Главная страница
Навигация по странице:

  • O_RDONLY Открыть файл только для чтения.O_WRONLY Открыть файл только для записи.O_RDWR

  • O_APPEND Записать данные в конец файла.O_TRUNC Если файл уже существует, сократить его длину до 0.O_CREAT

  • 0x282 Права доступа к файлам

  • S_IRUSR Право чтения файла предоставляется пользователю (владельцу).S_IWUSR Право записи файла предоставляется пользователю (владельцу).S_IXUSR

  • S_IROTH Право чтения файла предоставляется всем (от other ).S_IWOTH Право записи в файл предоставляется всем.S_IXOTH

  • 0x283 Идентификатор пользователя

  • Хакинг. Хакинг__искусство_эксплоита_2_е_469663841. Книга дает полное представление о программировании, машин ной архитектуре, сетевых соединениях и хакерских приемах


    Скачать 2.5 Mb.
    НазваниеКнига дает полное представление о программировании, машин ной архитектуре, сетевых соединениях и хакерских приемах
    АнкорХакинг
    Дата16.06.2022
    Размер2.5 Mb.
    Формат файлаpdf
    Имя файлаХакинг__искусство_эксплоита_2_е_469663841.pdf
    ТипКнига
    #595131
    страница12 из 51
    1   ...   8   9   10   11   12   13   14   15   ...   51

    100
    0x200 Программирование функции и обработки критических ошибок. Функция usage() опреде- лена выше main(), поэтому ей не нужен прототип.
    simplenote.c
    #include
    #include
    #include
    #include
    #include
    void usage(char *prog_name, char *filename) {
    printf(“Usage: %s \n”, prog_name, filename);
    exit(0);
    }
    void fatal(char *); // Функция обработки критических ошибок void *ec_malloc(unsigned int); // Оболочка для malloc() с проверкой ошибок int main(int argc, char *argv[]) {
    int fd; // file descriptor char *buffer, *datafile;
    buffer = (char *) ec_malloc(100);
    datafile = (char *) ec_malloc(20);
    strcpy(datafile, “/tmp/notes”);
    if(argc < 2) // Если аргументов командной строки нет,
    usage(argv[0], datafile); // вывести сообщение о правилах вызова
    // и завершить работу.
    strcpy(buffer, argv[1]); // Копировать в буфер.
    printf(“[DEBUG] buffer @ %p: \’%s\’\n”, buffer, buffer);
    printf(“[DEBUG] datafile @ %p: \’%s\’\n”, datafile, datafile);
    strncat(buffer, “\n”, 1); // Добавить в конце перевод строки.
    // Открытие файла fd = open(datafile, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR);
    if(fd == -1)
    fatal(“in main() while opening file”);
    printf(“[DEBUG] file descriptor is %d\n”, fd);
    // Запись данных if(write(fd, buffer, strlen(buffer)) == -1)
    fatal(“in main() while writing buffer to file”);
    // Закрытие файла if(close(fd) == -1)
    fatal(“in main() while closing file”);
    printf(“Note has been saved.\n”);
    free(buffer);

    0x280 Опираясь на основы
    101
    free(datafile);
    }
    // Функция для вывода сообщения об ошибке и завершения работы программы void fatal(char *message) {
    char error_message[100];
    strcpy(error_message, “[!!] Fatal Error “);
    strncat(error_message, message, 83);
    perror(error_message);
    exit(-1);
    }
    // Оболочка для malloc() с проверкой ошибок void *ec_malloc(unsigned int size) {
    void *ptr;
    ptr = malloc(size);
    if(ptr == NULL)
    fatal(“in ec_malloc() on memory allocation”);
    return ptr;
    }
    За исключением необычных флагов в функции open(), код этой програм- мы должен быть вполне ясен. Здесь также используется ряд стандартных функций, не встречавшихся ранее. Функция strlen() принимает стро- ку и возвращает ее длину. Она используется вместе с функцией write(), которой нужно знать, сколько байт должно быть записано. Функция perror()
    (от print error) служит для вывода сообщения об ошибке и ис- пользуется в fatal() для вывода дополнительного сообщения об ошибке
    (если таковое имеется) и завершения работы программы.
    reader@hacking:

    /booksrc $ gcc -o simplenote simplenote.c reader@hacking:/booksrc $ ./simplenote
    Usage: ./simplenote
    reader@hacking:/booksrc $ ./simplenote “this is a test note”
    [DEBUG] buffer @ 0x804a008: ‘this is a test note’
    [DEBUG] datafile @ 0x804a070: ‘/tmp/notes’
    [DEBUG] file descriptor is 3
    Note has been saved.
    reader@hacking:/booksrc $ cat /tmp/notes this is a test note reader@hacking:/booksrc $ ./simplenote “great, it works”
    [DEBUG] buffer @ 0x804a008: ‘great, it works’
    [DEBUG] datafile @ 0x804a070: ‘/tmp/notes’
    [DEBUG] file descriptor is 3
    Note has been saved.
    reader@hacking:/booksrc $ cat /tmp/notes this is a test note great, it works reader@hacking:/booksrc $

    102
    0x200 Программирование
    Вывод программы не вызывает вопросов, но кое-что в исходном коде требует пояснения. Файлы fcntl.h и sys/stat.h должны быть включены
    (#include), потому что в них определены флаги, используемые функци- ей open(). Первая группа флагов находится в fcntl.h и участвует в опре- делении режима доступа. В режиме доступа должен быть задан хотя бы один из следующих флагов:
    O_RDONLY
    Открыть файл только для чтения.
    O_WRONLY
    Открыть файл только для записи.
    O_RDWR
    Открыть файл для чтения и записи.
    Эти флаги можно использовать вместе с некоторыми другими, необя- зательными, соединяя их поразрядным ИЛИ. В число наиболее упо- требительных и полезных флагов входят:
    O_APPEND
    Записать данные в конец файла.
    O_TRUNC
    Если файл уже существует, сократить его длину до 0.
    O_CREAT
    Создать файл, если он еще не существует.
    Поразрядные операции действуют над битами, пропуская их через стандартные логические вентили, такие как ИЛИ и И. Если два бита поступают на вход вентиля ИЛИ, результат будет 1, если один или дру- гой бит равен 1. Если два бита поступают на вход вентиля И, результат будет 1, если оба бита равны 1. Над 32-разрядными числами можно вы- полнять поразрядные операции, применяя логические операторы к их соответствующим битам. Исходный код и вывод программы bitwise.c
    иллюстрируют эти поразрядные операции.
    bitwise.c
    #include
    int main() {
    int i, bit_a, bit_b;
    printf(“bitwise OR operator |\n”);
    for(i=0; i < 4; i++) {
    bit_a = (i & 2) / 2; // Взять второй бит.
    bit_b = (i & 1); // Взять первый бит.
    printf(“%d | %d = %d\n”, bit_a, bit_b, bit_a | bit_b);
    }
    printf(“\nbitwise AND operator &\n”);
    for(i=0; i < 4; i++) {
    bit_a = (i & 2) / 2; // Взять второй бит.
    bit_b = (i & 1); // Взять первый бит.
    printf(“%d & %d = %d\n”, bit_a, bit_b, bit_a & bit_b);
    }
    }

    0x280 Опираясь на основы
    103
    Результат компиляции и выполнения bitwise.c:
    reader@hacking:/booksrc $ gcc bitwise.c reader@hacking:/booksrc $ ./a.out bitwise OR operator |
    0 | 0 = 0 0 | 1 = 1 1 | 0 = 1 1 | 1 = 1
    bitwise AND operator &
    0 & 0 = 0 0 & 1 = 0 1 & 0 = 0 1 & 1 = 1
    reader@hacking:/booksrc $
    Значения флагов, используемых в функции open(), состоят из един- ственного бита. Благодаря этому можно объединять их с помощью по- разрядного ИЛИ, не теряя информации. Программа fcntl_flags.c и ее вывод позволяют изучить некоторые флаги, определенные в fcntl.h, и результат их объединения.
    fcntl_flags.c
    #include
    #include
    void display_flags(char *, unsigned int);
    void binary_print(unsigned int);
    int main(int argc, char *argv[]) {
    display_flags(“O_RDONLY\t\t”, O_RDONLY);
    display_flags(“O_WRONLY\t\t”, O_WRONLY);
    display_flags(“O_RDWR\t\t\t”, O_RDWR);
    printf(“\n”);
    display_flags(“O_APPEND\t\t”, O_APPEND);
    display_flags(“O_TRUNC\t\t\t”, O_TRUNC);
    display_flags(“O_CREAT\t\t\t”, O_CREAT);
    printf(“\n”);
    display_flags(“O_WRONLY|O_APPEND|O_CREAT”, O_WRONLY|O_APPEND|O_CREAT);
    }
    void display_flags(char *label, unsigned int value) {
    printf(“%s\t: %d\t:”, label, value);
    binary_print(value);
    printf(“\n”);
    }
    void binary_print(unsigned int value) {
    unsigned int mask = 0xff000000; // Маска для старшего байта.
    unsigned int shift = 256*256*256; // Смещение для старшего байта.

    104
    0x200 Программирование unsigned int byte, byte_iterator, bit_iterator;
    for(byte_iterator=0; byte_iterator < 4; byte_iterator++) {
    byte = (value & mask) / shift; // Выделить каждый байт.
    printf(“ “);
    for(bit_iterator=0; bit_iterator < 8; bit_iterator++) { // Вывести
    // биты байта.
    if(byte & 0x80) // Если старший бит в байте не 0,
    printf(“1”); // вывести 1.
    else printf(“0”); // Иначе вывести 0.
    byte *= 2; // Сдвинуть все биты влево на 1.
    }
    mask /= 256; // Переместить биты маски вправо на 8.
    shift /= 256; // Переместить биты смещения вправо на 8.
    }
    }
    Результат компиляции и выполнения fcntl_flags.c:
    reader@hacking:/booksrc $ gcc fcntl_flags.c reader@hacking:/booksrc $ ./a.out
    O_RDONLY : 0 : 00000000 00000000 00000000 00000000
    O_WRONLY : 1 : 00000000 00000000 00000000 00000001
    O_RDWR : 2 : 00000000 00000000 00000000 00000010
    O_APPEND : 1024 : 00000000 00000000 00000100 00000000
    O_TRUNC : 512 : 00000000 00000000 00000010 00000000
    O_CREAT : 64 : 00000000 00000000 00000000 01000000
    O_WRONLY|O_APPEND|O_CREAT : 1089 : 00000000 00000000 00000100 01000001
    $
    Применение битовых флагов и поразрядной логики – эффективный и распространенный прием. Поскольку каждый флаг является чис- лом, в котором может быть установлен в 1 только один определенный бит, выполнение поразрядного ИЛИ над такими величинами равно- сильно их сложению. В fcntl_flags.c 1 + 1024 + 64 = 1089. Разумеется это возможно, только если каждый флаг использует только один определенный бит.
    0x282 Права доступа к файлам
    Если режим доступа в функции open() определяется флагом O_CREAT, ну- жен дополнительный аргумент, задающий права доступа к создавае- мому файлу. В этом аргументе участвуют флаги, определяемые в sys/
    stat.h, которые можно комбинировать с помощью поразрядного ИЛИ.
    S_IRUSR
    Право чтения файла предоставляется пользователю (владельцу).
    S_IWUSR
    Право записи файла предоставляется пользователю (владельцу).
    S_IXUSR
    Право исполнения файла предоставляется пользователю (вла- дельцу).

    0x280 Опираясь на основы
    105
    S_IRGRP
    Право чтения файла предоставляется группе.
    S_IWGRP
    Право записи в файл предоставляется группе.
    S_IXGRP
    Право выполнения файла предоставляется группе.
    S_IROTH
    Право чтения файла предоставляется всем (от other).
    S_IWOTH
    Право записи в файл предоставляется всем.
    S_IXOTH
    Право исполнения файла предоставляется всем.
    Тому, кто знаком с системой прав доступа к файлам в UNIX, эти фла- ги должны быть абсолютно понятны. Если они не понятны, рассмотрим вкратце права доступа к файлам в UNIX.
    У каждого файла есть владелец и группа. Увидеть их можно с помощью команды ls -l.
    reader@hacking:/booksrc $ ls -l /etc/passwd simplenote*
    -rw-r--r-- 1 root root 1424 2007-09-06 09:45 /etc/passwd
    -rwxr-xr-x 1 reader reader 8457 2007-09-07 02:51 simplenote
    -rw------- 1 reader reader 1872 2007-09-07 02:51 simplenote.c reader@hacking:/booksrc $
    Владелец файла simplenote* – root, группа – тоже root. У других двух файлов simplenote владелец – reader и группа – reader.
    Права чтения, записи и исполнения можно включать и выключать в трех разных полях для пользователя, для группы и для всех. Права для пользователя задают, что может делать с файлом его владелец (чи- тать, писать и/или исполнять), права для группы задают, что могут де- лать пользователи, принадлежащие к этой группе, а права для всех за- дают, что могут делать все остальные.
    Эти поля отображены и в начале вывода команды ls -l. Сначала идут права на чтение/запись/исполнение для владельца (r – право на чтение, w
    – право на запись, x – право на исполнение, отсутствие права обозна- чено дефисом -). Следующие три символа – права группы, последние три – права для всех остальных. В приведенном примере у програм- мы simplenote включены все три права доступа для владельца. Каждо- му праву соответствует битовый флаг; 4 (двоичное 100) – для чтения,
    2 (двоичное 010) – для записи, 1 (двоичное 001) – для исполнения. По- скольку бит для каждого значения уникален, поразрядное ИЛИ дает такой же результат, как сложение этих чисел. Значения можно склады- вать, чтобы задавать права доступа владельца, группы и всех осталь- ных в команде chmod.
    reader@hacking:/booksrc $ chmod 731 simplenote.c reader@hacking:/booksrc $ ls -l simplenote.c
    -rwx-wx--x 1 reader reader 1826 2007-09-07 02:51 simplenote.c reader@hacking:/booksrc $ chmod ugo-wx simplenote.c reader@hacking:/booksrc $ ls -l simplenote.c
    -r-------- 1 reader reader 1826 2007-09-07 02:51 simplenote.c reader@hacking:/booksrc $ chmod u+w simplenote.c

    106
    0x200 Программирование reader@hacking:/booksrc $ ls -l simplenote.c
    -rw------- 1 reader reader 1826 2007-09-07 02:51 simplenote.c reader@hacking:/booksrc $
    Первая команда (chmod 731) дает владельцу права чтения, записи и ис- полнения, поскольку первое число 7 (4 + 2 + 1), группе – права запи- си и исполнения, поскольку второе число 3 (2 + 1), а всем остальным – только исполнения, потому что третье число 1. С помощью chmod мож- но также добавлять и отнимать права. В следующей команде chmod ар- гумент ugo-wx означает отнять права записи и исполнения у
    владельца,
    группы и всех остальных. В последней команде chmod u+w владельцу до- бавляется право записи.
    В программе simplenote дополнительным аргументом прав доступа для функции open() является S_IRUSR|S_IWUSR, вследствие чего права доступа к создаваемому файлу /tmp/notes будут ограничены правами на чтение и запись, предоставленными только его владельцу.
    reader@hacking:/booksrc $ ls -l /tmp/notes
    -rw------- 1 reader reader 36 2007-09-07 02:52 /tmp/notes reader@hacking:/booksrc $
    0x283 Идентификатор пользователя
    У каждого пользователя UNIX-системы есть уникальный числовой идентификатор (user ID, UID). Идентификатор пользователя можно узнать с помощью команды id.
    reader@hacking:/booksrc $ id reader
    uid=999(reader)
    gid=999(reader)
    groups=999(reader),4(adm),20(dialout),24(cdrom),25(floppy),29(audio),
    30(dip),44(video),46(plugdev),104(scanner),112(netdev),113(lpadmin),
    115(powerdev),117(admin)
    reader@hacking:/booksrc $ id matrix uid=500(matrix) gid=500(matrix) groups=500(matrix)
    reader@hacking:/booksrc $ id root uid=0(root) gid=0(root) groups=0(root)
    reader@hacking:/booksrc $
    Пользователь root с идентификатором 0 представляет собой админи- стратора системы, обладающего полным доступом к ней. Команда su по- зволяет предстать перед системой другим пользователем, и если ее вы- полняет root, вводить пароль не нужно. Команда sudo позволяет выпол- нить от имени root отдельную команду. На загрузочном диске
    1
    коман- да sudo для простоты настроена на выполнение без ввода пароля. Эти команды дают простой способ переключения между пользователями.
    reader@hacking:/booksrc $ sudo su jose
    1
    Который можно скачать по адресу www.symbol.ru/library/hacking-2ed. –
    Прим. ред.

    0x280 Опираясь на основы
    107
    jose@hacking:/home/reader/booksrc $ id uid=501(jose) gid=501(jose) groups=501(jose)
    jose@hacking:/home/reader/booksrc $
    Пользователь jose может запустить программу simplenote, которая бу- дет выполняться с его кодом идентификации, но у нее не будет прав до- ступа к файлу /tmp/notes. Владельцем этого файла является пользова- тель reader, и только у него есть право его чтения и записи .
    jose@hacking:/home/reader/booksrc $ ls -l /tmp/notes
    -rw------- 1 reader reader 36 2007-09-07 05:20 /tmp/notes jose@hacking:/home/reader/booksrc $ ./simplenote “a note for jose”
    [DEBUG] buffer @ 0x804a008: ‘a note for jose’
    [DEBUG] datafile @ 0x804a070: ‘/tmp/notes’
    [!!] Fatal Error in main() while opening file: Permission denied jose@hacking:/home/reader/booksrc $ cat /tmp/notes cat: /tmp/notes: Permission denied jose@hacking:/home/reader/booksrc $ exit exit reader@hacking:/booksrc $
    Все прекрасно, если reader – единственный пользователь программы
    simplenote; однако очень часто нескольким пользователям требуется до- ступ к определенным частям одного и того же файла. Например, в фай- ле /etc/passwd хранятся данные об учетных записях всех пользовате- лей системы, включая информацию о том, какая оболочка запускается для каждого пользователя по умолчанию. Команда chsh дает возмож- ность каждому пользователю изменить свою оболочку по умолчанию.
    Эта программа должна внести изменения в файл /etc/passwd, но только в ту строку, которая относится к учетной записи данного пользователя.
    В UNIX эта проблема решается с помощью права доступа setuid (set user ID
    ). Этот дополнительный бит в правах доступа можно установить с помощью команды chmod. При запуске программы с этим флагом она выполняется с идентификатором пользователя, который является вла- дельцем файла.
    reader@hacking:/booksrc $ which chsh
    /usr/bin/chsh reader@hacking:/booksrc $ ls -l /usr/bin/chsh /etc/passwd
    -rw-r--r-- 1 root root 1424 2007-09-06 21:05 /etc/passwd
    -rwsr-xr-x 1 root root 23920 2006-12-19 20:35 /usr/bin/chsh reader@hacking:/booksrc $
    У программы chsh установлен флаг setuid, о чем свидетельствует сим- вол s в правах доступа. Так как владельцем файла является root и уста- новлен бит setuid, при запуске программы любым пользователем она будет выполняться от имени root.
    Владельцем файла /etc/passwd, в который должна сделать запись про- грамма chsh, также является root, и разрешение на запись предоставле- но только владельцу. Программа chsh устроена так, что разрешает за-

    108
    0x200 Программирование пись только той строки /etc/passwd, которая относится к пользовате- лю, запустившему программу, даже если реально она выполняется от имени root. Таким образом, у работающей программы есть обычный
    (действительный) ID и эффективный ID. Эти идентификаторы можно получить с помощью функций getuid() и geteuid() соответственно, как показано в программе uid_demo.c.
    uid_demo.c
    #include
    int main() {
    printf(“real uid: %d\n”, getuid());
    printf(“effective uid: %d\n”, geteuid());
    }
    Результат компиляции и выполнения uid_demo.c:
    reader@hacking:/booksrc $ gcc -o uid_demo uid_demo.c reader@hacking:/booksrc $ ls -l uid_demo
    -rwxr-xr-x 1 reader reader 6825 2007-09-07 05:32 uid_demo reader@hacking:/booksrc $ ./uid_demo real uid: 999
    effective uid: 999
    reader@hacking:/booksrc $ sudo chown root:root ./uid_demo reader@hacking:/booksrc $ ls -l uid_demo
    -rwxr-xr-x 1 root root 6825 2007-09-07 05:32 uid_demo reader@hacking:/booksrc $ ./uid_demo real uid: 999
    effective uid: 999
    reader@hacking:/booksrc $
    Вывод программы uid_demo показывает, что после выполнения про - граммы оба ID равны 999, поскольку 999 – это идентификатор поль- зователя для reader. Далее команда sudo используется с командой chown, чтобы изменить владельца и группу uid_demo на root. Программу по- прежнему можно запустить, потому что у нее есть права исполнения для всех остальных, и она покажет, что оба ID остались равными 999, потому что это по-прежнему идентификатор пользователя.
    reader@hacking:/booksrc $ chmod u+s ./uid_demo chmod: changing permissions of `./uid_demo’: Operation not permitted reader@hacking:/booksrc $ sudo chmod u+s ./uid_demo reader@hacking:/booksrc $ ls -l uid_demo
    -rwsr-xr-x 1 root root 6825 2007-09-07 05:32 uid_demo reader@hacking:/booksrc $ ./uid_demo real uid: 999
    effective uid: 0
    reader@hacking:/booksrc $
    Так как теперь владельцем программы является root, нужно с помо- щью sudo изменить права доступа к ней. Команда chmod u+s включа- ет флаг setuid, что видно по результату выполнения ls -l. Если теперь

    0x280 Опираясь на основы
    1   ...   8   9   10   11   12   13   14   15   ...   51


    написать администратору сайта