A post on the (aptly named) /dev/ttyS0 device hacking blog entitled "Reverse Engineering Serial Ports" reminded me that I had an AMX NXA-WAP250G Wireless Access Point that I’d been meaning to investigate for some time. I thought I’d document the process I went through while reverse engineering it, in the hope that it’s interesting or useful to someone.

The Firmware
Not having the device to hand, I started with what I could find out from a saved firmware update – a file named zz-img.bin, dated 2008-08-04 and 1,350,968 bytes in size. I went with what’s usually my first instinct in situations like this, and tried the file command:
zz-img.bin: ELF 32-bit MSB executable, MIPS, MIPS-II version 1 (SYSV), statically linked, stripped
It seemed likely the firmware image was actually a MIPS-architecture ELF, in which strings showed some strong indications that zlib compression was present:
oversubscribed dynamic bit lengths tree
incomplete dynamic bit lengths tree
oversubscribed literal/length tree
incomplete literal/length tree
I’ve omitted the other 14,000 lines of output!
As the only human-readable strings of characters in the output, they were quite obvious. They’re likely to be immediately recognisable to anyone who has reverse engineered firmware before, but a simple Google 1 search for any of them would be enough to come to the same conclusion.
Hoping to find out what was hiding compressed inside the file, I tried running binwalk over it; that told me nothing I didn’t already know – that I was looking at a MIPS ELF. Slightly disheartened, I hacked together a trivial Python program to naively step through the firmware image, repeatedly calling zlib.decompress until it succeeded without error, or the end of the file was reached.
A moment later, starting 19,569 bytes from the beginning of the file, decompression was successful. I now had 3,303,265 bytes of output saved to a file imaginatively named zz-img.out; file didn’t recognise it but binwalk claimed had 88 identifiable components:
DECIMAL HEX DESCRIPTION
-------------------------------------------------------------------------------------------------------
1062235 0x10355B LZMA compressed data (sig 2), properties: 0x5D, dictionary size: 554696704 bytes, uncompressed size: 50372624 bytes
2339492 0x23B2A4 Zip archive data, v0.0
2380548 0x245304 GIF image data, version 89a, 69 x 23
2381732 0x2457A4 GIF image data, version 89a, 1 x 1
2382466 0x245A82 TIFF image data, little-endian
2464692 0x259BB4 GIF image data, version 89a, 69 x 23
2465938 0x25A092 TIFF image data, little-endian
2466722 0x25A3A2 TIFF image data, little-endian
2467538 0x25A6D2 TIFF image data, big-endian
2534356 0x26ABD4 GIF image data, version 89a, 69 x 23
2535636 0x26B0D4 GIF image data, version 89a, 69 x 23
2536866 0x26B5A2 TIFF image data, little-endian
2542338 0x26CB02 TIFF image data, little-endian
2545572 0x26D7A4 GIF image data, version 89a, 69 x 23
2546740 0x26DC34 GIF image data, version 89a, 69 x 23
2809172 0x2ADD54 GIF image data, version 89a, 32 x 32
2898498 0x2C3A42 TIFF image data, little-endian
2988972 0x2D9BAC LZMA compressed data (sig 2), properties: 0x5D, dictionary size: 687865856 bytes, uncompressed size: 10 bytes
2996232 0x2DB808 Linux Journalled Flash filesystem, little endian
3021080 0x2E1918 gzip compressed data, was "HACL.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:05 2004
3021992 0x2E1CA8 gzip compressed data, was "HCfg.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:05 2004
3022612 0x2E1F14 gzip compressed data, was "HQos.htm", from NTFS filesystem (NT), last modified: Tue Sep 14 09:39:59 2004
3023176 0x2E2148 gzip compressed data, was "HSecurity.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:05 2004
3023852 0x2E23EC gzip compressed data, was "HServer.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:06 2004
3024468 0x2E2654 gzip compressed data, was "HSetup.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:06 2004
3025208 0x2E2938 gzip compressed data, was "HSetupAv.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:06 2004
3026100 0x2E2CB4 gzip compressed data, was "HWpa.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:06 2004
3026644 0x2E2ED4 gzip compressed data, was "Hfw.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:06 2004
3027024 0x2E3050 gzip compressed data, was "Hfwadv.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:06 2004
3027696 0x2E32F0 gzip compressed data, was "Hradio.htm", from NTFS filesystem (NT), last modified: Tue Sep 14 04:13:29 2004
3028572 0x2E365C gzip compressed data, was "Hsetup2.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:07 2004
3029060 0x2E3844 gzip compressed data, was "about.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:07 2004
3029296 0x2E3930 gzip compressed data, was "ap_stats.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:07 2004
3030240 0x2E3CE0 gzip compressed data, was "cfgscr.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:07 2004
3031228 0x2E40BC gzip compressed data, was "configs.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:07 2004
3032416 0x2E4560 gzip compressed data, was "index.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:12 2004
3033104 0x2E4810 gzip compressed data, was "lastupld.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:12 2004
3033376 0x2E4920 gzip compressed data, was "privacy.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:12 2004
3034432 0x2E4D40 gzip compressed data, was "privedit.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:12 2004
3036020 0x2E5374 gzip compressed data, was "privnew.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:12 2004
3037940 0x2E5AF4 gzip compressed data, was "qos.htm", from NTFS filesystem (NT), last modified: Tue Sep 14 08:43:01 2004
3039708 0x2E61DC gzip compressed data, was "radio.htm", from NTFS filesystem (NT), last modified: Thu Sep 16 12:04:50 2004
3041244 0x2E67DC gzip compressed data, was "reboot.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:13 2004
3041580 0x2E692C gzip compressed data, was "rstcfg.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:13 2004
3041828 0x2E6A24 gzip compressed data, was "scanning.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:13 2004
3042136 0x2E6B58 gzip compressed data, was "security.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:14 2004
3044496 0x2E7490 gzip compressed data, was "server.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:14 2004
3045708 0x2E794C gzip compressed data, was "setleft.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:15 2004
3046316 0x2E7BAC gzip compressed data, was "setup.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:15 2004
3047624 0x2E80C8 gzip compressed data, was "setup2.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:15 2004
3049028 0x2E8644 gzip compressed data, was "setupadv.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:15 2004
3050884 0x2E8D84 gzip compressed data, was "setupfr3.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:15 2004
3051220 0x2E8ED4 gzip compressed data, was "stafr3.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:16 2004
3051592 0x2E9048 gzip compressed data, was "stafr3a.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:16 2004
3051968 0x2E91C0 gzip compressed data, was "stafr3b.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:16 2004
3052348 0x2E933C gzip compressed data, was "staleft.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:16 2004
3053180 0x2E967C gzip compressed data, was "stalist.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:17 2004
3053920 0x2E9960 gzip compressed data, was "stastats.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:17 2004
3055432 0x2E9F48 gzip compressed data, was "survey.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:17 2004
3056192 0x2EA240 gzip compressed data, was "upldadv.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:18 2004
3057888 0x2EA8E0 gzip compressed data, was "upldprog.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:18 2004
3058180 0x2EAA04 gzip compressed data, was "upldstat.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:18 2004
3059028 0x2EAD54 gzip compressed data, was "upload.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:18 2004
3060464 0x2EB2F0 gzip compressed data, was "wpa.htm", from NTFS filesystem (NT), last modified: Fri Sep 10 04:32:37 2004
3061812 0x2EB834 GIF image data, version 89a, 1 x 1
3061856 0x2EB860 GIF image data, version 89a, 61 x 25
3062528 0x2EBB00 GIF image data, version 89a, 88 x 25
3063412 0x2EBE74 GIF image data, version 89a, 77 x 25
3067216 0x2ECD50 GIF image data, version 89a, 61 x 25
3067936 0x2ED020 GIF image data, version 89a, 364 x 390
3072756 0x2EE2F4 GIF image data, version 89a, 460 x 235
3120580 0x2F9DC4 GIF image data, version 89a, 39 x 15
3121012 0x2F9F74 GIF image data, version 89a, 77 x 25
3121820 0x2FA29C GIF image data, version 89a, 1 x 1
3121864 0x2FA2C8 GIF image data, version 89a, 179 x 120
3127352 0x2FB838 GIF image data, version 89a, 54 x 40
3127656 0x2FB968 GIF image data, version 89a, 95 x 40
3128144 0x2FBB50 GIF image data, version 89a, 1 x 40
3128192 0x2FBB80 GIF image data, version 89a, 72 x 40
3128584 0x2FBD08 GIF image data, version 89a, 94 x 25
3129540 0x2FC0C4 GIF image data, version 89a, 77 x 25
3130348 0x2FC3EC GIF image data, version 89a, 77 x 25
3131156 0x2FC714 GIF image data, version 89a, 1 x 1
3131200 0x2FC740 GIF image data, version 89a, 270 x 80
3132364 0x2FCBCC GIF image data, version 89a, 61 x 25
3133136 0x2FCED0 GIF image data, version 89a, 61 x 25
3211978 0x3102CA Linux Journalled Flash filesystem, little endian
(I initially tried binwalk v0.4.3 which output over a hundred false positive “JFFS” and “LZMA” entries. The output shown is from v0.5.0 which is much more accurate, on this sample at least.)
Of those, the gzipped ones looked like they could be interesting, with plausible names and modification dates. Using the dd and gunzip commands, I extracted one (though I understand the latest version of binwalk can do this itself) but the resulting HTML file turned out to be a fairly uninteresting part of the access point’s web interface.
Moving on, I tried strings again on zz-img.out. This time, operating on uncompressed data, the output was much more useful.
There were many references to VxWorks:
Jul 11 2008, 15:37:45
Boot parameters:
AR531XPLUS
unknown boarddata rev!
Atheros AR5315 default
There appeared to be a command line interface, complete with help:
Some of which looked particularly interesting:
find
connect to BSS X
connect
Copy file
Boot parameters
boot
Temporary factory admin
admin
One of the other strings stood out too, “OWOWOWOWOWOWOWOW”. Amusingly, a Google search for that string led me straight back to another post on the /dev/ttyS0 blog about a mystery VxWorks filesystem (later identified as MemFS).
At this point, I considered it was fairly likely the device was running VxWorks, had a command line interface of some sort, and that if it came to it, modifying the existing firmware update was at least plausible. There’s much more I could have investigated in the firmware – perhaps starting with that MemFS filesystem – but by this point I’d managed to find the actual device itself and was eager to open it up and see what it looked like inside.
The Hardware
As it turned out, I could have probably skipped the firmware analysis and jumped straight to powering the device up and taking it to pieces (not necessarily in that order).
Any router hackers out there will no doubt find that board familiar; it looks just like a Fonera 2100. The FON2100 router is based on the Atheros AR5315 SoC, which matched up with what I’d seen in my firmware analysis. The part numbers of the Hynix HY57V281620ETP-H memory is also consistent, while the ST 25P32V6P flash chip is slightly different.
From some further research, I discovered that the Fonera 2100 is actually an Accton MR3201A in disguise. The Edge-Core WA3101, Philips SNR6500, SMC WEBT-G, Siemens Gigaset WLAN Repeater 108, and the Meraki Mini all appear to be slightly (if that) modified versions of the same design. This was great news, because it meant reverse engineering my esoteric router would be enormously simpler than I might have expected – there’s plenty of information about those other routers about there, particularly concerning running Linux on them.
Delving into the information that the OpenWRT and DD-WRT projects had about these routers, I found out that most, if not all, of them had an ST 25P64V6P – 8MB – flash, while the WAP250G has a 25P32V6P with only 4MB capacity. That was annoying, but among the many published hardware hacks is an SD card mod which would massively improve the amount of storage available.
Aside from some fanciful ideas about future hardware modifications, the most pertinent information I’d found out was that Fonera’s serial port pinout is well known and published. To connect to it, I needed something that would talk serial at TTL signal levels (3.3V) and not RS-232 (somewhere around 15V). Just as I was considering cutting up a USB phone cable, I realised that I had a full-blown Linux system with a handily accessible serial port that runs at the correct voltage – my Raspberry Pi.
The Raspberry Pi
I cut up and soldered together some cables from an old PC case that would previously have connected the external buttons to the PC’s motherboard – the ones that would have gone to the HDD LED and reset switch of the PC are quite obvious in the picture below. The GPIO pins of the Pi are well documented and the OpenWRT page about the Fonera includes its serial pinout, which I confirmed with a multimeter, as described in the post that set me off with this whole project.

With Raspbian Wheezy running on the Pi, using the serial port was quite straightforward. I had to edit cmdline.txt on the SD card to disable the serial console on /dev/ttyAMA0, otherwise the Pi would be outputting kernel messages over it as it booted up. Likewise I commented out the getty line from /etc/inittab on the system to prevent it from issuing a login prompt over the serial port.
With the Pi connected to the powered-up router as pictured above, I fired up minicom, told it to connect to ttyAMA0 with the baud rate 9600 and 8N1 (rarely a bad guess) and gingerly tapped “enter”.
I was instantly greeted with a login prompt. Neat! I knew from the 250G’s documentation what the web interface default credentials were, so I tried those – ‘Admin’ and ’1988′:
Password: ****
ACCTON Access Point Rev v1.0.6.0
wlan[0,0] -> help
List of Access Point CLI commands:
wlan[0,0] ->
As you can see, the serial connection works, the login was successful but the ‘help’ output I initially found while examining the firmware was absent. I tried on of the commands I’d seen in that help text:
AP software v1.0.6.0
That worked, so it seemed like the ‘help’ might be correct, so I wasn’t sure why I couldn’t see it. Looking back at that help text for some other commands to try, one in particular stood out – ‘admin’. The line above it – presumably the description of the command – said “Temporary Factory admin” so I tried it:
Password: ****
Sorry
wlan[0,0] -> admin
Password:
Ok
It asked me for a password; I tried ’1998′ which was incorrect. Just as I was considering loading the firmware up in IDA or looking through it for more suspicious looking strings, I tried again and just hit enter – a blank password. That worked!
Interestingly, after using the ‘admin’ command, ‘help’ now works and outputs the full unabridged text I had extracted from the firmware earlier:
List of Access Point CLI commands:
? -- Display CLI Command List
i -- Display task information
add remoteWbr -- Add a remote Wireless Bridge
admin -- Temporary factory admin
boot flash -- Boot from flash
boot ethernet -- Boot from network
cp -- Copy file
config wlan -- config wlanX
config virtualap -- config virtual ap
config bss -- config bss
connect bss -- connect to bssX
del acl -- Delete Access Control List
del key -- Delete Encryption key
del remoteWbr -- Delete a remote Wireless Bridge
find bss -- Find BSS
find bssPassive -- Find BSS with passive scans
find channel -- Find Available Channel
find all -- Find All BSS
format -- Format flash filesytem
MFT_Ant -- Setting Antenna Status
MFT_Boot_Ver -- MFT Show boot code version .
MFT_Led -- MFT Setting Led Traffic Rate .
MFT_Show_Boot -- Show boot up message
start_tr -- start traffic rate monitor
stop_tr -- stop traffic rate monitor
bootrom -- Update boot rom image
ftp -- Software update via FTP
get 11gonly -- Display 11g Only Allowed
get 11goptimize -- Display 11g Optimization Level
get 11goverlapbss -- Display Overlapping BSS Protection
get abolt --
get acl -- Display Access Control List
get aging -- Display Aging Interval
get antenna -- Display Antenna Diversity
get arptable -- Display ARP Table
get route -- Display Route Table
get association -- Display Association Table
get authentication -- Display Authentication Type
get autochannelselect -- Display Auto Channel Select
get basic11b -- Display Basic 11b Rates
get basic11g -- Display Basic 11g Rates
get beaconinterval -- Display Beacon Interval
get bootLine -- Display the bootLine
get burstSeqThreshold -- Display Max Number of frames in a Burst
get burstTime -- Display Burst Time
get cacheperf -- Display the cache performance counters
get calibration -- Display Noise And Offset Calibration Mode
get cckTrigHigh -- Display Higher Trigger Threshold for CCK Phy Errors for ANI Control
get cckTrigLow -- Display Lower Trigger Threshold for CCK Phy Errors for ANI Control
get cckWeakSigThr -- Display ANI Parameter for CCK Weak Signal Detection Threshold
get channel -- Display Radio Channel
get cipher -- Display Encryption cipher
get compproc -- Display Compression scheme
get compwinsize -- Display Compression Window Size
get config -- Display Current AP Configuration
get countrycode -- Display Country Code
get cpu -- Display CPU Loading
get radarnewchannel -- Display radar new channel
get csabeaconcount -- Display CSA Beacon Count
get ctsmode -- Display CTS mode
get ctsrate -- Display CTS rate
get ctstype -- Display CTS type
get domainsuffix -- Display Domain Name Server suffix
get dtim -- Display Data Beacon Rate (DTIM)
get enableANI -- Display Adaptive Noise Immunity Control On/Off
get encryption -- Display Encryption Mode
get extendedchanmode -- Display Extended Channel Mode
get firStepLvl -- Display ANI Parameter for FirStepLevel
get fragmentthreshold -- Display Fragment Threshold
get frequency -- Display Radio Frequency (MHz)
get gateway -- Display Gateway IP Address
get gbeaconrate -- Display 11g Beacon Rate
get gdraft5 -- Display 11g Draft 5.0 compatibility
get groupkeyupdate -- Display Group Key Update Interval (in Seconds)
get hardware -- Display Hardware Revisions
get hostipaddr -- Display Host IP Address
get information -- Display Manufacture Information
get interVF -- Display Inter Vap Forwarding State
get intraVF -- Display Intra Vap Forwarding State
get ipaddr -- Display IP Address
get ipmask -- Display IP Subnet Mask
get jsw -- Display Jumpstart Mode
get jsP2PassPhrase -- Display JS-P2 passphrase
get key -- Display Encryption Key
get keyentrymethod -- Display Encyrption Key Entry Method
get keysource -- Display Source Of Encryption Keys
get login -- Display Login User Name
get minimumrate -- Display Minimum Rate
get nameaddr -- Display IP address of name server
get nf -- Display Noise Floor
get noiseImmunityLvl -- Display ANI Parameter for Noise Immunity Level
get ofdmTrigHigh -- Display Higher Trigger Threshold for OFDM Phy Errors for ANI Control
get ofdmTrigLow -- Display Lower Trigger Threshold for OFDM Phy Errors for ANI Control
get ofdmWeakSigDet -- Display ANI Parameter for OFDM Weak Signal Detection
get overRidetxpower -- Display Tx power override
get operationMode -- Display Operation Mode
get pktLogEnable -- Display Packet Logging Mode
get power -- Display Transmit Power Setting
get pppoe -- display the PPPoE setting
get pppoeInfo -- display the PPPoE setting
get pvid -- Display the VLAN Tag
get quietAckCtsAllow -- Display if Ack/Cts frames are allowed during quiet period
get quietDuration -- Display Duration of quiet period
get quietOffset -- Display Offset of quiet period into the beacon period
get radiusname -- Display RADIUS server name or IP address
get radiusport -- Display RADIUS port number
get rate -- Display Data Rate
get reg -- Display the register contents at the given offset
get telecregstatus -- Display Telec 5GHz Regulatory Update status
get remoteAp -- Display Remote Ap's Mac Address
get reset -- Display # of resets
get remoteWbr -- Display configured Remote Wireless bridges
get hwtxretries -- Display HW Transmit Retry Limit
get swtxretries -- Display SW Transmit Retry Limit
get rogueAPDetect -- Display Rogue AP Detection Mode
get bkScaninterval -- Display Background Scan Interval for Rogue AP detection
get rtsthreshold -- Display RTS/CTS Threshold
get shortpreamble -- Display Short Preamble Usage
get shortslottime -- Display Short Slot Time Usage
get snmp -- Display SNMP Community Name
get sntpserver -- Display SNTP/NTP Server IP Address
get softwareretry -- Display Software Retry
get spurImmunityLvl -- Display ANI Parameter for Spur Immunity Level
get ssid -- Display Service Set ID
get ssidsuppress -- Display SSID Suppress Mode
get active -- Display Active (up) Mode
get station -- Display Station Status
get SuperG -- Display SuperG Feature Status
get systemname -- Display Access Point System Name
get telnet -- Display Telnet Mode
get timeout -- Display Telnet Timeout
get tzone -- Display Time Zone Setting
get updateparam -- Display Vendor Default Firmware Update Params
get upsd -- Display UPSD Mode
get uptime -- Display UpTime
get vaps -- Display Number of Virtual APs
get vlan -- Display VLAN Operational State
get qos -- Display QoS Mode
get watchdog -- Display Watchdog Mode
get wds -- Display WDS Mode
get wep -- Display Encryption Mode
get wirelessmode -- Display Wireless LAN Mode
get wmm -- Display WMM Mode
get wmmParamBss -- Display WMM parameters used by STA in this BSS
get wmmParam -- Display WMM parameters used by this AP
get usrp -- Display the User Priority
get wlanstate -- Display wlan state
get xrpoll -- Display XR poll
get xrbss -- Display XR Bss Info
get xrFragmentThreshold -- Display XR fragment threshold
get mtu -- Display ppp MTU
help -- Display CLI Command List
Lebradeb -- Disable reboot during radar detection
ls -- list directory
mem -- system memory statistics
mv -- Move file
netpool -- Display Netpool usage
np -- Network Performance
ns -- Network Performance Server
ping -- Ping
pktLog -- Packet Log
radar! -- Simulate radar detection on current channel
reboot -- Reboot Access Point
rm -- Remove file
run -- Run command file
quit -- Logoff
set 11gonly -- Set 11g Only Allowed
set 11goptimize -- Set 11g Optimization Level
set 11goverlapbss -- Set Overlapping BSS Protection
set abolt --
set acl -- Set Access Control List
set aging -- Set Aging Interval
set antenna -- Set Antenna
set authentication -- Set Authentication Type
set autochannelselect -- Set Auto Channel Selection
set basic11b -- Set Use of Basic 11b Rates
set basic11g -- Set Use of Basic 11g Rates
set beaconinterval -- Modify Beacon Interval
set bkScaninterval -- Modify Background Scan Interval for Rogue AP Detection
set board -- Set the board data
set bootLine -- Change the bootline
set burstSeqThreshold -- Set Max Number of frames in a Burst
set burstTime -- Set Burst Time
set cachePerf -- Begin cache performance monitoring
set calibration -- Set Calibration Period
set cckTrigHigh -- Set Higher Trigger Threshold for CCK Phy Errors For ANI Control
set cckTrigLow -- Set Lower Trigger Threshold for CCK Phy Errors For ANI Control
set cckWeakSigThr -- Set ANI Parameter for CCK Weak Signal Detection Threshold
set channel -- Set Radio Channel
set cipher -- Set Cipher
set compproc -- Set Compression Scheme
set compwinsize -- Set Compression Window Size
set consolelog -- Set Console Log Enable Disable
set countrycode -- Set Country Code
set radarnewchannel -- Set radar new channel
set csabeaconcount -- Set CSA Beacon Count
set ctsmode -- Set CTS Mode
set ctsrate -- Set CTS Rate
set ctstype -- Set CTS Type
set domainsuffix -- Set Domain Name Server Suffix
set dtim -- Set Data Beacon Rate (DTIM)
set enableANI -- Turn Adaptive Noise Immunity Control On/Off
set encryption -- Set Encryption Mode
set extendedchanmode -- Set Extended Channel Mode
set factorydefault -- Restore to Default Factory Settings
set firStepLvl -- Set ANI Parameter for FirStepLevel
set fragmentthreshold -- Set Fragment Threshold
set frequency -- Set Radio Frequency (MHz)
set gateway -- Set Gateway IP Address
set gbeaconrate -- Set 11g Beacon Rate
set groupkeyupdate -- Set Group Key Update Interval (in Seconds)
set gdraft5 -- Set 11g Draft 5.0 compatibility
set getsnmp -- Modify Get SNMP Community Name
set hostipaddr -- Set Host IP address
set interVF -- Set Inter Vap Forwarding State
set intraVF -- Set Intra Vap Forwarding State
set ipaddr -- Set IP Address
set ipmask -- Set IP Subnet Mask
set jsw -- Set Jumpstart Mode
set jsp2Passwd -- Set JS-P2 password
set key -- Set Encryption Key
set keyentrymethod -- Select Encryption Key Entry Method
set keysource -- Select Source Of Encryption Keys
set login -- Modify Login User Name
set minimumrate -- Set Minimum Rate
set minimumrate -- Set Minimum Rate
set minimumrate -- Set Minimum Rate
set minimumrate -- Set Minimum Rate
set minimumrate -- Set Minimum Rate
set nameaddress -- Set Name Server IP address
set noiseImmunityLvl -- Set ANI Parameter for Noise Immunity Level
set ofdmTrigHigh -- Set Higher Trigger Threshold for OFDM Phy Errors for ANI Control
set ofdmTrigLow -- Set Lower Trigger Threshold for OFDM Phy Errors for ANI Control
set ofdmWeakSigDet -- Set ANI Parameter for OFDM Weak Signal Detection
set overRidetxpower -- Set Tx power override
set operationMode -- Set operation Mode
set password -- Modify Password
set passphrase -- Modify Passphrase
set pktLogEnable -- Enable Packet Logging
set power -- Set Transmit Power
set pppoe -- Enable the PPPoE
set pppoePassword -- Set the PPPoE password
set pppoeUsername -- Set the PPPoE username
set pvid -- Set the VLAN Tag
set quietAckCtsAllow -- Allow Ack/Cts frames during quiet period
set quietDuration -- Duration of quiet period
set quietOffset -- Offset of quiet period into the beacon period
set radiusname -- Set RADIUS name or IP address
set radiusport -- Set RADIUS port number
set radiussecret -- Set RADIUS shared secret
set rate -- Set Data Rate
set rate -- Set Data Rate
set rate -- Set Data Rate
set rate -- Set Data Rate
set rate -- Set Data Rate
set reg -- Set Register Value
set telecregupdate -- Perform Telec Regulatory Update
set telecregupdatereverse -- Perform Reverse of Telec Regulatory Update
set regcapbitswrite -- Write Regulatory Domain Capability bits to EEPROM
set regulatorydomain -- Set Regulatory Domain
set remoteAP -- Set Remote AP's Mac Address
set hwtxretries -- Set HW Transmit Retry Limit
set swtxretries -- Set SW Transmit Retry Limit
set rogueAPDetect -- Set Rogue AP Detection Mode
set rtsthreshold -- Set RTS/CTS Threshold
set shortpreamble -- Set Short Preamble
set shortslottime -- Set Short Slot Time
set setsnmp -- Modify Set SNMP Community Name
set sntpserver -- Set SNTP/NTP Server IP Address
set softwareretry -- Set Software Retry
set spurImmunityLvl -- Set ANI Parameter for Spur Immunity Level
set ssid -- Set Service Set ID
set ssidsuppress -- Set SSID Suppress Mode
set active -- Set Active (up) Mode
set station -- Set Station Skype Authentication
set SuperG -- Super G Features
set systemname -- Set Access Point System Name
set telnet -- Set Telnet Mode
set timeout -- Set Telnet Timeout
set tzone -- Set Time Zone Setting
set updateparam -- Set Vendor Default Firmware Update Params
set vaps -- Set Number of Virtual APs
set upsd -- Set UPSD Mode
set vlan -- Set VLAN Operational State
set qos -- Set QoS Mode
set watchdog -- Set Watchdog Mode
set wds -- Set WDS Mode
set wep -- Set Encryption Mode
set wlanstate -- Set wlan state
set wirelessmode -- Set Wireless LAN Mode
set usrp -- Set the User Priority
set wmm -- Set WMM Mode
set wmmParamBss -- Set WMM parameters used by STAs in this BSS
set wmmParam -- Set WMM parameters used by this AP
set xr -- Set XR
set nat -- Set NAT/DHCP Server
set mtu -- Display ppp MTU
spy report -- Print spy report
spy start -- Start spy
spy stop -- Stop spy
start wlan -- Start the current wlan
stop wlan -- Stop the current wlan
timeofday -- Display Current Time of Day
version -- Software version
nat_tcp -- nat_tcp_show
nat_udp -- nat_udp_show
I tried a few commands to get a feel for the device:
Product SN :
AP Software : v1.0.6.0
MAC Address : 00-12-CF-80-46-2C
wlan[0,0] -> get updateparam
Vendor Default Update Parameters:
Hostname:
Username:
Password:
Imagepath:
Imagename:
Flag: 0x0
wlan[0,0] -> ls
zz-img.bin 1350968
apcfg 6886
apcfg.bak 6885
2101248 bytes free
wlan[0,0] -> MFT_Boot_Ver
Boot code version is 1.1.0
wlan[0,0] -> bootrom
Not enough parameters!
It looked like there was a filesystem on the flash, containing the zz-img.bin firmware I originally started with, and another file called apcfg. Using the ‘ftp’ command I’d seen in ‘help’ I uploaded both of these files to an FTP server running on the Pi. The md5sum of the new zz-img.bin matched the firmware image I started with, while the apcfg was, as the name implies, a configuration file. It begins:
magic Ar52xxAP
fwc: 8
login Admin
nameaddr 8.8.8.8
domainsuffix
RADIUSaddr
RADIUSport 1812
RADIUSsecret
password 1988
(At some point, someone – probably me – must have configured it with Google’s Public DNS service running on the IP address 8.8.8.8)
As I belatedly found out, all of these commands work fine over the telnet interface that’s also running on the router. I should probably have tried that earlier, but I was particularly interested in gaining access to the bootloader on the router to see if I could persuade it to boot up a different firmware. Eager to see if that was possible, I typed ‘reboot’ and crossed my fingers:
0x80ed2750 (tCliTask): wlan0: vportBSSEndStop -- already stopped!
Rebooting AP...
ar531xPlus rev 0x00000086 firmware startup...
Accton boot code version 1.1.0
4 3 00
auto-booting...
Attached TCP/IP interface to ae0.
Warning: no netmask specified.
Attaching network interface lo0... done.
Attaching to TFFS... Attaching to TFFS... done.
Loading /fl/zz-img.bin...Boot web up ...
1456176
Starting at 0x804846e0...
/fl/ - Volume is OK
Reading Configuration File "/fl/apcfg".
Configuration file checksum: 85c2c is good
Attaching interface lo0...done
wireless access point starting...
Auto Channel Scan selected 2412 MHz, channel 1
wlan0 Ready
Ready
Success! Hitting enter got me back to the login prompt, so that appeared to be the sum total of the bootup messages. Soft-rebooting the device like this (rather than powering it up with the Pi attached) was fortuitous as the router has the same bug as the Fonera; having something already connected to the serial interface when it’s powered on causes it to hang and produce no serial output.
Trying to interrupt the boot loader, after much trial and error I hit ‘Esc’ during what’s evidently supposed to be a countdown that appears just before the “auto-booting” message. That dropped me into what looked like a command prompt, so I tried ‘help’ again:
oot]: help
? - print this list
@ - boot (load and go)
p - print boot params
c - change boot params
L - ACCTON MFT Led Test
e - print fatal exception
v - print version
B - change board data
S - show board data
n netif - print network interface device address
$dev(0,procnum)host:/file h=# e=# b=# g=# u=usr [pw=passwd] f=#
tn=targetname s=script o=other
boot device: tffs=drive,removable file name: /tffs0/vxWorks
Boot flags:
0x02 - load local system symbols
0x04 - don't autoboot
0x08 - quick autoboot (no countdown)
0x20 - disable login security
0x40 - use bootp to get boot parameters
0x80 - use tftp to get boot image
0x100 - use proxy arp
available boot devices:Enhanced Network Devices
ae0 tffs
This is the standard VxWorks “BSP” bootloader, and the commands it lists works as advertised:
boot device : tffs:
unit number : 0
processor number : 0
file name : /fl/zz-img.bin
inet on ethernet (e) : 192.168.1.240:0xffffff00
flags (f) : 0x0
other (o) : ae
[Boot]: c
'.' = clear field; '-' = go to previous field; ^D = quit
boot device : tffs:0
processor number : 0
host name :
file name : /fl/zz-img.bin
inet on ethernet (e) : 192.168.1.240:0xffffff00
inet on backplane (b):
host inet (h) :
gateway inet (g) :
user (u) :
ftp password (pw) (blank = use rsh):
flags (f) : 0x0
target name (tn) :
startup script (s) :
other (o) : ae
[Boot]: S
name: SAP2315A-FLF-38FT
magic: 35333131
cksum: a943
rev: 5
major: 1
minor: 0
pciid: 0013
wlan0: yes 00:12:cf:80:46:2d
wlan1: no ff:ff:ff:ff:ff:ff
enet0: yes 00:12:cf:80:46:2c
enet1: no ff:ff:ff:ff:ff:ff
localbus: no ff:ff:ff:ff:ff:ff
PCI: no ff:ff:ff:ff:ff:ff
uart0: yes
sysled: no, gpio 0
factory: yes, gpio 6
serclk: internal
cpufreq: calculated 184000000 Hz
sysfreq: calculated 92000000 Hz
memcap: disabled
watchdg: enabled
product sn:
country code: NA
hardware rev: R01
product name: SAP2315A-FLF-38FT
hardware id: 0
manufacturing date: 20080205
Wireless Bridge is not supported
Boot code version : 1.1.0
[Boot]: v
CPU: SAP2315A-FLF-38FT
BSP version: 1.1.0
Creation date: Aug 17 2006, 19:47:11
I was pleased to see that loading a boot image over the network was supported. To try it, I used the ‘c’ command seen above to change the boot device to ae0, entered the IP address of the Pi, the path to its local copy of zz-img.bin and set the flags value to 0×80 (“use tftp to get boot image”).
Without that flag, the BSP would try to use ordinary FTP (as opposed to TFTP) which I encountered some issues with (“Error loading file: errno = 0xDD” 2). Being somewhat simpler, TFTP was easier to get working – I just installed acftpd on the Pi, verified from my laptop that I could download a file from it, then rebooted the router.
I was slightly surprised to see it work! Other than a slightly different “Loading” message, the router fetched its firmware from the Pi and booted up into it as normal. This told me two things, firstly that as long as I could still access the bootloader I had a potential way to recover the device from any meddling gone wrong, and secondly that BSP would fetch and execute an ELF image.
I’d noted earlier that all of the other routers in this family I could find reportedly ran Linux out of the box. It seemed that using the same RedBoot bootloader that they did would help get me towards my vague long-term goal for getting Linux going on this router too. It would also prove that I could run arbitrary code on the device.
RedBoot
Getting a copy of RedBoot for this router was an interesting learning experience – most people aren’t interested in an ELF executable of it, they want a stripped down ‘ROM’ version to flash directly to their device. I certainly wanted to make sure it would work before I thought about going that far, and not finding any suitable pre-built images, I decided to build my own. That would also help with the issue of the 250G’s flash memory size being different to that of the Fonera.
As the Fonera 2100 is so well known, there are plenty of logs out there of RedBoot booting on it. All of them contained the line “Board: ap51″ which was very helpful in helping me narrow down what I was looking for. That led me to Micro Redboot, which seemed to be almost exactly what I was looking for. Unfortunately I failed to get it to build – unfortunately the world, and particularly gcc, seems to have moved on in the years since most router RedBoot trees were last built, resulting in all sorts of incompatibilities and syntax errors when attempting to build them with a modern toolchain.
I wish I’d noticed this before spending the time I did on Micro Redboot, but knowing that the WAP250G was practically a clone of the Meraki Mini was very helpful, because they provide their source code, including the version of RedBoot they use. Building it turned out to be straightforward, as the file redboot-ap61.tar.gz – despite the ‘61’ in the name – can also be used to build an ap51 RedBoot, and even contains the i386 Linux toolchain needed to do so.
After unpacking that archive under Linux and examining the Makefile, building a customized RedBoot was almost as simple as typing:
Knowing the values to use for the RAM and flash size was straightforward, being identifiable from the markings on the chips themselves. The Ethernet PHY was harder, if only because I couldn’t see it on the board. Various Fonera-hacking websites told me it was an “Altima AC101″ (which is printed on a chip on the bottom of the board), but how that mapped to the choices I had (“admtek”, “marvell”, “realtek”, “icplus” or “kendin”) I had no idea. So I tried the first one.
Of course, when I said building it was “almost as simple” as the command above, I hadn’t factored in the error that would appear partway through the build process:
That was caused by the use of some obsolete syntax (“tail +2″ should be “tail -n2″ since 2007 or so!) and could be corrected by setting the _POSIX2_VERSION variable in the environment before running make:
I set the TFTPPATH variable to somewhere under my home directory (rather than the default /tftpboot) so I’d have permission to write to it. After typing the above, and a few seconds of compilation, I now had two new files: ap51-4mb-16mb.ram and ap51-4mb-16mb.ram. The former is the ELF image I needed.
total 752
-rwxr-xr-x 1 james james 601653 Nov 28 18:28 ap51-4mb-16mb.ram
-rwxr-xr-x 1 james james 158816 Nov 28 18:28 ap51-4mb-16mb.rom
The (relatively) huge size of the ELF (almost 600KB!) surprised me for a moment, but as file noted, the file wasn’t stripped of debugging symbols. The mipsisa32-elf-strip tool included in the toolchain made short work of those. I was left with a with a 152KB ELF, which I uploaded to the Pi and placed in the tftp directory. Switching back to minicom, I accessed the bootloader on the router and changed it to boot this new file, which was just a case of changing the filename as it was already set up to boot over TFTP. I then tried booting it up:
Attached TCP/IP interface to ae0.
Attaching network interface lo0... done.
Loading... 250448
Starting at 0x800410bc...
+**Warning** FLASH configuration checksum error or invalid key
Use 'fconfig -i' to [re]initialize database
Invalid PHY ID1 for enet0 port0. Expected 0x0243, read 0x0022
... waiting for BOOTP information
Ethernet eth0: MAC address 00:12:cf:80:46:2c
Can't get BOOTP info for device!
RedBoot(tm) bootstrap and debug environment [RAM]
Non-certified release, version v1.3.0 - built 18:28:43, Nov 28 2012
Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
Board: ap51
RAM: 0x80000000-0x81000000, [0x8007e250-0x80fe1000] available
FLASH: 0xa8000000 - 0xa83f0000, 64 blocks of 0x00010000 bytes each.
RedBoot>
Wow. RedBoot loaded fine – though the “Invalid PHY ID1″ message told me that I’d guessed wrong when choosing the PHY earlier. The “Expected 0×0243, read 0×0022″ detail was extremely useful though – buried in the RedBoot source, in a file called rtPhy.h I found this:
which contained the comment:
* rtPhy.h - definitions for the ethernet PHY.
* This code supports a simple 1-port ethernet phy, Realtek RTL8201BL,
* and compatible PHYs, such as the Kendin KS8721B.
* All definitions in this file are operating system independent!
*/
That looked promising, so I tried rebuilding RedBoot with the ENET_PHY value set to ‘realtek’. Unfortunately, an unsatisfied constraint – that on the AR531X platform the PHY could be any of the types I listed except ‘realtek’ (typical) – caused the build to fail. The helpful comment above led me to try ‘kendin’ instead, and that both built and booted fine:
Use 'fconfig -i' to [re]initialize database
PHY ID is 0022:5521
... waiting for BOOTP information
Ethernet eth0: MAC address 00:12:cf:80:46:2c
IP: 192.168.0.10/255.255.255.0, Gateway: 192.168.0.1
Default server: 192.168.0.1
RedBoot(tm) bootstrap and debug environment [RAM]
Non-certified release, version v1.3.0 - built 18:48:12, Nov 28 2012
Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
Board: ap51
RAM: 0x80000000-0x81000000, [0x8007d6f0-0x80fe1000] available
FLASH: 0xa8000000 - 0xa83f0000, 64 blocks of 0x00010000 bytes each.
RedBoot> bdshow
name: SAP2315A-FLF-38FT
magic: 35333131
cksum: a943
rev: 5
major: 1
minor: 0
pciid: 0013
wlan0: yes 00:12:cf:80:46:2d
wlan1: no ff:ff:ff:ff:ff:ff
enet0: yes 00:12:cf:80:46:2c
enet1: no ff:ff:ff:ff:ff:ff
uart0: yes
sysled: no, gpio 0
factory: yes, gpio 6
serclk: internal
cpufreq: calculated 184000000 Hz
sysfreq: calculated 92000000 Hz
memcap: disabled
watchdg: enabled
serialNo: <Not a string: 0xA83E007C>
Watchdog Gpio pin: 65535
secret number: <Not a string: 0xA83E008A>
It even set an IP address over BOOTP, so the network interface was clearly working.
RedBoot’s ‘help’ output is well known, so I won’t paste it here, but one of the reasons I wanted to run it in the first place was this command:
x -b <location> [-l <length>] [-s] [-1|2|4]
The RedBoot startup banner lists RAM and FLASH memory locations and sizes, so I speculated that I could use that command to dump their contents over the serial interface. After making sure minicom was logging everything to disk (or rather the SD card on the Pi), I dumped the flash contents like so:
A8000000: 10 00 01 4F 00 00 00 00 10 00 02 04 00 00 00 00 |...O............|
A8000010: 10 00 06 78 00 00 00 00 10 00 06 76 00 00 00 00 |...x.......v....|
A8000020: 10 00 06 74 00 00 00 00 10 00 06 72 00 00 00 00 |...t.......r....|
A8000030: 10 00 06 70 00 00 00 00 10 00 06 6E 00 00 00 00 |...p.......n....|
...
(I’ve altered the spacing slightly to get it to fit neatly.)
The actual output was of course 258,048 (0x3F0000) lines long, and I wish I’d thought to increase the baud rate before typing the command, as it took several hours to complete over the 9600 baud connection!
A couple of lines of Python code was sufficient to turn the dumped output into a binary image of the flash contents, exactly 4MB in length. I was conscious that dumping 20MB (before conversion) of hex dump over a bodged-together serial connection with no handshaking might not be very reliable, but luckily there was another RedBoot command to help:
cksum -b <location> -l <length>
Handily, it accepts the same parameters as the ‘dump’ command, and I used it to calculate a checksum of the flash contents:
POSIX cksum = 3466121872 4128768 (0xce98d290 0x003f0000)
I was momentarily dismayed though when the CRC32 of my dumped binary didn’t match that value, but looking at the above again I started wondering what exactly the “POSIX algorithm” was referring to. As I had the source code to hand I could find out easily, and in the process of looking at posix_crc.c in the RedBoot source, found what’s probably the most useful source code comment I have ever read:
// Same basic algorithm as CRC-16, but the bits are defined in the
// opposite order. This computation matches the output of the
// Linux 'cksum' program.
Well, that’s handy. Sure enough:
3466121872 4128768 rom.bin
At this point I was fairly sure that I had an accurate dump of the entire flash contents from the router. Even if I break the bootloader somehow, I can hopefully find a way to re-flash that image back to the chip, either via a JTAG cable or by physically de-soldering it from the board, if it came to that. Having said that, if it did come to that, I’d probably just put an 8MB chip in its place and flash it with the dump from a Fonera 2100 or a Meraki Mini.
From a reverse engineering perspective, the dumped data turns out to be reasonably interesting. Presumably for wear levelling purposes, slightly changed copies of the apcfg file are spread out fairly evenly over the flash, including details of all of the SSIDs this router has previously been configured with.
Next, I’ll probably use RedBoot to flash itself directly to the device, using the ‘fis’ commands it provides. ‘fis list’ shows what looks like garbage at the moment:
Name FLASH addr Mem addr Length Entry point
AP2315A-FLF-38FT 0x00FFFFFF 0x00323030 0x38303230 0x35000031
<Not a string: 0x80FF0000> 0x2D464C46 0x2D333846 0x54006566 0x61756C74
I assume that’s due to the flash block it would use to store that information being used by VxWorks for a different purpose. ‘fis create’ would probably fix that, but I’d like to be more sure before I try!
Once RedBoot is permanently on the device, I’ll use it to boot Linux, either DD-WRT or OpenWRT most likely; first over the network and once I’m satisfied it works as expected, directly from flash. Longer term I’ll probably perform the Fonera SD card mod, and I have a vague idea about using the router as an I²C or SPI controller interfaced to some LED lighting strips.
Final Notes (TL;DR)
I now know that almost everything here could have been performed over the telnet connection without opening the device up at all; the ‘boot ethernet’ command can be used to instruct the bootloader to load an image over the network. The change persists between reboots, though holding down the reset button can be used to reset the unit to factory defaults and hence boot again from flash. That could be used to recover from failed attempts to network boot.
Likewise, RedBoot can be connected to over telnet once it has loaded, so in theory the whole process of re-flashing the device with a new bootloader and operating system could be done remotely. The procedure would take some refinement though.
During the research for this post, I found these instructions for flashing a D-Link DWL-2100AP over its serial console. They look very similar to what I was planning on doing to flash RedBoot to the WAP250G, the 2100AP is based on the same architecture and has the same RAM and flash size (though it’s not connected through SPI, so there are differences). If the 2100AP has a telnet accessible shell, and it has the ‘boot ethernet’ command, it should be possible to flash it to Linux without opening it up, too. According to that router’s official documentation [PDF] though, that command is missing. I think I might have one in a box somewhere, if I find it I’ll give it a try.
After dumping the flash contents, I did so for the RAM too. I booted VxWorks, then soft rebooted into RedBoot via the BSP bootloader in as few steps as I could. I didn’t bother checksumming it due to its volatile nature, but I was pleased to see that easily identifiable chunks of VxWorks code remained visible in the resulting 16MB file. I’ve not read about anyone using RedBoot to dump the entire RAM or ROM contents of a device before, so I think this technique has a certain novelty to it. I now have a firmware image, its decompressed contents and a partial memory dump from running code to investigate should I wish to do so further.
I enjoyed finding out more about what makes this little router tick, and hope to find something useful to do with it soon!

I was with you all the way to “aptly named”!
How did you learn all this? Makes me feel bad for asking you to PR check 100 urls! It’s like asking Einstein to do your bookkeeping…
Wow, that’s one amazing piece of detective work. I used to do the level 3 support for Proteon back in the day and have decoded many a core dump. It was a lot easier than this because it was done in native hex and I didn’t need to know Linux. Great work!
Thanks for your web pages! I bought a SMC WEBT-G and have problem finding a way to boot RedBoot for 6 months, without success. Inspired by your experiment, now I can upload and boot my RedBoot. :)