#NotPetya and #Petya compared: any hope for
decrypting files?
Positive
Technologies expert Dmitry Sklyarov provides here his comparison of NotPetya
ransomware, which attacked companies this week, with a sample of Petya from
2016. Is decryption of ransomed files possible? And what does the code tell us
about the malware's creation?
This post
considers the portions of the two viruses responsible for MFT encryption. This
encryption runs when the ransomware has administrator rights.
What NotPetya
does
At the
moment of infection (while Windows is still running), the virus writes code to
the start of the disk. This code will be run after restart. The virus writes its
configuration, verification data, and original MBR to certain sectors.
Let's start
by looking at disk sector 0x20, which is something like a machine-specific
configuration. During an infection, the following values are written to sector 0x20:
-
Indicator
that the MFT is not encrypted (value 0)
-
EncryptionKey
(random sequence 32 bytes long)
-
Nonce
(random sequence 8 bytes long)
-
Personal
Installation Key (random sequence of 60 characters from the following alphabet:
123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz)
Random data
is generated by the CryptGenRandom function, which is believed to be cryptographically
strong.
512 bytes
with the value 0x07 are written to sector 0x21.
A version of
the original MBR, in which every byte has been XOR’ed with the value 0x07, is
written to sector 0x22.
After the
initial restart, the MFT is encrypted. Before this happens:
-
Sector
0x20 is read
-
MFT
encryption indicator is set (value 1)
-
EncryptionKey
is copied to a temporary buffer
-
The
field with EncryptionKey is overwritten with null bytes
-
Sector
0x20 is written to disk
-
Sector
0x21 (all 0x07) is read
-
Contents
of that sector are encrypted using EncryptionKey + Nonce
-
Sector
0x21 is written to disk
Then the
MFT sectors are encrypted with the same EncryptionKey + Nonce. The code of the encryption
algorithm strongly resembles the Salsa20 algorithm, but there are some differences.
Instead of the constant "expand 32-byte k," the constant "-1nvalid
s3ct-id" is used. So far I have not been able to repeat the results of encryption
with a known key. Possibly the authors have made an error somewhere, which
would seem to be confirmed by this post: https://twitter.com/kryptoslogic/status/880058211516260352
When
everything is encrypted, the machine restarts again, and the ransomware appears
on screen requesting the decryption key.
The key is
supposed to be a 32-character string containing a combination of the following
characters: 0123456789abcdef. This string is run through a function that
accepts an arbitrary number of bytes as input, and outputs 32 bytes. Presumably
this is the SPONGENT hash function (to be confirmed). Then the output is fed
through the same function 128 times, which gives us EncryptionKey. To check
whether the key is valid, an attempt is made to decrypt the contents of sector 0x21,
and if the expected unencrypted text is found there (all 0x07), MFT decryption and
MBR restoration are started.
Can the attacker decrypt user files?
In my view,
the authors of NotPetya did not intend for files to be recoverable after
receipt of payment. Here's why:
1. The Personal Installation Key, which
needs to be given to the virus creators after paying the ransom, is not related
in any way to EncryptionKey. Both keys are random data. One key does not tell
us anything about the other key, unless the attackers have some special
knowledge about the workings of CryptGenRandom. Alternatively, the authors are
supposed to send both EncryptionKey + Personal Installation Key to their own server,
but nobody has reported such activity (and I have not seen such indications in
the code, although it cannot be ruled out).
2. If my guess about the SPONGENT hash
function proves correct, the decryption key is supposed to be the output of the
hash. In order to calculate a valid key, this hash would need to be reversed
(129 times), which is impossible with today's technology.
3. The entropy of EncryptionKey is 32*8
== 256 bits. The entropy of the hex key (entered by the user) is 32*4 == 128 bits.
Any operation can only reduce entropy. Therefore, 32 hexadecimal characters
cannot give us 32 bytes with definite values.
Differences from Petya (sample dated January 9,
2016)
Petya did
not want to infect my test machine. Maybe it requires a network connection or
something else—in any case, I had to do a memory dump.
I have not managed to review the code that generates the sectors used in the MBR set by Petya, but I did look at screenshots and the code run after restart.
Differences:
1. Sectors 0x36–0x39 are used (compare
to NotPetya: 0x20–0x23).
2. Most auxiliary functions (text
display, sector read/write) are identical to Petya.
3. Petya contains a function and
strings for displaying a skull-and-bones banner. NotPetya has a very similar function
but it is probably never called, and the strings have been zeroed out.
4. The length of the Personal Installation
Key is 90 characters (15 groups of 6 characters each) versus 60 in NotPetya. Using
an alphabet of 58 characters, a maximum of 527 bits of information can be so
conveyed (versus 351 in NotPetya).
5. The Petya dump shows strings secp256k1
and secp192k1, which might mean that the Personal Installation Key is derived
from EncryptionKey, and is calculated using elliptic-curve cryptography.
6. The user-entered key to start decryption
should be a 16-character string from the following alphabet: 123456789abcdefghijkmnopqrstuvwxABCDEFGHJKLMNPQRSTUVWX.
7. Nothing resembling SPONGENT (or any
other hash) is found.
8. Salsa20 uses the original constant "expand
32-byte k." The code of the functions is nearly identical, and while the
Petya code was likely generated by a compiler (optimization was applied to
repeating characters), it seems that in NotPetya, the constants were simply replaced.
Petya:
NotPetya:
The
evidence, in my view, suggests that another strain of Petya existed, and after replacing
constants and strings, that it was used to create NotPetya.
Again, I do
not believe that NotPetya was intended to support decryption of victims' files,
while Petya did in fact have such functionality. Disk recovery may still be an
option, however. Both viruses have similar errors in the implementation of encryption
algorithms, which could make it possible to quickly brute-force an encryption
key to recover all encrypted data. Back in 2016, researchers described a method for recovering Petya-encrypted data
without paying a ransom.
UPD
NotPetya: MFT encryption code
NotPetya: MFT encryption code
Origins
Among the
versions of Petya encountered in 2016—with their different colors (1, 2), "duet" with mischa ransomware, and
this form as well—it is worthwhile to look at
PetyaGoldenEye.malware,
which was first uploaded to VirusTotal last December.
The code
that NotPetya writes to the beginning of a disk, as well as
the code run from the MBR, is extremely similar to the code written by PetyaGoldenEye:
SHA256: b5ef16922e2c76b09edd71471dd837e89811c5e658406a8495c1364d0d9dc690.
Differences
we found in NotPetya compared to PetyaGoldenEye:
- Many text strings have been changed (the ransom demand has been corrected and the skull picture has been removed).
- Offsets for several strings have been changed (message size changed, requiring that the beginnings of the strings be repositioned).
- In the function at address 0000:86E0, a piece of code jumps around (and is never run); this code is responsible for displaying a banner (flashing skull and crossbones) before any key is pressed.
- The banner color has been changed from yellow (0xE) to red (0xC), although the banner is not displayed.
- At address 0000:848E, a function call has been removed and replaced by three NOP instructions. The function is responsible for clearing the keyboard buffer (which is no longer necessary, since keystrokes are not anticipated).
- In the function at address 0000:96D4 (expand for Salsa20), the initial state of the string has been changed from "expand 32-byte k" to "-1nvalid s3ct-id".
- In the function at address 0000:998E (permute for SPONGENT), the initial value of LFSR (linear-feedback shift register) has been changed from 0x9E to 0xA3.
No other
changes in the code were found.
Cryptography
SPONGENT hash function
We believe
that code for implementing SPONGENT was taken from here. We can easily make that code equivalent
to what we see in NotPetya: in the permute() function, replace the initial value of the lfsr variable and rewrite the spongent() function so that it takes an array
pointer and array length as input, instead of a null-terminated string.
Notably, the
initial value of LFSR == 0x9E (as described in the original specification for SPONGENT-256/256/16)
yields 140 rounds, but the initial value 0xA3 used in NotPetya results in 152 rounds,
slightly increasing cryptographic robustness.
Salsa20 encryption
function
The code
for implementing Salsa20 was likely taken from here. By replacing the "o"
array value in the function s20_expand32() and replacing the body of the function s20_littleendian() with the string return
*(__int16*)b; we get code
equivalent to that used in NotPetya.
Because of
incorrect implementation of s20_littleendian() (most likely, due to incorrect typing or
16-bit compiler error), two of each four bytes in the keystream array are not used at all. In
effect, this makes the encryption key 128-bit, instead of 256-bit (halving its
robustness). However, bruteforcing the entire 128-bit key space is still
unrealistic with today's technologies.
Conclusions
The
creators of Petya implemented MFT encryption using robust (although uncommon) cryptographic
primitives for which they used code from GitHub repositories.
Errors in the first version of Petya (Petya Red) made
it possible to decrypt data without paying a ransom.
Later
versions (Petya Green, PetyaGoldenEye) corrected many of these mistakes,
leaving only the type conversion error that halved the effective key length
used for encryption. Attempts to take advantage of this weakness in Petya Green were unsuccessful.
The most
likely scenario is that the creators of NotPetya did not have access to the Petya
sources, and could not make necessary changes to them and recompile the
project. Instead, they based NotPetya on existing code from PetyaGoldenEye, which
they analyzed with a disassembler, and made changes using a hex editor.
Efforts to
find ways to recover files encrypted by NotPetya are still ongoing.
No comments:
Post a Comment