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!
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.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. 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.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! 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));
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! ComplianceRegistry is responsible for stores identity information linked to an address and the storage history of the address.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.report_vault_double_payment(), which takes two txs and verify that they reference the same user request.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. 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.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. 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.msg.sender for the call.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.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.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!delegatecall() on a pre-compiled contract causing infinite money creation problems because of the events it was emitting.delegatecall() attack mentioned above. Eventually, they stumbled upon Velas.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. 127.0.0.1 or localhost of course!tailscaled binary used for configuring the service. What can we do with this issue? Accessing private keys from the node is possible with this.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. s3:*. They noticed this problem on other Mastodon servers as well.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.