<!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <ahref="http://nginx.org/">nginx.org</a>.<br /> Commercial support is available at <ahref="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> HTTP/1.1 405 Not Allowed Server: nginx/1.18.0 Date: Tue, 21 Apr 2020 16:28:12 GMT Content-Type: text/html Content-Length: 157 Connection: close <html> <head><title>405 Not Allowed</title></head> <body> <center><h1>405 Not Allowed</h1></center> <hr><center>nginx/1.18.0</center> </body> </html>
<!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <ahref="http://nginx.org/">nginx.org</a>.<br /> Commercial support is available at <ahref="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> HTTP/1.1 404 Not Found Server: nginx/1.18.0 Date: Tue, 21 Apr 2020 16:23:52 GMT Content-Type: text/html Content-Length: 153 Connection: keep-alive <html> <head><title>404 Not Found</title></head> <body> <center><h1>404 Not Found</h1></center> <hr><center>nginx/1.18.0</center> </body> </html>
分析 function k(e) 可知,是要对 r 参数进行签名的,r 又跟e、t、a、n 这几个参数相关,因此要搞清楚这几个参数的值是怎么来的,所有就在函数开始的第一行就下断点来跟进。
1 2 3 4 5 6 7 8 9 10 11 12
functionk(e) { const t = g() , n = m(); let a; a = e ? b(e) : {}; const r = e ? `${c.a.stringify(a.hasParams)}&${t}&time=${n}` : `&${t}&time=${n}`; return e = Object.assign({}, a.params, { sign: h()(decodeURIComponent(r)), time: n }), e }
首先是 t,跟进 g 函数,执行到 return 就可以发现 t = 年 + “5616” + 月 + 日
然后就是 n,这个 e 的值呢,根据跟进可知是 cookie 里面的,不过这个 e 在本案例的作用不大,最后通过 return 就可以知道返回的值就是:当前时间戳- e
接下来就是 a,根据返回的结果可知 a 的值和 e 相同,通过分析数据包可知,e的内容即请求参数(GET)或请求体(POST)
然后 r 的值就出来了,也就是签名的明文
综上所述 r = 请求内容 + & + t + & + n(这里的请求内容需要注意的是,POST Data是Json格式的要转换为:key1=value1&key1=value1…) 其中 t = 年 + “5616” + 月 + 日 n = 当前时间戳(本案例可不减e也可成功)
0x02 分析加密算法
将断点打在签名代码行,跟进代码的执行,发现加密的类名是 Md5,所有可以计算 r 的 md5 值,与代码执行的 sign 结果进行比较。
defrequest(self, flow): if flow.request.method == "POST": ctx.log.info(f'\n原POST请求体:{flow.request.text}') data = json.loads(flow.request.get_text()) if data != '{}'and'sign'in data: del data['sign'] del data['time'] for k in data: self.plaintext += f"{k}={str(data[k])}&" timestamp = int(time.time() * 1000) self.plaintext += f"{self.today}&time={timestamp}" self.md5()
data["sign"] = self.new_sign data["time"] = timestamp flow.request.set_text(json.dumps(data).replace(' ', '')) ctx.log.info(f'\n新POST请求体:{flow.request.text}') self.plaintext = '' else: ctx.log.info('无参数,无需改签') elif flow.request.method == "GET": ctx.log.info(f'\n原GET请求体:{flow.request.query}') query = flow.request.query if query != '{}'and'sign'in query: del query['sign'] del query['time'] if query: for k in query: self.plaintext += f"{k}={str(query[k])}&" else: self.plaintext = "&" timestamp = int(time.time()) * 1000 self.plaintext += f"{self.today}&time={timestamp}" self.md5()