题目地址:
I had a router firmware upgrade.
I tried to log in as admin / admin with the default account information to set up the router
but it does not connect.
Analyze the cause and get your account information
md5(ID_PW)
固件下载地址:
https://drive.google.com/open?id=0B4SaQn817BNcc1BjRFVZV0EydUU
之前很少接触过路由器安全相关方面的知识
自己大概想了想, 感觉路由器的最容易受到攻击的方面大概有这些:
- Web层面漏洞
权限提升
命令执行 - 二进制
缓冲区 - 不当配置
等等
再有就是喜儿乐见的各种厂商由于各种原因留下的后门, 找这种后门最有意思了
有的厂商说是开发失误, 原本用来测试的脚本/功能被直接发布到了正式版
谁说的清呢 :D
目前大部分路由器都采用了 Linux 系统, 这为漏洞的挖掘提供了不少便利, 毕竟各种 Linux 工具都是上手就能用
路由器的文件系统一般都为: SquashFS
要对路由器进行漏洞分析, 首先需要拿到路由器的固件
一般来说拿到固件有两种方法
方法一: 直接去官方网站下载官方提供的固件, 其中直接打包了路由器的文件系统
方法二: 通过拆解路由器, 通过串口将整个系统镜像下来 (这种方法比较麻烦不像官方直接提供镜像那么方便, 不过通用性较强, 最近准备研究研究, 已淘宝了编程器和TTL线)
了解 SquashFS 文件系统:
https://www.ibm.com/developerworks/cn/linux/1306_qinzl_squashfs/
准备工作:
- 安装 binwalk 用于提取路由器固件中的文件系统
- IDA_pro
- squashfs-tools
- sasquatch
在安装 sasquatch 过程中, 有一个需要注意的地方
在编译的时候会有一段错误, 是某一个数据结构的定义太旧了, 需要将其修改为新的头文件, 具体哪个头文件在错误提示中有, 按照提示操作即可
上述环境只可以用来静态分析, 并不能进行动态调试, 动态调试还需要安装 qemu 的 MIPS 虚拟机
看看这个题目怎么做吧, 这个题目目标是找到路由器的管理员用户名和密码
提供了路由器的固件
首先 binwalk 将文件系统提取出来
➜ router ls
DS_CTF_FORENSIC03
➜ router binwalk -e ./DS_CTF_FORENSIC03
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
4880 0x1310 LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size: 61248 bytes
141408 0x22860 LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size: 4938068 bytes
1638400 0x190000 Squashfs filesystem, little endian, version 4.0, compression:lzma, size: 2236252 bytes, 1162 inodes, blocksize: 131072 bytes, created: 2017-03-01 14:23:33
➜ router
进入其文件系统的文件夹: squashfs-root
接下来我们需要注意寻找几样东西
- web 服务器的二进制程序 (通常在
/bin/httpd
或者/bin/web
) - 各种功能的 cgi 文件 (
/home
或者/tmp
或者/var
) - web 源码, html/js (好像没啥用)
- 有的路由器会安装 lua, 这种直接可以去找 web 源码, 接下来只要像审计 php 那样去审计就可以完成 web 层面的漏洞分析了
还可以找一下 web 服务器的配置文件, 这样有可能可以找到 url 路由信息
这道题目的 web 服务器位于:
➜ squashfs-root find . -name '*http*' -type f
./sbin/httpd
web 根目录位于: /home/httpd
➜ httpd ls
192.168.0.1 basicapp captcha.cgi common help index.html js m_login.cgi natrouterconf time.css version
192.168.255.1 build_date cgi expertconf images index_nologin.html login_session.css mypage.html netinfo time.v2.css wirelessconf
192.168.255.250 captcha checkup firewallconf images2 index_org.html m_handler.cgi nasconf sysconf trafficconf
既然这个题目的目的是管理员的用户名和密码, 那么重点关注登录的逻辑
发现存在文件 m_login.cgi
拖入 IDA 进行分析
发现在数据段中有直接写好的 JavaScript, 猜想登录是通过 ajax 实现的
根据字符串的排列顺序可以推测出, 先获取验证码, 然后点击登录按钮后, 就直接将数据 POST 到 m_handler.cgi
, 这个 cgi 文件会对密码的正确性进行验证
目前这个文件已经没有用了, 再看看 m_handler.cgi
注意到这里有一个函数叫 get_id_password , 猜想密码验证的函数会调用这个函数获取正确的密码, 然后进行比较, 看一下交叉引用
看到上面的字符串 passwd 以及 username, 和之前看到的 HTTP 的字符段是一样的, 并且在这段代码上面还看到了 captcha 的字符串, 这里的逻辑应该是从 HTTP 请求头中获取用户输入的用户名和密码, 再看看这个 get_id_password
是如何实现的
是一个外部函数, 当然是调用外部的 so 库了, 我们需要看一下这个 cgi 文件调用了那些 so 文件
➜ httpd readelf -d ./m_handler.cgi
Dynamic section at offset 0x160 contains 31 entries:
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: [libcgi.so]
0x00000001 (NEEDED) Shared library: [libuserland.so]
0x00000001 (NEEDED) Shared library: [libcrypt.so.0]
0x00000001 (NEEDED) Shared library: [librtl.so]
0x00000001 (NEEDED) Shared library: [libgcc_s.so.1]
0x00000001 (NEEDED) Shared library: [libc.so.0]
0x0000000c (INIT) 0x400cec
0x0000000d (FINI) 0x403320
0x00000004 (HASH) 0x400280
0x00000005 (STRTAB) 0x400858
0x00000006 (SYMTAB) 0x400428
0x0000000a (STRSZ) 980 (bytes)
0x0000000b (SYMENT) 16 (bytes)
0x70000016 (MIPS_RLD_MAP) 0x413b60
0x00000015 (DEBUG) 0x0
0x00000003 (PLTGOT) 0x413b80
0x70000001 (MIPS_RLD_VERSION) 1
0x70000005 (MIPS_FLAGS) NOTPOT
0x70000006 (MIPS_BASE_ADDRESS) 0x400000
0x7000000a (MIPS_LOCAL_GOTNO) 7
0x70000011 (MIPS_SYMTABNO) 67
0x70000012 (MIPS_UNREFEXTNO) 30
0x70000013 (MIPS_GOTSYM) 0x11
0x00000014 (PLTREL) REL
0x00000017 (JMPREL) 0x400cd4
0x00000002 (PLTRELSZ) 24 (bytes)
0x70000032 (MIPS_PLTGOT) 0x413b64
0x6ffffffe (VERNEED) 0x400cb4
0x6fffffff (VERNEEDNUM) 1
0x6ffffff0 (VERSYM) 0x400c2c
0x00000000 (NULL) 0x0
有一个没有见过的 libuserland.so
看看这个 so 有什么符号
➜ squashfs-root find . -name 'libuserland.so'
./lib/libuserland.so
➜ squashfs-root readelf -s ./lib/libuserland.so | grep password
39: 00008c30 192 FUNC GLOBAL DEFAULT 10 check_password
100: 00008cf0 176 FUNC GLOBAL DEFAULT 10 get_default_id_password
214: 00008da0 204 FUNC GLOBAL DEFAULT 10 get_id_password
果然, 找到了 get_id_password
的定义
有一个函数叫 iconfig_get_value_direct
这个看名字似乎是从一个配置文件中读取一个键的值
这个文件是: /etc/iconfig.cfg
那么用户名和密码应该是就在这里了
找一下这个文件:
➜ squashfs-root find . -name 'iconfig.cfg'
./default/etc/iconfig.cfg
➜ squashfs-root cat ./default/etc/iconfig.cfg
wantype.wan1=dynamic
dhblock.eth1=0
ppp_mtu=1454
fakedns=0
upnp=1
ppp_mtu=1454
timeserver=time.windows.com,gmt23,1,540,0
wan_ifname=eth1
auto_dns=1
dhcp_auto_detect=0
wireless_ifmode+wlan0=wlan0,0
dhcpd=1
lan_ip=192.168.0.1
lan_netmask=255.255.255.0
dhcpd_conf=br0,192.168.0.2,192.168.0.254,192.168.0.1,255.255.255.0
dhcpd_opt=7200,30,200,
dhcpd_configfile=/etc/udhcpd.conf
dhcpd_lease_file=/etc/udhcpd.leases
dhcpd_static_lease_file=/etc/udhcpd.static
http_auth=session
login=hacker
password=hacked123
lang=utf-8
找到了:
login=hacker
password=hacked123