Alla artiklar
#pgadmin#docker#misconfiguration#incident-response#rce#cryptominer#postgres#container-security

Tre sekunder från internetscan till kryptominer: pgAdmin i desktop-läge

Alexander Norman

En pgAdmin-container publicerad mot internet med SERVER_MODE satt till False har ingen autentisering alls. Den som når porten är redan inloggad som administratör. I en färsk incident tog det tre sekunder från första anropet till körande kryptominer, med hjälp av en färdigsparad databasanslutning som containern själv tillhandahöll.

Kort version

Fyra inställningar i ett enda Docker Compose-block bildade tillsammans en fullständig kompromettering. Var för sig ser de rimliga ut, och tre av dem förekommer i guider och exempelkonfigurationer. Ihop publicerade de ett autentiserat databasadministrationsverktyg mot öppna internet.

Hela attacken tog tre sekunder, från början till slut, och utfördes av en automatiserad scanner som använde python-requests. Det var ingen riktad attack. Det var en maskin som hittade en öppen dörr enligt schema.

De fyra inställningarna

yaml
pgadmin:
  ports:
    - "5050:80"                                          # 1. publicerad på 0.0.0.0
  environment:
    PGADMIN_CONFIG_SERVER_MODE: 'False'                  # 2. ingen autentisering alls
    PGADMIN_CONFIG_MASTER_PASSWORD_REQUIRED: 'False'     # 3. sparade uppgifter fritt användbara
    PGADMIN_SERVER_JSON_FILE: '/pgadmin4/servers.json'   # 4. förkonfigurerad DB-anslutning
    PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_PASSWORD:-admin} #    (standardlösenord, spelar ingen roll nu)

1. "5050:80" binder mot alla gränssnitt. Dockers korta portsyntax utgår från 0.0.0.0, så containern är nåbar från internet om inte en brandvägg säger annat. "127.0.0.1:5050:80" hade begränsat den till värden.

2. SERVER_MODE: 'False' är den avgörande. pgAdmin har två lägen. Server-läget är fleranvändarläge och kräver inloggning. Desktop-läget utgår från att programmet körs på din egen dator, där operativsystemet är säkerhetsgränsen, och autentiserar därför inte alls. I en container publicerad mot internet blir varje besökare automatiskt administratör.

Det är därför loggarna varken innehöll misslyckade inloggningar eller brute force. Det fanns inget inloggningssteg att misslyckas med. Det är också därför den här typen av incident är lätt att missa vid loggranskning: angriparens anrop ser exakt ut som en administratörs.

3. MASTER_PASSWORD_REQUIRED: 'False' tar bort spärren som skyddar sparade anslutningsuppgifter.

4. PGADMIN_SERVER_JSON_FILE förladdar en databasanslutning, och den tillhörande pgpass-filen innehåller databaslösenordet i klartext. Den automatiska administratören möttes alltså av en färdig, fungerande databasanslutning.

Standardlösenordet på femte raden är närmast en fotnot. När autentiseringen är avstängd skyddar lösenordet ingenting.

Vad angriparen gjorde

mermaid
flowchart TD
    A["Massscanner hittar<br/>öppen port 5050"] --> B["POST /browser/master_password<br/>rensar spärren"]
    B --> C["Skapar och ansluter<br/>ett serverobjekt"]
    C --> D["POST /import_export/job<br/>kör en binär som ett 'jobb'"]
    D --> E["Hämtar och startar<br/>kryptominern"]
    E --> F["DELETE serverobjektet<br/>tar bort sitt eget spår"]

Exekveringssteget missbrukar pgAdmins import/export-funktion, som kör en binär på servern som ett bakgrundsjobb. Det är en dokumenterad funktion, och sårbarheter av typen CVE-2024-3116 handlar just om att den vägen blir nåbar för någon som inte borde ha den. Med autentiseringen avstängd är "någon som inte borde ha den" hela internet.

Städsteget är värt att notera. Scannern raderade serverobjektet den själv skapat, vilket tar bort det uppenbara spåret i pgAdmins gränssnitt. Anropsloggen hade fortfarande allt, och minerbinärens skapelsetid stämde med anropens tidsstämplar på sekunden.

Vad som drabbades, och inte

Databasen klarade sig: inga angriparskapade roller, inga superusers, inga externa anslutningar, inga tecken på manipulation. Minern ville ha CPU, inte data, vilket är typiskt för opportunistisk scanning.

Det är tur snarare än design. Pgpass-filen med databaslösenordet var läsbar för den automatiska administratören, så uppgiften måste behandlas som röjd oavsett om den användes. Att rotera den är inte valfritt.

Vad du bör göra

Om du kör pgAdmin i container:

  • Sätt aldrig SERVER_MODE: 'False' på något som är nåbart över nätverk. Det är en inställning för din egen dator.
  • Bind administrationsverktyg till localhost (127.0.0.1:5050:80) och nå dem via SSH-portforwarding eller VPN. Ett administrationsgränssnitt har inget på en publik port att göra.
  • Förladda inte databasuppgifter i containern. Bekvämlighet för dig är bekvämlighet för den som kommer först.
  • Måste du exponera det, sätt autentisering framför och behåll MASTER_PASSWORD_REQUIRED påslagen.

Mer generellt: behandla varje publicerad port som en inventarielista. docker ps visar vad du publicerat, jämför det med vad du menade att publicera. I det här fallet hade en enda genomgång av docker port fångat felet, när som helst, innan scannrarna gjorde det.

Tror du att det hänt dig: stoppa containern i stället för att radera den först, så att bevisen finns kvar. Spara anropsloggarna, hasha oväntade binärer, och kontrollera både databasroller och aktiva anslutningar. Rotera sedan alla uppgifter containern kunde läsa, och ta bort verktyget snarare än att konfigurera om det om du inte faktiskt behöver det igång.

Den obekväma delen

Tre av de fyra inställningarna finns för att göra utvecklingsarbetet enklare, och de dyker upp i blogginlägg och startmallar just för att de verkligen gör det. Felet var inte exotiskt. Det var en utvecklingsformad konfiguration som hamnade i en internetformad miljö, vilket är ett av de vanligaste sätten att förlora system på.

Försvaret är tråkigt och effektivt: veta vad som är publicerat, och utgå från att allt på en publik port hittas av en automatiserad scanner inom dagar.


Adminor arbetar med attackyteövervakning och säkerhetstestning. Vill du veta vad er organisation just nu har publicerat mot internet, hör av dig.

Vill ni se vad er externa angreppsyta egentligen ser ut? Gratis hälsokoll, ingen creditcard, två minuter.