PictShare < 3.7.1의 info API를 통한 민감 정보 노출(CWE-522). PoC + 권고문 작성.
info API를 통한 민감 정보 노출허가된 보안 연구. 방어 및 교육 목적으로만 사용하는 PoC입니다.
PictShare의 /api/info/<hash> 엔드포인트는
업로드된 모든 파일에 대한 전체 원시 메타데이터 객체를 반환합니다 — 여기에는 삭제를
승인하는 비밀 delete_code, 그리고 업로더의 IP, User-Agent, 원격 포트, SHA-1이 포함됩니다.
파일의 (공개적으로 보이는) 해시를 알고 있는 인증되지 않은 공격자는 해당 파일의
delete_code를 읽은 다음 호스팅된 임의 파일을 영구적으로 삭제할 수 있습니다.
| CVE | CVE-2026-104051 |
| 제품 | PictShare (자체 호스팅 이미지/미디어 호스트) |
| 영향 받는 버전 | >= 2.0.0, < 3.7.1 |
| 수정된 버전 | v3.7.1 |
| 취약점 | 불충분하게 보호된 자격 증명 (CWE-522) → 임의 파일 삭제 + 프라이버시 침해 |
| 권한 | 없음 (인증되지 않음) |
| CVSS 3.1 | 8.2 HIGH — AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:H |
| CVSS 4.0 | 8.8 HIGH — AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:N/VA:H |
| 발견자 | Alisher Qarshibayev |
| 권고문 | VulnCheck |
API::info()는 해시를 조회한 뒤 getMetadataOfHash()를 그대로 반환합니다 — 필드
화이트리스트가 없습니다:
// src/inc/api.class.php (< 3.7.1)
public function info()
{
$hash = $this->url[1] ?? '';
if (!$hash) return ['status' => 'err', 'reason' => 'Missing hash'];
if (!isExistingHash($hash)) return ['status' => 'err', 'reason' => 'Hash not found'];
return getMetadataOfHash($hash); // <-- raw meta.json, includes delete_code, ip, useragent
}
그리고 info 라우트 이전의 유일한 관문인 checkPermissions()는 신원이 아니라 파일
시스템 쓰기 가능 여부를 검사하므로, info는 인증 없이 접근할 수 있습니다:
public function checkPermissions()
{
if (!isFolderWritable(getDataDir())) throw new Exception('Data directory not writable');
else if (!isFolderWritable(ROOT.DS.'tmp')) throw new Exception('Temp directory not writable');
}
반환되는 메타데이터에는 delete_code가 포함되며, 삭제 API는 이를 유일한 승인 비밀로
받아들입니다:
// src/inc/api.class.php delete()
$correctCode = getDeleteCodeOfHash($hash);
if ($correctCode !== $code && $masterCode !== $code)
return ['status' => 'err', 'reason' => 'Invalid delete code'];
deleteHash($hash);
파일 해시는 공개되어 있으므로(모든 공유 이미지 URL에 나타납니다), 전체 공격 체인 —
info를 통해 코드를 유출한 뒤 delete를 통해 삭제 — 은 사용자가 이미 공유한 URL
외에는 아무것도 필요로 하지 않습니다.
python3 poc.py --url https://pics.example.com --hash <public_file_hash>
# add --delete to actually exercise the deletion (destructive) step
예상 결과:
[*] GET /api/info/<hash>
[+] Leaked metadata via info API:
delete_code : 7f3a9c1e... <-- SECRET, should never be exposed
ip : 203.0.113.44 <-- uploader privacy leak
useragent : Mozilla/5.0 ...
remote_port : 51544
sha1 : da39a3ee...
[+] CVE-2026-104051 confirmed: delete_code exposed to unauthenticated caller
[i] With --delete: GET /api/delete/<leaked_code>/<hash> -> {"status":"ok"}
poc.py를 참조하세요. 삭제는 선택 사항(--delete)이므로 기본 실행은
읽기 전용이며 비파괴적입니다.
PictShare 3.7.1로 업그레이드하세요 (수정 커밋 ce5fc47).
info()는 이제 엄격한 화이트리스트(mime, size, hash, sha1, uploaded)를 반환하며
더 이상 delete_code, ip, useragent, remote_port를 유출하지 않습니다. 일반 지침:
API 응답은 필드를 명시적으로 화이트리스트해야 하며, 비밀과 공개 데이터를 혼합한 내부
레코드를 절대 직렬화해서는 안 됩니다.
관련: CVE-2026-104356 — 이 유출이 없더라도
delete_code는rand()로 생성되었기 때문에 예측 가능했습니다.
| 날짜 | 사건 |
|---|---|
| 2026-10-01 | 공개 공개, CVE 예약 및 게시 (VulnCheck), v3.7.1에서 수정 |
벤더에 책임 있게 공개하고 VulnCheck를 통해 조정했습니다. 이 PoC가 릴리스되기 전에 수정되었습니다. 방어 및 교육 목적으로 게시되었습니다.