通过c输入sudo密码



我以前问过这个问题,但没有人直接回答。我想知道如何通过c代码输入sudo密码。我正在尝试编写一个脚本,以便能够执行sudo bash并输入所需的密码。我也知道硬编码密码的风险,但在这种情况下我并不介意。

否。这样做是一种反模式。

根据情况,有几种替代方案可供选择:

  • 使用gksudo(如果设置了DISPLAY环境变量)进行图形提示

  • 安装要在/usr/share/yourapp/scripts//usr/lib/yourapp/scripts/中执行的脚本,以及允许使用sudo运行脚本而无需在/etc/sudoers.d/yourapp中提供密码的正确sudo配置(或在没有/etc/sudoers.d/的系统中为/etc/sudoers)
    nbsp;

  • 在程序开始时,检查geteuid() == 0。如果没有,请使用gksudo/sudo重新执行self,以获得root权限。

    对于正常操作,程序应该只使用执行程序的真实用户的权限。为了以后能够提高权限,将"保存"根权限。因此,最初,您的程序将使用例如放弃特权

    uid_t  uid = getuid();
    gid_t  gid = getgid();
    if (setresgid(gid, gid, 0) == -1 ||
    setresuid(uid, uid, 0) == -1) {
    /* Failed: no root privileges! */
    }
    

    要重新提升权限,请使用

    if (setresgid(gid, 0, 0) == -1 ||
    setresuid(uid, 0, 0) == -1) {
    /* Failed: no root privileges! */ 
    }
    

    它只将有效标识更改为root(就像setuid二进制文件所做的那样)或

    if (setresgid(0, 0, 0) == -1 ||
    setresuid(0, 0, 0) == -1) {
    /* Failed: no root privileges! */ 
    }
    

    它将真实和有效的身份转换为根。

    通常,特权被提升只是为了分叉一个有特权的子从机,之后主程序使用完全放弃特权

    if (setresgid(gid, gid, gid) == -1 ||
    setresuid(uid, uid, uid) == -1) {
    /* Failed. */
    }
    

    在父对象和子对象之间只保留一对套接字或管道;然后,子进程可以分叉并执行新的进程。(如果使用Unix域套接字,父进程甚至可以通过辅助消息发送新的描述符用于新进程的标准流。)
     

  • 使用文件系统功能为程序提供所需的功能,而无需提升其所有权限。

    例如,sudo setcap CAP_NET_BIND_SERVICE=pe /usr/bin/yourapp/usr/bin/yourapp提供了CAP_NET_BIND_SERVICE功能(允许且有效;不继承),允许您的程序绑定到任何未使用的TCP/IP和UDP/IP端口,包括1-1024。有关功能的详细描述,请参阅man 7功能

  • 使用一个受信任的助手二进制文件(程序)为您充当sudo。如果您在例如/usr/lib/yourapp/execute上安装它,您可以添加必要的sudo配置,以便在不提供密码的情况下执行它。或者,您可以使它成为setuid root,或者通过文件系统功能为它提供必要的功能。

    为了避免其他程序利用此帮助程序,您必须确保它仅由您的程序执行。确保这一点的一种方法是让你的程序创建一个Unix域套接字对,让程序的一端打开,另一端为描述符3中的助手。在执行任何操作之前,助手会检查是否还没有要接收的内容(以避免"管道填充"攻击),并向父对象写入一个字节。父级使用单个字节进行响应,但在辅助消息中使用其凭据。凭据包含父级的进程ID。(不要简单地使用getppid(),因为这允许某些攻击;当我们进行检查时,这种套接字方法会验证父进程是否仍然有效。)最后,使用readlink()读取/proc/PID/exe伪符号链接,其中PID是凭据辅助消息中的父进程ID。此时,助手应该发送一个字节,并再次接收一个带有凭据的字节作为辅助消息,以确保父进程仍然相同。

    验证过程很复杂,但也是必要的,以避免滥用帮助程序而容易利用根权限。要了解另一种实现这一点的方法,请查看Apache suEXEC,它是Apache使用特定用户权限执行CGI程序的助手


假设你对以合理的方式做事完全不感兴趣,并坚持使用密码。好的我只要求你不要发布这样的代码,或者至少警告你的用户它是完全不安全的。

这不仅仅是一次粗暴的黑客攻击:这是一次自杀式的黑客攻击,类似于在电子邮件签名中输入网站密码,因为你只会给那些首先应该有管理员权限访问你网站的朋友发邮件。所以,脚枪,带一根扳机,没有安全感,装备着涂有河豚毒素的子弹。有一个漂亮的标签,上面写着大的、孩子可读的字母,上面写著"请和我一起玩!我很安全!",存放在孩子的卧室里。

最简单的方法是使用-S标志执行sudo,这将使它从标准输入中读取密码。例如,example.c

#define  _POSIX_C_SOURCE  200809L
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
int main(void)
{
FILE  *cmd;
int    status;
cmd = popen("/usr/bin/sudo -S id -un 2>/dev/null", "w");
if (!cmd) {
fprintf(stderr, "Cannot run sudo: %s.n", strerror(errno));
return EXIT_FAILURE;
}
fprintf(cmd, "Passwordn");
fflush(cmd);
status = pclose(cmd);
if (WIFEXITED(status)) {
if (WEXITSTATUS(status) == EXIT_SUCCESS)
fprintf(stderr, "No errors.n");
else
fprintf(stderr, "Command failed with exit status %d.n", WEXITSTATUS(status));
} else
if (WIFSIGNALED(status))
fprintf(stderr, "Command killed by signal %d.n", WTERMSIG(status));
else
fprintf(stderr, "Command failed.n");
return EXIT_SUCCESS;
}

命令管道是以写入模式打开的,这样我们就可以向它写入密码。2>/dev/null重定向隐藏了密码提示。

如果密码正确,以上将把以root身份运行时id -un输出的内容(即:root)输出到标准输出,把No errors.输出到标准错误。

如果密码不正确,sudo会重试几次(所以几秒钟内什么都不会发生),然后程序会向标准错误报告Command failed with exit status 1.,因为当密码不正确时,sudo就是这样做的。

最新更新