Introdução
Este artigo pressupõe um conhecimento prático de técnicas básicas de ShellCoding e x86 montagem, vou refazer estes não no presente documento. Espero poder ensinar-lhe algumas das menos conhecidas técnicas ShellCoding que eu peguei, o que permitirá que você escreva shellcodes menor e melhor. Não tenho a pretensão de ter inventado qualquer uma destas técnicas, exceto para aquele que usa a instrução DIV.
A multiplicidade de mul
Esta técnica foi originalmente desenvolvido pela Sorbo de darkircop.net. A instrução mul pode, à primeira vista, parecem banais, e é óbvio propósito. No entanto, quando confrontado com o difícil desafio de diminuir o seu shellcode, prova ser bastante útil. Primeiro algumas informações básicas sobre a instrução mul si.
mul realiza uma assinatura de multiplicar dois números inteiros. Leva apenas um operando, o outro está implicitamente especificado pelo registo %eax. Assim, uma instrução comum mul poderia ser algo como isto:
Isso seria multiplicar o valor armazenado em %eax pelo operando de Mul, que neste caso seria 10 * 10. O resultado é, então, implicitamente armazenado em EDX: EAX. O resultado é armazenado em um período de dois registros porque tem o potencial de ser consideravelmente maior do que o valor anterior, susceptíveis de exceder a capacidade de um único registo (isto é também como pontos flutuantes são armazenados em alguns casos, como uma sidenote interessante) .
Então, agora vem a questão sempre importante. Como podemos usar esses atributos para nossa vantagem, ao escrever shellcode? Bem, vamos pensar por um segundo, a instrução leva apenas um operando, portanto, uma vez que é uma instrução muito comum, que irá gerar apenas dois bytes em nosso shellcode final. Ele multiplica o que é passado para ele pelo valor armazenado em %eax, e armazena o valor em ambos os %edx e %eax, substituindo completamente o conteúdo de ambos os registos, independentemente de se é necessário fazê-lo, a fim de armazenar o resultado da multiplicação. Vamos colocar nossos chapéus matemático por um segundo, e considero este, o que é o único resultado possível de uma multiplicação por 0? A resposta, como você deve ter adivinhado, é 0. I think it's about time para alguns códigos de exemplo, então aqui está:
O que é isso shellcode fazendo? Pois bem, ele está fora do 0 %ecx registo utilizando a instrução XOR, assim que nós sabemos agora que é de 0 %ecx. Em seguida, ele faz uma mul %ecx, que, como acabamos de aprender, está operando multiplica pelo valor do %eax, e então passa a armazenar o resultado da multiplicação em EDX: EAX. Assim, independentemente do conteúdo anterior de %eax,%eax agora deve ser 0. No entanto isso não é tudo,%edx é 0'd agora também, porque, apesar de não ocorrer estouro, ainda substitui o registo %edx com o bit de sinal (bit mais à esquerda) de %eax. Usando esta técnica, podemos zerar três registros em apenas três bytes, enquanto que por qualquer outro método (que eu saiba) que teria tomado pelo menos seis.
A instrução div
Div. é muito semelhante à mul, na medida em que leva apenas um operando e, implicitamente, divide o operando pelo valor de %eax. Também gosto, mul ele armazena o resultado da divisão em %eax. Novamente, vamos exigir que o lado matemático do nosso cérebro para descobrir como podemos tirar proveito desta instrução. Mas primeiro, vamos pensar sobre o que normalmente é armazenado no registrador %eax. O registo %eax contém o valor de retorno de funções e / ou syscalls. A maioria syscalls que são usados em ShellCoding retornará -1 (em caso de falha) ou um valor positivo de algum tipo, só muito raramente eles irão retornar 0 (embora ela não ocorrer). Então, se nós sabemos que, após uma syscall é realizada, %eax terá um valor diferente de zero, e que a instrução %eax divl vai dividir %eax, por si só, e depois armazenar o resultado em %eax, podemos dizer que a execução a instrução %eax divl, após uma syscall irá colocar o valor 1 em %eax. Então ... como isso é aplicável a ShellCoding? Bem, a sua é outra coisa importante que %eax é utilizada, e que está a passar o syscall específico que você gostaria de chamar a int $ 0x80. Acontece que a syscall que corresponde ao valor 1 é exit (). Agora, para um exemplo:
Agora, temos uma função de 3 de saída de bytes, onde, como antes era 5 bytes. No entanto, existe uma captura, o que se faz uma syscall retornar 0? Bem na situação ímpar em que isso poderia acontecer, você pode fazer muitas coisas diferentes, como o inc% eax,% eax dec% eax não nada que não fará% eax-zero. Algumas pessoas dizem que a saída não são importantes no shellcode, porque seu código é executado independentemente de haver ou não ele sai limpo. Eles estão certos também, se você realmente precisa salvar 3 bytes para caber seu shellcode em algum lugar, a saída () não vale a pena manter. No entanto, quando o código não terminar, ele irá tentar executar o que foi depois de sua última instrução, o que provavelmente irão produzir uma ILL SIG (instrução ilegal), que é um erro muito estranho, e será registrado pelo sistema. Assim, uma saída () simplesmente adiciona uma camada extra de discrição para sua exploração, de modo que mesmo se falhar ou se você não pode apagar todos os registros, pelo menos esta parte da sua presença será clara.
Libertar o poder do Leal
A instrução Leal é uma instrução muitas vezes negligenciada em shellcode, embora seja bastante útil. Considere este pequeno pedaço de shellcode.
Isto irá carregar o valor de 17 em eax, e claro de todos os pedaços estranhos de eax. Isso ocorre porque o Leal instrução carrega uma variável do tipo longa em que é operando desitination. Nele está o uso normal, esta seria carregar o endereço de uma variável em um registrador, criando assim uma espécie de ponteiro. No entanto, desde ecx é 0'd e 0 +17 = 17, temos de carregar o valor de 17 em eax, em vez de qualquer tipo de endereço real. Em um shell normal que faríamos algo assim, para realizar a mesma coisa:
Eu posso ouvir você dizer, mas que é um byte shellcode mais curto que o Leal, e você está completamente certo. No entanto, em um shellcode real você já pode ter a 0 fora de um registo como ecx (ou registrar quaisquer outros), para a instrução xorl no shellcode Leal não é contabilizada. Aqui está um exemplo:
0
Ambos os shellcodes chamada setuid (0), mas um faz de 7 bytes, enquanto o outro faz de 8. Outra vez, eu ouvi-lo dizer, mas isso é apenas um byte não faz muita diferença, e você está certo, aqui não faz muita diferença (exceto no shellcode concursos de tamanho pissing = p) , mas quando aplicada a shellcodes muito maior, que muitas chamadas de função e necessidade de fazer coisas como esta freqüentemente, pode guardar um pouco de espaço.
Conclusão
Espero que todos aprendemos alguma coisa, e vão sair e aplicar seus conhecimentos para criar shellcodes menor e melhor. Se você sabe quem inventou a técnica Leal, por favor me diga e eu vou de crédito dele / dela.
Este artigo pressupõe um conhecimento prático de técnicas básicas de ShellCoding e x86 montagem, vou refazer estes não no presente documento. Espero poder ensinar-lhe algumas das menos conhecidas técnicas ShellCoding que eu peguei, o que permitirá que você escreva shellcodes menor e melhor. Não tenho a pretensão de ter inventado qualquer uma destas técnicas, exceto para aquele que usa a instrução DIV.
A multiplicidade de mul
Esta técnica foi originalmente desenvolvido pela Sorbo de darkircop.net. A instrução mul pode, à primeira vista, parecem banais, e é óbvio propósito. No entanto, quando confrontado com o difícil desafio de diminuir o seu shellcode, prova ser bastante útil. Primeiro algumas informações básicas sobre a instrução mul si.
mul realiza uma assinatura de multiplicar dois números inteiros. Leva apenas um operando, o outro está implicitamente especificado pelo registo %eax. Assim, uma instrução comum mul poderia ser algo como isto:
Código:
0x0a movl $,%eax mul $ 0x0a
Então, agora vem a questão sempre importante. Como podemos usar esses atributos para nossa vantagem, ao escrever shellcode? Bem, vamos pensar por um segundo, a instrução leva apenas um operando, portanto, uma vez que é uma instrução muito comum, que irá gerar apenas dois bytes em nosso shellcode final. Ele multiplica o que é passado para ele pelo valor armazenado em %eax, e armazena o valor em ambos os %edx e %eax, substituindo completamente o conteúdo de ambos os registos, independentemente de se é necessário fazê-lo, a fim de armazenar o resultado da multiplicação. Vamos colocar nossos chapéus matemático por um segundo, e considero este, o que é o único resultado possível de uma multiplicação por 0? A resposta, como você deve ter adivinhado, é 0. I think it's about time para alguns códigos de exemplo, então aqui está:
Código:
xorl% ecx,% ecx % ecx mul
A instrução div
Div. é muito semelhante à mul, na medida em que leva apenas um operando e, implicitamente, divide o operando pelo valor de %eax. Também gosto, mul ele armazena o resultado da divisão em %eax. Novamente, vamos exigir que o lado matemático do nosso cérebro para descobrir como podemos tirar proveito desta instrução. Mas primeiro, vamos pensar sobre o que normalmente é armazenado no registrador %eax. O registo %eax contém o valor de retorno de funções e / ou syscalls. A maioria syscalls que são usados em ShellCoding retornará -1 (em caso de falha) ou um valor positivo de algum tipo, só muito raramente eles irão retornar 0 (embora ela não ocorrer). Então, se nós sabemos que, após uma syscall é realizada, %eax terá um valor diferente de zero, e que a instrução %eax divl vai dividir %eax, por si só, e depois armazenar o resultado em %eax, podemos dizer que a execução a instrução %eax divl, após uma syscall irá colocar o valor 1 em %eax. Então ... como isso é aplicável a ShellCoding? Bem, a sua é outra coisa importante que %eax é utilizada, e que está a passar o syscall específico que você gostaria de chamar a int $ 0x80. Acontece que a syscall que corresponde ao valor 1 é exit (). Agora, para um exemplo:
Código:
xorl %ebx,%ebx mul %ebx push %edx pushl $0x3268732f pushl $0x6e69622f mov %esp, %ebx push %edx push %ebx mov %esp,%ecx movb $0xb, %al #execve() syscall, doesn't return at all unless it fails, in which case it returns -1 int $0x80 divl %eax # -1 / -1 = 1 int $0x80
Libertar o poder do Leal
A instrução Leal é uma instrução muitas vezes negligenciada em shellcode, embora seja bastante útil. Considere este pequeno pedaço de shellcode.
Código:
xorl %ecx,%ecx leal 0x10(%ecx),%eax
Código:
xorl %eax,%eax movb $0x10,%eax
Código:
xorl %eax,%eax xorl %ebx,%ebx movb $0x17,%al int $0x80 xorl %ebx,%ebx leal 0x17(%ebx),%al int $0x8
Ambos os shellcodes chamada setuid (0), mas um faz de 7 bytes, enquanto o outro faz de 8. Outra vez, eu ouvi-lo dizer, mas isso é apenas um byte não faz muita diferença, e você está certo, aqui não faz muita diferença (exceto no shellcode concursos de tamanho pissing = p) , mas quando aplicada a shellcodes muito maior, que muitas chamadas de função e necessidade de fazer coisas como esta freqüentemente, pode guardar um pouco de espaço.
Conclusão
Espero que todos aprendemos alguma coisa, e vão sair e aplicar seus conhecimentos para criar shellcodes menor e melhor. Se você sabe quem inventou a técnica Leal, por favor me diga e eu vou de crédito dele / dela.
Comment