Por que a localização das variáveis ​​de ambiente varia tanto?

9

Lendo o livro Hacking: The Art of Exploitation de Jon Erickson, estou tentando aproximar o endereço de uma variável de ambiente SHELLCODEpara explorar um programa.

Toda vez que corro getenv("SHELLCODE");para obter o local, o resultado é completamente diferente.

Extrato do meu shell:

> for i in $(seq 10); do ./a.out SHELLCODE; done
SHELLCODE is at 0xff9ab3a3
SHELLCODE is at 0xffcdb3a3
SHELLCODE is at 0xffb9a3a3
SHELLCODE is at 0xffa743a3
SHELLCODE is at 0xffdb43a3
SHELLCODE is at 0xfff683a3
SHELLCODE is at 0xffef03a3
SHELLCODE is at 0xffc1c3a3
SHELLCODE is at 0xff85a3a3
SHELLCODE is at 0xff8e03a3

Entendo que, se o nome do programa for modificado ou forem adicionadas novas variáveis ​​de ambiente, a posição será um pouco diferente, mas por que o local varia tanto?

Janman
fonte
O getenvmanual diz que retorna um ponteiro para uma string que contém o valor da variável. Todo o resto não é especificado, portanto seu kernel e / ou compilador podem fixar o valor onde quiserem, desde que a promessa do ponteiro permaneça verdadeira. Estou supondo que a resposta exata para isso possa ser pesada e depende de vários detalhes de implementação de mapeamento de memória e da fase da lua. (Eu não sou assistente suficiente para lhe dar a resposta exata.)
Anko
"Entendo que se o nome do programa for modificado ou se novas variáveis ​​de ambiente forem adicionadas, a posição será um pouco diferente, mas por que o local varia tanto?" Isso é verdade na mais simples de todas as implementações possíveis, mas certamente não é necessário.
dmckee --- gatinho ex-moderador

Respostas:

13

O que você descreve é ​​um recurso anti-exploração chamado ASLR ( Randomização do Layout do Espaço de Endereço ). Basicamente, o kernel coloca o endereço mais alto da pilha de chamadas de função de um programa em um endereço ligeiramente diferente ("aleatório") toda vez que o kernel carrega o arquivo ELF do programa do disco. Os endereços argve as variáveis ​​de ambiente, dos quais o seu código de shell é um, terminam em um endereço variável a cada chamada do programa.

O ASLR deve dificultar a exploração de estouros de buffer e outras vulnerabilidades relacionadas à pilha. O explorador precisa escrever código ou fazer algo para explicar os endereços variáveis ​​de variáveis ​​e valores na pilha de chamadas de função.

Parece que você pode desativar o ASLR fazendo algo como:

echo 0 > /proc/sys/kernel/randomize_va_space

como usuário root. Desde que você cita explicitamente o Ubuntu, o comando acima é diferente:

echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
Bruce Ediger
fonte
Sim, isso fez o truque. Notei que o autor do livro usa o Ubuntu 10.04, que ainda não tinha ASLR.
Janman