作为一名刚刚进入网络安全领域的小白,仅在此简单记录一些我刚刚开始学习代码审计的相关笔记。

审计前的环境准备

一、既然是代码审计,那么相应的环境准备肯定是必不可少的啦

windows下一般构建wamp/wnmp环境,Linux环境下一般构建lamp/lnmp环境

这里我个人推荐使用phpstudy--一键化配置环境,只需要我们在本地安装软件即可

小皮面板(phpstudy) - 让天下没有难配的服务器环境! (xp.cn)

官方下载链接如上,下载安装完成后启动我们的环境就配好啦,是不是很简单

二、环境搭建好了,接下来就需要了解一些必要的知识啦:

不同的代码在不同的环境下执行的结果也会不同,所以在审计的过程中我们也要注意版本。

首先我们先来了解一下PHP核心配置

常用的一些PHP_INI_*常量的定义

                       常量                                            含义
              PHP_INI_USER该选项配置可在用户的脚本或windows注册表中设置
              PHP_INI_PERDIR该选项配置可在php.ini..htaccess或httpd.conf中设置
              PHP_INI_SYSTEM该配置选项可在php.ini或httpd.conf中设置
              PHP_INI_ALL该配置选项可在任何地方设置
              php ini only该配置选项可仅可在php.ini中设置

 1.register_globals(全局变量注册开关)

在该选项设置为on的时候,会直接把用户GET、POST、等方式提交的参数注册成全局变量并初始化为参数对应的值,使得提交参数可以直接在脚本中使用。

php版本<=4.2.3时设置为PHP_INI_ALL;php>=5.3.0时被废弃

<?php
if($user='admin')
{
echo 'true';
//do ssomething
}
?>

2.allow_url_include(是否允许包含远程文件)

该选项配置为on时,它可以直接包含远程文件,当存在include($var)且$var可控的时候,可以直接控制$var变量来执行PHP代码

PHP5.2.0后默认设置为off,设置范围为PHP_INI_ALL

<?php
include $GET['a'];
?>

3.这里我就要介绍几个可以起到同样作用的函数了

magic_quotes_gpc(魔术引号自动过滤)

magic_quotes_runtime(魔术引号自动过滤)

magic_quotes_sybase(魔术引号自动过滤)

当这三个选项都开启时,会自动在单引号(')、双引号(")、反斜杠(\)及空字符前面加上反斜杠(\),但是在php5.4后就被取消了

区别:处理的对象不一样

magic_qutes_gpc是对GET、POST、COOKIE传过来的参数进行过滤

magic_quotes_runtime只对从数据库或者文件中获取的数据进行过滤

magic_quotes_sybase用于过滤特殊字符,当其开启时会自动覆盖掉magic_quotes_gpc=on的配置,他们的处理对象都一样,但是magic_quotes_sybase时将空字符进行转义和把单引号(')转成双引号(")

4.safe_mode(安全模式)

PHP5.4之后取消

这个函数开启后会对一些函数进行限制

1)所有文件操作函数:比如unlink()、file()和include()等都会收到影响

举个栗子:文件a.php的所有者是用户a,问价b.php的所有者是用户b,这个时候我们就不能使用用户a去对b.php进行操作,如果有一些脚本文件放在非web服务启动用户所有目录下,需要用include()来加载一些类或者函数,可以使用safe_mode_include_dir指令来配置可以包含的路径

2)通过函数popen()、system()、以及exec()等函数执行命令或者程序会报错

如果我们需要使用一些外部脚本,可以把它们集中放在一个目录下,然后使用safe_mode_exec_dir指令执行脚本的目录

范围:PHP_INI_ALL

5.open_basedir PHP可访问目录open_basedir指令用来限制PHP只能访问那些目录

但是指定的限制实际上是前缀,比如限制open_basedir=/www/a,但是还可以访问www/ab或www/a

6.disable_functions(禁用函数)

开启后可以用来禁用一些敏感函数,记住禁用时要把dll()也加入,因为攻击者可以使用dll()函数来加载自定义的PHP拓展义突破该指令限制

范围php.ini only

disable_functions=phpinfo,eval,passthru,exec,system

7.display_errors和error_reporting 错误显示

display_error表名是否显示PHP脚本内部错误的选项

error_reporting用来设置错误显示的级别

范围都是PHP_INI_ALL

审计辅助与漏洞验证工具

审计代码时如果只是靠我们人力一个一个去找,无疑效率时很低下的,这时我们就可以借用一些工具来提高效率

在这里我推荐的是seay源代码审计系统+notepad++/UltraEdit/everedit+burpsuit(SQL执行监控工具),当然具体还是看个人使用习惯

SQL执行监控工具开启方式,一种方式就是直接使用MySQL语句开启

set global general_log=on;
SET GLOBAL log_output='table';

另一种就是到配置文件中修改

geneal_log=ON
geneal_log_file={日志路径}/query.log

上述工具都可以在百度中找到,由于本篇文章主要还是记录我在代码审计上的学习过程,所以在配置环境上就不在详述了(各位前辈大佬的文章写得比我详细多了)

通用代码审计思路

1.根据敏感关键字回溯参数传递过程

根据敏感函数来逆向追溯参数的传递过程,是目前使用的最多的方式之一,因为绝大多数的漏洞都是由于函数的使用不当造成的。比如SQL注入的特征Select 、Insert等结合From、Where等关键字可以判断

$_SERVER

这种方法的有点就是可以快速的挖掘想要的漏洞,但是对程序的真题框架了解不够深入

2.查找可控变量,正向追踪变量传递过程

3.寻找敏感功能点,通读功能点代码

1)文件上传功能

2)文件管理功能

3)登录认证功能

4)找回密码功能

4.直接通读全文代码

首先看程序的大体代码结构,比如主目录有哪些文件,模块目录有哪些文件,插件目录有哪些文件,注意文件的大小,时间等

1)函数集文件:通常包括functions或者common等关键字,这些文件里一般是一些公共函数,提供给其他文件统一调用

2)配置文件:通常包含confg关键字,配置文件包括Web程序运行必须的功能性配置选项以及数据库等配置信息。

3)安全过滤文件:重要!!!通常有filter、safe、check等关键字,这类文件主要是对文件参数进行过滤,比如SQL和XSS常用的是addslashes()函数进行过滤

4)index文件:index是一个程序的入口文件,所以我们通常只读一遍index文件就可以大致了解整个程序的架构、运行的流程、包含到的文件、其中的核心文件有哪些

通读全文代码的好处显而易见,可以更好的了解程序的架构以及业务逻辑,能够挖掘更多、更高质量的漏洞,但同样缺点也很明显,时间花费长、读起来会比较累

总结:

在此处做一个小小的总结,代码审计的思路大概是:首先可以根据你想要寻找的漏洞去定位关键词,根据相关危险函数进行审计,或者你也可以通读全文代码,了解整个代码体系结构,然后根据危险函数去寻找相关漏洞。

漏洞挖掘与防范(基础篇)

这一节我们主要学习关于SQL注入、XSS、CSRF等一些比较基础的漏洞,知道如何攻击,当然也要知道如何去防范啦。

首先是SQL注入:

SQL注入作为最普遍最常见的漏洞,相信解除渗透的小伙伴们一定不会陌生啦。

原因:开发者在编写操作数据库代码时,直接将外部可控的参数拼接到SQL语句中,没有经过任何过滤或者过滤不严谨就直接放入数据库引擎中执行。

攻击方式:

1.在权限比较大的情况下,通过SQL注入直接写入Webshell,或者直接执行系统命令;

2.在权限比较小的情况下,通过SQL注入查询数据库信息来查询获得管理员账号密码等信息,或者修改数据库一些内容进行一些钓鱼或者其他间接利用。

常用工具:SQLmap;

种类:普通注入、盲注(时间盲注、布尔盲注)、报错注入、宽字节注入、二次注入等;

出现地方:SQL注入一般都会出现在登录页面、获取HTTP头(useragent/client-ip)、订单处理等一些业务比较复杂的地方,业务越复杂,开发者写代码的时候比较容易出问题。

一、普通注入

最简单,一般直接联合查询即可。

关键字:select_from、mysql_connect、mysql_query、mysql_fetch_row、update、insert、delete等

二、编码注入

程序输入前会对参数进行编码处理,通过输入转码函数不兼容的字符就可能导致输出的字符编程有害函数,比如MySQL的宽字节注入(gbk)

关键字:urldecode、rawurldecode、set character_set_client=gbk、SET NAMES 'gbk'、mysql_set_charset('gbk') 等

三、防范:

1.使用过滤函数,比如magic_quotes_gpc/runtime

2.过滤函数和类:addslashes、mysql_[real_]escape_string、intval、PDO prepare预编译

其次是XSS(跨站脚本攻击)漏洞

有SQL注入的地方一般很大概率都存在着XSS漏洞

种类:

1.反射型:通过外部输入然后直接在浏览器端触发

2.DOM型(存储型):把利用代码保存在数据库或者文件中,然后web读取并触发

原理流程图大概是:攻击者提交恶意代码->应用存储代码->应用输出恶意代码->受害者中招

推荐新手小伙伴可以审计一下骑士CMS

危害:窃取cookie、修改页面钓鱼等,前段能做的事它都能做

挖掘经验:

挖掘XSS漏洞的关键在于寻找没有被过滤的函数,常用的输出函数列表如下:

print,print_r,echo,printf,sprintf,die,var,dump,var_dump,export

实际浏览器环境对XSS利用的影响非常大,所以还需要掌握各种浏览器容错、编码等特性和数据协议

出现位置:

像文章发表、评论回复、留言以及资料设置的地方

漏洞防范:

一、特殊字符HTML实体转码

比如一个图片标签:<img src="$_GET['a']"/>,这时我们就可以通过输入双引号来闭合第一个单引号利用漏洞,一般的XSS漏洞都是因为没过滤特殊字符,导致可以注入单双引号以及尖括号等字符利用漏洞,防御这类字符只需要过滤掉相关的特殊字符即可

一些特殊字符:

1)单引号(')

2)双引号(")

3)  尖括号(<>)

4) 反斜杠(\)

5)冒号(:)

6)   and符(&)

7)#号(#)

看到这里,小伙伴们可以想一个问题:这些字符应该怎么过滤,什么时候过滤?

二、标签事件属性黑白名单

前面提到可以通过过滤字符的方式来防御XSS注入,但实际上也是可以绕过的,比如利用宽字节注入的方式来吃掉反斜杠,再利用标签事件来执行js代码,这时我们可以增加黑白名单或者正则表达式匹配

然后是CSRF漏洞

CSRF全称是cross-site request forgery,跨站请求伪造(就是劫持其他用户去进行一些请求),危害:比如添加管理员账号、修改网站配置、直接写入webshell等

挖掘经验:

CSRF主要是用于越权操作,比如管理后台、会员中心、论坛帖子以及交易管理等地方可能会出现

挖掘CSRF的时候可以先搭建好环境,打开几个非静态页面,抓包看看有没有token,如果没有token的话,直接请求这个页面,不带referer。如果返回的数据还是一样的那说明很有可能存在CSRF漏洞了。如果你有核心代码,你可以看看核心文件(被大量文件引用的基础文件,或者直接搜token)里面有没有验证token和referer相关代码。

可以看看Discuz CSRF备份拖库漏洞分析,Woo Yun-2014-64886

漏洞防范:

防御CSRF漏洞最主要的还是解决可行的问题,即便是管理员权限提交到服务器的数据,也不一定是完全可信的,所以方式有:

1.增加token/referer验证避免img请求的水坑攻击

2.增加验证码

Token验证

这里讲讲Token验证,Toekn中文是“标志”,在计算机认证领域叫令牌。你可以简单理解为在页面或者cookie里面增加一个不可预测的字符串,服务器在接收操作的时候只要验证下这个字符串是不是上次访问留下的即可判断是不是可信请求。

验证码验证

考虑到用户体验,所以一般我们主要使用的验证方式还是验证码验证。

漏洞挖掘与防范进阶:

一、文件操作漏洞

文件操作包括文件包含、文件删除、文件上传、文件修改、文件读取等

1.文件包含漏洞

分为本地文件包含(LFI)和远程文件包含(RFI)

挖掘经验:

        文件包含漏洞大多会出现在模块加载、模板加载以及cache调用的地方,比如传入的模块名参数,实际上直接把这个拼接到了包含文件的路径中。可以直接搜索include(),include_once,require,require_once()来回溯看看有没有可控的变量。

本地文件包含(LFI):

指只能包含本机文件的文件包含漏洞。比如上传一个允许文件上传的文件格式的文件再包含来执行代码,包含PHP上传的临时文件,在请求URL或者ua里面加入要执行的代码,webserver记录到日志后再包含webserver的日志,还有像linux下可以包含/proc/self/environ文件。

远程文件包含(RFI):

可以包含远程文件的包含漏洞,远程文件包含需要设置allow_url_include=on,php2.5之后这个选项的可修改范围是PHP_INI_ALL。四个文件包含的函数都支持HTTP、FTP等协议。

文件包含截断:大多数的文件包含漏洞都是需要截断的。

第一种方式:利用%00截断,但是这种方式受限于GPC和addslashes等函数的过滤,PHP5.3之后修复

第二种方式:利用多个英文句号(.)和反斜杠(/)来截断,这种方式不受限于GPC,不过同样在PHP5.3版本之后修复。

 第三种方式:远程文件包含时利用问号(?)来伪截断,不受GPC和PHP本地限制。


2.文件读取下载漏洞

文件读取漏洞和下载漏洞其实差别不大。2012年phpcms的任意文件读取可以看看。

挖掘经验:

一种方式是先黑盒看功能点对应的文件,再去读文件。另一种是搜文件读取的函数,文件读取函数列表如下:

file_get_contents(),highlight_file(),fopen(),readfile(),fread(),fgetss(),fgets(),parse_ini_file(),show_source(),file().

3.文件上传漏洞

文件上传漏洞大多是没有限制文件格式导致可以直接上传文件,目前存在较多的是黑名单过滤存在绕过导致文件上传漏洞。

目前大多数web应用都是基于几个框架来写,上传的点都是调用的同一个类,上传函数只有move_upload_file()。

1.未过滤或者本地过滤

未过滤或本地过滤的共同点都是在服务器端没有过滤,这个为过滤指的是没限制任何格式的文件上传。

2.黑名单拓展名过滤

1)限制的拓展名不够全

2)验证拓展的方式存在问题可以直接绕过

3.文件头、cotent-type验证绕过

4.文件删除漏洞

文件删除漏洞出现在有文件管理功能的应用上比较多,这些应用一般也都有文件上传和读取功能。

unlink()函数、老版本下session——destroy()函数

挖掘经验:挖掘文件删除漏洞可以先去找相应的功能点,直接黑盒测试一下看看能不能删除某个文件,如果不能删除,再从执行流程去追提交的文件名参数的传递过程。

5.文件操作漏洞防范

1.通用文件操作防御

共同点:

1)由越权操作引起可以操作未授权操作的文件---对权限的管理要合理

2)要操作更多文案需要跳转目录---有的文件操作是不需要直接传入文件名的

3)大多数都是直接在请求中传入文件名--要避免目录跳转的问题

文件上传漏洞防范

1)白名单方式过滤文件拓展名

使用in_array()或者是三等于===来对比拓展名

2)保存文件上传的文件时重命名文件

文件名命名规则采用时间戳的拼接随机数的MD5值方式"md5(time()+rand(1,1000))"

二.代码执行漏洞

代码执行漏洞是指应用程序本身过滤不严,用户可以通过请求将代码注入到应用中去执行。

影响函数:eval(),assert(),preg_replace(),call_user_func(),call_user_func_array(),array_map()等

还有PHP的动态函数($a($b))

挖掘经验:

eval()和assert()函数导致的代码执行漏洞大多是因为载入缓存或者模板以及对变量的处理不严格导致,比如直接把一个外部可控的采纳数拼接到模板里面,然后调用者两个函数去当做PHP代码执行

preg_match()函数的代码执行需要/e参数,漏洞出现最多的是对参数的处理,因此一般都在URL,HTML标签以及文章内容等过滤功能。

call_user_func()和call_user_func_array()函数的功能是调用函数,array_map()函数的作用是调用函数并且除第一个参数外其他参数为数组

1.代码执行函数

1)eval()和assert():用来动态执行代码

2)preg_replace():对字符串进行正则处理

3)调用函数不严

call_user_func()和array_map()

2.动态函数执行

由于PHP的特性原因,PHP的函数也可以直接有字符串拼接,这导致了PHP在安全控制上的难度增加,PHP动态函数写法为变量(参数)

推荐thinkphp代码执行漏洞分析

3.漏洞防范

可以采用白名单过滤

三、命令执行漏洞

代码执行漏洞指的是可以执行PHP脚本代码,而命令执行漏洞指的是可以执行系统或者应用命令,比如CMD或者bash,可以执行命令的函数有:system(),exec(),shell_exec(),passthru(),pcntl_exec(),popen(),proc_open()

另外还有反引号(`)

挖掘经验:

命令执行漏洞经常出现在包含环境包的应用里,类似于亿邮(eyou)这类产品

这里我们说一下反引号命令执行(`)

实际上它调用的是shell_exec()函数

防范:

一种是使用系统本身自带的命令防注入函数,addslashes(),mysql_[real_]escape_string()等函数

还有包括escapeshellcmd()和escapeshellarg()

escapeshellcmd()过滤的是整条命令

还有一种就是参数白名单

漏洞挖掘与防范(深入篇)

一、变量覆盖漏洞

变量覆盖指的是可以用我们自定义的参数值来替换程序原有的变量值,变量覆盖漏洞通常需要结合程序的其他功能来实现完整攻击。

变量覆盖漏洞大多数由函数使用不当导致,常见的函数有:extract(),parse_str(),import_request_variables()(用在全局变量注册没有开启的时候)

挖掘经验:

由于变量覆盖漏洞通常需要结合程序的其他功能来实现,因此挖掘一个变量覆盖漏洞不仅仅需要考虑是否能够实现变量覆盖,还要考虑后面的代码能不能让这个漏洞利用起来。要挖掘可用的变量覆盖漏洞,一定要看漏洞代码执行之前存在哪些变量可以覆盖并且后面有被使用到。

除了开头提到的一些函数,国内很多程序使用$$符号注册变量也会导致变量覆盖。

函数使用不当:

1.extract():

extract()函数覆盖变量需要一定的条件,它的官方功能说明为:“从数组中将变量导入到当前的符号表。”通俗来说就是将数组中的键值对注册成变量

2.parse_str()函数

parse_str()函数的作用是解析字符串并注册成变量,它在变量注册前不会验证变量是否存在,这也就导致了变量覆盖漏洞的产生。

3.import_request_variables

import_request_variables()函数的作用是吧GET、POST、cookie的参数注册成变量

4.$$变量覆盖

暂不细说

漏洞防范:

关键是验证注册变量是否存在

1.使用原始变量

2.验证变量存在

二、逻辑处理漏洞

广义上来说,这类漏洞大多数是由于程序的逻辑失误导致的,常见的有:支付、找回密码、程序安装等

挖掘经验:通读功能点代码,熟悉业务流程,关注程序是否可重复安装、修改密码处是否可以越权修改其他用户的账号密码、找回密码验证码是否可暴力破解以及修改其他用户密码、cookie是否可预测或者说cookie验证是否可绕过。

一、等于与存在绕过

1.in_array函数

判断一个值是否在某一个数组列表里面

2.is_numeric函数

判断一个变量是否为数字

3.双等于==和三等于===

区别在于双等于在判断前会先做变量类型转换,而三等于则不会

二、账户体系中的越权漏洞

越权漏洞分为水平越权和垂直越权

水平越权是指原相同等级权限的用户,A用户可以查看操作到B用户的私有信息

垂直越权是指不在同权限等级的用户,低权限等级用户A可以查看或操作高权限等级用户B的私有信息,而这个查看或操作权限本来是A用户不该拥有的

越权漏洞的形成都是账户体系上在判断权限时不严格导致存在绕过漏洞,这一类的绕过通常发生在cookie验证不严、简单判断用户提交的参数。

1.未exit或return引发的安全问题

某些情况下在经过if条件判断之后,有两种操作,一种是继续执行if后面的操作,一种是在if体内退出当前操作,但是这个退出行为有不少开发忘记写了。

2.常见支付漏洞

比如把支付数字改成负数,重复发包来利用时间差,比如很久以前遇到的qq刷钻。

漏洞防范:

可以看到逻辑漏洞的产生主要是因为开发者业务逻辑或者代码逻辑理解不清晰导致。

a:要深入熟悉业务逻辑

b:要多注意函数的功能和差异

三:会话认证漏洞

会话认证是一个非常大的话题,涉及各种认证协议和框架,如cookie、session、sso、oauth、openid等,出现问题比较多的还是cookie上面。

cookie是保存在用户端上的,可以被用户修改;

session是保存在服务器端上的,如果没有代码操作,一般不能被用户修改。

挖掘经验:

认证漏洞能遇到比较多的是出现在cookie验证上面,通常是没有使用session来认证,而是直接将用户信息保存在cookie中。一般挖掘的时候,可以先看一下程序的登录功能代码,看看整个登录过程的业务逻辑有没有可以控制session值或者直接绕过cookie代码

cookie认证安全:

cookie可以保存任何字符串,各个浏览器保存的cookie字节数大小都不一样,一般都不超过4096个字节,通常cookie用来保存登录账号的认证信息。

cookie出现很大的问题是cookie的SQL注入等常见漏洞,这里还有一个问题就是cookie可以被伪造

漏洞防范:

所有用户的输入都不是完全可信的,所以在防御认证前,先要熟悉业务流程,把cookie和session结合起来使用,严格限制输入的异常字符以及避免使用客户端提交上来的内容去直接进行操作。

另外在设置session时需要保证客户端不能操作敏感session参数,特别需要注意的是敏感数据不要放到cookie中。

二次漏洞审计

二次漏洞有点像存储型XSS,就算插入了payload,能不能用还得看页面输出有没有过滤,由于这一类漏洞挖掘起来逻辑会稍微复杂一些,所以目前还属于重灾区。

那么什么是二次漏洞呢?

需要先构造好的payload写入网站保存,在第二次或者多次请求后调用攻击代码触发或者修改配置触发的漏洞叫做二次漏洞。

审计技巧:

重点关注购物车、订单、引用数据、文章编辑、草稿等,越是逻辑复杂的地方越是容易出现漏洞。

代码审计的一些小技巧:

1.钻GPC转义的空子

GPC会自动把我们提交上去的单引号等敏感字符给转义掉,这样我们的攻击代码就没法执行了,GPC是PHP天生自带的功能,所以使我们最大的天敌,但是GPC并不是过滤了所有变量,比如我们常见的$_server变量就没有被GPC过滤,包括转码过程中,也是可以利用的。

比如宽字节注入,就是将%df和%5c(\)组合使\变成了中文字符。

2.神奇的字符串

字符串处理函数报错信息泄露:

E_ALL提示所有问题、E_WARNING提示错误信息、E_NOTICE基础提示信息

字符串截断:

%00字符截断

iconv函数字符编码转换截断

3.php://输入输出流

比如php://input,php://filter,php://output

4.代码解析标签

1)脚本标签:<script language="php">...</script>

2)短标签:<?...?>,使用短标签需要设置shor_open_tag=on

3)asp标签:<%...%>,需要设置asp_tag=on

 5.fuzz漏洞

6.不严谨的正则表达式

没有使用^和$限定匹配开始位置

特殊字符未转义

7.十余种MYSQL报错注入

1)floor()

id=1 and (select 1 from (select count(*),concat(user(),floor(rand(0)*2)) x from information_schema.tables group by x)a) 

2)extractvalue()

id =1 and (extractvalue(1,concat(0x5c,(select user()))))

3)updatexml()

id=1 AND (updatexml(1,concat(0x5e24,(select user()),0x5e24),1))

4)GeometryCollection()

id=1 AND GeometryCollection((select *from(select *from(select user ())a)b))

5)polygon()

id=1 AND polygon((select *from (select *from(select user())a)b))

6)multipoint()

id=1 AND multipoint((select *from(select *from(select user()) a)b))

7)multilinestring()

id=1 AND multilinestring((select *from(select *from(select user()a)b))

8)multipolygon()

id=1 AND multipolygon((select *from (select *from(select user())a)b))

9)linestring()

id=1 AND LINESTRING((select *from(select*from(select user())a)b))

10)exp()

id =1 and exp(~(SELECT*from(SELECT user())a))

8.Windows FindFirstFile利用

9.PHP可变变量

Logo

更多推荐