Natas Wargame Level25 Writeup(头部注入+POST/GET注入)
sourcecode核心代码:
1 <?php 2 // cheers and <3 to malvina 3 // - morla 4 5 function setLanguage(){ 6 /* language setup */ 7 if(array_key_exists("lang",$_REQUEST)) 8 if(safeinclude("language/" . $_REQUEST["lang"] )) 9 return 1; 10 safeinclude("language/en"); 11 } 12 13 function safeinclude($filename){ 14 // check for directory traversal 15 if(strstr($filename,"../")){ 16 logRequest("Directory traversal attempt! fixing request."); 17 $filename=str_replace("../","",$filename); 18 } 19 // dont let ppl steal our passwords 20 if(strstr($filename,"natas_webpass")){ 21 logRequest("Illegal file access detected! Aborting!"); 22 exit(-1); 23 } 24 // add more checks... 25 26 if (file_exists($filename)) { 27 include($filename); 28 return 1; 29 } 30 return 0; 31 } 32 33 function listFiles($path){ 34 $listoffiles=array(); 35 if ($handle = opendir($path)) 36 while (false !== ($file = readdir($handle))) 37 if ($file != "." && $file != "..") 38 $listoffiles[]=$file; 39 40 closedir($handle); 41 return $listoffiles; 42 } 43 44 function logRequest($message){ 45 $log="[". date("d.m.Y H::i:s",time()) ."]"; 46 $log=$log . " " . $_SERVER['HTTP_USER_AGENT']; 47 $log=$log . " \"" . $message ."\"\n"; 48 $fd=fopen("/var/www/natas/natas25/logs/natas25_" . session_id() .".log","a"); 49 fwrite($fd,$log); 50 fclose($fd); 51 } 52 ?> 53 54 <h1>natas25</h1> 55 <div id="content"> 56 <div align="right"> 57 <form> 58 <select name='lang' onchange='this.form.submit()'> 59 <option>language</option> 60 <?php foreach(listFiles("language/") as $f) echo "<option>$f</option>"; ?> 61 </select> 62 </form> 63 </div> 64 65 <?php 66 session_start(); 67 setLanguage(); 68 69 echo "<h2>$__GREETING</h2>"; 70 echo "<p align=\"justify\">$__MSG"; 71 echo "<div align=\"right\"><h6>$__FOOTER</h6><div>"; 72 ?>
首先要将注入点分析清楚:一共有三个注入点
1.$_REQUEST["lang"] 即get/post注入
2.$_SERVER['HTTP_USER_AGENT'] http头部信息注入
3.session_id() cookie注入
23条注入能够发生的条件是safeinclude函数检测到了非法输入,而且必须是“../”这种非法输入,若是“web_pass”这种的话会直接exit(-1)。
这里第一条过滤非法输入语句存在漏洞,例如..././将../去掉后就变成了../,根本原因就在于没有使用while语句,没有想到过滤一次后依然(助攻)存在../,所以过滤应该持续检测直到非法字符不再出现。
第一条直接注入比较困难,原因在于即使用..././绕过了第一条检测,第二条检测也很难直接将"web_pass"下的密码给include进来,所以应该思考利用23两个注入,23两个注入必须触发“../”检测,随后logRequest($message)将信息写入/var/www/natas/natas25/logs/natas25_session_id().log。
很容易得到新思路,将“密码”或者能够显示密码的php语句写入到session_id().log之中,随后在safeinclude中将其include进来,由于这里是$_SERVER['HTTP_USER_AGENT'] (通过字符串串联起来),所以没法执行命令做字符串替换,可以考虑写入php语句:
<?php echo file_get_contents("/etc/natas_webpass/natas26")?>
参考:http://php.net/manual/zh/function.file-get-contents.php
这样做以后,只要触发第一条过滤机制,密码就会在.log被include进来时显示,考虑如何即触发../又能够将.log包含进来:GET: lang=..././..././..././..././..././var/www/natas/natas25/logs/natas25_session_id().log即可
流程:GET输入触发第一次过滤,开始记录日志,headers中http-agent的php执行语句被记录到/var/www/natas/natas25/logs/natas25_session_id().log。同时输入被过滤为../../../../../var/www/natas/natas25/logs/natas25_session_id().log。file_exists()检测正确,将其include进来,触发php echo 语句,显示flag。
有两个地方需要注入,即get/post 和 headers。
注:如果想要注入session_id的话(虽然这没什么用。。),记得改cookie,Firefox里面发送http请求时会自动将headers中的cookie该回为真实的值。
总结:1.过滤机制一定要达到在任何情况下确定不包含非法字符(考虑周全)2.对用户的输入(不一定是真的“输入”,只要是用户传过来的信息)都要做防注入或过滤处理。3.做题的思路很重要,一是要注意过滤机制是否不够严格,而是碰壁后应该全局思考所有的注入点,只要是自己能篡改的信息都要思考能否注入,而且可能是多个注入点联合使用。
flag:oGgWAJ7zcGT28vYazGo4rkhOPDhBu34T