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!

Stealing Millions from the Blockchain via Bad Access Control on IBC- 1385

CyberArk    Reference →Posted 1 Year Ago
  • IBC on Cosmos is a generalized way for crosschain communication. In the case of Comdex, they were using IBC to get oracle price updates from Band.
  • The IBC protocol itself is trustless and identifies another chain based on a channel ID that cannot be set by the chain instead of the chain name. This trustless nature sounds great but has to be kept in mind when using IBC.
  • Comdex did not allowlist a specific oracle update packet to the channel of Bandchain. Why is this bad? Any blockchain, including a solo machine (individual user with a private key) could have called this and set the prices of an oracle. Since the dex prices could be arbitrarily controlled, stealing all of the funds in the protocol would have been trivial.
  • To me, the main takeaway is that if communication on IBC is expected with only a single chain then this logic needs to be added to the handler of the IBC packet. Otherwise, the trustless nature will cause problems in your chain.

Morpho Blue Security Framework: Building the Most Secure Lending Protocol- 1384

Merlin Egalite - Morpho    Reference →Posted 1 Year Ago
  • Morpho Blue is a lending protocol that took security extremely serious from the ground up. So, their perspective on how to make a protocol unhackable is truly interesting.
  • For their security framework, they have 4 different parts:
    1. Pre-Build
    2. Build & Test
    3. Pre-Deployment
    4. Post Deployment
  • During the pre-building phase, their goal was to make the protocol as simple and feature removed as possible. Simple things are open to secure! They made threat models and had large debates about what functionality was there and what wasn't. During this phase, different PoCs were written as well.
  • Now, for the most important part - building and testing. Once they had a clear business objectives they set out to build the final version. To catch bugs early, they wrote unit and integration tests. They aimed to catch ever branch of code. To ensure good coverage, they use BTT and forge coverage.
  • To make tests even better, one can use mutation tools gambit or vertigo-rs. They implemented fuzzing tests with Foundry as well. At Morpho Labs there is a protocol team and integration team. The integration team handles reviews and some of the tests. Every developer reviews all smart contracts that will be deployed, which is crazy!
  • While still in the building/testing stage they get formal verification done from Certona, send the code to VCs/advisors and a breaking bootcamp, which is where everyone tries to cause major issues in the code.
  • At this point, they're ready for the pre-deployment phase. They got reviews from Open Zeppelin and Spearbit through Cantina. They have some interesting points about booking audits. First, book them in advance - it's hard to get audits from the best firms. Second, timing is super hard to setup - being early is bad and late is annoying. Reviews are stressful for devs but always give the auditors all of your time.
  • They also did a 100K pre-deployment bug bounty with Hats Finance. In the post deployment, it's all about good monitoring and a large bug bounty.
  • Overall, an interesting talk into building a secure protocol from scratch. The tldr; is spend a lot of time in testing and on audits.

Geth Out-of-Order EIP Application Denial-of-Service- 1383

iosiro    Reference →Posted 1 Year Ago
  • The Ethereum Virtual Machine (EVM) has EIPs for various large or VM breaking changing. At some specific point, these changes are made to the VM and are there until some other change is made.
  • When creating a new version of the EVM, the EIPs are based upon the block number. These changes are typically for gas things and opcode changes. However, the merge upgrade can be enabled even with older EIPs disabled. This desync in programmatic expectations is the root cause of the bug.
  • EIP2929 has a wrapper function that does some changing on the gas calculations. First, the oldCalculator() is called to get the raw price of gas. If the account is cold (hasn't been accessed in the TX yet), there's a 2500 extra fee. Theoretically, the operation of gas + coldCost could overflow, resulting in a lot less gas than necessary being charged.
  • The gasCall() function calculates the cost of allocating the specific amount of memory, with a maximum of 128GB. There are some other gas operations in this area being calculated, with one of them overflowing if it occurs.
  • So, the goal here is to get the gas + coldCost to overflow while not overflowing the checked overflow in the function above that. If this was possible, then the returned gas would be super small, resulting in way too much resources being consumed.
  • What's the actual consequence? Making this call 5 times is taking up an absurd amount of RAM, which results in the node crashing. This only needs to be an eth_call on an exposed RPC node to trigger this. It just requires a very precise gas being provided to a CALL instruction via the stack to trigger this.
  • This effected mainnet RPC providers like Infura, Alchemy, QuickNode, Flashbots and more. For whatever reason, the Ethereum foundation felt it was out of scope because it excludes RPC execution bugs from their bug bounty. Overall, an interesting post on breaking the RPC node of Ethereum. I hope to see more of this author in the future!

IBIS hotel check-in terminal keypad-code leakage- 1382

Pentagrid AG    Reference →Posted 1 Year Ago
  • At hacker congress this year, some of the folks found a vulnerability in the check in kiosk. Shocker!
  • When checking in at the hotel terminal, the lookup function required an alphanumeric booking ID. When submitting an incorrect code, an error appears, as expected.
  • When providing dashes (-), it would display all booking IDs. This appears to be a master code or a test function for debugging. The review contains a booking ID, timestamp and the total price.
  • If you click on the room number then it would output the room number. By getting all IDs from the first bug, then you'd be able to get the room code. Yikes!
  • Only requiring a booking ID for a room code is not great. These may be leaked by discarded invoices or print outs. How would we fix this? Further data should be required, such as an ID, passport number, PIN code that was emailed or something else.
  • Overall, a fairly funny and old school issue.

ERC-1271 Signature Replay Vulnerability- 1381

Howy Ho    Reference →Posted 1 Year Ago
  • Cryptographic signatures are super useful in Ethereum Solidity smart contracts for proving that a user approves an action. However, it'd be nice to do this for smart contracts but there is no key. So, what to do?
  • ERC-1271 is a specification for calling smart contracts that require signatures. Instead of an actual signatures, it calls a function and verifies the action being performed.
  • Most SCA (Smart Contract accounts) implement ERC-1271 using the similar methods to EOAs. When processing information from a smart contract that was checking the signature for the SCA, it did NOT include the origin contract. This meant that signatures were not specific enough!
  • Why is this bad? If the same address owns multiple SCAs, then there is no discriminator between the two SCAs! So, a replay attack could be used from one SCA to another.
  • Several implementations, including Alchemy's LightAccount, were vulnerable to this issue. When signing data, it's important to be as specific as possible and verify everything possible to prevent these types of issues. Good find!

Bypassing DOMPurify with good old XML- 1380

RyotaK    Reference →Posted 1 Year Ago
  • Recently, there was a bypass in DOMPurify when it's used to sanitize XML documents. Since bugs come in pairs, the author looked and found two more variants of the bug in the codebase. For context, DOMPurify is the go-to method for ensuring that rich text doesn't contain malicious JS.
  • XML and HTML have different parsing rules. For example, <?xml-stylesheet ><h1>Hello</h1>)"> ?> is parsed as a single node of XML but HTML recognizes an h1 tag.
  • When encountering a <? in XML, this is part of the spec. However, in HTML, this is processed as a bogus comment. So, there is a mismatch between the HTML and XML parsing.
  • The Processing Instructions allows us to bypass if the sanitized XML document is later later processed as an HTML document. Is this a normal case? I suppose that this is something that should be reported.
  • They found a similar issue within the [CDATA[ of an XML portion as well. It seems that different contexts are a common bypass for DOMPurify. So, interesting!

Instantaneous Unbounding in Cosmos SDK- 1379

Jessy - Amulet    Reference →Posted 1 Year Ago
  • The staking module is at the core of the Cosmos SDK ecosystem. If the security of this can be broken, then all is lost.
  • The economic security of the Cosmos SDK relies on four related concepts: bonding, unbonding and delegation and redelegation. Within the framework, there are only a set amount of validators at a time. So, users can delegate their funds to a validator.
  • Bonding is the process of committing the chains token as a mechanism of proof of stake. Once bonded, it takes 21 days to unbond. To improve the quality of life for delegators, if the delegated validator was not in the active set, they could instantly unbond without the 21 day wait.
  • Using a combination of features, there is a logical bypass to instantly unbound without any consequence. First, redelegate your funds from a bonded to a non-bonded validator. Next, unbond your funds from the validator, which works because they are not in the active set. Put plainly, it's super simple but was hidden beneath a ton of features.
  • Why is this bad? The entire economic security of the Cosmos SDK relies on the assumption that this cannot happen! As an example, an attacker could vote in a Governance proposal and the immediately unbond to use the funds.
  • While reviewing the issue, they noticed several occurrences of this happening on the Cosmos Hub. Some of them were the reporter testing out the issue but many were live exploits. This means that a bug collision existed and that somebody was abusing the vulnerability for their own gain. Yikes!
  • The author wrote up some notes on the remediation process in the code but also the coordination with the affected parties. Being able to notify all of the different blockchains is an important yet difficult problem to solve. Overall, an awesome post on a simple yet deep vulnerability.

IBC Rate Limits: Extending IBC Rate Limits (3/3)- 1378

Range Team    Reference →Posted 1 Year Ago
  • This is part 3 of a series about IBC (interblockchain communication) token rate limiting. They have a nice dashboard that shows all of the rate limits on Osmosis. In this article, they attempt to make some improvements to IBC rate limits.
  • Right now, the rate limits must be approved via a governance proposal. This means that new tokens don't have limits and that's a bummer. So, they recommended including a default rate limit when it's a new token on chain. This PR is still open though.
  • The next issue they tackle is boundary attacks. The way that the rate limit is designed is using periods instead of a running time box. So, an attacker can transfer all of the tokens they can at the end of a period then a bunch more at the beginning of the period. The period is reset within the execution of a given transaction.
  • Instead, they recommend using a automatic period rollover for the rate limiting for A) security and B) usability. They implemented this by resetting the limit within the EndBlocker once the period has ended.
  • This is still susceptible to boundary attacks though. So, they have a two period averaging algorithm. The idea behind this is to calculate the average values of the capacity between two periods. They decided to add a decay on the earlier periods in order to make it more user friendly on UIs. Again, there is an open PR for both of these changes.
  • Another idea is to add notional value rate limits. However, this requires Oracles in order to do correctly, which has its own security risks. Depending on where the values are coming from, they can be manipulated or have times of volatility.
  • Having speed bumps or timelocks can allow for action to be taken. The same thing can be done for large transactions - simply delaying them for some static amount of time can allow for actions to take place.
  • To make life better for big parties, having conditional bypasses can be good as well. For instance, a sender based allowlist, transaction type or whatever else. However, doing this can open things up to an attack if they can be abused.
  • Overall, these seem good; it's awesome having it documented though. Wormhole has a rolling time period to prevent boundary issues. Additionally, there are notional values that are used from CoinGecko too. The research was good but it's a bummer that most of the PRs haven't been merged into the project.

But You Told Me You Were Safe: Attacking the Mozilla Firefox Sandbox (Part 2) - 1377

Hossein Lotfi    Reference →Posted 1 Year Ago
  • In part one, the author used a prototype pollution vulnerability to compromise the Renderer process. In part two, they uses another prototype pollution vulnerability from their privileged position.
  • The sandboxed renderer process has various interfaces for communicating with the privileged Chrome process. Some are even directly reachable through JavaScript. One of these inferfaces is NotificationDB, which is almost only JavaScript by itself.
  • The Notification:Save() function calls into taskSave(). When saving, it checks the objects origin and notification. It performs a write like this -
    this.notifications[origin][notification.id] = notification;
    
  • If the value of origin is set to __proto__ then notification.id will also be part of the write, with the rest of the notification being the value written. Using this, any global JavaScript can be overwritten! Since is not just limited to the NotificationDB.jsm either; it affects all JavaScript modules for any Chrome-level things.
  • In the TabAttributes.jsm module, there is some code that iterates through the element of a list called data using a for. Luckily for us, this will only iterate over prototypes! Using this code, it's possible to set arbitrary HTML (typically XUL) attribute of a tab. To trigger this, there are a few ways but one of them is the most convenient - crash the tab and on automatic reinitialization the pollution happens.
  • The XUL event handlers can be used within the attributes. So, on page load when the pollution happens, we can add a JavaScript to onunderflow attributes to execute arbitrary JavaScript within the Chrome process. Since this is highly privileged process, compromise is fairly trivial.
  • To start with, they set the preference security.sandbox.content.level to 0 in order to prevent sandboxing in new tabs for the future. From there, we open a new tab and call C:\\Windows\\System32\\cmd.exe to execute arbitrary commands. Game over at this point.
  • Every language seems to have its drawbacks in terms of security. C has memory corruption issues, JavaScript has prototype pollution... Overall, a fascinating series on using a memory safe language to still compromise the browser via a logic bug.

But You Told Me You Were Safe: Attacking the Mozilla Firefox Renderer (Part 1) - 1376

Hossein Lotfi    Reference →Posted 1 Year Ago
  • Browser exploitation is extremely complicated and difficult. Most of the bugs are memory corruption issues. Hence, there are multiple layers of exploitation required because of a large amount of sandboxing. In this two part series, ZDI goes through a Firefox browser compromise that uses prototype pollution instead of memory corruption through and through.
  • In the Firefox JavaScript engine SpiderMonkey, large parts are implemented using built-in JavaScript. The code runs in the same context as the users code, which is interesting. Prototype pollution is a vulnerability class that changes the prototype object of JavaScript to perform unintended operations.
  • When handling the top level await feature, the function GatherAsyncParentCompletions is called. Within this, there is a call to array.push, which uses the prototype hierarchy. By setting the getter/setter for the prototype, we can trigger an external call to me made. Why does this matter? We can get access to the module type in JavaScript!
  • The SpiderMonkey code has some privileged function calls. By getting a reference to the module object via the pollution on the prototype, we trivially get memory corruption with out of bounds array writes. Aptly, there is no bounds check with the function named UnsafeSetReservedSlot()
  • To exploit this, the author goes through a few steps:
    1. Create a new array object.
    2. Set some of the properties of the object to force the allocation of a slot_ array.
    3. Use our out of bounds write bug from above to corrupt the capacity of the array.
    4. Use the array to read and write into the heap to corruption all the things.
  • To get code execution, they wrote their shellcode as floating point numbers in Web Assembly that were JITed. Now, they can jump to this location to start a chain. There are some funny restrictions like the same series of 8 bytes can't be used in a row. So, they call VirtualProtect from their shellcode in order to circumvent the JIT W^X protection.
  • This compromises the renderer but there is still much more to hack! The next post goes into the sandbox escape.