Versions Compared

Key

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

...

  • 当該関数は次のような機能をします。
    • 当該関数はsetCandy()関数を呼び出してCandy情報を設定します。
    • 当該関数はlogin()関数を呼び出しして使用してアカウント情報を確認します。
    • 当該関数は使用者がloginに失敗する場合、次のように動作します。
      • 当該関数はloginが失敗の際の使用者にアカウントを生成することか問いかけます。
        • 当該関数はaddAccount()関数を利用して新しいアカウントを生成します。
      • また、当該関数はloginを3度失敗するとプログラムは終了されます。
    • 当該関数は使用者がloginに成功すると、下の機能を利用することができます。
      • 向上出力、注文、充電、ログアウト個数表示、注文、チャージ、ログアウト
      • gLoginAccount→stateの値が1の場合"orderMenu"、"Account"機能を利用することができます

...

  • 当該関数は次のような機能をします。
    • 当該関数は使用者からID、Passwordの入力を受けます。
    • 当該関数は入力を受けた値を全域変数gAccount[]に存在するかどうか確認します。
    • 当該関数は認証に成功すると、該当アカウント情報が保存されたgAccount[]の住所を全域の変数の アドレスを全域の変数"gLoginAccount"に保存します。
Code Block
languagecpp
titlelogin()
signed __int64 login()
{
  size_t lenUserInputID; // rbx
  size_t lenID; // rax
  size_t lenUserInputPW; // rbx
  size_t lenPW; // rax
  signed int i; // [rsp+Ch] [rbp-34h]
  char id[8]; // [rsp+10h] [rbp-30h]
  char pw[8]; // [rsp+20h] [rbp-20h]
  unsigned __int64 v8; // [rsp+28h] [rbp-18h]

  v8 = __readfsqword(0x28u);
  memset(id, 0, 8uLL);
  memset(pw, 0, 8uLL);
  printf("\nEnter your ID.\n> ", 0LL);
  UserInput(id, 8LL);
  printf("Enter your Password.\n> ", 8LL);
  UserInput(pw, 8LL);
  for ( i = 0; i <= 2; ++i )
  {
    if ( gAccount[i].state )
    {
      lenUserInputID = strlen(id);
      if ( lenUserInputID == strlen(gAccount[i].fd->id) )
      {
        lenID = strlen(gAccount[i].fd->id);
        if ( !strncmp(gAccount[i].fd->id, id, lenID) )
        {
          lenUserInputPW = strlen(pw);
          if ( lenUserInputPW == strlen(gAccount[i].fd->pw) )
          {
            lenPW = strlen(gAccount[i].fd->pw);
            if ( !strncmp(gAccount[i].fd->pw, pw, lenPW) )
            {
              gLoginAccount = (struct ACCOUNT *)(32LL * i + 0x604220);
              printf("\nHi, %s", gAccount[i].fd->id);
              return 1LL;
            }
          }
        }
      }
    }
  }
  return 0LL;
}

...

addAccount()

  • 当該関数は次のような機能をします。
    • 当該関数は、除隊変数gAccount当該関数は、状態変数gAccount[]。stateの値が'0'だった場合、次のように動作します。
      • 当該関数はmalloc()を使用して128 byteのheap領域を割り当てられます。
        • 当該関数は、当該領域の住所をgAccount当該関数は、当該領域の アドレスをgAccount[i]。fdに保存します。
        • 当該関数は、該当領域にID、Password、profile情報を保存します。

...

purchase

  • 当該関数は次のような機能をします。
    • 当該関数は、除隊変数gStockCntの値が0の場合、メッセージを出力、当該機能を終了します。当該関数は、状態変数gStockCntの値が0の場合、メッセージを出力、当該機能を終了します。
    • 当該関数は、状態変数gStockCntの値が0がない場合、次のような機能をします。当該関数は、除隊変数gStockCntの値が0がない場合、次のような機能をします。
      • 当該関数は使用者から購買するキャンディーのコード番号(candyInfo[0])、キャンディーの数(candyInfo[1])を入力されます。
        • 当該関数は購入できたキャンディー・コード番号、キャンディーの個数であるかを確認します。
      • 当該関数は正常な購買が進行され、キャンディーの在庫がない場合は、下記の関数が呼び出されます。
        • reSortStock()
        • setBoard()

...

Code Block
languagecpp
titlesetBoard()
unsigned __int64 setBoard()
{
  unsigned __int64 v0; // ST08_8

  v0 = __readfsqword(0x28u);
  puts("Please enter a comment for candy.");
  board = (__int64)malloc(1200uLL);
  UserInput(board, 1200LL);
  return __readfsqword(0x28u) ^ v0;
}

charge

  • 当該関数は次のような機能をします。
    • 当該関数は使用者から充電する金額の番号は、入力されます。当該関数は使用者からチャージする金額の番号は、入力されます。
    • 当該関数は、当該金額を"gLoginAccount→bk"領域に加えます。

...

  • 当該関数はgLoginAccount->stateの値が1の場合、使用可能です。
  • 当該関数は次のような機能をします。
    • 当該関数は使用可能な機能のリストを出力します。
      • アカウントを削除、暗証番号変更アカウントを削除、パスワード変更
    • 当該関数は使用者としてから使用する機能の番号を入力を受けて、当該機能を呼び出しています。

...

delAccount()

  • 当該関数は次のような機能をします。
    • 当該関数は、除隊変数gAccount当該関数は、状態変数gAccount[]を利用して削除可能なアカウントを出力します。
    • 当該関数は使用者から削除する勘定の番号を入力されます。
    • 当該関数は使用者が選択したアカウントのstate情報が'3'ある場合、削除を進めます。
      • 当該関数は、該当アカウント(gAccount[num])の情報を初期化します。
        • state=0
        • fd→state=0
        • memset(gAccount[num]。fd、0、0x80uLL);
      • 当該関数は、該当アカウント(gAccount[num])のfd領域(heap)を解除します。
    • 当該関数はgAccount[num]。fd領域に"gAccount[num]。fd-16"演算した値を保存します。
      • 保存される値はFree chunkのHeadアドレスです。
      • これによってThe House of Lore、UAF脆弱性が発生することになります。

...

changePW

  • 当該関数は次のような機能をします。
    • 当該関数は、除隊変数当該関数は、状態変数"gAccount[i]。state"を利用して秘密番号の変更が可能なアカウントを出力します。
    • 当該関数は使用者から暗証番号を変更する勘定の番号を入力されます。当該関数は使用者からパスワードを変更する勘定の番号を入力されます。
    • 当該関数は、該当アカウントの'gAccount[]。fd.state'領域に保存された値が'0'がない場合、暗証番号を変更がない場合、パスワードを変更することができます。
Code Block
languagecpp
titlechangePW()
unsigned __int64 changePW()
{
  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("%ld) %s\n", gAccount[i].number, gAccount[i].fd->id);
  }
  puts("\nPlease enter the number of the account you want to change PW");
  num = retNumber(2LL);
  if ( num )
  {
    if ( num <= 3 )
    {
      if ( gAccount[--num].fd )
      {
        if ( gAccount[num].fd->state )
        {
          puts("Enter your New Password.");
          UserInput(gAccount[num].fd->pw, 8LL);
        }
      }
    }
  }
  return __readfsqword(0x28u) ^ v4;
}

...

  • 当該関数は次のような機能をします。
    • 当該関数はcheckCancel(i)関数をキャンセル可能な注文を確認して、注文取り消しの可能なリストを出力します。
    • 当該関数はキャンセル可能な注文があり、使用者から注文ボンホウル入力を受けます。当該関数はキャンセル可能な注文があり、使用者から注文番号の入力を受けます。
    • 当該関数は入力値を検証した後reSort()関数を呼び出しして注文をキャンセルします。

...

  • 説明は進行する前に出題者はプレイヤーたちが"House of lore"脆弱性を利用して解決することを望んでいました。
    • しかし、当該脆弱性のほかにもさまざまな形で攻撃が可能です。

Fake chunk

  • 当該プログラムで脆弱性を理解するため、ACCOUNT構造体に対する理解が必要です。当該番組で脆弱性を理解するため、ACCOUNT構造体に対する理解が必要です。
    • 該当構造体は、除隊変数で宣言されています。該当構造体は、状態変数で宣言されています。
    • 当該プログラムは3つのACCOUNT構造体を使用します。当該番組は3つのACCOUNT構造体を使用します。
      • 最初の構造体には'Admin'のアカウント情報が保存されています。
      • 2、3番目の構造体は使用者が生成したアカウントの情報が保存されます。

...

  • 次のようにUAF脆弱性を使用して"gAccount[1]。fd→state"値を変更することができます。
    • ACCOUNT構造体の大きさは128 byteです。
    • orderCandy()関数にdest->candyDescription(飴の情報を入力する領域キャンディの情報を入力する領域)に割り当てられる大きさは124 byteです。
    • 解除された"gAccount[1]。fd"領域を"dest→candyDescription"に割り当てられなければなりません。
      • 該当領域("dest→candyDescription")に文字16個以上を保存すると、"gAccount[1]。fd→state"領域を覆って使うことができます。
  • 注意する内容は次のようです。
    • UAFの攻撃を行う際、一番重要な部分はHouse of lore攻撃に向けてACCOUNT構造体と同じ大きさの空間を割り当てられて解除することができなければなりません。
      • つまり、解除された"gAccount[1]。fd"領域に必ず"dest->candyDescription"に割り当てられる領域が割り当てられなければなりません。
    • そして下のような領域が"gAccount[1]。fd"領域に割り当てられていないように注意しなければなりません。
      • 当該プログラムはキャンディを注文するためにはOrder listで購入するキャンディを追加しなければなりません。当該番組は飴玉を注文するためにはOrder listで購入する飴を追加しなければなりません。
        • Order listで購入する飴を追加たびにlistで購入するキャンディを追加たびにHeap領域(24 byte)を割り当てられます。
      • 当該番組は注文したあめが店にない製品なら当該プログラムは注文したキャンディが店にない製品ならHeap領域(24 byte)を割り当てられます。

...

Leak Libc Address

  • 次のようなHeap構造設計が必要です。
    • 攻撃者は1つの飴をOrder 攻撃者は1つのキャンディをOrder listに追加して、注文を完了します。
    • 攻撃者は2つの飴をOrder 攻撃者は2つのキャンディをOrder listに追加します。
Code Block
titledebugging
gdb-peda$ parseheap 
addr                prev                size                 status              fd                bk                
0xa17000            0x0                 0x90                 Used                None              None
0xa17090            0x0                 0x410                Used                None              None
0xa174a0            0x0                 0x20                 Used                None              None
0xa174c0            0x0                 0x20                 Used                None              None
0xa174e0            0x0                 0x20                 Used                None              None
0xa17500            0x0                 0x20                 Used                None              None
0xa17520            0x0                 0x20                 Used                None              None
0xa17540            0x0                 0x20                 Used                None              None
0xa17560            0x0                 0x20                 Used                None              None
0xa17580            0x0                 0x20                 Used                None              None
0xa175a0            0x0                 0x20                 Used                None              None
0xa175c0            0x0                 0x20                 Used                None              None
0xa175e0            0x0                 0x20                 Used                None              None
0xa17600            0x100006567         0x20                 Used                None              None
0xa17620            0xa17630            0x90                 Used                None              None
0xa176b0            0x0                 0x20                 Used                None              None
gdb-peda$

...

  • 次のような方法で解除されたHeap領域をSmall binに登録します。
    • 攻撃者は最初に登録したキャンディを全て購入します。
      • 当該プログラムはキャンディを全部消尽をすれば使用していたHeap領域を全て解除します。当該番組は飴玉を全部消尽をすれば使用していたHeap領域を全て解除します。
        • 飴説明キャンディ説明(0x90)領域はUnsortedbinに登録されます。
          • この時fd、bkにmain arenaのアドレスの値が保存されます。
    • また、当該プログラムは全部消尽されたキャンディーに対する評価内容を保存するために、Heap領域を割り当てます。
      • malloc()はこの際、解除されたキャンディ情報(0x20)領域、飴説明領域、キャンディ説明(0x90)領域を一つの領域(0xb0)に変更します。
      • malloc()はHeap領域(1200 byte)を割り当てにより、当該領域をSmall binに保存します。
        • 当該Free chunkのfd、bkの領域にSmall binの住所が保存されます。binの アドレスが保存されます。
Code Block
titledebugging
gdb-peda$ parseheap 
addr                prev                size                 status              fd                bk                
0xa17000            0x0                 0x90                 Used                None              None
0xa17090            0x0                 0x410                Used                None              None
0xa174a0            0x0                 0x20                 Used                None              None
0xa174c0            0x0                 0x20                 Used                None              None
0xa174e0            0x0                 0x20                 Used                None              None
0xa17500            0x0                 0x20                 Used                None              None
0xa17520            0x0                 0x20                 Used                None              None
0xa17540            0x0                 0x20                 Used                None              None
0xa17560            0x0                 0x20                 Used                None              None
0xa17580            0x0                 0x20                 Used                None              None
0xa175a0            0x0                 0x20                 Used                None              None
0xa175c0            0x0                 0x20                 Used                None              None
0xa175e0            0x0                 0x20                 Used                None              None
0xa17600            0x100006567         0xb0                 Freed     0x7ff5052a2c18    0x7ff5052a2c18
0xa176b0            0xb0                0x20                 Used                None              None
0xa176d0            0x100006567         0x4c0                Used                None              None
gdb-peda$ p main_arena.bins[20]
$6 = (mchunkptr) 0xa17600
gdb-peda$ p main_arena.bins[21]
$7 = (mchunkptr) 0xa17600
gdb-peda$

...

Panel
titleHeap area structure

AddressStateHeap sizefdbk
Order list[0]0xa175e0A0x20NoneNone
倉庫に保存されたキャンディー・&キャンディ説明

0xa17600

F0xb0

0x7ff5052a2c18

0x7ff5052a2c18

Order list[1]

0xa176b0

A0x20NoneNone
購入したキャンディー・評価

0xa176d0

A0x4c0NoneNone
  • 次のような方法でLibc addressを抽出することができます。
    • 攻撃者は1つの飴をOrder 攻撃者は1つのキャンディをOrder listに追加します。
      • Order listに追加されたキャンディの情報は一つの領域(0xb0)に変更領域に割り当てられます。
    • 攻撃者はOrder listの内容を出力してLibc addressを抽出することができます。

...

  • 次のようにHouse of loreに必要なFake chunkを生成することができます。
    • 生成したアカウントを利用して次のようにチャージが必要です。生成したアカウントを利用して次のように充電が必要です。
      • 2番目のアカウント:6308456(0x604268)
      • 3番目のアカウント:6308416(0x604240)
    • 2番目のアカウントを削除します。
  • 次のようなgAccount[]構造を持つようになります。

...

  • まず攻撃者はbkの領域を覆って書くために次のように"gAccount[1]。fd→state"の値を操作しなければなりません。
  • 攻撃者は次のようにUAF脆弱性を使用することができます。
    • Order listに新しいケンディウル追加して、注文を完了します。listに新しいキャンディを追加して、注文を完了します。
      • この時"dest→candyDescription"領域に"gAccount[1]。fd+0x10"領域の住所が保存されます。領域の アドレスが保存されます。
        • 該当領域に16以上の文字を保存します。
    • 次のように"gAccount[1]。fd→state"値を変更されます。

...

Panel
titleHeap area structure

AddressStateHeap sizefdbk
倉庫に保存された0度キャンデー情報0xa175e0A0x20NoneNone
Order list[0]0xa17600

A

0x20NoneNone
倉庫に保存された0度キャンデー説明

0xa17620

A0x90

None

None

倉庫に保存された1度キャンデー情報

0xa176b0

F0x200x0None
購入したキャンディー・評価

0xa176d0

A0x4c0NoneNone
倉庫に保存された1度キャンデー説明0xA17B90A0x90

None

None
gAccount[2].fd0xA17c20A0x90NoneNone
  • 次のように1度キャンディを購入して0xA17B90領域がSmallbinに登録されるようにします。次のように1度ケンディウル購入して0xA17B90領域がSmallbinに登録されるようにします。
    • 0xA17B90領域がSmallbin[16]、[17]に登録されました。

...

  • 次のような方法でmain_arena.bins[17]領域にgAccount[1]のアドレス値を保存することができます。
    • 攻撃者はOrder listにケンディウル追加して、注文を完了します。listにキャンディを追加して、注文を完了します。
Code Block
titleOverwrite Smallbin bk
gdb-peda$ p main_arena.bins[16]
$3 = (mchunkptr) 0xA17B90
gdb-peda$ p main_arena.bins[17]
$4 = (mchunkptr) 0x604240
gdb-peda$ 
  • 次のようにgAccount[]領域を割り当てられます。
    • 少し前に追加したケンディウルいずれも購買します。少し前に追加したキャンディをいずれも購買します。
    • 攻撃者はOrder listにケンディウル追加して、注文を完了します。listにキャンディを追加して、注文を完了します。
      • この時キャンデー説明を入力される領域にgAccount[1]。fd領域が割り当てられます。
      • 次のような方法で希望する領域の値を変更できます。
        • gAccount[1]。fd="接近を希望する領域の住所接近を希望する領域の アドレス"-0x18
        • 2番目のアカウントのパスワード変更を使用して"アプローチを希望する領域"にユーザ入力値を保存することができます。

...