I also decided to publish it in this thread (an not in supernode source repository) because it's interesting how vulnerabilities are hidden in the code.
Supernode implements a signature cache, like Satoshi client. The data structure to hold the cache is
private Set
To check if a signature is on the cache, the code does:
StringBuffer c = new StringBuffer ();
c.append (new String (Hex.encode (sig), "US-ASCII"));
c.append (new String (Hex.encode (pubkey), "US-ASCII"));
c.append (new String (Hex.encode (hash), "US-ASCII"));
cacheKey = c.toString ();
if ( validSignatureCache.contains (cacheKey) )
{
return true;
}
The problem is that the fields (sig,pubkey,hash) are concatenated without a separator, so it's possible to "move" bytes from sig to pubkey an viceversa.
POSSIBLE ATTACK
1) The attacker creates one non-standard transactions tx1 with one output 0 whose scriptPubKey is: OP_CHECKSIG
(Tx1 is sent directly to a miner, and included in a block)
2) The attacker then creates a correct transaction TxA that spends Tx1 whose scriptSig is:
This transaction must be very large and not include any fees, so it's not included in a block by miners.
When bitsofproof supernode receives TxA by a peer it validates the signature (which is correct) and it adds the (sig|pubkey|hash) to the cache.
3) The attacker creates a transaction TxB similar to TxA in every field except for the scriptSig, which becomes:
Where
and
4) The attacker mines a block including TxB.
5) The block is sent to the supernode. Because (sig|pubkey|hash) is in the signature cache of the application, this node accepts the block as valid.
But no other node accepts this block, because TxB has clearly an invalid signature
Maybe there is an easy way to attack using this vulnerability.
POSSIBLE SOLUTION
Add some separators:
c.append (new String (Hex.encode (sig), "US-ASCII"));
c.append ("|");
c.append (new String (Hex.encode (pubkey), "US-ASCII"));
c.append ("|");
c.append (new String (Hex.encode (hash), "US-ASCII"));
Best regards,
Sergio Lerner