Set-UID特权程序原理级攻击方法

Set-UID背景

特权程序必要性

linux的密码是存储在/etc/shadow这个影子文件中的,这个文件的权限设置成只有root用户
才可以访问,但是修改密码必须要修改该文件,那普通用户如何实现修改自己的密码呢?多数系统
用特权程序来解决这个问题,这个特权程序叫passwd

Set-UID原理

特权程序的实现方式有两种,守护进程和Set-UID程序。守护进程用root身份运行,普通程序向他发请求解决。
Set-UID用一个比特位告诉操作系统区别对待。Set-UID的好处是不用另起root程序,普通用户就可以完成
修改密码操作。而赋予Set-UID权限后,普通用户只能执行Set-UID中定义好的操作。

Set-UID不安全的地方

/bin/sh变成Set-UID不是安全做法,因该程序可以执行用户指定的任意命令  
vi程序变成Set-UID也不是安全做法,因允许用户在编辑器内执行任意外部命令  

Set-UID改变有效用户id

linux进程的三个用户id

真实用户id(uid): 运行进程的用户,运行命令/bin/id  
有效用户id(euid): 访问控制中使用的id,就是程序的所有者  
保留用户id    

在这里插入图片描述
这个实验说明,只有当文件所有者为root用户时,才能通过Set-UID改变其有效用户id。而4755中的4设置了
Set-UID比特,使有效用户id(euid)为0,成为特权程序。这种情况下,即使该进程由普通用户执行,也拥有root用户权限
在这里插入图片描述

这个实验说明,即使所有者是root,只要有效用户id不为0,还是一个非特权程序。同样,如果只是设置Set-UID,文件所有者不是root,也是非特权程序。

chown命令会自动清空Set-UID比特,做实验时要注意先输入chown,再输入chmod

Set-UID的主要攻击面

在这里插入图片描述

用户输入

特权程序如果没有很好地检查用户输入,将容易受到攻击。
比如chsh出过一个漏洞,修改/etc/passwd时,没有考虑到用户可能会输入两行字符,输入两行时相当于新建了一个用户,这样就可以建一个root用户。

系统输入

如特权程序需要修改系统某一个文件,但这个文件有可能被软链接到/etc/shadow

环境变量

如system("ls"),这个ls不提供具体路径就是一个不安全的方式,可以在环境变量中设置一个恶意的ls程序攻击。

权限泄露

su程序原理

linux的su程序是特权程序,用于用户切换,切换成第二个用户后,将抛弃进程的特权,再运行第二个用户默认的shell程序,
如果程序写的有问题,抛弃进程特权这个步骤没做好的话,就会出现权限泄露的问题。

文件句柄没关闭导致权限泄露

使用命令创建下面的程序
vi cap_leak.c    

权限泄露例子程序如下:

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

void main()
{
    int fd;
    char *v[2];
    fd = open("/etc/zzz", O_RDWR | O_APPEND);
    if (fd == -1) {
        printf("Cannot open /etc/zzz\n");
        exit(0);
    }
    printf("fd is %d\n", fd);
    setuid(getuid());
    v[0] = "/bin/sh";
    v[1] = 0;
    execve(v[0], v, 0);
}
第一步,它打开了一个只有root 用户可以修改的文件
/etc/zzz。在文件被打开后,程序定义了一个文件描述符,通过该文件描述符完成
后续对文件的操作。文件描述符是权限的一种形式,任何拥有它的人都可以访问对应的文件。
第二步,通过将有效用户ID(root)变得跟真实用户ID一样,程序降低了自身的权限,实际上相当于放弃了进程的root 特权。
      setuid(getuid());这行作用是将有效用户id(root)变成真实用户id,降低权限  
第三步,程序调用了一个 shell程序。
然而上述程序忘记了关闭文件,文件描述符仍然有效,因此这个非特权进程呈仍然可
以修改|etc/zzz文件。从程序的执行结果来看,可以发现文件描述符的值是。通过“echo...&3”命令可以修改/etc/zzz
文件。这里“&3”表示文件描述符3。在运行这个Set-UID程序之前,无法修改受保护的/etc/zzz文件。但是通过Set-UID程序获得文件描述符后,可以成功地修改该文件。

先把cap_leak变成set-uid程序:

在这里插入图片描述

用泄露的权限使普通用户可以修改受保护的文件:
在这里插入图片描述
!!! 实验结论

运行set-uid程序前无法修改文件,运行set-uid程序获得了文件描述符后,可以成功修改文件。
这个泄露完全是没有关闭文件句柄导致。

通过system函数攻击

!!! system函数原理在这里插入代码片

通过man system命令得知,system()是调用/bin/sh -c command来执行外部命令的。或者说外部
命令不是直接执行,而是shell程序首先被执行,然后shell将command作为输入并解析它。而shell程序
非常灵活,只要将命令用分号分隔就可以执行额外的指令。

!!! 程序设计背景

比如审计一家公司是否欺诈,需要查看linux所有文件,但为了保护系统不被修改,需要开发一个程序
只能看不能改。
vi catall.c
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    char *cat="/bin/cat";
    if (argc < 2)
    {
        printf("Please type a file name.\n");
        return 1;
    }
    char *command = malloc(strlen(cat) + strlen(argv[1]) + 2);
    sprintf(command, "%s %s", cat, argv[1]);
    system(command);
    return 0;
}

在这里插入图片描述
得到了root权限的shell

shell 实际上执行了两个命令:/bin/任意的文cat aa”和“/bin /sh”。因为aa 只是一个件名,cat找不到该文件,这个结果不需
要关注。要关注的是第二个命令,希望SRet-UID程序执行一个shell程序,这样就可以得到root权限的shell。在下面的结果中, shell的井号提
示符(#)说明获得了root shell。可以通过输入id命令来进一步确认,命令的输出结果显示euid (有效的用户id)是root。

在这里插入图片描述

!!! warning

Ubuntu 16.04以上版本,/bin/sh实际上是一个指向/bin/dash的链接文件,dash实现了
一个保护机制,当它发现自己在一个Set-UID的进程中运行时,会立刻把有效用户id变成实际
用户id,主动放弃特权。故利用/bin/sh发起的攻击不会成功。这也是上面显示Permission denied
的原因    
需要安装一个zsh的shell程序来做这个实验  
sudo apt install zsh  
sudo ln -sf /bin/zsh /bin/sh

!!! warning

实验结束记得运行: sudo ln -sf /bin/dash /bin/sh 改回来

用execve代替system

!!! execve不会调用shell

和system不同的是execve不会调用shell程序,而是直接运行指令  
execve的三个参数分别是:1、运行的指令 2、指令的参数 3、传入新程序
的环境变量
#include <unistd.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
    char *v[3];
    if (argc < 2)
    {
        printf("please type a file name.\n");
        return 1;
    }
    v[0] = "/bin/cat";
    v[1] = argv[1];
    v[2] = 0;
    execve(v[0], v, 0);
    return 0;
}
execve()函数接收三个参数:①运行的指令;②指令用到的参数;③传入新程序的环境变量。它会直接请求操作系统(而不是shell程序)执行指定的命令,因此它是个系统调用函数。如果在第二个参数中包含了额外的指令,它们只会被作为一个参数,而非一个指令。
这就是为什么在下面这个实验中,/bin/'cat解释找不到文件“aa ;/bin/sh”的原因,因为对cat程序来说,整个字符串就是一个参数。

在这里插入图片描述

!!! 实验说明

如果第二个参数加了额外的参数,他们只会被作为一个参数

攻击php调外部命令

!!! 程序语言调外部命令攻击点

Perl程序有open()函数,是通过shell实现的  
PHP有system()函数,工作原理和c类似
vi /var/www/html/list.php
<?php
    print("Please specify the path of the directory");
    print("<p>");
    $dir=$_GET['dir'];
    print("Directory path: " . $dir . "<p>");
    system("/bin/ls $dir");
?>    

上面脚本的目的是列出Web服务器某一目录中的内容。目录的路径存储在dir参数中,
该参数由用户通过HTTP 请求提供。因为该脚本使用system()函数来执行外部指令,攻击
者可以向服务器发送如下的HTTP 请求:

http://1ocalhost/list. php?dir=.;date

在接受了上述请求后, PHP程序会执行“/bin/1s .;date”指令,相当于两个命令“/'bin/ls”.和“date”。第二个命令是攻击者选择的。
在真实的攻击中,攻击者可以用一些恶意的命令来代替date命令。例如,删除某个文件,窃取敏感数据或者建立反向shell。

通过php成功hacker到了系统信息:
!!! 安全中两个重要原则

数据与代码分离原则:system没有做到这个原则,而execve做到了  
最小特权原则:Set-UID没有做到这个原则
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值