路由器漏洞挖掘(栈,危险函数,方法)

MIPS32架构堆栈:

  1. 和x86 架构一样,都是由高地址向低地址增长,无EBP。
  2. 进入函数调用时,把栈指针(sp)向下移动n比特,这个大小为n比特的存储空间为此函数的stack Frame。
  3. 此后栈指针不移动,只有在函数返回时,加上这个偏移量恢复现场。
  4. 由于不能随便移动栈指针,所以寄存器压栈和出栈使用偏移
  5. A调用B,会在A 的栈顶预留一部分空间保存b的调用参数,称为参数空间。
  6. 参数传递,前4个参数通过a0-a4传递,超出的会放入参数空间。
  7. 返回地址:把返回地址直接存入$ra寄存器。
  8. 函数执行的命令的取指从$PC中取

    从某个地址到’jr $ra' 指令之间的二进制序列称为gadget

函数调用过程:

  

函数调用参数:

  

   说明:在调用函数b前,参数使用a0-a3外加参数空间的参数,当B调用并分配了栈空间,b会把a0-a3的值存储到A的参数空间

函数调用栈数据情况:

    说明:非叶子函数has_stack调用时,会把返回main 的地址放到自己的栈底部,如图:0x0040042c,

       数据从低到高覆盖,有可能覆盖返回main的地址,造成缓冲区溢出。 

 

危险函数:

  1,sprintf

    下面是 sprintf() 函数的声明。

    int sprintf(char *str, const char *format, ...)

    参数

  • str -- 这是指向一个字符数组的指针,该数组存储了 C 字符串。
  • format -- 这是字符串,包含了要被写入到字符串 str 的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。format 标签属性是 %[flags][width][.precision][length]specifier,具体讲解如下:
#include <stdio.h>
#include <math.h>

int main()
{
   char str[80];

   sprintf(str, "Pi 的值 = %f", M_PI);
   puts(str);
   
   return(0);
}


输出:
Pi 的值 = 3.141593
sprintf使用

 strchr使用

  char *strchr(const char *s, int c) 
  功能: 查找字符串s中首次出现c字符的位置

  说明: 返回首次出现c的位置的指针,返回的地址是被查找的字符串指针开始的第一个与c相同字符的指针,若s中不存在c则返回NULL。。。。

  返回值: 成功返回要查找的字符第一次出现的位置,否则返回NULL。。。。

strrchr使用

  char *strrchr(const char *s, int c)

  功能: 查找一个字符c在一个字符串s中最后一次出现的位置(也就是从s的右侧开始查找字符c首次出现的位置),并返回从字符串中的字符c所在的位置开始直到字符串s结束的所有字符。 若没有找到字符c,则返回NULL。

 

strstr函数使用

char *strstr(const char *haystack, const char *needle);
haystack        -->被查找的目标字符串"父串"
needle          -->要查找的字符串对象"子串"
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
    char *res = strstr("xxxhost: www.baidu.com", "host");
    if(res == NULL) printf("res1 is NULL!\n");
    else printf("%s\n", res);    // print:-->'host: www.baidu.com'
    res = strstr("xxxhost: www.baidu.com", "cookie");
    if(res == NULL) printf("res2 is NULL!\n");
    else printf("%s\n", res);    // print:-->'res2 is NULL!'
    return 0;
}

注:strstr函数中参数严格"区分大小写"
strstr 使用示例

strcasestr函数 

strcasestr函数的功能、使用方法与strstr基本一致。
strcasestr函数在"子串"与"父串"进行比较的时候,"不区分大小写"
#define _GNU_SOURCE             // 宏定义必须有,否则编译会有Warning警告信息
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
    char *res = strstr("xxxhost: www.baidu.com", "Host");
    if(res == NULL) printf("res1 is NULL!\n");
    else printf("%s\n", res);     // print:-->'host: www.baidu.com'
    return 0;
}
strcasestr 使用示例

 memset使用

   将s所指向的某一块内存中的每个字节的内容全部设置为ch指定的ASCII值,

  块的大小由第三个参数指定,这个函数通常为新申请的内存做初始化工作

  用 法: void *memset(void *s, char ch, unsigned n);

#include <string.h>

  #include <stdio.h>

  #include <memory.h>

  int main(void)

  {

  char buffer[] = "Hello world/n";

  printf("Buffer before memset: %s/n", buffer);

  memset(buffer, '*', strlen(buffer) );// //数组直接首地址传进去。 主要是对数组指针的修改!!因为可以被修改而const char int等这些不能被修改 和malloc 配套使用

  printf("Buffer after memset: %s/n", buffer);

  return 0;

  }

  输出结果:

  Buffer before memset: Hello world

  Buffer after memset: ***********
memset 使用示例

memcpy

C 库函数 void *memcpy(void *str1, const void *str2, size_t n) 从存储区 str2 复制 n 个字符到存储区 str1

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

int main ()
{
   const char src[50] = "http://www.w3cschool.cc";
   char dest[50];

   printf("Before memcpy dest = %s\n", dest);
   memcpy(dest, src, strlen(src)+1);
   printf("After memcpy dest = %s\n", dest);
   
   return(0);
}
让我们编译并运行上面的程序,这将产生以下结果:

Before memcpy dest =
After memcpy dest = http://www.w3cschool.cc
memcpy 使用示例

fgets函数使用

 原型  char *  fgets(char * s, int n,FILE *stream);

    参数:

         s: 字符型指针,指向存储读入数据的缓冲区的地址。

         n: 从流中读入n-1个字符

         stream : 指向读取的流。

   返回值:

          1. 当n<=0 时返回NULL,即空指针。

          2. 当n=1 时,返回空串"".

          3. 如果读入成功,则返回缓冲区的地址。

          4. 如果读入错误或遇到文件结尾(EOF),则返回NULL.

 

 

漏洞挖掘方法

代码审计:

  1. 使用IDA对目标进行反汇编
  2. 收索可能造成安全漏洞的危险函数
  3. 跟踪危险函数如何获取和处理用户提供的数据过程,判断是否存在安全漏洞

危险函数分类:

1,部分用户提供数据来源的相关函数

  • 命令行参数:argv操作
  • 环境变量:getenv()
  • 输入数据文件:read() fscanf()getc() fgetc() fgets() fscanf()
  • 键盘输入/stdin: read,  scanf   getchar   gets
  • 网络数据:read  recv  recvfrom

2,部分数据操作的相关危险函数

  • 字符串复制:strcpy(char *dest,char *src)       strncpy
  • 命令执行:system  execve
  • 字符串格式化:strcat
  • 格式化字符串:sprintf   snprintf

定位上诉危险函数,根据参数个数,类型跟踪个参数,分析缓冲区大小,判断是否存在漏洞

  • 对于1,采用正向数据流跟踪,从输入点开始跟踪
  • 对于2,采用逆向数据流跟踪,反向跟踪参数数据流向,找出缓冲区大小

自动化二进制文件审计工具

Bugscam:x86平台下,

R-bugscam: RISC指令审计工具,误报多,还需人工进一步分析

 

posted @ 2018-06-28 11:56  CobrAMG  阅读(1545)  评论(0编辑  收藏  举报