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!

SportsDAO Flashloan Attack Analysis- 1022

Faith    Reference →Posted 3 Years Ago
  • The SportDAO is a DAO centered around athletics. There are many collectables in sports that can easily moved to blockchain like playing cards and sneakers. The SportsDAO has its own sDAO tokens as well.
  • The sDAO appears to be a standard ERC20 token but has a few extra functions that override the standard IERC20 functions. A few to note for this vulnerability:
    • stakeLP(): Allows a user to stake BUSD-sDAO LP tokens directly in the contract.
    • getReward(): Collect sDAO tokens from the staked LP tokens.
    • withdrawTeam(): Transfers all LP tokens to a preset TEAM address.
    • tranferFrom(): Added functionality for calculating the total staking reward of the tokens accumulated when sDAO tokens are transfered from the BUSD-sDAO token contract.
  • The code for the transferFrom() math for the tokens is incorrect. When executing the code for staking, the functionality only checks to see if the address we're trying to transfer to is the BUSD-sDAO LP token. If it is, then 7% of that is added directly to the totalStakeReward.
  • Why is this a problem? The variable totalStakeReward is used directly in the rewards per token calculation AND is directly accessible to any user. Within the transfer() function, only msg.sender must be the owner, indicating this is a flaw in the contract.
  • The final piece of the puzzle is that the function withdrawTeam() can be called externally by anybody to send funds to the TEAM address, which is owned by the SportsDAO. By pairing this functionality of transferring with the direct control over some of the fields for rewards, we come across a vulnerability!
  • The issue relies in the control of sending funds and the control over the math happening. In the statement below, the funds of LPInstance can be removed by the second issue mentioned above. Since this is the denominator of the math, controlling this is a HUGE deal.
    newPerTokenReward = (totalStakeReward - lastTotalStakeReward) * 1e18 
                             / LPInstance.balanceOf(address(this));
    
  • The idea is to make the funds of LPInstance be extremely small; this can be done first by removing all of the funds via the withdrawTeam() then adding in a tiny amount via the bug in transferFrom(). Once the denominator is tiny, the math for the rewards is completely busted. The amount of rewards per token will be extremely high, since it believes it has very little of the token!
  • An attacker used this pair of bugs, alongside a small flash loan, to get a large amount of funds from the contract. The author of this post includes a full proof of concept as well. Overall, awesome explanation of the vulnerability and nice POC!

Hack Analysis: Saddle Finance, April 2022- 1021

Immunefi    Reference →Posted 3 Years Ago
  • Saddle Finance is an automated market maker (AMM) on Ethereum. In particular, they specialize in stable swaps and aim to reduce the slippage of users. The bulk of the code is based on Curve but has been widely re-implemented.
  • There are two types of pools: Standard and Meta. The standard pool is an AMM pool where the tokens provided for liquidity are swapped via the pool. In the meta tool, a pegged token and another token represent the liquidity in the standard pool. Meta allow liquidity in one pool to be used in additional pools.
  • When trying to figure out the fees for a given Liquidity Provider (LP) token, there is a mispricing. The LP token's virtual price grows and grows as more fees are taken. However, the swap function does not account for this virtual price. The base virtual price calculation was simply NOT applied to the contract.
  • Interestingly enough, forks of Saddle (Nerve and Synapse) were exploited for a similar issue. Patches were made to the forks and Saddle itself but they missed the patch on the swap calculation.
  • At a high level, we need make a very large swap for the LP token with the missing price calculation. How this is precisely done:
    • Obtain USDC funds via a flash loan.
    • Swap USDC for sUSD.
    • Swap the sUSD into the Saddle pool in order to get the LP token via the Meta pool.
    • Swap the LP token for sUSD via the Meta pool. Doing this over and over again allows for us to obtain a lot more sUSD because of the LP token mispricing.
    • Swap sUSD for USDC.
  • In the real world attack, the attacker swaps the sUSD and LP several times to remove all of the liquidity from the Meta pool. The article demonstrates a proof of concept of the exploit as well, which is pretty cool to look at!
  • Two takeaways for me. First, financial calculation mistakes are easy to make, hard to trace and costly- they are not obvious patterns to follow for auditors. Secondly, where there are bugs, there are likely more bugs! In this case, they patched the bulk of the functionality but missed a single location. Unfortunately, this was all the attacker needed.

Mt Pelerin Double Transaction Bugfix Review- 1020

Immunefi    Reference →Posted 3 Years Ago
  • Mt Pelerin is a financial intuition in Switzerland that leverages the blockchain to operate. The smart contract ComplianceRegistry is responsible for stores identity information linked to an address and the storage history of the address.
  • This Compliance Registry is managed by trusted intermediaries, such as KYC/AML providers. Based on the tokens used provider, the registry will return the compliance information of the token.
  • The function cancelOnHoldTransfer can be called to cancel transfers for a trusted intermediary to get their tokens back. This takes in a trusted intermediary and an array of transactions to cancel. There is a loop that verifies that the transfer.from is the same as msg.sender for the transaction to cancel.
  • While looping over the array, it does not check to see if the transaction has been cancelled. Since the cancelled funds are sent back to the user at the end of each transaction, infinite money can be stolen using this technique.
  • The transactions would be cancelled, but it's at the end of the loop. So, to exploit this, the same transaction needs to be added multiple times to steal all of the money. Overall, a good bug that seems to be common when looping over elements that own money.

The Defrauded Fraud Proof of A Bitcoin Bridge- 1019

pwning.eth    Reference →Posted 3 Years Ago
  • interBTC is a wrapper around Bitcoin on the Polkadot ecosystem. Each interBTC is backed 1 to 1 for Bitcoin.
  • Over-collateralization is when a loan of more money is used to obtain something of lesser value. In the context of cryptocurrencies, this is commonly used for Collateralized Debt Position (CDP) protocols for minting stable coins from valuable assets. For instance, the MakerDAO does this for the DAI token.
  • In the context of InterBTC, a mapping of a high value token (BTC) to the native tokens of INTR and KINT can be made. Usually, the price properties of these tokens are made by price oracles. How do we trust these anonymous entities though?
  • When using Bitcoins assets from the Bitcoin blockchain to the Moonlight blockchain, there has to be a way to verify that the things claimed from BTC are correct. This is done via a Simplified Payment Verification (SPV) system. The validation is done by storing minimum information about the header of each block then checking the merkle proof and it.
  • An off-chain relayer ensures that the vaults don't move BTC unless specific calls are made. If a vault moves BTC without authorization, then the collateral of the vault is slashed. A vault can be reported for fraud by calling the function report_vault_double_payment(), which takes two txs and verify that they reference the same user request.
  • When comparing if two tx's are the different, the check is flawed. The class BytesParser will ignore trailing bytes of a raw transaction. This results in different transactions being parsed into the same transaction. From looking at the fix, it appears that a duplication check for the two IDs needs to be done. Hence, an attacker can report ANY vault and steal 5% of the funds while the rest get dumped.
  • Within Moonlight, there are several different versions of an address. All of the balances are maintained by uxtos; every utxtos has a public key which can only be unlocked with the corresponding ScriptSig or private key.
  • One of the interesting types is Pay to Script Hash (P2SH). Any public key can be encoded in a vault address with just its hash and the actual public key. The rest of the ScriptSig can be edited to match our mutable public key.
  • This creates a signature malleability problem with trying to ensure duplicates aren't being used. This isn't a problem until we enter the SPV system.
  • This lack of consistency on the public key has interesting implications. Within the SPV system, the function report_vault_theft gets the ScriptPubKey address from the ScriptSig. However, as mentioned before, we can arbitrarily forge these to return other vaults. So, we can always bypass the misbehavior checks and, even worse, we can get a benign vault slashed to steal money! P2WSH had a similar parsing problem as well.
  • What's the solution to this? Since these are fundamental design flaws, they decided to remove the theft reporting functions entirely. Overall, this was an awesome post diving into the complicated parts of a blockchain ecosystem.

How to Steal $100M from Flawless Smart Contracts- 1018

PwningEth    Reference →Posted 3 Years Ago
  • The delegateCall() function in Solidity is used to share the state between two contracts. The msg.value and msg.sender are shared when using this call. In the context of native contracts or functions emitting events, this has weird consequences though.
  • In a different bug in the Aurora Engine, an abuse of this was found to make a delegateCall to an event emitter. Then, an offchain listener would add the funds to this user account. Since the msg.value was never actually sent to the contract, this essentially prints money. What else could go wrong with this? An interesting note is that the delegateCall() user is preserved the original user and NOT from the actual caller.
  • Moonbeam and Moonriver are EVM compatible platforms. The native tokens, MOVR and GLMR, are precompiled ERC-20 contracts. When making calls to EVM related functions, it preserves the msg.sender for the call.
  • So, what's the actual issue? The msg.sender preservation can be abused to perform an action as another user! Simply calling something with delegateCall() will preserve this, allowing the msg.sender to be the actual user on calls to other contracts.
  • Currently, we still need a way to get the user to execute our code. This could be done via a phishing attack to execute a contract, but could be hard to do. In reality, all we need is a callback in our contract to be hit. What has callbacks? Flash loan providers! This could have been used to steal 12M without any user interaction.
  • They also found a callback on a protocol called Glimmer. Although there is not too much being stored in the native MOVR contract, the amount deposited is consider collateral from the lending protocol. So, the steps of deposit, borrow, transfer and bad debt can be used over and over again to steal all of the funds from the contract!
  • delegateCall() is a dangerous function in the EVM. From user impersonation to logs to the older days of malicious calls, the consequences of it need to be well audited. Good find!

Velas Infinite Mint Vulnerability Writeup- 1017

Oren Yomtov    Reference →Posted 3 Years Ago
  • While reading blockchain security articles, the author of this post stumbled across this post talking about delegatecall() on a pre-compiled contract causing infinite money creation problems because of the events it was emitting.
  • From there, they went through a list of the most popular blockchains one by one. The author was looking for pre-compiled smart contracts to see if any of them were vulnerable to the delegatecall() attack mentioned above. Eventually, they stumbled upon Velas.
  • Velas is a side chain built on Solana but has a special instruction to invoke EVM programs as well. With the chains native currency VLX, this is held by the Native Type. When a program runs in the EVM space, it belongs to the EvmState account.
  • The bridge between VLX from the EVM space to the Native space is done by sending a transaction to a precompiled contract. By making a delegateCall to the function transferToNative the contract believes that the proper funds are there even though the contract making the delegateCall is the true owner of the funds.
  • The blockchain now executes code that will transfer the funds back to the native state, even though they were never removed from the ETH state. This can be done over and over again to create an infinite amount of VLX tokens in the EVM space. Overall, great bug discovery after a lot of time of looking!

CVE-2022-40300: SQL Injection in ManageEngine Privileged Access Management- 1016

Zero Day Initiative (ZDI)    Reference →Posted 3 Years Ago
  • Password Manager Pro is a secure vault for storing and managing shared sensitive information such as passwords, documents, and digital identities of enterprises. A user can access the web console via three different services.
  • When making a request to add a resource, there is a partially built SQL statement. With this statement, it uses a find and replace functionality to add in the resource from the request. Since this does not do any verification on the text, this creates a SQL injection issue on future calls.
  • This vulnerability is an authenticated issue but does lead to arbitrary SQL code using as SYSTEM on Windows. Overall, the bug explanation is okay... they seem to go too deep on things that don't matter, like the specifics of the HTTP protocol. Fun bug though! SQL injection is alive and well is 2022!

RCE in Tailscale, DNS Rebinding, and You- 1015

Emily Trau    Reference →Posted 3 Years Ago
  • Tailscale is a mesh VPN service. A network connection is established with Wireguard to one another on demand. To execute the website code for a VPN user, it will use the V8 engine. The security features for connected to privileged sockets and the Same Origin Policy (SOP) apply as well.
  • The setup was vulnerable to DNS rebinding attacks. This means that although the original DNS request mapped to some domain, on the next DNS request it will map to something else. What would be good to map to? 127.0.0.1 or localhost of course!
  • Since we're now on the localhost, we have the permissions to all the API without any authentication. This gives us the ability to introspect and reconfigure the tailscaled binary used for configuring the service. What can we do with this issue? Accessing private keys from the node is possible with this.
  • Using the previous vulnerability, many other things can be hit. A PATCH request to the preferences API can be used to update the control plane server. This allows us backdoored access to the network that this computer is on. When using this URL, it is specified as a parameter to open up a web browser. This can be used to open arbitrary binaries from the internet; absolutely amazing.
  • The issue above has the Mark of the Web, meaning a user is asked whether or not this can be executed. The application can be configured for the proxy to NOT mark stuff with the Mark of the Web! This means we can download an executable to the local machine and use the previous bug to execute it without any other popups.
  • After getting code execution on the device, they go more into how the DNS rebinding affects different browsers and different operators systems. They learned that the attack they were using worked fine locally but NOT remotely because of the browser protections in Chrome. FireFox was exploitable from a remote context though.
  • The Tailscaled server runs a web server at 100.100.100.100. Since this isn't considered a private address, this is vulnerable to rebinding attacks. They also found that the PeerAPI was vulnerable to the rebinding as well. The security model of Tailscale says to use authentication based upon network position. This is not a great thing to do with the threat of DNS rebinding.
  • Overall, an interesting piece of research into the VPN and a good representation of the dangers of DNS rebinding. Good work!

System misconfiguration is the number one vulnerability, at least for Mastodon- 1014

Lenin Alevski    Reference →Posted 3 Years Ago
  • During an interview, the author of the post once got the question: "What is the most common security vulnerability?" To Lenin's surprise, it was system misconfiguration.
  • With people flocking from Twitter to Mastodon, the author of the post decided to take a look at the security of the infosec Mastodon. While on it, they were curious how the user content was stored. The content appeared to be an AWS S3 XML response. On top of this, it was from minio (Multi-Cloud Object Storage).
  • The hacker made some observations:
    • User content is uploaded to minio buckets.
    • If this is coming directly from a browser request then there must be anonymous read access on the resources.
  • Using the minio client, which is similar to S3, they were able to list the contents of the Mastodon S3 bucket. Additionally, there were other folders in this bucket that were NOT meant to be public.
  • If we can read, can we write? The author attempted to upload something and it worked! They made a tiny modification to the Infosec Mastodon logo just to prove a point. What's the security issue? The S3 bucket policy allows for s3:*. They noticed this problem on other Mastodon servers as well.
  • Overall, a great commentary on the most common security vulnerability of them all - misconfigurations.

A Confused Deputy Vulnerability in AWS AppSync- 1013

Nick Frichette - Datadog    Reference →Posted 3 Years Ago
  • AWS Appsync is a GraphQL endpoint as a service. There are several different underlying data storage, such Lambda, DynamoDB, RDS and many others. There is also a custom option for this, which allows for the creating of developer written resolvers.
  • To authorize the actions that AppSync will perform, a role ARN is passed in. The role has two components: a trust policy for who can assume the role and the IAM permissions this provides. In this case, the trusted entity for assuming is AppSync and the permissions are S3.
  • Here's a good question: what stops a user from passing in an IAM role from a different account? The service has permission to assume the role, since they are allowed in the policy, but not for this user. This is known as the Confused Deputy Problem - "where a less-privileged entity (the attacker) convinces a more-privileged entity or service (AppSync) to perform some action on its behalf."
  • AWS safeguards against these types of attacks quite well - with validation usually being done on the account the role is owned by. This wasn't an exception to the rule! There is validation being done. However, changing the casing of the parameter in the URL skips validation and gets the role to be used anyway.
  • For instance, passing in httpConfig as the parameter with a cross account role wouldn't work. However, HTTPCONFIG would bypass the validation! This allows for the role being assumed into another account.
  • In terms of exploitation, an attacker could pass in the bad role and write there own resolver API to query the information that the role has access to. From S3 buckets to DynamoDB, the custom resolver would have some serious impact here. To remediate the problem slightly, an attacker needs to know the role ARN, the role ARN must have allowlisted AppSync and all of the resources in the account will have to be guessed by the attacker.
  • Case sensitivity problems are not new! The difference between two interpreters - verification and use, caused a major problem here. Overall, pretty neat bug!