代码审计——渗透测试(上)

前言

最近在看php代码审计,学习下代码审计,看了不少师傅的博客,写的很好,下面不少是借鉴师傅们的,好记性不如烂笔头,记下,以后可以方便查看。

php代码审计需要比较强的代码能力和足够的耐心。这篇文章是写给我这样的刚刚开始审计的菜鸟,下面如果写的哪里有错误的话,还望提出,不吝赐教。

在这里也立个flag:一周至少审计一种CMS(大小不分),希望自己能够坚持下去,任重而道远。

代码审计–准备
1,先放一张大图,php代码审计的几个方向,也是容易出问题的地方,没事的时候可以多看看。
代码审计——渗透测试(上)_第1张图片2,代码审计也就是拿到某网站的源码,进行审计,从而发现漏洞,但是我们审计的时候并不一定要一行一行的去看吧,这样未免也太浪费时间了,所以我们需要工具进行帮助我们。当属 “Seay源代码审计系统2.1” 优先选择(静态分析,关键字查找定位代码不错,但是误报很高)。

我们在做代码审计的时候,个人建议先要把审计的某CMS随便点点,先熟悉一下功能。代码审计前先进行黑盒测试是个不错的选择,知道哪里有问题,然后再去找出问题的代码。

要关注变量和函数,

1.可以控制的变量【一切输入都是有害的 】

2.变量到达有利用价值的函数[危险函数] 【一切进入函数的变量是有害的】

------来源t00ls

代码审计–漏洞
一,漏洞类型

1.sql注入

2.文件操作[上传/写入/读取/删除]

3.文件包含

4.命令执行

5.xss

6.cookie欺骗

7.逻辑漏洞

…等等

我们平常再进行黑盒测试时,上面的每种漏洞都有相对应的挖掘技巧,这里代码审计也是有技巧的。我们进行黑盒测试getshell的时候,往往是上面的sql注入,文件操作(上传),文件包含,命令执行相对容易getshell的。xss的话危害也很大,可以泄露内网的信息,如果的是存储型xss的话,就可以打管理员的cookie,然后进行下一步的攻击。逻辑漏洞是相对麻烦的,危害是很要命的,逻辑漏洞也分为很多种,其中一元买东西是很出彩的,这里通过修改订单进行伪造支付金额。

所以我们要认识清楚漏洞原理,积累cms常出漏洞,积累找这种漏洞的技巧。
二,漏洞分析
下面我们就进行分析一下各种漏洞形成的原因吧
1,首先我们要做好准备工作,审计环境:windows环境(Apache+MySQL+php),可以使用集成的,wampserver,phpstudy其他,我用的是wamp,这里在下载的时候不要用版本太高的,因为版本太高,会出现php语法警告以及不兼容的情况。(下一篇也就是我准备写的一个审计笔记,我平常用的wampserver,由于我的mysql的版本太高,一直安装不成功,后来又重装了一个环境(upupw),会在下一篇详细介绍)(文章里面所提到的环境和工具后面都会分享到百度云盘)。

2,准备好了就直接上手分析吗?其实有更不错的选择,那就是----黑盒+白盒。黑盒很重要!黑盒很重要!黑盒很重要!这是重要的事情。我们在黑盒测试的时候,可以花费点时间,因为用的时间越多,我们对所要分析的CMS的功能更熟悉,代码审计的时候也就容易分析,比如看到搜索框,当然要看下有没有注入或者是能不能弹出来框框,以及留言板有没有xss。交互的数据很重要!
这里有个小技巧,本地测试的时候要把输入点打印出来。
将用户的输入数据进行var_dump,重要的是对最终的sql语句进行var_dump,这和给你省去很多力气!我们只要var_dump($sql)然后再可以去黑盒测试,[比如搜索框,用户登入,文件上传名称等等]。

3,现在可以进行漏洞分析了,下面会写到比较常见的漏洞类型以及审计不同漏洞的技巧。
XSS漏洞
XSS又叫CSS (Cross Site Script) ,跨站脚本攻击。它指的是恶意攻击者往web页面里插入恶意html代码,当用户浏览该页之时,嵌入其中Web里面的html代码会被执行,从而达到恶意用户的特殊目的。 xss分为存储型的xss和反射型xss, 基于DOM的跨站脚本XSS。

【反射型】
反射型xss审计的时候基本的思路都一样,通过寻找可控没有过滤(或者可以绕过)的参数,通过echo等输出函数直接输出。寻找的一般思路就是寻找输出函数,再去根据函数寻找变量。一般的输出函数有这些:print , print_r , echo , printf , sprintf , die , var_dump ,var_export。
测试代码如下:

http://127.0.0.1/test/xssf.php?xssf=#)
代码审计——渗透测试(上)_第2张图片代码审计——渗透测试(上)_第3张图片分析如下:首先看下源码
代码审计——渗透测试(上)_第4张图片

Hello ' . $_GET[ 'name' ] . '
'; } ?>

这里我们可以清楚的看到 if 里面的php函数array_key_exists,现在不懂没关系,百度一下你就知道。

array_key_exists(key,array)

key必需。规定键名。array必需。规定数组。

array_key_exists() 函数检查某个数组中是否存在指定的键名,如果键名存在则返回 true,如果键名不存在则返回 false。

输入的值也就是GET得到的值是以数组的形式,然后判断GET得到的name是不是空,如果满足 if 语句,这里就会进行 if 括号里面的,echo '

Hello ’ . $_GET[ ‘name’ ] . ‘
’; 我们可以清楚的看到,这里直接输出传的name参数,并没有任何的过滤与检查,存在明显的XSS漏洞。

这里我们可以再进行分析一下medium中等难度下的代码

', '', $_GET[ 'name' ] );

// Feedback for end user
echo "
Hello ${name}
"; } ?>

可以看到有一点上low的代码是不一样的,那就是进行了一次过滤,

用的str_replace()函数,这个函数的功能是:以其他字符替换字符串中的一些字符(区分大小写)。

这里的作用是替换

这里对输入进行了过滤,基于黑名单的思想,使用str_replace函数将输入中的

双写绕过:输入

大小写混淆绕过:输入,成功弹框。这里就不截图了。

High等级也是基于黑名单思想,进行过滤。但是我们可以通过其他标签来进行XSS。

$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'name' ] ); 

代码如上,这里就不一一分析了。

【存储型】

存储型xss审计和反射型xss审计时候思路差不多,不过存储型xss会在数据库“中转”一下,主要审计sql语句update ,insert更新和插入。

进行白盒审计前,我们先进行下黑盒测试

输入name的时候发现,name输不了那么多了,这是我们可以右键审查元素,可以看到限制长度为10了,其实说这句话,只是想提醒一下像我这样的小白,审查元素也是一门"学问"

name出随便输入,message处输入:,可以看到会弹出框框

代码审计——渗透测试(上)_第5张图片这是看下源码,我们分析下

' . mysql_error() . '
' ); //mysql_close(); } ?>

可以看到接收POST过来的参数,trim()函数是移除字符串两侧的空白字符或其他预定义字符。

这里先进行过滤一下,把我们输入字符串两侧的空白字符和其他预定义字符给过滤掉。预定义字符包括:\t,\n,\x0B,\r以及空格。

$message = stripslashes( $message );

然后stripslashes()函数:删除反斜杠

然后message参数再经过mysql_real_escape_string()函数进行转义。

mysql_real_escape_string() 函数转义 SQL 语句中使用的字符串中的特殊字符。

下列字符受影响:

  • \x00
  • \n
  • \r
  • "
  • \x1a
    如果成功,则该函数返回被转义的字符串。如果失败,则返回 false。

最后给插入数据库。这个时候我们去数据库看一下,如下图,可以看到xss代码已经插入数据库了,这也就是存储型XSS与反射性XSS的区别。

因为我们在前端看到的都是经由数据库传过来的数据,所以会弹出框框。
代码审计——渗透测试(上)_第6张图片这里我最后总结一下,顺便再分析一下。

我输入的值是:这个时候就把 m e s s a g e 传 入 数 据 库 , 也 就 是 上 图 数 据 库 中 的 数 据 。 前 端 读 取 的 数 据 的 时 候 是 从 数 据 库 中 读 取 , 因 此 把 message传入数据库,也就是上图数据库中的数据。前端读取的数据的时候是从数据库中读取,因此把 messagemessage读出来,从而造成了存储型XSS漏洞。

还有medium,high,这里就不做分析了,这里解决XSS漏洞的方法就是用htmlspecialchars函数进行编码。但是要注意的是,如果htmlspecialchars函数使用不当,

攻击者就可以通过编码的方式绕过函数进行XSS注入,尤其是DOM型的XSS。说的DOM型XSS,下面就是啦。

【DOM】

这个DVWA里面没有这种,这里还是我们自己动手丰衣足食吧。

基于DOM的跨站脚本XSS:通过访问document.URL 或者document.location执行一些客户端逻辑的javascript代码。不依赖发送给服务器的数据。


Welcome!
Hi


Welcome to our system …

代码审计——渗透测试(上)_第7张图片
代码审计——渗透测试(上)_第8张图片
浏览器开始解析这个HTML为DOM,DOM包含一个对象叫document,document里面有个URL属性,这个属性里填充着当前页面的URL。当解析器到达javascript代码,它会执行它并且修改你的HTML页面。倘若代码中引用了document.URL,那么,这部分字符串将会在解析时嵌入到HTML中,然后立即解析,同时,javascript代码会找到(alert(…))并且在同一个页面执行它,这就产生了xss的条件。

注意:

  1. 恶意程序脚本在任何时候不会嵌入到处于自然状态下的HTML页面(这和其他种类的xss不太一样)。

2.这个攻击只有在浏览器没有修改URL字符时起作用。 当url不是直接在地址栏输入,Mozilla.会自动转换在document.URL中字符<和>(转化为%3C 和 %3E),因此在就不会受到上面示例那样的攻击了,在IE6下没有转换<和>,因此他很容易受到攻击。

这里可以看到我的浏览器自动转换了字符<>,所以没有弹出框,这里我们知道原理就好,IE6下没有转换<和>,所以是可以弹框框的。

SQL注入漏洞

sql注入是我们审计比较重视的漏洞之一
SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。SQL注入的产生原因:①不当的类型处理;②不安全的数据库配置;③不合理的查询集处理;④不当的错误处理;⑤转义字符处理不合适;⑥多个提交处理不当。

首先说一下普通的注入审计,可以通过 G E T , _GET, GET,_POST等传参追踪数据库操作,也可以通过select , delete , update,insert 数据库操作语句反追踪传参。

现在的一般的CMS都注意到了SQL注入的严重性,所以他们对于注入都进行了一定的过滤,一般他们会用到两种过滤方法。

01.对于数字型的输入,直接使用intval($_GET[id]),强制转换成整数,这种过滤是毫无办法的。
a n n i d = ! e m p t y ( ann_id = !empty( annid=!empty(_REQUEST[‘ann_id’]) ? intval( R E Q U E S T [ ′ a n n i d ′ ] ) : ′ ′ ; 要 是 没 有 i n t v a l ( _REQUEST['ann_id']) : ''; 要是没有intval( REQUEST[annid]):;intval(_GET[id]) 那就尴尬了。
ad_js.php?ad_id=1%20union%20select%201,2,3,4,5,6,(select%20concat(admin_name,0x23,email,0x23,pwd)%20from%20blue_admin)
02.有些输入是字符型的,不可能转换成数字。这个使用就使用addslashes对输入进行转义。
aaa’aa ==> aaa\’aa
aaa\aa ==> aaa\aa
SELECT * FROM post WHERE id=’aaa\’ union select pwd from admin limit 0,1#

下面介绍下常见的SQL注入类型,最后再用DVWA进行分析。

漏洞(一)ip没过滤直接进到sql语句

函数讲解:

getenv : 这个函数是获得环境变量的函数,也可以用来获得$_SERVER数组的信息。

getenv(‘HTTP_X_FORWARDED_FOR’) --> $_SERVER[HTTP_X_FORWARDED_FOR]

当然http头还有referer 这也是可以伪装的,要是没有过滤好也会产生会注入问题

漏洞(二)宽字节注入 [对字符]
如果发现 cms是GBK 只有看看 能不能宽字节注入
Sqlmap 的unmagicquotes.py 可以进行宽字测试
解决宽字节注入办法:mysql_query(“SET character_set_connection=gbk,character_set_results=gbk,character_set_client=binary”, $conn);
到这里就一般高枕无忧了…
但是 要是画蛇添足得使用iconv就可能出现问题了
有些cms:
会加上下面语句避免乱码
iconv(‘utf-8’, ‘gbk’, $_GET[‘word’]);
将传入的word有utf-8转成gbk…
发现錦的utf-8 编码是0xe98ca6,而的gbk 编码是0xe55c
我们输入錦’ -->%e5%5c%27【%5c就是\】
在经过转移------>%e5%5c%5c%27【5c%5c就是\】这样我们就可以注入了

漏洞(三)二次注入
攻击payload首先被Web服务器上的应用存储,随后又在关键操作中被使用,这便被称为二次注入漏洞。
详细请看(http://www.cnblogs.com/ichunqiu/p/5852330.html)

漏洞(四)文件名注入
因为 F I L E , _FILE, FILE_SERVER不受gpc影响,那么可能造成注入…
有些cms会把name的值保存在数据库里,但又没有对name进行过滤。
乌云编号:wooyun-2010-051124

漏洞(五)报错注入
1、通过floor报错,注入语句如下:
and select 1 from (select count(),concat(version(),floor(rand(0)2))x from information_schema.tables group by x)a);
2、通过ExtractValue报错,注入语句如下:
and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables limit 1)));
3、通过UpdateXml报错,注入语句如下:
and 1=(updatexml(1,concat(0x3a,(selectuser())),1))
4、通过NAME_CONST报错,注入语句如下:
and exists(select
from (select
from(selectname_const(@@version,0))a join (select name_const(@@version,0))b)c)
5、通过join报错,注入语句如下:
select * from(select * from mysql.user ajoin mysql.user b)c;
6、通过exp报错,注入语句如下:
and exp(~(select * from (select user () ) a) );
7、通过GeometryCollection()报错,注入语句如下:
and GeometryCollection(()select *from(select user () )a)b );
8、通过polygon ()报错,注入语句如下:
and polygon (()select * from(select user ())a)b );
9、通过multipoint ()报错,注入语句如下:
and multipoint (()select * from(select user() )a)b );
10、通过multlinestring ()报错,注入语句如下:
and multlinestring (()select * from(selectuser () )a)b );
11、通过multpolygon ()报错,注入语句如下:
and multpolygon (()select * from(selectuser () )a)b );
12、通过linestring ()报错,注入语句如下:
and linestring (()select * from(select user() )a)b );

小技巧:最好可见在本地测试时候讲你的输入点打印出来
我会将用户的输入数据进行var_dump
重要的是对最终的sql语句进行var_dump,这和给你省去很多力气!我们只要var_dump($sql)然后再可以去黑盒测试。

DVWA分析

SQL Injection

选择Low级别,便于审计分析。首先我们黑盒测试一下,我们输入:

1‘or ’1‘=’1这个时候就可以判断出存在字符型注入。

1’ or 1=1 order by 2 # ,1’ or 1=1 order by 3 #,这个时候就可以判断2个字段。下面的就不进行注入爆库了。
代码审计——渗透测试(上)_第9张图片这个时候看下源码分析一下。


' . mysql_error() . '' ); // Get results $num = mysql_numrows( $result ); $i = 0; while( $i < $num ) { // Get values $first = mysql_result( $result, $i, "first_name" ); $last = mysql_result( $result, $i, "last_name" ); // Feedback for end user echo "
ID: {$id}
First name: {$first}
Surname: {$last}
"; // Increase loop count $i++; } mysql_close(); } ?>
可以看到,接收到submit传过来的值,id没有进行任何的检查与过滤,存在明显的SQL注入。

选择medium级别

代码如下
' . mysql_error() . '
' ); // Get results $num = mysql_numrows( $result ); $i = 0; while( $i < $num ) { // Display values $first = mysql_result( $result, $i, "first_name" ); $last = mysql_result( $result, $i, "last_name" ); // Feedback for end user echo "
ID: {$id}
First name: {$first}
Surname: {$last}
"; // Increase loop count $i++; } //mysql_close(); } ?>

可以看到对接收到的参数id 只是用函数mysql_real_escape_string()转义了一下。

下列字符受影响:

  • \x00
  • \n
  • \r
  • "
  • \x1a

而且前端页面设置了下拉选择表单,希望以此来控制用户的输入。不过没多大用处,我们依然可以通过抓包改参数,提交恶意构造的查询参数。

抓包更改参数id为1 or 1=1 #,查询成功,说明存在数字型注入。(由于是数字型注入,服务器端的mysql_real_escape_string函数就形同虚设了,因为数字型注入并不需要借助引号。),所以我们还是可以进行注入。

选择high级别

代码分析

Something went wrong.
' ); // Get results $num = mysql_numrows( $result ); $i = 0; while( $i < $num ) { // Get values $first = mysql_result( $result, $i, "first_name" ); $last = mysql_result( $result, $i, "last_name" ); // Feedback for end user echo "
ID: {$id}
First name: {$first}
Surname: {$last}
"; // Increase loop count $i++; } mysql_close(); } ?>

以看到,与Medium级别的代码相比,High级别的只是在SQL查询语句中添加了LIMIT 1,希望以此控制只输出一个结果。

虽然添加了LIMIT 1,但是我们可以通过#将其注释掉。这样的就又可以进行注入了。

SQL Injection(Blind),即SQL盲注

与一般注入的区别在于,一般的注入攻击者可以直接从页面上看到注入语句的执行结果,而盲注时攻击者通常是无法从显示页面上获取执行结果,甚至连注入语句是否执行都无从得知,因此盲注的难度要比一般注入高。目前网络上现存的SQL注入漏洞大多是SQL盲注。

代码分析

 0 ) {
// Feedback for end user
echo '
User ID exists in the database.
'; } else { // User wasn't found, so the page wasn't! header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' ); // Feedback for end user echo '
User ID is MISSING from the database.
'; } mysql_close(); } ?>

可以看到,Low级别的代码对参数id没有做任何检查、过滤,存在明显的SQL注入漏洞,同时SQL语句查询返回的结果只有两种

User ID exists in the database.
User ID is MISSING from the database.

因此这里是SQL盲注漏洞。

输入1’ and 1=1 #,显示存在。输入1’ and 1=2 #,显示不存在。说明存在字符型的SQL盲注。这里仅作判断存在SQL注入,不进一步攻击。

选择medium级别

代码分析

 0 ) {
// Feedback for end user
echo '
User ID exists in the database.
'; } else { // Feedback for end user echo '
User ID is MISSING from the database.
'; } //mysql_close(); } ?>

可以看到对接收到的参数id 只是用函数mysql_real_escape_string()转义了一下。

下列字符受影响:

  • \n
  • \r
  • "
  • \x1a
    而且前端页面设置了下拉选择表单,希望以此来控制用户的输入。不过没多大用处,我们依然可以通过抓包改参数,提交恶意构造的查询参数。

抓包更改参数输入1’ and 1=1 #,显示存在。输入1’ and 1=2 #,显示不存在。说明存在字符型的SQL盲注,查询成功,说明存在注入。

high级别

代码分析

 0 ) {
// Feedback for end user
echo '
User ID exists in the database.
'; } else { // Might sleep a random amount if( rand( 0, 5 ) == 3 ) { sleep( rand( 2, 4 ) ); } // User wasn't found, so the page wasn't! header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' ); // Feedback for end user echo '
User ID is MISSING from the database.
'; } mysql_close(); } ?>

可以看到,High级别的代码利用cookie传递参数id,当SQL查询结果为空时,会执行函数sleep(seconds),目的是为了扰乱基于时间的盲注。同时在 SQL查询语句中添加了LIMIT 1,希望以此控制只输出一个结果。

虽然添加了LIMIT 1,但是我们可以通过#将其注释掉。但由于服务器端执行sleep函数,会使得基于时间盲注的准确性受到影响,但仍然是可以注入的。

你可能感兴趣的:(笔记,web安全)