How to fill in a Command Line Interface? - linux

I am to automate the installation phase of a legacy system, because I do not want to put more efforts again and again when ever I want to install it. During the installation process on Linux Terminal, I have to answer some questions regarding the basic configurations. Indeed, it is easy to automate the shell commands by putting them all in a batch file like the following:
bin/startServer destination/sub_v1
bin/startAdminInterface
....
However, I do not know how to automate the answers of a specific questions like the following:
Enter the server's IP address:
Enter the email of the contact person:
Would you like to disable UDP services?(y/n) [n]:
....
Is there any tool or programming language can deal with this situation? or Is there any way to pass the answers as a parameters within the batch file?
Thanks in advance.

The classic Linux tool for this job is expect.
With expect one can expect different questions and variations on a question, and the question does not have to be typed exactly. expect does not blindly answer every prompt, but rather it provides answers to the questions actually asked.
Here is a short example:
#!/usr/bin/expect -f
spawn someScript.sh
expect "Enter the server's IP address:"
send "10.0.0.4\r"
expect "Enter the email of the contact person:"
send "foo#bar.com\r"
expect "Would you like to disable UDP services?(y/n) [n]:"
send "y\r"

So, imagine this is a simplified version of the script:
#!/bin/bash
read -p "Enter something:" thing
read -p "Enter server IP:" ip
read -p "Enter Email:" email
echo Received $thing, $ip, $email
and this is in a file called answers
thingywhatnot
11.12.33.240
bozo#brains.com
You would run
installationScript < answers
and it would print this
Received thingywhatnot, 11.12.33.240, bozo#brains.com

Related

Security question: Are NodeJS spawns logged anywhere?

If you run a command in Terminal, say
rsync -avuP [SourcPath] [DestPath]
That command will get logged in, say .bash_history, .zsh_history, .bash_sessions, etc.
So if you make use of something as notoriously insecure as sshpass
say sshpass -P password -p MySecetPassword [Some command requiring std input], that too will be logged.
But what happens when you do the equivalent when spawning a process using Node JS?
passw = functionThatRetrievesPasswordSecurely();
terminalCmd = "sshpass";
terminalArgs = ["-P, "password", "-p", passw, "command", "requiring", "a", "password", "entry"];
spawn = require("child_process").spawn(terminalCmd, terminalArgs);
spawn.stdout.on("data", data => {console.log("stdout, no details"});
spawn.stderr.on("data", data => {console.log("stderr, no details"});
spawn.on("close", data => {console.log("Process complete, no details"});
Are the terminalCmd or terminalArgs logged anywhere?
If so, where?
If not, is this a secure way to make use opf sshpass?
There isn't a node specific history file for execs unless you created one by logging the arguments. There can be lower level OS logging that captures this type of data, like an audit log.
Passing a password on the command line is still considered the least secure way.
Try -f to pass a file or -d for a file descriptor instead (or ssh keys should always be the first port of call)
The man page explains...
The -p option should be considered the least secure of all of sshpass's options. All system users can see the password in the command line with a simple "ps" command. Sshpass makes a minimal attempt to hide the password, but such attempts are doomed to create race conditions without actually solving the problem. Users of sshpass are encouraged to use one of the other password passing techniques, which are all more secure.
In particular, people writing programs that are meant to communicate the password programatically are encouraged to use an anonymous pipe and pass the pipe's reading end to sshpass using the -d option.

NodeJS spawn does not escape bad strings

I want to download a url in a remote host using ssh, i was using exec(), it was working:
const cmd = `mkdir -p /home/username/test; wget --no-check-certificate -q -U \"\" -c \"${url}\" -O /home/username/test/img.jpg`;
const out = execSync(`ssh -o ConnectTimeout=8 -o StrictHostKeyChecking=no -p 2356 username#${ip} '${cmd}'`);
But it's usafe to use the url variable this way, the value of this variable is from user input, so i found some posts on stackoverflow saying that i need to use spawn:
const url = 'https://example.com/image.jpg';
const out = spawnSync('ssh', [
'-o', 'ConnectTimeout=8',
'-o', 'StrictHostKeyChecking=no',
'-p', '2356',
`username#${ip}`,
`mkdir -p /home/username/test; wget --no-check-certificate -q -U "" -c "${url}" -O /home/username/test/img.jpg`,
]);
What about if const url = 'https://example.com/image.jpg"; echo 5; "';, the echo will be executed, could someone tell me how to execute this code in a safe way?
There are two aspect. First, you are correct that execSync is unsafe. To quote from the documentation:
Never pass unsanitized user input to this function. Any input containing shell metacharacters may be used to trigger arbitrary command execution.
A solution is to use execSpawn, as you pointed out, for example, like in this related answer.
However, in your example, you are calling ssh and passing it a text, which will be executed by the shell on the remote system. Because of that, you are still vulnerable to the attack, as you showed in the example. But note that it is no longer a NodeJs related exploit, but an exploit on ssh and the shell.
To mitigate the attack, I would recommend to concentrate on the remote server. Instead of sending it a command over ssh, which it should trust and execute in the shell, you could provide a clear defined API from the server. In the HTTP interface, you can accept input and do a proper validation (instead of simplify trusting it). The advantage is that you do not need to deal with the subtleties of the shell.
If you are forced to work with ssh, you could validate the URL and only if it is safe, forward it to the server. It is still not ideal from a security perspective. First, the remote server will need to trust you completely (often it is better to avoid that and instead validate as locally as possible). Second, the validation itself is not straightforward. You will need to decide if a string looks like an URL (e.g. by using new URL(url)), but the more difficult aspect is to make sure that no exploits slip through. I don't have a concrete example, but I would be cautious to assume all strings that pass the URL parser will be safe to execute in a shell environment.
In summary, if possible try to avoid ssh with passing shell command in that situation (input data controlled by an attacker). Instead prefer a normal API like a HTTP interface (or other text or binary protocols). If it is not possible, try hard to sanitize the data before sending it out. Maybe you know in advance how a URL will look like (e.g. the list of allowed hostnames, allowed paths, etc). But realize that there might be hidden examples that you will overlook, and never underestimate the creativity of an attacker.

Using flock to lock file for X time

I am a Linux novice and currently developing a security system using Raspberry Pi 3 and MotionEye. To get notifications via e-mail, I am attempting to create a custom shell script that will send an e-mail if there is motion, lock for X minutes, then send another e-mail if there is still motion. However, I am having some difficulties.
I created a simple Python script named "send_email.py" using SMTP that works perfectly fine for sending e-mails when I execute it via command line.
The shell script (named "flock_email.sh") is where I run into troubles in a few regards:
Whenever I run flock_email.sh, it completely overwrites send_email.py. I have tried to change file permission so it is only executable by the user, but it still overwrites.
The flock command/function does not work as I intended or at all. I have looked all over the internet and tried multiple different codes, but none have worked. I have attached my various flock_email.sh scripts I have tried.
Not necessarily a problem, but I am a bit confused on what my "shebang" line should be. For flock_email.sh I have it as "!#/bin/bash", which I believe makes the script it executable, at least according to this. Do I still need to change the permissions via the command "chmod +x flock_email.sh"? The path is /home/pi, which is essentially the main directory of my Pi.
The different solutions I have tried:
In flock_email.sh, I have tried to directly change the file permissions to read-only instead of using flock, having it sleep, then changing the permissions back to allow execution of the file.
Multiple flock_email.sh implementations, as attached.
To summarize:
I need to execute send_email.py before locking the file flock_email.sh.
Once locked, it needs to stay locked for X time.
Does anyone have any pointers or suggestions? I have spent well over 15 hours tinkering with this and feel like I have gotten nowhere!
send_email.py:
#!/usr/bin/env
import smtplib
def send_email():
content = "Message I want to send to specified e-mail."
sender = "e-mail account that will send message"
pword = "password of sender"
receiver = "e-mail account that will receive message"
mail = smtplib.SMTP("smtp.gmail.com",587)
mail.ehlo
mail.starttls()
mail.login(sender,pword)
mail.sendmail(sender,receiver,content)
mail.close()
send_email()
flock_email.sh (1):
#!/bin/bash
(
python /home/pi/send_email.py
flock -e 200
sleep [time in seconds]
)
flock_email.sh (2):
#!/bin/bash
(
python /home/pi/send_email.py
exec 3>/home/pi/send_email.py
flock -x 3
sleep [time in seconds]
exec 3>&-
)
flock_email.sh (3):
#!/bin/bash
python /home/pi/send_email.py
chmod 444 /home/pi/send_email.py # modify to read only for all
sleep [time in seconds]
chmod 755 /home/pi/send_email.py # modify to rwx for owner, r-x for others
The reason why man flock and all posts say to use > is because you're supposed to use a dedicated lock file, typically in /var/lock:
#!/bin/bash
exec 3> /var/lock/motionmail
flock -ne 3 || exit
python /home/pi/send_email.py
sleep 3600
This additionally fixes you sending your email regardless, before you ever check the lock, and aborts new emails instead of queueing them all up.
You choose the lock file name based on the scope you want your lock to have:
If you only want one email per hour, you can use something like /var/lock/motionmail because there's just one per system.
If you want one email for each user per hour, you can use $HOME/.motionmail.lock because there's just one per user.
You can use /home/pi/send_email.py if you want with <, but this implies that you want one email per hour not only for each user, programming language and script copy, but also every time you hit save and replace the file with your editor*
* Editors differ in whether they replace or overwrite a file

Perl - How to send local mail?

I would like to integrate the following terminal command into a Perl script.
Terminal command:
mutt -s "User Monitoring" -a "/home/mipa/Documents/System_Monitoring/protocol_name.csv" -- mipa#localhost.localdomain
The command sends local mail containing a file attachment to a user on the same system.
I have a small problem with the command though. It does seem to require more user interaction than just the command listed here. The command requires the user to follow a menu to confirm the values and hit the "y" key to send.
My question here is two-folded. Is there a similar mail command that does not require user interaction and works by just following a single command with predefined flags? And how would I integrate this command into a Perl script where I would be able to choose the file name, and the receiving user followed by issuing the command?
Any guidance regarding a possible solution is highly appreciated.
there are a few ways to send command line emails in Linux: How do I send a file as an email attachment using Linux command line?
why is the -- in your command? that maybe confusing mutt.
https://unix.stackexchange.com/questions/108916/automatically-attach-a-file-to-a-mail-with-mutt has a few more suggestions for sending mail with mutt.
I prefer to use MIME::Lite to send emails, rather than spawning an external command, which avoids the problems you are having. MIME::Lite is able to handle sending emails with attachments.
Here is a quick example:
#!/usr/bin/perl
use strict;
use MIME::Lite;
my $msg = MIME::Lite->new(
To => 'foo.bar#foobar.com',
Subject => 'Test message with attachments',
Type => 'multipart/mixed'
);
$msg->attach(
Type => 'TEXT',
Data => "Here's the file you wanted"
);
$msg->attach(
Type => 'image/png',
Path => 'somefile.png',
Filename => 'somefile.png',
Disposition => 'attachment'
);
$msg->send();
This would send a message containing a small amount of text and a single attachment.
There are a lot more examples given in the POD for MIME::Lite.

X3270 Connection and Programming

I'm looking at using a X3270 terminal emulator. I have http://x3270.bgp.nu/ looked over this source material and still don't see how to start using the tool or configure it.
I'm wonder how I can open a terminal and connect. Another question is how could I integrate this into a python program?
edit:
here is a snippet:
em = Emulator()
em.connect(ip)
em.send_string('*user name*')
em.exec_command('Tab')
em.send_string('*user password*')
em.send_enter()
em.send_enter()
em.wait_for_field()
em.save_screen("{0}screenshot".format(*path*))
looking at the save screen i see that the cursor hasn't moved? I can move the cursor using
em.move_to(7,53)
but after that i don't get any text sent through. Any Ideas?
Here's what I do; it works 100% of the time:
from py3270 import *
import sys, os
host = "%s" % sys.argv[1].upper()
try:
e = Emulator()
e.connect(host)
e.wait_for_field()
except WaitError:
print "py3270.connect(%s) failed" % (host)
sys.exit(1)
print "--- connection made to %s ---" % (host)`
If you haven't got a network connection to your host, that wait_for_field() call is going to wait for a full 120 seconds. No matter what I do, I don't seem to be able to affect the length of that timeout.
But your user doesn't have to wait that long, just have him kill your script with a KeyboardInterrupt. Hopefully, your user will grow accustomed to success equaling the display of that "--- connection made ..." message so he'll know he's in trouble when/if the host doesn't respond.
And that's a point I need to make: you don't connect to a terminal (as you described), rather you connect to a host. That host can be either a VTAM connection or some kind of LPAR, usually TSO or z/VM, sometimes CICS or IMS, that VTAM will take you to. Each kind of host has differing prompts & screen content you might need to test for, and sometimes those contents are different depending on whose system you're trying to connect to. Your script becomes the "terminal", depending on what you want to show your user.
What you need to do next depends on what kind of system you're trying to talk to. Through VTAM? (Need to select a VTAM application first?) To z/VM? TSO? Are you logging on or DIALing? What's the next keystroke/field you have to use when you're working with a graphic x3270/c3270 terminal? You need to know that in order to choose your next command.
Good luck!
Please read my comment above first - it would be helpful to have more detail as to what you need to do.
After considering that…have you looked at the py3270 package at https://pypi.python.org/pypi/py3270/0.1.5 ? The summary says it talks to x3270.

Resources