我有一个脚本,它在其自身内部启动一个带有参数秘密的命令。例如:
#!/bin/bash
command-name secret
在运行命令时,我可以通读ps -ef | grep command-name
这是秘密。
有没有办法以通过ps -ef
的方式隐藏秘密,命令行参数被混淆了?
答案 0 :(得分:9)
如果秘密在执行之间没有变化,请使用特殊配置文件".appsecrets"
。将文件的权限设置为所有者只读。在文件内部为秘密设置环境变量。该文件需要位于运行该命令的用户的主目录中。
#!/bin/bash
#filename: .appsecrets
set SECRET=polkalover
加载配置文件,以便设置环境变量。
. ~/.appsecrets
我见过的事情:
<强> 1)强>
echo $SECRET | command
有效。我们正在使用Korn。
<强> 2)强>
password=$ENV{"SECRET"};
如果你能控制代码(例如在perl或C ++中)
第3)强>
. ./.app.config #sets the environment variables
isql -host [host] -user [user] -password <<SECRET
${SQLPASSWORD}
SECRET
有效。一个限制是<<
字符串必须是给予命令的最后一个参数。如果在-password
这种方法的好处是你可以安排它,这样秘密可以隐藏在生产中。在生产中使用相同的文件名,但它将位于生产中运行命令的帐户的主目录中。然后,您可以像访问root帐户一样锁定对机密的访问权限。只有某些人可以“su”到prod帐户来查看或维护这个秘密,而开发人员仍然可以运行该程序,因为他们在自己的主目录中使用自己的“.appsecret”文件。
您可以使用此方法为任意数量的应用程序存储安全信息,只要它们使用不同的环境变量名称作为其秘密。
(错误的方式)
我看到DBA使用的一种旧方法是将SYBASE设置为"/opt/././././././././././././././././././././././././././././././././././sybase/bin"
。所以他们的命令行很长,ps截断了它。但是在linux中我认为你可以从/ proc。
答案 1 :(得分:9)
首先,您无法隐藏命令行参数。在启动程序时(在程序有机会对参数进行运行时更改之前),它们仍然可以通过ps aux
和cat /proc/$YOUR_PROCESS_PID/cmdline
显示。好消息是,通过使用替代方案,您仍然可以拥有秘密:
使用环境变量。如果您的程序可以阅读它们,请执行以下操作:
mySecret='hello-neo' myCommand
使用标准输入:
mySecret='hello-neo' printenv mySecret | myCommand
使用临时文件描述符:
myCommand <( mySecret='hello-neo' printenv mySecret )
在最后一种情况下,您的程序将像myCommand /dev/fd/67
一样启动,其中/dev/fd/67
的内容是您的秘密(本例中为hello-neo
)。
在上述所有方法中,要小心将命令保留在bash命令历史记录中(~/.bash_history
)。您可以通过从脚本(文件)运行命令,或通过每次交互式提示自己输入密码来避免这种情况:
read mySecret
myCommand # approach 2
printenv mySecret | myCommand # approach 3
myCommand <( printenv mySecret ) # approach 4
答案 2 :(得分:7)
从ps
隐瞒你的秘密论据的唯一方法不是提供秘密作为论据。一种方法是将秘密放在一个文件中,并重定向文件描述符3以读取文件,然后删除该文件:
echo secret > x.$$
command 3<x.$$
rm -f x.$$
目前尚不清楚这是一种拯救秘密的安全方式; echo命令是一个内置的shell,所以它不应该出现在'ps'输出中(任何外观都会稍纵即逝)。很久以前,echo
不是内置的 - 事实上,在MacOS X上,即使它是内置于所有shell,仍然有/bin/echo
。
当然,这假设您拥有command
的源,并且可以修改它以从预先打开的文件描述符而不是命令行参数中读取秘密。如果您无法修改命令,则完全卡住了 - “ps”列表将显示信息。
如果你是命令所有者,你可以提取另一个技巧:你可以捕获参数(秘密),将它写入管道或文件(立即取消链接),然后重新执行命令,而不是秘密论证;第二次调用知道,由于秘密不存在,它应该在第一次调用隐藏秘密的任何地方查找。第二次调用(减去秘密)是在处理隐藏秘密所需的微小间隔之后出现在'ps'输出中的内容。不如从头开始设置秘密通道。但这些表明了你必须走的长度。
从程序内部切换一个参数 - 例如用零覆盖 - 不会隐藏'ps'中的参数。
答案 3 :(得分:4)
expect
库是为这些事情部分创建的,因此您仍然可以向进程提供密码/其他敏感信息,而不必将其作为参数传递。假设当没有给出“秘密”时,程序当然会要求它。
答案 4 :(得分:4)
我在另一篇文章中看到了它。这是Linux下最简单的方法。
这会修改所有其他程序看到的命令行的内存部分。
strncpy(argv[1], "randomtrash", strlen(argv[1]));
您也可以更改进程的名称,但仅限于从命令行读取时。像top
这样的程序会显示真实的进程名称:
strncpy(argv[0], "New process name", strlen(argv[0]));
不要忘记复制最大strlen(argv[0])
个字节,因为可能没有更多的空间分配。
我认为只能在我们修改的内存部分找到参数,所以我认为这就像魅力一样。如果有人对此有所了解,请发表评论。
VasyaNovikov注意:在调用程序之后但在开始执行您所描述的更改之前,仍然可以截获密码。
答案 5 :(得分:1)
答案 6 :(得分:1)
您可以使用LD_PRELOAD
让一个库在该二进制文件本身的进程中操作某些二进制文件的命令行参数,其中ps
不会选择它。有关详细信息,请参阅服务器故障上的this answer of mine。
答案 7 :(得分:0)
如果要手动运行脚本,最好的方法是从STDIN
中读取它#!/bin/bash
read -s -p "Enter your secret: " secret
command "$secret"
答案 8 :(得分:0)
#include <boost/algorithm/string/predicate.hpp>
void hide(int argc, char** argv, std::string const & arg){
for(char** current = argv; current != argv+ argc ;++current){
if(boost::algorithm::starts_with(*current, "--"+arg)){
bzero(*current, strlen(*current));
}
}
}
int main(int argc, char** argv){
hide(argc, argv, "password");
}
答案 9 :(得分:0)
这是在ps中的环境变量中隐藏秘密的一种方法:
#!/bin/bash
read -s -p "Enter your secret: " secret
umask 077 # nobody but the user can read the file x.$$
echo "export ES_PASSWORD=$secret" > x.$$
. x.$$ && your_awesome_command
rm -f x.$$ # Use shred, wipe or srm to securely delete the file
在ps输出中,您将看到以下内容:
$ps -ef | grep your_awesome_command
root 23134 1 0 20:55 pts/1 00:00:00 . x.$$ && your_awesome_command
Elastalert和Logstash是可以通过环境变量访问密码的服务示例。
答案 10 :(得分:0)
我总是将敏感数据存储在我没有放入 git 的文件中,并使用这样的秘密:
$(cat path/to/secret)