FCSC 2020 - infiltrate (reverse)
Reverse - infiltrate
The following quote was given as mission
Des agents ont réussi à exfiltrer un fichier en utilisant la LED du disque dur durant une copie de disque. Ils nous ont fourni l’image de la capture
And the file started with the following picture.
Extracting the hidden file
Quickly looking at the pixel just by zooming on the picture I only saw black and white pixel. No gray ones, meaning that there was only two values (255, 255, 255
for white and (0, 0, 0)
for black.
We can quickly check it out with the python lib PIL
This will output : {(0, 0, 0), (255, 255, 255)}
, confirming they are only two possible values.
Knowing this we can assume that (0, 0, 0)
is a binary 0
value and (255, 255, 255
if a 1
. We can script something to retrieve the whole data.
from struct import pack
from PIL import Image
str_data = ""
bytes_data = b""
# fetching all 0 and 1
for pix in list(Image.open("./infiltrate.png", "r").getdata()):
if pix == (0,0,0):
str_data += "0"
else:
str_data += "1"
# splitting bits in bytes
for x in [str_data[i:i+8] for i in range(0, len(str_data), 8)]:
bytes_data += pack("B", int(x, 2))
open("out", "wb").write(bytes_data)
We now have another file, we can check which kind of file this is.
λ ackira ~/nextcloud/CTF/FCSC2020/reverse/infiltrate » file out
out: data
λ ackira ~/nextcloud/CTF/FCSC2020/reverse/infiltrate » binwalk out
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
16 0x10 ELF, 64-bit LSB shared object, AMD x86-64, version 1 (SYSV)
1249 0x4E1 Ubiquiti firmware header, third party, ~CRC32: 0x0, version: "SSL_1.0.0"
An ELF
file is inside the out
file starting from the 16th
bytes, we can extract it with dd
dd if=out of=elf bs=1 skip=16
And then check it dependencies
linux-vdso.so.1 (0x00007ffd87365000)
libcrypto.so.1.0.0 => /usr/lib/libcrypto.so.1.0.0 (0x00007f51c3c29000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f51c3a63000)
libdl.so.2 => /usr/lib/libdl.so.2 (0x00007f51c3a5e000)
/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007f51c40cf000)
libcrypto.so.1.0.0
please no :(
We can also check it symbols and start it to see how it behave
λ ackira ~/nextcloud/CTF/FCSC2020/reverse/infiltrate » nm elf | grep T
000000000000089a T doit
0000000000000ae4 T _fini
0000000000200f88 d _GLOBAL_OFFSET_TABLE_
00000000000006e8 T _init
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
0000000000000ae0 T __libc_csu_fini
0000000000000a70 T __libc_csu_init
00000000000009f5 T main
0000000000000790 T _start
0000000000201010 D __TMC_END__
λ ackira ~/nextcloud/CTF/FCSC2020/reverse/infiltrate » ./elf
Hello! Entrez la clé
help
Mauvaise clé !
It’s seems to have only two functions main
as usual and doit
. It want a key and we have to find it.
Let’s run ltrace to see which functions it uses from the libcrypto
λ ackira ~/nextcloud/CTF/FCSC2020/reverse/infiltrate » ltrace ./elf
puts("Hello! Entrez la cl\303\251 "Hello! Entrez la clé
) = 23
fgets(hello
"hello\n", 7, 0x7f88471587e0) = 0x7ffe7e1fcc80
strlen("hello\n") = 6
SHA1(0x7ffe7e1fcc80, 6, 0x7ffe7e1fcc50, 6) = 0x7ffe7e1fcc50
puts("Mauvaise cl\303\251 !"Mauvaise clé !
) = 16
putchar(10, 0x55b30abb02a0, 0, 0x7f8847089567
) = 10
+++ exited (status 0) +++
The SHA1
function is called, certainly with our input. Lets disassemble the doit
function and check how the comparison is done.
Nothing is done in main after reading the disassembly of this function
000000000000089a <doit>:
89a: 55 push rbp
89b: 48 89 e5 mov rbp,rsp
89e: 48 83 ec 40 sub rsp,0x40
8a2: 48 89 7d c8 mov QWORD PTR [rbp-0x38],rdi
8a6: 64 48 8b 04 25 28 00 mov rax,QWORD PTR fs:0x28
8ad: 00 00
8af: 48 89 45 f8 mov QWORD PTR [rbp-0x8],rax
8b3: 31 c0 xor eax,eax
8b5: 48 8b 45 c8 mov rax,QWORD PTR [rbp-0x38]
8b9: 48 89 c7 mov rdi,rax
8bc: e8 8f fe ff ff call 750 <strlen@plt>
8c1: 48 89 c1 mov rcx,rax
8c4: 48 8d 55 e0 lea rdx,[rbp-0x20]
8c8: 48 8b 45 c8 mov rax,QWORD PTR [rbp-0x38]
8cc: 48 89 ce mov rsi,rcx
8cf: 48 89 c7 mov rdi,rax
8d2: e8 89 fe ff ff call 760 <SHA1@plt>
8d7: c7 45 dc 00 00 00 00 mov DWORD PTR [rbp-0x24],0x0
8de: c7 45 d8 00 00 00 00 mov DWORD PTR [rbp-0x28],0x0
8e5: e9 be 00 00 00 jmp 9a8 <doit+0x10e>
8ea: 0f b6 45 e0 movzx eax,BYTE PTR [rbp-0x20]
8ee: 3c 58 cmp al,0x58
8f0: 0f 85 aa 00 00 00 jne 9a0 <doit+0x106>
8f6: 0f b6 45 e1 movzx eax,BYTE PTR [rbp-0x1f]
8fa: 3c 23 cmp al,0x23
8fc: 0f 85 9e 00 00 00 jne 9a0 <doit+0x106>
902: 0f b6 45 ea movzx eax,BYTE PTR [rbp-0x16]
906: 3c a3 cmp al,0xa3
908: 0f 85 92 00 00 00 jne 9a0 <doit+0x106>
90e: 0f b6 45 e2 movzx eax,BYTE PTR [rbp-0x1e]
912: 3c db cmp al,0xdb
914: 0f 85 86 00 00 00 jne 9a0 <doit+0x106>
91a: 0f b6 45 e3 movzx eax,BYTE PTR [rbp-0x1d]
91e: 3c 97 cmp al,0x97
920: 75 7e jne 9a0 <doit+0x106>
922: 0f b6 45 e6 movzx eax,BYTE PTR [rbp-0x1a]
926: 3c c4 cmp al,0xc4
928: 75 76 jne 9a0 <doit+0x106>
92a: 0f b6 45 e4 movzx eax,BYTE PTR [rbp-0x1c]
92e: 3c 68 cmp al,0x68
930: 75 6e jne 9a0 <doit+0x106>
932: 0f b6 45 e5 movzx eax,BYTE PTR [rbp-0x1b]
936: 3c 01 cmp al,0x1
938: 75 66 jne 9a0 <doit+0x106>
93a: 0f b6 45 f2 movzx eax,BYTE PTR [rbp-0xe]
93e: 3c 26 cmp al,0x26
940: 75 5e jne 9a0 <doit+0x106>
942: 0f b6 45 e7 movzx eax,BYTE PTR [rbp-0x19]
946: 3c a0 cmp al,0xa0
948: 75 56 jne 9a0 <doit+0x106>
94a: 0f b6 45 e8 movzx eax,BYTE PTR [rbp-0x18]
94e: 3c e2 cmp al,0xe2
950: 75 4e jne 9a0 <doit+0x106>
952: 0f b6 45 e9 movzx eax,BYTE PTR [rbp-0x17]
956: 3c d7 cmp al,0xd7
958: 75 46 jne 9a0 <doit+0x106>
95a: 0f b6 45 f3 movzx eax,BYTE PTR [rbp-0xd]
95e: 3c 12 cmp al,0x12
960: 75 3e jne 9a0 <doit+0x106>
962: 0f b6 45 eb movzx eax,BYTE PTR [rbp-0x15]
966: 3c 30 cmp al,0x30
968: 75 36 jne 9a0 <doit+0x106>
96a: 0f b6 45 ec movzx eax,BYTE PTR [rbp-0x14]
96e: 3c b2 cmp al,0xb2
970: 75 2e jne 9a0 <doit+0x106>
972: 0f b6 45 ed movzx eax,BYTE PTR [rbp-0x13]
976: 3c bb cmp al,0xbb
978: 75 26 jne 9a0 <doit+0x106>
97a: 0f b6 45 ef movzx eax,BYTE PTR [rbp-0x11]
97e: 3c fe cmp al,0xfe
980: 75 1e jne 9a0 <doit+0x106>
982: 0f b6 45 f0 movzx eax,BYTE PTR [rbp-0x10]
986: 3c 27 cmp al,0x27
988: 75 16 jne 9a0 <doit+0x106>
98a: 0f b6 45 ee movzx eax,BYTE PTR [rbp-0x12]
98e: 3c 82 cmp al,0x82
990: 75 0e jne 9a0 <doit+0x106>
992: 0f b6 45 f1 movzx eax,BYTE PTR [rbp-0xf]
996: 3c cc cmp al,0xcc
998: 75 06 jne 9a0 <doit+0x106>
99a: 83 45 dc 01 add DWORD PTR [rbp-0x24],0x1
99e: eb 04 jmp 9a4 <doit+0x10a>
9a0: 83 6d dc 01 sub DWORD PTR [rbp-0x24],0x1
9a4: 83 45 d8 01 add DWORD PTR [rbp-0x28],0x1
9a8: 83 7d d8 13 cmp DWORD PTR [rbp-0x28],0x13
9ac: 0f 8e 38 ff ff ff jle 8ea <doit+0x50>
9b2: 83 7d dc 14 cmp DWORD PTR [rbp-0x24],0x14
9b6: 75 1a jne 9d2 <doit+0x138>
9b8: 48 8b 45 c8 mov rax,QWORD PTR [rbp-0x38]
9bc: 48 89 c6 mov rsi,rax
9bf: 48 8d 3d 2e 01 00 00 lea rdi,[rip+0x12e] # af4 <_IO_stdin_used+0x4>
9c6: b8 00 00 00 00 mov eax,0x0
9cb: e8 40 fd ff ff call 710 <printf@plt>
9d0: eb 0c jmp 9de <doit+0x144>
9d2: 48 8d 3d 38 01 00 00 lea rdi,[rip+0x138] # b11 <_IO_stdin_used+0x21>
9d9: e8 42 fd ff ff call 720 <puts@plt>
9de: 90 nop
9df: 48 8b 45 f8 mov rax,QWORD PTR [rbp-0x8]
9e3: 64 48 33 04 25 28 00 xor rax,QWORD PTR fs:0x28
9ea: 00 00
9ec: 74 05 je 9f3 <doit+0x159>
9ee: e8 7d fd ff ff call 770 <__stack_chk_fail@plt>
9f3: c9 leave
9f4: c3 ret
So after some debugging we found that our string is sha1 hashed and the result is stored at [rbp-0x20]
. Then this value is compared byte per byte to hardcoded value.
Let’s use vim
to extract these value and put it in the right order (as in the original disassembly they are not checked in the order, yes I didn’t check it and found a wrong hash aha).
8ea: 0f b6 45 e0 movzx eax,BYTE PTR [rbp-0x20]
8ee: 3c 58 cmp al,0x58
8f6: 0f b6 45 e1 movzx eax,BYTE PTR [rbp-0x1f]
8fa: 3c 23 cmp al,0x23
90e: 0f b6 45 e2 movzx eax,BYTE PTR [rbp-0x1e]
912: 3c db cmp al,0xdb
91a: 0f b6 45 e3 movzx eax,BYTE PTR [rbp-0x1d]
91e: 3c 97 cmp al,0x97
92a: 0f b6 45 e4 movzx eax,BYTE PTR [rbp-0x1c]
92e: 3c 68 cmp al,0x68
932: 0f b6 45 e5 movzx eax,BYTE PTR [rbp-0x1b]
936: 3c 01 cmp al,0x1
922: 0f b6 45 e6 movzx eax,BYTE PTR [rbp-0x1a]
926: 3c c4 cmp al,0xc4
942: 0f b6 45 e7 movzx eax,BYTE PTR [rbp-0x19]
946: 3c a0 cmp al,0xa0
94a: 0f b6 45 e8 movzx eax,BYTE PTR [rbp-0x18]
94e: 3c e2 cmp al,0xe2
952: 0f b6 45 e9 movzx eax,BYTE PTR [rbp-0x17]
956: 3c d7 cmp al,0xd7
902: 0f b6 45 ea movzx eax,BYTE PTR [rbp-0x16]
906: 3c a3 cmp al,0xa3
962: 0f b6 45 eb movzx eax,BYTE PTR [rbp-0x15]
966: 3c 30 cmp al,0x30
96a: 0f b6 45 ec movzx eax,BYTE PTR [rbp-0x14]
96e: 3c b2 cmp al,0xb2
972: 0f b6 45 ed movzx eax,BYTE PTR [rbp-0x13]
976: 3c bb cmp al,0xbb
98a: 0f b6 45 ee movzx eax,BYTE PTR [rbp-0x12]
98e: 3c 82 cmp al,0x82
97a: 0f b6 45 ef movzx eax,BYTE PTR [rbp-0x11]
97e: 3c fe cmp al,0xfe
982: 0f b6 45 f0 movzx eax,BYTE PTR [rbp-0x10]
986: 3c 27 cmp al,0x27
992: 0f b6 45 f1 movzx eax,BYTE PTR [rbp-0xf]
996: 3c cc cmp al,0xcc
93a: 0f b6 45 f2 movzx eax,BYTE PTR [rbp-0xe]
93e: 3c 26 cmp al,0x26
95a: 0f b6 45 f3 movzx eax,BYTE PTR [rbp-0xd]
95e: 3c 12 cmp al,0x12
If we extract each byte we found the following hash : 5823db976801c4a0e2d7a330b2bb82fe27cc2612
We can check if it is present in known rainbow tables online with hash-buster
( but is also present in crackstation)
$ python ~/tools/crypto/Hash-Buster/hash.py -s 5823db976801c4a0e2d7a330b2bb82fe27cc2612
_ _ ____ ____ _ _ ___ _ _ ____ ___ ____ ____
|__| |__| [__ |__| |__] | | [__ | |___ |__/
| | | | ___] | | |__] |__| ___] | |___ | \ v3.0
[!] Hash function : SHA1
401445
The flag is : FCSC{401445}