Skip to content

Commit

Permalink
feat: completed the controller and node develop, refs #2
Browse files Browse the repository at this point in the history
  • Loading branch information
giper45 committed Nov 3, 2022
1 parent 98a02a2 commit 30fcde6
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 9 deletions.
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ generate-controller-test:

controller-run:
$(POETRY_RUN) vuln-controller run-env 10.5.0.5
controller-run-all:
$(POETRY_RUN) vuln-controller run-envs

controller-down-all:
$(POETRY_RUN) vuln-controller down-envs
controller-norun:
$(POETRY_RUN) vuln-controller run-env 10.5.0.9

Expand Down
49 changes: 49 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,55 @@ poetry run vuln-runner <command>
```


## Remote mode
It is possible to use `vuln-runner` in distributed node:
1. A *vuln-node* initializes a token and run a tcp server that listens for commands
2. A *vuln-controller* starts the vulnerable environments

### node configuration
Initializes the node:

```
vuln-runner init
vuln-node init
```
You have to define a token that will be used to validate the requests that comes from a controller.

Start the vulnerable node:
```
vuln-node start
```
The `vuln-node` listens for connections on port **4545** .
When a vuln-node is listening for a connection the controlle is able to find it through the **discovery** step.


### controller configuration
Initialize the controller
```
vuln-runner init
vuln-controller init
```

Discovery the remote nodes
```
vuln-controller discovery <subnet_vulnerable_nodes> -u
```
The `-u` option updates the `hosts.json` configuration file present in the ~/.vulnenv folder .

When you have configured the `hosts.json` it is possible to generate a vulnerable environment configuration composed of `<no_env>` vulnerable scenarios. For example, the following command:
```
vuln-controller generate-vulnenv 2
```

generates two vulnerable environment for each `vuln-node` discovered previosly.

### Design considerations for the distributed architecture
The token is used to authenticate the requests that comes from the controller. It is not used as secure mechanism.
All the protocol is unencrypted, as we suppose that the environment is "unsecure-by-default". It is used to setup vulnerable machines. An attacker could potentially intercepts the requests and put them down.

You could setup firewall rules to allow the connections to the **4545** only from the controller IP host.

This is useful as the students should not be able to see that port.

## Credits
Developed by gx1 [@SecSI](https://secsi.io)
Expand Down
35 changes: 35 additions & 0 deletions docker_vuln_controller/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@

NODE_PORT = 4545
TIMEOUT_SOCKET = 0.0001
RUN_TIMEOUT_SOCKET = 1

def check_unauth(ret):
print(ret)
if ret == "UNAUTHORIZED":
err("Invalid token")

def _msg(token, type, data = None):
if data:
Expand All @@ -26,6 +32,9 @@ def hello(token):
def run(token, cves):
return _msg(token, "run", cves)

def down(token, cves):
return _msg(token, "down", cves)

def parse_version(version_string):
v_number = version_string.split()[1].replace('v', '')
return v_number
Expand All @@ -48,6 +57,7 @@ def ping(self):
self.sock.send(hello(self.token).encode('utf-8'))
# Receive
version_string = self.sock.recv(1024).decode()
check_unauth(version_string)
version_number = parse_version(version_string)
if version_number == VERSION:
ret = True
Expand All @@ -69,10 +79,14 @@ def ping(self):
def run(self, cves):
ret = False
try:
self.sock.settimeout(RUN_TIMEOUT_SOCKET)
self.sock.connect((self.address, NODE_PORT))
self.sock.send(run(self.token, cves).encode('utf-8'))
# Receive
ret = self.sock.recv(1024).decode()
check_unauth(ret)
if ret == "STARTED":
log("{} vulnenv started".format(self.address))


except socket.gaierror:
Expand All @@ -84,3 +98,24 @@ def run(self, cves):
self.sock.close()
return ret

def down(self, cves):
ret = False
try:
self.sock.settimeout(RUN_TIMEOUT_SOCKET)
self.sock.connect((self.address, NODE_PORT))
self.sock.send(down(self.token, cves).encode('utf-8'))
# Receive
ret = self.sock.recv(1024).decode()
check_unauth(ret)
if ret == "STOPPED":
log("{} vulnenv stopped".format(self.address))


except socket.gaierror:
err('There an error resolving the host')

except Exception as e:
err("Communication error: {}".format(e))

self.sock.close()
return ret
20 changes: 19 additions & 1 deletion docker_vuln_controller/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def check_initialization():
def check_token():
h = token_initialized()
if not h:
err("Token not initialized, please run \"vuln-node init\" first")
err("Token not initialized, please run \"vuln-controller init\" first")
return h

@typer_app.command()
Expand Down Expand Up @@ -86,7 +86,25 @@ def run_env(host: str):
err("vulnenv not found for {}".format(host))
vuln_client.run(env_host)

@typer_app.command()
def run_envs():
h = check_token()
envs = h.envs
hosts = envs.keys()
for host in hosts:
env_host = envs.get(host)
vuln_client = VulnClient(host, h.token)
vuln_client.run(env_host)

@typer_app.command()
def down_envs():
h = check_token()
envs = h.envs
hosts = envs.keys()
for host in hosts:
env_host = envs.get(host)
vuln_client = VulnClient(host, h.token)
vuln_client.down(env_host)

@typer_app.command()
def ping(ip: str):
Expand Down
1 change: 1 addition & 0 deletions docker_vuln_node/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def check_token():



# Start the vuln-node
@typer_app.command()
def start():
check_initialization()
Expand Down
49 changes: 41 additions & 8 deletions docker_vuln_node/node.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import socket
from docker_vuln_runner.helper import err, log, VERSION
from docker_vuln_runner.helper import err, log, warn, VERSION
from docker_vuln_runner.vuln import Vuln, Vulnenv, vuln_home, get_vuln_objects, all_ports, get_duplicates, vuln_init, check_init, vuln_update, is_initialized, vuln_names, run_vuln, find_vuln_projects, down_vuln, check_docker
from docker_vuln_runner.message import VulnMessage

from threading import Thread
from time import perf_counter


NODE_PORT = 4545


Expand All @@ -22,16 +26,45 @@ def __init__(self, hosts_obj):

# log("Json received --> {}".format(jsonReceived))
vuln_message = VulnMessage.parse_json(jsonReceived)
if vuln_message.is_hello():
c.send("vuln-runner v{}".format(VERSION).encode('utf-8'))
self.dispatch_msg(c, vuln_message)
c.close()

elif vuln_message.is_run():
vuln_envs = vuln_message.data
for v in vuln_envs:
run_vuln(self.vulhubs, v['name'])
def dispatch_msg(self, c, vuln_message):
received_token = vuln_message.token
if received_token != self.hosts_obj.token:
warn("Invalid token received")
c.send("UNAUTHORIZED".encode('utf-8'))
return

# if received_token !=
if vuln_message.is_hello():
c.send("vuln-runner v{}".format(VERSION).encode('utf-8'))

elif vuln_message.is_run():
vuln_envs = vuln_message.data
threads = [Thread(target=run_vuln, args=(self.vulhubs, v['name'])) for v in vuln_envs]

# TBD: Insert TODO
for thread in threads:
thread.start()

c.send("STARTED".encode('utf-8'))

elif vuln_message.is_down():
vuln_envs = vuln_message.data
threads = [Thread(target=down_vuln, args=(self.vulhubs, v['name'])) for v in vuln_envs]

# TBD: Insert TODO
for thread in threads:
thread.start()

c.send("STOPPED".encode('utf-8'))


# for thread in threads:
# thread.join()


c.close()

def shutdown(self):
self.sock.shutdown(socket.SHUT_RDWR)
Expand Down
2 changes: 2 additions & 0 deletions docker_vuln_runner/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ def is_hello(self):
def is_run(self):
return self.msg == 'run'

def is_down(self):
return self.msg == 'down'

def msg(self):
return json.dumps(self.__dict__)

0 comments on commit 30fcde6

Please sign in to comment.