# Exploit 200: MemoMemo is a simple binary that records strings, allows editing, and keeps a username/password:```What's user name: bkDo you wanna set password? (y/n) nok
1. Leave message on memo2. Edit message last memo3. View memo4. Delete memo5. Change password6. Quit.>> ```
it has quite a few problems 1. new_memo (0x00400c52) sets a global variable last_memo before checking in use/in bounds 2. new_memo allows overflowing onto the heap when specifying memo size, but the memo is not put in the memo array 3. new_memo stores a stack pointer (to the local memo pointer variable) into a global array after the memo array 4. edit_memo (0x00400da8) only checks if a memo is in use, not for out of bounds 5. change_password (0x00400ff6) has an off by one error, overflowing a null byte into the memo sizes array 6. there is a function at 0x00400b47, which is never called, mmaps RWX memory, reads 0x1000 bytes into it, and jumps to itthere are other bugs too, but it turns out this is exploitable with just 1, 4, and 6. It's possible to exploit it through the heap, but the last function saves a lot of time.
## new_memo sets a global variable too early```0x00400c6f      call fcn.get_input0x00400c74      cdqe0x00400c76      mov qword [obj.last_memo], rax0x00400c7d      mov rax, qword [obj.last_memo]  ; Stores memo index0x00400c84      shl rax, 30x00400c88      add rax, 0x602a700x00400c8e      mov rax, qword [rax]0x00400c91      test rax, rax                   ; Checks if in use0x00400c94      jne 0x400d9b0x00400c9a      mov rax, qword [obj.last_memo]0x00400ca1      cmp rax, 4                      ; Checks array bounds0x00400ca5      ja 0x400d87```
## new_memo overflows the heap```0x00400d58      mov edi, 0x200x00400d5d      call sub.malloc_216_870         ; malloc(0x20)0x00400d62      mov qword [rbp - new_memo], rax0x00400d66      mov rax, qword [rbp - new_memo]0x00400d6a      mov rdx, qword [rbp - memo_size]0x00400d6e      mov rsi, rax0x00400d71      mov edi, 00x00400d76      call sub.read_168_840            ; Read in user supplied size```
## new_memo stores stack addresses in a global array (weird...)```0x00400cfa      mov rax, qword [obj.last_memo]0x00400d01      shl rax, 30x00400d05      lea rdx, [rax + obj.memos]       ; Stores memo pointer in array0x00400d0c      mov rax, qword [rbp - new_memo]0x00400d10      mov qword [rdx], rax0x00400d13      mov rax, qword [obj.last_memo]0x00400d1a      add rax, 5                       ; Add 5 to index0x00400d1e      shl rax, 30x00400d22      lea rdx, [rax + obj.memos]       ; Indexing into memo array0x00400d29      lea rax, [rbp - new_memo]        ; lea stack address to store there??0x00400d2d      mov qword [rdx], rax0x00400d30      mov rax, qword [obj.last_memo]0x00400d37      mov rdx, qword [rbp - memo_size]0x00400d3b      mov dword [rax*4 + obj.sizes], edx  ; store size in array preceding memo array```
## edit_memo only checks for in use, not out of bounds```0x00400db7      mov rax, qword [obj.last_memo]0x00400dbe      shl rax, 30x00400dc2      add rax, obj.memos0x00400dc8      mov rax, qword [rax]0x00400dcb      test rax, rax0x00400dce      je 0x400e400x00400dd0      mov edi, str.Edit_message:```
## the handy shellcode-executing function:```(fcn) fcn.lol 122 0x00400b47      push rbp 0x00400b48      mov rbp, rsp 0x00400b4b      sub rsp, 0x100x00400b4f      mov edi, str.this_is_hidden_memo_pad0x00400b54      call sub.puts_128_8180x00400b59      mov edi, str.you_can_write_anything_here0x00400b5e      call sub.puts_128_8180x00400b63      mov r9d, 00x00400b69      mov r8d, 00x00400b6f      mov ecx, 0x320x00400b74      mov edx, 70x00400b79      mov esi, 0x10000x00400b7e      mov edi, 0x414100000x00400b83      call sub.mmap_144_828              ; mmaps with RWX0x00400b88      mov qword [rbp - local_8h], rax 0x00400b8c      mov rax, qword [rbp - local_8h]0x00400b90      mov edx, 0x10000x00400b95      mov esi, 00x00400b9a      mov rdi, rax 0x00400b9d      call sub.memset_160_8380x00400ba2      mov rax, qword [rbp - local_8h]0x00400ba6      mov edx, 0x10000x00400bab      mov rsi, rax 0x00400bae      mov edi, 00x00400bb3      call sub.read_168_840              ; Reads input into this new memory0x00400bb8      mov rax, qword [rbp - local_8h]0x00400bbc      call rax                           ; Calls our new shellcode0x00400bbe      nop0x00400bbf      leave0x00400bc0      ret ```
## The ExploitThe goal is to call the shellcode-running function, which can easily be done with a stack overflow because PIE is off, and stack addresses were kindly written into the global memo array.The exploit is pretty simple, and goes like this: 1. allocate memos with index 0 and 1 2. call new_memo and ask for index 6, overwritting the last_memo variable, without leaving a memo. 3. call edit_memo, which does not check for out-of-bounds, only that the memo is not null. The memo is memo_list[6] which falls into the array of stack addresses, and length is used from memo_sizes[6] which is actually in the memo array, and is allocated. It is necessary to use index 6 rather than 5 due to differing data sizes. 4. we are now writing directly to the stack, 0x18 bytes from the return address, which we will overwrite with the nice shellcode function. 5. input shellcode, get a shell, cat flag.
see solve.py
bkp{you are a talented and ambitious hacker}