
Explore Chinese routers on RT5350
Once, lolipop bought a router on aliexpress. Yes, not a simple router, but very compact and cheap, with 2 Ethernet ports, USB, and even from a company that sold its mp3 players in the Russian Federation in the early 2000s: Nexx WT1520H.

The standard firmware, as almost always, was scarce, and, of course, I wanted to replace it with something more sane. But here's the problem - there are no alternative firmware for the router, and it’s not clear how to flash it, because no other firmware was accepted through the web interface, I didn’t see the header of the firmware before, and binwalk did not find anything in it, so it is encrypted:
lolipop poured data from the flash drive through the programmer, and we began to pick it.
The entire init process is responsible for the entire process of initializing the equipment and launching programs - / sbin / rc. This is such a coolbox busybox, which contains almost the entire logic of the router:
By deduction and nmap it was found out that telnetd was launched on the router, which is accessible through the WAN interface! Here it is! However, logging in failed either under the root user or under the admin user.
Busybox acts as telnetd. Let's look into it (login_main function): Well

, now it starts up before entering the password, however, the standard password “admin” is not accepted. Interesting. We look further:

That's it! Login nexxadmin, password y1n2inc.com0755, with access via WAN.
There is mtd_write in the firmware, so nothing prevents us from uploading OpenWRT directly to the flash right now, which was done by lolipopbut still it was interesting to reverse the encryption algorithm. Unfortunately, my MIPS assembly skills in my head are clearly not enough, and I experienced great discomfort only when looking at all this code, so I ordered the same router for myself, and, lo and behold, I had it 2 months later.

Only RX is connected, the ground is common with the laptop via USB power.
The router can be updated both through the web interface and via tftp (which, again, listens to WAN!). The tftp daemon (upgraded from rc) seems to be broken because updating through it did not lead to updating the firmware in the router, although there were no errors. It should be noted that updating firmware on tftp requires authentication with the same password as on the web interface, so it's hard to call it backdoor, rather just a misconfigured service.
I decided to investigate the firmware update precisely through tftp.
A simple upgrade through the standard tftp client led to “Upgrade not possible: Incorrect Password” from upgraded. Let's look into it:

Regular clients do not seem to be able to send tftp options, so I downloaded the tftpy python library , modified one line in the client example file, and it worked:
Excellent! Now it remains to deal with encryption firmware. There is a decrypto function in rc, it looks something like this:

I could not find the key in the static, so I started debugging. To debug something on the device, of course, you must first assemble the debugger. IDA Pro does not compile linux_server under MIPS (and the router is built on this architecture), so it was necessary to somehow build gdbserver under the router. The router uses the old-old kernel 2.6.21 with uClibc 0.9.28. First of all, I decided to use buildroot so that it builds both the uchib toolchain and gdbserver statically. Well, everything was assembled, it seems to start, however, when debugging through IDA Pro, the server constantly crashes, ptrace produces some strange errors, well, I think we need to rebuild it with headers from the kernel 2.6.21 and with uClibc 0.9.28, t .to. uClibc never promised binary compatibility. Ralink SDK found on the Internetwith the correct kernel version and uClibc. The GDBServer compiled by this toolchain behaved one-on-one like the old one. Unfortunately, IDA Pro has some incompatibility with gdbserver, which runs on MIPS. Fortunately, gdbserver works great with regular gdb compiled under mips (./configure --target mipsel-linux).
I very rarely debug something in bare gdb, and convenient add-ons and scripts for it work only with x86 and ARM. Fortunately, I found a repository with .gdbinit for MIPS , and the debugging convenience has increased markedly. It all happened something like this:

Ultimately, the key was found just a few lines above, which should be expected:

After I wrote the script to decrypt the firmware, lolipopsent me another one with a similar header, but from a different router. The first 4 characters (magic) she had were R3G2. Searching this line in Google, it was found that everything had already been done before us, even at the beginning of 2013 :(
In any decrypted firmware there is a Linux Kernel Image line, which is always at the same offset. This line is longer than XOR- the key, which means that we don’t need to get it from rc from different manufacturers, but we can just “find” it from this line,
but it’s not enough to unzip the firmware, we also need to pack it so that it can be updated via the web interface.As it turned out, the update function has a control count Oh, the amount of firmware:

What looks like in C like this:
Now we have everything we need to upload any firmware via the web interface.
Encryption
Firmware with backdoor and such poor quality force the consumer to look for normally working software for their device. lolipop added support for this device in OpenWRT, and will be added to Trunk soon. And also, yesterday the release of OpenWRT Barrier Breaker was finally released! (there is no announcement on the site yet).
That's how we live.

The standard firmware, as almost always, was scarce, and, of course, I wanted to replace it with something more sane. But here's the problem - there are no alternative firmware for the router, and it’s not clear how to flash it, because no other firmware was accepted through the web interface, I didn’t see the header of the firmware before, and binwalk did not find anything in it, so it is encrypted:
00000000 32 33 35 30 6b d9 39 00 00 00 0e 02 00 00 00 00 |2350k.9.........|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 3e 19 53 c5 |............>.S.|
00000020 63 f5 51 9f 82 74 2d 03 2e 2f 1f 32 9c 4a 93 96 |c.Q..t-../.2.J..|
00000030 15 82 23 d0 b2 7e d7 1b 13 c3 1b 1f 06 fa f8 e0 |..#..~..........|
00000040 bb 43 9b c6 ee fc 4b 7a e6 50 71 2b f4 f3 95 c3 |.C....Kz.Pq+....|
00000050 63 d0 a3 9c 92 2e 16 c6 19 1c 4a 93 cb 95 c3 63 |c.........J....c|
00000060 d2 9b 1a f5 2e 16 c6 19 1c 4a 93 f9 68 3c 9c 73 |.........J..h<.s|
00000070 14 63 d5 10 5e d3 6b 25 2b c2 2e 07 eb 85 73 25 |.c..^.k%+.....s%|
00000080 9b 6b c0 f2 d8 9b cf 65 56 ac a9 c2 28 61 dd 55 |.k.....eV...(a.U|
00000090 18 a4 5b e9 ba 11 93 ec 30 76 4f 40 c1 f0 7c cb |..[.....0vO@..|.|
000000a0 36 d3 b3 93 fe 3d 6b 10 66 fa 43 39 f2 f6 c0 91 |6....=k.f.C9....|
lolipop poured data from the flash drive through the programmer, and we began to pick it.
Firmware research
The entire init process is responsible for the entire process of initializing the equipment and launching programs - / sbin / rc. This is such a coolbox busybox, which contains almost the entire logic of the router:
Hidden text
.text:0040E758 .globl start_services
.text:0040E758 start_services: # CODE XREF: main+14C8p
.text:0040E758 # DATA XREF: main+14C0o ...
.text:0040E758
.text:0040E758 var_10 = -0x10
.text:0040E758 var_8 = -8
.text:0040E758
.text:0040E758 li $gp, 0x7EBF8
.text:0040E760 addu $gp, $t9
.text:0040E764 addiu $sp, -0x20
.text:0040E768 sw $ra, 0x20+var_8($sp)
.text:0040E76C sw $gp, 0x20+var_10($sp)
.text:0040E770 la $t9, start_syslog
.text:0040E774 nop
.text:0040E778 jalr $t9 ; start_syslog
.text:0040E77C nop
.text:0040E780 lw $gp, 0x20+var_10($sp)
.text:0040E784 nop
.text:0040E788 la $t9, start_proftpd
.text:0040E78C nop
.text:0040E790 jalr $t9 ; start_proftpd
.text:0040E794 nop
.text:0040E798 lw $gp, 0x20+var_10($sp)
.text:0040E79C nop
.text:0040E7A0 la $t9, start_telnetd
.text:0040E7A4 nop
.text:0040E7A8 jalr $t9 ; start_telnetd
.text:0040E7AC nop
.text:0040E7B0 lw $gp, 0x20+var_10($sp)
.text:0040E7B4 nop
.text:0040E7B8 la $t9, load_smb_driver
.text:0040E7BC nop
.text:0040E7C0 jalr $t9 ; load_smb_driver
.text:0040E7C4 nop
.text:0040E7C8 lw $gp, 0x20+var_10($sp)
.text:0040E7CC nop
.text:0040E7D0 la $t9, sys_led_init
.text:0040E7D4 nop
.text:0040E7D8 jalr $t9 ; sys_led_init
.text:0040E7DC li $a0, 2
.text:0040E7E0 lw $gp, 0x20+var_10($sp)
.text:0040E7E4 nop
.text:0040E7E8 la $t9, start_upnp
.text:0040E7EC nop
.text:0040E7F0 jalr $t9 ; start_upnp
.text:0040E7F4 nop
.text:0040E7F8 lw $gp, 0x20+var_10($sp)
.text:0040E7FC nop
.text:0040E800 la $t9, start_dhcpd
.text:0040E804 nop
.text:0040E808 jalr $t9 ; start_dhcpd
.text:0040E80C nop
.text:0040E810 lw $gp, 0x20+var_10($sp)
.text:0040E814 nop
.text:0040E818 la $t9, start_ntpc
.text:0040E81C nop
.text:0040E820 jalr $t9 ; start_ntpc
.text:0040E824 nop
.text:0040E828 lw $gp, 0x20+var_10($sp)
.text:0040E82C nop
.text:0040E830 la $t9, start_dns
.text:0040E834 nop
.text:0040E838 jalr $t9 ; start_dns
.text:0040E83C nop
.text:0040E840 lw $gp, 0x20+var_10($sp)
.text:0040E844 nop
.text:0040E848 la $t9, start_ddns
.text:0040E84C nop
.text:0040E850 jalr $t9 ; start_ddns
.text:0040E854 nop
.text:0040E858 lw $gp, 0x20+var_10($sp)
.text:0040E85C nop
.text:0040E860 la $t9, start_igmp_proxy
.text:0040E864 nop
.text:0040E868 jalr $t9 ; start_igmp_proxy
.text:0040E86C nop
.text:0040E870 lw $gp, 0x20+var_10($sp)
.text:0040E874 nop
.text:0040E878 la $t9, start_ipmac_bind
.text:0040E87C nop
.text:0040E880 jalr $t9 ; start_ipmac_bind
.text:0040E884 nop
.text:0040E888 lw $gp, 0x20+var_10($sp)
.text:0040E88C nop
.text:0040E890 la $t9, start_block_ipmac
.text:0040E894 nop
.text:0040E898 jalr $t9 ; start_block_ipmac
.text:0040E89C nop
.text:0040E8A0 lw $gp, 0x20+var_10($sp)
.text:0040E8A4 nop
.text:0040E8A8 la $t9, start_block_port
.text:0040E8AC nop
.text:0040E8B0 jalr $t9 ; start_block_port
.text:0040E8B4 nop
.text:0040E8B8 lw $gp, 0x20+var_10($sp)
.text:0040E8BC nop
.text:0040E8C0 la $t9, start_ddos
.text:0040E8C4 nop
.text:0040E8C8 jalr $t9 ; start_ddos
.text:0040E8CC nop
.text:0040E8D0 lw $gp, 0x20+var_10($sp)
.text:0040E8D4 nop
.text:0040E8D8 la $t9, start_monitor_rate
.text:0040E8DC nop
.text:0040E8E0 jalr $t9 ; start_monitor_rate
.text:0040E8E4 nop
.text:0040E8E8 lw $gp, 0x20+var_10($sp)
.text:0040E8EC nop
.text:0040E8F0 la $t9, start_upgraded
.text:0040E8F4 nop
.text:0040E8F8 jalr $t9 ; start_upgraded
.text:0040E8FC nop
.text:0040E900 lw $gp, 0x20+var_10($sp)
.text:0040E904 nop
.text:0040E908 la $t9, start_conntrack_limit
.text:0040E90C nop
.text:0040E910 jalr $t9 ; start_conntrack_limit
.text:0040E914 nop
.text:0040E918 lw $gp, 0x20+var_10($sp)
.text:0040E91C nop
.text:0040E920 la $t9, start_macfilter
.text:0040E924 nop
.text:0040E928 jalr $t9 ; start_macfilter
.text:0040E92C nop
.text:0040E930 lw $gp, 0x20+var_10($sp)
.text:0040E934 nop
.text:0040E938 la $t9, start_black_management
.text:0040E93C nop
.text:0040E940 jalr $t9 ; start_black_management
.text:0040E944 nop
.text:0040E948 lw $gp, 0x20+var_10($sp)
.text:0040E94C nop
.text:0040E950 la $t9, start_wlan_wps
.text:0040E954 nop
.text:0040E958 jalr $t9 ; start_wlan_wps
.text:0040E95C nop
.text:0040E960 lw $gp, 0x20+var_10($sp)
.text:0040E964 nop
.text:0040E968 la $t9, start_trakerurl
.text:0040E96C nop
.text:0040E970 jalr $t9 ; start_trakerurl
.text:0040E974 nop
.text:0040E978 lw $gp, 0x20+var_10($sp)
.text:0040E97C lw $ra, 0x20+var_8($sp)
.text:0040E980 move $v0, $zero
.text:0040E984 jr $ra
.text:0040E988 addiu $sp, 0x20
.text:0040E988 # End of function start_services
By deduction and nmap it was found out that telnetd was launched on the router, which is accessible through the WAN interface! Here it is! However, logging in failed either under the root user or under the admin user.
Busybox acts as telnetd. Let's look into it (login_main function): Well

, now it starts up before entering the password, however, the standard password “admin” is not accepted. Interesting. We look further:

That's it! Login nexxadmin, password y1n2inc.com0755, with access via WAN.
There is mtd_write in the firmware, so nothing prevents us from uploading OpenWRT directly to the flash right now, which was done by lolipopbut still it was interesting to reverse the encryption algorithm. Unfortunately, my MIPS assembly skills in my head are clearly not enough, and I experienced great discomfort only when looking at all this code, so I ordered the same router for myself, and, lo and behold, I had it 2 months later.
We continue the study

Only RX is connected, the ground is common with the laptop via USB power.
The router can be updated both through the web interface and via tftp (which, again, listens to WAN!). The tftp daemon (upgraded from rc) seems to be broken because updating through it did not lead to updating the firmware in the router, although there were no errors. It should be noted that updating firmware on tftp requires authentication with the same password as on the web interface, so it's hard to call it backdoor, rather just a misconfigured service.
I decided to investigate the firmware update precisely through tftp.
A simple upgrade through the standard tftp client led to “Upgrade not possible: Incorrect Password” from upgraded. Let's look into it:

Regular clients do not seem to be able to send tftp options, so I downloaded the tftpy python library , modified one line in the client example file, and it worked:
--- tftpy_client.py 2014-09-30 21:48:57.375550027 +0400
+++ tftpy_client.py_ 2014-09-30 21:48:50.355520342 +0400
@@ -83,7 +83,7 @@
progresshook = Progress(tftpy.log.info).progresshook
- tftp_options = {}
+ tftp_options = {'admin': ''}
if options.blksize:
tftp_options['blksize'] = int(options.blksize)
if options.tsize:
Excellent! Now it remains to deal with encryption firmware. There is a decrypto function in rc, it looks something like this:

I could not find the key in the static, so I started debugging. To debug something on the device, of course, you must first assemble the debugger. IDA Pro does not compile linux_server under MIPS (and the router is built on this architecture), so it was necessary to somehow build gdbserver under the router. The router uses the old-old kernel 2.6.21 with uClibc 0.9.28. First of all, I decided to use buildroot so that it builds both the uchib toolchain and gdbserver statically. Well, everything was assembled, it seems to start, however, when debugging through IDA Pro, the server constantly crashes, ptrace produces some strange errors, well, I think we need to rebuild it with headers from the kernel 2.6.21 and with uClibc 0.9.28, t .to. uClibc never promised binary compatibility. Ralink SDK found on the Internetwith the correct kernel version and uClibc. The GDBServer compiled by this toolchain behaved one-on-one like the old one. Unfortunately, IDA Pro has some incompatibility with gdbserver, which runs on MIPS. Fortunately, gdbserver works great with regular gdb compiled under mips (./configure --target mipsel-linux).
I very rarely debug something in bare gdb, and convenient add-ons and scripts for it work only with x86 and ARM. Fortunately, I found a repository with .gdbinit for MIPS , and the debugging convenience has increased markedly. It all happened something like this:

Ultimately, the key was found just a few lines above, which should be expected:

After I wrote the script to decrypt the firmware, lolipopsent me another one with a similar header, but from a different router. The first 4 characters (magic) she had were R3G2. Searching this line in Google, it was found that everything had already been done before us, even at the beginning of 2013 :(
In any decrypted firmware there is a Linux Kernel Image line, which is always at the same offset. This line is longer than XOR- the key, which means that we don’t need to get it from rc from different manufacturers, but we can just “find” it from this line,
but it’s not enough to unzip the firmware, we also need to pack it so that it can be updated via the web interface.As it turned out, the update function has a control count Oh, the amount of firmware:

What looks like in C like this:
for (i=0; i> 16) + 0xffff;
checksum = ~(checksum + (checksum >> 16)) & 0xffff;
printf("Checksum = 0x%04X\n", checksum);
data[i] = checksum & 0xFF;
data[i+1] = (checksum >> 8) & 0xFF;
Now we have everything we need to upload any firmware via the web interface.
References
DecryptionEncryption
Conclusion
This method is suitable for many devices on the SoC RT5350. This is probably some kind of regular way to update the firmware from the SDK.Firmware with backdoor and such poor quality force the consumer to look for normally working software for their device. lolipop added support for this device in OpenWRT, and will be added to Trunk soon. And also, yesterday the release of OpenWRT Barrier Breaker was finally released! (there is no announcement on the site yet).
That's how we live.