Как ввести/ответить на приглашение терминала из скрипта Perl?

Я пытаюсь взломать забытый пароль для раздела luks. Я сгенерировал список комбинаций и теперь пытаюсь расшифровать том из Perl-скрипта.

Проблема заключается в том, чтобы ввести подсказку из самого скрипта, так как: system('cryptsetup', ('open', '/dev/sdd1', 'crypt-vol', '--type=luks')) просто выплевывает Enter passphrase for /dev/sdd1 и ждет, пока я введу ее вручную.

Как я могу подойти к этому?

Большое спасибо за любую помощь.

* это мой том, и я не забыл пароль полностью, поэтому я создал список комбинаций при условии, что помню некоторые детали. Это как ›6 тысяч возможностей, так что это должно быть возможно сломать.


person Dmitry Koroliov    schedule 26.09.2020    source источник
comment
Это та же проблема? stackoverflow .com/questions/11236307/   -  person Christian Baumann    schedule 26.09.2020
comment
Забудьте о перле. Используйте expect, предназначенный для работы с интерактивными программами, читающими из /dev/tty.   -  person Jens    schedule 26.09.2020
comment
Возможно, использовать модуль Perl Expect?   -  person TLP    schedule 26.09.2020
comment
@Jens Я уже создал что-то с модулем Perl Expect. Вроде запустилось, теперь подожду часов 20 максимум (моя оценка), потом в зависимости от результатов что-нибудь выложу, либо ответ (если заработает), либо обновлю вопрос.   -  person Dmitry Koroliov    schedule 26.09.2020
comment
@TLP да, я делаю это сейчас. Единственное возможное? проблема может заключаться в том, что я создаю новый экземпляр expect в каждом цикле while, так как crypsetup завершает работу с кодом 512 на втором или третьем элементе для ввода пароля   -  person Dmitry Koroliov    schedule 26.09.2020
comment
@user907860 user907860 Это может быть то, о чем вы могли бы спросить в новом вопросе.   -  person TLP    schedule 26.09.2020
comment
читая справочную страницу для cryptsetup, вы можете указать --key-file вместо запроса пароля   -  person hoffmeister    schedule 26.09.2020
comment
--key-file тоже может быть STDIN.   -  person Sobrique    schedule 26.09.2020


Ответы (2)


Не используйте «ключевой файл» с cryptsetup. Файл ключа может быть STDIN.

So:

echo "passphrase_here" | cryptsetup -d - <other  options>

В Perl вы можете использовать для этого IPC::Run2, что позволяет вам читать/записывать в FH, но если вам просто нужен код возврата для проверки парольной фразы, это не нужно.

Например. https://blog.sleeplessbeastie.eu/2019/03/27/how-to-test-luks-passphrase/

So:

open ( my $crypter, '|-', "cryptsetup luksOpen -d - --test-passphrase " )

print {$crypter} "Your passphrase";

close ( $crypter );
print "Got return code of $?"
person Sobrique    schedule 26.09.2020

Мне действительно понравилась идея использовать STDIN, поэтому, если кто-нибудь когда-нибудь попадет на эту страницу, подумайте, можете ли вы использовать STDIN в своей ситуации.

Но я хотел бы опубликовать свой собственный ответ, в котором используется модуль Expect Perl, потому что:

  • Я использовал его, и было доказано, что он работает, по крайней мере, в Linux (хотя в вопросе в комментариях упоминается, что у модуля были проблемы с запуском в Windows);
  • поскольку вопрос был назван без упоминания cryptsetup (который может принимать пароль на STDIN), поэтому модуль Expect здесь является общим решением, которое должно работать для других инструментов;

Мое решение ниже. Я не очень много читал документацию, поэтому могут быть лучшие способы сделать это. Для меня этого было достаточно, чтобы понять идею создания экземпляра объекта и методы ожидания/отправки.

Вы создаете экземпляр, как если бы вы только что запустили программу в терминале:

my $exp = Expect->new('progName', ($arg1, $arg2, $etc));

Затем с ним можно взаимодействовать с помощью методов expect (который ожидает/подтверждает вывод программы пользователю) и send (который позволяет пользователю "печатать").

expect может вызываться как в скалярном, так и в списочном контексте (я использовал списочный), и он принимает строку или регулярное выражение того, какой результат ожидать и как долго. Если за указанное время не произошло ожидаемого вывода, выдается ошибка:

                       #sec to wait for  #use regexp (don't match exactly) #regexp to match against
my @out = $exp->expect(10,               '-re',                            'smth');

send просто принимает ввод

$exp->send('some chars');

Вот и все, нужно просто создать скрипт, который будет работать так, как будто это человек-пользователь.


И на всякий случай, если это может быть кому-то удобно, я опубликую свое полное конкретное решение для cryptsetup (я протестировал его на фиктивном томе, который он смог смонтировать, и я запустил его на реальном томе с 6к комбинаций перепробовал без заметных проблем):

*Я забыл закрыть здесь файловый дескриптор, поэтому нужно добавить close($fd), где это уместно

use strict;
use warnings;
use feature 'say';


# I installed Expect with its deps locally in my situation, so I had to change @INC
BEGIN {
  unshift(@INC, './perl-mods/lib/perl5/');
  unshift(@INC, './perl-mods/lib/perl5/x86_64-linux-thread-multi/');
}

use Expect;

my $devName = '/dev/sdb3';
my $combinationsFileName = 'combs.txt';
open(my $fd, '<', $combinationsFileName);
my $lineCount = 0;

while (<$fd>) {
  my $pass = $_;
  chomp($_);
  say $_ . ' ' . ++$lineCount;

  my $exp = Expect->new('cryptsetup', ('open', $devName, 'crypt-vol')) or die 'err 1';
  my @out = $exp->expect(10, '-re', 'Enter passphrase') or die 'err 2';
  $exp->send($pass);
  @out = $exp->expect(10, '-re', 'No key available') or die 'err 3';

  #if cryptsetup returned an error code
  if ($out[1]) {
    die $out[1] . ' ' . $pass;
  }
}
person Dmitry Koroliov    schedule 27.09.2020