[enhancement] Add windows support and windows binary build to Coercer (#97)

* split task preparation and execution into seperate functions

* Update debug + verbose printing

* Refactor reporter, standardize print formatting, and add logging

* Initial Windows Support

* Create windows binary installer script

* Add small snippet to README for using the installer script

* Update installer to install C++ Build Tools

* Fix bug with coerce mode and packet redirection

* Update URL in installer.ps1

---------

Co-authored-by: p0rtL6 <p0rtl.pue@gmail.com>
This commit is contained in:
p0rtL6
2025-03-21 08:42:42 +01:00
committed by GitHub
co-authored by p0rtL6
parent aba43d34b6
commit e1a5d44c4f
13 changed files with 397 additions and 674 deletions
+3
View File
@@ -10,6 +10,9 @@
<br>
</p>
## Windows Support
To build a binary for Windows, download the `installer.ps1` script from this repository. Run it simply with no arguments to create a binary in the working directory. Use `-h` or `--help` for the help menu with options.
## Features
- Core:
+17 -7
View File
@@ -8,9 +8,9 @@
import argparse
import os
import sys
import threading
from sectools.network.domains import is_fqdn
from sectools.network.ip import is_ipv4_cidr, is_ipv4_addr, is_ipv6_addr, expand_cidr, expand_port_range
from coercer.core.Reporter import create_reporter
VERSION = "2.4.3"
@@ -187,6 +187,8 @@ def parseArgs():
def main():
lmhash, nthash, options = parseArgs()
from coercer.core.Reporter import create_reporter
create_reporter(options, options.verbose)
from coercer.core.Reporter import reporter
@@ -195,11 +197,19 @@ def main():
from coercer.core.modes.coerce import action_coerce
from coercer.core.modes.fuzz import action_fuzz
from coercer.network.smb import try_login
from coercer.network.utils import can_listen_on_port
from coercer.network.utils import can_listen_on_port, redirect_smb_packets
from coercer.core.loader import find_and_load_coerce_methods
available_methods = find_and_load_coerce_methods()
if options.smb_port == 445 and sys.platform == "win32" and (options.mode == "scan" or options.mode == "fuzz"):
reporter.print_info("Redirecting packets between port 445 <-> 4445")
options.redirecting_smb_packets = True
redirector = threading.Thread(target=redirect_smb_packets)
redirector.start()
else:
options.redirecting_smb_packets = False
# Parsing targets
targets = []
if options.target_ip is not None:
@@ -265,8 +275,8 @@ def main():
reporter.print_info("Starting scan mode")
if credentials.is_anonymous():
reporter.print_info("No credentials provided, trying to connect with a NULL session.")
if not can_listen_on_port("0.0.0.0", 445):
reporter.print_error("Cannot listen on port tcp/%d. Are you root or are other servers running?" % 445)
if not can_listen_on_port("0.0.0.0", 4445 if options.redirecting_smb_packets else options.smb_port):
reporter.print_error("Cannot listen on port tcp/%d. Are you root or are other servers running?" % 4445 if options.redirecting_smb_packets else options.smb_port)
else:
for target in targets:
reporter.print_info("Scanning target %s" % target)
@@ -289,8 +299,8 @@ def main():
reporter.print_info("Starting fuzz mode")
if credentials.is_anonymous():
reporter.print_info("No credentials provided, trying to connect with a NULL session.")
if not can_listen_on_port("0.0.0.0", 445):
reporter.print_error("Cannot listen on port tcp/%d. Are you root or are other servers running?" % 445)
if not can_listen_on_port("0.0.0.0", 4445 if options.redirecting_smb_packets else options.smb_port):
reporter.print_error("Cannot listen on port tcp/%d. Are you root or are other servers running?" % 4445 if options.redirecting_smb_packets else options.smb_port)
else:
for target in targets:
reporter.print_info("Fuzzing target %s" % target)
+1 -1
View File
@@ -213,7 +213,7 @@ class Reporter(object):
sys.stdout.write(EscapeCodes.ERASE_LINE)
if self.options.mode in ["scan", "fuzz"]:
if result == TestResult.SMB_AUTH_RECEIVED:
if result == TestResult.SMB_AUTH_RECEIVED or result == TestResult.SMB_AUTH_RECEIVED_NTLMv1 or result == TestResult.SMB_AUTH_RECEIVED_NTLMv2:
self.print_result("+", "SMB Auth", msprotocol_rpc_instance, EscapeCodes.BOLD_BRIGHT_GREEN)
elif result == TestResult.HTTP_AUTH_RECEIVED:
self.print_result("+", "HTTP Auth", msprotocol_rpc_instance, EscapeCodes.BOLD_BRIGHT_GREEN)
+1 -1
View File
@@ -155,4 +155,4 @@ def execute_tasks(tasks, options, target, credentials, mode, listening_ip=None,
if options.verbose:
reporter.print_error(" ", "Cannot bind to interface (%s, %s)!" % (uuid, version))
else:
reporter.print(transportType.value, " '", (taskEntry, EscapeCodes.BOLD_BRIGHT_BLUE), "' ", ("closed", EscapeCodes.BOLD_BRIGHT_RED), "!", symbol=("!", EscapeCodes.BRIGHT_RED), verbose=True)
reporter.print(transportType.value, " '", (taskEntry, EscapeCodes.BOLD_BRIGHT_BLUE), "' ", ("closed", EscapeCodes.BOLD_BRIGHT_RED), "!", symbol=("!", EscapeCodes.BRIGHT_RED), verbose=True)
+9 -315
View File
@@ -14,334 +14,28 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import optparse
import ssl
try:
from SocketServer import TCPServer, UDPServer, ThreadingMixIn
except:
from socketserver import TCPServer, UDPServer, ThreadingMixIn
from threading import Thread
from socketserver import TCPServer, ThreadingMixIn
from .utils import *
import struct
from coercer.core.Reporter import reporter
class ThreadingUDPServer(ThreadingMixIn, UDPServer):
def server_bind(self):
if OsInterfaceIsSupported():
try:
if settings.Config.Bind_To_ALL:
pass
else:
if (sys.version_info > (3, 0)):
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
else:
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
except:
pass
UDPServer.server_bind(self)
class ThreadingTCPServer(ThreadingMixIn, TCPServer):
def server_bind(self):
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
if OsInterfaceIsSupported():
try:
if settings.Config.Bind_To_ALL:
pass
else:
if (sys.version_info > (3, 0)):
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
if sys.platform == "win32":
self.socket.bind(settings.Config.OURIP)
else:
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
if (sys.version_info > (3, 0)):
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
else:
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
except:
pass
TCPServer.server_bind(self)
class ThreadingTCPServerAuth(ThreadingMixIn, TCPServer):
def server_bind(self):
if OsInterfaceIsSupported():
try:
if settings.Config.Bind_To_ALL:
pass
else:
if (sys.version_info > (3, 0)):
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
else:
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
except:
pass
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0))
TCPServer.server_bind(self)
class ThreadingUDPMDNSServer(ThreadingMixIn, UDPServer):
def server_bind(self):
MADDR = "224.0.0.251"
MADDR6 = 'ff02::fb'
self.socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 255)
Join = self.socket.setsockopt(socket.IPPROTO_IP,socket.IP_ADD_MEMBERSHIP, socket.inet_aton(MADDR) + settings.Config.IP_aton)
#IPV6:
if (sys.version_info > (3, 0)):
mreq = socket.inet_pton(socket.AF_INET6, MADDR6) + struct.pack('@I', if_nametoindex2(settings.Config.Interface))
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq)
else:
mreq = socket.inet_pton(socket.AF_INET6, MADDR6) + struct.pack('@I', if_nametoindex2(settings.Config.Interface))
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq)
if OsInterfaceIsSupported():
try:
if settings.Config.Bind_To_ALL:
pass
else:
if (sys.version_info > (3, 0)):
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
else:
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
except:
pass
UDPServer.server_bind(self)
class ThreadingUDPLLMNRServer(ThreadingMixIn, UDPServer):
def server_bind(self):
MADDR = '224.0.0.252'
MADDR6 = 'FF02:0:0:0:0:0:1:3'
self.socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 255)
Join = self.socket.setsockopt(socket.IPPROTO_IP,socket.IP_ADD_MEMBERSHIP,socket.inet_aton(MADDR) + settings.Config.IP_aton)
#IPV6:
mreq = socket.inet_pton(socket.AF_INET6, MADDR6) + struct.pack('@I', if_nametoindex2(settings.Config.Interface))
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq)
if OsInterfaceIsSupported():
try:
if settings.Config.Bind_To_ALL:
pass
else:
if (sys.version_info > (3, 0)):
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
else:
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
except:
pass
UDPServer.server_bind(self)
ThreadingUDPServer.allow_reuse_address = 1
ThreadingUDPServer.address_family = socket.AF_INET6
ThreadingTCPServer.allow_reuse_address = 1
ThreadingTCPServer.address_family = socket.AF_INET6
ThreadingUDPMDNSServer.allow_reuse_address = 1
ThreadingUDPMDNSServer.address_family = socket.AF_INET6
ThreadingUDPLLMNRServer.allow_reuse_address = 1
ThreadingUDPLLMNRServer.address_family = socket.AF_INET6
ThreadingTCPServerAuth.allow_reuse_address = 1
ThreadingTCPServerAuth.address_family = socket.AF_INET6
def serve_thread_udp_broadcast(host, port, handler):
try:
server = ThreadingUDPServer(('', port), handler)
server.serve_forever()
except:
reporter.print_error("Error starting UDP server on port %s, check permissions or other servers running." % str(port))
def serve_NBTNS_poisoner(host, port, handler):
serve_thread_udp_broadcast('', port, handler)
def serve_MDNS_poisoner(host, port, handler):
try:
server = ThreadingUDPMDNSServer(('', port), handler)
server.serve_forever()
except:
reporter.print_error("Error starting UDP server on port %s, check permissions or other servers running." % str(port))
def serve_LLMNR_poisoner(host, port, handler):
try:
server = ThreadingUDPLLMNRServer(('', port), handler)
server.serve_forever()
except:
reporter.print_error("Error starting UDP server on port %s, check permissions or other servers running." % str(port))
def serve_thread_udp(host, port, handler):
try:
if OsInterfaceIsSupported():
server = ThreadingUDPServer(('', port), handler)
server.serve_forever()
else:
server = ThreadingUDPServer(('', port), handler)
server.serve_forever()
except:
reporter.print_error("Error starting UDP server on port %s, check permissions or other servers running." % str(port))
def serve_thread_tcp(host, port, handler):
try:
if OsInterfaceIsSupported():
server = ThreadingTCPServer(('', port), handler)
server.serve_forever()
else:
server = ThreadingTCPServer(('', port), handler)
server.serve_forever()
except:
reporter.print_error("Error starting TCP server on port %s, check permissions or other servers running." % str(port))
def serve_thread_tcp_auth(host, port, handler):
try:
if OsInterfaceIsSupported():
server = ThreadingTCPServerAuth(('', port), handler)
server.serve_forever()
else:
server = ThreadingTCPServerAuth(('', port), handler)
server.serve_forever()
except:
reporter.print_error("Error starting TCP server on port %s, check permissions or other servers running." % str(port))
def serve_thread_SSL(host, port, handler):
try:
cert = os.path.join(settings.Config.ResponderPATH, settings.Config.SSLCert)
key = os.path.join(settings.Config.ResponderPATH, settings.Config.SSLKey)
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.load_cert_chain(cert, key)
if OsInterfaceIsSupported():
server = ThreadingTCPServer(('', port), handler)
server.socket = context.wrap_socket(server.socket, server_side=True)
server.serve_forever()
else:
server = ThreadingTCPServer(('', port), handler)
server.socket = context.wrap_socket(server.socket, server_side=True)
server.serve_forever()
except:
reporter.print_error("Error starting SSL server on port %s, check permissions or other servers running." % str(port))
def main():
try:
if (sys.version_info < (3, 0)):
reporter.print_warn("Still using python 2? :(")
reporter.print_in_progress("Listening for events...")
threads = []
# Load (M)DNS, NBNS and LLMNR Poisoners
from poisoners.LLMNR import LLMNR
from poisoners.NBTNS import NBTNS
from poisoners.MDNS import MDNS
threads.append(Thread(target=serve_LLMNR_poisoner, args=('', 5355, LLMNR,)))
threads.append(Thread(target=serve_MDNS_poisoner, args=('', 5353, MDNS,)))
threads.append(Thread(target=serve_NBTNS_poisoner, args=('', 137, NBTNS,)))
# Load Browser Listener
from servers.Browser import Browser
threads.append(Thread(target=serve_thread_udp_broadcast, args=('', 138, Browser,)))
if settings.Config.HTTP_On_Off:
from servers.HTTP import HTTP
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 80, HTTP,)))
if settings.Config.WinRM_On_Off:
from servers.WinRM import WinRM
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 5985, WinRM,)))
if settings.Config.WinRM_On_Off:
from servers.WinRM import WinRM
threads.append(Thread(target=serve_thread_SSL, args=(settings.Config.Bind_To, 5986, WinRM,)))
if settings.Config.SSL_On_Off:
from servers.HTTP import HTTP
threads.append(Thread(target=serve_thread_SSL, args=(settings.Config.Bind_To, 443, HTTP,)))
if settings.Config.RDP_On_Off:
from servers.RDP import RDP
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 3389, RDP,)))
if settings.Config.DCERPC_On_Off:
from servers.RPC import RPCMap, RPCMapper
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 135, RPCMap,)))
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, settings.Config.RPCPort, RPCMapper,)))
if settings.Config.WPAD_On_Off:
from servers.HTTP_Proxy import HTTP_Proxy
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 3141, HTTP_Proxy,)))
if settings.Config.ProxyAuth_On_Off:
from servers.Proxy_Auth import Proxy_Auth
threads.append(Thread(target=serve_thread_tcp_auth, args=(settings.Config.Bind_To, 3128, Proxy_Auth,)))
if settings.Config.SMB_On_Off:
if settings.Config.LM_On_Off:
from servers.SMB import SMB1LM
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 445, SMB1LM,)))
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 139, SMB1LM,)))
else:
from servers.SMB import SMB1
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 445, SMB1,)))
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 139, SMB1,)))
if settings.Config.Krb_On_Off:
from servers.Kerberos import KerbTCP, KerbUDP
threads.append(Thread(target=serve_thread_udp, args=('', 88, KerbUDP,)))
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 88, KerbTCP,)))
if settings.Config.SQL_On_Off:
from servers.MSSQL import MSSQL, MSSQLBrowser
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 1433, MSSQL,)))
threads.append(Thread(target=serve_thread_udp_broadcast, args=(settings.Config.Bind_To, 1434, MSSQLBrowser,)))
if settings.Config.FTP_On_Off:
from servers.FTP import FTP
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 21, FTP,)))
if settings.Config.POP_On_Off:
from servers.POP3 import POP3
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 110, POP3,)))
if settings.Config.LDAP_On_Off:
from servers.LDAP import LDAP, CLDAP
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 389, LDAP,)))
threads.append(Thread(target=serve_thread_udp, args=('', 389, CLDAP,)))
if settings.Config.SMTP_On_Off:
from servers.SMTP import ESMTP
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 25, ESMTP,)))
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 587, ESMTP,)))
if settings.Config.IMAP_On_Off:
from servers.IMAP import IMAP
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 143, IMAP,)))
if settings.Config.DNS_On_Off:
from servers.DNS import DNS, DNSTCP
threads.append(Thread(target=serve_thread_udp, args=('', 53, DNS,)))
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 53, DNSTCP,)))
for thread in threads:
thread.daemon = True
thread.start()
if settings.Config.AnalyzeMode:
reporter.print_info("Responder is in analyze mode. No NBT-NS, LLMNR, MDNS requests will be poisoned.")
if settings.Config.DHCP_On_Off:
from poisoners.DHCP import DHCP
DHCP(settings.Config.DHCP_DNS)
while True:
time.sleep(1)
except KeyboardInterrupt:
sys.exit("\r%s Exiting..." % color('[+]', 2, 1))
if __name__ == '__main__':
main()
ThreadingTCPServer.address_family = socket.AF_INET6
+2 -2
View File
@@ -1260,9 +1260,9 @@ class SMBTransRAPData(Packet):
def calculate(self):
#Padding
if len(str(self.fields["Data"]))%2==0:
self.fields["PipeTerminator"] = "\x00\x00\x00\x00"
self.fields["PipeTerminator"] = "\x00\x00\x00\x00"
else:
self.fields["PipeTerminator"] = "\x00\x00\x00"
self.fields["PipeTerminator"] = "\x00\x00\x00"
##Convert Path to Unicode first before any Len calc.
self.fields["PipeName"] = self.fields["PipeName"].encode('utf-16le').decode('latin-1')
##Data Len
+48 -20
View File
@@ -133,7 +133,7 @@ class Settings:
self.ProxyAuth_On_Off = options.ProxyAuth_On_Off
self.CommandLine = str(sys.argv)
self.Bind_To = utils.FindLocalIP(self.Interface, self.OURIP)
self.Bind_To6 = utils.FindLocalIP6(self.Interface, self.OURIP)
self.Bind_To6 = utils.FindLocalIP(self.Interface, self.OURIP, socket.AF_INET6)
self.DHCP_DNS = options.DHCP_DNS
self.ExternalIP6 = options.ExternalIP6
@@ -277,34 +277,62 @@ class Settings:
self.AnalyzeLogger = logging.getLogger('Analyze Log')
self.AnalyzeLogger.addHandler(ALog_Handler)
# the certs folder is not even included in this copy of Responder so it should be skipped
# First time Responder run?
if os.path.isfile(self.ResponderPATH+'/Responder.db'):
pass
else:
# if os.path.isfile(self.ResponderPATH+'/Responder.db'):
# pass
# else:
#If it's the first time, generate SSL certs for this Responder session and send openssl output to /dev/null
Certs = os.system("./certs/gen-self-signed-cert.sh >/dev/null 2>&1")
# Certs = os.system("./certs/gen-self-signed-cert.sh >/dev/null 2>&1")
try:
NetworkCard = subprocess.check_output(["ifconfig", "-a"])
except:
if sys.platform == "win32":
try:
NetworkCard = subprocess.check_output(["ip", "address", "show"])
except subprocess.CalledProcessError as ex:
NetworkCard = "Error fetching Network Interfaces:", ex
NetworkCard = subprocess.check_output(["ipconfig"])
except Exception as e:
NetworkCard = "Error fetching Network Interfaces:", str(e)
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"])
DNS = subprocess.check_output(["ipconfig", "/all"])
except subprocess.CalledProcessError as ex:
DNS = "Error fetching DNS configuration:", ex
pass
except Exception as e:
DNS = "Error fetching Network Interfaces:", str(e)
pass
try:
RoutingInfo = subprocess.check_output(["route", "print"])
except subprocess.CalledProcessError as ex:
RoutingInfo = "Error fetching Routing information:", ex
pass
except Exception as e:
RoutingInfo = "Error fetching Network Interfaces:", str(e)
pass
else:
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
except Exception as e:
NetworkCard = "Error fetching Network Interfaces:", str(e)
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 = "%s\nCurrent environment is:\nNetwork Config:\n%s\nDNS Settings:\n%s\nRouting info:\n%s\n\n"%(utils.HTTPCurrentDate(), NetworkCard.decode('latin-1'),DNS.decode('latin-1'),RoutingInfo.decode('latin-1'))
try:
+21 -299
View File
@@ -19,33 +19,18 @@ import sys
import re
import logging
import socket
import time
from coercer.structures import EscapeCodes
from . import settings
import datetime
import codecs
import struct
import random
try:
import netifaces
except:
sys.exit('You need to install python-netifaces or run Responder with python3...\nTry "apt-get install python-netifaces" or "pip install netifaces"')
from calendar import timegm
import psutil
from coercer.core.Reporter import reporter
def if_nametoindex2(name):
if settings.Config.PY2OR3 == "PY2":
import ctypes
import ctypes.util
libc = ctypes.CDLL(ctypes.util.find_library('c'))
ret = libc.if_nametoindex(name)
return ret
else:
return socket.if_nametoindex(settings.Config.Interface)
def RandomChallenge():
if settings.Config.PY2OR3 == "PY3":
if settings.Config.NumChal == "random":
@@ -103,39 +88,6 @@ def text(txt):
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:
reporter.print_info("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.PY2OR3 == "PY2":
if settings.Config.ExternalIP:
@@ -191,71 +143,26 @@ def IsIPv6IP(IP):
else:
return False
def FindLocalIP(Iface, OURIP):
def FindLocalIP(Iface, OURIP, family=socket.AF_INET):
if family != socket.AF_INET and family != socket.AF_INET6:
raise ValueError("Provided family must either be AF_INET or AF_INET6")
if Iface == 'ALL':
return '0.0.0.0'
try:
if IsOsX():
return OURIP
elif IsIPv6IP(OURIP):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, 25, str(Iface+'\0').encode('utf-8'))
s.connect(("127.0.0.1",9))#RFC 863
ret = s.getsockname()[0]
s.close()
return ret
elif IsIPv6IP(OURIP) == False and OURIP != None:
return OURIP
elif OURIP == None:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, 25, str(Iface+'\0').encode('utf-8'))
s.connect(("127.0.0.1",9))#RFC 863
ret = s.getsockname()[0]
s.close()
return ret
except socket.error:
reporter.print_error("Error: %s: Interface not found" % Iface)
sys.exit(-1)
def FindLocalIP6(Iface, OURIP):
if Iface == 'ALL':
return '::'
try:
if IsIPv6IP(OURIP) == False:
try:
#Let's make it random so we don't get spotted easily.
randIP = "2001:" + ":".join(("%x" % random.randint(0, 16**4) for i in range(7)))
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
s.connect((randIP+':80', 1))
IP = s.getsockname()[0]
reporter.print_info("IP is: %s" % IP)
return IP
except:
try:
#Try harder; Let's get the local link addr
IP = str(netifaces.ifaddresses(Iface)[netifaces.AF_INET6][0]["addr"].replace("%"+Iface, ""))
return IP
except:
IP = '::1'
reporter.print_warn("You don't have an IPv6 address assigned.")
return IP
if family == socket.AF_INET:
return '0.0.0.0'
else:
return '::'
if (family == socket.AF_INET and (IsOsX() or (IsIPv6IP(OURIP) == False and OURIP != None))) or (family == socket.AF_INET6 and IsIPv6IP(OURIP)):
return OURIP
except socket.error:
reporter.print_error("Error: %s: Interface not found" % Iface)
sys.exit(-1)
IP = next((addr.address for addr in psutil.net_if_addrs().get(Iface, []) if addr.family == family), None)
if IP is not None:
return IP
else:
reporter.print_warn("You don't have an %s address assigned." % "IPv4" if family == socket.AF_INET else "IPv6")
return "127.0.0.1" if family == socket.AF_INET else "::1"
# Function used to write captured hashs to a file.
def WriteData(outfile, data, user):
@@ -305,17 +212,6 @@ def NetworkRecvBufferPython2or3(data):
else:
return str(data.decode('latin-1'))
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.execute('CREATE TABLE DHCP (timestamp TEXT, MAC TEXT, IP TEXT, RequestedIP TEXT)')
cursor.commit()
cursor.close()
def SaveToDb(result):
for k in [ 'module', 'type', 'client', 'hostname', 'user', 'cleartext', 'hash', 'fullhash' ]:
@@ -399,178 +295,4 @@ def SaveToDb(result):
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] = ''
result['SentToIp'] = result['SentToIp'].replace("::ffff:","")
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 SaveDHCPToDb(result):
for k in [ 'MAC', 'IP', 'RequestedIP']:
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 DHCP WHERE MAC=? AND IP=? AND RequestedIP=?", (result['MAC'], result['IP'], result['RequestedIP']))
(count,) = res.fetchone()
if not count:
cursor.execute("INSERT INTO DHCP VALUES(datetime('now'), ?, ?, ?)", (result['MAC'], result['IP'], result['RequestedIP']))
cursor.commit()
cursor.close()
def Parse_IPV6_Addr(data):
if data[len(data)-4:len(data)] == b'\x00\x1c\x00\x01':
return 'IPv6'
elif data[len(data)-4:len(data)] == b'\x00\x01\x00\x01':
return True
elif data[len(data)-4:len(data)] == b'\x00\xff\x00\x01':
return True
return False
def IsIPv6(data):
if "::ffff:" in data:
return False
else:
return True
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 ''.join(list(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(" To support this project:")
print(" Patreon -> https://www.patreon.com/PythonResponder")
print(" Paypal -> https://paypal.me/PythonResponder")
print('')
print(" Author: Laurent Gaffie (laurent.gaffie@gmail.com)")
print(" To kill this script hit CTRL-C")
print('')
def StartupMessage():
enabled = color('[ON]', 2, 1)
disabled = color('[OFF]', 1, 1)
print('')
print(color("[+] ", 2, 1) + "Poisoners:")
print(' %-27s' % "LLMNR" + (enabled if settings.Config.AnalyzeMode == False else disabled))
print(' %-27s' % "NBT-NS" + (enabled if settings.Config.AnalyzeMode == False else disabled))
print(' %-27s' % "MDNS" + (enabled if settings.Config.AnalyzeMode == False else disabled))
print(' %-27s' % "DNS" + enabled)
print(' %-27s' % "DHCP" + (enabled if settings.Config.DHCP_On_Off else disabled))
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(' %-27s' % "RDP server" + (enabled if settings.Config.RDP_On_Off else disabled))
print(' %-27s' % "DCE-RPC server" + (enabled if settings.Config.DCERPC_On_Off else disabled))
print(' %-27s' % "WinRM server" + (enabled if settings.Config.WinRM_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' % "Force ESS downgrade" + (enabled if settings.Config.NOESS_On_Off == True or settings.Config.LM_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' % "Responder IPv6" + color('[%s]' % settings.Config.Bind_To6, 5, 1))
if settings.Config.ExternalIP:
print(' %-27s' % "Responder external IP" + color('[%s]' % settings.Config.ExternalIP, 5, 1))
if settings.Config.ExternalIP6:
print(' %-27s' % "Responder external IPv6" + color('[%s]' % settings.Config.ExternalIP6, 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('')
print(color("[+] ", 2, 1) + "Current Session Variables:")
print(' %-27s' % "Responder Machine Name" + color('[%s]' % settings.Config.MachineName, 5, 1))
print(' %-27s' % "Responder Domain Name" + color('[%s]' % settings.Config.DomainName, 5, 1))
print(' %-27s' % "Responder DCE-RPC Port " + color('[%s]' % settings.Config.RPCPort, 5, 1))
cursor.close()
+7 -9
View File
@@ -36,7 +36,7 @@ ResponderOptions = namedtuple(
)
def create_smb_server(control_structure, listen_ip, interface, lock):
def create_smb_server(control_structure, listen_ip, listen_port, interface, lock, verbose=False):
"""Factory function for creating a SMBServer object"""
def record_result(result):
@@ -69,6 +69,7 @@ def create_smb_server(control_structure, listen_ip, interface, lock):
settings.init()
responder_options.update(dict(ExternalIP=listen_ip, OURIP=listen_ip))
responder_options.update(dict(Interface=interface))
responder_options.update(dict(Verbose=verbose))
options = ResponderOptions(*responder_options.values())
settings.Config.populate(options)
from coercer.ext.responder import SMB
@@ -82,7 +83,8 @@ def create_smb_server(control_structure, listen_ip, interface, lock):
def run(self_):
# FIXME I wanted to bind to listen_ip, but that allows yields:
# 'Address family for hostname not supported'
self_.server = Responder.ThreadingTCPServer(('', 445), SMB.SMB1)
self_.server = Responder.ThreadingTCPServer(('', listen_port), SMB.SMB1)
self_.server.allow_reuse_address = True
self_.server.serve_forever()
@@ -104,11 +106,7 @@ class Listener(object):
super(Listener, self).__init__()
self.options = options
if self.options.mode in ["fuzz", "scan"]:
self.smb_port = self.options.smb_port
elif self.options.mode in ["coerce"]:
self.smb_port = self.options.smb_port
self.smb_port = 4445 if options.redirecting_smb_packets else self.options.smb_port
self.timeout = 1
self.listen_ip = "0.0.0.0"
@@ -124,8 +122,8 @@ class Listener(object):
Function start_smb(self, control_structure)
"""
lock = threading.Lock()
smb_server = create_smb_server(control_structure, self.listen_ip,
self.options.interface or 'ALL', lock)
smb_server = create_smb_server(control_structure, self.listen_ip, self.smb_port,
self.options.interface or 'ALL', lock, self.options.verbose)
smb_server.start()
lock.acquire(timeout=self.timeout)
smb_server.shutdown()
+13 -19
View File
@@ -9,30 +9,14 @@ import sys
import struct
from platform import uname
import psutil
from coercer.core.Reporter import reporter
def get_ip_address_of_interface(ifname):
"""
Function get_ip_address_of_interface(ifname)
"""
if sys.platform == "win32":
return None
elif sys.platform == "linux" and "microsoft" not in uname().release.lower() and "microsoft" not in uname().version.lower():
import fcntl
if type(ifname) == str:
ifname = bytes(ifname, "utf-8")
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
SIOCGIFADDR = 0x8915
try:
ifname = struct.pack('256s', ifname[:15])
a = fcntl.ioctl(s.fileno(), SIOCGIFADDR, ifname)[20:24]
return socket.inet_ntoa(a)
except OSError as e:
return None
else:
return None
return next(iter([addr.address for addr in psutil.net_if_addrs().get(ifname, []) if addr.family == socket.AF_INET]), None)
def get_ip_address_to_target_remote_host(host, port):
@@ -76,7 +60,7 @@ def get_ip_addr_to_listen_on(target, options):
reporter.print_error("Could not get IP address of interface '%s'" % options.interface)
else:
# Getting ip address of interface that can access remote target
possible_ports, k = [445, 139, 88], 0
possible_ports, k = [4445 if options.redirecting_smb_packets else options.smb_port, 139, 88], 0
while listening_ip is None and k < len(possible_ports):
listening_ip = get_ip_address_to_target_remote_host(target, possible_ports[k])
k += 1
@@ -102,3 +86,13 @@ def get_next_http_listener_port(current_value, listen_ip, options):
current_value = options.min_http_port + ((current_value + 1) % port_window)
return current_value
def redirect_smb_packets():
import pydivert
with pydivert.WinDivert("tcp.DstPort == 445 or tcp.SrcPort == 4445") as w:
for packet in w:
if packet.dst_port == 445 and packet.is_inbound:
packet.dst_port = 4445
if packet.src_port == 4445 and packet.is_outbound:
packet.src_port = 445
w.send(packet)
+1 -1
View File
@@ -12,4 +12,4 @@ class TransportType(Enum):
Enum class TransportType
"""
NCACN_IP_TCP = "DCERPC port"
NCAN_NP = "SMB named pipe"
NCAN_NP = "SMB named pipe"
+272
View File
@@ -0,0 +1,272 @@
# Coercer Installer
$PythonVersion = '3.13.0'
$StartingDirectory = Get-Location
$PythonInstallerPath = Join-Path -Path $Env:TEMP -ChildPath "python-$PythonVersion.exe"
$RepositoryArchivePath = Join-Path -Path $Env:TEMP -ChildPath "coercer.zip"
$RepositoryFolderPath = Join-Path -Path $Env:TEMP -ChildPath "coercer-windows-support"
$MachinePythonKey = "HKLM:\Software\Python\PythonCore"
$UserPythonKey = "HKCU:\Software\Python\PythonCore"
$FoundPython = $False
$PythonVersionParts = $PythonVersion.Split(".")
$TruncatedPythonVersion = "$($PythonVersionParts[0]).$($PythonVersionParts[1])"
$BuildToolsKey = 'HKLM:\Software\Microsoft\VisualStudio'
$BuildToolsMinVersion = '14.0'
$Options = New-object System.Collections.Hashtable
$Options['OutputDir'] = @{
Name = 'Output Directory'
Desc = 'Set the output directory for the built script'
Keywords = @('-o', '--output-dir')
Value = $StartingDirectory
Type = 'Path'
}
$Flags = New-object System.Collections.Hashtable
$Flags['OverridePython'] = @{
Name = 'Override Installed Python'
Desc = "Install Python $PythonVersion even if an existing python version is installed"
Keywords = @('-P', '--override-python')
Value = $False
}
$Flags['LeavePython'] = @{
Name = 'Leave Installed Python'
Desc = "If installed, do not uninstall Python $PythonVersion from the system"
Keywords = @('-L', '--leave-python')
Value = $False
}
$Flags['InstallSystemWide'] = @{
Name = 'Install Script System-Wide'
Desc = 'Install script to C:\Program Files\ and add them to the PATH (Ignores Output Directory)'
Keywords = @('-I', '--install-systemwide')
Value = $False
}
function GetKeyByKeyword {
param (
[hashtable]$HashTable,
[string]$Keyword
)
foreach ($Key in $HashTable.Keys) {
$Item = $HashTable[$Key]
if ($Item.Keywords -contains $Keyword) {
return $Key
}
}
return $Null
}
$HelpMenuPadding = 25
function Show-HelpMenu {
Write-Host '=== Coercer Installer ==='
Write-Host 'Downloads, builds, and installs scripts from the Coercer repository'
Write-Host ''
Write-Host 'Usage: installer.ps1 [FLAGS] [OPTIONS]'
Write-Host ''
Write-Host 'Flags:'
foreach ($Flag in $Flags.Values) {
$FormattedKeywords = $Flag['Keywords'] -join ' '
Write-Host " $($FormattedKeywords.PadRight($HelpMenuPadding)) $($Flag['Desc'])"
}
Write-Host ''
Write-Host 'Options:'
Write-Host " $('-h --help'.PadRight($HelpMenuPadding)) Display this menu"
foreach ($Option in $Options.Values) {
$FormattedKeywords = $Option['Keywords'] -join ' '
Write-Host " $($FormattedKeywords.PadRight($HelpMenuPadding)) $($Option['Desc']) (default: $($Option['Value']))"
}
Write-Host ''
}
for ($I = 0; $I -lt $Args.Count; $I++) {
if ($Args[$I] -eq '-h' -or $Args[$I] -eq '--help') {
Show-HelpMenu
exit 0
}
elseif ($Args[$I].startsWith('-')) {
$ArgParts = $Args[$I] -split '='
$Keyword = $ArgParts[0]
$Value = $Null
$FlagsKey = GetKeyByKeyword -HashTable $Flags -Keyword $Keyword
$OptionsKey = GetKeyByKeyword -HashTable $Options -Keyword $Keyword
if ($ArgParts.Count -eq 2) {
$Value = $ArgParts[1]
}
elseif ($ArgParts.Count -gt 1) {
throw "Error in $($Options[$OptionsKey]['Name']): Multiple equals signs (Use -h or --help for help)"
}
if ($FlagsKey) {
$Flags[$FlagsKey]['Value'] = $True
}
elseif ($OptionsKey) {
if (-not $Value) {
$I++
$Value = $Args[$I]
}
if (-not $Value) {
throw "Error in $($Options[$OptionsKey]['Name']): No value recieved (Use -h or --help for help)"
}
if ($Options[$OptionsKey]['type'] -eq 'Path' -and -not (Test-Path $Value)) {
throw "Error in $($Options[$OptionsKey]['Name']): Path does not exist (Use -h or --help for help)"
}
$Options[$OptionsKey]['Value'] = $Value
}
else {
throw "Error: Unrecognized argument (Use -h or --help for help)"
}
}
}
# Check Local Machine Registry
if (Test-Path $MachinePythonKey) {
Get-ChildItem $MachinePythonKey | ForEach-Object {
if ($_.PSChildName -eq $TruncatedPythonVersion) {
$FoundPython = $True
Write-Host "Python $($_.PSChildName) found in Local Machine"
}
}
}
# Check Current User Registry
if (Test-Path $UserPythonKey) {
Get-ChildItem $UserPythonKey | ForEach-Object {
if ($_.PSChildName -eq $TruncatedPythonVersion) {
$FoundPython = $True
Write-Host "Python $($_.PSChildName) found in Current User"
}
}
}
# Download and install Python
if (-not $FoundPython -or $Flags['OverridePython']['Value']) {
Write-Host "Python $PythonVersion is not installed, installing now..."
Invoke-WebRequest -Uri "https://www.python.org/ftp/python/$PythonVersion/python-$PythonVersion-amd64.exe" -OutFile $PythonInstallerPath
Start-Process $PythonInstallerPath -ArgumentList "/quiet PrependPath=1 Include_launcher=0" -Wait
# Refresh PATH
$Env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
}
# Check for vaild build tools installed
Write-Host 'Checking build tools install...'
$VersionPattern = "^\d+\.\d+"
$VersionKeys = Get-ChildItem -Path $BuildToolsKey | Where-Object { $_.PSChildName -match $versionPattern }
$FoundValidBuildTools = $False
foreach ($version in $versionKeys) {
if ($FoundValidBuildTools) { break }
try {
$versionNumber = [version]$version.PSChildName
if ($versionNumber -lt [version]$BuildToolsMinVersion) {
continue
}
$runtimePath = "$($version.PSPath)\VC\Runtimes\debug\X64"
if (Test-Path $runtimePath) {
$FoundValidBuildTools = $True
}
}
catch {}
}
if (-not $FoundValidBuildTools) {
Write-Host 'Microsoft C++ Build Tools not found, version 14.0+ is required, installing...'
try {
$BuildToolsPath = Join-Path $env:TEMP 'buildtools.exe'
Invoke-WebRequest -Uri 'https://aka.ms/vs/17/release/vs_BuildTools.exe' -OutFile $BuildToolsPath
$BuildArgs = '--quiet --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended'
Start-Process $BuildToolsPath -ArgumentList $BuildArgs -Wait
}
catch {
throw 'Error installing build tools, download it manually (https://aka.ms/vs/17/release/vs_BuildTools.exe)'
}
}
# Download and unzip repository
Write-Host 'Downloading repository...'
Invoke-WebRequest -Uri "https://github.com/p0dalirius/coercer/archive/refs/heads/master.zip" -OutFile $RepositoryArchivePath
Expand-Archive -Path $RepositoryArchivePath -DestinationPath $Env:TEMP -Force
Remove-Item $RepositoryArchivePath
# Begin build process
Write-Host 'Beginning build process...'
Set-Location -Path $RepositoryFolderPath
try {
# Create and activate virtual environment
python -m venv .venv
.venv\Scripts\Activate.ps1
pip install pyinstaller
# Setup
pip install -r requirements.txt
python setup.py install
Write-Host "Building..."
$Arguments = @('--onefile', '--collect-all', 'impacket', '--add-data', 'coercer;coercer')
pyinstaller $Arguments "Coercer.py"
$BuiltScriptPath = Join-Path -Path $RepositoryFolderPath -ChildPath "dist\Coercer.exe"
if ($Flags['InstallSystemWide']['Value']) {
# Prepare destination folder
Write-Host 'Copying executable to Program Files...'
New-Item -ItemType Directory -Path 'C:\Program Files\Coercer' -Force
# Copy built executable into program files
Copy-Item -Path $BuiltScriptPath -Destination 'C:\Program Files\Coercer' -Force
}
else {
Copy-Item -Path $BuiltScriptPath -Destination $Options['OutputDir']['Value'] -Force
}
if ($Flags['InstallSystemWide']['Value']) {
# Get the current PATH environment variable
Write-Host "Updating PATH..."
$CurrentPath = [System.Environment]::GetEnvironmentVariable('Path', [System.EnvironmentVariableTarget]::Machine)
# Check if the path already exists in PATH
if ($CurrentPath -notlike "*C:\Program Files\Coercer*") {
# Append the new path to the existing PATH variable
$NewPath = $CurrentPath + ';' + 'C:\Program Files\Coercer'
# Set the new PATH variable
[System.Environment]::SetEnvironmentVariable('Path', $NewPath, [System.EnvironmentVariableTarget]::Machine)
Write-Host 'Successfully added C:\Program Files\Coercer to PATH.'
}
else {
Write-Host 'C:\Program Files\Coercer is already in PATH.'
}
}
}
catch {
Write-Error 'Build Failed. Make sure you have Microsoft Visual Studio C++ Build Tools installed (Check MSVC, Windows 11 SDK)'
Write-Error "$($_.Exception.Message)"
}
Write-Host 'Cleaning up...'
deactivate
Set-Location -Path $StartingDirectory
Remove-Item -Recurse -Force $RepositoryFolderPath
if (-not $Flags['LeavePython']['Value'] -and (-not $FoundPython -or $Flags['OverridePython']['Value'])) {
Write-Host 'Uninstalling Python...'
Start-Process $PythonInstallerPath -ArgumentList "/uninstall /quiet PrependPath=1" -Wait
}
Write-Host 'Done!'
+2
View File
@@ -3,3 +3,5 @@ xlsxwriter
jinja2
sectools
netifaces
psutil
pydivert; sys_platform == "win32"