# Down The Rabbit Hole

• Category: Forensics
• 150 Points
• Solved by the JCTF Team

## Description

An Excel file was attached.

## Solution

Let's start by inspecting the Excel Workbook. If we open it with a dedicated program, we get one sheet named "Sheet1" saying "Find the hidden sheet".

We can right-click and select "Show sheet" to view hidden sheets:

Sheet2 says:

And Sheet3:

Excel files are actually just zip archives. We can extract them and look inside.

``````┌──([email protected])-[/media/…/Down_The_Rabbit_Hole/out/xl/worksheets]
└─\$ ls -al
total 37
drwxrwx--- 1 root vboxsf    0 Nov 10 23:19 .
drwxrwx--- 1 root vboxsf    0 Nov 10 23:21 ..
-rwxrwx--- 1 root vboxsf 9309 Nov 10 22:52 sheet1.xml
-rwxrwx--- 1 root vboxsf 9378 Nov 10 23:09 sheet2.xml
-rwxrwx--- 1 root vboxsf 9458 Nov 10 23:19 sheet3.xml
-rwxrwx--- 1 root vboxsf   48 Nov 10 22:41 sheet4.xml``````

Sheet4 says:

``````┌──([email protected])-[/media/…/Down_The_Rabbit_Hole/out/xl/worksheets]
└─\$ cat sheet4.xml
Now go back and find the super DUPer hidden rows``````

If we check inside the XMLs, we can see that some rows have duplicate entries, e.g.:

``````    <row r="106" spans="1:1" x14ac:dyDescent="0.25">
<c r="A106">
<v>73</v>
</c>
</row>
<row r="107" spans="1:1" x14ac:dyDescent="0.25">
<c r="A107">
<v>97</v>
</c>
</row>
<row r="108" spans="1:1" x14ac:dyDescent="0.25">
<c r="A108">
<v>65</v>
</c>
</row>
<row r="109" spans="1:1" x14ac:dyDescent="0.25">
<c r="A109">
<v>73</v>
</c>
</row>
<row r="109" spans="1:1" x14ac:dyDescent="0.25">
<c r="A109">
<v>86</v>
</c>
</row>
<row r="110" spans="1:1" x14ac:dyDescent="0.25">
<c r="A110">
<v>60</v>
</c>
</row>
<row r="111" spans="1:1" x14ac:dyDescent="0.25">
<c r="A111">
<v>108</v>
</c>
</row>``````

Row `109` is duplicate, the first value is `73` which is ASCII for `I`. We locate the duplicates to get the flag.

This can be done programmatically:

``````import xml.etree.ElementTree as ET
from pathlib import Path

namespaces = {
}

flag = ""

for sheet in Path('out/xl/worksheets/').glob('sheet*.xml'):
try:
tree = ET.parse(sheet)

dups = {}

for row in tree.findall('.//t:row', namespaces):
row_num = row.attrib["r"]
row_val = row.find("t:c/t:v", namespaces).text

if row_num in dups:
flag += chr(int(dups[row_num]))
else:
dups[row_num] = row_val
except ET.ParseError:
pass

print(flag)``````

Output:

``````┌──([email protected])-[/media/sf_CTFs/intent/Down_The_Rabbit_Hole]
└─\$ python3 solve.py
INTENT{u_f0und_w0nd3rl2nd}``````