Post

SWPUCTF 2022 新生赛wasm

pre

首先安装wabt

0x01

1
./wasm-decompile  wasm.wasm wasm.dcmp

option 也可以使用wasm2wat,wasm2c 生成其他文件 不好审计效果好像都不太友好

0x02

进入wasm.dcmp找到关键函数check

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
function assembly_index_check(a:int):int {
  var b:int;
  var e:int;
  lib_memory_stack_pointer = lib_memory_stack_pointer - 8;
  stack_check();
  label B_a:
  lib_memory_stack_pointer[0]:long = 0L;
  e = 
    {
      if (lib_array_Array_i32_get_length(a) != 38) {     //长度为38
        e = 0;
        lib_memory_stack_pointer = lib_memory_stack_pointer + 8;
        return e;
        label B_d:
        unreachable;
      }
      lib_memory_stack_pointer[0]:int =
        (b = lib_array_Array_i32_slice(a, 7, -1)); // 数组slice  b = a[7:-1]
      var c:int = 0;
      loop L_f {
        var d:int = c < lib_array_Array_i32_get_length(b); // 循环30次
        if (d) {
          assembly_index_reverse(b); // 数组倒转
          assembly_index_rotate(b, 1); // 数组 >> 1
          //这里可以看出,其实数组反转一次,数组循环右移一位,此时在反转一次,此时相当于原数组(第一次反转前)左移一次
          // 所以偶数次 实际就是不变 
          label B_h:
          c = c + 1;
          continue L_f;
        }
      }
      // 相当于执行assembly_index_lp(b[0:10])和assembly_index_rp(b[10:30])
      label B_e:
      if (assembly_index_lp({
                              e = lib_array_Array_i32_slice(b, 0, 10);
                              lib_memory_stack_pointer[1]:int = e;
                              e;
                              label B_i:
                            })) {
        assembly_index_rp(
          {
            e = lib_array_Array_i32_slice(b, 10, lib_builtins_i32_MAX_VALUE);
            lib_memory_stack_pointer[1]:int = e;
            e;
            label B_k:
          })
      } else {
        0
      }
      label B_b:
    }
  lib_memory_stack_pointer = lib_memory_stack_pointer + 8;
  return e;
}

所以我们只需要查看assembly_index_lp和assembly_index_rp这两个函数即可

首先看assembly_index_lp

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
function assembly_index_lp(a:int):int {
  return 
    if (if (if (if (if (if (if (if (if (lib_array_Array_i32_get(a, 0) + lib_array_Array_i32_get(a, 5) ==
                                        lib_array_Array_i32_get(a, 1) + lib_array_Array_i32_get(a, 9)) {
                                      lib_array_Array_i32_get(a, 0) + lib_array_Array_i32_get(a, 1) +
                                      lib_array_Array_i32_get(a, 2) +
                                      lib_array_Array_i32_get(a, 3) +
                                      lib_array_Array_i32_get(a, 4) +
                                      lib_array_Array_i32_get(a, 5) +
                                      lib_array_Array_i32_get(a, 6) +
                                      lib_array_Array_i32_get(a, 7) +
                                      lib_array_Array_i32_get(a, 8) +
                                      lib_array_Array_i32_get(a, 9) ==
                                      1022
                                    } else {
                                      0
                                    }) {
                                  lib_array_Array_i32_get(a, 7) - lib_array_Array_i32_get(a, 8) == 10
                                } else {
                                  0
                                }) {
                              lib_array_Array_i32_get(a, 3) + lib_array_Array_i32_get(a, 2) +
                              lib_array_Array_i32_get(a, 1) ==
                              330
                            } else {
                              0
                            }) {
                          lib_array_Array_i32_get(a, 5) * lib_array_Array_i32_get(a, 6) *
                          lib_array_Array_i32_get(a, 8) ==
                          617500
                        } else {
                          0
                        }) {
                      lib_array_Array_i32_get(a, 6) * 2 ==
                      lib_array_Array_i32_get(a, 3) + 15
                    } else {
                      0
                    }) {
                  lib_array_Array_i32_get(a, 7) ==
                  lib_array_Array_i32_get(a, 5) + lib_array_Array_i32_get(a, 4) -
                  lib_array_Array_i32_get(a, 2) +
                  3
                } else {
                  0
                }) {
              lib_array_Array_i32_get(a, 8) + lib_array_Array_i32_get(a, 4) == 209
            } else {
              0
            }) {
          lib_array_Array_i32_get(a, 1) + lib_array_Array_i32_get(a, 8) +
          lib_array_Array_i32_get(a, 9) -
          lib_array_Array_i32_get(a, 4) ==
          204
        } else {
          0
        }) {
      lib_array_Array_i32_get(a, 0) * lib_array_Array_i32_get(a, 1) *
      lib_array_Array_i32_get(a, 2) ==
      1350628
    } else {
      0
    }

emm看起来想是一堆方程,那就解吧,当时手头没有纸笔,只能被迫用z3了

数学大佬可以手动解出orz

好了数组前10位已经搞定,下面来看数组后20位

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
function assembly_index_rp(a:int):int {
  var c:int;
  var e:int;
  lib_memory_stack_pointer = lib_memory_stack_pointer - 4;
  stack_check();
  label B_a:
  lib_memory_stack_pointer[0]:int = 0;
  e = 
    {
      lib_memory_stack_pointer[0]:int =
        (c = lib_rt_newArray(20, 2, 3, 528)); // 长度20的数组
      var b:int = 0;
      loop L_d {
        var d:int = b < lib_array_Array_i32_get_length(a); // 获取长度
        if (d) {
          if (lib_array_Array_i32_get(c, b) == (lib_array_Array_i32_get(a, b) ^ 2)) {
            lib_array_Array_i32_set(c, b, lib_array_Array_i32_get(a, b))
          } else {
            e = 0;
            lib_memory_stack_pointer = lib_memory_stack_pointer + 4;
            return e;
            label B_h:
            unreachable;
          }
          label B_f:
          b = b + 1;
          continue L_d;
        }
      }
      label B_c:
      1;
      label B_b:
    }
  lib_memory_stack_pointer = lib_memory_stack_pointer + 4;
  return e;
}

这里看到c数组^2就是b数组 c数组到底是什么需要细看lib_rt_newArray

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function lib_rt_newArray(a:int, b:int, c:int, d:int):int {
  var f:int;
  lib_memory_stack_pointer = lib_memory_stack_pointer - 4;
  stack_check();
  label B_a:
  lib_memory_stack_pointer[0]:int = 0;
  var h:int = 
    {
      var e:int = a << b;
      lib_memory_stack_pointer[0]:int = (f = lib_rt_newBuffer(e, 0, d)); //lib_rt_newBuffer(len,?,src)
      var g:{ a:int, b:int, c:int, d:int } = lib_rt_itcms_new(16, c); //lib_rt_itcms_new(rtsize,rtid)
      g.a = f; // buffer
      lib_rt_itcms_link(g, f, 0);
      g.b = f; //link?
      g.c = e; 
      g.d = a; //长度
      g;
      label B_b:
    }
  lib_memory_stack_pointer = lib_memory_stack_pointer + 4;
  return h;
}

可以看到在528之后的20字节,填充了c,在数据区找到了相应的数据

1
2
3
4
5
6
7
8
9
10
data d_lPvjcliqdmpmwpumpi(offset: 508) =
  "l\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00P\00\00\00v\00\00\00j\00"
  "\00\00c\00\00\00l\00\00\00i\00\00\00q\00\00\00]\00\00\00d\00\00\00m\00"
  "\00\00p\00\00\00]\00\00\00{\00\00\00m\00\00\00w\00\00\00p\00\00\00]\00"
  "\00\00u\00\00\00m\00\00\00p\00\00\00i\00\00\00\00\00\00\00\00\00\00\00"
  "\00\00\00\00";
  data d_Objectalreadypinned(offset: 620) =
  "<\00\00\00\00\00\00\00\00\00\00\00\01\00\00\00*\00\00\00O\00b\00j\00e\00"
  "c\00t\00 \00a\00l\00r\00e\00a\00d\00y\00 \00p\00i\00n\00n\00e\00d\00\00"
  "\00";

528之后的实际字符串为’vjcliq]dmp]{mwp]umpi’ 好了分析结束

0x03

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
from z3 import *
from pwn import * 

a0, a1, a2, a3, a4, a5, a6, a7, a8, a9 =BitVecs('a0 a1 a2 a3 a4 a5 a6 a7 a8 a9',32)
s = Solver()
s.add(a0 < 128)
s.add(a1 < 128)
s.add(a2 < 128)
s.add(a3 < 128)
s.add(a4 < 128)
s.add(a5 < 128)
s.add(a6 < 128)
s.add(a7 < 128)
s.add(a8 < 128)
s.add(a9 < 128)
s.add(a0 > 0)
s.add(a1 > 0)
s.add(a3 > 0)
s.add(a4 > 0)
s.add(a5 > 0)
s.add(a6 > 0)
s.add(a7 > 0)
s.add(a8 > 0)
s.add(a9 > 0)
s.add(a0 + a5 == a1 + a9)
s.add(a0 + a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 == 1022)
s.add(a7 - a8 == 10)
s.add(a3 + a2 + a1 == 330)
s.add(a5 * a6 * a8 == 617500)
s.add(a6 * 2 == a3 + 15)
s.add(a7 == a5 + a4 - a2 + 3)
s.add(a8 + a4 == 209)
s.add(a1 + a8 + a9 - a4 == 204)
s.add(a0 * a1 * a2 == 1350628)
check = s.check()
print(check)
model = s.model()
print(model)
flag = 'vvasm_And_' # maybe you should parse model
# print(flag) 
ss = 'vjcliq]dmp]{mwp]umpi'
b = xor(ss,2)
ss = str(b,encoding='ascii')
flag += ss

for i in range(30):
    flag = flag[::-1]
    # print(flag)
    flag = flag[-1] + flag[:-1]
    # print(flag)

print(flag)

0x04

flag = vvasm_And_thanks_for_your_work

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