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 사이의 값을 맞추라고 한다.
불가능하다.
기드라로 바이너리를 디컴파일 해보자.
실행 순서는 다음과 같다.
값이 지속적으로 변하므로, 브루트포싱 같은 공격은 불가능하다.
숫자를 정확히 알 수 있는 방법을 찾아야 한다.
시간값은 계속 변하므로 seed를 시간값으로 설정하면 안전할 것이라고 생각할 수 있지만, 사실 그렇지 않다.
다음과 같은 특징에 의해서 troll 프로그램의 결과는 예측될 수 있다.
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코드를 실행하면 플래그 값을 확인할 수 있다.