戰(zhàn):從配置文件到內(nèi)存的密碼搜索指南)
1. 從一次真實(shí)的內(nèi)部安全演練說起上個(gè)月我們團(tuán)隊(duì)進(jìn)行了一次內(nèi)部紅藍(lán)對(duì)抗演練。我作為藍(lán)隊(duì)成員負(fù)責(zé)防守幾臺(tái)關(guān)鍵的Linux應(yīng)用服務(wù)器。演練開始沒多久監(jiān)控告警就響了——有一臺(tái)測(cè)試機(jī)的SSH登錄日志出現(xiàn)了異常。我立刻登錄上去排查在/var/log/auth.log里看到了大量來自內(nèi)網(wǎng)未知IP的失敗嘗試。這顯然是紅隊(duì)在嘗試橫向移動(dòng)。我當(dāng)時(shí)的第一個(gè)念頭不是去封IP而是立刻檢查這臺(tái)服務(wù)器上有沒有“遺留”的敏感文件。因?yàn)榻?jīng)驗(yàn)告訴我攻擊者一旦通過某種方式比如利用一個(gè)脆弱的Web應(yīng)用拿到了一個(gè)低權(quán)限的shell他們的首要目標(biāo)絕不是立刻提權(quán)而是翻箱倒柜尋找能讓他們通往其他系統(tǒng)的“鑰匙”——也就是各種配置文件、腳本、備份文件里明文存儲(chǔ)的賬號(hào)密碼。果然我在一個(gè)用于部署的deploy.sh腳本里發(fā)現(xiàn)了硬編碼的數(shù)據(jù)庫(kù)密碼在一個(gè)~/.bash_history文件里看到了帶-p參數(shù)的mysql命令記錄甚至在一個(gè)臨時(shí)日志文件里找到了某次調(diào)試時(shí)打印出的完整連接字符串。如果紅隊(duì)成員先我一步找到這些他們就能輕松登錄數(shù)據(jù)庫(kù)竊取數(shù)據(jù)甚至以此為跳板攻擊網(wǎng)絡(luò)中的其他機(jī)器。這次經(jīng)歷再次印證了一個(gè)老生常談卻又極易忽視的真理在Linux系統(tǒng)上敏感信息的泄露往往不是由于高深的技術(shù)漏洞而是源于運(yùn)維中的不良習(xí)慣和疏忽。無論是內(nèi)網(wǎng)滲透測(cè)試中的攻擊方還是日常運(yùn)維中的防守方掌握一套系統(tǒng)性的敏感文件查找方法都至關(guān)重要。對(duì)于安全研究人員和運(yùn)維工程師而言在Linux環(huán)境下定位潛在的賬號(hào)密碼泄露點(diǎn)是一項(xiàng)基礎(chǔ)且核心的技能。這不僅僅是“找密碼”更是理解應(yīng)用程序行為、梳理配置脈絡(luò)、進(jìn)行安全審計(jì)的過程。本文將從實(shí)戰(zhàn)角度出發(fā)拋開那些華而不實(shí)的自動(dòng)化工具依賴深入講解如何基于Linux系統(tǒng)本身的特點(diǎn)用手工結(jié)合命令的方式高效、精準(zhǔn)地完成這項(xiàng)任務(wù)。我們會(huì)從常見存儲(chǔ)位置、針對(duì)性搜索命令、歷史痕跡分析、到內(nèi)存與進(jìn)程中的密碼抓取形成一個(gè)完整的排查鏈路。無論你是想加固自己的服務(wù)器還是在授權(quán)范圍內(nèi)進(jìn)行安全評(píng)估這些方法都能提供直接的幫助。2. 理解敏感信息的常見藏身之處在開始“翻找”之前我們必須先知道去哪里找。Linux系統(tǒng)中的密碼和密鑰并不會(huì)像Windows的LSA Secrets那樣有一個(gè)統(tǒng)一的保險(xiǎn)庫(kù)。它們往往分散在以下幾個(gè)地方其存在通常都有合理的業(yè)務(wù)原因但也因此成為安全隱患。2.1 配置文件密碼的重災(zāi)區(qū)這是最直接、最普遍的存儲(chǔ)位置。許多應(yīng)用程序?yàn)榱俗詣?dòng)化運(yùn)行會(huì)將連接憑證寫入配置文件。用戶級(jí)配置在用戶家目錄下以點(diǎn)號(hào).開頭的隱藏文件是首要目標(biāo)。例如~/.ssh/包含id_rsa私鑰、known_hosts曾連接過的主機(jī)密鑰有時(shí)甚至?xí)衏onfig文件里明文寫有連接密碼雖然不推薦。~/.aws/credentials和config文件可能包含AWS的訪問密鑰和密鑰。~/.docker/config.json可能包含容器倉(cāng)庫(kù)的登錄憑證。~/.git-credentialsGit的憑據(jù)緩存文件。~/.bashrc,~/.bash_profile,~/.zshrc等這些shell初始化文件里有時(shí)會(huì)為了方便而直接導(dǎo)出環(huán)境變量如export DB_PASSWORD123456這是極其危險(xiǎn)的做法。~/.mysql_history,~/.psql_history等數(shù)據(jù)庫(kù)客戶端的命令歷史如果執(zhí)行過帶密碼的連接命令就會(huì)被記錄在此。系統(tǒng)級(jí)與應(yīng)用級(jí)配置位于/etc目錄下或應(yīng)用安裝目錄中。/etc目錄這是核心區(qū)域。像/etc/passwd和/etc/shadow需root權(quán)限存儲(chǔ)著系統(tǒng)用戶哈希但我們的目標(biāo)更多是應(yīng)用配置。例如/etc/mysql/my.cnf或/etc/mysql/debian.cnf中可能有數(shù)據(jù)庫(kù)密碼舊的FTP服務(wù)器配置/etc/vsftpd.confWeb應(yīng)用的配置文件如/etc/apache2/sites-available/下的某些conf文件可能包含數(shù)據(jù)庫(kù)連接信息。應(yīng)用目錄例如一個(gè)Web應(yīng)用根目錄下的config.php、application.yml、.env文件。特別是.env文件在框架如Laravel、Django中常用它本意是隔離環(huán)境變量但若權(quán)限設(shè)置不當(dāng)或誤提交到代碼庫(kù)就會(huì)導(dǎo)致密碼泄露。查找命令如find /var/www -name *.env -o -name *config*.php -o -name application*.yml 2/dev/null。注意直接搜索/etc下的所有文件包含“password”字符串可能會(huì)返回大量結(jié)果其中很多是注釋或示例。更有效的方法是結(jié)合對(duì)服務(wù)如mysql,postgresql,redis的了解定位其標(biāo)準(zhǔn)配置文件路徑。2.2 腳本文件自動(dòng)化背后的隱患Shell腳本、Python腳本、SQL腳本等是自動(dòng)化運(yùn)維的利器也常常是密碼的“陳列館”。為了在腳本中直接連接數(shù)據(jù)庫(kù)、調(diào)用API或遠(yuǎn)程執(zhí)行命令開發(fā)者常常圖省事將密碼以明文形式寫在腳本里。部署腳本(deploy.sh,update.sh)可能包含SCP、SSH、Ansible或數(shù)據(jù)庫(kù)的明文密碼。備份腳本(backup.sh)為了自動(dòng)備份數(shù)據(jù)庫(kù)到遠(yuǎn)程常出現(xiàn)mysqldump -u root -ppassword這樣的命令。定時(shí)任務(wù)腳本(cron job)在/etc/cron.*/目錄下或用戶crontab -l列出的任務(wù)中調(diào)用的腳本需要仔細(xì)檢查。查找技巧使用grep時(shí)不要只搜索password還要搜索pwd、pass、secret、key、token等常見變量名并且使用-r進(jìn)行遞歸-i進(jìn)行忽略大小寫。例如grep -r -i pass\|pwd\|secret /opt/scripts/ 2/dev/null。2.3 日志文件被遺忘的泄露現(xiàn)場(chǎng)日志的本意是記錄但常常記錄了不該記錄的東西。應(yīng)用程序在調(diào)試或報(bào)錯(cuò)時(shí)可能會(huì)將完整的連接字符串、請(qǐng)求參數(shù)包括密碼打印到日志中。Web服務(wù)器日志/var/log/apache2/access.log或/var/log/nginx/access.log中如果采用GET方式傳遞密碼極其錯(cuò)誤會(huì)在URL中明文顯示。錯(cuò)誤日志(error.log)中也可能包含配置信息或堆棧跟蹤里的敏感數(shù)據(jù)。應(yīng)用日志在/var/log/下或應(yīng)用自定義目錄中如/var/log/tomcat/、/home/app/logs/。查找最近修改過的、較大的日志文件。命令歷史之前提到的.bash_history是最典型的例子。但要注意如果用戶設(shè)置了HISTCONTROLignorespace并在命令前加空格該命令就不會(huì)被記錄。此外還可以檢查~/.sh_history,~/.zsh_history等。2.4 內(nèi)存與進(jìn)程運(yùn)行時(shí)密碼的提取這是進(jìn)階技術(shù)通常需要root權(quán)限。有些密碼永遠(yuǎn)不會(huì)落盤只存在于進(jìn)程的內(nèi)存空間里。例如一個(gè)啟動(dòng)了的MySQL服務(wù)進(jìn)程其內(nèi)存中必然持有連接數(shù)據(jù)庫(kù)的密碼或哈希一個(gè)通過ssh-agent緩存的私鑰密碼也存在于內(nèi)存中。進(jìn)程命令行參數(shù)使用ps auxfww或ps -ef命令查看進(jìn)程啟動(dòng)時(shí)的完整命令行。有時(shí)密碼會(huì)通過-p參數(shù)直接傳遞。例如一個(gè)過時(shí)的mysqld啟動(dòng)命令/usr/sbin/mysqld --usermysql --passwordMySuperSecretPass。進(jìn)程內(nèi)存轉(zhuǎn)儲(chǔ)使用gdbGNU調(diào)試器或/proc/$PID/mem接口可以附加到進(jìn)程并嘗試從其內(nèi)存空間中搜索字符串。這是一個(gè)更復(fù)雜、對(duì)系統(tǒng)有侵入性的操作必須在授權(quán)范圍內(nèi)謹(jǐn)慎進(jìn)行。一個(gè)相對(duì)簡(jiǎn)單的命令是使用strings工具處理進(jìn)程的內(nèi)存映射strings /proc/$PID/mem | grep -i pass。但更常見和專業(yè)的做法是使用像gcore生成核心轉(zhuǎn)儲(chǔ)文件然后用strings分析。3. 手工排查構(gòu)建你的搜索命令組合拳了解了目標(biāo)在哪下一步就是組織有效的搜索。完全依賴單一自動(dòng)化腳本可能會(huì)遺漏上下文或產(chǎn)生大量誤報(bào)。手工排查的核心思路是由面到點(diǎn)層層遞進(jìn)。3.1 初始偵察快速定位可疑文件首先獲得一個(gè)shell后無論什么權(quán)限先對(duì)環(huán)境有個(gè)整體了解。當(dāng)前用戶與權(quán)限idwhoamisudo -l查看當(dāng)前用戶能以root身份運(yùn)行哪些命令這本身可能就是個(gè)突破口。系統(tǒng)信息uname -acat /etc/*-release了解系統(tǒng)版本。運(yùn)行的服務(wù)netstat -tulpn或ss -tulpn查看開放端口和對(duì)應(yīng)進(jìn)程這能告訴你系統(tǒng)上跑了什么服務(wù)MySQL? Redis? PostgreSQL?從而明確重點(diǎn)搜索方向。查找有特殊權(quán)限或最近修改的文件find / -perm -4000 -type f 2/dev/null查找SUID文件提權(quán)可能。find / -perm -2000 -type f 2/dev/null查找SGID文件。find / -type f -mtime -7 2/dev/null查找最近7天內(nèi)修改過的文件。攻擊者上傳的工具或修改的配置可能在其中。find / -type f -name “*.bak” -o -name “*.old” -o -name “*.temp” 2/dev/null。備份文件、舊配置文件往往包含原始的、未加密的密碼。3.2 核心搜索基于內(nèi)容的精準(zhǔn)挖掘這是最關(guān)鍵的步驟。我們將使用find、grep、awk等命令的組合。基礎(chǔ)關(guān)鍵字搜索從根目錄開始搜索包含常見密碼關(guān)鍵詞的文件。注意這會(huì)比較慢且可能觸發(fā)大量權(quán)限錯(cuò)誤所以我們將錯(cuò)誤輸出重定向到/dev/null。# 搜索包含password, pass, pwd等關(guān)鍵詞的文件并顯示匹配行的前后幾行內(nèi)容 grep -r -n -i -B2 -A2 passw\|pwd\|secret\|key\|token /etc /home /opt /var 2/dev/null | head -100-B2 -A2參數(shù)可以顯示匹配行前后各2行的內(nèi)容這對(duì)于理解密碼的上下文比如是哪個(gè)變量、在哪個(gè)配置文件里非常有幫助。針對(duì)特定格式的搜索密碼有時(shí)會(huì)以特定格式出現(xiàn)。連接字符串搜索mysql://postgresql://jdbc:://user:pass。grep -r ://[^:]*:[^]* /home /opt 2/dev/nullBase64編碼看起來像亂碼的長(zhǎng)字符串可能是編碼后的密碼??梢运阉鹘Y(jié)尾的字符串或者用grep -E匹配Base64字符集。grep -r -E ([A-Za-z0-9/]{4})*([A-Za-z0-9/]{3}|[A-Za-z0-9/]{2})? /path/to/search 2/dev/null | head -20JSON或YAML格式搜索password:password:。grep -r -i \password\\s*: /path/to/search 2/dev/null檢查歷史與內(nèi)存命令歷史立即查看當(dāng)前shell的歷史以及所有可讀用戶的.bash_history。history # 當(dāng)前shell歷史 cat ~/.bash_history for user in $(ls /home); do echo History for $user ; cat /home/$user/.bash_history 2/dev/null | tail -50; done進(jìn)程信息ps auxfww | grep -E “(mysql|redis|postgres|ssh)” # 查看相關(guān)進(jìn)程的命令行 # 如果有root權(quán)限可以嘗試從進(jìn)程內(nèi)存中搜索字符串 # 例如找到MySQL的PID PID$(pgrep mysqld) if [ ! -z $PID ]; then strings /proc/$PID/environ | grep -i pass fi3.3 權(quán)限提升與深度搜索如果當(dāng)前用戶權(quán)限較低很多文件無法讀取。那么搜索的第一步可能變成了權(quán)限提升。利用找到的數(shù)據(jù)庫(kù)密碼嘗試登錄數(shù)據(jù)庫(kù)也許能在數(shù)據(jù)庫(kù)里找到其他系統(tǒng)的密碼例如某些應(yīng)用將配置存在數(shù)據(jù)庫(kù)里。或者利用找到的SSH私鑰嘗試連接其他服務(wù)器。這就是所謂的“橫向移動(dòng)”。在獲得更高權(quán)限尤其是root后搜索范圍將豁然開朗讀取所有用戶的家目錄grep -r -i “pass” /home/* 2/dev/null。檢查/etc/shadow雖然密碼是哈希值但弱密碼可以通過哈希碰撞或彩虹表破解??梢允褂胾nshadow工具結(jié)合john或hashcat進(jìn)行破解測(cè)試僅限授權(quán)測(cè)試。檢查內(nèi)存中的敏感信息使用/proc文件系統(tǒng)或工具如linpeas、LinEnum這些是自動(dòng)化腳本但原理是手工命令的集合進(jìn)行更全面的信息收集。4. 從攻擊者視角看防御如何讓你的密碼“隱身”了解了攻擊者如何尋找密碼我們就能更好地進(jìn)行防御。這不僅僅是安全人員的職責(zé)更是每一位系統(tǒng)管理員和開發(fā)者的必修課。4.1 配置管理杜絕明文存儲(chǔ)使用配置管理工具與密鑰庫(kù)將密碼、API密鑰等敏感信息從配置文件中徹底移除。使用如HashiCorp Vault、AWS Secrets Manager、Azure Key Vault等密鑰管理服務(wù)。在應(yīng)用啟動(dòng)時(shí)從這些服務(wù)動(dòng)態(tài)拉取憑據(jù)。環(huán)境變量對(duì)于簡(jiǎn)單場(chǎng)景可以使用環(huán)境變量。但要注意環(huán)境變量在ps命令中可能被看到通過/proc/$PID/environ且可能在日志中泄露。確保不將敏感信息打印到日志。配置文件權(quán)限如果必須使用配置文件將其權(quán)限設(shè)置為僅所有者可讀chmod 600 config.properties。并確保其所屬用戶和組正確。4.2 開發(fā)與運(yùn)維規(guī)范代碼審查將“硬編碼密碼/密鑰”作為代碼審查的高危項(xiàng)。使用預(yù)提交鉤子pre-commit hook掃描代碼中是否含有密碼模式。清理歷史記錄定期清理或妥善管理命令歷史。對(duì)于包含敏感信息的命令可以在其前面加空格如果HISTCONTROL設(shè)置了ignorespace或者直接unset HISTFILE再執(zhí)行命令但更好的做法是根本不在命令行中直接輸入密碼。最小權(quán)限原則運(yùn)行服務(wù)的賬戶如mysqlwww-data不應(yīng)該有讀取其他用戶家目錄或無關(guān)配置文件的權(quán)限。通過嚴(yán)格的用戶和文件權(quán)限控制即使某個(gè)服務(wù)被攻破也能將影響范圍限制在最小。4.3 日志與監(jiān)控日志脫敏確保應(yīng)用程序和中間件的日志配置中啟用了脫敏功能避免將密碼、令牌、身份證號(hào)等敏感信息寫入日志。文件完整性監(jiān)控使用工具如AIDE、Tripwire或Osquery監(jiān)控關(guān)鍵配置文件如/etc/passwd/etc/shadow Web應(yīng)用配置文件的變更并在發(fā)生未授權(quán)修改時(shí)告警。進(jìn)程監(jiān)控監(jiān)控異常進(jìn)程的創(chuàng)建特別是那些嘗試讀取/etc/shadow或大量掃描文件系統(tǒng)的進(jìn)程。5. 實(shí)戰(zhàn)案例一次完整的內(nèi)部排查模擬假設(shè)我們作為內(nèi)部安全員接到通知某臺(tái)Web服務(wù)器(192.168.1.10)可能因一個(gè)過時(shí)的Web框架版本存在漏洞而被初步入侵。我們需要登錄該服務(wù)器檢查是否存在敏感信息泄露并評(píng)估風(fēng)險(xiǎn)。步驟1初始連接與環(huán)境評(píng)估通過SSH使用已有賬號(hào)登錄。首先檢查當(dāng)前權(quán)限(id)發(fā)現(xiàn)是普通用戶webadmin。運(yùn)行sudo -l發(fā)現(xiàn)該用戶被允許以root身份運(yùn)行/usr/bin/systemctl restart apache2這是一個(gè)有價(jià)值的點(diǎn)但暫時(shí)用不上。先看看系統(tǒng)跑著什么ss -tulpn顯示有80Apache、3306MySQL、22SSH端口開放。步驟2針對(duì)性搜索Web相關(guān)配置既然有Apache和MySQL重點(diǎn)搜索相關(guān)配置和代碼。# 查找網(wǎng)站根目錄通常Apache默認(rèn)在/var/www/html find /var/www -type f -name “*.php” -o -name “*.env” -o -name “config*.php” -o -name “*.yml” -o -name “*.yaml” 2/dev/null | head -20發(fā)現(xiàn)路徑/var/www/html/wordpress/wp-config.php。這是WordPress的配置文件經(jīng)典的存在數(shù)據(jù)庫(kù)密碼的地方。cat /var/www/html/wordpress/wp-config.php | grep -A2 -B2 “DB_PASSWORD”果然找到了define(DB_PASSWORD, Wpss123456);。步驟3利用找到的密碼進(jìn)行橫向試探嘗試用這個(gè)密碼連接本機(jī)的MySQL。mysql -u wordpressuser -pWpss123456 -h 127.0.0.1成功登錄。在MySQL中可以查看是否有其他數(shù)據(jù)庫(kù)或表存儲(chǔ)了更多信息。執(zhí)行show databases;發(fā)現(xiàn)除了wordpress庫(kù)還有一個(gè)app_config庫(kù)。進(jìn)入該庫(kù)發(fā)現(xiàn)一張表service_credentials里面竟然明文存儲(chǔ)了訪問內(nèi)網(wǎng)另一臺(tái)Redis緩存服務(wù)器(192.168.1.20)和一臺(tái)文件服務(wù)器(192.168.1.30)的密碼。步驟4擴(kuò)大搜索范圍退出MySQL?,F(xiàn)在有了新的目標(biāo)。同時(shí)繼續(xù)在本地搜索。# 檢查webadmin用戶的歷史和文件 cat ~/.bash_history ls -la ~/.ssh/ cat ~/.ssh/config 2/dev/null # 搜索備份腳本 find / -type f -name “*.sh” -exec grep -l “pass\|pwd” {} \; 2/dev/null在/opt/scripts/backup_db.sh中發(fā)現(xiàn)使用了mysqldump -u root -pRootDBPass!#的命令。這又是一個(gè)高權(quán)限的數(shù)據(jù)庫(kù)密碼。步驟5評(píng)估與報(bào)告至此我們發(fā)現(xiàn)了至少三處嚴(yán)重的明文密碼泄露WordPress配置文件中的數(shù)據(jù)庫(kù)密碼已導(dǎo)致可訪問app_config庫(kù)。app_config庫(kù)中存儲(chǔ)的其他內(nèi)網(wǎng)服務(wù)密碼導(dǎo)致內(nèi)網(wǎng)橫向移動(dòng)風(fēng)險(xiǎn)劇增。備份腳本中的MySQL root密碼導(dǎo)致數(shù)據(jù)庫(kù)完全失控。根本原因開發(fā)人員將生產(chǎn)數(shù)據(jù)庫(kù)密碼硬編碼在配置文件中另一個(gè)應(yīng)用將多個(gè)服務(wù)的憑證以明文形式存在業(yè)務(wù)數(shù)據(jù)庫(kù)里運(yùn)維人員在腳本中直接使用root密碼。防御措施完全缺失。建議立即更改所有涉及的服務(wù)密碼。將WordPress的wp-config.php文件權(quán)限設(shè)置為640所有者設(shè)為root組設(shè)為Web服務(wù)器用戶。廢除備份腳本中的明文密碼改用mysql_config_editor設(shè)置登錄路徑或從安全存儲(chǔ)中獲取。徹底改造app_config庫(kù)移除明文密碼引入統(tǒng)一的密鑰管理服務(wù)。對(duì)所有服務(wù)器進(jìn)行一輪類似的敏感信息掃描。通過這個(gè)模擬案例你可以看到一次簡(jiǎn)單的查找如何像剝洋蔥一樣層層深入地揭示出整個(gè)系統(tǒng)中脆弱的安全實(shí)踐。它遠(yuǎn)不止是執(zhí)行幾條grep命令而是一個(gè)結(jié)合了系統(tǒng)知識(shí)、應(yīng)用理解、邏輯推理和持續(xù)驗(yàn)證的過程。無論是攻擊還是防御對(duì)這套流程的熟練掌握都價(jià)值連城。