Rating:

# Exploit 200: Memo
Memo is a simple binary that records strings, allows editing, and keeps a username/password:
```
What's user name: bk
Do you wanna set password? (y/n) n
ok

1. Leave message on memo
2. Edit message last memo
3. View memo
4. Delete memo
5. Change password
6. 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 it
there 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_input
0x00400c74 cdqe
0x00400c76 mov qword [obj.last_memo], rax
0x00400c7d mov rax, qword [obj.last_memo] ; Stores memo index
0x00400c84 shl rax, 3
0x00400c88 add rax, 0x602a70
0x00400c8e mov rax, qword [rax]
0x00400c91 test rax, rax ; Checks if in use
0x00400c94 jne 0x400d9b
0x00400c9a mov rax, qword [obj.last_memo]
0x00400ca1 cmp rax, 4 ; Checks array bounds
0x00400ca5 ja 0x400d87
```

## new_memo overflows the heap
```
0x00400d58 mov edi, 0x20
0x00400d5d call sub.malloc_216_870 ; malloc(0x20)
0x00400d62 mov qword [rbp - new_memo], rax
0x00400d66 mov rax, qword [rbp - new_memo]
0x00400d6a mov rdx, qword [rbp - memo_size]
0x00400d6e mov rsi, rax
0x00400d71 mov edi, 0
0x00400d76 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, 3
0x00400d05 lea rdx, [rax + obj.memos] ; Stores memo pointer in array
0x00400d0c mov rax, qword [rbp - new_memo]
0x00400d10 mov qword [rdx], rax
0x00400d13 mov rax, qword [obj.last_memo]
0x00400d1a add rax, 5 ; Add 5 to index
0x00400d1e shl rax, 3
0x00400d22 lea rdx, [rax + obj.memos] ; Indexing into memo array
0x00400d29 lea rax, [rbp - new_memo] ; lea stack address to store there??
0x00400d2d mov qword [rdx], rax
0x00400d30 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, 3
0x00400dc2 add rax, obj.memos
0x00400dc8 mov rax, qword [rax]
0x00400dcb test rax, rax
0x00400dce je 0x400e40
0x00400dd0 mov edi, str.Edit_message:
```

## the handy shellcode-executing function:
```
(fcn) fcn.lol 122
0x00400b47 push rbp
0x00400b48 mov rbp, rsp
0x00400b4b sub rsp, 0x10
0x00400b4f mov edi, str.this_is_hidden_memo_pad
0x00400b54 call sub.puts_128_818
0x00400b59 mov edi, str.you_can_write_anything_here
0x00400b5e call sub.puts_128_818
0x00400b63 mov r9d, 0
0x00400b69 mov r8d, 0
0x00400b6f mov ecx, 0x32
0x00400b74 mov edx, 7
0x00400b79 mov esi, 0x1000
0x00400b7e mov edi, 0x41410000
0x00400b83 call sub.mmap_144_828 ; mmaps with RWX
0x00400b88 mov qword [rbp - local_8h], rax
0x00400b8c mov rax, qword [rbp - local_8h]
0x00400b90 mov edx, 0x1000
0x00400b95 mov esi, 0
0x00400b9a mov rdi, rax
0x00400b9d call sub.memset_160_838
0x00400ba2 mov rax, qword [rbp - local_8h]
0x00400ba6 mov edx, 0x1000
0x00400bab mov rsi, rax
0x00400bae mov edi, 0
0x00400bb3 call sub.read_168_840 ; Reads input into this new memory
0x00400bb8 mov rax, qword [rbp - local_8h]
0x00400bbc call rax ; Calls our new shellcode
0x00400bbe nop
0x00400bbf leave
0x00400bc0 ret
```

## The Exploit
The 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}

Original writeup (https://github.com/DMArens/CTF-Writeups/tree/master/2017/BostonKeyParty/memo-exploit300).