Post

SunshineCTF - warp

0x01

直接运行显示权限不够,sudo运行后显示监听本机的端口

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
/* WARNING: Enum "__rlimit_resource": Some values do not have unique names */
/* DWARF original prototype:
   Result<(),_alloc::boxed::Box<dyn_core::error::Error,_alloc::alloc::Global>> main(void) */

Result<> __rustcall warp_ebpf::warp_ebpf::main(void)

{
  &[u8] data;
  rlimit rlim;
  Ebpf ebpf;
  Result<> residual;
  Ebpf val;
  String iface;
  String val_1;
  Result<> residual_3;
  Result<> residual_4;
  Result<> residual_5;
  RingBuf<> rb;
  Result<> residual_6;
  RingBuf<> val_2;
  RingBufItem item;
  u8 buffer [33];
  Event event;
  String str;
  Argument args [1];
  Argument args_1 [1];
  Result<> residual_7;
  Xdp *prog;
  Result<> residual_2;
  Result<> residual_1;
  rlimit64 local_8f8 [7];
  ControlFlow<> local_888;
  Result<> local_820;
  undefined1 local_7b8 [104];
  undefined1 local_750 [1872];
  
  local_8f8[0].rlim_cur = 0xffffffffffffffff;
  local_8f8[0].rlim_max = 0xffffffffffffffff;
  setrlimit(__RLIMIT_MEMLOCK,local_8f8);
  data.length = 0x51e0;
  data.data_ptr = &DAT_002e5000;
  aya::bpf::Ebpf::load(&local_820,data);
  core::result::branch<>(&local_888,&local_820);
  if (local_888._0_8_ != -0x7ffffffffffffff7) {
                    /* WARNING: Subroutine does not return */
    memcpy(local_7b8,&local_888,0x68);
  }
                    /* WARNING: Subroutine does not return */
  memcpy(local_750,&local_888.field_0x8,0x60);
}


主体代码很少,但是其中有一些奇怪的部分:

1
2
  aya::bpf::Ebpf::load(&local_820,data);
  core::result::branch<>(&local_888,&local_820);

这是为了加载bpf代码,查看其加载的数据,发现了ELF开头的部分:

编写脚本提取相关的ELF代码并查看:

1
2
(venv13) woc@myarch:sunshine/warp $ file stage1.o
stage1.o: ELF 64-bit LSB relocatable, eBPF, version 1 (SYSV), with debug_info, not stripped

然而不能直接运行,因为这是eBPF llvm 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
/* ether header : 14B */

undefined8 xdp_prog(uint *packet_start)

{
  ulonglong uVar1;
  bool bVar2;
  ushort *data;
  ulonglong uVar3;
  longlong lVar4;
  byte data_char;
  ushort *puVar5;
  ushort *header_length;
  ushort local_21;
  byte local_1f;
  byte local_1e;
  ushort local_1d;
  byte local_1b;
  byte local_1a;
  ushort local_19;
  byte local_17;
  byte local_16;
  ushort local_15;
  byte local_13;
  byte local_12;
  ushort local_11;
  byte local_f;
  byte local_e;
  ushort local_d;
  byte local_b;
  byte local_a;
  ushort local_9;
  byte local_7;
  byte local_6;
  ushort local_5;
  
  header_length = (ushort *)(ulonglong)packet_start[1];
  uVar3 = (ulonglong)*packet_start;
  puVar5 = (ushort *)(uVar3 + 0xe);
  if (((puVar5 <= header_length) && ((ushort *)(uVar3 + 0x22) <= header_length)) &&
     (*(short *)(uVar3 + 0xc) == 8)) {
    uVar1 = (ulonglong)*(byte *)puVar5 & 0xf;
    if (0x13 < uVar1 * 4) {
                    /* TCP type */
      if (*(char *)(uVar3 + 0x17) == '\x06') {
        if (header_length < puVar5 + uVar1 * 2 + 10) {
          return 2;
        }
        uVar3 = (ulonglong)(puVar5[uVar1 * 2 + 6] >> 2) & 0x3c;
        puVar5 = (ushort *)((longlong)puVar5 + uVar3 + uVar1 * 4);
        if (uVar3 < 0x14) {
          return 2;
        }
      }
      else {
        if (*(char *)(uVar3 + 0x17) != '\x11') {
          return 2;
        }
        puVar5 = puVar5 + uVar1 * 2 + 4;
      }
                    /* Signature = 'W4rp' */
      if (((puVar5 + 2 <= header_length) &&
          (((ulonglong)*(byte *)((longlong)puVar5 + 3) << 0x18 | (ulonglong)(byte)puVar5[1] << 0x10
           | (ulonglong)*puVar5) == L'\x70723457')) &&
         (data = (ushort *)bpf_ringbuf_reserve(rb,0x21,0), data != (ushort *)0x0)) {
        if ((((((puVar5 + 2 < header_length) &&
               (*(byte *)data = (byte)puVar5[2], (ushort *)((longlong)puVar5 + 5) < header_length))
              && (((*(byte *)((longlong)data + 1) = *(byte *)((longlong)puVar5 + 5),
                   puVar5 + 3 < header_length &&
                   ((((*(byte *)(data + 1) = (byte)puVar5[3],
                      (ushort *)((longlong)puVar5 + 7) < header_length &&
                      (*(byte *)((longlong)data + 3) = *(byte *)((longlong)puVar5 + 7),
                      puVar5 + 4 < header_length)) &&
                     (*(byte *)(data + 2) = (byte)puVar5[4],
                     (ushort *)((longlong)puVar5 + 9) < header_length)) &&
                    ((*(byte *)((longlong)data + 5) = *(byte *)((longlong)puVar5 + 9),
                     puVar5 + 5 < header_length &&
                     (*(byte *)(data + 3) = (byte)puVar5[5],
                     (ushort *)((longlong)puVar5 + 0xb) < header_length)))))) &&
                  (*(byte *)((longlong)data + 7) = *(byte *)((longlong)puVar5 + 0xb),
                  puVar5 + 6 < header_length)))) &&
             ((*(byte *)(data + 4) = (byte)puVar5[6],
              (ushort *)((longlong)puVar5 + 0xd) < header_length &&
              (*(byte *)((longlong)data + 9) = *(byte *)((longlong)puVar5 + 0xd),
              puVar5 + 7 < header_length)))) &&
            (((*(byte *)(data + 5) = (byte)puVar5[7],
              (ushort *)((longlong)puVar5 + 0xf) < header_length &&
              (((*(byte *)((longlong)data + 0xb) = *(byte *)((longlong)puVar5 + 0xf),
                puVar5 + 8 < header_length &&
                (*(byte *)(data + 6) = (byte)puVar5[8],
                (ushort *)((longlong)puVar5 + 0x11) < header_length)) &&
               (*(byte *)((longlong)data + 0xd) = *(byte *)((longlong)puVar5 + 0x11),
               puVar5 + 9 < header_length)))) &&
             (((((*(byte *)(data + 7) = (byte)puVar5[9],
                 (ushort *)((longlong)puVar5 + 0x13) < header_length &&
                 (*(byte *)((longlong)data + 0xf) = *(byte *)((longlong)puVar5 + 0x13),
                 puVar5 + 10 < header_length)) &&
                (*(byte *)(data + 8) = (byte)puVar5[10],
                (ushort *)((longlong)puVar5 + 0x15) < header_length)) &&
               ((*(byte *)((longlong)data + 0x11) = *(byte *)((longlong)puVar5 + 0x15),
                puVar5 + 0xb < header_length &&
                (*(byte *)(data + 9) = (byte)puVar5[0xb],
                (ushort *)((longlong)puVar5 + 0x17) < header_length)))) &&
              ((*(byte *)((longlong)data + 0x13) = *(byte *)((longlong)puVar5 + 0x17),
               puVar5 + 0xc < header_length &&
               (((*(byte *)(data + 10) = (byte)puVar5[0xc],
                 (ushort *)((longlong)puVar5 + 0x19) < header_length &&
                 (*(byte *)((longlong)data + 0x15) = *(byte *)((longlong)puVar5 + 0x19),
                 puVar5 + 0xd < header_length)) &&
                (*(byte *)(data + 0xb) = (byte)puVar5[0xd],
                (ushort *)((longlong)puVar5 + 0x1b) < header_length)))))))))) &&
           (((*(byte *)((longlong)data + 0x17) = *(byte *)((longlong)puVar5 + 0x1b),
             puVar5 + 0xe < header_length &&
             (*(byte *)(data + 0xc) = (byte)puVar5[0xe],
             (ushort *)((longlong)puVar5 + 0x1d) < header_length)) &&
            ((*(byte *)((longlong)data + 0x19) = *(byte *)((longlong)puVar5 + 0x1d),
             puVar5 + 0xf < header_length &&
             (((*(byte *)(data + 0xd) = (byte)puVar5[0xf],
               (ushort *)((longlong)puVar5 + 0x1f) < header_length &&
               (*(byte *)((longlong)data + 0x1b) = *(byte *)((longlong)puVar5 + 0x1f),
               puVar5 + 0x10 < header_length)) &&
              ((*(byte *)(data + 0xe) = (byte)puVar5[0x10],
               (ushort *)((longlong)puVar5 + 0x21) < header_length &&
               (*(byte *)((longlong)data + 0x1d) = *(byte *)((longlong)puVar5 + 0x21),
               puVar5 + 0x11 < header_length)))))))))) {
          *(byte *)(data + 0xf) = (byte)puVar5[0x11];
          if ((ushort *)((longlong)puVar5 + 0x23) < header_length) {
            *(byte *)((longlong)data + 0x1f) = *(byte *)((longlong)puVar5 + 0x23);
          }
        }
        lVar4 = 0;
        do {
          data_char = *(byte *)(lVar4 + 0x70723457) ^ 0x60;
          if (0x20 < (longlong)(char)data_char) {
            data_char = (char)(((longlong)(char)data_char + 0xeU & 0xffffffff) % 0x5e) + 0x21;
          }
          *(byte *)((longlong)&local_21 + lVar4) = data_char;
          lVar4 = lVar4 + 1;
        } while (lVar4 != 0x1e);
        if (((((((ulonglong)*(byte *)((longlong)data + 7) << 0x18 | (ulonglong)(byte)data[3] << 0x10
                | (ulonglong)data[2]) << 0x20 |
               (ulonglong)*(byte *)((longlong)data + 3) << 0x18 | (ulonglong)(byte)data[1] << 0x10 |
               (ulonglong)*data) !=
               (((ulonglong)local_1a << 0x18 | (ulonglong)local_1b << 0x10 | (ulonglong)local_1d) <<
                0x20 | (ulonglong)local_1e << 0x18 | (ulonglong)local_1f << 0x10 |
                       (ulonglong)local_21)) ||
             ((((ulonglong)*(byte *)((longlong)data + 0xf) << 0x18 |
                (ulonglong)(byte)data[7] << 0x10 | (ulonglong)data[6]) << 0x20 |
              (ulonglong)*(byte *)((longlong)data + 0xb) << 0x18 | (ulonglong)(byte)data[5] << 0x10
              | (ulonglong)data[4]) !=
              (((ulonglong)local_12 << 0x18 | (ulonglong)local_13 << 0x10 | (ulonglong)local_15) <<
               0x20 | (ulonglong)local_16 << 0x18 | (ulonglong)local_17 << 0x10 |
                      (ulonglong)local_19))) ||
            ((((ulonglong)*(byte *)((longlong)data + 0x17) << 0x18 |
               (ulonglong)(byte)data[0xb] << 0x10 | (ulonglong)data[10]) << 0x20 |
             (ulonglong)*(byte *)((longlong)data + 0x13) << 0x18 | (ulonglong)(byte)data[9] << 0x10
             | (ulonglong)data[8]) !=
             (((ulonglong)local_a << 0x18 | (ulonglong)local_b << 0x10 | (ulonglong)local_d) << 0x20
             | (ulonglong)local_e << 0x18 | (ulonglong)local_f << 0x10 | (ulonglong)local_11))) ||
           ((((ulonglong)*(byte *)((longlong)data + 0x1b) << 0x18 |
              (ulonglong)(byte)data[0xd] << 0x10 | (ulonglong)data[0xc]) !=
             ((ulonglong)local_6 << 0x18 | (ulonglong)local_7 << 0x10 | (ulonglong)local_9) ||
            (bVar2 = false, data[0xe] != local_5)))) {
          bVar2 = true;
        }
        *(bool *)(data + 0x10) = !bVar2;
        bpf_ringbuf_submit(data,0);
      }
    }
  }
  return 2;
}

其中大部分代码都是对packet进行解析,真正有用的在最后(着重看其中存在“比较”的逻辑,这里是连续的!=),这里看似字节比较是不连续的,其实只是反汇编后的变量编号问题。

bpf程序的数据很多在map中存储,可以用bpftool查看。 先运行程序,然后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(venv13) woc@myarch:sunshine/warp $ sudo bpftool map show
11: hash_of_maps  name cgroup_hash  flags 0x0
        key 8B  value 4B  max_entries 2048  memlock 165920B
        pids systemd(1)
19: array  name .rodata  flags 0x80
        key 4B  value 46B  max_entries 1  memlock 312B
        frozen
        pids warp(164315)
20: ringbuf  name rb  flags 0x0
        key 0B  value 0B  max_entries 4096  memlock 16680B
        pids warp(164315)
22: array  name libbpf_global  flags 0x0
        key 4B  value 32B  max_entries 1  memlock 296B
23: array  name pid_iter.rodata  flags 0x480
        key 4B  value 4B  max_entries 1  memlock 8192B
        btf_id 265  frozen
        pids bpftool(164377)
24: array  name libbpf_det_bind  flags 0x0
        key 4B  value 32B  max_entries 1  memlock 296B

可以看到已经出现了和warp有关的map

1
2
3
4
5
6
7
8
(venv13) woc@myarch:sunshine/warp $ sudo bpftool map dump id 19
key:
00 00 00 00
value:
57 34 72 70 00 00 00 00  00 00 00 00 00 00 00 00
24 26 5f 2c 5f 3f 5f 50  58 21 00 50 11 41 15 50
54 20 55 56 50 58 3f 50  53 23 23 23 23 2e
Found 1 element

[TODO]能否不借助bpftool直接找出程序数据存放的位置?

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