People often ask me "How did you learn how to hack?" The answer: by reading. This page is a collection of the blog posts and other articles that I have accumulated over the years of my journey. Enjoy!
get(), which can be used with specific parameters. In Python, using the syntax func(**var) in a function call will treat var as a key/value pair where the key is the named parameter to use a particular value. _connector and _negated, were not being filtered adequately for SQL injection. The thing is, these aren't usually controllable values. **var syntax comes into play. If an attacker could control the contents of **var being used in one of the vulnerable functions, they can control the parameters vulnerable to SQL injection! They claim this can lead to authentication bypasses, data exfil and privilege escalation, which is true but context-dependent. runc, the underlying containerization used by Docker and Podman. All of them allow for writing to the /proc file system to escape the container.runc will mask several files. In practice, this means that the value just points to /dev/null in the local container. However, there is a race condition around this. It's possible to use the race condition on the creation of a bind-mount to create a symlink for the target on the host system. The ol' switcheroo! By getting read/write to /proc/sys/kernel/core_pattern via this trick, it's possible to get a container escape with the coredump privileged upcalls. /dev/null is deleted on the container, then runc would ignore the error, and the masking process becomes a no-op. In practice, this means that an attacker could read the /proc files. This was found after the first one and was also fixed./dev/console bind-mounts. When creating the bind mount to /dev/pts/$n, an attacker can replace /dev/pts/$n with a symlink. Naturally, this allows for writing to files on the host machine. This bug is after the pivot from root but the core_pattern trick from above can still be used.os.Create() that were stress-inducing. Although not directly exploitable, they decided to provide fixes for them anyway. Around race conditions on /dev/pts/$n writes, they added additional protections. A single bug should really trigger a large set of security improvements while you are there./proc to a tmpfs./proc/self/sched instead of the proper one. This was done via a symlink. runc thinks that it was writing to /proc/self/attr/exec but it wrote to another file instead. Price(BPT) = (D / total supply) where D represents the pool's virtual value and BPT is Balancer Pool Token.D becomes smaller, then the BPT price will appear cheaper. In Balancer, batchSwap() is used to perform multi-hop swaps. The user can specify the exact amount in or the actual amount out to receive. _swapGivenOut() must calculate the input amount that is required for the transfer to succeed. Upon doing this, the function upscale() rounds down to benefit the user. It is standard practice always to have rounding benefit the protocol; otherwise, incidents like this can occur. wstETH to cbETH. To perform a trade to get 8 cbETH, the math is (amount * 100) / 9 = ?. This means (8 * 100) / 9 = 800 / 9 = 88.888 in practice. Now, the upscale function will round to 88 instead of 89. In practice, this is catastrophic. It allows a user to exchange a smaller amount of one underlying asset (wstETH) for another (cbETH)! Over time, this decreases the invariant D, since there is now less liquidity. As a result, the corresponding BPT becomes deflated. D value. The price manipulation of D is how the attackers profit. In a separate transaction, they purchase the BPT at a significant discount and sell it for a substantial profit. This could have been done in the same transaction, but they likely did it in a separate one to prevent frontrunning.UPDATE based upon this. In the case of a bank transfer, this leads to multiple operations appearing as a single one. The value subtracted is $100 that should be done twice on the value. Instead, it's done a single time because of the values that the update has access to.Serializable level was used. Pretty neat!Serializable transaction isolation level to these transactions. This would have a large impact on the application though. Another option is to add a MUTEX via FOR SHARE or FOR UPDATE on SELECT operations. This will instruct the database to wait until the transaction is complete, allowing for the reading/editing of these fields. A final way is to add a version row to each column. By comparing the version on the read vs. the write, it will prevent race conditions.random function to exploit the system. In this case, the author of the post was targeting a password reset token.TickCount is used. This is the number of milliseconds since the machine was booted.random()! In the .NET framework, there is a note about this. "As a result, different Random objects that are created in close succession by a call to the parameterless constructor have identical default seed values and, therefore, produce identical sets of random numbers." So, if calls to random are made within the same 1ms, they will produce the same output. If you have your own password reset token and tried resetting another user's, it all went well then they should be the same.urlopen function can read local files, for instance. CVE-2023-24329 showed that a space at the beginning of a URL could trigger a SSRF if using blocklisting. The point is that parser differentials can lead to horrible security issues.http://example.com:000123:443, parse out http://example.com:000123, and then the browser would interpret this as http://example.com:123. The difference here was between the browser and the PHP backend. @ character and a path that started with /tmp allowed them to read files from the file system in the file upload code. However, the data was BLIND, since the file contents were being added to the $_FILES global variable. If sent with multipart/form-data, the contents go into the $_POST variable but with no control of the file name.Content-Disposition header to make this possible. They had the source code for this application, so they were able to see the sinks of this. The confusion happens in the second request. By adding a double quote to the request in the name, it reads the contents of /etc/passwd. Since the username parameter was the closest thing to the file contents, the file was added to the variable and returned in PHP. The rest of the data is effectively ignored because it's a very nice parser. /etc/passwd to the user, demonstrating a full file read via SSRF. The key was bypassing the $_FILES variable restriction to inject the file contents directly into the $_POST parameter.../../ in the error message, we can traverse up the path for other requests. In this case, it's possible to create arbitrary PUT requests on GitLab. The impact of this is immense! Trick users into adding admins, elevating membership, and approving membership. I assume that the contents of the PUT request are controlled via JSON with this. enforce_path_traversal_check to an internal library, making this default to true. Great bug and great report!%PDF in the JSON at all, it'll be considered valid PDF and valid JSON. It just needs to be within the first 1024 bytes.%0A between PDF objects with spaces. Then, open a double quote with the PDF header and other valid-looking PDF data. file has strict limits on input size. By making the sizes too large to handle, it may revert to the default file type. In many ways, this should trigger an error, but that apparently differs on the system.