Security Professionals - ipfw add deny all from eindgebruikers to any

hardening van mailen vanuit WordPress

04-09-2021, 06:13 door Anoniem, 13 reacties
WordPress Plugin Contact-form-7 maakt gebruik van Exim's sendmail met parameters "-t -i" en ook de exim4 executable voor (hier lokale LMTP) bezorging onder Debian 11.

Dat is niet wenselijk voor hardening doeleinden want dan moet de php7.4-fpm service via systemd rechten hebben om te doen wat exim4 doet. Het zou beter zijn als je vanuit de php code een mailbestand kunt plaatsen in de Exim queue en aan de draaiende Exim4 service de bezorging over te laten. Kan dat? Zo ja, hoe?

De gehardende php7.4-fpm heeft geen netwerkrechten (geen DNS), wel Unix sockets.
Reacties (13)
04-09-2021, 09:50 door Anoniem
Daar is de spooler directory voor.
04-09-2021, 10:27 door Anoniem
Nee niet php moet die rechten hebben, maar sendmail (in dit geval het sendmail programma wat bij exim4 hoort).
En uiteraard moet php dat sendmail programma kunnen starten.
04-09-2021, 11:06 door Anoniem
Ik ben totaal geen kenner van Wordpress (en die plugin) en van Exim4, maar ik was nieuwsgierig genoeg om even de documentatie van de plugin die je noemt in te duiken. Wat me daar opvalt is dat er met geen woord gerept wordt over hoe een e-mail eigenlijk verzonden wordt. Dat doet mij vermoeden dat die plugin zich daar ook niet mee bemoeit maar dat overlaat aan Wordpress [*]. Je mededeling dat de plugin sendmail/exim4 gebruikt zou dan niet kloppen, het zou Wordpress zelf zijn die dat doet, en de plugin zou dan weer gebruik maken van de faciliteit die Wordpress ervoor biedt.

Het sendmail-commando is trouwens iets dat meerdere mailservers op Linux/Unix bieden, om compatibel te zijn aan het oorspronkelijke sendmail. Het heeft als het goed is helemaal niet de rechten nodig van de mail-daemon (exim4), maar levert alleen mail aan de daemon aan. Bij jou kennelijk via LMTP, als ik goed plaats waar dat gebruikt wordt, maar dat had ook bijvoorbeeld een maildrop-directory kunnen zijn waaruit de mail-daemon de berichten oppakt. Als dat inderdaad via LMTP gebeurt is dat denk ik al een duidelijke indicatie dat je het over met elkaar communicerende processen hebt die helemaal niet met dezelfde rechten hoeven te draaien.

Wat jij denk ik nodig hebt is een beter inzicht in wat nou eigenlijk precies door welke component wordt geregeld en hoe dat gebeurt en met elkaar samenhangt. Ik doe hier natuurlijk de nodige aannames, ik ben niet de diepte in gegaan, maar als mijn aannames kloppen denk ik dat de plugin het versturen van e-mails aan Wordpress overlaat, dat Wordpress daarvoor het sendmail-commando aanroept, en dat dat een e-mail aan Exim aanlevert zonder daarvoor met de rechten van Exim zelf te moeten draaien.

Zorg dat je die hele ketting van acties goed in beeld hebt. Ga per onderdeel de documentatie bekijken om te zien hoe het eigenlijk werkt, onder welke rechten het draait, wat daaraan in te stellen is, wat die instellingen nu zijn en wat ze zouden moeten zijn. Behalve de documentatie van de plugin heb je ook de documentatie van Wordpress zelf te raadplegen en die van Exim, inclusief die van het door Exim geleverde sendmail-commando.

[*] Dat de plugin het aan Wordpress overlaat lijkt te worden bevestigd in de FAQ. Daar staat een vraag over het oplossen van een foutmelding met een rode rand, die mogelijk kan worden opgelost door een andere mailserver te kiezen. Het antwoord linkt naar een pagina van Wordpress over SMTP-plugins. Ik moet zeggen dat ik een beetje de kriebels krijg van documentatie die overslaat om aan te geven hoe het geheel eigenlijk is opgebouwd. Je hebt meer aan documentatie die een volledig overzicht geeft, het ontbreken daarvan betekent in mijn ervaring meestal dat je voortdurend tegen verrassingen aan kan lopen die je moeilijk had kunnen zien aankomen. Ik vind dat geen goed teken, en wellicht is dat precies de reden dat jij nu overzicht mist en vragen stelt.
04-09-2021, 12:03 door Anoniem
Door Anoniem: Nee niet php moet die rechten hebben, maar sendmail (in dit geval het sendmail programma wat bij exim4 hoort).
En uiteraard moet php dat sendmail programma kunnen starten.

Helaas, sendmail en exim worden gestart vanuit het profiel/omgeving van php7.4-fpm (strace). De extra sendmail/Exim rechten zijn op deze manier noodzakelijk.

@ Vandaag, 09:50 door Anoniem
Exim moet o.a. weten wat de bestemming is, daar doet sendmail met -i -t. sendmail plaatst bestanden in de spooler directories en het past databases aan, als je een bestand bekijkt zie je dat bovenaan het bestand allerlei metadata staat. Dus alleen een bericht plaatsen is onvoldoende, daar gebeurt dan niets mee.
04-09-2021, 15:35 door Anoniem
Door Anoniem: WordPress Plugin Contact-form-7 maakt gebruik van Exim's sendmail met parameters "-t -i" en ook de exim4 executable voor (hier lokale LMTP) bezorging onder Debian 11.

Dat is niet wenselijk voor hardening doeleinden want dan moet de php7.4-fpm service via systemd rechten hebben om te doen wat exim4 doet. Het zou beter zijn als je vanuit de php code een mailbestand kunt plaatsen in de Exim queue en aan de draaiende Exim4 service de bezorging over te laten. Kan dat? Zo ja, hoe?

De gehardende php7.4-fpm heeft geen netwerkrechten (geen DNS), wel Unix sockets.

Huh ?
Ik snap niet waarom php of een andere client die extra rechten nodig zou hebben ?

De klassieke Unix mail manier is nu juist dat de mailclient (cron, mutt, elm, mail ) sendmail of andere MTA aanroept en de mail en ontvangers geeft .
Het is dan het mailsysteem die de dns en socket rechten heeft , schrijfrechten in spooldirectories, en eventueel de extra privileges om in de homedir van local users af te leveren .

Ik vraag me dus af wat er gedaan is zodanig dat (phpuser) geen exim -bm <recipients> msg mag uitvoeren ?

Het lijkt me in elk geval geen vooruitgang om phpuser dan rechten te gaan zitten geven om in mailspools te schrijven (en evt rechten om exim een zetje geven 'process spooldir nu' ).
04-09-2021, 19:40 door Anoniem
Door Anoniem:
Helaas, sendmail en exim worden gestart vanuit het profiel/omgeving van php7.4-fpm (strace). De extra sendmail/Exim rechten zijn op deze manier noodzakelijk.
Dat klopt niet! In Linux kan een proces wat je start best meer rechten hebben dan het proces wat het opstart!
Dat kan met setuid/setgid, met setcap, en wellicht nog wel op meer manieren.
(dit zijn acties op de sendmail binary die in het filesystem worden opgeslagen en die bepalen met welke rechten het
programma draait)
04-09-2021, 19:47 door Anoniem
Overigens als je geen gedoe met rechten wilt hebben dan kun je ook zorgen dat exim4 luistert op localhost:25 en dan
in PHP de mail met SMTP naar localhost laten afleveren (direct het SMTP protocol praten in PHP dus).
Dan hoef je geen externe executables te starten. De exim4 daemon draait dan en pakt die mail aan en levert die af.
Je kunt configureren dat je alleen op localhost (::1 of 127.0.0.1) wilt luisteren, zodat je niet het risico loopt om een open
mailserver te worden. Dat is een standaardsituatie, meestal is dat zelfs de default na installatie van een exim4 pakket
op een Linux distributie. En dat is niet voor niets want dit is een gebruikelijke manier van werken voor afleveren van
lokaal gegenereerde mail.
04-09-2021, 21:37 door Anoniem
@ Vandaag, 11:06 door Anoniem
Ja, het klopt dat een ander deel van WordPress de daadwerkelijke verzending doet. Dat is vermoedelijk phpmailer. Strace laat niet precies zien wie wat doet, maar het laat wel zien welk proces wat doet. Strace attached aan de pid's van php7.4-fpm, dat is 1 root proces en 2 www-data processen en een aantal threads. Ik zie dus wel wat er gebeurt, maar niet wie wat doet.

Misschien kan ik voor dit geval sendmail/exim4 overslaan en rechtstreeks het bericht in de lokale IMAP structuur (Maildir/new) plaatsen. Dat is een hack, daarvoor zou ik de code van de Contact Form plugin moeten aanpassen. Dat is lastig met updaten.

Ik wil niet het wiel opnieuw uitvinden, vandaar dat ik het hier vraag.

@ Vandaag, 15:35 door Anoniem
Linux Systemd werkt met een context, zodanig dat je niet elk proces volledige root rechten hoeft te geven. Je kunt vergaand beveiligen. Kijk met
systemd-analyze security
of
systemd-analyze security php7.4-fpm
. Elk proces wat vanuit de daemon wordt gestart heeft daarmee ook de environment met de geselecteerde set permissies en blokkeringen van die service.conf.

Het werkt als is een container waarbij extra rechten/blokkeringen over het file systeem en andere interne systemen en API's worden gelegd. Zo kun je bijvoorbeeld wel Unix sockets toelaten, en geen IPv4 en IPv6. Je kunt er ook voor kiezen dat alle netwerkverkeer voor IPv4 en IPv6 lokaal moet zijn. Dat soort dingen heeft een sterk effect op de beveiliging. Stel dat je PHP wordt gehackt, dan heeft die niet zomaar de mogelijkheid data naar het internet te sturen.

Apparmor, LXC doen iets soortgelijks met profielen.

# systemd-analyze security
UNIT EXPOSURE PREDICATE HAPPY
apache2.service 4.4 OK
dovecot.service 3.9 OK
exim4.service 4.5 OK
mariadb.service 1.7 OK
php7.4-fpm.service 4.4 OK
ssh.service 9.6 UNSAFE
systemd-ask-password-console.service 9.4 UNSAFE
systemd-ask-password-wall.service 9.4 UNSAFE
systemd-fsckd.service 9.3 UNSAFE
systemd-initctl.service 9.4 UNSAFE
systemd-journald.service 4.3 OK
systemd-logind.service 2.6 OK
systemd-networkd.service 2.9 OK
systemd-timesyncd.service 2.1 OK
systemd-udevd.service 8.0 EXPOSED
unattended-upgrades.service 9.6 UNSAFE

Laag is goed. Hoog is slecht. Je ziet hier dat Apache2, Exim4, php7.4-fpm en Mariadb al handmatig zijn beveiligd. Nog lang niet alle (systeem-)processen zijn goed beveiligd in een standaard Debian 11 installatie.

Als je SSH zou dichtschroeven erf je de beperkingen van die omgeving als je inlogt.
05-09-2021, 08:36 door Anoniem
Door Anoniem: Linux Systemd werkt met een context, zodanig dat je niet elk proces volledige root rechten hoeft te geven. Je kunt vergaand beveiligen. Kijk met
systemd-analyze security
of
systemd-analyze security php7.4-fpm
. Elk proces wat vanuit de daemon wordt gestart heeft daarmee ook de environment met de geselecteerde set permissies en blokkeringen van die service.conf.
Ben je ervan op de hoogte dat daemons als apache2 en exim4 hun werk helemaal niet als root doen? Ze starten weliswaar als root, maar dat dient om naar gepriviligeerde poorten (poortnummers onder 1024) te kunnen luisteren. Ik zie dat exim4 na allocatie van die poorten van root overstapt op de user Debian-exim. Apache2 maakt een fork (kloon) van zichzelf die terugvalt naar user www-data, die de poort(en) om naar te luisteren erft en (via verder geforkte worker-processen) requests afhandelt. Het proces dat nog onder root blijft draaien dient om als er iets goed misgaat, als bijvoorbeeld de netwerkverbinding opnieuw gealloceerd moet worden, de zaak helemaal opnieuw op te starten. Voor dat soort dingen heeft systemd ook faciliteiten, maar apache2 (en trouwens ook exim) zijn ouder dan systemd en kunnen ook draaien op systemen zonder systemd.

Dat bijvoorbeeld apache2 op Debian in de defaultconfiguratie een hele dikke UNSAFE van 'systemd-analyze security' krijgt wil daarom niet zeggen dat het ook echt zo droevig gesteld is ermee, systemd-analyze pikt niet op wat apache2 zelf al doet. Daarmee wil ik niet beweren dat de toegevoegde mogelijkheden van systemd onzin zijn, je kan je met systemd bijvoorbeeld onafhankelijk maken van de vraag of het in de daemon-software zelf wel goed is geïmplementeerd.

Misschien kan ik voor dit geval sendmail/exim4 overslaan en rechtstreeks het bericht in de lokale IMAP structuur (Maildir/new) plaatsen. Dat is een hack, daarvoor zou ik de code van de Contact Form plugin moeten aanpassen. Dat is lastig met updaten.
Niet doen, dat wordt veel te getruukt. Als je de neiging hebt om dat soort dingen te gaan doen is dat een signaal dat je de verkeerde weg inslaat of al ergens de verkeerde weg in bent geslagen. Dat laatste los je niet op door verder te gaan op de verkeerde weg en te proberen de gevolgen te bestrijden, dat los je op door terug te gaan naar het punt waar je verkeerd ging en daar de goede weg te nemen.

Je noemde dat naast sendmail ook exim4 als commando wordt aangeroepen vanuit php7.4-fpm, voor locale bezorging via LMTP. Als ik het goed begrijp ondersteunt exim4 dat als manier om via unix sockets (die je ook noemt) mail aan te leveren aan een ander proces. Begrijp ik goed dat je niet alleen sendmail uitvoert om mail te bezorgen maar ook exim4 om het vanuit je php7.4-fpm-container door te geven aan de eigenlijke exim4-service, omdat dat niet vanzelf blijkt te werken?

Ik heb in de verste verte niet genoeg kennis van zowel exim4 als van de mogelijkheden van systemd die je gebruikt, maar als ik me niet vergis is sendmail dezelfde executable als exim4 en gebruikt die de suid-bit om met andere/hogere rechten te draaien dan de gebruiker die hem aanroept. Het lijkt me dan heel waarschijnlijk dat de container die je via systemd hebt ingericht blokkeert dat sendmail de aangeleverde berichten nog kan plaatsen waar de exim4-daemon ze kan oppakken, omdat de suid-user binnen een container alleen maar binnen die container rechten heeft en niet daarbuiten. En dan vermoed ik dat de LMTP-oplossing bedoeld was om die beperking te omzeilen, maar dat je er tegenaan loopt dat dat om een (nog) onduidelijke reden ook niet werkt.

Overweeg of het volstaat om, in plaats van alle netwerktoegang te blokkeren, php7.4-fpm alleen localhost toe te staan. Dat kan je in de servicedefinitie met IPAddressAllow=localhost en IPAddressDeny=any regelen (zie "man systemd.resource-control"), en dan kan je de suggestie van Anoniem van gisteren om 19:47 volgen: lever aan de exim4-daemon aan via SMTP en zonder ingewikkelde constructies waar je het overzicht over kwijtraakt.

Als het per se op poortniveau moet worden dichtgetimmerd is het mogelijk om systemd-services van een eigen firewall te voorzien die ook op poortniveau kan filteren, maar helaas wordt dat weer knap ingewikkeld, je moet er zogenaamde BPF-programma's voor schrijven en daaraan refereren met de opties IPIngressFilterPath en IPEgressFilterPath. Zie bijvoorbeeld hier voor een indruk van wat die BPF-programma's om het lijf hebben:

https://kailueke.gitlab.io/systemd-custom-bpf-firewall/

Je zou in plaats daarvan ook met iptables of nftables een firewall-regel kunnen maken die blokkeert dat vanaf de server zelf verbinding wordt gemaakt met andere dan toegestane poorten op localhost. Dat is minder specifiek (je regelt zo niet welk proces welke poort mag benaderen) maar ook veel simpeler dan geklooi met BPF-programma's, en iemand die jou ooit moet vervangen zal vermoedelijk eerder bekend zijn met Netfilter-interfaces dan met die BPF-programma's.

Ik kan niet voor jou invullen wat nodig is voor dit systeem, maar sla niet door in complexiteit, want het is heel makkelijk om dingen ingewikkelder te maken dan je zelf nog aankan, zeker als je middenin worstelingen zit om iets aan de praat te krijgen. Dan ga je fouten maken, en fouten leveren risico's op, voor de beveiliging en voor de continuïteit. Probeer het zo simpel mogelijk te houden, liefst beduidend simpeler dan je op dit moment denkt aan te kunnen, want de werkelijkheid heeft de vervelende neiging om een beroep te doen op je kennis en overzicht op momenten dat je met heel andere puzzels zit te worstelen en er eigenlijk geen ruimte voor hebt.
05-09-2021, 10:06 door Anoniem
Door Anoniem:
Linux Systemd werkt
Die 3 woorden kom je meestal niet in combinatie tegen.
"Systemd kan niet" of "systemd geeft problemen met" etc dat is veel gebruikelijker.
Als je graag problemen wilt, dan ben je met systemd goed bezig!
18-09-2021, 09:00 door Anoniem
Voor degenen die willen weten wat het uiteindelijk geworden is:

In de PHP code schrijft een bestand met de inhoud (body) van het formulier onder function compose naar current working directory: /var/www/phpsite. Er kan nergens anders een bestand worden geschreven, want PHP code mag dat niet.

Ik heb een programma in (veilig) C geschreven dat het bericht ophaalt in de /var/www/phpsite directory leest, SMTP headers voorvoegt en als kant en klaar bericht met de door Dovecot geadviseerde naam in de Maildir/new directory van de virtuele gebruiker plaatst. Voor het ontdekken van een nieuw bericht is inotify()'s IN_CLOSE_WRITE event en een add_watch op directory niveau toegepast. inoftiy maakt deel uit van de Linux kernel. Zodra PHP de file write+close in de phpsite directory uitvoert zorgt inotify voor een seintje naar het programma. Door deze systeem API verbruikt het programma praktisch geen cpu cycles, het staat onderaan het lijstje processen in top.

Er is een systemd service gemaakt voor het programma. Deze service draait onder een user account zonder home directory. Enkele speciale rechten zijn wel nodig: CAP_CHOWN, @privileged. SupplementaryGroups is gebruikt om de gebruiker lid te maken van zowel www-data als vmail. Geen netwerkrechten (o.a. RestrictAddressFamilies=~). TemporaryFileSystem maakt een tijdelijke root aan met 2 BindPaths naar de bron en doel directory's. Een flink aantal directories is ontoegankelijk gemaakt met InaccessiblePaths. De output van het programma is te zien in de daemon logs. De systemd-analyze security score is 1.0, dat kan nog iets beter.

Het doel is hiermee behaald: een veilige manier om formuliergegevens in een lokale mailbox te bezorgen zonder PHP netwerkrechten te geven. Zodra PHP netwerkrechten heeft kan het eenvoudig data weg laten lekken. Met Unix sockets of alleen lokaal netwerk zou het misschien ook gewerkt hebben, dan zou email vrij verstuurbaar zijn vanuit PHP. Er blijft nog wel een kwetsbaarheid in zitten dat PHP bestanden kan aanmaken die voor de wereld toegankelijk zijn via de web server. Dat blijft wel beperkt tot bestanden in de phpsite directory.
18-09-2021, 16:04 door Anoniem
Jaja je hebt dus zelf een implementatie van de local delivery agent geschreven.
Zeker kan dat soms een veiliger situatie opleveren omdat je dan niet opgescheept zit met allerlei geavanceerde
mogelijkheden van bestaande delivery agents (zoals die van exim4 of sendmail) opgescheept zit die je niet nodig
hebt, niet snapt, en niet onder controle kunt houden.
Maar toch denk ik niet dat dit nou een goede algemene oplossing is voor het onderhavige probleem.
Je had ook je formulier "in veilig C" kunnen schrijven ipv in PHP. Dan zouden de mensen ook hun wenkbrouwen fronsen.
18-09-2021, 19:49 door Anoniem
WordPress en PHP zijn een gegeven in dit geval.

Het wegnemen van publiek mailen (lees: netwerkrechten) in PHP zorgt voor de veiligheid. PHP draait nu zonder netwerkrechten, daarmee worden de gevolgen van een exploit in PHP beperkt. Zelfs als er "root" wordt bereikt. Dan moet er eerst uit de systemd jail en PHP changeroot worden gebroken.
Er zou een simpele open source tool moeten zijn om lokaal mail te bezorgen, maar de meeste gebruiken het netwerk.

Helaas is defacement van de site niet makkelijk te voorkomen omdat WordPress schijfrechten vereist. Zonder die rechten toont Apache HTTP error 500.

Veilig C schrijven kun je leren. Wat de tool doet kun je ook in elke willekeurige andere taal implementeren die inotify ondersteunt, inclusief bash. Dus ook een bash scripter kan dat. Het is wel makkelijker en veiliger om het in C of een andere echte taal te doen aangezien je dan geen bash omgeving (of Python, Ruby, etc.) nodig hebt en de leesbaarheid vaak beter is. De tool is niet publiek bereikbaar, dus dat zou je kunnen doen.
Reageren

Deze posting is gelocked. Reageren is niet meer mogelijk.