TamuCTF2020] PWN - TROLL

노션으로 옮김·2020년 3월 28일
0

wargame

목록 보기
27/59
post-thumbnail

문제

There's a troll who thinks his challenge won't be solved until the heat death of the universe.

nc challenges.tamuctf.com 4765

nc로 접속해서 프로그램 동작을 확인해본다.

root@goorm:/work/myspace/TAMUCTF/pwn# nc challenges.tamuctf.com 4765

Who goes there?
Welcome to my challenge, . No one has ever succeeded before. Will you be the first?
I am thinking of a number from 1-100000. What is it?
1
You have failed. Goodbye.
root@goorm:/work/myspace/TAMUCTF/pwn#

1부터 100000 사이의 값을 맞추라고 한다.
불가능하다.


풀이

코드 파악

기드라로 바이너리를 디컴파일 해보자.

실행 순서는 다음과 같다.

  1. 현재의 timestamp값을 seed로 해서 랜덤한 값을 생성한다.
  2. 그리고 사용자의 입력과 비교하여 불일치할 경우 프로그램은 종료된다.
  3. 일치할 경우, 다시 반복하여 100번을 성공하면 플래그값을 출력해준다.

값이 지속적으로 변하므로, 브루트포싱 같은 공격은 불가능하다.
숫자를 정확히 알 수 있는 방법을 찾아야 한다.

트릭

시간값은 계속 변하므로 seed를 시간값으로 설정하면 안전할 것이라고 생각할 수 있지만, 사실 그렇지 않다.

다음과 같은 특징에 의해서 troll 프로그램의 결과는 예측될 수 있다.

  1. 시간값은 일정하게 변하므로 예측가능하다.
  2. seed를 받아서 생성하는 rand 함수는 seed 값만 동일하다면 항상 서버에서나 로컬에서나 동일한 랜덤값을 반환한다.

따라서 다음의 결과에 다다를 수 있다.

문제와 동일하게 랜덤 값을 100번 생성하는 프로그램을 생성하고, 그 인자로 서버에서 사용하는 timestamp 값을 전달하자.
그리고 출력되는 값을 서버로 전송하면 플래그를 획득할 수 있겠다.

검증

그렇다면 이제 필요한 것은, 서버에서 사용하는 timestamp값을 얻는 것이다.

이것은 간단하다.

nc에 접속과 동시에 로컬에서 현재 timestamp값을 확인하면 된다.
그리고 랜덤한 값을 생성하여 그 값을 서버에 전송하도록 코드를 작성하자.

먼저 현재의 timestamp 값을 구한 뒤, 랜덤한 값을 생성하는 코드이다.

gen.cpp

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <string.h>

int main(void)
{
        FILE *fp ;
    // Open the existing file GfgTest.c using fopen()
    // in write mode using "w" attribute
    fp = fopen("keys", "w") ;
	int sd = time(0);
	printf("generat a key file using a seed value of [%d]\n", sd);
    srand(sd);
    for(int i = 0; i<100; i++)
        fprintf(fp, "%d;", rand()%100000 + 1);
		fprintf(fp, "\n");
        printf("successful generate a key file\n");
    return 0;
}

다음으로, 앞서 구한 key값을 서버에 전송하여 플래그값을 획득하는 파이썬 코드이다.

ex.py

from pwn import *
import time
import re

p = None
while True:
        p_gen = process('gen')
        p = remote('challenges.tamuctf.com', 4765)
        ts = int(time.time())
        recv = p_gen.recvall()
        p_gen.close()
        pt = re.compile('\[[a-z0-9]*\]')
        res = pt.findall(recv)
        pt = re.compile('[0-9]+')
        res = pt.findall(res[0])
        res = res[0]

        print "timestamp for generating a key: " + res
        print "timestamp now: " + str(ts)

        if str(ts) != res:
                print "timestamp mismatched"
                p.close()
                continue
        else:
                break
print p.recvuntil('Who goes there?')
p.sendline('woou')

keys = []
with open('keys', 'r') as f:
        strs = ''.join(f.readlines())
        keys = strs.split(';')
for x in range(len(keys)-1):
        print p.recvuntil('What is it?')
        p.sendline(keys[x])
p.interactive()

PoC코드를 실행하면 플래그 값을 확인할 수 있다.

0개의 댓글