TyCoon is a multi-stage challenge I designed for the 2023 finals edition of the European Cyber Week. Here is the source code for this challenge.
Scenario Link to heading
Evil corp installed a malware on John’s backup server. That malware is listening for a NUKE order on UDP/9999. When received, it verifies the origin of the request using a DGA and encrypts backup files. It then deletes the symmetric key but leaves an encrypted key for later recovery. Finally, it rewrites the bootloader with a ransom note and reboots.
We are John’s friend and our task is to retrieve the secret key for backup files decryption. We have to reverse the malware (we can also restore the bootloader) in order to find the domain name used while the attack was launched. Hopefully, we find the ransomware gang panel and from there we find the key and decrypt John’s key and files in order to reveal the flag.
Writeup Link to heading
You’re given an infected.tgz
and your role is to recover encrypted files within.
Let’s take a look at the infected image:
1$ tar zxvf infected.tgz
2infected.img
3$ xxd -l 512 infected.img
400000000: fa31 c08e d88e d0bc 0020 89e5 fbe8 d900 .1....... ......
500000010: bb25 7ce8 f800 bb53 7ce8 f200 bb94 7ce8 .%|....S|.....|.
600000020: ec00 e9b8 000a 204f 6f6f 7073 2c20 796f ...... Ooops, yo
700000030: 7572 2069 6d70 6f72 7461 6e74 2066 696c ur important fil
800000040: 6573 2061 7265 2065 6e63 7279 7074 6564 es are encrypted
900000050: 210a 000a 2054 6f20 6465 6372 7970 7420 !... To decrypt
1000000060: 7365 6e64 2031 2e35 2042 5443 2074 6f20 send 1.5 BTC to
1100000070: 6d70 3979 6145 7a75 796d 344c 4548 3364 mp9yaEzuym4LEH3d
1200000080: 7278 6544 5331 7053 5172 4b69 4a7a 4a69 rxeDS1pSQrKiJzJi
1300000090: 314d 0a00 0a20 5468 656e 2065 6d61 696c 1M... Then email
14000000a0: 2075 7320 6174 2063 6f6e 7461 6374 4065 us at contact@e
15000000b0: 7669 6c63 6f72 702e 636f 6d20 7769 7468 vilcorp.com with
16000000c0: 2079 6f75 2070 6572 736f 6e61 6c20 4944 you personal ID
17000000d0: 3a20 6e47 5139 7846 3834 430a 0031 c0cd : nGQ9xF84C..1..
18000000e0: 16cd 1968 00f0 6af0 cb50 b803 00cd 1058 ...h..j..P.....X
19000000f0: c350 b40e b00d cd10 b00a cd10 58c3 60b4 .P..........X.`.
2000000100: 0e8a 073c 0074 05cd 1043 ebf5 61c3 e8ed ...<.t...C..a...
2100000110: ffe8 ddff c3ff ffff ffff ffff ffff ffff ................
2200000120: ffff ffff ffff ffff ffff ffff ffff ffff ................
2300000130: ffff ffff ffff ffff ffff ffff ffff ffff ................
2400000140: ffff ffff ffff ffff ffff ffff ffff ffff ................
2500000150: ffff ffff ffff ffff ffff ffff ffff ffff ................
2600000160: ffff ffff ffff ffff ffff ffff ffff ffff ................
2700000170: ffff ffff ffff ffff ffff ffff ffff ffff ................
2800000180: ffff ffff ffff ffff ffff ffff ffff ffff ................
2900000190: ffff ffff ffff ffff ffff ffff ffff ffff ................
30000001a0: ffff ffff ffff ffff ffff ffff ffff ffff ................
31000001b0: ffff ffff ffff ffff ffff ffff ffff ffff ................
32000001c0: ffff ffff ffff ffff ffff ffff ffff ffff ................
33000001d0: ffff ffff ffff ffff ffff ffff ffff ffff ................
34000001e0: ffff ffff ffff ffff ffff ffff ffff ffff ................
35000001f0: ffff ffff ffff ffff ffff ffff ffff 55aa ..............U.
When launching (qemu-system-x86_64 -hda infected.img
) the image, we indeed
are launching an infected machine:
The testdisk
utility can both write a standard MBR code and reconstruct the
partition table.
1$ cp infected.img bootable.img
2$ testdisk bootable.img
[find partitions and fix the partition table] [repair mbr bootloader code]
After running it, here is the code obtained that allows us to boot the system again:
$ xxd -l 512 bootable.img
00000000: fc31 c08e d031 e48e d88e c0be 007c bf00 .1...1.......|..
00000010: 06b9 0001 f3a5 beee 07b0 08ea 2006 0000 ............ ...
00000020: 803e b307 ff75 0488 16b3 0780 3c00 7404 .>...u......<.t.
00000030: 0806 af07 83ee 10d0 e873 f090 9090 9090 .........s......
00000040: 9090 9090 9090 9090 9090 9090 9090 9090 ................
00000050: 9090 9090 9090 9090 9090 9090 9090 9090 ................
00000060: 9090 9090 9090 9090 9090 9090 9090 9090 ................
00000070: 9090 9090 9090 9090 9090 9090 9090 bebe ................
00000080: 07b0 00b9 0400 803c 0075 6efe c083 c610 .......<.un.....
00000090: e2f4 31db b40e be9d 078a 0eaf 07ac d0e9 ..1.............
000000a0: 7302 cd10 08c9 75f5 b03a cd10 31c0 cd16 s.....u..:..1...
000000b0: 3c00 74f8 be8b 07b9 0200 e8ba 003c 0d74 <.t..........<.t
000000c0: b43c 6172 063c 7a77 022c 2088 c3be 9d07 .<ar.<zw., .....
000000d0: 8a0e af07 acd0 e973 0438 c374 0608 c975 .......s.8.t...u
000000e0: f3eb afb8 0d0e 31db cd10 8d84 6200 3c07 ......1.....b.<.
000000f0: 7507 b01f a2af 07eb 9931 d2b9 0100 3c04 u........1....<.
00000100: 7411 73f3 30e4 b104 d2e0 bebe 0701 c68a t.s.0...........
00000110: 16b3 07bf 0500 56f6 c280 7431 b441 bbaa ......V...t1.A..
00000120: 5552 cd13 5a5e 5672 1e81 fb55 aa75 18f6 UR..Z^Vr...U.u..
00000130: c101 7413 8b44 088b 5c0a be8d 0789 4408 ..t..D..\.....D.
00000140: 895c 0ab4 42eb 0c8a 7401 8b4c 02b8 0102 .\..B...t..L....
00000150: bb00 7c50 c606 8f07 01cd 1358 5e73 054f ..|P.......X^s.O
00000160: 75b4 eb93 813e fe7d 55aa 75f6 ea00 7c00 u....>.}U.u...|.
00000170: 00be 8307 b90a 0050 b40e 31db accd 10e2 .......P..1.....
00000180: fb58 c354 6573 7444 6973 6b0d 0a10 0001 .X.TestDisk.....
00000190: 0000 7c00 0000 0000 0000 0000 0031 3233 ..|..........123
000001a0: 3446 0000 414e 4454 6d62 7200 0202 021f 4F..ANDTmbr.....
000001b0: c700 0080 0000 0000 ffff ffff ffff 8020 ...............
000001c0: 2100 83df 130c 0008 0000 0020 0300 00df !.......... ....
000001d0: 140c 8225 174e 0028 0300 0000 1000 0025 ...%.N.(.......%
000001e0: 184e 8315 5005 0028 1300 00d8 2c00 0000 .N..P..(....,...
000001f0: 0000 0000 0000 0000 0000 0000 0000 55aa ..............U.
Using testdisk, we found an recovered the /backup
folder but also discovered
some suspicious files under /root
:
1$ ls -R recovery/
2recovery/:
3backup root
4
5recovery/backup:
6Artists.csv secrets.db.enc
7
8recovery/root:
9implant key
The /backup/Artists.csv
file looks clean, we can give it to John. However,
its secrets.db.enc looks like it has been encrypted, let’s fix that for him.
It looks like /root/implant
is the malware we’re looking for!
There is also a /root/key
file.
1/root$ file *
2implant: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped
3key: data
4/root$ xxd key
500000000: 0ac8 6aa7 ce0f 9af6 fbff 91f9 c6d9 9dee ..j.............
600000010: 9450 a659 a22e 0ddc b51b 1a27 2361 6b53 .P.Y.......'#akS
700000020: 4ca7 b6e4 3852 4edb bca3 79fa 53c9 0fcd L...8RN...y.S...
800000030: d29a d806 630f 9a0c 04ab 584f 1d07 b7bc ....c.....XO....
900000040: 64d7 a492 edac 647b f5f1 4a50 e162 46c6 d.....d{..JP.bF.
1000000050: 3724 718a 957c 3c97 3b46 458d 2da7 d72e 7$q..|<.;FE.-...
1100000060: a60e 6af8 4b29 b9f8 ed40 a4ec e333 99d7 ..j.K)...@...3..
1200000070: 598e 8ee5 6517 02c6 7151 032a cb18 acca Y...e...qQ.*....
1300000080: 8449 8751 0017 0e82 6555 7717 aeeb 1501 .I.Q....eUw.....
1400000090: f09e 0ffd de19 d0d6 f681 8862 a7be 26da ...........b..&.
15000000a0: daac 0c8a 92ef 64b6 a129 8566 1b17 23a1 ......d..).f..#.
16000000b0: 8f42 c5c1 d08b 76e2 688f 2ee1 60f0 0072 .B....v.h...`..r
17000000c0: 0168 2453 5b90 a8e7 5479 3e9f 4114 2d9a .h$S[...Ty>.A.-.
18000000d0: 0dfc f8f9 dd6b ed5f fe45 3040 92d2 aff4 .....k._.E0@....
19000000e0: 858d d4f6 0ee5 c785 6f45 db84 77e5 3742 ........oE..w.7B
20000000f0: 33ec 8c60 d9fd ae72 0989 83d4 53f5 f012 3..`...r....S...
There is no symbols but we can extract a lot of juicy strings from the implant:
1shred -zuf key.bin
2shred /etc/hosts
3/root/secret
4/user/secret
5/root/backup
6/user/backup
7/dev/sda
8/dev/hda
9/dev/sdb
10/dev/hdb
11/dev/sdc
12/dev/hdc
13/dev/sdd
14/dev/hdd
15/dev/sde
16/dev/hde
17/dev/sdf
18/dev/hdf
19/dev/sdg
20/dev/hdg
21current domain is %s.%s
22openssl enc -aes-256-cbc -salt -pbkdf2 -in
23 -out
24.enc -pass file:./key.bin
25shred -uzf
26 Ooops, your important files are encrypted!
27 To decrypt send 1.5 BTC to mp9yaEzuym4LEH3drxeDS1pSQrKiJzJi1M
28 Then email us at contact@evilcorp.com with you personal ID: nGQ9xF84C
We can understand some bits of information out of those strings:
- The files have been encrypted using a
key.bin
key file that was then deleted usingshred
, so we don’t try to recover it. - Both the
secret
andbackup
directories ofroot
anduser
folders have been targeted. - A format-string is mentioning what looks like a domain name.
- The
/etc/hosts
file also has beenshred
ded.
Trying to use the left-over /root/key
file leads to nothing. What about the
domain thing?
Before handling incoming commands, the implant is checking the domain name
associated with the sender. We can recover the domain using the domain name
generation algorithm at 0x4011F1
:
1void __fastcall __noreturn sub_4011F1(unsigned int a1)
2{
3 __int64 v1; // rax
4 __int64 v2; // rax
5 __int64 v3; // rax
6 unsigned int v4; // [rsp+8h] [rbp-2E0h] BYREF
7 int cmd; // [rsp+Ch] [rbp-2DCh] BYREF
8 char v6[32]; // [rsp+10h] [rbp-2D8h] BYREF
9 __int16 v7[65]; // [rsp+30h] [rbp-2B8h] BYREF
10 char v8[255]; // [rsp+B2h] [rbp-236h] BYREF
11 char v9[311]; // [rsp+1B1h] [rbp-137h] BYREF
12
13 while ( 1 )
14 {
15 while ( 1 )
16 {
17 do
18 v4 = 0x80;
19 while ( recvfrom_4049E0(a1, &cmd, 4LL, 0LL, v7, &v4) != 4 );
20 if ( !(unsigned int)getnameinfo_4025E0(v7, v4, (__int64)v8, 0xFFu, (__int64)v6, 0x20u, 2) )
21 {
22 generate_domain_401517();
23 memset(v9, 0, 0xFFuLL);
24 v1 = strcat_40A300((__int64)v9, (__int64)&g_domain_name);
25 v2 = strcat_40A300(v1, (__int64)&string_dot_414000);
26 v3 = strcat_40A300(v2, (__int64)&string_bzh_414002);
27 if ( !(unsigned int)sub_40A440(v8, v3) )
28 break;
29 }
30 }
31 if ( !(unsigned int)sub_40A510(&cmd, "ABRT", 4LL) )
32 abrt();
33 if ( !(unsigned int)sub_40A510(&cmd, "NUKE", 4LL) )
34 nuke();
35 cmd = 4932417;
36 sub_405AA0(a1, &cmd, 4LL, 0LL, v7, v4);
37 }
38}
The domain name is generated at generate_domain_401517 and is appended with a dot at string_dot_414000 and a “bzh” TLD at string_bzh_414002.
Most of the job now is to reverse the generate_domain_401517 algorithm:
1unsigned __int64 generate_domain_401517()
2{
3 int *v0; // rax
4 __m128 day; // xmm1
5 __m128 year; // xmm0
6 char *domain; // rcx
7 __m128 month; // xmm2
8 unsigned __int64 v5; // xmm3_8
9 unsigned __int64 result; // rax
10 __int64 v7; // [rsp+8h] [rbp-10h] BYREF
11
12 v7 = time_40B0C0(0LL);
13 v0 = (int *)localtime_40B020(&v7);
14 day = (__m128)(unsigned __int64)v0[3];
15 year = (__m128)(unsigned __int64)(v0[5] + 1900);
16 domain = (char *)&g_domain_name;
17 month = (__m128)(unsigned __int64)(v0[4] + 1);
18 do
19 {
20 ++domain;
21 month = _mm_xor_ps(
22 (__m128)_mm_slli_epi64((__m128i)_mm_and_ps(month, (__m128)xmmword_4141A0), 4u),
23 (__m128)_mm_srli_epi64((__m128i)_mm_xor_ps((__m128)_mm_slli_epi64((__m128i)month, 2u), month), 1u));
24 year = _mm_xor_ps(
25 _mm_and_ps((__m128)_mm_slli_epi64((__m128i)year, 8u), (__m128)xmmword_4141B0),
26 (__m128)_mm_srli_epi64((__m128i)_mm_xor_ps((__m128)_mm_slli_epi64((__m128i)year, 3u), year), 4u));
27 day = _mm_xor_ps(
28 _mm_and_ps((__m128)_mm_slli_epi64((__m128i)day, 4u), (__m128)xmmword_4141C0),
29 (__m128)_mm_srli_epi64((__m128i)_mm_xor_ps((__m128)_mm_slli_epi64((__m128i)day, 0x10u), day), 2u));
30 v5 = month.m128_u64[0] ^ year.m128_u64[0] ^ day.m128_u64[0];
31 result = v5 / 0x19;
32 *(domain - 1) = v5 % 0x19 + 97;
33 }
34 while ( (char *)&g_domain_name + 9 != domain );
35 end_of_g_domain_name_41A631 = 0;
36 return result;
37}
The nine domain name characters are generated from a struct tm
structure
obtained from the localtime(time(NULL))
call. The assembly for the loop may
be more helpful than the decompiler to recover the DGA:
1loc_401577:
2movaps xmm7, xmm2 ; Move Aligned Four Packed Single-FP
3movaps xmm3, cs:xmmword_4141A0 ; Move Aligned Four Packed Single-FP
4xor edx, edx ; Logical Exclusive OR
5inc rcx ; Increment by 1
6psllq xmm7, 2 ; Packed Shift Left Logical (Qword)
7movaps xmm6, xmm7 ; Move Aligned Four Packed Single-FP
8movaps xmm7, xmm0 ; Move Aligned Four Packed Single-FP
9xorps xmm6, xmm2 ; Bitwise Logical XOR for Single-FP Data
10psllq xmm7, 3 ; Packed Shift Left Logical (Qword)
11andps xmm2, xmm3 ; Bitwise Logical And for Single-FP
12psrlq xmm6, 1 ; Packed Shift Right Logical (Qword)
13psllq xmm2, 4 ; Packed Shift Left Logical (Qword)
14movaps xmm3, xmm7 ; Move Aligned Four Packed Single-FP
15xorps xmm2, xmm6 ; Bitwise Logical XOR for Single-FP Data
16xorps xmm3, xmm0 ; Bitwise Logical XOR for Single-FP Data
17movaps xmm6, xmm1 ; Move Aligned Four Packed Single-FP
18psllq xmm0, 8 ; Packed Shift Left Logical (Qword)
19psrlq xmm3, 4 ; Packed Shift Right Logical (Qword)
20movaps xmm7, xmm2 ; Move Aligned Four Packed Single-FP
21andps xmm0, xmm5 ; Bitwise Logical And for Single-FP
22psllq xmm6, 10h ; Packed Shift Left Logical (Qword)
23xorps xmm0, xmm3 ; Bitwise Logical XOR for Single-FP Data
24movaps xmm3, xmm6 ; Move Aligned Four Packed Single-FP
25xorps xmm3, xmm1 ; Bitwise Logical XOR for Single-FP Data
26psllq xmm1, 4 ; Packed Shift Left Logical (Qword)
27xorps xmm7, xmm0 ; Bitwise Logical XOR for Single-FP Data
28psrlq xmm3, 2 ; Packed Shift Right Logical (Qword)
29andps xmm1, xmm4 ; Bitwise Logical And for Single-FP
30xorps xmm1, xmm3 ; Bitwise Logical XOR for Single-FP Data
31movaps xmm3, xmm7 ; Move Aligned Four Packed Single-FP
32xorps xmm3, xmm1 ; Bitwise Logical XOR for Single-FP Data
33movq rax, xmm3 ; Move 64 bits
34div rsi ; Unsigned Divide
35add edx, 61h ; 'a' ; Add
36mov [rcx-1], dl
37cmp rdi, rcx ; Compare Two Operands
38jnz loc_401577 ; Jump if Not Zero (ZF=0)
You can either debug, emulate it or reimplement it.
Here is a C transcript or the original DGA:
1#include <stdlib.h>
2#include <stdint.h>
3#include <stdio.h>
4#include <err.h>
5
6int main(int ac, char**av)
7{
8 if (ac != 4)
9 errx(EXIT_FAILURE, "usage: %s <month> <day> <year>\n", av[0]);
10
11 char subdomain[10];
12 uint64_t month = (uint64_t)atoi(av[1]);
13 uint64_t day = (uint64_t)atoi(av[2]);
14 uint64_t year = (uint64_t)atoi(av[3]);
15 for(unsigned i = 0 ; i < sizeof(subdomain) - 1; ++i)
16 {
17 month = ((month ^ 4 * month) >> 1) ^ 16 * (month & 0xFFFFFFF2);
18 year = ((year ^ 8 * year) >> 4) ^ ((year & 0xFFFFFFF4) << 8);
19 day = ((day ^ (day << 16)) >> 2) ^ ((day & 0xFFFFFFFA) << 4);
20 subdomain[i] = (char)(((year ^ month ^ day) % 25) + 'a');
21 }
22
23 subdomain[sizeof(subdomain)-1] = 0;
24 printf("subdomain: %s\n", subdomain);
25}
With such algorithm, we are able to recover the domain name generated for the date of the attack:
1$ ./dga 07 26 2023
2subdomain: uxigxmxvm
Now let’s hack back those hackers at uxigxmxvm.bzh
!
It’s a static website leaking data from those hackers victims. Can we find
John’s data over there? Definitely not, but as we explore the website, it
stands out that each company data is leaked under /files/<ID>
and that ID
looks pretty much like the one we were given in the corrupted bootloader.
By Looking at /files/nGQ9xF84C/
, we recover a key.pem
key file.
1$ wget uxigxmxvm.bzh/files/nGQ9xF84C/key.pem
2$ cat key.pem
3-----BEGIN PRIVATE KEY-----
4MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDChc3ubr7clJtt
5RGVTIKmaZdRDMETKZIOLIehLH3U52QJ1Xa1ruZ+PC1BKWVNPqS/E3x9p5CSec6Ba
6nJtn7KI1m7Qxu8uCtkr8xCZ1jFge1KYmYh4u21r7fJzdXM9qyxgML3knKi4GV0BA
7clZ6UXX6m/432CzufbmDhMRSd7XfdQed8X2SK7gwtePOmqY4AmnRl9ozLtR+qTff
8sv5FtZQcxyA5FHR9MQlTaYzg+mKrvtax+vKZg+INfolQobXKoi17nLwHhZ5Ow8Ha
9xyLkqMfBC3hej6qo2yBY5JzxgIGhufjXV1F82IbFFx6B7JY2hmvhjiAG4dqfkHWw
10q+ojOYoVAgMBAAECggEAHvLAjEuaBH3aP/yumEFX6o+Clrv9EyxXEhGaI9WZ8NME
11xUfbBGAbMYbNxpPGoaPGd1k+Zg+yVHQLUk9HRGC4KrTz6tO43GTaB7QXda1CBIm1
12nja5xvUHA9WpdBNE5stFhK7K5OnHj80IP8NRMeh4T5/LnEvsU3dfnBFJVjY4kpgE
13tXsZxBU8NaR6XtZEx1ohtUwVMZth4ZMgNs1b24acQaH0KK40sG8sbzqhdA2Qk+cQ
14XKPyji6uS4stzpxQrgC4eyD2aM/Oq0g7zSf+HfhCY03Fvx97G4rDRtpP4KIW2Htg
15gkoaVwOBXiNsqMD935n09Xwplk9Lawioe/f8LQEQQwKBgQDsr6SLMDn4oMQFombN
16lgKcejI93XDOHpJS9Oxh/Y6yLdAeQUaLUX7DfR90XiTLRuP6BiljWN8Dh66nrklo
17JBYUW1FIZeqL2Woa14BT0MZN14x0c3wunqR1zQWlGmwROc+phAJp/Y2Q/AyDDkrn
18wvV01/tT0BJ+0jcfcI5gV134wwKBgQDSZV7Pf3GOD2kH5jjCBHWNXVf45UJktqjk
193I//rOfy4XO2bR8TKufo8mM8lOmRxsThpWgxnKjE+6qisSahqwObB9R73aebPFBq
20KMCNOMsjj5+isuhhwaH5rtS1OUCBpM+mkjkZmua6tJtiH1UhEPUJoPmEf4+CcGF8
213RTW1jeERwKBgQCtHPKek1FzVjLJZDUI3VVfmcixkwt01stzPYy/RzNdg0CbQGcW
22cy7iUNv2wvzqaRlJv8P51ACZll3aaxFpyCsWDIxxBYn9a7G9nC1SIHtKaANlESqc
239o+XUbN1RNQR7VTDybfySe+HQbLtEEEdLm1VXruGW8OLWrnSlwKr2Hr0/QKBgQDK
24EK2UH1QSGd7HxWYxgFLd6A47bwPq8jsXQnXSGl/SNpEJXZgAsq50XYbNgj8o0Hv6
25Mv/01f6I4SOqiPUPQ818sXJzXBhC0RRyQJ1dhHQkvSWV/rmMWYmU4UJMoqW/XWhJ
26FBpe6xQ5sIejH3CFB2IvUzkQ9eoAXqpiX3pKMwaytQKBgQCYVJ5KtW20f9Ox7qJZ
272MDMu7L5gj/6C02fGN+bLLrudyxBcYvqiSzwE7Q5ZG6TRUGWSNASl9SqsK24MI2E
28LdgAWInYleCS8Jali1wZtXGxtpvdRYlLiDtV58Qr7RBcpfLDVoAxyiCFtWearZqZ
29AJbu+b9e33Z4SzI17gTHeRvcRw==
30-----END PRIVATE KEY-----
On John’s machine, the implant used a key.bin
file for file encryption before
deleting it. However, it left a key
file.
1$ openssl rsautl -decrypt -inkey key.pem -in recovery/root/key -out key.bin
2$ cat key.bin
3UyhXwZQ+cxB+QunKoBA2Nbzj5SfhoBVFtFUyoS25EMg=
It looks like we recovered the 256 bits key used for file encryption. By looking at the implant strings, aes cbc was used, let’s try that on secrets.db.enc:
1$ openssl enc -d -aes-256-cbc -pbkdf2 -in recovery/backup/secrets.db.enc -out secrets.db -pass file:key.bin
2$ file secrets.db
3secrets.db: SQLite 3.x database, last written using SQLite version 3038001
4$ sqlite3 secrets.db .dump
5PRAGMA foreign_keys=OFF;
6BEGIN TRANSACTION;
7CREATE TABLE secrets(flag text not null);
8INSERT INTO secrets VALUES('ECW{all_your_file_belong_to_us}');
9COMMIT;
Awesome, here is your flag!