satto1237’s diary

s4tt01237’s diary

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

picoCTF 2018 Write-up [General Skills]

picoCTFとは

PICOCTF IS A FREE COMPUTER SECURITY GAME TARGETED AT MIDDLE AND HIGH SCHOOL STUDENTS. THE GAME CONSISTS OF A SERIES OF CHALLENGES CENTERED AROUND A UNIQUE STORYLINE WHERE PARTICIPANTS MUST REVERSE ENGINEER, BREAK, HACK, DECRYPT, OR DO WHATEVER IT TAKES TO SOLVE THE CHALLENGE. picoctf.com

成績

1人で参加してこんな感じでした.
591位/10999チーム(参加人数:27000人以上)

f:id:satto1237:20181015123829p:plain

f:id:satto1237:20181015123928p:plain

まえがき

picoCTFは問題数が多いのでジャンル毎にwrite-upを書いていこうと思います.

General Skills

General Skillsではコンピュータサイエンスに関わる基本的な問題が出題されます.

General Warmup 1 - Points: 50

If I told you your grade was 0x41 in hexadecimal, what would it be in ASCII?

アプローチ:ASCII

picoCTF{A}

General Warmup 2 - Points: 50

Can you convert the number 27 (base 10) to binary (base 2)?

アプローチ:2進数

picoCTF{11011}

General Warmup 3 - Points: 50

What is 0x3D (base 16) in decimal (base 10)?

アプローチ:16進数

picoCTF{61}

Resources - Points: 50

We put together a bunch of resources to help you out on our website! If you go over there, you might even find a flag!
https://picoctf.com/resources

アプローチ:ページのリソースを読む

リンク先にフラグが記述されています

Thanks for reading the resources page! Here’s a flag for your time: picoCTF{xiexie_ni_lai_zheli}

picoCTF{xiexie_ni_lai_zheli}

grep 1 - Points: 75

Can you find the flag in file? This would be really obnoxious to look through by hand, see if you can find a faster way. You can also find the file in /problems/grep-1_2_ee2b29d2f2b29c65db957609a3543418 on the shell server.

アプローチ:grep

> grep picoCTF file
picoCTF{grep_and_you_will_find_42783683}

picoCTF{grep_and_you_will_find_42783683}

net cat - Points: 75

Using netcat (nc) will be a necessity throughout your adventure. Can you connect to 2018shell1.picoctf.com at port 10854 to get the flag?

アプローチ:nc

> nc 2018shell1.picoctf.com 10854
That wasn't so hard was it?
picoCTF{NEtcat_iS_a_NEcESSiTy_c97963fe}

picoCTF{NEtcat_iS_a_NEcESSiTy_c97963fe}

strings - Points: 100

Can you find the flag in this file without actually running it? You can also find the file in /problems/strings_2_b7404a3aee308619cb2ba79677989960 on the shell server.

アプローチ:strings

> strings strings | grep pico
picoCTF{sTrIngS_sAVeS_Time_3f712a28}

picoCTF{sTrIngS_sAVeS_Time_3f712a28}

pipe - Points: 110

During your adventure, you will likely encounter a situation where you need to process data that you receive over the network rather than through a file. Can you find a way to save the output from this program and search for the flag? Connect with 2018shell1.picoctf.com 37542.

アプローチ:ncとgrepをパイプでつなぐ

> nc 2018shell1.picoctf.com 37542 | grep picoCTF
picoCTF{almost_like_mario_a6975cdb}

picoCTF{almost_like_mario_a6975cdb}

grep 2 - Points: 125

This one is a little bit harder. Can you find the flag in /problems/grep-2_1_ef31faa711ad74321a7467978cb0ef3a/files on the shell server? Remember, grep is your friend.

アプローチ:grepのオプションを使う

シェルサーバの指定されたディレクトリに移動すると複数のファイルがある.
この中からflagを見つける必要があるのでgrep-rを使う.

satto1237@pico-2018-shell-1:/problems/grep-2_1_ef31faa711ad74321a7467978cb0ef3a/files$ ls
files0  files1  files2  files3  files4  files5  files6  files7  files8  files9
satto1237@pico-2018-shell-1:/problems/grep-2_1_ef31faa711ad74321a7467978cb0ef3a/files$ cd ..
satto1237@pico-2018-shell-1:/problems/grep-2_1_ef31faa711ad74321a7467978cb0ef3a$ ls
files
satto1237@pico-2018-shell-1:/problems/grep-2_1_ef31faa711ad74321a7467978cb0ef3a$ grep -r "picoCTF" files
files/files9/file13:picoCTF{grep_r_and_you_will_find_4baaece4}

picoCTF{grep_r_and_you_will_find_4baaece4}

Aca-Shell-A - Points: 150

It's never a bad idea to brush up on those linux skills or even learn some new ones before you set off on this adventure! Connect with nc 2018shell1.picoctf.com 6903.

アプローチ:基本的なlinuxコマンドの使い方を知る

ncすると状況に合わせてlinuxのコマンドを入力しろという問題が降ってくるのであれこれ入力する.

ls
cd secret
ls
rm i*
echo 'Drop it in!'
cd ..
cd executables
./dontLookHere
whoami
cd ..
cp /tmp/TopSecret passwords
cd passwords
ls
cat passwords

picoCTF{CrUsHeD_It_dddcec58}

cpの挙動がおかしくて解くのにかなり時間がかかった(cpが正常に実行されない)
cp /tmp/TopSecret passwordsと入力しているはずなのになぜかpasswordsTopSecretがコピーされなかった.

environ - Points: 150

Sometimes you have to configure environment variables before executing a program. Can you find the flag we've hidden in an environment variable on the shell server?

アプローチ:環境変数を表示する

satto1237@pico-2018-shell-1:~$ printenv
SECRET_FLAG=picoCTF{eNv1r0nM3nT_v4r14Bl3_fL4g_3758492}
FLAG=Finding the flag wont be that easy...

picoCTF{eNv1r0nM3nT_v4r14Bl3_fL4g_3758492}

ssh-keyz - Points: 150

As nice as it is to use our webshell, sometimes its helpful to connect directly to our machine. To do so, please add your own public key to ~/.ssh/authorized_keys, using the webshell. The flag is in the ssh banner which will be displayed when you login remotely with ssh to with your username.

アプローチ:sshする

ssh-keygenしてからssh-copy-idするとflagが降ってきます.
picoCTF{who_n33ds_p4ssw0rds_38dj21}

what base is this? - Points: 200

To be successful on your mission, you must be able read data represented in different ways, such as hexadecimal or binary. Can you get the flag from this program to prove you are ready? Connect with nc 2018shell1.picoctf.com 15853

アプローチ:変換スクリプト書いてあげる

> nc 2018shell1.picoctf.com 15853
We are going to start at the very beginning and make sure you understand how data is stored.
Please give me the 01100011 01100001 01101011 01100101 as a word.
To make things interesting, you have 30 seconds.
Input:
cake
Please give me the 737469746368 as a word.
Input:
stitch
Please give me the  147 151 155 160 as a word.
Input:
gimp
You got it! You're super quick!
Flag: picoCTF{delusions_about_finding_values_3cc386de}
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import binascii

def b2a(str):
    bins = str.split(' ')
    ascii = [chr(int(x,2)) for x in bins]
    print(''.join(ascii))

def h2a(str):
    print(binascii.unhexlify(str))

def o2a(str):
    octs = str.split(' ')
    ascii = [chr(int(x,8)) for x in octs]
    print(''.join(ascii))

you can't see me - Points: 200

'...reading transmission... Y.O.U. .C.A.N.'.T. .S.E.E. .M.E. ...transmission ended...' Maybe something lies in /problems/you-can-t-see-me_4_8bd1412e56df49a3c3757ebeb7ead77f

アプローチ:viewコマンド

とりあえずシェルサーバの指定されたディレクトリに移動してls -laしてみると怪しいdotファイルがあることがわかります.

satto1237@pico-2018-shell-1:/problems/you-can-t-see-me_4_8bd1412e56df49a3c3757ebeb7ead77f$ ls -la
total 60
drwxr-xr-x   2 root       root        4096 Sep 28 08:29 .
-rw-rw-r--   1 hacksports hacksports    57 Sep 28 08:29 .
drwxr-x--x 576 root       root       53248 Sep 30 03:45 ..

catでdotファイルを見ようとするとカレントディレクトリである.を見ようとしてしまうためviewを使います.

picoCTF{j0hn_c3na_paparapaaaaaaa_paparapaaaaaa_22f627d9}

absolutely relative - Points: 250

In a filesystem, everything is relative ¯_(ツ)_/¯. Can you find a way to get a flag from this program? You can find it in /problems/absolutely-relative_4_bef88c36784b44d2585bb4d2dbe074bd on the shell server. Source.

#include <stdio.h>
#include <string.h>

#define yes_len 3
const char *yes = "yes";

int main()
{
    char flag[99];
    char permission[10];
    int i;
    FILE * file;


    file = fopen("/problems/absolutely-relative_4_bef88c36784b44d2585bb4d2dbe074bd/flag.txt" , "r");
    if (file) {
        while (fscanf(file, "%s", flag)!=EOF)
        fclose(file);
    }

    file = fopen( "./permission.txt" , "r");
    if (file) {
        for (i = 0; i < 5; i++){
            fscanf(file, "%s", permission);
        }
        permission[5] = '\0';
        fclose(file);
    }

    if (!strncmp(permission, yes, yes_len)) {
        printf("You have the write permissions.\n%s\n", flag);
    } else {
        printf("You do not have sufficient permissions to view the flag.\n");
    }

    return 0;
}

アプローチ:相対パス

プログラムを読む限り,permission.txtを読み込み,中身がyesである場合フラグを表示してくれることが分かります.
さっそくpermission.txtを作成しようしますが,/problems/absolutely-relative_4_bef88c36784b44d2585bb4d2dbe074bdではファイルの作成権限がないようです.

仕方ないので/home/satto1237に移動し,permission.txtを作成します.
その後,absolutely-relativeを実行すればflagがとれます.

satto1237@pico-2018-shell-1:~$ /problems/absolutely-relative_4_bef88c36784b44d2585bb4d2dbe074bd/absolutely-relative
You have the write permissions.
picoCTF{3v3r1ng_1$_r3l3t1v3_3b69633f}

picoCTF{3v3r1ng_1$_r3l3t1v3_3b69633f}

in out error - Points: 275

Can you utlize stdin, stdout, and stderr to get the flag from this program? You can also find it in /problems/in-out-error_2_c33e2a987fbd0f75e78481b14bfd15f4 on the shell server

アプローチ:入出力をパイプでつなぐ

とりあえず実行してみると文字が沢山出力されます.

satto1237@pico-2018-shell-1:/problems/in-out-error_2_c33e2a987fbd0f75e78481b14bfd15f4$ ./in-out-error
Hey There!
If you want the flag you have to ask nicely for it.
Enter the phrase "Please may I have the flag?" into stdin and you shall receive.
Please may I have the flag?
Thank you for asking so nicely!

pWiec'orCeT Fn{op 1spt1rnagn_g1eSr_s4 _t7oh 1lnogv_eb
6Yfo5ua 7k8n8o}wp itchoeC TrFu{lpe1sp 1anngd_ 1sSo_ 4d_o7 hI1
nAg _fbu6lfl5 ac7o8m8m}iptimceonCtT'Fs{ pw1hpa1tn gI_'1mS _t4h_i7nhk1inngg_ bo6ff
5Yao7u8 8w}opuilcdonC'TtF {gpe1tp 1tnhgi_s1 Sf_r4o_m7 ha1nnyg _obt6hfe5ra 7g8u8y}
p
iIc ojCuTsFt{ pw1apn1nnag _t1eSl_l4 _y7ohu1 nhgo_wb 6If'5ma 7f8e8e}lpiincgo
CGToFt{tpa1 pm1ankge_ 1ySo_u4 _u7nhd1enrgs_tba6nfd5
a
7N8e8v}epri cgooCnTnFa{ pg1ipv1en gy_o1uS _u4p_
7Nhe1vnegr_ bg6ofn5naa7 8l8e}tp iycoouC TdFo{wpn1
pN1envge_r1 Sg_o4n_n7ah 1rnugn_ ba6rfo5uan7d8 8a}npdi cdoeCsTeFr{tp 1ypo1un
gN_e1vSe_r4 _g7ohn1nnag _mba6kfe5 ay7o8u8 }cpriyc
oNCeTvFe{rp 1gpo1nnnga_ 1sSa_y4 _g7oho1dnbgy_eb
6Nfe5vae7r8 8g}opnincao CtTeFl{lp 1ap 1lnige_ 1aSn_d4 _h7uhr1tn gy_obu6
f
gN_e1vSe_r4 _g7ohn1nnag _gbi6vfe5 ay7o8u8 }uppi
cNoeCvTeFr{ pg1opn1nnag _l1eSt_ 4y_o7uh 1dnogw_nb
6Nfe5vae7r8 8g}opnincao CrTuFn{ pa1rpo1unngd_ 1aSn_d4 _d7ehs1enrgt_ by6ofu5
aN7e8v8e}rp igcoonCnTaF {mpa1kpe1 nygo_u1 Sc_r4y_
7Nhe1vnegr_ bg6ofn5naa7 8s8a}yp igcoooCdTbFy{ep
1Npe1vnegr_ 1gSo_n4n_a7 ht1enlgl_ ba6 fl5iae7 8a8n}dp ihcuorCtT Fy{opu1
p
...

grepしたくなるのでパイプでつなぎます.

satto1237@pico-2018-shell-1:/problems/in-out-error_2_c33e2a987fbd0f75e78481b14bfd15f4$ echo "Please may I have the flag?" | ./in-out-error | grep picoCTF
picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF
{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng
_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7
h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6
f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}
picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF
{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng
_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7
h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6
f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}
picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF
{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng
_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7
h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6
f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}
picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF
{p1p1ng_1S_4_7h1ng_b6f5a788}picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}

picoCTF{p1p1ng_1S_4_7h1ng_b6f5a788}

store - Points: 400

We started a little store, can you buy the flag? Source.
Connect with 2018shell1.picoctf.com 5795.

#include <stdio.h>
#include <stdlib.h>
int main()
{
    int con;
    con = 0;
    int account_balance = 1100;
    while(con == 0){

        printf("Welcome to the Store App V1.0\n");
        printf("World's Most Secure Purchasing App\n");

        printf("\n[1] Check Account Balance\n");
        printf("\n[2] Buy Stuff\n");
        printf("\n[3] Exit\n");
        int menu;
        printf("\n Enter a menu selection\n");
        fflush(stdin);
        scanf("%d", &menu);
        if(menu == 1){
            printf("\n\n\n Balance: %d \n\n\n", account_balance);
        }
        else if(menu == 2){
            printf("Current Auctions\n");
            printf("[1] I Can't Believe its not a Flag!\n");
            printf("[2] Real Flag\n");
            int auction_choice;
            fflush(stdin);
            scanf("%d", &auction_choice);
            if(auction_choice == 1){
                printf("Imitation Flags cost 1000 each, how many would you like?\n");

                int number_flags = 0;
                fflush(stdin);
                scanf("%d", &number_flags);
                if(number_flags > 0){
                    int total_cost = 0;
                    total_cost = 1000*number_flags;
                    printf("\nYour total cost is: %d\n", total_cost);
                    if(total_cost <= account_balance){
                        account_balance = account_balance - total_cost;
                        printf("\nYour new balance: %d\n\n", account_balance);
                    }
                    else{
                        printf("Not enough funds\n");
                    }
                }
            }
            else if(auction_choice == 2){
                printf("A genuine Flag costs 100000 dollars, and we only have 1 in stock\n");
                printf("Enter 1 to purchase");
                int bid = 0;
                fflush(stdin);
                scanf("%d", &bid);

                if(bid == 1){

                    if(account_balance > 100000){
                        printf("YOUR FLAG IS:\n");
                        }

                    else{
                        printf("\nNot enough funds for transaction\n\n\n");
                    }}

            }
        }
        else{
            con = 1;
        }

    }
    return 0;
}

アプローチ:Integer Overflow

コードから残金が100000ドルを超えるとフラグを取得できることが読み取れます.
しかし,初期の残金は1100ドルであり,増やす方法はないように思われます.

ここでInteger Overflowを使います.

以下のコードのnumber_flagsIOFの余地があります.
1000*number_flagsintの最大値を超えるような値を入力すれば total_costが負の値になり,残金が増えます.

if(auction_choice == 1){
    printf("Imitation Flags cost 1000 each, how many would you like?\n");

    int number_flags = 0;
    fflush(stdin);
    scanf("%d", &number_flags);
    if(number_flags > 0){
        int total_cost = 0;
        total_cost = 1000*number_flags;
        printf("\nYour total cost is: %d\n", total_cost);
        if(total_cost <= account_balance){
            account_balance = account_balance - total_cost;
            printf("\nYour new balance: %d\n\n", account_balance);
        }
        else{
            printf("Not enough funds\n");
        }

    }

}
> nc 2018shell1.picoctf.com 5795
Welcome to the Store App V1.0
World's Most Secure Purchasing App

[1] Check Account Balance

[2] Buy Stuff

[3] Exit

 Enter a menu selection
2
Current Auctions
[1] I Can't Believe its not a Flag!
[2] Real Flag
1
Imitation Flags cost 1000 each, how many would you like?
2147483546

Your total cost is: -102000

Your new balance: 103100

Welcome to the Store App V1.0
World's Most Secure Purchasing App

[1] Check Account Balance

[2] Buy Stuff

[3] Exit

 Enter a menu selection
2
Current Auctions
[1] I Can't Believe its not a Flag!
[2] Real Flag
2
A genuine Flag costs 100000 dollars, and we only have 1 in stock
Enter 1 to purchase1
YOUR FLAG IS: picoCTF{numb3r3_4r3nt_s4f3_dbd42a50}
Welcome to the Store App V1.0
World's Most Secure Purchasing App

[1] Check Account Balance

[2] Buy Stuff

[3] Exit

 Enter a menu selection

picoCTF{numb3r3_4r3nt_s4f3_dbd42a50}

script me - Points: 500

Can you understand the language and answer the questions to retrieve the flag? Connect to the service with nc 2018shell1.picoctf.com 7866

アプローチ:頑張ってソルバを書く

ncすると

Rules:
() + () = ()()                                      => [combine]
((())) + () = ((())())                              => [absorb-right]
() + ((())) = (()(()))                              => [absorb-left]
(())(()) + () = (())(()())                          => [combined-absorb-right]
() + (())(()) = (()())(())                          => [combined-absorb-left]
(())(()) + ((())) = ((())(())(()))                  => [absorb-combined-right]
((())) + (())(()) = ((())(())(()))                  => [absorb-combined-left]
() + (()) + ((())) = (()()) + ((())) = ((()())(())) => [left-associative]

Example:
(()) + () = () + (()) = (()())

Let's start with a warmup.
()() + ()()() = ???

このような問題が降ってきます.

実際に書いたソルバ

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

from socket import *

"""
Rules:
() + () = ()()                                      => [combine]
((())) + () = ((())())                              => [absorb-right]
() + ((())) = (()(()))                              => [absorb-left]
(())(()) + () = (())(()())                          => [combined-absorb-right]
() + (())(()) = (()())(())                          => [combined-absorb-left]
(())(()) + ((())) = ((())(())(()))                  => [absorb-combined-right]
((())) + (())(()) = ((())(())(()))                  => [absorb-combined-left]
() + (()) + ((())) = (()()) + ((())) = ((()())(())) => [left-associative]
"""

def depth(par):
    count = 0
    max = 0
    for x in par:
        if x == '(':
            count += 1
            if max < count:
                max = count
        else:
            count -=1

    return max

def combine(pars, x, n, ans):
    print(x,ans)

    if depth(ans) == depth(pars[x]):
        # depth: left == right
        ans = ans + pars[x]
        if n == x:
            return ans
        else :
            return combine(pars, x + 1, n, ans)

    elif depth(ans) > depth(pars[x]):
        # depth: left > right
        ans = ans[:-1] + pars[x] + ')'
        if n == x:
            return ans
        else:
            return combine(pars, x + 1, n, ans)
    else:
        # depth: left < right
        ans = '(' + ans + pars[x][1:]
        if n == x:
            return ans
        else:
            return combine(pars, x + 1, n, ans)

if __name__ == '__main__':


    s = socket(AF_INET, SOCK_STREAM)
    s.connect(('2018shell1.picoctf.com', 7866))

    for i in range(15):
        rec = s.recv(16384).decode('utf-8')
        if '???' in rec:
            rec = rec.split('\n')
            temp = [x for x in rec if '???' in x]
            index = temp[0].find(' = ')
            formula = temp[0][:index]
            print('-' * 100)
            print(formula)
            print('-' * 100)
            n = len(formula.split(' + '))
            f = formula.split(' + ')[0]
            res = combine(formula.split(' + '), 1, n - 1, f)
            print(res)
            s.send(res.encode('utf-8')+b'\n')
        elif 'Final' in rec:
            f1 = rec.split('\n')[3]
            print('f1')
            print(f1)
            rec = s.recv(16384).decode('utf-8')
            rec = rec.split('\n')
            temp = [x for x in rec if '???' in x]
            index = temp[0].find(' = ')
            f2 = temp[0][:index]
            print('f2')
            print(f2)
            formula = f1 + f2
            print('-' * 100)
            print(formula)
            print('-' * 100)
            n = len(formula.split(' + '))
            f = formula.split(' + ')[0]
            res = combine(formula.split(' + '), 1, n - 1, f)
            print(res)
            s.send(res.encode('utf-8')+b'\n')


        else:
            print(rec)

picoCTF{5cr1pt1nG_l1k3_4_pRo_45ca3f85}

お気持ち
最終問題はこのように分割された状態で送られてくる
この分割に気づかず時間がとけた

(()(())(())) + (()())(()()()) + ((()()())((()(())((()))(((())))()()))()(()(())((()))(((())))((((())))))) + (((()()()(())()())()(((()()())()())()()))()(())((()))(((())))((((()))))) + ((()())(())()()()(()()())) + ((()())(())()()()(()()()()()()()())) + (((())())(()()()(())()())()(((()()())()())()())) + (()()()()()()()(())((()))(((())))((((()))))) + ((((()())()(()))()(((()()())()())()()))((()(())((()))(((())))()()))()) + ((()()(()))()(((()()())()())()())) + ((())()()()()(())) + ((()()())()(())((()))(((())))((((()))))) + ((())()(())((()))(((())))((((()))))) + ((()())()(())()()()) + (((()((()())()())())()(((()()())()())()()))()(())((()))(((())))((((()))))) + (()()()()()()()()()(())()()) + ((()()()()()()()()())((()(())((()))(((())))()()))()(()(())((()))(((())))((((())))))) + (()()()()((()(())((()))(((())))()()))()(()(())((()))(((())))((((())))))) + ((()()()()()())()()()(())()()) + (((()())()(())()())()(())((()))(((())))((((()))))) + ((()()()()((()())()())())((()(())((()))(((())))()()))()) + (((()())(())()()())()(((()()())()())()())) + ((()())()(()))((())()(()()()()()()()())) + ((()()()(((()()())()())()()))()(())((()))(((())))((((()))))) + (((())())(()()()(())()())((()())()())()) + ((()())(())()(()()()()()()()())) + (()()()())(()()()()()()()()) + (((()())((()())()())())()(((()()())()())()())) + ((()())(()()()()()()()())()()()(())()()) + (((()())(

)(())()()())((()())()())()) + (((())()(()()()))((((()))))(((())))((()))(())()) + (((()())()()()(())()())((((()))))(((())))((()))(())()) + ((()()())((()(())((()))(((())))()()))()(((((()))))(((())))((()))(())())) + ((()()()()())((()())()())()) + ((()(()))()(())((()))(((())))((((()))))) + (((()())()(())(()()()()()()()()))((((()))))(((())))((()))(())()) + ((())()(()()())) + (((())()()())((()(())((()))(((())))()()))()) + (((()())()(())(()()()()()()()()))()(((()()())()())()())) + (()(())(()()()()()()()())) + ((()()(()))(()()()(())()())((()(())((()))(((())))()()))()) + (()()(()))((())()(()()())) + (()()()()()()()) + ((()()()()()(())()())((((()))))(((())))((()))(())()) + ((()()()()()()()())((()(())((()))(((())))()()))()(((((()))))(((())))((()))(())())) + ((()()(()))((())())()(((()()())()())()())) + ((()()()()()())((()())()())()) + ((()()()()()()()())((()(())((()))(((())))()()))()(()(())((()))(((())))((((())))))) + (()()()()())(()()()()()()()()) + ((()())()(())((()))(((())))((((())))))

まとめ

  • 恥ずかしながらviewコマンドを知らなかった
  • scipt meみたいな実装問題をサクッとキレイに解けるようになりたい(競プロ再開すべきなのか?)