Skip to content

Commit e5d7a78

Browse files
author
DanArmor
committed
feat: en version babygame-02, tic-tac. Typos
1 parent 674e74c commit e5d7a78

File tree

5 files changed

+141
-27
lines changed

5 files changed

+141
-27
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# babygame02 #
2+
3+
## Overview ##
4+
5+
200 points
6+
7+
Category: [Binary Exploitation](../)
8+
9+
Tags : `#picoCTF 2023` `Binary Exploitation` `game`
10+
11+
## Description ##
12+
13+
Break the game and get the flag.
14+
Additional details will be available after launching your challenge instance.
15+
16+
## Solution ##
17+
18+
Скачиваем предложенный экзешник игры для анализа.
19+
[Запускаем Гидру](https://github.com/NationalSecurityAgency/ghidra/releases)
20+
21+
Декомпилируем. Расставляем удобные нам имена локальных переменных, чтобы код читался проще
22+
Замечаем функцию `win`, которая выводит флаг - ищем референс на неё и понимаем, что она нигде не вызывается.
23+
24+
Смотрим функцию `move_player` и видим не упомянутую команду `l<символ>` которая меняет символ, представляющий игрока на поле с `@` на любой введенный. Значит, мы можем поменять один байт внутри массива чаров, представляющего карту.
25+
26+
Замечаем, что на "карту"(массив чаров длинной 2700) игрок выставляется следующей строчкой кода по анализу Гидры(undefined имеет длину 1 байт):
27+
`*(undefined *)(*playerCoordY * 0x5a + map + playerCoordY[1]) = player_tile;`
28+
29+
Это значит, что мы можем ходить по памяти по одному байту за пределами карты, т.к. выражение в скобках - `int` и он приводится потом к указателю на однобайтовый тип данных, разыменовав который мы устанавливаем значок игрока на карту
30+
31+
Замечаем, что адрес возврата из `move_player` в `main` равен 080497**04**, а адрес начала функции `win` равен 080497**5d**, которые как раз различаются на один байт. А мы как раз обладаем возможностью изменить один байт в любой точки памяти из-за способа адресации, выбранного создателем игры.
32+
33+
Значение **5d** равно символу `']'`.
34+
35+
Запускаем удобный дебагер - я воспользовался [gdb+gef](https://github.com/hugsy/gef), ставим брейкпоинт на `move_player` и смотрим, как выглядит стек.
36+
37+
Смещение от начала массива, представляющего карту до первого байта адреса возврата из `move_player` в main равно 39. Это значит, что нам надо от левого верхнего угла 39 раз повторить ход влево (от левого - т.к. мы ползем вверх по стеку - в сторону уменьшения адресов)
38+
39+
При попытке просто проехаться на 39 влево мы цепляем важное и все крашит - поэтому мы делаем шаг вверх, чтобы "загрязнять" своими похождениями мусорные байты(ход вверх сместил нас на 90 байт вверх по стеку).
40+
41+
После 39 влево делаем один раз вниз (получаем минус 90 байт, которые мы прибавили ранее ходом вверх) - и попадаем на нужный байт. При установке на него его значение заменяется значком нашего игрока - поэтому предварительно выполняем команду `l]`
42+
43+
Тестируем локально. Радуемся - все получилось - мы подменили адрес возврата на адрес начала `win` и вызвали её
44+
45+
Запускаем дистанционно - ничего не работает.
46+
47+
Почему-то буфер не сбрасывается, если мы приходим в самое начало функции `win` 080497**5d**, поэтому пробуем последующие адреса вида 080497**xx** (т.к. мы можем менять только один байт), пока не получится
48+
49+
Сработало на адресе 080497**79**, а `0x79` - это символ `y`
50+
51+
Так мы и получили нашу полезную нагрузку для этого задания и флаг
52+
53+
------
54+
Последовательность ввода для получения флага:
55+
```
56+
ly
57+
aaaa
58+
wwwww
59+
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
60+
s
61+
```
62+
------

Binary Exploitation/babygame02/babygame02.md

+26-18
Original file line numberDiff line numberDiff line change
@@ -15,41 +15,49 @@ Additional details will be available after launching your challenge instance.
1515

1616
## Solution ##
1717

18-
Скачиваем предложенный экзешник игры для анализа
19-
[Запускаем Гидру](https://github.com/NationalSecurityAgency/ghidra/releases)
18+
Let's download **.exe**.
19+
[Start Ghidra](https://github.com/NationalSecurityAgency/ghidra/releases)
2020

21-
Декомпилируем. Расставляем удобные нам имена локальных переменных, чтобы код читался проще
22-
Замечаем функцию `win`, которая выводит флаг - ищем референс на неё и понимаем, что она нигде не вызывается.
21+
Decompiling. Arrange the local variable names, so that the code is easier to read.
22+
Note the `win` function that outputs the flag - there is not reference to it, it is not called anywhere.
2323

24-
Смотрим функцию move_player и видим не упомянутую команду `l<символ>` которая меняет символ, представляющий игрока на поле с `@` на любой введенный. Значит, мы можем поменять один байт внутри массива чаров, представляющего карту.
24+
Inside the `move_player` function we can see a hidden command `l<symbol>` - it changes the symbol, that represents the player.
25+
26+
So we can use it as follows:
27+
1. player:`@`
28+
2. command:`l3`
29+
3. player: `3`
30+
31+
It means, that we can change one byte inside the array of chars, that represents a map.
32+
33+
The following line is responsible for placing player character on the map:(undefined size is 1 byte):
2534

26-
Замечаем, что на "карту"(массив чаров длинной 2700) игрок выставляется следующей строчкой кода по анализу Гидры(undefined имеет длину 1 байт):
2735
`*(undefined *)(*playerCoordY * 0x5a + map + playerCoordY[1]) = player_tile;`
2836

29-
Это значит, что мы можем ходить по памяти по одному байту за пределами карты, т.к. выражение в скобках - `int` и он приводится потом к указателю на однобайтовый тип данных, разыменовав который мы устанавливаем значок игрока на карту
37+
It means, that we can travel across the memory byte by byte, because `int` value `(*playerCoordY * 0x5a + map + playerCoordY[1])` was casted to a pointer on value of size 1 byte. And we can change one byte anywhere in the stack. It's not much we can do - and the first (and it is right) thought would be about changing the return address.
3038

31-
Замечаем, что адрес возврата из `move_player` в `main` равен 080497**04**, а адрес начала функции `win` равен 080497**5d**, которые как раз различаются на один байт. А мы как раз обладаем возможностью изменить один байт в любой точки памяти из-за способа адресации, выбранного создателем игры.
39+
We can see, that return address of `move_player` inside `main` is 080497**04** and start address of the `win` function is 080497**5d**. They differ by one byte. Now we, what we need to do.
3240

33-
Запускаем удобный дебагер - я воспользовался [gdb+gef](https://github.com/hugsy/gef), ставим брейкпоинт на move_player и смотрим, как выглядит стек.
41+
**5d** is equal to char `']'`.
3442

35-
Смещение от начала массива, представляющего карту до первого байта адреса возврата из move_player в main равно 39. Это значит, что нам надо от левого верхнего угла 39 раз повторить ход влево (от левого - т.к. мы ползем вверх по стеку - в сторону уменьшения адресов)
43+
Run a debugger you're comfortable with - I was using [gdb+gef](https://github.com/hugsy/gef). Place breakpoint on `move_player` and inspect the stack.
3644

37-
При попытке просто проехаться на 39 влево мы цепляем важное и все крашит - поэтому мы делаем шаг вверх, чтобы "загрязнять" своими похождениями мусорные байты(ход вверх сместил нас на 90 байт вверх по стеку).
45+
Offset from the beginning of the array to the first byte of the return address from `move_player` is equal to **39**. It means, that we need to make 39 steps to the left from the top left corner.
3846

39-
После 39 влево делаем один раз вниз (получаем минус 90 байт, которые мы прибавили ранее ходом вверх) - и попадаем на нужный байт. При установке на него его значение заменяется значком нашего игрока - поэтому предварительно выполняем команду `l]`
47+
But program will crush, if you do like that. So we need to move up from top left conner (because with that we will move by 90 bytes in one step, and will not overwrite something important on the stack with our player-char).
4048

41-
Тестируем локально. Радуемся - все получилось - мы подменили адрес возврата на адрес начала `win` и вызвали её
49+
So we need to make one step up. Then we make 39 steps to the left. And finally - make one step down (it eliminates out +90 bytes offset from the beginning) - and it's done.
4250

43-
Запускаем дистанционно - ничего не работает.
51+
Locally it will work just fune. Yay!
4452

45-
Почему-то буфер не сбрасывается, если мы приходим в самое начало функции win 080497**5d**, поэтому пробуем последующие адреса вида 080497**xx** (т.к. мы можем менять только один байт), пока не получится
53+
Then you will run that remote and it will not work.
4654

47-
Сработало на адресе 080497**79**, а `0x79` - это символ `y`
55+
I don't know why, but buffer will not flush, if you jump exactly to 080497**5d** - the beginning of the `win`. So we just try addresses of next instructions until it works.
4856

49-
Так мы и получили нашу полезную нагрузку для этого задания и флаг
57+
It worked with 080497**79**, and `0x79` == `'y'`
5058

5159
------
52-
Последовательность ввода для получения флага:
60+
So, here is the input for the task:
5361
```
5462
ly
5563
aaaa
+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# tic-tac #
2+
3+
## Overview ##
4+
5+
200 points
6+
7+
Category: [Binary Exploitation](../)
8+
9+
Tags : `#picoCTF 2023` `Binary Exploitation` `linux` `bash` `toctou`
10+
11+
## Description ##
12+
13+
Someone created a program to read text files; we think the program reads files with root privileges but apparently it only accepts to read files that are owned by the user running it.
14+
Additional details will be available after launching your challenge instance.
15+
16+
## Solution ##
17+
18+
Самая большая подсказка - тег задачи `toctou`, что является названием вида уязвимостей. `toctou` -> `Time-of-check to time-of-use`
19+
20+
Файлом `flag.txt` владеет root, программой владеет тоже root, но там стоит бит `s` в правах - значит она запустится от рута - мы должны заставить её открыть `flag.txt`, при этом обойдя проверку нашего настоящего uid с uid владельца файла со стороны программы через функцию getuid.
21+
22+
1. Подключаемся по SSH Замечаем, что проверка владения файлом со стороны программы (где getuid == uid_файла) происходит один раз, а дальше идет чтение файла
23+
24+
2. Создаем файл, которым мы владеем - `ttt.txt` - я написал туда `123`
25+
26+
3. Создадим символьную ссылку `my_link` и будем её бесконечно привязывать к `ttt.txt`, затем к `flag.txt` и так по кругу следующим скриптом:
27+
28+
```bash
29+
while true; do ln -sf /home/ctf-player/ttt.txt /home/ctf-player/my_link; ln -sf /home/ctf-player/flag.txt /home/ctf-player/my_link; done &
30+
```
31+
32+
4. Затем запускаем бесконечный цикл, который выполняет программу на `my_link` следующим скриптом:
33+
34+
```bash
35+
while true; do ./txtreader my_link; done
36+
```
37+
5. После этого в определенный момент произойдет следующее: программа проверит uid юзера на совпадение с uid владельца файла, когда `my_link` -> `ttt.txt`. Затем `my_link` переподвяжится на `flag.txt`, а параллельно с этим программа `txtreader` выполнит чтение из `my_link`, тем самым мы получим флаг, т.к. мы обошли проверку uid, а файл `flag.txt` прочитается, т.к. им владеет root, под именем которого программа выполняется
38+
39+
![Screenshot of the results](1.jpg)

Binary Exploitation/tic-tac/tic-tac.md

+12-7
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,30 @@ Additional details will be available after launching your challenge instance.
1515

1616
## Solution ##
1717

18-
Самая большая подсказка - тег задачи `toctou`, что является названием вида уязвимостей. `toctou` -> `Time-of-check to time-of-use`
18+
The most useful hint - tag of the task `toctou`. It is a name of the vulnerability: `toctou` -> `Time-of-check to time-of-use`.
1919

20-
Файлом `flag.txt` владеет root, программой владеет тоже root, но там стоит бит `s` в правах - значит она запустится от рута - мы должны заставить её открыть `flag.txt`, при этом обойдя проверку нашего настоящего uid с uid владельца файла со стороны программы через функцию getuid.
20+
The owner of the `flag.txt` is **root**, also `root` is the owner of the program.
2121

22-
1. Подключаемся по SSH Замечаем, что проверка владения файлом со стороны программы (где getuid == uid_файла) происходит один раз, а дальше идет чтение файла
22+
But program have bit `s` in its permissions - it means, that it runs from **root**: we need to trick it to open `flag.txt`, avoiding uid check from the program at the same time.
2323

24-
2. Создаем, которым мы владеем - `ttt.txt` - я написал туда `123`
24+
1. Connect via SSH to the instance. We can see, that there is **one** check for uid.
2525

26-
3. Создадим символьную ссылку my_link и будем её бесконечно привязывать к `ttt.txt`, затем к `flag.txt` и так по кругу следующим скриптом:
26+
2. Create a file - I named it `ttt.txt` and wrote `123` inside it.
27+
28+
3. Create a symbol link `my_link`. Let's endlessly make it point to `ttt.txt`, then to `flag.txt` in a loop with following script:
2729

2830
```bash
2931
while true; do ln -sf /home/ctf-player/ttt.txt /home/ctf-player/my_link; ln -sf /home/ctf-player/flag.txt /home/ctf-player/my_link; done &
3032
```
3133

32-
4. Затем запускаем бесконечный цикл, который выполняет программу на `my_link` следующим скриптом:
34+
4. Then let's endless loop, that runs `txtreader` over `my_link`:
3335

3436
```bash
3537
while true; do ./txtreader my_link; done
3638
```
37-
5. После этого в определенный момент произойдет следующее: программа проверит uid юзера на совпадение с uid владельца файла, когда `my_link` -> `ttt.txt`. Затем `my_link` переподвяжится на `flag.txt`, а параллельно с этим программа `txtreader` выполнит чтение из `my_link`, тем самым мы получим флаг, т.к. мы обошли проверку uid, а файл `flag.txt` прочитается, т.к. им владеет root, под именем которого программа выполняется
39+
5. Then next events will occure:
40+
1. Program will check uid, when `my_link` -> `ttt.txt`.
41+
2. `my_link` will change and point to `flag.txt`.
42+
3. `txtreader` will read from `my_link` - we have already bypass uid check, so we will get the `flag.txt`.
3843

3944
![Screenshot of the results](1.jpg)

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ I will describe, how to solve some challenges, that are not presented in [this r
2121
* Reverse Engineering
2222
* **[No way out](Reverse%20Engineering/No%20way%20out/No-way-out.md)**
2323
* Binary Exploitation
24-
* **[babygame02 (RU)](Binary%20Exploitation/babygame02/babygame02.md)**
25-
* **[tic-tac (RU)](Binary%20Exploitation/tic-tac/tic-tac.md)**
24+
* **[babygame02 (EN :gb:)](Binary%20Exploitation/babygame02/babygame02.md)** | **[babygame02 (RU :ru:)](Binary%20Exploitation/babygame02/babygame02-ru.md)**
25+
* **[tic-tac (EN :gb:)](Binary%20Exploitation/tic-tac/tic-tac.md)** | **[tic-tac (RU :ru:)](Binary%20Exploitation/tic-tac/tic-tac-ru.md)**
2626

2727
Full solutions to the challenges are provided in the write ups, however the actual flag values are withheld.

0 commit comments

Comments
 (0)