校园网加密审计全过程复盘
10.0.98.1 认证页密码审计:账密在哪
结论
无加密。账号密码明文放在 GET 请求的 URL 参数里发出去,抓包直接可见。
- 前端有加密函数
enc_pwd,但开关page_data_encrypt='0'(关闭) en_md5=0(无 MD5)、enableHttps=0(纯 HTTP)- 实测抓到:
user_password=123456明文
账密出现在哪
- 传输(主要):登录请求
GET http://10.0.98.1:801/eportal/portal/login?...&user_account=<账号>&user_password=<密码>,参数明文进 URL。 - 本地存储:登录前 JS 会把账密写进浏览器 cookie:
a43.js的login.login():cookie.set('DDDDD', II(escape(账号))); cookie.set('upass', II(escape(密码)))- 勾选"记住密码"还会存
save_DDDDD/save_upass(用II()简单异或混淆,不是加密)
找到账密的过程
第 1 步:拿到登录页加载的所有 JS
门户首页是个壳,真正逻辑在 a41.js / a43.js 等文件里。
第 2 步:静态读代码,确认加密是关的a41.js 顶部直接写明:
var page_data_encrypt='0'; // 0-不加密加密函数 enc_pwd 只是逐字符异或 + 转 hex,属弱混淆。
第 3 步:顺着登录流程找"字段叫什么"——这里我找错了a43.js 的 default_login() 构造登录数据,字段是 DDDDD(账号)、upass(密码),发给 /drcom/login。门户页自身的配置变量也写着 authuserfield='DDDDD'、authpassfield='upass'。
我据此断定登录格式是 DDDDD/upass,于是把分析脚本写成只匹配这种格式。
第 4 步:抓包实锤,发现脚本什么都没打出来
在路由器上抓包(设备先注销再登录),回放 pcap,脚本空手而归。起初我还以为"没抓到登录",于是直接去翻 pcap 里的原始数据,结果真相是:
登录抓到了,但格式和我猜的完全不一样:
GET /eportal/portal/login?...&user_account=zjbggzhh&user_password=123456 (801端口)字段是 user_account/user_password,走 801 端口的 /eportal/portal/login,不是代码里那套 DDDDD/upass。
第 5 步:改对
按 pcap 里的真实格式重写脚本(两种格式都认),回放即出 4 组明文账密(zjbggzhh/123456 等)。
为什么一开始会找错?
根本原因:我追错了文件,不是只追错一条函数。
页面实际加载的是压缩版
a40.js,我却去读了未压缩的a43.js。
门户页开头var isJSMin=1,意思是"用压缩版 JS"。压缩版a40.js里的登录函数login.login()是这样的:switch(page.login_method) { case 1: login.login_portal(...); break; // 新版:user_account/user_password → 801 default: login.default_login(...); // 旧版:DDDDD/upass → /drcom/login }而我没加载的那个未压缩版
a43.js里,login.login()是直接调default_login()的简化版,根本没有这个 switch。
我把a43.js当成了实际执行代码,于是得出"登录格式是 DDDDD/upass、走 /drcom/login"的错误结论。门户首页自身的配置变量把我带偏了:
authuserfield='DDDDD'、authpassfield='upass'写的是旧版字段,加深了错误印象。没有第一时间怀疑自己的假设。脚本打不出东西时,我先是怀疑"没抓到",而不是"匹配格式错了"。直到直接翻原始 pcap,才纠正过来。
801 端口在代码里的完整对应
从端口定义到发出请求,链路是通的(以实际加载的 a40.js 为准):
| 步骤 | 代码 | 作用 |
|---|---|---|
| 1 | a41.js var epHTTPPort=801; | 定义 eportal 的 HTTP 端口 = 801 |
| 2 | a41.js ep_port = http ? epHTTPPort : enHTTPSPort | 当前走 HTTP,ep_port = 801 |
| 3 | a41.js portal_api = http://主机:801/eportal/portal/ | 拼出带 801 的基础地址 |
| 4 | a40.js login.login() 的 switch(page.login_method) | login_method=1(来自服务器 loadConfig 配置)→ 走 login_portal() |
| 5 | a40.js login_portal() | 构造 user_account、user_password 等参数,调 portal_login(data) |
| 6 | a40.js portal_login() | url = (login_method==0 ? /drcom : portal_api) + 'login' → http://10.0.98.1:801/eportal/portal/login |
logout 同理:logout.logout_portal() 构造 user_account=drcom&user_password=123(注销请求里那组固定的假账密就是这么来的),发到 801 的 /eportal/portal/logout——和抓到的完全一致。
教训:登录格式以实际抓到的包为准,代码只是参考,可能是错的。而且要先确认"实际加载的是哪个文件"(
isJSMin之类开关),别拿没被加载的文件当依据。
工具与命令
路由器上(无 Python),用 tcpdump + awk/sed 即可,脚本在 /root/:
# 实时抓+打印账密(先注销再登录)
/root/sniff-login-router.sh
# 落盘抓包,登录后 Ctrl-C
/root/capture-login-router.sh
# 回放 pcap 打印账密
/root/analyze-login-router.sh关键抓包命令:
tcpdump -i any -nn -l -s 0 -A 'host 10.0.98.1 and (tcp port 80 or tcp port 801)'