# Pkg:Web:616pts  
Shou hoards a flag in a NodeJS binary and he thinks it is safe. Prove him
wrong.  
[Source Code](pkg1.zip)

# Solution  
zipファイルが配られる。  
解凍するとlinux、macos、winの実行ファイルが出現する。  
自前のwin機でアイコンを見ると、どうやらnodeで開発されたexeのようだ。  
実行すると`App listening on port 10001`と10001番ポートでHTTPサーバが立ち上がる。  
アクセスすると以下のようなページが表示された。  
![image1.png](images/image1.png)  
ウサギさんが跳ねており、右側にEncrypted Flagが表示されている。  
以下のような文字列であった。  
```text  
V44FTEScskUnyxOlSRtWiWqrY6tGOPYtxvNOZxx6rxQD7BAJJncc86enn5FYp53hJDdbCcJDsudy39grhL7DAlUe+NPOgV+j7BN1igZRE9C+y5kORoyKF7AP0H5oErn6HdvdUK9f3ANfWJk9EzcB3M7MhcyC/zmL/xZ4Bf4VmVVicZCVDEteYCNVPA8vr0olphXJIEkBmhXG3wy9OrKTkh4VonqSjMvlBvqWELJlsWUdgvKVht2yHVErwF1K27xf  
```  
Real Flagは取得できないのでexeを解析する。  
問題名から[pkg](https://github.com/vercel/pkg)のようだ。  
梱包されたパッケージはSnapshot filesystemにアクセスでき、そこに各種ファイルが配置されるらしい。  
天才チームメンバが「[Sunshine CTF 2019 - The Whole
Pkg](https://fireshellsecurity.team/sunshine-the-whole-pkg/)」なる類題を見つけてくれた。  
バイナリファイルの`C:\\\snapshot`を書き換えることで、エントリーポイントをローカルのjsファイルに差し替えることができるらしい。  
書き換えるためのパスを知るために、grepをかける。  
```bash  
$ strings binaryexpress-win.exe | grep snapshot  
~~~  
{"C:\\\snapshot\\\flag1\\\server.js":{"0":[0,2112],"3":[2112,119]},"C:\\\snapshot\\\flag1\\\package.json":{"1":[2231,436],"3":[2667,119]},"C:\\\snapshot\\\flag1\\\views\\\flag.ejs":{"1":[2786,5943],"3":[8729,120]},"C:\\\snapshot\\\flag1\\\node_modules\\\ejs\\\package.json":{"1":[8849,896],"3":[9745,119]},"C:\\\snapshot\\\flag1\\\node_modules\\\ejs\\\lib\\\ejs.js":{"0":[9864,20904],"1":[30768,27481],"3":[58249,121]},"C:\\\snapshot\\\flag1\\\node_modules\\\express\\\package.json":{"1":[58370,2623],"3":[60993,120]},"C:\\\snapshot\\\flag1\\\node_modules\\\express\\\index.js":{"0":[61113,568],"1":[61681,224],"3":[61905,119]},"C:\\\snapshot\\\flag1\\\node_modules\\\node-
rsa\\\package.json":{"1":[62024,863],"3":[62887,119]},"C:\\\snapshot\\\flag1\\\node_modules\\\node-
rsa\\\src\\\NodeRSA.js":{"0":[63006,11856],"1":[74862,13824],"3":[88686,121]},"C:\\\snapshot\\\flag1\\\private_key.der":{"1":[88807,345],"3":[89152,119]},"C:\\\snapshot\\\flag1"  
~~~  
"C:\\\snapshot\\\flag1\\\node_modules\\\color-
name":{"2":[3096728,27],"3":[3096755,117]},"C:\\\snapshot\\\flag1\\\node_modules\\\filelist\\\node_modules":{"2":[3096872,31],"3":[3096903,117]},"C:\\\snapshot\\\flag1\\\node_modules\\\iconv-
lite\\\encodings\\\tables":{"2":[3097020,126],"3":[3097146,117]}}  
"C:\\\snapshot\\\flag1\\\server.js"  
```  
今回は`C:\\\snapshot\\\flag1\\\server.js`の`C:\\\snapshot`を`C:\\\snapshoo`に編集し、ローカルに作成した`C:\snapshoo\flag1\server.js`を読み込ませる。  
本来の`C:\snapshot\flag1\server.js`を読み取ってしまえばフラグが書かれていると考え、以下のようなserver.jsを作成した。  
```js  
const fs = require("fs");  
var data =
fs.readFileSync("C:\\\snapshot\\\flag1\\\server.js").toString("utf8");  
console.log(data);  
```  
エントリーポイントを書き換えた`binaryexpress-win_snapshoo.exe`を実行すると以下の結果が得られた。  
```  
>binaryexpress-win_snapshoo.exe  
source-code-not-available  
```  
どうやらソースは見せてくれないようだ。  
復元が難しいため、grep結果より他のファイルを調査すると`C:\snapshot\flag1\private_key.der`が存在することがわかる。  
これを読み取りEncrypted Flagを復号すればよい。  
以下の通りserver.jsを書き換える。  
```js  
const fs = require("fs");  
//var data =
fs.readFileSync("C:\\\snapshot\\\flag1\\\server.js").toString("utf8");  
var data =
fs.readFileSync("C:\\\snapshot\\\flag1\\\private_key.der").toString("hex");  
console.log(data);  
```  
実行すると次の通りになる。  
```  
>binaryexpress-win_snapshoo.exe  
30820155020100300d06092a864886f70d01010105000482013f3082013b020100024100986676bc7f0f74451ba334cda8789af88b023c683b1f8b6dd6e0266edb7e1dd2f2bbc39e4d1b0d42cfc5cbb2f4538c2cb7654b86076756e8f10183fb4054d2f5020301000102410084c155135457a1000658404a1a449d327edcfec40924ac6f8d2b8b2f2c728b04f6f103d28a203ec367951752097243192a6d0ad6f9eef317cea0fdc36202c9ed022100eae770f32c77135461aa7d5ada3d14b2670475984c5354b7eff06602ed80690b022100a616383d8d19faad64d14ec99a6ba589b02353078d4db2b110e235d67edd33ff0220041e4ca7a6c6ebaad60f84251ca067857d32e1d0eabda745964a53af877471e30221008a5a1e155ff21138d9afe602d8a8ed67aa1b72f1ea8a9bdd16246a16b8ed897f022049beb187600910cebb9bcc6ba9be94d54dec76aba0ffdbb5ee696595aced7539  
```  
ファイルのhexが得られたため適当にhex2binして、private_key.derに戻してやればよい。  
derをそのまま読み込んでも復号可能だと思われるが、扱いやすいpemにする。  
```bash  
$ openssl rsa -in private_key.der -inform DER -out private_key.pem -outform
PEM  
writing RSA key  
$ cat private_key.pem  
\-----BEGIN RSA PRIVATE KEY-----  
MIIBOwIBAAJBAJhmdrx/D3RFG6M0zah4mviLAjxoOx+LbdbgJm7bfh3S8rvDnk0b  
DULPxcuy9FOMLLdlS4YHZ1bo8QGD+0BU0vUCAwEAAQJBAITBVRNUV6EABlhAShpE  
nTJ+3P7ECSSsb40riy8scosE9vED0oogPsNnlRdSCXJDGSptCtb57vMXzqD9w2IC  
ye0CIQDq53DzLHcTVGGqfVraPRSyZwR1mExTVLfv8GYC7YBpCwIhAKYWOD2NGfqt  
ZNFOyZprpYmwI1MHjU2ysRDiNdZ+3TP/AiAEHkynpsbrqtYPhCUcoGeFfTLh0Oq9  
p0WWSlOvh3Rx4wIhAIpaHhVf8hE42a/mAtio7WeqG3Lx6oqb3RYkaha47Yl/AiBJ  
vrGHYAkQzrubzGupvpTVTex2q6D/27XuaWWVrO11OQ==  
\-----END RSA PRIVATE KEY-----  
```  
あとは暗号文を復号するだけなので、`node-rsa`を用いて以下のようなプログラムsolver.jsを作成する。  
```js  
const NodeRSA = require("node-rsa");

const key = new NodeRSA(`  
\-----BEGIN RSA PRIVATE KEY-----  
MIIBOwIBAAJBAJhmdrx/D3RFG6M0zah4mviLAjxoOx+LbdbgJm7bfh3S8rvDnk0b  
DULPxcuy9FOMLLdlS4YHZ1bo8QGD+0BU0vUCAwEAAQJBAITBVRNUV6EABlhAShpE  
nTJ+3P7ECSSsb40riy8scosE9vED0oogPsNnlRdSCXJDGSptCtb57vMXzqD9w2IC  
ye0CIQDq53DzLHcTVGGqfVraPRSyZwR1mExTVLfv8GYC7YBpCwIhAKYWOD2NGfqt  
ZNFOyZprpYmwI1MHjU2ysRDiNdZ+3TP/AiAEHkynpsbrqtYPhCUcoGeFfTLh0Oq9  
p0WWSlOvh3Rx4wIhAIpaHhVf8hE42a/mAtio7WeqG3Lx6oqb3RYkaha47Yl/AiBJ  
vrGHYAkQzrubzGupvpTVTex2q6D/27XuaWWVrO11OQ==  
\-----END RSA PRIVATE KEY-----  
`);

const encrypted =
"V44FTEScskUnyxOlSRtWiWqrY6tGOPYtxvNOZxx6rxQD7BAJJncc86enn5FYp53hJDdbCcJDsudy39grhL7DAlUe+NPOgV+j7BN1igZRE9C+y5kORoyKF7AP0H5oErn6HdvdUK9f3ANfWJk9EzcB3M7MhcyC/zmL/xZ4Bf4VmVVicZCVDEteYCNVPA8vr0olphXJIEkBmhXG3wy9OrKTkh4VonqSjMvlBvqWELJlsWUdgvKVht2yHVErwF1K27xf";

const decrypted = key.decrypt(encrypted, "utf8");  
console.log("flag: ", decrypted);  
```  
実行する。  
```bash  
$ node solver.js  
flag: we{32e0f460-710f-4a05-b716-39d1acc3a387@jU3tGue$31t}  
```  
flagが得られた。

## we{32e0f460-710f-4a05-b716-39d1acc3a387@jU3tGue$31t}

Original writeup
(https://github.com/satoki/ctf_writeups/tree/master/WeCTF_2022/Pkg).