#!/bin/bash ##################################################################### # # Fortify SCA FPR파일 분석 스크립트 # # 이 스크립트는 FPR파일을 분석하여 아래의 파일을 출력한다. # 1. CSV포맷의 요약,상세 리포트 # 2. TXT포맷의 Suppressed된 취약점의 IID 리스트 # # 윈도우에서 실행 시: # bash -c "./fpr_report.sh webgoat.fpr" # # by 이존석(hasu0707@esvali.com) # ##################################################################### DEBUG_ON=1 VERSION=0.2 FILTER_SET="Security Auditor View" #FILTER_SET="Quick View" WIN_MINGW_DIR="/cygdrive/c/PortableApps/cmd_cygwin_x86_64" FPR_TMP_DIR=./fpr_tmp REPORT_TEMPLATE=./my_report_template.xml SUPPRESSED_LIST_SUFFIX=suppressed_list.txt TMP_FILE1=./tmpfile.txt ##################################################################### # # 사용방법 출력 # ##################################################################### func_usage() { echo "$0 ver.${VERSION}" echo echo "usage: $0 <FPR file>" } ##################################################################### # # 초기화 # $1 : FPR 파일명 # ##################################################################### func_init() { if [ ${DEBUG_ON} -eq 1 ] then echo ">> func_init()" fi if [ -z "${WINDIR}" ]; then IS_WINDOWS=0 else IS_WINDOWS=1 fi if [ ${IS_WINDOWS} -eq 1 ]; then DEVNULL=null.dev WINCMD="/cygdrive/c/Windows/System32/cmd.exe /C" FORTIFY_HOME="/cygdrive/c/Program Files/Fortify/Fortify_SCA_and_Apps_18.10" REPORT_GENERATOR="ReportGenerator.bat" PATH=${FORTIFY_HOME}/bin:${WIN_MINGW_DIR}/bin:${PATH} else DEVNULL=/dev/null WINCMD="" FORTIFY_HOME="/opt/Fortify/Fortify_SCA_and_Apps_18.20" REPORT_GENERATOR="ReportGenerator" PATH=${FORTIFY_HOME}/bin:${PATH} fi BUILD_ID=$(basename $1 .fpr) } ##################################################################### # # 필요한 유틸리티가 있는지 검사 # ##################################################################### func_check_utils() { if [ ${DEBUG_ON} -eq 1 ] then echo ">> func_check_utils()" fi local IS_EXIT=0; UTILNAMES=( "xmllint" "unzip" "sed" "basename") # 윈도우 유틸리티 체킹 if [ ${IS_WINDOWS} -eq 1 ]; then if [ ! -e ${WIN_MINGW_DIR}/bin/xmllint ] || [ ! -e ${WIN_MINGW_DIR}/bin/unzip ] || [ ! -e ${WIN_MINGW_DIR}/bin/sed ] || [ ! -e ${WIN_MINGW_DIR}/bin/basename ]; then echo "ERROR: ${WIN_MINGW_DIR} not found !" IS_EXIT=1 fi if [ ${IS_EXIT} -ne 0 ]; then exit 1 fi return fi # 리눅스 유틸리티 체킹 for LOOP1 in "${UTILNAMES[@]}" do which ${LOOP1} > ${DEVNULL} if [ $? -ne 0 ]; then echo "ERROR: ${LOOP1} not found !" IS_EXIT=1 fi done # ReportGenerator 체크 if [ ! -e ${FORTIFY_HOME}/bin/${REPORT_GENERATOR} ]; then echo "ERROR: ${REPORT_GENERATOR} not found !" IS_EXIT=1 fi # Fortify Report Template 체크 if [ ! -e ${REPORT_TEMPLATE} ]; then echo "ERROR: ${REPORT_TEMPLATE} not found !" IS_EXIT=1 fi # 없는 유틸리티가 있으면 스크립트 종료 if [ ${IS_EXIT} -ne 0 ]; then exit 1 fi unset UTILNAMES } ##################################################################### # # 임시 및 불필요한 파일 삭제 # ##################################################################### func_clean() { if [ ${DEBUG_ON} -eq 1 ] then echo ">> func_clean()" fi if [ ${IS_WINDOWS} -eq 1 ]; then rm -f ${DEVNULL} fi rm -rf ${FPR_TMP_DIR} rm -f ${TMP_FILE1} rm -f ${BUILD_ID}.xml } ##################################################################### # # FPR파일 unzip # $1 : fpr 파일명 # ##################################################################### func_unzip() { if [ ${DEBUG_ON} -eq 1 ] then echo ">> func_unzip()" fi if [ -d ${FPR_TMP_DIR} ] then rm -rf ${FPR_TMP_DIR} fi mkdir ${FPR_TMP_DIR} unzip $1 -d ${FPR_TMP_DIR} audit.fvdl audit.xml filtertemplate.xml &> ${DEVNULL} } ##################################################################### # # FPR파일에서 Suppressed된 취약점들의 IID를 뽑아서 저장한다. # $1 : suppressed 목록이 기록될 파일명 # ##################################################################### func_write_suppressed_list() { local S_COUNT=1 local RET_VAL=0 if [ ${DEBUG_ON} -eq 1 ] then echo ">> func_write_suppressed_list()" fi rm -f ${1} while [ ${RET_VAL} -eq 0 ] do xmllint \ --encode UTF-8 --nowarning --noblanks \ --xpath "//*[local-name()='Audit']/*[local-name()='IssueList']/*[local-name()='Issue'][${S_COUNT}]/@instanceId" \ ./fpr_tmp/audit.xml \ >> ${1} 2> ${DEVNULL} RET_VAL=$? if [ ${RET_VAL} -eq 0 ] then S_COUNT=$((S_COUNT + 1)) fi echo >> ${1} done # 불필요한 문자열 및 빈줄 삭제 sed -i "s/ instanceId=\"//g" ${1} sed -i "s/\"$//g" ${1} sed -i "/^$/d" ${1} # Suppressed된 갯수 출력 if [ ${DEBUG_ON} -eq 1 ] then echo ">> suppressed count: $((S_COUNT - 1))" fi return $((S_COUNT - 1)) } ##################################################################### # # ReportGenerator를 사용하여 XML 리포트를 뽑는다. # $1 : 입력 FPR 파일명 # $2 : 출력 XML 파일명 # ##################################################################### func_reportgenerator() { if [ ${DEBUG_ON} -eq 1 ] then echo ">> func_reportgenerator()" fi ${WINCMD} "${REPORT_GENERATOR}" \ -format xml \ -template ${REPORT_TEMPLATE} \ -filterSet "${FILTER_SET}" \ -showSuppressed -source $1 -f $2 } ##################################################################### # # ReportGenerator로 만든 XML을 파싱하여 상세 CSV 리포트를 만든다 # $1 : 입력 XML 파일명 # $2 : 출력 CSV 파일명 # ##################################################################### func_xml_to_csv_detail() { if [ ${DEBUG_ON} -eq 1 ] then echo ">> func_xml_to_csv_detail()" fi xmllint --encode UTF-8 --xpath \ "/ReportDefinition/ReportSection[3]/SubSection[2]/IssueListing/Chart/GroupingSection/Issue/@iid|//Folder|//Kingdom|//Category|//Primary/FilePath|//Primary/LineStart" \ $1 > ${TMP_FILE1} sed -i \ -e "s/<\/LineStart>/\n/g" -e "s/<LineStart>//g" \ -e "s/<\/Category>/,/g" -e "s/<Category>//g" \ -e "s/<\/Folder>/,/g" -e "s/<Folder>//g" \ -e "s/<\/Kingdom>/,/g" -e "s/<Kingdom>//g" \ -e "s/<\/FilePath>/,/g" -e "s/<FilePath>//g" \ -e "s/ iid=\"//g" -e "s/<>//g" \ -e 's/\"/,/g' \ ${TMP_FILE1} echo "IID,CATEGORY,FOLDER,KINGDOM,FILE_PATH,LINE_NO" > $2 cat ${TMP_FILE1} >> $2 rm -f ${TMP_FILE1} } ##################################################################### # # ReportGenerator로 만든 XML을 파싱하여 요약 CSV 리포트를 만든다 # $1 : 입력 XML 파일명 # $2 : 출력 CSV 파일명 # ##################################################################### func_xml_to_csv_summary() { if [ ${DEBUG_ON} -eq 1 ] then echo ">> func_xml_to_csv_summary()" fi xmllint --encode UTF-8 --xpath \ "/ReportDefinition/ReportSection[1]/SubSection[2]/IssueListing/Chart/GroupingSection/groupTitle" \ $1 > ${TMP_FILE1} echo >> ${TMP_FILE1} xmllint --encode UTF-8 --xpath \ "/ReportDefinition/ReportSection[1]/SubSection[2]/IssueListing/Chart/GroupingSection/@count" \ $1 >> ${TMP_FILE1} sed -i \ -e "s/<\/groupTitle>/,/g" -e "s/<groupTitle>//g" \ -e 's/ count=\"//g' -e 's/\"/,/g' -e "s/,$//g" \ ${TMP_FILE1} cat ${TMP_FILE1} > $2 rm -f ${TMP_FILE1} } ##################################################################### # # main # ##################################################################### # 명령행 인수가 없으면 사용방법 출력하고 끝냄 if [ $# -lt 1 ]; then func_usage exit 3 fi # FPR 파일 존재 여부 체크 if [ ! -e ${1} ]; then echo "ERROR: ${1} not found !" func_usage exit 2 fi func_init ${1} func_check_utils func_unzip ${1} func_write_suppressed_list ${BUILD_ID}_${SUPPRESSED_LIST_SUFFIX} func_reportgenerator ${1} ${BUILD_ID}.xml func_xml_to_csv_detail ${BUILD_ID}.xml ${BUILD_ID}_detail.csv func_xml_to_csv_summary ${BUILD_ID}.xml ${BUILD_ID}_summary.csv func_clean