格式化字符串实例

实验环境

Ubuntu 16.04 32bits

实验

实验一

vul_formatstr2.c代码:
格式化字符串实例_第1张图片

编译vul_formatstr2.c:
格式化字符串实例_第2张图片

用gdb跟踪程序的执行 :
格式化字符串实例_第3张图片
格式化字符串实例_第4张图片格式化字符串实例_第5张图片

栈顶为0xbfffec40,user_input的首地址为0xbfffeb5c,位于栈顶开始的第7个(4字节)单元。

user_input的首地址与栈顶的距离为7个(4字节)单元。

格式化字符串实例_第6张图片
第七个“%08x”表示第七个格式,代表字符串“ABCD”;
第八个“%08x”表示第八个格式,代表字符串“%08x”。

其中的第7个格式化输出0x44434241就是字符串"ABCD"的十六进制代码。
将"ABCD"替换成要改写的内存地址,并且第7个格式化参数为%n,正确设置第6个格式化参数,就可以改写内存的值。
通常,scanf()会将键盘输入的字符转换成ASCII码再存入,比如输入字符5会存为0x35。若直接通过键盘输入,则需要将地址根据ASCII码反转换成键盘可输入的字符,比如0x31323231的键盘输入是1221。然而问题是ASCII码表中只有128个字符,且0x80之后没有对应的字符,因此无法从键盘输入任意4字节的内存地址。

解决办法是将要输入的数据写入到文件,然后利用命令行的重定向功能,将该文件作为程序的输入。这样一来程序从文件中而不是从键盘中获得输入数据,就避开了任意数字的输入问题。
这里要注意的是scanf把一些特殊数字作为分隔符,如果在scanf里仅有一个“%s”的话,分隔符之后的数据将不会被读取。这些数字为0x0A(新行),0x0C(换页),0x0D(返回),0x20(空格)。在输入文件中要避免使用这些特殊数字。

程序read2file.c从键盘输入4字节和格式化串,并将其存入文件
mystring中。

read2file.c代码:
格式化字符串实例_第7张图片

……
scanf("%u",&u_addr);	//输入需要改写内容的地址
……
scanf("%s",buf+4);	//输入格式字符串
……

由于地址随机化机制使得vul_formatstr2.c中的变量地址动态变化,为了使实验成功需要关闭地址随机化机制:

sudo sysctl -w kernel.randomize_va_space=0

在这里插入图片描述

假定要修改变量B的内容,设B的地址=0xbfffeca4=3221220516
在这里插入图片描述

因 此 read2file 从 键 盘 输 入 整 数 3221220516 和 格 式 串%08x.%08x.%08x.%08x.%08x.%08x.%08x.

编译read2file.c:
格式化字符串实例_第8张图片
运行:

格式化字符串实例_第9张图片
结果,修改成功:
格式化字符串实例_第10张图片

实验二

改写的值>0xffff时,上述方法不可用。
如果变量的值太大,需要分两次写内存才能避免可能的段错误。

变量B的值改成0xfedcba98:
修改read2file.c为read2file2.c,将输入的“地址”及“地址+2”输入到格式串的前3个(4字节)单元中。

read2file2.c代码:
格式化字符串实例_第11张图片
编译:
格式化字符串实例_第12张图片
运行:

格式化字符串实例_第13张图片
修改成功。

实验三

修改将变量B的值改成0xba98fedc

修改read2file2.c代码:
格式化字符串实例_第14张图片
编译:
格式化字符串实例_第15张图片
运行:
格式化字符串实例_第16张图片
修改成功。

你可能感兴趣的:(Vitualbox,Ubuntu,ubuntu)