攻防世界-PWN进阶区-echo_back(CISCN-2018-Quals)

本题考查的是对格式化字符串漏洞的利用以及修改_IO_2_1_stdin来实现任意地址写

题目分析

checksec:
在这里插入图片描述
发现保护全开

源码分析:

echo函数:
在这里插入图片描述
在该函数中有明显的格式化字符串漏洞,但是格式化字符串的长度有限制,最长只能为7,这使得许多利用格式化字符串进行任意内存写的方式不能使用,不过泄露信息还是能够做到的
对于信息泄露,首先我们需要获取libc的基地址,这样我们才能计算system和/bin/sh在程序中的位置。而本题利用的泄露信息与以往的题目不同,以前一般是泄露某个库函数(read,write,printf等等)的got表地址来计算libc基地址的。但是本题因为开启了PIE以及输入长度的限制,我们难以得到got表在内存中的地址。所以本题是利用 __libc_start_main 来获取libc基地址的:main函数的返回地址为__libc_start_main + 0xf0,获得了main函数的返回地址就能计算出__libc_start_main的地址,也能计算出libc的基地址。而main函数的返回地址是保存在栈上的,根据调试可以发现使用 %19$p 就能得到main的返回地址。同理使用 %13$p就可以得到echo函数的返回地址从而计算出程序的地址。
在这里插入图片描述
通过上面的步骤我们能够计算出system和/bin/sh的地址,但是我们还需要修改函数的返回地址才能执行我们的代码。而%12$p处就保存了main函数rbp的地址,该地址+0x8就是main函数的返回地址了。
现在我们已经基本获取到了需要的地址,但是还有一个问题,就是如何把我们的rop链写入。这里就需要用到源代码中的setName函数:
在这里插入图片描述

我们先把名字设为aaaa,然后查看栈
在这里插入图片描述

可以看到我们设置的名字在%16$的位置,所以我们可以先把名字设为想要写入的地址,然后利用格式化字符串就能向该地址写入数据了。
但是还有一个问题,因为题目的限制,我们能够输入的字符数是有限的,在题目的限制下我们难以把ROP链写到返回地址上,这里我们就需要利用 _IO_2_1_stdin 了。

基础知识

在echo函数中,程序使用了scanf来读取长度,而scanf是从stdin中读取数据的,如果我们能够修改它,就能实现任意内存写入。

_IO_FILE

当Linux新建一个进程时,会自动创建3个文件描述符0、1和2,分别对应标准输入、标准输出和错误输出。C库中与文件描述符对应的是文件指针,与文件描述符0、1和2类似,我们可以直接使用文件指针stdin、stdout和stderr。
下面是stdio.h中的代码

typedef struct _IO_FILE FILE;  
 
/* Standard streams.  */  
extern struct _IO_FILE *stdin;      /* Standard input stream.  */  
extern struct _IO_FILE *stdout;     /* Standard output stream.  */  
extern struct _IO_FILE *stderr;     /* Standard error output stream.  */  
#ifdef __STDC__  
/* C89/C99 say they're macros.  Make them happy.  */  
#define stdin stdin  
#define stdout stdout  
#define stderr stderr  
#endif 

从上面的源码可以看出,stdin、stdout和stderr确实是文件指针。而C标准要求stdin、stdout和stderr是宏定义,所以在C库的代码中又定义了同名宏。stdin、stdout和stderr的定义代码如下:

_IO_FILE *stdin = (FILE *) &_IO_2_1_stdin_;  
_IO_FILE *stdout = (FILE *) &_IO_2_1_stdout_;  
_IO_FILE *stderr = (FILE *) &_IO_2_1_stderr_; 

让我们再看看文件的读取过程:
_IO_new_file_underflow 这个函数最终调用了_IO_SYSREAD系统调用来读取文件。在这之前,它做了一些处理

int _IO_new_file_underflow (_IO_FILE *fp)
{
   
  _IO_ssize_t count;
  ...
  if (fp->_flags & _IO_NO_READS)
    <
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值