黑客教你几招消灭代码漏洞的方法

指针释放完后必须置为空指针

86aeaf295279a51f46ea885a1a64874d.png

cfbaa1ee312ec20860d7f920b2a56616.png

指针释放没处理好,容易引发高风险漏洞:内存破坏漏洞。

在编程中对指针进行释放后,需要将该指针设置为NULL,以防止后续free指针的误用,从而导致UAF (Use After Free)等其他内存破坏问题。尤其在结构体、类里面存储的原始指针。

错误释放指针范例

9e19afd2a11875285a8d2f399178c58d.png

正确释放指针范例

0c6e8560d0b93d20bbc7e5c03d4e3e4c.png

针对指针释放建议的解决方案:建议使用string、vector、智能指针等代替原始内存管理机制,这样可以大量减少这类型的错误。

指针应用时必须检查空指针

9fd0d66f1dc0826ea6274c278c5049ff.png

a4a650c9f55039194aeed4f738e3c6fa.png

这类问题没处理好,容易引发低风险的拒绝服务漏洞风险

下面是检查空指针范例

45be97df2a29c70759703ef08bf9dfb8.png

注意检查指针大小的方式

6fd8029be4ac6697e738471df1d9cc71.png

47d539fcdb9f3c14ec76b339b19494c9.png

检查指针大小没处理好,它会引发中风险逻辑漏洞的风险

下面是检查指针大小范例

16de8a58fa8aa5163b0b2ed825aaffe5.png

智能指针使用安全

33f0d0e7e04ffcb7b53e69aee34c0543.png

1e17e28bf56a6410558cbb2e0cf21e8f.png

智能指针如果没应用好,会引发高风险漏洞:内存破坏漏洞

在编程中使用智能指针时候,必须防止智能指针和原始指针混用,否则可能会导致对象生命周期问题,例如UAF安全风险。

错误的使用智能指针

74b5c2c49ce5cfd594a9551c6e3905d3.png

正确的使用智能指针

4b56703e3670c9af19bf7c1b745d5b9b.png

防止错误类型转换

d9a4ffa17573232e257731b1bc3b9f89.png

239ef38df20a546669c223155fa9d201.png

类型转换处理不好会引发高风险的漏洞:内存破坏漏洞

在编程中对指针、对象或变量进行操作时,需要能够正确判断所操作对象的原始类型。如果使用了与原始类型不兼容的类型进行访问操作,那么代码就会存在安全的隐患。

错误类型转换范例

5e5ff55e0632a5d3d2da5be48454b422.png

正确使用类型转换范例

d29953e3521e7cc92db1af3f2f8810c4.png

不可直接使用无长度限制的函数

a29f5fa6bfca1d832e6d02d42d956c9c.png

d9fcf2a2eadfba7282df3f1e4e245c67.png

使用无长度限制的的函数,它会引发中风险漏洞和高风险漏洞:信息泄露漏洞和缓冲区溢出漏洞。

不能直接使用无长度限制的字符串拷贝、输入函数、例如:strcpy、sprintf、wcscpy、mbscpy等函数,这些函数的特征是:通过输入一长串字符串,而不限制长度。如果环境允许,应当使用_s安全版本替代,或者使用n版本函数(如:snprintf,vsnprintf)。

若使用形如sscanf之类的函数时,在处理字符串输入时应该通过%10s这样的方式来严格限制字符串长度,同时确保字符串末尾有\0。如果环境允许应该使用_s安全版本。

在使用n系列拷贝函数时,要确保正确计算缓冲区长度,同时,如果你不确定是否地面在各个编译器下都能确保末尾有0时候,建议增加1字节输入缓冲区,并将其置为\0,以确保输出的字符串结尾一定有\0。

建议使用方案:在C++中,建议用string、vector等更高封装层的基础组件代替原始指针和动态数组,可以有效提高代码的可读性和安全性。

调用启动进程类的系统函数的安全做法

0f1b47683b5b1ea26078def2ab0d5035.png

1aed0a7c961f2cc1c7580c9fc38eecae.png

没调用好启动进程类的系统函数,它会引发两大高风险漏洞:代码执行漏洞和权限提升漏洞。

在调用如 system、WinExec、CreateProcess、SheellExecute等启动进程类的函数,需要严格检查函数的参数。

当启动时从用户输入、环境变量读取组合命令行时,还需要注意是否可能存在命令注入风险。最好进行检查用户输入是否含有非法数据。

下面可以借鉴的范例

d6037ad623d4437d3b4d0a45bfc30c83.png

尽量不要使用_alloca和可变长度数组

5be3623c8488b9c37d1c2ea32ffb67da.png

a738f5a3982d03237c0fd2fe4068f25d.png

使用_alloca和可变长度数组,它可能会引发低风险和高风险漏洞:拒绝服务漏洞和内存破坏漏洞。

_alloca和可变长度数组使用的内存量在编译期间是未知的,尤其是在循环中使用时,根据编译器的实现不同,可能会导致:1.栈溢出;2.缺少栈内存测试的编译器实现可能导致申请到非栈内存,并导致内存损坏。

对于C++,可变长度数组也是非标准扩展,在代码规范中禁止使用。

307e4a950a75ebbb6a001d85c660b7b8.png

调用printf系列函数,参数必须对应

68752ac81b7910e7861134ec8edb1923.png

d1439f28eac909012fffa036645f33b8.png

调用printf系列函数没处理好会引发中风险漏洞:信息泄露漏洞

调用printf系列函数,如sprintf,snprintf,vprintf等必须对应控制符号和参数。

573cbdd4ca8c36cc43913601f04bf8b1.png

不要把用户可修改字符串作为printf系列函数的“format”参数

6f332c4d6e8d00febd489351b55a0825.png

8ef998360122bf722879899f1c50fea0.png

这个没处理好,它会引发低风险、中风险和两大高风险漏洞:拒绝服务、信息泄露、内存破坏和代码执行漏洞。

如果用户可以控制字符串,则通过%n、%p等内容,最坏情况洗可以直接执行任意恶意代码。

7db0ff890b3d6edb6b7900e0b91ea210.png

对数组delete时需要使用delete[]

7e88c33cfdf173225734c483c243cc39.png

2fca638be555693b9a9eebd2240bd831.png

这个没处理好,它会引发低风险、中风险和高风险漏洞:内存泄漏、逻辑漏洞、内存破坏漏洞

delete []操作符用于删除数组。delete操作符用于删除非数组对象。它们分别调用operator delete[]和operator delete。

建议的解决方案在C++代码中,使用string、vector、智能指针(比如std::unique_ptr)等可以消除绝大多数 delete[] 的使用场景,并且代码更清晰。

ed6652977712451fdd1dc7c00d4d3770.png

使用switch中必须使用default

ab99a66a6152ed473a1e66ca2e34c95c.png

fc2ebe899dd4833e0df5404a9fa944a9.png

编程中switch没应用好,它会引发两大中风险漏洞:逻辑漏洞、内存泄漏漏洞。

switch中应该有default,以处理各种预期外的情况。这可以确保switch接受用户输入,或者后期在其他开发者修改函数后确保switch仍可以覆盖到所有情况,并确保逻辑正常运行。

c9bc664487b5622ce51aeb42d0df1123.png

在debug版本或错误信息中不提供过多信息。

1a4ef37f4c598e9123fff320618bf1f2.png

379ac3af65481d4aa7310cb419ff9f12.png

提供过多的信息,这会引发中风险的信息泄露漏洞。

包含过多信息的Debug消息不应当被用户获取到。Debug信息可能会泄露一些值,例如内存数据、内存地址等内容,这些内容可以帮助攻击者在初步控制程序后,更容易地攻击程序。

不能返回栈上变量的地址和使用未初始化栈变量

1d06d190a2970d51348848b52ed30943.png

03ff8ec0ec92122606f91da431d18a75.png

这个情况,会引发高风险的内存破坏漏洞。

函数不可以返回栈上的变量的地址,它的内容再函数返回后就会失效,可以用堆类传递简单类型变量。

在栈上声明的变量使用之前确认是否已经初始化了。最好是在声明变量的时候,就直接初始化变量值。

建议方案:强烈建议返回 string、vector 等类型,会让代码更加简单和安全。

错误的范例

7241653b44284b8faf711156df257505.png

正确的用法范例

444b13c6922ce9a8c8983e17df78ce96.png

函数的每个分支都应该有返回值

029a4e95fee40a819f29bb27102d2001.png

f4ce86f40bc49e973e7f1f90d803a4af.png

函数中的分支没处理好,它会引发两大中风险漏洞:信息泄露,逻辑漏洞。

函数的每个分支都应该有返回值,否则如果函数走到无返回值的分支,其结果是未知的。

错误用法的范例

1a8eb53c0cf28f7d312c8957279eb77e.png

正确用法的范例

f843dde35a3708076419716598c92908.png

在多线程中变量应确保线程安全性

c979c9dce0abe7d59d61a68a65207b3a.png

9080fba2d6bf6e3040c28026fecfb4a4.png

线程中的变量没处理好,它会引发两大中风险漏洞:信息泄露,逻辑漏洞。

当一个变量可能被多个线程使用时,应当使用原子操作或加锁操作。

建议解决方案:

对于C代码,C11 后推荐使用 atomic 标准库。

对于C++代码,C++11后,推荐使用 std::atomic。

错误用法范例

663056e55e286ddbcbe1dda8244e5895.png

正确用法范例

0a73f1deca5306130bbae3d42a64f9e2.png

在程序中不得明文存储敏感信息。

e38420665d1cebe48f9dd8aa80df7290.png

098dbdb288be62e4b5c2dae224a3bf56.png

存储明文信息,它会引发高风险漏洞风险:敏感信息泄露漏洞。

用户的敏感信息应该使用加密算法进行做处理,并做到传输过程中加密,存储过程中加密,存储状态下加密。在程序运行内存中的用户敏感信息应该完全抹除。

使用rand()类函数应正确初始化

8d2784521ef5243b8d78144f6bd573b4.png

8c701e99765e7b8db7d82b85aac96a2e.png

编程中rand函数没有正确初始化,它会引发逻辑漏洞的高风险漏洞。

在编程中,rand类函数的随机性并不高。而且在使用前需要使用srand()来初始化。未初始化的随机数可能导致某些内容可预测。

38e94fe01f8c589cc90fa6eae22e4f1a.png

操作文件时候避免路径穿越问题

104a4cd952ad8e329e402624bec09842.png

cfe6bce96dfa0adfa986779be0054706.png

编程中,如果文件路径没处理好,它会引发高风险的逻辑漏洞。

在进行文件操作时,需要判断外部传入的文件名是否合法,如果文件名中包含 ../ 等特殊字符,则会造成路径穿越,导致任意文件的读写。

42dc0e43950de1c7452434f9f083d8b5.png

避免相对路径导致被劫持的问题

87dda0424bcef7437660c7ffd540caeb.png

0b8ea76b426dc429a5c2fc52d5c28549.png

编程中相对路径没处理好会引发逻辑漏洞风险。

在编程中,使用相对路径可能导致一些安全风险,例如DLL、EXE劫持等问题。

针对DLL劫持编码安全的建议:

  1. 调用LoadLibrary,LoadLibraryEx,CreateProcess,ShellExecute等进行模块加载的函数时,指明模块的完整(全)路径,禁止使用相对路径,这样就可避免从其它目录加载DLL。

  2. 在应用程序的开头调用SetDllDirectory(TEXT("")); 从而将当前目录从DLL的搜索列表中删除。

    结合SetDefaultDllDirectories,AddDllDirectory,RemoveDllDirectory这几个API配合使用,可以有效的规避DLL劫持问题。

f31cb6ee5f7b48ef48f1f1cfeb8732eb.png

文件权限控制

f5b6857809789850663da966130d7056.png

d70e2c595de460e5b66471d46e38088c.png

编程中,文件权限没处理好,它会引发中风险的逻辑漏洞风险。

在创建文件时,需要根据文件的敏感级别设置不同的访问权限,以防止敏感数据被其他恶意程序读取或写入。

f3394fe1f9044b8d047a43a81bfa4fe4.png

防止整数溢出

9bc9cd8743625bedcdb757fd9a58727a.png

3e95c08392f5af5750ba8087ed591b99.png

在编程中,数据操作时候没处理好,它会引发高风险的漏洞:内存破坏。

在计算时需要考虑整数溢出的可能,尤其在进行内存操作时,需要对分配、拷贝等大小进行合法校验,防止整数溢出导致的漏洞。

错误用法范例

88f40b4b08d0afec2625bdaff4a884c0.png

正确用法范例

7c9a91ad936397a88cc524ca140baed1.png

防止Off-By-One漏洞

11ceea2286ef9569f0d0096c2fe98c41.png

cfb31f02debbb56c0e1ca39b8c96b28b.png

计算和操作数据的时候没处理好,它会引发高风险漏洞:内存破坏

在进行计算或者操作时,如果使用的最大值或最小值不正确,使得该值比正确值多1或少1,可能导致安全风险。

解决方案:建议使用 string、vector 等组件代替原始指针和数组操作。

7b39450252e371876e036fad2c94c8ad.png

运算时检查除以零异常

bf3a9b8af8ff2a4af93366c98ca3e996.png

3f3173e5d5910317748d565640cd30e0.png

编程中,数据运算没检查除以零的情况,它会引发低风险的漏洞:拒绝服务漏洞。

在进行除法运算时,需要判断被除数是否为零,以防导致程序不符合预期或者崩溃。

6d0266a1683691ecdd826172bede5129.png

防止数字类型的错误强转

d6f1c38a8a96664dd7af0fa769367e46.png

b42d4ee72d233ee3c4d5fc504c059360.png

在编程中数值类型没处理好,它会引发中风险逻辑漏洞和高风险内存破坏漏洞。

在有符号和无符号数字参与的运算中,需要注意类型强转,它可能导致的逻辑错误,建议指定参与计算时数字的类型或者统一类型参与计算。

下图是参考范例

2bd7b1629a795ab1fc1f69d9ddde369f.png

比较数据大小时加上最小或最大值的校验

b63555218fcdd841d1c1a579dd1c83fd.png

5c0237faa2c7f040fe0059366f676926.png

编程中数据比较没处理好,它会引发高风险的内存破坏漏洞

在编程中进行数据大小比较时,要合理地校验数据的区间范围,建议根据数值类型,对其进行最大和最小值的判断,以防止非预期错误。

9fd01f5ae06db5dffde2fe0e27242b19.png

49c9732aa1b0ca63c4ab63e86f0b523a.png

E N D

dd1f5941a192beed315c612cc1a6dd1f.png

 
 

推荐阅读:

阿里黑客入门学习资料流出来了!!

推荐收藏黑客APP破解常用工具集合!

6步傻瓜式点击在树莓派上安好Win11

红蓝攻防演练资产收集小工具

bd7189a578229d74e444632c99f141ef.png

 
 
最近整理一份小白入门黑客资料《初学者如何入门黑客教程》,覆盖了网络渗透、网络攻击、防御、各种黑客常用工具入门等等。
获取方式:关注公众号并回复 黑客 领取,更多内容陆续奉上。

明天见(。・ω・。)ノ♡

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值