0x01 筹备
拿到程序首先查看下文件属性,是32位的elf可执行文件,开启了NX(将数据所在页标识为不可执行),RELRO(设置符号重定向表为只读或在程序启动时就解析并绑定所有动静符号,Partial RELRO阐明咱们对got表具备写权限),Stack Canary found阐明对栈进行了爱护,个别不可笼罩函数返回地址进行攻打。
执行函数能够看到先让咱们输出name,再让咱们输出了message,有输出的中央都有可能触发破绽。
0x02 操作
1、应用ida查看源代码,能够看到printf(&s)处存在格式化字符串破绽。而咱们的指标是使全局变量pwnme处的值为8,咱们要想方法把8写到pwnme(0804A068)的地位。
2、上面咱们来剖析下格式化字符串破绽原理
失常的printf的函数为
printf("test %d,test %s ",123,"test")
函数参数压栈程序为从右向左
堆栈图如图所示
如果printf写成printf(&s)的模式,那么会把s代表的字符串当成format。如果s=“%x%x%x”,就会从format所在地址往下读取3个32bit的值,而这三个4字节数据位于main函数的堆栈中,如图所示
咱们能够用printf中的%n来进行利用。
%n:将%n之前printf曾经打印的字符个数赋值给指针所指向的地址
%N$n:将%n之前printf曾经打印的字符个数赋值给间隔format所在地址向高地址偏移N*4字节的地址外面的指针所指向的值(32位程序为32/8bit)
0x03 利用
1、查看伪代码,咱们能够看到s变量间隔main函数栈顶为28h个字节,即10进制的40个字节。
2、咱们输出的message将存在以s变量地址为起始的地位处。而s间隔format偏移为10(10*4个字节)。咱们只有把pwnme的地址(4个字节)放在s的起始地位,再加上4个字节,接着存入%10$n,即可实现将(4+4)8存入间隔format偏移10这个地址外面的值所指向的地址(即pwnme的地址)。
利用堆栈图如下:
3、代码
from pwn import * context(os='linux', arch='i386', log_level='debug')#sh=remote("",45107) sh=process("./cgfsb")elf=ELF("./cgfsb")pwnme=elf.symbols['pwnme']#print("%x"%pwnme)payload=p32(pwnme)+p32(0x11111111)+b"%10$n" sh.sendlineafter("name",str(1))sh.sendlineafter("please",payload)sh.interactive()
4、胜利获取到flag