Skip to content

Commit

Permalink
Merge pull request #55 from fkie-cad/dev
Browse files Browse the repository at this point in the history
Merge dev into main
  • Loading branch information
ru37z authored Jun 29, 2022
2 parents 109cf7d + a46cce1 commit ae9039e
Show file tree
Hide file tree
Showing 40 changed files with 216 additions and 57 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ pip install --editable .
```

Before building SOCBED, you need to manually download Windows 10 and adapt a provisioning script:
- Download a Windows 10 64-bit ISO image from Microsoft. We are currently using version 21H2 (November 2021) in English for testing, but other versions should work as well.
- Download a Windows 10 64-bit ISO image from Microsoft (see [here](https://www.microsoft.com/en-us/software-download/windows10ISO)). We are currently using version 21H2 (November 2021) in English for testing, but other versions should work as well.
- Calculate the MD5 hash of this ISO file using `md5sum <filename>.iso`.
- Open the file `provisioning/packer/client.json` and change the values of the fields `iso_url` and `iso_checksum` accordingly.
- Open the file `provisioning/packer/client.json` and change the values of the fields `iso_url` and `iso_checksum` under `variables` (at the bottom of the file) accordingly.

The script below will execute everything required to build and configure each respective machine, including snapshotting.
It will download the remaining ISO files, automatically boot the machines and provision the necessary versions of software dependencies with no interaction needed.
Expand Down Expand Up @@ -190,4 +190,4 @@ If you would like to contribute, please let us know.

The files in this repository are licensed under the GNU General Public License Version 3. See [LICENSE](LICENSE) for details.

If you are using SOCBED for your academic work, please cite the paper mentioned above.
If you are using SOCBED for your academic work, please cite the paper mentioned above.
2 changes: 1 addition & 1 deletion provisioning/ansible/host_vars/client.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# OpenSSH installation variables
openssh_temporary_dir: "C:\\Temp"
openssh_download_url: "https://github.com/PowerShell/Win32-OpenSSH/releases/download/v8.0.0.0p1-Beta/OpenSSH-Win64.zip"
openssh_download_url: "https://github.com/PowerShell/Win32-OpenSSH/releases/download/v8.1.0.0p1-Beta/OpenSSH-Win64.zip"
openssh_extract_dir: "C:\\OpenSSH"
openssh_archive_name: "OpenSSH-Win64"

Expand Down
5 changes: 3 additions & 2 deletions provisioning/packer/attacker.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
"--nic2",
"hostonly",
"--hostonlyadapter2",
"vboxnet0"
"{{user `vm_hostonlyif`}}"
],
[
"modifyvm",
Expand Down Expand Up @@ -114,7 +114,8 @@
"ssh_host_addr": "192.168.56.31",
"vm_description": "SOCBED: Attacker",
"vm_version": "fresh",
"vm_output": "./exports/attacker"
"vm_output": "./exports/attacker",
"vm_hostonlyif": "{{env `HOSTONLYIF`}}"
}
}

Expand Down
5 changes: 3 additions & 2 deletions provisioning/packer/client.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"--nic2",
"hostonly",
"--hostonlyadapter2",
"vboxnet0",
"{{user `vm_hostonlyif`}}",
"--macaddress2",
"005056000101",
"--nic3",
Expand Down Expand Up @@ -119,7 +119,8 @@
"iso_url": "/usr/share/runner-dependencies/windows_isos/Win10_21H2_English_x64.iso",
"vm_description": "SOCBED: Client",
"vm_version": "fresh",
"vm_output": "./exports/client"
"vm_output": "./exports/client",
"vm_hostonlyif": "{{env `HOSTONLYIF`}}"
}
}

5 changes: 3 additions & 2 deletions provisioning/packer/companyrouter.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"ssh_host_addr": "192.168.56.10",
"vm_description": "SOCBED: Company Router",
"vm_version": "fresh",
"vm_output": "./exports/companyrouter"
"vm_output": "./exports/companyrouter",
"vm_hostonlyif": "{{env `HOSTONLYIF`}}"
},
"builders": [
{
Expand Down Expand Up @@ -45,7 +46,7 @@
"--nic4",
"hostonly",
"--hostonlyadapter4",
"vboxnet0"
"{{user `vm_hostonlyif`}}"
]
],
"boot_wait": "10s",
Expand Down
5 changes: 3 additions & 2 deletions provisioning/packer/dmzserver.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
"--nic2",
"hostonly",
"--hostonlyadapter2",
"vboxnet0"
"{{user `vm_hostonlyif`}}"
],
[
"modifyvm",
Expand Down Expand Up @@ -125,7 +125,8 @@
"ssh_host_addr": "192.168.56.20",
"vm_description": "SOCBED: DMZ Server",
"vm_version": "fresh",
"vm_output": "./exports/dmzserver"
"vm_output": "./exports/dmzserver",
"vm_hostonlyif": "{{env `HOSTONLYIF`}}"
}
}

5 changes: 3 additions & 2 deletions provisioning/packer/internalserver.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
"--nic2",
"hostonly",
"--hostonlyadapter2",
"vboxnet0"
"{{user `vm_hostonlyif`}}"
],
[
"modifyvm",
Expand Down Expand Up @@ -125,7 +125,8 @@
"ssh_host_addr": "192.168.56.11",
"vm_description": "SOCBED: Internal Server",
"vm_version": "fresh",
"vm_output": "./exports/internalserver"
"vm_output": "./exports/internalserver",
"vm_hostonlyif": "{{env `HOSTONLYIF`}}"
}
}

5 changes: 3 additions & 2 deletions provisioning/packer/internetrouter.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"ssh_host_addr": "192.168.56.30",
"vm_description": "SOCBED: Internet Router",
"vm_version": "fresh",
"vm_output": "./exports/InternetRouter"
"vm_output": "./exports/InternetRouter",
"vm_hostonlyif": "{{env `HOSTONLYIF`}}"
},
"builders": [
{
Expand Down Expand Up @@ -38,7 +39,7 @@
"--nic3",
"hostonly",
"--hostonlyadapter3",
"vboxnet0"
"{{user `vm_hostonlyif`}}"
]
],
"boot_wait": "10s",
Expand Down
5 changes: 3 additions & 2 deletions provisioning/packer/logserver.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
"--nic2",
"hostonly",
"--hostonlyadapter2",
"vboxnet0"
"{{user `vm_hostonlyif`}}"
],
[
"modifyvm",
Expand Down Expand Up @@ -125,7 +125,8 @@
"ssh_host_addr": "192.168.56.12",
"vm_description": "SOCBED: Log Server",
"vm_version": "fresh",
"vm_output": "./exports/logserver"
"vm_output": "./exports/logserver",
"vm_hostonlyif": "{{env `HOSTONLYIF`}}"
}
}

29 changes: 25 additions & 4 deletions src/attacks/attack.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@
# along with SOCBED. If not, see <http://www.gnu.org/licenses/>.


import re
import socket
from contextlib import contextmanager
from types import SimpleNamespace
from signal import SIGINT, default_int_handler, signal

import paramiko
from attacks.printer import Printer, ListPrinter, MultiPrinter
Expand Down Expand Up @@ -71,13 +73,19 @@ def run(self):

@contextmanager
def wrap_ssh_exceptions(self):
signal(SIGINT, self.interrupt_handler)
try:
yield
except (paramiko.SSHException, socket.error, socket.timeout) as e:
raise AttackException(e)
except socket.timeout:
print(f"Timeout after {self.ssh_client.channel_timeout}s")
except (paramiko.SSHException, socket.error) as err:
raise AttackException(err) from err
finally:
signal(SIGINT, default_int_handler)

def exec_command_on_target(self, command):
self.exec_commands_on_target([command])
with self.wrap_ssh_exceptions():
self.ssh_client.exec_command_on_target(command, self.printer)

def exec_commands_on_target(self, commands):
with self.wrap_ssh_exceptions():
Expand All @@ -87,13 +95,26 @@ def connect_to_target(self):
with self.wrap_ssh_exceptions():
self.ssh_client.connect_to_target()

def interrupt_handler(self, _signum, _frame):
if hasattr(self, "handler"):
print("\rStopping...")
self.handler.shutdown()
elif hasattr(self.ssh_client, "stdin"):
print("\rStopping...")
self.ssh_client.stdin.channel.send("\x03")
else:
print("Cannot cancel command")


@contextmanager
def check_printed(self, indicator):
# Removes all ANSI escape sequences to prevent unintended string mismatches when checking for success
ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')
lp = ListPrinter()
old_printer = self.printer
self.printer = MultiPrinter(printers=[lp, old_printer])
yield
self.printer = old_printer
if not any(indicator in line for line in lp.printed):
if not any(indicator in ansi_escape.sub("", line) for line in "".join(lp.printed).split("\n")):
raise AttackException(
"Attack failed: Indicator \"{}\" not found in output".format(indicator))
2 changes: 1 addition & 1 deletion src/attacks/attack_c2_exfiltration.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def _start_handler(self):
def _handle_output(self):
for line in self.handler.stdout:
self._respond(line)
self.print(line.strip("\n"))
self.print(line)

def _respond(self, line):
if "Meterpreter session 1 opened" in line:
Expand Down
2 changes: 1 addition & 1 deletion src/attacks/attack_change_wallpaper.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def _start_handler(self):
def _handle_output(self):
for line in self.handler.stdout:
self._respond(line)
self.print(line.strip("\n"))
self.print(line)

def _respond(self, line):
if "Meterpreter session 1 opened" in line:
Expand Down
2 changes: 1 addition & 1 deletion src/attacks/attack_download_malware_meterpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def _start_handler(self):
def _handle_output(self):
for line in self.handler.stdout:
self._respond(line)
self.print(line.strip("\n"))
self.print(line)

def _respond(self, line):
if "Meterpreter session 1 opened" in line:
Expand Down
2 changes: 1 addition & 1 deletion src/attacks/attack_execute_malware.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,4 @@ def _execute_malware_command(self):
"{exec} && echo successful execution of \"{file}\"",
"echo could not execute \"{file}\""
]).format(exec=try_execution_cmd, file=self.options.file)
return "cmd /c \"{cmd}\"".format(cmd=check_error_cmd)
return check_error_cmd
2 changes: 1 addition & 1 deletion src/attacks/attack_hashdump.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def _handle_output(self):
try:
for line in self.handler.stdout:
self._respond(line)
self.print(line.strip("\n"))
self.print(line)
except UnicodeDecodeError as e:
self.print("UnicodeDecodeError: {}".format(e))
self.handler.shutdown()
Expand Down
4 changes: 2 additions & 2 deletions src/attacks/attack_kill_reverse_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ def _reset_reverse_connection(self):
]
for process in things_to_kill:
cmd = (
'cmd /c "wmic process where '
f'\"Description like \'{process}\'\" call terminate" '
'wmic process where '
f'\"Description like \'{process}\'\" call terminate '
'&& echo Successful wmic execution\"')
with self.check_printed("Successful wmic execution"):
self.exec_command_on_target(cmd)
4 changes: 2 additions & 2 deletions src/attacks/attack_mimikatz.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class MimikatzAttack(Attack):
handler = None

def run(self):
with self.check_printed("2aca7635afdc3febc408bee6b89acf16"):
with self.check_printed("2aca7635afdc3febc4"):
with self.wrap_ssh_exceptions():
self._start_handler()
self._handle_output()
Expand All @@ -52,7 +52,7 @@ def _handle_output(self):
try:
for line in self.handler.stdout:
self._respond(line)
self.print(line.strip("\n"))
self.print(line)
except UnicodeDecodeError as e:
self.print("UnicodeDecodeError: {}".format(e))
self.handler.shutdown()
Expand Down
4 changes: 3 additions & 1 deletion src/attacks/attack_sqlmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
# along with SOCBED. If not, see <http://www.gnu.org/licenses/>.


from shutil import get_terminal_size
from attacks import Attack, AttackInfo, AttackOptions


Expand All @@ -37,4 +38,5 @@ def run(self):
self.exec_command_on_target(self._sqlmap_command())

def _sqlmap_command(self):
return f"echo \"{self.options.url}\" | sqlmap --purge --batch --dump"
columns = get_terminal_size().columns
return f"export COLUMNS={columns}; echo \"{self.options.url}\" | sqlmap --purge --batch --dump"
2 changes: 1 addition & 1 deletion src/attacks/attack_take_screenshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def _start_handler(self):
def _handle_output(self):
for line in self.handler.stdout:
self._respond(line)
self.print(line.strip("\n"))
self.print(line)

def _respond(self, line):
if "Meterpreter session 1 opened" in line:
Expand Down
2 changes: 1 addition & 1 deletion src/attacks/printer.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def print(self, msg):
class ConsolePrinter(Printer):
def print(self, msg):
super().print(msg=msg)
print(msg)
print(msg, end="")


class FilePrinter(Printer):
Expand Down
4 changes: 3 additions & 1 deletion src/attacks/reverseconnectionhandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# You should have received a copy of the GNU General Public License
# along with SOCBED. If not, see <http://www.gnu.org/licenses/>.

import time

class ReverseConnectionHandler:
handler_timeout = 330
Expand All @@ -31,7 +32,7 @@ def __init__(self, ssh_client, lhost, lport):
def start(self):
self.ssh_client.connect_to_target()
self.stdin, self.stdout, self.stderr = self.ssh_client.exec_command(
self._msf_command(), timeout=self.channel_timeout)
self._msf_command(), timeout=self.channel_timeout, get_pty=True)

def _msf_command(self):
return (
Expand All @@ -48,4 +49,5 @@ def _msf_command(self):

def shutdown(self):
self.stdin.write("exit -y\n")
time.sleep(1)
self.ssh_client.close()
Loading

0 comments on commit ae9039e

Please sign in to comment.