2016-11-08 15 views
0

64-bit Linux stack smashing tutorial: Part 1 использует Get environment variable address gist для получения адреса переменной окружения. Предварительным условием является сначала отключить ASLR через echo 0 > proc/sys/kernel/randomize_va_space.Почему этот кусок кода может получить адрес переменной окружения?

Содержание сути является:

/* 
* I'm not the author of this code, and I'm not sure who is. 
* There are several variants floating around on the Internet, 
* but this is the one I use. 
*/ 

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int main(int argc, char *argv[]) { 
    char *ptr; 

    if(argc < 3) { 
     printf("Usage: %s <environment variable> <target program name>\n", argv[0]); 
     exit(0); 
    } 
    ptr = getenv(argv[1]); /* get env var location */ 
    ptr += (strlen(argv[0]) - strlen(argv[2]))*2; /* adjust for program name */ 
    printf("%s will be at %p\n", argv[1], ptr); 
} 

Почему *2 используется для настройки для имени программы?

Я предполагаю, что имя программы сохраняется дважды над стеком.

enter image description here

Следующая диаграмма из https://lwn.net/Articles/631631/ дает более подробную информацию:

------------------------------------------------------------- 0x7fff6c845000 
0x7fff6c844ff8: 0x0000000000000000 
     _ 4fec: './stackdump\0'      <------+ 
    env/ 4fe2: 'ENVVAR2=2\0'        | <----+ 
     \_ 4fd8: 'ENVVAR1=1\0'        | <---+ | 
    / 4fd4: 'two\0'          |  | |  <----+ 
args | 4fd0: 'one\0'          |  | | <---+ | 
     \_ 4fcb: 'zero\0'         |  | | <--+ | | 
      3020: random gap padded to 16B boundary   |  | |  | | | 

На этой диаграмме ./stackdump используется для выполнения программы. Поэтому я вижу, что имя программы ./stackdump сохраняется один раз над строками среды. И если ./stackdump запускается из оболочки Bash, Bashell сохранит его в строках среды с ключом _:

_

(подчеркивания.) При запуске оболочки установлен абсолютный путь, используемый для вызова оболочки или сценарий оболочки, который передается в списке окружения или аргументов . Впоследствии он расширяется до последнего аргумента предыдущей команды после расширения. Также установлено полное имя пути, которое используется для вызова каждой команды, выполняемой и помещенной в окружение , экспортированное в эту команду. При проверке почты этот параметр содержит имя почтового файла.

Окружающая среда находится над стеком. Таким образом, имя программы сохраняется в другой раз выше стека.

+1

Что именно вы спрашиваете? Код работает, потому что getenv получает адрес переменной среды, а вызов вашей программы также занимает место в стеке, поэтому вы соответствующим образом корректируете указатель. Это в комментариях к коду. –

+0

Насколько мне известно, в названии программы, выделенной в стеке, обычно содержится около 2 байтов на символ. Первое место, которое я видел в этом фрагменте кода, было в * Hacking: Art of Exploitation * от Jon Erickson. Я предлагаю читать больше там или изучать ядро ​​Linux, чтобы понять, как выглядит стек в памяти. –

+0

@JacobH да, код берет начало с Страница 147 и 148 из * Взлом: Искусство эксплуатации, второе издание * Джона Эриксона. Но книга не объясняет, почему она работает. –

ответ

0

В случае, если кому-то все еще интересно, почему. Это связано с тем, что имя программы также сохраняется в имени переменной среды «_», кроме того, что перед всеми переменными окружения вставляется в стек.

Вы можете проверить это, установив gdb в процесс и проанализировав содержимое стека под последними переменными окружения. Пусть 0x7fffffffabcd это адрес последнего переменного окружения:

$ gdb -p <pid> 

(gdb) x/20s 0x7fffffffabcd 

Название программы хранится в argv[0] не влияет на адрес переменной окружении, потому что она находится на вершине последнего переменного окружения в стеке.

0

Сохранить следующий код в stackdump.c:

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

int main(int argc, char *argv[]) { 
    char *ptr; 
    int i; 

    for (i = 0; i < argc; i++) { 
    printf(" argv[%d]: %p, %p, %s\n", i, argv + i, argv[i], argv[i]); 
    } 

    char * program = (char *)getauxval(AT_EXECFN); 
    printf("AT_EXECFN:    , %p, %s\n", program, program); 
    char* path = getenv("PATH"); 
    printf("  PATH:    , %p, %s\n", path, path); 
    char* underscore = getenv("_"); 
    printf("  _:    , %p, %s\n", underscore, underscore); 
} 

Во-первых, работает gcc -o stackdump stackdump.c для компиляции кода. Во-вторых, выполните echo 0 > proc/sys/kernel/randomize_va_space. В-третьих, бег ./stackdump zero one two дать:

argv[0]: 0x7fffffffe4a8, 0x7fffffffe6e5, ./stackdump 
    argv[1]: 0x7fffffffe4b0, 0x7fffffffe6f1, zero 
    argv[2]: 0x7fffffffe4b8, 0x7fffffffe6f6, one 
    argv[3]: 0x7fffffffe4c0, 0x7fffffffe6fa, two 
AT_EXECFN:    , 0x7fffffffefec, ./stackdump 
    PATH:    , 0x7fffffffee89, /usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/cloud-user/.local/bin:/home/cloud-user/bin 
     _:    , 0x7fffffffefe0, ./stackdump 

Три копии ./stackdump находятся в адресном пространстве программы, как показано выше.Два из них имеют более высокий, чем адрес PATH, как показано ниже:

AT_EXECFN: 0x7fffffffefec, ./stackdump 
     _: 0x7fffffffefe0, ./stackdump 
    PATH: 0x7fffffffee89, /usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/cloud-user/.local/bin:/home/cloud-user/bin 

Так причина *2 переменная _ среды и AT_EXECFNauxiliary vector value.