javascript代码混淆与加解密方式

 更新时间:2023年06月03日 16:00:10   作者:nginx123  
这篇文章主要介绍了javascript代码混淆与加解密方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

javascript代码混淆与加解密

开发一个python的程序,功能很简单,对某个网页发送post请求,把response的结果解析后存入数据库,供后续分析。

抓包

首先是抓包,使用burp suite,发现该网页原始的post请求如下:

因存在隐私信息,部分字段值已修改

uid=487f764baab641be902f4dxxxxxxxxx&timestamp=1596436610125&sign=iNtdr75WKc7VHmbn8pu4VLqddoLEhupmin6LSi8vj%2Bn%2FyJ0zHlu34LVqQojiN4K6OoB6ggz0Q5NSx6rxxxxxxx%3D%3D

uid应该是该用户的id,timestamp为当前时间戳,很好理解,sign暂时不去管它。

在burp里,使用repeat重新发包,修改timestamp时间戳字段后,无法收到response,怀疑sign为验证标识。

继续使用原来的时间戳,可以收到response包,但是一段时间后,时间戳失效,不再能收到response。

分析如下:

网站为了防止DDOS攻击,设置了请求验证,通过加密算法把用户id和当前时间戳进行加密后,放入sign字段中。在服务器端解密后验证,如验证通过,返回response,验证不通过,丢弃请求包。

timestamp字段应该是用于sign有效期判断,超过一定时间,该sign失效。

代码审计

打开网页源代码,发现加密js代码:

<!-- 加密start-->
<script src="js/httpUtil.min.js"></script>
<script type="text/javascript" src="plugins/CryptoJSv3.1.2/rollups/tripledes.js"></script>
<script type="text/javascript" src="plugins/CryptoJSv3.1.2/components/mode-ecb-min.js"></script>
<script src="plugins/bootstrap-table-1.11.0/bootstrap-table.min.js"></script>
<script src="plugins/bootstrap-table-1.11.0/locale/bootstrap-table-zh-CN.min.js"></script>
<script src="plugins/jquery.tmpl.min.js"></script>
<script src="plugins/DESUtil.min.js"></script>

打开最后一个js文件,内容如下:

eval(function(p, a, c, k, e, d) {
    e = function(c) {
        return (c < a ? "": e(parseInt(c / a))) + ((c = c % a) > 35 ? String.fromCharCode(c + 29) : c.toString(36))
    };
    if (!''.replace(/^/, String)) {
        while (c--) d[e(c)] = k[c] || e(c);
        k = [function(e) {
            return d[e]
        }];
        e = function() {
            return '\\w+'
        };
        c = 1;
    };
    while (c--) if (k[c]) p = p.replace(new RegExp('\\b' + e(c) + '\\b', 'g'), k[c]);
    return p;
} ('3 T(e,t,n){t=G==t||""==t||D 0===t?{A:(9 b).B()}:t;5 r=(9 b).x();t.v=r;5 o=f(d(t));t.u=o,$.s({w:"l",i:t,J:e,P:"R",m:3(e){},p:3(e){n(e)},k:3(e,t){},z:3(e){}})}3 Q(e,t,n){t=G==t||""==t||D 0===t?{A:(9 b).B()}:t;5 r=(9 b).x();t.v=r;5 o=f(d(t));t.u=o,$.s({w:"l",i:t,J:e,14:!1,10:!1,11:!1,m:3(e){},p:3(e){n(e)},k:3(e,t){},z:3(e){}})}5 c="12",7="Z";3 f(e){5 t=2.4.8.6(c),n=2.4.8.6(7);h y=2.j.13(e,t,{7:n,a:2.a.E,I:2.L.O}),2.4.q.U(y.K)}3 W(e){e=2.4.q.6(e).N();5 t=2.4.8.6(c),n=2.4.8.6(7);h 2.j.S({K:2.4.V.6(e)},t,{7:n,a:2.a.E,I:2.L.O}).N(2.4.8)}3 d(e){5 t="",n=[];H(M C e)n[n.F]=M;H(g C n.Y(),n)t=t+n[g]+"="+e[n[g]]+",";h t=t.X(0,t.F-1)}', 62, 67, '||CryptoJS|function|enc|var|parse|iv|Utf8|new|mode|Date|key|mapSortToString||encryptByDESModeCBC|value|return|data|DES|complete|post|beforeSend|||success|Base64||ajax||sign|timestamp|type|valueOf|encrypted|error|date|getTime|in|void|CBC|length|null|for|padding|url|ciphertext|pad|thisKey|toString|Pkcs7|dataType|ajaxDESWebUploadImg|json|decrypt|ajaxDESWeb|stringify|Hex|decryptByDESModeCBC|substring|sort|asdewqrf|processData|contentType|keycansr|encrypt|cache'.split('|'), 0, {}))

我们看到有这部分代码

while(c–)if(k[c])p=p.replace(new RegExp('\b'+e©+'\b',‘g'),k[c]);return p;

这个是标准的javascript混淆加密压缩

用document.getElementById(‘textareaID’).innerText=p; 替代 return p;

放入普通html文件的body部分打开,得到javascript代码如下:

function ajaxDESWeb(e, t, n) {
    t = null == t || "" == t || void 0 === t ? {
        date: (new Date).getTime()
    }: t;
    var r = (new Date).valueOf();
    t.timestamp = r;
    var o = encryptByDESModeCBC(mapSortToString(t));
    t.sign = o,
    $.ajax({
        type: "post",
        data: t,
        url: e,
        dataType: "json",
        beforeSend: function(e) {},
        success: function(e) {
            n(e)
        },
        complete: function(e, t) {},
        error: function(e) {}
    })
}
function ajaxDESWebUploadImg(e, t, n) {
    t = null == t || "" == t || void 0 === t ? {
        date: (new Date).getTime()
    }: t;
    var r = (new Date).valueOf();
    t.timestamp = r;
    var o = encryptByDESModeCBC(mapSortToString(t));
    t.sign = o,
    $.ajax({
        type: "post",
        data: t,
        url: e,
        cache: !1,
        processData: !1,
        contentType: !1,
        beforeSend: function(e) {},
        success: function(e) {
            n(e)
        },
        complete: function(e, t) {},
        error: function(e) {}
    })
}
var key = "keycansr",
iv = "asdewqrf";
function encryptByDESModeCBC(e) {
    var t = CryptoJS.enc.Utf8.parse(key),
    n = CryptoJS.enc.Utf8.parse(iv);
    return encrypted = CryptoJS.DES.encrypt(e, t, {
        iv: n,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    }),
    CryptoJS.enc.Base64.stringify(encrypted.ciphertext)
}
function decryptByDESModeCBC(e) {
    e = CryptoJS.enc.Base64.parse(e).toString();
    var t = CryptoJS.enc.Utf8.parse(key),
    n = CryptoJS.enc.Utf8.parse(iv);
    return CryptoJS.DES.decrypt({
        ciphertext: CryptoJS.enc.Hex.parse(e)
    },
    t, {
        iv: n,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    }).toString(CryptoJS.enc.Utf8)
}
function mapSortToString(e) {
    var t = "",
    n = [];
    for (thisKey in e) n[n.length] = thisKey;
    for (value in n.sort(), n) t = t + n[value] + "=" + e[n[value]] + ",";
    return t = t.substring(0, t.length - 1)
}

注意到以下代码

o = encryptByDESModeCBC(mapSortToString(t));
    t.sign = o,

sign是通过这里得到的

继续寻找encryptByDESModeCBC和mapSortToString

看到mapSortToString是把uid和timestamp用逗号分隔的等式拼接后,用CryptoJS的加解密库进行DES加密

从js代码中还可以看到加解密使用的key和IV

var key = "keycansr",
iv = "asdewqrf";

解密验证

为了验证我们代码审计的结论,把抓包的sign用python进行DES解密

代码如下:

myDes.py

from Crypto.Cipher import DES
import base64
class DESUtil:
    __BLOCK_SIZE_8 = BLOCK_SIZE_8 = DES.block_size
    __IV = "asdewqrf" # __IV = chr(0)*8
    @staticmethod
    def encryt(str, key):
        cipher = DES.new(key, DES.MODE_CBC, DESUtil.__IV)
        x = DESUtil.__BLOCK_SIZE_8 - (len(str) % DESUtil.__BLOCK_SIZE_8)
        if x != 0:
            str  = str + chr(x)*x
        msg = cipher.encrypt(str)
        # msg = base64.urlsafe_b64encode(msg).replace('=', '')
        msg = base64.b64encode(msg)
        return msg
    @staticmethod
    def decrypt(enStr, key):
        cipher = DES.new(key, DES.MODE_CBC,DESUtil.__IV)
        # enStr += (len(enStr) % 4)*"="
        # decryptByts = base64.urlsafe_b64decode(enStr)
        decryptByts = base64.b64decode(enStr)
        msg = cipher.decrypt(decryptByts)
        print(msg)
        print(len(msg))
        print(msg[len(msg)-1])
        #paddingLen = ord((msg[len(msg)-1]))
        paddingLen = msg[len(msg) - 1]
        return msg[0:-paddingLen]
if __name__ == "__main__":
    mySign = 'iNtdr75WKc7VHmbn8pu4VLqddoLEhupmin6LSi8vj%2Bn%2FyJ0zHlu34LVqQojiN4K6OoB6ggz0Q5NSx6rxxxxxxx=='
    key = 'keycansr'
    print(DESUtil.decrypt(mySign, key)

执行结果如下:

b'timestamp=1596436610125,uid=487f764baab641be902f4dxxxxxxxxx'

验证了我们之前代码审计的结论

构造POST请求

知道加解密算法后,很容易就构造POST请求

代码如下:

sendHttps.py
import requests
import time
from myDes import *
from requests.packages import urllib3
urllib3.disable_warnings()
uuid = '487f764baab641be902f4dxxxxxxxxx'
ttime = time.time()*1000
key='keycansr'
sstr = "timestamp="+str(ttime)+',uid='+uuid
ssign = DESUtil.encryt(sstr, key)
#print(ssign)
data = {'uid':uuid, 'timestamp':ttime, 'sign':ssign}
req = requests.post('https://xxxx.com/api/user/userAccount/list',data=data,verify=False)
print(req.text)

后续就是对req.text的内容进行json解码和正则分析,然后插入到PostgreSQL的数据库中进行分析。

js代码混淆处理办法

将JavaScript 代码转换成颜文字网络表情的编码已达到混淆的目的

原理:这类混淆通常都是使用构造函数将字符串作为代码运行

例如:

const sum = new Function('a','b','return a+b');
console.log(sum(2,6));

解决方法:

1.直接将混淆后的代码粘贴到控制台通过VM 查看源代码 只对报错代码有效

2.对于在控制台输出不报错的代码,

第一种方法:删除代码结尾的“(’_’);”

第二种方法:删除后替换为“toString()”方法输出,再将修改后的代码粘贴至控制台运行

将JavaScript 代码转换成只有6种字符([, ], (, ), !, +)的编码

以达到混淆的目的

例如:

‘0':'[+[]]'
‘1':'[+!+[]]'
…

解决方法:

1.直接将混淆后的代码粘贴至控制台通过查看VM查看源代码

2.代码最后有成对的括号,删除代码结尾的‘()’ ;或者替换为 ‘toString()’ 或将修改后的代码粘贴至控制台运行。

3.代码最后没有成对括号,只有列如‘)’这种,将代码通过https://beautifier.io/ 这个网站美化以后,复制到编辑器中,通过最后一个括号找到前面括号,把括号之中的代码复制出来,在控制带输出就会得到源码

通过eval()编码的代码

解决方法:

将eval 中的代码复制出来,更改为alert / document.write / console.log 在控制台输出就能解密

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 用director.js实现前端路由使用实例

    用director.js实现前端路由使用实例

    本篇文章主要介绍了director.js实现前端路由,在不刷新的情况下,利用“#”号组织不同的URL路径,并根据不同的URL路径进行不同的方法调用。有兴趣的了解一下。
    2017-01-01
  • Javascript技术技巧大全(五)

    Javascript技术技巧大全(五)

    Javascript技术技巧大全(五)...
    2007-01-01
  • js 如何实现对数据库的增删改查

    js 如何实现对数据库的增删改查

    JavaScript操作数据库JS操作Access数据库,跟其他语言操作差不多,总结了一下习惯代码,需要的朋友可以参考下
    2012-11-11
  • js脚本分页代码分享(7种样式)

    js脚本分页代码分享(7种样式)

    这篇文章主要介绍了7种JS脚本分页样式,推荐给大家,有需要的小伙伴可以参考下。
    2015-08-08
  • ECharts formatter属性设置的3种方法(字符串模板,函数模板,回调函数)

    ECharts formatter属性设置的3种方法(字符串模板,函数模板,回调函数)

    formatter有两种写法,一种字符串模板,另一种是回调函数,下面这篇文章主要给大家介绍了关于ECharts formatter属性设置的3种方法,分别是字符串模板,函数模板,回调函数,需要的朋友可以参考下
    2023-02-02
  • JS实现小球的弹性碰撞效果

    JS实现小球的弹性碰撞效果

    这篇文章主要介绍了JS实现小球的弹性碰撞效果 ,代码简单易懂,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2017-11-11
  • js实现jquery的offset()方法实例

    js实现jquery的offset()方法实例

    这篇文章主要介绍了js实现jquery的offset()方法,实例分析了jquery的offset()方法原理与采用javascript实现的技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-01-01
  • 详解js私有作用域中创建特权方法

    详解js私有作用域中创建特权方法

    这篇文章主要为大家详细介绍了js私有作用域中创建特权方法,何为特权方法,特权方法就是有权访问私有变量和私有函数的公有方法,感兴趣的小伙伴们可以参考一下
    2016-01-01
  • js 获取扫码枪输入数据的方法

    js 获取扫码枪输入数据的方法

    这篇文章主要介绍了js 获取扫码枪输入数据的方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-06-06
  • js 中的柯里化与反柯里化的基础概念和用法

    js 中的柯里化与反柯里化的基础概念和用法

    柯里化是将接受多个参数的函数转换成一系列只接受单个参数的函数的过程,而反柯里化是将柯里化函数转换成接受多个参数的函数的过程,本文将带大家理解 js 中的柯里化与反柯里化,需要的朋友可以参考下
    2023-07-07

最新评论