Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
lazenca0x0@ubuntu:~/Documents/CTF/SECCON2017$ file ./Lazenca.0x0 
./Lazenca.0x0: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=1bfd795acede916210985e5865d2de9697e7505a, stripped
lazenca0x0@ubuntu:~/Documents/CTF/SECCON2017$ checksec.sh --file ./Lazenca.0x0 
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
Partial RELRO   Canary found      NX enabled    No PIE          No RPATH   No RUNPATH   ./Lazenca.0x0
lazenca0x0@ubuntu:~/Documents/CTF/SECCON2017$ 

Binary analysis (Finding vulnerabilities)

Struct

Code Block
typedef struct ORDER{
    char orderCode[8];
    unsigned int  orderNumber;
    char orderCandyName[8];
    int  candyCode;
};

typedef struct CANDIES {
    char candyName[8];
    unsigned int  orderNumber;
    int candyCode;
};

...

  • 해당 함수는 다음과 같은 기능을 합니다.

    • 해당 함수는 전역 변수 gAccount[].state 의 값이 '0' 인 경우 다음과 같이 동작합니다.

      • 해당 함수는 malloc()을 사용하여 128 byte의 heap 영역을 할당받습니다.

        • 해당 함수는 해당 영역의 주소를 gAccount[i].fd에 저장합니다.

        • 해당 함수는 해당 영역에 ID, Password, 등의 정보를 profile 정보를 저장합니다.
Code Block
languagecpp
titleaddAccount(unsigned int a1)
unsigned __int64 __fastcall addAccount(unsigned int a1)
{
  unsigned int i; // [rsp+10h] [rbp-10h]
  signed int empty; // [rsp+14h] [rbp-Ch]
  unsigned __int64 v4; // [rsp+18h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  empty = 1;
  for ( i = 0; i <= 2 && empty; ++i )
  {
    if ( !gAccount[i].state )
    {
      empty = 0;
      gAccount[i].state = a1;
      gAccount[i].number = i + 1;
      gAccount[i].fd = (struct IDPW *)malloc(128uLL);
      gAccount[i].fd->state = 1LL;
      puts("\nEnter your New ID.");
      UserInput(gAccount[i].fd->id, 8LL);
      puts("Enter your New Password.");
      UserInput(gAccount[i].fd->pw, 8LL);
      puts("Enter your profile.");
      UserInput(gAccount[i].fd->description, 88LL);
      gAccount[i].bk = 10000LL;
    }
  }
  if ( empty )
    puts("Could not add user.");
  return __readfsqword(0x28u) ^ v4;
}

...

Code Block
languagecpp
titledelAccount()
unsigned __int64 delAccount()
{
  unsigned int i; // [rsp+8h] [rbp-18h]
  unsigned int num; // [rsp+Ch] [rbp-14h] MAPDST
  unsigned __int64 v4; // [rsp+18h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  puts("\nAccount list");
  for ( i = 0; i <= 2; ++i )
  {
    if ( gAccount[i].state )
      printf("%d) %s\n", gAccount[i].number, gAccount[i].fd->id);
  }
  puts("\nPlease enter the number of the account you want to delete");
  num = retNumber(2LL);
  if ( num && num <= 3 )
  {
    if ( gAccount[--num].state == 3 )
    {
      gAccount[num].state = 0LL;
      gAccount[num].fd->state = 0LL;
      printf("The account(%s) has been deleted.\n", gAccount[num].fd->id);
      memset(gAccount[num].fd, 0, 0x80uLL);
      free(gAccount[num].fd);
      gAccount[num].fd = (struct IDPW *)((char *)gAccount[num].fd - 16);
    }
    else
    {
      puts("You can not delete the account.");
    }
  }
  return __readfsqword(0x28u) ^ v4;
}

Proof of concept

Struct ACCOUNT


  • 해당 프로그램에서 취약성을 이해하기 위해 ACCOUNT 구조체에 대한 이해가 필요합니다.
    • 해당 프로그램은 3개의 ACCOUNT 구조체를 사용합니다.
    • 해당 구조체는 전역 변수로 선언되어 있습니다.
Panel
0x604240gAccount[0].stategAccount[0].number
0x604240gAccount[0].fdgAccount[0].bk
0x604240gAccount[1].stategAccount[1].number
0x604240gAccount[1].fdgAccount[1].bk
0x604240gAccount[2].stategAccount[2].number
0x604240gAccount[2].fdgAccount[2].bk
  • 다음과 같이 House of lore 취약성에 필요한 Fake chunk를 생성할 수 있습니다.
  • 해당 프로그램은 delAccount() 함수를 이용해 gAccount[*].fd 영역에 Free chunk의 Head 주소를 저장 할 수 있습니다.
Code Block
struct ACCOUNT{
    long state;
    long number;
    struct IDPW *fd;
    long bk;
};



changePW

  • 해당 함수는 다음과 같은 기능을 합니다.

    • 해당 함수는 전역 변수 "gAccount[i].state"를 이용해 비밀번호 변경이 가능한 계정을 출력합니다.

    • 해당 함수는 사용자로 부터 비밀번호를 변경할 계정의 번호를 입력 받습니다.

    • 해당 함수는 해당 계정의 '.fd.state' 영역에 저장된 값이 '0'이 아닐 경우 비밀번호를 변경할 수 있습니다.

...