Hint: Connect withnc chatserver 12345 . After entering a username, type/help and watch which commands the server advertises. Two of them,/date and/ping , run something on the host itself. Keep that in mind for later.
Hint:python3 -c "print('A' * 8192)" | nc chatserver 12345
The username field has a length check, so the server should refuse the oversized name and drop the connection. That is actually a useful result: it tells you this input is guarded, so you move on to the next one.
Hint: You can also chain the login and the payload in one shot:python3 -c "print('Test'); print('A' * 8192)" | nc chatserver 12345
The first line logs you in as 'Test'. The second line is the oversized message. The message buffer is far smaller than what you are sending, so (you don't know it just yet, but) writing past its end corrupts the stack and the server falls over.
Being disconnected without apparent reason or suddently getting no response from the server is exactly what you are looking for.
char buffer[BUFFER_SIZE]; // BUFFER_SIZE is 1024
...
bytes_received = read(client_socket, buffer, 2048); // reads up to 2048 bytesThe buffer holds 1024 bytes, but the read is told it may pull in 2048. Anything past byte 1024 spills into whatever the compiler placed next on the stack. Push far enough and you corrupt something the function depends on, and the server process dies. From your side that shows up only as your connection (and everyone else's) being dropped, because the crash happens server side, not in your terminal.Hint: Doing this by hand is slow, so automate it. The pieces you need:seq produces a range of numbers, a shellfor loop lets you reuse each value,python3 -c runs a one line script where'A'*n repeats a character n times, and a pipe intonc delivers it. Chain those so each iteration prints its length and then sends a slightly longer payload, and watch which length is the last one your session survives. Make sure your range reaches past where you expect the break, or you will never see it.
Hint:python3 -c "print('guest'); print('A'*256 + 'Admin')" will print 256 times theA character and thenAdmin .
Here, I used 256 as an example.
With the right payload, logging in asguest passes the reserved-name filter.
TheA bytes then fill the message buffer to its edge, and the trailingAdmin lands directly in the username field, overwritingguest .
The reserved-name check already ran at login, so nothing stops you now.
The server echoesmessage sent as: Admin , and/whoami will confirm it. You did not bypass the filter, you wrote straight past it.
char *handle_command(char *buffer) {
char shell[64] = "bash -c ";
char command[1024];
strcpy(command, buffer); // no length check
...
else if (strncmp(command, "/ping", 5) == 0) {
return exec_linux(shell, "ping -c 1 2>&1 127.0.0.1");
}And here is what char *exec_linux(char *shell, char *command) {
char cmd[512];
sprintf(cmd, "%s '%s' ", shell, command);
fp = popen(cmd, "r");
...
}The Hint: Three things have to be true at once. The message must still begin with/ping , or the vulnerable branch never runs. You need enough padding after that to reachshell , and you can find that offset the same way you measured the buffer earlier. Finally, whatever you place intoshell becomes the front of the command, so the leftover'ping ...' text has to be neutralised: a# inside a shell command starts a comment and swallows everything after it. Picture how the prefix, the padding, your command, and that# join into one single line.