IDA로 decompiler했다
int __fastcall main(int argc, const char **argv, const char **envp)
{
int v4; // [rsp+24h] [rbp-22Ch] BYREF
int v5; // [rsp+28h] [rbp-228h]
int v6; // [rsp+2Ch] [rbp-224h]
size_t size; // [rsp+30h] [rbp-220h]
char *buf; // [rsp+38h] [rbp-218h]
char s[256]; // [rsp+40h] [rbp-210h] BYREF
char value[264]; // [rsp+140h] [rbp-110h] BYREF
unsigned __int64 v11; // [rsp+248h] [rbp-8h]
v11 = __readfsqword(0x28u);
setup();
puts("[Sane Env System]");
do
{
menu();
v5 = 0;
__isoc99_scanf("%d", &v4);
if ( v4 == 4 )
{
v5 = 1;
}
else
{
if ( v4 > 4 )
goto LABEL_36;
switch ( v4 )
{
case 3:
size = confstr(0, 0LL, 0LL);
if ( !size )
{
puts("_CS_PATH invalid!");
exit(-1);
}
buf = (char *)malloc(size);
if ( !buf )
{
puts("malloc() failed!");
exit(-1);
}
if ( !confstr(0, buf, size) )
{
puts("confstr() failed!");
exit(-1);
}
if ( setenv("PATH", buf, 1) == -1 )
{
puts("PATH setup failed!");
exit(-1);
}
free(buf);
if ( system("cat ~/flag") == -1 )
{
puts("system() failed!");
exit(-1);
}
puts("system() worked!");
break;
case 1:
do
v6 = getchar();
while ( v6 != 10 && v6 != -1 );
printf("Environment variable name: ");
fgets(s, 256, stdin);
if ( s[strlen(s) - 1] == 10 )
s[strlen(s) - 1] = 0;
printf("Environment variable value: ");
fgets(value, 256, stdin);
if ( value[strlen(value) - 1] == 10 )
value[strlen(value) - 1] = 0;
if ( setenv(s, value, 1) == -1 )
{
puts("setenv() failed!");
exit(-1);
}
puts("Environment variable set!");
break;
case 2:
do
v6 = getchar();
while ( v6 != 10 && v6 != -1 );
printf("Environment variable name: ");
fgets(s, 256, stdin);
if ( s[strlen(s) - 1] == 10 )
s[strlen(s) - 1] = 0;
if ( unsetenv(s) == -1 )
{
puts("unsetenv() failed!");
exit(-1);
}
puts("Environment variable cleared!");
break;
default:
LABEL_36:
puts("no hack!");
exit(-1);
}
}
}
while ( !v5 );
return 0;
}
주어진 코드는 C 언어로 작성된 프로그램으로, 환경 변수를 설정하거나 해제하는 기능을 제공하는 메뉴 기반의 시스템입니다. 여기서는 코드의 주요 흐름과 각 부분의 동작을 상세히 설명하겠습니다.
1. 주요 변수 설명
- v4: 사용자가 선택한 메뉴 옵션을 저장하는 변수.
- v5: 종료 조건을 나타내는 플래그. v5 = 1이면 프로그램 종료.
- size: 환경 변수 값 크기를 저장.
- buf: 동적 메모리 할당된 환경 변수 값을 저장하는 포인터.
- s: 환경 변수 이름을 저장하는 버퍼(256바이트).
- value: 환경 변수 값을 저장하는 버퍼(264바이트).
- v11: 스택 보안용 Canary 값으로, 스택 오버플로우 방지를 위해 사용.
2. 함수 설명
(1) setup()
- 프로그램 초기화를 수행합니다. 상세 내용은 코드에 포함되어 있지 않지만, 일반적으로 버퍼 초기화나 보안 설정을 포함할 수 있습니다.
(2) menu()
- 메뉴를 화면에 출력합니다. 사용자가 선택할 수 있는 옵션을 제공합니다.
3. 코드 흐름
(1) 초기화 및 반복 구조
v11 = __readfsqword(0x28u);
setup();
puts("[Sane Env System]");
- Canary 값(v11)을 읽어 스택 보호를 설정.
- 초기화 함수(setup()) 호출.
- "[Sane Env System]" 메시지 출력.
(2) 메뉴 실행 루프
do {
menu();
v5 = 0;
__isoc99_scanf("%d", &v4);
- 메뉴를 출력하고 사용자 입력(v4)을 받습니다.
- 입력값에 따라 분기하며, 옵션이 4인 경우 프로그램 종료 플래그(v5 = 1)를 설정합니다.
4. 메뉴 옵션별 동작
(1) 옵션 1: 환경 변수 추가
printf("Environment variable name: ");
fgets(s, 256, stdin);
...
if (setenv(s, value, 1) == -1) {
puts("setenv() failed!");
exit(-1);
}
- 사용자로부터 환경 변수 이름과 값을 입력받습니다.
- setenv()를 호출해 환경 변수를 설정하며, 이름이 이미 존재하면 덮어씁니다.
- 성공 시 "Environment variable set!" 메시지를 출력.
(2) 옵션 2: 환경 변수 삭제
printf("Environment variable name: ");
fgets(s, 256, stdin);
...
if (unsetenv(s) == -1) {
puts("unsetenv() failed!");
exit(-1);
}
- 사용자로부터 환경 변수 이름을 입력받습니다.
- unsetenv()를 호출해 해당 환경 변수를 제거합니다.
- 성공 시 "Environment variable cleared!" 메시지를 출력.
(3) 옵션 3: PATH 환경 변수 설정 및 파일 읽기
size = confstr(0, 0LL, 0LL);
buf = (char *)malloc(size);
...
if (setenv("PATH", buf, 1) == -1) {
puts("PATH setup failed!");
exit(-1);
}
- confstr()를 사용해 _CS_PATH 값을 가져옵니다.
- 동적으로 메모리를 할당(malloc)하여 PATH 값을 설정.
- system("cat ~/flag") 명령어를 실행해 홈 디렉토리의 flag 파일 내용을 출력.
(4) 기본 또는 잘못된 입력 처리
default:
puts("no hack!");
exit(-1);
- 메뉴에 정의되지 않은 값이나 유효하지 않은 입력을 받으면 "no hack!" 메시지를 출력하고 프로그램을 종료.
5. 종료 조건
while (!v5);
return 0;
- 옵션 4를 선택하면 v5 = 1로 설정되고 루프가 종료됩니다.
6. 보안 취약점
이 코드에는 몇 가지 보안 취약점이 존재할 수 있습니다:
- 버퍼 오버플로우 가능성:
- fgets()로 입력받은 s와 value의 크기를 초과하는 입력이 들어올 경우 오버플로우가 발생할 수 있습니다.
- 예를 들어, value는 264바이트로 선언되었지만 입력은 더 클 수 있습니다.
- system() 명령어 호출:
- system("cat ~/flag")는 명령어 주입 공격에 취약할 수 있습니다.
- 예를 들어, PATH 환경 변수가 악의적으로 변경될 경우 다른 바이너리를 실행할 위험이 있습니다.
- 메모리 누수:
- malloc()로 할당된 메모리가 정상적으로 해제되지 않는 경우 메모리 누수가 발생할 수 있습니다.
7. 개선 방안
- 버퍼 크기 제한:
- fgets(s, sizeof(s), stdin)와 같이 입력 길이를 제한.
- 동적 메모리 관리:
- 모든 할당된 메모리를 사용 후 해제.
- system() 대체:
- system() 대신 보안성이 높은 방법을 사용 (예: 파일 입출력 함수).
- 입력 검증:
- 사용자 입력값(v4)의 범위를 엄격히 검증.
요약
이 코드는 환경 변수 추가, 삭제, 및 시스템 명령어 실행을 제공하는 프로그램으로, 학습 목적으로 보일 수 있으나 여러 보안 취약점을 포함하고 있습니다. 특히 system() 호출과 버퍼 크기 초과를 주의 깊게 다뤄야 합니다. 추가적인 질문이 있다면 언제든 알려주세요! 😊
주어진 힌트를 통해 문제를 풀기 위한 방향성을 구체적으로 정리하겠습니다. env 명령어로 출력되는 환경 변수가 문제 풀이의 핵심이며, 리눅스 시스템에서 환경 변수의 역할과 이를 활용한 취약점 공격에 대해 이해해야 합니다.
환경 변수와 관련된 기본 개념
1. PATH 환경 변수
- 역할: 실행 가능한 명령어의 경로를 지정.
- 문제 관련성:
- 프로그램에서 system() 호출 시, PATH에 설정된 디렉토리 순서대로 명령어를 탐색.
- PATH를 조작하면 하드코딩된 명령어(cat)를 다른 스크립트로 대체 가능.
2. HOME 환경 변수
- 역할: 현재 사용자의 홈 디렉토리를 나타냄.
- 문제 관련성:
- system("cat ~/flag")에서 ~는 HOME 환경 변수를 참조.
- HOME 값을 조작하면 다른 디렉토리를 홈 디렉토리처럼 인식하도록 설정 가능.
3. env 명령어 사용
- env 명령어로 현재 환경 변수 목록을 확인:
env
- 주요 환경 변수:
- PATH: 실행 가능한 명령어 경로.
- HOME: 홈 디렉토리 경로.
- SHELL: 기본 셸 프로그램.
문제 풀이 전략
힌트를 바탕으로 환경 변수를 조작하여 플래그 파일을 읽는 방법을 단계적으로 정리합니다.
1. PATH를 조작하여 명령어 대체
- 현재 디렉토리에 악성 스크립트를 생성:
- echo '#!/bin/sh' > cat echo 'cat /flag' >> cat chmod +x cat
- 프로그램 실행 후 메뉴에서 옵션 1을 선택:
- > 1 Environment variable name: PATH Environment variable value: .
- 옵션 3 실행:
- > 3
2. HOME 환경 변수 조작
- HOME을 / 또는 다른 디렉토리로 설정:
- Environment variable name: HOME Environment variable value: /
- 프로그램에서 system("cat ~/flag") 호출 시:
- ~가 /로 해석되어 /flag 파일을 읽으려 시도.
- 옵션 3 실행:
- > 3
3. 추가적인 환경 변수 검토
- LD_PRELOAD 환경 변수:
- 동적 라이브러리를 로드하여 프로그램 동작을 변경할 수 있습니다.
- 플래그 파일 경로를 우회하거나 명령어를 대체할 수 있습니다.
요약
문제 해결 흐름
- PATH 조작:
- 명령어 실행 경로를 현재 디렉토리로 변경.
- HOME 조작:
- ~를 /로 해석되도록 홈 디렉토리를 변경.
- 명령어 실행:
- 하드코딩된 system("cat ~/flag") 호출로 플래그 파일 읽기.
최종 플래그 출력
플래그 파일(/flag) 내용이 출력되며, 형식은 DH{...}입니다.
문제를 해결하는 과정에서 추가적인 어려움이 있으면 알려주세요! 😊
힌트 ~ 는 HOME이었다...
'Dreamhack > Dreamhack Wargame (Challenge)' 카테고리의 다른 글
[135] IT 비전공자 [dreamhack]Arm Training-v1문제 풀기 (0) | 2025.01.23 |
---|---|
[134] IT 비전공자 [dreamhack]BISC Safe문제 풀기 (0) | 2025.01.22 |
[132] IT 비전공자 [dreamhack]STREAMer-Prototype문제 풀기 (0) | 2025.01.20 |
[131] IT 비전공자 [dreamhack]Grand Theft Auto문제 풀기 (0) | 2025.01.19 |
[130] IT 비전공자 [dreamhack]산타 할아버지도 힘들어요문제 풀기 (0) | 2025.01.18 |