Firmadyne `getArch.sh` === --- ###### tags: `firmadyne` `security` 本篇為 firmadyne `getArch.sh` Trace 紀錄 --- **目錄** [TOC] # /scripts/getArch.sh ```shell==3 set -e set -u ``` 參考: http://www.ruanyifeng.com/blog/2017/11/bash-set.html - `set -e`: 只要腳本執行發生錯誤就停下 - `set -u`: 遇到沒定義過的變數就當錯誤 --- ```shell==6 if [ -e ./firmadyne.config ]; then source ./firmadyne.config elif [ -e ../firmadyne.config ]; then source ../firmadyne.config else echo "Error: Could not find 'firmadyne.config'!" exit 1 fi ``` 先執行一次 `firmadyne.config` --- ```shell==15 function getArch() { if (echo ${FILETYPE} | grep -q "MIPS64") then ARCH="mips64" elif (echo ${FILETYPE} | grep -q "MIPS") then ARCH="mips" elif (echo ${FILETYPE} | grep -q "ARM64") then ARCH="arm64" elif (echo ${FILETYPE} | grep -q "ARM") then ARCH="arm" elif (echo ${FILETYPE} | grep -q "Intel 80386") then ARCH="intel" elif (echo ${FILETYPE} | grep -q "x86-64") then ARCH="intel64" elif (echo ${FILETYPE} | grep -q "PowerPC") then ARCH="ppc" else ARCH="" fi } ``` echo `${FILETYPE}` 變數,並用 grep 抓取關鍵字 以有沒有關鍵字來判斷 ARCH 是什麼 --- ```shell==42 function getEndian() { if (echo ${FILETYPE} | grep -q "LSB") then END="el" elif (echo ${FILETYPE} | grep -q "MSB") then END="eb" else END="" fi } ``` echo `${FILETYPE}` 變數,並用 grep 抓取關鍵字 以有沒有關鍵字來判斷 END(endian) 是什麼 --- ```shell==54 INFILE=${1} BASE=$(basename "$1") IID=${BASE%.tar.gz} ``` 依據官方示範使用這個腳本的方式 `./scripts/getArch.sh ./images/1.tar.gz` `${INFILE}` 為 `./images/1.tar.gz` `${BASE}` 為 `1.tar.gz` `${IID}` 為 `1` Line 55 basename 指令只抓取檔名,去掉前面路徑的部分 Line 56 `${A%B}` shell 會去掉參數 A 中,右邊最短符合 B 的 pattern 參考: https://www.itread01.com/content/1541066526.html --- ```shell=58 mkdir -p "/tmp/${IID}" ``` 創目錄 `/tmp/1` --- ```shell==60 set +e FILES="$(tar -tf $INFILE | grep -e "/busybox\$") " FILES+="$(tar -tf $INFILE | grep -E "/sbin/[[:alpha:]]+")" FILES+="$(tar -tf $INFILE | grep -E "/bin/[[:alpha:]]+")" set -e ``` `set -e` 是 只要腳本執行發生錯誤就停下,而 `+e` 就是取消這功能 `tar -tf $INFILE` 查看 `$INFILE` tar 包中的東西 FILES 為 - 以 /busybox 結尾的檔案 - 是 /sbin/... 的檔案 - 是 /bin/... 的檔案 `grep` 參數 `-e` 跟 `-E` 差別可看 http://benjr.tw/97395 --- ```shell==66 for TARGET in ${FILES} do SKIP=$(echo "${TARGET}" | fgrep -o / | wc -l) tar -xf "${INFILE}" -C "/tmp/${IID}/" --strip-components=${SKIP} ${TARGET} TARGETLOC="/tmp/$IID/${TARGET##*/}" if [ -h ${TARGETLOC} ] || [ ! -f ${TARGETLOC} ] then continue fi FILETYPE=$(file ${TARGETLOC}) echo -n "${TARGET}: " getArch getEndian if [ -n "${ARCH}" ] && [ -n "${END}" ] then ARCHEND=${ARCH}${END} echo ${ARCHEND} psql -d firmware -U firmadyne -h 127.0.0.1 -q -c "UPDATE image SET arch = '$ARCHEND' WHERE id = $IID;" rm -fr "/tmp/${IID}" exit 0 else echo -n ${ARCH} echo ${END} fi done ``` - `--strip-components` 參考 https://serverfault.com/questions/330127/tar-remove-leading-directory-components-on-extraction Line 66 for in loop 以空白或換行切割 `${FILE}` Line 68 分段解釋 - 首先 echo 出 `${TARGET}` - `fgrep -o /` -o 只輸出符合 pattern 的部分,並一次輸出一行 - `wc -l` 算輸出有幾行 所以這個組合技就是算這個 `${TARGET}` 有幾個 `/` 的啦 Line 69 從 `${INFILE}` extarct 出 `${TARGET}` 存到 `/tmp/${IID}`,且將前面的路徑全省略 例如說 `${TARGET}` 為 `/bin/su` 此指令 extarct 出此 file 存到 `/tmp/1/su` (假設 `${IID}` 為 1) Line 70 `${TARGETLOC}` 接續上面的例子就會是 `/tmp/1/su` `${variable##pattern}` 去掉 variable 中左邊最長的 match pattern Line 72 ~ 74 判斷如下 - `-h file`: True if file exists and is a symbolic link. - `-f file`: True if file exists and is a regular file. 總之確保 `${TARGETLOC}` 是正常檔案,不是符號連結後,繼續執行 Line 77 file command 用來查看 file type Line 80 81 用 file 的輸出來判斷 ARCH 跟 END Line 83 判斷如下 - `-n string`: True if the length of string is non-zero. 總之整體簡單來說,就是用 `/bin` `/sbin` 底下通常放執行檔的特性 用 file 指令來抓任意一個執行檔的 Architecture 跟 Endian 資訊 並存回資料庫中