Files
RDP/CTF.py
admin a38172556b Загрузить файлы в «/»
Выполнение команд, получение инфы о системе. Короче работает все кроме доступа к графической оболочке. Доступ к шеллу через веб
2026-03-29 18:55:18 +00:00

799 lines
28 KiB
Python
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from flask import Flask, render_template, request, jsonify, session
import subprocess
import os
import uuid
import time
from datetime import datetime
import base64
import io
import platform
import socket
from PIL import Image
app = Flask(__name__)
app.secret_key = os.urandom(24)
class RemoteDesktop:
def __init__(self):
self.sessions = {}
self.screen_quality = 80
self.screen_scale = 0.7
self.screenshot_method = None
self._detect_screenshot_method()
def _detect_screenshot_method(self):
"""Автоматическое определение доступного метода захвата экрана"""
methods = []
# Проверяем системные утилиты для Ubuntu
if subprocess.run(['which', 'gnome-screenshot'], capture_output=True).returncode == 0:
methods.append('gnome-screenshot')
if subprocess.run(['which', 'scrot'], capture_output=True).returncode == 0:
methods.append('scrot')
if subprocess.run(['which', 'import'], capture_output=True).returncode == 0:
methods.append('imagemagick')
# Проверяем Python библиотеки
try:
import mss
methods.append('mss')
except ImportError:
pass
print(f"📸 Доступные методы захвата экрана: {methods}")
if methods:
self.screenshot_method = methods[0]
print(f"✅ Выбран метод: {self.screenshot_method}")
else:
print("Не найдены методы захвата экрана")
def create_session(self):
session_id = str(uuid.uuid4())
self.sessions[session_id] = {
'created_at': datetime.now(),
'last_activity': datetime.now()
}
return session_id
def get_system_info(self):
"""Получение информации о системе"""
try:
# Получаем информацию о дистрибутиве Ubuntu
distro_info = ""
try:
with open('/etc/lsb-release', 'r') as f:
for line in f:
if line.startswith('DISTRIB_DESCRIPTION'):
distro_info = line.split('=')[1].strip().strip('"')
except:
distro_info = "Ubuntu (точная версия неизвестна)"
system_info = {
'distribution': distro_info,
'platform': platform.system(),
'platform_release': platform.release(),
'architecture': platform.machine(),
'hostname': socket.gethostname(),
'username': os.getenv('USER'),
'display': os.environ.get('DISPLAY', ':0'),
'screenshot_method': self.screenshot_method,
'python_version': platform.python_version(),
'current_directory': os.getcwd()
}
return system_info
except Exception as e:
return {'error': str(e)}
def capture_screenshot(self):
"""Создание скриншота рабочего стола"""
try:
if not self.screenshot_method:
return None, "Не найдены методы захвата экрана"
if self.screenshot_method == 'gnome-screenshot':
return self._capture_with_gnome_screenshot()
elif self.screenshot_method == 'scrot':
return self._capture_with_scrot()
elif self.screenshot_method == 'imagemagick':
return self._capture_with_imagemagick()
elif self.screenshot_method == 'mss':
return self._capture_with_mss()
else:
return None, f"Неизвестный метод: {self.screenshot_method}"
except Exception as e:
return None, f"Ошибка захвата экрана: {str(e)}"
def _capture_with_gnome_screenshot(self):
"""Захват экрана с помощью gnome-screenshot (рекомендуется для Ubuntu)"""
try:
# Используем временный файл для надежности
temp_file = f"/tmp/screenshot_{int(time.time())}.png"
result = subprocess.run([
'gnome-screenshot', '-f', temp_file, '--include-pointer'
], capture_output=True, text=True, timeout=10)
if result.returncode != 0:
return None, f"GNOME Screenshot failed: {result.stderr}"
# Читаем файл
with open(temp_file, 'rb') as f:
img_data = f.read()
# Удаляем временный файл
os.unlink(temp_file)
img = Image.open(io.BytesIO(img_data))
return self._encode_image(img), None
except subprocess.TimeoutExpired:
return None, "GNOME Screenshot timeout"
except Exception as e:
return None, f"GNOME Screenshot error: {str(e)}"
def _capture_with_scrot(self):
"""Захват экрана с помощью scrot"""
try:
temp_file = f"/tmp/screenshot_{int(time.time())}.png"
result = subprocess.run(['scrot', '-o', temp_file],
capture_output=True, text=True, timeout=10)
if result.returncode != 0:
return None, f"Scrot failed: {result.stderr}"
with open(temp_file, 'rb') as f:
img_data = f.read()
os.unlink(temp_file)
img = Image.open(io.BytesIO(img_data))
return self._encode_image(img), None
except subprocess.TimeoutExpired:
return None, "Scrot timeout"
except Exception as e:
return None, f"Scrot error: {str(e)}"
def _capture_with_imagemagick(self):
"""Захват экрана с помощью ImageMagick"""
try:
result = subprocess.run(['import', '-window', 'root', 'png:-'],
capture_output=True, timeout=10)
if result.returncode != 0:
return None, f"ImageMagick failed: {result.stderr}"
img = Image.open(io.BytesIO(result.stdout))
return self._encode_image(img), None
except subprocess.TimeoutExpired:
return None, "ImageMagick timeout"
except Exception as e:
return None, f"ImageMagick error: {str(e)}"
def _capture_with_mss(self):
"""Захват экрана с помощью mss"""
try:
import mss
with mss.mss() as sct:
monitor = sct.monitors[1]
screenshot = sct.grab(monitor)
img = Image.frombytes("RGB", screenshot.size, screenshot.bgra, "raw", "BGRX")
return self._encode_image(img), None
except Exception as e:
return None, f"MSS error: {str(e)}"
def _encode_image(self, img):
"""Кодирование изображения в base64"""
try:
# Масштабирование
if self.screen_scale != 1.0:
new_size = (int(img.width * self.screen_scale),
int(img.height * self.screen_scale))
img = img.resize(new_size, Image.Resampling.LANCZOS)
buffer = io.BytesIO()
img.save(buffer, format='JPEG', quality=self.screen_quality)
return base64.b64encode(buffer.getvalue()).decode('utf-8')
except Exception as e:
raise Exception(f"Image encoding error: {str(e)}")
def execute_command(self, command):
"""Выполнение команды в оболочке"""
try:
result = subprocess.run(command, shell=True, capture_output=True, text=True, timeout=30)
output = result.stdout
if result.stderr:
output += f"\nSTDERR: {result.stderr}"
return output, None
except subprocess.TimeoutExpired:
return None, "Command timeout"
except Exception as e:
return None, f"Command error: {str(e)}"
def send_key(self, key):
"""Отправка клавиши (эмуляция)"""
try:
# Используем xdotool для эмуляции клавиатуры
result = subprocess.run(['xdotool', 'key', key],
capture_output=True, text=True, timeout=10)
if result.returncode == 0:
return True, None
else:
return False, result.stderr
except Exception as e:
return False, f"Keyboard error: {str(e)}"
def mouse_click(self, x, y, button='left'):
"""Клик мыши в указанных координатах"""
try:
# Используем xdotool для эмуляции мыши
if button == 'left':
click_arg = '1'
elif button == 'right':
click_arg = '3'
else:
click_arg = '1'
result = subprocess.run([
'xdotool', 'mousemove', str(x), str(y), 'click', click_arg
], capture_output=True, text=True, timeout=10)
if result.returncode == 0:
return True, None
else:
return False, result.stderr
except Exception as e:
return False, f"Mouse click error: {str(e)}"
remote_desktop = RemoteDesktop()
@app.route('/')
def index():
if 'session_id' not in session:
session['session_id'] = remote_desktop.create_session()
system_info = remote_desktop.get_system_info()
return render_template('remote_desktop.html', system_info=system_info)
@app.route('/system-info')
def system_info():
info = remote_desktop.get_system_info()
return jsonify(info)
@app.route('/screenshot')
def screenshot():
"""Получение скриншота"""
if 'session_id' not in session:
return jsonify({'error': 'Сессия не найдена'})
image_data, error = remote_desktop.capture_screenshot()
if error:
return jsonify({'error': error})
return jsonify({'image': image_data})
@app.route('/command', methods=['POST'])
def execute_command():
"""Выполнение команды"""
if 'session_id' not in session:
return jsonify({'error': 'Сессия не найдена'})
data = request.get_json()
command = data.get('command', '').strip()
if not command:
return jsonify({'error': 'Пустая команда'})
output, error = remote_desktop.execute_command(command)
if error:
return jsonify({'error': error})
return jsonify({'output': output})
@app.route('/keyboard', methods=['POST'])
def keyboard_action():
"""Эмуляция клавиатуры"""
if 'session_id' not in session:
return jsonify({'error': 'Сессия не найдена'})
data = request.get_json()
key = data.get('key', '')
if not key:
return jsonify({'error': 'Не указана клавиша'})
success, error = remote_desktop.send_key(key)
if not success:
return jsonify({'error': error})
return jsonify({'status': 'success'})
@app.route('/mouse/click', methods=['POST'])
def mouse_click():
"""Клик мыши"""
if 'session_id' not in session:
return jsonify({'error': 'Сессия не найдена'})
data = request.get_json()
x = data.get('x', 0)
y = data.get('y', 0)
button = data.get('button', 'left')
success, error = remote_desktop.mouse_click(x, y, button)
if not success:
return jsonify({'error': error})
return jsonify({'status': 'success'})
@app.route('/settings', methods=['POST'])
def update_settings():
"""Обновление настроек"""
if 'session_id' not in session:
return jsonify({'error': 'Сессия не найдена'})
data = request.get_json()
quality = data.get('quality')
scale = data.get('scale')
if quality is not None:
remote_desktop.screen_quality = max(10, min(100, quality))
if scale is not None:
remote_desktop.screen_scale = max(0.1, min(1.0, scale))
return jsonify({
'quality': remote_desktop.screen_quality,
'scale': remote_desktop.screen_scale
})
@app.route('/test')
def test_page():
"""Тестовая страница"""
image_data, error = remote_desktop.capture_screenshot()
if error:
return f"""
<html>
<body style="background: #1e1e1e; color: white; font-family: Ubuntu, Arial; padding: 20px;">
<h2>❌ Ошибка захвата экрана</h2>
<p>{error}</p>
<h3>Решение для Ubuntu:</h3>
<code style="background: #2d2d30; padding: 15px; display: block;">
sudo apt update<br>
sudo apt install gnome-screenshot scrot imagemagick xdotool<br>
pip install mss pillow
</code>
</body>
</html>
"""
return f"""
<html>
<body style="background: #1e1e1e; color: white; font-family: Ubuntu, Arial; padding: 20px;">
<h2>✅ Тест захвата экрана - УСПЕШНО!</h2>
<p>Метод: {remote_desktop.screenshot_method}</p>
<img src="data:image/jpeg;base64,{image_data}" style="max-width: 800px; border: 2px solid #007acc; border-radius: 5px;">
<p><a href="/" style="color: #007acc; text-decoration: none;">← Вернуться к удаленному рабочему столу</a></p>
</body>
</html>
"""
if __name__ == '__main__':
os.makedirs('templates', exist_ok=True)
with open('templates/remote_desktop.html', 'w', encoding='utf-8') as f:
f.write('''<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Удаленный рабочий стол Ubuntu</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Ubuntu', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: #1e1e1e;
color: #ffffff;
line-height: 1.6;
}
.header {
background: #2d2d30;
padding: 20px;
border-bottom: 1px solid #3e3e42;
text-align: center;
}
.header h1 {
color: #007acc;
margin-bottom: 10px;
}
.controls {
display: flex;
gap: 10px;
background: #2d2d30;
padding: 15px;
border-bottom: 1px solid #3e3e42;
flex-wrap: wrap;
justify-content: center;
}
button {
background: #007acc;
color: white;
border: none;
padding: 12px 20px;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
font-family: 'Ubuntu', sans-serif;
transition: background 0.3s;
}
button:hover {
background: #005a9e;
transform: translateY(-1px);
}
.desktop-container {
position: relative;
width: 100%;
min-height: 500px;
background: #000;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
}
#remote-screen {
max-width: 95%;
max-height: 75vh;
border: 3px solid #333;
border-radius: 8px;
box-shadow: 0 4px 20px rgba(0,0,0,0.5);
cursor: crosshair;
}
.status-bar {
background: #007acc;
padding: 10px 20px;
display: flex;
justify-content: space-between;
font-size: 14px;
font-family: 'Ubuntu Mono', monospace;
}
.error-message {
background: #d32f2f;
color: white;
padding: 15px;
margin: 10px;
border-radius: 6px;
border-left: 4px solid #ff5252;
}
.info-panel {
background: #2d2d30;
padding: 20px;
margin: 15px;
border-radius: 8px;
border: 1px solid #3e3e42;
display: none;
}
.command-section {
background: #2d2d30;
padding: 20px;
margin: 15px;
border-radius: 8px;
}
.command-input {
width: 100%;
padding: 12px;
background: #1e1e1e;
border: 1px solid #3e3e42;
color: white;
border-radius: 6px;
font-family: 'Ubuntu Mono', monospace;
margin-bottom: 10px;
}
.placeholder {
color: #888;
font-size: 20px;
text-align: center;
padding: 60px 20px;
}
.success-badge {
background: #388e3c;
color: white;
padding: 8px 16px;
border-radius: 20px;
font-size: 12px;
display: inline-block;
margin-left: 10px;
}
#command-output {
background: #1e1e1e;
padding: 15px;
border-radius: 6px;
margin-top: 10px;
max-height: 300px;
overflow-y: auto;
font-family: 'Ubuntu Mono', monospace;
font-size: 13px;
white-space: pre-wrap;
display: none;
}
</style>
</head>
<body>
<div class="header">
<h1>🖥️ Удаленный рабочий стол Ubuntu</h1>
<p>Управление рабочим столом через веб-интерфейс</p>
</div>
<div class="controls">
<button onclick="refreshScreen()">🔄 Обновить экран</button>
<button onclick="toggleAutoRefresh()">⏱️ Авто-обновление</button>
<button onclick="showSystemInfo()"> Информация о системе</button>
<button onclick="testConnection()">🧪 Тест подключения</button>
<button onclick="sendEnter()">↵ Отправить Enter</button>
<button onclick="sendCtrlC()">⎈ Ctrl+C</button>
</div>
<div id="error-container"></div>
<div id="info-panel" class="info-panel"></div>
<div class="desktop-container" id="desktop-container">
<div id="screen-placeholder" class="placeholder">
🖼️ Нажмите "Обновить экран" для захвата рабочего стола
</div>
<img id="remote-screen" style="display: none;" alt="Удаленный рабочий стол"
onclick="handleScreenClick(event)">
</div>
<div class="command-section">
<h3>💻 Командная строка</h3>
<input type="text" id="command-input" class="command-input"
placeholder="Введите команду (например: ls -la, pwd, gnome-terminal...)"
onkeypress="handleCommandInput(event)">
<button onclick="executeCommand()" style="width: 200px;">⚡ Выполнить команду</button>
<div id="command-output"></div>
</div>
<div class="status-bar">
<span id="status-info">Статус: Готов</span>
<span id="performance-info">Метод: {{ system_info.screenshot_method }} | Ubuntu</span>
</div>
<script>
let autoRefreshInterval = null;
let isAutoRefresh = false;
const remoteScreen = document.getElementById('remote-screen');
const screenPlaceholder = document.getElementById('screen-placeholder');
const statusInfo = document.getElementById('status-info');
const performanceInfo = document.getElementById('performance-info');
const infoPanel = document.getElementById('info-panel');
const errorContainer = document.getElementById('error-container');
const commandOutput = document.getElementById('command-output');
const commandInput = document.getElementById('command-input');
// Инициализация
document.addEventListener('DOMContentLoaded', function() {
updateStatus('Система готова к работе');
commandInput.focus();
});
function refreshScreen() {
updateStatus('Захват экрана...');
fetch('/screenshot?' + new Date().getTime())
.then(response => response.json())
.then(data => {
if (data.error) {
showError('Ошибка: ' + data.error);
screenPlaceholder.style.display = 'block';
remoteScreen.style.display = 'none';
screenPlaceholder.innerHTML = '' + data.error;
} else if (data.image) {
hideError();
remoteScreen.src = 'data:image/jpeg;base64,' + data.image;
screenPlaceholder.style.display = 'none';
remoteScreen.style.display = 'block';
updateStatus('Экран обновлен ✓');
}
})
.catch(error => {
showError('Ошибка подключения: ' + error);
});
}
function toggleAutoRefresh() {
isAutoRefresh = !isAutoRefresh;
if (isAutoRefresh) {
autoRefreshInterval = setInterval(refreshScreen, 3000);
updateStatus('Авто-обновление включено (3 сек)');
} else {
clearInterval(autoRefreshInterval);
updateStatus('Авто-обновление выключено');
}
}
function executeCommand() {
const command = commandInput.value.trim();
if (!command) return;
updateStatus('Выполнение команды...');
commandOutput.style.display = 'block';
commandOutput.textContent = 'Выполнение...';
fetch('/command', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ command: command })
})
.then(response => response.json())
.then(data => {
if (data.error) {
commandOutput.textContent = 'Ошибка: ' + data.error;
commandOutput.style.color = '#ff5252';
} else {
commandOutput.textContent = data.output;
commandOutput.style.color = '#4caf50';
}
updateStatus('Команда выполнена ✓');
commandInput.value = '';
commandInput.focus();
})
.catch(error => {
commandOutput.textContent = 'Ошибка сети: ' + error;
commandOutput.style.color = '#ff5252';
updateStatus('Ошибка выполнения команды');
});
}
function handleCommandInput(event) {
if (event.key === 'Enter') {
executeCommand();
}
}
function handleScreenClick(event) {
const rect = remoteScreen.getBoundingClientRect();
const x = Math.round(event.clientX - rect.left);
const y = Math.round(event.clientY - rect.top);
// Масштабируем координаты для реального экрана
const scaleX = remoteScreen.naturalWidth / rect.width;
const scaleY = remoteScreen.naturalHeight / rect.height;
const realX = Math.round(x * scaleX);
const realY = Math.round(y * scaleY);
fetch('/mouse/click', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
x: realX,
y: realY,
button: event.button === 2 ? 'right' : 'left'
})
}).then(() => {
updateStatus('Клик мыши отправлен ✓');
setTimeout(refreshScreen, 500); // Обновляем экран после клика
}).catch(error => {
showError('Ошибка мыши: ' + error);
});
event.preventDefault();
}
function sendEnter() {
fetch('/keyboard', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ key: 'Return' })
}).then(() => {
updateStatus('Enter отправлен ✓');
setTimeout(refreshScreen, 500);
}).catch(error => {
showError('Ошибка клавиатуры: ' + error);
});
}
function sendCtrlC() {
fetch('/keyboard', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ key: 'ctrl+c' })
}).then(() => {
updateStatus('Ctrl+C отправлен ✓');
setTimeout(refreshScreen, 500);
}).catch(error => {
showError('Ошибка клавиатуры: ' + error);
});
}
function showSystemInfo() {
fetch('/system-info')
.then(response => response.json())
.then(data => {
let infoHtml = '<h3>🖥️ Информация о системе Ubuntu:</h3>';
for (const [key, value] of Object.entries(data)) {
infoHtml += `<p><strong>${key}:</strong> ${value}</p>`;
}
infoPanel.innerHTML = infoHtml;
infoPanel.style.display = 'block';
})
.catch(error => {
showError('Ошибка загрузки информации: ' + error);
});
}
function testConnection() {
window.open('/test', '_blank');
}
function updateStatus(message) {
statusInfo.textContent = 'Статус: ' + message;
}
function showError(message) {
errorContainer.innerHTML = `<div class="error-message">${message}</div>`;
updateStatus('Ошибка');
}
function hideError() {
errorContainer.innerHTML = '';
}
// Запрещаем контекстное меню на изображении
remoteScreen.addEventListener('contextmenu', function(e) {
e.preventDefault();
});
</script>
</body>
</html>''')
print("=" * 60)
print("🖥️ УДАЛЕННЫЙ РАБОЧИЙ СТОЛ ДЛЯ UBUNTU")
print("=" * 60)
system_info = remote_desktop.get_system_info()
print(f"💻 Система: {system_info.get('distribution', 'Ubuntu')}")
print(f"📸 Метод захвата: {remote_desktop.screenshot_method}")
if remote_desktop.screenshot_method:
print("✅ Захват экрана настроен корректно")
else:
print("❌ Установите зависимости:")
print(" sudo apt install gnome-screenshot scrot imagemagick xdotool")
print("🌐 Сервер запущен: http://0.0.0.0:5000")
print("🧪 Тест: http://0.0.0.0:5000/test")
print("=" * 60)
app.run(host='0.0.0.0', port=5000, debug=False, threaded=True)