Simovits

De inledande grymheterna – efterforskningar inför sårbarhetsskanning

Välkommen till dagens avsnitt av ”utlägg om sällan förekommande inslag rörande sårbarhetsskanningar”. Denna gång ska vi fundera lite på hur en sårbarhetsskanning kan te sig för en organisation med ett omfattande antal externa resurser. Poängen här är att båda bedriva en skanning som är tidseffektiv och hanterbar, men dessutom som kan upptäcka förändringar inom den externt exponerade IT-miljön.

En given förutsättning är att organisationens namn och eventuella förkortningar är kända. Därefter så kan en inledande undersökning påbörjas. Syftet är att kunna samla in information om mål och resurser som finns extern för denna, för att sedan kunna undersöka dessa närmare i form av olika informations-berikningar och därefter skanningar.

I huvudsak kan en helt generisk undersökning för en organisation utgå ifrån sådana saker som:

Bägge dessa punkter kan utföras separat (och bägge bör utföras). Emellertid är den första punkten allt mer sällan relevant, då många organisationer köper in IT-drift av olika leverantörer. I det fallet så kommer den nyttjade leverantören vara de som är ”ägare” av IP-adresserna. För stora organisationer så är det dock förfarande ofta fallet att de äger ett eget IP-block. Denna gång så betraktar vi enbart denna första punk.

Den europeiska regionala internet registratet är RIPE. Via deras sida går det att söka på namnet hos en organisation för att se vilka IP-rymder denna har registrerade på sig. Dessvärre är det utanför omfattningen av denna blogg att helt undersöka detta i detalj, nedan följer ett kod-exempel på hur en sådan förfrågan kan yttra sig i node.js (där det är underförstått att hela denna efterforskning i princip ska kunna automatiseras).

let query = `(${search}) AND (object-type:inetnum)`;

let queryEncoded = encodeURI(query);


let apiQuery = await fetch("https://apps.db.ripe.net/db-web-ui/api/rest/fulltextsearch/select?facet=true&format=xml&hl=true&q="+queryEncoded+"&start=0&wt=json", {headers: {'Content-Type': 'application/json', "Accept": "application/json"}}).then(res => res.json()).then(body => {
//console.log(JSON.stringify(body, null, 2));
return body;
});

Resultatet från ovan kan, beroende på storlek, vara omfattade. Oavsett så finns nu vetskap om vilken IP-rymd som organisationen förvaltar. Emellertid så bör dessa IP-adresser undersökas för tillhörande/relaterat fullständigt namn (FQDN). Det finns flera anledningar bakom detta, men ett framträdande exempel är att det vanliga sårbarhetsskannings verktyget Nessus och flera av dess tillägg (plugin) inte kan hantera webbapplikations-skanningar när dessa utförs med IP-adresser som mål.

Ett antal olika sätt kan tänkas för att uppdaga relaterade namn till de insamlade IP-adresserna. Dessa inkluderar bland annat:

Observera att ingen av dessa ovan är garanterad att upptäcka om det finns något tillhörande namn till IP-adressen (inget garanterat sätt finns såvitt författaren erfarit).

Att redogöra i detalj för hur olika DNS-förfrågningar fungerar är bortom omfattningen av denna blogg. Förenklat så kan en omvänd DNS-förfrågan kallas den operation som från en IP-adress ger information om de namn(en) som ska peka på denna adress. Inget av detta är dock något som måste förhålla sig till varandra på ett korrekt sätt (dvs är det möjligt att ha ett omvänt DNS-uppslag som inte är inversen av det vanliga ty något av de förekommande uppslagen är inkorrekta). Den intresserade läsaren kan nedan finna ett kod-exempel på hur ett flertal omvända DNS-uppslag kan utföras i node.js.

async function reverseDNSrange (cidrRange) {
  let range = new IPCIDR(cidrRange);
  range = range.toArray();
  let results = range.map(function(ip){
    return dnsPromises.reverse(ip).then(
      result => {
        let obj = {};
        obj[ip] = result;
        return obj;
      },
      error => {
        let obj = {};
        obj[ip] = false;
        return obj;
      }
    );
  });
  return Promise.all(results);
};


async function reverseDNSall (ipRanges) {
  let results = [];
  for (const list of ipRanges) {
    console.log("Running reverse DNS for IP range: " + list)
    await reverseDNSrange(list).then(
      result => {
        results = results.concat(result);
      }
    );
  }
  results = await validateReverseDNSall(results);
  return results;
};



async function validateReverseDNSall (reverseDNSres) {
  // Tanken är att jag går igenom alla nuvarande resutlat, gör DNS-förfrågan på  dem och sedan enbart behåller dem som matchar IP:n. Sedan noterar jag alla fall där detta inte stämmer!!
  let validatedDNSresults = [];
  let deviationFilePath = "report_squaters/report_squaters.txt";
  await mkdir(deviationFilePath.split("/")[0]).catch((reason) => console.log(reason));
  let filterFunction = (entryRes) => {
    if (Object.values(entryRes)[0]) {
      return entryRes;
    }
  };
  let namesToCheck = reverseDNSres.filter(entry => filterFunction(entry));
  // Vi måste kolla alla Ip:adresser och alla dess namn så att DNS-> IP stämmer och det inte var fel med IP->DNS
  let oldNames;
  let newNames;
  let deviationReport = "";
  for (const entry of namesToCheck){
    // Kan finnas flera namn för varje IP!
    oldNames = entry[Object.keys(entry)[0]];
    newNames = [];
    for (const name of oldNames){
      let dnsR = await makeDNSquery(name);
      try {
        dnsR = dnsR[0]
      } catch (e) {
        dnsR = "xxxx";
        console.log("The DNS resolver failed (see makeDNSquery:s error message above) " + e);
      }
      if (Object.keys(entry)[0] == dnsR){
        newNames.push(name);
      } else {
        deviationReport = deviationReport + "name: " + name + " real_IP: " + dnsR[0] + " reverse_DNS_IP: " +  Object.keys(entry)[0] + "\n"
      }
    }
    entry[Object.keys(entry)[0]] = newNames;
    validatedDNSresults.push(entry);
  }
  writeFile(deviationFilePath, deviationReport);
  return validatedDNSresults;
};

Resultatet från denna är en lista av namn associerade med förmedlad lista av IP-adresser.

Om tjänsten använder sig av TLS och/eller asymmetrisk kryptografi så finns det för varje tjänst ett relaterat digitalt certifikat. Detta ska bland annat innehålla namnet på tjänsten (igen finns ingen garanti för att detta är på en korrekt eller vedertagen form, dessutom kan så kallade ”wildecard” namn göra det mer komplicerat). En anslutning för att erhålla certifikatet kan initierats trots att namnet saknas. Det vanligt förekommande verktyget nmap har ett specifikt skript som kan nyttjas för att just erhålla certifikatet. Nedan återfinns ett sådant exempel (notera att det är mycket möjligt att bygga vidare på detta i sitt eget automatiserings-projekt, något som författaren har gjort, men den resulterande koden är alltför omständlig för att presentera här).

nmap -sS -p 443 --script ssl-cert  [targets]

Beroende på storleken hos organisationen så kan ett omfattande antal IP-adresser och namn nu vara insamlade. Att direkt förmedla dessa till ett sårbarhetsskanningsverktyg (såsom Nessus) är i regel ingen bra idé då denna är väldigt långsam att bedöma vilka mål som ”lever”/är aktiva. Ett bättre sätt är att först bedöma om dessa är nåbara för att sedan enbart utföra en sårbarhetsskanning av dessa. På det sättet så kan tidsåtgången för själva sårbarhetsskanningen ofta drastiskt reduceras. Ett verktyg som är väl lämpat för detta är masscan, vilket har avhandlats i tidigare blogg (https://simovits.com/att-valja-ratt-verktyg-for-jobbet-ett-kort-utlagg-om-masscan/) och därför inte kommer att beskrivas närmare här. Tanken är att resultatet från denna kan bearbetas för att sedan förmedlas vidare till exempelvis Nessus.

Avslutande ord

Denna gång har vi betraktat olika förarbetes-aspekter kopplade till sårbarhetsskanningar av omfattande externa IT-miljöer. Att enbart använda exempelvis Nessus innebär både en sämre och långsammare skanning; det finns mycket att vinna på att utföra en del för-behandling. Vid framtida tillfällen kan det eventuellt bli aktuellt med en djupdykning i någon av delarna ovan, eller en redogörelse för hur dessa kan kopplas ihop för att automatisera undersökningen och på det sättet göra de återkommande inför varje periodisk sårbarhetsskanning.