@ -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.
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.
{{<figuresrc="/img/posts/liveoverflow-minecraft-server/first_ip_screenshot.png"title="Screenshot of video containing the IP address">}}
{{<figuresrc="/img/posts/liveoverflow-minecraft-server/first_ip_screenshot.png"title="Screenshot of video containing the IP address">}}
### IP change
### 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.
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.
_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)_
_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)_
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.
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.
@ -41,12 +41,12 @@ When opening the source of the page we also find the following comment: "Here is
```js
```js
function send() {
function send() {
let emoji = $("#emoji")[0].value;
let emoji = $("#emoji")[0].value;
if (emoji.length > 0) {
if (emoji.length > 0) {
$.post("/", { emoji: emoji }, function (data) {
$.post("/", { emoji: emoji }, function (data) {
$("#msg")[0].innerHTML = "<b>" + data + "</b>";
$("#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.
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.
@ -41,12 +41,12 @@ When opening the source of the page we also find the following comment: "Here is
```js
```js
function send() {
function send() {
let emoji = $("#emoji")[0].value;
let emoji = $("#emoji")[0].value;
if (emoji.length > 0) {
if (emoji.length > 0) {
$.post("/", { emoji: emoji }, function (data) {
$.post("/", { emoji: emoji }, function (data) {
$("#msg")[0].innerHTML = "<b>" + data + "</b>";
$("#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:
After submitting this, we get the following result:
{{<codelanguage="text"title="Result">}}
{{<collapsible-blockbadge="text"title="Result">}}
```js
```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:
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`:
@ -97,7 +97,7 @@ In [3]: pickle.loads(base64.b64decode("gAN9cQAoWAUAAABib2FyZHEBXXECKF1xAyhYAQAAA
This time our board is quite a bit larger:
This time our board is quite a bit larger:
{{<codelanguage="py"title="Board">}}
{{<collapsible-blockbadge="py"title="Board">}}
```py
```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.
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:
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:
{{<codelanguage="py"title="solve.py">}}
{{<collapsible-blockbadge="py"title="solve.py">}}
```python
```python
import hashlib
import hashlib
@ -304,7 +304,7 @@ if __name__ == "__main__":
print(export_base64(game))
print(export_base64(game))
```
```
{{</code>}}
{{</collapsible-block>}}
After running this script, we get the following result:
After running this script, we get the following result:
@ -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`.
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`.
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.
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
```js
function check() {
function check() {
// Get key from localStorage
// Get key from localStorage
// The key is initialized in startup()
// The key is initialized in startup()
// > "eyJ1c2VyaWQiOjB9.1074"
// > "eyJ1c2VyaWQiOjB9.1074"
key = localStorage.getItem("key");
key = localStorage.getItem("key");
// Get the token from the url
// Get the token from the url
// > "token=eyJ1c2VyaWQiOjB9.1074"
// > "token=eyJ1c2VyaWQiOjB9.1074"
hash = window.location.search.split("?")[1];
hash = window.location.search.split("?")[1];
// If key and hash are not empty:
// If key and hash are not empty:
if (key !== null && hash != "token=" + key) {
if (key !== null && hash != "token=" + key) {
// Split the key by a .
// Split the key by a .
// > (2)["eyJ1c2VyaWQiOjB9", "1074"]
// > (2)["eyJ1c2VyaWQiOjB9", "1074"]
parts = key.split(".");
parts = key.split(".");
// Decode the base64 from the first part of the key
// Decode the base64 from the first part of the key
// > "{"userid":0}"
// > "{"userid":0}"
text = atob(parts[0]);
text = atob(parts[0]);
// Get the value of the second part of the key as an int
// Get the value of the second part of the key as an int
// > 1074
// > 1074
checksum = parseInt(parts[1]);
checksum = parseInt(parts[1]);
// Calculate the value of text
// Calculate the value of text
// > 1074
// > 1074
count = calculate(text);
count = calculate(text);
// If the last part of the key is correct:
// If the last part of the key is correct:
if (count == checksum) {
if (count == checksum) {
// Execute this function after 5000ms
// Execute this function after 5000ms
setTimeout(function () {
setTimeout(function () {
// Execute a get request with the token parameter
// Execute a get request with the token parameter
window.location = "index.php?token=" + key;
window.location = "index.php?token=" + key;
}, 5000);
}, 5000);
}
}
}
}
}
}
```
```
@ -148,14 +148,14 @@ Let's turn this into some code:
@ -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:
> 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),
> - [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,
> - [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 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).
> 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:
> The `controlCar` must return an integer denoting where the car should drive:
>
>
> - -1 (or any other negative value): drive more to the left,
> - -1 (or any other negative value): drive more to the left,
> - 0: continue straight / straighten up the car,
> - 0: continue straight / straighten up the car,
> - 1 (or any other positive value): drive more to the right.
> - 1 (or any other positive value): drive more to the right.
When opening the source, we also find the following comment:
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:
To solve this challenge, I came up with the following script:
{{<codelanguage="js"title="solve.js">}}
{{<collapsible-blockbadge="js"title="solve.js">}}
```js
```js
function controlCar(scanArray) {
function controlCar(scanArray) {
if (!window.has_reset_game) {
if (!window.has_reset_game) {
window.has_reset_game = true;
window.has_reset_game = true;
window.car_position = 0;
window.car_position = 0;
window.queue = [];
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;
}
}
left = scanArray[left];
if (window.queue.length === 0) {
center = scanArray[center];
let left, center, right;
right = scanArray[right];
if (window.car_position === -1) {
let furthest = Math.max(left, center, right);
left = 8;
let closest = Math.min(left, center, right);
center = 12;
right = 15;
console.log(left, center, right);
} else if (window.car_position === 0) {
left = 4;
let moveInDirection = (direction) => {
center = 8;
console.log("Going in direction", direction);
right = 12;
if (direction === window.car_position) {
} else if (window.car_position === 1) {
window.queue.push(0);
left = 1;
} else if (direction > window.car_position) {
center = 4;
window.queue.push(1, 1, 1, 1);
right = 8;
window.car_position += 1;
}
} else if (direction <window.car_position){
window.queue.push(-1, -1, -1, -1);
left = scanArray[left];
window.car_position -= 1;
center = scanArray[center];
}
right = scanArray[right];
};
let furthest = Math.max(left, center, right);
if (closest <0)moveInDirection(window.car_position);
let closest = Math.min(left, center, right);
else if (furthest === left) moveInDirection(-1);
else if (furthest === center) moveInDirection(0);
console.log(left, center, right);
else if (furthest === right) moveInDirection(1);
}
let moveInDirection = (direction) => {
console.log("Going in direction", direction);
return window.queue.pop();
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.
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.
subtitle = "Act 1 - SANS Holiday Hack Challenge 2024"
subtitle = "Act 1 - SANS Holiday Hack Challenge 2024"
date = 2024-11-23T11:44:53+01:00
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!"
subtitle = "Act 1 - SANS Holiday Hack Challenge 2024"
subtitle = "Act 1 - SANS Holiday Hack Challenge 2024"
date = 2024-11-24T18:23:54+01:00
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!"
subtitle = "Prologue - SANS Holiday Hack Challenge 2024"
subtitle = "Prologue - SANS Holiday Hack Challenge 2024"
date = 2024-11-21T14:23:34+01:00
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!"
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:
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:
subtitle = "Prologue - SANS Holiday Hack Challenge 2024"
subtitle = "Prologue - SANS Holiday Hack Challenge 2024"
date = 2024-11-21T15:18:53+01:00
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!"
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.
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.
subtitle = "Prologue - SANS Holiday Hack Challenge 2024"
subtitle = "Prologue - SANS Holiday Hack Challenge 2024"
date = 2024-11-21T13:46:55+01:00
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!"
{{ 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 }}