- 34,644
- 0
- 18 Дек 2022
- EDB-ID
- 13024
- Проверка EDB
-
- Пройдено
- Автор
- TH1NK3R
- Тип уязвимости
- PAPERS
- Платформа
- MULTIPLE
- CVE
- N/A
- Дата публикации
- 2008-09-28
Код:
=-|================================================-{ www.enye-sec.org }-====|
=-[ Bricando com sockets (port scanning) ]-==================================|
=-|==========================================================================|
=-[ por Pepelux <[email protected]> ]-=====================-[13/11/2007]-=|
=-|==========================================================================|
=-[ Traduzido por: Th1nk3r <[email protected]> ]=======-[19/09/2008]-=|
=-|==========================================================================|
O Texto na sua versão original pode ser encontrado em:
http://www.milw0rm.com/papers/224
NOTA DO TRADUTOR (Note of Translator):
==============================================================================
Todo o conteúdo apresentado neste documento é de responsabilidade do
escritor, sendo que eu apenas me dei o trabalho de traduzi-lo.
Perdoem-me pelos poucos erros ortográficos e gramaticais, pois não
tive tempo de fazer uma revisão completa. [:p]
Dedico a tradução à todos meus amigos.
Th1nk3r
==============================================================================
------[ 0.- Ãndice ]
0.- Ãndice
1.- Breve introdução
1.1.- Scan aberto (Open Scan)
1.2.- Scan semi-aberto (Half Open Scan)
1.3.- Stealth Scan
2.- Brincando com sockets
2.1.- TCP Sockets
2.2.- UDP / ICMP Sockets
3.- Detecção de sistemas operacionais
3.1.- Alguns testes
4.- Arquivos
5.- Referências
6.- Finalizando
------[ 1.- Breve Introdução ]
Por muitos tempo nossos métodos de escanear portas foi usando o telnet, fazendo manualmente.
Hoje as pessoas usam os mais sofisticados programas que possuem varios métodos para escanear
um faixa de IP procurando por uma grande quantidade de portas.
Eu estarei escrevendo de forma rapida os diferentes métodos de scanning, pois um conteúdo
que vá mais fundo pode ser encontrado na Internet. Além disso, ao fim desse arquivo você pode
encontrar dicas de como aprender sockets de maneira divertida.
------[ 1.1.- Scan aberto (Open Scan) ]
Conhecida como TCP Scan e normalmente usada para programar sockets, essa técnica é
antiga e trabalha fazendo uma conexão completa com o servidor. É como se conectar
a cada porta de um servidor através do telnet, mas automaticamente.
Com isso se faz uma conexão com 3 pacotes (conhecida como three-way-handshake [aperto-de-mao em tres passos]):
Para portas abertas temos:
Cliente ----> SYN ---->
<---- SYN/ACK <---- Servidor
Cliente ----> ACK ---->
Para portas fechadas temos:
Cliente ----> SYN ---->
<---- RST <---- Servidor
Vantagens : Muito fácil de programar.
Desvantagens : Muito fácil de detectar e gera logs a cada conexão.
------[ 1.2.- Scan semi-aberto (Half Open Scan)]
Ésta tecnica trabalha fazendo com que a conexão seja iniciada, mas não completada.
Envia-se um SYN, mas não envia-se um ACK se a porta estiver aberta.
Usando RAW sockets nós podemos programar manualmente os cabeçalhos do socket e enviar
somente o inicio da conexão. Logo veremos isso melhor com alguns exemplos.
------[ 1.3.- Stealth Scan ]
É similar aos métodos anteriores, mas envia-se outra flag, ou uma combinação de flags.
O mais conhecido e usado pelo nmap é:
SYN
SYN+ACK
FIN
ACK
NULL (all flags with 0)
XMAS (FIN=URG=PSH=1)
Nos exemplos que virão nós veremos isso claramente.
------[ 2.- Brincando com sockets ]
É a hora de se divertir. Nós enviaremos diferentes pacotes alterando as flags e estudando
os resultados.
Nos testes eu usei dois computadores:
Cliente : 192.168.2.5 (Linux Debian - kernel 2.6.18.1)
Servidor : 192.168.2.7 (Linux Debian - kernel 2.6.21.2)
Portas abertas no servidor: 22(TCP), 80(TCP), 111(UDP)
------[ 2.1.- TCP Sockets ]
Para examinar as portas TCP, nós usaremos um programa para enviar e receber RAW Sockets,
o que nos permitirá escolher os valores dos flags.
- sendsock.c ->
Usage: ./sendsocket [s|a|r|p|u|f] [-x host_source] -d host_destination -c port
-s SYN flag enabled
-a ACK flag enabled
-r RST flag enabled
-p PSH flag enabled
-u URG flag enabled
-f FIN flag enabled
Enviar SYN (half open connection)
---------------------------------
Consiste em fazer uma semi conexão, enviando um SYN, e quando obtermos qualquer
resposta (ACK+SYN ou RST) enviaramos um RST para finalizar a conexão (usando RAW
Sockets, o pacote RST é enviado automaticamente pelo kernel).
A idéia original consiste em enviar um SYN e se o servidor responder com um ACK+SYN,
nós enviamos um pacote RST dizendo que nós não queremos fazer uma conexão. Como
a conexão não foi completada o servidor nao salva nenhum log. :-)
Atualmente muitos computadores podem detectar essa tecnica e salvar um log ou bloquear
esse tipo de ataque com um firewall.
Vantangens : Funciona em todos os sistemas operacionais e portas, se não existir um firewall.
Desvantagens : É muito fácil de detectar e gerar logs.
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 80 -s
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 1 | 0 | 0 | 0 | 0 | 0 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=39553 - ID=27032
DADOS RECEBIDOS
-------------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 1 | 1 | 0 | 0 | 0 | 0 | 64 | 53270
seq=-1378930670 - ack_seq=863708102 - doff=6 - check=8049 - ID=0
Porta aberta. Nós obtemos um SYN+ACK e Window<>0
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 23 -s
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 1 | 0 | 0 | 0 | 0 | 0 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=54145 - ID=27032
DADOS RECEBIDOS
-------------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 1 | 1 | 0 | 0 | 0 | 64 | 0
seq=0 - ack_seq=863708102 - doff=5 - check=49281 - ID=0
Porta fechada. Nós obtemos um ACK+RST e Window=0.
Enviar ACK
----------
Este método apenas tem efeito em alguns DBS antigos e Sistemas Operacionais Unix. Consiste
em checar o campo Window. Se obter um Window=0 a porta está aberta e se obter um Window<>0 a
porta está fechada.
Vantangens : É dificil de ser detectado.
Desvantangens : Não funciona em todos os SOs.
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 80 -a
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 1 | 0 | 0 | 0 | 0 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=35969 - ID=27032
DADOS RECEBIDOS
-------------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 0 | 1 | 0 | 0 | 0 | 64 | 0
seq=0 - ack_seq=0 - doff=5 - check=61122 - ID=0
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 23 -a
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 1 | 0 | 0 | 0 | 0 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=50561 - ID=27032
DADOS RECEBIDOS
-------------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 0 | 1 | 0 | 0 | 0 | 64 | 0
seq=0 - ack_seq=0 - doff=5 - check=10179 - ID=0
Nesse caso meu linux não é vulnerável e nós obtemos o mesmo resultado resultados
com a porta aberta ou fechada.
Enviar RST
----------
Este ataque apenas tem efeito em alguns sistemas e nem sempre é eficaz. Nesse caso
nós obtemos apenas um ACK ou se nós nao obtemos resposta, a porta está aberta e se nós
obtermos um RST, a porta está fechada.
Vantangens : É dificil de ser detectado.
Desvantangens : Não funciona em todos os SOs e nem em todas as portas.
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 80 -r
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 0 | 1 | 0 | 0 | 0 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=39041 - ID=27032
DADOS RECEBIDOS
-------------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 1 | 0 | 1 | 0 | 0 | 53 | 37920
seq=1193401395 - ack_seq=908914171 - doff=5 - check=43532 - ID=4979
Porta aberta. Nós obtemos ACK+PSH, TTL<64 e Window<>0.
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 23 -r
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 0 | 1 | 0 | 0 | 0 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=53633 - ID=27032
Sem resposta ... Porta fechada.
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 22 -r
DADOS ENVIADOS
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 0 | 1 | 0 | 0 | 0 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=53889 - ID=27032
Sem resposta ... A resposta não é confiável pois a porta está aberta.
Como nós podemos ver, se obtermos qualquer resposta a porta está aberta e se
nós nao obtermos resposta, nós nao podemos saber se a porta está aberta ou fechada.
Enviar PSH
----------
Este ataque apenas tem efeito em alguns sistemas e nem sempre é eficaz. Nesse caso se nós
obtemos um ACK+PSH e um Windows<>0 ou não obtermos resposta, a porta está aberta e se obtermos
um RST, a porta está fechada.
Vantagens : É dificil de ser detectado.
Desvantagens : Não funciona em todos os SOs.
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 80 -p
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 0 | 0 | 1 | 0 | 0 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=38017 - ID=27032
DADOS RECEBIDOS
-------------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 1 | 0 | 1 | 0 | 0 | 53 | 17447
seq=1710733151 - ack_seq=1317887646 - doff=5 - check=32634 - ID=4439
Porta aberta. Nós obtemos um ACK+PSH, TTL<64 e Window<>0.
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 23 -p
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 0 | 0 | 1 | 0 | 0 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=52609 - ID=27032
DADOS RECEBIDOS
-------------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 1 | 1 | 0 | 0 | 0 | 64 | 0
seq=0 - ack_seq=846930886 - doff=5 - check=49537 - ID=0
Porta fechada. Nós obtemos RST, TTL=64 e Window=0.
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 22 -p
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 0 | 0 | 1 | 0 | 0 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=52865 - ID=27032
Sem resposta ... porta fechada.
Enviar URG
----------
Este ataque apenas tem efeito em alguns sistemas e nem sempre é eficaz. Nesse caso se
obtermos um ACK sem um RST ou se nao obtermos resposta, a porta está aberta. Se obtermos
um RST, a porta está fechada.
Vantagens : É dificil de ser detectado.
Desvantagens: Funciona no meu Linux mas pode nao funcionar em alguns sistemas.
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 80 -u
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 0 | 0 | 0 | 1 | 0 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=31873 - ID=27032
DADOS RECEBIDOS
-------------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 1 | 0 | 1 | 0 | 0 | 53 | 37920
seq=-716127216 - ack_seq=1741636632 - doff=5 - check=41524 - ID=59663
Porta aberta. Obtemos ACK+PSH, TTL<64 e Window<>0.
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 23 -u
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 0 | 0 | 0 | 1 | 0 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=46465 - ID=27032
DADOS RECEBIDOS
-------------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 1 | 1 | 0 | 0 | 0 | 64 | 0
seq=0 - ack_seq=846930886 - doff=5 - check=49537 - ID=0
Porta fechada. Obtemos ACK+RST, TTL=64 e Window=0.
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 22 -u
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 0 | 0 | 0 | 1 | 0 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=3968 - ID=27032
Sem resposta: Porta aberta.
Enviar FIN
----------
Este ataque apenas tem efeito em alguns sistemas e nem sempre é eficaz. No caso se
obtermos um ACK ou se nao obtermos resposta, a porta está aberta. Se obtermos um RST
a porta está fechada.
Em outros sistemas voce poderá notar a diferença na flag RST. Se está ativada a porta
está fechada e se o valor de RST é zero a porta está aberta.
Vantagens : É dificil de detectar.
Desvantagens: Nao funciona em todos os sistemas operacionais porque é baseada em um bug.
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 80 -f
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 0 | 0 | 0 | 0 | 1 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=39809 - ID=27032
DADOS RECEBIDOS
-------------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 1 | 0 | 1 | 0 | 1 | 53 | 37920
seq=-1722694640 - ack_seq=1741636632 - doff=5 - check=39751 - ID=56001
Porta aberta. Nós obtemos ACK+PSH+FIN,TTL<64 e Window<>0.
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 23 -f
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 0 | 0 | 0 | 0 | 1 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=54401 - ID=27032
DADOS RECEBIDOS
-------------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 1 | 1 | 0 | 0 | 0 | 64 | 0
seq=0 - ack_seq=863708102 - doff=5 - check=49281 - ID=0
Porta fechada. Obtemos ACK+RST, TTL=64 e Window=0.
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 22 -f
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 0 | 0 | 0 | 0 | 1 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=54657 - ID=27032
Sem resposta... Porta aberta.
Enviar SYN+ACK
--------------
Nós usaremos algumas combinações de flags. Este ataque só funciona em alguns
sistemas. Quando funciona, se voce obter qualquer resposta, a porta está aberta
e se receber um RST, a porta está fechada.
Vantagens : É dificil de detectar.
Desvantagens: Não funciona em todos os sistemas.
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 80 -s -a
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 1 | 1 | 0 | 0 | 0 | 0 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=35457 - ID=27032
DADOS RECEBIDOS
-------------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 0 | 1 | 0 | 0 | 0 | 64 | 0
seq=0 - ack_seq=0 - doff=5 - check=61122 - ID=0
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 23 -s -a
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 1 | 1 | 0 | 0 | 0 | 0 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=50049 - ID=27032
DADOS RECEBIDOS
-------------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 0 | 1 | 0 | 0 | 0 | 64 | 0
seq=0 - ack_seq=0 - doff=5 - check=10179 - ID=0
No caso nós obtemos o mesmo resultado e nós nao sabemos se porta está
aberta ou fechada. Como eu disse, isso tem efeito em apenas alguns sistemas. :)
Enviar SYN+PSH
--------------
Quando nós nao obtemos um RST e Windows<>0, a porta está aberta e com um RST
e Window=0, a porta está fechada.
Vantagens : É dificil detectar.
Desvantagens: Funciona no meu Linux mas nao sei se funciona em outros sistemas.
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 80 -s -p
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 1 | 0 | 0 | 1 | 0 | 0 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=37505 - ID=27032
DADOS RECEBIDOS
-------------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 1 | 1 | 0 | 0 | 0 | 0 | 64 | 53270
seq=1874969709 - ack_seq=863708102 - doff=6 - check=51491 - ID=0
Porta aberta. Nós obtemos um SYN+ACK e Window<>0.
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 22 -s -p
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 1 | 0 | 0 | 1 | 0 | 0 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=52353 - ID=27032
DADOS RECEBIDOS
-------------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 1 | 1 | 0 | 0 | 0 | 0 | 64 | 53270
seq=1445991790 - ack_seq=863708102 - doff=6 - check=52148 - ID=0
Porta aberta. Obtemos SYN+ACK e Window<>0.
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 23 -s -p
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 1 | 0 | 0 | 1 | 0 | 0 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=52097 - ID=27032
DADOS RECEBIDOS
-------------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 1 | 1 | 0 | 0 | 0 | 64 | 0
seq=0 - ack_seq=863708102 - doff=5 - check=49281 - ID=0
Porta fechada. Obtemos ACK+RST e Window=0.
Enviar URG+FIN
--------------
Nesse método, se nós nao obtermos reposta, a porta está aberta e com RST,
a porta está fechada.
Vantagens : É dificil detectar.
Desvantagens: Funciona no meu Linux mas nao sei se funciona em outros sistemas.
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 80 -u -f
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 0 | 0 | 0 | 1 | 1 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=31617 - ID=27032
Sem resposta... porta aberta.
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 23 -u -f
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 0 | 0 | 0 | 1 | 1 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=46209 - ID=27032
DADOS RECEBIDOS
-------------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 1 | 1 | 0 | 0 | 0 | 64 | 0
seq=0 - ack_seq=863708102 - doff=5 - check=49281 - ID=0
Porta fechada. Obtemos um ACK+RST.
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 22 -u -f
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 0 | 0 | 0 | 1 | 1 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=46465 - ID=27032
Sem resposta... porta aberta.
Enviar URG+FIN+PSH
------------------
Mais conhecida como XMAS scan, quando nós nao obtemos resposta ou nao obtemos um RST,
a porta está aberta. Está fechada quando obtemos um RST.
Vantagens : É dificil de detectar.
Desvantagens: Funciona somente em alguns sistemas.
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 80 -p -u -f
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 0 | 0 | 1 | 1 | 1 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=23938 - ID=27032
DADOS RECEBIDOS
-------------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 1 | 1 | 0 | 0 | 0 | 0 | 47 | 10262
seq=128745367 - ack_seq=338264191 - doff=10 - check=49414 - ID=0
Porta aberta. Nós obtemos um SYN+ACK.
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 22 -p -u -f
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 0 | 0 | 1 | 1 | 1 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=38786 - ID=27032
Sem resposta ... porta fechada.
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 22 -u -f
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 0 | 0 | 1 | 1 | 1 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=38530 - ID=27032
DADOS RECEBIDOS
-------------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 1 | 1 | 0 | 0 | 0 | 56 | 0
seq=0 - ack_seq=863708102 - doff=5 - check=43650 - ID=56815
Porta fechada. Nós obtemos um ACK+RST.
Enviar nulo
-----------
Conhecido como "null scan", ésta técnica consiste em enviar flags com zero. Nesse caso,
quando a resposta é um ACK ou se nao obtemos resposta, a porta está aberta e com um RST,
a porta está fechada.
Vantagens : É dificil de detectar.
Desvantagens: Funciona somente em alguns sistemas.
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 80
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 0 | 0 | 0 | 0 | 0 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=40065 - ID=27032
DADOS RECEBIDOS
-------------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 1 | 0 | 0 | 0 | 0 | 53 | 22560
seq=-515721121 - ack_seq=1706581918 - doff=5 - check=55050 - ID=61453
Porta aberta. Nós obtemos ACK.
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 23
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 0 | 0 | 0 | 0 | 0 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=54657 - ID=27032
DADOS RECEBIDOS
-------------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 1 | 1 | 0 | 0 | 0 | 64 | 0
seq=0 - ack_seq=846930886 - doff=5 - check=49537 - ID=0
Porta fechada. Obtemos ACK+RST.
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 22
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 0 | 0 | 0 | 0 | 0 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=54913 - ID=27032
Sem resposta... porta aberta.
Enviar SYN+ACK+RST+PSH+URG+FIN
------------------------------
Consiste em enviar todas as flags ativadas (com valores 1). Nesse caso, quando
a resposta é um ACK ou se nao obtemos resposta, a porta está aberta.
Com um RST a porta está fechada.
Vantagens : É dificil de detectar.
Desvantagens: Funciona somente em UNIX.
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 80 -s -a -r
-p -u -f
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 1 | 1 | 1 | 1 | 1 | 1 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=23937 - ID=27032
DADOS RECEBIDOS
-------------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 1 | 0 | 1 | 0 | 1 | 53 | 37920
seq=2033962504 - ack_seq=-1093275500 - doff=5 - check=8061 - ID=35468
Porta aberta. Obtemos um ACK+PSH.
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 23 -s -a -r
-p -u -f
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 1 | 1 | 1 | 1 | 1 | 1 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=38529 - ID=27032
Sem resposta... resultado nao valido porque a porta está realmente fechada.
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 22 -s -a -r
-p -u -f
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 1 | 1 | 1 | 1 | 1 | 1 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=38785 - ID=27032
Sem resposta... resultado nao valido porque a porta está aberta.
Nesse caso a tecnica nao é valida para nos porque as resposta nao batem. Como eu
disse, somente funciona em UNIXs.
------[ 2.2.- UDP / ICMP Sockets ]
Para verificar se portas UDP estão aberta nós iremos brincar um pouco mais enviando
pacotes. O protocolo UDP nao é orientado em uma conexão como o protocolo TCP, e nós nao
podemos esperar por uma resposta depois de enviar um pacote. Por isso, usando somente
UDP nós nao podemos saber se uma porta está ou não aberta.
Para escanear nós teremos o auxilio de pacotes ICMP. Por que? porque quando voce tenta
fazer uma conexão com uma porta UDP o servidor irá responder com um pacote ICMP em caso
de erro; justamente um pacote tipo 3 / codigo 3 , que se você ver nos documentos RFC
você entenderá: tipo 3 = destino da mensagem inacessÃvel /
codigo 3 = porta inacessÃvel.
Como nós amamos fazer estas coisas manualmente, nós usaremos 2 programas:
- checkicmp.c -> Escuta por conexões ICMP no nosso computador.
- sendudp.c -> Envia um pacote UDP em um host/porta.
flashgordon# ./checkicmp
Waiting data ...
Enquanto o programa aguarda, nós abriremos outro terminal e enviaremos em uma porta fechada:
flashgordon# ./sendudp 192.168.2.7 100
Sending UDP packet to 192.168.2.7:100
No primeiro terminal nós podemos ver:
flashgordon# ./checkicmp
Waiting data ...
Received: type 3 code 3
Isto nos diz que a porta está fechada... verifique em uma porta aberta para
ver o que acontece:
flashgordon# ./sendudp 192.168.2.7 111
Sending UDP packet to 192.168.2.7:111
E no outro terminal:
flashgordon# ./checkicmp
Waiting data ...
Received: type 3 code 3
Nada muda (a mensagem) ... como nós nao recebemos qualquer pacote nós podemos dizer
que a porta está aberta.
Teste outra vez com uma porta fechada:
flashgordon# ./sendudp 192.168.2.7 101
Sending UDP packet to 192.168.2.7:101
E no outro terminal:
flashgordon# ./checkicmp
Waiting data ...
Received: type 3 code 3
Received: type 3 code 3
Nós obtemos outro pacote ICMP nos dizendo que a porta 101 está fechada também.
------[ 3.- Detecção de sistemas operacionais ]
Nós podemos saber o sistema operacional rodando em um servidor sem fazer
uma conexão TCP. Como ocorre com os metodos de scan mostrados anteriormente,
servidores diferentes podem responder pacotes diferentes (nós vimos que
conexões TCP envia um SYN e espera por um SYN+ACK ou um RST) porque cada sistema
pode responder de forma diferente. O mesmo acontece enviando pacotes UDP ou
ICMP que nao são tÃpicos para fazer fazer uma conexão padrão.
Eu nao mostrarei todas as diferenças entre sistemas operacionais pois isso requer
uma grande quantidade de testes, de sistemas operacionais e de tempo. :) ....
Além do mais, o scanner nmap tem um ótimo banco de dados de sistemas operacionais
detectáveis, baseado no famoso QueSO de Savage.
Mas nós iremos brincar um pouco mais com os sockets para ver e entender tudo isso.
Nos testes eu usei 4 computadores:
Cliente : 192.168.2.5 (Linux Debian - kernel 2.6.18.1)
Servidor1: 192.168.2.7 (Linux Debian)
Servidor2: 192.168.2.6 (Windows 2000 Server)
Servidor3: 192.168.2.8 (Solaris)
Porta aberta nos 3 servidores: 80(TCP)
Antes de fazer qualquer coisa para entender a detecção de sistemas operacionais
você pode brincar com mais headers de cada pacote, mas para nao alterar os programas
e como isso é somente um teste, eu usarei a mesma flag como antes.
------[ 3.1.- Alguns testes ]
Para fazer os testes eu enviarei um pacote TCP Ã porta 80 (aberta) com flags
SYN+URG+FIN ativadas.
Primeiro servidor, sob Linux:
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.7 -c 80 -s -u -f
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 1 | 0 | 0 | 0 | 1 | 1 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=31617 - ID=27032
DADOS RECEBIDOS
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 1 | 1 | 0 | 0 | 0 | 0 | 64 | 6272
seq=24764339 - ack_seq=863708102 - doff=6 - check=32130 - ID=0
Segundo servidor, sob Windows:
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.6 -c 80 -s -u -f
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 1 | 0 | 0 | 0 | 1 | 1 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=17292 - ID=27032
DADOS RECEBIDOS
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 0 | 1 | 0 | 1 | 0 | 0 | 48 | 33820
seq=2043592525 - ack_seq=772288166 - doff=5 - check=30285 - ID=15717
Terceiro servidor, sob Solaris:
flashgordon# ./sendsocket -x 192.168.2.5 -d 192.168.2.8 -c 80 -s -u -f
DADOS ENVIADOS
---------
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 1 | 0 | 0 | 0 | 1 | 1 | 64 | 65535
seq=846930886 - ack_seq=0 - doff=5 - check=50815 - ID=27032
DADOS RECEBIDOS
| SYN | ACK | RST | PSH | URG | FIN | TTL | Window
| 1 | 1 | 0 | 0 | 0 | 0 | 41 | 65535
seq=1684159920 - ack_seq=1278904408 - doff=6 - check=34271 - ID=62243
Se nós analisarmos as diferenças:
- Linux : SYN+ACK - TTL=64 - Window= 6272
- Windows: ACK+PSH - TTL=48 - Window=33820
- Solaris: SYN+ACK - TTL=41 - Window=65535
Como eu disse anteriormente, isto é somente um teste para entender como a detecção de sistemas
operacionais funciona. Realmente nós temos que alterar mais campos e combinar com os pacotes UDP
e ICMP. As diferenças entre Linux, Windows e Solaris é evidente, mas usando mais testes nós
podemos ver as diferenças entre diferentes versões de sistemas operacionais, por exemplo
entre um Windows 98 e Windows 2000, ou ver diferenças entre cada Distribuição Linux ou
Kernels.
------[ 4.- Arquivos ]
Programas usados para fazer os testes:
--- sendsocket.c --------------------------8<---------------------------------
// sendsocket.c
// By Pepelux
// Change DEFAULT_HOST writing your private IP if you want to use always the
// same IP address
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netdb.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/wait.h>
#include<sys/select.h>
#include<sys/time.h>
#include<netinet/in.h>
#include<netinet/ip.h>
#include<linux/if_ether.h>
#include<linux/if_packet.h>
#include<netinet/tcp.h>
#define Error(msg) { perror(msg); exit -1; }
#define DEFAULT_HOST "PUT HERE YOUR PRIVATE IP"
#define PBUFFER 10000
#define BUFFER_LONG 65536
#define DEFAULT_LEN (sizeof(struct tcphdr)+sizeof(struct iphdr))
void usage(char *nom);
unsigned short cksum(unsigned short *, int);
void SendPacket(struct sockaddr_in saddr, struct sockaddr_in daddr, int dport,
int syn, int ack, int psh, int rst, int urg, int fin);
int main(int argc, char *argv[]) {
int dport;
char *host_dest, *host_source;
struct sockaddr_in saddr, daddr;
struct hostent *hostentry;
int i, c;
int h = 0; // destination flag
int x = 0; // Source flag
int syn = 0; // SYN flag
int ack = 0; // ACK flag
int rst = 0; // RST flag
int urg = 0; // URG flag
int fin = 0; // FIN flag
int psh = 0; // PSH flag
if (geteuid() != 0) {
printf("You must be root to use RAW Sockets\n");
exit(0);
}
// Check params
while((c = getopt(argc, argv, "saprufd:x:c:")) != -1) {
switch(c) {
case 'd': // destination host
if(strlen(optarg) == 0) usage(argv[0]);
host_dest = optarg;
h++;
break;
case 's': // SYN
syn = 1;
break;
case 'a': // ACK
ack = 1;
break;
case 'r': // RST
rst = 1;
break;
case 'p': // PUSH
psh = 1;
break;
case 'u': // URG
urg = 1;
break;
case 'f': // FIN
fin = 1;
break;
case 'x': // source host
if(strlen(optarg) == 0) usage(argv[0]);
host_source = optarg;
x++;
break;
case 'c': // destination port
if(strlen(optarg) == 0) usage(argv[0]);
dport = atoi(optarg);
break;
default:
usage(argv[0]);
break;
}
}
if (x == 0) host_source = DEFAULT_HOST;
if (h == 0) usage(argv[0]); // you must write destination host. Error
// IP source
if((hostentry = gethostbyname(host_source)) == NULL)
Error("Error solving source address");
bzero(&saddr, sizeof(struct sockaddr));
saddr.sin_family = AF_INET;
saddr.sin_addr = *((struct in_addr *)hostentry->h_addr);
// IP destination
if((hostentry = gethostbyname(host_dest)) == NULL)
Error("Error solving destination address");
bzero(&daddr, sizeof(struct sockaddr));
daddr.sin_family = AF_INET;
daddr.sin_addr = *((struct in_addr *)hostentry->h_addr);
// Send data
SendPacket(saddr, daddr, dport, syn, ack, psh, rst, urg, fin);
}
void SendPacket(struct sockaddr_in saddr, struct sockaddr_in daddr, int dport,
int syn, int ack, int psh, int rst, int urg, int fin) {
int destination_port, source_port, on, s, rs, pid;
int status, i;
char buffer[BUFFER_LONG], rbuffer[BUFFER_LONG];
char string[BUFFER_LONG];
struct iphdr *iphdr, *riphdr;
struct tcphdr *tcphdr, *rtcphdr;
struct sockaddr from;
int fromlen, ethlen;
struct pseudohdr {
struct in_addr saddr;
struct in_addr daddr;
unsigned char zero;
unsigned char protocol;
unsigned short length;
} *pseudoheader;
ethlen = sizeof(struct ethhdr);
on = 1;
source_port = htons(random());
destination_port = htons(dport);
setvbuf(stdout, NULL, _IONBF, 0);
fflush(stdout);
if((pid=fork()) == -1)
Error("fork");
if(pid) {
if((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
Error("socket");
if(setsockopt(s, IPPROTO_IP, IP_HDRINCL,(char *)&on,
sizeof(on)) < 0)
Error("setsockopt");
bzero(buffer, BUFFER_LONG);
// TCP header
tcphdr = (struct tcphdr *)(buffer+
sizeof(struct iphdr));
tcphdr->source = htons(source_port); // puerto origen
tcphdr->dest = destination_port; // puerto destino
tcphdr->window = htons(65535); // ventana
tcphdr->seq = random(); // numero de secuencia aleatorio
tcphdr->syn = syn; // flag SYN
tcphdr->ack = ack; // flag ACK
tcphdr->rst = rst; // flag RST
tcphdr->psh = psh; // flag PSH
tcphdr->urg = urg; // flag URG
tcphdr->fin = fin; // flag FIN
tcphdr->doff = sizeof(struct tcphdr) / 4;
// TCP pseudoheader
pseudoheader = (struct pseudohdr *)
((unsigned char *)tcphdr-sizeof(struct pseudohdr));
pseudoheader->saddr = saddr.sin_addr; // direccion origen
pseudoheader->daddr = daddr.sin_addr; // direccion destino
pseudoheader->protocol = IPPROTO_TCP; // protocolo
pseudoheader->length = htons(sizeof(struct tcphdr));
tcphdr->check = cksum((unsigned short *)
pseudoheader, sizeof(struct pseudohdr)+sizeof(struct tcphdr));
// IP header
bzero(buffer, sizeof(struct iphdr));
iphdr = (struct iphdr *)buffer;
iphdr->ihl = 5; // IHL (longitud de cabecera)
iphdr->version = 4; // version
iphdr->tot_len = htons(DEFAULT_LEN); // longitud del datagrama
iphdr->id = htons(random()); // numero de identifiacion (aleatorio)
iphdr->ttl = IPDEFTTL; // tiempo de vida
iphdr->protocol = IPPROTO_TCP; // protocolo
iphdr->daddr = daddr.sin_addr.s_addr; // direccion origen
iphdr->saddr = saddr.sin_addr.s_addr; // direccion destino
printf(" SENT DATA\n");
printf(" ---------\n");
printf("| SYN | ACK | RST | PSH | URG | FIN | TTL |
Window\n");
printf("| %d | %d | %d | %d | %d | %d | %d
| %d\n", syn, ack, rst, psh, urg, fin, iphdr->ttl,
tcphdr->window);
printf("seq=%d - ack_seq=%d - doff=%d - check=%d - ID=%d\n\n",
tcphdr->seq, tcphdr->ack_seq, tcphdr->doff,
tcphdr->check, iphdr->id);
if(sendto(s, buffer, DEFAULT_LEN, 0x0, (struct sockaddr *)
&daddr, sizeof(struct sockaddr) ) != DEFAULT_LEN)
Error("sendto");
wait(&status);
close(s);
exit(0);
} else {
if((rs = socket(AF_INET, SOCK_PACKET, htons(ETH_P_IP))) < 0)
Error("socket input");
if((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
Error("socket");
if(setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char *)&on,
sizeof(on)) < 0)
Error("setsockopt");
while(1) {
if(recvfrom(rs, rbuffer, BUFFER_LONG, 0x0,
(struct sockaddr *)&from, &fromlen) <= 0)
Error("recvfrom");
riphdr = (struct iphdr *)(rbuffer+ethlen);
if(riphdr->protocol == IPPROTO_TCP) {
rtcphdr = (struct tcphdr *)(rbuffer+ethlen+
sizeof(struct iphdr));
if(rtcphdr->source == destination_port) {
bzero(buffer, BUFFER_LONG);
printf(" RECEIVED DATA\n");
printf(" -------------\n");
printf("| SYN | ACK | RST | PSH | URG
| FIN | TTL | Window\n");
printf("| %d | %d | %d | %d
| %d | %d | %d | %d\n",
rtcphdr->syn, rtcphdr->ack,
rtcphdr->rst, rtcphdr->psh,
rtcphdr->urg, rtcphdr->fin,
riphdr->ttl, rtcphdr->window);
printf("seq=%d - ack_seq=%d -
doff=%d - check=%d - ID=%d\n\n",
rtcphdr->seq, rtcphdr->ack_seq,
rtcphdr->doff, rtcphdr->check,
riphdr->id);
return;
}
}
}
close(rs);
close(s);
}
return;
}
unsigned short cksum(unsigned short *ptr,int nbytes)
{
register long sum;
unsigned short oddbyte;
register unsigned short anwser;
sum = 0;
while(nbytes>1)
{
sum += *ptr++;
nbytes -= 2;
}
if(nbytes==1)
{
oddbyte = 0;
*((unsigned char *) & oddbyte) = *(unsigned char *)ptr;
sum += oddbyte;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
anwser = ~sum;
return(anwser);
}
void usage(char *nom) {
printf("Usage: %s [s|a|r|p|u|f] [-x host_source] -d host_destination
-c port\n", nom);
printf("\t-s SYN flag enabled\n");
printf("\t-a ACK flag enabled\n");
printf("\t-r RST flag enabled\n");
printf("\t-p PSH flag enabled\n");
printf("\t-u URG flag enabled\n");
printf("\t-f FIN flag enabled\n");
exit(-1);
}
-------------------------------------------8<---------------------------------
--- checkicmp.c ---------------------------8<---------------------------------
// checkicmp.c
// By Pepelux
#include <netinet/in.h>
#include <netinet/ip_icmp.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#define Error(msg) { perror(msg); exit -1; }
int main(void) {
int s;
struct sockaddr_in dir = {AF_INET, 0, 0 };
char buff[1024];
int len = sizeof(dir);
struct icmphdr *rec = (struct icmphdr*) (buff + sizeof(struct iphdr));
if (geteuid() != 0) {
printf("You must be root\n");
exit(0);
}
if ((s = socket(AF_INET, SOCK_RAW, 1)) < 0)
Error("socket");
printf("Waiting data ...\n");
while (1) {
bzero(buff, 1024);
while (recvfrom(s, buff, 1024, 0, (struct sockaddr_in*) &dir,
&len) > 0)
printf("Received:\ttype %d\tcode %d\n", rec->type,
rec->code);
}
}
-------------------------------------------8<---------------------------------
--- sendudp.c -----------------------------8<---------------------------------
// sendudp.c
// By Pepelux
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#define Error(msg) { perror(msg); exit -1; }
main (int argc, char *argv[])
{
int s;
int dport;
struct sockaddr_in addr_dest;
if (argc!=3) {
printf ("Usage: %s ip port\n", argv[0]);
exit(0);
}
dport = atoi(argv[2]);
printf ("Sending UDP packet to %s:%d\n",argv[1], dport);
if ((s=socket(AF_INET,SOCK_DGRAM,0)) < 0)
Error("socket");
addr_dest.sin_addr.s_addr=inet_addr(argv[1]);
addr_dest.sin_family=AF_INET;
addr_dest.sin_port=htons(dport);
if (sendto(s,"\n",1,0,(struct sockaddr*)&addr_dest,sizeof(struct
sockaddr_in)) < 0)
Error("sendto");
close (s);
}
-------------------------------------------8<---------------------------------
------[ 5.- Referências ]
Aqui estão links de páginas interessantes que eu usei para escrever este documento:
Standards (RFCs):
Protocolo TCP : http://www.rfc-editor.org/rfc/rfc793.txt
Protocolo IP : http://www.rfc-editor.org/rfc/rfc791.txt
Protocolo UDP : http://www.rfc-editor.org/rfc/rfc768.txt
Protocolo ICMP : http://www.rfc-editor.org/rfc/rfc792.txt
Documentação do Nmap: http://insecure.org/nmap/man/
------[ 6.-Finalizando ]
Bem, sim, tudo o que é feito pelo nmap, é mais bonito, mais rápido e melhor
... mas, isso é engraçado, não? :p
Nmap tem muitos métodos de scan mas algumas vezes a resposta é imprevisÃvel,
dependendo do sistema operacional rodando. Por isso é bom escanear manualmente!
Além do mais você vai deixar menos logs e irá aprender mais.
Abraços!!!
Pepelux <[email protected]>
http://www.enye-sec.org
=-|================================================================ EOF =====|
# milw0rm.com [2008-09-28]
- Источник
- www.exploit-db.com