首页
论坛
课程
招聘
[原创]栈溢出原理与实践之读书笔记
2022-2-8 14:07 26345

[原创]栈溢出原理与实践之读书笔记

2022-2-8 14:07
26345

0.前言

新的一年想把0day漏洞安全这本书读完,会一步一步踏踏实实的学完,和大家共享笔记。
环境我想用vs2019运行,老的编译器很多人不用了,渐渐的会被淘汰。用新的编译器可以锻炼下编译选项的功底。
我的笔记是配合书写的,理论部分会少用笔墨,着重在实验上。

1.基础知识

这一部分书上讲解的足够了,如果暂时看不懂,多看看就好。功夫不负有心人,迟早学会的事情。

2.栈溢出原理与实践

2.1.系统栈的工作原理

这一部分书上讲解的足够了,如果暂时看不懂,多看看就好。功夫不负有心人,迟早学会的事情。

2.2.修改邻接变量

运行环境:

VS2019 X86 Debug

运行设置:

属性->c/c++->常规->sdl检查关闭
属性->c/c++->代码运行->基本运行时检查->关闭【堆栈帧 (/RTCs)】
然后运行代码,输入qqqqqqqq即,可完成简单的溢出覆盖。
图片.png

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
27
28
29
30
31
32
#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)的关闭,则是为了让程序不在运行时检查程序。
如果不关闭堆栈帧 (/RTCs),原本buffer[8]会因为检查多出8字节。然后程序报错,我原本以为时字符对齐的问题,检查后发现不是。是运行时检查的问题。
图片.png
图片.png

 

关闭堆栈帧 (/RTCs)的汇编代码:

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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

开启堆栈帧 (/RTCs)的汇编代码:

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
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

通过代码的比较,我们可以发现,函数使用@_RTC_CheckStackVars@8进行检测,跟进去发现该函数容纳了两个_RTC_CheckStackVars,当检测不是0CCCCCCCCh的时候,会报错,并进入_RTC_StackFailure函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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++->常规->sdl检查关闭
属性->c/c++->代码运行->基本运行时检查->关闭【堆栈帧 (/RTCs)】

实验情况:

修改上述配置后,发现无法正常运行,单步调试发现fopen断点出现问题。搜索查询后发现有些编译器不支持rw+的格式。这里我们将rw+修改为r+即可正确运行。r和r+的区别是r+拥有写权限。我大胆猜测,rw+不支持的原因是功能设计上的重复。

在这里我们运行还会遇到一个问题

我们需要把栈保护天使GS关闭。
属性->c/c++->代码运行->安全检查->关闭【禁用安全检查 (/GS-)】
这个时候代码就会报书上期望我们出现的错误,返回值出现错误。理论方面书上说的已经很全面,这里就简单画个图。

最终结果如下图,符合书上预期:

2.4.向进程中植入代码

运行环境:VS2019 X86 Debug

运行设置:

属性->c/c++->常规->sdl检查关闭
属性->c/c++->代码运行->基本运行时检查->关闭【堆栈帧 (/RTCs)】
属性->c/c++->代码运行->安全检查->关闭【禁用安全检查 (/GS-)】

实验情况:

创建一个文件,password.txt,构造shellcode。这里按照书上就好,然后看下面的步骤。

配置需要进行修改,因为要静态获取buffer地址,aslr随机基址要关闭,因为要在数据区执行代码,数据执行保护(DEP)也要关闭。
属性->链接器->高级->随机基址->否
属性->链接器->高级->数据执行保护(DEP)->否

 

password.txt,有两个地方需要修改,根据书中描述。
一个是Messagebox的地址,在下图中会讲解如何寻找。
一个是buffer的地址,下文中也会详细介绍细节。

我们在程序中添加messagebox,这样我们的代码就会调用User32.dll,我们使用dependency可以获取该模块函数地址。

根据书中方法,计算正确值

1
2
>>> hex(0x69E00000+0x83670)
'0x69e83670'

但是可以看到,程序并不能正确运行,这问题常出在现在的windows操作系统里,优先基址常常不是实际加载地址,在PE格式中DLL会给出一个优先加载地址,当程序并未占用该地址时,优先按照该基址进行计算。占用的话,会重新申请空间。
问题发生了,如何解决,这里使用Ollydbg查看模块地址。

 

下面是Ollydbg的正确解决方案
步骤1:点击E字母

步骤2:找到User32,此时使用该模块地址计算,可以获得正确地址,成功弹出messagebox
如果不想算,就按一下User32,快捷键ctrl+n,找到messageboxA一样可以。

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



 

注:
不知不觉三阶段快毕业了,非常感谢科锐的指导,科锐的耐心指导,才能够让我的基础越加雄厚。
非常感谢钱老师、张老师、王老师、田老师、唐老师、江老师。
尤其王老师,陪伴我们走了最长的路,还记得科锐学习的时候经常学崩溃,因为任务量多,对新手难。
有一次哭着和王老师聊天,王老师帮我排解压力、还把笔记借给我学习,非常感谢。
这是估计是我在科锐期间最后一次发帖了,在此纪念一年的学习时光。
祝科锐越来越好,也祝自己越来越好。


看雪招聘平台创建简历并且简历完整度达到90%及以上可获得500看雪币~

最后于 2022-3-7 11:56 被瑞皇编辑 ,原因:
上传的附件:
收藏
点赞2
打赏
分享
打赏 + 50.00雪花
打赏次数 1 雪花 + 50.00
 
赞赏  Editor   +50.00 2022/03/02 恭喜您获得“雪花”奖励,安全圈有你而精彩!
最新回复 (3)
雪    币: 21
活跃值: 活跃值 (361)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lukarl 活跃值 2022-2-8 17:51
2
1
有配套的视频课程
https://ke.qq.com/course/3485787?tuin=178b36ba
都是参考0Day这本书的
雪    币: 1000
活跃值: 活跃值 (892)
能力值: ( LV4,RANK:55 )
在线值:
发帖
回帖
粉丝
瑞皇 活跃值 2022-2-8 19:08
3
0
lukarl 有配套的视频课程 https://ke.qq.com/course/3485787?tuin=178b36ba 都是参考0Day这本书的
咦,还有这个东西呀,谢谢提醒了~
不过他只有前四章还要88,觉得有点贵了,我的需求是整本书读完。
目前刷起来不是很吃力,我还是愿意更扎实的慢慢看书。
谢谢小伙伴啦
雪    币: 411
活跃值: 活跃值 (299)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
冷酷的果冻 活跃值 2022-3-4 20:11
4
0
赞赞赞
游客
登录 | 注册 方可回帖
返回