2014-11-16 4 views
0

Мне сложно с этим переполнением буфера. Код adm.c выглядит следующим образом:Переполнение буфера для перехода к отключенной функции

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

// define to allow administrative access, undef to restrict 
#undef ADMINISTRATIVE 
//#define ADMINISTRATIVE 

// function prototypes for "main.c" functions 

int main (int argc, char *argv[]); 
void list(void); 
void add(void); 
void quit(void); 
void delete(void); 
void deleteall(void); 
void normal(char *user); 
void administrative(char *nothing); 
void debug(char *nothing); 
void rot13(char *user, char *rot13pwd); 

typedef void (*menufunctype)(char *); 
typedef void (*userfunctype)(void); 
typedef void (*adminfunctype)(void); 

// jump table for non-administrative functions 
userfunctype userfunc[3] = {add, list, quit}; 

// jump table for administrative functions 
adminfunctype adminfunc[5] = {delete, deleteall, add, list, quit}; 


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

    menufunctype menufunc[3]={debug, administrative, normal}; 
    char rot13pwd[20]; 
    char user[20]; 
    char pwd[20]; 

    printf("Enter authorization code: "); fflush(stdout); 
    gets(pwd); 
    printf("Enter username or \"admin\" for admin functions: "); fflush(stdout); 
    gets(user); 

    // authenticate user 
    rot13(user, rot13pwd); 

    if (strcmp(pwd, rot13pwd)) { 
    puts("Authentication FAILED. Access denied.\n"); 
    exit(1); 
    } 

    // passed authentication, now display debug, normal or 
    // administrative menu. If administrative access is prohibited by 
    // compile-time "ADMINISTRATIVE" symbol, then don't allow admin 
    // under any circumstances. 

    if (! strncmp("debug", user, 5)) { 
    (*menufunc[0])(user); 
    } 
    else if (! strncmp("admin", user, 5)) { 
#if defined(ADMINISTRATIVE) 
    (*menufunc[1])(0); 
#else 
    puts("NO ADMINSTRATIVE ACCESS AVAILABLE--SEE YOUR SYSTEMS ADMINISTRATOR."); 
#endif 
    } 
    else { 
    (*menufunc[2])(user); 
    } 
} 

// menu for users with non-administrative access 
void normal(char *user) { 
    char buf[40]; 
    char normalaccessfile[20]=".normal_access"; 
    char choice[2]; 
    int ch; 

    // audit trail 
    sprintf(buf, "echo %s >> %s", user, normalaccessfile); 
    system(buf); 

    while (1) { 
    puts("\n##### MENU ######\n"); 
    puts("[0] Add a record"); 
    puts("[1] List all records"); 
    puts("[2] Exit\n"); 
    printf("Choice: "); fflush(stdout); 
    gets(choice); 

    // audit trail 
    sprintf(buf, "echo %c >> %s", choice[0], normalaccessfile); 
    system(buf); 

    ch = atoi(choice); 
    if (ch < 0 || ch > 2) { 
     puts("Invalid choice.\n"); 
    } 
    else { 
     (*userfunc[ch])(); 
    } 
    } 
} 

// menu for administrators 
void administrative(char *nothing) { 
    char buf[80]; 
    char administrativeaccessfile[80]=".admin_access"; 
    char choice[2]; 
    int ch; 

    while (1) { 
    puts("\n----- RESTRICTED ADMIN MENU -----\n"); 
    puts("[0] Delete a record"); 
    puts("[1] Delete all records"); 
    puts("[2] Add a record"); 
    puts("[3] List all records"); 
    puts("[4] Exit\n"); 

    printf("Choice: "); fflush(stdout); 
    gets(choice); 

    // audit trail 
    sprintf(buf, "echo %c >> %s", choice[0], administrativeaccessfile); 
    system(buf); 

    ch = atoi(choice); 
    if (ch < 0 || ch > 4) { 
     puts("Invalid choice.\n"); 
    } 
    else { 
     (*adminfunc[ch])(); 
    } 

    } 
} 


// menu for debug account 
void debug(char *nothing) { 

    // implement debug menu later... 

    // Marjorie: CHANGE THIS BEFORE RELEASE: MAJOR SECURITY HOLE! 
    system(nothing); 
} 


// USER FUNCTIONS 

// list all records 
void list() { 
    puts("*** LIST ***"); 
} 

// add a record 
void add() { 
    puts("*** ADD ***"); 
} 


// ADMINISTRATIVE FUNCTIONS 

// delete a record 
void delete() { 
    puts("*** ADMIN: DELETE ***"); 
} 

// delete all record 
void deleteall() { 
    puts("*** ADMIN: DELETE ALL ***"); 
} 


// UNRESTRICTED 

// quit 
void quit() { 
    puts("*** BYE ***"); 
    exit(1); 
} 


// ROT13 calculation 
void rot13(char *user, char *rot13pwd) { 
    int i; 
    char cap; 

    for (i=0; i < 20; i++) { 
    rot13pwd[i] = user[i]; 
    cap = rot13pwd[i] & 32; 
    rot13pwd[i] &= ~cap; 
    rot13pwd[i] = ((rot13pwd[i] >= 'A') && (rot13pwd[i] <= 'Z') ? 
      ((rot13pwd[i] - 'A' + 13) % 26 + 'A') : rot13pwd[i]) | cap; 
    } 
    rot13pwd[20]=0; 
} 

Проблема заключается в том, что я должен перейти к административной функции, но она отключена в коде. Я должен выяснить, как обходить #undef ADMINISTRATIVE и как-то войти в функцию. До сих пор я понял, пароль для пользователя с правами администратора, который nqzva и disasembled основной функции, но я бы потерял ... :(

(gdb) disas main 
Dump of assembler code for function main: 
    0x0000000000400784 <+0>: push %rbp 
    0x0000000000400785 <+1>: mov %rsp,%rbp 
    0x0000000000400788 <+4>: sub $0x90,%rsp 
    0x000000000040078f <+11>: mov %edi,-0x84(%rbp) 
    0x0000000000400795 <+17>: mov %rsi,-0x90(%rbp) 
    0x000000000040079c <+24>: movq $0x400b04,-0x20(%rbp) 
    0x00000000004007a4 <+32>: movq $0x4009cb,-0x18(%rbp) 
    0x00000000004007ac <+40>: movq $0x4008aa,-0x10(%rbp) 
    0x00000000004007b4 <+48>: mov $0x400d68,%eax 
    0x00000000004007b9 <+53>: mov %rax,%rdi 
    0x00000000004007bc <+56>: mov $0x0,%eax 
    0x00000000004007c1 <+61>: callq 0x4005f0 <[email protected]> 
    0x00000000004007c6 <+66>: mov 0x200c83(%rip),%rax  # 0x601450 <[email protected]@GLIBC_2.2.5> 
    0x00000000004007cd <+73>: mov %rax,%rdi 
    0x00000000004007d0 <+76>: callq 0x400690 <[email protected]> 
    0x00000000004007d5 <+81>: lea -0x80(%rbp),%rax 
    0x00000000004007d9 <+85>: mov %rax,%rdi 
    0x00000000004007dc <+88>: callq 0x400670 <[email protected]> 
    0x00000000004007e1 <+93>: mov $0x400d88,%eax 
    0x00000000004007e6 <+98>: mov %rax,%rdi 
    0x00000000004007e9 <+101>: mov $0x0,%eax 
---Type <return> to continue, or q <return> to quit--- 
    0x00000000004007ee <+106>: callq 0x4005f0 <[email protected]> 
    0x00000000004007f3 <+111>: mov 0x200c56(%rip),%rax  # 0x601450 <[email protected]@GLIBC_2.2.5> 
    0x00000000004007fa <+118>: mov %rax,%rdi 
    0x00000000004007fd <+121>: callq 0x400690 <[email protected]> 
    0x0000000000400802 <+126>: lea -0x60(%rbp),%rax 
    0x0000000000400806 <+130>: mov %rax,%rdi 
    0x0000000000400809 <+133>: callq 0x400670 <[email protected]> 
    0x000000000040080e <+138>: lea -0x40(%rbp),%rdx 
    0x0000000000400812 <+142>: lea -0x60(%rbp),%rax 
    0x0000000000400816 <+146>: mov %rdx,%rsi 
    0x0000000000400819 <+149>: mov %rax,%rid  
    0x000000000040081c <+152>: callq 0x400b76 <rot13> 
    0x0000000000400821 <+157>: lea -0x40(%rbp),%rdx 
    0x0000000000400825 <+161>: lea -0x80(%rbp),%rax 
    0x0000000000400829 <+165>: mov %rdx,%rsi 
    0x000000000040082c <+168>: mov %rax,%rdi 
    0x000000000040082f <+171>: callq 0x400680 <[email protected]> 
    0x0000000000400834 <+176>: test %eax,%eax 
    0x0000000000400836 <+178>: je  0x40084c <main+200> 
    0x0000000000400838 <+180>: mov $0x400db8,%edi 
    0x000000000040083d <+185>: callq 0x400600 <[email protected]> 
    0x0000000000400842 <+190>: mov $0x1,%edi 
---Type <return> to continue, or q <return> to quit--- 
    0x0000000000400847 <+195>: callq 0x400610 <[email protected]> 
    0x000000000040084c <+200>: lea -0x60(%rbp),%rax 
    0x0000000000400850 <+204>: mov $0x5,%edx 
    0x0000000000400855 <+209>: mov %rax,%rsi 
    0x0000000000400858 <+212>: mov $0x400de0,%edi 
    0x000000000040085d <+217>: callq 0x400620 <[email protected]> 
    0x0000000000400862 <+222>: test %eax,%eax 
    0x0000000000400864 <+224>: jne 0x400875 <main+241> 
    0x0000000000400866 <+226>: mov -0x20(%rbp),%rdx 
    0x000000000040086a <+230>: lea -0x60(%rbp),%rax 
    0x000000000040086e <+234>: mov %rax,%rdi 
    0x0000000000400871 <+237>: callq *%rdx 
    0x0000000000400873 <+239>: jmp 0x4008a8 <main+292> 
    0x0000000000400875 <+241>: lea -0x60(%rbp),%rax 
    0x0000000000400879 <+245>: mov $0x5,%edx 
    0x000000000040087e <+250>: mov %rax,%rsi 
    0x0000000000400881 <+253>: mov $0x400de6,%edi 
    0x0000000000400886 <+258>: callq 0x400620 <[email protected]> 
    0x000000000040088b <+263>: test %eax,%eax 
    0x000000000040088d <+265>: jne 0x40089b <main+279> 
    0x000000000040088f <+267>: mov $0x400df0,%edi 
    0x0000000000400894 <+272>: callq 0x400600 <[email protected]> 
    0x0000000000400899 <+277>: jmp 0x4008a8 <main+292> 
---Type <return> to continue, or q <return> to quit--- 
    0x000000000040089b <+279>: mov -0x10(%rbp),%rdx 
    0x000000000040089f <+283>: lea -0x60(%rbp),%rax 
    0x00000000004008a3 <+287>: mov %rax,%rdi 
    0x00000000004008a6 <+290>: callq *%rdx 
    0x00000000004008a8 <+292>: leaveq 
    0x00000000004008a9 <+293>: retq 
End of assembler dump. 

Я думал об эксплуатации system(nothing); внутри функций debug() и Я смог запустить исполняемый файл C, который я создал, с именем debug, когда я использую отладку пользователя и qroht в качестве пароля, но я не вижу, как это поможет мне войти в административную функцию, если только я не могу вызвать административную функцию из этого C-исполняемого файла (на данный момент он просто показывает «Hello World!» при выполнении adm.c программы).

У меня также есть этот скрипт perl, который позволяет мне получить доступ к обычному меню (я предполагаю, что это так, но мне нужна правильная строка, чтобы иметь возможность переполнять программу и переходить между адресами):

perl -e 'print pack("H*","6e61716572660A616e647265730A");' | ./adm 

Любая помощь будет очень признательна.

+0

Поскольку ввод в меню считывается с 'gets' **, он заполнен дырками безопасности **. По этой причине 'get' больше не является частью стандарта C. Вы должны иметь возможность создавать эксплойтер буфера, основанный на использовании 'gets', который позволит вам получить доступ к адресам функций администратора. Поиск на 'get'-эксплойтах. У меня нет быстрой строки, чтобы предлагать, но есть много в Интернете. Удачи. –

+0

Эта строка: void delete (void); использует ключевое слово (из C++), предлагая использовать другое имя. – user3629249

+0

@ DavidC.Rankin почему бы не сосредоточиться на проблеме и попытаться заставить шары говорить об устаревших функциях? Хотя этот парень заботится о том, чтобы не передавать строки дольше, чем размер буфера, код становится вокруг долгое время (64-битное время) –

ответ

1

Вот простое руководство для вас:

  1. Все считывается с помощью получает функцию, так тривиально переписать menufunc массива (при условии, что ваш компилятор помещает его в вышестоящем адресе памяти в на основе его разборки.)

  2. Положите точку останова внутри основного напр. строка: получает (пользователь);

  3. Используйте gdb для печати адреса «административной» функции.

  4. Используйте gdb для печати адресов пользовательского буфера, а также массива menufunc в текущем стеке.

  5. Рассчитать их относительное положение, чтобы вы знали, сколько вам нужно, чтобы записать данные за конец пользовательского массива, чтобы перезаписать menufunc [2]. (В зависимости от того, насколько хорошо вы читаете сборку, вы также можете рассчитать это прямо из разборки, которую вы опубликовали)

  6. Дайте имя пользователя, которое записывает правильный адрес (то есть адрес функции «административный» в menufunc [2] осторожнее с предисловием здесь). Обратите внимание, что вам нужно передать имя пользователя, содержащее непечатаемые символы. Конечно, вам нужно убедиться, что rot13 указанного вами пароля также совпадает с именем пользователя.

Это почти пошаговое руководство, поэтому я оставляю его как упражнение, как заполнить пробелы.

-1

Основная причина, вы не можете попасть в административный кодекс в том, что у вас есть #ifdef «d это в препроцессора проход, так что не была составлена ​​ в программу.Это оказывает такое же влияние на комментирование всего кода или его удаление из исходного файла.

Это означает, что у вас нет этого административного кода в программе, и вы не можете его выполнить. Вместо того чтобы заставить его зависеть от макроса препроцессора, просто поставьте обычный оператор if(), чтобы программа прошла через него или нет, в зависимости от какой-либо проверки, сделанной в Интернете.

+0

Это совершенно неправильно. Единственным результатом директивы '#if defined (ADMINISTRATIVE)' является то, что административная функция ** не отображается в пользовательском меню **. Это не имеет никакого отношения к тому, компилируется ли в программу 'void Administrative (char * nothing)'. Это так, как оно было предназначено для проблемы. –

+0

Но это никогда не появляется. Если вы решите во время компиляции, когда какой-то код будет скомпилирован (я имею в виду код коммутатора, а не функцию). Как должна быть вызвана функция? Вы не можете сделать тест препроцессора полезным во время выполнения, поскольку он позволяет вам решить, какой код следует поместить в окончательный исполняемый файл или нет, а не принимать решения во время выполнения. Только в случае, если у вас есть две разные программы: одна для пользователя и одна для администратора (скомпилированная с разными значениями для макроса ADMINISTRATOR), - это когда вы можете иметь это, чтобы иметь смысл. –

+0

Как написано, код скрывает вызов '(* menufunc [1]) (0);' и заменяет его сообщением, отображаемым в части '# else'. Вы можете понизить меня, но вы не правы. Конечно, функция появляется, но вызов нет, так в чем причина этого? –

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