<div dir="ltr">Hello, I've found 4 vulnerabilities while auditing the rtmpdump project(git://<a href="http://git.ffmpeg.org/rtmpdump">git.ffmpeg.org/rtmpdump</a>).<br><br>1. Return value of the AMF3ReadString function in amf.c, causing out-of-bounds reading<br>During the second handshake stage, the string (message) can be encoded as a value or reference. The first identification string is a value or reference. 0 means that the string is encoded as value, and the remaining 28 bits are used for encoding its length. 1 means that the string is encoded as a quotation, and the remaining 28 bits are used for coded quotation. The code to decode the amf3 string is as follows:<br><br>int<br>AMF3ReadString(const char *data, AVal *str)<br>{<br>  int32_t ref = 0;<br>  int len;<br>  assert(str != 0);<br><br>  len = AMF3ReadInteger(data, &ref);<br>  data += len;<br><br>  if ((ref & 0x1) == 0)<br>    { /* reference: 0xxx */<br>      uint32_t refIndex = (ref >> 1);<br>      RTMP_Log(RTMP_LOGDEBUG,<br> "%s, string reference, index: %d, not supported, ignoring!",<br> __FUNCTION__, refIndex);<br> str->av_val = NULL;<br> str->av_len = 0;<br>      return len;<br>    }<br>  else<br>    {<br>      uint32_t nSize = (ref >> 1);<br><br>      str->av_val = (char *)data;<br>      str->av_len = nSize;<br><br>      return len + nSize;<br>    }<br>  return len;<br>}<br><br>int<br>AMF3_Decode(AMFObject *obj, const char *pBuffer, int nSize, int bAMFData)<br>{<br>……<br>  int len;<br>……<br> len = AMF3ReadString(pBuffer, &cd.cd_name);<br> nSize -= len;<br> pBuffer += len;<br>……<br>     if (nSize <=0)<br>{<br>invalid:<br> RTMP_Log(RTMP_LOGDEBUG, "%s, invalid class encoding!",<br>   __FUNCTION__);<br> return nOriginalSize;<br>}<br>     len = AMF3ReadString(pBuffer, &memberName);<br>……<br>}<br><br>The return value of AMF3ReadString is assigned to a signed variable “len”, which set len to  a negative number[CWE-196], and nSize and pBuffer are added and subtracted without testing. nSize represents the number of unread bytes in the buffer. After pBuffer += len (big unsigned int) then using it causes address controllable, length-controllable out-of-bounds read.<br><br>PoC (poc1.py) is in the attachment.<br>$ python2 poc1.py<br>$ rtmpdump -r rtmp://<a href="http://127.0.0.1/test/test">127.0.0.1/test/test</a> -o /dev/null<br>RTMPDump v2.4<br>(c) 2010 Andrej Stepanchuk, Howard Chu, The Flvstreamer Team; license: GPL<br>Connecting ...<br>INFO: Connected...<br>Segmentation fault (core dumped)<br><br><br>2. Misuse of snprintf in the HTTP_Post function in rtmp.c causes heap information leakage<br>The code is as follows:<br>static int HTTP_Post(RTMP *r, RTMPTCmd cmd, const  char *buf, int  len)<br>{<br>char hbuf[512];<br>int hlen = snprintf(hbuf, sizeof(hbuf), "POST /%s%s/%d HTTP/1.1\r\n"<br> "Host: %.*s:%d\r\n"<br> "Accept: */*\r\n"<br> "User-Agent: Shockwave Flash\r\n"<br> "Connection: Keep-Alive\r\n"<br> "Cache-Control: no-cache\r\n"<br> "Content-type: application/x-fcs\r\n"<br> "Content-length: %d\r\n\r\n", RTMPT_cmds[cmd],<br> r->m_clientID.av_val ? r->m_clientID.av_val : "",<br> r->m_msgCounter, r->Link.hostname.av_len, r->Link.hostname.av_val,<br> r->Link.port, len);<br>RTMPSockBuf_Send(&r->m_sb, hbuf, hlen);<br>hlen = RTMPSockBuf_Send(&r->m_sb, buf, len);<br>r->m_msgCounter++;<br>r->m_unackd++;<br>return hlen;<br>}<br><br>The maximum length of hbuf is 512 bytes, and the maximum length of characters written by snprintf is 512 bytes (sizeof(hbuf)). When the length of the formatted string is greater than 512, the excess part will be truncated, and the return value hlen represents the length of the string to be copied instead of the actual length of the actual copy. RTMPSockBuf_Send(&r->m_sb, hbuf, hlen); regards hlen as the length of the actual copy, which  sends more data from hbuf.<br><br><br>3. Negative memcpy length in AMF_EncodeString function in amf.c<br>The code is as follows:<br>char * AMF_EncodeString(char *output, char *outend, const AVal *bv){<br>if ((bv->av_len < 65536 && output + 1 + 2 + bv->av_len > outend) ||<br>output + 1 + 4 + bv->av_len > outend)<br>return  NULL;<br>if (bv->av_len < 65536){<br>*output++ = AMF_STRING;<br>output = AMF_EncodeInt16(output, outend, bv->av_len);<br>}<br>else{<br>*output++ = AMF_LONG_STRING;<br>output = AMF_EncodeInt32(output, outend, bv->av_len);<br>}<br>memcpy(output, bv->av_val, bv->av_len);<br>output += bv->av_len;<br>return output;<br>}<br><br>The bv->av_len can be negative, and a malicious command can be constructed to make parseAMF() using a negative memcpy length, causing DoS.<br><br>PoC:<br>$ rtmpdump -i "rtmp://<a href="http://media3.scctv.net/live/scctv_800">media3.scctv.net/live/scctv_800</a> conn=O:\05 conN=NS:\:0" -o /dev/null<br>rtmp://<a href="http://media3.scctv.net/live/scctv_800">media3.scctv.net/live/scctv_800</a> can be any valid online rtmp url.<br><br><br>4. 3-byte out-of-bounds read in the AMF3ReadString function in amf.c<br> Here the code is extracted from the amf.c AMF3_Decode function.<br>for (i = 0; i < cdnum; i++){<br>AVal memberName;<br>if (nSize <=0){<br>invalid:<br>RTMP_Log(RTMP_LOGDEBUG, "%s, invalid class encoding!", __FUNCTION__);<br>return nOriginalSize;<br>}<br>len = AMF3ReadString(pBuffer, &memberName);<br>RTMP_Log(RTMP_LOGDEBUG, "Member: %s", memberName.av_val);<br>AMF3CD_AddProp(&cd, &memberName);<br>nSize -= len;<br>pBuffer += len;<br>}<br><br>The patch for the CVE-2015-8270 vulnerability: if (nSize <= 0){…} prevents pBuffer from increasing out of bounds, but when nSize == 1, it bypasses the patch, and the subsequent AMF3ReadString can read up to 4 bytes afterwards, so it can read 3 bytes out of bounds.<br><br>PoC (poc4.py) is in the attachment.<br>$ python2 poc4.py<br>$ rtmpdump -r rtmp://<a href="http://127.0.0.1/test/test">127.0.0.1/test/test</a> -o /dev/null<br><br>Best regards,<br>Zhiquan Tang of Tencent Blade Team<br></div>