mirror of
https://github.com/p0dalirius/Coercer
synced 2026-08-09 13:01:12 +00:00
[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:
@@ -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:
|
||||
|
||||
+16
-6
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.platform == "win32":
|
||||
self.socket.bind(settings.Config.OURIP)
|
||||
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
|
||||
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()
|
||||
|
||||
@@ -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,13 +277,38 @@ 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'):
|
||||
# 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")
|
||||
|
||||
if sys.platform == "win32":
|
||||
try:
|
||||
NetworkCard = subprocess.check_output(["ipconfig"])
|
||||
except Exception as e:
|
||||
NetworkCard = "Error fetching Network Interfaces:", str(e)
|
||||
pass
|
||||
try:
|
||||
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:
|
||||
#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")
|
||||
|
||||
try:
|
||||
NetworkCard = subprocess.check_output(["ifconfig", "-a"])
|
||||
except:
|
||||
@@ -292,6 +317,9 @@ class Settings:
|
||||
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:
|
||||
|
||||
+15
-293
@@ -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':
|
||||
if family == socket.AF_INET:
|
||||
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':
|
||||
else:
|
||||
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
|
||||
|
||||
else:
|
||||
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' ]:
|
||||
@@ -400,177 +296,3 @@ def SaveToDb(result):
|
||||
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))
|
||||
|
||||
|
||||
@@ -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
@@ -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)
|
||||
+272
@@ -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!'
|
||||
@@ -3,3 +3,5 @@ xlsxwriter
|
||||
jinja2
|
||||
sectools
|
||||
netifaces
|
||||
psutil
|
||||
pydivert; sys_platform == "win32"
|
||||
Reference in New Issue
Block a user