本文为看雪论坛优秀文章
看雪论坛作者ID:瑞皇
新的一年想把0day漏洞安全这本书读完,会一步一步踏踏实实的学完,和大家共享笔记。
环境我想用vs2019运行,老的编译器很多人不用了,渐渐的会被淘汰。用新的编译器可以锻炼下编译选项的功底。
我的笔记是配合书写的,理论部分会少用笔墨,着重在实验上。
1
基础知识
2
栈溢出原理与实践
2.1 系统栈的工作原理
2.2 修改邻接变量
运行环境:
运行设置:
属性->c/c++->代码运行->基本运行时检查->关闭【堆栈帧 (/RTCs)】
然后运行代码,输入qqqqqqqq即,可完成简单的溢出覆盖。
int verify_password(char* password)
{
int authenticated;
char buffer[8];// add local buffto be overflowed
authenticated = strcmp(password, PASSWORD);
strcpy(buffer, password);//over flowed here!
return authenticated;
}
void main()
{
int valid_flag = 0;
char password[1024];
while (1)
{
printf("please input password: ");
scanf("%s", password);
valid_flag = verify_password(password);
if (valid_flag)
{
printf("incorrect password!nn");
}
else
{
printf("Congratulation! You have passed the verification!n");
break;
}
}
}
实验情况:SDL关闭和头文件的增加为了让程序代码跑起来。
如果不关闭堆栈帧 (/RTCs),原本buffer[8]会因为检查多出8字节。然后程序报错,我原本以为时字符对齐的问题,检查后发现不是。是运行时检查的问题。

int verify_password(char* password)
{
004015F0 push ebp
004015F1 mov ebp,esp
004015F3 sub esp,50h
004015F6 mov eax,dword ptr [__security_cookie (0407004h)]
004015FB xor eax,ebp
004015FD mov dword ptr [ebp-4],eax
00401600 push ebx
00401601 push esi
00401602 push edi
00401603 mov ecx,offset _06E17EB3_Test@cpp (0409008h)
00401608 call @__CheckForDebuggerJustMyCode@4 (0401285h)
int authenticated;
char buffer[8];// add local buffto be overflowed
authenticated = strcmp(password, PASSWORD);
0040160D push offset string "1234567" (0405B30h)
00401612 mov eax,dword ptr
00401615 push eax
00401616 call _strcmp (040103Ch)
0040161B add esp,8
0040161E mov dword ptr [authenticated],eax
password);//over flowed here!
00401621 mov eax,dword ptr
00401624 push eax
00401625 lea ecx,[buffer]
00401628 push ecx
00401629 call _strcpy (040119Ah)
0040162E add esp,8
return authenticated;
00401631 mov eax,dword ptr [authenticated]
}
00401634 pop edi
00401635 pop esi
00401636 pop ebx
00401637 mov ecx,dword ptr [ebp-4]
0040163A xor ecx,ebp
0040163C call @__security_check_cookie@4 (040111Dh)
00401641 mov esp,ebp
00401643 pop ebp
00401644 ret
int verify_password(char* password)
{
00E317A0 push ebp
00E317A1 mov ebp,esp
00E317A3 sub esp,0E0h
00E317A9 push ebx
00E317AA push esi
00E317AB push edi
00E317AC lea edi,[ebp-20h]
00E317AF mov ecx,8
00E317B4 mov eax,0CCCCCCCCh
00E317B9 rep stos dword ptr es:[edi]
00E317BB mov eax,dword ptr [__security_cookie (0E3A004h)]
00E317C0 xor eax,ebp
00E317C2 mov dword ptr [ebp-4],eax
00E317C5 mov ecx,offset _06E17EB3_Test@cpp (0E3C008h)
00E317CA call @__CheckForDebuggerJustMyCode@4 (0E3132Fh)
int authenticated;
char buffer[8];// add local buffto be overflowed
authenticated = strcmp(password, PASSWORD);
00E317CF push offset string "1234567" (0E37B30h)
00E317D4 mov eax,dword ptr
00E317D7 push eax
00E317D8 call _strcmp (0E31046h)
00E317DD add esp,8
00E317E0 mov dword ptr [authenticated],eax
password);//over flowed here!
00E317E3 mov eax,dword ptr
00E317E6 push eax
00E317E7 lea ecx,[buffer]
00E317EA push ecx
00E317EB call _strcpy (0E31212h)
00E317F0 add esp,8
return authenticated;
00E317F3 mov eax,dword ptr [authenticated]
}
00E317F6 push edx
00E317F7 mov ecx,ebp
00E317F9 push eax
00E317FA lea edx,ds:[0E31828h]
00E31800 call @_RTC_CheckStackVars@8 (0E311EFh)
00E31805 pop eax
00E31806 pop edx
00E31807 pop edi
00E31808 pop esi
00E31809 pop ebx
00E3180A mov ecx,dword ptr [ebp-4]
00E3180D xor ecx,ebp
00E3180F call @__security_check_cookie@4 (0E31154h)
00E31814 add esp,0E0h
00E3181A cmp ebp,esp
00E3181C call __RTC_CheckEsp (0E31253h)
00E31821 mov esp,ebp
00E31823 pop ebp
00E31824 ret
00E31825 nop dword ptr [eax]
00E31828 add dword ptr [eax],eax
00E3182A add byte ptr [eax],al
00E3182C xor byte ptr [eax],bl
00E3182E jecxz __$EncStackInitStart+84h (0E31830h)
00E31830 in al,0FFh
00E31832 ?? ??????
}
00E31833 dec dword ptr [eax]
00E31835 add byte ptr [eax],al
00E31837 add byte ptr [eax+ebx],bh
00E3183A jecxz __$EncStackInitStart+90h (0E3183Ch)
00E3183C bound esi,qword ptr [ebp+66h]
00E3183F jb 00001843
006E1DD4 mov ecx,dword ptr [ebx+4]
006E1DD7 mov eax,dword ptr [frame]
006E1DDA mov edx,dword ptr [ecx+edi]
006E1DDD cmp dword ptr [edx+eax-4],0CCCCCCCCh
006E1DE5 jne _RTC_CheckStackVars+39h (06E1DF9h)
006E1DE7 mov eax,dword ptr [ecx+edi+4]
006E1DEB add eax,edx
006E1DED mov edx,dword ptr [frame]
006E1DF0 cmp dword ptr [eax+edx],0CCCCCCCCh
006E1DF7 je _RTC_CheckStackVars+49h (06E1E09h)
006E1DF9 push dword ptr [ecx+edi+8]
006E1DFD mov eax,dword ptr [ebp+4]
006E1E00 push eax
006E1E01 call _RTC_StackFailure (06E1352h)

2.3 控制程序的执行流程
运行环境:VS2019 X86 Debug
运行设置:
属性->c/c++->代码运行->基本运行时检查->关闭【堆栈帧 (/RTCs)】
实验情况:

在这里我们运行还会遇到一个问题:
我们需要把栈保护天使GS关闭。
这个时候代码就会报书上期望我们出现的错误,返回值出现错误。理论方面书上说的已经很全面,这里就简单画个图。

最终结果如下图,符合书上预期:
2.4 向进程中植入代码
运行环境:VS2019 X86 Debug
运行设置:
属性->c/c++->代码运行->基本运行时检查->关闭【堆栈帧 (/RTCs)】
属性->c/c++->代码运行->安全检查->关闭【禁用安全检查 (/GS-)】
实验情况:
配置需要进行修改,因为要静态获取buffer地址,aslr随机基址要关闭,因为要在数据区执行代码,数据执行保护(DEP)也要关闭。
属性->链接器->高级->随机基址->否
属性->链接器->高级->数据执行保护(DEP)->否
一个是Messagebox的地址,在下图中会讲解如何寻找。
一个是buffer的地址,下文中也会详细介绍细节。

我们在程序中添加messagebox,这样我们的代码就会调用User32.dll,我们使用dependency可以获取该模块函数地址。
0x69E00000+0x83670) > hex(
'0x69e83670'
问题发生了,如何解决,这里使用Ollydbg查看模块地址。

0x75cc0000+0x83670) > hex(
'0x75d43670'


看雪ID:瑞皇
https://bbs.pediy.com/user-home-848111.htm
#
原文始发于微信公众号(看雪学苑):栈溢出原理与实践之读书笔记
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论