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.
    image
    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

    image

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

    image

    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


    image
    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:

    image

    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:

    image

    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:

    image

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

    image

    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:

    image

    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

    Decryption
    Encryption

    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.

    Also popular now: