使用shc加密shell脚本

使用shc加密shell脚本

使用

之前为了防止svn认证问题,都是直接把svn的用户名、密码写在脚本里面的。由于明文密码非常不安全,所以必须采取密文保存。
为了不影响原有脚本流程,采用了抽取svn命令为独立脚本,在这个脚本里面写上用户名和密码,并加密保存。

加密采用了shc这个工具进行。该工具采用arc4的方式加密数据,而且比较简单,运行之后会根据输入的脚本(svn.sh)生成两个文件:
svn.sh.x这个是加密后的可执行程序,svn.sh.x.c这个是那个可执行程序的C源码。最终运行只需要前面那个.x结尾的可执行程序即可。

简单说下我的使用,刚开始什么参数都不加,最终生成的.x文件为动态链接,虽然没有什么依赖,但是需要动态链接glibc。由于我本地的
glibc版本远大于服务器上的,所以导致这个文件无法运行,提示找不到GLIBC 2.6找不到。查看了帮助文档之后,可以通过设置CFLAGS
环境变量,修改编译参数,再加上其他参数,最终的命令为:

CFLAGS="-static" shc -v -T -r -f svn.sh

其中通过环境变量,让编译输出的.x文件变成静态链接,这样就不需要依赖主机的任何动态链接库;-v参数输出命令的详细输出;
-T参数增加traceable,让输出的可执行程序可追踪;-r参数生成可分发的二进制程序。

这样原先脚本执行svn,只要直接改成svn.sh.x,去掉原先的用户名、密码,这样密码就被加密保存了。

原理

shc采用arc4加密,在命令中,大致通过
- 处理输入参数
- 读取脚本
- 解析使用的shell
- 生成C源码文件
- 编译C源码文件
这几步完成。在生成源码文件的时候,会对内容进行arc4加密,C源码中重新进行arc4进行解密,最终通过execvp调用运行最终的脚本。

几个参数的大致实现:

-T

如果不设置这个变量,生成的可执行文件将不能被trace

void untraceable(char * argv0)
{
    char proc[80];
    int pid, mine;

    switch(pid = fork()) {
        case  0:
            pid = getppid();
            /* For problematic SunOS ptrace */
            #if defined(__FreeBSD__)
            sprintf(proc, "/proc/%d/mem", (int)pid);
            #else
            sprintf(proc, "/proc/%d/as",  (int)pid);
            #endif
            close(0);
            mine = !open(proc, O_RDWR|O_EXCL);
            if (!mine && errno != EBUSY)
                mine = !ptrace(PTRACE_ATTACH, pid, 0, 0);
                if (mine) {
                    kill(pid, SIGCONT);
                } else {
                    perror(argv0);
                    kill(pid, SIGKILL);
                }
                _exit(mine);
        case -1:
            break;
        default:
            if (pid == waitpid(pid, 0, 0))
                return;
    }
    perror(argv0);
    _exit(1);
}

首先fock一个进程,试图去通过ptrace调用挂载到新fock出来的进程上,如果成功了,说明没有被其他进程trace,则发送SIGCONT信号继续执行,
否则直接发送SIGKILL信号终止进程继续执行。但是在实际使用过程中,不知道为什么,偶尔会让服务器上多出T状态的进程,看上是因为ptrace调用
向进程发送了SIGSTOP之后,再次发送SIGCONT没有成功。因此后面都加上了-T参数,跳过这个不能追踪设置。当前这样会大大降低安全性。

-e

这个参数可以指定可执行程序失效时间,超过这个时间加密后的可执行程序将无法运行。实现也很简单直接把加密后的过期时间放在了生成的C代码前,
执行shell之前,会有

if (date[0] && (atoll(date)<time(NULL)))
    return msg1;

这样的判断,直接阻止程序的运行。

发表回复

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

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据