我正在尝试书籍The Shellcoder's Handbook: Discovering and Exploiting Security Holes, 2nd Edition第23页的一个例子。下面是我所指的C程序,它需要用户输入并测试条件User Input % 853 == 83
。我在64位Linux机器上试用这个例子。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int valid_serial(char *psz){
size_t len = strlen(psz);
unsigned total = 0;
if (len<0){
return 0;
}
for (size_t i = 0; i < len; i++){
if(psz[i] < '0' || psz[i] > 'z'){
return 0;
}
total += psz[i];
}
if (total % 853 == 83){
return 1;
}
return 0;
}
int validate_serial(){
char serial[24];
fscanf(stdin, "%s", serial);
if(valid_serial(serial)){
return 1;
}
else{
return 0;
}
}
int do_valid_stuff(){
printf("The entered serial number is valid\n");
exit(0);
}
int do_invalid_stuff(){
printf("The entered serial number is Invalid\n");
exit(1);
}
int main(void){
if (validate_serial()){
do_valid_stuff();
}
else{
do_invalid_stuff();
}
return 0;
}
我编译了上面的程序,并使用gcc -g -fno-stack-protector serial.c -o serial
关闭了堆栈保护程序,正如预期的那样程序运行正常
$ printf "HHHHHHHHHHHHH" | ./serial
The entered serial number is valid
$ printf "1234" | ./serial
The entered serial number is Invalid
Q1)如何在GDB中输入十六进制值?
在GDB中,我在以下行创建断点
line 31 fscanf(stdin, "%s", serial);
line 33 if (valid_serial(serial));
在第一个断点第31行,这就是我所拥有的
(gdb) disassemble main
Dump of assembler code for function main:
0x0000555555554912 <+0>: push rbp
0x0000555555554913 <+1>: mov rbp,rsp
0x0000555555554916 <+4>: mov eax,0x0
0x000055555555491b <+9>: call 0x555555554899 <validate_serial>
0x0000555555554920 <+14>: test eax,eax
0x0000555555554922 <+16>: je 0x555555554930 <main+30>
0x0000555555554924 <+18>: mov eax,0x0
0x0000555555554929 <+23>: call 0x5555555548de <do_valid_stuff>
0x000055555555492e <+28>: jmp 0x55555555493a <main+40>
0x0000555555554930 <+30>: mov eax,0x0
0x0000555555554935 <+35>: call 0x5555555548f8 <do_invalid_stuff>
0x000055555555493a <+40>: mov eax,0x0
0x000055555555493f <+45>: pop rbp
0x0000555555554940 <+46>: ret
End of assembler dump.
(gdb) x/20xg $rsp
0x7fffffffe4f0: 0x0000000000000000 0x0000000000000000
0x7fffffffe500: 0x0000555555554950 0x00005555555546c0
0x7fffffffe510: 0x00007fffffffe520 0x0000555555554920
0x7fffffffe520: 0x0000555555554950 0x00007ffff7a5a2b1
0x7fffffffe530: 0x0000000000040000 0x00007fffffffe608
0x7fffffffe540: 0x00000001f7b9b2e8 0x0000555555554912
0x7fffffffe550: 0x0000000000000000 0x9eeb30dff32f3990
0x7fffffffe560: 0x00005555555546c0 0x00007fffffffe600
0x7fffffffe570: 0x0000000000000000 0x0000000000000000
0x7fffffffe580: 0xcbbe658aabef3990 0xcbbe753e255d3990
(gdb)
因此,在下一步中,我必须使用validate_serial
指令0x0000555555554920
的地址覆盖call
do_valid_stuff
的返回地址0x0000555555554929
}}
继续gdb
(gdb) c
Continuing.
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA)IUUUU
Breakpoint 2, validate_serial () at serial.c:33
33 if(valid_serial(serial)){
成功覆盖了返回地址
(gdb) x/20xg $rsp
0x7fffffffe4f0: 0x4141414141414141 0x4141414141414141
0x7fffffffe500: 0x4141414141414141 0x4141414141414141
0x7fffffffe510: 0x4141414141414141 0x0000555555554929
0x7fffffffe520: 0x0000555555554950 0x00007ffff7a5a2b1
0x7fffffffe530: 0x0000000000040000 0x00007fffffffe608
0x7fffffffe540: 0x00000001f7b9b2e8 0x0000555555554912
0x7fffffffe550: 0x0000000000000000 0x9eeb30dff32f3990
0x7fffffffe560: 0x00005555555546c0 0x00007fffffffe600
0x7fffffffe570: 0x0000000000000000 0x0000000000000000
0x7fffffffe580: 0xcbbe658aabef3990 0xcbbe753e255d3990
(gdb) c
Continuing.
The entered serial number is valid
[Inferior 1 (process 9851) exited normally]
(gdb)
我无法使用以下方法将地址覆盖为0x0000555555554929。
(gdb) c
Continuing.
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x29\x49\x55\x55\x55\x55\x00\x00
(gdb) x/20xg $rsp
0x7fffffffe4f0: 0x4141414141414141 0x4141414141414141
0x7fffffffe500: 0x4141414141414141 0x4141414141414141
0x7fffffffe510: 0x4141414141414141 0x3934785c3932785c
0x7fffffffe520: 0x3535785c3535785c 0x3535785c3535785c
0x7fffffffe530: 0x3030785c3030785c 0x00007fffffffe600
0x7fffffffe540: 0x00000001f7b9b2e8 0x0000555555554912
0x7fffffffe550: 0x0000000000000000 0xb17102b2c99239fc
0x7fffffffe560: 0x00005555555546c0 0x00007fffffffe600
0x7fffffffe570: 0x0000000000000000 0x0000000000000000
0x7fffffffe580: 0xe42457e7915239fc 0xe42447531fe039fc
(gdb) c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
Q2)即使使用以下方法,我也无法覆盖返回地址。是因为ASLR?
$ printf "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x29\x49\x55\x55\x55\x55\x00\x00" | ./serial
Segmentation fault