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!

Learning by Breaking - A LayerZero Case Study - Part 2- 1355

Trust Security    Reference →Posted 2 Years Ago
  • In the first part, the author goes over how the EVM part of Layer Zero works. In this part, they go over some bugs that they found within the ecosystem.
  • Being able to shut down an individual cross chain message arbitrarily is a rather bad issue. Not only as a single user but since things must be done sequentially on LZ, being able to force a transaction to revert could block the whole setup.
  • On a crosschain swap, the developers consider the scenario where transaction reverts by handling it within a try/catch block. So, even if this reverts, it should be able to handle it. But, Trust has an interesting piece of insight on this!
  • If the call to a contract is made but address is NOT a contract that exists then the try/catch block of code will NOT handle it properly. Instead, the transaction will simply revert. This leads to a persistent DoS attack, since it will block transactions occurring afterwards.
  • The developers thought of this situation occurring. So, they have function that will remove a transaction from the queue when this happens. Sadly for Trust, this was fixed at a different layer of the stack that they had not seen and was found internally by the team.
  • Looking at the same code they wanted to force a revert in a different way. If the try/catch was correct so they turned to gas related attacks. When executing an external call, the user pays a fixed 175000 gas.
  • First, they tried a return data bomb attack. This is when the copying of the reason for the external call eats up a ton of gas. In this case, it wasn't possible because to eat up all of this gas in this case.
  • What they did realize was that the failure case was copying the payload into storage. Since every zero to non-zero storage costs 22.1K gas. The payload was capped to 10K at the LZ level for a total of 313 operations or 7M gas. To attack this, we would send a swap with a very large payload then have it fail. To unDoS this a relayer would need to pay 7M gas, which is a lot.
  • Once again, the development team had found the vulnerability internally then sent it to people doing an audit. To fix the vulnerability they added some middleware to the router call that protections against many of these gas spending edge cases. The check appears to be within some router code, which is extremely strange place to put it.
  • Overall, it was interesting reading about various gas denial of service techniques. It's a bummer that neither of these bugs panned out for Trust but I believe in part 3 they get something.

The Cosmos Security Handbook- 1354

Fault Tolerant    Reference →Posted 2 Years Ago
  • Several folks wrote about issues to look for in Cosmos-based blockchains. I have a personal list of these but it's nice to see a large external list! Cosmos is built via writing Go code at the infrastructure layer, as opposed to writing code in a virtual machine like the EVM. This creates many unique issues.
  • The first mentioned class is non-determinism. If different groups of validators see different proofs at the end of execution of a transaction then the blockchain will come to a halt. Randomness, Go maps (randomly determine where to start in a map), timestamps from the local machine, concurrency and floats by different platforms.
  • The second class are in protocol panics. Code executes within the BeginBlock/EndBlock that panics will lead to a chain halt. Hence, panics should be handled in a nice way. This can happen via bad math operations, bulk coin sends for blacklisted addresses and added in panics.
  • A third thing to watch out for is unmetered computation. Only stateful things have gas meters. For instance, reading/writing to state within a callable message. However, BeginBlock/EndBlock do not. So, if a user can setup code to end in these locations, it can be real bad. Additionally, bad loops on non-state operations can cause halts as well.
  • The next one is Key Malleability and Prefix Iteration. In Cosmos, all state is simply a key-value store. For storage, it's recommended to add a prefix to a data type so that you don't overwrite the wrong things or create collisions. Even checking for existence by a prefix needs to be done carefully. I remember thinking about these collisions myself but most developers are smart enough to add a large string to the beginning of the data to signify a datatype.
  • An iterator is created for going through a KVS space. When using an iterator, adding the prefix to the store is crucial. Otherwise, unintended data could be iterated over the top of. Iterators are inclusive of the first byte but exclusive of the end byte. So, this can create a bad iterators over the top of data.
  • Cosmos developers need to consider gas. The KVS does contain automatic gas charging for storage reads and writes but sometimes more needs to be done. However, adding more gas for specific operations can be necessary to prevent spam. Cosmos is known to have high levels of congestion and not having a good way of handling this during peak load. The gas stuff on Cosmos feels like a blackbox to me atm.
  • Overall, a good series of issues! They're going to do a CosmWasm and IBC post in the future, which will be good for everyone in the space. I look forward to seeing the post and adding to my list of test cases on Cosmos based blockchains.

zkSync Era Findings & Analysis Report- 1353

C4    Reference →Posted 2 Years Ago
  • zksync is a zero knowledge (ZK) project that was building out a ZK EVM. The contest had 1.1M in rewards. The winner Winnie had never touched ZK stuff before but decided to ramp up on it before the event. I purposely didn't do this because I thought that the competition would have too many specialist but I was wrong about that!
  • ZK logic uses arithmetic circuits which act as gates with logic similar to binary logic in traditional computers. The circuits must be implement this strictly otherwise there may be more than one correct answer, which is unacceptable for a EVM execution.
  • On the div operation the circuit wasn't constrained enough. There is a missing check on the result of the subtraction. This means that the division with a smart contract could be given an incorrect result, which is awful. The exact same missing constraint exists on shr as well.
  • The lack of constraints is a very common critical vulnerability within ZK systems. This was done with log emitting, AND, OR and out of bounds memory reads as well. For the AND and OR values, the constraint only must be less than 128. For XOR, there is an integer truncation bug that leads to the same affect.
  • The final high finding is a denial of service via an unprovable via an over constrained circuit. If a dividend is nonzero and the divisor is zero, the quotient and remainder are both zero. Interesting that BOTH the over and under constraints are bad.
  • There are also a plethora of medium severity and low findings. Many of these are wrong values or differing implementations between the EVM and the zEVM. These are worth reading but there are too many to make notes about.

More secure Facebook Canvas Part 2: More Account Takeovers- 1352

Youssef Sammouda    Reference →Posted 2 Years Ago
  • Youssef specializes in finding vulnerabilities in clientside JavaScript code. Specifically, with Facebook integrations. In this article, he goes through a chain of issues that led to an account takeover but looking at the authentication process of Facebook Games.
  • When trying to authenticate using OAuth in this iFrame, there is some postMessage communication that occurs. Once this happens, a request to Facebook is made that pops up on a dialog box and returns back authentication information for the requesting application.
  • Of course, doing this as some security risk. So, they try to validate the redirect_uri and requesting origin. When getting the response from the Facebook OAuth endpoint, the redirect URI was the location for the postMessage sending origin. So, if you specified instagram, it would try to send the information to the instagram domain in the postMessage.
  • If the origin is null or undefined, then the value of "k" is set. This setting gets set automatically to the URL of the game application (aka iframe URL). Additionally, there is a check to verify that the app ID matches the URL for the postMessage is being sent to.
  • Since Youssef spends so much time at Meta, he knows everything about the authentication process. He knows that all Facebook apps have fbconnect://success as a valid redirect_uri.
  • So, what's the attack here? There's a race condition on the checking of the k value for the origin. First, we send the request with fbconnect URL with the instagram app, which is valid. While the OAuth request is in flight we submit a new k value to replace the postMessage origin to send it. With this, we're able to get the OAuth code for any app!
  • This was fixed by checking that the app_id is the current one. While testing the fix they noticed that if you included a parameter with app_id[0]="" that this was interpreted as the parameter but could only clear it for some reason. While looking around they found a new parameter called encrypted_query_string which could contain the same information as before. The author found an encryption oracle via a server side redirect that encrypted the information for them.
  • So, using this, we submit a postMessage with the app_id and redirect_uri with the empty string to clear it. Next, we use the information provided by the encryption oracle with the malicious redirect_uri. Now, we have bypassed the protection once again. To fix this once and for all, an allowlist of JSON parameters was made for the postMessage call.
  • All of Youssef's post require a very deep understanding of the Meta ecosystem and rely on various small primitives to achieve a goal. Parameter pollution, encryption oracle... so many little things! I think this shows the power of specialization and note taking on little quirks discovered within the application to create huge impact. Youssef was on the Critical Thinking podcast recently and has some further good insights on this.

Every known way to get references to windows, in javascript- 1351

Daniel Brain    Reference →Posted 2 Years Ago
  • This article is a list of different ways to get window references. When doing client side security, getting a reference to a window is big way to cause havoc.
  • First, looking at the window. Using window.open() on both a new window and an existing window. Second, if you're inside of a popup window you can get a reference to the parent with window.opener(), even with a cross domain setup.
  • Next, we have iFrames! window.top can get the reference to the top level window when in an iFrame. window.frames shows all frames within a given window. Additionally, if it's named, then windows.frames['frameName'] can be used too.
  • A window object can be sent via a postMessage even in the cross domain case. If a window has the same domain as another window, you can reference globals on that window.
  • Most of these rules can be chained together as well. The author mentions that it's not always possible to get a reference to something. In particular, a cross-domain iframe or an iframe that opens a popup window.
  • Good article on a very esoteric JavaScript concept!

Learning by Breaking - A LayerZero Case Study - Part One- 1350

Trust Security    Reference →Posted 2 Years Ago
  • LayerZero is a very large blockchain bridge that holds a large amount of value, as well as many cross-chain applications made by other developers.
  • The functionality for calling is fairly simple on the smart contract side. On the sending side, call send() to the UltraLightNode (ULN) contract which emits an event. On the other chain, receive() is called from an entrypoint of LZ after a Merkle proof is done. Trust includes a nice callstack for this as well.
  • A user can pick a specific relayer while doing this. When getting a relayer to send over the message, you need to pay for gas as well.
  • In September of 2022, ULNv1 was deprecated. Why? Trust claims it was a silent fix of a vulnerability with no public information about it. If you look at a diff of the codebases, instead of just srcAddress it's using srcAddress,dstAddress for the PacketReceived event.
  • When calling validateTransactionProof() on a transaction the nonce used to be pulled from the mapping [srcChainId][srcAddress]. Now, it's [srcChainId][srcAddress][dstAddress]. Why is this a big deal?
  • The incoming transactions must come in order as well... 1,2,3... A client contract can pick their own relayer/oracle pair. Given this information, we have a slot collision. Another user can submit a transaction from the same client contract with a different relayer to the same destination and chain to spoof it. Since there is replay protection, this made the real message unreceivable. Boom!
  • $250K was paid to the first whitehat then samczsun reported it after but got a $50K good will bounty. To me, the slot collision is something I've never seen before and I'd be curious to see more of these. Thinking in depth about mapping and user controllable values seems like a good way to go.

The Risks of the #MonikerLink Bug in Microsoft Outlook and the Big Picture- 1349

Haifei Li - Checkpoint Research    Reference →Posted 2 Years Ago
  • Outlook is the most popular email client in the world with all of the other Microsoft Office Suite of products being equally important. Finding vulnerabilities in this can have devastating consequences.
  • Everyone knows what URLs are - http, https, etc.. However, there are many other URLs for other apps, such as Skype. The file:// URL can be used to reference local files on the system. By default, this is blocked from execution on Word when clicked on.
  • Some researchers found a weird bypass for this check. If the path has an exclamation point then some text afterwards then the check is bypassed. For example - file:///\\10.10.111.111\test\test.rtf!something. The exclamation point has some special meaning in Outlook that changes the meaning of the parsing from a file to a Moniker to try to find COM objects.
  • What's the impact of this? First, a request to a file at a remote location would leak the NTLM hash. Second, since this tries to parse the item as a COM object, it may be possible to escalate this to RCE. However, there is no real example of this and it feels like scare tactic.
  • A fairly simple mishap on the parsing of the URL. When deep knowledge of a system comes obvious bugs.

0Kage Diaries Chapter 1 — Enzyme Finance- 1348

0Kage    Reference →Posted 2 Years Ago
  • Enzyme Fiance is an on-chain asset management protocol. Users can create access rules, trading limits and other various rules. Within this, there are three main roles: asset manager, end users and the protocols being interacted with.
  • The manager handles the funds in order to create a secure yield generating platform, which the users will benefit from. However, who should have to pay for the gas on a rebalancing? To solve this problem, there is a gas station network relayer for handling exactly this case. This works by having the users pay the expected gas charges up front then executing the transaction via a network of relayers.
  • Within this architecture, there are a few different roles. First, the relay server is a web server that takes in a request for a transaction. The paymaster is the contract setup by the application using the GSN to pay for the gas prior to executing the call. The relayhub is the entrypoint for the relayer itself. Finally, the forwarder is the contract on the network for the GSN that is trusted to execute the call, where the application should implement a caller interface for this.
  • We have an anonymous user from the GSN network making calls to the contract on behalf of another user. So, access control is complicated to do with this setup. One job of the forwarder is to call the function preRelayedCall() to ensure that the recipient matches the forwarder in the relay request. When overriding the original implementation of this function from GSN, they removed this check.
  • For integration into the network, the relayer is trusted and must be allow listed by the network. Since the check was removed, an malicious forwarder can abuse this to profit from it. Remember, the forwarder is the entity actually performing the transaction and getting paid out in gas for their troubles. Since the forwarder isn't validated, an attacker can send a fake message then receive payment for it!
  • How much payment? According to the GSN docs, the gas information should be validated within the paymasters preRelayedCall() as well. But, there is no verification of the gas parameters for this. As a result, a malicious relayer can set very high gas values then get paid out a lot by the paymaster. To make matters worse, since the paymaster is replenished with 0.5ETH magically, this can be done on repeat to steal more and more ETH.
  • To fix this, there are two bugs that should be remediated. First, checking the forwarder address. Second, checking that the gas parameters are sane.
  • The author leaves us with a few takeaways. First, small features can still have big impacts. Second, more misconfigurations can lead to the amplification of impact, such as with the missing gas price check. Finally, design is key. GSN rewrote some of their code to do this verification themselves instead of putting the blame on the developers.
  • Overall, a very in depth read onto a GSN integration vulnerability. It's interesting how a small access control issue turned into the stealing of money from the protocol. Great find and write up!

Stacks DoS Bugfix Review- 1347

Immunefi    Reference →Posted 2 Years Ago
  • Stacks is a Bitcoin L2 blockchain. It uses the Clarity (Cl) language, which has a LISP-like syntax, for executing smart contracts.
  • For some reason, the article says that it's more secure to use an interpreted language vs a compiled language, which makes zero sense to me. Neither of these is more or less secure, as shown by the bug.
  • The vulnerability is a really simple denial of service vulnerability found by bad error handling. When calling ft-get-supply with a non-existent address the Rust error handling doesn't consider the case where nothing is returned. So, the Clarity VM crashes in this case.
  • Fixing this is trivial; just make a call to Some/None in Rust. Overall, a really simple bug that paid out quite a bit. The more esoteric stuff you look, the lower the bugs will be on the tree.

ChatGPT Account Takeover - Wildcard Web Cache Deception- 1346

Harel    Reference →Posted 2 Years Ago
  • Last year, a web cache deception caching vulnerability was discovered in ChatGPT. The vulnerability was that anything ending in a particular file type was cached but it had a fuzzy path resolution. By combining these together it was possible to get a credential file cached for a particular user by clicking on a link. So, this was fixed, but how well?
  • The author was testing a new share feature that allowed users to share their chats with others. They noticed that the shared chat wouldn't update when the chat updated. So, a caching issue maybe? They saw a Cf-Cache-Status: HIT header in the URL, which made them think that something was off here. After playing around with the requests, they realized that anything under /share/ was being cached by Cloudflare.
  • Prior to going to the web server, the CDN Cloudflare was doing the processing and performing the caching based upon the provided rules. From messing around with it, they noticed that if a path was URL encoded it was NOT being processed by Cloudflare but WAS being processed by the server. This desync in processing allowed for some weirdness to happen. What if we could get Cloudflare to think that the response was for /share/ to cache it but this came from a different path in reality?
  • This is what the author came up with:
    https://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123
    
  • The %2F..%2F after the share will be processed by the backend server but NOT the CDN. So, the CDN thinks we're at /share but the backend thinks we're at a different path. By setting this to be the /auth/session path, this creates the same web cache deception vulnerability as before. The author has a really good image on describing how the flow of this attack works to steal the session information via forcing something to be cached that shouldn't be.
  • Overall, I absolutely love this bug! It's interesting to see how things are cached. I wonder if there's a tool to figure out where caches live that could be added to Burp Suite?