[pwnable.xyz] fishing - thread
Wargame/pwnable.xyz

[pwnable.xyz] fishing - thread

๐Ÿงก fishing ์„ค๋ช…

pwnable.xyz ๋ฌธ์ œ ์ค‘์— ์žฌ๋ฏธ์žˆ๊ฒŒ ํ‘ผ ๋ฌธ์ œ๊ฐ€ ์žˆ์–ด์„œ ์†Œ๊ฐœํ•ด๋ณด๋ ค๊ณ  ํ•œ๋‹ค. binary๋ฅผ ๋ด๋ณด๋„๋ก ํ•˜์ž.

undefined8 main(void)

{
  undefined4 uVar1;
  
  setup();
  banner();
  do {
    show_menu();
    uVar1 = read_int();
    switch(uVar1) {
    default:
      err("Invalid choice");
      break;
    case 1:
      add_group_member();
      break;
    case 2:
      modify_group_member();
      break;
    case 3:
      write_in_book();
      break;
    case 4:
      go_fishing();
      break;
    case 5:
      stop_fishing();
      break;
    case 6:
      puts("Bye. I\'m keeping the deposit");
      return 0;
    }
  } while( true );
}

main ํ•จ์ˆ˜๋Š” ์ด๋ ‡๊ฒŒ ์ƒ๊ฒผ๋‹ค.

void add_group_member(void)

{
  undefined4 uVar1;
  void **ppvVar2;
  void *pvVar3;
  
  if (group_size < 6) {
    ppvVar2 = (void **)malloc(0x20);
    pvVar3 = malloc(0x18);
    *ppvVar2 = pvVar3;
    __printf_chk(1,"Name: ");
    read_string(*ppvVar2,0x18);
    pvVar3 = malloc(0x18);
    ppvVar2[1] = pvVar3;
    __printf_chk(1,"Job: ");
    read_string(ppvVar2[1],0x18);
    __printf_chk(1,"Age: ");
    uVar1 = read_int();
    *(undefined4 *)(ppvVar2 + 2) = uVar1;
    *(void ***)(group + (long)group_size * 8) = ppvVar2;
    group_size = group_size + 1;
    return;
  }
  puts("You would sink the boat with that many people");
  return;

group member์„ ์ƒ์„ฑํ•˜๋Š” ํ•จ์ˆ˜๋‹ค. heap ๊ตฌ์กฐ๋Š” ๋Œ€์ถฉ ์ด๋ ‡๊ฒŒ ์ƒ๊ฒผ๋‹ค.

void modify_group_member(void)

{
  undefined8 *puVar1;
  uint uVar2;
  undefined4 uVar3;
  
  puts("Which person do you need to change?");
  uVar2 = read_int();
  if (5 < uVar2) {
    puts("A group member can only be 0-5");
    return;
  }
  puVar1 = *(undefined8 **)(group + (long)(int)uVar2 * 8);
  if (puVar1 != (undefined8 *)0x0) {
    __printf_chk(1,"Name: ");
    read_string(*puVar1,0x18);
    __printf_chk(1,"Job: ");
    read_string(puVar1[1],0x18);
    __printf_chk(1,"Age: ");
    uVar3 = read_int();
    *(undefined4 *)(puVar1 + 2) = uVar3;
    return;
  }
  puts("That person doesn\'t exist");
  return;
}

๋‹จ์ˆœํžˆ group member์˜ ์ •๋ณด๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ํ•จ์ˆ˜๋‹ค.

void write_in_book(void)

{
  void *pvVar1;
  
  puts("What do you want to say?");
  pvVar1 = malloc(0x20);
  read_string(pvVar1,0x20);
  return;
}

์•„๋ฌด๋Ÿฐ ์กฐ๊ฑด ์—†์ด 0x20 size๋ฅผ ๊ฐ€์ง„ heap์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

void go_fishing(void)

{
  long in_FS_OFFSET;
  pthread_t pStack24;
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  if (fishing == 0) {
    if (group_size < 2) {
      puts("You need 2 or more people to fish");
    }
    else {
      fishing = 1;
      pthread_create(&pStack24,(pthread_attr_t *)0x0,gone_fishing,(void *)0x0);
      puts("You\'re group has now left to catch some fish");
    }
  }
  else {
    puts("You\'re group is already fishing, wait until they come back");
  }
  if (local_10 == *(long *)(in_FS_OFFSET + 0x28)) {
    return;
  }
                    /* WARNING: Subroutine does not return */
  __stack_chk_fail();
}

 ์ด ๋ถ€๋ถ„์ด ์žฌ๋ฏธ์žˆ๋Š”๋ฐ, ์ผ๋‹จ ๋‚š์‹œ๋ฅผ ๊ฐ€๋ ค๋ฉด group size๊ฐ€ 2 ์ด์ƒ์ด์–ด์•ผ ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ , gone_fishing ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๋Š”๋ฐ ์ด ๋ถ€๋ถ„์—์„œ ์Šค๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. 

void remove_person(int param_1)

{
  void **__ptr;
  
  __ptr = *(void ***)(group + (long)param_1 * 8);
  if (__ptr != (void **)0x0) {
    free(*__ptr);
    free(__ptr[1]);
    free(__ptr);
    return;
  }
  return;
}
undefined8 gone_fishing(void)

{
  int iVar1;
  
  iVar1 = pthread_mutex_lock((pthread_mutex_t *)mutex);
  if (iVar1 != 0) {
    err("Fatal locking");
  }
  iVar1 = group_size + -1;
  puts("\n!!!!ALERT!!!");
  __printf_chk(1,"%s has fallen over board\n",**(undefined8 **)(group + (long)iVar1 * 8));
  puts("We are trying to save them");
  remove_person(iVar1);
  iVar1 = pthread_cond_wait((pthread_cond_t *)cond,(pthread_mutex_t *)mutex);
  if (iVar1 != 0) {
    err("Fatal");
  }
  puts("\nOk we are coming back. Btw they died...");
  group_size = group_size + -1;
  fishing = 0;
  iVar1 = pthread_mutex_unlock((pthread_mutex_t *)mutex);
  if (iVar1 != 0) {
    err("Fatal unlocking");
  }
  return 0;
}

 ์ด ํ•จ์ˆ˜๋Š” ์ด๋ ‡๊ฒŒ ์ƒ๊ฒผ๋‹ค. ์ผ๋‹จ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๋ฉด mutex๋ฅผ ์ด์šฉํ•ด ์Šค๋ ˆ๋“œ์— ๋ฝ์„ ๊ฑด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์•„์ฃผ ๋ถˆ์Œํ•˜๊ฒŒ๋„ ๋งˆ์ง€๋ง‰ ๊ทธ๋ฃน์— ์žˆ๋Š” ์‚ฌ๋žŒ์€ ๊ฐ‘ํŒ ๋ฐ‘์œผ๋กœ ๋–จ์–ด์ง€๊ฒŒ ๋œ๋‹ค ใ… ใ… .. ๋–จ์–ด์ง„ ๊ทธ๋ฃน์„ ์ธ์ž๋กœ ๊ฐ–๊ณ  remove_person์„ ์‹คํ–‰ํ•˜๋Š”๋ฐ ์ด ํ•จ์ˆ˜์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. 

 heap์„ ํ• ๋‹นํ•˜๋Š” ์ˆœ์„œ๋Š” name -> job ์ˆœ์„œ์ธ๋ฐ, ํ•ด๋‹น ํ•จ์ˆ˜์—์„œ๋Š” ๋ฐ˜๋Œ€๋กœ free ํ•œ๋‹ค. ๋˜ํ•œ ์ „์—ญ๋ณ€์ˆ˜์— ์žˆ๋Š” data์™€ heap์— ์žˆ๋Š” data๋ฅผ ์ง€์šฐ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— UAF๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

 ๊ทธ๋ฆฌ๊ณ  cond signal์ด ์˜ฌ ๋•Œ๊นŒ์ง€ ์Šค๋ ˆ๋“œ๋ฅผ ๋Œ€๊ธฐ ์ƒํƒœ๋กœ ์ „ํ™˜ํ•œ๋‹ค.

void stop_fishing(void)

{
  int iVar1;
  
  if (fishing == 0) {
    puts("You\'re group is not fishing");
    return;
  }
  iVar1 = pthread_cond_signal((pthread_cond_t *)cond);
  if (iVar1 == 0) {
    return;
  }
  err("Fatal signaling");
  return;
}

์ด ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๋ฉด cond signal์„ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.

 

๐Ÿงก Attack Vector

์œ„์—์„œ ๋งํ–ˆ๋‹ค ์‹ถ์ด UAF๋ฅผ ์ด์šฉํ•ด์„œ heap์„ ์กฐ์ž‘ํ•˜๋ฉด ๋œ๋‹ค. ์ ๋‹นํžˆ ๋งŒ์ ธ์ฃผ๊ณ  heap_base, pie_base๋ฅผ leakํ•œ ๋‹ค์Œ์— GOT overwrite๋กœ win ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•ด์ฃผ๋ฉด ๋๋‚œ๋‹ค. 

'Wargame > pwnable.xyz' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[pwnable.xyz] All Clear  (0) 2021.07.17
[pwnable.xyz] Heap - House of Force ๋ณต์Šต (note v3)  (2) 2021.07.09
[pwnable.xyz] executioner v2 ์‚ฝ์งˆ  (2) 2021.07.03
[pwnable.xyz] executioner trick(?)  (2) 2021.07.01
[pwnable.xyz] Free spirit trick ์†Œ๊ฐœ  (2) 2021.06.26