Full transcript
0:00Docker. I barely know her. When SSRF is
0:03enough full Docker escape on Windows
0:06Docker Desktop CVE 20259074.
0:10This is a recent write up that I will
0:12leave a link in the video description.
0:13And I do want to give a big shout out.
0:14We'll hop over to his LinkedIn. Felix
0:17Boule. I'm so sorry. I don't know how to
0:19pronounce your last name. Felix.
0:21Sometimes bugs don't need to be that
0:22complicated. This is the tale of how I
0:24found the full Docker escape that was
0:26attributed CVE20259074.
0:29And that is now fixed. It is patched. So
0:31if you are running Docker for desktop on
0:34Windows or Mac OS, make sure you update
0:37upgrade get to version 4.44.3.
0:41Up until that version, an SSRF or like
0:43server side request forgery or a simple
0:46web request from any container was
0:48enough to fully compromise the host
0:51computer. Now you might think of Docker
0:52usually running containers in like oh an
0:55isolated sort of guest space but no we
0:57mean physically the whole computer the
0:59host computer where the Docker engine
1:01and Docker service runs. Felix wants to
1:04shout out Felipe Duger again I'm so
1:06sorry in pronunciation from Pivotal
1:08Technologies. He's a longtime friend and
1:10Docker expert. So I asked for his input
1:12and help during the research. I'll leave
1:14a link to his LinkedIn profile just as
1:16well in the video description. So here
1:17is the situation on an unpatched docker
1:20for desktop for Windows. Anything below
1:22version 4.44.3
1:24any container running container instance
1:26could connect to this IP address on this
1:30port without any authentication. They
1:32could create and start a privileged
1:34container so it could have access to the
1:35host and it could mount the host C drive
1:38running on Windows onto or into that
1:41container. With that you gain full
1:42access on the Windows host. That means
1:44you have access to the file system.
1:46That's not immediately a code execution
1:48on the host, but as I'm sure you know,
1:50you could leverage that write capability
1:53or any read capability, I guess, if you
1:54want on the Windows file system like to
1:57stage something into the startup folder
1:59or gain some other persistence via
2:01scheduled task or whatever and then
2:02eventually get further code execution
2:04and compromise the full computer. This
2:07192.168.65.7
2:0965.7 and port 2375 is the control plane
2:14or like the Docker service API, the
2:17capability to run Docker stuff, hey,
2:20spawn, start containers, create
2:22containers, etc. Again, I'll put a link
2:23to that in the video description, but
2:25I'm more interested in how can we play
2:27with it? Can we do this, too? I thought,
2:29let's go ahead and install Docker
2:31Desktop on Windows and then see if we
2:33could recreate this in a vulnerable
2:34version. Of course, if we were to go try
2:36and download Docker Desktop for Windows
2:38from their website, we'll get a Docker
2:41desktopinst installer.exe. And if you
2:43were to download this, this will be the
2:45patched version, like the latest 4.44.3.
2:48And there's no easy way that I could
2:50tell from the link or URL to be able to
2:52like adjust the version that you're
2:54downloading. I don't think they show or
2:56offer or include I couldn't at least
2:58couldn't track it down any previous or
3:00older versions of Docker Desktop from
3:03their website. So to be honest, the next
3:04thought that I had would be to look on
3:06virus total or is this hosted or
3:08available for download anywhere else on
3:10the internet. Virus Total keeps things
3:12kind of easy for us and we know that the
3:14file will now be called docker desktop
3:17installer.exe.
3:19So we could simply search for files like
3:20with that file name. And if we get a
3:22couple hits probably going to get things
3:24recent from todayish or around this time
3:27frame. And if we go click in one of
3:28these, the Docker desktop installer in
3:31the details section, we might be able to
3:33get a clue as to what the version is.
3:35Scrolling down, we could actually see,
3:37oh yeah, exactly. File version
3:39information. Zooming in a little bit
3:41more, you could see this section here
3:42with the file version included as part
3:44of the data for the portable executable
3:46or the.exe file itself. We could see
3:494.44.3.202
3:52blah blah blah. So that one is patched,
3:54right? That's version 4.44.3.
3:56I want the vulnerable one. So, could I
3:58simply just like add to my query? I
4:01don't see why not. Let's try to see.
4:03Could I just look for that as the file
4:05name kind of in strings. And I'm not
4:07even using like any operators here. I'm
4:08just going to make this stupid, dumb,
4:10and easy. Let me search for 4.44.2.
4:13Now, when we get results back, I do see
4:15a couple. Let's check the details on
4:16him. This one is perfect file version
4:19information. This clues us in 4.44.2.
4:23So, let me download this from virus
4:24total. Click download sample download
4:26file. And now I have the Docker desktop
4:29installer on my desktop. Let me say I
4:32usually record videos inside of a
4:34virtual machine because I just prefer to
4:35do that when looking at malware and
4:37vulnerabilities and exploits and weird
4:38stuff, right? But I always get a little
4:40bit sketched when I have to record on my
4:42host. This might be a scenario because I
4:44have not yet provisioned or set up even
4:46this desktop machine to uh virtualize
4:49inside of virtualized virtual machines.
4:51You know what I mean? like nested
4:52virtualization because Docker on Windows
4:55uses Windows Subsystem for Linux or WSL
4:58and WSL 2. You could use HyperV just as
5:01well, but let me see if I can get this
5:03installed. Okay, installation succeeded.
5:05I have to restart my computer though.
5:07And since it's my host, going to stop
5:08recording for a quick moment. Okay, I
5:11have rebooted. Now I am inside of Docker
5:14Desktop on Windows. We're going to ahead
5:16and start the Docker engine. I guess
5:18I'll move my face a little bit further
5:19down. Obviously, you could see I don't
5:20know if that's funny. New version is
5:22available. Yeah. Uh, we should update.
5:24I'll talk more about that later, but
5:25let's get this thing going just to show
5:26you it in action. Okay, looks like
5:28Docker on Windows is ready. So, let me
5:31open up a terminal. And do I have the
5:33command on the command line? Docker. I
5:35do. Okay. Excellent. All right. Now,
5:37let's bounce back to the write up and
5:39article for a quick second so we could
5:40see how the pock or proof of concept
5:42worked. The entire exploit takes two
5:45post HTTP calls from inside any
5:48container. Okay, kind of easy. post a
5:50JSON payload to /containers create. Now
5:53again this is like the API for the
5:55docker engine obviously giving us the
5:57capability to create a new container
5:59binding the host C drive to a folder
6:01inside the container like /mounthost C
6:04colhostroot in the container and using a
6:07startup cmd or command to write or read
6:10anything under that host routt on
6:12container startup. Now that we created
6:14the container, you do need to start it,
6:16but that's again just coming from the
6:18API or this connection 192.16868.57
6:22or whatever 2375 was the port. And you
6:24post to the container start endpoint
6:27with the ID of the container that you
6:29just created. That will launch the
6:30container and start execution. And
6:32because this is all webbased, right,
6:35like the fact that you're just making
6:36two post requests, you could do like
6:38with curl or wget or python or anything,
6:42right? uh you could have the opportunity
6:44to do this via a web app like if a web
6:47app were presented as a front-end
6:49application and maybe it was just served
6:52out of a container. Well, if there were
6:54a vulnerability in that application
6:55where you had SSRF or serverside request
6:58forgery, then you could just try to
7:00manipulate any of the capabilities like
7:02use that vulnerability on its own to now
7:04exploit this. They mentioned you don't
7:06need code execution or you technically
7:08don't need code execution because if
7:10there's an opportunity to still make
7:11those web requests without running
7:13commands, this is doable. There's some
7:15really cool lessons here in the spotting
7:17the gap sooner section. At its core,
7:19this is just kind of an oversight
7:20because that internal API is reachable
7:22from any container without
7:24authentication or any other access
7:25control. Good reminder that critical
7:27security gaps often stem from the most
7:28basic assumptions. And look, they found
7:30this just by running end mapap against
7:32the Docker documented private network.
7:34That's easy to do. It's not isolated, at
7:37least as we've learned. So, you could
7:39always test your network isolation and
7:41don't trust that all security models are
7:42aligned by default. Cool takeaways:
7:44internal interfaces are not inherently
7:46secure. Assess every access path and
7:48entry points, both external and internal
7:50tests and scans are essential. And work
7:52with your friends, encourage outside
7:54collaboration, even if that's just
7:55public and private bug bounty programs,
7:57to find these lowhanging fruit things.
7:59Because this is in essence simple,
8:01right? You're just creating a container,
8:02starting it, and then taking advantage
8:04of all the functionalities that Docker
8:06naturally gives you and with good
8:07intentions. Hey, mounting capabilities
8:09from the host, being able to run
8:11commands like that is good. So, it's
8:12just taking advantage of the fact that
8:14this is all possible with just the
8:16hiccup gimmick that oh, we could reach
8:18the internal API without any issue. They
8:21have a little uh proof.mpp4 or a video
8:23demonstration, but we could do the very
8:25same thing. We could try it out and run
8:26it ourselves. Proof of concept can be
8:28executed from any container running
8:30docker run tac it for interactive in a
8:33terminal and they just use an alpine
8:35image. So Linux right vanilla barebone
8:38basics alpine image using bin sh as
8:41their okay invoking command to run or
8:43entry point so that they have a shell
8:45they can interact from. Again not
8:47necessary because if there is an
8:49opportunity for ssrf this could all
8:50still be done. So let's take a look at
8:52this proof of concept that they have
8:54here. Obviously, this is just simple
8:56bash like running from the shell or bin
8:58sh as you ran within Alpine. And they're
9:01using wget, that small command line
9:03utility to be able to work with internet
9:04resources over HTTP. They send a header
9:07to provide a JSON blob. And the post
9:09data that they use is just like you
9:11would expect in any sort of Docker
9:13container configuration specifying, oh,
9:15let's create a new container with an
9:16Alpine image. Again, use a command or
9:18cmd where they invoke sh taxi to provide
9:21a command as an argument. And just as a
9:23simple test, they echo the word poned
9:25into hostroot/pone.ext.
9:28That of course could be anything you
9:29want to read or write files or take
9:32things out of the host machine, put it
9:33in the container or the guest or write
9:36what could be something in the startup
9:37directory for later access, persistence,
9:40post, exploitation, etc. The gimmick
9:42here though of course is using a host
9:44config that will bind or mount part of
9:46the host file system within the guest
9:49container. So the colon here is the
9:50delimiter and because hey you've got the
9:52capability to reach mounted hosts in
9:54/mount/host in the C drive of the
9:58computer Windows host machine in the
10:00directory/hostroot
10:02they don't output anything so t capital
10:04O to a hyphen or just nothing or maybe
10:07that's standard output forgive me we'll
10:08see it when we run it but obviously it's
10:10that exact same IP address and port
10:12number for the internal control plane or
10:15HTTP docker API they staged that as a
10:18temporary file just create.json. So in a
10:21later line, they could retrieve the
10:22container ID. That's that C ID variable
10:25that they set here. They're using
10:26command substitution with just the
10:28dollar sign parenthesis, the cut utility
10:30to use the delimiter of a double quote
10:32field number four out of that file
10:34create.json. And then with that, because
10:37you know that was the key ingredient, we
10:39needed to get to the other HTTP endpoint
10:41for their API containers container ID
10:44and then start it. No post is necessary
10:46there. We just needed to hit that
10:48endpoint with a post request but no like
10:50form data body payload. Does that make
10:52sense? Like we could go through the
10:53process of oh changing this command but
10:55I feel like we're okay. Check out one of
10:57the other previous videos when we were
10:58looking at the winar CVE. You can see
11:00how it might write on the file system to
11:03startup. So that way there's code
11:05execution just the computer begins and
11:07runs. Let's try to use this proof of
11:10concept. But first let's get a docker
11:12image running back on our terminal or
11:15command line. Remember this all happens
11:17inside of a guest container. So let's
11:19try to run tac it for interactive
11:21intelllete on the terminal. Alpine being
11:24the image name that we want to run and
11:26then the command or entry point will
11:27start with /bin/sh.
11:30Will that work for me? Okay, I have a
11:32Linux prompt here. Now I am the root
11:34user inside of this Alpine Linux image
11:37guest container. But if I were to you
11:40know what? Let's open up uh Windows
11:41Explorer. And you know what? Rather than
11:43exposing the root of my file system to
11:45you all on the internet, let me create
11:46just a directory for uh docker cve test.
11:50Obviously, this folder will start empty.
11:52But let's adjust our pock to now write
11:54to pone.ext inside of the host route or
11:58part of the file system where we do have
11:59docker cve test and a forward slash to
12:03note inside of that subdirectory there.
12:04Does that make sense? Let's copy all
12:06this and let me put these side by side
12:08and then let's paste in this command. I
12:11didn't I didn't have to do anything
12:13else. I didn't have to say anything. It
12:14already It just did it. Right. Open that
12:16up in Sublime Text. It's exactly what
12:18you think. Bear in mind, I'm on my host
12:20computer. This is my desktop machine.
12:23And I just wanted to do the little demo.
12:25Light off the fireworks here because of
12:27course we've now broken out of that
12:29Docker container that we were in and
12:31could have the capability on the whole
12:32rest of my machine. That's it. Those
12:34couple commands. Obviously, that is why
12:37this is a 9.3 CVS out of 10 critical
12:40severity. Okay. Uh breakout, escape the
12:43sandbox of a Docker instance. And I
12:45believe that's even beyond their
12:47encapsulated or enhanced container
12:49isolation feature functionality thing.
12:51There are links down below. We could go
12:53take a look at the CVE CV 20259074.
12:57Docker desktop allows unauthenticated
12:59access to a Docker engine API from
13:02containers. Yeah, even with or without
13:04enhanced container isolation enabled and
13:06with or without the exposed Damon on
13:08that instance. Now, this happens again
13:11only on Windows or at least that's what
13:13I've showcased. But if we take a look at
13:15the release notes from Docker, they're
13:18now offering this patch of 4.44.3. And
13:21this was released relatively quickly
13:22from what I understand. That's fixed.
13:24That's patched. But this is affecting
13:26Windows and Mac. If we look at Felipe or
13:29Phillip, I'm so sorry. If we look at his
13:32blog, he covers the exact same thing.
13:34And again, we'll have a link in the
13:35video description. He tells the whole
13:37story, which is kind of cool. A little
13:39bit of the human walk back of how this
13:41was approached. But of course, this is
13:43not going to be affecting Linux because
13:45Linux does not use a TCP socket for the
13:48Docker engine's API. It uses a name pipe
13:51on the host file system. Unless there's
13:52any like super specific unsafe
13:54misconfiguration, the container usually
13:56does not have access to that name pipe
13:58and can't make these internal engine
14:00like control plane calls to the API,
14:02right? But his little MacOSS proof of
14:05concept is done with just simple Python
14:07code and he imports Docker. You can see
14:09the syntax here. Import Docker, create a
14:11new client where you connect to that API
14:14and then run a whole new container of
14:16Alpine being the image. a command to run
14:19touching the or creating the file
14:21/mount/pone where it has now mounted
14:24from what would have been the MacOss
14:26file system/ users and their username
14:28now/mount inside the container neat easy
14:32too easy now here's the thing first and
14:34foremost you should patch you should
14:36update you should get the latest version
14:374.44.3 44.3 would recommend you do that.
14:40But I wonder and I'm curious of your
14:42take. So please genuinely let me know in
14:44the comments. What is the likelihood of
14:46this being exploited? It is within a
14:48container. You don't need the code
14:50execution to be ran within the
14:51container. If there were a forward
14:53front-facing web app that SSRF was an
14:55opportunity or the server side request
14:57forgery vulnerability existed, then you
14:59could sort of chain this or enact and
15:01invoke this via that. Maybe that's a
15:04thing. I don't know how easily you might
15:06be able to fingerprint for what looks
15:07like a web app being ran out of a Docker
15:09container with the old version on
15:11Windows or Mac, but granted that it
15:13should be a Docker container running in
15:15production if it were to be exposed
15:17probably out on the open internet via
15:19Windows or Mac. That seems just a little
15:21unlikely to me. Regardless, extremely
15:24cool, neat find, and I think Felix was
15:26pretty upfront like, "Hey, he stumbled
15:28across this." And him and his buddy, his
15:30friend were trying to go take a look,
15:32see how you could pull that thread. And
15:33that's how a whole lot of sweet fun
15:35security vulnerability research stuff
15:36just tends to happen. Real bummer that
15:38there wasn't a bug bounty or anything uh
15:40sort of a payout for him, but I think it
15:41sounds like he's getting a sweet merch
15:42bag. So cool. But there you go. You
15:44know, that's it. That's what everybody's
15:46screaming and shouting about for uh this
15:48big Docker 9.3 critical severity CVE
15:5120259074.
15:53Patch your potatoes, everybody. Thank
15:54you so much for watching. Please do all
15:56those YouTube algorithm things. Like,
15:57comment, subscribe. I'm going to go
15:58remove the uh vulnerable version of
16:00Docker that's installed on my host
16:02desktop machine. Uh, thanks. I'll see
16:03you