
Analysis and PoC for CVE-2018-14847, MikroTik RouterOS Winbox information disclosure vulnerability allowing unauthenticated read access to the credential database.
Unauthenticated path traversal in MikroTik's Winbox protocol leaking admin credentials from /flash/rw/store/user.dat
CVE-2018-14847 is a path traversal vulnerability in MikroTik RouterOS affecting the Winbox management protocol (TCP port 8291). An unauthenticated remote attacker can read arbitrary files from the router's filesystem, including the user credential database /flash/rw/store/user.dat, which stores passwords encrypted with a weak static XOR key.
The vulnerability was originally disclosed by Jacob Baines (Tenable) in July 2018 through the By the Way exploit. This repository contains a standalone Python3 reimplementation with full protocol documentation.
| Channel | Versions |
|---|
| Longterm | 6.30.1 - 6.40.7 |
| Stable | 6.29 - 6.42 |
| Beta | 6.29rc1 - 6.43rc3 |
MikroTik patched this vulnerability in April 2018. Devices running RouterOS older than the fixed versions remain vulnerable.
Winbox is MikroTik's proprietary binary management protocol running on TCP port 8291. Frames are structured as:
[total_len - 2][0x01][0x00][total_len - 4]["M2"][fields...]
The 4-byte header encodes the total frame size. It is not a standard little-endian u16 - each byte encodes total_length - 2 and total_length - 4 independently.
Field encoding inside each frame:
| Type byte | Meaning | Value |
|---|---|---|
| 0xff | Extended field marker | followed by field_id and value |
| 0x09 | u8 integer | 1 byte |
| 0x21 | String | 1-byte length prefix + data |
| 0x88 | Reply-expected marker | no value |
| 0xfe | Extended field id | 3-byte id + type + value |
The filesystem handler lives at endpoint (sys=5, handler=0) and exposes three relevant commands:
The Winbox filesystem handler does not sanitize the path passed to the open-file command. By embedding '/////./../' sequences, an attacker escapes the sandbox boundary and reaches the root filesystem:
/////./..//////./..//////./../flash/rw/store/user.dat
Each '/////./../' segment (10 bytes) steps one directory level up. Three segments reach the root, after which flash/rw/store/user.dat is the RouterOS user credential database. The request requires no authentication.
The exploit sends two frames:
user.dat is a sequence of nv::message records. Each record is preceded by a 2-byte LE length field and starts with the magic bytes M2. Fields inside each record use a 3-byte LE field id:
| Field id | Type | Meaning |
|---|
| 0x01 | string | username |
| 0x02 | u8 | group - 3 = full admin access |
| 0x11 | string | encrypted password (empty if not set) |
Passwords are encrypted with a static XOR key derived from a hardcoded salt compiled into RouterOS:
key = MD5(username + "283i4jfkai3389")
password = XOR(encrypted_pass[i], key[i % len(key)]) until null byte
This means any user.dat extracted from any affected device can be decrypted offline without brute force.
After obtaining the admin password, the attacker can authenticate via Winbox and use the create-file command to write two files that activate the hidden developer login:
/pckg/option activates the option package
/flash/nova/etc/devel-login enables the devel user
Once these files exist, the router exposes a BusyBox root shell via Telnet and SSH under the user devel, using the admin's password.
Telnet must be connected first for SSH to work on some RouterOS versions.
Exploit_CVE_2018_14847.py is a self-contained Python3 exploit with zero external dependencies. It implements the Winbox binary protocol from scratch and performs:
# Default port 8291
python3 Exploit_CVE_2018_14847.py 192.168.1.10
# Custom port
python3 Exploit_CVE_2018_14847.py 192.168.1.10 8291
Post-exploitation - developer backdoor shell:
# Telnet (must connect first)
telnet -l devel 192.168.1.10
# SSH (after Telnet session)
ssh -oHostKeyAlgorithms=+ssh-dss [email protected]