Thread: New to C and Segfault

  1. #1
    Registered User
    Join Date
    Mar 2020
    Posts
    9

    Question New to C and Segfault

    Hi,

    I'm not a C programmer, have been a SysAd for quite some time and can write shell scripts so I have some rudimentary programming knowledge.

    I have some C code that is available on GitHub. I have compiled it on CentOS7 and it works. Works well enough and is reliable enough during stress testing for the last two weeks now. I would like to understand how it works in the long run (if I can even begin to understand C basics).

    Problem: it segfaults on Debian Buster and Arch Linux. The company I'm working for uses Debian containers, hence my dilemma.

    I just registered for this forum minutes ago and don't know what to expect. I don't want to appear as being lazy but I need the help, the entry barrier for being proficient in C is enormous for me right now.

    Can I ask for help by posting the GitHub link and include what I have tried along with gcc warnings, gdb output and valgrind output which point to a function(s) in a file? I have also tried to contact the author, no response (yet).

    That is as much as I have managed to isolate the problem.

    Please advise?

    Thank you.
    Last edited by ephemeric; 03-22-2020 at 01:31 PM. Reason: Misspelling in title.

  2. #2
    Registered User rstanley's Avatar
    Join Date
    Jun 2014
    Location
    New York, NY
    Posts
    1,110
    Rather than asking us to go to an outside site, you should post the code here in CODE blocks as you are instructed in the Forum Rules FAQ.

  3. #3
    Registered User
    Join Date
    Dec 2017
    Posts
    1,628
    Sure, post the GitHub link and the other stuff.

    @rstanley, Large multi-file programs are probably best posted as a link.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  4. #4
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    Large multi-file programs are probably best posted as a link.
    Actually posting large programs is usually not the "best", it would be better to post the smallest complete program that illustrates the problem.

  5. #5
    Registered User
    Join Date
    May 2009
    Posts
    4,183
    I would lookup the gdb backtrace command.

    Tim S.
    "...a computer is a stupid machine with the ability to do incredibly smart things, while computer programmers are smart people with the ability to do incredibly stupid things. They are,in short, a perfect match.." Bill Bryson

  6. #6
    Registered User
    Join Date
    Mar 2020
    Posts
    9
    Hi,

    Wow, quick responses, excellent!

    Here is the link for reference purposes only, I didn't mean to imply one must go there: GitHub - NickStephens/WRATH: A TCP hijacking platform

    Any advice on how to do things better is appreciated as I'm unsure if one pastes the entire file or only the functions affected? I'm not in a position (yet) to accurately gauge the bare minimum LoC I should post.

    I tried to RTFM a bit and saw that this could be an alignment issue?
    ATM, there is just so much information I'm overwhelmed.

    I stepped through the frames in GDB, couldn't see much more than the BT shows already.

    GCC warnings:

    Code:
    src/main.c:85:13: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] 85 | app_cmd = (char *) safe_malloc(length);
    
    src/main.c:90:13: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] 90 | app_cmd = (unsigned char *) safe_malloc(length);
    GBD backtrace:

    Code:
    (gdb) run -o tcp -i eth0 -tR
    Starting program: /home/robert/tmp/WRATH/wrath -o tcp -i eth0 -tR
    [Thread debugging using libthread_db enabled]
    Using host libthread_db library "/usr/lib/libthread_db.so.1".
    Watching victims on eth0
    Victim filter: tcp[tcpflags] & tcp-ack != 0
    
    
    Program received signal SIGSEGV, Segmentation fault.
    0x00007ffff7c38a00 in __strcpy_sse2_unaligned () from /usr/lib/libc.so.6
    (gdb) bt
    #0  0x00007ffff7c38a00 in __strcpy_sse2_unaligned () from /usr/lib/libc.so.6
    #1  0x000055555555677d in wrath_observe () at src/main.c:91
    #2  0x00005555555564d4 in main (argc=6, argv=0x7fffffffebd8) at src/main.c:39
    main.c, apologies as I have pasted the entire file to preserve line numbers so we can follow along from the above output:

    Code:
    #include <stdlib.h>
    #include <signal.h>
    #include <libnet.h>
    #include "wrath.h"
    
    struct arg_values *user_values;
    struct lcp_package *chp;
    char *app_cmd_con;
    FILE *fp;
    int openned = 0;
    libnet_t *libnet_handle;
    pcap_t *pcap_handle;
    
    void wrath_observe();
    
    void wrath_terminate(int signal) {
        printf("\n");
        printf("Injection Statistics:\n");
    
        struct libnet_stats l_stats;
        libnet_stats(libnet_handle, &l_stats);
        printf("Packets Injected: %d\n", l_stats.packets_sent);
        printf("WRATH terminating...\n");
    
        if (openned)
            fclose(fp);
    
        exit(0);
    }
    
    int main(int argc, char *argv[]) {
    
        signal(SIGTERM, wrath_terminate);
        signal(SIGINT, wrath_terminate);
    
        user_values = (struct arg_values *) malloc(sizeof (struct arg_values));
        arg_eval(argc, argv, user_values);
    
        wrath_observe(user_values);
    
        free(user_values);
    }
    
    void wrath_observe() {
        char libnet_errbuf[LIBNET_ERRBUF_SIZE];
        char pcap_errbuf[PCAP_ERRBUF_SIZE];
        char *device;
    
        /* initializing bundle */
        chp = (struct lcp_package *) malloc(sizeof (struct lcp_package));
        memset(chp, 0x00, sizeof(struct lcp_package));
    
        chp->cline_args = user_values;
    
        /* initializing sniffer, getting into position */
        pcap_handle = wrath_position(user_values);
    
        /* grabbing device name for libnet */
            if (strcmp(user_values->interface, "\0") == 0) { // if interface is not set
                device = pcap_lookupdev(pcap_errbuf);
                if(device == NULL) {
                    fprintf(stderr, "error fetching interface: %s %s\n", pcap_errbuf, "(this program must be run as root)");
                    exit(1);
                }
            } else { // if interface is set
                device = user_values->interface;
            }
    
        // initializing environment for libent in advanced mode
        libnet_handle = libnet_init(LIBNET_RAW4_ADV, device, libnet_errbuf);
        if (libnet_handle == NULL) {
            fprintf(stderr, "trouble initiating libnet interface: %s \n", libnet_errbuf);
            exit(1);
        }
        chp->libnet_handle = libnet_handle;
    
        // finding payload
        int length;
        char *app_cmd = "\0";
        if (strcmp(user_values->input_file, "\0") != 0) { // If an input file has been specified
            int app_fd;
            app_fd = open(user_values->input_file, O_RDONLY, 0);
            if ((length = file_size(app_fd)) == -1)
                fatal_error("getting file size");
            app_cmd = (char *) safe_malloc(length);
            read(app_fd, app_cmd, length-1);
            app_cmd[length-1] = '\0';
        } else if (!strcmp(user_values->command, "\0") != 0) { // If a command has been specified but not an input file
            length = strlen(user_values->command);
            app_cmd = (unsigned char *) safe_malloc(length);
            strcpy(app_cmd, user_values->command);
            app_cmd[length-1] = '\0';
        }
    
        // finding and setting up logfile
        if ((strcmp(user_values->logfile, "\0"))) {
            fp = fopen(user_values->logfile, "w");
            openned = 1;
            chp->logfile = fp;
        }
    
        // converting and setting payload
        char *app_cmd_con = (char *) malloc(strlen(app_cmd));
        if (strcmp(app_cmd, "\0") != 0) { // if a payload was found
            wrath_char_encode(app_cmd, app_cmd_con);
            free(app_cmd);
            chp->payload = app_cmd_con;
        } else {
            chp->payload = "\0";
        }
    
        printf("Starting WRATH ...\n");
        printf("Hijacking specified packets with ... \n");
        //printf("Payload:\n%s\n", chp->payload);
        printf("-----BEGINNING-OF-PAYLOAD-----\n");
        printf("%s",chp->payload);
        printf("\n--------END-OF-PAYLOAD--------\n");
        if (openned) {
            fprintf(fp, "Starting WRATH ...\n");
            fprintf(fp, "Hijacking specified packets with ... \n");
            fprintf(fp, "Payload:\n%s\n", chp->payload);
            fprintf(fp, "-----BEGINNING-OF-PAYLOAD-----\n");
            fprintf(fp, chp->payload);
            fprintf(fp, "\n--------END-OF-PAYLOAD--------\n");
        }
    
        // seeding psuedorandom number generator
        libnet_seed_prand(libnet_handle);
    
    
        int cap_amount = -1;
        if (user_values->count != 0) // if count is set
            cap_amount = user_values->count;
    
        pcap_loop(pcap_handle, cap_amount, wrath_inject, (u_char *) chp);
        pcap_close(pcap_handle);
    
        // getting statistical information
        struct libnet_stats l_stats;
    
        libnet_stats(libnet_handle, &l_stats);
        printf("Wrath Stats: \n");
        printf("Packets Injected: %d\n", l_stats.packets_sent);
    
        if (openned)
            fclose(fp);
        libnet_destroy(libnet_handle);
        free(app_cmd_con);
        free(chp);
    }
    Thank you.
    Last edited by ephemeric; 03-23-2020 at 03:48 AM. Reason: Fix double line spacing.

  7. #7
    Registered User
    Join Date
    Mar 2020
    Posts
    9
    How can I edit the thread title to fix the misspelling?

  8. #8
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    You definitely need to find out where safe_malloc is prototyped, and include the appropriate header.

    Your machine has 64-bit addresses.
    Without a prototype, C thinks safe_malloc returns int - which if it's just 32 bits means you're losing half the address.

    Hence
    src/main.c:85:13: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] 85 | app_cmd = (char *) safe_malloc(length);

    What do you need the title changing to (I can do).
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  9. #9
    Registered User
    Join Date
    Mar 2020
    Posts
    9
    Please can you correct the misspelling in the title: "Segault" to "Segfault"?

    I see safe_malloc() is in wrath-utils.h:

    Code:
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    /* many of these functions are heavily influenced by Jon Erickson's design in his
       book "Hacking: The Art of Exploitation" */
    
    /* prints error message and exits */
    void fatal_error(char *err_mesg) {
            fprintf(stderr, "[ERROR] %s\n", err_mesg);
            exit(1);
    }
    
    /* attempts to allocate space on the heap through malloc.
     * if an error occurs, the program terminates. */
    void *safe_malloc(int size) {
            void *ptr;
            if ((ptr = malloc(size)) == NULL)
                    fatal_error("try to allocate memory on heap");
            return ptr;
    }
    ...

  10. #10
    Registered User
    Join Date
    Mar 2020
    Posts
    9
    Code:
    robert@archlinux wrath]$ grep -r wrath-utils.h src/
    src/wrath-injector.c:#include "wrath-utils.h"
    Is there a reason "wrath-utils.h" is not included in main.c but included in another source file?

  11. #11
    Registered User
    Join Date
    Mar 2020
    Posts
    9
    If I include wrath-utils.h (safe_malloc) in main.c:

    Code:
    #include <stdlib.h>
    #include <signal.h>
    #include <libnet.h>
    #include "wrath.h"
    #include "wrath-utils.h"
    and comment the same include in wrath-injector.c:

    Code:
    #include <libnet.h>
    #include <pcap.h>
    #include "wrath-structs.h"
    #include "wrath-builders.h"
    //#include "wrath-utils.h"
    #include "wrath-applevel.h"
    and compile using gcc the previous "cast to pointer from integer of different size" is gone!

    Is this dumb or a valid fix?

  12. #12
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Fix looks good.
    Try it and see what happens.

    > //#include "wrath-utils.h"
    Was probably not necessary to do this.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  13. #13
    Registered User
    Join Date
    Mar 2020
    Posts
    9
    If I don't comment the include in wrath-injector.c I get:

    Code:
    cc -g -O0 -Wno-implicit-function-declaration -c src/main.c src/wrath-args.c src/wrath-reactor.c src/wrath-injector.c src/wrath-builders.c src/wrath-http.c src/wrath-generic-app.c
    cc -g -O0 -Wno-implicit-function-declaration -o wrath main.o wrath-args.o wrath-injector.o wrath-reactor.o wrath-builders.o wrath-http.o wrath-generic-app.o -lpcap -lnet
    /usr/bin/ld: wrath-injector.o: in function `fatal_error':
    /home/robert/tmp/wrath/src/wrath-utils.h:10: multiple definition of `fatal_error'; main.o:/home/robert/tmp/wrath/src/wrath-utils.h:10: first defined here
    /usr/bin/ld: wrath-injector.o: in function `safe_malloc':
    /home/robert/tmp/wrath/src/wrath-utils.h:17: multiple definition of `safe_malloc'; main.o:/home/robert/tmp/wrath/src/wrath-utils.h:17: first defined here
    /usr/bin/ld: wrath-injector.o: in function `file_size':
    /home/robert/tmp/wrath/src/wrath-utils.h:25: multiple definition of `file_size'; main.o:/home/robert/tmp/wrath/src/wrath-utils.h:25: first defined here
    /usr/bin/ld: wrath-injector.o: in function `shiftl':
    /home/robert/tmp/wrath/src/wrath-utils.h:33: multiple definition of `shiftl'; main.o:/home/robert/tmp/wrath/src/wrath-utils.h:33: first defined here
    /usr/bin/ld: wrath-injector.o: in function `wrath_char_encode':
    /home/robert/tmp/wrath/src/wrath-utils.h:46: multiple definition of `wrath_char_encode'; main.o:/home/robert/tmp/wrath/src/wrath-utils.h:46: first defined here
    collect2: error: ld returned 1 exit status
    make: *** [makefile:14: all] Error 1
    However, it no longer segfaults!

    This was a pointer (pun intended) in the right direction:

    Your machine has 64-bit addresses.
    Without a prototype, C thinks safe_malloc returns int - which if it's just 32 bits means you're losing half the address.
    May I ask, 64bit arch means 64bit pointer addresses?

    So the cast:

    Code:
    app_cmd = (char *) safe_malloc(length);
    means the pointer is 64bits in length but the int returned from the function (which the compiler initially cannot find a prototype for) is 32bits?

  14. #14
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Well the multiply defined things are because your wrath-utils.h should really be called wrath-utils.c, because it contains actual code.

    #including definitions only works if you include it once in the project.

    An actual wrath-utils.h would contain
    Code:
    #ifndef WRATH_UTILS_H
    #define WRATH_UTILS_H
    
    /* prints error message and exits */
    void fatal_error(char *err_mesg);
     
    /* attempts to allocate space on the heap through malloc.
     * if an error occurs, the program terminates. */
    void *safe_malloc(int size);
    
    // prototypes for whatever else is in there.
    #endif

    > May I ask, 64bit arch means 64bit pointer addresses?
    That's the usual inference, yes.


    > means the pointer is 64bits in length but the int returned from the function (which the compiler initially cannot find a prototype for) is 32bits?
    Well the actual function returns a pointer, but the compiler couldn't see that at the time, so it only bothered to transfer the lower 32 bits thinking it was an int.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  15. #15
    Registered User
    Join Date
    Mar 2020
    Posts
    9
    Well the actual function returns a pointer, but the compiler couldn't see that at the time, so it only bothered to transfer the lower 32 bits thinking it was an int.
    Reading carefully, I see that now. I was mistaken.

    Salem, I cannot thank you enough.

    I am very grateful for the help.

    I will post again when I need help, this site is brilliant.

    Cheers!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. SegFault Help!
    By Giorgos Prapas in forum C Programming
    Replies: 4
    Last Post: 12-14-2015, 01:01 PM
  2. Segfault
    By Triumph in forum C Programming
    Replies: 5
    Last Post: 04-10-2009, 02:24 AM
  3. Sometimes segfault, sometimes not
    By jcafaro10 in forum C Programming
    Replies: 18
    Last Post: 04-07-2009, 06:53 PM
  4. segFault
    By Fox101 in forum C Programming
    Replies: 1
    Last Post: 04-10-2008, 12:00 AM
  5. segfault with gcc, but not with TC
    By koodoo in forum C Programming
    Replies: 15
    Last Post: 04-23-2007, 09:08 AM

Tags for this Thread