Posts for: #CTF

TokyoWesternsCTF2019 gnote


Problem

Environment

  • linux version: 4.19.65
  • mmap_min_addr: 0x1000
  • No SMAP

Module

      typedef struct request_t {
  uint32_t cmd;
  uint32_t arg;
} request_t;

int64_t gnote_write(struct file *a1, const request_t *req, size_t a3,
                    loff_t *a4) {
  uint64_t len;
  note_data_t *req;
  void *new_note_data;

  mutex_lock(&lock);
  switch (req->cmd) {
    case 1:
      if ((uint64_t)cnt <= 7) {
        len = (uint32_t)req->arg;
        cur_note = &notes[cnt];
        cur_note->len = len;
        if (len <= 0x10000) {
          new_note_data = kmalloc(len, 0x6000C0LL);
          ++cnt;
          cur_note->data = new_note_data;
        }
      }
      break;
    case 2:
      printk("Edit Not implemented\n");
      break;
    case 3:
      printk("Delete Not implemented\n");
      break;
    case 4:
      printk("Copy Not implemented\n");
      break;
    case 5:
      if ((uint32_t)req->arg < (uint64_t)cnt) selected = (uint32_t)req->arg;
      break;
    default:
      break;
  }
  mutex_unlock(&lock);
  return a3;
}

uint64_t gnote_read(struct file *a1, char *a2, size_t len, loff_t *a4) {
  note_data_t *cur_note;

  mutex_lock(&lock);
  if (selected == -1) {
    mutex_unlock(&lock);
    return 0LL;
  } else {
    cur_note = &notes[selected];
    if (cur_note->len <= len) len = cur_note->len;
    copy_to_user(a2, cur_note->data, len);
    selected = -1LL;
    mutex_unlock(&lock);
    return len;
  }
}

The gnote module has just 3 features: add new note, select note and get note’s content. But with these features, we cannot write content to note (Edit is not implemented…).

Read more →

TokyoWesternsCTF2020 eebpf


Problem

Environment

  • kernel version: 5.4.58
  • unprivileged_bpf_disabled: 0

Patch file

The important part is following:

      diff -r ./buildroot-2020.08-rc3/output/build/linux-5.4.58/include/uapi/linux/bpf.h buildroot-2020.08-rc3_original/output/build/linux-5.4.58/include/uapi/linux/bpf.h
27d26
< #define BPF_ALSH	0xe0	/* sign extending arithmetic shift left */
diff -r ./buildroot-2020.08-rc3/output/build/linux-5.4.58/kernel/bpf/tnum.c buildroot-2020.08-rc3_original/output/build/linux-5.4.58/kernel/bpf/tnum.c
42,52d41
< struct tnum tnum_alshift(struct tnum a, u8 min_shift, u8 insn_bitness)
< {
< 	if (insn_bitness == 32)
< 		//Never reach here now.
< 		return TNUM((u32)(((s32)a.value) << min_shift),
< 			    (u32)(((s32)a.mask)  << min_shift));
< 	else
< 		return TNUM((s64)a.value << min_shift,
< 			    (s64)a.mask  << min_shift);
< }
< 
diff -r ./buildroot-2020.08-rc3/output/build/linux-5.4.58/kernel/bpf/verifier.c buildroot-2020.08-rc3_original/output/build/linux-5.4.58/kernel/bpf/verifier.c
4867,4897d4866
< 	case BPF_ALSH:
< 		if (umax_val >= insn_bitness) {
< 			/* Shifts greater than 31 or 63 are undefined.
< 			 * This includes shifts by a negative number.
< 			 */
< 			mark_reg_unknown(env, regs, insn->dst_reg);
< 			break;
< 		}
< 
< 		/* Upon reaching here, src_known is true and
< 		 * umax_val is equal to umin_val.
< 		 */
< 		if (insn_bitness == 32) {
< 			//Now we don't support 32bit. Cuz im too lazy.
< 			mark_reg_unknown(env, regs, insn->dst_reg);
< 			break;
< 		} else {
< 			dst_reg->smin_value <<= umin_val;
< 			dst_reg->smax_value <<= umin_val;
< 		}
< 
< 		dst_reg->var_off = tnum_alshift(dst_reg->var_off, umin_val,
< 						insn_bitness);
< 
< 		/* blow away the dst_reg umin_value/umax_value and rely on
< 		 * dst_reg var_off to refine the result.
< 		 */
< 		dst_reg->umin_value = 0;
< 		dst_reg->umax_value = U64_MAX;
< 		__update_reg_bounds(dst_reg);
< 		break;

And related location is following:

Read more →

BalsnCTF2019 Krazynote


Problem

Environment

  • kernel version: 5.1.9

Features

This challenge provide note misc device with which we can save(0xffffff00) and get(0xffffff02), update(0xffffff01) data using unlocked_ioctl. When we save and get, update data on it, the xor-encrypted data is stored.

And the struct enc_data (stored data) and struct request_t is following:

typedef struct request_t {
  uint64_t idx;
  uint64_t size;
  uint64_t data;
} request_t;

typedef struct enc_data_t {
  uint64_t xor_key;
  uint64_t size;
  uint64_t data_addr_minus_page_offset_base;
  char enc_data[0]; // Struct Hack; see https://www.geeksforgeeks.org/struct-hack/
} enc_data_t;

Vulnerability

Since unlocked_ioctl does not perform blocked-ioctl and the device does not use mutex, we can do race condition attack easily. Furthermore in given kernel environment, non-privileged userfaultfd is allowed.

Read more →