su部分帐户免密码切换

一、需求

最近业务部分希望在几百台主机上安装python expect包(pexpect),向其了解了下需求,其需求是通过4a审计平台登陆到他们业务的任一主机后(默认是user1 用户登陆),其希望可以在user1下执行某命令后,可以向user2、user3、user4几个用户免密切换,除此之外的其他用户不能切换。了解需求后,发现可以通过如下方法实现该需求:



<br />
  1. 通过expect(包括其他语言的衍生类)通过自动匹配并输入密码实现;
  2. 通过sudo配置NOPASSWD su实现(将需要切换的用户在sudo里配死);
  3. 通过OS底层函数进行uid、gid切换(需要s权限位配置和相关权限控制)
<br />



像expect、python、java、ruby等语言实现的expect的代码是不加密或编译后弱加密的,都可以读取源码后获取其密码内容。尽管shell 类语言也可以加密,但相对于更底层的语言c、c++、golang等编译出的二进制文件相比还是太弱鸡。所以本篇就以golang和c语言为例实现下这个需求。

二、golang expect实现

github上找了几个expect相关功能的模块,发现都不成功,后来找了一个可用的模块:github.com/ThomasRooney/gexpect ,具体代码如下:



<br />
package main
import (
    "fmt"
    gexpect "github.com/ThomasRooney/gexpect"
)
func main() {
    child, err := gexpect.Spawn("su - zabbix")
    if err != nil {
        panic(err)
    }
    child.Expect("Password")
    child.SendLine("zabbixpasswd")
    child.Interact()
}
<br />



上面并没有进行用户控制,如有需要可以使用os/user模块或syscall模块实现。这部分代码是以切换zabbix用户为例,如果需要匹配多个用户,可以通过switch……case语句实现。



虽然上面的代码实现了功能,但是副作用也比较大。比如:输入的命令会重复输出,ps执行不能全屏幕,无法 tab补全等。虽然后面也尝试和其他pty和term模块进行整合,但功力不够,并没有成功。

三、c语言实现

网上找了下su命令的源码看了下,发现其内部调用了两个头文件unistd.h和pwd.h ,前都用以实现uid、gid、euid、egid等的切换和调用(需s权限位),后都用于读取/etc/passwd文件,返回结构体中相关的值。由于unistd.h的帮助信息较多,这里只截取下pwd.h的相关帮助信息,如下图:



<img src="https://www.361way.com/wp-content/uploads/2018/12/pwd-header.png" width="688" height="402" title="pwd-header" alt="pwd-header" />



这里使用的getpwnam方法,用于匹配哪一个用户可以调用该程序实现用户功能切换,同上面golang一样,这里以只切换zabbix为例,需要匹配多个用户,可以通过switch……case语句实现。代码如下:



<br />
#include 
#include 
#include 
#include 
int main(void)
{
    int current_uid = getuid();
    printf("My UID is: %d. My GID is: %dn", current_uid, getgid());
    system("/usr/bin/id");
    if (setuid(0))
    {
        perror("setuid");
        return 1;
    }
    struct passwd *pw;
    pw = getpwnam("kiosk");
    if(pw->pw_uid==current_uid){  //进行用户控制,只有kiosk用户可以执行切换
        system("/usr/bin/su - zabbix");
    }
    return 0;
}
可以使用如下命令进行编译和设置用户属性和s权限位:



<br />
gcc -o setuid setuid.c
chown root.root setuid
chmod u+s setuid 或chmod 4755 setuid 
pwd.h相关的用户可以参考如下两篇文章:



<a href="https://aljensencprogramming.wordpress.com/tag/etcpasswd/" target="_blank" rel="noopener">https://aljensencprogramming.wordpress.com/tag/etcpasswd/</a>



<a href="https://www.adampalmer.me/iodigitalsec/2009/10/03/linux-c-setuid-setgid-tutorial/" target="_blank" rel="noopener">https://www.adampalmer.me/iodigitalsec/2009/10/03/linux-c-setuid-setgid-tutorial/</a>



后来查了下golang的手册,发现syscall 模块包中也包含有上面的相关方法,理论也可以实现以上功能。具体可以参考官方文档:



<a href="https://golang.org/pkg/syscall/" target="_blank" rel="noopener">https://golang.org/pkg/syscall/</a>



s权限位比较便利,但也比较危险,使用不当很容易被提权,所以系统下的很多安全工具,都会通过find 查看带有s 权限的文件。当然本篇实现的这个需求,也有一个好处,就是不论主机的其他用户的密码如何更换,都可以成功进行用户切换,这点其实和sudo实现的功能是类似的。

su部分帐户免密码切换》有1条评论

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注