Linux - 使用setuid位进行提权

54 篇文章 24 订阅
23 篇文章 1 订阅

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

王万林 Ben

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

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

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

打赏作者

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

抵扣说明:

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

余额充值