
Cisco ASA의 lina 바이너리에 대한 체계적인 리버스 엔지니어링을 통해 CVE-2025-20333 및 CVE-2025-20362를 포함한 메모리 손상 취약점을 발견하고 분석하며, 원격 코드 실행 프리미티브를 찾는 데 중점을 둡니다.
lina의 전체 커버리지 리버스 엔지니어링작성일: 2026-08-12
대상: lab_asav9-12-4-67/lina (ASAv 9.12(4)67, ELF x86-64, PIE; Ghidra 이미지 베이스 0x100000; 함수 112,687개, 매핑 약 167MB, 심볼 642,707개)
트랙 목표: lina 바이너리에 대한 체계적이고 완전한 RE 커버리지 — 지금까지 수행된 가설 기반 표적 RE를 보완하며 — 랩이 아직 찾지 못한 프리미티브를 사냥하기 위한 것이다(20362+20333에 대한 실제 환경 인증 없는 루트 RCE가 입증되었으므로, 그것은 존재한다).
이전의 모든 RE는 **표적 기반(targeted)**이었다(폴트 PC 디컴파일, 문자열 앵커 xref 탐색, 바인딩 범위 스윕). 그 결과 감사된 모든 범위(H4-1/2/3/4, tostring(userdata) 리플렉션, SSH/SNMP/IKE %p, 대체 오버플로 패밀리, 생존 오라클)가 종결(close)되었다 — ../RCE_BLOCKERS.md, ../NEW_ROADS_TO_CODE_EXECUTION.md 참조. 이러한 종결은 범위별로 이루어진 것이다. 112k 함수 바이너리의 가 바로 APT가 찾지 못한 프리미티브가 존재해야 할 곳이다. 이 트랙은 "다음 표면 추측"을 로 대체한다.
임계 경로와의 관계: 알려진 체인의 난관(hard gate)은 여전히 **P0(실시간 원격 정보 유출)**이다. CIFS readdir 오버리드(Step 19i, 4바이트 윈도우)는 실증적으로 확인된 유일한 유출이며 전경(foreground) 실증 트랙으로 유지된다. LINA_FULL_RE는 체계적 헤지이다: 감사되지 않은 코드에서 더 나은 유출/프리미티브를 찾거나, 존재하지 않음을 증명하는 것이다.
0x55..(lina) 또는 0x7f..(libc/heap) qword를 방출할 수 있는 네트워크 도달 가능 경로: 포맷 문자열 방출기(포인터에 대한 %p/%lx/%x), 오버리드(길이가 초기화된 데이터에 의해 제한되지 않는 경우), 힙 잔여물의 반사, 초기화되지 않은 버퍼 에코.memcpy/memmove/strcpy/strcat/sprintf/vsprintf/gets 클래스 및 사용자 정의 복사 루프), 모든 프로토콜 표면에 걸쳐(이미 소진된 WebVPN Lua 바인딩뿐만 아니라 — ../LINA_ALT_OVERFLOW_FAMILIES_RE.md 참조).csco_config)에서의 전방 호출 그래프를 구축하여 트리아지 히트를 실제로 와이어에서 도달 가능한지에 따라 순위를 매길 수 있게 한다.(사용자가 보류: CVE-2025-20363 싱크 사냥 — OSINT에 따르면 이는 유출을 소비하며 20333의 형제이다. ../CVE-2025-20363_OSINT.md 참조.)
| 단계 | 내용 | 도구 | 출력 |
|---|---|---|---|
| 1. 코퍼스 | 112,687개 전체 함수를 디스크로 일괄 디컴파일(함수당 .c 파일 하나, 주소별 샤딩) | Ghidra run_script_inline(Java, DecompInterface), 청크 단위 + 재개 가능 | corpus/<shard>/<addr>.c |
| 2. 기계적 트리아지 | 코퍼스에서 싱크 패턴(아래의 유출 + 오버플로 클래스)을 ripgrep으로 검색 | 로컬 스크립트, triage/ | 히트 테이블(CSV/MD) |
| 3. 도달 가능성 필터 | 네트워크 진입점에서 도달 가능한 함수의 히트만 유지 | Ghidra 호출 그래프(get_function_call_graph/script) + 진입점 시드 목록 | 순위가 매겨진 히트 목록 |
| 4. 딥다이브 | 순위가 매겨진 히트에 대한 표적 RE(기존 ghidra-re 서브에이전트 패턴) | ghidra-mcp | 이 폴더의 findings 문서 |
1단계는 순수 컴퓨팅 작업이다(추정 수 시간수 일, 무인 실행, 재개 가능). 23단계는 저비용/로컬 작업이다. 4단계는 유일하게 인간/LLM 작업량이 많은 단계이며 퍼널에 의해 범위가 제한된다.
Research notes/LINA_FULL_RE/
README.md — this file (master plan + status)
TRIAGE.md — sink-pattern catalog + reachability plan (stage 2/3 spec)
scripts/ — decompile + triage + driver scripts
corpus/ — stage-1 output: decompiled functions, sharded (corpus/2c/02c6cc80.c)
_progress.txt — resumable progress marker (done count, last address)
_errors.txt — per-function decompile failures
triage/ — stage-2/3 outputs (hit tables, ranked lists)
findings/ — stage-4 deep-dive writeups (one MD per confirmed candidate)
| 단계 | 상태 | 비고 |
|---|---|---|
| 1. 코퍼스 | 완료 2026-08-12(~19:03 UTC-4) | 함수 111,997/111,997개, 오류 0건, corpus/에 548MB. scripts/decompile_all.py를 통해 4.3 fn/s 속도로 26,214초(~7.3시간) 소요(GhidraMCP batch_decompile, 호출당 20개 함수 상한) |
| 2. 트리아지 | 완료 2026-08-13 | scripts/triage_stage2.py. 클래스별 히트 테이블은 triage/*_hits.csv, 순위 조인은 triage/RANKED.md |
| 3. 도달 가능성 | 완료 2026-08-13(재실행, 시드 수정됨) | 코퍼스 call+ref 그래프(엣지 427,198개). 도달 가능 26,291/111,997(23.5%) — preauth 26,278 / admin 13 / post20362 0. 시드 수정: registrar 0317b4e0, session 0317c0a0(기존 030ab4e0/030ac0a0은 함수 시작점이 아님). 여전히 하한값(vtables)이다. |
| 4. 딥다이브 | 진행 중 2026-08-17 | L1 종결. L2 C-경로 GO(정적): WebVPN UCTE create_type3_message가 클램프 없이 공격자의 Type-2 TargetInfo를 복사하고, 유출은 Type-3 Authorization: NTLM을 타고 공격자 HTTP 서버로 되돌아간다(findings/L2_NTLM_C_PATH_TYPE3.md). Lua ntlm.parseType2는 휴면 상태의 쌍둥이다. O1/O5 프로토콜 패스 종결(정적): IKE/SSH/SNMP/EWS/PDTS 복사는 대상 크기 제한형(dest-sized), 전송측(send-side), 또는 이미 알려진 것이다(031af6d0 / 02ff2f30). O1 "기타(other)" 725건 종결(정적): 스택/글로벌/param+const 필터 → 새로운 대상 오버플로 GO 없음. 015a8b30은 클램프되지 않은 addrtype 헬퍼이며, 호출자는 AF 크기 4/0x10만 전달한다(findings/O1_OTHER_SWEEP.md). O2 종결(정적): 도달 가능한 복사 루프 605개, 새로운 대상 오버플로 GO 없음. FUN_02fd7270 = ucte_ntlm_authenticate_connection → L2 C-경로 GO와 동일한 create_type3_message(findings/O2_SWEEP.md). 다음: 랩 NTLM 프로브(post-20362) — 0x7f../0x55.. qword가 나타나면 유출 윈도우에서 CIFS를 능가한다. 선택적 정적 분석: O3/O4. |
재개/제어: 드라이버는 출력 파일이 이미 존재하는 함수를 건너뛴다 — 언제든 python3 scripts/decompile_all.py를 다시 실행하여 계속할 수 있다. 정상 종료: touch corpus/STOP. Ghidra 또는 MCP 플러그인이 재시작되면 드라이버를 다시 실행하기만 하면 된다.
발견된 플러그인 제약(2026-08-12): run_script_inline이 비활성화되어 있다(GHIDRA_MCP_ALLOW_SCRIPTS 미설정) → 코퍼스는 HTTP 배치 엔드포인트만 사용한다. batch_decompile은 ?functions=0x..,0x..,..를 GET 쿼리 매개변수로 받으며(JSON 본문이 아님), 응답을 경고 없이 20개 함수로 잘라낸다 → 드라이버 청크 크기 = 20.
list_functions가 반환한 그대로의 RVA이다(검증됨: corpus/02/02c6cc80.c = luaH_get = RVA 0x2c6cc80). 참고: GhidraMCP HTTP 플러그인은 RVA 스타일 주소를 보고하며, Ghidra VA = RVA + 0x100000이 아니다.../RCE_BLOCKERS.md / ../TODO.md를 인용할 것.0x55.. vs 0x7f.. vs 힙), 그리고 신뢰성 측면에서 CIFS readdir 프리미티브(Step 19i)를 능가하는지 여부.