Skip to content

Repository files navigation

Balance Retreival

This is a "Balance Retreivar" for the recursive call vulnerability for Maker-Otc.

Results

Block: 1679390

DSEthToken @ 0xd654bdd32fc99471455e86c2e7f7d7b6437e9179

AddressAmmount
0x9a63d185a79129fdab19b58bb631ea36a420544e0
0xf5c7bcb44ebafc72d46dbc70b717272e19024da40
0x1695f4bf231688057ffe247e29bc033cb31d7e60800000000000000002
0xefbadcad52f6baec237731123e638fd4e34f63c48000000000010826
0x01c4f84a43bc3162a6aa911b54044a9f2345325e0
0xbb101ae8ac3cec6e26575b7d6446ee1f91d83c1d0
0x76e21054127ab5fdb3ad8ba1590d2c9cf92c8959200000000000000000
0x3b4ded25c77c7034c3c336f888285df24bd23dd10
0xe25e3a1947405a1f82dd8e3048a9ca471dc782e1603430701484
0x095f5a51d06f6340d80b6d29ea2e88118ad730fe0
0xd25658414d41ab0da3f7e28f592863c5b42181011
0x201d38287aa29bdb16fc512776826d1c370820700
0xba75f066005108d58dc5c4aae3a9be53a0ea920d450000999999963371
0x9f73bc871764c879fd9e0f524278373fa7875068147775869041
0xa96c7266e081c08c911b91081a8c0b5fdc5d3f8b12
0x26bf32bb4efc2c6c73c3819ad7adf18c494d9afe1960000000000000260
0x4406a2c7867470130b06e688c3542122081b7e4a1567
0x9fff802e6bdcbcc47c20c33446e1fd99eb72c70531000
0x859d231d76c0d796bcf46a7304b086e6328682d5336047014800
0x660cf0d7ba6aba3d5c5ff2131e1a1404afa7a00071000000000000000
0x9006a41cbdfbdde6802f63b1795207b56cf0fd991004210615581750
0x0b6a778c8f6bffce3d484cdc78329eb29175bef4505439423237
0xf27960b52ef2cf8c62b145cc3238cb5344386aa2999999999686
0x7d1cd61f6153efd679963d101c5c49374989c7e70
0x26bdce6e4ea9afd060049993ed11f153eb1e322f2
0x57573706e969b480d1fc3e38e7537d71b5e3cdcd0
0x0d53ac8163d98791e77b23da0b5097552f6b6753888888888889
0x0d05b9f9ed0b149d91d91ce7ba89df11e9abb53f12592999000000000
0xb7e4e93fbabf3904d28564574b3692293e6ea4760
0xdc99b79555385ab2fe0ff28c3c954a07b28aac5e920000000439
0x131ce849aadf6624e73b06dd7b7ba7e3c98a6a9b460952381000
0x6a6af0730497634e8c6be9ee2b88eb0e696f1a550
0x8fdb7441bd9263499af346135153a737aa9b3fbb0
0x271b45faf56b0ec406e64ab39b80ec187de71e8c0
0x0009be88c3bf9e0fd0c43ad84ae994d8424fee030
0x76df61770a702069fe1381eae55ad11a03deca9350000000000000000000
0xf8bda96b67036ee48107f2a0695ea673479dda563060000000000000000
0x59b03f715990e90bf7f1317d3dcf50de67fad3510
0x154a7453cec1d76ea38e630c9f852a96e2a97ac5850000000000000000
0xd8da6bf26964af9d7eed9e03e53415d37aa9604522022399999999999180
0x5586b392b5127598e9b3a4635131bc7bbda20c2b40000111111110591
0xcd185269dbaf38ff5d2b5845dd11c62d6d833c22180000000000000000
0xf9dff387dcb5cc4cca5b91adb07a95f54e9f1bb635103958542668000000
0xf764bd7cd53cf07ec70b9c6df16e6c9239b03be90
0x417ab2c56f9509c2cc07a1ada72fbb382f662280820
0xc44f4ab5bc60397c737eb0683391b633f83c48fa10000000000000000
0x46b515cd71a19221ee768c88f492a741108ef3f00
0xf51bc4633f5924465c8c6317169faf3e4312e82f5742025100001000000000
0x35d68fb24df0e54d44e6cc32f75f1cc891f57811999999999561
0xc33b624c14147e8f5d22266c8cd56241fa90d1ae335545090012554050
0x90f011a326b6ecb37284eb5e2113d71228d0187f619047619000
0xa8c8b89fd99a25b4a085dff3d967b47b10b370340
0x5781aab44ceb682eed8afd9b63cbf0f4edefb5e315000000000000000000

SimpleMarket @ 0xf51bc4633f5924465c8c6317169faf3e4312e82f

AddressTokenAmmount
0x095f5a51d06f6340d80b6d29ea2e88118ad730feETH600000000000000000000
0x0d05b9f9ed0b149d91d91ce7ba89df11e9abb53fETH320000001000000000
0x0d05b9f9ed0b149d91d91ce7ba89df11e9abb53fMKR90000000000000000
0xb7e4e93fbabf3904d28564574b3692293e6ea476ETH50000000000000000000
0xf9dff387dcb5cc4cca5b91adb07a95f54e9f1bb6MKR1717247649891466400000
0xf9dff387dcb5cc4cca5b91adb07a95f54e9f1bb6ETH4796250000000000000000
0x154a7453cec1d76ea38e630c9f852a96e2a97ac5ETH3020000000000000000
0x8af93c5312e91fdb0a4c07e5e27256b2967fc926MKR4000000000000000000000
0xcd185269dbaf38ff5d2b5845dd11c62d6d833c22ETH2000000000000000000
0x90f011a326b6ecb37284eb5e2113d71228d0187fMKR59250000000000000000
0x201d38287aa29bdb16fc512776826d1c37082070ETH60000000000000000000
0xd8da6bf26964af9d7eed9e03e53415d37aa96045ETH182315100000000000000
0xd8da6bf26964af9d7eed9e03e53415d37aa96045MKR24486215538847118000
0x26bdce6e4ea9afd060049993ed11f153eb1e322fETH48110000000000000000

Verify

make sure you have dapple installed on your system and an ethereum homestead rpc node running on localhost:8545

  1. clone this repo in git and make sure all submodules are present
git clone git@github.com:nexusdev/hack-recovery.git --recursive
cd hack-recovery
git submodule update --init --recursive
  1. install the needed npm dependencies npm i
  2. run the script make

How it Work

"use strict";

The block height before the attack is 1679390 so we will retreive the needed information from this block.

const blockHeight = 1679390;

Overview

  1. DSEthToken
    1. find all addresses which could hold tokens
    2. find balances for each address
    3. generate and save as object
  2. SimpleMarket
    1. find number of offers
    2. find all offers
    3. filter for valid offers
    4. sort and group offers by address and token
    5. generate and save as object

first we set up our environment

var Web3 = require('web3');
var _ = require('lodash');
var async = require('async');
var BigNumber = require('bignumber.js');
var fs = require('fs');
var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));

DSEthToken

The first contract we want to rescue is the DSEthToken contract. The known vulnerability was discovered in dappsys@92a4fd915b69ccb2553994af3bded429a9467417 Here we load its interface after we build it previously

var dappsys = require('./dappsys.json');
var DSEthToken = web3.eth.contract(JSON.parse(dappsys.DSEthToken.interface));
var dsEthToken = DSEthToken.at('0xd654bdd32fc99471455e86c2e7f7d7b6437e9179');

We are interested in the balances of each address. Unfortunately we are dealing here with a mapping: mapping( address => uint ) _balances; therefore its not possible to query all addresses which hold tokens. However, we can filter all the Deposit and Transfer events to learn about all possible addresses, which could hold any tokens

var deposits = dsEthToken.Deposit({},{fromBlock: 0, toBlock: blockHeight});
var transfears = dsEthToken.Transfer({},{fromBlock: 0, toBlock: blockHeight});
var getAllEvents = async.parallel.bind(async, [
deposits.get.bind(deposits),
transfears.get.bind(transfears)
]);

After we retrieve those events, we have to filter them for addresses, which could possibly hold ether: In case of a Deposit, the sender(who) could have ether In case of a Transfer, the receiver(to) could have ether

var filterDeposits = function (event) {
return event.args.who;
}
var filterTransfear = function (event) {
return event.args.to;
}

Apply the filter and concatenate the addresses to one array also we are just interested in unique addresses

var filterAddresses = function (res, cb) {
let deposits = res[0];
let transfears = res[1];
let addresses =
deposits.map(filterDeposits)
.concat(transfears.map(filterTransfear))
cb(null, _.uniq(addresses));
}

Now we have just to lookup and output the balances of each address.

var getAllBalances = (addresses, cb) => {
async.parallel(
addresses.map(address => dsEthToken.balanceOf.bind(dsEthToken, address, blockHeight)),
(err, balances) => {cb(err, addresses, balances)})
};

Generate a balances object, which is a mapping (address => balance) and save it as dsEthToken.json

var saveBalances = function (addresses, balances, cb) {
let totalSum = new BigNumber(0);
let savedBalances = {};
console.log('\nResults for DSEthToken:');
balances.forEach((balance, index) => {
totalSum = totalSum.plus(balance);
savedBalances[addresses[index]] = balance.toString(10);
console.log(addresses[index], balance.toString(10) );
});
fs.writeFileSync('dsEthToken.json', JSON.stringify(savedBalances, false, 2));
console.log("Total Sum:", web3.fromWei(totalSum,'ether').toString(10)+"eth");
console.log("balances saved to ./dsEthToken.json");
cb(null, savedBalances);
}

Now we created all our tasks to to retrieve all important information for dsEthToken.

var getDsEthTokenBalances = async.waterfall.bind(this, [
getAllEvents,
filterAddresses,
getAllBalances,
saveBalances
]);

SimpleMarket

Next we will rescue the funds from Maker-OTC, in particular all active orders from SimpleMarket@0xf51bc4633f5924465c8c6317169faf3e4312e82f

var makerotc = require('./maker-otc.json');
var SimpleMarket = web3.eth.contract(JSON.parse(makerotc.SimpleMarket.interface));
var simpleMarket = SimpleMarket.at('0xf51bc4633f5924465c8c6317169faf3e4312e82f');

First we need to know how many orders there are:

var getOrderNumber = simpleMarket.last_offer_id.bind(simpleMarket);

With that info we can get all orders with.

var getOffer = simpleMarket.offers.bind(simpleMarket);

We can get all offers provided we know how many there are.

var getAllOffers = (number, cb) => async.mapSeries.bind(async, _.range(number), getOffer, cb)()

Also we are just interested in active orders and in particular in who sells how much of what.

var filterOffers = (offers, cb) => {

Get only active offers

 let interestingOffers = offers.filter(offer => offer[5]);

and return interesting properties.

 let interestingProperties = interestingOffers.map(offer => ({
owner: offer[4],
token: web3.toAscii(offer[1]).replace(/\u0000/g,''),
ammount: offer[0]
}));
cb(null, interestingProperties);
}

After we got all the interesting stuff, we can sum over each user and toke to get the total offered amount.

var constructInterestingObject = (offers, cb) => {
var balances = {}; // mapping (address => token => balance)
offers.forEach(offer => {

Ensure we are aware of the owner.

 if (!(offer.owner in balances)) balances[offer.owner] = {};

In case we are (owner => token) aware => we add the token to the known balance in case we are not token aware => we simply add it

 if (offer.token in balances[offer.owner]) {
balances[offer.owner][offer.token] =
balances[offer.owner][offer.token].plus(offer.ammount);
} else {
balances[offer.owner][offer.token] =
offer.ammount;
}
});

After this we also format the balance to decimals and save it as simpleMarket.json

 console.log('\nResults for SimpleMarket:');
_.each(balances, (tokens, owner) => {
_.each(tokens, (balance, token) => {
balances[owner][token] = balance.toString(10);
console.log(owner, token, balance.toString(10));
});
});
fs.writeFileSync('simpleMarket.json', JSON.stringify(balances, false, 2));
cb(null, balances);
}

Now we combine all our tasks to retrieve the balances for SimpleMarket

var getSimpleMarketBalances = async.waterfall.bind(this, [
getOrderNumber,
getAllOffers,
filterOffers,
constructInterestingObject
])

After this we generate a human readable document with all relevant information:

var genDoc = function (err, docs) {
let dsEthToken = docs[0];
let simpleMarket = docs[1];
var readmeTemplate = fs.readFileSync('README.md.tmp', {encoding: 'utf8'});
var indexMd = fs.readFileSync('index.md', {encoding: 'utf8'});

Generate dsEthToken table. Generate simpleMarket table.

 var dsEthTokenTable = `| Address | Ammount |\n| ------------- | ------------- |\n`
+ _.map(dsEthToken, (balance, address) => `| ${address} | ${balance} |`).join('\n');
var simpleMarketTable = `| Address | Token | Ammount |\n| ------------- | ------------- | ------------- |\n`
+ _.flatten(_.map(simpleMarket, (tokens, address) =>
_.map(tokens, (balance, token) =>
`| ${address} | ${token} | ${balance} |`))
).join('\n');
var scope = {
how: indexMd,
dsEthToken: dsEthTokenTable,
simpleMarket: simpleMarketTable
};

Generate and save the readme file.

 var template = _.template(readmeTemplate);
var readme = template(scope);
fs.writeFileSync('README.md', readme);
}

Run the tasks.

async.parallel([
getDsEthTokenBalances,
getSimpleMarketBalances
], genDoc);
console.log('running the tasks, this may take several minutes...');

About

No description, website, or topics provided.

Resources

Stars

3 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages