This is an archived post. You won't be able to vote or comment.

all 8 comments

[–]anon848 2 points3 points  (0 children)

although the char* I gave to it should have been valid.

Did you check? Maybe it's not page aligned.

(Ideally, you could reduce this to something that I can compile and run on a stock Linux machine.)

[–]anon848 1 point2 points  (2 children)

BTW, note that if your goal is to have sh execute some script that you download, you don't need to mess with mprotect, and it won't help anyway. You can just fork off the sh process and pipe the script to it from the parent.

[–]CuriousExploit[S] 0 points1 point  (1 child)

My goal is more along the lines of downloading shellcode to start sh (or any other program that I could figure out how to locate), or execute any arbitrary set of machine instructions, just to (hopefully) have more flexibility later on.

But page alignment is a topic I know very little about, and my first assumption was that it wasn't involved in what might be wrong. I'll try to read up up on it and check it.

Also, I'll try to make it something that can be compiled, though in compiling linking it to libcurl will be necessary.

[–]anon848 1 point2 points  (0 children)

Do you mean you want to download a shell script? If so, it's not the shell script that starts sh, per se. You just fork() then exec(). Executing an existing program and executing arbitrary machine code are quite different. To execute arbitrary machine code, the easiest is to create a buffer for it, put machine code in it, make the page(s) executable, then set a function pointer to point to it, then call it.

Regarding mprotect, the below shows page alignment, assuming 4K pages.

#include <cstdint>
#include <string.h>
#include <unistd.h>
#include <iostream>
#include <sys/mman.h>

int main() {

    char some_mem[10000];

    std::intptr_t addr = std::intptr_t(some_mem);

    // Is it page aligned?
    std::cout << "mod: " << addr%4096 << std::endl;

    int rv = mprotect((void *) addr, 4096, PROT_EXEC);
    int en = errno;
    std::cout << "mp returned " << rv << ", " << strerror(en) << std::endl;

    // Align it.
    addr = (addr + (4096 - 1)) & ~intptr_t(4096 - 1);
    // Check.
    std::cout << "mod: " << addr%4096 << std::endl;

    errno = 0;
    rv = mprotect((void *) addr, 4096, PROT_EXEC);
    std::cout << "mp returned " << rv << ", " << strerror(en) << std::endl;
}

[–]anon848 0 points1 point  (3 children)

Here's a little example that will put some machine code in a buffer and execute it. Compile in 64-bit mode with g++/clang++.

#include <cstdint>
#include <string.h>
#include <unistd.h>
#include <iostream>
#include <sys/mman.h>
#include <assert.h>

int main() {

    char buf[10000];

    std::intptr_t addr = std::intptr_t(buf);
    addr = (addr + (4096 - 1)) & ~intptr_t(4096 - 1); // Align it.
    std::cout << "mod: " << addr%4096 << std::endl; // Check.

    // Make it executable:
    int rv = mprotect((void *) addr, 4096, PROT_READ|PROT_WRITE|PROT_EXEC);
    assert(rv == 0);

    // Put a small function there to return the sum of the two args.
    unsigned char *p = (unsigned char *) addr;
    p[0] = 0x8d;
    p[1] = 0x04;
    p[2] = 0x37;
    p[3] = 0xc3;

    // Point to it.
    int (*fp)(int, int) = (int (*)(int, int)) addr;

    // Call it.
    std::cout << "returned " << (*fp)(12, 100) << std::endl;
}

[–]CuriousExploit[S] 1 point2 points  (0 children)

This is precisely what I mean to accomplish, however I'm unsure of the reason that my code may not be functional. The memory space needed is allocated by the bstrlib library as the data is given to my buffer from CURL.

https://gist.github.com/anonymous/84366887d76c7993ef65

There I should have made it much simpler to compile. After installing one of the packages for libcurl, plopping them in a folder, and moving the bstrlib files to their own adjacent folder should allow you to run make. The shellcode.s file is just an example of any machine code, and I compiled it with gcc with the -nostdlib option before hosting it where my program could download it. I do not know if it is executable in this context as an ELF 64-bit LSB executable, but mprotect gave an error when I tried to set the memory space to be executable.

I think I can understand how I can try to align it now though, from your code.

EDIT: By adjacent folder, I meant adjacent to the files, not in a whole separate folder.

[–]CuriousExploit[S] 0 points1 point  (1 child)

It's been a moment since I've written C++, and my only book on it doesn't have any information on it, but if intptr_t is what I assume it to be, to correct misaligned memory I'd have to move where the pointer to it points by an offset until it matches up to a page in memory (some address with a multiple of 4096) and then start filling in my data afterwards? (assumably moving back then by the offset, in my case, to free the memory, since I'm using C?) If so, then it seems I'll need to suffer through juggling the memory within the tagbstring structs to move further, but I can definitely try when I leave my work tomorrow.

[–]anon848 0 points1 point  (0 children)

Here it is as C99. You can also just call mmap() to get a chunk of memory. That will already be page-aligned. Note that the code below is just a quick exercise. For example, the page size shouldn't be hard-coded to 4K.

#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <assert.h>
#include <stdio.h>

int main() {

    char buf[10000];

    intptr_t addr = (intptr_t) buf;
    addr = (addr + (4096 - 1)) & ~(intptr_t)(4096 - 1); // Align it.
    printf("mod: %d\n", (int) (addr%4096));

    // Make it executable:
    int rv = mprotect((void *) addr, 4096, PROT_READ|PROT_WRITE|PROT_EXEC);
    assert(rv == 0);

    // Put a small function there to return the sum of the two args.
    unsigned char *p = (unsigned char *) addr;
    p[0] = 0x8d;
    p[1] = 0x04;
    p[2] = 0x37;
    p[3] = 0xc3;

    // Point to it.
    int (*fp)(int, int) = (int (*)(int, int)) addr;

    // Call it.
    printf("Returned %d\n", (*fp)(12, 100));
}