Resources

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!

From Terminal Output to Arbitrary Remote Code Execution- 1237

solid-snail    Reference →Posted 2 Years Ago
  • Terminals are the most common way for developers to interact with computers. The control codes of this is conveyed in-band to the users. Escape sequences like \x1b[32m are a good example of this. The author decided to look into the iTerm2 emulator.
  • Similar to phone phreaking back in the day, the goal of the attack is to use arbitrary characters printed to the terminal to change the control flow of the terminal itself.
  • The idea behind the attack is sticking characters into stdin via terminal escape codes. By doing this, we can force a command to be executed. The payload is a complete mess to look at. But, the concept is simply this with various twists.
  • For instance, the \x1b[5n code is a Device Status Report (DSR). This will end up pushes the character n to stdin. By using this, and various other things, we craft arbitrary commands.
  • Then, we push the command arg1|m4 using various schengians of pushing data to stdin. The m4 command is a C/C++ macro engine, allowing for code execution via the previous input of syscmd(open -a Calculator).
  • The line \x1bP1000p%session-changed $9 s\n acts a tmux (terminal multiplexor) command that will press enter for us, executing our command now in stdin.
  • I don't fully understand the payload. There's a lot of juggling between things and the actual reason for searching through history isn't very well explained. Regardless, I loved the attack method and hope to see many more of these in the future.

How Cross-Site Frame Counting Exposes Private Repositories on GitHub- 1236

medi    Reference →Posted 2 Years Ago
  • Cross-site frame counting is a technique for counting the amount of window references (iFrames) from external websites. This is not a vulnerability by itself but can be used to leak private information. For instance, if there's an iFrame for a user logged into a site and no iFrame if not, then this leaks that the user is logged in.
  • - While testing VS-Codespaces integration with Github, the author noticed a quirk about the iFrames:
    • 2 iFrames2 iFrames: The private repository exists but the file does not.
    • 1 iFrame: The private repository exists and the file both exist.
    • 0 iFrames: The private repository does not exist.
  • So, we can determine the state of a user based upon the number of frames. Neat! The exploit is a loop of opening a location in the browser by setting the win.location and checking how many frames were loaded.
  • How do you fix this? You load a consistent number of iFrames no matter the state. Overall, interesting bug with pretty significant impact.

When URL parsers disagree (CVE-2023-38633)- 1235

Zac Sims - Canva     Reference →Posted 2 Years Ago
  • URL parsing is super hard to do properly. There is a standard that has been updated and changed over the years. Additionally, if there is a difference in verification vs. use at any point, this can lead to massive security issues. In this article, they were looking at an SVG parser.
  • Previous research has showed that the Inkscape CLI parser is vulnerable to path traversal within rendered SVGs. Within this parser, the XInclude format is also supported, a method of merging XML documents (SVGs are just XML). The underlying library for Inkscape is librsvg, which Canva uses.
  • Within librsvg, every URL goes through validation to ensure it is not malicious. For instance, being able to include arbitrary local files would be a big no-no. The rules are VERY strict, making it relatively safe to use.
  • The parser for validation is done with one parser but the loading of the SVG is done using the parser Gio. Anytime there are two parsers operating on the same data, there is likely many bugs lurking. A slight misunderstanding on one end could lead to the break you need.
  • The authors of the post setup a fuzzer to test the differences in the file resolve process. While doing this, they noticed that current.svg?../../../../../../../etc/passwd passes the validation but can resolve files. How is this? From my understanding, the ? gets stripped from the resolver and is unhandled by the validator.
  • The Gio parser will happily traverse files and traverse further up. A canonicalization process is done on the link. As it turns out, it starts in the directory in which the program is at. So, placing a . at the beginning can be used to force the program to traverse further up.
  • The full SVG link is .?../../../../../../../etc/passwd. To me, this really shows the power of differential fuzzing. Who would have thought about a question mark in the path? Not me, only the fuzzer.
  • At the end, they note some interesting things going forward for similar research. My favorite is that the file URIs support query strings, but this varies depending on the library.

CVE-2016-4484: Cryptsetup Initrd root Shell- 1234

Hector Marco & Ismael Ripoll - Cybersecurity Group    Reference →Posted 2 Years Ago
  • Cryptsetup is used to unlock the system partition when using the Linux Unified Key Setup (LUKS). This is all about full disk encryption!
  • When booting up in Linux, there is a special file system called initramfs that runs before Linux has been fully added but after the bootloader like GRUB. This state initializes the Linux OS and the root partition. So, by design, initramfs is used to decrypt the main file system.
  • When using LUKS, a user must provide a password or one must be given from the TPM. If this fails, then a user can try again. If this fails more than 3 times, then the system reboots. If this fails 30 times on x86 machines, then the machine goes into a state where it feels it's broken.
  • What should the system do if it's broken? By default, this drops into an initramfs shell. In this case, we can modify initramfs, continue the boot process and more. This is NOT supposed to happen if LUKS is being used for file system encryption though.
  • This is where the bug is at. When checking to see if the maximum number of attempts has been checked, the bash statement will always return false, taking the wrong path. This ends up being horrible, since the system drops into the shell when it shouldn't.
  • What can you actually do in this state? By modifying the initramfs state, you could modify the boot procedure. Even worse, with auto-decryption via TPMs, we can bypass the boot policies that would normally restrict decrypting the file system.
  • How do you perform this exploit? Pressing enter 93 times. The authors believed that this bug was added in via new features being introduced into the system without considering the global issues. As people say "Complexity is the worst enemy of security." Overall, a good post on boot security.

Mashing Enter to Bypass Full Disk Encryption with TPM, Clevis, Dracut and Systemd - 1233

Michael Fincham - Pulse Security    Reference →Posted 2 Years Ago
  • Full disk encryption for an unintended computer is a surprising difficult problem to solve. A classic way of doing this is using a TPM to store an encryption key but only having the encryption key accessible if the computer is in the right state via policy sessions. Because of the policy, it's not possible to modify the running code. Because of the FDE, it's not possible to modify the file system, making for a secure system.
  • The above approach has a problem with bus sniffing to get the key but working very well otherwise.
  • An unattended disk encryption setup still allows a user to view the output of the boot process or manually enter the key if something goes wrong. Usually, a screen is presented for interacting with this functionality but quickly goes into the boot process if the TPM is active and working.
  • In the automatic flow, there is room for logic bugs. If an attacker can interact with the system after decryption but before the full load of the OS, then they could cause havoc.
  • In 2016, Debian's cryptsetup startup script allowed for holding the ENTER key to gain root access to an early boot environment. Since this was post decryption, an attacker with a root shell could modify the file system or do whatever they want to compromise the system.
  • The author decided to perform fuzzing to see what would happen. This was using an Atmel Microcontroller to enter key presses very fast, in a similar way to a rubber ducky. The program pressed the ENTER key every 10 milliseconds, which is much faster than just holding down the key on a keyboard.
  • By doing this, the key presses restrict the auto decryption and autoboot from happening. Because of all the failures, it goes into a recovery mode with a root shell in an early boot env. Once there, we can call basic TPM commands to decrypt the drive, bypassing the FDE.
  • Why does this occur? It's super complicated. An agent plugin is used for systemd with a pool of different responders from these plugins. When using both dracut and clevis at the same time, Clevis implements a systemd password agent for unlocking, but the user may also enter a password using the normal interactive agent. For whatever reason (which I don't fully get), this puts it into a very weird state that drops us into an emergency shell at the end.
  • A super interesting flaw in the low level process. It's fascinating that simply pressing enter can bypass the boot process. This architecture seems to be at fault; I'd wonder if similar types of bugs exist in this system from this design.

Commit-Reveal scheme in Solidity- 1232

Srinivas Joshi - Coinmonks    Reference →Posted 2 Years Ago
  • A commit-reveal scheme is a mechanism to have a secret value on chain without actually disclosing it until it's necessary. This is useful since everything on the blockchain is public.
  • The commit is a user setting a hash with unique values to them. This hash is generated from a secret value offline, which will be provided later.
  • The reveal is a user specifying their secret value. Of course, we check that the offline hash matches the contract generated hash to ensure that the value is the proper one. At this point, a decision can be made on whatever values we are operating on.
  • Why is this useful? Frontrunning can be used if a user submits a transaction where they will make a bunch of money from a secret. Additionally, secrets on the blockchain are public.
  • To do this correctly, there is a commit window and a reveal window. These should never overlap; otherwise, frontrunning will be possible. Additionally, the hash should not just be based upon the value but the address making the call; this is to prevent simple replay attacks.
  • The rest of this article is a code implementation of how this works. Overall, interesting scheme to work around a blockchain limitation.

Huckleberry: IBC Event Hallucinations- 1231

Felix Wilhelm - JumpCrypto    Reference →Posted 2 Years Ago
  • The Cosmos SDK is a blockchain development framework for application specific blockchains. Built into its core is blockchain interoperability by IBC (interblockchain communication).
  • Within the Cosmos SDK and most other blockchains, there are events. This makes it easy for off-chain applications to monitor the blockchain and query its state then act on these messages. So, keeping these events valid is important for the security of the system.
  • When communicating via IBC with two blockchains, a relayer sends over the data with a MsgRecvPacket message. If an error occurs within this handling, the blockchain cannot revert. This is because the other chain communicating needs to revert the state changes that were supposed to happen (but failed) from chain A to chain B.
  • So, instead, it uses an IBC acknowledgement message. Successful ack means the call succeeded and a failure indicates that the call to IBC failed for whatever reason. The relayer would then send the result from the target chain back to the original chain to revert the changes.
  • When handling an IBC packet with a failure, the event is still emitted due to poorly written code. Why is this bad? The events are emitted, even though the state changes were never made. As a result, any off-chain program listening would believe this went through when it really didn't.
  • The author calls with a "hallucination", which is a really good name for this. To trigger this, we must force a bad ack event. With CosmWasm, this is trivial through the built in IBC support. Then, to exploit this, an attacker can trigger arbitrary actions through CosmWasm, such as a bridge request. From there, this will have bad events emitted, tricking whatever off-chain applications. For non CosmWasm chains, other methods may be possible to trigger this.
  • What else is vulnerable? A decentralized exchange that requires transfer from one chain to another that is looking for events could be vulnerable. Additionally, various bridges could have been exploited in this way as well.
  • Overall, a really simple issue that was overlooked by the developers that caused a very serious problem. This was a really good find by Felix on the Cosmos SDK side.

How Tornado Cash Works- 1230

Jeffrey Scholz - Rare Skills    Reference →Posted 2 Years Ago
  • Tornado Cash is a smart contract cryptocurrency mixer. This allows users at one address to withdraw funds at another address without creating a traceable link between the two addresses. Seems impossible right? This is all about zero knowledge proofs. This is proof that an operation was carried out with giving the secret value. RSA math says I know two secret prime numbers without ever showing you those prime numbers.
  • The owners of Tornado got sued by the US government because of how well it works for money laundering. A user can put money in and there's no possible way to associate the address on the output. Although, you can associate an address with receiving funds from Tornado cash or depositing funds, you cannot figure out who sent to who.
  • The naive and not privacy preserving solution is to create two secret numbers and put the hash on the chain. If you can reveal the two secret numbers, then you can take the money out. To make this private, we can go over a list of hashes in a loop by ORing all of them together with zero knowledge proof data. This allows us to find a valid hash without revealing which hash is the one we proved.
  • Merkle trees are a common data structure used in blockchain because of the ease of verification. So, instead of iterating through a list of hashes, we can use a merkle tree instead. In particular, the withdrawer must prove knowledge of the preimage of a leaf without revealing the leaf and demonstrate that we have a valid Merkle proof for the node.
  • If we removed a node from the Merkle tree, this would disclose which item we were taking out. So, how do we prevent double spends? The hash from above was two numbers: a nonce and a secret value. The contract code uses a hash of the nonce to determine if this node has been used. So, if you tried to withdraw twice, it would not work. Naturally, this process of knowing the nonce is done as a zk proof. This strategy is called a nullifier scheme.
  • The Merkle tree needs to be faster to be usable. So, some optimizations have been made. First, the tree has a fixed depth of 2^32 deposits with every element starting off as 0s. Second, the left-most node that does not have a value is overwritten.
  • The quirks from above have immense impact on how the program works. Since all updates are performed on the left-most updated node, everything to the right is going to be 0. Because of this, they have recomputed all of these values of different depths to make the program more efficient.
  • The second shortcut is that since we add in a consistent order, we do not have to recalculate the tree all the time. Instead, we can use previously cached values and only update small chunks from the real update. Pretty neat!
  • The rest of the article goes into the code of the project. I still do not understand how the program performs the zero knowledge proofs but understand why they are being used at least. Awesome article!

Smashing the state machine: the true potential of web race conditions- 1229

James Kettle    Reference →Posted 2 Years Ago
  • Race conditions are issues that stem from the timing of requests being made. Historically, most race conditions were time of check vs. time of use (TOCTOU). For instance, redeeming a gift card multiple times by submitting the requests simultaneously. The author calls these limit overrun attacks. However, there are other TOCTOU issues besides limit overruns.
  • James Kettle introduces a new class of race condition bugs beyond limit overrun attacks: state machine races. Best quote of the article: "Every pentester knows that multi-step sequences are a hotbed for vulnerabilities, but with race conditions, everything is multi-step." By considering every operation that the backend performs a state change, new requests between these changes could cause major havoc by accessing unintended substates.
  • The author was testing an application where the flow was Login->Assign Role to token. So, what happens prior to the role being assigned to the user? It's an admin user! So, by making a request while the role assignment process was occurring, the user could briefly become an administrator. This is a perfect example of a sub state causing problems.
  • These race conditions can be extremely tight though. How do we hit these? Network jitter between two requests can cause particular conditions to not work. A common technique is the last byte sync, where the final byte is not send until the very end.
  • HTTP/2 allows for multiple requests to go over a single packet. This was abused for Timing Attacks in the past. Now, James Kettle was abusing this to get the network jitter to be extremely low. On top of this, they combined the last byte sync from before in order to get 20-30 requests interpreted all at the same time. This is implemented into Burp Intruder but they have more details on how to do this yourself as well.
  • Finding these types of vulnerabilities is extremely difficult to do. So, the author came up with a methodology for finding these bugs. First, we need to identify objects, such as users and sessions, with security controls that that we want to bypass. Then, identify functionality that reads or writes to this state, such as profile edits, password resets and more. Finally, race these various types of requests to find a problematic sub-state.
  • The big questions to be ask are:
    1. How is the data stored? Persistent server side state data is what should be tested here.
    2. What's the operation keyed on?. Finding weird sub-states may only be possible in situations where two items share the same key or the state has various operations that change in a single request.
    3. Editing or appending. Editing is much more prune to race conditions.
  • Of course, Kettle went through some case studies. While looking through email invitations functionality, sending the same invitation request 6 times turned up 5 successes and 1 "this has already been taken" message and two emails instead of 1. This was different than doing this sequentially. So, the weirdness of this call indicates that a weird sub-state has been hit.
  • Initially, this did not gather much. However, they came up with a crazy attack scenario. Doing the email resolution process, what if you replaced the email? The email resolution would verify it while the replacement would swap the email. Sadly, the code being sent was for an already verified account and not the new one trying to be added.
  • During the Gitlab process of changing an email, the author noticed that it was incredibly fast; much faster than sending an email is. So, this indicating that another thread was likely being used to send this. The author decided to change their email address twice at the same time. While doing this, they noticed that the To and body did not always match. Sometimes, the confirmation code for one user was included in the other users email! What a crazy bug!
  • Testing for these bugs is complicated via blackbox but impossible to spot via whitebox testing. There are many many many bugs like this waiting to be discovered in the wild. I hope to find some of these in the near future via blackbox testing. Race conditions thrive on complexity.

cypher exploit - 7th august 2023 - post-mortem- 1228

Cypher    Reference →Posted 2 Years Ago
  • Cypher is a protocol for lending, borrowing and trading using margin. Margin is the process of betting on assets using value that you are borrowing from somebody else.
  • There are two types of account: master account and sub accounts. The master account acts as a cache for all sub accounts under it. This information includes asset values, collateral ratio and more. Master accounts are cross-collateralized, meaning that a sub account can use assets from another sub account. This cross collateralization can be turned off on a particular sub account as well.
  • The function EditSubAccountMargining can be used to change the mode of the sub account. However, there is a bug here: the cache of the sub account in the master account is not updated to reflect this. The lack of updating the cache puts the account into a bizarre corrupted state.
  • The goal of a loan managing process is to ensure that a user cannot borrow more money than their entitled to for their collateral. Breaking this logic would result in a complete loss of assets for the protocol.
  • Although this is not fully explained, this is the root cause of the issue. Once in this state, the usage of the sub account will no longer effect the master account. So, removing funds from the sub account would make the master account believe it had more funds than it really did, allowing for more money to be taken out than expected.
  • There is a second bug that allowed this to be exploited though. The functionality for verifying margin on volatile assets had an uninitialized oracle. This led the trade being accepted, even though it should not have been. In the end, this led to $1M in stolen funds from bad loans.