首页
社区
课程
招聘
[原创]4.堆溢出和COM漏洞寻找
发表于: 2019-12-26 20:29 8188

[原创]4.堆溢出和COM漏洞寻找

2019-12-26 20:29
8188

先观察代码
可以得到一个类似结构得链表,如果在这里溢出修改pNext的话,因为fscanf结束后,还有pNode->pNext = pHead,会还原回去所以这里不行。


这句代码的作用就是输入,没用写入的机会,所以也没用

而这两句代码能够溢出数据,并且不会被写回,这里解释下为什么非要溢出改pNext,如果仅仅只是溢出数据,那么任何一个fscanf(fp, "%s", pNode->szName);这样的写法都能够随便溢出,但是我们缺少能够执行我们shellcode的机会。第一个fscanf修改我们要第二次要写入数据的位置。第二个fscanf
会写入第二次数据,这次我们把数据写到哪里,能够有机会执行,又能够有写的权限?

继续看,下面调用了两个函数,printffclose
例如:printf里面会调用WriteFileReadFile等api
fclose会调用CloseHandle等api,感兴趣的话可以OD自己跟进去看
如果这些api通过IAT表调用的话,那么我们第二次写入的shellcode放入api在IAT表的地址,那么不就会执行到我们的shellcode吗?

#include "stdafx.h"
#include <string.h>
#include <stdlib.h>
#include <windows.h>
#include <iostream.h>

struct tagNode
{
    char szName[8];
  struct tagNode *pNext;
};

struct tagTest
{
  short Magic;
  short nLength;
  char *szBuf;
};

void test(char *szPwd)
{
  tagNode *pHead = NULL; 
  tagNode *pNode = NULL; 
  FILE *fp = NULL;
  fp = fopen("name.txt", "r+");
  if (fp == NULL)
  {
    exit(-1);
  }

  int nRet = EOF;
  for (int i = 0; i < 3; i++)
  {
    pNode = new struct tagNode;
    nRet = fscanf(fp, "%s", pNode->szName);

    pNode->pNext = pHead;
    pHead = pNode;
  }

  for (pNode = pHead; pNode != NULL; pNode = pNode->pNext)
  {
    printf("%s\r\n", pNode->szName);
  }

  pNode = pHead;
  fscanf(fp, "%s", pNode->szName);

  pNode = pHead->pNext;
  fscanf(fp, "%s", pNode->szName);

  for (pNode = pHead; pNode != NULL; pNode = pNode->pNext)
  {
    printf("%s\r\n", pNode->szName);
  }

  if (fp)
  {
    fclose(fp);
    fp = NULL;
  }
}

int main(int argc, char* argv[])
{
  char szPwd[] = "Hello";
  test(szPwd);

  system("pause");
  return 0;
}
for (int i = 0; i < 3; i++)
{
  pNode = new struct tagNode;
  nRet = fscanf(fp, "%s", pNode->szName);

  pNode->pNext = pHead;
  pHead = pNode;
}
for (pNode = pHead; pNode != NULL; pNode = pNode->pNext)
{
  printf("%s\r\n", pNode->szName);
}
pNode = pHead;
fscanf(fp, "%s", pNode->szName);

pNode = pHead->pNext;
fscanf(fp, "%s", pNode->szName);
for (pNode = pHead; pNode != NULL; pNode = pNode->pNext)
{
  printf("%s\r\n", pNode->szName);
}

if (fp)
{
  fclose(fp);
  fp = NULL;
}
00430250 >76C83ED3  kernel32.ReadFile
  • 案例代码
  • 先观察代码
    可以得到一个类似结构得链表,如果在这里溢出修改pNext的话,因为fscanf结束后,还有pNode->pNext = pHead,会还原回去所以这里不行。

    for (int i = 0; i < 3; i++)
    {
      pNode = new struct tagNode;
      nRet = fscanf(fp, "%s", pNode->szName);
    
      pNode->pNext = pHead;
      pHead = pNode;
    }
    


    这句代码的作用就是输入,没用写入的机会,所以也没用

    for (pNode = pHead; pNode != NULL; pNode = pNode->pNext)
    {
      printf("%s\r\n", pNode->szName);
    }
    

    而这两句代码能够溢出数据,并且不会被写回,这里解释下为什么非要溢出改pNext,如果仅仅只是溢出数据,那么任何一个fscanf(fp, "%s", pNode->szName);这样的写法都能够随便溢出,但是我们缺少能够执行我们shellcode的机会。第一个fscanf修改我们要第二次要写入数据的位置。第二个fscanf
    会写入第二次数据,这次我们把数据写到哪里,能够有机会执行,又能够有写的权限?

    pNode = pHead;
    fscanf(fp, "%s", pNode->szName);
    
    pNode = pHead->pNext;
    fscanf(fp, "%s", pNode->szName);
    

    继续看,下面调用了两个函数,printffclose
    例如:printf里面会调用WriteFileReadFile等api
    fclose会调用CloseHandle等api,感兴趣的话可以OD自己跟进去看
    如果这些api通过IAT表调用的话,那么我们第二次写入的shellcode放入api在IAT表的地址,那么不就会执行到我们的shellcode吗?

    for (pNode = pHead; pNode != NULL; pNode = pNode->pNext)
    {
      printf("%s\r\n", pNode->szName);
    }
    
    if (fp)
    {
      fclose(fp);
      fp = NULL;
    }
    
  • 进入printf函数查看间接调用的API
    看到了WriteFile

    也可以用访问断点来查看是否调用

    发现有间接访问

    记录下
    00430250 >76C83ED3  kernel32.ReadFile
    
  • 编写读入的数据
    fscanf遇到\x0D\x0A\x0C....会被截断

    第一个循环构造的链表
    ![]
    接下来是我们定位的溢出位置的第一次执行,把ReadFileIAT地址给写进去

    crtl+g过去看发现是我们api地址

    写进去了但是崩溃了为什么呢?
    因为call 这个地址跳过去一个不对的地址肯定崩

    红框就是填写shllecode地址,正好是写入位置+4

    在这个地址下硬件执行断点,发现可以来一切正常

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2019-12-27 08:35 被自然dashen编辑 ,原因:
收藏
免费 1
支持
分享
最新回复 (1)
雪    币: 4120
活跃值: (5822)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
2
辛苦大佬
2019-12-26 22:08
0
游客
登录 | 注册 方可回帖
返回
//