Tags: excel reverse 

Rating:

# Excellent Crackme
We know one can do pretty much everything in Excel spreadsheets, but this...

[excel_crackme](VolgaCTF_excel_crackme.xlsm)

Open the excel file:
![Capture](Capture.PNG)

Unzipping the xlsm file and decompiled the vba source code using `pcode2code`:
```
pcode2code xl/vbaProject.bin -o decompile
```
Analyse the code, only **VolgaCTF function** is important for finding the flag

```vb6
Private Sub VolgaCTF()
Dim input As String
Dim solution As Long
Dim number As Long
Dim answer As Long
input = Range("L15") 'L15 is the flag input box cell
For i = 1 To Len(input) 'i will loop to 1 to length of input
solution = 0
For j = 1 To Len(input) 'j will loop to 1 to length of input
'Get the value of cell and assign into number
number = CInt(Cells(99 + i, 99 + j).Value)
'Get a character from input from index j
c = Mid(input, j, 1)
'Add the number times the ASCII value of c to solution
solution = solution + number * Asc(c)
Next j
'Get the value of cell and assign to answer
answer = CLng(Cells(99 + i, 99 + Len(input) + 1).Value)
'If answer not equal solution means wrong flag
If (answer <> solution) Then
MsgBox "Wrong Flag!"
Exit Sub
End If
Next i
'Only if all answer equal to all solution then the flag is correct
MsgBox "Congratz"
End Sub
```
After I reversing the code, immediately found a secret number table starts at (CV,100), because of `Cells(99 + i, 99 + j)` and `i` `j` starts at 1

![Screenshot](Screenshot1.png)

It is a `45*46` table, and I notice last column of the table is quite large compared to other number:

![Screenshot2](Screenshot2.png)

After more deep analysing, I found these are **Simultaneous equations!**
```
Assume abcdefgh (unknown) is the input characters
First row:
620a +340b +895c -39d +945e +321f +586g +487h... = 490493
Second row:
-19a +85b -456c +228d -127e -777f +191g +605h... = -7845
etc
```
Therefore, the flag length must be 45 (45 column)

I decide to use `z3 solver` in python to solve this:
```py
from z3 import *
n = 45
inp = [Int('inp%i' %i) for i in range(n)]
numbers = [i.strip().split(" ") for i in open("numbers.txt",'r').read().split("\n")]
solver = Solver()
solver.add(inp[0] == ord("V"))
solver.add(inp[1] == ord("o"))
solver.add(inp[2] == ord("l"))
solver.add(inp[3] == ord("g"))
solver.add(inp[4] == ord("a"))
solver.add(inp[5] == ord("C"))
solver.add(inp[6] == ord("T"))
solver.add(inp[7] == ord("F"))
solver.add(inp[8] == ord("{"))
for i in range(9,45):
solver.add(inp[i] >= 32)
solver.add(inp[i] <= 126)
solver.add(inp[44] == ord("}"))
for i in range(44):
condition = ""
for j in range(n):
condition += "("+ numbers[i][j] + "* inp[%i])+" % j
solver.add(eval(condition[:-1] + "==" + numbers[i][n]))
print(solver.check())
modl = solver.model()
print(''.join([chr(modl[inp[i]].as_long()) for i in range(n)]))
```
It took around 2 minutes to solve:
```
time python solve2.py
sat
VolgaCTF{7h3_M057_M47h_cr4ckM3_y0u_3V3R_533N}

real 1m41.494s
user 1m41.331s
sys 0m0.095s
```
## Flag
```
VolgaCTF{7h3_M057_M47h_cr4ckM3_y0u_3V3R_533N}
```

## Better Solution
After the CTF ends, I saw better solution that can solve faster:
[Unhappi writeups](https://ilovectf.github.io/jekyll/update/2020/03/29/Volga.html#excellent-crackme-150-points)
[Better solution](solve3.py)

It use matrix to solve like the picture below:
![Matrix](Matrices.png)

Original writeup (https://github.com/Hong5489/VolgaCTF2020/tree/master/excellent_crackme).