この大会は2019/8/13 1:00(JST)~2019/8/17 1:00(JST)に開催されました。
今回もチームで参戦。結果は3001点で926チーム中59位でした。
自分で解けた問題をWriteupとして書いておきます。
Tux Trivia Show (Misc)
$ nc chall.2019.redpwn.net 6001 Welcome to Tux Trivia Show!!! What is the capital of Fiji? Suva Correct! Next question coming... What is the capital of Washington? Time out!
国の首都やアメリカの各州の州都を答えていく問題。https://github.com/icyrockcom/country-capitals/blob/master/data/country-list.csvで首都のリストを入手。アメリカの州都のリストも別途入手する。
ただ、微妙にスペルが違っていたり、2バイト文字を使っていたりするので、調整する。
import socket import re capital_dic={ 'Alabama': 'Montgomery', 'Alaska': 'Juneau', 'Arizona':'Phoenix', 'Arkansas':'Little Rock', 'California': 'Sacramento', 'Colorado':'Denver', 'Connecticut':'Hartford', 'Delaware':'Dover', 'Florida': 'Tallahassee', 'Georgia': 'Atlanta', 'Hawaii': 'Honolulu', 'Idaho': 'Boise', 'Illinois': 'Springfield', 'Indiana': 'Indianapolis', 'Iowa': 'Des Moines', 'Kansas': 'Topeka', 'Kentucky': 'Frankfort', 'Louisiana': 'Baton Rouge', 'Maine': 'Augusta', 'Maryland': 'Annapolis', 'Massachusetts': 'Boston', 'Michigan': 'Lansing', 'Minnesota': 'St. Paul', 'Mississippi': 'Jackson', 'Missouri': 'Jefferson City', 'Montana': 'Helena', 'Nebraska': 'Lincoln', 'Nevada': 'Carson City', 'New Hampshire': 'Concord', 'New Jersey': 'Trenton', 'New Mexico': 'Santa Fe', 'New York': 'Albany', 'North Carolina': 'Raleigh', 'North Dakota': 'Bismarck', 'Ohio': 'Columbus', 'Oklahoma': 'Oklahoma City', 'Oregon': 'Salem', 'Pennsylvania': 'Harrisburg', 'Rhode Island': 'Providence', 'South Carolina': 'Columbia', 'South Dakota': 'Pierre', 'Tennessee': 'Nashville', 'Texas': 'Austin', 'Utah': 'Salt Lake City', 'Vermont': 'Montpelier', 'Virginia': 'Richmond', 'Washington': 'Olympia', 'West Virginia': 'Charleston', 'Wisconsin': 'Madison', 'Wyoming': 'Cheyenne' } def recvuntil(s, tail): data = '' while True: if tail in data: return data data += s.recv(1) def get_capital_from_country(s): for countryinfo in countries_list: country = countryinfo.split(',')[0][1:-1] capital = countryinfo.split(',')[1][1:-1] if country == s: return capital return '' def get_capital_from_state(s): if s in capital_dic: return capital_dic[s] else: return 'Not Found!' with open('country-list.csv', 'r') as f: countries_list = f.readlines() s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('chall.2019.redpwn.net', 6001)) data = recvuntil(s, '\n').rstrip() print data for i in range(1000): print 'Round %d' % (i+1) data = recvuntil(s, '\n').rstrip() print data pattern = 'capital of (.+)\?' m = re.search(pattern, data) country = m.group(1) capital = get_capital_from_country(country) if capital == '': capital = get_capital_from_state(country) if capital == '': break print capital s.sendall(capital + '\n') data = recvuntil(s, '\n').rstrip() print data data = recvuntil(s, '\n').rstrip() print data data = s.recv(8192) print data
実行結果は以下の通り。
: Round 1000 What is the capital of Hungary? Budapest Correct! Next question coming... Here is your flag: flag{TUX_tr1v1A_sh0w+m3st3r3d_:D}
flag{TUX_tr1v1A_sh0w+m3st3r3d_:D}
BabbyPwn (Pwn)
ncで接続するだけ。
$ nc chall.2019.redpwn.net 4001 So you want the flag, I see You should stop Stealing is wrong You wouldn't steal a car Well... Okay But know this You are irredeemably a bad person flag{st341ing_is_wr0ng}
flag{st341ing_is_wr0ng}
Generic Crackme (Reverse Engineering)
$ ./generic_crackme plz enter password plz: aaa lolno
正しいパスワードがフラグになるはず。IDAで開き、処理を追う。
main関数は以下のようになっていて、sub_1168の結果により分岐する。
sub_1168関数は以下のようになっていて、先頭からsub_1159関数の結果、以下のようになっていればよい。
e, p, h, h, z
sub_1159関数は以下のようになっていて、1を足しているだけ。
以上のことから、パスワードはdoggy
flag{doggy}
Generic Crackme Redux (Reverse Engineering)
$ ./generic_crackme_redux
Enter access code: 123
Bzzzzrrrppp
正しいアクセスコードがフラグになるはず。IDAで開き、処理を追う。
main関数は以下のようになっていて、sub_1169の結果により分岐する。
sub_1169関数は以下のようになっていて、処理をした後の結果比較をしている。
1. a = アクセスコード << 2 ; a = アクセスコードの4倍 2. a += アクセスコード ; a = アクセスコードの5倍 3. a += a; a = アクセスコードの10倍 4. aと0xac292(=705170)を比較し、同じならOK
アクセスコードを求めるためには10で割ればよい。
705170 / 10 = 70517
flag{70517}
Dunce Crypto (Crypto)
シーザー暗号そ推測し、https://www.geocachingtoolbox.com/index.php?lang=en&page=caesarCipherで復号する。
Rotation 7: flag{I_d0nt_w4nt_t0_p4y_my_tax3s}
flag{I_d0nt_w4nt_t0_p4y_my_tax3s}
Super Hash (Crypto)
10回md5を取ると、CD04302CBBD2E0EB259F53FAC7C57EE2になるものがフラグ。md5は英大文字にすることに気を付け、ブルートフォースする。
import itertools import string import hashlib def ten_hash(s): res = s for i in range(10): res = hashlib.md5(res).hexdigest().upper() return res h = 'CD04302CBBD2E0EB259F53FAC7C57EE2' found = False for size in range(1, 5): for c in itertools.product(string.printable, repeat=size): text = ''.join(c) if ten_hash(text) == h: found = True flag = 'flag{%s}' % text print flag break if found: break
flag{^}
Trinity (Crypto)
lowercaseで答えるということから、アルファベットの大文字と小文字の区別がないエンコード方式と推測できる。0を., 1を-, 2をスペースにしてモールス信号として変換する。
- . .-. -. .- .-. -.-- .. ... -- --- .-. . .- .-. -.-. .- -. . -... ..- - .. -... . - -.-- --- ..- - .... --- ..- --. .... - --- ..-. .. - ..-. .. .-. ... -
https://morsecode.scphillips.com/translator.htmlで変換する。
TERNARYISMOREARCANEBUTIBETYOUTHOUGHTOFITFIRST
フラグは小文字で答える必要があるので、小文字にする。
ternaryismorearcanebutibetyouthoughtofitfirst
010000100110100101101110011000010111001001111001 (Crypto)
$ nc chall2.2019.redpwn.net 5001 011101010110110001110100011010010110110101100001011101000110010100100000011001010110111001100011011100100111100101110000011101000110100101101111011011100010000001110011011001010111001001110110011010010110001101100101 0101011101000001010100100100111001001001010011100100011100111010001000000100100100100000011011110110111001101100011110010010000001110011011000010111100100100000001100000010000001101111011100100010000000110001 0010100001001110001011000110010100101001: (110001100101111011100111001001001101011011100101000110010000001010101011010011110010111110011001010001000001001000011111101100000111000001000110101111111011100010001011110111000110101100000101001000000101111000111010100110000101111100111010010001100000100010010110011110001101001111110010110000100000111101100111100100001100101111000100111101001001010101001001100100110011001110011010000001100110100010001010101011011111001110000100100000011011110100101010110110101110000110111001010100000000010000001100011110100001101011110100100101001111010110111101100011011001111011010101100100010101011111010011011000101110010111000110001001111010010010100110111000100101000000010011000101110001011100100101100110101000111111011111000100101100100001101000101110000101001001111111111100110100010011110000011110100011111101100110000000000000111100100010101100010000101111100111101111101110111100111010000101100001101011101000111011000010100110000101011010011001000001110000011011100101100111001100000010101000101110101101001000010000101, 10000000000000001) 0100010101001110010000110101001001011001010100000101010001000101010001000010000001001101010001010101001101010011010000010100011101000101: 10010000010001011010010101101100000000110101011010010110011111001001111101111100100110110011011110010000111000001100110011110011011100101000001011001100101001111100011011010110101110100100111010000101001000111110101010110100101000111101000001101111010001100110000101010100000010001011011010000110010001111011000111010001100110110100000101100000101000001101010110010011011110001110111111001010011011010011100110100110100111100001011001011010100111111101100011110001000000010100001100100100100010101100110000000111011111100101100100000011110101110110000010101000001111100001110011010011100010110010010010110110000111100000000001011011110010110111000010110001101001011001001000110111110011101111000010011000010110100011000000010101100011010011110101010110110111100001101110011101111100101001000011101111000001110000001100000011001101010110011111010110011010111000101100010001101111011101111101110101100110010100010111100000000010001010110111101000000000110100101100001111000101000001000001100101011111100010101011111001100100 > 1 1 > 0 0
0, 1を一部ASCII文字にしてみる。
ultimate encryption service WARNING: I only say 0 or 1 (N,e): (110001100101111011100111001001001101011011100101000110010000001010101011010011110010111110011001010001000001001000011111101100000111000001000110101111111011100010001011110111000110101100000101001000000101111000111010100110000101111100111010010001100000100010010110011110001101001111110010110000100000111101100111100100001100101111000100111101001001010101001001100100110011001110011010000001100110100010001010101011011111001110000100100000011011110100101010110110101110000110111001010100000000010000001100011110100001101011110100100101001111010110111101100011011001111011010101100100010101011111010011011000101110010111000110001001111010010010100110111000100101000000010011000101110001011100100101100110101000111111011111000100101100100001101000101110000101001001111111111100110100010011110000011110100011111101100110000000000000111100100010101100010000101111100111101111101110111100111010000101100001101011101000111011000010100110000101011010011001000001110000011011100101100111001100000010101000101110101101001000010000101, 10000000000000001) ENCRYPTED MESSAGE: 10010000010001011010010101101100000000110101011010010110011111001001111101111100100110110011011110010000111000001100110011110011011100101000001011001100101001111100011011010110101110100100111010000101001000111110101010110100101000111101000001101111010001100110000101010100000010001011011010000110010001111011000111010001100110110100000101100000101000001101010110010011011110001110111111001010011011010011100110100110100111100001011001011010100111111101100011110001000000010100001100100100100010101100110000000111011111100101100100000011110101110110000010101000001111100001110011010011100010110010010010110110000111100000000001011011110010110111000010110001101001011001001000110111110011101111000010011000010110100011000000010101100011010011110101010110110111100001101110011101111100101001000011101111000001110000001100000011001101010110011111010110011010111000101100010001101111011101111101110101100110010100010111100000000010001010110111101000000000110100101100001111000101000001000001100101011111100010101011111001100100
RSA暗号で、この後0, 1で数値を指定すると、復号した結果の末尾を0, 1で返してくれると推測できる。LSB decryption oracle attackで復号する。
import socket from fractions import Fraction from Crypto.Util.number import long_to_bytes def recvuntil(s, tail): data = '' while True: if tail in data: return data data += s.recv(1) def bin_2_ascii(b): a = '' for i in range(0, len(b), 8): a += chr(int(b[i:i+8], 2)) return a def lsb_oracle(s, enc): data = recvuntil(s, '> ') print data + enc s.sendall(enc + '\n') data = recvuntil(s, '\n').strip() print data return int(data) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('chall2.2019.redpwn.net', 5001)) pt = '' data = recvuntil(s, '\n').rstrip() print data pt += bin_2_ascii(data) + '\n' data = recvuntil(s, '\n').rstrip() print data pt += data + '\n' data = recvuntil(s, '\n').rstrip() print data pt += bin_2_ascii(data) + '\n' data = recvuntil(s, '\n').rstrip() print data pt += data + '\n' data = recvuntil(s, '\n').rstrip() print data pt += bin_2_ascii(data.split(':')[0]) + ':' + data.split(':')[1] + '\n' data = recvuntil(s, '\n').rstrip() print data pt += data + '\n' data = recvuntil(s, '\n').rstrip() print data pt += bin_2_ascii(data.split(':')[0]) + ':' + data.split(':')[1] + '\n' print pt N = int(pt.split('\n')[-4].split(': (')[1].split(', ')[0], 2) e = int(pt.split('\n')[-4].split(': (')[1].split(', ')[1][:-1], 2) c = int(pt.split('\n')[-2].split(': ')[1], 2) print 'N =', N print 'e =', e print 'c =', c data = recvuntil(s, '\n').rstrip() print data pt += data + '\n' bounds = [0, Fraction(N)] i = 0 while True: print 'Round %d' % (i+1) i += 1 c2 = (c * pow(2, e, N)) % N lsb = lsb_oracle(s, bin(c2)[2:]) if lsb == 1: bounds[0] = sum(bounds)/2 else: bounds[1] = sum(bounds)/2 diff = bounds[1] - bounds[0] diff = diff.numerator / diff.denominator if diff == 0: m = bounds[1].numerator / bounds[1].denominator break c = c2 flag = long_to_bytes(m) print flag
実行結果は以下の通り。
: Round 1024 > 101100011100000111000110110010110111000101100011100100111111100000011010111100011011011011011110000100101011110111010100000101000100011010101111111011100000100101001111010000011010000011101011001010110010010010111001100110011100111000001101101100010101000111101011000011011010101001111110001101100011001111100110011101000100110000000100101100111101100000111100110110100010011000011011010110011110010010011011110100101110101000111110000000000111000101110111010010101011001100000011000001110001110000110111101010001101000000000111111001101001001101011101000111010101101001110111100111111110101111111101110000011001101110100111000100001100100000011110010011010001111110011011111111111110101101010111100111001101100110000001101110011111010100101110110000101101100101010001111110111111100010010000010010110101001101010110111001110100000010101111010001000000010001001011001100000010000000111011010111010111100111111111101101110100011001111111111111101100101000110011100001110100111100000010101110100001001011111111111011101000 1 flag{y0u_s0lved_th3_l3ast_s1gn1f1c1nt_RSA!-1123}
flag{y0u_s0lved_th3_l3ast_s1gn1f1c1nt_RSA!-1123}
Survey (Misc)
アンケートに答えたら、フラグが表示された。
flag{thks_for_playing}