Bitcoin/Altcoin Stratum Pool Mass Duplicate Shares

2016-04-05T00:00:00
ID PACKETSTORM:136556
Type packetstorm
Reporter Packet Storm
Modified 2016-04-05T00:00:00

Description

                                        
                                            `## Bitcoin/Altcoin Stratum Pool Mass Duplicate Shares Exploit ##  
  
This particular vulnerability makes it possible to force a Stratum Mining  
Pool to accept "invalid" shares by the thousands for each mining pool  
round. It is possible to make pure money from this vulnerability. The  
exploit is real but affects only a fraction of Stratum Mining Pools. Let's  
dig into the technical side of this vulnerability.  
  
##### What is stratum mining #####  
  
Most of the known mining pools allow to use the so called stratum mining  
pool protocol. The bitcoin and altcoin miner is configured to use the host  
address and port of the stratum miner protocol server.  
  
For example the eligius (http://eligius.st) mining pool offers a stratum  
connection for mining. This mining pool is *not* affected by this  
vulnerability.  
  
Once connected to the stratum server the miner will "do work" and solve a  
mathematical, crypto task. Once it has solved one of this tasks it will  
*submit* a so called *share* to the stratum server. The more shares the  
miners generate the more they are rewarded after a successful mining round  
has completed. The actual reward given to the miner much depends on the  
style of reward system used by the mining pool.  
  
Miners submit shares using the method "mining.submit" when operating with  
stratum. Client submissions contain:  
  
1. Worker name  
2. Job ID  
3. ExtraNonce 2  
4. nTime  
5. Nonce  
  
The server will respond with a successful accepted share response or will  
reject the share submit request.  
  
Share submits can be sent at any time to the stratum server. The stratum  
server will accept only valid shares and in the case of this particular  
vulnerability stratum will accept *one* valid initial share and *thousands*  
of shares that follow the initial valid share but are "invalid" because  
they do not solve the mathematical task in any way. The vulnerable mining  
pool will accept the shares as pure payment of coins if left unnoticed.  
  
##### node stratum pool #####  
I will show you one mining pool written in javascript and making use of  
node.js to illustrate the bug. Blow is a screenshot of the vulnerable  
source code, can you spot the bug?  
  
  
===== Listing Number 1. ======  
https://github.com/zone117x/node-stratum-pool/blob/02e78da1ab53a2409bbb8721f9771346c373482b/lib/jobManager.js  
  
this.processShare = function(jobId, previousDifficulty, difficulty,  
extraNonce1, extraNonce2, nTime, nonce, ipAddress, port, workerName){  
var shareError = function(error){  
_this.emit('share', {  
job: jobId,  
ip: ipAddress,  
worker: workerName,  
difficulty: difficulty,  
error: error[1]  
});  
return {error: error, result: null};  
};  
  
var submitTime = Date.now() / 1000 | 0;  
  
if (extraNonce2.length / 2 !== _this.extraNonce2Size)  
return shareError([20, 'incorrect size of extranonce2']);  
  
var job = this.validJobs[jobId];  
  
if (typeof job === 'undefined' || job.jobId != jobId ) {  
return shareError([21, 'job not found']);  
}  
  
if (nTime.length !== 8) {  
return shareError([20, 'incorrect size of ntime']);  
}  
  
var nTimeInt = parseInt(nTime, 16);  
if (nTimeInt < job.rpcData.curtime || nTimeInt > submitTime + 7200)  
{  
return shareError([20, 'ntime out of range']);  
}  
  
if (nonce.length !== 8) {  
return shareError([20, 'incorrect size of nonce']);  
}  
  
if (!job.registerSubmit(extraNonce1, extraNonce2, nTime, nonce)) {  
return shareError([22, 'duplicate share']);  
}  
  
  
===== Listing Number 1. ======  
https://github.com/zone117x/node-stratum-pool/blob/02e78da1ab53a2409bbb8721f9771346c373482b/lib/blockTemplate.js  
  
this.registerSubmit = function(extraNonce1, extraNonce2, nTime, nonce){  
var submission = extraNonce1 + extraNonce2 + nTime + nonce;  
if (submits.indexOf(submission) === -1){  
submits.push(submission);  
return true;  
}  
return false;  
};  
  
At listing number 1. you can see the function that processes a submitted  
share. It will check for a valid shape of the mining.submit parameters. And  
finally call job.registerSubmit(...) at line 211 with this parameters to  
check if it handles a duplicate share. It *should* discard a duplicate  
share with a shareError and return from this javascript function. When we  
look into the registerSubmit function we see the lines:  
  
*115.* var submission = extraNonce1 + extraNonce2 + nTime + nonce;   
*116.* if (submits.indexOf(submission) === -1){   
*117.* submits.push(submission);   
*118.* return true; <----- share is accepted   
*119.* }   
*120.* return false; <----- share isn't handled, duplicate  
share.  
  
So how can you submit the duplicate shares? It is rather easy. extraNonce1,  
extraNonce2, Nonce, nTime are HEX values. And everybody knows that HEX  
values can contain ASCII characters.  
  
Let's take an example of extraNonce1 being 0xDEADBEEF. What will  
registerSubmit function do with the share if we submit 0xdEADBEEF and then  
0xdeADBEEF and then 0xdeaDBEEF and so on and so on. Well: the program will  
blindly accept the shares! This is because the registerSubmit function is  
case insensitive and the share is still valid by arithmetic.  
  
  
Best wishes & regards,  
Administrator of Websecurity web site  
http://exploits4coins.com/landing$blog  
  
  
  
`