格式化字符串溢出原理详解

admin 2024年9月28日12:19:56评论15 views字数 2844阅读9分28秒阅读模式

概念:

printf作为C语言中的输出函数,其使用方式是填充两个参数,分别是格式化字符和变量。
printf("格式化字符"变量(指针、整形等变量));
但有的人为了省事也会写成 :
printf(变量);
虽然都可以正常输出,但那是在正常情况下。而在不正常的情况下比如被利用时,printf(变量);这样的写法就变得很危险了。

C语言格式化字符:

%c:
输出字符,配上%n可用于向指定地址写数据。
%d:
输出十进制整数,配上%n可用于向指定地址写数据。
%x:
输出16进制数据,如%i$x表示要泄漏偏移i处4字节长的16进制数据,%i$lx表示要偏移i处8字节长的16进制数据。32bit和64bit环境下一样。
%p:
输出16进制数据,与%x基本一样,只是附加了前级0x,在32bit下输出4字节,在64bit下输出8字节,可通过输出字节的长度来判断目标环境是32biti不是64bit。
%s:
输出的内容是字符串,即将偏移处指针指向的字符串输出,如%i$s表示输出偏移i处地址所指向的字符串。在32bit和64bit环境下一样,可用于读取GOT表等信息。
%n:
将%n之前printf已经打印的字符个数赋值给偏移处指针所指向的地址位置,如%100x%10$n表示将0x64写入偏移10处保存的指针所指向的地址(4字节),而%$hn表示写入的地址空间为2字节,%$hhn表示写入的地址空间为1字节。
%$lln:
表示写入的地址空间为8字节,在32bit和64bit环境下一样。有时直接写4字节会导致程序崩溃或等候时间过长,可以通过%$hn或%$hhn来适时调整。

文件解析:

获取到的文件样本。

格式化字符串溢出原理详解

可以丢到kali下尝试运行,并查看文件信息。

1、./pwn7运行

格式化字符串溢出原理详解

2、查看文件类型命令:

file pwn7

格式化字符串溢出原理详解

可见是32位下的Linux文件。

3、查看保护机制:

checksec --file=pwn7

格式化字符串溢出原理详解

  • RELRO:开启则无法修改got表。

  • Stack:开启则无法直接覆盖EIP让程序任意跳转,跳转后会进行cookie校验;但这项保护可以被绕过。

  • NX:开启则shellcode无法被执行。

  • PIE:开启在每次程序运行地址都会变化,未开启则返回值括号内是程序的基址。

4、用32位编辑器查看:

格式化字符串溢出原理详解

格式化字符串溢出原理详解

获取到两个信息,一个是.ELF格式的文件,即Linux平台下的可执行文件。另一个是文件的编译信息,即GCC,C语言的文件。那么就可能存在有格式化字符串的溢出。

5readelf -h 可读取 elf 文件头。头文件包含如下:

readelf -h
  • ELF 魔数。

  • 文件机器字节长度。

  • 数据存储方式。

  • 版本。

  • 运行平台。

  • ABI 版本。

  • ELF 重定位类型。

  • 硬件平台。

  • 硬件平台版本。

  • 入口地址(目标文件入口地址为 0,只有相对位置)。

  • 程序的入口和长度。

  • 段表的位置和长度。

格式化字符串溢出原理详解

可见程序入口地址为0x8048450。

IDA逆向:

格式化字符串溢出原理详解

定位到入口地址,向下翻找到了main函数。

格式化字符串溢出原理详解

空格切换到图形模式分析。

格式化字符串溢出原理详解

可见输入输出套在一个死循环里,基本可以判断为格式化字符串的溢出。

格式化字符串溢出原理详解

Got表修改与Libc基址偏移:

1、找到libc_start_main在栈内的偏移,使用%p暴露该地址
2、利用LibcSearcher猜测使用的libc,算出libc基址
3、计算出此libcsystem地址
4、把prinfgot表改为system地址
5、执行system(’/bin/sh’)

Got表与PLT表:

还是使用gdb来进行观察。(详细gdb安装与使用教程在文章末尾)

格式化字符串溢出原理详解

格式化字符串溢出原理详解

第一个jmp跳转的就是函数对应的Got表。

格式化字符串溢出原理详解

格式化字符串溢出原理详解

类似于一个间接寻址的过程。

我们就把获取数据段存放函数地址的那一小段代码称为PLT过程链接表)

存放函数地址的数据段称为GOT全局偏移表)

格式化字符串溢出原理详解

格式化字符串溢出原理详解

所以如果我们可以把printfGot表指向改为system地址,那么就可以执行命令,反弹shell。但是我们不知道system的地址。

因为Got表中的内容,会在_dl_runtimw_resolve之前和之后,将真正的函数地址,也就是glibc运行库中的函数的地址,回写到代码段,就是got[n]n>=3)中。

也就是说在函数第一次调用时,才通过连接器动态解析并加载到.got.plt中,而这个过程称之为延时加载或者惰性加载

Libc基址偏移获取system Got表地址

glibclinux下面c标准库的实现,即GNU C Libraryglibc本身是GNU旗下的C标准库,后来逐渐成为了Linux的标准c库,而Linux下原来的标准cLinux libc逐渐不再被维护。

Linux下面的标准c库不仅有这一个,如uclibcklibc,但是glibc无疑是用得最多的。glibc/lib目录下的.so文件为libc.so.6

获取函数在libc中的偏移量:

libc已知:

libc已知的情况,可以通过反编译libc获取地址。利用radare分析libc文件,可以获取libc中write的偏移地址

也可以通过pwntoolsELF类,加载libc文件来获取目标函数的偏移地址。

格式化字符串溢出原理详解

libc未知:

libc未知的情况下,需要确定libc的版本号。

同一个版本的libc对应的函数的实际地址是一样的,因此通过收集所有libc库的实际函数的地址,就利用泄露的函数的实际地址确定libc版本,从而进一步获取libc中函数的偏移地址。

PY中可以使用LibSearcher库。

格式化字符串溢出原理详解

因为函数的实际地址=libc基址+函数在libc中偏移量,而在Got表的介绍中我们可以拿到函数的实际地址,就可以计算得到libc的基址,从而计算得到libc的偏移量,最后推算出system的实际地址。

GDB+pwndbg+fmtarg获取libc偏移量:

1、安装GDB用于程序的调试:

apt install gdb

2pwndbg安装:

git clone https://github.com/pwndbg/pwndbgcd pwndbg./setup.sh

如果是手动下载的话需要初始化git仓库,git init 。

3pwdgdb安装:

fmtarg是属于pwdgdb中的一个偏移计算的工具。

cd ~/git clone https://github.com/scwuaptx/Pwngdb.git cp ~/Pwngdb/.gdbinit ~/

4、配置dbggdb共存环境

vim ~/.gdbinit

格式化字符串溢出原理详解

5、执行gdb pwn7调试程序

格式化字符串溢出原理详解

6、使用b printfprintf处下断点

7、输入r执行程序

8、程序提示用户输入,输入123456,此时程序运行到printf语句停止

格式化字符串溢出原理详解

9、输入stack 60命令查看栈情况

格式化字符串溢出原理详解

格式化字符串溢出原理详解

10、使用fmtarg 0xffffd17c算出偏移:

poc编写的是获取的输入的Got表实际地址,所以这里计算的是输入的偏移

格式化字符串溢出原理详解

格式化字符串溢出原理详解

11、编写poc获取shell

格式化字符串溢出原理详解

详细说明:

格式化字符串溢出原理详解

12python3执行脚本

由于库pwn仅存在于3.0以上版本,所以需要使用python3

格式化字符串溢出原理详解

格式化字符串溢出原理详解

成功拿到shell

原文始发于微信公众号(黑熊安全):格式化字符串溢出原理详解

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年9月28日12:19:56
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   格式化字符串溢出原理详解https://cn-sec.com/archives/1989543.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息