Not at This Address! | Chengdu LianAn Technology Vulnerability Analysis Series Phase V

Authorization Validation Error

BEOSIN
8 min readOct 12, 2018

As the foundations of cryptocurrencies in Ethereum, smart contracts are bearing the weight of enormous financial assets. The daily frequency of transactions in Ethereum is around 500–750 thousand times per day. While in May and February, there were two days having 1 million times transaction.

Function call is like the bullets in the battlefield for Ethereum ecosystem. What smart contracts do are various, but there exists a common feature in them — inheriting the members of address. In other words, address is the foundation of contracts. Looking back at previous 4 analysis, we understand that attackers try every way to take advantage of vulnerabilities within contracts. So attacking from address could also be a method.

Speaking of address in smart contracts, let’s talk about tx.origin variable and ecrecover() function related vulnerabilities.

Overview

As the official language of Ethereum, solidity defines the address as 20 bytes and 160-bit value. Every contract has its own address and can call other contracts on other addresses. Members of address type include call() and delegatecall() which we mentioned in last phase. The related vulnerabilities are discussed already. Different contract addresses represent different contracts and their privileges. So the address of the contract is its ID card.

tx.origin is a global variable which traverses the entire call stack and returns the address of the account that originally sent the call (or transaction). ecrecover() is a globally available method to verify if the returned address is the same as the signer.

In general terms, tx.origin is the original owner of the contract in the whole transaction, when contract A calls the function of contract B, the original owner is also the intermediate contract, namely contract A.

But if we say contract A calls contract C first, and contract C calls contract B. The intermediate contract should be contract C and tx.origin should be contract A.

The vulnerability exploits tx.origin can be analogized as below:

Remember in Super Bad that Evan and Seth want to buy some adult beverages even when they are underage? They called Fogell to buy some for them using his fake ID as Mr. McLovin. So when the shop assistant Mindy wants to see some ID, Fogell pulls out the fake one to show her. Instead of verifying the age of Fogell, the verification was directed to Mr. McLovin, the intermediate fake ID. That’s how they got the alcohols.

As for ecrecover function problem, when passing values has no mistakes, the use of it will be alright. But the problem is, if passing values are wrong, exception rules should be made for precautions.

Let’s analyze these two vulnerabilities using case contracts.

In-Depth Analysis

  1. The misuse of tx.orirgin

Vulnerability Analysis

As we said above, tx.origin is a global variable which traverses call stack and returns address of the account that originally sent the call (or transaction). In smart contract, using this variable to verify identification could be vulnerable to attacks similar to phishing. Please refer to StackExchangeQuestion, the blog of PeterVenesses and Solidity-tx.origin attack for deeper reading.

Now we use the following case for analysis:

This contract includes three functions: a constructor to specify owner; a fallback function with payable keyword to receive transaction; a withdrawAll function to add verification on tx.origin, if tx.origin is the owner specified, all ethers on this contract address will be sent to _recipient.

Assume an attacker creates this contract:

Attacker lures the owner of original contract (Phishable.sol) to send ethers to attack contract (POC.sol) address. Subsequently calling fallback function in the attack contract to execute attack() function. At this moment, phOwner == msg.sender, and it will call the withdrawAll() function of the original contract. Execution now enters the original contract, but msg.sender represents the address of the original contract, and tx.origin is the address of the transaction initiator, which is the owner of the original contract. require(tx.origin == owner); is satisfied. Hence the execution of _recipient.transfer(this.balance);, and that’s how the ethers within the original contract was transferred to the attacker.

Bug-fix

tx.origin should not be used to authorize in the smart contract. However, this does not mean that tx.origin should never be used. There are some effective usage of such variable. Such as rejecting external referencing from outside the contract, require(tx.origin == msg.sender) could be used and it will also help prevent intermediate contract from calling original contract.

2. Missing 0 address exception in ecrecover

Vulnerability Analysis

keccak256() and ecrecover() are both built-in functions, keccak256() could be used for calculate the signature, while ecrecover() could be used to recover it. When all passing values are correct, these two functions could be used together to verify address.

For example,

This contract seems normal, but if we dig deeper, we can find that if ecrecover was input with wrong parameter (_v=29 for instance), this function will return 0 address. If the verification address sent from the contract function is also 0, wrong logic will appear through assertion.

In the function transferProxy, if the input parameter _from is 0, then ecrecover function will return 0 because the parameter is wrong, which will result in if goes through. This leaves a vulnerability in contract.

Let’s see a more complex contract.

decode() function is in charge of passing the data after signing, which is for the verification of the returned value being the same as the signing address. Ethereum provides web3.eth.sign method to generate digital signature for data. So the signing data could be acquired through the js code below:

The result of running this js code shows as this:

Bug-fix

Filtering the 0x0 address, for instance:

Be Vigilant

This vulnerability does not have related attack incident because there were users reporting this problem on github to Solidity about this issue in June, 2016. The confusion caused by tx.origin emerged and someone suggested that it should be removed.

This issue drew a lot attention because the DAO attack happened on 17th of June. The discussion about throwing away this variable heated up. But as we mentioned, to reject external function referencing from outside the contract, using require(tx.origin == msg.sender) is very effective and adds protection to the original contract. In terms of external function call (or referencing), we’ve discussed it in the last phase. Please refer to it using this link: .

Therefore, someone else came up with this idea which is adding a warning while using tx.origin.

Solidity Official accepted this idea and added the warning in time to prevent vicious attacks from happening afterwards.

However, can we ignore this vulnerability now that there is a warning?

The trend of smart contract is changing now because of the Ethereum games and DApps rising. The gravity of Ethereum is leaning to these two instead of simple ICO contracts. Games using its unique randomness and entertaining features to draw attentions from gamers and investors, while they are repeating the mistakes happened in simple ICO contracts. What’s worse, there are some developers creating honeypots which show as obvious loopholes while hiding vicious mechanism to lure gamers. Some known vulnerabilities are modified by hackers and become new frauds. Recently the game called ‘QUESTION’ uses the flaws of etherscan.io to gather money from gamers.

Conclusion

Whether it’s the deception of address verification or honey pot trick, attackers are always aiming at the pocket of investors who are chasing the profit. We strongly recommend that investors should raise awareness of security and increase knowledge of smart contracts. Differentiating and analyzing is the pre-requisite of a good investment and secure development.

References:

[1]: Solidity Security: https://blog.sigmaprime.io/solidity-security.html#tx-origin

[2]: ERC20 Token Smart Contract Security Risks: transferProxy-keccak256

[3]: ERC20 Token Smart Contract Security Risks: approveProxy-keccak256

About Chengdu LianAn Technology

Chengdu LianAn Technology Co. Ltd. is headquartered in Chengdu and focuses on blockchain security field. Founded by Prof. Xia Yang and Prof. Wensheng Guo of UESTC, LianAn Tech’s core team members consist of more than 30 associate professors, postdoctoral students, doctors and masters with experience of studying at overseas leading universities and laboratories (CSDS, Yale, and UCLA) as well as industry elite from Alibaba Huawei, and other famous enterprises. Using formal verification as its core technology, this team has been providing years of services for security critical systems in aerospace, military and other fields. Chengdu LianAn Technology Co. Ltd. is the one and only company in China that applies this technology to blockchain security field.

Being the only blockchain security company that obtained strategic investment from Fenbushi capital, LianAn Technology has signed strategic cooperation agreements with well-known corporations such as Huobi, OKEX, KuCoin, LBank, CoinMex, Becent, ONT, Scry, CareerOn, IoTeX, DALICHAIN, Bplus, Bytom, Bubi Blockchain, and YUNPHANT. In addition, it has made cooperative agreement with France Inria, the top formal verification team in the world. LianAn Tech was listed on the “2018 China Blockchain Industry White Paper” issued by the Ministry of Industry and Information Technology, and it has also been selected for the smart contract security audit recommendation List.

--

--

BEOSIN

Blockchian Security · IDE · Beosin-VaaS · Formal Verification · SAS | China leading enterprise in blockchain security field