Python 非交互式进程的密码管理 挑战
我需要一个密码管理工具,它将被其他进程调用(各种脚本:python、php、perl等),它将能够识别和验证调用方脚本,以便执行访问控制:返回密码或退出-1 目前的执行情况 在研究了各种框架之后,我决定使用Python 非交互式进程的密码管理 挑战,python,security,password-protection,pid,shlex,Python,Security,Password Protection,Pid,Shlex,我需要一个密码管理工具,它将被其他进程调用(各种脚本:python、php、perl等),它将能够识别和验证调用方脚本,以便执行访问控制:返回密码或退出-1 目前的执行情况 在研究了各种框架之后,我决定使用python的keepassdb,它能够处理keepassv1.X后端数据库文件,并构建我自己的访问控制覆盖层(因为稍后可以定制并集成到我们的LDAP中,以供用户/组访问)。访问控制通过重载每个条目的notes字段来完成,以包括允许访问密码的SHA-256哈希列表。(注意,这也验证了脚本没有被
python
的keepassdb
,它能够处理keepassv1.X后端数据库文件,并构建我自己的访问控制覆盖层(因为稍后可以定制并集成到我们的LDAP中,以供用户/组访问)。访问控制通过重载每个条目的notes
字段来完成,以包括允许访问密码的SHA-256哈希列表。(注意,这也验证了脚本没有被任何人更改)
使用-p
参数调用密码管理器,该参数是被调用脚本/应用程序的PID,并将执行以下步骤:
1
之前,必须找到调用方PID,该进程是父进程0的init
。这样我们就可以确定是谁调用了这个密码管理器实例shlex
用于此)caller.py
成为允许访问特定条目e
的脚本。运行它时,命令行看起来像python/path/to/caller.py arg1 arg2。解析命令行的代码是:
cmd=walk\u ppids(pid)
lg.debug(cmd)
如果cmd为False:
lg.错误(“PID%s不是我的父进程或根本不是进程!”%PID)
系统出口(-1)
cmd_parts=shlex.split(cmd)
正在运行_script=“”
对于cmd_零件中的p:
如果重新搜索(\(php | py | pl | sh | groovy | bat)$),p,re.I):
运行脚本=p
打破
如果未运行\u脚本:
lg.error(“无法识别此脚本的名称/路径!”)
系统出口(-1)
running\u script=os.path.abspath(running\u script)
lg.debug(“找到”+运行_脚本)
phash=hash_文件(打开(运行_脚本'rb'),hashlib.sha256()
父进程的命令行是通过以下方式获取的:
os.popen(“ps-p%s-o args=“%ppid).read().strip()
现在,混淆上述函数的最简单方法是创建一个shell脚本,而不使用.sh
扩展名,该扩展名将caller.py
作为第一个参数。sh不使用其参数,而是调用密码管理器查询条目e
。命令行看起来像false\sh./caller.py
,因此上面的代码返回pass。。。这样做是错误的
问题
有人会认为这是一个很早以前就解决的常见问题,没有程序员将硬编码传递到脚本/应用程序,但我做了几天的研究,似乎找不到任何类似的方法。我理解这个问题更具开放性,因此我将接受以下答案:
- 我是在重新发明轮子吗?是否有类似的框架/软件
- 依靠PIDs,这是正确的方法吗?还有别的办法吗
- 在实现方面,发布的代码是否可以改进为更健壮、更容易混淆?(
分析部分)shlex
caller.py
不能在/bin/bash
上运行
python也可以利用类似的漏洞,例如
命令python-W./caller.py./myUberHack.py
。如果命令行分析器向解释器查找第一个.py
参数,则会认为caller.py
正在运行。。。但事实并非如此
为所有解释器构建所有调用规则太耗时了,所以我硬编码了这些假设。它们存储在元组中,每行为:
(file extension, positional argument, interpreter first letters)
exts=(
(“.py”,1,“python”),
(“.php”,2,“php”),
(“.pl”,1,“perl”),
(“.sh”,1,“/bin/bash”),#假设,我们只接受bash
(“.groovy”,1,“groovy”),
(“.rb”,1,“ruby”),
)
“”“将扩展名与位置参数和解释器匹配”“”
现在的验证代码是:
exts中i的:
#检查指定的cmdline位置和扩展名
如果cmd_parts[i[1]].strip().endswith(i[0]):
lg.debug(“检查”+cmd_部分[i[1]])
正在运行\u script=cmd\u parts[i[1]]
#确保解释器与扩展名匹配
如果运行的是_script.endswith(i[0]),而不是cmd_parts[0]。则使用(i[2])启动:
lg.错误(“错误的解释者…走开…”)
系统出口(-1)
打破
现在想不出比这更好的了……改进:使规则更加严格
第一步是确认正确的扩展在正确的解释器上运行,这意味着caller.py
不能在/bin/bash
上运行
python也可以利用类似的漏洞,例如
命令python-W./caller.py./myUberHack.py
。如果命令行分析器向解释器查找第一个.py
参数,则会认为caller.py
正在运行。。。但事实并非如此
<