one_gadget的一些姿勢

unr4v31發表於2021-08-22

概要

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

相關文章