0ctf 2019 zero_task

一个条件竞争的洞,以前没有接触过。比赛完研究了wp复现下。

new_thread结构体如下

new_thread:
thread_area        size0x8
thread_area+0x8    size    0x8
thread_area+0x10    choice    
thread_area+0x14    key    0x20
thread_area+0x34    IV    0x10
...
thread_area+0x60    task_id
thread_area+0x68    thread_binlist
thread_area+0x88    EVP_CIPHER_CTX_new

delete中并没有uaf的问题

void delete(void)

{
  void **__ptr;
  int task_id;
  void **local_18;
  void **local_10;
  
  __ptr = DAT_00302028;
  local_18 = DAT_00302028;
  local_10 = DAT_00302028;
  printf("Task id : ");
  task_id = my_read8();
  if ((DAT_00302028 == (void **)0x0) || (task_id != *(int *)(DAT_00302028 + 0xc))) {
    while (local_18 != (void **)0x0) {
      if (task_id == *(int *)(local_18 + 0xc)) {
        local_10[0xd] = local_18[0xd];
        EVP_CIPHER_CTX_free((EVP_CIPHER_CTX *)local_18[0xb]);
        free(*local_18);
        free(local_18);
        return;
      }
      local_10 = local_18;
      local_18 = (void **)local_18[0xd];
    }
  }
  else {
    DAT_00302028 = (void **)DAT_00302028[0xd];
    EVP_CIPHER_CTX_free((EVP_CIPHER_CTX *)__ptr[0xb]);
    free(*__ptr);
                    /* 这里不存在uaf
                       00302028会存储线程链的值,在释放前会判断这个值是否为空
                        */
    free(__ptr);
  }
  return;
}

存在的问题是创建新线程执行start_routine时的条件竞争(这里产生条件竞争的原因是子线程会共享主线程的bss段,在创建子线程时sleep(2)后再更新bss段的数据)

void start_routine(uchar **ppuParm1)

{
  int iVar1;
  long in_FS_OFFSET;
  int local_34;
  uchar **local_30;
  ulong local_28;
  undefined8 local_20;
  undefined8 local_18;
  undefined8 local_10;
  
  local_10 = *(undefined8 *)(in_FS_OFFSET + 0x28);
  local_34 = 0;
  local_20 = 0;
  local_18 = 0;
  local_28 = 0;
  local_30 = ppuParm1;
  puts("Prepare...");
  sleep(2);
  memset(DAT_00302030,0,0x1010);
  iVar1 = EVP_CipherUpdate((EVP_CIPHER_CTX *)local_30[0xb],DAT_00302030,&local_34,*local_30,
                           (int)local_30[1]);
  if (iVar1 == 0) {
                    /* WARNING: Subroutine does not return */
    pthread_exit((void *)0x0);
  }
  local_28 = local_28 + (long)local_34;
  iVar1 = EVP_CipherFinal_ex((EVP_CIPHER_CTX *)local_30[0xb],DAT_00302030 + local_28,&local_34);
  if (iVar1 == 0) {
                    /* WARNING: Subroutine does not return */
    pthread_exit((void *)0x0);
  }
  local_28 = local_28 + (long)local_34;
  puts("Ciphertext: ");
  my_printf(stdout,(long)DAT_00302030,local_28,0x10,1);
                    /* WARNING: Subroutine does not return */
  pthread_exit((void *)0x0);
}

神仙东西,思路大致看懂了tql,orz

总结一下学到的改变执行流的思路吧:条件竞争并不能写任意内存,程序也没有任意地址写的漏洞,这时可以尝试找一个相对地址的调用,如果这个相对地址可控,我们就可以改变执行流了

原文地址:https://www.cnblogs.com/snip3r/p/10609983.html