När internet öppnar eld

Det mesta som träffar en webbserver från internet är ganska odramatiskt. Bots letar efter WordPress-installationer, gamla administrationssidor, .env-filer och annat som kanske finns där.

Ibland händer något som sticker ut.

Den 27 september dök IP-adressen 20.214.191.94 upp i Knockwatch. Första anropet kom 12:00:37 och sökte efter:

/wp-content/plugins/hellopress/wp_filemanager.php

Två sekunder senare fortsatte det:

/this_is_a_new_hello_world.php
/3PJcpMFsD8B.php
/aa.php
/z70.php
/f35.php
/adminfuns.php
/av.php
/dex.php
/chosen.php
/1.php?p=
/radio.php
/blacks.php
/alfa.php

Och sedan fortsatte det.

På bara några tiotals sekunder provades en lång rad olika PHP-filer. Namnen varierade från sådant som ser någorlunda begripligt ut till mer märkliga namn som BDKR28WP.php, pJPoKA.php och drttewyh.php. Varje försök syns i Knockwatch-databasen tillsammans med tidpunkt, HTTP-metod och statuskod.

Tolkieninspirerad illustration (anstormninen av Helms klyfta) av en våg av automatiserade webbförfrågningar mot en server
När internet öppnar eld. En visualisering av hur en automatiserad salva kan upplevas när den följs i Knockwatch.

En salva

Jag har börjat kalla sådana här sekvenser för salvor.

Det är inte en teknisk term, men den beskriver ganska bra hur det ser ut när man följer trafiken i realtid. Förfrågningarna kommer snabbt efter varandra och riktas mot nya filer hela tiden.

Ett stycke ur salvan såg exempelvis ut så här:

12:01:05  GET  /xwpg.php
12:01:06  GET  /flamini.php
12:01:07  GET  /themes.php
12:01:08  GET  /0.php
12:01:08  GET  /opsh.php
12:01:09  GET  /media.php
12:01:10  GET  /images.php
12:01:10  GET  /ops.php
12:01:11  GET  /mac.php
12:01:12  GET  /pass4.php?p=
12:01:12  GET  /drttewyh.php
12:01:13  GET  /sh.php

Det är alltså inte någon som sitter och skriver filnamnen i en webbläsare. Mönstret är automatiserat och systematiskt.

Knockwatch visar både 301 och efterföljande 404 för många av anropen. Det beror på hur förfrågningarna hanteras och omdirigeras på webbservern. Det intressanta här är inte varje enskild rad, utan mönstret som uppstår när hundratals rader läggs bredvid varandra.

Den kom tillbaka

Det kanske mest intressanta är att samma IP-adress inte nöjde sig med ett besök.

Den 28 september kom en ny sekvens. Nu dök bland annat namn som 100.php, biufile.php, coffexium.php, coffee.php, wp-ws68.php och ws13.php upp.

Den 30 september var adressen tillbaka igen.

Då fortsatte sökandet med ytterligare PHP-filer. Senare i den sekvensen provades bland annat wordfence-waf.php, wpuse.php, Components.php, gptsh.php, asset.php och en lång rad andra namn.

Totalt finns 416 databasrader för IP-adressen i den här historiken.

Problemet med att känna igen fienden

Det här blev också ett intressant exempel när jag arbetade med Fail2ban.

Det är relativt enkelt att skriva ett filter som reagerar på en viss känd URL. Problemet är att en scanner som den här inte behöver fråga efter samma fil om och om igen. Den kan fortsätta med xwpg.php, flamini.php, opsh.php, gptsh.php och hundratals andra namn.

Försöker man skriva regler för varje tänkbart filnamn jagar man hela tiden efter scannern.

Det intressantare är därför beteendet:

Vad gör en IP-adress under en viss tidsperiod?

Många förfrågningar mot PHP-filer som inte finns, mängder av 404-svar och ständigt nya sökvägar under några tiotals sekunder är tillsammans betydligt mer information än ett enskilt anrop mot exempelvis /admin.php.

Det är också en av anledningarna till att jag byggde Knockwatch. Apache-loggen innehåller redan informationen, men några hundra loggrader är svåra att överblicka. När samma data hamnar i en databas går det att börja ställa frågor till den.

Vem kommer tillbaka?
Hur snabbt skickas förfrågningarna?
Hur många olika sökvägar provas?

Och framför allt: vilka mönster går att se som man annars hade missat?

Det är där en till synes ganska ointressant rad i en accesslogg börjar bli intressant.