4

I've researched this question, and the closest answer I could find was this. gdb - debugging with piped input (not arguments)

I need to do exactly what this person was asking, however, I need to be able to send input AFTER having already viewed a portion of my program run.

This is the code I'm looking at in GDB

#define SECRET1 0x44
#define SECRET2 0x55

int main(int argc, char *argv[])
{
char user_input[100];

int *secret;
int int_input;
int a, b, c, d; /* other variables, not used here.*/

/* The secret value is stored on the heap */
secret = (int *) malloc(2*sizeof(int));

/* getting the secret */
secret[0] = SECRET1; secret[1] = SECRET2;

printf("The variable secret’s address is 0x%8x (on stack)\n", &secret);
printf("The variable secret’s value is 0x%8x (on heap)\n", secret);
printf("secret[0]’s address is 0x%8x (on heap)\n", &secret[0]);
printf("secret[1]’s address is 0x%8x (on heap)\n", &secret[1]);

printf("Please enter a decimal integer\n");
scanf("%d", &int_input);  /* getting an input from user */

printf("Please enter a string\n");
scanf("%s", user_input); /* getting a string from user */

/* Vulnerable place */
printf(user_input);
printf("\n");

/* Verify whether your attack is successful */
printf("The original secrets: 0x%x -- 0x%x\n", SECRET1, SECRET2);
printf("The new secrets:      0x%x -- 0x%x\n", secret[0], secret[1]);

return 0;
}

I'm attempting to perform a format string attack on my virtual machine. To do that, I need to know what address the secrets are being stored. The program tells me this through output with these lines

  printf("The variable secret’s address is 0x%8x (on stack)\n", &secret);
  printf("The variable secret’s value is 0x%8x (on heap)\n", secret);
  printf("secret[0]’s address is 0x%8x (on heap)\n", &secret[0]);
  printf("secret[1]’s address is 0x%8x (on heap)\n", &secret[1]);

The nature of the attack requires that I send non-ASCII hex values as input for the 2nd scanf,so I can't simply type the input myself. I have accomplished setting up my input using perl here,

ramtest@ramtest-VirtualBox:/tmp$ perl -e 'print "5\x0a"; print "\x08\xb0\x04\x08%x.%x.%x.%x.%x.%x.%x";' > /tmp/input

I then run

$gdb ./vul_prog < /tmp/input

I've gotten my method to work in an environment where memory randomization is off, as I can run the program once, look at the memory addresses, then change the perl script, and simply run it again. However, with memory randomization on, I can't know where the addresses will be before I run it, so I need to be able to see the portion of the program that tells me the addresses run before I create and send my input.

I've attempted to do so in the way that seemed most intuitive here, but I just get a syntax error.

Starting program: /home/ramtest/Downloads/vulprog 
The variable secret’s address is 0xbfffefd8 (on stack)
The variable secret’s value is 0x 804b008 (on heap)
secret[0]’s address is 0x 804b008 (on heap)
secret[1]’s address is 0x 804b00c (on heap)
Please enter a decimal integer
1
Please enter a string

Breakpoint 2, 0x0804858f in main ()
(gdb) c > /tmp/input
A syntax error in expression, near `> /tmp/input'.
(gdb) c < /tmp/input
A syntax error in expression, near `< /tmp/input'.

Is it possible for me to set a breakpoint in GDB right before I am prompted for input, then send the /tmp/input information as input somehow?

If so, how would I go about that?

Any help would be appreciated.

Community
  • 1
  • 1

1 Answers1

2

Just use the run command. I'll demonstrate by feeding /bin/cat to gdb, and breaking in its main(), with standard input redirected:

Example:

$ gdb /bin/cat
GNU gdb (GDB) Fedora 7.12.1-47.fc25
[ ... ]
(gdb) b main
Breakpoint 1 at 0x1bc0
(gdb) run </etc/issue
Starting program: /usr/bin/cat </etc/issue

Breakpoint 1, 0x0000555555555bc0 in main ()
(gdb) c
Continuing.
\S
Kernel \r on an \m (\l)

[Inferior 1 (process 18190) exited normally]
(gdb) 

You should be able to start your program under gdb, set a breakpoint just before scanf, then run it with standard input redirected from an empty file. I don't expect that your program will attempt to read from its standard input until then, so it won't see the end-of-file condition on its redirected standard input.

When the breakpoint hits you should have your memory addresses, then prepare your payload and simply append it to the zero-length file, then

c

the execution, which should then proceed and attempt to read the payload that's now available on its standard input.

A variation of this technique that won't even require a debugger would be to use a named pipe that gets opened for writing, in advance, then run this program with its standard input redirected from the named pipe. The expected result would be the program printing the memory addresses, then blocking when it reads from the pipe. At this point you can prepare your payload, and write it to the pipe.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148