cakectf 2021 hwdbg writeup

  • ~2.99K Words
  1. 1. cakectf 2021 hwdbg
    1. 1.1. chall
    2. 1.2. solve
      1. 1.2.1. 問題の解析
      2. 1.2.2. 特権昇格の方法
      3. 1.2.3. 準備

cakectf 2021 hwdbg

chall

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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

void print_usage(char *progname)
{
puts("Hardware (I/O port) debugging utility\n");
printf("Usage: %s mr|mw|ior|iow <size> <offset>\n", progname);
exit(1);
}

int mem_read(off_t _offset, size_t _size)
{
fputs("mem_read: Not implemented\n", stderr);
return -1;
}

int mem_write(off_t offset, size_t size)
{
char buf[0x1000];
int fd = open("/dev/mem", O_RDWR|O_SYNC);
if (fd == -1) {
perror("/dev/mem");
return -1;
}

lseek(fd, offset, SEEK_SET);
for (size_t i = 0; i < size; i += 0x1000) {
ssize_t nb = read(0, buf, 0x1000);
if (nb <= 0) break;
write(fd, buf, i + 0x1000 <= size ? nb : size % 0x1000);
}

close(fd);
}

int io_read(size_t size) {
fputs("io_read: Not implemented\n", stderr);
return -1;
}

int io_write(size_t size) {
fputs("io_write: Not implemented\n", stderr);
return -1;
}

int main(int argc, char **argv)
{
if (argc < 4)
print_usage(argv[0]);

size_t size = strtoll(argv[2], NULL, 16);
off_t offset = strtoll(argv[3], NULL, 16);

if (strcmp(argv[1], "mr") == 0) {
/* Memory read for hardware operation */
return mem_read(offset, size);

} else if (strcmp(argv[1], "mw") == 0) {
/* Memory write for hardware operation */
return mem_write(offset, size);

} else if (strcmp(argv[1], "ior") == 0) {
/* Input from hardware I/O port */
return io_read(size);

} else if (strcmp(argv[1], "iow") == 0) {
/* Output to hardware I/O port */
return io_write(size);

} else {
print_usage(argv[0]);
}
}

solve

問題の解析

実装されている内容は、Hardware (I/O port) debugging utilityという形で物理メモリへのmem writeのみが実装されています。これを使って特権を得ることが問題です。

特権昇格の方法

セキュリティは何もない状態の想定では、以下が簡単なものらしい…(ほかにもあるらしいがあんま分かってない)

  1. modprobe_path/core_patternの上書き
  2. commit_creds(prepare_kernel_cred(0))の実行
  3. cred structureの上書き

今回は、物理メモリを任意に書き換えできるので、1がよさそうです。

とはいっても、modprobe_pathは/sbin/modprobe_pathの書き換えで、core_patternはcoreの書き換えです。

今回は/sbin/modprobe_pathの書き換えをしてみることに…

準備

/sbin/modprobe_pathの書き換えに必要なのは、AAWとこれが存在するアドレスです。

AAWは問題で渡されているのですでに解決しています。アドレス側は、手元でどうにかして知る必要があります。

root権限で\dev\memの中はみれるので*dd if=/dev/mem of=kernel_data.bin bs=1M skip=30 count=1*で物理メモリの内容をkernel_data.binに保存して/sbin/modprobeを探す形でアドレスを特定しました。

あとは、そのアドレスにこちら側が用意したファイルを適当なfile((/tmp/hogehogee))を実行することで、書き換えた先のfile(/tmp/a)を実行してもらえれば終わりです。

e.g./tmp/hogehogee: #!/bin/sh\ncat /flag.txt > /tmp/flag\n

e.g./tmp/a: '\xff\xff\xff\xff'

これで、/tmp/flagにflagが記載されるのでこれを読めば勝ちです。

CakeCTF{phys1c4l_4ddr3ss_1s_th3_m0st_h0n3st_4ddr3ss_083f63}

知らないことが多すぎて勉強になった…