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