ED 201c: Linux Buffer Overflow: Command Injection (15 pts)

What You Need

A Debian machine. Any other Linux machine will also work, but the instructions below may need some modification.

Purpose

To develop a very simple buffer overflow exploit in Linux, using injected shell commands.

Task 1: Installing Software

If you are using a Debian 10 machine, as recommended, execute these commands to install development tools:

sudo apt update
sudo apt install build-essential gcc-multilib gdb -y

Task 2: Exploiting a Local Service

Creating a Vulnerable Program

This program inputs a name from the user and prints out a "Goodbye" message. It then calls system() to print out the date. It uses two buffers in a subroutine to do that in an unsafe manner, allowing the name buffer to overflow into the command buffer.

In a Terminal window, execute this command:


nano buf.c
Copy and paste in this code:

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

int bo(char *name, char *cmd){
        char c[40], n[40];
        printf("Name is at %p; command is at %p\n", n, c);
        strcpy(c, cmd);
        strcpy(n, name);
        printf("Goodbye, %s!\n", n);
        printf("Executing command: %s\n", c);
        fflush(stdout);
        system(c);
}

int main(){
        char name[200];
        printf("What is your name?\n");
        scanf("%s", name);
        bo(name, "date");
}

Save the file with Ctrl+X, Y, Enter.

Execute this command to compile the code for 32-bit systems without modern protections against stack overflows, and with debugging symbols:


gcc -g -m32 -o buf32 buf.c
It should compile without errors, as shown in the image below.

Running the Program Normally

Execute this command:

./buf32
Enter your first name when prompted to.

The program prints out the location of the Name buffer and the command buffer, says "Goodbye", and excutes the command "date", as shown below.

Notice the hexadecimal addresses of the "name" and "command" buffers, and verify that the "command" buffer is stored at a higher memory address, as shown below.

Troubleshooting

If the "command" buffer is stored before the "name" buffer, change the declaration statement in the bo() function to the line shown below and recompile the program.

char n[40], c[40];

Observing a Crash

Execute this command:

./buf32
Enter fifty 'A' characters instead of your name.

The program attempts to execute the command AAAAAAAAAA, as shown below.

Finding the Code Injection Point

Execute this command:

./buf32
Enter this string, which contains forty characters followed by "ls":

AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDDDDDDDDls
The program executes the "ls" command, showing the files in your working directory, as shown below.

Escaping Spaces

Try to inject the "ls -l" command the same way. The "-l" is ignored, as shown below.

The space is interpreted as the end of a string. There are several methods of avoiding this, as listed below.

Test these techniques and figure out how to execute the "ls -l" command, as shown below.

Task 2: Exploiting a Remote Server

Vulnerable Form

Try putting in a short name, and then make the name longer until you get unexpected results.

For a good time, try this string:

0123456789012345678901234567890123456789ls
Your name:    

ED 201.1: Flag 1 (5 pts)

There's a file on the server named "flag1". Find the flag inside it.

ED 201.2: Flag 2 (10 pts)

There's a file on the server named "flag2". Find the flag inside it.

Sources

I based this on the "pwn1" and "pwn2" challenges in the 2015 SCTF competition.

Posted: 1-6-16 by Sam Bowne
Last revised 2-28-16
ASLR disabling removed 3-31-16
URL changed to "direct" 1-19-17
gcc fix added 1-25-18
Minor language fixes 8-25-18
Updated for WCIL 5-22-19
Updated for Google Cloud servers 6-23-19
Updated to remove Google Cloud references 2-8-21
Format updated 2-8-22