本文是高级前端加解密与验签实战的第6篇文章,本系列文章实验靶场为Yakit里自带的Vulinbox靶场,本文讲述的是绕过RSA加密来爆破登录。
分析
这里的代码跟上文的类似,但是加密的公钥是通过请求服务端获取的
http://127.0.0.1:8787/crypto/js/rsa/generator
由于密钥是服务端生产的,服务端有公私钥信息,所以自然不需要传递公私钥了。
请求格式如下,只有被加密的内容:
序列+热加载
序列
打开Yakit的Web Fuzzer,点击左侧的序列
选择从服务端获取密钥的那个数据包
使用数据提取器提取公钥
提取结果正常:
再添加序列:
先把请求体置空,编写热加载代码
热加载
本来之前写的是请求体格式跟上文一样,然后在热加载里请求来获取密钥,缺点也显而易见,每次登录请求都会多出了一个请求公钥的数据包,所以最后选择用Yakit的序列配合热加载标签传参来加密。
由于Yakit热加载标签只能传一个参数,这里感谢Yakit群群友Gun的帮助,给了我一个手动分割参数的函数。
把序列第一个请求提取到的publicKey
变量和需要加密的数据传过去,由splitParams
分割,然后传参给encrypt
进行RSA加密。
序列格式:
{{yak(splitParams|{{p(publicKey)}}|{"username":"admin","password":"admin123","age":"20"})}}
热加载代码:
encrypt = (pemPublic, data) => { data = codec.RSAEncryptWithOAEP(pemPublic /*type: []byte*/, data)~ data = codec.EncodeBase64(data) body = f`{"data":"${data}"}` return body } //分割传过来的参数,每个参数中间以|分隔 splitParams = (params) => { pairs := params.SplitN("|", 2) return encrypt(pairs[0], pairs[1]) }
执行序列,爆破成功,使用序列的好处就是只获取一次公钥即可。
之前的代码:
弃用代码,就不做解释了。
getPubkey = func(host) { //通过请求动态获取公钥 rsp, req = poc.HTTP(f`GET /crypto/js/rsa/generator HTTP/1.1 Host: ${host} `)~ body = poc.GetHTTPPacketBody(rsp) // 响应体 params = json.loads(body) publicKey = str.ReplaceAll(params.publicKey, r"n", "n") println(publicKey) return publicKey } encryptData = (packet) => { body = poc.GetHTTPPacketBody(packet) host = poc.GetHTTPPacketHeader(packet, "Host") pemBytes = getPubkey(host) // 获取公钥 println(pemBytes) data = codec.RSAEncryptWithOAEP(pemBytes /*type: []byte*/, body)~ data = codec.EncodeBase64(data) body = f`{"data":"${data}"}` return string(poc.ReplaceBody(packet, body, false)) } //发送到服务端修改数据包 // beforeRequest = func(req){ // return encryptData(req) // } //调试用 packet = <<<TEXT POST /crypto/js/rsa/fromserver HTTP/1.1 Host: 127.0.0.1:8787 Content-Type: application/json Content-Length: 179 {"username":"admin","password":"123456","age":"20"} TEXT result = (encryptData(packet)) print(result)