이 정보는 Ubuntu 16.04 환경에서 실행 중인 바이너리(binary)의 보안 속성과 메모리 구조를 분석한 결과입니다. 아래에 각 항목의 의미와 보안에 미치는 영향을 설명하겠습니다.
1. Arch: i386-32-little
- 설명:
- 바이너리는 **32비트 아키텍처(i386)**에서 실행되며, 리틀 엔디안(Little Endian) 형식으로 데이터를 저장.
- 리틀 엔디안: 데이터의 가장 낮은 바이트가 메모리의 가장 낮은 주소에 저장되는 형식.
- 영향:
- 32비트 아키텍처에서는 메모리 주소 범위가 4GB로 제한되며, 보안 기능도 64비트보다 덜 강력.
- 리틀 엔디안은 대부분의 x86 프로세서에서 기본적으로 사용.
2. RELRO (Relocation Read-Only)
- 설명:
- RELRO는 실행 시점에 재배치 가능한 데이터(예: GOT, Global Offset Table)를 읽기 전용으로 변경하여 악용을 방지하는 보안 기술.
- 결과에 "No RELRO"로 표시된 것은, 이 바이너리가 RELRO 보호를 사용하지 않음을 의미.
- 영향:
- 공격자가 GOT를 수정하는 GOT overwrite 공격에 취약.
- 권장 설정은 Partial RELRO 또는 Full RELRO.
3. Stack: No canary found
- 설명:
- **스택 카나리(Stack Canary)**는 스택 오버플로우 공격을 방지하기 위해, 스택 프레임에 무작위 값(Canary)을 삽입하는 보안 기술.
- "No canary found"는 이 바이너리가 스택 카나리를 사용하지 않음을 의미.
- 영향:
- 공격자가 스택 오버플로우를 이용하여 반환 주소를 덮어쓰는 ROP(Return-Oriented Programming) 공격에 취약.
4. NX (Non-Executable Stack)
- 설명:
- NX(No-eXecute)는 스택, 힙과 같은 메모리 영역에서 실행을 방지하는 보안 기술.
- "NX enabled"는 이 바이너리가 NX 보호를 활성화하여, 실행 가능한 페이로드를 스택이나 힙에 삽입하는 공격을 방지한다는 의미.
- 영향:
- NX 보호 덕분에 스택 기반 쉘코드 공격이 더 어려워짐.
- 그러나 ROP 공격 같은 기술로 우회 가능.
5. PIE (Position Independent Executable)
- 설명:
- PIE는 바이너리를 실행 시 마다 무작위 메모리 주소에서 로드하여 메모리의 레이아웃을 예측하기 어렵게 만드는 기술.
- "No PIE"는 이 바이너리가 **고정 주소(0x8048000)**에서 로드된다는 의미.
- 영향:
- 메모리 주소가 고정되어 있으므로, 공격자가 바이너리의 함수나 변수를 악용하기가 쉬움.
- 권장 설정은 PIE 활성화.
종합적인 보안 평가
- 이 바이너리는 여러 보안 기능이 부족하여 익스플로잇에 취약합니다:
- No RELRO: GOT overwrite 공격 가능.
- No canary: 스택 오버플로우 공격 가능.
- No PIE: 메모리 레이아웃 예측 가능.
- NX enabled는 쉘코드 실행을 일부 방지하지만, ROP 공격은 여전히 가능.
보안 개선 방법
- RELRO 활성화:
- 컴파일 시 Partial RELRO 또는 Full RELRO 설정.
- 예: gcc -Wl,-z,relro,-z,now
- 스택 카나리 추가:
- 컴파일 시 -fstack-protector 또는 -fstack-protector-strong 플래그 추가.
- PIE 활성화:
- 컴파일 시 -fPIE와 -pie 플래그 사용.
- 정적 분석 및 취약점 점검:
- 바이너리를 실행하기 전에 AddressSanitizer 같은 도구로 테스트.
결론
- 이 바이너리는 기본적인 보안 설정이 부족하여 취약점이 많습니다.
- 이러한 분석 결과는 익스플로잇 연구를 위한 기반 정보를 제공하거나 보안 강화를 위한 기준점으로 사용됩니다. 추가 질문이 있다면 언제든 물어보세요! 😊
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
FILE *fp;
struct my_page {
char name[16];
int age;
};
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);
}
int main()
{
struct my_page my_page;
char flag_buf[56];
int idx;
memset(flag_buf, 0, sizeof(flag_buf));
initialize();
while(1) {
printf("1. Join\n");
printf("2. Print information\n");
printf("3. GIVE ME FLAG!\n");
printf("> ");
scanf("%d", &idx);
switch(idx) {
case 1:
printf("Name: ");
read(0, my_page.name, sizeof(my_page.name));
printf("Age: ");
scanf("%d", &my_page.age);
break;
case 2:
printf("Name: %s\n", my_page.name);
printf("Age: %d\n", my_page.age);
break;
case 3:
fp = fopen("/flag", "r");
fread(flag_buf, 1, 56, fp);
break;
default:
break;
}
}
}
이 코드는 간단한 C 프로그램으로, 사용자와의 입력-출력을 통해 이름과 나이를 입력받아 출력하거나, 특정 조건에서 /flag 파일을 읽는 동작을 수행합니다. 다음은 코드의 주요 요소와 동작에 대한 상세 설명입니다.
1. 주요 구조 및 초기화
(1) struct my_page
- struct my_page는 사용자 정보를 저장하기 위한 구조체입니다:
struct my_page { char name[16]; // 이름을 최대 15자까지 저장 (+1은 NULL 종료) int age; // 나이 저장 };
(2) flag_buf
- 길이 56의 버퍼로, /flag 파일의 내용을 읽어 저장하기 위해 사용:
char flag_buf[56];
(3) initialize 함수
- 프로그램의 환경을 초기화합니다:
- 버퍼링 비활성화: 입력과 출력에서 버퍼링을 제거하여, I/O가 즉시 실행되도록 설정.
- 타이머 설정: 30초 안에 입력을 완료하지 않으면 프로그램이 종료.
void initialize() { setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); signal(SIGALRM, alarm_handler); alarm(30); }
(4) alarm_handler
- 30초 타이머가 만료되면 호출되는 함수로, 프로그램을 종료합니다:
void alarm_handler() { puts("TIME OUT"); exit(-1); }
2. main 함수의 동작
(1) 사용자 메뉴 제공
- 프로그램은 루프를 통해 반복적으로 메뉴를 출력하고 사용자 입력을 처리합니다:
printf("1. Join\n"); printf("2. Print information\n"); printf("3. GIVE ME FLAG!\n"); printf("> "); scanf("%d", &idx);
(2) 메뉴 동작
- 1번 (Join):
- 사용자 이름과 나이를 입력받아 구조체에 저장.
- 이름은 read()로 입력받아 크기를 제한.
- 나이는 scanf()로 입력받음.
case 1: printf("Name: "); read(0, my_page.name, sizeof(my_page.name)); printf("Age: "); scanf("%d", &my_page.age); break;
- 2번 (Print information):
- 입력받은 이름과 나이를 출력.
case 2: printf("Name: %s\n", my_page.name); printf("Age: %d\n", my_page.age); break;
- 3번 (GIVE ME FLAG!):
- /flag 파일을 열어 읽고, 내용을 flag_buf에 저장.
- 파일의 최대 길이 56바이트를 읽음.
case 3: fp = fopen("/flag", "r"); fread(flag_buf, 1, 56, fp); break;
- 기타 입력:
- 아무 작업도 수행하지 않고 루프를 계속 진행.
3. 잠재적 보안 문제
(1) 이름 입력의 버퍼 초과 가능성
- read()로 이름을 입력받을 때, my_page.name 크기를 초과하면 버퍼 오버플로우가 발생할 수 있습니다.
read(0, my_page.name, sizeof(my_page.name));
- 입력 크기를 명확히 제한하지 않으면, 이후 메모리 영역을 덮어쓸 위험이 있습니다.
(2) /flag 파일 접근
- /flag 파일의 내용을 읽는 기능은 일반적으로 제한되어야 하지만, 접근 제한이 없으므로 이를 악용할 가능성이 있습니다.
- fread()로 읽은 내용을 출력하지 않기 때문에, 입력 조작(익스플로잇)을 통해 메모리 내 flag_buf 값을 유출할 가능성이 있습니다.
(3) RELRO가 비활성화된 환경에서의 위험
- 코드 분석 결과 "No RELRO" 및 "No canary found"와 같은 설정에서는 익스플로잇을 통한 추가적인 메모리 조작 가능성이 존재.
4. 익스플로잇 가능성
목표: /flag 파일의 내용을 확인.
- 입력 크기를 초과하여 버퍼 오버플로우를 유도.
- 메모리 조작으로 /flag 파일의 내용을 외부로 출력.
단계:
- 입력 초과 유도:
- my_page.name에 16바이트를 초과하는 데이터를 입력하여, 인접 메모리 영역(flag_buf)에 영향을 미침.
- /flag 데이터 유출:
- 입력값을 조작하여 프로그램의 동작을 변경.
- 예: printf() 등의 동작을 유도해 flag_buf 출력.
5. 개선점
(1) 입력 검증
- 이름 입력에서 정확한 크기 제한 추가:
read(0, my_page.name, sizeof(my_page.name) - 1);
(2) 민감 데이터 보호
- /flag 내용을 메모리에 저장하지 않고, 읽은 후 바로 출력하거나 처리.
(3) 보안 옵션 추가
- 컴파일 시 RELRO와 스택 카나리 활성화:
gcc -Wl,-z,relro,-z,now -fstack-protector-strong -o program program.c
6. 결론
이 코드는 보안적으로 취약한 부분이 있으며, 특히 버퍼 오버플로우와 /flag 접근 기능이 익스플로잇의 대상이 될 가능성이 큽니다. 이러한 문제를 해결하려면, 입력 검증과 보안 강화 컴파일 옵션을 추가해야 합니다.
문제코드를 보면 my_page 구조체 변수와 flag_buf가 있는데case 1에서는 my_page의 구조체의 값들을 입력받고
case 2에서는 my_page의 구조체의 값들을 출력해준다
case 3에서는 flag_buf에 flag값을 넣어준다
my_page의 구조체중 name에서는 20만큼 입력을 제한하고
age에서는 입력에 제한이 없기 때문에 age를 이용할 수 있다
출처 ㅣhttps://stfofu.tistory.com/48
case 2:
printf("Name: %s\n", my_page.name);
printf("Age: %d\n", my_page.age);
break;
%s은 null을 만나기전까지 모두 출력해준다 따라서 0이 없도록 buf와 v5를 모두 채워주면3번 메뉴에서
s에 flag를 넣고 2번 메뉴에서 flag까지 출력되도록할수있다
출처ㅣ https://koharinn.tistory.com/257
이번 문제는 memory_leakage를 사용하여 플래그를 획득하는 문제입니다. case 1에서는 my_page.name에 최대 16바이트 크기의 입력값을 입력하고 my_page.age에 정수를 입력합니다. case 2에서는 저장된 변수를 출력합니다. case 3에서는 flag 값을 flag_buf에 저장합니다.
문제 풀이 동작은 다음과 같습니다. case 2의 printf("Name: %s\n", my_page.name);에서 %s는 널 바이트가 나올 때 까지 문자를 출력합니다. 하지만 case 1의 read(0, my_page.name, sizeof(my_page.name));에서는 16바이트 만큼의 문자를 입력받을 수 있으므로 my_page.name의 마지막 문자에 0이 아닌 다른 문자가 존재하면 널 바이트가 나올 때 까지 쓰레기 값을 출력하게 됩니다.
출처 ㅣhttps://lemon-soju.tistory.com/52
disassemble main 하러 가보자
(gdb) disassemble main
Dump of assembler code for function main:
0x080486eb <+0>: lea 0x4(%esp),%ecx
0x080486ef <+4>: and $0xfffffff0,%esp
0x080486f2 <+7>: push -0x4(%ecx)
0x080486f5 <+10>: push %ebp
0x080486f6 <+11>: mov %esp,%ebp
0x080486f8 <+13>: push %ecx
0x080486f9 <+14>: sub $0x64,%esp
0x080486fc <+17>: mov %gs:0x14,%eax
0x08048702 <+23>: mov %eax,-0xc(%ebp)
0x08048705 <+26>: xor %eax,%eax
0x08048707 <+28>: sub $0x4,%esp
0x0804870a <+31>: push $0x38
0x0804870c <+33>: push $0x0
0x0804870e <+35>: lea -0x44(%ebp),%eax
0x08048711 <+38>: push %eax
0x08048712 <+39>: call 0x8048550 <memset@plt>
0x08048717 <+44>: add $0x10,%esp
0x0804871a <+47>: call 0x804869b <initialize>
0x0804871f <+52>: sub $0xc,%esp
0x08048722 <+55>: push $0x80488c9
0x08048727 <+60>: call 0x8048500 <puts@plt>
0x0804872c <+65>: add $0x10,%esp
--Type <RET> for more, q to quit, c to continue without paging--
0x0804872f <+68>: sub $0xc,%esp
0x08048732 <+71>: push $0x80488d1
0x08048737 <+76>: call 0x8048500 <puts@plt>
0x0804873c <+81>: add $0x10,%esp
0x0804873f <+84>: sub $0xc,%esp
0x08048742 <+87>: push $0x80488e6
0x08048747 <+92>: call 0x8048500 <puts@plt>
0x0804874c <+97>: add $0x10,%esp
0x0804874f <+100>: sub $0xc,%esp
0x08048752 <+103>: push $0x80488f7
0x08048757 <+108>: call 0x80484c0 <printf@plt>
0x0804875c <+113>: add $0x10,%esp
0x0804875f <+116>: sub $0x8,%esp
0x08048762 <+119>: lea -0x5c(%ebp),%eax
0x08048765 <+122>: push %eax
0x08048766 <+123>: push $0x80488fa
0x0804876b <+128>: call 0x8048560 <__isoc99_scanf@plt>
0x08048770 <+133>: add $0x10,%esp
0x08048773 <+136>: mov -0x5c(%ebp),%eax
0x08048776 <+139>: cmp $0x2,%eax
0x08048779 <+142>: je 0x80487da <main+239>
0x0804877b <+144>: cmp $0x3,%eax
0x0804877e <+147>: je 0x8048804 <main+281>
--Type <RET> for more, q to quit, c to continue without paging--
0x08048784 <+153>: cmp $0x1,%eax
0x08048787 <+156>: je 0x804878e <main+163>
0x08048789 <+158>: jmp 0x8048835 <main+330>
0x0804878e <+163>: sub $0xc,%esp
0x08048791 <+166>: push $0x80488fd
0x08048796 <+171>: call 0x80484c0 <printf@plt>
0x0804879b <+176>: add $0x10,%esp
0x0804879e <+179>: sub $0x4,%esp
0x080487a1 <+182>: push $0x10
0x080487a3 <+184>: lea -0x58(%ebp),%eax
0x080487a6 <+187>: push %eax
0x080487a7 <+188>: push $0x0
0x080487a9 <+190>: call 0x80484b0 <read@plt>
0x080487ae <+195>: add $0x10,%esp
0x080487b1 <+198>: sub $0xc,%esp
0x080487b4 <+201>: push $0x8048904
0x080487b9 <+206>: call 0x80484c0 <printf@plt>
0x080487be <+211>: add $0x10,%esp
0x080487c1 <+214>: sub $0x8,%esp
0x080487c4 <+217>: lea -0x58(%ebp),%eax
0x080487c7 <+220>: add $0x10,%eax
0x080487ca <+223>: push %eax
0x080487cb <+224>: push $0x80488fa
--Type <RET> for more, q to quit, c to continue without paging--
0x080487d0 <+229>: call 0x8048560 <__isoc99_scanf@plt>
0x080487d5 <+234>: add $0x10,%esp
0x080487d8 <+237>: jmp 0x8048835 <main+330>
0x080487da <+239>: sub $0x8,%esp
0x080487dd <+242>: lea -0x58(%ebp),%eax
0x080487e0 <+245>: push %eax
0x080487e1 <+246>: push $0x804890a
0x080487e6 <+251>: call 0x80484c0 <printf@plt>
0x080487eb <+256>: add $0x10,%esp
0x080487ee <+259>: mov -0x48(%ebp),%eax
0x080487f1 <+262>: sub $0x8,%esp
0x080487f4 <+265>: push %eax
0x080487f5 <+266>: push $0x8048914
0x080487fa <+271>: call 0x80484c0 <printf@plt>
0x080487ff <+276>: add $0x10,%esp
0x08048802 <+279>: jmp 0x8048835 <main+330>
0x08048804 <+281>: sub $0x8,%esp
0x08048807 <+284>: push $0x804891d
0x0804880c <+289>: push $0x804891f
0x08048811 <+294>: call 0x8048540 <fopen@plt>
0x08048816 <+299>: add $0x10,%esp
0x08048819 <+302>: mov %eax,0x804a06c
0x0804881e <+307>: mov 0x804a06c,%eax
--Type <RET> for more, q to quit, c to continue without paging--
0x08048823 <+312>: push %eax
0x08048824 <+313>: push $0x38
0x08048826 <+315>: push $0x1
0x08048828 <+317>: lea -0x44(%ebp),%eax
0x0804882b <+320>: push %eax
0x0804882c <+321>: call 0x80484f0 <fread@plt>
0x08048831 <+326>: add $0x10,%esp
0x08048834 <+329>: nop
0x08048835 <+330>: jmp 0x804871f <main+52>
End of assembler dump.
main stack frame 32
-----------------------------ebp - 0x58 88
my_page.name[16]
my_page.age[4]
=================ebp 0x44 68
flag_buf[56]
---------------------------------
ebp[4]
-------------------------------------
ret
name과 age를 입력할시에
최대값을 입력한다면printf 사용시에 널문자를 만날때 출력을 정지하므로
.my_page에 널값이 없고
flag_buf에 널값이 있어
출력시에 flag_buf까지 나온다
이를 이용해 문제를 해결할 수 있다
출처ㅣhttps://stfofu.tistory.com/48
gdb를 이용하여 변수들의 주소를 확인하면 아래와 같습니다.
mypage.name : 0xffffd4b0
mypage.age : 0xffffd4c0
flag_buf : 0xffffd4c4
mypage.name와 mypage.age의 차이가 16바이트 이므로 mypage.name의 마지막 문자열이 널 바이트가 아닌 경우 바로 뒤에 있는 mypage.age 값도 출력하게 됩니다. 그리고 mypage.age의 값은 최대 4바이트 크기로
널 바이트가 없을 경우 flag_buf에 있는 값까지 출력하게 됩니다. 따라서 아래와 같이 입력 값을 순서대로 입력하면 플래그가 출력됩니다. 286331153은 16진수로 0x11111111이고 널 바이트인 0x00이 아닌 값으로 4바이트를 모두 채우기 위함입니다.
출처ㅣhttps://lemon-soju.tistory.com/52
이 문제는 프로그램의 메모리 배치와 입출력 방식의 취약점을 악용하여 flag_buf 값을 출력하는 익스플로잇 사례입니다. 다음은 자세한 설명입니다.
1. 문제의 핵심 메커니즘
- my_page.name의 동작
- my_page.name은 16바이트 크기의 문자열 배열입니다.
- read() 함수는 최대 16바이트를 입력받아 널 바이트(\0)를 자동으로 추가하지 않음.
- 따라서, 입력이 16바이트일 경우 널 종료(\0)가 없고, 이후 메모리에 저장된 값까지 출력될 가능성이 있습니다.
- printf의 %s 동작
- %s는 문자열을 출력하며, 널 바이트(\0)를 만날 때까지 메모리를 계속 읽음.
- my_page.name에 널 종료가 없다면, 메모리 내 다음 데이터를 문자열로 출력하려고 시도.
- 메모리 배치
- my_page.name (16바이트): 0xffffd4b0
- my_page.age (4바이트): 0xffffd4c0
- flag_buf (56바이트): 0xffffd4c4
- my_page.name와 my_page.age는 인접해 있음.
- my_page.name이 널 종료되지 않으면, **my_page.age와 flag_buf**까지 이어서 출력 가능.
2. 취약점 동작
(1) case 1에서 입력 처리
- read()로 my_page.name에 16바이트 입력.
- 입력한 16바이트가 널 종료가 없으면, my_page.age와 flag_buf 값을 포함한 메모리를 문자열로 해석.
(2) case 2에서 출력
- printf("Name: %s\n", my_page.name);:
- %s는 널 종료를 만날 때까지 메모리를 읽으므로, my_page.name 이후의 메모리 값(my_page.age 및 flag_buf)까지 출력.
(3) 메모리 연속성 악용
- my_page.name의 마지막 값이 널이 아니라면:
- my_page.age (4바이트) 출력.
- **flag_buf (56바이트)**까지 이어져 출력 가능.
3. 익스플로잇 입력
입력 전략
- my_page.name:
- 16바이트를 채움.
- 마지막에 널 바이트가 아닌 값(\x11, 즉 0x11)을 입력.
- my_page.age:
- my_page.age의 값을 **0x11111111 (286331153)**로 설정.
- 이는 널 바이트가 없는 값을 의도적으로 삽입하여 flag_buf로 접근하도록 만듦.
4. 입력 예제 및 동작
입력 값
- case 1에서 입력:
- my_page.name: aaaaaaaaaaaaaaa\x11 (총 16바이트, 널 종료 없음)
- my_page.age: 286331153 (10진수, 16진수로는 0x11111111)
동작 분석
- 메모리 상태
- my_page.name: aaaaaaaaaaaaaaa\x11 (16바이트)
- my_page.age: 0x11111111 (4바이트, 널 종료 없음)
- flag_buf: /flag 파일 내용 (56바이트).
- 출력 과정
- printf("Name: %s\n", my_page.name);:
- %s는 my_page.name에서 시작해 널 바이트를 찾을 때까지 계속 읽음.
- my_page.name → my_page.age → flag_buf로 이어서 읽기.
- my_page.age와 flag_buf 값이 문자열로 출력.
- printf("Name: %s\n", my_page.name);:
5. 문제 해결을 위한 코드 개선
(1) my_page.name의 널 종료 보장
- read()를 호출한 후 배열 마지막에 널 종료 추가:
read(0, my_page.name, sizeof(my_page.name) - 1); my_page.name[sizeof(my_page.name) - 1] = '\0';
(2) 안전한 문자열 출력
- printf 대신 fgets와 같은 함수 사용:
printf("Name: %.15s\n", my_page.name);
(3) 입력 크기 제한
- 입력 길이를 엄격히 제한하여 버퍼 오버플로우 방지.
6. 요약
- 취약점 설명:
- %s는 널 종료가 없을 경우 메모리 값을 계속 읽으므로, my_page.age 및 flag_buf까지 출력.
- 익스플로잇 원리:
- my_page.name의 마지막에 널 종료를 없애고, my_page.age 값을 조작하여 flag_buf 값을 출력.
- 해결 방안:
- 입력 검증과 출력 시 널 종료를 보장하여 메모리 읽기 범위를 제한.
추가로 더 궁금한 점이 있다면 언제든지 물어보세요! 😊
4294967295 채우는게 맞지않아? 16바이트 채울꺼면?
네, 정확히 말씀하셨습니다! 4294967295(10진수)는 0xFFFFFFFF(16진수)로, 4바이트(32비트) 데이터를 모두 1로 채우는 값입니다. 이를 사용하면 my_page.age 값을 널 바이트 없이 꽉 채울 수 있습니다.
1. 왜 4294967295로 채우는가?
- **my_page.age**는 int형 변수로 4바이트 크기입니다.
- 널 바이트가 없는 값을 채워야 flag_buf까지 출력이 이어질 수 있습니다.
- **0xFFFFFFFF**는 모든 비트가 1로 설정된 값이므로, 널 바이트(\x00)가 없습니다.
2. 입력 동작 정리
1단계: my_page.name 채우기
- read(0, my_page.name, sizeof(my_page.name))를 통해 16바이트 입력.
- 예:
aaaaaaaaaaaaaaaa
- 널 바이트를 자동으로 추가하지 않으므로, 마지막 바이트는 유효한 값으로 남음.
2단계: my_page.age 채우기
- scanf("%d", &my_page.age)를 통해 my_page.age를 입력.
- **4294967295**를 입력하여 my_page.age의 4바이트를 모두 1로 채움:
- 메모리 값: 0xFFFFFFFF.
3. 메모리 상태
메모리 레이아웃
입력을 아래와 같이 하면:
- my_page.name: aaaaaaaaaaaaaaa\x11
- my_page.age: 4294967295 (0xFFFFFFFF)
- flag_buf: /flag 파일의 내용.
메모리 상태는 다음과 같습니다:
주소 내용
0xffffd4b0 | aaaaaaaaaaaaaaa\x11 |
0xffffd4c0 | 0xFFFFFFFF |
0xffffd4c4 | /flag 내용 |
4. 출력 결과
출력 흐름
- printf("Name: %s\n", my_page.name):
- %s는 널 바이트를 만날 때까지 읽으므로:
- my_page.name → my_page.age → flag_buf를 모두 읽음.
- %s는 널 바이트를 만날 때까지 읽으므로:
출력 결과
입력된 16바이트 + 4294967295(4바이트) + flag_buf 내용을 한꺼번에 출력.
5. 코드 상의 문제점
- 널 바이트 미보장:
- my_page.name에서 널 종료가 없어 이후 메모리를 읽음.
- 입력 검증 부족:
- my_page.age에 널 바이트 없는 값을 채워 악용 가능.
- 메모리 보호 부족:
- 변수 간 메모리가 인접하여 잘못된 데이터 출력 가능.
6. 결론
**4294967295**는 **my_page.age**에 4바이트를 꽉 채우고 널 바이트 없이 데이터 출력을 확장하기에 적합한 값입니다. 이를 통해 flag_buf의 내용을 출력할 수 있습니다. 😊
왜 그럼 4294967295게 아니라 286331153을 채우는거야?
4294967295(0xFFFFFFFF) 대신 **286331153(0x11111111)**를 사용하는 이유는 특정 입력 패턴을 통해 익스플로잇을 더 쉽게 제어하거나 출력 데이터를 구분하기 위함일 가능성이 큽니다. 자세히 설명하겠습니다.
1. 숫자 선택의 이유
1-1. 4294967295(0xFFFFFFFF)의 특징
- 모든 비트가 1로 설정된 값.
- 널 바이트(0x00)가 없어서 출력 범위를 확장하기에 적합.
- 하지만, 출력된 데이터를 해석하기 어려울 수 있음.
- 예: 출력이 모두 ÿÿÿÿ(ASCII 값 0xFF)처럼 보임.
1-2. 286331153(0x11111111)의 특징
- 비트 패턴이 **0001 0001 0001 0001 ...**처럼 반복.
- 출력 시 !!!!(ASCII 값 0x11)로 표시되어, 익스플로잇의 결과를 시각적으로 쉽게 확인 가능.
- 디버깅 및 출력 확인에 유리.
2. 사용자의 목표
2-1. 출력 범위 확장
- printf("Name: %s\n", my_page.name);에서 %s는 널 바이트를 만날 때까지 메모리를 읽습니다.
- my_page.age 값을 널 바이트 없는 값(0xFFFFFFFF 또는 0x11111111)으로 설정하면, 다음 메모리 영역(flag_buf)까지 읽히도록 조작 가능합니다.
2-2. 데이터 확인 용이성
- 0x11111111은 사람이 쉽게 구분할 수 있는 출력(!!!!)을 제공.
- 디버깅 중 데이터를 시각적으로 확인하기 쉽게 하려는 의도가 있습니다.
3. 익스플로잇 동작 비교
4294967295(0xFFFFFFFF)를 사용하는 경우
- my_page.age 값: ÿÿÿÿ (ASCII 값 0xFF).
- 출력 데이터가 모두 동일한 값으로 채워져, flag_buf를 구분하기 어려울 수 있음.
286331153(0x11111111)를 사용하는 경우
- my_page.age 값: !!!! (ASCII 값 0x11).
- 출력 결과에서 my_page.age와 flag_buf의 경계를 쉽게 확인 가능.
4. 선택된 값의 의미
- 0xFFFFFFFF: 가장 단순하고 확실하게 널 바이트 없는 값.
- 0x11111111: 디버깅, 출력 확인, 익스플로잇 성공 여부를 시각적으로 명확히 하려는 의도.
5. 결론
- 286331153(0x11111111)을 사용하는 이유는 출력 데이터를 더 쉽게 확인하고 익스플로잇을 디버깅하기 용이하기 때문입니다.
- **4294967295(0xFFFFFFFF)**를 사용하는 것도 가능하지만, 데이터 시각화에서 불편할 수 있습니다.
궁금한 점이 더 있다면 말씀해주세요! 😊
ax16개 널 종료 없는거
286331153으로 널 종료 없는거 0x11111111 이진수로 10001000100010001000100010001
하면 flag_buf까지 이어서 읽어져서 flag가 출력된다
'Dreamhack > Dreamhack Wargame (Challenge)' 카테고리의 다른 글
[84] IT 비전공자 [dreamhack]what-is-my-ip문제 풀기 (0) | 2024.12.02 |
---|---|
[83] IT 비전공자 [dreamhack]BypassIF문제 풀기 (0) | 2024.12.01 |
[81] IT 비전공자 [dreamhack]NoSQL-CouchDB문제 풀기 (0) | 2024.11.29 |
[80] IT 비전공자 [dreamhack]Type c-j문제 풀기 (0) | 2024.11.28 |
[79] IT 비전공자 [dreamhack]out of money문제 풀기 (0) | 2024.11.27 |