目标网站:
http://60.173.254.126/
这算是一个列表页,展示了一些小区,然后单击小区跳转到小区详情,但是跳转链接被加密了,是通过JS算出来的:
本篇文章的目标就是破解这个加密。
二、分析
上一小节的图里可以看到,在单击链接的时候绑定了一个事件reurl,在开发者工具的console上输入reurl并回车:
拿到代码:
function reurl(a) { a.href = "/item/" + recode(a.id) }
可以看到在这里修改了链接的地址,用到了链接里的一个id属性:
<a id="2714" style="cursor:pointer" onclick="reurl(this)" target="_blank" title="清樾园">清樾园</a>
同时id的解密还依赖了recode,同样的套路拿到它的代码:
function recode(a) { var n = nscaler(a); var c = SetObjNum(String(a).length); var d = SetObjNum(String(a).length); n = parseInt(n) + parseInt(d); var b = $("#iptstamp").val(); b = nscaler(b.toString()); return c + "-" + n + "-" + d + "-" + b }
这个方法中依赖了两个方法和一个dom元素,先看nscaler,用同样的方法从console跟进去拿到它的代码:
function nscaler(a) { var b = ""; var ar = String(a).split(''); $.each(ar, function (i, e) { switch (e) { case "0": b += "0"; break; case "1": b += "2"; break; case "2": b += "5"; break; case "3": b += "8"; break; case "4": b += "6"; break; case "5": b += "1"; break; case "6": b += "3"; break; case "7": b += "4"; break; case "8": b += "9"; break; case "9": b += "7"; break } }); return b }
从逻辑上看,这个方法是将字符串使用一个映射表映射为一个新的值:
{ 0: 0, 1: 2, 2: 5, 3: 8, 4: 6, 5: 1, 6: 3, 7: 4, 8: 9, 9: 7, }
然后是SetObjNum,从console跟进去拿到源码,注意到跟进去的时候tab的标题是VMxxx格式的,说明可能是eval定义的:
function SetObjNum(n) { var a = ""; for (var i = 0; i < n; i++) a += Math.floor(Math.random() * 10); return a }
这个方法就是生成一个随机数,然后是$("#iptstamp").val();,在页面源代码:
view-source:http://60.173.254.126/
中搜索iptstamp可以找到,这就是服务器返回的一个时间戳:
至此,所有逻辑已经捋清楚,接下来就是编码实现。
三、编码实现
#!/usr/bin/env python3 # encoding: utf-8 """ @author: CC11001100 """ import random import requests from bs4 import BeautifulSoup def crawl(): url = "http://60.173.254.126/" html = requests.get(url).text doc = BeautifulSoup(html, features="html.parser") iptstamp = doc.select_one("#iptstamp")["value"] r = {} for x in doc.select("a[id][onclick][title][style]"): id = x["id"] link = "http://60.173.254.126/item/" + recode(id, iptstamp) title = x["title"] r[title] = link return r def recode(s, iptstamp): n = nscaler(s) c = set_obj_num(len(n)) d = set_obj_num(len(n)) n = int(n) + int(d) b = nscaler(iptstamp) return str(c) + "-" + str(n) + "-" + str(d) + "-" + str(b) def set_obj_num(n): r = 0 for _ in range(0, n): r += int(random.random() * 10) return r def nscaler(s): mapping = { 0: 0, 1: 2, 2: 5, 3: 8, 4: 6, 5: 1, 6: 3, 7: 4, 8: 9, 9: 7, } result = 0 for x in s: result = result * 10 + mapping[int(x)] return str(result) if __name__ == "__main__": print(crawl())
运行效果:
经验证无误。
本作品采用知识共享署名 4.0 国际许可协议进行许可。