2016 AIS3 Pre-exam Write-up

前言

well,這算是我第一次認真玩的ctf吧ww 基本上都是邊打邊學的,智商不夠打得好累(#

先附上成果:

實力很廢所以成果也很廢QQ

(PS. 排名應該並非最終名次,實際名次大概比這稍微低一點)

Misc

misc1

ais3{2016_^_^_hello_world!}

直接給flag不解釋。

misc2

有一個叫UNPACK_ME的不知名檔案 16進制打開是長這樣

00000000: 375a bcaf 271c 0003 97fa 34cd bf75 0400  7Z..'.....4..u..
00000010: 0000 0000 2400 0000 0000 0000 0f6d 9320  ....$........m.
00000020: 7fc7 1bd6 3232 8b34 c4a3 bda1 35ff 1bfe  ....22.4....5...
00000030: 7606 9e02 4b37 0f8a 77d6 0fba c7d4 3364  v...K7..w.....3d
00000040: 71f1 cc64 a788 ee07 1d2e 4e63 da79 3394  q..d......Nc.y3.

一開頭看到7Z,很明顯就知道是7zip壓縮檔 但嘗試一下發現用7zip打不開,google一下發現,真正的 7z header 是 7z (377a bcaf) 而非 7Z (375a bcaf) 於是把header改掉後嘗試打開:

第一個檔案(tArdCNLMPjLxqs5USx3T)一樣把header改成正確,直接用 7zip 開啟,發現有密碼 於是合理猜測,第二個檔案(UDJRRDVRJyfbWBxEMLEX)的檔名,就是第一個檔案的密碼 然後,真的就是呢ww

順利開啟後:

第一個檔案再次把header改成正確 而 secret.txt 裡面擺的就是第一個檔案的解壓縮密碼 解壓縮後… 第一個檔案再次把header改成正確 而secret.txt裡面擺的就是第一個檔案的解壓縮密碼 (loop…) 現在開始,執行數百個一樣的動作!!!

於是寫了一個小程式幫忙解壓縮(需配上cmd版的7zip來運作) 這code我寫好久QQ 不要問我為甚麼不用shell或py,因為我很少用他們rrr 該開始認真學了orz

#include <sys/types.h>
#include <stdio.h>
#include <dirent.h>
#include <errno.h>
#include <vector>
#include <string>
#include <iostream>
#include <fstream>
using namespace std;

int getdir(string dir, vector<string> &files);

int main()
{
    fstream fin;
    char secret[50];

    for(int i=0;i<1000;i++){
        fin.open("./x/secret.txt",ios::in);
        fin.getline(secret,sizeof(secret),'\n');
        fin.close();
        
        string dir = string("./x");
        vector<string> files = vector<string>();
        getdir(dir, files);
        
        char filename[50];
        if(files[2]=="secret.txt")
            strcpy(filename,files[3].c_str());
        else if(files[3]!="flag.txt")
            strcpy(filename,files[2].c_str());
        
        FILE *cfPtr;
        unsigned char b[] = {0x37, 0x7a};
        char path[25]="./x/";
        for(int i=4;i<25;i++){
            path[i]=filename[i-4];
        }
        cfPtr = fopen(path, "rb+");
        fwrite(b, sizeof(b), 1, cfPtr);
        fclose(cfPtr);
        
        char cmd[50];
        sprintf(cmd, "7za x ./x/%s -o./x/ -p%s -y", filename,secret); 
        cout << cmd;
        system(cmd);
        char path2[]="./x/";
        strcat(path2,filename);
        remove(path2);
        cout << "remove" << path2;
    }
    return 0;
}
int getdir(string dir, vector<string> &files){
    DIR *dp;
    struct dirent *dirp;
    if((dp = opendir(dir.c_str())) == NULL){
        cout << "Error(" << errno << ") opening " << dir << endl;
        return errno;
    }
    while((dirp = readdir(dp)) != NULL){
        files.push_back(string(dirp->d_name));
    }
    closedir(dp);
    return 0;
}

最後會解出一個 flag.txt檔 打開就是Flagais3{7zzZzzzZzzZzZzzZiP}

misc3

不會解,略過ww

Crypto

crypto1

XOR 加密感覺很基本啊 但是我太混完全沒研究過 於是放棄ㄏㄏ

crypto2

完全只靠Web技巧過關的 完全只靠Web技巧過關的 完全只靠Web技巧過關的

覺得蠻酷的所以要講三次XD

題目的source code長這樣:

<?php
    $path = "..";
    $file = "flag.txt";
    $authenticated = false;
    $secret = trim(file_get_contents("$path/$file"));
    assert(strlen($secret) <= 60);

    if(isset($_GET['expire']) && isset($_GET['auth'])) {
        $expire = $_GET['expire'];
        $auth = $_GET['auth'];
        $qstr = substr(strstr($_SERVER['REQUEST_URI'], '?'), 1);
        $qstr = preg_replace('/&auth=.*/', '', $qstr);
        $qstr = urldecode($qstr);
        if(sha1($secret . "$qstr") === $auth) {
            if($expire > time(0)) {
                $authenticated = true;
            }
        }
    } else {
        $expire = time(0) - 1000000;
        $auth = sha1($secret . "expire=$expire");
        $uri = preg_replace('/\?.*/', '', $_SERVER['REQUEST_URI']);
        header("HTTP/1.1 302 Found");
        header("Location: $uri?expire=$expire&auth=$auth");
        die;
    }
?>

從這段看出來,他給的expire和auth是必定是過期的

$expire = time(0) - 1000000;
$auth = sha1($secret . "expire=$expire");

所以判斷必定無法成立。

但問題出在這段:

$qstr = preg_replace('/&auth=.*/', '', $qstr);

意思就是他把&auth=xxxxx前面的參數拿來出來設為$qstr 在正常狀況下,網址應該呈現http://quiz.ais3.org:8014/expire=12345&auth=xxxxxx這種形式

因此理論上會取出expire=12345設為$qstr的值,再把它拿去做驗證 而驗證的過程是這一段

if(sha1($secret . "$qstr") === $auth) {
      if($expire > time(0)) {
          $authenticated = true;
      }
}

值得注意的是,$qstr使用者是有竄改的可能的,例如:

http://quiz.ais3.org:8014/ob'_'ov&auth=xxxxxx

如此一來,$qstr就變成ob’_‘ov了

因此,我構造了這樣的網址:

http://quiz.ais3.org:8014/?expire=[伺服端一開始給的expire]&auth=[伺服端一開始給的auth]&expire=99999999999

他判斷auth是利用到前面正常的expire 而判斷時間則是用實際GET到的參數,也就是後面覆蓋過去的expire=99999999999

然後就成功PASS了XDD

這題應該是在考 Length extension attack,可是我好像完全沒用到啊wwwwwwww

crypto3

沒時間解喇

Binary

binary1

讀程式進來直接給 angr 跑

然後FLAG GET ais3{readING_ASSemblY_4_FUN!}

remote

我不會。

Web

web1

題目敘述: There is a secret page in these website. Even Google can not find it, can you?

google找不到,所以就猜是robots.txt

User-agent: *
Disallow: /admin
Disallow: /cgi-bin/
Disallow: /images/
Disallow: /tmp/
Disallow: /private/
Disallow: /this_secret_page_you_should_not_know_where_it_is.php

ais3{Y0u_beat_the_G00g1e!!}

是說,我一開始猜不到是robots.txt,是先解完 web2 回來才想到的@@

web2

Source code長這樣

<?php
error_reporting(0);
include "flag.php";

// Strong IP firewall, no-one can pass this except the admin in localhost
if ($_SERVER['REMOTE_ADDR'] !== '127.0.0.1')
{
    header("Location: you_should_not_pass");
}
?>

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Admin Panel</title>
</head>
<body>
    Admin's secret is: <?php echo $flag; ?>
</body>
</html>

他判斷完IP位址後,是用header("Location: you_should_not_pass");把我們帶出去 但後面的內容還是會繼續執行

於是我抓出他的Response header,把location那攔刪掉就會正常顯示出flag了 ais3{admin's_pane1_is_on_fir3!!!!!} (之後想到其實能用curl直接抓出來@@

web3

這題網站有很多檔 這裡只給出重點網頁的source code

<?php
include "you_should_not_pass.php";
# general WAF
function waf()
{
    $keywords = [
        "union",
        "select",
        "insert",
        "where",
        "update",
        "order",
        # danger!!!!
        "flag",
    ];
    $uri = parse_url($_SERVER["REQUEST_URI"]);
    parse_str($uri['query'], $query);
    foreach($keywords as $token)
    {
        foreach($query as $k => $v)
        {
            if (stristr($k, $token))
                bad();
            if (stristr($v, $token))
                bad();
        }
    }
}
waf();

一開始就是基本的LFI讀出source code,就不寫了

這題的重點在於parse_url,他有神奇的bug (php5.X才有的樣子,我在自己的電腦上就踹不出來) 只要在filename前面加一個斜線,就會干擾parse_url的解析了

於是構造出這樣的網址:https://quiz.ais3.org:8013//download.php?p=../flag.php

CTF{haha!i_bypassed_the_fucking_waf!}

附上解救我這題的連結:http://lorexxar.cn/2016/05/10/asis-bcloud/#bypass%E7%9B%AE%E5%BD%95%E8%BF%87%E6%BB%A4

Discussion and feedback