parent
5cf47899c3
commit
0782ceb77a
5 changed files with 336 additions and 0 deletions
@ -0,0 +1,336 @@ |
||||
+++ |
||||
author = "Maik de Kruif" |
||||
title = "Secret Location - Base" |
||||
subtitle = "Beginners Quest 4 - Google CTF" |
||||
date = 2021-09-24T16:33:25+01:00 |
||||
description = "A writeup for challenge 4 of the beginners quests of the Google CTF." |
||||
cover = "img/writeups/google-ctf/2021/beginners-quest/4/cover.png" |
||||
tags = [ |
||||
"Google CTF", |
||||
"Beginners Quest", |
||||
"ctf", |
||||
"hacking", |
||||
"writeup", |
||||
"web", |
||||
"coding", |
||||
] |
||||
categories = [ |
||||
"ctf", |
||||
"writeups", |
||||
"hacking", |
||||
] |
||||
+++ |
||||
|
||||
## Story line |
||||
|
||||
You’re taking a stroll in the lab, when Dr. Klostermann is calling your name: "Agent, we’ve discovered the origin of the device. This time you won’t be able to reach your destination by air, but by the new Trans-Sibiriean Railway, as opposed to the old one, which runs along side it at the same time, it is a bit odd. And it goes to Shenzhen. I am sorry agent, but the further you go into this task, the more precautions you will have to take, and remember, the enemy can be anyone. It could be a conductor, the engineer, it could even be our own people that will meet you at the spot you need to be at. Be selective with who you trust. I think you got the point, go now, I got much to do. Agent, much depends on you!." |
||||
|
||||
### Attachment |
||||
|
||||
[attachment.zip](/files/writeups/google-ctf/2021/beginners-quest/4/attachment.zip) |
||||
|
||||
## Recon |
||||
|
||||
When opening the attachment, we can find two files: `chal.c` and `pico.uf2`. |
||||
|
||||
Before this challenge I had never heard of a `uf2` file, but from googling "pico.uf2", I found that it is probably a firmware file for the Paspberry Pi Pico. |
||||
|
||||
While I would have loved to play around with that, I didn't have one at hand. So we'll have to do with the `chal.c` file (which is probably the file running in the firmware). |
||||
|
||||
### `chal.c` |
||||
|
||||
{{< code language="c" title="chal.c" isCollapsed="true" >}} |
||||
|
||||
```c |
||||
#include <stdbool.h> |
||||
|
||||
#include "hardware/gpio.h" |
||||
#include "hardware/structs/sio.h" |
||||
#include "pico/stdlib.h" |
||||
|
||||
int main(void) |
||||
{ |
||||
for (int i = 0; i < 8; i++) { |
||||
gpio_init(i); |
||||
gpio_set_dir(i, GPIO_OUT); |
||||
} |
||||
gpio_put_all(0); |
||||
|
||||
for (;;) { |
||||
gpio_set_mask(67); |
||||
gpio_clr_mask(0); |
||||
sleep_us(100); |
||||
gpio_set_mask(20); |
||||
gpio_clr_mask(3); |
||||
sleep_us(100); |
||||
gpio_set_mask(2); |
||||
gpio_clr_mask(16); |
||||
sleep_us(100); |
||||
gpio_set_mask(57); |
||||
gpio_clr_mask(4); |
||||
sleep_us(100); |
||||
gpio_set_mask(0); |
||||
gpio_clr_mask(25); |
||||
sleep_us(100); |
||||
gpio_set_mask(5); |
||||
gpio_clr_mask(2); |
||||
sleep_us(100); |
||||
gpio_set_mask(18); |
||||
gpio_clr_mask(65); |
||||
sleep_us(100); |
||||
gpio_set_mask(1); |
||||
gpio_clr_mask(2); |
||||
sleep_us(100); |
||||
gpio_set_mask(64); |
||||
gpio_clr_mask(17); |
||||
sleep_us(100); |
||||
gpio_set_mask(2); |
||||
gpio_clr_mask(0); |
||||
sleep_us(100); |
||||
gpio_set_mask(1); |
||||
gpio_clr_mask(6); |
||||
sleep_us(100); |
||||
gpio_set_mask(18); |
||||
gpio_clr_mask(65); |
||||
sleep_us(100); |
||||
gpio_set_mask(1); |
||||
gpio_clr_mask(0); |
||||
sleep_us(100); |
||||
gpio_set_mask(4); |
||||
gpio_clr_mask(2); |
||||
sleep_us(100); |
||||
gpio_set_mask(0); |
||||
gpio_clr_mask(0); |
||||
sleep_us(100); |
||||
gpio_set_mask(64); |
||||
gpio_clr_mask(16); |
||||
sleep_us(100); |
||||
gpio_set_mask(16); |
||||
gpio_clr_mask(64); |
||||
sleep_us(100); |
||||
gpio_set_mask(2); |
||||
gpio_clr_mask(4); |
||||
sleep_us(100); |
||||
gpio_set_mask(0); |
||||
gpio_clr_mask(3); |
||||
sleep_us(100); |
||||
gpio_set_mask(9); |
||||
gpio_clr_mask(0); |
||||
sleep_us(100); |
||||
gpio_set_mask(0); |
||||
gpio_clr_mask(1); |
||||
sleep_us(100); |
||||
gpio_set_mask(0); |
||||
gpio_clr_mask(8); |
||||
sleep_us(100); |
||||
gpio_set_mask(8); |
||||
gpio_clr_mask(0); |
||||
sleep_us(100); |
||||
gpio_set_mask(65); |
||||
gpio_clr_mask(24); |
||||
sleep_us(100); |
||||
gpio_set_mask(22); |
||||
gpio_clr_mask(64); |
||||
sleep_us(100); |
||||
gpio_set_mask(0); |
||||
gpio_clr_mask(0); |
||||
sleep_us(100); |
||||
gpio_set_mask(0); |
||||
gpio_clr_mask(5); |
||||
sleep_us(100); |
||||
gpio_set_mask(0); |
||||
gpio_clr_mask(2); |
||||
sleep_us(100); |
||||
gpio_set_mask(65); |
||||
gpio_clr_mask(16); |
||||
sleep_us(100); |
||||
gpio_set_mask(22); |
||||
gpio_clr_mask(65); |
||||
sleep_us(100); |
||||
gpio_set_mask(1); |
||||
gpio_clr_mask(6); |
||||
sleep_us(100); |
||||
gpio_set_mask(4); |
||||
gpio_clr_mask(0); |
||||
sleep_us(100); |
||||
gpio_set_mask(66); |
||||
gpio_clr_mask(21); |
||||
sleep_us(100); |
||||
gpio_set_mask(1); |
||||
gpio_clr_mask(0); |
||||
sleep_us(100); |
||||
gpio_set_mask(0); |
||||
gpio_clr_mask(2); |
||||
sleep_us(100); |
||||
gpio_set_mask(24); |
||||
gpio_clr_mask(65); |
||||
sleep_us(100); |
||||
gpio_set_mask(67); |
||||
gpio_clr_mask(24); |
||||
sleep_us(100); |
||||
gpio_set_mask(24); |
||||
gpio_clr_mask(67); |
||||
sleep_us(100); |
||||
gpio_set_mask(2); |
||||
gpio_clr_mask(8); |
||||
sleep_us(100); |
||||
gpio_set_mask(65); |
||||
gpio_clr_mask(18); |
||||
sleep_us(100); |
||||
gpio_set_mask(16); |
||||
gpio_clr_mask(64); |
||||
sleep_us(100); |
||||
gpio_set_mask(2); |
||||
gpio_clr_mask(0); |
||||
sleep_us(100); |
||||
gpio_set_mask(68); |
||||
gpio_clr_mask(19); |
||||
sleep_us(100); |
||||
gpio_set_mask(19); |
||||
gpio_clr_mask(64); |
||||
sleep_us(100); |
||||
gpio_set_mask(72); |
||||
gpio_clr_mask(2); |
||||
sleep_us(100); |
||||
gpio_set_mask(2); |
||||
gpio_clr_mask(117); |
||||
sleep_us(100); |
||||
|
||||
gpio_put_all(0); |
||||
sleep_ms(500); |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
``` |
||||
|
||||
{{< /code >}} |
||||
|
||||
In this code, we see a lot of calls to the functions `gpio_set_mask()` and `gpio_clr_mask()`. When looking up what these to, we find [this documentation](https://raspberrypi.github.io/pico-sdk-doxygen/group__hardware__gpio.html): |
||||
|
||||
{{< figure src="/img/writeups/google-ctf/2021/beginners-quest/4/doc-functions.png" title="Functions documentation" >}} |
||||
|
||||
{{< figure src="/img/writeups/google-ctf/2021/beginners-quest/4/doc-set-mask.png" title="gpio_set_mask() documentation" >}} |
||||
|
||||
### Bitmasks |
||||
|
||||
In the `gpio_set_mask()` documentation, we see that it wants a bitmask of GPIO values. So what is a bitmask? |
||||
|
||||
A bitmask is used for logical operations to transform an array of bits using another array. For example, a bitmask can be used with OR: |
||||
|
||||
| Operation | Value | |
||||
| --------- | ---------------------------- | |
||||
| | `1001 0101` | |
||||
| OR | **`1111 0000`** <- _bitmask_ | |
||||
| = | `1111 0101` | |
||||
|
||||
## Solving |
||||
|
||||
To get the values at every `sleep()`, we just have to apply the masks one by one. |
||||
|
||||
But before we can do that, we first need the individual values to work with. To get them, I wrote the following python script. |
||||
|
||||
```py |
||||
set_mask_str = "gpio_set_mask" |
||||
clr_mask_str = "gpio_clr_mask" |
||||
|
||||
set_masks = [] |
||||
clr_masks = [] |
||||
|
||||
with open("chal.c", "r") as file: |
||||
for line in file: |
||||
set_mask_loc = line.find(set_mask_str) |
||||
clr_mask_loc = line.find(clr_mask_str) |
||||
|
||||
end = line.find(")") |
||||
|
||||
if set_mask_loc != -1: |
||||
set_masks.append( |
||||
int(line[set_mask_loc + len(set_mask_str) + 1:end])) |
||||
|
||||
if clr_mask_loc != -1: |
||||
clr_masks.append( |
||||
int(line[clr_mask_loc + len(clr_mask_str) + 1:end])) |
||||
``` |
||||
|
||||
All this script does, is read the `chal.c` file line by line. If the line contains either the `gpio_set_mask()` or the `gpio_clr_mask()` function, it gets the location of the parameter and appends it to a list. |
||||
|
||||
In the end we get two lists: `set_masks` and `clr_masks`. |
||||
|
||||
### Applying the masks |
||||
|
||||
Now comes the more difficult part, we have to apply these masks. |
||||
|
||||
For setting the masks, we can use the bitwise OR operation (`|`). It works like this: |
||||
|
||||
| State | Value | |
||||
| ------------- | --------------- | |
||||
| Initial value | `1001 0101` | |
||||
| Bitmask | **`1111 0000`** | |
||||
| Result | `1111 0101` | |
||||
|
||||
As we can see in this table, it now set the bytes passed to `gpio_set_mask()` to true. |
||||
|
||||
Clearing the masks is a little harder. For this we'll need to first invert the bitmask (`~`), and than use the bistwise AND operation (`&`) with the current value. It would work like this: |
||||
|
||||
| State | Value | |
||||
| -------------- | --------------- | |
||||
| Initial value | `1111 0101` | |
||||
| Bitmask | **`1100 0010`** | |
||||
| Invert bismask | **`0011 1101`** | |
||||
| Result | `0011 0101` | |
||||
|
||||
If we turn this into a python script, it would look like this: |
||||
|
||||
```py |
||||
current_output = 0 |
||||
flag = "" |
||||
|
||||
for set_mask, clr_mask in zip(set_masks, clr_masks): |
||||
current_output |= set_mask |
||||
current_output &= ~ clr_mask |
||||
flag += chr(current_output) |
||||
|
||||
print(flag.strip()) |
||||
``` |
||||
|
||||
{{< code language="py" title="Full code" isCollapsed="true" >}} |
||||
|
||||
```py |
||||
set_mask_str = "gpio_set_mask" |
||||
clr_mask_str = "gpio_clr_mask" |
||||
|
||||
set_masks = [] |
||||
clr_masks = [] |
||||
|
||||
with open("chal.c", "r") as file: |
||||
for line in file: |
||||
set_mask_loc = line.find(set_mask_str) |
||||
clr_mask_loc = line.find(clr_mask_str) |
||||
|
||||
end = line.find(")") |
||||
|
||||
if set_mask_loc != -1: |
||||
set_masks.append( |
||||
int(line[set_mask_loc + len(set_mask_str) + 1:end])) |
||||
|
||||
if clr_mask_loc != -1: |
||||
clr_masks.append( |
||||
int(line[clr_mask_loc + len(clr_mask_str) + 1:end])) |
||||
|
||||
current_output = 0 |
||||
flag = "" |
||||
|
||||
for set_mask, clr_mask in zip(set_masks, clr_masks): |
||||
current_output |= set_mask |
||||
current_output &= ~ clr_mask |
||||
flag += chr(current_output) |
||||
|
||||
print(flag.strip()) |
||||
``` |
||||
|
||||
{{< /code >}} |
||||
|
||||
## Solution |
||||
|
||||
When executing this code, we get the flag! It's `CTF{be65dfa2355e5309808a7720a615bca8c82a13d7}`. |
Binary file not shown.
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 20 KiB |
Loading…
Reference in new issue