Close
0%
0%

Wi-Fi Router Autopsy

Breathe new life into an old Wi-Fi router: explore hardware - software connections, reverse engineer components, and test security.

Similar projects worth following
In this exciting journey of discovery and learning, I'll be dissecting an old Wi-Fi router I found in the back of a drawer. My goal is to gain a deep understanding of its inner workings, explore security vulnerabilities, and potentially unlock hidden features or repurpose it for new applications.

The subject of this project is the TP-Link TL-WR1043ND ver 1.8, a now-discontinued model that was popular in the early 2010s. Its feature set and powerful hardware for its time make it an interesting candidate for exploration.

Throughout this project, I'll share my methodologies, tools used, and lessons learned. This hands-on approach will not only provide valuable insights into router construction and security but also serve as a learning platform for those interested in embedded systems, network security, and hardware hacking.

Join me as I embark on this Wi-Fi router autopsy, turning an old piece of technology into a treasure trove of knowledge and potential innovation!

Technical Overview of the Hardware

The TP-Link TL-WR1043ND v1.8, released in the early 2010s, is a discontinued wireless N gigabit router designed for high-speed home and small office networks. At its core is a MIPS architecture powered by an Atheros AR9132 system-on-chip (SoC), clocked at 400 MHz. This processor, paired with 32 MiB of DDR RAM and 8 MiB of SPI flash storage, provides sufficient computational power for advanced networking tasks and custom firmware experimentation. The router supports the 802.11b/g/n wireless standards at 2.4 GHz, achieving theoretical speeds of up to 300 Mbps under ideal conditions, although real-world performance depends on environmental factors and antenna configuration.

Basic links

  • 1 × Tp-Link TL-WR1043ND ver 1.8

  • Chapter 3 - JTAG

    yaluke03/25/2025 at 19:38 0 comments

    As I found in chapter 1, my TP-Link TL-WR1043ND ver 1.8 router has a JTAG port available on the board. This discovery opens up exciting possibilities for deeper exploration and manipulation of the device. JTAG (Joint Test Action Group) is a powerful interface that allows direct access to the router's hardware, enabling advanced debugging, firmware extraction, and even potential security research.

    In this chapter, we'll delve into connecting to the JTAG port using a Raspberry Pi 5 as our debugging tool. This approach offers a cost-effective and accessible method for hardware enthusiasts and security researchers to interact with the router at a low level. We'll explore the capabilities of JTAG, from basic connectivity to more advanced operations like dumping the router's flash memory.

    Let's embark on this journey to unlock the full potential of our TP-Link router through the power of JTAG interfacing.

    What is JTAG?

    JTAG, which stands for Joint Test Action Group, is a powerful and versatile hardware interface standard that has become integral to electronics testing, debugging, and programming. Originally developed in the 1980s, JTAG was designed to address the challenges of testing increasingly complex printed circuit boards (PCBs) with densely packed components.

    At its core, JTAG provides a standardized method for accessing and controlling the pins of integrated circuits (ICs) on a PCB without the need for physical probing. This is achieved through a simple serial interface, typically consisting of four or five pins:

    • TCK (Test Clock)
    • TMS (Test Mode Select)
    • TDI (Test Data In)
    • TDO (Test Data Out)
    • TRST (Test Reset, optional)

    JTAG's primary functions include:

    • Boundary Scan Testing: Allows for testing interconnections between ICs on a PCB without direct physical access.
    • Debugging: Provides access to internal chip resources, enabling developers to inspect and modify registers, memory, and system state.
    • Programming: Facilitates in-system programming of devices like FPGAs and flash memory.

    The JTAG interface has become so ubiquitous that it's now found in most modern microprocessors, FPGAs, and many other types of ICs. Its versatility has made it an essential tool for hardware developers, allowing them to test, debug, and program devices throughout the development lifecycle and even after product deployment.

    Raspberry Pi 5 as a JTAG debugging tool

    The Raspberry Pi 5, released in late 2023, introduces a powerful yet cost-effective platform for JTAG debugging, particularly suited for enthusiasts and researchers working on projects like our TP-Link TL-WR1043ND router exploration. Priced at around $80 USD, it offers an accessible entry point into advanced hardware debugging.

    Key features of the Raspberry Pi 5 as a JTAG debugging tool include:

    • Improved processing power with the BCM2712 chip
    • Enhanced GPIO capabilities
    • Compatibility with standard JTAG protocols

    However, the platform does come with some limitations:

    • Limited official documentation for the new RPi I/O chipset (RP1)
    • Lack of RTCK (Return Test Clock) support, affecting adaptive JTAG clocking

    Despite these challenges, the Raspberry Pi 5 excels in firmware extraction tasks, achieving speeds of approximately 850 KB/s. However, it may show some limitations in real-time register access compared to dedicated professional debuggers.

    The platform's versatility and low cost make it an attractive option for hobbyists and researchers, especially those working on projects like our router exploration. While it requires some additional configuration and workarounds, the Raspberry Pi 5 offers a powerful and flexible solution for JTAG debugging tasks.

    Physical Connection: Raspberry Pi 5 to TP-Link JTAG Interface

    JTAG Connector Identification

    The TP-Link TL-WR1043ND v1.8 features a 14-pin EJTAG 2.6 standard header located near the serial port (labeled “JP1" on PCB):

    This aligns with OpenWRT documentation confirming MIPS EJTAG compliance. The JTAG 2.6...

    Read more »

  • Chapter 2 – Firmware Tour

    yaluke03/17/2025 at 14:58 0 comments

    The binary file dumped earlier from the flash memory is not merely a collection of random data. In this chapter, I'll demonstrate how to analyze and extract useful information from such a binary file for further analysis and potential modifications. I'll be using Kali Linux for this process, but other Linux distributions should work similarly.

    Useful links

    https://openwrt.org/toh/tp-link/tl-wr1043nd

    https://openwrt.org/docs/techref/flash.layout

    Initially, I planned to use the flash layout information provided by OpenWrt. However, I quickly realized that my router uses the original TP-Link firmware (version TL-WR1043ND_V1_140319), which differs from OpenWrt's layout. Therefore, there are no shortcuts—I must analyze the flash data manually.

    First Raw View

    Based on general information from OpenWrt documentation, I expected the following basic layout:

    • Bootloader at the beginning
    • Firmware header and kernel data following the bootloader
    • SquashFS filesystem containing Linux files
    • SoC-specific data stored at the end of the flash memory

    To verify this structure, I used `binwalk`, a tool that analyzes binary files to identify embedded filesystems, compressed data, and known signatures. Running:

    binwalk flash_data.bin 

    produced the following output:

    From this analysis, I identified several key areas:

    • 0x00000000: Bootloader section
    • 0x00020000 (128 kB): TP-Link firmware header
    • 0x00020200 (512 bytes later): Compressed Linux kernel (size: 1023.5 kB)
    • 0x120000 (1152 kB): SquashFS filesystem containing the Linux file structure

    Notably, no explicit information about SoC-specific data appeared at this stage. Thus, further manual analysis was necessary.

    Extracting Firmware Components

    Bootloader Extraction

    The bootloader occupies the first 128 kB of flash memory. To extract it into a separate file, I used the Linux `dd` command, which copies specific parts of a file based on given parameters:

    dd bs=1024 count=256 if=flash_data.bin of=bootloader.bin

    Here, `bs` specifies chunk size (1024 bytes = 1kB), and `count` specifies how many chunks to copy (128 chunks × 1024 bytes = 128kB).

    A bootloader is responsible for initializing hardware and loading an operating system. To confirm its architecture type, I ran:

    binwalk -Y bootloader.bin

    This confirmed that router uses MIPS architecture:

    TP-Link Header

    Following the bootloader is a small TP-Link header occupying exactly 512 bytes. Extracting it is straightforward:

    dd bs=512 count=1 skip=256 if=flash_data.bin of=tplink_header.bin

    Linux Kernel

    Next, I extracted the compressed Linux kernel using similar logic:

    dd bs=512 count=2047 skip=257 if=flash_data.bin of=kernel.bin

    Since this kernel is compressed, it can be manually decompressed using:

    binwalk -Me kernel.bin

    This command produces _kernel.bin.extracted folder with uncompressed Linux kernel inside. As kernel is also valid executable file we can confirm architecture using binwalk -Y, similar to the bootloader case.

    Linux Filesystem (SquashFS)

    The SquashFS filesystem starts at offset `0x120000` (1152 kB) and occupies exactly `3852370` bytes. To extract it:

    dd if=flash_data.bin bs=1 skip=1179648 count=3852370 of=filesystem.bin

     Then, to unpack its contents using `binwalk`:

    binwalk -Me filesystem.bin

      This command produces a directory containing the extracted Linux file structure:

    Alternatively, another useful tool called `sasquatch` can also handle SquashFS extraction efficiently:

    sasquatch -C lzma -be filesystem.bin

    Both methods successfully revealed the internal filesystem structure.

    Identifying SoC-Specific Data

    To locate SoC-specific data stored at the end of flash memory, I used entropy analysis (`binwalk -E`). Entropy measures randomness within data; low entropy typically indicates padding (`0x00` or `0xFF`) or uncompressed code sections, while high entropy suggests compressed or encrypted data. Running entropy analysis with standard parameters:

    ... Read more »

  • Chapter 1 – Recovering the Passwords

    yaluke03/12/2025 at 06:29 0 comments

    The router had spent the last seven years forgotten in the back of a drawer. During that time, I used a device provided by my internet service provider. After connecting the old router to power, it booted successfully and started serving a network. However, I had no idea what the passwords were—neither for Wi-Fi nor for administration access. Before resorting to pressing the reset button, I decided to experiment and see if I could somehow retrieve the passwords.

    Disassembling the Router

    Disassembly was straightforward, though reading instructions beforehand would have been beneficial—I ended up breaking two fasteners in the process. A quick inspection of the PCB revealed two connectors: one 1x4-pin and one 2x7-pin connector. Documentation found on openwrt.org confirmed these connectors as UART and JTAG interfaces:

    Connecting via UART Using Raspberry Pi 5

    Since I didn't have a USB-to-serial adapter available, I decided to use a Raspberry Pi 5 (RPi) to communicate with the router through UART. The configuration was simple:

    1. First, I enabled the serial hardware interface on the Raspberry Pi using `raspi-config`.
    2. Next, with both devices powered off, I connected them as follows:
    Raspberry Pi 5Router UART
    GND (pin 6)pin 2
    GPIO14/UART0 TX (pin 8)pin 3
    GPIO15/UART0 RX (pin 10)pin 4

    After making these connections, I powered on only the Raspberry Pi.

    Using minicom to Access Router's Serial Console

    The first tool I used for communication was `minicom`, installed on Raspberry Pi with:

    sudo apt install minicom

    Using communication parameters provided by OpenWrt documentation—baud rate: 115200, data bits: 8, parity: none, stop bits: 1, flow control: none—and the RPi UART device (`/dev/ttyAMA0`), the command line looked like this:

    minicom -b 115200 -8 -D /dev/ttyAMA0

    Minicom then waited for data from the router. Upon powering up the router, after a few seconds I saw this output:

    When seeing "Autobooting in 1 second," I quickly typed `tpl` followed by <enter> to interrupt booting and enter the boot prompt. At this prompt, various commands were available (`help` lists them all). However, only one command seemed useful for inspecting memory contents: `md` (memory display).

    Dumping Router Flash Memory

    I assumed passwords were stored somewhere within flash memory, which should be mapped into address space. Based on OpenWrt documentation (flash layout and flashing instructions), I confirmed that flash memory starts at address `0xbf000000` and occupies an 8 MB address range. This was precisely the area I wanted to dump and analyze.

    Minicom offers an option (`-C`) to log all communication into a file. Initially, my idea was to use this feature along with the `md.b` command to dump flash memory:

    Output from `md` can be parsed easily and converted into binary format for an exact copy of flash data. Unfortunately, random chunks of data occasionally went missing during dumping—I wasn't sure if this was due to issues with the router itself, Raspberry Pi hardware limitations, or something else entirely.

    Reliable Data Dumping with Python Script

    To ensure reliable data dumping—checking for missing data and retrying failed reads—I decided to write a Python script using the `pyserial` library (`pip3 install pyserial`). Here's a snippet of Python code that automates connecting to the router's boot prompt (eliminating manual typing of `tpl`):

    import serial
    from time import sleep
    
    with serial.Serial('/dev/ttyAMA0', 115200, timeout=1) as conn:
            # connect and "login"
            logged_in = False
            buffer = ''
            while(not logged_in):
                x = str(conn.read(), encoding='utf-8')
                buffer = buffer + x
                print(x, end='')
                if len(buffer) >= 24 and buffer[-24:] == 'Autobooting in 1 seconds':
                    # now we have 1 second to "login"...
                    sleep(0.1)
                    # by sending 'tpl' string to device
                    conn.write(bytes('tpl\n', 'utf-8'))
                    # let's read all the stuff before sending next command
                    x = str(conn.read(100), encoding='utf-8')
                    print(x)
                    logged_in = True
    ... Read more »

View all 3 project logs

Enjoy this project?

Share

Discussions

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates