pwn 字符串格式化漏洞 02-覆盖栈的内容

1.1 大致方向

通过修改栈和内存来劫持程序的执行流,
%n 转换指示符 ,将当前成功写入流的缓冲区的字符串个数 存储 到参数指定的整数中。

1.2继续花式hello world

#include 
int main()
{
        int i;
        char str[] = "hello";

        printf("%s %n\n",str,&i);
        printf("%d\n",i);
}

运行:

root@MSI:/mnt/c/Users/13013/Desktop/PWN/pwn 字符串格式化漏洞/02-覆盖栈的内容# ./example
hello
6

1.3

  • 分析:
    这里的 i没有被附有初值,但是输出是6
  • 原因:
    转换指示符之前写入了6个(包括空格)字符(h e l l o ' '),没有长度修饰的时候,默认写入一个int类型的值,

1.4 一般利用情况:

通常情况下,我们要需要覆写的值是一个 shellcode 的地址,而这个地址往往是一 个很大的数字。这时我们就需要通过使用具体的宽度或精度的转换规范来控制写入 的字符个数,即在格式字符串中加上一个十进制整数来表示输出的最小位数,如果 实际位数大于定义的宽度,则按实际位数输出,反之则以空格或 0 补齐

just like this:

#include 
int main()
{
        int i;
        printf("%10u%n\n",1,&i);
        printf("%d\n",i);
        printf("%.50u%n\n",1,&i);
        printf("%d\n",i);
        printf("%0100u%n\n",1,&i);
        printf("%d\n",i);
}

运行结果:

root@MSI:/mnt/c/Users/13013/Desktop/PWN/pwn 字符串格式化漏洞/02-覆盖栈的内容# ./shellcode
         1
10
00000000000000000000000000000000000000000000000001
50
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
100

仔细思考一下,我就就可以把一个地址写入内存
注:

  • 在64位中,RDI被用于传递格式字符串,所以我们就无法改写参数了
  • 格式字符串("aa%15$na")这种,一定要8字节对齐

2. 关于参数位置的计算

(要改变的地址 - 输入的地址)/ 8 + gdb中的偏移 = 参数位置

这个地方可以顺便讲讲canry绕过
参考题:
攻防世界 Mary_Morton(ASIS-CTF-Finals-2017)
WP:(推荐)
Mary Morton wp
WP讲的比较详细了

3.pwntools中相关工具:

3.1pwntools pwnlib.fmtstr

1- 自动化的字符串漏洞的利用:

class pwnlib.fmtstr.FmtStr(execute_fmt, offset=None, padlen=0, n umbwritten=0)

  • excute_fmt(funtion):与漏洞进程进行交互
  • offset(int):你控制的第一个程序的偏移量
  • padlen(int):在payload前添加pad大小
  • numbwritten(int):已写入字节数

2- 自动生成payload

pwnlib.fmtstr.fmtstr_payload(offset, writes, numbwritten=0, writ e_size='byte')

  • offset (int):你控制的第一个格式化程序的偏移量
  • writes (dict):格式为 {addr: value, addr2: value2},用于往 addr 里写入 value的值(常用:{printf_got})
  • numbwritten (int):已经由 printf 函数写入的字节数
  • write_size (str):必须是 byte,short 或 int。告诉你是要逐 byte 写,逐 short 写还是逐 int 写(hhn,hn或n)

================施工未完成===============

3.2直接上题

3.2.1源代码:

#include
int main()
{
        char str[1024];
        while(1)
        {
                memset(str,'\0',1024);
                read(0,str,1024);
                printf(str);
                fflush(stdout);
        }
}

3.2.2常规套路:

root@MSI:/mnt/c/Users/13013/Desktop/PWN/pwn 字符串格式化漏洞/02-覆盖栈的内容# rabin2 -I fmt
arch     x86
baddr    0x400000
binsz    6814
bintype  elf
bits     64
canary   false
class    ELF64
compiler GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609
crypto   false
endian   little
havecode true
intrp    /lib64/ld-linux-x86-64.so.2
laddr    0x0
lang     c
linenum  true
lsyms    true
machine  AMD x86-64 architecture
maxopsz  16
minopsz  1
nx       true
os       linux
pcalign  0
pic      false
relocs   true
relro    partial
rpath    NONE
sanitiz  false
static   false
stripped false
subsys   linux
va       true

3.2.3思路:

我们的思路是将 printf() 函数的地址改 成 system() 函数的地址,这样当我们再次输入 /bin/sh 时,就可以获得 shell 了。

====================================

4.1 CVE-2012-0809

官方解释
EXP思路
以后在CVE合集里更新吧

4.2 补充

格式化字符串函数

常见的有格式化字符串函数有

  • 输入
    • scanf
  • 输出
函数 基本介绍
printf 输出到stdout
fprintf 输出到指定FILE流
vprintf 根据参数列表格式化输出到 stdout
vfprintf 根据参数列表格式化输出到指定FILE流
sprintf 输出到字符串
snprintf 输出指定字节数到字符串
vsprintf 根据参数列表格式化输出到字符串
vsnprintf 根据参数列表格式化输出指定字节到字符串
setproctitle 设置argv
syslog 输出日志
err, verr, warn, vwarn等 。。。

-----------转自ctfwiki

你可能感兴趣的:(pwn 字符串格式化漏洞 02-覆盖栈的内容)