...
- 当該関数は次のような機能をします。
- 当該関数は、除隊変数gAccount[]。stateの値が'0'だった場合、次のように動作します。
- 当該関数はmalloc()を使用して128 byteのheap領域を割り当てられます。を使用して128 byteのheap領域を割り当てられます。
- 当該関数は、当該領域の住所をgAccount[i]。fdに保存します。
- 当該関数は、該当領域にID、Password、profile情報を保存します。
- 当該関数はmalloc()を使用して128 byteのheap領域を割り当てられます。を使用して128 byteのheap領域を割り当てられます。
- 当該関数は、除隊変数gAccount[]。stateの値が'0'だった場合、次のように動作します。
...
- 当該関数は次のような機能をします。
- 当該関数はmalloc()関数を利用して1200 byteのHeap領域を割り当てられます。関数を利用して1200 byteのHeap領域を割り当てられます。
- 当該関数は、該当領域に使用者から値を入力を受けて保存します。
...
- 当該関数は次のような機能をします。
- 当該関数は使用者から充電する金額の番号は、入力されます。
- 当該関数は、当該金額を当該関数は、当該金額を"gLoginAccount→bk"領域に加えます。
| Code Block | ||||
|---|---|---|---|---|
| ||||
unsigned __int64 charge()
{
unsigned int chargeInfo[2]; // [rsp+0h] [rbp-10h]
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
v2 = __readfsqword(0x28u);
chargeInfo[0] = 0;
puts("Please select the amount to charge.");
puts("0) 1");
puts("1) 10");
puts("2) 100");
puts("3) 1000");
puts("4) 10000");
puts("5) 100000");
chargeInfo[1] = retNumber(2LL);
switch ( chargeInfo[1] )
{
case 0u:
chargeInfo[0] = 1;
break;
case 1u:
chargeInfo[0] = 10;
break;
case 2u:
chargeInfo[0] = 100;
break;
case 3u:
chargeInfo[0] = 1000;
break;
case 4u:
chargeInfo[0] = 10000;
break;
case 5u:
chargeInfo[0] = 100000;
break;
default:
break;
}
gLoginAccount->bk += chargeInfo[0];
printf("%ld yen charged.\n", chargeInfo[0], *(_QWORD *)chargeInfo);
return __readfsqword(0x28u) ^ v2;
} |
...
- 当該関数は次のような機能をします。
- 当該関数は、除隊変数gAccount[]を利用して削除可能なアカウントを出力します。
- 当該関数は使用者から削除する勘定の番号を入力されます。
- 当該関数は使用者が選択したアカウントのstate情報が'3'ある場合、削除を進めます。
- 当該関数は、該当アカウント(gAccount[num])の情報を初期化します。
- state=0
- fd→state=0
- memset(gAccount[num]。fd、0、0x80uLL);
- 当該関数は、該当アカウント(gAccount[num])のfd領域のfd領域(heap)を解除します。を解除します。
- 当該関数は、該当アカウント(gAccount[num])の情報を初期化します。
- 当該関数はgAccount[num]。fd領域に"gAccount[num]。fd-16"演算した値を保存します。
- 保存される値はFree chunkのHeadアドレスです。
- これによってThe House of Lore、UAF脆弱性が発生することになります。
...
- 当該関数は次のような機能をします。
- 当該関数はchoiceCandy()関数を使用して注文するキャンディーの番号を入力されます。
- 当該関数はmalloc()関数を使用して24 byteのheap領域を割り当てられます。関数を使用して24 byteのheap領域を割り当てられます。
- 当該関数は、該当領域に注文するキャンディーの情報を保存します。
...
- 当該関数は次のような機能をします。
- 当該関数はfree()関数を利用してgOrderList関数を利用してgOrderList[a1]領域を解除します。領域を解除します。
| Code Block | ||||
|---|---|---|---|---|
| ||||
unsigned __int64 __fastcall reSort(unsigned int a1)
{
int i; // [rsp+14h] [rbp-Ch]
unsigned __int64 v3; // [rsp+18h] [rbp-8h]
v3 = __readfsqword(0x28u);
free(gOrderList[a1]);
if ( a1 < gOrderCnt )
{
for ( i = 0; a1 + i < gOrderCnt; ++i )
gOrderList[a1 + i] = gOrderList[a1 + i + 1];
}
gOrderList[gOrderCnt--] = 0LL;
return __readfsqword(0x28u) ^ v3;
} |
...
- 当該関数は次のような機能をします。
- 当該関数は使用者からキャンディ注文の進めるかどうかを確認します。
- 当該関数はgetStockNum()関数を使用してgOrderList[]に保存された値がgStock[]に存在するかどうか確認します。
- 当該関数はgOrderList[]に保存された値gStock[]に存在する場合、次のように処理されます。
- "gStock[]->candyNumber"に"gOrderList[]→orderNumber"の値を加えることになります。
- 当該関数はgOrderList[]に保存された値gStock[]に存在しない場合、次のように処理されます。
- 当該関数はmalloc()関数を使用して24 byteのheap領域を割り当てます。関数を使用して24 byteのheap領域を割り当てます。
- 当該関数は、該当領域にキャンディに対する情報を保存します。
- キャンディの名前や価格、キャンディの情報が保存されているアドレス値
- また、当該関数は124 byteのheap領域を割り当てて、当該領域に使用者から入力を受けたキャンデー情報を保存します。
- 当該関数はgOrderList[]に保存された値gStock[]に存在する場合、次のように処理されます。
- 当該関数はgOrderList[]に保存された値gStock[]にすべて保存した後、gOrderListにすべて保存した後、gOrderList[]領域を全て解除します。領域を全て解除します。
| Code Block | ||||
|---|---|---|---|---|
| ||||
unsigned __int64 orderCandy()
{
struct STOCK *dest; // ST10_8
unsigned int i; // [rsp+4h] [rbp-1Ch]
int num; // [rsp+Ch] [rbp-14h]
unsigned __int64 v4; // [rsp+18h] [rbp-8h]
v4 = __readfsqword(0x28u);
if ( gOrderCnt )
{
orderList();
puts("\nWould you like to order these candies?");
puts("0) Yes, 1) No");
if ( !(unsigned int)retNumber(2LL) )
{
for ( i = 0; i < gOrderCnt; ++i )
{
num = getStockNum(i);
if ( num )
{
gStock[num - 1]->candyNumber += gOrderList[i]->orderNumber;
}
else if ( (unsigned int)gStockCnt > 4 )
{
puts("The warehouse is full. Your new order can not be completed.");
}
else
{
puts("\nEnter information about newly added candy.");
dest = (struct STOCK *)malloc(24uLL);
strncpy(dest->candyName, gOrderList[i]->orderCandyName, 8uLL);
dest->candyNumber = gOrderList[i]->orderNumber;
printf("Enter the price of %s candy.\n", dest);
dest->candyPrice = retNumber(5LL);
printf("Enter a description of the %s candy.\n", dest);
dest->candyDescription = (char *)malloc(124uLL);
UserInput(dest->candyDescription, 124LL);
gStock[gStockCnt++] = dest;
}
}
while ( gOrderCnt )
{
free(gOrderList[gOrderCnt - 1]);
gOrderList[gOrderCnt-- - 1] = 0LL;
}
}
}
else
{
puts("You have never ordered a product.");
}
return __readfsqword(0x28u) ^ v4;
} |
Proof of concept
- 説明は進行する前に出題者はプレイヤーたちが"House of lore"脆弱性を利用して解決することを望んでいました。
- しかし、当該脆弱性のほかにもさまざまな形で攻撃が可能です。
Fake chunk
- 当該番組で脆弱性を理解するため、ACCOUNT構造体に対する理解が必要です。
- 該当構造体は、除隊変数で宣言されています。
- 当該番組は3つのACCOUNT構造体を使用します。
- 最初の構造体には'Admin'のアカウント情報が保存されています。
- 2、3番目の構造体は使用者が生成したアカウントの情報が保存されます。
...
| Panel | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||||||||||||||||||||||
|
...
| Panel | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||||||||||||||||||||||
|
- 次のような方法でLibc addressを抽出することができます。
- 攻撃者は1つの飴をOrder listに追加します。
- Order listに追加されたキャンディの情報は一つの領域(0xb0)に変更領域に割り当てられます。
- 攻撃者はOrder listの内容を出力してLibc addressを抽出することができます。
- 攻撃者は1つの飴をOrder listに追加します。
...
| Panel | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||||||||||||||||||||||||||||
|
...
| Panel | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||||||||||||||||||||||||||||||||||||||||
|
...
| Panel | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||||||||||||||||||||||||||||||||||||||||
|
...
| Panel | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||||||||||||||||||||||||||||||||||||||||
|
...
| Panel | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
- 次のように2度アカウントのパスワードの変更を通じて、bk領域の値を引き続き変更できます。
- bkの領域に最初のFake chunkの開始アドレスを保存しました。
...