python爬蟲 - js逆向之猿人學第十九題突破ja3指紋驗證

前言

廢話不多說,直接幹,再來猿人學19題

 

 

分析

 

看了下,沒有加密參數:

 

然後拿着接口直接請求:

 

 有結果的,不會吧,這麼簡單?沒有加密參數?這次這麼草率?

 

用代碼訪問,唉,臥槽,就是他媽的不行,果然有貓膩

 

 

 換requests:

 

 確實不行,

 

用postman看看,可以的

 

 

這他媽就很秀啊,上一次這種感覺還是http2.0的時候,但是上面我已經用了httpx了啊,也不行,說明就不是http2.0了。

 

這種無力感,接着又想到上次驗證請求頭,把請求頭寫死看看:

 

 

果然也不是,那肯定,相同的反爬策略應該不會再考一次,

 

 

好騷啊,就是無法正常返回結果,那他肯定驗證了某個東西,怎麼辦,再看下,用curl呢:

 

 

也不行,我直接在瀏覽器的編輯腳本界面snippets裏執行,發現可以有結果

 

 

 

 

那就只有抓包看看了,當我打開charles抓包時,有這個提示:

 

 

 

然後看抓包軟件拿到的東西,這個問題,在抓包軟件裏終於復現了

 

 

那就看下到底它檢測了什麼東西,能夠識別抓包工具和爬蟲腳本了 

 

 

後續我接着研究,發現這個網站好像針對性的對mac端做了檢測,因爲我windows端開抓包工具是可以抓到的:

charles:

 

 

fiddler:

 

 

 

 

然後,我來了個神操作,這他媽出來了,好騷啊

 

 

 同時,上面的操作,我是開着fiddler可以的,把fiddler一關再請求,又不行了:

 

 

繼續開上fiddler,然後把請求頭放開:

 

 

那說明驗證的並不是請求頭了,那此時你會不會想,一直開着fiddler然後請求,得出結果並提交就完了,但是這樣一點都不符合我們程序員的套路,那以後遇到這種網站,而項目要部署在服務器上的,你不可能一邊開着個抓包工具,一邊請求吧,況且服務器用的都是linux,沒記錯,fiddler沒有linux版啊

所以,還得是從原理上入手

 

那麼思考下,開了fiddler跟沒開fidder有什麼區別,最容易想到的代理證書的區別。fiddler僞造證書,有關中間人攻擊的理論就不說了,詳細的可以百度

 

那還有個區別,利用中間人攻擊原理,讓服務端以爲fiddler是客戶端,而不再是爬蟲腳本

到底是哪個原因?

 

還是先上個wireshark抓包吧:

 

需要用最新版的wireshark才能看到ja3指紋,因爲ja3指紋是基於tls1.3的,舊版的wireshark只能看到tls1.2及以下的

最新版下載地址:https://www.wireshark.org/download.html

 

這是瀏覽器請求一個接口的數據

 

 

 

 

 

 

 

 

 這是爬蟲程序請求一次接口的數據:

 

 

 

臥槽,一眼就能看出來,這也太大區別了吧,所以,接下來就是分析區別了

 

 

 

 

先看瀏覽器的:

 選中那個【client Hello】包,展開最後這個

 

 

 

 

展開

 

 

 

 

 

 

 

 

滑到最後,這他媽不就是ja3指紋算法

 

 

 

臥槽了

 

有關ja3指紋的,可以看這篇文章:爲什麼隨機 IP、隨機 UA 也逃不掉被反爬蟲的命運

 

這好騷啊,也就是說,他用了ja3指紋,識別到了你用的python的請求庫去請求,所以直接給你返回【page not found】。

 

那麼怎麼辦?ja3指紋也僞造嗎?按照理論,是不是把瀏覽器的指紋也僞造就可以了?那麼現在的關鍵點來了,怎麼找到瀏覽器的指紋呢?

 

再看,最後有個字段,b9開頭的,不知道是不是,

 

 

 

 

 

 

複製-值

b9a4540c16ca6a3812040d3227049f61

 

現在再看下python腳本的指紋:

 

找到hello包:

 

 

 

看到這個,記一下,

 

 總結了下不同機制出現的ja3指紋

 

 

 

所以,從這個就可以很明顯的發現不同了,長度啊,明顯很長的都是不通過的,爲什麼那麼長,說明底層的加密算法用的不一樣啊,這就是原因了

 

那現在這個關鍵的問題,怎麼做到跟瀏覽器一樣啊,以前我們寫爬蟲,僞造跟瀏覽器一樣,改了請求頭就行了,可現在這個指紋,怎麼改啊

 

 

 先看一篇文章,一個黑客大佬寫的,裏面介紹了4種方法:點我

 

1.訪問ip指定host繞過waf

上文提到過,套了阿里雲waf的服務器cname解析到了yundunwaf3.com的域名,這種情況可以直接ping 域名獲取真實ip,然後請求地址設置爲真實ip 在 HTTP Header的Host字段中指定域名即可繞過waf的防護

當然這種方式如果目標服務器開啓了強制域名訪問會失效

 

2.代理中轉請求

在本地啓動代理服務器,如Burp Suite,發起http請求時指定代理服務器爲burp的地址,讓burp來進行TLS握手,算是一種曲線救國的方法

 

3.更換request工具庫

Requests其實是對urllib3的一個封裝,那python有沒有不用urllib的http request庫呢?

翻了翻aiohttp的源碼發現貌似並沒有用urllib3,抓包發現tls指紋和requests也有着明顯的差異

實際測試aiohttp確實沒有被攔截

4.魔改requests

從根本上解決問題,debug跟蹤到了幾處可能可以修改TLS握手特徵的代碼

/usr/local/lib/python3.9/site-packages/urllib3/util/ssl_.py

 

4個方法裏,第一個,不行,我直接把域名替換成了host,仍然如此,說明不是cdn式的防護,第二個,開代理,這個我在windows+fiddler可以,mac下不行,這裏也就解釋上面爲啥開fiddler可行,第三個,我換了httpx和aiohttp,都不行。

 

那就只剩第四個方法了,而,前面介紹ja3指紋的博主,也說了怎麼魔改ja3指紋的:點我

 

先把代碼拷貝下來看,執行看看能不能用:

 

 

 

發現不行,因爲其實目標不一樣,上面的原貼的代碼是爲了欺騙對方,我不是同一個電腦發出的請求,而是多個,所以用了random.shuffle來亂序算法,達到每次出來都不是同一個ja3指紋,而這裏我們要的是欺騙服務器,我們用的是瀏覽器訪問,而不是爬蟲程序訪問

 

看ja3指紋的對比就知道,差太多了

 

 

所以並不是說青南大佬(上面介紹ja3的國內大佬,公衆號未聞code那個)的代碼不行,只是不符合這裏的場景

 

說白了就是指紋長度過長了,而且用random.shuffle,改變了一些算法順序,那這第4個方法也不行嗎?

 

那就無解了啊,查閱了大量資料,好多文章都是直接複製粘貼青南大佬的那篇,剩下的都是些介紹ja3原理的,找到個py庫:pyja3,點我  我還以爲有人寫了個破解庫呢,給我整的老激動了,結果仔細一看就是說可以從pcap文件裏提取出ja3指紋字符串出來,此時此刻對於這裏遇到的問題來說,沒有用

 

相關破解和繞過的,只找到這一篇:點我,裏面的代碼跟青南大佬的代碼幾乎沒區別,唯一的就是沒有對加密算法進行random.shuffle。

 

得,繼續看源碼吧,看能不能找到點靈感,看下最原始的ssl的加密算法部分,以下這個是源碼

 

 

我突然想到,那行,既然就是長度不一樣,長度不一樣的原因就是用的算法不一樣了,那我肯定沒法再加算法,我刪點試試呢?

 

我把圈出來的刪了

 

同時把__init__部分刪了,因爲模板場景不同

 

 

 

 

 

執行,還是不行:

 

 

當我開始一個個測試,一會兒刪前面,一會兒刪後面的,一會兒隨機刪一個或者兩個

 

 

反正最後的結果都是不行,此時,根據我的經驗,我突然想起,以前搞過的那些js加密過後很長的加密字段,都是用了很多次加密算法得算法得出來的,所以我大膽猜測,還是加密算法用的太多了,我直接刪好幾個加密算法看看:

我直接把下面選中都刪了:

 

 

如下,一執行,發現,可行了

 

 

再看指紋:

 

 

 

雖然搞出來了,有點激動,但是別急哈,從長遠角度考慮,先看ja3指紋,確實變短了好多,不過已經比瀏覽器還短了,那假如某個網站要驗證長度不能比瀏覽器的海長呢? 所以一定刪到儘量跟瀏覽器一致

 

 

 

最後結果我的測試,把選中的都刪了:

 

 

 

這樣就可以了:

 

CIPHERS = (
'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:RSA+3DES:!aNULL:'
'!eNULL:!MD5'
)

 

 

 

 

再看ja3指紋,最後的長度已經跟瀏覽器很接近了

 

 

 

感覺還是有點長,再刪一個:

 

 

看指紋,此時感覺又比瀏覽器還短了,那不行,就還是上面那個了

 

 

 

 

 

python調試

 

代碼:

import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.ssl_ import create_urllib3_context

CIPHERS = (
    'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:RSA+3DES:!aNULL:'
    '!eNULL:!MD5'
)

headers = {
    'accept': 'application/json, text/javascript, */*; q=0.01',
    'accept-encoding': 'gzip, deflate, br',
    'accept-language': 'zh-CN,zh;q=0.9',
    'cache-control': 'no-cache',
    'pragma': 'no-cache',
    'user-agent': 'yuanrenxue.project',
    'x-requested-with': 'XMLHttpRequest',
    'cookie': 'sessionid=換成你的id'
}


class DESAdapter(HTTPAdapter):
    def init_poolmanager(self, *args, **kwargs):
        context = create_urllib3_context(ciphers=CIPHERS)
        kwargs['ssl_context'] = context
        return super(DESAdapter, self).init_poolmanager(*args, **kwargs)

    def proxy_manager_for(self, *args, **kwargs):
        context = create_urllib3_context(ciphers=CIPHERS)
        kwargs['ssl_context'] = context
        return super(DESAdapter, self).proxy_manager_for(*args, **kwargs)


def get_page(s, page):
    r = s.get(f'https://match.yuanrenxue.com/api/match/19?page={page}', headers=headers)
    res = r.json()
    data = res.get('data')
    s = [int(d.get('value')) for d in data]
    print(123123,s)
    return s


def get_data(s):
    end = 0
    for i in range(1, 6):
        temp = get_page(s, i)
        print()
        end += sum(temp)
    print('end', end)
    return end


s = requests.Session()
s.mount('https://match.yuanrenxue.com', DESAdapter())
get_data(s)

  

 

運行:

 

 

 

 

 

提交

 

 

 

 

結語

其實也沒啥技術含量,就是剛出來沒多久的ja3指紋驗證,其他都沒啥

那麼,就真的這樣嗎?有了這個開頭,相信以後很多網站都會用到這個

 

然後你再看上面的ja3指紋的截圖,還有個很明顯的特徵,看最後一個數值,瀏覽器的是【0】,而這裏是【0-1-2】,假如模板服務器驗證了最後一個數字一定是【0】呢?怎麼搞?我試了下,好像還沒找到能直接爲0的

 

我試瞭如下的,最後的數字都沒法是【0】

  • ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:RSA+3DES:!aNULL:!eNULL:!MD5
  • ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:RSA+3DES:!aNULL:!eNULL
  • ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:RSA+3DES:!aNULL
  • ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:RSA+3DES:!NULL
  • ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:RSA+3DES:NULL
  • ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:RSA+3DES:0

 

你可以自己試試了。更多的ja3,自行研究了。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章