′ 雨。 · 2015/01/14 10:08javascript
里面不少都是像laterain学习到的, 若是能考上cuit的话 自动献菊花了。php
首先拿到一份源码 确定是先install上。 而在安装文件上又会常常出现问题。html
通常的安装文件在安装完成后 基本上都不会自动删除这个安装的文件 我遇到过的会自动删除的好像也就qibocms了。java
其余的基本都是经过生成一个lock文件 来判断程序是否安装过了 若是存在这个lock文件了 就会退出了。 这里首先 先来讲一下安装文件常常出现的问题。mysql
这种的虽然很少 可是有时仍是会遇到个。 在安装完成后 并不会自动删除文件 又不会生成lock来判断是否安装过了。 致使了能够直接重装过linux
例子: WooYun: PHPSHE B2C 重装。程序员
由于install 通常都会有step 步骤啥的。。 Step 1 check 啥啥 step 2 是安装啥的。 而一些cms 默认step是1 而step又是GET 来的 而他check lock的时候就是在step1里面。 这时候若是咱们直接用GET提交step 2 那么就直接进入下一步了 就没check lock了。web
例如某cms中的安装文件算法
#!php
if (empty ($step))
{
$step = 1;//当用户没有提交step的时候 赋值为1
}
require_once ("includes/inc_install.php");
$gototime = 2000;
/*------------------------
显示协议文件
------------------------*/
if ($step == 1) //当1才检测lock
{
if (file_exists('installed.txt'))
{
echo '<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
你已经安装过该系统,若是想从新安装,请先删除install目录下的 installed.txt 文件,而后再安装。
</body>
</html>';
exit;
}
include_once ("./templates/s1.html");
exit ();
}
/*------------------------
测试环境要求
------------------------*/
else
if ($step == 2) // 咱们直接提交step为2 就不check lock了
{
$phpv = @ phpversion();
$sp_os = $_ENV["OS"];
$sp_gd = @ gdversion();
$sp_server = $_SERVER["SERVER_SOFTWARE"];
$sp_host = (empty ($_SERVER["SERVER_ADDR"]) ? $_SERVER["SERVER_HOST"] : $_SERVER["SERVER_ADDR"]);
$sp_name = $_SERVER["SERVER_NAME"];
$sp_max_execution_time = ini_get('max_execution_time');
$sp_allow_reference = (ini_get('allow_call_time_pass_reference') ? '<font color=green>[√]On</font>' : '<font color=red>[×]Off</font>');
$sp_allow_url_fopen = (in
复制代码
#!php
header("Content-Type: text/html; charset={$lang}");
foreach(Array('_GET','_POST','_COOKIE') as $_request){
foreach($$_request as $_k => $_v) ${$_k} = _runmagicquotes($_v);
}
function _runmagicquotes(&$svar){
if(!get_magic_quotes_gpc()){
if( is_array($svar) ){
foreach($svar as $_k => $_v) $svar[$_k] = _runmagicquotes($_v);
}else{
$svar = addslashes($svar);
}
}
return $svar;
}
if(file_exists($insLockfile)){
exit(" 程序已运行安装,若是你肯定要从新安装,请先从FTP中删除 install/install_lock.txt!");
}
foreach($$_request as $_k => $_v) ${$_k} = _runmagicquotes($_v);
复制代码
这里是一个常常遇到的一个变量覆盖。sql
致使了咱们能够覆盖掉$insLockfile 从而让file_exists 为false就不会退出了。致使再次重装。 这个变量覆盖不知道咋的 能在一些小cms的安装文件里看到。
以前看的xdcms 和 frcms 都存在这个变量覆盖。
这个从早期的phpdisk 的那个 header bypass 到如今的又遇到各类。
好久前的phpdisk的安装文件中。
判断是否存在lock文件 若是存在lock文件了 就会header到index.php
可是header 后 他并无exit 因此并不会退出 致使了又是一个重装。
跟这种相似的还有javascript 弹个框 啥的 也没exit的。
例子: WooYun: 开源轻论坛StartBBS前台getshell
例子: WooYun: FengCMS 修复不当致使getshell
这个也比较少, 就随便说句。 就是像dedecms好久之前的那样 在安装完成后会在install.php rename 为 Install.php.bak 可是因为apache的解析漏洞 若是没法识别最后的一个后缀的话 就会向上解析,那么就又成php了。 而后又结合dedecms安装时的变量覆盖 又成重装了。
这种例子也不算太多, 本身好像也没遇到过太多。
首先以以前发过的sitestar举例下
#!php
if(file_exists($lockfile) && ($_a=='template' || $_a=='setting' || $_a=='check')) {
exit('please delete install.lock!');
}
复制代码
这里咱们来理解一下这个逻辑, 这里的file_exists($lockfile) 由于安装成功后 lockfile 确定存在的 因此这里确定会是true 而后再看一下 这里是一个 && true true 才会进入语句块。 那么若是$_a 不为 template 、 setting 、 check 的话 那么后面的就为false True and false => false就不会进入这个语句块 就不会exit 再配合后面的
#!php
else if($_a=="create"){
$link = mysql_connect($db_host,$db_user,$db_pwd);
复制代码
恰好有个其余的 若是$_a 为 create 那么就不会退出这个脚本
恰好这个create 能达到Getshell的效果
例子: WooYun: 建站之星Sitestar前台Getshell一枚
剩下的还有hdwiki以前也有一个基本差很少这样的例子
#!php
if (file_exists(HDWIKI_ROOT.'/data/install.lock') && $step != '8') {
echo "<font color='red'>{$lang['tipAlreadyInstall']}</font>";
exit();
}
复制代码
若是step为8的话 那么就不会执行exit了。
#!php
case 8:
require_once HDWIKI_ROOT.'/config.php';
require_once HDWIKI_ROOT.'/lib/hddb.class.php';
require_once HDWIKI_ROOT.'/lib/util.class.php';
require_once HDWIKI_ROOT.'/lib/string.class.php';
$db = new hddb(DB_HOST, DB_USER, DB_PW, DB_NAME, DB_CHARSET);
//install
$setting=$db->result_first('select `value` from '.DB_TABLEPRE.'setting WHERE `variable` = \'site_appkey\'');
if ($setting){
echo "<span style='font-size:20px;'>百科联盟开通成功.</span><a href='../'>进入首页</a>";
break;
}
//update info
$data = $_GET['info'];
$data = str_replace(' ', '+', $data);
$info = base64_decode($data);
if ($info){
$obj = unserialize($info);
if(is_array($obj)){
$url2 = 'http://localhost/count2/in.php?action=update&sitedomain='.$_SERVER['SERVER_NAME'].'&info='.$data;
$data = util::hfopen($url2);
//if gbk then toutf8
if ($lang['commonCharset'] == 'GBK'){
$obj['sitenick'] = string::hiconv($obj['sitenick'], 'gbk', 'utf-8');
复制代码
恰好这里step 8 又能执行一些特殊的操做。。 如今就把case 8 注释掉了。
这里代码我就不复制过了 省得占篇幅。
这里差很少是我比较常遇到的一些安装文件常常遇到的问题了,忽然想也想不到其余啥的了。
这里再来谈一下包含
其实包含也并无什么好说的。
包含通常也就分为LFI RFI local file inclusion 和 remote嘛
对于LFI的话 由于不少都限制了包含的后缀结尾必须为.php Include ($a.'.php') 例如这种的
因此咱们想包含咱们的图片马儿的话 那么就须要截断后面的这.php
1: 00截断 须要gpc off && php<5.3.4 2: 长文件名截断 反正这个我不多成功。 3: 转换字符集形成的截断 这个对包含的话基本用不上。上传的话 就是felixk3y牛发的那个转换字符集形成的上传截断那个。
还有一些cms限制包含的后缀必须为.php的时候用的是截取字符判断是否是.php 例以下面一段简单的代码
#!php
$include_file=$_GET[include_file];
if ( isset( $include_file ) && strtolower( substr( $include_file, -4 ) ) == ".php" )
{
require( $include_file );
}
复制代码
对传递过来的截取了后面4个字符 判断是否是.php 若是是.php才进行包含。
这里能够用zip(或者phar)协议嘛(固然这个也是找laterain学的 哈哈)。
首先新建一个1.php 里面随便写个phpinfo把
而后压缩成.zip 而后把zip的名字改为 yu.jpg
而后把这个.jpg上传上去 而后包含
对于一些LFI 找不到上传图片的地方的话 也有不少牛发过了一些不能上传图片LFI的技巧 各类包含日志 环境变量啥的 这里我就也很少说了。
下面再来讲RFI
若是能RFI的话 那么就是最方便的了。
包含远程文件 或者又是php://input data啥的 各类伪协议。
可是也都知道RFI最大的限制条件就是须要allow_url_include on
且 变量前未定义路径 或者 常量。
Allow_url_include 默认都是off
那么不管是allow_url_include on 仍是 变量前无路径 或者 常量
那都是rfi的硬伤。
这里介绍一种在allow_url_include off的状况下也能rfi的
可是成功率也并不过高。
首先在php.ini里看一下allow_url_include
; Whether to allow include/require to open URLs (like http:// or ftp://) as files.
allow_url_include = Off
复制代码
翻译一下,容许包含url 例如 http:// ftp:// 之类的协议。
当off的时候确定就是不容许去包含这样的协议。
这里咱们先来测试一下
#!php
<?php
include($_GET[yu]);
复制代码
首先 allow_url_include && allow_url_fopen 都为on的时候
成功RFI。
而后 allow_url_include 为 on allow_url_fopen 为off
直接包含远程文件失败 这时候咱们用一下伪协议试试。
再次成功rfi。
当allow_url_include && allow_url_fopen 为off的时候。
伪协议失败。
包含文件
URL file-access is disabled in the server configuration 不容许包含。
确定还有很多人记得好久之前的那个星外无可执行目录的时候
利用远程调用cmd继续提权
那个利用的是共享文件 而后在星外主机上来执行。
那么这里咱们也试试
包含共享文件成功。 这里只本地测试了 没具体测试。
可是因为445的缘由 可能基本都失败。
下面来讲一下注入。 这里谈的是mysql。 注入大概也就是把用户可控的一些变量, 带入到了数据库的各类操做当中且没有作好很好的过滤。 好比注册用户的时候检测用户名是否存在的时候,把用户提交的用户名拿到数据库中去查询。 查询是否存在这个用户名, 若是这里对用户名没有作好过滤的话 那么用户就能够提交一些特殊字符来注入了。
如今注入的主要缘由是 不少程序员在写sql语句的时候 仍是搞的语句拼接。
一些用了预编译或者是在查询的函数中再来过滤 不少时候就给跪了。
select update insert delete
复制代码
由于mysql query 并不能执行多行语句, 除非pdo啥的能多行 因此不能像mssql那样 还能在select后执行个update管理的语句。
对于这四种类型的注入通常的语句的构造也不一样。
若是有mysql error的话
那么这四种就都能用报错注入 这种是比较方便的
若是没mysql error的话
Select 的注入 通常是用union select 若是把对数据库中的查询结果展现出来的话那么就能直接出数据了。 若是无回显的话 那么固然就是盲注了。
Update的注入 若是是在update set的位置的话 那么咱们能够找找这个表的哪一个column会被展现出来 例如若是一个update的注入点是在用户表且是在set位置可控的话 那么咱们能够update email这个column 而后去用户资料看一下本身的email就出数据了 语句例如 update table set email=(select user()) 若是是在where后的话 那么通常也就是盲注了。
Insert 的注入 也是通常是经过找哪一个column会不会显示出来 尽可能把要出的数据插入到这个column里面去。 若是没显示的话 也是盲注。
Delete的注入 通常都是盲注了。
数字型注入主要就是由于他的变量并无用单引号引住。
可是基本上都是被强制类型转换了 intval啥的。
可是有时候会有遗漏的嘛。
而字符型和搜索型的 都是会有单引号引住的。
因此须要闭合单引号再来进行注入。
说到单引号不得不说个php.ini里的配置
Magic_quotes_gpc 在稍微高点的版本默认都是on
可是却在应该是5.4就已经废除了。
从字面意思上来看 就是对GPC QUOTE嘛
GPC 对应的就是GET POST COOKIE
会被转义的字符为 ' “ \ NULL 会在前面添加上一个转义符。
致使了失去原本的意义 没法闭合单引号进行注入。
(1) 全局没有作addslashes的
像这种全局没有对GET POST COOKIE 作addslashes的 这种厂商基本是会在查询的时候 再对一些用户可控的变量进行addslashes 甚至是不进行addslashes 直接带入查询的。
这样的就算在查询的时候进行addslashes 在不少时候也都能找到几处遗漏了addslashes的。 这种的比较简单 很少说。
(2) 全局作addslashes
如今稍微好一点的厂商都知道了在全局文件中对 GET POST COOKIE 作addslashes (甚至是在带入查询的函数中再作了转义或者预编译 这种给跪) 因此基本不用担忧哪里遗漏了哪里忘记了addslashes) 这种的基本是首先先get magic quotes gpc 判断gpc是否开启 若是没开启的话 再调用addslashes来转义 。 若是开启的话 就不用来addslashes了。 没开启就addslashes.
这里主要讲的就是这种类型的注入的一些常见的
这个是一个老生常谈的问题, 从一开始的数据库字符集GBK的宽字节注入 到如今也有好久了。
可是并非字符集为GBK的就能宽字节注入。
总有一些小伙伴说咋我看的cms 字符集是gbk的 可是咋不能宽字节呢?
这是由于数据库的链接方式不一样
Set names gbk 这样的就能宽字节
可是如今这样的基本都看不到了。 由于基本都是设置了二进制读取了。
Binary。
这样的宽字节基本没了, 却有了另一种。
由于转换字符集形成的宽字节注入
从utf8转到gbk 或者从gbk转到 utf8啥的。
錦 从UTF8 转成 GBK以后成了 %e5%5c 74cms对GET POST COOKIE …… 都作了addslashes 因此' 转义后为\' ->%5C %e5%5c%5c' 两个\ 则单引号出来
例子2: WooYun: qibocms 下载系统SQL注入一枚(官网可重现)
由于在全局文件中addslashes
若是咱们能找到一些解码的 例如urldecode base64_decode的
那么咱们先提交encode以后的 那么就能不被转义了。
而后decode后 再带入查询 形成了注入 无视gpc。
这种的很常见。
例子不少 随便找一个
例子: WooYun: qibocms B2b 注入一枚 //qibocms 注入
例子: WooYun: phpdisk V7 sql注入2 //phpdisk 注入
常见的变量覆盖 有啥extract 和 parse_str 函数啥的
固然还有$$
变量覆盖得结合一些具体的场景了。
例如extract($_POST)啥的 直接从POST数组中取出变量
这样的仍是遇到过几个 而后覆盖掉以前的一些变量。
覆盖的话 通常是覆盖掉表前缀之类的
Select * from $pre_admin where xxx 像这种的就覆盖掉$pre
而后直接补全语句而后注入。
例子: WooYun: qibocms分类注入一枚可提高本身为管理
例子2: WooYun: phpmps 注入一枚
固然 $$ 也挺常常用到的 这个例子很不错。
例子3: WooYun: MetInfo最新版(5.2.4)一处SQL盲注漏洞
一些cms中 总有一些逗比过滤函数
会把’ 啥的 replace 成空
可是他彷佛忘记了本身全局有转义?
用户提交一个' 全局转义成\' 而后这过滤函数又会把 ' replace 成空
那么就留下了\ 致使能够吃掉一个单引号 是double query的话
Select * from c_admin where username=’admin\’ and email=’inject#’
复制代码
这样就能够注入了。
话说以前还遇到过一个厂商。。 以前提交了漏洞 是由于他会把
' " 都会替换成空 而后提交以后 他就去掉了' 就是不把' 替换成空了。
可是他彷佛忘记了 " 也会被转义。。 那么提交一个 " 就又剩下了一个转义符。
例子: WooYun: PHPCMS全版本通杀SQL注入漏洞
固然还有一些replace 是用户可控的。就是说用户能够想把啥提交成空就提交成空
例如好久前的cmseasy 和 ecshop的那个注入
例如这段代码
#!php
$order_sn = str_replace($_GET['subject'],'',$_GET['out_trade_no']);
复制代码
这里由于会被转义 若是提交 ' 就成 \' 这里能够看到
这里清成空的 是咱们get来的 那咱们就想办法把\ replace掉
可是若是咱们GET提交把\ replace 那么会被转义 就是replace掉\
可是咱们只是 \' 因此不能把\去掉 若是我有\ 还要你清空个毛啊。
这里咱们来理清一下思路。
Addslashes 会对' " \ NULL 转义
' => \'
" => \"
\ => \\
NULL => \0
复制代码
那这里咱们就提交 %00’ 就会被转义生成 \0\' 这时候咱们再提交把0替换成空 那么就成了\' 单引号也就成功出来了。
例子: WooYun: cmseasy绕过补丁SQL注入一枚
由于在不少cms中 基本上都只是对GET POST COOKIE 进行addslashes
而没有对SERVER进行转义。
而一些SERVER的变量也是用户能够控制的。
例如啥 QUERY_STRING X_FORWARDED_FOR CLIENT_IP HTTP_HOST ACCEPT_LANGUAGE 不少。
这里最多见的固然也就是X_FORWARDED_FOR
这个通常是在ip函数中用到 若是后面没有进行验证ip是否合法的话就直接return 这个大部分时候都会致使注入。
例子1: WooYun: Phpyun注入漏洞二
这里说到验证ip 这里基本都是用的正则来验证是否合法。
而一些厂商连正则都写错。
例如在cmseasy中的验证ip的正则中(%.+)
致使了后面能够写任意字符。
例子2: WooYun: CmsEasy最新版本无限制SQL注射
最近本身在看douphp 里面的验证ip的正则本身也发现了一点小问题。
不过也就只是小问题而已。
Douphp中的获取ip的函数。
#!php
function get_ip() {
static $ip;
if (isset($_SERVER)) {
if (isset($_SERVER["HTTP_X_FORWARDED_FOR"])) {
$ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
} else if (isset($_SERVER["HTTP_CLIENT_IP"])) {
$ip = $_SERVER["HTTP_CLIENT_IP"];
} else {
$ip = $_SERVER["REMOTE_ADDR"];
}
} else {
if (getenv("HTTP_X_FORWARDED_FOR")) {
$ip = getenv("HTTP_X_FORWARDED_FOR");
} else if (getenv("HTTP_CLIENT_IP")) {
$ip = getenv("HTTP_CLIENT_IP");
} else {
$ip = getenv("REMOTE_ADDR");
}
}
if (preg_match('/^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/', $ip)) {
return $ip;
} else {
return '127.0.0.1';
}
}
}
复制代码
来看看验证ip是否合法的正则
#!php
preg_match('/^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/', $ip)
复制代码
这里咱们仔细来看看 他这里是准备匹配小数点 可是他直接写成了.
都知道在正则中.表示的是匹配任意字符 除开换行符意外 可是在开启/s 修正符之后 换行符也会匹配。
不过他这个.后面没啥+或者?的 致使也就只能写一个字符。
他这里直接写成了. 那在这里咱们就能引入单引号了。不过也就一个字符。
这里的正确写法应该是.
也差很少 也是由于全局只对COOKIE GET POST 转义 遗漏了FILES 且不受gpc。
FILES 注入通常是由于上传 会把上传的名字带到insert当中入库。
而后这里文件的名字是咱们能够控制的 因此致使了注入。
而这里的上传的名字是咱们能够控制的。
例子: WooYun: qibocms 黄页系统SQL注入一枚
还有一些 在入库的时候才对文件的名字进行了转义 而在获取后缀后 在入库的时候对文件名转义了却没有对后缀转义也致使了注入
例子: WooYun: Supesite 前台注入 #2 (Insert)
好久之前php<4.20的时候 为了方便 register_globals 默认都是on。
而到了后面 register_globals 的弊端也显现了出来, 因此也在好久之前默认都是off了。
而到了如今, 不少cms 却喜欢模仿register_globals 搞起了伪全局机制。
例如啥qibocms metinfo destoon 啥的啊。
这样是方便了很多, 可是若是哪里遗漏了初始化 那么就会致使注入了。
感受这种的挺好玩的 多找了几个例子。
例子: WooYun: qibocms地方门户系统注入一个问题(demo测试)
例子: WooYun: qibocms地方门户系统注入(多处相似,demo测试)
例子: WooYun: 齐博地方门户系统SQL注入漏洞(无需登陆可批量)
由于在对全局转义的时候
不少cms 都只是判断gpc 是否开启
若是off 就对数组中的value就行addslashes
却忘记了对数组中的key进行转义。
那么这样也致使了一个问题。 也就是在Gpc off的时候那么数组的key没有被过滤 致使能够引入单引号。(据说低版本的php对二维数组中的key就算gpc on 也不会转义)
若是哪里把数组中的key 读取出来 而后把key带入到了查询当中
那么也会形成安全问题。
并且这样的例子不少。 简直惨不忍睹。 例子: WooYun: qibocms V7 整站系统最新版SQL注入一枚 & 另一处能引入转义符的地方。 //数组key的注入例子: WooYun: qibocms多个系统绕过补丁继续注入2
例子: WooYun: qibocms所有开源系统 Getshell
例子: WooYun: Discuz 5.x 6.x 7.x 前台SQL注入漏洞一枚
这种算是比较常见的一种注入的。
代码大概如
#!php
<?php
$key=0;
$a=$_GET[a][$key];
$b=$_GET[b];
Mysql_query("select * from table where xxx='$a' and xx='$b'")
复制代码
若是这里$_GET[a] 提交的是一个数组 且含有一个key为0的那么$a就是对应的这个key的value
可是这里并无强制要求为数组。
那么咱们提交一个字符串 那么后面的[0] 那么就是截取的第一个字符
在全局中 单引号被转义为\' 截取第一个字符就为了\
吃掉一个单引号 而后就在$b处写入inject能够注入了。
例子: WooYun: qibocms 地方门户系统 注入#4(demo测试)
还有map发的那Disucz 7.2的那注入也同样。
很常见的一种洞。
比较常见的uc 和 alipay tenpay chinabank 啥的
特别是uc 由于默认uc里面都会striplashes
Uc的话 通常会遇到的问题是uckey默认的。
或者是uckey这个常量根本就没有初始化。
致使了uckey可控 再致使了Getshell 或者 注入啥的。
还有tenpay 和 alipay 啥的 一些是由于忘记把过滤的文件包含进来
且key默认是空的 致使能够经过验证。
例子: WooYun: phpmps 注入 (可修改其余用户密码,官网成功) // phpmps uc致注入
例子: WooYun: PHPEMS (在线考试系统) 设计缺陷 Getshell一枚(官网已shell) /phpems uc致getshell
例子: WooYun: 最土团购注入一枚可直接提高本身为管理 & 无限刷钱。 //最土团购 chinabank致注入
例子: WooYun: Destoon Sql注入漏洞2(有条件) //destoon tenpay致注入
例子: WooYun: CSDJCMS程式舞曲最新版Sql 一枚 //csdj tenpay致注入
其实也不仅是数字型 只是说一些忘记加单引号的地方都这样。
只是通常数字型的都不会加单引号的。
通常的是
#!php
$id=$_GET[id];
Select * from table where id=$id;
复制代码
$id 没被单引号 且 没有被强制类型转换 那么就算addslashes了 因为不须要去闭合单引号 因此也无影响。
例子: WooYun: qibocms 地方门户系统 注入#3 (demo测试)
并非一些数字型 一些其余的点也有些忘记加单引号 致使了注入。 例子: WooYun: Supesite 前台注入 #3 (Delete)
这里supesite的注入还涉及到了一个设计缺陷。 这里把
#!php
$query = $_SGLOBAL['db']->query('SELECT * FROM '.tname('spacetags').' WHERE itemid=\''.$itemid.'\' AND status=\''.$status.'\'')
复制代码
$itemid 首先带入到了查询当中 是被单引号了的。。 若是查询出来的有结果 才会带入到delete中 若是无结果 就不执行delete的语句了。 而在数据库中itemid中 存储的是int类型 因此他这里本意是想要用户只能提交数字型才能查询出结果。 若是不是提交的数字的话 那么就查询不出来结果 就不去执行下面的delete语句了。 可是因为mysql的类型转换 由于他这里储存的是int类型 因此咱们提交4xxxxx 跟咱们提交4 是同样的
#!php
$_SGLOBAL['db']->query('DELETE FROM '.tname('spacetags').' WHERE itemid='.$itemid.' AND tagid IN ('.simplode($deletetagidarr).') AND status=\''.$status.'\'');
复制代码
而后就执行这个delete语句 而后没单引号 形成了注入。
例子: WooYun: phpyun v3.2 (20141226) 两处注入。
这个phpyun的注入 主要是由于php是弱类型语言
一些厂商喜欢这样写
#!php
If ($a>1){
Mysql_query(select id from table where id=$a)
}
复制代码
他这个原本是想用户提交数字才能经过这个判断 可是因为弱语言 1+asd啥的 都能经过 因此又致使了注入。
也是一种比较常见的注入。 涉及到的是入库和出库。 由于有全局转义 而后入库的时候
#!php
Insert into table (username) values ('a\'');
复制代码
这样入库后 转义符就会消失 那么就是a' 若是哪里再把这个查询出来 那么也就是出库的是a' 若是再把出库的 再带入到了查询啥的 那么就再次成功的引入了单引号致使了注入
例子: WooYun: phpyun v3.2 (20141226) 两处注入。 例子: WooYun: qibocms 地方门户系统 二次注入#5(demo测试) 例子: WooYun: 74cms (20140709) 二枚二次注入 例子: WooYun: Hdwiki最新版二次注入一枚
比较是硬伤的是 不少时候数据库中存储的长度是有限制的。 因此一些也不是太好利用。
不知道也应不该该把这个归为一类。
大概是由于一些查询的时候 直接把$_POST啥的 直接带入到了查询函数当中
例如cmseasy的rec_insert的查询函数中。
而后foreach key 出来 而后foreach 出来的key 作了查询中的column
这种的防止方法通常是 把数据库中的column查询出来 而后in_array 判断一下$_POST出来的key 是否在数据库中的column中 下面两个例子就是这样修复的。
例子: WooYun: 云人才系统SQL注入,绕过WAF 例子: WooYun: Cmseasy SQL注射漏洞之三
有些cms 在全局addslashes后 而后在后面的文件中又stripslashes
去掉了转义符 而后又能够闭合单引号了。
#!php
$_SESSION['flow_consignee'] = stripslashes_deep($consignee);
复制代码
例子: http://www.2cto.com/Article/201301/182509.html //以前的ecshop注入 。
有些cms 有的时候会限制用户输入的长度
因此只截取一部分
例如uchome的cutstr($asd,32);
这样只容许输入32个字符 并且uchome里面的这个也没有像dz那样截取字符的后面加...
那么若是咱们提交一个1111111111111111111111111111111’
被转义后成1111111111111111111111111111111\’
而后截取32个字符 就是1111111111111111111111111111111\
若是又是double query的话 吃掉一个单引号 而后下一个连着的可控变量又能够注入了。
结果在uchome中找到了个能引入转义符的 结果只有一个可控的。
例子: WooYun: Hdwiki (20141205) 存在7处SQL注入漏洞(含以前处理不当安全的漏洞) //里面的0x06
不知道放哪。这个也放到注入板块来把。。
其实就是此次的DZ6.X 7.X 那个任意代码执行的漏洞
#!php
if (isset($_REQUEST['GLOBALS']) OR isset($_FILES['GLOBALS'])) {
exit('Request tainting attempted.');
}
foreach(array('_COOKIE', '_POST', '_GET') as $_request) {
foreach($$_request as $_key => $_value) {
$_key{0} != '_' && $$_key = daddslashes($_value);
}
}
复制代码
主要关键代码就上面这两段。 这里把GET POST COOKIE 循环出来 而后注册一个变量 可是 这里不容许建立GLOBALS变量 而后DZ7.X 就是用这样处理的 若是设置了REQUEST 的 GLOBALS
就直接退出
这段代码在好久之前确实是没什么问题
由于那时候的request order 仍是gpc
可是在php 5.3 之后 request order 默认成了gp
也就是成了get 和 Post 不包含cookie了。
因此 $_REQUEST里面就不包含COOKIE提交来的了。
并且这后面也把COOKIE循环出来 注册变量
因此这里咱们在COOKIE里面提交GLOBALS 就不会被检测出来了。
并且也成功注册了GLOBALS变量。
因此在结合后面的一些些代码就形成了代码执行。
例子: WooYun: Discuz!某两个版本前台产品命令执行(无需登陆)
以上就差很少是我常常所遇到的注入问题 好像暂时也想不到其余什么的了
下面介绍一些我在cms遇到的找回密码时候犯得错误。
找回密码不少都是验证的token 就是在找回密码的时候生成一个token 而后存储到数据库中。 而后把找回密码的地址发到邮箱中 url中就含有token 由用户点开后就能修改密码 基本就是验证的这个token。 其实通常的能够找回任意用户密码的缘由就是弱token 致使能够被攻击者搞到。 包括不少厂商验证的时候就是四位纯数字啥的。 能够枚举。 固然也能够延伸一下, 一些cms的密码加密方式很难破掉。 有时候咱们拿到了管理的密码破不掉也是鸡肋。 因此有时候也能够利用这种方法 通常找回密码是用的邮箱 首先咱们能够注入把管理的邮箱注入出来 而后再去找回密码 再把数据库的token注入出来 再构造一下地址 就能重置密码。 这个给我印象比较深的是 在ssctf的比赛中嘛 当时机油问了问我 那wordpress那题 有个插件的注入 而后由于都知道wp的加密基本很难破。 因此也是用的这种方法。 由于通常都是弱token的问题 随便找几个例子了
#!php
$resetpwd = md5(rand());
复制代码
能够看到这个生成的token 就是对rand()函数生成出来的数字进行md5一次
来看一下rand()
注释:在某些平台下(例如 Windows)RAND_MAX 只有 32768。若是须要的范围大于 32768,那么指定 min 和 max 参数就能够生成大于 RAND_MAX 的数了,或者考虑用 mt_rand() 来替代它。 若是不指定一些参数的话 那么最大值才32768 一个并不算大的值 那么咱们首先对这32768种可能 md5出来一个列表 而后咱们直接枚举这32768种可能 总会有一个对的。
例子: WooYun: Thinksaas找回密码处设计错误利用帐户可找回密码。
#!php
$encryptstring=md5($this->time.$verification.$auth);
复制代码
补丁后 多了一个$auth $timetemp=date("Y-m-d H:i:s",$this->time); $auth = util::strcode($timetemp, 'ENCODE'); 能够$auch 是对时间来了一个算法。 结果这个算法的KEY并无初始化 致使了若是咱们知道了这个时间 就能够本身生成出来加密的字符串 这里带入算法的是时间 这里是咱们能够知道的。
例子: WooYun: Hdwiki设计缺陷知邮箱可改密码(包括管理员) //绕过补丁继续找回hdwiki任意用户密码
这个上传就大概说说。
通常的上传漏洞多是未验证上传后缀 或者是验证上传后缀被bypass 或者是上传的文件验证了上传后缀可是文件名不重命名。
对于那些验证了后缀可是文件名不重命名的
通常能够试试截断yu.php%00.jpg 固然%00 要urldecode
固然 毕竟截断鸡肋了。 上面提到过限制条件了。
还能够是结合各类webserver的解析漏洞
例如iis6的 xx.asp/yu.jpg yu.php;.jpg yu.asp;.jpg aspx 固然不能这样解析了。
若是不重命名的就上传这样就好了。
Nginx的低版本解析漏洞: yu.jpg/1.php 对于这种直接上传一个xxxx.jpg 再在这后面加上各类/.php 试试的
Apache解析漏洞 yu.php.xxx 在最后一个后缀识别不出来的时候 那么就向上解析
最终解析成.php
像phpweb后台那个上传漏洞。不少人遇到apache的时候
没法截断的时候就上传一个yu.php.jpg 有些人比较疑问的是为啥有时候成功有时候失败。
这个主要是看os 像windows的话 .jpg 就直接是图片了
因此在windows下 就直接识别成图片了 而不是.php
而在linux下 .jpg不被识别 就向上识别成.php
这些解析漏洞在上传中也挺常常遇到的。
上传的验证通常是 MIME、客户端的JS验证、白名单、黑名单。
前面两种都比较简单。
白名单就是容许用户上传哪些后缀的。 黑名单就是禁止用户上传哪些后缀的。
这两种相比来讲通常是黑名单容易bypass一点。 黑名单的绕过仍是得具体看他黑名单的代码。 有的直接大小写就过。 有些没对文件名trim的 直接在文件名后面加空格。 Windows下的 文件名后%81-%99 decode后的 或者是windows下的特性 .php::$data 这样上传上去依旧是.php
其实上传还挺重要的。。 可是我又不知道说哪些。 仍是具体看代码把。
这个主要是涉及到的是 任意文件删除 任意文件复制 任意文件重命名 任意文件移动 任意文件下载……。 由于像如今的cms不少都自带得有加密 解密 函数 例如qibocms的mymd5 Dz的authcode 啥的。 对于这些任意文件操做的 首先能够试试拿到配置文件中的数据库的链接账号和密码 尝试外联一下 可是不少时候都是只容许本地连的 不少时候很差利用的时候能够利用拿到配置文件 而后拿到这些函数的key 而后本身生成一个加密的字符串 而后再结合具体的代码进行最大化的利用。
通常是挺很差利用的,仍是结合具体的场景,有些由于全局的过滤而不能注入的,能够尝试用任意文件删除,删掉这个文件,再进行注入 通常的利用仍是经过删除安装文件生成的lock文件,而后达到重装。
不过这样弊很大。
例子: WooYun: phpyun (20141230) 任意文件删除致注入可改任意用户密码(4处打包)
复制的话 确定涉及到了 要复制的文件 要复制到的路径。
若是是要复制的文件可控 要复制到的路径不可控的话 例如qibocms以前的一个洞
#!php
copy(ROOT_PATH."$webdb[updir]/$value",ROOT_PATH."$webdb[updir]/{$value}.jpg");
复制代码
这里$value 是可控的 可是又不能截断 复制到的路径限制了.jpg结尾。
这时候咱们就能够把$value控制为 保存了qibocms的加密函数的key的配置文件
而后复制后 成了一个.jpg 那咱们就能够直接打开 看到key了
例子: WooYun: Qibocms图片系统任意文件查看致使的多处注入(可提高本身为管理员)
若是两个都彻底可控的话 那确定是直接把本身的图片复制成一个.php马儿了。
其实跟上面复制差很少, 不少时候也是经过下载配置文件 拿到key。 再进行各类操做。。
例子: WooYun: qibocmsV7整站系统任意文件下载致使无限制注入多处(可提高本身为管理 Demo演示)
这个例子还涉及到了一个win的特性bypass 黑名单
这种问题主要是想进各类办法把这些加密函数的key拿到 或者想办法加密一些特殊字符而后拿到加密的字符串
加密函数确定就涉及到了各类算法。
算法问题通常主要是由于一些弱算法 致使了 知道明文 知道密文 可逆
拿到加密函数中的key 从而再本身生成一个本身想要的加密字符串。
再结合具体的点 而后进行具体的利用。
例子: WooYun: DedeCMS-V5.7-SP1(2014-07-25)sql注入+新绕过思路 例子: WooYun: phpcms最新版绕过全局防护暴力注入(官网演示)
还有的一类算是 一个点 要加密的是咱们可控的 并且密文会输出 并且这个可控的点能引入特殊字符 那么咱们就把一些特殊字符带入到这里面 而后拿到密文 再找到一处decode后会进行特殊操做的点 而后进行各类操做。
例子: WooYun: 程氏舞曲CMS某泄露,致使sql注入
例子: WooYun: PHPCMS最新版(V9)SQL注入一枚
例子: WooYun: 一个PHPWIND可拿shell的高危漏洞
例子: WooYun: PHPCMS V9 一个随心所欲的漏洞
寥寥草草的把这篇文章写完了。
比本身预期想的少写了不少, 由于在一开始写的时候仍是挺有感受的。
由于读书一个月也才放一次假, 都是抽时间在慢慢写着。
后面差很少写了1W字的时候,存稿居然丢了, 弄了半天也没找回
就感受不想写了, 后面又翻了翻 找到了一篇本身以前保存的写了差很少两三千字的
而后就再慢慢的开始写了, 也就草草的结束了。
固然这里只是总结了一些常见的类型, 确定在实战中会遇到各类各样的状况 各类过滤啥的。
各类逻辑错误须要本身慢慢去体会了。