# ping CTF 2023
[toc]
## path-traversal-101
FLAGはいくつかのtaskをクリアすれば手に入りそうです。
`index.js`
```javascript=
} else if (!session.task3) {
const result = task3(solution);
console.log("task3: " + result);
if (result) {
session.task3 = true;
res.render("exam", {
task: FLAG,
});
} else {
res.render("exam", {
task: tasks[2],
error: "Try again!",
});
}
}
```
**ソースコードを眺めると、全てのリクエストの`User-Agent` に`robot`と必要なことがわかります。**
`robot.js`
```javascript=
export default (req, res, next) => {
const userAgent = req.get("User-Agent");
if (userAgent == "robot") {
next();
} else {
res.render("robot", { error: "🤖🤖🤖🤖🤖" });
}
};
```
そして、フラグを取得するには、TASKとやらをこなしていく必要がある。
```javascript=
if (!session.task1) {
const result = task1(solution);
console.log("task1: ");
console.log(result);
if (result) {
session.task1 = true;
res.render("exam", {
task: tasks[1],
});
} else {
res.render("exam", {
task: tasks[0],
error: "Try again!",
});
}
} else if (!session.task2) {
const result = task2(solution);
console.log("task2: " + result);
if (result) {
session.task2 = true;
res.render("exam", {
task: tasks[2],
});
} else {
res.render("exam", {
task: tasks[1],
error: "Try again!",
});
}
} else if (!session.task3) {
const result = task3(solution);
console.log("task3: " + result);
if (result) {
session.task3 = true;
res.render("exam", {
task: FLAG,
});
} else {
res.render("exam", {
task: tasks[2],
error: "Try again!",
});
}
}
```
条件自体はそこまで厳しくないのでやっていくだけ。
まず最初に、以下のURLにアクセスを行い、User-Agentをrobotに変更する。
```text=
https://path-traversal-101.knping.pl/%F0%9F%A4%96
```

Task1は、以下の条件。
```javascript=
export const task1 = (solution) => {
preTask(solution);
if (!solution.startsWith("/robot") || solution.endsWith("/flag")) {
throw new Error(
"You cannot access the flag!!! You are task1 UNAUTHORIZED!!! 🤖🤖🤖🤖🤖"
);
}
const solutionPath = path.join("/", solution);
return solutionPath === "/flag";
};
```
最初が`/robot`で終わる必要があり、`/flag`で終わってはいけなさそうなのでそれに従う。
```
/robot/../flag/.
```

次はTask2
```javascript=
export const task2 = (solution) => {
preTask(solution);
solution = solution.replaceAll("../", "");
if (solution === "/flag") {
throw new Error(
"You cannot ACCESS the flag!!! You are UNAUTHORIZED!!! 🤖🤖🤖🤖🤖"
);
}
const solutionPath = path.join("/", solution);
return solutionPath === "/flag";
};
```
これは、`/flag`ならだめというものなので、`./flag`でよし。と思わせておいて、実は`preTask`関数に阻まれるためうまくいかない。
```javascript
const preTask = (solution) => {
if (typeof solution !== "string") {
throw new Error("Solution must be a string");
}
if (solution.length > 512) {
throw new Error("Solution must be less than 512 characters");
}
if (solution === "flag") {
throw new Error("Your solution can't be 'flag'");
}
if (solution === "./flag") {
throw new Error("Your solution can't be './flag'");
}
};
```
がこれもそこまできつい条件ではないので、
`././flag`にすれば良いことがわかる。
最後のTask3
```javascript
export const task3 = (solution) => {
preTask(solution);
if (solution.includes("../") || solution === "/flag") {
throw new Error(
"You CANNOT ACCESS the flag!!! You are UNAUTHORIZED!!! 🤖🤖🤖🤖🤖"
);
}
const solutionPath = path.join("/", solution);
return solutionPath === "/flag";
};
```
../が含まれていてはならず、`/flag`でもダメ。
先ほどと同じ値でバイパスができる。
これで`FAKE`フラグを取得可能なので、本番環境に打ち込めばヨシ

`flag`

## i-see-no-vulnerability
コードを読むと、画像にある文字を、出力するようなアプリケーションであることがわかります。
`visioedDict[uuid]`には、画像から読み取った文字が入ります。
```javascript
const unsafe_text = visionedDict[uuid];
if (unsafe_text === undefined) {
return res.redirect("/");
}
const text = DOMPurify.sanitize(unsafe_text);
const page = readFileSync("./templates/result.html", "utf8")
.replaceAll("{{VISION_TEXT}}", text)
.replaceAll("{{IMAGE}}", uuid);
res.send(page);
```
textを、`{{VISION_TEXT}}`と置き換えますが、rsult.htmlをしっかり読まなかったせいで、当初、`Dompurify`のバイパスをしなければならないと考えていました。
`result.html`
```html
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Image {{IMAGE}}</title>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css" />
</head>
<body>
<section class="hero">
<div class="hero-body">
<p class="title">I'm a visionary!!!</p>
<p class="subtitle">I see...</p>
<div id="vision">{{VISION_TEXT}}</div>
</div>
</section>
<footer class="footer">
<div class="content has-text-centered">
<p><a href="/">Go back</a></p>
<p>
NSFW? <form method="post" action="/report/{{IMAGE}}"><input type="submit" value="Click here to report" class="button" /></form>
</p>
</div>
</footer>
<script>
const text = "{{VISION_TEXT}}";
if (text.length === 0) {
vision.innerHTML = "<img src='/i-see-nothing.gif' />";
}
</script>
</body
```
ですが、`DOMpurify`のバイパスなどはせずとも、以下の箇所ですぐにXSSを発火させることができることに気づきます。
```htmlembedded
<script>
const text = "{{VISION_TEXT}}";
if (text.length === 0) {
vision.innerHTML = "<img src='/i-see-nothing.gif' />";
}
</script>
```
ここまで気づけばもうあとはやるだけです。
以下の画像を、アップロードあと、botに対して送れば終わりです。

## 復習
## pocket-app
**解けなかったので復習。**
## dont-be-alarmed
**解けなかったので復習。**