格式化字符串漏洞实验
格式化字符串漏洞是由像 printf(user_input) 这样的代码引起的,其中 user_input 是用户输入的数据,具有 Set-UID root 权限的这类程序在运行的时候,printf 语句将会变得非常危险。
-
实验一:
找出 secret[1]的值
输入命令:
ls
vi test.c
gcc -z execstack -fno-stack-protector -o djw test.c
其中test.c的代码为
include <stdlib.h>
include <stdio.h>
define SECRET1 0x44
define SECRET2 0x55
int main(int argc, char *argv[])
{
char user_input[100];
int *secret;
long int_input;
int a, b, c, d; /* other variables, not used here.*/
/* The secret value is stored on the heap */
secret = (int *) malloc(2*sizeof(int));
/* getting the secret */
secret[0] = SECRET1; secret[1] = SECRET2;
printf("The variable secret's address is 0x%8x (on stack)
", &secret);
printf("The variable secret's value is 0x%8x (on heap)
", secret);
printf("secret[0]'s address is 0x%8x (on heap)
", &secret[0]);
printf("secret[1]'s address is 0x%8x (on heap)
", &secret[1]);
printf("Please enter a decimal integer
");
scanf("%d", &int_input); /* getting an input from user */
printf("Please enter a string
");
scanf("%s", user_input); /* getting a string from user */
/* Vulnerable place */
printf(user_input);
printf("
");
/* Verify whether your attack is successful */
printf("The original secrets: 0x%x -- 0x%x
", SECRET1, SECRET2);
printf("The new secrets: 0x%x -- 0x%x
", secret[0], secret[1]);
return 0;
}
编译后进行执行,如图
首先定位 int_input 的位置,这样就确认了%s 在格式字符串中的位置(由于与文档上000000000000000C不一致,所以要进一步确定位置)
用%08x进行显示,如图
输入 secret[1]的地址,记得做进制转换,同时在格式字符串中加入%s,如图
U 的 ascii 码就是 55。
修改 secret[1]的值
如果只要求修改,不要求改什么,可以利用%n进行修改,修改如下:
修改 secret[1]为期望值
要改成自己期望的值,可以进行填充:
%n可以进行计数,0x3e8 = 1000。
-
实验二:
include <sys/types.h>
include <sys/stat.h>
include <fcntl.h>
int main()
{
char buf[1000];
int fp, size;
unsigned int *address;
/* Putting any number you like at the beginning of the format string */
address = (unsigned int *) buf;
*address = 0x113222580;
/* Getting the rest of the format string */
scanf("%s", buf+4);
size = strlen(buf+4) + 4;
printf("The string length is %d
", size);
/* Writing buf to "mystring" */
fp = open("mystring", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (fp != -1) {
write(fp, buf, size);
close(fp);
} else {
printf("Open failed!
");
}
}
现在让我们把第一个实验中的 scanf 语句去掉,并去掉与 int_input 变量相关的所有语句,同时设置关闭地址随机化选项。操作如下:
在这里,刚开始碰到了问题,权限不够。后来用sudo进行提权,要输入密码,根据以往设计者的情况,密码为dees,进行提权后指令即可执行成功。
修改 secret[0]的值
修改 test.c 后编译 test.c 与 write_string.c 然后通过 write_string 程序将内容输入进 mystring 文件中,文件内容包括代码中加入的头四个字节和你之后输入的内容。实验过程如下:
在这里试验了好多次,由于刚开始没有找准位置,以为./test不需要,./write_string之后直接按之前的位置安放%n进行输入就好。导致The original secrets和The news secret内容一致,甚至出现segmentation fault的情况。后来总结了一下,重新对test进行测试,找准了位置,再进行上面命令的输入,就得到了准确的结果。
0x31=49=5*8+5个逗号+开头4个字节。