概要
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版本是個坑,懂的都懂。