最新消息:欢迎大家关注安全工具箱微信公众号,域名信息查询,微信搜索安全工具箱添加关注即可,或访问在线安全工具箱

Openwrt漏洞挖掘之不要用小米路由偷偷下小电影哦

漏洞预警 表哥C 4540浏览 0评论

本文是通过小米路由作为案例,讲解如何挖掘openwrt的漏洞,并且通过一个小米路由的0day作为实例,让大家更容易理解测试的方法。

1 提取固件内容

首先肯定是将固件中文件系统的内容提取出来,然后对其进行分析,也可以是分析其固件中应用程序是否存在漏洞,如Uhttpd等服务,也可以分析其web程序是否存在漏洞 如openwrt,
由于本人对二进制并不熟悉,所以此次的内容就是针对openwrt luci的。

1.1 固件解包

通过执行Binwalk可以发现存在如下内容:

  1. root@kali:~/miwifi# binwalk brcm4709_r2d_all_79e11_2.8.19.bin
  2. DECIMAL HEXADECIMAL DESCRIPTION
  3. --------------------------------------------------------------------------------
  4. 672 0x2A0 LZMA compressed data, properties: 0x5D, dictionary size: 65536 bytes, uncompressed size: 90046464 bytes
  5. 30048716 0x1CA81CC TRX firmware header, little endian, image size: 3047424 bytes, CRC32: 0xA85FDFF0, flags: 0x0, version: 1, header size: 28 bytes, loader offset: 0x1C, linux kernel offset: 0x0, rootfs offset: 0x0
  6. 30048744 0x1CA81E8 LZMA compressed data, properties: 0x5D, dictionary size: 65536 bytes, uncompressed size: 5902752 bytes

通过加上-e参数对其进行解压,解压之后将会得到一个目录,进去查看之后内容如下:

  1. root@kali:~/miwifi# cd _brcm4709_r2d_all_79e11_2.8.19.bin.extracted/
  2. root@kali:~/miwifi/_brcm4709_r2d_all_79e11_2.8.19.bin.extracted# ls
  3. 1CA81E8 1CA81E8.7z 2A0 2A0.7z
  4. root@kali:~/miwifi/_brcm4709_r2d_all_79e11_2.8.19.bin.extracted# file 2A0
  5. 2A0: UBI image, version 1
  6. root@kali:~/miwifi/_brcm4709_r2d_all_79e11_2.8.19.bin.extracted# file 1CA81E8
  7. 1CA81E8: data
  8. root@kali:~/miwifi/_brcm4709_r2d_all_79e11_2.8.19.bin.extracted#

1.2 提取文件系统

与其他不同的是,miwifi使用的是UBI的文件系统,这个文件系统挂载起来比较麻烦,在尝试了无数次之后发现一个自动化就能挂载的脚本
https://github.com/jrspruitt/ubi_reader
安装方式:

  1. $ sudo apt-get install liblzo2-dev
  2. $ sudo apt-get install python-lzo
  3. $ git clone https://github.com/jd-boyd/python-lzo.git
  4. $ cd python-lzo
  5. $ python setup.py install

通过执行

  1. ubireader_extract_images 2A0

可以得到如下结果

  1. root@kali:~/miwifi/_brcm4709_r2d_all_79e11_2.8.19.bin.extracted# ubireader_extract_images 2A0
  2. root@kali:~/miwifi/_brcm4709_r2d_all_79e11_2.8.19.bin.extracted# ls
  3. 1CA81E8 1CA81E8.7z 2A0 2A0.7z *ubifs-root*
  4. root@kali:~/miwifi/_brcm4709_r2d_all_79e11_2.8.19.bin.extracted#
  5. root@kali:~/miwifi/_brcm4709_r2d_all_79e11_2.8.19.bin.extracted/ubifs-root/2A0# ubireader_extract_files img-1883837156_vol-system.ubifs
  6. Extracting files to: ubifs-root

将会生成一个名叫 ubifs-root 的文件夹里面还存放这一个文件,这个文件就是ubi镜像的最终文件,在通过ubireader_extract_files对其进行提取即可,最后生成的文件夹,其中就存放的该固件的文件系统。

2 Openwrt的简单介绍

OpenWrt 可以被描述为一个嵌入式的 Linux 发行版,(主流路由器固件有 dd-wrt,tomato,openwrt三类)而不是试图建立一个单一的、静态的系统。OpenWrt的包管理提供了一个完全可写的文件系统,从应用程序供应商提供的选择和配置,并允许您自定义的设备,以适应任何应用程序。
对于开发人员,OpenWrt 是使用框架来构建应用程序,而无需建立一个完整的固件来支持;对于用户来说,这意味着其拥有完全定制的能力,可以用前所未有的方式使用该设备。
以上内容来自百度百科
Openwrt是一个支持用Lua进行开发嵌入式的linux路由系统,详细的内容就不说了,就简单说一下,基本在openwrt都是使用lua进行开发的,其中lua的目录结构大概如下
所有的lua模块和web调用的lua程序都在这个目录下面:

  1. /usr/lib/lua/
  2. /usb/lib/lua/luci #这里存放的就是luci也就是openwrt web访问所需的内容。

openwrt在开发的时候 基本上是MVC模式,既 Model,View,Controller,所以大家看下图就可以一目了然

Controller目录中存放的就是所有走web访问的入口文件,Model中放的就是一些所需要的模块,View就是html模板。

3 寻找漏洞

寻找漏洞的第一步自然是寻找一些高风险的漏洞,首先需要的就是查找出不需要登录就可以调用的模块,首先我们来看一个Contraller是怎么写的
文件位置:/usb/lib/lua/luci/controller/diagnosis/index.lua

  1. module("luci.controller.diagnosis.index", package.seeall)
  2. function index()
  3. local root = node()
  4. if not root.target then
  5. root.target = alias("diagnosis")
  6. root.index = true
  7. end
  8. local page = node("diagnosis")
  9. page.target = firstchild()
  10. page.title = _("")
  11. page.order = 110
  12. page.sysauth = "admin"
  13. page.mediaurlbase = "/xiaoqiang/diagnosis"
  14. page.sysauth_authenticator = "htmlauth"
  15. page.index = true
  16. entry({"diagnosis"}, template("diagnosis/home"), _("首页"), 1, 0x09)
  17. entry({"diagnosis", "wanerr"}, call("action_wanerr"), _(""), 2, 0x09)
  18. entry({"diagnosis", "errindex"}, call("action_errindex"), _(""), 3, 0x09)
  19. end
  20. function action_wanerr()
  21. local result = {}
  22. result["code"] = 0
  23. result["data"] = {
  24. ["a"] = _("对不起,小米路由器出现网络连接问题无法打开网页"),
  25. ["b"] = _("1、请检查网线是否正确连接路由器WAN口上"),
  26. ["c"] = _("2、请检查网线是否损坏"),
  27. ["d"] = _("3、请检查路由器WAN口是否损坏"),
  28. ["e"] = _("小米路由器技术支持")
  29. }
  30. luci.http.write_json(result)
  31. end
  32. function action_errindex()
  33. local result = {}
  34. result["code"] = 0
  35. result["data"] = {
  36. ["a"] = _("对不起,小米路由器出现网络连接问题无法打开网页"),
  37. ["b"] = _("立即进行网络诊断"),
  38. ["c"] = _("小米路由器技术支持")
  39. }
  40. luci.http.write_json(result)
  41. end

其中最为关键的一个内容便是

  1. entry({"diagnosis", "wanerr"}, call("action_wanerr"), _(""), 2, 0x09)

这一段的意思就是,我通过访问

  1. http://127.0.0.1/cgi-bin/luci/diagnosis/index/wanerr

就可以调用action_wanerr 函数,然后0x09就是一个权限标志位,经过多次摸索发现0x9,0x01,0x0d的标志位是不需要登录就可以访问的。
那我们就先查找出所有0x09,0x08,0x0d标志位的文件,如下

  1. api/misystem.lua:33: entry({"api", "misystem", "topo_graph"}, call("getTopoGraph"), (""), 114, 0x0d)
  2. api/xqsystem.lua:61: entry({"api", "xqsystem", "upgrade_status"}, call("upgradeStatus"), (""), 148, 0x0d)
  3. api/xqsystem.lua:73: entry({"api", "xqsystem", "cancel"}, call("cancelUpgrade"), (""), 160, 0x0d)
  4. api/xqsystem.lua:123: entry({"api", "xqsystem", "flash_permission"}, call("flashPermission"), (""), 200, 0x0d)
  5. web/index.lua:74: entry({"web", "upgrading"}, template("web/syslock"), _("路由升级"), 101, 0x0d)
  6. web/index.lua:81: entry({"web", "topo"}, template("web/topograph"), _(""), 130, 0x0d)
  7. api/xqnetwork.lua:90: entry({"api", "xqnetwork", "wan_link"}, call("getWanLinkStatus"), (""), 265, 0x09)
  8. api/xqnetwork.lua:104: entry({"api", "xqnetwork", "pppoe_catch"}, call("pppoeCatch"), (""), 264, 0x09)
  9. api/misystem.lua:91: entry({"api", "misystem", "lsusb"}, call("lsusb"), (""), 150, 0x09)
  10. api/misystem.lua:97: entry({"api", "misystem", "r_ip_conflict"}, call("rIpConflict"), (""), 155, 0x09)
  11. api/misystem.lua:99: entry({"api", "misystem", "tb_info"}, call("toolbarInfo"), (""), 156, 0x09)
  12. api/xqsystem.lua:13: entry({"api", "xqsystem", "init_info"}, call("getInitInfo"), (""), 101, 0x09)
  13. api/xqsystem.lua:14: entry({"api", "xqsystem", "fac_info"}, call("getFacInfo"), (""), 101, 0x09)
  14. api/xqsystem.lua:133: entry({"api", "xqsystem", "set_payment_info"}, call("setPaymentInfo"), (""), 207, 0x09)
  15. api/xqsystem.lua:134: entry({"api", "xqsystem", "sign_order"}, call("signOrder"), (""), 208, 0x09)
  16. diagnosis/index.lua:16: entry({"diagnosis"}, template("diagnosis/home"), _("首页"), 1, 0x09)
  17. diagnosis/index.lua:18: entry({"diagnosis", "wanerr"}, call("action_wanerr"), _(""), 2, 0x09)
  18. diagnosis/index.lua:19: entry({"diagnosis", "errindex"}, call("action_errindex"), _(""), 3, 0x09)
  19. dispatch/index.lua:17: entry({"dispatch"}, template("index"), _("跳转"), 1, 0x09)
  20. web/index.lua:26: entry({"web", "logout"}, call("action_logout"), 11, 0x09)
  21. web/index.lua:41: entry({"web", "init", "hello"}, call("action_hello"), _("欢迎界面"), 14, 0x09) --不需要登录
  22. web/index.lua:42: entry({"web", "init", "agreement"}, template("web/init/agreement"), _("用户协议"), 14, 0x09) --不需要登录
  23. web/index.lua:43: entry({"web", "init", "privacy"}, template("web/init/privacy"), _("用户体验改进计划"), 14, 0x09) --不需要登录
  24. web/index.lua:76: entry({"web", "webinitrdr"}, call("action_webinitrdr"), _(""), 110, 0x09)
  25. web/index.lua:79: entry({"web", "ieblock"}, template("web/ieblock"), _(""), 120, 0x09)
  26. api/xqpassport.lua:12: entry({"api", "xqpassport", "login"}, call("passportLogin"), (""), 401, 0x01)
  27. api/xqpassport.lua:14: entry({"api", "xqpassport", "rigister"}, call("routerRegister"), (""), 405, 0x01)
  28. api/xqpassport.lua:15: entry({"api", "xqpassport", "binded"}, call("getBindInfo"), (""), 406, 0x01)
  29. api/xqnetdetect.lua:12: --entry({"api", "xqnetdetect", "wan_status"}, call("getWanStatus"), _(""), 351, 0x01)
  30. api/xqnetdetect.lua:13: entry({"api", "xqnetdetect", "sys_info"}, call("getSysInfo"), (""), 352, 0x01)
  31. api/xqnetdetect.lua:14: entry({"api", "xqnetdetect", "ping_test"}, call("pingTest"), (""), 353, 0x01)
  32. api/xqnetdetect.lua:15: entry({"api", "xqnetdetect", "detect"}, call("systemDiagnostics"), (""), 354, 0x01)
  33. api/xqnetdetect.lua:16: entry({"api", "xqnetdetect", "sys_status"}, call("systemStatus"), (""), 355, 0x01)
  34. api/xqnetdetect.lua:19: entry({"api", "xqnetdetect", "nettb"}, call("nettb"), (""), 359, 0x01)
  35. api/misns.lua:12: entry({"api", "misns", "prepare"}, call("prepare"), (""), 201, 0x01)
  36. api/misns.lua:17: entry({"api", "misns", "sns_init"}, call("snsInit"), (""), 206, 0x01)
  37. api/misns.lua:21: entry({"api", "misns", "authorization_status"}, call("authorizationStatus"), (""), 210, 0x01)
  38. api/xqsystem.lua:17: entry({"api", "xqsystem", "system_info"}, call("getSysInfo"), (""), 104, 0x01)
  39. api/xqsystem.lua:32: entry({"api", "xqsystem", "get_languages"}, call("getLangList"), (""), 118, 0x01)
  40. api/xqsystem.lua:33: entry({"api", "xqsystem", "get_main_language"}, call("getMainLang"), (""), 119, 0x01)
  41. api/xqsystem.lua:45: entry({"api", "xqsystem", "passport_bind_info"}, call("getPassportBindInfo"), (""), 132, 0x01)
  42. api/xqsystem.lua:60: entry({"api", "xqsystem", "flash_status"}, call("flashStatus"), (""), 147, 0x01)
  43. api/xqsystem.lua:86: entry({"api", "xqsystem", "device_mac"}, call("getDeviceMacaddr"), (""), 173, 0x01)
  44. service/cachecenter.lua:11: entry({"service", "cachecenter", "report_key"}, call("reportKey"), _(""), nil, 0x01)
  45. service/datacenter.lua:34: entry({"service", "datacenter", "media_delta"}, call("mediaDelta"), _(""), nil, 0x01)
  46. service/datacenter.lua:35: entry({"service", "datacenter", "media_metadata"}, call("mediaMetadata"), _(""), nil, 0x01)
  47. service/datacenter.lua:36: entry({"service", "datacenter", "share_miui_dir"}, call("shareMiuiBackupDir"), _(""), nil, 0x01)
  48. service/datacenter.lua:37: entry({"service", "datacenter", "get_file_list"}, call("getFileList"), _(""), nil, 0x01)
  49. service/datacenter.lua:38: entry({"service", "datacenter", "get_storage_info"}, call("getStorageInfo"), _(""), nil, 0x01)
  50. service/datacenter.lua:39: entry({"service", "datacenter", "get_youku_status"}, call("getYoukuStatus"), _(""), nil, 0x01)
  51. service/datacenter.lua:40: entry({"service", "datacenter", "bind_youku_appid"}, call("bindYoukuAppid"), _(""), nil, 0x01)

先选择几个重点的模块看一下,如:xqsystem,datacenter, misystem先选择第一个来查看一下:
通过如下内容:

  1. api/misystem.lua:33: entry({"api", "misystem", "topo_graph"}, call("getTopoGraph"), (""), 114, 0x0d)

得知,可以通过访问http:///cgi-bin/luci/api/misystem/topo_graph 来调用getTopoGraph,可以去看一下getTopoGraph函数的内容,

  1. function getTopoGraph()
  2. local XQTopology = require("xiaoqiang.module.XQTopology")
  3. local result = {
  4. ["code"] = 0
  5. }
  6. local simplified = tonumber(LuciHttp.formvalue("simplified")) == 1 and true or false
  7. local graph = simplified and XQTopology.simpleTopoGraph() or XQTopology.topologicalGraph()
  8. result["graph"] = graph
  9. result["show"] = graph.leafs and 1 or 0
  10. LuciHttp.write_json(result)
  11. end

发现函数中也没有做任何验证,进行访问即可得到如下信息


在测试其他的模块也有一些信息泄漏的漏洞,

其中比较严重的漏洞是下面这个,可以获取这个用户使用离线下载的文件列表,函数如下:

  1. function getFileList()
  2. local payload = {}
  3. payload["api"] = 3
  4. payload["path"] = LuciHttp.formvalue("path")
  5. payload["sharedOnly"] = true
  6. tunnelRequestDatacenter(payload)
  7. end

看内容应该是获取path下目录,但是也做了校验,并不能跳出其设置的用户目录,但是比如我们获取了下面这位用户,看到他下了一些小电影,什么黑丝豹纹,都是什么意思哦

来自为知笔记(Wiz)

转载请注明:安全工具箱 » Openwrt漏洞挖掘之不要用小米路由偷偷下小电影哦

发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址