在Unix上隐藏命令行参数的秘密

Ker*_*y82 31 unix bash

我有一个脚本,在其自身内部启动一个带有参数的命令,这是一个秘密.例如:

#!/bin/bash
command-name secret
Run Code Online (Sandbox Code Playgroud)

在运行命令时,我可以通读ps -ef | grep command-name哪个是秘密.

有没有办法以通过ps -ef命令行参数混淆的方式隐藏秘密?

Vas*_*kov 11

  1. 首先,您不能隐藏命令行参数.他们仍然会通过可见ps aux,并cat /proc/$YOUR_PROCESS_PID/cmdline在启动程序(该程序有机会做运行时更改参数之前)的时间.好消息是,通过使用替代方案,您仍然可以拥有秘密:

  2. 使用环境变量.如果您的程序可以读取它们,请执行以下操作

    mySecret='hello-neo' myCommand
    
    Run Code Online (Sandbox Code Playgroud)
  3. 使用标准输入:

    mySecret='hello-neo' printenv mySecret | myCommand
    
    Run Code Online (Sandbox Code Playgroud)
  4. 使用临时文件描述符:

    myCommand <( mySecret='hello-neo' printenv mySecret )
    
    Run Code Online (Sandbox Code Playgroud)

在最后一种情况下,您的程序将启动myCommand /dev/fd/67,其中内容/dev/fd/67是您的秘密(hello-neo在此示例中).


在上述所有方法中,要小心将命令保留在bash命令history(~/.bash_history)中.您可以通过从脚本(文件)运行命令或通过每次交互式提示自己输入密码来避免这种情况:

    read mySecret
    myCommand  # approach 2
    printenv mySecret | myCommand  # approach 3
    myCommand <( printenv mySecret )  # approach 4
Run Code Online (Sandbox Code Playgroud)

  • @Mark 感谢您对同一用户权限的评论。事实上,env 并不能保护你免受你自己的用户的侵害。但它确实可以防止其他人。这对我来说是一个巨大的差异。 (6认同)
  • 是的,你可以,我看到程序一直用'*'掩盖他们的命令行参数.在`ps -ef`的输出中是这样的:`/ xware/lib/EmbedThunderManager******************************************` (3认同)
  • @VasyaNovikov 我已经验证 Meow 是正确的。`mysql -u root -p mypassword` 在 `top` 和 `ps -ef` 中都显示为 `mysql -u root -px xxxxxxxxxx`。这与滚动或截断无关。 (3认同)
  • 环境变量可能比参数好,但也好不了多少。`猫/proc/1234/environ | 只要您拥有特权(root 或所有者),tr '\0\033' '\n~'` 就会显示环境变量。一旦进程运行,隐藏环境变量 (setenv) 可能会更容易,但在进程能够隐藏数据之前,攻击者仍然有一些时间读取文件。嗅探进程不一定具有太少的权限来读取敏感进程的环境。 (3认同)

Kel*_*nch 9

如果秘密在执行之间没有变化,请使用特殊配置文件".appsecrets".将文件的权限设置为所有者只读.在文件内部为秘密设置环境变量.该文件需要位于运行该命令的用户的主目录中.

#!/bin/bash  
#filename: .appsecrets
set SECRET=polkalover  
Run Code Online (Sandbox Code Playgroud)

加载配置文件,以便设置环境变量.

. ~/.appsecrets
Run Code Online (Sandbox Code Playgroud)

我见过的事情:

1)
echo $SECRET | command

如果命令提示输入密码来自stdin,并且'echo'是shell的内置函数,则可以正常工作.我们正在使用Korn.

2)
password=$ENV{"SECRET"};

如果您能控制代码,则可以工作(例如,在perl或C++中)

3)
. ./.app.config #sets the environment variables
isql -host [host] -user [user] -password <<SECRET
${SQLPASSWORD}
SECRET

如果命令可以从std-in接受秘密,则可以正常工作.一个限制是<<字符串必须是给予命令的最后一个参数.如果在-password之后必须出现非可选的arg,这可能会很麻烦

这种方法的好处是你可以安排它,这样秘密就可以隐藏在生产中.在生产中使用相同的文件名,但它将位于生产中运行命令的帐户的主目录中.然后,您可以像访问root帐户一样锁定对机密的访问权限.只有某些人可以"su"到prod帐户来查看或维护这个秘密,而开发人员仍然可以运行该程序,因为他们在自己的主目录中使用自己的".appsecret"文件.

您可以使用此方法为任意数量的应用程序存储安全信息,只要它们为其秘密使用不同的环境变量名称即可.

(错误的
方法)我看到DBA使用的一种旧方法是将SYBASE设置为"/opt/././././././././././././././././././././././././././././././././././sybase/bin".所以他们的命令行很长,ps截断了它.但是在linux中我认为你可以从/ proc中嗅出完整的命令行.

  • '命令行只显示给定的环境变量,而不是它的值' - 这些注释在两个方面都是**错误的**.首先,点击〜/ .appsecrets文件已经将shell的命令行参数重置为只有一个,$ 1的值现在是'SECRET = polkalover'; 没有变量,更不用说环境变量,称为SECRET.其次,如果你创建了一个变量SECRET(不是很难),运行'command $ SECRET'会在执行命令之前扩展$ SECRET,而`ps`会显示信息的扩展版本. (3认同)
  • _"......所以他们的命令行很长,`ps`截断了它"_------使用`ps ww`它可以显示完整的命令行 (2认同)

Jon*_*ler 7

隐瞒你的秘密论据的唯一方法ps就是不要把这个秘密作为论据.一种方法是将秘密放在一个文件中,并重定向文件描述符3以读取文件,然后删除该文件:

echo secret > x.$$
command 3<x.$$
rm -f x.$$
Run Code Online (Sandbox Code Playgroud)

目前尚不完全清楚这是一种拯救秘密的安全方式; echo命令是一个内置的shell,所以它不应该出现在'ps'输出中(任何外观都会稍纵即逝).很久以前,echo不是内置的 - 事实上,在MacOS X上,/bin/echo即使它是内置的所有炮弹,仍然有一个内置.

当然,这假设您拥有源command并可以修改它以从预先打开的文件描述符而不是命令行参数中读取秘密.如果您无法修改命令,那么您将完全陷入困境 - "ps"列表将显示该信息.

如果你是命令所有者,你可以获得另一个技巧:你可以捕获参数(秘密),将它写入管道或文件(立即取消链接),然后重新执行命令而不使用secret参数; 第二次调用知道,由于秘密不存在,它应该在第一次调用隐藏秘密的任何地方查找.第二次调用(减去秘密)是在处理隐藏秘密所需的微小间隔之后出现在'ps'输出中的内容.不如从头开始设置秘密通道.但这些表明了你必须走的长度.

从程序内部切换一个参数 - 例如用零覆盖 - 不会隐藏'ps'中的参数.

  • @JorgeFuentesGonzález:如果它是日志文件系统,覆盖文件也不会删除旧内容。 (3认同)
  • 我会在echo之前添加一个`umask 077`,以确保只有用户才能读取该文件. (2认同)

Jor*_*lez 6

我在另一个帖子上看到的。这是Linux下最简单的方法。

这会修改所有其他程序看到的命令行的内存部分。

strncpy(argv[1], "randomtrash", strlen(argv[1]));
Run Code Online (Sandbox Code Playgroud)

您还可以更改进程的名称,但仅限于从命令行读取时。像这样的程序top将显示真实的进程名称:

strncpy(argv[0], "New process name", strlen(argv[0]));
Run Code Online (Sandbox Code Playgroud)

不要忘记复制最大strlen(argv[0])字节数,因为可能没有分配更多空间。

我认为参数只能在我们修改的内存部分中找到,所以我认为这很有魅力。如果有人对此有所了解,请发表评论。

VasyaNovikov注意:在程序调用之后但在开始执行您描述的更改之前,仍然可以拦截密码。

  • 请注意,在程序调用之后但在开始执行您所描述的更改之前,密码仍然可以被拦截。这包括启动时间,因此它不为零。 (3认同)

Wri*_*ken 5

expect库部分是为这些事情创建的,因此您仍然可以向进程提供密码/其他敏感信息,而无需将其作为参数传递。假设当没有给出“秘密”时,程序当然会要求它。