Привет. Это не статья, это такая маленькая нотатка по уязвимости форматных строк на 64 ричных системах.
на 64-ричных системах валидный адрес это 8 байт, из которых 2 нульбайта. То есть записать мы его через аргумент не можем. никак. зато, форматная строка берет данные со стека и работает со стеком непосредственно. если углубиться то форматная строка "смещает свой курсор" по стеку от начала буффера, с которым работает. чем больше %lx конструкций в ней будет - тем на дальшее значение на стеке направляется курсор. так вот, что бы положить валидный адрес на стек нам нужно класть его в конце конструкции с форматными строками (которые тоже занимают место на стеке). все данные (включая конструкции с форматной строкой) лягут на стек и разобьются на блоки по 8 байт. что бы записать что-либо куда-либо с помощью форматной строки мы должны применить спецификатор %ln (l - long = 8 байт, уточнитель размера спецификатора) на тот блок памяти стека, в котором лежит тот адрес, значение по которому мы хотим перезаписать. и перезапишется это значение - длинной строки.
буффер ограничен, а вот длину строки мы можем контролировать с помощью спецификатора %ld
к примеру %999999999ld увеличит значение записанное %ln в ячейку памяти по адресу, на который этот самый %ln и был применен.
Наглядно:
вот такая конструкция (пейлоад сверху) даёт мне :
вот такой вывод. я вижу что мои 7 спецификаторов разделенных дефисами дали мне вывод 7 блоков памяти со стека
я запускаю программу под дебагером заново, и смотрю значение 0x7fffffffe190 до входа в печатающую ф-ю:
вижу там буквы А с начала буффера. окей.
теперь я переделываю конструкцию пэйлоада:
и смотрю на значение этого же адреса памяти ПОСЛЕ того как вышел из печатающей ф-ции. как мы видим - оно равно 0x1f=31
добавляем размер строки с помощью %999llx- (не буффера, а самой строки внутри логики libc) и видим как сменилось значение после перезаписи
*%llx - в данном случае ll определяет тип данных long long. это не принципиально. принципиально оличие просто %d (4 байта) от %ld (8 байт)
вот до печатающей ф-ции:
и вот после:
как видите мы можем ее контроллировать. Однако, для записи 64ричного адреса понадобится очень много времени. так как каждый символ будет отпечатан.
на этом всё.
на 64-ричных системах валидный адрес это 8 байт, из которых 2 нульбайта. То есть записать мы его через аргумент не можем. никак. зато, форматная строка берет данные со стека и работает со стеком непосредственно. если углубиться то форматная строка "смещает свой курсор" по стеку от начала буффера, с которым работает. чем больше %lx конструкций в ней будет - тем на дальшее значение на стеке направляется курсор. так вот, что бы положить валидный адрес на стек нам нужно класть его в конце конструкции с форматными строками (которые тоже занимают место на стеке). все данные (включая конструкции с форматной строкой) лягут на стек и разобьются на блоки по 8 байт. что бы записать что-либо куда-либо с помощью форматной строки мы должны применить спецификатор %ln (l - long = 8 байт, уточнитель размера спецификатора) на тот блок памяти стека, в котором лежит тот адрес, значение по которому мы хотим перезаписать. и перезапишется это значение - длинной строки.
буффер ограничен, а вот длину строки мы можем контролировать с помощью спецификатора %ld
к примеру %999999999ld увеличит значение записанное %ln в ячейку памяти по адресу, на который этот самый %ln и был применен.
Наглядно:
вот такая конструкция (пейлоад сверху) даёт мне :
вот такой вывод. я вижу что мои 7 спецификаторов разделенных дефисами дали мне вывод 7 блоков памяти со стека
я запускаю программу под дебагером заново, и смотрю значение 0x7fffffffe190 до входа в печатающую ф-ю:
вижу там буквы А с начала буффера. окей.
теперь я переделываю конструкцию пэйлоада:
и смотрю на значение этого же адреса памяти ПОСЛЕ того как вышел из печатающей ф-ции. как мы видим - оно равно 0x1f=31
добавляем размер строки с помощью %999llx- (не буффера, а самой строки внутри логики libc) и видим как сменилось значение после перезаписи
*%llx - в данном случае ll определяет тип данных long long. это не принципиально. принципиально оличие просто %d (4 байта) от %ld (8 байт)
вот до печатающей ф-ции:
и вот после:
как видите мы можем ее контроллировать. Однако, для записи 64ричного адреса понадобится очень много времени. так как каждый символ будет отпечатан.
на этом всё.
Последнее редактирование: