Postmortem of Monero CCS Hack: A Transaction Graph Analysis

On September 1st, 2023, an attacker swept the balance of the Monero CCS Wallet containing 2675.73 XMR in nine transactions, according to the incident disclosure.

Moonstone Research decided to investigate how the attacker moved these funds, and in doing so, we discovered some interesting results. Most notably, we were able to reliably trace forward through three of the attacker's transfers. This report shows the information that we have learned in the first 24 hours of our investigation. Our knowledge should improve over time.

Starting Transactions

Unfortunately, we did not have the luxury to narrow down enotes in this case, since the attacker reportedly spent funds from a different wallet. Since we had no transaction key and destination address for these nine transfers, we needed to assume that any of the enotes generated in these initial withdrawal transactions could be held by the attacker. There were no change enotes back to the Monero CCS wallet.

Here are the nine transactions that we started with:

Transaction ID Number of input enotes Number of output enotes Block height
ffc82…bc56a 33 2 2965023
08487…b90cc 146 2 2965023
4b73b…868a9 146 2 2965024
8a5ed…c1441 146 2 2965024
56dd0…89e2c 146 2 2965024
e2ab7…f73db 146 2 2965025
9bf31…16b6b 146 2 2965025
837de…7ff6a8 146 2 2965026
9c278…e29f4 146 2 2965026

First Crescent Discovery Report

We thus entered the following nine transactions into our Crescent Discovery scanner to make a Crescent Discovery Report. The unfiltered transaction graph (which is a part of the full report) was messy due to the number of enotes involved (18).

Unfiltered transaction graph

When we filtered out transactions with only one matching enote, we found an obvious lead: bb77d…d1a58.

Filtered transaction graph

This transaction uses seventeen input enotes and creates eleven output enotes. We observe the following nine poisoned enotes in the transaction's rings, each from unique origin transactions:

Ring index Poisoned enote Poisoned enote origin transaction
1 43b81…e9d44 9bf31…16b6b
2 42baa…e432d 8a5ed…c1441
3 f7b8a…cf5f3 ffc82…bc56a
4 1cc55…1cf40 56dd0…89e2c
9 6a700…16d0b 4b73b…868a9
10 5d6d…c85af 9c278…e29f4
11 2747…f2ece 837de…ff6a8
12 00b6…2e23d 08487…b90cc
14 759e…b9429 e2ab7…f73db

Due to the way Monero decoys are selected, it is extremely unlikely that this transaction was created by any person other than the attacker.

The true spends of rings 1, 2, 3, 4, 9, 10, 11, 12, and 14 should now be known. This accounts for all nine attacker transactions. We do not know what funds were spent in the rings 0, 5, 6, 7, 8, 15, 16. One future area of research should be to investigate these rings backward to see if we can deduce any previous transaction origins for these other funds. We did not do this for this initial analysis, but we will conduct this research later. Moonstone Research supports analyzing transactions both forward and backward.

Ring index Poisoned enote
0 e33c8…9b026
5 aa810…73782
6 a634e…b1bcd
7 9629c…67de7
8 9588c…56930
15 28ccc…2f7c8
16 05574…f071f

If we assume that this is a PocketChange transaction, then that would imply that one of these eleven outgoing enotes went to a counterparty, and ten were returned as change. However, it's possible that the user sent the funds to themself, in which case all eleven output enotes would be change.

There are other leads that could have spent some of the funds from the nine originating transactions, but they are less likely. Transactions with several matches are common when we do not have the ability to narrow down which enotes were received.

Transaction ID Number of matching enotes Reasoning why this is probably a false positive
32baf…e12cd 4 Massive number (99) of rings in this transaction
f6efe…db103 2 Only two matches, which is statistically common in this case
7486d…a0efc 2 Only two matches, which is statistically common in this case
968a2…55706 2 Only two matches, which is statistically common in this case
9e4e7…be06f 2 Only two matches, which is statistically common in this case
17e50…d8d72 2 Only two matches, which is statistically common in this case

Second Crescent Discovery Report

With the excellent transaction lead bb77d…d1a58, we made a new Crescent Discovery Report using the eleven outputs from this transaction. There were two candidates with more than one match:

Transaction ID Number of matching enotes
2c5b4…ad5ec 6
06550…ca47b 2

We initially focused on 2c5b4…ad5ec because it had the most matches, shown below:

Ring index Poisoned enote
0 2de84…49e53
1 d408a…6f6f1
3 6e4f8…997db
4 0a897…beaed
5 bafce…54fde
6 5d904…66075

Third and Fourth Crescent Discovery Reports

All rings except for ring 2 are accounted for. However, we decided to generate a Crescent Discovery Report with both 2c5b4…ad5ec and 06550…ca47b as origin transactions to see if any additional transaction graph information was revealed. Sure enough, we found that the poisoned enote 8949a…d4277 from ring 2 of transaction 2c5b4…ad5ec was created in transaction 06550…ca47b. Thus, we have accounted for all seven rings.

We then ran one last Crescent Discovery Report that analyzed the relationships between all these transactions.

Final Monero transaction graph

With this fourth Crescent Discovery Report, we are able to trace forward three attacker transactions with high accuracy. The most likely timeline appears to be:

  1. The attacker drained the Monero CCS wallet in nine transactions.
  2. The attacker sent XMR to a counterparty, a service, an exchange, or themself in transaction bb77d…d1a58 using Monerujo PocketChange.
  3. The attacker sent XMR to a counterparty, a service, or an exchange in transaction 06550…ca47b.
  4. The attacker sent XMR to a counterparty, a service, or an exchange in transaction 2c5b4…ad5ec.

Missing Funds

We were able to account for the majority of enotes, but some are not accounted for. In transaction bb77d…d1a58 with elevent output enotes, we are able to find clear future transactions for eight of these output enotes. We are most likely not accounting for a counterparty output enote and two change output enotes. There are no clear leads for these three output enotes. This may change as we spend more time on the investigation.

We can not yet account for enote 1aec8…fb136 created in transaction 06550…ca47b. This is likely a change output enote to the sender, so they may use it later. Alternatviely, it could be a 0-value output enote, though we do not think this is likely.

We can not yet account for output enotes from the transaction 2c5b4…ad5ec.

Exchange Deposits?

All Monero exchanges and services should check to see if they received the following transactions, which were very likely to have been sent by the original attacker:

bb77d03cae08942f43cccd759ade505a1c9435470a4a2cabfa5e26d2c93d1a58
06550272cdfa1eea98d288b2d57c272b5c52a2b195b4f808c8c03422a58ca47b
2c5b45bf398dcae482019a46fb2d06d334bf4260484dc4857fc35db3689ad5ec

If you received these transactions, please contact info@MoonstoneResearch.com. We can help advise you on the next steps.

If you are a Monero community member, please reach out to all exchange parties you can think of, including instant exchangers, to see if they received deposits in these transactions.

User of Monerujo PocketChange

It is peculiar that a user who otherwise created transactions with exactly two output enotes (which is normal for Monero transactions) created an initial merging transaction with elevent output enotes.

Transactions with an atypical number of output enotes occur for a variety of reasons, but these are almost always anchored in some specific use-case. For example, transactions with multiple output enotes might be sent by an exchange to multiple of their customers who wish to withdraw. However, transactions with more than two output enotes are probably not destined as an exchange or instant exchange deposit, since there is only one recipient.

Monerujo is an Android non-custodial Monero wallet. They offer a feature called PocketChange, which aims to mitigate a disadvantage of Monero by creating multiple "pockets" (enotes), which can then be spent in several scenarios without waiting for Monero's ten block lock. The Monerujo team states:

As long as [PocketChange is] enabled, every time you use Monerujo to send moneros somewhere, it will take a bigger coin, split it in parts, and spread those smaller coins into 10 different pockets. That way, the coins won’t merge again, and you’ll be ready to spend instantly from all those pockets without waiting the dreadful 20 minutes.

Monerujo published an update for a more sophisticated version of PocketChange in late August 2023. Transaction bb77d…d1a58 occured on September 2nd, 2023. Instead of always maintaining exactly ten pockets, Monerujo 3.3.8 will now try to maintain a minimum of six and a maximum of fourteen.

Moonstone Research believes that the attacker is most likely a Monerujo wallet user who had PocketChange enabled. We think it is unlikely that an attacker would otherwise create a transaction with eleven output enotes. We believe this is the most likely case, regardless if the attacker was using Monerujo version 3.3.7 or 3.3.8.

In theory, the transaction bb77d…d1a58 could have been a payment to multiple threat actors batched together, but we do not believe this is the case due to the future merging of enotes. If different threat actors received one output enote each in this transaction, then we should not expect to see the future merging that was observed.

Moonstone Research believes that transaction bb77d…d1a58 was sent by the attacker to some other counterparty. One of these eleven output enotes went to the counterparty, and ten output enotes returned to the wallet. It is also possible that the user performed a "churn" transaction here to themself, though using churning with PocketChange would not be performed by an intelligent actor.

About Monero Tracing

Monero tracing is not deterministic in the same way that Bitcoin and Ethereum tracing often is. Monero transactions purposefully impose complexity to their transaction graphs, leading to false positives and ambiguity.

Moonstone Research tools investigate Monero transaction graphs and use heuristics to track funds. These heuristics are subject to errors. Transaction graph analysis is a useful tool, though it should be used alongside other evidence in investigations.

About Moonstone Research

Moonstone Research is a boutique blockchain analysis firm that investigates difficult-to-trace transactions. We specialize in tracing ransomware and other illicit payments. We also assist compliance professionals with supplementary investigations and reporting. We can help recover stolen funds. Please email us if you would like to get in touch.