使用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;
这样的判断,直接阻止程序的运行。