流量加密编程开发 密级: 【C-1】 | 时间:2024-02-06 | 目录:博客文章 | 编辑本文 文章距今已发表三个月,请自行判断文中技术方法、代码的有效性:) ## 前言 现在国网、移动的小程序、app基本都对流量请求进行了加密。这很大程序上让渗透测试和漏洞挖掘的工作变得异常困难。根据一些挖洞经历,基本上都是通过前端的公钥进行数据加密,为了更好的去挖掘漏洞,花费几小时时间,让Un1kPoc客户端实现了RSA的流量加密传输。 ## 前期准备 简单的来梳理一下我们的业务流程: 1.前端获取公钥(publickey) 2.对请求json数据用公钥加密 3.传递给后端 4.私钥解密 5.常规的后期业务逻辑 所以我们需要做的首先是准备一个配套的公私钥。 ``` openssl genrsa -out pri.pem 1024 //生成私钥 openssl rsa -in pri.pem -pubout -out pub.pem //根据私钥生成公钥 ``` js有个库,叫jsencrypt.min.js,大致参考了一下教程,最简单的写法如下 ``` var rsa = new RSAKey(); //建立一个rsa对象 rsa.setPublic(modulus, exponent); var modulus = "***"; //生成私钥的模量 命令为 openssl rsa -in pri.pem -noout -modulu var exponent = "10001"; //设置e var res = rsa.encrypt("加密内容"); console.log(res) ``` 这里是坑点之一,本来产生加密内容非常的正常顺利。加密内容为123,123456a,测试一下,这些都没问题。直到我部署到了生产的接口时,出现了问题。 ![](https://img.meituan.net/imgupload/a460825ca472b57c54d92e4c2ca4c66620565.png) 参考了一下STACKOVERFLOW,才知道rsa加密不了长数据。而我的请求包的body是很长的,它会根据漏洞poc改变长度,我也无法确定。 解决方法: ``` JSEncrypt.prototype.encryptLong2 = function(string) { var k = this.getKey(); try { var lt = ""; var ct = ""; //RSA每次加密117bytes,需要辅助方法判断字符串截取位置 //1.获取字符串截取点 var bytes = new Array(); bytes.push(0); var byteNo = 0; var len, c; len = string.length; var temp = 0; for (var i = 0; i < len; i++) { c = string.charCodeAt(i); if (c >= 0x010000 && c <= 0x10FFFF) { byteNo += 4; } else if (c >= 0x000800 && c <= 0x00FFFF) { byteNo += 3; } else if (c >= 0x000080 && c <= 0x0007FF) { byteNo += 2; } else { byteNo += 1; } if ((byteNo % 117) >= 114 || (byteNo % 117) == 0) { if (byteNo - temp >= 114) { bytes.push(i); temp = byteNo; } } } //2.截取字符串并分段加密 if (bytes.length > 1) { for (var i = 0; i < bytes.length - 1; i++) { var str; if (i == 0) { str = string.substring(0, bytes[i + 1] + 1); } else { str = string.substring(bytes[i] + 1, bytes[i + 1] + 1); } var t1 = k.encrypt(str); ct += t1; }; if (bytes[bytes.length - 1] != string.length - 1) { var lastStr = string.substring(bytes[bytes.length - 1] + 1); ct += k.encrypt(lastStr); } return hexToBytes(ct); } var t = k.encrypt(string); var y = hexToBytes(t); return y; } catch(ex) { return false; } }; ``` 方法大致意思就是,加密的字符超过了一定长度,就以117为单位进行分段加密。 之前后端的解密代码,我用的是php,因为很简单,他解密的字段类型是十六进制字符串 ``` $encrypt_data = pack("H*", $hex_encrypt_data); ``` 我们可控的是hex_encrypt_data,但是我们的字节数组是无法传入的。于是只能前端写的方法,把字节数组转换成十六进制的字符串。 ``` function hexToBytes(hex) { for (var bytes = [], c = 0; c < hex.length; c += 2) bytes.push(parseInt(hex.substr(c, 2), 16)); return bytes; } function bytesToHex(bytes) { for (var hex = [], i = 0; i < bytes.length; i++) { hex.push((bytes[i] >>> 4).toString(16)); hex.push((bytes[i] & 0xF).toString(16)); } return hex.join(""); } ``` 我们对提交的poc进行rsa加密,把内容打印出来,通过上面两个方法,成功产生了长字符串产生的rsa加密后的字符串。于是前端的任务已经完成了,我们把注释删掉,直接进行解密。 ``` openssl_private_decrypt($encrypt_data, $decrypt_data, $private_key); ``` 这样$decrypt_data中就保存了我们的解密内容,但是测试发现结果是空的,又懵逼了。看了点资料,发现rsa对解密也有长度限制。 ![](https://img.meituan.net/imgupload/1c985790088a02e5f6eb6e48198e396514437.png) 那我就知道怎么写了,对chunks变量做128切割。然后分段解密。 ``` foreach ($chunks as $chunk) { openssl_private_decrypt($chunk, $decrypt_data, $private_key); // echo "$decrypt_data"; $data .= $decrypt_data; } echo $data; ``` 重新测试成功 ## 效果 ![](https://img.meituan.net/imgupload/371254a1bb392c4f17791d25d679e8d5200418.png) 评论列表 写评论 您的IP:3.133.134.121,临时用户名:c1a30273评论已接入DepyWAF审计与流量系统,请勿频繁操作导致IP拉黑 提交评论 © 版权声明:非标注『转载』情况下本文为原创文章,版权归 Depy's docs 所有,转载请联系博主获得授权。