You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
if (ip < map->first_ip || ip > map->last_ip) // [1]
15
+
return -IPSET_ERR_BITMAP_RANGE;
14
16
...
15
17
if (tb[IPSET_ATTR_IP_TO]) {
16
18
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
17
19
if (ret)
18
20
return ret;
19
21
if (ip > ip_to) {
20
22
swap(ip, ip_to);
21
-
if (ip < map->first_ip) // [1]
23
+
if (ip < map->first_ip) // [2]
22
24
return -IPSET_ERR_BITMAP_RANGE;
23
25
}
24
26
} else if (tb[IPSET_ATTR_CIDR]) {
25
27
u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
26
28
...
27
-
ip_set_mask_from_to(ip, ip_to, cidr); // [2]
29
+
ip_set_mask_from_to(ip, ip_to, cidr); // [3]
28
30
} else {
29
31
ip_to = ip;
30
32
}
31
33
32
-
if (ip_to > map->last_ip) // [3]
34
+
if (ip_to > map->last_ip) // [4]
33
35
return -IPSET_ERR_BITMAP_RANGE;
34
36
35
-
for (; !before(ip_to, ip); ip += map->hosts) { // [4]
37
+
for (; !before(ip_to, ip); ip += map->hosts) { // [5]
36
38
e.id = ip_to_id(map, ip);
37
39
ret = adtfn(set, &e, &ext, &ext, flags);
38
40
```
39
41
40
-
When `tb[IPSET_ATTR_IP_TO]` is not present but `tb[IPSET_ATTR_CIDR]` exists, `ip` and `ip_to` calculated via `ip_set_mask_from_to` based on `tb[IPSET_ATTR_CIDR]`. It's possible to have `ip` less than the actual `map->first_ip` and there's no check of `ip` after that. Therefore, the loop at [4] can proceed outside range ip that allocated (`map->first_ip` until `map->last_ip`).
42
+
When `tb[IPSET_ATTR_IP_TO]` is not present but `tb[IPSET_ATTR_CIDR]` exists, `ip` and `ip_to` calculated via `ip_set_mask_from_to` based on `tb[IPSET_ATTR_CIDR]`. It's possible to have `ip` less than the actual `map->first_ip` and there's no check of `ip` after that.
41
43
44
+
Consider when we have `map->first_ip` to be `0xffffffcb` and `map->last_ip` be `0xffffffff`, then we pass `IPSET_ATTR_IP` with value `0xffffffff` and `IPSET_ATTR_CIDR` with `3`, the result after [3] will make `ip` equal to `0xe0000000` and `ip_to` equal to `0xffffffff`, it would pass the check at [1], [4] and continue proceed to [5]. Therefore, the loop at [5] can proceed outside range ip that allocated (`map->first_ip` until `map->last_ip`).
42
45
43
46
# Primitives
44
-
## OOB Write to Kernel Heap Leak
45
47
46
-
`adtfn` will resolve to `bitmap_ip_add` function (defined as `mtype_add` in `net/netfilter/ipset/ip_set_bitmap_gen.h`). It will fetch extension `x` from `map->extensions` with `e.id` as index.
48
+
`adtfn` will resolve to `bitmap_ip_add` function (defined as `mtype_add` in `net/netfilter/ipset/ip_set_bitmap_gen.h`, mtype is just macro to `bitmap_ip`). It will fetch extension `x` from `map.extensions` with `e.id` as index.
We also can control the size of map (`bitmap_ip` type) by passing `first_ip` and `last_ip` when we initially create the ip set.
67
71
72
+
## OOB Write to Kernel Heap Leak
68
73
By crafting `e.id` it can lead OOB write, for example when we set the comment in sets, it can spill the kernel heap address in the next chunk because `comment` in `ip_set_init_comment` is outside the range.
This is the path that we used to leak kernel heap addr, by shaping heap to `..[skbuff][bitmap_ip][skbuff][skbuff]..` the OOB write of kernel addr will spilled to the next chunk which is socket buffer. By receiving socket buffer, it can contain kernel heap address so we can use it for the next step exploitation.
95
+
This is the path that we used to leak kernel heap addr, by shaping heap to `..[skbuff][bitmap_ip][skbuff][skbuff]..` the OOB write of kernel addr will spilled to the next chunk which is socket buffer.
96
+
97
+
In our exploit we choose to work on kmalloc-cg-1024 in this step, we allocate `bitmap_ip` and spray socket buffer at kmalloc-cg-1024. `ip_set_init_comment` will spilled kernel heap addr from kmalloc-192 to the socket buffer.
98
+
99
+
By receiving socket buffer, we can get kernel heap address to use it for the next step exploitation.
91
100
92
101
## OOB Write Arbitrary Value
93
102
Another type of OOB that we can use is OOB write with arbitrary value. This works using set that contain `counter`.
The victim object (`struct bitmap_ip`) is allocated with `GFP_KERNEL_ACCOUNT` so it's guarantee can reside in the same slab cache with `msg_msgseg` object. So we put `bitmap_ip` right before `msg_msgseg`, then perform OOB write so we can write arbitrary value on `msg_msgseg.next`.
139
147
140
-
By using arbitrary free, we choose `pipe_buffer` as another victim object because it's familiar for us and easy to plan for the next step of exploit. But the kernel heap leak primitives we had only allocate buffer on generic kernel cache, so we kind of guess a little bit to get `pipe_buffer` address that located in account cache. Basically, from our observation we can calculate `leak_addr ~(0x10000000 - 1)` with `leak_addr` as kernel heap addr leaked from kmalloc-192 chunk, we can guess `pipe_buffer` in confident probability.
148
+
In this step choose to work on kmalloc-cg-2048, we allocate `bitmap_ip` and spray `msg_msgseg` at kmalloc-cg-2048. The victim object (`struct bitmap_ip`) is allocated with `GFP_KERNEL_ACCOUNT` so it's guarantee can reside in the same slab cache with `msg_msgseg` object. So we put `bitmap_ip` right before `msg_msgseg`, then perform OOB write so we can write arbitrary value on `msg_msgseg.next`.
149
+
150
+
By using arbitrary free, we choose `pipe_buffer` as another victim object because it's familiar for us and easy to plan for the next step of exploit. But the kernel heap leak primitives we had only allocate buffer on generic kernel cache (kmalloc-192), so we kind of guess a little bit to get `pipe_buffer` address that located in account cache. Basically, from our observation we can calculate `leak_addr ~(0x10000000 - 1)` with `leak_addr` as kernel heap addr leaked from kmalloc-192 chunk, we can guess `pipe_buffer` in confident probability.
141
151
142
152
## Use-After-Free to Control RIP
143
153
In this step, we already free `pipe_buffer` by arbitrary free. Next, we reclaim victim `pipe_buffer` using socket buffer. We spray socket buffer and hope it placed at same address as `pipe_buffer`. Then, we write to the pipe and it will filled one of our socket buffer with `pipe_buffer` content.
@@ -148,7 +158,7 @@ Controlling RIP, we simply free the that socket buffer and reallocate with new o
148
158
149
159
# Control RIP to ROP Chain
150
160
We reached this code path where we control all fields in `pipe_buffer`.
0 commit comments