BUPT软件安全实验六

1.目标

(1)通过%x来查看栈内容,重建栈内存,获得该frame的返回地址。

(2)通过%s查看指定地址内容。

(3)对sprintf函数及shellcode做解释分析。

(4)通过格式化字符串造成的缓冲区溢出覆盖返回地址,执行shellcode。

在这一过程中,我需要详述跟踪调试过程,在实验关键处进行截图说明。

(5)解决思考题,即:破解foo.exe程序,在不改变源代码的情况下,要求通过命令行输入,利用格式化字符串漏洞%n的方式,调用隐藏的foo函数,并尝试调用一个shellcode。

2.测试步骤与结果

(1)通过%x查看栈内容

代码如下所示:

        如上所示,执行printf时第四个%x没有提供对应的参数,因此会显示本应该是参数所在位置的栈内容。在OllyDbg中打开该程序以验证此推测:

        运行至CALL test._printf处,

        此时观察右下角:

        可以看到显示了本应该是参数所在位置的栈内容。

        通过更多的%x甚至可以重建大部分的栈内存:

(2)通过%s查看指定地址内容

        代码如下所示:

        运行后出现如下界面:

        在OllyDbg中打开程序,并执行printf函数:

        1,2,3是提供3个参数。利用%x步进,将%s的参数对应到77E61044,因此可以输出77E61044开始的字符串直到遇到截断符。0x0012FF58为format字符串起始地址,前四个字节即我们想要查看的内存地址77E61044:

(3)缓冲区溢出

        代码如下所示:

        作为向字符数组中写入数据的格式化输出函数,sprintf会假定存在任意长度的缓冲区。此处将字符数组user作为由用户构造的输入,其中出现了非常规字符%497d,是此次实验成功的关键。\x39\x4a\x42\x00是shellcode的起始地址,用来覆盖返回地址。\x90…\x33…\xD0…\x90为此次的弹框的shellcode:

        第一次调用sprintf(buffer,"ERR Wrong command:%.400s",user);时写入数据的目的地址为0x0012FB2C,格式化字符串为"ERR Wrong command:%.400s",%.400s对应的参数为起始地址为0x00424A30的字符串,即用户输入的字符数组user。对地址0x00424A30数据窗口跟随后可以看见该字符数组的内容:

        对地址0x0012FB2C查看ASCII数据,可见此时buffer中的字符串为"ERR Wrong command:%497d\x39\x4a\x42\x00",其后的数据由于0x00而被截断:

执行sprintf(outbuf, buffer);时buffer中格式化字符串为"ERR Wrong command:%497d\x39\x4a\x42\x00",根据格式化字符串,sprintf会读取一个参数以%497d的格式写入outbuf,由于未提供该参数,会自动将栈地址0x0012FAE0中的值视为该参数,即0x12FF80(十进制1245056)。需要写入outbuf的总字符串长度为19+497=516,而outbuf长度为512,因此会导致栈溢出,使得函数返回执行sprintf后outbuf中的内容。

        outbuf起始地址为0x0012FD2C,19字节的字符串"ERR Wrong command:"后为497字节的整型数字1245056,因此从0x0012FF30开始为\x39\x4a\x42\x00。下图可见成功将返回地址覆写为shellcode起始地址0x00424A39:

        继续执行,可以看到弹出对话框:

3.测试结论

        通过利用格式化输出函数的漏洞,可以达到查看栈内容、查看指定地址内容、构造缓冲区溢出以实现shellcode植入等目的。这一方面有助于我们对程序进行分析,另一方面,我们应该意识到,若攻击者掌握了这些漏洞利用方式,很有可能造成极大的破坏,需要采取相应的防范措施。

        通过这次测试,我对软件安全有了更深刻的认识,也意识到软件面临着极大的安全隐患,需要我们去保护和守卫。而要达到这一点,我们要去主动学习更多的知识、熟悉使用更加强有力的工具。

4.思考题

        破解foo.exe程序,在不改变源代码的情况下,要求通过命令行输入,利用格式化字符串漏洞 %n的方式,调用隐藏的foo函数,并尝试调用一个shellcode       foo.exe程序代码如下:

        首先分析一下程序的源代码,看它是干什么的:main函数中根据命令行提供的参数打开对应的文件。如果这个文件不存在,那么就调用PrintMessage函数打印相应的错误信息。在PrintMessage函数中把错误分为GhastlyError和RecoverableError两类。要想调用foo函数,可以通过%n把fErrFunc函数的地址修改为foo函数的地址。命令行参数为:%x%x…%x%x%n+fErrFunc函数指针的地址。snprintf之后buf为Can'tFind%x%x…%x%x%n+fErrFunc函数指针的地址,接下来由于fprintf(stdout, buf)中缺少了argument参数,所以已打出的字符总数通过%n被写入fErrFunc函数指针的地址。通过控制%x调整已打出的字符总数就能达到我们的目的。在OllyDbg中,点击调试->参数,向程序传递命令行参数。首先尝试一串%x:

%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x

        可以看到fErrFunc的地址是0x0012FF18,2578是%x的ASCII码。现在在后面加上%pABC试试:

%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%pABC

        由分析可得,需要把\x18\xff\x12放置在一个可写位置,在前面加上"."来调整%x输出的内容。

.......%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%pABC

        现在把%p改成%hn,因为多了一个"h",所以前面少一个"."。在后面还要放上\x18\xff\x12:

        如下所示,0x0012FF18处的值已经被改成0040017E:

foo的地址是0x00401014,现在写入的值是0x0040017E,还差3734个字节。

        需要注意的是,这里是3744不是3734,因为原来第一个%x打印了6个字节,为了对齐删掉了4个"."又少打印了4个字节,所以要把总共少打印的这10个字节加回去。从下图可以看出第一个%x对应的内容是0012FF80,只打印了12FF80;第二个%x对应的内容是00000000,只打印了0;从第三个%x开始正常打印8个字节:

        再次运行程序,可以看到成功调用了隐藏的foo函数:

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值