Home FlareOn 11 Challenge 2 - Checksum
Post
Cancel

FlareOn 11 Challenge 2 - Checksum

DiE Info

Tossing checksum.exe into Detect it Easy, we can see that it is written in Golang.

Throwing caution to the wind, we run checksum.exe and are presented with a series of addition questions. Each must be answered correctly or the program exits.

Finally, after a bit, we are asked for a final Checksum… Enter the wrong checksum and the program exits.

Ghidra Analysis

Time to throw this into Ghidra as I think it has some Golang support. Right?

Now, I know virtually nothing about Golang. So, I’ll use a bit of chatGPT here:

…maybe helpful? Let’s take a look at Exports in Ghidra and see if we can find a main function.

Turns out, there’s a few…

main.b

Seems to handle errors:

main.main

This is the meat and potatoes. We can see our goodboy and badboy messages as well as some other interesting things:

Click to view the main.main code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
/* DWARF original prototype: void main.main(void)
   Golang function info: Flags: []
   Golang source: C:/Users/chuong.dong/Exclusions/check_sum/checksum.go:40
   Golang stacktrace signature: undefined main.main() */

void main::main.main(void)

{
  byte bVar1;
  char cVar2;
  bool bVar3;
  undefined8 extraout_RAX;
  uint8 *ptr;
  int iVar4;
  uint uVar5;
  int extraout_RCX;
  runtime.itab *prVar6;
  undefined8 extraout_RBX;
  undefined **ppuVar7;
  void *extraout_RSI;
  runtime.itab *extraout_RDI;
  internal/abi.Type *piVar8;
  undefined8 uVar9;
  string s;
  io.Writer w;
  io.Reader r;
  string s_00;
  io.Writer w_00;
  io.Reader r_00;
  error err;
  string sVar10;
  io.Writer w_01;
  error eVar11;
  io.Writer w_02;
  fmt.Fscanf_multivalue_return_type fVar12;
  []uint8 [Var13;
  encoding/hex.Decode_multivalue_return_type eVar14;
  []uint8 [Var15;
  os.UserCacheDir_multivalue_return_type oVar16;
  string a1;
  string format;
  string format_00;
  string errorString;
  string errorString_00;
  string errorString_01;
  string errorString_02;
  string errorString_03;
  string errorString_04;
  string errorString_05;
  []interface_{} a;
  []interface_{} a_00;
  []interface_{} a_01;
  []interface_{} a_02;
  []interface_{} a_03;
  []interface_{} a_04;
  string a0;
  []uint8 [Var17;
  uint8 local_1e8 [24];
  undefined1 local_1d0 [8];
  uint8 local_1c8 [32];
  runtime.itab *local_1a8;
  uint local_1a0;
  uint local_198;
  int local_190;
  int local_188;
  undefined8 local_180;
  int local_178;
  int local_170;
  uint local_168;
  uint64 local_160;
  uint64 local_158;
  uint64 local_150;
  internal/abi.Type *local_148;
  uint32 auStack_140 [28];
  golang.org/x/crypto/chacha20poly1305.xchacha20poly1305 *local_d0;
  golang.org/x/crypto/chacha20poly1305.xchacha20poly1305 *local_c8;
  golang.org/x/crypto/chacha20poly1305.xchacha20poly1305 *local_c0;
  uint8 *local_b8;
  undefined8 local_b0;
  uint8 *local_a8;
  uint8 *local_a0;
  internal/abi.Type *local_98;
  string *psStack_90;
  internal/abi.Type *local_88;
  string *psStack_80;
  undefined *local_78;
  undefined8 uStack_70;
  internal/abi.PtrType *local_68;
  string *psStack_60;
  internal/abi.Type *local_58;
  string *psStack_50;
  internal/abi.PtrType *local_48;
  int *piStack_40;
  internal/abi.Type *local_38;
  void *pvStack_30;
  internal/abi.Type *local_28;
  void *pvStack_20;
  int *local_18;
  string *local_10;
  
  piVar8 = (internal/abi.Type *)0x0;
  uVar9._0_4_ = 0;
  uVar9._4_4_ = 0;
  while (local_1d0 <= CURRENT_G.stackguard0) {
    runtime::runtime.morestack_noctxt();
  }
  local_150 = math/rand/v2::math/rand/v2.(*Rand).uint64n(math/rand/v2.globalRand,5);
  local_18 = runtime::runtime.newobject(&int___internal/abi.Type);
  iVar4 = 0;
  while (iVar4 < (int)(local_150 + 3)) {
    local_190 = iVar4;
    local_158 = math/rand/v2::math/rand/v2.(*Rand).uint64n(math/rand/v2.globalRand,10000);
    local_160 = math/rand/v2::math/rand/v2.(*Rand).uint64n(math/rand/v2.globalRand,10000);
    local_38 = piVar8;
    pvStack_30 = (void *)uVar9;
    local_28 = piVar8;
    pvStack_20 = (void *)uVar9;
    pvStack_30 = runtime::runtime.convT64(local_158);
    local_38 = &int___internal/abi.Type;
    pvStack_20 = runtime::runtime.convT64(local_160);
    local_28 = &int___internal/abi.Type;
    local_168 = local_160 + local_158;
    w.data = os.Stdout;
    w.tab = &os::*os.File__implements__io.Writer___runtime.itab;
    format.len = 0x15;
    format.str = &DAT_004ca484;
    a.len = 2;
    a.array = (interface_{} *)&local_38;
    a.cap = 2;
    fmt::fmt.Fprintf(w,format,a);
    local_48 = &*int___internal/abi.PtrType;
    piStack_40 = local_18;
    r.data = os.Stdin;
    r.tab = &os::*os.File__implements__io.Reader___runtime.itab;
    format_00.len = 3;
    format_00.str = &DAT_004c73c1;
    a_00.len = 1;
    a_00.array = (interface_{} *)&local_48;
    a_00.cap = 1;
    fVar12 = fmt::fmt.Fscanf(r,format_00,a_00);
    errorString.len = 0x15;
    errorString.str = (uint8 *)"Not a valid answer...";
    main.b(fVar12.err,errorString);
    if (*local_18 != local_168) {
      runtime::runtime.printlock();
      s_00.len = 0xe;
      s_00.str = (uint8 *)"Try again! ;)\n";
      runtime::runtime.printstring(s_00);
      runtime::runtime.printunlock();
      return;
    }
    runtime::runtime.printlock();
    s.len = 0x2c;
    s.str = (uint8 *)"Good math!!!\n------------------------------\n";
    runtime::runtime.printstring(s);
    runtime::runtime.printunlock();
    iVar4 = local_190 + 1;
  }
  local_10 = runtime::runtime.newobject(&string___internal/abi.Type);
  local_10->str = (uint8 *)0x0;
  local_58 = &string___internal/abi.Type;
  psStack_50 = &gostr_Checksum:;
  w_00.data = os.Stdout;
  w_00.tab = &os::*os.File__implements__io.Writer___runtime.itab;
  a_02.len = 1;
  a_02.array = (interface_{} *)&local_58;
  a_02.cap = 1;
  fmt::fmt.Fprint(w_00,a_02);
  local_68 = &*string___internal/abi.PtrType;
  psStack_60 = local_10;
  r_00.data = os.Stdin;
  r_00.tab = &os::*os.File__implements__io.Reader___runtime.itab;
  sVar10.len = 3;
  sVar10.str = &DAT_004c73c4;
  a_01.len = 1;
  a_01.array = (interface_{} *)&local_68;
  a_01.cap = 1;
  fVar12 = fmt::fmt.Fscanf(r_00,sVar10,a_01);
  errorString_00.len = 0x1e;
  errorString_00.str = (uint8 *)"Fail to read checksum input...";
  main.b(fVar12.err,errorString_00);
  [Var13 = runtime::runtime.stringtoslicebyte(&local_1c8,*local_10);
  local_1a0 = [Var13.cap;
  local_c8 = (golang.org/x/crypto/chacha20poly1305.xchacha20poly1305 *)[Var13.array;
  eVar14 = encoding/hex::encoding/hex.Decode([Var13,[Var13);
  local_198 = eVar14.~r0;
  if (local_1a0 < local_198) {
                    /* WARNING: Subroutine does not return */
    runtime::runtime.panicSliceAcap(local_198,eVar14.~r1,local_198);
  }
  errorString_01.len = 0x17;
  errorString_01.str = (uint8 *)"Not a valid checksum...";
  main.b(eVar14.~r1,errorString_01);
  [Var15 = runtime::runtime.makeslice(&uint8___internal/abi.Type,0x18,0x18);
  local_a0 = [Var15.array;
  for (uVar5 = 0; (int)uVar5 < (int)local_198; uVar5 = uVar5 + 1) {
    if (uVar5 == 0x18) break;
    if (0x17 < uVar5) {
                    /* WARNING: Subroutine does not return */
      runtime::runtime.panicIndex(uVar5,[Var15.len,0x18);
    }
    local_a0[uVar5] = local_c8->key[uVar5];
  }
  if (local_198 == 0x20) {
    local_d0 = runtime::runtime.newobject
                         (&golang.org/x/crypto/chacha20poly1305::
                           golang.org/x/crypto/chacha20poly1305.xchacha20poly1305___internal/abi.Str uctType
                           .Type);
    if (local_d0 != local_c8) {
      local_c0 = local_d0;
      runtime::runtime.memmove(local_d0,local_c8,0x20);
      local_d0 = local_c0;
    }
    local_1a8 = &golang.org/x/crypto/chacha20poly1305::
                 *chacha20poly1305.xchacha20poly1305__implements__cipher.AEAD___runtime.itab;
    prVar6 = (runtime.itab *)0x0;
    ppuVar7 = (undefined **)0x0;
  }
  else {
    uStack_70 = 0x20;
    local_78 = &DAT_004cccc6;
    local_1a8 = (runtime.itab *)0x0;
    prVar6 = &errors::*errors.errorString__implements__error___runtime.itab;
    local_d0 = (golang.org/x/crypto/chacha20poly1305.xchacha20poly1305 *)0x0;
    ppuVar7 = &local_78;
  }
  eVar11.data = ppuVar7;
  eVar11.tab = prVar6;
  errorString_02.len = 0x29;
  errorString_02.str = (uint8 *)"Maybe it\'s time to analyze the binary! ;)";
  main.b(eVar11,errorString_02);
  (*(code *)local_1a8[1].inter)(local_d0,0,0,0,local_a0,0x18,0x18);
  err.data = extraout_RSI;
  err.tab = extraout_RDI;
  errorString_03.len = 0x29;
  errorString_03.str = (uint8 *)"Maybe it\'s time to analyze the binary! ;)";
  local_180 = extraout_RBX;
  local_178 = extraout_RCX;
  local_b0 = extraout_RAX;
  main.b(err,errorString_03);
  local_148 = piVar8;
  auStack_140._0_8_ = uVar9;
  runtime::runtime.duffzero_00463086(&local_150);
  crypto/sha256::crypto/sha256.(*digest).Reset((crypto/sha256.digest *)&local_148);
  [Var15.len = local_180;
  [Var15.array = (uint8 *)local_b0;
  [Var15.cap = local_178;
  crypto/sha256::crypto/sha256.(*digest).Write((crypto/sha256.digest *)&local_148,[Var15);
  [Var17.cap = 0;
  [Var17.array = (uint8 *)0x0;
  [Var17.len = 0;
  [Var15 = crypto/sha256::crypto/sha256.(*digest).Sum((crypto/sha256.digest *)&local_148,[Var17);
  local_188 = [Var15.len;
  local_b8 = [Var15.array;
  local_168 = local_188 << 1;
  [Var15 = runtime::runtime.makeslice(&uint8___internal/abi.Type,local_168,local_168);
  ptr = [Var15.array;
  iVar4 = 0;
  uVar5 = 0;
  while( true ) {
    if (local_188 <= iVar4) {
      sVar10 = runtime::runtime.slicebytetostring((runtime.tmpBuf *)local_1e8,ptr,local_168);
      if (sVar10.len == local_10->len) {
        cVar2 = runtime::runtime.memequal(sVar10.str,local_10->str);
        if (cVar2 == '\0') {
          bVar3 = false;
        }
        else {
          bVar3 = main.a(*local_10);
        }
      }
      else {
        bVar3 = false;
      }
      if (bVar3 == false) {
        local_88 = &string___internal/abi.Type;
        psStack_80 = &gostr_Maybe_it's_time_to_analyze_the_b;
        w_01.data = os.Stdout;
        w_01.tab = &os::*os.File__implements__io.Writer___runtime.itab;
        a_03.len = 1;
        a_03.array = (interface_{} *)&local_88;
        a_03.cap = 1;
        fmt::fmt.Fprintln(w_01,a_03);
      }
      oVar16 = os::os.UserCacheDir();
      local_170 = oVar16.~r0.len;
      local_a8 = oVar16.~r0;
      errorString_04.len = 0x13;
      errorString_04.str = (uint8 *)"Fail to get path...";
      main.b(oVar16.~r1,errorString_04);
      a1.len = 0x16;
      a1.str = (uint8 *)"\\REAL_FLAREON_FLAG.JPG";
      a0.len = local_170;
      a0.str = local_a8;
      sVar10 = runtime::runtime.concatstring2((runtime.tmpBuf *)0x0,a0,a1);
      [Var13.len = local_180;
      [Var13.array = (uint8 *)local_b0;
      [Var13.cap = local_178;
      eVar11 = os::os.WriteFile(sVar10,[Var13,0x1a4);
      errorString_05.len = 0x15;
      errorString_05.str = (uint8 *)"Fail to write file...";
      main.b(eVar11,errorString_05);
      local_98 = &string___internal/abi.Type;
      psStack_90 = &gostr_Noice!!;
      w_02.data = os.Stdout;
      w_02.tab = &os::*os.File__implements__io.Writer___runtime.itab;
      a_04.len = 1;
      a_04.array = (interface_{} *)&local_98;
      a_04.cap = 1;
      fmt::fmt.Fprintln(w_02,a_04);
      return;
    }
    bVar1 = local_b8[iVar4];
    if (local_168 <= uVar5) break;
    ptr[uVar5] = (&DAT_004c9145)[bVar1 >> 4];
    if (local_168 <= uVar5 + 1) {
                    /* WARNING: Subroutine does not return */
      runtime::runtime.panicIndex(uVar5 + 1,uVar5,local_168);
    }
    ptr[uVar5 + 1] = (&DAT_004c9145)[bVar1 & 0xf];
    iVar4 = iVar4 + 1;
    uVar5 = uVar5 + 2;
  }
                    /* WARNING: Subroutine does not return */
  runtime::runtime.panicIndex(uVar5,uVar5,local_168);
}

writefile Writing a file at some point?

main.a

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
bool main::main.a(string checksum)

{
  undefined1 uVar1;
  uintptr *puVar2;
  uint uVar3;
  int len;
  int iVar4;
  string sVar5;
  []uint8 [Var6;
  []uint8 src;
  string checksum_spill;
  
  len = checksum.len;
  puVar2 = (uintptr *)checksum.str;
  while (&stack0x00000000 <= CURRENT_G.stackguard0) {
    runtime::runtime.morestack_noctxt();
  }
  if (puVar2 == (uintptr *)0x0) {
    puVar2 = &runtime.zerobase;
  }
  [Var6 = runtime::runtime.makeslice(&uint8___internal/abi.Type,len,len);
  iVar4 = 0;
  while( true ) {
    if (len <= iVar4) {
      src.len = len;
      src.array = [Var6.array;
      src.cap = len;
      sVar5 = encoding/base64::encoding/base64.(*Encoding).EncodeToString
                        (encoding/base64.StdEncoding,src);
      if (sVar5.len == 0x58) {
        uVar1 = runtime::runtime.memequal
                          (sVar5.str,
                           "cQoFRQErX1YAVw1zVQdFUSxfAQNRBXUNAxBSe15QCVRVJ1pQEwd/WFBUAlElCFBFUnlaB1UL ByRdBEFdfVtWVA=="
                           ,0x58);
      }
      else {
        uVar1 = 0;
      }
      return (bool)uVar1;
    }
    uVar3 = iVar4 + (iVar4 / 0xb + (iVar4 >> 0x3f)) * -0xb;
    if (10 < uVar3) break;
    [Var6.array[iVar4] = *(byte *)((int)puVar2 + iVar4) ^ (&DAT_004c8035)[uVar3];
    iVar4 = iVar4 + 1;
  }
                    /* WARNING: Subroutine does not return */
  runtime::runtime.panicIndex(uVar3,iVar4,0xb); 
  1. Function takes string checksum as a parameter:

  2. This base64 encoded value that seems to be compared with something
  3. Bitwise xor occuring between checksum and DAT_004c8035

Double clicking on DAT_004c8035 and we see:

So, our bitwise xor seems to be against the key 'FlareOn2024'

A Closer Look

Our checksum is bitwise xor’d with the key ‘FlareOn2024’. The result is base64 encoded and compared with another hardcoded base64 value.

The Recipe

Using CyberChef we can easily reverse this process:

  1. base64 decode the hardcoded value
  2. XOR with FlareOn2024
  3. Grab our checksum!

Success?

Ok but where is the flag?

Need to look back in main.main

Remember the file that was written? Looks like it is being written to UserCacheDir

But…uh where the hell is that??

I’m sure AI knows…

Sure enough in %localappdata% we find REAL_FLAREON_FLAG.JPG

This post is licensed under CC BY 4.0 by the author.