整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          從JS文件中發(fā)現(xiàn)「認(rèn)證繞過(guò)」漏洞

          譯:h4d35

          預(yù)估稿費(fèi):120RMB

          投稿方式:發(fā)送郵件至linwei#360.cn,或登陸網(wǎng)頁(yè)版在線投稿

          前言


          本篇文章主要介紹了在一次漏洞懸賞項(xiàng)目中如何利用配置錯(cuò)誤挖到一個(gè)認(rèn)證繞過(guò)漏洞。

          從JS文件中發(fā)現(xiàn)認(rèn)證繞過(guò)漏洞


          本文內(nèi)容源自一個(gè)私有漏洞賞金計(jì)劃。在這個(gè)漏洞計(jì)劃中,接受的漏洞范圍限于目標(biāo)網(wǎng)站少數(shù)幾個(gè)公開的功能。基于前期發(fā)現(xiàn)的問(wèn)題(當(dāng)我被邀請(qǐng)進(jìn)這個(gè)計(jì)劃時(shí),其他人一共提交了5個(gè)漏洞),似乎很難再挖到新的漏洞。同時(shí),在賞金詳情中提到了這樣一句話:

          如果你成功進(jìn)入管理頁(yè)面,請(qǐng)立即報(bào)告,請(qǐng)勿在/admin中進(jìn)行進(jìn)一步的測(cè)試。

          然而,目標(biāo)網(wǎng)站中存在一個(gè)僅限于未認(rèn)證和未經(jīng)授權(quán)的用戶訪問(wèn)的管理頁(yè)面。當(dāng)我們?cè)L問(wèn)/login或/admin時(shí)會(huì)跳轉(zhuǎn)到https://bountysite.com/admin/dashboard?redirect=/。

          對(duì)登錄頁(yè)面進(jìn)行暴力破解也許是一個(gè)可行方案,但是我并不喜歡這種方式。看一下網(wǎng)頁(yè)源碼,沒什么有用的內(nèi)容。于是我開始查看目標(biāo)網(wǎng)站的結(jié)構(gòu)。似乎目標(biāo)網(wǎng)站的JS文件都放在少數(shù)幾個(gè)文件夾中,如/lib、/js、/application等。

          有意思!

          祭出神器BurpSuite,使用Intruder跑一下看能否在上述文件夾中找到任何可訪問(wèn)的JS文件。將攻擊點(diǎn)設(shè)置為https://bountysite.com/admin/dashboard/js/*attack*.js。注意,不要忘記.js擴(kuò)展名,這樣如果文件能夠訪問(wèn)則返回200響應(yīng)。確實(shí)有意思!因?yàn)槲艺业搅艘恍┛稍L問(wèn)的JS文件,其中一個(gè)文件是/login.js。

          訪問(wèn)這個(gè)JS文件https://bountysite.com/admin/dashboard/js/login.js,請(qǐng)求被重定向至管理頁(yè)面:) 。但是,我并沒有查看該文件的權(quán)限,只能看到部分接口信息。

          但是我并沒有就此止步。這看起來(lái)很奇怪,為什么我訪問(wèn)一個(gè).js文件卻被作為HTML加載了呢?經(jīng)過(guò)一番探查,終于發(fā)現(xiàn),我能夠訪問(wèn)管理頁(yè)面的原因在于*login*。是的,只要在請(qǐng)求路徑/dashboard/后的字符串中含有*login*(除了'login',這只會(huì)使我回到登錄頁(yè)面),請(qǐng)求就會(huì)跳轉(zhuǎn)到這個(gè)管理接口,但是卻沒有正確的授權(quán)。

          我繼續(xù)對(duì)這個(gè)受限的管理接口進(jìn)行了進(jìn)一步的測(cè)試。再一次查看了頁(yè)面源碼,試著搞清楚網(wǎng)站結(jié)構(gòu)。在這個(gè)管理接口中,有其他一些JS文件能夠幫助我理解管理員是如何執(zhí)行操作的。一些管理操作需要一個(gè)有效的令牌。我試著使用從一個(gè)JS文件中泄露的令牌執(zhí)行相關(guān)管理操作,然并卵。請(qǐng)求還是被重定向到了登錄頁(yè)面。我發(fā)現(xiàn)另外一個(gè)真實(shí)存在的路徑中也部署了一些內(nèi)容,那就是/dashboard/controllers/*.php。

          再一次祭出BurpSuite,使用Intruder檢查一下是否存在可以從此處訪問(wèn)的其他任何路徑。第二次Intruder的結(jié)果是,我發(fā)現(xiàn)幾乎不存在其他無(wú)需授權(quán)即可訪問(wèn)的路徑。這是基于服務(wù)器返回的500或者200響應(yīng)得出的結(jié)論。

          回到我在上一步偵察中了解到的網(wǎng)站結(jié)構(gòu)中,我發(fā)現(xiàn)這些路徑是在/controllers中定義的,通過(guò)/dashboard/*here*/進(jìn)行訪問(wèn)。但是直接訪問(wèn)這些路徑會(huì)跳轉(zhuǎn)到登錄頁(yè)面,似乎網(wǎng)站對(duì)Session檢查得還挺嚴(yán)格。此時(shí)我又累又困,幾乎都打算放棄了,但是我想最后再試一把。如果我利用與訪問(wèn)管理頁(yè)面相同的方法去執(zhí)行這些管理操作會(huì)怎么樣呢?很有趣,高潮來(lái)了:) 我能夠做到這一點(diǎn)。

          通過(guò)訪問(wèn)/dashboard/photography/loginx,請(qǐng)求跳轉(zhuǎn)到了Admin Photography頁(yè)面,并且擁有完整的權(quán)限!

          從這里開始,我能夠執(zhí)行和訪問(wèn)/dashboard/*路徑下的所有操作和目錄,這些地方充滿了諸如SQL注入、XSS、文件上傳、公開重定向等漏洞。但是,我沒有繼續(xù)深入測(cè)試,因?yàn)檫@些都不在賞金計(jì)劃之內(nèi),根據(jù)計(jì)劃要求,一旦突破管理授權(quán)限制,應(yīng)立即報(bào)告問(wèn)題。此外,根據(jù)管理頁(yè)面顯示的調(diào)試錯(cuò)誤信息可知,我之所以能夠訪問(wèn)到管理頁(yè)面,是因?yàn)閼?yīng)用程序在/dashboard/controllers/*文件中存在錯(cuò)誤配置。期望達(dá)到的效果是:只要請(qǐng)求鏈接中出現(xiàn)*login*,就重定向至主登錄頁(yè)面,然而,實(shí)際情況并不如人所愿。

          后記


          總之,這是有趣的一天!我拿到了這個(gè)漏洞賞金計(jì)劃最大金額的獎(jiǎng)勵(lì)。

          xios是什么?

          Axios 是一個(gè)基于 promise 的 HTTP 庫(kù),可以用在瀏覽器和 node.js 中。我們知道 Promise 是 js 異步的一種解決方案,它最大的特性就是可以通過(guò) .then 的方式來(lái)進(jìn)行鏈?zhǔn)秸{(diào)用。

          其實(shí)說(shuō)白了axios是對(duì)ajax的封裝,axios有的ajax都有,ajax有的axios不一定有,總結(jié)一句話就是axios是ajax,ajax不止axios。

          為什么選擇axios?

          1. vue的作者尤雨溪推薦使用axios.
          2. 符合前后端分離的趨勢(shì),及前端的MVVM的浪潮

          功能特點(diǎn):

        1. 在瀏覽器中發(fā)送XMLHttpRequests請(qǐng)求
        2. 在node.js中發(fā)送http請(qǐng)求
        3. 支持Promise API
        4. 攔截請(qǐng)求和響應(yīng)
        5. 轉(zhuǎn)換請(qǐng)求和響應(yīng)數(shù)據(jù)
        6. 取消請(qǐng)求
        7. 自動(dòng)轉(zhuǎn)換 JSON 數(shù)據(jù)
        8. 客戶端支持防御 XSRF
        9. 支持多種請(qǐng)求方式:

        10. axios(config)
        11. axios.request(config)
        12. axios.get(url, [, config])
        13. axios.delete(url, [, config])
        14. axios.head(url, [, config])
        15. axios.post(url, [,data[,config] ])
        16. axios.put(url, [,data[,config] ])
        17. axios.patch(url, [,data[,config] ])
        18. Axios的基本使用

          axios的使用比較簡(jiǎn)單,文檔講得也非常清晰,你應(yīng)該先閱讀axios的官方文檔:axios文檔。

          在html頁(yè)面中直接引入使用:

          <script src="https://unpkg.com/axios/dist/axios.min.js"></script>

          Html頁(yè)面基本使用

          以下案例中的get請(qǐng)求地址為crmeb相關(guān)演示站地址,可用于測(cè)試獲取!

          1. 獲取一個(gè)get請(qǐng)求
          <script>
            const url = 'https://store.crmeb.net/api/pc/get_category_product'
            axios({
              url: url,
              method: 'get',  // 這里可以省略,默認(rèn)為get
            }).then(res => {
              // 返回請(qǐng)求到的數(shù)據(jù)
              console.log(res)
            }).catch(err => {
              // 返回錯(cuò)誤信息
              console.log(err)
            })  
          </script>
          1. 在get請(qǐng)求的url中傳參,只需要定義一個(gè)params:{}即可!
          <script>
            const url = 'https://store.crmeb.net/api/pc/get_category_product'
            axios({
              url: url,
              method: 'get',  // 這里可以省略,默認(rèn)為get
              // 這里的鍵值對(duì)會(huì)拼接成這樣url?page=1&limit=3
              params: {
                page: 1,
                limit: 3
              }
            }).then(res => {
              // 返回請(qǐng)求到的數(shù)據(jù)
              console.log(res)
            }).catch(err => {
              // 返回錯(cuò)誤信息
              console.log(err)
            })  
          </script>
          1. 發(fā)送一個(gè)post請(qǐng)求,與get請(qǐng)求類似,只需要將method改為post,定義一個(gè)data:{}即可,data中的數(shù)據(jù)則是服務(wù)器需要接收的字段數(shù)據(jù)!
          <script>
          axios({
            method: 'post',
            url: '/user/12345',
            data: {
              firstName: 'Fred',
              lastName: 'Flintstone'
            }
          }).then(res => {
              // 返回請(qǐng)求到的數(shù)據(jù)
              console.log(res)
            }).catch(err => {
              // 返回錯(cuò)誤信息
              console.log(err)
            });
          </script>
          1. 發(fā)送一個(gè)并發(fā)請(qǐng)求

          如果在開發(fā)中需要等到多個(gè)接口的數(shù)據(jù)同時(shí)請(qǐng)求到后才能繼續(xù)后邊的邏輯,那么即可使用并發(fā)請(qǐng)求,axios并發(fā)請(qǐng)求,使用all方法,all方法的參數(shù)為一個(gè)數(shù)組,數(shù)組的每個(gè)值可以為一次請(qǐng)求,請(qǐng)求完成后直接.then即可合并兩次請(qǐng)求的數(shù)據(jù),返回結(jié)果為一個(gè)數(shù)組!

          <script>
          axios.all([
              axios({
                  url: 'https://store.crmeb.net/api/pc/get_products',
                  params: {
                      page: 1,
                      limit: 20,
                      cid: 57,
                      sid: 0,
                      priceOrder: '', 
                      news: 0,
                  }
              }),
              axios({
                  url: 'https://store.crmeb.net/api/pc/get_company_info',
              })
          ]).then(results => {
              console.log(results)
          })
          </script>

          如果你想自動(dòng)把這個(gè)數(shù)組展開的話在then()方法中傳入axios.spread()方法即可,如下所示:

          <script>
          axios.all([
              axios({
                  url: 'https://store.crmeb.net/api/pc/get_products',
                  params: {
                      page: 1,
                      limit: 20,
                      cid: 57,
                      sid: 0,
                      priceOrder: '', 
                      news: 0,
                  }
              }),
              axios({
                  url: 'https://store.crmeb.net/api/pc/get_company_info',
              })
          ]).then(axios.spread((res1, res2) => {
              console.log(res1);
              console.log(res2);
          }))
          </script>

          但在使用vue組件化開發(fā)的時(shí)候一般我們會(huì)通過(guò)npm安裝,引入項(xiàng)目!

          組件化開發(fā)中使用

          1. 使用npm進(jìn)行安裝
          npm install axios --save

          一般在實(shí)際項(xiàng)目中我們并不會(huì)像上邊這樣直接去使用axios請(qǐng)求數(shù)據(jù),而是將axios封裝在一個(gè)單獨(dú)的文件,這樣做的目的主要是用來(lái)抽取公共邏輯到一個(gè)配置文件里,對(duì)這些公共邏輯做一個(gè)封裝,即使某一天這個(gè)axios框架不維護(hù)了,或者出現(xiàn)了重大bug也不再修復(fù)的時(shí)候,我們可以只修改配置文件即可達(dá)到全局修改的目的,如果把每次請(qǐng)求邏輯都寫到對(duì)應(yīng)的組件中,那修改起來(lái)簡(jiǎn)直就是一個(gè)噩夢(mèng)!

          1. 封裝一個(gè)axios的請(qǐng)求文件request.js

          在項(xiàng)目的src目錄下創(chuàng)建一個(gè)network文件夾,再在其中創(chuàng)建一個(gè)request.js文件,路徑為:src/network/request.js

          // src/network/request.js
          
          // 引入axios
          import axios from 'axios'
          
          // 這里未使用default導(dǎo)出,是為了以后的擴(kuò)展,便于導(dǎo)出多個(gè)方法
          export function request(config){
              // 創(chuàng)建axios實(shí)例
              const instance = axios.create({
                  // 這里定義每次請(qǐng)求的公共數(shù)據(jù),例如全局請(qǐng)求頭,api根地址,過(guò)期時(shí)間等
                  // 具體參數(shù)可參考axios的官方文檔
                  baseURL: 'http://demo26.crmeb.net/api',
                  timeout: 5000
              })
              
              // 攔截請(qǐng)求,如果獲取某個(gè)請(qǐng)求需要攜帶一些額外數(shù)據(jù)
              instance.interceptors.request.use(
                  config => {
                      console.log(config);
                      return config;
                  }, err => {
                      console.log(err);
                  })
                  
              // 攔截響應(yīng)
              instance.interceptors.response.use(
                  res => {
                      console.log(res)
                      return res.data
                  }, err => {
                      console.log(err)
                  }
              )
              
              // 發(fā)送請(qǐng)求
              return instance(config)  
          1. 使用我們封裝的request請(qǐng)求

          一般我們會(huì)將所有的請(qǐng)求放在一個(gè)api.js文件中,將每次請(qǐng)求封裝為一個(gè)方法,比如我這里會(huì)在request.js的同目錄創(chuàng)建一個(gè)api.js文件封裝我們所有的請(qǐng)求。

          import { request } from '../api/request'
          
          // 獲取分類
          export const getHomeCategory = () => {
              return request({
                  url: '/category'
              })
          }
          
          // 獲取banner圖
          export const getHomeBanner = () => {
              return request({
                  url: '/pc/get_banner'
              })
          }

          之后再在組件中引入調(diào)用導(dǎo)出的相關(guān)接口方法即可,如:

          import { getHomeBanner } from "../network/api"
          
          getHomeBanner().then(res => {
          	console.log(res)
          })

          以上就是一個(gè)簡(jiǎn)單的封裝,其中有個(gè)攔截請(qǐng)求和攔截響應(yīng),可能很多初學(xué)的人理解起來(lái)有點(diǎn)吃力,我在這里以個(gè)人淺見闡述,希望能帶給你些許啟發(fā)!

          何為攔截器?

          還是發(fā)揮閱讀理解能力,攔截?cái)r截其實(shí)就是此路是我開,此樹是我栽,要想過(guò)此路,留下買路錢,攔截請(qǐng)求就是比如某些請(qǐng)求需要攜帶一些額外的信息才能訪問(wèn),實(shí)際項(xiàng)目中最常見的就是需要登錄后才能查看的信息,請(qǐng)求中就必須攜帶token才能訪問(wèn),就可以在這里處理,還有攔截響應(yīng),比如請(qǐng)求到數(shù)據(jù)之后,發(fā)現(xiàn)不符合要求,先攔下來(lái)處理一下,再返回給前端,這就是一個(gè)攔截器的基本工作流程!

        19. axios有一個(gè)全局?jǐn)r截的方式:axios.interceptors()
        20. 攔截成功后必須return返回,否則數(shù)據(jù)無(wú)法請(qǐng)求到
        21. 如下所示:

            // 攔截請(qǐng)求,如果獲取某個(gè)請(qǐng)求需要攜帶一些額外數(shù)據(jù)
              instance.interceptors.request.use(
                  config => {
                      console.log(config);
                      return config;
                  }, err => {
                      console.log(err);
                  })
                  
              // 攔截響應(yīng)
              instance.interceptors.response.use(
                  res => {
                      console.log(res)
                      return res.data
                  }, err => {
                      console.log(err)
                  }
              )

          axios還為我們提供了一些全局配置,如下:

          axios.defaults.baseURL = 'https://api.example.com';
          axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
          axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

          當(dāng)然也可以將其配置在我們之前創(chuàng)建的axios實(shí)例中,使其只作用于某個(gè)實(shí)例!

          然后來(lái)看一下 axios 的所有配置信息:

          數(shù)據(jù)來(lái)自axios中文文檔

          各種請(qǐng)求體格式中,文件上傳是比較特殊的一種,通常其content-type請(qǐng)求頭為multipart/form-data,可以提交文本與文件混合的請(qǐng)求數(shù)據(jù)。這一節(jié)我們通過(guò)兩個(gè)例子來(lái)看看postman怎么調(diào)用文件上傳的請(qǐng)求。

          文件格式請(qǐng)求體實(shí)現(xiàn)請(qǐng)求

          請(qǐng)求示例1:只包含文件格式參數(shù)的接口

          以特斯汀學(xué)院自動(dòng)化測(cè)試平臺(tái)項(xiàng)目上傳頭像圖片的接口為例。

          項(xiàng)目地址:http://www.testingedu.com.cn/mypro/#/login

          接口地址:http://www.testingedu.com.cn/mypro/api/user/setavatar

          從接口抓包信息中可以看到,Content-Type為multipart/form-data; boundary=----WebKitFormBoundarysArkjRsb6TbgepSl,其中的boundry是作為請(qǐng)求體多個(gè)部分的參數(shù)的分割線邊界的,從請(qǐng)求體內(nèi)容第一行就可以看到這個(gè)分割線的值。

          在Postman中完成該文件上傳接口的調(diào)用時(shí),需要選擇body中的form-data,在填寫內(nèi)容時(shí)注意將鼠標(biāo)移到key列輸入框的右側(cè),會(huì)出現(xiàn)一個(gè)下拉框,可以選擇參數(shù)類型為Text或者File,針對(duì)文件參數(shù)選擇File,并填寫抓包信息中獲取到的鍵名file,最后在VALUEL列中選擇要上傳的文件。

          設(shè)置完請(qǐng)求體之后查看請(qǐng)求頭可以看到Content-Type的值已經(jīng)被自動(dòng)設(shè)置為multipart/form-data,而boundry字段則是在請(qǐng)求發(fā)送時(shí)計(jì)算得到。所以使用postman完成文件上傳接口請(qǐng)求時(shí),并不需要額外設(shè)置Content-Type。

          要注意,設(shè)置頭像接口需要前置調(diào)用測(cè)試平臺(tái)登錄接口之后才能正常完成請(qǐng)求,否則會(huì)提示缺少user_id字段,在請(qǐng)求前先參考json格式請(qǐng)求章節(jié)的示例登錄接口http://www.testingedu.com.cn/mypro/api/user/login完成登錄操作之后再調(diào)用設(shè)置頭像接口。

          這里,我們完成了一個(gè)只有文件參數(shù)的文件上傳接口,接下來(lái),再看一個(gè)除了文件參數(shù),還有文本格式參數(shù)的文件上傳接口。

          請(qǐng)求示例2:同時(shí)包含文件與文本格式請(qǐng)求的接口

          以特斯汀電商項(xiàng)目個(gè)人信息修改頭像的接口為例。

          項(xiàng)目地址:http://www.testingedu.com.cn:8000/Home/User/info.html

          接口地址:http://www.testingedu.com.cn:8000/index.php/home/Uploadify/imageUp/savepath/head_pic/pictitle/banner/dir/images.html

          從抓包信息中可以看到,請(qǐng)求體中包含了多段由boundry分割開的請(qǐng)求參數(shù)內(nèi)容,除了上傳的文件參數(shù)之外,還包含了部分純文本內(nèi)容的參數(shù)。

          將fiddler切換到WebForms格式顯示則可以看到完整的參數(shù)列表,每一行的參數(shù)名為其中name指定的字段。

          在Postman中完成請(qǐng)求時(shí),針對(duì)同時(shí)出現(xiàn)文件和文本格式的請(qǐng)求,在選擇填寫的參數(shù)類型時(shí),根據(jù)對(duì)應(yīng)類型進(jìn)行選擇并填寫。

          由此可以看到,文件上傳格式處理時(shí),在Postman里只需要按照請(qǐng)求參數(shù)格式選擇并逐個(gè)填寫,并不復(fù)雜。

          至此,在Postman中完成常見的幾種請(qǐng)求體格式的請(qǐng)求操作都已實(shí)現(xiàn)。

          回顧總結(jié)一下,常用的接口測(cè)試請(qǐng)求體的編輯格式包括如下幾種,和Content-Type頭域分別對(duì)應(yīng):

          • application/x-www-form-urlencoded:url編碼格式 即 鍵=值&鍵=值格式

          在Postman中使用x-www-form-urlencoded進(jìn)行填寫,或者使用raw格式填寫,再手動(dòng)設(shè)置Content-Type

          • application/json: json格式 即 {"鍵":值,"鍵":值} 格式

          在Postman中使用raw格式選擇json完成填寫。

          • text/xml:xml格式 即 <鍵>值<鍵>格式

          在Postman中使用raw格式填寫,再手動(dòng)設(shè)置Content-Type為text/xml。

          • multipart/form-data: 文本與文件混合格式表單,通常用于文件上傳

          在Postman中使用form-data填寫,注意文件和文本類型格式,分別選擇Text和File格式。


          主站蜘蛛池模板: 亚洲欧美日韩中文字幕一区二区三区 | 3d动漫精品成人一区二区三| 91久久精品无码一区二区毛片| 国产精品一区二区香蕉| 国产精品一区二区毛卡片| 国产亚洲综合一区柠檬导航| 无码人妻一区二区三区免费视频 | av无码人妻一区二区三区牛牛| 精品免费国产一区二区| 亚洲熟女综合一区二区三区| 精品深夜AV无码一区二区老年| 国产成人AV一区二区三区无码| 中文字幕一区二区三区视频在线| 亚洲人成网站18禁止一区| 久久久国产精品亚洲一区| 国产精品视频无圣光一区| 亚洲成AV人片一区二区密柚 | 亚洲一区二区三区深夜天堂| 日韩一区二区三区无码影院| 国产高清一区二区三区视频| 国产成人无码AV一区二区在线观看| 中文字幕日韩一区二区不卡 | 怡红院一区二区在线观看| 日韩最新视频一区二区三| 成人区精品一区二区不卡亚洲| 少妇无码一区二区二三区| 日本成人一区二区| 中文字幕AV无码一区二区三区| 日韩精品一区在线| 成人精品一区二区三区中文字幕| 久久久av波多野一区二区| 99无码人妻一区二区三区免费| 日本一区二区高清不卡| 午夜福利一区二区三区在线观看| 黑巨人与欧美精品一区| 一区二区三区观看免费中文视频在线播放 | 久久久老熟女一区二区三区| 亚洲日本一区二区三区| 狠狠综合久久av一区二区| 综合久久一区二区三区| 久久精品国产一区二区三 |