add archiver writeup
Signed-off-by: Julien CLEMENT <julien.clement@epita.fr>
This commit is contained in:
		
							parent
							
								
									32286c8a62
								
							
						
					
					
						commit
						95852bee94
					
				
							
								
								
									
										324
									
								
								jujure/content/writeups/fcsc_2024/archiver.md
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										324
									
								
								jujure/content/writeups/fcsc_2024/archiver.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,324 @@
 | 
			
		||||
---
 | 
			
		||||
title: "Black box reversing | Archiver @ FCSC 2024"
 | 
			
		||||
date: "2024-04-13 22:00:00"
 | 
			
		||||
author: "Juju"
 | 
			
		||||
tags: ["Reverse", "Writeup", "fcsc"]
 | 
			
		||||
toc: true
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
# Intro
 | 
			
		||||
 | 
			
		||||
This writeup is not a really serious one, if you are reading this
 | 
			
		||||
as part of the FCSC writeup reviews, my submitted writeups are
 | 
			
		||||
actually for `svartalfheim` and `megalosaure`. I still thought
 | 
			
		||||
it would be funny to include this one as it is not that long and
 | 
			
		||||
I think my solution is kind of unintended.
 | 
			
		||||
 | 
			
		||||
Basically we are given a `Windows` stripped binary, compiled
 | 
			
		||||
from `rust`. The binary is an encrypted archive manager.
 | 
			
		||||
 | 
			
		||||
This challenge managed to put every single reverser red flag
 | 
			
		||||
in a single binary.
 | 
			
		||||
 | 
			
		||||
I tried opening up the binary in `binary ninja` or `IDA`, but it
 | 
			
		||||
was as expected: stripped `rust`.
 | 
			
		||||
 | 
			
		||||
So let's close this up, never touch it again and see what we can
 | 
			
		||||
do without reading the code or debugging.
 | 
			
		||||
 | 
			
		||||
{{< image src="/archiver/meme.jpg" style="border-radius: 8px;" >}}
 | 
			
		||||
 | 
			
		||||
## Challenge description
 | 
			
		||||
 | 
			
		||||
`reverse` | `490 pts` `5 solves` `:star::star:`
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
Notre équipe SIGINT a intercepté un e-mail contenant une pièce jointe
 | 
			
		||||
result.fcsc. Vu l'extension, il doit s'agir d'une archive au format
 | 
			
		||||
propriétaire FCSC. Nous avons pu récupérer l'utilitaire dans sa version
 | 
			
		||||
Windows, archiver.exe.
 | 
			
		||||
 | 
			
		||||
Vu le contenu de l'e-mail, ça a l'air assez important. Est-ce qu'on a une
 | 
			
		||||
chance de savoir ce qu'il y a dedans ?
 | 
			
		||||
 | 
			
		||||
Votre prédécesseur, après avoir réussi une analyse similaire, a sombré
 | 
			
		||||
dans la folie et réside désormais dans un asile psychiatrique. Il
 | 
			
		||||
murmurait des mots étranges comme "TTD" et parlait sans arrêt de hardware
 | 
			
		||||
breakpoint.
 | 
			
		||||
 | 
			
		||||
Note : La chaîne que vous trouverez est à mettre entre FCSC{} pour avoir
 | 
			
		||||
le flag.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Given files
 | 
			
		||||
 | 
			
		||||
[archiver.exe](/archiver/archiver.exe)
 | 
			
		||||
 | 
			
		||||
[result.fcsc](/archiver/result.fcsc)
 | 
			
		||||
 | 
			
		||||
# Writeup
 | 
			
		||||
 | 
			
		||||
## Overview
 | 
			
		||||
 | 
			
		||||
With the binary, we are also given a `result.fcsc`, which is
 | 
			
		||||
an archive encrypted with the given binary.
 | 
			
		||||
 | 
			
		||||
This archive contains the flag and we must decrypt it.
 | 
			
		||||
 | 
			
		||||
```console
 | 
			
		||||
$ xxd result.fcsc 
 | 
			
		||||
00000000: 0100 0000 0000 0000 21e2 ae0f b85f de7b  ........!...._.{
 | 
			
		||||
00000010: b246 ed90 194f 601e 041b 3c8a c6e9 37b1  .F...O`...<...7.
 | 
			
		||||
00000020: 878b d8e0 e796 a098 1800 0000 0000 0000  ................
 | 
			
		||||
00000030: d44a b96f ea76 8c55 73a0 7266 1a5e b5fd  .J.o.v.Us.rf.^..
 | 
			
		||||
00000040: c3bf cc29 8ed7 e925 1800 0000 0000 0000  ...)...%........
 | 
			
		||||
00000050: f96d be51 956d 9342 7e3d 1c0d bbef ad7a  .m.Q.m.B~=.....z
 | 
			
		||||
00000060: bc57 7bf0 f36a cb23                      .W{..j.#
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Common fields
 | 
			
		||||
 | 
			
		||||
### Sizes
 | 
			
		||||
 | 
			
		||||
First thing we can see are 3 `uint64_t` packed in little endian at offsets:
 | 
			
		||||
 | 
			
		||||
* `0x0`
 | 
			
		||||
* `0x28`
 | 
			
		||||
* `0x48`
 | 
			
		||||
 | 
			
		||||
Given how small these numbers are, they are probably representing
 | 
			
		||||
some sizes.
 | 
			
		||||
 | 
			
		||||
If we count manually, we see that the last two `uint64_t` represent the size of the data that immediatly follows them.
 | 
			
		||||
 | 
			
		||||
The first one is still unknown but as it is `1`, it probably just
 | 
			
		||||
is the number of files in the archive.
 | 
			
		||||
 | 
			
		||||
### sha256
 | 
			
		||||
 | 
			
		||||
Now let's try to create our own archive:
 | 
			
		||||
 | 
			
		||||
```console
 | 
			
		||||
$ echo -n 'FCSC{test_flag}' > flag.txt
 | 
			
		||||
$ $ ./archiver.exe create password test.db flag.txt
 | 
			
		||||
$ xxd test.db 
 | 
			
		||||
00000000: 0100 0000 0000 0000 21e2 ae0f b85f de7b  ........!...._.{
 | 
			
		||||
00000010: b246 ed90 194f 601e 041b 3c8a c6e9 37b1  .F...O`...<...7.
 | 
			
		||||
00000020: 878b d8e0 e796 a098 1800 0000 0000 0000  ................
 | 
			
		||||
00000030: 8257 3ccc 2608 498d b6b7 5801 740f 2e4e  .W<.&.I...X.t..N
 | 
			
		||||
00000040: 8b36 0169 9273 2c91 1f00 0000 0000 0000  .6.i.s,.........
 | 
			
		||||
00000050: a278 0ee8 7308 548a 84af 1ad4 6c0c 0844  .x..s.T.....l..D
 | 
			
		||||
00000060: de13 a830 ea7f 4d37 19ea 7efe 14b5 c5    ...0..M7..~....
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Two things are already weird:
 | 
			
		||||
 | 
			
		||||
* Everything is identical to the given archive until offset `0x30`
 | 
			
		||||
* This archive is larger than the given one. Either the flag is really small or data is compressed.
 | 
			
		||||
 | 
			
		||||
Let's try to archive a really low entropy file to see if the archive is smaller:
 | 
			
		||||
 | 
			
		||||
```console
 | 
			
		||||
$ echo -n 'aaaaaaaaaaaaaaa' > aaaaaaaa
 | 
			
		||||
$ ./archiver.exe create password low_entropy.db aaaaaaaa 
 | 
			
		||||
$ xxd low_entropy.db 
 | 
			
		||||
00000000: 0100 0000 0000 0000 1f3c e404 15a2 081f  .........<......
 | 
			
		||||
00000010: a3ee e75f c39f ff8e 56c2 2270 d1a9 78a7  ..._....V."p..x.
 | 
			
		||||
00000020: 249b 592d cebd 20b4 1800 0000 0000 0000  $.Y-.. .........
 | 
			
		||||
00000030: b2b6 ed4e 38bb 52b8 5cd7 12a7 7df6 261b  ...N8.R.\...}.&.
 | 
			
		||||
00000040: 2bbf f8df 77c4 dfe8 1f00 0000 0000 0000  +...w...........
 | 
			
		||||
00000050: b2b6 ed4e 38bb 52b8 8876 7671 b114 9799  ...N8.R..vvq....
 | 
			
		||||
00000060: cb38 24e6 02f9 26f9 25ec a7b8 bdb9 56    .8$...&.%.....V
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
I put exactly the same sizes in the file name and size data.
 | 
			
		||||
 | 
			
		||||
The resulting archive is exactly the same size so no compression
 | 
			
		||||
is performed.
 | 
			
		||||
 | 
			
		||||
But wait ! Something changed !
 | 
			
		||||
 | 
			
		||||
In our first archive, the firsts `0x30` bytes where identical
 | 
			
		||||
but now they differ starting at `0x8`, they differ for `0x20` bytes
 | 
			
		||||
before becoming the same again on the field we identified as a size.
 | 
			
		||||
 | 
			
		||||
Well, we changed two things: the filename and the file data.
 | 
			
		||||
 | 
			
		||||
It is unlikely that we guessed the file data on our first try.
 | 
			
		||||
 | 
			
		||||
But the filename however ? What if the the format stores a hash
 | 
			
		||||
of the filename on `0x20` bytes at offset `0x8` ?
 | 
			
		||||
 | 
			
		||||
```console
 | 
			
		||||
$ echo -n 'flag.txt' | sha256sum 
 | 
			
		||||
21e2ae0fb85fde7bb246ed90194f601e041b3c8ac6e937b1878bd8e0e796a098  -
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Bingo ! It matches the bytes we have in our first custom archive
 | 
			
		||||
and the one given.
 | 
			
		||||
 | 
			
		||||
So we know that the filename is `flag.txt` and that the archives
 | 
			
		||||
stores the `sha256` of the filename at offset `0x8`.
 | 
			
		||||
 | 
			
		||||
### Cipher texts
 | 
			
		||||
 | 
			
		||||
I wil now try to play with data sizes to identify what are the sizes in the binary refering to.
 | 
			
		||||
 | 
			
		||||
Let's create an archive with a filename 1 byte smaller, and data 1 byte larger:
 | 
			
		||||
 | 
			
		||||
```console
 | 
			
		||||
$ echo -n 'aaaaaaaaaaaaaaaa' > aaaaaaa
 | 
			
		||||
$ ./archiver.exe create password sizes.db aaaaaaa
 | 
			
		||||
$ xxd sizes.db 
 | 
			
		||||
00000000: 0100 0000 0000 0000 e462 4071 4b5d b3a2  .........b@qK]..
 | 
			
		||||
00000010: 3eee 6047 9a62 3efb a4d6 33d2 7fe4 f03c  >.`G.b>...3....<
 | 
			
		||||
00000020: 904b 9e21 9a7f be60 1700 0000 0000 0000  .K.!...`........
 | 
			
		||||
00000030: 8ab9 acd8 126c cc48 064e 9843 2fa1 9492  .....l.H.N.C/...
 | 
			
		||||
00000040: 8503 ce34 399c 9820 0000 0000 0000 008a  ...49.. ........
 | 
			
		||||
00000050: b9ac d812 6ccc f370 a362 da68 de94 c7d2  ....l..p.b.h....
 | 
			
		||||
00000060: aa91 eb29 2be2 0aa3 a74f fd99 4dc0 ca    ...)+....O..M..
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Notice that the first `uint64_t` went from `0x18` to `0x17` and
 | 
			
		||||
the second one from `0x1f` to `0x20`
 | 
			
		||||
 | 
			
		||||
Thus the first size and data correspond to the encrypted file name, and the second one to the encrypted data.
 | 
			
		||||
 | 
			
		||||
We can also see that encrypted data is always exactly `0x10` bytes
 | 
			
		||||
larger that the plaintext. So it probably just adds a `0x10` bytes IV in front of it.
 | 
			
		||||
 | 
			
		||||
Looking back at the original archive, we can thus see that the
 | 
			
		||||
the filename is `0x8` bytes large (which matches the `flag.txt`
 | 
			
		||||
we found) and the data is also `0x8` bytes large, thus confirming
 | 
			
		||||
the really small flag. (see below for a reminder of the original
 | 
			
		||||
archive)
 | 
			
		||||
 | 
			
		||||
```console
 | 
			
		||||
$ xxd result.fcsc 
 | 
			
		||||
00000000: 0100 0000 0000 0000 21e2 ae0f b85f de7b  ........!...._.{
 | 
			
		||||
00000010: b246 ed90 194f 601e 041b 3c8a c6e9 37b1  .F...O`...<...7.
 | 
			
		||||
00000020: 878b d8e0 e796 a098 1800 0000 0000 0000  ................
 | 
			
		||||
00000030: d44a b96f ea76 8c55 73a0 7266 1a5e b5fd  .J.o.v.Us.rf.^..
 | 
			
		||||
00000040: c3bf cc29 8ed7 e925 1800 0000 0000 0000  ...)...%........
 | 
			
		||||
00000050: f96d be51 956d 9342 7e3d 1c0d bbef ad7a  .m.Q.m.B~=.....z
 | 
			
		||||
00000060: bc57 7bf0 f36a cb23                      .W{..j.#
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Figuring out the crypto
 | 
			
		||||
 | 
			
		||||
Now I will try to get a file as close as possible as the original
 | 
			
		||||
flag and see how the resulting archive behaves to small
 | 
			
		||||
input mutations:
 | 
			
		||||
 | 
			
		||||
```console
 | 
			
		||||
$ echo -n '12345678' > flag.txt
 | 
			
		||||
$ ./archiver.exe create password 12345678.db flag.txt 
 | 
			
		||||
$ echo -n '22345678' > flag.txt
 | 
			
		||||
$ ./archiver.exe create password 22345678.db flag.txt 
 | 
			
		||||
$ xxd 12345678.db 
 | 
			
		||||
00000000: 0100 0000 0000 0000 21e2 ae0f b85f de7b  ........!...._.{
 | 
			
		||||
00000010: b246 ed90 194f 601e 041b 3c8a c6e9 37b1  .F...O`...<...7.
 | 
			
		||||
00000020: 878b d8e0 e796 a098 1800 0000 0000 0000  ................
 | 
			
		||||
00000030: 8257 3ccc 2608 498d b6b7 5801 740f 2e4e  .W<.&.I...X.t..N
 | 
			
		||||
00000040: 8b36 0169 9273 2c91 1800 0000 0000 0000  .6.i.s,.........
 | 
			
		||||
00000050: d509 6e9f 3d4a 06c1 9daa bebe f6cb c23b  ..n.=J.........;
 | 
			
		||||
00000060: cf4e 3d32 2b68 09cf                      .N=2+h..
 | 
			
		||||
$ xxd 22345678.db 
 | 
			
		||||
00000000: 0100 0000 0000 0000 21e2 ae0f b85f de7b  ........!...._.{
 | 
			
		||||
00000010: b246 ed90 194f 601e 041b 3c8a c6e9 37b1  .F...O`...<...7.
 | 
			
		||||
00000020: 878b d8e0 e796 a098 1800 0000 0000 0000  ................
 | 
			
		||||
00000030: 8257 3ccc 2608 498d b6b7 5801 740f 2e4e  .W<.&.I...X.t..N
 | 
			
		||||
00000040: 8b36 0169 9273 2c91 1800 0000 0000 0000  .6.i.s,.........
 | 
			
		||||
00000050: d609 6e9f 3d4a 06c1 cc6e be60 dd5d 8214  ..n.=J...n.`.]..
 | 
			
		||||
00000060: 05bb cadc 0bf1 e4b8                      ........
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Most part of the two archives are identical, as expected.
 | 
			
		||||
 | 
			
		||||
But maybe a little bit too much identical:
 | 
			
		||||
 | 
			
		||||
Look at the IV of the file data's cipher text (offset `0x50`)
 | 
			
		||||
 | 
			
		||||
The first 8 bytes are almost identical, only the first one
 | 
			
		||||
has been increased by one.
 | 
			
		||||
 | 
			
		||||
Could it be that the IV is generated with the clear text data ?
 | 
			
		||||
 | 
			
		||||
Let's try with an other data:
 | 
			
		||||
 | 
			
		||||
```console
 | 
			
		||||
$ echo -n '32345678' > flag.txt
 | 
			
		||||
$ ./archiver.exe create password 32345678.db flag.txt 
 | 
			
		||||
$ xxd 32345678.db 
 | 
			
		||||
00000000: 0100 0000 0000 0000 21e2 ae0f b85f de7b  ........!...._.{
 | 
			
		||||
00000010: b246 ed90 194f 601e 041b 3c8a c6e9 37b1  .F...O`...<...7.
 | 
			
		||||
00000020: 878b d8e0 e796 a098 1800 0000 0000 0000  ................
 | 
			
		||||
00000030: 8257 3ccc 2608 498d b6b7 5801 740f 2e4e  .W<.&.I...X.t..N
 | 
			
		||||
00000040: 8b36 0169 9273 2c91 1800 0000 0000 0000  .6.i.s,.........
 | 
			
		||||
00000050: d709 6e9f 3d4a 06c1 fcd2 be2a c42f bdf1  ..n.=J.....*./..
 | 
			
		||||
00000060: 43e8 9879 eb86 bf95                      C..y....
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Again, patching slightly the `n`th byte of the clear text only
 | 
			
		||||
patched slightly the `n`th byte of the IV.
 | 
			
		||||
 | 
			
		||||
I played with some values and noticed that the operation performed
 | 
			
		||||
is actually a xor:
 | 
			
		||||
 | 
			
		||||
```console
 | 
			
		||||
>>> 0xd7 ^ ord('3')
 | 
			
		||||
228
 | 
			
		||||
>>> 0xd6 ^ ord('2')
 | 
			
		||||
228
 | 
			
		||||
>>> 0xd5 ^ ord('1')
 | 
			
		||||
228
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
So the clear text is xored with a key to generate the IV,
 | 
			
		||||
but I do not know the said key, which seems to be derived
 | 
			
		||||
from the archive password.
 | 
			
		||||
 | 
			
		||||
## Known plaintext
 | 
			
		||||
 | 
			
		||||
Or do I ?
 | 
			
		||||
 | 
			
		||||
Remember that I know that filename is `flag.txt`, and that I have
 | 
			
		||||
an associated ciphertext.
 | 
			
		||||
 | 
			
		||||
With a little bit of luck, the IV of the filename cipher text
 | 
			
		||||
is generated with the key:
 | 
			
		||||
 | 
			
		||||
```console
 | 
			
		||||
>>> 0x82 ^ ord('f')
 | 
			
		||||
228
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Looks like it does.
 | 
			
		||||
 | 
			
		||||
Since I have a known plaintext, example cipher text.
 | 
			
		||||
 | 
			
		||||
I can simply, xor the plaintext with the filename IV to recover
 | 
			
		||||
the xor key.
 | 
			
		||||
 | 
			
		||||
Then apply the same key to the file data IV to recover the
 | 
			
		||||
plain text:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
```python
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
from pwn import *
 | 
			
		||||
filename = b'flag.txt'
 | 
			
		||||
IV = b'\xd4\x4a\xb9\x6f\xea\x76\x8c\x55'
 | 
			
		||||
c = b'\xf9\x6d\xbe\x51\x95\x6d\x93\x42'
 | 
			
		||||
key = xor(IV, filename)
 | 
			
		||||
flag = xor(c, key)
 | 
			
		||||
print('FCSC{' + flag.decode() + '}')
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```console
 | 
			
		||||
$ ./solve.py 
 | 
			
		||||
FCSC{KKfYQogc}
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								jujure/static/archiver/archiver.exe
									
									
									
									
									
										Executable file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										
											BIN
										
									
								
								jujure/static/archiver/archiver.exe
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								jujure/static/archiver/result.fcsc
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										
											BIN
										
									
								
								jujure/static/archiver/result.fcsc
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
		Loading…
	
		Reference in New Issue
	
	Block a user