2013-02-09 2 views
9

Я узнаю о переполнении буфера и пытаюсь его создать. У меня есть этот код:Компиляция C для переполнения буфера

#include <stdio.h> 

char *secret = "password"; 

void go_shell() { 
    char *shell = "/bin/sh"; 
    char *cmd[] = { "/bin/sh", 0 }; 
    setreuid(0); 
    execve(shell,cmd,0); 
} 

int authorize() { 
    char password[64]; 
    printf("Enter Password: "); 
    gets(password); 
    if (!strcmp(password,secret)) { 
     return 1; 
    } 
    else { 
     return 0; 
    } 
} 

int main() { 
    if (authorize()) { 
     printf("login successful\n"); 
     go_shell(); 
    } else { 
     printf("Incorrect password\n"); 
    } 
    return 0; 
} 

Я компилировать это с GCC, а затем запустить его в БГД

вхожу около 100 «A» S в качестве пароля и аварийное завершение работы программы.

Проблема нет регистра не переписывается в 0x4141414141414141

Я гугле это и добавил -fno-stack-protector флаг gcc, который позволил КПБ быть перезаписаны в 0x4141414141414141, но ничего другого.

Мне было интересно, есть ли способ скомпилировать код, чтобы RIP можно было перезаписать.

+0

Вы используете Linux? Думаю, вам также нужно установить там какой-то флаг. – nhahtdh

+0

Использование Mac OSX. Любая идея, что такое флаг? – carloabelli

+0

Я не знаю о Mac OSX - вероятно, будет сильно отличаться от Ubuntu (извините, я на самом деле сделал это на Ubuntu, а не на Linux). – nhahtdh

ответ

3

Ваш код уже делает то, что вы хотите, если вы скомпилируете -fno-stack-protector. Причина, по которой вы не видите RIP со значением 0x4141414141414141 в GDB, заключается в том, что общая ошибка защиты возникает до обновления RIP. (Если возникает ошибка страницы, обработчик GPF обычно загружает страницу из свопа и возобновляет выполнение, начиная с команды с ошибкой.)

+0

Спасибо за помощь, но мне было интересно, есть ли способ отключить этот GPF, чтобы RIP мог быть установлен в' 0x4141414141414141', потому что это то, что происходит в учебнике, которое я использую. – carloabelli

+0

@ cabellicar123 Вы не можете избежать GPF, если вы не создаете исполняемую страницу по этому адресу. Просто приступайте к обучению. Вероятно, следующим шагом будет предоставление специально созданного пароля, который заставит код перейти к действительному адресу. – nwellnhof

+0

Большое спасибо за помощь! – carloabelli

1

Причина, по которой вы получаете сбой EIP 0 × 41414141 на x32, заключается в том, что когда программа появляется ранее сохраненное значение EIP из стека и обратно в EIP, CPU затем пытается выполнить команду по адресу памяти 0 × 41414141, которая вызывает segfault. (он должен получить страницу до начала курса)

Теперь, когда выполнение программы x64, когда предыдущее сохраненное значение RIP возвращается в регистр RIP, ядро ​​затем пытается выполнить инструкции по адресу памяти 0 × 4141414141414141. Во-первых, из-за обращения к канонической форме биты с 48 по 63 любого виртуального адреса должны быть копиями бит 47 (способом, близким к расширению знака), или процессор вызывает исключение. Если это не проблема, ядро ​​выполняет дополнительные проверки перед вызовом обработчика ошибок страницы, так как максимальный адрес пространства пользователя равен 0x00007FFFFFFFFFF.

Чтобы понять, в архитектуре x32 адрес передается без какой-либо «проверки» на обработчик ошибок страницы, который пытается загрузить страницу, которая запускает ядро ​​для отправки segfault программы, но x64 не доходит до этого.

Проверьте это, перезапишите RIP с помощью 0 × 0000414141414141, и вы увидите, что ожидаемое значение помещается в RIP, поскольку предварительные кадры передаются с помощью ядра, а затем обработчик ошибок страницы вызывается, как и случай x32 (что, конечно, тогда приводит к сбою программы).

Смежные вопросы