SSH login through Perl - perl

I am using Net:Appliance::Session to login to a remote Unix server, but am not able to connect. Below is my code and the debug output:
my $s = Net::Appliance::Session->new({
personality => 'Bash',
transport => 'SSH',
host => $host,
});
$s->set_global_log_at('debug');
try {
print "Trying to connect\n";
$s->connect({ username => $user, password => $pass });
print "Executing command\n";
print $s->cmd($cmd);
}
catch {
warn "failed to execute command: $_";
}
finally {
$s->close;
};
And the output is:
Trying to connect
[ 0.019420] pr finding prompt
[ 0.028553] tr creating Net::Telnet wrapper for ssh
[ 0.031377] tr connecting with: ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o CheckHostIP=no -l user ...
[ 3.151205] du SEEN:
Warning: Permanently added '...' (RSA) to the list of known hosts.
[ 3.183935] pr failed: [Can't call method "isa" on an undefined value at /usr/lib/perl5/site_perl/5.14/Net/CLI/Interact/Phrasebook.pm line 247.
], sending WAKE_UP and trying again
[ 3.184943] pr finding prompt
[ 4.898408] du SEEN:
Warning: Permanently added '...' (RSA) to the list of known hosts.
Password:
[ 4.920447] pr failed to find prompt! wrong phrasebook?
failed to execute command: Warning: Permanently added '...' (RSA) to the list of known hosts.
Password:
...propagated at /usr/lib/perl5/site_perl/5.14/Net/CLI/Interact/Role/Prompt.pm line 127.
When I login through Putty, I get the following response and can login successfully:
login as: user
Using keyboard-interactive authentication.
Password:
I cannot figure out what I am doing wrong. Any help is appreciated.
EDIT: I think I should mention that I am using Cygwin for this. I have manually logged in to the remote server and the keys in my .ssh/known_hosts file are also set, but still get the RSA error when running this program in Cygwin. I saw this question in SO: "Warning: Permanently added to the list of known hosts” message from Git and added the line UserKnownHostsFile ~/.ssh/known_hosts to my config file, but the error refuses to go away.
EDIT2: When I use the -vvv option in the above program, I get the following output:
Trying to connect
[ 0.020327] pr finding prompt
[ 0.062541] tr creating Net::Telnet wrapper for ssh
[ 0.063709] tr connecting with: ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o CheckHostIP=no -vvv -l user 1.1.1.1
[ 0.731041] du SEEN:
OpenSSH_6.2p2
[ 0.851829] pr failed: [Can't call method "isa" on an undefined value at /usr/lib/perl5/site_perl/5.14/Net/CLI/Interact/Phrasebook.pm line 247.
], sending WAKE_UP and trying again
[ 0.852459] pr finding prompt
[ 0.852748] du SEEN:
OpenSSH_6.2p2, OpenSSL 1.0.1e 11 Feb 2013
[ 0.863739] pr failed to find prompt! wrong phrasebook?
failed to execute command: OpenSSH_6.2p2, OpenSSL 1.0.1e 11 Feb 2013
...propagated at /usr/lib/perl5/site_perl/5.14/Net/CLI/Interact/Role/Prompt.pm line 127.

The Net::Appliance::Session module is using is set of matching patterns called "Phrasebook" to guess password query output, command ending prompt, ...
In your case, there are 2 major issue and one minor/cosmetic one:
Net::Appliance::Session rely on connection profile. The correct one is named "bash" and not "Bash"
The bash default phrasebook (located in "~site_perl/Net/CLI/Interact/phrasebook/unix/bash/pb") is targeting ssh/bash based appliance and is not matching your everyday unix server behavior:
prompt user
match /[Uu]sername: $/
prompt pass
match /password(?: for \w+)?: $/
prompt generic
match /\w+#.+\$ $/
prompt privileged
match /^root#.+# $/
macro begin_privileged
send sudo su -
match pass or privileged
macro end_privileged
send exit
match generic
macro disconnect
send logout
As you can see, both "generic" and "pass" prompt does not match your usual linux password and prompt. You will need to adjust it to your needs:
create a library structure by creating some nested directory: "mylib\mybash\"
make a copy of the "bash" phrasebook to that nested directory and edit it to match your unix server behaviour.
There is also the ssh warning output:
Warning: Permanently added '...' (RSA) to the list of known hosts.
You just need to set ssh warnings to off using either the "-q" or "-o LogLevel=quiet" options to the ssh calling options.
So, in the end, your code would look like that:
my $s = Net::Appliance::Session->new
({ add_library => 'mylib',
personality => 'mybash',
transport => 'SSH',
host => $host,
connect_options => { opts => [ '-q', ], },
});
$s->set_global_log_at('debug');
try {
print "Trying to connect\n";
$s->connect({ username => $user, password => $pass });
print "Executing command\n";
print $s->cmd($cmd);
}
catch {
warn "failed to execute command: $_";
}
finally {
$s->close;
};
With a phrasebook like this one (quickly tuned to my freebsd server):
prompt user
match /[Uu]sername: $/
prompt pass
match /[Pp]assword:\s*$/
prompt generic
match /\w+#.+[\$>] $/
prompt privileged
match /^root#.+# $/
macro begin_privileged
send sudo su -
match pass or privileged
macro end_privileged
send exit
match generic
macro disconnect
send logout
macro paging
send terminal length %s
NOTE:
About "Net::Appliance::Session" vs "Net::OpenSSH":
both modules are handling ssh connectionx fine
"Net::Appliance::Session" is more "cisco/whatever-appliance" oriented, but should permit easily to connect to a server, execute 1 command, get its result, then go root and execute another command (very handy if you don't have direct root access from ssh)
"Net::OpenSSH" is handling command execution though ssh on 1 command only basis, that is it execute a command, get its result and exit. No direct way to set an environment, go root and execute the command (you need to use a wrapper like Net::Telnet on it to do that)
"Net::OpenSSH" requires a fairly recent version of openssh client and does not work on Windows, not even under Cygwin (see "Net::OpenSSH" manual).

Try using Net::OpenSSH instead. It would be easier to use and more reliable when talking to a Unix server.

Related

I am trying to create a tpm2-based auto unlock sh script, but the script fails with file not found

I am trying to create a TPM-based unlock script using tpm2-tools with instructions from Tevora Secure boot tpm2. I have set up the key, loaded it with cryptsetup luksAddKey secret.bin, then tested it using tpm2_unlock -c 0x81000000 --auth pci:sha1:0,2,3,7 and returns the value of secret.bin. For extra measures, to make sure it works, I loaded secret.bin into "/etc/crypttab", ran # update-initramfs -u -k all, and rebooted. Upon reboot, the system unlocked.
I copied over the following code into "/etc/initramfs-tools/hooks/tpm2"
#!/bin/sh -e
if [ "$1" = "prereqs" ]; then exit 0; fi
. /usr/share/initramfs-tools/hook-functions
copy_exec /usr/local/bin/tpm2_unseal
copy_exec /usr/local/lib/libtss2-tcti-device.so
I appended my etc/crypttab from cryptname UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx none luks to cryptname UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx none luks,keyscript=/usr/local/bin/passphrase-from-tpm
I rewrote the following script because the tpm2-tools command was outdated, edited in the new command, and stored it in /usr/local/bin/passphrase-from-tpm:
#!/bin/sh
set -e
echo "Unlocking via TPM" >&2
export TPM2TOOLS_TCTI="device:/dev/tpm0"
/usr/local/bin/tpm2_unseal -c 0x81000000 --auth pcr:sha1:0,2,3,7
if [ $? -eq 0 ]; then
exit
fi
/lib/cryptsetup/askpass "Unlocking the disk fallback $CRYPTTAB_SOURCE ($CRYPTTAB_NAME)\nEnter passphrase: "
I ran # update-initramfs -u -k all then rebooted. In reboot, I get the following error: /lib/cryptsetup/scripts/passphrase-from-tpm: line 5: /usr/local/bin/tpm2_unseal: not found
I have tried many times to edit passphrase-from-tpm unsuccessfully, including:
Moving both passphrase-from-tpm into "/boot/efi/EFI/BOOT/" and referencing crypttab to that file
Modifying passphrase-from-tpm to use a relative file path to tpm_unseal
Before I figured out how to create a backup linux boot using:
objcopy \
--add-section .osrel=/etc/os-release --change-section-vma .osrel=0x20000 \
--add-section .cmdline=cmdline.txt --change-section-vma .cmdline=0x30000 \
--add-section .linux="/boot/vmlinuz" --change-section-vma .linux=0x40000 \
--add-section .initrd="/boot/initrd.img" --change-section-vma .initrd=0x3000000 \
/usr/lib/systemd/boot/efi/linuxx64.efi.stub /boot/EFI/BOOT/BOOT_RECX64.EFI
I would be locked out of the system completely because of the error and had to reinstall Ubuntu about 40 times. I have suffered a lot and want to quit but I am too stubborn to throw in the flag.
just copy tpm2_unseal to /usr/local/bin/
I'm trying to make a working setup following basically those instructions, plus a few others I have found. While not working 100% yet, check that both /etc/initramfs-tools/hooks/tpm2 and /usr/local/bin/passphrase-from-tpm are marked executable (sudo chmod ug+x $filename).
After making the initramfs, you can run the following to ensure that the TPM related files are actually in the image. Replace the path in the filename by whatever update-initramfs said it was generating:
$ lsinitramfs /boot/initrd.img-5.0.0-37-generic | egrep "(tpm|libtss)"
lib/cryptsetup/scripts/passphrase-from-tpm
lib/modules/5.0.0-37-generic/kernel/crypto/asymmetric_keys/tpm_key_parser.ko
lib/modules/5.0.0-37-generic/kernel/crypto/asymmetric_keys/asym_tpm.ko
lib/udev/rules.d/tpm-udev.rules
usr/local/lib/libtss2-sys.so.0
usr/local/lib/libtss2-mu.so.0
usr/local/lib/libtss2-sys.so.0.0.0
usr/local/lib/libtss2-tcti-device.so
usr/local/lib/libtss2-tcti-device.so.0
usr/local/lib/libtss2-tcti-device.so.0.0.0
usr/local/lib/libtss2-mu.so.0.0.0
usr/local/bin/tpm2_unseal
Additionally, I have modified /usr/local/bin/passphrase-from-tpm to the following:
#!/bin/sh
TPM_DEVICE=/dev/tpm0
TPM_REGISTER=0x81000001
TPM_SEAL_POLICY=sha256:0,2,4,7
export TPM2TOOLS_TCTI="device:$TPM_DEVICE"
if [ "$CRYPTTAB_TRIED" -eq 0 ]; then
echo "Unlocking via TPM" >&2
/usr/local/bin/tpm2_unseal -H $TPM_REGISTER -L $TPM_SEAL_POLICY
UNSEAL_STATUS=$?
echo "Unseal status $UNSEAL_STATUS" >&2
if [ $UNSEAL_STATUS -eq 0 ]; then
exit
fi
else
echo "TPM unlocking previously failed for $CRYPTTAB_SOURCE ($CRYPTTAB_NAME)" >&2
/lib/cryptsetup/askpass "Enter passphrase for $CRYPTTAB_SOURCE ($CRYPTTAB_NAME): "
fi
Note that the command line options to tpm2_unseal are for the 3.x versions of tpm2-tools. If you're using another version, you might need to update the options.
I pulled out various bits into variables at the top of the file. Modify TPM_REGISTER and TPM_SEAL_POLICY to match how you created the TPM object. set -e was removed since if any command failed, the whole script would exit, preventing the askpass fallback from ever running if tpm2_unseal failed.
Additionally, I noticed that if the script fails for some reason, systemd will attempt to run it again. If the secret in the TPM doesn't match the LUKS key, this will render the system unbootable, since the unseal succeeds, but unlocking fails, and systemd will run the script again.
Looking at the man page for crypttab, I discovered that one of the environment variables provided to the keyscript is CRYPTTAB_TRIED which is the number of tries it has attempted to unlock the volume. If CRYPTTAB_TRIED is 0, it'll attempt to use the TPM, as shown by this test (Running as non-root, so accessing the TPM device fails):
$ export CRYPTTAB_SOURCE=some_device
$ export CRYPTTAB_NAME=some_device_name
$ export CRYPTTAB_TRIED=0
$ ./passphrase-from-tpm
Unlocking via TPM
ERROR:tcti:src/tss2-tcti/tcti-device.c:440:Tss2_Tcti_Device_Init() Failed to open device file /dev/tpm0: Permission denied
ERROR: tcti init allocation routine failed for library: "device" options: "/dev/tpm0"
ERROR: Could not load tcti, got: "device"
Unseal status 1
When it tries running the script again, CRYPTTAB_TRIED will be greater than 0, making it display the password prompt instead:
$ export CRYPTTAB_TRIED=1
$ ./passphrase-from-tpm
TPM unlocking previously failed for some_device (some_device_name)
Enter passphrase for some_device (some_device_name):
Hopefully this is still of use to you, and helpful to anyone else trying to get the house of cards that is disk encryption with a TPM on Linux working.

Perl - Can't get data from metasploit RPC server

What I have used as resource : https://metasploit.help.rapid7.com/v1/docs/rpc-api
First I have started msf rpc server :
msfrpcd -U msf -P test -f -S -a 127.0.0.1
[*] MSGRPC starting on 127.0.0.1:55553 (NO SSL):Msg...
[*] MSGRPC ready at 2019-01-11 00:56:29 +0900.
after that the server is up and is showing up via browser in http://127.0.0.1:55553
The script I have used while using XML::RPC to get data
use XML::RPC;
use strict;
use warnings;
my $fm = XML::RPC->new( 'http://127.0.0.1:55553/api/' );
my $session = $fm->call( 'auth.login', { username => 'msf', password => 'test' });
my $x = $fm->call('group.command'); #api
The error when I run the script :
no data at /usr/local/share/perl/5.26.1/XML/RPC.pm line 288.
It seems that the api used is not working or perphaps something wrong
Do you have any better way to get data from msf rpc server?

Replace host key automatically on linux

I have a script that connects to an SFTP server with the following code:
use Net::SFTP::Foreign;
my %cfg = (
user => "$user",
password => "$password",
port => 22,
more => [-o => 'StrictHostKeyChecking no']
);
my $sftp = Net::SFTP::Foreign->new("$host",%cfg);
I am using StrictHostKeyChecking to make sure the script automatically accepts the ssh key.
The issue begins when the server replaces the host key with new one. I get the error: WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
So I have to manually remove the key by running ssh-keygen -R testserver.com
After that the script works fine again.
I am trying to find a way to autmatically replace the key if it changes.
Technically I can run ssh-keygen -R testserver.com every time the script runs, but I do not like that solution.
So far I am not able to a good automated way to replace the key.
Add another option that points UserKnownHostsFile to /dev/null should do the trick, not that it's recommend from security perspective ;-)
use Net::SFTP::Foreign;
my %cfg = (
user => "$user",
password => "$password",
port => 22,
more => [-o => 'StrictHostKeyChecking=no',
-o => 'UserKnownHostsFile=/dev/null']
);
my $sftp = Net::SFTP::Foreign->new("$host",%cfg);

Perl and Selenium::Remote::Driver

EDITED AGAIN
I have a server on AWS somewhere in Northern Virginia and this is my monitoring server. I ssh into this Ubuntu server from another State to do system administration. I want to do web automation tests on this server which will test a web application on the Internet hitting a URL and verify that I can selenium test a login and authenticate successfully. This server is on an AWS cloud I'm not quite sure which Perl module to use since I'm accessing it remotely.
There are two CPAN modules: Selenium::Remote::Driver and WWW::Selenium. I have tried both and they are giving me issues. And I really don't know which is appropriate for my scenario. When I use Selenium::Remote::Driver, I get the following error:
Selenium server did not return proper status at /usr/local/share/perl/5.18.2/Selenium/Remote/Driver.pm line 401.
When I use WWW::Selenium, I get this error:
Failed to start new browser session: org.openqa.selenium.server.RemoteCommandException: Error while launching browser
I was able to launch firefox manually from the AWS monitoring server by exporting the DISPLAY but it was really slow. I have heard that I can use a headless browser but I would have to export the DISPLAY by:
export DISPLAY=:5
But remember, I'm sshing into this AWS/Selenium server from my desktop so I'm assuming I use the above command on the AWS/Selenium Server while I'm ssh into it from my desktop? Actually, at this point, I'm not sure I'm doing here. Can somebody help?
The problem in this type of questions is that the variety of configurations and binaries in your setup might be so broad that the it is hard to actually provide a straight and correct answer for YOUR SETUP.
This answer has the following assumptions:
you have downloaded the selenium-server-standalone.jar into /usr/lib/
you have jdk 1.8 ( run the java -version in the shell
you have installed and configured the xvfb-run ( it is a fight on it's own )
So :
```
# ssh to your server , obs the -X !
ssh -X user-name#server-name
# start the selenium-server-standalone on the server
xvfb-run -e /dev/stdout java -Dwebdriver.chrome.driver=/usr/bin/chromedriver -jar /usr/lib/selenium-server-standalone.jar &
# one liner test - this is one veery long one
perl -e 'use strict ; use warnings ; use Data::Printer ; my $host="127.0.0.1"; use Selenium::Remote::Driver;my $driver = Selenium::Remote::Driver->new( "browser_name" =>"chrome", "error_handler" => sub { print $_[1]; croak 'goodbye'; }, "remote_server_addr" => "$host","port"=> "4444");$driver->debug_on();$driver->get("http://www.google.com"); print $driver->get_title();$driver->quit();' &
```
Here is the code in the one-liner as a perl script
#!/usr/bin/env perl
use strict ;
use warnings ;
use Carp ;
use Data::Printer ;
use Selenium::Remote::Driver;
my $host="127.0.0.1";
my $driver = Selenium::Remote::Driver->new(
"browser_name" =>"chrome"
, "error_handler" => sub { print $_[1]; croak 'goodbye' ; }
, "remote_server_addr" => "$host"
, "port"=> "4444") ;
$driver->debug_on() ;
$driver->get("http://www.google.com");
print $driver->get_title();
$driver->quit();
The output should look something like:
```
Prepping get
Executing get
REQ: POST, http://127.0.0.1:4444/wd/hub/session/ddb9c2575ab026cdb8c640bdc554181b/url, {"url":"http://www.google.com"}
RES: {"sessionId":"ddb9c2575ab026cdb8c640bdc554181b","status":0,"value":null}
Prepping getTitle
Executing getTitle
REQ: GET, http://127.0.0.1:4444/wd/hub/session/ddb9c2575ab026cdb8c640bdc554181b/title, {}
RES: {"sessionId":"ddb9c2575ab026cdb8c640bdc554181b","status":0,"value":"Google"}
GooglePrepping quit
Executing quit
REQ: DELETE, http://127.0.0.1:4444/wd/hub/session/ddb9c2575ab026cdb8c640bdc554181b, {}
RES: {"sessionId":"ddb9c2575ab026cdb8c640bdc554181b","status":0,"value":null}
```
Try running the below code:
#!/usr/bin/perl
use warnings;
use strict;
use Selenium::Remote::Driver;
my $host = "10.10.1.1"; //Enter your server IP in this place
my $driver = new Selenium::Remote::Driver('remote_server_addr' => $host,
'port' => '4444',
'auto_close' => 0);
$driver->get('http://www.google.com');

SNMP v3 with NET::SNMP working, but snmpwalk/snmpget not?

I have the following (working) perl script:
use Net::SNMP;
# create session to the host
my ($session, $error) = Net::SNMP->session(
-hostname => $hostname,
-version => 'snmpv3',
-username => 'my_user_name',
-authkey => 'my_authkey',#actually, here stands the real authkey as configured on the switch
-privkey => 'my_privkey',#same as on switch
-authprotocol => 'sha',
-privProtocol => 'des'
);
if (!defined($session)) {
print $error . "\n";
last;
}
# retrieve a table from the remote agent
my $result = $session->get_table(
-baseoid => $MAC_OID
);
if (!defined($result)) {
print $session->error . "\n";
$session->close;
last;
}
#print out the result of the snmp query
#....
Now I wanted to use snmpwalk or snmpget with the same keys. For that, I created a snmp.conf file in .snmp of my home directory with the following content:
defSecurityName my_user_name
defContext ""
defAuthType SHA
defSecurityLevel authPriv
defAuthPassphrase my_auth_key here
defVersion 3
defPrivPassphrase my_privkey here
defPrivType DES
As I see it, I use the same credentials in the script and for snmpget. Why do I get snmpget: Authentication failure (incorrect password, community or key) ?
That depends on the version of snmpget and snmpset you use. When I tested an older version of net-snmp against my C# based SNMP agent http://sharpsnmplib.codeplex.com I noticed that for SHA authen mode + DES privacy mode a bug prevented the net-snmp command line tools from generating the correct message bytes (the encryption is wrong so that no agent can decrypt it).
My suggestion is that you try to use Net::SNMP instead, as like you found out, it is not affected by the same bug.
Your problem is that you're using an authentication key for Net::SNMP and a password for the command-line net-snmp tools. Based on your Net::SNMP usage you're actually using 'localized' keys. Which means the right tokens for your snmp.conf file are:
defAuthLocalizedKey 0xHEXSTRING
defPrivLocalizedKey 0xHEXSTRING
See the snmp.conf manual page for further details.