Cara Memecahkan CAPTCHA AWS WAF di Python (Halaman 405)

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

Untuk memecahkan CAPTCHA AWS WAF di Python, Anda membaca tiga nilai dari halaman yang menjawab dengan HTTP 405, lalu mengirimkannya ke pemecah AWS WAF CapSkip dengan amazon_waf, lalu menukar jawabannya dengan cookie aws-waf-token. Jawabannya bukan token yang Anda tempel ke formulir. Jawabannya adalah pasangan voucher yang ditukar AWS dengan cookie, jadi alur ini memiliki satu langkah lebih banyak daripada reCAPTCHA. Panduan ini menjalankan seluruh loop dengan SDK Python CapSkip dan requests dalam sekitar 70 baris. CapSkip berjalan di PC Windows Anda sendiri tanpa biaya per pemecahan, jadi percobaan ulang tidak memerlukan biaya apa pun.

Apa yang Anda butuhkan

  • CapSkip 3.0.0 atau lebih baru yang berjalan di PC Windows. Rilis itu menambahkan pemecahan AWS WAF. Lihat panduan penyiapan untuk menjalankannya pertama kali.
  • Python 3.10 atau lebih baru dan paket capskip versi 1.4.0 atau lebih baru. Versi 1.3.0 tidak memiliki metode amazon_waf. Kode di bawah dijalankan pada Python 3.11.7 dan 3.14.0 dengan capskip 1.4.0 dan requests 2.34.2. Python 3.10 tidak dicoba di sini.
  • Prompt PowerShell. Perintahnya memakai sintaks PowerShell.
  • Halaman milik Anda atau yang boleh Anda otomatisasi, di balik aturan dengan aksi CAPTCHA AWS WAF.
  • Sebuah alamat untuk pemecah CAPTCHA. Dalam mode Local, CapSkip menjawab di 127.0.0.1 hanya untuk perangkat itu. Dalam mode Server, CapSkip mendengarkan di alamat jaringan atau IP publik Anda, sehingga skrip di PC lain, VPS, atau platform hosting dapat menjangkaunya melalui API. Keduanya diatur di pengaturan koneksi.

Cara pengujiannya: kode dijalankan terhadap tiga server mock (server pengganti yang dibuat khusus untuk pengujian) yang saya tulis, bukan terhadap situs AWS WAF sungguhan. Satu meniru pemeriksaan AWS WAF dari CapSkip yang tercantum dalam Dokumentasi API, satu berperan sebagai situs yang dilindungi, dan satu lagi sebagai host token AWS. SDK-nya adalah capskip 1.4.0 yang asli. Saya juga menjalankan skrip sekali terhadap aplikasi CapSkip di PC saya, dengan situs mock sebagai targetnya. Aplikasi tidak bisa memecahkan halaman palsu, jadi aplikasi menjawab ERROR_CAPTCHA_UNSOLVABLE tiga kali dan skrip berakhir dengan RuntimeError, yang menunjukkan error itu sampai ke loop sebagai ApiException. Tidak ada situs AWS WAF sungguhan yang terlibat, jadi tidak ada angka di bawah ini yang merupakan waktu pemecahan, dan saya tidak bisa memastikan bahwa situs sungguhan tertentu menerima cookie yang dihasilkan alur ini.

Langkah 1: baca halaman challenge

Ketika sebuah aturan dengan aksi CAPTCHA cocok dengan permintaan yang tidak memiliki token valid, AWS WAF menjawab dengan HTTP 405 dan header x-amzn-waf-action yang disetel ke captcha. Menurut Dokumentasi AWS WAF, halaman puzzle hanya disertakan jika permintaan mengirim header Accept yang meminta text/html. Panggilan requests biasa mengirim Accept generik, jadi skrip menyetelnya sendiri. Tanpa itu, Anda bisa mendapat 405 tanpa isi apa pun untuk dibaca.

Halaman itu mendefinisikan objek kecil bernama gokuProps dengan tiga nilai: key, iv, dan context. Halaman itu juga memuat challenge.js dan captcha.js dari host awswaf.com. Nilai iv dan context berubah pada setiap halaman challenge, jadi baca nilai yang baru setiap kali. Respons 202 dengan header yang disetel ke challenge adalah hal yang berbeda: itu adalah aksi Challenge senyap dari AWS WAF, yang tidak memiliki puzzle. Dokumentasi CapSkip hanya menjelaskan halaman 405 dan widget, jadi panduan ini tidak membahasnya.

# 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"),
    }

Fungsi ini mengembalikan None bila respons bukan halaman CAPTCHA, sehingga skrip dapat membedakan “tidak ada yang perlu dipecahkan” dari “sudah dipecahkan”. Fungsi ini membaca nilai-nilainya dengan dua ekspresi reguler kecil, bukan parser JSON, karena halaman itu berisi JavaScript, bukan JSON. Jika target Anda menulis kunci dengan cara berbeda, sesuaikan ekspresinya dan tidak ada hal lain.

Langkah 2: pecahkan dengan amazon_waf

Metode SDK-nya adalah amazon_waf. Hanya sitekey dan url yang wajib. Untuk halaman challenge, sitekey adalah gokuProps.key, dan iv serta context adalah dua nilai lainnya. Keduanya dikirim bersamaan: kirim keduanya atau tidak sama sekali. Jika Anda menghilangkan keduanya, CapSkip membacanya dari halaman saat pemecahan, yang disebut dokumentasi sebagai pilihan yang lebih aman bila salinan halaman Anda berumur lebih dari beberapa menit. Panduan ini mengirimnya karena halamannya baru saja diambil.

Kedua alamat skrip adalah opsi. Masing-masing harus berupa alamat https di host awswaf.com, dan SDK menolak yang lain sebelum permintaan dikirim. Jawabannya kembali sebagai dictionary dengan captcha_voucher dan existing_token, ditambah jawaban mentah di code dan nomor task di captchaId. Metode ini menunggu dengan timeout 300 detik yang lebih panjang, yang juga dipakai reCAPTCHA, karena CapSkip memecahkan puzzle di browser sungguhan. Saya tidak mengukur waktunya.

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"],
    )

Untuk memecahkan melalui proxy, tambahkan argumen proxy pada panggilan: sebuah dictionary dengan type disetel ke HTTP dan uri disetel ke user:[email protected]:8080. Pada eksekusi mock, nilai itu tiba di in.php sebagai proxy dan proxytype. Satu alamat sudah cukup untuk pengujian. Situs di balik AWS WAF sering memasangkan CAPTCHA dengan pembatasan laju, jadi aliran pemecahan yang stabil dari satu alamat mendapat perlakuan lebih ketat, dan dokumentasi CapSkip menyarankan daftar proxy di Settings atau proxy per panggilan bila token harus berasal dari jaringan tertentu. Pemecah milik CapSkip sendiri mengirim pemuatan halaman, puzzle, dan pertukaran voucher melalui satu proxy, sehingga AWS melihat satu alamat. Jika Anda memberikan proxy pada pemecahan, kirim permintaan Anda sendiri melalui proxy yang sama. Saya tidak bisa menguji bagian itu. Lihat panduan rotasi proxy yang membahas cara merotasinya.

Langkah 3: tukar voucher dengan cookie aws-waf-token

Pasangan voucher tidak berguna dengan sendirinya. AWS menukarnya dengan cookie jadi di sebuah endpoint voucher yang berada di samping challenge.js: folder yang sama, dengan voucher sebagai pengganti challenge.js. POST pasangan itu sebagai JSON, dan balasannya memiliki field token. Dokumentasi CapSkip mengirim body sebagai text/plain dengan header Origin yang cocok dengan situs. Kode milik aplikasi CapSkip sendiri juga mengirim Referer, jadi fungsi ini mengirim keduanya. Dokumentasi SDK menyebutkan bahwa pasangan itu berumur pendek, jadi tukar segera setelah tiba dan jangan pernah menyimpannya.

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

Langkah 4: contoh lengkap yang berfungsi

Blok terakhir menyatukan alur CAPTCHA AWS WAF di Python dan menambahkan percobaan ulang. Simpan keempat blok dalam satu file, satu demi satu, lalu jalankan. Setiap percobaan mengambil halaman lagi, jadi tiap kali iv dan context-nya baru. Puzzle yang gagal memunculkan ApiException, dan loop mencoba lagi dengan puzzle baru. Setelah token tiba, skrip meminta halaman dengan cookie yang sudah disetel.

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])

Pada eksekusi mock, skrip berperilaku seperti ini pada kedua versi Python:

Pengaturan mockYang dilakukan skrip
Setiap puzzle dijawabSatu task, satu pertukaran voucher, lalu status 200 dengan halaman asli
Dua puzzle pertama ditolakDua baris percobaan, lalu status 200 pada task ketiga
Tiga puzzle pertama ditolakTiga baris percobaan, lalu RuntimeError
Permintaan tanpa header AcceptMock mengirim 405 tanpa halaman, read_challenge mengembalikan None dan skrip mencetak 405, jadi pertahankan header itu

Cookie berfungsi selama waktu imunitas (immunity time) situs. AWS menetapkan 300 detik secara default dan membiarkan pemilik situs memilih dari 60 detik hingga tiga hari. Dokumentasi AWS WAF menjelaskan hal ini. Saat 405 kembali, jalankan loop lagi. Jika Anda membuat banyak permintaan, simpan token dan pakai ulang sampai saat itu, alih-alih memecahkan sekali per permintaan.

Kesalahan umum

KesalahanPenyebabPerbaiki
ValidationExceptioniv tanpa context, alamat skrip yang bukan https di host awswaf.com, atau url yang bukan alamat lengkapKirim iv dan context bersamaan, dan salin setiap alamat skrip persis seperti di halaman
ApiException dengan ERROR_CAPTCHA_UNSOLVABLEPuzzle tidak bisa dijawabKirim lagi. Dokumentasi API menyebutkan bahwa setiap percobaan menghasilkan puzzle baru
ERROR_TASK_NOT_SUPPORTEDDokumentasi API mencantumkan ini untuk tipe task yang dimatikan di CapSkipPeriksa pengaturan AWS WAF di aplikasi CapSkip
ERROR_PROXY_FORMATString proxy tidak bisa diuraiGunakan user:pass@ip:port
ERROR_NO_SLOT_AVAILABLEAPI key memiliki batas laju permintaan dan Anda melampauinyaTunggu beberapa detik lalu kirim lagi
NetworkExceptionCapSkip tidak berjalan, atau host atau port-nya salahJalankan CapSkip dan periksa pengaturan koneksi
POST voucher ditolakKemungkinan besar pasangan yang kedaluwarsa atau tidak cocok. Kode aplikasi CapSkip mengharapkan HTTP 400 dari AWS untuk existing_token yang tidak valid. Saya tidak bisa mereproduksi yang satu ini terhadap AWS sungguhanTukar segera, dan kirim task baru
Masih 405 dengan cookieToken kedaluwarsa, atau situs membacanya dari tempat lainPecahkan lagi, dan periksa bagaimana permintaan milik halaman itu membawa token

Menjalankan solver di sebuah server

Skrip memerlukan dua hal dari CapSkip: host dan port. Dalam mode Local itu adalah 127.0.0.1 dan PC Anda sendiri. Dalam mode Server, CapSkip mendengarkan di alamat jaringan atau IP publik Anda, sehingga skrip di PC lain, VPS, atau platform hosting dapat memanggilnya melalui API yang sama. Ubah host dan port di konstruktor CapSkip, dan tidak ada hal lain dalam kode yang berubah. IP publik statis disarankan untuk akses jarak jauh yang stabil. Mode Server tetap berjalan di hardware Anda sendiri dan tetap tanpa meteran. Mode ini memang membuka port untuk semua alamat, jadi tambahkan aturan blokir Windows Firewall untuk alamat yang tidak boleh menjangkaunya. Lihat pengaturan koneksi untuk cara beralih mode.

FAQ

Bisakah saya memecahkan CAPTCHA AWS WAF di Python tanpa browser?

Skrip Anda tidak memerlukan browser. Skrip hanya mengirim permintaan HTTP biasa ke CapSkip dan ke situs, dan CapSkip memecahkan puzzle di browser sungguhan pada mesin tempatnya berjalan, seperti dijelaskan dokumentasi SDK. Status 405 hanyalah cara AWS WAF menandai aksi CAPTCHA-nya.

Apakah SDK mengembalikan aws-waf-token secara langsung?

Tidak. SDK mengembalikan captcha_voucher dan existing_token, dan Anda menukarnya di endpoint voucher untuk mendapatkan token. API createTask JSON juga menerima AWS WAF, dan beberapa formatnya mengembalikan token secara langsung. Dokumentasi API mencantumkan formatnya.

Bagaimana jika CAPTCHA-nya berupa widget di dalam formulir?

Itu adalah bentuk kedua yang dipakai AWS WAF. Nilainya berasal dari apiKey widget dan alamat jsapi.js, bukan dari gokuProps. Panduan widget Node.js menjelaskannya, dan panggilannya memakai metode yang sama.

Bisakah platform hosting menjalankan ini terhadap CapSkip saya?

Bisa, lewat mode Server. Atur CapSkip untuk mendengarkan di jaringan atau IP publik Anda, arahkan konstruktor CapSkip ke host dan port itu, dan loop bekerja sama seperti pada satu PC. Pemecah tetap berjalan di hardware Anda.

Versi singkatnya

Sebuah CAPTCHA AWS WAF di Python memerlukan empat langkah: baca halaman 405 dengan header Accept HTML, panggil amazon_waf, tukar pasangan voucher dengan cookie, dan ulangi permintaan dengan cookie itu. Mencoba ulang itu gratis di mesin Anda sendiri, dan itulah inti dari pemecah captcha tanpa batas untuk situs terlindungi yang kadang memberi Anda puzzle yang tidak bisa dijawab. Untuk bagian SDK lainnya, lihat Halaman pemecah CAPTCHA Python.