Как отключить патч FORTIFY_SOURCE, используя ошибку строки формата

Этот вопрос относится к: Панегирик для строк формата от phrack (http://www.phrack.org/issues.html?issue=67&id=9)

//File: test.c
//gcc -D_FORTIFY_SOURCE=2 -O2
int main(){
  char buf[256];
  fgets(buf, sizeof(buf), stdin);
  printf(buf);
}

Я не понимаю в их статье, как предоставление строки fmt, например %1$*269168516$, может отключить бит _IO_FLAGS2_FORTIFY в структуре stdout FILE?

Это потому, что когда мы переполняем целочисленное смещение, args_type[offset] может указывать на любое место в памяти, и в частности на stdout->_flags2, чтобы установить его в 0?

Если да, то как мы можем узнать, что нам удалось его отключить? потому что, когда я пытаюсь использовать этот код, я не могу получить segfault, как указано в статье. (вариант компиляции: gcc -m32 -z execstack -fno-stack-protector -ggdb -O2 -D_FORTIFY_SOURCE=2 -o prog test.c)

(gdb) disas vprintf
Dump of assembler code for function vprintf:
   0xf7e9ed90 <+0>: push   %ebp
   0xf7e9ed91 <+1>: mov    %esp,%ebp
   0xf7e9ed93 <+3>: push   %ebx
   0xf7e9ed94 <+4>: sub    $0xc,%esp
   0xf7e9ed97 <+7>: mov    0xc(%ebp),%eax
   0xf7e9ed9a <+10>:    call   0xf7f6ac66
   0xf7e9ed9f <+15>:    add    $0x11b255,%ebx
   0xf7e9eda5 <+21>:    mov    %eax,0x8(%esp)
   0xf7e9eda9 <+25>:    mov    0x8(%ebp),%eax
   0xf7e9edac <+28>:    mov    %eax,0x4(%esp)
   0xf7e9edb0 <+32>:    mov    -0x7c(%ebx),%eax
   0xf7e9edb6 <+38>:    mov    (%eax),%eax
   0xf7e9edb8 <+40>:    mov    %eax,(%esp)
   0xf7e9edbb <+43>:    call   0xf7e99a60 <vfprintf>
   0xf7e9edc0 <+48>:    add    $0xc,%esp
   0xf7e9edc3 <+51>:    pop    %ebx
   0xf7e9edc4 <+52>:    pop    %ebp
   0xf7e9edc5 <+53>:    ret

person user3102158    schedule 07.03.2014    source источник


Ответы (1)


Это потому, что когда мы переполняем целочисленное смещение, args_type[offset] может указывать на любое место в памяти, и в частности на stdout->_flags2, чтобы установить его в 0?

Да.

Если да, то как мы можем узнать, что нам удалось его отключить?

Вы проверяете это, используя %n в строке формата. Если это не ошибка, то вы преуспели.

Я не могу получить segfault, как указано в статье

Если вы имеете в виду, что ввод %n не дает вам:

*** %n in writable segment detected ***
Aborted

Тогда у вас нет _FORTIFY_SOURCE для начала.

person Jester    schedule 07.03.2014
comment
Хорошо, это работает. Но я не понимаю, почему они говорят, что мы выберем какое-то нелепое назначение, например %1$*269168516$. Если он не падает, продолжайте увеличивать его примерно на 20000. Почему они хотят, чтобы он рухнул? И как мы можем найти правильный параметр ширины, потому что я пробовал числа выше того, что я использовал здесь, и немного ниже, и каждый раз я не получаю сообщение об ошибке? Это потому, что как только мы превысим определенный МАКСИМУМ, каждое значение выше будет указывать на stdout-›_flags2 ? (допустимы %1$*269168515$x, %1$*26916851888$x и т. д.) - person user3102158; 07.03.2014
comment
Сбой провоцируется для того, чтобы можно было легко найти инструкцию, выполняющую запись. Это еще не перезапись флага, поэтому важно только найти неверный адрес. Затем будет рассчитано правильное значение, зная значение в ecx во время сбоя. - person Jester; 07.03.2014
comment
вы имеете в виду, что мы хотим найти: stdout-›_flags2 |= _IO_FLAGS2_FORTIFY; ? Я не понимаю, как я могу получить сбой, я должен переборщить, пока я не получу сбой? - person user3102158; 07.03.2014
comment
Нет, он находит файл args_type[specs[cnt].width_arg] = PA_INT;. Вы также можете просто разобрать vfprintf в gdb и попытаться найти строку. - person Jester; 07.03.2014