Wolfshirtz walks us through how he would solve the Summer Camp 2020 – Enumeration and Exploitation challenge: Reverse Engineering.
For the weekly challenge, a small piece of code was given in a Ruby file:
def main
key = 0x80
enc = [211, 203, 217, 173, 195, 193, 212, 173, 180, 181, 182, 185]
puts "Can I haz auth?"
auth = gets.chomp.bytes.to_a
if enc == auth.map! {|a| key ^ a} then
puts "Congrats"
else
puts "fail"
end
end
main
This is a fairly simple script that relies on some of Ruby’s functional programming features (namely higher order functions and anonymous functions, or lambdas).
I am going to explain higher order functions and lambdas in Python instead of Ruby because the concepts are the same across programming languages and the only resulting difference is syntax.
Higher order functions
Put simply, higher order functions are functions that take functions as arguments and/or return a function as the return value. This is a fairly powerful that can be used to distill a complex idea in a fairly small amount of code.
The higher order function used in the above example is map
. To understand, map lets look at an example of map being implemented in Python.
def myMap(func, iter):
#map is already a function defined in the python runtime
for i in iter:
yield func(i)
Map takes a function as an input as well as an iterable data type (think lists and dictionaries)
Lambdas
Lambdas, or anonymous functions, are a way of creating functions that will be used once. (Note: Depending on the programming language, lambdas don’t have to be single use, but most of time they are). These are useful when you need to pass a function to a higher order function, but don’t want to define a completely new function. Lambda syntax also tends to be simpler and shorter than a traditional function definition. Here is an example of passing a lambda to a higher order function in Python.
a = [1,2,3,4]
map(lambda x: x + 1, a)
Bit Math 101
There are a quite a few operations when doing math on the bit level (the 0’s and 1’s!). For the sake of simplicity we are going to look at three operations: AND, OR, and XOR.
Each of these three operations are logical operators. Logical operators can be thought of on a true or false basis. For OR, only one of the two operands has to be true (AKA 1) to satisfy the condition as true. In the AND operation, both operands have to be true to satisfy the condition as true, or else it’s considered false (AKA 0). XOR is slightly different in that it works like OR, but if both operands are the same it comes back as false. (Hint: XOR also works as a simple form of encryption!)
To play around with these operations, you can run the following Python operators against some test numbers:
>>> 1 ^ 0 #Xor
1
>>> 1 & 0 #And
0
>>> 1 or 0 #Or
1
Wrap up
Using what you have learned from this blog post, you should be able to figure out the input that makes the Ruby script write “Congrats” out to the console!
With love and root shells,