Ruby system arguments - ruby

I'm trying to use system to run nmap from a ruby program. I want to escape some of the arguments to prevent shell injection so I'm using the following form:
system('nmap', '-sn', hostname)
This works fine, however I want to use the -oX - option to output xml to stdout. The following code doesn't seem to work though:
system('nmap', '-sn', '-oX -', hostname)
The -oX - argument seems to be ignored, can anyone suggest a workaround?

As system also escapes spaces in arguments, your system call with -oX - will effectively be called as
nmap "-sn" "-oX -" "example.com"
with the space being part of a single argument. It will thus not be considered a valid argument for nmap. To fix this, you actually have to pass it as two arguments. Here, the space in the single argument will not be escaped:
system('nmap', '-sn', '-oX', '-', hostname)

Related

Saltstack cloud.map with Bash variables

I'm trying to provision a Windows virtual machine in VMWare using Salt Cloud wrapped in a bash script so that I can parameterise it but I'm having a problem with the escaping of the map_data.
my command is:
#!/bin/bash
salt salt-cloud cloud.map_run map_data='{"PROFILE":[{"HOSTNAME":{"folder":"FOLDER","devices":{"network":{"Network adapter 1":{"ip":"MYIP"}}}}}]}'
This works fine however I would like HOSTNAME, FOLDER and MYIP to be variables ($hostname $folder and $ip) and I'm struggling a bit with the escaping so that the variables are expanded and passed correctly to salt.
I have tried putting the variable inline in the command:
salt salt-cloud cloud.map_run map_data='{"PROFILE":[{"$hostname":{"folder":"$folder,"devices":{"network":{"Network adapter 1":{"ip":"$ip"}}}}}]}'
This gets as far as copying the template in the profile before bombing out with a vmware error about the variblised elements being incorrect
I have also tried to encapsulate the whole map data in a variable, escaping the double quotes and passing that, e.g,
data="'{\"PROFILE\":[{\"$hostname\":{\"folder\":\"$folder\",\"devices\":{\"network\":{\"Network adapter 1\":{\"ip\":\"$ip\"}}}}}]}'"
This appears to expand correctly if I echo it out but when I add it to my command:
salt salt-cloud cloud.map_run map_data=$data
I get the following error:
Passed invalid arguments to cloud.map_run: map_run() takes at most 1 argument (10 given)
I know that this is probably not strictly Salt's problem but I wondered if anyone out there could give me some pointers on how to proceed?
Did you try the concatenation of strings like that :
salt salt-cloud cloud.map_run map_data='{"PROFILE":[{"'$hostname'":{"folder":"'$folder',"devices":{"network":{"Network adapter 1":{"ip":"'$ip'"}}}}}]}'
I don't use the cloud app myself, so I can't test it but looking at the first command you give:
salt salt-cloud cloud.map_run map_data='{"PROFILE":[{"$hostname":{"folder":"$folder,"devices":{"network":{"Network adapter 1":{"ip":"$ip"}}}}}]}'
Because the variables are in single quotes, they won't expand. So that won't work.
The second command you gave:
data="'{\"PROFILE\":[{\"$hostname\":{\"folder\":\"$folder\",\"devices\":{\"network\":{\"Network adapter 1\":{\"ip\":\"$ip\"}}}}}]}'"
Looks correct, it will expand the variables, but compared to the first command it will also add single quotes to the string (I think you forgot to remove those?).
Also in your first command a " seems to be missing after $folder.
Fixing those mistakes gives me the command:
salt salt-cloud cloud.map_run map_data="{\"PROFILE\":[{\"$hostname\":{\"folder\":\"$folder\",\"devices\":{\"network\":{\"Network adapter 1\":{\"ip\":\"$ip\"}}}}}]}"
which I think would work. If you put an echo in front of your command, and just copy your json, you can copy/paste it into a json formatter like https://jsonformatter.curiousconcept.com/ and it will tell you if the json you used is correct. This will help you find things like missing quotes.

Bash variable character replacement ends up to an empty string or a command not valid

I am working on a shell script to retrieve variable content from a JSON file via JQ. The JSON file is in string format (no matter whether this is a real string or a number) and to retrieve the variable in my bash script I did something like this
my_domain=$(cat /vagrant/data_bags/config.json | jq ."app"[0]."domain")
The above code once echoed results in "mydomain" with a beginning and a trailing quote sign. I though this was a normal behaviour of the echo command. However, while concatenating my variable with another shell command the system raise an error. For instance, the following command
cp /vagrant/public_html/index.php "/var/www/"+$my_domain+"/index.php"
fails with the following error
cp: cannot create regular file `/var/www/+"mydomain"+/index.php': No such file or directory
At this stage, I wasn't able to identify whether it's me doing the wrong concatenation with the plus sign or the variable is effectively including the quotes that in any case will end up generating an error.
I have tried to replace the quotes in my variable, but I ended up getting the system raising a "Command not found" error.
Can somebody suggest what am I doing wrong?
+ is not used for string concatenation in bash (or perl, or php). Just:
cp /vagrant/public_html/index.php "/var/www/$my_domain/index.php"
Embedding a variable inside a double-quoted text string is known as interpolation, and is one of the reasons why we need the $ prefix, to indicate that this is a variable. Interpolation is specifically not done inside single quoted strings.
Braces ${my_domain} are not required because the / directory separators are not valid characters in a variable name, so there is no ambiguity.
For example:
var='thing'
echo "Give me your ${var}s" # Correct, appends an 's' after 'thing'
echo "Give me your $vars" # incorrect, looks for a variable called vars.
If a variable (like 'vars') does not exist then (by default) it will not complain, it will just give an empty string. Braces (graph brackets) are required more in c-shell (csh or tcsh) because of additional syntax for modifying variables, which involves special trailing characters.
You don't need to use + to concatenate string in bash, change your command to
cp /vagrant/public_html/index.php "/var/www/"${my_domain}"/index.php"
My problem was not related only to the wrong concatenation, but also to the JQ library that after parsing the value from the JSon file was returning text between quotes.
In order to avoid JQ doing this, just add the -rawoutput parameter when calling JQ.

Some symbols don't effect cmd commands while others do

I noticed that cmd seems to accept some characters at the ends of commands. for example all of the following function correctly:
cls.
cls;
cls(
cls\
cls+
cls=
cls\"whatever"
cls\$
cls\#
and these do not:
cls'
cls$
cls)
cls-
cls#
cls\/
Does anybody know why this happens?
Thanks in advance.
It depends on the batch parser.
;,= are general batch delimiters, so you can append/prepend them to the most commands without effect.
;,,= ,=; echo hello
;,cls,;,,
The . dot can be appended to the most commands, as the parser will try to find a file named cls (without extension) cls.exe cls.bat, and when nothing is found then it takes the internal command.
The opening bracket is also a special charcter that the parser removes without error.
The \ backslash is used as path delimiter, so sometimes it works but sometimes you could change even the command.
cls\..\..\..\windows\system32\calc.exe

How can I scp a file with a colon in the file name?

I'm trying to copy a file using scp in bash with a colon (:) character in the source filename. The obfuscated version of my command I'm using is:
scp file\:\ name.mp4 user#host:"/path/to/dest"
I get this error:
ssh: Could not resolve hostname Portal 2: Name or service not known
I know I could just rename the file and remove the :, but I'd like to know if it's possible to escape the colon.
Not quite a bash escaping problem, it's scp treating x: as a [user#]host prefix, try:
scp ./file:\ name.mp4 user#host:"/path/to/dest"
Using relative (e.g. ./) or fully qualified paths (/path/to/source) prevents this behaviour - the presence of / before a : causes OpenSSH to stop checking for a possible host: or user#host: prefix).
OpenSSH's scp only special-cases filenames that start with a colon allowing those to work without problems, it has no support for escaping a : in the normal sense, and has no other notion of valid hostnames so almost any filename with a : can cause this (or equivalent IPv6 behaviour if [ ] are found before :).
This can also affect other programs, e.g. rsync, the same workaround applies there.
(Due to OpenSSH's simplistic parsing of [] enclosed IPv6 addresses, you can successfully scp files containing : which start with [, or contain #[ before the : and do not contain ]: , but that's not generally useful ;-)
(The below text was written when the original question was How do I escape a colon in bash? It applies to that situation, but not to scp as no amount of shell escaping will help there.)
To answer the question about how to escape :, you don't need to, but "\:" works. Places that a : is used:
the null command :, no need to escape, though you can, just like \e\c\h\o foo it has no effect on the command ("no effect" is not completely true, if you escape one or more characters it will prevent an alias being matched, and you can alias :)
PATH (and others, CDPATH, MAILPATH) escaping the values has no useful effect (I have been unable to run a program in my PATH from a directory containing a :, which is a little unexpected)
parameter expansion ${name:-x} and more, name must be [a-zA-Z_][a-zA-Z0-9_], so no need to escape variables names, and since there's no ambiguity, no need to escape subsequent : in the other variations of parameter expansion
? : trinary operates only on variables and numbers, no need to escape
== and =~ with classes in the pattern like [[:digit:]], you can escape with \: but I'm at a loss as to how that might ever be useful...
within command or function names, no need to escape, \: has no useful effect
(Note that the null command is just :, you can have a command or function named like ":foo" and it can be invoked without escaping, in this respect it's different to # where a command named #foo would need to be escaped.)
I try using fully qualified paths as #mr.spuratic answer but not work and in my situation, I have to use absolute paths, this is my solution:
scp `hostname`:/root/this/is/test/file.txt user#host:"/path/to/dest"

How can I run a unix command without using a space character so that I can execute a remote command?

I've been learning about remote/arbitrary command execution. In doing so, I came across some Ruby I thought would be fun to try and exploit.
I've been somewhat successful as I managed to get it to run the 'ls' command, but I can't work out how to add space characters into my commands. If I add a space in, the parse method that URI calls throws an exception.
Here's the code I was trying to exploit:
injection = "www.google.com';ls;#"
require 'uri'
URI.parse(injection)
puts `curl '#{injection}'`
So your challenge, should you choose to accept it, is to run an 'ls -l' command instead of 'ls' by only changing the injection string. You may not change anything but the first line.
Things I've tried:
ls%2f-l - # Doesn't raise an exception but unix doesn't unescape CGI encodings.
ls\x20-l - # Raises an exception because Ruby parses the UTF-8.
# Other various escape combinations (\\x20, etc)
Maybe it's not possible?
Thanks
You can use the Internal Field Separator (<space><tab><newline>). Since this is what the shell separates with anyway, it will accept it as a separator.
injection = "www.google.com';ls$IFS-l;#"
(BTW, thanks for a nice Saturday night puzzle.)
Is - it's possible. Just put your string in quotes:
1) from a command prompt:
two strings # No quote: the shell sees two strings
"one string" # with single (') or double quotes (") the shell sees only one string
2) from a string literal
mystring = "\"this will be interpreted as one string\"";

Resources