Skip to content

Latest commit

 

History

History
393 lines (280 loc) · 25.7 KB

doublespending.md

File metadata and controls

393 lines (280 loc) · 25.7 KB
timezone
Pacific/Auckland

请在上边的 timezone 添加你的当地时区,这会有助于你的打卡状态的自动化更新,如果没有添加,默认为北京时间 UTC+8 时区 时区请参考以下列表,请移除 # 以后的内容

timezone: Pacific/Honolulu # 夏威夷-阿留申标准时间 (UTC-10)

timezone: America/Anchorage # 阿拉斯加标准时间 (UTC-9)

timezone: America/Los_Angeles # 太平洋标准时间 (UTC-8)

timezone: America/Denver # 山地标准时间 (UTC-7)

timezone: America/Chicago # 中部标准时间 (UTC-6)

timezone: America/New_York # 东部标准时间 (UTC-5)

timezone: America/Halifax # 大西洋标准时间 (UTC-4)

timezone: America/St_Johns # 纽芬兰标准时间 (UTC-3:30)

timezone: America/Sao_Paulo # 巴西利亚时间 (UTC-3)

timezone: Atlantic/Azores # 亚速尔群岛时间 (UTC-1)

timezone: Europe/London # 格林威治标准时间 (UTC+0)

timezone: Europe/Berlin # 中欧标准时间 (UTC+1)

timezone: Europe/Helsinki # 东欧标准时间 (UTC+2)

timezone: Europe/Moscow # 莫斯科标准时间 (UTC+3)

timezone: Asia/Dubai # 海湾标准时间 (UTC+4)

timezone: Asia/Kolkata # 印度标准时间 (UTC+5:30)

timezone: Asia/Dhaka # 孟加拉国标准时间 (UTC+6)

timezone: Asia/Bangkok # 中南半岛时间 (UTC+7)

timezone: Asia/Shanghai # 中国标准时间 (UTC+8)

timezone: Asia/Taipei # 台灣标准时间 (UTC+8)

timezone: Asia/Tokyo # 日本标准时间 (UTC+9)

timezone: Australia/Sydney # 澳大利亚东部标准时间 (UTC+10)

timezone: Pacific/Auckland # 新西兰标准时间 (UTC+12)


doublespending

  1. 自我介绍 Doublespending
  2. 你认为你会完成本次残酷学习吗?Yes

Notes

2024.08.29

A: Damn Vulnerable DeFi(18)

2024.08.30

A: Damn Vulnerable DeFi(18)

2024.08.31

A: Damn Vulnerable DeFi(18)

  • The Rewarder
    • claimRewards uses_setClaimed to prevent reclaiming based on <token, sender, batchNumber>.
    • However, _setClaimed is only called after token switch of inputClaims array.
    • So, before switching token, we can reclaim with same <token, sender, batchNumber>.

2024.09.01

A: Damn Vulnerable DeFi(18)

  • Selfie
    • If we want to take all the token inside SelfiePool
    • We should call SelfiePool.emergencyExit
    • To bypass the check of SelfiePool.emergencyExit, we should use SimpleGovernance.executeAction.
    • To execute an action, we should calling SimpleGovernance.queueAction first.
    • To call SimpleGovernance.queueAction, we should bypass the check of _hasEnoughVotes which means we should get more than half of the voting token.
    • We can use SelfiePool.flashLoan to get the require token voting token.
    • Then, we can delegate the token and SimpleGovernance.queueAction.
    • Finally, we can return the token to SelfiePool.
    • After ACTION_DELAY_IN_SECONDS, we can call SimpleGovernance.executeAction.

2024.09.02

A: Damn Vulnerable DeFi(18)

  • Compromised

    • The basic attack vector is that we buy the nft with low price and sell it with high price.
    • So, we should manipulate oracle. Specifically, we should control two of the three price sources to manipulate the median price.
    • The strange response from the server includes the base64 encoded private keys of two price sources.
    • With the private keys, we can manipulate the nft price oracle.

2024.09.03

A: Damn Vulnerable DeFi(18)

  • Puppet
    • We can manipulate the oracle price of PuppetPool to enable almost free borrow.
    • At first, We can sell the token for ETH to make uniswapPair.balance * (10 ** 18) / token.balanceOf(uniswapPair) small
    • Then, we borrow all the token balance of PuppetPool with very few ETH.
    • Finally, we can sell ETH for the token to get back tokens which are used to manipulate the oracle price of PuppetPool.
    • Note: If we want to attack with only one transacation, we can
      • Deploy an Attacker contract
      • Attack inside the constructor
      • Pay ETH to constructor
      • Pay Token to constructor by permit2

2024.09.04

A: Damn Vulnerable DeFi(18)

  • Puppet V2
    • The attack vector is still exist like Puppet
    • The differences are
      • use WETH instead of ETH
      • use IUniswapV2Router02

2024.09.05

A: Damn Vulnerable DeFi(18)

  • Backdoor
    • We find that proxyCreated will ensure the setup process is fine
    • So, we can check if there is something missed
    • We can see that <to, data> and <paymentToken, payment, paymentReceiver> are not checked.
    • However, proxyCreated is called after setup, so we do not have any token to transfer
    • Then, we can check the logic of setupModules(to, data)
    • Finally, we find that delegate call is allowed here.
    • So, we can let the wallet approve the token to anyone by manipulate the <to, data> input.
    • Finally, we can use transferFrom to rug the token of the wallet.

2024.09.06

A: Damn Vulnerable DeFi(18)

  • Free Rider

    • From here, we can buy nft for free

      • payable(_token.ownerOf(tokenId)).sendValue(priceToPay) actually pay to the new owner (i.e. msg.sender) instead of the previous owner
    • However, we need to have enough ETH to bypass the check here when buying the first NFT.
    • We find that we can use the flashswap of uniswap v2
      • Put the above logic inside uniswapV2Call

2024.09.07

A: Damn Vulnerable DeFi(18)

  • Climber
    • If we want to transfer all token of ClimberVault, we have three potential choices:
      • withdraw: onlyOwner
      • sweepFunds: onlySweeper
      • upgradeToAndCall: onlyOwner
    • sweeper can only be set while initialize. It is unlikely compromised.
    • owner is the ClimberTimelock. It is more likely compromised. Then, upgradeToAndCall is more dangerous than withdraw
    • So, we need ClimberTimelock to call upgradeToAndCall. We must call execute in this case.
  • It seem that we actor as ClimberTimelock itself to do arbitrary call including upgradeToAndCall until the check here
  • To bypass the check
    • We should make scheduled operation can be executed immediatedly. So, we can update dely to zero here.
    • We should call schedule.

2024.09.08

A: Damn Vulnerable DeFi(18)

  • Wallet Mining
    • At first we should find the nonce that match the USER_DEPOSIT_ADDRESS. After brute-force method, we find that nonce equals to 13
    • Then, we should bypass can(msg.sender, aim)
    • It's weired that we actually can reinit the AuthorizedUpgradeable for the misuse of the slots under TransparentProxy
      • When the proxy calls the init method of AuthorizedUpgradeable, needsInit is actually the first slot of TransparentProxy (e.g. upgrader) instead of the first slot of AuthorizedUpgradeable (e.g. needsInit).
      • At first, upgrader is msg.sender. So, we can bypass the check here.
      • Then, AuthorizerFactory will set upgrader to zero address
      • Finally, upgrader is set to non-zero address again. So, we can reinit.

2024.09.09

A: Damn Vulnerable DeFi(18)

  • ABI Smuggling

    • The key is to bypass the selector check when exeucte

          bytes4 selector;
          uint256 calldataOffset = 4 + 32 * 3; // calldata position where `actionData` begins
          assembly {
              selector := calldataload(calldataOffset)
          }
      
          if (!permissions[getActionId(selector, msg.sender, target)]) {
              revert NotAllowed();
          }
      
    • The above implemtation to fetch selector is not correct. For, the data of actionData is not required to follow the offset of actionData. The right approach to fetch selector is according to the offset.

    • So, we can add malicious data following the offset and let the above code fetch wrong selector which is approved to player.

    • Then, we set offset to skip the malicious data and point to the real selector which will be executed here.

2024.09.10

A: Damn Vulnerable DeFi(18)

  • Puppet V3
    • The attack vector is the same as Puppet and Puppet V2
    • The differences are
      • Uniswap v3 oracle will prevent price manipulation in the same block. So, we should call lendingPool.borrow in the future block.
      • use ISwapRouter of Uniswap V3

2024.09.11

A: Damn Vulnerable DeFi(18)

  • Shards

    • First, we can buy shards for free becase the required token can be zero in case want * _toDVT(offer.price, _currentRate) < offer.totalShards. We find the max number of free shards is 133.
    • Then, we can cancel immediately because of the incorrect timestamp check
    • Again, there is also incorrect calculation of refund token here.
    • We can keep calling fill and cancel to fetch all the token of ShardsNFTMarketplace.

2024.09.12

A: Damn Vulnerable DeFi(18)

  • Withdrawal
    • As a operator, we can invoke arbitrary withdrawal to secure all the token inside l1 bridge.
    • Then, we should leave enough token to l1 bride for 3 noraml withdrawals and not enough token for 1 suspicious withdrawal with pretty large amount.
    • Then, after the DELAY, we can finalize the 4 withdrawals.
      • The 3 normal withdrawals can receive the token
      • The 1 suspicous withdrawals cannot recevie the token for the l1 bridge does not have enough token.
      • No matter if the reciver can receive the token, the withdrawals will finalized.
    • Finally, we should return the token back to the l1 bridge.

2024.09.13

A: Damn Vulnerable DeFi(18) DONE

2024.09.14

skip

2024.09.15

B: EthTaipei CTF 2023(5)

2024.09.16

B: EthTaipei CTF 2023(5)

2024.09.17

skip

2024.09.18

B: EthTaipei CTF 2023(5)

  • CasinoAdvanced
    • Almost the same as Casino
    • Besides, we should swap the free WETH to USDC to play the game which will have 2x returns in some slots. Then, we can withdraw all the USDC inside CasinoAdvanced.
    • Next, we should swap the USDC to WBTC to play the game which will have 2x returns in some slots. Then, we can withdraw all the WBTC inside CasinoAdvanced.

2024.09.19

B: EthTaipei CTF 2023(5)

2024.09.20

B: EthTaipei CTF 2023(5)

  • WBC
    • We should create contract Ans implmenting IGame to satisfy the requirements of WBC
    • To pass bodyCheck
      • Call bodyCheck inside constructor of Ans to meet the requirement here
      • Use differnt salt to create Ans with different addresses to meet the requirement here
    • To pass ready
      • judge() of Ans should return block.conbase.
    • To pass _swing
      • To pass _secondBase
      • steal() of Ans should return the input value by just copy
      • To pass _thirdBase - We should find xxx that this.decode(xxx) = "HitAndRun".
        • xxx = 0*(32-10)||9||HitAndRun
            function decode(bytes32 data) external pure returns (string memory) {
              assembly {
                  mstore(0x20, 0x20)
                  mstore(0x49, data)
                  // [0x20(offset), 0*9 || data[0:23](length), data[23:32] || 0*23(raw)]
                  // [0x20(offset), 0*9 || xxx.length(length), xxx.data || 0*23(raw)]
                  return(0x20, 0x60)
              }
            }
          
      • To pass _homeBase
        • We should find a way to distinguish the two sequential static call. - We can use gasleft()
        • We can find a value i - gasleft() % i == 0 in the first call - gasleft() % i != 0 in the second call

2024.09.21

B: Grey Cat the Flag 2024 Milotruck challs (6)

  • GreyHats Dollar
    • The share finally updates at this line
    • transferFrom has not consider the case that from equals to to.

2024.09.22

B: Grey Cat the Flag 2024 Milotruck challs (6)

  • Escrow

    • Ownership of escrowId has been renounced at the end.

    • So, we should find a way to get back the ownership through deployEscrow

    • Approach 1

    • Approach 2

      • To by pass the check here, we can construct different implId that can generate the same escrowId
      • We can add the same implementation here with the same impl parameter.
      • Then, we get different implId(=1) with the same impl and implId does not contribute to escrowId
      • However, only factory owner can call addImplementation.