Ir para conteúdo

Dúvidas na execução de shellcode


bsd0x

Posts Recomendados

Olá, pessoal, recentemente adquiri interesse em desenvolvimento de exploits entre outros assuntos relacionados.

Ainda sou muito iniciante e estou tendo algumas dificuldades para entender alguma peculiaridades. Fiz um código em C utilizando assembly inline e o mesmo não estava compilando, achei uma solução para isso na internet que seria execução o seguinte trecho de código.

int (*ret)() = (int(*)())sc;

ret();

Minha dúvida é: qual a diferença entre usar o __asm__("jmp sc") e usar a solução acima?

Codigo completo

/*
 8049000:	b8 01 00 00 00       	mov    eax,0x1
 8049005:	bb 01 00 00 00       	mov    ebx,0x1
 804900a:	cd 80                	int    0x80


 8049000:	b8 01 00 00 00       	mov    eax,0x1
 8049005:	bb 00 00 00 00       	mov    ebx,0x0
 804900a:	cd 80                	int    0x80


*/

#include <stdio.h>

int main() {
	unsigned char sc[] = 
		"\xb8\x01\x00\x00\x00"
		"\xbb\x01\x00\x00\x00"
		"\xcd\x80";

	printf("Shellcode length: %d\n", sizeof(sc));

	//__asm__("jmp sc");

	int (*ret)() = (int(*)())sc;

	ret();
}

 

 

Link para o comentário
Compartilhar em outros sites

Isso, provavelmente, não funcionará, ou, pelo menos, não funcionará em qualquer "box" linux...

Em primeiro lugar, os "segmentos" de dados, num sistema paginado, pode definir as páginas com o bit NX ligdo (NX de Non eXecutable). Isso costuma ser  particularmente verdade, inclusive, para a pilha. Daí, simplesmente definir um ponteiro de função apontando para a sequência de bytes que definem as instruções simplesmente causará um segmentation fault na maioria dos "boxes" com kernels modernos.

Em segundo lugar, o uso da "int 0x80", embora também exista em sistemas amd64 (x86-64), geralmente causam problemas (especialmente com uso de ponteiros). A coisa complica se quiser criar um "shellcode" no modo amd64 (x86-64), onde referências à memória costumam ser relativas ao RIP.

O que se pode fazer com relação ao primeiro caso é alocar as páginas "executáveis" (com o bit NX desligado) usando as system calls mmap() e mprotect() [ativando o flag PROT_EXEC] - mesmo assim, dependendo da versão do kernel, existem proteções para esse tipo de tentativa... Depois, copia-se o conteúdo do "shellcode" para dentro dessas páginas. Daí salta-se para elas.

Link para o comentário
Compartilhar em outros sites

Quanto a dúvida: A diferença é que o operador () de C realizará um CALL... No contexto acima, tanto o JMP quanto um CALL deixarão de fazer o housekeeping necessário para destruir objetos e outras coisas necessárias da libc... Desconsiderando isso, TANTO FAZ fazer um JMP ou um CALL, NESTE CASO.

Link para o comentário
Compartilhar em outros sites

PS: Você deve estar pensando: "Ahhh... mas aqui funciona!"... Eu usei "provavelmente" e "pode" em vários lugares do texto... Em alguns ambientes que seguem a SysV ABI isso ai não funciona (acho que é o caso do FreeBSD e do MacOS, por exemplo).

Mas, isso aqui PODE funcionar:
 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>

int main( void )
{
  int x;
  static unsigned char shcodep[] = "\x31\xc0"   // xor eax,eax
                                   "\xc3";      // ret

  int (*f)(void);

  // FIXME: PODE ser que funcione!
  // Cria página com NX desligado, privada ao processo com permissão de leitura/escrita.
  f = mmap( NULL, 
            sizeof shcodep, 
            PROT_READ | PROT_WRITE | PROT_EXEC, 
            MAP_PRIVATE | MAP_ANONYMOUS, 
            -1, 
            0 );

  if ( (ssize_t)f == -1 )
  {
    perror( "mmap" );
    return EXIT_FAILURE;
  }

  // Copia o "código" para a página alocada.
  memcpy( f, shcodep, sizeof shcodep );

  x = f();  // chama...

  munmap( f, sizeof shcodep );

  printf( "%d\n", x );

  return EXIT_SUCCESS;
}

 

Link para o comentário
Compartilhar em outros sites

Muito obrigado pela aula, Fred hahahaha
vou tentar aplicar isso:
 

Quote

O que se pode fazer com relação ao primeiro caso é alocar as páginas "executáveis" (com o bit NX desligado) usando as system calls mmap() e mprotect() [ativando o flag PROT_EXEC] - mesmo assim, dependendo da versão do kernel, existem proteções para esse tipo de tentativa... Depois, copia-se o conteúdo do "shellcode" para dentro dessas páginas. Daí salta-se para elas.

Abraço!

Inclusive, saudades do grupo C/asm do facebook hahahaha
 

Link para o comentário
Compartilhar em outros sites

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

  • Quem Está Navegando   0 membros estão online

    • Nenhum usuário registrado visualizando esta página.
×
×
  • Criar Novo...