专栏首页白安全组某高考志愿信息网站爬虫分析

某高考志愿信息网站爬虫分析

对于某高考志愿信息网站写了一个爬虫, 遇到了一些问题, 在这里记录一下, 顺便学到了一些反爬虫的技巧.

获取每个学校的分数线情况, 首先在浏览器查看所有请求, 找到获取数据的请求, 但是可以发现他这个请求回来的某些数据应该是经过加密的.

这个解密代码一定在客户端, 因此我们找找, 看看能不能找到解密的代码. 首先我们添加请求断点, 看看能有什么突破.

接下来触发请求, 我们来看一下Call Stack中的信息, 经过排查, 我们可以发现如下重要的函数:

通过查找源码, 我们找到上面的那个函数的源码, 这里代码没经过压缩和混淆, 因此可读性是真的好, 太良心了. 我们可以发现其中的两个关键的函数showNumbercnDeCrypt, 猜测应该是这两个函数完成的对于参数的解密

直接在这些函数下断点, 来看看具体的调用, 我们可以发现showNumber的代码非常简单, 这里就不解释了.

接下来是cnDeCrypt, 这个函数看起来比较复杂, 实际上, 可以直接复制代码到控制台, 这个是可以直接执行的, 简单分析一下可以知道他调用了split()forEach两个函数

在这里, 简单翻译一下这段代码吧, 到这里, 这个函数的作用就十分明显了.

var _cnDeCrypt = function (zlVjhiyMm1) {
    var YB2 = "";
    zlVjhiyMm1.split("|").forEach(function ($lvd3) {
        if ($lvd3.search(/【(.*?)】/) !== -1) {
            YB2 += $lvd3.replace('【', '').replace('】', '');
        } else {
            $lvd3 = $lvd3.replace(/[g-t]/ig, "");
            YB2 += "\x26\x23\x78" + $lvd3 + "\x3b"        }
    });
    return YB2
}

最后我们可以发现, 最终返回的是html编码, 但是这个和数据好像并不一样, 我们审查元素来看看, 发现其内容是看不懂的内容, 这里感觉应该是采用了字体加密

我们通过请求搜索一下字体文件, 我们可以发现如下的可疑文件, 利用FontEditor, 来查看一下.

首先打开数字来看看, 字符串和数字差不多, 在这里就不截图展示了.

这个手动写一个字典吧, 我没找到好的解决方案, 反正这个也不多, 有大佬有好的方案可以告诉我, 我是截图然后识别的.

from fontTools.ttLib import TTFontdef get_number_dict():    font = TTFont('./number_a.woff')
    keys = font['glyf'].keys()
    values = list("    6920714538")
    return dict((k, v) for k, v in zip(keys, values))def get_string_dict():    font = TTFont('./cn_5.woff')
    keys = font['glyf'].keys()
    values = list(
        "    像艺包据印探及营命历曲服机境械磁飞食备植空武设水居油洋测纽统件软轻美丁下与世业丝中主义乌书事互交产人仪价休会伤伦估体作供侦俄保信修健儿光克党全公共关兵其军农准减出分划则别制刷力功加务动助劳化医华卫发古史司合告品商回国土地型培声大天女媒子学安定宝实审室家宾密小少尔展属嵌工市师广应康建开录形影律微德心情想感成战房技投护报拉控推播收放政教数文料斯无日时景智术材村来查正民气污河治法泰海源灾炸然照爆版物环班理生用画界疗监知石研种科秘移程税立筑算管类精纺组织经网职育能自航船英草葡萄行表装观规视计论评识译试语财质资路车轨轮运通造采量金鉴间非韩项预饰馆验高麻()0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
    return dict((k, v) for k, v in zip(keys, values))

直接下载字体文件, 然后生成对应的字典. 对于数字和字符串解密的函数, 这里有两种方案:

  1. 利用Python重写js代码, 这个代码逻辑也不复杂, 不难实现
  2. 直接利用Python解析JS代码, 因为我比较懒, 所以采用的第二种方案.
def show_number(string="o6onqsf732|oipr72hef1|g6htsfn732"):    code = """var showNumber = function(myNumbers) {
        var ns = [];
        myNumbers.split("|").forEach(function(value) {
            value = value.replace(/[g-t]/ig, "");
            ns.push(value);
        });
        return ns
    }
    """    ctx = execjs.compile(code)
    return ctx.call('showNumber', string)def cn_decrypt(string="gmcl6ak5|gsc6gl74|c6nktgda"):    code = """
    var _cnDeCrypt = function (zlVjhiyMm1) {
        var YB2 = "";
        var string_list = [];
        zlVjhiyMm1['\x73\x70\x6c\x69\x74']("\x7c")['\x66\x6f\x72\x45\x61\x63\x68'](function ($lvd3) {
            if ($lvd3['\x73\x65\x61\x72\x63\x68'](/【(.*?)】/) != -1) {
                YB2 += $lvd3['\x72\x65\x70\x6c\x61\x63\x65']("\u3010", "")['\x72\x65\x70\x6c\x61\x63\x65']("\u3011", "")
                string_list.push($lvd3['\x72\x65\x70\x6c\x61\x63\x65']("\u3010", "")['\x72\x65\x70\x6c\x61\x63\x65']("\u3011", ""));
            } else {
                $lvd3 = $lvd3['\x72\x65\x70\x6c\x61\x63\x65'](/[g-t]/ig, "");
                YB2 += "\x26\x23\x78" + $lvd3 + "\x3b"
                string_list.push("\x26\x23\x78" + $lvd3 + "\x3b")
            }
        });
        return string_list
    }
    """    ctx = js2py.eval_js(code)
    string_list = ctx.call('_cnDeCrypt', string)
    ret = ''    string_dict = get_string_dict()
    for string in string_list:
        if string.startswith('&#x'):
            ret += string_dict['uni' + string.replace('&#x', '').replace(';', '').upper()]
        else:
            ret += string
    return ret

在这里, 我修改了部分js的代码, 便于python解析, 网站本身的代码我就不完整的贴上来了, 前面的截图都有. 在这里有一个坑, 如果用execjs遇到转义字符会有问题, 当然这个代可以手动吧转义代码去掉, 或者用另一个库js2py.

到这里, 返回数据的解密就完成了, 下面我们来看一看请求的参数是如何加密的.

采用之前的方案, 在url处下断点, 查看找到关键函数, 我们可以发现这里调用是youzyEpt这个函数进行的加密

从源码中找到这个函数, 先来看看.

显然这里采用的AES进行的加密, 这么明显, 不过多解释了, 我们来看一下他的密钥是怎么得到的, 查看源码, 发现3个关键文件

读一下代码, 不难发现密钥是: [11, 23, 32, 43, 45, 46, 67, 8, 9, 10, 11, 12, 13, 14, 15, 16], 下面我们直接用Python写加密算法吧, 因为我不想引入js的aes加密算法了, 调用js还麻烦.

from Crypto.Cipher import AESdef params_encrypt(data):    key = bytes([11, 23, 32, 43, 45, 46, 67, 8, 9, 10, 11, 12, 13, 14, 15, 16])
    txt = str(json.dumps(data)).encode(encoding='utf-8')
    ctr = Counter.new(128, initial_value=5)
    cipher = AES.new(key, AES.MODE_CTR, counter=ctr)
    data = cipher.decrypt(txt)
    return b2a_hex(data).decode(encoding='utf-8'

写完之后, 让我们下断点测试一下代码是否正确.

对于密钥的获取, 如果不想读代码的话, 可以直接通过断点解决.

这样就完成了对于请求的加密和解密.

在这里讲一个小技巧, 如果请求的js文件后面有类似于v=timestamps等代码, 在source下断点之后, 刷新页面断点会消失.

可以采用代{过}{滤}理软件将其代{过}{滤}理到本地, 然后硬编码debugger这样就可以刷新也可以保持断点了. 在这里我用的Charles, 找到对应的url, 右键map local, 然后配置一下就可以了.

总结

对于这个网站, 代码几乎没有混淆和压缩, 因此读起来还是十分愉悦的, 对于调试, 如果在请求js的后面添加v=timestamps等类似的东西的话, 下完断点之后, 重新请求会消失, 可以采用代{过}{滤}理软件, 把这些东西代{过}{滤}理到本地, 添加debugger下断点来进行调试.

本文分享自微信公众号 - 白安全组(bai-1152770445)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-03-29

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 如何绕过cdn获取网站真实ip进行测试?

    一般网站会使用cdn进行防御,我们访问时会经过cdn然后再经过源站服务器,这样我们进行渗透测试时很容易被拦截。而在这里,我们的思路是这样的:通过找到源站ip之后...

    网e渗透安全部
  • 挖矿木马详解

    攻击者通过各种手段将挖矿程序植入受害者的计算机中,在受害者不知情的情况下利用其计算机的云算力进行挖矿,从而获取利益,这类非法植入用户计算机的挖矿程序就是挖矿...

    网e渗透安全部
  • 白帽黑帽真的有差别么

    下面讲讲我对于他们的理解,众所周知,黑帽无疑是最赚钱的,单从以前接的一个简单的渗透单,虽然本质是违法,但是利润高的让人禁不住诱惑,区区一周就有好几万入账,可能这...

    网e渗透安全部
  • 漏洞预警|豆瓣日记页面存在存储型XSS

    原本测试直接插入,但是实测未能接收,测试IMG标签并对链接做过修整代码,接收成功、

    周俊辉
  • nginx的worker_processes优化

    nginx的worker_processes参数 来源: http://bbs.linuxtone.org/thread-1062-1-1.html 分享一: ...

    用户1173509
  • WordPress发布文章自动同步到新浪微博(带特色图片)

    整体来源于张戈博客,本处仅是修改添加了一处显示文章分类的小功能,若是一篇文章有多个分类,默认使用第一个。经测试好像对于七牛中设置了空间防盗链的不太友好,可能会报...

    汐楓
  • VMware Skyline

    一、VMware Skyline 介绍 VMware Skyline是一款创新的主动支持类产品,它为工作台带来了高性能技术和工具,从根本上改变了提供客户支持的方...

    孙杰
  • mxnet框架样本,使用C++接口

    哇塞,好久么有跟进mxnet啦,python改版了好多好多啊,突然发现C++用起来才是最爽的. 贴一个mxnet中的C++Example中的mlp网络和实现,感...

    Gxjun
  • 面试题17(以下java程序输出什么?)

    以下java程序输出什么? 有如下一段程序: public class Test{ private static int i=1; public int g...

    Java学习
  • 「 从0到1学习微服务SpringCloud 」07 RabbitMq的基本使用

    在上篇文章中,我们已经用到了MQ,用于实现配置自动刷新。接下来,就具体说说MQ的应用场景以及RabbtMq的基本使用。

    KEN DO EVERTHING

扫码关注云+社区

领取腾讯云代金券