Buccaneer Privacy System (BUCC V3)

Smart Contract Audit Report

Audit Summary

BUCC V3 Audit Report Buccaneer is intending to build a private and immutable on-chain currency.

For this audit, we were contracted by the Buccaneer V3 team to attempt to reverse engineer and break the privacy of the Buccaneer Privacy System without source code.

The main contract analyzed was the BUCC V3 contract, deployed at 0x434804dc508eFEA4120057353650a3AC50f4f818 on the Rinkeby Testnet. The BUCC team provided us with these instructions and select ABIs to leverage in our analysis.

Date: August 22nd, 2022.

Audit Objectives & Findings

The audit objectives provided by the BUCC Team can be found below in bold. Our team's response is written below each objective.
Overall, we found that the privacy provided by the Buccaneer Privacy System can be broken, and that the system relies upon security through obscurity.

Demonstrate/prove that BUCC's privacy system is a purely smart contract-based system and nothing more, with no components critical or non-critical being not on-chain or fully decentralized, such as the Bermuda DAPP.

Although the privacy system appears to be a fully on-chain system, the majority of the platform is highly centralized across various contracts which can be manipulated by the project team at any time. Many components can be swapped out for other contracts at any time, which would alter the outcomes of the platform's critical functionality. Moreover, the privacy system only provides privacy through obscurity, as discussed in more detail below.

Demonstrate/prove that there exists no mechanism by which the creators, or anyone else can mint BUCC tokens after the TGE wherein 10 million units with 18 decimal place precision will be minted.

We disagree with the assertion that a mechanism to mint BUCC tokens does not exist. Upon calling the decrypt() function, the user's 'revealed' balance is increased by their 'hidden' balance as determined by the EndPoint contract. As the team can set the EndPoint contract address to any value at any time, the team can arrange the logic so that the 'hidden' balance is never decreased in the EndPoint contract for select addresses. This can enable the project team to mint an unlimited number of tokens.

Demonstrate/prove that there exists no mechanism to 'burn' tokens, either by action of the user, or the project team.

Similarly, we disagree with the claim that there is no way to burn tokens. The token contract contains a subtractValue() function which decreases the specified user's balance by a specified amount. Although this function can only be called by the Engine address, this address can be set by the project team to any value at any time, meaning that the project team does have the ability to remove tokens from users' balances. Furthermore, nothing can prevent a user from sending tokens to the 0xdead address, effectively burning them.

Demonstrate/prove that the BUCC token is not a payment token to use the network but in fact part of the BUCC smart contract suite and all work as one. Demonstrate/prove the fact that the Buccaneer Privacy System cannot privatize any other 3rd party cryptocurrency.

The BUCC token is not used as a payment token within the Buccaneer Privacy System. The Buccaneer Privacy System cannot privatize any other cryptocurrencies. The smart contracts are designed with the intent to only provide privacy to the BUCC token, and no way to add other tokens exists. That being said, the Buccaneer Privacy System does not provide true privacy, as discussed in more detail below.

Demonstrate/prove that the Buccaneer Privacy System is not a tumbler, but in fact a private currency running on Ethereum's Layer 1 without external assistance in any minor or major way. Demonstrate/prove that the Buccaneer Privacy System does not utilize obfuscation as a means to attain apparent privacy.

The Buccaneer Privacy System does not actually provide privacy. Instead, it utilizes obfuscation as a means to attain apparent privacy. The BUCC system attempts to create privacy by encoding user's received balances. This encoding, however, is merely obfuscation of the sent token amount. At the end of the encoding process, the resulting value is stored in the EndPoint contract as a user's 'hidden balance'.
Encrypted balances are meant to only be read by the token contract - but by impersonating the token contract on a forked network, we can query the EndPoint contract directly to determine the 'hidden balance' for any account.
Moreover, although the details of transactions produced by the system are intended to private and secure, internal call data can be deciphered as shown below to extract the recipient address and amount sent for any private transaction through the Bermuda system.
For more details about how we cracked the Bermuda privacy code, read the “Breaking the Buccaneer Privacy System” sections below.

Platform Overview

  • The BUCC V3 token contract intends to provide privacy to users by obscuring balances so that they cannot be read by traditional measures.
  • This contract relies on several other external contracts which we initially were not provided ABIs for. By the time we received those ABIs, our team had already reverse engineered the relevant contracts to determine how to read encrypted balances and private transaction data.
  • The external contracts enable users to swap tokens, leveraging external pricing oracles, or a relayer/trusted forwarder. Other external contracts support the obscured-balance logic.
  • The contract supports meta transactions to forward all gas payments to the trusted forwarder address in an effort to promote "gasless" transactions.
  • Anyone can call the TESTaddUpBalance() to increase their balance by 100 tokens at any time. (We assume this is purely for testing purposes.)
  • Only the Engine address can call the subtractValue() function to deduct any amount from the user's balance at any time. As the team can change this contract's address, they could have the ability to burn users' tokens.
  • The Engine and EndPoint contracts are meant to support the Bermuda privacy function of the BUCC token.
  • Anyone can use the BUCC contract to execute a batch of transactions on the Engine contract.
  • When sending tokens using the Bermuda privacy functions, the amount and recipient appear to be obscured.
  • Looking at on-chain internal calls for deposits through Bermuda, however, our team has determined that anyone can determine the intended recipient and amount sent.
  • Upon querying a user's balance in the BUCC contract, only a portion of the balance may be shown or none if no tokens were ever received via a normal transfer.
  • In order to display the full balance, a user who has received tokens via Bermuda must call the decrypt() function which will access the obscured balance which is ultimately stored in the EndPoint contract.
  • While this balance is meant to be hidden before the calling of decrypt(), we discovered anyone can read any addresses' hidden balance, as discussed below.
  • When sending the token normally, the recipient will see their balance increase by the sent amount.
Ownership Controls:
  • The team can set the swap fee rate to any value at any time.
  • The team can set the Trusted Forwarder, Engine, EndPoint, Swap, Paymaster, RelayHub, Oracle, and Pool addresses to any address at any time. This effectively allows the team to upgrade these contracts.
  • The team can self-destruct the contract at any time, forwarding any and all ETH in the contract to the caller's address.
  • The team can renounce ownership.

Breaking the Buccaneer Privacy System

Decrypting Hidden Balances

After reverse engineering the contracts and noticing what input data was sent to function selectors on various contracts, our team determined that the privacy system can be broken using only on-chain data. To prove this, we created the below test scenario on the Rinkeby testnet.

First, we use the Bermuda privacy system to send 150 tokens (out of 200 in the current balance) from 0x88 to 0x6e: BUCC V3 Audit Report

Next, we investigate the transactions. After sending tokens via Bermuda, we see 2 transactions:

After the transfer via Bermuda, the recipient (0x6e's) balance is unchanged as it is stored in the EndPoint contract as a 'hidden balance':

BUCC V3 Audit Report BUCC V3 Audit Report

While the EndPoint contract only allows the BUCC token address to read users' 'hidden balances', we can query EndPoint contract ourselves. To do so, we found the function selector for the call to get the hidden balance:

BUCC V3 Audit Report

Then we leveraged Tenderly to fork the network and impersonate the BUCC contract to query the balance of the 0x6e account on the EndPoint contract directly:

BUCC V3 Audit Report

After performing the above call, we received an output from the simulation which showed the return value in hexadecimal format:

BUCC V3 Audit Report

Converting the Hexadecimal output to decimals shows that 0x6e's encrypted balance is 150 BUCC tokens, the same amount sent:

BUCC V3 Audit Report

Discerning Recipients & Sent Amounts

The BUCC instructions indicated that "BUCC is private due to the fact that the recipient and amount transacted cannot be found out due to advanced and custom encryption methods." We have found this to be untrue, and we are able to determine the recipient and amount of any private transaction through Bermuda.

While addresses and sent amounts may be obscured in the transaction data originating from a user's wallet, when sending via Bermuda internal calls occur that reveal the true recipient of the private transfer as well as the amount sent.

By stepping through the internal calls of the sendTx() transaction from the 0x88 address in our example earlier, we can see the recipient address that the tokens are being sent to (the 0x6e address), immediately followed by the amount of tokens that are being sent in hex-encoded format:

BUCC V3 Audit Report

Storage Layout

OBJECT TYPE STORAGE SLOT CONTENTS
owner address 0 0x88a81a9a5E5710CA4ea0c1E5b3593EfF8050c28c
unknown
7da0a877Address
address 1 0x00
Trusted Forwarder
stor2 struct array 2 "BV3"
Array for name() string
stor3 struct array 3 "BUCC V3"
Array for symbol() string
_decimals uint8 4 18
stor4 address 4
offset 8
0xDA8e93d567eb80B7851327d67F90aDA52fC76095
Engine contract (same as stor13)
stor5 address 5 0x00
Swap contract address (same as stor14)
stor6 address 6 0x4517cE26A5D6f2b0b66d4cb511f03b12e6E1c02f
Bermuda EndPoint (same as stor15)
stor7 address 7 0x00
Oracle
stor8 address 8 0x0CFdc04eD1Cd1938afDA1a37f38C6fad077d4205
Unknown unverified contract
stor9 uint32 9 0
stor9 address 9 0x13c0802B9CF99B1AF1818fBF8221171d2aE808dB
Unknown self-destructed contract
stor10 address 10 0x29Fe97Cc1751d8C8A9c4b8FCF3339dF7cd98a825
TetherTest ERC20 token
stor11 uint32 11 0
stor11 address 11 0x65128c80fb562FA8f08BC657CAc33e29ea784c21
TetherTest/WETH UniswapV3Pool
stor12 address 12 0xc778417E063141139Fce010982780140Aa0cD5Ab
WETH contract
stor13 address 13 0xDA8e93d567eb80B7851327d67F90aDA52fC76095
Engine contract (same as stor4)
stor14 address 14 0x00
Swap contract address (same as stor5)
stor15 address 15 0x4517cE26A5D6f2b0b66d4cb511f03b12e6E1c02f
Bermuda EndPoint (same as stor6)
stor16 address 16 0x00
Oracle
balanceOf mapping (address => uint256) 17-18 Mapping for Balances
stor19 address 19 0x00
Paymaster
stor20 address 20 0x00
RelayHub
stor21 address 21 0x00
Oracle
allowance mapping(address => mapping(address => uint256)) 22-27 Mapping for allowances
stor28 mapping of uint8 28 Unknown mapping of
address to boolean
unknown
efdc4352
uint256 29 0
Fee rate
stor30 mapping(address => bool) 30 Mapping for locks
stor31 struct array 31 "2.2.4"
Array for Version Recepient Number (string)

About SourceHat

SourceHat has quickly grown to have one of the most experienced and well-equipped smart contract auditing teams in the industry. Our team has conducted 1300+ solidity smart contract audits covering all major project types and protocols, securing a total of over $50 billion U.S. dollars in on-chain value across 1500 projects!.
Our firm is well-reputed in the community and is trusted as a top smart contract auditing company for the review of solidity code, no matter how complex. Our team of experienced solidity smart contract auditors performs audits for tokens, NFTs, crowdsales, marketplaces, gambling games, financial protocols, and more!

Contact us today to get a free quote for a smart contract audit of your project!

What is a SourceHat Audit?

Typically, a smart contract audit is a comprehensive review process designed to discover logical errors, security vulnerabilities, and optimization opportunities within code. A SourceHat Audit takes this a step further by verifying economic logic to ensure the stability of smart contracts and highlighting privileged functionality to create a report that is easy to understand for developers and community members alike.

How Do I Interpret the Findings?

Each of our Findings will be labeled with a Severity level. We always recommend the team resolve High, Medium, and Low severity findings prior to deploying the code to the mainnet. Here is a breakdown on what each Severity level means for the project:

  • High severity indicates that the issue puts a large number of users' funds at risk and has a high probability of exploitation, or the smart contract contains serious logical issues which can prevent the code from operating as intended.
  • Medium severity issues are those which place at least some users' funds at risk and has a medium to high probability of exploitation.
  • Low severity issues have a relatively minor risk association; these issues have a low probability of occurring or may have a minimal impact.
  • Informational issues pose no immediate risk, but inform the project team of opportunities for gas optimizations and following smart contract security best practices.