####################################################################### Luigi Auriemma Application: Abyss Webserver (http://www.aprelium.com) Versions: X1 (v 1.1.2) Platform: Windows and Linux Bug: Crash caused by the reading of an unreachable memory zone Date: 05 Apr 2003 Author: Luigi Auriemma e-mail: aluigi@autistici.org web: aluigi.org ####################################################################### 1) Introduction 2) Bug 3) The Code 4) Fix ####################################################################### =============== 1) Introduction =============== Abyss is a very good free and tiny webserver that not only has a lot of functions but it also run on both Win and Linux systems. ####################################################################### ====== 2) Bug ====== As all the webservers in the world, Abyss read the HTTP fields ("Host:" and "Referer:" for example) sent by the remote clients in their HTTP requests. Every HTTP field is followed by a value used for pass some parameters to the webserver, like what browser we use, if we want that the current connection remain alive for more seconds, if we wanna resume the download of a file and much more. The problem in Abyss X1 webserver happen when 2 fields passed by the client are incomplete (without their values). These fields are: - "Connection:" used for specify if we want to break or continue the current connection with the server. - "Range:" used for specify how many bytes and from what offset we want to start or continue the download of a file. So instead of sending for example the field "Connection: close" the attacker will send only "Connection:" without any value after it, and now we will see what really happen in Abyss webserver when it receive this malformed field. When Abyss receive a request, it will read each HTTP field and every value of eachone of these fields. In the case of "Connection:" and "Range:" fields, the server not only must read them but must also compare them with some default strings for see what type of operation the client has choose (for example in case of "Connection:", the server will compare its value with "close" or "Keep-Alive"). The comparison made by the server is case insensitive and for make it the server use the function strnicmp on Windows and strncasecmp on Linux. Now Abyss will simply pass the following arguments to the comparison function: 1) address of the first string: this is the value that follow the HTTP field. This address will be 0x00000000 if the value doesn't exist. 2) address of the second string: this is the string we must compare for see if the first is equal or not ("Keep-Alive" for example). 3) number of chars to compare: this is equal to the size of the second string (the number of chars in "Keep-Alive" for example). The following is a visual example of the usage of strnicmp function on a Windows systems (don't worry it is the same on Linux too). The example is just the vulnerable function on Abyss X1 (v1.1.2) that calls strnicmp for compare the value of the "Connection:" field without check if this value really exist and is stored in memory. :0040E3EA 6A0A push 00A :0040E3EC 68205E4100 push 00415E20 (StringData)"keep-alive" :0040E3F1 FF7508 push dword[ebp+08] :0040E3F4 FF151C114100 call dword[0041111C ->0001205A _strnicmp] Explanation: :0040E3EA it pass 00A (= 10), it is the size of "keep-alive" (3) :0040E3EC it pass the address of the string "keep-alive" (2) :0040E3F1 it pass the address of the HTTP field value (1) :0040E3F4 the program calls the strnicmp function (At offset 0040E473 you can see the same thing for the "Range:" field) And now the debugger or just only the disassembler will give us the right explanation of the crash that we will see after sending one of the 2 malformed HTTP fields to Abyss webserver: On Windows the crash will happen at EIP 0x78013590 of MSVCRT.DLL that is the function that reads the chars of the first string that is stored in memory. The Assembly instruction at that offset is "mov ah, [esi]", but naturally ESI is NULL because DOESN'T exist the string in memory (the attacker has not sent it!) and the program cannot read a zone of memory located at 0x00000000. Same thing happen on Linux that crash at EIP 0x42079db7, that is the function strncasecmp. ####################################################################### =========== 3) The Code =========== For test the bug try to send the following HTTP request: -------------- GET / HTTP/1.0 Connection: -------------- or -------------- GET / HTTP/1.0 Range: -------------- ####################################################################### ====== 4) Fix ====== Version X1 v1.1.4 resolve the problem. #######################################################################