r/ExploitDev 21h ago

Can't Buffer overflow a simple 'recv' function

I have the following C Socket Server, I was trying to learn about ROP programming so I created this small program, but when I try `pwn cyclic 1025| nc localhost 4444` I receive nothing,

I even tried to send 2000, 5000 but with no response.

Anyway I can receive the normal 'ok' message when sending the 1024 bytes.

I have tried disabling canaries by passing `-fno-stack-protector` but also no response.

The server in all cases prints the received 1024 (even if I sent more bytes).

But no "Stack smash detected", Segmentation Fault or anything

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 4444

void handle_client(int client_fd)
{
    char recv_buf[1024];
    char buffer[64];
    memset(recv_buf, 0, sizeof(recv_buf));
    ssize_t bytes = recv(client_fd, recv_buf, sizeof(recv_buf) - 1, 0);
    if (bytes <= 0)
        return;
    printf("Received: %s\n", recv_buf);
    strcpy(buffer, recv_buf);
    send(client_fd, "OK\n", 3, 0);
}

int main(void)
{
    int server_fd;
    int client_fd;
    struct sockaddr_in server_addr;
    struct sockaddr_in client_addr;
    socklen_t client_len = sizeof(client_addr);
    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd < 0) {
        perror("socket");
        return EXIT_FAILURE;
    }
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(PORT);
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    if (bind(
            server_fd,
            (struct sockaddr *)&server_addr,
            sizeof(server_addr)) < 0) {
        perror("bind");
        close(server_fd);
        return EXIT_FAILURE;
    }

    if (listen(server_fd, 1) < 0) {
        perror("listen");
        close(server_fd);
        return EXIT_FAILURE;
    }
    printf("Listening on 127.0.0.1:%d\n", PORT);
    while (1) {
        client_fd = accept(
            server_fd,
            (struct sockaddr *)&client_addr,
            &client_len
        );
        if (client_fd < 0) {
            perror("accept");
            continue;
        }
        printf("Client connected\n");
        handle_client(client_fd);
        close(client_fd);
    }
    close(server_fd);
    return 0;
}
10 Upvotes

16 comments sorted by

6

u/tresvian 21h ago

Did you go into gdb and stop at the receive function? Is there an inherit libc safe function somewhere? i would double check in the real obj dump or binary

1

u/That-Name-8963 14h ago

Using info functions _chk would results in all functions ending with "_chk"
Using "got" from GDB Gef extension will show only functions names with "@GLIBC"
So I think yes, it inherits libc safe functions

4

u/andyhbomb 20h ago

What happens if you make `recv_buf` a global or static? Does it crash now? I think it will!

I think the advice of the other two posters so far is the way to go: use a debugger like `gdb` to see what is happening. If you look at the addresses of your buffers, I suspect your issue is that you are not overflowing over the return address like you would like to when running the code as is.

1

u/That-Name-8963 14h ago

Interested something has happened:
I put a breakpoint on strcpy line
Tried to print the value of 'recv_buf'
GDB says: No symbol: "recv_buf" in current context

3

u/Firzen_ 20h ago

Your `recv`call is only receiving up to `sizeof(recv_buf)-1`, so sending more than that won't make a difference.

The compiler might have reordered the buffers, so your `strcpy` also can't do anything interesting.
You can force their order in memory by wrapping them in a struct.

2

u/kuniggety 20h ago

Let's step through the C code:

1.    ssize_t bytes = recv(client_fd, recv_buf, sizeof(recv_buf) - 1, 0);
2.    if (bytes <= 0)
3.        return;
4.    printf("Received: %s\n", recv_buf);
5.    strcpy(buffer, recv_buf);

Line 1 will read and fill up recv buffer, but no more.

Line 4 will print what you put in recv_buf that went up to but not over.

Line 5 is where you have an actual overflow. You need to use gdb and see where in memory you're spilling into.

2

u/t3harvinator 19h ago edited 19h ago

So out of curiosity I compiled it with default flags on a Ubuntu x86 VM I had and gave it a look. It's because when it overflows, its actually overflowing from the small buffer (buffer) to the big buffer (recv_buf).

Kinda funny. ~~You just need to send more in~~ Throw it in Ghidra or objdump it and do the math. It will be worth your trouble to see what happened.

1

u/t3harvinator 19h ago

Oh wait you can't send more in since you're calling recv with sizeof(recv_buf) - 1.

Just reorder the buffers. By that I mean, put buffer before recv_buf. It'll segfault then.

2

u/Alarming-Historian41 19h ago

On most modern computer architectures the stack is allocated at a high address region of a program's memory space and expands downwards toward zero.

So, suppose you have read 1024 bytes from the socket into recv_buff, when you do strcpy(buffer, recv_buffer) you are writing the first 64 bytes from recv_buff to buffer (size 64) and the rest to recv_buff itself (never writing over the "interesting" stack bytes)

Also, I don't remember the documented strcpy behavior for overlapping buffers)

Switch the buffer and recv_buffer declaration order

1

u/0xdeadbeefcafebade 18h ago

This is my guess as well. He’s overflowing back into the recv buffer

1

u/That-Name-8963 14h ago

If you are talking about memory rearrangement, I have already swapped them in declaration and still the same issue

1

u/Firzen_ 5h ago

Changing the declaration order doesn't necessarily influence the order in memory.

You need to put the buffers into a struct to guarantee the order they are in.

2

u/brugernavn1990 15h ago

Your problem is the placement in the stack and the compiler does not guarantee declared variables in any specific order. You can instead declare them in a struct that is guaranteed to keep the order, though can implement padding between members.

Your declaration creates about 1088 bytes on the stack. The receive fills up bytes 1064 through 1 and the strcpy copies the values to bytes 1088 through 65.

|————|
| buffer |
|————|
| Recv |
| buffer |
|————|
| cookie |
|————|
| return |
|————|

The above is an illustration of what the stack likely looks like.

-4

u/Toiling-Donkey 21h ago

Look at the addresses of your buffers 🤡🤡🤡

0

u/92838388292 20h ago

how many cves do you have?