zoukankan      html  css  js  c++  java
  • 路由器漏洞挖掘(栈,危险函数,方法)

    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!
    ");
        else printf("%s
    ", res);    // print:-->'host: www.baidu.com'
        res = strstr("xxxhost: www.baidu.com", "cookie");
        if(res == NULL) printf("res2 is NULL!
    ");
        else printf("%s
    ", 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!
    ");
        else printf("%s
    ", 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
    ", dest);
       memcpy(dest, src, strlen(src)+1);
       printf("After memcpy dest = %s
    ", 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指令审计工具,误报多,还需人工进一步分析

  • 相关阅读:
    149. Max Points on a Line(js)
    148. Sort List(js)
    147. Insertion Sort List(js)
    146. LRU Cache(js)
    145. Binary Tree Postorder Traversal(js)
    144. Binary Tree Preorder Traversal(js)
    143. Reorder List(js)
    142. Linked List Cycle II(js)
    141. Linked List Cycle(js)
    140. Word Break II(js)
  • 原文地址:https://www.cnblogs.com/CoBrAMG/p/9221199.html
Copyright © 2011-2022 走看看