Parity Multi-Sig Exploit Case Study
@tomusdrw
Tomasz Drwięga
24 Nov 2017, Katowice
I do feel equally responsible, even though I don't work on contracts development.
Core & Protocol
development
in: Rust
parity (ethereum)
parity-bitcoin
parity-polkadot
UI & dapp dev tools + services
in: JavaScript
Contract development
in: Solidity
parity-ipfs
Parity Wallet
@parity/oo7
PICOPS
Registries & Certifiers
secret-store
parity-bridge
parity-whisper
Multi-Sig
How did it happen then?
Decentralized, blockchain-based platform for programmable money.
User A
User B
Priv A
Pub B
Priv B
5 BTC
Simple transfer from one account to another.
To send funds further B needs to "unlock" them with hers Private Key
Decentralized, blockchain-based platform for programmable money.
User A
Contract
Priv A
Pub C
1. A deposits 5 ETH
in the contract
"Anyone can deposit, but only B can withdraw after block #N.
1% Tax is sent to D upon withdrawal."
User B
Priv B
3. Contract sends 4.95 ETH to B
3. Contract sends 0.05 ETH to D
2. B calls function 'withdraw()'
contract TaxCollector {
address taxAddress;
address withdrawAddress;
// Deploy(create) & initialize the contract
function TaxCollector(address _withdraw, address _tax) public {
withdrawAddress = _withdraw;
taxAddress = _tax;
}
// Fallback function
// (called when 'function name' not provided)
function () public payable {
// no need to do anything, just accept the transfer
}
function withdraw() public {
// only callable by 'B'
require(msg.sender == withdrawAddress);
// Calculate tax
var tax = this.balance / 100;
// Perform the transfers
taxAddress.transfer(tax);
withdrawAddress.transfer(this.balance);
}
}
User A
Priv A
MultiSig Contract
Pub C
"A signature of 3 out of 4 is required to spend funds. Owners: [A, B, X, Y]"
"At least 3 of
[A, B, X, Y] required"
5 ETH
5 ETH
A deploys the Contract
User A
Priv A
MultiSig Contract
Pub C
A, B & X authorize the withdrawal.
User B
Priv B
User X
Priv X
1. "Send 3 ETH to D"
2. "Send 3 ETH to D"
3. "Send 3 ETH to D"
"Contracts sends 3 ETH to D"
Jan, 2014
Ethereum Whitepaper
Jul, 2015
Jan-Jun, 2015
Frontier Launched
Ethereum Audits
Dec, 2015
Parity (EthCore) Founded
Mar, 2016
Parity 1.0 release after security audit
(& homestead HF)
Jun, 2016
DAO Hack
(& HF)
Dec, 2016
Multi-Sig Librarification
Jul, 2017
Multi-Sig
Hack
Nov, 2017
Multi-Sig
Freeze
(the scale not accurate)
Everyone who wants to use the MultSig needs to pay high fee for deploying the Contract
(~2500k GAS)
IDEA: Let's deploy a Library with code and wallets will just refer to that library.
(~500k GAS)
It's also saves blockchain storage space
(good for the entire ecosystem)
Original MultiSig Contract
(audited)
MultiSig Contract
Library
MultiSig Shell
Shell contract just delegates calls to the library
Similar pattern described at https://blog.zeppelin.solutions/proxy-libraries-in-solidity-79fbe4b970fd
// Not an actuall code,
// just to give you the idea.
contract Wallet {
function Wallet(
address[] _owners,
uint _required,
uint _daylimit
) {
_callInitWalletFromLibrary(
_owners,
_required,
_dayLimit
);
}
function() payable {
_delegateCallToLibrary(msg.data);
}
}
WalletStub.sol
contract WalletLibrary {
function WalletLibrary() {
address[] owners; owners.push(address(0x0));
init_wallet(owners, 1, 0);
}
function init_wallet(
address[] _owners, uint _required, uint _daylimit
) only_uninitialized public
{
/* Skipped */
}
// kills the contract sending everything to `_to`.
function kill(address _to) onlymanyowners(sha3(msg.data))
external
{
suicide(_to);
}
function confirm(uint _value, bytes _code) internal
returns (address o_addr)
{
// confirms some operations
}
}
WalletLibrary.sol
Obviously
Tomasz Drwięga
@tomusdrw
Parity Technologies