0x01 简述

云南招考频道是高考查分,录取查询的平台,每年高考分数均在此处查询,由于查询时是通过考号查询密码生成口令后访问服务器页面,此方法通过利用漏洞生成口令提前查询高考分数,避免放榜后大量流量导致服务器卡顿,以及提前知高考成绩

0x02 入口

入口均为静态页面,此处截图已进行修改屏蔽,截图中的域名实际不存在

云南招考频道:https://www.ynzs.cn/

image-20200814103011728

高考查分入口:https://www.ynzs.cn/{高考年份}gkcf/web.html

image-20200814104449432

考生成绩报告:https://gk.ynzs.cn/{年份}/gkcf/{a}/{b}.html

image-20200814104631658

0x03 操作过程

此处将使用2019高考查分页面查询2020的考生高考成绩

  1. 打开2019查分地址:https://www.ynzs.cn/2019gkcf/web.html

    image-20200814105054784

  2. 输入2020考生的准考证号,查询密码

    image-20200814105213275

  3. 点击查询,跳转错误页面

    image-20200814105317451

  4. 点击地址栏,将2019改为2020

    [-] https://gk.ynzs.cn/2019/gkcf/xx/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.html
    [+] https://gk.ynzs.cn/2020/gkcf/xx/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.html
    
  5. 查询完毕

    image-20200814105955987

0x04 代码分析

2019的查询代码:https://www.ynzs.cn/2019gkcf/js/web.js

$(document).ready(function(){
	
	$("#user").focus();
	$("input:text,textarea,input:password").focus(function() {
		$(this).addClass("cur_select");
    });
    $("input:text,textarea,input:password").blur(function() {
		$(this).removeClass("cur_select");
    });

	
	$("#btn").click(function(){
		var user = $.trim($("#user").val());
		var pass = $.trim($("#pass").val());
		if(user==""){
			$(".sub").html("<b>准考证号不能为空!</b>");
			$("#user").focus();
			return false;
		}
		
		if(user.length !=9){
			$(".sub").html("<b>准考证号应为9位!</b>");
			$("#user").focus();
			return false;
	   	}
		
		if(pass==""){
			$(".sub").html("<b>查询密码不能为空!</b>");
			$("#pass").focus();
			return false;
		}
		
		$.ajax({
			type: "POST",
			url: "check.php?action=query",
			timeout : 3000,
			dataType: "json",
			data: {"user":user,"pass":pass},
			beforeSend: function(){
				$(".sub").html("<b>正在查询,请稍候!</b>");
			},
			success: function(json){
				if(json.success==1){
					window.location.href=json.url;
				}else{
					alert(json.msg);
					return false;
				}
			},
			complete : function(XMLHttpRequest,status){ 
		    if(status=='timeout'){
				  $(".sub").html("<b>查询超时,请重试!</b>");
		    }
		  }
		});
	});
});

作用:

方法:     POST
数据类型:  JSON
数据内容:  {"user":user,"pass":pass}
地址:     https://www.ynzs.cn/2019gkcf/check.php?action=query

2020的查询代码:https://www.ynzs.cn/2020gkcf/js/wait.min.js

var isOpen = !1,
    querytime = 12954714e5;
$(document).ready(function () {
    function a(a, b) {
        return "" == a ? ($(".sub").html("<b>\u51C6\u8003\u8BC1\u53F7\u4E0D\u80FD\u4E3A\u7A7A!</b>"), $("#user")
            .focus(), !1) : 9 == a.length ? "" != b || ($(".sub").html(
            "<b>\u67E5\u8BE2\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A!</b>"), $("#pass").focus(), !1) : ($(
            ".sub").html("<b>\u51C6\u8003\u8BC1\u53F7\u5E94\u4E3A9\u4F4D!</b>"), $("#user").focus(), !1)
    }
    function b(a, b) {
        $("#qurey").hide(), $("#waitdiv").show(), $("#rewaitdiv").hide();
        var d = 3 + 10 * Math.random(),
            e = parseInt(1 + 9 * Math.random());
        setTimeout(function () {
            e >= 1 ? c(a, b) : ($("#qurey").hide(), $("#waitdiv").hide(), $("#rewaitdiv").show())
        }, 1e3 * 5)
    }
    function c(a, b) {
        $.ajax({
            type: "POST",
            url: "check.php?action=query",
            timeout: 3e3,
            dataType: "json",
            data: {
                user: a,
                pass: b
            },
            success: function (a) {
                return 1 == a.success ? void(window.location.href = a.url) : (alert(a.msg), !1)
            },
            complete: function (a, b) {
                "timeout" == b && ($("#qurey").show(), $("#rewaitdiv").hide(), $("#waitdiv").hide(),
                    $(".sub").html("<b>\u67E5\u8BE2\u8D85\u65F6\uFF0C\u8BF7\u91CD\u8BD5!</b>"))
            },
            error: function () {
                $("#qurey").hide(), $("#rewaitdiv").show(), $("#waitdiv").hide()
            }
        })
    }
    $("#user").focus(), $("input:text,textarea,input:password").focus(function () {
        $(this).addClass("cur_select")
    }), $("input:text,textarea,input:password").blur(function () {
        $(this).removeClass("cur_select")
    }), $("#btn").click(function () {
        var d = $.trim($("#user").val()),
            e = $.trim($("#pass").val());
        if (a(d, e)) {
            var f = new Date,
                g = f.getTime();
            g <= querytime ? $(".sub").html(
                    "<b>\u5F53\u524D\u8FD8\u672A\u5F00\u653E\u9AD8\u8003\u67E5\u5206!</b>") : isOpen ?
                b(d, e) : c(d, e)
        }
    }), $("#btnreload").click(function () {
        var c = $.trim($("#user").val()),
            d = $.trim($("#pass").val());
        a(c, d) && b(c, d)
    })
});

解密后,其中变量名称被压缩

var isOpen = !1,
    querytime = 12954714e5;
$(document).ready(function() {
    function a(a, b) {
        return "" == a ? ($(".sub").html("<b>准考证号不能为空!</b>"), $("#user")
            .focus(), !1) : 9 == a.length ? "" != b || ($(".sub").html(
            "<b>查询密码不能为空!</b>"), $("#pass").focus(), !1) : ($(
            ".sub").html("<b>准考证号应为9位!</b>"), $("#user").focus(), !1)
    }

    function b(a, b) {
        $("#qurey").hide(), $("#waitdiv").show(), $("#rewaitdiv").hide();
        var d = 3 + 10 * Math.random(),
            e = parseInt(1 + 9 * Math.random());
        setTimeout(function() {
            e >= 1 ? c(a, b) : ($("#qurey").hide(), $("#waitdiv").hide(), $("#rewaitdiv").show())
        }, 1e3 * 5)
    }

    function c(a, b) {
        $.ajax({
            type: "POST",
            url: "check.php?action=query",
            timeout: 3e3,
            dataType: "json",
            data: {
                user: a,
                pass: b
            },
            success: function(a) {
                return 1 == a.success ? void(window.location.href = a.url) : (alert(a.msg), !1)
            },
            complete: function(a, b) {
                "timeout" == b && ($("#qurey").show(), $("#rewaitdiv").hide(), $("#waitdiv").hide(),
                    $(".sub").html("<b>查询超时,请重试!</b>"))
            },
            error: function() {
                $("#qurey").hide(), $("#rewaitdiv").show(), $("#waitdiv").hide()
            }
        })
    }
    $("#user").focus(), $("input:text,textarea,input:password").focus(function() {
        $(this).addClass("cur_select")
    }), $("input:text,textarea,input:password").blur(function() {
        $(this).removeClass("cur_select")
    }), $("#btn").click(function() {
        var d = $.trim($("#user").val()),
            e = $.trim($("#pass").val());
        if (a(d, e)) {
            var f = new Date,
                g = f.getTime();
            g <= querytime ? $(".sub").html("<b>当前还未开放高考查分!</b>") : isOpen ?
                b(d, e) : c(d, e)
        }
    }), $("#btnreload").click(function() {
        var c = $.trim($("#user").val()),
            d = $.trim($("#pass").val());
        a(c, d) && b(c, d)
    })
});

作用分析:

方法:     POST
数据类型:  JSON
数据内容:  {"user":a,"pass":b}
地址:     https://www.ynzs.cn/2020gkcf/check.php?action=query

由数据可以推断:

  1. check.php不返回数据,而是直接重定向
  2. check.php的口令获取算法相同,口令考虑为MD5计算而来

0x05 总结反思

  1. 总结
    1. 口令使用md5(准考证号 + 查询密码) 获得
    2. 口令与年份无关
    3. 口令生成方法未知
  2. 反思
    1. 在设计查询时,使用模板+数据渲染,不保存实体图片
    2. 增加页面token,防止越权
    3. 简单的unicode压缩并不能加密,可以使用以下算法加密JS
      1. aaencode
      2. jjencode
      3. JS Fuck
    4. 短信推送更方便