Skip to content

Instantly share code, notes, and snippets.

@JackMc
Last active May 28, 2023 15:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JackMc/e92d37247fe91aaac6e16dbc61577896 to your computer and use it in GitHub Desktop.
Save JackMc/e92d37247fe91aaac6e16dbc61577896 to your computer and use it in GitHub Desktop.
The Great Processor: NorthSec 2023 CTF Challenge by @Becojo
require 'rexml'
require 'json'
$stdout.sync = true
class State < Struct.new(:cells, :selection)
def initialize
state = REXML::Functions.json_parse(File.read("state.json"))
@cells = state[:@cells].map do |key, value|
[REXML::Functions.json_parse(key.to_s), value]
end.to_h
end
def to_xml
cells = @cells.map do |(col, row), value|
" <cell col=\"#{col.to_i}\" row=\"#{row.to_i}\">#{value.to_i}</cell>"
end
"<cells>\n#{cells.join("\n")}\n</cells>"
end
def query(query)
doc = REXML::Document.new(to_xml)
REXML::XPath.match(doc, query)
end
def clear(nodes)
return if nodes.nil?
nodes.each do |node|
node.text = ""
end
end
def set(value, nodes)
return if nodes.nil?
nodes.each do |node|
node.text = value.to_i
end
end
def render(cells = @cells)
keys = cells.keys
minx, maxx = keys.map(&:first).minmax
miny, maxy = keys.map(&:last).minmax
cell_width = cells.values.map { _1.to_s.size }.max + 1
[].tap do |output|
output << ("+-" + "-" * cell_width) * maxx + "+\n"
(miny..maxy).each do |y|
(minx..maxx).each do |x|
cell = cells[[x, y]].to_s.ljust(cell_width)
output << "| #{cell}"
end
output << "|\n"
output << ("+-" + "-" * cell_width) * maxx
output << "+\n"
end
end.join
end
end
module REXML::Functions
def self.export_xml
STATE.to_xml
end
def self.import_xml(*_)
# importing xml is dangerous. we'll do it later.
"todo: import_xml"
end
def self.json_parse(value)
# at least json is safe to parse
JSON.parse(value, symbolize_names: true)
end
def self.json_get(json, key)
key = string(key)
json[key] or json[key.to_sym]
end
def self.json_key(json, value)
json.key(value)
end
def self.select(x1, y1, x2, y2)
filters = [
"@col >= #{y1.to_i}",
"@col <= #{y2.to_i}",
"@row >= #{x1.to_i}",
"@row <= #{x2.to_i}"
]
STATE.query("//cell[#{filters.join(' and ')}]")
end
def self.clear(nodes = nil)
STATE.clear(nodes)
end
def self.set(value, nodes = nil)
STATE.set(value, nodes)
end
def self.render
STATE.render
end
def self.source
@source ||= File.read(__FILE__).split("__#{'END'}__").first
end
def self.help
@help ||= DATA.read
end
end
STATE = State.new
puts "XSpreadsheet 23.129-3348.1"
puts "Type help() for help."
puts
loop do
print "> "
begin
query = gets
exit if query.nil?
rescue Interrupt
exit
end
begin
puts STATE.query(query)
rescue Exception => e
warn(e)
puts "error"
end
puts
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment