在发送 stdin 输入之前等待来自子进程的提示

use*_*042 6 python subprocess fuzzing

我有一个 linux x86 二进制文件,它要求输入密码并打印出密码是正确还是不正确。我想使用 python 来模糊输入。

下面是我运行二进制文件的屏幕截图,然后给它字符串“asdf”,并收到字符串“不正确”

截屏:

截屏

到目前为止,我已经尝试使用 Python3 subprocess 模块来

  1. 将二进制文件作为子进程运行
  2. 收到密码提示
  3. 发送一个字符串。
  4. 收到回复

这是我的脚本

p = subprocess.Popen("/home/pj/Desktop/L1/lab1",stdin=subprocess.PIPE, stdout=subprocess.PIPE)
print (p.communicate()[0])
Run Code Online (Sandbox Code Playgroud)

运行这个脚本的结果是

b'Please supply the code: \nIncorrect\n'
Run Code Online (Sandbox Code Playgroud)

我希望只收到提示,但是在我有机会发送我的输入之前,二进制文件也返回了不正确的响应。

我如何改进我的脚本以便成功地与这个二进制文件交互?

iva*_*eev 6

仔细阅读文档(强调我的):

\n\n
\n

Popen.communicate(input=None)

\n\n

与进程交互:将数据发送到标准输入。从 stdout 和 stderr 读取数据,直到到达文件末尾。等待进程终止。\n 可选输入参数应该是要发送到子进程的字符串\n或 None(如果不应向子进程发送数据)。

\n\n

communicate()返回一个元组(stdoutdata, stderrdata)

\n\n

请注意,如果要将数据发送到进程\xe2\x80\x99s stdin,则需要\n 使用stdin=PIPE. 类似地,要在结果元组中获取除 None 之外的任何内容,您也需要给出stdout=PIPE\n 和/或stderr=PIPE

\n
\n\n

因此,您没有向该进程发送任何内容,而是立即读取所有内容。stdout

\n\n
\n\n

在您的情况下,您实际上不需要等待提示将数据发送到进程,因为流异步工作:进程仅在尝试读取其时才会获取您的输入STDIN

\n\n
In [10]: p=subprocess.Popen(("bash", "-c","echo -n \'prompt: \'; read -r data; echo $data"),stdin=subprocess.PIPE,stdout=subprocess.PIPE)\n\nIn [11]: p.communicate(\'foobar\')\nOut[11]: (\'prompt: foobar\\n\', None)\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

如果您出于某种原因坚持等待提示(例如,您的进程也在提示之前检查输入,期待其他内容),您需要STDOUT手动阅读并非常小心阅读的内容:因为 Python 是file.read阻塞的,一个简单的read()将死锁,因为它等待 EOF 并且子进程不会关闭STDOUT- 因此不会产生 EOF - 直到它收到您的输入。如果输入或输出长度可能超过 stdio 的缓冲区长度(在您的具体情况下不太可能),您还需要在单独的线程中执行 stdout 读取和 stdin 写入

\n\n

这是一个可以pexpect为您解决这个问题的示例(我使用的是pexpect.fdexpect而不是pexpect.spawn 文档中建议的,因为它适用于所有平台):

\n\n
In [1]: import pexpect.fdpexpect\n\nIn [8]: p=subprocess.Popen(("bash", "-c","echo -n \'prom\'; sleep 5; echo \'pt: \'; read -r data; echo $data"),stdin=subprocess.PIPE,stdout=subprocess.PIPE)\n\nIn [10]: o=pexpect.fdpexpect.fdspawn(p.stdout.fileno())\n\nIn [12]: o.expect("prompt: ")\nOut[12]: 0\n\nIn [16]: p.stdin.write("foobar")    #you can communicate() here, it does the same as\n                                    # these 3 steps plus protects from deadlock\nIn [17]: p.stdin.close()\nIn [18]: p.stdout.read()\nOut[18]: \'foobar\\n\'\n
Run Code Online (Sandbox Code Playgroud)\n

  • 程序可以在提示之前刷新输入,就像“getpass”的情况一样。我怀疑,这样做是为了防止天才用“echo password |”发送密码。myprogram`,并记录他们的密码。 (2认同)