Populous Smart Contracts Audit

Alexander Seleznev
SmartDec Cybersecurity Blog
11 min readSep 28, 2017

--

In this report we consider the security of the Populous project. Populous is “an invoice and trade finance platform” using Ethereum based Smart Contracts. Our task is to find and describe security issues in the Smart Contracts and its interaction with the backend.

Procedure

In our analysis we considered Populous whitepaper and Smart Contracts code (version with latest commit 10de4ae on 21 Apr 2017). We used several publicly available automated Solidity analysis tools. Also, we scanned project’s Smart Contracts with our own tool. All the issues found by tools were manually checked (rejected or confirmed). Contracts were manually analyzed, their logic was checked and compared with the one described in the whitepaper. Besides, we analyzed the interactions between the backend and Smart Contracts.

Format

For each found vulnerability we describe possible threat agents, attack vectors, security weakness, technical and business impacts of the attack, vulnerability severity (critical, medium, low) and recommendations on the vulnerability elimination.

Since the backend source code is unavailable (and if it was, we still wouldn’t be able to check whether the same version is being executed on the server) we will consider it as vulnerable by default.

Systems on Smart Contracts are meant to be trustless or partly trustless. Thus, we will consider system administrators and developers as possible attackers, since users are not meant to trust them. We will consider administrators and developers as possible attackers also because an external attacker can possibly gain an administrator access to the backend and act as an administrator.

Platform description

The platform implements invoice auctions. The process involves administrators of the system, borrowers who sell invoices and investors who bid on auction to buy invoices.

When the borrower registers, he provides information about his company. The administrator approves or blocks his account. Then the borrower provides information for the invoice and the auction. After that the administrator generates credit score for the invoice. Then the administrator rejects or approves the auction and defines service fees. The described part of the system is implemented in backend.

The auction is implemented in Smart Contracts. The investors form groups, group set its goal (amount of money from investors to be collected). The group that reaches its goal first becomes the winner of the auction. The borrower gets the money. Bidders (investors) of the losing groups are refunded with their money. When the borrower cashes the invoice, he sends the money to the platform. When the funds are received, the investors from the winning group receive their winnings.

The platform operates (bids are made and winnings given) with stable currency tokens pegged 1 to 1 with worldwide government’s currencies. When the actor deposits funds into the platform, an equivalent amount of tokens is deposited into his account. Also BTC and other cryptocurrencies can be deposited. The deposited BTC are converted to GBP, based on the current exchange rate and the actor receives Populous GBP tokens equivalent to the GBP amount. The conversion is done manually, by the platform admin, with partner brokers. Other cryptocurrencies are converted to BTC and follow the same procedure.

The actor can withdraw his tokens for the equivalent of the corresponding worldwide government currency. Platform fees apply upon withdrawal.

Automated Analysis

We used several publicly available automated Solidity analysis tools. Here are the combined results of their analysis.

Manual Analysis

All the issues found by tools were manually checked (rejected or confirmed). Contracts were manually analyzed, their logic was checked and compared with the one described in the whitepaper. Besides, we analyzed the interactions between the backend and Smart Contracts.

Error In Logic: The Auction Duration Has Ended

If none of the groups has reached its goal during the auction time, the auction is closed (Crowdsale.checkDeadline (line 94)). After that the borrower is chose one of the groups to be the winner by invoking Crowdsale.borrowerChooseWinner (line 236). However, the borrower will not be able to do so, since this method has the onlyOpenAuction modifier, which means the method can not be invoked after the auction is closed.

Such behaviour directly and significantly contradicts the Populous whitepaper, which says:

“1.6.8. The auction duration has ended.1.6.8.1. The borrower has the option to accept the funds from an investors group of his choosing, even if the group hasn’t reached its goal.”

Besides, at the specified moment the Crowdsale.winnerGroupIndex (line 55) variable has not been initialized yet, since it is initialized only when some group reaches its goal in Crowdsale.bid (line 225) or when the borrower chooses the winner in Crowdsale.borrowerChooseWinner (line 241). That means that its value is 0 at the moment and the group that was created first (and thus has the 0 index) in this auction is a winner. This is a very serious bug and vulnerability.

Attack

Threat agent: any Ethereum user.

Attack vector: the attacker creates the first group for each Populous auction that has no groups yet and bids a minimal value of money.

Security weakness: undefined system’s behaviour when the auction duration has ended.

Technical impact: the attacker becomes the winner for every auction with ended duration, no matter how little money he or she has bid.

Business impact: undefined, since the system’s behaviour is undefined. Hypothetically, the borrower gets very little money for his invoice and the attacker gets the full cost of the invoice when the invoice is payed by the borrower. More likely, the administrators has to intervene the operation of the system significantly. Both scenarios mean serious reputational losses for the platform. The first one also means money losses for the borrower.

Severity: critical (can occur even without a deliberate exploit; severe impact).

Recommendation: define system’s behaviour when the auction duration has ended in Smart Contracts. Review the Smart Contracts code and compare its logic to the one described in the whitepaper.

Unlimited Group Creation

In Populous auctions are held between groups of investors. When the auction is over, investors of groups are refunded with their tokens. This means that the code need to execute loops over losing groups. Several methods of the contract implement such loops: Crowdsale.findBidder(line 174), Crowdsale.findBidder(line 185), Populous.fundWinnerGroup(line 364), Populous.refundLosingGroups(line 279).

The Populous.refundLosingGroups(line 279) method even contains the following developer comment:

@dev This function has to be split, because it might exceed the gas limit, if the groups and bidders are too many.

Groups are created by investors via the Crowdsale.createGroup(line 156) method. This method is available to any Ethereum user, which means anyone can create groups. Besides, the method does not set/check any constraints on number of groups. Thus, an attacker can create as many groups as he wants. The only constraint is attacker’s amount of ether to pay for the gas to invoke createGroup.

If attacker creates many enough groups, the methods listed below will be aborted when the gas runs out. This will block contract’s lifecycle. It will become impossible to refund losing groups, thus it will be impossible to accept invoice payment and to fund winner group of investors. Besides, the party that calls the refund method will waste gas.

This kind of vulnerability is known as “Gas Limits And Loops” or “DoS with Block Gas Limit”.

Attack

Threat agent: any Ethereum user.

Attack vector: attacker creates many groups via the Crowdsale.createGroup(line 156) method.

Security weakness: number of groups to be created is not restricted.

Technical impact: methods for refund will be aborted due to the gas lack.

Business impact: it will become impossible to refund losing groups, thus it will be impossible to accept invoice payment and to fund winner group of investors; users lose their money and/or time time; the system loses reputation.

Severity: critical (easily exploitable, severe impact).

Recommendation 1: in current implementation it is possible to unblock the contract by manually invoking the Populous.refundLosingGroupBidder(line 308) method for every bidder.

Recommendation 2: implement safe loops with gas amount checks.

Recommendation 3: this attack can be avoided by limiting the number of groups for the auction. This attack can be made expensive by taking fees for groups creation.

Smart Contracts and Backend

In Populous a significant part of the system (credit scoring, funds depositing) is backend, which is not a Smart Contract but a usual code. This means that the user can not check what is done there, thus, the user needs to trust system developers and administrators. Furthermore, an external attacker can possibly gain an administrator access to the backend and act as an administrator.

Ethereum Smart Contracts were designed to help parties interact without trust (or to isolate trust, i.e. to rely on trust only in those parts of the system in which it is necessary). Thus, the characteristic described above is undesirable in Smart Contracts systems.

System administrator or the attacker who has gained administrator access to the backend is capable of performing different attacks including the two examples below.

Attack 1

Threat agent: administrator or developer of the platform; an attacker who has gained unauthorized access to the system using possible vulnerabilities in backend.

Attack vector: an attacker changes the credit scoring of the invoice (which is possible since credit scoring is calculated by backend, not by Smart Contract).

Security weakness: credit scoring is calculated by backend.

Technical impact: system gives investors false credit scoring of the invoice.

Business impact 1: investors buy the attacker’s invoice that is given too high score and lose their money; the system loses reputation.

Business impact 2: invoice is given too low score and attacker buys it for lower price; the borrower loses money; the system loses money; the system loses reputation.

Severity: medium (potentially exploitable, severe impact).

Recommendation: calculate scoring in Smart Contract; provide investors with an open source calculation system and the invoice raw data or avoid this calculation at all (for instance, implement internal reputation system).

Attack 2

Threat agent: administrator or developer of the platform; an attacker who has gained unauthorized access to the system using possible vulnerabilities in backend.

Attack vector: an attacker interrupts the BTC exchange process and sells (buys) stable currency tokens to the user for the price higher (lower), then the price of the broker with who attacker trades.

Security weakness: currency exchange is implemented in backend.

Technical impact: the user is given a disadvantageous exchange rate; the difference is kept by the attacker.

Business impact: the user loses money; the system loses reputation.

Severity: medium (potentially exploitable, severe impact).

Recommendation: sell stable currency tokens in Smart Contract for Ether; use exchange rates from a trusted source in Ethereum network.

General recommendation for this and similar vulnerabilities is to implement the whole system in Smart Contracts leaving for the backend as little as possible (in ideal case — nothing or only visualisation).

Warning: Should be constant but is not

The following methods in safeMath.sol are not declared as constant while in fact they do not modify the state: safeMath.safeMul(line 4), safeMath.safeSub(line 10), safeMath.safeAdd(line 15) and safeMath.assert(line 21) .

In current version the compiler does not enforce that a constant method is not modifying state. However, this may change in future, so we recommend to declare methods that do not modify the state as constant.

All checked vulnerabilities

The problems that we have found in Populous are described above. We should also describe vulnerabilities that we searched and haven’t found in Populous, and thus the probability of their appearance in the platform is low.

We have scanned Populous Smart Contracts for commonly known and more specific vulnerabilities. Here are some of the commonly known vulnerabilities that we considered (the full list includes them but is not limited to them).

Reentrancy (not found)

Any interaction from a contract A with another contract B and any transfer of Ether hands over control to the contract B. This makes it possible for B to call back into A before this interaction is completed. Furthermore, you also have to take multi-contract situations into account. The called contract (B) could modify the state of third (C) contract you depend on.

https://media.readthedocs.org/pdf/solidity/develop/solidity.pdf

Timestamp Dependence (not found)

The timestamp of the block can be manipulated by the miner, and so should not be used for critical components of the contract. Block numbers and average block time can be used to estimate time, but this is not future proof as block times may change.

https://github.com/ethereum/wiki/wiki/Safety#timestamp-dependence

Gas Limit and Loops (present, see above)

Loops that do not have a fixed number of iterations, for example, loops that depend on storage values are insecure. Due to the block gas limit, transactions can only consume a certain amount of gas. Either explicitly or just due to normal operation, the number of iterations in a loop can grow large enough, so required amount of gas exceed block gas limit. This cause the complete contract to be stalled at a certain point. This may not apply to constant functions that are only executed to read data from the blockchain. Still, such functions may be called by other contracts as part of on-chain operations and stall those.

http://solidity.readthedocs.io/en/develop/security-considerations.html#gas-limit-and-loops

DoS with (Unexpected) Throw (not found)

Vulnerability of this type are intended to make the contract unavailable to achieve the purpose for which it is designed. In this case it is due to the unexpected throw.

https://github.com/ethereum/wiki/wiki/Safety#dos-with-unexpected-throw

DoS with Block Gas Limit (present, see above)

Each Ethereum block can process a certain amount of computation. If you try to go over that, your transaction will fail. This can lead to problems even in the absence of an intentional attack. However, it’s especially bad if an attacker can manipulate the amount of gas needed.

https://github.com/ethereum/wiki/wiki/Safety#dos-with-block-gas-limit

Transaction-Ordering Dependence (not found)

Since a transaction is in the mempool for a short while, one can know what actions will occur, before it is included in a block. This can be troublesome for things like decentralized markets, where a transaction to buy some tokens can be seen, and a market order implemented before the other transaction gets included.

https://github.com/ethereum/wiki/wiki/Safety#transaction-ordering-dependence-tod

tx.origin (not found)

Using tx.origin for authorization is insecure.

http://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin

Exception disorder (not found)

In Solidity there are several situations where an exception may be raised, e.g. if (i) the execution runs out of gas; (ii) the call stack reaches its limit; (iii) the command throw is executed. However, Solidity is not uniform in the way it handles exceptions: there are two different behaviours, which depend on how contracts call each others. The irregularity in how exceptions are handled may affect the security of contracts.

https://eprint.iacr.org/2016/1007.pdf

Gasless send (not found)

When using the function send to transfer ether to a contract, it is possible to incur in an out-of-gas exception. This may be quite unexpected by programmers, because transferring ether is not generally associated to executing code. The reason behind this exception is subtle. This is due to the fact that function C.send (amount)is compiled in the same way of a call with empty signature.

https://eprint.iacr.org/2016/1007.pdf

Conclusion

In this report we have considered the security of the invoice and trade finance platform Populous. In our analysis we considered Populous whitepaper and Smart Contracts code (version with latest commit 10de4ae on 21 Apr 2017).

Contracts logic was checked and compared with the one described in the whitepaper. Serious discrepancies and errors were found (see “Error In Logic: The Auction Duration Has Ended”). It is highly recommended to review the Smart Contracts and backend code and compare its logic to the one described in the whitepaper.

We used several publicly available automated Solidity analysis tools. Also, we scanned project’s Smart Contracts with our own tool. All the issues found by tools were manually checked. Also, some new issues were found during the manual analysis of the platform. All confirmed issues and commonly known rejected vulnerabilities are described above.

For each found vulnerability we described possible threat agents, attack vectors, security weakness, technical and business impacts of the attack, vulnerability severity and recommendations on the vulnerability elimination.

The project’s Smart Contracts and its interaction with backend appeared to contain some critical security issues (see “Error In Logic: The Auction Duration Has Ended”, “Unlimited Group Creation”, and “Smart Contracts and Backend”). It is highly recommended to consider these issues and take appropriate measures (see recommendations above), since the exploitation of these vulnerabilities may lead to severe impact on the platform and it’s users.

Besides, it is highly recommended to work on the backend security. Firstly, implement in backend as few functions as possible (implement as many as possible in Smart Contracts). Secondly, perform Smart Contracts and backend security analysis.

Disclaimer: smart contracts code has changed since commit 10de4ae on 21 Apr 2017.

This audit was performed by SmartDec.

--

--