[pwn基础] Linux安全机制

Canary(栈溢出保护)

Canary:(取名自地下煤矿的金丝雀,因为它能够比旷工更早的发现煤气泄漏,有预警的作用),是一种用于对抗栈溢出攻击的技术,即SSP安全机制,有时候也叫做Stack cookies

Canary的值是上的一个随机数,在程序启动时随机生成并且保存在比函数返回地址更低的位置。(看过栈溢出文章的应该都知道,我们栈溢出就是为了覆盖返回地址),由于我们覆盖到返回地址,那么不可避免的会覆盖到这个随机数(Cannary),程序在函数返回前,检查下Cannary是否被覆盖从而判断是否被栈溢出,从而达到保护栈的目的。

开启关闭Cannary

#默认情况下是会开启Canary保护的

#禁用栈保护
gcc -fno-stack-protector cannary.c -o cannary
#开启局部保护(只保护局部变量中含有char数组的函数)
gcc -fstack-protector cannary.c -o cannary
#开启全局保护
gcc -fstack-protector-all cannary.c -o cannary #命令速记
stack-protector(栈保护)
-f(开启)
-fno(关闭)
-all(全部)

Canary的种类

Cannary通常可以分为3中类型,terminator、random、random XOR,具体的实现有StackGuard、StackShield、Propoliced等

Terminator canaries(终结者金丝雀)

大多数缓冲区溢出攻击都基于某些字符串操作,比如说strcpy,这些操作基本上以字符串终止符结束\x00

终止符金丝雀包含 NULL(0x00)、CR(0x0d)、LF(0x0a)和 EOF(0xff)这四个字符,这四个字符应终止大多数字符串操作,从而使溢出尝试无害。

这可以防止使用 strcpy() 和其他方法的攻击,这些方法在复制空字符时返回。

绕过方法:
攻击者可以使用其已知值覆盖金丝雀,并使用特制值覆盖返回地址,从而绕过这种类型的保护,从而导致代码执行。
当使用非字符串函数来复制缓冲区并且缓冲区内容和缓冲区长度都受攻击者控制时,可能会发生这种情况。

Random cannaries(随机金丝雀)

随机金丝雀是在程序执行时随机选择的。

使用此方法,攻击者无法在程序启动之前通过搜索可执行映像来了解金丝雀值。随机值取自 /dev/urandom(如果可用),如果不支持 /dev/urandom,则通过hash一天中的时间来创建。这种随机性足以阻止大多数预测尝试。

绕过方法:
需要配合信息泄漏漏洞
如果应用程序中存在可用于读取金丝雀值的信息泄漏漏洞,则可以绕过这种保护。

Random XOR cannaries(随机异或金丝雀)

随机异或金丝雀是使用全部或部分控制数据(帧指针+返回地址等)进行异或加干扰的随机金丝雀。

这样,一旦金丝雀或控制数据被破坏,金丝雀值就是错误的,它将导致程序立即终止。

绕过方式总结:

泄露内存中的canary,如通过格式化字符串漏洞打印出来
one-by-one爆破,但是一般是多线程的程序,产生新线程后canary不变才行。最高位为00。
劫持_stack_chk_fail函数,canary验证失败会进行该函数,__stack_chk_fail 函数是一个普通的延迟绑定函数,可以通过修改 GOT 表劫持这个函数。
覆盖线程局部存储TLS中的canary,溢出尺寸比较大可以用。同时修改栈上的canary和TLS中的canary.

NX(No-eXecute)

No-eXecute(NX)表示不可执行,其原理是将数据所在的内存页标识为不可执行。

相当于Windows平台上的DEP(数据执行保护),NX的实现由软件和硬件共同完成

  • 硬件层:利用CPU的NX位,对相应页表项中的第63位进行设置

    • NX=1,不可知性
    • NX=0,可执行
  • 软件层面:需要操作系统支持NX以配置页表,涉及相关API
    • Windows:VirtualAllocVirtualProtect
    • Linux:mmapmprotect
if ${readelf} -l "${1}" 2>/dev/null | grep -q 'GNU_STACK'; then
if ${readelf} -l "${1}" 2>/dev/null | grep 'GNU_STACK' | grep -q 'RWE'; then
echo_message '\033[31mNX disabled\033[m ' 'NX disabled,' ' nx="no"' '"nx":"no",'
else
echo_message '\033[32mNX enabled \033[m ' 'NX enabled,' ' nx="yes"' '"nx":"yes",'
fi
else
echo_message '\033[31mNX disabled\033[m ' 'NX disabled,' ' nx="no"' '"nx":"no",'
fi
#判断是否有GNU_STACK,继续判断是否有RWE权限,否则就是开启了NX保护.

绕过方式:

在Linx中,当装载器将程序载入进内存空间后,将程序的.text节标记为可执行,而其余的数据段.data、.bss、.rodata以及堆栈均为不可执行。

所以:无法用传统的修改GOT表来执行shellcode.

绕过的正确方法:
攻击者可以通过代码重用来执行攻击(ret2libc)。

PIE(ASLR地址随机化)

PIE(Position-Independent Executable) 中文解释为地址无关可执行文件。

也叫做ASLR(地址空间随机化)全称是叫(Address Space Layout Randomization)。

这个搞过逆向的应该都不会陌生,比如搞过Windows逆向或者是iOS/macOS逆向的,我们在逆一个程序的时候。用动态调试器去调试他的时候,他的装载地址或入口点地址,每次重启后都是会变化的,

所以每次都需要在IDA中计算出基地址,然后再加上模块的基址才能在调试器中找到真实的内存地址,在iOS中则每次都要image list -o -f来找装载的地址。

ASLR cat /proc/sys/kernel/randomize_va_space有三种情况:

0:表示全部关闭

1:表示部分开启

2:表示完全开启(在部分开启的基础上增加了heap的随机化)

ASLR Executable PLT Heap Stack Shared Libraries
0 × × × × ×
1 × × ×
2 × ×
2+pie

PIE 位置无关可执行文件,在应用层的编译器上实现,通过将程序编译为位置无关代码PIC,使程序加载到任意位置,就像是一个特殊的共享库。PIE会一定程度上影响性能。

关闭PIE/ALSR(地址随机化)

sudo -s echo 0 > /proc/sys/kernel/randomize_va_space
gcc -fpie -pie -o test test.c // 开启PIE,此时强度为1
gcc -fPIE -pie -o test test.c // 开启PIE,此时为最高强度2
gcc -fpic -o test test.c // 开启PIC,此时强度为1,不会开启PIE
gcc -fPIC -o test test.c // 开启PIC,此时为最高强度2,不会开启PIE #助记
-pie (开启)
-no-pie(关闭)

PIE/ALSR 检查脚本

if ${readelf} -h "${1}" 2>/dev/null | grep -q 'Type:[[:space:]]*EXEC'; then
echo_message '\033[31mNo PIE \033[m ' 'No PIE,' ' pie="no"' '"pie":"no",'
elif ${readelf} -h "${1}" 2>/dev/null | grep -q 'Type:[[:space:]]*DYN'; then
if ${readelf} -d "${1}" 2>/dev/null | grep -q 'DEBUG'; then
echo_message '\033[32mPIE enabled \033[m ' 'PIE enabled,' ' pie="yes"' '"pie":"yes",'
else
echo_message '\033[33mDSO \033[m ' 'DSO,' ' pie="dso"' '"pie":"dso",'
fi
elif ${readelf} -h "${1}" 2>/dev/null | grep -q 'Type:[[:space:]]*REL'; then
echo_message '\033[33mREL \033[m ' 'REL,' ' pie="rel"' '"pie":"rel",'
else
echo_message '\033[33mNot an ELF file\033[m ' 'Not an ELF file,' ' pie="not_elf"' '"pie":"not_elf",'
fi

FORTIFY_SOURCE

FORTIFY_SOURCE(源码增强),这个其实有点类似与Windows中用新版Visual Studio进行开发的时候,当你用一些危险函数比如strcpy、sprintf、strcat,编译器会提示你用xx_s加强版函数。

FORTIFY_SOURCE本质上一种检查和替换机制,对GCC和glibc的一个安全补丁。

目前支持memcpy, memmove, memset, strcpy, strncpy, strcat, strncat,sprintf, vsprintf, snprintf, vsnprintf, gets等。

开启关闭FORTIFY_SOURCE

#默认Ubuntu16.04下是关闭的,测试发现Ubuntu18.04是开启的
gcc -D_FORTIFY_SOURCE=1 仅仅只在编译时进行检查(尤其是#include <string.h>这种文件头)
gcc -D_FORTIFY_SOURCE=2 程序执行时也会进行检查(如果检查到缓冲区溢出,就会终止程序) #助记
FORTIFY_SOURCE(代码增强)
-D 1(开启缓冲区溢出攻击检查)
-D 2(开启缓冲区溢出以及格式化字符串攻击检查) ,通过数组大小来判断替换`strcpy、memcpy、memset`等函数名,来防止缓冲区溢出。

RELRO

RELRO全称:Relocation Read-Only(重定位表只读),之前文章有介绍过动态链接(GOT表、PLT表)需要延迟绑定。

在启用延时绑定时,符号的解析只发生在第一次使用的时候,该过程是通过PLT表进行的,解析完成后,相应的GOT表条目才会修改为正确的函数地址。因此,在延迟绑定的情况下,.got.plt必须是可写的。攻击者就可以通过篡改地址劫持程序。

RELRO就是为了解决延迟绑定的安全问题的,之前可以看到我们很轻松的用调试器修改了GOT表,达到了劫持效果,RELRO会把这些延迟绑定表设置成只读,防止来修改。

RELRO一般有两种形式:

Partial RELRO(部分RELRO):

Ubuntu 16.04开始默认的GCC设置,几乎所有的二进制文件都至少有部分RELRO。这样仅仅只能防止全局变量上的缓冲区溢出从而覆盖到GOT。

(.dynamic、.got)初始化时候标记为只读。

Full RELRO(完全RELRO):

使整个GOT只读,从而无法被覆盖,但是这样会大大增加程序的启动时间,因为需要在启动之前解析所有的符号。

也就是延迟绑定被禁止了,所有的导入符号在开始时候被解析,.got.plt段会被完全初始化为目标函数的最终地址,并且被mprotect标记为只读,但是.got.plt会被合并到.got,也就看不到这些段了,对性能会造成影响。

开启关闭RELRO

#关闭RELRO
-z norelro 禁用relro
#开启RELRO
-z lazy 开启Partial RELRO(部分RELRO)
-z now FULL PARTIAL(完全开启RELRO) #助记
-z (RELRO)
norelro (关闭RELRO)
lazy (开启部分RELRO)
now (完全开启RELRO)

PWN菜鸡交流小分队

最后感谢大家的阅读,本菜鸡也是刚学,文章中如有错误请及时指出。

大家也可以来群里骂我哈哈哈,群里有PWN、RE、WEB大佬,欢迎交流

参考文章 :

http://www.manongzj.com/blog/27-gvafmooopa.html (PWN保护机制详解)

https://www.cnblogs.com/ttxs69/p/pwn_canary.html (PWN之Canary学习)

https://lzeroyuee.cn/2021/02/23/Linux-Pwn-安全机制/ (Linux Pwn - 安全机制)

https://www.redhat.com/en/blog/security-technologies-stack-smashing-protection-stackguard (安全技术:堆栈粉碎保护 (StackGuard))

https://clibre.io/blog/por-secciones/hardening/item/413-proteccion-de-ejecutables-fortify-source (可执行文件保护:FORTIFY_SOURCE)

《CTF权威指南(PWN篇)》

[pwn基础] Linux安全机制的更多相关文章

  1. 【深入浅出Linux网络编程】 “基础 -- 事件触发机制”

    回顾一下“"开篇 -- 知其然,知其所以然"”中的两段代码,第一段虽然只使用1个线程但却也只能处理一个socket,第二段虽然能处理成百上千个socket但却需要创建同等数量的线程 ...

  2. 20155301 滕树晨linux基础——linux进程间通信(IPC)机制总结

    20155301 滕树晨linux基础--linux进程间通信(IPC)机制总结 共享内存 共享内存是在多个进程之间共享内存区域的一种进程间的通信方式,由IPC为进程创建的一个特殊地址范围,它将出现在 ...

  3. Linux Namespaces机制

    转自:http://www.cnblogs.com/lisperl/archive/2012/05/03/2480316.html Linux Namespaces机制提供一种资源隔离方案.PID,I ...

  4. linux进程同步机制_转

    转自:Linux进程同步机制 具体应用可参考:线程同步       IPC之信号量 为了能够有效的控制多个进程之间的沟通过程,保证沟通过程的有序和和谐,OS必须提供一 定的同步机制保证进程之间不会自说 ...

  5. Linux保护机制和绕过方式

    Linux保护机制和绕过方式 CANNARY(栈保护) ​ 栈溢出保护是一种缓冲区溢出攻击缓解手段,当函数存在缓冲区溢出攻击漏洞时,攻击者可以覆盖栈上的返回地址来让shellcode能够得到执行.用C ...

  6. [pwn基础]动态链接原理

    目录 [pwn基础]动态链接原理 动态链接概念 动态链接调用so例子 GOT(全局偏移表) got表劫持小实验 PLT(延迟绑定) PLT概念 延迟绑定(PLT表) 实战学习 [pwn基础]动态链接原 ...

  7. [pwn基础]Pwntools学习

    目录 [pwn基础]Pwntools学习 Pwntools介绍 Pwntools安装 Pwntools常用模块和函数 pwnlib.tubes模块学习 tubes.process pwnlib.con ...

  8. Linux模块机制浅析

    Linux模块机制浅析   Linux允许用户通过插入模块,实现干预内核的目的.一直以来,对linux的模块机制都不够清晰,因此本文对内核模块的加载机制进行简单地分析. 模块的Hello World! ...

  9. android & Linux uevent机制

    Linux uevent机制 Uevent是内核通知android有状态变化的一种方法,比如USB线插入.拔出,电池电量变化等等.其本质是内核发送(可以通过socket)一个字符串,应用层(andro ...

随机推荐

  1. JavaWeb知识梳理(可收藏)

    **JavaWeb相关知识 ** 1.Servlet 1.1 Status Code(Http状态码) 1.1xx 请求信息 Http状态码 Http Status Code Http状态码含义中文说 ...

  2. kubectl get node -n wide --show-labels

    集群环境:1.k8s用的是二进制方式安装2.操作系统是linux (centos)3.操作系统版本为 7.4/7.94.k8s的应用管理.node管理.pod管理等用rancher.k8s令牌以及ma ...

  3. 帝国cms插件 一键替换数据表中已发表文章的内容关键字

    你是不是也在优化网站,是不是网站发展了一段时间之后才来做优化的,这样当然就会导致已经发表文章里的内容关键字,不能得到替换了! 小编根据后台替换内容关键字的程序,重写了一段 通过运行单个页面就能直接替换 ...

  4. Unity中的2D层级显示问题

    ##1.层级显示 ###使用素材为免费或自制 本文章只用于学习和记录 在Unity2D游戏中可能出现以下情况 贴图的前后关系不正确 可以通过控制图片的层级来解决 本示例中杰西卡和树木都是搭载了图片的空 ...

  5. java基础知识-序列化/反序列化-gson基础知识

    以下内容来之官网翻译,地址 1.Gson依赖 1.1.Gradle/Android dependencies { implementation 'com.google.code.gson:gson:2 ...

  6. 1.Docker容器学习之新生入门必备基础知识

    0x00 Docker 快速入门 1.基础介绍 描述:Docker [ˈdɑ:kə(r)] 是一个基于Go语言开发实现的遵循Apache 2.0协议开源项目,目标是实现轻量级的操作系统虚拟化解决方案: ...

  7. Codeforces Round #707 (Div. 2)A.英语漏洞 + C.Going Home C题收获不小

    A题英语漏洞 A题传送门: https://codeforces.com/contest/1501/problem/A 其实题目说的很明白, 只是我傻傻的会错了意, 话不多说, 开整. 前两行是说, ...

  8. Java语言学习day18--7月24日

    ###01get和set方法 * A.get和set方法 * 年龄已被私有,错误的值无法赋值,可是正确的值也赋值不了,这样还是不行,那肿么办呢?按照之前所学习的封装的原理,隐藏后,还需要提供访问方式. ...

  9. SpringBoot--Easycode、mybatisX插件生成entity,controller,service,dao,mapper IDEA版 项目提效神器

    一.介绍 Easycode是idea的一个插件,可以直接对数据的表生成entity,controller,service,dao,mapper,无需任何编码,简单而强大. MybatisX 是一款基于 ...

  10. XCTF练习题---WEB---simple_js

    XCTF练习题---WEB---simple_js flag:Cyberpeace{786OsErtk12} 解题步骤: 1.观察题目,打开场景 2.打开该场景后发现是一个登录界面,随便输入一个密码, ...