挑战
我需要一个密码管理工具,它将被其他进程(所有类型的脚本: python、php、perl等)调用,并且它将能够识别和验证调用者脚本以执行访问控制:要么返回密码,要么退出-1。
目前的执行情况
在研究了各种框架之后,我决定使用python
的keepassdb
,它能够处理Keepass V1.X后端数据库文件并构建我自己的访问控制覆盖层(因为以后可以为用户/组访问定制并集成到LDAP中)。访问控制是通过重载每个条目的notes
字段来完成的,其中包括允许访问密码的SHA-256散列。(请注意,这也验证了脚本没有被任何人更改)
使用-p
参数调用密码管理器,该参数是被调用脚本/应用程序的PID,将执行以下步骤:
1
之前,必须找到调用方PID,该进程是具有父级0的init
。这样,我们就知道是谁调用了这个密码管理器实例。shlex
)。问题所在
上面的实现对于合法的脚本很有效,但是很容易混淆它。让caller.py
是允许访问特定条目e
的脚本。运行它时,命令行看起来像python /path/to/caller.py arg1 arg2
。分析命令行的代码是:
cmd = walk_ppids(pid)
lg.debug(cmd)
if cmd is False:
lg.error("PID %s is not my parent process or not a process at all!" % pid)
sys.exit(-1)
cmd_parts = shlex.split(cmd)
running_script = ""
for p in cmd_parts:
if re.search("\.(php|py|pl|sh|groovy|bat)$", p, re.I):
running_script = p
break
if not running_script:
lg.error("Cannot identify this script's name/path!")
sys.exit(-1)
running_script = os.path.abspath(running_script)
lg.debug("Found "+running_script)
phash = hash_file(open(running_script, 'rb'), hashlib.sha256())
父进程的命令行是使用以下方法获得的:
os.popen("ps -p %s -o args=" % ppid).read().strip()
现在,混淆上述函数的最简单方法是创建一个没有.sh
扩展的shell脚本,该扩展以caller.py
作为第一个参数。sh不使用其参数,而是调用查询条目e
的密码管理器。命令行看起来像fake_sh ./caller.py
,因此上面的代码返回.这是不该做的事。
问题
人们可能会认为,这是很久以前解决的一个常见问题,没有程序员硬编码就会进入脚本/应用程序,但我做了几天的研究,似乎找不到任何类似的方法。我明白这个问题是比较开放的,所以我会接受以下的答案:
shlex
分析部分)发布于 2015-12-20 13:43:24
改进:使规则更加严格
第一步是确认正确的扩展在正确的解释器上运行,这意味着caller.py
不能在/bin/bash
上运行。
类似的漏洞可以通过python利用,例如命令python -W ./caller.py ./myUberHack.py
。命令行分析器查找解释器的第一个.py
参数时会认为caller.py
正在运行.但事实并非如此。
为所有解释器构建所有调用规则太费时了,所以我对假设进行了硬编码。这些存储在tuple
中,每一行都是:
(file extension, positional argument, interpreter first letters)
exts = (
(".py", 1, "python"),
(".php", 2, "php"),
(".pl", 1, "perl"),
(".sh", 1, "/bin/bash"), # Assumption, we accept only bash
(".groovy", 1, "groovy"),
(".rb", 1, "ruby"),
)
"""Matching extensions to positional arguments and interpreters"""
现在的验证代码是:
for i in exts:
# Check the specified cmdline position and extension
if cmd_parts[i[1]].strip().endswith(i[0]):
lg.debug("Checking "+cmd_parts[i[1]])
running_script = cmd_parts[i[1]]
# Make sure that the interpretter matches the extension
if running_script.endswith(i[0]) and not cmd_parts[0].startswith(i[2]):
lg.error("Wrong interpretter... go away...")
sys.exit(-1)
break
现在没有比这更好的了..。
https://stackoverflow.com/questions/34380618
复制相似问题