[Python] Antibot solver blackbox testing fails after 200 runs

Discussão em 'Python' iniciado por Stack, Junho 4, 2025.

  1. Stack

    Stack Membro Participativo

    My team has designed an antibot for a project and now I am testing its vulnerabilities. I have created a antibot solver bypass using some python and javascript. I am running into a super weird run time dependency issue where my solver ALWAYS fails after 200-210 attempts, BUT it starts working again if I reset the solver server. How it works:

    1. Antibot Solver hosted as python flask server. Doesnt matter if hosted locally or google cloud run.
    2. I run some client side code to request the solver server
    3. Solver server returns signature payload

    After my client side code beats the Antibot 200-220 times it ALWAYS starts failing with an error "Signature Validation Error". I am black box testing so can't look into it. I have tried many many times and 200-220 is the threshold where it always begins failing.

    • KEYPOINT: After I begin getting the error after 200 success, it does not help to restart the client side code. However, turning off the flask server and restarting it immediately lets me get another 200 success, then I need to restart the flask server again. I think something that gets init at runtime, such as a UUID/hash in some module gets leaked and the solver starts flagging it. Or maybe after 200 tries there's memory overflow in the heap and the signature calculation starts getting dirty over writes.

    Solver server structure:


    • Main.py (flask server)


    • gen.py (antibot solver logic, imports js using pythons javascript module)


    • solve.js (javascript code hosting a decompiled wasm) - I assume it uses the heap by creating a buffer


    • I have tried making sure all random values are truly random (not repeated identical seeds)


    • I have added logs to my JS code to monitor memory usage, memory and heap look fine with no overflow, there is always 1-2 MB available


    • I have tried to use the python garbage collector to clean asyncFun after a solve is done by the server.


    • I have tried to import the modules inside the functions rather than the top of the file.

    New idea

    • I want to reload all python modules using importlib every time the server solves

    The problem Im running into though is that it doesn't seem safe to reload 5 python modules in a concurrent environment where requests to the solver server come at random times and high volume (currently testing at 20 threads). Based on my design how can I reload all modules, I am especially interested in reloading the javascript module because that is used to import the JS solver. Maybe reloading the libs won't fix it, but this is something that happens when the solver turns on, If anyone has a better suggestion I'd appreciate it.

    main.py

    from flask import Flask, request, jsonify
    from google.oauth2 import service_account
    from google.cloud import firestore
    from gen import *

    app = Flask(__name__)
    creds = service_account.Credentials.from_service_account_file("service.json")
    db = firestore.Client(credentials=creds)

    @app.route('/recalculate', methods=['GET', 'POST'])
    def recalculate():
    try:
    data = Calculate()

    return jsonify(data), 200
    except Exception as e:
    return jsonify({"error": str(e)}), 500

    if __name__ == '__main__':
    port = int(os.environ.get('PORT', 8080))
    app.run(host='0.0.0.0', port=port)


    gen.py

    from javascript import require
    import urllib.parse
    import requests_go
    import importlib
    import hashlib
    import random
    import base64
    import mmh3
    import json
    import math
    import time
    import gc

    def Calculate(...):
    try:
    asyncFun = require("solve.js")
    except Exception as e:
    print(f"Failed to init js: {e}")
    return "", ""

    result = asyncFun['asyncSign'](...)

    del asyncFun
    gc.collect()

    return result


    solve.js

    // 26k lines of decompiled wasm

    async function asyncSign() {
    retasmFunc.A();

    var0 = retasmFunc.y(var50["length"] + 1);
    new Uint8Array(retasmFunc.v["buffer"], var0, var51["length"])["set"](var9);
    }

    module.exports = {
    asyncSign: asyncSign,
    };

    Continue reading...

Compartilhe esta Página