Подтвердить что ты не робот

Переполнение буфера работает в gdb, но не без него

Я на CentOS 6.4 32 бит и пытаюсь вызвать переполнение буфера в программе. В GDB это работает. Вот результат:

[[email protected] bufferoverflow]# gdb stack
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-60.el6_4.1)
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /root/bufferoverflow/stack...done.
(gdb) r
Starting program: /root/bufferoverflow/stack
process 6003 is executing new program: /bin/bash
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.107.el6_4.2.i686
sh-4.1#

Однако, когда я запускаю стек программы только по отдельности, это вызывает ошибки seg. Почему это может быть?

4b9b3361

Ответ 1

Разработка Exploit может привести к серьезным головным болям, если вы недостаточно учитываете факторы, которые вводят недетерминированность в процесс отладки. В частности, адреса стека в отладчике могут не соответствовать адресам во время нормального выполнения. Этот артефакт происходит из-за того, что загрузчик операционной системы помещает как переменные среды, так и параметры программы перед началом стека:

Process layout

Поскольку ваша уязвимая программа не принимает никаких аргументов, переменные среды, вероятно, являются виновниками. Убедитесь, что они одинаковы в обоих вызовах, в оболочке и в отладчике. С этой целью вы можете обернуть свой вызов в env:

env - /path/to/stack

И с отладчиком:

env - gdb /path/to/stack
($) show env
LINES=24
COLUMNS=80

В приведенном выше примере есть две переменные среды, заданные gdb, которые вы можете дополнительно отключить:

unset env LINES
unset env COLUMNS

Теперь show env должен возвращать пустой список. На этом этапе вы можете начать процесс отладки, чтобы найти абсолютный адрес стека, который вы планируете перейти (например, 0xbffffa8b), и зафиксировать его в своем эксплоите.

Еще одна тонкая, но важная деталь: есть разница между вызовами ./stack и /path/to/stack: поскольку argv[0] содержит программу точно так, как вы ее вызывали, вам нужно обеспечить равные строки вызова. Поэтому я использовал /path/to/stack в приведенных выше примерах, а не только ./stack и gdb stack.

При изучении использования уязвимостей безопасности памяти я рекомендую использовать нижеприведенную программу-оболочку, которая делает тяжелую работу и обеспечивает равные смещения стека:

$ invoke stack         # just call the executable
$ invoke -d stack      # run the executable in GDB

Вот script:

#!/bin/sh

while getopts "dte:h?" opt ; do
  case "$opt" in
    h|\?)
      printf "usage: %s -e KEY=VALUE prog [args...]\n" $(basename $0)
      exit 0
      ;;
    t)
      tty=1
      gdb=1
      ;;
    d)
      gdb=1
      ;;
    e)
      env=$OPTARG
      ;;
  esac
done

shift $(expr $OPTIND - 1)
prog=$(readlink -f $1)
shift
if [ -n "$gdb" ] ; then
  if [ -n "$tty" ]; then
    touch /tmp/gdb-debug-pty
    exec env - $env TERM=screen PWD=$PWD gdb -tty /tmp/gdb-debug-pty --args $prog "[email protected]"
  else
    exec env - $env TERM=screen PWD=$PWD gdb --args $prog "[email protected]"
  fi
else
  exec env - $env TERM=screen PWD=$PWD $prog "[email protected]"
fi

Ответ 2

Причина, по которой ваш переполнение буфера работает под gdb и segfaults, в противном случае заключается в том, что gdb отключает рандомизацию размещения адресного пространства. Я считаю, что это было включено по умолчанию в gdb версии 7.

Вы можете проверить это, выполнив следующую команду:

show disable-randomization

И установите его с помощью

set disable-randomization on

или

set disable-randomization off

Ответ 3

Адрес указателя кадра стека при запуске кода в gdb отличается от обычного запуска. Таким образом, вы можете повредить обратный адрес прямо в режиме gdb, но он может не работать при обычном режиме. Основная причина этого - переменные среды различаются между двумя ситуациями.

Поскольку это всего лишь демонстрация, вы можете изменить код жертвы и распечатать адрес буфера. Затем измените адрес возврата на смещение + адрес буфера.

В действительности, однако, вам нужно угадать обратный адрес добавить NOP sled до вашего вредоносного кода. И вы можете угадать несколько раз, чтобы получить правильный адрес, так как ваше предположение может быть неправильным.

Надеюсь, это поможет вам.

Ответ 4

Я попробовал решение, принятое здесь, и оно не работает (для меня). Я знал, что gdb добавил переменные среды, и по этой причине адрес стека не соответствует, но даже удаляя эти переменные, я не могу работать с эксплойтом без gdb (я также попробовал script, опубликованный в принятом решении).

Но поиск в Интернете я нашел для меня другие script: https://github.com/hellman/fixenv/blob/master/r.sh

Использование в основном такое же, что script в принятом решении:

  • r.sh gdb./program [args] для запуска программы в gdb
  • r.sh./program [args] для запуска программы без gdb

И этот script работает для меня.

Ответ 5

Вот простой способ запуска вашей программы с одинаковыми стеками в терминале и в gdb:

Сначала убедитесь, что ваша программа скомпилирована без защиты стека,

gcc -m32 -fno-stack-protector -z execstack -o shelltest shelltest.c -g

и ASLR отключен:

echo 0 > /proc/sys/kernel/randomize_va_space

ПРИМЕЧАНИЕ: значение по умолчанию на моей машине равно 2, обратите внимание на ваш, прежде чем изменять это.

Затем запустите свою программу так (терминал и gdb соответственно):

env -i PWD="/root/Documents/MSec" SHELL="/bin/bash" SHLVL=0 /root/Documents/MSec/shelltest
env -i PWD="/root/Documents/MSec" SHELL="/bin/bash" SHLVL=0 gdb /root/Documents/MSec/shelltest

Внутри gdb убедитесь, что unset LINES и COLUMNS.

Примечание. Я получил эти переменные среды, играя с программой .

Эти два прогона дадут вам одинаковые указатели на вершину стека, поэтому нет необходимости в удаленных script shenanigans, если вы пытаетесь использовать бинарный файл удаленно.

Ответ 6

Одна из главных вещей, которые gdb делает, что не происходит вне gdb, - это нулевая память. Скорее всего, где-то в коде вы не инициализируете свою память, а получаете значения мусора. Gdb автоматически очищает всю память, которую вы выделяете, скрывая эти типы ошибок.

Например: следующее должно работать в gdb, но не за его пределами:

int main(){
    int **temp = (int**)malloc(2*sizeof(int*)); //temp[0] and temp[1] are NULL in gdb, but not outside
    if (temp[0] != NULL){
        *temp[0] = 1; //segfault outside of gdb
    }
    return 0;
}

Попробуйте запустить программу под valgrind, чтобы узнать, может ли она обнаружить эту проблему.

Ответ 7

Я работаю на CentOS 6.4 32 бит и пытаюсь вызвать переполнение буфера в программе... Однако, когда я запускаю стек программ только сам по себе, это seg faults.

Вы также должны убедиться, что FORTIFY_SOURCE не влияет на ваши результаты. Ошибка seg звучит, как FORTIFY_SOURCE, может быть проблемой, потому что FORTIFY_SOURCE будет вставлять "безопасные" вызовы функций для защиты от некоторых типов переполнений буфера. Если компилятор может определить размеры буфера назначения, то размер проверяется и abort() вызывается с нарушением (т.е. Ваш сбой).

Чтобы отключить FORTIFY_SOURCE для тестирования, вы должны скомпилировать с помощью -U_FORTIFY_SOURCE или -D_FORTIFY_SOURCE=0.