難度: ★☆☆☆☆ 1星
一、目標
目標網站:
這算是一個列表頁,展示了一些小區,然后單擊小區跳轉到小區詳情,但是跳轉鏈接被加密了,是通過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())
運行效果:
經驗證無誤。
倉庫:
請注意爬蟲文章具有時效性,本文寫於2020-11-25日。