其他
栈溢出原理与实践之读书笔记
本文为看雪论坛优秀文章
看雪论坛作者ID:瑞皇
新的一年想把0day漏洞安全这本书读完,会一步一步踏踏实实的学完,和大家共享笔记。
环境我想用vs2019运行,老的编译器很多人不用了,渐渐的会被淘汰。用新的编译器可以锻炼下编译选项的功底。
我的笔记是配合书写的,理论部分会少用笔墨,着重在实验上。
1
基础知识
2
栈溢出原理与实践
2.1 系统栈的工作原理
2.2 修改邻接变量
运行环境:
运行设置:
属性->c/c++->代码运行->基本运行时检查->关闭【堆栈帧 (/RTCs)】
然后运行代码,输入qqqqqqqq即,可完成简单的溢出覆盖。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PASSWORD "1234567"
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!\n\n");
}
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 [password]
00401615 push eax
00401616 call _strcmp (040103Ch)
0040161B add esp,8
0040161E mov dword ptr [authenticated],eax
strcpy(buffer, password);//over flowed here!
00401621 mov eax,dword ptr [password]
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 [password]
00E317D7 push eax
00E317D8 call _strcmp (0E31046h)
00E317DD add esp,8
00E317E0 mov dword ptr [authenticated],eax
strcpy(buffer, password);//over flowed here!
00E317E3 mov eax,dword ptr [password]
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可以获取该模块函数地址。
>>> hex(0x69E00000+0x83670)
'0x69e83670'
问题发生了,如何解决,这里使用Ollydbg查看模块地址。
>>> hex(0x75cc0000+0x83670)
'0x75d43670'
看雪ID:瑞皇
https://bbs.pediy.com/user-home-848111.htm
# 往期推荐
2.CVE-2021-4034 pkexec本地提权漏洞复现与原理分析
3.Microsoft Windows提权漏洞CVE-2013-3660 x86、x64双平台分析
6.什么是runC?
球分享
球点赞
球在看
点击“阅读原文”,了解更多!