Перед отправкой ввода стандартного ввода дождитесь запроса от подпроцесса - PullRequest
0 голосов
/ 23 января 2019

У меня есть бинарный файл Linux x86, который запрашивает пароль и распечатывает, является ли пароль правильным или неправильным. Я хотел бы использовать Python для фаззинга ввода.

Ниже приведен скриншот того, как я запускаю двоичный файл, затем задаю ему строку «asdf» и получаю строку «неправильный»

Скриншот:

Screenshot

До сих пор я пытался использовать модуль подпроцесса Python3 для

  1. запустить двоичный файл как подпроцесс
  2. получить запрос на ввод пароля
  3. отправить строку.
  4. получить ответ

Вот мой сценарий

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

результат выполнения этого скрипта

b'Please supply the code: \nIncorrect\n'

Я ожидаю получить только приглашение, однако двоичный файл также возвращает неправильный ответ, прежде чем я получу возможность отправить свой ввод.

Как я могу улучшить свой скрипт, чтобы успешно взаимодействовать с этим двоичным файлом?

1 Ответ

0 голосов
/ 23 января 2019

Внимательно прочитайте документацию (выделено мной):

Popen.communicate(input=None)

Взаимодействовать с процессом: Отправитьданные в стандартный вводЧитайте данные из stdout и stderr, пока не будет достигнут конец файла.Подождите, пока процесс завершится.Необязательный входной аргумент должен быть строкой для отправки дочернему процессу , или None, если никакие данные не должны быть отправлены дочернему процессу.

communicate() возвращает кортеж (stdoutdata, stderrdata).

Обратите внимание, что если вы хотите отправить данные в стандартный поток процесса, вам нужно создать объект Popen с stdin=PIPE.Точно так же, чтобы получить что-то кроме None в кортеже результата, вам нужно указать также stdout=PIPE и / или stderr=PIPE.

Итак, вы ничего не отправляете процессу и читаете все из stdout сразу.


В вашем случае вам на самом деле не нужно ждать запроса на отправку данных процессу, потому что потоки работают асинхронно:процесс получит ваш ввод, только когда попытается прочитать его STDIN:

In [10]: p=subprocess.Popen(("bash", "-c","echo -n 'prompt: '; read -r data; echo $data"),stdin=subprocess.PIPE,stdout=subprocess.PIPE)

In [11]: p.communicate('foobar')
Out[11]: ('prompt: foobar\n', None)

Если вы настаиваете на ожидании приглашения по какой-либо причине (например, ваш процесс проверяет ввод перед запросом,тоже, ожидая чего-то другого), вам нужно прочитать STDOUT вручную и быть ОЧЕНЬ осторожным, сколько вы читаете : поскольку Python file.read блокирует, простой read() будет тупиком, потому что он ожидает EOFи подпроцесс не закрывается STDOUT - таким образом, не производит EOF - пока не получит от вас информацию.Если длина входных или выходных данных может превышать длину буфера stdio (маловероятно в вашем конкретном случае), вам также необходимо выполнять чтение stdout и запись stdin в отдельных потоках .

ВотПример использования pexpect, который позаботится об этом для вас (я использую pexpect.fdexpect вместо pexpect.spawn , предложенного в документе , потому что он работает на всех платформах):

In [1]: import pexpect.fdpexpect

In [8]: p=subprocess.Popen(("bash", "-c","echo -n 'prom'; sleep 5; echo 'pt: '; read -r data; echo $data"),stdin=subprocess.PIPE,stdout=subprocess.PIPE)

In [10]: o=pexpect.fdpexpect.fdspawn(p.stdout.fileno())

In [12]: o.expect("prompt: ")
Out[12]: 0

In [16]: p.stdin.write("foobar")    #you can communicate() here, it does the same as
                                    # these 3 steps plus protects from deadlock
In [17]: p.stdin.close()
In [18]: p.stdout.read()
Out[18]: 'foobar\n'
...