追洞小組 | 實戰CVE-2020-7471漏洞

出品|MS08067實驗室(www.ms08067.com)git

本文做者:守拙(Ms08067實驗室追洞小組成員)github

1、漏洞名稱:

經過StringAgg(分隔符)的潛在SQL注入漏洞sql

2、漏洞編號:

CVE-2020-7471數據庫

3、漏洞描述:

Django 1.11.28以前的1.11.x、2.2.10以前的2.2.x和3.0.3以前的3.0.x版本容許SQL注入,若是不受信任的數據用做StringAgg分隔符(例如,在存在多行數據下載的Django應用程序中,使用用戶指定的列分隔符進行下載的場景)。經過向contrib.postgres.aggregates.StringAgg實例傳遞一個精心構造的分隔符,可能會破壞轉義並注入惡意SQL。django

4、影響版本:

Django 1.11.x < 1.11.28
Django 2.2.x < 2.2.10
Django 3.0.x < 3.0.3安全

5、漏洞分析

聚合函數StringAgg的delimiter參數未經任何轉義就嵌入到sql語句中,致使sql注入微信

6、實驗環境及準備:

1.數據庫:postgresql,版本無所謂,本文中使用kali虛擬機中自帶的數據庫,容許外部鏈接網絡

  • 修改以下文件,監聽全部端口
/etc/postgresql/12/main/postgresql.conf

  • 修改以下文件,容許外部鏈接
/etc/postgresql/12/main/pg_hba.conf

  • 重啓服務後,鏈接數據庫並建立測試數據庫
登錄:psql -U postgres -h [kali主機的IP]
建立測試數據庫:CREATE DATABASE test,後面poc中會用到
其餘postgresql語法能夠參考菜鳥教程

2.POC: https://github.com/Saferman/CVE-2020-7471,運行環境django3.0.2app

  • 安裝django3.0.2
    pip installdjango==3.0.2
  • 使用pycharm調試POC代碼,參考POC中的readme文檔

  • 初始化數據庫後能夠用pgadmin鏈接看下,test數據庫中應該有以下表

  • Vul_app_info表中應該以下字段和數據

7、復現步驟:

POC測試腳本中有兩個函數query()和query_with_evil(),前者用於模糊測試,後者用於注入點證實函數

1.模糊測試

  • 經過運行query()函數的異常捕獲能夠知道有兩個特殊字符讓程序產生了報錯(%和’)
  • 將程序中異常捕獲註釋掉,payload使用%和’單獨測試

  • 經過報錯能夠看出分號沒有轉義致使sql語句報錯,並直接在報錯信息返回了拼接後的sql語句。將斷點打在執行sql語句併產生報錯的代碼塊去看完整的sql

  • 獲得程序運行的實際sql語句
SELECT "vul_app_info"."gender", STRING_AGG("vul_app_info"."name", \'\'\') AS "mydefinedname" FROM "vul_app_info" GROUP BY "vul_app_info"."gender" LIMIT 21

2.注入點證實

  • 經過注入sql語句使查詢結果區別與程序本來的查詢結果來證實注入點的可用
  • 程序本來執行的sql語句,最後是limit 21
SELECT "vul_app_info"."gender", STRING_AGG("vul_app_info"."name", \'- \') AS "mydefinedname" FROM "vul_app_info" GROUP BY "vul_app_info"."gender" LIMIT 21
  • 注入後的 sql 語句,最後是 limit 1,只返回一行數據
SELECT "vul_app_info"."gender", STRING_AGG("vul_app_info"."name", \'- \') AS "mydefinedname" FROM "vul_app_info" GROUP BY "vul_app_info"."gender" LIMIT 1 OFSET 1 --
  • 運行結果驗證

8、其餘思考:

1. 漏洞利用場景

  • Django 應用返回聚合數據的場景
  • 用於聚合的字符用戶可控
  • 數據庫得是 postgresql 數據庫
  • 好像不容易存在這種場景...

2. 漏洞挖掘思路

  • 針對可能存在問題的函數,構建測試環境
  • 針對該函數進行模糊測試,看是否有 sql 語句報錯信息
  • 若是模糊測試成功讓 sql 語句報錯,進行注入點利用驗證

3. 漏洞修復

  • 新版本中將delimiter 參數用Value函數處理了一下,再傳遞到sql中

  • 升級django版本(3.1.6)再debug一下

  • 分割符的地方用了%s,沒有直接拼接進去,根據Value函數的註釋說法是將參數放到sql的參數列表中,最終如下面的方式執行,則不存在sql注入風險
sql="SELECT * FROM user_contacts WHERE username = %s"
user='zhugedali'
cursor.execute(sql,[user])

4.同類型函數

  • 在postgresql數據庫中和StringAgg函數同樣能夠傳遞分隔符參數的函數還有
array_to_string(array_agg(name),'-')

  • 可是django中沒有找到這個函數的API(沒有提供或者是我太菜了沒找到..)



轉載請聯繫做者並註明出處!

Ms08067安全實驗室專一於網絡安全知識的普及和培訓。團隊已出版《Web安全攻防:滲透測試實戰指南》,《內網安全攻防:滲透測試實戰指南》,《Python安全攻防:滲透測試實戰指南》,《Java代碼安全審計(入門篇)》等書籍。
團隊公衆號按期分享關於CTF靶場、內網滲透、APT方面技術乾貨,從零開始、以實戰落地爲主,致力於作一個實用的乾貨分享型公衆號。
官方網站:https://www.ms08067.com/

掃描下方二維碼加入實驗室VIP社區
加入後邀請加入內部VIP羣,內部微信羣永久有效!

相關文章
相關標籤/搜索