Repository restructuring
This commit is contained in:
12
__init__.py
12
__init__.py
@@ -1,12 +0,0 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
__doc__ = __doc__ or ""
|
||||
__all__ = [
|
||||
"util", "fileserver", "xss_handler", "rev_shell",
|
||||
"xp_cmdshell", "dnsserver", "sqli", "smtpserver",
|
||||
"upload_file", "pcap_file_extract"
|
||||
]
|
||||
|
||||
inc_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
sys.path.append(inc_dir)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -125,6 +125,7 @@ TIP_DOCKER_ROOTLESS="In rootless mode privilege escalation to root will not be p
|
||||
TIP_CVE_2019_5021="Alpine linux version 3.3.x-3.5.x accidentally allow users to login as root with a blank password, if we have command execution in the container we can become root using su root"
|
||||
TIP_CVE_2019_13139="Docker versions before 18.09.4 are vulnerable to a command execution vulnerability when parsing URLs"
|
||||
TIP_CVE_2019_5736="Docker versions before 18.09.2 are vulnerable to a container escape by overwriting the runC binary"
|
||||
TIP_CVE_2025_9074="Docker Desktop versions between 4.25 to 4.44.2 on Windows and MacOS are vulnerable to a container escape via a malicious image. See https://github.com/PtechAmanja/CVE-2025-9074-Docker-Desktop-Container-Escape"
|
||||
|
||||
TIP_SYS_MODULE="Giving the container the SYS_MODULE privilege allows for kernel modules to be mounted. Using this, a malicious module can be used to execute code as root on the host."
|
||||
|
||||
@@ -378,7 +379,7 @@ userCheck() {
|
||||
groups=$(groups| sed "s/\($DANGEROUS_GROUPS\)/${LG}${EX}&${NC}${DG}/g")
|
||||
printStatus "$groups" "None"
|
||||
|
||||
if ! [ $isUserRoot ]; then
|
||||
if ! [ "$isUserRoot" ]; then
|
||||
printQuestion "Sudo ...................."
|
||||
if [ -x "$(command -v sudo)" ]; then
|
||||
if sudo -n -l 2>/dev/null; then
|
||||
@@ -631,7 +632,7 @@ containerPrivileges() {
|
||||
fi
|
||||
}
|
||||
|
||||
containerExploits() {
|
||||
containerExploitAlpine() {
|
||||
# If we are on an alpine linux disto check for CVE–2019–5021
|
||||
if [ -f "/etc/alpine-release" ]; then
|
||||
alpineVersion=$(cat /etc/alpine-release)
|
||||
@@ -648,6 +649,62 @@ containerExploits() {
|
||||
fi
|
||||
}
|
||||
|
||||
containerExploitAPI() {
|
||||
# Check if docker api is exposed (including CVE-2025-9074)
|
||||
api_available="0"
|
||||
api_host=""
|
||||
api_hosts="192.168.65.7:2375 172.17.0.1:2375"
|
||||
|
||||
printQuestion "Docker API exposed ......"
|
||||
|
||||
if [ -x "$(command -v curl)" ] || [ -x "$(command -v wget)" ]; then
|
||||
for host in $api_hosts; do
|
||||
if [ -x "$(command -v curl)" ]; then
|
||||
if curl -s --connect-timeout 1 "http://$host/version" >/dev/null 2>&1; then
|
||||
api_available="1"
|
||||
api_host="$host"
|
||||
break
|
||||
fi
|
||||
else
|
||||
if wget -O - "http://$host/version" --connect-timeout=1 --tries=1 -q >/dev/null 2>&1; then
|
||||
api_available="1"
|
||||
api_host="$host"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$api_available" = "0" ]; then
|
||||
printNo
|
||||
return
|
||||
fi
|
||||
|
||||
printSuccess "Yes ($api_host)"
|
||||
printQuestion "└── CVE-2025-9074 ......."
|
||||
|
||||
if [ -x "$(command -v curl)" ]; then
|
||||
if curl -s --connect-timeout 1 "http://$api_host/containers/json" >/dev/null 2>&1; then
|
||||
printYesEx
|
||||
printTip "$TIP_CVE_2025_9074"
|
||||
else
|
||||
printNo
|
||||
fi
|
||||
elif wget -O - "http://$api_host/containers/json" --connect-timeout=1 --tries=1 -q >/dev/null 2>&1; then
|
||||
printYesEx
|
||||
printTip "$TIP_CVE_2025_9074"
|
||||
else
|
||||
printNo
|
||||
fi
|
||||
else
|
||||
printError "Unknown (curl/wget not installed)"
|
||||
fi
|
||||
}
|
||||
|
||||
containerExploits() {
|
||||
containerExploitAlpine
|
||||
containerExploitAPI
|
||||
}
|
||||
|
||||
enumerateContainers() {
|
||||
printSection "Enumerating Containers"
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# Copyright (c) 2016-2023, https://github.com/mzet-
|
||||
# Copyright (c) 2016-2026, https://github.com/mzet-
|
||||
#
|
||||
# linux-exploit-suggester.sh comes with ABSOLUTELY NO WARRANTY.
|
||||
# This is free software, and you are welcome to redistribute it
|
||||
@@ -9,7 +9,7 @@
|
||||
# file for usage of this software.
|
||||
#
|
||||
|
||||
VERSION=v1.1
|
||||
VERSION=v1.2
|
||||
|
||||
# bash colors
|
||||
#txtred="\e[0;31m"
|
||||
@@ -852,6 +852,18 @@ author: wbowling (orginal exploit author); bcoles (author of exploit update at '
|
||||
EOF
|
||||
)
|
||||
|
||||
EXPLOITS[((n++))]=$(cat <<EOF
|
||||
Name: ${txtgrn}[CVE-2018-14634]${txtrst} Mutagen Astronomy
|
||||
Reqs: pkg=linux-kernel,x86_64,ver>=4.14.1,ver<=4.14.54
|
||||
Tags: debian=8,RHEL=6|7
|
||||
Rank: 1
|
||||
analysis-url: https://www.qualys.com/2018/09/25/cve-2018-14634/mutagen-astronomy-integer-overflow-linux-create_elf_tables-cve-2018-14634.txt
|
||||
exploit-db: 45516
|
||||
Comments: systems with less than 32GB of RAM are unlikely to be affected by this issue
|
||||
author: Qualys
|
||||
EOF
|
||||
)
|
||||
|
||||
EXPLOITS[((n++))]=$(cat <<EOF
|
||||
Name: ${txtgrn}[CVE-2018-18955]${txtrst} subuid_shell
|
||||
Reqs: pkg=linux-kernel,ver>=4.15,ver<=4.19.2,CONFIG_USER_NS=y,sysctl:kernel.unprivileged_userns_clone==1,cmd:[ -u /usr/bin/newuidmap ],cmd:[ -u /usr/bin/newgidmap ]
|
||||
@@ -916,6 +928,18 @@ author: chompie1337
|
||||
EOF
|
||||
)
|
||||
|
||||
EXPLOITS[((n++))]=$(cat <<EOF
|
||||
Name: ${txtgrn}[CVE-2021-3493]${txtrst} Ubuntu OverlayFS
|
||||
Reqs: pkg=linux-kernel,ver>=3.13,ver<5.14,x86_64
|
||||
Tags: ubuntu=(14.04|16.04|18.04|20.04|20.10)
|
||||
Rank: 1
|
||||
analysis-url: https://ssd-disclosure.com/ssd-advisory-overlayfs-pe/
|
||||
src-url: https://raw.githubusercontent.com/briskets/CVE-2021-3493/refs/heads/main/exploit.c
|
||||
Comments: Only Ubuntu is affected.
|
||||
author: ssd-disclosure
|
||||
EOF
|
||||
)
|
||||
|
||||
EXPLOITS[((n++))]=$(cat <<EOF
|
||||
Name: ${txtgrn}[CVE-2021-22555]${txtrst} Netfilter heap out-of-bounds write
|
||||
Reqs: pkg=linux-kernel,ver>=2.6.19,ver<=5.12-rc6
|
||||
@@ -937,11 +961,25 @@ Tags: ubuntu=(20.04|21.04),debian=11
|
||||
Rank: 1
|
||||
analysis-url: https://dirtypipe.cm4all.com/
|
||||
src-url: https://haxx.in/files/dirtypipez.c
|
||||
bof-url: https://raw.githubusercontent.com/The-Z-Labs/bof-launcher/refs/heads/main/bofs/src/dirtypipe.zig
|
||||
Comments: BOF version o the exploit available to be run with bof-launcher.
|
||||
exploit-db: 50808
|
||||
author: blasty (original exploit author: Max Kellermann)
|
||||
EOF
|
||||
)
|
||||
|
||||
EXPLOITS[((n++))]=$(cat <<EOF
|
||||
Name: ${txtgrn}[CVE-2022-0995]${txtrst} watch_queue
|
||||
Reqs: pkg=linux-kernel,ver>=5.8,ver<5.16.5,x86_64
|
||||
Tags: ubuntu=21.10{kernel:5.13.0.37-generic}
|
||||
Rank: 1
|
||||
analysis-url: https://github.com/Bonfee/CVE-2022-0995
|
||||
src-url: https://github.com/Bonfee/CVE-2022-0995/archive/refs/heads/main.zip
|
||||
Comments: Not 100% reliable, may need to be run a couple of times. It rare cases it may panic the kernel.
|
||||
author: Bonfee (vulnerability discovery and PoC: Jann Horn)
|
||||
EOF
|
||||
)
|
||||
|
||||
EXPLOITS[((n++))]=$(cat <<EOF
|
||||
Name: ${txtgrn}[CVE-2022-2586]${txtrst} nft_object UAF
|
||||
Reqs: pkg=linux-kernel,ver>=3.16,CONFIG_USER_NS=y,sysctl:kernel.unprivileged_userns_clone==1
|
||||
@@ -967,6 +1005,30 @@ author: vulnerability discovery: EDG Team from NCC Group; Author of this exploit
|
||||
EOF
|
||||
)
|
||||
|
||||
EXPLOITS[((n++))]=$(cat <<EOF
|
||||
Name: ${txtgrn}[CVE-2023-0386]${txtrst} OverlayFS suid smuggle
|
||||
Reqs: pkg=linux-kernel,ver>=5.11,ver<=6.2,CONFIG_USER_NS=y,sysctl:kernel.unprivileged_userns_clone==1
|
||||
Tags: ubuntu=22.04.1{kernel:5.15.0-57-generic}
|
||||
Rank: 1
|
||||
analysis-url: https://securitylabs.datadoghq.com/articles/overlayfs-cve-2023-0386/
|
||||
src-url: https://github.com/xkaneiki/CVE-2023-0386/archive/refs/heads/main.zip
|
||||
Comments: CONFIG_USER_NS needs to be enabled && kernel.unprivileged_userns_clone=1 required
|
||||
author: vuln discovery: Miklos Szeredi; exploit author: xkaneiki
|
||||
EOF
|
||||
)
|
||||
|
||||
EXPLOITS[((n++))]=$(cat <<EOF
|
||||
Name: ${txtgrn}[CVE-2024-1086]${txtrst} double-free in nf_tables
|
||||
Reqs: pkg=linux-kernel,x86_64,ver>=5.14,ver<=6.6,CONFIG_NF_TABLES=y,CONFIG_USER_NS=y,sysctl:kernel.unprivileged_userns_clone==1
|
||||
Tags: debian=12,ubuntu=22.04
|
||||
Rank: 1
|
||||
analysis-url: https://pwning.tech/nftables/
|
||||
src-url: https://github.com/Notselwyn/CVE-2024-1086/archive/refs/heads/main.zip
|
||||
Comments: CONFIG_USER_NS and CONFIG_NF_TABLES need to be enabled && kernel.unprivileged_userns_clone=1 required
|
||||
author: notselwyn
|
||||
EOF
|
||||
)
|
||||
|
||||
|
||||
############ USERSPACE EXPLOITS ###########################
|
||||
n=0
|
||||
@@ -1539,6 +1601,17 @@ author: berdav
|
||||
EOF
|
||||
)
|
||||
|
||||
EXPLOITS_USERSPACE[((n++))]=$(cat <<EOF
|
||||
Name: ${txtgrn}[CVE-2025-32463]${txtrst} sudo-chwoot
|
||||
Reqs: pkg=sudo,ver>=1.9.14,ver<=1.9.17
|
||||
Tags: ubuntu=24.04.1,fedora=41
|
||||
Rank: 1
|
||||
analysis-url: https://www.stratascale.com/resource/cve-2025-32463-sudo-chroot-elevation-of-privilege/
|
||||
src-url: https://github.com/mirchr/CVE-2025-32463-sudo-chwoot/archive/refs/heads/main.zip
|
||||
author: Rich Mirch
|
||||
EOF
|
||||
)
|
||||
|
||||
###########################################################
|
||||
## security related HW/kernel features
|
||||
###########################################################
|
||||
@@ -1828,11 +1901,11 @@ EOF
|
||||
|
||||
|
||||
version() {
|
||||
echo "linux-exploit-suggester "$VERSION", mzet, https://z-labs.eu, March 2019"
|
||||
echo "linux-exploit-suggester $VERSION by mzet"
|
||||
}
|
||||
|
||||
usage() {
|
||||
echo "LES ver. $VERSION (https://github.com/mzet-/linux-exploit-suggester) by @_mzet_"
|
||||
echo "LES ver. $VERSION (https://github.com/mzet-/linux-exploit-suggester) by mzet"
|
||||
echo
|
||||
echo "Usage: linux-exploit-suggester.sh [OPTIONS]"
|
||||
echo
|
||||
@@ -2626,6 +2699,7 @@ for EXP_TEMP in "${SORTED_EXPLOITS[@]}"; do
|
||||
EXPLOIT_DB=$(echo "$EXP" | grep "exploit-db: " | awk '{print $2}')
|
||||
analysis_url=$(echo "$EXP" | grep "analysis-url: " | awk '{print $2}')
|
||||
ext_url=$(echo "$EXP" | grep "ext-url: " | awk '{print $2}')
|
||||
bof_url=$(echo "$EXP" | grep "bof-url: " | awk '{print $2}')
|
||||
comments=$(echo "$EXP" | grep "Comments: " | cut -d' ' -f 2-)
|
||||
reqs=$(echo "$EXP" | grep "Reqs: " | cut -d' ' -f 2)
|
||||
|
||||
@@ -2679,6 +2753,7 @@ for EXP_TEMP in "${SORTED_EXPLOITS[@]}"; do
|
||||
[ -n "$tags" ] && echo -e " Tags: $tags"
|
||||
echo -e " Download URL: $src_url"
|
||||
[ -n "$ext_url" ] && echo -e " ext-url: $ext_url"
|
||||
[ -n "$bof_url" ] && echo -e " bof-url: $bof_url"
|
||||
[ -n "$comments" ] && echo -e " Comments: $comments"
|
||||
|
||||
# handles --full filter option
|
||||
@@ -58,6 +58,8 @@ CALL :ColorLine " %E%41mWinPEAS should be used for authorized penetration test
|
||||
CALL :ColorLine " %E%41mAny misuse of this software will not be the responsibility of the author or of any other collaborator.%E%40;97m"
|
||||
CALL :ColorLine " %E%41mUse it at your own networks and/or with the network owner's permission.%E%40;97m"
|
||||
ECHO.
|
||||
ECHO. [i] Best Linux PE and hardening course: https://hacktricks-training.com/courses/lhe/
|
||||
ECHO.
|
||||
|
||||
:SystemInfo
|
||||
CALL :ColorLine "%E%32m[*]%E%97m BASIC SYSTEM INFO"
|
||||
@@ -71,7 +73,7 @@ CALL :T_Progress 2
|
||||
:ListHotFixes
|
||||
where wmic >nul 2>&1
|
||||
if %errorlevel% equ 0 (
|
||||
wmic qfe get Caption,Description,HotFixID,InstalledOn | more
|
||||
wmic qfe get Caption,Description,HotFixID,InstalledOn
|
||||
) else (
|
||||
powershell -command "Get-HotFix | Format-Table -AutoSize"
|
||||
)
|
||||
@@ -204,7 +206,7 @@ CALL :T_Progress 1
|
||||
CALL :ColorLine " %E%33m[+]%E%97m Registered Anti-Virus(AV)"
|
||||
where wmic >nul 2>&1
|
||||
if %errorlevel% equ 0 (
|
||||
WMIC /Node:localhost /Namespace:\\root\SecurityCenter2 Path AntiVirusProduct Get displayName /Format:List | more
|
||||
WMIC /Node:localhost /Namespace:\\root\SecurityCenter2 Path AntiVirusProduct Get displayName /Format:List
|
||||
) else (
|
||||
powershell -command "Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntiVirusProduct | Select-Object -ExpandProperty displayName"
|
||||
)
|
||||
@@ -238,7 +240,7 @@ CALL :ColorLine " %E%33m[+]%E%97m MOUNTED DISKS"
|
||||
ECHO. [i] Maybe you find something interesting
|
||||
where wmic >nul 2>&1
|
||||
if %errorlevel% equ 0 (
|
||||
wmic logicaldisk get caption | more
|
||||
wmic logicaldisk get caption
|
||||
) else (
|
||||
fsutil fsinfo drives
|
||||
)
|
||||
@@ -405,7 +407,7 @@ CALL :T_Progress 1
|
||||
|
||||
:BasicUserInfo
|
||||
CALL :ColorLine "%E%32m[*]%E%97m BASIC USER INFO
|
||||
ECHO. [i] Check if you are inside the Administrators group or if you have enabled any token that can be use to escalate privileges like SeImpersonatePrivilege, SeAssignPrimaryPrivilege, SeTcbPrivilege, SeBackupPrivilege, SeRestorePrivilege, SeCreateTokenPrivilege, SeLoadDriverPrivilege, SeTakeOwnershipPrivilege, SeDebbugPrivilege
|
||||
ECHO. [i] Check if you are inside the Administrators group or if you have enabled any token that can be use to escalate privileges like SeImpersonatePrivilege, SeAssignPrimaryPrivilege, SeTcbPrivilege, SeBackupPrivilege, SeRestorePrivilege, SeCreateTokenPrivilege, SeLoadDriverPrivilege, SeTakeOwnershipPrivilege, SeDebugPrivilege
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#users--groups
|
||||
ECHO.
|
||||
CALL :ColorLine " %E%33m[+]%E%97m CURRENT USER"
|
||||
@@ -670,7 +672,7 @@ if "%long%" == "true" (
|
||||
ECHO.
|
||||
where wmic >nul 2>&1
|
||||
if !errorlevel! equ 0 (
|
||||
for /f %%x in ('wmic logicaldisk get name ^| more') do (
|
||||
for /f %%x in ('wmic logicaldisk get name') do (
|
||||
set tdrive=%%x
|
||||
if "!tdrive:~1,2!" == ":" (
|
||||
%%x
|
||||
Binary file not shown.
Binary file not shown.
0
win/PetitPotam.py → tools/exploits/PetitPotam.py
Normal file → Executable file
0
win/PetitPotam.py → tools/exploits/PetitPotam.py
Normal file → Executable file
@@ -5,8 +5,6 @@ import os
|
||||
import re
|
||||
import sys
|
||||
import pty
|
||||
import util
|
||||
import upload_file
|
||||
import time
|
||||
import random
|
||||
import threading
|
||||
@@ -16,6 +14,9 @@ import select
|
||||
import argparse
|
||||
import signal
|
||||
|
||||
from hackingscripts.utils import util
|
||||
from hackingscripts.tools.misc import upload_file
|
||||
|
||||
try:
|
||||
import SocketServer
|
||||
except ImportError:
|
||||
118
tools/misc/tcp_template.py
Normal file
118
tools/misc/tcp_template.py
Normal file
@@ -0,0 +1,118 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import re
|
||||
import sys
|
||||
import json
|
||||
import argparse
|
||||
import urllib.parse
|
||||
|
||||
def generate_template(listen_address, listen_port, remote_host, remote_port):
|
||||
|
||||
# we could all need that
|
||||
imports = [
|
||||
"os",
|
||||
"socket",
|
||||
"threading"
|
||||
]
|
||||
|
||||
partial_imports = {
|
||||
"hackingscripts.utils": ["util"],
|
||||
"hackingscripts.utils.packeter": ["Packer", "Parser"]
|
||||
}
|
||||
|
||||
imports = "\n".join(f"import {i}" for i in sorted(imports, key=len))
|
||||
imports += "\n" + "\n".join(sorted(list(f"from {p} import {', '.join(i)}" for p, i in partial_imports.items()), key=len))
|
||||
return f"""#!/usr/bin/env python
|
||||
|
||||
#
|
||||
# THE BASE OF THIS FILE WAS AUTOMATICALLY GENERATED BY {' '.join(sys.argv)}
|
||||
# For more information, visit: https://git.romanh.de/Roman/HackingScripts
|
||||
#
|
||||
|
||||
{imports}
|
||||
|
||||
BUFFER_SIZE = 4096
|
||||
|
||||
class Packet:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def from_data(data):
|
||||
packet = Packet()
|
||||
parser = Parser(data)
|
||||
# TODO: auto-generated method stub
|
||||
return packet
|
||||
|
||||
def pack(self):
|
||||
buf = Packer()
|
||||
# TODO: auto-generated method stub
|
||||
return buf.get()
|
||||
|
||||
def forward(source, destination):
|
||||
try:
|
||||
while True:
|
||||
data = source.recv(BUFFER_SIZE)
|
||||
if not data:
|
||||
break
|
||||
|
||||
# TODO: Parse / Manipulate packet
|
||||
# packet = Packet.from_data(data)
|
||||
# repacked = packet.pack()
|
||||
|
||||
destination.sendall(data)
|
||||
except Exception:
|
||||
pass
|
||||
finally:
|
||||
source.close()
|
||||
destination.close()
|
||||
|
||||
def handle_client(client_socket, remote_host, remote_port):
|
||||
try:
|
||||
remote_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
remote_socket.connect((remote_host, remote_port))
|
||||
except Exception as e:
|
||||
print(f"Failed to connect to remote: {{e}}")
|
||||
client_socket.close()
|
||||
return
|
||||
|
||||
# Start bidirectional forwarding
|
||||
threading.Thread(target=forward, args=(client_socket, remote_socket), daemon=True).start()
|
||||
threading.Thread(target=forward, args=(remote_socket, client_socket), daemon=True).start()
|
||||
|
||||
def start_proxy(local_host, local_port, remote_host, remote_port):
|
||||
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
server.bind((local_host, local_port))
|
||||
server.listen(100)
|
||||
|
||||
print(f"[*] Forwarding from {{local_host}}:{{local_port}} to {{remote_host}}:{{remote_port}}")
|
||||
|
||||
while True:
|
||||
client_socket, addr = server.accept()
|
||||
print(f"[+] Connection from {{addr[0]}}:{{addr[1]}}")
|
||||
threading.Thread(
|
||||
target=handle_client,
|
||||
args=(client_socket, remote_host, remote_port),
|
||||
daemon=True
|
||||
).start()
|
||||
|
||||
if __name__ == "__main__":
|
||||
start_proxy({repr(listen_address)}, {listen_port}, {repr(remote_host)}, {remote_port})
|
||||
"""
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Exploit Template for tcp application attacks",
|
||||
formatter_class=argparse.RawTextHelpFormatter
|
||||
)
|
||||
|
||||
parser.add_argument("la", type=str, help="Listen Address")
|
||||
parser.add_argument("lp", type=int, help="Listen Port", choices=range(1,65535+1))
|
||||
parser.add_argument("rh", type=str, help="Remote Host")
|
||||
parser.add_argument("rp", type=int, help="Remote Port", choices=range(1,65535+1))
|
||||
|
||||
args = parser.parse_args()
|
||||
template = generate_template(args.la, args.lp, args.rh, args.rp)
|
||||
print(template)
|
||||
@@ -2,9 +2,10 @@
|
||||
|
||||
import sys
|
||||
import os
|
||||
import util
|
||||
import argparse
|
||||
|
||||
from hackingscripts.utils import util
|
||||
|
||||
def serve_file(listen_sock, path, forever=False):
|
||||
try:
|
||||
while True:
|
||||
@@ -17,7 +17,8 @@ def generate_template(base_url, features):
|
||||
|
||||
partial_imports = {
|
||||
"bs4": ["BeautifulSoup"],
|
||||
"hackingscripts": ["util", "rev_shell"],
|
||||
"hackingscripts.utils": ["util"],
|
||||
"hackingscripts.tools.exploits": ["rev_shell"],
|
||||
"urllib3.exceptions": ["InsecureRequestWarning"]
|
||||
}
|
||||
|
||||
0
dnsserver.py → tools/server/dnsserver.py
Normal file → Executable file
0
dnsserver.py → tools/server/dnsserver.py
Normal file → Executable file
0
ftpserver.py → tools/server/ftpserver.py
Normal file → Executable file
0
ftpserver.py → tools/server/ftpserver.py
Normal file → Executable file
0
smtpserver.py → tools/server/smtpserver.py
Normal file → Executable file
0
smtpserver.py → tools/server/smtpserver.py
Normal file → Executable file
0
sshserver.py → tools/server/sshserver.py
Normal file → Executable file
0
sshserver.py → tools/server/sshserver.py
Normal file → Executable file
@@ -1,14 +1,15 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import argparse
|
||||
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||
from urllib.parse import urlparse
|
||||
import threading
|
||||
import requests
|
||||
import time
|
||||
import os
|
||||
import ssl
|
||||
import util
|
||||
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||
from urllib.parse import urlparse
|
||||
from hackingscripts.utils import util
|
||||
from hackingscripts.tools.server.xss_handler import generate_payload as generate_xss_payload
|
||||
|
||||
class FileServerRequestHandler(BaseHTTPRequestHandler):
|
||||
|
||||
@@ -357,7 +358,6 @@ if __name__ == "__main__":
|
||||
file_server.forwardRequest("/proxy", url)
|
||||
print("Exfiltrate data using:", file_server.get_full_url("/proxy", ip_address))
|
||||
elif args.action == "xss":
|
||||
from xss_handler import generate_payload as generate_xss_payload
|
||||
payload_type = args.payload if args.payload else "img"
|
||||
xss = generate_xss_payload(payload_type, file_server.get_full_url("/exfiltrate", ip_address))
|
||||
file_server.addFile("/xss", xss)
|
||||
63
update.sh
63
update.sh
@@ -39,26 +39,25 @@ get_latest_version () {
|
||||
}
|
||||
|
||||
echo "Updating scripts…"
|
||||
download https://raw.githubusercontent.com/initstring/uptux/master/uptux.py uptux.py
|
||||
download https://raw.githubusercontent.com/pentestmonkey/unix-privesc-check/master/upc.sh unix-privesc-check.sh
|
||||
download https://github.com/DominicBreuker/pspy/releases/latest/download/pspy64 pspy64
|
||||
download https://github.com/DominicBreuker/pspy/releases/latest/download/pspy32 pspy
|
||||
download https://raw.githubusercontent.com/flozz/p0wny-shell/master/shell.php p0wny-shell.php
|
||||
download https://raw.githubusercontent.com/diego-treitos/linux-smart-enumeration/master/lse.sh lse.sh
|
||||
download https://raw.githubusercontent.com/mzet-/linux-exploit-suggester/master/linux-exploit-suggester.sh linux-exploit-suggester.sh
|
||||
download https://github.com/rebootuser/LinEnum/raw/master/LinEnum.sh LinEnum.sh
|
||||
download https://github.com/stealthcopter/deepce/raw/main/deepce.sh deepce.sh
|
||||
download https://raw.githubusercontent.com/topotam/PetitPotam/main/PetitPotam.py PetitPotam.py
|
||||
download https://raw.githubusercontent.com/initstring/uptux/master/uptux.py payloads/linux/uptux.py
|
||||
download https://raw.githubusercontent.com/pentestmonkey/unix-privesc-check/master/upc.sh payloads/linux/unix-privesc-check.sh
|
||||
download https://github.com/DominicBreuker/pspy/releases/latest/download/pspy64 payloads/linux/pspy64
|
||||
download https://github.com/DominicBreuker/pspy/releases/latest/download/pspy32 payloads/linux/pspy
|
||||
download https://raw.githubusercontent.com/flozz/p0wny-shell/master/shell.php payloads/web/p0wny-shell.php
|
||||
download https://raw.githubusercontent.com/diego-treitos/linux-smart-enumeration/master/lse.sh payloads/linux/lse.sh
|
||||
download https://raw.githubusercontent.com/mzet-/linux-exploit-suggester/master/linux-exploit-suggester.sh payloads/linux/linux-exploit-suggester.sh
|
||||
download https://github.com/rebootuser/LinEnum/raw/master/LinEnum.sh payloads/linux/LinEnum.sh
|
||||
download https://github.com/stealthcopter/deepce/raw/main/deepce.sh payloads/linux/deepce.sh
|
||||
|
||||
echo ""
|
||||
echo "Updating LinPEAS + WinPEAS…"
|
||||
peas_version=$(get_latest_version peass-ng/PEASS-ng)
|
||||
if [ ! -z "$peas_version" ]; then
|
||||
echo "Got PEAS version: $peas_version"
|
||||
download https://github.com/peass-ng/PEASS-ng/releases/download/$peas_version/linpeas.sh linpeas.sh
|
||||
download https://github.com/peass-ng/PEASS-ng/releases/download/$peas_version/winPEASx86.exe win/winPEAS.exe
|
||||
download https://github.com/peass-ng/PEASS-ng/releases/download/$peas_version/winPEASx64.exe win/winPEASx64.exe
|
||||
download https://github.com/peass-ng/PEASS-ng/releases/download/$peas_version/winPEAS.bat win/winPEAS.bat
|
||||
download https://github.com/peass-ng/PEASS-ng/releases/download/$peas_version/linpeas.sh payloads/linux/linpeas.sh
|
||||
download https://github.com/peass-ng/PEASS-ng/releases/download/$peas_version/winPEASx86.exe payloads/windows/winPEAS.exe
|
||||
download https://github.com/peass-ng/PEASS-ng/releases/download/$peas_version/winPEASx64.exe payloads/windows/winPEASx64.exe
|
||||
download https://github.com/peass-ng/PEASS-ng/releases/download/$peas_version/winPEAS.bat payloads/windows/winPEAS.bat
|
||||
else
|
||||
echo "Unable to determine latest PEAS version"
|
||||
fi
|
||||
@@ -66,24 +65,24 @@ fi
|
||||
# TODO: add others
|
||||
echo ""
|
||||
echo "Updating windows tools…"
|
||||
download https://live.sysinternals.com/accesschk.exe win/accesschk.exe
|
||||
download https://live.sysinternals.com/accesschk64.exe win/accesschk64.exe
|
||||
download https://github.com/int0x33/nc.exe/raw/master/nc.exe win/nc.exe
|
||||
download https://github.com/int0x33/nc.exe/raw/master/nc64.exe win/nc64.exe
|
||||
download https://github.com/k4sth4/Juicy-Potato/raw/main/x86/jp32.exe win/JuicyPotato.exe
|
||||
download https://github.com/k4sth4/Juicy-Potato/raw/main/x64/jp.exe win/JuicyPotato64.exe
|
||||
download https://github.com/uknowsec/SweetPotato/raw/master/SweetPotato-Webshell-new/bin/Release/SweetPotato.exe win/SweetPotato.exe
|
||||
download https://github.com/BeichenDream/GodPotato/releases/latest/download/GodPotato-NET4.exe win/GodPotato.exe
|
||||
download https://raw.githubusercontent.com/topotam/PetitPotam/main/PetitPotam.py win/PetitPotam.py
|
||||
download https://live.sysinternals.com/accesschk.exe payloads/windows/accesschk.exe
|
||||
download https://live.sysinternals.com/accesschk64.exe payloads/windows/accesschk64.exe
|
||||
download https://github.com/int0x33/nc.exe/raw/master/nc.exe payloads/windows/nc.exe
|
||||
download https://github.com/int0x33/nc.exe/raw/master/nc64.exe payloads/windows/nc64.exe
|
||||
download https://github.com/k4sth4/Juicy-Potato/raw/main/x86/jp32.exe payloads/windows/JuicyPotato.exe
|
||||
download https://github.com/k4sth4/Juicy-Potato/raw/main/x64/jp.exe payloads/windows/JuicyPotato64.exe
|
||||
download https://github.com/uknowsec/SweetPotato/raw/master/SweetPotato-Webshell-new/bin/Release/SweetPotato.exe payloads/windows/SweetPotato.exe
|
||||
download https://github.com/BeichenDream/GodPotato/releases/latest/download/GodPotato-NET4.exe payloads/windows/GodPotato.exe
|
||||
download https://raw.githubusercontent.com/topotam/PetitPotam/main/PetitPotam.py tools/exploits/PetitPotam.py
|
||||
|
||||
echo ""
|
||||
chisel_version=$(get_latest_version jpillora/chisel v)
|
||||
if [ ! -z "$chisel_version" ]; then
|
||||
echo "Got Chisel version: $chisel_version"
|
||||
curl -s -L "https://github.com/jpillora/chisel/releases/download/v${chisel_version}/chisel_${chisel_version}_linux_386.gz" | gzip -d > chisel
|
||||
curl -s -L "https://github.com/jpillora/chisel/releases/download/v${chisel_version}/chisel_${chisel_version}_linux_amd64.gz" | gzip -d > chisel64
|
||||
curl -s -L "https://github.com/jpillora/chisel/releases/download/v${chisel_version}/chisel_${chisel_version}_windows_386.gz" | gzip -d > win/chisel.exe
|
||||
curl -s -L "https://github.com/jpillora/chisel/releases/download/v${chisel_version}/chisel_${chisel_version}_windows_amd64.gz" | gzip -d > win/chisel64.exe
|
||||
curl -s -L "https://github.com/jpillora/chisel/releases/download/v${chisel_version}/chisel_${chisel_version}_linux_386.gz" | gzip -d > payloads/linux/chisel
|
||||
curl -s -L "https://github.com/jpillora/chisel/releases/download/v${chisel_version}/chisel_${chisel_version}_linux_amd64.gz" | gzip -d > payloads/linux/chisel64
|
||||
curl -s -L "https://github.com/jpillora/chisel/releases/download/v${chisel_version}/chisel_${chisel_version}_windows_386.gz" | gzip -d > payloads/windows/chisel.exe
|
||||
curl -s -L "https://github.com/jpillora/chisel/releases/download/v${chisel_version}/chisel_${chisel_version}_windows_amd64.gz" | gzip -d > payloads/windows/chisel64.exe
|
||||
else
|
||||
echo "Unable to determine latest chisel version"
|
||||
fi
|
||||
@@ -91,14 +90,14 @@ fi
|
||||
sharphound_version=$(get_latest_version BloodHoundAD/SharpHound v)
|
||||
if [ ! -z "$sharphound_version" ]; then
|
||||
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 payloads/windows/ SharpHound.exe SharpHound.ps1
|
||||
fi
|
||||
|
||||
socat_version=$(get_latest_version "3ndG4me/socat" v)
|
||||
if [ ! -z "$socat_version" ]; then
|
||||
echo "Got socat version: $socat_version"
|
||||
download https://github.com/3ndG4me/socat/releases/download/v${socat_version}/socatx86.bin socat
|
||||
download https://github.com/3ndG4me/socat/releases/download/v${socat_version}/socatx64.bin socat64
|
||||
download https://github.com/3ndG4me/socat/releases/download/v${socat_version}/socatx86.exe win/socat.exe
|
||||
download https://github.com/3ndG4me/socat/releases/download/v${socat_version}/socatx64.exe win/socat64.exe
|
||||
download https://github.com/3ndG4me/socat/releases/download/v${socat_version}/socatx86.bin payloads/linux/socat
|
||||
download https://github.com/3ndG4me/socat/releases/download/v${socat_version}/socatx64.bin payloads/linux/socat64
|
||||
download https://github.com/3ndG4me/socat/releases/download/v${socat_version}/socatx86.exe payloads/windows/socat.exe
|
||||
download https://github.com/3ndG4me/socat/releases/download/v${socat_version}/socatx64.exe payloads/windows/socat64.exe
|
||||
fi
|
||||
0
utils/__init__.py
Normal file
0
utils/__init__.py
Normal file
133
utils/packeter.py
Normal file
133
utils/packeter.py
Normal file
@@ -0,0 +1,133 @@
|
||||
import struct
|
||||
|
||||
class StructWrapper:
|
||||
@staticmethod
|
||||
def _endian(e):
|
||||
return ">" if e else "<"
|
||||
|
||||
@staticmethod
|
||||
def _format_size(f):
|
||||
format_sizes = {
|
||||
"c": 1,
|
||||
"h": 2, "H": 2,
|
||||
"i": 4, "I": 4,
|
||||
"q": 8, "Q": 8,
|
||||
}
|
||||
|
||||
assert f in format_sizes
|
||||
return format_sizes[f]
|
||||
|
||||
class Parser(StructWrapper):
|
||||
def __init__(self, data, big_endian=False):
|
||||
self.data = data
|
||||
self.offset = 0
|
||||
self.big_endian = big_endian
|
||||
|
||||
def eof(self):
|
||||
return self.offset >= len(self.data)
|
||||
|
||||
def remaining_size(self):
|
||||
return len(self.data[self.offset:])
|
||||
|
||||
def _struct_unpack(self, big_endian, f):
|
||||
size = self._format_size(f)
|
||||
assert self.remaining_size() >= size
|
||||
|
||||
# grab default endianess, when none is given
|
||||
if big_endian is None:
|
||||
big_endian = self.big_endian
|
||||
|
||||
value = struct.unpack(self._endian(big_endian) + f, self.data[self.offset:self.offset+size])[0]
|
||||
self.offset += size
|
||||
return value
|
||||
|
||||
def read_byte(self):
|
||||
return self._struct_unpack(big_endian, "c")
|
||||
|
||||
def read_char(self):
|
||||
return chr(self.read_byte())
|
||||
|
||||
def read_signed_short(self, big_endian=None):
|
||||
return self._struct_unpack(big_endian, "h")
|
||||
|
||||
def read_unsigned_short(self, big_endian=None):
|
||||
return self._struct_unpack(big_endian, "H")
|
||||
|
||||
def read_signed_int(self, big_endian=None):
|
||||
return self._struct_unpack(big_endian, "i")
|
||||
|
||||
def read_unsigned_int(self, big_endian=None):
|
||||
return self._struct_unpack(big_endian, "I")
|
||||
|
||||
def read_signed_long(self, big_endian=None):
|
||||
return self._struct_unpack(big_endian, "q")
|
||||
|
||||
def read_unsigned_long(self, big_endian=None):
|
||||
return self._struct_unpack(big_endian, "Q")
|
||||
|
||||
def read_bin(self, length):
|
||||
d = self.data[self.offset:self.offset+length]
|
||||
assert len(self.data[self.offset:]) >= length
|
||||
self.offset += length
|
||||
return d
|
||||
|
||||
def read_until(self, byte):
|
||||
data = b""
|
||||
while not self.eof():
|
||||
c = self.read_byte()
|
||||
if c == byte:
|
||||
break
|
||||
data += c
|
||||
return data
|
||||
|
||||
class Packer(StructWrapper):
|
||||
def __init__(self, big_endian=False):
|
||||
self.buffer = b""
|
||||
self.offset = 0
|
||||
self.big_endian = big_endian
|
||||
|
||||
def get(self):
|
||||
return self.buffer
|
||||
|
||||
def length(self):
|
||||
return len(self.buffer)
|
||||
|
||||
def _struct_pack(self, big_endian, f, value):
|
||||
# grab default endianess, when none is given
|
||||
if big_endian is None:
|
||||
big_endian = self.big_endian
|
||||
|
||||
size = self._format_size(f)
|
||||
self.buffer += struct.pack(self._endian(big_endian) + f, value)
|
||||
self.offset += size
|
||||
|
||||
def write_byte(self, value):
|
||||
self._struct_pack(big_endian, "c", value)
|
||||
|
||||
def write_char(self, value):
|
||||
self._struct_pack(big_endian, "c", value.encode())
|
||||
|
||||
def write_signed_short(self, value, big_endian=None):
|
||||
self._struct_pack(big_endian, "c", value)
|
||||
|
||||
def write_unsigned_short(self, value, big_endian=None):
|
||||
self._struct_pack(big_endian, "H", value)
|
||||
|
||||
def write_signed_int(self, value, big_endian=None):
|
||||
self._struct_unpack(big_endian, "i", value)
|
||||
|
||||
def write_unsigned_int(self, value, big_endian=None):
|
||||
self._struct_unpack(big_endian, "I", value)
|
||||
|
||||
def write_signed_long(self, value, big_endian=None):
|
||||
self._struct_unpack(big_endian, "q", value)
|
||||
|
||||
def rwrite_unsigned_long(self, value, big_endian=None):
|
||||
self._struct_unpack(big_endian, "Q", value)
|
||||
|
||||
def write_bin(self, value):
|
||||
self.buffer += value
|
||||
self.offset += len(value)
|
||||
|
||||
def write_string(self, value, encoding="UTF-8"):
|
||||
self.write_bin(value.encode(encoding))
|
||||
@@ -14,6 +14,18 @@ import re
|
||||
import json
|
||||
import urllib.parse
|
||||
|
||||
def hex_dump(data, column_size=16):
|
||||
printables = (string.ascii_letters + string.digits + string.punctuation).encode()
|
||||
for i in range(0, len(data), column_size):
|
||||
row = data[i:i+column_size]
|
||||
as_string = "".join("." if bytes([b]) not in printables else chr(b) for b in row)
|
||||
as_hex = " ".join("%02x" % b for b in row)
|
||||
|
||||
if len(row) < column_size:
|
||||
as_hex += " " * 3 * (column_size - len(row))
|
||||
|
||||
print("%08x" % (i * column_size), "|", as_hex, "|", as_string)
|
||||
|
||||
def is_port_in_use(port):
|
||||
import socket
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||||
@@ -158,12 +170,11 @@ def assert_regex_match(pattern, data, err=None):
|
||||
err = f"[-] Data does not match pattern '{pattern}': '{data}'" if err is None else err
|
||||
exit_with_error(None, err)
|
||||
|
||||
def open_server(address, ports=None, retry=True):
|
||||
def open_server(address, ports=None, retry=False):
|
||||
listen_port = None
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
|
||||
while retry:
|
||||
|
||||
while True:
|
||||
if isinstance(ports, int):
|
||||
listen_port = ports
|
||||
retry = False
|
||||
@@ -173,12 +184,15 @@ def open_server(address, ports=None, retry=True):
|
||||
listen_port = random.randint(10000,65535)
|
||||
|
||||
try:
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
sock.bind((address, listen_port))
|
||||
sock.listen(1)
|
||||
return sock
|
||||
except Exception as e:
|
||||
if not retry:
|
||||
print("[-] Unable to listen on port %d: %s" % (listenPort, str(e)))
|
||||
if retry:
|
||||
print("[-] Unable to listen on port %d: %s, Retrying…" % (listen_port, str(e)))
|
||||
time.sleep(1.0)
|
||||
else:
|
||||
raise e
|
||||
|
||||
class Stack:
|
||||
@@ -1,273 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import re
|
||||
import sys
|
||||
import json
|
||||
import argparse
|
||||
import requests
|
||||
import urllib.parse
|
||||
import util
|
||||
from bs4 import BeautifulSoup
|
||||
from crawl_urls import Crawler
|
||||
|
||||
requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
|
||||
|
||||
class WebServiceFinder:
|
||||
|
||||
def __init__(self, args):
|
||||
self.parseUrl(args.url)
|
||||
self.parseCookies(args.cookie)
|
||||
self.headers = { }
|
||||
self.session = requests.Session()
|
||||
self.verbose = args.verbose
|
||||
|
||||
if args.user_agent:
|
||||
self.headers["User-Agent"] = args.user_agent
|
||||
|
||||
def parseUrl(self, url):
|
||||
parts = urllib.parse.urlparse(url)
|
||||
if parts.scheme == '':
|
||||
self.url = "http://" + url
|
||||
self.scheme = "http"
|
||||
elif parts.scheme not in ["http","https"]:
|
||||
print("[-] Unsupported URL scheme:", parts.scheme)
|
||||
exit(1)
|
||||
else:
|
||||
self.url = url
|
||||
self.scheme = parts.scheme
|
||||
|
||||
def resolve(self, uri):
|
||||
if uri is None or uri.strip() == "":
|
||||
return self.url
|
||||
elif urllib.parse.urlparse(uri).scheme != "":
|
||||
return uri
|
||||
|
||||
target = self.url
|
||||
if not target.endswith("/"):
|
||||
target += "/"
|
||||
if uri.startswith("/"):
|
||||
uri = uri[1:]
|
||||
|
||||
return target + uri
|
||||
|
||||
def do_get(self, uri, **args):
|
||||
|
||||
uri = self.resolve(uri)
|
||||
if self.verbose:
|
||||
sys.stdout.write("GET %s: " % uri)
|
||||
|
||||
res = self.session.get(uri, headers=self.headers, cookies=self.cookies, verify=False, **args)
|
||||
if self.verbose:
|
||||
sys.stdout.write("%d %s\n" % (res.status_code, res.reason))
|
||||
|
||||
return res
|
||||
|
||||
def parseCookies(self, cookie_list):
|
||||
self.cookies = { }
|
||||
if cookie_list:
|
||||
for cookie in cookie_list:
|
||||
cookie = cookie.strip()
|
||||
if "=" in cookie:
|
||||
index = cookie.find("=")
|
||||
key, val = cookie[0:index], cookie[index+1:]
|
||||
self.cookies[key] = val
|
||||
else:
|
||||
self.cookies[cookie] = ""
|
||||
|
||||
def scan(self):
|
||||
print("[ ] Retrieving:", self.url)
|
||||
|
||||
uri = "/"
|
||||
while True:
|
||||
startPage = self.do_get(uri, allow_redirects=False)
|
||||
if startPage.status_code in [301, 302, 397, 308]:
|
||||
uri = startPage.headers["Location"]
|
||||
if urllib.parse.urlparse(uri).scheme == "https" and self.scheme == "http":
|
||||
self.url = self.url.replace("http","https",1)
|
||||
self.scheme = "https"
|
||||
|
||||
print("[+] Server redirecting to:", uri)
|
||||
else:
|
||||
break
|
||||
|
||||
self.analyseHeaders(startPage)
|
||||
if "text/html" in startPage.headers["Content-Type"]:
|
||||
self.analyseHtml(startPage)
|
||||
elif "text/xml" in startPage.headers["Content-Type"]:
|
||||
self.analyseXml(startPage)
|
||||
|
||||
self.analyseRobots()
|
||||
self.analyseSitemap()
|
||||
self.analyseChangelog()
|
||||
self.checkJoomlaVersion()
|
||||
self.checkManifest()
|
||||
|
||||
def checkManifest(self):
|
||||
url = "/static/manifest.json"
|
||||
res = self.do_get(url)
|
||||
if res.status_code == 200:
|
||||
try:
|
||||
manifest = json.loads(res.text)
|
||||
if "name" in manifest:
|
||||
print("[+] Found manifest name:", manifest["name"])
|
||||
except:
|
||||
pass
|
||||
|
||||
def checkJoomlaVersion(self):
|
||||
url = "/administrator/manifests/files/joomla.xml"
|
||||
res = self.do_get(url)
|
||||
if res.status_code == 200:
|
||||
soup = BeautifulSoup(res.text, "lxml")
|
||||
extension = soup.find("extension")
|
||||
if extension and extension.has_attr("version"):
|
||||
print("[+] Found Joomla version:", extension["version"])
|
||||
|
||||
def analyseHeaders(self, res):
|
||||
phpFound = False
|
||||
banner_headers = ["Server", "X-Powered-By", "X-Runtime", "X-Version"]
|
||||
for banner in banner_headers:
|
||||
if banner in res.headers:
|
||||
phpFound = phpFound or ("PHP" in res.headers[banner])
|
||||
print("[+] %s Header: %s" % (banner, res.headers[banner]))
|
||||
if not phpFound and "PHPSESSID" in self.session.cookies:
|
||||
print("[+] PHP detected, unknown version")
|
||||
|
||||
def printMatch(self, title, match, group=1, version_func=str):
|
||||
if match:
|
||||
version = "Unknown version" if group is None or len(match.groups()) <= group else version_func(match.group(group))
|
||||
print("[+] Found %s: %s" % (title, version))
|
||||
return True
|
||||
return False
|
||||
|
||||
def retrieveMoodleVersion(self, v):
|
||||
res = requests.get("https://docs.moodle.org/dev/Releases")
|
||||
soup = BeautifulSoup(res.text, "html.parser")
|
||||
versionStr = "Unknown"
|
||||
|
||||
for tr in soup.find_all("tr"):
|
||||
tds = tr.find_all("td")
|
||||
th = tr.find("th")
|
||||
if len(tds) == 4 and th and int(tds[1].text.strip()) == v:
|
||||
versionStr = th.text.strip()
|
||||
if versionStr.startswith("Moodle "):
|
||||
versionStr = versionStr[len("Moodle"):].strip()
|
||||
break
|
||||
|
||||
return "%s (%d)" % (versionStr, v)
|
||||
|
||||
def analyseXml(self,res):
|
||||
soup = BeautifulSoup(res.text, "lxml")
|
||||
|
||||
title = soup.find("title")
|
||||
if title:
|
||||
print("[+] Found XML title:", title.text.strip())
|
||||
|
||||
generator = soup.find("generator")
|
||||
if generator:
|
||||
if generator.has_attr("version"):
|
||||
print("[+] Found XML Generator version:", generator["version"])
|
||||
|
||||
def analyseHtml(self, res):
|
||||
soup = BeautifulSoup(res.text, "html.parser")
|
||||
|
||||
meta_generator = soup.find("meta", {"name":"generator"})
|
||||
if meta_generator:
|
||||
banner = meta_generator["content"].strip()
|
||||
print("[+] Meta Generator:", banner)
|
||||
|
||||
body = soup.find("body")
|
||||
if body:
|
||||
gitea_pattern = re.compile(r"Gitea Version: ([0-9\.]*)")
|
||||
self.printMatch("Gitea", gitea_pattern.search(body.text))
|
||||
|
||||
footer = soup.find("footer")
|
||||
if footer:
|
||||
content = footer.text.strip()
|
||||
|
||||
gogs_pattern = re.compile(r"(^|\s)Gogs Version: ([a-zA-Z0-9.-]+)($|\s)")
|
||||
go_pattern = re.compile(r"(^|\s)Go([0-9.]+)($|\s+)")
|
||||
|
||||
self.printMatch("Gogs", gogs_pattern.search(content), 2)
|
||||
self.printMatch("Go", go_pattern.search(content), 2)
|
||||
|
||||
versionInfo = soup.find("div", {"class": "versionInfo"})
|
||||
if versionInfo:
|
||||
content = versionInfo.text.strip()
|
||||
|
||||
cacti_pattern = re.compile(r"Version ([0-9.]*) .* The Cacti Group")
|
||||
self.printMatch("Cacti", cacti_pattern.search(content), 1)
|
||||
|
||||
poweredBy = soup.find(id="poweredBy")
|
||||
if poweredBy:
|
||||
content = poweredBy.text.strip()
|
||||
|
||||
osticket_pattern = re.compile(r"powered by osTicket")
|
||||
self.printMatch("OsTicket", osticket_pattern.search(content))
|
||||
|
||||
moodle_pattern_1 = re.compile(r"^https://download.moodle.org/mobile\?version=(\d+)(&|$)")
|
||||
moodle_pattern_2 = re.compile(r"^https://docs.moodle.org/(\d+)/")
|
||||
litecart_pattern = re.compile(r"^https://www.litecart.net")
|
||||
wordpress_pattern = re.compile(r"/wp-(admin|includes|content)/(([^/]+)/)*(wp-emoji-release.min.js|style.min.css)\?ver=([0-9.]+)(&|$)")
|
||||
|
||||
urls = Crawler(self.url).collect_urls(soup)
|
||||
for url in urls:
|
||||
self.printMatch("Moodle", moodle_pattern_1.search(url), version_func=lambda v: self.retrieveMoodleVersion(int(v)))
|
||||
self.printMatch("Moodle", moodle_pattern_2.search(url), version_func=lambda v: "%d.%d" % (int(v)//10,int(v)%10))
|
||||
self.printMatch("Litecart", litecart_pattern.search(url), group=None)
|
||||
if self.printMatch("Wordpress", wordpress_pattern.search(url), group=5):
|
||||
print("[ ] You should consider using 'wpscan' for further investigations and more accurate results")
|
||||
|
||||
def analyseRobots(self):
|
||||
res = self.do_get("/robots.txt", allow_redirects=False)
|
||||
if res.status_code != 200:
|
||||
print("[-] robots.txt not found or inaccessible")
|
||||
return False
|
||||
|
||||
def analyseSitemap(self):
|
||||
res = self.do_get("/sitemap.xml", allow_redirects=False)
|
||||
if res.status_code != 200:
|
||||
print("[-] sitemap.xml not found or inaccessible")
|
||||
return False
|
||||
|
||||
def analyseChangelog(self):
|
||||
|
||||
drupal_pattern = re.compile("^Drupal ([0-9.]+),")
|
||||
drupal_found = False
|
||||
|
||||
changelog_files = ["CHANGELOG", "CHANGELOG.txt"]
|
||||
for file in changelog_files:
|
||||
res = self.do_get(file, allow_redirects=False)
|
||||
if res.status_code != 200:
|
||||
continue
|
||||
|
||||
print("[+] Found:", file)
|
||||
for line in res.text.split("\n"):
|
||||
line = line.strip()
|
||||
if not drupal_found and self.printMatch("Drupal", drupal_pattern.search(line)):
|
||||
drupal_found = True
|
||||
|
||||
|
||||
def banner():
|
||||
print("""
|
||||
,--------. ,--. ,--------. ,--. ,--. ,--.
|
||||
'--. .--',---. ,---.,-' '-.'--. .--',---. ,---. | | ,--. ,--. / | / \\
|
||||
| | | .-. :( .-''-. .-' | | | .-. || .-. || | \ `' / `| | | () |
|
||||
| | \ --..-' `) | | | | ' '-' '' '-' '| | \ / | |.--.\ /
|
||||
`--' `----'`----' `--' `--' `---' `---' `--' `--' `--''--' `--'
|
||||
|
||||
""")
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("url", help="The target URI to scan to, e.g. http://example.com:8080/dir/")
|
||||
parser.add_argument("--proxy", help="Proxy to connect through") # TODO
|
||||
parser.add_argument("--user-agent", help="User-Agent to use")
|
||||
parser.add_argument("--cookie", help="Cookies to send", action='append')
|
||||
parser.add_argument('--verbose', '-v', help="Verbose otuput", action='store_true')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
banner()
|
||||
|
||||
client = WebServiceFinder(args)
|
||||
client.scan()
|
||||
Reference in New Issue
Block a user