Сегодня я увидел проект с открытым исходным кодом под названием Command2API, который очень интересен, и я хочу поделиться им с вами.
источник
Что касается того, почему родился этот проект, в оригинальном репо есть этот абзац:
Взяв в качестве примера недавний RCE Log4j, в тесте безопасности интрасети платформа DNSLog недоступна из-за ограничений сетевой среды.В настоящее время при проверке уязвимости Log4j считается, что необходимо напрямую проверить, Подключен сервис LDAP, но включен готовый инструмент JNDI-инъекций.Нет API для сервиса, чтобы напрямую подтягивать результаты соответствующего сервиса, что требует ручного просмотра, что занимает очень много времени.Кроме того, BurpSuite для сканирования написан пассивный плагин В целях экономии времени этот скрипт написан просто для получения Результат выполнения JNDI-инструмента возвращается в виде API, что удобно плагинам для подтягивания результатов на наличие уязвимости проверка.
В любом случае, общая идея заключается в том, что если результаты выполнения некоторых команд могут быть выставлены через HTTP API, мы можем более легко получить результаты выполнения команд, что очень удобно в некоторых сценариях.
Итак, вот автор написал этот проект.
принцип
Этот принцип на самом деле очень прост: использовать поток Python для запуска веб-сервиса, поток для выполнения команды и делиться результатом выполнения команды с веб-сервисом через глобальные переменные.
бегать
Давайте запустим его здесь и посмотрим на эффект.
Сначала вам нужно скачать следующие элементы:
git clone https://github.com/gh0stkey/Command2API.git
Затем просто укажите команду, которую хотите запустить, и порт, на котором работает API, например:
python Command2Api.py "执行的命令" Web运行的端口
Обратите внимание, что python здесь использует Python2, а не Python3, потому что исходный проект ссылается на пакет BaseHTTPServer, который недоступен в Python3.
Здесь мы выполняем команду ping, чтобы попробовать:
python Command2Api.py "ping www.baidu.com" 8888
Результаты приведены ниже:
Как видите, здесь сначала выводится рабочий адрес:
URL: http://HOST:8888/c1IvlLF9
Теперь мы открываемhttp://localhost:8888/c1IvlLF9Проверьте это.
Вы можете видеть, что результаты консоли отображаются на веб-странице.
Но эта страница не может обновляться автоматически, вам нужно нажать «Обновить», чтобы получить последние результаты.
Введение окончено.
Так что в некоторых случаях этот проект весьма полезен.
Например:
- В тесте безопасности интрасети его можно использовать для получения результата выполнения инструмента JNDI и возврата его в виде API, что упрощает наблюдение за результатом выполнения.
- Мы хотим отслеживать или получать выходные данные программы командной строки в режиме реального времени, такой как сканер Scrapy, такой как веб-сервер и т. д., которые могут быть раскрыты.
- Если мы хотим быстро поделиться результатом выполнения программы, мы можем использовать эту команду для создания веб-сайта, которым можно поделиться с Ngrok.
и Т. Д.
Анализ исходного кода
Давайте еще раз взглянем на исходный код, он на самом деле очень простой, всего таких кодов:
import subprocess
import BaseHTTPServer
import SimpleHTTPServer
import cgi
import threading
import sys
import string
import random
l = []
uri = '/' + ''.join(random.sample(string.ascii_letters+string.digits,8))
class thread(threading.Thread):
def __init__(self, threadname, command):
threading.Thread.__init__(self, name='Thread_' + threadname)
self.threadname = int(threadname)
self.command = command
def run(self):
global l
ret = subprocess.Popen(
self.command,
shell=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
for i in iter(ret.stdout.readline, b""):
res = i.decode().strip()
print(res)
l.append(res)
class ServerHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
def do_GET(self):
global l
if self.path == uri:
self.send_response(200)
self.send_header('Content-Type', 'text/plain')
self.end_headers()
self.wfile.write(l)
if __name__ == '__main__':
# New Thread: Get Command Result
t1 = thread('1', sys.argv[1])
t1.start()
# Webserver
port = int(sys.argv[2])
print("URL: http://HOST:{0}{1}".format(port, uri))
Handler = ServerHandler
httpd = BaseHTTPServer.HTTPServer(('0.0.0.0', port), Handler)
httpd.serve_forever()
Видно, что эту команду выполняет Popen, затем результат захватывается и присваивается как переменная через PIPE, а затем другой поток запускает сервер и записывает результат в Response.
Это такой простой код для реализации такой удобной функции.
оптимизация
Тем не менее, я думаю, что в этом проекте еще есть много возможностей для оптимизации.
- Теперь поддерживается Python2 вместо Python3.
- Результаты веб-страницы не обновляются автоматически.
- Веб-результат представляет собой список, а формат результата консоли неоднороден.
- Этот инструментарий не может быть защищен через pip.
- ХОСТ выходного результата можно оптимизировать, и получить к нему прямой доступ путем копирования непросто.
- Результаты могут быть опубликованы с помощью Ngrok.
- Было бы еще лучше, если бы команды можно было интерактивно контролировать через веб-страницу.
Я посмотрю, если у меня будет время, я могу попробовать переписать этот проект и реализовать некоторые из вышеперечисленных функций оптимизации, и я вышлю его, когда закончу его писать.
Спасибо за чтение~
Для более интересного контента, пожалуйста, обратите внимание на мои публичные аккаунты «Coder of Attack» и «Cui Qingcai丨Jing Mi».