Improve collapsable code to be reusable

master
Maik de Kruif 2 weeks ago
parent 7481185e14
commit fc16fb4046
No known key found for this signature in database
GPG Key ID: DB1A8C782DD43CB3
  1. 7
      content/posts/liveoverflow-minecraft-server.md
  2. 6
      content/writeups/adventofctf/2020/challenge_13.md
  3. 22
      content/writeups/adventofctf/2020/challenge_16.md
  4. 22
      content/writeups/adventofctf/2020/challenge_17.md
  5. 202
      content/writeups/adventofctf/2020/challenge_22.md
  6. 10
      content/writeups/adventofctf/2020/challenge_24.md
  7. 150
      content/writeups/adventofctf/2020/challenge_4.md
  8. 6
      content/writeups/adventofctf/2020/challenge_6.md
  9. 116
      content/writeups/google-ctf/2021/beginners-quest/3.md
  10. 8
      content/writeups/google-ctf/2021/beginners-quest/4.md
  11. 12
      content/writeups/google-ctf/2021/beginners-quest/5.md
  12. 76
      content/writeups/google-ctf/2021/beginners-quest/6.md
  13. 4
      content/writeups/google-ctf/2021/beginners-quest/7.md
  14. 2
      content/writeups/holiday-hack-challenge/2024/act1/curling.md
  15. 2
      content/writeups/holiday-hack-challenge/2024/act1/frosty-keypad.md
  16. 6
      content/writeups/holiday-hack-challenge/2024/prologue/elf-connect.md
  17. 6
      content/writeups/holiday-hack-challenge/2024/prologue/elf-minder.md
  18. 2
      content/writeups/holiday-hack-challenge/2024/prologue/orientation.md
  19. 28
      themes/maik-blog/assets/scss/_buttons.scss
  20. 50
      themes/maik-blog/assets/scss/_collapsible-block.scss
  21. 7
      themes/maik-blog/assets/scss/_main.scss
  22. 2
      themes/maik-blog/assets/scss/main.scss
  23. 17
      themes/maik-blog/layouts/shortcodes/code.html
  24. 17
      themes/maik-blog/layouts/shortcodes/collapsible-block.html

@ -25,7 +25,6 @@ During one of his earlier videos, LiveOverflow challenged his viewers to find th
In LiveOverflow's eighth video, [he told his viewers that the server has been opened to the public](https://youtu.be/QradKmQ27JY?t=1246). I immediately started looking for ways to find it. After researching for a while, I found multiple ways to find it, but I thought they would all take a fair bit of time (I'll get back to this later). So, instead of spending time actually learning stuff, I rewatched his videos to see if there would be a clue in there. Luckily it worked out. In [one video](https://youtu.be/Hmmr1oLt-V8?t=28) he blurred the IP inside the terminal, but forgot about the terminal title bar :smile:. I notified him of this, as it was obviously unintended, and the IP was changed shortly after, as many people apparently found it.
{{< figure src="/img/posts/liveoverflow-minecraft-server/first_ip_screenshot.png" title="Screenshot of video containing the IP address" >}}
### IP change
@ -36,7 +35,7 @@ During my research, I came across masscan. This is a piece of software that lets
I got to work and wrote a script that scans the IP range in which the old IP was located. It starts by using masscan to scan the entire range of IP addresses, and saves it to a file to use later. I then read this file, and request basic Minecraft server information like its MOTD, players and favicon. This information was saved in another file, in which, I could easily search for LiveOverflow. In the end, the new IP only had one digit changed.
{{< code language="python" title="scan.py" isCollapsed="true" >}}
{{< collapsible-block badge="python" title="scan.py" isCollapsed="true" >}}
```py
import masscan
@ -261,7 +260,7 @@ print(len(current_servers))
print(len(valid_servers))
```
{{< /code >}}
{{< /collapsible-block >}}
_This code is copied from a Jupyter Notebook, so it's not the most efficient and may not even work, the [here for the Github Gist of the Notebook](https://gist.github.com/maikka39/8019e2f1a45e1021fff05bd1e1688e14)_
@ -354,7 +353,7 @@ if ((delta > 1f / 256 || deltaAngle > 10f) && !this.player.isImmobile()) {
}
```
In short, this code means we can move around a tiny bit before a `PlayerMoveEvent` is sent. This caught my interest, as I thought there might be a way to change the `lastPos`. After reading more code, I found out there was!
In short, this code means we can move around a tiny bit before a `PlayerMoveEvent` is sent. This caught my interest, as I thought there might be a way to change the `lastPos`. After reading more code, I found out there was!
If we send a position that is far away, like x+100, y+100, the player will be teleported back before the `PlayerMoveEvent` gets sent. During this teleport action, `lastPos` get set to the position the player had before the “far away packet” was sent.

@ -24,7 +24,7 @@ aliases = [
]
+++
- Points: 1300
- Points: 1300
## Description
@ -117,7 +117,7 @@ Let's try to use the previous attack but with the flag file:
We get a big error:
{{< code language="html" title="Error message" >}}
{{< collapsible-block badge="html" title="Error message" >}}
```html
<br />
@ -183,7 +183,7 @@ line: 3 in <b>/var/www/html/index.php</b> on line <b>40</b><br />
<b>/var/www/html/index.php</b> on line <b>43</b><br />
```
{{< /code >}}
{{< /collapsible-block >}}
We probably got it because PHP is actually handling the PHP file as a PHP file 😀. This means we have to get it in some other way.

@ -25,7 +25,7 @@ aliases = [
]
+++
- Points: 1600
- Points: 1600
## Description
@ -41,12 +41,12 @@ When opening the source of the page we also find the following comment: "Here is
```js
function send() {
let emoji = $("#emoji")[0].value;
if (emoji.length > 0) {
$.post("/", { emoji: emoji }, function (data) {
$("#msg")[0].innerHTML = "<b>" + data + "</b>";
});
}
let emoji = $("#emoji")[0].value;
if (emoji.length > 0) {
$.post("/", { emoji: emoji }, function (data) {
$("#msg")[0].innerHTML = "<b>" + data + "</b>";
});
}
}
```
@ -74,7 +74,7 @@ This means the server is most likely using either Jinja2 of Twig.
Now that we found the vulnerability, we can start exploiting it. Let's start by getting the config. We can try to get it by entering `{{config}}` or `{{config.items()}}` as the emoji.
{{< code language="python" title="Result" >}}
{{< collapsible-block badge="python" title="Result" >}}
```python
dict_items([
@ -224,7 +224,7 @@ dict_items([
])
```
{{< /code >}}
{{< /collapsible-block >}}
If we take a look at it we find an item called 'flag' but it looks like it is encrypted in some way:
@ -282,7 +282,7 @@ The source of the server is probably `app.py` as it's the default for flask appl
config.__class__.__init__.__globals__['os'].popen('cat app.py').read()
```
{{< code language="python" title="app.py" >}}
{{< collapsible-block badge="python" title="app.py" >}}
```python
import random
@ -332,7 +332,7 @@ if __name__ == '__main__':
```
{{< /code >}}
{{< /collapsible-block >}}
When looking at the file, we see that the flag variable is set to the output of the `magic` function:

@ -25,7 +25,7 @@ aliases = [
]
+++
- Points: 1700
- Points: 1700
## Description
@ -41,12 +41,12 @@ When opening the source of the page we also find the following comment: "Here is
```js
function send() {
let emoji = $("#emoji")[0].value;
if (emoji.length > 0) {
$.post("/", { emoji: emoji }, function (data) {
$("#msg")[0].innerHTML = "<b>" + data + "</b>";
});
}
let emoji = $("#emoji")[0].value;
if (emoji.length > 0) {
$.post("/", { emoji: emoji }, function (data) {
$("#msg")[0].innerHTML = "<b>" + data + "</b>";
});
}
}
```
@ -154,7 +154,7 @@ To get the subclasses, we first have to convert `''.__class__.__mro__[1].__subcl
After submitting this, we get the following result:
{{< code language="text" title="Result" >}}
{{< collapsible-block badge="text" title="Result" >}}
```js
[
@ -643,7 +643,7 @@ After submitting this, we get the following result:
]
```
{{< /code >}}
{{< /collapsible-block >}}
In this result we find the following class: `<class 'os._wrap_close'>`. This is the `os` module and it is on index `127`. We can verify it's index by getting it from the submodules list using the following input:
@ -680,7 +680,7 @@ Now let's grab the contents of `app.py`:
{{ [[[""|attr("\x5f\x5fclass\x5f\x5f")|attr("\x5f\x5fmro\x5f\x5f")][0][1]|attr("\x5f\x5fsubclasses\x5f\x5f")()][0][127]|attr("\x5f\x5finit\x5f\x5f")|attr("\x5f\x5fglobals\x5f\x5f")][0]["popen"]("cat app\x2epy")|attr("read")() }}
```
{{< code language="python" title="app.py" >}}
{{< collapsible-block badge="python" title="app.py" >}}
```py
import random
@ -732,7 +732,7 @@ if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000)
```
{{< /code >}}
{{< /collapsible-block >}}
## Magic function

@ -25,7 +25,7 @@ aliases = [
]
+++
- Points: 2200
- Points: 2200
## Description
@ -49,8 +49,8 @@ When opening the page, we will see a broken image, this is expected as the file
```html
<img
src="data:image/jpeg;base64,PD9waHAKCmluY2x1ZGUoInNlY3JldC5waHAiKTsKCmlmIChzdHJwb3MoY2hlY2tfc2VjcmV0KCksICJhbGxvdyIpICE9PSBmYWxzZSkgewogICBlY2hvIGdldF9mbGFnKCk7IAp9Cgo/Pgo="
width="100%"
src="data:image/jpeg;base64,PD9waHAKCmluY2x1ZGUoInNlY3JldC5waHAiKTsKCmlmIChzdHJwb3MoY2hlY2tfc2VjcmV0KCksICJhbGxvdyIpICE9PSBmYWxzZSkgewogICBlY2hvIGdldF9mbGFnKCk7IAp9Cgo/Pgo="
width="100%"
/>
```
@ -80,64 +80,71 @@ Alas, we get the cat picture again. That's weird. There might be a filter on the
Using the same decoding method, we get the following result:
{{< code language="php" title="index.php" >}}
{{< collapsible-block badge="php" title="index.php" >}}
```html
<!DOCTYPE html>
<html class="no-js" lang="">
<head>
<meta charset="utf-8" />
<meta http-equiv="x-ua-compatible" content="ie=edge" />
<title>Advent of CTF 22</title>
<meta name="description" content="" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="style.css" type="text/css" media="screen" />
<link
rel="stylesheet"
href="https://use.fontawesome.com/releases/v5.6.3/css/all.css"
integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/"
crossorigin="anonymous"
/>
<style>
.row-margin-05 {
margin-top: 0.5em;
}
.row-margin-10 {
margin-top: 1em;
}
.row-margin-20 {
margin-top: 2em;
}
.row-margin-30 {
margin-top: 3em;
}
</style>
</head>
<body>
<div class="jumbotron bg-transparent mb-0 radius-0">
<div class="container fluid">
<div class="row">
<div class="col-xl-6 mx-auto">
<h1 class="display-2">
Advent of CTF <span class="vim-caret">22</span>
</h1>
<div class="lead mb-3 text-mono text-warning">
Your daily dose of CTF for December
</div>
<div class="row">
<div class="col-xl-12 mx-auto">
<div class="card">
<div class="card-header text-center">
<h2>The big reveal</h2>
</div>
<div class="card-body">
<?php
<head>
<meta charset="utf-8" />
<meta http-equiv="x-ua-compatible" content="ie=edge" />
<title>Advent of CTF 22</title>
<meta name="description" content="" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link
rel="stylesheet"
href="style.css"
type="text/css"
media="screen"
/>
<link
rel="stylesheet"
href="https://use.fontawesome.com/releases/v5.6.3/css/all.css"
integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/"
crossorigin="anonymous"
/>
<style>
.row-margin-05 {
margin-top: 0.5em;
}
.row-margin-10 {
margin-top: 1em;
}
.row-margin-20 {
margin-top: 2em;
}
.row-margin-30 {
margin-top: 3em;
}
</style>
</head>
<body>
<div class="jumbotron bg-transparent mb-0 radius-0">
<div class="container fluid">
<div class="row">
<div class="col-xl-6 mx-auto">
<h1 class="display-2">
Advent of CTF <span class="vim-caret">22</span>
</h1>
<div class="lead mb-3 text-mono text-warning">
Your daily dose of CTF for December
</div>
<div class="row">
<div class="col-xl-12 mx-auto">
<div class="card">
<div class="card-header text-center">
<h2>The big reveal</h2>
</div>
<div class="card-body">
<?php
if (!isset($_GET["image"])) {
?>
<a href="/index.php?image=cat.jpg">Is this santa?</a>
<?php
<a href="/index.php?image=cat.jpg"
>Is this santa?</a
>
<?php
} else {
$path = $_GET["image"];
if (strpos($path,"secret") !== false) {
@ -145,49 +152,62 @@ Using the same decoding method, we get the following result:
}
$image = file_get_contents($path);
echo '<img src="data:image/jpeg;base64,'.base64_encode($image).'" width="100%"/>';
} ?>
</div>
<div class="card-footer text-center">Almost there</div>
</div>
</div>
</div>
<div class="row row-margin-30">
<div class="card mb-3 bg-dark text-white">
<div class="card-body">
<div class="row">
<div class="col-md-2">
<img src="/logo.png" />
</div>
<div class="col-md-9 offset-md-1 align-middle">
<p class="text-center">
<span class="align-middle">
The Advent of CTF is brought to you by
<a href="http://www.novi.nl">NOVI Hogeschool</a>. It
is built by
<a
href="https://twitter.com/credmp/"
class="icoTwitter"
title="Twitter"
><i class="fab fa-twitter"></i> @credmp</a
>. If you are looking for a Dutch Cyber Security
Bachelor degree or bootcamp,
<a href="https://www.novi.nl">check us out</a>.
</span>
</p>
} ?>
</div>
<div class="card-footer text-center">
Almost there
</div>
</div>
</div>
</div>
<div class="row row-margin-30">
<div class="card mb-3 bg-dark text-white">
<div class="card-body">
<div class="row">
<div class="col-md-2">
<img src="/logo.png" />
</div>
<div
class="col-md-9 offset-md-1 align-middle"
>
<p class="text-center">
<span class="align-middle">
The Advent of CTF is brought
to you by
<a href="http://www.novi.nl"
>NOVI Hogeschool</a
>. It is built by
<a
href="https://twitter.com/credmp/"
class="icoTwitter"
title="Twitter"
><i
class="fab fa-twitter"
></i>
@credmp</a
>. If you are looking for a
Dutch Cyber Security
Bachelor degree or bootcamp,
<a
href="https://www.novi.nl"
>check us out</a
>.
</span>
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</body>
</html>
```
{{< /code >}}
{{< /collapsible-block >}}
Just the PHP part:

@ -26,7 +26,7 @@ aliases = [
]
+++
- Points: 2400
- Points: 2400
## Description
@ -97,7 +97,7 @@ In [3]: pickle.loads(base64.b64decode("gAN9cQAoWAUAAABib2FyZHEBXXECKF1xAyhYAQAAA
This time our board is quite a bit larger:
{{< code language="py" title="Board" >}}
{{< collapsible-block badge="py" title="Board" >}}
```py
{
@ -179,7 +179,7 @@ This time our board is quite a bit larger:
}
```
{{< /code >}}
{{< /collapsible-block >}}
We can see that a `chain` value has been added. From the title of this challenge, we can say that this is the blockchain that we likely have to bypass.
@ -230,7 +230,7 @@ We can see that, to verify the game, the function loops through all the blocks i
To crack this, we can simply reverse this algorithm. To do this, I grabbed the script from the HTML source, and added a crack method like so:
{{< code language="py" title="solve.py" >}}
{{< collapsible-block badge="py" title="solve.py" >}}
```python
import hashlib
@ -304,7 +304,7 @@ if __name__ == "__main__":
print(export_base64(game))
```
{{< /code >}}
{{< /collapsible-block >}}
After running this script, we get the following result:

@ -24,7 +24,7 @@ aliases = [
]
+++
- Points: 400
- Points: 400
## Description
@ -36,64 +36,64 @@ Visit <https://04.adventofctf.com> to start the challenge.
When opening the website we're (for the first time) not provided with a login form. It is still authentication though as we are greeted with a message: "If you have access to it the special present will be shown below:". Also, I noticed the URL changed after about five seconds. That hints at some javascript, so let's open the sources tab in devtools. We find `login.js`.
{{< code language="js" title="login.js" >}}
{{< collapsible-block badge="js" title="login.js" >}}
```js
function startup() {
key = localStorage.getItem("key");
key = localStorage.getItem("key");
if (key === null) {
localStorage.setItem("key", "eyJ1c2VyaWQiOjB9.1074");
}
if (key === null) {
localStorage.setItem("key", "eyJ1c2VyaWQiOjB9.1074");
}
}
var _0x1fde = ["charCodeAt"];
(function (_0x93ff3a, _0x1fded8) {
var _0x39b47b = function (_0x54f1d3) {
while (--_0x54f1d3) {
_0x93ff3a["push"](_0x93ff3a["shift"]());
}
};
_0x39b47b(++_0x1fded8);
var _0x39b47b = function (_0x54f1d3) {
while (--_0x54f1d3) {
_0x93ff3a["push"](_0x93ff3a["shift"]());
}
};
_0x39b47b(++_0x1fded8);
})(_0x1fde, 0x192);
var _0x39b4 = function (_0x93ff3a, _0x1fded8) {
_0x93ff3a = _0x93ff3a - 0x0;
var _0x39b47b = _0x1fde[_0x93ff3a];
return _0x39b47b;
_0x93ff3a = _0x93ff3a - 0x0;
var _0x39b47b = _0x1fde[_0x93ff3a];
return _0x39b47b;
};
function calculate(_0x54f1d3) {
var _0x58628b = _0x39b4,
_0xc289d4 = 0x0;
for (let _0x19ddf3 in text) {
_0xc289d4 += text[_0x58628b("0x0")](_0x19ddf3);
}
return _0xc289d4;
var _0x58628b = _0x39b4,
_0xc289d4 = 0x0;
for (let _0x19ddf3 in text) {
_0xc289d4 += text[_0x58628b("0x0")](_0x19ddf3);
}
return _0xc289d4;
}
function check() {
key = localStorage.getItem("key");
hash = window.location.search.split("?")[1];
key = localStorage.getItem("key");
hash = window.location.search.split("?")[1];
if (key !== null && hash != "token=" + key) {
parts = key.split(".");
text = atob(parts[0]);
checksum = parseInt(parts[1]);
if (key !== null && hash != "token=" + key) {
parts = key.split(".");
text = atob(parts[0]);
checksum = parseInt(parts[1]);
count = calculate(text);
count = calculate(text);
if (count == checksum) {
setTimeout(function () {
window.location = "index.php?token=" + key;
}, 5000);
if (count == checksum) {
setTimeout(function () {
window.location = "index.php?token=" + key;
}, 5000);
}
}
}
}
startup();
check();
```
{{< /code >}}
{{< /collapsible-block >}}
This looks like some obfuscated code. So I started with de-obfuscating the code. After a few minutes of reading the code, I remembered to always start at the output. And after looking at the `check()` function I found out I had wasted my time.
@ -101,42 +101,42 @@ As it turns out, we don't need to know what the obfuscated code does. If we read
```js
function check() {
// Get key from localStorage
// The key is initialized in startup()
// > "eyJ1c2VyaWQiOjB9.1074"
key = localStorage.getItem("key");
// Get the token from the url
// > "token=eyJ1c2VyaWQiOjB9.1074"
hash = window.location.search.split("?")[1];
// If key and hash are not empty:
if (key !== null && hash != "token=" + key) {
// Split the key by a .
// > (2) ["eyJ1c2VyaWQiOjB9", "1074"]
parts = key.split(".");
// Decode the base64 from the first part of the key
// > "{"userid":0}"
text = atob(parts[0]);
// Get the value of the second part of the key as an int
// > 1074
checksum = parseInt(parts[1]);
// Calculate the value of text
// > 1074
count = calculate(text);
// If the last part of the key is correct:
if (count == checksum) {
// Execute this function after 5000ms
setTimeout(function () {
// Execute a get request with the token parameter
window.location = "index.php?token=" + key;
}, 5000);
// Get key from localStorage
// The key is initialized in startup()
// > "eyJ1c2VyaWQiOjB9.1074"
key = localStorage.getItem("key");
// Get the token from the url
// > "token=eyJ1c2VyaWQiOjB9.1074"
hash = window.location.search.split("?")[1];
// If key and hash are not empty:
if (key !== null && hash != "token=" + key) {
// Split the key by a .
// > (2) ["eyJ1c2VyaWQiOjB9", "1074"]
parts = key.split(".");
// Decode the base64 from the first part of the key
// > "{"userid":0}"
text = atob(parts[0]);
// Get the value of the second part of the key as an int
// > 1074
checksum = parseInt(parts[1]);
// Calculate the value of text
// > 1074
count = calculate(text);
// If the last part of the key is correct:
if (count == checksum) {
// Execute this function after 5000ms
setTimeout(function () {
// Execute a get request with the token parameter
window.location = "index.php?token=" + key;
}, 5000);
}
}
}
}
```
@ -148,14 +148,14 @@ Let's turn this into some code:
```js
function generateHash(input) {
// Set the global text variable defined in
// login.js, otherwise calculate doesn't work
text = input;
// Set the global text variable defined in
// login.js, otherwise calculate doesn't work
text = input;
let count = calculate(text);
let key = btoa(text) + "." + count;
let count = calculate(text);
let key = btoa(text) + "." + count;
console.log(key);
console.log(key);
}
generateHash('{"userid":0}');

@ -24,7 +24,7 @@ aliases = [
]
+++
- Points: 600
- Points: 600
## Description
@ -72,7 +72,7 @@ As you can see the string is escaped and the result of this query will have the
When submitting it I got the following result:
{{< code language="text" title="Result" >}}
{{< collapsible-block badge="text" title="Result" >}}
```markdown
| id | Description | Proof |
@ -244,7 +244,7 @@ When submitting it I got the following result:
| secrets | 2-------- | 3------- |
```
{{< /code >}}
{{< /collapsible-block >}}
## Solution

@ -58,9 +58,9 @@ Upon opening the website, we're greeted with a code editor and some text:
>
> The controlCar function takes a single parameter – `scanArray` – which is an array containing 17 integers denoting distance > from your car to the nearest obstacle:
>
> - [indexes 0-7]: on the left side of the car (index 7 is the measurement at the left headlight),
> - [index 8]: at the center of the car,
> - [indexes 9-16]: on the right side of the car (index 9 is the measurement at the right headlight).
> - [indexes 0-7]: on the left side of the car (index 7 is the measurement at the left headlight),
> - [index 8]: at the center of the car,
> - [indexes 9-16]: on the right side of the car (index 9 is the measurement at the right headlight).
>
> See also [this image]({{< ref "#radar-image" >}}) (it's not precise, but will give you an idea what you are looking at).
>
@ -72,9 +72,9 @@ Upon opening the website, we're greeted with a code editor and some text:
>
> The `controlCar` must return an integer denoting where the car should drive:
>
> - -1 (or any other negative value): drive more to the left,
> - 0: continue straight / straighten up the car,
> - 1 (or any other positive value): drive more to the right.
> - -1 (or any other negative value): drive more to the left,
> - 0: continue straight / straighten up the car,
> - 1 (or any other positive value): drive more to the right.
When opening the source, we also find the following comment:
@ -92,66 +92,66 @@ When opening the source, we also find the following comment:
To solve this challenge, I came up with the following script:
{{< code language="js" title="solve.js" >}}
{{< collapsible-block badge="js" title="solve.js" >}}
```js
function controlCar(scanArray) {
if (!window.has_reset_game) {
window.has_reset_game = true;
window.car_position = 0;
window.queue = [];
}
if (window.queue.length === 0) {
let left, center, right;
if (window.car_position === -1) {
left = 8;
center = 12;
right = 15;
} else if (window.car_position === 0) {
left = 4;
center = 8;
right = 12;
} else if (window.car_position === 1) {
left = 1;
center = 4;
right = 8;
if (!window.has_reset_game) {
window.has_reset_game = true;
window.car_position = 0;
window.queue = [];
}
left = scanArray[left];
center = scanArray[center];
right = scanArray[right];
let furthest = Math.max(left, center, right);
let closest = Math.min(left, center, right);
console.log(left, center, right);
let moveInDirection = (direction) => {
console.log("Going in direction", direction);
if (direction === window.car_position) {
window.queue.push(0);
} else if (direction > window.car_position) {
window.queue.push(1, 1, 1, 1);
window.car_position += 1;
} else if (direction < window.car_position) {
window.queue.push(-1, -1, -1, -1);
window.car_position -= 1;
}
};
if (closest < 0) moveInDirection(window.car_position);
else if (furthest === left) moveInDirection(-1);
else if (furthest === center) moveInDirection(0);
else if (furthest === right) moveInDirection(1);
}
return window.queue.pop();
if (window.queue.length === 0) {
let left, center, right;
if (window.car_position === -1) {
left = 8;
center = 12;
right = 15;
} else if (window.car_position === 0) {
left = 4;
center = 8;
right = 12;
} else if (window.car_position === 1) {
left = 1;
center = 4;
right = 8;
}
left = scanArray[left];
center = scanArray[center];
right = scanArray[right];
let furthest = Math.max(left, center, right);
let closest = Math.min(left, center, right);
console.log(left, center, right);
let moveInDirection = (direction) => {
console.log("Going in direction", direction);
if (direction === window.car_position) {
window.queue.push(0);
} else if (direction > window.car_position) {
window.queue.push(1, 1, 1, 1);
window.car_position += 1;
} else if (direction < window.car_position) {
window.queue.push(-1, -1, -1, -1);
window.car_position -= 1;
}
};
if (closest < 0) moveInDirection(window.car_position);
else if (furthest === left) moveInDirection(-1);
else if (furthest === center) moveInDirection(0);
else if (furthest === right) moveInDirection(1);
}
return window.queue.pop();
}
```
{{< /code >}}
{{< /collapsible-block >}}
It starts off by initializing some global variables if the game is running for the first time (or after a restart). After which, it check if there are still moves in the queue. If so, it grabs the last item out of the queue and returns it.

@ -43,7 +43,7 @@ You’re taking a stroll in the lab, when Dr. Klostermann is calling your name:
[attachment.zip](/files/writeups/google-ctf/2021/beginners-quest/4/attachment.zip)
{{< code language="c" title="chal.c" isCollapsed="true" >}}
{{< collapsible-block badge="c" title="chal.c" isCollapsed="true" >}}
```c
#include <stdbool.h>
@ -208,7 +208,7 @@ int main(void)
}
```
{{< /code >}}
{{< /collapsible-block >}}
## Recon
@ -308,7 +308,7 @@ for set_mask, clr_mask in zip(set_masks, clr_masks):
print(flag.strip())
```
{{< code language="py" title="Full code" isCollapsed="true" >}}
{{< collapsible-block badge="py" title="Full code" isCollapsed="true" >}}
```py
set_mask_str = "gpio_set_mask"
@ -343,7 +343,7 @@ for set_mask, clr_mask in zip(set_masks, clr_masks):
print(flag.strip())
```
{{< /code >}}
{{< /collapsible-block >}}
## Solution

@ -50,7 +50,7 @@ As you and Gökhan are leaving the crates to enter a car, you spot the tough guy
[attachment.zip](/files/writeups/google-ctf/2021/beginners-quest/5/attachment.zip)
{{< code language="py" title="RoboCaller1337.py" isCollapsed="true" >}}
{{< collapsible-block badge="py" title="RoboCaller1337.py" isCollapsed="true" >}}
```py
import random
@ -103,9 +103,9 @@ if __name__ == "__main__":
main()
```
{{< /code >}}
{{< /collapsible-block >}}
{{< code language="txt" title="robo_numbers_list.txt" isCollapsed="true" >}}
{{< collapsible-block badge="txt" title="robo_numbers_list.txt" isCollapsed="true" >}}
```txt
263-170-6234
@ -734,7 +734,7 @@ if __name__ == "__main__":
446-996-9104
```
{{< /code >}}
{{< /collapsible-block >}}
## Recon
@ -793,7 +793,7 @@ for a,b in zip(key, secret):
print(flag)
```
{{< code language="py" title="Full code" isCollapsed="true" >}}
{{< collapsible-block badge="py" title="Full code" isCollapsed="true" >}}
```py
from mt19937predictor import MT19937Predictor
@ -816,7 +816,7 @@ for a,b in zip(key, secret):
print(flag)
```
{{< /code >}}
{{< /collapsible-block >}}
## Solution

@ -50,7 +50,7 @@ After having climbed through the window, you wait for a while on the ground. The
[attachment.zip](/files/writeups/google-ctf/2021/beginners-quest/6/attachment.zip)
{{< code language="txt" title="encodings" isCollapsed="true" >}}
{{< collapsible-block badge="txt" title="encodings" isCollapsed="true" >}}
```text
I made a super secret encoder. I remember using:
@ -64,15 +64,15 @@ I made a super secret encoder. I remember using:
I also use gzip and zlib (to compress the stuff) and I like hiding things in files...
```
{{< /code >}}
{{< /collapsible-block >}}
{{< code language="txt" title="chall.txt" isCollapsed="true" >}}
{{< collapsible-block badge="txt" title="chall.txt" isCollapsed="true" >}}
```txt
File is too large to display here.
```
{{< /code >}}
{{< /collapsible-block >}}
## Recon
@ -336,7 +336,7 @@ for line in data:
print(line)
```
{{< code language="text" title="output" >}}
{{< collapsible-block badge="text" title="output" >}}
```text
nyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyya~
@ -776,7 +776,7 @@ nyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyya~
nyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyya~
```
{{< /code >}}
{{< /collapsible-block >}}
### nya~
@ -841,43 +841,43 @@ Then, let's follow the steps to convert brainfuck to Unary in reverse.
1. Remove the leading `1`
```py
unary_code = unary_code[1:]
```
```py
unary_code = unary_code[1:]
```
2. Replace unary with brainfuck
```py
for i in range(0, len(unary_code), 3):
operation = unary_code[i:i+3]
if operation == "000":
brainfuck_code += ">"
elif operation == "001":
brainfuck_code += "<"
elif operation == "010":
brainfuck_code += "+"
elif operation == "011":
brainfuck_code += "-"
elif operation == "100":
brainfuck_code += "."
elif operation == "101":
brainfuck_code += ","
elif operation == "110":
brainfuck_code += "["
elif operation == "111":
brainfuck_code += "]"
```
```py
for i in range(0, len(unary_code), 3):
operation = unary_code[i:i+3]
if operation == "000":
brainfuck_code += ">"
elif operation == "001":
brainfuck_code += "<"
elif operation == "010":
brainfuck_code += "+"
elif operation == "011":
brainfuck_code += "-"
elif operation == "100":
brainfuck_code += "."
elif operation == "101":
brainfuck_code += ","
elif operation == "110":
brainfuck_code += "["
elif operation == "111":
brainfuck_code += "]"
```
3. Print the result:
```py
print(brainfuck_code)
```
```py
print(brainfuck_code)
```
```bf
[-]>[-]<++++++[>++++++++++<-]>+++++++.<+[>++++++++++<-]>+++++++.<+[>----------<-]>----.<+++++[>++++++++++<-]>+++.<+[>----------<-]>-.<[>----------<-]>----.<+++++[>----------<-]>-------.<[>++++++++++<-]>+.<++++++[>++++++++++<-]>+++.<++++++[>----------<-]>----.<++++[>++++++++++<-]>++++.<+[>++++++++++<-]>+++++.<++++++[>----------<-]>--.<++++[>++++++++++<-]>+++++++.<+[>++++++++++<-]>++++.<++++++[>----------<-]>-.<[>++++++++++<-]>++++.<++++++[>++++++++++<-]>++.<+[>++++++++++<-]>+.<
```
```bf
[-]>[-]<++++++[>++++++++++<-]>+++++++.<+[>++++++++++<-]>+++++++.<+[>----------<-]>----.<+++++[>++++++++++<-]>+++.<+[>----------<-]>-.<[>----------<-]>----.<+++++[>----------<-]>-------.<[>++++++++++<-]>+.<++++++[>++++++++++<-]>+++.<++++++[>----------<-]>----.<++++[>++++++++++<-]>++++.<+[>++++++++++<-]>+++++.<++++++[>----------<-]>--.<++++[>++++++++++<-]>+++++++.<+[>++++++++++<-]>++++.<++++++[>----------<-]>-.<[>++++++++++<-]>++++.<++++++[>++++++++++<-]>++.<+[>++++++++++<-]>+.<
```
### Brainfuck
@ -903,7 +903,7 @@ CTF{pl34s3_n0_m04r}
As for most ctf problems, I've written a script that executes all the step automatically and returns the flag.
{{< code language="py" title="solve.py" isCollapsed="true" >}}
{{< collapsible-block badge="py" title="solve.py" isCollapsed="true" >}}
```py
# pip install brainfuck-interpreter
@ -1065,7 +1065,7 @@ flag = brainfuck.evaluate(brainfuck_code)
print(flag)
```
{{< /code >}}
{{< /collapsible-block >}}
## Solution

@ -42,7 +42,7 @@ Nowak is very impressed by your skills. You and him sit down by a table, and you
[attachment.zip](/files/writeups/google-ctf/2021/beginners-quest/7/attachment.zip)
{{< code language="python" title="chall.py" isCollapsed="true" >}}
{{< collapsible-block badge="python" title="chall.py" isCollapsed="true" >}}
```py
from Crypto.Util.number import *
@ -63,7 +63,7 @@ print(n)
#21034814455172467787319632067588541051616978031477984909593707891829600195022041640200088624987623056713604514239406145871910044808006741636513624835862657042742260288941962019533183418661144639940608960169440421588092324928046033370735375447302576018460809597788053566456538713152022888984084306297869362373871810139948930387868426850576062496427583397660227337178607544043400076287217521751017970956067448273578322298078706011759257235310210160153287198740097954054080553667336498134630979908988858940173520975701311654172499116958019179004876438417238730801165613806576140914402525031242813240005791376093215124477
```
{{< /code >}}
{{< /collapsible-block >}}
## Recon

@ -3,7 +3,7 @@ author = "Maik de Kruif"
title = "Curling"
subtitle = "Act 1 - SANS Holiday Hack Challenge 2024"
date = 2024-11-23T11:44:53+01:00
description = "In the fourth challenge of the Holiday Hack Challenge 2024, we'll explore how to use curl using the Linux manpages."
description = "In the Curling challenge, we join Bow Ninecandle to learn how to use the curl command for sending web requests. The silver tasks include sending basic requests, handling self-signed certificates, posting data, and more. Afterwards, we use our knowledge to solve extra tasks involving file paths and redirects, completing the challenge for the gold medal!"
cover = "img/writeups/holiday-hack-challenge/2024/act1/curling/cover.png"
tags = [
"Holiday Hack Challenge",

@ -3,7 +3,7 @@ author = "Maik de Kruif"
title = "Frosty Keypad"
subtitle = "Act 1 - SANS Holiday Hack Challenge 2024"
date = 2024-11-24T18:23:54+01:00
description = "In the fourth challenge of the Holiday Hack Challenge 2024, we'll explore how to use curl using the Linux manpages."
description = "In this challenge, we help Morcel Nougat recover a shredded document by decoding clues from a book and using an old-school telephone keypad. After enabling a hidden flashlight, we script a solution to bypass rate limits and crack the final code, solving both the Silver and Gold challenges!"
cover = "img/writeups/holiday-hack-challenge/2024/act1/frosty-keypad/cover.png"
tags = [
"Holiday Hack Challenge",

@ -3,7 +3,7 @@ author = "Maik de Kruif"
title = "Elf Connect"
subtitle = "Prologue - SANS Holiday Hack Challenge 2024"
date = 2024-11-21T14:23:34+01:00
description = "Let's play our first game of the Holiday Hack Challenge. To win, we'll have to use the DevTools to read some code, and figure out how the scoring mechanism works."
description = "In Elf Connect, we help Angel Candysalt solve a word-matching puzzle. After earning the silver medal by finding groups of related words, we dig into the game’s code using DevTools. By analyzing the scoring logic, we bypass the normal gameplay and directly trigger the gold medal with a simple code execution in the browser console!"
cover = "img/writeups/holiday-hack-challenge/2024/prologue/elf-connect/cover.png"
tags = [
"Holiday Hack Challenge",
@ -98,7 +98,7 @@ Object.keys(wordSets).map((round) =>
This might look a little complicated, so let me explain it for you. We start by looping over `wordSets`, this contains all the words for a specific round. We then look at the correct sets, and map the four indices to the actual word in the list. If we execute this code, we get the following output:
{{< code language="json" title="Results" isCollapsed="true" >}}
{{< collapsible-block badge="json" title="Results" isCollapsed="true" >}}
```json
[
@ -129,7 +129,7 @@ This might look a little complicated, so let me explain it for you. We start by
]
```
{{< /code >}}
{{< /collapsible-block >}}
This just get us the correct answer though, and we'll need more for gold.

@ -3,7 +3,7 @@ author = "Maik de Kruif"
title = "Elf Minder"
subtitle = "Prologue - SANS Holiday Hack Challenge 2024"
date = 2024-11-21T15:18:53+01:00
description = "On to our second game of the Holiday Hack Challenge. This time we'll have to find some routes."
description = "In Elf Minder, we guide an elf through twelve levels of maze-like puzzles. Silver is straightforward; solve the puzzles normally. For gold, we inspect the game’s code with DevTools and find hidden admin controls. By enabling them, we can clear obstacles and draw a path directly to the finish. Alternatively, we manipulate springs to bounce the elf straight to the end. Both methods secure the gold medal!"
cover = "img/writeups/holiday-hack-challenge/2024/prologue/elf-minder/cover.png"
tags = [
"Holiday Hack Challenge",
@ -113,7 +113,7 @@ From the hint given in the conversation with the elf Poinsettia, we got the foll
A good starting point here would be to first figure out how the springs work.
{{< code language="js" title="guide.js (getSpringTarget)" isCollapsed="true" >}}
{{< collapsible-block badge="js" title="guide.js (getSpringTarget)" isCollapsed="true" >}}
```js
getSpringTarget(springCell) {
@ -157,7 +157,7 @@ getSpringTarget(springCell) {
}
```
{{< /code >}}
{{< /collapsible-block >}}
In one of the source files, `guide.js`, there is a function called `getSpringTarget`. This function, as the name suggests, returns the location where the elf should go after encountering a spring.

@ -3,7 +3,7 @@ author = "Maik de Kruif"
title = "Holiday Hack Orientation"
subtitle = "Prologue - SANS Holiday Hack Challenge 2024"
date = 2024-11-21T13:46:55+01:00
description = "An easy start of the Holiday Hack Challenge 2024."
description = "In the Holiday Hack Orientation, we meet Jingle Ringford, who introduces us to the 2024 SANS Holiday Hack Challenge. Our first task is simple; enter the correct answer in the “First Terminal” to unlock the gold medal and begin the adventure!"
cover = "img/writeups/holiday-hack-challenge/2024/prologue/orientation/cover.png"
tags = [
"Holiday Hack Challenge",

@ -71,31 +71,3 @@ a.button {
padding: 14px 24px;
}
}
.code-toolbar {
margin-bottom: 20px;
.toolbar-item a {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 3px 8px;
margin-bottom: 5px;
background: $light-background-secondary;
text-decoration: none;
text-align: center;
font-size: 13px;
font-weight: 500;
border-radius: 8px;
border: 1px solid transparent;
appearance: none;
cursor: pointer;
outline: none;
.dark-theme & {
background: $dark-background-secondary;
color: inherit;
}
}
}

@ -1,4 +1,4 @@
.collapsable-code {
.collapsible-block {
position: relative;
width: 100%;
margin: 40px 0;
@ -8,41 +8,50 @@
visibility: hidden;
}
.highlight,
.code-toolbar .highlight {
&__content {
max-height: 80vh;
overflow: auto;
transition: max-height 0.15s ease;
transition: max-height 0.15s ease, padding-top 0.15s ease,
padding-bottom 0.15s ease;
border-bottom-left-radius: 10px;
border-bottom-right-radius: 10px;
background-color: lighten($light-background-secondary, 5%);
.dark-theme & {
background-color: darken($dark-background-secondary, 6%);
}
padding: 0 1em;
&:has(> :last-child:nth-child(1)),
&:not(:has(*)) {
padding: 1em;
}
&:has(.highlight) {
padding: 0 !important;
}
}
input[type="checkbox"]:checked {
~ .highlight,
~ .code-toolbar .highlight {
~ .collapsible-block__content {
max-height: 0;
padding: 0;
padding-top: 0;
padding-bottom: 0;
border-top: none;
overflow: hidden;
}
~ .code-toolbar {
padding: 0;
border-top: none;
.toolbar {
display: none;
}
}
~ label {
border-radius: 10px;
transition: border-radius 0.15s ease 0.1s;
}
~ label .collapsable-code__toggle:after {
~ label .collapsible-block__toggle:after {
content: attr(data-label-expand);
}
}
@ -59,6 +68,7 @@
min-height: 30px;
margin: 0;
cursor: pointer;
transition: border-radius 0s ease 0s;
.dark-theme & {
background: $dark-background-secondary;
@ -79,7 +89,7 @@
}
}
&__language {
&__badge {
background: $light-background;
color: $light-color;
border-radius: 10px;
@ -112,8 +122,4 @@
margin-bottom: 0;
border-radius: 0;
}
.code-toolbar {
margin: 0;
}
}

@ -304,8 +304,9 @@ pre {
}
blockquote {
position: relative;
border-left: 2px solid;
margin: 40px;
margin: 20px 40px;
padding: 10px 20px;
@media #{$media-size-phone} {
@ -315,12 +316,12 @@ blockquote {
&:before {
content: "";
font-family: Georgia, serif;
// font-family: Georgia, serif;
font-display: auto;
font-size: 3.875rem;
position: absolute;
left: -40px;
top: -20px;
top: -13px;
}
p:first-of-type {

@ -16,5 +16,5 @@
@import "portfolios";
@import "footer";
@import "sharing-buttons";
@import "code";
@import "collapsible-block";
@import "masonry";

@ -1,17 +0,0 @@
{{ $id := delimit (shuffle (seq 1 9)) "" }}
{{ if .Get "language" }}
<div class="collapsable-code">
<input id="{{ .Get "id" | default $id }}" type="checkbox" {{ if ( eq ( .Get "isCollapsed" ) "true" ) -}} checked
{{- end }} />
<label for="{{ .Get "id" | default $id }}">
<span class="collapsable-code__language">{{ .Get "language" }}</span>
{{ if .Get "title" }}<span class="collapsable-code__title">{{ .Get "title" | markdownify }}</span>{{ end }}
<span class="collapsable-code__toggle" data-label-expand="{{ .Get "expand" | default "" }}"
data-label-collapse="{{ .Get "collapse" | default "▽" }}"></span>
</label>
{{ .Inner | markdownify }}
</div>
{{ else }}
{{ errorf "If you want to use the \"collapsable code\" shortcode, you need to pass a mandatory \"language\" param. The issue occured in %q (%q)" .Page.File .Page.Permalink }}
{{ end }}

@ -0,0 +1,17 @@
{{ $id := delimit (shuffle (seq 1 9)) "" }}
<div class="collapsible-block">
<input id="{{ .Get "id" | default $id }}" type="checkbox" {{ if ( eq ( .Get "isCollapsed" ) "true" ) -}} checked
{{- end }} />
<label for="{{ .Get "id" | default $id }}">
{{- with .Get "badge" }}
<span class="collapsible-block__badge">{{ . }}</span>
{{- end }}
{{ if .Get "title" }}<span class="collapsible-block__title">{{ .Get "title" | markdownify }}</span>{{ end }}
<span class="collapsible-block__toggle" data-label-expand="{{ .Get "expand" | default "" }}"
data-label-collapse="{{ .Get "collapse" | default "▽" }}"></span>
</label>
<div class="collapsible-block__content">
{{ .Inner | markdownify }}
</div>
</div>
Loading…
Cancel
Save