突破tls/ja3新輪子

俞正東發表於2023-05-02

我之前的文章介紹了SSL指紋識別

https://mp.weixin.qq.com/s/BvotXrFXwYvGWpqHKoj3uQ

很多人來問我BYPass的方法

主流的BYPASS方法有兩大類:

  1. 使用定製ja3的網路庫 go在這塊的庫比較流行(比如go的庫requests還有cycletls) 缺點在於,就是得用go語言開發(cycletls有nodejs的但是也是開了一個go語言的一個websocket)

  2. 魔改curl,最有名的就是curl-impersonate 對應win版本的 https://github.com/depler/curl-impersonate-win 缺點就是編譯複雜,使用方式上,得用包裝curl的第三方庫,用的多就是python的pycurl 其他語言的比較少

正好五一有時間,站在巨人們的肩膀上我用go語言開發了一個代理服務.

只需要設定這個代理服務,就可以自定義ja3引數

這樣任何語言都可以直接用了,而且只需要加一個webproxy即可

具體效果可以往下看

image
image

解壓後如上圖,包含2個檔案

  • ja3proxy.exe ja3proxy是go開發的一個控制檯程式
  • localhost_root.pfx 本地證照

(測試加我要)

為了方便本機測試,先安裝localhost_root.pfx證照, (如果不安裝證照,也可以執行,只不過你需要將請求忽略ssl verify) image

證照密碼為123456

image
image

選擇位置為:受信任的根證照頒發機構

image
image

安裝成功後,使用如下命令 執行ja3proxy.exe


ja3proxy.exe -pfxFile=localhost_root.pfx -pfxPwd=123456
image
image

支援的引數共有如下:

  • pfxFile (pfx型別證照)
  • pfxPwd (pfx證照的密碼)
  • authName 如果你要開啟ja3proxy代理服務的basicauth認證,可以設定
  • authPwd (同上)
  • httpPort (ja3proxy代理的http埠,預設為8080)
  • httpsPort (ja3proxy代理的https埠,預設為8443)
  • certFile 非pfx型別證照可以設定
  • keyFile 同上

ja3proxy執行成功後,測試程式碼如下:



var proxy = new WebProxy
{
    // 這就是我們的ja3proxy
 Address = new Uri($"http://localhost:8080")
};

var httpClientHandler = new HttpClientHandler
{
 Proxy = proxy,
};

// 因為我們再上面把證照新增到本機受信任了 所以這行程式碼不需要,如果你不操作受信任證照的話,就需要
//httpClientHandler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;


var client2 = new HttpClient(handler: httpClientHandler, disposeHandler: true);

// 設定ja3指紋
client2.DefaultRequestHeaders.Add("tls-ja3","771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,17513-10-18-11-51-13-27-0-35-65281-43-16-45-5-23-21,29-23-24,0");
// 設定ja3proxy執行請求的超時
client2.DefaultRequestHeaders.Add("tls-timeout","10");
// 設定ja3proxy執行請求用代理,設定後請求目標伺服器拿到的就是代理ip
// client2.DefaultRequestHeaders.Add("tls-proxy","http://252.45.26.333:5543");

// 設定當前請求的useragent
client2.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36");


var result = await client2.GetStringAsync("https://kawayiyi.com/tls");
Console.WriteLine(result);

執行後,校驗ja3一致

{
  "sni": "kawayiyi.com",
  "tlsVersion": "Tls13",
  "tcpConnectionId": "0HMQ8N2PQCRQE",
  "random": "AwN2jHvxe/TKafrfmZ1KG2JWrD7u6M1N4dpeIGdYQwA=",
  "sessionId": "FvNiwCLizsA2JZt0/8865tX2A5VsfbgjlCu4Qg4jPjg=",
  "tlsHashOrigin": "771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,17513-10-18-11-51-13-27-0-35-65281-43-16-45-5-23-21,29-23-24,0",
  "tlsHashMd5": "05556c7568c3d3a65c4e35d42f102d78",
  "cipherList": [
    "TLS_AES_128_GCM_SHA256",
    "TLS_AES_256_GCM_SHA384",
    "TLS_CHACHA20_POLY1305_SHA256",
    "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
    "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
    "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
    "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
    "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
    "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
    "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
    "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
    "TLS_RSA_WITH_AES_128_GCM_SHA256",
    "TLS_RSA_WITH_AES_256_GCM_SHA384",
    "TLS_RSA_WITH_AES_128_CBC_SHA",
    "TLS_RSA_WITH_AES_256_CBC_SHA"
  ],
  "extentions": [
    "extensionApplicationSettings",
    "supported_groups",
    "signed_certificate_timestamp",
    "ec_point_formats",
    "key_share",
    "signature_algorithms",
    "compress_certificate",
    "server_name",
    "session_ticket",
    "renegotiation_info",
    "supported_versions",
    "application_layer_protocol_negotiation",
    "psk_key_exchange_modes",
    "status_request",
    "extended_master_secret",
    "padding"
  ],
  "supportedgroups": [
    "X25519",
    "CurveP256",
    "CurveP384"
  ],
  "ecPointFormats": [
    "uncompressed"
  ],
  "proto": "HTTP/2",
  "h2": {
    "SETTINGS": {
      "1": "65536",
      "3": "1000",
      "4": "6291456",
      "5": "16384",
      "6": "262144"
    },
    "WINDOW_UPDATE": "15663105",
    "HEADERS": [
      ":method",
      ":authority",
      ":scheme",
      ":path"
    ]
  },
  "user_agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36",
  "clientIp": "103.219.192.197"
}

nodejs測試

const request = require('request');

const options = {
    url:'https://kawayiyi.com/tls',
    method: 'GET',
    headers: {
        'tls-ja3':'771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,17513-10-18-11-51-13-27-0-35-65281-43-16-45-5-23-21,29-23-24,0',
        'tls-timeout':'10',
        'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36', // 設定請求頭中的 User-Agent
    },
    proxy: 'http://localhost:8080',
    strictSSL:false
};

request.get(options, (error, response, body) => {
    if (error) {
        console.error(error);
        return;
    }
    console.log('body:', body);
});
image
image

h2的header順序:m,a,s,p 和chrome保持一致

原理

image
image

ja3proxy(是一箇中間人)接管你的請求,然後自己去目標建立tls,clienthello就用你指定的ja3引數

 

突破tls/ja3新輪子

相關文章