概要
one_gadget是libc中存在的一些执行execve("/bin/sh", NULL, NULL)
的片段,当可以泄露libc地址,并且可以知道libc版本的时候,可以使用此方法来快速控制指令寄存器开启shell。
相比于system("/bin/sh")
,这种方式更加方便,不用控制RDI、RSI、RDX等参数。运用于不利构造参数的情况。
安装及使用方式
-
首先需要安装Ruby(Ruby < 2.4 会导致one_gadget无法安装,最好是通过添加仓库的方式安装)
# 添加仓库 sudo add-apt-repository ppa:brightbox/ruby-ng sudo apt-get update # 指定ruby 2.6版本 sudo apt-get install ruby2.6 ruby2.6-dev # 贴一条删除旧版本ruby的命令 sudo apt-get purge --auto-remove ruby
-
然后安装one_gadget
sudo gem install one_gadget
-
使用方法很简单
one_gadget libc.so.6
踩坑记录
-
one_gadget并不总是可以获取shell,它首先要满足一些条件才能执行成功(如果没有满足条件也执行成功了,那纯粹就是靠脸了)
unravel@unravel:~/Desktop/note$ one_gadget libc-2.23.so 0x45226 execve("/bin/sh", rsp+0x30, environ) constraints: rax == NULL # 这个提示的意思就是在调用one_gadget前需要满足的条件 0x4527a execve("/bin/sh", rsp+0x30, environ) constraints: [rsp+0x30] == NULL 0xf03a4 execve("/bin/sh", rsp+0x50, environ) constraints: [rsp+0x50] == NULL 0xf1247 execve("/bin/sh", rsp+0x70, environ) constraints: [rsp+0x70] == NULL
-
这次祥云杯我就是遇到这种情况,one_gadget无法调用,原因是我将one_gadget写入了
_malloc_hook
中,_malloc_hook
会使用jmp rax
来执行代码,所以在执行one_gadget时,rax必定不为NULL,只能排除第一个one_gadget。而其他三个one_gadget均无法满足要求,后来是利用realloc
函数来多push几个参数到栈上,而此时恰好满足one_gadget的条件,也就可以获取shell了。
总结
以前从来没注意过one_gadget的调用过程,借这次比赛机会了解了一下,也学到了很多小技巧,在这里记录一下。
- 如果是使用
_malloc_hook
来调用one_gadget,那么需要配合realloc
来构造所需参数,realloc
在libc中的符号是__libc_realloc
- 如果是使用其他方式调用one_gadget,比如说修改GOT表,那么需要在栈上提前构造好参数,或者将rax寄存器清零
- 在泄露libc地址的时候,最好是泄露
read
函数的地址,因为read
函数距离one_gadget的偏移是不会变的,只需要将read
函数真实地址减去0x6109,就可以使用one_gadget了,具体可以自行调试一下便知。那这么做的好处就是不用去知道libc的版本,省了很大一部分时间和精力,libc版本是个坑,懂的都懂。