For many, the new year inspires a renewed sense of excitement about the challenges and opportunities ahead, both personally and societally. I can’t help but wonder if Satoshi Nakamoto felt a similar sense of excitement when mining the first Bitcoin block on January 3, 2009, heralding the dawn of the cryptocurrency era. In the 16 years since Satoshi planted that first Bitcoin seed, a vast ecosystem of cryptocurrency and blockchain technologies has sprung up, rivaling the $669 billion notional trading volume of the US stock market with up to $456 billion in daily transactions. As impressive as the adoption of cryptocurrency has been, we’re still in its early days, and novel use cases for blockchain technologies are being explored every day.

With so much money moving through today’s cryptocurrency markets, any exploitation of vulnerabilities can result in devastating losses—not only for individual users but also for the networks, exchanges, and companies facilitating these transactions. Despite the industry’s substantial investments in cybersecurity, news headlines continue to announce massive cryptocurrency hacks at an alarmingly frequent rate. For hackers, such tangible risks and high stakes translate into lucrative bug bounty opportunities. For instance, consider the below screenshot showcasing public bug bounty programs related to cryptocurrency and blockchain security on the Bugcrowd platform. Some are offering rewards as high as $100,000!

 

Broken encryption schemes

 

Understanding the risk

Encryption is one of the foundational security mechanisms in blockchain technology. It protects data integrity, secures communications, and ensures the authenticity of transactions. However, when blockchain developers rely on weak cryptographic algorithms or insufficient key lengths, they introduce severe vulnerabilities that can be exploited by attackers.

Common issues associated with broken encryption schemes include:

  • Use of weak cryptographic algorithms: Legacy algorithms like MD5, SHA-1, and DES have been proven to be susceptible to brute force attack and collision attacks.
  • Insufficient key lengths: The use of short cryptographic keys subject otherwise secure algorithms to compromises via brute-force attacks. Generally speaking, such weaknesses are an expected result of computational advances over time and do not necessarily implicate any underlying weakness in the cryptographic algorithm itself. For example, it used to be commonplace to use 2048-bit Rivest RSA keys, but with the advancement of application-specific integrated circuit (ASIC) hardware, best practices now call for 4096-bit RSA keys.

Real-world example: SHA-1 hash collision attack

One of the most well-documented examples of the dangers of using weak cryptographic algorithms is the SHA-1 hash collision attack, which occurs when two different inputs produce the same hash value. This vulnerability was proven by researchers from Google and CWI Amsterdam in 2017, where they successfully generated two different files that produced the same SHA-1 hash. Cryptographers had actually been raising the alarm for a few years that SHA-1 was showing signs of weakening against collision attacks. Nevertheless, SHA-1 was widely used for digital signatures, cryptographic hashing, and integrity checks within blockchain implementations. As it relates to blockchain technologies, the SHA-1 hash collision vulnerability could theoretically allow an attacker to specially craft a transaction with which the digital signature collides with another transaction, thereby allowing the attacker to manipulate transactions or impersonate other users.

 

Insufficient cryptographic validation

 

Understanding the risk

Cryptographic validation is a fundamental security measure in blockchain systems, ensuring that transactions, digital signatures, and cryptographic proofs remain tamper-proof and verifiable. However, when cryptographic validation is insufficient or improperly implemented, attackers can exploit weaknesses to forge transactions, bypass authentication mechanisms, or manipulate consensus mechanisms, among other attacks.

Common issues associated with insufficient cryptographic validation include:

  • Improper signature verification, which allows unauthorized transactions due to flawed verification logic.
  • Weak multi-signature implementations, which fail to properly enforce multiparty authorization.
  • Lack of message authentication, which enables data tampering in network communications.
  • Bypassing integrity checks, which allows malicious data to pass as legitimate due to weak validation methods.
  • Incorrect cryptographic proof verification, which enables double-spending or fraudulent claims in zero-knowledge proof (ZKP) and smart contract applications.

Real-world example: The Binance Bridge hack (2022)

One of the most significant cryptographic validation failures in recent blockchain history was the Binance Bridge exploit of October 2022, which resulted in the loss of $570 million worth of Binance Coin (BNB) tokens due to improper cryptographic validation. The Binance Bridge is a cross-chain protocol that enables the movement of assets between different blockchains. This vulnerability stemmed from a failure of the Binance Bridge protocol to properly verify the Merkle proof of transactions, which effectively allowed attackers to mint unauthorized wrapped tokens.

There’s quite a bit to unpack with this example, and we could fill an entire separate article on the nuances of just this single hack. However, we need not dive deep into the specifics of this example to glean some important takeaways that we can integrate into our own security research methodologies and workflows. For starters, this example demonstrates that impactful bugs can be found by methodically testing cryptographic validation routines whenever we encounter them. To draw a parallel to traditional web application hacking, think of such attacks as the blockchain equivalent to tampering with the session token for a web application login.

This example also highlights the fact that blockchain technologies are constantly evolving and do so at an astounding pace, which presents many opportunities for hackers. Whether it’s ZKPs, Merkel trees, or cross-chain protocols, you’re likely to encounter many new cryptographic technologies when hacking blockchains. Some of the reference materials for these technologies are dense, but I would encourage you to take the time to understand them, as doing so will help you build a unique hacking skill set. After all, having skills in niche/emerging technologies translates into less competition surrounding a given target, which in turn translates into greater potential for finding high-impact, non-duplicate vulnerabilities.

 

Side-channel attacks

 

Understanding the risk

As we discussed in the first article of this series, side-channel attacks exploit unintended information leakage from hardware or software implementations rather than target cryptographic algorithms directly. Blockchain technologies present some very interesting opportunities for side-channel attacks, such as hardware cryptocurrency wallets, blockchain nodes, and blockchain integrations in small footprint hardware components. At a high level, we can use side-channel attacks to extract private keys, manipulate transactions, or undermine privacy mechanisms. Most side-channel attacks targeting blockchain technologies will resemble similar attacks against other cryptographic implementations, with a few notable exceptions:

  • Electromagnetic radiation: Radio frequency (RF) emissions can be used to extract private keys from hardware wallets.
  • Timing analysis: Many blockchain technologies make use of wrapped signatures, tokens, etc., which often operate on a combination of known and unknown inputs. We can combine such partial knowledge of inputs with measurements of execution times to recover secret keys. Common targets for such attacks include blockchain protocols and service providers (e.g., cross-chain bridges, cryptocurrency exchanges, and mobile apps).

Real-world example: Trezor One power analysis attack

One of the most intriguing examples of a side-channel attack in the blockchain sphere occurred in 2019, when security researchers demonstrated that a power analysis attack could be used to determine the PIN for unlocking a Trezor hardware cryptocurrency wallet. The Ledger team has provided a detailed write-up on the attack, which can serve as a great start for anyone interested in setting up the environment necessary for power analysis attacks. Another extremely valuable tool for power analysis attacks is ChipWhisperer. Such attacks can have significant impacts because hardware wallets are marketed to be one of the most secure ways to achieve self-custody of cryptocurrencies and typically implement controls to protect against the theft of funds in the event the device is lost or stolen.

 

Faulty randomness in smart contracts

 

Understanding the risk

Randomness (i.e., entropy) is a critical component in blockchain applications, particularly for lotteries, decentralized apps (dApps), airdrops, and randomized reward distributions. However, generating secure and unpredictable random numbers is inherently challenging, and potentially even more so in a deterministic blockchain environment. Insufficient randomness can manifest in a variety of ways across different blockchain components—and we’re going to take a deep dive through a case study below—but smart contracts, in particular, present some unique attack vectors.

When smart contracts rely on insecure or predictable randomness, we can potentially manipulate the outcomes of cryptographic operations to our advantage, leading to significant financial and systemic risks. This is because randomness is used in smart contracts for everything from picking winners in gambling dApps to generating hashes in privacy-preserving protocols and selecting leaders in proof-of-stake consensus mechanisms. There have been many examples over the years of developers using insecure sources of randomness in the context of smart contract operations, which makes this an especially promising attack vector.

Common sources of faulty randomness in smart contracts include:

  • Previous block traits: While some characteristics of previous blocks, such as block hashes, timestamps, or difficulty, may appear to be random at first glance, they actually have quite low entropy when evaluated mathematically. Just as importantly, such characteristics of a block may be subject to manipulation by miners, who could tamper with inputs, making outcomes more predictable.
  • On-chain pseudorandom number generators (PRNGs): Using Solidity’s keccak256() or similar hashing functions improperly has been shown to lead to predictable random values.
  • Off-chain entropy sources: Smart contracts sometimes insecurely implement external randomness sources or rely on untrustworthy/predictable sources, such as values collected from a centralized API.

Real-world example: The Moonbirds NFT randomization attack (2022)

A notable example of how faulty randomness in smart contracts can be exploited was the 2022 Moonbirds non-fungible token (NFT) drop, where attackers manipulated the random minting process to secure rare NFTs. Moonbirds is a high-profile NFT project that was found to use on-chain randomness when determining the traits of minted NFTs. Specifically, the NFT contract relied on the block hashes of previous blocks as an entropy source when selecting the recipient of newly minted NFTs. By manipulating the inputs and timing of transactions, attackers were able to skew the outcomes of the randomized minting recipient selection algorithm in their favor, ultimately minting disproportionately rare and high-value NFTs worth approximately $1.5 million.

 

Replay attacks

 

Understanding the risk

Replay attacks are an age-old vulnerability, compromising everything from network protocols to web applications over the years. In many historical cases, it was necessary to first establish some kind of person-in-the-middle position before a replay attack could be carried out. But the public nature of blockchains presents some interesting and unique attack vectors for today’s hackers. In the blockchain context, replay attacks occur when a valid transaction from one blockchain network is captured and maliciously rebroadcasted on another network, allowing an attacker to duplicate transactions or perform unauthorized operations. Such attacks are particularly relevant when a blockchain has a hard fork or integrates multichain transactions and/or interoperability protocols. Blockchain-based replay attacks can be used to achieve any of the following:

  • Unauthorized fund transfers—Duplicate a transaction to spend funds on another chain without a sender’s consent.
  • Contract exploitation—Smart contracts that rely on transaction signatures without proper chain-specific validation can be manipulated without invalidating the signature.
  • Denial of service—Continuous replaying of transactions can flood a blockchain network, disrupting normal operations, potentially increasing network fees, and wasting mining resources (depending on the consensus mechanism).

For hackers, a key to finding replay attack weaknesses is to identify instances in which no chain-specific metadata is incorporated into transaction signatures. This can be achieved by studying a chain’s transaction structure or by simply attempting to duplicate signed transactions from one chain on a forked chain (or vice versa). While the most common instances of blockchain replay attacks have occurred in the context of hard forks, another likely scenario occurs when a new blockchain project reuses the codebase of a prior project without incorporating chain-specific metadata, such as a chainId.

Real-world example: The Ethereum Classic replay attack (2016)

In 2016, Ethereum underwent a hard fork, which created two separate chains: Ethereum (ETH) and Ethereum Classic (ETC). Following the hard fork, transactions on one chain were valid on the other chain because there was no built-in replay protection. In theory, if a user sent ETH on the new Ethereum chain, an attacker could replay the same transaction on Ethereum Classic (ETC), causing an unintended transfer of ETC as well. Many exchanges implemented manual controls to help prevent the exploitation of the vulnerability, but there were reports that unaware users who didn’t take preventive measures suffered significant financial losses. Ultimately, Ethereum implemented replay protections that incorporate chain-specific metadata into the transaction signature generation/validation process.

 

Cross-chain bridge vulnerabilities

 

Understanding the risk

Cross-chain bridges serve an important role in the context of layer-2 blockchain networks, decentralized finance (DeFi) applications, and multichain smart contracts. However, according to Chainanlysis, cross-chain bridge hacks contributed to the theft of over $2 billion in cryptocurrency, accounting for 69% of total funds stolen in 2022. Essentially, these bridges facilitate the transfer of assets from one blockchain network to another. As hackers, we often look for the places where a handoff occurs between different systems because security gaps tend to manifest at these interfaces. This is doubly so in the context of blockchains because the cryptographic traits of one network are often incompatible with those of other networks, which requires complex (and error-prone) workflows consisting of asset conversion, transaction binding, and a specific order of operations. Below are some common cross-chain bridge vulnerabilities:

  • Weak or compromised validation mechanisms—Attackers can exploit weak signature verification, allowing unauthorized transactions.
  • Flawed smart contracts—Bugs in bridge smart contracts can lead to token loss, double spending, or contract takeovers.
  • Oracle manipulation—Inaccurate price feeds or compromised off-chain oracles can be used to exploit bridge transactions.
  • Private key leaks—Poorly managed multi-signature or key-based bridge mechanisms increase the risk of fund theft.
  • Reentrancy and logic flaws—Bridges that do not properly carry out the transaction execution order can be drained through reentrancy attacks.

Real-world example: Nomad Bridge exploit (2022)

One of the most notable cross-chain bridge exploits occurred in August 2022, when attackers drained over $190 million from the Nomad Bridge. Essentially, a routine network upgrade went horribly wrong when one of Nomad’s proxy contracts marked a zero hash value as a trusted root. This, in turn, allowed the automatic approval of messages, which attackers used to unlock funds. This hack highlights the fact that protocol complexity and decentralized trust models, both of which are widely found in the blockchain ecosystem, present many security challenges—or, for hackers, many opportunities. 

Case study: Bitcoin Android Wallet vulnerability

A widely stated mantra in the cryptocurrency world goes as follows—Not your keys, not your crypto. This fundamental cryptocurrency principle emphasizes the importance of self-custody, which means if one does not personally control the private keys for their crypto wallets, then one does not truly own the cryptocurrency contained therein. A lot of people use mobile app-based cryptocurrency wallets as a way to achieve self-custody without sacrificing the convenience of quick and frictionless trading often associated with cryptocurrency exchanges. This is exactly what users of the Bitcoin Android Wallet had in mind back in 2013, when some users’ Bitcoin wallets were suddenly drained without their consent. As it turns out, a flaw in the Android OS led to predictable random number generation, which in turn led to the insecure generation of the private keys associated with users’ crypto wallets. In total, this vulnerability was used to steal at least 59.32152538 BTC, worth over $6 million today.

While this vulnerability dates back to 2013, it’s just as relevant today as it was back then—and it serves as a great example of how a simple flaw in the implementation of cryptography can have devastating downstream effects. In this section, we take a deep dive into this vulnerability. We look at both the mathematical implications of weak random number generation and ways to find and exploit such vulnerabilities in the bug bounty context. Lastly, we’ll see what generalizations we can glean from this example to incorporate into our hacking methodologies and workflows.

To help illustrate this vulnerability, consider how a post office (PO) box works. A PO box has 1) a publicly known address to which anyone in the world can send a letter and 2) a physical mailbox key, which grants access to any letters received at that address. Naturally, the security of the PO box relies on the fact that only its owner has access to the physical mailbox key—if you lose control of the key, then you lose control of everything inside the mailbox. Now, imagine you decided to place your PO box key in an envelope and mail it to yourself. As that envelope works its way through the mail delivery system, anyone could just open the envelope, remove the key, and….it’s not your PO box anymore—it’s theirs. That’s basically what happened with the Bitcoin Android Wallet vulnerability. In our example, the publicly known address of the PO box represents the crypto wallet public key, and the physical mailbox key represents the crypto wallet private key.

The role of randomness in cryptocurrency wallets

At the heart of every cryptocurrency wallet is a public-private key pair. As you may recall from our introductory article, “Cryptography for hackers Part I,” asymmetric encryption (aka public-key cryptography) employs a pair of keys: a public key for encryption and a private key for decryption. In the context of a cryptocurrency wallet, the public key acts like an address for receiving funds, while the private key is a secret code that grants ownership and control over those funds. The creation of our crypto wallet’s public-private key pair is the first place where we encounter random number generation in the context of cryptocurrency.

Now that we’ve generated our crypto wallet, we’re ready to interact with the Bitcoin network. The body of a Bitcoin transaction object consists of the following essential components: 

  1. The full public key associated with the sender’s crypto wallet
  2. The public key hash (i.e., address) of the recipient’s crypto wallet
  3. Transaction details, such as the amount of Bitcoin being sent.

The sender then uses the private key associated with their wallet to cryptographically sign the transaction with the Elliptic Curve Digital Signature Algorithm (ECDSA). This is the second place where we encounter random number generation, and it’s here that the root of the Bitcoin Android Wallet vulnerability lies.

Mathematical theory of the attack

To fully appreciate this vulnerability, it’s helpful to start with the mathematics underlying the ECDSA. Some of the equations might be intimidating at first glance, but have no fear. Our goal here is just to visualize the overall concepts. We begin with the resulting components of an ECDSA signature, which consists of two (2) parts:

 

  • r (i.e., the “random component”)—The x-coordinate of the elliptic curve point generated by multiplying the random nonce (k) with the curve’s generator point (G).

  • s (i.e., the “signature component”)—The relationship between the private key (d), message hash (z), and r.

When calculating the random component of the ECDSA signature (r), the sender must provide a random nonce (k). It is vitally important that the k-nonce is unpredictable and unique for every transaction. If the k-nonce is ever reused, or if it’s predictable, then the sender’s private key can be recovered from the Bitcoin transaction object on the blockchain. But don’t just take my word for it!

For two different messages (m₁ and m₂) signed with the same private key (d) and nonce (k), the signatures are:

where:

 

d = Sender’s private key.

r = Same value in both signatures (because the same k was used).

z₁ and z₂ = Different hashes of two transaction messages (m₁ and m₂).

s₁ and s₂ = Two different signature components.

n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141

 

What the above linear equations show is that all variables except for k and d are public information (gleaned from the Bitcoin blockchain). With this in mind, all we have to do is solve for k and then we can solve for d, which is the sender’s private key.

Then, we solve for k

​Lastly, we plug k into the original equation for s₁ and solve for d:

 

Practical demonstration

Of course, anyone can throw equations on a screen and do some handwaving, but this doesn’t prove anything. So, let’s put our hypothesis to the test with real data. Below is a Python script that derives a private key from real-world values of r, s₁, and s₂. I’ll show you how we came up with r, s₁, and s₂ next, but for this phase, it’s sufficient just to remember that these values are publicly disclosed on a blockchain for a given transaction. You’ll need Python v3 with the following modules installed: base64, ecdsa, and hashlib.

from hashlib import sha256

import base64

 

# Given signature components from two transactions with reused k-nonce

r = 739782792349518524188608102386183698332784846164637486308790956455323664256

s1 = 661108047169462910392100696086740161908236005166706809601531837701299766634

s2 = 75301993667279997514689204672392137596190504853647616607090793199828946245055

 

# Message hashes corresponding to each signature

z1 = int.from_bytes(sha256(b"Transaction A").digest(), "big")

z2 = int.from_bytes(sha256(b"Transaction B").digest(), "big")

 

# Curve order (secp256k1)

n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141

 

# Recover the nonce k

k = ((z1 - z2) * pow(s1 - s2, -1, n)) % n

 

# Recover the private key (d)

d = ((s1 * k - z1) * pow(r, -1, n)) % n

 

# Convert to base64 with proper byte alignment

byte_length = (d.bit_length() + 7) // 8  # Ensure correct byte size

d_base64 = base64.b64encode(d.to_bytes(byte_length, 'big')).decode()

 

# Print results

print(f"Recovered private key: {hex(d)}")

print(f"Base64 representation: {d_base64}")

As you can see from the above output, we were able to derive the private key of 0x9deaddc1e9656ee81cae8c1d9deaddc1e9656ee81cae8c1d9deaddc1e965. In the next script, I’ll show you how I generated s₁ and s₂ using this private key. For illustration purposes, my private key is simply the integer representation of the hexadecimal decoding of the Base64 string “nerdwellbugcrowdnerdwellbugcrowdnerdwell.” If you want to further prove to yourself that the math works, just substitute your own Base64 string and rerun the first script using the resulting s₁, and s₂ values. Recall from above that r (the “random component”) for a given transaction is disclosed on the blockchain and incorporates the k-nonce into its calculation. For a deep dive into how r and s are encoded in the blockchain transaction, see this article:

 https://medium.com/coinmonks/on-bitcoin-transaction-sizes-97e31bc9d816#17d6.

Lastly, note that in the script below, we use the same k-nonce (and by extension, r) for both calls to calculate_signature_components(), which was the underlying vulnerability in the 2013 Bitcoin Android Wallet hack. 

 

from hashlib import sha256

import base64

 

# Curve order (secp256k1)

n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141

# Private Key

d = int.from_bytes( base64.b64decode( 'nerdwellbugcrowdnerdwellbugcrowdnerdwell' ) )

# k-nonce

k = 295990755076957304699390954000840642031

# r

r = 739782792349518524188608102386183698332784846164637486308790956455323664256

 

# Compute the SHA-256 hash of a message and return as an integer.

def hash_message(message):

    return int.from_bytes(sha256(message.encode()).digest(), 'big')

 

# Compute s values for an ECDSA signature.

def calculate_signature_components(d, k, z, r):

    s = (pow(k, -1, n) * (z + d * r)) % n

    return s

 

# Generate hashes for two messages

z1 = hash_message("Transaction A")

z2 = hash_message("Transaction B")

s1 = calculate_signature_components(d, k, z1, r)

s2 = calculate_signature_components(d, k, z2, r)

 

# Print results

print(f"Computed s1: {int(s1)}")

print(f"Computed s2: {int(s2)}")

 

Conclusion

As this article highlights, blockchain technologies present many lucrative opportunities for hackers. In some cases, it’s just a matter of applying age-old cryptographic attacks to these new use cases. In other cases, new cryptographic algorithms and technologies have been developed to better serve the unique needs of specific blockchain use cases. While some of these hacks can be intimidating at first glance, it’s helpful to just break them down into manageable chunks and work through each chunk one at a time. And remember—the more difficult something seems, the less likely other hackers will take the time to dig into it—which means less competition and more bugs for you and me! Stay tuned for the next article in our series on cryptography for hackers. Happy hacking!