天天看點

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

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

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

一、漏洞名稱:

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

二、漏洞編号:

CVE-2020-7471

三、漏洞描述:

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 1.11.x < 1.11.28

Django 2.2.x < 2.2.10

Django 3.0.x < 3.0.3

五、漏洞分析

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

六、實驗環境及準備:

1.資料庫:postgresql,版本無所謂,本文中使用kali虛拟機中自帶的資料庫,允許外部連接配接

  • 修改如下檔案,監聽所有端口
/etc/postgresql/12/main/postgresql.conf
           
追洞小組 | 實戰CVE-2020-7471漏洞
  • 修改如下檔案,允許外部連接配接
/etc/postgresql/12/main/pg_hba.conf
           
追洞小組 | 實戰CVE-2020-7471漏洞
  • 重新開機服務後,連接配接資料庫并建立測試資料庫
登陸:psql -U postgres -h [kali主機的IP]
建立測試資料庫:CREATE DATABASE test,後面poc中會用到
其他postgresql文法可以參考菜鳥教程
           

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

  • 安裝django3.0.2

    pip installdjango==3.0.2

  • 使用pycharm調試POC代碼,參考POC中的readme文檔
追洞小組 | 實戰CVE-2020-7471漏洞
  • 初始化資料庫後可以用pgadmin連接配接看下,test資料庫中應該有如下表
追洞小組 | 實戰CVE-2020-7471漏洞
  • Vul_app_info表中應該如下字段和資料
追洞小組 | 實戰CVE-2020-7471漏洞

七、複現步驟:

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

1.模糊測試

  • 通過運作query()函數的異常捕獲可以知道有兩個特殊字元讓程式産生了報錯(%和’)
  • 将程式中異常捕獲注釋掉,payload使用%和’單獨測試
追洞小組 | 實戰CVE-2020-7471漏洞
追洞小組 | 實戰CVE-2020-7471漏洞
  • 通過報錯可以看出分号沒有轉義導緻sql語句報錯,并直接在報錯資訊傳回了拼接後的sql語句。将斷點打在執行sql語句并産生報錯的代碼塊去看完整的sql
追洞小組 | 實戰CVE-2020-7471漏洞
追洞小組 | 實戰CVE-2020-7471漏洞
  • 得到程式運作的實際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 --
           
  • 運作結果驗證
追洞小組 | 實戰CVE-2020-7471漏洞

八、其他思考:

1. 漏洞利用場景

  • Django 應用傳回聚合資料的場景
  • 用于聚合的字元使用者可控
  • 資料庫得是 postgresql 資料庫
  • 好像不容易存在這種場景...

2. 漏洞挖掘思路

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

3. 漏洞修複

  • 在django的git倉庫的送出記錄中可以看到django官方的修複方案
  • https://github.com/django/django/commit/eb31d845323618d688ad429479c6dda973056136
追洞小組 | 實戰CVE-2020-7471漏洞
  • 新版本中将delimiter 參數用Value函數處理了一下,再傳遞到sql中
追洞小組 | 實戰CVE-2020-7471漏洞
  • 更新django版本(3.1.6)再debug一下
追洞小組 | 實戰CVE-2020-7471漏洞
  • 分割符的地方用了%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),\'-\')
           
追洞小組 | 實戰CVE-2020-7471漏洞
  • 但是django中沒有找到這個函數的API(沒有提供或者是我太菜了沒找到..)

轉載請聯系作者并注明出處!

Ms08067安全實驗室專注于網絡安全知識的普及和教育訓練。團隊已出版《Web安全攻防:滲透測試實戰指南》,《内網安全攻防:滲透測試實戰指南》,《Python安全攻防:滲透測試實戰指南》,《Java代碼安全審計(入門篇)》等書籍。

團隊公衆号定期分享關于CTF靶場、内網滲透、APT方面技術幹貨,從零開始、以實戰落地為主,緻力于做一個實用的幹貨分享型公衆号。

官方網站:https://www.ms08067.com/

掃描下方二維碼加入實驗室VIP社群

加入後邀請加入内部VIP群,内部微信群永久有效!