搁废品站捡的智能门禁, 小区里还有几个这样子的, 都断电了
拆解
硬件信息
- SoC: MediaTek MT7628NN
- Flash: 8 MB
- RAM: 64 MB
- 电源: DC 5V - 25V
- 以太网: 1 x RJ45 (10/100 Mbps)
- 无线: 802.11n 2.4g-only
- 板载LED
状态1: GPIO/43 active-low
状态2: GPIO/44 active-low
电源: 常亮 - 按钮:
WPS/RESET: GPIO/14 active-low - 蓝牙: CC2541 via UART1 (ttyS1) and GPIO/26-29
- RFID: MF RC522 on I2C@28
- RTC时钟: DS1339 on I2C@68
外壳面板 (通过 CON1 线缆连接)
LED (刷卡区):
- 绿 GPIO/3 active-high
- 红 GPIO/11 active-high
- Matrix keypad 矩阵键盘: (active-low)
列⟍行 | GPIO/20 | GPIO/21 | GPIO/19 |
---|---|---|---|
GPIO/24 | 1 | 2 | 3 |
GPIO/25 | 4 | 5 | 6 |
GPIO/22 | 7 | 8 | 9 |
GPIO/23 | BACK | 0 | ENTER |
这里的行和列反了, 厂商开发人员不会不知道横行数列吧..
清除键的键码是 BACK 不是 CLEAR, 应该是厂商设计问题
- UART: 1 x UART on PCB - 57600 8N1
- 继电器: GPIO/42 active-high
- 蜂鸣器: GPIO/15 active-high
固件分析
将以太网与电脑连接, 可 DHCP 到 10.10.10.0/24
的网段, nmap 对网关扫描可确定 OpenSSH 22 端口开放, Telnet 9900 端口
按下底部 RESET 按钮并将电脑手动设置上述 IP, 可打开 Firmware Upgrade Web 控制台, 不过实测无法刷入任何固件
直接上 TTL
OS 版本
QdWrt, 直接不演了, 就是 OpenWrt 14.07 (BARRIER BREAKER) 修改的
内核版本 3.10
root@qc202:/# cat /etc/openwrt_release
DISTRIB_ID="QdWrt"
DISTRIB_RELEASE="2.2.0"
DISTRIB_REVISION="fdf6082e9cb1c51d4b49b6965e33ff8cf39feae2"
DISTRIB_CODENAME="qc202"
DISTRIB_TARGET="ramips/generic"
DISTRIB_DESCRIPTION="QdWrt qc202 2.2.0"
DISTRIB_TAINTS="no-all busybox"
root@qc202:/# cat /etc/openwrt_version
2.2.0
Opkg 更新软件
尝试使用 Opkg 更新软件, 是厂家自带的源, 不过已经打不开了, 应用商店也找不到 App 了, 确定是厂家跑路了
root@qc202:/# opkg update
Downloading http://www.qding.me/Packages.gz.
wget: bad address 'www.qding.me'
Collected errors:
* opkg_download: Failed to download http://www.qding.me/Packages.gz, wget returned 1.
root@qc202:/# cat /etc/opkg.conf
dest root /
dest ram /tmp
lists_dir ext /var/opkg-lists
option overlay_root /overlay
src/gz qc202 http://www.qding.me
内核命令行
root@qc202:/# cat /proc/cmdline
console=ttyS1,57600n8 root=/dev/mtdblock5 rootfstype=squashfs,jffs2
分区布局
root@qc202:/# cat /proc/mtd
dev: size erasesize name
mtd0: 00800000 00010000 "ALL"
mtd1: 00030000 00010000 "Bootloader"
mtd2: 00010000 00010000 "Config"
mtd3: 00010000 00010000 "Factory"
mtd4: 007a0000 00010000 "firmware"
mtd5: 00661235 00010000 "rootfs"
mtd6: 00270000 00010000 "rootfs_data"
mtd7: 00010000 00010000 "qdinfo"
端口监听状态
root@qc202:/# netstat -anp
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:53 0.0.0.0:* LISTEN 1198/dnsmasq
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 724/dropbear
tcp 0 0 :::9900 :::* LISTEN 733/telnetd
tcp 0 0 :::53 :::* LISTEN 1198/dnsmasq
tcp 0 0 :::22 :::* LISTEN 724/dropbear
udp 0 0 0.0.0.0:48400 0.0.0.0:* 1080/QDReader2
udp 0 0 0.0.0.0:30000 0.0.0.0:* 1080/QDReader2
udp 0 0 0.0.0.0:53 0.0.0.0:* 1198/dnsmasq
udp 0 0 0.0.0.0:67 0.0.0.0:* 1198/dnsmasq
udp 448 0 0.0.0.0:45450 0.0.0.0:* 1088/QDReaderWatche
udp 0 0 :::53 :::* 1198/dnsmasq
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags Type State I-Node PID/Program name Path
unix 7 [ ] DGRAM 843 612/logd /dev/log
unix 2 [ ACC ] STREAM LISTENING 345 377/ubusd /var/run/ubus.sock
unix 2 [ ] DGRAM 1436 1080/QDReader2
unix 2 [ ] DGRAM 1123 655/netifd
unix 3 [ ] STREAM CONNECTED 850 377/ubusd /var/run/ubus.sock
unix 2 [ ] DGRAM 1217 655/netifd
unix 3 [ ] STREAM CONNECTED 921 655/netifd
unix 3 [ ] STREAM CONNECTED 845 612/logd
unix 2 [ ] DGRAM 890 1/procd
unix 3 [ ] STREAM CONNECTED 922 377/ubusd /var/run/ubus.sock
unix 3 [ ] STREAM CONNECTED 709 1/procd
unix 3 [ ] STREAM CONNECTED 847 377/ubusd /var/run/ubus.sock
unix 2 [ ] DGRAM 1143 724/dropbear
unix 2 [ ] DGRAM 1520 1198/dnsmasq
unix 3 [ ] STREAM CONNECTED 710 377/ubusd /var/run/ubus.sock
unix 3 [ ] STREAM CONNECTED 849 613/logread
WLAN 密码
密码统一是 abc123456
root@qc202:/# cat /etc/config/wireless
config wifi-device 'mt7628'
option type 'mt7628'
option vendor 'ralink'
option band '2.4G'
option channel '0'
option auotch '2'
option country 'CN'
option macaddr 'xx:xx:xx:xx:xx:xx'
config wifi-iface
option device 'mt7628'
option ifname 'ra0'
option network 'lan'
option mode 'ap'
option encryption 'psk2'
option key 'abc123456'
option ssid 'QD_xxxxxxxxxxxx'
ROOT 密码 (OpenSSH/Telnet)
在我使用 TTL 修改 ROOT 密码重启后, ROOT 密码被改了
大概应该是有脚本重置密码, 可能是明文或者哈希
好巧不巧, 他确实用的是哈希, 但是旁边注释了明文, 注释立大功!
先说结论, ROOT 密码是 szqdingnet123
root@qc202:/# cat /etc/rc.qding
...
set_root_password() {
# szqdingnet123
local pw_new="root:$1$YJZCSuYq$dAv3YWx0ahZcmWV9hfgMh1:16857:0:99999:7:::"
local pw_old=$(grep "root:" /etc/shadow)
if [ $pw_old == $pw_new ]; then
echo "root password is configed, return."
else
pw="root:\$1\$YJZCSuYq\$dAv3YWx0ahZcmWV9hfgMh1:16857:0:99999:7:::"
sed -i "s/^root:.*/${pw}/g" /etc/shadow
echo "set root password"
fi
}
...
导出驱动包
root@qc202:/# opkg list-installed
kernel - 3.10.14-p112871-1-479cfba38eae3a80f46a23ab5e92588d
kmod-dnsresolver - 3.10.14-p112871-1
kmod-fs-nfs - 3.10.14-p112871-1
kmod-fs-nfs-common - 3.10.14-p112871-1
kmod-gpio-button-hotplug - 3.10.14-p112871-1
kmod-hw_wdg - 3.10.14-p112871-1
kmod-input-core - 3.10.14-p112871-1
kmod-input-evdev - 3.10.14-p112871-1
kmod-input-polldev - 3.10.14-p112871-1
kmod-ip6tables - 3.10.14-p112871-1
kmod-ipt-conntrack - 3.10.14-p112871-1
kmod-ipt-core - 3.10.14-p112871-1
kmod-ipt-nat - 3.10.14-p112871-1
kmod-ipt-nathelper - 3.10.14-p112871-1
kmod-ipv6 - 3.10.14-p112871-1
kmod-lib-crc-ccitt - 3.10.14-p112871-1
kmod-mt7628 - 3.10.14-p112871+p4rev-120396-1
kmod-ppp - 3.10.14-p112871-1
kmod-pppoe - 3.10.14-p112871-1
kmod-pppox - 3.10.14-p112871-1
kmod-qd-dev - 3.10.14-p112871-1
kmod-rdm - 3.10.14-p112871-1
kmod-slhc - 3.10.14-p112871-1
kmod-spi-dev - 3.10.14-p112871-1
libblobmsg-json - 2014-08-04-dffbc09baf71b294185a36048166d00066d433b5
qd-utils - 1
qding-files - 1-fdf6082e9cb1c51d4b49b6965e33ff8cf39feae2
qdspi-test - 0.1
这厂子还是有点实力的, 自己写内核模块了, 不过 rmmod
就会导致 Kernel Panic, 看上去是有 Bug
kmod-qd-dev 逆向工程
这里只放出 kmod 的逆向思路, 其他程序大同小异
逆向 kmod 时, 我们需要配合 vmlinux 对照一起看
先通过 binwalk 解压 uImage 获得 vmlinuz / vmlinux, 然后使用 vmlinux-to-elf 补全符号表
建议单独开个虚拟机/容器装 binwalk 和 vmlinux-to-elf, 里面不少包可能会破坏系统 python 依赖, 用虚拟机/容器强制装工具就行
apt install binwalk squashfs-tools mtd-utils -y
# 自行安装 vmlinux-to-elf
binwalk -eM flash.bin # 这里以整个 flash 为例, 也可以只解析 kernel / firmware 分区
cd _flash.bin.extracted/
vmlinux-to-elf 50040 vmlinux.elf # 50040 是 binwalk 解压后的 vmlinuz / vmlinux
然后我们就可以把 vmlinux.elf
扔进逆向工具 (例如 IDA)
GPIO Matrix Keypad / GPIO 矩阵键盘
先根据内核版本找到对应的 linux 源码方便对照数据结构
数据结构不一定完全一样, 但是大同小异.
可以用谷歌找找有没有厂家SDK泄露流出, 尽量减少反编译后的差异
上图 vmlinux 反编译后和 Linux 主线内核 以及 MTK SDK Linux 源码 还是有点差异的, 应该是编译器优化导致的 (内联函数减少调用开销)
图中的偏移量 4 对应的就是 GPIO 字段的数据大小 uint32
编译后数据结构都是连续的, 由于 Linux 结构体嵌套复杂, 这里我是凭感觉找的 (键盘是 4 行 3 列, 找连续的3和4)
前三个是 4字节 的指针, 对应二进制偏移量, 剩下的数据结构在图例一一标出, 根据端序这里应该从后往前看
08 0D 00 00 对应偏移量 00 00 0D 08 如下图所示
第一个个是 4字节 的指针, 依然对应二进制偏移量, 剩下的数据结构在图例一一标出, 根据端序这里还是应该从后往前看
最终我们找到了 keymap 和 对应的 GPIO
刷写固件
OpenWRT PR
OpenWRT SNAPSHOT 固件包
RFID 需要自己打 kmod
刷写 Breed
通过 OpenSSH 22 / Telnet 9900 连接到设备 10.10.10.1
, 密码为 szqdingnet123
原厂固件并没有附带 sftp, 建议本地用 python -m http.server
起个 http 服务器, 用 wget 拉到设备里
mtd write breed-mt7688-reset38.bin Bootloader
通过 Breed Enter / UART 进入 Breed (无法使用按钮)
建议备份EEPROM和编程器固件
刷入 sysupgrade 固件重启即可
再次通过 Breed Enter / UART 进入 Breed (Breed无法正确初始化 GPIO)
公版 Breed 会导致部分硬件 (如 RTC 2082年, GPIO 错误) 异常, 所以通过 Breed 刷回原厂 Bootloader (下方原厂固件下载内的 dumps/mtdblock1
)
直接刷写镜像
通过 OpenSSH 22 / Telnet 9900 连接到设备 10.10.10.1
, 密码为 szqdingnet123
原厂固件并没有附带 sftp, 建议本地用 python -m http.server
起个 http 服务器, 用 wget 拉到设备里
mtd -r write openwrt-ramips-mt76x8-qding_qc202-squashfs-sysupgrade.bin firmware
通过 UBoot WebUI 刷写
设置静态IP 10.10.10.100/24
浏览器访问 http://10.10.10.1
上传 factory
结尾固件
如果没有请看下面制作方法
制作原厂兼容镜像
安装 Golang 编译环境
安装 mkqdimg
go install gitlab.com/CoiaPrant/mkqdimg@latest
制作镜像
mkqdimg -B qc202 -f openwrt-ramips-mt76x8-qding_qc202-squashfs-sysupgrade.bin
将产物 factory.bin
上传到 Uboot WebUI 刷写
1 条评论
啊这就跑路了?我还想抓包这个门禁接入hass呢。。