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
- 你认为你会完成本次残酷学习吗?Yes
A: Damn Vulnerable DeFi(18)
- UnstoppableVault
UnstoppableMonitor.onFlashLoan
revert whenconvertToShares(totalSupply) != balanceBefore
- We can get the share amount by
convertToShares(totalSupply)
- In normal case, share amount equals to asset amount by
deposit
ormint
method. - However, if we transfer the token to the pool directly, the share amount does not changed but the asset amount increases.
- NaiveReceiver
- We can send all weth of
IERC3156FlashBorrower receiver
tofeeReceiver
by calling flashLoan 10 times - Then, we use
Forwrarder
to callMulticall
with awithdraw
call. - In this case,
msg.sender
isForwarder
and the pool will use the last 20 bytes as thesender
- So, we can append
feeReceiver
to thewithdraw
call to act asfeeReceiver
.
- We can send all weth of
A: Damn Vulnerable DeFi(18)
- Truster
target.functionCall(data)
can be atoken.approve(player, TOKENS_IN_POOL)
call.- To by pass the balance check, we can set
amount
offlashLoad
to be 0 - Finally, palyer can use
token.transferFrom
to rescue all funds in the pool.
- Side Entrance
- To by pass the balance check, we can set
amount
offlashLoad
to be 0. - Receiver can call
pool.deposit
while calling back to receiver.- the ownership of the deposit can be assigned to receiver.
- the balance of pool have not changed.
- To by pass the balance check, we can set
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 ofinputClaims
array. - So, before switching token, we can reclaim with same <token, sender, batchNumber>.
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 useSimpleGovernance.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 callSimpleGovernance.executeAction
.
- If we want to take all the token inside
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.
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
bypermit2
- Deploy an
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
- The attack vector is still exist like
A: Damn Vulnerable DeFi(18)
- Backdoor
- We find that
proxyCreated
will ensure thesetup
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 aftersetup
, 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.
- We find that
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
- Put the above logic inside
-
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 theClimberTimelock
. It is more likely compromised. Then,upgradeToAndCall
is more dangerous thanwithdraw
- So, we need
ClimberTimelock
to callupgradeToAndCall
. We must callexecute
in this case.
- If we want to transfer all token of
- It seem that we actor as
ClimberTimelock
itself to do arbitrary call includingupgradeToAndCall
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
.- For
address(this)
is the role admin ofPROPOSER_ROLE
. We can updatePROPOSER_ROLE
to malicious contract. - We can call the malicious contract and let it schedule the executions.
- For
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 thatnonce
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 underTransparentProxy
- When the proxy calls the init method of
AuthorizedUpgradeable
,needsInit
is actually the first slot ofTransparentProxy
(e.g.upgrader
) instead of the first slot ofAuthorizedUpgradeable
(e.g.needsInit
). - At first,
upgrader
ismsg.sender
. So, we can bypass the check here. - Then,
AuthorizerFactory
will setupgrader
to zero address - Finally,
upgrader
is set to non-zero address again. So, we can reinit.
- When the proxy calls the init method of
- At first we should find the nonce that match the
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 ofactionData
is not required to follow theoffset
ofactionData
. The right approach to fetchselector
is according to theoffset
. -
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.
-
A: Damn Vulnerable DeFi(18)
- Puppet V3
- The attack vector is the same as
Puppet
andPuppet 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
- Uniswap v3 oracle will prevent price manipulation in the same block. So, we should call
- The attack vector is the same as
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
andcancel
to fetch all the token ofShardsNFTMarketplace
.
- First, we can buy shards for free becase the required token can be zero in case
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.
A: Damn Vulnerable DeFi(18) DONE
- CurvyPuppet
- Curve LP Oracle Manipulation: Post Mortem
- We can manipulate the curve pool using fund from aave flashloan
skip
B: EthTaipei CTF 2023(5)
- Arcade
- According execution order of the code,
_redeem
acutally is executed after_setNewPlayer
insidechangePlayer
- So,
getCurrentPlayerPoints()
will get the point of new player instead of the old palyer. - Finally, old player can mint the token from the points of new player.
- According execution order of the code,
B: EthTaipei CTF 2023(5)
- Casino
- The
_bet
insideplay
is used to charge token from user_bet
will first consider the input token is a CToken and try to callcToken.bet(msg.sender, amount)
. If faild,_bet
will consider the input token as an token.- However, if the token has a fallback function, the
cToken.bet(msg.sender, amount)
can be executed and charge nothing.
- The
CToken.get
insideplay
is sendamount * slot()
ctoken to user- So, we should find a slot where more than
amount
ctoken is sent.
- So, we should find a slot where more than
- Finally, we can call
withdraw
to convert cToken to token.
- The
skip
B: EthTaipei CTF 2023(5)
- CasinoAdvanced
- Almost the same as
Casino
- Besides, we should swap the free
WETH
toUSDC
to play the game which will have 2x returns in some slots. Then, we can withdraw all theUSDC
inside CasinoAdvanced. - Next, we should swap the
USDC
toWBTC
to play the game which will have 2x returns in some slots. Then, we can withdraw all theWBTC
inside CasinoAdvanced.
- Almost the same as
B: EthTaipei CTF 2023(5)
- ETHTaipeiWarRoomNFT
- At first, we can see that balance is changed after NFT transfer. Reentrancy attack is obvious.
- Then, solidity (version < 0.8.0) has not applied underflow check as default.
- Finally, we can withdraw twice using
onERC721Received
callback and make the balance underflow.
B: EthTaipei CTF 2023(5)
- WBC
- We should create contract
Ans
implmentingIGame
to satisfy the requirements ofWBC
- To pass
bodyCheck
- To pass
ready
judge()
ofAns
should returnblock.conbase
.
- To pass
_swing
- To pass
_secondBase
steal()
ofAns
should return theinput
value by just copy- To pass
_thirdBase
- We should find xxx thatthis.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) } }
- xxx = 0*(32-10)||9||HitAndRun
- 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
- We should find a way to distinguish the two sequential static call. - We can use
- To pass
- We should create contract
B: Grey Cat the Flag 2024 Milotruck challs (6)
- GreyHats Dollar
- The share finally updates at this line
transferFrom
has not consider the case thatfrom
equals toto
.- At this case, we get
shares[to=from] = origin + _shares
- However, the share is expected unchanged.
- At this case, we get
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
- To by pass the check here, we can construct different
args
that can generate the sameescrowId
args
contributes totokenX
andtokenY
. They are fetched here.tokenY
is expected to beaddress(0)
.- However,
_getArgAddress
just reads 20 bytes fromargOffset
. - However,
tokenY
can bebytes19(0)
. If the following byte is bytes1(0), we can always gettokenY
asaddress(0)
by_getArgAddress
. - For length of data smaller than 256, so the following byte is bytes1(0).
- Why not just append 0 bytes to
args
?- Becasue there is a length check here
- To by pass the check here, we can construct different
-
Approach 2
- To by pass the check here, we can construct different
implId
that can generate the sameescrowId
- We can add the same implementation here with the same
impl
parameter. - Then, we get different
implId
(=1) with the sameimpl
andimplId
does not contribute toescrowId
- However, only factory owner can call
addImplementation
.
- To by pass the check here, we can construct different
-