I was going to give exchanges a bit more time to react, but I don't want to sit on this longer than needed.
Link for the report at
https://gist.githubusercontent.com/Earlz/41c5c18113210d3c36f9/raw/4d14022e3c75a6a10c653bd98831fd3bbded79a1/gistfile1.txtTL;DR; Exploit, blockchain is completely ruined and unsalvageable. Devs used exploit to amplify their hashrate and mine all the blocks
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
Exploit report:
Written by Jordan Earls (earlz, earlz.net), June 30th 2015, 9:20pm
Verify this message's signature by going to
https://keybase.io/earlzKNOWN COINS AFFECTED: Pharmacoin, Hexxcoin, MasterDOGE
(Note, just because a coin is affected does not mean the developer had any knowledge of this)
Pharma and thus all of it's forks have a LIVE EXPLOIT. Investigation continues as to what source code is responsible,
However. I can point to the side-effects of this exploit:
The PoW hash in Pharma is "distorted" to appear to be more powerful than it actually is.
It appears that the scrypt hash is generated correctly, but then modified seemingly unintentionally.
The end result is that this mangled hash is a higher difficulty than it actually is, thus making the entire
coin network have a higher difficulty than it really does.
A miner MUST take this into account when generating blocks on this network. A legit mining pool's blocks
will still be considered valid. However, a malicious miner can use this advantage and mine blocks that are much weaker,
and thus can basically have their hashrate amplified by a significant amount.
You can prove that a pool knowingly took part in this by taking it's PoW hash of a block it solved, shifting it left by 1 byte
and confirming that the block's PoW hash does not match the difficulty required for the network at that time
You can verify this by using this program:
https://github.com/Earlz/hashchecker See below for in-progress exploit details
litecoin:
Data used: 020000008F49E5FD7EF50DB9A2A1BFF5D3E93717A096329A8AC802A248463EF366CEEA1099B1FD0
D
B4CE8F4728251711F759081D0B5B4DA015FB78421D8FFBFDA1105A2ABDA1DB521B64101B00E60CD
0
true result: 000000000009183C881DEBBEAD806241A2467EB42BF4FBBFC988DC4045E91A46
wallet result: 000000000009183c881debbead806241a2467eb42bf4fbbfc988dc4045e91a46
pharma:
Data used: 07000000C29AB087984FC66B1333D0E7BFA44C901171CF8B609E8450C9C27C2F082BDBFD83D0919
A
75A7DB8E2DE73944F8C67B999014BD82EDDF3EB52FF1C28FEC4AB444B6B97655C261221BA9C0560
6
true result: 00000000203B7BC14DF5A74C09045BDC127C90FF7ED73C0C84C2AE4C21AC9A9B
wallet result: 0000000000203b7bc14df5a74c09045bdc127c90ff7ed73c0c84c2ae4c21ac9a
block info for relevant blocks used:
[earlz@earlztest2 src]$ ~/coins/litecoin/src/litecoin-cli getblock 65858117fadcff3b591ad4cbd320ecd3b0a63ffda1db9609822cf09ade790aa9
{
"raw" : "020000008F49E5FD7EF50DB9A2A1BFF5D3E93717A096329A8AC802A248463EF366CEEA1099B1FD0
DB4CE8F4728251711F759081D0B5B4DA015FB78421D8FFBFDA1105A2ABDA1DB521B64101B00E60C
D0",
"powhash" : "000000000009183c881debbead806241a2467eb42bf4fbbfc988dc4045e91a46",
"hash" : "65858117fadcff3b591ad4cbd320ecd3b0a63ffda1db9609822cf09ade790aa9",
"confirmations" : 307648,
"size" : 10184,
"height" : 500000,
"version" : 2,
"merkleroot" : "2a5a10a1fdfb8f1d4278fb15a04d5b0b1d0859f711172528478fceb40dfdb199",
"tx" : [
"7290af5dd8bfebda2852c0949742b110cfcf8931c40ff5a5aac18329bcbf0540",
"9b9047924ce1a690b90d38c922666baf18ea5259d26890193f5b7d3a9921b5a5"
],
"time" : 1390125501,
"nonce" : 3490506240,
"bits" : "1b10641b",
"difficulty" : 3998.22171415,
"chainwork" : "0000000000000000000000000000000000000000000000000ccc596c88108dfb",
"previousblockhash" : "10eace66f33e4648a202c88a9a3296a01737e9d3f5bfa1a2b90df57efde5498f",
"nextblockhash" : "dd7c727ff0f5d825c3ce15d608dd63d48a41647369ba1afa79d5ae9760b8f209"
}
[earlz@earlztest2 src]$ popd
~/coins/pharma/src
[earlz@earlztest2 src]$ ./pharmad getinfo
{
"version" : "v1.0.1.0-g32a928e",
"protocolversion" : 60020,
"walletversion" : 60000,
"balance" : 0.00000000,
"newmint" : 0.00000000,
"stake" : 0.00000000,
"blocks" : 64466,
"timeoffset" : 37,
"moneysupply" : 86631250.00916556,
"connections" : 83,
"proxy" : "",
"ip" : "1XXX",
"difficulty" : {
"proof-of-work" : 2501.83885576,
"proof-of-stake" : 10056110.06951050
},
"testnet" : false,
"keypoololdest" : 1433727007,
"keypoolsize" : 101,
"paytxfee" : 0.00001000,
"mininput" : 0.00000000,
"errors" : ""
}
[earlz@earlztest2 src]$ ./pharmad getblockbynumber 6793
{
"raw" : "07000000C29AB087984FC66B1333D0E7BFA44C901171CF8B609E8450C9C27C2F082BDBFD83D0919
A75A7DB8E2DE73944F8C67B999014BD82EDDF3EB52FF1C28FEC4AB444B6B97655C261221BA9C056
06",
"hash" : "2eeb9ea9e31a3f2b3a4067416fc5a076f655e1bd65c84ca39430daabe9f1c7ab",
"confirmations" : 57674,
"size" : 212,
"height" : 6793,
"version" : 7,
"merkleroot" : "44b44aec8fc2f12fb53edfed82bd1490997bc6f84439e72d8edba7759a91d083",
"mint" : 10000.00000000,
"time" : 1433844150,
"nonce" : 106348713,
"bits" : "1b2261c2",
"difficulty" : 1906.09198269,
"blocktrust" : "7721efe4c7a",
"chaintrust" : "b7ff730dc5620f",
"previousblockhash" : "fddb2b082f7cc2c950849e608bcf7111904ca4bfe7d033136bc64f9887b09ac2",
"nextblockhash" : "8938068868ae0fc3eb441ae5ce9286571b17cf2c875b45cf90ec80bfd47887f1",
"flags" : "proof-of-work",
"proofhash" : "0000000000203b7bc14df5a74c09045bdc127c90ff7ed73c0c84c2ae4c21ac9a",
"entropybit" : 1,
"modifier" : "47d924eb1325e958",
"tx" : [
"44b44aec8fc2f12fb53edfed82bd1490997bc6f84439e72d8edba7759a91d083"
]
}
Code notes:
The exploit is somewhere in pbkdf2.cpp. Some unintuitive pointer arithmetic is done which appears to malform the resulting PoW hash.
A good comparison is to diff it against the version in Crave. I replaced this file with Crave's version and it compiles fine, but results in the wallet instantly failing because the genesis seed hash is no longer matching.
Output (line breaks added for clarity) when also printing out the genesis hash:
[earlz@earlztest2 src]$ ./pharmad -daemon
hash: 00000102617cecd8aeba57d393e295389b83ff81f223898240282757ad7cdf7e
pharmad: chainparams.cpp:111: CMainParams::CMainParams(): Assertion `hashGenesisBlock == uint256("0x0000000102617cecd8aeba57d393e295389b83ff81f223898240282757ad7cdf")' failed.
Aborted (core dumped)
For reference, here the hashes are aligned to see the obvious difference.
true hash: 0x00000102617cecd8aeba57d393e295389b83ff81f223898240282757ad7cdf7e
wallet hash: 0x0000000102617cecd8aeba57d393e295389b83ff81f223898240282757ad7cdf
How to check for this exploit in other coins:
Replace the pbkdf2.cpp file with Crave's version from
https://raw.githubusercontent.com/industrialcoinmagic/crave/master/src/pbkdf2.cppIf the blockchain syncs completely after doing this, then it should be safe.
Conclusion:
Honestly, this is the most elaborate exploit I've ever seen in the altcoin world.
The review for Pharma is of course now an invalidated F as well as for Hexxcoin because of this exploit.
I reviewed these coins and found nothing wrong initially because this exploit is so well hidden.
Measures will be taken in the future to verify PoW hashes, but I must remind everyone that my reviews are not 100% guarantees.
My reviews pick out the obvious problems and the simpler exploits. I spend about 1-2 hours per review.
Figuring out this exploit took more than 10 hours all together and I still can't point to the exact line of code that's the problem.
I will continue to strive to review the code in altcoins, but everyone needs to realize that the bad guys have the upper hand here.
-----BEGIN PGP SIGNATURE-----
Version: Keybase OpenPGP v2.0.14
Comment:
https://keybase.io/cryptowsFcBAABCgAGBQJVk5ElAAoJEAKXMK2l7Ra+OrQP+weHqq8m4aRSxnnWP+Hmqdhu
ImHjm2z86bsi8poV7wop5ZRxP0PamevjdnPpzCAWSc1NrnbNDOstN8VNlPpCiD4N
5/fE+pPqlMmy94CPUXgP3UsNsIS2lncQCNnPhou3DqQw5EtfihOiPR+UbPgrwH6t
w14/Avr17+Ceja9v6mbyOVEEKBtqofNQbSsKzUcmO7+1d72sWMc4AJRz/gWH9KOv
bUlBW9/1curZDvRbaiMDV32YTQyNJf6wEUHkhhL1z++Xy05l8pfHuGwMqJ0fGcD8
sk4Y7qD+4N9wfkwuoq8CSBNgkIQwftT0XJLvW22lWwwwY20FXCLChs5v1ZkkxepY
KbjFr/U4uAlDiJgHRNQfdVZrqMO86OLGdT6cFQ3q9N0Nt35acOZFvqw3w76Cgi0m
5IBCh8X2n1PVmwTPI9z3H5Qr2LqqfAkEkCP6Bi4GqtBHuMXoi3i6LWfhlOCVw0QE
slVBhD5sJbrLyt9qzwQczEatmus5PM1JoPeStB3AxkMcyoJnfURBlh0BEsn0YCbd
YCCnukiZagqWlgF+xxBhjeL7aXpggPaL4j9V8A9kVqSe0DHg5Hn7Qx0Srbfal5lF
ChFxjYm3NO5LXpw6kRYaxjz3x00SjGx54r8n+mEYlJ6Cfos4CgPssrV2Vh7H0Iss
V7qjrnEiGynE6+papfXd
=OCRf
-----END PGP SIGNATURE-----