课程笔记"/>
php代码审计课程笔记
代码审计
第一章 代码审计环境
-
PHP核心配置详解(前5个很重要)
register_globals
(全局变量注册开关)版本5.4.0移除- 功能:把用户GET、POST等方式提交上来的参数注册成全局变量,并初始化值为参数对应的值,使得提交参数可以直接在脚本中使用。
- **
allow_url_include
(是否允许包含远程文件)**5.2.0默认off- 功能:直接包含远程文件,当存在include( v a r ) 且 var)且 var)且var可控的情况下,可以直接控制$var变量来执行PHP代码。
- **
magic_quotes_gpc
(魔术引号自动过滤)**5.4取消- 功能:自动在GET、POST、COOKIE变量中的**单引号(‘)、双引号(“)、反斜杠(\)及空字符(NULL)**前面加上反斜杠(\)。
- php5不过滤$_server变量
- **
magic_quotes_runtime
(魔术引号自动过滤)**5.4取消- 功能:自动在单引号(‘)、双引号(“)、反斜杠(\)及空字符(NULL)前面加上反斜杠(\)。但只对从数据库或者文件中获取的数据进行过滤。(区别)
- **
magic_quotes_sybase
(魔术引号自动过滤)**5.4取消
- 功能:用于自动过滤特殊字符,当设置为on时,会覆盖掉magic_quotes_gpc=on 的配置。处理对象仍是GET、POST、COOKIE变量,但仅仅转义空字符和把单引号(‘)变成双引号(“)(区别)
safe_mode
(安全模式)- 限制文件操作函数,命令执行函数
open_basedir
- 限制php只能访问的目录,前缀。
disable_functions
- 禁用函数,dl()也需要添加。
display_errors()
和error_reporting()
display_errors()
显示php内部错误error_reporting()
错误级别
-
黑盒测试:功能测试是指在不接触代码的情况下,测试系统的功能是否有BUG,是否满足设计需求。
-
白盒测试(代码审计):结构测试、基于代码的测试,以开放的形式从代码层面寻找BUG,如果发现有BUG则返回修复,直到没有bug才允许软件发布上线。
-
灰盒测试:介于白盒测试与黑盒测试之间,多用于集成测试阶段,不仅关注输出、输入的正确性,同时也关注程序内部的情况。
第二章 审计辅助与漏洞检验工具
-
2.2工具名字和大致特点
-
Seay源代码审计系统
- 基于C#语言开发的,针对PHP代码
- 主要特点:(1)一键自动化白盒审计;(2)代码调试;(3)正则编码;(4)自定义插件及规则
-
基本正则
第三章 通用代码审计思路
-
什么是代码审计?指对源代码进行检查,寻找代码中的漏洞。
-
常见代码审计思路(掌握每一种思路和优缺点)
-
根据敏感关键字回溯参数传递过程
优点:只需搜索相关敏感关键字,能定向挖掘,快速挖掘
缺点:为通读代码,对框架了解不熟,定位利用点花费时间多,不能覆盖逻辑漏洞
-
查找可控变量,正向追踪变量传递过程
-
寻找敏感功能点,通读功能点代码(哪些功能点出现漏洞以及漏洞里面一些函数的作用 主要php内置的)
- 文件上传
- 文件管理
- 登录认证
- 找回密码
-
通读全文代码。
查看大体代码结构
- 函数集文件:通常命名中包含functions或者common关键字。打开index.php在头部文件一般能找到
- 配置文件:通常包含config关键字
- 安全过滤文件:通常包含filter, safe, check等关键字
- index文件
-
第四章 漏洞挖掘与防范(基础)
常见的Web漏洞:SQL注入、XSS、文件操作、代码 / 命令执行、变量覆盖以及逻辑处理。掌握基本原理和防御方法
SQL注入
SQL注入的基础利用方式:普通注入、盲注、报错注入、
**挖掘经验:**登录页面、获取HTTP头(client-ip和x-forward-for)、订单处理(二次注入)等地方
重点:编码注入(宽字节注入)、二次注入 。(要知道原理,利用的例子如何修补)。
-
宽字节注入
触发条件:
character_set_client=gbk
反斜杠(\)的URL码为
%5c
漏洞利用时在参数后加
%df'
/1.php?id=-1%df' and 1=1%23 ==>> select * from user where id='1運' and 1=1#' 因为单引号被转义成\',前面的%df和转义字符\反斜杠(%5c)组合成%df%5c,即为“運”
漏洞防范:
SET NAMES 'GBK',character_set_client=binary
mysql_set_charset('gbk'),mysql_real_escape_string()
过滤 推荐使用PDO方式来解决。
-
二次urldecode注入(重点,案例分析)
当某处使用了urldecode()或者rawurldecode(),会导致二次解码生成单引号而引发注入。可搜索之进行二次注入漏洞挖掘。
<?php $a=addslashes($_GET['id]); #WebServer自己的参数过滤机制,加反斜杠转义 $b=urldecode($a); #漏洞利用函数 echo '$a='.$a; echo '$b='.$b; ?> 漏洞利用:/1.php?id=1%2527 ==>> $a=1%27 $b=1'
sql漏洞防范
如何防范以及过滤的函数和类。
-
5.4之前魔术引号GPC/runtime(对int型乏力)
-
过滤函数
-
addslashes()
:范围和GPC一样,参数为字符串 -
mysql_escape_string()
和mysql_real_escape_string()
受影响的字符
\x00 \n \r \ ' " \x1a
后者接受的是一个连接句柄并根据当前字符集转义字符串
-
intval()/floatval()
将变量转换为int/float型
-
-
过滤类
-
PDO 预编译:注意禁用php本地模拟prepare
XSS
原理,骑士cms调试,防范方法
原理:反射和存储型
挖掘经验:关键在于寻找没有被过滤的参数,且参数传入到输出函数。掌握浏览器容错机制、编码特性和数据协议。漏洞经常出现在文章发表,评论回复,留言,资料设置等地方。
漏洞防范:
-
特殊字符HTML实体编码(输出和二次调用的时候)
htmlspecialchars()
-
标签黑名单
-
Anti-XSS
-
HttpOnly
CSRF
原理,防范
跨站请求伪造
挖掘经验:用于越权操作,漏洞出现在有权限控制的地方,如管理后台、会员中心、帖子、交易管理等
漏洞防范:
- 验证码
- token/referer
第五章 漏洞挖掘与防范(进阶)
文件漏洞(重点)
-
文件包含
-
文件包含函数有
include()、include_once()、require()、require_once()
区别在于
include()、include_once()
在包含文件时即使遇到错误,下面的代码也 会接着执行;而require()、require_once()
则会直接报错退出程序。 -
本地文件包含
如何挖掘,利用
挖掘经验:模块加载、模板加载以及cache调用的地方。一般从上面几个函数回溯看看是否有可控变量。
利用:上传文件后再包含来执行代码、php上传临时文件,包含webserver日志等
-
远程文件包含
如何挖掘,利用
条件:
allow_url_include=on
利用:
- 普通利用
- php://input流
-
文件包含截断
几种方式
- %00:受限于GPC和
addslashes()
过滤,5.3版本后也不能用 - 多个
.
和/
:5.3版本后不能用 ?
伪截断:webserver会把?
后的当作请求参数
- %00:受限于GPC和
-
-
文件读取与下载
知道有哪些函数,挖掘经验,防范
挖掘经验:黑盒查看功能点,白盒搜索文件读取函数跟踪可控变量
文件读取函数
file_get_contents()
highlight_file()
fopen()
readfile()
fread()
fgetss()
fgets()
parese_ini_file()
show_source()
file()
include()
php://filter/
-
文件删除
知道有哪些函数,挖掘经验,防范
挖掘经验:找相应功能点测试是否能删除某个文件,白盒搜索关键函数
函数:
unlink()
session_destroy()
:任意删除文件
漏洞防范:
- 合理的权限管理
- 隐藏文件名
- 避免目录跳越
- 白名单过滤
- 上传文件重命名
代码执行漏洞
概念:指应用程序本身过滤不严,用户可以通过请求将代码注入到应用中执行。
掌握代码函数具体用法,知道如何写exp ,挖掘经验
函数:
-
eval()
-
assert()
-
preg_replace()
-
call_user_func()
-
call_user_func_array()
-
array_map()
-
动态函数
($a($b))
挖掘经验:
-
eval()
和assert()
函数导致代码执行漏洞的原因:载入缓存或者模板以及对变量的处理不严格。 -
preg_replace()
函数的代码执行需要 /e 参数,此函数用于对字符串进行正则处理。
请求/1.php?str=[phpinfo()]
时,则执行代码phpinfo()
call_user_func()、call_user_func_array()
函数的功能是调用其他函数。
-
动态
-
array_map()
调用函数并且除第一个参数外的其他参数为数组
漏洞防范:
- 参数白名单结合正则表达式
案例分析:
命令执行漏洞
掌握代码函数具体用法,知道如何写exp ,挖掘经验,防注入函数
函数:
system()
exec()
shell_exec()
passthru()
- `:反引号,实质是调用shell_exec()函数,以上都是直接传入命令并返回结果
pcntl_exec()
popen()
proc_open()
:不会返回结果,仅一个指针
漏洞防范:
-
使用PHP自带的命令防注入函数,包括
escapeshellcmd()
和escapeshellarg()
。其中,-
escapeshellcmd()
是过滤整条命令。参数为string反斜线(****)会在以下字符之前插入: & # ; ` | * ? ~ < > ^ ( ) ]{ } $ \ , \x0A 和 \xFF。 ’ 和 " 仅在不配对的时候被转义。
在 Windows 平台上,所有这些字符以及 % 和 ! 字符都会被空格代替。
-
escapeshellarg()
是用来保证传入命令执行函数里的参数确实是以字符串参数形式存在的。过滤参将参数限制在一对双引号里,确保参数为一个字符串
把双引号替换为空格
-
-
对命令执行函数的参数做白名单限制
第六章 漏洞挖掘与防范(深入)
变量覆盖
掌握函数,重点函数参数,利用,防范
变量覆盖:指可以用我们自定义的参数值替换程序原有的变量值。
挖掘经验:搜寻特定的函数并回溯变量是否可控
函数:
-
**extract()**
将数组中的键值对注册成变量
var_array:必须。规定要使用的输入
extract_type():可选。extract()函数将检查每个键名是否合法,也检查和符号表中的变量名是否冲突。——此参数决定了会不会导致变量覆盖漏洞。
对非法、数字和冲突的键名的处理会依据以下参数决定- EXTR_OVERWRITE:默认。如果有冲突,则覆盖已有的变量。
- EXTR_SKIP:如果有冲突,不覆盖已有的变量。
- EXTR_IF_EXISTS:仅在当前符号表中已有同名变量时,覆盖它们的值。其他的都不处理。
- EXTR__PREFIX_ALL:给所有的变量名前加上前缀prefix
- EXTR__PREFIX_INVALID:仅在非法或数字**变量名前加上前缀prefix
- EXTR_PREFIX_SAME:如果有冲突,在变量名前加上前缀prefix
prefix:可选
-
parse_str()
解析字符串并注册为变量,不会验证当前变量是否已经存在,所以会直接覆盖掉已有变量
-
import_request_variables(’GPC‘)
用在没有开启全局变量注册的时候,调用了这个函数则相当于开启了全局变量注册
把GET、POST、COOKIE的参数注册为变量
$$变量覆盖(重点,案例分析、研究结果及其原因)
<?php$a=1;foreach(array('_COOKIE','_POST','_GET') as $_request) {foreach($$_request as $_key => $_value) {echo $_key.'<br />';$$_key = addslashes($_value);}}echo $a;?>漏洞利用:/1.php?a=2==>>a2分析:$_key为 COOKIE、POST、GET中的参数,提交 ?a=2 时,则$key的值为a,而还有一个$在a的前面,结合起来就是$a= addslashes($_value);这样就会覆盖掉已有变量a的值。故代码执行后,成功把变量$a的值覆盖为了2
漏洞防范:
- 使用原始变量数组
- 验证变量是否存在
逻辑处理
常见函数、利用方法、防范
挖掘经验:是否可重复安装、修改密码是否可越权、找回密码是否可暴力破解、cookie是否可破解等
函数:
-
in_array() 函数:判断一个值是否在某一个数组列表里面。
会做自动的类型转换
-
is_numeric 函数:判断一个变量是否为数字。
传入hex能直接通过,容易引发二次注入和xss
双等于和三等于
区别在于在判断等于之前会先做变量类型转换,而三等于则不会
会话认证漏洞
知道有这个就ok
cookie数据未校验,可破解
第七章 二次漏洞审计
二次漏洞概念,举例说明,产生流程图,审计技巧
定义二次漏洞:需要先构造好利用代码写入网站保存,在第二次或多次请求后调用代码触发或者修改配置触发的漏洞。
二次漏洞产生的流程图
审计技巧:通读代码,关键字定位,购物车,订单,文章编辑,草稿等与数据库交互的地方
第八章 代码审计小技巧
GPC
那些是不受GPC保护的 ,如何利用
-
$_SERVER
该变量取到的header字段不受影响
-
$_FILE
字符处理
mb_convert_encoding()
:编码转换
字符处理函数报错信息泄露 error_reporting():
错误提示:
-
E_ALL代表提示所有问题、
-
E_WARNING代表显示错误信息、
-
E_NOTICE显示基础提示信息
字符截断
iconv()
函数,用来做字符编码转换。字符集的编码转换总会存在一定的差异性,导致部分编码不能被成功转换,即乱码。使用该函数进行转码时,遇到不能处理的字符串则后续字符串会不被处理。(即截断,无输出)
PHP://输入输出流
三个流的方法
-
php://input —— 可以访问请求的原始数据的只读流;可以直接读取到POST上没有经过解析的原始数据,但不能获取“multipart/form-data”方式提交的数据。
-
php://output —— 将流数据输出
-
php://filter —— 一个文件操作的协议,对磁盘文件作读写操作。类似于readfile()、file()和file_get_contents()
php://filter/write=string.rot13/resource=1.php
/1.php?f=php://filter/convert.base64-encode/resource=1.php
php代码解析标签
了解三个
- 脚本标签:
<script language="php">...< /script>
- 短标签:
< ? ... ?>
- asp:
<% ...%>
fuzz
概念 举例说明
概念:对特定目标的模糊测试
正则
书上两例子如何利用和修补
-
ip匹配
/\d+\.\d+\.\d+\.\d+/
未匹配结尾,绕过:123.0.0.1aa
应使用
/^\d+\.\d+\.\d+\.\d+$/
-
特殊字符转义
\.
MySQL报错注入
有十余种,最常见的是 floor()、updatexml()、extractvalue() 这三个函数
-
floor()
id = 1 and (select 1 from (select count(*).concat(user(),floor(rand(0)*2))x from infomation_schema.tables group by x)a)
-
updatexml()
id = 1 and (extractvalue(1,concat(0x5c,(select user()))))
-
extractvalue()
id = 1 and (updatexml(1,concat(0x5c,(select user(),0x5c),1))
Windows FindFirstFile
如何利用如何匹配
函数功能:在Windows下,只要知道文件所在目录,就能利用Windows特性,到一个文件夹(包括子文件夹)去搜索指定文件。
利用方法:将文件名不可知部分之后的字符用“<”或者“>”代替即可。
注意:一个“<”、“>”只能代表一个字符,更多则需使用 “<<”
```
<?php
include($_GET['file']);
?>
在1.php同目录下建立一个12345.txt,其内容为phpinfo()函数
包含方法:/1.php?file=1<<
```
可变变量
${@phpinfo()}
第九章 参数的安全过滤
掌握函数
内置过滤函数
SQL注入过滤函数:addslashes()、mysql_real_escape_string()、mysql_escape_string()
作用都是给字符串添加反斜杠\ 来转义单双引号、反斜线和空字符。
XSS过滤函数:htmlspecialchars()、strip_tags()
htmlspecialchars():将字符串中的特殊字符转换成HTML实体编码。(& 变为 &)
strip_tags():用来去掉HTML及PHP标记。(<h1>xxxx</h1> 变为 xxxx
)
第十章 使用安全的加密算法
知道哪些是对称,哪些是非对称,用于啥场合
加密:指将明文直接可见的数据以特定的算法进行混淆,以保证数据的安全掩蔽性。
对称加密算法:AES、DES、3DES、TDEA、IDEA、RC2、RC4、RC5、Blowfish、SKIPJACK
非对称加密:RSA
在国密算法中
SM1、SM4、SM7、祖冲之算法 ——》对称算法
SM2、SM9 ——》非对称算法
SM3 ——》哈希算法
单向加密(不可逆算法):md4、md5 和 sha1、sha192、sha256
王小云教授为破解MD5、SHA-1等算法做出了巨大贡献。
第十一章 业务功能安全设计
功能设计有什么用,会存在什么问题,怎么挖掘,如何设计一个安全的
-
验证码包括:图片验证码、滑动验证码、短信\邮箱\电话、二维码等分类。
如何设计一个强壮的验证码?
- 设置验证码错误次数
- 不放在cookie和html页面
- 只能请求一次
- 动态生成
- 验证码复杂性
-
撞库漏洞
导致产生的几种情况
用户名和密码错误次数都无限制
单时间段内用户的密码错误次数限制
单时间段内IP登录错误次数限制
解决方案:使用登录验证码和多因素验证 -
针对充值支付漏洞的主要应对手法
保证数据可信,商品单价及总价不可从客户端获取;
购买数量不能小于等于0,且不能超过65535;
账户支付锁定机制。当一个支付操作开始就立马锁定当前用户,不能同时两个后端请求对余额进行操作。 -
远程地址访问漏洞
SSRF 指服务器端请求伪造漏洞
SSRF 其攻击目标一般是从外网无法访问的内部系统
SSRF 可以对外网服务器所在的内网进行扫描限制短地址短链接
-
设计文件管理功能时,应遵循:
禁止写入脚本可在服务器端执行的文件;
限制文件管理功能操作的目录;
限制文件管理功能访问权限;
禁止上传特殊字符文件名的文件。 -
数据库管管理
限制可操作的数据库表
限制备份到服务器的文件名
-
通常文件和数据库备份易出现的问题:
未授权访问和越权访问
备份文件名可预测
生成的文件可利用Web中间件解析漏洞执行代码 -
需要掌握网站安全防御的内容
一个网站的应用安全防御应该包括对输入的特殊字符过滤、输出过滤、异常访问检测、自身安全检测等等。
其中,自身安全检测方式有:木马查杀、弱后台地址检测、弱口令检测等等。
第十二章 应用安全体系建设
- 用代码来实现最简单的登录限制策略:
- 限制登录IP
- 双因素验证。比如手机验证码、动态令牌
- 多因素验证方式
- 手机短信验证码
- 手机语音验证码
- 手机App动态令牌
- 邮箱验证码
- 实体令牌卡
- 电子图片令牌卡
- 硬件令牌
- 一个网站的应用安全防御应该包括:对输入的特殊字符过滤、输出过滤、异常访问检测、自身安全检测。
- 自身安全检测方式有:木马查杀、弱后台地址检测、弱口令检测等。
第十三章 C语言安全
注意L1级别 18和27 问题出在什么地方,如何写出正确的,漏洞基本原理
重点
-
exp34
解决方案:
-
str31
解决方案
-
*C语言安全需要注意哪些方面
- 提高任何C或C++应用程序的整体安全性。
- 阻止利用不安全的字符串操作逻辑进行缓冲区溢出、栈溢出以及面向返回值的编程攻击。
- 避免因不正确使用动态内存管理函数而导致的漏洞和安全缺陷。
- 消除因有符号整数溢出、无符号整数回绕和截断误差而导致的整数相关问题。
- 执行安全的I/O操作,避免文件系统漏洞。
- 正确使用格式化输出函数,避免引入格式字符串漏洞。
- 在开发并发代码时,避免竞争条件和其他可利用的漏洞。
-
需要掌握的用户注册的安全设置思路
- 设计验证码
- 采集用户机器唯一识别码,拦截短时间内多次注册
- 根据账号格式自学习识别垃圾账号
- 防止SQL注入漏洞和XSS漏洞
-
UTF-8:多字节字符集,每个UTF-8字符由1~4个字节表示。
-
C、C++操作字符串错误:无界字符串复制、差一错误、空结尾错误、字符串截断
-
缓冲区溢出
- 将数据复制到不足以容纳数据的缓冲区,会导致缓冲区溢出。
- 经常发生在字符串操作汇总
- 可截断限制拷贝,并确保目标区域的大小足以容纳复制数据和null结束符。
- 容易发生缓冲区溢出的情景:
- 将字符串定义为以空字符结尾的字符数组
- 未进行隐式的边界检查
- 提供了未强制行边界检查的标准字符串函数调用
-
C语言:具备良好的移植性和跨平台支持,以及高效率的低级处理能力。
PHP内置重点函数
-
addslashes()
:范围和GPC一样,参数为字符串 -
mysql_escape_string()
和mysql_real_escape_string()
受影响的字符
\x00 \n \r \ ' " \x1a
后者接受的是一个连接句柄并根据当前字符集转义字符串
-
intval()
/floatval()
将变量转换为int/float型 -
htmlspecialchars()
:HTML实体 -
file_get_contents()
-
highlight_file()
-
fopen()
-
readfile()
-
fread()
-
fgetss()
-
fgets()
-
parese_ini_file()
-
show_source()
-
file()
-
unlink()
-
session_destroy()
:任意删除文件 -
eval()
-
assert()
-
preg_replace()
-
call_user_func()
-
call_user_func_array()
-
array_map()
-
动态函数
($a($b))
-
system()
-
exec()
-
shell_exec()
-
passthru()
-
`:反引号,实质是调用shell_exec()函数,以上都是直接传入命令并返回结果
-
pcntl_exec()
-
popen()
-
proc+open()
:不会返回结果,仅一个指针 -
escapeshellcmd()
-
escapeshellarg()
-
**extract()**
-
parse_str()
-
import_request_variables()
-
mb_convert_encoding()
-
iconv()
-
chr()
intval()
/floatval()
将变量转换为int/float型
-
htmlspecialchars()
:HTML实体 -
file_get_contents()
-
highlight_file()
-
fopen()
-
readfile()
-
fread()
-
fgetss()
-
fgets()
-
parese_ini_file()
-
show_source()
-
file()
-
unlink()
-
session_destroy()
:任意删除文件 -
eval()
-
assert()
-
preg_replace()
-
call_user_func()
-
call_user_func_array()
-
array_map()
-
动态函数
($a($b))
-
system()
-
exec()
-
shell_exec()
-
passthru()
-
`:反引号,实质是调用shell_exec()函数,以上都是直接传入命令并返回结果
-
pcntl_exec()
-
popen()
-
proc+open()
:不会返回结果,仅一个指针 -
escapeshellcmd()
-
escapeshellarg()
-
**extract()**
-
parse_str()
-
import_request_variables()
-
mb_convert_encoding()
-
iconv()
-
chr()
-
strip_tags()
参考
《代码审计:企业级Web代码安全架构》
更多推荐
php代码审计课程笔记
发布评论