SBN

Browsing for Bugs: Finding and Reporting a $3M Bug in Premia Finance

I’m Ayaz Mammadov, a security engineer at Zellic. I often come across
vulnerabilities in code. One day, I was browsing projects during my
spare time and found something interesting from Premia Finance — an
uncaught bug that could have led to millions of dollars in lost funds.

Though now resolved, this story serves as an interesting example of the
process security engineers take to discover bugs. From finding targets
to exploring a codebase, we’ll go over the steps it takes to find and
expose a vulnerability and how the Premia Finance bug was caught.

Finding a Target

There are several factors that come into play when finding a target.

Platforms, ecosystems, and languages. These are most important to
consider when finding a target. Newer and less mature platforms that use
different languages present more opportunity for finding security flaws
— developer knowledge and confidence is not yet strong, which leaves
more room for error. Further, when searching for vulnerabilities in less
mature platforms, there is less competition (because of limited
information and a high barrier to entry). An experienced security
researcher has a significant advantage in finding bugs on newer
platforms because of their domain expertise. However, there are
disadvantages when it comes to newer platforms: there are far fewer
projects available, and on average those projects have a smaller total
value locked (TVL).

The TVL range. The larger the TVL of the project, the more severe
the bugs are. Apart from obvious criticals that cause loss of funds,
even less severe bugs that would occasionally be disregarded as user
error or an unlikely incident can have far-reaching and spread-out
effects. This is especially true when other nonstandard contracts/tokens
(e.g., ERC-777s) are involved that have special features that are not
accounted for. Large projects usually also have more audits from
different auditing companies and bug bounty systems, which greatly
reduce low-hanging fruit. However, small projects might not have auditor
bug bounties.

Project type and its mechanisms. Crypto shows up in many fields,
whether it be in video games, casinos, markets/DeFi, NFT marketplaces,
escrow systems, mixers, wallets, and so on. Here, a security
researcher’s personal preference is most important, as experience with
and knowledge of the common pitfalls of specific projects and their
interactions with well-known DeFi projects (e.g., Compound, Uniswap) is
greatly appreciated. The trade-offs here are obvious, as finance-related
protocols usually contain higher TVLs. On the contrary, other crypto
projects may contain less TVL but more lines of on-chain code and higher
complexity, which makes it easier to find security flaws.

”Forktasticity”. This is an unspoken topic; it describes how forked
a project is and how likely it’s to be used as a base for other
projects. One may notice that a lot of decentralized apps (dApps) are
altered forks of other popular protocols (e.g., Compound, AAVE,
Uniswap). These projects may have few changes that a security researcher
can quickly cover if they are already up-to-date with the original
protocol and the possible side effects that changes have. Conversely,
they also usually contain widely reviewed code that is unlikely to have
any issues. These projects also expose opportunities: when an exploit
affects a protocol, it usually affects many of its forks. Security
researchers who are on the watch and following recent news, or use tools
like Zellic’s Forky
(coming soon), can often take advantage of being an early bird to secure
other protocols.

Methodology of Finding Bugs

There are three main ways of exploring code: focusing on breadth,
focusing on depth, and focusing on speed.

The breadth-first style of security research relies on common,
low-hanging fruit, which are issues that present themselves in a similar
manner. The upside of this approach is that a security researcher can
cover more code with just a quick skim and without much consideration of
the underlying intentions, effects, and architectural decisions taken
during the development phase. This type of security research is also
context-free, meaning that it can be done without having to take notes
and piecing together how things work. This type of security research is
advantageous because it can be employed at any time, when energy is low,
and when there isn’t that much free time, and it can be done on a whim.
But the downside is that it is difficult to find in-depth bugs in secure
and popular protocols.

The depth-first style of security research prefers to uncover every
detail and inner workings of a protocol, methodically going over each
line of code and thinking about various consequences and possible
exploitation. This would ideally be the only style of security research,
as if it is effectively implemented, it results in uncovering deep,
hard-to-catch bugs. However, there are clear downsides: if the protocol
being looked at is not fairly large or commonly seen and results are not
found, the effort spent deeply thinking about the protocol is not of
much value. This style of security research is preferred for larger
projects (e.g., Compound, AAVE) because even if issues are not found,
the knowledge gained from conducting the research is easily applicable
to forks and other protocols. When a security researcher inevitably
encounters the same code they’ve already read, they’ll be able to get up
to speed a lot faster.

Lastly, a speed-based approach can be employed where a security
researcher keeps their eyes out for accounts on social media (such as
Twitter/Telegram) that report issues that affect popular protocols. This
information can be used to target similar forks or projects, tailoring
the vulnerability to them. This requires a security researcher to be
up-to-date and vigilant.

Finding the Protocols

There are multiple sources for finding protocols, from websites to
social media to news feeds. I personally use websites such as
DeFiLlama to browse through DeFi protocols as
they provide values for the TVL and the platform on which the project is
based. Other important pieces of information like previous audits or
links to documentation can also be quickly found. The website
DappRadar is an alternative. A lot of upcoming
projects won’t be listed on any aggregators but need to be discovered
through social media such as Twitter and Telegram.

Finding the Bug

During my spare time, I decided to open up
DeFiLlama. My preference is to look at
projects with a TVL greater than five million dollars and ones that
contain bug bounties. Bug bounties are a win-win situation — they ensure
protocols are secured while supporting the work and efforts of security
researchers.

I looked through several projects, glancing at their descriptions and
doing a very brief overlook of the project structure to determine my
interest. Then, I stumbled upon Premia Finance. When finding a new
project, I look at its documentation and get a bird’s-eye view of how
everything works and what the purpose of the protocol is. In this case,
it was an options-based market.

The first thing to look at is the project structure to determine certain
pieces of information:

  • Is the code original, or is it a fork? If the latter, is it altered
    fork code?

  • What is the topmost function being called by users? (Usually, these
    functions are external/public, but that’s not always the case as it
    could be called by another contract, so do due diligence with
    cross-referencing.)

  • Are there commonly shared implementations (ERC-20s, etc.)?

  • Are there custom implementations for things that have already
    established implementations (custom onlyOwner, nonReentrant,
    etc.)?

The Bug

After exploring the project, I came across a function called sendFrom
that is responsible for sending staked users’ tokens across chains.

A user can allocate allowance to another user such that they can manage
their tokens across chains. The function responsible for this in the
invocation of sendFrom is _debitFrom. The _debitFrom checks that
the user calling sendFrom has been allocated allowance from the from
address, and if that is the case, it then burns the tokens that are to
be sent across chains. Otherwise, it reverts.

function _debitFrom(
address from,
uint16,
bytes memory,
uint256 amount
) internal virtual override {
address spender = msg.sender;

if (from != spender) {
unchecked {
mapping(address => uint256)
storage allowances = ERC20BaseStorage.layout().allowances[
spender
]; // (1)

uint256 allowance = allowances[spender]; // (2)
if (amount > allowance) revert OFT_InsufficientAllowance();

_approve(
from,
spender,
allowances[spender] = allowance - amount
);
}
}

_burn(from, amount);
}

The issue arises in the allowance check — specifically the allowance
being checked. When simplified, the allowance being checked is
allowances[msg.sender][msg.sender] (see lines (1) and (2)). As a
result, any user can grant allowance to themself to arbitrarily cause
cross-chain transfers of other users’ tokens to an arbitrary address. In
conclusion, any user can steal any other user’s funds using cross-chain
transfers.

The Impact

At the time this vulnerability was discovered, there were three million
dollars’ worth of Premia tokens staked across multiple chains. All of
these staked tokens were at risk of being stolen.

The Fix

The function was fixed by properly retrieving the allowances variable
using the from address and not spender.

function _debitFrom(
address from,
uint16,
bytes memory,
uint256 amount
) internal virtual override {
address spender = msg.sender;

if (from != spender) {
unchecked {
mapping(address => uint256)
storage allowances = ERC20BaseStorage.layout().allowances[
from
];

uint256 allowance = allowances[spender];
if (amount > allowance) revert OFT_InsufficientAllowance();

_approve(
from,
spender,
allowances[spender] = allowance - amount
);
}
}

_burn(from, amount);
}

After this fix, if a malicious user were to supply a from address that
hadn’t granted allowance to them, the check would confirm this, as it
would then use the from address’s allowance and not the msg.sender’s
allowance.

Conclusion

We hope this was an interesting and informative read about the different
methods for finding targets, the advantages and downsides of certain
protocols/projects, the different sources to find said protocols, and an
example bug that we found.

This story aimed to help researchers optimize their bug-hunting process.
We encourage all security researchers to get out there — go secure
protocols in the wild!

Disclosure Timeline

  • 7/12/2023 — We get in touch with the Premia Finance team.

  • 7/13/2023 — They confirm the issue and start working on remediation.

  • 7/25/2023 — The bug bounty was rewarded.

  • 7/31/2023 — The bug is fixed, and the vulnerability can be
    disclosed.

A big thanks to the Premia Finance team for getting back to us quickly
and handling communications in a timely manner.

About Us

Zellic specializes in securing emerging technologies. Our security researchers have uncovered vulnerabilities in the most valuable targets, from Fortune 500s to DeFi giants.

Developers, founders, and investors trust our security assessments to ship quickly, confidently, and without critical vulnerabilities. With our background in real-world offensive security research, we find what others miss.

Contact us for an audit that’s better than the rest. Real audits, not rubber stamps.

*** This is a Security Bloggers Network syndicated blog from Zellic — Research Blog authored by Zellic — Research Blog. Read the original post at: https://www.zellic.io/blog/browsing-for-bugs-3m-bug-in-premia-finance