小米
小米路由4A分析
• 0x01:Get Shell
路由器暴露串口,焊接之后上电,查看启动信息。
Erasing SPI Flash...raspi_erase: offs:20000 len:10000
.
Writing to SPI Flash...
.
done
## Booting image at bc160000 ...
Image Name: MIPS OpenWrt Linux-3.10.14
Image Type: MIPS Linux Kernel Image (lzma compressed)
Data Size: 1425061 Bytes = 1.4 MB
Load Address: 80000000
Entry Point: 80000000
Verifying Checksum ... OK
Uncompressing Kernel Image ... - init -
[ 5.750000] ra2880stop()...Done
[ 5.760000] Free TX/RX Ring Memory!
init started: BusyBox v1.19.4 (2019-04-01 03:43:26 UTC)
Please press Enter to activate this console. rcS S boot: INFO: rc script run time limit to 65 seconds.
[ 6.120000] MIWIFI crash syslog initialize skiped! Code=1
[ 16.250000] ipaccount: ifname [eth0.1] event[4]
[ 16.250000] ipaccount: ifname [br-lan] event[4]
[ 16.250000] ipaccount: ifname [eth0.2] event[4]
看到Booting image是0xBC160000,基本可以判断是联发科mt762x的soc。 内核启动后不能输入,应该是没有设相应内核参数。
为了get shell,我们来修改一下启动脚本: 把spi flash焊下来,读取内容(这里用的RT809H编程器,他的对应软件选择20170928版本,最新的2019版本不知道为什么有问题)。
先binwalk一下。
uImage header长度为64字节,应该没有修改过uboot。正常header的格式如下:
主要关注点就是ih_hcrc与 ih_dcrc两处crc校验。
ih_hcrc位header的crc,校验前会把ih_hcrc填充位0再计算crc32。
ih_dcrc是从zimage起长度为ih_size数据的crc32 理论上这个ih_size只是检查kernel,不会到后面的文件系统部分,验证也确实如此。
但我印象里好像360的路由也校验到了文件系统部分。
这里就不需要管uboot校验的问题了,直接修改文件系统。 binwalk -Me解压flash镜像,进入squashfs目录,openwrt通常会去找rc,d中 S开头的文件,执行他的start函数,在/etc/rc.d中发现了S40telnet脚本:
#!/bin/sh /etc/rc.common# Copyright (C) 2006-2011 OpenWrt.org
START=40
start() { service_start /usr/sbin/telnetd -l /bin/login.sh return 0}
stop() { service_stop /usr/sbin/telnetd}login.sh:#!/bin/sh# Copyright (C) 2006-2011 OpenWrt.org
if ( ! grep -qs '^root:[!x]\?:' /etc/shadow || \ ! grep -qs '^root:[!x]\?:' /etc/passwd ) && \ [ -z "$FAILSAFE" ]then ft_mode=`cat /proc/xiaoqiang/ft_mode` if [ "$ft_mode" = "1" ]; then exec /bin/ash --login else busybox login fifi
这个脚本貌似首先会正则判断一下root密码,然后检查/proc/xiaoqiang/ft_mode的值,来确定是否要密码来登陆,比较有趣,等拿shell了详细分析一下。
为了理解路由器的启动流程,在rcS中加一些打印日志。
并尝试在这里直接开telnet:
制作文件系统,命令如下:
mksquashfs ./squashfs-root root.squashfs44 -nopad -noappend -root-owned -comp xz -b 256k -p '/dev d 755 0 0' -p '/dev/console c 600 0 0 5 1' -processors 1
这里要注意-comp xz,表示以xz格式压缩文件系统,这里要与之前Binwalk看到的squashfs的压缩方式一致。
然后将新生成的文件系统放在0x2C0000处覆盖原有文件系统,并且保持0xDC0000 开始处是Jffs2文件系统。(也就是说把新生成的覆盖到0x2C0000-0xDC0000处,其余都保持不变)。
然后通过编程器刷入flash,再焊到路由器上。
这里顺便总结一下编程器与flash读取方法: 最稳定的方法还是吹下来直接拿编程器读,用过CH341A和RT809H编程器,RT809H不知道什么原因总是识别不了,CH341A每次校验会有问题。 还有一些不用吹flash直接读的方法(夹子,脚夹),有时也不太稳定:
用Arduino或者树莓派也可以读写spi flash,而且比较稳定,按照下面的几张图把树莓派和flash连起来。
然后通过flashrom读写flash(https://github.com/flashrom/flashrom)
sudo raspi-config ------> Interfacing options ----------> spi enable sudo apt install git libpci-dev libusb-1.0 libusb-dev git clone https://github.com/flashrom/flashrom.gitcd flashrommake && sudo make install
//读, spispeed可以设置大一些flashrom -p linux_spi:dev=/dev/spidev0.0,spispeed=512 -r flash.dat -c GD25B128B/GD25Q128B -V
//写,-c是指定设备flashrom -p linux_spi:dev=/dev/spidev0.0,spispeed=512 -w flash.dat -c GD25B128B/GD25Q128B -V
刷写后,启动路由器,诡异的是启动脚本的打印日志并没有任何变化。 想一想这里是dump了整个flash的内容,之前binwalk的结果,在Uboot与内核之间有很多的zlib或者jffs2格式的东西。
//不确定 我估计有可能即使修改了flash里的根文件系统,但是flash里其他的地方没有修改,有可能内核认为已经挂在了文件系统,而不从初始的squashfs重新挂在。
这里我按reset键5秒,发现成功修改文件系统。 按reset的串口打印:
[ 78.020000] [sched_delayed] sched: RT throttling activated[ 78.460000] press reset button over 5s[ 78.460000] : sending a SIGUSR2 to process 4347pid 4347 recv sig SIGUSR2!gpio btn reset![ 78.960000] press reset button over 5s[ 78.960000] : sending a SIGUSR2 to process 4347[ 79.470000] led=44, on=1, off=4000, blinks,=1, reset=1, time=4000[ 79.480000] led=11, on=1, off=4000, blinks,=1, reset=1, time=4000[ 79.490000] led=11, on=1, off=4000, blinks,=1, reset=1, time=4000[ 79.500000] led=44, on=4000, off=1, blinks,=1, reset=1, time=4000pid 4347 recv sig SIGUSR2!gpio btn reset![ 80.060000] led=44, on=1, off=4000, blinks,=1, reset=1, time=4000[ 80.080000] led=11, on=1, off=4000, blinks,=1, reset=1, time=4000[ 80.090000] led=11, on=1, off=4000, blinks,=1, reset=1, time=4000[ 80.100000] led=44, on=4000, off=1, blinks,=1, reset=1, time=4000router monitor is not running, exit./sbin/wifi: CALLER: /bin/sh/etc/rc.common/etc/rc.d/K01shutdownshutdown[ 84.220000] ipaccount: ifname [eth0.2] event[9][ 84.220000] ipaccount: ifname [eth0.2] event[2][ 84.240000] ipaccount: ifname [eth0.2] event[6][ 84.250000] ipaccount: ifname [eth0.2] event[17]/sbin/wifi: ...mt7612.type=mt7612.../sbin/wifi: run1 eval type disable_mt7612/sbin/wifi: run2 eval disable_mt7612 'mt7612'[ 84.820000] ipaccount: ifname [wl0] event[9][ 84.860000] br-lan: port 2(wl0) entered disabled state[ 84.860000] ipaccount: ifname [wl0] event[2]/sbin/wifi: ...mt7628.type=mt7628.../sbin/wifi: run1 eval type disable_mt7628/sbin/wifi: run2 eval disable_mt7628 'mt7628'[ 85.020000] ipaccount: ifname [wl1] event[9][ 85.020000] wifi_disassoc2 MAC 30-b4-9e-af-0d-5a, ReasonCode 4[ 85.030000] wifi_log: [Class 2 - SEND DISASSOC] - if="wl1", sta_mac="30:b4:9e:af:0d:5a", bssid="ec:41:18:da:a9:fd", action="send-disassoc", info="mlme kick out sta", reason="4", Aid="1"[ 85.050000] br-lan: port 3(wl1) entered disabled state[ 85.050000] ipaccount: ifname [wl1] event[2][ 85.160000] ipaccount: ifname [wl2] event[9][ 85.170000] MtAsicSetPreTbtt(): bss_idx=0, PreTBTT timeout = 0x0[ 85.170000] MtAsicSetPiggyBack(783): Not support for HIF_MT yet![ 86.010000] tx_kickout_fail_count = 0[ 86.010000] tx_timeout_fail_count = 0[ 86.010000] rx_receive_fail_count = 0[ 86.020000] alloc_cmd_msg = 250[ 86.020000] free_cmd_msg = 250[ 86.030000] ipaccount: ifname [wl2] event[2]program name :'/usr/bin/longloopd'longloopd: is not runninglongloopd: is not running!/sbin/wifi: CALLER: /bin/sh/etc/rc.common/etc/rc.d/K90networkshutdown/sbin/wifi: ...mt7612.type=mt7612.../sbin/wifi: run1 eval type disable_mt7612/sbin/wifi: run2 eval disable_mt7612 'mt7612'/sbin/wifi: ...mt7628.type=mt7628.../sbin/wifi: run1 eval type disable_mt7628/sbin/wifi: run2 eval disable_mt7628 'mt7628'[ 88.840000] ipaccount: ifname [ifb0] event[9][ 88.840000] ipaccount: ifname [ifb0] event[2][ 88.880000] ipaccount: ifname [br-lan] event[9][ 88.880000] br-lan: port 1(eth0.1) entered disabled state[ 88.890000] ipaccount: ifname [br-lan] event[2][ 88.910000] ipaccount: ifname [br-lan] event[8][ 88.910000] device eth0.1 left promiscuous mode[ 88.910000] device eth0 left promiscuous mode[ 88.920000] br-lan: port 1(eth0.1) entered disabled state[ 89.020000] ipaccount: ifname [eth0.1] event[9][ 89.030000] ipaccount: ifname [eth0.1] event[2][ 89.030000] IPv6: ADDRCONF(NETDEV_UP): eth0.1: link is not ready[ 89.040000] ipaccount: ifname [eth0.1] event[6][ 89.060000] ipaccount: ifname [eth0.1] event[17][ 89.060000] ipaccount: ifname [eth0] event[9][ 89.060000] ra2880stop()...Done[ 89.070000] Free TX/RX Ring Memory![ 89.070000] ipaccount: ifname [eth0] event[2][ 89.090000] device wl0 left promiscuous mode[ 89.100000] br-lan: port 2(wl0) entered disabled state[ 89.110000] device wl1 left promiscuous mode[ 89.110000] br-lan: port 3(wl1) entered disabled state[ 89.120000] ipaccount: ifname [br-lan] event[11][ 89.120000] ipaccount: ifname [br-lan] event[6][ 89.140000] ipaccount: ifname [br-lan] event[17][ 89.150000] ipaccount: ifname [lo] event[9][ 89.180000] ipaccount: ifname [lo] event[2]program name :'/usr/bin/longloopd'longloopd: is not runninglongloopd: is not running!/etc/rc.common: line 92: swapoff: not foundThe system is going down NOW!Sent SIGTERM to all processesApr 1 11:59:41 wrsst[4265]: wrsst got signal(15), exit.
Sent SIGKILL to all processesRequesting system reboot[ 91.840000] Stopped WatchDog Timer.[ 91.840000] MT7612E cleanup[ 91.840000] ipaccount: ifname [apclii0] event[6][ 91.850000] ipaccount: ifname [apclii0] event[17][ 91.850000] RtmpOSNetDevDetach(): RtmpOSNetDeviceDetach(), dev->name=wl0![ 91.860000] ipaccount: ifname [wl0] event[6][ 91.860000] ipaccount: landev_uninit clear ifname [wl0][ 91.870000] ipaccount: ifname [wl0] event[17][ 91.880000] Restarting system.[ 91.880000]
[ 91.880000] before restart close watchdog[ 91.880000] Stopped WatchDog Timer.
[03080D08][03080D08][88880000][24244848][00242448]DU Setting Cal Done
重启后的启动脚本日志: 刷新overlayfs和nvram
进入rcS:
开始遍历调用rc.d中S开头的启动脚本
启动后发现没有telnet依然没有开启,qemu跑一下路由里的busybox telnetd
看来busybox是小米修改过了的,大概分析一下:
函数表起始:
Let’s Look inside:) 整体看下来没看出啥异常,上调试器看看
这里理论上是会走到telnetd处理函数:
F7进去发现到了函数0x41739C,怀疑小米做了类似hook的操作来修改busybox
静态看了一下基本就是对/proc/xiaoqiang这个目录的文件进行操作,这里ft_mode 我怀疑是 factory_mode,如果值为0就直接退出了。等拿了shell再看下。
为了getshell,先上传个mipel版本的busybox,修改S40telnet脚本:
重新刷写,上电,reset,发现成功开启telnet。 但是需要密码,试了下貌似不是弱口令,尝试修改脚本如下:
重新刷,成功拿shell:
netstat -anp和nmap结果
评论
发表评论