远程代码执行漏洞(RCE)

RCE英文全称:remote command/code execute(远程命令/代码执行漏洞)

分为远程命令执行ping和远程代码执行evel。

漏洞成因:命令执行漏洞形成的原因是web服务器对用户输入的命令安全监测不足,导致恶意代码被执行。

我们常见的路由器、防火墙、入侵检测等设备的web管理界面上
一般会给用户提供一个ping操作的web界面,用户从web界面输入目标IP,提交后,后台会对该IP地址进行一次ping测试,并返回测试结果。其实这就是一个接口,可以让攻击者直接向后台服务器远程注入操作系统命令或者代码,从而控制后台系统,这就是RCE漏洞。相当于直接操控服务器电脑的cmd命令行!高危漏洞!

这里涉及到一个概念:ping

Ping是Windows、Unix和Linux系统下的一个命令。ping也属于一个通信协议,是TCP/IP协议的一部分。利用“ping”命令可以检查网络是否连通,可以很好地帮助我们分析和判定网络故障。应用格式:ping空格IP地址

image-20220329113042498

对于ping指令的一些补充:

当应用需要调用一些外部程序去处理内容的情况下,就会用到一些执行系统命令的函数。如PHP中的system,exec,shell_exec等,当用户可以控制命令执行函数中的参数时,将可注入恶意系统命令到正常命令中,造成命令执行攻击。

这个其实也可以类比为eval($_POST[‘’]);这种情况,当不控制转入的参数的时候,就会被控制。

漏洞危害

继承Web服务程序的权限去执行系统命令或读写文件
反弹shell
控制整个网站甚至控制服务器
进一步内网渗透

PHP涉及函数

常见函数

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():将文件中的每行内容以字符为单位反序输出,即第一个字符最后输出,最后一个字符最先输出,依次类推。

输出函数

cat函数 由第一行开始显示内容,并将所有内容输出
tac函数 从最后一行倒序显示内容,并将所有内容输出
nl 类似于cat -n,显示时输出行号
more 根据窗口大小,一页一页的现实文件内容
less 和more类似,但其优点可以往前翻页,而且进行可以搜索字符
head 只显示头几行
tail 只显示最后几行

命令执行函数

system() 输出并返回最后一行shell结果。
exec() 不输出结果,返回最后一行shell结果,所有结果可以保存到一个返回的数组里面。
passthru() 只调用命令,把命令的运行结果原样地直接输出到标准输出设备上。(替换system)

获取文件内容函数

pos()是current()的别名
pos():返回数组中当前元素的值
scandir():函数返回一个数组,其中包含指定路径中的文件和目录(获取目录下的文件)
localeconv():返回一包含本地数字及货币格式信息的数组。其中数组中的第一个为点号(.)

正则表达式:

元字符:

1、**+**,+ 号代表前面的字符必须至少出现一次(1次或多次)。

2、*****,* 号代表前面的字符可以不出现,也可以出现一次或者多次(0次、或1次、或多次)。

3、,? 问号代表前面的字符最多只可以出现一次(0次或1次)。

其中+ *具有贪婪性,这两个元字符会尽可能多的匹配字符。如果希望实现最小匹配、或是非贪婪,可以使用?来限制。

普通字符:

普通字符包括没有显式指定为元字符的所有可打印和不可打印字符。这包括所有大写和小写字母、所有数字、所有标点符号和一些其他符号。

[ABC] 匹配括号中的所有字符。

[^ABC] 匹配除了中括号中的所有字符

[A-Z] 表示一个区间,其中匹配所有的大写字母(当然,也可以[A-z]匹配所有的大小写)

. 匹配除了换行符之外的任何单个字符

[\s\S] 匹配所有,\s是匹配所有空白符,包括换行符,\S是匹配所有非空白符,不包括换行。

\w 匹配字母、数字、下划线

非打印字符:

image-20220329123107547

特殊字符:

许多元字符要求在试图匹配它们时特别对待。若要匹配这些特殊字符,必须首先使字符”转义”,即,将反斜杠字符\ 放在它们前面。下表列出了正则表达式中的特殊字符:

image-20220330191040233

限定符:

限定符用来指定正则表达式的一个给定组件必须要出现多少次才能满足匹配。有 * 或 + 或 ? 或 {n} 或 {n,} 或 {n,m} 共6种。

正则表达式的限定符有:

image-20220330191139231

定位符:

定位符使您能够将正则表达式固定到行首或行尾。它们还使您能够创建这样的正则表达式,这些正则表达式出现在一个单词内、在一个单词的开头或者一个单词的结尾。

定位符用来描述字符串或单词的边界,^ 和 $ 分别指字符串的开始与结束,\b 描述单词的前或后边界,\B 表示非单词边界。

正则表达式的定位符有:

image-20220330200551984

不能将限定符和定位符一起使用,因为在紧靠换行或者单词边界的前面或者后面不能有一个以上的位置(?)

所以不能使用^*这种形式的表达式。

如果要匹配一行文本开始的地方的文本,要在正则表达式的开始使用^字符。

单词边界是单词和空格之间的位置。非单词边界是任何其他位置。

\b 字符的位置是非常重要的。如果它位于要匹配的字符串的开始,它在单词的开始处查找匹配项。如果它位于字符串的结尾,它在单词的结尾处查找匹配项。

字符串 apt 出现在单词 Chapter 中的非单词边界处,但出现在单词 aptitude 中的单词边界处。对于 \B 非单词边界运算符,不可以匹配单词的开头或结尾。

这两个东西比较重要的作用就是可以标识想要匹配的字符串到底是在一个单词的开头还是中间,或是结尾。通过对部分字符串的位置进行标识,可以做到对匹配进行过滤。

eg:

可以只匹配 Chapter 中的字符串 apt,但不匹配 aptitude 中的字符串 apt。

反向引用:

对一个正则表达式模式或部分模式两边添加圆括号将导致相关匹配存储到一个临时缓冲区中,所捕获的每个子匹配都按照在正则表达式模式中从左到右出现的顺序存储。

缓冲区编号从 1 开始,最多可存储 99 个捕获的子表达式。每个缓冲区都可以使用 \n 访问,其中 n 为一个标识特定缓冲区的一位或两位十进制数。

可以使用非捕获元字符 ?:?= ?! 来重写捕获,忽略对相关匹配的保存。

基本应该就是引用其中一段的匹配式。

修饰符:

标记也称为修饰符,正则表达式的标记用于指定额外的匹配策略。

标记不写在正则表达式里,标记位于表达式之外,格式如下:

/pattern/flags

image-20220330211825418

元字符:

https://www.runoob.com/regexp/regexp-metachar.html

使用:

在Linux中,通配符?表示匹配单个字符。

这个就和之前表示的不一样了,需要特别看一下。

\i 与大小写都进行匹配
\w 与任意单词字符匹配,任意单词字符表示 [A-Z]、 [a-z]、[0-9]、_
\d 与任意数字匹配

上面这部分可以直接看元字符

Windows环境下的管道符:

1、|,表示直接执行后面的语句。

image-20220330213250836

直接执行了后面的whoami语句。

2、||,如果前面执行的语句出错(包括但不限于命令语句出错或者是后面的语句部分出错),就执行后面的语句。

image-20220330213427396

3、&,如果前面的语句为假则直接执行后面的语句,前面的语句可真可假。

image-20220401235516607

image-20220401235642058

4、&&,如果前面的语句为真,则先执行第一个命令,后执行第二个命令。如果为假,就两个都不执行。

image-20220401235819393

image-20220401235925143

Linux环境下的管道符:

1、;当执行完了前面的命令之后,就执行后面的。

ping www.baidu.com;whoami

1600512054_5f65e0364695687b45fad.png!small

2、|,只显示后面语句的执行结果

ping www.baidu.com|whoami

3、||,当前面的语句执行错误的时候,会执行后面的语句。

1600512086_5f65e056a06ea92ce6174.png!small

4、&,如果前面的语句为假,则直接指向后面的语句,前面的语句可真可假

无数字字母构造webshell:

当对输入进行了过滤之后,可以通过运算和拼接的方式来得到需要的字母或是数字。

常见的运算方式:

1、异或运算
2、按位与运算
3、按位或运算

例如在PHP中,当将两个变量的值进行异或的时候,会首先将两个变量的值转换为ascii,然后再将ascii进行二进制转换,之后再将两个变量进行异或,后将异或结果转换为ascii,将ascii转换为字符串。。

(这种PHP中的绕过方式其实是很常见的。)

两个变量->转换为ascii->转换为二进制->进行异或->异或二进制转换为ascii->转换为字符串。