Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add automatic tests #79

Merged
merged 25 commits into from
Jul 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 12 additions & 24 deletions .github/workflows/build_preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@ jobs:
with:
name: linux-arm
path: packages/linux/arm64/*
- name: install test dependencies
run: |
sudo pip install impacket pytest
- name: copy beagle into path
run: |
sudo cp packages/linux/amd64/SMBeagle /bin/smbeagle
sudo chmod +x /bin/smbeagle
sudo mkdir /empty_dir
- name: run pytest
run: |
cd tests
sudo ROOTDIR=/ pytest -v -k "not on_windows"
build_windows:
runs-on: windows-2019
steps:
Expand Down Expand Up @@ -71,27 +83,3 @@ jobs:
with:
name: windows-x64
path: packages\windows/x64\*
test_on_linux:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build linux x64
run: dotnet publish -c Release --self-contained -r linux-x64 -o packages/linux/amd64 -p:PublishSingleFile=true -p:PublishTrimmed=true -p:InvariantGlobalization=true -p:DebugType=None -p:DebugSymbols=false -p:VersionSuffix=pr$(echo $GITHUB_REF | awk 'BEGIN { FS = "/" } ; { print $3 }')
- name: install test dependencies
run: |
sudo pip install impacket pytest
- run: |
sudo cp packages/linux/amd64/SMBeagle /bin/smbeagle
sudo chmod +x /bin/smbeagle
sudo mkdir /empty_dir
- name: run pytest
run: |
cd tests
sudo pytest -v
9 changes: 9 additions & 0 deletions tests/Dockerfile.Linux
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM punksecurity/smbeagle
RUN apt update && apt install python3 python3-pip -y
RUN pip install impacket pytest
RUN mkdir /empty_dir
WORKDIR /tests/
COPY tests/* .
ENTRYPOINT [ "" ]
ENV ROOTDIR "/"
CMD pytest -v -k 'not on_windows'
23 changes: 23 additions & 0 deletions tests/Dockerfile.Windows
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
FROM mcr.microsoft.com/windows:20H2
ENV PYTHON_VERSION 3.10.5
ENV PYTHON_GET_PIP_URL https://bootstrap.pypa.io/get-pip.py

COPY windows_scripts/* /
RUN "powershell -noprofile -executionpolicy bypass -file .\install_python.ps1"

RUN "pip install impacket pytest"

ENV ROOTDIR "C:\\"
WORKDIR "C:\\"
RUN mkdir empty_dir tests
COPY tests tests
COPY x64 "C:\\windows\\system32\\."
WORKDIR tests
CMD pytest -v -k "not on_linux"

# Cant test native auth as windows auth broken in containers... tried this hacky fix but no good
#RUN net user /add test
#RUN net localgroup administrators test /add
#USER test
#ENV NATIVE_AUTH=1
#RUN net user test goose; pytest -k test_fifty_files_in_the_root
14 changes: 11 additions & 3 deletions tests/tests/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@


def __setupSMB(address, dir, SMB2 = True):
os.chdir("/empty_dir")
os.chdir(f"{os.environ['ROOTDIR']}empty_dir")
server = smbserver.SimpleSMBServer(listenAddress=address, listenPort=445)
server.addShare("share", dir, "")
server.addCredential("test", 1200, "9FD78381EC915F1AAAD3B435B51404EE", "25EDEDFF26CB970623DDA4733227A3F7")
server.setSMB2Support(SMB2)
server.setLogFile('')
server.start()

def setupSMB(address, dir):
Expand All @@ -25,7 +26,7 @@ class SMB(object):
def __init__(self, address = "0.0.0.0", dir_structure = ["fileA", "fileB"]):
self.address = address
self.dir_structure = dir_structure
self.dir = f"/{uuid.uuid4().hex}"
self.dir = f"{os.environ['ROOTDIR']}{uuid.uuid4().hex}"
def __enter__(self):
self.smb = setupSMB(self.address, self.dir)
os.mkdir(self.dir)
Expand Down Expand Up @@ -57,8 +58,15 @@ def runSMBeagle(*args, print_out=True):
def runSMBeagleToCSV(*args):
return runSMBeagle("-c","out.csv",*args)

def runSMBeagleQuick(*args):
return runSMBeagleToCSV("-D",*args)

def runSMBeagleToCSVWithAuth(*args):
return runSMBeagleToCSV("-u","test", "-p", "goose", *args)
try:
os.environ["NATIVE_AUTH"]
return runSMBeagleToCSV(*args)
except:
return runSMBeagleToCSV("-u","test", "-p", "goose", *args)

def runSMBeagleToCSVWithAuthAndReturnResults(*args):
print(runSMBeagleToCSVWithAuth(*args))
Expand Down
30 changes: 16 additions & 14 deletions tests/tests/test_010_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,42 @@

username_or_password_missing_error = "ERROR: Username and Password required on none Windows platforms"
def test_username_and_password_required_on_linux():
assert username_or_password_missing_error in runSMBeagleToCSV()
assert username_or_password_missing_error in runSMBeagleQuick()
def test_password_required_on_linux():
assert username_or_password_missing_error in runSMBeagleToCSV("-p","goose")
assert username_or_password_missing_error in runSMBeagleQuick("-p","goose")
def test_username_required_on_linux():
assert username_or_password_missing_error in runSMBeagleToCSV("-u","goose")
assert username_or_password_missing_error in runSMBeagleQuick("-u","goose")
def test_username_and_password_not_required_on_windows():
assert username_or_password_missing_error not in runSMBeagleQuick()
def test_username_and_password_accepted():
assert username_or_password_missing_error not in runSMBeagleToCSV("-u","goose", "-p", "goose")
assert username_or_password_missing_error not in runSMBeagleQuick("-u","goose", "-p", "goose")
def test_long_username_accepted():
assert username_or_password_missing_error not in runSMBeagleToCSV("--username","goose", "-p", "goose")
assert username_or_password_missing_error not in runSMBeagleQuick("--username","goose", "-p", "goose")
def test_long_password_accepted():
assert username_or_password_missing_error not in runSMBeagleToCSV("-u","goose", "--password", "goose")
assert username_or_password_missing_error not in runSMBeagleQuick("-u","goose", "--password", "goose")

output_required_error = "At least one option from group 'output' (c, csv-file, e, elasticsearch-host)"
def test_csv_or_elasticsearch_required():
assert output_required_error in runSMBeagle()
def test_short_csv_accepted():
assert output_required_error not in runSMBeagle("-c","out.csv")
assert output_required_error not in runSMBeagleQuick("-c","out.csv")
def test_long_csv_accepted():
assert output_required_error not in runSMBeagle("--csv-file","out.csv")
assert output_required_error not in runSMBeagleQuick("--csv-file","out.csv")
def test_short_elasticsearch_accepted():
assert output_required_error not in runSMBeagle("-e","elasticsearch")
assert output_required_error not in runSMBeagleQuick("-e","elasticsearch")
def test_long_elasticsearch_accepted():
assert output_required_error not in runSMBeagle("--elasticsearch-host","elasticsearch")
assert output_required_error not in runSMBeagleQuick("--elasticsearch-host","elasticsearch")


def test_manual_host_accepted():
assert "127.0.0.2" in runSMBeagleToCSVWithAuth("-h", "127.0.0.2")
assert "127.0.0.2" in runSMBeagleToCSVWithAuth("-D","-h", "127.0.0.2")
def test_multiple_manual_host_accepted():
output = runSMBeagleToCSVWithAuth("-h", "127.0.0.2", "127.0.0.3")
output = runSMBeagleToCSVWithAuth("-D","-h", "127.0.0.2", "127.0.0.3")
assert "127.0.0.2" in output and "127.0.0.3" in output

def test_manual_network_accepted():
output = runSMBeagleToCSVWithAuth("-n", "127.0.0.0/24")
output = runSMBeagleToCSVWithAuth("-D", "-n", "127.0.0.0/24")
assert "127.0.0.0/24" in output
def test_multiple_manual_network_accepted():
output = runSMBeagleToCSVWithAuth("-n", "127.0.0.0/24", "127.0.1.0/24")
output = runSMBeagleToCSVWithAuth("-D","-n", "127.0.0.0/24", "127.0.1.0/24")
assert "127.0.0.0/24" in output and "127.0.1.0/24" in output
20 changes: 10 additions & 10 deletions tests/tests/test_020_tcp_scans.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,51 +10,51 @@

def test_one_manual_host_tcp_success():
with SMB():
assert one_smb_service_discovered_message in runSMBeagleToCSVWithAuth("-h", "127.0.0.2")
assert one_smb_service_discovered_message in runSMBeagleToCSVWithAuth("-D", "-h", "127.0.0.2")

def test_one_manual_host_tcp_fail_if_not_listening():
with SMB("127.0.0.2"):
assert no_smb_service_discovered_message in runSMBeagleToCSVWithAuth("-h", "127.0.0.3")
assert no_smb_service_discovered_message in runSMBeagleToCSVWithAuth("-D", "-h", "127.0.0.3")

def test_two_manual_host_tcp_success():
with SMB("127.0.0.2"):
with SMB("127.0.0.3"):
assert two_smb_service_discovered_message in runSMBeagleToCSVWithAuth("-h", "127.0.0.2", "127.0.0.3")
assert two_smb_service_discovered_message in runSMBeagleToCSVWithAuth("-D", "-h", "127.0.0.2", "127.0.0.3")

def test_one_manual_host_tcp_success_and_not_two_if_second_not_listening():
with SMB("127.0.0.2"):
assert one_smb_service_discovered_message in runSMBeagleToCSVWithAuth("-h", "127.0.0.2", "127.0.0.3")
assert one_smb_service_discovered_message in runSMBeagleToCSVWithAuth("-D", "-h", "127.0.0.2", "127.0.0.3")

def test_one_discovered_host_tcp_success():
with SMB("127.0.0.2"):
assert one_smb_service_discovered_message in runSMBeagleToCSVWithAuth("-n", "127.0.0.0/24")
assert one_smb_service_discovered_message in runSMBeagleToCSVWithAuth("-D", "-n", "127.0.0.0/24")

def test_no_discovered_host_when_filtered():
with SMB("127.0.0.2"):
assert no_smb_service_discovered_message in runSMBeagleToCSVWithAuth("-n", "127.0.0.0/24","-H","127.0.0.2" )
assert no_smb_service_discovered_message in runSMBeagleToCSVWithAuth("-D", "-n", "127.0.0.0/24","-H","127.0.0.2" )

def test_one_discovered_host_when_one_filtered():
with SMB("127.0.0.2"):
with SMB("127.0.0.3"):
assert one_smb_service_discovered_message in runSMBeagleToCSVWithAuth("-n", "127.0.0.0/24","-H","127.0.0.2" )
assert one_smb_service_discovered_message in runSMBeagleToCSVWithAuth("-D", "-n", "127.0.0.0/24","-H","127.0.0.2" )

def test_two_discovered_host_tcp_success():
with SMB("127.0.0.2"):
with SMB("127.0.0.3"):
assert two_smb_service_discovered_message in runSMBeagleToCSVWithAuth("-n", "127.0.0.0/24")
assert two_smb_service_discovered_message in runSMBeagleToCSVWithAuth("-D", "-n", "127.0.0.0/24")

def test_three_discovered_host_tcp_success():
with SMB("127.0.0.2"):
with SMB("127.0.0.3"):
with SMB("127.0.0.4"):
assert three_smb_service_discovered_message in runSMBeagleToCSVWithAuth("-n", "127.0.0.0/24")
assert three_smb_service_discovered_message in runSMBeagleToCSVWithAuth("-D", "-n", "127.0.0.0/24")

def test_four_discovered_host_tcp_success():
with SMB("127.0.0.2"):
with SMB("127.0.0.3"):
with SMB("127.0.0.4"):
with SMB("127.0.0.5"):
assert four_smb_service_discovered_message in runSMBeagleToCSVWithAuth("-n", "127.0.0.0/24")
assert four_smb_service_discovered_message in runSMBeagleToCSVWithAuth("-D", "-n", "127.0.0.0/24")

def test_disable_network_discovery():
no_networks_to_scan_message = "there are no networks or hosts to scan"
Expand Down
16 changes: 16 additions & 0 deletions tests/windows_scripts/install_python.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
$url = ('https://www.python.org/ftp/python/{0}/python-{0}-amd64.exe' -f $env:PYTHON_VERSION)
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Invoke-WebRequest -Uri $url -OutFile 'python.exe';
# https://docs.python.org/3.7/using/windows.html#installing-without-ui
Start-Process python.exe -Wait -ArgumentList @(
'/quiet',
'InstallAllUsers=1',
'TargetDir=C:\Python',
'PrependPath=1',
'Shortcuts=0',
'Include_doc=0',
'Include_pip=1',
'Include_test=0'
);
#the installer updated PATH, so we should refresh our local value
Remove-Item python.exe -Force