Как находить ошибки в коде

Эта статья — кон­спект вебина­ра по веб‑уяз­вимос­тям, который я про­водил для читате­лей «Хакера». В кон­це будет при­веде­на его запись, где ты смо­жешь уви­деть то, что не попало в тек­сто­вую вер­сию. Если тебе инте­рес­ны такие темы и ты бы хотел разоб­рать­ся в них глуб­же, за­писы­вай­ся на мой курс по безопас­ности веб‑при­ложе­ний!

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

Впро­чем, боль­шинс­тво уяз­вимос­тей не при­вяза­ны к кон­крет­ному язы­ку или сте­ку тех­нологий, так что, узнав их на при­мере PHP, ты лег­ко смо­жешь экс­плу­ати­ровать подоб­ные баги и в ASP. NET, и в каком‑нибудь Node. JS.

А еще пре­дуп­режу, что задач­ки, которые мы сегод­ня раз­берем, не сов­сем началь­ного уров­ня и сов­сем уж «вален­кам» тут делать нечего — сна­чала сто­ит почитать мат­часть и хоть нем­ного пред­став­лять, с чем хочешь иметь дело. Если же ты можешь отли­чить HTTP от XML и у тебя не воз­ника­ет воп­росов вида «а что за дол­лары в коде?», то доб­ро пожало­вать!

warning

Ни автор кур­са, ни редак­ция «Хакера» не несут ответс­твен­ности за твои дей­ствия. При­мене­ние матери­алов этой статьи про­тив любой сис­темы без раз­решения ее вла­дель­ца прес­леду­ется по закону.

Се­год­ня мы раз­берем нес­коль­ко задач, которые я решал сам в рам­ках тре­ниров­ки. Воз­можно, они покажут­ся тебе слож­ными, но не пугай­ся — всег­да есть воз­можность отто­чить свои навыки на сай­тах пра­витель­ств спе­циали­зиро­ван­ных сай­тах для хакеров. Я сей­час говорю о HackTheBox и Root-me, которы­ми поль­зуюсь сам и вся­чес­ки советую дру­гим. Две из сегод­няшних задач взя­ты имен­но отту­да.

Задача 1

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

По сути, тут все­го три стро­ки кода. Казалось бы, где тут может зак­расть­ся уяз­вимость?

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

В кон­це очи­щен­ное имя фай­ла под­став­ляет­ся в путь и заг­ружа­ется файл с этим име­нем. Ничего пло­хого.

Итак, что может пой­ти не по пла­ну?

Как ты уже, конеч­но, догадал­ся — проб­лема в фун­кции очис­тки вво­да (которая preg_replace ). Давай обра­тим­ся к пер­вой попав­шей­ся шпар­галке по регуляр­ным выраже­ниям.

ШпаргалкаШпар­галка

Тут пря­мо написан ответ, как обой­ти защиту (под­сказ­ка: ищи спра­ва).

Ви­дишь точ­ку? А шапоч­ку ( ^ )? Та стро­ка чита­ется как «если в начале стро­ки находит­ся любое количес­тво любых сим­волов, кро­ме перено­са стро­ки, и это закан­чива­ется сле­шем, уда­лить соот­ветс­тву­ющую часть стро­ки».

Клю­чевое тут «кро­ме перено­са стро­ки». Если в начале стро­ки будет перенос стро­ки — регуляр­ка не отра­бота­ет и вве­ден­ная стро­ка попадет в include( ) без филь­тра­ции.

РезультатРе­зуль­тат

Задача 2

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

В задании нам дает­ся прос­той фай­лооб­менник и про­сят получить дос­туп к панели адми­на.

Интерфейс файлообменникаИн­терфейс фай­лооб­менни­ка

Ин­терфейс край­не прост: есть кноп­ка заг­рузки фай­ла на сер­вер и прос­мотр заг­ружен­ных фай­лов по пря­мым ссыл­кам. Забегая впе­ред, ска­жу, что гру­зить скрип­ты на PHP, bash и про­чие — бес­полез­но, про­вер­ки реали­зова­ны вер­но и ошиб­ка в дру­гом мес­те.

Об­рати вни­мание на ниж­нюю часть стра­ницы, а точ­нее — на фра­зу «frequent backups: this opensource script is launched every 5 minutes for saving your files». И при­веде­на ссыл­ка на скрипт, вызыва­емый каж­дые пять минут в сис­теме.

Да­вай гля­нем на него прис­таль­нее:

Ка­залось бы — что тут такого? На парамет­ры ты вли­ять не можешь, а ман­тру при­зыва tar вооб­ще зна­ешь как свои пять паль­цев. А проб­лема в самой ман­тре: тут она написа­на не пол­ностью. Точ­нее, не в том виде, как ее уви­дит сам tar.

Что дела­ет звез­дочка? Вмес­то нее bash под­ста­вит име­на всех фай­лов в текущей пап­ке. Вро­де ничего кри­миналь­ного.

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

Интересности в TarИн­терес­ности в Tar

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

Прос­то заголо­вок и коман­да копиро­вания админ­ской панели в текущую пап­ку. Естес­твен­но, тут мог быть реверс‑шелл или еще что‑то, но для решения кон­крет­но этой задачи такая «тяжелая артилле­рия» не нуж­на.

Те­перь дожида­емся выпол­нения нашего шел­ла — и уви­дим в окне фай­лооб­менни­ка файл админ‑панели в виде прос­того тек­ста. Оста­лось толь­ко открыть его и най­ти там пароль!

Пароль в чистом видеПа­роль в чис­том виде

Задача 3

Тут у нас пла­гин для WordPress, который поз­воля­ет запись аудио и видео.

Я не буду про­сить тебя най­ти уяз­вимость, а сра­зу покажу ее.

Уязвимое местоУяз­вимое мес­то

Как вид­но из строк 247–251 на скрин­шоте, не пре­дус­мотре­но никаких про­верок на тип или содер­жимое фай­ла — это прос­то клас­сичес­кая заг­рузка!

Есть, прав­да, огра­ниче­ние: файл гру­зит­ся в стан­дар­тную дирек­торию WordPress ( / wordpress/ wp-content/ uploads/< YEAR>/ < MONTH>). Это зна­чит, что лис­тинг содер­жимого нам по умол­чанию недос­тупен. А в стро­ке 247 генери­рует­ся слу­чай­ный иден­тифика­тор, который под­став­ляет­ся в начало име­ни фай­ла, то есть обра­тить­ся к / wordpress/ wp-content/ uploads/ 2021/ 01/ shell. php уже не вый­дет. Непоря­док!

По­луча­ет уни­каль­ный иден­тифика­тор с пре­фик­сом, осно­ван­ный на текущем вре­мени в мик­росекун­дах.

<…>

Вни­мание. Эта фун­кция не гаран­тиру­ет получе­ния уни­каль­ного зна­чения. Боль­шинс­тво опе­раци­онных сис­тем син­хро­низи­рует вре­мя с NTP либо его ана­лога­ми, так что сис­темное вре­мя пос­тоян­но меня­ется. Сле­дова­тель­но, воз­можна ситу­ация, ког­да эта фун­кция вер­нет неуни­каль­ный иден­тифика­тор для про­цес­са/потока. <…>

Так как PHP — про­ект откры­тый, мы можем под­смот­реть исходни­ки фун­кций стан­дар­тной биб­лиоте­ки. Откры­ваем исходник uniqid( ) на GitHub, перехо­дим к стро­ке 76 и наб­люда­ем сле­дующее:

Что тут про­исхо­дит? А то, что воз­вра­щаемое зна­чение зависит исклю­читель­но от текуще­го вре­мени, которое в рам­ках одной пла­неты впол­не пред­ска­зуемо.

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

По­лучен­ное зна­чение лег­ко мож­но кон­верти­ровать обратно в дату и вре­мя его генера­ции:

Ко­неч­но, бру­тить все 13 сим­волов — вши заедят, но у нас есть спо­соб получ­ше: мы можем проб­рутить вари­анты на осно­ве вре­мени заг­рузки плюс‑минус пол­секун­ды, что­бы нивели­ровать раз­бежки часов на кли­енте и сер­вере. А мож­но прос­то поверить, что часы у обо­их хос­тов точ­ные, а зна­чит, мож­но про­верить не мил­лион вари­антов (1 секун­ду), а толь­ко вари­анты, воз­можные меж­ду вре­менем отправ­ки зап­роса и вре­менем получе­ния отве­та. На шус­тром канале это будет поряд­ка 300–700 мс, что не так и мно­го.

Ко­неч­но, не все реаль­ные кей­сы тре­буют глу­боких поз­наний в PHP или дру­гом сер­верном язы­ке. Мно­гие ошиб­ки мож­но най­ти, даже не откры­вая код — с помощью авто­мати­чес­ких ска­неров. Под­робнее о них — в на­шей статье об авто­мати­чес­ком взло­ме. Они здо­рово помога­ют, так что не грех иметь пароч­ку под рукой для экс­пресс‑ана­лиза!

Я наб­росал прос­той скрипт на Python для демонс­тра­ции такой воз­можнос­ти. Его код пред­став­лен ниже:

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

Так­же нуж­но пом­нить, что раз­бежки все же могут быть, и чис­то на вся­кий слу­чай сто­ит про­верить, нас­коль­ко локаль­ное вре­мя соот­ветс­тву­ет вре­мени на сер­вере. Час­тень­ко оно воз­вра­щает­ся сер­вером в заголов­ке Last-Modified и поз­воля­ет понять, какую величи­ну кор­рекции внес­ти в свои рас­четы.

Как бы еще опти­мизи­ровать перебор?

Ну, во‑пер­вых, питон сам по себе очень мед­ленный и, конеч­но, не смог бы выпол­нить соеди­нение, переда­чу заголов­ков, отправ­ку фай­ла и про­чие мел­кие нак­ладные рас­ходы в тот же момент. А интер­пре­татор PHP на сто­роне сер­вера едва ли момен­таль­но про­верит пра­ва, запус­тит скрипт, отра­бота­ет слу­жеб­ные фун­кции и дой­дет до собс­твен­но уяз­вимого мес­та. Тут мож­но накинуть эдак тысяч сто мик­росекунд без малей­ших потерь.

Во‑вто­рых, выпол­нение uniqid( ) оче­вид­но про­исхо­дит не в самом кон­це фун­кции. Еще нуж­но вре­мя на обра­бот­ку заг­ружен­ного фай­ла, запись отве­та (заголов­ков), отправ­ку это­го все­го по сети и на обра­бот­ку отве­та интер­пре­тато­ром Python. Тут тоже мож­но поряд­ка 100 000 мик­росекунд вычесть.

Вот так на ров­ном мес­те мы сок­ратили перебор на 200 000 зап­росов. Мно­го это или мало? В моем слу­чае это сок­ратило количес­тво зап­росов еще при­мер­но на треть.

Ос­талось поряд­ка 500 000 вари­антов, которые мож­но переб­рать в пре­делах часа или даже мень­ше — у меня это заняло минут 15.

Те­перь давай напишем еще один скрипт, который и будет искать наш шелл с исполь­зовани­ем это­го алго­рит­ма:

Вот и всё: запус­каешь, через некото­рое вре­мя получа­ешь путь, и хост зах­вачен!

На­вер­няка у тебя воз­ник воп­рос, нель­зя ли как‑то еще усо­вер­шенс­тво­вать этот перебор, потому что 500 тысяч вари­антов — это все рав­но как‑то мно­гова­то? Мож­но, но такого зна­чимо­го уско­рения, как рань­ше, уже не будет. Суть в том, что мож­но идти не от начала про­межут­ка вре­мени к кон­цу, а от середи­ны к кра­ям. По опы­ту, это работа­ет нес­коль­ко быс­трее.

Другой способ

Задача 4

Пос­ледняя на сегод­ня задач­ка — тоже с root-me и тоже из катего­рии реалис­тичных, но замет­но пос­ложнее. Сер­вис Web TV — новей­шая фран­цуз­ская раз­работ­ка в сфе­ре интернет‑телеви­дения. Но нас инте­ресу­ет не новая дешевая тра­гедия, а админка.

Главная страница Web TV. Простите за мой французскийГлав­ная стра­ница Web TV. Прос­тите за мой фран­цуз­ский

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

Поп­робу­ем залоги­нить­ся и перех­ватить зап­рос на авто­риза­цию с помощью Burp.

Буква З в слове «реальность» означает «защищенность»Бук­ва З в сло­ве «реаль­ность» озна­чает «защищен­ность»

Зап­рос отправ­ляем в Repeater (пов­торитель). Пусть пока там полежит.

Взгля­нем еще разок на фор­му логина. Какие мыс­ли тебя посеща­ют, ког­да ты видишь фор­му для авто­риза­ции? Конеч­но, SQL-инъ­екция! А давай ткнем туда кавыч­ку. Написа­ли. Отправ­ляем. Хм, ничего не поменя­лось. А как вооб­ще узнать, что что‑то поменя­лось? Смот­ри на заголо­вок Content-Length в отве­те: в нашем слу­чае там при­ходит ров­но 2079 байт, если инъ­екции не было, и, оче­вид­но, при­дет силь­но дру­гой резуль­тат в про­тив­ном слу­чае. Я поп­робовал еще нем­ного, и инъ­екция так прос­то не выяви­лась, так что давай поищем в дру­гом мес­те, а потом вер­немся к это­му зап­росу.

Я поп­робовал перей­ти на стра­ницу / page_index и получил ошиб­ку как на скри­не ниже.

Ошибка интерпретатораОшиб­ка интер­пре­тато­ра

/?action=../../index. php/?action=../../index. php

Вид­но не все, но если открыть ответ в Burp или даже прос­то прос­мотреть код стра­ницы бра­узе­ром — откры­вает­ся пол­ный исходник. Вот тебе и directory traversal налицо.

Результат обхода каталогаРе­зуль­тат обхо­да катало­га

Пом­нишь, мы не мог­ли най­ти путь к админке? А на скрин­шоте он есть: имен­но на него будет редирект, ког­да скрипт про­верит логин и пароль.

Да­вай, не отхо­дя от кас­сы, сра­зу и его про­чита­ем — вдруг там что‑нибудь инте­рес­ное есть.

Где посмотреть и как читать логи с ошибками сервера

Где посмотреть и как читать логи с ошибками сервера

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

Как читать логи с ошибками сервера

Что такое логи

Это текстовые файлы, которые хранятся на жестком диске сервера. Создаются и заполняются в автоматическом режиме, в хронологическом порядке. В них записываются:

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

Классификация логов

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

Записи в системные журналы выполняет установленный софт.

Классификация логов

Зачем нужны логи

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

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

Источники:

https://xakep. ru/2021/01/12/websec-errors/

https://timeweb. com/ru/community/articles/gde-posmotret-i-kak-chitat-logi-s-oshibkami-servera

Понравилась статья? Поделиться с друзьями:
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: