mirror of
https://github.com/Kowntaewook/MCPTrace.git
synced 2026-11-02 04:45:09 +01:00
Document verified Windows MCP RAM recovery and per-run limits
This commit is contained in:
@@ -2,11 +2,6 @@ name: Windows positive memory validation
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: ['test/windows-mcp-positive']
|
||||
paths:
|
||||
- 'validation/windows_positive/**'
|
||||
- '.github/workflows/windows-positive-memory.yml'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
@@ -6,13 +6,17 @@ Windows·Linux 프로세스 메모리에서 MCP/JSON-RPC 메시지 후보를 추
|
||||
**상태: 초기 구현.** 프레임워크 패키지 버전은 `volatility3==2.28.2`로 고정했습니다.
|
||||
분석 대상은 Windows x64와 Linux x86-64입니다. 합성 테스트와 함께 공개 Windows 11 x64
|
||||
빌드 22000 이미지 1개와 Linux 이미지 2개를 시험했습니다.
|
||||
Windows에서는 선택한 프로세스 4개의 VAD 1,561개를 검사했고 MCP 후보는 0개였습니다.
|
||||
해당 Windows 11 샘플에서는 선택한 프로세스 4개의 VAD 1,561개를 검사했고 MCP 후보는 0개였습니다.
|
||||
[Windows 실제 RAM 검증](docs/windows-memory-validation.md)에는 실행 범위와 대형 빈 주소 영역
|
||||
읽기 개선을 기록했습니다. Linux MCP 활동 샘플의 Python 프로세스
|
||||
2개에서 후보 41개를 추출하고 원문·해시·VMA 범위를 다시 대조했습니다. 이 샘플은 VMware
|
||||
메타데이터가 없어 물리 메모리 배치를 추정해 변환한 조건부 결과입니다.
|
||||
[실제 RAM 검증 기록과 재현 절차](docs/real-memory-validation.md)를 참고하세요.
|
||||
전체 메시지 복원율·정밀도, Windows의 실제 MCP 메시지 추출, 다른 OS 빌드의 호환성은 아직 검증하지 않았습니다.
|
||||
추가로 [Windows Server 2022의 실제 MCP 통신·RAM 양성 검증](docs/windows-positive-memory-validation.md)을
|
||||
수행했습니다. 마지막 실행에서 원문을 별도 보관하지 않은 조건은 논리 메시지 16/21개와 도구 호출
|
||||
5/8쌍, 원문 보관 대조군은 20/21개와 7/8쌍을 복원했습니다. 내보낸 레코드 120개의 원문·주소·해시도
|
||||
대조했습니다. 정답 로깅이 있는 작은 stdio 통제 실험이며, 일반적인 복원율·정밀도나 다른
|
||||
클라이언트·Windows 빌드의 호환성을 보장하지 않습니다.
|
||||
|
||||
| 분석할 이미지 | 명령 | 프로세스 메모리 영역 |
|
||||
| --- | --- | --- |
|
||||
@@ -236,7 +240,7 @@ Linux의 마운트 네임스페이스·chroot·심볼릭 링크도 해석하지
|
||||
- `pslist`에서 보이지 않는 프로세스, 해제되어 VAD/VMA 밖에 남은 흔적, 현재 레이어가 읽지 못하는 페이지는 범위 밖입니다.
|
||||
- `bytes_read`는 읽기에 성공한 바이트 수입니다. 후보 제한으로 중단하면 읽은 버퍼 전체가 처리됐다는 뜻은 아닙니다.
|
||||
후보 제한은 일반 JSON-RPC에도 적용되므로 잡음이 많으면 관련 메시지에 도달하기 전에 중단할 수 있습니다.
|
||||
- 검색 결과 없음은 흔적 부재의 증명이 아닙니다. 모든 프로세스에 요약 행을 남기며 탐지율·복원율 수치를 주장하지 않습니다.
|
||||
- 검색 결과 없음은 흔적 부재의 증명이 아닙니다. 모든 프로세스에 요약 행을 남기며 일반적인 탐지율·복원율 수치를 주장하지 않습니다.
|
||||
|
||||
테스트 실행:
|
||||
|
||||
|
||||
+4
-1
@@ -4,7 +4,9 @@
|
||||
공개 Linux 이미지 2개에 대한 실행 결과는 [실제 RAM 검증 기록](real-memory-validation.md)에
|
||||
별도로 기록했습니다. MCP 활동 샘플은 누락된 VMware 메타데이터를 대신해 추정한 물리 메모리
|
||||
배치를 적용했습니다. [Windows 11 실제 이미지 검증](windows-memory-validation.md)도 수행했으나,
|
||||
그 이미지에서는 MCP 후보가 나오지 않았습니다. 전체 메시지 기준 성능 평가는 아직 수행하지 않았습니다.
|
||||
그 이미지에서는 MCP 후보가 나오지 않았습니다. 이후
|
||||
[Windows Server 2022의 실제 MCP 통신·RAM 양성 검증](windows-positive-memory-validation.md)에서
|
||||
정답이 있는 메시지 복원을 확인했습니다. 일반적인 복원 성능 평가는 아직 수행하지 않았습니다.
|
||||
|
||||
## 자동 검증
|
||||
|
||||
@@ -25,6 +27,7 @@ CI는 Ubuntu/Windows 분석 호스트와 Python 3.10/3.12 조합을 구성합니
|
||||
| 어댑터 | 실제 TreeGrid, 프로세스별 제한·요약, 뒤쪽 VAD/VMA 읽기 오류 이후 기존 증거 보존 |
|
||||
| Linux 태스크 | 실제 PID 필터, 프로세스 간 ID 비연결, 사용자 주소 공간 없음, 레이어 생성 실패, active_mm 대체 사용 금지 |
|
||||
| 출력 | 실제 Volatility CLI 파일 핸들러, JSONL 원문 왕복·해시, 기존 파일 비덮어쓰기 |
|
||||
| 검증 하네스 | 논리 메시지/복사본/비전송 대조군 분리, PID/typed ID별 후보 연결 대조, Windows 파일 핸들 정리 |
|
||||
| 로딩 | 새 CLI 프로세스에서 -p 경로로 Windows/Linux 플러그인 검색 및 도움말 생성 |
|
||||
|
||||
`tests/test_plugin.py`의 EPROCESS/VAD, `tests/test_linux_plugin.py`의 task_struct/mm/VMA 열거 객체와
|
||||
|
||||
@@ -112,6 +112,8 @@ vol -q --offline --cache-path cache -s symbols -f evidence/Win11Dump.mem -r json
|
||||
vol -q --offline --cache-path cache -s symbols -p plugins -f evidence/Win11Dump.mem -o output/win11 -r json windows.mcptrace.MCPTrace --pid 3244 6524 6248 2180 --dump > output/win11/findings.json 2> output/win11/stderr.txt
|
||||
```
|
||||
|
||||
후속 검증에는 실제 MCP 호출과 정답 메시지를 기록한 Windows 덤프가 필요합니다.
|
||||
후속으로 실제 MCP 호출과 정답 메시지를 기록한
|
||||
[Windows Server 2022 RAM 양성 검증](windows-positive-memory-validation.md)을 수행했습니다.
|
||||
이는 다른 OS 빌드에서의 별도 실험입니다.
|
||||
이번 결과만으로 Windows의 MCP 복원 성능, 다른 Windows 빌드 호환성, 정밀도·재현율을
|
||||
주장하지 않습니다. 원본 덤프·심볼·메모리 내용은 저장소에 커밋하지 않습니다.
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
# Windows 실제 MCP 통신의 RAM 복원 검증
|
||||
|
||||
검증일: 2026-10-27. GitHub Actions의 Windows Server 2022 x64 빌드 20348 VM에서
|
||||
공식 Python MCP SDK로 실제 stdio 요청·응답을 실행하고 WinPmem으로 RAM을 수집했습니다.
|
||||
`windows.mcptrace.MCPTrace`를 실행한 뒤 정답 로그와 비교하고, 모든 추출 원문을 native
|
||||
Windows 프로세스 레이어에서 다시 읽어 주소·길이·SHA-256·VAD 범위를 대조했습니다.
|
||||
덤프에 테스트 JSON을 주입하거나 합성 페이지 테이블을 사용하지 않았습니다.
|
||||
|
||||
## 실행과 결과
|
||||
|
||||
[최종 실행 40459138175](https://github.com/Kowntaewook/MCPTrace/actions/runs/40459138175)은
|
||||
수집·분석·대조·원본 임시 덤프 삭제를 모두 마치고 성공했습니다.
|
||||
[첫 실행 40457925570](https://github.com/Kowntaewook/MCPTrace/actions/runs/40457925570)의
|
||||
분석 관측값도 함께 기록해 실행 사이의 차이를 숨기지 않습니다.
|
||||
|
||||
| 실행 | 조건 | 복원 논리 메시지 | 완전한 도구 요청·응답 쌍 | 추출 레코드 / 통신 정답과 일치 | 비전송 대조군 |
|
||||
| --- | --- | ---: | ---: | ---: | ---: |
|
||||
| 첫 실행, 정리 단계 실패 | natural | 17/21 (81.0%) | 6/8 | 92 / 92 | 0 |
|
||||
| 첫 실행, 정리 단계 실패 | retained | 21/21 (100%) | 8/8 | 106 / 105 | 1 |
|
||||
| 수정 후 전체 성공 | natural | 16/21 (76.2%) | 5/8 | 55 / 55 | 0 |
|
||||
| 수정 후 전체 성공 | retained | 20/21 (95.2%) | 7/8 | 65 / 64 | 1 |
|
||||
|
||||
최종 실행에서 내보낸 **120개 레코드, 33,318 bytes 전부**의 원문·해시·가상 주소·VAD 범위가
|
||||
재읽기와 일치했습니다. 정답과 대조 가능한 방향성 후보 링크 316개에서 잘못된 연결 0개,
|
||||
대조 불가능한 링크 0개를 관측했습니다. 이 수에는 복사본 간 연결이 포함되며 316개의 고유
|
||||
요청·응답 쌍을 의미하지 않습니다. 첫 실행은 198개 레코드·80,401 bytes와 링크 550개를
|
||||
대조했습니다. 두 실행 모두 각 조건에서 동일 PID 내 완전한 도구 요청·응답 쌍이 존재했습니다.
|
||||
|
||||
최종 실행의 동일 PID 내 메시지/쌍은 natural 클라이언트 14개/5쌍, 서버 7개/1쌍,
|
||||
retained 클라이언트 18개/6쌍, 서버 9개/2쌍입니다. retained의 합집합 7쌍을 한 프로세스에서
|
||||
7쌍이 모두 복원됐다는 뜻으로 읽으면 안 됩니다.
|
||||
|
||||
두 실행의 차이는 관측 결과이며 원인을 분리하는 실험은 수행하지 않았습니다. 특히 프레임을
|
||||
보관한 조건도 두 번째 실행에서는 1개 메시지를 찾지 못했습니다. 이 결과만으로 누락 원인을
|
||||
메모리 해제·paging·수집 누락·스캐너 중 하나로 확정하지 않습니다. 전체 실행 성공 조건은
|
||||
100% 복원이 아니라 원문 검증과 동일 PID의 실제 요청·응답 복원입니다.
|
||||
|
||||
최종 코드의 테스트 126개와 Ruff 검사·포맷 검사가 통과했습니다.
|
||||
[Ubuntu/Windows × Python 3.10/3.12의 네 CI 조합](https://github.com/Kowntaewook/MCPTrace/actions/runs/40459143849)도 통과했습니다.
|
||||
|
||||
첫 실행도 메시지 복원과 원문 대조는 통과했지만, 검증기가 파일 핸들을 닫지 않아 마지막
|
||||
RAM 파일 삭제가 Windows `WinError 32`로 실패했습니다. 첫 실행의 `manifest.json`에는
|
||||
정리 전에 기록한 `passed`가 남아 있으므로 **첫 실행 전체를 성공으로 해석하면 안 됩니다.**
|
||||
Volatility 레이어를 의존성 역순으로 닫고, 정리까지 끝난 뒤 성공을 기록하도록 수정했습니다.
|
||||
검증 예외가 발생할 때도 실제 FileLayer 핸들이 닫히는 회귀 테스트를 추가했습니다.
|
||||
|
||||
## 실험 조건과 해석
|
||||
|
||||
독립된 클라이언트·서버 쌍 두 개, 총 Python 프로세스 네 개를 동시에 유지했습니다.
|
||||
각 쌍은 initialize, initialized 알림, tools/list와 echo_marker 도구 호출 8회를 수행합니다.
|
||||
정답은 조건별 21개 논리 메시지(요청 10개, 응답 10개, 알림 1개)입니다.
|
||||
도구의 실제 응답에서 입력 문자열·실험 UUID·순번·서버 PID를 확인했습니다.
|
||||
입력은 ASCII, 한글·이모지, 이스케이프·줄바꿈·중괄호, 2 KiB 문자열, 중복 텍스트 등을 포함합니다.
|
||||
|
||||
- `natural`: 전송/수신 경계에서 정답 로그를 기록하지만 직렬화 프레임을 별도 목록으로 보관하지 않습니다.
|
||||
로깅으로 생성된 복사본이 남을 수 있으므로 계측되지 않은 일반 클라이언트와 같은 조건은 아닙니다.
|
||||
- `retained`: 실제 통신 프레임 21개를 메모리에 보관하는 유리한 양성 대조군입니다.
|
||||
전송하지 않은 tools/call JSON 하나도 보관합니다. 이것을 실제 통신 정답에는 포함하지 않습니다.
|
||||
|
||||
메시지 복원 수는 두 엔드포인트에서 찾은 결과의 **합집합에서 중복을 제거한 값**입니다.
|
||||
메모리 복사본은 서로 다른 증거 레코드로 보존하며 복원 메시지 수를 늘리지 않습니다.
|
||||
요청·응답 쌍도 두 엔드포인트 합집합과 동일 PID 내 발견을 따로 집계합니다.
|
||||
각 조건의 클라이언트·서버 PID별 수치는 보고서의 `comparison.json`에 있습니다.
|
||||
|
||||
정답 대조는 JSON 키 순서와 공백을 정규화한 메시지 객체 기준입니다. 수신 정답은 SDK가 파싱한
|
||||
객체를 재직렬화한 것으로, 파이프 원본 바이트 캡처가 아닙니다. 원문 바이트 검증은 별도로
|
||||
덤프의 해당 가상 주소를 `pad=False`로 다시 읽어 수행했습니다. 같은 Volatility의 native
|
||||
레이어를 사용한 재읽기이며, 다른 포렌식 엔진과의 교차 검증은 아닙니다.
|
||||
|
||||
비전송 대조군도 복원됐습니다. 따라서 **MCP 형식의 JSON이 메모리에 존재한다는 사실만으로
|
||||
실제 전송·공격·도구 실행을 입증할 수 없습니다.** 통신 로그와 일치하는 레코드 비율을
|
||||
일반적인 탐지 정밀도로 표현하지 않습니다. 후보 연결 오류 0도 이 단일 세션·고유 ID의 작은
|
||||
통제 집합에서 대조 가능한 연결에 한정됩니다. `ambiguous-id` 표시와 복사본은 유지됩니다.
|
||||
|
||||
## 환경·수집·검사 범위
|
||||
|
||||
- Windows Server 2022 x64 `10.0.20348`, Python `3.12.10`, `volatility3==2.28.2`.
|
||||
- 공식 Python SDK `mcp==1.26.0`, stdio, 실제 협상 프로토콜 `2025-11-25`.
|
||||
- MCPTrace `0.2.0`; 최종 실행 커밋 `14a8947c388f10c559b406f5d3bf783265d29705`.
|
||||
- [공식 WinPmem 배포 바이너리](https://github.com/Velocidex/WinPmem/releases/download/v4.0.rc1/go-winpmem_amd64_1.0-rc2_signed.exe).
|
||||
SHA-256: `86691bb4af2c17dd9ec4834c04a99ad51e04f780a07d1b05bc382a5d1892e0c4`.
|
||||
서명 정책·보안 설정을 변경하지 않고 드라이버 설치·수집·제거를 수행했습니다.
|
||||
|
||||
최종 실행의 RAM은 8,584,425,472 bytes이고, 이미지 논리 크기는
|
||||
11,811,160,064 bytes입니다. 이미지 SHA-256:
|
||||
`22027df47f06eec202e2d25c9fd40b996a1bc6374f158b035e9245764af3edb6`.
|
||||
수집 시작/종료는 2026-10-27 06:07:11.326 / 06:08:08.407 UTC로 약 57.08초입니다.
|
||||
각 조건의 마지막 정답 메시지 기록부터 수집 시작까지 약 0.089초입니다.
|
||||
첫 실행은 수집 약 40.56초, 마지막 메시지부터 시작까지 약 0.085초였습니다.
|
||||
|
||||
| 조건·역할 | PID | VAD 수 | 읽은 bytes | 읽지 못한 bytes | 내보낸 레코드 |
|
||||
| --- | ---: | ---: | ---: | ---: | ---: |
|
||||
| natural client | 5752 | 141 | 25,849,856 | 4,441,501,696 | 39 |
|
||||
| natural server | 3980 | 145 | 20,398,080 | 4,449,112,064 | 16 |
|
||||
| retained client | 4552 | 141 | 25,763,840 | 4,441,587,712 | 46 |
|
||||
| retained server | 6784 | 146 | 22,634,496 | 4,463,456,256 | 19 |
|
||||
|
||||
총 573개 VAD에서 94,646,272 bytes를 읽었습니다.
|
||||
모든 대상에서 error/skip이 없고, 바이트·레코드·앵커·후보 제한에 도달하지 않았으며 잘못된 영역은 0입니다.
|
||||
내부 candidate_records는 126개, MCP 관련성 필터 후 relevant/displayed_records는 120개입니다.
|
||||
원문 검증과 정답 비교의 분모는 내보낸 120개입니다.
|
||||
|
||||
물리 주소 간 빈 구간을 포함한 sparse raw 이미지이므로 파일 논리 크기가 설치 RAM보다 큽니다.
|
||||
물리 메모리 수집은 시간이 걸리는 live acquisition이며 단일 시점의 원자적 스냅샷이 아닙니다.
|
||||
호출 직후 수집을 시작하고 수집 동안 추가 도구 호출 없이 프로세스를 유지했습니다.
|
||||
지연 시간이나 메모리 부하를 달리한 실험이 아니므로 흔적의 보존 기간을 추정하지 않습니다.
|
||||
|
||||
`windows.info.Info`에서 심볼을 준비한 뒤 MCPTrace와 원문 재읽기는 offline으로 실행했습니다.
|
||||
선택한 네 PID의 VAD를 기본 설정으로 검사했고 크기/레코드 제한을 임의로 늘리지 않았습니다.
|
||||
`unreadable_bytes`에는 예약되어 사용하지 않는 주소 공간도 포함됩니다.
|
||||
RAM 해시는 분석 전후 같았으며, 전체 덤프는 VM 내부에서 분석 후 삭제했습니다.
|
||||
|
||||
## 재현 자료와 남은 범위
|
||||
|
||||
[실행 하네스와 명령](../validation/windows_positive/README.md),
|
||||
[수동 실행 워크플로](../.github/workflows/windows-positive-memory.yml)를 제공합니다.
|
||||
저장소에는 재현 코드와 집계 결과를 기록합니다. Actions 결과 아티팩트에는 측정 JSON,
|
||||
정답 메시지, 정답 또는 명시적 비전송 대조군과 일치한 추출 레코드, 수집/분석 로그가 있으며
|
||||
[최종 아티팩트](https://github.com/Kowntaewook/MCPTrace/actions/runs/40459138175/artifacts/12713857072)의
|
||||
보관 만료는 2026-11-03입니다. ZIP SHA-256은
|
||||
`abfdbbea869bc47c8dfac01bfaa515882d8204d5914a62abf70ce68851689a5e`입니다. RAM 이미지나 미분류 후보 원문은 업로드하지 않습니다.
|
||||
RAM에서 추출한 원문을 포함하는 결과 ZIP은 저장소에 추가하지 않았습니다.
|
||||
덤프 원본을 보존하지 않았으므로 동일 이미지의 제3자 재분석은 불가능하며, 하네스로 새로운
|
||||
캡처를 만들어 반복 검증할 수 있습니다. 각 실행의 이미지 해시는 실행 결과의 식별자입니다.
|
||||
|
||||
이 결과는 **Windows Server 2022의 특정 Python SDK·stdio 조건에서 실제 MCP 메시지를
|
||||
추출할 수 있다는 양성 검증**입니다. Windows 11에서의 MCP 양성 검증, Claude Desktop 등
|
||||
실제 클라이언트, HTTP/SSE 전송, 장시간 지연·추가 부하, 다른 SDK, 다중 세션의 ID 재사용,
|
||||
부분 메시지·인자 복원율은 아직 평가하지 않았습니다. 공격 탐지율을 측정한 실험도 아닙니다.
|
||||
|
||||
기존 [Windows 11 공개 덤프 검사](windows-memory-validation.md)는 MCP 후보가 없었던 별도
|
||||
호환성·읽기 검증입니다. 그 결과와 이번 Server 2022 양성 검증을 구분합니다.
|
||||
@@ -40,7 +40,7 @@ WinPmem은 제작자가 제공한 서명된 실행 파일을 사용하고 SHA-25
|
||||
수행합니다. 실패를 성공/건너뛰기로 처리하지 않습니다.
|
||||
|
||||
GitHub Actions의 `Windows positive memory validation` 워크플로도 같은 하네스를 실행합니다.
|
||||
초기 검증 브랜치의 push로 실행하고, 기본 브랜치에 반영한 뒤에는 workflow_dispatch로 실행할 수 있습니다.
|
||||
기본 브랜치에 반영한 뒤 Actions 화면에서 workflow_dispatch로 수동 실행할 수 있습니다.
|
||||
실제 덤프는 일회용 VM 안에서만 분석하고 종료 시 삭제합니다. 전체 RAM이나 미분류 후보 원문은
|
||||
업로드하지 않으며 정답 메시지·대조군과 일치한 아티팩트, 측정값, 수집/분석 로그만 7일 보관합니다.
|
||||
|
||||
@@ -55,4 +55,5 @@ GitHub Actions의 `Windows positive memory validation` 워크플로도 같은
|
||||
성공 조건은 실제 통신한 도구 요청·응답 한 쌍 이상이 동일 PID에서 복구되고, 내보낸 원문이
|
||||
재읽기 대조를 통과하며, 정답과 대조할 수 있는 연결에 오류가 없는 것입니다. `retained`만 성공해도
|
||||
전체 실험은 실행 가능성을 확인한 것으로 기록되므로 **반드시 natural/retained 수치를 나눠 읽어야 합니다.**
|
||||
현재 문서는 실행 절차이며, 실제 실행 결과는 실행한 Actions 기록과 결과 보고서로 확인합니다.
|
||||
실제로 수행한 Windows Server 2022 캡처와 조건별 수치는
|
||||
[양성 검증 보고서](../../docs/windows-positive-memory-validation.md)에 기록했습니다.
|
||||
|
||||
Reference in New Issue
Block a user