echo_back(xctf)

0x0 程序保护和流程

保护:

protect

流程:

main()

main

echo_back()

echo_back

存在一个格式化字符串漏洞。

0x1 利用过程

1.题目保护全开,程序中又没有可用的字符串,函数。所以只能通过格式化字符串漏洞泄露地址,写入有限数据。

2.既然有格式化字符串漏洞,肯定是要泄露栈上的信息。但是由于限制了字符串最长为7,所以只能逐位泄露。

选择使用ida的远程调试,因为可以丢弃alarm()发出的signal。选择在echo_back()的retn处下断点

echo_back_break

直到到输入%6$p时在栈上发现了被输出的数据(为什么是第6个参数才输出在栈上的值呢?,这要结合x64的传参顺序,前6个参数在寄存器中,之后的再从栈上取数据。现在当第一个参数为输入的字符串,后5个都是寄存器中的数据,所以只有在偏移为6的时候开始从栈上取数据)。

%6$p

此时在retn处程序停止执行。可以看到0x7FFEEF3D35E0处为偏移量为6。

stack_status

rsp指向栈顶位置,也就是返回的地址位置为main+0x9C。

registers

此时可以通过掌握的基础知识分析处几个点(结合上述图片食用)。

  • retn指令在执行之前还有一个leave指令,而leave指令相当于。
mov rsp,rbp
pop rbp

通过寄存器信息可以得出main函数的rbp位于0x7FFEEF3D3640。main函数的返回地址位于0x7FFEEF3D3648。

  • 发现栈上0x7FFEEF3D3638和0x7FFEEF3D3608中的数据是一样的,它们也同时位于各自rbp-0x8的位置。所以可以判断出这两个是canary的值。
  • 可以找到之前输入的数据,结合echo_back()中的数据摆放位置可以轻松找到,输入的数据长度7位于0x7FFEEF3D35FC,"%6$p\n"位于0x7FFEEF3D3600=0x7FFEEF3D35FC+0x4。
  • 可以知道main函数中的变量name存放的位置,rbp-0x10=0x7FFEEF3D3640-0x10=0x7FFEEF3D3630

3.通过以上分析可以知道libc的基地址,elf文件加载的基地址,main函数的返回地址。但是由于输入限制了字符串最长为7,导致无法大量的向程序中写入数据。通过查阅资料(ctf-wiki)得知,因为进程中包含了系统默认的三个文件流 stdin\stdout\stderr,因此这种方式可以不需要进程中存在文件操作,通过 scanf\printf 一样可以进行利用。并且可以在 libc.so 中找到 stdin\stdout\stderr 等符号,这些符号是指向 FILE 结构的指针,真正结构的符号是

_IO_2_1_stderr_
_IO_2_1_stdout_
_IO_2_1_stdin_

在libc中的位置。

_IO_2_1_stdin_

_IO_FILE 结构体

struct _IO_FILE {
   
  int _flags;       /* High-order word is _IO_MAGIC; rest is flags. */
  /* The following pointers correspond to the C++ streambuf protocol. */
  /* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
  char* _IO_read_ptr;   /* Current read pointer */
  char* _IO_read_end;   /* End of get area. */
  char* _IO_read_base;  /* Start of putback+get area. */
  char* _IO_write_base; /* Start of put area. */
  char* _IO_write_ptr;  /* Current put pointer. */
  char* _IO_write_end;  /* End of put area. */
  char* _IO_buf_base;   /* Start of reserve area. */
  char* _IO_buf_end;    /* End of reserve area. */
  /* The following fields are used to support backing up and undo. */
  char *_IO_save_base; /* Pointer to start of non-current get area. */
  char *_IO_backup_base;  /* Pointer to first valid character of backup area */
  char *_IO_save_end; /* Pointer to end of non-current get area. */

  struct _IO_marker *_markers;

  struct _IO_FILE *_chain;

  int _fileno;
  int _flags2;
  _IO_off_t _old_offset; /* This used to be _offset but it's too small.  */
};

在_IO_FILE 中_IO_buf_base 表示操作的起始地址,_IO_buf_end 表示结束地址,结合对文件读写的源码,可以发现_IO_new_file_underflow 这个函数最终调用了_IO_SYSREAD系统调用来读取文件。所以可以通过控制这两个数据可以实现控制读写的操作。

int
_IO_new_file_underflow (_IO_FILE *fp)
{
   
  _IO_ssize_t count;
#if 0
  /* SysV does not make this test; take it out for compatibility */
  if (fp->_flags & _IO_EOF_SEEN)
    return (EOF);
#endif

  if 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值