【雑記】stratumにおけるshareの重複承認への対策

移行直後ハッシュの割にblockが見つけられていないユーザーが存在することが話題となりましたがこういうことだったとは・・・ 移行当初からハッシュレートの割にblock発見量が少ないユーザーが存在することから何か不正をしているのでは?と噂になっていましたが、このたびもなとれ運営のびりある氏の指摘もあり、採掘サーバであるstratumにshareの重複送信によるハッシュ水増しが可能な脆弱性があることが明らかとなりました。

 

 

今回の問題となっているものは、node.jsにより実装されているnode-stratum-pool(node-open-mining-portalがstratumとして利用しているソフト)とPythonにて実装されているstratum-miningで、実際には過去に同じshareを送信済みであったとしても、条件を満たした場合に同じshareを重複してカウントし実際よりハッシュレートを水増しできるという脆弱性です。

なおこの脆弱性自体は、今年の5月上旬にCrypto-Expert氏管理のstratum-mining側で修正が実施され、その後5月下旬にNOMPのgit projectでも指摘が行われていたようですが、こちらは実態のnode-stratum-poolにて修正が行われていないため現在も残っています。(ゆえにstratum-miningで該当のプロジェクトから5月中旬以降にcloneした場合は不要です。)

解決法を以下にまとめておきますので、プール運営に携わっている方などは参考にどうぞ。

stratum-mining利用時

Crypto-Expert氏管理のstratum-miningの最新版への入れ替えで対策ができます。(こちらへの入れ替え時はこの後のstratum-mining特有の問題も参照のこと

$ git clone https://github.com/Crypto-Expert/stratum-mining.git

またはstratum-miningのディレクトリ中のlib/templateregistry.pyに太字の文字列を以下のように追記する。

        # Check if extranonce2 looks correctly. extranonce2 is in hex form...
        if len(extranonce2) != self.extranonce2_size * 2:
            raise SubmitException("Incorrect size of extranonce2. Expected %d chars" % (self.extranonce2_size*2))
        
        # normalize the case to prevent duplication of valid shares by the client
	ntime = ntime.lower()
	nonce = nonce.lower()
	extranonce2 = extranonce2.lower()
        # Check for job
        job = self.get_job(job_id, worker_name, ip)
        if job == None:
            raise SubmitException("Job '%s' not found" % job_id)
                
        # Check if ntime looks correct
        if len(ntime) != 8:
            raise SubmitException("Incorrect size of ntime. Expected 8 chars")

        if not job.check_ntime(int(ntime, 16)):

詳しくは以下を参照のこと。

https://github.com/Crypto-Expert/stratum-mining/commit/d5b4ffddf60117c177945e0ea544288e9a9b2db9

NOMP(node-open-mining-portal),node-stratum-poo利用時

実体となるnode-stratum-poolのlib/stratum.jsに対し、以下の太字を追記する。 ※おそらくこれであっていると思われますが、間違っている場合はご指摘いただけると助かります

 

            // If the authorizer wants us to close the socket lets do it.
            if (result.disconnect === true) {
                options.socket.destroy();
            }
        });
    }

    function handleSubmit(message){
        nTime : message.params[3].toLowerCase(),
        nonce : message.params[4].toLowerCase()
        if (!_this.authorized){
            sendJson({
                id    : message.id,
                result: null,
                error : [24, "unauthorized worker", null]
            });
            considerBan(false);
            return;
        }
        if (!_this.extraNonce1){
            sendJson({
                id    : message.id,
                result: null,
                error : [25, "not subscribed", null]
            });

詳しくは以下を参照のこと。

https://github.com/zone117x/node-open-mining-portal/issues/430

 

なお、この脆弱性は現時点で他のstratumにも存在するかは現時点で不明です。(とはいえだいたいの方はどちらかを使っているので問題はないと思われますが・・・)

 

現在ASIC Poolを始めとした国内プールでは今回の問題への対策が行われており、VIP Poolを除いた他のプールは対応が完了。 残っているVIP Poolも日曜日には対応を完了させる予定とのことです。 VIP Poolも含め対応が完了しました。

しかし、厳密に言うとVIP Poolで実際に悪用された脆弱性は別物のようです。

 

stratum-mining特有の問題

このstratum-mining特有の問題は、難易度設定まわりでアルゴリズムごとに適切な目標難易度が設定されないというものです。

この問題が存在するのはCrypto-Expert氏が管理する「stratum-mining」で現在確認が取れています。  他の方が管理するstratum-mining、たとえばahmedbodi氏が管理する「stratum-mining」などではこの問題は発生しません。 ただし、他の方が管理しているstratum-miningでは最初に挙げた脆弱性は修正されていないものも存在するので忘れずに対策を実施してください。(詳しい対象は後ほど記述します)

 

今回stratum-mining特有の脆弱性はCrypto-Expert氏が管理する「stratum-mining」における2013年12月16日のcommitに端を発する問題です。 該当のcommitは以下のリンクより。

https://github.com/Crypto-Expert/stratum-mining/commit/24e71e40e7b4141fadb30c33e6733b55403e0abe

抜粋すると以下の部分が問題の個所(変更点)です。

    def diff_to_target(self, difficulty):
        '''Converts difficulty to target'''
	if settings.COINDAEMON_ALGO == 'scrypt' or 'scrypt-jane':
	       	diff1 = 0x0000ffff00000000000000000000000000000000000000000000000000000000
        elif settings.COINDAEMON_ALGO == 'quark':
                diff1 = 0x000000ffff000000000000000000000000000000000000000000000000000000
        else:   diff1 = 0x00000000ffff0000000000000000000000000000000000000000000000000000
	return diff1 / difficulty

マイニングアルゴのscrypt-janeに対応するためにコードが追加されたのがこのcommitです。

一見するとよさそうなコードに見えます。しかしこの部分、抜き出して実行してみるとおかしなことになります。

以下に部分的に抜き出して実行できるようにしたコードを置いておきます。 期待としてはquarkの処理が実行されてほしいわけですが・・・


見ての通り、quarkを選んでいるのにもかかわらずscryptとしての処理がなされてしまいました。

このコードの問題点を修正すると以下になります。


元のコードはor演算の右側が常に1となるため、一番上のif分の処理が常に実行されてしまう、つまりは論理演算で端折ってはいけない”何が何と等しいか?”を適切に記述しなかったために起きている問題なわけです。

 

修正方法は簡単で、「lib/template_registry.py」の該当部分を以下の太字のように修正するだけでこの問題は解決します。

    def diff_to_target(self, difficulty):
        '''Converts difficulty to target'''
	if settings.COINDAEMON_ALGO == 'scrypt' or settings.COINDAEMON_ALGO =='scrypt-jane':
	       	diff1 = 0x0000ffff00000000000000000000000000000000000000000000000000000000
        elif settings.COINDAEMON_ALGO == 'quark':
                diff1 = 0x000000ffff000000000000000000000000000000000000000000000000000000
        else:   diff1 = 0x00000000ffff0000000000000000000000000000000000000000000000000000
	return diff1 / difficulty

なおこの問題の対象となるstratum-miningは、Crypto-Expert氏のstratum-miningとこのプロジェクトから2013年12月16日以降にforkしたプロジェクトです。 metalicjames氏のstratum-mining-Lyra2REも対象です。 ただし、mrtexaznl氏管理のstratum-miningのようにfork後に対応アルゴ追加と同時に修正しているものも存在するため、それ以降だからといって対象とは限らないのでご注意を。(逆に言うと対象以外でもこの問題を抱えている可能性がありますが・・・)

そして何より不思議なのは、指摘がなされているにも関わらずいまだに修正されていない点だったりしますが、「現状NOMP系に大部分が移行してる」というあたりも影響しているのかもしれません・・・

投稿者プロフィール

monaf
mona digestの管理人でもあります。 こちらは向こうでは外れてしまうような内容を中心にお送りしてまいります。

monacoin:MMditkELuURZgDPduLDLGYArA15G7nWFo3
kumacoin:KHtxC7CdYUUfXLEEprxoN8re58ckhNbSwb
ringo:RVQNKVMRcJ8dCH687zQo3nDUN7JXgoRdid
bitzeny:ZboAKf49TpBg5ef9vSXxNbajmyyjZNNCat

About Author

monaf
mona digestの管理人でもあります。 こちらは向こうでは外れてしまうような内容を中心にお送りしてまいります。 monacoin:MMditkELuURZgDPduLDLGYArA15G7nWFo3 kumacoin:KHtxC7CdYUUfXLEEprxoN8re58ckhNbSwb ringo:RVQNKVMRcJ8dCH687zQo3nDUN7JXgoRdid bitzeny:ZboAKf49TpBg5ef9vSXxNbajmyyjZNNCat

Leave a Comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です