{"content":{"title":"零时科技 || OKC 项目被攻击事件分析","body":"​\r\n# 事件背景\r\n2023-11-13 18:51:57 (UTC) 链上发生一笔针对 OKC Token 的攻击事件，黑客通过存在缺陷的MinerPool获取了及时收益\r\n\r\n**黑客攻击交易：**\r\n\r\n0xd85c603f71bb84437bc69b21d785f982f7630355573566fa365dbee4cd236f08\r\n\r\n**黑客攻击合约1：**\r\n\r\n0xD5d8c2fd8A743A89BC497B2F180C52d719a007B9\r\n\r\n**黑客攻击合约2：**\r\n\r\n0x617432Fc98c1fFaAB62B8cB94Cef6D75ABD95598\r\n\r\n**黑客攻击合约3：**\r\n\r\n0x28e7c8337373C81bAF0A4FE88ee6E33d3C23E974\r\n\r\n**攻击者地址：**\r\n\r\n0xbbcc139933D1580e7c40442E09263e90E6F1D66D\r\n\r\n**漏洞合约：**\r\n\r\n0x36016C4F0E0177861E6377f73C380c70138E13EE （MinerPool）\r\n\r\n# 攻击分析\r\n通过对链上交易数据分析，我们对其交易进行整理归纳。\r\n\r\n黑客首先通过多个闪电贷进行对攻击资金的筹集，共借款 2,753,399 USDT Token。\r\n\r\n![image](https://image.3001.net/images/20240103/1704255584_6594e060ca7eeb10784ad.png!small)\r\n\r\n随后立即将其中 130,000 USDT Token 兑换为一个最小单位的 USDT Token 和 27,264 OKC Token 。\r\n\r\n由于 PancakeSwapv2 使用的是AMM（恒定函数做市商），在该模型中，交易池中的两种代币的数量乘积是一个常数。可以用以下公式表示：\r\n![image](https://image.3001.net/images/20240103/1704255601_6594e071440028fe835ee.png!small)\r\n\r\n\r\n其中：\r\n\r\n• x是交易池中第一种代币的数量。\r\n\r\n• y是交易池中第二种代币的数量。\r\n\r\n• k是一个常数，表示池中两种代币数量的乘积。\r\n\r\n当一个交易者想要用一种代币兑换另一种代币时，他们会增加交易池中一种代币的数量（dx），同时减少另一种代币的数量（dy），以保持的不变性。这个过程会改变代币的相对价格。\r\n\r\n假设交易者想要用代币A兑换代币B，那么在交易前后，恒定乘积公式应该保持成立：\r\n![image](https://image.3001.net/images/20240103/1704255618_6594e082e5bf3186965ba.png!small)\r\n\r\n\r\n由于k是不变的，这意味着x·y在交易前后是相同的。但是，因为交易者增加了代币A的数量（dx）并且减少了代币B的数量（dy），这将导致代币B的价格上升。\r\n\r\n代币的即时价格可以通过计算池中两种代币数量的比率来得出。如果代币A是x，代币B是y，则代币B相对于代币A的价格是y/x。在交易之后，代币B的数量减少了，代币A的数量增加了，所以新的价格变成了（y-dy）/(x+dy) 。由于分子减小而分母增大，这个比率变小了，意味着代币B的价格上升。\r\n\r\n在大额交易的情况下，dx和dy可能非常大，这会导致价格的显著变动。这是因为为了保持k的不变，必须从池中移除大量的dy来补偿dx的增加。这种大额交易对池中代币数量的巨大影响导致了价格的显著变化。\r\n\r\n故攻击者通过使用大额闪电贷资金进行买入OKC，导致 OKC 数量减少，从而拉高了 OKC Token 的价格，将 1 OKC = 0.3 USDT 的价格提升到 1 OKC = 68.9 USDT。\r\n![image](https://image.3001.net/images/20240103/1704255636_6594e0947d68719a3ab56.png!small)\r\n\r\n\r\n后攻击者创建了两个合约地址，并分别向两个地址中发送了 0.01 OKC 和 0.0001 USDT 和 一个最小单位的OKC。\r\n\r\n![image](https://image.3001.net/images/20240103/1704255650_6594e0a222c4b8c2be71b.png!small)\r\n\r\n![image](https://image.3001.net/images/20240103/1704255662_6594e0ae1e1cfca5d4b8b.png!small)\r\n\r\n然后黑客使用主要的攻击合约对 PancakePair_USDT_OKC 池子添加流动性操作，得到约 225,705 个LP Token。\r\n![image](https://image.3001.net/images/20240103/1704255684_6594e0c41ac0955cdf6f2.png!small)\r\n\r\n\r\n随后将 LP Token 全部转移至 攻击者创建的 0x28e7c8337373C81bAF0A4FE88ee6E33d3C23E974 攻击合约中随后立即调用漏洞合约中的 processLPReward 函数，对合约内存储的 lpHolder 地址进行奖励分配。此处虽然攻击者的操作只是向 MinerPool 合约转账，但是该合约在接受转账的回调函数中调用了processLPReward 函数。\r\n\r\n![image](https://image.3001.net/images/20240103/1704255699_6594e0d34bd7772e36bff.png!small)\r\n![image](https://image.3001.net/images/20240103/1704255713_6594e0e1a4097f1856279.png!small)\r\n\r\n\r\n根据下图，我们得知攻击合约 0x28e7c8337373C81bAF0A4FE88ee6E33d3C23E974 在奖励领取中获得了 77,890 个 OKC Token。\r\n\r\n![image](https://image.3001.net/images/20240103/1704255728_6594e0f07d247855cea3d.png!small)\r\n\r\n然后攻击者转出攻击合约 0x28e7..E974 的的 LP Token 并将其销毁移除流动性,获得了 1,884,223 USDT Token，以及 27,264 OKC Token。\r\n\r\n并转移出另外两个攻击合约中的所有的Token至主要攻击合约\r\n\r\n0xD5d8c2fd8A743A89BC497B2F180C52d719a007B9 ，分别为：272 个，77,890 个 OKC Token。\r\n\r\n![image](https://image.3001.net/images/20240103/1704255750_6594e10618863c4ab63b1.png!small)\r\n\r\n黑客将所有的OKC ，约 104,610 OKC Token 兑换为约 136,518 USDT Token，此时黑客总持有约 2,759,918 USDT Token。\r\n![image](https://image.3001.net/images/20240103/1704255767_6594e117796f042a432d2.png!small)\r\n\r\n\r\n最后，黑客归还所有闪电贷的本金和利息，最终剩余约 6,268 USDT Token，并全部转移至攻击者地址\r\n\r\n0xbbcc139933D1580e7c40442E09263e90E6F1D66D。\r\n\r\n![image](https://image.3001.net/images/20240103/1704255783_6594e12743d1b94671cfa.png!small)\r\n\r\n# 漏洞分析\r\n通过攻击分析得知，黑客主要获利资金是由 MinerPool 合约中 processLPReward 函数，该函数逻辑主要是获取 lpHolder 并根据其 LP 数量直接按比例进行奖励。\r\n\r\n我们可以看一下攻击者创建的第三个攻击合约中的执行逻辑：\r\n![image](https://image.3001.net/images/20240103/1704255804_6594e13c36c742360dc14.png!small)\r\n\r\n\r\n从该处逻辑可以看出addHolder函数中使用了 extcodesize() 来计算地址当前的大小，用来判断地址是否是合约地址，但是在攻击者通过 CREATE2 创建合约，由于合约在初始化时，该地址大小依然为0，从而来攻击者在其构造函数中调用该函数绕过其中的合约调用限制。\r\n![image](https://image.3001.net/images/20240103/1704255845_6594e165c4450ebbb4cae.png!small)\r\n\r\n其在转账时调用了 addHolder 函数将 合约地址添加到了 lpHolder 名单，所以该合约才可以通过领取奖励获取及时的OKC奖励。\r\n\r\n根据对 processLPReward 函数代码逻辑进行分析，可以从下图中看出，虽然设置了领取奖励的锁定时间，但是未设置 LP 持有时间进行校验或限制，导致黑客通过闪电贷获取大量临时资金，并兑换为LP ，并在领取奖励后立即销毁。\r\n![image](https://image.3001.net/images/20240103/1704255863_6594e17759bfd0e7ed09a.png!small)\r\n\r\n\r\n# 总结\r\n简单来说，黑客通过闪电贷借了大量USDT，并兑换大量OKC，从而拉高了OKC的价格。并且由于OKC项目未设置LP奖励发放的锁仓要求，所以黑客在获取奖励后立刻撤回流动性，从而获取了项目方发放的流动性提供者的奖励。并将OKC项目方奖励的OKC Token出售。最终获利 6,268 USDT。\r\n\r\n\r\n​"},"author":{"user":"https://learnblockchain.cn/people/52","address":null},"history":null,"timestamp":1704255944,"version":1}