iT邦幫忙

2023 iThome 鐵人賽

DAY 4
0
Security

一天一個漏洞介紹系列 第 4

CVE-2023-41349 externally-controlled format string

  • 分享至 

  • xImage
  •  

介紹

這次挑了一個在台灣電腦網路危機處理暨協調中心看到的漏洞,是跟ASUS路由器的OpenVPN設定有關,在匯出設定時有可能會觸發此漏洞,不過並沒有詳細描述如何執行
匯出OpenVPN設定

影響產品

RT-AX88U

影響版本

小於3.0.0.4_388_23748所有版本

原理

今天會著重介紹在externally-controlled format string本身而不是漏洞內容(TVN也沒有公佈太多細節🥲)
先從一段Express.js的程式開始

const app = require("express")();

app.get("/unauthorized", function handler(req, res) {
  let user = req.query.user;
  let ip = req.connection.remoteAddress;
  console.log("Unauthorized access attempt by " + user, ip);
});
const server = app.listen(8081, function () {
  const host = server.address().address;
  const port = server.address().port;
  console.log("Example app listening at http://%s:%s", host, port);

});

上面這段Code會開一個Endpoint在/unauthorized,並且將訪問者的User跟IP打印出來
如果我們今天照著他規則走的話(在這邊假設User id是87)
https://ithelp.ithome.com.tw/upload/images/20230918/20162653jW5iv4oeid.png
後端就會看到對應的紀錄
https://ithelp.ithome.com.tw/upload/images/20230918/20162653mXvOrxLI7U.png
那如果今天故意丟一個他沒想到的輸入,比如說%d
https://ithelp.ithome.com.tw/upload/images/20230918/20162653g6451YUVFI.png
這個時候再到後端看,User變成NaN了🤯
https://ithelp.ithome.com.tw/upload/images/20230918/20162653inU0PxzSdH.png
如果這種情況發生在log紀錄可能還有其他地方可以trace,但是如果是在商業邏輯處理或者驗證時出現的話,可能會發生想不到的災難。
回到上面的Code,這是因為我們在User帶入了%d, 因此與前面的字串合併了從Unauthorized access attempt by 變成Unauthorized access attempt by %d
那麼大家都知道%d代表這個地方要塞的是一個數字,但是我們只剩下一個IP這個參數可以用,但是他一定不是數字,所以就會被轉成NaN

// 這串也會吐NaN回來
Number(req.connection.remoteAddress)

我們原本想要記錄下來的事件也消失了💨

解決

既然知道了輸入可能會被惡意更換成沒辦法預期的,那麼我們有沒有辦法可以預防?
當然有,就Express.js能使用的,有下面兩個

他們不僅可以提供驗證傳入資料格式正確性,也可以在需要的時候進行額外檢查(像是User ID是否存在、檢查額外權限等)
我們這次用Express Validator示範

const express = require("express");
const app = require("express")();
const { query, validationResult } = require('express-validator');

// Parse incoming request into json
app.use(express.json());

app.get("/unauthorized", query('user').isInt(),  function handler(req, res) {
  // Validate input
  const validResult = validationResult(req);
  let user = req.query.user;
  let ip = req.connection.remoteAddress;
  // Empty means there's no validation error
  if (validResult.isEmpty()) {
    console.log("Unauthorized access attempt by " + user, ip);
    return res.status(403).send({ msg: 'Unauthorized' });
  }
  return res.status(400).send({ errors: validResult.array() });
});
const server = app.listen(8081, function () {
  const host = server.address().address;
  const port = server.address().port;
  console.log("Example app listening at http://%s:%s", host, port);
});

在上面我們在/unauthorizedpath後面加上了檢查user必須為number的條件(這邊後面你想檢查多少欄位就可以接多少)
這次,%d沒有辦法順利通過了,得到的會是express-validator傳回來的錯誤
https://ithelp.ithome.com.tw/upload/images/20230918/20162653CB7t3DD271.png

參考


上一篇
CVE-2023-40580 Information leak
系列文
一天一個漏洞介紹4
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言