Files
RDP/WEBSHELL/gotty(unsafe).py
admin 2726c4aa4d Загрузить файлы в «WEBSHELL»
gotty.py - WEB шелл с разрешенным списком команд

gotty(unsafe).py - WEB шелл без фильтрации команд (допускает любые команды оболочки ЛИНУКС BASH)
2026-03-29 19:00:28 +00:00

512 lines
17 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
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 threading
import uuid
from datetime import datetime
import shlex
app = Flask(__name__)
app.secret_key = os.urandom(24) # Случайный секретный ключ
class CommandSession:
def __init__(self):
self.sessions = {}
def create_session(self):
session_id = str(uuid.uuid4())
self.sessions[session_id] = {
'created_at': datetime.now(),
'working_dir': os.getcwd(),
'history': []
}
return session_id
def execute_command(self, session_id, command):
if session_id not in self.sessions:
return "Сессия не найдена"
session_data = self.sessions[session_id]
# Добавляем команду в историю
session_data['history'].append({
'command': command,
'timestamp': datetime.now()
})
try:
# Выполняем команду в текущей директории сессии
process = subprocess.Popen(
command,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
cwd=session_data['working_dir'],
executable='/bin/bash' if os.name != 'nt' else None
)
# Ждем завершения с таймаутом
try:
stdout, stderr = process.communicate(timeout=60)
return_code = process.returncode
except subprocess.TimeoutExpired:
process.kill()
stdout, stderr = process.communicate()
return f"Ошибка: команда выполнялась слишком долго и была остановлена\n\nSTDOUT:\n{stdout}\nSTDERR:\n{stderr}"
# Формируем вывод
output = ""
if stdout:
output += f"STDOUT:\n{stdout}\n"
if stderr:
output += f"STDERR:\n{stderr}\n"
if return_code != 0:
output += f"Код возврата: {return_code}"
return output.strip()
except Exception as e:
return f"Ошибка выполнения: {str(e)}"
def change_directory(self, session_id, new_dir):
if session_id not in self.sessions:
return False, "Сессия не найдена"
try:
if new_dir == "~":
new_dir = os.path.expanduser("~")
elif new_dir == "-":
# Возврат к предыдущей директории (можно реализовать при необходимости)
new_dir = os.getcwd()
new_dir = os.path.abspath(new_dir)
if os.path.exists(new_dir) and os.path.isdir(new_dir):
os.chdir(new_dir)
self.sessions[session_id]['working_dir'] = new_dir
return True, f"Директория изменена на: {new_dir}"
else:
return False, f"Директория не существует: {new_dir}"
except Exception as e:
return False, f"Ошибка смены директории: {str(e)}"
command_manager = CommandSession()
@app.route('/')
def index():
if 'session_id' not in session:
session['session_id'] = command_manager.create_session()
return render_template('index.html')
@app.route('/execute', 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': 'Пустая команда'})
# Обработка команды cd
if command.startswith('cd '):
new_dir = command[3:].strip()
success, message = command_manager.change_directory(session['session_id'], new_dir)
return jsonify({
'output': message,
'command': command,
'timestamp': datetime.now().strftime('%H:%M:%S'),
'current_dir': command_manager.sessions[session['session_id']]['working_dir']
})
# Выполняем команду
output = command_manager.execute_command(session['session_id'], command)
return jsonify({
'output': output,
'command': command,
'timestamp': datetime.now().strftime('%H:%M:%S'),
'current_dir': command_manager.sessions[session['session_id']]['working_dir']
})
@app.route('/sessions', methods=['GET'])
def list_sessions():
return jsonify({
'active_sessions': len(command_manager.sessions),
'current_session': session.get('session_id'),
'current_dir': command_manager.sessions.get(session.get('session_id', ''), {}).get('working_dir', '')
})
@app.route('/history', methods=['GET'])
def command_history():
if 'session_id' not in session:
return jsonify({'error': 'Сессия не найдена'})
session_data = command_manager.sessions.get(session['session_id'])
if not session_data:
return jsonify({'error': 'Данные сессии не найдены'})
history = session_data.get('history', [])[-10:] # Последние 10 команд
formatted_history = [
{
'command': item['command'],
'timestamp': item['timestamp'].strftime('%H:%M:%S')
}
for item in history
]
return jsonify({'history': formatted_history})
@app.route('/clear-session', methods=['POST'])
def clear_session():
session_id = session.get('session_id')
if session_id in command_manager.sessions:
del command_manager.sessions[session_id]
session.pop('session_id', None)
return jsonify({'message': 'Сессия очищена'})
@app.route('/system-info', methods=['GET'])
def system_info():
"""Базовая информация о системе"""
try:
# Информация о системе
system_info = {
'platform': os.uname().sysname if hasattr(os, 'uname') else os.name,
'current_user': os.getenv('USER', 'Unknown'),
'cpu_count': os.cpu_count(),
'current_directory': os.getcwd()
}
return jsonify(system_info)
except Exception as e:
return jsonify({'error': f'Не удалось получить информацию о системе: {str(e)}'})
if __name__ == '__main__':
# Создаем папку для шаблонов если её нет
os.makedirs('templates', exist_ok=True)
# Создаем HTML шаблон
with open('templates/index.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>Web Shell - Полный доступ</title>
<style>
:root {
--bg-color: #1e1e1e;
--text-color: #00ff00;
--error-color: #ff4444;
--warning-color: #ffaa00;
--info-color: #4488ff;
}
body {
font-family: 'Courier New', monospace;
background-color: var(--bg-color);
color: var(--text-color);
margin: 0;
padding: 20px;
line-height: 1.4;
}
.header {
border-bottom: 1px solid #333;
padding-bottom: 10px;
margin-bottom: 20px;
}
.warning {
background-color: var(--warning-color);
color: #000;
padding: 10px;
border-radius: 5px;
margin: 10px 0;
font-weight: bold;
}
.terminal {
background-color: #000;
border: 1px solid #333;
border-radius: 5px;
padding: 20px;
height: 60vh;
overflow-y: auto;
margin-bottom: 20px;
}
.output {
margin-bottom: 10px;
white-space: pre-wrap;
word-break: break-all;
}
.command-line {
display: flex;
align-items: center;
background-color: #000;
padding: 10px;
border-radius: 5px;
border: 1px solid #333;
}
.prompt {
margin-right: 10px;
color: var(--info-color);
font-weight: bold;
}
#command-input {
background: transparent;
border: none;
color: var(--text-color);
font-family: 'Courier New', monospace;
font-size: 16px;
outline: none;
flex-grow: 1;
}
.timestamp {
color: #888;
font-size: 12px;
}
.error {
color: var(--error-color);
}
.info {
color: var(--info-color);
}
.user-command {
color: #ffff00;
font-weight: bold;
}
.controls {
display: flex;
gap: 10px;
margin: 10px 0;
flex-wrap: wrap;
}
button {
background-color: #333;
color: var(--text-color);
border: 1px solid #555;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
font-family: 'Courier New', monospace;
}
button:hover {
background-color: #444;
}
.status-bar {
display: flex;
justify-content: space-between;
margin-top: 10px;
font-size: 12px;
color: #888;
}
</style>
</head>
<body>
<div class="header">
<h1>Web Shell - Полный доступ к системе</h1>
<div class="warning">
⚠️ ВНИМАНИЕ: Полный доступ к оболочке системы! Будьте осторожны с командами.
</div>
</div>
<div class="controls">
<button onclick="clearTerminal()">Очистить терминал</button>
<button onclick="clearSession()">Новая сессия</button>
<button onclick="showHistory()">История команд</button>
<button onclick="showSystemInfo()">Информация о системе</button>
</div>
<div class="terminal" id="terminal">
<div class="output info">
Добро пожаловать в Web Shell с полным доступом!<br>
Доступны все команды системы. Таймаут выполнения: 60 секунд.<br>
Текущая директория: <span id="current-dir"></span>
</div>
</div>
<div class="command-line">
<span class="prompt" id="prompt">$</span>
<input type="text" id="command-input" placeholder="Введите любую команду системы...">
</div>
<div class="status-bar">
<span id="session-info">Загрузка...</span>
<span id="command-counter">Команд выполнено: 0</span>
</div>
<script>
const terminal = document.getElementById('terminal');
const commandInput = document.getElementById('command-input');
const sessionInfo = document.getElementById('session-info');
const commandCounter = document.getElementById('command-counter');
const currentDirElement = document.getElementById('current-dir');
const promptElement = document.getElementById('prompt');
let commandCount = 0;
// Фокус на поле ввода
commandInput.focus();
// Загружаем начальную информацию
loadSessionInfo();
loadSystemInfo();
// Обработка отправки команды
commandInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
const command = commandInput.value.trim();
if (command) {
executeCommand(command);
commandInput.value = '';
}
}
});
function executeCommand(command) {
// Показываем команду в терминале
addOutput('$ ' + command, 'user-command');
// Отправляем на сервер
fetch('/execute', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({command: command})
})
.then(response => response.json())
.then(data => {
if (data.error) {
addOutput(data.error, 'error');
} else {
addOutput(data.output, 'command-output');
// Обновляем текущую директорию
if (data.current_dir) {
currentDirElement.textContent = data.current_dir;
promptElement.textContent = `[${data.current_dir.split('/').pop() || data.current_dir}] $`;
}
}
commandCount++;
commandCounter.textContent = `Команд выполнено: ${commandCount}`;
})
.catch(error => {
addOutput('Ошибка сети: ' + error, 'error');
});
}
function addOutput(text, className) {
const output = document.createElement('div');
output.className = `output ${className}`;
output.textContent = text;
terminal.appendChild(output);
terminal.scrollTop = terminal.scrollHeight;
}
function clearTerminal() {
terminal.innerHTML = '<div class="output info">Терминал очищен</div>';
loadSystemInfo();
}
function clearSession() {
if (confirm('Вы уверены, что хотите начать новую сессию?')) {
fetch('/clear-session', {method: 'POST'})
.then(() => {
location.reload();
});
}
}
function showHistory() {
fetch('/history')
.then(response => response.json())
.then(data => {
if (data.error) {
addOutput(data.error, 'error');
} else {
let historyText = 'Последние команды:\\n';
data.history.forEach((item, index) => {
historyText += `${index + 1}. [${item.timestamp}] ${item.command}\\n`;
});
addOutput(historyText, 'info');
}
});
}
function showSystemInfo() {
fetch('/system-info')
.then(response => response.json())
.then(data => {
if (data.error) {
addOutput(data.error, 'error');
} else {
let infoText = 'Информация о системе:\\n';
for (const [key, value] of Object.entries(data)) {
infoText += `${key}: ${value}\\n`;
}
addOutput(infoText, 'info');
}
});
}
function loadSessionInfo() {
fetch('/sessions')
.then(response => response.json())
.then(data => {
sessionInfo.textContent = `Активных сессий: ${data.active_sessions}`;
if (data.current_dir) {
currentDirElement.textContent = data.current_dir;
promptElement.textContent = `[${data.current_dir.split('/').pop() || data.current_dir}] $`;
}
});
}
function loadSystemInfo() {
// Загружаем базовую информацию о системе при старте
showSystemInfo();
}
// Автодополнение по Tab
commandInput.addEventListener('keydown', function(e) {
if (e.key === 'Tab') {
e.preventDefault();
// Базовая реализация автодополнения
const currentInput = commandInput.value;
// Можно расширить для реального автодополнения
}
});
</script>
</body>
</html>''')
print("Запуск Web Shell с полным доступом...")
print("⚠️ ПРЕДУПРЕЖДЕНИЕ: Этот сервер предоставляет полный доступ к системе!")
print("🚫 Не используйте в production без дополнительных мер безопасности!")
print("🌐 Сервер запущен: http://0.0.0.0:5000")
app.run(host='0.0.0.0', port=5000, debug=False)