I am writing a very simple bind shell in Perl that is supposed to open a specific port on windows and when I connect to it with ncat, I should be able to write commands from ncat, those be executed on the machine and to return me STDOUT.
Here is my code so far:
use strict; use IO::Socket;
my($sock, $newmsg, $cmd, $MAXLEN, $PORTNO);
$MAXLEN = 2048;
$PORTNO = 4444;
$sock = IO::Socket::INET->new(LocalPort => $PORTNO, Proto => 'udp');
while ($sock->recv($newmsg, $MAXLEN)) {
my($port, $ipaddr) = sockaddr_in($sock->peername);
my #cmd = qx($newmsg);
print(#cmd);
$sock->send(#cmd);
}
If I type something easy like echo Hello world it returns as expected, Hello World. Problem arises when I type dir or something that includes new lines(or so I have guessed, I'm pretty new with perl).
When typing dir, the result gets printed on the perl shell (as expected, due to print(#cmd), but then also prints usage: $sock->send(BUF, [FLAGS, [TO]]) at -e line 1. and exits, but I never receive the message in ncat.
I am running the command from a command shell as a one-liner:
perl -e "use strict; use IO::Socket; my($sock, $newmsg, $cmd, $MAXLEN, $PORTNO); $MAXLEN = 1024; $PORTNO = 4444; $sock = IO::Socket::INET->new(LocalPort => $PORTNO, Proto => 'udp'); while ($sock->recv($newmsg, $MAXLEN)) {my($port, $ipaddr) = sockaddr_in($sock->peername);my #cmd = qx($newmsg);print(#cmd);$sock->send(#cmd);}"
How can I do it so that it prints things as dir?
Your problem is with $sock->send(#cmd). The send method expects the message to be a scalar not an array. You can fix this by the following
my $CRLF="\x0D\x0A"; # Network line break
$sock->send(join $CRLF, #cmd); # Convert #command into a single string
Related
Using Perl's Net::Telnet module to retrieve data from upsd.
There is one particular function I'm trying to implement, retrieving the data for a single var.
The problem is only a single line is output, and that line is used to match
Prompt, so it is not output.
Here's raw telnet:
telnet dns1 3493
Trying 192.168.15.1...
Connected to dns1.
Escape character is '^]'.
get var cp1500 ups.test.result
VAR cp1500 ups.test.result "Done and passed"
Connection closed by foreign host.
Here's some code:
#!/usr/bin/perl
use strict;
use warnings;
use Net::Telnet;
my $host = "dns1";
my $model = "cp1500";
my $bvar = "ups.test.result";
my $t = new Net::Telnet (Timeout => 3, Port => 3493, Prompt => "/VAR $model $bvar/");
$t->open($host);
my #ary = $t->cmd("get var $model $bvar");
print #ary,"\n";
This just prints the newline as the array is empty. Prompt is matched else there'd be a timeout error. How can I get that single line of output back for processing in the script?
This is my solution, use Socket instead of Net::Telnet.
#!/usr/bin/perl
use strict;
use warnings;
use Socket;
my $host = 'str003';
my $port = 3493;
my $model = 'cp1350';
my $quer = 'get var';
my $bvar = 'ups.test.result';
my ($sock,$iaddr,$paddr,$send);
$iaddr = inet_aton($host);
$paddr = sockaddr_in($port, $iaddr);
$send = join(' ',$quer,$model,$bvar);
socket($sock, AF_INET, SOCK_STREAM, 6) or die $!;
connect($sock , $paddr) or die "connect failed : $!";
send($sock , "$send\nlogout\n" , 0);
while (my $line = <$sock>)
{
if ($line =~ /^VAR/) {
print "$line\n";
}
}
close($sock);
This is the one where one line of data is returned:
VAR cp1350 ups.test.result "Done and passed"
If I want to start a Perl Dancer app, I have to run the following command:
perl app.psgi
If I want to pass an option to the application and access it inside the script from #ARGV, I can do it like this:
perl app.psgi --option1 --option2
I can run this app using also "plackup", however I cannot pass the options like when I am running the script using Perl. The #ARGV parameters array is empty.
What can I do?
How can I pass command line options to the "app.psgi" script started from "plackup"?
Below is the file of how the script approximately looks like:
#!/usr/bin/env perl
use Dancer2;
use Data::Dumper;
use MIME::Base64 qw( encode_base64 );
use POSIX;
my $system = shift #ARGV || 'default_system';
print "SYSTEM: $system\n";
my $host = '127.0.0.1';
my $port = 5000;
set host => $host;
set port => $port;
get '/expenses' => sub {
my %params = params;
return to_json {status => 'OK'};
};
post '/expenses' => sub {
my %params = params;
return to_json {status => 'OK'};
};
dance;
It seem like plackup is running the app in a sandbox environment where #ARGV is being erased.
You can still try use environment variables instead of arguments on the command line. For example, using MY_SYSTEM as an example:
#!/usr/bin/env perl
use Dancer2;
use Data::Dumper;
use MIME::Base64 qw( encode_base64 );
use POSIX;
print "SYSTEM: $ENV{MY_SYSTEM}\n";
# [...]
and then run the app using:
$ MY_SYSTEM=Foo plackup app.psgi
I have tried the perl modules Net::SSH:Perl and Net::OpenSSH to no avail. X11 forwarding does work because if I do a "ssh root#host" and execute an X application such as "xterm" I get a window back.
Here are some things I've tried:
$self->{'ssh'} = Net::OpenSSH->new("root:PW#".$hostname);
print $self->{'ssh'}->capture("env"); #The display variable is not set so it won't work
print $self->{'ssh'}->capture("xterm");
Nope
$self->{'ssh'} = Net::OpenSSH->new("root:PW#".$hostname, master_opts => ['-X' => '']);
print $self->{'ssh'}->capture("env"); #The display variable is not set so it won't work
print $self->{'ssh'}->capture("xterm"); #Nope
print $self->{'ssh'}->capture({master_opts => ['-X']}, "xterm"); #Nope
Nope, now for Net::SSH::Perl
$self->{'ssh'} = Net::SSH::Perl->new("$hostname", debug=>0);
$self->{'ssh'}->login("root","pass");
my ($stdout, $stderr, $exit) = $self->{'ssh'}->cmd("xterm"); #Nope
Nope
$self->{'ssh'} = Net::SSH::Perl->new("$hostname", debug=>0, options=>["ForwardX11 yes"]);
$self->{'ssh'}->login("root","pass");
my ($stdout, $stderr, $exit) = $self->{'ssh'}->cmd("xterm"); #Nope
The only thing that actually works is if I do the following, so I know X11 forwarding is working in Perl.
`ssh root#host xterm`
I would rather get the modules working if possible but if I can somehow open up a bidirectional pipe, communicate with SSH and receive data WHEN I WANT TO (similar to how I can $self->{'ssh'}->cmd() and receive the output at any time in my script), I will do that. I just don't know where to start. Anyone else did this before?
The development version of Net::OpenSSH has a new option forward_X11. This seems to work:
my $ssh = Net::OpenSSH->new("localhost", forward_X11 => 1);
print $ssh->capture({forward_X11 => 1}, "env"); # includes DISPLAY=localhost...
print $ssh->capture({forward_X11 => 1}, "xclock"); # starts the xclock program
Note that you have to specify the new option on both the constructor and the actual command.
See also http://www.perlmonks.org/?node_id=1028837
Try to debug this script. I think it maybe an issue of variable interpolation? I'm not sure.
It works using options if I pass the values like so:
perl test-file-exists.pl --file /proj/Output/20111126/_GOOD
I am trying to remove the option of passing in --file since I need to generate the date
dynamically.
perl test-file-exists.pl
Given the code changes below (I commented out the options piece). I am trying to create the string (see $chkfil). I am getting errors passing in $dt4. Somehow, its not passing in the file string that I am creating into this other module.
use strict;
use warnings;
use lib '/home/test/lib';
use ProxyCmd;
use Getopt::Long;
#
### Set up for Getopt
#
#my $chkfil;
#my $help;
#usage() if ( #ARGV < 1 or
# ! GetOptions('help|?' => \$help,
# 'file=s' => \$chkfil)
# or defined $help );
my $cmd = ProxyCmd->new( User=>"test_acct",
AuthToken=>"YToken",
loginServer=>"host.com");
# Get previous day
my $dt4 = qx {date --date='-1day' +'%Y%m%d'};
# Check file
my $chkfil = qq{/proj/Output/$dt4/_GOOD};
# Now test the fileExists function
print "Checking 'fileExists':\n";
my $feResults = $cmd->fileExists("$chkfil");
if ($feResults == 0) {
print "File Exists!\n";
} else {
print "File Does Not Exist\n";
}
sub usage
{
print "Unknown option: #_\n" if ( #_ );
print "usage: program [--file /proj/Output/20111126/_GOOD] [--help|-?]\n";
exit;
}
When you use backticks or qx, you get the trailing newline included so chomp it off:
my $dt4 = qx {date --date='-1day' +'%Y%m%d'};
chomp $dt4;
and you'll get a sensible filename.
You could also use DateTime and friends to avoid shelling out entirely.
I am using select with a TCP server. I want to add STDIN to the select filehandle set.
#!/usr/bin/perl
use IO::Select;
use IO::Socket::INET;
my $sock = IO::Socket::INET->new(LocalPort => $serv_listen_port, Proto => 'tcp', List en=> 1);
my $s = IO::Select->new();
$s->add(\*STDIN); #want to be responsive to user input (allow me to type commands for example)
$s->add($sock);
#readytoread=$s->can_read(1); #timeout = 1sec
foreach $readable (#readytoread) {
if ($readable==$sock) {
#This was a listen request, I accept and add new client here
}
if ($readable == STDIN){ #what to do on this line?
#This is user typing input into server on terminal
}
}
Need help with 4th to last line in the code here.
$readable->fileno == fileno STDIN
Or, if you're comfortable with that, fileno STDIN is zero, which you can check directly.
can_read returns the exact value passed to add, so you can simply use
$readable == \*STDIN