mercredi 12 juillet 2017

qemu ARM VM for [crackme|malware] analysis

My setup for ARM analysis

Once in a while, I have to analyze linux binaries in ARM architecture (in CTF, or crackme or when I got an ARM malware). There is many way to do it:

  • do static analysis only (good for crackme)
  • buy a raspberry pi (good for crackme)
  • buy an ARM machine somewhere in the cloud (well, never tried it, but why not)
  • use virtual machines 

I choose personnaly virtual machine over other solutions because of dynamic analysis, snapshots, the availabilty of it and the free as in free beer \o/

1/ qemu ARM on x86_64

When you want to emulate an arch, you think at qemu. So, installing qemu is as simple as download and compile it, or apt-get it:

mitsurugi@dojo:~$ dpkg -l | grep qemu-system-arm
ii  qemu-system-arm                           1:2.8+dfsg-5                         amd64        QEMU full system emulation binaries (arm)
mitsurugi@dojo:~$

and you're done.

2/ disk image

Next, you have to grab a linux distro. It's really faster to use a preinstalled image than installing from an iso. There is a lot of documentation which point to https://www.aurel32.net/info/debian_arm_qemu.php . This works, but I don't recommend it. The kernel and images are really old, and for my needs, gdb was too old. Use another image, decently recent. I recommend a raspbian image, really good for this usage.

I have scripts to automatize the process of downloading and configuring disk image for qemu-system-arm.

First, an a udev rule:

mitsurugi@dojo:~/chall/armv6_stretch$ cat 90-qemu.rules 
KERNEL=="sda", SYMLINK+="mmcblk0"
KERNEL=="sda?", SYMLINK+="mmcblk0p%n"
KERNEL=="sda2", SYMLINK+="root"
mitsurugi@dojo:~/chall/armv6_stretch$ 

And the script to get and create the disk image:

mitsurugi@dojo:~/chall/armv6_stretch$ cat get.sh 
#!/bin/bash
set -x
#wget http://xecdesign.com/downloads/linux-qemu/kernel-qemu
wget http://downloads.raspberrypi.org/raspbian_latest
wget https://github.com/dhruvvyas90/qemu-rpi-kernel/blob/master/kernel-qemu-4.4.34-jessie?raw=true
unzip raspbian_latest && rm raspbian_latest
loopdev=`sudo losetup -f`
img=`echo *.img`
offset=`file $img | grep -oh 'startsector [^,]*' | tail -n 1 | cut -d' ' -f2`
offset=$(($offset*512))
mntdir=mnt
sudo mkdir -p $mntdir
sudo chown root:root $mntdir
sudo losetup --offset $offset $loopdev $img
sudo mount $loopdev $mntdir
sudo bash -c "echo > $mntdir/etc/ld.so.preload"
sudo cp 90-qemu.rules $mntdir/etc/udev/rules.d
sudo umount $mntdir
sudo losetup -d $loopdev
qemu-img convert -O qcow2 -f raw $img raspbian.qcow2
rm $img
mitsurugi@dojo:~/chall/armv6_stretch$ 

Now you'll have a .qcow2 raspberry disk image and a linux kernel.
(those two scripts are slightly modified from http://xecdesign.com/ website, down at this moment)

3/ network setup

For my needs, I don't want to be bridged, I want to be able to firewall or block network access for the VM.
I don't want to use user-mode-nat, because firewalling can be too hard to put in place.
The good setup is TUN-TAP mode.

From the host, you have an interface tap0. The guest is connected to the host with this interface.
You can do your setup as you like, masquerade the guest to give internet access, firewall it, give static or dynamic addresse. Do as you want. I did a really simple setup (every docs on the internet overcomplicate this tasks).

First create your tap0 interface and give rights to your user, then configure it:

mitsurugi@dojo:~/chall/armv6_stretch$ cat config_ip.sh
echo "[+] Configuring interface"
sudo tunctl -t tap0 -u mitsurugi
sudo ifconfig tap0 172.16.42.42/24
mitsurugi@dojo:~/chall/armv6_stretch$ 

In the VM, configure the IP to be 172.16.42.222 or any IP in 172.16.42.X range.

This is really simple and powerfull because you can even configure a private IP address (if things are hardcoded in the binary you want to analyze) like

mitsurugi@dojo:~/chall/armv6_stretch$ sudo ifconfig tap0 8.8.8.8

and configure anything you need on the host side. I recommend dnsmasq which can act as a DHCP and DNS, with very little configuration. You can even lie to any DNS request you want, set up HTTP servers, ftp servers, mitm all the things \o/

4/ Command line to launch the image

The command line is:

mitsurugi@dojo:~/chall/armv6_stretch$ cat launch.sh 
#! /bin/bash
qemu-system-arm -cpu arm1176 \
                -m 256 \
                -kernel kernel-qemu-4.4.34-jessie \
                -M versatilepb \
                -append "root=/dev/sda2 rootfstype=ext4 rw console=ttyAMA0" \
                -hda raspbian.qcow2 \
                -net nic \
                -net tap,ifname=tap0,script=no,downscript=no $1
mitsurugi@dojo:~/chall/armv6_stretch$

Nothing fancy, you can't use more than 256M of RAM, and the net is made through tap, without any script (because you just configured it by yourself).

Be prepared for the first boot to configure a lot of things.

At first, use the qemu serial console (CTRL-ALT-3 when you see the strawberry logo on black screen) and log in. Why the serial console? Because you won't have any keyboard problem. The raspbian is configured to use QWERTY US keyboard. The serial console use your keyboard layout. The default login/pass is pi/raspberry http://elinux.org/R-Pi_Troubleshooting#Passwords  and you can use sudo to get root rights.

5/ First boot

Configure network, hostname, passwords, add a user, give root a password (eventually), d/l and configure all your analysis tools (gdbinit, scripts and so on), remove all the stuff you don't care about. And, reboot! Is everything OK? ssh works? Good!
You can forgot the CTRL-ALT-3 serial line and use ssh from now on.

Personnaly, I don't set up a default gw for the VM. This way, I'm almost sure than any malware I launch in it won't scan my internal network or the internet. This can be configured after on a case to case basis.

I set up the hostname as "router". If ever a malware would scan the hostname, it won't be an obvious name like "VM1" or "sandbox" or "analysis".

6/ Snapshotting for the win

The really good part about qemu is the -snapshot switch. This switch is made for a one-time snapshot. Whith it, anything is written on disk. When you poweroff the VM, every change made is lost. That's really, really good if you want to launch a malware. Even if this malware gain persistance to disk, modify files, or even trash your hard disk, it doesn't matter. Launch binary, look, modify things, trash VM, relaunch it. Very convenient. Don't forget to track and log every action in a scratchpad on your host because you can lost all of your work.

mitsurugi@dojo:~/chall/armv6_stretch$ ./launch.sh -snapshot
(do your stuff... Then halt the VM)

mitsurugi@dojo:~/chall/armv6_stretch$

The VM is in clean state. For me, that's the hugest win. No need to clean up tracks leaved by the malware, no need to reconfigure things. Reboot machine -> you're done. You can even hard stop it by closing the qemu windows.

Qemu has another option, with persistent snapshot. The disk image is used as a "base" image, and another file is used as a snapshot. This way, you can stop and reboot, any changes are stored in the snapshot file. If you want to restore the clean, initial state, just trash the snapshot file and launch qemu with the base image (see qemu documentation). I never had to use it.

99/ Conclusion

This setup will allow you to launch and analyze any ARM binary in a relative security. I'm not aware of any qemu escape ARM to x86_64, and the network setup allows you to easily block requests to the outside world and simulate all the things.