前言

现在前端开发为了提高爬虫的难度及加强安全性,都会在数据包提交前进行加密,最典型的就是传参加密,相信大家在测试的时候都遇到过,那么我们在抓取数据包并修改之后,修改之后的参数无法通过后端程序数据完整性的校验,就无法进行进一步测试。如果我们逆向解析出加密的过程,就可以模拟出相同的密文,通过后端接口的校验。

最近由于工作需要,在搜索资料的时候,学到了很多爬虫大佬们的关于JS逆向、APK逆向、代码分析等方面的经验和技巧,后续会分部分记录并总结下来。

0x01 常见加密算法

比较简单的base64、hex等这些编码就不再说了。

1.1 对称加密

  • 常用算法:DES、DES3、AES

  • 根据密钥长度不同又分为:AES-128、AES-192、AES-256

  • 其中AES-192和AES-256在Java中使用需获取无政策限制权限文件

  • 加密/解密使用相同的密钥

  • 加密和解密的过程是可逆的

1.2 非对称加密

  • 常用算法:RSA

  • 使用公钥加密,使用私钥解密

  • 公钥是公开的,私钥保密

  • 加密处理安全,但是性能极差,单次加密长度有限制

  • RSA既可用于数据交换,也可用于数据校验

  • 数据校验通常结合消息摘要算法 MD5withRSA 等

两种加密算法常见结合套路:1、随机生成密钥2、密钥用于AES/DES/3DES加密数据3、RSA对密钥加密4、提交加密后的密钥和加密后的数据给服务器

1.3 信息摘要算法/签名算法

  • 常用算法:MD5、HMAC(HmacMD5、HmacSHA1、HmacSHA256)、SHA(SHA1、SHA256、SHA512)

  • 不管明文多长,散列后的密文定长

  • 明文不一样,散列后结果一定不一样

  • 散列后的密文不可逆

  • 一般用于校验数据完整性、签名 sign

  • 由于密文不可逆,所以后台无法还原,也就是说他要验证,会在后台以跟前台一样的方式去重新签名一遍。也就是说他会把源数据和签名后的值一起提交到后台。所以我们要保证在签名时候的数据和提交上去的源数据一致,这种算法特喜欢在内部加入时间戳

0x02 JS逆向流程

以登录为例的基本流程:
  1. 如果网页有跳转,必须勾选preserve log(F12-Network)防止丢包

  2. 看一下有没有框架,右键查看框架源代码(弹出式登陆界面)

  3. 登陆尽量使用错误密码,防止跳转

  4. 查看关键登陆包,分析哪些参数是加密的

  5. 使用别的浏览器分析哪些参数是固定的值

  6. 初步猜测加密的方法

  7. 搜索

  • 直接搜索参数,比如:pwd=pwd =pwd:pwd :

  • 密码框地方右键 检查 查看 id name type

找到加密的地方(重点)

进行代码调试

找出所有的加密代码

  • 从最后一步开始写起,缺啥找啥

  • 如果找的是函数的话,search 要带上 function xxx

  • 如果看到加密的地方有个类,并且之后是用 prototype 把方法加在原生对象上的话,要把 所有加在原生对象上的方法都找出来

  • 函数找多了没关系,只要不报错不会影响结果,但是不能找少了

0x03 实例操作

打开网站,抓包

修改个数据,比如修改num为1000

有些杠精该说了:我渗透测试改这有毛用。

是没用,只是以此为例。。。

可以看到,修改过参数数据后,后端数据校验之后不合法,所以没有返回数据。

打开测试网站 -> F12控制台 -> 切换至 XHR

这里我们看下需要做的有什么?

  1. 请求中有token(t明显是时间戳),token和数据不匹配后端不返回数据

  2. 返回的数据是加密的,需要解密

接下来我们就定位具体的加密函数和解密函数。

按照上面提到的流程步骤

打开控制台 -> source ->搜索

搜索加密参数名 token

根据搜索结果的文件名判断,基本上就是第二个文件,点击打开

token的生成代码

var token = md5(String(page) + String(num) + String(timestamp));

设置断点,刷新

成功进入断点,没毛病了

根据加密函数,编写脚本

可以看到,生成的token和URL中的一致,至此,加密部分完成。

解密部分同样的道理,搜索返回包中的参数,直接搜索list发现有点多,不太好观察,还有一种方法

可以看到数据部分html的id为ip-list,再次搜索

成功找到解密数据包的代码

设置断点,进一步确认

没毛病,可以看到decode_str后就开始出现我们需要的明文数据了,所以这里的 decode_str 就是我们要的解密方法。剩下就是分析代码,编写解密脚本了。

function decode_str(scHZjLUh1) {    scHZjLUh1 = Base64["\x64\x65\x63\x6f\x64\x65"](scHZjLUh1);    key = '\x6e\x79\x6c\x6f\x6e\x65\x72';    len = key["\x6c\x65\x6e\x67\x74\x68"];    code = '';    for (i = 0; i < scHZjLUh1["\x6c\x65\x6e\x67\x74\x68"]; i++) {        var coeFYlqUm2 = i % len;        code += window["\x53\x74\x72\x69\x6e\x67"]["\x66\x72\x6f\x6d\x43\x68\x61\x72\x43\x6f\x64\x65"](scHZjLUh1["\x63\x68\x61\x72\x43\x6f\x64\x65\x41\x74"](i) ^ key["\x63\x68\x61\x72\x43\x6f\x64\x65\x41\x74"](coeFYlqUm2))    }    return Base64["\x64\x65\x63\x6f\x64\x65"](code)}

先运行下看看

报错,提示Base64未定义,设置断点,找到Base64的具体代码

复制粘贴进代码,再次运行

艹,提示Windows未定义,根据流程,缺啥补啥,debug,找对应的值

可以看到分别对应的是StringfromCharCode

那就是调用了String.fromCharCode方法了,替换掉,再次运行

bingo~

成功解密获取到明文数据。

0x04 Python实现加密方法合集

关于上述第一部分的常见加密算法,GitHub有对应的仓库,直接可以用的

GitHub:https://github.com/dhfjcuff/R-A-M-D-D3-S-M-H/

# -*- coding:utf-8 -*-import base64import rsafrom Crypto.Cipher import AESfrom Crypto.PublicKey import RSAfrom pyDes import des, CBC, PAD_PKCS5from Crypto.Cipher import DES3import hashlibimport hmacclass USE_AES:    """    AES    除了MODE_SIV模式key长度为:32, 48, or 64,    其余key长度为16, 24 or 32    详细见AES内部文档    CBC模式传入iv参数    本例使用常用的ECB模式    """    def __init__(self, key):        if len(key) > 32:            key = key[:32]        self.key = self.to_16(key)    def to_16(self, key):        """        转为16倍数的bytes数据        :param key:        :return:        """        key = bytes(key, encoding="utf8")        while len(key) % 16 != 0:            key += b'\0'        return key  # 返回bytes    def aes(self):        return AES.new(self.key, AES.MODE_ECB) # 初始化加密器    def encrypt(self, text):        aes = self.aes()        return str(base64.encodebytes(aes.encrypt(self.to_16(text))),                   encoding='utf8').replace('\n', '')  # 加密    def decodebytes(self, text):        aes = self.aes()        return str(aes.decrypt(base64.decodebytes(bytes(            text, encoding='utf8'))).rstrip(b'\0').decode("utf8"))  # 解密class USE_RSA:    """    生成密钥可保存.pem格式文件    1024位的证书,加密时最大支持117个字节,解密时为128;    2048位的证书,加密时最大支持245个字节,解密时为256。    加密大文件时需要先用AES或者DES加密,再用RSA加密密钥,详细见文档    文档:https://stuvel.eu/files/python-rsa-doc/usage.html#generating-keys    """    def __init__(self, number=1024):        """        :param number: 公钥、私钥        """        self.pubkey, self.privkey = rsa.newkeys(number)    def rsaEncrypt(self, text):        """        :param test: str        :return: bytes        """        content = text.encode('utf-8')        crypto = rsa.encrypt(content, self.pubkey)        return crypto        def rsaDecrypt(self, text):        """        :param text:bytes         :return: str        """        content = rsa.decrypt(text, self.privkey)        con = content.decode('utf-8')        return con            def savePem(self, path_name, text):        """        :param path_name: 保存路径        :param text: str        :return:bytes        """        if "PEM" in path_name.upper():            path_name = path_name[:-4]        with open('{}.pem'.format(path_name), 'bw') as f:            f.write(text.save_pkcs1())    def readPem(self, path_name, key_type):        """        :param path_name: 密钥文件        :param key_type:类型         :return:         """        if 'pubkey' in key_type:            self.pubkey = rsa.PublicKey.load_pkcs1(path_name)        else:            self.privkey = rsa.PublicKey.load_pkcs1(path_name)        return True    def sign(self, message, priv_key=None, hash_method='SHA-1'):        """        生成明文的哈希签名以便还原后对照        :param message: str        :param priv_key:        :param hash_method: 哈希的模式        :return:        """        if None == priv_key:            priv_key = self.privkey        return rsa.sign(message.encode(), priv_key, hash_method)    def checkSign(self, mess, result, pubkey=None):        """        验证签名:传入解密后明文、签名、公钥,验证成功返回哈希方法,失败则报错        :param mess: str        :param result: bytes        :param pubkey:         :return: str        """        if None == pubkey:            pubkey = self.privkey        try:            result = rsa.verify(mess, result, pubkey)            return result        except:            return Falseclass USE_DES:    """    des(key,[mode], [IV], [pad], [pad mode])    key:必须正好8字节    mode(模式):ECB、CBC    iv:CBC模式中必须提供长8字节    pad:填充字符    padmode:加密填充模式PAD_NORMAL or PAD_PKCS5    """    def __init__(self, key, iv):        if not isinstance(key, bytes):            key = bytes(key, encoding="utf8")        if not isinstance(iv, bytes):            iv = bytes(iv, encoding="utf8")        self.key = key        self.iv = iv    def encrypt(self, text):        """        DES 加密        :param text: 原始字符串        :return: 加密后字符串,bytes        """        if not isinstance(text, bytes):            text = bytes(text, "utf-8")        secret_key = self.key        iv = self.iv        k = des(secret_key, CBC, iv, pad=None, padmode=PAD_PKCS5)        en = k.encrypt(text, padmode=PAD_PKCS5)        return en    def descrypt(self, text):        """        DES 解密        :param text: 加密后的字符串,bytes        :return:  解密后的字符串        """        secret_key = self.key        iv = self.iv        k = des(secret_key, CBC, iv, pad=None, padmode=PAD_PKCS5)        de = k.decrypt(text, padmode=PAD_PKCS5)        return de.decode()class USE_DES3:    """    new(key, mode, *args, **kwargs)    key:必须8bytes倍数介于16-24    mode:    iv:初始化向量适用于MODE_CBC、MODE_CFB、MODE_OFB、MODE_OPENPGP,4种模式        ``MODE_CBC``, ``MODE_CFB``, and ``MODE_OFB``长度为8bytes        ```MODE_OPENPGP```加密时8bytes解密时10bytes        未提供默认随机生成    nonce:仅在 ``MODE_EAX`` and ``MODE_CTR``模式中使用            ``MODE_EAX``建议16bytes            ``MODE_CTR``建议[0, 7]长度            未提供则随机生成    segment_size:分段大小,仅在 ``MODE_CFB``模式中使用,长度为8倍数,未指定则默认为8    mac_len:适用``MODE_EAX``模式,身份验证标记的长度(字节),它不能超过8(默认值)    initial_value:适用```MODE_CTR```,计数器的初始值计数器块。默认为**0**。    """    def __init__(self, key):        self.key = key        self.mode = DES3.MODE_ECB    def encrypt(self, text):        """        传入明文        :param text:bytes类型,长度是KEY的倍数        :return:        """        if not isinstance(text, bytes):            text = bytes(text, 'utf-8')        x = len(text) % 8        text = text+b'\0'*x        cryptor = DES3.new(self.key, self.mode)        ciphertext = cryptor.encrypt(text)        return ciphertext    def decrypt(self, text):        cryptor = DES3.new(self.key, self.mode)        plain_text = cryptor.decrypt(text)        st = str(plain_text.decode("utf-8")).rstrip('\0')        return stdef USE_MD5(test):    if not isinstance(test, bytes):        test = bytes(test, 'utf-8')    m = hashlib.md5()    m.update(test)    return m.hexdigest()def USE_HMAC(key, text):    if not isinstance(key, bytes):        key = bytes(key, 'utf-8')    if not isinstance(text, bytes):        text = bytes(text, 'utf-8')    h = hmac.new(key, text, digestmod='MD5')    return h.hexdigest()def USE_SHA(text):    if not isinstance(text, bytes):        text = bytes(text, 'utf-8')    sha = hashlib.sha1(text)    encrypts = sha.hexdigest()    return encryptsif __name__ == '__main__':    aes_test = USE_AES("assssssssdfasasasasa")    a = aes_test.encrypt("测试")    b = aes_test.decodebytes(a)    rsa_test = USE_RSA()    a = rsa_test.rsaEncrypt("测试加密")    b = rsa_test.rsaDecrypt(a)    des_test = USE_DES(b"12345678", b"12345678")    a = des_test.encrypt("测试加密")    b = des_test.descrypt(a)    des3_test = USE_DES3(b"123456789qazxswe")    a = des3_test.encrypt("测试加密")    b = des3_test.decrypt(a)    md5_test = USE_MD5("测试签名")    hmac_test = USE_HMAC("123456", "测试")    sha_test = USE_SHA("测试加密")

参考资料

公众号:咸鱼学python

公众号:小周码字

hikaridatasource 加密后登陆不上_渗透测试 | 突破前端JS加密限制相关推荐

  1. hikaridatasource 加密后登陆不上_python测试开发django42.auth模块登陆认证

    前言 在开发一个网站时,经常会用到用户的注册和登陆相关的账号管理功能,auth模块是Django提供的标准权限管理系统,可以提供用户身份认证, 用户组和权限管理. 像用户注册.用户登录.用户认证.注销 ...

  2. form标签的action之前 加密_口令爆破之突破前端JS加密

    0x00 前言 近期安全测试时发现一个系统前台使用了SSO,但是在比较隐蔽API中发现了后台的登录接口,该接口未使用SSO,同时没有图形验证码等校验,通过分析最终爆破进入后台. 0x01 确认攻击途径 ...

  3. 2022年全国职业院校技能大赛“网络安全”竞赛试题文件上传渗透测试答案Flag

    B-9任务九:文件上传渗透测试 *任务说明:仅能获取Server9的IP地址 1.通过渗透机Kali2.0对服务器场景Server9进行网站目录暴力枚举测试(使用工具DirBuster,扫描服务器80 ...

  4. 中职网络安全竞赛设备-----文件上传渗透测试

    经典赛题-文件上传渗透测试 渗透机:(Kali Linux1)用户名:root 密码:toor 渗透机:(Kali Linux2)用户名:root 密码:toor 靶   机:(Windows 7)用 ...

  5. 加密后变成乱码解密_个人磁盘加密软件,使用VeraCrypt进行整盘加密介绍

    为了加强日常工作文档的管控,需要对个人PC上的文件进行加密存储,防止电脑.硬盘.U盘等存储介质丢失,导致数据泄露. 市面上基于文件夹加密的工具软件,大多数采用的是隐藏文件或者隔离文件的方式进行加密存储 ...

  6. 输入一个四位数将其加密后输出c语言,输入一个四位数,将其加密后输出.方法是将该数每一位的数字加9,然后除以10取余作为该位上的新数字,最后将千位上的数字和十...

    问题描述: 输入一个四位数,将其加密后输出.方法是将该数每一位的数字加9,然后除以10取余作为该位上的新数字,最后将千位上的数字和十位上的数字互换,组成加密后的新四位数. #include int m ...

  7. screnc加密后文件不能执行_芯片加密后还能不能再次使用【详细介绍】

    随着信息技术的发展,信息的载体-芯片的运用也越来越多了,随之而来的芯片安全性的要求也越来越高了,各个芯片厂商对芯片保密性要求越来越高,芯片的加密,保证了芯片中的信息的安全性.经常有客户打电话过来问,这 ...

  8. sql server ssl安全错误_渗透测试 丨 SQL注入的攻与防

    " 注入攻击漏洞,例如SQL,OS以及LDAP注入.这些攻击发生在当不可信的数据作为命令或者查询语句的一部分,被发送给解释器的时候.攻击者发送的恶意数据可以欺骗解释器,以执行计划外的命令或者 ...

  9. 复检网站_渗透测试项目分析手段

    最近我们Sinesafe参加的几家机构的渗透测试防守方防护方案评估复查,部分防守方缺乏对攻击者的正确认知,攻击者的手法已经比较高超了,不扫描,不落地,污染日志等都很普及了.同时也要正确认知对手:攻防演 ...

最新文章

  1. flask中使用Flask-SQLALCHEMY-------一个简单的例子
  2. 小白搞懂了GC全过程,全靠阿里专家12张图
  3. isa 2006 下发布 owa
  4. QT的QMessageAuthenticationCode类的使用
  5. window.addeventlistener 不能调用方法_Java入门第十四课:如何定义”方法“
  6. git push到GitHub的时候遇到! [rejected] master -> master (non-fast-forward)的问题
  7. Metro 应用无法打开解决办法
  8. 计算机实训教学论文,计算机实训教学探索论文
  9. 2007年8月25日华为的几个面试题
  10. JetBrains(Intellij, pycharm)多行编辑模式
  11. 【TSP】基于matlab遗传算法求解中国35省会城市旅行商问题【含Matlab源码 1222期】
  12. 开源生产排程aps软件dream设计思路分析
  13. 树莓派的GPIO等接口
  14. 《机器学习》总结与心得
  15. 如何让你的YOLOV3模型更小更快?
  16. matlab中zeros()函数
  17. JQuery字符串文本替换并且加样式
  18. Linux C获取当前时间(精确到微秒)
  19. 智能AR场景模拟书法临摹系统
  20. 如何在android设备上insmod自己单独编译的.ko,解决签名问题

热门文章

  1. 使用Linq判断DataTable数据是否重复
  2. Oracle中Cursor介绍
  3. retargeting PHP,Retargeting the Animation 教学
  4. 已解决AttributeError set object has no attribute items(亲测)
  5. Kibana停止kibana的方法命令:找到5601端口对应的进程ID 把此进程进行kill即可
  6. 反思快速完成功能代码
  7. Linux之ubuntu的网卡配置
  8. Go的RESTful
  9. mt4服务器显示无连接,mt4怎样连接服务器地址
  10. 大大提高你的工作效率的Linux 技巧