如何从Perl脚本输入/回答终端提示?

问题描述

我正试图破解一个luks分区的忘记密码。我生成一个组合列表,现在我正尝试从Perl脚本中解密该卷。

问题是从脚本本身输入提示,因为:system('cryptsetup',('open','/dev/sdd1','crypt-vol','--type=luks'))只是吐出Enter passphrase for /dev/sdd1并等待我手动输入。

我该如何处理?

非常感谢您的帮助。

* 这是我的密码,并且我还没有完全忘记密码,因此,只要我记得一些细节,就可以创建组合列表。就像> 6k的可能性,所以打破它应该是可行的。

解决方法

不要在cryptsetup中使用“密钥文件”。密钥文件可以是STDIN。

所以:

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

在perl中,您可以使用IPC::Run2来进行此操作,从而允许您对FH进行读/写操作,但是如果您只需要返回码来测试密码,则不需要。

例如https://blog.sleeplessbeastie.eu/2019/03/27/how-to-test-luks-passphrase/

所以:

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

print {$crypter} "Your passphrase";

close ( $crypter );
print "Got return code of $?"
,

我实际上很喜欢使用STDIN的想法,因此,如果有人在此页面上亮过,请考虑是否可以根据自己的情况使用STDIN。

但是我想发布自己的答案,该答案使用Expect Perl模块,因为:

  • 我使用了它,并且证明它至少可以在Linux上工作(尽管注释中的问题提到该模块在Windows上运行时存在问题);
  • 因为问题的标题没有提及cryptsetup(可以接受STDIN上的密码),所以Expect模块就像这里的通用解决方案,应该可以在其他工具上使用;

我的解决方案如下。我没有阅读太多文档,因此可能会有更好的方法来做到这一点。对我来说,掌握对象实例化的概念以及期望/发送方法就足够了。

您可以像在终端中启动程序一样创建实例:

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

然后可以通过expect(等待/确认程序对用户的输出)和send(允许用户进行“键入”)方法与之交互。

expect可以在标量或列表上下文中调用(我使用了清单1),并且它接受期望输出多长时间的字符串或正则表达式。如果在指定时间内没有发生预期的输出,则会引发错误:

                       #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的完整特定解决方案(我已经在一个能够安装的虚拟卷上​​对其进行了测试,并且已经在一个虚拟卷上运行了该解决方案。尝试了6k组合的真实体积,而没有任何明显的问题):

*我忘了在这里关闭文件描述符,所以应该在适当的地方添加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,'Enter passphrase') or die 'err 2';
  $exp->send($pass);
  @out = $exp->expect(10,'No key available') or die 'err 3';

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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...