Skip to content
On this page

S1C7: Delegate

1. 问题

挑战使用 delegatecall 调用一个 Delegate 合约。需要操纵 delegatecall 的目标和参数来获取 flag。

2. 原因

delegatecall 在调用者的存储上下文中执行被调用合约的代码。如果 Delegate 合约有修改关键存储变量的函数,攻击者可以通过 delegatecall 修改挑战合约的存储。

3. 方案

  1. 分析 Delegate 合约的存储布局,确定哪个函数会修改挑战合约的关键变量
  2. 通过挑战合约的 delegatecall 入口调用该函数
  3. 两次 cast send 完成攻击
bash
# Step 1: 通过 delegatecall 修改关键状态
cast send $CHALLENGE "forwardCall(bytes)" <encoded_delegate_call>
# Step 2: 调用 mintFlag
cast send $CHALLENGE "mintFlag()"

4. 遇到的陷阱

存储布局冲突: delegatecall 保持调用者的存储布局,需要使用相同存储槽位的变量。

5. 陷阱的原因

delegatecall 不改变 msg.sender 和存储上下文,只借用被调用合约的代码逻辑。变量按照声明顺序存储在槽位中,如果两个合约的变量声明顺序不同,会导致意外的存储覆盖。

6. 如何解决

仔细分析挑战合约和 Delegate 合约的存储布局。使用 cast storage 读取关键槽位,确保调用正确的函数。

7. 技术要点

要点说明
delegatecall借用目标合约的代码,但使用调用者的存储上下文和 msg.sender
存储布局冲突合约升级/代理模式中的经典问题:存储槽位必须对齐
代理模式delegatecall 是 UUPS/Transparent 代理的基础

Built with AiAda