




This is the first of a series of articles on security and exploiting. For starters we’ll cover basic debugging tools before we get into actual exploiting because the first step to exploiting is reverse-engineering most of the time.
The series targets experienced developers and tries to go straight to the point for them. Every article in this series is tagged “security”.
strace is a tool that prints system calls like open, connect, etc … and signals like INT, KILL, etc … of a process. It is very useful to know what a program is doing.
strace
as a wrapperYou can start a program using strace as a wrapper as such:
$ strace ./main
execve("./main", ["./main"], [/* 43 vars */]) = 0
brk(0) = 0x1b7a000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=169727, ...}) = 0
mmap(NULL, 169727, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7ff0770cd000
close(3) = 0
open("/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\34\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2022349, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff0770cc000
mmap(NULL, 3832336, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7ff076b2f000
mprotect(0x7ff076ccd000, 2097152, PROT_NONE) = 0
mmap(0x7ff076ecd000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x19e000) = 0x7ff076ecd000
mmap(0x7ff076ed3000, 14864, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7ff076ed3000
close(3) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff0770cb000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff0770ca000
arch_prctl(ARCH_SET_FS, 0x7ff0770cb700) = 0
mprotect(0x7ff076ecd000, 16384, PROT_READ) = 0
mprotect(0x7ff0770f7000, 4096, PROT_READ) = 0
munmap(0x7ff0770cd000, 169727) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 5), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff0770f6000
write(1, "Hello 6 World\n", 14Hello 6 World
) = 14
exit_group(0) = ?
+++ exited with 0 +++
-e
Strace will probably output much more than you need. You could use the -e
option to filter calls:
$ strace -e open,close,read,write ./main
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
close(3) = 0
open("/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\34\2\0\0\0\0\0"..., 832) = 832
close(3) = 0
write(1, "Hello 6 World\n", 14Hello 6 World
) = 14
+++ exited with 0 +++
-o
You’ll note that strace outputs quite an amount of data for our little main
program, imagine how much it will output for a bigger program … Way to much.
Use the -o
option to get strace to output to a file:
strace -o /tmp/main.strace ./main
-p
Use something like ps aux
or pgrep
to find a process ID. Then you can
attach to it with -p
:
strace -o /tmp/postgresql -p 1234
You might have to do that as root:
sudo strace -o /tmp/postgresql -p 1234
Else, you might have this error:
strace: attach: ptrace(PTRACE_ATTACH, ...): Operation not permitted
-t
or -r
Use -t
for time:
$ strace -t ./main
18:15:28 execve("./main", ["./main"], [/* 43 vars */]) = 0
18:15:28 brk(0) = 0x24ac000
18:15:28 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
18:15:28 open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
18:15:28 fstat(3, {st_mode=S_IFREG|0644, st_size=169727, ...}) = 0
18:15:28 mmap(NULL, 169727, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f8d7b716000
18:15:28 close(3) = 0
18:15:28 open("/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
18:15:28 read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\34\2\0\0\0\0\0"..., 832) = 832
18:15:28 fstat(3, {st_mode=S_IFREG|0755, st_size=2022349, ...}) = 0
18:15:28 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f8d7b715000
18:15:28 mmap(NULL, 3832336, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f8d7b178000
18:15:28 mprotect(0x7f8d7b316000, 2097152, PROT_NONE) = 0
18:15:28 mmap(0x7f8d7b516000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x19e000) = 0x7f8d7b516000
18:15:28 mmap(0x7f8d7b51c000, 14864, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f8d7b51c000
18:15:28 close(3) = 0
18:15:28 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f8d7b714000
18:15:28 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f8d7b713000
18:15:28 arch_prctl(ARCH_SET_FS, 0x7f8d7b714700) = 0
18:15:28 mprotect(0x7f8d7b516000, 16384, PROT_READ) = 0
18:15:28 mprotect(0x7f8d7b740000, 4096, PROT_READ) = 0
18:15:28 munmap(0x7f8d7b716000, 169727) = 0
18:15:28 fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 6), ...}) = 0
18:15:28 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f8d7b73f000
18:15:28 write(1, "Hello 6 World\n", 14Hello 6 World
) = 14
18:15:28 exit_group(0) = ?
18:15:28 +++ exited with 0 +++
And -r
for relative time:
$ strace -r ./main
0.000000 execve("./main", ["./main"], [/* 43 vars */]) = 0
0.000307 brk(0) = 0x1392000
0.000108 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
0.000075 open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
0.000056 fstat(3, {st_mode=S_IFREG|0644, st_size=169727, ...}) = 0
0.000083 mmap(NULL, 169727, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f971f25d000
0.000061 close(3) = 0
0.000071 open("/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
0.000078 read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\34\2\0\0\0\0\0"..., 832) = 832
0.000091 fstat(3, {st_mode=S_IFREG|0755, st_size=2022349, ...}) = 0
0.000050 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f971f25c000
0.000044 mmap(NULL, 3832336, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f971ecbf000
0.000034 mprotect(0x7f971ee5d000, 2097152, PROT_NONE) = 0
0.000055 mmap(0x7f971f05d000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x19e000) = 0x7f971f05d000
0.000053 mmap(0x7f971f063000, 14864, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f971f063000
0.000064 close(3) = 0
0.000053 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f971f25b000
0.000031 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f971f25a000
0.000032 arch_prctl(ARCH_SET_FS, 0x7f971f25b700) = 0
0.000097 mprotect(0x7f971f05d000, 16384, PROT_READ) = 0
0.000036 mprotect(0x7f971f287000, 4096, PROT_READ) = 0
0.000027 munmap(0x7f971f25d000, 169727) = 0
0.000069 fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 6), ...}) = 0
0.000053 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f971f286000
0.000058 write(1, "Hello 6 World\n", 14Hello 6 World
) = 14
0.000058 exit_group(0) = ?
0.000063 +++ exited with 0 +++
-s 1024
Sometimes, strace will truncate strings to print which we might want to read. Use the -s
option:
-s strsize Specify the maximum string size to print (the default is 32).
Note that filenames are not considered strings and are
always printed in full.
-c
$ strace -c ./main
Hello 6 World
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
0.00 0.000000 0 1 read
0.00 0.000000 0 1 write
0.00 0.000000 0 2 open
0.00 0.000000 0 2 close
0.00 0.000000 0 3 fstat
0.00 0.000000 0 8 mmap
0.00 0.000000 0 3 mprotect
0.00 0.000000 0 1 munmap
0.00 0.000000 0 1 brk
0.00 0.000000 0 1 1 access
0.00 0.000000 0 1 execve
0.00 0.000000 0 1 arch_prctl
------ ----------- ----------- --------- --------- ----------------
100.00 0.000000 25 1 total