FFmpeg is a tool I came across some time ago while analyzing the encryption of a certain video website. It is extremely powerful and is the most commonly used open-source software for video processing, with widespread applications. It is extensively used in video websites and commercial software (such as YouTube and iTunes) and serves as the standard implementation for encoding/decoding many audio and video formats. In FFmpeg 2.X, improper handling of HTTP Live Streaming (HLS) m3u8 files can lead to SSRF vulnerabilities and arbitrary file read vulnerabilities. When a website allows users to upload multimedia files and processes them using FFmpeg, this vulnerability can be triggered.
HLS (HTTP Live Streaming)
HLS (HTTP Live Streaming) is a streaming protocol developed by Apple based on the HTTP protocol. It is widely used on PCs and iPhones. Its basic principle is to split a video stream into many small TS stream files, which are then downloaded via HTTP in small chunks. When a new streaming session starts, the client first downloads an m3u8 (playlist) file, which contains all the data for the HLS session.
In simple terms, HLS is a video streaming file format. Most video websites today use streaming media to play videos. To put it in my own words, a complete video file is split into numerous TS files. TS files are still video files, but each TS file represents a very short duration of the video.
The index file for HLS, also known as the m3u8 text file, acts as the playlist.
The logic for playing HLS video streams on the client side is straightforward. First, the client downloads a primary index file, which contains the addresses of secondary index files (e.g., Alternate-A, Alternate-B, Alternate-C). The client then downloads the secondary index files, which in turn contain the download addresses for TS files. This allows the client to sequentially download TS video files and play them continuously.
#EXTM3U #EXT-X-TARGETDURATION:8 #EXT-X-ALLOW-CACHE:YES #EXT-X-PLAYLIST-TYPE:VOD #EXT-X-VERSION:3 #EXT-X-MEDIA-SEQUENCE:1 #EXTINF:3.754, seg-1-f1-v1-a1.ts?1mqgoyWZAC6vEjtMMTcvGkyU5AimjYcZuGVfPqAufYI769J-tDClP-xags8qqmD5umWfpLyFAP5hwohKTpafGO5K_YUNc1kX05uBi5aOEM9LUzUdXeFmKSoqVUtlWwIDDzsdIUwBsZ4LIgpc4PtGQDflORbu7nMMg-W5rNWM_wnyLJMW8le4M39TwCecyXAgwLYJM7trTWZBMWWhpQQg ...... #EXTINF:7.257, seg-1162-f1-v1-a1.ts?1mqgoyWZAC6vEjtMMTcvGkyU5AimjYcZuGVfPqAufYI769J-tDClP-xags8qqmD5umWfpLyFAP5hwohKTpafGO5K_YUNc1kX05uBi5aOEM9LUzUdXeFmKSoqVUtlWwIDDzsdIUwBsZ4LIgpc4PtGQDflORbu7nMMg-W5rNWM_wnyLJMW8le4M39TwCecyXAgwLYJM7trTWZBMWWhpQQg #EXT-X-ENDLIST
Here, I use an example m3u8 file from a certain website, showing only the beginning and end portions.
- #EXTM3U: The header of an m3u8 file, which must be present at the beginning.
- #EXT-X-TARGETDURATION: The maximum duration of each TS segment, which is 8 seconds in this case.
- #EXT-X-ALLOW-CACHE: Indicates whether caching is allowed.
- #EXT-X-VERSION: This tag is optional.
- #EXT-X-MEDIA-SEQUENCE: The sequence number of the first TS segment.
- #EXTINF: Specifies the duration of a TS stream segment.
- #EXT-X-ENDLIST: Acts as the end-of-file marker.
These are the basic tags of an m3u8 file. The issue arises when FFmpeg requests TS stream files. Since we can forge an m3u8 file, FFmpeg does not validate the stream addresses and directly makes the requests.
Now that we have a basic understanding of HLS, letâs look at the vulnerability itself. Vulhub provides an environment with a video upload feature for this vulnerability.
<?php if(!empty($_FILES)){$filename=escapeshellarg($_FILES['file']['tmp_name']);$newname='./'.uniqid().'.mp4';shell_exec("ffmpeg -i $filename$newname");} ?>
From the command `ffmpeg -i $filename $newname`, we can see that the parameters are directly passed to FFmpeg for execution without any validation of the uploaded file. Here, we upload a custom-crafted m3u8 file.

In this example, I retained only the necessary parameters for the m3u8 file (#EXT-X-MEDIA-SEQUENCE or #EXT-X-TARGETDURATION must be present; the former defines the sequence number of TS stream files. Removing them will result in an error: invalid file). Then, I submitted this file.

At the same time, I used `nc` on my VPS to listen on the corresponding port.

From the user-agent, it is evident that the request was indeed made by FFmpeg/libav, which directly initiated an HTTP request. This results in an SSRF. Combining this SSRF with arbitrary file reading, letâs examine the protocols supported by FFmpeg.
Input Protocols:
applehttp, bluray, cache, concat, crypto, data, file, gopher, hls, http, httpproxy, https, mmsh, mmst, pipe, rtp, srtp, tcp, tls, udp, rtmp, rtmpe, rtmps, rtmpt, rtmpte
Output Protocols:
file, gopher, http, httpproxy, https, md5, pipe, rtp, srtp, tcp, tls, udp, rtmp, rtmpe, rtmps, rtmpt, rtmpte