前段时间找到一个练习pwn的网站,pwnable.kr

这里记录其中的passcode的做题过程,给自己加深印象。

废话不多说了,看一下题目,

看到题目,就ssh连接进去,就看到三个文件如下

看了一下我们的用户名,并不能直接查看flag这个文件。查看passcode.c的源码看一下

#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== && passcode2==){
printf("Login OK!\n");
system("/bin/cat flag");
}
else{
printf("Login Failed!\n");
exit();
}
} void welcome(){
char name[];
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 ;
}

可以看到整个程序的流程很简单,就是要我们输入两个数,让这两个数等于特定的数,就输出flag的内容,但是根据她的提示,程序有问题,可以直接使用gcc来尝试编译一下,就发现在登录函数里,对于两个passcode的值没有加上取地址符号,这将会导致scanf把passcode1和passcode2中的值作为存储输入的地址,如果地址不可写,就会造成一个内存错误。这样我们直接输入特定的值肯定不行了。。。。这里我们看一下这个程序的防护

程序有栈溢出保护和NX(数据执行保护)看了大牛的wp之后,知道关键点在welcome这里,因为welcome这里开了一个有点大的数组,有没有可能改变login中passcode1或passcode2的值,因为welcome和login这两个函数是连续调用的,导致他们拥有相同的栈底。我们看一下passcode的反汇编代码。。objdump -d passcode

 <login>:                     //这里是login函数
: push %ebp
: e5 mov %esp,%ebp
: ec sub $0x28,%esp        //分配栈空间
804856a: b8 mov $0x8048770,%eax
804856f: mov %eax,(%esp)
: e8 a9 fe ff ff call <printf@plt>
: b8 mov $0x8048783,%eax
804857c: 8b f0 mov -0x10(%ebp),%edx //看到这里是passcode1的内容作为参数传递给scanf
804857f: mov %edx,0x4(%esp)
: mov %eax,(%esp)
: e8 ff ff ff call 80484a0 <__isoc99_scanf@plt>
804858b: a1 2c a0 mov 0x804a02c,%eax
: mov %eax,(%esp)
: e8 fe ff ff call <fflush@plt>
: b8 mov $0x8048786,%eax
804859d: mov %eax,(%esp)
80485a0: e8 7b fe ff ff call <printf@plt>
80485a5: b8 mov $0x8048783,%eax
80485aa: 8b f4 mov -0xc(%ebp),%edx    //这里是passcode2的内容作为参数传递给scanf
80485ad: mov %edx,0x4(%esp)
80485b1: mov %eax,(%esp)
80485b4: e8 e7 fe ff ff call 80484a0 <__isoc99_scanf@plt>
80485b9: c7 movl $0x8048799,(%esp)
80485c0: e8 8b fe ff ff call <puts@plt>
80485c5: 7d f0 e6 cmpl $0x528e6,-0x10(%ebp)    //第一个比较
80485cc: jne 80485f1 <login+0x8d>
80485ce: 7d f4 c9 cc cmpl $0xcc07c9,-0xc(%ebp)    //第二个比较
80485d5: 1a jne 80485f1 <login+0x8d>
80485d7: c7 a5 movl $0x80487a5,(%esp)
80485de: e8 6d fe ff ff call <puts@plt>
80485e3: c7 af movl $0x80487af,(%esp)
80485ea: e8 fe ff ff call <system@plt>    //执行系统命令,关键点
80485ef: c9 leave
80485f0: c3 ret
80485f1: c7 bd movl $0x80487bd,(%esp)
80485f8: e8 fe ff ff call <puts@plt>
80485fd: c7 movl $0x0,(%esp)
: e8 fe ff ff call <exit@plt> <welcome>:
: push %ebp
804860a: e5 mov %esp,%ebp
804860c: ec sub $0x88,%esp
: a1 mov %gs:0x14,%eax
: f4 mov %eax,-0xc(%ebp)
804861b: c0 xor %eax,%eax
804861d: b8 cb mov $0x80487cb,%eax
: mov %eax,(%esp)
: e8 f6 fd ff ff call <printf@plt>
804862a: b8 dd mov $0x80487dd,%eax
804862f: 8d lea -0x70(%ebp),%edx //name的地址
: mov %edx,0x4(%esp)
: mov %eax,(%esp)
: e8 fe ff ff call 80484a0 <__isoc99_scanf@plt>
804863e: b8 e3 mov $0x80487e3,%eax
: 8d lea -0x70(%ebp),%edx
: mov %edx,0x4(%esp)
804864a: mov %eax,(%esp)
804864d: e8 ce fd ff ff call <printf@plt>
: 8b f4 mov -0xc(%ebp),%eax
: xor %gs:0x14,%eax
804865c: je <welcome+0x5a>
804865e: e8 dd fd ff ff call <__stack_chk_fail@plt>
: c9 leave
: c3 ret <main>:
: push %ebp
: e5 mov %esp,%ebp
: e4 f0 and $0xfffffff0,%esp
804866b: ec sub $0x10,%esp
804866e: c7 f0 movl $0x80487f0,(%esp)
: e8 d6 fd ff ff call <puts@plt>
804867a: e8 8a ff ff ff call <welcome>
804867f: e8 e0 fe ff ff call <login> //连续调用,导致栈底是相同的
: c7 movl $0x8048818,(%esp)
804868b: e8 c0 fd ff ff call <puts@plt>
: b8 mov $0x0,%eax
: c9 leave
: c3 ret
: nop
: nop
: nop
804869a: nop
804869b: nop
804869c: nop
804869d: nop
804869e: nop
804869f: nop

从上面我们看到,因为welcome和login的栈底相同,看到name的地址在ebp-0x70, 而passcode1的地址在ebp-0x10, 0x70 == 112, 0x10 == 16

所以0x70-0x10 == 0x60 == 96,所以我们可以看到name的最后四个字节就是passcode1的值,所以我们可以利用welcome来改变passcode1的值,

因为程序开启了栈溢出保护,所以我们不能再继续增加name的输入来改变passcode2的值(如果能改,直接改为两个特定数就可以了,但这里不行)。

从大牛的WP知道,这里我们要使用的是一种GOT表复写的技术,GOT表就是一个函数指针数组(具体搜索),我们看到程序在我们输入之后会调用pritnf函数,

所以我们可以将passcode1的值改为printf的地址,然后接下来会通过scanf将上面的关键系统命令的地址写进去,改变整个程序的执行过程,当程序调用

printf函数的时候,由于它的地址已经被改变了,所以会跳到关键系统命令的地方去。

80485e3:    c7   af        movl   $0x80487af,(%esp)
80485ea: e8 fe ff ff call <system@plt>

所以我们要知道printf的got地址,然后将它的地址改为 0x080485ea这个关键的地方。使用objdump -R passcode来看一下GOT表

passcode@ubuntu:~$ objdump -R passcode

passcode:     file format elf32-i386

DYNAMIC RELOCATION RECORDS
OFFSET TYPE VALUE
08049ff0 R_386_GLOB_DAT __gmon_start__
0804a02c R_386_COPY stdin@@GLIBC_2.
0804a000 R_386_JUMP_SLOT printf@GLIBC_2.0 //printf的地址
0804a004 R_386_JUMP_SLOT fflush@GLIBC_2.
0804a008 R_386_JUMP_SLOT __stack_chk_fail@GLIBC_2.
0804a00c R_386_JUMP_SLOT puts@GLIBC_2.
0804a010 R_386_JUMP_SLOT system@GLIBC_2.
0804a014 R_386_JUMP_SLOT __gmon_start__
0804a018 R_386_JUMP_SLOT exit@GLIBC_2.
0804a01c R_386_JUMP_SLOT __libc_start_main@GLIBC_2.
0804a020 R_386_JUMP_SLOT __isoc99_scanf@GLIBC_2.

我这里使用pwntools这个包来写利用脚本。因为scanf是要求%d输入,所以0x080485ea == 134514154

最后就看到flag了。。。。。。。。

                                        --好好学习,天天向上

pwnable.kr的passcode的更多相关文章

  1. 【pwnable.kr】passcode

    pwnable从入门到放弃,第六题. ssh passcode@pwnable.kr -p2222 (pw:guest) 完全是‘&’的锅. #include <stdio.h> ...

  2. pwnable.kr之passcode

    使用ssh passcode@pwnable.kr -p2222登录到远程服务器, ls -l 查看目录下的文件, -r--r----- root passcode_pwn Jun flag -r-x ...

  3. pwnable.kr 之 passcode write up

    先看源码: #include <stdio.h> #include <stdlib.h> void login(){ int passcode1; int passcode2; ...

  4. pwnable.kr col之write up

    Daddy told me about cool MD5 hash collision today. I wanna do something like that too! ssh col@pwnab ...

  5. 【pwnable.kr】col

    pwnable从入门到放弃第二题, ssh col@pwnable.kr -p2222 (pw:guest) 同样是登录,然后看到了col.c.col.flag三个文件,读一下col.c #inclu ...

  6. pwnable.kr bof之write up

    这一题与前两题不同,用到了静态调试工具ida 首先题中给出了源码: #include <stdio.h> #include <string.h> #include <st ...

  7. pwnable.kr brainfuck之write up

    I made a simple brain-fuck language emulation program written in C. The [ ] commands are not impleme ...

  8. pwnable.kr login之write up

    main函数如下: auth函数如下: 程序的流程如下: 输入Authenticate值,并base64解码,将解码的值代入md5_auth函数中 mad5_auth()生成其MD5值并与f87cd6 ...

  9. pwnable.kr详细通关秘籍(二)

    i春秋作家:W1ngs 原文来自:pwnable.kr详细通关秘籍(二) 0x00 input 首先看一下代码: 可以看到程序总共有五步,全部都满足了才可以得到flag,那我们就一步一步来看 这道题考 ...

随机推荐

  1. HTTPS 双向认证构建移动设备安全体系

    HTTPS 双向认证构建移动设备安全体系 对于一些高安全性要求的企业内项目,我们有时希望能够对客户端进行验证.这个时候我们可以使用Https的双向认证机制来实现这个功能. 单向认证:保证server是 ...

  2. Linux系统下配置环境变量

    一.环境变量文件介绍 转自:http://blog.csdn.net/cscmaker/article/details/7261921 Linux中环境变量包括系统级和用户级,系统级的环境变量是每个登 ...

  3. poj Flip Game 1753 (枚举)

    Flip Game Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 27005   Accepted: 11694 Descr ...

  4. Netty 实现聊天功能

    Netty 是一个 Java NIO 客户端服务器框架,使用它可以快速简单地开发网络应用程序,比如服务器和客户端的协议.Netty 大大简化了网络程序的开发过程比如 TCP 和 UDP 的 socke ...

  5. NDK笔记(二)-在Android Studio中使用ndk-build

    前面一篇我们接触了CMake,这一篇写写关于ndk-build的使用过程.刚刚用到,想到哪儿写哪儿. 环境背景 Android开发IDE版本:AndroidStudio 2.2以上版本(目前已经升级到 ...

  6. 百度编辑器UEditor的使用方法

    百度编辑器具有丰富文本编辑功能,且开源免费,其使用方法如下: 1.在官网上下载对应的Uditor压缩包:http://ueditor.baidu.com/website/download.html 2 ...

  7. 【Android自学日记】两种适配器的使用

    ArrayAdapter适配器: (1)用于显示基本的文字内容 (2)基本使用过程:新建适配器---创建或加载数据源---适配器加载数据源---视图加载适配器 ArrayAdapter(上下文,当前L ...

  8. Java实现比较版本号

    涉及到客户端的系统中经常需要用到比较版本号的功能,但是比较版本号又不能完全按照字符串比较的方式去用compareTo之类的方法: 这就需要我们总结版本号的通用规则,设计一个比较算法并封装成通用方法来使 ...

  9. 一对一还是一对多? MVP设计前提

    设计MVP之前,先要确定好以下模块之间是一对多还是一对一的关系: View ---> Presenter --> Model --> Interface(URL) 就是一个View只 ...

  10. 在Oracle中恢复被DROP掉的表

    在Oracle中可能不小心会DROP掉一个表,如果没有定期做备份的话,将会带来很大的麻烦.如果有的情况下,每天的数据都很重要,而定期备份的周期又稍长,情况恐怕也不容乐观!以前只知道Windows有个回 ...