## 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

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. ======

    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. ======

    this.registerSubmit = function(extraNonce1, extraNonce2, nTime, nonce){
        var submission = extraNonce1 + extraNonce2 + nTime + nonce;
        if (submits.indexOf(submission) === -1){
            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

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

# siph0n [2016-04-06]