センスがないブログ

趣味の話とかいろいろ

DARTSLIVE HomeのデータをPythonで受け取る

先日電子ダーツボードのダーツライブホームを購入して、なんとなくPCからもデータ受信できたら嬉しいかなと思ってやってみました。

前バージョンの200sまでは、Bluetoothキーボードとして認識されていたようですが、HOMEではBLEが使われているようです。

なので、スマホアプリのBLE Scannerを使ってcharacteristicを確認してみます。

f:id:NonSense:20211201013505j:plain

サービスとしてはUARTだけっぽいです。

6e40fff6-b5a3-f393-e0a9-e50e24dcca9eをlistenしておくと何かが押されたときに、5byteのデータが降ってきます。

形式は "a1 03 XX 00 00"でXXにセグメント固有の番号が入ります。また、チェンジボタンも同形式のデータできます。

これをもとにPythonコードを起こしてみました。

import asyncio
from bleak import BleakClient

address = "F9:C7:40:CA:47:1E"
uuid = "6e40fff6-b5a3-f393-e0a9-e50e24dcca9e"

dat = {
    0x3c:"D20",
    0x28:"S20_O",
    0x50:"T20",
    0x14:"S20_I",
    0x29:"D1",
    0x15:"S1_O",
    0x3d:"T1",
    0x01:"S1_I",
    0x3a:"D18",
    0x26:"S18_O",
    0x4e:"T18",
    0x12:"S18_I",
    0x2c:"D4",
    0x18:"S4_O",
    0x40:"T4",
    0x04:"S4_I",
    0x35:"D13",
    0x21:"S13_O",
    0x49:"T13",
    0x0d:"S13_I",
    0x2e:"D6",
    0x1a:"S6_O",
    0x42:"T6",
    0x06:"S6_I",
    0x32:"D10",
    0x1e:"S10_O",
    0x46:"T10",
    0x0a:"S10_I",
    0x37:"D15",
    0x23:"S15_O",
    0x4b:"T15",
    0x0f:"S15_I",
    0x2a:"D2",
    0x16:"S2_O",
    0x3e:"T2",
    0x02:"S2_I",
    0x39:"D17",
    0x25:"S17_O",
    0x4d:"T17",
    0x11:"S17_I",
    0x2b:"D3",
    0x17:"S3_O",
    0x3f:"T3",
    0x03:"S3_I",
    0x3b:"D19",
    0x27:"S19_O",
    0x4f:"T19",
    0x13:"S19_I",
    0x2f:"D7",
    0x1b:"S7_O",
    0x43:"T7",
    0x07:"S7_I",
    0x38:"D16",
    0x24:"S16_O",
    0x4c:"T16",
    0x10:"S16_I",
    0x30:"D8",
    0x1c:"S8_O",
    0x44:"T8",
    0x08:"S8_I",
    0x33:"D11",
    0x1f:"S11_O",
    0x47:"T11",
    0x0b:"S11_I",
    0x36:"D14",
    0x22:"S14_O",
    0x4a:"T14",
    0x0e:"S14_I",
    0x31:"D9",
    0x1d:"S9_O",
    0x45:"T9",
    0x09:"S9_I",
    0x34:"D12",
    0x20:"S12_O",
    0x48:"T12",
    0x0c:"S12_I",
    0x2d:"D5",
    0x19:"S5_O",
    0x41:"T5",
    0x05:"S5_I",
    0x51:"BULL",
    0x52:"D-BULL",
    0x54:"CHANGE"
}

def handler(sender, data):
    print(dat[data[2]])

async def run(address, loop):
    async with BleakClient(address, loop=loop) as client:
        x = await client.is_connected()
        print("Connected: {0}".format(x))
        await client.start_notify(uuid, handler)
        while(True):
            await asyncio.sleep(100.0, loop=loop)

loop = asyncio.get_event_loop()
loop.run_until_complete(run(address, loop))

asyncioは初めて触ってお作法とかよくわかっていないでかなりおかしなことになっているかもしれないですが、とりあえず動きます。

Bluetooth 4.0以上に対応している環境であれば、動作するはずです。
addressで指定しているMACアドレスはおそらくハード毎に異なると思うので、各自自分でBLE Scannerで調べるなり、コード書いたりしてなんとかして下さい。

うまく動けば当たったセグメントの名前が表示されます。

以下は本題とは関係無い話ですが、アプリをPCでも出してくれるとPC張り付き勢の自分からすると、タブレットとかを準備しなくて良いので便利だなぁとずっと思っています。
あとはなんか電源入れるのかなり難しくないですか??コストカットは分かりますが操作性がうんちなので、ここは物理ボタンにするかボタン面積広くしてほしいなぁとも思いながらこの記事は終わりにします。

ISCCTF2020のwriteup的サムシン

 

前置き

2020.iscctf.site

2020/10/24 10:00~23:00(JST)で開催されたISCCTF2020に参加しました。

f:id:NonSense:20201024233912p:plain

最終的に6位でした

Pwnは何も知らないので一番簡単そうなBOF問だけ解いてそれ以外は全部ダメでした

formatStringAttack*1とかROPとか何するかは知ってるけどやり方を知らないので結局意味ないですね

でもそれ以外の点が出る問題は全部解けたのでいい感じです。

Miscの競プロ問も面白そうだし点だしても良かったんじゃね?とか思いました。自分は競技プロできないので死ぬほど時間かかりそうです。

f:id:NonSense:20201024234156p:plain

とりあえずPwn以外でWriteupを書いていこうと思います。

 

[Rev 100] strings

Stringsコマンド叩けば出てきます

f:id:NonSense:20201024234935p:plain

[Rev 468] bookshop

本屋さんアプリ的なもののバイナリがもらえます

f:id:NonSense:20201024235806p:plain

とりあえずお買い物してみます

What will you do?
buy(b)/status(s)/read(r)
b
now stock is...
shop status is ...
item                |price  |stock
-----------------------------------
Kirara               380     3
MAX                  380     3
Carat                490     1
Forward              590     2
Miracle              366     3
flag                 65535   1
-----------------------------------
what do you want?
> Kirara
buying Kirara ...
Thank you for your purchase!!
What will you do?
buy(b)/status(s)/read(r)
r
you having...
Kirara
Which one do you read?
>Kirara
Sorry can't read Kirara
What will you do?
buy(b)/status(s)/read(r)
s
shop status is ...
item                |price  |stock
-----------------------------------
Kirara               380     2
MAX                  380     3
Carat                490     1
Forward              590     2
Miracle              366     3
flag                 65535   1
-----------------------------------
your status is ...
--------------------
having...
Kirara
current money is ... 1620
-------------------

 買ったものは読めるようになるっぽいので、flagを買って中身を読んでみたいです。

What will you do?
buy(b)/status(s)/read(r)
b
now stock is...
shop status is ...
item                |price  |stock
-----------------------------------
Kirara               380     2
MAX                  380     3
Carat                490     1
Forward              590     2
Miracle              366     3
flag                 65535   1
-----------------------------------
what do you want?
> flag
Oops!!
You don't have enough money to buy it
Your current money is 1620

 お金が足りないようです。

ここでズルをする方法として、

1. 頑張ってバイナリを読んでflagの中身を取り出す

2. 所持金をめっちゃ増やす

3. flagの値段を買える値段にする

とかがあると思います

自分は、なんか楽そうだったので3の値段安くする方法でやりました

 

値段を設定しているところを探すためにとりあえずバイナリの中身を見てみます

f:id:NonSense:20201025001717p:plain

 IDAはなんかこういい感じにしてくれるのでgdb-pedaで脳死pdisass mainができなくてめんどくさいときにぶん投げると導いてくれます(たぶん)

 なんとなく17Chとか1EAhとか24Ehとかが10進数に直すと380,490,590と、値段で見たことある感じの値があります。そのなかに0FFFFhとflagの値段の65535っぽいのがあるので、これを適当な値に書き換えてみます。

 命令のアドレスで場所を特定して、FF FF 00 00を6E 01 00 00と書き換えます。(10進で366)

f:id:NonSense:20201025003022p:plain

 これで実行すると

Welcome to BookStore!!
What will you do?
buy(b)/status(s)/read(r)
s
shop status is ...
item                |price  |stock
-----------------------------------
Kirara               380     3
MAX                  380     3
Carat                490     1
Forward              590     2
Miracle              366     3
flag                 366     1
-----------------------------------
your status is ...
--------------------
current money is ... 2000
-------------------

ちゃんと書き換わっています

いい感じになったので、flagを買って読んでみます

What will you do?
buy(b)/status(s)/read(r)
b
now stock is...
shop status is ...
item                |price  |stock
-----------------------------------
Kirara               380     3
MAX                  380     3
Carat                490     1
Forward              590     2
Miracle              366     3
flag                 366     1
-----------------------------------
what do you want?
> flag
buying flag ...
Thank you for your purchase!!
What will you do?
buy(b)/status(s)/read(r)
r
you having...
flag
Which one do you read?
>flag
ISCCTF{y0u_c4n_p4tch_b1n4r13s_w1th_xxd_4nd_vim}

 

[Rev 495] The Full Bug

この問題はあんまり良くない解き方をしてしまいました

 

もらえるバイナリは、たぶんコマンドライン引数にフラグ文字列を入れてそれが正しいかそうでないかとか判定するやつだと思います(中身をよく見ていない)

そして、動的解析をしようとするとめっちゃ怒られます

f:id:NonSense:20201025004411p:plain

なんかよくわからんしめんどくさそうなのでIDAさんに突っ込みます。

f:id:NonSense:20201025004951p:plain

関数一覧の一部ですが、C++かRustの人間の温かみをあまり感じられないものが大量に出てきます。

mainから呼び出しを辿っていくと、The_Full_Bug::mainなる関数がでてきて、これが処理の中心な感じがします。

f:id:NonSense:20201025005651p:plain

ダイヤグラムを見る感じ、なんかいろいろなことをしてそうです。

もう少し詳しく見てみます。

右側中央の大きなブロックの中に配列にデータを突っ込んでそうなコードを見つけました。

f:id:NonSense:20201025010228p:plain

 16進部分だけ持ってくると

46 43 5B 51 44 24 47 52 70 26 57 25 76 78 53 7F 4F 43 2C 7F 5B 52 20 73 5B 52 6D 6F 58 53 2C 7C 58 24 2C 24 5B 41 5B 7E 4D 26 44 62 4D 27 44 6F 71 51 5B 7F 71 53 2C 7E 58 27 5F 24 4F 27 76 6D 77 78 71 2C

 こんな感じのデータが取れました。

その後の処理を見ていくと、

_$LT$alloc..vec..Vec$LT$T$GT$$u20$as$u20$core..ops..deref..Deref$GT$::deref::h095f8fa7760680c1
core::slice::_$LT$impl$u20$$u5b$T$u5d$$GT$::iter::hbf4a62277f4c02b7
core::iter::traits::iterator::Iterator::map::h4ec00d9c43bda0fd
core::iter::traits::iterator::Iterator::collect::h5b2f0cfab82d6013
base64::decode::decode::h75202e9d7508ae03
core::result::Result$LT$T$C$E$GT$::unwrap::hef1d52418495604f
alloc::string::String::from_utf8::h9956b5d28caa9b81
core::result::Result$LT$T$C$E$GT$::unwrap::hf0324079e5d371f6
core::fmt::ArgumentV1::new::h593d68c1ab5846f7
core::fmt::Arguments::new_v1::h09c81c25c4a3b7d7
std::io::stdio::_print::h20eb70976f14aeea

のように関数呼び出しが続きます。

わざわざ1byteごとにメモリに入れてたのも踏まえつつ、雰囲気で見ると、mapで1byteづつ取り出して各々なんかしらの処理を加えたものをbase64でデコードしたものをプリントしているように見えます。

だいたいの場合1byteごとに処理するのはXORか加減算くらいなので、とりあえずCyberChefにさっきのバイト列を突っ込んでXOR Brute Forceをしてみます

f:id:NonSense:20201025011559p:plain

なんとなくKey = 0x15のときだけBase64っぽいので、Base64デコードまでしてみます。

f:id:NonSense:20201025011755p:plain

フラグでました

たぶん本当はデバッガ検知を無効にしたりAngrで殴ったり色々しないといけないような気がします。

 

[Web 100] Greetinjs

 JSのソースを読むとあります

f:id:NonSense:20201025012525p:plain

 

[Web 285] Yonezer

 アクセスするとこんな画面です

f:id:NonSense:20201025013213p:plain

Lets' Watchを押すとこんな感じです

f:id:NonSense:20201025013301p:plain

 Sourceを押すとソースコードを見せてくれます

<html>
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="style.css">
</head>
<body>

<?php

function html($string) {
    return htmlspecialchars($string);
}

$flag = file_get_contents("../flag.txt");

class secret{

    public function data(){
        global $flag;
        echo($flag);
    }

}



class share_video{
    public $text="Hello Everone";

    public function data(){
        echo("<h1>" . html($this->text) . "</h1><br>");
        echo("<MARQUEE><h1>Do you like this video 👀?</h1></MARQUEE>\n");
        $urls = ["https://www.youtube.com/embed/s582L3gujnw","https://www.youtube.com/embed/gJX2iy6nhHc", "https://www.youtube.com/embed/SX_ViT4Ra7k","https://www.youtube.com/embed/Zw_FKq10S8M"];
        $num = rand(0,3);
        $url = $urls[$num];
        echo ("<div id=\"all\"><iframe width=\"1000\" height=\"600\" src=\"". $url . "\"></iframe></div>");

        }
    }


$serialized = @$_GET["data"];
$hoge = @unserialize($serialized);
if($hoge){
    $hoge->data();

}
?>
</body>
</html>

 画面表示をするために、オブジェクトのdataメソッドを呼んでいますが、オブジェクトの取得元は、GETパラメータで受け取った文字列をunserialize関数でphp変数に戻したものです。

www.php.net

 マニュアルにあるように、unserialize関数はユーザが直接いじれる値に使ってはいけないようです。

 問題のソースコードを読む感じでは、flag変数にflag.txtの内容があり、secretクラスのdataメソッドを呼ぶと表示してくれそうなので、そういう感じにしたいです。

ここで、URLをみてみると、

http://[server_addr]/share.php?data=O:11:"share_video":1:{s:4:"text";s:13:"Hello%20Everone";}

 と良さげな感じのデータが乗っています。これはシリアライズされたクラスのデータのハズです。

www.phpinternalsbook-ja.com

 中身はよくわかんないですが、とりあえず今はsecretのdataを呼び出せればいいので、クラス名っぽいところと文字数だけ変えてアクセスしてみます。

http://[server_addr]/share.php?data=O:6:"secret":1:{s:4:"text";s:13:"Hello%20Everone";}

f:id:NonSense:20201025022202p:plain

[Web 475] mark damn it

 Markdownを入力してConvertを押すとHTMLに変換してくれます。

f:id:NonSense:20201025022905p:plain

 問題添付ファイルのうち、Gemfileを見てみます。

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem "kramdown", "2.2.1"
gem "sinatra"
gem "puma"

 MarkdownからHTMLへの変換はkramdownを使っていそうです。

わざわざバージョンを指定している感じがとても怪しいので少し調べてみます。

nvd.nist.gov

 2020年の7月に発表されたての脆弱性:CVE-2020-14001が出てきました。

kramdownの2.3.0未満のバージョンには任意ファイルの読み込みと任意コードの実行ができる脆弱性があるようです。

今回の問題では2.2.1が使われているので、この脆弱性を使えそうです。

 

www.feneshi.co

 このページ*2のように、テンプレートオプションの中にうまい具合にしてコマンドを入れ込んで、サーバのディレクトリ内を調べていきます。

f:id:NonSense:20201025024942p:plain

 フラグファイルっぽいものがあったので中身を覗いてみます

f:id:NonSense:20201025025056p:plain

 

[Web 491] crackjwt

f:id:NonSense:20201025025747p:plain

 かわいい*3

 Get Flagを押してみます

f:id:NonSense:20201025025947p:plain

 adminじゃないとフラグは読ませてくれないようです。

問題文がjwtをcrackしろと言っているのでjwtについて調べてみます

techblog.yahoo.co.jp

 なんかしらの情報とハッシュをくっつけて認証とかに使うモノのようです。

 

ここで問題ページのソースコードを見てみます。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>crackjwt</title>
    <style>
        p {
            text-align: center;
        }

        .flgBtn {
            display: inline-block;
            padding: 0.3em 1em;
            text-decoration: none;
            color: #1DA1F2;
            border: solid 2px #1DA1F2;
            border-radius: 3px;
            transition: .5s;
        }

        .flgBtn:hover {
            background: #1DA1F2;
            color: white;
        }
    </style>
</head>

<body>
    <p>
        <img src="static/welcome.gif" alt="welcome"><br>
        <a href="flag.php" class="flgBtn">Get Flag</a>
    </p>
    <!-- <a href="?source">debug</a> -->
</body>

</html>

 コメントに消しそびれみたいなものがあるのでその記述にそって、?sourceをURLにつけてアクセスしてみると、そのページのphpソースコードが表示されました。

indexページとflag.phpのソースがそれぞれ見れたので、関係ありそうなところだけ見ていきます。

 index

$file = fopen('/var/www/app/private/secret.txt', 'r');
$secret = fgets($file);
fclose($file);
if (!isset($_COOKIE['token'])) {
    setcookie('token', generate($secret));
}

function generate($secret)
{
    $header = json_encode(array(
        'alg' => 'sha256',
        'typ' => 'JWT'
    ));

    $payload = json_encode(array(
        'isAdmin' => '0'
    ));
    $signature = hash('sha256', $header . $payload . $secret);
    return trim(base64_encode($header), '=') . '.' .
        trim(base64_encode($payload), '=') . '.' .
        trim(base64_encode($signature), '=');
}

 flag.php

$file = fopen('/var/www/app/private/secret.txt', 'r');
$secret = fgets($file);
fclose($file);

if (!isset($_COOKIE['token'])) {
    $flg = 1;
}


$parted = explode('.', $_COOKIE['token']);
$signature = $parted[2];

if (isset($flg) || hash('sha256', base64_decode($parted[0]) . base64_decode($parted[1]) . $secret) != base64_decode($signature)) {
    die('<script>alert("Invalid token!!");document.location="/"</script>');
}

$payload = json_decode(base64_decode($parted[1]), true);
$isAdmin = $payload["isAdmin"];
if ($isAdmin == 0) {
    echo '<img src="static/nyoronyoro.gif" alt="nyoronyoro"><p>You don\'t have the authority to read flag.<br>Please come back as an administrator.</p>';
} else {
    require('/var/www/app/private/flag.php');
    echo '<img src="./static/congrats.gif" alt="congrats"><p>Congrats!!<br><strong>' . $flag . '</strong></p>';
}

 Cookieの中のtokenがJWTのようです。

Cookieの中身を確認してみると、

token=eyJhbGciOiJzaGEyNTYiLCJ0eXAiOiJKV1QifQ.eyJpc0FkbWluIjoiMCJ9.Yzc5Y2Y2MzlkYjkyNjdjZDkwNzJhNDkyODU0ZTE0ZWYwOTI2NDI3NTlkN2M0YmViN2Y1NDBjOTU4NWYzNzFjYg

のようになっています。

jwtは「.」区切りでbase64エンコードされているので各々デコードすると、

{"alg":"sha256","typ":"JWT"}
{"isAdmin":"0"}
c79cf639db9267cd9072a492854e14ef092642759d7c4beb7f540c9585f371cb

このように3つのデータを取り出せます。

上から、ヘッダ, ペイロード, シグネチャです。

isAdminを1にすればadminとして認めてくれそうな気がします。

このページにおいて、認証処理がどのようになっているかを確認するためにflag.phpのコードを見てみます。

 

flag.phpのコードから、認証の処理は

$parted = explode('.', $_COOKIE['token']);
$signature = $parted[2];
if (isset($flg) || hash('sha256', base64_decode($parted[0]) . base64_decode($parted[1]) . $secret) != base64_decode($signature)) {
    die('<script>alert("Invalid token!!");document.location="/"</script>');
}

 のように、tokenのヘッダとペイロードとsecretをつなげたモノのsha256ハッシュが、シグネチャと一致していないと弾かれるようになっています。

 

なんとかして、でっち上げたJWTを本物と認識させたいです。

moneyforward.com

 このサイトにあるnone-attackは、今回の問題では3シグネチャが必ず必要になるため使うことができません。

また、brute-force secretでもどの辞書を使っても特定することができませんでした。脆弱なsecretは使われていないようです。

 

そうなると、別の方法でsecretを手に入れなければなりません。

flag.phpのコードを見ると、secretは

 /var/www/app/private/secret.txt

 にあるようです。 まともな設定なら見られなさそうな場所です。

問題の添付ファイルにnginx.confがあるので中身を見てみます。

server {
    index index.php index.html;
    server_name localhost;
    root /var/www/html;
    
    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    location /static {
        alias /var/www/app/static/;
    }

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass crackjwt:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

qiita.com

 staticのエイリアスパストラバーサルが起こせそうです。

 secret.txtを読んでみたいので

http://[server_addr]/static../private/secret.txt

にアクセスしてみます。

f:id:NonSense:20201025041035p:plain

 secret.txtの中身のようなものが手に入りました。

 JWTの形式は先ほどの通りなので、

{"alg":"sha256","typ":"JWT"}{"isAdmin":"1"}48a939f9d0ef3778ee4fbbca6ffdd933

 をsha256ハッシュしてBase64エンコードしたものがシグネチャ部分になります。

f:id:NonSense:20201025042117p:plain

残りのヘッダとペイロードBase64エンコードして「.」でつなげます。

eyJhbGciOiJzaGEyNTYiLCJ0eXAiOiJKV1QifQ.eyJpc0FkbWluIjoiMSJ9.ZmFlNjNhNjFkMTExYTRiYmY2MmU5YzAzZmI1N2U5MTNmM2FmYjE5OTdiNDVjMzA4MDNjZDljYjgxYmY4ODc3YQ

 これをCookieにセットして、flag.phpにアクセスします。

f:id:NonSense:20201025042609p:plain

 

[Misc 468] Shell Ain't Bad Place to Be

// maybe-later: 

www.jx-zhang.xyz

 

[Forenssics 387] Last Logon

// maybe-later:

./rip.exe -r SAM -a

github.com

*1:この問題に関してはオフセットは7なのに、ずっと8だと思いこんでいた。凡ミス

*2:これは後で気づいたことですが、たぶん作問者様のページっぽい

*3:かわいい

InterKosenCTFのWriteUpをすこし

チーム:074m4K053nのN0n5enseで出てました

f:id:NonSense:20190120222114p:plain

弱い(確信)

チームとしては全体10位で高専チームで3位でした。

Cryptoが強い先輩がいて、夜寝て朝起きたらCrypto全部解かれてたときはビビりました。

 

とりあえずでWriteUp的なものを書いて置こうと思います。

 

 [Cheat 100] lights out

うさみみとかねこまんまでメモリ見てフラグ形式で検索

f:id:NonSense:20190120223330p:plain

[Cheat 250] anti cheat

chromeデベロッパツールで難読化解除するなりして、読む気を起こさせてから、SCOREを表示してるところを検索かけると、_e3._r3にスコアが入ってるんじゃないかと思って、watchしてゲームしてると確からしいので、それでまた検索。

f:id:NonSense:20190120223643p:plain

_e3._r3が使われているところをみると、インクリメントしてるところとかあるので、+=10000みたいなのにして実行すると、怒られます。

他を探してみると、

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

とかいうのがあって、これがハイスコアのしきい値ではないかと予想して、元コードで該当部分を書き換えて_e3._r3>=2とかにしてゲームオーバーまで持っていくとフラグが出てきました。

f:id:NonSense:20190120224355p:plain

想定解ではなかったようです。

[Forensics 200] conversation

FTKで漁ってたらなんか画像が出てきました

f:id:NonSense:20190120225839p:plain

問題がconversationだったので、チャットができそうなアプリとかを最初調べてたんですけど、あんまり関係なかったですね

ちなみにdata/com.google.android.apps.messaging/databases/bugle_dbのconversation_list_search_viewにJiro Kosenくんとママとの会話がありました。

f:id:NonSense:20190120230643p:plain

 

KOSEN セキュリティ・コンテスト2018に参加しました(日記とWrite-Up) #kosensc

こんにちはセンス無いです。

今回KOSENSCに小山高専のチーム" 074m4K053n (おたまこうせん) "略称"074m4"として参加しました。

チーム構成は4年生な僕と、自作OSとかしちゃう系の同級生1人と、たしか専攻科1年のpythonできる系の先輩と数学ができる先輩でした。

 

前回の木更津高専さん主幹の大会はインテンシブ・イングリッシュとかいう教科のせいで行けるはずの会場に行けなかったうえ、参加すらもできなかったというクソ仕様でした。

今回はちゃんと大会に参加できました。よかったね。

今回は会場が福岡(だっけ?)なので、会場には行かずにリモート参加です。

 

学校のラウンジを借りてみんなでPC持ち寄って参加しました。

手前側がぼく達のチームで、奥が別のチーム" おやまようちえん(おやまどうぶつえん) "略称:"およ"です。毎回毎回チーム名なんなんですかね。

KOSENSCのslackのrandomに顔入り写真をアップロードしてしまう情報リテラシーのかけらもない学校ですうちは。(でかいポカリのペットボトル顔の前で持ってるのが僕です)

 

それで、そんな頭の悪い学校のチームの結果は、3250点で総合3位でした。

webに弱いのが見え見えですね。(というかwebの配点高くない????)

今回のチームは僕がちょっとwebの知識あるくらいな感じだったので、脆弱性名と攻撃方法ををpythonが書ける系のおにいさんにぶん投げるみたいなノリでweb問解いてました。

"およ"のほうも7位なのでだいぶ頑張れたと思います。拍手拍手!

 

全23問の中で僕が解いたのは、たしか

  • 07 シンプルなQRコード [Binary 200]
  • 08 旅行の写真 [Crypto 200]
  • 10 Basic認証 [NetWork 100]
  • 18 更新されたIoT対応デバイス [Misc 50]
  • 20 サイトを見ていただけなのに [Misc 50]
  • 21 謎のファイル [Misc 100]
  • 23 攻撃ログ [Misc 300]

なはずです。

以上が間違っていなければ、僕がsubmitした分の得点は1000点分ですね。

他の人に解き方だけ教えて、解いてもらったものとかもあるのでもうちょっと貢献できているはず。

 

これからCTF始めそうな学校の低学年とかにも備えて、僕が解いたやつ以外にも解法を聞いてるやつもWrite-Upしていこうと思います。そこそこ丁寧めに書くつもりです。

 

00 Sample [Sample 100]

 

やるだけ。

 

01 まどわされるな! [Binary 100]

 渡される問題ファイル"flag.out"をcatするなりfileなりするとELFであるとわかります。

とりあえず、stringsに突っ込むなり、catするなり、テキストエディタに突っ込むなりすると

flag is SCKOSEN{you_are_go... oops! I Forgot!

 というテキストが見つかります。見つかるはずです。彼は脳内メモリが26bytesしか無いようです。ナメてますね。

(僕はこの問題を解いていないし、実行したらどうなるかとか知らないです。)

これが、"片方のフラグ"らしいです。

そして、このflag.outを、メモ帳に突っ込んでjpgのマジックナンバーFF D8 FF EE(.リ.)を目Grepするか、binwalk(win環境ならDataCutter.exeとか)に突っ込むとケツにjpgがくっついているとわかります。

そのバイナリを取り出すと

こんなのが出てきます。

これらを結合したらフラグです。

 

問題の"まどわされるな!"は、おそらくELFの解析のこととかでしょうね。

 

マジックナンバー(ファイルの頭についてる識別コード的なもの)はいくらか覚えていると便利なので一回は目を通して見よう!!! マジックナンバーまとめ

 

02 ログインしたい! [Binary 100]

渡されるのはELFらしいですが、解いてないし、話も聞いてないので解法知らないです。

stringsとかltraceとかstraceすればフラグ出るんじゃないんですか(適当)

 

03 printf [Binary 100]

とりあえず、ncしてみます。

するとなんだか、

みたいなのが出てきます。接続毎にthe secret is in の値は変わるようです。

what do you want:

と聞かれるので

Money!!!

とか書いてEnterッタッーンってすると、

there is no Money!!!

 って言われます。ナメてますね。

そして、この結果と問題名、からメタ推論すると、内部のコードは

printf("what do you want:");

scanf("%s",str);

printf("there is no %s",str);

みたいになっていると思われます。

そして、"%x %x %x"とか入力すると、

このようにアドレス値っぽいのが出力されます。

これらのことから、典型的なFormat String Attack(書式文字列攻撃)が効くやつとわかります。

さらに、" the secret is in "とか言っているあたりから、そこに表示されているアドレスにフラグがあると目星をつけます。

僕はコード書けない系なので、先輩に脆弱性と攻撃手法を伝えてコード書いてもらいました。先輩は脆弱性知らなかったっぽいのでぼくの間接的得点です。+100

とっても典型的な問題なので、解き方とかコードとかは調べればいくらでも出てくると思います。

 

04 XOR,XOR [Binary 200]

 ぼくは何もしりません。

なんかプログラムの中でフラグを作っているらしいので、デバッガ使って適当なところで止めたりすると、フラグが出てくるそうです。しらんけど

 

05 Simple anti debugger [Binary 250]

これも知らないです。

先輩が

アセンブラ高級言語だなぁと思いながら、バイナリ書き換えた

 とか言ってました。

デバッガを弾いてるとこのコードを書き換えて、"Simple non anti debugger"にしてdgbぶん回して解いたって言ってましたよ。

 

06 exchangeable if [Crypto 100]

次のような画像が渡されます。

ナメてますね。

このファイルをstringsにかけるなりすると、

md5=2009d1c114ed83f57cf8adde69fd6ca8 

という文字列を見つける事ができます。

ぼくが分かったのはここまででした。

しばらくしたら、数学のできるおにいさんが、

トイレ行ってたらなんかフラグでてたww 

 みたいなこと言っててsubmitしたらsuccessしてました。こわい

解法を聞いたところ、あのMD5はフラグのハッシュだったらしいです。

不明な文字がxxxxの4文字で、入りうる文字は大小英数字の計62文字っぽくて、全ケースは62^4=14776336です。

確かにトイレ行ってる間に出そうな数です。

コード書いて、ハッシュが一致したものがフラグです。

 

07 シンプルなQRコード [Crypto 200]

こんなことしてたので当然この問題はぼくに回ってきました。

 

はい。

問題では、次のようなQRコードが渡されます。

なんかすっごいみたことありますねこういう問題。

SECCON CTF 2013のonline予選[forensics 400]の問題ですね。

eleclog.quitsq.com

はい。ここのブログ様のようにやりましょう。

数学のできるお兄さんに、上のブログURLをぶん投げて、誤り訂正ビットから、マスクパターン指定子を計算してもらいました。

結果は0b011 = 3らしいです。

この結果を用いて、手でごちゃごちゃやろうとしてるところに同級生くんが強そうなツールを見つけてきてくれました。

github.com

めっちゃ強そうですね。(名前大好き)

このツールに文字列にしたQRの配置をぶん投げると、デコードしてくれます。

とりあえず問題のQRコードを文字列化するコードを適当に書きます。(ぼくはHSPで書いた)

そんでもって、このツールに突っ込みます。

すると、

不明なモード指定子 

みたいな感じで怒られてしまいます。

デバックモードのオプションをつけて実行してみると、モード指定子が書いてある、右下のパターンを見ると、確かに存在しないモード指定子になっています。(確か0b1010)

ぼくは一回、数学のできるお兄さんに出してもらったマスクパターンでマスキングした画像を作っていて、そのパターンとは明らかに違っていたので、おそらく"ツールがはじき出したマスクパターンが間違っている"と予想立てしました。

このツールは-mオプションでマスクパターン指定子を指定することができるそうなので、計算してもらった"3"を指定して実行してあげると、フラグが出てきます。

 

08 旅行の写真 [Crypto 200]

次のような画像が渡されます。

何かを隠しているそうです。

とりあえず、中のデータを見てみましたが、特に怪しそうなところは見当たりません。

よくわかんないので

png ステガノ

でGooglingしました。

すると、トップでこんな記事が出てきました。

ステガノグラフィーの解析について

"うさみみハリケーン"の"青い空を見上げればいつもそこに白い猫"のヘルプっぽいです。

読み進めると、赤色数値のビット0を抽出するとフラグが出てくる例とかが書いてあります。

こういう系かなと思ってとりあえずソフトをDLして、突っ込んで"ステガノグラフィー解析"を押しました。

こんな感じの画面になります。

左上の"次候補"を押して行くと

いろいろなタイプの表示をすることができます。

 こんな感じで。

とりあえず次候補をクリックしまくってみます。

こんな感じになります。

どうやら、緑と青のビット[3:0]に本来の画像ではないデータが入っているっぽいです。

 

そしたら、画面右上の"ビット抽出"を押します。

 こんな画面になります。

そしたら、さっき見つけた怪しそうなビットに対応するとこにチェックを入れます。

 そして、"バイナリデータ"表示を押すと、

フラグが出てきます。

 

いやぁ、マジで便利ですねうさみみさん。

コード書こうとしたらすごいめんどくさいし、そもそも兆候を見つけられない気がします。

ちなみに、この問題は僕がFirst Solverでした。

初日終了時点で " あの " insecureさんちも解けてなかったのでだいぶ浮かれてました。

 

09 CMA [Crypto 250]

数学のできるおにいさんが解いてました。

問題の.txtを読むとRSA暗号の問題っぽいです。

ファイルでは公開鍵n,eの組とそれに対応する暗号文cが2つづつ与えられています。

それらの値を見ると、

n1=n2

e1≠e2

であるとわかります。

そしてファイルには、

Dec(c1) == Dec(c2) == m?: True 

 と最後に書いてあります。

c1とc2を解読した結果が一致しているということでしょう。

このような場合には、Common Modulus Attackが有効です。

あとは適当に調べて書いてある通りに実行すれば解けるはずです。

inaz2.hatenablog.com

ももテクさんめっちゃ参考になるはずです。

 

09 RSA? [Crypto 300]

これも数学のできるおにいさんが解いてました。

おにいさん曰く、問題文の

冪演算のない世界線に来てしまった。

から、ヒントを得たそうです。

 

通常のRSA暗号の仕組みは、

暗号化 : c = m^e mod n

復号 : m = c^d mod n

の式で表されます。

しかし、この問題では冪演算が存在しないそうなので、冪演算の代わりに掛け算を使っているのではないかという予想を立てたそうです。

そうすると、暗号化の式は c = m*e mod n となります。

これを復号する場合は m = c/e mod n となりそうです。

あとは計算して文字列化して終わりです。

 

10 Basic認証 [NetWork 100]

pcapが渡されるので、とりあえずWireSharkで開いてみます。

そして、適当なパケットを右クリして追跡でTCPストリームなりHTTPストリームなりを表示してみると

こういうのが出てきて、

Authorization: Basic am9objpzOG9YKnpsY3JvOD8jd2xibHByNA==

 の最後のブロックをBase64でデコードすると、

 john:s8oX*zlcro8?#wlblpr4

 となります。

それで、ストリームの最後の方に

<p>flag is here

<a href="/flag.zip">flag.zip</a>.</p>

<p>(zip password is john's password.)</p>

 と書いてあるのでflag.zipを取り出します。

ファイル -> オブジェクトをエクスポート -> HTTP でflag.zipがある行を選択して保存します。あとは書いてある通り、johnさんのパスを突っ込んで回答したらフラグが出てきます。

 

11 ログインしてフラグを入手せよ。 [NetWork 150]

ぼくは解いてないので知らないです。

これを解いたおにいさん曰く、akictfに同じような問題あるそうです。

そのWrite-Upを探せば解けるはずです。

 

12 サーバーから情報を抜き出せ!

 問題で与えられているサーバーにアクセスするとこんな感じの画面が出てきます。

画像が頭おかしくて好きです。

このページは画像しか表示していないうえに、ソースコードにも怪しいところがありません。

わかんないので、画像を右クリして新しいタブとかで開いてみます。

するとURLがこのようになります。この状況からメタ推論して、このリクエストにはディレクトトラサーバルちゃんトラバーサルの脆弱性があると考えます。

問題文で、フラグのファイルは"flag.txt"ということが分かっているので、とりあえず、filenameのパラメータに書いて見ます。

 

はい。このディレクトリにはそんなもの存在しないそうです。

僕はここで詰まったので、先輩に状況を投げたら、" ../flag.txt "指定したら行けた!!ってなってました。

そういうことらしいです。

これも僕の間接的得点ですねきっと。+100

 

14 アカウントを奪え [Web 300]

問題のサーバーにアクセスすると、

こんな表示になります。

kosenjohでログインしろとのことなので、Useridにそれ突っ込んでPasswordにpasswordとか1234とか弱そうなパスをとりあえず突っ込んで見ます。ただ、なんか違うっぽいのでSQLインジェクションとかできるんじゃね??とか思い始めます。

Useridにkosenjoh、Passwordに典型的なSQLiの'OR 1=1;-- を突っ込むと

こんなページに飛ばされます。

古戦場から逃げるな!!

さっきのフォームのphpコードですね。

この問題の最終目的は"kosenjoh"のパスワードを抜くことだそうです。

コードを読む感じでは、SQLのクエリの結果は成功か失敗かしかわからなそうです。

こういう場合はブラインドSQLを使います。1文字づつ調べて行くやつです。

僕はコード書けない人種なので、pythonのおにいさんにこのソースのページと参考になりそうな記事をぶん投げたら解いてくれました。

間接的得点+300

 

15 47405b599e22969295ebed486d7343cb [Web 300]

解けなかった問題その1

とりあえず問題名が謎なので調べて見ると、

"SQL Injection"のMD5ハッシュだそうです。

はい。ヒントですね。

問題のサーバーにアクセスしてみます。

こんな表示です。SQLiしろってことらしいのでとりあえず上のNo.に'OR 1=1;-- を入れてみます。

こんな感じのデータの組が83件表示されますValueはなんだかAsciiコードっぽいですが、あんまり関係なさそうなのでスルーしました。

(insecureさんのWrite-upにデコードした結果が書いてありました。ここにはフラグないでwフラグはだれかのパスやぞwwみたいな感じになるらしいですよ。

スルーしたけど、あってもなくてもあんまり関係なさそうだったので良かったです。

 

んで、したのログインフォームっぽいとこも調べて見ます。

ぼくあんまりかじってないので、詳しく書けないんですが、IDにadmin突っ込んで、適当なインジェクション仕込むと、Welcomeとか表示されたそうです。

どうせadminのパスワードがフラグだろうと踏んでいたので、pythonのおにいさんにブラインドSQLのコード組んでもらってやってもらってたんですが、なぜか途中で404が吐かれるようになって結局解けずじまいでした。

相当悔しがってました。わかる。ちゃんとしたWrite-Up読みたければinsecureさんのとこ見に行くといいと思うよ。

furutsuki.hatenablog.com

 

16 進撃せよ [Web 300]

解けなかった問題その2です。

WAFの問題でした。

アクセスしてみます。

"test.txt"をクリックするとtestと表示されました。

URLを見ると、

http://waf.kosensc2018.tech/list/dGVzdC50eHQ= 

 となっていました末尾は明らかにBase64なのでデコードしたら"test.txt"になりました。

次に"flag.txt"をクリックすると、

ってなります。 わふ~~~

また、ファイル名はBase64エンコードしなくても、アクセスできるみたいです。しかし、相変わらずflag.txtはわふ~~~ってなります。

つまりは、(平文にflagが含まれている) or (Base64でデコードした結果にflagが含まれている) っていうことですね。たぶん。

どうにかしてflagを含まずにflag.txtと表現するという方針でいろいろやってたんですけど、全部ダメでした。

例えば内部がshell的なものと想定してfl''ag.txtと入れてみたり、文字列連結のシェル芸とかしてみたりしてました。

途中やってて、../のb64エンコードを突っ込んだら、無が表示されたので、ディレクトリトラサーバルちゃんがいるって気づきはしました。気づきは。

他の人のWrite-Upみると../../../../../etc/passwdが成功するらしいです。ぼくも同じようなことやったんですけど多分../の数が違うのだけを入れていた可能性がとても高いです。残念。まあ見れていたところで、その先は絶対進められなかったとおもいますけどね。

 

この問題は"flag.txt"を2回b64エンコードすることでflagを取れたそうです。エスパー問題らしいです。

とても単純でした。エスパー力が足りませんでしたね。

これ解けていれば2位になれていたので、とっっってもくやしいです。くぁwせdrftgyふじこlp;@:「」あsdfあsdf

 

はい。まあ仕方ないですね。こういうこともあります。トランプの裏側から番号当てるゲームをしまくって10月のonline予選に備えます。どうせまたSECCON{STAR_WARS}とかでてくるから。

 

17 人大杉を見たくない [Misc 50]

KOSENSCのMisc問はほとんどがGoogling力を試される感じですね。

www.atmarkit.co.jp

まあこれじゃないですか?

正解知らないんでわかんないですけど、たぶんavaliabilityです。

 

18 更新されたIoT対応デバイス [Misc 50]

Joke RFCですね。いつものって感じです。

Hyper Text Coffee Pot Control Protocol - Wikipedia

https://tools.ietf.org/html/rfc7168

コーヒーのやつを知ってればお茶のも知ってると思います。

コーヒーをお茶向けに拡張したやつらしいですよ。

Joke RFC伝書鳩プロトコルとかも結構好きです。

 

19 君の名は2018 [Misc 50]

前回のKOSENSCで"君の名は"っていう問題が出たらしいですね。

これも調べるだけです。

これはだいぶ話題になったので知ってる人がほとんどだと思います。

 

20 サイトを見ていただけなのに [Misc 50]

気合で調べましょう。

ドライブバイダウンロード - Wikipedia

pythonのおにいさんはハイフン区切りを見逃していたらしくて投げてました。いただき

 

21 謎のファイル [Misc 100]

とりあえずファイルをダウンロードします。

zipらしいです。よくわかんないのでとりあえず展開しましょう。

はい。分かる人は一瞬でわかると思うんですけど、Microsoft Wordのファイル構造です。(wordってディレクトリがあるからそれでも気づけるかも)

あとは、"rename_me.xml"とかいうファイルがありますね。

名前変えればよさそうです。

wordのファイル(.docx)を作って、拡張子を.zipに変えて展開してみましょう。

CTFやったことのある人ならば、オフィスのファイルは全部zipで展開できるってのを知ってると思います。知らなかった人はおぼえて。

さっきの問題のやつと比較してあげると、"rename_me.xml"は"[Content_Types].xml"にリネームしてあげればよさそうです。

名前を変えたら、zip圧縮して、拡張子を.docxに変えてWordとかで開いて見ましょう。

縦書きでフラグが出てきます。

 

22 ディスクが足りない! [Misc 100]

悲痛な叫びですね。

ファイルをダウンロードすると.gzのファイルをもらえます。

展開しまくるとフラグが出てくるそうです。

僕解いてないので知らないです。

 

圧縮しまくると1bitとかになっちゃうって思いこんでるやつですね。かわいい。

 

23 攻撃ログ [Misc 300]

ファイルを落っことしてくると、Apacheさんのアクセスログっぽいです。

生のテキストだとクソ見づらいので適当なビューワを落としてきました。

www.vector.co.jp

こんな感じ。生テキストよりずっといいです。

一応1万行ちょっと全部目を通した感じだと、セッションハイジャックしようとしてたり、windows\system.iniとか/etc/passwdとかを見ようとしたりファイルアップロードで書き換えようとしてるような感じでした。なんかゲームサーバーとか社員用のファイルエディタとかブラウザ、その他いろいろな機能を提供してるみたいですね。全く関係ないです。

技術的な観点からログを探すならば、攻撃が成功してるであろうログをピックアップしていく感じになるでしょう。やるなら、コードが200以外でファイルをいじっているようなログとか。

そういうのはめんどくさいので問題として成立するようなログを探す方向でやりました。このログは、ほとんどのログが重複していて、唯一のログというのが見当たりません。

つまり、他のログと重複していない唯一のログを探し出すのが目標になります。

落としてきたツールの機能をいろいろ使って調べてみたところ、ログの中にAgentが3種類登場することがわかりました。

  • Content-type:-
  • Content-type:application/x-www-form-urlencoded
  • Content-type:multipart/form-data;

これらの3つです。そして、一番下のmultipart/form-data;は11039行のログの中でたった1つしか存在していませんでした。

192.168.10.26 - - [29/Aug/2018:20:56:37 -0700] "POST /fileupload/upload.action HTTP/1.1" 500 347 time:49 Content-type:multipart/form-data; boundary=---------------------------100000000000

このログですね。

これをsha-1でハッシュしたのを送って300点!かとおもったらなぜか、不正解。

結局sha-1ハッシュを大文字で書いていたのが悪かったみたいです。

小文字でsubmitしたら通りました。そこら辺2種類登録しといてほしいですね。

 

Content-type:multipart/form-data;はファイルアップロードのときに出るやつなので、これをアテにして解いていく感じなんですかね。

おそらくディレクトリトラバーサル経由のファイルアップロードでシステム書き換えられた!みたいな想定で。

 


 

以上、結局全問触れてしまいました(需要がなさそう)。自分が解いてないやつは詳しく書いてないですけど、多分調べれば全部解けるので、まあそういうことで。

 

今回もとても楽しめたので、来年も是非参加したいですね。

KOSENSCは難易度がSECCONの予選とかよりも学生向きで、解きやすいのが多くていいですね。(KoHやりたかった)

あとは要望というか、愚痴というかなんですけど、スコアグラフとかのページを公開してほしいなぁって思ったりしました。youtubeの配信だと切り替えの時間が早すぎてまともに見れなかったんですよね。

それと、ジャンル分けをもうちょっと詳しくしてほしいなぁって思いました。ステガノだとかreverseだとかそういう

 

次はSECCON online予選になるのでWebを解けるようにして挑みたいですね。

今回のKOSENSCはなんだかwebの1問あたりの配点すごく高かったですね。Webはぼくらのチームの弱点なので、とてもつらい感じでした。

でもまあ、全正答まで2問に迫れたのでだいぶ良かったと思います。

 

こんなかんじですかね。

わざわざここまで10,829文字も読んでくれてありがとうございました。

参加者、運営陣の方々おつかれさまでした。最後の方とかスコア白熱しててとってもいい大会でした!

BMS用IIDX専コンを自作

2020/08 追記: googleフォトから画像を貼り付けているため現時点で表示がされていないと思います。

 

きっかけは弐寺専コンが欲しいと友人に頼まれたことです。

友人はACサイズなことと1P2P切り替え出来ることと小さいのがいいと言うのでその方向で設計します。

f:id:NonSense:20200830211051p:plain

はい。

一応中身の補強用の垂木的なものも全部書いてあります。

頑丈に作ることで板の反響から来る騒音を軽減できます。(個人的見解)

 

天板と底板は9mm、側面の板は12mmで設計しました。

裏面は鬼目ナットを突っ込んでネジで固定して、メンテ用に取り外せるようにしました。

 

これで設計は終わりなのでホームセンターに行って板を買ってきます。

見た目と強度的にMDF板にしました。

ホームセンターだと板カットのサービスがあるのでとても便利です。

 

買ってきたので仮組みしてみます。

f:id:NonSense:20200830211124j:plain

f:id:NonSense:20200830211144j:plain



ホームセンターのお兄ちゃんが上手だったので精度はかなりいいです。

 

寸法の間違いが無いのでとりあえず、側面だけボンドで組み立てます。

f:id:NonSense:20200830211210j:plain

ボンド塗っておもりで加圧して放置です。

 

次に皿を作ります。

皿は黒のABSの2mm板を使います。

f:id:NonSense:20200830211228j:plain

学校の工房を借りて気合で丸く削りました。

CGじゃないです。

はざいやさんとかに頼むときっと楽です。

これと一緒に皿の下の土台になる木を削ります。

12mm板を2枚重ねて24mmにします。

多分これくらいでACとおんなじくらいの位置になります。

皿本体はこれでOKです。

 

次にボタンを取り付ける板を作ります。

友人仕様に1P2P切り替えの機能を要求されているので、本体とは分離した板にボタンを取り付けます。

筐体本体への取り付け穴は完全に対称にしてあるので180度ひっくり返して使えます。

f:id:NonSense:20200830211244j:plain

f:id:NonSense:20200830211307j:plain

 

下に4mmのMDF、上に2mmのアクリル板の2層構造です。

ついでに間に挟む紙も作ります。

f:id:NonSense:20200830211326j:plain



こういう。

ダサいです。

 

次に皿の構造部分を作ります。

クラスメイトに3Dプリンタでフランジとエンコーダの歯を印刷してもらいました。

f:id:NonSense:20200830211340j:plain

f:id:NonSense:20200830211402j:plain

便利ですね。

結局このエンコーダの歯は使うことにはなりませんでしたが。

 

3Dプリンタがない場合はM8くらいのぼボルトを使うといいです。

皿に穴開けてナットで止めれば終わりです。

エンコーダの歯はレポート用紙の一番最後の厚紙とかそういう奴を切って使うといいです。

僕もそうしました。

 

これで大体部品揃ったので組み立てます。

ボタンはお金が無いのでお金が出来るまではとりあえず自分の専コンのボタンを付けておきます。

f:id:NonSense:20200830211417j:plain

f:id:NonSense:20200830211431j:plain

 

エンコーダはさっき言ったように紙です。

センサーは秋月で売ってる透過型のフォトインタラプタです。

基板は自作物です。

pic18f2550でMicrochipさんのサンプルプログラムを適当に改造して使ってます。

 

USB接続でPCからはゲームパッドとして認識されます。

このように。

Infinitasはやってないですがせっかくマイコン積んでいるのでInfinitas仕様の皿の挙動も実装しました。

動くかはわかりません。テスト出来ないので。

 

以上です。

友人君は今年大学受験なり就職なりする年なので今年度中は僕が遊んでいるつもりです。

 

今年中は僕が持っているので小山高専工陵祭のエレ研だかEE専門企画のところにおいておく予定です。

僕が遊んです。来てくみてださい。

 

 

テストプレイ動画あげました。

www.youtube.com

チュウニズムのエミュレータを作ってみる

どうも、センス無いです。

 

これまで、たまにTwitterに上げてたチュウニエミュの進捗ですが、ブログの方にまとめて行きたいと思います。(まとまってたほうが幸せになれる人多いと思った)

進捗があり次第、このページに追記していく感じでいこうと思います。

Tweet貼り付けてく感じでいいですよね 

あんまり更新頻度高くないと思います。

 

 

 

  • 譜面仕様を軽く説明
  • 4/8更新分進捗
  • TAPの追加
  • FLICKの追加
  • HOLDの追加
  • SLIDEの追加
  • AIRの追加
  • どうでもいい開発道中(日記含む)

譜面仕様を軽く説明

リズムの記述方法はBMS形式と同じです。

ヘッダ部も既存のBMS形式とほとんど同じです。

ただ、チャンネルと実データ部はチュウニズム用にだいぶ変えました。

チュウニズムは音再生は無いので…

詳しい仕様は要望があれば、早期に公開しますが、ソフトがリリース可能になったときと同時に公開するつもりでいます。

(一番早いのは本人に直接聞くこと)

 

 

4/8更新分進捗

アルストロメリアの紫譜面を借りて実際のゲームに近い形での描画・再生テストです。

 

 

TAPの追加

 

 

FLICKの追加

 

 

続きを読む

KOSENSEC2016に参加した話(軽いWriteUpのようなもの込)

高専セキュリティコンテスト2016にzabun_oyamaとして参加しました。

今回初開催の大会だったのでいろいろとトラブルが多かったですね。というかトラブルしかなかったというか、なんか凄かったです(語彙力)

 

このセキュリティコンテストですが、各チームにIoTサービスを提供する感じのサーバのアドレスが開始直後に渡されて、そこにSSHで接続して、リモートで脆弱性修正なりバグ潰しなんかをしていって点を稼ぐ形式でした。

珍しいことに問題文が一切無く、修正するべき箇所のジャンルだけが示されるだけでした。

 

サーバが提供するサービスは、今回の競技課題のIoT車のステータスを確認したりだとかシステムの時間を変更するだとか、ファイルをアップロードするだとかそういうサービスです。このサービスに行き着くためにはbasic認証を通らなければなりません。

 

自分たちのチームはI2(?)の300点問題しか解けなかったです。

一番解けてるチームが多かったやつですね。

これは、/home/scuser/直下だかのbackdoorなるいかにもなディレクトリがあるので中身を確認します。

するとREADMEがあってcatなりで中身みるとpassword_is_backdoorみたいなことが書いてあります。同じディレクトリにもう一個なんかファイルがあった気がしますが忘れました。なんか中身がなくてファイル名で「これはデバック用ですよ」みたいなこと書いてあるだけのファイルだけだった気がする。

それで、passwd-とかindex_old.phpのページとかでユーザ一覧みるとbackdoorなるユーザが存在しているのが分かります。

さっきパスワードは教えてもらったので

$su backdoor

してパスワードにbackdoor入れるとログオン出来ます。

ユーザ名とパスワードが同じなのはパスワードが弱いので自分で適当なパスワードに変えてやります。

すると300点が手に入ります。

 

他の問題はhttp://サーバ名/admin/の中に入れないと話になりません。

adminのパスは"password"だったようです(同じ学校の別チームに聞いた)

まあ典型的な弱いパスワードですよね。

これに気づけると結構な得点を稼げると思います。

adminに入ってからはまずシステム時間を変えるページがあるのでそこでOSコマンドインジェクションして/var/www/html/の下のファイルの権限を777にしときます。

そしたら、.htpasswdの中身を書き換えて、adminのパスを変えます。多分これでI2のどれかの点が入ると思います。

 

他は、IoTCarのステータスを表示するstatus.phpがあってこれをadminのページから見ると表の一部でエラーを吐きます。ソース読むと、数値しか入らないところに直で文字列突っ込んでるのが分かります。これを直せば多分点が入ります。

他はインジェクションできるコードとかを直したり、p=ファイル名でファイル表示しちゃう感じのよくある脆弱性持ちのfile.phpを直したり、サーバの中身全部見れちゃうindex_old.phpとかいう危ないやつ消したり、index.htmlをubuntuのデフォページじゃなくてadminのあたりに飛ぶようにすればいいんじゃないんですかね?

ここら辺は競技時間中にやったことじゃないので合ってるかは知りません。

 

 

あと、競技終了後にいろいろ議論になってますが、サーバによってiotcarの実行ファイルがあったり無かったり、その実行ファイルの所有者はrootでiotcar.pyの中でsystemにコマンド投げて自分のユーザであるscuserにroot権限与えられちゃうってのはさすがにどうかと、今回優勝したチームは見事に当たりのサーバを引いて、開始30分でrootを取れたそうです。

多分rootが取れるのは運営側では意図してなかったと思います。

デフォでは/var/www/html/admin/の中のファイルはscuserには読み込み権限しか無く、所有者はwww-dataさんになっていてadminページからインジェクションするとこいつの権限でscuserに書き込み権限を与えることが出来ます。まあ当然rootは取れないはずです。

 

あと面白かったのは、127.0.0.1のどっかだかのポート(忘れた)でudp通信して/etc/iotcar/の中のデバイスを模したファイルに書き込むiotcar.pyスクリプト

これ最初の状態では構文エラーでて実行出来ませんでした。

何分だか経って運営側から修正されたコードが渡されました。が、これも正しく動きません。

まず、udpで受け取るデータは文字列になって届きます。それをそのまま数値と比較してるので、何度データ送りつけてもif文で弾かれて何も起きません。

次に、ファイルの開くモードが間違ってたりしてるので直します。

ここら辺は僕は直接触ってないので詳しく言えないですがそんな感じのことをしてやるとiotcarのとこのファイルにデータが書き込まれます。

これが問題なのか、仕様なのかは知りません。

結局これのバグ潰しをしたところで点が入る訳でも無かったようですね。

意味が解らない。

*1

 

まあそんな感じでした。

とにかくadminに入れなかったのが悔やまれるなぁって感じの大会でした。

*1:雰囲気から察するにスクリプトを運営側で一度もテストしていない??