Трудности Понимание Форматирования Строка Эксплуатация - PullRequest
0 голосов
/ 15 апреля 2020

Я читаю книгу «Взлом: Искусство эксплуатации, 2-е издание», и я нахожусь в главе уязвимости форматной строки. Я прочитал эту главу несколько раз, но я не могу ее четко понять, даже если немного погуглил.

Итак, в книге есть этот уязвимый код:

 char text[1024];
...
 strcpy(text, argv[1]);
 printf("The right way to print user-controlled input:\n");
 printf("%s", text);
 printf("\nThe wrong way to print user-controlled input:\n");
 printf(text);

Затем после компиляции ,

reader@hacking:~/booksrc $ ./fmt_vuln $(perl -e 'print "%08x."x40')
The right way to print user-controlled input:
%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.
%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.
%08x.%08x.
The wrong way to print user-controlled input:
bffff320.b7fe75fc.00000000.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.30252
e78.252e7838.2e783830.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.30252e78.2
52e7838.2e783830.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.30252e78.252e78
38.2e783830.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.

Кажется, что байты 0x25, 0x30, 0x38, 0x78 и 0x2e повторяются много.

reader@hacking:~/booksrc $ printf "\x25\x30\x38\x78\x2e\n"
%08x.

Во-первых, почему это значение повторяется?

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

Но мне кажется, что это противоречит тому, что он ранее написал, и способу организации кадров стека

Когда вызывается эта функция printf () (как и для любой функции), аргументы передаются в стек в обратном порядке.

Итак, не должна ли строка форматирования иметь меньший адрес памяти, поскольку она является первым аргументом? И где хранится строка формата?

reader@hacking:~/booksrc $ ./fmt_vuln AAAA%08x.%08x.%08x.%08x
The right way to print user-controlled input:
AAAA%08x.%08x.%08x.%08x
The wrong way to print user-controlled input:
AAAAbffff3d0.b7fe75fc.00000000.41414141

Здесь снова, почему AAAA повторяется в 41414141. Из того, что я понимаю, функция printf сначала печатает AAAA, затем, когда она видит первый %08x, она получает значение из адреса памяти в предыдущем кадре стека, затем делает то же самое со вторым %08x таким образом, значение второго находится в адресе памяти выше, чем первый, и, наконец, возвращается к значению AAAA, расположенному в нижнем адресе памяти, в кадре стека функции printf.

Я отлаживал первый пример с $(perl -e 'print "%08x."x40') в качестве аргумента. Я запускаю: Linux 5.3.0-40-generi c, 18.04.1-Ubuntu, x86_64

(gdb) run $(perl -e 'print "%08x." x 40')
Starting program: /home/kuro/fmt_vuln $(perl -e 'print "%08x." x 40')
The right way to print user-controlled input:
%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.
The wrong way to print user-controlled input:
07a51260.4b3eb8c0.4b10e154.00000000.4b16c3a0.9d357fc8.9d357b10.78383025.30252e78.2e783830.3830252e.252e7838.78383025.30252e78.2e783830.3830252e.252e7838.78383025.30252e78.2e783830.3830252e.252e7838.78383025.30252e78.2e783830.3830252e.252e7838.78383025.30252e78.2e783830.3830252e.252e7838.4b618d00.4b5fd000.00000000.9d357c80.00000000.00000000.00000000.4b3ef6f0.

Breakpoint 1, main (argc=2, argv=0x7ffd9d357fc8) at fmt_vuln.c:19
19      printf("[*] test_val @ 0x%08x = %d 0x%08x\n", &test_val, test_val, test_val);
(gdb) x/-100xw $rsp
0x7ffd9d357940: 0x00000400  0x00000000  0x4b07c1aa  0x00007fb8
0x7ffd9d357950: 0x00000016  0x00000000  0x00000003  0x00000000
0x7ffd9d357960: 0x00000001  0x00000000  0x00002190  0x000003e8
0x7ffd9d357970: 0x00000005  0x00000000  0x00008800  0x00000000
0x7ffd9d357980: 0x00000000  0x00000000  0x00000400  0x00000000
0x7ffd9d357990: 0x00000000  0x00000000  0x5e970730  0x00000000
0x7ffd9d3579a0: 0x65336234  0x30663666  0x90890300  0x79e57be9
0x7ffd9d3579b0: 0x1cd79dbf  0x00000000  0x00000000  0x00000000
0x7ffd9d3579c0: 0x05cec660  0x000055ef  0x9d357fc0  0x00007ffd
0x7ffd9d3579d0: 0x00000000  0x00000000  0x00000000  0x00000000
0x7ffd9d3579e0: 0x9d357ee0  0x00007ffd  0x4b062f26  0x00007fb8
0x7ffd9d3579f0: 0x00000030  0x00000030  0x9d357be8  0x00007ffd
0x7ffd9d357a00: 0x9d357a10  0x00007ffd  0x90890300  0x79e57be9
0x7ffd9d357a10: 0x4b3ea760  0x00007fb8  0x07a51260  0x000055ef
0x7ffd9d357a20: 0x4b3eb8c0  0x00007fb8  0x4b0891bd  0x00007fb8
0x7ffd9d357a30: 0x00000000  0x00000000  0x4b3ea760  0x00007fb8
0x7ffd9d357a40: 0x00000d68  0x00000000  0x00000169  0x00000000
0x7ffd9d357a50: 0x07a51260  0x000055ef  0x4b08af51  0x00007fb8
0x7ffd9d357a60: 0x4b3e62a0  0x00007fb8  0x4b3ea760  0x00007fb8
0x7ffd9d357a70: 0x0000000a  0x00000000  0x05cec660  0x000055ef
0x7ffd9d357a80: 0x9d357fc0  0x00007ffd  0x00000000  0x00000000
0x7ffd9d357a90: 0x00000000  0x00000000  0x4b08b403  0x00007fb8
0x7ffd9d357aa0: 0x4b3ea760  0x00007fb8  0x9d357ee0  0x00007ffd
0x7ffd9d357ab0: 0x05cec660  0x000055ef  0x4b0808f5  0x00007fb8
0x7ffd9d357ac0: 0x00000000  0x00000000  0x05cec824  0x000055ef
(gdb) x/100xw $rsp
0x7ffd9d357ad0: 0x9d357fc8  0x00007ffd  0x9d357b10  0x00000002
0x7ffd9d357ae0: 0x78383025  0x3830252e  0x30252e78  0x252e7838
0x7ffd9d357af0: 0x2e783830  0x78383025  0x3830252e  0x30252e78
0x7ffd9d357b00: 0x252e7838  0x2e783830  0x78383025  0x3830252e
0x7ffd9d357b10: 0x30252e78  0x252e7838  0x2e783830  0x78383025
0x7ffd9d357b20: 0x3830252e  0x30252e78  0x252e7838  0x2e783830
0x7ffd9d357b30: 0x78383025  0x3830252e  0x30252e78  0x252e7838
0x7ffd9d357b40: 0x2e783830  0x78383025  0x3830252e  0x30252e78
0x7ffd9d357b50: 0x252e7838  0x2e783830  0x78383025  0x3830252e
0x7ffd9d357b60: 0x30252e78  0x252e7838  0x2e783830  0x78383025
0x7ffd9d357b70: 0x3830252e  0x30252e78  0x252e7838  0x2e783830
0x7ffd9d357b80: 0x78383025  0x3830252e  0x30252e78  0x252e7838
0x7ffd9d357b90: 0x2e783830  0x78383025  0x3830252e  0x30252e78
0x7ffd9d357ba0: 0x252e7838  0x2e783830  0x4b618d00  0x00007fb8
0x7ffd9d357bb0: 0x4b5fd000  0x00007fb8  0x00000000  0x00000000
0x7ffd9d357bc0: 0x9d357c80  0x00007ffd  0x00000000  0x00000000
0x7ffd9d357bd0: 0x00000000  0x00000000  0x00000000  0x00000000
0x7ffd9d357be0: 0x4b3ef6f0  0x00007fb8  0x4b6184c8  0x00007fb8
0x7ffd9d357bf0: 0x9d357c80  0x00007ffd  0x4b3ef000  0x00007fb8
0x7ffd9d357c00: 0x4b3ef914  0x00007fb8  0x4b3ef3c0  0x00007fb8
0x7ffd9d357c10: 0x4b617048  0x00007fb8  0x00000000  0x00000000
0x7ffd9d357c20: 0x00000000  0x00000000  0x4b6179f0  0x00007fb8
0x7ffd9d357c30: 0x4b0030e8  0x00007fb8  0x00000000  0x00000000
0x7ffd9d357c40: 0x4b3efa00  0x00007fb8  0x00000480  0x00000000
0x7ffd9d357c50: 0x00000027  0x00000000  0x00000000  0x00000000

Значения, которые появляются перед "% 08x". в неправильном выводе отображаются в более низких адресах, чем «% 08x». ценности. Почему? Предполагается, что строка формата находится на вершине стека.

Значения, которые появляются после «% 08x». значения в выводе Неверный путь отображаются в более высоких адресах, чем «% 08x». ценности. Итак, в предыдущем стеке.

Почему это так? Разве вывод не должен начинаться со значения строки формата или после?

Кроме того, в книге он не печатает значения после «% 08x». ценности. Но некоторые напечатаны в моем случае. И некоторые значения в выводе даже не фигурируют в стеке, как 4b16c3a0 .

1 Ответ

3 голосов
/ 15 апреля 2020

Я должен рекомендовать против того, что вы делаете. Вы сосредотачиваетесь на уязвимостях в C без четкого понимания самого языка. Это упражнение в разочаровании. В качестве доказательства я предлагаю, чтобы на каждый вопрос, который вы ставите об упражнении, отвечали понимание printf (3), а не стековые уязвимости.

Вывод вашей строки perl (содержимое argv[1]) начинается с %08x.%08x.%08x.%08x.%08x. Это строка формата. Каждый %08x ищет дополнительный аргумент printf, целое число, которое нужно напечатать в шестнадцатеричном представлении. Как правило, вы можете сделать что-то вроде

int a = 'B';
printf( "%02x\n", a );

, который производит 42 намного быстрее, чем компьютер из Автостопом по Галактике .

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

В "хорошем" случае строка формата - "%s", объявляя один аргумент типа строки, который вы указали. Это работает намного лучше, да.

Большинство компиляторов в настоящее время уделяют особое внимание printf. Они могут выдавать предупреждения, если строка формата не является константой времени компиляции, и они могут проверить, что каждый аргумент имеет правильный тип для соответствующего спецификатора формата. Целая глава в вашей книге, таким образом, может быть спорным, просто используя возможности компилятора и обращая внимание на его диагностику.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...