Проблема в коде заключается в том, что длина len
, которая рассчитывается с использованием strlen()
, равна short
. Это означает, что это 16-битное значение. Поскольку strlen()
возвращает size_t
, что является 64-битным значением в моей системе x86_64, только 16 младших бит будут сохранены в переменной len
.
Итак, на первый взгляд вы можете отправить что-нибудь более чем 65 535 байтов, переполнить это short int
и сохранить только младшие 16 бит. Но есть еще одна проблема, которую стоит отметить. Переменная len
представляет собой короткое целое число со знаком . Это означает, что он хранит значения из [-32768,32767]
, тогда как size_t
является значением без знака. Поэтому, когда strlen()
возвращает свое значение, длины, для которых установлен максимальный бит (больше 32 767 байт), станут отрицательными числами.
Вот пример gdb
сеанса, иллюстрирующий это:
(gdb) break 22
Breakpoint 1 at 0x829: file challenge.c, line 22.
(gdb) run `ruby -e 'print("A"*32768)'`
Starting program: /home/josh/foo/challenge `ruby -e 'print("A"*32768)'`
Breakpoint 1, main (argc=2, argv=0x7fffffff6338) at challenge.c:22
22 if (type == 0x00b1c2d3) {
(gdb) p len
$1 = -32768
(gdb) x/64bx $rsp
0x7ffffffee260: 0x38 0x63 0xff 0xff 0xff 0x7f 0x00 0x00
0x7ffffffee268: 0x00 0x00 0x00 0x00 0x02 0x00 0x00 0x00
0x7ffffffee270: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7ffffffee278: 0x00 0x00 0x00 0x80 0xef 0xbe 0xad 0xde
0x7ffffffee280: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0x7ffffffee288: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0x7ffffffee290: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0x7ffffffee298: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
(gdb)
Посмотрите, как байты в 0x7ffffffee27a
равны 0x00 0x80
? Это от -32768 до short int
, поэтому длина воспринимается как отрицательная (намного меньше 32 700!).
Я также включил некоторую дополнительную информацию в дамп памяти, чтобы вы могли видеть, что поле type
немедленно следует за полем len
в памяти, за которым следует массив buf
(который содержит мой 32768 * 1030). * s!). Обратите внимание, что будут работать только определенные длины ввода - те, которые выглядят отрицательными или переполняются до значения менее 32 700 при усечении до 16 бит.
Это не решает всей проблемы, но, по крайней мере, должно дать вам хорошее начало для понимания того, что вы можете контролировать. Также обратите внимание, что есть данные над массивом buf
, например, где rbp
указывает, ваш сохраненный указатель возврата и т. Д. В зависимости от того, как вы это компилируете (например, с или без стековых канареек и т. Д.), Они могут по пути вам предстоит еще кое-что решить.