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


    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指令审计工具,误报多,还需人工进一步分析

  • 相关阅读:
    机器学习笔记--KNN算法2-实战部分
    机器学习笔记--KNN算法1
    机器学习---python环境搭建
    机器学习简介
    用心去记录未来三年学习生活。
    jmeter5.1.1 生成html报告
    mysql字符串拼接
    linux 下mysql 慢查 my.ini/my.cnf 文件路径
    JMeter 分布式压测
    Jmeter压测报错 java.net.BindException: Address already in use: connect
  • 原文地址:https://www.cnblogs.com/CoBrAMG/p/9221199.html
Copyright © 2020-2023  润新知