
Reversing the Petya ransomware with constraint solvers - ingve
http://0xec.blogspot.com/2016/04/reversing-petya-ransomware-with.html
======
musesum
Well, since we're talking about 16 bit software ...

In 1991, my company was sandboxing commercial software. This was for try-
before-you-buy. Except, instead of recompiling a crippled version, we would
take a retail SKU, encipher the executables and then deliver with a device
driver: a VxD. The VxD would hook the low level Int13 IO calls to pass all
disk IO through a write-through cache. The installed app could read from
anywhere on the disk. But, all attempts to write would copy the changed
sectors to the cache. This would allow a perfect uninstall; simply remove the
cache and the disk reverts back to its preinstalled state. This was because
most software, back in 1991, assumed that you'd never want to uninstall. So,
it would scatter its junk all over the place.

Now imagine if the VxD was part of the OS. Any downloaded exe could access the
HD, but all writes would write-through to a separate cache. That was 25 years
ago. This is a roundabout way of asking: how feasible is sandboxing to avoid
malware?

~~~
geofft
The Linux machines in MIT's computer labs do essentially the same thing. Right
after you log in, there's a wrapper around your entire X session that union-
mounts a tmpfs on top of the root filesystem, puts you in that chroot, and
gives you root. It's not secure against active malice (and not intended to be,
since you have physical access to the machine), but it lets people run `sudo
pip install` or `sudo npm install -g` or `sudo make install` or whatever, and
it only stays around until they log out.

The trouble with root access is that there's always a way for active malice to
get in. For instance, our approach is trivially vulnerable to loading a kernel
module. It's possible that something like user namespaces would solve that
today.

~~~
marmight
Are you sure it's not even more trivially vulnerable than that? From man 2
chroot:

 _This call does not change the current working directory, so that after the
call '.' can be outside the tree rooted at '/'. In particular, the superuser
can escape from a "chroot jail" by doing:_

 _mkdir foo; chroot foo; cd .._

~~~
andrewchambers
you have misunderstood what you are reading. man 2 is the library doc not the
chroot program, this page is just reminding people to cd into the root
otherwise they will be vulnerable.

~~~
marmight
You're right insofar as you can't use the chroot command to escape a "chroot
jail" because it automatically calls chdir() for you, but any root user can
escape one by invoking the following linux system calls:

    
    
      chdir("/"); /* go to / of "chroot jail" */
      mkdir("foo", ...); /* create directory in jail */
      chroot("foo"); /* change / to foo */
      /* fail to chdir("foo"); */
      chdir(".."); /* instead go up parent (there is nothing preventing you since you are no longer in the "chroot jail" since the jail is now foo and you never entered it) */
      chdir("..");
      /* ... */
      chdir(".."); /* . is now the real root */
      chroot("."); /* change / to the real root */
    

This is why the man pages for the linux system call rightfully put "chroot
jail" in scare quotes. They are trivially escaped by a root user making basic
linux system calls, and the man pages even sketch out how for you. Some
operating systems attempt to provide more secure chroot jails, but linux
chroot() does not provide this.

~~~
comex
> Some operating systems attempt to provide more secure chroot jails, but
> linux chroot() does not provide this.

Note that this includes Linux itself with CLONE_NEWNS + pivot_root (which is
what Docker does).

~~~
geofft
Oh! I didn't know Docker used pivot_root, and I was always curious why that
call and chroot() both existed. This makes some sense.

------
vizzah
Maybe I am too old school, but I can't understand how all these fancy
'constraint solvers' (and in another solution, definitions akin to genes and
chromosomes (hair raising)
[https://news.ycombinator.com/item?id=11474613](https://news.ycombinator.com/item?id=11474613))
are helping to write a standard brute-forcer for the flawed algorithm? Are
these solvers doing anything more intelligent??

~~~
rurban
Solvers don't do brute force at all. Otherwise you wouldn't come up with ways
to crack crypto. Solvers work with SAT and SMT languages, which means purely
logical and extended to simple words and bitarrays, and the solvers mentioned
there (cbmc is also in this league), can solve normal programming logic
backwards.

Means you assert a result on a variable at the end, specify which variables
and states will affect the wanted result, and the framework and solver will
efficiently backtrack all the possible solutions of input variables to come up
to your desired endstate, by filtering out impossible paths and values. Like
in a game.

Z3 is very popular, because you can write your problem in python. Ages ago
lisp was very popular, and some of the very first lisp programs from the 60ies
were such solvers (general planner) leading to AI. And recently with the
implementation of efficient simple open-source SMT solvers (minisat, ...)
implemented within gcc or llvm you can now even use normal C programs and
backtrack results, optimize and check types, do bounds checking, generate
tests from bugs and so on. This is not comparable to simple fuzzing or brute-
forcing, it knows the program flow, and works the flow backwards.

~~~
vizzah
Thanks for explaining! I just can't understand how such 'solvers' can help
with crypto, when strong crypto-algos are not reversible and hence there is no
point to approach them backwards?

If any algorithm can be weakened by such 'problem solvers', it wouldn't be
considered strong? For instance, can SHA256 be reversed (i.e. collision found)
faster with such a solver? I guess not..

I realize that with crypto, solvers can optimize the flow of the algorithm,
make it more efficient and omit repeating some code parts, but a good
bruteforcer written in assembly can be as optimized..?

~~~
wrs
Crypto algorithms are deterministic, and therefore reversible. Solvers would
work with any crypto, it's just that with normal crypto your computer would
degrade to dust before they had time to finish. This was breakable because the
Salsa algorithm was processing 16 bits instead of 32, which makes the set of
possible earlier states astronomically smaller.

~~~
floodyberry-
A "properly" implemented 16 bit Salsa20 would have 64/128 bits of key, which
would still take a very long time to break. The reason _this_ implementation
was broken (assuming the referenced snippet [1] is accurate) is the rotl
function and the rotation values. The shifts are being calculated for 32 bits
but are being used with 16 bit values. Instead of all 16 bits being rotated
and used, half the shifts result in 0 while the others affect only a handful
of high bits, which means there is very little diffusion going on.

[1]: [https://gist.githubusercontent.com/extremecoders-
re/499d4617...](https://gist.githubusercontent.com/extremecoders-
re/499d461753b50998f81c9011895f10fe/raw/49cd11f2e82767ab0df04f04506feb60c63d919b/borkedsalsasnip.c)

------
sillysaurus3
_Searching for "expand 32-byte k" would directly lead you to Salsa. The exact
code used in the malware can be found here. I am using the word exact in a
broad sense. If it had been a ditto copy, we would have no chance of breaking
it. The original Salsa implementation uses 32 bit (uint32_t) variables. This
salsa implementation uses 16 bit variables for the same purpose borking it
badly._

:)

The author made it look so easy to reverse this. Kudos, and thanks for the
community service.

------
jwilk
[https://news.ycombinator.com/item?id=11474613](https://news.ycombinator.com/item?id=11474613)

~~~
tomsmeding
Yes, thought of this too. Wonder if there's a difference in the versions they
analysed (and broke).

------
ZoF
This is awesome; funny that having Windows XP actually protects you from
ransomeware in this case.

~~~
ams6110
So does not having Windows at all (at least for this ransomware).

~~~
ZoF
Yes, but that's not explicitly mentioned in the article and is expected given
that it's targeting a specific platform. You could say the same of OSX.

fwiw I've been using various flavors of linux for years(CentOS/Arch/FreeBSD
lately) for everything but a single dev laptop I keep Windows for
testing/native apps.

My comment wasn't meant to be advocating Windows, let alone XP, I just thought
it was funny.

------
aab0
So is this a case of 16-bit keys being easy to bruteforce and even easier to
use a symbolic solver on, or is there something more subtle going on?

~~~
ExtremeCoders
This is not bruteforce. The flaw is the attackers used the same crypto
algorithm but with smaller width variables. This rendered some of the crypto
useless. Half of the total bytes in the keystream are always null and
correspondingly half of total bytes in the ciphertext retain their original
value. always Even with 16-bit variables proper implementation would have made
this a lot tougher.

As they say, Don't' roll your own crypto.

~~~
userbinator
_As they say, Don 't' roll your own crypto._

I have a feeling the malware author, working in 16-bit realmode, forgot that
ints are usually 16 bits wide in that environment. A "typedef unsigned int
uint32_t" behaves as expected in the usual 32/64-bit environment, but not in
16-bit. It's unlikely the author invented the 16-bit Salsa20 variant, but
rather copied existing code and just compiled it wrongly.

------
userbinator
_Instead it encrypts the MFT (Master Partition Table) on NTFS volumes_

I wonder what happens with FAT32, or does it just do a stupidly simple
"encrypt the first _n_ sectors of the disk"?

------
DblPlusUngood
I find it extremely amusing that after going through all the trouble of
building the malware+infrastructure to sell keys, the authors couldn't be
troubled to write the 5 lines of assembly code to enter protected mode. You
can even leave paging off!

~~~
a1k0n
You don't even need to be in protected mode to use 32-bit registers. You can
sort of bounce in and out just enough to use them with the 66 prefix. I used
to do that but it's been so long I forgot how.

~~~
commentereleven
I think you're talking about unreal mode.

[http://wiki.osdev.org/Unreal_Mode](http://wiki.osdev.org/Unreal_Mode)

~~~
a1k0n
That's right, I was, but on further reflection you don't need to do anything
special in this case since it's just doing 32 bit math, not 32 bit addressing.
EAX/EBX/etc should just work in real mode IIRC.

------
13of40
Regarding the 'expand 32-byte k' part: I've seen other malware that obfuscates
its strings that way, by writing them into a buffer using one instruction per
character, so you can't retrieve them with a simple 'strings' command. The
thing that bugs me is they've gone to that length to hide the string, but they
didn't randomize the order of the instructions, and as a result you can
trivially retrieve the string with your disassembler.

