tom@home.htb:~$

Blog o HTB

17 November 2020

Lokálně dostupné služby po footholdu: localhost není boundary

Úvod a kontext

Mnoho systémů se spoléhá na jednoduchou domněnku: tahle služba je bezpečná, protože poslouchá jen na 127.0.0.1. To může fungovat proti anonymnímu návštěvníkovi z internetu. Jakmile ale útočník získá první shell, situace se zásadně mění. Z localhostu se stává plnohodnotná útočná plocha a interní porty najednou představují další vrstvu systému, kterou je potřeba prozkoumat stejně disciplinovaně jako veřejný web.

Tohle téma se částečně dotýká i SSRF, ale není to totéž. Samostatný článek o SSRF, reverse proxy a localhost trust assumptions řeší, jak se na interní službu dostat ještě před footholdem. Tento text naopak řeší situaci po prvním shellu: co hledat na 127.0.0.1, proč to bývá důležité a jak z lokálních služeb nevytvářet tichou druhou administrativu.

Proč localhost po footholdu přestává chránit

127.0.0.1 není autorizační model. Je to jen síťové umístění. Jakmile je útočník uvnitř hostu nebo kontejneru, otevírá se mu přístup k věcem, které byly dosud schované za lokálním bindem:

To je důvod, proč se po footholdu nevyplatí bezhlavě skenovat celou síť, ale velmi cíleně číst, co běží lokálně a jaký bezpečnostní význam tyto služby mají.

Co typicky na localhostu běží

Lokální služby po footholdu mívají několik opakujících se podob.

1. Interní administrační API

Aplikace často skrývá citlivější endpointy za lokální bind:

Předpoklad bývá jednoduchý: na localhost se přece veřejný uživatel nedostane. Po shellu je tento předpoklad pryč.

2. Datové služby a cache

Redis, InfluxDB, databáze, message brokery nebo jiné pomocné služby často neběží veřejně, ale lokálně. To je rozumné pouze tehdy, pokud se zároveň počítá s tím, že první kompromitace hostu tyto služby okamžitě zpřístupní.

3. Pomocné interní workflow

Na localhostu neběží jen standardní produkty. Často tam bývá i:

Právě tyto méně nápadné služby bývají po footholdu nejzajímavější, protože jsou navržené s implicitní důvěrou k lokálnímu volajícímu.

Jak tenhle vzorec vypadal v konkrétních případech

Na jednom hostu byl po prvním shellu klíčový až GraphQL endpoint na portu 8080, který zvenku vůbec nebyl vidět. Teprve lokální enumerace ukázala, že služba běží, a spojení s SeImpersonatePrivilege z něj udělalo přechod až k SYSTEM. Veřejný web byl důležitý jen pro foothold; skutečná eskalace ležela na localhostu.

Jinde se po vstupu pod účtem patrick ukázala interní InfluxDB na 127.0.0.1:8086, z níž šlo vytáhnout hesla dalších uživatelů. Až další lokální služba na 8443 otevřela přístup k chatu a jeho funkci /file, která vydala rootův klíč. Tady je velmi dobře vidět, že lokální služby po footholdu tvořily celý druhý útokový řetězec.

Další případ stál na tom, že uživatelský shell dovolil přes SSH port-forward osahat lokální službu na 13907. Nebyla veřejná a sama působila jako interní pomocník. Teprve ruční práce s protokolem a následné zhroucení privilegovaného wrapperu do debuggeru z ní udělaly cestu k rootu.

Na jiném systému zase běžela Kibana konzole jen na 127.0.0.1:5601. Zvenku se k ní nešlo dostat, ale po shellu se ukázalo, že umí načíst lokální soubor a že vedle ní běží log processing workflow s vysokými právy. Opět tedy nešlo o “jednu lokální službu”, ale o celý lokální ekosystém, který po footholdu najednou ztratil ochranu.

I kompromitovaný kontejner ukazuje stejný vzorec. Jakmile útočník získal shell uvnitř GitLab kontejneru, lokální Redis už nebyl interní služba chráněná bindem na loopback. Stal se přirozenou součástí útočné plochy daného runtime prostředí.

Jak k localhostu po footholdu přistupovat

Po prvním shellu má smysl uvažovat o localhostu jako o nové mapě systému, ne jako o jednom triku.

1. Nejdřív zjistit, co poslouchá

Bez přehledu o lokálních portech není možné odhadnout další směr. Důležitější než agresivní scan bývají:

ss -lntp
netstat -ano
lsof -i -P -n

Cílem není “najít všechno”. Cílem je pochopit:

2. Číst konfigurace a pomocné soubory

Lokální port sám o sobě ještě neřekne, co služba dělá. Hodnotu často přinese až:

Právě tam se ukáže, zda je lokální služba jen cache, nebo třeba plnohodnotné administrační API.

3. Testovat lokální služby v jejich kontextu

Jakmile je jasné, co na localhostu běží, dává smysl zkoumat:

Pořád nejde o bezhlavé fuzzování. Jde o čtení architektury hostu po kompromitaci.

Co se na localhostu hledá nejčastěji

Prakticky se vyplatí cíleně myslet na tyto kategorie:

Společný vzorec je pořád stejný: služba nebyla navržená tak, aby odolávala nedůvěryhodnému uživateli na stejném hostu.

Obrana a bezpečnější návrh

1. Localhost nebrat jako jedinou ochranu

Interní služba má mít vlastní autentizaci a vlastní autorizaci. Bind na 127.0.0.1 může být doplňkové omezení, ne jediný důvod, proč je něco “bezpečné”.

2. Oddělit role a práva procesů

Jestli veřejná aplikace běží pod účtem, který po compromise automaticky vidí citlivé lokální služby, je hranice mezi webem a interní vrstvou příliš tenká.

3. Minimalizovat hodnotu lokálních služeb

Lokální endpoint nemá vracet tajemství, číst libovolné soubory ani spouštět privilegované akce jen proto, že ho volá něco “ze stejného stroje”.

4. Po compromise počítat s plným přístupem k loopbacku

Threat model hostu musí předpokládat, že první shell automaticky znamená přístup k 127.0.0.1. Pokud některá interní služba tento scénář nepřežije, je třeba ji přepracovat nebo izolovat.

5. Monitorovat neobvyklé lokální vztahy mezi službami

Lokální přístupy mezi procesy, které se v běžném provozu nepotkávají, bývají silný signál útoku i chybného návrhu. Totéž platí pro podezřelé port-forwardy a náhlé volání interních konzolí z nečekaného účtu.

Shrnutí klíčových poznatků

Co si odnést do praxe

tags: localhost - post-exploitation - pivot - services