Reversing

revmem

strace

strace is a diagnostic, debugging and instructional userspace utility for Linux. It is used to monitor and tamper with interactions between processes and the Linux kernel, which include system calls, signal deliveries, and changes of process state.

ltrace

ltrace is a library call tracer and it is primarily used to trace calls made by programs to library functions. It can also trace system calls and signals, like strace.

A first approach

Reversing challenge, meaning that we have just the binary and no remote connection needed. We just need to find the correct output that will make our binary print the flag. In this case we can start launching the binary with some random input to check its behaviour:

$  ./revmem ciao
Wrong!

Ok, now lets strace it:

$ strace ./revmem ciao
execve("./revmem", ["./revmem", "ciao"], 0x7fffffffe338 /* 39 vars */) = 0
brk(NULL)                               = 0x555555559000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=95222, ...}) = 0
mmap(NULL, 95222, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7ffff7fe0000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\35\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2030928, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ffff7fde000
mmap(NULL, 4131552, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7ffff79e2000
mprotect(0x7ffff7bc9000, 2097152, PROT_NONE) = 0
mmap(0x7ffff7dc9000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e7000) = 0x7ffff7dc9000
mmap(0x7ffff7dcf000, 15072, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7ffff7dcf000
close(3)                                = 0
arch_prctl(ARCH_SET_FS, 0x7ffff7fdf4c0) = 0
mprotect(0x7ffff7dc9000, 16384, PROT_READ) = 0
mprotect(0x555555557000, 4096, PROT_READ) = 0
mprotect(0x7ffff7ffc000, 4096, PROT_READ) = 0
munmap(0x7ffff7fe0000, 95222)           = 0
brk(NULL)                               = 0x555555559000
brk(0x55555557a000)                     = 0x55555557a000
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 5), ...}) = 0
write(1, "Wrong!\n", 7Wrong!
)                 = 7
exit_group(0)                           = ?
+++ exited with 0 +++

Not useful at all.

Actually is way easier than it looks like

Now lets try ltrace on it:

Well...

This is happening because of this line of code:

From which we can see that the program is taking the flag which is hardcoded in memory.

From this snippet of code we can see that the flag is put in memory by a malloc after being obtained by XORing the encoded version of the flag. Because of the strcmp with the flag in memory and our input we can see the flag in clear with ltrace.

revmemp

Very similar to revmem. Both strace and ltrace outputs are not very useful in this case. We can try to debug the application when the strcmp between the user input and the flag gets executed. From the disassembler:

Which corresponds to:

If we try to put a breakpoint there and to debug it:

Turns out we can't debug it with gdb:

Rip. This is a special function called INIT function, which is called before the begin of the main, which means that they are kind of hidden. Good way to find them: looking at which text output they prints, and search for it into Ghidra, or run strings on the binary

Can we stop the binary from escaping that check? Yes, we just need to patch the binary: we could, for example, replace the exit(-1) with tops to avoid this check altogether.

Still, we have another problem. The following function gets called multiple time during execution:

It basicaly checks if the first and second symbols of entry are breakpoints (0xcc). It basically avoids the user from using them.

How to patch the binary (xxd, the hard way)

We'll be using vim. First of all open the binary: vim ./revmemnp. then input the following:

this gives us hex dump of the binary. Then we need to search for the byte codes of the instruction we want to replace. To search in vim we use the forward slash command. So, we want to replace the exit in the debugger avoider function to be a bunch of nop. So we'll first search for its first opcode:

Then press enter, and keep pressing n until we find our function:

Then we can use I to enter intert mode, overwrite it with pops (note that it is made up of 5 opcodes, which means we need 5 nops), and pass :%!xdd -r and :wq to save and exit. Or you could just use a gui hex editor, it works either way.

The exploit

Basically we just need to overwrite both checks, the one which prevents us from setting a breakpoint, and the one that checks if we have gdb attached. Once the binary has been patched to remove the exit, we just start the binary with gdb, set a breakpoint in the strcmp, and then we can just see the flag in clear as argument of the strcmp:


keycheck_baby

In this challenge we have to reverse engineer a key encryption algorithm divided in two steps. We have the key which is split in two and encrypted differently using two loops.

Pt.1

This first loop XORs the key with characters from the string babuzz % 6 (modulo), which is the length of the string itself. Easy reverse, since we have the result of the XOR, which is the magic0 variable and we can just XOR the two to get past it (since the XOR is an invertible function):

Pt.2

As for the second one:

We have a CBC encryption algorithm:

Cipher block chaining (CBC) is a mode of operation for a block cipher -- one in which a sequence of bits are encrypted as a single unit, or block, with a cipher key applied to the entire block. Cipher block chaining uses what is known as an initialization vector (IV) of a certain length.

Implemented as such:

Note: in both loops the label LAB_00101487 take the instruction pointer to the end of the main, making the program exit. To reverse this we need an equation system as such:

{p0=c0βˆ’IVp1=c1βˆ’c0...pn=cnβˆ’cnβˆ’1\left\{ \begin{array}{ll} p_{0} = c_{0} - IV \\ p_{1} = c_{1} - c_{0} \\ ... \\ p_{n} = c_{n} - c_{n-1} \\ \end{array} \right.

Where $IV$ is the initialization vector. This can be implemented in python as follows:

In the code above $p_{i}$ are characters of the flag, while $c_{i}$ are characters of magic1.

crackme

Another easy reversing challenge, in this case we have a XOR cypher:

Solution:

Last updated