Python ile AWS WAF CAPTCHA Nasıl Çözülür (405 Sayfaları)

aws waf captcha in python - How to Solve AWS WAF CAPTCHA in Python (405 Pages)

Python’da bir AWS WAF CAPTCHA’sını çözmek için HTTP 405 ile yanıt veren sayfadan üç değeri okuyup bunları CapSkip AWS WAF çözücüsü üzerinden amazon_waf ile gönderip yanıtı bir aws-waf-token çerezi ile takas edersiniz. Yanıt, bir forma yapıştıracağınız bir token değildir. AWS’nin çerezle takas ettiği bir voucher çiftidir; bu yüzden bu akış reCAPTCHA’dan bir adım fazladır. Bu rehber, CapSkip Python SDK ve requests ile bütün döngüyü yaklaşık 70 satırda çalıştırır. CapSkip, çözüm başına ücret olmadan kendi Windows bilgisayarınızda çalışır; bu yüzden bir yeniden deneme hiçbir şeye mal olmaz.

Neye ihtiyacınız var

  • Bir Windows bilgisayarında çalışan CapSkip 3.0.0 veya üzeri. Bu sürümle AWS WAF çözme desteği geldi. İlk başlatmayı kurulum kılavuzu adım adım anlatır.
  • Python 3.10 veya üzeri ve capskip paketinin 1.4.0 veya üzeri sürümü. 1.3.0 sürümünde amazon_waf metodu yoktur. Aşağıdaki kod, capskip 1.4.0 ve requests 2.34.2 ile Python 3.11.7 ve 3.14.0 üzerinde çalıştı. Python 3.10 burada denenmedi.
  • Bir PowerShell istemi. Komutlar PowerShell sözdizimini kullanır.
  • Sahibi olduğunuz ya da otomatikleştirmenize izin verilen, AWS WAF CAPTCHA eylemi içeren bir kuralın arkasındaki bir sayfa.
  • Çözücü için bir adres. Local modunda CapSkip 127.0.0.1 üzerinden yalnızca o cihaza yanıt verir. Server modunda ağ adresinizi veya genel IP’nizi dinler, böylece başka bir bilgisayardaki, bir VPS’teki veya barındırılan bir platformdaki script API üzerinden ona erişebilir. İkisi de şurada ayarlanır: bağlantı ayarları.

Nasıl test edildi: kod, gerçek bir AWS WAF sitesine karşı değil, benim yazdığım üç sahte (mock) sunucuya karşı çalıştırıldı. Birincisi AWS WAF denetimlerini, CapSkip API belgeleri içinde listelendiği gibi kopyalar; ikincisi korunan sitenin, üçüncüsü AWS’nin token sunucusunun yerini tutar. SDK, gerçek capskip 1.4.0 idi. Script’i ayrıca bir kez, hedef olarak mock siteyi vererek, bilgisayarımdaki CapSkip uygulamasına karşı da çalıştırdım. Uygulama sahte bir sayfayı çözemez, bu yüzden üç kez ERROR_CAPTCHA_UNSOLVABLE yanıtı verdi ve script RuntimeError ile bitti; bu da söz konusu hatanın döngüye bir ApiException olarak ulaştığını gösterir. Hiçbir canlı AWS WAF sitesi kullanılmadı, bu yüzden aşağıdaki hiçbir sayı bir çözüm süresi değildir ve belirli bir canlı sitenin bu akışın ürettiği çerezi kabul edeceğini söyleyemem.

1. Adım: challenge sayfasını okuyun

CAPTCHA eylemi içeren bir kural, geçerli token’ı olmayan bir isteğe uyduğunda AWS WAF, HTTP 405 ve captcha değerine ayarlanmış x-amzn-waf-action başlığıyla yanıt verir. AWS WAF belgeleri bulmaca sayfasının yalnızca istek, text/html isteyen bir Accept başlığı gönderdiğinde dahil edildiğini söyler. Düz bir requests çağrısı genel bir Accept gönderir, bu yüzden script bir tane ayarlar. Bu olmadan içinde okunacak hiçbir şey bulunmayan bir 405 alabilirsiniz.

Bu sayfa, gokuProps adlı küçük bir nesne tanımlar; nesnede üç değer vardır: key, iv ve context. Ayrıca bir awswaf.com sunucusundan challenge.js ve captcha.js dosyalarını yükler. iv ve context değerleri her challenge sayfasında değişir, bu yüzden her seferinde yeniden okuyun. x-amzn-waf-action başlığı challenge olan bir 202 yanıtı farklı bir şeydir: o, AWS WAF tarafından sunulan sessiz Challenge eylemidir ve bulmaca içermez. CapSkip belgeleri yalnızca 405 sayfasını ve widget’ı anlatır, bu yüzden bu rehber onu kapsamaz.

# pip install capskip requests
import re
import requests

PAGE_URL = "https://www.example.com/"  # the page that answers HTTP 405
HEADERS = {  # AWS WAF sends its puzzle page only when the request accepts HTML
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/130.0 Safari/537.36",
    "Accept": "text/html",
}


def read_challenge(session):
    resp = session.get(PAGE_URL, timeout=30)
    if resp.status_code != 405 or "gokuProps" not in resp.text:
        return None  # no AWS WAF challenge on this response
    block = re.search(r"gokuProps\s*=\s*\{(.*?)\}", resp.text, re.S).group(1)
    field = lambda name: re.search(rf'"{name}"\s*:\s*"([^"]+)"', block).group(1)
    script = lambda name: re.search(rf'<script[^>]+src="([^"]+/{name}\.js)"', resp.text).group(1)
    return {
        "sitekey": field("key"),
        "iv": field("iv"),
        "context": field("context"),
        "challenge_script": script("challenge"),
        "captcha_script": script("captcha"),
    }

Fonksiyon, yanıt bir CAPTCHA sayfası değilse None döndürür; böylece bir script “çözülecek bir şey yok” ile “çözüldü” durumunu ayırt edebilir. Değerleri bir JSON ayrıştırıcı yerine iki küçük düzenli ifadeyle (regex) okur, çünkü sayfa JSON değil JavaScript içerir. Hedefiniz anahtarları farklı biçimde tırnaklıyorsa ifadeyi ayarlayın, başka hiçbir şeye dokunmayın.

2. Adım: amazon_waf ile çözün

SDK metodunun adı amazon_waf. Yalnızca sitekey ve url zorunludur. Bir challenge sayfasında sitekey, gokuProps.key değeridir; iv ve context ise diğer iki değerdir. Bunlar birlikte gider: ikisini de gönderin ya da hiçbirini göndermeyin. İkisini de bırakırsanız CapSkip bunları çözüm sırasında sayfadan okur; sayfanın sizdeki kopyası birkaç dakikadan eskiyse belgeler bunu daha güvenli seçenek olarak niteler. Bu rehber, sayfayı az önce çektiği için onları gönderir.

İki script adresi seçeneklerdir. Her biri bir awswaf.com sunucusundaki https adresi olmalıdır ve SDK, başka her şeyi bir istek gönderilmeden önce reddeder. Yanıt, captcha_voucher ve existing_token içeren bir sözlük olarak gelir; ham yanıt code altında, görev numarası ise captchaId altında bulunur. Metot, reCAPTCHA’nın kullandığı daha uzun 300 saniyelik zaman aşımıyla bekler, çünkü CapSkip bulmacayı gerçek bir tarayıcıda çözer. Süresini ölçmedim.

from capskip import CapSkip

# Local mode. In Server mode, use your server's address instead.
solver = CapSkip(host="127.0.0.1", port=8080)


def solve(challenge):
    # The answer is a voucher pair, not a token.
    return solver.amazon_waf(
        sitekey=challenge["sitekey"],
        iv=challenge["iv"],
        context=challenge["context"],
        url=PAGE_URL,
        challenge_script=challenge["challenge_script"],
        captcha_script=challenge["captcha_script"],
    )

Çözümü bir proxy üzerinden yönlendirmek için çağrıya bir proxy argümanı ekleyin: type değeri HTTP, uri değeri user:[email protected]:8080 olan bir sözlük. Mock çalıştırmasında bu, in.php’ye bir proxy ve bir proxytype olarak ulaştı. Test için tek bir adres yeterlidir. AWS WAF arkasındaki siteler CAPTCHA’yı çoğu zaman hız sınırlarıyla birlikte kullanır; bu yüzden tek bir adresten sürekli çözüm akışı daha sert bir muamele görür ve CapSkip belgeleri, token belirli bir ağdan gelmek zorundaysa Settings içinde bir proxy listesi ya da çağrı başına bir proxy önerir. CapSkip’in kendi çözücüsü sayfa yüklemelerini, bulmacayı ve voucher takasını tek bir proxy üzerinden gönderir, bu yüzden AWS tek bir adres görür. Çözüme bir proxy veriyorsanız kendi isteklerinizi de aynı proxy üzerinden gönderin. Bu kısmı test edemedim. Proxy döndürme kılavuzu bunların nasıl döndürüleceğini anlatır.

3. Adım: voucher’ı aws-waf-token çerezi ile takas edin

Voucher çifti tek başına işe yaramaz. AWS onu, challenge.js yanında duran bir voucher endpoint’inde bitmiş çerezle takas eder: aynı klasör, challenge.js yerine voucher yazılmış hâliyle. Çifti JSON olarak POST edin; yanıtta bir token alanı bulunur. CapSkip belgeleri gövdeyi, siteyle eşleşen bir Origin başlığıyla birlikte text/plain olarak gönderir. CapSkip uygulamasının kendi kodu ayrıca bir Referer gönderir, bu yüzden fonksiyon ikisini de gönderir. SDK belgeleri çiftin kısa ömürlü olduğunu söyler, bu yüzden gelir gelmez takas edin ve asla saklamayın.

import json
from urllib.parse import urlsplit


def exchange(result, challenge):
    # The voucher endpoint sits beside challenge.js, same folder.
    voucher_url = challenge["challenge_script"].rsplit("/", 1)[0] + "/voucher"
    site = urlsplit(PAGE_URL)
    pair = {
        "captcha_voucher": result["captcha_voucher"],
        "existing_token": result["existing_token"],
    }
    reply = requests.post(
        voucher_url,
        data=json.dumps(pair),
        headers={
            "Content-Type": "text/plain;charset=UTF-8",
            "Origin": f"{site.scheme}://{site.netloc}",
            "Referer": f"{site.scheme}://{site.netloc}/",
        },
        timeout=30,
    )
    reply.raise_for_status()
    return reply.json()["token"]  # the aws-waf-token cookie value

4. Adım: tam çalışan örnek

Son blok, Python’da AWS WAF CAPTCHA akışını bir araya getirir ve yeniden denemeyi ekler. Dört bloğun hepsini tek bir dosyaya, art arda kaydedin ve çalıştırın. Her deneme sayfayı yeniden çeker, böylece her seferinde yeni bir iv ve context gider. Başarısız bir bulmaca ApiException fırlatır ve döngü yeni bir bulmacayla yeniden dener. Token geldikten sonra script sayfayı çerez ayarlı olarak ister.

from capskip import ApiException


def fetch_protected():
    session = requests.Session()
    session.headers.update(HEADERS)
    for attempt in range(1, 4):
        challenge = read_challenge(session)  # fresh page, fresh iv and context
        if challenge is None:
            return session.get(PAGE_URL, timeout=30)  # no challenge, real page
        try:
            result = solve(challenge)
        except ApiException as err:
            print(f"attempt {attempt}: {err}")  # each retry draws a new puzzle
            continue
        token = exchange(result, challenge)  # exchange at once, never store it
        return session.get(PAGE_URL, cookies={"aws-waf-token": token}, timeout=30)
    raise RuntimeError("AWS WAF CAPTCHA not solved in 3 attempts")


if __name__ == "__main__":
    page = fetch_protected()
    print(page.status_code, page.text[:60])

Mock çalıştırmasında script, her iki Python sürümünde de şöyle davrandı:

Mock ayarıScript ne yaptı
Her bulmaca yanıtlandıBir görev, bir voucher takası, ardından gerçek sayfayla 200 durumu
İlk iki bulmaca reddedildiİki deneme satırı, ardından üçüncü görevde 200 durumu
İlk üç bulmaca reddedildiÜç deneme satırı, ardından RuntimeError
Accept başlığı olmayan istekMock, sayfasız bir 405 gönderdi, read_challenge None döndürdü ve script 405 yazdırdı; bu yüzden başlığı koruyun

Çerez, sitenin bağışıklık süresi boyunca çalışır. AWS varsayılan olarak 300 saniye ayarlar ve site sahibinin 60 saniyeden üç güne kadar seçim yapmasına izin verir; bunu AWS WAF belgeleri açıklar. 405 geri döndüğünde döngüyü yeniden çalıştırın. Çok sayıda istek yapıyorsanız her istek için bir kez çözmek yerine token’ı saklayın ve o ana kadar yeniden kullanın.

Yaygın hatalar

HataNedenDüzeltme
ValidationExceptioncontext olmadan iv, bir awswaf.com sunucusunda olmayan ya da https olmayan bir script adresi veya tam adres olmayan bir urliv ve context değerlerini birlikte gönderin ve her script adresini sayfadaki hâliyle aynen kopyalayın
ERROR_CAPTCHA_UNSOLVABLE içeren ApiExceptionBulmaca yanıtlanamadıYeniden gönderin. API belgeleri her denemenin yeni bir bulmaca getirdiğini belirtir
ERROR_TASK_NOT_SUPPORTEDAPI belgeleri bunu, CapSkip’te kapatılmış bir görev türü için listelerCapSkip uygulamasındaki AWS WAF ayarlarını kontrol edin
ERROR_PROXY_FORMATProxy dizesi ayrıştırılamadıuser:pass@ip:port kullanın
ERROR_NO_SLOT_AVAILABLEAPI anahtarının bir istek hız sınırı var ve onu aştınızBirkaç saniye bekleyin ve yeniden gönderin
NetworkExceptionCapSkip çalışmıyor ya da host veya port yanlışCapSkip’i başlatın ve bağlantı ayarlarını kontrol edin
Voucher POST isteği reddedildiBüyük olasılıkla eskimiş ya da eşleşmeyen bir çift. CapSkip uygulamasının kodu, geçersiz bir existing_token için AWS’den HTTP 400 bekler. Bunu gerçek AWS’ye karşı yeniden üretemedimHemen takas edin ve yeni bir görev gönderin
Çerezle birlikte hâlâ 405Token’ın süresi doldu ya da site onu başka bir yerden okuyorYeniden çözün ve sayfanın kendi isteklerinin token’ı nasıl taşıdığını kontrol edin

Çözücüyü bir sunucuda çalıştırmak

Script’in CapSkip’ten iki şeye ihtiyacı var: bir host ve bir port. Local modunda bunlar 127.0.0.1 ve kendi bilgisayarınızdır. Server modunda CapSkip ağ adresinizi veya genel bir IP’yi dinler, böylece başka bir bilgisayardaki, bir VPS’teki veya barındırılan bir platformdaki script aynı API üzerinden ona erişebilir. Host ve port değerlerini CapSkip constructor’ında değiştirin; koddaki başka hiçbir şey değişmez. Kararlı uzaktan erişim için statik bir genel IP önerilir. Server modu da kendi donanımınızda çalışır ve çözüm başına ücretlendirme yoktur. Yine de portu her adrese açar, bu yüzden ulaşmaması gereken adresler için bir Windows Firewall engelleme kuralı ekleyin. Modlar arasında nasıl geçileceğini bağlantı ayarları bölümünde bulabilirsiniz.

FAQ

Python’da bir AWS WAF CAPTCHA’sını tarayıcı olmadan çözebilir miyim?

Script’inizin tarayıcıya ihtiyacı yoktur. CapSkip’e ve siteye düz HTTP istekleri gönderir; CapSkip ise SDK belgelerinin anlattığı gibi bulmacayı, çalıştığı makinedeki gerçek bir tarayıcıda çözer. 405 durumu, AWS WAF tarafından CAPTCHA eyleminin işaretlenme biçimidir.

SDK, aws-waf-token değerini doğrudan döndürür mü?

Hayır. captcha_voucher ve existing_token döndürür; bunları voucher endpoint’inde token ile takas edersiniz. JSON createTask API’si AWS WAF için de çalışır ve biçimlerinden birkaçı token’ı doğrudan döndürür. Bu biçimleri API belgeleri listeler.

CAPTCHA bir formun içindeki bir widget ise ne olur?

Bu, AWS WAF tarafından kullanılan ikinci biçimdir. Değerler gokuProps yerine widget’ın apiKey değerinden ve jsapi.js adresinden gelir. Node.js widget kılavuzu bunu ayrıntılı anlatır ve çağrı aynı metotla yapılır.

Barındırılan bir platform bunu benim CapSkip’ime karşı çalıştırabilir mi?

Evet, Server modu ile. CapSkip’i ağınızı veya genel IP’nizi dinleyecek şekilde ayarlayın, CapSkip constructor’ını o host ve port bilgisine yöneltin; döngü tek bir bilgisayardakiyle aynı çalışır. Çözücü sizin donanımınızda kalır.

Kısa özet

Python’da bir AWS WAF CAPTCHA’sını çözmek dört hamle sürer: 405 sayfasını HTML Accept başlığıyla okuyun, amazon_waf metodunu çağırın, voucher çiftini çerezle takas edin ve isteği onunla yineleyin. Kendi makinenizde yeniden denemek ücretsizdir; bu, sınırsız captcha çözücü olmanın asıl amacıdır, özellikle ara sıra yanıtlanamayan bir bulmaca veren korumalı bir site için. SDK’nın geri kalanı için bkz. Python CAPTCHA çözücü sayfası.