my Question is how I can convert the STDIN of cmd ARGV or gets from hex to ascii
I know that if I assigned hex string to variable it'll be converted once I print it
ex
hex_var = "\x41\41\x41\41"
puts hex_var
The result will be
AAAA
but I need to get the value from command line by (ARGV or gets)
say I've this lines
s = ARGV
puts s
# another idea
puts s[0].gsub('x' , '\x')
then I ran
ruby gett.rb \x41\x41\x41\x41
I got
\x41\x41\x41\x41
is there a way to get it work ?
There are a couple problems you're dealing with here. The first you've already tried to address, but I don't think your solution is really ideal. The backslashes you're passing in with the command line argument are being evaluated by the shell, and are never making it to the ruby script. If you're going to simply do a gsub in the script, there's no reason to even pass them in. And doing it your way means any 'x' in the arguments will get swapped out, even those that aren't being used to indicate a hex. It would be better to double escape the \ in the argument if possible. Without context of where the values are coming from, it's hard to say with way would actually be better.
ruby gett.rb \\x41\\x41
That way ARGV will actually get '\x41\x41', which is closer to what you want.
It's still not exactly what you want, though, because ARGV arguments are created without expression substitution (as though they are in single quotes). So Ruby is escaping that \ even though you don't want it to. Essentially you need to take that and re-evaluate it as though it were in double quotes.
eval('"%s"' % s)
where s is the string.
So to put it all together, you could end up with either of these:
# ruby gett.rb \x41\x41
ARGV.each do |s|
s = s.gsub('x' , '\x')
p eval('"%s"' % s)
end
# => "AA"
# ruby gett.rb \\x41\\x41
ARGV.each do |s|
p eval('"%s"' % s)
end
# => "AA"
Backlashes entered in the console will be interpreted by the shell and will
not make it into your Ruby script, unless you enter two backlashes in a row,
in which case you script will get a literal backlash and no automatic
conversion of hexadecimal character codes following those backlashes.
You can convert these escaped codes to characters manually if you replace the last line of your script with this:
puts s.gsub(/\\x([[:xdigit:]]{1,2})/) { $1.hex.chr }
Then run it with double backlashed input:
$ ruby gett.rb \\x41\\x42\\x43
ABC
When fetching user input through gets or similar, only a single backslash will be need to be entered by the user for each character escape, since that will indeed be passed to your script as literal backslashes and thus handled correctly by the above gsub call.
An alternative way when parsing command line arguments would be to let the shell interpret the character escapes for you. How to do this will depend on what shell you are using. If using bash, it can be done
like this:
$ echo $'\x41\x42\x43'
ABC
$ ruby -e 'puts ARGV' $'\x41\x42\x43'
ABC
Related
I have an AWS lambda function that receives user's code from a browser as a string and runs eval in a sandboxed environment as in a standard REPL. I am not trying to interpolate a string. I am trying to have eval recognize and perform operations on strings.
I am somewhat limited in the operations I can perform. Basic regex replacement is cool, but I don't think I would be able to do anything more involved than that, but perhaps I'm mistaken.
This works for basic arithmetic operations, the creation of class instances, etc. However, it fails to perform string operations properly. When I pass:
eval `("3*4")`
it returns 12, which is great. However, if I pass:
eval(""str:" + " test"")
it fails to return "str: test". In fact it returns nothing.
It has been suggested that I escape the double quotes. In a REPL, replacing all double quotes with escaped ones, such as \", works.
eval("\"str \" + \"test\"") # => "str test"
However, when I try this with AWS, it returns "\"str \" + \"test\"".
I look forward to hearing your responses.
You shouldn't expect eval(""str:" + " test"") to work. The problem is not related to AWS lambda. If you try this on your own machine, using pry or irb, you will get a SyntaxError. That's because your interpreter can't understand that you are only passing one unified string to eval. So you need to escape all quotation marks inside your string:
eval("\"str \" + \"test\"")
If you have tested it in a REPL without escaping, and it worked, it seems that the REPL you are using, somehow changes your input before sending it to interpreter.
I have seemed to find a work around.
To begin, I will first clarify what my issue was. Say a user entered the following:
class Test
attr_accesssor :data
def initialize(data = nil)
#data = data
end
end
Followed by
Test.new(4).data
eval would properly return 4.
Now say, however, that the user instead wrote
Test.new("A nice, fine string").data
eval would return nothing.
I noticed, however, that if I tacked on a .inspect, as shown below:
Test.new("A nice, fine string").data.inspect
I would be returned A nice, fine string.
So my solution was to wrap the entirety of the user's code in parenthesis and then call .inspect.
Which was accomplished by the following line
code = "(" << code << ").inspect"
Thank you to everyone who took the time to help me out. I really appreciate all of the feedback and suggestions.
You need to be careful about string interpolation when using eval on strings:
str = %(This is my String. It's name is string. Now I can eval "Hooray for my string")
eval(str.inspect)
#=> "This is my String. It's name is string. Now I can eval \"Hooray for my string\""
however these will raise errors
eval(str)
#=> SyntaxError: (eval):1: unterminated string meets end of file
eval(puts str) # will output the string but raise an error after it.
#=> This is my String. It's name is string. Now I can eval "Hooray for my string"
# TypeError: no implicit conversion of nil into String
but this will work
eval("puts #{str.inspect}")
#=> This is my String. It's name is string. Now I can eval "Hooray for my string"
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\"";
In the Ruby string :
"${0} ${1} ${2:hello}"
is ${i} the ith argument in the command that called this particular file.
Tried searching the web for "Ruby ${0}" however the search engines don't like non-alphanumeric characters.
Consulted a Ruby book which says #{...} will substitute the results of the code in the braces, however this does not mention ${...}, is this a special syntax to substitute argvalues into a string, thanks very much,
Joel
As mentioned above ${0} will do nothing special, $0 gives the name of the script, $1 gives the first match from a regular expression.
To interpolate a command line argument you'd normally do this:
puts "first argument = #{ARGV[0]}"
However, ARGV is also aliased as $* so you could also write
puts "first argument = #{$*[0]}"
Perhaps that's where the confusion arose?
Ok this is driving me crazy:
`ls #{"/media/music/Miles Davis"}`
fails because of the space between "Miles" and "Davis"
Say I write a ruby script and a user passes file path as an argument. How do I escape it and feed to a shell-out command. Yes, yes, I know, shelling out should be avoided. But this is a contrived example, I still need this.
I would do system("ls", ARGV[0]), but it doesn't return the stdout output of ls as a string, which is what backticks do well.
How do escape whatever you insert in a shellout?
Use require 'shellwords' and Shellwords.escape, which will fix this sort of stuff for you:
http://apidock.com/ruby/Shellwords/shellescape
Stay away from building shell strings
This is a fine vector for arbitrary code execution.
In this case, you could use popen, which does the escaping for you, e.g.:
#!/usr/bin/env ruby
IO.popen(['printf', 'a b']) do |f|
puts f.read
end
This outputs:
a b
just as if we had run on the terminal:
/usr/bin/printf 'a b'
If a b hadn't been escaped, we wouldn't get a b as expected, because running an unquoted:
/usr/bin/printf a b
in the terminal gives:
a/usr/bin/printf: warning: ignoring excess arguments, starting with ‘b’
Tested in Ubuntu 20.02, Ruby 2.6.
Double quotes also works:
`ls "#{'/media/music/Miles Davis'}"`
or
`ls "#{ARGV[0]}"`
Why does this line output "z" instead of "?"
$ ruby -e 'puts %x[ echo #{"?"} ]'
Suppose the expression inside the #{...} is a variable that may have the value of "?". How should I modify this script so that the question mark is outputted instead of "z"?
(Please forgive the title of this question -- I don't yet understand what is going on here well enough to provide a more descriptive title.)
It's not ruby, it's your shell.
Many shells expand the ? character to match a single character in command line arguments.
It's useful, if you have a bunch of files name tempA,temp1,tempB,...,temp9 that you want to delete, but you don't want to delete 'temple'
% rm temp?
So I'm guessing you have a file or directory in your working directory named 'z', and the ? matches that, so it gets replaced by the shell.
Normally, when inside single quotes (like your ruby script) it wouldn't get expanded, but since you're passing the question mark to a shell command, it gets expanded there.
% ruby -e 'puts %x[ echo ? ]'
z
%
Should show you the same behaviour.
Also, if you touch a couple other single character filenames like a b c d, those should show up too:
% touch a b c
% ruby -e 'puts %x[ echo ? ]'
a b c z
%
If you want to avoid this when calling exterior shell commands from within ruby, you'll have to escape any strings you pass out. For most purposes String#inspect should give a good enough escaping.
It doesn't?
irb(main):001:0> puts %x[echo #{"?"}]
?
=> nil
Using #{} will give you the value of any variables inside - I'm not sure why you're using it instead of
puts %x[echo "?"]
or just
puts '?'