Breaking Ethereum Nodes with Teatime

Photo by Sergey Norkov on Unsplash

Security in the Ethereum ecosystem is multi-faceted. From smart contract code to the Ethereum base protocol: quality assurance, audits, and rigorous testing are on their way to becoming the norm. With the number of security-focused companies, the number of eyes looking at Ethereum’s code is increasing by the week. This begs the question: Are there vulnerabilities further down the hood?

Attacks on the P2P layer and the node software itself are juicy targets for adversaries as they are a crucial point of infrastructure in the overall system. Were these attacks to succeed, efforts to secure the Ethereum protocol and smart contracts could be in vain, and potentially all funds would be put at risk. For example, think along the lines of a DoS vulnerability that could significantly reduce the number of nodes in the Ethereum P2P network. As a consequence of this vulnerability, a 51% attack might become much more feasible for an attacker, especially one with access to on-demand cloud resources. Another potential attack vector could target the accounts registered on node software, where private keys might be at risk due to insecure passphrases, or authentication bypasses.

Auditing decentralized infrastructure is hard. The exact number of users is hard to pinpoint when the underlying protocol is typically permissionless. Code complexity of node software is high, interfaces are often heterogeneous across implementations, and some projects lack documentation and proper business logic isolation. Security tools are either not used, or use a custom implementation provided by the core developers themselves, such as Geth’s fuzz tests. Even if testing and security tooling is assumed to be flawless, there is still a lot of room for misconfiguration of the software itself and the machine the node is running on. Insecure Docker containers, outdated operating systems, vulnerable software running alongside the node software - the attack surface becomes vast when looking beyond the high-level concepts of Ethereum.

I have thought and worried about this quite a bit, and believe that there is an inherent need for a framework to check arbitrary infrastructure attack vectors, specifically in Blockchain deployment scenarios. This is not an easy feat, and I have a day job, so I decided to come up with some functional requirements and reduce the scope for an initial version. The framework should be:

  • Extensible: People who are smarter than me should be able to easily implement their scan ideas without having to spend a day to get familiar with the code.
  • Reasonable: There should be reasonable abstractions to hide unnecessary complexity and focus on security work at hand
  • Understandable: It should be easy to use, and good documentation can get users started right away
  • Flexible: The framework needs to be able to integrate seamlessly with other solutions such as message queues, databases, and ultimately frontends

The result of these requirements and a week of hacking is Teatime! The Teatime library aims to be the foundation of an attack framework that can be extended to fit the use cases of scanning decentralized infrastructure. For now, Teatime focuses on Ethereum 1.0 and JSON-RPC interfaces, however, I plan to extend it in order to cover additional attack vectors. Let’s see what a scan looks like:

from teatime.plugins.context import NodeType
from teatime.plugins.eth1 import (
    GethDatadir,
    GethNodeInfo,
    NodeVersion,
    OpenAccounts,
    PeerlistLeak,
)
from teatime.reporting import Issue
from teatime.scanner import Scanner

TARGET_IP = "<node-ip-here>"
TARGET_PORT = 8545
INFURA_URL = "https://mainnet.infura.io/v3/<your-key-here>"
GETH_REPO = "https://api.github.com/repos/ethereum/go-ethereum/releases/latest"


def get_scanner():
    return Scanner(
        ip=TARGET_IP,
        port=TARGET_PORT,
        node_type=NodeType.GETH,
        plugins=[
            GethDatadir(),
            NodeVersion(geth_url=GETH_REPO),
            GethNodeInfo(),
            OpenAccounts(INFURA_URL),
            PeerlistLeak(),
        ],
    )


if __name__ == "__main__":
    scanner = get_scanner()
    report = scanner.run()
    issue: Issue
    for issue in report.issues:
        print(issue.title, f"({issue.severity})")
        print("-" * (len(issue.title + str(issue.severity)) + 3))
        print(issue.description)
        print("Raw response:", str(issue.raw_data)[:30] + "...", "\n")

Here we check for five weaknesses:

  • a public Geth datadir, which potentially leaks path information of the deployment
  • a stale Geth version (checked against the official Geth repo’s releases
  • leaking Geth node information with a RPC call in the admin namespace
  • whether accounts are registered on the node
  • whether the node’s peer list is available publicly

Executing the script will result in the following output (apart from some informational log messages):

Admin datadir access (LOW)
--------------------------
The datadir directory path can be fetched using the admin_datadir RPC call.
Raw response: /root/.ethereum/devchain...

NodeVersion (NONE)
------------------
The node surfaces it's version information
Raw response: Geth/v1.9.9-stable-85eeb821/li...

Node version out of date (HIGH)
-------------------------------
1.9.9 != 1.9.21
Raw response: Geth/v1.9.9-stable-85eeb821/li...

Admin Node Info Leaks (LOW)
---------------------------
Admin-only information can be fetched using the admin_nodeInfo RPC call.
Raw response: {'id': '94b82260db33e63d1b7425...

Found account (MEDIUM)
----------------------
Account: 0x007ccffb7916f37f7aeef05e8096... Balance: 0
Raw response: 0x007ccffb7916f37f7aeef05e8096...

Admin Peerlist Access (MEDIUM)
------------------------------
Admin-only information about the peer list can be fetched using the admin_peers RPC call.
Raw response: [{'enode': 'enode://80e3287dde...

Of course, these are not the only scans available. From peerlist manipulation attempts, trying to change the coinbase address for miner payouts, to simpler information leaks, admin interface misconfigurations, and informational scans, a total of 34 RPC-focused scans are already available. In future work, I would love to extend teatime to cover a broader range of technologies such as Ethereum 2.0, IPFS, Filecoin, as well as increase the variety of scans for Ethereum 1.0, going beyond RPC-based vectors.

Check out the project on Github! If you have feedback, feel free to hit me up on Twitter @lethalspoons.

Now go out and scan your nodes. :)


Thinking about smart contract security? We can provide training, ongoing advice, and smart contract auditing. Contact us.

All posts chevronRight icon

`