简体   繁体   中英

Reading from a data file in c

I've been working my way through The Art of Exploitation by Jon Erickson, but I've come to a sticking point regarding reading data from a file and his code.

There are two programs ./notetaker and ./notesearch, the former is used to create a note with the users id, the latter is used to retrieve notes by the current user.

However, after making a note and trying to access it through ./notesearch, the note isn't displayed as text as suggested in the book.

What I have deduced so far is that the file that is created in ./notetaker is a data file as opposed to a text file, so when it is printed out it is not readable.

So why is the author suggesting that his code works, when in reality it doesn't and what would be the simplest work around.

I have started looking at fopen, fgets() etc as the solution, but it seems to be far removed from the original code.

If I get ./notesearch to look at a random text file it will print out in human readable form, so the problem I believe lies in the creation of the original file and its type.

But unfortunately I am none the wiser as to how to overcome the problem

Snippet from ./notetaker

int main(int argc, char *argv[]) {
    int userid;
    int file_descriptor;
    char *buffer, *datafile;

    buffer = (char *) ec_malloc(100);
    datafile = (char *) ec_malloc(20);
    strcpy(datafile, "notes");

    if (argc < 2)
        usage(argv[0], datafile);

    strcpy(buffer, argv[1]);

    printf("[DEBUG] buffer @ %p: '%s'\n", buffer, buffer);
    printf("[DEBUG] datafile @ %p: '%s'\n", datafile, datafile);

    strncat(buffer, "\n", 1); //adds a newline to end

    // opening file
    file_descriptor = open(datafile, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR);
    if (file_descriptor == -1)
        fatal("in main() while opening file");
    printf("[DEBUG] file descriptor is %d\n", file_descriptor);
    userid = getuid();

    // write data
    if (write(file_descriptor, &userid, 4) == -1)
        fatal("in main() while writing userid to file");
    write(file_descriptor, "\n", 1);
    if (write(file_descriptor, buffer, strlen(buffer)) == -1)
        fatal("in main() while writing buffer to file");
    write(file_descriptor, "\n", 1);

    // closing file
    if (close(file_descriptor) == -1)
        fatal("in main() while closing file");

Snippet from ./notesearch

#define FILENAME "notes"

int print_notes(int, int, char *);
int find_user_note(int, int);
int search_note(char *, char *);

int main(int argc, char *argv[]) {
    int userid, printing = 1, file_descriptor;
    char search_string[100];

    if (argc > 1)
        strcpy(search_string, argv[1]);
    else
        search_string[0] = 0;

    userid = getuid();
    file_descriptor = open(FILENAME, O_RDONLY);
    if (file_descriptor == -1)
        fatal("in main() while opening file for reading");

    while (printing)
        printing = print_notes(file_descriptor, userid, search_string);

    printf("------ [ end of note data ] ------\n");
    close(file_descriptor);
}

// print notes for a given uid
// can match an optional search string
int print_notes(int file_descriptor, int uid, char *search_string) {
    int note_length;
    char byte = 0, note_buffer[100];

    note_length = find_user_note(file_descriptor, uid);

    // if EOF return 0
    if (note_length == -1)
        return 0;

    read(file_descriptor, note_buffer, note_length); // read note data
    note_buffer[note_length] = 0; // terminate string

    // print note if search_string
    if (search_note(note_buffer, search_string))
        printf("------ [ note data ] ------\n");
        printf(note_buffer);
        printf("\n");
    return 1;
}

// finds next note for given uid
int find_user_note(int file_descriptor, int user_uid) {
    int note_uid = -1;
    unsigned char byte;
    int length;

    while (note_uid != user_uid) {
        if (read(file_descriptor, &note_uid, 4) != 4) // read uid data
            return -1;
        if (read(file_descriptor, &byte, 1) != 1) // read newline separator
            return -1;

        byte = length = 0;

        while (byte != '\n') {
            if (read(file_descriptor, &byte, 1) != 1) // read a single byte
                return -1;
            length++;
        }
    }

    // rewind file by bytes length
    lseek(file_descriptor, length * -1, SEEK_CUR);

    printf("[DEBUG] found a %d byte note for user id %d\n", length, note_uid);
    return length;
}

SOLVED: Tried the code on a 32 bit vm and all was well, although not entirely sure as to why this maybe, but has been my work around for the moment.

This is likely because the code makes assumptions about the size of integers and other types which it should not. For example...

int userid;
... 
userid = getuid();
...
if (write(file_descriptor, &userid, 4) == -1)
    fatal("in main() while writing userid to file");

There's two mistakes there. getuid returns a uid_t , not an int . They might be the same size so it might work.

More important, they've hard coded the size of userid as 4 bytes. userid is an int which is only guaranteed to be at least 2 bytes. On 32 bit machines it is typically 4 bytes (32 bits). On 64 bit machines it is 8 bytes (64 bits).

It works on a 32-bit VM because there int is 4 bytes.

Instead, use the proper types and sizeof to get the size.

uid_t userid;
... 
userid = getuid();
...
if (write(file_descriptor, &userid, sizeof(userid)) == -1)
    fatal("in main() while writing userid to file");

Overall the quality of this code is very poor. I'm hoping it's written this way for illustrative purposes.

  • strcpy(buffer, argv[1]) and strcpy(search_string, argv[1]) risk a buffer overflow.
  • There's a number of places they fail to check that file operations succeed.
  • There is a deceptive if condition.
    if (search_note(note_buffer, search_string))
        printf("------ [ note data ] ------\n");
        printf(note_buffer);
        printf("\n");

The indentation makes it look like it's all inside an if , but the lack of braces means it's really this:

    if (search_note(note_buffer, search_string)) {
        printf("------ [ note data ] ------\n");
    }
    printf(note_buffer);
    printf("\n");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM